summaryrefslogtreecommitdiff
path: root/Presence/XMPPServer.hs
diff options
context:
space:
mode:
Diffstat (limited to 'Presence/XMPPServer.hs')
-rw-r--r--Presence/XMPPServer.hs62
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)
71import GHC.Conc (labelThread) 72import GHC.Conc (labelThread)
72#endif 73#endif
73import Control.Concurrent.STM 74import Control.Concurrent.STM
75import Data.List hiding ((\\))
74-- import Control.Concurrent.STM.TChan 76-- import Control.Concurrent.STM.TChan
75import Network.SocketLike 77import Network.SocketLike
76import Text.Printf 78import Text.Printf
@@ -108,6 +110,8 @@ import DebugTag
108import Stanza.Build 110import Stanza.Build
109import Stanza.Parse 111import Stanza.Parse
110import Stanza.Types 112import Stanza.Types
113import MUC
114import 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"
121newtype Local a = Local a deriving (Eq,Ord,Show) 125newtype Local a = Local a deriving (Eq,Ord,Show)
122newtype Remote a = Remote a deriving (Eq,Ord,Show) 126newtype Remote a = Remote a deriving (Eq,Ord,Show)
123 127
124data 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
131data XMPPServerParameters = 128data 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
1370sendRoomOccupants :: Text -> Text -> Text -> Text -> JoinedRoom k -> TChan Stanza -> IO ()
1371sendRoomOccupants 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
1358stanzaTypeString :: StanzaWrap a -> String 1394stanzaTypeString :: StanzaWrap a -> String
1359stanzaTypeString stanza = concat . take 1 . words $ show (stanzaType stanza) 1395stanzaTypeString 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
1384applyStanza :: Server PeerAddress ConnectionData releaseKey Event 1420applyStanza :: 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
1390applyStanza sv quitVar xmpp stanza = case stanzaOrigin stanza of 1427applyStanza 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