8798ff6fc1
- Fixed commands from v 0.4.0 and tests - Added primitive Result Sets support (XEP-0059)
149 lines
3.2 KiB
Go
149 lines
3.2 KiB
Go
package stanza
|
|
|
|
import (
|
|
"encoding/xml"
|
|
"strconv"
|
|
"time"
|
|
)
|
|
|
|
// ============================================================================
|
|
// MUC Presence extension
|
|
|
|
// MucPresence implements XEP-0045: Multi-User Chat - 19.1
|
|
type MucPresence struct {
|
|
PresExtension
|
|
XMLName xml.Name `xml:"http://jabber.org/protocol/muc x"`
|
|
Password string `xml:"password,omitempty"`
|
|
History History `xml:"history,omitempty"`
|
|
}
|
|
|
|
const timeLayout = "2006-01-02T15:04:05Z"
|
|
|
|
// History implements XEP-0045: Multi-User Chat - 19.1
|
|
type History struct {
|
|
XMLName xml.Name
|
|
MaxChars NullableInt `xml:"maxchars,attr,omitempty"`
|
|
MaxStanzas NullableInt `xml:"maxstanzas,attr,omitempty"`
|
|
Seconds NullableInt `xml:"seconds,attr,omitempty"`
|
|
Since time.Time `xml:"since,attr,omitempty"`
|
|
}
|
|
|
|
type NullableInt struct {
|
|
Value int
|
|
isSet bool
|
|
}
|
|
|
|
func NewNullableInt(val int) NullableInt {
|
|
return NullableInt{val, true}
|
|
}
|
|
|
|
func (n NullableInt) Get() (v int, ok bool) {
|
|
return n.Value, n.isSet
|
|
}
|
|
|
|
// UnmarshalXML implements custom parsing for history element
|
|
func (h *History) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
|
h.XMLName = start.Name
|
|
|
|
// Extract attributes
|
|
for _, attr := range start.Attr {
|
|
switch attr.Name.Local {
|
|
case "maxchars":
|
|
v, err := strconv.Atoi(attr.Value)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
h.MaxChars = NewNullableInt(v)
|
|
case "maxstanzas":
|
|
v, err := strconv.Atoi(attr.Value)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
h.MaxStanzas = NewNullableInt(v)
|
|
case "seconds":
|
|
v, err := strconv.Atoi(attr.Value)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
h.Seconds = NewNullableInt(v)
|
|
case "since":
|
|
t, err := time.Parse(timeLayout, attr.Value)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
h.Since = t
|
|
}
|
|
}
|
|
|
|
// Consume remaining data until element end
|
|
for {
|
|
t, err := d.Token()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
switch tt := t.(type) {
|
|
case xml.EndElement:
|
|
if tt == start.End() {
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (h History) MarshalXML(e *xml.Encoder, start xml.StartElement) (err error) {
|
|
mc, isMcSet := h.MaxChars.Get()
|
|
ms, isMsSet := h.MaxStanzas.Get()
|
|
s, isSSet := h.Seconds.Get()
|
|
|
|
// We do not have any value, ignore history element
|
|
if h.Since.IsZero() && !isMcSet && !isMsSet && !isSSet {
|
|
return nil
|
|
}
|
|
|
|
// Encode start element and attributes
|
|
start.Name = xml.Name{Local: "history"}
|
|
|
|
if isMcSet {
|
|
attr := xml.Attr{
|
|
Name: xml.Name{Local: "maxchars"},
|
|
Value: strconv.Itoa(mc),
|
|
}
|
|
start.Attr = append(start.Attr, attr)
|
|
}
|
|
|
|
if isMsSet {
|
|
attr := xml.Attr{
|
|
Name: xml.Name{Local: "maxstanzas"},
|
|
Value: strconv.Itoa(ms),
|
|
}
|
|
start.Attr = append(start.Attr, attr)
|
|
}
|
|
|
|
if isSSet {
|
|
attr := xml.Attr{
|
|
Name: xml.Name{Local: "seconds"},
|
|
Value: strconv.Itoa(s),
|
|
}
|
|
start.Attr = append(start.Attr, attr)
|
|
}
|
|
|
|
if !h.Since.IsZero() {
|
|
attr := xml.Attr{
|
|
Name: xml.Name{Local: "since"},
|
|
Value: h.Since.Format(timeLayout),
|
|
}
|
|
start.Attr = append(start.Attr, attr)
|
|
}
|
|
if err := e.EncodeToken(start); err != nil {
|
|
return err
|
|
}
|
|
|
|
return e.EncodeToken(xml.EndElement{Name: start.Name})
|
|
|
|
}
|
|
|
|
func init() {
|
|
TypeRegistry.MapExtension(PKTPresence, xml.Name{Space: "http://jabber.org/protocol/muc", Local: "x"}, MucPresence{})
|
|
}
|