93 } |
98 } |
94 if doSend { |
99 if doSend { |
95 sendXmpp <- obj |
100 sendXmpp <- obj |
96 } |
101 } |
97 default: |
102 default: |
98 Warn.Logf("Unhandled non-stanza: %T %#v", x, x) |
103 if Debug { |
99 } |
104 log.Printf("Unrecognized input: %T %#v", |
100 } |
105 x, x) |
101 } |
106 } |
102 } |
107 } |
103 |
108 } |
104 func (cl *Client) handleStreamError(se *streamError) { |
109 } |
105 Info.Logf("Received stream error: %v", se) |
|
106 cl.setStatus(StatusShutdown) |
|
107 } |
110 } |
108 |
111 |
109 func (cl *Client) handleFeatures(fe *Features) { |
112 func (cl *Client) handleFeatures(fe *Features) { |
110 cl.Features = fe |
113 cl.Features = fe |
111 if fe.Starttls != nil { |
114 if fe.Starttls != nil { |
112 start := &starttls{XMLName: xml.Name{Space: NsTLS, |
115 start := &starttls{XMLName: xml.Name{Space: NsTLS, |
113 Local: "starttls"}} |
116 Local: "starttls"}} |
114 cl.sendXml <- start |
117 cl.sendRaw <- start |
115 return |
118 return |
116 } |
119 } |
117 |
120 |
118 if len(fe.Mechanisms.Mechanism) > 0 { |
121 if len(fe.Mechanisms.Mechanism) > 0 { |
119 cl.chooseSasl(fe) |
122 cl.chooseSasl(fe) |
131 |
134 |
132 cl.setStatus(StatusConnectedTls) |
135 cl.setStatus(StatusConnectedTls) |
133 |
136 |
134 // Now re-send the initial handshake message to start the new |
137 // Now re-send the initial handshake message to start the new |
135 // session. |
138 // session. |
136 cl.sendXml <- &stream{To: cl.Jid.Domain, Version: XMPPVersion} |
139 cl.sendRaw <- &stream{To: cl.Jid.Domain, Version: XMPPVersion} |
137 } |
140 } |
138 |
141 |
139 // Send a request to bind a resource. RFC 3920, section 7. |
142 // Send a request to bind a resource. RFC 3920, section 7. |
140 func (cl *Client) bind() { |
143 func (cl *Client) bind() { |
141 res := cl.Jid.Resource |
144 res := cl.Jid.Resource |
146 msg := &Iq{Header: Header{Type: "set", Id: NextId(), |
149 msg := &Iq{Header: Header{Type: "set", Id: NextId(), |
147 Nested: []interface{}{bindReq}}} |
150 Nested: []interface{}{bindReq}}} |
148 f := func(st Stanza) { |
151 f := func(st Stanza) { |
149 iq, ok := st.(*Iq) |
152 iq, ok := st.(*Iq) |
150 if !ok { |
153 if !ok { |
151 Warn.Log("non-iq response") |
154 cl.setError(fmt.Errorf("non-iq response to bind %#v", |
|
155 st)) |
|
156 return |
152 } |
157 } |
153 if iq.Type == "error" { |
158 if iq.Type == "error" { |
154 Warn.Log("Resource binding failed") |
159 cl.setError(fmt.Errorf("Resource binding failed")) |
|
160 return |
155 } |
161 } |
156 var bindRepl *bindIq |
162 var bindRepl *bindIq |
157 for _, ele := range iq.Nested { |
163 for _, ele := range iq.Nested { |
158 if b, ok := ele.(*bindIq); ok { |
164 if b, ok := ele.(*bindIq); ok { |
159 bindRepl = b |
165 bindRepl = b |
160 break |
166 break |
161 } |
167 } |
162 } |
168 } |
163 if bindRepl == nil { |
169 if bindRepl == nil { |
164 Warn.Logf("Bad bind reply: %#v", iq) |
170 cl.setError(fmt.Errorf("Bad bind reply: %#v", iq)) |
|
171 return |
165 } |
172 } |
166 jidStr := bindRepl.Jid |
173 jidStr := bindRepl.Jid |
167 if jidStr == nil || *jidStr == "" { |
174 if jidStr == nil || *jidStr == "" { |
168 Warn.Log("Can't bind empty resource") |
175 cl.setError(fmt.Errorf("empty resource in bind %#v", |
|
176 iq)) |
|
177 return |
169 } |
178 } |
170 jid := new(JID) |
179 jid := new(JID) |
171 if err := jid.Set(*jidStr); err != nil { |
180 if err := jid.Set(*jidStr); err != nil { |
172 Warn.Logf("Can't parse JID %s: %s", *jidStr, err) |
181 cl.setError(fmt.Errorf("bind: an't parse JID %s: %v", |
|
182 *jidStr, err)) |
|
183 return |
173 } |
184 } |
174 cl.Jid = *jid |
185 cl.Jid = *jid |
175 Info.Logf("Bound resource: %s", cl.Jid.String()) |
|
176 cl.setStatus(StatusBound) |
186 cl.setStatus(StatusBound) |
177 } |
187 } |
178 cl.SetCallback(msg.Id, f) |
188 cl.SetCallback(msg.Id, f) |
179 cl.sendXml <- msg |
189 cl.sendRaw <- msg |
180 } |
190 } |
181 |
191 |
182 // Register a callback to handle the next XMPP stanza (iq, message, or |
192 // Register a callback to handle the next XMPP stanza (iq, message, or |
183 // presence) with a given id. The provided function will not be called |
193 // presence) with a given id. The provided function will not be called |
184 // more than once. If it returns false, the stanza will not be made |
194 // more than once. If it returns false, the stanza will not be made |