Forgot to add the new xmpp.go from my last commit. Also added some
simple tests of data type marshaling.
--- a/structs.go Sat Dec 24 00:39:18 2011 -0700
+++ b/structs.go Sat Dec 24 09:55:26 2011 -0700
@@ -44,7 +44,7 @@
type StreamError struct {
cond definedCondition
- text errText
+ text *errText
}
var _ xml.Marshaler = &StreamError{}
@@ -54,7 +54,6 @@
}
type errText struct {
- XMLName xml.Name
Lang string
text string `xml:"chardata"`
}
@@ -88,7 +87,9 @@
buf := bytes.NewBuffer(nil)
buf.WriteString("<stream:error>")
xml.Marshal(buf, s.cond)
- xml.Marshal(buf, s.text)
+ if s.text != nil {
+ xml.Marshal(buf, s.text)
+ }
buf.WriteString("</stream:error>")
return buf.Bytes(), nil
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/structs_test.go Sat Dec 24 09:55:26 2011 -0700
@@ -0,0 +1,50 @@
+// 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 (
+ "bytes"
+ "testing"
+ "xml"
+)
+
+func TestStreamMarshal(t *testing.T) {
+ s := &Stream{to: "bob"}
+ exp := `<stream:stream to="bob">`
+ assertMarshal(t, exp, s)
+
+ s = &Stream{to: "bob", from: "alice", id: "#3", version: "5.3"}
+ exp = `<stream:stream to="bob" from="alice" id="#3" version="5.3">`
+ assertMarshal(t, exp, s)
+
+ s = &Stream{lang: "en_US"}
+ exp = `<stream:stream xml:lang="en_US">`
+ assertMarshal(t, exp, s)
+}
+
+func TestStreamErrorMarshal(t *testing.T) {
+ name := xml.Name{Space: nsStreams, Local: "ack"}
+ e := &StreamError{cond: definedCondition{name}}
+ exp := `<stream:error><ack xmlns="` + nsStreams +
+ `"></ack></stream:error>`;
+ assertMarshal(t, exp, e)
+
+ txt := errText{Lang: "pt", text: "things happen"}
+ e = &StreamError{cond: definedCondition{name}, text: &txt}
+ exp = `<stream:error><ack xmlns="` + nsStreams +
+ `"></ack><text xmlns="` + nsStreams +
+ `" xml:lang="pt">things happen</text></stream:error>`
+ assertMarshal(t, exp, e)
+}
+
+func assertMarshal(t *testing.T, expected string, marshal interface{}) {
+ buf := bytes.NewBuffer(nil)
+ xml.Marshal(buf, marshal)
+ observed := string(buf.Bytes())
+ if expected != observed {
+ t.Errorf("Expected:\n%s\nObserved:\n%s\n", expected,
+ observed)
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xmpp.go Sat Dec 24 09:55:26 2011 -0700
@@ -0,0 +1,60 @@
+// 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.
+
+// This package implements a simple XMPP client according to RFCs 3920
+// and 3921, plus the various XEPs at http://xmpp.org/protocols/.
+package xmpp
+
+import (
+ "fmt"
+ "net"
+ "os"
+)
+
+const (
+ serverSrv = "xmpp-server"
+ clientSrv = "xmpp-client"
+)
+
+// The client in a client-server XMPP connection.
+type Client struct {
+ //In <-chan *Stanza
+ //Out chan<- *Stanza
+ tcp *net.TCPConn
+}
+
+// Connect to the appropriate server and authenticate as the given JID
+// with the given password.
+func NewClient(jid *JID, password string) (*Client, os.Error) {
+ // Resolve the domain in the JID.
+ _, srvs, err := net.LookupSRV(clientSrv, "tcp", jid.Domain)
+ if err != nil {
+ return nil, os.NewError("LookupSrv " + jid.Domain +
+ ": " + err.String())
+ }
+
+ var c *net.TCPConn
+ for _, srv := range srvs {
+ addrStr := fmt.Sprintf("%s:%d", srv.Target, srv.Port)
+ addr, err := net.ResolveTCPAddr("tcp", addrStr)
+ if err != nil {
+ err = os.NewError(fmt.Sprintf("ResolveTCPAddr(%s): %s",
+ addrStr, err.String()))
+ continue
+ }
+ c, err = net.DialTCP("tcp", nil, addr)
+ if err != nil {
+ err = os.NewError(fmt.Sprintf("DialTCP(%s): %s",
+ addr, err.String()))
+ continue
+ }
+ }
+ if c == nil {
+ return nil, err
+ }
+
+ cl := Client{}
+ cl.tcp = c
+ return &cl, nil
+}