diff options
-rw-r--r-- | src/Network/Tox/Crypto/Transport.hs | 74 |
1 files changed, 59 insertions, 15 deletions
diff --git a/src/Network/Tox/Crypto/Transport.hs b/src/Network/Tox/Crypto/Transport.hs index 20b0abae..1583ef6f 100644 --- a/src/Network/Tox/Crypto/Transport.hs +++ b/src/Network/Tox/Crypto/Transport.hs | |||
@@ -61,6 +61,7 @@ data NetCrypto | |||
61 | parseNetCrypto :: ByteString -> SockAddr -> Either String (NetCrypto, SockAddr) | 61 | parseNetCrypto :: ByteString -> SockAddr -> Either String (NetCrypto, SockAddr) |
62 | parseNetCrypto pkt@(B.uncons -> Just (0x1a,_)) saddr = left ("parseNetCrypto: "++) $ (,saddr) . NetHandshake <$> runGet get pkt | 62 | parseNetCrypto pkt@(B.uncons -> Just (0x1a,_)) saddr = left ("parseNetCrypto: "++) $ (,saddr) . NetHandshake <$> runGet get pkt |
63 | parseNetCrypto pkt@(B.uncons -> Just (0x1b,_)) saddr = left ("parseNetCrypto: "++) $ (,saddr) . NetCrypto <$> runGet get pkt | 63 | parseNetCrypto pkt@(B.uncons -> Just (0x1b,_)) saddr = left ("parseNetCrypto: "++) $ (,saddr) . NetCrypto <$> runGet get pkt |
64 | parseNetCrypto _ _ = Left "parseNetCrypto: ?" | ||
64 | 65 | ||
65 | encodeNetCrypto :: NetCrypto -> SockAddr -> (ByteString, SockAddr) | 66 | encodeNetCrypto :: NetCrypto -> SockAddr -> (ByteString, SockAddr) |
66 | encodeNetCrypto (NetHandshake x) saddr = (B.cons 0x1a (runPut $ put x),saddr) | 67 | encodeNetCrypto (NetHandshake x) saddr = (B.cons 0x1a (runPut $ put x),saddr) |
@@ -160,12 +161,12 @@ userStatus = lens getter setter | |||
160 | setter (TwoByte USERSTATUS _) status = TwoByte USERSTATUS (fromIntegral . fromEnum $ status) | 161 | setter (TwoByte USERSTATUS _) status = TwoByte USERSTATUS (fromIntegral . fromEnum $ status) |
161 | setter _ _ = erCompat "userStatus" | 162 | setter _ _ = erCompat "userStatus" |
162 | 163 | ||
163 | nick :: Functor f => (String -> f String)-> (CryptoMessage -> f CryptoMessage) | 164 | nick :: Functor f => (Text -> f Text)-> (CryptoMessage -> f CryptoMessage) |
164 | nick = lens getter setter | 165 | nick = lens getter setter |
165 | where | 166 | where |
166 | getter (UpToN NICKNAME bstr) = T.unpack $ T.decodeUtf8 bstr | 167 | getter (UpToN NICKNAME bstr) = T.decodeUtf8 bstr |
167 | getter _ = erCompat "nick" | 168 | getter _ = erCompat "nick" |
168 | setter (UpToN NICKNAME _) nick = UpToN NICKNAME (T.encodeUtf8 . T.pack $ nick) | 169 | setter (UpToN NICKNAME _) nick = UpToN NICKNAME (T.encodeUtf8 $ nick) |
169 | setter _ _ = erCompat "nick" | 170 | setter _ _ = erCompat "nick" |
170 | 171 | ||
171 | statusMessage :: Functor f => (String -> f String)-> (CryptoMessage -> f CryptoMessage) | 172 | statusMessage :: Functor f => (String -> f String)-> (CryptoMessage -> f CryptoMessage) |
@@ -336,13 +337,13 @@ instance HasMessageName CryptoMessage where | |||
336 | getMessageName (UpToN (fromEnum -> 0xC7) (sizedN 9 -> B.splitAt 8 -> (_,onebyte))) | 337 | getMessageName (UpToN (fromEnum -> 0xC7) (sizedN 9 -> B.splitAt 8 -> (_,onebyte))) |
337 | = let [n] = B.unpack onebyte | 338 | = let [n] = B.unpack onebyte |
338 | in toEnum . fromIntegral $ n | 339 | in toEnum . fromIntegral $ n |
339 | getMessageName _ = error "getMessageName on CryptoMessage without message number field." | 340 | getMessageName _ = error "getMessageName on CryptoMessage without message name field." |
340 | 341 | ||
341 | setMessageName (UpToN xE@(fromEnum -> 0x63) (sizedAtLeastN 9 -> B.splitAt 8 -> (bs,xs))) messagename | 342 | setMessageName (UpToN xE@(fromEnum -> 0x63) (sizedAtLeastN 9 -> B.splitAt 8 -> (bs,xs))) messagename |
342 | = UpToN xE (B.concat [bs,B.cons (fromIntegral $ fromEnum messagename) (B.drop 1 xs)]) | 343 | = UpToN xE (B.concat [bs,B.cons (fromIntegral $ fromEnum messagename) (B.drop 1 xs)]) |
343 | setMessageName (UpToN xE@(fromEnum -> 0xC7) (sizedAtLeastN 9 -> B.splitAt 8 -> (bs,xs))) messagename | 344 | setMessageName (UpToN xE@(fromEnum -> 0xC7) (sizedAtLeastN 9 -> B.splitAt 8 -> (bs,xs))) messagename |
344 | = UpToN xE (B.concat [bs,B.cons (fromIntegral $ fromEnum messagename) (B.drop 1 xs)]) | 345 | = UpToN xE (B.concat [bs,B.cons (fromIntegral $ fromEnum messagename) (B.drop 1 xs)]) |
345 | setMessageName _ _ = error "setMessageName on CryptoMessage without message number field." | 346 | setMessageName _ _ = error "setMessageName on CryptoMessage without message name field." |
346 | 347 | ||
347 | messageName :: (Functor f, HasMessageName x) => (MessageName -> f MessageName) -> (x -> f x) | 348 | messageName :: (Functor f, HasMessageName x) => (MessageName -> f MessageName) -> (x -> f x) |
348 | messageName = lens getMessageName setMessageName | 349 | messageName = lens getMessageName setMessageName |
@@ -356,17 +357,51 @@ class HasMessageData x where | |||
356 | instance HasMessageData CryptoMessage where | 357 | instance HasMessageData CryptoMessage where |
357 | getMessageData (UpToN (fromEnum -> 0x63) (sizedAtLeastN 9 -> B.splitAt 9 -> (_,mdata))) = mdata | 358 | getMessageData (UpToN (fromEnum -> 0x63) (sizedAtLeastN 9 -> B.splitAt 9 -> (_,mdata))) = mdata |
358 | getMessageData (UpToN (fromEnum -> 0xC7) (sizedAtLeastN 9 -> B.splitAt 9 -> (_,mdata))) = mdata | 359 | getMessageData (UpToN (fromEnum -> 0xC7) (sizedAtLeastN 9 -> B.splitAt 9 -> (_,mdata))) = mdata |
359 | getMessageData _ = error "getMessageData on CryptoMessage without message number field." | 360 | getMessageData _ = error "getMessageData on CryptoMessage without message data field." |
360 | 361 | ||
361 | setMessageData (UpToN xE@(fromEnum -> 0x63) (sizedAtLeastN 9 -> B.splitAt 9 -> (bs,xs))) messagedata -- MESSAGE_GROUPCHAT | 362 | setMessageData (UpToN xE@(fromEnum -> 0x63) (sizedAtLeastN 9 -> B.splitAt 9 -> (bs,xs))) messagedata -- MESSAGE_GROUPCHAT |
362 | = UpToN xE (B.concat [bs,messagedata]) | 363 | = UpToN xE (B.concat [bs,messagedata]) |
363 | setMessageData (UpToN xE@(fromEnum -> 0xC7) (sizedAtLeastN 9 -> B.splitAt 9 -> (bs,xs))) messagedata -- LOSSY_GROUPCHAT | 364 | setMessageData (UpToN xE@(fromEnum -> 0xC7) (sizedAtLeastN 9 -> B.splitAt 9 -> (bs,xs))) messagedata -- LOSSY_GROUPCHAT |
364 | = UpToN xE (B.concat [bs,messagedata]) | 365 | = UpToN xE (B.concat [bs,messagedata]) |
365 | setMessageData _ _ = error "setMessageData on CryptoMessage without message number field." | 366 | setMessageData _ _ = error "setMessageData on CryptoMessage without message data field." |
366 | 367 | ||
367 | messageData :: (Functor f, HasMessageData x) => (MessageData -> f MessageData) -> (x -> f x) | 368 | messageData :: (Functor f, HasMessageData x) => (MessageData -> f MessageData) -> (x -> f x) |
368 | messageData = lens getMessageData setMessageData | 369 | messageData = lens getMessageData setMessageData |
369 | 370 | ||
371 | class HasTitle x where | ||
372 | getTitle :: x -> Text | ||
373 | setTitle :: x -> Text -> x | ||
374 | |||
375 | instance HasTitle CryptoMessage where | ||
376 | getTitle (UpToN (fromEnum -> 0x62) (sizedAtLeastN 4 -> B.splitAt 3 -> (_,B.uncons -> Just (0x0a,mdata)))) = decodeUtf8 mdata | ||
377 | getTitle _ = error "getTitle on CryptoMessage without title field." | ||
378 | |||
379 | -- If its not | ||
380 | setTitle (UpToN xE@(fromEnum -> 0x62) (sizedAtLeastN 4 -> B.splitAt 3 -> (bs,B.uncons -> Just (_,xs)))) messagedata -- MESSAGE_GROUPCHAT | ||
381 | = UpToN xE (B.concat [bs,B.cons 0x0a (encodeUtf8 messagedata)]) | ||
382 | setTitle _ _ = error "setTitle on CryptoMessage without title field." | ||
383 | |||
384 | title :: (Functor f, HasTitle x) => (Text -> f Text) -> (x -> f x) | ||
385 | title = lens getTitle setTitle | ||
386 | |||
387 | class HasName x where | ||
388 | getName :: x -> Text | ||
389 | setName :: x -> Text -> x | ||
390 | |||
391 | |||
392 | instance HasName CryptoMessage where | ||
393 | -- Only MESSAGE_GROUPCHAT:NameChange has Name field | ||
394 | getName (UpToN xE (sizedAtLeastN 4 -> B.splitAt 3 -> (_,B.uncons -> Just (toEnum . fromIntegral -> NameChange,mdata)))) | isGroupChatMsg xE = decodeUtf8 mdata | ||
395 | getName _ = error "getName on CryptoMessage without name field." | ||
396 | |||
397 | -- If its not NameChange, this setter will set it to NameChange | ||
398 | setName (UpToN xE (sizedAtLeastN 4 -> B.splitAt 3 -> (bs,B.uncons -> Just (_,xs)))) name | ||
399 | | isGroupChatMsg xE = UpToN xE (B.concat [bs,B.cons (fromIntegral $ fromEnum NameChange) (encodeUtf8 name)]) | ||
400 | setName _ _ = error "setName on CryptoMessage without name field." | ||
401 | |||
402 | name :: (Functor f, HasTitle x) => (Text -> f Text) -> (x -> f x) | ||
403 | name = lens getTitle setTitle | ||
404 | |||
370 | data PeerInfo | 405 | data PeerInfo |
371 | = PeerInfo | 406 | = PeerInfo |
372 | { piPeerNum :: PeerNumber | 407 | { piPeerNum :: PeerNumber |
@@ -375,6 +410,10 @@ data PeerInfo | |||
375 | , piName :: ByteString -- byte-prefix for length | 410 | , piName :: ByteString -- byte-prefix for length |
376 | } deriving (Eq,Show) | 411 | } deriving (Eq,Show) |
377 | 412 | ||
413 | instance HasPeerNumber PeerInfo where | ||
414 | getPeerNumber = piPeerNum | ||
415 | setPeerNumber x n = x { piPeerNum = n } | ||
416 | |||
378 | instance Serialize PeerInfo where | 417 | instance Serialize PeerInfo where |
379 | get = do | 418 | get = do |
380 | w16 <- get | 419 | w16 <- get |
@@ -404,6 +443,7 @@ msg :: MessageID -> CryptoMessage | |||
404 | msg mid | Just (True,0) <- msgSizeParam mid = OneByte mid | 443 | msg mid | Just (True,0) <- msgSizeParam mid = OneByte mid |
405 | msg mid | Just (True,1) <- msgSizeParam mid = TwoByte mid 0 | 444 | msg mid | Just (True,1) <- msgSizeParam mid = TwoByte mid 0 |
406 | msg mid | Just (False,_) <- msgSizeParam mid = UpToN mid B.empty | 445 | msg mid | Just (False,_) <- msgSizeParam mid = UpToN mid B.empty |
446 | msg mid = UpToN mid B.empty | ||
407 | 447 | ||
408 | leaveMsg :: Serialize a => a -> CryptoMessage | 448 | leaveMsg :: Serialize a => a -> CryptoMessage |
409 | leaveMsg groupnum = UpToN DIRECT_GROUPCHAT (B.snoc (S.encode groupnum) 0x01) | 449 | leaveMsg groupnum = UpToN DIRECT_GROUPCHAT (B.snoc (S.encode groupnum) 0x01) |
@@ -429,11 +469,15 @@ msgSizeParam FILE_SENDREQUEST = Just (False,300) -- 1+1+4+8+32+max255 = up to 30 | |||
429 | msgSizeParam FILE_CONTROL = Just (False,7) -- 8 bytes if seek, otherwise 4 | 469 | msgSizeParam FILE_CONTROL = Just (False,7) -- 8 bytes if seek, otherwise 4 |
430 | msgSizeParam INVITE_GROUPCHAT = Just (False,38) | 470 | msgSizeParam INVITE_GROUPCHAT = Just (False,38) |
431 | msgSizeParam ONLINE_PACKET = Just (True,35) | 471 | msgSizeParam ONLINE_PACKET = Just (True,35) |
432 | msgSizeParam DIRECT_GROUPCHAT = Nothing -- 1+2+1 thus Just (True,3) leave & peer-query, but variable in response packets | 472 | msgSizeParam DIRECT_GROUPCHAT {-0x62-} = Nothing -- 1+2+1 thus Just (True,3) leave & peer-query, but variable in response packets |
433 | msgSizeParam MESSAGE_GROUPCHAT = Nothing -- variable | 473 | msgSizeParam MESSAGE_GROUPCHAT {-0x63-} = Nothing -- variable |
434 | msgSizeParam LOSSY_GROUPCHAT = Nothing -- variable | 474 | msgSizeParam LOSSY_GROUPCHAT {-0xC7-} = Nothing -- variable |
435 | msgSizeParam _ = Nothing | 475 | msgSizeParam _ = Nothing |
436 | 476 | ||
477 | isGroupChatMsg MESSAGE_GROUPCHAT = True | ||
478 | isGroupChatMsg LOSSY_GROUPCHAT = True | ||
479 | isGroupChatMsg _ = False | ||
480 | |||
437 | -- TODO: Flesh this out. | 481 | -- TODO: Flesh this out. |
438 | data MessageID -- First byte indicates data | 482 | data MessageID -- First byte indicates data |
439 | = Padding -- ^ 0 padding (skipped until we hit a non zero (data id) byte) | 483 | = Padding -- ^ 0 padding (skipped until we hit a non zero (data id) byte) |
@@ -532,10 +576,10 @@ data MessageID -- First byte indicates data | |||
532 | | MessengerLossless093 | 576 | | MessengerLossless093 |
533 | | MessengerLossless094 | 577 | | MessengerLossless094 |
534 | | MessengerLossless095 | 578 | | MessengerLossless095 |
535 | | INVITE_GROUPCHAT | 579 | | INVITE_GROUPCHAT -- 0x60 |
536 | | ONLINE_PACKET | 580 | | ONLINE_PACKET -- 0x61 |
537 | | DIRECT_GROUPCHAT | 581 | | DIRECT_GROUPCHAT -- 0x62 |
538 | | MESSAGE_GROUPCHAT | 582 | | MESSAGE_GROUPCHAT -- 0x63 |
539 | | MessengerLossless100 | 583 | | MessengerLossless100 |
540 | | MessengerLossless101 | 584 | | MessengerLossless101 |
541 | | MessengerLossless102 | 585 | | MessengerLossless102 |
@@ -635,7 +679,7 @@ data MessageID -- First byte indicates data | |||
635 | | MessengerLossy196 | 679 | | MessengerLossy196 |
636 | | MessengerLossy197 | 680 | | MessengerLossy197 |
637 | | MessengerLossy198 | 681 | | MessengerLossy198 |
638 | | LOSSY_GROUPCHAT | 682 | | LOSSY_GROUPCHAT -- 0xC7 |
639 | | MessengerLossy200 | 683 | | MessengerLossy200 |
640 | | MessengerLossy201 | 684 | | MessengerLossy201 |
641 | | MessengerLossy202 | 685 | | MessengerLossy202 |