diff options
Diffstat (limited to 'Presence/Presence.hs')
-rw-r--r-- | Presence/Presence.hs | 213 |
1 files changed, 128 insertions, 85 deletions
diff --git a/Presence/Presence.hs b/Presence/Presence.hs index 15775857..9b91dc1d 100644 --- a/Presence/Presence.hs +++ b/Presence/Presence.hs | |||
@@ -32,7 +32,7 @@ import System.IO.Error (isDoesNotExistError) | |||
32 | import System.Posix.User (getUserEntryForID,userName) | 32 | import System.Posix.User (getUserEntryForID,userName) |
33 | import qualified Data.ByteString.Lazy.Char8 as L | 33 | import qualified Data.ByteString.Lazy.Char8 as L |
34 | import qualified ConfigFiles | 34 | import qualified ConfigFiles |
35 | import Data.Maybe (maybeToList,listToMaybe,mapMaybe) | 35 | import Data.Maybe |
36 | import Data.Bits | 36 | import Data.Bits |
37 | import Data.Int (Int8) | 37 | import Data.Int (Int8) |
38 | import Data.XML.Types (Event) | 38 | import Data.XML.Types (Event) |
@@ -56,10 +56,12 @@ isPeerKey k = case k of { PeerKey {} -> True ; _ -> False } | |||
56 | isClientKey :: ConnectionKey -> Bool | 56 | isClientKey :: ConnectionKey -> Bool |
57 | isClientKey k = case k of { ClientKey {} -> True ; _ -> False } | 57 | isClientKey k = case k of { ClientKey {} -> True ; _ -> False } |
58 | 58 | ||
59 | localJID :: Text -> Text -> IO Text | 59 | localJID :: Text -> Text -> Text -> IO Text |
60 | localJID user resource = do | 60 | localJID user "." resource = do |
61 | hostname <- textHostName | 61 | hostname <- textHostName |
62 | return $ user <> "@" <> hostname <> "/" <> resource | 62 | return $ user <> "@" <> hostname <> "/" <> resource |
63 | localJID user profile resource = | ||
64 | return $ user <> "@" <> profile <> "/" <> resource | ||
63 | 65 | ||
64 | data PresenceState = forall status. PresenceState | 66 | data PresenceState = forall status. PresenceState |
65 | { clients :: TVar (Map ConnectionKey ClientState) | 67 | { clients :: TVar (Map ConnectionKey ClientState) |
@@ -72,6 +74,9 @@ data PresenceState = forall status. PresenceState | |||
72 | } | 74 | } |
73 | 75 | ||
74 | 76 | ||
77 | newPresenceState :: Maybe ConsoleWriter | ||
78 | -> TMVar (XMPPServer, Connection.Manager status Text) | ||
79 | -> IO PresenceState | ||
75 | newPresenceState cw xmpp = atomically $ do | 80 | newPresenceState cw xmpp = atomically $ do |
76 | clients <- newTVar Map.empty | 81 | clients <- newTVar Map.empty |
77 | clientsByUser <- newTVar Map.empty | 82 | clientsByUser <- newTVar Map.empty |
@@ -87,6 +92,7 @@ newPresenceState cw xmpp = atomically $ do | |||
87 | } | 92 | } |
88 | 93 | ||
89 | 94 | ||
95 | presenceHooks :: PresenceState -> Int -> XMPPServerParameters | ||
90 | presenceHooks state verbosity = XMPPServerParameters | 96 | presenceHooks state verbosity = XMPPServerParameters |
91 | { xmppChooseResourceName = chooseResourceName state | 97 | { xmppChooseResourceName = chooseResourceName state |
92 | , xmppTellClientHisName = tellClientHisName state | 98 | , xmppTellClientHisName = tellClientHisName state |
@@ -165,21 +171,25 @@ identifyTTY' ttypids uid inode = ttypid | |||
165 | textify (tty,pid) = (fmap lazyByteStringToText tty, pid) | 171 | textify (tty,pid) = (fmap lazyByteStringToText tty, pid) |
166 | 172 | ||
167 | chooseResourceName :: PresenceState | 173 | chooseResourceName :: PresenceState |
168 | -> ConnectionKey -> SockAddr -> t -> IO Text | 174 | -> ConnectionKey -> SockAddr -> Maybe Text -> Maybe Text -> IO Text |
169 | chooseResourceName state k addr desired = do | 175 | chooseResourceName state k addr clientsNameForMe desired = do |
170 | muid <- getLocalPeerCred' addr | 176 | muid <- getLocalPeerCred' addr |
171 | (mtty,pid) <- getTTYandPID muid | 177 | (mtty,pid) <- getTTYandPID muid |
172 | user <- getJabberUserForId muid | 178 | user <- getJabberUserForId muid |
173 | status <- atomically $ newTVar Nothing | 179 | status <- atomically $ newTVar Nothing |
174 | flgs <- atomically $ newTVar 0 | 180 | flgs <- atomically $ newTVar 0 |
181 | profile <- fmap (fromMaybe ".") $ forM clientsNameForMe $ \wanted_profile -> do | ||
182 | -- TODO: allow user to select profile | ||
183 | return "." | ||
175 | let client = ClientState { clientResource = maybe "fallback" id mtty | 184 | let client = ClientState { clientResource = maybe "fallback" id mtty |
176 | , clientUser = user | 185 | , clientUser = user |
177 | , clientPid = pid | 186 | , clientProfile = profile |
178 | , clientStatus = status | 187 | , clientPid = pid |
179 | , clientFlags = flgs } | 188 | , clientStatus = status |
189 | , clientFlags = flgs } | ||
180 | 190 | ||
181 | do -- forward-lookup of the buddies so that it is cached for reversing. | 191 | do -- forward-lookup of the buddies so that it is cached for reversing. |
182 | buds <- configText ConfigFiles.getBuddies (clientUser client) | 192 | buds <- configText ConfigFiles.getBuddies (clientUser client) (clientProfile client) |
183 | forM_ buds $ \bud -> do | 193 | forM_ buds $ \bud -> do |
184 | let (_,h,_) = splitJID bud | 194 | let (_,h,_) = splitJID bud |
185 | forkIO $ void $ resolvePeer h | 195 | forkIO $ void $ resolvePeer h |
@@ -191,7 +201,7 @@ chooseResourceName state k addr desired = do | |||
191 | (pcInsertNetworkClient k client) | 201 | (pcInsertNetworkClient k client) |
192 | mb | 202 | mb |
193 | 203 | ||
194 | localJID (clientUser client) (clientResource client) | 204 | localJID (clientUser client) (clientProfile client) (clientResource client) |
195 | 205 | ||
196 | where | 206 | where |
197 | getTTYandPID muid = do | 207 | getTTYandPID muid = do |
@@ -226,8 +236,8 @@ forClient state k fallback f = do | |||
226 | tellClientHisName :: PresenceState -> ConnectionKey -> IO Text | 236 | tellClientHisName :: PresenceState -> ConnectionKey -> IO Text |
227 | tellClientHisName state k = forClient state k fallback go | 237 | tellClientHisName state k = forClient state k fallback go |
228 | where | 238 | where |
229 | fallback = localJID "nobody" "fallback" | 239 | fallback = localJID "nobody" "." "fallback" |
230 | go client = localJID (clientUser client) (clientResource client) | 240 | go client = localJID (clientUser client) (clientProfile client) (clientResource client) |
231 | 241 | ||
232 | toMapUnit :: Ord k => [k] -> Map k () | 242 | toMapUnit :: Ord k => [k] -> Map k () |
233 | toMapUnit xs = Map.fromList $ map (,()) xs | 243 | toMapUnit xs = Map.fromList $ map (,()) xs |
@@ -237,11 +247,11 @@ resolveAllPeers hosts = fmap (toMapUnit . concat) $ Prelude.mapM (fmap (take 1) | |||
237 | 247 | ||
238 | 248 | ||
239 | rosterGetStuff | 249 | rosterGetStuff |
240 | :: (L.ByteString -> IO [L.ByteString]) | 250 | :: (ConfigFiles.User -> ConfigFiles.Profile -> IO [L.ByteString]) |
241 | -> PresenceState -> ConnectionKey -> IO [Text] | 251 | -> PresenceState -> ConnectionKey -> IO [Text] |
242 | rosterGetStuff what state k = forClient state k (return []) | 252 | rosterGetStuff what state k = forClient state k (return []) |
243 | $ \client -> do | 253 | $ \client -> do |
244 | jids <- configText what (clientUser client) | 254 | jids <- configText what (clientUser client) (clientProfile client) |
245 | let hosts = map ((\(_,h,_)->h) . splitJID) jids | 255 | let hosts = map ((\(_,h,_)->h) . splitJID) jids |
246 | case state of | 256 | case state of |
247 | PresenceState { server = svVar } -> do | 257 | PresenceState { server = svVar } -> do |
@@ -267,13 +277,16 @@ data Conn = Conn { connChan :: TChan Stanza | |||
267 | , auxAddr :: SockAddr } | 277 | , auxAddr :: SockAddr } |
268 | 278 | ||
269 | configText :: Functor f => | 279 | configText :: Functor f => |
270 | (L.ByteString -> f [L.ByteString]) -> Text -> f [Text] | 280 | (ConfigFiles.User -> ConfigFiles.Profile -> f [L.ByteString]) |
271 | configText what u = fmap (map lazyByteStringToText) | 281 | -> Text -- user |
272 | $ what (textToLazyByteString u) | 282 | -> Text -- profile |
273 | 283 | -> f [Text] -- items | |
274 | getBuddies' :: Text -> IO [Text] | 284 | configText what u p = fmap (map lazyByteStringToText) |
285 | $ what (textToLazyByteString u) (Text.unpack p) | ||
286 | |||
287 | getBuddies' :: Text -> Text -> IO [Text] | ||
275 | getBuddies' = configText ConfigFiles.getBuddies | 288 | getBuddies' = configText ConfigFiles.getBuddies |
276 | getSolicited' :: Text -> IO [Text] | 289 | getSolicited' :: Text -> Text -> IO [Text] |
277 | getSolicited' = configText ConfigFiles.getSolicited | 290 | getSolicited' = configText ConfigFiles.getSolicited |
278 | 291 | ||
279 | sendProbesAndSolicitations :: PresenceState | 292 | sendProbesAndSolicitations :: PresenceState |
@@ -282,10 +295,11 @@ sendProbesAndSolicitations state k laddr chan = do | |||
282 | -- get all buddies & solicited matching k for all users | 295 | -- get all buddies & solicited matching k for all users |
283 | xs <- runTraversableT $ do | 296 | xs <- runTraversableT $ do |
284 | cbu <- lift $ atomically $ readTVar $ clientsByUser state | 297 | cbu <- lift $ atomically $ readTVar $ clientsByUser state |
285 | user <- liftT $ Map.keys cbu | 298 | (user,LocalPresence cmap) <- liftT $ Map.toList cbu |
299 | profile <- liftT $ nub $ map clientProfile $ Map.elems cmap | ||
286 | (isbud,getter) <- liftT [(True ,getBuddies' ) | 300 | (isbud,getter) <- liftT [(True ,getBuddies' ) |
287 | ,(False,getSolicited')] | 301 | ,(False,getSolicited')] |
288 | bud <- liftMT $ getter user | 302 | bud <- liftMT $ getter user profile |
289 | let (u,h,r) = splitJID bud | 303 | let (u,h,r) = splitJID bud |
290 | addr <- liftMT $ nub `fmap` resolvePeer h | 304 | addr <- liftMT $ nub `fmap` resolvePeer h |
291 | liftT $ guard (PeerKey addr == k) | 305 | liftT $ guard (PeerKey addr == k) |
@@ -294,10 +308,10 @@ sendProbesAndSolicitations state k laddr chan = do | |||
294 | -- is a bad idea. Perhaps due to laziness and an | 308 | -- is a bad idea. Perhaps due to laziness and an |
295 | -- unforced list? Instead, we will return a list | 309 | -- unforced list? Instead, we will return a list |
296 | -- of (Bool,Text) for processing outside. | 310 | -- of (Bool,Text) for processing outside. |
297 | return (isbud,u,if isbud then "" else user) | 311 | return (isbud,u,user,profile) |
298 | -- XXX: The following O(n²) nub may be a little | 312 | -- XXX: The following O(n²) nub may be a little |
299 | -- too onerous. | 313 | -- too onerous. |
300 | forM_ (nub xs) $ \(isbud,u,user) -> do | 314 | forM_ (nub xs) $ \(isbud,u,user,profile) -> do |
301 | let make = if isbud then presenceProbe | 315 | let make = if isbud then presenceProbe |
302 | else presenceSolicitation | 316 | else presenceSolicitation |
303 | toh = peerKeyToText k | 317 | toh = peerKeyToText k |
@@ -378,13 +392,17 @@ rewriteJIDForClient laddr jid buds = do | |||
378 | else peerKeyToResolvedName buds (PeerKey addr) | 392 | else peerKeyToResolvedName buds (PeerKey addr) |
379 | return (mine,(n,h',r)) | 393 | return (mine,(n,h',r)) |
380 | 394 | ||
395 | -- This attempts to reverse resolve a peers address to give the human-friendly | ||
396 | -- domain name as it appears in the roster. It prefers host names that occur | ||
397 | -- in the given list of JIDs, but will fall back to any reverse-resolved name | ||
398 | -- and if it was unable to reverse the address, it will yield an ip address. | ||
381 | peerKeyToResolvedName :: [Text] -> ConnectionKey -> IO Text | 399 | peerKeyToResolvedName :: [Text] -> ConnectionKey -> IO Text |
382 | peerKeyToResolvedName buds k@(ClientKey { localAddress=addr }) = return "ErrorClIeNt1" | 400 | peerKeyToResolvedName buds k@(ClientKey { localAddress=addr }) = return "ErrorClIeNt1" |
383 | peerKeyToResolvedName buds pk = do | 401 | peerKeyToResolvedName buds pk = do |
384 | ns <- peerKeyToResolvedNames pk | 402 | ns <- peerKeyToResolvedNames pk |
385 | let hs = map (\jid -> let (_,h,_)=splitJID jid in h) buds | 403 | let hs = map (\jid -> let (_,h,_)=splitJID jid in h) buds |
386 | ns' = sortBy (comparing $ not . flip elem hs) ns | 404 | ns' = sortBy (comparing $ not . flip elem hs) ns |
387 | return $ maybe (peerKeyToText pk) id (listToMaybe ns') | 405 | return $ fromMaybe (peerKeyToText pk) (listToMaybe ns') |
388 | 406 | ||
389 | 407 | ||
390 | multiplyJIDForClient :: SockAddr -> Text -> IO (Bool,[(Maybe Text,Text,Maybe Text)]) | 408 | multiplyJIDForClient :: SockAddr -> Text -> IO (Bool,[(Maybe Text,Text,Maybe Text)]) |
@@ -468,33 +486,46 @@ deliverMessage state fail msg = | |||
468 | if not mine then fail else do | 486 | if not mine then fail else do |
469 | let to' = unsplitJID (n,h,r) | 487 | let to' = unsplitJID (n,h,r) |
470 | cmap <- atomically . readTVar $ clientsByUser state | 488 | cmap <- atomically . readTVar $ clientsByUser state |
471 | (from',chans,ks) <- do | 489 | chans <- fmap (fromMaybe []) $ do |
472 | flip (maybe $ return (Nothing,[],[])) n $ \n -> do | 490 | forM (n >>= flip Map.lookup cmap) $ \presence_container -> do |
473 | buds <- configText ConfigFiles.getBuddies n | 491 | let ks = Map.keys (networkClients presence_container) |
492 | chans = do | ||
493 | (k,client) <- Map.toList $ networkClients presence_container | ||
494 | chan <- maybeToList $ Map.lookup k key_to_chan | ||
495 | return (clientProfile client, chan) | ||
496 | forM chans $ \(profile,chan) -> do | ||
497 | buds <- configText ConfigFiles.getBuddies (fromJust n) profile | ||
474 | from' <- do | 498 | from' <- do |
475 | flip (maybe $ return Nothing) (stanzaFrom msg) $ \from -> do | 499 | flip (maybe $ return Nothing) (stanzaFrom msg) $ \from -> do |
476 | (_,trip) <- rewriteJIDForClient laddr from buds | 500 | (_,trip) <- rewriteJIDForClient laddr from buds |
477 | return . Just $ unsplitJID trip | 501 | return . Just $ unsplitJID trip |
478 | let nope = return (from',[],[]) | 502 | return (from',chan) |
479 | flip (maybe nope) (Map.lookup n cmap) $ \presence_container -> do | ||
480 | let ks = Map.keys (networkClients presence_container) | ||
481 | chans = mapMaybe (flip Map.lookup key_to_chan) ks | ||
482 | return (from',chans,ks) | ||
483 | putStrLn $ "chan count: " ++ show (length chans) | 503 | putStrLn $ "chan count: " ++ show (length chans) |
484 | let msg' = msg { stanzaTo=Just to' | 504 | if null chans then do |
485 | , stanzaFrom=from' } | 505 | forM_ (stanzaFrom msg) $ \from -> do |
486 | if null chans then deliverToConsole state fail msg' else do | 506 | from' <- do |
487 | forM_ chans $ \Conn { connChan=chan} -> do | 507 | -- Fallback to "." profile when no clients. |
488 | putStrLn $ "sending "++show (stanzaId msg)++" to clients "++show ks | 508 | buds <- maybe (return []) |
489 | -- TODO: Cloning isn't really neccessary unless there are multiple | 509 | (\n -> configText ConfigFiles.getBuddies n ".") |
490 | -- destinations and we should probably transition to minimal cloning, | 510 | n |
491 | -- or else we should distinguish between announcable stanzas and | 511 | (_,trip) <- rewriteJIDForClient laddr from buds |
492 | -- consumable stanzas and announcables use write-only broadcast | 512 | return . Just $ unsplitJID trip |
493 | -- channels that must be cloned in order to be consumed. | 513 | let msg' = msg { stanzaTo=Just to' |
494 | -- For now, we are doing redundant cloning. | 514 | , stanzaFrom=from' } |
495 | dup <- cloneStanza msg' | 515 | deliverToConsole state fail msg' |
496 | sendModifiedStanzaToClient dup | 516 | else do |
497 | chan | 517 | forM_ chans $ \(from',Conn { connChan=chan}) -> do |
518 | -- TODO: Cloning isn't really neccessary unless there are multiple | ||
519 | -- destinations and we should probably transition to minimal cloning, | ||
520 | -- or else we should distinguish between announcable stanzas and | ||
521 | -- consumable stanzas and announcables use write-only broadcast | ||
522 | -- channels that must be cloned in order to be consumed. | ||
523 | -- For now, we are doing redundant cloning. | ||
524 | let msg' = msg { stanzaTo=Just to' | ||
525 | , stanzaFrom=from' } | ||
526 | dup <- cloneStanza msg' | ||
527 | sendModifiedStanzaToClient dup | ||
528 | chan | ||
498 | 529 | ||
499 | 530 | ||
500 | setClientFlag :: PresenceState -> ConnectionKey -> Int8 -> IO () | 531 | setClientFlag :: PresenceState -> ConnectionKey -> Int8 -> IO () |
@@ -513,9 +544,9 @@ informSentRoster state k = do | |||
513 | setClientFlag state k cf_interested | 544 | setClientFlag state k cf_interested |
514 | 545 | ||
515 | 546 | ||
516 | subscribedPeers :: Text -> IO [SockAddr] | 547 | subscribedPeers :: Text -> Text -> IO [SockAddr] |
517 | subscribedPeers user = do | 548 | subscribedPeers user profile = do |
518 | jids <- configText ConfigFiles.getSubscribers user | 549 | jids <- configText ConfigFiles.getSubscribers user profile |
519 | let hosts = map ((\(_,h,_)->h) . splitJID) jids | 550 | let hosts = map ((\(_,h,_)->h) . splitJID) jids |
520 | fmap Map.keys $ resolveAllPeers hosts | 551 | fmap Map.keys $ resolveAllPeers hosts |
521 | 552 | ||
@@ -546,7 +577,7 @@ informClientPresence0 state mbk client stanza = do | |||
546 | when (not is_avail) $ do | 577 | when (not is_avail) $ do |
547 | atomically $ setClientFlag0 client cf_available | 578 | atomically $ setClientFlag0 client cf_available |
548 | maybe (return ()) (sendCachedPresence state) mbk | 579 | maybe (return ()) (sendCachedPresence state) mbk |
549 | addrs <- subscribedPeers (clientUser client) | 580 | addrs <- subscribedPeers (clientUser client) (clientProfile client) |
550 | ktc <- atomically $ readTVar (keyToChan state) | 581 | ktc <- atomically $ readTVar (keyToChan state) |
551 | let connected = mapMaybe (flip Map.lookup ktc . PeerKey) addrs | 582 | let connected = mapMaybe (flip Map.lookup ktc . PeerKey) addrs |
552 | forM_ connected $ \con -> do | 583 | forM_ connected $ \con -> do |
@@ -649,7 +680,7 @@ answerProbe state mto k chan = do | |||
649 | 680 | ||
650 | flip (maybe $ return ()) muser $ \(u,conn,ch) -> do | 681 | flip (maybe $ return ()) muser $ \(u,conn,ch) -> do |
651 | 682 | ||
652 | resolved_subs <- resolvedFromRoster ConfigFiles.getSubscribers u | 683 | resolved_subs <- resolvedFromRoster ConfigFiles.getSubscribers u (_todo {- profile -}) |
653 | let gaddrs = groupBy (\a b -> snd a == snd b) (sort resolved_subs) | 684 | let gaddrs = groupBy (\a b -> snd a == snd b) (sort resolved_subs) |
654 | whitelist = do | 685 | whitelist = do |
655 | xs <- gaddrs | 686 | xs <- gaddrs |
@@ -693,7 +724,7 @@ sendCachedPresence :: PresenceState -> ConnectionKey -> IO () | |||
693 | sendCachedPresence state k = do | 724 | sendCachedPresence state k = do |
694 | forClient state k (return ()) $ \client -> do | 725 | forClient state k (return ()) $ \client -> do |
695 | rbp <- atomically $ readTVar (remotesByPeer state) | 726 | rbp <- atomically $ readTVar (remotesByPeer state) |
696 | jids <- configText ConfigFiles.getBuddies (clientUser client) | 727 | jids <- configText ConfigFiles.getBuddies (clientUser client) (clientProfile client) |
697 | let hosts = map ((\(_,h,_)->h) . splitJID) jids | 728 | let hosts = map ((\(_,h,_)->h) . splitJID) jids |
698 | addrs <- resolveAllPeers hosts | 729 | addrs <- resolveAllPeers hosts |
699 | let onlines = rbp `Map.intersection` Map.mapKeys PeerKey addrs | 730 | let onlines = rbp `Map.intersection` Map.mapKeys PeerKey addrs |
@@ -714,7 +745,7 @@ sendCachedPresence state k = do | |||
714 | sendModifiedStanzaToClient (dup { stanzaFrom=Just from' }) | 745 | sendModifiedStanzaToClient (dup { stanzaFrom=Just from' }) |
715 | (connChan con) | 746 | (connChan con) |
716 | 747 | ||
717 | pending <- configText ConfigFiles.getPending (clientUser client) | 748 | pending <- configText ConfigFiles.getPending (clientUser client) (clientProfile client) |
718 | hostname <- textHostName | 749 | hostname <- textHostName |
719 | forM_ pending $ \pending_jid -> do | 750 | forM_ pending $ \pending_jid -> do |
720 | let cjid = unsplitJID ( Just $ clientUser client | 751 | let cjid = unsplitJID ( Just $ clientUser client |
@@ -728,27 +759,39 @@ sendCachedPresence state k = do | |||
728 | return () | 759 | return () |
729 | 760 | ||
730 | addToRosterFile :: (MonadPlus t, Traversable t) => | 761 | addToRosterFile :: (MonadPlus t, Traversable t) => |
731 | (L.ByteString -> (L.ByteString -> IO (t L.ByteString)) | 762 | (ConfigFiles.User |
763 | -> ConfigFiles.Profile | ||
764 | -> (L.ByteString -> IO (t L.ByteString)) | ||
732 | -> Maybe L.ByteString | 765 | -> Maybe L.ByteString |
733 | -> t1) | 766 | -> t1) |
734 | -> Text -> Text -> [SockAddr] -> t1 | 767 | -> Text -- user |
735 | addToRosterFile doit whose to addrs = | 768 | -> Text -- profile |
736 | modifyRosterFile doit whose to addrs True | 769 | -> Text -> [SockAddr] -> t1 |
770 | addToRosterFile doit whose profile to addrs = | ||
771 | modifyRosterFile doit whose profile to addrs True | ||
737 | 772 | ||
738 | removeFromRosterFile :: (MonadPlus t, Traversable t) => | 773 | removeFromRosterFile :: (MonadPlus t, Traversable t) => |
739 | (L.ByteString -> (L.ByteString -> IO (t L.ByteString)) | 774 | (ConfigFiles.User |
775 | -> ConfigFiles.Profile | ||
776 | -> (L.ByteString -> IO (t L.ByteString)) | ||
740 | -> Maybe L.ByteString | 777 | -> Maybe L.ByteString |
741 | -> t1) | 778 | -> t1) |
742 | -> Text -> Text -> [SockAddr] -> t1 | 779 | -> Text -- user |
743 | removeFromRosterFile doit whose to addrs = | 780 | -> Text -- profile |
744 | modifyRosterFile doit whose to addrs False | 781 | -> Text -> [SockAddr] -> t1 |
782 | removeFromRosterFile doit whose profile to addrs = | ||
783 | modifyRosterFile doit whose profile to addrs False | ||
745 | 784 | ||
746 | modifyRosterFile :: (Traversable t, MonadPlus t) => | 785 | modifyRosterFile :: (Traversable t, MonadPlus t) => |
747 | (L.ByteString -> (L.ByteString -> IO (t L.ByteString)) | 786 | (ConfigFiles.User |
787 | -> ConfigFiles.Profile | ||
788 | -> (L.ByteString -> IO (t L.ByteString)) | ||
748 | -> Maybe L.ByteString | 789 | -> Maybe L.ByteString |
749 | -> t1) | 790 | -> t1) |
750 | -> Text -> Text -> [SockAddr] -> Bool -> t1 | 791 | -> Text -- user |
751 | modifyRosterFile doit whose to addrs bAdd = do | 792 | -> Text -- profile |
793 | -> Text -> [SockAddr] -> Bool -> t1 | ||
794 | modifyRosterFile doit whose profile to addrs bAdd = do | ||
752 | let (mu,_,_) = splitJID to | 795 | let (mu,_,_) = splitJID to |
753 | cmp jid = runTraversableT $ do | 796 | cmp jid = runTraversableT $ do |
754 | let (msu,stored_h,mr) = splitJID (lazyByteStringToText jid) | 797 | let (msu,stored_h,mr) = splitJID (lazyByteStringToText jid) |
@@ -767,7 +810,7 @@ modifyRosterFile doit whose to addrs bAdd = do | |||
767 | if null (stored_addrs \\ addrs) then mzero else do | 810 | if null (stored_addrs \\ addrs) then mzero else do |
768 | -- keep | 811 | -- keep |
769 | return jid | 812 | return jid |
770 | doit (textToLazyByteString whose) | 813 | doit (textToLazyByteString whose) (Text.unpack profile) |
771 | cmp | 814 | cmp |
772 | (guard bAdd >> Just (textToLazyByteString to)) | 815 | (guard bAdd >> Just (textToLazyByteString to)) |
773 | 816 | ||
@@ -781,9 +824,9 @@ clientSubscriptionRequest state fail k stanza chan = do | |||
781 | flip (maybe fail) mu $ \u -> do | 824 | flip (maybe fail) mu $ \u -> do |
782 | -- add to-address to from's solicited | 825 | -- add to-address to from's solicited |
783 | addrs <- resolvePeer h | 826 | addrs <- resolvePeer h |
784 | addToRosterFile ConfigFiles.modifySolicited (clientUser client) to addrs | 827 | addToRosterFile ConfigFiles.modifySolicited (clientUser client) (clientProfile client) to addrs |
785 | removeFromRosterFile ConfigFiles.modifyBuddies (clientUser client) to addrs | 828 | removeFromRosterFile ConfigFiles.modifyBuddies (clientUser client) (clientProfile client) to addrs |
786 | resolved_subs <- resolvedFromRoster ConfigFiles.getSubscribers (clientUser client) | 829 | resolved_subs <- resolvedFromRoster ConfigFiles.getSubscribers (clientUser client) (clientProfile client) |
787 | let is_subscribed = not . null $ intersect (map ((mu,).PeerKey) addrs) resolved_subs | 830 | let is_subscribed = not . null $ intersect (map ((mu,).PeerKey) addrs) resolved_subs |
788 | -- subscribers: "from" | 831 | -- subscribers: "from" |
789 | -- buddies: "to" | 832 | -- buddies: "to" |
@@ -831,10 +874,10 @@ clientSubscriptionRequest state fail k stanza chan = do | |||
831 | 874 | ||
832 | 875 | ||
833 | resolvedFromRoster | 876 | resolvedFromRoster |
834 | :: (L.ByteString -> IO [L.ByteString]) | 877 | :: (ConfigFiles.User -> ConfigFiles.Profile -> IO [L.ByteString]) |
835 | -> UserName -> IO [(Maybe UserName, ConnectionKey)] | 878 | -> UserName -> Text -> IO [(Maybe UserName, ConnectionKey)] |
836 | resolvedFromRoster doit u = do | 879 | resolvedFromRoster doit u profile = do |
837 | subs <- configText doit u | 880 | subs <- configText doit u profile |
838 | runTraversableT $ do | 881 | runTraversableT $ do |
839 | (mu,h,_) <- liftT $ splitJID `fmap` subs | 882 | (mu,h,_) <- liftT $ splitJID `fmap` subs |
840 | addr <- liftMT $ fmap nub $ resolvePeer h | 883 | addr <- liftMT $ fmap nub $ resolvePeer h |
@@ -870,7 +913,7 @@ peerSubscriptionRequest state fail k stanza chan = do | |||
870 | (_,fromtup) <- rewriteJIDForClient laddr from [] | 913 | (_,fromtup) <- rewriteJIDForClient laddr from [] |
871 | flip (maybe fail) mto_u $ \u -> do | 914 | flip (maybe fail) mto_u $ \u -> do |
872 | flip (maybe fail) mfrom_u $ \from_u -> do | 915 | flip (maybe fail) mfrom_u $ \from_u -> do |
873 | resolved_subs <- resolvedFromRoster ConfigFiles.getSubscribers u | 916 | resolved_subs <- resolvedFromRoster ConfigFiles.getSubscribers u (_todo {- profile -}) |
874 | let already_subscribed = elem (mfrom_u,k) resolved_subs | 917 | let already_subscribed = elem (mfrom_u,k) resolved_subs |
875 | is_wanted = case stanzaType stanza of | 918 | is_wanted = case stanzaType stanza of |
876 | PresenceRequestSubscription b -> b | 919 | PresenceRequestSubscription b -> b |
@@ -900,9 +943,9 @@ peerSubscriptionRequest state fail k stanza chan = do | |||
900 | 943 | ||
901 | already_pending <- | 944 | already_pending <- |
902 | if is_wanted then | 945 | if is_wanted then |
903 | addToRosterFile ConfigFiles.modifyPending u from' addrs | 946 | addToRosterFile ConfigFiles.modifyPending u (_todo {- profile -}) from' addrs |
904 | else do | 947 | else do |
905 | removeFromRosterFile ConfigFiles.modifySubscribers u from' addrs | 948 | removeFromRosterFile ConfigFiles.modifySubscribers u (_todo {- profile -}) from' addrs |
906 | reply <- makeInformSubscription "jabber:server" to from is_wanted | 949 | reply <- makeInformSubscription "jabber:server" to from is_wanted |
907 | sendModifiedStanzaToPeer reply chan | 950 | sendModifiedStanzaToPeer reply chan |
908 | return False | 951 | return False |
@@ -933,9 +976,9 @@ clientInformSubscription state fail k stanza = do | |||
933 | let (mu,h,mr) = splitJID to | 976 | let (mu,h,mr) = splitJID to |
934 | addrs <- resolvePeer h | 977 | addrs <- resolvePeer h |
935 | -- remove from pending | 978 | -- remove from pending |
936 | buds <- resolvedFromRoster ConfigFiles.getBuddies (clientUser client) | 979 | buds <- resolvedFromRoster ConfigFiles.getBuddies (clientUser client) (clientProfile client) |
937 | let is_buddy = not . null $ map ((mu,) . PeerKey) addrs `intersect` buds | 980 | let is_buddy = not . null $ map ((mu,) . PeerKey) addrs `intersect` buds |
938 | removeFromRosterFile ConfigFiles.modifyPending (clientUser client) to addrs | 981 | removeFromRosterFile ConfigFiles.modifyPending (clientUser client) (clientProfile client) to addrs |
939 | let (relationship,addf,remf) = | 982 | let (relationship,addf,remf) = |
940 | case stanzaType stanza of | 983 | case stanzaType stanza of |
941 | PresenceInformSubscription True -> | 984 | PresenceInformSubscription True -> |
@@ -947,8 +990,8 @@ clientInformSubscription state fail k stanza = do | |||
947 | else "none" ) | 990 | else "none" ) |
948 | , ConfigFiles.modifyOthers | 991 | , ConfigFiles.modifyOthers |
949 | , ConfigFiles.modifySubscribers ) | 992 | , ConfigFiles.modifySubscribers ) |
950 | addToRosterFile addf (clientUser client) to addrs | 993 | addToRosterFile addf (clientUser client) (clientProfile client) to addrs |
951 | removeFromRosterFile remf (clientUser client) to addrs | 994 | removeFromRosterFile remf (clientUser client) (clientProfile client) to addrs |
952 | 995 | ||
953 | do | 996 | do |
954 | cbu <- atomically $ readTVar (clientsByUser state) | 997 | cbu <- atomically $ readTVar (clientsByUser state) |
@@ -1009,8 +1052,8 @@ peerInformSubscription state fail k stanza = do | |||
1009 | -- This would allow us to answer anonymous probes with 'unsubscribed'. | 1052 | -- This would allow us to answer anonymous probes with 'unsubscribed'. |
1010 | flip (maybe fail) muser $ \user -> do | 1053 | flip (maybe fail) muser $ \user -> do |
1011 | addrs <- resolvePeer from_h | 1054 | addrs <- resolvePeer from_h |
1012 | was_solicited <- removeFromRosterFile ConfigFiles.modifySolicited user from'' addrs | 1055 | was_solicited <- removeFromRosterFile ConfigFiles.modifySolicited user (_todo {- profile -}) from'' addrs |
1013 | subs <- resolvedFromRoster ConfigFiles.getSubscribers user | 1056 | subs <- resolvedFromRoster ConfigFiles.getSubscribers user (_todo {- profile -}) |
1014 | let is_sub = not . null $ map ((from_u,) . PeerKey) addrs `intersect` subs | 1057 | let is_sub = not . null $ map ((from_u,) . PeerKey) addrs `intersect` subs |
1015 | let (relationship,addf,remf) = | 1058 | let (relationship,addf,remf) = |
1016 | case stanzaType stanza of | 1059 | case stanzaType stanza of |
@@ -1023,8 +1066,8 @@ peerInformSubscription state fail k stanza = do | |||
1023 | else "none") | 1066 | else "none") |
1024 | , ConfigFiles.modifyOthers | 1067 | , ConfigFiles.modifyOthers |
1025 | , ConfigFiles.modifyBuddies ) | 1068 | , ConfigFiles.modifyBuddies ) |
1026 | addToRosterFile addf user from'' addrs | 1069 | addToRosterFile addf user (_todo {- profile -}) from'' addrs |
1027 | removeFromRosterFile remf user from'' addrs | 1070 | removeFromRosterFile remf user (_todo {- profile -}) from'' addrs |
1028 | 1071 | ||
1029 | hostname <- textHostName | 1072 | hostname <- textHostName |
1030 | let to' = unsplitJID (Just user, hostname, Nothing) | 1073 | let to' = unsplitJID (Just user, hostname, Nothing) |