From 6fbfe9fd0a422c49ca333f20803b329fa9b42b95 Mon Sep 17 00:00:00 2001 From: genofire Date: Mon, 24 Jun 2019 12:20:44 +0200 Subject: [PATCH 1/5] Update pres_muc_test.go --- pres_muc_test.go | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/pres_muc_test.go b/pres_muc_test.go index b2120e3..7200fc0 100644 --- a/pres_muc_test.go +++ b/pres_muc_test.go @@ -58,3 +58,35 @@ func TestMucHistory(t *testing.T) { t.Errorf("incorrect max stanza: '%d'", muc.History.MaxStanzas) } } + +// https://xmpp.org/extensions/xep-0045.html#example-37 +func TestMucNoHistory(t *testing.T) { + str := ` + + + +` + + pres := xmpp.Presence{Attrs: xmpp.Attrs{ + From: "hag66@shakespeare.lit/pda", + Id: "n13mt3l", + To: "coven@chat.shakespeare.lit/thirdwitch", + }, + Extensions: []xmpp.PresExtension{ + xmpp.MucPresence{ + History: xmpp.History{MaxStanzas: 0}, + }, + }, + } + data, err := xml.Marshal(&pres) + if err != nil { + t.Error("error on encode:", err) + } + + if data != str { + t.Errorf("incorrect max stanza: '%d'", muc.History.MaxStanzas) + } +} From 19717723945d3d40374ba5929bfc7b1cc6b3539b Mon Sep 17 00:00:00 2001 From: Martin/Geno Date: Mon, 24 Jun 2019 16:38:22 +0200 Subject: [PATCH 2/5] fix everything --- pres_muc.go | 8 ++++---- pres_muc_test.go | 34 ++++++++++++++++++---------------- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/pres_muc.go b/pres_muc.go index 10d947e..b61f0ae 100644 --- a/pres_muc.go +++ b/pres_muc.go @@ -18,10 +18,10 @@ type MucPresence struct { // History implements XEP-0045: Multi-User Chat - 19.1 type History struct { - MaxChars int `xml:"maxchars,attr,omitempty"` - MaxStanzas int `xml:"maxstanzas,attr,omitempty"` - Seconds int `xml:"seconds,attr,omitempty"` - Since time.Time `xml:"since,attr,omitempty"` + MaxChars *int `xml:"maxchars,attr,omitempty"` + MaxStanzas *int `xml:"maxstanzas,attr,omitempty"` + Seconds *int `xml:"seconds,attr,omitempty"` + Since *time.Time `xml:"since,attr,omitempty"` } func init() { diff --git a/pres_muc_test.go b/pres_muc_test.go index 7200fc0..532bc0a 100644 --- a/pres_muc_test.go +++ b/pres_muc_test.go @@ -54,30 +54,32 @@ func TestMucHistory(t *testing.T) { t.Error("muc presence extension was not found") } - if muc.History.MaxStanzas != 20 { + if *muc.History.MaxStanzas != 20 { t.Errorf("incorrect max stanza: '%d'", muc.History.MaxStanzas) } } // https://xmpp.org/extensions/xep-0045.html#example-37 func TestMucNoHistory(t *testing.T) { - str := ` - - - -` + str := "" + + "" + + "" + + "" + + "" + + maxstanzas := 0 pres := xmpp.Presence{Attrs: xmpp.Attrs{ - From: "hag66@shakespeare.lit/pda", - Id: "n13mt3l", - To: "coven@chat.shakespeare.lit/thirdwitch", - }, + From: "hag66@shakespeare.lit/pda", + Id: "n13mt3l", + To: "coven@chat.shakespeare.lit/thirdwitch", + }, Extensions: []xmpp.PresExtension{ xmpp.MucPresence{ - History: xmpp.History{MaxStanzas: 0}, + History: xmpp.History{MaxStanzas: &maxstanzas}, }, }, } @@ -86,7 +88,7 @@ func TestMucNoHistory(t *testing.T) { t.Error("error on encode:", err) } - if data != str { - t.Errorf("incorrect max stanza: '%d'", muc.History.MaxStanzas) + if string(data) != str { + t.Errorf("incorrect stanza: \n%s\n%s", str, data) } } From 0ee4764d31e1f6a595368c6aa76d107ec757ebff Mon Sep 17 00:00:00 2001 From: Mickael Remond Date: Wed, 26 Jun 2019 18:25:17 +0200 Subject: [PATCH 3/5] Update error.go Fix typo in comment --- error.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/error.go b/error.go index 2fe542f..a4b4f17 100644 --- a/error.go +++ b/error.go @@ -27,7 +27,7 @@ func (x *Err) Namespace() string { return x.XMLName.Space } -// UnmarshalXML implements custom parsing for IQs +// UnmarshalXML implements custom parsing for XMPP errors func (x *Err) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { x.XMLName = start.Name From 3d088a6078ebac5e2d7ac9eb8c0872a72eb72846 Mon Sep 17 00:00:00 2001 From: Mickael Remond Date: Wed, 26 Jun 2019 18:25:59 +0200 Subject: [PATCH 4/5] Use NullableInt to encode presence history values --- pres_muc.go | 127 +++++++++++++++++++++++++++++++++++++++++++++-- pres_muc_test.go | 11 ++-- 2 files changed, 130 insertions(+), 8 deletions(-) diff --git a/pres_muc.go b/pres_muc.go index b61f0ae..f7ae599 100644 --- a/pres_muc.go +++ b/pres_muc.go @@ -2,6 +2,7 @@ package xmpp import ( "encoding/xml" + "strconv" "time" ) @@ -16,12 +17,130 @@ type MucPresence struct { History History `xml:"history,omitempty"` } +const timeLayout = "2006-01-02T15:04:05Z" + // History implements XEP-0045: Multi-User Chat - 19.1 type History struct { - MaxChars *int `xml:"maxchars,attr,omitempty"` - MaxStanzas *int `xml:"maxstanzas,attr,omitempty"` - Seconds *int `xml:"seconds,attr,omitempty"` - Since *time.Time `xml:"since,attr,omitempty"` + 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() { diff --git a/pres_muc_test.go b/pres_muc_test.go index 532bc0a..5b8db83 100644 --- a/pres_muc_test.go +++ b/pres_muc_test.go @@ -46,16 +46,18 @@ func TestMucHistory(t *testing.T) { var parsedPresence xmpp.Presence 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 xmpp.MucPresence if ok := parsedPresence.Get(&muc); !ok { t.Error("muc presence extension was not found") + return } - if *muc.History.MaxStanzas != 20 { - t.Errorf("incorrect max stanza: '%d'", muc.History.MaxStanzas) + if v, ok := muc.History.MaxStanzas.Get(); !ok || v != 20 { + t.Errorf("incorrect MaxStanzas: '%#v'", muc.History.MaxStanzas) } } @@ -79,13 +81,14 @@ func TestMucNoHistory(t *testing.T) { }, Extensions: []xmpp.PresExtension{ xmpp.MucPresence{ - History: xmpp.History{MaxStanzas: &maxstanzas}, + History: xmpp.History{MaxStanzas: xmpp.NewNullableInt(maxstanzas)}, }, }, } data, err := xml.Marshal(&pres) if err != nil { t.Error("error on encode:", err) + return } if string(data) != str { From 80f32b4af7f51477eb5c06d0a3aba4076586a86a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20R=C3=A9mond?= Date: Thu, 27 Jun 2019 09:47:08 +0200 Subject: [PATCH 5/5] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index accab4a..b9ba409 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,6 @@ func handleMessage(s xmpp.Sender, p xmpp.Packet) { } ``` -## Documentation +## Reference documentation -Please, check GoDoc for more information: [gosrc.io/xmpp](https://godoc.org/gosrc.io/xmpp) +The code documentation is available on GoDoc: [gosrc.io/xmpp](https://godoc.org/gosrc.io/xmpp)