summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--xmppServer.hs99
1 files changed, 77 insertions, 22 deletions
diff --git a/xmppServer.hs b/xmppServer.hs
index d553d1e7..81cbf212 100644
--- a/xmppServer.hs
+++ b/xmppServer.hs
@@ -15,7 +15,7 @@ import Network.Socket
15 , SockAddr(..) 15 , SockAddr(..)
16 ) 16 )
17import System.Endian (fromBE32) 17import System.Endian (fromBE32)
18import Data.List (nub) 18import Data.List (nub, (\\) )
19import Data.Monoid ( (<>) ) 19import Data.Monoid ( (<>) )
20import qualified Data.Text as Text 20import qualified Data.Text as Text
21import qualified Data.Text.IO as Text 21import qualified Data.Text.IO as Text
@@ -27,6 +27,7 @@ import Data.Text (Text)
27import qualified Data.Map as Map 27import qualified Data.Map as Map
28import Data.Map (Map) 28import Data.Map (Map)
29import Control.Exception ({-evaluate,-}handle,SomeException(..),bracketOnError,ErrorCall(..)) 29import Control.Exception ({-evaluate,-}handle,SomeException(..),bracketOnError,ErrorCall(..))
30import System.IO.Error (isDoesNotExistError)
30import System.Posix.User (getUserEntryForID,userName) 31import System.Posix.User (getUserEntryForID,userName)
31import qualified Data.ByteString.Lazy.Char8 as L 32import qualified Data.ByteString.Lazy.Char8 as L
32import qualified ConfigFiles 33import qualified ConfigFiles
@@ -471,6 +472,9 @@ subscribedPeers user = do
471 let hosts = map ((\(_,h,_)->h) . splitJID) jids 472 let hosts = map ((\(_,h,_)->h) . splitJID) jids
472 fmap Map.keys $ resolveAllPeers hosts 473 fmap Map.keys $ resolveAllPeers hosts
473 474
475clientJID con client = unsplitJID ( Just $ clientUser client
476 , addrToText $ auxAddr con
477 , Just $ clientResource client)
474 478
475-- | Send presence notification to subscribed peers. 479-- | Send presence notification to subscribed peers.
476-- Note that a full JID from address will be added to the 480-- Note that a full JID from address will be added to the
@@ -489,9 +493,7 @@ informClientPresence state k stanza = do
489 ktc <- atomically $ readTVar (keyToChan state) 493 ktc <- atomically $ readTVar (keyToChan state)
490 let connected = mapMaybe (flip Map.lookup ktc . PeerKey) addrs 494 let connected = mapMaybe (flip Map.lookup ktc . PeerKey) addrs
491 forM_ connected $ \con -> do 495 forM_ connected $ \con -> do
492 let from' = unsplitJID ( Just $ clientUser client 496 let from' = clientJID con client
493 , addrToText $ auxAddr con
494 , Just $ clientResource client)
495 mto <- runTraversableT $ do 497 mto <- runTraversableT $ do
496 to <- liftT $ stanzaTo stanza 498 to <- liftT $ stanzaTo stanza
497 (to',_) <- liftMT $ rewriteJIDForPeer to 499 (to',_) <- liftMT $ rewriteJIDForPeer to
@@ -612,33 +614,86 @@ sendCachedPresence state k = do
612 -- send local buddies. 614 -- send local buddies.
613 return () 615 return ()
614 616
617addToRosterFile doit whose to addrs = do
618 let (mu,_,_) = splitJID to
619 cmp jid = runTraversableT $ do
620 let (mu,stored_h,mr) = splitJID (lazyByteStringToText jid)
621 flip (maybe mzero) mr . const $ do
622 flip (maybe mzero) mu $ \stored_u -> do
623 flip (maybe $ return jid) mu $ \u -> do
624 if stored_u /= u then return jid else do
625 stored_addrs <- lift $ nub `fmap` resolvePeer stored_h
626 if null (stored_addrs \\ addrs) then return jid else do
627 mzero
628 doit (textToLazyByteString whose)
629 cmp
630 (Just $ textToLazyByteString to)
631
615clientSubscriptionRequest :: PresenceState -> IO () -> ConnectionKey -> Stanza -> TChan Stanza -> IO () 632clientSubscriptionRequest :: PresenceState -> IO () -> ConnectionKey -> Stanza -> TChan Stanza -> IO ()
616clientSubscriptionRequest state fail k stanza chan = do 633clientSubscriptionRequest state fail k stanza chan = do
634 forClient state k fail $ \client -> do
617 flip (maybe fail) (stanzaTo stanza) $ \to -> do 635 flip (maybe fail) (stanzaTo stanza) $ \to -> do
618 putStrLn $ "TODO: clientSubscriptionRequest" 636 putStrLn $ "Forwarding solictation to peer"
619 -- TODO: resolve hostname 637 let (mu,h,_) = splitJID to
620 -- TODO: add to solicited 638 to <- return $ unsplitJID (mu,h,Nothing) -- delete resource
621 -- TODO; if already connected, send solicitation 639 flip (maybe fail) mu $ \u -> do
622 -- TODO: addPeer 640 addrs <- nub `fmap` resolvePeer h
623 return () 641 if null addrs then fail else do
642 -- add to-address to from's solicited
643 addToRosterFile ConfigFiles.modifySolicited (clientUser client) to addrs
644 (ktc,ap) <- atomically $
645 liftM2 (,) (readTVar $ keyToChan state)
646 (readTVar $ associatedPeers state)
647 let dsts = Map.fromList $ map ((,()) . PeerKey) addrs
648 cdsts = ktc Map.\\ dsts
649 forM_ (Map.toList cdsts) $ \(pk,con) -> do
650 -- if already connected, send solicitation ...
651 let from = clientJID con client
652 sendModifiedStanzaToPeer (stanza { stanzaTo = Just to
653 , stanzaFrom = Just from })
654 (connChan con)
655 let addrm = Map.fromList (map (,()) addrs)
656 when (not . Map.null $ addrm Map.\\ ap) $ do
657 -- Add peer if we are not already associated ...
658 sv <- atomically $ takeTMVar $ server state
659 addPeer sv (head addrs)
624 660
625peerSubscriptionRequest :: PresenceState -> IO () -> ConnectionKey -> Stanza -> TChan Stanza -> IO () 661peerSubscriptionRequest :: PresenceState -> IO () -> ConnectionKey -> Stanza -> TChan Stanza -> IO ()
626peerSubscriptionRequest state fail k stanza chan = do 662peerSubscriptionRequest state fail k stanza chan = do
627 putStrLn $ "TODO: peerSubscriptionRequest" 663 putStrLn $ "TODO: peerSubscriptionRequest"
628 -- TODO: if already subscribed, reply and quit 664 flip (maybe fail) (stanzaFrom stanza) $ \from -> do
629 665 flip (maybe fail) (stanzaTo stanza) $ \to -> do
630 -- TODO: add to pending 666 let (mto_u,h,_) = splitJID to
631 667 (mfrom_u,from_h,_) = splitJID from
632 -- TODO: send to clients 668 to <- return $ unsplitJID (mto_u,h,Nothing) -- delete resource
633 -- "all available resources in accordence with section 8" 669 from <- return $ unsplitJID (mfrom_u,from_h,Nothing) -- delete resource
670 flip (maybe fail) mto_u $ \u -> do
671 flip (maybe fail) mfrom_u $ \from_u -> do
672 subs <- configText ConfigFiles.getSubscribers u
673 let resolved_subs = runTraversableT $ do
674 (mu,h,_) <- liftT $ splitJID `fmap` subs
675 addr <- liftMT $ resolvePeer h
676 return (mu,PeerKey addr)
677 already_subscribed <- fmap (elem (mfrom_u,k)) resolved_subs
634 -- Section 8 says (for presence of type "subscribe", the server MUST 678 -- Section 8 says (for presence of type "subscribe", the server MUST
635 -- adhere to the rules defined under Section 3 and summarized under 679 -- adhere to the rules defined under Section 3 and summarized under
636 -- Appendix A. 680 -- see Appendix A. (pariticularly Appendex A.3.1)
637 -- Appendex A.3.1 says 681 if already_subscribed
638 -- contact ∈ subscribers --> SHOULD NOT, already handled 682 then do
639 -- contact ∉ subscribers & contact ∈ pending --> SHOULD NOT 683 -- contact ∈ subscribers --> SHOULD NOT, already handled
640 -- contact ∉ subscribers & contact ∉ pending --> MUST 684 -- TODO: already subscribed, reply and quit
641 685 return ()
686 else do
687 -- Catch exception in case the user does not exist
688 handle (\e -> let _ = isDoesNotExistError e in fail) $ do
689 -- add from-address to to's pending
690 addrs <- resolvePeer from_h
691 already_pending <- addToRosterFile ConfigFiles.modifyPending u from addrs
692
693 -- contact ∉ subscribers & contact ∈ pending --> SHOULD NOT
694 when (not already_pending) $ do
695 -- contact ∉ subscribers & contact ∉ pending --> MUST
696 -- TODO: send to clients
642 return () 697 return ()
643 698
644clientInformSubscription state fail k stanza = do 699clientInformSubscription state fail k stanza = do