]> code.delx.au - pymsnt/blob - src/misciq.py
Reimport and tags (0.10.1)
[pymsnt] / src / misciq.py
1 # Copyright 2004-2005 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 from twisted.words.protocols.jabber import jid
8 else:
9 from tlib.domish import Element
10 from tlib.jabber import jid
11 from twisted.internet import reactor, task
12 from debug import LogEvent, INFO, WARN, ERROR
13 import jabw
14 import legacy
15 import disco
16 import config
17 import lang
18 import base64
19 import sys
20
21
22 class ConnectUsers:
23 def __init__(self, pytrans):
24 self.pytrans = pytrans
25 self.pytrans.adHocCommands.addCommand("connectusers", self.incomingIq, "command_ConnectUsers")
26
27 def sendProbes(self):
28 for jid in self.pytrans.xdb.files():
29 jabw.sendPresence(self.pytrans, jid, config.jid, ptype="probe")
30
31 def incomingIq(self, el):
32 to = el.getAttribute("from")
33 ID = el.getAttribute("id")
34 ulang = utils.getLang(el)
35
36 if config.admins.count(jid.JID(to).userhost()) == 0:
37 self.pytrans.discovery.sendIqError(to=to, fro=config.jid, ID=ID, xmlns=disco.COMMANDS, etype="cancel", condition="not-authorized")
38 return
39
40
41 self.sendProbes()
42
43 iq = Element((None, "iq"))
44 iq.attributes["to"] = to
45 iq.attributes["from"] = config.jid
46 if(ID):
47 iq.attributes["id"] = ID
48 iq.attributes["type"] = "result"
49
50 command = iq.addElement("command")
51 command.attributes["sessionid"] = self.pytrans.makeMessageID()
52 command.attributes["xmlns"] = disco.COMMANDS
53 command.attributes["status"] = "completed"
54
55 x = command.addElement("x")
56 x.attributes["xmlns"] = "jabber:x:data"
57 x.attributes["type"] = "result"
58
59 title = x.addElement("title")
60 title.addContent(lang.get(ulang).command_ConnectUsers)
61
62 field = x.addElement("field")
63 field.attributes["type"] = "fixed"
64 field.addElement("value").addContent(lang.get(ulang).command_Done)
65
66 self.pytrans.send(iq)
67
68
69 class Statistics:
70 def __init__(self, pytrans):
71 self.pytrans = pytrans
72 self.pytrans.adHocCommands.addCommand("stats", self.incomingIq, "command_Statistics")
73
74 # self.stats is indexed by a unique ID, with value being the value for that statistic
75 self.stats = {}
76 self.stats["Uptime"] = 0
77 self.stats["OnlineUsers"] = 0
78 self.stats["TotalUsers"] = 0
79
80 legacy.startStats(self)
81
82 def incomingIq(self, el):
83 to = el.getAttribute("from")
84 ID = el.getAttribute("id")
85 ulang = utils.getLang(el)
86
87 iq = Element((None, "iq"))
88 iq.attributes["to"] = to
89 iq.attributes["from"] = config.jid
90 if(ID):
91 iq.attributes["id"] = ID
92 iq.attributes["type"] = "result"
93
94 command = iq.addElement("command")
95 command.attributes["sessionid"] = self.pytrans.makeMessageID()
96 command.attributes["xmlns"] = disco.COMMANDS
97 command.attributes["status"] = "completed"
98
99 x = command.addElement("x")
100 x.attributes["xmlns"] = "jabber:x:data"
101 x.attributes["type"] = "result"
102
103 title = x.addElement("title")
104 title.addContent(lang.get(ulang).command_Statistics)
105
106 for key in self.stats:
107 label = getattr(lang.get(ulang), "command_%s" % key)
108 description = getattr(lang.get(ulang), "command_%s_Desc" % key)
109 field = x.addElement("field")
110 field.attributes["var"] = key
111 field.attributes["label"] = label
112 field.attributes["type"] = "text-single"
113 field.addElement("value").addContent(str(self.stats[key]))
114 field.addElement("desc").addContent(description)
115
116 self.pytrans.send(iq)
117
118
119
120 class AdHocCommands:
121 def __init__(self, pytrans):
122 self.pytrans = pytrans
123 self.pytrans.discovery.addFeature(disco.COMMANDS, self.incomingIq, config.jid)
124 self.pytrans.discovery.addNode(disco.COMMANDS, self.sendCommandList, "command_CommandList", config.jid, True)
125
126 self.commands = {} # Dict of handlers indexed by node
127 self.commandNames = {} # Dict of names indexed by node
128
129 def addCommand(self, command, handler, name):
130 self.commands[command] = handler
131 self.commandNames[command] = name
132 self.pytrans.discovery.addNode(command, self.incomingIq, name, config.jid, False)
133
134 def incomingIq(self, el):
135 itype = el.getAttribute("type")
136 fro = el.getAttribute("from")
137 froj = jid.JID(fro)
138 to = el.getAttribute("to")
139 ID = el.getAttribute("id")
140
141 LogEvent(INFO, "", "Looking for handler")
142
143 node = None
144 for child in el.elements():
145 xmlns = child.defaultUri
146 node = child.getAttribute("node")
147
148 handled = False
149 if(child.name == "query" and xmlns == disco.DISCO_INFO):
150 if(node and self.commands.has_key(node) and (itype == "get")):
151 self.sendCommandInfoResponse(to=fro, ID=ID)
152 handled = True
153 elif(child.name == "query" and xmlns == disco.DISCO_ITEMS):
154 if(node and self.commands.has_key(node) and (itype == "get")):
155 self.sendCommandItemsResponse(to=fro, ID=ID)
156 handled = True
157 elif(child.name == "command" and xmlns == disco.COMMANDS):
158 if((node and self.commands.has_key(node)) and (itype == "set" or itype == "error")):
159 self.commands[node](el)
160 handled = True
161 if(not handled):
162 LogEvent(WARN, "", "Unknown Ad-Hoc command received.")
163 self.pytrans.discovery.sendIqError(to=fro, fro=config.jid, ID=ID, xmlns=xmlns, etype="cancel", condition="feature-not-implemented")
164
165
166 def sendCommandList(self, el):
167 to = el.getAttribute("from")
168 ID = el.getAttribute("id")
169 ulang = utils.getLang(el)
170
171 iq = Element((None, "iq"))
172 iq.attributes["to"] = to
173 iq.attributes["from"] = config.jid
174 if ID:
175 iq.attributes["id"] = ID
176 iq.attributes["type"] = "result"
177
178 query = iq.addElement("query")
179 query.attributes["xmlns"] = disco.DISCO_ITEMS
180 query.attributes["node"] = disco.COMMANDS
181
182 for command in self.commands:
183 item = query.addElement("item")
184 item.attributes["jid"] = config.jid
185 item.attributes["node"] = command
186 item.attributes["name"] = getattr(lang.get(ulang), self.commandNames[command])
187
188 self.pytrans.send(iq)
189
190 def sendCommandInfoResponse(self, to, ID):
191 LogEvent(INFO, "", "Replying to disco#info")
192 iq = Element((None, "iq"))
193 iq.attributes["type"] = "result"
194 iq.attributes["from"] = config.jid
195 iq.attributes["to"] = to
196 if(ID): iq.attributes["id"] = ID
197 query = iq.addElement("query")
198 query.attributes["xmlns"] = disco.DISCO_INFO
199
200 feature = query.addElement("feature")
201 feature.attributes["var"] = disco.COMMANDS
202 self.pytrans.send(iq)
203
204 def sendCommandItemsResponse(self, to, ID):
205 LogEvent(INFO, "", "Replying to disco#items")
206 iq = Element((None, "iq"))
207 iq.attributes["type"] = "result"
208 iq.attributes["from"] = config.jid
209 iq.attributes["to"] = to
210 if(ID): iq.attributes["id"] = ID
211 query = iq.addElement("query")
212 query.attributes["xmlns"] = disco.DISCO_ITEMS
213 self.pytrans.send(iq)
214
215
216 class VCardFactory:
217 def __init__(self, pytrans):
218 self.pytrans = pytrans
219 self.pytrans.discovery.addFeature("vcard-temp", self.incomingIq, "USER")
220 self.pytrans.discovery.addFeature("vcard-temp", self.incomingIq, config.jid)
221
222 def incomingIq(self, el):
223 itype = el.getAttribute("type")
224 fro = el.getAttribute("from")
225 froj = jid.JID(fro)
226 to = el.getAttribute("to")
227 ID = el.getAttribute("id")
228 if(itype != "get" and itype != "error"):
229 self.pytrans.discovery.sendIqError(to=fro, fro=config.jid, ID=ID, xmlns="vcard-temp", etype="cancel", condition="feature-not-implemented")
230 return
231
232 LogEvent(INFO, "", "Sending vCard")
233
234 toGateway = not (to.find('@') > 0)
235
236 if(not toGateway):
237 if(not self.pytrans.sessions.has_key(froj.userhost())):
238 self.pytrans.discovery.sendIqError(to=fro, fro=config.jid, ID=ID, xmlns="vcard-temp", etype="auth", condition="not-authorized")
239 return
240 s = self.pytrans.sessions[froj.userhost()]
241 if(not s.ready):
242 self.pytrans.discovery.sendIqError(to=fro, fro=config.jid, ID=ID, xmlns="vcard-temp", etype="auth", condition="not-authorized")
243 return
244
245 c = s.contactList.findContact(to)
246 if(not c):
247 self.pytrans.discovery.sendIqError(to=fro, fro=config.jid, ID=ID, xmlns="vcard-temp", etype="cancel", condition="recipient-unavailable")
248 return
249
250
251 iq = Element((None, "iq"))
252 iq.attributes["to"] = fro
253 iq.attributes["from"] = to
254 if ID:
255 iq.attributes["id"] = ID
256 iq.attributes["type"] = "result"
257 vCard = iq.addElement("vCard")
258 vCard.attributes["xmlns"] = "vcard-temp"
259 if(toGateway):
260 FN = vCard.addElement("FN")
261 FN.addContent(legacy.name)
262 DESC = vCard.addElement("DESC")
263 DESC.addContent(legacy.name)
264 URL = vCard.addElement("URL")
265 URL.addContent(legacy.url)
266 else:
267 if(c.nickname):
268 NICKNAME = vCard.addElement("NICKNAME")
269 NICKNAME.addContent(c.nickname)
270 if(c.avatar):
271 PHOTO = c.avatar.makePhotoElement()
272 vCard.addChild(PHOTO)
273
274 self.pytrans.send(iq)
275
276 class IqAvatarFactory:
277 def __init__(self, pytrans):
278 self.pytrans = pytrans
279 self.pytrans.discovery.addFeature(disco.IQAVATAR, self.incomingIq, "USER")
280 self.pytrans.discovery.addFeature(disco.STORAGEAVATAR, self.incomingIq, "USER")
281
282 def incomingIq(self, el):
283 itype = el.getAttribute("type")
284 fro = el.getAttribute("from")
285 froj = jid.JID(fro)
286 to = el.getAttribute("to")
287 ID = el.getAttribute("id")
288
289 if(itype != "get" and itype != "error"):
290 self.pytrans.discovery.sendIqError(to=fro, fro=config.jid, ID=ID, xmlns=disco.IQAVATAR, etype="cancel", condition="feature-not-implemented")
291 return
292
293 LogEvent(INFO, "", "Retrieving avatar")
294
295 if(not self.pytrans.sessions.has_key(froj.userhost())):
296 self.pytrans.discovery.sendIqError(to=fro, fro=config.jid, ID=ID, xmlns=disco.IQAVATAR, etype="auth", condition="not-authorized")
297 return
298 s = self.pytrans.sessions[froj.userhost()]
299 if(not s.ready):
300 self.pytrans.discovery.sendIqError(to=fro, fro=config.jid, ID=ID, xmlns=disco.IQAVATAR, etype="auth", condition="not-authorized")
301 return
302
303 c = s.contactList.findContact(to)
304 if(not c):
305 self.pytrans.discovery.sendIqError(to=fro, fro=config.jid, ID=ID, xmlns=disco.IQAVATAR, etype="cancel", condition="recipient-unavailable")
306 return
307
308 iq = Element((None, "iq"))
309 iq.attributes["to"] = fro
310 iq.attributes["from"] = to
311 if ID:
312 iq.attributes["id"] = ID
313 iq.attributes["type"] = "result"
314 query = iq.addElement("query")
315 query.attributes["xmlns"] = disco.IQAVATAR
316 if(c.avatar):
317 DATA = c.avatar.makeDataElement()
318 query.addChild(DATA)
319
320 self.pytrans.send(iq)
321
322
323
324 class PingService:
325 def __init__(self, pytrans):
326 self.pytrans = pytrans
327 # self.pingCounter = 0
328 # self.pingTask = task.LoopingCall(self.pingCheck)
329 self.pingTask = task.LoopingCall(self.whitespace)
330 # reactor.callLater(10.0, self.start)
331
332 # def start(self):
333 # self.pingTask.start(120.0)
334
335 def whitespace(self):
336 self.pytrans.send(" ")
337
338 # def pingCheck(self):
339 # if(self.pingCounter >= 2 and self.pytrans.xmlstream): # Two minutes of no response from the main server
340 # LogEvent(WARN, "", "Disconnecting because the main server has ignored our pings for too long.")
341 # self.pytrans.xmlstream.transport.loseConnection()
342 # elif(config.mainServerJID):
343 # d = self.pytrans.discovery.sendIq(self.makePingPacket())
344 # d.addCallback(self.pongReceived)
345 # d.addErrback(self.pongFailed)
346 # self.pingCounter += 1
347
348 # def pongReceived(self, el):
349 # self.pingCounter = 0
350
351 # def pongFailed(self, el):
352 # pass
353
354 # def makePingPacket(self):
355 # iq = Element((None, "iq"))
356 # iq.attributes["from"] = config.jid
357 # iq.attributes["to"] = config.mainServerJID
358 # iq.attributes["type"] = "get"
359 # query = iq.addElement("query")
360 # query.attributes["xmlns"] = disco.IQVERSION
361 # return iq
362
363 class GatewayTranslator:
364 def __init__(self, pytrans):
365 self.pytrans = pytrans
366 self.pytrans.discovery.addFeature(disco.IQGATEWAY, self.incomingIq, config.jid)
367
368 def incomingIq(self, el):
369 fro = el.getAttribute("from")
370 ID = el.getAttribute("id")
371 itype = el.getAttribute("type")
372 if(itype == "get"):
373 self.sendPrompt(fro, ID, utils.getLang(el))
374 elif(itype == "set"):
375 self.sendTranslation(fro, ID, el)
376
377
378 def sendPrompt(self, to, ID, ulang):
379 LogEvent(INFO)
380
381 iq = Element((None, "iq"))
382
383 iq.attributes["type"] = "result"
384 iq.attributes["from"] = config.jid
385 iq.attributes["to"] = to
386 if ID:
387 iq.attributes["id"] = ID
388 query = iq.addElement("query")
389 query.attributes["xmlns"] = disco.IQGATEWAY
390 desc = query.addElement("desc")
391 desc.addContent(lang.get(ulang).gatewayTranslator)
392 prompt = query.addElement("prompt")
393
394 self.pytrans.send(iq)
395
396 def sendTranslation(self, to, ID, el):
397 LogEvent(INFO)
398
399 # Find the user's legacy account
400 legacyaccount = None
401 for query in el.elements():
402 if(query.name == "query"):
403 for child in query.elements():
404 if(child.name == "prompt"):
405 legacyaccount = str(child)
406 break
407 break
408
409
410 if(legacyaccount and len(legacyaccount) > 0):
411 LogEvent(INFO, "", "Sending translated account.")
412 iq = Element((None, "iq"))
413 iq.attributes["type"] = "result"
414 iq.attributes["from"] = config.jid
415 iq.attributes["to"] = to
416 if ID:
417 iq.attributes["id"] = ID
418 query = iq.addElement("query")
419 query.attributes["xmlns"] = disco.IQGATEWAY
420 prompt = query.addElement("prompt")
421 prompt.addContent(legacy.translateAccount(legacyaccount))
422
423 self.pytrans.send(iq)
424
425 else:
426 self.pytrans.discovery.sendIqError(to, ID, disco.IQGATEWAY)
427 self.pytrans.discovery.sendIqError(to=to, fro=config.jid, ID=ID, xmlns=disco.IQGATEWAY, etype="retry", condition="bad-request")
428
429
430
431 class VersionTeller:
432 def __init__(self, pytrans):
433 self.pytrans = pytrans
434 self.pytrans.discovery.addFeature(disco.IQVERSION, self.incomingIq, config.jid)
435 self.pytrans.discovery.addFeature(disco.IQVERSION, self.incomingIq, "USER")
436
437 def incomingIq(self, el):
438 eltype = el.getAttribute("type")
439 if(eltype != "get"): return # Only answer "get" stanzas
440
441 self.sendVersion(el)
442
443 def sendVersion(self, el):
444 LogEvent(INFO)
445 iq = Element((None, "iq"))
446 iq.attributes["type"] = "result"
447 iq.attributes["from"] = el.getAttribute("to")
448 iq.attributes["to"] = el.getAttribute("from")
449 if(el.getAttribute("id")):
450 iq.attributes["id"] = el.getAttribute("id")
451 query = iq.addElement("query")
452 query.attributes["xmlns"] = disco.IQVERSION
453 name = query.addElement("name")
454 name.addContent(legacy.name)
455 version = query.addElement("version")
456 version.addContent(legacy.version)
457 os = query.addElement("os")
458 os.addContent("Python" + ".".join([str(x) for x in sys.version_info[0:3]]) + " - " + sys.platform)
459
460 self.pytrans.send(iq)
461
462
463