diff options
-rw-r--r-- | Presence/XMPPServer.hs | 28 | ||||
-rw-r--r-- | xmppServer.hs | 68 |
2 files changed, 85 insertions, 11 deletions
diff --git a/Presence/XMPPServer.hs b/Presence/XMPPServer.hs index af392f27..4dda1f70 100644 --- a/Presence/XMPPServer.hs +++ b/Presence/XMPPServer.hs | |||
@@ -22,6 +22,8 @@ module XMPPServer | |||
22 | , sendModifiedStanzaToClient | 22 | , sendModifiedStanzaToClient |
23 | , presenceProbe | 23 | , presenceProbe |
24 | , presenceSolicitation | 24 | , presenceSolicitation |
25 | , makePresenceStanza | ||
26 | , JabberShow(..) | ||
25 | ) where | 27 | ) where |
26 | 28 | ||
27 | import Debug.Trace | 29 | import Debug.Trace |
@@ -746,6 +748,32 @@ grokStanza "jabber:client" stanzaTag = | |||
746 | mkname :: Text -> Text -> XML.Name | 748 | mkname :: Text -> Text -> XML.Name |
747 | mkname namespace name = (Name name (Just namespace) Nothing) | 749 | mkname namespace name = (Name name (Just namespace) Nothing) |
748 | 750 | ||
751 | makePresenceStanza namespace mjid pstat = do | ||
752 | stanzaFromList PresenceStatus { presenceShow = pstat | ||
753 | , presencePriority = Nothing | ||
754 | , presenceStatus = [] | ||
755 | } | ||
756 | $ [ EventBeginElement (mkname namespace "presence") | ||
757 | (setFrom $ typ pstat) ] | ||
758 | ++ (shw pstat >>= jabberShow) ++ | ||
759 | [ EventEndElement (mkname namespace "presence")] | ||
760 | where | ||
761 | setFrom = maybe id | ||
762 | (\jid -> (attr "from" jid :) ) | ||
763 | mjid | ||
764 | typ Offline = [attr "type" "unavailable"] | ||
765 | typ _ = [] | ||
766 | shw ExtendedAway = ["xa"] | ||
767 | shw Chatty = ["chat"] | ||
768 | shw Away = ["away"] | ||
769 | shw DoNotDisturb = ["dnd"] | ||
770 | shw _ = [] | ||
771 | jabberShow stat = | ||
772 | [ EventBeginElement "{jabber:client}show" [] | ||
773 | , EventContent (ContentText stat) | ||
774 | , EventEndElement "{jabber:client}show" ] | ||
775 | |||
776 | |||
749 | makePong :: Text -> Maybe Text -> Text -> Text -> [XML.Event] | 777 | makePong :: Text -> Maybe Text -> Text -> Text -> [XML.Event] |
750 | makePong namespace mid to from = | 778 | makePong namespace mid to from = |
751 | -- Note: similar to session reply | 779 | -- Note: similar to session reply |
diff --git a/xmppServer.hs b/xmppServer.hs index 107054bf..699c6a7a 100644 --- a/xmppServer.hs +++ b/xmppServer.hs | |||
@@ -292,7 +292,24 @@ newConn state k addr outchan = do | |||
292 | when (isPeerKey k) | 292 | when (isPeerKey k) |
293 | $ sendProbesAndSolicitations state k addr outchan | 293 | $ sendProbesAndSolicitations state k addr outchan |
294 | 294 | ||
295 | eofConn state k = atomically $ modifyTVar' (keyToChan state) $ Map.delete k | 295 | eofConn state k = do |
296 | atomically $ modifyTVar' (keyToChan state) $ Map.delete k | ||
297 | case k of | ||
298 | ClientKey {} -> do | ||
299 | stanza <- makePresenceStanza "{jabber:server}" Nothing Offline | ||
300 | informClientPresence state k stanza | ||
301 | PeerKey {} -> do | ||
302 | let h = peerKeyToText k | ||
303 | jids <- atomically $ do | ||
304 | rbp <- readTVar (remotesByPeer state) | ||
305 | return $ do | ||
306 | umap <- maybeToList $ Map.lookup k rbp | ||
307 | (u,rp) <- Map.toList umap | ||
308 | r <- Map.keys (resources rp) | ||
309 | return $ unsplitJID (Just u, h, Just r) | ||
310 | forM_ jids $ \jid -> do | ||
311 | stanza <- makePresenceStanza "{jabber:client}" (Just jid) Offline | ||
312 | informPeerPresence state k stanza | ||
296 | 313 | ||
297 | {- | 314 | {- |
298 | rewriteJIDForClient1:: Text -> IO (Maybe ((Maybe Text,Text,Maybe Text),SockAddr)) | 315 | rewriteJIDForClient1:: Text -> IO (Maybe ((Maybe Text,Text,Maybe Text),SockAddr)) |
@@ -427,6 +444,9 @@ deliverMessage state fail msg = | |||
427 | sendModifiedStanzaToClient dup | 444 | sendModifiedStanzaToClient dup |
428 | chan | 445 | chan |
429 | 446 | ||
447 | -- | Send presence notification to subscribed peers. | ||
448 | -- Note that a full JID from address will be added to the | ||
449 | -- stanza if it is not present. | ||
430 | informClientPresence state k stanza = do | 450 | informClientPresence state k stanza = do |
431 | dup <- cloneStanza stanza | 451 | dup <- cloneStanza stanza |
432 | atomically $ do | 452 | atomically $ do |
@@ -461,9 +481,24 @@ informPeerPresence state k stanza = do | |||
461 | flip (maybe $ return ()) muser $ \user -> do | 481 | flip (maybe $ return ()) muser $ \user -> do |
462 | 482 | ||
463 | clients <- atomically $ do | 483 | clients <- atomically $ do |
464 | -- TODO: Store the stanza | 484 | |
485 | -- Update remotesByPeer... | ||
486 | rbp <- readTVar (remotesByPeer state) | ||
487 | let umap = maybe Map.empty id $ Map.lookup k rbp | ||
488 | rp = case (presenceShow $ stanzaType stanza) of | ||
489 | Offline -> | ||
490 | maybe (Map.empty) | ||
491 | (Map.delete resource . resources) | ||
492 | $ Map.lookup user umap | ||
493 | _ -> maybe (Map.singleton resource ()) | ||
494 | (Map.insert resource () . resources ) | ||
495 | $ Map.lookup user umap | ||
496 | umap' = Map.insert user (RemotePresence rp) umap | ||
497 | writeTVar (remotesByPeer state) $ Map.insert k umap' rbp | ||
498 | -- TODO: Store or delete the stanza (remotesByPeer) | ||
499 | |||
465 | -- For now, all clients: | 500 | -- For now, all clients: |
466 | -- (TODO: interested/authorized clients only.) | 501 | -- (TODO: interested/auteorized clients only.) |
467 | ktc <- readTVar (keyToChan state) | 502 | ktc <- readTVar (keyToChan state) |
468 | runTraversableT $ do | 503 | runTraversableT $ do |
469 | (ck,client) <- liftMT $ fmap Map.toList $ readTVar (clients state) | 504 | (ck,client) <- liftMT $ fmap Map.toList $ readTVar (clients state) |
@@ -482,15 +517,21 @@ informPeerPresence state k stanza = do | |||
482 | (connChan con) | 517 | (connChan con) |
483 | 518 | ||
484 | answerProbe state k stanza chan = do | 519 | answerProbe state k stanza chan = do |
485 | putStrLn $ "answerProbe! " ++ show (stanzaType stanza) | 520 | -- putStrLn $ "answerProbe! " ++ show (stanzaType stanza) |
486 | ktc <- atomically $ readTVar (keyToChan state) | 521 | ktc <- atomically $ readTVar (keyToChan state) |
487 | replies <- runTraversableT $ do | 522 | muser <- runTraversableT $ do |
488 | to <- liftMaybe $ stanzaTo stanza | 523 | to <- liftT $ stanzaTo stanza |
489 | conn <- liftMaybe $ Map.lookup k ktc | 524 | conn <- liftT $ Map.lookup k ktc |
490 | let (mu,h,_) = splitJID to -- TODO: currently resource-id is ignored on presence | 525 | let (mu,h,_) = splitJID to -- TODO: currently resource-id is ignored on presence |
491 | -- probes. Is this correct? Check the spec. | 526 | -- probes. Is this correct? Check the spec. |
492 | liftIOMaybe $ guardPortStrippedAddress h (auxAddr conn) | 527 | liftMT $ guardPortStrippedAddress h (auxAddr conn) |
493 | u <- liftMaybe mu | 528 | u <- liftT mu |
529 | let ch = addrToText (auxAddr conn) | ||
530 | return (u,conn,ch) | ||
531 | |||
532 | flip (maybe $ return ()) muser $ \(u,conn,ch) -> do | ||
533 | |||
534 | replies <- runTraversableT $ do | ||
494 | cbu <- lift . atomically $ readTVar (clientsByUser state) | 535 | cbu <- lift . atomically $ readTVar (clientsByUser state) |
495 | lpres <- liftMaybe $ Map.lookup u cbu | 536 | lpres <- liftMaybe $ Map.lookup u cbu |
496 | clientState <- liftT $ Map.elems (networkClients lpres) | 537 | clientState <- liftT $ Map.elems (networkClients lpres) |
@@ -499,11 +540,16 @@ answerProbe state k stanza chan = do | |||
499 | let jid = unsplitJID (Just $ clientUser clientState | 540 | let jid = unsplitJID (Just $ clientUser clientState |
500 | , ch | 541 | , ch |
501 | ,Just $ clientResource clientState) | 542 | ,Just $ clientResource clientState) |
502 | ch = addrToText (auxAddr conn) | ||
503 | return stanza { stanzaFrom = Just jid } | 543 | return stanza { stanzaFrom = Just jid } |
544 | |||
504 | forM_ replies $ \reply -> do | 545 | forM_ replies $ \reply -> do |
505 | sendModifiedStanzaToPeer reply chan | 546 | sendModifiedStanzaToPeer reply chan |
506 | -- TODO: if null replies, send offline message | 547 | |
548 | -- if no presence, send offline message | ||
549 | when (null replies) $ do | ||
550 | let jid = unsplitJID (Just u,ch,Nothing) | ||
551 | pstanza <- makePresenceStanza "{jabber:server}" (Just jid) Offline | ||
552 | atomically $ writeTChan (connChan conn) pstanza | ||
507 | 553 | ||
508 | main = runResourceT $ do | 554 | main = runResourceT $ do |
509 | state <- liftIO . atomically $ do | 555 | state <- liftIO . atomically $ do |