diff options
author | joe <joe@jerkface.net> | 2014-03-09 16:56:11 -0400 |
---|---|---|
committer | joe <joe@jerkface.net> | 2014-03-09 16:56:11 -0400 |
commit | 23aff0ea436480ca65a9141f1498e6b53007f45b (patch) | |
tree | d187be6d99aa472f56f5c9ba9e315f720dce3c64 | |
parent | 17d5d5dcb575ddf9e951c4ea027530bf910c8e0d (diff) |
bug fixes
-rw-r--r-- | Presence/XMPPServer.hs | 7 | ||||
-rw-r--r-- | xmppServer.hs | 90 |
2 files changed, 65 insertions, 32 deletions
diff --git a/Presence/XMPPServer.hs b/Presence/XMPPServer.hs index a181b3e5..5a5cd9cc 100644 --- a/Presence/XMPPServer.hs +++ b/Presence/XMPPServer.hs | |||
@@ -795,8 +795,8 @@ makePresenceStanza namespace mjid pstat = do | |||
795 | , EventContent (ContentText stat) | 795 | , EventContent (ContentText stat) |
796 | , EventEndElement "{jabber:client}show" ] | 796 | , EventEndElement "{jabber:client}show" ] |
797 | 797 | ||
798 | makeRosterUpdate tojid contact (suborask,relationship) = do | 798 | makeRosterUpdate tojid contact as = do |
799 | let attrs = [attr suborask relationship] | 799 | let attrs = map (uncurry attr) as |
800 | stanzaFromList Unrecognized | 800 | stanzaFromList Unrecognized |
801 | [ EventBeginElement "{jabber:client}iq" | 801 | [ EventBeginElement "{jabber:client}iq" |
802 | [ attr "to" tojid | 802 | [ attr "to" tojid |
@@ -1343,13 +1343,12 @@ sendRoster query xmpp replyto = do | |||
1343 | hostname <- xmppTellMyNameToClient xmpp | 1343 | hostname <- xmppTellMyNameToClient xmpp |
1344 | let getlist f = do | 1344 | let getlist f = do |
1345 | bs <- f xmpp k | 1345 | bs <- f xmpp k |
1346 | -- js <- mapM parseHostNameJID bs | ||
1347 | return (Set.fromList bs) -- js) | 1346 | return (Set.fromList bs) -- js) |
1348 | buddies <- getlist xmppRosterBuddies | 1347 | buddies <- getlist xmppRosterBuddies |
1349 | subscribers <- getlist xmppRosterSubscribers | 1348 | subscribers <- getlist xmppRosterSubscribers |
1350 | solicited <- getlist xmppRosterSolicited | 1349 | solicited <- getlist xmppRosterSolicited |
1351 | subnone0 <- getlist xmppRosterOthers | 1350 | subnone0 <- getlist xmppRosterOthers |
1352 | let subnone = subnone0 \\ (Set.union buddies subscribers) | 1351 | let subnone = Set.union solicited subnone0 \\ Set.union buddies subscribers |
1353 | let subto = buddies \\ subscribers | 1352 | let subto = buddies \\ subscribers |
1354 | let subfrom = subscribers \\ buddies | 1353 | let subfrom = subscribers \\ buddies |
1355 | let subboth = Set.intersection buddies subscribers | 1354 | let subboth = Set.intersection buddies subscribers |
diff --git a/xmppServer.hs b/xmppServer.hs index 74adc620..5771510a 100644 --- a/xmppServer.hs +++ b/xmppServer.hs | |||
@@ -15,7 +15,7 @@ import Network.Socket | |||
15 | , SockAddr(..) | 15 | , SockAddr(..) |
16 | ) | 16 | ) |
17 | import System.Endian (fromBE32) | 17 | import System.Endian (fromBE32) |
18 | import Data.List (nub, (\\) ) | 18 | import Data.List (nub, (\\), intersect ) |
19 | import Data.Monoid ( (<>) ) | 19 | import Data.Monoid ( (<>) ) |
20 | import qualified Data.Text as Text | 20 | import qualified Data.Text as Text |
21 | import qualified Data.Text.IO as Text | 21 | import qualified Data.Text.IO as Text |
@@ -86,14 +86,18 @@ data ClientState = ClientState | |||
86 | , clientUser :: Text | 86 | , clientUser :: Text |
87 | , clientPid :: Maybe ProcessID | 87 | , clientPid :: Maybe ProcessID |
88 | , clientStatus :: TVar (Maybe Stanza) | 88 | , clientStatus :: TVar (Maybe Stanza) |
89 | , clientFlags :: Int8 | 89 | , clientFlags :: TVar Int8 |
90 | } | 90 | } |
91 | 91 | ||
92 | -- | True if the client has sent an initial presence | 92 | -- | True if the client has sent an initial presence |
93 | clientIsAvailable c = clientFlags c .&. cf_available /= 0 | 93 | clientIsAvailable c = do |
94 | flgs <- readTVar (clientFlags c) | ||
95 | return $ flgs .&. cf_available /= 0 | ||
94 | 96 | ||
95 | -- | True if the client has requested a roster | 97 | -- | True if the client has requested a roster |
96 | clientIsInterested c = clientFlags c .&. cf_interested /= 0 | 98 | clientIsInterested c = do |
99 | flgs <- readTVar (clientFlags c) | ||
100 | return $ flgs .&. cf_interested /= 0 | ||
97 | 101 | ||
98 | data LocalPresence = LocalPresence | 102 | data LocalPresence = LocalPresence |
99 | { networkClients :: Map ConnectionKey ClientState | 103 | { networkClients :: Map ConnectionKey ClientState |
@@ -171,11 +175,12 @@ chooseResourceName state k addr desired = do | |||
171 | (mtty,pid) <- getTTYandPID muid | 175 | (mtty,pid) <- getTTYandPID muid |
172 | user <- getJabberUserForId muid | 176 | user <- getJabberUserForId muid |
173 | status <- atomically $ newTVar Nothing | 177 | status <- atomically $ newTVar Nothing |
178 | flgs <- atomically $ newTVar 0 | ||
174 | let client = ClientState { clientResource = maybe "fallback" id mtty | 179 | let client = ClientState { clientResource = maybe "fallback" id mtty |
175 | , clientUser = user | 180 | , clientUser = user |
176 | , clientPid = pid | 181 | , clientPid = pid |
177 | , clientStatus = status | 182 | , clientStatus = status |
178 | , clientFlags = 0 } | 183 | , clientFlags = flgs } |
179 | 184 | ||
180 | atomically $ do | 185 | atomically $ do |
181 | modifyTVar' (clients state) $ Map.insert k client | 186 | modifyTVar' (clients state) $ Map.insert k client |
@@ -310,12 +315,22 @@ newConn state k addr outchan = do | |||
310 | when (isPeerKey k) | 315 | when (isPeerKey k) |
311 | $ sendProbesAndSolicitations state k addr outchan | 316 | $ sendProbesAndSolicitations state k addr outchan |
312 | 317 | ||
318 | delclient k mlp = do | ||
319 | lp <- mlp | ||
320 | let nc = Map.delete k $ networkClients lp | ||
321 | guard $ not (Map.null nc) | ||
322 | return $ lp { networkClients = nc } | ||
323 | |||
313 | eofConn state k = do | 324 | eofConn state k = do |
314 | atomically $ modifyTVar' (keyToChan state) $ Map.delete k | 325 | atomically $ modifyTVar' (keyToChan state) $ Map.delete k |
315 | case k of | 326 | case k of |
316 | ClientKey {} -> do | 327 | ClientKey {} -> do |
328 | forClient state k (return ()) $ \client -> do | ||
317 | stanza <- makePresenceStanza "jabber:server" Nothing Offline | 329 | stanza <- makePresenceStanza "jabber:server" Nothing Offline |
318 | informClientPresence state k stanza | 330 | informClientPresence state k stanza |
331 | atomically $ do | ||
332 | modifyTVar' (clientsByUser state) | ||
333 | $ Map.alter (delclient k) (clientUser client) | ||
319 | PeerKey {} -> do | 334 | PeerKey {} -> do |
320 | let h = peerKeyToText k | 335 | let h = peerKeyToText k |
321 | jids <- atomically $ do | 336 | jids <- atomically $ do |
@@ -465,12 +480,13 @@ deliverMessage state fail msg = | |||
465 | 480 | ||
466 | 481 | ||
467 | setClientFlag state k flag = | 482 | setClientFlag state k flag = |
468 | atomically $ modifyTVar' (clients state) | 483 | atomically $ do |
469 | $ Map.adjust | 484 | cmap <- readTVar (clients state) |
470 | (\c -> c { clientFlags = clientFlags c .|. flag }) | 485 | flip (maybe $ return ()) (Map.lookup k cmap) $ \client -> do |
471 | k | 486 | modifyTVar' (clientFlags client) (\flgs -> flgs .|. flag) |
472 | 487 | ||
473 | informSentRoster state k = setClientFlag state k cf_interested | 488 | informSentRoster state k = do |
489 | setClientFlag state k cf_interested | ||
474 | 490 | ||
475 | 491 | ||
476 | subscribedPeers user = do | 492 | subscribedPeers user = do |
@@ -493,7 +509,8 @@ informClientPresence state k stanza = do | |||
493 | flip (maybe $ return ()) mb $ \cstate -> do | 509 | flip (maybe $ return ()) mb $ \cstate -> do |
494 | writeTVar (clientStatus cstate) $ Just dup | 510 | writeTVar (clientStatus cstate) $ Just dup |
495 | forClient state k (return ()) $ \client -> do | 511 | forClient state k (return ()) $ \client -> do |
496 | when (not $ clientIsAvailable client) $ do | 512 | is_avail <- atomically $ clientIsAvailable client |
513 | when (not is_avail) $ do | ||
497 | setClientFlag state k cf_available | 514 | setClientFlag state k cf_available |
498 | sendCachedPresence state k | 515 | sendCachedPresence state k |
499 | addrs <- subscribedPeers (clientUser client) | 516 | addrs <- subscribedPeers (clientUser client) |
@@ -546,7 +563,8 @@ informPeerPresence state k stanza = do | |||
546 | forM_ clients $ \(ck,con,client) -> do | 563 | forM_ clients $ \(ck,con,client) -> do |
547 | -- (TODO: appropriately authorized clients only.) | 564 | -- (TODO: appropriately authorized clients only.) |
548 | -- For now, all "available" clients (available = sent initial presence) | 565 | -- For now, all "available" clients (available = sent initial presence) |
549 | when (clientIsAvailable client) $ do | 566 | is_avail <- atomically $ clientIsAvailable client |
567 | when is_avail $ do | ||
550 | froms <- do | 568 | froms <- do |
551 | let ClientKey laddr = ck | 569 | let ClientKey laddr = ck |
552 | (_,trip) <- multiplyJIDForClient laddr from | 570 | (_,trip) <- multiplyJIDForClient laddr from |
@@ -557,11 +575,11 @@ informPeerPresence state k stanza = do | |||
557 | sendModifiedStanzaToClient (dup { stanzaFrom=Just from' }) | 575 | sendModifiedStanzaToClient (dup { stanzaFrom=Just from' }) |
558 | (connChan con) | 576 | (connChan con) |
559 | 577 | ||
560 | answerProbe state k stanza chan = do | 578 | answerProbe state mto k chan = do |
561 | -- putStrLn $ "answerProbe! " ++ show (stanzaType stanza) | 579 | -- putStrLn $ "answerProbe! " ++ show (stanzaType stanza) |
562 | ktc <- atomically $ readTVar (keyToChan state) | 580 | ktc <- atomically $ readTVar (keyToChan state) |
563 | muser <- runTraversableT $ do | 581 | muser <- runTraversableT $ do |
564 | to <- liftT $ stanzaTo stanza | 582 | to <- liftT $ mto |
565 | conn <- liftT $ Map.lookup k ktc | 583 | conn <- liftT $ Map.lookup k ktc |
566 | let (mu,h,_) = splitJID to -- TODO: currently resource-id is ignored on presence | 584 | let (mu,h,_) = splitJID to -- TODO: currently resource-id is ignored on presence |
567 | -- probes. Is this correct? Check the spec. | 585 | -- probes. Is this correct? Check the spec. |
@@ -665,6 +683,11 @@ clientSubscriptionRequest state fail k stanza chan = do | |||
665 | if null addrs then fail else do | 683 | if null addrs then fail else do |
666 | -- add to-address to from's solicited | 684 | -- add to-address to from's solicited |
667 | addToRosterFile ConfigFiles.modifySolicited (clientUser client) to addrs | 685 | addToRosterFile ConfigFiles.modifySolicited (clientUser client) to addrs |
686 | removeFromRosterFile ConfigFiles.modifyBuddies (clientUser client) to addrs | ||
687 | resolved_subs <- resolvedFromRoster ConfigFiles.getSubscribers (clientUser client) | ||
688 | let is_subscribed = not . null $ intersect (map ((mu,).PeerKey) addrs) resolved_subs | ||
689 | -- subscribers: "from" | ||
690 | -- buddies: "to" | ||
668 | 691 | ||
669 | (ktc,ap) <- atomically $ | 692 | (ktc,ap) <- atomically $ |
670 | liftM2 (,) (readTVar $ keyToChan state) | 693 | liftM2 (,) (readTVar $ keyToChan state) |
@@ -677,7 +700,11 @@ clientSubscriptionRequest state fail k stanza chan = do | |||
677 | chans <- clientCons state ktc (clientUser client) | 700 | chans <- clientCons state ktc (clientUser client) |
678 | forM_ chans $ \( Conn { connChan=chan }, client ) -> do | 701 | forM_ chans $ \( Conn { connChan=chan }, client ) -> do |
679 | -- roster update ask="subscribe" | 702 | -- roster update ask="subscribe" |
680 | update <- makeRosterUpdate cjid to ("ask","subscribe") | 703 | update <- makeRosterUpdate cjid to |
704 | [ ("ask","subscribe") | ||
705 | , if is_subscribed then ("subscription","from") | ||
706 | else ("subscription","none") | ||
707 | ] | ||
681 | sendModifiedStanzaToClient update chan | 708 | sendModifiedStanzaToClient update chan |
682 | _ -> return () | 709 | _ -> return () |
683 | 710 | ||
@@ -700,6 +727,7 @@ clientSubscriptionRequest state fail k stanza chan = do | |||
700 | -- Add peer if we are not already associated ... | 727 | -- Add peer if we are not already associated ... |
701 | sv <- atomically $ takeTMVar $ server state | 728 | sv <- atomically $ takeTMVar $ server state |
702 | addPeer sv (head addrs) | 729 | addPeer sv (head addrs) |
730 | atomically $ putTMVar (server state) sv | ||
703 | 731 | ||
704 | 732 | ||
705 | resolvedFromRoster | 733 | resolvedFromRoster |
@@ -755,6 +783,7 @@ peerSubscriptionRequest state fail k stanza chan = do | |||
755 | -- (note: swapping to and from for reply) | 783 | -- (note: swapping to and from for reply) |
756 | reply <- makeInformSubscription "jabber:server" to from is_wanted | 784 | reply <- makeInformSubscription "jabber:server" to from is_wanted |
757 | sendModifiedStanzaToPeer reply chan | 785 | sendModifiedStanzaToPeer reply chan |
786 | answerProbe state (Just to) k chan | ||
758 | else do | 787 | else do |
759 | 788 | ||
760 | -- TODO: if peer-connection is to self, then auto-approve local user. | 789 | -- TODO: if peer-connection is to self, then auto-approve local user. |
@@ -797,7 +826,7 @@ clientInformSubscription state fail k stanza = do | |||
797 | addrs <- resolvePeer h | 826 | addrs <- resolvePeer h |
798 | -- remove from pending | 827 | -- remove from pending |
799 | buds <- resolvedFromRoster ConfigFiles.getBuddies (clientUser client) | 828 | buds <- resolvedFromRoster ConfigFiles.getBuddies (clientUser client) |
800 | let is_buddy = not . null $ map ((mu,) . PeerKey) addrs \\ buds | 829 | let is_buddy = not . null $ map ((mu,) . PeerKey) addrs `intersect` buds |
801 | removeFromRosterFile ConfigFiles.modifyPending (clientUser client) to addrs | 830 | removeFromRosterFile ConfigFiles.modifyPending (clientUser client) to addrs |
802 | let (relationship,addf,remf) = | 831 | let (relationship,addf,remf) = |
803 | case stanzaType stanza of | 832 | case stanzaType stanza of |
@@ -813,20 +842,27 @@ clientInformSubscription state fail k stanza = do | |||
813 | addToRosterFile addf (clientUser client) to addrs | 842 | addToRosterFile addf (clientUser client) to addrs |
814 | removeFromRosterFile remf (clientUser client) to addrs | 843 | removeFromRosterFile remf (clientUser client) to addrs |
815 | 844 | ||
845 | do | ||
846 | cbu <- atomically $ readTVar (clientsByUser state) | ||
847 | putStrLn $ "cbu = " ++ show (fmap (fmap clientPid . networkClients) cbu) | ||
848 | |||
816 | -- send roster update to clients | 849 | -- send roster update to clients |
817 | (clients,ktc) <- atomically $ do | 850 | (clients,ktc) <- atomically $ do |
818 | cbu <- readTVar (clientsByUser state) | 851 | cbu <- readTVar (clientsByUser state) |
819 | let mlp = mu >>= flip Map.lookup cbu | 852 | let mlp = Map.lookup (clientUser client) cbu |
820 | let cs = maybe [] (Map.toList . networkClients) mlp | 853 | let cs = maybe [] (Map.toList . networkClients) mlp |
821 | ktc <- readTVar (keyToChan state) | 854 | ktc <- readTVar (keyToChan state) |
822 | return (cs,ktc) | 855 | return (cs,ktc) |
823 | forM_ clients $ \(ck, client) -> do | 856 | forM_ clients $ \(ck, client) -> do |
824 | when (clientIsInterested client) $ do | 857 | is_intereseted <- atomically $ clientIsInterested client |
858 | putStrLn $ "clientIsInterested: "++show is_intereseted | ||
859 | is_intereseted <- atomically $ clientIsInterested client | ||
860 | when is_intereseted $ do | ||
825 | flip (maybe $ return ()) (Map.lookup ck ktc) $ \con -> do | 861 | flip (maybe $ return ()) (Map.lookup ck ktc) $ \con -> do |
826 | hostname <- textHostName | 862 | hostname <- textHostName |
827 | -- TODO: Should cjid include the resource? | 863 | -- TODO: Should cjid include the resource? |
828 | let cjid = unsplitJID (mu, hostname, Nothing) | 864 | let cjid = unsplitJID (mu, hostname, Nothing) |
829 | update <- makeRosterUpdate cjid to relationship | 865 | update <- makeRosterUpdate cjid to [relationship] |
830 | sendModifiedStanzaToClient update (connChan con) | 866 | sendModifiedStanzaToClient update (connChan con) |
831 | 867 | ||
832 | -- notify peer | 868 | -- notify peer |
@@ -839,6 +875,7 @@ clientInformSubscription state fail k stanza = do | |||
839 | sendModifiedStanzaToPeer (dup { stanzaTo = Just $ to' | 875 | sendModifiedStanzaToPeer (dup { stanzaTo = Just $ to' |
840 | , stanzaFrom = Just from }) | 876 | , stanzaFrom = Just from }) |
841 | (connChan con) | 877 | (connChan con) |
878 | answerProbe state (Just from) pk (connChan con) | ||
842 | 879 | ||
843 | peerInformSubscription state fail k stanza = do | 880 | peerInformSubscription state fail k stanza = do |
844 | putStrLn $ "TODO: peerInformSubscription" | 881 | putStrLn $ "TODO: peerInformSubscription" |
@@ -858,7 +895,7 @@ peerInformSubscription state fail k stanza = do | |||
858 | addrs <- resolvePeer from_h | 895 | addrs <- resolvePeer from_h |
859 | was_solicited <- removeFromRosterFile ConfigFiles.modifySolicited user from'' addrs | 896 | was_solicited <- removeFromRosterFile ConfigFiles.modifySolicited user from'' addrs |
860 | subs <- resolvedFromRoster ConfigFiles.getSubscribers user | 897 | subs <- resolvedFromRoster ConfigFiles.getSubscribers user |
861 | let is_sub = not . null $ map ((from_u,) . PeerKey) addrs \\ subs | 898 | let is_sub = not . null $ map ((from_u,) . PeerKey) addrs `intersect` subs |
862 | let (relationship,addf,remf) = | 899 | let (relationship,addf,remf) = |
863 | case stanzaType stanza of | 900 | case stanzaType stanza of |
864 | PresenceInformSubscription True -> | 901 | PresenceInformSubscription True -> |
@@ -873,20 +910,17 @@ peerInformSubscription state fail k stanza = do | |||
873 | addToRosterFile addf user from'' addrs | 910 | addToRosterFile addf user from'' addrs |
874 | removeFromRosterFile remf user from'' addrs | 911 | removeFromRosterFile remf user from'' addrs |
875 | 912 | ||
876 | ktc <- atomically $ readTVar (keyToChan state) | ||
877 | flip (maybe fail) (Map.lookup k ktc) | ||
878 | $ \Conn { auxAddr=laddr } -> do | ||
879 | hostname <- textHostName | 913 | hostname <- textHostName |
880 | let to' = unsplitJID (Just user, hostname, Nothing) | 914 | let to' = unsplitJID (Just user, hostname, Nothing) |
881 | (_,fromtup) <- rewriteJIDForClient laddr from | ||
882 | chans <- clientCons state ktc user | 915 | chans <- clientCons state ktc user |
883 | forM_ chans $ \(Conn { connChan=chan }, client) -> do | 916 | forM_ chans $ \(Conn { connChan=chan }, client) -> do |
884 | update <- makeRosterUpdate to' from relationship | 917 | update <- makeRosterUpdate to' from'' [relationship] |
885 | when (clientIsInterested client) $ do | 918 | is_intereseted <- atomically $ clientIsInterested client |
919 | when is_intereseted $ do | ||
886 | sendModifiedStanzaToClient update chan | 920 | sendModifiedStanzaToClient update chan |
887 | -- TODO: interested/availabe clients only? | 921 | -- TODO: interested/availabe clients only? |
888 | dup <- cloneStanza stanza | 922 | dup <- cloneStanza stanza |
889 | sendModifiedStanzaToClient dup { stanzaFrom = Just $ unsplitJID fromtup | 923 | sendModifiedStanzaToClient dup { stanzaFrom = Just $ from'' |
890 | , stanzaTo = Just to' } | 924 | , stanzaTo = Just to' } |
891 | chan | 925 | chan |
892 | 926 | ||
@@ -924,7 +958,7 @@ main = runResourceT $ do | |||
924 | , xmppDeliverMessage = deliverMessage state | 958 | , xmppDeliverMessage = deliverMessage state |
925 | , xmppInformClientPresence = informClientPresence state | 959 | , xmppInformClientPresence = informClientPresence state |
926 | , xmppInformPeerPresence = informPeerPresence state | 960 | , xmppInformPeerPresence = informPeerPresence state |
927 | , xmppAnswerProbe = answerProbe state | 961 | , xmppAnswerProbe = \k stanza chan -> answerProbe state (stanzaTo stanza) k chan |
928 | , xmppClientSubscriptionRequest = clientSubscriptionRequest state | 962 | , xmppClientSubscriptionRequest = clientSubscriptionRequest state |
929 | , xmppPeerSubscriptionRequest = peerSubscriptionRequest state | 963 | , xmppPeerSubscriptionRequest = peerSubscriptionRequest state |
930 | , xmppClientInformSubscription = clientInformSubscription state | 964 | , xmppClientInformSubscription = clientInformSubscription state |