summaryrefslogtreecommitdiff
path: root/Presence
diff options
context:
space:
mode:
authorjoe <joe@jerkface.net>2013-07-09 01:40:47 -0400
committerjoe <joe@jerkface.net>2013-07-09 01:40:47 -0400
commit5d96f7581837e84b7e2db7f119879bc701709ddd (patch)
tree9298f1ed49e343e7767166f5abd2877eaf24e284 /Presence
parentc0895f5a2e604bc4594354399498e2ebb19d8c8e (diff)
send subscription requests to remote peers
Diffstat (limited to 'Presence')
-rw-r--r--Presence/XMPP.hs79
-rw-r--r--Presence/XMPPTypes.hs2
-rw-r--r--Presence/main.hs25
3 files changed, 71 insertions, 35 deletions
diff --git a/Presence/XMPP.hs b/Presence/XMPP.hs
index a08c1a0e..735eaf3a 100644
--- a/Presence/XMPP.hs
+++ b/Presence/XMPP.hs
@@ -71,6 +71,7 @@ import Control.Monad as Monad
71import Text.XML.Stream.Parse (parseBytes,content) 71import Text.XML.Stream.Parse (parseBytes,content)
72import Text.XML.Stream.Render 72import Text.XML.Stream.Render
73import Data.XML.Types as XML 73import Data.XML.Types as XML
74import qualified Data.Text as S (takeWhile)
74import Data.Text.Encoding as S (decodeUtf8,encodeUtf8) 75import Data.Text.Encoding as S (decodeUtf8,encodeUtf8)
75import Data.Text.Lazy.Encoding as L (decodeUtf8,encodeUtf8) 76import Data.Text.Lazy.Encoding as L (decodeUtf8,encodeUtf8)
76import Data.Text.Lazy (toStrict) 77import Data.Text.Lazy (toStrict)
@@ -512,7 +513,7 @@ toClient session pchan cmdChan rchan = toClient' False False
512 CmdChan (Send xs) -> send xs >> loop 513 CmdChan (Send xs) -> send xs >> loop
513 CmdChan BoundToResource -> toClient' True isInterested 514 CmdChan BoundToResource -> toClient' True isInterested
514 CmdChan InterestedInRoster -> toClient' isBound True 515 CmdChan InterestedInRoster -> toClient' isBound True
515 CmdChan cmd -> liftIO (putStrLn $ "unhandled event: "++show cmd) >> loop 516 -- CmdChan cmd -> liftIO (putStrLn $ "unhandled event: "++show cmd) >> loop
516 RChan (RequestedSubscription who contact) -> do 517 RChan (RequestedSubscription who contact) -> do
517 jid <- liftIO $ getJID session 518 jid <- liftIO $ getJID session
518 when (isInterested && Just who==name jid) $ do 519 when (isInterested && Just who==name jid) $ do
@@ -712,18 +713,20 @@ presenceErrorRemoteNotFound iqid from to = return
712 , EventEndElement "{stream:client}presence" 713 , EventEndElement "{stream:client}presence"
713 ] 714 ]
714 715
716presenceSubscribed from = return
717 [ EventBeginElement "{stream:client}presence"
718 [ attr "from" from
719 , attr "type" "subscribed"
720 ]
721 , EventEndElement "{stream:client}presence"
722 ]
723
715clientRequestsSubscription session cmdChan stanza = do 724clientRequestsSubscription session cmdChan stanza = do
716 -- make bare jid
717 -- check local server and obey rules 3.1.3 of rfc 6121
718 -- or forward to remote peer
719 -- or bail with type='error' as shown in 3.1.2
720 -- if not bailed,
721 -- add to solicited
722 -- do roster push with subscription=none ask=subscribe
723 liftIO $ do 725 liftIO $ do
724 putStrLn $ "CLIENT PRESENCE SUBSCRIBE " ++ show stanza 726 putStrLn $ "CLIENT PRESENCE SUBSCRIBE " ++ show stanza
725 withJust (lookupAttrib "to" (tagAttrs stanza)) $ \to_str -> do 727 withJust (lookupAttrib "to" (tagAttrs stanza)) $ \to_str0 -> do
726 let from = lookupAttrib "from" (tagAttrs stanza) 728 let to_str = S.takeWhile (/='/') to_str0
729 from = lookupAttrib "from" (tagAttrs stanza)
727 iqid = lookupAttrib "id" (tagAttrs stanza) 730 iqid = lookupAttrib "id" (tagAttrs stanza)
728 let handleError e | isDoesNotExistError e = do 731 let handleError e | isDoesNotExistError e = do
729 putStrLn $ "remote-server-not-found" 732 putStrLn $ "remote-server-not-found"
@@ -732,12 +735,18 @@ clientRequestsSubscription session cmdChan stanza = do
732 handleError e = do 735 handleError e = do
733 putStrLn $ "ERROR: "++ show e 736 putStrLn $ "ERROR: "++ show e
734 handleIO handleError $ do 737 handleIO handleError $ do
735 to_jid <- parseHostNameJID (L.fromChunks [S.encodeUtf8 to_str]) 738 let to_str' = (L.fromChunks [S.encodeUtf8 to_str])
736 addSolicited session (L.fromChunks [S.encodeUtf8 to_str]) -- jid 739 to_jid <- fmap bare $ parseHostNameJID to_str'
737 putStrLn $ "added to solicited: " ++ show to_jid 740 if (is_remote . peer) to_jid
738 -- TODO: create roster item and push to interested clients 741 then do
739 -- addSolicited should write event to a roster channel 742 addSolicited session to_str' to_jid
740 -- that toClient will be listening on. 743 putStrLn $ "added to solicited: " ++ show to_jid
744 -- TODO: notify peer.
745 else do
746 -- addLocalSubscriber session to_str
747 -- self <- getJID session
748 r <- presenceSubscribed to_str -- self
749 atomically $ writeTChan cmdChan (Send r)
741 return () 750 return ()
742 751
743peerRequestsSubsription session stanza = do 752peerRequestsSubsription session stanza = do
@@ -807,14 +816,16 @@ fromPeer session = doNestingXML $ do
807 816
808 817
809 818
810data OutBoundMessage = OutBoundPresence Presence | PresenceProbe JID JID 819data OutBoundMessage = OutBoundPresence Presence
820 | PresenceProbe JID JID
821 | Solicitation JID JID
811 deriving Prelude.Show 822 deriving Prelude.Show
812 823
813newServerConnections = newTVar Map.empty 824newServerConnections = newTVar Map.empty
814 825
815data CachedMessages = CachedMessages 826data CachedMessages = CachedMessages
816 { presences :: Map JID JabberShow 827 { presences :: Map JID JabberShow
817 , probes :: Map JID (Set JID) 828 , probes :: Map JID (Set (Bool,JID))
818 } 829 }
819 830
820connect_to_server chan peer = (>> return ()) . runMaybeT $ do 831connect_to_server chan peer = (>> return ()) . runMaybeT $ do
@@ -831,7 +842,11 @@ connect_to_server chan peer = (>> return ()) . runMaybeT $ do
831 writeIORef cached (cache { presences=Map.insert jid st . presences $ cache }) 842 writeIORef cached (cache { presences=Map.insert jid st . presences $ cache })
832 cacheCmd (PresenceProbe from to) cached = do 843 cacheCmd (PresenceProbe from to) cached = do
833 cache <- readIORef cached 844 cache <- readIORef cached
834 let probes' = Map.adjust (Set.insert from) to $ probes cache 845 let probes' = Map.adjust (Set.insert (True,from)) to $ probes cache
846 writeIORef cached (cache { probes=probes' })
847 cacheCmd (Solicitation from to) cached = do
848 cache <- readIORef cached
849 let probes' = Map.adjust (Set.insert (False,from)) to $ probes cache
835 writeIORef cached (cache { probes=probes' }) 850 writeIORef cached (cache { probes=probes' })
836 851
837 fix $ \sendmsgs -> do 852 fix $ \sendmsgs -> do
@@ -873,7 +888,7 @@ goodbyePeer =
873 , EventEndDocument 888 , EventEndDocument
874 ] 889 ]
875 890
876presenceProbe sock fromjid tojid = do 891presenceProbe sock fromjid tojid typ = do
877 addr <- getSocketName sock 892 addr <- getSocketName sock
878 let jidstr jid = toStrict . L.decodeUtf8 893 let jidstr jid = toStrict . L.decodeUtf8
879 $ name jid <$++> "@" 894 $ name jid <$++> "@"
@@ -887,7 +902,7 @@ presenceProbe sock fromjid tojid = do
887 [ EventBeginElement "{jabber:server}presence" 902 [ EventBeginElement "{jabber:server}presence"
888 [ attr "from" from 903 [ attr "from" from
889 , attr "to" to 904 , attr "to" to
890 , attr "type" "probe" 905 , attr "type" typ
891 ] 906 ]
892 , EventEndElement "{jabber:server}presence" 907 , EventEndElement "{jabber:server}presence"
893 ] 908 ]
@@ -928,20 +943,29 @@ toPeer sock cache chan fail = do
928 checkConnection cmd 943 checkConnection cmd
929 yieldOr r (fail . Just $ cmd) 944 yieldOr r (fail . Just $ cmd)
930 prettyPrint ">P: " r 945 prettyPrint ">P: " r
931 sendProbe from to = do 946 sendProbe' from to typ = do
932 r <- liftIO $ presenceProbe sock from to 947 r <- liftIO $ presenceProbe sock from to typ
933 let cmd = PresenceProbe from to 948 let cmd = PresenceProbe from to
934 checkConnection cmd 949 checkConnection cmd
935 yieldOr r (fail . Just $ cmd) 950 yieldOr r (fail . Just $ cmd)
936 prettyPrint ">P: " r 951 prettyPrint ">P: " r
952 sendProbe from to = sendProbe' from to "probe"
953 sendSolicitation from to = sendProbe' from to "subscribe"
937 954
938 send greetPeer 955 send greetPeer
939 forM_ (Map.assocs . presences $ cache) $ \(jid,st) -> do 956 forM_ (Map.assocs . presences $ cache) $ \(jid,st) -> do
940 sendPresence (Presence jid st) 957 sendPresence (Presence jid st)
941 forM_ (Map.assocs . probes $ cache) $ \(to,froms) -> do 958 forM_ (Map.assocs . probes $ cache) $ \(to,froms) -> do
942 forM_ (Set.toList froms) $ \from -> do 959 forM_ (Set.toList froms) $ \(got,from) -> do
943 liftIO $ L.putStrLn "sending cached probe..." 960 if got
944 sendProbe from to 961 then do
962 liftIO $ L.putStrLn "sending cached probe..."
963 sendProbe from to
964 else do
965 liftIO $ L.putStrLn "sending cached solicitation..."
966 sendSolicitation from to
967
968
945 fix $ \loop -> do 969 fix $ \loop -> do
946 event <- lift . atomically $ readTChan chan 970 event <- lift . atomically $ readTChan chan
947 case event of 971 case event of
@@ -949,6 +973,9 @@ toPeer sock cache chan fail = do
949 PresenceProbe from to -> do 973 PresenceProbe from to -> do
950 liftIO $ L.putStrLn "sending live probe..." 974 liftIO $ L.putStrLn "sending live probe..."
951 sendProbe from to 975 sendProbe from to
976 Solicitation from to -> do
977 liftIO $ L.putStrLn "sending live solicitation..."
978 sendSolicitation from to
952 loop 979 loop
953 send goodbyePeer 980 send goodbyePeer
954 981
diff --git a/Presence/XMPPTypes.hs b/Presence/XMPPTypes.hs
index 2bba8614..2bad795a 100644
--- a/Presence/XMPPTypes.hs
+++ b/Presence/XMPPTypes.hs
@@ -45,7 +45,7 @@ class JabberClientSession session where
45 getMyOthers :: session -> IO [ByteString] 45 getMyOthers :: session -> IO [ByteString]
46 getMyPending :: session -> IO [ByteString] 46 getMyPending :: session -> IO [ByteString]
47 getMySolicited :: session -> IO [ByteString] 47 getMySolicited :: session -> IO [ByteString]
48 addSolicited :: session -> ByteString -> IO () 48 addSolicited :: session -> ByteString -> JID -> IO ()
49 49
50class JabberPeerSession session where 50class JabberPeerSession session where
51 data XMPPPeerClass session 51 data XMPPPeerClass session
diff --git a/Presence/main.hs b/Presence/main.hs
index bbaac97a..036d7237 100644
--- a/Presence/main.hs
+++ b/Presence/main.hs
@@ -2,6 +2,7 @@
2{-# LANGUAGE OverloadedStrings #-} 2{-# LANGUAGE OverloadedStrings #-}
3{-# LANGUAGE TypeFamilies #-} 3{-# LANGUAGE TypeFamilies #-}
4{-# LANGUAGE ExistentialQuantification #-} 4{-# LANGUAGE ExistentialQuantification #-}
5{-# LANGUAGE TupleSections #-}
5module Main where 6module Main where
6 7
7import System.Directory 8import System.Directory
@@ -196,15 +197,19 @@ instance JabberClientSession ClientSession where
196 L.putStrLn $ "cached presence: " <++> bshow p 197 L.putStrLn $ "cached presence: " <++> bshow p
197 action p 198 action p
198 199
199 addSolicited s jid = do 200 addSolicited s jid_str jid = do
200 user <- readIORef (unix_uid s) >>= getJabberUserForId 201 me <- getJID s
201 addJid ConfigFiles.modifySolicited user jid 202 withJust (name me) $ \user -> do
203 addJid ConfigFiles.modifySolicited user jid_str
202 let rchan = rosterChannel . presence_state $ s 204 let rchan = rosterChannel . presence_state $ s
203 atomically $ do 205 atomically $ do
204 isempty <- isEmptyTMVar rchan 206 isempty <- isEmptyTMVar rchan
205 when (not isempty) $ do 207 when (not isempty) $ do
206 (_,ch) <- readTMVar rchan 208 (_,ch) <- readTMVar rchan
207 writeTChan ch (RequestedSubscription user jid) 209 writeTChan ch (RequestedSubscription user jid_str)
210 sendMessage (outGoingConnections . presence_state $ s)
211 (Solicitation me jid)
212 (peer jid)
208 213
209 214
210 getMyBuddies s = do 215 getMyBuddies s = do
@@ -381,16 +386,20 @@ sendProbes state jid = do
381 buddies <- ConfigFiles.getBuddies user 386 buddies <- ConfigFiles.getBuddies user
382 fmap catMaybes (mapM parseHostNameJID' buddies) 387 fmap catMaybes (mapM parseHostNameJID' buddies)
383 L.putStrLn $ "buddies for " <++> bshow jid <++> " = " <++> bshow buddies 388 L.putStrLn $ "buddies for " <++> bshow jid <++> " = " <++> bshow buddies
389 wanted <- do
390 wanted <- ConfigFiles.getSolicited user
391 fmap catMaybes (mapM parseHostNameJID' wanted)
384 remotes <- readTVarIO (remoteUsers state) 392 remotes <- readTVarIO (remoteUsers state)
385 forM_ buddies $ \buddy -> do 393 forM_ (map (True,) buddies ++ map (False,) wanted) $ \(got,buddy) -> do
386 let mjids = fmap snd $ Map.lookup (peer buddy) remotes 394 let mjids = fmap snd $ Map.lookup (peer buddy) remotes
387 jids <- maybe (return MM.empty) readTVarIO mjids 395 jids <- maybe (return MM.empty) readTVarIO mjids
388 withJust (splitResource buddy) $ \(buddyU,_) -> do 396 withJust (splitResource buddy) $ \(buddyU,_) -> do
389 let noinfo = not (MM.member buddyU jids) 397 let noinfo = not (MM.member buddyU jids)
390 when noinfo $ do 398 when noinfo $ do
391 L.putStrLn $ "sendMessage " <++> bshow (PresenceProbe jid buddy) 399 let msg = if got then PresenceProbe jid buddy else Solicitation jid buddy
392 sendMessage (outGoingConnections state) (PresenceProbe jid buddy) (peer buddy) 400 L.putStrLn $ "sendMessage " <++> bshow msg
393 return () 401 sendMessage (outGoingConnections state) msg (peer buddy)
402
394 403
395track_login host state e = do 404track_login host state e = do
396#ifndef NOUTMP 405#ifndef NOUTMP