-# 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
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")
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")
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
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")
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)