diff options
Diffstat (limited to 'Presence')
-rw-r--r-- | Presence/ConfigFiles.hs | 8 | ||||
-rw-r--r-- | Presence/XMPP.hs | 48 | ||||
-rw-r--r-- | Presence/XMPPTypes.hs | 7 | ||||
-rw-r--r-- | Presence/main.hs | 56 |
4 files changed, 98 insertions, 21 deletions
diff --git a/Presence/ConfigFiles.hs b/Presence/ConfigFiles.hs index 39442ffd..808e6dd8 100644 --- a/Presence/ConfigFiles.hs +++ b/Presence/ConfigFiles.hs | |||
@@ -88,9 +88,11 @@ modifyFile (tag,file) user test appending = configPath user file >>= doit | |||
88 | return False | 88 | return False |
89 | 89 | ||
90 | 90 | ||
91 | modifySolicited = modifyFile ("<? solicited ?>", solicitedFile) | 91 | modifySolicited = modifyFile ("<? solicited ?>" , solicitedFile) |
92 | modifyBuddies = modifyFile ("<? buddies ?>" , buddyFile) | 92 | modifyBuddies = modifyFile ("<? buddies ?>" , buddyFile) |
93 | modifyOthers = modifyFile ("<? others ?>" , otherFile) | 93 | modifyOthers = modifyFile ("<? others ?>" , otherFile) |
94 | modifyPending = modifyFile ("<? pending ?>" , pendingFile) | ||
95 | modifySubscribers = modifyFile ("<? subscribers ?>", subscriberFile) | ||
94 | 96 | ||
95 | addBuddy :: User -> ByteString -> IO () | 97 | addBuddy :: User -> ByteString -> IO () |
96 | addBuddy user buddy = | 98 | addBuddy user buddy = |
diff --git a/Presence/XMPP.hs b/Presence/XMPP.hs index 9190ee3c..173e7cdf 100644 --- a/Presence/XMPP.hs +++ b/Presence/XMPP.hs | |||
@@ -419,6 +419,7 @@ handleIQGet session cmdChan tag = do | |||
419 | atomically $ do | 419 | atomically $ do |
420 | writeTChan cmdChan InterestedInRoster | 420 | writeTChan cmdChan InterestedInRoster |
421 | writeTChan cmdChan . Send $ roster | 421 | writeTChan cmdChan . Send $ roster |
422 | sendPending session | ||
422 | req -> unhandledGet req | 423 | req -> unhandledGet req |
423 | 424 | ||
424 | 425 | ||
@@ -502,15 +503,17 @@ toClient session pchan cmdChan rchan = toClient' False False | |||
502 | let loop = toClient' isBound isInterested | 503 | let loop = toClient' isBound isInterested |
503 | send xs = yield xs >> prettyPrint ">C: " xs | 504 | send xs = yield xs >> prettyPrint ">C: " xs |
504 | event <- liftIO . atomically $ | 505 | event <- liftIO . atomically $ |
505 | foldr1 orElse [fmap PChan $ readTChan pchan | 506 | foldr1 orElse [fmap CmdChan $ readTChan cmdChan |
506 | ,fmap RChan $ readTChan rchan | 507 | ,fmap RChan $ readTChan rchan |
507 | ,fmap CmdChan $ readTChan cmdChan | 508 | ,fmap PChan $ readTChan pchan |
508 | ] | 509 | ] |
509 | case event of | 510 | case event of |
510 | CmdChan QuitThread -> return () | 511 | CmdChan QuitThread -> return () |
511 | CmdChan (Send xs) -> send xs >> loop | 512 | CmdChan (Send xs) -> send xs >> loop |
512 | CmdChan BoundToResource -> toClient' True isInterested | 513 | CmdChan BoundToResource -> toClient' True isInterested |
513 | CmdChan InterestedInRoster -> toClient' isBound True | 514 | CmdChan InterestedInRoster -> do |
515 | liftIO . putStrLn $ "Roster: interested" | ||
516 | toClient' isBound True | ||
514 | -- CmdChan cmd -> liftIO (putStrLn $ "unhandled event: "++show cmd) >> loop | 517 | -- CmdChan cmd -> liftIO (putStrLn $ "unhandled event: "++show cmd) >> loop |
515 | RChan (RequestedSubscription who contact) -> do | 518 | RChan (RequestedSubscription who contact) -> do |
516 | jid <- liftIO $ getJID session | 519 | jid <- liftIO $ getJID session |
@@ -520,11 +523,15 @@ toClient session pchan cmdChan rchan = toClient' False False | |||
520 | loop | 523 | loop |
521 | RChan (NewBuddy who contact) -> do | 524 | RChan (NewBuddy who contact) -> do |
522 | liftIO . putStrLn $ "Roster push: NewBuddy "++show (isInterested,who,contact) | 525 | liftIO . putStrLn $ "Roster push: NewBuddy "++show (isInterested,who,contact) |
523 | jid <- liftIO $ getJID session | 526 | (jid,me) <- liftIO $ do |
527 | jid <- getJID session | ||
528 | me <- asHostNameJID jid | ||
529 | return (jid,me) | ||
530 | withJust me $ \me -> do | ||
524 | when (isInterested && Just who==name jid) $ do | 531 | when (isInterested && Just who==name jid) $ do |
525 | send [ EventBeginElement "{jabber:client}presence" | 532 | send [ EventBeginElement "{jabber:client}presence" |
526 | [ attrbs "from" contact | 533 | [ attrbs "from" contact |
527 | , attrbs "to" (L.show jid) | 534 | , attrbs "to" me |
528 | , attr "type" "subscribed" | 535 | , attr "type" "subscribed" |
529 | ] | 536 | ] |
530 | , EventEndElement "{jabber:client}presence" ] | 537 | , EventEndElement "{jabber:client}presence" ] |
@@ -537,12 +544,28 @@ toClient session pchan cmdChan rchan = toClient' False False | |||
537 | [attr "subscription" subscription] | 544 | [attr "subscription" subscription] |
538 | send r | 545 | send r |
539 | loop | 546 | loop |
547 | RChan (PendingBuddy who contact) -> do | ||
548 | liftIO . putStrLn $ "Roster: Pending buddy "++show (isInterested,who,contact) | ||
549 | (jid,me) <- liftIO $ do | ||
550 | jid <- getJID session | ||
551 | me <- asHostNameJID jid | ||
552 | return (jid,me) | ||
553 | withJust me $ \me -> do | ||
554 | when (isInterested && Just who==name jid) $ do | ||
555 | send [ EventBeginElement "{jabber:client}presence" | ||
556 | [ attrbs "from" contact | ||
557 | , attrbs "to" me | ||
558 | , attr "type" "subscribe" | ||
559 | ] | ||
560 | , EventEndElement "{jabber:client}presence" ] | ||
561 | loop | ||
540 | PChan presence -> do | 562 | PChan presence -> do |
541 | when isBound $ do | 563 | when isBound $ do |
542 | xs <- liftIO $ xmlifyPresenceForClient presence | 564 | xs <- liftIO $ xmlifyPresenceForClient presence |
543 | send xs | 565 | send xs |
544 | loop | 566 | loop |
545 | 567 | ||
568 | |||
546 | handleClient | 569 | handleClient |
547 | :: (SocketLike sock, HHead l (XMPPClass session), | 570 | :: (SocketLike sock, HHead l (XMPPClass session), |
548 | JabberClientSession session) => | 571 | JabberClientSession session) => |
@@ -805,21 +828,12 @@ peerRequestsSubsription session stanza = do | |||
805 | ps <- userStatus session user | 828 | ps <- userStatus session user |
806 | mapM_ (announcePresence session) ps | 829 | mapM_ (announcePresence session) ps |
807 | else | 830 | else |
808 | -- TODO | 831 | liftIO $ processRequest session user fromjid |
809 | -- if no client: | ||
810 | -- add pending | ||
811 | -- else: | ||
812 | -- notify client(s) | ||
813 | return () | ||
814 | return () | ||
815 | 832 | ||
816 | clientApprovesSubscription session stanza = do | 833 | clientApprovesSubscription session stanza = do |
817 | liftIO $ putStrLn $ "CLIENT APPROVES SUBSCRIPTION" | 834 | liftIO $ putStrLn $ "CLIENT APPROVES SUBSCRIPTION" |
818 | -- add subscribers | 835 | withJust (lookupAttrib "to" (tagAttrs stanza)) $ \to_str -> do |
819 | -- remove pending | 836 | liftIO $ approveSubscriber session (textToByteString to_str) |
820 | -- remove others | ||
821 | -- notify peer | ||
822 | return () | ||
823 | 837 | ||
824 | peerApprovesSubscription session stanza = do | 838 | peerApprovesSubscription session stanza = do |
825 | liftIO $ putStrLn $ "PEER APPROVES SUBSCRIPTION" | 839 | liftIO $ putStrLn $ "PEER APPROVES SUBSCRIPTION" |
diff --git a/Presence/XMPPTypes.hs b/Presence/XMPPTypes.hs index e05d0782..6d00d509 100644 --- a/Presence/XMPPTypes.hs +++ b/Presence/XMPPTypes.hs | |||
@@ -38,6 +38,7 @@ import ByteStringOperators | |||
38 | import SocketLike | 38 | import SocketLike |
39 | import GetHostByAddr | 39 | import GetHostByAddr |
40 | import Data.Maybe (listToMaybe,catMaybes) | 40 | import Data.Maybe (listToMaybe,catMaybes) |
41 | import Control.Monad.STM | ||
41 | 42 | ||
42 | class JabberClientSession session where | 43 | class JabberClientSession session where |
43 | data XMPPClass session | 44 | data XMPPClass session |
@@ -48,6 +49,7 @@ class JabberClientSession session where | |||
48 | subscribe :: session -> Maybe JID -> IO (TChan Presence) | 49 | subscribe :: session -> Maybe JID -> IO (TChan Presence) |
49 | subscribeToRoster :: session -> IO (TChan RosterEvent) | 50 | subscribeToRoster :: session -> IO (TChan RosterEvent) |
50 | forCachedPresence :: session -> (Presence -> IO ()) -> IO () | 51 | forCachedPresence :: session -> (Presence -> IO ()) -> IO () |
52 | sendPending :: session -> IO () | ||
51 | getMyBuddies :: session -> IO [ByteString] | 53 | getMyBuddies :: session -> IO [ByteString] |
52 | getMySubscribers :: session -> IO [ByteString] | 54 | getMySubscribers :: session -> IO [ByteString] |
53 | getMyOthers :: session -> IO [ByteString] | 55 | getMyOthers :: session -> IO [ByteString] |
@@ -55,6 +57,7 @@ class JabberClientSession session where | |||
55 | getMySolicited :: session -> IO [ByteString] | 57 | getMySolicited :: session -> IO [ByteString] |
56 | addSolicited :: session -> ByteString -> JID -> IO () | 58 | addSolicited :: session -> ByteString -> JID -> IO () |
57 | isSubscribed :: session -> ByteString -> IO Bool | 59 | isSubscribed :: session -> ByteString -> IO Bool |
60 | approveSubscriber :: session -> ByteString -> IO () | ||
58 | 61 | ||
59 | class JabberPeerSession session where | 62 | class JabberPeerSession session where |
60 | data XMPPPeerClass session | 63 | data XMPPPeerClass session |
@@ -68,6 +71,7 @@ class JabberPeerSession session where | |||
68 | getBuddies :: XMPPPeerClass session -> ByteString -> IO [ByteString] | 71 | getBuddies :: XMPPPeerClass session -> ByteString -> IO [ByteString] |
69 | getSubscribers :: XMPPPeerClass session -> ByteString -> IO [ByteString] | 72 | getSubscribers :: XMPPPeerClass session -> ByteString -> IO [ByteString] |
70 | processApproval :: session -> ByteString -> JID -> IO () | 73 | processApproval :: session -> ByteString -> JID -> IO () |
74 | processRequest :: session -> ByteString -> JID -> IO () | ||
71 | 75 | ||
72 | -- | Jabber ID (JID) datatype | 76 | -- | Jabber ID (JID) datatype |
73 | data JID = JID { name :: Maybe ByteString | 77 | data JID = JID { name :: Maybe ByteString |
@@ -90,6 +94,9 @@ data RosterEvent = RequestedSubscription | |||
90 | | NewBuddy | 94 | | NewBuddy |
91 | {- user: -} ByteString | 95 | {- user: -} ByteString |
92 | {- contact: -} ByteString | 96 | {- contact: -} ByteString |
97 | | PendingBuddy | ||
98 | {- user: -} ByteString | ||
99 | {- contact: -} ByteString | ||
93 | deriving Prelude.Show | 100 | deriving Prelude.Show |
94 | 101 | ||
95 | data Peer = LocalHost | RemotePeer SockAddr | 102 | data Peer = LocalHost | RemotePeer SockAddr |
diff --git a/Presence/main.hs b/Presence/main.hs index eab02e88..5cccffea 100644 --- a/Presence/main.hs +++ b/Presence/main.hs | |||
@@ -207,6 +207,23 @@ instance JabberClientSession ClientSession where | |||
207 | L.putStrLn $ "cached presence: " <++> bshow p | 207 | L.putStrLn $ "cached presence: " <++> bshow p |
208 | action p | 208 | action p |
209 | 209 | ||
210 | sendPending s = do | ||
211 | jid <- getJID s | ||
212 | putStrLn $ "sendPending "<++> bshow jid | ||
213 | flip (maybe (return ())) (name jid) $ \user -> do | ||
214 | pending <- ConfigFiles.getPending user | ||
215 | let getRChan = do | ||
216 | let rchan = rosterChannel . presence_state $ s | ||
217 | isempty <- isEmptyTMVar rchan | ||
218 | if (not isempty) | ||
219 | then do | ||
220 | (_,ch) <- readTMVar rchan | ||
221 | return . Just $ ch | ||
222 | else return Nothing | ||
223 | atomically $ do | ||
224 | whenJust getRChan $ \rchan -> do | ||
225 | forM_ pending (writeTChan rchan . PendingBuddy user) | ||
226 | |||
210 | addSolicited s jid_str jid = do | 227 | addSolicited s jid_str jid = do |
211 | me <- getJID s | 228 | me <- getJID s |
212 | withJust (name me) $ \user -> do | 229 | withJust (name me) $ \user -> do |
@@ -247,6 +264,21 @@ instance JabberClientSession ClientSession where | |||
247 | msubs <- mapM (cmpJID cjid) subs | 264 | msubs <- mapM (cmpJID cjid) subs |
248 | return (Nothing `elem` msubs) | 265 | return (Nothing `elem` msubs) |
249 | 266 | ||
267 | approveSubscriber s contact = do | ||
268 | user <- readIORef (unix_uid s) >>= getJabberUserForId | ||
269 | cjid <- parseHostNameJID contact | ||
270 | let rmjid modify user buddy = modify user (cmpJID buddy) Nothing | ||
271 | addRawJid ConfigFiles.modifySubscribers user contact -- add subscribers | ||
272 | rmjid ConfigFiles.modifyPending user cjid | ||
273 | rmjid ConfigFiles.modifyOthers user cjid | ||
274 | -- TODO | ||
275 | -- roster push (to other clients, or do we include the approver?) | ||
276 | sendMessage (outGoingConnections . presence_state $ s) | ||
277 | (Approval (JID (Just user) LocalHost Nothing) | ||
278 | cjid) | ||
279 | (peer cjid) | ||
280 | |||
281 | |||
250 | tupleToJID (user,tty,pid) = jid user LocalHost tty | 282 | tupleToJID (user,tty,pid) = jid user LocalHost tty |
251 | 283 | ||
252 | data PeerSession = PeerSession { | 284 | data PeerSession = PeerSession { |
@@ -330,7 +362,29 @@ instance JabberPeerSession PeerSession where | |||
330 | (_,ch) <- readTMVar rchan | 362 | (_,ch) <- readTMVar rchan |
331 | writeTChan ch (NewBuddy user buddy) | 363 | writeTChan ch (NewBuddy user buddy) |
332 | return () | 364 | return () |
333 | 365 | processRequest session user buddy = do | |
366 | let addjid modify user buddy = do | ||
367 | hbuddy <- asHostNameJID buddy | ||
368 | modify user (cmpJID buddy) hbuddy | ||
369 | was_pending <- addjid ConfigFiles.modifyPending user buddy | ||
370 | putStrLn $ "processRequest was_pending="<++>bshow was_pending | ||
371 | -- "all available resources in accordence with section 8" | ||
372 | -- Section 8 says (for presence of type "subscribe", the server MUST | ||
373 | -- adhere to the rules defined under Section 3 and summarized under | ||
374 | -- Appendix A. | ||
375 | -- Appendex A.3.1 says | ||
376 | -- contact ∈ subscribers --> SHOULD NOT, already handled | ||
377 | -- contact ∉ subscribers & contact ∈ pending --> SHOULD NOT | ||
378 | -- contact ∉ subscribers & contact ∉ pending --> MUST | ||
379 | when (not was_pending) $ do | ||
380 | let rchan = rosterChannel . peer_global $ session | ||
381 | mbuddy <- asHostNameJID buddy | ||
382 | withJust mbuddy $ \buddy -> do | ||
383 | atomically $ do | ||
384 | isempty <- isEmptyTMVar rchan | ||
385 | when (not isempty) $ do | ||
386 | (_,ch) <- readTMVar rchan | ||
387 | writeTChan ch (PendingBuddy user buddy) | ||
334 | 388 | ||
335 | 389 | ||
336 | data RefCountedChan = forall a. RefCountedChan (TMVar (RefCount,TChan a)) | 390 | data RefCountedChan = forall a. RefCountedChan (TMVar (RefCount,TChan a)) |