diff options
-rw-r--r-- | src/Network/Tox/Crypto/Transport.hs | 85 |
1 files changed, 68 insertions, 17 deletions
diff --git a/src/Network/Tox/Crypto/Transport.hs b/src/Network/Tox/Crypto/Transport.hs index f7fd0f7e..4b2e97ce 100644 --- a/src/Network/Tox/Crypto/Transport.hs +++ b/src/Network/Tox/Crypto/Transport.hs | |||
@@ -10,6 +10,7 @@ module Network.Tox.Crypto.Transport | |||
10 | , NetCrypto(..) | 10 | , NetCrypto(..) |
11 | , CryptoData(..) | 11 | , CryptoData(..) |
12 | , CryptoMessage(..) | 12 | , CryptoMessage(..) |
13 | , MessageName(..) | ||
13 | , CryptoPacket(..) | 14 | , CryptoPacket(..) |
14 | , HandshakeData(..) | 15 | , HandshakeData(..) |
15 | , Handshake(..) | 16 | , Handshake(..) |
@@ -18,6 +19,7 @@ module Network.Tox.Crypto.Transport | |||
18 | , UserStatus(..) | 19 | , UserStatus(..) |
19 | , TypingStatus(..) | 20 | , TypingStatus(..) |
20 | , GroupChatId(..) | 21 | , GroupChatId(..) |
22 | , MessageType(..) | ||
21 | -- feild name classes | 23 | -- feild name classes |
22 | , HasGroupChatID(..) | 24 | , HasGroupChatID(..) |
23 | , HasGroupNumber(..) | 25 | , HasGroupNumber(..) |
@@ -25,10 +27,14 @@ module Network.Tox.Crypto.Transport | |||
25 | , HasMessageNumber(..) | 27 | , HasMessageNumber(..) |
26 | , HasMessageName(..) | 28 | , HasMessageName(..) |
27 | , HasMessageData(..) | 29 | , HasMessageData(..) |
30 | , HasName(..) | ||
31 | , HasTitle(..) | ||
32 | , HasMessage(..) | ||
33 | , HasMessageType(..) | ||
28 | -- lenses | 34 | -- lenses |
29 | , userStatus, nick, statusMessage, typingStatus, message, action, groupChatID | 35 | , userStatus, nick, statusMessage, typingStatus, message, action, groupChatID |
30 | , groupNumber, groupNumberToJoin, peerNumber, messageNumber | 36 | , groupNumber, groupNumberToJoin, peerNumber, messageNumber |
31 | , messageName, messageData | 37 | , messageName, messageData, name, title, message, messageType |
32 | -- constructor | 38 | -- constructor |
33 | , msg | 39 | , msg |
34 | , leaveMsg | 40 | , leaveMsg |
@@ -36,6 +42,7 @@ module Network.Tox.Crypto.Transport | |||
36 | -- utils | 42 | -- utils |
37 | , sizedN | 43 | , sizedN |
38 | , sizedAtLeastN | 44 | , sizedAtLeastN |
45 | , isIndirectGrpChat | ||
39 | ) where | 46 | ) where |
40 | 47 | ||
41 | import Crypto.Tox | 48 | import Crypto.Tox |
@@ -192,14 +199,6 @@ statusMessage = lens getter setter | |||
192 | setter (UpToN STATUSMESSAGE _) nick = UpToN STATUSMESSAGE (T.encodeUtf8 . T.pack $ nick) | 199 | setter (UpToN STATUSMESSAGE _) nick = UpToN STATUSMESSAGE (T.encodeUtf8 . T.pack $ nick) |
193 | setter _ _ = erCompat "statusMessage" | 200 | setter _ _ = erCompat "statusMessage" |
194 | 201 | ||
195 | message :: Functor f => (String -> f String)-> (CryptoMessage -> f CryptoMessage) | ||
196 | message = lens getter setter | ||
197 | where | ||
198 | getter (UpToN MESSAGE bstr) = T.unpack $ T.decodeUtf8 bstr | ||
199 | getter _ = erCompat "message" | ||
200 | setter (UpToN MESSAGE _) message = UpToN MESSAGE (T.encodeUtf8 . T.pack $ message) | ||
201 | setter _ _ = erCompat "message" | ||
202 | |||
203 | action :: Functor f => (String -> f String)-> (CryptoMessage -> f CryptoMessage) | 202 | action :: Functor f => (String -> f String)-> (CryptoMessage -> f CryptoMessage) |
204 | action = lens getter setter | 203 | action = lens getter setter |
205 | where | 204 | where |
@@ -341,6 +340,7 @@ instance HasMessageNumber CryptoMessage where | |||
341 | messageNumber :: (Functor f, HasMessageNumber x) => (Word32 -> f Word32) -> (x -> f x) | 340 | messageNumber :: (Functor f, HasMessageNumber x) => (Word32 -> f Word32) -> (x -> f x) |
342 | messageNumber = lens getMessageNumber setMessageNumber | 341 | messageNumber = lens getMessageNumber setMessageNumber |
343 | 342 | ||
343 | |||
344 | class HasMessageName x where | 344 | class HasMessageName x where |
345 | getMessageName :: x -> MessageName | 345 | getMessageName :: x -> MessageName |
346 | setMessageName :: x -> MessageName -> x | 346 | setMessageName :: x -> MessageName -> x |
@@ -363,6 +363,36 @@ instance HasMessageName CryptoMessage where | |||
363 | messageName :: (Functor f, HasMessageName x) => (MessageName -> f MessageName) -> (x -> f x) | 363 | messageName :: (Functor f, HasMessageName x) => (MessageName -> f MessageName) -> (x -> f x) |
364 | messageName = lens getMessageName setMessageName | 364 | messageName = lens getMessageName setMessageName |
365 | 365 | ||
366 | data MessageType = Msg MessageID | ||
367 | | GrpMsg MessageName | ||
368 | deriving (Eq,Show) | ||
369 | |||
370 | class HasMessageType x where | ||
371 | getMessageType :: x -> MessageType | ||
372 | setMessageType :: x -> MessageType -> x | ||
373 | |||
374 | instance HasMessageType CryptoMessage where | ||
375 | getMessageType (OneByte mid) = Msg mid | ||
376 | getMessageType (TwoByte mid _) = Msg mid | ||
377 | getMessageType m@(UpToN mid _) | isIndirectGrpChat mid = GrpMsg (getMessageName m) | ||
378 | getMessageType (UpToN mid _) = Msg mid | ||
379 | |||
380 | setMessageType m@(UpToN mid _) (GrpMsg mname) | isIndirectGrpChat mid = setMessageName m mname | ||
381 | setMessageType (OneByte _ ) (GrpMsg mname) = setMessageName (UpToN MESSAGE_GROUPCHAT B.empty ) mname | ||
382 | setMessageType (TwoByte _ x) (GrpMsg mname) = setMessageName (UpToN MESSAGE_GROUPCHAT (B.singleton x)) mname | ||
383 | setMessageType (UpToN _ x) (GrpMsg mname) = setMessageName (UpToN MESSAGE_GROUPCHAT x) mname | ||
384 | setMessageType m (Msg mid) | Just (True,1) <- msgSizeParam mid = OneByte mid | ||
385 | setMessageType (OneByte mid0 ) (Msg mid) | Just (True,2) <- msgSizeParam mid = TwoByte mid 0 | ||
386 | setMessageType (TwoByte mid0 x) (Msg mid) | Just (True,2) <- msgSizeParam mid = TwoByte mid x | ||
387 | setMessageType (UpToN mid0 x) (Msg mid) | Just (True,n) <- msgSizeParam mid = UpToN mid (sizedN n x) | ||
388 | setMessageType (OneByte mid0) (Msg mid) = UpToN mid B.empty | ||
389 | setMessageType (TwoByte mid0 x) (Msg mid) = UpToN mid (B.singleton x) | ||
390 | setMessageType (UpToN mid0 x) (Msg mid) = UpToN mid x | ||
391 | |||
392 | -- | This lens should always succeed on CryptoMessage | ||
393 | messageType :: (Functor f, HasMessageType x) => (MessageType -> f MessageType) -> (x -> f x) | ||
394 | messageType = lens getMessageType setMessageType | ||
395 | |||
366 | type MessageData = B.ByteString | 396 | type MessageData = B.ByteString |
367 | 397 | ||
368 | class HasMessageData x where | 398 | class HasMessageData x where |
@@ -388,17 +418,38 @@ class HasTitle x where | |||
388 | setTitle :: x -> Text -> x | 418 | setTitle :: x -> Text -> x |
389 | 419 | ||
390 | instance HasTitle CryptoMessage where | 420 | instance HasTitle CryptoMessage where |
391 | getTitle (UpToN (fromEnum -> 0x62) (sizedAtLeastN 4 -> B.splitAt 3 -> (_,B.uncons -> Just (0x0a,mdata)))) = decodeUtf8 mdata | 421 | getTitle (UpToN DIRECT_GROUPCHAT {-Ox62-} (sizedAtLeastN 4 -> B.splitAt 3 -> (_,B.uncons -> Just (0x0a,mdata)))) = decodeUtf8 mdata |
422 | getTitle (UpToN xE (sizedAtLeastN 4 -> B.splitAt 3 -> (_,B.uncons -> Just (toEnum . fromIntegral -> GroupchatTitleChange,mdata)))) | ||
423 | | isIndirectGrpChat xE = decodeUtf8 mdata | ||
392 | getTitle _ = error "getTitle on CryptoMessage without title field." | 424 | getTitle _ = error "getTitle on CryptoMessage without title field." |
393 | 425 | ||
394 | -- If its not | 426 | setTitle (UpToN xE@DIRECT_GROUPCHAT {-0x62-} (sizedAtLeastN 4 -> B.splitAt 3 -> (bs,B.uncons -> Just (_,xs)))) messagedata |
395 | setTitle (UpToN xE@(fromEnum -> 0x62) (sizedAtLeastN 4 -> B.splitAt 3 -> (bs,B.uncons -> Just (_,xs)))) messagedata -- MESSAGE_GROUPCHAT | ||
396 | = UpToN xE (B.concat [bs,B.cons 0x0a (encodeUtf8 messagedata)]) | 427 | = UpToN xE (B.concat [bs,B.cons 0x0a (encodeUtf8 messagedata)]) |
428 | setTitle (UpToN xE (sizedAtLeastN 4 -> B.splitAt 3 -> (bs,B.uncons -> Just (_,xs)))) title | ||
429 | | isIndirectGrpChat xE = UpToN xE (B.concat [bs,B.cons (fromIntegral $ fromEnum GroupchatTitleChange) (encodeUtf8 title)]) | ||
397 | setTitle _ _ = error "setTitle on CryptoMessage without title field." | 430 | setTitle _ _ = error "setTitle on CryptoMessage without title field." |
398 | 431 | ||
399 | title :: (Functor f, HasTitle x) => (Text -> f Text) -> (x -> f x) | 432 | title :: (Functor f, HasTitle x) => (Text -> f Text) -> (x -> f x) |
400 | title = lens getTitle setTitle | 433 | title = lens getTitle setTitle |
401 | 434 | ||
435 | class HasMessage x where | ||
436 | getMessage :: x -> Text | ||
437 | setMessage :: x -> Text -> x | ||
438 | |||
439 | instance HasMessage CryptoMessage where | ||
440 | getMessage (UpToN MESSAGE bstr) = T.decodeUtf8 bstr | ||
441 | getMessage (UpToN xE (sizedAtLeastN 9 -> B.splitAt 8 -> (_,B.uncons -> Just (mnameByte,mdata)))) | ||
442 | | isIndirectGrpChat xE = decodeUtf8 mdata | ||
443 | getMessage _ = error "getMessage on CryptoMessage without message field." | ||
444 | |||
445 | setMessage (UpToN MESSAGE _) message = UpToN MESSAGE (T.encodeUtf8 $ message) | ||
446 | setMessage (UpToN xE (sizedAtLeastN 9 -> B.splitAt 8 -> (bs,B.uncons -> Just (mnameByte,xs)))) message | ||
447 | | isIndirectGrpChat xE = UpToN xE (B.concat [bs,B.cons (if mnameByte == 0 then 0x40 else mnameByte) (encodeUtf8 message)]) | ||
448 | setMessage _ _ = error "setMessage on CryptoMessage without message field." | ||
449 | |||
450 | message :: (Functor f, HasMessage x) => (Text -> f Text) -> (x -> f x) | ||
451 | message = lens getMessage setMessage | ||
452 | |||
402 | class HasName x where | 453 | class HasName x where |
403 | getName :: x -> Text | 454 | getName :: x -> Text |
404 | setName :: x -> Text -> x | 455 | setName :: x -> Text -> x |
@@ -406,12 +457,12 @@ class HasName x where | |||
406 | 457 | ||
407 | instance HasName CryptoMessage where | 458 | instance HasName CryptoMessage where |
408 | -- Only MESSAGE_GROUPCHAT:NameChange has Name field | 459 | -- Only MESSAGE_GROUPCHAT:NameChange has Name field |
409 | getName (UpToN xE (sizedAtLeastN 4 -> B.splitAt 3 -> (_,B.uncons -> Just (toEnum . fromIntegral -> NameChange,mdata)))) | isGroupChatMsg xE = decodeUtf8 mdata | 460 | getName (UpToN xE (sizedAtLeastN 4 -> B.splitAt 3 -> (_,B.uncons -> Just (toEnum . fromIntegral -> NameChange,mdata)))) | isIndirectGrpChat xE = decodeUtf8 mdata |
410 | getName _ = error "getName on CryptoMessage without name field." | 461 | getName _ = error "getName on CryptoMessage without name field." |
411 | 462 | ||
412 | -- If its not NameChange, this setter will set it to NameChange | 463 | -- If its not NameChange, this setter will set it to NameChange |
413 | setName (UpToN xE (sizedAtLeastN 4 -> B.splitAt 3 -> (bs,B.uncons -> Just (_,xs)))) name | 464 | setName (UpToN xE (sizedAtLeastN 4 -> B.splitAt 3 -> (bs,B.uncons -> Just (_,xs)))) name |
414 | | isGroupChatMsg xE = UpToN xE (B.concat [bs,B.cons (fromIntegral $ fromEnum NameChange) (encodeUtf8 name)]) | 465 | | isIndirectGrpChat xE = UpToN xE (B.concat [bs,B.cons (fromIntegral $ fromEnum NameChange) (encodeUtf8 name)]) |
415 | setName _ _ = error "setName on CryptoMessage without name field." | 466 | setName _ _ = error "setName on CryptoMessage without name field." |
416 | 467 | ||
417 | name :: (Functor f, HasTitle x) => (Text -> f Text) -> (x -> f x) | 468 | name :: (Functor f, HasTitle x) => (Text -> f Text) -> (x -> f x) |
@@ -489,9 +540,9 @@ msgSizeParam MESSAGE_GROUPCHAT {-0x63-} = Nothing -- variable | |||
489 | msgSizeParam LOSSY_GROUPCHAT {-0xC7-} = Nothing -- variable | 540 | msgSizeParam LOSSY_GROUPCHAT {-0xC7-} = Nothing -- variable |
490 | msgSizeParam _ = Nothing | 541 | msgSizeParam _ = Nothing |
491 | 542 | ||
492 | isGroupChatMsg MESSAGE_GROUPCHAT = True | 543 | isIndirectGrpChat MESSAGE_GROUPCHAT = True |
493 | isGroupChatMsg LOSSY_GROUPCHAT = True | 544 | isIndirectGrpChat LOSSY_GROUPCHAT = True |
494 | isGroupChatMsg _ = False | 545 | isIndirectGrpChat _ = False |
495 | 546 | ||
496 | -- TODO: Flesh this out. | 547 | -- TODO: Flesh this out. |
497 | data MessageID -- First byte indicates data | 548 | data MessageID -- First byte indicates data |