29 var _ fmt.Stringer = &JID{} |
29 var _ fmt.Stringer = &JID{} |
30 var _ flag.Value = &JID{} |
30 var _ flag.Value = &JID{} |
31 |
31 |
32 // XMPP's <stream:stream> XML element |
32 // XMPP's <stream:stream> XML element |
33 type stream struct { |
33 type stream struct { |
|
34 XMLName xml.Name `xml:"stream stream"` |
34 To string `xml:"to,attr"` |
35 To string `xml:"to,attr"` |
35 From string `xml:"from,attr"` |
36 From string `xml:"from,attr"` |
36 Id string `xml:"id,attr"` |
37 Id string `xml:"id,attr"` |
37 Lang string `xml:"lang,attr"` |
38 Lang string `xml:"lang,attr"` |
38 Version string `xml:"version,attr"` |
39 Version string `xml:"version,attr"` |
39 } |
40 } |
40 |
41 |
41 var _ xml.Marshaler = &stream{} |
|
42 var _ fmt.Stringer = &stream{} |
42 var _ fmt.Stringer = &stream{} |
43 |
43 |
44 // <stream:error> |
44 // <stream:error> |
45 type streamError struct { |
45 type streamError struct { |
46 Any Generic `xml:",any"` |
46 Any Generic `xml:",any"` |
47 Text *errText `xml:"text"` |
47 Text *errText `xml:"text"` |
48 } |
48 } |
49 |
49 |
50 var _ xml.Marshaler = &streamError{} |
|
51 |
|
52 type errText struct { |
50 type errText struct { |
|
51 XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-streams text"` |
53 Lang string `xml:"lang,attr"` |
52 Lang string `xml:"lang,attr"` |
54 Text string `xml:",chardata"` |
53 Text string `xml:",chardata"` |
55 } |
54 } |
56 |
55 |
57 var _ xml.Marshaler = &errText{} |
|
58 |
|
59 type Features struct { |
56 type Features struct { |
60 Starttls *starttls `xml:"starttls"` |
57 Starttls *starttls `xml:"starttls"` |
61 Mechanisms mechs `xml:"mechanisms"` |
58 Mechanisms mechs `xml:"mechanisms"` |
62 Bind *bindIq `xml:"bind"` |
59 Bind *bindIq `xml:"bind"` |
63 Session *Generic `xml:"session"` |
60 Session *Generic `xml:"session"` |
64 Any *Generic `xml:",any"` |
61 Any *Generic `xml:",any"` |
65 } |
62 } |
66 |
63 |
67 type starttls struct { |
64 type starttls struct { |
68 XMLName xml.Name |
65 XMLName xml.Name |
69 Required *string `xml:"required"` |
66 Required *string `xml:"required"` |
104 innerxml() string |
101 innerxml() string |
105 } |
102 } |
106 |
103 |
107 // message stanza |
104 // message stanza |
108 type Message struct { |
105 type Message struct { |
109 To string `xml:"to,attr"` |
106 XMLName xml.Name `xml:"message"` |
110 From string `xml:"from,attr"` |
107 To string `xml:"to,attr,omitempty"` |
111 Id string `xml:"id,attr"` |
108 From string `xml:"from,attr,omitempty"` |
112 Type string `xml:"type,attr"` |
109 Id string `xml:"id,attr,omitempty"` |
113 Lang string `xml:"lang,attr"` |
110 Type string `xml:"type,attr,omitempty"` |
114 Innerxml string `xml:",innerxml"` |
111 Lang string `xml:"lang,attr,omitempty"` |
115 Error *Error `xml:"error"` |
112 Innerxml string `xml:",innerxml"` |
|
113 Error *Error `xml:"error"` |
116 Subject *Generic `xml:"subject"` |
114 Subject *Generic `xml:"subject"` |
117 Body *Generic `xml:"body"` |
115 Body *Generic `xml:"body"` |
118 Thread *Generic `xml:"thread"` |
116 Thread *Generic `xml:"thread"` |
119 Nested []interface{} |
117 Nested []interface{} |
120 } |
118 } |
121 |
119 |
122 var _ xml.Marshaler = &Message{} |
|
123 var _ Stanza = &Message{} |
120 var _ Stanza = &Message{} |
124 |
121 |
125 // presence stanza |
122 // presence stanza |
126 type Presence struct { |
123 type Presence struct { |
127 To string `xml:"to,attr"` |
124 XMLName xml.Name `xml:"presence"` |
128 From string `xml:"from,attr"` |
125 To string `xml:"to,attr,omitempty"` |
129 Id string `xml:"id,attr"` |
126 From string `xml:"from,attr,omitempty"` |
130 Type string `xml:"type,attr"` |
127 Id string `xml:"id,attr,omitempty"` |
131 Lang string `xml:"lang,attr"` |
128 Type string `xml:"type,attr,omitempty"` |
132 Innerxml string `xml:",innerxml"` |
129 Lang string `xml:"lang,attr,omitempty"` |
133 Error *Error `xml:"error"` |
130 Innerxml string `xml:",innerxml"` |
|
131 Error *Error `xml:"error"` |
134 Show *Generic `xml:"show"` |
132 Show *Generic `xml:"show"` |
135 Status *Generic `xml:"status"` |
133 Status *Generic `xml:"status"` |
136 Priority *Generic `xml:"priority"` |
134 Priority *Generic `xml:"priority"` |
137 Nested []interface{} |
135 Nested []interface{} |
138 } |
136 } |
139 |
137 |
140 var _ xml.Marshaler = &Presence{} |
|
141 var _ Stanza = &Presence{} |
138 var _ Stanza = &Presence{} |
142 |
139 |
143 // iq stanza |
140 // iq stanza |
144 type Iq struct { |
141 type Iq struct { |
145 To string `xml:"to,attr"` |
142 XMLName xml.Name `xml:"iq"` |
146 From string `xml:"from,attr"` |
143 To string `xml:"to,attr,omitempty"` |
147 Id string `xml:"id,attr"` |
144 From string `xml:"from,attr,omitempty"` |
148 Type string `xml:"type,attr"` |
145 Id string `xml:"id,attr,omitempty"` |
149 Lang string `xml:"lang,attr"` |
146 Type string `xml:"type,attr,omitempty"` |
|
147 Lang string `xml:"xml lang,attr,omitempty"` |
150 Innerxml string `xml:",innerxml"` |
148 Innerxml string `xml:",innerxml"` |
151 Error *Error `xml:"error"` |
149 Error *Error `xml:"error"` |
152 Nested []interface{} |
150 Nested []interface{} |
153 } |
151 } |
154 |
152 |
155 var _ xml.Marshaler = &Iq{} |
|
156 var _ Stanza = &Iq{} |
153 var _ Stanza = &Iq{} |
157 |
154 |
158 // Describes an XMPP stanza error. See RFC 3920, Section 9.3. |
155 // Describes an XMPP stanza error. See RFC 3920, Section 9.3. |
159 type Error struct { |
156 type Error struct { |
160 XMLName xml.Name `xml:"error"` |
157 XMLName xml.Name `xml:"error"` |
205 jid.Domain = parts[3] |
202 jid.Domain = parts[3] |
206 jid.Resource = parts[5] |
203 jid.Resource = parts[5] |
207 return nil |
204 return nil |
208 } |
205 } |
209 |
206 |
210 func (s *stream) MarshalXML() ([]byte, error) { |
207 func (s *stream) String() string { |
211 buf := bytes.NewBuffer(nil) |
208 buf := bytes.NewBuffer(nil) |
212 buf.WriteString("<stream:stream") |
209 buf.WriteString("<stream:stream") |
213 writeField(buf, "xmlns", "jabber:client") |
|
214 writeField(buf, "xmlns:stream", NsStream) |
|
215 writeField(buf, "to", s.To) |
210 writeField(buf, "to", s.To) |
216 writeField(buf, "from", s.From) |
211 writeField(buf, "from", s.From) |
217 writeField(buf, "id", s.Id) |
212 writeField(buf, "id", s.Id) |
218 writeField(buf, "xml:lang", s.Lang) |
213 writeField(buf, "xml:lang", s.Lang) |
219 writeField(buf, "version", s.Version) |
214 writeField(buf, "version", s.Version) |
220 buf.WriteString(">") |
215 buf.WriteString(">") |
221 // We never write </stream:stream> |
216 return buf.String() |
222 return buf.Bytes(), nil |
|
223 } |
|
224 |
|
225 func (s *stream) String() string { |
|
226 result, _ := s.MarshalXML() |
|
227 return string(result) |
|
228 } |
217 } |
229 |
218 |
230 func parseStream(se xml.StartElement) (*stream, error) { |
219 func parseStream(se xml.StartElement) (*stream, error) { |
231 s := &stream{} |
220 s := &stream{} |
232 for _, attr := range se.Attr { |
221 for _, attr := range se.Attr { |
244 } |
233 } |
245 } |
234 } |
246 return s, nil |
235 return s, nil |
247 } |
236 } |
248 |
237 |
249 func (s *streamError) MarshalXML() ([]byte, error) { |
|
250 buf := bytes.NewBuffer(nil) |
|
251 buf.WriteString("<stream:error>") |
|
252 xml.Marshal(buf, s.Any) |
|
253 if s.Text != nil { |
|
254 xml.Marshal(buf, s.Text) |
|
255 } |
|
256 buf.WriteString("</stream:error>") |
|
257 return buf.Bytes(), nil |
|
258 } |
|
259 |
|
260 func (e *errText) MarshalXML() ([]byte, error) { |
|
261 buf := bytes.NewBuffer(nil) |
|
262 buf.WriteString("<text") |
|
263 writeField(buf, "xmlns", NsStreams) |
|
264 writeField(buf, "xml:lang", e.Lang) |
|
265 buf.WriteString(">") |
|
266 xml.Escape(buf, []byte(e.Text)) |
|
267 buf.WriteString("</text>") |
|
268 return buf.Bytes(), nil |
|
269 } |
|
270 |
|
271 func writeField(w io.Writer, field, value string) { |
238 func writeField(w io.Writer, field, value string) { |
272 if value != "" { |
239 if value != "" { |
273 io.WriteString(w, " ") |
240 io.WriteString(w, " ") |
274 io.WriteString(w, field) |
241 io.WriteString(w, field) |
275 io.WriteString(w, `="`) |
242 io.WriteString(w, `="`) |
289 return fmt.Sprintf("<%s %s>%s%s</%s %s>", u.XMLName.Space, |
256 return fmt.Sprintf("<%s %s>%s%s</%s %s>", u.XMLName.Space, |
290 u.XMLName.Local, sub, u.Chardata, u.XMLName.Space, |
257 u.XMLName.Local, sub, u.Chardata, u.XMLName.Space, |
291 u.XMLName.Local) |
258 u.XMLName.Local) |
292 } |
259 } |
293 |
260 |
294 func marshalXML(st Stanza) ([]byte, error) { |
|
295 buf := bytes.NewBuffer(nil) |
|
296 buf.WriteString("<") |
|
297 buf.WriteString(st.GetName()) |
|
298 if st.GetTo() != "" { |
|
299 writeField(buf, "to", st.GetTo()) |
|
300 } |
|
301 if st.GetFrom() != "" { |
|
302 writeField(buf, "from", st.GetFrom()) |
|
303 } |
|
304 if st.GetId() != "" { |
|
305 writeField(buf, "id", st.GetId()) |
|
306 } |
|
307 if st.GetType() != "" { |
|
308 writeField(buf, "type", st.GetType()) |
|
309 } |
|
310 if st.GetLang() != "" { |
|
311 writeField(buf, "xml:lang", st.GetLang()) |
|
312 } |
|
313 buf.WriteString(">") |
|
314 |
|
315 if m, ok := st.(*Message); ok { |
|
316 err := xml.Marshal(buf, m.Subject) |
|
317 if err != nil { |
|
318 return nil, err |
|
319 } |
|
320 err = xml.Marshal(buf, m.Body) |
|
321 if err != nil { |
|
322 return nil, err |
|
323 } |
|
324 err = xml.Marshal(buf, m.Thread) |
|
325 if err != nil { |
|
326 return nil, err |
|
327 } |
|
328 } |
|
329 if p, ok := st.(*Presence); ok { |
|
330 err := xml.Marshal(buf, p.Show) |
|
331 if err != nil { |
|
332 return nil, err |
|
333 } |
|
334 err = xml.Marshal(buf, p.Status) |
|
335 if err != nil { |
|
336 return nil, err |
|
337 } |
|
338 err = xml.Marshal(buf, p.Priority) |
|
339 if err != nil { |
|
340 return nil, err |
|
341 } |
|
342 } |
|
343 if nested := st.GetNested(); nested != nil { |
|
344 for _, n := range nested { |
|
345 xml.Marshal(buf, n) |
|
346 } |
|
347 } else if st.innerxml() != "" { |
|
348 buf.WriteString(st.innerxml()) |
|
349 } |
|
350 |
|
351 buf.WriteString("</") |
|
352 buf.WriteString(st.GetName()) |
|
353 buf.WriteString(">") |
|
354 return buf.Bytes(), nil |
|
355 } |
|
356 |
|
357 func (er *Error) Error() string { |
261 func (er *Error) Error() string { |
358 buf := bytes.NewBuffer(nil) |
262 buf := bytes.NewBuffer(nil) |
359 xml.Marshal(buf, er) |
263 xml.NewEncoder(buf).Encode(er) |
360 return buf.String() |
264 return buf.String() |
361 } |
265 } |
362 |
266 |
363 func (m *Message) GetName() string { |
267 func (m *Message) GetName() string { |
364 return "message" |
268 return "message" |
484 iq.Nested = append(iq.Nested, n) |
380 iq.Nested = append(iq.Nested, n) |
485 } |
381 } |
486 |
382 |
487 func (iq *Iq) innerxml() string { |
383 func (iq *Iq) innerxml() string { |
488 return iq.Innerxml |
384 return iq.Innerxml |
489 } |
|
490 |
|
491 func (iq *Iq) MarshalXML() ([]byte, error) { |
|
492 return marshalXML(iq) |
|
493 } |
385 } |
494 |
386 |
495 // Parse a string into a struct implementing Stanza -- this will be |
387 // Parse a string into a struct implementing Stanza -- this will be |
496 // either an Iq, a Message, or a Presence. |
388 // either an Iq, a Message, or a Presence. |
497 func ParseStanza(str string) (Stanza, error) { |
389 func ParseStanza(str string) (Stanza, error) { |
498 r := strings.NewReader(str) |
390 r := strings.NewReader(str) |
499 p := xml.NewParser(r) |
391 p := xml.NewDecoder(r) |
500 tok, err := p.Token() |
392 tok, err := p.Token() |
501 if err != nil { |
393 if err != nil { |
502 return nil, err |
394 return nil, err |
503 } |
395 } |
504 se, ok := tok.(xml.StartElement) |
396 se, ok := tok.(xml.StartElement) |