package xmpp import ( "encoding/xml" "log" ) // routingTable is a data structure which contains routing information for XML // elements. The xml.StartElement at the beginning of an XML element has a name // containing the XML namespace and a local name. Based on this compisition // which forms the xml.Name the appropriate handler function is defined by each // entry of the routingTable. type routingTable []struct { name xml.Name handler func(*session, []xml.Token) } // getRoutingTable returns the routing table used in // xengineering.eu/limox/xmpp. Since Go does not allow such a datatype as a // constant such a function is a simple yet inefficient approach to guarantee // that an unmodified routing table is delivered to each user. A global // variable would have the problem that it could be altered during execution. func getRoutingTable() routingTable { return routingTable{ {xml.Name{`http://etherx.jabber.org/streams`, `features`}, streamFeaturesHandler}, {xml.Name{`urn:ietf:params:xml:ns:xmpp-sasl`, `success`}, saslSuccessHandler}, {xml.Name{`urn:ietf:params:xml:ns:xmpp-sasl`, `failure`}, saslFailureHandler}, {xml.Name{`jabber:client`, `iq`}, iqHandler}, } } // route determines the correct handler function for the given XML element by a // given routingTable. In addition it executes the determined handler function. // If no handler function is found an error message is send via the log module. func route(s *session, e []xml.Token, t routingTable) { var name xml.Name // TODO a stronger definition of an XML element (as here // https://www.w3schools.com/xml/xml_elements.asp) would define that the // first Token of an element is a StartElement token. This would make this // code easier. escape := false for _, token := range e { switch s := token.(type) { case xml.StartElement: name = s.Name escape = true } if escape { break } } for _, r := range t { if name == r.name { r.handler(s, e) return } } log.Println("Could not route XML element") }