152 lines
4.6 KiB
Go
152 lines
4.6 KiB
Go
// Copyright 2016 The Mellium Contributors.
|
|
// Use of this source code is governed by the BSD 2-clause
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package stanza
|
|
|
|
import (
|
|
"encoding/xml"
|
|
|
|
"mellium.im/xmlstream"
|
|
"mellium.im/xmpp/internal/ns"
|
|
"mellium.im/xmpp/jid"
|
|
)
|
|
|
|
// 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 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"`
|
|
}
|
|
|
|
// NewPresence unmarshals an XML token into a Presence.
|
|
func NewPresence(start xml.StartElement) (Presence, error) {
|
|
v := Presence{
|
|
XMLName: start.Name,
|
|
}
|
|
for _, attr := range start.Attr {
|
|
if attr.Name.Local == "lang" && attr.Name.Space == ns.XML {
|
|
v.Lang = attr.Value
|
|
continue
|
|
}
|
|
if attr.Name.Space != "" && attr.Name.Space != start.Name.Space {
|
|
continue
|
|
}
|
|
|
|
var err error
|
|
switch attr.Name.Local {
|
|
case "id":
|
|
v.ID = attr.Value
|
|
case "to":
|
|
if attr.Value != "" {
|
|
v.To, err = jid.Parse(attr.Value)
|
|
if err != nil {
|
|
return v, err
|
|
}
|
|
}
|
|
case "from":
|
|
if attr.Value != "" {
|
|
v.From, err = jid.Parse(attr.Value)
|
|
if err != nil {
|
|
return v, err
|
|
}
|
|
}
|
|
case "type":
|
|
v.Type = PresenceType(attr.Value)
|
|
}
|
|
}
|
|
return v, nil
|
|
}
|
|
|
|
// StartElement converts the Presence into an XML token.
|
|
func (p Presence) StartElement() xml.StartElement {
|
|
// Keep whatever namespace we're already using but make sure the localname is
|
|
// "presence".
|
|
name := p.XMLName
|
|
name.Local = "presence"
|
|
|
|
attr := make([]xml.Attr, 0, 5)
|
|
if p.Type != "" {
|
|
attr = append(attr, xml.Attr{Name: xml.Name{Local: "type"}, Value: string(p.Type)})
|
|
}
|
|
if !p.To.Equal(jid.JID{}) {
|
|
attr = append(attr, xml.Attr{Name: xml.Name{Local: "to"}, Value: p.To.String()})
|
|
}
|
|
if !p.From.Equal(jid.JID{}) {
|
|
attr = append(attr, xml.Attr{Name: xml.Name{Local: "from"}, Value: p.From.String()})
|
|
}
|
|
if p.ID != "" {
|
|
attr = append(attr, xml.Attr{Name: xml.Name{Local: "id"}, Value: p.ID})
|
|
}
|
|
if p.Lang != "" {
|
|
attr = append(attr, xml.Attr{Name: xml.Name{Space: ns.XML, Local: "lang"}, Value: p.Lang})
|
|
}
|
|
|
|
return xml.StartElement{
|
|
Name: name,
|
|
Attr: attr,
|
|
}
|
|
}
|
|
|
|
// Wrap wraps the payload in a stanza.
|
|
//
|
|
// If to is the zero value for jid.JID, no to attribute is set on the resulting
|
|
// presence.
|
|
func (p Presence) Wrap(payload xml.TokenReader) xml.TokenReader {
|
|
return xmlstream.Wrap(payload, p.StartElement())
|
|
}
|
|
|
|
// Error returns a token reader that wraps the provided Error in a presence
|
|
// stanza with the to and from attributes switched and the type set to
|
|
// ErrorPresence.
|
|
func (p Presence) Error(err Error) xml.TokenReader {
|
|
p.Type = ErrorPresence
|
|
p.From, p.To = p.To, p.From
|
|
return p.Wrap(err.TokenReader())
|
|
}
|
|
|
|
// PresenceType is the type of a presence stanza.
|
|
// It should normally be one of the constants defined in this package.
|
|
type PresenceType string
|
|
|
|
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"
|
|
)
|