|
1 // Copyright 2011 The Go Authors. All rights reserved. |
|
2 // Use of this source code is governed by a BSD-style |
|
3 // license that can be found in the LICENSE file. |
|
4 |
|
5 package xmpp |
|
6 |
|
7 import ( |
|
8 "fmt" |
|
9 "io" |
|
10 "os" |
|
11 "xml" |
|
12 ) |
|
13 |
|
14 // This file contains support for roster management, RFC 3921, Section 7. |
|
15 |
|
16 type RosterIq struct { |
|
17 Iq |
|
18 Query RosterQuery |
|
19 } |
|
20 var _ ExtendedStanza = &RosterIq{} |
|
21 |
|
22 // Roster query/result |
|
23 type RosterQuery struct { |
|
24 // Should always be NsRoster, "query" |
|
25 XMLName xml.Name |
|
26 Item []RosterItem |
|
27 } |
|
28 |
|
29 // See RFC 3921, Section 7.1. |
|
30 type RosterItem struct { |
|
31 // Should always be "item" |
|
32 XMLName xml.Name |
|
33 Jid string `xml:"attr"` |
|
34 Subscription string `xml:"attr"` |
|
35 Name string `xml:"attr"` |
|
36 Group []string |
|
37 } |
|
38 |
|
39 func (riq *RosterIq) InnerMarshal(w io.Writer) os.Error { |
|
40 return xml.Marshal(w, riq.Query) |
|
41 } |
|
42 |
|
43 // Implicitly becomes part of NewClient's extStanza arg. |
|
44 func rosterStanza(name *xml.Name) ExtendedStanza { |
|
45 return &RosterIq{} |
|
46 } |
|
47 |
|
48 // Synchronously fetch this entity's roster from the server and cache |
|
49 // that information. |
|
50 func (cl *Client) fetchRoster() os.Error { |
|
51 iq := &RosterIq{Iq: Iq{From: cl.Jid.String(), Id: <- cl.Id, |
|
52 Type: "get"}, Query: RosterQuery{XMLName: |
|
53 xml.Name{Local: "query", Space: NsRoster}}} |
|
54 ch := make(chan os.Error) |
|
55 f := func(st Stanza) bool { |
|
56 iq, ok := st.(*RosterIq) |
|
57 if !ok { |
|
58 ch <- os.NewError(fmt.Sprintf( |
|
59 "Roster query result not iq: %v", st)) |
|
60 return false |
|
61 } |
|
62 if iq.Type == "error" { |
|
63 ch <- iq.Error |
|
64 return false |
|
65 } |
|
66 q := iq.Query |
|
67 cl.roster = make(map[string] *RosterItem, len(q.Item)) |
|
68 for _, item := range(q.Item) { |
|
69 cl.roster[item.Jid] = &item |
|
70 } |
|
71 ch <- nil |
|
72 return false |
|
73 } |
|
74 cl.HandleStanza(iq.Id, f) |
|
75 cl.Out <- iq |
|
76 // Wait for f to complete. |
|
77 return <- ch |
|
78 } |
|
79 |
|
80 // BUG(cjyar) The roster isn't actually updated when things change. |
|
81 |
|
82 // Returns the current roster of other entities which this one has a |
|
83 // relationship with. Changes to the roster will be signaled by an |
|
84 // appropriate Iq appearing on Client.In. See RFC 3921, Section 7.4. |
|
85 func (cl *Client) Roster() map[string] *RosterItem { |
|
86 r := make(map[string] *RosterItem) |
|
87 for key, val := range(cl.roster) { |
|
88 r[key] = val |
|
89 } |
|
90 return r |
|
91 } |