-
-
Notifications
You must be signed in to change notification settings - Fork 24
/
Copy pathstanza.go
113 lines (95 loc) · 3.27 KB
/
stanza.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
// Copyright 2020 The Mellium Contributors.
// Use of this source code is governed by the BSD 2-clause
// license that can be found in the LICENSE file.
package stanza
import (
"encoding/xml"
"mellium.im/xmlstream"
"mellium.im/xmpp/internal/attr"
"mellium.im/xmpp/jid"
)
// Namespaces used by this package, provided as a convenience.
const (
// The namespace for unique and stable stanza and origin IDs.
NSSid = "urn:xmpp:sid:0"
// The namespace for delayed delivery.
NSDelay = "urn:xmpp:delay"
// The namespace used by stanza errors.
NSError = "urn:ietf:params:xml:ns:xmpp-stanzas"
// The namespace used by stanzas in the client-to-server protocol.
NSClient = "jabber:client"
// The namespace used by stanzas in the server-to-server protocol.
NSServer = "jabber:server"
)
const idLen = 32
// ID is a unique and stable stanza ID.
type ID struct {
XMLName xml.Name `xml:"urn:xmpp:sid:0 stanza-id"`
ID string `xml:"id,attr"`
By jid.JID `xml:"by,attr"`
}
// TokenReader implements xmlstream.Marshaler.
func (id ID) TokenReader() xml.TokenReader {
return xmlstream.Wrap(nil, xml.StartElement{
Name: xml.Name{Space: NSSid, Local: "stanza-id"},
Attr: []xml.Attr{
{Name: xml.Name{Local: "id"}, Value: id.ID},
{Name: xml.Name{Local: "by"}, Value: id.By.String()},
},
})
}
// WriteXML implements xmlstream.WriterTo.
func (id ID) WriteXML(w xmlstream.TokenWriter) (int, error) {
return xmlstream.Copy(w, id.TokenReader())
}
// OriginID is a unique and stable stanza ID generated by an originating entity
// that may want to hide its identity.
type OriginID struct {
XMLName xml.Name `xml:"urn:xmpp:sid:0 origin-id"`
ID string `xml:"id,attr"`
}
// TokenReader implements xmlstream.Marshaler.
func (id OriginID) TokenReader() xml.TokenReader {
return xmlstream.Wrap(nil, xml.StartElement{
Name: xml.Name{Space: NSSid, Local: "origin-id"},
Attr: []xml.Attr{
{Name: xml.Name{Local: "id"}, Value: id.ID},
},
})
}
// WriteXML implements xmlstream.WriterTo.
func (id OriginID) WriteXML(w xmlstream.TokenWriter) (int, error) {
return xmlstream.Copy(w, id.TokenReader())
}
// Is tests whether name is a valid stanza based on the localname and namespace.
// If stanzaNS is the empty string, Is matches any namespace.
func Is(name xml.Name, stanzaNS string) bool {
return (name.Local == "iq" || name.Local == "message" || name.Local == "presence") && (stanzaNS == "" || name.Space == stanzaNS)
}
// AddID returns an transformer that adds a random stanza ID to any stanzas that
// does not already have one.
func AddID(by jid.JID, stanzaNS string) xmlstream.Transformer {
return xmlstream.InsertFunc(func(start xml.StartElement, level uint64, w xmlstream.TokenWriter) error {
if Is(start.Name, stanzaNS) && level == 1 {
_, err := ID{
ID: attr.RandomLen(idLen),
By: by,
}.WriteXML(w)
return err
}
return nil
})
}
// AddOriginID is an xmlstream.Transformer that adds an origin ID to any stanzas
// found in the input stream.
func AddOriginID(r xml.TokenReader, stanzaNS string) xml.TokenReader {
return xmlstream.InsertFunc(func(start xml.StartElement, level uint64, w xmlstream.TokenWriter) error {
if Is(start.Name, stanzaNS) && level == 1 {
_, err := OriginID{
ID: attr.RandomLen(idLen),
}.WriteXML(w)
return err
}
return nil
})(r)
}