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