summaryrefslogtreecommitdiff
path: root/Presence
diff options
context:
space:
mode:
Diffstat (limited to 'Presence')
-rw-r--r--Presence/ConfigFiles.hs8
-rw-r--r--Presence/XMPP.hs48
-rw-r--r--Presence/XMPPTypes.hs7
-rw-r--r--Presence/main.hs56
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
91modifySolicited = modifyFile ("<? solicited ?>", solicitedFile) 91modifySolicited = modifyFile ("<? solicited ?>" , solicitedFile)
92modifyBuddies = modifyFile ("<? buddies ?>" , buddyFile) 92modifyBuddies = modifyFile ("<? buddies ?>" , buddyFile)
93modifyOthers = modifyFile ("<? others ?>" , otherFile) 93modifyOthers = modifyFile ("<? others ?>" , otherFile)
94modifyPending = modifyFile ("<? pending ?>" , pendingFile)
95modifySubscribers = modifyFile ("<? subscribers ?>", subscriberFile)
94 96
95addBuddy :: User -> ByteString -> IO () 97addBuddy :: User -> ByteString -> IO ()
96addBuddy user buddy = 98addBuddy 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
546handleClient 569handleClient
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
816clientApprovesSubscription session stanza = do 833clientApprovesSubscription 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
824peerApprovesSubscription session stanza = do 838peerApprovesSubscription 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
38import SocketLike 38import SocketLike
39import GetHostByAddr 39import GetHostByAddr
40import Data.Maybe (listToMaybe,catMaybes) 40import Data.Maybe (listToMaybe,catMaybes)
41import Control.Monad.STM
41 42
42class JabberClientSession session where 43class 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
59class JabberPeerSession session where 62class 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
73data JID = JID { name :: Maybe ByteString 77data 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
95data Peer = LocalHost | RemotePeer SockAddr 102data 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
250tupleToJID (user,tty,pid) = jid user LocalHost tty 282tupleToJID (user,tty,pid) = jid user LocalHost tty
251 283
252data PeerSession = PeerSession { 284data 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
336data RefCountedChan = forall a. RefCountedChan (TMVar (RefCount,TChan a)) 390data RefCountedChan = forall a. RefCountedChan (TMVar (RefCount,TChan a))