structs.go
changeset 110 7696e6a01709
parent 108 8ec06aff386e
child 111 36287f2cf06e
equal deleted inserted replaced
109:3887d7ad19c1 110:7696e6a01709
     7 // This file contains data structures.
     7 // This file contains data structures.
     8 
     8 
     9 import (
     9 import (
    10 	"bytes"
    10 	"bytes"
    11 	"encoding/xml"
    11 	"encoding/xml"
    12 	"errors"
       
    13 	"flag"
    12 	"flag"
    14 	"fmt"
    13 	"fmt"
    15 	// BUG(cjyar): We should use stringprep
    14 	// BUG(cjyar): We should use stringprep
    16 	// "code.google.com/p/go-idn/src/stringprep"
    15 	// "code.google.com/p/go-idn/src/stringprep"
    17 	"regexp"
    16 	"regexp"
    78 	Any       *Generic
    77 	Any       *Generic
    79 }
    78 }
    80 
    79 
    81 // One of the three core XMPP stanza types: iq, message, presence. See
    80 // One of the three core XMPP stanza types: iq, message, presence. See
    82 // RFC3920, section 9.
    81 // RFC3920, section 9.
    83 type Stanza interface {
    82 type Stanza struct {
    84 	// // Returns "iq", "message", or "presence".
       
    85 	// GetName() string
       
    86 	// // The to attribute.
       
    87 	// GetTo() string
       
    88 	// // The from attribute.
       
    89 	// GetFrom() string
       
    90 	// The id attribute. TODO maybe remove this.
       
    91 	GetId() string
       
    92 	// // The type attribute.
       
    93 	// GetType() string
       
    94 	// // The xml:lang attribute.
       
    95 	// GetLang() string
       
    96 	// // A nested error element, if any.
       
    97 	// GetError() *Error
       
    98 	// // Zero or more (non-error) nested elements. These will be in
       
    99 	// // namespaces managed by extensions.
       
   100 	// GetNested() []interface{}
       
   101 	addNested(interface{})
       
   102 	innerxml() string
       
   103 }
       
   104 
       
   105 // message stanza
       
   106 type Message struct {
       
   107 	XMLName  xml.Name `xml:"message"`
       
   108 	To       string   `xml:"to,attr,omitempty"`
       
   109 	From     string   `xml:"from,attr,omitempty"`
       
   110 	Id       string   `xml:"id,attr,omitempty"`
       
   111 	Type     string   `xml:"type,attr,omitempty"`
       
   112 	Lang     string   `xml:"http://www.w3.org/XML/1998/namespace lang,attr,omitempty"`
       
   113 	Innerxml string   `xml:",innerxml"`
       
   114 	Error    *Error
       
   115 	Subject  *Generic `xml:"subject"`
       
   116 	Body     *Generic `xml:"body"`
       
   117 	Thread   *Generic `xml:"thread"`
       
   118 	Nested   []interface{}
       
   119 }
       
   120 var _ Stanza = &Message{}
       
   121 
       
   122 // presence stanza
       
   123 type Presence struct {
       
   124 	XMLName  xml.Name `xml:"presence"`
       
   125 	To       string   `xml:"to,attr,omitempty"`
       
   126 	From     string   `xml:"from,attr,omitempty"`
       
   127 	Id       string   `xml:"id,attr,omitempty"`
       
   128 	Type     string   `xml:"type,attr,omitempty"`
       
   129 	Lang     string   `xml:"http://www.w3.org/XML/1998/namespace lang,attr,omitempty"`
       
   130 	Innerxml string   `xml:",innerxml"`
       
   131 	Error    *Error
       
   132 	Show     *Generic `xml:"show"`
       
   133 	Status   *Generic `xml:"status"`
       
   134 	Priority *Generic `xml:"priority"`
       
   135 	Nested   []interface{}
       
   136 }
       
   137 var _ Stanza = &Presence{}
       
   138 
       
   139 // iq stanza
       
   140 type Iq struct {
       
   141 	XMLName  xml.Name `xml:"iq"`
       
   142 	To       string   `xml:"to,attr,omitempty"`
    83 	To       string   `xml:"to,attr,omitempty"`
   143 	From     string   `xml:"from,attr,omitempty"`
    84 	From     string   `xml:"from,attr,omitempty"`
   144 	Id       string   `xml:"id,attr,omitempty"`
    85 	Id       string   `xml:"id,attr,omitempty"`
   145 	Type     string   `xml:"type,attr,omitempty"`
    86 	Type     string   `xml:"type,attr,omitempty"`
   146 	Lang     string   `xml:"http://www.w3.org/XML/1998/namespace lang,attr,omitempty"`
    87 	Lang     string   `xml:"http://www.w3.org/XML/1998/namespace lang,attr,omitempty"`
   147 	Innerxml string   `xml:",innerxml"`
    88 	Innerxml string   `xml:",innerxml"`
   148 	Error    *Error
    89 	Error    *Error
   149 	Nested   []interface{}
    90 	Nested   []interface{}
   150 }
    91 }
   151 var _ Stanza = &Iq{}
    92 
       
    93 // message stanza
       
    94 type Message struct {
       
    95 	XMLName  xml.Name `xml:"message"`
       
    96 	Stanza
       
    97 	Subject  *Generic `xml:"subject"`
       
    98 	Body     *Generic `xml:"body"`
       
    99 	Thread   *Generic `xml:"thread"`
       
   100 }
       
   101 
       
   102 // presence stanza
       
   103 type Presence struct {
       
   104 	XMLName  xml.Name `xml:"presence"`
       
   105 	Stanza
       
   106 	Show     *Generic `xml:"show"`
       
   107 	Status   *Generic `xml:"status"`
       
   108 	Priority *Generic `xml:"priority"`
       
   109 }
       
   110 
       
   111 // iq stanza
       
   112 type Iq struct {
       
   113 	XMLName  xml.Name `xml:"iq"`
       
   114 	Stanza
       
   115 }
   152 
   116 
   153 // Describes an XMPP stanza error. See RFC 3920, Section 9.3.
   117 // Describes an XMPP stanza error. See RFC 3920, Section 9.3.
   154 type Error struct {
   118 type Error struct {
   155 	XMLName xml.Name `xml:"error"`
   119 	XMLName xml.Name `xml:"error"`
   156 	// The error type attribute.
   120 	// The error type attribute.
   278 		return "unreadable error"
   242 		return "unreadable error"
   279 	}
   243 	}
   280 	return string(buf)
   244 	return string(buf)
   281 }
   245 }
   282 
   246 
   283 func (m *Message) GetId() string {
       
   284 	return m.Id
       
   285 }
       
   286 
       
   287 func (m *Message) addNested(n interface{}) {
       
   288 	m.Nested = append(m.Nested, n)
       
   289 }
       
   290 
       
   291 func (m *Message) innerxml() string {
       
   292 	return m.Innerxml
       
   293 }
       
   294 
       
   295 func (p *Presence) GetId() string {
       
   296 	return p.Id
       
   297 }
       
   298 
       
   299 func (p *Presence) addNested(n interface{}) {
       
   300 	p.Nested = append(p.Nested, n)
       
   301 }
       
   302 
       
   303 func (p *Presence) innerxml() string {
       
   304 	return p.Innerxml
       
   305 }
       
   306 
       
   307 func (iq *Iq) GetId() string {
       
   308 	return iq.Id
       
   309 }
       
   310 
       
   311 func (iq *Iq) addNested(n interface{}) {
       
   312 	iq.Nested = append(iq.Nested, n)
       
   313 }
       
   314 
       
   315 func (iq *Iq) innerxml() string {
       
   316 	return iq.Innerxml
       
   317 }
       
   318 
       
   319 
       
   320 // Parse a string into a struct implementing Stanza -- this will be
       
   321 // either an Iq, a Message, or a Presence.
       
   322 func ParseStanza(str string) (Stanza, error) {
       
   323 	r := strings.NewReader(str)
       
   324 	p := xml.NewDecoder(r)
       
   325 	tok, err := p.Token()
       
   326 	if err != nil {
       
   327 		return nil, err
       
   328 	}
       
   329 	se, ok := tok.(xml.StartElement)
       
   330 	if !ok {
       
   331 		return nil, errors.New("Not a start element")
       
   332 	}
       
   333 	var stan Stanza
       
   334 	switch se.Name.Local {
       
   335 	case "iq":
       
   336 		stan = &Iq{}
       
   337 	case "message":
       
   338 		stan = &Message{}
       
   339 	case "presence":
       
   340 		stan = &Presence{}
       
   341 	default:
       
   342 		return nil, errors.New("Not iq, message, or presence")
       
   343 	}
       
   344 	err = p.DecodeElement(stan, &se)
       
   345 	if err != nil {
       
   346 		return nil, err
       
   347 	}
       
   348 	return stan, nil
       
   349 }
       
   350 
       
   351 var bindExt Extension = Extension{StanzaHandlers: map[string]func(*xml.Name) interface{}{NsBind: newBind},
   247 var bindExt Extension = Extension{StanzaHandlers: map[string]func(*xml.Name) interface{}{NsBind: newBind},
   352 	Start: func(cl *Client) {}}
   248 	Start: func(cl *Client) {}}
   353 
   249 
   354 func newBind(name *xml.Name) interface{} {
   250 func newBind(name *xml.Name) interface{} {
   355 	return &bindIq{}
   251 	return &bindIq{}
   356 }
   252 }
       
   253 
       
   254 func getStanza(v interface{}) *Stanza {
       
   255 	switch s := v.(type) {
       
   256 	case *Iq:
       
   257 		return &s.Stanza
       
   258 	case *Message:
       
   259 		return &s.Stanza
       
   260 	case *Presence:
       
   261 		return &s.Stanza
       
   262 	}
       
   263 	return nil
       
   264 }