diff options
-rw-r--r-- | xmppServer.hs | 91 |
1 files changed, 88 insertions, 3 deletions
diff --git a/xmppServer.hs b/xmppServer.hs index 118a16b2..803b4324 100644 --- a/xmppServer.hs +++ b/xmppServer.hs | |||
@@ -32,7 +32,11 @@ import qualified ConfigFiles | |||
32 | import Data.Maybe (maybeToList,listToMaybe,mapMaybe) | 32 | import Data.Maybe (maybeToList,listToMaybe,mapMaybe) |
33 | import Data.Bits | 33 | import Data.Bits |
34 | import Data.Int (Int8) | 34 | import Data.Int (Int8) |
35 | import Data.XML.Types (Event) | ||
36 | import System.Posix.Types (UserID,CPid) | ||
37 | import Control.Applicative | ||
35 | 38 | ||
39 | import LockedChan (LockedChan) | ||
36 | import TraversableT | 40 | import TraversableT |
37 | import UTmp (ProcessID,users) | 41 | import UTmp (ProcessID,users) |
38 | import LocalPeerCred | 42 | import LocalPeerCred |
@@ -71,8 +75,10 @@ isPeerKey k = case k of { PeerKey {} -> True ; _ -> False } | |||
71 | isClientKey :: ConnectionKey -> Bool | 75 | isClientKey :: ConnectionKey -> Bool |
72 | isClientKey k = case k of { ClientKey {} -> True ; _ -> False } | 76 | isClientKey k = case k of { ClientKey {} -> True ; _ -> False } |
73 | 77 | ||
78 | textHostName :: IO Text | ||
74 | textHostName = fmap Text.pack BSD.getHostName | 79 | textHostName = fmap Text.pack BSD.getHostName |
75 | 80 | ||
81 | localJID :: Text -> Text -> IO Text | ||
76 | localJID user resource = do | 82 | localJID user resource = do |
77 | hostname <- textHostName | 83 | hostname <- textHostName |
78 | return $ user <> "@" <> hostname <> "/" <> resource | 84 | return $ user <> "@" <> hostname <> "/" <> resource |
@@ -92,19 +98,25 @@ data RemotePresence = RemotePresence | |||
92 | 98 | ||
93 | 99 | ||
94 | 100 | ||
101 | pcSingletonNetworkClient :: ConnectionKey | ||
102 | -> ClientState -> LocalPresence | ||
95 | pcSingletonNetworkClient key client = | 103 | pcSingletonNetworkClient key client = |
96 | LocalPresence | 104 | LocalPresence |
97 | { networkClients = Map.singleton key client | 105 | { networkClients = Map.singleton key client |
98 | } | 106 | } |
99 | 107 | ||
108 | pcInsertNetworkClient :: ConnectionKey -> ClientState -> LocalPresence -> LocalPresence | ||
100 | pcInsertNetworkClient key client pc = | 109 | pcInsertNetworkClient key client pc = |
101 | pc { networkClients = Map.insert key client (networkClients pc) } | 110 | pc { networkClients = Map.insert key client (networkClients pc) } |
102 | 111 | ||
112 | pcRemoveNewtworkClient :: ConnectionKey | ||
113 | -> LocalPresence -> Maybe LocalPresence | ||
103 | pcRemoveNewtworkClient key pc = if pcIsEmpty pc' then Nothing | 114 | pcRemoveNewtworkClient key pc = if pcIsEmpty pc' then Nothing |
104 | else Just pc' | 115 | else Just pc' |
105 | where | 116 | where |
106 | pc' = pc { networkClients = Map.delete key (networkClients pc) } | 117 | pc' = pc { networkClients = Map.delete key (networkClients pc) } |
107 | 118 | ||
119 | pcIsEmpty :: LocalPresence -> Bool | ||
108 | pcIsEmpty pc = Map.null (networkClients pc) | 120 | pcIsEmpty pc = Map.null (networkClients pc) |
109 | 121 | ||
110 | 122 | ||
@@ -127,14 +139,23 @@ getConsolePids state = do | |||
127 | us <- UTmp.users | 139 | us <- UTmp.users |
128 | return $ map (\(_,tty,pid)->(lazyByteStringToText tty,pid)) us | 140 | return $ map (\(_,tty,pid)->(lazyByteStringToText tty,pid)) us |
129 | 141 | ||
142 | lazyByteStringToText :: L.ByteString -> Text | ||
130 | lazyByteStringToText = (foldr1 (<>) . map Text.decodeUtf8 . L.toChunks) | 143 | lazyByteStringToText = (foldr1 (<>) . map Text.decodeUtf8 . L.toChunks) |
144 | |||
145 | textToLazyByteString :: Text -> L.ByteString | ||
131 | textToLazyByteString s = L.fromChunks [Text.encodeUtf8 s] | 146 | textToLazyByteString s = L.fromChunks [Text.encodeUtf8 s] |
132 | 147 | ||
148 | identifyTTY' :: [(Text, ProcessID)] | ||
149 | -> System.Posix.Types.UserID | ||
150 | -> L.ByteString | ||
151 | -> IO (Maybe Text, Maybe System.Posix.Types.CPid) | ||
133 | identifyTTY' ttypids uid inode = ttypid | 152 | identifyTTY' ttypids uid inode = ttypid |
134 | where ttypids' = map (\(tty,pid)->(L.fromChunks [Text.encodeUtf8 tty], pid)) ttypids | 153 | where ttypids' = map (\(tty,pid)->(L.fromChunks [Text.encodeUtf8 tty], pid)) ttypids |
135 | ttypid = fmap textify $ identifyTTY ttypids' uid inode | 154 | ttypid = fmap textify $ identifyTTY ttypids' uid inode |
136 | textify (tty,pid) = (fmap lazyByteStringToText tty, pid) | 155 | textify (tty,pid) = (fmap lazyByteStringToText tty, pid) |
137 | 156 | ||
157 | chooseResourceName :: PresenceState | ||
158 | -> ConnectionKey -> SockAddr -> t -> IO Text | ||
138 | chooseResourceName state k addr desired = do | 159 | chooseResourceName state k addr desired = do |
139 | muid <- getLocalPeerCred' addr | 160 | muid <- getLocalPeerCred' addr |
140 | (mtty,pid) <- getTTYandPID muid | 161 | (mtty,pid) <- getTTYandPID muid |
@@ -184,17 +205,21 @@ chooseResourceName state k addr desired = do | |||
184 | ) | 205 | ) |
185 | muid | 206 | muid |
186 | 207 | ||
208 | forClient :: PresenceState | ||
209 | -> ConnectionKey -> IO b -> (ClientState -> IO b) -> IO b | ||
187 | forClient state k fallback f = do | 210 | forClient state k fallback f = do |
188 | mclient <- atomically $ do | 211 | mclient <- atomically $ do |
189 | cs <- readTVar (clients state) | 212 | cs <- readTVar (clients state) |
190 | return $ Map.lookup k cs | 213 | return $ Map.lookup k cs |
191 | maybe fallback f mclient | 214 | maybe fallback f mclient |
192 | 215 | ||
216 | tellClientHisName :: PresenceState -> ConnectionKey -> IO Text | ||
193 | tellClientHisName state k = forClient state k fallback go | 217 | tellClientHisName state k = forClient state k fallback go |
194 | where | 218 | where |
195 | fallback = localJID "nobody" "fallback" | 219 | fallback = localJID "nobody" "fallback" |
196 | go client = localJID (clientUser client) (clientResource client) | 220 | go client = localJID (clientUser client) (clientResource client) |
197 | 221 | ||
222 | toMapUnit :: Ord k => [k] -> Map k () | ||
198 | toMapUnit xs = Map.fromList $ map (,()) xs | 223 | toMapUnit xs = Map.fromList $ map (,()) xs |
199 | 224 | ||
200 | resolveAllPeers :: [Text] -> IO (Map SockAddr ()) | 225 | resolveAllPeers :: [Text] -> IO (Map SockAddr ()) |
@@ -237,6 +262,8 @@ rosterGetSubscribers = rosterGetStuff ConfigFiles.getSubscribers | |||
237 | data Conn = Conn { connChan :: TChan Stanza | 262 | data Conn = Conn { connChan :: TChan Stanza |
238 | , auxAddr :: SockAddr } | 263 | , auxAddr :: SockAddr } |
239 | 264 | ||
265 | configText :: Functor f => | ||
266 | (L.ByteString -> f [L.ByteString]) -> Text -> f [Text] | ||
240 | configText what u = fmap (map lazyByteStringToText) | 267 | configText what u = fmap (map lazyByteStringToText) |
241 | $ what (textToLazyByteString u) | 268 | $ what (textToLazyByteString u) |
242 | 269 | ||
@@ -245,6 +272,8 @@ getBuddies' = configText ConfigFiles.getBuddies | |||
245 | getSolicited' :: Text -> IO [Text] | 272 | getSolicited' :: Text -> IO [Text] |
246 | getSolicited' = configText ConfigFiles.getSolicited | 273 | getSolicited' = configText ConfigFiles.getSolicited |
247 | 274 | ||
275 | sendProbesAndSolicitations :: PresenceState | ||
276 | -> ConnectionKey -> SockAddr -> TChan Stanza -> IO () | ||
248 | sendProbesAndSolicitations state k laddr chan = do | 277 | sendProbesAndSolicitations state k laddr chan = do |
249 | -- get all buddies & solicited matching k for all users | 278 | -- get all buddies & solicited matching k for all users |
250 | xs <- runTraversableT $ do | 279 | xs <- runTraversableT $ do |
@@ -279,6 +308,7 @@ sendProbesAndSolicitations state k laddr chan = do | |||
279 | atomically $ writeTChan chan stanza | 308 | atomically $ writeTChan chan stanza |
280 | -- reverse xs `seq` return () | 309 | -- reverse xs `seq` return () |
281 | 310 | ||
311 | newConn :: PresenceState -> ConnectionKey -> SockAddr -> TChan Stanza -> IO () | ||
282 | newConn state k addr outchan = do | 312 | newConn state k addr outchan = do |
283 | atomically $ modifyTVar' (keyToChan state) | 313 | atomically $ modifyTVar' (keyToChan state) |
284 | $ Map.insert k Conn { connChan = outchan | 314 | $ Map.insert k Conn { connChan = outchan |
@@ -286,12 +316,15 @@ newConn state k addr outchan = do | |||
286 | when (isPeerKey k) | 316 | when (isPeerKey k) |
287 | $ sendProbesAndSolicitations state k addr outchan | 317 | $ sendProbesAndSolicitations state k addr outchan |
288 | 318 | ||
319 | delclient :: (Alternative m, Monad m) => | ||
320 | ConnectionKey -> m LocalPresence -> m LocalPresence | ||
289 | delclient k mlp = do | 321 | delclient k mlp = do |
290 | lp <- mlp | 322 | lp <- mlp |
291 | let nc = Map.delete k $ networkClients lp | 323 | let nc = Map.delete k $ networkClients lp |
292 | guard $ not (Map.null nc) | 324 | guard $ not (Map.null nc) |
293 | return $ lp { networkClients = nc } | 325 | return $ lp { networkClients = nc } |
294 | 326 | ||
327 | eofConn :: PresenceState -> ConnectionKey -> IO () | ||
295 | eofConn state k = do | 328 | eofConn state k = do |
296 | atomically $ modifyTVar' (keyToChan state) $ Map.delete k | 329 | atomically $ modifyTVar' (keyToChan state) $ Map.delete k |
297 | case k of | 330 | case k of |
@@ -325,9 +358,6 @@ rewriteJIDForClient1 jid = do | |||
325 | return $ Just ((n,h',r), addr) | 358 | return $ Just ((n,h',r), addr) |
326 | -} | 359 | -} |
327 | 360 | ||
328 | todo = error "Unimplemented" | ||
329 | |||
330 | |||
331 | -- | for example: 2001-db8-85a3-8d3-1319-8a2e-370-7348.ipv6-literal.net | 361 | -- | for example: 2001-db8-85a3-8d3-1319-8a2e-370-7348.ipv6-literal.net |
332 | ip6literal :: Text -> Text | 362 | ip6literal :: Text -> Text |
333 | ip6literal addr = Text.map dash addr <> ".ipv6-literal.net" | 363 | ip6literal addr = Text.map dash addr <> ".ipv6-literal.net" |
@@ -351,6 +381,7 @@ rewriteJIDForClient laddr jid buds = do | |||
351 | else peerKeyToResolvedName buds (PeerKey addr) | 381 | else peerKeyToResolvedName buds (PeerKey addr) |
352 | return (mine,(n,h',r)) | 382 | return (mine,(n,h',r)) |
353 | 383 | ||
384 | sameAddress :: SockAddr -> SockAddr -> Bool | ||
354 | sameAddress laddr addr = laddr `withPort` 0 == addr `withPort` 0 | 385 | sameAddress laddr addr = laddr `withPort` 0 == addr `withPort` 0 |
355 | 386 | ||
356 | peerKeyToResolvedName :: [Text] -> ConnectionKey -> IO Text | 387 | peerKeyToResolvedName :: [Text] -> ConnectionKey -> IO Text |
@@ -373,10 +404,12 @@ multiplyJIDForClient laddr jid = do | |||
373 | return (mine,map (\h' -> (n,h',r)) names) | 404 | return (mine,map (\h' -> (n,h',r)) names) |
374 | 405 | ||
375 | 406 | ||
407 | addrTextToKey :: Text -> IO (Maybe ConnectionKey) | ||
376 | addrTextToKey h = do | 408 | addrTextToKey h = do |
377 | maddr <- parseAddress (strip_brackets h) | 409 | maddr <- parseAddress (strip_brackets h) |
378 | return (fmap PeerKey maddr) | 410 | return (fmap PeerKey maddr) |
379 | 411 | ||
412 | guardPortStrippedAddress :: Text -> SockAddr -> IO (Maybe ()) | ||
380 | guardPortStrippedAddress h laddr = do | 413 | guardPortStrippedAddress h laddr = do |
381 | maddr <- fmap (fmap (`withPort` 0)) $ parseAddress (strip_brackets h) | 414 | maddr <- fmap (fmap (`withPort` 0)) $ parseAddress (strip_brackets h) |
382 | let laddr' = laddr `withPort` 0 | 415 | let laddr' = laddr `withPort` 0 |
@@ -398,6 +431,7 @@ rewriteJIDForPeer jid = do | |||
398 | to' = unsplitJID (n,h',r) | 431 | to' = unsplitJID (n,h',r) |
399 | in (to',addr) | 432 | in (to',addr) |
400 | 433 | ||
434 | deliverToConsole :: PresenceState -> IO () -> Stanza -> IO () | ||
401 | deliverToConsole state fail msg = do | 435 | deliverToConsole state fail msg = do |
402 | putStrLn $ "TODO: deliver to console" | 436 | putStrLn $ "TODO: deliver to console" |
403 | did1 <- writeActiveTTY (consoleWriter state) msg | 437 | did1 <- writeActiveTTY (consoleWriter state) msg |
@@ -405,6 +439,10 @@ deliverToConsole state fail msg = do | |||
405 | if not (did1 || did2) then fail else return () | 439 | if not (did1 || did2) then fail else return () |
406 | 440 | ||
407 | -- | deliver <message/> or error stanza | 441 | -- | deliver <message/> or error stanza |
442 | deliverMessage :: PresenceState | ||
443 | -> IO () | ||
444 | -> StanzaWrap (LockedChan Event) | ||
445 | -> IO () | ||
408 | deliverMessage state fail msg = | 446 | deliverMessage state fail msg = |
409 | case stanzaOrigin msg of | 447 | case stanzaOrigin msg of |
410 | NetworkOrigin senderk@(ClientKey {}) _ -> do | 448 | NetworkOrigin senderk@(ClientKey {}) _ -> do |
@@ -465,25 +503,30 @@ deliverMessage state fail msg = | |||
465 | chan | 503 | chan |
466 | 504 | ||
467 | 505 | ||
506 | setClientFlag :: PresenceState -> ConnectionKey -> Int8 -> IO () | ||
468 | setClientFlag state k flag = | 507 | setClientFlag state k flag = |
469 | atomically $ do | 508 | atomically $ do |
470 | cmap <- readTVar (clients state) | 509 | cmap <- readTVar (clients state) |
471 | flip (maybe $ return ()) (Map.lookup k cmap) $ \client -> do | 510 | flip (maybe $ return ()) (Map.lookup k cmap) $ \client -> do |
472 | setClientFlag0 client flag | 511 | setClientFlag0 client flag |
473 | 512 | ||
513 | setClientFlag0 :: ClientState -> Int8 -> STM () | ||
474 | setClientFlag0 client flag = | 514 | setClientFlag0 client flag = |
475 | modifyTVar' (clientFlags client) (\flgs -> flgs .|. flag) | 515 | modifyTVar' (clientFlags client) (\flgs -> flgs .|. flag) |
476 | 516 | ||
517 | informSentRoster :: PresenceState -> ConnectionKey -> IO () | ||
477 | informSentRoster state k = do | 518 | informSentRoster state k = do |
478 | setClientFlag state k cf_interested | 519 | setClientFlag state k cf_interested |
479 | 520 | ||
480 | 521 | ||
522 | subscribedPeers :: Text -> IO [SockAddr] | ||
481 | subscribedPeers user = do | 523 | subscribedPeers user = do |
482 | jids <- configText ConfigFiles.getSubscribers user | 524 | jids <- configText ConfigFiles.getSubscribers user |
483 | let hosts = map ((\(_,h,_)->h) . splitJID) jids | 525 | let hosts = map ((\(_,h,_)->h) . splitJID) jids |
484 | fmap Map.keys $ resolveAllPeers hosts | 526 | fmap Map.keys $ resolveAllPeers hosts |
485 | 527 | ||
486 | -- | this JID is suitable for peers, not clients. | 528 | -- | this JID is suitable for peers, not clients. |
529 | clientJID :: Conn -> ClientState -> Text | ||
487 | clientJID con client = unsplitJID ( Just $ clientUser client | 530 | clientJID con client = unsplitJID ( Just $ clientUser client |
488 | , addrToText $ auxAddr con | 531 | , addrToText $ auxAddr con |
489 | , Just $ clientResource client) | 532 | , Just $ clientResource client) |
@@ -491,10 +534,17 @@ clientJID con client = unsplitJID ( Just $ clientUser client | |||
491 | -- | Send presence notification to subscribed peers. | 534 | -- | Send presence notification to subscribed peers. |
492 | -- Note that a full JID from address will be added to the | 535 | -- Note that a full JID from address will be added to the |
493 | -- stanza if it is not present. | 536 | -- stanza if it is not present. |
537 | informClientPresence :: PresenceState | ||
538 | -> ConnectionKey -> StanzaWrap (LockedChan Event) -> IO () | ||
494 | informClientPresence state k stanza = do | 539 | informClientPresence state k stanza = do |
495 | forClient state k (return ()) $ \client -> do | 540 | forClient state k (return ()) $ \client -> do |
496 | informClientPresence0 state (Just k) client stanza | 541 | informClientPresence0 state (Just k) client stanza |
497 | 542 | ||
543 | informClientPresence0 :: PresenceState | ||
544 | -> Maybe ConnectionKey | ||
545 | -> ClientState | ||
546 | -> StanzaWrap (LockedChan Event) | ||
547 | -> IO () | ||
498 | informClientPresence0 state mbk client stanza = do | 548 | informClientPresence0 state mbk client stanza = do |
499 | dup <- cloneStanza stanza | 549 | dup <- cloneStanza stanza |
500 | atomically $ writeTVar (clientStatus client) $ Just dup | 550 | atomically $ writeTVar (clientStatus client) $ Just dup |
@@ -516,6 +566,10 @@ informClientPresence0 state mbk client stanza = do | |||
516 | , stanzaTo = mto } | 566 | , stanzaTo = mto } |
517 | (connChan con) | 567 | (connChan con) |
518 | 568 | ||
569 | informPeerPresence :: PresenceState | ||
570 | -> ConnectionKey | ||
571 | -> StanzaWrap (LockedChan Event) | ||
572 | -> IO () | ||
519 | informPeerPresence state k stanza = do | 573 | informPeerPresence state k stanza = do |
520 | -- Presence must indicate full JID with resource... | 574 | -- Presence must indicate full JID with resource... |
521 | putStrLn $ "xmppInformPeerPresence checking from address..." | 575 | putStrLn $ "xmppInformPeerPresence checking from address..." |
@@ -579,6 +633,8 @@ informPeerPresence state k stanza = do | |||
579 | sendModifiedStanzaToClient (dup { stanzaFrom=Just from' }) | 633 | sendModifiedStanzaToClient (dup { stanzaFrom=Just from' }) |
580 | (connChan con) | 634 | (connChan con) |
581 | 635 | ||
636 | answerProbe :: PresenceState | ||
637 | -> Maybe Text -> ConnectionKey -> TChan Stanza -> IO () | ||
582 | answerProbe state mto k chan = do | 638 | answerProbe state mto k chan = do |
583 | -- putStrLn $ "answerProbe! " ++ show (stanzaType stanza) | 639 | -- putStrLn $ "answerProbe! " ++ show (stanzaType stanza) |
584 | ktc <- atomically $ readTVar (keyToChan state) | 640 | ktc <- atomically $ readTVar (keyToChan state) |
@@ -634,6 +690,7 @@ answerProbe state mto k chan = do | |||
634 | pstanza <- makePresenceStanza "jabber:server" (Just jid) Offline | 690 | pstanza <- makePresenceStanza "jabber:server" (Just jid) Offline |
635 | atomically $ writeTChan (connChan conn) pstanza | 691 | atomically $ writeTChan (connChan conn) pstanza |
636 | 692 | ||
693 | sendCachedPresence :: PresenceState -> ConnectionKey -> IO () | ||
637 | sendCachedPresence state k = do | 694 | sendCachedPresence state k = do |
638 | forClient state k (return ()) $ \client -> do | 695 | forClient state k (return ()) $ \client -> do |
639 | rbp <- atomically $ readTVar (remotesByPeer state) | 696 | rbp <- atomically $ readTVar (remotesByPeer state) |
@@ -671,12 +728,27 @@ sendCachedPresence state k = do | |||
671 | -- send local buddies. | 728 | -- send local buddies. |
672 | return () | 729 | return () |
673 | 730 | ||
731 | addToRosterFile :: (MonadPlus t, Traversable t) => | ||
732 | (L.ByteString -> (L.ByteString -> IO (t L.ByteString)) | ||
733 | -> Maybe L.ByteString | ||
734 | -> t1) | ||
735 | -> Text -> Text -> [SockAddr] -> t1 | ||
674 | addToRosterFile doit whose to addrs = | 736 | addToRosterFile doit whose to addrs = |
675 | modifyRosterFile doit whose to addrs True | 737 | modifyRosterFile doit whose to addrs True |
676 | 738 | ||
739 | removeFromRosterFile :: (MonadPlus t, Traversable t) => | ||
740 | (L.ByteString -> (L.ByteString -> IO (t L.ByteString)) | ||
741 | -> Maybe L.ByteString | ||
742 | -> t1) | ||
743 | -> Text -> Text -> [SockAddr] -> t1 | ||
677 | removeFromRosterFile doit whose to addrs = | 744 | removeFromRosterFile doit whose to addrs = |
678 | modifyRosterFile doit whose to addrs False | 745 | modifyRosterFile doit whose to addrs False |
679 | 746 | ||
747 | modifyRosterFile :: (Traversable t, MonadPlus t) => | ||
748 | (L.ByteString -> (L.ByteString -> IO (t L.ByteString)) | ||
749 | -> Maybe L.ByteString | ||
750 | -> t1) | ||
751 | -> Text -> Text -> [SockAddr] -> Bool -> t1 | ||
680 | modifyRosterFile doit whose to addrs bAdd = do | 752 | modifyRosterFile doit whose to addrs bAdd = do |
681 | let (mu,_,_) = splitJID to | 753 | let (mu,_,_) = splitJID to |
682 | cmp jid = runTraversableT $ do | 754 | cmp jid = runTraversableT $ do |
@@ -769,6 +841,8 @@ resolvedFromRoster doit u = do | |||
769 | addr <- liftMT $ fmap nub $ resolvePeer h | 841 | addr <- liftMT $ fmap nub $ resolvePeer h |
770 | return (mu,PeerKey addr) | 842 | return (mu,PeerKey addr) |
771 | 843 | ||
844 | clientCons :: PresenceState | ||
845 | -> Map ConnectionKey t -> Text -> IO [(t, ClientState)] | ||
772 | clientCons state ktc u = do | 846 | clientCons state ktc u = do |
773 | mlp <- atomically $ do | 847 | mlp <- atomically $ do |
774 | cmap <- readTVar $ clientsByUser state | 848 | cmap <- readTVar $ clientsByUser state |
@@ -848,6 +922,11 @@ peerSubscriptionRequest state fail k stanza chan = do | |||
848 | chan | 922 | chan |
849 | 923 | ||
850 | 924 | ||
925 | clientInformSubscription :: PresenceState | ||
926 | -> IO () | ||
927 | -> ConnectionKey | ||
928 | -> StanzaWrap (LockedChan Event) | ||
929 | -> IO () | ||
851 | clientInformSubscription state fail k stanza = do | 930 | clientInformSubscription state fail k stanza = do |
852 | forClient state k fail $ \client -> do | 931 | forClient state k fail $ \client -> do |
853 | flip (maybe fail) (stanzaTo stanza) $ \to -> do | 932 | flip (maybe fail) (stanzaTo stanza) $ \to -> do |
@@ -907,6 +986,11 @@ clientInformSubscription state fail k stanza = do | |||
907 | (connChan con) | 986 | (connChan con) |
908 | answerProbe state (Just from) pk (connChan con) | 987 | answerProbe state (Just from) pk (connChan con) |
909 | 988 | ||
989 | peerInformSubscription :: PresenceState | ||
990 | -> IO () | ||
991 | -> ConnectionKey | ||
992 | -> StanzaWrap (LockedChan Event) | ||
993 | -> IO () | ||
910 | peerInformSubscription state fail k stanza = do | 994 | peerInformSubscription state fail k stanza = do |
911 | putStrLn $ "TODO: peerInformSubscription" | 995 | putStrLn $ "TODO: peerInformSubscription" |
912 | -- remove from solicited | 996 | -- remove from solicited |
@@ -957,6 +1041,7 @@ peerInformSubscription state fail k stanza = do | |||
957 | , stanzaTo = Just to' } | 1041 | , stanzaTo = Just to' } |
958 | chan | 1042 | chan |
959 | 1043 | ||
1044 | main :: IO () | ||
960 | main = runResourceT $ do | 1045 | main = runResourceT $ do |
961 | args <- liftIO getArgs | 1046 | args <- liftIO getArgs |
962 | let verbosity = getSum $ flip foldMap args $ \case | 1047 | let verbosity = getSum $ flip foldMap args $ \case |