This library aims to make writing XMPP clients (in particular bots) easy and fun. Here is a small example:
import Network import Network.XMPP -- The bot's JID is "firstname.lastname@example.org" botUsername = "bot" botServer = "example.com" botPassword = "secret" botResource = "bot" main :: IO () main = withSocketsDo $ do -- Connect to server... c <- openStream botServer getStreamStart c runXMPP c $ do -- ...authenticate... startAuth botUsername botServer botPassword botResource sendpresence -- ...and do something. run run :: XMPP () run = do -- Wait for an incoming message... msg <- waitForStanza (isChat `conj` hasBody) let sender = maybe "" id (getAttr "from" msg) len = length $ maybe "" id (getMessageBody msg) -- ...answer... sendMessage sender ("Your message was "++(show len)++" characters long.") -- ...and repeat. run
XMPP is a protocol for streaming XML also known as Jabber. It is described in RFCs 3920 and 3921, and in a series of XMPP Extension Protocols (XEPs). All of this can be found at http://www.xmpp.org.
- data XMPP a
- runXMPP :: XMPPConnection c => c -> XMPP () -> IO ()
- sendStanza :: XMLElem -> XMPP ()
- addHandler :: StanzaPredicate -> StanzaHandler -> Bool -> XMPP ()
- waitForStanza :: StanzaPredicate -> XMPP XMLElem
- quit :: XMPP ()
- type StanzaPredicate = XMLElem -> Bool
- type StanzaHandler = XMLElem -> XMPP ()
- liftIO :: MonadIO m => forall a. IO a -> m a
- data XMLElem
- xmlPath :: [String] -> XMLElem -> Maybe XMLElem
- xmlPath' :: [String] -> [XMLElem] -> Maybe XMLElem
- getAttr :: String -> XMLElem -> Maybe String
- getCdata :: XMLElem -> Maybe String
- allChilds :: XMLElem -> [XMLElem]
- xmlToString :: Bool -> XMLElem -> String
- sendIq :: String -> String -> [XMLElem] -> XMPP String
- sendIqWait :: String -> String -> [XMLElem] -> XMPP XMLElem
- hasBody :: StanzaPredicate
- getMessageBody :: XMLElem -> Maybe String
- sendMessage :: String -> String -> XMPP ()
- sendPresence :: Integer -> XMPP ()
- conj :: (a -> Bool) -> (a -> Bool) -> a -> Bool
- attributeMatches :: String -> (String -> Bool) -> StanzaPredicate
- isMessage :: StanzaPredicate
- isPresence :: StanzaPredicate
- isIq :: StanzaPredicate
- isChat :: StanzaPredicate
- isFrom :: String -> StanzaPredicate
- iqXmlns :: String -> StanzaPredicate
- iqGet :: String -> StanzaPredicate
- iqSet :: String -> StanzaPredicate
- handleVersion :: String -> String -> String -> XMPP ()
- getErrorCode :: XMLElem -> Integer
- hasNodeName :: String -> StanzaPredicate
- getUsername :: String -> String
- getResource :: String -> String
- getBareJid :: String -> String
- startAuth :: String -> String -> String -> String -> Integer -> XMPP Integer
- data TCPConnection
- openStream :: String -> IO TCPConnection
- getStreamStart :: TCPConnection -> IO XMLElem
- class XMPPConnection c where
The XMPP monad
A function in the XMPP monad behaves a bit like a thread in a cooperative threading system: when it decides to wait for more input, it "sleeps", letting other "threads" run, until input matching a certain predicate arrives.
Run a function in the XMPP monad using the given XMPP connection. After that, keep looping as long as there are handlers waiting for incoming stanzas.
Catch more than one stanza?
|-> XMPP ()|
When a stanza matching the predicate arrives, call the given handler. This is analogous to spawning a new thread, except that the "thread" is only run if and when a matching stanza arrives.
Stanza handlers can be one-shot or permanent, as indicated by the third argument.
Suspend execution of current function while waiting for a stanza matching the predicate.
Terminate the loop as soon as the current function exits. This
works by removing all stanza handlers, which makes
A data structure representing an XML element.
|XML String [(String, String)] [XMLElem]|
Tags have a name, a list of attributes, and a list of child elements.
Character data just contains a string.
Follow a "path" of named subtags in an XML tree. For every element in the given list, find the subtag with that name and proceed recursively.
Default xmlPath doesn't find subtag2 if we have tag1subtag1 and tag1subtag2 in xml stanza.
Convert the tag back to XML. If the first parameter is true, close the tag.
JID of recipient
Type of IQ, either "get" or "set"
|-> XMPP String|
ID of sent stanza
Send an IQ request, returning the randomly generated ID.
JID of recipient
Type of IQ, either "get" or "set"
|-> XMPP XMLElem|
Send an IQ request and wait for the response, without blocking other activity.
Send an ordinary "chat" type message.
Apply the predicate to the named attribute. Return false if the tag has no such attribute.
Return true if the stanza is an IQ stanza in the given namespace.
Return true if the stanza is a "get" request in the given namespace.
Return true if the stanza is a "set" request in the given namespace.
Establish a handler for answering to version requests with the given information. See XEP-0092: Software Version.
Return stanza's error code or -1 (if can't parse error node). Zero if no error.
Get username part of JID, i.e. the part before the @ sign.
"" if the JID contains no @ sign.
Get resource part of JID, i.e. the part after /.
"" if the JID has no resource.
Username (part before @ in JID)
Server (part after @ in JID)
Resource (unique identifier for this connection)
|-> XMPP Integer|
Error number. Zero if authentication succeeded.
Non-SASL authentication, following XEP-0078.
Open a TCP connection to the named server, port 5222, and send a stream header. This should really check SRV records.
Get the stream header that the server sent. This needs to be called before doing anything else with the stream.
A class for various kinds of XMPP connections.
Get incoming stanzas from the connection.
Send a stanza on the connection.
Close the connection.