package xmpp import ( "encoding/xml" "errors" "log" ) type tokenRouter struct { start xml.StartElement end xml.EndElement buffer []xml.Token level uint16 // XML nesting level enc *encoder } func newTokenRouter(e *encoder) tokenRouter { return tokenRouter{ buffer: make([]xml.Token, 0), level: 0, enc: e, } } func (r *tokenRouter) route(t xml.Token) error { r.buffer = append(r.buffer, t) switch unwrapped := t.(type) { case xml.StartElement: r.level += 1 if r.level == 1 { r.start = unwrapped r.buffer = r.buffer[:0] // call start handler } case xml.EndElement: if r.level == 0 { log.Println("Ignoring XML end element on nesting level zero") return nil } r.level -= 1 switch r.level { case 0: return errors.New("Stream was closed by server") case 1: // call elementRouter err := routeElement(r.buffer) if err != nil { return err } r.buffer = r.buffer[:0] } case xml.ProcInst: log.Println("Ignoring xml.ProcInst element") r.buffer = r.buffer[:len(r.buffer)-1] case xml.Directive: log.Println("Ignoring xml.Directive element") r.buffer = r.buffer[:len(r.buffer)-1] case xml.Comment: log.Println("Ignoring xml.Comment element") r.buffer = r.buffer[:len(r.buffer)-1] } return nil } func routeElement(b []xml.Token) error { tab := elementRoutingTable{ {xml.Name{"http://etherx.jabber.org/streams", "features"}, streamFeatures}, } switch unwrapped := b[0].(type) { case xml.StartElement: for _, v := range(tab) { if unwrapped.Name == v.name { err := v.handler(b) if err != nil { return err } return nil } } log.Printf("Ignoring XML element '%s' from namespace '%s'", unwrapped.Name.Local, unwrapped.Name.Space) default: log.Println("Ignoring XML element which has no StartElement as first token") } return nil } type elementRoutingTable []struct { name xml.Name handler func(b []xml.Token) error } func streamFeatures(b []xml.Token) error { err := sendSaslAuth(b) if err != nil { return err } return nil } func sendSaslAuth(b []xml.Token) error { mechanisms := make([]string, 0) for i, v := range(b) { switch token := v.(type) { case xml.StartElement: expected := xml.Name{"urn:ietf:params:xml:ns:xmpp-sasl", "mechanism"} if token.Name == expected { if i >= (len(b)-1) { continue } switch payload := b[i+1].(type) { case xml.CharData: mechanisms = append(mechanisms, string(payload)) } } } } for _, v := range(mechanisms) { if v == "PLAIN" { return nil } } return errors.New("No compatible SASL mechanism given") }