--- a/xmpp/structs.go Sun Feb 09 09:50:38 2014 -0700
+++ b/xmpp/structs.go Sun Feb 09 09:52:28 2014 -0700
@@ -5,26 +5,19 @@
import (
"bytes"
"encoding/xml"
- "flag"
"fmt"
- // BUG(cjyar): Doesn't use stringprep. Could try the implementation at
- // "code.google.com/p/go-idn/src/stringprep"
+ "log"
"reflect"
- "regexp"
"strings"
)
+// BUG(cjyar): Doesn't use stringprep. Could try the implementation at
+// "code.google.com/p/go-idn/src/stringprep"
+
// JID represents an entity that can communicate with other
// entities. It looks like node@domain/resource. Node and resource are
// sometimes optional.
-type JID struct {
- Node string
- Domain string
- Resource string
-}
-
-var _ fmt.Stringer = &JID{}
-var _ flag.Value = &JID{}
+type JID string
// XMPP's <stream:stream> XML element
type stream struct {
@@ -82,8 +75,8 @@
// One of the three core XMPP stanza types: iq, message, presence. See
// RFC3920, section 9.
type Header struct {
- To string `xml:"to,attr,omitempty"`
- From string `xml:"from,attr,omitempty"`
+ To JID `xml:"to,attr,omitempty"`
+ From JID `xml:"from,attr,omitempty"`
Id string `xml:"id,attr,omitempty"`
Type string `xml:"type,attr,omitempty"`
Lang string `xml:"http://www.w3.org/XML/1998/namespace lang,attr,omitempty"`
@@ -96,9 +89,9 @@
type Message struct {
XMLName xml.Name `xml:"jabber:client message"`
Header
- Subject *Generic `xml:"jabber:client subject"`
- Body *Generic `xml:"jabber:client body"`
- Thread *Generic `xml:"jabber:client thread"`
+ Subject []Text `xml:"jabber:client subject"`
+ Body []Text `xml:"jabber:client body"`
+ Thread *Data `xml:"jabber:client thread"`
}
var _ Stanza = &Message{}
@@ -107,9 +100,9 @@
type Presence struct {
XMLName xml.Name `xml:"presence"`
Header
- Show *Generic `xml:"jabber:client show"`
- Status *Generic `xml:"jabber:client status"`
- Priority *Generic `xml:"jabber:client priority"`
+ Show *Data `xml:"jabber:client show"`
+ Status []Text `xml:"jabber:client status"`
+ Priority *Data `xml:"jabber:client priority"`
}
var _ Stanza = &Presence{}
@@ -137,7 +130,23 @@
type bindIq struct {
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-bind bind"`
Resource *string `xml:"resource"`
- Jid *string `xml:"jid"`
+ Jid *JID `xml:"jid"`
+}
+
+// Holds human-readable text, with an optional language
+// specification. Generally multiple instances of these can be found
+// together, allowing the software to choose which language to present
+// to the user.
+type Text struct {
+ XMLName xml.Name
+ Lang string `xml:"http://www.w3.org/XML/1998/namespace lang,attr,omitempty"`
+ Chardata string `xml:",chardata"`
+}
+
+// Non-human-readable content of some sort, used by the protocol.
+type Data struct {
+ XMLName xml.Name
+ Chardata string `xml:",chardata"`
}
// Holds an XML element not described by the more specific types.
@@ -149,32 +158,38 @@
var _ fmt.Stringer = &Generic{}
-func (jid *JID) String() string {
- result := jid.Domain
- if jid.Node != "" {
- result = jid.Node + "@" + result
+func (j JID) Node() string {
+ at := strings.Index(string(j), "@")
+ if at == -1 {
+ return ""
}
- if jid.Resource != "" {
- result = result + "/" + jid.Resource
- }
- return result
+ return string(j[:at])
}
-// Set implements flag.Value. It returns true if it successfully
-// parses the string.
-func (jid *JID) Set(val string) error {
- r := regexp.MustCompile("^(([^@/]+)@)?([^@/]+)(/([^@/]+))?$")
- parts := r.FindStringSubmatch(val)
- if parts == nil {
- return fmt.Errorf("%s doesn't match user@domain/resource", val)
+func (j JID) Domain() string {
+ at := strings.Index(string(j), "@")
+ slash := strings.LastIndex(string(j), "/")
+ if slash == -1 {
+ slash = len(j)
}
- // jid.Node = stringprep.Nodeprep(parts[2])
- // jid.Domain = stringprep.Nodeprep(parts[3])
- // jid.Resource = stringprep.Resourceprep(parts[5])
- jid.Node = parts[2]
- jid.Domain = parts[3]
- jid.Resource = parts[5]
- return nil
+ return string(j[at+1 : slash])
+}
+
+func (j JID) Resource() string {
+ slash := strings.LastIndex(string(j), "/")
+ if slash == -1 {
+ return ""
+ }
+ return string(j[slash+1:])
+}
+
+// Returns the bare JID, which is the JID without the resource part.
+func (j JID) Bare() JID {
+ node := j.Node()
+ if node == "" {
+ return JID(j.Domain())
+ }
+ return JID(fmt.Sprintf("%s@%s", node, j.Domain()))
}
func (s *stream) String() string {
@@ -260,7 +275,7 @@
func (er *Error) Error() string {
buf, err := xml.Marshal(er)
if err != nil {
- Warn.Log("double bad error: couldn't marshal error")
+ log.Println("double bad error: couldn't marshal error")
return "unreadable error"
}
return string(buf)
@@ -269,7 +284,7 @@
var bindExt Extension = Extension{}
func init() {
- bindExt.StanzaHandlers = make(map[xml.Name]reflect.Type)
+ bindExt.StanzaTypes = make(map[xml.Name]reflect.Type)
bName := xml.Name{Space: NsBind, Local: "bind"}
- bindExt.StanzaHandlers[bName] = reflect.TypeOf(bindIq{})
+ bindExt.StanzaTypes[bName] = reflect.TypeOf(bindIq{})
}