# HG changeset patch # User Chris Jones # Date 1325177316 25200 # Node ID 78961db80baef8d332650dbb35c820bc8d8f553e # Parent 13bcc96a5a6c7e81da01cf7b005c31d853a83257 Added Client.StartSession(). diff -r 13bcc96a5a6c -r 78961db80bae structs.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" } diff -r 13bcc96a5a6c -r 78961db80bae xmpp.go --- 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 +}