|
|
|
|
-- Picklers and unpicklers convert Haskell data to XML and XML to Haskell data,
|
|
|
|
|
-- respectively. By convention, pickler/unpickler ("PU") function names start
|
|
|
|
|
-- with "xp".
|
|
|
|
|
|
|
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
|
|
|
|
{-# LANGUAGE ViewPatterns #-}
|
|
|
|
|
{-# LANGUAGE NoMonomorphismRestriction #-}
|
|
|
|
|
|
|
|
|
|
{-# OPTIONS_HADDOCK hide #-}
|
|
|
|
|
|
|
|
|
|
module Network.Xmpp.Marshal where
|
|
|
|
|
|
|
|
|
|
import Data.XML.Pickle
|
|
|
|
|
import Data.XML.Types
|
|
|
|
|
|
|
|
|
|
import qualified Control.Exception as Ex
|
|
|
|
|
import Data.Text (Text)
|
|
|
|
|
import qualified Data.Text as Text
|
|
|
|
|
|
|
|
|
|
import Network.Xmpp.Types
|
|
|
|
|
|
|
|
|
|
xpNonemptyText :: PU Text NonemptyText
|
|
|
|
|
xpNonemptyText = ("xpNonemptyText" , "") <?+> xpWrap Nonempty fromNonempty xpText
|
|
|
|
|
|
|
|
|
|
xpStreamStanza :: PU [Node] (Either StreamErrorInfo Stanza)
|
|
|
|
|
xpStreamStanza = xpEither xpStreamError xpStanza
|
|
|
|
|
|
|
|
|
|
xpExtendedAttrs :: PU [Attribute] [ExtendedAttribute]
|
|
|
|
|
xpExtendedAttrs = ("xpAttrVerbatim" , "") <?+>
|
|
|
|
|
xpIso (map (\(name, cs) -> (name, flattenContents cs)))
|
|
|
|
|
(map (\(name, c) -> (name, [ContentText c])))
|
|
|
|
|
where
|
|
|
|
|
flattenContents = Text.concat . filterContentText
|
|
|
|
|
filterContentText = map (\c -> case c of
|
|
|
|
|
ContentText t -> t
|
|
|
|
|
ContentEntity{} -> Ex.throw UnresolvedEntityException )
|
|
|
|
|
|
|
|
|
|
xpStanza :: PU [Node] Stanza
|
|
|
|
|
xpStanza = ("xpStanza" , "") <?+> xpAlt stanzaSel
|
|
|
|
|
[ xpWrap IQRequestS (\(IQRequestS x) -> x) xpIQRequest
|
|
|
|
|
, xpWrap IQResultS (\(IQResultS x) -> x) xpIQResult
|
|
|
|
|
, xpWrap IQErrorS (\(IQErrorS x) -> x) xpIQError
|
|
|
|
|
, xpWrap MessageErrorS (\(MessageErrorS x) -> x) xpMessageError
|
|
|
|
|
, xpWrap MessageS (\(MessageS x) -> x) xpMessage
|
|
|
|
|
, xpWrap PresenceErrorS (\(PresenceErrorS x) -> x) xpPresenceError
|
|
|
|
|
, xpWrap PresenceS (\(PresenceS x) -> x) xpPresence
|
|
|
|
|
]
|
|
|
|
|
where
|
|
|
|
|
-- Selector for which pickler to execute above.
|
|
|
|
|
stanzaSel :: Stanza -> Int
|
|
|
|
|
stanzaSel (IQRequestS _) = 0
|
|
|
|
|
stanzaSel (IQResultS _) = 1
|
|
|
|
|
stanzaSel (IQErrorS _) = 2
|
|
|
|
|
stanzaSel (MessageErrorS _) = 3
|
|
|
|
|
stanzaSel (MessageS _) = 4
|
|
|
|
|
stanzaSel (PresenceErrorS _) = 5
|
|
|
|
|
stanzaSel (PresenceS _) = 6
|
|
|
|
|
|
|
|
|
|
xpMessage :: PU [Node] (Message)
|
|
|
|
|
xpMessage = ("xpMessage" , "") <?+> xpWrap
|
|
|
|
|
(\((tp, qid, from, to, lang, attrs), ext) -> Message qid from to lang tp ext attrs)
|
|
|
|
|
(\(Message qid from to lang tp ext attrs) -> ((tp, qid, from, to, lang, attrs), ext))
|
|
|
|
|
(xpElem "{jabber:client}message"
|
|
|
|
|
(xp6Tuple
|
Change Read/Show instances, update picklers and change LangTag exports
The reason for removing these instances are the same as in #24.
Affected types are: StanzaID, IQRequestType, MessageType,
PresenceType, StanzaErrorType, StanzaErrorCondition, SaslError,
StreamErrorCondition, Version, and LangTag.
It's quite boilerplate and ugly, but I think that it will do for now.
13 years ago
|
|
|
(xpDefault Normal $ xpAttr "type" xpMessageType)
|
|
|
|
|
(xpAttrImplied "id" xpId)
|
|
|
|
|
(xpAttrImplied "from" xpJid)
|
|
|
|
|
(xpAttrImplied "to" xpJid)
|
|
|
|
|
xpLangTag
|
|
|
|
|
xpExtendedAttrs
|
|
|
|
|
-- TODO: NS?
|
|
|
|
|
)
|
|
|
|
|
(xpAll xpElemVerbatim)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
xpPresence :: PU [Node] Presence
|
|
|
|
|
xpPresence = ("xpPresence" , "") <?+> xpWrap
|
|
|
|
|
(\((qid, from, to, lang, tp, attr), ext)
|
|
|
|
|
-> Presence qid from to lang tp ext attr)
|
|
|
|
|
(\(Presence qid from to lang tp ext attr)
|
|
|
|
|
-> ((qid, from, to, lang, tp, attr), ext))
|
|
|
|
|
(xpElem "{jabber:client}presence"
|
|
|
|
|
(xp6Tuple
|
|
|
|
|
(xpAttrImplied "id" xpId)
|
|
|
|
|
(xpAttrImplied "from" xpJid)
|
|
|
|
|
(xpAttrImplied "to" xpJid)
|
|
|
|
|
xpLangTag
|
Change Read/Show instances, update picklers and change LangTag exports
The reason for removing these instances are the same as in #24.
Affected types are: StanzaID, IQRequestType, MessageType,
PresenceType, StanzaErrorType, StanzaErrorCondition, SaslError,
StreamErrorCondition, Version, and LangTag.
It's quite boilerplate and ugly, but I think that it will do for now.
13 years ago
|
|
|
(xpDefault Available $ xpAttr "type" xpPresenceType)
|
|
|
|
|
xpExtendedAttrs
|
|
|
|
|
)
|
|
|
|
|
(xpAll xpElemVerbatim)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
xpIQRequest :: PU [Node] IQRequest
|
|
|
|
|
xpIQRequest = ("xpIQRequest" , "") <?+> xpWrap
|
|
|
|
|
(\((qid, from, to, lang, tp, attr),body)
|
|
|
|
|
-> IQRequest qid from to lang tp body attr)
|
|
|
|
|
(\(IQRequest qid from to lang tp body attr)
|
|
|
|
|
-> ((qid, from, to, lang, tp, attr), body))
|
|
|
|
|
(xpElem "{jabber:client}iq"
|
|
|
|
|
(xp6Tuple
|
|
|
|
|
(xpAttr "id" xpId)
|
|
|
|
|
(xpAttrImplied "from" xpJid)
|
|
|
|
|
(xpAttrImplied "to" xpJid)
|
|
|
|
|
xpLangTag
|
Change Read/Show instances, update picklers and change LangTag exports
The reason for removing these instances are the same as in #24.
Affected types are: StanzaID, IQRequestType, MessageType,
PresenceType, StanzaErrorType, StanzaErrorCondition, SaslError,
StreamErrorCondition, Version, and LangTag.
It's quite boilerplate and ugly, but I think that it will do for now.
13 years ago
|
|
|
((xpAttr "type" xpIQRequestType))
|
|
|
|
|
xpExtendedAttrs
|
|
|
|
|
)
|
|
|
|
|
xpElemVerbatim
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
xpIQResult :: PU [Node] IQResult
|
|
|
|
|
xpIQResult = ("xpIQResult" , "") <?+> xpWrap
|
|
|
|
|
(\((qid, from, to, lang, _tp, attr),body)
|
|
|
|
|
-> IQResult qid from to lang body attr)
|
|
|
|
|
(\(IQResult qid from to lang body attr)
|
|
|
|
|
-> ((qid, from, to, lang, (), attr ), body))
|
|
|
|
|
(xpElem "{jabber:client}iq"
|
|
|
|
|
(xp6Tuple
|
|
|
|
|
(xpAttr "id" xpId)
|
|
|
|
|
(xpAttrImplied "from" xpJid)
|
|
|
|
|
(xpAttrImplied "to" xpJid)
|
|
|
|
|
xpLangTag
|
|
|
|
|
((xpAttrFixed "type" "result"))
|
|
|
|
|
xpExtendedAttrs
|
|
|
|
|
)
|
|
|
|
|
(xpOption xpElemVerbatim)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
----------------------------------------------------------
|
|
|
|
|
-- Errors
|
|
|
|
|
----------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
xpStanzaErrorCondition :: PU [Node] StanzaErrorCondition
|
|
|
|
|
xpStanzaErrorCondition = ("xpErrorCondition" , "") <?+> xpWrapEither
|
|
|
|
|
(\(cond, (),cont) -> case (cond, cont) of
|
|
|
|
|
(Gone _, x) -> Right $ Gone x
|
|
|
|
|
(Redirect _, x) -> Right $ Redirect x
|
|
|
|
|
(x , Nothing) -> Right x
|
|
|
|
|
_ -> Left
|
|
|
|
|
("Only Gone and Redirect may have character data"
|
|
|
|
|
:: String)
|
|
|
|
|
)
|
|
|
|
|
(\x -> case x of
|
|
|
|
|
(Gone t) -> (Gone Nothing, (), t)
|
|
|
|
|
(Redirect t) -> (Redirect Nothing, () , t)
|
|
|
|
|
c -> (c, (), Nothing))
|
|
|
|
|
(xpElemByNamespace
|
|
|
|
|
"urn:ietf:params:xml:ns:xmpp-stanzas"
|
|
|
|
|
xpStanzaErrorConditionShape
|
|
|
|
|
xpUnit
|
|
|
|
|
(xpOption $ xpContent xpNonemptyText)
|
|
|
|
|
)
|
|
|
|
|
where
|
|
|
|
|
-- Create the "shape" of the error condition. In case of Gone and Redirect
|
|
|
|
|
-- the optional field is left empty and must be filled in by the caller
|
|
|
|
|
xpStanzaErrorConditionShape :: PU Text StanzaErrorCondition
|
|
|
|
|
xpStanzaErrorConditionShape = ("xpStanzaErrorCondition", "") <?>
|
|
|
|
|
xpIso stanzaErrorConditionFromText
|
|
|
|
|
stanzaErrorConditionToText
|
|
|
|
|
stanzaErrorConditionToText BadRequest = "bad-request"
|
|
|
|
|
stanzaErrorConditionToText Conflict = "conflict"
|
|
|
|
|
stanzaErrorConditionToText FeatureNotImplemented = "feature-not-implemented"
|
|
|
|
|
stanzaErrorConditionToText Forbidden = "forbidden"
|
|
|
|
|
stanzaErrorConditionToText (Gone _) = "gone"
|
|
|
|
|
stanzaErrorConditionToText InternalServerError = "internal-server-error"
|
|
|
|
|
stanzaErrorConditionToText ItemNotFound = "item-not-found"
|
|
|
|
|
stanzaErrorConditionToText JidMalformed = "jid-malformed"
|
|
|
|
|
stanzaErrorConditionToText NotAcceptable = "not-acceptable"
|
|
|
|
|
stanzaErrorConditionToText NotAllowed = "not-allowed"
|
|
|
|
|
stanzaErrorConditionToText NotAuthorized = "not-authorized"
|
|
|
|
|
stanzaErrorConditionToText PolicyViolation = "policy-violation"
|
|
|
|
|
stanzaErrorConditionToText RecipientUnavailable = "recipient-unavailable"
|
|
|
|
|
stanzaErrorConditionToText (Redirect _) = "redirect"
|
|
|
|
|
stanzaErrorConditionToText RegistrationRequired = "registration-required"
|
|
|
|
|
stanzaErrorConditionToText RemoteServerNotFound = "remote-server-not-found"
|
|
|
|
|
stanzaErrorConditionToText RemoteServerTimeout = "remote-server-timeout"
|
|
|
|
|
stanzaErrorConditionToText ResourceConstraint = "resource-constraint"
|
|
|
|
|
stanzaErrorConditionToText ServiceUnavailable = "service-unavailable"
|
|
|
|
|
stanzaErrorConditionToText SubscriptionRequired = "subscription-required"
|
|
|
|
|
stanzaErrorConditionToText UndefinedCondition = "undefined-condition"
|
|
|
|
|
stanzaErrorConditionToText UnexpectedRequest = "unexpected-request"
|
|
|
|
|
stanzaErrorConditionFromText "bad-request" = BadRequest
|
|
|
|
|
stanzaErrorConditionFromText "conflict" = Conflict
|
|
|
|
|
stanzaErrorConditionFromText "feature-not-implemented" = FeatureNotImplemented
|
|
|
|
|
stanzaErrorConditionFromText "forbidden" = Forbidden
|
|
|
|
|
stanzaErrorConditionFromText "gone" = Gone Nothing
|
|
|
|
|
stanzaErrorConditionFromText "internal-server-error" = InternalServerError
|
|
|
|
|
stanzaErrorConditionFromText "item-not-found" = ItemNotFound
|
|
|
|
|
stanzaErrorConditionFromText "jid-malformed" = JidMalformed
|
|
|
|
|
stanzaErrorConditionFromText "not-acceptable" = NotAcceptable
|
|
|
|
|
stanzaErrorConditionFromText "not-allowed" = NotAllowed
|
|
|
|
|
stanzaErrorConditionFromText "not-authorized" = NotAuthorized
|
|
|
|
|
stanzaErrorConditionFromText "policy-violation" = PolicyViolation
|
|
|
|
|
stanzaErrorConditionFromText "recipient-unavailable" = RecipientUnavailable
|
|
|
|
|
stanzaErrorConditionFromText "redirect" = Redirect Nothing
|
|
|
|
|
stanzaErrorConditionFromText "registration-required" = RegistrationRequired
|
|
|
|
|
stanzaErrorConditionFromText "remote-server-not-found" = RemoteServerNotFound
|
|
|
|
|
stanzaErrorConditionFromText "remote-server-timeout" = RemoteServerTimeout
|
|
|
|
|
stanzaErrorConditionFromText "resource-constraint" = ResourceConstraint
|
|
|
|
|
stanzaErrorConditionFromText "service-unavailable" = ServiceUnavailable
|
|
|
|
|
stanzaErrorConditionFromText "subscription-required" = SubscriptionRequired
|
|
|
|
|
stanzaErrorConditionFromText "undefined-condition" = UndefinedCondition
|
|
|
|
|
stanzaErrorConditionFromText "unexpected-request" = UnexpectedRequest
|
|
|
|
|
stanzaErrorConditionFromText _ = UndefinedCondition
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
xpStanzaError :: PU [Node] StanzaError
|
|
|
|
|
xpStanzaError = ("xpStanzaError" , "") <?+> xpWrap
|
|
|
|
|
(\((tp, _code), (cond, txt, ext)) -> StanzaError tp cond txt ext)
|
|
|
|
|
(\(StanzaError tp cond txt ext) -> ((tp, Nothing), (cond, txt, ext)))
|
|
|
|
|
(xpElem "{jabber:client}error"
|
|
|
|
|
(xp2Tuple
|
|
|
|
|
(xpAttr "type" xpStanzaErrorType)
|
|
|
|
|
(xpAttribute' "code" xpId))
|
|
|
|
|
(xp3Tuple
|
|
|
|
|
xpStanzaErrorCondition
|
|
|
|
|
(xpOption $ xpElem "{urn:ietf:params:xml:ns:xmpp-stanzas}text"
|
Change Read/Show instances, update picklers and change LangTag exports
The reason for removing these instances are the same as in #24.
Affected types are: StanzaID, IQRequestType, MessageType,
PresenceType, StanzaErrorType, StanzaErrorCondition, SaslError,
StreamErrorCondition, Version, and LangTag.
It's quite boilerplate and ugly, but I think that it will do for now.
13 years ago
|
|
|
(xpAttrImplied xmlLang xpLang)
|
|
|
|
|
(xpContent xpNonemptyText)
|
|
|
|
|
)
|
|
|
|
|
(xpOption xpElemVerbatim)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
xpMessageError :: PU [Node] (MessageError)
|
|
|
|
|
xpMessageError = ("xpMessageError" , "") <?+> xpWrap
|
|
|
|
|
(\((_, qid, from, to, lang, attr), (err, ext)) ->
|
|
|
|
|
MessageError qid from to lang err ext attr)
|
|
|
|
|
(\(MessageError qid from to lang err ext attr) ->
|
|
|
|
|
(((), qid, from, to, lang, attr), (err, ext)))
|
|
|
|
|
(xpElem "{jabber:client}message"
|
|
|
|
|
(xp6Tuple
|
|
|
|
|
(xpAttrFixed "type" "error")
|
|
|
|
|
(xpAttrImplied "id" xpId)
|
|
|
|
|
(xpAttrImplied "from" xpJid)
|
|
|
|
|
(xpAttrImplied "to" xpJid)
|
Change Read/Show instances, update picklers and change LangTag exports
The reason for removing these instances are the same as in #24.
Affected types are: StanzaID, IQRequestType, MessageType,
PresenceType, StanzaErrorType, StanzaErrorCondition, SaslError,
StreamErrorCondition, Version, and LangTag.
It's quite boilerplate and ugly, but I think that it will do for now.
13 years ago
|
|
|
(xpAttrImplied xmlLang xpLang)
|
|
|
|
|
xpExtendedAttrs
|
|
|
|
|
)
|
|
|
|
|
(xp2Tuple xpStanzaError (xpAll xpElemVerbatim))
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
xpPresenceError :: PU [Node] PresenceError
|
|
|
|
|
xpPresenceError = ("xpPresenceError" , "") <?+> xpWrap
|
|
|
|
|
(\((qid, from, to, lang, _, attr),(err, ext)) ->
|
|
|
|
|
PresenceError qid from to lang err ext attr)
|
|
|
|
|
(\(PresenceError qid from to lang err ext attr) ->
|
|
|
|
|
((qid, from, to, lang, (), attr), (err, ext)))
|
|
|
|
|
(xpElem "{jabber:client}presence"
|
|
|
|
|
(xp6Tuple
|
|
|
|
|
(xpAttrImplied "id" xpId)
|
|
|
|
|
(xpAttrImplied "from" xpJid)
|
|
|
|
|
(xpAttrImplied "to" xpJid)
|
|
|
|
|
xpLangTag
|
|
|
|
|
(xpAttrFixed "type" "error")
|
|
|
|
|
xpExtendedAttrs
|
|
|
|
|
)
|
|
|
|
|
(xp2Tuple xpStanzaError (xpAll xpElemVerbatim))
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
xpIQError :: PU [Node] IQError
|
|
|
|
|
xpIQError = ("xpIQError" , "") <?+> xpWrap
|
|
|
|
|
(\((qid, from, to, lang, _tp, attr),(err, body)) ->
|
|
|
|
|
IQError qid from to lang err body attr)
|
|
|
|
|
(\(IQError qid from to lang err body attr) ->
|
|
|
|
|
((qid, from, to, lang, (), attr), (err, body)))
|
|
|
|
|
(xpElem "{jabber:client}iq"
|
|
|
|
|
(xp6Tuple
|
|
|
|
|
(xpAttr "id" xpId)
|
|
|
|
|
(xpAttrImplied "from" xpJid)
|
|
|
|
|
(xpAttrImplied "to" xpJid)
|
|
|
|
|
xpLangTag
|
|
|
|
|
((xpAttrFixed "type" "error"))
|
|
|
|
|
xpExtendedAttrs
|
|
|
|
|
)
|
|
|
|
|
(xp2Tuple xpStanzaError (xpOption xpElemVerbatim))
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
xpStreamError :: PU [Node] StreamErrorInfo
|
|
|
|
|
xpStreamError = ("xpStreamError" , "") <?+> xpWrap
|
|
|
|
|
(\((cond,() ,()), txt, el) -> StreamErrorInfo cond txt el)
|
|
|
|
|
(\(StreamErrorInfo 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"
|
Change Read/Show instances, update picklers and change LangTag exports
The reason for removing these instances are the same as in #24.
Affected types are: StanzaID, IQRequestType, MessageType,
PresenceType, StanzaErrorType, StanzaErrorCondition, SaslError,
StreamErrorCondition, Version, and LangTag.
It's quite boilerplate and ugly, but I think that it will do for now.
13 years ago
|
|
|
xpStreamErrorCondition
|
|
|
|
|
xpUnit
|
|
|
|
|
xpUnit
|
|
|
|
|
)
|
|
|
|
|
(xpOption $ xpElem
|
|
|
|
|
"{urn:ietf:params:xml:ns:xmpp-streams}text"
|
|
|
|
|
xpLangTag
|
|
|
|
|
(xpContent xpNonemptyText)
|
|
|
|
|
)
|
|
|
|
|
(xpOption xpElemVerbatim) -- Application specific error conditions
|
|
|
|
|
)
|
|
|
|
|
)
|
Change module structure
We can treat all functions related to SASL negotiation as a submodule
to Pontarius XMPP if there are no dependencies from the internal
Network.Xmpp modules to the SASL functionality. Because of this,
`auth' and `authSimple' were moved from Session.hs to Sasl.hs. As the
bind and the `{urn:ietf:params:xml:ns:xmpp-session}session'
functionality are related only to the SASL negotation functionality,
these functions has been moved to the SASL submodule as well.
As these changes only leaves `connect' in the Session module, it seems
fitting to move `connect' to Network.Xmpp.Stream (not
Network.Xmpp.Connection, as `connect' depends on `startStream').
The internal Network.Xmpp modules (Connection.hs) no longer depend on
the Concurrent submodule. This will decrease the coupling between
Network.Xmpp and the concurrent implementation, making it easier for
developers to replace the concurrent implementation if they wanted to.
As Network.Xmpp.Connection is really a module that breaks the
encapsulation that is Network.Xmpp and the concurrent interface, I
have renamed it Network.Xmpp.Internal. As this frees up the
Network.Xmpp.Connection name, Network.Xmpp.Connection_ can reclaim it.
The high-level "utility" functions of Network.Xmpp.Utilities,
Network.Xmpp.Presence, and Network.Xmpp.Message has been moved to
Network.Xmpp.Utilities. This module contains functions that at most
only depend on the internal Network.Xmpp.Types module, and doesn't
belong in any other module.
The functionality of Jid.hs was moved to Types.hs.
Moved some of the functions of Network.Xmpp.Pickle to
Network.Xmpp.Marshal, and removed the Network.Xmpp.Pickle module.
A module imports diagram corresponding to the one of my last patch
shows the new module structure. I also include a diagram showing
the `Sasl' and `Concurrent' module imports.
13 years ago
|
|
|
|
|
|
|
|
xpLangTag :: PU [Attribute] (Maybe LangTag)
|
Change Read/Show instances, update picklers and change LangTag exports
The reason for removing these instances are the same as in #24.
Affected types are: StanzaID, IQRequestType, MessageType,
PresenceType, StanzaErrorType, StanzaErrorCondition, SaslError,
StreamErrorCondition, Version, and LangTag.
It's quite boilerplate and ugly, but I think that it will do for now.
13 years ago
|
|
|
xpLangTag = xpAttrImplied xmlLang xpLang
|
|
|
|
|
|
|
|
|
|
xpLang :: PU Text LangTag
|
|
|
|
|
xpLang = ("xpLang", "") <?>
|
|
|
|
|
xpPartial ( \input -> case langTagFromText input of
|
|
|
|
|
Nothing -> Left "Could not parse language tag."
|
|
|
|
|
Just j -> Right j)
|
|
|
|
|
langTagToText
|
Change module structure
We can treat all functions related to SASL negotiation as a submodule
to Pontarius XMPP if there are no dependencies from the internal
Network.Xmpp modules to the SASL functionality. Because of this,
`auth' and `authSimple' were moved from Session.hs to Sasl.hs. As the
bind and the `{urn:ietf:params:xml:ns:xmpp-session}session'
functionality are related only to the SASL negotation functionality,
these functions has been moved to the SASL submodule as well.
As these changes only leaves `connect' in the Session module, it seems
fitting to move `connect' to Network.Xmpp.Stream (not
Network.Xmpp.Connection, as `connect' depends on `startStream').
The internal Network.Xmpp modules (Connection.hs) no longer depend on
the Concurrent submodule. This will decrease the coupling between
Network.Xmpp and the concurrent implementation, making it easier for
developers to replace the concurrent implementation if they wanted to.
As Network.Xmpp.Connection is really a module that breaks the
encapsulation that is Network.Xmpp and the concurrent interface, I
have renamed it Network.Xmpp.Internal. As this frees up the
Network.Xmpp.Connection name, Network.Xmpp.Connection_ can reclaim it.
The high-level "utility" functions of Network.Xmpp.Utilities,
Network.Xmpp.Presence, and Network.Xmpp.Message has been moved to
Network.Xmpp.Utilities. This module contains functions that at most
only depend on the internal Network.Xmpp.Types module, and doesn't
belong in any other module.
The functionality of Jid.hs was moved to Types.hs.
Moved some of the functions of Network.Xmpp.Pickle to
Network.Xmpp.Marshal, and removed the Network.Xmpp.Pickle module.
A module imports diagram corresponding to the one of my last patch
shows the new module structure. I also include a diagram showing
the `Sasl' and `Concurrent' module imports.
13 years ago
|
|
|
|
|
|
|
|
xmlLang :: Name
|
|
|
|
|
xmlLang = Name "lang" (Just "http://www.w3.org/XML/1998/namespace") (Just "xml")
|
|
|
|
|
|
|
|
|
|
-- Given a pickler and an object, produces an Element.
|
|
|
|
|
pickleElem :: PU [Node] a -> a -> Element
|
|
|
|
|
pickleElem p = pickle $ xpNodeElem p
|
|
|
|
|
|
|
|
|
|
-- Given a pickler and an element, produces an object.
|
|
|
|
|
unpickleElem :: PU [Node] a -> Element -> Either UnpickleError a
|
|
|
|
|
unpickleElem p x = unpickle (xpNodeElem p) x
|
|
|
|
|
|
|
|
|
|
xpNodeElem :: PU [Node] a -> PU Element a
|
|
|
|
|
xpNodeElem = xpRoot . xpUnliftElems
|
Change module structure
We can treat all functions related to SASL negotiation as a submodule
to Pontarius XMPP if there are no dependencies from the internal
Network.Xmpp modules to the SASL functionality. Because of this,
`auth' and `authSimple' were moved from Session.hs to Sasl.hs. As the
bind and the `{urn:ietf:params:xml:ns:xmpp-session}session'
functionality are related only to the SASL negotation functionality,
these functions has been moved to the SASL submodule as well.
As these changes only leaves `connect' in the Session module, it seems
fitting to move `connect' to Network.Xmpp.Stream (not
Network.Xmpp.Connection, as `connect' depends on `startStream').
The internal Network.Xmpp modules (Connection.hs) no longer depend on
the Concurrent submodule. This will decrease the coupling between
Network.Xmpp and the concurrent implementation, making it easier for
developers to replace the concurrent implementation if they wanted to.
As Network.Xmpp.Connection is really a module that breaks the
encapsulation that is Network.Xmpp and the concurrent interface, I
have renamed it Network.Xmpp.Internal. As this frees up the
Network.Xmpp.Connection name, Network.Xmpp.Connection_ can reclaim it.
The high-level "utility" functions of Network.Xmpp.Utilities,
Network.Xmpp.Presence, and Network.Xmpp.Message has been moved to
Network.Xmpp.Utilities. This module contains functions that at most
only depend on the internal Network.Xmpp.Types module, and doesn't
belong in any other module.
The functionality of Jid.hs was moved to Types.hs.
Moved some of the functions of Network.Xmpp.Pickle to
Network.Xmpp.Marshal, and removed the Network.Xmpp.Pickle module.
A module imports diagram corresponding to the one of my last patch
shows the new module structure. I also include a diagram showing
the `Sasl' and `Concurrent' module imports.
13 years ago
|
|
|
|
|
|
|
|
mbl :: Maybe [a] -> [a]
|
|
|
|
|
mbl (Just l) = l
|
|
|
|
|
mbl Nothing = []
|
|
|
|
|
|
|
|
|
|
lmb :: [t] -> Maybe [t]
|
|
|
|
|
lmb [] = Nothing
|
|
|
|
|
lmb x = Just x
|
|
|
|
|
|
|
|
|
|
xpStream :: PU [Node] (Text, Maybe Jid, Maybe Jid, Maybe Text, Maybe LangTag)
|
|
|
|
|
xpStream = xpElemAttrs
|
|
|
|
|
(Name "stream" (Just "http://etherx.jabber.org/streams") (Just "stream"))
|
|
|
|
|
(xp5Tuple
|
|
|
|
|
(xpAttr "version" xpId)
|
|
|
|
|
(xpAttrImplied "from" xpJid)
|
|
|
|
|
(xpAttrImplied "to" xpJid)
|
|
|
|
|
(xpAttrImplied "id" xpId)
|
|
|
|
|
xpLangTag
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
-- Pickler/Unpickler for the stream features - TLS, SASL, and the rest.
|
|
|
|
|
xpStreamFeatures :: PU [Node] StreamFeatures
|
|
|
|
|
xpStreamFeatures = ("xpStreamFeatures","") <?> xpWrap
|
|
|
|
|
(\(tls, sasl, ver, preAppr, rest)
|
|
|
|
|
-> StreamFeatures tls (mbl sasl) ver preAppr rest)
|
|
|
|
|
(\(StreamFeatures tls sasl ver preAppr rest)
|
|
|
|
|
-> (tls, lmb sasl, ver, preAppr, rest))
|
|
|
|
|
(xpElemNodes
|
|
|
|
|
(Name
|
|
|
|
|
"features"
|
|
|
|
|
(Just "http://etherx.jabber.org/streams")
|
|
|
|
|
(Just "stream")
|
|
|
|
|
)
|
|
|
|
|
(xp5Tuple
|
|
|
|
|
(xpOption pickleTlsFeature)
|
|
|
|
|
(xpOption pickleSaslFeature)
|
|
|
|
|
(xpOption pickleRosterVer)
|
|
|
|
|
picklePreApproval
|
|
|
|
|
(xpAll xpElemVerbatim)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
where
|
|
|
|
|
pickleTlsFeature :: PU [Node] Bool
|
|
|
|
|
pickleTlsFeature = ("pickleTlsFeature", "") <?>
|
|
|
|
|
xpElemNodes "{urn:ietf:params:xml:ns:xmpp-tls}starttls"
|
|
|
|
|
(xpElemExists "{urn:ietf:params:xml:ns:xmpp-tls}required")
|
|
|
|
|
pickleSaslFeature :: PU [Node] [Text]
|
|
|
|
|
pickleSaslFeature = ("pickleSaslFeature", "") <?>
|
|
|
|
|
xpElemNodes "{urn:ietf:params:xml:ns:xmpp-sasl}mechanisms"
|
|
|
|
|
(xpAll $ xpElemNodes
|
|
|
|
|
"{urn:ietf:params:xml:ns:xmpp-sasl}mechanism" (xpContent xpId))
|
|
|
|
|
pickleRosterVer = xpElemNodes "{urn:xmpp:features:rosterver}ver" $
|
|
|
|
|
xpElemExists "{urn:xmpp:features:rosterver}optional"
|
|
|
|
|
picklePreApproval = xpElemExists "{urn:xmpp:features:pre-approval}sub"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
xpJid :: PU Text Jid
|
|
|
|
|
xpJid = ("xpJid", "") <?>
|
|
|
|
|
xpPartial ( \input -> case jidFromText input of
|
|
|
|
|
Nothing -> Left "Could not parse JID."
|
|
|
|
|
Just j -> Right j)
|
|
|
|
|
jidToText
|
Change Read/Show instances, update picklers and change LangTag exports
The reason for removing these instances are the same as in #24.
Affected types are: StanzaID, IQRequestType, MessageType,
PresenceType, StanzaErrorType, StanzaErrorCondition, SaslError,
StreamErrorCondition, Version, and LangTag.
It's quite boilerplate and ugly, but I think that it will do for now.
13 years ago
|
|
|
|
|
|
|
|
xpIQRequestType :: PU Text IQRequestType
|
|
|
|
|
xpIQRequestType = ("xpIQRequestType", "") <?>
|
|
|
|
|
xpPartial ( \input -> case iqRequestTypeFromText input of
|
|
|
|
|
Nothing -> Left "Could not parse IQ request type."
|
|
|
|
|
Just j -> Right j)
|
|
|
|
|
iqRequestTypeToText
|
|
|
|
|
where
|
|
|
|
|
iqRequestTypeFromText "get" = Just Get
|
|
|
|
|
iqRequestTypeFromText "set" = Just Set
|
|
|
|
|
iqRequestTypeFromText _ = Nothing
|
|
|
|
|
iqRequestTypeToText Get = "get"
|
|
|
|
|
iqRequestTypeToText Set = "set"
|
|
|
|
|
|
|
|
|
|
xpMessageType :: PU Text MessageType
|
|
|
|
|
xpMessageType = ("xpMessageType", "") <?>
|
|
|
|
|
xpIso messageTypeFromText
|
|
|
|
|
messageTypeToText
|
Change Read/Show instances, update picklers and change LangTag exports
The reason for removing these instances are the same as in #24.
Affected types are: StanzaID, IQRequestType, MessageType,
PresenceType, StanzaErrorType, StanzaErrorCondition, SaslError,
StreamErrorCondition, Version, and LangTag.
It's quite boilerplate and ugly, but I think that it will do for now.
13 years ago
|
|
|
where
|
|
|
|
|
messageTypeFromText "chat" = Chat
|
|
|
|
|
messageTypeFromText "groupchat" = GroupChat
|
|
|
|
|
messageTypeFromText "headline" = Headline
|
|
|
|
|
messageTypeFromText "normal" = Normal
|
|
|
|
|
messageTypeFromText _ = Normal
|
Change Read/Show instances, update picklers and change LangTag exports
The reason for removing these instances are the same as in #24.
Affected types are: StanzaID, IQRequestType, MessageType,
PresenceType, StanzaErrorType, StanzaErrorCondition, SaslError,
StreamErrorCondition, Version, and LangTag.
It's quite boilerplate and ugly, but I think that it will do for now.
13 years ago
|
|
|
messageTypeToText Chat = "chat"
|
|
|
|
|
messageTypeToText GroupChat = "groupchat"
|
|
|
|
|
messageTypeToText Headline = "headline"
|
|
|
|
|
messageTypeToText Normal = "normal"
|
|
|
|
|
|
|
|
|
|
xpPresenceType :: PU Text PresenceType
|
|
|
|
|
xpPresenceType = ("xpPresenceType", "") <?>
|
|
|
|
|
xpPartial ( \input -> case presenceTypeFromText input of
|
|
|
|
|
Nothing -> Left "Could not parse presence type."
|
|
|
|
|
Just j -> Right j)
|
|
|
|
|
presenceTypeToText
|
|
|
|
|
where
|
|
|
|
|
presenceTypeFromText "" = Just Available
|
|
|
|
|
presenceTypeFromText "available" = Just Available
|
|
|
|
|
presenceTypeFromText "unavailable" = Just Unavailable
|
|
|
|
|
presenceTypeFromText "subscribe" = Just Subscribe
|
|
|
|
|
presenceTypeFromText "subscribed" = Just Subscribed
|
|
|
|
|
presenceTypeFromText "unsubscribe" = Just Unsubscribe
|
|
|
|
|
presenceTypeFromText "unsubscribed" = Just Unsubscribed
|
|
|
|
|
presenceTypeFromText "probe" = Just Probe
|
|
|
|
|
presenceTypeFromText _ = Nothing
|
Change Read/Show instances, update picklers and change LangTag exports
The reason for removing these instances are the same as in #24.
Affected types are: StanzaID, IQRequestType, MessageType,
PresenceType, StanzaErrorType, StanzaErrorCondition, SaslError,
StreamErrorCondition, Version, and LangTag.
It's quite boilerplate and ugly, but I think that it will do for now.
13 years ago
|
|
|
presenceTypeToText Available = "available"
|
|
|
|
|
presenceTypeToText Unavailable = "unavailable"
|
|
|
|
|
presenceTypeToText Subscribe = "subscribe"
|
|
|
|
|
presenceTypeToText Subscribed = "subscribed"
|
|
|
|
|
presenceTypeToText Unsubscribe = "unsubscribe"
|
|
|
|
|
presenceTypeToText Unsubscribed = "unsubscribed"
|
|
|
|
|
presenceTypeToText Probe = "probe"
|
|
|
|
|
|
|
|
|
|
xpStanzaErrorType :: PU Text StanzaErrorType
|
|
|
|
|
xpStanzaErrorType = ("xpStanzaErrorType", "") <?>
|
|
|
|
|
xpPartial ( \input -> case stanzaErrorTypeFromText input of
|
|
|
|
|
Nothing -> Left "Could not parse stanza error type."
|
|
|
|
|
Just j -> Right j)
|
|
|
|
|
stanzaErrorTypeToText
|
|
|
|
|
where
|
|
|
|
|
stanzaErrorTypeFromText "auth" = Just Auth
|
|
|
|
|
stanzaErrorTypeFromText "cancel" = Just Cancel
|
|
|
|
|
stanzaErrorTypeFromText "continue" = Just Continue
|
|
|
|
|
stanzaErrorTypeFromText "modify" = Just Modify
|
|
|
|
|
stanzaErrorTypeFromText "wait" = Just Wait
|
|
|
|
|
stanzaErrorTypeFromText _ = Nothing
|
|
|
|
|
stanzaErrorTypeToText Auth = "auth"
|
|
|
|
|
stanzaErrorTypeToText Cancel = "cancel"
|
|
|
|
|
stanzaErrorTypeToText Continue = "continue"
|
|
|
|
|
stanzaErrorTypeToText Modify = "modify"
|
|
|
|
|
stanzaErrorTypeToText Wait = "wait"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
xpStreamErrorCondition :: PU Text StreamErrorCondition
|
|
|
|
|
xpStreamErrorCondition = ("xpStreamErrorCondition", "") <?>
|
|
|
|
|
xpIso streamErrorConditionFromText
|
|
|
|
|
streamErrorConditionToText
|
Change Read/Show instances, update picklers and change LangTag exports
The reason for removing these instances are the same as in #24.
Affected types are: StanzaID, IQRequestType, MessageType,
PresenceType, StanzaErrorType, StanzaErrorCondition, SaslError,
StreamErrorCondition, Version, and LangTag.
It's quite boilerplate and ugly, but I think that it will do for now.
13 years ago
|
|
|
where
|
|
|
|
|
streamErrorConditionToText StreamBadFormat = "bad-format"
|
|
|
|
|
streamErrorConditionToText StreamBadNamespacePrefix = "bad-namespace-prefix"
|
|
|
|
|
streamErrorConditionToText StreamConflict = "conflict"
|
|
|
|
|
streamErrorConditionToText StreamConnectionTimeout = "connection-timeout"
|
|
|
|
|
streamErrorConditionToText StreamHostGone = "host-gone"
|
|
|
|
|
streamErrorConditionToText StreamHostUnknown = "host-unknown"
|
|
|
|
|
streamErrorConditionToText StreamImproperAddressing = "improper-addressing"
|
|
|
|
|
streamErrorConditionToText StreamInternalServerError = "internal-server-error"
|
|
|
|
|
streamErrorConditionToText StreamInvalidFrom = "invalid-from"
|
|
|
|
|
streamErrorConditionToText StreamInvalidNamespace = "invalid-namespace"
|
|
|
|
|
streamErrorConditionToText StreamInvalidXml = "invalid-xml"
|
|
|
|
|
streamErrorConditionToText StreamNotAuthorized = "not-authorized"
|
|
|
|
|
streamErrorConditionToText StreamNotWellFormed = "not-well-formed"
|
|
|
|
|
streamErrorConditionToText StreamPolicyViolation = "policy-violation"
|
|
|
|
|
streamErrorConditionToText StreamRemoteConnectionFailed = "remote-connection-failed"
|
|
|
|
|
streamErrorConditionToText StreamReset = "reset"
|
|
|
|
|
streamErrorConditionToText StreamResourceConstraint = "resource-constraint"
|
|
|
|
|
streamErrorConditionToText StreamRestrictedXml = "restricted-xml"
|
|
|
|
|
streamErrorConditionToText StreamSeeOtherHost = "see-other-host"
|
|
|
|
|
streamErrorConditionToText StreamSystemShutdown = "system-shutdown"
|
|
|
|
|
streamErrorConditionToText StreamUndefinedCondition = "undefined-condition"
|
|
|
|
|
streamErrorConditionToText StreamUnsupportedEncoding = "unsupported-encoding"
|
|
|
|
|
streamErrorConditionToText StreamUnsupportedFeature = "unsupported-feature"
|
|
|
|
|
streamErrorConditionToText StreamUnsupportedStanzaType = "unsupported-stanza-type"
|
|
|
|
|
streamErrorConditionToText StreamUnsupportedVersion = "unsupported-version"
|
|
|
|
|
streamErrorConditionFromText "bad-format" = StreamBadFormat
|
|
|
|
|
streamErrorConditionFromText "bad-namespace-prefix" = StreamBadNamespacePrefix
|
|
|
|
|
streamErrorConditionFromText "conflict" = StreamConflict
|
|
|
|
|
streamErrorConditionFromText "connection-timeout" = StreamConnectionTimeout
|
|
|
|
|
streamErrorConditionFromText "host-gone" = StreamHostGone
|
|
|
|
|
streamErrorConditionFromText "host-unknown" = StreamHostUnknown
|
|
|
|
|
streamErrorConditionFromText "improper-addressing" = StreamImproperAddressing
|
|
|
|
|
streamErrorConditionFromText "internal-server-error" = StreamInternalServerError
|
|
|
|
|
streamErrorConditionFromText "invalid-from" = StreamInvalidFrom
|
|
|
|
|
streamErrorConditionFromText "invalid-namespace" = StreamInvalidNamespace
|
|
|
|
|
streamErrorConditionFromText "invalid-xml" = StreamInvalidXml
|
|
|
|
|
streamErrorConditionFromText "not-authorized" = StreamNotAuthorized
|
|
|
|
|
streamErrorConditionFromText "not-well-formed" = StreamNotWellFormed
|
|
|
|
|
streamErrorConditionFromText "policy-violation" = StreamPolicyViolation
|
|
|
|
|
streamErrorConditionFromText "remote-connection-failed" = StreamRemoteConnectionFailed
|
|
|
|
|
streamErrorConditionFromText "reset" = StreamReset
|
|
|
|
|
streamErrorConditionFromText "resource-constraint" = StreamResourceConstraint
|
|
|
|
|
streamErrorConditionFromText "restricted-xml" = StreamRestrictedXml
|
|
|
|
|
streamErrorConditionFromText "see-other-host" = StreamSeeOtherHost
|
|
|
|
|
streamErrorConditionFromText "system-shutdown" = StreamSystemShutdown
|
|
|
|
|
streamErrorConditionFromText "undefined-condition" = StreamUndefinedCondition
|
|
|
|
|
streamErrorConditionFromText "unsupported-encoding" = StreamUnsupportedEncoding
|
|
|
|
|
streamErrorConditionFromText "unsupported-feature" = StreamUnsupportedFeature
|
|
|
|
|
streamErrorConditionFromText "unsupported-stanza-type" = StreamUnsupportedStanzaType
|
|
|
|
|
streamErrorConditionFromText "unsupported-version" = StreamUnsupportedVersion
|
|
|
|
|
streamErrorConditionFromText _ = StreamUndefinedCondition -- §4.9.2
|