11 // Callback to handle a stanza with a particular id. |
11 // Callback to handle a stanza with a particular id. |
12 type callback struct { |
12 type callback struct { |
13 id string |
13 id string |
14 // Return true means pass this to the application |
14 // Return true means pass this to the application |
15 f func(Stanza) bool |
15 f func(Stanza) bool |
16 } |
|
17 |
|
18 // Receive XMLish structures, handle all the stream-related ones, and |
|
19 // send XMPP stanzas on to the client. |
|
20 func (cl *Client) recvStream(recvXml <-chan interface{}, sendXmpp chan<- Stanza) { |
|
21 defer close(sendXmpp) |
|
22 |
|
23 handlers := make(map[string]func(Stanza) bool) |
|
24 Loop: |
|
25 for { |
|
26 select { |
|
27 case h := <-cl.handlers: |
|
28 handlers[h.id] = h.f |
|
29 case x, ok := <-recvXml: |
|
30 if !ok { |
|
31 break Loop |
|
32 } |
|
33 switch obj := x.(type) { |
|
34 case *stream: |
|
35 handleStream(obj) |
|
36 case *streamError: |
|
37 cl.handleStreamError(obj) |
|
38 case *Features: |
|
39 cl.handleFeatures(obj) |
|
40 case *starttls: |
|
41 cl.handleTls(obj) |
|
42 case *auth: |
|
43 cl.handleSasl(obj) |
|
44 case Stanza: |
|
45 send := true |
|
46 id := obj.GetHeader().Id |
|
47 if handlers[id] != nil { |
|
48 f := handlers[id] |
|
49 delete(handlers, id) |
|
50 send = f(obj) |
|
51 } |
|
52 if send { |
|
53 sendXmpp <- obj |
|
54 } |
|
55 default: |
|
56 Warn.Logf("Unhandled non-stanza: %T %#v", x, x) |
|
57 } |
|
58 } |
|
59 } |
|
60 } |
16 } |
61 |
17 |
62 // Receive XMPP stanzas from the client and send them on to the |
18 // Receive XMPP stanzas from the client and send them on to the |
63 // remote. Don't allow the client to send us any stanzas until |
19 // remote. Don't allow the client to send us any stanzas until |
64 // negotiation has completed. This loop is paused until resource |
20 // negotiation has completed. This loop is paused until resource |
94 sendXml <- x |
50 sendXml <- x |
95 } |
51 } |
96 } |
52 } |
97 } |
53 } |
98 |
54 |
99 func handleStream(ss *stream) { |
55 // Receive XMLish structures, handle all the stream-related ones, and |
|
56 // send XMPP stanzas on to the client. |
|
57 func (cl *Client) recvStream(recvXml <-chan interface{}, sendXmpp chan<- Stanza) { |
|
58 defer close(sendXmpp) |
|
59 |
|
60 handlers := make(map[string]func(Stanza) bool) |
|
61 for { |
|
62 select { |
|
63 case h := <-cl.handlers: |
|
64 handlers[h.id] = h.f |
|
65 case x, ok := <-recvXml: |
|
66 if !ok { |
|
67 return |
|
68 } |
|
69 switch obj := x.(type) { |
|
70 case *stream: |
|
71 // Do nothing. |
|
72 case *streamError: |
|
73 cl.handleStreamError(obj) |
|
74 case *Features: |
|
75 cl.handleFeatures(obj) |
|
76 case *starttls: |
|
77 cl.handleTls(obj) |
|
78 case *auth: |
|
79 cl.handleSasl(obj) |
|
80 case Stanza: |
|
81 send := true |
|
82 id := obj.GetHeader().Id |
|
83 if handlers[id] != nil { |
|
84 f := handlers[id] |
|
85 delete(handlers, id) |
|
86 send = f(obj) |
|
87 } |
|
88 if send { |
|
89 sendXmpp <- obj |
|
90 } |
|
91 default: |
|
92 Warn.Logf("Unhandled non-stanza: %T %#v", x, x) |
|
93 } |
|
94 } |
|
95 } |
100 } |
96 } |
101 |
97 |
102 func (cl *Client) handleStreamError(se *streamError) { |
98 func (cl *Client) handleStreamError(se *streamError) { |
103 Info.Logf("Received stream error: %v", se) |
99 Info.Logf("Received stream error: %v", se) |
104 cl.inputControl <- sendAbort |
100 cl.inputControl <- sendAbort |
128 cl.layer1.startTls(&cl.tlsConfig) |
124 cl.layer1.startTls(&cl.tlsConfig) |
129 |
125 |
130 // Now re-send the initial handshake message to start the new |
126 // Now re-send the initial handshake message to start the new |
131 // session. |
127 // session. |
132 cl.sendXml <- &stream{To: cl.Jid.Domain, Version: XMPPVersion} |
128 cl.sendXml <- &stream{To: cl.Jid.Domain, Version: XMPPVersion} |
133 } |
|
134 |
|
135 // Register a callback to handle the next XMPP stanza (iq, message, or |
|
136 // presence) with a given id. The provided function will not be called |
|
137 // more than once. If it returns false, the stanza will not be made |
|
138 // available on the normal Client.Recv channel. The callback must not |
|
139 // read from that channel, as deliveries on it cannot proceed until |
|
140 // the handler returns true or false. |
|
141 func (cl *Client) SetCallback(id string, f func(Stanza) bool) { |
|
142 h := &callback{id: id, f: f} |
|
143 cl.handlers <- h |
|
144 } |
129 } |
145 |
130 |
146 // Send a request to bind a resource. RFC 3920, section 7. |
131 // Send a request to bind a resource. RFC 3920, section 7. |
147 func (cl *Client) bind() { |
132 func (cl *Client) bind() { |
148 res := cl.Jid.Resource |
133 res := cl.Jid.Resource |
188 return false |
173 return false |
189 } |
174 } |
190 cl.SetCallback(msg.Id, f) |
175 cl.SetCallback(msg.Id, f) |
191 cl.sendXml <- msg |
176 cl.sendXml <- msg |
192 } |
177 } |
|
178 |
|
179 // Register a callback to handle the next XMPP stanza (iq, message, or |
|
180 // presence) with a given id. The provided function will not be called |
|
181 // more than once. If it returns false, the stanza will not be made |
|
182 // available on the normal Client.Recv channel. The callback must not |
|
183 // read from that channel, as deliveries on it cannot proceed until |
|
184 // the handler returns true or false. |
|
185 func (cl *Client) SetCallback(id string, f func(Stanza) bool) { |
|
186 h := &callback{id: id, f: f} |
|
187 cl.handlers <- h |
|
188 } |