summaryrefslogtreecommitdiff
path: root/xmpp/router.go
blob: 1e21c9b51396ed588e0a927228ec43d0b4451aa3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
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")
}