diff options
-rw-r--r-- | ToxChat.hs | 107 | ||||
-rw-r--r-- | ToxToXMPP.hs | 71 | ||||
-rw-r--r-- | examples/dhtd.hs | 30 | ||||
-rw-r--r-- | src/Data/Tox/Msg.hs | 10 |
4 files changed, 179 insertions, 39 deletions
diff --git a/ToxChat.hs b/ToxChat.hs new file mode 100644 index 00000000..fba5d33b --- /dev/null +++ b/ToxChat.hs | |||
@@ -0,0 +1,107 @@ | |||
1 | {-# LANGUAGE CPP #-} | ||
2 | {-# LANGUAGE PartialTypeSignatures #-} | ||
3 | module ToxChat | ||
4 | ( module Chat | ||
5 | , module ToxChat | ||
6 | ) where | ||
7 | |||
8 | import Control.Concurrent.STM | ||
9 | import Control.Monad | ||
10 | import Data.Char | ||
11 | import Data.Dependent.Sum | ||
12 | import Data.Function | ||
13 | import qualified Data.Map as Map | ||
14 | ;import Data.Map (Map) | ||
15 | import Data.Maybe | ||
16 | import qualified Data.Text as T | ||
17 | ;import Data.Text (Text) | ||
18 | import Debug.Trace | ||
19 | |||
20 | #ifdef THREAD_DEBUG | ||
21 | import Control.Concurrent.Lifted.Instrument | ||
22 | #else | ||
23 | import Control.Concurrent.Lifted | ||
24 | import GHC.Conc (labelThread) | ||
25 | #endif | ||
26 | |||
27 | import Chat | ||
28 | import Data.Tox.Msg | ||
29 | import DebugTag | ||
30 | import DPut | ||
31 | import MUC | ||
32 | import Network.Tox.AggregateSession | ||
33 | |||
34 | forkUntilSignaled :: String -> STM (IO ()) -> IO (IO ()) | ||
35 | forkUntilSignaled lbl action = do | ||
36 | quitSignal <- newTVarIO False | ||
37 | t <- forkIO $ do | ||
38 | fix $ \loop -> join $ atomically | ||
39 | $ orElse (do readTVar quitSignal >>= check | ||
40 | return $ return ()) | ||
41 | (fmap (>> loop) $ action) | ||
42 | labelThread t lbl | ||
43 | return $ atomically (writeTVar quitSignal True) | ||
44 | |||
45 | data RoomData k = RoomData | ||
46 | { room :: Maybe (Room k) | ||
47 | , pendingInvites :: [(AggregateSession,Int,Maybe Text,Invite)] | ||
48 | } | ||
49 | |||
50 | chatevents :: (Ord conkey, Show conkey) => TVar (Map Text (RoomData conkey)) -> STM (IO ()) | ||
51 | chatevents rsvar = do | ||
52 | rs <- readTVar rsvar | ||
53 | if Map.null rs | ||
54 | then retry | ||
55 | else do | ||
56 | ios <- flip Map.traverseWithKey rs $ \rkey r -> do | ||
57 | ps <- maybe (return mempty) roomPending $ room r | ||
58 | trace ("roomPending " ++ show ps) $ return () | ||
59 | case Map.toList ps of | ||
60 | (k,t):ts -> do | ||
61 | roomCommit (fromJust $ room r) k t | ||
62 | modifyTVar' rsvar | ||
63 | $ Map.adjust (\d -> d { pendingInvites = take 1 (pendingInvites d)}) | ||
64 | rkey | ||
65 | return $ do | ||
66 | dput XJabber $ "toxchat-committed " ++ show (rkey,length ts,k,t) | ||
67 | case membershipEffect $ chatMessage t of | ||
68 | MembershipEffect Outside Inside -> do | ||
69 | forM_ (pendingInvites r) $ \(c,i,jid,inv) -> do | ||
70 | -- TODO b <- checkCompatible me them c | ||
71 | dput XJabber $ "Replying to invite " ++ show inv | ||
72 | dispatchMessage c (Just i) | ||
73 | $ Pkt INVITE_GROUPCHAT ==> inv { invite = AcceptedInvite } | ||
74 | _ -> return () | ||
75 | _ -> retry | ||
76 | return $ foldl1 (>>) ios | ||
77 | |||
78 | data InviteCache m = InviteCache | ||
79 | { rememberInvite :: AggregateSession -> Int {- session ID -} -> Maybe Text {- origin -} -> Invite -> m () | ||
80 | , lookupInvite :: Text {- chatroom JID -} -> m (Maybe Invite) | ||
81 | } | ||
82 | |||
83 | forkToxChat :: MUC -> IO (IO (), InviteCache IO) | ||
84 | forkToxChat muc = do | ||
85 | (chan, rs) <- atomically $ do | ||
86 | c <- dupTChan (mucChan muc) | ||
87 | rs <- newTVar Map.empty -- TODO: This seems to redundantly duplicate MUC{mucRooms}. | ||
88 | return (c,rs) | ||
89 | quit <- forkUntilSignaled "toxchat" $ orElse (chatevents rs) $ do | ||
90 | e <- readTChan chan | ||
91 | case e of | ||
92 | MUCCreate room jid nick r -> modifyTVar' rs $ | ||
93 | Map.alter (\d -> Just $ RoomData (Just r) (maybe [] pendingInvites d)) | ||
94 | (T.toLower room) | ||
95 | return $ case e of | ||
96 | MUCCreate room jid nick _ -> | ||
97 | dput XJabber $ unwords $ map T.unpack | ||
98 | [ "MUCCreate", room, jid, nick ] | ||
99 | return $ (,) quit InviteCache | ||
100 | { rememberInvite = \c i jid inv -> do | ||
101 | dput XJabber $ "remember invite " ++ show (T.pack $ show $ inviteChatID inv, i, jid ) | ||
102 | atomically $ do | ||
103 | modifyTVar' rs $ Map.alter (\d -> Just $ RoomData (room =<< (d:: Maybe (RoomData _))) | ||
104 | ( ((c,i,jid,inv) :) $ maybe [] pendingInvites d)) | ||
105 | (T.pack $ map toLower $ show $ inviteChatID inv) | ||
106 | , lookupInvite = \_ -> return Nothing | ||
107 | } | ||
diff --git a/ToxToXMPP.hs b/ToxToXMPP.hs index 4814553d..1420c642 100644 --- a/ToxToXMPP.hs +++ b/ToxToXMPP.hs | |||
@@ -8,7 +8,7 @@ module ToxToXMPP where | |||
8 | 8 | ||
9 | import Control.Monad | 9 | import Control.Monad |
10 | import Crypto.Tox | 10 | import Crypto.Tox |
11 | import Data.Conduit as C | 11 | import Conduit as C |
12 | import qualified Data.Conduit.List as CL | 12 | import qualified Data.Conduit.List as CL |
13 | import Data.Dependent.Sum | 13 | import Data.Dependent.Sum |
14 | import Data.Function | 14 | import Data.Function |
@@ -44,19 +44,38 @@ toxUserStatus Tox.Away = XMPP.Away | |||
44 | toxUserStatus Busy = DoNotDisturb | 44 | toxUserStatus Busy = DoNotDisturb |
45 | toxUserStatus _ = XMPP.Away -- Default, shouldn't occur. | 45 | toxUserStatus _ = XMPP.Away -- Default, shouldn't occur. |
46 | 46 | ||
47 | toxToXmpp :: Monad m => SockAddr -> PublicKey -> Text -> ConduitM Tox.CryptoMessage XML.Event m () | 47 | -- Currently unused, see note in 'toxJID'. |
48 | toxToXmpp laddr me theirhost = do | 48 | toJabberResource :: Int -> Maybe Text |
49 | toJabberResource addr = T.pack . show <$> Just (positive addr) | ||
50 | where | ||
51 | positive addr | addr < 0 = 2 * negate addr + 1 | ||
52 | | otherwise = 2 * addr | ||
53 | |||
54 | toxJID :: Text -> Int -> Text | ||
55 | toxJID theirhost addr = | ||
56 | -- unsplitJID (Nothing, theirhost, toJabberResource addr) | ||
57 | -- | ||
58 | -- Not encoding the Tox session ID because Pidgin apparently doesn't | ||
59 | -- cope well with resource IDs occuring on bare hostname JIDs. | ||
60 | unsplitJID (Nothing, theirhost, Nothing) | ||
61 | |||
62 | toxToXmpp :: Monad m => | ||
63 | (Int -> Maybe Text -> Invite -> m ()) | ||
64 | -> SockAddr | ||
65 | -> PublicKey | ||
66 | -> Text | ||
67 | -> ConduitM (Int,Tox.CryptoMessage) XML.Event m () | ||
68 | toxToXmpp store_invite _ me theirhost = do | ||
49 | CL.sourceList $ XMPP.greet' "jabber:server" theirhost | 69 | CL.sourceList $ XMPP.greet' "jabber:server" theirhost |
50 | let me_u = Nothing | 70 | let me_u = Nothing |
51 | me_h = xmppHostname me | 71 | me_h = xmppHostname me |
52 | im_from = (Just $ unsplitJID (Nothing, theirhost, Nothing)) -- /from/ | ||
53 | im_to = (Just $ unsplitJID | 72 | im_to = (Just $ unsplitJID |
54 | ( me_u | 73 | ( me_u |
55 | -- /to/ should match local address of this node. | 74 | -- /to/ should match local address of this node. |
56 | , me_h | 75 | , me_h |
57 | , Nothing)) | 76 | , Nothing)) |
58 | let | 77 | let |
59 | statelessMessages = \case | 78 | statelessMessages addr im_from = \case |
60 | 79 | ||
61 | Pkt MESSAGE :=> Identity bs -> | 80 | Pkt MESSAGE :=> Identity bs -> |
62 | xmppInstantMessage "jabber:server" im_from im_to [] bs | 81 | xmppInstantMessage "jabber:server" im_from im_to [] bs |
@@ -75,7 +94,8 @@ toxToXmpp laddr me theirhost = do | |||
75 | [ attr "style" "font-weight:bold; color:red" ] | 94 | [ attr "style" "font-weight:bold; color:red" ] |
76 | ("INVITE(todo)" <> (T.pack $ show ginv)) | 95 | ("INVITE(todo)" <> (T.pack $ show ginv)) |
77 | case invite ginv of | 96 | case invite ginv of |
78 | GroupInvite {} -> xmppInvite "jabber:server" me_h (fromJust im_from) (fromJust im_to) ginv | 97 | GroupInvite {} -> do C.lift $ store_invite addr im_from ginv |
98 | xmppInvite "jabber:server" me_h (fromJust im_from) (fromJust im_to) ginv | ||
79 | _ -> return () | 99 | _ -> return () |
80 | 100 | ||
81 | toxmsg -> do | 101 | toxmsg -> do |
@@ -84,24 +104,27 @@ toxToXmpp laddr me theirhost = do | |||
84 | (T.pack $ "Unhandled message: " ++ show (msgID toxmsg)) | 104 | (T.pack $ "Unhandled message: " ++ show (msgID toxmsg)) |
85 | 105 | ||
86 | flip fix available $ \loop status -> do | 106 | flip fix available $ \loop status -> do |
87 | let go (Pkt USERSTATUS :=> Identity st) = do | 107 | m <- await |
88 | let status' = status { presenceShow = toxUserStatus st } | 108 | forM_ m $ \(addr,x) -> do |
89 | xmppPresence "jabber:server" im_from status' | 109 | let im_from = (Just $ toxJID theirhost addr) |
90 | loop status' | 110 | case x of |
91 | 111 | Pkt USERSTATUS :=> Identity st -> do | |
92 | go (Pkt STATUSMESSAGE :=> Identity bs) = do | 112 | let status' = status { presenceShow = toxUserStatus st } |
93 | let status' = status { presenceStatus = [("",bs)] } | 113 | xmppPresence "jabber:server" im_from status' |
94 | xmppPresence "jabber:server" im_from status' | 114 | loop status' |
95 | loop status' | 115 | |
96 | 116 | Pkt STATUSMESSAGE :=> Identity bs -> do | |
97 | go (Pkt ONLINE :=> _) = do | 117 | let status' = status { presenceStatus = [("",bs)] } |
98 | xmppPresence "jabber:server" im_from status | 118 | xmppPresence "jabber:server" im_from status' |
99 | loop status | 119 | loop status' |
100 | 120 | ||
101 | go x = do | 121 | Pkt ONLINE :=> _ -> do |
102 | statelessMessages x | 122 | xmppPresence "jabber:server" im_from status |
103 | loop status | 123 | loop status |
104 | await >>= mapM_ go | 124 | |
125 | x -> do | ||
126 | statelessMessages addr im_from x | ||
127 | loop status | ||
105 | 128 | ||
106 | xmppPresence :: Monad m => Text -> Maybe Text -> StanzaType -> ConduitM i XML.Event m () | 129 | xmppPresence :: Monad m => Text -> Maybe Text -> StanzaType -> ConduitM i XML.Event m () |
107 | xmppPresence namespace mjid p = do | 130 | xmppPresence namespace mjid p = do |
diff --git a/examples/dhtd.hs b/examples/dhtd.hs index a602b772..6756b14b 100644 --- a/examples/dhtd.hs +++ b/examples/dhtd.hs | |||
@@ -115,6 +115,7 @@ import qualified Connection.Tcp as Tcp (ConnectionEvent(..),noCleanUp,TCPStatus) | |||
115 | import DPut | 115 | import DPut |
116 | import DebugTag | 116 | import DebugTag |
117 | import LocalChat | 117 | import LocalChat |
118 | import ToxChat | ||
118 | import MUC | 119 | import MUC |
119 | 120 | ||
120 | 121 | ||
@@ -1022,7 +1023,7 @@ clientSession s@Session{..} sock cnum h = do | |||
1022 | ] | 1023 | ] |
1023 | rs = map mkrow cs | 1024 | rs = map mkrow cs |
1024 | return $ do | 1025 | return $ do |
1025 | hPutClient h $ showColumns rs | 1026 | hPutClient h $ "connections\n" ++ showColumns rs |
1026 | 1027 | ||
1027 | ("help", s) | Just DHT{..} <- Map.lookup netname dhts | 1028 | ("help", s) | Just DHT{..} <- Map.lookup netname dhts |
1028 | -> cmd0 $ do | 1029 | -> cmd0 $ do |
@@ -1157,11 +1158,12 @@ newXmmpSink session@(Tox.NCrypto { ncOutgoingQueue = outGoingQVar }) = C.awaitFo | |||
1157 | 1158 | ||
1158 | onNewToxSession :: XMPPServer | 1159 | onNewToxSession :: XMPPServer |
1159 | -> TVar (Map.Map Uniq24 AggregateSession) | 1160 | -> TVar (Map.Map Uniq24 AggregateSession) |
1161 | -> InviteCache IO | ||
1160 | -> ContactInfo extra | 1162 | -> ContactInfo extra |
1161 | -> SockAddr | 1163 | -> SockAddr |
1162 | -> Tox.Session | 1164 | -> Tox.Session |
1163 | -> IO () | 1165 | -> IO () |
1164 | onNewToxSession sv ssvar ContactInfo{accounts} addrTox netcrypto = do | 1166 | onNewToxSession sv ssvar invc ContactInfo{accounts} addrTox netcrypto = do |
1165 | let them s = Tox.longTermKey $ runIdentity cookie -- remote tox key | 1167 | let them s = Tox.longTermKey $ runIdentity cookie -- remote tox key |
1166 | where Tox.Cookie _ cookie = Tox.handshakeCookie (sReceivedHandshake s) | 1168 | where Tox.Cookie _ cookie = Tox.handshakeCookie (sReceivedHandshake s) |
1167 | 1169 | ||
@@ -1193,7 +1195,7 @@ onNewToxSession sv ssvar ContactInfo{accounts} addrTox netcrypto = do | |||
1193 | _ -> retry) | 1195 | _ -> retry) |
1194 | (return ()) | 1196 | (return ()) |
1195 | toxSnk = C.mapM_ (uncurry $ dispatchMessage c) | 1197 | toxSnk = C.mapM_ (uncurry $ dispatchMessage c) |
1196 | xmppSrc = toxSrc .| C.map snd .| toxToXmpp addrTox (me s) (xmppHostname $ them s) | 1198 | xmppSrc = toxSrc .| toxToXmpp (rememberInvite invc c) addrTox (me s) (xmppHostname $ them s) |
1197 | xmppSnk = flushPassThrough xmppToTox | 1199 | xmppSnk = flushPassThrough xmppToTox |
1198 | .| C.mapMaybe (\case Flush -> Nothing | 1200 | .| C.mapMaybe (\case Flush -> Nothing |
1199 | Chunk x -> Just (Nothing,x)) | 1201 | Chunk x -> Just (Nothing,x)) |
@@ -1288,11 +1290,14 @@ selectManager mtman tcp profile = case T.splitAt 43 profile of | |||
1288 | 1290 | ||
1289 | initTox :: Options | 1291 | initTox :: Options |
1290 | -> TVar (Map.Map Uniq24 AggregateSession) | 1292 | -> TVar (Map.Map Uniq24 AggregateSession) |
1291 | -> TVar Tox.AnnouncedKeys -> Maybe XMPPServer -> IO ( Maybe (Tox.Tox JabberClients) , IO () | 1293 | -> TVar Tox.AnnouncedKeys |
1294 | -> Maybe XMPPServer | ||
1295 | -> InviteCache IO | ||
1296 | -> IO ( Maybe (Tox.Tox JabberClients) , IO () | ||
1292 | , Map.Map String DHT | 1297 | , Map.Map String DHT |
1293 | , IO [SockAddr] | 1298 | , IO [SockAddr] |
1294 | , [SockAddr]) | 1299 | , [SockAddr]) |
1295 | initTox opts ssvar keysdb mbxmpp = case porttox opts of | 1300 | initTox opts ssvar keysdb mbxmpp invc = case porttox opts of |
1296 | "" -> return (Nothing,return (), Map.empty, return [],[]) | 1301 | "" -> return (Nothing,return (), Map.empty, return [],[]) |
1297 | toxport -> do | 1302 | toxport -> do |
1298 | addrTox <- getBindAddress toxport (ip6tox opts) | 1303 | addrTox <- getBindAddress toxport (ip6tox opts) |
@@ -1301,7 +1306,7 @@ initTox opts ssvar keysdb mbxmpp = case porttox opts of | |||
1301 | addrTox | 1306 | addrTox |
1302 | (case mbxmpp of | 1307 | (case mbxmpp of |
1303 | Nothing -> \_ _ _ -> return () | 1308 | Nothing -> \_ _ _ -> return () |
1304 | Just xmpp -> onNewToxSession xmpp ssvar) | 1309 | Just xmpp -> onNewToxSession xmpp ssvar invc) |
1305 | (dhtkey opts) | 1310 | (dhtkey opts) |
1306 | (\_ _ -> return ()) -- TODO: TCP relay send | 1311 | (\_ _ -> return ()) -- TODO: TCP relay send |
1307 | (quitTox, toxStrap4, toxStrap6) <- Tox.forkTox tox True | 1312 | (quitTox, toxStrap4, toxStrap6) <- Tox.forkTox tox True |
@@ -1493,11 +1498,12 @@ initJabber :: Options | |||
1493 | -> Announcer | 1498 | -> Announcer |
1494 | -> Maybe (Tox.Tox JabberClients) | 1499 | -> Maybe (Tox.Tox JabberClients) |
1495 | -> Map.Map String DHT | 1500 | -> Map.Map String DHT |
1501 | -> MUC | ||
1496 | -> IO ( Maybe XMPPServer | 1502 | -> IO ( Maybe XMPPServer |
1497 | , Maybe (Manager TCPStatus T.Text) | 1503 | , Maybe (Manager TCPStatus T.Text) |
1498 | , Maybe (PresenceState Pending) | 1504 | , Maybe (PresenceState Pending) |
1499 | ) | 1505 | ) |
1500 | initJabber opts ssvar announcer mbtox toxdhts = case portxmpp opts of | 1506 | initJabber opts ssvar announcer mbtox toxdhts toxchat = case portxmpp opts of |
1501 | "" -> return (Nothing,Nothing,Nothing) | 1507 | "" -> return (Nothing,Nothing,Nothing) |
1502 | p -> do | 1508 | p -> do |
1503 | cport <- getBindAddress p True{-IPv6 supported-} | 1509 | cport <- getBindAddress p True{-IPv6 supported-} |
@@ -1522,7 +1528,8 @@ initJabber opts ssvar announcer mbtox toxdhts = case portxmpp opts of | |||
1522 | state <- newPresenceState cw tman sv (selectManager tman tcp) | 1528 | state <- newPresenceState cw tman sv (selectManager tman tcp) |
1523 | chat <- atomically newMUC | 1529 | chat <- atomically newMUC |
1524 | quitChatService <- forkLocalChat chat | 1530 | quitChatService <- forkLocalChat chat |
1525 | let chats = Map.singleton "chat" chat | 1531 | let chats = Map.fromList [ ("local", chat) |
1532 | , ("ngc", toxchat) ] | ||
1526 | forkXmpp sv (presenceHooks state chats (verbosity opts) (Just cport) (Just sport)) | 1533 | forkXmpp sv (presenceHooks state chats (verbosity opts) (Just cport) (Just sport)) |
1527 | conns <- xmppConnections sv | 1534 | conns <- xmppConnections sv |
1528 | return (Just sv, Just conns, Just state) | 1535 | return (Just sv, Just conns, Just state) |
@@ -1546,6 +1553,9 @@ main = do | |||
1546 | forM ([minBound .. maxBound]::[DebugTag]) setQuiet | 1553 | forM ([minBound .. maxBound]::[DebugTag]) setQuiet |
1547 | forM (verboseTags opts) setVerbose | 1554 | forM (verboseTags opts) setVerbose |
1548 | 1555 | ||
1556 | toxchat <- atomically newMUC | ||
1557 | (quitToxChat,invc) <- forkToxChat toxchat | ||
1558 | |||
1549 | (quitBt,btdhts,btips,baddrs) <- case portbt opts of | 1559 | (quitBt,btdhts,btips,baddrs) <- case portbt opts of |
1550 | "" -> return (return (), Map.empty,return [],[]) | 1560 | "" -> return (return (), Map.empty,return [],[]) |
1551 | p -> do | 1561 | p -> do |
@@ -1638,9 +1648,9 @@ main = do | |||
1638 | ssvar <- atomically $ newTVar Map.empty | 1648 | ssvar <- atomically $ newTVar Map.empty |
1639 | rec (mbtox,quitTox,toxdhts,toxips,(taddrs::[SockAddr]),msv,mconns,mstate) <- do | 1649 | rec (mbtox,quitTox,toxdhts,toxips,(taddrs::[SockAddr]),msv,mconns,mstate) <- do |
1640 | 1650 | ||
1641 | (mbtox,quitTox,toxdhts,toxips,(taddrs::[SockAddr])) <- initTox opts ssvar keysdb msv | 1651 | (mbtox,quitTox,toxdhts,toxips,(taddrs::[SockAddr])) <- initTox opts ssvar keysdb msv invc |
1642 | 1652 | ||
1643 | (msv,mconns,mstate) <- initJabber opts ssvar announcer mbtox toxdhts | 1653 | (msv,mconns,mstate) <- initJabber opts ssvar announcer mbtox toxdhts toxchat |
1644 | 1654 | ||
1645 | return (mbtox,quitTox,toxdhts,toxips,(taddrs::[SockAddr]),msv,mconns,mstate) | 1655 | return (mbtox,quitTox,toxdhts,toxips,(taddrs::[SockAddr]),msv,mconns,mstate) |
1646 | 1656 | ||
diff --git a/src/Data/Tox/Msg.hs b/src/Data/Tox/Msg.hs index e8c26a56..6550fd95 100644 --- a/src/Data/Tox/Msg.hs +++ b/src/Data/Tox/Msg.hs | |||
@@ -261,14 +261,14 @@ instance Show ChatID where | |||
261 | show (ChatID ed) = showToken32 ed | 261 | show (ChatID ed) = showToken32 ed |
262 | 262 | ||
263 | data InviteType = GroupInvite { groupName :: Text } | 263 | data InviteType = GroupInvite { groupName :: Text } |
264 | | AccptedInvite | 264 | | AcceptedInvite |
265 | | ConfirmedInvite { inviteNodes :: [NodeInfo] } | 265 | | ConfirmedInvite { inviteNodes :: [NodeInfo] } |
266 | deriving (Eq,Show) | 266 | deriving (Eq,Show) |
267 | 267 | ||
268 | instance Sized InviteType where | 268 | instance Sized InviteType where |
269 | size = VarSize $ \x -> case x of | 269 | size = VarSize $ \x -> case x of |
270 | GroupInvite name -> B.length (T.encodeUtf8 name) | 270 | GroupInvite name -> B.length (T.encodeUtf8 name) |
271 | AccptedInvite -> 0 | 271 | AcceptedInvite -> 0 |
272 | ConfirmedInvite ns -> 0 -- TODO: size of node list. | 272 | ConfirmedInvite ns -> 0 -- TODO: size of node list. |
273 | 273 | ||
274 | data Invite = Invite | 274 | data Invite = Invite |
@@ -292,20 +292,20 @@ instance Serialize Invite where | |||
292 | Invite chatid chatkey <$> case invite_type of | 292 | Invite chatid chatkey <$> case invite_type of |
293 | 0 -> do bs <- remaining >>= getBytes -- TODO: size can be determined from group shared state. | 293 | 0 -> do bs <- remaining >>= getBytes -- TODO: size can be determined from group shared state. |
294 | return $ GroupInvite $ decodeUtf8 bs | 294 | return $ GroupInvite $ decodeUtf8 bs |
295 | 1 -> return AccptedInvite | 295 | 1 -> return AcceptedInvite |
296 | 2 -> return $ ConfirmedInvite [] -- TODO: decode nodes | 296 | 2 -> return $ ConfirmedInvite [] -- TODO: decode nodes |
297 | 297 | ||
298 | put x = do | 298 | put x = do |
299 | putWord8 254 -- GP_FRIEND_INVITE | 299 | putWord8 254 -- GP_FRIEND_INVITE |
300 | putWord8 $ case invite x of | 300 | putWord8 $ case invite x of |
301 | GroupInvite {} -> 0 -- GROUP_INVITE | 301 | GroupInvite {} -> 0 -- GROUP_INVITE |
302 | AccptedInvite -> 1 -- GROUP_INVITE_ACCEPTED | 302 | AcceptedInvite -> 1 -- GROUP_INVITE_ACCEPTED |
303 | ConfirmedInvite {} -> 2 -- GROUP_INVITE_CONFIRMATION | 303 | ConfirmedInvite {} -> 2 -- GROUP_INVITE_CONFIRMATION |
304 | put $ inviteChatID x | 304 | put $ inviteChatID x |
305 | put $ key2id $ inviteChatKey x | 305 | put $ key2id $ inviteChatKey x |
306 | case invite x of | 306 | case invite x of |
307 | GroupInvite name -> putByteString $ encodeUtf8 name | 307 | GroupInvite name -> putByteString $ encodeUtf8 name |
308 | AccptedInvite -> return () | 308 | AcceptedInvite -> return () |
309 | ConfirmedInvite ns -> return () -- TODO: encode nodes. | 309 | ConfirmedInvite ns -> return () -- TODO: encode nodes. |
310 | 310 | ||
311 | instance Packet Invite where | 311 | instance Packet Invite where |