xmpp: mellium.im/xmpp/stanza Index | Examples | Files

package stanza

import "mellium.im/xmpp/stanza"

Package stanza contains functionality for dealing with XMPP stanzas and stanza level errors.

Stanzas (Message, Presence, and IQ) are the basic building blocks of an XMPP stream. Messages are used to send data that is fire-and-forget such as chat messages. Presence is a publish-subscribe mechanism and is used to broadcast availability on the network (sometimes called "status" in chat, eg. online, offline, or away). IQ (Info/Query) is a request response mechanism for data that requires a response (eg. fetching an avatar or a list of client features).

There are two APIs for creating stanzas in this package, a token based XML stream API where the final stanza can be read from an xml.TokenReader, and a struct based API that relies on embedding structs in this package into the users own types. Stanzas created using either API are not guaranteed to be valid or enforce specific stanza semantics. For instance, using this package you could create an IQ without a unique ID, which is illegal in XMPP. Packages that require correct stanza semantics, such as the `mellium.im/xmpp` package, are expected to enforce stanza semantics when encoding stanzas to a stream.

Custom Stanzas

The stanza types in this package aren't very useful by themselves. To transmit meaningful data our stanzas must contain a payload. To add a payload with the struct based API we use composition to create a new struct that contains the payload as additional fields. For example, XEP-0199: XMPP Ping defines an IQ stanza with a payload named "ping" qualified by the "urn:xmpp:ping" namespace. To implement this in our own code we might create a Ping struct similar to the following:

// PingIQ is an IQ stanza with an XEP-0199: XMPP Ping payload.
type PingIQ struct {
    stanza.IQ

    Ping struct{} `xml:"urn:xmpp:ping ping"`
}

For details on marshaling and the use of the xml tag, refer to the encoding/xml package.

We could also create a similar stanza with the token stream API:

// PingIQ returns an xml.TokenReader that outputs a new IQ stanza with a
// ping payload.
func PingIQ(to jid.JID) xml.TokenReader {
    start := xml.StartElement{Name: xml.Name{Space: "urn:xmpp:ping", Local: "ping"}}
    return stanza.WrapIQ(
        stanza.IQ{To: to, Type: stanza.GetIQ},
        xmlstream.Wrap(nil, start)
    )
}

Code:

package main

import (
    "encoding/xml"
    "log"
    "os"

    "mellium.im/xmlstream"
    "mellium.im/xmpp/jid"
    "mellium.im/xmpp/stanza"
)

// WrapPingIQ returns an xml.TokenReader that outputs a new IQ stanza with
// a ping payload.
func WrapPingIQ(to jid.JID) xml.TokenReader {
    start := xml.StartElement{Name: xml.Name{Local: "ping", Space: "urn:xmpp:ping"}}
    return stanza.WrapIQ(stanza.IQ{To: to, Type: stanza.GetIQ}, xmlstream.Wrap(nil, start))
}

func main() {
    j := jid.MustParse("feste@example.net/siJo4eeT")
    e := xml.NewEncoder(os.Stdout)
    e.Indent("", "\t")

    ping := WrapPingIQ(j)
    if _, err := xmlstream.Copy(e, ping); err != nil {
        log.Fatal(err)
    }
    if err := e.Flush(); err != nil {
        log.Fatal(err)
    }
}

Code:

package main

import (
    "encoding/xml"
    "log"
    "os"

    "mellium.im/xmpp/jid"
    "mellium.im/xmpp/stanza"
)

// PingIQ represents a ping from XEP-0199: XMPP Ping.
type PingIQ struct {
    stanza.IQ

    Ping struct{} `xml:"urn:xmpp:ping ping"`
}

func main() {
    e := xml.NewEncoder(os.Stdout)
    e.Indent("", "\t")

    j := jid.MustParse("feste@example.net/siJo4eeT")
    err := e.Encode(PingIQ{
        IQ: stanza.IQ{
            Type: stanza.GetIQ,
            To:   j,
        },
    })
    if err != nil {
        log.Fatal(err)
    }
}

Index

Examples

Package Files

doc.go error.go iq.go message.go presence.go

func WrapIQ Uses

func WrapIQ(iq IQ, payload xml.TokenReader) xml.TokenReader

WrapIQ wraps a payload in an IQ stanza. The resulting IQ may not contain an id or from attribute and thus may not be valid without further processing.

func WrapMessage Uses

func WrapMessage(to jid.JID, typ MessageType, payload xml.TokenReader) xml.TokenReader

WrapMessage wraps a payload in a message stanza.

func WrapPresence Uses

func WrapPresence(to jid.JID, typ PresenceType, payload xml.TokenReader) xml.TokenReader

WrapPresence wraps a payload in a presence stanza.

If to is the zero value for jid.JID, no to attribute is set on the resulting presence.

type Condition Uses

type Condition string

Condition represents a more specific stanza error condition that can be encapsulated by an <error/> element.

const (
    // The sender has sent a stanza containing XML that does not conform to
    // the appropriate schema or that cannot be processed (e.g., an IQ
    // stanza that includes an unrecognized value of the 'type' attribute
    // or an element that is qualified by a recognized namespace but that
    // violates the defined syntax for the element); the associated error
    // type SHOULD be "modify".
    BadRequest Condition = "bad-request"

    // Access cannot be granted because an existing resource exists with the
    // same name or address; the associated error type SHOULD be "cancel".
    Conflict Condition = "conflict"

    // The feature represented in the XML stanza is not implemented by the
    // intended recipient or an intermediate server and therefore the stanza
    // cannot be processed (e.g., the entity understands the namespace but
    // does not recognize the element name); the associated error type
    // SHOULD be "cancel" or "modify".
    FeatureNotImplemented Condition = "feature-not-implemented"

    // The requesting entity does not possess the necessary permissions to
    // perform an action that only certain authorized roles or individuals
    // are allowed to complete (i.e., it typically relates to authorization
    // rather than authentication); the associated error type SHOULD be
    // "auth".
    Forbidden Condition = "forbidden"

    // The recipient or server can no longer be contacted at this address,
    // typically on a permanent basis (as opposed to the <redirect/> error
    // condition, which is used for temporary addressing failures); the
    // associated error type SHOULD be "cancel" and the error stanza SHOULD
    // include a new address (if available) as the XML character data of the
    // <gone/> element (which MUST be a Uniform Resource Identifier [URI] or
    // Internationalized Resource Identifier [IRI] at which the entity can
    // be contacted, typically an XMPP IRI as specified in RFC 5122).
    Gone Condition = "gone"

    // The server has experienced a misconfiguration or other internal error
    // that prevents it from processing the stanza; the associated error
    // type SHOULD be "cancel".
    InternalServerError Condition = "internal-server-error"

    // The addressed JID or item requested cannot be found; the associated
    // error type SHOULD be "cancel".
    //
    // Security Warning: An application MUST NOT return this error if
    // doing so would provide information about the intended recipient's
    // network availability to an entity that is not authorized to know
    // such information (for a more detailed discussion of presence
    // authorization, refer to the discussion of presence subscriptions
    // in RFC 6121); instead it MUST return a ServiceUnavailable
    // stanza error.
    ItemNotFound Condition = "item-not-found"

    // The sending entity has provided (e.g., during resource binding) or
    // communicated (e.g., in the 'to' address of a stanza) an XMPP address
    // that violates the rules of the mellium.im/xmpp/jid package; the
    // associated error type SHOULD be "modify".
    //
    //  Implementation Note: Enforcement of the format for XMPP localparts
    //  is primarily the responsibility of the service at which the
    //  associated account or entity is located (e.g., the example.com
    //  service is responsible for returning <jid-malformed/> errors
    //  related to all JIDs of the form <localpart@example.com>), whereas
    //  enforcement of the format for XMPP domainparts is primarily the
    //  responsibility of the service that seeks to route a stanza to the
    //  service identified by that domainpart (e.g., the example.org
    //  service is responsible for returning <jid-malformed/> errors
    //  related to stanzas that users of that service have to tried send
    //  to JIDs of the form <localpart@example.com>).  However, any entity
    //  that detects a malformed JID MAY return this error.
    JIDMalformed Condition = "jid-malformed"

    // The recipient or server understands the request but cannot process it
    // because the request does not meet criteria defined by the recipient
    // or server (e.g., a request to subscribe to information that does not
    // simultaneously include configuration parameters needed by the
    // recipient); the associated error type SHOULD be "modify".
    NotAcceptable Condition = "not-acceptable"

    // The recipient or server does not allow any entity to perform the
    // action (e.g., sending to entities at a blacklisted domain); the
    // associated error type SHOULD be "cancel".
    NotAllowed Condition = "not-allowed"

    // The sender needs to provide credentials before being allowed to
    // perform the action, or has provided improper credentials (the name
    // "not-authorized", which was borrowed from the "401 Unauthorized"
    // error of HTTP, might lead the reader to think that this condition
    // relates to authorization, but instead it is typically used in
    // relation to authentication); the associated error type SHOULD be
    // "auth".
    NotAuthorized Condition = "not-authorized"

    // The entity has violated some local service policy (e.g., a message
    // contains words that are prohibited by the service) and the server MAY
    // choose to specify the policy in the <text/> element or in an
    // application-specific condition element; the associated error type
    // SHOULD be "modify" or "wait" depending on the policy being violated.
    PolicyViolation Condition = "policy-violation"

    // The intended recipient is temporarily unavailable, undergoing
    // maintenance, etc.; the associated error type SHOULD be "wait".
    //
    // Security Warning: An application MUST NOT return this error if
    // doing so would provide information about the intended recipient's
    // network availability to an entity that is not authorized to know
    // such information (for a more detailed discussion of presence
    // authorization, refer to the discussion of presence subscriptions
    // in RFC 6121); instead it MUST return a ServiceUnavailable stanza
    // error.
    RecipientUnavailable Condition = "recipient-unavailable"

    // The recipient or server is redirecting requests for this information
    // to another entity, typically in a temporary fashion (as opposed to
    // the <gone/> error condition, which is used for permanent addressing
    // failures); the associated error type SHOULD be "modify" and the error
    // stanza SHOULD contain the alternate address in the XML character data
    // of the <redirect/> element (which MUST be a URI or IRI with which the
    // sender can communicate, typically an XMPP IRI as specified in
    // RFC 5122).
    //
    // Security Warning: An application receiving a stanza-level redirect
    // SHOULD warn a human user of the redirection attempt and request
    // approval before proceeding to communicate with the entity whose
    // address is contained in the XML character data of the <redirect/>
    // element, because that entity might have a different identity or
    // might enforce different security policies.  The end-to-end
    // authentication or signing of XMPP stanzas could help to mitigate
    // this risk, since it would enable the sender to determine if the
    // entity to which it has been redirected has the same identity as
    // the entity it originally attempted to contact.  An application MAY
    // have a policy of following redirects only if it has authenticated
    // the receiving entity.  In addition, an application SHOULD abort
    // the communication attempt after a certain number of successive
    // redirects (e.g., at least 2 but no more than 5).
    Redirect Condition = "redirect"

    // The requesting entity is not authorized to access the requested
    // service because prior registration is necessary (examples of prior
    // registration include members-only rooms in XMPP multi-user chat
    // [XEP-0045] and gateways to non-XMPP instant messaging services, which
    // traditionally required registration in order to use the gateway
    // [XEP-0100]); the associated error type SHOULD be "auth".
    RegistrationRequired Condition = "registration-required"

    // A remote server or service specified as part or all of the JID of the
    // intended recipient does not exist or cannot be resolved (e.g., there
    // is no _xmpp-server._tcp DNS SRV record, the A or AAAA fallback
    // resolution fails, or A/AAAA lookups succeed but there is no response
    // on the IANA-registered port 5269); the associated error type SHOULD
    // be "cancel".
    RemoteServerNotFound Condition = "remote-server-not-found"

    // A remote server or service specified as part or all of the JID of the
    // intended recipient (or needed to fulfill a request) was resolved but
    // communications could not be established within a reasonable amount of
    // time (e.g., an XML stream cannot be established at the resolved IP
    // address and port, or an XML stream can be established but stream
    // negotiation fails because of problems with TLS, SASL, Server
    // Dialback, etc.); the associated error type SHOULD be "wait" (unless
    // the error is of a more permanent nature, e.g., the remote server is
    // found but it cannot be authenticated or it violates security
    // policies).
    RemoteServerTimeout Condition = "remote-server-timeout"

    // The server or recipient is busy or lacks the system resources
    // necessary to service the request; the associated error type SHOULD be
    // "wait".
    ResourceConstraint Condition = "resource-constraint"

    // The server or recipient does not currently provide the requested
    // service; the associated error type SHOULD be "cancel".
    //
    // Security Warning: An application MUST return a ServiceUnavailable
    // stanza error instead of ItemNotFound or RecipientUnavailable if
    // if sending one of the latter errors would provide information about
    // the intended recipient's network availability to an entity that is
    // not authorized to know such information (for a more detailed discussion
    // of presence authorization, refer to RFC 6121).
    ServiceUnavailable Condition = "service-unavailable"

    // The requesting entity is not authorized to access the requested
    // service because a prior subscription is necessary (examples of prior
    // subscription include authorization to receive presence information as
    // defined in RFC 6121 and opt-in data feeds for XMPP publish-subscribe
    // as defined in [XEP-0060]); the associated error type SHOULD be
    // "auth".
    SubscriptionRequired Condition = "subscription-required"

    // The error condition is not one of those defined by the other
    // conditions in this list; any error type can be associated with this
    // condition, and it SHOULD NOT be used except in conjunction with an
    // application-specific condition.
    UndefinedCondition Condition = "undefined-condition"

    // The recipient or server understood the request but was not expecting
    // it at this time (e.g., the request was out of order); the associated
    // error type SHOULD be "wait" or "modify".
    UnexpectedRequest Condition = "unexpected-request"
)

A list of stanza error conditions defined in RFC 6120 §8.3.3

type Error Uses

type Error struct {
    XMLName   xml.Name
    By        jid.JID
    Type      ErrorType
    Condition Condition
    Text      map[string]string
}

Error is an implementation of error intended to be marshalable and unmarshalable as XML.

Text is a map of language tags to human readable representations of the error in a given language. Normally there will just be one with an empty language (eg. "": "Some error"). The keys are not validated to make sure they comply with BCP 47.

func (Error) Error Uses

func (se Error) Error() string

Error satisfies the error interface by returning the condition.

func (Error) MarshalXML Uses

func (se Error) MarshalXML(e *xml.Encoder, _ xml.StartElement) error

MarshalXML satisfies the xml.Marshaler interface for Error.

Code:

e := xml.NewEncoder(os.Stdout)
e.Indent("", "\t")

err := e.Encode(stanza.Error{
    By:        jid.MustParse("me@example.com"),
    Type:      stanza.Cancel,
    Condition: stanza.BadRequest,
    Text: map[string]string{
        "en": "Malformed XML in request",
    },
})
if err != nil {
    panic(err)
}

Output:

<error type="cancel" by="me@example.com">
	<bad-request xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"></bad-request>
	<text xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" xml:lang="en">Malformed XML in request</text>
</error>

func (Error) TokenReader Uses

func (se Error) TokenReader() xml.TokenReader

TokenReader satisfies the xmlstream.Marshaler interface for Error.

func (*Error) UnmarshalXML Uses

func (se *Error) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error

UnmarshalXML satisfies the xml.Unmarshaler interface for StanzaError.

Code:

d := xml.NewDecoder(strings.NewReader(`
	<error type="cancel" by="me@example.com">
		<bad-request xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"></bad-request>
		<text xmlns="urn:ietf:params:xml:ns:xmpp-stanzas">Malformed XML</text>
	</error>`))

se := stanza.Error{}
err := d.Decode(&se)
if err != nil {
    panic(err)
}

fmt.Printf("%s: %s", se, se.Text[""])

Output:

bad-request: Malformed XML

func (Error) WriteXML Uses

func (se Error) WriteXML(w xmlstream.TokenWriter) (n int, err error)

WriteXML satisfies the xmlstream.WriterTo interface. It is like MarshalXML except it writes tokens to w.

type ErrorType Uses

type ErrorType string

ErrorType is the type of an stanza error payloads. It should normally be one of the constants defined in this package.

const (
    // Cancel indicates that the error cannot be remedied and the operation should
    // not be retried.
    Cancel ErrorType = "cancel"

    // Auth indicates that an operation should be retried after providing
    // credentials.
    Auth ErrorType = "auth"

    // Continue indicates that the operation can proceed (the condition was only a
    // warning).
    Continue ErrorType = "continue"

    // Modify indicates that the operation can be retried after changing the data
    // sent.
    Modify ErrorType = "modify"

    // Wait is indicates that an error is temporary and may be retried.
    Wait ErrorType = "wait"
)

type IQ Uses

type IQ struct {
    XMLName xml.Name `xml:"iq"`
    ID      string   `xml:"id,attr"`
    To      jid.JID  `xml:"to,attr,omitempty"`
    From    jid.JID  `xml:"from,attr,omitempty"`
    Lang    string   `xml:"http://www.w3.org/XML/1998/namespace lang,attr,omitempty"`
    Type    IQType   `xml:"type,attr"`
}

IQ ("Information Query") is used as a general request response mechanism. IQ's are one-to-one, provide get and set semantics, and always require a response in the form of a result or an error.

type IQType Uses

type IQType string

IQType is the type of an IQ stanza. It should normally be one of the constants defined in this package.

const (
    // GetIQ is used to query another entity for information.
    GetIQ IQType = "get"

    // SetIQ is used to provide data to another entity, set new values, and
    // replace existing values.
    SetIQ IQType = "set"

    // ResultIQ is sent in response to a successful get or set IQ.
    ResultIQ IQType = "result"

    // ErrorIQ is sent to report that an error occurred during the delivery or
    // processing of a get or set IQ.
    ErrorIQ IQType = "error"
)

func (IQType) MarshalText Uses

func (t IQType) MarshalText() ([]byte, error)

MarshalText ensures that the zero value for IQType is marshaled to XML as a valid IQ get request. It satisfies the encoding.TextMarshaler interface for IQType.

type Message Uses

type Message struct {
    XMLName xml.Name    `xml:"message"`
    ID      string      `xml:"id,attr,omitempty"`
    To      jid.JID     `xml:"to,attr,omitempty"`
    From    jid.JID     `xml:"from,attr,omitempty"`
    Lang    string      `xml:"http://www.w3.org/XML/1998/namespace lang,attr,omitempty"`
    Type    MessageType `xml:"type,attr,omitempty"`
}

Message is an XMPP stanza that contains a payload for direct one-to-one communication with another network entity. It is often used for sending chat messages to an individual or group chat server, or for notifications and alerts that don't require a response.

type MessageType Uses

type MessageType string

MessageType is the type of a message stanza. It should normally be one of the constants defined in this package.

const (
    // NormalMessage is a standalone message that is sent outside the context of a
    // one-to-one conversation or groupchat, and to which it is expected that the
    // recipient will reply. Typically a receiving client will present a message
    // of type "normal" in an interface that enables the recipient to reply, but
    // without a conversation history.
    NormalMessage MessageType = "normal"

    // ChatMessage represents a message sent in the context of a one-to-one chat
    // session.  Typically an interactive client will present a message of type
    // "chat" in an interface that enables one-to-one chat between the two
    // parties, including an appropriate conversation history.
    ChatMessage MessageType = "chat"

    // ErrorMessage is generated by an entity that experiences an error when
    // processing a message received from another entity.
    ErrorMessage MessageType = "error"

    // GroupChatMessage is sent in the context of a multi-user chat environment.
    // Typically a receiving client will present a message of type "groupchat" in
    // an interface that enables many-to-many chat between the parties, including
    // a roster of parties in the chatroom and an appropriate conversation
    // history.
    GroupChatMessage MessageType = "groupchat"

    // HeadlineMessage provides an alert, a notification, or other transient
    // information to which no reply is expected (e.g., news headlines, sports
    // updates, near-real-time market data, or syndicated content). Because no
    // reply to the message is expected, typically a receiving client will present
    // a message of type "headline" in an interface that appropriately
    // differentiates the message from standalone messages, chat messages, and
    // groupchat messages (e.g., by not providing the recipient with the ability
    // to reply).
    HeadlineMessage MessageType = "headline"
)

type Presence Uses

type Presence struct {
    XMLName xml.Name     `xml:"presence"`
    ID      string       `xml:"id,attr"`
    To      jid.JID      `xml:"to,attr"`
    From    jid.JID      `xml:"from,attr"`
    Lang    string       `xml:"http://www.w3.org/XML/1998/namespace lang,attr,omitempty"`
    Type    PresenceType `xml:"type,attr,omitempty"`
}

Presence is an XMPP stanza that is used as an indication that an entity is available for communication. It is used to set a status message, broadcast availability, and advertise entity capabilities. It can be directed (one-to-one), or used as a broadcast mechanism (one-to-many).

type PresenceType Uses

type PresenceType string

PresenceType is the type of a presence stanza. It should normally be one of the constants defined in this package.

const (
    // AvailablePresence is a special case that signals that the entity is
    // available for communication.
    AvailablePresence PresenceType = ""

    // ErrorPresence indicates that an error has occurred regarding processing of
    // a previously sent presence stanza; if the presence stanza is of type
    // "error", it MUST include an <error/> child element
    ErrorPresence PresenceType = "error"

    // ProbePresence is a request for an entity's current presence. It should
    // generally only be generated and sent by servers on behalf of a user.
    ProbePresence PresenceType = "probe"

    // SubscribePresence is sent when the sender wishes to subscribe to the
    // recipient's presence.
    SubscribePresence PresenceType = "subscribe"

    // SubscribedPresence indicates that the sender has allowed the recipient to
    // receive future presence broadcasts.
    SubscribedPresence PresenceType = "subscribed"

    // UnavailablePresence indicates that the sender is no longer available for
    // communication.
    UnavailablePresence PresenceType = "unavailable"

    // UnsubscribePresence indicates that the sender is unsubscribing from the
    // receiver's presence.
    UnsubscribePresence PresenceType = "unsubscribe"

    // UnsubscribedPresence indicates that the subscription request has been
    // denied, or a previously granted subscription has been revoked.
    UnsubscribedPresence PresenceType = "unsubscribed"
)

Package stanza imports 5 packages (graph) and is imported by 7 packages. Updated 2019-08-10. Refresh now. Tools for package owners.