diff options
author | joe <joe@jerkface.net> | 2013-07-02 03:30:26 -0400 |
---|---|---|
committer | joe <joe@jerkface.net> | 2013-07-02 03:30:26 -0400 |
commit | d6d23835b19f1d804be5c5a181fd38586bb6b136 (patch) | |
tree | c7f4b32fd00d1fd905ffdd94be0f6c179cb6176d | |
parent | 814f6cceb3486e87115aeb40f3766d60a0768f18 (diff) |
Reply to presence probes.
-rw-r--r-- | Presence/XMPP.hs | 43 | ||||
-rw-r--r-- | Presence/XMPPTypes.hs | 16 | ||||
-rw-r--r-- | Presence/main.hs | 44 |
3 files changed, 68 insertions, 35 deletions
diff --git a/Presence/XMPP.hs b/Presence/XMPP.hs index eb1774d1..99e7b3f1 100644 --- a/Presence/XMPP.hs +++ b/Presence/XMPP.hs | |||
@@ -345,7 +345,7 @@ handleIQGet session cmdChan tag = do | |||
345 | req -> unhandledGet req | 345 | req -> unhandledGet req |
346 | 346 | ||
347 | 347 | ||
348 | fromClient :: (MonadThrow m,MonadIO m, XMPPSession session) => | 348 | fromClient :: (MonadThrow m,MonadIO m, JabberClientSession session) => |
349 | session -> TChan Commands -> Sink XML.Event m () | 349 | session -> TChan Commands -> Sink XML.Event m () |
350 | fromClient session cmdChan = doNestingXML $ do | 350 | fromClient session cmdChan = doNestingXML $ do |
351 | let log = liftIO . L.putStrLn . ("(C) " <++>) | 351 | let log = liftIO . L.putStrLn . ("(C) " <++>) |
@@ -402,7 +402,7 @@ toClient pchan cmdChan = fix $ \loop -> do | |||
402 | 402 | ||
403 | handleClient | 403 | handleClient |
404 | :: (SocketLike sock, HHead l (XMPPClass session), | 404 | :: (SocketLike sock, HHead l (XMPPClass session), |
405 | XMPPSession session) => | 405 | JabberClientSession session) => |
406 | HCons sock (HCons t l) -> Source IO ByteString -> Sink ByteString IO () -> IO () | 406 | HCons sock (HCons t l) -> Source IO ByteString -> Sink ByteString IO () -> IO () |
407 | handleClient st src snk = do | 407 | handleClient st src snk = do |
408 | let HCons sock (HCons _ st') = st | 408 | let HCons sock (HCons _ st') = st |
@@ -431,7 +431,7 @@ handleClient st src snk = do | |||
431 | 431 | ||
432 | listenForXmppClients :: | 432 | listenForXmppClients :: |
433 | (HList l, HHead l (XMPPClass session), HExtend e1 l2 l1, | 433 | (HList l, HHead l (XMPPClass session), HExtend e1 l2 l1, |
434 | HExtend e l1 (HCons PortNumber l), XMPPSession session) => | 434 | HExtend e l1 (HCons PortNumber l), JabberClientSession session) => |
435 | Family -> e1 -> e -> l2 -> IO ServerHandle | 435 | Family -> e1 -> e -> l2 -> IO ServerHandle |
436 | listenForXmppClients addr_family session_factory port st = do | 436 | listenForXmppClients addr_family session_factory port st = do |
437 | doServer (addr_family .*. port .*. session_factory .*. st) handleClient | 437 | doServer (addr_family .*. port .*. session_factory .*. st) handleClient |
@@ -462,28 +462,28 @@ renderChunks = fixMaybeT $ \loop -> do | |||
462 | 462 | ||
463 | 463 | ||
464 | listenForRemotePeers | 464 | listenForRemotePeers |
465 | :: (HList l, HHead l (XMPPClass session), | 465 | :: (HList l, HHead l (XMPPPeerClass session), |
466 | HExtend e l1 (HCons PortNumber l), HExtend e1 l2 l1, | 466 | HExtend e l1 (HCons PortNumber l), HExtend e1 l2 l1, |
467 | XMPPSession session) => | 467 | JabberPeerSession session) => |
468 | Family -> e1 -> e -> l2 -> IO ServerHandle | 468 | Family -> e1 -> e -> l2 -> IO ServerHandle |
469 | listenForRemotePeers addrfamily session_factory port st = do | 469 | listenForRemotePeers addrfamily session_factory port st = do |
470 | doServer (addrfamily .*. port .*. session_factory .*. st) handlePeer | 470 | doServer (addrfamily .*. port .*. session_factory .*. st) handlePeer |
471 | 471 | ||
472 | handlePeer | 472 | handlePeer |
473 | :: (SocketLike sock, HHead l (XMPPClass session), | 473 | :: (SocketLike sock, HHead l (XMPPPeerClass session), |
474 | XMPPSession session) => | 474 | JabberPeerSession session) => |
475 | HCons sock (HCons t1 l) -> Source IO ByteString -> t -> IO () | 475 | HCons sock (HCons t1 l) -> Source IO ByteString -> t -> IO () |
476 | handlePeer st src snk = do | 476 | handlePeer st src snk = do |
477 | let HCons sock (HCons _ st') = st | 477 | let HCons sock (HCons _ st') = st |
478 | session_factory = hHead st' | 478 | session_factory = hHead st' |
479 | name <- fmap bshow $ getPeerName sock | 479 | name <- fmap bshow $ getPeerName sock |
480 | L.putStrLn $ "(P) connected " <++> name | 480 | L.putStrLn $ "(P) connected " <++> name |
481 | session <- newSession session_factory sock | 481 | session <- newPeerSession session_factory sock |
482 | 482 | ||
483 | finally ( src $= parseBytes def $$ fromPeer session ) | 483 | finally ( src $= parseBytes def $$ fromPeer session ) |
484 | $ do | 484 | $ do |
485 | L.putStrLn $ "(P) disconnected " <++> name | 485 | L.putStrLn $ "(P) disconnected " <++> name |
486 | closeSession session | 486 | closePeerSession session |
487 | 487 | ||
488 | 488 | ||
489 | handlePeerPresence session stanza False = do | 489 | handlePeerPresence session stanza False = do |
@@ -527,6 +527,7 @@ matchAttribMaybe name Nothing attrs | |||
527 | 527 | ||
528 | presenceTypeOffline = Just "unavailable" | 528 | presenceTypeOffline = Just "unavailable" |
529 | presenceTypeOnline = Nothing | 529 | presenceTypeOnline = Nothing |
530 | presenceTypeProbe = Just "probe" | ||
530 | 531 | ||
531 | isPresenceOf (EventBeginElement name attrs) testType | 532 | isPresenceOf (EventBeginElement name attrs) testType |
532 | | name=="{jabber:server}presence" | 533 | | name=="{jabber:server}presence" |
@@ -534,7 +535,23 @@ isPresenceOf (EventBeginElement name attrs) testType | |||
534 | = True | 535 | = True |
535 | isPresenceOf _ _ = False | 536 | isPresenceOf _ _ = False |
536 | 537 | ||
537 | fromPeer :: (MonadThrow m,MonadIO m, XMPPSession session) => | 538 | handlePresenceProbe session stanza = do |
539 | withJust (lookupAttrib "to" (tagAttrs stanza)) $ \to -> do | ||
540 | -- withJust (lookupAttrib "from" (tagAttrs stanza)) $ \from -> do | ||
541 | jid <- liftIO $ parseAddressJID $ L.fromChunks [S.encodeUtf8 to] | ||
542 | withJust (name jid) $ \user -> do | ||
543 | liftIO $ L.putStrLn $ "RECEIVED PROBE "<++>bshow (peerAddress session,to) | ||
544 | liftIO $ do | ||
545 | subs <- getSubscribers (peerSessionFactory session) user | ||
546 | forM_ subs $ \jidstr -> do | ||
547 | handle (\(SomeException _) -> return ()) $ do | ||
548 | sub <- parseHostNameJID jidstr | ||
549 | when (peer sub == peer jid) $ do | ||
550 | ps <- userStatus session user | ||
551 | mapM_ (announcePresence session) ps | ||
552 | return () | ||
553 | |||
554 | fromPeer :: (MonadThrow m,MonadIO m, JabberPeerSession session) => | ||
538 | session -> Sink XML.Event m () | 555 | session -> Sink XML.Event m () |
539 | fromPeer session = doNestingXML $ do | 556 | fromPeer session = doNestingXML $ do |
540 | let log = liftIO . L.putStrLn . ("(P) " <++>) | 557 | let log = liftIO . L.putStrLn . ("(P) " <++>) |
@@ -558,6 +575,8 @@ fromPeer session = doNestingXML $ do | |||
558 | -> handlePeerPresence session stanza True | 575 | -> handlePeerPresence session stanza True |
559 | _ | stanza `isPresenceOf` presenceTypeOffline | 576 | _ | stanza `isPresenceOf` presenceTypeOffline |
560 | -> handlePeerPresence session stanza False | 577 | -> handlePeerPresence session stanza False |
578 | _ | stanza `isPresenceOf` presenceTypeProbe | ||
579 | -> handlePresenceProbe session stanza | ||
561 | _ -> unhandledStanza | 580 | _ -> unhandledStanza |
562 | 581 | ||
563 | awaitCloser stanza_lvl | 582 | awaitCloser stanza_lvl |
@@ -761,8 +780,8 @@ sendMessage cons msg peer = do | |||
761 | 780 | ||
762 | 781 | ||
763 | 782 | ||
764 | seekRemotePeers :: XMPPConfig config => | 783 | seekRemotePeers :: JabberPeerSession config => |
765 | config -> TChan Presence -> TVar (Map Peer (TChan OutBoundMessage, ThreadId)) -> IO b0 | 784 | XMPPPeerClass config -> TChan Presence -> TVar (Map Peer (TChan OutBoundMessage, ThreadId)) -> IO b0 |
766 | seekRemotePeers config chan server_connections = do | 785 | seekRemotePeers config chan server_connections = do |
767 | fix $ \loop -> do | 786 | fix $ \loop -> do |
768 | event <- atomically $ readTChan chan | 787 | event <- atomically $ readTChan chan |
diff --git a/Presence/XMPPTypes.hs b/Presence/XMPPTypes.hs index b46b4294..6e054708 100644 --- a/Presence/XMPPTypes.hs +++ b/Presence/XMPPTypes.hs | |||
@@ -31,18 +31,24 @@ import Control.DeepSeq | |||
31 | import ByteStringOperators | 31 | import ByteStringOperators |
32 | import SocketLike | 32 | import SocketLike |
33 | 33 | ||
34 | class XMPPSession session where | 34 | class JabberClientSession session where |
35 | data XMPPClass session | 35 | data XMPPClass session |
36 | newSession :: SocketLike sock => XMPPClass session -> sock -> IO session | 36 | newSession :: SocketLike sock => XMPPClass session -> sock -> IO session |
37 | setResource :: session -> ByteString -> IO () | 37 | setResource :: session -> ByteString -> IO () |
38 | getJID :: session -> IO JID | 38 | getJID :: session -> IO JID |
39 | closeSession :: session -> IO () | 39 | closeSession :: session -> IO () |
40 | subscribe :: session -> Maybe JID -> IO (TChan Presence) | 40 | subscribe :: session -> Maybe JID -> IO (TChan Presence) |
41 | announcePresence :: session -> Presence -> IO () | ||
42 | 41 | ||
43 | class XMPPConfig config where | 42 | class JabberPeerSession session where |
44 | getBuddies :: config -> ByteString -> IO [ByteString] | 43 | data XMPPPeerClass session |
45 | getSubscribers :: config -> ByteString -> IO [ByteString] | 44 | newPeerSession :: SocketLike sock => XMPPPeerClass session -> sock -> IO session |
45 | closePeerSession :: session -> IO () | ||
46 | peerAddress :: session -> Peer | ||
47 | userStatus :: session -> ByteString -> IO [Presence] | ||
48 | announcePresence :: session -> Presence -> IO () | ||
49 | peerSessionFactory :: session -> XMPPPeerClass session | ||
50 | getBuddies :: XMPPPeerClass session -> ByteString -> IO [ByteString] | ||
51 | getSubscribers :: XMPPPeerClass session -> ByteString -> IO [ByteString] | ||
46 | 52 | ||
47 | -- | Jabber ID (JID) datatype | 53 | -- | Jabber ID (JID) datatype |
48 | data JID = JID { name :: Maybe ByteString | 54 | data JID = JID { name :: Maybe ByteString |
diff --git a/Presence/main.hs b/Presence/main.hs index e02b4348..7981f00b 100644 --- a/Presence/main.hs +++ b/Presence/main.hs | |||
@@ -78,7 +78,7 @@ data ClientSession = ClientSession { | |||
78 | presence_state :: PresenceState | 78 | presence_state :: PresenceState |
79 | } | 79 | } |
80 | 80 | ||
81 | instance XMPPSession ClientSession where | 81 | instance JabberClientSession ClientSession where |
82 | data XMPPClass ClientSession = ClientSessions PresenceState | 82 | data XMPPClass ClientSession = ClientSessions PresenceState |
83 | 83 | ||
84 | newSession (ClientSessions state) sock = do | 84 | newSession (ClientSessions state) sock = do |
@@ -119,29 +119,23 @@ instance XMPPSession ClientSession where | |||
119 | let tvar = subscriberMap (presence_state session) | 119 | let tvar = subscriberMap (presence_state session) |
120 | atomically $ subscribeToMap tvar jid | 120 | atomically $ subscribeToMap tvar jid |
121 | 121 | ||
122 | announcePresence _ _ = error "announcePresence on client session?" | ||
123 | |||
124 | 122 | ||
125 | data PeerSession = PeerSession { | 123 | data PeerSession = PeerSession { |
126 | announced :: TVar (Set JID), | 124 | announced :: TVar (Set JID), |
127 | peer_name :: Peer, | 125 | peer_name :: Peer, |
128 | peer_global :: PresenceState | 126 | peer_global :: PresenceState |
129 | } | 127 | } |
130 | instance XMPPSession PeerSession where | 128 | instance JabberPeerSession PeerSession where |
131 | data XMPPClass PeerSession = PeerSessions PresenceState | 129 | data XMPPPeerClass PeerSession = PeerSessions PresenceState |
132 | |||
133 | setResource _ _ = error "setResource on peer session?" | ||
134 | getJID _ = error "getJID on peer session?" | ||
135 | subscribe _ _ = error "subscribe on peer session?" | ||
136 | 130 | ||
137 | newSession (PeerSessions state) sock = do | 131 | newPeerSession (PeerSessions state) sock = do |
138 | me <- fmap (RemotePeer . withoutPort) (getPeerName sock) | 132 | me <- fmap (RemotePeer . withoutPort) (getPeerName sock) |
139 | L.putStrLn $ "PEER SESSION: open "<++>showPeer me | 133 | L.putStrLn $ "PEER SESSION: open "<++>showPeer me |
140 | let remotes = remoteUsers state | 134 | let remotes = remoteUsers state |
141 | jids <- atomically $ getRefFromMap remotes me (newTVar Set.empty) return | 135 | jids <- atomically $ getRefFromMap remotes me (newTVar Set.empty) return |
142 | return $ PeerSession jids me state | 136 | return $ PeerSession jids me state |
143 | 137 | ||
144 | closeSession session = do | 138 | closePeerSession session = do |
145 | L.putStrLn $ "PEER SESSION: close "<++>showPeer (peer_name session) | 139 | L.putStrLn $ "PEER SESSION: close "<++>showPeer (peer_name session) |
146 | let offline jid = Presence jid Offline | 140 | let offline jid = Presence jid Offline |
147 | unrefFromMap (remoteUsers . peer_global $ session) (peer_name session) | 141 | unrefFromMap (remoteUsers . peer_global $ session) (peer_name session) |
@@ -149,6 +143,22 @@ instance XMPPSession PeerSession where | |||
149 | js <- fmap Set.toList (readTVarIO . announced $ session) | 143 | js <- fmap Set.toList (readTVarIO . announced $ session) |
150 | forM_ js $ announcePresence session . offline | 144 | forM_ js $ announcePresence session . offline |
151 | 145 | ||
146 | peerSessionFactory session = PeerSessions (peer_global session) | ||
147 | |||
148 | peerAddress session = peer_name session | ||
149 | |||
150 | userStatus session user = do | ||
151 | let state = peer_global session | ||
152 | (tty,users) <- atomically $ do | ||
153 | tty <- readTVar $ currentTTY state | ||
154 | users <- readTVar $ activeUsers state | ||
155 | return (tty,users) | ||
156 | let jids = Set.filter (\jid->name jid==Just user) users | ||
157 | ps = map (\jid -> Presence jid (matchResource tty jid)) . Set.toList $ jids | ||
158 | if null ps | ||
159 | then return [Presence (JID { name=Just user, peer=LocalHost, resource=Nothing }) Offline] | ||
160 | else return ps | ||
161 | |||
152 | announcePresence session (Presence jid status) = do | 162 | announcePresence session (Presence jid status) = do |
153 | (greedy,subs) <- atomically $ do | 163 | (greedy,subs) <- atomically $ do |
154 | subs <- readTVar $ subscriberMap (peer_global session) | 164 | subs <- readTVar $ subscriberMap (peer_global session) |
@@ -162,6 +172,10 @@ instance XMPPSession PeerSession where | |||
162 | Offline -> Set.delete jid jids | 172 | Offline -> Set.delete jid jids |
163 | _ -> Set.insert jid jids | 173 | _ -> Set.insert jid jids |
164 | 174 | ||
175 | getBuddies _ user = ConfigFiles.getBuddies user | ||
176 | getSubscribers _ user = ConfigFiles.getSubscribers user | ||
177 | |||
178 | |||
165 | subscribeToChan tmvar = | 179 | subscribeToChan tmvar = |
166 | (do (cnt,chan) <- takeTMVar tmvar | 180 | (do (cnt,chan) <- takeTMVar tmvar |
167 | putTMVar tmvar (cnt+1,chan) | 181 | putTMVar tmvar (cnt+1,chan) |
@@ -284,12 +298,6 @@ on_chvt state vtnum = do | |||
284 | return (us,fmap snd subs,fmap snd locals_greedy) | 298 | return (us,fmap snd subs,fmap snd locals_greedy) |
285 | update_presence locals_greedy subs users $ matchResource tty | 299 | update_presence locals_greedy subs users $ matchResource tty |
286 | 300 | ||
287 | data UnixConfig = UnixConfig | ||
288 | |||
289 | instance XMPPConfig UnixConfig where | ||
290 | getBuddies _ user = ConfigFiles.getBuddies user | ||
291 | getSubscribers _ user = ConfigFiles.getSubscribers user | ||
292 | |||
293 | start :: Network.Socket.Family -> IO () | 301 | start :: Network.Socket.Family -> IO () |
294 | start ip4or6 = do | 302 | start ip4or6 = do |
295 | let host = LocalHost | 303 | let host = LocalHost |
@@ -298,7 +306,7 @@ start ip4or6 = do | |||
298 | dologin :: t -> IO () | 306 | dologin :: t -> IO () |
299 | 307 | ||
300 | chan <- atomically $ subscribeToChan (localSubscriber global_state) | 308 | chan <- atomically $ subscribeToChan (localSubscriber global_state) |
301 | remotes <- forkIO $ seekRemotePeers UnixConfig chan (outGoingConnections global_state) | 309 | remotes <- forkIO $ seekRemotePeers (PeerSessions global_state) chan (outGoingConnections global_state) |
302 | 310 | ||
303 | installHandler sigUSR1 (Catch (dologin (userError "signaled"))) Nothing | 311 | installHandler sigUSR1 (Catch (dologin (userError "signaled"))) Nothing |
304 | -- installHandler sigTERM (CatchOnce (dologin (userError "term signaled"))) Nothing | 312 | -- installHandler sigTERM (CatchOnce (dologin (userError "term signaled"))) Nothing |