4 |
4 |
5 package xmpp |
5 package xmpp |
6 |
6 |
7 import ( |
7 import ( |
8 "fmt" |
8 "fmt" |
9 "io" |
|
10 "os" |
9 "os" |
11 "xml" |
10 "xml" |
12 ) |
11 ) |
13 |
12 |
14 // This file contains support for roster management, RFC 3921, Section 7. |
13 // 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 |
14 |
22 // Roster query/result |
15 // Roster query/result |
23 type RosterQuery struct { |
16 type RosterQuery struct { |
24 // Should always be NsRoster, "query" |
17 // Should always be NsRoster, "query" |
25 XMLName xml.Name |
18 XMLName xml.Name |
34 Subscription string `xml:"attr"` |
27 Subscription string `xml:"attr"` |
35 Name string `xml:"attr"` |
28 Name string `xml:"attr"` |
36 Group []string |
29 Group []string |
37 } |
30 } |
38 |
31 |
39 func (riq *RosterIq) MarshalXML() ([]byte, os.Error) { |
|
40 return marshalXML(riq) |
|
41 } |
|
42 |
|
43 func (riq *RosterIq) InnerMarshal(w io.Writer) os.Error { |
|
44 return xml.Marshal(w, riq.Query) |
|
45 } |
|
46 |
|
47 // Implicitly becomes part of NewClient's extStanza arg. |
32 // Implicitly becomes part of NewClient's extStanza arg. |
48 func rosterStanza(name *xml.Name) ExtendedStanza { |
33 func newRosterQuery(name *xml.Name) interface{} { |
49 return &RosterIq{} |
34 return &RosterQuery{} |
50 } |
35 } |
51 |
36 |
52 // Synchronously fetch this entity's roster from the server and cache |
37 // Synchronously fetch this entity's roster from the server and cache |
53 // that information. |
38 // that information. |
54 func (cl *Client) fetchRoster() os.Error { |
39 func (cl *Client) fetchRoster() os.Error { |
55 iq := &RosterIq{Iq: Iq{From: cl.Jid.String(), Id: <- cl.Id, |
40 iq := &Iq{From: cl.Jid.String(), Id: <- cl.Id, Type: "get", |
56 Type: "get"}, Query: RosterQuery{XMLName: |
41 Nested: RosterQuery{XMLName: xml.Name{Local: "query", |
57 xml.Name{Local: "query", Space: NsRoster}}} |
42 Space: NsRoster}}} |
58 ch := make(chan os.Error) |
43 ch := make(chan os.Error) |
59 f := func(st Stanza) bool { |
44 f := func(st Stanza) bool { |
60 iq, ok := st.(*RosterIq) |
|
61 if !ok { |
|
62 ch <- os.NewError(fmt.Sprintf( |
|
63 "Roster query result not iq: %v", st)) |
|
64 return false |
|
65 } |
|
66 if iq.Type == "error" { |
45 if iq.Type == "error" { |
67 ch <- iq.Error |
46 ch <- iq.Error |
68 return false |
47 return false |
69 } |
48 } |
70 q := iq.Query |
49 rq, ok := st.XNested().(*RosterQuery) |
71 cl.roster = make(map[string] *RosterItem, len(q.Item)) |
50 if !ok { |
72 for _, item := range(q.Item) { |
51 ch <- os.NewError(fmt.Sprintf( |
|
52 "Roster query result not query: %v", st)) |
|
53 return false |
|
54 } |
|
55 cl.roster = make(map[string] *RosterItem, len(rq.Item)) |
|
56 for _, item := range(rq.Item) { |
73 cl.roster[item.Jid] = &item |
57 cl.roster[item.Jid] = &item |
74 } |
58 } |
75 ch <- nil |
59 ch <- nil |
76 return false |
60 return false |
77 } |
61 } |