diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Crypto/Tox.hs | 16 | ||||
-rw-r--r-- | src/Network/Tox.hs | 4 | ||||
-rw-r--r-- | src/Network/Tox/Crypto/Handlers.hs | 102 | ||||
-rw-r--r-- | src/Network/Tox/Crypto/Transport.hs | 41 |
4 files changed, 144 insertions, 19 deletions
diff --git a/src/Crypto/Tox.hs b/src/Crypto/Tox.hs index a25f9f4f..9f86f6a4 100644 --- a/src/Crypto/Tox.hs +++ b/src/Crypto/Tox.hs | |||
@@ -7,7 +7,7 @@ | |||
7 | {-# LANGUAGE DeriveTraversable #-} | 7 | {-# LANGUAGE DeriveTraversable #-} |
8 | {-# LANGUAGE ExplicitNamespaces #-} | 8 | {-# LANGUAGE ExplicitNamespaces #-} |
9 | {-# LANGUAGE TypeOperators #-} | 9 | {-# LANGUAGE TypeOperators #-} |
10 | {-# LANGUAGE MagicHash, UnboxedTuples #-} | 10 | {-# LANGUAGE MagicHash, UnboxedTuples, BangPatterns #-} |
11 | module Crypto.Tox | 11 | module Crypto.Tox |
12 | ( PublicKey | 12 | ( PublicKey |
13 | , publicKey | 13 | , publicKey |
@@ -35,6 +35,7 @@ module Crypto.Tox | |||
35 | , Nonce8(..) | 35 | , Nonce8(..) |
36 | , Nonce24(..) | 36 | , Nonce24(..) |
37 | , incrementNonce24 | 37 | , incrementNonce24 |
38 | , addtoNonce24 | ||
38 | , Nonce32(..) | 39 | , Nonce32(..) |
39 | , getRemainingEncrypted | 40 | , getRemainingEncrypted |
40 | , putEncrypted | 41 | , putEncrypted |
@@ -258,17 +259,18 @@ hsalsa20 k n = BA.append a b | |||
258 | newtype Nonce24 = Nonce24 ByteString | 259 | newtype Nonce24 = Nonce24 ByteString |
259 | deriving (Eq, Ord, ByteArrayAccess,Data) | 260 | deriving (Eq, Ord, ByteArrayAccess,Data) |
260 | 261 | ||
261 | incrementNonce24 :: Nonce24 -> IO Nonce24 | 262 | addtoNonce24 :: Nonce24 -> Word -> IO Nonce24 |
262 | incrementNonce24 (Nonce24 n24) = Nonce24 <$> BA.copy n24 init | 263 | addtoNonce24 (Nonce24 n24) n = Nonce24 <$> BA.copy n24 init |
263 | where | 264 | where |
264 | init :: Ptr Word -> IO () | 265 | init :: Ptr Word -> IO () |
265 | init ptr | fitsInInt (Proxy :: Proxy Word64) = do | 266 | init ptr | fitsInInt (Proxy :: Proxy Word64) = do |
266 | let frmBE64 = fromIntegral . fromBE64 . fromIntegral | 267 | let frmBE64 = fromIntegral . fromBE64 . fromIntegral |
267 | tBE64 = fromIntegral . toBE64 . fromIntegral | 268 | tBE64 = fromIntegral . toBE64 . fromIntegral |
269 | !(W# input) = n | ||
268 | W# w1 <- frmBE64 <$> peek ptr | 270 | W# w1 <- frmBE64 <$> peek ptr |
269 | W# w2 <- frmBE64 <$> peekElemOff ptr 1 | 271 | W# w2 <- frmBE64 <$> peekElemOff ptr 1 |
270 | W# w3 <- frmBE64 <$> peekElemOff ptr 2 | 272 | W# w3 <- frmBE64 <$> peekElemOff ptr 2 |
271 | let (# overflw, sum #) = plusWord2# w3 (int2Word# 1#) | 273 | let (# overflw, sum #) = plusWord2# w3 input |
272 | (# overflw', sum' #) = plusWord2# w2 overflw | 274 | (# overflw', sum' #) = plusWord2# w2 overflw |
273 | (# discard, sum'' #) = plusWord2# w1 overflw' | 275 | (# discard, sum'' #) = plusWord2# w1 overflw' |
274 | poke ptr $ tBE64 (W# sum'') | 276 | poke ptr $ tBE64 (W# sum'') |
@@ -278,13 +280,14 @@ incrementNonce24 (Nonce24 n24) = Nonce24 <$> BA.copy n24 init | |||
278 | init ptr | fitsInInt (Proxy :: Proxy Word32) = do | 280 | init ptr | fitsInInt (Proxy :: Proxy Word32) = do |
279 | let frmBE32 = fromIntegral . fromBE32 . fromIntegral | 281 | let frmBE32 = fromIntegral . fromBE32 . fromIntegral |
280 | tBE32 = fromIntegral . toBE32 . fromIntegral | 282 | tBE32 = fromIntegral . toBE32 . fromIntegral |
283 | !(W# input) = n | ||
281 | W# w1 <- frmBE32 <$> peek ptr | 284 | W# w1 <- frmBE32 <$> peek ptr |
282 | W# w2 <- frmBE32 <$> peekElemOff ptr 1 | 285 | W# w2 <- frmBE32 <$> peekElemOff ptr 1 |
283 | W# w3 <- frmBE32 <$> peekElemOff ptr 2 | 286 | W# w3 <- frmBE32 <$> peekElemOff ptr 2 |
284 | W# w4 <- frmBE32 <$> peekElemOff ptr 3 | 287 | W# w4 <- frmBE32 <$> peekElemOff ptr 3 |
285 | W# w5 <- frmBE32 <$> peekElemOff ptr 4 | 288 | W# w5 <- frmBE32 <$> peekElemOff ptr 4 |
286 | W# w6 <- frmBE32 <$> peekElemOff ptr 5 | 289 | W# w6 <- frmBE32 <$> peekElemOff ptr 5 |
287 | let (# overflw_, sum_ #) = plusWord2# w6 (int2Word# 1#) | 290 | let (# overflw_, sum_ #) = plusWord2# w6 input |
288 | (# overflw__, sum__ #) = plusWord2# w5 overflw_ | 291 | (# overflw__, sum__ #) = plusWord2# w5 overflw_ |
289 | (# overflw___, sum___ #) = plusWord2# w6 overflw__ | 292 | (# overflw___, sum___ #) = plusWord2# w6 overflw__ |
290 | (# overflw, sum #) = plusWord2# w3 overflw___ | 293 | (# overflw, sum #) = plusWord2# w3 overflw___ |
@@ -298,6 +301,9 @@ incrementNonce24 (Nonce24 n24) = Nonce24 <$> BA.copy n24 init | |||
298 | pokeElemOff ptr 5 $ tBE32 (W# sum_) | 301 | pokeElemOff ptr 5 $ tBE32 (W# sum_) |
299 | init _ = error "incrementNonce24: I only support 64 and 32 bits" | 302 | init _ = error "incrementNonce24: I only support 64 and 32 bits" |
300 | 303 | ||
304 | incrementNonce24 :: Nonce24 -> IO Nonce24 | ||
305 | incrementNonce24 nonce24 = addtoNonce24 nonce24 1 | ||
306 | |||
301 | quoted :: ShowS -> ShowS | 307 | quoted :: ShowS -> ShowS |
302 | quoted shows s = '"':shows ('"':s) | 308 | quoted shows s = '"':shows ('"':s) |
303 | 309 | ||
diff --git a/src/Network/Tox.hs b/src/Network/Tox.hs index 87835769..2f778874 100644 --- a/src/Network/Tox.hs +++ b/src/Network/Tox.hs | |||
@@ -89,7 +89,7 @@ import Crypto.Tox | |||
89 | import Data.Word64Map (fitsInInt) | 89 | import Data.Word64Map (fitsInInt) |
90 | import qualified Data.Word64Map (empty) | 90 | import qualified Data.Word64Map (empty) |
91 | import Network.Tox.Crypto.Transport (NetCrypto) | 91 | import Network.Tox.Crypto.Transport (NetCrypto) |
92 | import Network.Tox.Crypto.Handlers (newSessionsState, cryptoNetHandler) | 92 | import Network.Tox.Crypto.Handlers (newSessionsState, cryptoNetHandler, cryptoDefaultHooks) |
93 | import qualified Network.Tox.DHT.Handlers as DHT | 93 | import qualified Network.Tox.DHT.Handlers as DHT |
94 | import qualified Network.Tox.DHT.Transport as DHT | 94 | import qualified Network.Tox.DHT.Transport as DHT |
95 | import Network.Tox.NodeId | 95 | import Network.Tox.NodeId |
@@ -309,7 +309,7 @@ newTox keydb addr = do | |||
309 | (const id) | 309 | (const id) |
310 | 310 | ||
311 | roster <- newRoster | 311 | roster <- newRoster |
312 | sessionsState <- newSessionsState crypto | 312 | sessionsState <- newSessionsState crypto cryptoDefaultHooks |
313 | return Tox | 313 | return Tox |
314 | { toxDHT = dhtclient | 314 | { toxDHT = dhtclient |
315 | , toxOnion = onionclient | 315 | , toxOnion = onionclient |
diff --git a/src/Network/Tox/Crypto/Handlers.hs b/src/Network/Tox/Crypto/Handlers.hs index 29f55e54..12818b2e 100644 --- a/src/Network/Tox/Crypto/Handlers.hs +++ b/src/Network/Tox/Crypto/Handlers.hs | |||
@@ -12,27 +12,48 @@ import Crypto.Hash | |||
12 | import Control.Applicative | 12 | import Control.Applicative |
13 | import Control.Monad | 13 | import Control.Monad |
14 | import Data.Time.Clock.POSIX | 14 | import Data.Time.Clock.POSIX |
15 | import qualified Data.ByteString as B | ||
16 | import Control.Lens | ||
17 | import Data.Function | ||
18 | import Data.Serialize as S | ||
19 | import Data.Word | ||
20 | import GHC.Conc (unsafeIOToSTM) | ||
21 | |||
22 | -- util, todo: move to another module | ||
23 | maybeToEither (Just x) = Right x | ||
24 | maybeToEither Nothing = Left "maybeToEither" | ||
15 | 25 | ||
16 | data NetCryptoSessionStatus = Unaccepted | Accepted | Confirmed | 26 | data NetCryptoSessionStatus = Unaccepted | Accepted | Confirmed |
17 | deriving (Eq,Ord,Show,Enum) | 27 | deriving (Eq,Ord,Show,Enum) |
18 | 28 | ||
19 | 29 | ||
30 | type IOHook addr x = addr -> x -> IO (Maybe (x -> x)) | ||
31 | type NetCryptoHook = IOHook SockAddr CryptoMessage | ||
32 | |||
33 | |||
20 | data NetCryptoSession = NCrypto { ncState :: TVar NetCryptoSessionStatus | 34 | data NetCryptoSession = NCrypto { ncState :: TVar NetCryptoSessionStatus |
21 | , ncTheirPacketNonce:: TVar Nonce24 -- base nonce + packet number | 35 | , ncTheirBaseNonce :: TVar Nonce24 -- base nonce + packet number |
22 | , ncMyPacketNonce :: TVar Nonce24 -- base nonce + packet number | 36 | , ncMyPacketNonce :: TVar Nonce24 -- base nonce + packet number |
23 | , ncHandShake :: TVar (Maybe (Handshake Encrypted)) | 37 | , ncHandShake :: TVar (Maybe (Handshake Encrypted)) |
24 | , ncCookie :: TVar (Maybe Cookie) | 38 | , ncCookie :: TVar (Maybe Cookie) |
25 | , ncTheirSessionPublic :: Maybe PublicKey | 39 | , ncTheirSessionPublic :: Maybe PublicKey |
26 | , ncSessionSecret :: SecretKey | 40 | , ncSessionSecret :: SecretKey |
27 | , ncSockAddr :: SockAddr | 41 | , ncSockAddr :: SockAddr |
42 | , ncHooks :: TVar (Map.Map MessageType [NetCryptoHook]) | ||
28 | } | 43 | } |
29 | 44 | ||
30 | data NetCryptoSessions = NCSessions { netCryptoSessions :: TVar (Map.Map SockAddr NetCryptoSession) | 45 | data NetCryptoSessions = NCSessions { netCryptoSessions :: TVar (Map.Map SockAddr NetCryptoSession) |
31 | , transportCrypto :: TransportCrypto | 46 | , transportCrypto :: TransportCrypto |
47 | , defaultHooks :: Map.Map MessageType [NetCryptoHook] | ||
32 | } | 48 | } |
33 | 49 | ||
34 | newSessionsState :: TransportCrypto -> IO NetCryptoSessions | 50 | newSessionsState :: TransportCrypto -> Map.Map MessageType [NetCryptoHook] -> IO NetCryptoSessions |
35 | newSessionsState crypto = error "todo" | 51 | newSessionsState crypto hooks = do |
52 | x <- atomically $ newTVar Map.empty | ||
53 | return NCSessions { netCryptoSessions = x | ||
54 | , transportCrypto = crypto | ||
55 | , defaultHooks = hooks | ||
56 | } | ||
36 | 57 | ||
37 | data HandshakeParams | 58 | data HandshakeParams |
38 | = HParam | 59 | = HParam |
@@ -48,6 +69,7 @@ newHandShakeData = error "todo" | |||
48 | 69 | ||
49 | cryptoNetHandler :: NetCryptoSessions -> SockAddr -> NetCrypto -> IO (Maybe (NetCrypto -> NetCrypto)) | 70 | cryptoNetHandler :: NetCryptoSessions -> SockAddr -> NetCrypto -> IO (Maybe (NetCrypto -> NetCrypto)) |
50 | cryptoNetHandler sessions addr (NetHandshake (Handshake (Cookie n24 ecookie) nonce24 encrypted)) = do | 71 | cryptoNetHandler sessions addr (NetHandshake (Handshake (Cookie n24 ecookie) nonce24 encrypted)) = do |
72 | -- Handle Handshake Message | ||
51 | let crypto = transportCrypto sessions | 73 | let crypto = transportCrypto sessions |
52 | allsessions = netCryptoSessions sessions | 74 | allsessions = netCryptoSessions sessions |
53 | anyRight xs f = foldr1 (<|>) $ map f xs | 75 | anyRight xs f = foldr1 (<|>) $ map f xs |
@@ -81,17 +103,18 @@ cryptoNetHandler sessions addr (NetHandshake (Handshake (Cookie n24 ecookie) non | |||
81 | Left _ -> return () | 103 | Left _ -> return () |
82 | Right hp@(HParam | 104 | Right hp@(HParam |
83 | { hpTheirBaseNonce = Just theirBaseNonce | 105 | { hpTheirBaseNonce = Just theirBaseNonce |
84 | , hpOtherCookie = Just otherCookie | 106 | , hpOtherCookie = Just otherCookie |
85 | , hpTheirSessionKeyPublic = theirSessionKey | 107 | , hpTheirSessionKeyPublic = theirSessionKey |
86 | , hpMySecretKey = key | 108 | , hpMySecretKey = key |
87 | , hpCookieRemotePubkey = remotePublicKey | 109 | , hpCookieRemotePubkey = remotePublicKey |
88 | , hpCookieRemoteDhtkey = remoteDhtPublicKey | 110 | , hpCookieRemoteDhtkey = remoteDhtPublicKey |
89 | }) -> do | 111 | }) -> do |
90 | sessionsmap <- atomically $ readTVar allsessions | 112 | sessionsmap <- atomically $ readTVar allsessions |
113 | -- Do a lookup, in case we decide to handle the update case differently | ||
91 | case Map.lookup addr sessionsmap of | 114 | case Map.lookup addr sessionsmap of |
92 | Nothing -> do -- create new session | 115 | _ -> do -- create new session |
93 | ncState0 <- atomically $ newTVar Accepted | 116 | ncState0 <- atomically $ newTVar Accepted |
94 | ncTheirPacketNonce0 <- atomically $ newTVar theirBaseNonce | 117 | ncTheirBaseNonce0 <- atomically $ newTVar theirBaseNonce |
95 | n24 <- atomically $ transportNewNonce crypto | 118 | n24 <- atomically $ transportNewNonce crypto |
96 | let myhandshakeData = newHandShakeData crypto hp | 119 | let myhandshakeData = newHandShakeData crypto hp |
97 | plain = encodePlain myhandshakeData | 120 | plain = encodePlain myhandshakeData |
@@ -105,22 +128,77 @@ cryptoNetHandler sessions addr (NetHandshake (Handshake (Cookie n24 ecookie) non | |||
105 | ncHandShake0 <- atomically $ newTVar (Just myhandshake) | 128 | ncHandShake0 <- atomically $ newTVar (Just myhandshake) |
106 | cookie0 <- atomically $ newTVar (Just otherCookie) | 129 | cookie0 <- atomically $ newTVar (Just otherCookie) |
107 | newsession <- generateSecretKey | 130 | newsession <- generateSecretKey |
131 | ncHooks0 <- atomically $ newTVar (defaultHooks sessions) | ||
108 | let netCryptoSession = | 132 | let netCryptoSession = |
109 | NCrypto { ncState = ncState0 | 133 | NCrypto { ncState = ncState0 |
110 | , ncTheirPacketNonce= ncTheirPacketNonce0 | 134 | , ncTheirBaseNonce= ncTheirBaseNonce0 |
111 | , ncMyPacketNonce = ncMyPacketNonce0 | 135 | , ncMyPacketNonce = ncMyPacketNonce0 |
112 | , ncHandShake = ncHandShake0 | 136 | , ncHandShake = ncHandShake0 |
113 | , ncCookie = cookie0 | 137 | , ncCookie = cookie0 |
114 | , ncTheirSessionPublic = Just theirSessionKey | 138 | , ncTheirSessionPublic = Just theirSessionKey |
115 | , ncSessionSecret = newsession | 139 | , ncSessionSecret = newsession |
116 | , ncSockAddr = addr | 140 | , ncSockAddr = addr |
141 | , ncHooks = ncHooks0 | ||
117 | } | 142 | } |
118 | atomically $ modifyTVar allsessions (Map.insert addr netCryptoSession) | 143 | atomically $ modifyTVar allsessions (Map.insert addr netCryptoSession) |
119 | Just netCryptoSession -> return () -- TODO: UPdate existing session | ||
120 | return Nothing | 144 | return Nothing |
121 | cryptoNetHandler sessions addr (NetCrypto (CryptoPacket nonce16 encrypted)) = do | 145 | cryptoNetHandler sessions addr (NetCrypto (CryptoPacket nonce16 encrypted)) = do |
122 | let crypto = transportCrypto sessions | 146 | let crypto = transportCrypto sessions |
147 | allsessions = netCryptoSessions sessions | ||
148 | sessionsmap <- atomically $ readTVar allsessions | ||
123 | -- Handle Encrypted Message | 149 | -- Handle Encrypted Message |
124 | -- TODO | 150 | case Map.lookup addr sessionsmap of |
125 | return Nothing | 151 | Nothing -> return Nothing -- drop packet, we have no session |
126 | -- cryptoNetHandler _ _ _ = return $ Just id | 152 | Just (NCrypto {ncState, ncHooks,ncSessionSecret,ncTheirSessionPublic,ncTheirBaseNonce}) -> do |
153 | theirBaseNonce <- atomically $ readTVar ncTheirBaseNonce | ||
154 | -- Try to decrypt message | ||
155 | let diff :: Word16 | ||
156 | diff = nonce16 - fromIntegral (last2Bytes theirBaseNonce) -- truncating to Word16 | ||
157 | tempNonce <- addtoNonce24 theirBaseNonce (fromIntegral diff) -- expanding to Word | ||
158 | let lr = do -- Either Monad -- | ||
159 | pubkey <- maybeToEither ncTheirSessionPublic | ||
160 | decodePlain =<< decrypt (computeSharedSecret ncSessionSecret pubkey tempNonce) encrypted | ||
161 | case lr of | ||
162 | Left _ -> return Nothing -- decryption failed, ignore packet | ||
163 | Right (CryptoData {bufferStart, bufferEnd, bufferData=cm}) -> do -- decryption succeeded, | ||
164 | -- TODO: Why do I need bufferStart & bufferEnd? | ||
165 | -- | ||
166 | -- buffer_start = highest packet number handled + 1 | ||
167 | -- , recvbuffers buffer_start | ||
168 | -- | ||
169 | -- bufferEnd = sendbuffer buffer_end if lossy, otherwise packet number | ||
170 | -- update ncTheirBaseNonce if necessary | ||
171 | when (diff > 2 * dATA_NUM_THRESHOLD)$ | ||
172 | atomically $ do | ||
173 | y <- readTVar ncTheirBaseNonce | ||
174 | -- all because Storable forces IO... | ||
175 | x <- unsafeIOToSTM $ addtoNonce24 y (fromIntegral dATA_NUM_THRESHOLD) | ||
176 | writeTVar ncTheirBaseNonce y | ||
177 | -- then set session confirmed, | ||
178 | atomically $ writeTVar ncState Confirmed | ||
179 | hookmap <- atomically $ readTVar ncHooks | ||
180 | -- if lossy, just run hook | ||
181 | if lossyness (msgID cm) == Lossy | ||
182 | then | ||
183 | case Map.lookup (cm ^. messageType) hookmap of | ||
184 | Nothing -> return Nothing -- discarding, because no hooks | ||
185 | Just hooks -> flip fix (hooks,cm) $ \loop (hooks,msg) -> do | ||
186 | let _ = cm :: CryptoMessage | ||
187 | case (hooks,cm) of | ||
188 | ([],_) -> return Nothing | ||
189 | (hook:more,cm) -> do | ||
190 | r <- hook addr cm :: IO (Maybe (CryptoMessage -> CryptoMessage)) | ||
191 | case r of | ||
192 | Just f -> loop (more,f cm) | ||
193 | Nothing -> return Nothing -- message consumed | ||
194 | else -- Lossless message, so try to restore sequence | ||
195 | error "todo try to restore sequence of lossless messages" | ||
196 | where | ||
197 | last2Bytes :: Nonce24 -> Word | ||
198 | last2Bytes (Nonce24 bs) = case S.decode (B.drop 22 bs) of | ||
199 | Right n -> n | ||
200 | _ -> error "unreachable-last2Bytes" | ||
201 | dATA_NUM_THRESHOLD = 21845 -- = 65535 / 3 | ||
202 | |||
203 | |||
204 | cryptoDefaultHooks = Map.empty | ||
diff --git a/src/Network/Tox/Crypto/Transport.hs b/src/Network/Tox/Crypto/Transport.hs index 634a7a43..7bc6e67f 100644 --- a/src/Network/Tox/Crypto/Transport.hs +++ b/src/Network/Tox/Crypto/Transport.hs | |||
@@ -43,6 +43,8 @@ module Network.Tox.Crypto.Transport | |||
43 | , sizedN | 43 | , sizedN |
44 | , sizedAtLeastN | 44 | , sizedAtLeastN |
45 | , isIndirectGrpChat | 45 | , isIndirectGrpChat |
46 | , LossyOrLossless(..) | ||
47 | , lossyness | ||
46 | ) where | 48 | ) where |
47 | 49 | ||
48 | import Crypto.Tox | 50 | import Crypto.Tox |
@@ -148,6 +150,10 @@ data CryptoData = CryptoData | |||
148 | , bufferData :: CryptoMessage | 150 | , bufferData :: CryptoMessage |
149 | } | 151 | } |
150 | 152 | ||
153 | instance Serialize CryptoData where | ||
154 | get = CryptoData <$> get <*> get <*> get | ||
155 | put (CryptoData start end dta) = put start >> put end >> put dta | ||
156 | |||
151 | -- The 'UserStatus' equivalent in Presence is: | 157 | -- The 'UserStatus' equivalent in Presence is: |
152 | -- | 158 | -- |
153 | -- data JabberShow = Offline | 159 | -- data JabberShow = Offline |
@@ -176,6 +182,25 @@ instance Sized CryptoMessage where | |||
176 | TwoByte {} -> 2 | 182 | TwoByte {} -> 2 |
177 | UpToN { msgBytes = bs } -> 1 + B.length bs | 183 | UpToN { msgBytes = bs } -> 1 + B.length bs |
178 | 184 | ||
185 | instance Serialize CryptoMessage where | ||
186 | get = do | ||
187 | i <- get :: Get MessageID | ||
188 | n <- remaining | ||
189 | case msgSizeParam i of | ||
190 | Just (True,1) -> return $ OneByte i | ||
191 | Just (True,2) -> TwoByte i <$> get | ||
192 | _ -> UpToN i <$> getByteString n | ||
193 | |||
194 | put (OneByte i) = putWord8 (fromIntegral . fromEnum $ i) | ||
195 | put (TwoByte i b) = do putWord8 (fromIntegral . fromEnum $ i) | ||
196 | putWord8 b | ||
197 | put (UpToN i x) = do putWord8 (fromIntegral . fromEnum $ i) | ||
198 | putByteString x | ||
199 | |||
200 | instance Serialize MessageID where | ||
201 | get = toEnum . fromIntegral <$> getWord8 | ||
202 | put x = putWord8 (fromIntegral . fromEnum $ x) | ||
203 | |||
179 | erCompat :: String -> a | 204 | erCompat :: String -> a |
180 | erCompat lens = error $ "Use of '" ++ lens ++ "' lens on incompatible CryptoMessage type" | 205 | erCompat lens = error $ "Use of '" ++ lens ++ "' lens on incompatible CryptoMessage type" |
181 | 206 | ||
@@ -381,6 +406,12 @@ data MessageType = Msg MessageID | |||
381 | | GrpMsg MessageName | 406 | | GrpMsg MessageName |
382 | deriving (Eq,Show) | 407 | deriving (Eq,Show) |
383 | 408 | ||
409 | instance Ord MessageType where | ||
410 | compare (Msg x) (Msg y) = compare x y | ||
411 | compare (GrpMsg x) (GrpMsg y) = compare x y | ||
412 | compare (Msg _) (GrpMsg _) = LT | ||
413 | compare (GrpMsg _) (Msg _) = GT | ||
414 | |||
384 | class HasMessageType x where | 415 | class HasMessageType x where |
385 | getMessageType :: x -> MessageType | 416 | getMessageType :: x -> MessageType |
386 | setMessageType :: x -> MessageType -> x | 417 | setMessageType :: x -> MessageType -> x |
@@ -564,6 +595,16 @@ isIndirectGrpChat MESSAGE_GROUPCHAT = True | |||
564 | isIndirectGrpChat LOSSY_GROUPCHAT = True | 595 | isIndirectGrpChat LOSSY_GROUPCHAT = True |
565 | isIndirectGrpChat _ = False | 596 | isIndirectGrpChat _ = False |
566 | 597 | ||
598 | data LossyOrLossless = UnknownLossyness | Lossless | Lossy | ||
599 | deriving (Eq,Ord,Enum,Show,Bounded) | ||
600 | |||
601 | lossyness :: MessageID -> LossyOrLossless | ||
602 | lossyness (fromEnum -> x) | x < 3 = Lossy | ||
603 | lossyness (fromEnum -> x) | x >= 16, x < 192 = Lossless | ||
604 | lossyness (fromEnum -> x) | x >= 192, x < 255 = Lossy | ||
605 | lossyness (fromEnum -> 255) = Lossless | ||
606 | lossyness _ = UnknownLossyness | ||
607 | |||
567 | -- TODO: Flesh this out. | 608 | -- TODO: Flesh this out. |
568 | data MessageID -- First byte indicates data | 609 | data MessageID -- First byte indicates data |
569 | = Padding -- ^ 0 padding (skipped until we hit a non zero (data id) byte) | 610 | = Padding -- ^ 0 padding (skipped until we hit a non zero (data id) byte) |