// 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.packagexmpp// This file contains data structures.import("bytes""flag""fmt""io""os""regexp""strings""xml")// JID represents an entity that can communicate with other// entities. It looks like node@domain/resource. Node and resource are// sometimes optional.typeJIDstruct{Node*stringDomainstringResource*string}var_fmt.Stringer=&JID{}var_flag.Value=&JID{}// XMPP's <stream:stream> XML elementtypeStreamstruct{Tostring`xml:"attr"`Fromstring`xml:"attr"`Idstring`xml:"attr"`Langstring`xml:"attr"`Versionstring`xml:"attr"`}var_xml.Marshaler=&Stream{}var_fmt.Stringer=&Stream{}// <stream:error>typeStreamErrorstruct{AnydefinedConditionText*errText}var_xml.Marshaler=&StreamError{}typedefinedConditionstruct{// Must always be in namespace nsStreamsXMLNamexml.NameChardatastring`xml:"chardata"`}typeerrTextstruct{Langstring`xml:"attr"`Textstring`xml:"chardata"`}var_xml.Marshaler=&errText{}typeFeaturesstruct{Starttls*starttlsMechanismsmechs}typestarttlsstruct{XMLNamexml.Namerequired*string}typemechsstruct{Mechanism[]string}typeauthstruct{XMLNamexml.NameChardatastring`xml:"chardata"`Mechanismstring`xml:"attr"`Any*Unrecognized}typeUnrecognizedstruct{XMLNamexml.Name}var_fmt.Stringer=&Unrecognized{}func(jid*JID)String()string{result:=jid.Domainifjid.Node!=nil{result=*jid.Node+"@"+result}ifjid.Resource!=nil{result=result+"/"+*jid.Resource}returnresult}func(jid*JID)Set(valstring)bool{r:=regexp.MustCompile("^(([^@/]+)@)?([^@/]+)(/([^@/]+))?$")parts:=r.FindStringSubmatch(val)ifparts==nil{returnfalse}ifparts[2]==""{jid.Node=nil}else{jid.Node=&parts[2]}jid.Domain=parts[3]ifparts[5]==""{jid.Resource=nil}else{jid.Resource=&parts[5]}returntrue}func(s*Stream)MarshalXML()([]byte,os.Error){buf:=bytes.NewBuffer(nil)buf.WriteString("<stream:stream")writeField(buf,"xmlns","jabber:client")writeField(buf,"xmlns:stream",nsStream)writeField(buf,"to",s.To)writeField(buf,"from",s.From)writeField(buf,"id",s.Id)writeField(buf,"xml:lang",s.Lang)writeField(buf,"version",s.Version)buf.WriteString(">")// We never write </stream:stream>returnbuf.Bytes(),nil}func(s*Stream)String()string{result,_:=s.MarshalXML()returnstring(result)}funcparseStream(sexml.StartElement)(*Stream,os.Error){s:=&Stream{}for_,attr:=rangese.Attr{switchstrings.ToLower(attr.Name.Local){case"to":s.To=attr.Valuecase"from":s.From=attr.Valuecase"id":s.Id=attr.Valuecase"lang":s.Lang=attr.Valuecase"version":s.Version=attr.Value}}returns,nil}func(s*StreamError)MarshalXML()([]byte,os.Error){buf:=bytes.NewBuffer(nil)buf.WriteString("<stream:error>")xml.Marshal(buf,s.Any)ifs.Text!=nil{xml.Marshal(buf,s.Text)}buf.WriteString("</stream:error>")returnbuf.Bytes(),nil}func(e*errText)MarshalXML()([]byte,os.Error){buf:=bytes.NewBuffer(nil)buf.WriteString("<text")writeField(buf,"xmlns",nsStreams)writeField(buf,"xml:lang",e.Lang)buf.WriteString(">")xml.Escape(buf,[]byte(e.Text))buf.WriteString("</text>")returnbuf.Bytes(),nil}funcwriteField(wio.Writer,field,valuestring){ifvalue!=""{io.WriteString(w," ")io.WriteString(w,field)io.WriteString(w,`="`)xml.Escape(w,[]byte(value))io.WriteString(w,`"`)}}func(u*Unrecognized)String()string{returnfmt.Sprintf("unrecognized{%s %s}",u.XMLName.Space,u.XMLName.Local)}