diff options
Diffstat (limited to 'ToxToXMPP.hs')
-rw-r--r-- | ToxToXMPP.hs | 94 |
1 files changed, 81 insertions, 13 deletions
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 #-} |
6 | module ToxToXMPP where | 6 | module ToxToXMPP where |
7 | 7 | ||
8 | import Control.Monad | ||
8 | import Crypto.Tox | 9 | import Crypto.Tox |
9 | import Data.Conduit as C | 10 | import Data.Conduit as C |
10 | import qualified Data.Conduit.List as CL | 11 | import qualified Data.Conduit.List as CL |
12 | import Data.Function | ||
11 | import Data.Monoid | 13 | import Data.Monoid |
12 | import qualified Data.Text as T | 14 | import qualified Data.Text as T |
13 | ;import Data.Text (Text) | 15 | ;import Data.Text (Text) |
14 | import Data.Word | ||
15 | import Data.Text.Encoding as T | 16 | import Data.Text.Encoding as T |
17 | import Data.Word | ||
16 | import Data.XML.Types as XML | 18 | import Data.XML.Types as XML |
17 | import EventUtil | 19 | import EventUtil |
18 | import Network.Address | 20 | import Network.Address |
19 | import Network.Tox.Crypto.Transport as Tox | 21 | import Network.Tox.Crypto.Transport as Tox hiding (UserStatus (..)) |
20 | import Network.Tox.NodeId | 22 | import Network.Tox.NodeId |
21 | import Util (unsplitJID) | 23 | import Util (unsplitJID) |
22 | import XMPPServer as XMPP | 24 | import XMPPServer as XMPP |
23 | 25 | ||
26 | available :: StanzaType | ||
27 | available = PresenceStatus { presenceShow = Available | ||
28 | , presencePriority = Nothing | ||
29 | , presenceStatus = [] | ||
30 | , presenceWhiteList = [] | ||
31 | } | ||
32 | |||
24 | xmppHostname :: PublicKey -> Text | 33 | xmppHostname :: PublicKey -> Text |
25 | xmppHostname k = T.pack $ show (key2id k) ++ ".tox" | 34 | xmppHostname k = T.pack $ show (key2id k) ++ ".tox" |
26 | 35 | ||
27 | toxToXmpp :: Monad m => SockAddr -> PublicKey -> Text -> Conduit Tox.CryptoMessage m XML.Event | 36 | toxUserStatus :: Word8 -> JabberShow |
37 | toxUserStatus 0 = Available | ||
38 | toxUserStatus 1 = Away | ||
39 | toxUserStatus 2 = DoNotDisturb | ||
40 | toxUserStatus _ = Away -- Default, shouldn't occur. | ||
41 | |||
42 | toxToXmpp :: Monad m => SockAddr -> PublicKey -> Text -> ConduitM Tox.CryptoMessage XML.Event m () | ||
28 | toxToXmpp laddr me theirhost = do | 43 | toxToXmpp 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 | |||
93 | xmppPresence :: Monad m => Text -> Maybe Text -> StanzaType -> ConduitM i XML.Event m () | ||
94 | xmppPresence 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 | ||
56 | xmppTyping :: Monad m => Text | 124 | xmppTyping :: 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 () |
61 | xmppTyping namespace mfrom mto x = | 129 | xmppTyping 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 () |
84 | xmppInstantMessage namespace mfrom mto style text = do | 152 | xmppInstantMessage 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") |