diff options
author | joe <joe@jerkface.net> | 2018-06-24 02:27:18 -0400 |
---|---|---|
committer | joe <joe@jerkface.net> | 2018-06-24 03:10:43 -0400 |
commit | 55db1198b3da0c706f2b9f1ed9c8fd11fc4ae552 (patch) | |
tree | de035195ed188f8611da54e6e339d9124d2a5b3f /Presence/Presence.hs | |
parent | 3054de811f4ae7659dfc4dc338aab2c3d11b5c27 (diff) |
XMPP: Type-checking on various uses of SockAddr.
Diffstat (limited to 'Presence/Presence.hs')
-rw-r--r-- | Presence/Presence.hs | 389 |
1 files changed, 206 insertions, 183 deletions
diff --git a/Presence/Presence.hs b/Presence/Presence.hs index af6597b6..244bbead 100644 --- a/Presence/Presence.hs +++ b/Presence/Presence.hs | |||
@@ -53,11 +53,13 @@ import Network.Tox.NodeId (key2id) | |||
53 | import Crypto.Tox (decodeSecret) | 53 | import Crypto.Tox (decodeSecret) |
54 | import DPut | 54 | import DPut |
55 | 55 | ||
56 | isPeerKey :: ConnectionKey -> Bool | 56 | {- |
57 | isPeerKey :: ClientAddress -> Bool | ||
57 | isPeerKey k = case k of { PeerKey {} -> True ; _ -> False } | 58 | isPeerKey k = case k of { PeerKey {} -> True ; _ -> False } |
58 | 59 | ||
59 | isClientKey :: ConnectionKey -> Bool | 60 | isClientKey :: ClientAddress -> Bool |
60 | isClientKey k = case k of { ClientKey {} -> True ; _ -> False } | 61 | isClientKey k = case k of { ClientKey {} -> True ; _ -> False } |
62 | -} | ||
61 | 63 | ||
62 | localJID :: Text -> Text -> Text -> IO Text | 64 | localJID :: Text -> Text -> Text -> IO Text |
63 | localJID user "." resource = do | 65 | localJID user "." resource = do |
@@ -86,20 +88,21 @@ data ToxManager k = ToxManager | |||
86 | } | 88 | } |
87 | 89 | ||
88 | data PresenceState = forall status. PresenceState | 90 | data PresenceState = forall status. PresenceState |
89 | { clients :: TVar (Map ConnectionKey ClientState) | 91 | { clients :: TVar (Map ClientAddress ClientState) |
90 | , clientsByUser :: TVar (Map Text LocalPresence) | 92 | , clientsByUser :: TVar (Map Text LocalPresence) |
91 | , clientsByProfile :: TVar (Map Text LocalPresence) | 93 | , clientsByProfile :: TVar (Map Text LocalPresence) |
92 | , remotesByPeer :: TVar (Map ConnectionKey | 94 | , remotesByPeer :: TVar (Map PeerAddress |
93 | (Map UserName RemotePresence)) | 95 | (Map UserName RemotePresence)) |
94 | , server :: TMVar (XMPPServer, Connection.Manager status Text) | 96 | , server :: TMVar (XMPPServer, Connection.Manager status Text) |
95 | , keyToChan :: TVar (Map ConnectionKey Conn) | 97 | , ckeyToChan :: TVar (Map ClientAddress Conn) |
98 | , pkeyToChan :: TVar (Map PeerAddress Conn) | ||
96 | , consoleWriter :: Maybe ConsoleWriter | 99 | , consoleWriter :: Maybe ConsoleWriter |
97 | , toxManager :: Maybe (ToxManager ConnectionKey) | 100 | , toxManager :: Maybe (ToxManager ClientAddress) |
98 | } | 101 | } |
99 | 102 | ||
100 | 103 | ||
101 | newPresenceState :: Maybe ConsoleWriter | 104 | newPresenceState :: Maybe ConsoleWriter |
102 | -> Maybe (PresenceState -> ToxManager ConnectionKey) | 105 | -> Maybe (PresenceState -> ToxManager ClientAddress) |
103 | -> TMVar (XMPPServer, Connection.Manager status Text) | 106 | -> TMVar (XMPPServer, Connection.Manager status Text) |
104 | -> IO PresenceState | 107 | -> IO PresenceState |
105 | newPresenceState cw toxman xmpp = atomically $ do | 108 | newPresenceState cw toxman xmpp = atomically $ do |
@@ -107,13 +110,15 @@ newPresenceState cw toxman xmpp = atomically $ do | |||
107 | clientsByUser <- newTVar Map.empty | 110 | clientsByUser <- newTVar Map.empty |
108 | clientsByProfile <- newTVar Map.empty | 111 | clientsByProfile <- newTVar Map.empty |
109 | remotesByPeer <- newTVar Map.empty | 112 | remotesByPeer <- newTVar Map.empty |
110 | keyToChan <- newTVar Map.empty | 113 | ckeyToChan <- newTVar Map.empty |
114 | pkeyToChan <- newTVar Map.empty | ||
111 | let st = PresenceState | 115 | let st = PresenceState |
112 | { clients = clients | 116 | { clients = clients |
113 | , clientsByUser = clientsByUser | 117 | , clientsByUser = clientsByUser |
114 | , clientsByProfile = clientsByProfile | 118 | , clientsByProfile = clientsByProfile |
115 | , remotesByPeer = remotesByPeer | 119 | , remotesByPeer = remotesByPeer |
116 | , keyToChan = keyToChan | 120 | , ckeyToChan = ckeyToChan |
121 | , pkeyToChan = pkeyToChan | ||
117 | , server = xmpp | 122 | , server = xmpp |
118 | , consoleWriter = cw | 123 | , consoleWriter = cw |
119 | , toxManager = Nothing | 124 | , toxManager = Nothing |
@@ -121,7 +126,7 @@ newPresenceState cw toxman xmpp = atomically $ do | |||
121 | return $ st { toxManager = fmap ($ st) toxman } | 126 | return $ st { toxManager = fmap ($ st) toxman } |
122 | 127 | ||
123 | 128 | ||
124 | nameForClient :: PresenceState -> ConnectionKey -> IO Text | 129 | nameForClient :: PresenceState -> ClientAddress -> IO Text |
125 | nameForClient state k = do | 130 | nameForClient state k = do |
126 | mc <- atomically $ do | 131 | mc <- atomically $ do |
127 | cmap <- readTVar (clients state) | 132 | cmap <- readTVar (clients state) |
@@ -139,9 +144,8 @@ presenceHooks state verbosity mclient mpeer = XMPPServerParameters | |||
139 | { xmppChooseResourceName = chooseResourceName state | 144 | { xmppChooseResourceName = chooseResourceName state |
140 | , xmppTellClientHisName = tellClientHisName state | 145 | , xmppTellClientHisName = tellClientHisName state |
141 | , xmppTellMyNameToClient = nameForClient state | 146 | , xmppTellMyNameToClient = nameForClient state |
142 | , xmppTellMyNameToPeer = \addr -> return $ addrToText addr | 147 | , xmppTellMyNameToPeer = \(Local addr) -> return $ addrToText addr |
143 | , xmppTellPeerHisName = return . peerKeyToText | 148 | , xmppTellPeerHisName = return . peerKeyToText |
144 | , xmppTellClientNameOfPeer = flip peerKeyToResolvedName | ||
145 | , xmppNewConnection = newConn state | 149 | , xmppNewConnection = newConn state |
146 | , xmppEOF = eofConn state | 150 | , xmppEOF = eofConn state |
147 | , xmppRosterBuddies = rosterGetBuddies state | 151 | , xmppRosterBuddies = rosterGetBuddies state |
@@ -164,7 +168,7 @@ presenceHooks state verbosity mclient mpeer = XMPPServerParameters | |||
164 | 168 | ||
165 | 169 | ||
166 | data LocalPresence = LocalPresence | 170 | data LocalPresence = LocalPresence |
167 | { networkClients :: Map ConnectionKey ClientState | 171 | { networkClients :: Map ClientAddress ClientState |
168 | -- TODO: loginClients | 172 | -- TODO: loginClients |
169 | } | 173 | } |
170 | 174 | ||
@@ -177,18 +181,17 @@ data RemotePresence = RemotePresence | |||
177 | 181 | ||
178 | 182 | ||
179 | 183 | ||
180 | pcSingletonNetworkClient :: ConnectionKey | 184 | pcSingletonNetworkClient :: ClientAddress -> ClientState -> LocalPresence |
181 | -> ClientState -> LocalPresence | ||
182 | pcSingletonNetworkClient key client = | 185 | pcSingletonNetworkClient key client = |
183 | LocalPresence | 186 | LocalPresence |
184 | { networkClients = Map.singleton key client | 187 | { networkClients = Map.singleton key client |
185 | } | 188 | } |
186 | 189 | ||
187 | pcInsertNetworkClient :: ConnectionKey -> ClientState -> LocalPresence -> LocalPresence | 190 | pcInsertNetworkClient :: ClientAddress -> ClientState -> LocalPresence -> LocalPresence |
188 | pcInsertNetworkClient key client pc = | 191 | pcInsertNetworkClient key client pc = |
189 | pc { networkClients = Map.insert key client (networkClients pc) } | 192 | pc { networkClients = Map.insert key client (networkClients pc) } |
190 | 193 | ||
191 | pcRemoveNewtworkClient :: ConnectionKey | 194 | pcRemoveNewtworkClient :: ClientAddress |
192 | -> LocalPresence -> Maybe LocalPresence | 195 | -> LocalPresence -> Maybe LocalPresence |
193 | pcRemoveNewtworkClient key pc = if pcIsEmpty pc' then Nothing | 196 | pcRemoveNewtworkClient key pc = if pcIsEmpty pc' then Nothing |
194 | else Just pc' | 197 | else Just pc' |
@@ -215,8 +218,8 @@ identifyTTY' ttypids uid inode = ttypid | |||
215 | textify (tty,pid) = (fmap lazyByteStringToText tty, pid) | 218 | textify (tty,pid) = (fmap lazyByteStringToText tty, pid) |
216 | 219 | ||
217 | chooseResourceName :: PresenceState | 220 | chooseResourceName :: PresenceState |
218 | -> ConnectionKey -> SockAddr -> Maybe Text -> Maybe Text -> IO Text | 221 | -> ClientAddress -> Remote SockAddr -> Maybe Text -> Maybe Text -> IO Text |
219 | chooseResourceName state k addr clientsNameForMe desired = do | 222 | chooseResourceName state k (Remote addr) clientsNameForMe desired = do |
220 | muid <- getLocalPeerCred' addr | 223 | muid <- getLocalPeerCred' addr |
221 | (mtty,pid) <- getTTYandPID muid | 224 | (mtty,pid) <- getTTYandPID muid |
222 | user <- getJabberUserForId muid | 225 | user <- getJabberUserForId muid |
@@ -297,17 +300,17 @@ chooseResourceName state k addr clientsNameForMe desired = do | |||
297 | ) | 300 | ) |
298 | muid | 301 | muid |
299 | 302 | ||
300 | -- Perform action with 'ClientState' associated with the given 'ConnectionKey'. | 303 | -- Perform action with 'ClientState' associated with the given 'ClientAddress'. |
301 | -- If there is no associated 'ClientState', then perform the supplied fallback | 304 | -- If there is no associated 'ClientState', then perform the supplied fallback |
302 | -- action. | 305 | -- action. |
303 | forClient :: PresenceState -> ConnectionKey -> IO b -> (ClientState -> IO b) -> IO b | 306 | forClient :: PresenceState -> ClientAddress -> IO b -> (ClientState -> IO b) -> IO b |
304 | forClient state k fallback f = do | 307 | forClient state k fallback f = do |
305 | mclient <- atomically $ do | 308 | mclient <- atomically $ do |
306 | cs <- readTVar (clients state) | 309 | cs <- readTVar (clients state) |
307 | return $ Map.lookup k cs | 310 | return $ Map.lookup k cs |
308 | maybe fallback f mclient | 311 | maybe fallback f mclient |
309 | 312 | ||
310 | tellClientHisName :: PresenceState -> ConnectionKey -> IO Text | 313 | tellClientHisName :: PresenceState -> ClientAddress -> IO Text |
311 | tellClientHisName state k = forClient state k fallback go | 314 | tellClientHisName state k = forClient state k fallback go |
312 | where | 315 | where |
313 | fallback = localJID "nobody" "." "fallback" | 316 | fallback = localJID "nobody" "." "fallback" |
@@ -316,14 +319,14 @@ tellClientHisName state k = forClient state k fallback go | |||
316 | toMapUnit :: Ord k => [k] -> Map k () | 319 | toMapUnit :: Ord k => [k] -> Map k () |
317 | toMapUnit xs = Map.fromList $ map (,()) xs | 320 | toMapUnit xs = Map.fromList $ map (,()) xs |
318 | 321 | ||
319 | resolveAllPeers :: [Text] -> IO (Map SockAddr ()) | 322 | resolveAllPeers :: [Text] -> IO (Map PeerAddress ()) |
320 | resolveAllPeers hosts = fmap (toMapUnit . concat) $ Prelude.mapM (fmap (take 1) . resolvePeer) hosts | 323 | resolveAllPeers hosts = fmap (toMapUnit . concat) $ Prelude.mapM (fmap (take 1) . resolvePeer) hosts |
321 | 324 | ||
322 | 325 | ||
323 | -- Read a roster file and start trying to connect to all relevent peers. | 326 | -- Read a roster file and start trying to connect to all relevent peers. |
324 | rosterGetStuff | 327 | rosterGetStuff |
325 | :: (ConfigFiles.User -> ConfigFiles.Profile -> IO [L.ByteString]) | 328 | :: (ConfigFiles.User -> ConfigFiles.Profile -> IO [L.ByteString]) |
326 | -> PresenceState -> ConnectionKey -> IO [Text] | 329 | -> PresenceState -> ClientAddress -> IO [Text] |
327 | rosterGetStuff what state k = forClient state k (return []) | 330 | rosterGetStuff what state k = forClient state k (return []) |
328 | $ \client -> do | 331 | $ \client -> do |
329 | jids <- configText what (clientUser client) (clientProfile client) | 332 | jids <- configText what (clientUser client) (clientProfile client) |
@@ -335,7 +338,7 @@ rosterGetStuff what state k = forClient state k (return []) | |||
335 | -- Grok peers to associate with from the roster: | 338 | -- Grok peers to associate with from the roster: |
336 | forM_ hosts $ \host -> do | 339 | forM_ hosts $ \host -> do |
337 | -- We need either conns :: Connection.Manager TCPStatus Text | 340 | -- We need either conns :: Connection.Manager TCPStatus Text |
338 | -- or toxman :: ToxManager ConnectionKey | 341 | -- or toxman :: ToxManager ClientAddress |
339 | -- It is decided by checking hostnames for .tox ending. | 342 | -- It is decided by checking hostnames for .tox ending. |
340 | let policySetter = fromMaybe (Connection.setPolicy conns host) $ do | 343 | let policySetter = fromMaybe (Connection.setPolicy conns host) $ do |
341 | toxman <- toxManager state | 344 | toxman <- toxManager state |
@@ -346,17 +349,17 @@ rosterGetStuff what state k = forClient state k (return []) | |||
346 | atomically $ putTMVar svVar (sv,conns) | 349 | atomically $ putTMVar svVar (sv,conns) |
347 | return jids | 350 | return jids |
348 | 351 | ||
349 | rosterGetBuddies :: PresenceState -> ConnectionKey -> IO [Text] | 352 | rosterGetBuddies :: PresenceState -> ClientAddress -> IO [Text] |
350 | rosterGetBuddies state k = rosterGetStuff ConfigFiles.getBuddies state k | 353 | rosterGetBuddies state k = rosterGetStuff ConfigFiles.getBuddies state k |
351 | 354 | ||
352 | rosterGetSolicited :: PresenceState -> ConnectionKey -> IO [Text] | 355 | rosterGetSolicited :: PresenceState -> ClientAddress -> IO [Text] |
353 | rosterGetSolicited = rosterGetStuff ConfigFiles.getSolicited | 356 | rosterGetSolicited = rosterGetStuff ConfigFiles.getSolicited |
354 | 357 | ||
355 | -- XXX: Should we be connecting to these peers? | 358 | -- XXX: Should we be connecting to these peers? |
356 | rosterGetOthers :: PresenceState -> ConnectionKey -> IO [Text] | 359 | rosterGetOthers :: PresenceState -> ClientAddress -> IO [Text] |
357 | rosterGetOthers = rosterGetStuff ConfigFiles.getOthers | 360 | rosterGetOthers = rosterGetStuff ConfigFiles.getOthers |
358 | 361 | ||
359 | rosterGetSubscribers :: PresenceState -> ConnectionKey -> IO [Text] | 362 | rosterGetSubscribers :: PresenceState -> ClientAddress -> IO [Text] |
360 | rosterGetSubscribers = rosterGetStuff ConfigFiles.getSubscribers | 363 | rosterGetSubscribers = rosterGetStuff ConfigFiles.getSubscribers |
361 | 364 | ||
362 | data Conn = Conn { connChan :: TChan Stanza | 365 | data Conn = Conn { connChan :: TChan Stanza |
@@ -413,23 +416,20 @@ getBuddiesAndSolicited state pred | |||
413 | -- of (Bool,Text) for processing outside. | 416 | -- of (Bool,Text) for processing outside. |
414 | return (isbud,u,user,profile) | 417 | return (isbud,u,user,profile) |
415 | 418 | ||
416 | sendProbesAndSolicitations :: PresenceState | 419 | sendProbesAndSolicitations :: PresenceState -> PeerAddress -> Local SockAddr -> TChan Stanza -> IO () |
417 | -> ConnectionKey -> SockAddr -> TChan Stanza -> IO () | 420 | sendProbesAndSolicitations state k (Local laddr) chan = do |
418 | sendProbesAndSolicitations state k laddr chan = do | ||
419 | -- get all buddies & solicited matching k for all users | 421 | -- get all buddies & solicited matching k for all users |
420 | xs <- getBuddiesAndSolicited state $ \case | 422 | xs <- getBuddiesAndSolicited state $ \case |
421 | h | ".tox" `Text.isSuffixOf` h -> return False -- Tox probes/solicitations are handled in ToxToXMPP module. | 423 | h | ".tox" `Text.isSuffixOf` h -> return False -- Tox probes/solicitations are handled in ToxToXMPP module. |
422 | h -> do | 424 | h -> do |
423 | addrs <- nub `fmap` resolvePeer h | 425 | addrs <- nub `fmap` resolvePeer h |
424 | case k of | 426 | return $ k `elem` addrs -- Only for this peer /k/. |
425 | ClientKey _ -> return False -- Solicitations and probes are only for peers. | ||
426 | PeerKey a -> return $ a `elem` addrs -- Only for this peer /k/. | ||
427 | forM_ xs $ \(isbud,u,user,profile) -> do | 427 | forM_ xs $ \(isbud,u,user,profile) -> do |
428 | let make = if isbud then presenceProbe | 428 | let make = if isbud then presenceProbe |
429 | else presenceSolicitation | 429 | else presenceSolicitation |
430 | toh = peerKeyToText k | 430 | toh = peerKeyToText k |
431 | jid = unsplitJID (u,toh,Nothing) | 431 | jid = unsplitJID (u,toh,Nothing) |
432 | me = addrToText laddr | 432 | me = addrToText laddr -- xmppTellMyNameToPeer |
433 | from = if isbud then me -- probe from server | 433 | from = if isbud then me -- probe from server |
434 | else -- solicitation from particular user | 434 | else -- solicitation from particular user |
435 | unsplitJID (Just user,me,Nothing) | 435 | unsplitJID (Just user,me,Nothing) |
@@ -439,38 +439,35 @@ sendProbesAndSolicitations state k laddr chan = do | |||
439 | atomically $ writeTChan chan stanza | 439 | atomically $ writeTChan chan stanza |
440 | -- reverse xs `seq` return () | 440 | -- reverse xs `seq` return () |
441 | 441 | ||
442 | newConn :: PresenceState -> ConnectionKey -> ConnectionData -> TChan Stanza -> IO () | 442 | |
443 | newConn state k cdta outchan = do | 443 | newConn :: PresenceState -> SockAddr -> ConnectionData -> TChan Stanza -> IO () |
444 | atomically $ modifyTVar' (keyToChan state) | 444 | newConn state saddr cdta outchan = |
445 | $ Map.insert k Conn { connChan = outchan | 445 | case classifyConnection saddr cdta of |
446 | , auxData = cdta } | 446 | Left (pkey,laddr) -> do |
447 | when (isPeerKey k) | 447 | atomically $ modifyTVar' (pkeyToChan state) |
448 | $ sendProbesAndSolicitations state k (cdAddr cdta) outchan | 448 | $ Map.insert pkey Conn { connChan = outchan |
449 | , auxData = cdta } | ||
450 | sendProbesAndSolicitations state pkey laddr outchan | ||
451 | Right (ckey,_) -> do | ||
452 | atomically $ modifyTVar' (ckeyToChan state) | ||
453 | $ Map.insert ckey Conn { connChan = outchan | ||
454 | , auxData = cdta } | ||
449 | 455 | ||
450 | delclient :: (Alternative m, Monad m) => | 456 | delclient :: (Alternative m, Monad m) => |
451 | ConnectionKey -> m LocalPresence -> m LocalPresence | 457 | ClientAddress -> m LocalPresence -> m LocalPresence |
452 | delclient k mlp = do | 458 | delclient k mlp = do |
453 | lp <- mlp | 459 | lp <- mlp |
454 | let nc = Map.delete k $ networkClients lp | 460 | let nc = Map.delete k $ networkClients lp |
455 | guard $ not (Map.null nc) | 461 | guard $ not (Map.null nc) |
456 | return $ lp { networkClients = nc } | 462 | return $ lp { networkClients = nc } |
457 | 463 | ||
458 | eofConn :: PresenceState -> ConnectionKey -> IO () | 464 | eofConn :: PresenceState -> SockAddr -> ConnectionData -> IO () |
459 | eofConn state k = do | 465 | eofConn state saddr cdta = do |
460 | atomically $ modifyTVar' (keyToChan state) $ Map.delete k | 466 | atomically $ case classifyConnection saddr cdta of |
461 | case k of | 467 | Left (pkey,_) -> modifyTVar' (pkeyToChan state) $ Map.delete pkey |
462 | ClientKey {} -> do | 468 | Right (ckey,_) -> modifyTVar' (ckeyToChan state) $ Map.delete ckey |
463 | forClient state k (return ()) $ \client -> do | 469 | case classifyConnection saddr cdta of |
464 | forM_ (toxManager state) $ \toxman -> do | 470 | Left (k,_) -> do |
465 | case Text.splitAt 43 (clientProfile client) of | ||
466 | (pub,".tox") -> deactivateAccount toxman k (clientProfile client) | ||
467 | _ -> return () | ||
468 | stanza <- makePresenceStanza "jabber:server" Nothing Offline | ||
469 | informClientPresence state k stanza | ||
470 | atomically $ do | ||
471 | modifyTVar' (clientsByUser state) $ Map.alter (delclient k) (clientUser client) | ||
472 | modifyTVar' (clientsByProfile state) $ Map.alter (delclient k) (clientProfile client) | ||
473 | PeerKey {} -> do | ||
474 | let h = peerKeyToText k | 471 | let h = peerKeyToText k |
475 | jids <- atomically $ do | 472 | jids <- atomically $ do |
476 | rbp <- readTVar (remotesByPeer state) | 473 | rbp <- readTVar (remotesByPeer state) |
@@ -482,29 +479,26 @@ eofConn state k = do | |||
482 | forM_ jids $ \jid -> do | 479 | forM_ jids $ \jid -> do |
483 | stanza <- makePresenceStanza "jabber:client" (Just jid) Offline | 480 | stanza <- makePresenceStanza "jabber:client" (Just jid) Offline |
484 | informPeerPresence state k stanza | 481 | informPeerPresence state k stanza |
482 | Right (k,_) -> do | ||
483 | forClient state k (return ()) $ \client -> do | ||
484 | forM_ (toxManager state) $ \toxman -> do | ||
485 | case Text.splitAt 43 (clientProfile client) of | ||
486 | (pub,".tox") -> deactivateAccount toxman k (clientProfile client) | ||
487 | _ -> return () | ||
488 | stanza <- makePresenceStanza "jabber:server" Nothing Offline | ||
489 | informClientPresence state k stanza | ||
490 | atomically $ do | ||
491 | modifyTVar' (clientsByUser state) $ Map.alter (delclient k) (clientUser client) | ||
492 | modifyTVar' (clientsByProfile state) $ Map.alter (delclient k) (clientProfile client) | ||
485 | 493 | ||
486 | -- | The given address is taken to be the local address for the socket this JID | 494 | parseRemoteAddress :: Text -> IO (Maybe (Remote SockAddr)) |
487 | -- came in on. The returned JID parts are suitable for unsplitJID to create a | 495 | parseRemoteAddress s = fmap Remote <$> parseAddress s |
488 | -- valid JID for communicating to a client. The returned Bool is True when the | ||
489 | -- host part refers to this local host (i.e. it equals the given SockAddr). | ||
490 | -- If there are multiple results, it will prefer one which is a member of the | ||
491 | -- given list in the last argument. | ||
492 | rewriteJIDForClient :: SockAddr -> Text -> [Text] -> IO (Bool,(Maybe Text,Text,Maybe Text)) | ||
493 | rewriteJIDForClient laddr jid buds = do | ||
494 | let (n,h,r) = splitJID jid | ||
495 | maddr <- parseAddress (strip_brackets h) | ||
496 | fromMaybe (return (False,(n,ip6literal h,r))) $ maddr <&> \addr -> do | ||
497 | let mine = laddr `withPort` 0 == addr `withPort` 0 | ||
498 | h' <- if mine then textHostName | ||
499 | else peerKeyToResolvedName buds (PeerKey addr) | ||
500 | return (mine,(n,h',r)) | ||
501 | 496 | ||
502 | -- This attempts to reverse resolve a peers address to give the human-friendly | 497 | -- This attempts to reverse resolve a peers address to give the human-friendly |
503 | -- domain name as it appears in the roster. It prefers host names that occur | 498 | -- domain name as it appears in the roster. It prefers host names that occur |
504 | -- in the given list of JIDs, but will fall back to any reverse-resolved name | 499 | -- in the given list of JIDs, but will fall back to any reverse-resolved name |
505 | -- and if it was unable to reverse the address, it will yield an ip address. | 500 | -- and if it was unable to reverse the address, it will yield an ip address. |
506 | peerKeyToResolvedName :: [Text] -> ConnectionKey -> IO Text | 501 | peerKeyToResolvedName :: [Text] -> PeerAddress -> IO Text |
507 | peerKeyToResolvedName buds k@(ClientKey { localAddress=addr }) = return "ErrorClIeNt1" | ||
508 | peerKeyToResolvedName buds pk = do | 502 | peerKeyToResolvedName buds pk = do |
509 | ns <- peerKeyToResolvedNames pk | 503 | ns <- peerKeyToResolvedNames pk |
510 | let hs = map (\jid -> let (_,h,_)=splitJID jid in h) buds | 504 | let hs = map (\jid -> let (_,h,_)=splitJID jid in h) buds |
@@ -512,27 +506,39 @@ peerKeyToResolvedName buds pk = do | |||
512 | return $ fromMaybe (peerKeyToText pk) (listToMaybe ns') | 506 | return $ fromMaybe (peerKeyToText pk) (listToMaybe ns') |
513 | 507 | ||
514 | 508 | ||
509 | -- | The given address is taken to be the local address for the socket this JID | ||
510 | -- came in on. The returned JID parts are suitable for unsplitJID to create a | ||
511 | -- valid JID for communicating to a client. The returned Bool is True when the | ||
512 | -- host part refers to this local host (i.e. it equals the given SockAddr). | ||
513 | -- If there are multiple results, it will prefer one which is a member of the | ||
514 | -- given list in the last argument. | ||
515 | rewriteJIDForClient :: Local SockAddr -> Text -> [Text] -> IO (Bool,(Maybe Text,Text,Maybe Text)) | ||
516 | rewriteJIDForClient (Local laddr) jid buds = do | ||
517 | let (n,h,r) = splitJID jid | ||
518 | maddr <- parseAddress (strip_brackets h) | ||
519 | fromMaybe (return (False,(n,ip6literal h,r))) $ maddr <&> \saddr -> do | ||
520 | let mine = sameAddress laddr saddr | ||
521 | h' <- if mine then textHostName | ||
522 | else peerKeyToResolvedName buds (addrToPeerKey $ Remote saddr) | ||
523 | return (mine,(n,h',r)) | ||
524 | |||
515 | -- Given a local address and an IP-address JID, we return True if the JID is | 525 | -- Given a local address and an IP-address JID, we return True if the JID is |
516 | -- local, False otherwise. Additionally, a list of equivalent hostname JIDS | 526 | -- local, False otherwise. Additionally, a list of equivalent hostname JIDS |
517 | -- are returned. | 527 | -- are returned. |
518 | multiplyJIDForClient :: SockAddr -> Text -> IO (Bool,[(Maybe Text,Text,Maybe Text)]) | 528 | multiplyJIDForClient :: ClientAddress -> Text -> IO (Bool,[(Maybe Text,Text,Maybe Text)]) |
519 | multiplyJIDForClient laddr jid = do | 529 | multiplyJIDForClient k jid = do |
520 | let (n,h,r) = splitJID jid | 530 | let (n,h,r) = splitJID jid |
521 | maddr <- parseAddress (strip_brackets h) | 531 | maddr <- parseAddress (strip_brackets h) |
522 | fromMaybe (return (False,[(n,ip6literal h,r)])) $ maddr <&> \addr -> do | 532 | fromMaybe (return (False,[(n,ip6literal h,r)])) $ maddr <&> \saddr -> do |
523 | let mine = sameAddress laddr addr | 533 | let Local laddr = addrFromClientKey k |
534 | mine = sameAddress laddr saddr | ||
524 | names <- if mine then fmap (:[]) textHostName | 535 | names <- if mine then fmap (:[]) textHostName |
525 | else peerKeyToResolvedNames (PeerKey addr) | 536 | else peerKeyToResolvedNames (addrToPeerKey $ Remote saddr) |
526 | return (mine,map (\h' -> (n,h',r)) names) | 537 | return (mine,map (\h' -> (n,h',r)) names) |
527 | 538 | ||
528 | 539 | ||
529 | addrTextToKey :: Text -> IO (Maybe ConnectionKey) | 540 | guardPortStrippedAddress :: Text -> Local SockAddr -> IO (Maybe ()) |
530 | addrTextToKey h = do | 541 | guardPortStrippedAddress h (Local laddr) = do |
531 | maddr <- parseAddress (strip_brackets h) | ||
532 | return (fmap PeerKey maddr) | ||
533 | |||
534 | guardPortStrippedAddress :: Text -> SockAddr -> IO (Maybe ()) | ||
535 | guardPortStrippedAddress h laddr = do | ||
536 | maddr <- fmap (fmap (`withPort` 0)) $ parseAddress (strip_brackets h) | 542 | maddr <- fmap (fmap (`withPort` 0)) $ parseAddress (strip_brackets h) |
537 | let laddr' = laddr `withPort` 0 | 543 | let laddr' = laddr `withPort` 0 |
538 | return $ maddr >>= guard . (==laddr') | 544 | return $ maddr >>= guard . (==laddr') |
@@ -541,15 +547,15 @@ guardPortStrippedAddress h laddr = do | |||
541 | -- | Accepts a textual representation of a domainname | 547 | -- | Accepts a textual representation of a domainname |
542 | -- JID suitable for client connections, and returns the | 548 | -- JID suitable for client connections, and returns the |
543 | -- coresponding ipv6 address JID suitable for peers paired | 549 | -- coresponding ipv6 address JID suitable for peers paired |
544 | -- with a SockAddr with the address part of that JID in | 550 | -- with a PeerAddress with the address part of that JID in |
545 | -- binary form. If no suitable address could be resolved | 551 | -- binary form. If no suitable address could be resolved |
546 | -- for the given name, Nothing is returned. | 552 | -- for the given name, Nothing is returned. |
547 | rewriteJIDForPeer :: Text -> IO (Maybe (Text,SockAddr)) | 553 | rewriteJIDForPeer :: Text -> IO (Maybe (Text,PeerAddress)) |
548 | rewriteJIDForPeer jid = do | 554 | rewriteJIDForPeer jid = do |
549 | let (n,h,r) = splitJID jid | 555 | let (n,h,r) = splitJID jid |
550 | maddr <- fmap listToMaybe $ resolvePeer h | 556 | maddr <- fmap listToMaybe $ resolvePeer h |
551 | return $ flip fmap maddr $ \addr -> | 557 | return $ flip fmap maddr $ \addr -> |
552 | let h' = addrToText addr | 558 | let h' = peerKeyToText addr |
553 | to' = unsplitJID (n,h',r) | 559 | to' = unsplitJID (n,h',r) |
554 | in (to',addr) | 560 | in (to',addr) |
555 | 561 | ||
@@ -567,14 +573,15 @@ deliverMessage :: PresenceState | |||
567 | -> IO () | 573 | -> IO () |
568 | deliverMessage state fail msg = | 574 | deliverMessage state fail msg = |
569 | case stanzaOrigin msg of | 575 | case stanzaOrigin msg of |
570 | NetworkOrigin senderk@(ClientKey {}) _ -> do | 576 | ClientOrigin senderk _ -> do |
571 | -- Case 1. Client -> Peer | 577 | -- Case 1. Client -> Peer |
572 | mto <- fmap join $ mapM rewriteJIDForPeer (stanzaTo msg) | 578 | mto <- fmap join $ mapM rewriteJIDForPeer (stanzaTo msg) |
573 | fromMaybe fail {- reverse lookup failure -} $ mto <&> \(to',addr) -> do | 579 | fromMaybe fail {- reverse lookup failure -} $ mto <&> \(to',k) -> do |
574 | let k = PeerKey addr | 580 | chans <- atomically $ readTVar (pkeyToChan state) |
575 | chans <- atomically $ readTVar (keyToChan state) | 581 | fromMaybe fail $ (Map.lookup k chans) <&> \Conn { connChan = chan |
576 | fromMaybe fail $ (Map.lookup k chans) <&> \(Conn { connChan = chan | 582 | , auxData = ConnectionData (Left (Local laddr)) |
577 | , auxData = ConnectionData laddr ctyp }) -> do | 583 | ctyp |
584 | } -> do | ||
578 | (n,r) <- forClient state senderk (return (Nothing,Nothing)) | 585 | (n,r) <- forClient state senderk (return (Nothing,Nothing)) |
579 | $ \c -> return (Just (clientUser c), Just (clientResource c)) | 586 | $ \c -> return (Just (clientUser c), Just (clientResource c)) |
580 | -- original 'from' address is discarded. | 587 | -- original 'from' address is discarded. |
@@ -582,11 +589,14 @@ deliverMessage state fail msg = | |||
582 | -- dup <- atomically $ cloneStanza (msg { stanzaTo=Just to', stanzaFrom=Just from' }) | 589 | -- dup <- atomically $ cloneStanza (msg { stanzaTo=Just to', stanzaFrom=Just from' }) |
583 | let dup = (msg { stanzaTo=Just to', stanzaFrom=Just from' }) | 590 | let dup = (msg { stanzaTo=Just to', stanzaFrom=Just from' }) |
584 | sendModifiedStanzaToPeer dup chan | 591 | sendModifiedStanzaToPeer dup chan |
585 | NetworkOrigin senderk@(PeerKey {}) _ -> do | 592 | PeerOrigin senderk _ -> do |
586 | key_to_chan <- atomically $ readTVar (keyToChan state) | 593 | (pchans,cchans) <- atomically $ do |
587 | fromMaybe fail $ (Map.lookup senderk key_to_chan) | 594 | pc <- readTVar (pkeyToChan state) |
595 | cc <- readTVar (ckeyToChan state) | ||
596 | return (pc,cc) | ||
597 | fromMaybe fail $ (Map.lookup senderk pchans) | ||
588 | <&> \(Conn { connChan = sender_chan | 598 | <&> \(Conn { connChan = sender_chan |
589 | , auxData = ConnectionData laddr ctyp }) -> do | 599 | , auxData = ConnectionData (Left laddr) ctyp }) -> do |
590 | fromMaybe fail $ (stanzaTo msg) <&> \to -> do | 600 | fromMaybe fail $ (stanzaTo msg) <&> \to -> do |
591 | (mine,(n,h,r)) <- rewriteJIDForClient laddr to [] | 601 | (mine,(n,h,r)) <- rewriteJIDForClient laddr to [] |
592 | if not mine then fail else do | 602 | if not mine then fail else do |
@@ -600,7 +610,7 @@ deliverMessage state fail msg = | |||
600 | let ks = Map.keys (networkClients presence_container) | 610 | let ks = Map.keys (networkClients presence_container) |
601 | chans = do | 611 | chans = do |
602 | (k,client) <- Map.toList $ networkClients presence_container | 612 | (k,client) <- Map.toList $ networkClients presence_container |
603 | chan <- maybeToList $ Map.lookup k key_to_chan | 613 | chan <- maybeToList $ Map.lookup k cchans |
604 | return (clientProfile client, clientUser client, chan) | 614 | return (clientProfile client, clientUser client, chan) |
605 | forM chans $ \(profile,user,chan) -> do | 615 | forM chans $ \(profile,user,chan) -> do |
606 | buds <- configText ConfigFiles.getBuddies user profile | 616 | buds <- configText ConfigFiles.getBuddies user profile |
@@ -642,7 +652,7 @@ deliverMessage state fail msg = | |||
642 | chan | 652 | chan |
643 | 653 | ||
644 | 654 | ||
645 | setClientFlag :: PresenceState -> ConnectionKey -> Int8 -> IO () | 655 | setClientFlag :: PresenceState -> ClientAddress -> Int8 -> IO () |
646 | setClientFlag state k flag = | 656 | setClientFlag state k flag = |
647 | atomically $ do | 657 | atomically $ do |
648 | cmap <- readTVar (clients state) | 658 | cmap <- readTVar (clients state) |
@@ -653,12 +663,12 @@ setClientFlag0 :: ClientState -> Int8 -> STM () | |||
653 | setClientFlag0 client flag = | 663 | setClientFlag0 client flag = |
654 | modifyTVar' (clientFlags client) (\flgs -> flgs .|. flag) | 664 | modifyTVar' (clientFlags client) (\flgs -> flgs .|. flag) |
655 | 665 | ||
656 | informSentRoster :: PresenceState -> ConnectionKey -> IO () | 666 | informSentRoster :: PresenceState -> ClientAddress -> IO () |
657 | informSentRoster state k = do | 667 | informSentRoster state k = do |
658 | setClientFlag state k cf_interested | 668 | setClientFlag state k cf_interested |
659 | 669 | ||
660 | 670 | ||
661 | subscribedPeers :: Text -> Text -> IO [SockAddr] | 671 | subscribedPeers :: Text -> Text -> IO [PeerAddress] |
662 | subscribedPeers user profile = do | 672 | subscribedPeers user profile = do |
663 | jids <- configText ConfigFiles.getSubscribers user profile | 673 | jids <- configText ConfigFiles.getSubscribers user profile |
664 | let hosts = map ((\(_,h,_)->h) . splitJID) jids | 674 | let hosts = map ((\(_,h,_)->h) . splitJID) jids |
@@ -667,20 +677,23 @@ subscribedPeers user profile = do | |||
667 | -- | this JID is suitable for peers, not clients. | 677 | -- | this JID is suitable for peers, not clients. |
668 | clientJID :: Conn -> ClientState -> Text | 678 | clientJID :: Conn -> ClientState -> Text |
669 | clientJID con client = unsplitJID ( Just $ clientUser client | 679 | clientJID con client = unsplitJID ( Just $ clientUser client |
670 | , addrToText $ cdAddr $ auxData con | 680 | , either (\(Local a) -> addrToText a) -- my host name, for peers |
681 | (error $ unlines [ "clientJID wrongly used for client connection!" | ||
682 | , "TODO: my host name for clients? nameForClient? localJID?"]) | ||
683 | $ cdAddr $ auxData con | ||
671 | , Just $ clientResource client) | 684 | , Just $ clientResource client) |
672 | 685 | ||
673 | -- | Send presence notification to subscribed peers. | 686 | -- | Send presence notification to subscribed peers. |
674 | -- Note that a full JID from address will be added to the | 687 | -- Note that a full JID from address will be added to the |
675 | -- stanza if it is not present. | 688 | -- stanza if it is not present. |
676 | informClientPresence :: PresenceState | 689 | informClientPresence :: PresenceState |
677 | -> ConnectionKey -> StanzaWrap (LockedChan Event) -> IO () | 690 | -> ClientAddress -> StanzaWrap (LockedChan Event) -> IO () |
678 | informClientPresence state k stanza = do | 691 | informClientPresence state k stanza = do |
679 | forClient state k (return ()) $ \client -> do | 692 | forClient state k (return ()) $ \client -> do |
680 | informClientPresence0 state (Just k) client stanza | 693 | informClientPresence0 state (Just k) client stanza |
681 | 694 | ||
682 | informClientPresence0 :: PresenceState | 695 | informClientPresence0 :: PresenceState |
683 | -> Maybe ConnectionKey | 696 | -> Maybe ClientAddress |
684 | -> ClientState | 697 | -> ClientState |
685 | -> StanzaWrap (LockedChan Event) | 698 | -> StanzaWrap (LockedChan Event) |
686 | -> IO () | 699 | -> IO () |
@@ -692,8 +705,8 @@ informClientPresence0 state mbk client stanza = do | |||
692 | atomically $ setClientFlag0 client cf_available | 705 | atomically $ setClientFlag0 client cf_available |
693 | maybe (return ()) (sendCachedPresence state) mbk | 706 | maybe (return ()) (sendCachedPresence state) mbk |
694 | addrs <- subscribedPeers (clientUser client) (clientProfile client) | 707 | addrs <- subscribedPeers (clientUser client) (clientProfile client) |
695 | ktc <- atomically $ readTVar (keyToChan state) | 708 | ktc <- atomically $ readTVar (pkeyToChan state) |
696 | let connected = mapMaybe (flip Map.lookup ktc . PeerKey) addrs | 709 | let connected = mapMaybe (flip Map.lookup ktc) addrs |
697 | forM_ connected $ \con -> do | 710 | forM_ connected $ \con -> do |
698 | let from' = clientJID con client | 711 | let from' = clientJID con client |
699 | mto <- runTraversableT $ do | 712 | mto <- runTraversableT $ do |
@@ -706,7 +719,7 @@ informClientPresence0 state mbk client stanza = do | |||
706 | (connChan con) | 719 | (connChan con) |
707 | 720 | ||
708 | informPeerPresence :: PresenceState | 721 | informPeerPresence :: PresenceState |
709 | -> ConnectionKey | 722 | -> PeerAddress |
710 | -> StanzaWrap (LockedChan Event) | 723 | -> StanzaWrap (LockedChan Event) |
711 | -> IO () | 724 | -> IO () |
712 | informPeerPresence state k stanza = do | 725 | informPeerPresence state k stanza = do |
@@ -749,7 +762,7 @@ informPeerPresence state k stanza = do | |||
749 | 762 | ||
750 | -- all clients, we'll filter available/authorized later | 763 | -- all clients, we'll filter available/authorized later |
751 | 764 | ||
752 | ktc <- readTVar (keyToChan state) | 765 | ktc <- readTVar (ckeyToChan state) |
753 | runTraversableT $ do | 766 | runTraversableT $ do |
754 | (ck,client) <- liftMT $ fmap Map.toList $ readTVar (clients state) | 767 | (ck,client) <- liftMT $ fmap Map.toList $ readTVar (clients state) |
755 | con <- liftMaybe $ Map.lookup ck ktc | 768 | con <- liftMaybe $ Map.lookup ck ktc |
@@ -762,8 +775,7 @@ informPeerPresence state k stanza = do | |||
762 | when is_avail $ do | 775 | when is_avail $ do |
763 | putStrLn $ "reversing for client: " ++ show from | 776 | putStrLn $ "reversing for client: " ++ show from |
764 | froms <- do -- flip (maybe $ return [from]) k . const $ do | 777 | froms <- do -- flip (maybe $ return [from]) k . const $ do |
765 | let ClientKey laddr = ck | 778 | (_,trip) <- multiplyJIDForClient ck from |
766 | (_,trip) <- multiplyJIDForClient laddr from | ||
767 | return (map unsplitJID trip) | 779 | return (map unsplitJID trip) |
768 | 780 | ||
769 | putStrLn $ "sending to client: " ++ show (stanzaType stanza,froms) | 781 | putStrLn $ "sending to client: " ++ show (stanzaType stanza,froms) |
@@ -777,35 +789,37 @@ consoleClients PresenceState{ consoleWriter = Just cw } = readTVar (cwClients cw | |||
777 | consoleClients _ = return Map.empty | 789 | consoleClients _ = return Map.empty |
778 | 790 | ||
779 | 791 | ||
780 | answerProbe :: PresenceState | 792 | answerProbe :: PresenceState -> Maybe Text -> PeerAddress -> TChan Stanza -> IO () |
781 | -> Maybe Text -> ConnectionKey -> TChan Stanza -> IO () | ||
782 | answerProbe state mto k chan = do | 793 | answerProbe state mto k chan = do |
783 | -- putStrLn $ "answerProbe! " ++ show (stanzaType stanza) | 794 | -- putStrLn $ "answerProbe! " ++ show (stanzaType stanza) |
784 | (ktc,cmap) <- atomically $ (,) <$> readTVar (keyToChan state) | 795 | ktc <- atomically $ readTVar (pkeyToChan state) |
785 | <*> readTVar (clients state) | ||
786 | muser <- runTraversableT $ do | 796 | muser <- runTraversableT $ do |
787 | to <- liftT $ mto | 797 | to <- liftT $ mto |
788 | conn <- liftT $ Map.lookup k ktc | 798 | conn <- liftT $ Map.lookup k ktc |
789 | let (mu,h,_) = splitJID to -- TODO: currently resource-id is ignored on presence | 799 | let (mu,h,_) = splitJID to -- TODO: currently resource-id is ignored on presence |
790 | -- probes. Is this correct? Check the spec. | 800 | -- probes. Is this correct? Check the spec. |
791 | liftMT $ guardPortStrippedAddress h (cdAddr $ auxData conn) | 801 | Left laddr = cdAddr $ auxData conn |
802 | liftMT $ guardPortStrippedAddress h laddr | ||
792 | u <- liftT mu | 803 | u <- liftT mu |
793 | let ch = addrToText (cdAddr $ auxData conn) | 804 | -- ORIG let ch = addrToText (auxAddr conn) |
794 | profile = fromMaybe "." $ clientProfile <$> Map.lookup k cmap | 805 | -- ORIG return (u,conn,ch) |
795 | return (u,profile,conn,ch) | 806 | let ch = addrToText a where Local a = laddr |
807 | return (u,conn,ch) | ||
796 | 808 | ||
797 | forM_ muser $ \(u,profile,conn,ch) -> do | 809 | forM_ muser $ \(u,conn,ch) -> do |
798 | 810 | ||
811 | profiles <- releventProfiles (cdType $ auxData conn) u | ||
812 | forM_ profiles $ \profile -> do | ||
813 | |||
814 | -- only subscribed peers should get probe replies | ||
799 | resolved_subs <- resolvedFromRoster ConfigFiles.getSubscribers u profile | 815 | resolved_subs <- resolvedFromRoster ConfigFiles.getSubscribers u profile |
800 | let gaddrs = groupBy (\a b -> snd a == snd b) (sort resolved_subs) | 816 | let gaddrs = groupBy sameHost (sort resolved_subs) |
817 | sameHost a b = (snd a == snd b) -- (==) `on` snd | ||
801 | whitelist = do | 818 | whitelist = do |
802 | xs <- gaddrs | 819 | xs <- gaddrs -- group of subscribed jids on the same host |
803 | x <- take 1 xs | 820 | x <- take 1 xs -- the host from the group |
804 | guard $ snd x==k | 821 | guard $ snd x==k -- only hosts matching the key /k/ |
805 | mapMaybe fst xs | 822 | mapMaybe fst xs -- all users subscribed at the remote peer /k/ |
806 | |||
807 | -- -- only subscribed peers should get probe replies | ||
808 | -- addrs <- subscribedPeers u | ||
809 | 823 | ||
810 | -- TODO: notify remote peer that they are unsubscribed? | 824 | -- TODO: notify remote peer that they are unsubscribed? |
811 | -- reply <- makeInformSubscription "jabber:server" to from False | 825 | -- reply <- makeInformSubscription "jabber:server" to from False |
@@ -838,16 +852,15 @@ answerProbe state mto k chan = do | |||
838 | 852 | ||
839 | -- Send friend requests and remote presences stored in remotesByPeer to XMPP | 853 | -- Send friend requests and remote presences stored in remotesByPeer to XMPP |
840 | -- clients. | 854 | -- clients. |
841 | sendCachedPresence :: PresenceState -> ConnectionKey -> IO () | 855 | sendCachedPresence :: PresenceState -> ClientAddress -> IO () |
842 | sendCachedPresence state k = do | 856 | sendCachedPresence state k = do |
843 | forClient state k (return ()) $ \client -> do | 857 | forClient state k (return ()) $ \client -> do |
844 | rbp <- atomically $ readTVar (remotesByPeer state) | 858 | rbp <- atomically $ readTVar (remotesByPeer state) |
845 | jids <- configText ConfigFiles.getBuddies (clientUser client) (clientProfile client) | 859 | jids <- configText ConfigFiles.getBuddies (clientUser client) (clientProfile client) |
846 | let hosts = map ((\(_,h,_)->h) . splitJID) jids | 860 | let hosts = map ((\(_,h,_)->h) . splitJID) jids |
847 | addrs <- resolveAllPeers hosts | 861 | addrs <- resolveAllPeers hosts |
848 | let onlines = rbp `Map.intersection` Map.mapKeys PeerKey addrs | 862 | let onlines = rbp `Map.intersection` addrs |
849 | ClientKey laddr = k | 863 | mcon <- atomically $ do ktc <- readTVar (ckeyToChan state) |
850 | mcon <- atomically $ do ktc <- readTVar (keyToChan state) | ||
851 | return $ Map.lookup k ktc | 864 | return $ Map.lookup k ktc |
852 | forM_ mcon $ \con -> do | 865 | forM_ mcon $ \con -> do |
853 | forM_ (Map.toList onlines) $ \(pk, umap) -> do | 866 | forM_ (Map.toList onlines) $ \(pk, umap) -> do |
@@ -855,7 +868,7 @@ sendCachedPresence state k = do | |||
855 | let h = peerKeyToText pk | 868 | let h = peerKeyToText pk |
856 | forM_ (Map.toList $ resources rp) $ \(resource,stanza) -> do | 869 | forM_ (Map.toList $ resources rp) $ \(resource,stanza) -> do |
857 | let jid = unsplitJID (Just user,h,Just resource) | 870 | let jid = unsplitJID (Just user,h,Just resource) |
858 | (mine,js) <- multiplyJIDForClient laddr jid | 871 | (mine,js) <- multiplyJIDForClient k jid |
859 | forM_ js $ \jid -> do | 872 | forM_ js $ \jid -> do |
860 | let from' = unsplitJID jid | 873 | let from' = unsplitJID jid |
861 | dup <- cloneStanza stanza | 874 | dup <- cloneStanza stanza |
@@ -883,7 +896,7 @@ addToRosterFile :: | |||
883 | -> t1) | 896 | -> t1) |
884 | -> Text -- user | 897 | -> Text -- user |
885 | -> Text -- profile | 898 | -> Text -- profile |
886 | -> Text -> [SockAddr] -> t1 | 899 | -> Text -> [PeerAddress] -> t1 |
887 | addToRosterFile doit whose profile to addrs = | 900 | addToRosterFile doit whose profile to addrs = |
888 | modifyRosterFile doit whose profile to addrs True | 901 | modifyRosterFile doit whose profile to addrs True |
889 | 902 | ||
@@ -895,7 +908,7 @@ removeFromRosterFile :: | |||
895 | -> t1) | 908 | -> t1) |
896 | -> Text -- user | 909 | -> Text -- user |
897 | -> Text -- profile | 910 | -> Text -- profile |
898 | -> Text -> [SockAddr] -> t1 | 911 | -> Text -> [PeerAddress] -> t1 |
899 | removeFromRosterFile doit whose profile to addrs = | 912 | removeFromRosterFile doit whose profile to addrs = |
900 | modifyRosterFile doit whose profile to addrs False | 913 | modifyRosterFile doit whose profile to addrs False |
901 | 914 | ||
@@ -920,7 +933,7 @@ modifyRosterFile :: | |||
920 | -> Text -- ^ user | 933 | -> Text -- ^ user |
921 | -> Text -- ^ profile | 934 | -> Text -- ^ profile |
922 | -> Text -- ^ JID that will be added or removed a hostname | 935 | -> Text -- ^ JID that will be added or removed a hostname |
923 | -> [SockAddr] -- ^ Alias addresses for hostname in the JID. | 936 | -> [PeerAddress] -- ^ Alias addresses for hostname in the JID. |
924 | -> Bool -- ^ True if adding, otherwise False | 937 | -> Bool -- ^ True if adding, otherwise False |
925 | -> t1 | 938 | -> t1 |
926 | modifyRosterFile doit whose profile to addrs bAdd = do | 939 | modifyRosterFile doit whose profile to addrs bAdd = do |
@@ -951,7 +964,7 @@ modifyRosterFile doit whose profile to addrs bAdd = do | |||
951 | (guard bAdd >> Just (textToLazyByteString to)) | 964 | (guard bAdd >> Just (textToLazyByteString to)) |
952 | 965 | ||
953 | 966 | ||
954 | clientSubscriptionRequest :: PresenceState -> IO () -> ConnectionKey -> Stanza -> TChan Stanza -> IO () | 967 | clientSubscriptionRequest :: PresenceState -> IO () -> ClientAddress -> Stanza -> TChan Stanza -> IO () |
955 | clientSubscriptionRequest state fail k stanza chan = do | 968 | clientSubscriptionRequest state fail k stanza chan = do |
956 | forClient state k fail $ \client -> do | 969 | forClient state k fail $ \client -> do |
957 | fromMaybe fail $ (splitJID <$> stanzaTo stanza) <&> \(mu,h,_) -> do | 970 | fromMaybe fail $ (splitJID <$> stanzaTo stanza) <&> \(mu,h,_) -> do |
@@ -967,7 +980,7 @@ clientSubscriptionRequest state fail k stanza chan = do | |||
967 | addToRosterFile ConfigFiles.modifySolicited cuser cprof to addrs | 980 | addToRosterFile ConfigFiles.modifySolicited cuser cprof to addrs |
968 | removeFromRosterFile ConfigFiles.modifyBuddies cuser cprof to addrs | 981 | removeFromRosterFile ConfigFiles.modifyBuddies cuser cprof to addrs |
969 | resolved_subs <- resolvedFromRoster ConfigFiles.getSubscribers cuser cprof | 982 | resolved_subs <- resolvedFromRoster ConfigFiles.getSubscribers cuser cprof |
970 | let is_subscribed = not . null $ [ (mu, PeerKey a) | a <- addrs ] | 983 | let is_subscribed = not . null $ [ (mu, a) | a <- addrs ] |
971 | `intersect` resolved_subs | 984 | `intersect` resolved_subs |
972 | -- subscribers: "from" | 985 | -- subscribers: "from" |
973 | -- buddies: "to" | 986 | -- buddies: "to" |
@@ -975,16 +988,18 @@ clientSubscriptionRequest state fail k stanza chan = do | |||
975 | case state of | 988 | case state of |
976 | PresenceState { server = svVar } -> do | 989 | PresenceState { server = svVar } -> do |
977 | 990 | ||
978 | (ktc,(sv,conns)) <- atomically $ | 991 | (cktc,pktc,(sv,conns)) <- atomically $ do |
979 | liftM2 (,) (readTVar $ keyToChan state) | 992 | cktc <- readTVar $ ckeyToChan state |
980 | (takeTMVar svVar) | 993 | pktc <- readTVar $ pkeyToChan state |
994 | sc <- takeTMVar svVar | ||
995 | return (cktc,pktc,sc) | ||
981 | 996 | ||
982 | -- Update roster for each client. | 997 | -- Update roster for each client. |
983 | case stanzaType stanza of | 998 | case stanzaType stanza of |
984 | PresenceRequestSubscription True -> do | 999 | PresenceRequestSubscription True -> do |
985 | hostname <- nameForClient state k | 1000 | hostname <- nameForClient state k |
986 | let cjid = unsplitJID (Just $ clientUser client, hostname,Nothing) | 1001 | let cjid = unsplitJID (Just $ clientUser client, hostname,Nothing) |
987 | chans <- clientCons state ktc (clientUser client) | 1002 | chans <- clientCons state cktc (clientUser client) |
988 | forM_ chans $ \( Conn { connChan=chan }, client ) -> do | 1003 | forM_ chans $ \( Conn { connChan=chan }, client ) -> do |
989 | -- roster update ask="subscribe" | 1004 | -- roster update ask="subscribe" |
990 | update <- makeRosterUpdate cjid to | 1005 | update <- makeRosterUpdate cjid to |
@@ -996,13 +1011,13 @@ clientSubscriptionRequest state fail k stanza chan = do | |||
996 | _ -> return () | 1011 | _ -> return () |
997 | 1012 | ||
998 | -- Send friend request to peer. | 1013 | -- Send friend request to peer. |
999 | let dsts = ktc `Map.intersection` | 1014 | let dsts = pktc `Map.intersection` toMapUnit addrs |
1000 | Map.fromList [ (PeerKey a, ()) | a <- addrs ] | ||
1001 | forM_ (Map.toList dsts) $ \(pk,con) -> do | 1015 | forM_ (Map.toList dsts) $ \(pk,con) -> do |
1002 | -- if already connected, send solicitation ... | 1016 | -- if already connected, send solicitation ... |
1003 | -- let from = clientJID con client | 1017 | -- let from = clientJID con client |
1004 | let from = unsplitJID ( Just $ clientUser client | 1018 | let Left laddr = cdAddr $ auxData con |
1005 | , addrToText $ cdAddr $ auxData con | 1019 | from = unsplitJID ( Just $ clientUser client |
1020 | , (\(Local a) -> addrToText a) $ laddr | ||
1006 | , Nothing ) | 1021 | , Nothing ) |
1007 | mb <- rewriteJIDForPeer to | 1022 | mb <- rewriteJIDForPeer to |
1008 | forM_ mb $ \(to',addr) -> do | 1023 | forM_ mb $ \(to',addr) -> do |
@@ -1022,20 +1037,20 @@ clientSubscriptionRequest state fail k stanza chan = do | |||
1022 | 1037 | ||
1023 | resolvedFromRoster | 1038 | resolvedFromRoster |
1024 | :: (ConfigFiles.User -> ConfigFiles.Profile -> IO [L.ByteString]) | 1039 | :: (ConfigFiles.User -> ConfigFiles.Profile -> IO [L.ByteString]) |
1025 | -> UserName -> Text -> IO [(Maybe UserName, ConnectionKey)] | 1040 | -> UserName -> Text -> IO [(Maybe UserName, PeerAddress)] |
1026 | resolvedFromRoster doit u profile = do | 1041 | resolvedFromRoster doit u profile = do |
1027 | subs <- configText doit u profile | 1042 | subs <- configText doit u profile |
1028 | runTraversableT $ do | 1043 | runTraversableT $ do |
1029 | (mu,h,_) <- liftT $ splitJID `fmap` subs | 1044 | (mu,h,_) <- liftT $ splitJID `fmap` subs |
1030 | addr <- liftMT $ fmap nub $ resolvePeer h | 1045 | addr <- liftMT $ fmap nub $ resolvePeer h |
1031 | return (mu,PeerKey addr) | 1046 | return (mu,addr) |
1032 | 1047 | ||
1033 | clientCons :: PresenceState | 1048 | clientCons :: PresenceState |
1034 | -> Map ConnectionKey t -> Text -> IO [(t, ClientState)] | 1049 | -> Map ClientAddress t -> Text -> IO [(t, ClientState)] |
1035 | clientCons state ktc u = map snd <$> clientCons' state ktc u | 1050 | clientCons state ktc u = map snd <$> clientCons' state ktc u |
1036 | 1051 | ||
1037 | clientCons' :: PresenceState | 1052 | clientCons' :: PresenceState |
1038 | -> Map ConnectionKey t -> Text -> IO [(ConnectionKey,(t, ClientState))] | 1053 | -> Map ClientAddress t -> Text -> IO [(ClientAddress,(t, ClientState))] |
1039 | clientCons' state ktc u = do | 1054 | clientCons' state ktc u = do |
1040 | mlp <- atomically $ do | 1055 | mlp <- atomically $ do |
1041 | cmap <- readTVar $ clientsByUser state | 1056 | cmap <- readTVar $ clientsByUser state |
@@ -1047,7 +1062,14 @@ clientCons' state ktc u = do | |||
1047 | return (k,(con,client)) | 1062 | return (k,(con,client)) |
1048 | return $ mapMaybe doit ks | 1063 | return $ mapMaybe doit ks |
1049 | 1064 | ||
1050 | peerSubscriptionRequest :: PresenceState -> IO () -> ConnectionKey -> Stanza -> TChan Stanza -> IO () | 1065 | releventProfiles :: ConnectionType -> Text -> IO [Text] |
1066 | releventProfiles XMPP _ = return ["."] | ||
1067 | releventProfiles ctyp user = do | ||
1068 | -- TODO: Return all the ".tox" profiles that a user has under his | ||
1069 | -- .presence/ directory. | ||
1070 | return [] | ||
1071 | |||
1072 | peerSubscriptionRequest :: PresenceState -> IO () -> PeerAddress -> Stanza -> TChan Stanza -> IO () | ||
1051 | peerSubscriptionRequest state fail k stanza chan = do | 1073 | peerSubscriptionRequest state fail k stanza chan = do |
1052 | putStrLn $ "Handling pending subscription from remote" | 1074 | putStrLn $ "Handling pending subscription from remote" |
1053 | fromMaybe fail $ (stanzaFrom stanza) <&> \from -> do | 1075 | fromMaybe fail $ (stanzaFrom stanza) <&> \from -> do |
@@ -1056,24 +1078,20 @@ peerSubscriptionRequest state fail k stanza chan = do | |||
1056 | (mfrom_u,from_h,_) = splitJID from | 1078 | (mfrom_u,from_h,_) = splitJID from |
1057 | to <- return $ unsplitJID (mto_u,h,Nothing) -- delete resource | 1079 | to <- return $ unsplitJID (mto_u,h,Nothing) -- delete resource |
1058 | from <- return $ unsplitJID (mfrom_u,from_h,Nothing) -- delete resource | 1080 | from <- return $ unsplitJID (mfrom_u,from_h,Nothing) -- delete resource |
1059 | (ktc,cmap) <- atomically $ (,) <$> readTVar (keyToChan state) | 1081 | (pktc,cktc,cmap) <- atomically $ do |
1060 | <*> readTVar (clients state) | 1082 | cktc <- readTVar (ckeyToChan state) |
1061 | fromMaybe fail $ (Map.lookup k ktc) | 1083 | pktc <- readTVar (pkeyToChan state) |
1062 | <&> \Conn { auxData=ConnectionData laddr ctyp } -> do | 1084 | cmap <- readTVar (clients state) |
1085 | return (pktc,cktc,cmap) | ||
1086 | fromMaybe fail $ (Map.lookup k pktc) | ||
1087 | <&> \Conn { auxData=ConnectionData (Left laddr) ctyp } -> do | ||
1063 | (mine,totup) <- rewriteJIDForClient laddr to [] | 1088 | (mine,totup) <- rewriteJIDForClient laddr to [] |
1064 | if not mine then fail else do | 1089 | if not mine then fail else do |
1065 | (_,fromtup) <- rewriteJIDForClient laddr from [] | 1090 | (_,fromtup) <- rewriteJIDForClient laddr from [] |
1066 | fromMaybe fail $ mto_u <&> \u -> do | 1091 | fromMaybe fail $ mto_u <&> \u -> do |
1067 | fromMaybe fail $ mfrom_u <&> \from_u -> do | 1092 | fromMaybe fail $ mfrom_u <&> \from_u -> do |
1068 | let profile = fromMaybe "." $ clientProfile <$> Map.lookup k cmap | 1093 | profiles <- releventProfiles ctyp u |
1069 | -- XXX profile is wrong. | 1094 | forM_ profiles $ \profile -> do |
1070 | -- TODO Likely the problem is that k is a peer ConnectionKey and of course | ||
1071 | -- will have no entry in the cmap. Thus giving "." even though it ought | ||
1072 | -- to be using a tox profile. | ||
1073 | -- | ||
1074 | -- Solution 1: Only .tox peers go in a tox profile. | ||
1075 | -- Solution 2: Duplicate non .tox peers in all profiles. | ||
1076 | -- Solution 3: Only one profile is active at a time. | ||
1077 | resolved_subs <- resolvedFromRoster ConfigFiles.getSubscribers u profile | 1095 | resolved_subs <- resolvedFromRoster ConfigFiles.getSubscribers u profile |
1078 | let already_subscribed = elem (mfrom_u,k) resolved_subs | 1096 | let already_subscribed = elem (mfrom_u,k) resolved_subs |
1079 | is_wanted = case stanzaType stanza of | 1097 | is_wanted = case stanzaType stanza of |
@@ -1116,7 +1134,7 @@ peerSubscriptionRequest state fail k stanza chan = do | |||
1116 | when (not already_pending) $ do | 1134 | when (not already_pending) $ do |
1117 | -- contact ∉ subscribers & contact ∉ pending --> MUST | 1135 | -- contact ∉ subscribers & contact ∉ pending --> MUST |
1118 | 1136 | ||
1119 | chans <- clientCons state ktc u | 1137 | chans <- clientCons state cktc u |
1120 | forM_ chans $ \( Conn { connChan=chan }, client ) -> do | 1138 | forM_ chans $ \( Conn { connChan=chan }, client ) -> do |
1121 | -- send to clients | 1139 | -- send to clients |
1122 | -- TODO: interested/available clients only? | 1140 | -- TODO: interested/available clients only? |
@@ -1128,7 +1146,7 @@ peerSubscriptionRequest state fail k stanza chan = do | |||
1128 | 1146 | ||
1129 | clientInformSubscription :: PresenceState | 1147 | clientInformSubscription :: PresenceState |
1130 | -> IO () | 1148 | -> IO () |
1131 | -> ConnectionKey | 1149 | -> ClientAddress |
1132 | -> StanzaWrap (LockedChan Event) | 1150 | -> StanzaWrap (LockedChan Event) |
1133 | -> IO () | 1151 | -> IO () |
1134 | clientInformSubscription state fail k stanza = do | 1152 | clientInformSubscription state fail k stanza = do |
@@ -1139,7 +1157,7 @@ clientInformSubscription state fail k stanza = do | |||
1139 | addrs <- resolvePeer h | 1157 | addrs <- resolvePeer h |
1140 | -- remove from pending | 1158 | -- remove from pending |
1141 | buds <- resolvedFromRoster ConfigFiles.getBuddies (clientUser client) (clientProfile client) | 1159 | buds <- resolvedFromRoster ConfigFiles.getBuddies (clientUser client) (clientProfile client) |
1142 | let is_buddy = not . null $ map ((mu,) . PeerKey) addrs `intersect` buds | 1160 | let is_buddy = not . null $ map (mu,) addrs `intersect` buds |
1143 | removeFromRosterFile ConfigFiles.modifyPending (clientUser client) (clientProfile client) to addrs | 1161 | removeFromRosterFile ConfigFiles.modifyPending (clientUser client) (clientProfile client) to addrs |
1144 | let (relationship,addf,remf) = | 1162 | let (relationship,addf,remf) = |
1145 | case stanzaType stanza of | 1163 | case stanzaType stanza of |
@@ -1160,12 +1178,13 @@ clientInformSubscription state fail k stanza = do | |||
1160 | putStrLn $ "cbu = " ++ show (fmap (fmap clientPid . networkClients) cbu) | 1178 | putStrLn $ "cbu = " ++ show (fmap (fmap clientPid . networkClients) cbu) |
1161 | 1179 | ||
1162 | -- send roster update to clients | 1180 | -- send roster update to clients |
1163 | (clients,ktc) <- atomically $ do | 1181 | (clients,ktc,pktc) <- atomically $ do |
1164 | cbu <- readTVar (clientsByUser state) | 1182 | cbu <- readTVar (clientsByUser state) |
1165 | let mlp = Map.lookup (clientUser client) cbu | 1183 | let mlp = Map.lookup (clientUser client) cbu |
1166 | let cs = maybe [] (Map.toList . networkClients) mlp | 1184 | let cs = maybe [] (Map.toList . networkClients) mlp |
1167 | ktc <- readTVar (keyToChan state) | 1185 | ktc <- readTVar (ckeyToChan state) |
1168 | return (cs,ktc) | 1186 | pktc <- readTVar (pkeyToChan state) |
1187 | return (cs,ktc,pktc) | ||
1169 | forM_ clients $ \(ck, client) -> do | 1188 | forM_ clients $ \(ck, client) -> do |
1170 | is_intereseted <- atomically $ clientIsInterested client | 1189 | is_intereseted <- atomically $ clientIsInterested client |
1171 | putStrLn $ "clientIsInterested: "++show is_intereseted | 1190 | putStrLn $ "clientIsInterested: "++show is_intereseted |
@@ -1179,8 +1198,8 @@ clientInformSubscription state fail k stanza = do | |||
1179 | sendModifiedStanzaToClient update (connChan con) | 1198 | sendModifiedStanzaToClient update (connChan con) |
1180 | 1199 | ||
1181 | -- notify peer | 1200 | -- notify peer |
1182 | let dsts = Map.fromList $ map ((,()) . PeerKey) addrs | 1201 | let dsts = toMapUnit addrs |
1183 | cdsts = ktc `Map.intersection` dsts | 1202 | cdsts = pktc `Map.intersection` dsts |
1184 | forM_ (Map.toList cdsts) $ \(pk,con) -> do | 1203 | forM_ (Map.toList cdsts) $ \(pk,con) -> do |
1185 | let from = clientJID con client | 1204 | let from = clientJID con client |
1186 | to' = unsplitJID (mu, peerKeyToText pk, Nothing) | 1205 | to' = unsplitJID (mu, peerKeyToText pk, Nothing) |
@@ -1192,18 +1211,21 @@ clientInformSubscription state fail k stanza = do | |||
1192 | 1211 | ||
1193 | peerInformSubscription :: PresenceState | 1212 | peerInformSubscription :: PresenceState |
1194 | -> IO () | 1213 | -> IO () |
1195 | -> ConnectionKey | 1214 | -> PeerAddress |
1196 | -> StanzaWrap (LockedChan Event) | 1215 | -> StanzaWrap (LockedChan Event) |
1197 | -> IO () | 1216 | -> IO () |
1198 | peerInformSubscription state fail k stanza = do | 1217 | peerInformSubscription state fail k stanza = do |
1199 | putStrLn $ "TODO: peerInformSubscription" | 1218 | putStrLn $ "TODO: peerInformSubscription" |
1200 | -- remove from solicited | 1219 | -- remove from solicited |
1201 | fromMaybe fail $ (stanzaFrom stanza) <&> \from -> do | 1220 | fromMaybe fail $ (stanzaFrom stanza) <&> \from -> do |
1202 | (ktc,cmap) <- atomically $ (,) <$> readTVar (keyToChan state) | 1221 | (ktc,cktc,cmap) <- atomically $ do |
1203 | <*> readTVar (clients state) | 1222 | pktc <- readTVar (pkeyToChan state) |
1223 | cktc <- readTVar (ckeyToChan state) | ||
1224 | cmap <- readTVar (clients state) | ||
1225 | return (pktc,cktc,cmap) | ||
1204 | fromMaybe fail $ (Map.lookup k ktc) | 1226 | fromMaybe fail $ (Map.lookup k ktc) |
1205 | <&> \(Conn { connChan=sender_chan | 1227 | <&> \(Conn { connChan=sender_chan |
1206 | , auxData =ConnectionData laddr ctyp }) -> do | 1228 | , auxData =ConnectionData (Left laddr) ctyp }) -> do |
1207 | (_,(from_u,from_h,_)) <- rewriteJIDForClient laddr from [] | 1229 | (_,(from_u,from_h,_)) <- rewriteJIDForClient laddr from [] |
1208 | let from'' = unsplitJID (from_u,from_h,Nothing) | 1230 | let from'' = unsplitJID (from_u,from_h,Nothing) |
1209 | muser = do | 1231 | muser = do |
@@ -1215,10 +1237,11 @@ peerInformSubscription state fail k stanza = do | |||
1215 | -- This would allow us to answer anonymous probes with 'unsubscribed'. | 1237 | -- This would allow us to answer anonymous probes with 'unsubscribed'. |
1216 | fromMaybe fail $ muser <&> \user -> do | 1238 | fromMaybe fail $ muser <&> \user -> do |
1217 | addrs <- resolvePeer from_h | 1239 | addrs <- resolvePeer from_h |
1218 | let profile = fromMaybe "." $ clientProfile <$> Map.lookup k cmap | 1240 | profiles <- releventProfiles ctyp user |
1241 | forM_ profiles $ \profile -> do | ||
1219 | was_solicited <- removeFromRosterFile ConfigFiles.modifySolicited user profile from'' addrs | 1242 | was_solicited <- removeFromRosterFile ConfigFiles.modifySolicited user profile from'' addrs |
1220 | subs <- resolvedFromRoster ConfigFiles.getSubscribers user profile | 1243 | subs <- resolvedFromRoster ConfigFiles.getSubscribers user profile |
1221 | let is_sub = not . null $ map ((from_u,) . PeerKey) addrs `intersect` subs | 1244 | let is_sub = not . null $ map (from_u,) addrs `intersect` subs |
1222 | putStrLn $ "DEBUG peerInformSubscription (is_sub,typ)=" ++ show (is_sub,stanzaType stanza) | 1245 | putStrLn $ "DEBUG peerInformSubscription (is_sub,typ)=" ++ show (is_sub,stanzaType stanza) |
1223 | let (relationship,addf,remf) = | 1246 | let (relationship,addf,remf) = |
1224 | case stanzaType stanza of | 1247 | case stanzaType stanza of |
@@ -1234,7 +1257,7 @@ peerInformSubscription state fail k stanza = do | |||
1234 | addToRosterFile addf user profile from'' addrs | 1257 | addToRosterFile addf user profile from'' addrs |
1235 | removeFromRosterFile remf user profile from'' addrs | 1258 | removeFromRosterFile remf user profile from'' addrs |
1236 | 1259 | ||
1237 | chans <- clientCons' state ktc user | 1260 | chans <- clientCons' state cktc user |
1238 | forM_ chans $ \(ckey,(Conn { connChan=chan }, client)) -> do | 1261 | forM_ chans $ \(ckey,(Conn { connChan=chan }, client)) -> do |
1239 | hostname <- nameForClient state ckey | 1262 | hostname <- nameForClient state ckey |
1240 | let to' = unsplitJID (Just user, hostname, Nothing) | 1263 | let to' = unsplitJID (Just user, hostname, Nothing) |