structs.go
branchgo.weekly.2012-01-15
changeset 93 fbd51fa6b7ea
parent 75 03a923eb5c01
child 94 0ef947611eec
equal deleted inserted replaced
87:d19b556d4ea6 93:fbd51fa6b7ea
    29 var _ fmt.Stringer = &JID{}
    29 var _ fmt.Stringer = &JID{}
    30 var _ flag.Value = &JID{}
    30 var _ flag.Value = &JID{}
    31 
    31 
    32 // XMPP's <stream:stream> XML element
    32 // XMPP's <stream:stream> XML element
    33 type stream struct {
    33 type stream struct {
       
    34 	XMLName xml.Name `xml:"stream stream"`
    34 	To      string `xml:"to,attr"`
    35 	To      string `xml:"to,attr"`
    35 	From    string `xml:"from,attr"`
    36 	From    string `xml:"from,attr"`
    36 	Id      string `xml:"id,attr"`
    37 	Id      string `xml:"id,attr"`
    37 	Lang    string `xml:"lang,attr"`
    38 	Lang    string `xml:"lang,attr"`
    38 	Version string `xml:"version,attr"`
    39 	Version string `xml:"version,attr"`
    39 }
    40 }
    40 
    41 
    41 var _ xml.Marshaler = &stream{}
       
    42 var _ fmt.Stringer = &stream{}
    42 var _ fmt.Stringer = &stream{}
    43 
    43 
    44 // <stream:error>
    44 // <stream:error>
    45 type streamError struct {
    45 type streamError struct {
    46 	Any  Generic `xml:",any"`
    46 	Any  Generic  `xml:",any"`
    47 	Text *errText `xml:"text"`
    47 	Text *errText `xml:"text"`
    48 }
    48 }
    49 
    49 
    50 var _ xml.Marshaler = &streamError{}
       
    51 
       
    52 type errText struct {
    50 type errText struct {
       
    51 	XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-streams text"`
    53 	Lang string `xml:"lang,attr"`
    52 	Lang string `xml:"lang,attr"`
    54 	Text string `xml:",chardata"`
    53 	Text string `xml:",chardata"`
    55 }
    54 }
    56 
    55 
    57 var _ xml.Marshaler = &errText{}
       
    58 
       
    59 type Features struct {
    56 type Features struct {
    60 	Starttls   *starttls `xml:"starttls"`
    57 	Starttls   *starttls `xml:"starttls"`
    61 	Mechanisms mechs `xml:"mechanisms"`
    58 	Mechanisms mechs     `xml:"mechanisms"`
    62 	Bind       *bindIq `xml:"bind"`
    59 	Bind       *bindIq   `xml:"bind"`
    63 	Session    *Generic `xml:"session"`
    60 	Session    *Generic  `xml:"session"`
    64 	Any        *Generic `xml:",any"`
    61 	Any        *Generic  `xml:",any"`
    65 }
    62 }
    66 
    63 
    67 type starttls struct {
    64 type starttls struct {
    68 	XMLName  xml.Name
    65 	XMLName  xml.Name
    69 	Required *string `xml:"required"`
    66 	Required *string `xml:"required"`
    73 	Mechanism []string `xml:"mechanism"`
    70 	Mechanism []string `xml:"mechanism"`
    74 }
    71 }
    75 
    72 
    76 type auth struct {
    73 type auth struct {
    77 	XMLName   xml.Name
    74 	XMLName   xml.Name
    78 	Chardata  string `xml:",chardata"`
    75 	Chardata  string   `xml:",chardata"`
    79 	Mechanism string `xml:"mechanism,attr"`
    76 	Mechanism string   `xml:"mechanism,attr"`
    80 	Any       *Generic `xml:",any"`
    77 	Any       *Generic `xml:",any"`
    81 }
    78 }
    82 
    79 
    83 // 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
    84 // RFC3920, section 9.
    81 // RFC3920, section 9.
   104 	innerxml() string
   101 	innerxml() string
   105 }
   102 }
   106 
   103 
   107 // message stanza
   104 // message stanza
   108 type Message struct {
   105 type Message struct {
   109 	To       string `xml:"to,attr"`
   106 	XMLName  xml.Name `xml:"message"`
   110 	From     string `xml:"from,attr"`
   107 	To       string   `xml:"to,attr,omitempty"`
   111 	Id       string `xml:"id,attr"`
   108 	From     string   `xml:"from,attr,omitempty"`
   112 	Type     string `xml:"type,attr"`
   109 	Id       string   `xml:"id,attr,omitempty"`
   113 	Lang     string `xml:"lang,attr"`
   110 	Type     string   `xml:"type,attr,omitempty"`
   114 	Innerxml string `xml:",innerxml"`
   111 	Lang     string   `xml:"lang,attr,omitempty"`
   115 	Error    *Error `xml:"error"`
   112 	Innerxml string   `xml:",innerxml"`
       
   113 	Error    *Error   `xml:"error"`
   116 	Subject  *Generic `xml:"subject"`
   114 	Subject  *Generic `xml:"subject"`
   117 	Body     *Generic `xml:"body"`
   115 	Body     *Generic `xml:"body"`
   118 	Thread   *Generic `xml:"thread"`
   116 	Thread   *Generic `xml:"thread"`
   119 	Nested   []interface{}
   117 	Nested   []interface{}
   120 }
   118 }
   121 
   119 
   122 var _ xml.Marshaler = &Message{}
       
   123 var _ Stanza = &Message{}
   120 var _ Stanza = &Message{}
   124 
   121 
   125 // presence stanza
   122 // presence stanza
   126 type Presence struct {
   123 type Presence struct {
   127 	To       string `xml:"to,attr"`
   124 	XMLName  xml.Name `xml:"presence"`
   128 	From     string `xml:"from,attr"`
   125 	To       string   `xml:"to,attr,omitempty"`
   129 	Id       string `xml:"id,attr"`
   126 	From     string   `xml:"from,attr,omitempty"`
   130 	Type     string `xml:"type,attr"`
   127 	Id       string   `xml:"id,attr,omitempty"`
   131 	Lang     string `xml:"lang,attr"`
   128 	Type     string   `xml:"type,attr,omitempty"`
   132 	Innerxml string `xml:",innerxml"`
   129 	Lang     string   `xml:"lang,attr,omitempty"`
   133 	Error    *Error `xml:"error"`
   130 	Innerxml string   `xml:",innerxml"`
       
   131 	Error    *Error   `xml:"error"`
   134 	Show     *Generic `xml:"show"`
   132 	Show     *Generic `xml:"show"`
   135 	Status   *Generic `xml:"status"`
   133 	Status   *Generic `xml:"status"`
   136 	Priority *Generic `xml:"priority"`
   134 	Priority *Generic `xml:"priority"`
   137 	Nested   []interface{}
   135 	Nested   []interface{}
   138 }
   136 }
   139 
   137 
   140 var _ xml.Marshaler = &Presence{}
       
   141 var _ Stanza = &Presence{}
   138 var _ Stanza = &Presence{}
   142 
   139 
   143 // iq stanza
   140 // iq stanza
   144 type Iq struct {
   141 type Iq struct {
   145 	To       string `xml:"to,attr"`
   142 	XMLName  xml.Name `xml:"iq"`
   146 	From     string `xml:"from,attr"`
   143 	To       string `xml:"to,attr,omitempty"`
   147 	Id       string `xml:"id,attr"`
   144 	From     string `xml:"from,attr,omitempty"`
   148 	Type     string `xml:"type,attr"`
   145 	Id       string `xml:"id,attr,omitempty"`
   149 	Lang     string `xml:"lang,attr"`
   146 	Type     string `xml:"type,attr,omitempty"`
       
   147 	Lang     string `xml:"xml lang,attr,omitempty"`
   150 	Innerxml string `xml:",innerxml"`
   148 	Innerxml string `xml:",innerxml"`
   151 	Error    *Error `xml:"error"`
   149 	Error    *Error `xml:"error"`
   152 	Nested   []interface{}
   150 	Nested   []interface{}
   153 }
   151 }
   154 
   152 
   155 var _ xml.Marshaler = &Iq{}
       
   156 var _ Stanza = &Iq{}
   153 var _ Stanza = &Iq{}
   157 
   154 
   158 // Describes an XMPP stanza error. See RFC 3920, Section 9.3.
   155 // Describes an XMPP stanza error. See RFC 3920, Section 9.3.
   159 type Error struct {
   156 type Error struct {
   160 	XMLName xml.Name `xml:"error"`
   157 	XMLName xml.Name `xml:"error"`
   175 
   172 
   176 // Holds an XML element not described by the more specific types.
   173 // Holds an XML element not described by the more specific types.
   177 type Generic struct {
   174 type Generic struct {
   178 	XMLName  xml.Name
   175 	XMLName  xml.Name
   179 	Any      *Generic `xml:",any"`
   176 	Any      *Generic `xml:",any"`
   180 	Chardata string `xml:",chardata"`
   177 	Chardata string   `xml:",chardata"`
   181 }
   178 }
   182 
   179 
   183 var _ fmt.Stringer = &Generic{}
   180 var _ fmt.Stringer = &Generic{}
   184 
   181 
   185 func (jid *JID) String() string {
   182 func (jid *JID) String() string {
   205 	jid.Domain = parts[3]
   202 	jid.Domain = parts[3]
   206 	jid.Resource = parts[5]
   203 	jid.Resource = parts[5]
   207 	return nil
   204 	return nil
   208 }
   205 }
   209 
   206 
   210 func (s *stream) MarshalXML() ([]byte, error) {
   207 func (s *stream) String() string {
   211 	buf := bytes.NewBuffer(nil)
   208 	buf := bytes.NewBuffer(nil)
   212 	buf.WriteString("<stream:stream")
   209 	buf.WriteString("<stream:stream")
   213 	writeField(buf, "xmlns", "jabber:client")
       
   214 	writeField(buf, "xmlns:stream", NsStream)
       
   215 	writeField(buf, "to", s.To)
   210 	writeField(buf, "to", s.To)
   216 	writeField(buf, "from", s.From)
   211 	writeField(buf, "from", s.From)
   217 	writeField(buf, "id", s.Id)
   212 	writeField(buf, "id", s.Id)
   218 	writeField(buf, "xml:lang", s.Lang)
   213 	writeField(buf, "xml:lang", s.Lang)
   219 	writeField(buf, "version", s.Version)
   214 	writeField(buf, "version", s.Version)
   220 	buf.WriteString(">")
   215 	buf.WriteString(">")
   221 	// We never write </stream:stream>
   216 	return buf.String()
   222 	return buf.Bytes(), nil
       
   223 }
       
   224 
       
   225 func (s *stream) String() string {
       
   226 	result, _ := s.MarshalXML()
       
   227 	return string(result)
       
   228 }
   217 }
   229 
   218 
   230 func parseStream(se xml.StartElement) (*stream, error) {
   219 func parseStream(se xml.StartElement) (*stream, error) {
   231 	s := &stream{}
   220 	s := &stream{}
   232 	for _, attr := range se.Attr {
   221 	for _, attr := range se.Attr {
   244 		}
   233 		}
   245 	}
   234 	}
   246 	return s, nil
   235 	return s, nil
   247 }
   236 }
   248 
   237 
   249 func (s *streamError) MarshalXML() ([]byte, error) {
       
   250 	buf := bytes.NewBuffer(nil)
       
   251 	buf.WriteString("<stream:error>")
       
   252 	xml.Marshal(buf, s.Any)
       
   253 	if s.Text != nil {
       
   254 		xml.Marshal(buf, s.Text)
       
   255 	}
       
   256 	buf.WriteString("</stream:error>")
       
   257 	return buf.Bytes(), nil
       
   258 }
       
   259 
       
   260 func (e *errText) MarshalXML() ([]byte, error) {
       
   261 	buf := bytes.NewBuffer(nil)
       
   262 	buf.WriteString("<text")
       
   263 	writeField(buf, "xmlns", NsStreams)
       
   264 	writeField(buf, "xml:lang", e.Lang)
       
   265 	buf.WriteString(">")
       
   266 	xml.Escape(buf, []byte(e.Text))
       
   267 	buf.WriteString("</text>")
       
   268 	return buf.Bytes(), nil
       
   269 }
       
   270 
       
   271 func writeField(w io.Writer, field, value string) {
   238 func writeField(w io.Writer, field, value string) {
   272 	if value != "" {
   239 	if value != "" {
   273 		io.WriteString(w, " ")
   240 		io.WriteString(w, " ")
   274 		io.WriteString(w, field)
   241 		io.WriteString(w, field)
   275 		io.WriteString(w, `="`)
   242 		io.WriteString(w, `="`)
   289 	return fmt.Sprintf("<%s %s>%s%s</%s %s>", u.XMLName.Space,
   256 	return fmt.Sprintf("<%s %s>%s%s</%s %s>", u.XMLName.Space,
   290 		u.XMLName.Local, sub, u.Chardata, u.XMLName.Space,
   257 		u.XMLName.Local, sub, u.Chardata, u.XMLName.Space,
   291 		u.XMLName.Local)
   258 		u.XMLName.Local)
   292 }
   259 }
   293 
   260 
   294 func marshalXML(st Stanza) ([]byte, error) {
       
   295 	buf := bytes.NewBuffer(nil)
       
   296 	buf.WriteString("<")
       
   297 	buf.WriteString(st.GetName())
       
   298 	if st.GetTo() != "" {
       
   299 		writeField(buf, "to", st.GetTo())
       
   300 	}
       
   301 	if st.GetFrom() != "" {
       
   302 		writeField(buf, "from", st.GetFrom())
       
   303 	}
       
   304 	if st.GetId() != "" {
       
   305 		writeField(buf, "id", st.GetId())
       
   306 	}
       
   307 	if st.GetType() != "" {
       
   308 		writeField(buf, "type", st.GetType())
       
   309 	}
       
   310 	if st.GetLang() != "" {
       
   311 		writeField(buf, "xml:lang", st.GetLang())
       
   312 	}
       
   313 	buf.WriteString(">")
       
   314 
       
   315 	if m, ok := st.(*Message); ok {
       
   316 		err := xml.Marshal(buf, m.Subject)
       
   317 		if err != nil {
       
   318 			return nil, err
       
   319 		}
       
   320 		err = xml.Marshal(buf, m.Body)
       
   321 		if err != nil {
       
   322 			return nil, err
       
   323 		}
       
   324 		err = xml.Marshal(buf, m.Thread)
       
   325 		if err != nil {
       
   326 			return nil, err
       
   327 		}
       
   328 	}
       
   329 	if p, ok := st.(*Presence); ok {
       
   330 		err := xml.Marshal(buf, p.Show)
       
   331 		if err != nil {
       
   332 			return nil, err
       
   333 		}
       
   334 		err = xml.Marshal(buf, p.Status)
       
   335 		if err != nil {
       
   336 			return nil, err
       
   337 		}
       
   338 		err = xml.Marshal(buf, p.Priority)
       
   339 		if err != nil {
       
   340 			return nil, err
       
   341 		}
       
   342 	}
       
   343 	if nested := st.GetNested(); nested != nil {
       
   344 		for _, n := range nested {
       
   345 			xml.Marshal(buf, n)
       
   346 		}
       
   347 	} else if st.innerxml() != "" {
       
   348 		buf.WriteString(st.innerxml())
       
   349 	}
       
   350 
       
   351 	buf.WriteString("</")
       
   352 	buf.WriteString(st.GetName())
       
   353 	buf.WriteString(">")
       
   354 	return buf.Bytes(), nil
       
   355 }
       
   356 
       
   357 func (er *Error) Error() string {
   261 func (er *Error) Error() string {
   358 	buf := bytes.NewBuffer(nil)
   262 	buf := bytes.NewBuffer(nil)
   359 	xml.Marshal(buf, er)
   263 	xml.NewEncoder(buf).Encode(er)
   360 	return buf.String()
   264 	return buf.String()
   361 }
   265 }
   362 
   266 
   363 func (m *Message) GetName() string {
   267 func (m *Message) GetName() string {
   364 	return "message"
   268 	return "message"
   398 
   302 
   399 func (m *Message) innerxml() string {
   303 func (m *Message) innerxml() string {
   400 	return m.Innerxml
   304 	return m.Innerxml
   401 }
   305 }
   402 
   306 
   403 func (m *Message) MarshalXML() ([]byte, error) {
       
   404 	return marshalXML(m)
       
   405 }
       
   406 
       
   407 func (p *Presence) GetName() string {
   307 func (p *Presence) GetName() string {
   408 	return "presence"
   308 	return "presence"
   409 }
   309 }
   410 
   310 
   411 func (p *Presence) GetTo() string {
   311 func (p *Presence) GetTo() string {
   442 
   342 
   443 func (p *Presence) innerxml() string {
   343 func (p *Presence) innerxml() string {
   444 	return p.Innerxml
   344 	return p.Innerxml
   445 }
   345 }
   446 
   346 
   447 func (p *Presence) MarshalXML() ([]byte, error) {
       
   448 	return marshalXML(p)
       
   449 }
       
   450 
       
   451 func (iq *Iq) GetName() string {
   347 func (iq *Iq) GetName() string {
   452 	return "iq"
   348 	return "iq"
   453 }
   349 }
   454 
   350 
   455 func (iq *Iq) GetTo() string {
   351 func (iq *Iq) GetTo() string {
   484 	iq.Nested = append(iq.Nested, n)
   380 	iq.Nested = append(iq.Nested, n)
   485 }
   381 }
   486 
   382 
   487 func (iq *Iq) innerxml() string {
   383 func (iq *Iq) innerxml() string {
   488 	return iq.Innerxml
   384 	return iq.Innerxml
   489 }
       
   490 
       
   491 func (iq *Iq) MarshalXML() ([]byte, error) {
       
   492 	return marshalXML(iq)
       
   493 }
   385 }
   494 
   386 
   495 // Parse a string into a struct implementing Stanza -- this will be
   387 // Parse a string into a struct implementing Stanza -- this will be
   496 // either an Iq, a Message, or a Presence.
   388 // either an Iq, a Message, or a Presence.
   497 func ParseStanza(str string) (Stanza, error) {
   389 func ParseStanza(str string) (Stanza, error) {
   498 	r := strings.NewReader(str)
   390 	r := strings.NewReader(str)
   499 	p := xml.NewParser(r)
   391 	p := xml.NewDecoder(r)
   500 	tok, err := p.Token()
   392 	tok, err := p.Token()
   501 	if err != nil {
   393 	if err != nil {
   502 		return nil, err
   394 		return nil, err
   503 	}
   395 	}
   504 	se, ok := tok.(xml.StartElement)
   396 	se, ok := tok.(xml.StartElement)
   514 	case "presence":
   406 	case "presence":
   515 		stan = &Presence{}
   407 		stan = &Presence{}
   516 	default:
   408 	default:
   517 		return nil, errors.New("Not iq, message, or presence")
   409 		return nil, errors.New("Not iq, message, or presence")
   518 	}
   410 	}
   519 	err = p.Unmarshal(stan, &se)
   411 	err = p.DecodeElement(stan, &se)
   520 	if err != nil {
   412 	if err != nil {
   521 		return nil, err
   413 		return nil, err
   522 	}
   414 	}
   523 	return stan, nil
   415 	return stan, nil
   524 }
   416 }