go-xmpp/stanza/presence.go

140 lines
3.3 KiB
Go
Raw Permalink Normal View History

package stanza
import (
"encoding/xml"
"reflect"
)
2018-01-13 17:50:17 +00:00
// ============================================================================
// Presence Packet
// Presence implements RFC 6120 - A.5 Client Namespace (a part)
2018-01-13 17:50:17 +00:00
type Presence struct {
XMLName xml.Name `xml:"presence"`
Attrs
Show PresenceShow `xml:"show,omitempty"`
Status string `xml:"status,omitempty"`
Priority int8 `xml:"priority,omitempty"` // default: 0
Error Err `xml:"error,omitempty"`
Extensions []PresExtension `xml:",omitempty"`
}
2018-01-13 17:50:17 +00:00
func (Presence) Name() string {
return "presence"
}
func NewPresence(a Attrs) Presence {
2018-01-25 10:00:20 +00:00
return Presence{
XMLName: xml.Name{Local: "presence"},
Attrs: a,
2018-01-25 10:00:20 +00:00
}
}
// Get search and extracts a specific extension on a presence stanza.
// It receives a pointer to an PresExtension. It will panic if the caller
// does not pass a pointer.
// It will return true if the passed extension is found and set the pointer
// to the extension passed as parameter to the found extension.
// It will return false if the extension is not found on the presence.
//
// Example usage:
// var muc xmpp.MucPresence
// if ok := msg.Get(&muc); ok {
// // muc presence extension has been found
// }
func (pres *Presence) Get(ext PresExtension) bool {
target := reflect.ValueOf(ext)
if target.Kind() != reflect.Ptr {
panic("you must pass a pointer to the message Get method")
}
for _, e := range pres.Extensions {
if reflect.TypeOf(e) == target.Type() {
source := reflect.ValueOf(e)
if source.Kind() != reflect.Ptr {
source = source.Elem()
}
target.Elem().Set(source.Elem())
return true
}
}
return false
}
2018-01-13 17:50:17 +00:00
type presenceDecoder struct{}
var presence presenceDecoder
func (presenceDecoder) decode(p *xml.Decoder, se xml.StartElement) (Presence, error) {
var packet Presence
err := p.DecodeElement(&packet, &se)
2018-01-23 08:08:21 +00:00
// TODO Add default presence type (when omitted)
2018-01-13 17:50:17 +00:00
return packet, err
}
// UnmarshalXML implements custom parsing for presence stanza
func (pres *Presence) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
pres.XMLName = start.Name
// Extract packet attributes
for _, attr := range start.Attr {
if attr.Name.Local == "id" {
pres.Id = attr.Value
}
if attr.Name.Local == "type" {
pres.Type = StanzaType(attr.Value)
}
if attr.Name.Local == "to" {
pres.To = attr.Value
}
if attr.Name.Local == "from" {
pres.From = attr.Value
}
if attr.Name.Local == "lang" {
pres.Lang = attr.Value
}
}
// decode inner elements
for {
t, err := d.Token()
if err != nil {
return err
}
switch tt := t.(type) {
case xml.StartElement:
if presExt := TypeRegistry.GetPresExtension(tt.Name); presExt != nil {
// Decode message extension
err = d.DecodeElement(presExt, &tt)
if err != nil {
return err
}
pres.Extensions = append(pres.Extensions, presExt)
} else {
// Decode standard message sub-elements
var err error
switch tt.Name.Local {
case "show":
err = d.DecodeElement(&pres.Show, &tt)
case "status":
err = d.DecodeElement(&pres.Status, &tt)
case "priority":
err = d.DecodeElement(&pres.Priority, &tt)
case "error":
err = d.DecodeElement(&pres.Error, &tt)
}
if err != nil {
return err
}
}
case xml.EndElement:
if tt == start.End() {
return nil
}
}
}
}