-- Picklers and unpicklers convert Haskell data to XML and XML to Haskell data, -- respectively. By convensions, pickler/unpickler ("PU") function names start -- out with "xp". {-# Language OverloadedStrings, ViewPatterns, NoMonomorphismRestriction #-} {-# OPTIONS_HADDOCK hide #-} module Network.Xmpp.Marshal where import Data.XML.Pickle import Data.XML.Types import Network.Xmpp.Pickle import Network.Xmpp.Types xpStreamStanza :: PU [Node] (Either XmppStreamError Stanza) xpStreamStanza = xpEither xpStreamError xpStanza xpStanza :: PU [Node] Stanza xpStanza = xpAlt stanzaSel [ xpWrap IQRequestS (\(IQRequestS x) -> x) xpIQRequest , xpWrap IQResultS (\(IQResultS x) -> x) xpIQResult , xpWrap IQErrorS (\(IQErrorS x) -> x) xpIQError , xpWrap MessageS (\(MessageS x) -> x) xpMessage , xpWrap MessageErrorS (\(MessageErrorS x) -> x) xpMessageError , xpWrap PresenceS (\(PresenceS x) -> x) xpPresence , xpWrap PresenceErrorS (\(PresenceErrorS x) -> x) xpPresenceError ] where -- Selector for which pickler to execute above. stanzaSel :: Stanza -> Int stanzaSel (IQRequestS _) = 0 stanzaSel (IQResultS _) = 1 stanzaSel (IQErrorS _) = 2 stanzaSel (MessageS _) = 3 stanzaSel (MessageErrorS _) = 4 stanzaSel (PresenceS _) = 5 stanzaSel (PresenceErrorS _) = 6 xpMessage :: PU [Node] (Message) xpMessage = xpWrap (\((tp, qid, from, to, lang), ext) -> Message qid from to lang tp ext) (\(Message qid from to lang tp ext) -> ((tp, qid, from, to, lang), ext)) (xpElem "{jabber:client}message" (xp5Tuple (xpDefault Normal $ xpAttr "type" xpPrim) (xpAttrImplied "id" xpPrim) (xpAttrImplied "from" xpPrim) (xpAttrImplied "to" xpPrim) xpLangTag -- TODO: NS? ) (xpAll xpElemVerbatim) ) xpPresence :: PU [Node] Presence xpPresence = xpWrap (\((qid, from, to, lang, tp), ext) -> Presence qid from to lang tp ext) (\(Presence qid from to lang tp ext) -> ((qid, from, to, lang, tp), ext)) (xpElem "{jabber:client}presence" (xp5Tuple (xpAttrImplied "id" xpPrim) (xpAttrImplied "from" xpPrim) (xpAttrImplied "to" xpPrim) xpLangTag (xpAttrImplied "type" xpPrim) ) (xpAll xpElemVerbatim) ) xpIQRequest :: PU [Node] IQRequest xpIQRequest = xpWrap (\((qid, from, to, lang, tp),body) -> IQRequest qid from to lang tp body) (\(IQRequest qid from to lang tp body) -> ((qid, from, to, lang, tp), body)) (xpElem "{jabber:client}iq" (xp5Tuple (xpAttr "id" xpPrim) (xpAttrImplied "from" xpPrim) (xpAttrImplied "to" xpPrim) xpLangTag ((xpAttr "type" xpPrim)) ) xpElemVerbatim ) xpIQResult :: PU [Node] IQResult xpIQResult = xpWrap (\((qid, from, to, lang, _tp),body) -> IQResult qid from to lang body) (\(IQResult qid from to lang body) -> ((qid, from, to, lang, ()), body)) (xpElem "{jabber:client}iq" (xp5Tuple (xpAttr "id" xpPrim) (xpAttrImplied "from" xpPrim) (xpAttrImplied "to" xpPrim) xpLangTag ((xpAttrFixed "type" "result")) ) (xpOption xpElemVerbatim) ) ---------------------------------------------------------- -- Errors ---------------------------------------------------------- xpErrorCondition :: PU [Node] StanzaErrorCondition xpErrorCondition = xpWrap (\(cond, (), ()) -> cond) (\cond -> (cond, (), ())) (xpElemByNamespace "urn:ietf:params:xml:ns:xmpp-stanzas" xpPrim xpUnit xpUnit ) xpStanzaError :: PU [Node] StanzaError xpStanzaError = xpWrap (\(tp, (cond, txt, ext)) -> StanzaError tp cond txt ext) (\(StanzaError tp cond txt ext) -> (tp, (cond, txt, ext))) (xpElem "{jabber:client}error" (xpAttr "type" xpPrim) (xp3Tuple xpErrorCondition (xpOption $ xpElem "{jabber:client}text" (xpAttrImplied xmlLang xpPrim) (xpContent xpId) ) (xpOption xpElemVerbatim) ) ) xpMessageError :: PU [Node] (MessageError) xpMessageError = xpWrap (\((_, qid, from, to, lang), (err, ext)) -> MessageError qid from to lang err ext) (\(MessageError qid from to lang err ext) -> (((), qid, from, to, lang), (err, ext))) (xpElem "{jabber:client}message" (xp5Tuple (xpAttrFixed "type" "error") (xpAttrImplied "id" xpPrim) (xpAttrImplied "from" xpPrim) (xpAttrImplied "to" xpPrim) (xpAttrImplied xmlLang xpPrim) -- TODO: NS? ) (xp2Tuple xpStanzaError (xpAll xpElemVerbatim)) ) xpPresenceError :: PU [Node] PresenceError xpPresenceError = xpWrap (\((qid, from, to, lang, _),(err, ext)) -> PresenceError qid from to lang err ext) (\(PresenceError qid from to lang err ext) -> ((qid, from, to, lang, ()), (err, ext))) (xpElem "{jabber:client}presence" (xp5Tuple (xpAttrImplied "id" xpPrim) (xpAttrImplied "from" xpPrim) (xpAttrImplied "to" xpPrim) xpLangTag (xpAttrFixed "type" "error") ) (xp2Tuple xpStanzaError (xpAll xpElemVerbatim)) ) xpIQError :: PU [Node] IQError xpIQError = xpWrap (\((qid, from, to, lang, _tp),(err, body)) -> IQError qid from to lang err body) (\(IQError qid from to lang err body) -> ((qid, from, to, lang, ()), (err, body))) (xpElem "{jabber:client}iq" (xp5Tuple (xpAttr "id" xpPrim) (xpAttrImplied "from" xpPrim) (xpAttrImplied "to" xpPrim) xpLangTag ((xpAttrFixed "type" "error")) ) (xp2Tuple xpStanzaError (xpOption xpElemVerbatim)) ) xpStreamError :: PU [Node] XmppStreamError xpStreamError = xpWrap (\((cond,() ,()), txt, el) -> XmppStreamError cond txt el) (\(XmppStreamError cond txt el) ->((cond,() ,()), txt, el)) (xpElemNodes (Name "error" (Just "http://etherx.jabber.org/streams") (Just "stream") ) (xp3Tuple (xpElemByNamespace "urn:ietf:params:xml:ns:xmpp-streams" xpPrim xpUnit xpUnit ) (xpOption $ xpElem "{urn:ietf:params:xml:ns:xmpp-streams}text" xpLangTag (xpContent xpId) ) (xpOption xpElemVerbatim) -- Application specific error conditions ) )