diff options
Diffstat (limited to 'Presence/XMPPServer.hs')
-rw-r--r-- | Presence/XMPPServer.hs | 62 |
1 files changed, 52 insertions, 10 deletions
diff --git a/Presence/XMPPServer.hs b/Presence/XMPPServer.hs index 3a255cdd..912bbf0b 100644 --- a/Presence/XMPPServer.hs +++ b/Presence/XMPPServer.hs | |||
@@ -2,6 +2,7 @@ | |||
2 | {-# LANGUAGE DoAndIfThenElse #-} | 2 | {-# LANGUAGE DoAndIfThenElse #-} |
3 | {-# LANGUAGE ExistentialQuantification #-} | 3 | {-# LANGUAGE ExistentialQuantification #-} |
4 | {-# LANGUAGE FlexibleInstances #-} | 4 | {-# LANGUAGE FlexibleInstances #-} |
5 | {-# LANGUAGE LambdaCase #-} | ||
5 | {-# LANGUAGE MultiWayIf #-} | 6 | {-# LANGUAGE MultiWayIf #-} |
6 | {-# LANGUAGE OverloadedStrings #-} | 7 | {-# LANGUAGE OverloadedStrings #-} |
7 | {-# LANGUAGE RankNTypes #-} | 8 | {-# LANGUAGE RankNTypes #-} |
@@ -71,6 +72,7 @@ import Control.Concurrent.Lifted (forkIO,myThreadId,ThreadId) | |||
71 | import GHC.Conc (labelThread) | 72 | import GHC.Conc (labelThread) |
72 | #endif | 73 | #endif |
73 | import Control.Concurrent.STM | 74 | import Control.Concurrent.STM |
75 | import Data.List hiding ((\\)) | ||
74 | -- import Control.Concurrent.STM.TChan | 76 | -- import Control.Concurrent.STM.TChan |
75 | import Network.SocketLike | 77 | import Network.SocketLike |
76 | import Text.Printf | 78 | import Text.Printf |
@@ -108,6 +110,8 @@ import DebugTag | |||
108 | import Stanza.Build | 110 | import Stanza.Build |
109 | import Stanza.Parse | 111 | import Stanza.Parse |
110 | import Stanza.Types | 112 | import Stanza.Types |
113 | import MUC | ||
114 | import Chat | ||
111 | 115 | ||
112 | -- peerport :: PortNumber | 116 | -- peerport :: PortNumber |
113 | -- peerport = 5269 | 117 | -- peerport = 5269 |
@@ -121,13 +125,6 @@ my_uuid = "154ae29f-98f2-4af4-826d-a40c8a188574" | |||
121 | newtype Local a = Local a deriving (Eq,Ord,Show) | 125 | newtype Local a = Local a deriving (Eq,Ord,Show) |
122 | newtype Remote a = Remote a deriving (Eq,Ord,Show) | 126 | newtype Remote a = Remote a deriving (Eq,Ord,Show) |
123 | 127 | ||
124 | data MUC = MUC | ||
125 | { mucRoomList :: IO [(Text{-room-},Maybe Text{-friendly room name-})] | ||
126 | , mucRoomOccupants :: Text{-room-} -> IO [(Text{-nick-},Maybe Text{-friendly name-})] | ||
127 | , mucReservedNick :: Text{-room-} -> IO (Maybe (Text{-JID-} -> IO (Maybe Text))) | ||
128 | , mucJoinRoom :: Text{-room-} -> Text{-nick-} -> ClientAddress -> Stanza -> IO () | ||
129 | } | ||
130 | |||
131 | data XMPPServerParameters = | 128 | data XMPPServerParameters = |
132 | XMPPServerParameters | 129 | XMPPServerParameters |
133 | { -- | Called when a client requests a resource id. The first Maybe indicates | 130 | { -- | Called when a client requests a resource id. The first Maybe indicates |
@@ -1286,6 +1283,8 @@ monitor sv params xmpp = do | |||
1286 | stanzas <- atomically newTChan | 1283 | stanzas <- atomically newTChan |
1287 | quitVar <- atomically newEmptyTMVar | 1284 | quitVar <- atomically newEmptyTMVar |
1288 | pp_mvar <- newMVar () -- Lock for synchronous pretty-printing of stanzas in log. | 1285 | pp_mvar <- newMVar () -- Lock for synchronous pretty-printing of stanzas in log. |
1286 | joined_rooms <- atomically | ||
1287 | $ newTVar (Map.empty :: Map.Map ClientAddress (Map.Map (Text,Text) (TChan Stanza,JoinedRoom ClientAddress))) | ||
1289 | fix $ \loop -> do | 1288 | fix $ \loop -> do |
1290 | action <- atomically $ foldr1 orElse | 1289 | action <- atomically $ foldr1 orElse |
1291 | [ readTChan chan >>= \((addr,u),e) -> return $ do | 1290 | [ readTChan chan >>= \((addr,u),e) -> return $ do |
@@ -1325,7 +1324,7 @@ monitor sv params xmpp = do | |||
1325 | -} | 1324 | -} |
1326 | dup <- cloneStanza stanza | 1325 | dup <- cloneStanza stanza |
1327 | 1326 | ||
1328 | t <- forkIO $ do applyStanza sv quitVar xmpp stanza | 1327 | t <- forkIO $ do applyStanza sv joined_rooms quitVar xmpp stanza |
1329 | forwardStanza quitVar xmpp stanza | 1328 | forwardStanza quitVar xmpp stanza |
1330 | labelThread t $ "process." ++ stanzaTypeString stanza | 1329 | labelThread t $ "process." ++ stanzaTypeString stanza |
1331 | 1330 | ||
@@ -1347,6 +1346,19 @@ monitor sv params xmpp = do | |||
1347 | liftIO $ takeMVar pp_mvar | 1346 | liftIO $ takeMVar pp_mvar |
1348 | runConduit $ stanzaToConduit dup .| prettyPrint typ | 1347 | runConduit $ stanzaToConduit dup .| prettyPrint typ |
1349 | liftIO $ putMVar pp_mvar () | 1348 | liftIO $ putMVar pp_mvar () |
1349 | , do | ||
1350 | m <- readTVar joined_rooms | ||
1351 | foldr orElse retry $ (`map` (do (k,rs) <- Map.toList m | ||
1352 | i <- Map.toList rs | ||
1353 | return (k,i))) | ||
1354 | $ \(k,((rkey,muckey),(replyto,r))) -> do | ||
1355 | (mine,ChatTransaction no cjid cnick es) <- readRoom k r | ||
1356 | return $ do | ||
1357 | me <- xmppTellMyNameToClient xmpp k | ||
1358 | dput XJabber $ "CHAT " ++ Text.unpack rkey ++ ": <" ++ Text.unpack cnick ++ "> " ++ show es | ||
1359 | forM_ es $ \case | ||
1360 | Join | mine -> sendRoomOccupants muckey me cnick rkey r replyto | ||
1361 | _ -> return () | ||
1350 | ] | 1362 | ] |
1351 | action | 1363 | action |
1352 | loop | 1364 | loop |
@@ -1355,6 +1367,30 @@ monitor sv params xmpp = do | |||
1355 | where | 1367 | where |
1356 | _ = str :: String | 1368 | _ = str :: String |
1357 | 1369 | ||
1370 | sendRoomOccupants :: Text -> Text -> Text -> Text -> JoinedRoom k -> TChan Stanza -> IO () | ||
1371 | sendRoomOccupants a me them room r replyto = do | ||
1372 | let roomjid n = room <> "@" <> a <> "." <> me <> "/" <> n | ||
1373 | xs <- map (\(n,m) -> (roomjid n, m)) | ||
1374 | <$> atomically (roomOccupants $ joinedRoom r) | ||
1375 | let (ys,xs') = partition (\(jid,_) -> jid == roomjid them) xs | ||
1376 | forM_ xs $ \(jid,_) -> do | ||
1377 | stanza <- makePresenceStanzaEx "jabber:client" (Just jid) Available | ||
1378 | [ EventBeginElement "{http://jabber.org/protocol/muc#user}x" [] | ||
1379 | , EventEndElement "{http://jabber.org/protocol/muc#user}x" | ||
1380 | ] | ||
1381 | ioWriteChan replyto stanza | ||
1382 | forM_ ys $ \(jid,_) -> do | ||
1383 | stanza <- makePresenceStanzaEx "jabber:client" (Just jid) Available | ||
1384 | [ EventBeginElement "{http://jabber.org/protocol/muc#user}x" [] | ||
1385 | , EventBeginElement "{http://jabber.org/protocol/muc#user}status" | ||
1386 | [ ("code",[ContentText "110"]) -- self-presence code. | ||
1387 | ] | ||
1388 | , EventEndElement "{http://jabber.org/protocol/muc#user}status" | ||
1389 | , EventEndElement "{http://jabber.org/protocol/muc#user}x" | ||
1390 | ] | ||
1391 | ioWriteChan replyto stanza | ||
1392 | |||
1393 | |||
1358 | stanzaTypeString :: StanzaWrap a -> String | 1394 | stanzaTypeString :: StanzaWrap a -> String |
1359 | stanzaTypeString stanza = concat . take 1 . words $ show (stanzaType stanza) | 1395 | stanzaTypeString stanza = concat . take 1 . words $ show (stanzaType stanza) |
1360 | 1396 | ||
@@ -1382,12 +1418,13 @@ lookupService me mucs to = case Text.toLower to of | |||
1382 | _ -> NotMe | 1418 | _ -> NotMe |
1383 | 1419 | ||
1384 | applyStanza :: Server PeerAddress ConnectionData releaseKey Event | 1420 | applyStanza :: Server PeerAddress ConnectionData releaseKey Event |
1421 | -> TVar (Map.Map ClientAddress (Map.Map (Text,Text) (TChan Stanza,JoinedRoom ClientAddress))) | ||
1385 | -> TMVar () | 1422 | -> TMVar () |
1386 | -> XMPPServerParameters | 1423 | -> XMPPServerParameters |
1387 | -> StanzaWrap (LockedChan Event) | 1424 | -> StanzaWrap (LockedChan Event) |
1388 | -> IO () | 1425 | -> IO () |
1389 | 1426 | ||
1390 | applyStanza sv quitVar xmpp stanza = case stanzaOrigin stanza of | 1427 | applyStanza sv joined_rooms quitVar xmpp stanza = case stanzaOrigin stanza of |
1391 | ClientOrigin k replyto -> | 1428 | ClientOrigin k replyto -> |
1392 | case stanzaType stanza of | 1429 | case stanzaType stanza of |
1393 | RequestResource clientsNameForMe wanted -> do | 1430 | RequestResource clientsNameForMe wanted -> do |
@@ -1446,7 +1483,12 @@ applyStanza sv quitVar xmpp stanza = case stanzaOrigin stanza of | |||
1446 | [ ("by", [ContentText roomjid]) ] | 1483 | [ ("by", [ContentText roomjid]) ] |
1447 | sendReply quitVar (Error JidMalformed (head reply)) reply replyto | 1484 | sendReply quitVar (Error JidMalformed (head reply)) reply replyto |
1448 | Just nick -> do | 1485 | Just nick -> do |
1449 | mucJoinRoom muc room nick k stanza | 1486 | jid <- xmppTellClientHisName xmpp k |
1487 | r <- mucJoinRoom muc jid nick room k -- stanza | ||
1488 | atomically $ do | ||
1489 | jrs <- readTVar joined_rooms | ||
1490 | let m = Map.findWithDefault Map.empty k jrs | ||
1491 | writeTVar joined_rooms $ Map.insert k (Map.insert (room,mucname) (replyto,r) m) jrs | ||
1450 | | otherwise -> do | 1492 | | otherwise -> do |
1451 | -- Handle presence stanza that is not a chatroom join. | 1493 | -- Handle presence stanza that is not a chatroom join. |
1452 | xmppInformClientPresence xmpp k stanza | 1494 | xmppInformClientPresence xmpp k stanza |