summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoe Crayne <joe@jerkface.net>2018-07-06 05:24:37 -0400
committerJoe Crayne <joe@jerkface.net>2018-07-06 05:25:36 -0400
commitea3f4e6543b6dddd94898c945a8ad2c24a46ae77 (patch)
tree6bff1ac5a1c7ff97cf6fb9387bf1cffe201d6a3f
parent95d6ae45e07707eb93f083ecf02d8f0df0015496 (diff)
tox-to-xmpp: presence updates.
-rw-r--r--Presence/Presence.hs24
-rw-r--r--ToxToXMPP.hs94
2 files changed, 100 insertions, 18 deletions
diff --git a/Presence/Presence.hs b/Presence/Presence.hs
index 4ca49f78..59926d13 100644
--- a/Presence/Presence.hs
+++ b/Presence/Presence.hs
@@ -178,7 +178,7 @@ data LocalPresence = LocalPresence
178 } 178 }
179 179
180data RemotePresence = RemotePresence 180data RemotePresence = RemotePresence
181 { resources :: Map Text Stanza 181 { resources :: Map ResourceName Stanza
182 -- , localSubscribers :: Map Text () 182 -- , localSubscribers :: Map Text ()
183 -- ^ subset of clientsByUser who should be 183 -- ^ subset of clientsByUser who should be
184 -- notified about this presence. 184 -- notified about this presence.
@@ -764,7 +764,14 @@ informPeerPresence state k stanza = do
764 -- Presence must indicate full JID with resource... 764 -- Presence must indicate full JID with resource...
765 dput XJabber $ "xmppInformPeerPresence checking from address..." 765 dput XJabber $ "xmppInformPeerPresence checking from address..."
766 forM_ (stanzaFrom stanza) $ \from -> do 766 forM_ (stanzaFrom stanza) $ \from -> do
767 let (muser,h,mresource) = splitJID from 767 let (muser0,h,mresource0) = splitJID from
768 -- We'll allow the case that user and resource are simultaneously
769 -- absent. They will be stored in the remotesByPeer map using the
770 -- empty string. This is to accomodate the tox protocol which didn't
771 -- anticipate a single peer would have multiple users or front-ends.
772 (muser,mresource) = case (muser0,mresource0) of
773 (Nothing,Nothing) -> (Just "", Just "")
774 _ -> (muser0,mresource0)
768 dput XJabber $ "xmppInformPeerPresence from = " ++ show from 775 dput XJabber $ "xmppInformPeerPresence from = " ++ show from
769 -- forM_ mresource $ \resource -> do 776 -- forM_ mresource $ \resource -> do
770 forM_ muser $ \user -> do 777 forM_ muser $ \user -> do
@@ -806,15 +813,22 @@ informPeerPresence state k stanza = do
806 con <- liftMaybe $ Map.lookup ck ktc 813 con <- liftMaybe $ Map.lookup ck ktc
807 return (ck,con,client) 814 return (ck,con,client)
808 dput XJabber $ "xmppInformPeerPresence (length clients="++show (length clients)++")" 815 dput XJabber $ "xmppInformPeerPresence (length clients="++show (length clients)++")"
816 (ctyp,cprof) <- atomically $ do
817 mconn <- Map.lookup k <$> readTVar (pkeyToChan state)
818 return $ fromMaybe (XMPP,".") $ do
819 ConnectionData _ ctyp cprof <- auxData <$> mconn
820 return (ctyp,cprof)
809 forM_ clients $ \(ck,con,client) -> do 821 forM_ clients $ \(ck,con,client) -> do
810 -- (TODO: appropriately authorized clients only.) 822 -- (TODO: appropriately authorized clients only.)
811 -- For now, all "available" clients (available = sent initial presence) 823 -- For now, all "available" clients (available = sent initial presence)
812 is_avail <- atomically $ clientIsAvailable client 824 is_avail <- atomically $ clientIsAvailable client
813 when is_avail $ do 825 when is_avail $ do
814 dput XJabber $ "reversing for client: " ++ show from 826 dput XJabber $ "reversing for client: " ++ show from
815 froms <- do -- flip (maybe $ return [from]) k . const $ do 827 froms <- case ctyp of
816 (_,trip) <- multiplyJIDForClient ck from 828 Tox | clientProfile client == cprof -> return [from]
817 return (map unsplitJID trip) 829 _ -> do -- flip (maybe $ return [from]) k . const $ do
830 (_,trip) <- multiplyJIDForClient ck from
831 return (map unsplitJID trip)
818 832
819 dput XJabber $ "sending to client: " ++ show (stanzaType stanza,froms) 833 dput XJabber $ "sending to client: " ++ show (stanzaType stanza,froms)
820 forM_ froms $ \from' -> do 834 forM_ froms $ \from' -> do
diff --git a/ToxToXMPP.hs b/ToxToXMPP.hs
index 8b2544d7..7208a1d1 100644
--- a/ToxToXMPP.hs
+++ b/ToxToXMPP.hs
@@ -5,26 +5,41 @@
5{-# LANGUAGE ViewPatterns #-} 5{-# LANGUAGE ViewPatterns #-}
6module ToxToXMPP where 6module ToxToXMPP where
7 7
8import Control.Monad
8import Crypto.Tox 9import Crypto.Tox
9import Data.Conduit as C 10import Data.Conduit as C
10import qualified Data.Conduit.List as CL 11import qualified Data.Conduit.List as CL
12import Data.Function
11import Data.Monoid 13import Data.Monoid
12import qualified Data.Text as T 14import qualified Data.Text as T
13 ;import Data.Text (Text) 15 ;import Data.Text (Text)
14import Data.Word
15import Data.Text.Encoding as T 16import Data.Text.Encoding as T
17import Data.Word
16import Data.XML.Types as XML 18import Data.XML.Types as XML
17import EventUtil 19import EventUtil
18import Network.Address 20import Network.Address
19import Network.Tox.Crypto.Transport as Tox 21import Network.Tox.Crypto.Transport as Tox hiding (UserStatus (..))
20import Network.Tox.NodeId 22import Network.Tox.NodeId
21import Util (unsplitJID) 23import Util (unsplitJID)
22import XMPPServer as XMPP 24import XMPPServer as XMPP
23 25
26available :: StanzaType
27available = PresenceStatus { presenceShow = Available
28 , presencePriority = Nothing
29 , presenceStatus = []
30 , presenceWhiteList = []
31 }
32
24xmppHostname :: PublicKey -> Text 33xmppHostname :: PublicKey -> Text
25xmppHostname k = T.pack $ show (key2id k) ++ ".tox" 34xmppHostname k = T.pack $ show (key2id k) ++ ".tox"
26 35
27toxToXmpp :: Monad m => SockAddr -> PublicKey -> Text -> Conduit Tox.CryptoMessage m XML.Event 36toxUserStatus :: Word8 -> JabberShow
37toxUserStatus 0 = Available
38toxUserStatus 1 = Away
39toxUserStatus 2 = DoNotDisturb
40toxUserStatus _ = Away -- Default, shouldn't occur.
41
42toxToXmpp :: Monad m => SockAddr -> PublicKey -> Text -> ConduitM Tox.CryptoMessage XML.Event m ()
28toxToXmpp laddr me theirhost = do 43toxToXmpp laddr me theirhost = do
29 CL.sourceList $ XMPP.greet' "jabber:server" theirhost 44 CL.sourceList $ XMPP.greet' "jabber:server" theirhost
30 let me_u = Nothing 45 let me_u = Nothing
@@ -35,29 +50,82 @@ toxToXmpp laddr me theirhost = do
35 -- /to/ should match local address of this node. 50 -- /to/ should match local address of this node.
36 , me_h 51 , me_h
37 , Nothing)) 52 , Nothing))
38 awaitForever $ \case 53 let
54 statelessMessages = \case
39 55
40 UpToN { msgID = MESSAGE 56 UpToN MESSAGE bs ->
41 , msgBytes = bs }
42 -> do
43 xmppInstantMessage "jabber:server" im_from im_to [] (T.decodeUtf8 bs) 57 xmppInstantMessage "jabber:server" im_from im_to [] (T.decodeUtf8 bs)
44 58
45 TwoByte TYPING st -> xmppTyping "jabber:server" im_from im_to st 59 TwoByte TYPING st -> xmppTyping "jabber:server" im_from im_to st
46 60
61 UpToN NICKNAME bs ->
62 xmppInstantMessage "jabber:server" im_from im_to
63 [ attr "style" "font-weight:bold; color:red" ]
64 ("NICKNAME(todo) " <> T.decodeUtf8 bs)
65
47 toxmsg | msgID toxmsg == PacketRequest -> return () 66 toxmsg | msgID toxmsg == PacketRequest -> return ()
48 67
49 toxmsg -> do 68 toxmsg -> do
50 xmppInstantMessage "jabber:server" 69 xmppInstantMessage "jabber:server" im_from im_to
51 im_from
52 im_to -- /to/ should match local address of this node.
53 [ attr "style" "font-weight:bold; color:red" ] 70 [ attr "style" "font-weight:bold; color:red" ]
54 (T.pack $ show $ msgID toxmsg) 71 (T.pack $ "Unhandled message: " ++ show (msgID toxmsg))
72
73 flip fix available $ \loop status -> do
74 let go (TwoByte USERSTATUS st) = do
75 let status' = status { presenceShow = toxUserStatus st }
76 xmppPresence "jabber:server" im_from status'
77 loop status'
78
79 go (UpToN STATUSMESSAGE bs) = do
80 let status' = status { presenceStatus = [("",T.decodeUtf8 bs)] }
81 xmppPresence "jabber:server" im_from status'
82 loop status'
83
84 go (OneByte ONLINE) = do
85 xmppPresence "jabber:server" im_from status
86 loop status
87
88 go x = do
89 statelessMessages x
90 loop status
91 await >>= mapM_ go
92
93xmppPresence :: Monad m => Text -> Maybe Text -> StanzaType -> ConduitM i XML.Event m ()
94xmppPresence namespace mjid p = do
95 let ns n = n { nameNamespace = Just namespace }
96 setFrom = maybe id
97 (\jid -> (attr "from" jid :) )
98 mjid
99 typ Offline = [attr "type" "unavailable"]
100 typ _ = []
101 shw ExtendedAway = ["xa"]
102 shw Chatty = ["chat"]
103 shw Away = ["away"]
104 shw DoNotDisturb = ["dnd"]
105 shw _ = []
106 jabberShow stat =
107 [ EventBeginElement "{jabber:client}show" []
108 , EventContent (ContentText stat)
109 , EventEndElement "{jabber:client}show" ]
110 C.yield $ EventBeginElement (ns "presence") (setFrom $ typ $ presenceShow p)
111 mapM_ C.yield $ shw (presenceShow p) >>= jabberShow
112 forM_ (presencePriority p) $ \prio -> do
113 C.yield $ EventBeginElement (ns "priority") []
114 C.yield $ EventContent $ ContentText (T.pack $ show prio)
115 C.yield $ EventEndElement (ns "priority")
116 forM_ (presenceStatus p) $ \(lang,txt) -> do
117 let atts | T.null lang = []
118 | otherwise = [ ("xml:lang", [ContentText lang]) ]
119 C.yield $ EventBeginElement (ns "status") atts
120 C.yield $ EventContent $ ContentText txt
121 C.yield $ EventEndElement (ns "status")
122 C.yield $ EventEndElement (ns "presence")
55 123
56xmppTyping :: Monad m => Text 124xmppTyping :: Monad m => Text
57 -> Maybe Text 125 -> Maybe Text
58 -> Maybe Text 126 -> Maybe Text
59 -> Word8 127 -> Word8
60 -> ConduitM i Event m () 128 -> ConduitM i XML.Event m ()
61xmppTyping namespace mfrom mto x = 129xmppTyping namespace mfrom mto x =
62 let ns n = n { nameNamespace = Just namespace } 130 let ns n = n { nameNamespace = Just namespace }
63 st = case x of 131 st = case x of
@@ -80,7 +148,7 @@ xmppInstantMessage :: Monad m => Text
80 -> Maybe Text 148 -> Maybe Text
81 -> [(Name, [Content])] 149 -> [(Name, [Content])]
82 -> Text 150 -> Text
83 -> ConduitM i Event m () 151 -> ConduitM i XML.Event m ()
84xmppInstantMessage namespace mfrom mto style text = do 152xmppInstantMessage namespace mfrom mto style text = do
85 let ns n = n { nameNamespace = Just namespace } 153 let ns n = n { nameNamespace = Just namespace }
86 C.yield $ EventBeginElement (ns "message") 154 C.yield $ EventBeginElement (ns "message")