forked from jshiffer/go-xmpp
190 lines
4.8 KiB
Go
190 lines
4.8 KiB
Go
package stanza
|
|
|
|
import (
|
|
"encoding/xml"
|
|
)
|
|
|
|
// ============================================================================
|
|
// StreamFeatures Packet
|
|
// Reference: The active stream features are published on
|
|
// https://xmpp.org/registrar/stream-features.html
|
|
// Note: That page misses draft and experimental XEP (i.e CSI, etc)
|
|
|
|
type StreamFeatures struct {
|
|
XMLName xml.Name `xml:"http://etherx.jabber.org/streams features"`
|
|
// Server capabilities hash
|
|
Caps Caps
|
|
// Stream features
|
|
StartTLS TlsStartTLS
|
|
Mechanisms saslMechanisms
|
|
Bind Bind
|
|
StreamManagement streamManagement
|
|
// Obsolete
|
|
Session StreamSession
|
|
// ProcessOne Stream Features
|
|
P1Push p1Push
|
|
P1Rebind p1Rebind
|
|
p1Ack p1Ack
|
|
Any []xml.Name `xml:",any"`
|
|
}
|
|
|
|
func (StreamFeatures) Name() string {
|
|
return "stream:features"
|
|
}
|
|
|
|
type streamFeatureDecoder struct{}
|
|
|
|
var streamFeatures streamFeatureDecoder
|
|
|
|
func (streamFeatureDecoder) decode(p *xml.Decoder, se xml.StartElement) (StreamFeatures, error) {
|
|
var packet StreamFeatures
|
|
err := p.DecodeElement(&packet, &se)
|
|
return packet, err
|
|
}
|
|
|
|
// Capabilities
|
|
// Reference: https://xmpp.org/extensions/xep-0115.html#stream
|
|
// "A server MAY include its entity capabilities in a stream feature element so that connecting clients
|
|
// and peer servers do not need to send service discovery requests each time they connect."
|
|
// This is not a stream feature but a way to let client cache server disco info.
|
|
type Caps struct {
|
|
XMLName xml.Name `xml:"http://jabber.org/protocol/caps c"`
|
|
Hash string `xml:"hash,attr"`
|
|
Node string `xml:"node,attr"`
|
|
Ver string `xml:"ver,attr"`
|
|
Ext string `xml:"ext,attr,omitempty"`
|
|
}
|
|
|
|
// ============================================================================
|
|
// Supported Stream Features
|
|
|
|
// StartTLS feature
|
|
// Reference: RFC 6120 - https://tools.ietf.org/html/rfc6120#section-5.4
|
|
type TlsStartTLS struct {
|
|
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-tls starttls"`
|
|
Required bool
|
|
}
|
|
|
|
// UnmarshalXML implements custom parsing startTLS required flag
|
|
func (stls *TlsStartTLS) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
|
stls.XMLName = start.Name
|
|
|
|
// Check subelements to extract required field as boolean
|
|
for {
|
|
t, err := d.Token()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
switch tt := t.(type) {
|
|
|
|
case xml.StartElement:
|
|
elt := new(Node)
|
|
|
|
err = d.DecodeElement(elt, &tt)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if elt.XMLName.Local == "required" {
|
|
stls.Required = true
|
|
}
|
|
|
|
case xml.EndElement:
|
|
if tt == start.End() {
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (sf *StreamFeatures) DoesStartTLS() (feature TlsStartTLS, isSupported bool) {
|
|
if sf.StartTLS.XMLName.Space+" "+sf.StartTLS.XMLName.Local == nsTLS+" starttls" {
|
|
return sf.StartTLS, true
|
|
}
|
|
return feature, false
|
|
}
|
|
|
|
// Mechanisms
|
|
// Reference: RFC 6120 - https://tools.ietf.org/html/rfc6120#section-6.4.1
|
|
type saslMechanisms struct {
|
|
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-sasl mechanisms"`
|
|
Mechanism []string `xml:"mechanism"`
|
|
}
|
|
|
|
// StreamManagement
|
|
// Reference: XEP-0198 - https://xmpp.org/extensions/xep-0198.html#feature
|
|
type streamManagement struct {
|
|
XMLName xml.Name `xml:"urn:xmpp:sm:3 sm"`
|
|
}
|
|
|
|
func (streamManagement) Name() string {
|
|
return "streamManagement"
|
|
}
|
|
|
|
func (sf *StreamFeatures) DoesStreamManagement() (isSupported bool) {
|
|
if sf.StreamManagement.XMLName.Space+" "+sf.StreamManagement.XMLName.Local == "urn:xmpp:sm:3 sm" {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
// P1 extensions
|
|
// Reference: https://docs.ejabberd.im/developer/mobile/core-features/
|
|
|
|
// p1:push support
|
|
type p1Push struct {
|
|
XMLName xml.Name `xml:"p1:push push"`
|
|
}
|
|
|
|
// p1:rebind suppor
|
|
type p1Rebind struct {
|
|
XMLName xml.Name `xml:"p1:rebind rebind"`
|
|
}
|
|
|
|
// p1:ack support
|
|
type p1Ack struct {
|
|
XMLName xml.Name `xml:"p1:ack ack"`
|
|
}
|
|
|
|
// ============================================================================
|
|
// StreamError Packet
|
|
|
|
type StreamError struct {
|
|
XMLName xml.Name `xml:"http://etherx.jabber.org/streams error"`
|
|
Error xml.Name `xml:",any"`
|
|
Text string `xml:"urn:ietf:params:xml:ns:xmpp-streams text"`
|
|
}
|
|
|
|
func (StreamError) Name() string {
|
|
return "stream:error"
|
|
}
|
|
|
|
type streamErrorDecoder struct{}
|
|
|
|
var streamError streamErrorDecoder
|
|
|
|
func (streamErrorDecoder) decode(p *xml.Decoder, se xml.StartElement) (StreamError, error) {
|
|
var packet StreamError
|
|
err := p.DecodeElement(&packet, &se)
|
|
return packet, err
|
|
}
|
|
|
|
// ============================================================================
|
|
// StreamClose "Packet"
|
|
|
|
// This is just a closing tag and hold no information
|
|
type StreamClosePacket struct{}
|
|
|
|
func (StreamClosePacket) Name() string {
|
|
return "stream:stream"
|
|
}
|
|
|
|
type streamCloseDecoder struct{}
|
|
|
|
var streamClose streamCloseDecoder
|
|
|
|
func (streamCloseDecoder) decode(_ xml.EndElement) StreamClosePacket {
|
|
return StreamClosePacket{}
|
|
}
|