X-Git-Url: https://code.delx.au/pymsnt/blobdiff_plain/c82ae883c8c1a236e80013c734fb56725b3c535c..85e6c0f55bd0d46cad7f94d15b52c7b64dc94c08:/src/misciq.py diff --git a/src/misciq.py b/src/misciq.py index bbbde0f..56b5be6 100644 --- a/src/misciq.py +++ b/src/misciq.py @@ -1,4 +1,4 @@ -# Copyright 2004 James Bunton +# Copyright 2004-2005 James Bunton # Licensed for distribution under the GPL version 2, check COPYING for details import utils @@ -9,48 +9,361 @@ else: from tlib.domish import Element from tlib.jabber import jid from twisted.internet import reactor, task - +from debug import LogEvent, INFO, WARN, ERROR +import jabw import legacy +import disco import config -import debug import lang +import base64 import sys -class PingService: +class ConnectUsers: def __init__(self, pytrans): self.pytrans = pytrans - self.pingCounter = 0 - self.pingCheckTask = task.LoopingCall(self.pingCheck) - reactor.callLater(10.0, self.start) + self.pytrans.adHocCommands.addCommand("connectusers", self.incomingIq, "command_ConnectUsers") - def start(self): - self.pingCheckTask.start(120.0) + def sendProbes(self): + for jid in self.pytrans.xdb.files(): + jabw.sendPresence(self.pytrans, jid, config.jid, ptype="probe") - def pingCheck(self): - if(self.pingCounter >= 2 and self.pytrans.xmlstream): # Two minutes of no response from the server - self.pytrans.xmlstream.transport.loseConnection() - elif(config.mainServerJID): - d = self.pytrans.discovery.sendIq(self.makePingPacket()) - d.addCallback(self.pongReceived) - self.pingCounter += 1 + def incomingIq(self, el): + to = el.getAttribute("from") + ID = el.getAttribute("id") + ulang = utils.getLang(el) + + if config.admins.count(jid.JID(to).userhost()) == 0: + self.pytrans.discovery.sendIqError(to=to, fro=config.jid, ID=ID, xmlns=disco.COMMANDS, etype="cancel", condition="not-authorized") + return + + + self.sendProbes() - def pongReceived(self, el): - self.pingCounter = 0 + iq = Element((None, "iq")) + iq.attributes["to"] = to + iq.attributes["from"] = config.jid + if(ID): + iq.attributes["id"] = ID + iq.attributes["type"] = "result" + + command = iq.addElement("command") + command.attributes["sessionid"] = self.pytrans.makeMessageID() + command.attributes["xmlns"] = disco.COMMANDS + command.attributes["status"] = "completed" + + x = command.addElement("x") + x.attributes["xmlns"] = "jabber:x:data" + x.attributes["type"] = "result" + + title = x.addElement("title") + title.addContent(lang.get(ulang).command_ConnectUsers) + + field = x.addElement("field") + field.attributes["type"] = "fixed" + field.addElement("value").addContent(lang.get(ulang).command_Done) + + self.pytrans.send(iq) + + +class Statistics: + def __init__(self, pytrans): + self.pytrans = pytrans + self.pytrans.adHocCommands.addCommand("stats", self.incomingIq, "command_Statistics") + + # self.stats is indexed by a unique ID, with value being the value for that statistic + self.stats = {} + self.stats["Uptime"] = 0 + self.stats["OnlineUsers"] = 0 + self.stats["TotalUsers"] = 0 + + legacy.startStats(self) + + def incomingIq(self, el): + to = el.getAttribute("from") + ID = el.getAttribute("id") + ulang = utils.getLang(el) + + iq = Element((None, "iq")) + iq.attributes["to"] = to + iq.attributes["from"] = config.jid + if(ID): + iq.attributes["id"] = ID + iq.attributes["type"] = "result" + + command = iq.addElement("command") + command.attributes["sessionid"] = self.pytrans.makeMessageID() + command.attributes["xmlns"] = disco.COMMANDS + command.attributes["status"] = "completed" + + x = command.addElement("x") + x.attributes["xmlns"] = "jabber:x:data" + x.attributes["type"] = "result" + + title = x.addElement("title") + title.addContent(lang.get(ulang).command_Statistics) + + for key in self.stats: + label = getattr(lang.get(ulang), "command_%s" % key) + description = getattr(lang.get(ulang), "command_%s_Desc" % key) + field = x.addElement("field") + field.attributes["var"] = key + field.attributes["label"] = label + field.attributes["type"] = "text-single" + field.addElement("value").addContent(str(self.stats[key])) + field.addElement("desc").addContent(description) + + self.pytrans.send(iq) + + + +class AdHocCommands: + def __init__(self, pytrans): + self.pytrans = pytrans + self.pytrans.discovery.addFeature(disco.COMMANDS, self.incomingIq, config.jid) + self.pytrans.discovery.addNode(disco.COMMANDS, self.sendCommandList, "command_CommandList", config.jid, True) + + self.commands = {} # Dict of handlers indexed by node + self.commandNames = {} # Dict of names indexed by node - def makePingPacket(self): + def addCommand(self, command, handler, name): + self.commands[command] = handler + self.commandNames[command] = name + self.pytrans.discovery.addNode(command, self.incomingIq, name, config.jid, False) + + def incomingIq(self, el): + itype = el.getAttribute("type") + fro = el.getAttribute("from") + froj = jid.JID(fro) + to = el.getAttribute("to") + ID = el.getAttribute("id") + + LogEvent(INFO, "", "Looking for handler") + + node = None + for child in el.elements(): + xmlns = child.defaultUri + node = child.getAttribute("node") + + handled = False + if(child.name == "query" and xmlns == disco.DISCO_INFO): + if(node and self.commands.has_key(node) and (itype == "get")): + self.sendCommandInfoResponse(to=fro, ID=ID) + handled = True + elif(child.name == "query" and xmlns == disco.DISCO_ITEMS): + if(node and self.commands.has_key(node) and (itype == "get")): + self.sendCommandItemsResponse(to=fro, ID=ID) + handled = True + elif(child.name == "command" and xmlns == disco.COMMANDS): + if((node and self.commands.has_key(node)) and (itype == "set" or itype == "error")): + self.commands[node](el) + handled = True + if(not handled): + LogEvent(WARN, "", "Unknown Ad-Hoc command received.") + self.pytrans.discovery.sendIqError(to=fro, fro=config.jid, ID=ID, xmlns=xmlns, etype="cancel", condition="feature-not-implemented") + + + def sendCommandList(self, el): + to = el.getAttribute("from") + ID = el.getAttribute("id") + ulang = utils.getLang(el) + + iq = Element((None, "iq")) + iq.attributes["to"] = to + iq.attributes["from"] = config.jid + if ID: + iq.attributes["id"] = ID + iq.attributes["type"] = "result" + + query = iq.addElement("query") + query.attributes["xmlns"] = disco.DISCO_ITEMS + query.attributes["node"] = disco.COMMANDS + + for command in self.commands: + item = query.addElement("item") + item.attributes["jid"] = config.jid + item.attributes["node"] = command + item.attributes["name"] = getattr(lang.get(ulang), self.commandNames[command]) + + self.pytrans.send(iq) + + def sendCommandInfoResponse(self, to, ID): + LogEvent(INFO, "", "Replying to disco#info") iq = Element((None, "iq")) + iq.attributes["type"] = "result" iq.attributes["from"] = config.jid - iq.attributes["to"] = config.mainServerJID - iq.attributes["type"] = "get" + iq.attributes["to"] = to + if(ID): iq.attributes["id"] = ID query = iq.addElement("query") - query.attributes["xmlns"] = "jabber:iq:version" - return iq + query.attributes["xmlns"] = disco.DISCO_INFO + + feature = query.addElement("feature") + feature.attributes["var"] = disco.COMMANDS + self.pytrans.send(iq) + + def sendCommandItemsResponse(self, to, ID): + LogEvent(INFO, "", "Replying to disco#items") + iq = Element((None, "iq")) + iq.attributes["type"] = "result" + iq.attributes["from"] = config.jid + iq.attributes["to"] = to + if(ID): iq.attributes["id"] = ID + query = iq.addElement("query") + query.attributes["xmlns"] = disco.DISCO_ITEMS + self.pytrans.send(iq) + + +class VCardFactory: + def __init__(self, pytrans): + self.pytrans = pytrans + self.pytrans.discovery.addFeature("vcard-temp", self.incomingIq, "USER") + self.pytrans.discovery.addFeature("vcard-temp", self.incomingIq, config.jid) + + def incomingIq(self, el): + itype = el.getAttribute("type") + fro = el.getAttribute("from") + froj = jid.JID(fro) + to = el.getAttribute("to") + ID = el.getAttribute("id") + if(itype != "get" and itype != "error"): + self.pytrans.discovery.sendIqError(to=fro, fro=config.jid, ID=ID, xmlns="vcard-temp", etype="cancel", condition="feature-not-implemented") + return + + LogEvent(INFO, "", "Sending vCard") + + toGateway = not (to.find('@') > 0) + + if(not toGateway): + if(not self.pytrans.sessions.has_key(froj.userhost())): + self.pytrans.discovery.sendIqError(to=fro, fro=config.jid, ID=ID, xmlns="vcard-temp", etype="auth", condition="not-authorized") + return + s = self.pytrans.sessions[froj.userhost()] + if(not s.ready): + self.pytrans.discovery.sendIqError(to=fro, fro=config.jid, ID=ID, xmlns="vcard-temp", etype="auth", condition="not-authorized") + return + + c = s.contactList.findContact(to) + if(not c): + self.pytrans.discovery.sendIqError(to=fro, fro=config.jid, ID=ID, xmlns="vcard-temp", etype="cancel", condition="recipient-unavailable") + return + + + iq = Element((None, "iq")) + iq.attributes["to"] = fro + iq.attributes["from"] = to + if ID: + iq.attributes["id"] = ID + iq.attributes["type"] = "result" + vCard = iq.addElement("vCard") + vCard.attributes["xmlns"] = "vcard-temp" + if(toGateway): + FN = vCard.addElement("FN") + FN.addContent(legacy.name) + DESC = vCard.addElement("DESC") + DESC.addContent(legacy.name) + URL = vCard.addElement("URL") + URL.addContent(legacy.url) + else: + if(c.nickname): + NICKNAME = vCard.addElement("NICKNAME") + NICKNAME.addContent(c.nickname) + if(c.avatar): + PHOTO = c.avatar.makePhotoElement() + vCard.addChild(PHOTO) + + self.pytrans.send(iq) + +class IqAvatarFactory: + def __init__(self, pytrans): + self.pytrans = pytrans + self.pytrans.discovery.addFeature(disco.IQAVATAR, self.incomingIq, "USER") + self.pytrans.discovery.addFeature(disco.STORAGEAVATAR, self.incomingIq, "USER") + + def incomingIq(self, el): + itype = el.getAttribute("type") + fro = el.getAttribute("from") + froj = jid.JID(fro) + to = el.getAttribute("to") + ID = el.getAttribute("id") + + if(itype != "get" and itype != "error"): + self.pytrans.discovery.sendIqError(to=fro, fro=config.jid, ID=ID, xmlns=disco.IQAVATAR, etype="cancel", condition="feature-not-implemented") + return + + LogEvent(INFO, "", "Retrieving avatar") + + if(not self.pytrans.sessions.has_key(froj.userhost())): + self.pytrans.discovery.sendIqError(to=fro, fro=config.jid, ID=ID, xmlns=disco.IQAVATAR, etype="auth", condition="not-authorized") + return + s = self.pytrans.sessions[froj.userhost()] + if(not s.ready): + self.pytrans.discovery.sendIqError(to=fro, fro=config.jid, ID=ID, xmlns=disco.IQAVATAR, etype="auth", condition="not-authorized") + return + + c = s.contactList.findContact(to) + if(not c): + self.pytrans.discovery.sendIqError(to=fro, fro=config.jid, ID=ID, xmlns=disco.IQAVATAR, etype="cancel", condition="recipient-unavailable") + return + + iq = Element((None, "iq")) + iq.attributes["to"] = fro + iq.attributes["from"] = to + if ID: + iq.attributes["id"] = ID + iq.attributes["type"] = "result" + query = iq.addElement("query") + query.attributes["xmlns"] = disco.IQAVATAR + if(c.avatar): + DATA = c.avatar.makeDataElement() + query.addChild(DATA) + + self.pytrans.send(iq) + + + +class PingService: + def __init__(self, pytrans): + self.pytrans = pytrans +# self.pingCounter = 0 +# self.pingTask = task.LoopingCall(self.pingCheck) + self.pingTask = task.LoopingCall(self.whitespace) +# reactor.callLater(10.0, self.start) + +# def start(self): +# self.pingTask.start(120.0) + + def whitespace(self): + self.pytrans.send(" ") + +# def pingCheck(self): +# if(self.pingCounter >= 2 and self.pytrans.xmlstream): # Two minutes of no response from the main server +# LogEvent(WARN, "", "Disconnecting because the main server has ignored our pings for too long.") +# self.pytrans.xmlstream.transport.loseConnection() +# elif(config.mainServerJID): +# d = self.pytrans.discovery.sendIq(self.makePingPacket()) +# d.addCallback(self.pongReceived) +# d.addErrback(self.pongFailed) +# self.pingCounter += 1 + +# def pongReceived(self, el): +# self.pingCounter = 0 + +# def pongFailed(self, el): +# pass + +# def makePingPacket(self): +# iq = Element((None, "iq")) +# iq.attributes["from"] = config.jid +# iq.attributes["to"] = config.mainServerJID +# iq.attributes["type"] = "get" +# query = iq.addElement("query") +# query.attributes["xmlns"] = disco.IQVERSION +# return iq class GatewayTranslator: def __init__(self, pytrans): self.pytrans = pytrans - self.pytrans.discovery.addFeature("jabber:iq:gateway", self.incomingIq) + self.pytrans.discovery.addFeature(disco.IQGATEWAY, self.incomingIq, config.jid) def incomingIq(self, el): fro = el.getAttribute("from") @@ -63,16 +376,17 @@ class GatewayTranslator: def sendPrompt(self, to, ID, ulang): - debug.log("GatewayTranslator: Sending translation details for jabber:iq:gateway - user %s %s" % (to, ID)) + LogEvent(INFO) iq = Element((None, "iq")) iq.attributes["type"] = "result" iq.attributes["from"] = config.jid iq.attributes["to"] = to - iq.attributes["id"] = ID + if ID: + iq.attributes["id"] = ID query = iq.addElement("query") - query.attributes["xmlns"] = "jabber:iq:gateway" + query.attributes["xmlns"] = disco.IQGATEWAY desc = query.addElement("desc") desc.addContent(lang.get(ulang).gatewayTranslator) prompt = query.addElement("prompt") @@ -80,7 +394,7 @@ class GatewayTranslator: self.pytrans.send(iq) def sendTranslation(self, to, ID, el): - debug.log("GatewayTranslator: Translating account for jabber:iq:gateway - user %s %s" % (to, ID)) + LogEvent(INFO) # Find the user's legacy account legacyaccount = None @@ -94,28 +408,31 @@ class GatewayTranslator: if(legacyaccount and len(legacyaccount) > 0): - debug.log("GatewayTranslator: Sending translated account for jabber:iq:gateway - user %s %s" % (to, ID)) + LogEvent(INFO, "", "Sending translated account.") iq = Element((None, "iq")) iq.attributes["type"] = "result" iq.attributes["from"] = config.jid iq.attributes["to"] = to - iq.attributes["id"] = ID + if ID: + iq.attributes["id"] = ID query = iq.addElement("query") - query.attributes["xmlns"] = "jabber:iq:gateway" + query.attributes["xmlns"] = disco.IQGATEWAY prompt = query.addElement("prompt") prompt.addContent(legacy.translateAccount(legacyaccount)) self.pytrans.send(iq) else: - self.pytrans.discovery.sendIqNotValid(to, ID, "jabber:iq:gateway") + self.pytrans.discovery.sendIqError(to, ID, disco.IQGATEWAY) + self.pytrans.discovery.sendIqError(to=to, fro=config.jid, ID=ID, xmlns=disco.IQGATEWAY, etype="retry", condition="bad-request") class VersionTeller: def __init__(self, pytrans): self.pytrans = pytrans - self.pytrans.discovery.addFeature("jabber:iq:version", self.incomingIq) + self.pytrans.discovery.addFeature(disco.IQVERSION, self.incomingIq, config.jid) + self.pytrans.discovery.addFeature(disco.IQVERSION, self.incomingIq, "USER") def incomingIq(self, el): eltype = el.getAttribute("type") @@ -124,21 +441,21 @@ class VersionTeller: self.sendVersion(el) def sendVersion(self, el): - debug.log("Discovery: Sending transport version information") + LogEvent(INFO) iq = Element((None, "iq")) iq.attributes["type"] = "result" - iq.attributes["from"] = config.jid + iq.attributes["from"] = el.getAttribute("to") iq.attributes["to"] = el.getAttribute("from") if(el.getAttribute("id")): iq.attributes["id"] = el.getAttribute("id") query = iq.addElement("query") - query.attributes["xmlns"] = "jabber:iq:version" + query.attributes["xmlns"] = disco.IQVERSION name = query.addElement("name") name.addContent(legacy.name) version = query.addElement("version") version.addContent(legacy.version) os = query.addElement("os") - os.addContent("Python" + sys.version) + os.addContent("Python" + ".".join([str(x) for x in sys.version_info[0:3]]) + " - " + sys.platform) self.pytrans.send(iq)