roster.go
changeset 36 9fe022261dcc
child 37 fbda8e925fdf
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/roster.go	Fri Dec 30 21:49:00 2011 -0700
@@ -0,0 +1,91 @@
+// Copyright 2011 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xmpp
+
+import (
+	"fmt"
+	"io"
+	"os"
+	"xml"
+)
+
+// This file contains support for roster management, RFC 3921, Section 7.
+
+type RosterIq struct {
+	Iq
+	Query RosterQuery
+}
+var _ ExtendedStanza = &RosterIq{}
+
+// Roster query/result
+type RosterQuery struct {
+	// Should always be NsRoster, "query"
+	XMLName xml.Name
+	Item []RosterItem
+}
+
+// See RFC 3921, Section 7.1.
+type RosterItem struct {
+	// Should always be "item"
+	XMLName xml.Name
+	Jid string `xml:"attr"`
+	Subscription string `xml:"attr"`
+	Name string `xml:"attr"`
+	Group []string
+}
+
+func (riq *RosterIq) InnerMarshal(w io.Writer) os.Error {
+	return xml.Marshal(w, riq.Query)
+}
+
+// Implicitly becomes part of NewClient's extStanza arg.
+func rosterStanza(name *xml.Name) ExtendedStanza {
+	return &RosterIq{}
+}
+
+// Synchronously fetch this entity's roster from the server and cache
+// that information.
+func (cl *Client) fetchRoster() os.Error {
+	iq := &RosterIq{Iq: Iq{From: cl.Jid.String(), Id: <- cl.Id,
+		Type: "get"}, Query: RosterQuery{XMLName:
+			xml.Name{Local: "query", Space: NsRoster}}}
+	ch := make(chan os.Error)
+	f := func(st Stanza) bool {
+		iq, ok := st.(*RosterIq)
+		if !ok {
+			ch <- os.NewError(fmt.Sprintf(
+				"Roster query result not iq: %v", st))
+			return false
+		}
+		if iq.Type == "error" {
+			ch <- iq.Error
+			return false
+		}
+		q := iq.Query
+		cl.roster = make(map[string] *RosterItem, len(q.Item))
+		for _, item := range(q.Item) {
+			cl.roster[item.Jid] = &item
+		}
+		ch <- nil
+		return false
+	}
+	cl.HandleStanza(iq.Id, f)
+	cl.Out <- iq
+	// Wait for f to complete.
+	return <- ch
+}
+
+// BUG(cjyar) The roster isn't actually updated when things change.
+
+// Returns the current roster of other entities which this one has a
+// relationship with. Changes to the roster will be signaled by an
+// appropriate Iq appearing on Client.In. See RFC 3921, Section 7.4.
+func (cl *Client) Roster() map[string] *RosterItem {
+	r := make(map[string] *RosterItem)
+	for key, val := range(cl.roster) {
+		r[key] = val
+	}
+	return r
+}