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 "bot@example.com" 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 Nothing Nothing -- ...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] -> [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 :: Maybe (String, [String]) -> Maybe 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
- iqError :: String -> StanzaPredicate
- iqResult :: String -> StanzaPredicate
- handleVersion :: String -> String -> String -> XMPP ()
- getErrorCode :: XMLElem -> Integer
- hasNodeName :: String -> StanzaPredicate
- getMessageStamp :: XMLElem -> Maybe String
- getJidRes :: XMLElem -> (String, String)
- cdata :: XMLElem -> String
- cdata' :: Maybe XMLElem -> Maybe String
- getUsername :: String -> String
- getResource :: String -> String
- getBareJid :: String -> String
- startAuth :: String -> String -> String -> String -> XMPP Integer
- data TCPConnection
- openStream :: String -> IO TCPConnection
- getStreamStart :: TCPConnection -> IO XMLElem
- class XMPPConnection c where
- getStanzas :: c -> IO [XMLElem]
- sendStanza :: c -> XMLElem -> IO ()
- closeConnection :: c -> IO ()
- data RosterItem = RosterItem {
- itemName :: String
- itemJid :: String
- itemSubscription :: Subscription
- itemGroups :: [String]
- data Subscription
- getRoster :: XMPP [RosterItem]
- data Presence
- = Available Status
- | Unavailable Status
- | Subscribe
- | Subscribed
- | Unsubscribe
- | Unsubscribed
- | Probe
- | Error
- data Status = Status StatusType [String]
- data StatusType
- = StatusOnline
- | StatusAway
- | StatusChat
- | StatusDND
- | StatusXA
- | StatusOffline
- doPresence :: XMLElem -> Presence
- doStatus :: XMLElem -> Status
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.
runXMPP :: XMPPConnection c => c -> XMPP () -> IO ()Source
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.
sendStanza :: XMLElem -> XMPP ()Source
Send an XMPP stanza.
:: StanzaPredicate | Stanza predicate. |
-> StanzaHandler | Stanza handler. |
-> Bool | 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.
waitForStanza :: StanzaPredicate -> XMPP XMLElemSource
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 runXMPP
exit.
type StanzaPredicate = XMLElem -> BoolSource
A stanza predicate.
type StanzaHandler = XMLElem -> XMPP ()Source
A handler function for a stanza.
XML functions
A data structure representing an XML element.
xmlPath :: [String] -> XMLElem -> Maybe XMLElemSource
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.
xmlToString :: Bool -> XMLElem -> StringSource
Convert the tag back to XML. If the first parameter is true, close the tag.
Stanza manipulation
:: String | JID of recipient |
-> String | Type of IQ, either "get" or "set" |
-> [XMLElem] | Payload elements |
-> XMPP String | ID of sent stanza |
Send an IQ request, returning the randomly generated ID.
:: String | JID of recipient |
-> String | Type of IQ, either "get" or "set" |
-> [XMLElem] | Payload elements |
-> XMPP XMLElem | Response stanza |
Send an IQ request and wait for the response, without blocking other activity.
hasBody :: StanzaPredicateSource
Return true if the message stanza has body text.
getMessageBody :: XMLElem -> Maybe StringSource
Get the body text of the message stanza, if any.
Send an ordinary "chat" type message.
sendPresence :: Maybe (String, [String]) -> Maybe Integer -> XMPP ()Source
Send ordinary online presence.
:: String | Attribute name |
-> (String -> Bool) | Attribute value predicate |
-> StanzaPredicate |
Apply the predicate to the named attribute. Return false if the tag has no such attribute.
isMessage :: StanzaPredicateSource
Return true if the tag is a message stanza.
isPresence :: StanzaPredicateSource
Return true if the tag is a presence stanza.
Return true if the tag is an IQ stanza.
isChat :: StanzaPredicateSource
Return true if the tag is a chat message.
isFrom :: String -> StanzaPredicateSource
Return true if the stanza is from the given JID.
iqXmlns :: String -> StanzaPredicateSource
Return true if the stanza is an IQ stanza in the given namespace. FIXME: query node not nessesary the first node in the iq stanza.
iqGet :: String -> StanzaPredicateSource
Return true if the stanza is a "get" request in the given namespace.
iqSet :: String -> StanzaPredicateSource
Return true if the stanza is a "set" request in the given namespace.
iqError :: String -> StanzaPredicateSource
Return true if the stanza is a "error" request in the given namespace.
iqResult :: String -> StanzaPredicateSource
Return true if the stanza is a "result" request in the given namespace.
Establish a handler for answering to version requests with the given information. See XEP-0092: Software Version.
getErrorCode :: XMLElem -> IntegerSource
Return stanza's error code or -1 (if can't parse error node). Zero if no error.
hasNodeName :: String -> StanzaPredicateSource
Return true if the tag has the given name.
getMessageStamp :: XMLElem -> Maybe StringSource
Get the stamp of message, if has any.
JID functions
getUsername :: String -> StringSource
Get username part of JID, i.e. the part before the @ sign.
Return ""
if the JID contains no @ sign.
getResource :: String -> StringSource
Get resource part of JID, i.e. the part after /.
Return ""
if the JID has no resource.
getBareJid :: String -> StringSource
Get the bare JID, i.e. everything except the resource.
Authentication
:: String | Username (part before @ in JID) |
-> String | Server (part after @ in JID) |
-> String | Password |
-> String | Resource (unique identifier for this connection) |
-> XMPP Integer | Error number. Zero if authentication succeeded. |
Non-SASL authentication, following XEP-0078.
TCP connections
openStream :: String -> IO TCPConnectionSource
Open a TCP connection to the named server, port 5222 (or others found in SRV), and send a stream header.
getStreamStart :: TCPConnection -> IO XMLElemSource
Get the stream header that the server sent. This needs to be called before doing anything else with the stream.
Abstract connections
class XMPPConnection c whereSource
A class for various kinds of XMPP connections.
getStanzas :: c -> IO [XMLElem]Source
Get incoming stanzas from the connection.
sendStanza :: c -> XMLElem -> IO ()Source
Send a stanza on the connection.
closeConnection :: c -> IO ()Source
Close the connection.
Roster management
data RosterItem Source
RosterItem | |
|
doPresence :: XMLElem -> PresenceSource
Read presence stanza.