summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Presence/Presence.hs5
-rw-r--r--Presence/XMPPServer.hs102
2 files changed, 84 insertions, 23 deletions
diff --git a/Presence/Presence.hs b/Presence/Presence.hs
index 224d3282..7a784fa1 100644
--- a/Presence/Presence.hs
+++ b/Presence/Presence.hs
@@ -170,6 +170,11 @@ presenceHooks state verbosity mclient mpeer = XMPPServerParameters
170 , xmppPeerInformSubscription = peerInformSubscription state 170 , xmppPeerInformSubscription = peerInformSubscription state
171 , xmppVerbosity = return verbosity 171 , xmppVerbosity = return verbosity
172 , xmppGroupChat = Map.singleton "chat" MUC 172 , xmppGroupChat = Map.singleton "chat" MUC
173 { mucRoomList = return [("testroom",Just "testroom")]
174 , mucRoomOccupants = \case
175 "testroom" -> return [("fakeperson",Nothing)]
176 _ -> return []
177 }
173 , xmppClientBind = mclient 178 , xmppClientBind = mclient
174 , xmppPeerBind = mpeer 179 , xmppPeerBind = mpeer
175 } 180 }
diff --git a/Presence/XMPPServer.hs b/Presence/XMPPServer.hs
index bc64ecd8..218e60e0 100644
--- a/Presence/XMPPServer.hs
+++ b/Presence/XMPPServer.hs
@@ -86,6 +86,7 @@ import Data.Conduit.ByteString.Builder (builderToByteStringFlush)
86import Data.Conduit.Blaze (builderToByteStringFlush) 86import Data.Conduit.Blaze (builderToByteStringFlush)
87#endif 87#endif
88 88
89import Control.Arrow
89import Control.Concurrent.STM.Util 90import Control.Concurrent.STM.Util
90import DNSCache (withPort) 91import DNSCache (withPort)
91import qualified Text.XML.Stream.Render as XML hiding (content) 92import qualified Text.XML.Stream.Render as XML hiding (content)
@@ -120,7 +121,8 @@ newtype Local a = Local a deriving (Eq,Ord,Show)
120newtype Remote a = Remote a deriving (Eq,Ord,Show) 121newtype Remote a = Remote a deriving (Eq,Ord,Show)
121 122
122data MUC = MUC 123data MUC = MUC
123 { -- todo 124 { mucRoomList :: IO [(Text,Maybe Text)]
125 , mucRoomOccupants :: Text -> IO [(Text,Maybe Text)]
124 } 126 }
125 127
126data XMPPServerParameters = 128data XMPPServerParameters =
@@ -655,8 +657,15 @@ makeInfo mid from mto = concat
655 , EventEndElement "{jabber:client}iq" ] 657 , EventEndElement "{jabber:client}iq" ]
656 ] 658 ]
657 659
658makeMUCInfo :: Maybe Text -> Text -> Maybe Text -> [Event] 660features :: [Text] -> [XML.Event]
659makeMUCInfo mid from mto = concat 661features fs = do
662 t <- fs
663 [ EventBeginElement "{http://jabber.org/protocol/disco#info}feature"
664 [("var",[ContentText t])],
665 EventEndElement "{http://jabber.org/protocol/disco#info}feature" ]
666
667makeMUCInfo :: Maybe Text -> Text -> Maybe Text -> [XML.Event] -> [XML.Event]
668makeMUCInfo mid from mto fs = concat
660 [ [ EventBeginElement "{jabber:client}iq" 669 [ [ EventBeginElement "{jabber:client}iq"
661 $ consid mid $ maybe id (\to -> (("to", [ContentText to]) :)) mto 670 $ consid mid $ maybe id (\to -> (("to", [ContentText to]) :)) mto
662 [("from", [ContentText from]) 671 [("from", [ContentText from])
@@ -677,7 +686,7 @@ makeMUCInfo mid from mto = concat
677 , EventBeginElement "{http://jabber.org/protocol/disco#info}feature" 686 , EventBeginElement "{http://jabber.org/protocol/disco#info}feature"
678 [("var",[ContentText "http://jabber.org/protocol/muc"])] 687 [("var",[ContentText "http://jabber.org/protocol/muc"])]
679 , EventEndElement "{http://jabber.org/protocol/disco#info}feature" ] 688 , EventEndElement "{http://jabber.org/protocol/disco#info}feature" ]
680 , [] 689 , fs
681 , [ EventEndElement "{http://jabber.org/protocol/disco#info}query" 690 , [ EventEndElement "{http://jabber.org/protocol/disco#info}query"
682 , EventEndElement "{jabber:client}iq" ] 691 , EventEndElement "{jabber:client}iq" ]
683 ] 692 ]
@@ -1313,6 +1322,29 @@ monitor sv params xmpp = do
1313stanzaTypeString :: StanzaWrap a -> String 1322stanzaTypeString :: StanzaWrap a -> String
1314stanzaTypeString stanza = concat . take 1 . words $ show (stanzaType stanza) 1323stanzaTypeString stanza = concat . take 1 . words $ show (stanzaType stanza)
1315 1324
1325data ServiceMatch a
1326 = NotMe -- ^ Hostname of another server.
1327 | UnknownService Text -- ^ Unknown subdomain of this host.
1328 | Service (Maybe Text) Text a -- ^ A known subdomain of this host. Optionally, a specific room name.
1329 | TopLevelService -- ^ This server's exact hostname.
1330
1331
1332lookupService :: Text -> Map.Map Text a -> Text -> (ServiceMatch a)
1333lookupService me mucs to = case Text.toLower to of
1334 nm | nm == Text.toLower me
1335 -> TopLevelService
1336 nm | let (a0,b) = Text.break (=='.') nm
1337 , Text.drop 1 b == Text.toLower me
1338 , let (a,service) = second (Text.drop 1) $ Text.break (=='@') a0
1339 -> if Text.null service -- No '@' means that variable /a/ is the service.
1340 then case Map.lookup a mucs of
1341 Just muc -> Service Nothing a muc
1342 Nothing -> UnknownService a -- ItemNotFound
1343 else case Map.lookup service mucs of
1344 Just muc -> Service (Just a) service muc
1345 Nothing -> UnknownService service
1346 _ -> NotMe
1347
1316applyStanza :: Server PeerAddress ConnectionData releaseKey Event 1348applyStanza :: Server PeerAddress ConnectionData releaseKey Event
1317 -> TMVar () 1349 -> TMVar ()
1318 -> XMPPServerParameters 1350 -> XMPPServerParameters
@@ -1375,29 +1407,53 @@ applyStanza sv quitVar xmpp stanza = case stanzaOrigin stanza of
1375 enableClientHacks name version replyto 1407 enableClientHacks name version replyto
1376 RequestInfo -> do 1408 RequestInfo -> do
1377 me <- xmppTellMyNameToClient xmpp k 1409 me <- xmppTellMyNameToClient xmpp k
1378 let fail = let query = "{http://jabber.org/protocol/disco#info}info" 1410 let unavail = let query = "{http://jabber.org/protocol/disco#info}info"
1379 reply = iq_service_unavailable (stanzaId stanza) me query 1411 reply = iq_service_unavailable (stanzaId stanza) me query
1380 in sendReply quitVar (Error ServiceUnavailable (head reply)) reply replyto 1412 in (Error ServiceUnavailable (head reply), reply)
1381 case fmap Text.toLower (stanzaTo stanza) of 1413 sto = fromMaybe me (stanzaTo stanza)
1382 Nothing -> fail 1414 let (rtyp,reply) = case lookupService me (xmppGroupChat xmpp) sto of
1383 Just nm | nm == Text.toLower me 1415 NotMe -> unavail
1416 (UnknownService a) -> unavail -- TODO ItemNotFound instead?
1417 (Service Nothing a muc)
1418 -> let reply = makeMUCInfo (stanzaId stanza) (a <> "." <> me) (stanzaFrom stanza) []
1419 in (Info, reply)
1420 (Service (Just room) a muc)
1421 -> let reply = makeMUCInfo (stanzaId stanza) (room <> "@" <> a <> "." <> me) (stanzaFrom stanza)
1422 $ features
1423 [ "http://jabber.org/protocol/muc#stable_id" ]
1424 in (Info, reply)
1425 TopLevelService
1384 -> let reply = makeInfo (stanzaId stanza) me (stanzaFrom stanza) 1426 -> let reply = makeInfo (stanzaId stanza) me (stanzaFrom stanza)
1385 in sendReply quitVar Info reply replyto 1427 in (Info, reply)
1386 Just nm | let (a,b) = Text.break (=='.') nm 1428 sendReply quitVar rtyp reply replyto
1387 , Text.drop 1 b == Text.toLower me
1388 , Just muc <- Map.lookup a (xmppGroupChat xmpp)
1389 -> let reply = makeMUCInfo (stanzaId stanza) (a <> "." <> me) (stanzaFrom stanza)
1390 in sendReply quitVar Info reply replyto
1391 -- TODO ItemNotFound
1392 _ -> fail
1393 RequestItems -> do 1429 RequestItems -> do
1394 -- let query = "{http://jabber.org/protocol/disco#items}query" 1430 -- let query = "{http://jabber.org/protocol/disco#items}query"
1395 me <- xmppTellMyNameToClient xmpp k 1431 me <- xmppTellMyNameToClient xmpp k
1396 let items = do 1432 let unavail = let query = "{http://jabber.org/protocol/disco#info}info"
1397 (name,MUC {}) <- Map.toList $ xmppGroupChat xmpp 1433 reply = iq_service_unavailable (stanzaId stanza) me query
1398 return (name <> "." <> me, Nothing) 1434 in return (Error ServiceUnavailable (head reply), reply)
1399 reply = makeItemList (stanzaId stanza) items me (stanzaFrom stanza) 1435 sto = fromMaybe me (stanzaTo stanza)
1400 sendReply quitVar Items reply replyto 1436 (rtyp,reply) <- case lookupService me (xmppGroupChat xmpp) sto of
1437 NotMe -> unavail
1438 (UnknownService a) -> unavail -- TODO ItemNotFound instead?
1439 (Service Nothing a muc) -> do
1440 items <- map (\(n,m) -> (n <> "@" <> a <> "." <> me, m))
1441 <$> mucRoomList muc
1442 let reply = makeItemList (stanzaId stanza) items (a <> "." <> me) (stanzaFrom stanza)
1443 return (Items, reply)
1444 (Service (Just room) a muc) -> do
1445 items <- map (\(n,m) -> (room <> "@" <> a <> "." <> me <> "/" <> n, m))
1446 <$> mucRoomOccupants muc room
1447 -- Note: I'm assuming 'mucRoomOccupants' returns an empty list for
1448 -- private rooms.
1449 let reply = makeItemList (stanzaId stanza) items (a <> "." <> me) (stanzaFrom stanza)
1450 return (Items, reply)
1451 TopLevelService -> do
1452 let items = do (name,MUC {}) <- Map.toList $ xmppGroupChat xmpp
1453 return (name <> "." <> me, Nothing)
1454 reply = makeItemList (stanzaId stanza) items me (stanzaFrom stanza)
1455 return (Items, reply)
1456 sendReply quitVar rtyp reply replyto
1401 UnrecognizedQuery query -> do 1457 UnrecognizedQuery query -> do
1402 me <- xmppTellMyNameToClient xmpp k 1458 me <- xmppTellMyNameToClient xmpp k
1403 let reply = iq_service_unavailable (stanzaId stanza) me query 1459 let reply = iq_service_unavailable (stanzaId stanza) me query