-# 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
import os
+import os.path
import shutil
-if(os.name == "posix"):
- import signal
+import time
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
-import types
# Must load config before everything else
import config
import xmlconfig
xmlconfig.reloadConfig()
-if(config.reactor == "epoll"):
- from twisted.internet import epollreactor
- epollreactor.install()
-elif(config.reactor == "poll"):
- from twisted.internet import pollreactor
- pollreactor.install()
-elif(config.reactor == "kqueue"):
- from twisted.internet import kqreactor
- kqreactor.install()
-elif(len(config.reactor) > 0):
- print "Unknown reactor: ", config.reactor, "Using default reactor"
-
from twisted.internet import reactor, task
from twisted.internet.defer import Deferred
-import twisted.python.log
-if(utils.checkTwisted()):
+if utils.checkTwisted():
from twisted.words.protocols.jabber import component, jid
from twisted.xish.domish import Element
else:
from tlib.jabber import component, jid
from tlib.domish import Element
-
+from debug import LogEvent, INFO, WARN, ERROR
import xdb
+import avatar
import session
import jabw
import disco
import register
import misciq
import lang
-import debug
import legacy
+import housekeep
#import gc
#gc.set_debug(gc.DEBUG_COLLECTABLE | gc.DEBUG_UNCOLLECTABLE | gc.DEBUG_INSTANCES | gc.DEBUG_OBJECTS)
class PyTransport(component.Service):
def __init__(self):
- debug.log("PyTransport: Service starting up")
+ LogEvent(INFO)
+
+ # Do any auto-update stuff
+ housekeep.init()
# Discovery, as well as some builtin features
self.discovery = disco.ServerDiscovery(self)
- self.discovery.addIdentity("gateway", legacy.id, legacy.name)
- self.discovery.addIdentity("conference", "text", legacy.name + " Chatrooms")
- self.discovery.addFeature("http://jabber.org/protocol/muc", None) # So that clients know you can create groupchat rooms on the server
+ self.discovery.addIdentity("gateway", legacy.id, legacy.name, config.jid)
+ self.discovery.addIdentity("conference", "text", legacy.name + " Chatrooms", config.jid)
+ self.discovery.addFeature(disco.XCONFERENCE, None, config.jid) # So that clients know you can create groupchat rooms on the server
+ self.discovery.addFeature("jabber:iq:conference", None, config.jid) # We don't actually support this, but Psi has a bug where it looks for this instead of the above
self.xdb = xdb.XDB(config.jid, legacy.mangle)
+ self.avatarCache = avatar.AvatarCache()
self.registermanager = register.RegisterManager(self)
self.gatewayTranslator = misciq.GatewayTranslator(self)
self.versionTeller = misciq.VersionTeller(self)
self.pingService = misciq.PingService(self)
+ self.adHocCommands = misciq.AdHocCommands(self)
+ self.vCardFactory = misciq.VCardFactory(self)
+ self.iqAvatarFactor = misciq.IqAvatarFactory(self)
+ self.connectUsers = misciq.ConnectUsers(self)
+ self.statistics = misciq.Statistics(self)
+ self.startTime = int(time.time())
self.xmlstream = None
self.sessions = {}
# Message IDs
self.messageID = 0
- self.loopCheckSessions = task.LoopingCall(self.loopCheckSessionsCall)
- self.loopCheckSessions.start(60.0) # call every ten seconds
-
- # Display active sessions if debug mode is on
- if(config.debugOn):
- self.loop = task.LoopingCall(self.loopCall)
- self.loop.start(60.0) # call every 60 seconds
- twisted.python.log.addObserver(self.exceptionLogger)
-
-
+ self.loopCall = task.LoopingCall(self.loopCall)
+ self.loopCall.start(60.0)
+
def removeMe(self):
- debug.log("PyTransport: Service shutting down")
- dic = utils.copyDict(self.sessions)
- for session in dic:
- dic[session].removeMe()
-
- def exceptionLogger(self, *kwargs):
- if(len(config.debugLog) > 0):
- kwargs = kwargs[0]
- if(kwargs.has_key("failure")):
- failure = kwargs["failure"]
- failure.printTraceback(debug) # Pass debug as a pretend file object because it implements the write method
- if(config.debugLog):
- debug.flushDebugSmart()
- print "Exception occured! Check the log!"
+ LogEvent(INFO)
+ for session in self.sessions.copy():
+ self.sessions[session].removeMe()
def makeMessageID(self):
self.messageID += 1
def makeID(self):
newID = "r" + str(self.lastID)
self.lastID += 1
- if(self.reservedIDs.count(newID) > 0):
+ if self.reservedIDs.count(newID) > 0:
# Ack, it's already used.. Try again
return self.makeID()
else:
self.reservedIDs.append(ID)
def loopCall(self):
- if(len(self.sessions) > 0):
- debug.log("Sessions:")
- for key in self.sessions:
- debug.log("\t" + self.sessions[key].jabberID)
+ numsessions = len(self.sessions)
+
+ #if config.debugOn and numsessions > 0:
+ # print "Sessions:"
+ # for key in self.sessions:
+ # print "\t" + self.sessions[key].jabberID
- def loopCheckSessionsCall(self):
- if(len(self.sessions) > 0):
- oldDict = utils.copyDict(self.sessions)
+ self.statistics.stats["Uptime"] = int(time.time()) - self.startTime
+ self.statistics.stats["OnlineUsers"] = numsessions
+ legacy.updateStats(self.statistics)
+ if numsessions > 0:
+ oldDict = self.sessions.copy()
self.sessions = {}
for key in oldDict:
session = oldDict[key]
- if(not session.alive):
- debug.log("Ghost session %s found. This shouldn't happen. Trace" % (session.jabberID))
+ if not session.alive:
+ LogEvent(WARN, "", "Ghost session found.")
# Don't add it to the new dictionary. Effectively removing it
else:
self.sessions[key] = session
def componentConnected(self, xmlstream):
- debug.log("PyTransport: Connected to main Jabberd server")
+ LogEvent(INFO)
self.xmlstream = xmlstream
self.xmlstream.addObserver("/iq", self.discovery.onIq)
self.xmlstream.addObserver("/presence", self.onPresence)
self.xmlstream.addObserver("/message", self.onMessage)
self.xmlstream.addObserver("/route", self.onRouteMessage)
+ if config.useXCP:
+ pres = Element((None, "presence"))
+ pres.attributes["to"] = "presence@-internal"
+ pres.attributes["from"] = config.compjid
+ x = pres.addElement("x")
+ x.attributes["xmlns"] = "http://www.jabber.com/schemas/component-presence.xsd"
+ x.attributes["xmlns:config"] = "http://www.jabber.com/config"
+ x.attributes["config:version"] = "1"
+ x.attributes["protocol-version"] = "1.0"
+ x.attributes["config-ns"] = legacy.url + "/component"
+ self.send(pres)
def componentDisconnected(self):
- debug.log("PyTransport: Disconnected from main Jabberd server")
+ LogEvent(INFO)
self.xmlstream = None
def onRouteMessage(self, el):
for child in el.elements():
- if(child.name == "message"):
+ if child.name == "message":
self.onMessage(child)
- elif(child.name == "presence"):
+ elif child.name == "presence":
+ # Ignore any presence broadcasts about other XCP components
+ if child.getAttribute("to") and child.getAttribute("to").find("@-internal") > 0: return
self.onPresence(child)
- elif(child.name == "iq"):
+ elif child.name == "iq":
self.discovery.onIq(child)
def onMessage(self, el):
fro = el.getAttribute("from")
- froj = jid.JID(fro)
- to = el.getAttribute("to")
-# if(to.find('@') < 0): return
+ try:
+ froj = jid.JID(fro)
+ except Exception, e:
+ LogEvent(WARN, "", "Failed stringprep.")
+ return
mtype = el.getAttribute("type")
- ulang = utils.getLang(el)
- body = None
- for child in el.elements():
- if(child.name == "body"):
- body = child.__str__()
- if(self.sessions.has_key(froj.userhost())):
+ if self.sessions.has_key(froj.userhost()):
self.sessions[froj.userhost()].onMessage(el)
- elif(mtype != "error"):
- debug.log("PyTrans: Sending error response to a message outside of session.")
+ elif mtype != "error":
+ to = el.getAttribute("to")
+ ulang = utils.getLang(el)
+ body = None
+ for child in el.elements():
+ if child.name == "body":
+ body = child.__str__()
+ LogEvent(INFO, "", "Sending error response to a message outside of session.")
jabw.sendErrorMessage(self, fro, to, "auth", "not-authorized", lang.get(ulang).notLoggedIn, body)
def onPresence(self, el):
fro = el.getAttribute("from")
- ptype = el.getAttribute("type")
- froj = jid.JID(fro)
to = el.getAttribute("to")
- toj = jid.JID(to)
- ulang = utils.getLang(el)
- if(self.sessions.has_key(froj.userhost())):
+ try:
+ froj = jid.JID(fro)
+ toj = jid.JID(to)
+ except Exception, e:
+ LogEvent(WARN, "", "Failed stringprep.")
+ return
+
+ if self.sessions.has_key(froj.userhost()):
self.sessions[froj.userhost()].onPresence(el)
else:
- if(to.find('@') < 0):
+ ulang = utils.getLang(el)
+ ptype = el.getAttribute("type")
+ if to.find('@') < 0:
# If the presence packet is to the transport (not a user) and there isn't already a session
- if(el.getAttribute("type") in [None, ""]): # Don't create a session unless they're sending available presence
- debug.log("PyTransport: Attempting to create a new session \"%s\"" % (froj.userhost()))
+ if not el.getAttribute("type"): # Don't create a session unless they're sending available presence
+ LogEvent(INFO, "", "Attempting to create a new session.")
s = session.makeSession(self, froj.userhost(), ulang)
- if(s):
+ if s:
+ self.statistics.stats["TotalUsers"] += 1
self.sessions[froj.userhost()] = s
- debug.log("PyTransport: New session created \"%s\"" % (froj.userhost()))
+ LogEvent(INFO, "", "New session created.")
# Send the first presence
s.onPresence(el)
else:
- debug.log("PyTransport: Failed to create session \"%s\"" % (froj.userhost()))
+ LogEvent(INFO, "", "Failed to create session")
jabw.sendMessage(self, to=froj.userhost(), fro=config.jid, body=lang.get(ulang).notRegistered)
- elif(el.getAttribute("type") != "error"):
- debug.log("PyTransport: Sending unavailable presence to non-logged in user \"%s\"" % (froj.userhost()))
+ elif el.getAttribute("type") != "error":
+ LogEvent(INFO, "", "Sending unavailable presence to non-logged in user.")
pres = Element((None, "presence"))
pres.attributes["from"] = to
pres.attributes["to"] = fro
self.send(pres)
return
- elif(ptype in ["subscribe", "subscribed", "unsubscribe", "unsubscribed"]):
+ elif ptype and (ptype.startswith("subscribe") or ptype.startswith("unsubscribe")):
# They haven't logged in, and are trying to change subscription to a user
# Lets log them in and then do it
- debug.log("PyTransport: Attempting to create a session to do subscription stuff %s" % (froj.userhost()))
+ LogEvent(INFO, "", "Attempting to create a session to do subscription stuff.")
s = session.makeSession(self, froj.userhost(), ulang)
- if(s):
+ if s:
self.sessions[froj.userhost()] = s
- debug.log("PyTransport: New session created \"%s\"" % (froj.userhost()))
+ LogEvent(INFO, "", "New session created.")
# Tell the session there's a new resource
s.handleResourcePresence(froj.userhost(), froj.resource, toj.userhost(), toj.resource, 0, None, None, None)
# Send this subscription
class App:
def __init__(self):
- # Check that there isn't already a PID file
- if(os.path.isfile(utils.doPath(config.pid))):
- pf = open(utils.doPath(config.pid))
- pid = int(str(pf.readline().strip()))
- pf.close()
- if(os.name == "posix"):
- try:
- os.kill(pid, signal.SIGHUP)
- self.alreadyRunning()
- except OSError:
- # The process is still up
- pass
- else:
- self.alreadyRunning()
-
- # Create a PID file
- pid = str(os.getpid())
- pf = file(utils.doPath(config.pid), 'w')
- pf.write("%s\n" % pid);
- pf.close()
-
- self.c = component.buildServiceManager(config.jid, config.secret, "tcp:%s:%s" % (config.mainServer, config.port))
+ jid = config.jid
+ if config.compjid: jid = config.compjid
+ self.c = component.buildServiceManager(jid, config.secret, "tcp:%s:%s" % (config.mainServer, config.port))
self.transportSvc = PyTransport()
self.transportSvc.setServiceParent(self.c)
self.c.startService()
def shuttingDown(self):
self.transportSvc.removeMe()
+ # Keep the transport running for another 3 seconds
def cb(ignored=None):
- os.remove(utils.doPath(config.pid))
+ pass
d = Deferred()
d.addCallback(cb)
reactor.callLater(3.0, d.callback, None)
xmlconfig.reloadConfig()
debug.reopenFile()
-def doSpoolPrepCheck():
- pre = utils.doPath(config.spooldir) + "/" + config.jid + "/"
- try:
- f = open(pre + "notes_to_myself", "r")
- for line in f.readlines():
- if line == "doSpoolPrepCheck\n":
- return
- f.close()
- except IOError:
- pass
-
- # New installation
- if not os.path.exists(pre):
- os.makedirs(pre)
- f = open(pre + "notes_to_myself", "w")
- f.write("doSpoolPrepCheck\n")
- f.close()
- return
-
- print "Checking spool files and stringprepping any if necessary...",
- for file in os.listdir(pre):
- if(file == "notes_to_myself"): return
- file = file.replace("%", "@")
- filej = jid.JID(file).full()
- if(file != filej):
- file = file.replace("@", "%")
- filej = filej.replace("@", "%")
- if(os.path.exists(filej)):
- print "Need to move", file, "to", filej, "but the latter exists!\nAborting!"
- os.exit(1)
- else:
- shutil.move(utils.doPath(pre + file, pre + filej))
- print "done"
- f = open(pre + "notes_to_myself", "a")
- f.write("doSpoolPrepCheck\n")
- f.close()
-
-
-if(__name__ == "__main__"):
+if os.name == "posix":
+ import signal
# Set SIGHUP to reload the config file & close & open debug file
- if(os.name == "posix"):
- signal.signal(signal.SIGHUP, SIGHUPstuff)
+ signal.signal(signal.SIGHUP, SIGHUPstuff)
- # Check that all the spool files stringprepped
- doSpoolPrepCheck()
+if __name__ == "__main__":
app = App()
reactor.run()
-