mirror of
https://github.com/FluuxIO/go-xmpp.git
synced 2024-11-21 10:02:00 -08:00
Resync with Master
Support NullableInt on MUC presence history element
This commit is contained in:
parent
5ed66de79e
commit
781b875cf1
@ -2,6 +2,7 @@ package stanza
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -16,14 +17,132 @@ type MucPresence struct {
|
|||||||
History History `xml:"history,omitempty"`
|
History History `xml:"history,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const timeLayout = "2006-01-02T15:04:05Z"
|
||||||
|
|
||||||
// History implements XEP-0045: Multi-User Chat - 19.1
|
// History implements XEP-0045: Multi-User Chat - 19.1
|
||||||
type History struct {
|
type History struct {
|
||||||
MaxChars int `xml:"maxchars,attr,omitempty"`
|
XMLName xml.Name
|
||||||
MaxStanzas int `xml:"maxstanzas,attr,omitempty"`
|
MaxChars NullableInt `xml:"maxchars,attr,omitempty"`
|
||||||
Seconds int `xml:"seconds,attr,omitempty"`
|
MaxStanzas NullableInt `xml:"maxstanzas,attr,omitempty"`
|
||||||
|
Seconds NullableInt `xml:"seconds,attr,omitempty"`
|
||||||
Since time.Time `xml:"since,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() {
|
func init() {
|
||||||
TypeRegistry.MapExtension(PKTPresence, xml.Name{"http://jabber.org/protocol/muc", "x"}, MucPresence{})
|
TypeRegistry.MapExtension(PKTPresence, xml.Name{"http://jabber.org/protocol/muc", "x"}, MucPresence{})
|
||||||
}
|
}
|
||||||
|
@ -46,15 +46,52 @@ func TestMucHistory(t *testing.T) {
|
|||||||
|
|
||||||
var parsedPresence stanza.Presence
|
var parsedPresence stanza.Presence
|
||||||
if err := xml.Unmarshal([]byte(str), &parsedPresence); err != nil {
|
if err := xml.Unmarshal([]byte(str), &parsedPresence); err != nil {
|
||||||
t.Errorf("Unmarshal(%s) returned error", str)
|
t.Errorf("Unmarshal(%s) returned error: %s", str, err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var muc stanza.MucPresence
|
var muc stanza.MucPresence
|
||||||
if ok := parsedPresence.Get(&muc); !ok {
|
if ok := parsedPresence.Get(&muc); !ok {
|
||||||
t.Error("muc presence extension was not found")
|
t.Error("muc presence extension was not found")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if muc.History.MaxStanzas != 20 {
|
if v, ok := muc.History.MaxStanzas.Get(); !ok || v != 20 {
|
||||||
t.Errorf("incorrect max stanza: '%d'", muc.History.MaxStanzas)
|
t.Errorf("incorrect MaxStanzas: '%#v'", muc.History.MaxStanzas)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://xmpp.org/extensions/xep-0045.html#example-37
|
||||||
|
func TestMucNoHistory(t *testing.T) {
|
||||||
|
str := "<presence" +
|
||||||
|
" id=\"n13mt3l\"" +
|
||||||
|
" from=\"hag66@shakespeare.lit/pda\"" +
|
||||||
|
" to=\"coven@chat.shakespeare.lit/thirdwitch\">" +
|
||||||
|
"<x xmlns=\"http://jabber.org/protocol/muc\">" +
|
||||||
|
"<history maxstanzas=\"0\"></history>" +
|
||||||
|
"</x>" +
|
||||||
|
"</presence>"
|
||||||
|
|
||||||
|
maxstanzas := 0
|
||||||
|
|
||||||
|
pres := stanza.Presence{Attrs: stanza.Attrs{
|
||||||
|
From: "hag66@shakespeare.lit/pda",
|
||||||
|
Id: "n13mt3l",
|
||||||
|
To: "coven@chat.shakespeare.lit/thirdwitch",
|
||||||
|
},
|
||||||
|
Extensions: []stanza.PresExtension{
|
||||||
|
stanza.MucPresence{
|
||||||
|
History: stanza.History{MaxStanzas: stanza.NewNullableInt(maxstanzas)},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
data, err := xml.Marshal(&pres)
|
||||||
|
if err != nil {
|
||||||
|
t.Error("error on encode:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if string(data) != str {
|
||||||
|
t.Errorf("incorrect stanza: \n%s\n%s", str, data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user