]> code.delx.au - pymsnt/blobdiff - src/misciq.py
Reimport and tags (0.10.1)
[pymsnt] / src / misciq.py
index bbbde0fffea1c765e1c9f9d0709c1f4f0bd729d9..56b5be6158f24b33477f65b97ffbdb723ea2dcb1 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright 2004 James Bunton <james@delx.cjb.net>
+# Copyright 2004-2005 James Bunton <james@delx.cjb.net>
 # 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)