Added Client.StartSession().
authorChris Jones <chris@cjones.org>
Thu, 29 Dec 2011 09:48:36 -0700
changeset 28 78961db80bae
parent 27 13bcc96a5a6c
child 29 a456133ed0ac
Added Client.StartSession().
structs.go
xmpp.go
--- a/structs.go	Wed Dec 28 16:10:20 2011 -0700
+++ b/structs.go	Thu Dec 29 09:48:36 2011 -0700
@@ -105,6 +105,9 @@
 	Type string `xml:"attr"`
 	Lang string `xml:"attr"`
 	Error *Error
+	Subject *Generic
+	Body *Generic
+	Thread *Generic
 	Any *Generic
 }
 var _ xml.Marshaler = &Message{}
@@ -118,6 +121,9 @@
 	Type string `xml:"attr"`
 	Lang string `xml:"attr"`
 	Error *Error
+	Show *Generic
+	Status *Generic
+	Priority *Generic
 	Any *Generic
 }
 var _ xml.Marshaler = &Presence{}
@@ -144,6 +150,7 @@
 	Any *Generic
 }
 var _ xml.Marshaler = &Error{}
+var _ os.Error = &Error{}
 
 // Holds an XML element not described by the more specific types.
 type Generic struct {
@@ -302,6 +309,11 @@
 	return buf.Bytes(), nil
 }
 
+func (er *Error) String() string {
+	bytes, _ := er.MarshalXML()
+	return string(bytes)
+}
+
 func (m *Message) XName() string {
 	return "message"
 }
--- a/xmpp.go	Wed Dec 28 16:10:20 2011 -0700
+++ b/xmpp.go	Thu Dec 29 09:48:36 2011 -0700
@@ -13,9 +13,11 @@
 	"bytes"
 	"fmt"
 	"io"
+	"log"
 	"net"
 	"os"
 	"sync"
+	"xml"
 )
 
 const (
@@ -28,6 +30,7 @@
 	nsTLS = "urn:ietf:params:xml:ns:xmpp-tls"
 	nsSASL = "urn:ietf:params:xml:ns:xmpp-sasl"
 	nsBind = "urn:ietf:params:xml:ns:xmpp-bind"
+	nsSession = "urn:ietf:params:xml:ns:xmpp-session"
 
 	// DNS SRV names
 	serverSrv = "xmpp-server"
@@ -218,6 +221,8 @@
 
 // This convenience function may be used to generate a unique id for
 // use in the Id fields of iq, message, and presence stanzas.
+// BUG(cjyar) This should be replaced with a goroutine that feeds a
+// channel.
 func (cl *Client) NextId() string {
 	cl.idMutex.Lock()
 	defer cl.idMutex.Unlock()
@@ -225,3 +230,32 @@
 	cl.nextId++
 	return fmt.Sprintf("id_%d", id)
 }
+
+// Start an XMPP session. This should typically be done immediately
+// after creating the new Client. Once the session has been
+// established, pr will be sent as an initial presence; nil means
+// don't send initial presence. The initial presence can be a
+// newly-initialized Presence struct. See RFC 3921, Section 3.
+func (cl *Client) StartSession(pr *Presence) os.Error {
+	id := cl.NextId()
+	iq := &Iq{To: cl.Jid.Domain, Id: id, Type: "set", Any:
+		&Generic{XMLName: xml.Name{Space: nsSession, Local:
+				"session"}}}
+	ch := make(chan os.Error)
+	f := func(st Stanza) bool {
+		if st.XType() == "error" {
+			log.Printf("Can't start session: %v", st)
+			ch <- st.XError()
+			return false
+		}
+		if pr != nil {
+			cl.Out <- pr
+		}
+		ch <- nil
+		return false
+	}
+	cl.HandleStanza(id, f)
+	cl.Out <- iq
+	// Now wait until the callback is called.
+	return <-ch
+}