-- |Implementation of Multi-User Chat, according to XEP-0045. This -- API needs more thought and will change. module Network.XMPP.MUC where import Network.XMPP -- |Return true if the stanza is from a JID whose \"username\@server\" -- part matches the given string. matchesBare :: String -> StanzaPredicate matchesBare bare = attributeMatches "from" ((==bare).getBareJid) -- |Join groupchat. joinGroupchat :: String -- ^Nickname to use -> String -- ^JID of room -> Maybe String -- ^Room password -> XMPP () joinGroupchat nick room password = do sendStanza $ XML "presence" [("to",room++"/"++nick)] [XML "x" [("xmlns","http://jabber.org/protocol/muc")] passNode] where passNode = maybe [] (\pass -> [XML "password" [] [CData pass]]) password -- |Leave groupchat. leaveGroupchat :: String -> XMPP () leaveGroupchat room = sendStanza $ XML "presence" [("to",room),("type","unavailable")] [] -- |Return true if the stanza is a message of type \"groupchat\". isGroupchatMessage :: StanzaPredicate isGroupchatMessage = isMessage `conj` attributeMatches "type" (=="groupchat") -- |Return true if the stanza is a private message in the named room. isGroupchatPrivmsg :: String -> StanzaPredicate isGroupchatPrivmsg room = matchesBare room `conj` attributeMatches "type" (=="chat") `conj` attributeMatches "from" ((/="") . getResource) -- |Send a groupchat message. sendGroupchatMessage :: String -- ^JID of chat room -> String -- ^Text of message -> XMPP () sendGroupchatMessage room body = sendStanza $ XML "message" [("to",room), ("type","groupchat")] [XML "body" [] [CData body]] -- |Send a private message in a chat room. sendGroupchatPrivateMessage :: String -- ^Nick of recipient -> String -- ^JID of chat room -> String -- ^Text of message -> XMPP () sendGroupchatPrivateMessage nick room body = sendStanza $ XML "message" [("to",room++"/"++nick), ("type","chat")] [XML "body" [] [CData body]] --- Subject getMessageSubject :: XMLElem -> Maybe String getMessageSubject = getCdata . maybe (XML [] [] []) id . xmlPath ["subject"] --- Occupants -- | Occupant data strucuture. data Occupant = Occupant { occRole :: Role , occAffiliation :: Affiliation , occNick :: String , occJid :: Maybe String } data Role = RModerator | RParticipant | RNone | RVisitor data Affiliation = AOwner | AAdmin | AMember | ANone -- | Create occupant from stanza. -- TODO: kick/ban/change status//change nick/etc parse doOccupant :: XMLElem -> Occupant doOccupant stanza = Occupant role aff nick jid where items = xmlPath' ["x", "item"] [stanza] item | length items == 0 = XML [] [] [] | otherwise = head items role = case getAttr "role" item of Just "moderator" -> RModerator Just "participant" -> RParticipant Just "visitor" -> RVisitor _ -> RNone aff = case getAttr "affiliation" item of Just "owner" -> AOwner Just "admin" -> AAdmin Just "member" -> AMember _ -> ANone nick = snd $ getJidRes stanza jid = getAttr "jid" item -- | Handler for groupchat events (join/leave/kicks/bans/etc). isGroupchatPresence :: StanzaPredicate isGroupchatPresence stanza = (isPresence stanza) && (not $ null xs') where xs = xmlPath' ["x"] [stanza] xs' = filter (attributeMatches "xmlns" (=="http://jabber.org/protocol/muc#user")) xs