diff -r fbda8e925fdf -r 2839fece923e stream.go --- a/stream.go Sat Dec 31 10:11:01 2011 -0700 +++ b/stream.go Sat Dec 31 11:39:23 2011 -0700 @@ -12,7 +12,6 @@ import ( "big" - "bytes" "crypto/md5" "crypto/rand" "crypto/tls" @@ -82,7 +81,7 @@ } func readXml(r io.Reader, ch chan<- interface{}, - extStanza map[string] func(*xml.Name) ExtendedStanza) { + extStanza map[string] func(*xml.Name) interface{}) { if debug { pr, pw := io.Pipe() go tee(r, pw, "S: ") @@ -150,15 +149,12 @@ // namespace that's registered with one of our // extensions. If so, we need to re-unmarshal into an // object of the correct type. - if st, ok := obj.(Stanza) ; ok && st.XChild() != nil { - name := st.XChild().XMLName + if st, ok := obj.(Stanza) ; ok && st.generic() != nil { + name := st.generic().XMLName ns := name.Space con := extStanza[ns] if con != nil { - obj = con(&name) - xmlStr, _ := marshalXML(st) - r := bytes.NewBuffer(xmlStr) - err = xml.Unmarshal(r, obj) + err = parseExtended(st, con) if err != nil { log.Printf("ext unmarshal: %v", err) @@ -172,6 +168,38 @@ } } +func parseExtended(st Stanza, con func(*xml.Name) interface{}) os.Error { + name := st.generic().XMLName + nested := con(&name) + + // 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.NewParser(reader) + var start *xml.StartElement + for { + t, err := p.Token() + if err != nil { + return err + } + if se, ok := t.(xml.StartElement) ; ok { + if se.Name.Space == name.Space { + start = &se + break + } + } + } + + // Unmarshal the nested element and stuff it back into the + // stanza. + err := p.Unmarshal(nested, start) + if err != nil { + return err + } + st.setNested(nested) + return nil +} + func writeXml(w io.Writer, ch <-chan interface{}) { if debug { pr, pw := io.Pipe() @@ -527,6 +555,7 @@ return response } +// BUG(cjyar) This should use iq.nested rather than iq.generic. // Send a request to bind a resource. RFC 3920, section 7. func (cl *Client) bind(bind *Generic) { res := cl.Jid.Resource @@ -542,7 +571,7 @@ log.Println("Resource binding failed") return false } - bind := st.XChild() + bind := st.generic() if bind == nil { log.Println("nil resource bind") return false