xmpp/structs.go
changeset 178 ccfebbd9f49b
parent 172 36a42bc073f0
child 179 4477c9f31f43
equal deleted inserted replaced
177:63f33bb8fa33 178:ccfebbd9f49b
     3 // This file contains data structures.
     3 // This file contains data structures.
     4 
     4 
     5 import (
     5 import (
     6 	"bytes"
     6 	"bytes"
     7 	"encoding/xml"
     7 	"encoding/xml"
     8 	"flag"
       
     9 	"fmt"
     8 	"fmt"
    10 	"log"
     9 	"log"
    11 	"reflect"
    10 	"reflect"
    12 	"regexp"
       
    13 	"strings"
    11 	"strings"
    14 )
    12 )
    15 
    13 
    16 // BUG(cjyar): Doesn't use stringprep. Could try the implementation at
    14 // BUG(cjyar): Doesn't use stringprep. Could try the implementation at
    17 // "code.google.com/p/go-idn/src/stringprep"
    15 // "code.google.com/p/go-idn/src/stringprep"
    18 
    16 
    19 // JID represents an entity that can communicate with other
    17 // JID represents an entity that can communicate with other
    20 // entities. It looks like node@domain/resource. Node and resource are
    18 // entities. It looks like node@domain/resource. Node and resource are
    21 // sometimes optional.
    19 // sometimes optional.
    22 type JID struct {
    20 type JID string
    23 	Node     string
       
    24 	Domain   string
       
    25 	Resource string
       
    26 }
       
    27 
       
    28 var _ fmt.Stringer = &JID{}
       
    29 var _ flag.Value = &JID{}
       
    30 
    21 
    31 // XMPP's <stream:stream> XML element
    22 // XMPP's <stream:stream> XML element
    32 type stream struct {
    23 type stream struct {
    33 	XMLName xml.Name `xml:"stream=http://etherx.jabber.org/streams stream"`
    24 	XMLName xml.Name `xml:"stream=http://etherx.jabber.org/streams stream"`
    34 	To      string   `xml:"to,attr"`
    25 	To      string   `xml:"to,attr"`
    96 
    87 
    97 // message stanza
    88 // message stanza
    98 type Message struct {
    89 type Message struct {
    99 	XMLName xml.Name `xml:"jabber:client message"`
    90 	XMLName xml.Name `xml:"jabber:client message"`
   100 	Header
    91 	Header
   101 	Subject []Text   `xml:"jabber:client subject"`
    92 	Subject []Text `xml:"jabber:client subject"`
   102 	Body    []Text   `xml:"jabber:client body"`
    93 	Body    []Text `xml:"jabber:client body"`
   103 	Thread  *Data  `xml:"jabber:client thread"`
    94 	Thread  *Data  `xml:"jabber:client thread"`
   104 }
    95 }
   105 
    96 
   106 var _ Stanza = &Message{}
    97 var _ Stanza = &Message{}
   107 
    98 
   108 // presence stanza
    99 // presence stanza
   109 type Presence struct {
   100 type Presence struct {
   110 	XMLName xml.Name `xml:"presence"`
   101 	XMLName xml.Name `xml:"presence"`
   111 	Header
   102 	Header
   112 	Show     *Data   `xml:"jabber:client show"`
   103 	Show     *Data  `xml:"jabber:client show"`
   113 	Status   []Text  `xml:"jabber:client status"`
   104 	Status   []Text `xml:"jabber:client status"`
   114 	Priority *Data   `xml:"jabber:client priority"`
   105 	Priority *Data  `xml:"jabber:client priority"`
   115 }
   106 }
   116 
   107 
   117 var _ Stanza = &Presence{}
   108 var _ Stanza = &Presence{}
   118 
   109 
   119 // iq stanza
   110 // iq stanza
   145 // Holds human-readable text, with an optional language
   136 // Holds human-readable text, with an optional language
   146 // specification. Generally multiple instances of these can be found
   137 // specification. Generally multiple instances of these can be found
   147 // together, allowing the software to choose which language to present
   138 // together, allowing the software to choose which language to present
   148 // to the user.
   139 // to the user.
   149 type Text struct {
   140 type Text struct {
   150 	XMLName xml.Name
   141 	XMLName  xml.Name
   151 	Lang     string `xml:"http://www.w3.org/XML/1998/namespace lang,attr,omitempty"`
   142 	Lang     string `xml:"http://www.w3.org/XML/1998/namespace lang,attr,omitempty"`
   152 	Chardata string `xml:",chardata"`
   143 	Chardata string `xml:",chardata"`
   153 }
   144 }
   154 
   145 
   155 // Non-human-readable content of some sort, used by the protocol.
   146 // Non-human-readable content of some sort, used by the protocol.
   156 type Data struct {
   147 type Data struct {
   157 	XMLName xml.Name
   148 	XMLName  xml.Name
   158 	Chardata string `xml:",chardata"`
   149 	Chardata string `xml:",chardata"`
   159 }
   150 }
   160 
   151 
   161 // Holds an XML element not described by the more specific types.
   152 // Holds an XML element not described by the more specific types.
   162 type Generic struct {
   153 type Generic struct {
   165 	Chardata string   `xml:",chardata"`
   156 	Chardata string   `xml:",chardata"`
   166 }
   157 }
   167 
   158 
   168 var _ fmt.Stringer = &Generic{}
   159 var _ fmt.Stringer = &Generic{}
   169 
   160 
   170 func (jid *JID) String() string {
   161 func (j JID) Node() string {
   171 	result := jid.Domain
   162 	at := strings.Index(string(j), "@")
   172 	if jid.Node != "" {
   163 	if at == -1 {
   173 		result = jid.Node + "@" + result
   164 		return ""
   174 	}
   165 	}
   175 	if jid.Resource != "" {
   166 	return string(j[:at])
   176 		result = result + "/" + jid.Resource
   167 }
   177 	}
   168 
   178 	return result
   169 func (j JID) Domain() string {
   179 }
   170 	at := strings.Index(string(j), "@")
   180 
   171 	slash := strings.LastIndex(string(j), "/")
   181 // Set implements flag.Value.
   172 	if slash == -1 {
   182 func (jid *JID) Set(val string) error {
   173 		slash = len(j)
   183 	r := regexp.MustCompile("^(([^@/]+)@)?([^@/]+)(/([^@/]+))?$")
   174 	}
   184 	parts := r.FindStringSubmatch(val)
   175 	return string(j[at+1 : slash])
   185 	if parts == nil {
   176 }
   186 		return fmt.Errorf("%s doesn't match user@domain/resource", val)
   177 
   187 	}
   178 func (j JID) Resource() string {
   188 	// jid.Node = stringprep.Nodeprep(parts[2])
   179 	slash := strings.LastIndex(string(j), "/")
   189 	// jid.Domain = stringprep.Nodeprep(parts[3])
   180 	if slash == -1 {
   190 	// jid.Resource = stringprep.Resourceprep(parts[5])
   181 		return ""
   191 	jid.Node = parts[2]
   182 	}
   192 	jid.Domain = parts[3]
   183 	return string(j[slash+1:])
   193 	jid.Resource = parts[5]
       
   194 	return nil
       
   195 }
   184 }
   196 
   185 
   197 func (s *stream) String() string {
   186 func (s *stream) String() string {
   198 	var buf bytes.Buffer
   187 	var buf bytes.Buffer
   199 	buf.WriteString(`<stream:stream xmlns="`)
   188 	buf.WriteString(`<stream:stream xmlns="`)