diff options
-rw-r--r-- | Connection.hs | 53 | ||||
-rw-r--r-- | Presence/Server.hs | 39 | ||||
-rw-r--r-- | Presence/XMPPServer.hs | 96 |
3 files changed, 142 insertions, 46 deletions
diff --git a/Connection.hs b/Connection.hs new file mode 100644 index 00000000..e3e9a8ca --- /dev/null +++ b/Connection.hs | |||
@@ -0,0 +1,53 @@ | |||
1 | {-# LANGUAGE DeriveFunctor #-} | ||
2 | module Connection where | ||
3 | |||
4 | import Control.Arrow | ||
5 | import Control.Concurrent.STM | ||
6 | import qualified Data.Map as Map | ||
7 | ;import Data.Map (Map) | ||
8 | |||
9 | import PingMachine | ||
10 | |||
11 | data Status status | ||
12 | = Dormant | ||
13 | | InProgress status | ||
14 | | Established | ||
15 | deriving Functor | ||
16 | |||
17 | data Policy | ||
18 | = RefusingToConnect | ||
19 | | OpenToConnect | ||
20 | | TryingToConnect | ||
21 | |||
22 | data Connection status = Connection | ||
23 | { connStatus :: STM (Status status) | ||
24 | , connPolicy :: STM Policy | ||
25 | , connPingLogic :: PingMachine | ||
26 | } | ||
27 | deriving Functor | ||
28 | |||
29 | data Manager status k = Manager | ||
30 | { setPolicy :: k -> Policy -> IO () | ||
31 | , connections :: STM (Map k (Connection status)) | ||
32 | , stringToKey :: String -> IO (Maybe k) -- TODO: It'd be nice for this to be pure, but | ||
33 | -- currently we do a DNS resolve. | ||
34 | , showProgress :: status -> String | ||
35 | , showKey :: k -> String | ||
36 | } | ||
37 | |||
38 | addManagers :: (Ord kA, Ord kB) => | ||
39 | Manager statusA kA | ||
40 | -> Manager statusB kB | ||
41 | -> Manager (Either statusA statusB) (Either kA kB) | ||
42 | addManagers mgrA mgrB = Manager | ||
43 | { setPolicy = either (setPolicy mgrA) (setPolicy mgrB) | ||
44 | , connections = do | ||
45 | as <- Map.toList <$> connections mgrA | ||
46 | bs <- Map.toList <$> connections mgrB | ||
47 | return $ Map.fromList $ map (Left *** fmap Left) as ++ map (Right *** fmap Right) bs | ||
48 | , stringToKey = \str -> do | ||
49 | ka <- fmap Left <$> stringToKey mgrA str | ||
50 | maybe (fmap Right <$> stringToKey mgrB str) (return . Just) ka | ||
51 | , showProgress = either (showProgress mgrA) (showProgress mgrB) | ||
52 | , showKey = either (showKey mgrA) (showKey mgrB) | ||
53 | } | ||
diff --git a/Presence/Server.hs b/Presence/Server.hs index 46b32b81..da0a6973 100644 --- a/Presence/Server.hs +++ b/Presence/Server.hs | |||
@@ -20,7 +20,9 @@ | |||
20 | -- | 20 | -- |
21 | -- * interface tweaks | 21 | -- * interface tweaks |
22 | -- | 22 | -- |
23 | module Server where | 23 | module Server |
24 | ( module Server | ||
25 | , module PingMachine ) where | ||
24 | 26 | ||
25 | import Data.ByteString (ByteString,hGetNonBlocking) | 27 | import Data.ByteString (ByteString,hGetNonBlocking) |
26 | import qualified Data.ByteString.Char8 as S -- ( hPutStrLn, hPutStr, pack) | 28 | import qualified Data.ByteString.Char8 as S -- ( hPutStrLn, hPutStr, pack) |
@@ -76,6 +78,9 @@ import InterruptibleDelay | |||
76 | import PingMachine | 78 | import PingMachine |
77 | import Network.StreamServer | 79 | import Network.StreamServer |
78 | import Network.SocketLike hiding (sClose) | 80 | import Network.SocketLike hiding (sClose) |
81 | import qualified Connection as G | ||
82 | ;import Connection (Manager (..), Policy(..)) | ||
83 | |||
79 | 84 | ||
80 | type Microseconds = Int | 85 | type Microseconds = Int |
81 | 86 | ||
@@ -762,3 +767,35 @@ warn str = S.hPutStrLn stderr str >> hFlush stderr | |||
762 | 767 | ||
763 | debugNoise :: Monad m => t -> m () | 768 | debugNoise :: Monad m => t -> m () |
764 | debugNoise str = return () | 769 | debugNoise str = return () |
770 | |||
771 | data TCPStatus = AwaitingRead | AwaitingWrite | ||
772 | |||
773 | tcpManager :: Show conkey => | ||
774 | (conkey -> (SockAddr, ConnectionParameters conkey u, Miliseconds)) | ||
775 | -> (String -> IO (Maybe conkey)) | ||
776 | -> Server conkey u releaseKey x | ||
777 | -> Manager TCPStatus conkey | ||
778 | tcpManager grokKey parseKey sv = Manager | ||
779 | { setPolicy = \k -> \case | ||
780 | TryingToConnect -> control sv $ case grokKey k of | ||
781 | (saddr,params,ms) -> ConnectWithEndlessRetry saddr params ms | ||
782 | OpenToConnect -> return () -- TODO | ||
783 | RefusingToConnect -> return () -- TODO | ||
784 | , connections = fmap exportConnection <$> readTVar (conmap sv) | ||
785 | , stringToKey = parseKey | ||
786 | , showProgress = \case | ||
787 | AwaitingRead -> "awaiting inbound" | ||
788 | AwaitingWrite -> "awaiting outbound" | ||
789 | , showKey = show | ||
790 | } | ||
791 | |||
792 | exportConnection :: ConnectionRecord u -> G.Connection TCPStatus | ||
793 | exportConnection (ConnectionRecord ckont cstate cdata) = G.Connection | ||
794 | { G.connStatus = return $ case cstate of | ||
795 | SaneConnection {} -> G.Established | ||
796 | ConnectionPair {} -> G.Established | ||
797 | ReadOnlyConnection {} -> G.InProgress AwaitingWrite | ||
798 | WriteOnlyConnection {} -> G.InProgress AwaitingRead | ||
799 | , G.connPolicy = return TryingToConnect | ||
800 | , G.connPingLogic = connPingTimer cstate | ||
801 | } | ||
diff --git a/Presence/XMPPServer.hs b/Presence/XMPPServer.hs index 3505a0a2..b23bb42e 100644 --- a/Presence/XMPPServer.hs +++ b/Presence/XMPPServer.hs | |||
@@ -8,7 +8,7 @@ module XMPPServer | |||
8 | , ConnectionKey(..) | 8 | , ConnectionKey(..) |
9 | , XMPPServerParameters(..) | 9 | , XMPPServerParameters(..) |
10 | , XMPPServer | 10 | , XMPPServer |
11 | , addPeer | 11 | , xmppConnections |
12 | , StanzaWrap(..) | 12 | , StanzaWrap(..) |
13 | , Stanza(..) | 13 | , Stanza(..) |
14 | , StanzaType(..) | 14 | , StanzaType(..) |
@@ -81,11 +81,12 @@ import qualified Data.Map as Map | |||
81 | import Data.Set (Set, (\\) ) | 81 | import Data.Set (Set, (\\) ) |
82 | import qualified Data.Set as Set | 82 | import qualified Data.Set as Set |
83 | import Data.String ( IsString(..) ) | 83 | import Data.String ( IsString(..) ) |
84 | import qualified System.Random | 84 | import qualified System.Random |
85 | import Data.Void (Void) | 85 | import Data.Void (Void) |
86 | import System.Endian (toBE32) | 86 | import System.Endian (toBE32) |
87 | import Control.Applicative | 87 | import Control.Applicative |
88 | import System.IO | 88 | import System.IO |
89 | import qualified Connection | ||
89 | 90 | ||
90 | peerport :: PortNumber | 91 | peerport :: PortNumber |
91 | peerport = 5269 | 92 | peerport = 5269 |
@@ -103,7 +104,7 @@ data JabberShow = Offline | |||
103 | | Chatty | 104 | | Chatty |
104 | deriving (Show,Enum,Ord,Eq,Read) | 105 | deriving (Show,Enum,Ord,Eq,Read) |
105 | 106 | ||
106 | data MessageThread = MessageThread { | 107 | data MessageThread = MessageThread { |
107 | msgThreadParent :: Maybe Text, | 108 | msgThreadParent :: Maybe Text, |
108 | msgThreadContent :: Text | 109 | msgThreadContent :: Text |
109 | } | 110 | } |
@@ -202,9 +203,9 @@ data XMPPServerParameters = | |||
202 | , xmppInformPeerPresence :: ConnectionKey -> Stanza -> IO () | 203 | , xmppInformPeerPresence :: ConnectionKey -> Stanza -> IO () |
203 | , -- | Called when a remote peer requests our status. | 204 | , -- | Called when a remote peer requests our status. |
204 | xmppAnswerProbe :: ConnectionKey -> Stanza -> TChan Stanza -> IO () | 205 | xmppAnswerProbe :: ConnectionKey -> Stanza -> TChan Stanza -> IO () |
205 | , xmppClientSubscriptionRequest :: IO () -> ConnectionKey -> Stanza -> TChan Stanza -> IO () | 206 | , xmppClientSubscriptionRequest :: IO () -> ConnectionKey -> Stanza -> TChan Stanza -> IO () |
206 | , -- | Called when a remote peer sends subscription request. | 207 | , -- | Called when a remote peer sends subscription request. |
207 | xmppPeerSubscriptionRequest :: IO () -> ConnectionKey -> Stanza -> TChan Stanza -> IO () | 208 | xmppPeerSubscriptionRequest :: IO () -> ConnectionKey -> Stanza -> TChan Stanza -> IO () |
208 | , xmppClientInformSubscription :: IO () -> ConnectionKey -> Stanza -> IO () | 209 | , xmppClientInformSubscription :: IO () -> ConnectionKey -> Stanza -> IO () |
209 | , -- | Called when a remote peer informs us of our subscription status. | 210 | , -- | Called when a remote peer informs us of our subscription status. |
210 | xmppPeerInformSubscription :: IO () -> ConnectionKey -> Stanza -> IO () | 211 | xmppPeerInformSubscription :: IO () -> ConnectionKey -> Stanza -> IO () |
@@ -220,14 +221,14 @@ enableClientHacks "Pidgin" version replyto = do | |||
220 | wlog "Enabling hack SimulatedChatErrors for client Pidgin" | 221 | wlog "Enabling hack SimulatedChatErrors for client Pidgin" |
221 | donevar <- atomically newEmptyTMVar | 222 | donevar <- atomically newEmptyTMVar |
222 | sendReply donevar | 223 | sendReply donevar |
223 | (InternalEnableHack SimulatedChatErrors) | 224 | (InternalEnableHack SimulatedChatErrors) |
224 | [] | 225 | [] |
225 | replyto | 226 | replyto |
226 | enableClientHacks "irssi-xmpp" version replyto = do | 227 | enableClientHacks "irssi-xmpp" version replyto = do |
227 | wlog "Enabling hack SimulatedChatErrors for client irssi-xmpp" | 228 | wlog "Enabling hack SimulatedChatErrors for client irssi-xmpp" |
228 | donevar <- atomically newEmptyTMVar | 229 | donevar <- atomically newEmptyTMVar |
229 | sendReply donevar | 230 | sendReply donevar |
230 | (InternalEnableHack SimulatedChatErrors) | 231 | (InternalEnableHack SimulatedChatErrors) |
231 | [] | 232 | [] |
232 | replyto | 233 | replyto |
233 | enableClientHacks _ _ _ = return () | 234 | enableClientHacks _ _ _ = return () |
@@ -240,7 +241,7 @@ cacheMessageId id' replyto = do | |||
240 | (InternalCacheId id') | 241 | (InternalCacheId id') |
241 | [] | 242 | [] |
242 | replyto | 243 | replyto |
243 | 244 | ||
244 | 245 | ||
245 | -- TODO: http://xmpp.org/rfcs/rfc6120.html#rules-remote-error | 246 | -- TODO: http://xmpp.org/rfcs/rfc6120.html#rules-remote-error |
246 | -- client connection | 247 | -- client connection |
@@ -318,7 +319,7 @@ copyToChannel | |||
318 | (Event -> a) -> LockedChan a -> TVar (Maybe [Event]) -> ConduitM Event Event m () | 319 | (Event -> a) -> LockedChan a -> TVar (Maybe [Event]) -> ConduitM Event Event m () |
319 | copyToChannel f chan closer_stack = awaitForever copy | 320 | copyToChannel f chan closer_stack = awaitForever copy |
320 | where | 321 | where |
321 | copy x = do | 322 | copy x = do |
322 | liftIO . atomically $ writeLChan chan (f x) | 323 | liftIO . atomically $ writeLChan chan (f x) |
323 | case x of | 324 | case x of |
324 | EventBeginDocument {} -> do | 325 | EventBeginDocument {} -> do |
@@ -333,9 +334,9 @@ copyToChannel f chan closer_stack = awaitForever copy | |||
333 | 334 | ||
334 | 335 | ||
335 | prettyPrint :: ByteString -> ConduitM Event Void IO () | 336 | prettyPrint :: ByteString -> ConduitM Event Void IO () |
336 | prettyPrint prefix = | 337 | prettyPrint prefix = |
337 | XML.renderBytes (XML.def { XML.rsPretty=True }) | 338 | XML.renderBytes (XML.def { XML.rsPretty=True }) |
338 | =$= CB.lines | 339 | =$= CB.lines |
339 | =$ CL.mapM_ (wlogb . (prefix <>)) | 340 | =$ CL.mapM_ (wlogb . (prefix <>)) |
340 | 341 | ||
341 | swapNamespace :: Monad m => Text -> Text -> ConduitM Event Event m () | 342 | swapNamespace :: Monad m => Text -> Text -> ConduitM Event Event m () |
@@ -534,7 +535,7 @@ stanzaFromList stype reply = do | |||
534 | 535 | ||
535 | grokStanzaIQGet :: Monad m => XML.Event -> NestingXML o m (Maybe StanzaType) | 536 | grokStanzaIQGet :: Monad m => XML.Event -> NestingXML o m (Maybe StanzaType) |
536 | grokStanzaIQGet stanza = do | 537 | grokStanzaIQGet stanza = do |
537 | mtag <- nextElement | 538 | mtag <- nextElement |
538 | flip (maybe $ return Nothing) mtag $ \tag -> do | 539 | flip (maybe $ return Nothing) mtag $ \tag -> do |
539 | case tagName tag of | 540 | case tagName tag of |
540 | "{urn:xmpp:ping}ping" -> return $ Just Ping | 541 | "{urn:xmpp:ping}ping" -> return $ Just Ping |
@@ -564,7 +565,7 @@ parseClientVersion = parseit Nothing Nothing | |||
564 | 565 | ||
565 | grokStanzaIQResult :: XML.Event -> NestingXML o IO (Maybe StanzaType) | 566 | grokStanzaIQResult :: XML.Event -> NestingXML o IO (Maybe StanzaType) |
566 | grokStanzaIQResult stanza = do | 567 | grokStanzaIQResult stanza = do |
567 | mtag <- nextElement | 568 | mtag <- nextElement |
568 | flip (maybe $ return (Just Pong)) mtag $ \tag -> do | 569 | flip (maybe $ return (Just Pong)) mtag $ \tag -> do |
569 | case tagName tag of | 570 | case tagName tag of |
570 | "{jabber:iq:version}query" | nameNamespace (tagName stanza)==Just "jabber:client" | 571 | "{jabber:iq:version}query" | nameNamespace (tagName stanza)==Just "jabber:client" |
@@ -573,7 +574,7 @@ grokStanzaIQResult stanza = do | |||
573 | 574 | ||
574 | grokStanzaIQSet :: XML.Event -> NestingXML o IO (Maybe StanzaType) | 575 | grokStanzaIQSet :: XML.Event -> NestingXML o IO (Maybe StanzaType) |
575 | grokStanzaIQSet stanza = do | 576 | grokStanzaIQSet stanza = do |
576 | mtag <- nextElement | 577 | mtag <- nextElement |
577 | flip (maybe $ return Nothing) mtag $ \tag -> do | 578 | flip (maybe $ return Nothing) mtag $ \tag -> do |
578 | case tagName tag of | 579 | case tagName tag of |
579 | "{urn:ietf:params:xml:ns:xmpp-bind}bind" -> do | 580 | "{urn:ietf:params:xml:ns:xmpp-bind}bind" -> do |
@@ -689,7 +690,7 @@ parseMessage ns stanza = do | |||
689 | parseChildren (th,cmap) = do | 690 | parseChildren (th,cmap) = do |
690 | child <- nextElement | 691 | child <- nextElement |
691 | lvl <- nesting | 692 | lvl <- nesting |
692 | xmllang <- xmlLang | 693 | xmllang <- xmlLang |
693 | let lang = maybe "" id xmllang | 694 | let lang = maybe "" id xmllang |
694 | let c = maybe emptyMsg id (Map.lookup lang cmap) | 695 | let c = maybe emptyMsg id (Map.lookup lang cmap) |
695 | -- log $ " child: "<> bshow child | 696 | -- log $ " child: "<> bshow child |
@@ -719,7 +720,7 @@ parseMessage ns stanza = do | |||
719 | Nothing -> return (th,cmap) | 720 | Nothing -> return (th,cmap) |
720 | (th,langmap) <- parseChildren ( MessageThread {msgThreadParent=Nothing, msgThreadContent=""} | 721 | (th,langmap) <- parseChildren ( MessageThread {msgThreadParent=Nothing, msgThreadContent=""} |
721 | , Map.empty ) | 722 | , Map.empty ) |
722 | return Message { | 723 | return Message { |
723 | msgLangMap = Map.toList langmap, | 724 | msgLangMap = Map.toList langmap, |
724 | msgThread = if msgThreadContent th/="" then Just th else Nothing | 725 | msgThread = if msgThreadContent th/="" then Just th else Nothing |
725 | } | 726 | } |
@@ -772,7 +773,7 @@ grokMessage ns stanzaTag = do | |||
772 | 773 | ||
773 | grokStanza | 774 | grokStanza |
774 | :: Text -> XML.Event -> NestingXML o IO (Maybe StanzaType) | 775 | :: Text -> XML.Event -> NestingXML o IO (Maybe StanzaType) |
775 | grokStanza "jabber:server" stanzaTag = | 776 | grokStanza "jabber:server" stanzaTag = |
776 | case () of | 777 | case () of |
777 | _ | stanzaTag `isServerIQOf` "get" -> grokStanzaIQGet stanzaTag | 778 | _ | stanzaTag `isServerIQOf` "get" -> grokStanzaIQGet stanzaTag |
778 | _ | stanzaTag `isServerIQOf` "result" -> grokStanzaIQResult stanzaTag | 779 | _ | stanzaTag `isServerIQOf` "result" -> grokStanzaIQResult stanzaTag |
@@ -780,7 +781,7 @@ grokStanza "jabber:server" stanzaTag = | |||
780 | _ | tagName stanzaTag == "{jabber:server}message" -> grokMessage "jabber:server" stanzaTag | 781 | _ | tagName stanzaTag == "{jabber:server}message" -> grokMessage "jabber:server" stanzaTag |
781 | _ -> return $ Just Unrecognized | 782 | _ -> return $ Just Unrecognized |
782 | 783 | ||
783 | grokStanza "jabber:client" stanzaTag = | 784 | grokStanza "jabber:client" stanzaTag = |
784 | case () of | 785 | case () of |
785 | _ | stanzaTag `isClientIQOf` "get" -> grokStanzaIQGet stanzaTag | 786 | _ | stanzaTag `isClientIQOf` "get" -> grokStanzaIQGet stanzaTag |
786 | _ | stanzaTag `isClientIQOf` "set" -> grokStanzaIQSet stanzaTag | 787 | _ | stanzaTag `isClientIQOf` "set" -> grokStanzaIQSet stanzaTag |
@@ -812,7 +813,7 @@ makeMessage namespace from to bod = | |||
812 | , msgSubject = Nothing } | 813 | , msgSubject = Nothing } |
813 | 814 | ||
814 | makeInformSubscription :: Text -> Text -> Text -> Bool -> IO Stanza | 815 | makeInformSubscription :: Text -> Text -> Text -> Bool -> IO Stanza |
815 | makeInformSubscription namespace from to approved = | 816 | makeInformSubscription namespace from to approved = |
816 | stanzaFromList (PresenceInformSubscription approved) | 817 | stanzaFromList (PresenceInformSubscription approved) |
817 | $ [ EventBeginElement (mkname namespace "presence") | 818 | $ [ EventBeginElement (mkname namespace "presence") |
818 | [ attr "from" from | 819 | [ attr "from" from |
@@ -843,16 +844,16 @@ makePresenceStanza namespace mjid pstat = do | |||
843 | shw Away = ["away"] | 844 | shw Away = ["away"] |
844 | shw DoNotDisturb = ["dnd"] | 845 | shw DoNotDisturb = ["dnd"] |
845 | shw _ = [] | 846 | shw _ = [] |
846 | jabberShow stat = | 847 | jabberShow stat = |
847 | [ EventBeginElement "{jabber:client}show" [] | 848 | [ EventBeginElement "{jabber:client}show" [] |
848 | , EventContent (ContentText stat) | 849 | , EventContent (ContentText stat) |
849 | , EventEndElement "{jabber:client}show" ] | 850 | , EventEndElement "{jabber:client}show" ] |
850 | 851 | ||
851 | makeRosterUpdate :: Text -> Text -> [(Name, Text)] -> IO Stanza | 852 | makeRosterUpdate :: Text -> Text -> [(Name, Text)] -> IO Stanza |
852 | makeRosterUpdate tojid contact as = do | 853 | makeRosterUpdate tojid contact as = do |
853 | let attrs = map (uncurry attr) as | 854 | let attrs = map (uncurry attr) as |
854 | stanzaFromList Unrecognized | 855 | stanzaFromList Unrecognized |
855 | [ EventBeginElement "{jabber:client}iq" | 856 | [ EventBeginElement "{jabber:client}iq" |
856 | [ attr "to" tojid | 857 | [ attr "to" tojid |
857 | , attr "id" "someid" | 858 | , attr "id" "someid" |
858 | , attr "type" "set" | 859 | , attr "type" "set" |
@@ -932,7 +933,7 @@ xmppInbound sv xmpp k laddr pingflag stanzas output donevar = doNestingXML $ do | |||
932 | } | 933 | } |
933 | ioWriteChan stanzas s | 934 | ioWriteChan stanzas s |
934 | you <- liftIO tellyourname | 935 | you <- liftIO tellyourname |
935 | flip (maybe $ unrecog) dispatch $ \dispatch -> | 936 | flip (maybe $ unrecog) dispatch $ \dispatch -> |
936 | case dispatch of | 937 | case dispatch of |
937 | -- Checking that the to-address matches this server. | 938 | -- Checking that the to-address matches this server. |
938 | -- Otherwise it could be a client-to-client ping or a | 939 | -- Otherwise it could be a client-to-client ping or a |
@@ -969,7 +970,7 @@ xmppInbound sv xmpp k laddr pingflag stanzas output donevar = doNestingXML $ do | |||
969 | awaitCloser stanza_lvl | 970 | awaitCloser stanza_lvl |
970 | liftIO . atomically $ writeTVar clsrs Nothing | 971 | liftIO . atomically $ writeTVar clsrs Nothing |
971 | loop | 972 | loop |
972 | 973 | ||
973 | 974 | ||
974 | while :: IO Bool -> IO a -> IO [a] | 975 | while :: IO Bool -> IO a -> IO [a] |
975 | while cond body = do | 976 | while cond body = do |
@@ -1033,7 +1034,7 @@ data XMPPState | |||
1033 | deriving (Eq,Ord) | 1034 | deriving (Eq,Ord) |
1034 | 1035 | ||
1035 | makePing :: Text -> Maybe Text -> Text -> Text -> [XML.Event] | 1036 | makePing :: Text -> Maybe Text -> Text -> Text -> [XML.Event] |
1036 | makePing namespace mid to from = | 1037 | makePing namespace mid to from = |
1037 | [ EventBeginElement (mkname namespace "iq") | 1038 | [ EventBeginElement (mkname namespace "iq") |
1038 | $ (case mid of | 1039 | $ (case mid of |
1039 | Just c -> (("id",[ContentText c]):) | 1040 | Just c -> (("id",[ContentText c]):) |
@@ -1073,7 +1074,7 @@ iq_bind_reply mid jid = | |||
1073 | iq_session_reply :: Maybe Text -> Text -> [XML.Event] | 1074 | iq_session_reply :: Maybe Text -> Text -> [XML.Event] |
1074 | iq_session_reply mid host = | 1075 | iq_session_reply mid host = |
1075 | -- Note: similar to Pong | 1076 | -- Note: similar to Pong |
1076 | [ EventBeginElement "{jabber:client}iq" | 1077 | [ EventBeginElement "{jabber:client}iq" |
1077 | (consid mid [("from",[ContentText host]) | 1078 | (consid mid [("from",[ContentText host]) |
1078 | ,("type",[ContentText "result"]) | 1079 | ,("type",[ContentText "result"]) |
1079 | ]) | 1080 | ]) |
@@ -1082,12 +1083,12 @@ iq_session_reply mid host = | |||
1082 | 1083 | ||
1083 | iq_service_unavailable :: Maybe Text -> Text -> XML.Name -> [XML.Event] | 1084 | iq_service_unavailable :: Maybe Text -> Text -> XML.Name -> [XML.Event] |
1084 | iq_service_unavailable mid host {- mjid -} req = | 1085 | iq_service_unavailable mid host {- mjid -} req = |
1085 | [ EventBeginElement "{jabber:client}iq" | 1086 | [ EventBeginElement "{jabber:client}iq" |
1086 | (consid mid [attr "type" "error" | 1087 | (consid mid [attr "type" "error" |
1087 | ,attr "from" host]) | 1088 | ,attr "from" host]) |
1088 | , EventBeginElement req [] | 1089 | , EventBeginElement req [] |
1089 | , EventEndElement req | 1090 | , EventEndElement req |
1090 | , EventBeginElement "{jabber:client}error" | 1091 | , EventBeginElement "{jabber:client}error" |
1091 | [ attr "type" "cancel" | 1092 | [ attr "type" "cancel" |
1092 | , attr "code" "503" ] | 1093 | , attr "code" "503" ] |
1093 | , EventBeginElement "{urn:ietf:params:xml:ns:xmpp-stanzas}service-unavailable" [] | 1094 | , EventBeginElement "{urn:ietf:params:xml:ns:xmpp-stanzas}service-unavailable" [] |
@@ -1139,7 +1140,7 @@ greet namespace = | |||
1139 | -} | 1140 | -} |
1140 | 1141 | ||
1141 | goodbye :: [XML.Event] | 1142 | goodbye :: [XML.Event] |
1142 | goodbye = | 1143 | goodbye = |
1143 | [ EventEndElement (streamP "stream") | 1144 | [ EventEndElement (streamP "stream") |
1144 | , EventEndDocument | 1145 | , EventEndDocument |
1145 | ] | 1146 | ] |
@@ -1274,7 +1275,7 @@ forkConnection sv xmpp k laddr pingflag src snk stanzas = do | |||
1274 | -- TODO: Probably some stanzas should be queued or saved for re-connect. | 1275 | -- TODO: Probably some stanzas should be queued or saved for re-connect. |
1275 | mapM_ fail $ filter notError (maybeToList last ++ es') | 1276 | mapM_ fail $ filter notError (maybeToList last ++ es') |
1276 | wlog $ "end post-queue fork: " ++ show k | 1277 | wlog $ "end post-queue fork: " ++ show k |
1277 | 1278 | ||
1278 | output <- atomically newTChan | 1279 | output <- atomically newTChan |
1279 | hacks <- atomically $ newTVar Map.empty | 1280 | hacks <- atomically $ newTVar Map.empty |
1280 | msgids <- atomically $ newTVar [] | 1281 | msgids <- atomically $ newTVar [] |
@@ -1376,8 +1377,8 @@ data PeerState | |||
1376 | peerKey :: SocketLike sock => sock -> IO (ConnectionKey,SockAddr) | 1377 | peerKey :: SocketLike sock => sock -> IO (ConnectionKey,SockAddr) |
1377 | peerKey sock = do | 1378 | peerKey sock = do |
1378 | addr <- getSocketName sock | 1379 | addr <- getSocketName sock |
1379 | peer <- | 1380 | peer <- |
1380 | sIsConnected sock >>= \c -> | 1381 | sIsConnected sock >>= \c -> |
1381 | if c then getPeerName sock -- addr is normally socketName | 1382 | if c then getPeerName sock -- addr is normally socketName |
1382 | else return addr -- Weird hack: addr is would-be peer name | 1383 | else return addr -- Weird hack: addr is would-be peer name |
1383 | laddr <- getSocketName sock | 1384 | laddr <- getSocketName sock |
@@ -1390,12 +1391,12 @@ clientKey sock = do | |||
1390 | return $ (ClientKey addr,paddr) | 1391 | return $ (ClientKey addr,paddr) |
1391 | 1392 | ||
1392 | xmlifyRosterItems :: Monad m => Set Text -> Text -> Set Text -> ConduitM i Event m () | 1393 | xmlifyRosterItems :: Monad m => Set Text -> Text -> Set Text -> ConduitM i Event m () |
1393 | xmlifyRosterItems solicited stype set = mapM_ item (Set.toList set) | 1394 | xmlifyRosterItems solicited stype set = mapM_ item (Set.toList set) |
1394 | where | 1395 | where |
1395 | item jid = do yield $ EventBeginElement "{jabber:iq:roster}item" | 1396 | item jid = do yield $ EventBeginElement "{jabber:iq:roster}item" |
1396 | ([ attr "jid" jid | 1397 | ([ attr "jid" jid |
1397 | , attr "subscription" stype | 1398 | , attr "subscription" stype |
1398 | ]++if Set.member jid solicited | 1399 | ]++if Set.member jid solicited |
1399 | then [attr "ask" "subscribe"] | 1400 | then [attr "ask" "subscribe"] |
1400 | else [] ) | 1401 | else [] ) |
1401 | yield $ EventEndElement "{jabber:iq:roster}item" | 1402 | yield $ EventEndElement "{jabber:iq:roster}item" |
@@ -1430,7 +1431,7 @@ sendRoster query xmpp replyto = do | |||
1430 | (consid (stanzaId query) | 1431 | (consid (stanzaId query) |
1431 | [ attr "to" jid | 1432 | [ attr "to" jid |
1432 | , attr "type" "result" ]) | 1433 | , attr "type" "result" ]) |
1433 | yield $ EventBeginElement "{jabber:iq:roster}query" [] -- todo: ver? | 1434 | yield $ EventBeginElement "{jabber:iq:roster}query" [] -- todo: ver? |
1434 | xmlifyRosterItems solicited "to" subto | 1435 | xmlifyRosterItems solicited "to" subto |
1435 | xmlifyRosterItems solicited "from" subfrom | 1436 | xmlifyRosterItems solicited "from" subfrom |
1436 | xmlifyRosterItems solicited "both" subboth | 1437 | xmlifyRosterItems solicited "both" subboth |
@@ -1462,7 +1463,7 @@ socketFromKey sv k = do | |||
1462 | case mcd of | 1463 | case mcd of |
1463 | Nothing -> case k of | 1464 | Nothing -> case k of |
1464 | ClientKey addr -> return addr | 1465 | ClientKey addr -> return addr |
1465 | PeerKey addr -> return addr | 1466 | PeerKey addr -> return addr |
1466 | -- XXX: ? wrong address | 1467 | -- XXX: ? wrong address |
1467 | -- Shouldnt happen anyway. | 1468 | -- Shouldnt happen anyway. |
1468 | Just cd -> return $ cdata cd | 1469 | Just cd -> return $ cdata cd |
@@ -1533,7 +1534,7 @@ xep0086 e = | |||
1533 | UnexpectedRequest -> ("wait", 400) | 1534 | UnexpectedRequest -> ("wait", 400) |
1534 | 1535 | ||
1535 | errorText :: StanzaError -> Text | 1536 | errorText :: StanzaError -> Text |
1536 | errorText e = | 1537 | errorText e = |
1537 | case e of | 1538 | case e of |
1538 | BadRequest -> "Bad request" | 1539 | BadRequest -> "Bad request" |
1539 | Conflict -> "Conflict" | 1540 | Conflict -> "Conflict" |
@@ -1635,7 +1636,7 @@ monitor sv params xmpp = do | |||
1635 | quitVar <- atomically newEmptyTMVar | 1636 | quitVar <- atomically newEmptyTMVar |
1636 | fix $ \loop -> do | 1637 | fix $ \loop -> do |
1637 | action <- atomically $ foldr1 orElse | 1638 | action <- atomically $ foldr1 orElse |
1638 | [ readTChan chan >>= \((k,u),e) -> return $ do | 1639 | [ readTChan chan >>= \((k,u),e) -> return $ do |
1639 | case e of | 1640 | case e of |
1640 | Connection pingflag xsrc xsnk -> do | 1641 | Connection pingflag xsrc xsnk -> do |
1641 | wlog $ tomsg k "Connection" | 1642 | wlog $ tomsg k "Connection" |
@@ -1665,7 +1666,7 @@ monitor sv params xmpp = do | |||
1665 | 1666 | ||
1666 | forkIO $ do | 1667 | forkIO $ do |
1667 | case stanzaOrigin stanza of | 1668 | case stanzaOrigin stanza of |
1668 | NetworkOrigin k@(ClientKey {}) replyto -> | 1669 | NetworkOrigin k@(ClientKey {}) replyto -> |
1669 | case stanzaType stanza of | 1670 | case stanzaType stanza of |
1670 | RequestResource wanted -> do | 1671 | RequestResource wanted -> do |
1671 | sockaddr <- socketFromKey sv k | 1672 | sockaddr <- socketFromKey sv k |
@@ -1676,7 +1677,7 @@ monitor sv params xmpp = do | |||
1676 | let requestVersion :: Producer IO XML.Event | 1677 | let requestVersion :: Producer IO XML.Event |
1677 | requestVersion = do | 1678 | requestVersion = do |
1678 | yield $ EventBeginElement "{jabber:client}iq" | 1679 | yield $ EventBeginElement "{jabber:client}iq" |
1679 | [ attr "to" rsc | 1680 | [ attr "to" rsc |
1680 | , attr "from" hostname | 1681 | , attr "from" hostname |
1681 | , attr "type" "get" | 1682 | , attr "type" "get" |
1682 | , attr "id" "version"] | 1683 | , attr "id" "version"] |
@@ -1780,7 +1781,7 @@ monitor sv params xmpp = do | |||
1780 | NetworkOrigin (PeerKey {}) _ -> "P" | 1781 | NetworkOrigin (PeerKey {}) _ -> "P" |
1781 | wlog "" | 1782 | wlog "" |
1782 | stanzaToConduit dup $$ prettyPrint typ | 1783 | stanzaToConduit dup $$ prettyPrint typ |
1783 | 1784 | ||
1784 | ] | 1785 | ] |
1785 | action | 1786 | action |
1786 | loop | 1787 | loop |
@@ -1794,9 +1795,14 @@ data XMPPServer | |||
1794 | , _xmpp_peer_params :: ConnectionParameters ConnectionKey SockAddr | 1795 | , _xmpp_peer_params :: ConnectionParameters ConnectionKey SockAddr |
1795 | } | 1796 | } |
1796 | 1797 | ||
1797 | addPeer :: XMPPServer -> SockAddr -> IO () | 1798 | grokPeer :: XMPPServer -> ConnectionKey -> (SockAddr, ConnectionParameters ConnectionKey SockAddr, Miliseconds) |
1798 | addPeer sv addr = do | 1799 | grokPeer sv (PeerKey addr) = (addr, _xmpp_peer_params sv, 10000) |
1799 | control (_xmpp_sv sv) (ConnectWithEndlessRetry addr (_xmpp_peer_params sv) 10000) | 1800 | |
1801 | xmppConnections :: XMPPServer -> Connection.Manager TCPStatus ConnectionKey | ||
1802 | xmppConnections sv = tcpManager (grokPeer sv) resolvPeer (_xmpp_sv sv) | ||
1803 | where | ||
1804 | resolvPeer :: String -> IO (Maybe ConnectionKey) | ||
1805 | resolvPeer str = fmap PeerKey <$> listToMaybe <$> resolvePeer (Text.pack str) | ||
1800 | 1806 | ||
1801 | xmppServer :: ( MonadResource m | 1807 | xmppServer :: ( MonadResource m |
1802 | , MonadIO m | 1808 | , MonadIO m |