-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbind_feature.go
More file actions
129 lines (112 loc) · 3 KB
/
bind_feature.go
File metadata and controls
129 lines (112 loc) · 3 KB
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package xmppcore
import (
"errors"
"strings"
"github.com/jackal-xmpp/stravaganza/v2"
)
var (
ErrNotIqBind = errors.New("not iq bind")
)
type IqBind struct {
IQ Stanza
Resource string
JID string
}
func (ib *IqBind) FromElem(elem stravaganza.Element) error {
if err := ib.IQ.FromElem(elem, NameIQ); err != nil {
return err
}
if b := elem.Child("bind"); b == nil {
return ErrNotIqBind
} else if b.Name() != "bind" || b.Attribute("xmlns") != NSBind {
return ErrNotIqBind
} else if r := b.Child("resource"); r != nil {
ib.Resource = r.Text()
} else if jid := b.Child("jid"); jid != nil {
ib.JID = jid.Text()
}
return nil
}
func (ib IqBind) ToElem(elem *stravaganza.Element) {
b := stravaganza.NewBuilder("bind").WithAttribute("xmlns", NSBind)
if ib.IQ.Type == TypeSet && ib.Resource != "" {
b.WithChild(stravaganza.NewBuilder("resource").WithText(ib.Resource).Build())
} else if ib.IQ.Type == TypeResult && ib.JID != "" {
b.WithChild(stravaganza.NewBuilder("jid").WithText(ib.JID).Build())
}
*elem = ib.IQ.ToElemBuilder().WithChild(b.Build()).Build()
}
type bindFeature struct {
rsb ResourceBinder
handled bool
mandatory bool
ib IqBind
IDAble
}
type ResourceBinder interface {
BindResource(part Part, resource string) (string, error)
}
const (
NSBind = "urn:ietf:params:xml:ns:xmpp-bind"
NSStanza = "urn:ietf:params:xml:ns:xmpp-stanzas"
BEResourceConstraint = "wait: resource constraint"
BENotAllowed = "cancel: not allowed"
)
func BindErrFromError(id string, err error) StanzaErr {
ss := strings.Split(err.Error(), ":")
errTag := strings.Trim(ss[1], " ")
return StanzaErr{
Stanza: Stanza{
ID: id,
Type: TypeError,
}, Err: Err{
Type: ss[0],
Desc: []ErrDesc{{Tag: errTag, Xmlns: NSStanza}},
},
}
}
func BindFeature(rsb ResourceBinder) bindFeature {
return bindFeature{IDAble: CreateIDAble(), rsb: rsb, handled: false, mandatory: false}
}
func (bf bindFeature) Mandatory() bool {
return bf.mandatory
}
func (bf bindFeature) Elem() stravaganza.Element {
elem := stravaganza.NewBuilder("bind").WithAttribute("xmlns", NSBind)
if bf.mandatory {
elem.WithChild(stravaganza.NewBuilder("required").Build())
}
return elem.Build()
}
func (bf *bindFeature) match(elem stravaganza.Element) bool {
if err := bf.ib.FromElem(elem); err != nil {
return false
}
if bf.ib.IQ.Type != TypeSet || bf.ib.IQ.Name != NameIQ || bf.ib.IQ.ID == "" {
return false
}
return true
}
func (bf bindFeature) Handled() bool {
return bf.handled
}
func (bf *bindFeature) Handle(elem stravaganza.Element, part Part) (cached bool, err error) {
if !bf.match(elem) {
return false, nil
}
bf.handled = true
rsc, err := bf.rsb.BindResource(part, bf.ib.Resource)
if err != nil {
BindErrFromError(bf.ib.IQ.ID, err).ToElem(&elem)
part.Channel().SendElement(elem)
return
}
IqBind{IQ: Stanza{
ID: bf.ib.IQ.ID,
Name: NameIQ,
Type: TypeResult,
To: bf.ib.IQ.From,
From: part.Attr().Domain}, JID: rsc}.ToElem(&elem)
err = part.Channel().SendElement(elem)
return
}