Fix panic when connection is reset immediately after establishing.
// This layer of the XMPP protocol translates between bytes and XMLish// structures.packagexmppimport("encoding/xml""fmt""io""log""reflect""strings")// Read bytes from a reader, unmarshal them as XML into structures of// the appropriate type, and send those structures on a channel.func(cl*Client)recvXml(rio.Reader,chchan<-interface{},extStanzamap[xml.Name]reflect.Type){deferclose(ch)// This trick loads our namespaces into the parser.nsstr:=fmt.Sprintf(`<a xmlns="%s" xmlns:stream="%s">`,NsClient,NsStream)nsrdr:=strings.NewReader(nsstr)p:=xml.NewDecoder(io.MultiReader(nsrdr,r))p.Token()Loop:for{// Sniff the next token on the stream.t,err:=p.Token()ift==nil{iferr!=io.EOF{cl.setError(fmt.Errorf("recv: %v",err))}break}varsexml.StartElementvarokboolifse,ok=t.(xml.StartElement);!ok{continue}// Allocate the appropriate structure for this token.varobjinterface{}switchse.Name.Space+" "+se.Name.Local{caseNsStream+" stream":st,err:=parseStream(se)iferr!=nil{cl.setError(fmt.Errorf("recv: %v",err))breakLoop}ch<-stcontinuecase"stream error",NsStream+" error":obj=&streamError{}caseNsStream+" features":obj=&Features{}caseNsTLS+" proceed",NsTLS+" failure":obj=&starttls{}caseNsSASL+" challenge",NsSASL+" failure",NsSASL+" success":obj=&auth{}caseNsClient+" iq":obj=&Iq{}caseNsClient+" message":obj=&Message{}caseNsClient+" presence":obj=&Presence{}default:obj=&Generic{}ifDebug{log.Printf("Ignoring unrecognized: %s %s",se.Name.Space,se.Name.Local)}}// Read the complete XML stanza.err=p.DecodeElement(obj,&se)iferr!=nil{cl.setError(fmt.Errorf("recv: %v",err))breakLoop}// If it's a Stanza, we try to unmarshal its innerxml// into objects of the appropriate respective// types. This is specified by our extensions.ifst,ok:=obj.(Stanza);ok{err=parseExtended(st.GetHeader(),extStanza)iferr!=nil{cl.setError(fmt.Errorf("recv: %v",err))breakLoop}}// Put it on the channel.ch<-obj}}funcparseExtended(st*Header,extStanzamap[xml.Name]reflect.Type)error{// Now parse the stanza's innerxml to find the string that we// can unmarshal this nested element from.reader:=strings.NewReader(st.Innerxml)p:=xml.NewDecoder(reader)for{t,err:=p.Token()iferr==io.EOF{break}iferr!=nil{returnerr}ifse,ok:=t.(xml.StartElement);ok{iftyp,ok:=extStanza[se.Name];ok{nested:=reflect.New(typ).Interface()// Unmarshal the nested element and// stuff it back into the stanza.err:=p.DecodeElement(nested,&se)iferr!=nil{returnerr}st.Nested=append(st.Nested,nested)}}}returnnil}// Receive structures on a channel, marshal them to XML, and send the// bytes on a writer.func(cl*Client)sendXml(wio.Writer,ch<-chaninterface{}){deferfunc(wio.Writer){ifc,ok:=w.(io.Closer);ok{c.Close()}}(w)enc:=xml.NewEncoder(w)forobj:=rangech{ifst,ok:=obj.(*stream);ok{_,err:=w.Write([]byte(st.String()))iferr!=nil{cl.setError(fmt.Errorf("send: %v",err))break}}else{err:=enc.Encode(obj)iferr!=nil{cl.setError(fmt.Errorf("send: %v",err))break}}}}