summaryrefslogtreecommitdiff
path: root/Presence
diff options
context:
space:
mode:
authorjoe <joe@jerkface.net>2013-07-02 03:30:26 -0400
committerjoe <joe@jerkface.net>2013-07-02 03:30:26 -0400
commitd6d23835b19f1d804be5c5a181fd38586bb6b136 (patch)
treec7f4b32fd00d1fd905ffdd94be0f6c179cb6176d /Presence
parent814f6cceb3486e87115aeb40f3766d60a0768f18 (diff)
Reply to presence probes.
Diffstat (limited to 'Presence')
-rw-r--r--Presence/XMPP.hs43
-rw-r--r--Presence/XMPPTypes.hs16
-rw-r--r--Presence/main.hs44
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
348fromClient :: (MonadThrow m,MonadIO m, XMPPSession session) => 348fromClient :: (MonadThrow m,MonadIO m, JabberClientSession session) =>
349 session -> TChan Commands -> Sink XML.Event m () 349 session -> TChan Commands -> Sink XML.Event m ()
350fromClient session cmdChan = doNestingXML $ do 350fromClient 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
403handleClient 403handleClient
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 ()
407handleClient st src snk = do 407handleClient 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
432listenForXmppClients :: 432listenForXmppClients ::
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
436listenForXmppClients addr_family session_factory port st = do 436listenForXmppClients 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
464listenForRemotePeers 464listenForRemotePeers
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
469listenForRemotePeers addrfamily session_factory port st = do 469listenForRemotePeers addrfamily session_factory port st = do
470 doServer (addrfamily .*. port .*. session_factory .*. st) handlePeer 470 doServer (addrfamily .*. port .*. session_factory .*. st) handlePeer
471 471
472handlePeer 472handlePeer
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 ()
476handlePeer st src snk = do 476handlePeer 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
489handlePeerPresence session stanza False = do 489handlePeerPresence session stanza False = do
@@ -527,6 +527,7 @@ matchAttribMaybe name Nothing attrs
527 527
528presenceTypeOffline = Just "unavailable" 528presenceTypeOffline = Just "unavailable"
529presenceTypeOnline = Nothing 529presenceTypeOnline = Nothing
530presenceTypeProbe = Just "probe"
530 531
531isPresenceOf (EventBeginElement name attrs) testType 532isPresenceOf (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
535isPresenceOf _ _ = False 536isPresenceOf _ _ = False
536 537
537fromPeer :: (MonadThrow m,MonadIO m, XMPPSession session) => 538handlePresenceProbe 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
554fromPeer :: (MonadThrow m,MonadIO m, JabberPeerSession session) =>
538 session -> Sink XML.Event m () 555 session -> Sink XML.Event m ()
539fromPeer session = doNestingXML $ do 556fromPeer 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
764seekRemotePeers :: XMPPConfig config => 783seekRemotePeers :: 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
766seekRemotePeers config chan server_connections = do 785seekRemotePeers 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
31import ByteStringOperators 31import ByteStringOperators
32import SocketLike 32import SocketLike
33 33
34class XMPPSession session where 34class 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
43class XMPPConfig config where 42class 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
48data JID = JID { name :: Maybe ByteString 54data 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
81instance XMPPSession ClientSession where 81instance 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
125data PeerSession = PeerSession { 123data 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}
130instance XMPPSession PeerSession where 128instance 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
165subscribeToChan tmvar = 179subscribeToChan 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
287data UnixConfig = UnixConfig
288
289instance XMPPConfig UnixConfig where
290 getBuddies _ user = ConfigFiles.getBuddies user
291 getSubscribers _ user = ConfigFiles.getSubscribers user
292
293start :: Network.Socket.Family -> IO () 301start :: Network.Socket.Family -> IO ()
294start ip4or6 = do 302start 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