]> code.delx.au - pymsnt/blob - src/disco.py
Reimporting (0.9.5)
[pymsnt] / src / disco.py
1 # Copyright 2004 James Bunton <james@delx.cjb.net>
2 # Licensed for distribution under the GPL version 2, check COPYING for details
3
4 import utils
5 if(utils.checkTwisted()):
6 from twisted.xish.domish import Element
7 else:
8 from tlib.domish import Element
9 from twisted.internet.defer import Deferred
10 from twisted.internet import reactor
11 import sys
12 import config
13 import debug
14 import legacy
15
16 XMPP_STANZAS = 'urn:ietf:params:xml:ns:xmpp-stanzas'
17 DISCO = "http://jabber.org/protocol/disco"
18 DISCO_ITEMS = DISCO + "#items"
19 DISCO_INFO = DISCO + "#info"
20
21
22 class ServerDiscovery:
23 def __init__ (self, pytrans):
24 debug.log("Discovery: Created server discovery manager")
25 self.pytrans = pytrans
26 self.identities = []
27 self.features = []
28 self.deferredIqs = {} # A dict indexed by (jid, id) of deferreds to fire
29
30 self.addFeature(DISCO, None)
31
32 def sendIq(self, el, timeout=15):
33 """ Used for sending IQ packets.
34 The id attribute for the IQ will be autogenerated if it is not there yet.
35 Returns a deferred which will fire with the matching IQ response as it's sole argument. """
36 def checkDeferred():
37 if(not d.called):
38 d.errback()
39 del self.deferredIqs[(jid, ID)]
40
41 jid = el.getAttribute("to")
42 ID = el.getAttribute("id")
43 if(not ID):
44 ID = self.pytrans.makeMessageID()
45 el.attributes["id"] = ID
46 self.pytrans.send(el)
47 d = Deferred()
48 self.deferredIqs[(jid, ID)] = d
49 reactor.callLater(timeout, checkDeferred)
50 return d
51
52 def addIdentity(self, category, ctype, name):
53 debug.log("Discovery: Adding identitity \"%s\" \"%s\" \"%s\"" % (category, ctype, name))
54 self.identities.append((category, ctype, name))
55
56 def addFeature(self, var, handler):
57 debug.log("Discovery: Adding feature support \"%s\" \"%s\"" % (var, handler))
58 self.features.append((var, handler))
59
60 def onIq(self, el):
61 fro = el.getAttribute("from")
62 to = el.getAttribute("to")
63 ID = el.getAttribute("id")
64 iqType = el.getAttribute("type")
65
66 # Check if it's a response to a send IQ
67 if(self.deferredIqs.has_key((fro, ID)) and iqType in ["error", "result"]):
68 self.deferredIqs[(fro, ID)].callback(el)
69 del self.deferredIqs[(fro, ID)]
70 return
71
72 if(iqType not in ["get", "set"]): return # Not interested
73
74 debug.log("Discovery: Iq received \"%s\" \"%s\". Looking for handler" % (fro, ID))
75
76 for query in el.elements():
77 xmlns = query.defaultUri
78
79 if(to.find('@') > 0): # Iq to a user
80 self.sendIqNotSupported(to=fro, fro=config.jid, ID=ID, xmlns=DISCO)
81
82 else: # Iq to transport
83 if(xmlns == DISCO_INFO):
84 self.sendDiscoInfoResponse(to=fro, ID=ID)
85 elif(xmlns == DISCO_ITEMS):
86 self.sendDiscoItemsResponse(to=fro, ID=ID)
87 else:
88 handled = False
89 for (feature, handler) in self.features:
90 if(feature == xmlns and handler):
91 debug.log("Discovery: Handler found \"%s\" \"%s\"" % (feature, handler))
92 handler(el)
93 handled = True
94 if(not handled):
95 debug.log("Discovery: Unknown Iq request \"%s\" \"%s\" \"%s\"" % (fro, ID, xmlns))
96 self.sendIqNotSupported(to=fro, fro=config.jid, ID=ID, xmlns=DISCO)
97
98 def sendDiscoInfoResponse(self, to, ID):
99 debug.log("Discovery: Replying to disco#info request from \"%s\" \"%s\"" % (to, ID))
100 iq = Element((None, "iq"))
101 iq.attributes["type"] = "result"
102 iq.attributes["from"] = config.jid
103 iq.attributes["to"] = to
104 if(ID):
105 iq.attributes["id"] = ID
106 query = iq.addElement("query")
107 query.attributes["xmlns"] = DISCO_INFO
108
109 # Add any identities
110 for (category, ctype, name) in self.identities:
111 identity = query.addElement("identity")
112 identity.attributes["category"] = category
113 identity.attributes["type"] = ctype
114 identity.attributes["name"] = name
115
116 # Add any supported features
117 for (var, handler) in self.features:
118 feature = query.addElement("feature")
119 feature.attributes["var"] = var
120 self.pytrans.send(iq)
121
122 def sendDiscoItemsResponse(self, to, ID):
123 debug.log("Discovery: Replying to disco#items request from \"%s\" \"%s\"" % (to, ID))
124 iq = Element((None, "iq"))
125 iq.attributes["type"] = "result"
126 iq.attributes["from"] = config.jid
127 iq.attributes["to"] = to
128 if(ID):
129 iq.attributes["id"] = ID
130 query = iq.addElement("query")
131 query.attributes["xmlns"] = DISCO_ITEMS
132
133 self.pytrans.send(iq)
134
135
136 def sendIqNotSupported(self, to, fro, ID, xmlns):
137 debug.log("Discovery: Replying with error to unknown Iq request")
138 iq = Element((None, "iq"))
139 iq.attributes["type"] = "error"
140 iq.attributes["from"] = fro
141 iq.attributes["to"] = to
142 if(ID):
143 iq.attributes["id"] = ID
144 error = iq.addElement("error")
145 error.attributes["xmlns"] = xmlns
146 error.attributes["type"] = "cancel"
147 error.attributes["xmlns"] = XMPP_STANZAS
148 text = error.addElement("text")
149 text.attributes["xmlns"] = XMPP_STANZAS
150 text.addContent("Not implemented.")
151
152 self.pytrans.send(iq)
153
154 def sendIqNotValid(self, to, ID, xmlns):
155 debug.log("Discovery: Replying with error to invalid Iq request")
156 iq = Element((None, "iq"))
157 iq.attributes["type"] = "error"
158 iq.attributes["from"] = config.jid
159 iq.attributes["to"] = to
160 if(ID):
161 iq.attributes["id"] = ID
162 error = iq.addElement("error")
163 error.attributes["xmlns"] = xmlns
164 error.attributes["type"] = "modify"
165 error.attributes["xmlns"] = XMPP_STANZAS
166 text = error.addElement("text")
167 text.attributes["xmlns"] = XMPP_STANZAS
168 text.addContent("Not valid.")
169
170 self.pytrans.send(iq)
171