diff options
-rw-r--r-- | xmppServer.hs | 99 |
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 | ) |
17 | import System.Endian (fromBE32) | 17 | import System.Endian (fromBE32) |
18 | import Data.List (nub) | 18 | import Data.List (nub, (\\) ) |
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 |
@@ -27,6 +27,7 @@ import Data.Text (Text) | |||
27 | import qualified Data.Map as Map | 27 | import qualified Data.Map as Map |
28 | import Data.Map (Map) | 28 | import Data.Map (Map) |
29 | import Control.Exception ({-evaluate,-}handle,SomeException(..),bracketOnError,ErrorCall(..)) | 29 | import Control.Exception ({-evaluate,-}handle,SomeException(..),bracketOnError,ErrorCall(..)) |
30 | import System.IO.Error (isDoesNotExistError) | ||
30 | import System.Posix.User (getUserEntryForID,userName) | 31 | import System.Posix.User (getUserEntryForID,userName) |
31 | import qualified Data.ByteString.Lazy.Char8 as L | 32 | import qualified Data.ByteString.Lazy.Char8 as L |
32 | import qualified ConfigFiles | 33 | import 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 | ||
475 | clientJID 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 | ||
617 | addToRosterFile 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 | |||
615 | clientSubscriptionRequest :: PresenceState -> IO () -> ConnectionKey -> Stanza -> TChan Stanza -> IO () | 632 | clientSubscriptionRequest :: PresenceState -> IO () -> ConnectionKey -> Stanza -> TChan Stanza -> IO () |
616 | clientSubscriptionRequest state fail k stanza chan = do | 633 | clientSubscriptionRequest 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 | ||
625 | peerSubscriptionRequest :: PresenceState -> IO () -> ConnectionKey -> Stanza -> TChan Stanza -> IO () | 661 | peerSubscriptionRequest :: PresenceState -> IO () -> ConnectionKey -> Stanza -> TChan Stanza -> IO () |
626 | peerSubscriptionRequest state fail k stanza chan = do | 662 | peerSubscriptionRequest 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 | ||
644 | clientInformSubscription state fail k stanza = do | 699 | clientInformSubscription state fail k stanza = do |