diff options
Diffstat (limited to 'Presence/XMPPServer.hs')
-rw-r--r-- | Presence/XMPPServer.hs | 61 |
1 files changed, 59 insertions, 2 deletions
diff --git a/Presence/XMPPServer.hs b/Presence/XMPPServer.hs index 6e0f5c5f..7eb0fbc5 100644 --- a/Presence/XMPPServer.hs +++ b/Presence/XMPPServer.hs | |||
@@ -192,8 +192,10 @@ peerKeyToResolvedName k@(PeerKey { callBackAddress=addr }) = do | |||
192 | return $ maybe (peerKeyToText k) Text.pack mname | 192 | return $ maybe (peerKeyToText k) Text.pack mname |
193 | 193 | ||
194 | 194 | ||
195 | wlog :: String -> IO () | ||
195 | wlog s = putStrLn s | 196 | wlog s = putStrLn s |
196 | where _ = s :: String | 197 | |
198 | wlogb :: ByteString -> IO () | ||
197 | wlogb s = Strict8.putStrLn s | 199 | wlogb s = Strict8.putStrLn s |
198 | 200 | ||
199 | xmlStream :: ReadCommand -> WriteCommand -> ( Source IO XML.Event | 201 | xmlStream :: ReadCommand -> WriteCommand -> ( Source IO XML.Event |
@@ -226,10 +228,14 @@ type FlagCommand = STM Bool | |||
226 | type ReadCommand = IO (Maybe ByteString) | 228 | type ReadCommand = IO (Maybe ByteString) |
227 | type WriteCommand = ByteString -> IO Bool | 229 | type WriteCommand = ByteString -> IO Bool |
228 | 230 | ||
231 | cloneStanza :: StanzaWrap (TChan a) -> STM (StanzaWrap (TChan a)) | ||
229 | cloneStanza stanza = do | 232 | cloneStanza stanza = do |
230 | dupped <- cloneTChan (stanzaChan stanza) | 233 | dupped <- cloneTChan (stanzaChan stanza) |
231 | return stanza { stanzaChan = dupped } | 234 | return stanza { stanzaChan = dupped } |
232 | 235 | ||
236 | copyToChannel | ||
237 | :: MonadIO m => | ||
238 | (Event -> a) -> TChan a -> TVar (Maybe [Event]) -> ConduitM Event Event m () | ||
233 | copyToChannel f chan closer_stack = awaitForever copy | 239 | copyToChannel f chan closer_stack = awaitForever copy |
234 | where | 240 | where |
235 | copy x = do | 241 | copy x = do |
@@ -251,6 +257,7 @@ prettyPrint prefix = | |||
251 | =$= CB.lines | 257 | =$= CB.lines |
252 | =$ CL.mapM_ (wlogb . (prefix <>)) | 258 | =$ CL.mapM_ (wlogb . (prefix <>)) |
253 | 259 | ||
260 | swapNamespace :: Monad m => Text -> Text -> ConduitM Event Event m () | ||
254 | swapNamespace old new = awaitForever swapit | 261 | swapNamespace old new = awaitForever swapit |
255 | where | 262 | where |
256 | swapit (EventBeginElement n as) | nameNamespace n==Just old = | 263 | swapit (EventBeginElement n as) | nameNamespace n==Just old = |
@@ -259,6 +266,7 @@ swapNamespace old new = awaitForever swapit | |||
259 | yield $ EventEndElement (n { nameNamespace = Just new }) | 266 | yield $ EventEndElement (n { nameNamespace = Just new }) |
260 | swapit x = yield x | 267 | swapit x = yield x |
261 | 268 | ||
269 | fixHeaders :: Monad m => Stanza -> ConduitM Event Event m () | ||
262 | fixHeaders Stanza { stanzaTo=mto, stanzaFrom=mfrom } = do | 270 | fixHeaders Stanza { stanzaTo=mto, stanzaFrom=mfrom } = do |
263 | x <- await | 271 | x <- await |
264 | maybe (return ()) f x | 272 | maybe (return ()) f x |
@@ -272,6 +280,7 @@ fixHeaders Stanza { stanzaTo=mto, stanzaFrom=mfrom } = do | |||
272 | as'' = maybe as' (\from->attr "from" from:as') mfrom | 280 | as'' = maybe as' (\from->attr "from" from:as') mfrom |
273 | 281 | ||
274 | 282 | ||
283 | sendModifiedStanzaToPeer :: Stanza -> TChan Stanza -> IO () | ||
275 | sendModifiedStanzaToPeer stanza chan = do | 284 | sendModifiedStanzaToPeer stanza chan = do |
276 | (echan,clsrs,quitvar) <- conduitToChan c | 285 | (echan,clsrs,quitvar) <- conduitToChan c |
277 | ioWriteChan chan | 286 | ioWriteChan chan |
@@ -283,6 +292,7 @@ sendModifiedStanzaToPeer stanza chan = do | |||
283 | where | 292 | where |
284 | c = stanzaToConduit stanza =$= swapNamespace "jabber:client" "jabber:server" =$= fixHeaders stanza | 293 | c = stanzaToConduit stanza =$= swapNamespace "jabber:client" "jabber:server" =$= fixHeaders stanza |
285 | 294 | ||
295 | sendModifiedStanzaToClient :: Stanza -> TChan Stanza -> IO () | ||
286 | sendModifiedStanzaToClient stanza chan = do | 296 | sendModifiedStanzaToClient stanza chan = do |
287 | (echan,clsrs,quitvar) <- conduitToChan c | 297 | (echan,clsrs,quitvar) <- conduitToChan c |
288 | ioWriteChan chan | 298 | ioWriteChan chan |
@@ -295,6 +305,8 @@ sendModifiedStanzaToClient stanza chan = do | |||
295 | c = stanzaToConduit stanza =$= swapNamespace "jabber:server" "jabber:client" =$= fixHeaders stanza | 305 | c = stanzaToConduit stanza =$= swapNamespace "jabber:server" "jabber:client" =$= fixHeaders stanza |
296 | 306 | ||
297 | -- id,to, and from are taken as-is from reply list | 307 | -- id,to, and from are taken as-is from reply list |
308 | -- todo: this should probably be restricted to IO monad | ||
309 | sendReply :: (Functor m, MonadIO m) => TMVar () -> StanzaType -> [Event] -> TChan Stanza -> m () | ||
298 | sendReply donevar stype reply replychan = do | 310 | sendReply donevar stype reply replychan = do |
299 | if null reply then return () | 311 | if null reply then return () |
300 | else do | 312 | else do |
@@ -363,8 +375,13 @@ C->Unrecognized <bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"/> | |||
363 | C->Unrecognized </iq> | 375 | C->Unrecognized </iq> |
364 | -} | 376 | -} |
365 | 377 | ||
378 | ioWriteChan :: MonadIO m => TChan a -> a -> m () | ||
366 | ioWriteChan c v = liftIO . atomically $ writeTChan c v | 379 | ioWriteChan c v = liftIO . atomically $ writeTChan c v |
367 | 380 | ||
381 | parsePresenceStatus | ||
382 | :: ( MonadThrow m | ||
383 | , MonadIO m | ||
384 | ) => Text -> NestingXML o m (Maybe StanzaType) | ||
368 | parsePresenceStatus ns = do | 385 | parsePresenceStatus ns = do |
369 | 386 | ||
370 | let toStat "away" = Away | 387 | let toStat "away" = Away |
@@ -399,6 +416,10 @@ parsePresenceStatus ns = do | |||
399 | , presencePriority = prio | 416 | , presencePriority = prio |
400 | , presenceStatus = status | 417 | , presenceStatus = status |
401 | } | 418 | } |
419 | grokPresence | ||
420 | :: ( MonadThrow m | ||
421 | , MonadIO m | ||
422 | ) => Text -> XML.Event -> NestingXML o m (Maybe StanzaType) | ||
402 | grokPresence ns stanzaTag = do | 423 | grokPresence ns stanzaTag = do |
403 | let typ = lookupAttrib "type" (tagAttrs stanzaTag) | 424 | let typ = lookupAttrib "type" (tagAttrs stanzaTag) |
404 | case typ of | 425 | case typ of |
@@ -413,6 +434,10 @@ grokPresence ns stanzaTag = do | |||
413 | Just "subscribe" -> return . Just $ PresenceRequestSubscription True | 434 | Just "subscribe" -> return . Just $ PresenceRequestSubscription True |
414 | _ -> return Nothing | 435 | _ -> return Nothing |
415 | 436 | ||
437 | parseMessage | ||
438 | :: ( MonadThrow m | ||
439 | , MonadIO m | ||
440 | ) => Text -> XML.Event -> NestingXML o m StanzaType | ||
416 | parseMessage ns stanza = do | 441 | parseMessage ns stanza = do |
417 | let bodytag = Name { nameNamespace = Just ns | 442 | let bodytag = Name { nameNamespace = Just ns |
418 | , nameLocalName = "body" | 443 | , nameLocalName = "body" |
@@ -462,11 +487,19 @@ parseMessage ns stanza = do | |||
462 | msgThread = if msgThreadContent th/="" then Just th else Nothing | 487 | msgThread = if msgThreadContent th/="" then Just th else Nothing |
463 | } | 488 | } |
464 | 489 | ||
490 | grokMessage | ||
491 | :: ( MonadThrow m | ||
492 | , MonadIO m | ||
493 | ) => Text -> XML.Event -> NestingXML o m (Maybe StanzaType) | ||
465 | grokMessage ns stanzaTag = do | 494 | grokMessage ns stanzaTag = do |
466 | t <- parseMessage ns stanzaTag | 495 | t <- parseMessage ns stanzaTag |
467 | return $ Just t | 496 | return $ Just t |
468 | 497 | ||
469 | grokStanza "jabber:server" stanzaTag = | 498 | |
499 | |||
500 | grokStanza | ||
501 | :: Text -> XML.Event -> NestingXML o IO (Maybe StanzaType) | ||
502 | ggrokStanza "jabber:server" stanzaTag = | ||
470 | case () of | 503 | case () of |
471 | _ | stanzaTag `isServerIQOf` "get" -> grokStanzaIQGet stanzaTag | 504 | _ | stanzaTag `isServerIQOf` "get" -> grokStanzaIQGet stanzaTag |
472 | _ | stanzaTag `isServerIQOf` "result" -> grokStanzaIQResult stanzaTag | 505 | _ | stanzaTag `isServerIQOf` "result" -> grokStanzaIQResult stanzaTag |
@@ -606,6 +639,7 @@ readUntilNothing ch = do | |||
606 | return (x:xs)) | 639 | return (x:xs)) |
607 | x | 640 | x |
608 | 641 | ||
642 | streamFeatures :: Text -> [XML.Event] | ||
609 | streamFeatures "jabber:client" = | 643 | streamFeatures "jabber:client" = |
610 | [ EventBeginElement (streamP "features") [] | 644 | [ EventBeginElement (streamP "features") [] |
611 | , EventBeginElement "{urn:ietf:params:xml:ns:xmpp-bind}bind" [] | 645 | , EventBeginElement "{urn:ietf:params:xml:ns:xmpp-bind}bind" [] |
@@ -625,6 +659,7 @@ streamFeatures "jabber:server" = | |||
625 | [] | 659 | [] |
626 | 660 | ||
627 | 661 | ||
662 | greet' :: Text -> Text -> [XML.Event] | ||
628 | greet' namespace host = | 663 | greet' namespace host = |
629 | [ EventBeginDocument | 664 | [ EventBeginDocument |
630 | , EventBeginElement (streamP "stream") | 665 | , EventBeginElement (streamP "stream") |
@@ -636,6 +671,7 @@ greet' namespace host = | |||
636 | ] | 671 | ] |
637 | ] ++ streamFeatures namespace | 672 | ] ++ streamFeatures namespace |
638 | 673 | ||
674 | consid :: Maybe Text -> [(Name, [Content])] -> [(Name, [Content])] | ||
639 | consid Nothing = id | 675 | consid Nothing = id |
640 | consid (Just sid) = (("id",[ContentText sid]):) | 676 | consid (Just sid) = (("id",[ContentText sid]):) |
641 | 677 | ||
@@ -644,6 +680,7 @@ data XMPPState | |||
644 | = PingSlot | 680 | = PingSlot |
645 | deriving (Eq,Ord) | 681 | deriving (Eq,Ord) |
646 | 682 | ||
683 | mkname :: Text -> Text -> XML.Name | ||
647 | mkname namespace name = (Name name (Just namespace) Nothing) | 684 | mkname namespace name = (Name name (Just namespace) Nothing) |
648 | 685 | ||
649 | makePing :: Text -> Maybe Text -> Text -> Text -> [XML.Event] | 686 | makePing :: Text -> Maybe Text -> Text -> Text -> [XML.Event] |
@@ -660,6 +697,7 @@ makePing namespace mid to from = | |||
660 | , EventEndElement "{urn:xmpp:ping}ping" | 697 | , EventEndElement "{urn:xmpp:ping}ping" |
661 | , EventEndElement $ mkname namespace "iq"] | 698 | , EventEndElement $ mkname namespace "iq"] |
662 | 699 | ||
700 | makePong :: Text -> Maybe Text -> Text -> Text -> [XML.Event] | ||
663 | makePong namespace mid to from = | 701 | makePong namespace mid to from = |
664 | -- Note: similar to session reply | 702 | -- Note: similar to session reply |
665 | [ EventBeginElement (mkname namespace "iq") | 703 | [ EventBeginElement (mkname namespace "iq") |
@@ -685,6 +723,7 @@ iq_bind_reply mid jid = | |||
685 | , EventEndElement "{jabber:client}iq" | 723 | , EventEndElement "{jabber:client}iq" |
686 | ] | 724 | ] |
687 | 725 | ||
726 | iq_session_reply :: Maybe Text -> Text -> [XML.Event] | ||
688 | iq_session_reply mid host = | 727 | iq_session_reply mid host = |
689 | -- Note: similar to Pong | 728 | -- Note: similar to Pong |
690 | [ EventBeginElement "{jabber:client}iq" | 729 | [ EventBeginElement "{jabber:client}iq" |
@@ -694,6 +733,7 @@ iq_session_reply mid host = | |||
694 | , EventEndElement "{jabber:client}iq" | 733 | , EventEndElement "{jabber:client}iq" |
695 | ] | 734 | ] |
696 | 735 | ||
736 | iq_service_unavailable :: Maybe Text -> Text -> XML.Name -> [XML.Event] | ||
697 | iq_service_unavailable mid host {- mjid -} req = | 737 | iq_service_unavailable mid host {- mjid -} req = |
698 | [ EventBeginElement "{jabber:client}iq" | 738 | [ EventBeginElement "{jabber:client}iq" |
699 | (consid mid [("type",[ContentText "error"]) | 739 | (consid mid [("type",[ContentText "error"]) |
@@ -731,6 +771,7 @@ wrapStanzaList xs = do | |||
731 | mfrom = m >>= lookupAttrib "from" . tagAttrs | 771 | mfrom = m >>= lookupAttrib "from" . tagAttrs |
732 | mid = m >>= lookupAttrib "id" . tagAttrs | 772 | mid = m >>= lookupAttrib "id" . tagAttrs |
733 | 773 | ||
774 | wrapStanzaConduit :: Monad m => StanzaWrap a -> ConduitM Event (Either (StanzaWrap Event) Event) m () | ||
734 | wrapStanzaConduit stanza = do | 775 | wrapStanzaConduit stanza = do |
735 | mfirst <- await | 776 | mfirst <- await |
736 | flip (maybe $ return ()) mfirst $ \first -> do | 777 | flip (maybe $ return ()) mfirst $ \first -> do |
@@ -749,6 +790,7 @@ greet namespace = | |||
749 | ] | 790 | ] |
750 | -} | 791 | -} |
751 | 792 | ||
793 | goodbye :: [XML.Event] | ||
752 | goodbye = | 794 | goodbye = |
753 | [ EventEndElement (streamP "stream") | 795 | [ EventEndElement (streamP "stream") |
754 | , EventEndDocument | 796 | , EventEndDocument |
@@ -888,6 +930,7 @@ data PeerState | |||
888 | | PeerConnected (TChan Stanza) | 930 | | PeerConnected (TChan Stanza) |
889 | -} | 931 | -} |
890 | 932 | ||
933 | peerKey :: (Socket,SockAddr) -> IO (ConnectionKey,SockAddr) | ||
891 | peerKey (sock,addr) = do | 934 | peerKey (sock,addr) = do |
892 | peer <- | 935 | peer <- |
893 | sIsConnected sock >>= \c -> | 936 | sIsConnected sock >>= \c -> |
@@ -896,6 +939,7 @@ peerKey (sock,addr) = do | |||
896 | laddr <- getSocketName sock | 939 | laddr <- getSocketName sock |
897 | return $ (PeerKey (peer `withPort` fromIntegral peerport),laddr) | 940 | return $ (PeerKey (peer `withPort` fromIntegral peerport),laddr) |
898 | 941 | ||
942 | clientKey :: (Socket,SockAddr) -> IO (ConnectionKey,SockAddr) | ||
899 | clientKey (sock,addr) = do | 943 | clientKey (sock,addr) = do |
900 | paddr <- getPeerName sock | 944 | paddr <- getPeerName sock |
901 | return $ (ClientKey addr,paddr) | 945 | return $ (ClientKey addr,paddr) |
@@ -934,6 +978,9 @@ xmlifyRosterItems solicited stype set = mapM_ item (Set.toList set) | |||
934 | else [] ) | 978 | else [] ) |
935 | yield $ EventEndElement "{jabber:iq:roster}item" | 979 | yield $ EventEndElement "{jabber:iq:roster}item" |
936 | 980 | ||
981 | conduitToChan | ||
982 | :: Conduit () IO Event | ||
983 | -> IO (TChan Event, TVar (Maybe [Event]), TMVar a) | ||
937 | conduitToChan c = do | 984 | conduitToChan c = do |
938 | chan <- atomically newTChan | 985 | chan <- atomically newTChan |
939 | clsrs <- atomically $ newTVar (Just []) | 986 | clsrs <- atomically $ newTVar (Just []) |
@@ -943,6 +990,11 @@ conduitToChan c = do | |||
943 | atomically $ writeTVar clsrs Nothing | 990 | atomically $ writeTVar clsrs Nothing |
944 | return (chan,clsrs,quitvar) | 991 | return (chan,clsrs,quitvar) |
945 | 992 | ||
993 | sendRoster :: | ||
994 | StanzaWrap a | ||
995 | -> XMPPServerParameters | ||
996 | -> TChan (StanzaWrap (TChan Event)) | ||
997 | -> IO () | ||
946 | sendRoster query xmpp replyto = do | 998 | sendRoster query xmpp replyto = do |
947 | let k = case stanzaOrigin query of | 999 | let k = case stanzaOrigin query of |
948 | NetworkOrigin k _ -> Just k | 1000 | NetworkOrigin k _ -> Just k |
@@ -999,6 +1051,11 @@ socketFromKey sv k = do | |||
999 | -- Shouldnt happen anyway. | 1051 | -- Shouldnt happen anyway. |
1000 | Just cd -> return $ cdata cd | 1052 | Just cd -> return $ cdata cd |
1001 | 1053 | ||
1054 | monitor :: | ||
1055 | Server ConnectionKey SockAddr | ||
1056 | -> ConnectionParameters ConnectionKey SockAddr | ||
1057 | -> XMPPServerParameters | ||
1058 | -> IO b | ||
1002 | monitor sv params xmpp = do | 1059 | monitor sv params xmpp = do |
1003 | chan <- return $ serverEvent sv | 1060 | chan <- return $ serverEvent sv |
1004 | stanzas <- atomically newTChan | 1061 | stanzas <- atomically newTChan |