30 var _ fmt.Stringer = &JID{} |
30 var _ fmt.Stringer = &JID{} |
31 var _ flag.Value = &JID{} |
31 var _ flag.Value = &JID{} |
32 |
32 |
33 // XMPP's <stream:stream> XML element |
33 // XMPP's <stream:stream> XML element |
34 type stream struct { |
34 type stream struct { |
35 To string `xml:"attr"` |
35 XMLName xml.Name `xml:"stream=http://etherx.jabber.org/streams stream"` |
36 From string `xml:"attr"` |
36 To string `xml:"to,attr"` |
37 Id string `xml:"attr"` |
37 From string `xml:"from,attr"` |
38 Lang string `xml:"attr"` |
38 Id string `xml:"id,attr"` |
39 Version string `xml:"attr"` |
39 Lang string `xml:"http://www.w3.org/XML/1998/namespace lang,attr"` |
40 } |
40 Version string `xml:"version,attr"` |
41 |
41 } |
42 var _ xml.Marshaler = &stream{} |
|
43 var _ fmt.Stringer = &stream{} |
42 var _ fmt.Stringer = &stream{} |
44 |
43 |
45 // <stream:error> |
44 // <stream:error> |
46 type streamError struct { |
45 type streamError struct { |
47 Any Generic |
46 XMLName xml.Name `xml:"http://etherx.jabber.org/streams error"` |
|
47 Any Generic `xml:",any"` |
48 Text *errText |
48 Text *errText |
49 } |
49 } |
50 |
50 |
51 var _ xml.Marshaler = &streamError{} |
|
52 |
|
53 type errText struct { |
51 type errText struct { |
54 Lang string `xml:"attr"` |
52 XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-streams text"` |
55 Text string `xml:"chardata"` |
53 Lang string `xml:"http://www.w3.org/XML/1998/namespace lang,attr"` |
56 } |
54 Text string `xml:",chardata"` |
57 |
55 } |
58 var _ xml.Marshaler = &errText{} |
|
59 |
56 |
60 type Features struct { |
57 type Features struct { |
61 Starttls *starttls |
58 Starttls *starttls |
62 Mechanisms mechs |
59 Mechanisms mechs |
63 Bind *bindIq |
60 Bind *bindIq |
82 } |
79 } |
83 |
80 |
84 // One of the three core XMPP stanza types: iq, message, presence. See |
81 // One of the three core XMPP stanza types: iq, message, presence. See |
85 // RFC3920, section 9. |
82 // RFC3920, section 9. |
86 type Stanza interface { |
83 type Stanza interface { |
87 // Returns "iq", "message", or "presence". |
84 // // Returns "iq", "message", or "presence". |
88 GetName() string |
85 // GetName() string |
89 // The to attribute. |
86 // // The to attribute. |
90 GetTo() string |
87 // GetTo() string |
91 // The from attribute. |
88 // // The from attribute. |
92 GetFrom() string |
89 // GetFrom() string |
93 // The id attribute. |
90 // The id attribute. TODO maybe remove this. |
94 GetId() string |
91 GetId() string |
95 // The type attribute. |
92 // // The type attribute. |
96 GetType() string |
93 // GetType() string |
97 // The xml:lang attribute. |
94 // // The xml:lang attribute. |
98 GetLang() string |
95 // GetLang() string |
99 // A nested error element, if any. |
96 // // A nested error element, if any. |
100 GetError() *Error |
97 // GetError() *Error |
101 // Zero or more (non-error) nested elements. These will be in |
98 // // Zero or more (non-error) nested elements. These will be in |
102 // namespaces managed by extensions. |
99 // // namespaces managed by extensions. |
103 GetNested() []interface{} |
100 // GetNested() []interface{} |
104 addNested(interface{}) |
101 addNested(interface{}) |
105 innerxml() string |
102 innerxml() string |
106 } |
103 } |
107 |
104 |
108 // message stanza |
105 // message stanza |
109 type Message struct { |
106 type Message struct { |
110 To string `xml:"attr"` |
107 XMLName xml.Name `xml:"message"` |
111 From string `xml:"attr"` |
108 To string `xml:"to,attr,omitempty"` |
112 Id string `xml:"attr"` |
109 From string `xml:"from,attr,omitempty"` |
113 Type string `xml:"attr"` |
110 Id string `xml:"id,attr,omitempty"` |
114 Lang string `xml:"attr"` |
111 Type string `xml:"type,attr,omitempty"` |
115 Innerxml string `xml:"innerxml"` |
112 Lang string `xml:"http://www.w3.org/XML/1998/namespace lang,attr,omitempty"` |
|
113 Innerxml string `xml:",innerxml"` |
116 Error *Error |
114 Error *Error |
117 Subject *Generic |
115 Subject *Generic `xml:"subject"` |
118 Body *Generic |
116 Body *Generic `xml:"body"` |
119 Thread *Generic |
117 Thread *Generic `xml:"thread"` |
120 Nested []interface{} |
118 Nested []interface{} |
121 } |
119 } |
122 |
|
123 var _ xml.Marshaler = &Message{} |
|
124 var _ Stanza = &Message{} |
120 var _ Stanza = &Message{} |
125 |
121 |
126 // presence stanza |
122 // presence stanza |
127 type Presence struct { |
123 type Presence struct { |
128 To string `xml:"attr"` |
124 XMLName xml.Name `xml:"presence"` |
129 From string `xml:"attr"` |
125 To string `xml:"to,attr,omitempty"` |
130 Id string `xml:"attr"` |
126 From string `xml:"from,attr,omitempty"` |
131 Type string `xml:"attr"` |
127 Id string `xml:"id,attr,omitempty"` |
132 Lang string `xml:"attr"` |
128 Type string `xml:"type,attr,omitempty"` |
133 Innerxml string `xml:"innerxml"` |
129 Lang string `xml:"http://www.w3.org/XML/1998/namespace lang,attr,omitempty"` |
|
130 Innerxml string `xml:",innerxml"` |
134 Error *Error |
131 Error *Error |
135 Show *Generic |
132 Show *Generic `xml:"show"` |
136 Status *Generic |
133 Status *Generic `xml:"status"` |
137 Priority *Generic |
134 Priority *Generic `xml:"priority"` |
138 Nested []interface{} |
135 Nested []interface{} |
139 } |
136 } |
140 |
|
141 var _ xml.Marshaler = &Presence{} |
|
142 var _ Stanza = &Presence{} |
137 var _ Stanza = &Presence{} |
143 |
138 |
144 // iq stanza |
139 // iq stanza |
145 type Iq struct { |
140 type Iq struct { |
146 To string `xml:"attr"` |
141 XMLName xml.Name `xml:"iq"` |
147 From string `xml:"attr"` |
142 To string `xml:"to,attr,omitempty"` |
148 Id string `xml:"attr"` |
143 From string `xml:"from,attr,omitempty"` |
149 Type string `xml:"attr"` |
144 Id string `xml:"id,attr,omitempty"` |
150 Lang string `xml:"attr"` |
145 Type string `xml:"type,attr,omitempty"` |
151 Innerxml string `xml:"innerxml"` |
146 Lang string `xml:"http://www.w3.org/XML/1998/namespace lang,attr,omitempty"` |
|
147 Innerxml string `xml:",innerxml"` |
152 Error *Error |
148 Error *Error |
153 Nested []interface{} |
149 Nested []interface{} |
154 } |
150 } |
155 |
|
156 var _ xml.Marshaler = &Iq{} |
|
157 var _ Stanza = &Iq{} |
151 var _ Stanza = &Iq{} |
158 |
152 |
159 // Describes an XMPP stanza error. See RFC 3920, Section 9.3. |
153 // Describes an XMPP stanza error. See RFC 3920, Section 9.3. |
160 type Error struct { |
154 type Error struct { |
161 XMLName xml.Name `xml:"error"` |
155 XMLName xml.Name `xml:"error"` |
162 // The error type attribute. |
156 // The error type attribute. |
163 Type string `xml:"attr"` |
157 Type string `xml:"type,attr"` |
164 // Any nested element, if present. |
158 // Any nested element, if present. |
165 Any *Generic |
159 Any *Generic |
166 } |
160 } |
167 |
161 var _ error = &Error{} |
168 var _ os.Error = &Error{} |
|
169 |
162 |
170 // Used for resource binding as a nested element inside <iq/>. |
163 // Used for resource binding as a nested element inside <iq/>. |
171 type bindIq struct { |
164 type bindIq struct { |
172 XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-bind bind"` |
165 XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-bind bind"` |
173 Resource *string `xml:"resource"` |
166 Resource *string `xml:"resource"` |
194 return result |
186 return result |
195 } |
187 } |
196 |
188 |
197 // Set implements flag.Value. It returns true if it successfully |
189 // Set implements flag.Value. It returns true if it successfully |
198 // parses the string. |
190 // parses the string. |
199 func (jid *JID) Set(val string) bool { |
191 func (jid *JID) Set(val string) error { |
200 r := regexp.MustCompile("^(([^@/]+)@)?([^@/]+)(/([^@/]+))?$") |
192 r := regexp.MustCompile("^(([^@/]+)@)?([^@/]+)(/([^@/]+))?$") |
201 parts := r.FindStringSubmatch(val) |
193 parts := r.FindStringSubmatch(val) |
202 if parts == nil { |
194 if parts == nil { |
203 return false |
195 return fmt.Errorf("%s doesn't match user@domain/resource", val) |
204 } |
196 } |
205 jid.Node = stringprep.Nodeprep(parts[2]) |
197 // jid.Node = stringprep.Nodeprep(parts[2]) |
206 jid.Domain = stringprep.Nodeprep(parts[3]) |
198 // jid.Domain = stringprep.Nodeprep(parts[3]) |
207 jid.Resource = stringprep.Resourceprep(parts[5]) |
199 // jid.Resource = stringprep.Resourceprep(parts[5]) |
208 return true |
200 jid.Node = parts[2] |
209 } |
201 jid.Domain = parts[3] |
210 |
202 jid.Resource = parts[5] |
211 func (s *stream) MarshalXML() ([]byte, os.Error) { |
203 return nil |
212 buf := bytes.NewBuffer(nil) |
204 } |
213 buf.WriteString("<stream:stream") |
205 |
214 writeField(buf, "xmlns", "jabber:client") |
206 func (s *stream) String() string { |
215 writeField(buf, "xmlns:stream", NsStream) |
207 var buf bytes.Buffer |
216 writeField(buf, "to", s.To) |
208 buf.WriteString(`<stream:stream xmlns="`) |
217 writeField(buf, "from", s.From) |
209 buf.WriteString(NsClient) |
218 writeField(buf, "id", s.Id) |
210 buf.WriteString(`" xmlns:stream="`) |
219 writeField(buf, "xml:lang", s.Lang) |
211 buf.WriteString(NsStream) |
220 writeField(buf, "version", s.Version) |
212 buf.WriteString(`"`) |
|
213 if s.To != "" { |
|
214 buf.WriteString(` to="`) |
|
215 xml.Escape(&buf, []byte(s.To)) |
|
216 buf.WriteString(`"`) |
|
217 } |
|
218 if s.From != "" { |
|
219 buf.WriteString(` from="`) |
|
220 xml.Escape(&buf, []byte(s.From)) |
|
221 buf.WriteString(`"`) |
|
222 } |
|
223 if s.Id != "" { |
|
224 buf.WriteString(` id="`) |
|
225 xml.Escape(&buf, []byte(s.Id)) |
|
226 buf.WriteString(`"`) |
|
227 } |
|
228 if s.Lang != "" { |
|
229 buf.WriteString(` xml:lang="`) |
|
230 xml.Escape(&buf, []byte(s.Lang)) |
|
231 buf.WriteString(`"`) |
|
232 } |
|
233 if s.Version != "" { |
|
234 buf.WriteString(` version="`) |
|
235 xml.Escape(&buf, []byte(s.Version)) |
|
236 buf.WriteString(`"`) |
|
237 } |
221 buf.WriteString(">") |
238 buf.WriteString(">") |
222 // We never write </stream:stream> |
239 return buf.String() |
223 return buf.Bytes(), nil |
240 } |
224 } |
241 |
225 |
242 func parseStream(se xml.StartElement) (*stream, error) { |
226 func (s *stream) String() string { |
|
227 result, _ := s.MarshalXML() |
|
228 return string(result) |
|
229 } |
|
230 |
|
231 func parseStream(se xml.StartElement) (*stream, os.Error) { |
|
232 s := &stream{} |
243 s := &stream{} |
233 for _, attr := range se.Attr { |
244 for _, attr := range se.Attr { |
234 switch strings.ToLower(attr.Name.Local) { |
245 switch strings.ToLower(attr.Name.Local) { |
235 case "to": |
246 case "to": |
236 s.To = attr.Value |
247 s.To = attr.Value |
245 } |
256 } |
246 } |
257 } |
247 return s, nil |
258 return s, nil |
248 } |
259 } |
249 |
260 |
250 func (s *streamError) MarshalXML() ([]byte, os.Error) { |
|
251 buf := bytes.NewBuffer(nil) |
|
252 buf.WriteString("<stream:error>") |
|
253 xml.Marshal(buf, s.Any) |
|
254 if s.Text != nil { |
|
255 xml.Marshal(buf, s.Text) |
|
256 } |
|
257 buf.WriteString("</stream:error>") |
|
258 return buf.Bytes(), nil |
|
259 } |
|
260 |
|
261 func (e *errText) MarshalXML() ([]byte, os.Error) { |
|
262 buf := bytes.NewBuffer(nil) |
|
263 buf.WriteString("<text") |
|
264 writeField(buf, "xmlns", NsStreams) |
|
265 writeField(buf, "xml:lang", e.Lang) |
|
266 buf.WriteString(">") |
|
267 xml.Escape(buf, []byte(e.Text)) |
|
268 buf.WriteString("</text>") |
|
269 return buf.Bytes(), nil |
|
270 } |
|
271 |
|
272 func writeField(w io.Writer, field, value string) { |
|
273 if value != "" { |
|
274 io.WriteString(w, " ") |
|
275 io.WriteString(w, field) |
|
276 io.WriteString(w, `="`) |
|
277 xml.Escape(w, []byte(value)) |
|
278 io.WriteString(w, `"`) |
|
279 } |
|
280 } |
|
281 |
|
282 func (u *Generic) String() string { |
261 func (u *Generic) String() string { |
283 if u == nil { |
262 if u == nil { |
284 return "nil" |
263 return "nil" |
285 } |
264 } |
286 var sub string |
265 var sub string |
290 return fmt.Sprintf("<%s %s>%s%s</%s %s>", u.XMLName.Space, |
269 return fmt.Sprintf("<%s %s>%s%s</%s %s>", u.XMLName.Space, |
291 u.XMLName.Local, sub, u.Chardata, u.XMLName.Space, |
270 u.XMLName.Local, sub, u.Chardata, u.XMLName.Space, |
292 u.XMLName.Local) |
271 u.XMLName.Local) |
293 } |
272 } |
294 |
273 |
295 func marshalXML(st Stanza) ([]byte, os.Error) { |
274 func (er *Error) Error() string { |
296 buf := bytes.NewBuffer(nil) |
275 buf, err := xml.Marshal(er) |
297 buf.WriteString("<") |
276 if err != nil { |
298 buf.WriteString(st.GetName()) |
277 if Log != nil { |
299 if st.GetTo() != "" { |
278 Log.Err("double bad error couldn't marshal error") |
300 writeField(buf, "to", st.GetTo()) |
|
301 } |
|
302 if st.GetFrom() != "" { |
|
303 writeField(buf, "from", st.GetFrom()) |
|
304 } |
|
305 if st.GetId() != "" { |
|
306 writeField(buf, "id", st.GetId()) |
|
307 } |
|
308 if st.GetType() != "" { |
|
309 writeField(buf, "type", st.GetType()) |
|
310 } |
|
311 if st.GetLang() != "" { |
|
312 writeField(buf, "xml:lang", st.GetLang()) |
|
313 } |
|
314 buf.WriteString(">") |
|
315 |
|
316 if m, ok := st.(*Message); ok { |
|
317 err := xml.Marshal(buf, m.Subject) |
|
318 if err != nil { |
|
319 return nil, err |
|
320 } |
279 } |
321 err = xml.Marshal(buf, m.Body) |
280 return "unreadable error" |
322 if err != nil { |
281 } |
323 return nil, err |
282 return string(buf) |
324 } |
|
325 err = xml.Marshal(buf, m.Thread) |
|
326 if err != nil { |
|
327 return nil, err |
|
328 } |
|
329 } |
|
330 if p, ok := st.(*Presence); ok { |
|
331 err := xml.Marshal(buf, p.Show) |
|
332 if err != nil { |
|
333 return nil, err |
|
334 } |
|
335 err = xml.Marshal(buf, p.Status) |
|
336 if err != nil { |
|
337 return nil, err |
|
338 } |
|
339 err = xml.Marshal(buf, p.Priority) |
|
340 if err != nil { |
|
341 return nil, err |
|
342 } |
|
343 } |
|
344 if nested := st.GetNested(); nested != nil { |
|
345 for _, n := range nested { |
|
346 xml.Marshal(buf, n) |
|
347 } |
|
348 } else if st.innerxml() != "" { |
|
349 buf.WriteString(st.innerxml()) |
|
350 } |
|
351 |
|
352 buf.WriteString("</") |
|
353 buf.WriteString(st.GetName()) |
|
354 buf.WriteString(">") |
|
355 return buf.Bytes(), nil |
|
356 } |
|
357 |
|
358 func (er *Error) String() string { |
|
359 buf := bytes.NewBuffer(nil) |
|
360 xml.Marshal(buf, er) |
|
361 return buf.String() |
|
362 } |
|
363 |
|
364 func (m *Message) GetName() string { |
|
365 return "message" |
|
366 } |
|
367 |
|
368 func (m *Message) GetTo() string { |
|
369 return m.To |
|
370 } |
|
371 |
|
372 func (m *Message) GetFrom() string { |
|
373 return m.From |
|
374 } |
283 } |
375 |
284 |
376 func (m *Message) GetId() string { |
285 func (m *Message) GetId() string { |
377 return m.Id |
286 return m.Id |
378 } |
287 } |
379 |
288 |
380 func (m *Message) GetType() string { |
|
381 return m.Type |
|
382 } |
|
383 |
|
384 func (m *Message) GetLang() string { |
|
385 return m.Lang |
|
386 } |
|
387 |
|
388 func (m *Message) GetError() *Error { |
|
389 return m.Error |
|
390 } |
|
391 |
|
392 func (m *Message) GetNested() []interface{} { |
|
393 return m.Nested |
|
394 } |
|
395 |
|
396 func (m *Message) addNested(n interface{}) { |
289 func (m *Message) addNested(n interface{}) { |
397 m.Nested = append(m.Nested, n) |
290 m.Nested = append(m.Nested, n) |
398 } |
291 } |
399 |
292 |
400 func (m *Message) innerxml() string { |
293 func (m *Message) innerxml() string { |
401 return m.Innerxml |
294 return m.Innerxml |
402 } |
295 } |
403 |
296 |
404 func (m *Message) MarshalXML() ([]byte, os.Error) { |
|
405 return marshalXML(m) |
|
406 } |
|
407 |
|
408 func (p *Presence) GetName() string { |
|
409 return "presence" |
|
410 } |
|
411 |
|
412 func (p *Presence) GetTo() string { |
|
413 return p.To |
|
414 } |
|
415 |
|
416 func (p *Presence) GetFrom() string { |
|
417 return p.From |
|
418 } |
|
419 |
|
420 func (p *Presence) GetId() string { |
297 func (p *Presence) GetId() string { |
421 return p.Id |
298 return p.Id |
422 } |
299 } |
423 |
300 |
424 func (p *Presence) GetType() string { |
|
425 return p.Type |
|
426 } |
|
427 |
|
428 func (p *Presence) GetLang() string { |
|
429 return p.Lang |
|
430 } |
|
431 |
|
432 func (p *Presence) GetError() *Error { |
|
433 return p.Error |
|
434 } |
|
435 |
|
436 func (p *Presence) GetNested() []interface{} { |
|
437 return p.Nested |
|
438 } |
|
439 |
|
440 func (p *Presence) addNested(n interface{}) { |
301 func (p *Presence) addNested(n interface{}) { |
441 p.Nested = append(p.Nested, n) |
302 p.Nested = append(p.Nested, n) |
442 } |
303 } |
443 |
304 |
444 func (p *Presence) innerxml() string { |
305 func (p *Presence) innerxml() string { |
445 return p.Innerxml |
306 return p.Innerxml |
446 } |
307 } |
447 |
308 |
448 func (p *Presence) MarshalXML() ([]byte, os.Error) { |
|
449 return marshalXML(p) |
|
450 } |
|
451 |
|
452 func (iq *Iq) GetName() string { |
|
453 return "iq" |
|
454 } |
|
455 |
|
456 func (iq *Iq) GetTo() string { |
|
457 return iq.To |
|
458 } |
|
459 |
|
460 func (iq *Iq) GetFrom() string { |
|
461 return iq.From |
|
462 } |
|
463 |
|
464 func (iq *Iq) GetId() string { |
309 func (iq *Iq) GetId() string { |
465 return iq.Id |
310 return iq.Id |
466 } |
311 } |
467 |
312 |
468 func (iq *Iq) GetType() string { |
|
469 return iq.Type |
|
470 } |
|
471 |
|
472 func (iq *Iq) GetLang() string { |
|
473 return iq.Lang |
|
474 } |
|
475 |
|
476 func (iq *Iq) GetError() *Error { |
|
477 return iq.Error |
|
478 } |
|
479 |
|
480 func (iq *Iq) GetNested() []interface{} { |
|
481 return iq.Nested |
|
482 } |
|
483 |
|
484 func (iq *Iq) addNested(n interface{}) { |
313 func (iq *Iq) addNested(n interface{}) { |
485 iq.Nested = append(iq.Nested, n) |
314 iq.Nested = append(iq.Nested, n) |
486 } |
315 } |
487 |
316 |
488 func (iq *Iq) innerxml() string { |
317 func (iq *Iq) innerxml() string { |
489 return iq.Innerxml |
318 return iq.Innerxml |
490 } |
319 } |
491 |
320 |
492 func (iq *Iq) MarshalXML() ([]byte, os.Error) { |
|
493 return marshalXML(iq) |
|
494 } |
|
495 |
321 |
496 // Parse a string into a struct implementing Stanza -- this will be |
322 // Parse a string into a struct implementing Stanza -- this will be |
497 // either an Iq, a Message, or a Presence. |
323 // either an Iq, a Message, or a Presence. |
498 func ParseStanza(str string) (Stanza, os.Error) { |
324 func ParseStanza(str string) (Stanza, error) { |
499 r := strings.NewReader(str) |
325 r := strings.NewReader(str) |
500 p := xml.NewParser(r) |
326 p := xml.NewDecoder(r) |
501 tok, err := p.Token() |
327 tok, err := p.Token() |
502 if err != nil { |
328 if err != nil { |
503 return nil, err |
329 return nil, err |
504 } |
330 } |
505 se, ok := tok.(xml.StartElement) |
331 se, ok := tok.(xml.StartElement) |
506 if !ok { |
332 if !ok { |
507 return nil, os.NewError("Not a start element") |
333 return nil, errors.New("Not a start element") |
508 } |
334 } |
509 var stan Stanza |
335 var stan Stanza |
510 switch se.Name.Local { |
336 switch se.Name.Local { |
511 case "iq": |
337 case "iq": |
512 stan = &Iq{} |
338 stan = &Iq{} |
513 case "message": |
339 case "message": |
514 stan = &Message{} |
340 stan = &Message{} |
515 case "presence": |
341 case "presence": |
516 stan = &Presence{} |
342 stan = &Presence{} |
517 default: |
343 default: |
518 return nil, os.NewError("Not iq, message, or presence") |
344 return nil, errors.New("Not iq, message, or presence") |
519 } |
345 } |
520 err = p.Unmarshal(stan, &se) |
346 err = p.DecodeElement(stan, &se) |
521 if err != nil { |
347 if err != nil { |
522 return nil, err |
348 return nil, err |
523 } |
349 } |
524 return stan, nil |
350 return stan, nil |
525 } |
351 } |