From 176c216d59b6ecedec498ce7f70ee87f1a3e06d4 Mon Sep 17 00:00:00 2001 From: Patrick Thiel Date: Sun, 1 Oct 2023 23:23:07 -0400 Subject: [PATCH 1/8] ref: begin python3 conversion --- Dockerfile | 2 +- config.py | 15 +- configure_phxd.py | 4 +- phxd | 12 +- server/HLDatabase.py | 4 +- server/HLDatabaseLogger.py | 1 + server/HLFileServer.py | 9 +- server/HLServer.py | 792 +++++++++++------------ server/HLServerLinkage.py | 22 +- server/HLTracker.py | 1 + server/HLWebServices.py | 5 +- server/database/MySQLDatabase.py | 11 +- server/database/TextDatabase.py | 36 +- server/handlers/AcctHandler.py | 17 +- server/handlers/ChatHandler.py | 19 +- server/handlers/FileHandler.py | 45 +- server/handlers/IconHandler.py | 5 +- server/handlers/NewsHandler.py | 5 +- server/handlers/UserHandler.py | 29 +- server/handlers/commands/0wn.py | 1 + server/handlers/commands/away.py | 1 + server/handlers/commands/broadcast.py | 1 + server/handlers/commands/color.py | 1 + server/handlers/commands/find.py | 1 + server/handlers/commands/me.py | 1 + server/handlers/commands/news.py | 1 + server/handlers/commands/uptime.py | 3 +- server/handlers/commands/xfers.py | 3 +- shared/HLProtocol.py | 883 +++++++++++++------------- shared/HLTransfer.py | 11 +- shared/HLTypes.py | 20 +- shared/HLUtils.py | 1 + support/text_db_setup.py | 1 + 33 files changed, 1005 insertions(+), 958 deletions(-) diff --git a/Dockerfile b/Dockerfile index 3ba5b98..ac4bbda 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:2-alpine +FROM python:3.9-alpine MAINTAINER Cat'Killer # The "exec" plugins are all written in bash and won't diff --git a/config.py b/config.py index 8543276..df9835a 100644 --- a/config.py +++ b/config.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import os ################################################################################ # database configuration @@ -38,8 +39,8 @@ ################################################################################ SERVER_PORT = 5500 -SERVER_NAME = "phxd server" -SERVER_DESCRIPTION = "Yet another phxd server instance" +SERVER_NAME = "icedtrip2" +SERVER_DESCRIPTION = "Yet another hotline server instance" IDLE_TIME = 10 * 60 BAN_TIME = 15 * 60 @@ -48,9 +49,13 @@ ################################################################################ # TRACKER_LIST example: -#TRACKER_LIST=[("tracker.hostname.tld", 5499), -# ("127.0.0.1", 5499)] -TRACKER_LIST=[] +TRACKER_LIST=[("tracker.preterhuman.net", 5499), + ("tracked.agent79.org", 5499), + ("hotline.duckdns.org", 5499), + ("tracked.stickytack.com", 5499), + ("tracked.nailbat.com", 5499), + ("hotline.ubersoft.org", 5499)] +#TRACKER_LIST=[] TRACKER_REFRESH_PERIOD=60 diff --git a/configure_phxd.py b/configure_phxd.py index 6985085..0acadb3 100755 --- a/configure_phxd.py +++ b/configure_phxd.py @@ -5,6 +5,8 @@ TODO: This is unecessarily complex. Need to use a better config file format instead """ +from __future__ import absolute_import +from __future__ import print_function __author__ = "Cat'Killer" __version__ = "0.0.1" __license__ = "WTFPL" @@ -55,7 +57,7 @@ def rewrite_config_file(filepath, values_dict): """ if not values_dict: return - keys = values_dict.keys() + keys = list(values_dict.keys()) with open(filepath, 'r') as config_file: config_str = config_file.read() with tempfile.NamedTemporaryFile(delete=False) as tmpconfig: diff --git a/phxd b/phxd index 944f9ed..0214799 100755 --- a/phxd +++ b/phxd @@ -1,5 +1,7 @@ #!/usr/bin/env python +from __future__ import absolute_import +from __future__ import print_function from twisted.internet import reactor from server.HLServer import HLServer from shared.HLTypes import * @@ -8,11 +10,11 @@ import server.handlers serv = HLServer() for modName in server.handlers.__all__: - try: - mod = __import__( "server.handlers.%s" % modName , None , None , "server.handlers" ) - mod.installHandler( serv ) - except ImportError: - print "error importing server.handlers.%s" % modName + try: + mod = __import__( "server.handlers.%s" % modName , None , None , "server.handlers" ) + mod.installHandler( serv ) + except ImportError: + print("error importing server.handlers.%s" % modName) serv.logEvent( LOG_TYPE_GENERAL , "Server started on port %d" % serv.port ) reactor.run() diff --git a/server/HLDatabase.py b/server/HLDatabase.py index 4d73c3a..84d852f 100644 --- a/server/HLDatabase.py +++ b/server/HLDatabase.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import +from __future__ import print_function from shared.HLTypes import * import server.database @@ -9,7 +11,7 @@ def getDatabase( type ): db = eval( "mod.%s()" % cls ) return db except ImportError: - print "error importing server.database.%s" % cls + print("error importing server.database.%s" % cls) return None class HLDatabase: diff --git a/server/HLDatabaseLogger.py b/server/HLDatabaseLogger.py index ee5b219..3d2f605 100644 --- a/server/HLDatabaseLogger.py +++ b/server/HLDatabaseLogger.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from logging import Handler class HLDatabaseLogger( Handler ): diff --git a/server/HLFileServer.py b/server/HLFileServer.py index 9ed8ea7..083010b 100644 --- a/server/HLFileServer.py +++ b/server/HLFileServer.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from twisted.internet.protocol import Factory , Protocol from twisted.internet.interfaces import IProducer from twisted.internet import reactor @@ -102,7 +103,7 @@ def addDownload( self , owner , path , offset ): def findTransfer( self , xfid ): """ Returns the HLTransfer (HLDownload or HLUpload) object for the specified transfer ID. """ - if self.transfers.has_key( xfid ): + if xfid in self.transfers: return self.transfers[xfid] return None @@ -116,19 +117,19 @@ def findTransfersForUser( self , uid ): def cancelTimeout( self , id ): """ Cancels a pending timeout for the specified transfer. """ - if self.timeouts.has_key( id ): + if id in self.timeouts: self.timeouts[id].cancel() del self.timeouts[id] def timeoutTransfer( self , id ): """ Called after an initial timeout to remove the dead transfer from the list of transfers. """ - if self.transfers.has_key( id ): + if id in self.transfers: del self.timeouts[id] del self.transfers[id] def removeTransfer( self , xfid ): """ Removes a transfer from the list of transfers. """ - if self.transfers.has_key( xfid ): + if xfid in self.transfers: info = self.transfers[xfid] user = self.server.getUser( info.owner ) if user != None: diff --git a/server/HLServer.py b/server/HLServer.py index 4dac84a..04287ab 100644 --- a/server/HLServer.py +++ b/server/HLServer.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import +from __future__ import print_function from twisted.internet.protocol import Factory , Protocol from twisted.internet import task from twisted.internet import reactor @@ -18,419 +20,419 @@ from logging.handlers import RotatingFileHandler class HLConnection( Protocol ): - """ Protocol subclass to handle parsing and dispatching of raw hotline data. """ - - def __init__( self , factory , connID ): - self.factory = factory - self.connID = connID - - def connectionMade( self ): - """ Called when a connection is accepted. """ - self.gotMagic = False - self.isIRC = False - self.packet = HLPacket() - self.buffer = "" - self.idleTimer = reactor.callLater( IDLE_TIME , self.idleCheck ) - - def connectionLost( self , reason ): - """ Called when the connection is lost. """ - if ( self.idleTimer != None ) and self.idleTimer.active(): - self.idleTimer.cancel() - self.factory.removeConnection( self.connID ) - - def dataReceived( self , data ): - """ Called when the socket receives data. """ - self.buffer += data - self.parseBuffer() - - def parseBuffer( self ): - """ Parses the current buffer until the buffer is empty or until no more packets can be parsed. """ - if self.gotMagic: - done = False - while not done: - if self.isIRC: - self.buffer = self.buffer.replace("\r", "") #FIXME is it really necessary ? it is also done during packet parsing - self.packet.isIRC = self.isIRC - self.packet.connID = self.connID - self.packet.server = self.factory - size = self.packet.parse( self.buffer ) - if size > 0: - if self.isIRC: - size = size + 1 - self.buffer = self.buffer[size:] - self.handlePacket() - self.packet = HLPacket() - else: - done = True - else: - if len( self.buffer ) >= 12: - ( proto , subProto , vers , subVers ) = unpack( "!LLHH" , self.buffer[0:12] ) - if proto == HLCharConst( "TRTP" ): - self.buffer = self.buffer[12:] - self.gotMagic = True - self.transport.write( pack( "!2L" , HLCharConst( "TRTP" ) , 0 ) ) - # If there is still data in the buffer, check for packets. - if len( self.buffer ) > 0: - self.parseBuffer() - else: - # Not hotline, assume IRC. Multiple commands can be chained in IRC. - cmds = self.buffer.splitlines() - if cmds[0].startswith("CAP"): - # We received CAP LS, ignore it and read the rest of the buffer - # This is for compatibility with IRC v3.02 clients like irssi - cmds.pop(0) - # If there are no further commands, close the connection. - if not cmds: - self.transport.loseConnection() - # More commands still in the buffer, parse them. - value = "" - try: - cmd, value = cmds[0].split(" ", 1) - except ValueError: - # Value isn't defined, only parse cmd - cmd = cmds[0].split(" ", 1)[0] - # Check the first command, if NICK or USER, login, else return UNKNOWN COMMAND - if ( cmd == "NICK" ) or ( cmd == "USER" ): - nick = value or "Unnamed" - user = self.factory.getUser( self.connID ) - user.nick = nick # Making sure we have the right nick. - self.transport.write ( "NOTICE * :*** Welcome to Hotline\r\n" ) - self.transport.write ( "NOTICE AUTH :*** You are NOT logged in\r\n" ) - self.transport.write ( "NOTICE AUTH :*** Please send '/msg loginserv login password' to proceed.\r\n" ) - self.transport.write ( "NOTICE AUTH :*** If you do not have an account, use '/msg loginserv guest' to proceed.\r\n" ) - self.transport.write ( ":"+IRC_SERVER_NAME+" 001 %s :Waiting for login input..\r\n" % nick ) - self.transport.write ( ":"+IRC_SERVER_NAME+" 375 %s :- MOTDs are for losers.\r\n" % user.nick ) - self.transport.write ( ":"+IRC_SERVER_NAME+" 372 %s :- :)\r\n" % user.nick ) - self.transport.write ( ":"+IRC_SERVER_NAME+" 376 %s :End of /MOTD command.\r\n" % user.nick ) + """ Protocol subclass to handle parsing and dispatching of raw hotline data. """ + + def __init__( self , factory , connID ): + self.factory = factory + self.connID = connID + + def connectionMade( self ): + """ Called when a connection is accepted. """ + self.gotMagic = False + self.isIRC = False + self.packet = HLPacket() + self.buffer = "" + self.idleTimer = reactor.callLater( IDLE_TIME , self.idleCheck ) + + def connectionLost( self , reason ): + """ Called when the connection is lost. """ + if ( self.idleTimer != None ) and self.idleTimer.active(): + self.idleTimer.cancel() + self.factory.removeConnection( self.connID ) + + def dataReceived( self , data ): + """ Called when the socket receives data. """ + self.buffer += data + self.parseBuffer() + + def parseBuffer( self ): + """ Parses the current buffer until the buffer is empty or until no more packets can be parsed. """ + if self.gotMagic: + done = False + while not done: + if self.isIRC: + self.buffer = self.buffer.replace("\r", "") #FIXME is it really necessary ? it is also done during packet parsing + self.packet.isIRC = self.isIRC + self.packet.connID = self.connID + self.packet.server = self.factory + size = self.packet.parse( self.buffer ) + if size > 0: + if self.isIRC: + size = size + 1 + self.buffer = self.buffer[size:] + self.handlePacket() + self.packet = HLPacket() + else: + done = True + else: + if len( self.buffer ) >= 12: + ( proto , subProto , vers , subVers ) = unpack( "!LLHH" , self.buffer[0:12] ) + if proto == HLCharConst( "TRTP" ): + self.buffer = self.buffer[12:] + self.gotMagic = True + self.transport.write( pack( "!2L" , HLCharConst( "TRTP" ) , 0 ) ) + # If there is still data in the buffer, check for packets. + if len( self.buffer ) > 0: + self.parseBuffer() + else: + # Not hotline, assume IRC. Multiple commands can be chained in IRC. + cmds = self.buffer.splitlines() + if cmds[0].startswith("CAP"): + # We received CAP LS, ignore it and read the rest of the buffer + # This is for compatibility with IRC v3.02 clients like irssi + cmds.pop(0) + # If there are no further commands, close the connection. + if not cmds: + self.transport.loseConnection() + # More commands still in the buffer, parse them. + value = "" + try: + cmd, value = cmds[0].split(" ", 1) + except ValueError: + # Value isn't defined, only parse cmd + cmd = cmds[0].split(" ", 1)[0] + # Check the first command, if NICK or USER, login, else return UNKNOWN COMMAND + if ( cmd == "NICK" ) or ( cmd == "USER" ): + nick = value or "Unnamed" + user = self.factory.getUser( self.connID ) + user.nick = nick # Making sure we have the right nick. + self.transport.write ( "NOTICE * :*** Welcome to Hotline\r\n" ) + self.transport.write ( "NOTICE AUTH :*** You are NOT logged in\r\n" ) + self.transport.write ( "NOTICE AUTH :*** Please send '/msg loginserv login password' to proceed.\r\n" ) + self.transport.write ( "NOTICE AUTH :*** If you do not have an account, use '/msg loginserv guest' to proceed.\r\n" ) + self.transport.write ( ":"+IRC_SERVER_NAME+" 001 %s :Waiting for login input..\r\n" % nick ) + self.transport.write ( ":"+IRC_SERVER_NAME+" 375 %s :- MOTDs are for losers.\r\n" % user.nick ) + self.transport.write ( ":"+IRC_SERVER_NAME+" 372 %s :- :)\r\n" % user.nick ) + self.transport.write ( ":"+IRC_SERVER_NAME+" 376 %s :End of /MOTD command.\r\n" % user.nick ) - self.isIRC = True - self.gotMagic = True - self.parseBuffer() - else: - self.transport.write ( ":"+IRC_SERVER_NAME+" 421 %s :Unknown command\r\n" % cmd ) - self.transport.loseConnection() - - def handlePacket( self ): - """ Dispatch the packet to the factory (and its listeners) and check to see if we should update our away status. """ - try: - user = self.factory.getUser( self.connID ) - if not user: - self.transport.loseConnection() - return - if self.isIRC and self.packet.irctrap: - # Unsupported command, return 421 - self.transport.write ( ":"+IRC_SERVER_NAME+" 421 %s %s :Unknown command\r\n" % (user.nick, self.packet.irctrap) ) - if user.isLoggedIn(): - # Make sure we're logged in before doing anything. - self.factory.dispatchPacket( self.connID , self.packet ) - if ( not isPingType( self.packet.type ) ) and ( not user.away ): - # We got a non-ping packet, and we're not away. - user.lastPacketTime = time.time() - if ( self.idleTimer != None ) and self.idleTimer.active(): - # If the idleTimer exists and hasn't fired yet, remain active. - self.idleTimer.reset( IDLE_TIME ) - else: - # Otherwise, we just came back from being idle. - user.status &= ~STATUS_AWAY - self.factory.dispatchPacket( self.connID , HLPacket( HTLC_HDR_USER_CHANGE ) ) - self.idleTimer = reactor.callLater( IDLE_TIME , self.idleCheck ) - elif ( self.packet.type == HTLC_HDR_LOGIN ): - user.isIRC = self.packet.isIRC - # If we're not logged in, only dispatch login packets. - user.lastPacketTime = time.time() - self.factory.dispatchPacket( self.connID , self.packet ) - elif ( self.packet.type == HTLC_HDR_PING ): - if self.packet.isIRC: - self.factory.dispatchPacket( self.connID , self.packet ) - else: - if ( self.packet.isIRC == 0 ) and ( self.packet.type != 0 ) and ( self.packet.type != 130 ): - print "got packet before login:" - print self.packet - except HLException , ex: - # Unhandled packets and task errors will be caught here. - if self.isIRC: - if self.packet.irctrap: - # Not sure this is still required since we already return a 421 "Unknown command" reply. - self.transport.write( "NOTICE * :*** HL Error 0x%x [%s] %s\r\n" % ( self.packet.type, self.packet.irctrap, ex.msg )) - else: - packet = HLPacket( HTLS_HDR_TASK , self.packet.seq , 1 ) - packet.addString( DATA_ERROR , ex.msg ) - self.writePacket( packet ) - if ex.fatal: - # The exception was fatal (i.e. failed login) so kill the connection. - self.transport.loseConnection() - - def idleCheck( self ): - """ Called a set amount of time after the last non-ping packet, mark us as idle and trick the handlers into sending the change. """ - user = self.factory.getUser( self.connID ) - if not user.away: - # Only send the change if the user is not away and not idle. - user.status |= STATUS_AWAY - self.factory.dispatchPacket( self.connID , HLPacket(HTLC_HDR_USER_CHANGE ) ) - del self.idleTimer - self.idleTimer = None - - def writePacket( self , packet ): - """ Flattens and writes a packet out to the socket. """ - packet.server = self.factory - self.transport.write( packet.flatten( self.factory.getUser( self.connID ) ) ) + self.isIRC = True + self.gotMagic = True + self.parseBuffer() + else: + self.transport.write ( ":"+IRC_SERVER_NAME+" 421 %s :Unknown command\r\n" % cmd ) + self.transport.loseConnection() + + def handlePacket( self ): + """ Dispatch the packet to the factory (and its listeners) and check to see if we should update our away status. """ + try: + user = self.factory.getUser( self.connID ) + if not user: + self.transport.loseConnection() + return + if self.isIRC and self.packet.irctrap: + # Unsupported command, return 421 + self.transport.write ( ":"+IRC_SERVER_NAME+" 421 %s %s :Unknown command\r\n" % (user.nick, self.packet.irctrap) ) + if user.isLoggedIn(): + # Make sure we're logged in before doing anything. + self.factory.dispatchPacket( self.connID , self.packet ) + if ( not isPingType( self.packet.type ) ) and ( not user.away ): + # We got a non-ping packet, and we're not away. + user.lastPacketTime = time.time() + if ( self.idleTimer != None ) and self.idleTimer.active(): + # If the idleTimer exists and hasn't fired yet, remain active. + self.idleTimer.reset( IDLE_TIME ) + else: + # Otherwise, we just came back from being idle. + user.status &= ~STATUS_AWAY + self.factory.dispatchPacket( self.connID , HLPacket( HTLC_HDR_USER_CHANGE ) ) + self.idleTimer = reactor.callLater( IDLE_TIME , self.idleCheck ) + elif ( self.packet.type == HTLC_HDR_LOGIN ): + user.isIRC = self.packet.isIRC + # If we're not logged in, only dispatch login packets. + user.lastPacketTime = time.time() + self.factory.dispatchPacket( self.connID , self.packet ) + elif ( self.packet.type == HTLC_HDR_PING ): + if self.packet.isIRC: + self.factory.dispatchPacket( self.connID , self.packet ) + else: + if ( self.packet.isIRC == 0 ) and ( self.packet.type != 0 ) and ( self.packet.type != 130 ): + print("got packet before login:") + print(self.packet) + except HLException as ex: + # Unhandled packets and task errors will be caught here. + if self.isIRC: + if self.packet.irctrap: + # Not sure this is still required since we already return a 421 "Unknown command" reply. + self.transport.write( "NOTICE * :*** HL Error 0x%x [%s] %s\r\n" % ( self.packet.type, self.packet.irctrap, ex.msg )) + else: + packet = HLPacket( HTLS_HDR_TASK , self.packet.seq , 1 ) + packet.addString( DATA_ERROR , ex.msg ) + self.writePacket( packet ) + if ex.fatal: + # The exception was fatal (i.e. failed login) so kill the connection. + self.transport.loseConnection() + + def idleCheck( self ): + """ Called a set amount of time after the last non-ping packet, mark us as idle and trick the handlers into sending the change. """ + user = self.factory.getUser( self.connID ) + if not user.away: + # Only send the change if the user is not away and not idle. + user.status |= STATUS_AWAY + self.factory.dispatchPacket( self.connID , HLPacket(HTLC_HDR_USER_CHANGE ) ) + del self.idleTimer + self.idleTimer = None + + def writePacket( self , packet ): + """ Flattens and writes a packet out to the socket. """ + packet.server = self.factory + self.transport.write( packet.flatten( self.factory.getUser( self.connID ) ) ) class HLServer( Factory ): - """ Factory subclass that handles all global server operations. Also owns database and fileserver objects. """ - - def __init__( self ): - self.port = SERVER_PORT - self.lastUID = 0 - self.lastChatID = 0 - self.clients = {} - self.chats = {} - self.handlers = [] - self.tempBans = {} - self.database = getDatabase( DB_TYPE ) - self.fileserver = HLFileServer( self ) - self.webserver = HLWebServices( self ) - self.startTime = time.time() - self.log = logging.getLogger( "phxd" ) - self.linker = HLServerLinker( self ) - self._initLog() - reactor.listenTCP( self.port , self ) - # Update all trackers periodically - recurrentTask = task.LoopingCall(self.updateTrackers) - recurrentTask.start(TRACKER_REFRESH_PERIOD) - #recurrentTask.addErrback(updateTrackersFailed) - - def updateTrackers(self): - """Updates the register trackers, if any, with the name - and description of server and the current user count. - """ - for hostname, port in TRACKER_LIST: - reactor.listenUDP(0, HLTrackerClient(self, hostname, port)) + """ Factory subclass that handles all global server operations. Also owns database and fileserver objects. """ + + def __init__( self ): + self.port = SERVER_PORT + self.lastUID = 0 + self.lastChatID = 0 + self.clients = {} + self.chats = {} + self.handlers = [] + self.tempBans = {} + self.database = getDatabase( DB_TYPE ) + self.fileserver = HLFileServer( self ) + self.webserver = HLWebServices( self ) + self.startTime = time.time() + self.log = logging.getLogger( "phxd" ) + self.linker = HLServerLinker( self ) + self._initLog() + reactor.listenTCP( self.port , self ) + # Update all trackers periodically + recurrentTask = task.LoopingCall(self.updateTrackers) + recurrentTask.start(TRACKER_REFRESH_PERIOD) + #recurrentTask.addErrback(updateTrackersFailed) + + def updateTrackers(self): + """Updates the register trackers, if any, with the name + and description of server and the current user count. + """ + for hostname, port in TRACKER_LIST: + reactor.listenUDP(0, HLTrackerClient(self, hostname, port)) - def updateTrackersFailed(self, reason): - """Errback invoked when the task to update the trackers - fails for whatever reason. - """ - print "Failed to update tracker: reason" + def updateTrackersFailed(self, reason): + """Errback invoked when the task to update the trackers + fails for whatever reason. + """ + print("Failed to update tracker: reason") - def _initLog( self ): - self.log.setLevel( logging.DEBUG ) - if ENABLE_FILE_LOG: - # the formatter is just for the file logger - fmt = logging.Formatter( '%(asctime)s\t%(message)s' ) - logSizeBytes = LOG_MAX_SIZE_MBYTES * 1024 * 1024 - try: - fileHandler = RotatingFileHandler( LOG_FILE, - maxBytes=logSizeBytes, backupCount=MAX_LOG_FILES ) - except IOError: - # Logfile directory most likely doesn't exist, attempt - # to create it and try again. - import os - os.makedirs(os.path.dirname(LOG_FILE)) - fileHandler = logging.FileHandler( LOG_FILE, - maxBytes=logSizeBytes, backupCount=MAX_LOG_FILES ) - # If opening the file handle fails at this point, raise - fileHandler.setFormatter( fmt ) - # make sure everything goes to the file log - fileHandler.setLevel( logging.DEBUG ) - self.log.addHandler( fileHandler ) - dbHandler = HLDatabaseLogger( self.database ) - # we only want server events and errors in the database log - dbHandler.setLevel( logging.INFO ) - self.log.addHandler( dbHandler ) - - def linkToServer( self, addr ): - ( ip , port ) = addr.split( ':' ) - self.linker.link( ip, int(port) ) + def _initLog( self ): + self.log.setLevel( logging.DEBUG ) + if ENABLE_FILE_LOG: + # the formatter is just for the file logger + fmt = logging.Formatter( '%(asctime)s\t%(message)s' ) + logSizeBytes = LOG_MAX_SIZE_MBYTES * 1024 * 1024 + try: + fileHandler = RotatingFileHandler( LOG_FILE, + maxBytes=logSizeBytes, backupCount=MAX_LOG_FILES ) + except IOError: + # Logfile directory most likely doesn't exist, attempt + # to create it and try again. + import os + os.makedirs(os.path.dirname(LOG_FILE)) + fileHandler = logging.FileHandler( LOG_FILE, + maxBytes=logSizeBytes, backupCount=MAX_LOG_FILES ) + # If opening the file handle fails at this point, raise + fileHandler.setFormatter( fmt ) + # make sure everything goes to the file log + fileHandler.setLevel( logging.DEBUG ) + self.log.addHandler( fileHandler ) + dbHandler = HLDatabaseLogger( self.database ) + # we only want server events and errors in the database log + dbHandler.setLevel( logging.INFO ) + self.log.addHandler( dbHandler ) + + def linkToServer( self, addr ): + ( ip , port ) = addr.split( ':' ) + self.linker.link( ip, int(port) ) - def addRemoteUser( self, remoteUser, sendChange = True ): - self.lastUID += 1 - user = HLUser( self.lastUID, "" ) - user.nick = remoteUser.nick - user.icon = remoteUser.icon - user.color = remoteUser.color - user.status = remoteUser.status - user.local = False - user.account = HLAccount( "" ) - user.account.name = "Linked Account" - user.valid = True + def addRemoteUser( self, remoteUser, sendChange = True ): + self.lastUID += 1 + user = HLUser( self.lastUID, "" ) + user.nick = remoteUser.nick + user.icon = remoteUser.icon + user.color = remoteUser.color + user.status = remoteUser.status + user.local = False + user.account = HLAccount( "" ) + user.account.name = "Linked Account" + user.valid = True - self.clients[self.lastUID] = ( None , user ) + self.clients[self.lastUID] = ( None , user ) - if sendChange: - change = HLPacket( HTLS_HDR_USER_CHANGE ) - change.addNumber( DATA_UID , user.uid ) - change.addString( DATA_NICK , user.nick ) - change.addNumber( DATA_ICON , user.icon ) - change.addNumber( DATA_STATUS , user.status ) - for ( conn , user ) in self.clients.values(): - if user.local: - conn.writePacket( change ) - return user.uid + if sendChange: + change = HLPacket( HTLS_HDR_USER_CHANGE ) + change.addNumber( DATA_UID , user.uid ) + change.addString( DATA_NICK , user.nick ) + change.addNumber( DATA_ICON , user.icon ) + change.addNumber( DATA_STATUS , user.status ) + for ( conn , user ) in self.clients.values(): + if user.local: + conn.writePacket( change ) + return user.uid - def removeRemoteUser( self, uid ): - if self.clients.has_key( uid ): + def removeRemoteUser( self, uid ): + if uid in self.clients: del( self.clients[uid] ) - - def handleUserLogin( self, user ): + + def handleUserLogin( self, user ): user.valid = True self.linker.forwardUserConnect( user ) - - def addTempBan( self , addr , reason = "no reason" ): - """ Adds a temporary ban for addr that will expire in BAN_TIME seconds. """ - if not self.tempBans.has_key( addr ): - self.tempBans[addr] = reason - reactor.callLater( BAN_TIME , self.removeTempBan , addr ) - - def removeTempBan( self , addr ): - """ Removes a temporary ban for addr, if it exists. """ - if self.tempBans.has_key( addr ): - del self.tempBans[addr] - - def checkForBan( self , addr ): - """ Returns the reason given for a ban, if it exists. Otherwise returns None. """ - if self.tempBans.has_key( addr ): - return self.tempBans[addr] - return self.database.checkBanlist( addr ) - - def buildProtocol( self , addr ): - """ Called when the factory accepts a connection and is asked to return a Protocol (in our case, a HLConnection). """ - self.lastUID += 1 - conn = HLConnection( self , self.lastUID ) - user = HLUser( self.lastUID , addr.host ) - self.clients[self.lastUID] = ( conn , user ) - for handler in self.handlers: - handler.handleUserConnected( self , user ) - return conn - - def registerPacketHandler( self , handler ): - """ Registers a HLPacketHandler. """ - if isinstance( handler , HLPacketHandler ): - self.handlers.append( handler ) - - def disconnectUser( self , uid ): - """ Actively disconnect the specified user. """ - if self.clients.has_key( uid ): - ( conn , user ) = self.clients[uid] - conn.transport.loseConnection() - - def removeConnection( self , connID ): - """ Called from HLConnection when a connection dies. """ - if self.clients.has_key( connID ): - ( conn , user ) = self.clients[connID] - if user.isLoggedIn(): - for handler in self.handlers: - handler.handleUserDisconnected( self , user ) - self.fileserver.cleanupTransfers( user.uid ) - self.linker.forwardUserDisconnect( user ) - del( self.clients[connID] ) - - def getUser( self , uid ): - """ Gets the HLUser object for the specified uid. """ - if self.clients.has_key( uid ): - ( conn , user ) = self.clients[uid] - return user - return None - + + def addTempBan( self , addr , reason = "no reason" ): + """ Adds a temporary ban for addr that will expire in BAN_TIME seconds. """ + if addr not in self.tempBans: + self.tempBans[addr] = reason + reactor.callLater( BAN_TIME , self.removeTempBan , addr ) + + def removeTempBan( self , addr ): + """ Removes a temporary ban for addr, if it exists. """ + if addr in self.tempBans: + del self.tempBans[addr] + + def checkForBan( self , addr ): + """ Returns the reason given for a ban, if it exists. Otherwise returns None. """ + if addr in self.tempBans: + return self.tempBans[addr] + return self.database.checkBanlist( addr ) + + def buildProtocol( self , addr ): + """ Called when the factory accepts a connection and is asked to return a Protocol (in our case, a HLConnection). """ + self.lastUID += 1 + conn = HLConnection( self , self.lastUID ) + user = HLUser( self.lastUID , addr.host ) + self.clients[self.lastUID] = ( conn , user ) + for handler in self.handlers: + handler.handleUserConnected( self , user ) + return conn + + def registerPacketHandler( self , handler ): + """ Registers a HLPacketHandler. """ + if isinstance( handler , HLPacketHandler ): + self.handlers.append( handler ) + + def disconnectUser( self , uid ): + """ Actively disconnect the specified user. """ + if uid in self.clients: + ( conn , user ) = self.clients[uid] + conn.transport.loseConnection() + + def removeConnection( self , connID ): + """ Called from HLConnection when a connection dies. """ + if connID in self.clients: + ( conn , user ) = self.clients[connID] + if user.isLoggedIn(): + for handler in self.handlers: + handler.handleUserDisconnected( self , user ) + self.fileserver.cleanupTransfers( user.uid ) + self.linker.forwardUserDisconnect( user ) + del( self.clients[connID] ) + + def getUser( self , uid ): + """ Gets the HLUser object for the specified uid. """ + if uid in self.clients: + ( conn , user ) = self.clients[uid] + return user + return None + def getUserCount(self): """Returns the number of logged in HLUsers.""" return len([user for _, user in self.clients.values() if user.isLoggedIn()]) - def getOrderedUserlist( self ): - """ Returns a list of HLUsers, ordered by uid. """ - keys = self.clients.keys() - keys.sort() - userlist = [] - for uid in keys: - ( conn , user ) = self.clients[uid] - if user.isLoggedIn(): - userlist.append( user ) - return userlist - - def createChat( self ): - """ Creates and registers a new private chat, returns the ID of the newly created chat. """ - self.lastChatID += 1 - chat = HLChat( self.lastChatID ) - self.chats[self.lastChatID] = chat - return chat - - def removeChat( self , id ): - """ Remove the specified private chat. """ - if self.chats.has_key( id ): - del self.chats[id] - - def getChat( self , id ): - """ Gets the HLChat object for the specified chat ID. """ - if self.chats.has_key( id ): - return self.chats[id] - return None - - def sendPacket( self , uid , packet ): - """ Sends the specified packet to the specified user. """ - if self.clients.has_key( uid ): - ( conn , user ) = self.clients[uid] - packet.isIRC = conn.isIRC - if user.local: - conn.writePacket( packet ) - else: - self.linker.forwardPacket( packet, user.uid ) - - def broadcastPacket( self , packet , priv = 0 ): - """ Sends the specified packet to all connected users. If priv is specified, only sends to users with that priv. """ - for ( conn , user ) in self.clients.values(): - packet.isIRC = conn.isIRC - if not user.local: - self.linker.forwardPacket( packet, user.uid ) - elif user.isLoggedIn(): - if priv > 0: - if user.hasPriv( priv ): - conn.writePacket( packet ) - else: - conn.writePacket( packet ) + def getOrderedUserlist( self ): + """ Returns a list of HLUsers, ordered by uid. """ + keys = list(self.clients.keys()) + keys.sort() + userlist = [] + for uid in keys: + ( conn , user ) = self.clients[uid] + if user.isLoggedIn(): + userlist.append( user ) + return userlist + + def createChat( self ): + """ Creates and registers a new private chat, returns the ID of the newly created chat. """ + self.lastChatID += 1 + chat = HLChat( self.lastChatID ) + self.chats[self.lastChatID] = chat + return chat + + def removeChat( self , id ): + """ Remove the specified private chat. """ + if id in self.chats: + del self.chats[id] + + def getChat( self , id ): + """ Gets the HLChat object for the specified chat ID. """ + if id in self.chats: + return self.chats[id] + return None + + def sendPacket( self , uid , packet ): + """ Sends the specified packet to the specified user. """ + if uid in self.clients: + ( conn , user ) = self.clients[uid] + packet.isIRC = conn.isIRC + if user.local: + conn.writePacket( packet ) + else: + self.linker.forwardPacket( packet, user.uid ) + + def broadcastPacket( self , packet , priv = 0 ): + """ Sends the specified packet to all connected users. If priv is specified, only sends to users with that priv. """ + for ( conn , user ) in self.clients.values(): + packet.isIRC = conn.isIRC + if not user.local: + self.linker.forwardPacket( packet, user.uid ) + elif user.isLoggedIn(): + if priv > 0: + if user.hasPriv( priv ): + conn.writePacket( packet ) + else: + conn.writePacket( packet ) - def dispatchPacket( self , connID , packet ): - """ Called from HLConnection to dispatch a packet to all registered packet handlers. """ - if self.clients.has_key( connID ): - handled = False - ( conn , user ) = self.clients[connID] - for handler in self.handlers: - handled |= handler.handlePacket( self , user , packet ) - if handled == False: - raise HLException , "unknown packet type" + def dispatchPacket( self , connID , packet ): + """ Called from HLConnection to dispatch a packet to all registered packet handlers. """ + if connID in self.clients: + handled = False + ( conn , user ) = self.clients[connID] + for handler in self.handlers: + handled |= handler.handlePacket( self , user , packet ) + if handled == False: + raise HLException("unknown packet type") - #def returnClients( self ): - # """ For irc :p """ - # return self.clients - # DELETEME i think its dead code!! + #def returnClients( self ): + # """ For irc :p """ + # return self.clients + # DELETEME i think its dead code!! - def logEvent( self , typeInt , msg , user = None ): - """ Logs an event. If user is specified, the event will be logged with the users nickname, login, and IP address. """ - login = "" - nickname = "" - ip = "" - if user != None: - login = user.account.login - nickname = user.nick - ip = user.ip - typeStr = str(typeInt) - try: - typeStr = LOG_TYPE_STR_MAP[typeInt] - except KeyError: - pass - # format as \t\t\t\t - # this is the "message" for the FileLogger - fmt = "%s\t%s\t%s\t%s\t%s" - if type == LOG_TYPE_ERROR: - self.log.error( fmt, typeStr, msg, login, nickname, ip ) - elif type == LOG_TYPE_DEBUG: - self.log.debug( fmt, typeStr, msg, login, nickname, ip ) - else: - self.log.info( fmt, typeStr, msg, login, nickname, ip ) - - def updateAccounts( self , acct ): - """ Updates the account information for all current users with login matching that of the specified HLAccount. """ - for ( conn , user ) in self.clients.values(): - if user.isLoggedIn() and ( user.account.login.upper() == acct.login.upper() ): - user.account.copyFrom( acct ) - self.dispatchPacket( user.uid , HLPacket( HTLC_HDR_USER_CHANGE ) ) + def logEvent( self , typeInt , msg , user = None ): + """ Logs an event. If user is specified, the event will be logged with the users nickname, login, and IP address. """ + login = "" + nickname = "" + ip = "" + if user != None: + login = user.account.login + nickname = user.nick + ip = user.ip + typeStr = str(typeInt) + try: + typeStr = LOG_TYPE_STR_MAP[typeInt] + except KeyError: + pass + # format as \t\t\t\t + # this is the "message" for the FileLogger + fmt = "%s\t%s\t%s\t%s\t%s" + if type == LOG_TYPE_ERROR: + self.log.error( fmt, typeStr, msg, login, nickname, ip ) + elif type == LOG_TYPE_DEBUG: + self.log.debug( fmt, typeStr, msg, login, nickname, ip ) + else: + self.log.info( fmt, typeStr, msg, login, nickname, ip ) + + def updateAccounts( self , acct ): + """ Updates the account information for all current users with login matching that of the specified HLAccount. """ + for ( conn , user ) in self.clients.values(): + if user.isLoggedIn() and ( user.account.login.upper() == acct.login.upper() ): + user.account.copyFrom( acct ) + self.dispatchPacket( user.uid , HLPacket( HTLC_HDR_USER_CHANGE ) ) diff --git a/server/HLServerLinkage.py b/server/HLServerLinkage.py index 5741f8a..a7e1db7 100644 --- a/server/HLServerLinkage.py +++ b/server/HLServerLinkage.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import +from __future__ import print_function from twisted.internet import reactor from twisted.internet.protocol import Protocol , Factory , ClientCreator from shared.HLProtocol import * @@ -23,7 +25,7 @@ def connectionMade( self ): self.factory.linkEstablished( self ) def connectionLost( self, reason ): - print "link connection lost" + print("link connection lost") def dataReceived( self, data ): self.buffer += data @@ -44,11 +46,11 @@ def fixPacket( self, packet ): for obj in packet.objs: if obj.type == DATA_UID: remoteUID = unpack( "!H" , obj.data )[0] - if self.remoteToLocal.has_key( remoteUID ): + if remoteUID in self.remoteToLocal: localUID = self.remoteToLocal[remoteUID] obj.data = pack( "!H" , localUID ) else: - print "ERROR: unable to map remote UID [%d]" % remoteUID + print("ERROR: unable to map remote UID [%d]" % remoteUID) def handleLinkPacket( self, packet ): if packet.type == HTLS_HDR_LINK_LOGIN: @@ -71,7 +73,7 @@ def handleLinkPacket( self, packet ): # a user left on the remote server user = HLUser() if user.parse( packet.getBinary(DATA_USER) ) > 0: - if self.remoteToLocal.has_key( user.uid ): + if user.uid in self.remoteToLocal: localUID = self.remoteToLocal[user.uid] self.factory.server.removeRemoteUser( localUID ) elif packet.type == HTLS_HDR_LINK_PACKET: @@ -82,17 +84,17 @@ def handleLinkPacket( self, packet ): self.fixPacket( localPacket ) self.factory.server.sendPacket( localUID, localPacket ) else: - print "ERROR: unknown link packet type" + print("ERROR: unknown link packet type") def forwardPacketData( self, data, uid ): - if self.localToRemote.has_key( uid ): + if uid in self.localToRemote: remoteUID = self.localToRemote[uid] fwdPacket = HLPacket( HTLS_HDR_LINK_PACKET ) fwdPacket.addNumber( DATA_UID, remoteUID ) fwdPacket.addBinary( DATA_PACKET, data ) self.transport.write( fwdPacket.flatten() ) else: - print "ERROR: unable to forward packet to local UID %d" % uid + print("ERROR: unable to forward packet to local UID %d" % uid) class HLServerLinker( Factory ): @@ -102,15 +104,15 @@ def __init__( self, server ): reactor.listenTCP( LINK_PORT, self ) def buildProtocol( self, addr ): - print "got link connection from %s" % addr.host + print("got link connection from %s" % addr.host) return LinkConnection( self ) def linkEstablished( self, link ): - print "added link" + print("added link") self.links.append( link ) def link( self, addr, port ): - print "linking to %s:%d" % (addr,port) + print("linking to %s:%d" % (addr,port)) c = ClientCreator( reactor, LinkConnection, self ) c.connectTCP( addr, port ) diff --git a/server/HLTracker.py b/server/HLTracker.py index 063b102..293809d 100644 --- a/server/HLTracker.py +++ b/server/HLTracker.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from twisted.internet import reactor from twisted.internet.protocol import DatagramProtocol from config import * diff --git a/server/HLWebServices.py b/server/HLWebServices.py index 244f017..3bda53b 100644 --- a/server/HLWebServices.py +++ b/server/HLWebServices.py @@ -1,8 +1,9 @@ +from __future__ import absolute_import from twisted.web import xmlrpc , server from twisted.internet import reactor from shared.HLTypes import * from config import * -from xmlrpclib import Binary +from six.moves.xmlrpc_client import Binary import time class HLWebServices( xmlrpc.XMLRPC ): @@ -16,7 +17,7 @@ def __init__( self , hlserver ): def xmlrpc_getServerUptime( self ): """ Returns the server uptime in seconds. """ - return long( time.time() - self.server.startTime ) + return int( time.time() - self.server.startTime ) def xmlrpc_getUserlist( self ): """ Returns a list of online users. Each entry is a dictionary containing user information. """ diff --git a/server/database/MySQLDatabase.py b/server/database/MySQLDatabase.py index d680d60..ba6720b 100644 --- a/server/database/MySQLDatabase.py +++ b/server/database/MySQLDatabase.py @@ -1,7 +1,10 @@ +from __future__ import absolute_import +from __future__ import print_function from server.HLDatabase import HLDatabase from shared.HLTypes import * from config import * import MySQLdb +from six.moves import range class MySQLDatabase (HLDatabase): """ MySQL-based implementation of HLDatabase. """ @@ -21,7 +24,7 @@ def loadAccount( self , login ): def saveAccount( self , acct ): cur = self.db.cursor() - if acct.id > 0L: + if acct.id > 0: cur.execute( "UPDATE accounts SET password = %s , name = %s , privs = %s , fileRoot = %s WHERE id = %s" , \ ( acct.password , acct.name , acct.privs , acct.fileRoot , acct.id ) ) else: @@ -59,7 +62,7 @@ def loadNewsPosts( self , limit = 0 ): def saveNewsPost( self , post ): cur = self.db.cursor() - if post.id > 0L: + if post.id > 0: cur.execute( "UPDATE news SET nick = %s , login = %s , post = %s , date = %s WHERE id = %s" , ( post.nick , post.login , post.post , post.date , post.id ) ) else: cur.execute( "INSERT INTO news ( nick , login , post , date ) VALUES ( %s , %s , %s , %s )" , ( post.nick , post.login , post.post , post.date ) ) @@ -72,7 +75,7 @@ def checkBanlist( self , addr ): cur = self.db.cursor() num = cur.execute( "SELECT reason FROM banlist WHERE address = %s" , addr ) except: - print "mysql connection lost. check that mysql is up. reconnecting now." + print("mysql connection lost. check that mysql is up. reconnecting now.") cur = self.db.cursor() self.db = MySQLdb.connect( host = DB_HOST , user = DB_USER , passwd = DB_PASS , db = DB_NAME ) num = cur.execute( "SELECT reason FROM banlist WHERE address = %s" , addr ) @@ -87,7 +90,7 @@ def logEvent( self , type , event , login = "" , nick = "" , ip = "" ): cur.execute( "INSERT INTO log ( type , login , nick , ip , entry , date ) VALUES ( %s , %s , %s , %s , %s , NOW() )" , ( type , login , nick , ip , event ) ) cur.close() except: - print "mysql connection lost. check that mysql is up. reconnecting now." + print("mysql connection lost. check that mysql is up. reconnecting now.") cur = self.db.cursor() self.db = MySQLdb.connect( host = DB_HOST , user = DB_USER , passwd = DB_PASS , db = DB_NAME ) cur.execute( "INSERT INTO log ( type , login , nick , ip , entry , date ) VALUES ( %s , %s , %s , %s , %s , NOW() )" , ( type , login , nick , ip , event ) ) diff --git a/server/database/TextDatabase.py b/server/database/TextDatabase.py index 46ec3ff..fda1404 100644 --- a/server/database/TextDatabase.py +++ b/server/database/TextDatabase.py @@ -1,9 +1,11 @@ +from __future__ import absolute_import from server.HLDatabase import HLDatabase from shared.HLTypes import * from config import * from datetime import datetime from os import mkdir , listdir , sep import re +from six.moves import range class TextDatabase (HLDatabase): """ Text-based implementation of HLDatabase. """ @@ -29,7 +31,7 @@ def loadAccount( self , login ): """ Creates a new HLAccount object and loads information for the specified login into it. Returns None if unsuccessful. """ acct = None try: - fp = file( self.accountsFile , "r" ) + fp = open( self.accountsFile , "r" ) except IOError: return acct for l in fp.readlines(): @@ -37,7 +39,7 @@ def loadAccount( self , login ): acct = HLAccount( login ) try: ( acct.id , acct.password , acct.name , acct.privs , acct.fileRoot ) = l.rstrip( "\n" ).split( "\t" )[1:6] - ( acct.id , acct.privs ) = ( int( acct.id ) , long( acct.privs ) ) + ( acct.id , acct.privs ) = ( int( acct.id ) , int( acct.privs ) ) break except ValueError: return None @@ -47,12 +49,12 @@ def loadAccount( self , login ): def saveAccount( self , acct ): """ Saves the specified HLAccount object to the database. If the HLAccount has a non-zero ID, the information is updated, otherwise a new account is inserted. """ try: - fp = file( self.accountsFile , "r" ) + fp = open( self.accountsFile , "r" ) lines = fp.readlines() fp.close() except IOError: lines = [] - if acct.id > 0L: + if acct.id > 0: # Finds the account lines that corresponds to the provided ID and updates the account's info. found = False for l in range( len( lines ) ): @@ -68,7 +70,7 @@ def saveAccount( self , acct ): return False if not found: return False - fp = file( self.accountsFile , "w" ) + fp = open( self.accountsFile , "w" ) fp.write( "".join( lines ) ) fp.close() else: @@ -87,7 +89,7 @@ def saveAccount( self , acct ): if uid > maxuid: maxuid = uid lines.append( "%s\t%s\t%s\t%s\t%s\t%s\t0\t0\t0000-00-00 00:00:00\n" % ( acct.login , int( maxuid ) + 1 , acct.password , acct.name , acct.privs , acct.fileRoot ) ) - fp = file( self.accountsFile , "w" ) + fp = open( self.accountsFile , "w" ) fp.write( "".join( lines ) ) fp.close() return True @@ -95,7 +97,7 @@ def saveAccount( self , acct ): def deleteAccount( self , login ): """ Deletes an account with the specified login. """ try: - fp = file( self.accountsFile , "r" ) + fp = open( self.accountsFile , "r" ) except IOError: return False ( found , lines ) = ( False , fp.readlines() ) @@ -107,14 +109,14 @@ def deleteAccount( self , login ): break if not found: return False - fp = file( self.accountsFile , "w" ) + fp = open( self.accountsFile , "w" ) fp.write( "".join( lines ) ) fp.close() return True def updateAccountStats( self , login , downloaded , uploaded , setDate = False ): try: - fp = file( self.accountsFile , "r" ) + fp = open( self.accountsFile , "r" ) except IOError: return False ( found , lines ) = ( False , fp.readlines() ) @@ -128,15 +130,15 @@ def updateAccountStats( self , login , downloaded , uploaded , setDate = False ) return False else: if ( downloaded > 0 ) or ( uploaded > 0 ): - acctBytesDown = long( acctBytesDown ) + downloaded - acctBytesUp = long( acctBytesUp ) + uploaded + acctBytesDown = int( acctBytesDown ) + downloaded + acctBytesUp = int( acctBytesUp ) + uploaded if setDate: acctLastLogin = datetime.now().strftime( "%Y-%m-%d %H:%M:%S" ) lines[l] = "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n" % ( acctLogin , acctID , acctPass , acctName , acctPrivs , acctFileRoot , acctBytesDown , acctBytesUp , acctLastLogin ) break if not found: return False - fp = file( self.accountsFile , "w" ) + fp = open( self.accountsFile , "w" ) fp.write( "".join( lines ) ) fp.close() return True @@ -152,7 +154,7 @@ def loadNewsPosts( self , limit = 0 ): files = files[len( files ) - limit:len( files )] for f in files: post = HLNewsPost() - fp = file( "%s%s%s" % ( self.newsDir , sep , f ) , "r" ) + fp = open( "%s%s%s" % ( self.newsDir , sep , f ) , "r" ) ( post.id , post.date , post.login , post.nick ) = fp.readline().rstrip( "\n" ).split( "\t" ) post.post = "".join( fp.readlines() ) fp.close() @@ -168,10 +170,10 @@ def saveNewsPost( self , post ): maxid = int( self.regexNewsID.match( listdir( "%s%s" % ( self.newsDir , sep ) )[-1] ).group() ) except: maxid = 0 - if post.id > 0L: + if post.id > 0: maxid = post.id - 1 else: - fp = file( "%s%s%s.txt" % ( self.newsDir , sep , maxid + 1 ) , "w" ) + fp = open( "%s%s%s.txt" % ( self.newsDir , sep , maxid + 1 ) , "w" ) fp.write( "%s\t%s\t%s\t%s\n%s" % ( str( maxid + 1 ) , post.date , post.login , post.nick , post.post ) ) fp.close() return True @@ -179,7 +181,7 @@ def saveNewsPost( self , post ): def checkBanlist( self , addr ): reason = None try: - fp = file( self.banlistFile , "r" ) + fp = open( self.banlistFile , "r" ) except: return reason for l in fp.readlines(): @@ -199,7 +201,7 @@ def logEvent( self , type , event , login = "" , nick = "" , ip = "" ): currentl no DEBUG messages available anyways, so it's redundant. """ return - fp = file( self.logFile , "a" ) + fp = open( self.logFile , "a" ) eventType = "???" try: eventType = self.logTypes[type] diff --git a/server/handlers/AcctHandler.py b/server/handlers/AcctHandler.py index de955ee..585e74a 100644 --- a/server/handlers/AcctHandler.py +++ b/server/handlers/AcctHandler.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from shared.HLProtocol import * from shared.HLTypes import * from config import * @@ -20,9 +21,9 @@ def handleAccountRead( self , server , user , packet ): acct = server.database.loadAccount( login ) if not user.hasPriv( PRIV_READ_USERS ): - raise HLException , "You cannot read accounts." + raise HLException("You cannot read accounts.") if acct == None: - raise HLException , "Error loading account." + raise HLException("Error loading account.") reply = HLPacket( HTLS_HDR_TASK , packet.seq ) reply.addString( DATA_LOGIN , HLEncode( acct.login ) ) @@ -39,9 +40,9 @@ def handleAccountModify( self , server , user , packet ): acct = server.database.loadAccount( login ) if not user.hasPriv( PRIV_MODIFY_USERS ): - raise HLException , "You cannot modify accounts." + raise HLException("You cannot modify accounts.") if acct == None: - raise HLException , "Invalid account." + raise HLException("Invalid account.") acct.name = name acct.privs = privs @@ -59,9 +60,9 @@ def handleAccountCreate( self , server , user , packet ): privs = packet.getNumber( DATA_PRIVS , 0 ) if not user.hasPriv( PRIV_CREATE_USERS ): - raise HLException , "You cannot create accounts." + raise HLException("You cannot create accounts.") if server.database.loadAccount( login ) != None: - raise HLException , "Login already exists." + raise HLException("Login already exists.") acct = HLAccount( login ) acct.password = md5( passwd ).hexdigest() @@ -75,8 +76,8 @@ def handleAccountCreate( self , server , user , packet ): def handleAccountDelete( self , server , user , packet ): login = HLEncode( packet.getString( DATA_LOGIN , "" ) ) if not user.hasPriv( PRIV_DELETE_USERS ): - raise HLException , "You cannot delete accounts." + raise HLException("You cannot delete accounts.") if server.database.deleteAccount( login ) < 1: - raise HLException , "Error deleting account." + raise HLException("Error deleting account.") server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) server.logEvent( LOG_TYPE_ACCOUNT , "Deleted account %s." % login , user ) diff --git a/server/handlers/ChatHandler.py b/server/handlers/ChatHandler.py index 4a7ce0d..16f51f1 100644 --- a/server/handlers/ChatHandler.py +++ b/server/handlers/ChatHandler.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from shared.HLProtocol import * from shared.HLTypes import * from shared.HLUtils import * @@ -37,7 +38,7 @@ def logChat( chat , user ): timestamp = time.localtime() fname = "%04d-%02d-%02d.txt" % ( timestamp[0] , timestamp[1] , timestamp[2] ) path = os.path.join( LOG_DIR , fname ) - out = file( path , "a" ) + out = open( path , "a" ) line = "%02d:%02d:%02d\t%s\t%s\t%s\n" % ( timestamp[3] , timestamp[4] , timestamp[5] , user.account.login , user.nick , chat ) out.write( line ) out.close() @@ -112,7 +113,7 @@ def handleChatCreate( self , server , user , packet ): who = server.getUser( uid ) if not user.hasPriv( PRIV_CREATE_CHATS ): - raise HLException , "You cannot create private chats." + raise HLException("You cannot create private chats.") # First, create the new chat, adding the user. chat = server.createChat() @@ -125,7 +126,7 @@ def handleChatCreate( self , server , user , packet ): reply.addString( DATA_NICK , user.nick ) reply.addNumber( DATA_ICON , user.icon ) reply.addNumber( DATA_STATUS , user.status ) - if user.color >= 0L: + if user.color >= 0: reply.addInt32( DATA_COLOR , user.color ) server.sendPacket( user.uid , reply ) @@ -147,9 +148,9 @@ def handleChatInvite( self , server , user , packet ): who = server.getUser( uid ) if who == None: - raise HLException , "Invalid user." + raise HLException("Invalid user.") if chat == None: - raise HLException , "Invalid chat." + raise HLException("Invalid chat.") if uid == user.uid: # Ignore self invitations. return @@ -157,7 +158,7 @@ def handleChatInvite( self , server , user , packet ): # Ignore all invitations after the first. return if not chat.hasUser( user ): - raise HLException , "You are not in this chat." + raise HLException("You are not in this chat.") if chat.hasUser( who ): # The specified user is already in the chat. return @@ -188,9 +189,9 @@ def handleChatJoin( self , server , user , packet ): chat = server.getChat( ref ) if chat == None: - raise HLException , "Invalid chat." + raise HLException("Invalid chat.") if not chat.hasInvite( user ): - raise HLException , "You were not invited to this chat." + raise HLException("You were not invited to this chat.") # Send a join packet to everyone in the chat. join = HLPacket( HTLS_HDR_CHAT_USER_CHANGE ) @@ -199,7 +200,7 @@ def handleChatJoin( self , server , user , packet ): join.addString( DATA_NICK , user.nick ) join.addNumber( DATA_ICON , user.icon ) join.addNumber( DATA_STATUS , user.status ) - if user.color >= 0L: + if user.color >= 0: join.addInt32( DATA_COLOR , user.color ) for u in chat.users: server.sendPacket( u.uid , join ) diff --git a/server/handlers/FileHandler.py b/server/handlers/FileHandler.py index 6ebc4a7..d21645c 100644 --- a/server/handlers/FileHandler.py +++ b/server/handlers/FileHandler.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from shared.HLProtocol import * from shared.HLTypes import * from config import * @@ -67,15 +68,15 @@ def handleFileList( self , server , user , packet ): path = buildPath( user.account.fileRoot , dir ) if not os.path.exists( path ): - raise HLException , "The specified directory does not exist." + raise HLException("The specified directory does not exist.") if not os.path.isdir( path ): - raise HLException , "The specified path is not a directory." + raise HLException("The specified path is not a directory.") if ( not user.hasPriv( PRIV_VIEW_DROPBOXES ) ) and ( path.upper().find( "DROP BOX" ) >= 0 ): - raise HLException , "You are not allowed to view drop boxes." + raise HLException("You are not allowed to view drop boxes.") fn = path.split("/")[-1] # gets folder name kang #beware of non exact matches!! FIXME if (path.upper().find("DROP BOX") >= 0) and (fn.upper()[0:4] != "DROP") and (fn.upper().find(user.account.login.upper()) < 0): - raise HLException, "Sorry, this is not your dropbox. You are not allowed to view it" + raise HLException("Sorry, this is not your dropbox. You are not allowed to view it") reply = HLPacket( HTLS_HDR_TASK , packet.seq ) files = os.listdir( path ) @@ -101,9 +102,9 @@ def handleFileDownload( self , server , user , packet ): path = buildPath( user.account.fileRoot , dir , name ) if not user.hasPriv( PRIV_DOWNLOAD_FILES ): - raise HLException , "You are not allowed to download files." + raise HLException("You are not allowed to download files.") if not os.path.exists( path ): - raise HLException , "Specified file does not exist." + raise HLException("Specified file does not exist.") offset = resume.forkOffset( HLCharConst( "DATA" ) ) xfer = server.fileserver.addDownload( user.uid , path , offset ) @@ -121,21 +122,21 @@ def handleFileUpload( self , server , user , packet ): options = packet.getNumber( DATA_XFEROPTIONS , 0 ) if not user.hasPriv( PRIV_UPLOAD_FILES ): - raise HLException , "You are not allowed to upload files." + raise HLException("You are not allowed to upload files.") path = buildPath( user.account.fileRoot , dir , name ) if os.path.exists( path ): # If this path exists, theres already a complete file. - raise HLException , "File already exists." + raise HLException("File already exists.") if ( not user.hasPriv( PRIV_UPLOAD_ANYWHERE ) ) and ( path.upper().find( "UPLOAD" ) < 0 ): - raise HLException , "You must upload to an upload directory." + raise HLException("You must upload to an upload directory.") # Make sure we have enough disk space to accept the file. upDir = buildPath( user.account.fileRoot , dir ) info = os.statvfs( upDir ) free = info[F_BAVAIL] * info[F_FRSIZE] if size > free: - raise HLException , "Insufficient disk space." + raise HLException("Insufficient disk space.") # All uploads in progress should have this extension. path += ".hpf" @@ -157,9 +158,9 @@ def handleFileDelete( self , server , user , packet ): path = buildPath( user.account.fileRoot , dir , name ) if not user.hasPriv( PRIV_DELETE_FILES ): - raise HLException , "You are not allowed to delete files." + raise HLException("You are not allowed to delete files.") if not os.path.exists( path ): - raise HLException , "Specified file does not exist." + raise HLException("Specified file does not exist.") if os.path.isdir( path ): # First, recursively delete everything inside the directory. @@ -181,11 +182,11 @@ def handleFolderCreate( self , server , user , packet ): path = buildPath( user.account.fileRoot , dir , name ) if not user.hasPriv( PRIV_CREATE_FOLDERS ): - raise HLException , "You are not allowed to create folders." + raise HLException("You are not allowed to create folders.") if os.path.exists( path ): - raise HLException , "Specified directory/file already exists." + raise HLException("Specified directory/file already exists.") - os.mkdir( path , 0755 ) + os.mkdir( path , 0o755 ) server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) def handleFileMove( self , server , user , packet ): @@ -197,11 +198,11 @@ def handleFileMove( self , server , user , packet ): newPath = buildPath( user.account.fileRoot , newDir , name ) if not user.hasPriv( PRIV_MOVE_FILES ): - raise HLException , "You are not allowed to move files." + raise HLException("You are not allowed to move files.") if not os.path.exists( oldPath ): - raise HLException , "Invalid file or directory." + raise HLException("Invalid file or directory.") if os.path.exists( newPath ): - raise HLException , "The specified file already exists." + raise HLException("The specified file already exists.") os.rename( oldPath , newPath ) server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) @@ -212,7 +213,7 @@ def handleFileGetInfo( self , server , user , packet ): path = buildPath( user.account.fileRoot , dir , name ) if not os.path.exists( path ): - raise HLException , "No such file or directory." + raise HLException("No such file or directory.") info = HLPacket( HTLS_HDR_TASK , packet.seq ) info.addString( DATA_FILENAME , name ) @@ -227,15 +228,15 @@ def handleFileSetInfo( self , server , user , packet ): newName = packet.getString( DATA_NEWFILE , oldName ) if ( oldName != newName ) and ( not user.hasPriv( PRIV_RENAME_FILES ) ): - raise HLException , "You cannot rename files." + raise HLException("You cannot rename files.") oldPath = buildPath( user.account.fileRoot , dir , oldName ) newPath = buildPath( user.account.fileRoot , dir , newName ) if not os.path.exists( oldPath ): - raise HLException , "Invalid file or directory." + raise HLException("Invalid file or directory.") if os.path.exists( newPath ): - raise HLException , "The specified file already exists." + raise HLException("The specified file already exists.") os.rename( oldPath , newPath ) server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) diff --git a/server/handlers/IconHandler.py b/server/handlers/IconHandler.py index f390e4e..45d0870 100644 --- a/server/handlers/IconHandler.py +++ b/server/handlers/IconHandler.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from shared.HLProtocol import * from shared.HLTypes import * from struct import pack @@ -25,7 +26,7 @@ def handleIconSet( self , server , user , packet ): user.gif = packet.getBinary( DATA_GIFICON , "" ) if len( user.gif ) > MAX_GIF_SIZE: user.gif = "" - raise HLException , "GIF icon too large." + raise HLException("GIF icon too large.") server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) change = HLPacket( HTLS_HDR_ICON_CHANGE ) change.addNumber( DATA_UID , user.uid ) @@ -40,4 +41,4 @@ def handleIconGet( self , server , user , packet ): icon.addBinary( DATA_GIFICON , info.gif ) server.sendPacket( user.uid , icon ) else: - raise HLException , "Invalid user." + raise HLException("Invalid user.") diff --git a/server/handlers/NewsHandler.py b/server/handlers/NewsHandler.py index 1265579..c4b54ca 100644 --- a/server/handlers/NewsHandler.py +++ b/server/handlers/NewsHandler.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from shared.HLProtocol import * from shared.HLTypes import * from config import * @@ -28,7 +29,7 @@ def handleNewsGet( self , server , user , packet ): news.addString( DATA_STRING , str ) server.sendPacket( user.uid , news ) else: - raise HLException , "You are not allowed to read the news." + raise HLException("You are not allowed to read the news.") def handleNewsPost( self , server , user , packet ): str = packet.getString( DATA_STRING , "" ) @@ -41,4 +42,4 @@ def handleNewsPost( self , server , user , packet ): server.broadcastPacket( notify , PRIV_READ_NEWS ) server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) else: - raise HLException , "You are not allowed to post news." + raise HLException("You are not allowed to post news.") diff --git a/server/handlers/UserHandler.py b/server/handlers/UserHandler.py index 07c63ec..0701002 100644 --- a/server/handlers/UserHandler.py +++ b/server/handlers/UserHandler.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from shared.HLProtocol import * from shared.HLUtils import * from shared.HLTypes import * @@ -28,22 +29,22 @@ def handleUserDisconnected( self , server , user ): def handleLogin( self , server , user , packet ): if user.isLoggedIn(): - raise HLException , ( "You are already logged in." , False ) + raise HLException( "You are already logged in." , False) login = HLEncode( packet.getString( DATA_LOGIN , HLEncode( "guest" ) ) ) password = HLEncode( packet.getString( DATA_PASSWORD , "" ) ) reason = server.checkForBan( user.ip ) if reason != None: - raise HLException , ( "You are banned: %s" % reason , True ) + raise HLException( "You are banned: %s" % reason , True) user.account = server.database.loadAccount( login ) if user.account == None: - raise HLException , ( "Login is incorrect." , True ) + raise HLException( "Login is incorrect." , True) if user.account.password != md5( password ).hexdigest(): user.nick = packet.getString( DATA_NICK , "unnamed" ) server.logEvent( LOG_TYPE_LOGIN , "Login failure" , user ) - raise HLException , ( "Password is incorrect." , True ) + raise HLException( "Password is incorrect." , True) if user.account.fileRoot == "": user.account.fileRoot = FILE_ROOT @@ -108,7 +109,7 @@ def handleUserChange( self , server , user , packet ): change.addNumber( DATA_ICON , user.icon ) change.addNumber( DATA_STATUS , user.status ) change.addString ( DATA_IRC_OLD_NICK , oldnick ) - if user.color >= 0L: + if user.color >= 0: change.addInt32( DATA_COLOR , user.color ) server.broadcastPacket( change ) @@ -124,12 +125,12 @@ def handleUserInfo( self , server , user , packet ): u = server.getUser( uid ) if not user.hasPriv( PRIV_USER_INFO ) and ( uid != user.uid ): - raise HLException , "You cannot view user information." + raise HLException("You cannot view user information.") if u == None: - raise HLException , "Invalid user." + raise HLException("Invalid user.") # Format the user's idle time. - secs = long( time.time() - u.lastPacketTime ) + secs = int( time.time() - u.lastPacketTime ) days = secs / 86400 secs -= ( days * 86400 ) hours = secs / 3600 @@ -167,9 +168,9 @@ def handleMessage( self , server , user , packet ): str = packet.getString( DATA_STRING , "" ) if not user.hasPriv( PRIV_SEND_MESSAGES ): - raise HLException , "You are not allowed to send messages." + raise HLException("You are not allowed to send messages.") if server.getUser( uid ) == None: - raise HLException , "Invalid user." + raise HLException("Invalid user.") msg = HLPacket( HTLS_HDR_MSG ) msg.addNumber( DATA_UID , user.uid ) @@ -184,11 +185,11 @@ def handleUserKick( self , server , user , packet ): who = server.getUser( uid ) if not user.hasPriv( PRIV_KICK_USERS ): - raise HLException , "You are not allowed to disconnect users." + raise HLException("You are not allowed to disconnect users.") if who == None: - raise HLException , "Invalid user." + raise HLException("Invalid user.") if who.account.login != user.account.login and who.hasPriv( PRIV_KICK_PROTECT ): - raise HLException , "%s cannot be disconnected." % who.nick + raise HLException("%s cannot be disconnected." % who.nick) action = "Kicked" if ban > 0: @@ -202,7 +203,7 @@ def handleUserKick( self , server , user , packet ): def handleBroadcast( self , server , user , packet ): str = packet.getString( DATA_STRING , "" ) if not user.hasPriv( PRIV_BROADCAST ): - raise HLException , "You cannot broadcast messages." + raise HLException("You cannot broadcast messages.") broadcast = HLPacket( HTLS_HDR_BROADCAST ) broadcast.addString( DATA_STRING , str ) server.broadcastPacket( broadcast ) diff --git a/server/handlers/commands/0wn.py b/server/handlers/commands/0wn.py index 2819930..0490324 100644 --- a/server/handlers/commands/0wn.py +++ b/server/handlers/commands/0wn.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from shared.HLProtocol import * def handle( server , user , arg , ref): diff --git a/server/handlers/commands/away.py b/server/handlers/commands/away.py index 499912f..5ba0abb 100644 --- a/server/handlers/commands/away.py +++ b/server/handlers/commands/away.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from shared.HLProtocol import * def handle( server , user , args , ref ): diff --git a/server/handlers/commands/broadcast.py b/server/handlers/commands/broadcast.py index 1516c4f..3296da3 100644 --- a/server/handlers/commands/broadcast.py +++ b/server/handlers/commands/broadcast.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from shared.HLProtocol import * def handle( server , user , arg , ref ): diff --git a/server/handlers/commands/color.py b/server/handlers/commands/color.py index c3c352e..c4b9843 100644 --- a/server/handlers/commands/color.py +++ b/server/handlers/commands/color.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from shared.HLProtocol import * def handle( server , user , arg , ref ): if len( arg ) > 0: diff --git a/server/handlers/commands/find.py b/server/handlers/commands/find.py index 912c0d7..3955088 100644 --- a/server/handlers/commands/find.py +++ b/server/handlers/commands/find.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from shared.HLProtocol import * import os diff --git a/server/handlers/commands/me.py b/server/handlers/commands/me.py index 9fcbb6f..04030e2 100644 --- a/server/handlers/commands/me.py +++ b/server/handlers/commands/me.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from shared.HLProtocol import * def handle( server , user , args , ref ): diff --git a/server/handlers/commands/news.py b/server/handlers/commands/news.py index 103781c..052c135 100644 --- a/server/handlers/commands/news.py +++ b/server/handlers/commands/news.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from shared.HLProtocol import * from server.handlers.NewsHandler import * diff --git a/server/handlers/commands/uptime.py b/server/handlers/commands/uptime.py index 667b47f..03dd6ec 100644 --- a/server/handlers/commands/uptime.py +++ b/server/handlers/commands/uptime.py @@ -1,8 +1,9 @@ +from __future__ import absolute_import from shared.HLProtocol import * import time def handle( server , user , args , ref ): - secs = long( time.time() - server.startTime ) + secs = int( time.time() - server.startTime ) days = secs / 86400 secs -= ( days * 86400 ) hours = secs / 3600 diff --git a/server/handlers/commands/xfers.py b/server/handlers/commands/xfers.py index f0daf00..81713ef 100644 --- a/server/handlers/commands/xfers.py +++ b/server/handlers/commands/xfers.py @@ -1,9 +1,10 @@ +from __future__ import absolute_import from shared.HLProtocol import * def handle( server , user , args , ref ): if user.hasPriv( PRIV_USER_INFO ): str = "" - if len( server.fileserver.transfers.values() ) == 0: + if len( list(server.fileserver.transfers.values()) ) == 0: str += "\r > No file transfers in progress." else: str += "\r > File transfers:" diff --git a/shared/HLProtocol.py b/shared/HLProtocol.py index e3bcc0d..2661f20 100644 --- a/shared/HLProtocol.py +++ b/shared/HLProtocol.py @@ -1,7 +1,10 @@ +from __future__ import absolute_import +from __future__ import print_function from struct import * from config import * import random import re +from six.moves import range def buildTrackerClientPacket(name, description, port, users): """Builds an info packet incorporating the specified name @@ -13,421 +16,421 @@ def buildTrackerClientPacket(name, description, port, users): name, pack('b', len(description)), description) def ircCheckUserNick( user ): - """ Check for nick conformance to IRC standards and rename a correct one """ - nickname = "" - nickname = user.nick.replace(" ", "") - nickname = re.search('^([0-9-A-z]*)', nickname).group(0) - nickname = str(user.uid)+"_"+nickname - return nickname + """ Check for nick conformance to IRC standards and rename a correct one """ + nickname = "" + nickname = user.nick.replace(" ", "") + nickname = re.search('^([0-9-A-z]*)', nickname).group(0) + nickname = str(user.uid)+"_"+nickname + return nickname def HLCharConst( str ): - """ Returns the numeric equivalent of a 4-character string (OSType in classic Mac OS). - Used for file types, creator codes, and magic numbers. """ - if len( str ) != 4: - return 0 - return 0L + ( ord( str[0] ) << 24 ) + ( ord( str[1] ) << 16 ) + ( ord( str[2] ) << 8 ) + ord( str[3] ) + """ Returns the numeric equivalent of a 4-character string (OSType in classic Mac OS). + Used for file types, creator codes, and magic numbers. """ + if len( str ) != 4: + return 0 + return 0 + ( ord( str[0] ) << 24 ) + ( ord( str[1] ) << 16 ) + ( ord( str[2] ) << 8 ) + ord( str[3] ) def HLEncode( str ): - """ Encodes a string based on hotline specifications; basically just - XORs each byte of the string. Used for logins and passwords. """ - if str != None: - out = "" - for k in range( len( str ) ): - out += chr( 255 - ord( str[k] ) ) - return out - return None + """ Encodes a string based on hotline specifications; basically just + XORs each byte of the string. Used for logins and passwords. """ + if str != None: + out = "" + for k in range( len( str ) ): + out += chr( 255 - ord( str[k] ) ) + return out + return None def isPingType( type ): - """ Returns True if the packet type can be considered a ping packet, i.e. - the server should not consider it when determining idle behavior. """ - if type == HTLC_HDR_PING: - return True - elif type == HTLC_HDR_USER_LIST: - return True - elif type == HTLC_HDR_USER_INFO: - return True - elif type == HTLC_HDR_ICON_GET: - return True - else: - return False + """ Returns True if the packet type can be considered a ping packet, i.e. + the server should not consider it when determining idle behavior. """ + if type == HTLC_HDR_PING: + return True + elif type == HTLC_HDR_USER_LIST: + return True + elif type == HTLC_HDR_USER_INFO: + return True + elif type == HTLC_HDR_ICON_GET: + return True + else: + return False class HLObject: - def __init__( self , type , data ): - self.type = type - self.data = data - - def __str__( self ): - return "HLObject [type=%d,size=%d]" % ( self.type , len( self.data ) ) - - def getObjects( self, type ): - objs = [] - for obj in self.objs: - if obj.type == type: - objs.append( obj ) - return objs - - def flatten( self ): - """ Returns a flattened, byte-swapped string for this hotline object. """ - return pack( "!2H" , self.type , len( self.data ) ) + self.data + def __init__( self , type , data ): + self.type = type + self.data = data + + def __str__( self ): + return "HLObject [type=%d,size=%d]" % ( self.type , len( self.data ) ) + + def getObjects( self, type ): + objs = [] + for obj in self.objs: + if obj.type == type: + objs.append( obj ) + return objs + + def flatten( self ): + """ Returns a flattened, byte-swapped string for this hotline object. """ + return pack( "!2H" , self.type , len( self.data ) ) + self.data class HLPacket: - def __init__( self , type = 0 , seq = 0 , flags = 0 , isIRC = 0 ): - self.objs = [] - self.type = type - self.seq = seq - self.flags = flags - self.isIRC = isIRC - self.server = None - self.irctrap = "" - self.connID = 0 - - def __str__( self ): - s = "HLPacket [type=%x,seq=%d,flags=%d]" % ( self.type , self.seq , self.flags ) - for obj in self.objs: - s += "\n " + str( obj ) - return s - - def parse( self , data ): - """ Tries to parse an entire packet from the data passed in. If successful, - returns the number of bytes parsed, otherwise returns 0. """ - if self.isIRC: - if len( data ) == 0: - return 0 - line = data.split( "\n" )[0] - if line == "": - line = data.split( "\r" )[0] - cmd = line.split( " " )[0].upper() - if cmd == "NICK": - self.type = HTLC_HDR_USER_CHANGE - if line.split( " " )[1].startswith( ":" ): - self.addString( DATA_NICK , line.split( " " )[1][1:]) - else: - self.addString( DATA_NICK , line.split( " " )[1] ) - self.addNumber( DATA_ICON , 500 ) - self.addNumber( DATA_COLOR , 1 ) - - elif cmd == "PING": - self.type = HTLC_HDR_PING - - elif cmd.startswith("LAGTIME"): - return len( line ) - - elif cmd == "PRIVMSG": - # Chat - if line.split( " " )[1].startswith("#"): - try: - if line.split( " ", 2)[2].startswith( ":" ): - reply = line.split( " " , 2 )[2][1:] - else: - reply = line.split( " " , 2 )[2] - chatid = line.split( " " )[1].replace( "#" , "" ) - if chatid != "public": - chatid = int( chatid ) - else: - chatid = 0 - self.type = HTLC_HDR_CHAT - self.addString( DATA_STRING , reply ) - self.addNumber( DATA_OPTION , 0 ) - self.addNumber( DATA_CHATID , chatid ) - except: - #TODO Handle condition or throw away ? - print "handle that" - # Private Message - else: - # Authentication "bot" - if line.split( " " , 2 )[1] == "loginserv": - self.type = HTLC_HDR_LOGIN - loginStr = line.split(" ", 3)[2] - if loginStr.startswith(":"): - # In IRC private messages not containing space separated text - # are not prefixed with a colon character ":". This is important - # for passwordless login to loginserv, i.e. Guest login. - loginStr = loginStr[1:] - self.addString( DATA_LOGIN , HLEncode( loginStr ) ) - try: - self.addString( DATA_PASSWORD , HLEncode( line.split( " " , 4 )[3] ) ) - except IndexError: - # No password provided, but HL can handle blank passwords, try that. - self.addString(DATA_PASSWORD, HLEncode("")) - print "no password provided.." - else: - try: - uid = int( line.split( " " , 2 )[1].split( "_" , 1 )[0] ) - self.type = HTLC_HDR_MSG - self.addNumber( DATA_UID , uid ) - self.addString( DATA_STRING , line.split( " " , 2 )[2][1:] ) - except: - # Throw an error, needs HLException - print "handle that" - elif cmd == "WHO": - self.type = HTLC_HDR_USER_LIST - - elif cmd == "WHOIS": - try: - uid = int( line.split( " " , 2 )[1].split( "_" , 1 )[0] ) - except: - return 0 - self.type = HTLC_HDR_USER_INFO - self.addNumber( DATA_UID , uid ) - - elif cmd == "KICK": - try: - uid = int( line.split( " " , 2 )[2].split( "_" , 1 )[0] ) - except: - return len( line ) - self.type = HTLC_HDR_KICK - self.addNumber( DATA_UID , uid ) - self.addNumber( DATA_BAN , 0 ) - - elif cmd == "MODE": - return len( line ) - - elif cmd == "JOIN": - #TODO if chat does not exists, send a HTLC_HDR_CHAT_CREATE - try: - chatid = int( line.split( "#" )[1] ) - except: - return len( line ) - self.type = HTLC_HDR_CHAT_JOIN - self.addNumber( DATA_CHATID , chatid ) - - - elif cmd == "PART": - try: - chatid = int( line.split( "#" )[1] ) - except: - return len( line ) - self.type = HTLC_HDR_CHAT_LEAVE - self.addNumber( DATA_CHATID , chatid ) - - elif cmd == "INVITE": - uid = int( line.split( " " , 2 )[1].split( "_" , 1 )[0] ) - chatid = int ( line.split( " " , 3 )[2].replace( "#" , "" ) ) - self.type = HTLC_HDR_CHAT_INVITE - self.addNumber( DATA_CHATID , chatid ) - self.addNumber( DATA_UID , uid ) - - elif cmd == "QUIT": - self.server.removeConnection( self.connID ) - - else: - self.irctrap = cmd - - return len( line ) - # This is the Hotline code now. - else: - if len( data ) < 20: - return 0 - ( self.type , self.seq , self.flags , size , check ) = unpack( "!5L", data[0:20] ) - if ( len( data ) - 20 ) < size: - return 0 - if size >= 2: - pos = 20 - count = unpack( "!H" , data[pos:pos+2] )[0] - pos += 2 - while count > 0: - ( obj_type , obj_size ) = unpack( "!2H", data[pos:pos+4] ) - pos += 4 - obj = HLObject( obj_type , data[pos:pos+obj_size] ) - self.addObject( obj ) - pos += obj_size - count = count - 1 - return 20 + size - - def addObject( self , obj ): - """ Adds a HLObject to the object list. """ - self.objs.append( obj ) - - def addString( self , type , data ): - """ Wraps a string in a HLObject and adds it. """ - obj = HLObject( type , data ) - self.addObject( obj ) - - def addNumber( self , type , data ): - """ Wraps a number in a HLObject, byte-swapping it based - on its magnitude, and adds it. """ - num = long( data ) - packed = "" - if num < ( 1L << 16 ): - packed = pack( "!H" , num ) - elif num < ( 1L << 32 ): - packed = pack( "!L" , num ) - elif num < ( 1L << 64 ): - packed = pack( "!Q" , num ) - obj = HLObject( type , packed ) - self.addObject( obj ) - - def addInt16( self , type , data ): - """ Adds a 16-bit byte-swapped number as a HLObject. """ - num = long( data ) - obj = HLObject( type , pack( "!H" , num ) ) - self.addObject( obj ) - - def addInt32( self , type , data ): - """ Adds a 32-bit byte-swapped number as a HLObject. """ - num = long( data ) - obj = HLObject( type , pack( "!L" , num ) ) - self.addObject( obj ) - - def addInt64( self , type , data ): - """ Adds a 64-bit byte-swapped number as a HLObject. """ - num = long( data ) - obj = HLObject( type , pack( "!Q" , num ) ) - self.addObject( obj ) - - def addBinary( self , type , data ): - """ Functionally equivalent to addString. """ - self.addString( type , data ) - - def getString( self , type , default = None ): - """ Returns a string for the specified object type, or - a default value when the specified type is not present. """ - for obj in self.objs: - if ( obj.type == type ) and ( len( obj.data ) > 0 ): - return obj.data - return default - - def getNumber( self , type , default = None ): - """ Returns a byte-swapped number for the specified object type, or - a default value when the specified type is not present. """ - for obj in self.objs: - if obj.type == type: - if len( obj.data ) == 2: - return unpack( "!H" , obj.data )[0] - elif len( obj.data ) == 4: - return unpack( "!L" , obj.data )[0] - elif len( obj.data ) == 8: - return unpack( "!Q" , obj.data )[0] - return default - - def getBinary( self , type , default = None ): - """ Functionally equivalent to getString. """ - return self.getString( type , default ) - - def flatten( self , user ): - """ Returns a flattened string of this packet and embedded objects. """ - data = "" - if self.isIRC: - if self.type == HTLS_HDR_PING: - data = "PONG :"+IRC_SERVER_NAME+"\r\n" - - elif self.type == HTLS_HDR_CHAT: - try: - chat = self.getString(DATA_STRING).split( ": " , 1 )[1].replace( "\r" , " " ) - except IndexError: - chat = self.getString(DATA_STRING).replace( "\r" , " " ) - try: - ( c , u ) = self.server.clients[self.getNumber( DATA_UID )] - # this should be hanlded already elsewhere but forgot :( - if user.uid == u.uid: - return data - mynick = ircCheckUserNick( u ) - mynick = u.nick.replace( " " , "" ) - except KeyError: - mynick = "PHXD" - chatid = self.getNumber( DATA_CHATID ) - if chatid == None: - channel = "public" - else: - channel = str(chatid) - data = ":"+mynick+" PRIVMSG #"+channel+" :"+chat[1:]+"\r\n" - - elif self.type == HTLS_HDR_MSG: - chat = self.getString( DATA_STRING ) - try: - ( c , u ) = self.server.clients[self.getNumber( DATA_UID )] - mynick = ircCheckUserNick( u ) - myip = u.ip - except KeyError: - mynick = "PHXD" - myip = "127.0.0.1" - data = ":"+mynick+"!~"+mynick+"@"+myip+" PRIVMSG "+user.nick+" :"+chat.replace( "\r" , " " )+"\r\n" - - elif self.type == HTLS_HDR_USER_LEAVE: - ( c, u ) = self.server.clients[self.getNumber( DATA_UID )] - mynick = ircCheckUserNick( u ) - if u.isIRC: - proto = "IRC" - else: - proto = "Hotline" - data = ":"+mynick+"!~"+mynick+"@"+u.ip+" PART #public :Client disconnected from "+proto+"\r\n" - - elif self.type == HTLS_HDR_USER_CHANGE: - ( c, u ) = self.server.clients[self.getNumber( DATA_UID )] - mynick = ircCheckUserNick( u ) - oldnick = self.getString( DATA_IRC_OLD_NICK ) - if not u.valid: # Login ? If so, force join the public channel - data = ":"+mynick+"!~"+mynick+"@"+u.ip+" JOIN :#public\r\n" - else: - if u.nick == oldnick: - data = "NOTICE *: *** "+oldnick+" changed status to "+str( u.status )+"\r\n" - else: - if user.uid == u.uid: - data = ":"+oldnick+"!~"+oldnick+"@"+u.ip+" NICK :"+user.nick+"\r\n" - else: - data = ":"+str( u.uid )+"_"+oldnick.replace( " " , "" )+" NICK "+ircCheckUserNick( u )+"\r\n" - - elif self.type == HTLS_HDR_TASK: - # check for HTLC_HDR_USER_LIST reply: - if self.getBinary( DATA_USER ): - keys = self.server.clients.keys() - keys.sort() - for uid in keys: - ( c , u ) = self.server.clients[uid] - mynick = ircCheckUserNick( u ) - if u.isLoggedIn(): - data += ":"+IRC_SERVER_NAME+" 352 "+mynick+" #public "+mynick+" "+u.ip+" "+IRC_SERVER_NAME+" "+u.account.name.replace( " ", "_" )+"\r\n" - data += ":"+IRC_SERVER_NAME+" 315 "+user.nick+" #public :End of /WHO list.\r\n" - - # HTLC_HDR_USER_INFO then :) - elif self.getString( DATA_NICK ): - uid = self.getNumber( DATA_UID ) - ( c , u ) = self.server.clients[uid] - mynick = ircCheckUserNick( u ) - info = self.getString( DATA_STRING ) - - idle = info.split( "idle: " )[1].split( '\r' )[0] - if u.isIRC: - proto = "IRC" - else: - proto = "Hotline" - - data = ":"+IRC_SERVER_NAME+" 311 "+user.nick+" "+mynick+" ~"+mynick+" "+u.ip+" * :"+u.account.name.replace(" ", "_")+"\r\n" - data += ":"+IRC_SERVER_NAME+" 312 "+user.nick+" "+mynick+" "+IRC_SERVER_NAME+" :http//chatonly.org\r\n" - data += ":"+IRC_SERVER_NAME+" 320 "+user.nick+" "+mynick+" :Using protocol "+proto+"\r\n" - data += ":"+IRC_SERVER_NAME+" 317 "+user.nick+" "+mynick+" "+idle+" 0 :seconds idle, signon time\r\n" - data += ":"+IRC_SERVER_NAME+" 318 "+user.nick+" "+mynick+" :End of /WHOIS list.\r\n" - - elif self.type == HTLS_HDR_CHAT_INVITE: - chatid = self.getNumber( DATA_CHATID) - uid = self.getNumber( DATA_UID ) - ( c , u ) = self.server.clients[uid] - mynick = ircCheckUserNick( u ) - data = ":PHXD PRIVMSG #public :"+mynick+" invites you to join private chat #"+str(chatid)+"\r\n" - elif self.type == HTLS_HDR_CHAT_USER_LEAVE: - chatid = self.getNumber( DATA_CHATID) - uid = self.getNumber( DATA_UID ) - ( c , u ) = self.server.clients[uid] - mynick = ircCheckUserNick( u ) - data = ":"+mynick+"!~"+mynick+"@"+u.ip+" PART #"+str( chatid )+" :Client left channel #"+str( chatid )+"\r\n" - - elif self.type == HTLS_HDR_CHAT_USER_CHANGE: - # Basically this is a JOIN packet for a private chat - chatid = self.getNumber( DATA_CHATID) - uid = self.getNumber( DATA_UID ) - ( c , u ) = self.server.clients[uid] - mynick = ircCheckUserNick( self.getString( DATA_NICK ) ) - data = ":"+mynick+"!~"+mynick+"@"+u.ip+" JOIN :#"+str(chatid)+"\r\n" - - elif self.type == HTLS_HDR_BROADCAST: - data = "NOTICE * :*** BROADCAST: "+self.getString( DATA_STRING )+"\r\n" - - return data - # Normal Hotline processing - else: - for obj in self.objs: - data += obj.flatten() - return pack( "!5L1H" , self.type , self.seq , self.flags , len( data ) + 2 , len( data ) + 2 , len( self.objs ) ) + data + def __init__( self , type = 0 , seq = 0 , flags = 0 , isIRC = 0 ): + self.objs = [] + self.type = type + self.seq = seq + self.flags = flags + self.isIRC = isIRC + self.server = None + self.irctrap = "" + self.connID = 0 + + def __str__( self ): + s = "HLPacket [type=%x,seq=%d,flags=%d]" % ( self.type , self.seq , self.flags ) + for obj in self.objs: + s += "\n " + str( obj ) + return s + + def parse( self , data ): + """ Tries to parse an entire packet from the data passed in. If successful, + returns the number of bytes parsed, otherwise returns 0. """ + if self.isIRC: + if len( data ) == 0: + return 0 + line = data.split( "\n" )[0] + if line == "": + line = data.split( "\r" )[0] + cmd = line.split( " " )[0].upper() + if cmd == "NICK": + self.type = HTLC_HDR_USER_CHANGE + if line.split( " " )[1].startswith( ":" ): + self.addString( DATA_NICK , line.split( " " )[1][1:]) + else: + self.addString( DATA_NICK , line.split( " " )[1] ) + self.addNumber( DATA_ICON , 500 ) + self.addNumber( DATA_COLOR , 1 ) + + elif cmd == "PING": + self.type = HTLC_HDR_PING + + elif cmd.startswith("LAGTIME"): + return len( line ) + + elif cmd == "PRIVMSG": + # Chat + if line.split( " " )[1].startswith("#"): + try: + if line.split( " ", 2)[2].startswith( ":" ): + reply = line.split( " " , 2 )[2][1:] + else: + reply = line.split( " " , 2 )[2] + chatid = line.split( " " )[1].replace( "#" , "" ) + if chatid != "public": + chatid = int( chatid ) + else: + chatid = 0 + self.type = HTLC_HDR_CHAT + self.addString( DATA_STRING , reply ) + self.addNumber( DATA_OPTION , 0 ) + self.addNumber( DATA_CHATID , chatid ) + except: + #TODO Handle condition or throw away ? + print("handle that") + # Private Message + else: + # Authentication "bot" + if line.split( " " , 2 )[1] == "loginserv": + self.type = HTLC_HDR_LOGIN + loginStr = line.split(" ", 3)[2] + if loginStr.startswith(":"): + # In IRC private messages not containing space separated text + # are not prefixed with a colon character ":". This is important + # for passwordless login to loginserv, i.e. Guest login. + loginStr = loginStr[1:] + self.addString( DATA_LOGIN , HLEncode( loginStr ) ) + try: + self.addString( DATA_PASSWORD , HLEncode( line.split( " " , 4 )[3] ) ) + except IndexError: + # No password provided, but HL can handle blank passwords, try that. + self.addString(DATA_PASSWORD, HLEncode("")) + print("no password provided..") + else: + try: + uid = int( line.split( " " , 2 )[1].split( "_" , 1 )[0] ) + self.type = HTLC_HDR_MSG + self.addNumber( DATA_UID , uid ) + self.addString( DATA_STRING , line.split( " " , 2 )[2][1:] ) + except: + # Throw an error, needs HLException + print("handle that") + elif cmd == "WHO": + self.type = HTLC_HDR_USER_LIST + + elif cmd == "WHOIS": + try: + uid = int( line.split( " " , 2 )[1].split( "_" , 1 )[0] ) + except: + return 0 + self.type = HTLC_HDR_USER_INFO + self.addNumber( DATA_UID , uid ) + + elif cmd == "KICK": + try: + uid = int( line.split( " " , 2 )[2].split( "_" , 1 )[0] ) + except: + return len( line ) + self.type = HTLC_HDR_KICK + self.addNumber( DATA_UID , uid ) + self.addNumber( DATA_BAN , 0 ) + + elif cmd == "MODE": + return len( line ) + + elif cmd == "JOIN": + #TODO if chat does not exists, send a HTLC_HDR_CHAT_CREATE + try: + chatid = int( line.split( "#" )[1] ) + except: + return len( line ) + self.type = HTLC_HDR_CHAT_JOIN + self.addNumber( DATA_CHATID , chatid ) + + + elif cmd == "PART": + try: + chatid = int( line.split( "#" )[1] ) + except: + return len( line ) + self.type = HTLC_HDR_CHAT_LEAVE + self.addNumber( DATA_CHATID , chatid ) + + elif cmd == "INVITE": + uid = int( line.split( " " , 2 )[1].split( "_" , 1 )[0] ) + chatid = int ( line.split( " " , 3 )[2].replace( "#" , "" ) ) + self.type = HTLC_HDR_CHAT_INVITE + self.addNumber( DATA_CHATID , chatid ) + self.addNumber( DATA_UID , uid ) + + elif cmd == "QUIT": + self.server.removeConnection( self.connID ) + + else: + self.irctrap = cmd + + return len( line ) + # This is the Hotline code now. + else: + if len( data ) < 20: + return 0 + ( self.type , self.seq , self.flags , size , check ) = unpack( "!5L", data[0:20] ) + if ( len( data ) - 20 ) < size: + return 0 + if size >= 2: + pos = 20 + count = unpack( "!H" , data[pos:pos+2] )[0] + pos += 2 + while count > 0: + ( obj_type , obj_size ) = unpack( "!2H", data[pos:pos+4] ) + pos += 4 + obj = HLObject( obj_type , data[pos:pos+obj_size] ) + self.addObject( obj ) + pos += obj_size + count = count - 1 + return 20 + size + + def addObject( self , obj ): + """ Adds a HLObject to the object list. """ + self.objs.append( obj ) + + def addString( self , type , data ): + """ Wraps a string in a HLObject and adds it. """ + obj = HLObject( type , data ) + self.addObject( obj ) + + def addNumber( self , type , data ): + """ Wraps a number in a HLObject, byte-swapping it based + on its magnitude, and adds it. """ + num = int( data ) + packed = "" + if num < ( 1 << 16 ): + packed = pack( "!H" , num ) + elif num < ( 1 << 32 ): + packed = pack( "!L" , num ) + elif num < ( 1 << 64 ): + packed = pack( "!Q" , num ) + obj = HLObject( type , packed ) + self.addObject( obj ) + + def addInt16( self , type , data ): + """ Adds a 16-bit byte-swapped number as a HLObject. """ + num = int( data ) + obj = HLObject( type , pack( "!H" , num ) ) + self.addObject( obj ) + + def addInt32( self , type , data ): + """ Adds a 32-bit byte-swapped number as a HLObject. """ + num = int( data ) + obj = HLObject( type , pack( "!L" , num ) ) + self.addObject( obj ) + + def addInt64( self , type , data ): + """ Adds a 64-bit byte-swapped number as a HLObject. """ + num = int( data ) + obj = HLObject( type , pack( "!Q" , num ) ) + self.addObject( obj ) + + def addBinary( self , type , data ): + """ Functionally equivalent to addString. """ + self.addString( type , data ) + + def getString( self , type , default = None ): + """ Returns a string for the specified object type, or + a default value when the specified type is not present. """ + for obj in self.objs: + if ( obj.type == type ) and ( len( obj.data ) > 0 ): + return obj.data + return default + + def getNumber( self , type , default = None ): + """ Returns a byte-swapped number for the specified object type, or + a default value when the specified type is not present. """ + for obj in self.objs: + if obj.type == type: + if len( obj.data ) == 2: + return unpack( "!H" , obj.data )[0] + elif len( obj.data ) == 4: + return unpack( "!L" , obj.data )[0] + elif len( obj.data ) == 8: + return unpack( "!Q" , obj.data )[0] + return default + + def getBinary( self , type , default = None ): + """ Functionally equivalent to getString. """ + return self.getString( type , default ) + + def flatten( self , user ): + """ Returns a flattened string of this packet and embedded objects. """ + data = "" + if self.isIRC: + if self.type == HTLS_HDR_PING: + data = "PONG :"+IRC_SERVER_NAME+"\r\n" + + elif self.type == HTLS_HDR_CHAT: + try: + chat = self.getString(DATA_STRING).split( ": " , 1 )[1].replace( "\r" , " " ) + except IndexError: + chat = self.getString(DATA_STRING).replace( "\r" , " " ) + try: + ( c , u ) = self.server.clients[self.getNumber( DATA_UID )] + # this should be hanlded already elsewhere but forgot :( + if user.uid == u.uid: + return data + mynick = ircCheckUserNick( u ) + mynick = u.nick.replace( " " , "" ) + except KeyError: + mynick = "PHXD" + chatid = self.getNumber( DATA_CHATID ) + if chatid == None: + channel = "public" + else: + channel = str(chatid) + data = ":"+mynick+" PRIVMSG #"+channel+" :"+chat[1:]+"\r\n" + + elif self.type == HTLS_HDR_MSG: + chat = self.getString( DATA_STRING ) + try: + ( c , u ) = self.server.clients[self.getNumber( DATA_UID )] + mynick = ircCheckUserNick( u ) + myip = u.ip + except KeyError: + mynick = "PHXD" + myip = "127.0.0.1" + data = ":"+mynick+"!~"+mynick+"@"+myip+" PRIVMSG "+user.nick+" :"+chat.replace( "\r" , " " )+"\r\n" + + elif self.type == HTLS_HDR_USER_LEAVE: + ( c, u ) = self.server.clients[self.getNumber( DATA_UID )] + mynick = ircCheckUserNick( u ) + if u.isIRC: + proto = "IRC" + else: + proto = "Hotline" + data = ":"+mynick+"!~"+mynick+"@"+u.ip+" PART #public :Client disconnected from "+proto+"\r\n" + + elif self.type == HTLS_HDR_USER_CHANGE: + ( c, u ) = self.server.clients[self.getNumber( DATA_UID )] + mynick = ircCheckUserNick( u ) + oldnick = self.getString( DATA_IRC_OLD_NICK ) + if not u.valid: # Login ? If so, force join the public channel + data = ":"+mynick+"!~"+mynick+"@"+u.ip+" JOIN :#public\r\n" + else: + if u.nick == oldnick: + data = "NOTICE *: *** "+oldnick+" changed status to "+str( u.status )+"\r\n" + else: + if user.uid == u.uid: + data = ":"+oldnick+"!~"+oldnick+"@"+u.ip+" NICK :"+user.nick+"\r\n" + else: + data = ":"+str( u.uid )+"_"+oldnick.replace( " " , "" )+" NICK "+ircCheckUserNick( u )+"\r\n" + + elif self.type == HTLS_HDR_TASK: + # check for HTLC_HDR_USER_LIST reply: + if self.getBinary( DATA_USER ): + keys = list(self.server.clients.keys()) + keys.sort() + for uid in keys: + ( c , u ) = self.server.clients[uid] + mynick = ircCheckUserNick( u ) + if u.isLoggedIn(): + data += ":"+IRC_SERVER_NAME+" 352 "+mynick+" #public "+mynick+" "+u.ip+" "+IRC_SERVER_NAME+" "+u.account.name.replace( " ", "_" )+"\r\n" + data += ":"+IRC_SERVER_NAME+" 315 "+user.nick+" #public :End of /WHO list.\r\n" + + # HTLC_HDR_USER_INFO then :) + elif self.getString( DATA_NICK ): + uid = self.getNumber( DATA_UID ) + ( c , u ) = self.server.clients[uid] + mynick = ircCheckUserNick( u ) + info = self.getString( DATA_STRING ) + + idle = info.split( "idle: " )[1].split( '\r' )[0] + if u.isIRC: + proto = "IRC" + else: + proto = "Hotline" + + data = ":"+IRC_SERVER_NAME+" 311 "+user.nick+" "+mynick+" ~"+mynick+" "+u.ip+" * :"+u.account.name.replace(" ", "_")+"\r\n" + data += ":"+IRC_SERVER_NAME+" 312 "+user.nick+" "+mynick+" "+IRC_SERVER_NAME+" :http//chatonly.org\r\n" + data += ":"+IRC_SERVER_NAME+" 320 "+user.nick+" "+mynick+" :Using protocol "+proto+"\r\n" + data += ":"+IRC_SERVER_NAME+" 317 "+user.nick+" "+mynick+" "+idle+" 0 :seconds idle, signon time\r\n" + data += ":"+IRC_SERVER_NAME+" 318 "+user.nick+" "+mynick+" :End of /WHOIS list.\r\n" + + elif self.type == HTLS_HDR_CHAT_INVITE: + chatid = self.getNumber( DATA_CHATID) + uid = self.getNumber( DATA_UID ) + ( c , u ) = self.server.clients[uid] + mynick = ircCheckUserNick( u ) + data = ":PHXD PRIVMSG #public :"+mynick+" invites you to join private chat #"+str(chatid)+"\r\n" + elif self.type == HTLS_HDR_CHAT_USER_LEAVE: + chatid = self.getNumber( DATA_CHATID) + uid = self.getNumber( DATA_UID ) + ( c , u ) = self.server.clients[uid] + mynick = ircCheckUserNick( u ) + data = ":"+mynick+"!~"+mynick+"@"+u.ip+" PART #"+str( chatid )+" :Client left channel #"+str( chatid )+"\r\n" + + elif self.type == HTLS_HDR_CHAT_USER_CHANGE: + # Basically this is a JOIN packet for a private chat + chatid = self.getNumber( DATA_CHATID) + uid = self.getNumber( DATA_UID ) + ( c , u ) = self.server.clients[uid] + mynick = ircCheckUserNick( self.getString( DATA_NICK ) ) + data = ":"+mynick+"!~"+mynick+"@"+u.ip+" JOIN :#"+str(chatid)+"\r\n" + + elif self.type == HTLS_HDR_BROADCAST: + data = "NOTICE * :*** BROADCAST: "+self.getString( DATA_STRING )+"\r\n" + + return data + # Normal Hotline processing + else: + for obj in self.objs: + data += obj.flatten() + return pack( "!5L1H" , self.type , self.seq , self.flags , len( data ) + 2 , len( data ) + 2 , len( self.objs ) ) + data # Client packet types @@ -537,41 +540,41 @@ def flatten( self , user ): # Hotline's idea of "bit 0" is ass backwards -PRIV_DELETE_FILES = 1L << 63 -PRIV_UPLOAD_FILES = 1L << 62 -PRIV_DOWNLOAD_FILES = 1L << 61 -PRIV_RENAME_FILES = 1L << 60 -PRIV_MOVE_FILES = 1L << 59 -PRIV_CREATE_FOLDERS = 1L << 58 -PRIV_DELETE_FOLDERS = 1L << 57 -PRIV_RENAME_FOLDERS = 1L << 56 -PRIV_MOVE_FOLDERS = 1L << 55 -PRIV_READ_CHAT = 1L << 54 -PRIV_SEND_CHAT = 1L << 53 -PRIV_CREATE_CHATS = 1L << 52 -PRIV_DELETE_CHATS = 1L << 51 -PRIV_SHOW_USER = 1L << 50 -PRIV_CREATE_USERS = 1L << 49 -PRIV_DELETE_USERS = 1L << 48 -PRIV_READ_USERS = 1L << 47 -PRIV_MODIFY_USERS = 1L << 46 -PRIV_CHANGE_PASSWORD = 1L << 45 -PRIV_UNKNOWN = 1L << 44 -PRIV_READ_NEWS = 1L << 43 -PRIV_POST_NEWS = 1L << 42 -PRIV_KICK_USERS = 1L << 41 -PRIV_KICK_PROTECT = 1L << 40 -PRIV_USER_INFO = 1L << 39 -PRIV_UPLOAD_ANYWHERE = 1L << 38 -PRIV_USE_ANY_NAME = 1L << 37 -PRIV_NO_AGREEMENT = 1L << 36 -PRIV_COMMENT_FILES = 1L << 35 -PRIV_COMMENT_FOLDERS = 1L << 34 -PRIV_VIEW_DROPBOXES = 1L << 33 -PRIV_MAKE_ALIASES = 1L << 32 -PRIV_BROADCAST = 1L << 31 - -PRIV_SEND_MESSAGES = 1L << 23 +PRIV_DELETE_FILES = 1 << 63 +PRIV_UPLOAD_FILES = 1 << 62 +PRIV_DOWNLOAD_FILES = 1 << 61 +PRIV_RENAME_FILES = 1 << 60 +PRIV_MOVE_FILES = 1 << 59 +PRIV_CREATE_FOLDERS = 1 << 58 +PRIV_DELETE_FOLDERS = 1 << 57 +PRIV_RENAME_FOLDERS = 1 << 56 +PRIV_MOVE_FOLDERS = 1 << 55 +PRIV_READ_CHAT = 1 << 54 +PRIV_SEND_CHAT = 1 << 53 +PRIV_CREATE_CHATS = 1 << 52 +PRIV_DELETE_CHATS = 1 << 51 +PRIV_SHOW_USER = 1 << 50 +PRIV_CREATE_USERS = 1 << 49 +PRIV_DELETE_USERS = 1 << 48 +PRIV_READ_USERS = 1 << 47 +PRIV_MODIFY_USERS = 1 << 46 +PRIV_CHANGE_PASSWORD = 1 << 45 +PRIV_UNKNOWN = 1 << 44 +PRIV_READ_NEWS = 1 << 43 +PRIV_POST_NEWS = 1 << 42 +PRIV_KICK_USERS = 1 << 41 +PRIV_KICK_PROTECT = 1 << 40 +PRIV_USER_INFO = 1 << 39 +PRIV_UPLOAD_ANYWHERE = 1 << 38 +PRIV_USE_ANY_NAME = 1 << 37 +PRIV_NO_AGREEMENT = 1 << 36 +PRIV_COMMENT_FILES = 1 << 35 +PRIV_COMMENT_FOLDERS = 1 << 34 +PRIV_VIEW_DROPBOXES = 1 << 33 +PRIV_MAKE_ALIASES = 1 << 32 +PRIV_BROADCAST = 1 << 31 + +PRIV_SEND_MESSAGES = 1 << 23 # Status bits diff --git a/shared/HLTransfer.py b/shared/HLTransfer.py index 7d59192..2095ed3 100644 --- a/shared/HLTransfer.py +++ b/shared/HLTransfer.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from shared.HLProtocol import * import os , time @@ -11,9 +12,9 @@ def __init__( self , id , path , owner , type ): self.name = os.path.basename( path ) self.owner = owner self.type = type - self.total = 0L - self.transferred = 0L - self.offset = 0L + self.total = 0 + self.transferred = 0 + self.offset = 0 self.startTime = 0.0 def overallPercent( self ): @@ -51,7 +52,7 @@ def __init__( self , id , path , owner , offset ): HLTransfer.__init__( self , id , path , owner , XFER_TYPE_DOWNLOAD ) self.offset = offset self.dataSize = os.path.getsize( path ) - offset - self.file = file( path , "r" ) + self.file = open( path , "r" ) self.file.seek( offset ) self.sentHeader = False self._buildHeaderData() @@ -101,7 +102,7 @@ def _buildHeaderData( self ): class HLUpload( HLTransfer ): def __init__( self , id , path , owner ): HLTransfer.__init__( self , id , path , owner , 1 ) - self.file = file( path , "a" ) + self.file = open( path , "a" ) self.initialSize = os.path.getsize( path ) self.buffer = "" self.state = STATE_FILP diff --git a/shared/HLTypes.py b/shared/HLTypes.py index 229a324..10286fa 100644 --- a/shared/HLTypes.py +++ b/shared/HLTypes.py @@ -1,7 +1,9 @@ +from __future__ import absolute_import from shared.HLProtocol import HLCharConst from datetime import datetime from struct import * import os +from six.moves import range LOG_TYPE_GENERAL = 1 LOG_TYPE_LOGIN = 2 @@ -34,11 +36,11 @@ class HLAccount: """ Stores account information. """ def __init__( self , login = "" ): - self.id = 0L + self.id = 0 self.login = login self.password = "" self.name = "Null Account" - self.privs = 0L + self.privs = 0 self.fileRoot = "" def copyFrom( self , acct ): @@ -62,7 +64,7 @@ def __init__( self , uid = 0 , addr = "" ): self.icon = 500 self.status = 0 self.gif = "" - self.color = -1L + self.color = -1 self.account = None self.away = False self.lastPacketTime = 0.0 @@ -83,7 +85,7 @@ def isLoggedIn( self ): def hasPriv( self , priv ): """ Returns True if the account associated with the user has the specified privilege. """ - return ( self.account != None ) and ( ( long( self.account.privs ) & priv ) > 0 ) + return ( self.account != None ) and ( ( int( self.account.privs ) & priv ) > 0 ) def parse( self, data ): if len(data) < 8: @@ -104,7 +106,7 @@ def flatten( self ): data += pack( "!4H" , self.uid , self.icon , self.status , len( self.nick ) ) data += self.nick # this is an avaraline extension for nick coloring - if self.color >= 0L: + if self.color >= 0: data += pack( "!L" , self.color ) return data @@ -158,7 +160,7 @@ def __init__( self , data = None ): def forkOffset( self , fork ): """ Returns the offset for the specified fork type. """ - if self.forkOffsets.has_key( fork ): + if fork in self.forkOffsets: return self.forkOffsets[fork] return 0 @@ -182,7 +184,7 @@ def flatten( self ): """ Flattens the resume information into a packed structure to send in a HLObject. """ data = pack( "!LH" , HLCharConst( "RFLT" ) , 1 ) data += ( "\0" * 34 ) - data += pack( "!H" , len( self.forkOffsets.keys() ) ) + data += pack( "!H" , len( list(self.forkOffsets.keys()) ) ) for forkType in self.forkOffsets.keys(): data += pack( "!4L" , forkType , self.forkOffsets[forkType] , 0 , 0 ) return data @@ -191,7 +193,7 @@ class HLNewsPost: """ Stores information about a single news post. """ def __init__( self , nick = "" , login = "" , post = "" ): - self.id = 0L + self.id = 0 self.nick = nick self.login = login self.post = post @@ -218,7 +220,7 @@ def handleUserDisconnected( self , server , user ): def handlePacket( self , server , user , packet ): """ Default dispatcher called when a packet is received. Calls any registered handler functions. Returns True when packet is handled. """ - if self._funcs.has_key( packet.type ): + if packet.type in self._funcs: self._funcs[packet.type]( server , user , packet ) return True return False diff --git a/shared/HLUtils.py b/shared/HLUtils.py index 17f3b8f..e5c14f7 100644 --- a/shared/HLUtils.py +++ b/shared/HLUtils.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import sys,os diff --git a/support/text_db_setup.py b/support/text_db_setup.py index 9ae1160..188a605 100644 --- a/support/text_db_setup.py +++ b/support/text_db_setup.py @@ -1,5 +1,6 @@ #!/usr/bin/env python +from __future__ import absolute_import import os from config import * From f07c30d7dbfdf102c5fe5cfda15ffa43a270cfa5 Mon Sep 17 00:00:00 2001 From: Patrick Thiel Date: Mon, 2 Oct 2023 22:44:09 -0400 Subject: [PATCH 2/8] Revert "ref: begin python3 conversion" This reverts commit 176c216d59b6ecedec498ce7f70ee87f1a3e06d4. --- Dockerfile | 2 +- config.py | 15 +- configure_phxd.py | 4 +- phxd | 12 +- server/HLDatabase.py | 4 +- server/HLDatabaseLogger.py | 1 - server/HLFileServer.py | 9 +- server/HLServer.py | 792 ++++++++++++----------- server/HLServerLinkage.py | 22 +- server/HLTracker.py | 1 - server/HLWebServices.py | 5 +- server/database/MySQLDatabase.py | 11 +- server/database/TextDatabase.py | 36 +- server/handlers/AcctHandler.py | 17 +- server/handlers/ChatHandler.py | 19 +- server/handlers/FileHandler.py | 45 +- server/handlers/IconHandler.py | 5 +- server/handlers/NewsHandler.py | 5 +- server/handlers/UserHandler.py | 29 +- server/handlers/commands/0wn.py | 1 - server/handlers/commands/away.py | 1 - server/handlers/commands/broadcast.py | 1 - server/handlers/commands/color.py | 1 - server/handlers/commands/find.py | 1 - server/handlers/commands/me.py | 1 - server/handlers/commands/news.py | 1 - server/handlers/commands/uptime.py | 3 +- server/handlers/commands/xfers.py | 3 +- shared/HLProtocol.py | 883 +++++++++++++------------- shared/HLTransfer.py | 11 +- shared/HLTypes.py | 20 +- shared/HLUtils.py | 1 - support/text_db_setup.py | 1 - 33 files changed, 958 insertions(+), 1005 deletions(-) diff --git a/Dockerfile b/Dockerfile index ac4bbda..3ba5b98 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.9-alpine +FROM python:2-alpine MAINTAINER Cat'Killer # The "exec" plugins are all written in bash and won't diff --git a/config.py b/config.py index df9835a..8543276 100644 --- a/config.py +++ b/config.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import import os ################################################################################ # database configuration @@ -39,8 +38,8 @@ ################################################################################ SERVER_PORT = 5500 -SERVER_NAME = "icedtrip2" -SERVER_DESCRIPTION = "Yet another hotline server instance" +SERVER_NAME = "phxd server" +SERVER_DESCRIPTION = "Yet another phxd server instance" IDLE_TIME = 10 * 60 BAN_TIME = 15 * 60 @@ -49,13 +48,9 @@ ################################################################################ # TRACKER_LIST example: -TRACKER_LIST=[("tracker.preterhuman.net", 5499), - ("tracked.agent79.org", 5499), - ("hotline.duckdns.org", 5499), - ("tracked.stickytack.com", 5499), - ("tracked.nailbat.com", 5499), - ("hotline.ubersoft.org", 5499)] -#TRACKER_LIST=[] +#TRACKER_LIST=[("tracker.hostname.tld", 5499), +# ("127.0.0.1", 5499)] +TRACKER_LIST=[] TRACKER_REFRESH_PERIOD=60 diff --git a/configure_phxd.py b/configure_phxd.py index 0acadb3..6985085 100755 --- a/configure_phxd.py +++ b/configure_phxd.py @@ -5,8 +5,6 @@ TODO: This is unecessarily complex. Need to use a better config file format instead """ -from __future__ import absolute_import -from __future__ import print_function __author__ = "Cat'Killer" __version__ = "0.0.1" __license__ = "WTFPL" @@ -57,7 +55,7 @@ def rewrite_config_file(filepath, values_dict): """ if not values_dict: return - keys = list(values_dict.keys()) + keys = values_dict.keys() with open(filepath, 'r') as config_file: config_str = config_file.read() with tempfile.NamedTemporaryFile(delete=False) as tmpconfig: diff --git a/phxd b/phxd index 0214799..944f9ed 100755 --- a/phxd +++ b/phxd @@ -1,7 +1,5 @@ #!/usr/bin/env python -from __future__ import absolute_import -from __future__ import print_function from twisted.internet import reactor from server.HLServer import HLServer from shared.HLTypes import * @@ -10,11 +8,11 @@ import server.handlers serv = HLServer() for modName in server.handlers.__all__: - try: - mod = __import__( "server.handlers.%s" % modName , None , None , "server.handlers" ) - mod.installHandler( serv ) - except ImportError: - print("error importing server.handlers.%s" % modName) + try: + mod = __import__( "server.handlers.%s" % modName , None , None , "server.handlers" ) + mod.installHandler( serv ) + except ImportError: + print "error importing server.handlers.%s" % modName serv.logEvent( LOG_TYPE_GENERAL , "Server started on port %d" % serv.port ) reactor.run() diff --git a/server/HLDatabase.py b/server/HLDatabase.py index 84d852f..4d73c3a 100644 --- a/server/HLDatabase.py +++ b/server/HLDatabase.py @@ -1,5 +1,3 @@ -from __future__ import absolute_import -from __future__ import print_function from shared.HLTypes import * import server.database @@ -11,7 +9,7 @@ def getDatabase( type ): db = eval( "mod.%s()" % cls ) return db except ImportError: - print("error importing server.database.%s" % cls) + print "error importing server.database.%s" % cls return None class HLDatabase: diff --git a/server/HLDatabaseLogger.py b/server/HLDatabaseLogger.py index 3d2f605..ee5b219 100644 --- a/server/HLDatabaseLogger.py +++ b/server/HLDatabaseLogger.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import from logging import Handler class HLDatabaseLogger( Handler ): diff --git a/server/HLFileServer.py b/server/HLFileServer.py index 083010b..9ed8ea7 100644 --- a/server/HLFileServer.py +++ b/server/HLFileServer.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import from twisted.internet.protocol import Factory , Protocol from twisted.internet.interfaces import IProducer from twisted.internet import reactor @@ -103,7 +102,7 @@ def addDownload( self , owner , path , offset ): def findTransfer( self , xfid ): """ Returns the HLTransfer (HLDownload or HLUpload) object for the specified transfer ID. """ - if xfid in self.transfers: + if self.transfers.has_key( xfid ): return self.transfers[xfid] return None @@ -117,19 +116,19 @@ def findTransfersForUser( self , uid ): def cancelTimeout( self , id ): """ Cancels a pending timeout for the specified transfer. """ - if id in self.timeouts: + if self.timeouts.has_key( id ): self.timeouts[id].cancel() del self.timeouts[id] def timeoutTransfer( self , id ): """ Called after an initial timeout to remove the dead transfer from the list of transfers. """ - if id in self.transfers: + if self.transfers.has_key( id ): del self.timeouts[id] del self.transfers[id] def removeTransfer( self , xfid ): """ Removes a transfer from the list of transfers. """ - if xfid in self.transfers: + if self.transfers.has_key( xfid ): info = self.transfers[xfid] user = self.server.getUser( info.owner ) if user != None: diff --git a/server/HLServer.py b/server/HLServer.py index 04287ab..4dac84a 100644 --- a/server/HLServer.py +++ b/server/HLServer.py @@ -1,5 +1,3 @@ -from __future__ import absolute_import -from __future__ import print_function from twisted.internet.protocol import Factory , Protocol from twisted.internet import task from twisted.internet import reactor @@ -20,419 +18,419 @@ from logging.handlers import RotatingFileHandler class HLConnection( Protocol ): - """ Protocol subclass to handle parsing and dispatching of raw hotline data. """ - - def __init__( self , factory , connID ): - self.factory = factory - self.connID = connID - - def connectionMade( self ): - """ Called when a connection is accepted. """ - self.gotMagic = False - self.isIRC = False - self.packet = HLPacket() - self.buffer = "" - self.idleTimer = reactor.callLater( IDLE_TIME , self.idleCheck ) - - def connectionLost( self , reason ): - """ Called when the connection is lost. """ - if ( self.idleTimer != None ) and self.idleTimer.active(): - self.idleTimer.cancel() - self.factory.removeConnection( self.connID ) - - def dataReceived( self , data ): - """ Called when the socket receives data. """ - self.buffer += data - self.parseBuffer() - - def parseBuffer( self ): - """ Parses the current buffer until the buffer is empty or until no more packets can be parsed. """ - if self.gotMagic: - done = False - while not done: - if self.isIRC: - self.buffer = self.buffer.replace("\r", "") #FIXME is it really necessary ? it is also done during packet parsing - self.packet.isIRC = self.isIRC - self.packet.connID = self.connID - self.packet.server = self.factory - size = self.packet.parse( self.buffer ) - if size > 0: - if self.isIRC: - size = size + 1 - self.buffer = self.buffer[size:] - self.handlePacket() - self.packet = HLPacket() - else: - done = True - else: - if len( self.buffer ) >= 12: - ( proto , subProto , vers , subVers ) = unpack( "!LLHH" , self.buffer[0:12] ) - if proto == HLCharConst( "TRTP" ): - self.buffer = self.buffer[12:] - self.gotMagic = True - self.transport.write( pack( "!2L" , HLCharConst( "TRTP" ) , 0 ) ) - # If there is still data in the buffer, check for packets. - if len( self.buffer ) > 0: - self.parseBuffer() - else: - # Not hotline, assume IRC. Multiple commands can be chained in IRC. - cmds = self.buffer.splitlines() - if cmds[0].startswith("CAP"): - # We received CAP LS, ignore it and read the rest of the buffer - # This is for compatibility with IRC v3.02 clients like irssi - cmds.pop(0) - # If there are no further commands, close the connection. - if not cmds: - self.transport.loseConnection() - # More commands still in the buffer, parse them. - value = "" - try: - cmd, value = cmds[0].split(" ", 1) - except ValueError: - # Value isn't defined, only parse cmd - cmd = cmds[0].split(" ", 1)[0] - # Check the first command, if NICK or USER, login, else return UNKNOWN COMMAND - if ( cmd == "NICK" ) or ( cmd == "USER" ): - nick = value or "Unnamed" - user = self.factory.getUser( self.connID ) - user.nick = nick # Making sure we have the right nick. - self.transport.write ( "NOTICE * :*** Welcome to Hotline\r\n" ) - self.transport.write ( "NOTICE AUTH :*** You are NOT logged in\r\n" ) - self.transport.write ( "NOTICE AUTH :*** Please send '/msg loginserv login password' to proceed.\r\n" ) - self.transport.write ( "NOTICE AUTH :*** If you do not have an account, use '/msg loginserv guest' to proceed.\r\n" ) - self.transport.write ( ":"+IRC_SERVER_NAME+" 001 %s :Waiting for login input..\r\n" % nick ) - self.transport.write ( ":"+IRC_SERVER_NAME+" 375 %s :- MOTDs are for losers.\r\n" % user.nick ) - self.transport.write ( ":"+IRC_SERVER_NAME+" 372 %s :- :)\r\n" % user.nick ) - self.transport.write ( ":"+IRC_SERVER_NAME+" 376 %s :End of /MOTD command.\r\n" % user.nick ) + """ Protocol subclass to handle parsing and dispatching of raw hotline data. """ + + def __init__( self , factory , connID ): + self.factory = factory + self.connID = connID + + def connectionMade( self ): + """ Called when a connection is accepted. """ + self.gotMagic = False + self.isIRC = False + self.packet = HLPacket() + self.buffer = "" + self.idleTimer = reactor.callLater( IDLE_TIME , self.idleCheck ) + + def connectionLost( self , reason ): + """ Called when the connection is lost. """ + if ( self.idleTimer != None ) and self.idleTimer.active(): + self.idleTimer.cancel() + self.factory.removeConnection( self.connID ) + + def dataReceived( self , data ): + """ Called when the socket receives data. """ + self.buffer += data + self.parseBuffer() + + def parseBuffer( self ): + """ Parses the current buffer until the buffer is empty or until no more packets can be parsed. """ + if self.gotMagic: + done = False + while not done: + if self.isIRC: + self.buffer = self.buffer.replace("\r", "") #FIXME is it really necessary ? it is also done during packet parsing + self.packet.isIRC = self.isIRC + self.packet.connID = self.connID + self.packet.server = self.factory + size = self.packet.parse( self.buffer ) + if size > 0: + if self.isIRC: + size = size + 1 + self.buffer = self.buffer[size:] + self.handlePacket() + self.packet = HLPacket() + else: + done = True + else: + if len( self.buffer ) >= 12: + ( proto , subProto , vers , subVers ) = unpack( "!LLHH" , self.buffer[0:12] ) + if proto == HLCharConst( "TRTP" ): + self.buffer = self.buffer[12:] + self.gotMagic = True + self.transport.write( pack( "!2L" , HLCharConst( "TRTP" ) , 0 ) ) + # If there is still data in the buffer, check for packets. + if len( self.buffer ) > 0: + self.parseBuffer() + else: + # Not hotline, assume IRC. Multiple commands can be chained in IRC. + cmds = self.buffer.splitlines() + if cmds[0].startswith("CAP"): + # We received CAP LS, ignore it and read the rest of the buffer + # This is for compatibility with IRC v3.02 clients like irssi + cmds.pop(0) + # If there are no further commands, close the connection. + if not cmds: + self.transport.loseConnection() + # More commands still in the buffer, parse them. + value = "" + try: + cmd, value = cmds[0].split(" ", 1) + except ValueError: + # Value isn't defined, only parse cmd + cmd = cmds[0].split(" ", 1)[0] + # Check the first command, if NICK or USER, login, else return UNKNOWN COMMAND + if ( cmd == "NICK" ) or ( cmd == "USER" ): + nick = value or "Unnamed" + user = self.factory.getUser( self.connID ) + user.nick = nick # Making sure we have the right nick. + self.transport.write ( "NOTICE * :*** Welcome to Hotline\r\n" ) + self.transport.write ( "NOTICE AUTH :*** You are NOT logged in\r\n" ) + self.transport.write ( "NOTICE AUTH :*** Please send '/msg loginserv login password' to proceed.\r\n" ) + self.transport.write ( "NOTICE AUTH :*** If you do not have an account, use '/msg loginserv guest' to proceed.\r\n" ) + self.transport.write ( ":"+IRC_SERVER_NAME+" 001 %s :Waiting for login input..\r\n" % nick ) + self.transport.write ( ":"+IRC_SERVER_NAME+" 375 %s :- MOTDs are for losers.\r\n" % user.nick ) + self.transport.write ( ":"+IRC_SERVER_NAME+" 372 %s :- :)\r\n" % user.nick ) + self.transport.write ( ":"+IRC_SERVER_NAME+" 376 %s :End of /MOTD command.\r\n" % user.nick ) - self.isIRC = True - self.gotMagic = True - self.parseBuffer() - else: - self.transport.write ( ":"+IRC_SERVER_NAME+" 421 %s :Unknown command\r\n" % cmd ) - self.transport.loseConnection() - - def handlePacket( self ): - """ Dispatch the packet to the factory (and its listeners) and check to see if we should update our away status. """ - try: - user = self.factory.getUser( self.connID ) - if not user: - self.transport.loseConnection() - return - if self.isIRC and self.packet.irctrap: - # Unsupported command, return 421 - self.transport.write ( ":"+IRC_SERVER_NAME+" 421 %s %s :Unknown command\r\n" % (user.nick, self.packet.irctrap) ) - if user.isLoggedIn(): - # Make sure we're logged in before doing anything. - self.factory.dispatchPacket( self.connID , self.packet ) - if ( not isPingType( self.packet.type ) ) and ( not user.away ): - # We got a non-ping packet, and we're not away. - user.lastPacketTime = time.time() - if ( self.idleTimer != None ) and self.idleTimer.active(): - # If the idleTimer exists and hasn't fired yet, remain active. - self.idleTimer.reset( IDLE_TIME ) - else: - # Otherwise, we just came back from being idle. - user.status &= ~STATUS_AWAY - self.factory.dispatchPacket( self.connID , HLPacket( HTLC_HDR_USER_CHANGE ) ) - self.idleTimer = reactor.callLater( IDLE_TIME , self.idleCheck ) - elif ( self.packet.type == HTLC_HDR_LOGIN ): - user.isIRC = self.packet.isIRC - # If we're not logged in, only dispatch login packets. - user.lastPacketTime = time.time() - self.factory.dispatchPacket( self.connID , self.packet ) - elif ( self.packet.type == HTLC_HDR_PING ): - if self.packet.isIRC: - self.factory.dispatchPacket( self.connID , self.packet ) - else: - if ( self.packet.isIRC == 0 ) and ( self.packet.type != 0 ) and ( self.packet.type != 130 ): - print("got packet before login:") - print(self.packet) - except HLException as ex: - # Unhandled packets and task errors will be caught here. - if self.isIRC: - if self.packet.irctrap: - # Not sure this is still required since we already return a 421 "Unknown command" reply. - self.transport.write( "NOTICE * :*** HL Error 0x%x [%s] %s\r\n" % ( self.packet.type, self.packet.irctrap, ex.msg )) - else: - packet = HLPacket( HTLS_HDR_TASK , self.packet.seq , 1 ) - packet.addString( DATA_ERROR , ex.msg ) - self.writePacket( packet ) - if ex.fatal: - # The exception was fatal (i.e. failed login) so kill the connection. - self.transport.loseConnection() - - def idleCheck( self ): - """ Called a set amount of time after the last non-ping packet, mark us as idle and trick the handlers into sending the change. """ - user = self.factory.getUser( self.connID ) - if not user.away: - # Only send the change if the user is not away and not idle. - user.status |= STATUS_AWAY - self.factory.dispatchPacket( self.connID , HLPacket(HTLC_HDR_USER_CHANGE ) ) - del self.idleTimer - self.idleTimer = None - - def writePacket( self , packet ): - """ Flattens and writes a packet out to the socket. """ - packet.server = self.factory - self.transport.write( packet.flatten( self.factory.getUser( self.connID ) ) ) + self.isIRC = True + self.gotMagic = True + self.parseBuffer() + else: + self.transport.write ( ":"+IRC_SERVER_NAME+" 421 %s :Unknown command\r\n" % cmd ) + self.transport.loseConnection() + + def handlePacket( self ): + """ Dispatch the packet to the factory (and its listeners) and check to see if we should update our away status. """ + try: + user = self.factory.getUser( self.connID ) + if not user: + self.transport.loseConnection() + return + if self.isIRC and self.packet.irctrap: + # Unsupported command, return 421 + self.transport.write ( ":"+IRC_SERVER_NAME+" 421 %s %s :Unknown command\r\n" % (user.nick, self.packet.irctrap) ) + if user.isLoggedIn(): + # Make sure we're logged in before doing anything. + self.factory.dispatchPacket( self.connID , self.packet ) + if ( not isPingType( self.packet.type ) ) and ( not user.away ): + # We got a non-ping packet, and we're not away. + user.lastPacketTime = time.time() + if ( self.idleTimer != None ) and self.idleTimer.active(): + # If the idleTimer exists and hasn't fired yet, remain active. + self.idleTimer.reset( IDLE_TIME ) + else: + # Otherwise, we just came back from being idle. + user.status &= ~STATUS_AWAY + self.factory.dispatchPacket( self.connID , HLPacket( HTLC_HDR_USER_CHANGE ) ) + self.idleTimer = reactor.callLater( IDLE_TIME , self.idleCheck ) + elif ( self.packet.type == HTLC_HDR_LOGIN ): + user.isIRC = self.packet.isIRC + # If we're not logged in, only dispatch login packets. + user.lastPacketTime = time.time() + self.factory.dispatchPacket( self.connID , self.packet ) + elif ( self.packet.type == HTLC_HDR_PING ): + if self.packet.isIRC: + self.factory.dispatchPacket( self.connID , self.packet ) + else: + if ( self.packet.isIRC == 0 ) and ( self.packet.type != 0 ) and ( self.packet.type != 130 ): + print "got packet before login:" + print self.packet + except HLException , ex: + # Unhandled packets and task errors will be caught here. + if self.isIRC: + if self.packet.irctrap: + # Not sure this is still required since we already return a 421 "Unknown command" reply. + self.transport.write( "NOTICE * :*** HL Error 0x%x [%s] %s\r\n" % ( self.packet.type, self.packet.irctrap, ex.msg )) + else: + packet = HLPacket( HTLS_HDR_TASK , self.packet.seq , 1 ) + packet.addString( DATA_ERROR , ex.msg ) + self.writePacket( packet ) + if ex.fatal: + # The exception was fatal (i.e. failed login) so kill the connection. + self.transport.loseConnection() + + def idleCheck( self ): + """ Called a set amount of time after the last non-ping packet, mark us as idle and trick the handlers into sending the change. """ + user = self.factory.getUser( self.connID ) + if not user.away: + # Only send the change if the user is not away and not idle. + user.status |= STATUS_AWAY + self.factory.dispatchPacket( self.connID , HLPacket(HTLC_HDR_USER_CHANGE ) ) + del self.idleTimer + self.idleTimer = None + + def writePacket( self , packet ): + """ Flattens and writes a packet out to the socket. """ + packet.server = self.factory + self.transport.write( packet.flatten( self.factory.getUser( self.connID ) ) ) class HLServer( Factory ): - """ Factory subclass that handles all global server operations. Also owns database and fileserver objects. """ - - def __init__( self ): - self.port = SERVER_PORT - self.lastUID = 0 - self.lastChatID = 0 - self.clients = {} - self.chats = {} - self.handlers = [] - self.tempBans = {} - self.database = getDatabase( DB_TYPE ) - self.fileserver = HLFileServer( self ) - self.webserver = HLWebServices( self ) - self.startTime = time.time() - self.log = logging.getLogger( "phxd" ) - self.linker = HLServerLinker( self ) - self._initLog() - reactor.listenTCP( self.port , self ) - # Update all trackers periodically - recurrentTask = task.LoopingCall(self.updateTrackers) - recurrentTask.start(TRACKER_REFRESH_PERIOD) - #recurrentTask.addErrback(updateTrackersFailed) - - def updateTrackers(self): - """Updates the register trackers, if any, with the name - and description of server and the current user count. - """ - for hostname, port in TRACKER_LIST: - reactor.listenUDP(0, HLTrackerClient(self, hostname, port)) + """ Factory subclass that handles all global server operations. Also owns database and fileserver objects. """ + + def __init__( self ): + self.port = SERVER_PORT + self.lastUID = 0 + self.lastChatID = 0 + self.clients = {} + self.chats = {} + self.handlers = [] + self.tempBans = {} + self.database = getDatabase( DB_TYPE ) + self.fileserver = HLFileServer( self ) + self.webserver = HLWebServices( self ) + self.startTime = time.time() + self.log = logging.getLogger( "phxd" ) + self.linker = HLServerLinker( self ) + self._initLog() + reactor.listenTCP( self.port , self ) + # Update all trackers periodically + recurrentTask = task.LoopingCall(self.updateTrackers) + recurrentTask.start(TRACKER_REFRESH_PERIOD) + #recurrentTask.addErrback(updateTrackersFailed) + + def updateTrackers(self): + """Updates the register trackers, if any, with the name + and description of server and the current user count. + """ + for hostname, port in TRACKER_LIST: + reactor.listenUDP(0, HLTrackerClient(self, hostname, port)) - def updateTrackersFailed(self, reason): - """Errback invoked when the task to update the trackers - fails for whatever reason. - """ - print("Failed to update tracker: reason") + def updateTrackersFailed(self, reason): + """Errback invoked when the task to update the trackers + fails for whatever reason. + """ + print "Failed to update tracker: reason" - def _initLog( self ): - self.log.setLevel( logging.DEBUG ) - if ENABLE_FILE_LOG: - # the formatter is just for the file logger - fmt = logging.Formatter( '%(asctime)s\t%(message)s' ) - logSizeBytes = LOG_MAX_SIZE_MBYTES * 1024 * 1024 - try: - fileHandler = RotatingFileHandler( LOG_FILE, - maxBytes=logSizeBytes, backupCount=MAX_LOG_FILES ) - except IOError: - # Logfile directory most likely doesn't exist, attempt - # to create it and try again. - import os - os.makedirs(os.path.dirname(LOG_FILE)) - fileHandler = logging.FileHandler( LOG_FILE, - maxBytes=logSizeBytes, backupCount=MAX_LOG_FILES ) - # If opening the file handle fails at this point, raise - fileHandler.setFormatter( fmt ) - # make sure everything goes to the file log - fileHandler.setLevel( logging.DEBUG ) - self.log.addHandler( fileHandler ) - dbHandler = HLDatabaseLogger( self.database ) - # we only want server events and errors in the database log - dbHandler.setLevel( logging.INFO ) - self.log.addHandler( dbHandler ) - - def linkToServer( self, addr ): - ( ip , port ) = addr.split( ':' ) - self.linker.link( ip, int(port) ) + def _initLog( self ): + self.log.setLevel( logging.DEBUG ) + if ENABLE_FILE_LOG: + # the formatter is just for the file logger + fmt = logging.Formatter( '%(asctime)s\t%(message)s' ) + logSizeBytes = LOG_MAX_SIZE_MBYTES * 1024 * 1024 + try: + fileHandler = RotatingFileHandler( LOG_FILE, + maxBytes=logSizeBytes, backupCount=MAX_LOG_FILES ) + except IOError: + # Logfile directory most likely doesn't exist, attempt + # to create it and try again. + import os + os.makedirs(os.path.dirname(LOG_FILE)) + fileHandler = logging.FileHandler( LOG_FILE, + maxBytes=logSizeBytes, backupCount=MAX_LOG_FILES ) + # If opening the file handle fails at this point, raise + fileHandler.setFormatter( fmt ) + # make sure everything goes to the file log + fileHandler.setLevel( logging.DEBUG ) + self.log.addHandler( fileHandler ) + dbHandler = HLDatabaseLogger( self.database ) + # we only want server events and errors in the database log + dbHandler.setLevel( logging.INFO ) + self.log.addHandler( dbHandler ) + + def linkToServer( self, addr ): + ( ip , port ) = addr.split( ':' ) + self.linker.link( ip, int(port) ) - def addRemoteUser( self, remoteUser, sendChange = True ): - self.lastUID += 1 - user = HLUser( self.lastUID, "" ) - user.nick = remoteUser.nick - user.icon = remoteUser.icon - user.color = remoteUser.color - user.status = remoteUser.status - user.local = False - user.account = HLAccount( "" ) - user.account.name = "Linked Account" - user.valid = True + def addRemoteUser( self, remoteUser, sendChange = True ): + self.lastUID += 1 + user = HLUser( self.lastUID, "" ) + user.nick = remoteUser.nick + user.icon = remoteUser.icon + user.color = remoteUser.color + user.status = remoteUser.status + user.local = False + user.account = HLAccount( "" ) + user.account.name = "Linked Account" + user.valid = True - self.clients[self.lastUID] = ( None , user ) + self.clients[self.lastUID] = ( None , user ) - if sendChange: - change = HLPacket( HTLS_HDR_USER_CHANGE ) - change.addNumber( DATA_UID , user.uid ) - change.addString( DATA_NICK , user.nick ) - change.addNumber( DATA_ICON , user.icon ) - change.addNumber( DATA_STATUS , user.status ) - for ( conn , user ) in self.clients.values(): - if user.local: - conn.writePacket( change ) - return user.uid + if sendChange: + change = HLPacket( HTLS_HDR_USER_CHANGE ) + change.addNumber( DATA_UID , user.uid ) + change.addString( DATA_NICK , user.nick ) + change.addNumber( DATA_ICON , user.icon ) + change.addNumber( DATA_STATUS , user.status ) + for ( conn , user ) in self.clients.values(): + if user.local: + conn.writePacket( change ) + return user.uid - def removeRemoteUser( self, uid ): - if uid in self.clients: + def removeRemoteUser( self, uid ): + if self.clients.has_key( uid ): del( self.clients[uid] ) - - def handleUserLogin( self, user ): + + def handleUserLogin( self, user ): user.valid = True self.linker.forwardUserConnect( user ) - - def addTempBan( self , addr , reason = "no reason" ): - """ Adds a temporary ban for addr that will expire in BAN_TIME seconds. """ - if addr not in self.tempBans: - self.tempBans[addr] = reason - reactor.callLater( BAN_TIME , self.removeTempBan , addr ) - - def removeTempBan( self , addr ): - """ Removes a temporary ban for addr, if it exists. """ - if addr in self.tempBans: - del self.tempBans[addr] - - def checkForBan( self , addr ): - """ Returns the reason given for a ban, if it exists. Otherwise returns None. """ - if addr in self.tempBans: - return self.tempBans[addr] - return self.database.checkBanlist( addr ) - - def buildProtocol( self , addr ): - """ Called when the factory accepts a connection and is asked to return a Protocol (in our case, a HLConnection). """ - self.lastUID += 1 - conn = HLConnection( self , self.lastUID ) - user = HLUser( self.lastUID , addr.host ) - self.clients[self.lastUID] = ( conn , user ) - for handler in self.handlers: - handler.handleUserConnected( self , user ) - return conn - - def registerPacketHandler( self , handler ): - """ Registers a HLPacketHandler. """ - if isinstance( handler , HLPacketHandler ): - self.handlers.append( handler ) - - def disconnectUser( self , uid ): - """ Actively disconnect the specified user. """ - if uid in self.clients: - ( conn , user ) = self.clients[uid] - conn.transport.loseConnection() - - def removeConnection( self , connID ): - """ Called from HLConnection when a connection dies. """ - if connID in self.clients: - ( conn , user ) = self.clients[connID] - if user.isLoggedIn(): - for handler in self.handlers: - handler.handleUserDisconnected( self , user ) - self.fileserver.cleanupTransfers( user.uid ) - self.linker.forwardUserDisconnect( user ) - del( self.clients[connID] ) - - def getUser( self , uid ): - """ Gets the HLUser object for the specified uid. """ - if uid in self.clients: - ( conn , user ) = self.clients[uid] - return user - return None - + + def addTempBan( self , addr , reason = "no reason" ): + """ Adds a temporary ban for addr that will expire in BAN_TIME seconds. """ + if not self.tempBans.has_key( addr ): + self.tempBans[addr] = reason + reactor.callLater( BAN_TIME , self.removeTempBan , addr ) + + def removeTempBan( self , addr ): + """ Removes a temporary ban for addr, if it exists. """ + if self.tempBans.has_key( addr ): + del self.tempBans[addr] + + def checkForBan( self , addr ): + """ Returns the reason given for a ban, if it exists. Otherwise returns None. """ + if self.tempBans.has_key( addr ): + return self.tempBans[addr] + return self.database.checkBanlist( addr ) + + def buildProtocol( self , addr ): + """ Called when the factory accepts a connection and is asked to return a Protocol (in our case, a HLConnection). """ + self.lastUID += 1 + conn = HLConnection( self , self.lastUID ) + user = HLUser( self.lastUID , addr.host ) + self.clients[self.lastUID] = ( conn , user ) + for handler in self.handlers: + handler.handleUserConnected( self , user ) + return conn + + def registerPacketHandler( self , handler ): + """ Registers a HLPacketHandler. """ + if isinstance( handler , HLPacketHandler ): + self.handlers.append( handler ) + + def disconnectUser( self , uid ): + """ Actively disconnect the specified user. """ + if self.clients.has_key( uid ): + ( conn , user ) = self.clients[uid] + conn.transport.loseConnection() + + def removeConnection( self , connID ): + """ Called from HLConnection when a connection dies. """ + if self.clients.has_key( connID ): + ( conn , user ) = self.clients[connID] + if user.isLoggedIn(): + for handler in self.handlers: + handler.handleUserDisconnected( self , user ) + self.fileserver.cleanupTransfers( user.uid ) + self.linker.forwardUserDisconnect( user ) + del( self.clients[connID] ) + + def getUser( self , uid ): + """ Gets the HLUser object for the specified uid. """ + if self.clients.has_key( uid ): + ( conn , user ) = self.clients[uid] + return user + return None + def getUserCount(self): """Returns the number of logged in HLUsers.""" return len([user for _, user in self.clients.values() if user.isLoggedIn()]) - def getOrderedUserlist( self ): - """ Returns a list of HLUsers, ordered by uid. """ - keys = list(self.clients.keys()) - keys.sort() - userlist = [] - for uid in keys: - ( conn , user ) = self.clients[uid] - if user.isLoggedIn(): - userlist.append( user ) - return userlist - - def createChat( self ): - """ Creates and registers a new private chat, returns the ID of the newly created chat. """ - self.lastChatID += 1 - chat = HLChat( self.lastChatID ) - self.chats[self.lastChatID] = chat - return chat - - def removeChat( self , id ): - """ Remove the specified private chat. """ - if id in self.chats: - del self.chats[id] - - def getChat( self , id ): - """ Gets the HLChat object for the specified chat ID. """ - if id in self.chats: - return self.chats[id] - return None - - def sendPacket( self , uid , packet ): - """ Sends the specified packet to the specified user. """ - if uid in self.clients: - ( conn , user ) = self.clients[uid] - packet.isIRC = conn.isIRC - if user.local: - conn.writePacket( packet ) - else: - self.linker.forwardPacket( packet, user.uid ) - - def broadcastPacket( self , packet , priv = 0 ): - """ Sends the specified packet to all connected users. If priv is specified, only sends to users with that priv. """ - for ( conn , user ) in self.clients.values(): - packet.isIRC = conn.isIRC - if not user.local: - self.linker.forwardPacket( packet, user.uid ) - elif user.isLoggedIn(): - if priv > 0: - if user.hasPriv( priv ): - conn.writePacket( packet ) - else: - conn.writePacket( packet ) + def getOrderedUserlist( self ): + """ Returns a list of HLUsers, ordered by uid. """ + keys = self.clients.keys() + keys.sort() + userlist = [] + for uid in keys: + ( conn , user ) = self.clients[uid] + if user.isLoggedIn(): + userlist.append( user ) + return userlist + + def createChat( self ): + """ Creates and registers a new private chat, returns the ID of the newly created chat. """ + self.lastChatID += 1 + chat = HLChat( self.lastChatID ) + self.chats[self.lastChatID] = chat + return chat + + def removeChat( self , id ): + """ Remove the specified private chat. """ + if self.chats.has_key( id ): + del self.chats[id] + + def getChat( self , id ): + """ Gets the HLChat object for the specified chat ID. """ + if self.chats.has_key( id ): + return self.chats[id] + return None + + def sendPacket( self , uid , packet ): + """ Sends the specified packet to the specified user. """ + if self.clients.has_key( uid ): + ( conn , user ) = self.clients[uid] + packet.isIRC = conn.isIRC + if user.local: + conn.writePacket( packet ) + else: + self.linker.forwardPacket( packet, user.uid ) + + def broadcastPacket( self , packet , priv = 0 ): + """ Sends the specified packet to all connected users. If priv is specified, only sends to users with that priv. """ + for ( conn , user ) in self.clients.values(): + packet.isIRC = conn.isIRC + if not user.local: + self.linker.forwardPacket( packet, user.uid ) + elif user.isLoggedIn(): + if priv > 0: + if user.hasPriv( priv ): + conn.writePacket( packet ) + else: + conn.writePacket( packet ) - def dispatchPacket( self , connID , packet ): - """ Called from HLConnection to dispatch a packet to all registered packet handlers. """ - if connID in self.clients: - handled = False - ( conn , user ) = self.clients[connID] - for handler in self.handlers: - handled |= handler.handlePacket( self , user , packet ) - if handled == False: - raise HLException("unknown packet type") + def dispatchPacket( self , connID , packet ): + """ Called from HLConnection to dispatch a packet to all registered packet handlers. """ + if self.clients.has_key( connID ): + handled = False + ( conn , user ) = self.clients[connID] + for handler in self.handlers: + handled |= handler.handlePacket( self , user , packet ) + if handled == False: + raise HLException , "unknown packet type" - #def returnClients( self ): - # """ For irc :p """ - # return self.clients - # DELETEME i think its dead code!! + #def returnClients( self ): + # """ For irc :p """ + # return self.clients + # DELETEME i think its dead code!! - def logEvent( self , typeInt , msg , user = None ): - """ Logs an event. If user is specified, the event will be logged with the users nickname, login, and IP address. """ - login = "" - nickname = "" - ip = "" - if user != None: - login = user.account.login - nickname = user.nick - ip = user.ip - typeStr = str(typeInt) - try: - typeStr = LOG_TYPE_STR_MAP[typeInt] - except KeyError: - pass - # format as \t\t\t\t - # this is the "message" for the FileLogger - fmt = "%s\t%s\t%s\t%s\t%s" - if type == LOG_TYPE_ERROR: - self.log.error( fmt, typeStr, msg, login, nickname, ip ) - elif type == LOG_TYPE_DEBUG: - self.log.debug( fmt, typeStr, msg, login, nickname, ip ) - else: - self.log.info( fmt, typeStr, msg, login, nickname, ip ) - - def updateAccounts( self , acct ): - """ Updates the account information for all current users with login matching that of the specified HLAccount. """ - for ( conn , user ) in self.clients.values(): - if user.isLoggedIn() and ( user.account.login.upper() == acct.login.upper() ): - user.account.copyFrom( acct ) - self.dispatchPacket( user.uid , HLPacket( HTLC_HDR_USER_CHANGE ) ) + def logEvent( self , typeInt , msg , user = None ): + """ Logs an event. If user is specified, the event will be logged with the users nickname, login, and IP address. """ + login = "" + nickname = "" + ip = "" + if user != None: + login = user.account.login + nickname = user.nick + ip = user.ip + typeStr = str(typeInt) + try: + typeStr = LOG_TYPE_STR_MAP[typeInt] + except KeyError: + pass + # format as \t\t\t\t + # this is the "message" for the FileLogger + fmt = "%s\t%s\t%s\t%s\t%s" + if type == LOG_TYPE_ERROR: + self.log.error( fmt, typeStr, msg, login, nickname, ip ) + elif type == LOG_TYPE_DEBUG: + self.log.debug( fmt, typeStr, msg, login, nickname, ip ) + else: + self.log.info( fmt, typeStr, msg, login, nickname, ip ) + + def updateAccounts( self , acct ): + """ Updates the account information for all current users with login matching that of the specified HLAccount. """ + for ( conn , user ) in self.clients.values(): + if user.isLoggedIn() and ( user.account.login.upper() == acct.login.upper() ): + user.account.copyFrom( acct ) + self.dispatchPacket( user.uid , HLPacket( HTLC_HDR_USER_CHANGE ) ) diff --git a/server/HLServerLinkage.py b/server/HLServerLinkage.py index a7e1db7..5741f8a 100644 --- a/server/HLServerLinkage.py +++ b/server/HLServerLinkage.py @@ -1,5 +1,3 @@ -from __future__ import absolute_import -from __future__ import print_function from twisted.internet import reactor from twisted.internet.protocol import Protocol , Factory , ClientCreator from shared.HLProtocol import * @@ -25,7 +23,7 @@ def connectionMade( self ): self.factory.linkEstablished( self ) def connectionLost( self, reason ): - print("link connection lost") + print "link connection lost" def dataReceived( self, data ): self.buffer += data @@ -46,11 +44,11 @@ def fixPacket( self, packet ): for obj in packet.objs: if obj.type == DATA_UID: remoteUID = unpack( "!H" , obj.data )[0] - if remoteUID in self.remoteToLocal: + if self.remoteToLocal.has_key( remoteUID ): localUID = self.remoteToLocal[remoteUID] obj.data = pack( "!H" , localUID ) else: - print("ERROR: unable to map remote UID [%d]" % remoteUID) + print "ERROR: unable to map remote UID [%d]" % remoteUID def handleLinkPacket( self, packet ): if packet.type == HTLS_HDR_LINK_LOGIN: @@ -73,7 +71,7 @@ def handleLinkPacket( self, packet ): # a user left on the remote server user = HLUser() if user.parse( packet.getBinary(DATA_USER) ) > 0: - if user.uid in self.remoteToLocal: + if self.remoteToLocal.has_key( user.uid ): localUID = self.remoteToLocal[user.uid] self.factory.server.removeRemoteUser( localUID ) elif packet.type == HTLS_HDR_LINK_PACKET: @@ -84,17 +82,17 @@ def handleLinkPacket( self, packet ): self.fixPacket( localPacket ) self.factory.server.sendPacket( localUID, localPacket ) else: - print("ERROR: unknown link packet type") + print "ERROR: unknown link packet type" def forwardPacketData( self, data, uid ): - if uid in self.localToRemote: + if self.localToRemote.has_key( uid ): remoteUID = self.localToRemote[uid] fwdPacket = HLPacket( HTLS_HDR_LINK_PACKET ) fwdPacket.addNumber( DATA_UID, remoteUID ) fwdPacket.addBinary( DATA_PACKET, data ) self.transport.write( fwdPacket.flatten() ) else: - print("ERROR: unable to forward packet to local UID %d" % uid) + print "ERROR: unable to forward packet to local UID %d" % uid class HLServerLinker( Factory ): @@ -104,15 +102,15 @@ def __init__( self, server ): reactor.listenTCP( LINK_PORT, self ) def buildProtocol( self, addr ): - print("got link connection from %s" % addr.host) + print "got link connection from %s" % addr.host return LinkConnection( self ) def linkEstablished( self, link ): - print("added link") + print "added link" self.links.append( link ) def link( self, addr, port ): - print("linking to %s:%d" % (addr,port)) + print "linking to %s:%d" % (addr,port) c = ClientCreator( reactor, LinkConnection, self ) c.connectTCP( addr, port ) diff --git a/server/HLTracker.py b/server/HLTracker.py index 293809d..063b102 100644 --- a/server/HLTracker.py +++ b/server/HLTracker.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import from twisted.internet import reactor from twisted.internet.protocol import DatagramProtocol from config import * diff --git a/server/HLWebServices.py b/server/HLWebServices.py index 3bda53b..244f017 100644 --- a/server/HLWebServices.py +++ b/server/HLWebServices.py @@ -1,9 +1,8 @@ -from __future__ import absolute_import from twisted.web import xmlrpc , server from twisted.internet import reactor from shared.HLTypes import * from config import * -from six.moves.xmlrpc_client import Binary +from xmlrpclib import Binary import time class HLWebServices( xmlrpc.XMLRPC ): @@ -17,7 +16,7 @@ def __init__( self , hlserver ): def xmlrpc_getServerUptime( self ): """ Returns the server uptime in seconds. """ - return int( time.time() - self.server.startTime ) + return long( time.time() - self.server.startTime ) def xmlrpc_getUserlist( self ): """ Returns a list of online users. Each entry is a dictionary containing user information. """ diff --git a/server/database/MySQLDatabase.py b/server/database/MySQLDatabase.py index ba6720b..d680d60 100644 --- a/server/database/MySQLDatabase.py +++ b/server/database/MySQLDatabase.py @@ -1,10 +1,7 @@ -from __future__ import absolute_import -from __future__ import print_function from server.HLDatabase import HLDatabase from shared.HLTypes import * from config import * import MySQLdb -from six.moves import range class MySQLDatabase (HLDatabase): """ MySQL-based implementation of HLDatabase. """ @@ -24,7 +21,7 @@ def loadAccount( self , login ): def saveAccount( self , acct ): cur = self.db.cursor() - if acct.id > 0: + if acct.id > 0L: cur.execute( "UPDATE accounts SET password = %s , name = %s , privs = %s , fileRoot = %s WHERE id = %s" , \ ( acct.password , acct.name , acct.privs , acct.fileRoot , acct.id ) ) else: @@ -62,7 +59,7 @@ def loadNewsPosts( self , limit = 0 ): def saveNewsPost( self , post ): cur = self.db.cursor() - if post.id > 0: + if post.id > 0L: cur.execute( "UPDATE news SET nick = %s , login = %s , post = %s , date = %s WHERE id = %s" , ( post.nick , post.login , post.post , post.date , post.id ) ) else: cur.execute( "INSERT INTO news ( nick , login , post , date ) VALUES ( %s , %s , %s , %s )" , ( post.nick , post.login , post.post , post.date ) ) @@ -75,7 +72,7 @@ def checkBanlist( self , addr ): cur = self.db.cursor() num = cur.execute( "SELECT reason FROM banlist WHERE address = %s" , addr ) except: - print("mysql connection lost. check that mysql is up. reconnecting now.") + print "mysql connection lost. check that mysql is up. reconnecting now." cur = self.db.cursor() self.db = MySQLdb.connect( host = DB_HOST , user = DB_USER , passwd = DB_PASS , db = DB_NAME ) num = cur.execute( "SELECT reason FROM banlist WHERE address = %s" , addr ) @@ -90,7 +87,7 @@ def logEvent( self , type , event , login = "" , nick = "" , ip = "" ): cur.execute( "INSERT INTO log ( type , login , nick , ip , entry , date ) VALUES ( %s , %s , %s , %s , %s , NOW() )" , ( type , login , nick , ip , event ) ) cur.close() except: - print("mysql connection lost. check that mysql is up. reconnecting now.") + print "mysql connection lost. check that mysql is up. reconnecting now." cur = self.db.cursor() self.db = MySQLdb.connect( host = DB_HOST , user = DB_USER , passwd = DB_PASS , db = DB_NAME ) cur.execute( "INSERT INTO log ( type , login , nick , ip , entry , date ) VALUES ( %s , %s , %s , %s , %s , NOW() )" , ( type , login , nick , ip , event ) ) diff --git a/server/database/TextDatabase.py b/server/database/TextDatabase.py index fda1404..46ec3ff 100644 --- a/server/database/TextDatabase.py +++ b/server/database/TextDatabase.py @@ -1,11 +1,9 @@ -from __future__ import absolute_import from server.HLDatabase import HLDatabase from shared.HLTypes import * from config import * from datetime import datetime from os import mkdir , listdir , sep import re -from six.moves import range class TextDatabase (HLDatabase): """ Text-based implementation of HLDatabase. """ @@ -31,7 +29,7 @@ def loadAccount( self , login ): """ Creates a new HLAccount object and loads information for the specified login into it. Returns None if unsuccessful. """ acct = None try: - fp = open( self.accountsFile , "r" ) + fp = file( self.accountsFile , "r" ) except IOError: return acct for l in fp.readlines(): @@ -39,7 +37,7 @@ def loadAccount( self , login ): acct = HLAccount( login ) try: ( acct.id , acct.password , acct.name , acct.privs , acct.fileRoot ) = l.rstrip( "\n" ).split( "\t" )[1:6] - ( acct.id , acct.privs ) = ( int( acct.id ) , int( acct.privs ) ) + ( acct.id , acct.privs ) = ( int( acct.id ) , long( acct.privs ) ) break except ValueError: return None @@ -49,12 +47,12 @@ def loadAccount( self , login ): def saveAccount( self , acct ): """ Saves the specified HLAccount object to the database. If the HLAccount has a non-zero ID, the information is updated, otherwise a new account is inserted. """ try: - fp = open( self.accountsFile , "r" ) + fp = file( self.accountsFile , "r" ) lines = fp.readlines() fp.close() except IOError: lines = [] - if acct.id > 0: + if acct.id > 0L: # Finds the account lines that corresponds to the provided ID and updates the account's info. found = False for l in range( len( lines ) ): @@ -70,7 +68,7 @@ def saveAccount( self , acct ): return False if not found: return False - fp = open( self.accountsFile , "w" ) + fp = file( self.accountsFile , "w" ) fp.write( "".join( lines ) ) fp.close() else: @@ -89,7 +87,7 @@ def saveAccount( self , acct ): if uid > maxuid: maxuid = uid lines.append( "%s\t%s\t%s\t%s\t%s\t%s\t0\t0\t0000-00-00 00:00:00\n" % ( acct.login , int( maxuid ) + 1 , acct.password , acct.name , acct.privs , acct.fileRoot ) ) - fp = open( self.accountsFile , "w" ) + fp = file( self.accountsFile , "w" ) fp.write( "".join( lines ) ) fp.close() return True @@ -97,7 +95,7 @@ def saveAccount( self , acct ): def deleteAccount( self , login ): """ Deletes an account with the specified login. """ try: - fp = open( self.accountsFile , "r" ) + fp = file( self.accountsFile , "r" ) except IOError: return False ( found , lines ) = ( False , fp.readlines() ) @@ -109,14 +107,14 @@ def deleteAccount( self , login ): break if not found: return False - fp = open( self.accountsFile , "w" ) + fp = file( self.accountsFile , "w" ) fp.write( "".join( lines ) ) fp.close() return True def updateAccountStats( self , login , downloaded , uploaded , setDate = False ): try: - fp = open( self.accountsFile , "r" ) + fp = file( self.accountsFile , "r" ) except IOError: return False ( found , lines ) = ( False , fp.readlines() ) @@ -130,15 +128,15 @@ def updateAccountStats( self , login , downloaded , uploaded , setDate = False ) return False else: if ( downloaded > 0 ) or ( uploaded > 0 ): - acctBytesDown = int( acctBytesDown ) + downloaded - acctBytesUp = int( acctBytesUp ) + uploaded + acctBytesDown = long( acctBytesDown ) + downloaded + acctBytesUp = long( acctBytesUp ) + uploaded if setDate: acctLastLogin = datetime.now().strftime( "%Y-%m-%d %H:%M:%S" ) lines[l] = "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n" % ( acctLogin , acctID , acctPass , acctName , acctPrivs , acctFileRoot , acctBytesDown , acctBytesUp , acctLastLogin ) break if not found: return False - fp = open( self.accountsFile , "w" ) + fp = file( self.accountsFile , "w" ) fp.write( "".join( lines ) ) fp.close() return True @@ -154,7 +152,7 @@ def loadNewsPosts( self , limit = 0 ): files = files[len( files ) - limit:len( files )] for f in files: post = HLNewsPost() - fp = open( "%s%s%s" % ( self.newsDir , sep , f ) , "r" ) + fp = file( "%s%s%s" % ( self.newsDir , sep , f ) , "r" ) ( post.id , post.date , post.login , post.nick ) = fp.readline().rstrip( "\n" ).split( "\t" ) post.post = "".join( fp.readlines() ) fp.close() @@ -170,10 +168,10 @@ def saveNewsPost( self , post ): maxid = int( self.regexNewsID.match( listdir( "%s%s" % ( self.newsDir , sep ) )[-1] ).group() ) except: maxid = 0 - if post.id > 0: + if post.id > 0L: maxid = post.id - 1 else: - fp = open( "%s%s%s.txt" % ( self.newsDir , sep , maxid + 1 ) , "w" ) + fp = file( "%s%s%s.txt" % ( self.newsDir , sep , maxid + 1 ) , "w" ) fp.write( "%s\t%s\t%s\t%s\n%s" % ( str( maxid + 1 ) , post.date , post.login , post.nick , post.post ) ) fp.close() return True @@ -181,7 +179,7 @@ def saveNewsPost( self , post ): def checkBanlist( self , addr ): reason = None try: - fp = open( self.banlistFile , "r" ) + fp = file( self.banlistFile , "r" ) except: return reason for l in fp.readlines(): @@ -201,7 +199,7 @@ def logEvent( self , type , event , login = "" , nick = "" , ip = "" ): currentl no DEBUG messages available anyways, so it's redundant. """ return - fp = open( self.logFile , "a" ) + fp = file( self.logFile , "a" ) eventType = "???" try: eventType = self.logTypes[type] diff --git a/server/handlers/AcctHandler.py b/server/handlers/AcctHandler.py index 585e74a..de955ee 100644 --- a/server/handlers/AcctHandler.py +++ b/server/handlers/AcctHandler.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import from shared.HLProtocol import * from shared.HLTypes import * from config import * @@ -21,9 +20,9 @@ def handleAccountRead( self , server , user , packet ): acct = server.database.loadAccount( login ) if not user.hasPriv( PRIV_READ_USERS ): - raise HLException("You cannot read accounts.") + raise HLException , "You cannot read accounts." if acct == None: - raise HLException("Error loading account.") + raise HLException , "Error loading account." reply = HLPacket( HTLS_HDR_TASK , packet.seq ) reply.addString( DATA_LOGIN , HLEncode( acct.login ) ) @@ -40,9 +39,9 @@ def handleAccountModify( self , server , user , packet ): acct = server.database.loadAccount( login ) if not user.hasPriv( PRIV_MODIFY_USERS ): - raise HLException("You cannot modify accounts.") + raise HLException , "You cannot modify accounts." if acct == None: - raise HLException("Invalid account.") + raise HLException , "Invalid account." acct.name = name acct.privs = privs @@ -60,9 +59,9 @@ def handleAccountCreate( self , server , user , packet ): privs = packet.getNumber( DATA_PRIVS , 0 ) if not user.hasPriv( PRIV_CREATE_USERS ): - raise HLException("You cannot create accounts.") + raise HLException , "You cannot create accounts." if server.database.loadAccount( login ) != None: - raise HLException("Login already exists.") + raise HLException , "Login already exists." acct = HLAccount( login ) acct.password = md5( passwd ).hexdigest() @@ -76,8 +75,8 @@ def handleAccountCreate( self , server , user , packet ): def handleAccountDelete( self , server , user , packet ): login = HLEncode( packet.getString( DATA_LOGIN , "" ) ) if not user.hasPriv( PRIV_DELETE_USERS ): - raise HLException("You cannot delete accounts.") + raise HLException , "You cannot delete accounts." if server.database.deleteAccount( login ) < 1: - raise HLException("Error deleting account.") + raise HLException , "Error deleting account." server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) server.logEvent( LOG_TYPE_ACCOUNT , "Deleted account %s." % login , user ) diff --git a/server/handlers/ChatHandler.py b/server/handlers/ChatHandler.py index 16f51f1..4a7ce0d 100644 --- a/server/handlers/ChatHandler.py +++ b/server/handlers/ChatHandler.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import from shared.HLProtocol import * from shared.HLTypes import * from shared.HLUtils import * @@ -38,7 +37,7 @@ def logChat( chat , user ): timestamp = time.localtime() fname = "%04d-%02d-%02d.txt" % ( timestamp[0] , timestamp[1] , timestamp[2] ) path = os.path.join( LOG_DIR , fname ) - out = open( path , "a" ) + out = file( path , "a" ) line = "%02d:%02d:%02d\t%s\t%s\t%s\n" % ( timestamp[3] , timestamp[4] , timestamp[5] , user.account.login , user.nick , chat ) out.write( line ) out.close() @@ -113,7 +112,7 @@ def handleChatCreate( self , server , user , packet ): who = server.getUser( uid ) if not user.hasPriv( PRIV_CREATE_CHATS ): - raise HLException("You cannot create private chats.") + raise HLException , "You cannot create private chats." # First, create the new chat, adding the user. chat = server.createChat() @@ -126,7 +125,7 @@ def handleChatCreate( self , server , user , packet ): reply.addString( DATA_NICK , user.nick ) reply.addNumber( DATA_ICON , user.icon ) reply.addNumber( DATA_STATUS , user.status ) - if user.color >= 0: + if user.color >= 0L: reply.addInt32( DATA_COLOR , user.color ) server.sendPacket( user.uid , reply ) @@ -148,9 +147,9 @@ def handleChatInvite( self , server , user , packet ): who = server.getUser( uid ) if who == None: - raise HLException("Invalid user.") + raise HLException , "Invalid user." if chat == None: - raise HLException("Invalid chat.") + raise HLException , "Invalid chat." if uid == user.uid: # Ignore self invitations. return @@ -158,7 +157,7 @@ def handleChatInvite( self , server , user , packet ): # Ignore all invitations after the first. return if not chat.hasUser( user ): - raise HLException("You are not in this chat.") + raise HLException , "You are not in this chat." if chat.hasUser( who ): # The specified user is already in the chat. return @@ -189,9 +188,9 @@ def handleChatJoin( self , server , user , packet ): chat = server.getChat( ref ) if chat == None: - raise HLException("Invalid chat.") + raise HLException , "Invalid chat." if not chat.hasInvite( user ): - raise HLException("You were not invited to this chat.") + raise HLException , "You were not invited to this chat." # Send a join packet to everyone in the chat. join = HLPacket( HTLS_HDR_CHAT_USER_CHANGE ) @@ -200,7 +199,7 @@ def handleChatJoin( self , server , user , packet ): join.addString( DATA_NICK , user.nick ) join.addNumber( DATA_ICON , user.icon ) join.addNumber( DATA_STATUS , user.status ) - if user.color >= 0: + if user.color >= 0L: join.addInt32( DATA_COLOR , user.color ) for u in chat.users: server.sendPacket( u.uid , join ) diff --git a/server/handlers/FileHandler.py b/server/handlers/FileHandler.py index d21645c..6ebc4a7 100644 --- a/server/handlers/FileHandler.py +++ b/server/handlers/FileHandler.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import from shared.HLProtocol import * from shared.HLTypes import * from config import * @@ -68,15 +67,15 @@ def handleFileList( self , server , user , packet ): path = buildPath( user.account.fileRoot , dir ) if not os.path.exists( path ): - raise HLException("The specified directory does not exist.") + raise HLException , "The specified directory does not exist." if not os.path.isdir( path ): - raise HLException("The specified path is not a directory.") + raise HLException , "The specified path is not a directory." if ( not user.hasPriv( PRIV_VIEW_DROPBOXES ) ) and ( path.upper().find( "DROP BOX" ) >= 0 ): - raise HLException("You are not allowed to view drop boxes.") + raise HLException , "You are not allowed to view drop boxes." fn = path.split("/")[-1] # gets folder name kang #beware of non exact matches!! FIXME if (path.upper().find("DROP BOX") >= 0) and (fn.upper()[0:4] != "DROP") and (fn.upper().find(user.account.login.upper()) < 0): - raise HLException("Sorry, this is not your dropbox. You are not allowed to view it") + raise HLException, "Sorry, this is not your dropbox. You are not allowed to view it" reply = HLPacket( HTLS_HDR_TASK , packet.seq ) files = os.listdir( path ) @@ -102,9 +101,9 @@ def handleFileDownload( self , server , user , packet ): path = buildPath( user.account.fileRoot , dir , name ) if not user.hasPriv( PRIV_DOWNLOAD_FILES ): - raise HLException("You are not allowed to download files.") + raise HLException , "You are not allowed to download files." if not os.path.exists( path ): - raise HLException("Specified file does not exist.") + raise HLException , "Specified file does not exist." offset = resume.forkOffset( HLCharConst( "DATA" ) ) xfer = server.fileserver.addDownload( user.uid , path , offset ) @@ -122,21 +121,21 @@ def handleFileUpload( self , server , user , packet ): options = packet.getNumber( DATA_XFEROPTIONS , 0 ) if not user.hasPriv( PRIV_UPLOAD_FILES ): - raise HLException("You are not allowed to upload files.") + raise HLException , "You are not allowed to upload files." path = buildPath( user.account.fileRoot , dir , name ) if os.path.exists( path ): # If this path exists, theres already a complete file. - raise HLException("File already exists.") + raise HLException , "File already exists." if ( not user.hasPriv( PRIV_UPLOAD_ANYWHERE ) ) and ( path.upper().find( "UPLOAD" ) < 0 ): - raise HLException("You must upload to an upload directory.") + raise HLException , "You must upload to an upload directory." # Make sure we have enough disk space to accept the file. upDir = buildPath( user.account.fileRoot , dir ) info = os.statvfs( upDir ) free = info[F_BAVAIL] * info[F_FRSIZE] if size > free: - raise HLException("Insufficient disk space.") + raise HLException , "Insufficient disk space." # All uploads in progress should have this extension. path += ".hpf" @@ -158,9 +157,9 @@ def handleFileDelete( self , server , user , packet ): path = buildPath( user.account.fileRoot , dir , name ) if not user.hasPriv( PRIV_DELETE_FILES ): - raise HLException("You are not allowed to delete files.") + raise HLException , "You are not allowed to delete files." if not os.path.exists( path ): - raise HLException("Specified file does not exist.") + raise HLException , "Specified file does not exist." if os.path.isdir( path ): # First, recursively delete everything inside the directory. @@ -182,11 +181,11 @@ def handleFolderCreate( self , server , user , packet ): path = buildPath( user.account.fileRoot , dir , name ) if not user.hasPriv( PRIV_CREATE_FOLDERS ): - raise HLException("You are not allowed to create folders.") + raise HLException , "You are not allowed to create folders." if os.path.exists( path ): - raise HLException("Specified directory/file already exists.") + raise HLException , "Specified directory/file already exists." - os.mkdir( path , 0o755 ) + os.mkdir( path , 0755 ) server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) def handleFileMove( self , server , user , packet ): @@ -198,11 +197,11 @@ def handleFileMove( self , server , user , packet ): newPath = buildPath( user.account.fileRoot , newDir , name ) if not user.hasPriv( PRIV_MOVE_FILES ): - raise HLException("You are not allowed to move files.") + raise HLException , "You are not allowed to move files." if not os.path.exists( oldPath ): - raise HLException("Invalid file or directory.") + raise HLException , "Invalid file or directory." if os.path.exists( newPath ): - raise HLException("The specified file already exists.") + raise HLException , "The specified file already exists." os.rename( oldPath , newPath ) server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) @@ -213,7 +212,7 @@ def handleFileGetInfo( self , server , user , packet ): path = buildPath( user.account.fileRoot , dir , name ) if not os.path.exists( path ): - raise HLException("No such file or directory.") + raise HLException , "No such file or directory." info = HLPacket( HTLS_HDR_TASK , packet.seq ) info.addString( DATA_FILENAME , name ) @@ -228,15 +227,15 @@ def handleFileSetInfo( self , server , user , packet ): newName = packet.getString( DATA_NEWFILE , oldName ) if ( oldName != newName ) and ( not user.hasPriv( PRIV_RENAME_FILES ) ): - raise HLException("You cannot rename files.") + raise HLException , "You cannot rename files." oldPath = buildPath( user.account.fileRoot , dir , oldName ) newPath = buildPath( user.account.fileRoot , dir , newName ) if not os.path.exists( oldPath ): - raise HLException("Invalid file or directory.") + raise HLException , "Invalid file or directory." if os.path.exists( newPath ): - raise HLException("The specified file already exists.") + raise HLException , "The specified file already exists." os.rename( oldPath , newPath ) server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) diff --git a/server/handlers/IconHandler.py b/server/handlers/IconHandler.py index 45d0870..f390e4e 100644 --- a/server/handlers/IconHandler.py +++ b/server/handlers/IconHandler.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import from shared.HLProtocol import * from shared.HLTypes import * from struct import pack @@ -26,7 +25,7 @@ def handleIconSet( self , server , user , packet ): user.gif = packet.getBinary( DATA_GIFICON , "" ) if len( user.gif ) > MAX_GIF_SIZE: user.gif = "" - raise HLException("GIF icon too large.") + raise HLException , "GIF icon too large." server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) change = HLPacket( HTLS_HDR_ICON_CHANGE ) change.addNumber( DATA_UID , user.uid ) @@ -41,4 +40,4 @@ def handleIconGet( self , server , user , packet ): icon.addBinary( DATA_GIFICON , info.gif ) server.sendPacket( user.uid , icon ) else: - raise HLException("Invalid user.") + raise HLException , "Invalid user." diff --git a/server/handlers/NewsHandler.py b/server/handlers/NewsHandler.py index c4b54ca..1265579 100644 --- a/server/handlers/NewsHandler.py +++ b/server/handlers/NewsHandler.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import from shared.HLProtocol import * from shared.HLTypes import * from config import * @@ -29,7 +28,7 @@ def handleNewsGet( self , server , user , packet ): news.addString( DATA_STRING , str ) server.sendPacket( user.uid , news ) else: - raise HLException("You are not allowed to read the news.") + raise HLException , "You are not allowed to read the news." def handleNewsPost( self , server , user , packet ): str = packet.getString( DATA_STRING , "" ) @@ -42,4 +41,4 @@ def handleNewsPost( self , server , user , packet ): server.broadcastPacket( notify , PRIV_READ_NEWS ) server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) else: - raise HLException("You are not allowed to post news.") + raise HLException , "You are not allowed to post news." diff --git a/server/handlers/UserHandler.py b/server/handlers/UserHandler.py index 0701002..07c63ec 100644 --- a/server/handlers/UserHandler.py +++ b/server/handlers/UserHandler.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import from shared.HLProtocol import * from shared.HLUtils import * from shared.HLTypes import * @@ -29,22 +28,22 @@ def handleUserDisconnected( self , server , user ): def handleLogin( self , server , user , packet ): if user.isLoggedIn(): - raise HLException( "You are already logged in." , False) + raise HLException , ( "You are already logged in." , False ) login = HLEncode( packet.getString( DATA_LOGIN , HLEncode( "guest" ) ) ) password = HLEncode( packet.getString( DATA_PASSWORD , "" ) ) reason = server.checkForBan( user.ip ) if reason != None: - raise HLException( "You are banned: %s" % reason , True) + raise HLException , ( "You are banned: %s" % reason , True ) user.account = server.database.loadAccount( login ) if user.account == None: - raise HLException( "Login is incorrect." , True) + raise HLException , ( "Login is incorrect." , True ) if user.account.password != md5( password ).hexdigest(): user.nick = packet.getString( DATA_NICK , "unnamed" ) server.logEvent( LOG_TYPE_LOGIN , "Login failure" , user ) - raise HLException( "Password is incorrect." , True) + raise HLException , ( "Password is incorrect." , True ) if user.account.fileRoot == "": user.account.fileRoot = FILE_ROOT @@ -109,7 +108,7 @@ def handleUserChange( self , server , user , packet ): change.addNumber( DATA_ICON , user.icon ) change.addNumber( DATA_STATUS , user.status ) change.addString ( DATA_IRC_OLD_NICK , oldnick ) - if user.color >= 0: + if user.color >= 0L: change.addInt32( DATA_COLOR , user.color ) server.broadcastPacket( change ) @@ -125,12 +124,12 @@ def handleUserInfo( self , server , user , packet ): u = server.getUser( uid ) if not user.hasPriv( PRIV_USER_INFO ) and ( uid != user.uid ): - raise HLException("You cannot view user information.") + raise HLException , "You cannot view user information." if u == None: - raise HLException("Invalid user.") + raise HLException , "Invalid user." # Format the user's idle time. - secs = int( time.time() - u.lastPacketTime ) + secs = long( time.time() - u.lastPacketTime ) days = secs / 86400 secs -= ( days * 86400 ) hours = secs / 3600 @@ -168,9 +167,9 @@ def handleMessage( self , server , user , packet ): str = packet.getString( DATA_STRING , "" ) if not user.hasPriv( PRIV_SEND_MESSAGES ): - raise HLException("You are not allowed to send messages.") + raise HLException , "You are not allowed to send messages." if server.getUser( uid ) == None: - raise HLException("Invalid user.") + raise HLException , "Invalid user." msg = HLPacket( HTLS_HDR_MSG ) msg.addNumber( DATA_UID , user.uid ) @@ -185,11 +184,11 @@ def handleUserKick( self , server , user , packet ): who = server.getUser( uid ) if not user.hasPriv( PRIV_KICK_USERS ): - raise HLException("You are not allowed to disconnect users.") + raise HLException , "You are not allowed to disconnect users." if who == None: - raise HLException("Invalid user.") + raise HLException , "Invalid user." if who.account.login != user.account.login and who.hasPriv( PRIV_KICK_PROTECT ): - raise HLException("%s cannot be disconnected." % who.nick) + raise HLException , "%s cannot be disconnected." % who.nick action = "Kicked" if ban > 0: @@ -203,7 +202,7 @@ def handleUserKick( self , server , user , packet ): def handleBroadcast( self , server , user , packet ): str = packet.getString( DATA_STRING , "" ) if not user.hasPriv( PRIV_BROADCAST ): - raise HLException("You cannot broadcast messages.") + raise HLException , "You cannot broadcast messages." broadcast = HLPacket( HTLS_HDR_BROADCAST ) broadcast.addString( DATA_STRING , str ) server.broadcastPacket( broadcast ) diff --git a/server/handlers/commands/0wn.py b/server/handlers/commands/0wn.py index 0490324..2819930 100644 --- a/server/handlers/commands/0wn.py +++ b/server/handlers/commands/0wn.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import from shared.HLProtocol import * def handle( server , user , arg , ref): diff --git a/server/handlers/commands/away.py b/server/handlers/commands/away.py index 5ba0abb..499912f 100644 --- a/server/handlers/commands/away.py +++ b/server/handlers/commands/away.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import from shared.HLProtocol import * def handle( server , user , args , ref ): diff --git a/server/handlers/commands/broadcast.py b/server/handlers/commands/broadcast.py index 3296da3..1516c4f 100644 --- a/server/handlers/commands/broadcast.py +++ b/server/handlers/commands/broadcast.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import from shared.HLProtocol import * def handle( server , user , arg , ref ): diff --git a/server/handlers/commands/color.py b/server/handlers/commands/color.py index c4b9843..c3c352e 100644 --- a/server/handlers/commands/color.py +++ b/server/handlers/commands/color.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import from shared.HLProtocol import * def handle( server , user , arg , ref ): if len( arg ) > 0: diff --git a/server/handlers/commands/find.py b/server/handlers/commands/find.py index 3955088..912c0d7 100644 --- a/server/handlers/commands/find.py +++ b/server/handlers/commands/find.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import from shared.HLProtocol import * import os diff --git a/server/handlers/commands/me.py b/server/handlers/commands/me.py index 04030e2..9fcbb6f 100644 --- a/server/handlers/commands/me.py +++ b/server/handlers/commands/me.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import from shared.HLProtocol import * def handle( server , user , args , ref ): diff --git a/server/handlers/commands/news.py b/server/handlers/commands/news.py index 052c135..103781c 100644 --- a/server/handlers/commands/news.py +++ b/server/handlers/commands/news.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import from shared.HLProtocol import * from server.handlers.NewsHandler import * diff --git a/server/handlers/commands/uptime.py b/server/handlers/commands/uptime.py index 03dd6ec..667b47f 100644 --- a/server/handlers/commands/uptime.py +++ b/server/handlers/commands/uptime.py @@ -1,9 +1,8 @@ -from __future__ import absolute_import from shared.HLProtocol import * import time def handle( server , user , args , ref ): - secs = int( time.time() - server.startTime ) + secs = long( time.time() - server.startTime ) days = secs / 86400 secs -= ( days * 86400 ) hours = secs / 3600 diff --git a/server/handlers/commands/xfers.py b/server/handlers/commands/xfers.py index 81713ef..f0daf00 100644 --- a/server/handlers/commands/xfers.py +++ b/server/handlers/commands/xfers.py @@ -1,10 +1,9 @@ -from __future__ import absolute_import from shared.HLProtocol import * def handle( server , user , args , ref ): if user.hasPriv( PRIV_USER_INFO ): str = "" - if len( list(server.fileserver.transfers.values()) ) == 0: + if len( server.fileserver.transfers.values() ) == 0: str += "\r > No file transfers in progress." else: str += "\r > File transfers:" diff --git a/shared/HLProtocol.py b/shared/HLProtocol.py index 2661f20..e3bcc0d 100644 --- a/shared/HLProtocol.py +++ b/shared/HLProtocol.py @@ -1,10 +1,7 @@ -from __future__ import absolute_import -from __future__ import print_function from struct import * from config import * import random import re -from six.moves import range def buildTrackerClientPacket(name, description, port, users): """Builds an info packet incorporating the specified name @@ -16,421 +13,421 @@ def buildTrackerClientPacket(name, description, port, users): name, pack('b', len(description)), description) def ircCheckUserNick( user ): - """ Check for nick conformance to IRC standards and rename a correct one """ - nickname = "" - nickname = user.nick.replace(" ", "") - nickname = re.search('^([0-9-A-z]*)', nickname).group(0) - nickname = str(user.uid)+"_"+nickname - return nickname + """ Check for nick conformance to IRC standards and rename a correct one """ + nickname = "" + nickname = user.nick.replace(" ", "") + nickname = re.search('^([0-9-A-z]*)', nickname).group(0) + nickname = str(user.uid)+"_"+nickname + return nickname def HLCharConst( str ): - """ Returns the numeric equivalent of a 4-character string (OSType in classic Mac OS). - Used for file types, creator codes, and magic numbers. """ - if len( str ) != 4: - return 0 - return 0 + ( ord( str[0] ) << 24 ) + ( ord( str[1] ) << 16 ) + ( ord( str[2] ) << 8 ) + ord( str[3] ) + """ Returns the numeric equivalent of a 4-character string (OSType in classic Mac OS). + Used for file types, creator codes, and magic numbers. """ + if len( str ) != 4: + return 0 + return 0L + ( ord( str[0] ) << 24 ) + ( ord( str[1] ) << 16 ) + ( ord( str[2] ) << 8 ) + ord( str[3] ) def HLEncode( str ): - """ Encodes a string based on hotline specifications; basically just - XORs each byte of the string. Used for logins and passwords. """ - if str != None: - out = "" - for k in range( len( str ) ): - out += chr( 255 - ord( str[k] ) ) - return out - return None + """ Encodes a string based on hotline specifications; basically just + XORs each byte of the string. Used for logins and passwords. """ + if str != None: + out = "" + for k in range( len( str ) ): + out += chr( 255 - ord( str[k] ) ) + return out + return None def isPingType( type ): - """ Returns True if the packet type can be considered a ping packet, i.e. - the server should not consider it when determining idle behavior. """ - if type == HTLC_HDR_PING: - return True - elif type == HTLC_HDR_USER_LIST: - return True - elif type == HTLC_HDR_USER_INFO: - return True - elif type == HTLC_HDR_ICON_GET: - return True - else: - return False + """ Returns True if the packet type can be considered a ping packet, i.e. + the server should not consider it when determining idle behavior. """ + if type == HTLC_HDR_PING: + return True + elif type == HTLC_HDR_USER_LIST: + return True + elif type == HTLC_HDR_USER_INFO: + return True + elif type == HTLC_HDR_ICON_GET: + return True + else: + return False class HLObject: - def __init__( self , type , data ): - self.type = type - self.data = data - - def __str__( self ): - return "HLObject [type=%d,size=%d]" % ( self.type , len( self.data ) ) - - def getObjects( self, type ): - objs = [] - for obj in self.objs: - if obj.type == type: - objs.append( obj ) - return objs - - def flatten( self ): - """ Returns a flattened, byte-swapped string for this hotline object. """ - return pack( "!2H" , self.type , len( self.data ) ) + self.data + def __init__( self , type , data ): + self.type = type + self.data = data + + def __str__( self ): + return "HLObject [type=%d,size=%d]" % ( self.type , len( self.data ) ) + + def getObjects( self, type ): + objs = [] + for obj in self.objs: + if obj.type == type: + objs.append( obj ) + return objs + + def flatten( self ): + """ Returns a flattened, byte-swapped string for this hotline object. """ + return pack( "!2H" , self.type , len( self.data ) ) + self.data class HLPacket: - def __init__( self , type = 0 , seq = 0 , flags = 0 , isIRC = 0 ): - self.objs = [] - self.type = type - self.seq = seq - self.flags = flags - self.isIRC = isIRC - self.server = None - self.irctrap = "" - self.connID = 0 - - def __str__( self ): - s = "HLPacket [type=%x,seq=%d,flags=%d]" % ( self.type , self.seq , self.flags ) - for obj in self.objs: - s += "\n " + str( obj ) - return s - - def parse( self , data ): - """ Tries to parse an entire packet from the data passed in. If successful, - returns the number of bytes parsed, otherwise returns 0. """ - if self.isIRC: - if len( data ) == 0: - return 0 - line = data.split( "\n" )[0] - if line == "": - line = data.split( "\r" )[0] - cmd = line.split( " " )[0].upper() - if cmd == "NICK": - self.type = HTLC_HDR_USER_CHANGE - if line.split( " " )[1].startswith( ":" ): - self.addString( DATA_NICK , line.split( " " )[1][1:]) - else: - self.addString( DATA_NICK , line.split( " " )[1] ) - self.addNumber( DATA_ICON , 500 ) - self.addNumber( DATA_COLOR , 1 ) - - elif cmd == "PING": - self.type = HTLC_HDR_PING - - elif cmd.startswith("LAGTIME"): - return len( line ) - - elif cmd == "PRIVMSG": - # Chat - if line.split( " " )[1].startswith("#"): - try: - if line.split( " ", 2)[2].startswith( ":" ): - reply = line.split( " " , 2 )[2][1:] - else: - reply = line.split( " " , 2 )[2] - chatid = line.split( " " )[1].replace( "#" , "" ) - if chatid != "public": - chatid = int( chatid ) - else: - chatid = 0 - self.type = HTLC_HDR_CHAT - self.addString( DATA_STRING , reply ) - self.addNumber( DATA_OPTION , 0 ) - self.addNumber( DATA_CHATID , chatid ) - except: - #TODO Handle condition or throw away ? - print("handle that") - # Private Message - else: - # Authentication "bot" - if line.split( " " , 2 )[1] == "loginserv": - self.type = HTLC_HDR_LOGIN - loginStr = line.split(" ", 3)[2] - if loginStr.startswith(":"): - # In IRC private messages not containing space separated text - # are not prefixed with a colon character ":". This is important - # for passwordless login to loginserv, i.e. Guest login. - loginStr = loginStr[1:] - self.addString( DATA_LOGIN , HLEncode( loginStr ) ) - try: - self.addString( DATA_PASSWORD , HLEncode( line.split( " " , 4 )[3] ) ) - except IndexError: - # No password provided, but HL can handle blank passwords, try that. - self.addString(DATA_PASSWORD, HLEncode("")) - print("no password provided..") - else: - try: - uid = int( line.split( " " , 2 )[1].split( "_" , 1 )[0] ) - self.type = HTLC_HDR_MSG - self.addNumber( DATA_UID , uid ) - self.addString( DATA_STRING , line.split( " " , 2 )[2][1:] ) - except: - # Throw an error, needs HLException - print("handle that") - elif cmd == "WHO": - self.type = HTLC_HDR_USER_LIST - - elif cmd == "WHOIS": - try: - uid = int( line.split( " " , 2 )[1].split( "_" , 1 )[0] ) - except: - return 0 - self.type = HTLC_HDR_USER_INFO - self.addNumber( DATA_UID , uid ) - - elif cmd == "KICK": - try: - uid = int( line.split( " " , 2 )[2].split( "_" , 1 )[0] ) - except: - return len( line ) - self.type = HTLC_HDR_KICK - self.addNumber( DATA_UID , uid ) - self.addNumber( DATA_BAN , 0 ) - - elif cmd == "MODE": - return len( line ) - - elif cmd == "JOIN": - #TODO if chat does not exists, send a HTLC_HDR_CHAT_CREATE - try: - chatid = int( line.split( "#" )[1] ) - except: - return len( line ) - self.type = HTLC_HDR_CHAT_JOIN - self.addNumber( DATA_CHATID , chatid ) - - - elif cmd == "PART": - try: - chatid = int( line.split( "#" )[1] ) - except: - return len( line ) - self.type = HTLC_HDR_CHAT_LEAVE - self.addNumber( DATA_CHATID , chatid ) - - elif cmd == "INVITE": - uid = int( line.split( " " , 2 )[1].split( "_" , 1 )[0] ) - chatid = int ( line.split( " " , 3 )[2].replace( "#" , "" ) ) - self.type = HTLC_HDR_CHAT_INVITE - self.addNumber( DATA_CHATID , chatid ) - self.addNumber( DATA_UID , uid ) - - elif cmd == "QUIT": - self.server.removeConnection( self.connID ) - - else: - self.irctrap = cmd - - return len( line ) - # This is the Hotline code now. - else: - if len( data ) < 20: - return 0 - ( self.type , self.seq , self.flags , size , check ) = unpack( "!5L", data[0:20] ) - if ( len( data ) - 20 ) < size: - return 0 - if size >= 2: - pos = 20 - count = unpack( "!H" , data[pos:pos+2] )[0] - pos += 2 - while count > 0: - ( obj_type , obj_size ) = unpack( "!2H", data[pos:pos+4] ) - pos += 4 - obj = HLObject( obj_type , data[pos:pos+obj_size] ) - self.addObject( obj ) - pos += obj_size - count = count - 1 - return 20 + size - - def addObject( self , obj ): - """ Adds a HLObject to the object list. """ - self.objs.append( obj ) - - def addString( self , type , data ): - """ Wraps a string in a HLObject and adds it. """ - obj = HLObject( type , data ) - self.addObject( obj ) - - def addNumber( self , type , data ): - """ Wraps a number in a HLObject, byte-swapping it based - on its magnitude, and adds it. """ - num = int( data ) - packed = "" - if num < ( 1 << 16 ): - packed = pack( "!H" , num ) - elif num < ( 1 << 32 ): - packed = pack( "!L" , num ) - elif num < ( 1 << 64 ): - packed = pack( "!Q" , num ) - obj = HLObject( type , packed ) - self.addObject( obj ) - - def addInt16( self , type , data ): - """ Adds a 16-bit byte-swapped number as a HLObject. """ - num = int( data ) - obj = HLObject( type , pack( "!H" , num ) ) - self.addObject( obj ) - - def addInt32( self , type , data ): - """ Adds a 32-bit byte-swapped number as a HLObject. """ - num = int( data ) - obj = HLObject( type , pack( "!L" , num ) ) - self.addObject( obj ) - - def addInt64( self , type , data ): - """ Adds a 64-bit byte-swapped number as a HLObject. """ - num = int( data ) - obj = HLObject( type , pack( "!Q" , num ) ) - self.addObject( obj ) - - def addBinary( self , type , data ): - """ Functionally equivalent to addString. """ - self.addString( type , data ) - - def getString( self , type , default = None ): - """ Returns a string for the specified object type, or - a default value when the specified type is not present. """ - for obj in self.objs: - if ( obj.type == type ) and ( len( obj.data ) > 0 ): - return obj.data - return default - - def getNumber( self , type , default = None ): - """ Returns a byte-swapped number for the specified object type, or - a default value when the specified type is not present. """ - for obj in self.objs: - if obj.type == type: - if len( obj.data ) == 2: - return unpack( "!H" , obj.data )[0] - elif len( obj.data ) == 4: - return unpack( "!L" , obj.data )[0] - elif len( obj.data ) == 8: - return unpack( "!Q" , obj.data )[0] - return default - - def getBinary( self , type , default = None ): - """ Functionally equivalent to getString. """ - return self.getString( type , default ) - - def flatten( self , user ): - """ Returns a flattened string of this packet and embedded objects. """ - data = "" - if self.isIRC: - if self.type == HTLS_HDR_PING: - data = "PONG :"+IRC_SERVER_NAME+"\r\n" - - elif self.type == HTLS_HDR_CHAT: - try: - chat = self.getString(DATA_STRING).split( ": " , 1 )[1].replace( "\r" , " " ) - except IndexError: - chat = self.getString(DATA_STRING).replace( "\r" , " " ) - try: - ( c , u ) = self.server.clients[self.getNumber( DATA_UID )] - # this should be hanlded already elsewhere but forgot :( - if user.uid == u.uid: - return data - mynick = ircCheckUserNick( u ) - mynick = u.nick.replace( " " , "" ) - except KeyError: - mynick = "PHXD" - chatid = self.getNumber( DATA_CHATID ) - if chatid == None: - channel = "public" - else: - channel = str(chatid) - data = ":"+mynick+" PRIVMSG #"+channel+" :"+chat[1:]+"\r\n" - - elif self.type == HTLS_HDR_MSG: - chat = self.getString( DATA_STRING ) - try: - ( c , u ) = self.server.clients[self.getNumber( DATA_UID )] - mynick = ircCheckUserNick( u ) - myip = u.ip - except KeyError: - mynick = "PHXD" - myip = "127.0.0.1" - data = ":"+mynick+"!~"+mynick+"@"+myip+" PRIVMSG "+user.nick+" :"+chat.replace( "\r" , " " )+"\r\n" - - elif self.type == HTLS_HDR_USER_LEAVE: - ( c, u ) = self.server.clients[self.getNumber( DATA_UID )] - mynick = ircCheckUserNick( u ) - if u.isIRC: - proto = "IRC" - else: - proto = "Hotline" - data = ":"+mynick+"!~"+mynick+"@"+u.ip+" PART #public :Client disconnected from "+proto+"\r\n" - - elif self.type == HTLS_HDR_USER_CHANGE: - ( c, u ) = self.server.clients[self.getNumber( DATA_UID )] - mynick = ircCheckUserNick( u ) - oldnick = self.getString( DATA_IRC_OLD_NICK ) - if not u.valid: # Login ? If so, force join the public channel - data = ":"+mynick+"!~"+mynick+"@"+u.ip+" JOIN :#public\r\n" - else: - if u.nick == oldnick: - data = "NOTICE *: *** "+oldnick+" changed status to "+str( u.status )+"\r\n" - else: - if user.uid == u.uid: - data = ":"+oldnick+"!~"+oldnick+"@"+u.ip+" NICK :"+user.nick+"\r\n" - else: - data = ":"+str( u.uid )+"_"+oldnick.replace( " " , "" )+" NICK "+ircCheckUserNick( u )+"\r\n" - - elif self.type == HTLS_HDR_TASK: - # check for HTLC_HDR_USER_LIST reply: - if self.getBinary( DATA_USER ): - keys = list(self.server.clients.keys()) - keys.sort() - for uid in keys: - ( c , u ) = self.server.clients[uid] - mynick = ircCheckUserNick( u ) - if u.isLoggedIn(): - data += ":"+IRC_SERVER_NAME+" 352 "+mynick+" #public "+mynick+" "+u.ip+" "+IRC_SERVER_NAME+" "+u.account.name.replace( " ", "_" )+"\r\n" - data += ":"+IRC_SERVER_NAME+" 315 "+user.nick+" #public :End of /WHO list.\r\n" - - # HTLC_HDR_USER_INFO then :) - elif self.getString( DATA_NICK ): - uid = self.getNumber( DATA_UID ) - ( c , u ) = self.server.clients[uid] - mynick = ircCheckUserNick( u ) - info = self.getString( DATA_STRING ) - - idle = info.split( "idle: " )[1].split( '\r' )[0] - if u.isIRC: - proto = "IRC" - else: - proto = "Hotline" - - data = ":"+IRC_SERVER_NAME+" 311 "+user.nick+" "+mynick+" ~"+mynick+" "+u.ip+" * :"+u.account.name.replace(" ", "_")+"\r\n" - data += ":"+IRC_SERVER_NAME+" 312 "+user.nick+" "+mynick+" "+IRC_SERVER_NAME+" :http//chatonly.org\r\n" - data += ":"+IRC_SERVER_NAME+" 320 "+user.nick+" "+mynick+" :Using protocol "+proto+"\r\n" - data += ":"+IRC_SERVER_NAME+" 317 "+user.nick+" "+mynick+" "+idle+" 0 :seconds idle, signon time\r\n" - data += ":"+IRC_SERVER_NAME+" 318 "+user.nick+" "+mynick+" :End of /WHOIS list.\r\n" - - elif self.type == HTLS_HDR_CHAT_INVITE: - chatid = self.getNumber( DATA_CHATID) - uid = self.getNumber( DATA_UID ) - ( c , u ) = self.server.clients[uid] - mynick = ircCheckUserNick( u ) - data = ":PHXD PRIVMSG #public :"+mynick+" invites you to join private chat #"+str(chatid)+"\r\n" - elif self.type == HTLS_HDR_CHAT_USER_LEAVE: - chatid = self.getNumber( DATA_CHATID) - uid = self.getNumber( DATA_UID ) - ( c , u ) = self.server.clients[uid] - mynick = ircCheckUserNick( u ) - data = ":"+mynick+"!~"+mynick+"@"+u.ip+" PART #"+str( chatid )+" :Client left channel #"+str( chatid )+"\r\n" - - elif self.type == HTLS_HDR_CHAT_USER_CHANGE: - # Basically this is a JOIN packet for a private chat - chatid = self.getNumber( DATA_CHATID) - uid = self.getNumber( DATA_UID ) - ( c , u ) = self.server.clients[uid] - mynick = ircCheckUserNick( self.getString( DATA_NICK ) ) - data = ":"+mynick+"!~"+mynick+"@"+u.ip+" JOIN :#"+str(chatid)+"\r\n" - - elif self.type == HTLS_HDR_BROADCAST: - data = "NOTICE * :*** BROADCAST: "+self.getString( DATA_STRING )+"\r\n" - - return data - # Normal Hotline processing - else: - for obj in self.objs: - data += obj.flatten() - return pack( "!5L1H" , self.type , self.seq , self.flags , len( data ) + 2 , len( data ) + 2 , len( self.objs ) ) + data + def __init__( self , type = 0 , seq = 0 , flags = 0 , isIRC = 0 ): + self.objs = [] + self.type = type + self.seq = seq + self.flags = flags + self.isIRC = isIRC + self.server = None + self.irctrap = "" + self.connID = 0 + + def __str__( self ): + s = "HLPacket [type=%x,seq=%d,flags=%d]" % ( self.type , self.seq , self.flags ) + for obj in self.objs: + s += "\n " + str( obj ) + return s + + def parse( self , data ): + """ Tries to parse an entire packet from the data passed in. If successful, + returns the number of bytes parsed, otherwise returns 0. """ + if self.isIRC: + if len( data ) == 0: + return 0 + line = data.split( "\n" )[0] + if line == "": + line = data.split( "\r" )[0] + cmd = line.split( " " )[0].upper() + if cmd == "NICK": + self.type = HTLC_HDR_USER_CHANGE + if line.split( " " )[1].startswith( ":" ): + self.addString( DATA_NICK , line.split( " " )[1][1:]) + else: + self.addString( DATA_NICK , line.split( " " )[1] ) + self.addNumber( DATA_ICON , 500 ) + self.addNumber( DATA_COLOR , 1 ) + + elif cmd == "PING": + self.type = HTLC_HDR_PING + + elif cmd.startswith("LAGTIME"): + return len( line ) + + elif cmd == "PRIVMSG": + # Chat + if line.split( " " )[1].startswith("#"): + try: + if line.split( " ", 2)[2].startswith( ":" ): + reply = line.split( " " , 2 )[2][1:] + else: + reply = line.split( " " , 2 )[2] + chatid = line.split( " " )[1].replace( "#" , "" ) + if chatid != "public": + chatid = int( chatid ) + else: + chatid = 0 + self.type = HTLC_HDR_CHAT + self.addString( DATA_STRING , reply ) + self.addNumber( DATA_OPTION , 0 ) + self.addNumber( DATA_CHATID , chatid ) + except: + #TODO Handle condition or throw away ? + print "handle that" + # Private Message + else: + # Authentication "bot" + if line.split( " " , 2 )[1] == "loginserv": + self.type = HTLC_HDR_LOGIN + loginStr = line.split(" ", 3)[2] + if loginStr.startswith(":"): + # In IRC private messages not containing space separated text + # are not prefixed with a colon character ":". This is important + # for passwordless login to loginserv, i.e. Guest login. + loginStr = loginStr[1:] + self.addString( DATA_LOGIN , HLEncode( loginStr ) ) + try: + self.addString( DATA_PASSWORD , HLEncode( line.split( " " , 4 )[3] ) ) + except IndexError: + # No password provided, but HL can handle blank passwords, try that. + self.addString(DATA_PASSWORD, HLEncode("")) + print "no password provided.." + else: + try: + uid = int( line.split( " " , 2 )[1].split( "_" , 1 )[0] ) + self.type = HTLC_HDR_MSG + self.addNumber( DATA_UID , uid ) + self.addString( DATA_STRING , line.split( " " , 2 )[2][1:] ) + except: + # Throw an error, needs HLException + print "handle that" + elif cmd == "WHO": + self.type = HTLC_HDR_USER_LIST + + elif cmd == "WHOIS": + try: + uid = int( line.split( " " , 2 )[1].split( "_" , 1 )[0] ) + except: + return 0 + self.type = HTLC_HDR_USER_INFO + self.addNumber( DATA_UID , uid ) + + elif cmd == "KICK": + try: + uid = int( line.split( " " , 2 )[2].split( "_" , 1 )[0] ) + except: + return len( line ) + self.type = HTLC_HDR_KICK + self.addNumber( DATA_UID , uid ) + self.addNumber( DATA_BAN , 0 ) + + elif cmd == "MODE": + return len( line ) + + elif cmd == "JOIN": + #TODO if chat does not exists, send a HTLC_HDR_CHAT_CREATE + try: + chatid = int( line.split( "#" )[1] ) + except: + return len( line ) + self.type = HTLC_HDR_CHAT_JOIN + self.addNumber( DATA_CHATID , chatid ) + + + elif cmd == "PART": + try: + chatid = int( line.split( "#" )[1] ) + except: + return len( line ) + self.type = HTLC_HDR_CHAT_LEAVE + self.addNumber( DATA_CHATID , chatid ) + + elif cmd == "INVITE": + uid = int( line.split( " " , 2 )[1].split( "_" , 1 )[0] ) + chatid = int ( line.split( " " , 3 )[2].replace( "#" , "" ) ) + self.type = HTLC_HDR_CHAT_INVITE + self.addNumber( DATA_CHATID , chatid ) + self.addNumber( DATA_UID , uid ) + + elif cmd == "QUIT": + self.server.removeConnection( self.connID ) + + else: + self.irctrap = cmd + + return len( line ) + # This is the Hotline code now. + else: + if len( data ) < 20: + return 0 + ( self.type , self.seq , self.flags , size , check ) = unpack( "!5L", data[0:20] ) + if ( len( data ) - 20 ) < size: + return 0 + if size >= 2: + pos = 20 + count = unpack( "!H" , data[pos:pos+2] )[0] + pos += 2 + while count > 0: + ( obj_type , obj_size ) = unpack( "!2H", data[pos:pos+4] ) + pos += 4 + obj = HLObject( obj_type , data[pos:pos+obj_size] ) + self.addObject( obj ) + pos += obj_size + count = count - 1 + return 20 + size + + def addObject( self , obj ): + """ Adds a HLObject to the object list. """ + self.objs.append( obj ) + + def addString( self , type , data ): + """ Wraps a string in a HLObject and adds it. """ + obj = HLObject( type , data ) + self.addObject( obj ) + + def addNumber( self , type , data ): + """ Wraps a number in a HLObject, byte-swapping it based + on its magnitude, and adds it. """ + num = long( data ) + packed = "" + if num < ( 1L << 16 ): + packed = pack( "!H" , num ) + elif num < ( 1L << 32 ): + packed = pack( "!L" , num ) + elif num < ( 1L << 64 ): + packed = pack( "!Q" , num ) + obj = HLObject( type , packed ) + self.addObject( obj ) + + def addInt16( self , type , data ): + """ Adds a 16-bit byte-swapped number as a HLObject. """ + num = long( data ) + obj = HLObject( type , pack( "!H" , num ) ) + self.addObject( obj ) + + def addInt32( self , type , data ): + """ Adds a 32-bit byte-swapped number as a HLObject. """ + num = long( data ) + obj = HLObject( type , pack( "!L" , num ) ) + self.addObject( obj ) + + def addInt64( self , type , data ): + """ Adds a 64-bit byte-swapped number as a HLObject. """ + num = long( data ) + obj = HLObject( type , pack( "!Q" , num ) ) + self.addObject( obj ) + + def addBinary( self , type , data ): + """ Functionally equivalent to addString. """ + self.addString( type , data ) + + def getString( self , type , default = None ): + """ Returns a string for the specified object type, or + a default value when the specified type is not present. """ + for obj in self.objs: + if ( obj.type == type ) and ( len( obj.data ) > 0 ): + return obj.data + return default + + def getNumber( self , type , default = None ): + """ Returns a byte-swapped number for the specified object type, or + a default value when the specified type is not present. """ + for obj in self.objs: + if obj.type == type: + if len( obj.data ) == 2: + return unpack( "!H" , obj.data )[0] + elif len( obj.data ) == 4: + return unpack( "!L" , obj.data )[0] + elif len( obj.data ) == 8: + return unpack( "!Q" , obj.data )[0] + return default + + def getBinary( self , type , default = None ): + """ Functionally equivalent to getString. """ + return self.getString( type , default ) + + def flatten( self , user ): + """ Returns a flattened string of this packet and embedded objects. """ + data = "" + if self.isIRC: + if self.type == HTLS_HDR_PING: + data = "PONG :"+IRC_SERVER_NAME+"\r\n" + + elif self.type == HTLS_HDR_CHAT: + try: + chat = self.getString(DATA_STRING).split( ": " , 1 )[1].replace( "\r" , " " ) + except IndexError: + chat = self.getString(DATA_STRING).replace( "\r" , " " ) + try: + ( c , u ) = self.server.clients[self.getNumber( DATA_UID )] + # this should be hanlded already elsewhere but forgot :( + if user.uid == u.uid: + return data + mynick = ircCheckUserNick( u ) + mynick = u.nick.replace( " " , "" ) + except KeyError: + mynick = "PHXD" + chatid = self.getNumber( DATA_CHATID ) + if chatid == None: + channel = "public" + else: + channel = str(chatid) + data = ":"+mynick+" PRIVMSG #"+channel+" :"+chat[1:]+"\r\n" + + elif self.type == HTLS_HDR_MSG: + chat = self.getString( DATA_STRING ) + try: + ( c , u ) = self.server.clients[self.getNumber( DATA_UID )] + mynick = ircCheckUserNick( u ) + myip = u.ip + except KeyError: + mynick = "PHXD" + myip = "127.0.0.1" + data = ":"+mynick+"!~"+mynick+"@"+myip+" PRIVMSG "+user.nick+" :"+chat.replace( "\r" , " " )+"\r\n" + + elif self.type == HTLS_HDR_USER_LEAVE: + ( c, u ) = self.server.clients[self.getNumber( DATA_UID )] + mynick = ircCheckUserNick( u ) + if u.isIRC: + proto = "IRC" + else: + proto = "Hotline" + data = ":"+mynick+"!~"+mynick+"@"+u.ip+" PART #public :Client disconnected from "+proto+"\r\n" + + elif self.type == HTLS_HDR_USER_CHANGE: + ( c, u ) = self.server.clients[self.getNumber( DATA_UID )] + mynick = ircCheckUserNick( u ) + oldnick = self.getString( DATA_IRC_OLD_NICK ) + if not u.valid: # Login ? If so, force join the public channel + data = ":"+mynick+"!~"+mynick+"@"+u.ip+" JOIN :#public\r\n" + else: + if u.nick == oldnick: + data = "NOTICE *: *** "+oldnick+" changed status to "+str( u.status )+"\r\n" + else: + if user.uid == u.uid: + data = ":"+oldnick+"!~"+oldnick+"@"+u.ip+" NICK :"+user.nick+"\r\n" + else: + data = ":"+str( u.uid )+"_"+oldnick.replace( " " , "" )+" NICK "+ircCheckUserNick( u )+"\r\n" + + elif self.type == HTLS_HDR_TASK: + # check for HTLC_HDR_USER_LIST reply: + if self.getBinary( DATA_USER ): + keys = self.server.clients.keys() + keys.sort() + for uid in keys: + ( c , u ) = self.server.clients[uid] + mynick = ircCheckUserNick( u ) + if u.isLoggedIn(): + data += ":"+IRC_SERVER_NAME+" 352 "+mynick+" #public "+mynick+" "+u.ip+" "+IRC_SERVER_NAME+" "+u.account.name.replace( " ", "_" )+"\r\n" + data += ":"+IRC_SERVER_NAME+" 315 "+user.nick+" #public :End of /WHO list.\r\n" + + # HTLC_HDR_USER_INFO then :) + elif self.getString( DATA_NICK ): + uid = self.getNumber( DATA_UID ) + ( c , u ) = self.server.clients[uid] + mynick = ircCheckUserNick( u ) + info = self.getString( DATA_STRING ) + + idle = info.split( "idle: " )[1].split( '\r' )[0] + if u.isIRC: + proto = "IRC" + else: + proto = "Hotline" + + data = ":"+IRC_SERVER_NAME+" 311 "+user.nick+" "+mynick+" ~"+mynick+" "+u.ip+" * :"+u.account.name.replace(" ", "_")+"\r\n" + data += ":"+IRC_SERVER_NAME+" 312 "+user.nick+" "+mynick+" "+IRC_SERVER_NAME+" :http//chatonly.org\r\n" + data += ":"+IRC_SERVER_NAME+" 320 "+user.nick+" "+mynick+" :Using protocol "+proto+"\r\n" + data += ":"+IRC_SERVER_NAME+" 317 "+user.nick+" "+mynick+" "+idle+" 0 :seconds idle, signon time\r\n" + data += ":"+IRC_SERVER_NAME+" 318 "+user.nick+" "+mynick+" :End of /WHOIS list.\r\n" + + elif self.type == HTLS_HDR_CHAT_INVITE: + chatid = self.getNumber( DATA_CHATID) + uid = self.getNumber( DATA_UID ) + ( c , u ) = self.server.clients[uid] + mynick = ircCheckUserNick( u ) + data = ":PHXD PRIVMSG #public :"+mynick+" invites you to join private chat #"+str(chatid)+"\r\n" + elif self.type == HTLS_HDR_CHAT_USER_LEAVE: + chatid = self.getNumber( DATA_CHATID) + uid = self.getNumber( DATA_UID ) + ( c , u ) = self.server.clients[uid] + mynick = ircCheckUserNick( u ) + data = ":"+mynick+"!~"+mynick+"@"+u.ip+" PART #"+str( chatid )+" :Client left channel #"+str( chatid )+"\r\n" + + elif self.type == HTLS_HDR_CHAT_USER_CHANGE: + # Basically this is a JOIN packet for a private chat + chatid = self.getNumber( DATA_CHATID) + uid = self.getNumber( DATA_UID ) + ( c , u ) = self.server.clients[uid] + mynick = ircCheckUserNick( self.getString( DATA_NICK ) ) + data = ":"+mynick+"!~"+mynick+"@"+u.ip+" JOIN :#"+str(chatid)+"\r\n" + + elif self.type == HTLS_HDR_BROADCAST: + data = "NOTICE * :*** BROADCAST: "+self.getString( DATA_STRING )+"\r\n" + + return data + # Normal Hotline processing + else: + for obj in self.objs: + data += obj.flatten() + return pack( "!5L1H" , self.type , self.seq , self.flags , len( data ) + 2 , len( data ) + 2 , len( self.objs ) ) + data # Client packet types @@ -540,41 +537,41 @@ def flatten( self , user ): # Hotline's idea of "bit 0" is ass backwards -PRIV_DELETE_FILES = 1 << 63 -PRIV_UPLOAD_FILES = 1 << 62 -PRIV_DOWNLOAD_FILES = 1 << 61 -PRIV_RENAME_FILES = 1 << 60 -PRIV_MOVE_FILES = 1 << 59 -PRIV_CREATE_FOLDERS = 1 << 58 -PRIV_DELETE_FOLDERS = 1 << 57 -PRIV_RENAME_FOLDERS = 1 << 56 -PRIV_MOVE_FOLDERS = 1 << 55 -PRIV_READ_CHAT = 1 << 54 -PRIV_SEND_CHAT = 1 << 53 -PRIV_CREATE_CHATS = 1 << 52 -PRIV_DELETE_CHATS = 1 << 51 -PRIV_SHOW_USER = 1 << 50 -PRIV_CREATE_USERS = 1 << 49 -PRIV_DELETE_USERS = 1 << 48 -PRIV_READ_USERS = 1 << 47 -PRIV_MODIFY_USERS = 1 << 46 -PRIV_CHANGE_PASSWORD = 1 << 45 -PRIV_UNKNOWN = 1 << 44 -PRIV_READ_NEWS = 1 << 43 -PRIV_POST_NEWS = 1 << 42 -PRIV_KICK_USERS = 1 << 41 -PRIV_KICK_PROTECT = 1 << 40 -PRIV_USER_INFO = 1 << 39 -PRIV_UPLOAD_ANYWHERE = 1 << 38 -PRIV_USE_ANY_NAME = 1 << 37 -PRIV_NO_AGREEMENT = 1 << 36 -PRIV_COMMENT_FILES = 1 << 35 -PRIV_COMMENT_FOLDERS = 1 << 34 -PRIV_VIEW_DROPBOXES = 1 << 33 -PRIV_MAKE_ALIASES = 1 << 32 -PRIV_BROADCAST = 1 << 31 - -PRIV_SEND_MESSAGES = 1 << 23 +PRIV_DELETE_FILES = 1L << 63 +PRIV_UPLOAD_FILES = 1L << 62 +PRIV_DOWNLOAD_FILES = 1L << 61 +PRIV_RENAME_FILES = 1L << 60 +PRIV_MOVE_FILES = 1L << 59 +PRIV_CREATE_FOLDERS = 1L << 58 +PRIV_DELETE_FOLDERS = 1L << 57 +PRIV_RENAME_FOLDERS = 1L << 56 +PRIV_MOVE_FOLDERS = 1L << 55 +PRIV_READ_CHAT = 1L << 54 +PRIV_SEND_CHAT = 1L << 53 +PRIV_CREATE_CHATS = 1L << 52 +PRIV_DELETE_CHATS = 1L << 51 +PRIV_SHOW_USER = 1L << 50 +PRIV_CREATE_USERS = 1L << 49 +PRIV_DELETE_USERS = 1L << 48 +PRIV_READ_USERS = 1L << 47 +PRIV_MODIFY_USERS = 1L << 46 +PRIV_CHANGE_PASSWORD = 1L << 45 +PRIV_UNKNOWN = 1L << 44 +PRIV_READ_NEWS = 1L << 43 +PRIV_POST_NEWS = 1L << 42 +PRIV_KICK_USERS = 1L << 41 +PRIV_KICK_PROTECT = 1L << 40 +PRIV_USER_INFO = 1L << 39 +PRIV_UPLOAD_ANYWHERE = 1L << 38 +PRIV_USE_ANY_NAME = 1L << 37 +PRIV_NO_AGREEMENT = 1L << 36 +PRIV_COMMENT_FILES = 1L << 35 +PRIV_COMMENT_FOLDERS = 1L << 34 +PRIV_VIEW_DROPBOXES = 1L << 33 +PRIV_MAKE_ALIASES = 1L << 32 +PRIV_BROADCAST = 1L << 31 + +PRIV_SEND_MESSAGES = 1L << 23 # Status bits diff --git a/shared/HLTransfer.py b/shared/HLTransfer.py index 2095ed3..7d59192 100644 --- a/shared/HLTransfer.py +++ b/shared/HLTransfer.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import from shared.HLProtocol import * import os , time @@ -12,9 +11,9 @@ def __init__( self , id , path , owner , type ): self.name = os.path.basename( path ) self.owner = owner self.type = type - self.total = 0 - self.transferred = 0 - self.offset = 0 + self.total = 0L + self.transferred = 0L + self.offset = 0L self.startTime = 0.0 def overallPercent( self ): @@ -52,7 +51,7 @@ def __init__( self , id , path , owner , offset ): HLTransfer.__init__( self , id , path , owner , XFER_TYPE_DOWNLOAD ) self.offset = offset self.dataSize = os.path.getsize( path ) - offset - self.file = open( path , "r" ) + self.file = file( path , "r" ) self.file.seek( offset ) self.sentHeader = False self._buildHeaderData() @@ -102,7 +101,7 @@ def _buildHeaderData( self ): class HLUpload( HLTransfer ): def __init__( self , id , path , owner ): HLTransfer.__init__( self , id , path , owner , 1 ) - self.file = open( path , "a" ) + self.file = file( path , "a" ) self.initialSize = os.path.getsize( path ) self.buffer = "" self.state = STATE_FILP diff --git a/shared/HLTypes.py b/shared/HLTypes.py index 10286fa..229a324 100644 --- a/shared/HLTypes.py +++ b/shared/HLTypes.py @@ -1,9 +1,7 @@ -from __future__ import absolute_import from shared.HLProtocol import HLCharConst from datetime import datetime from struct import * import os -from six.moves import range LOG_TYPE_GENERAL = 1 LOG_TYPE_LOGIN = 2 @@ -36,11 +34,11 @@ class HLAccount: """ Stores account information. """ def __init__( self , login = "" ): - self.id = 0 + self.id = 0L self.login = login self.password = "" self.name = "Null Account" - self.privs = 0 + self.privs = 0L self.fileRoot = "" def copyFrom( self , acct ): @@ -64,7 +62,7 @@ def __init__( self , uid = 0 , addr = "" ): self.icon = 500 self.status = 0 self.gif = "" - self.color = -1 + self.color = -1L self.account = None self.away = False self.lastPacketTime = 0.0 @@ -85,7 +83,7 @@ def isLoggedIn( self ): def hasPriv( self , priv ): """ Returns True if the account associated with the user has the specified privilege. """ - return ( self.account != None ) and ( ( int( self.account.privs ) & priv ) > 0 ) + return ( self.account != None ) and ( ( long( self.account.privs ) & priv ) > 0 ) def parse( self, data ): if len(data) < 8: @@ -106,7 +104,7 @@ def flatten( self ): data += pack( "!4H" , self.uid , self.icon , self.status , len( self.nick ) ) data += self.nick # this is an avaraline extension for nick coloring - if self.color >= 0: + if self.color >= 0L: data += pack( "!L" , self.color ) return data @@ -160,7 +158,7 @@ def __init__( self , data = None ): def forkOffset( self , fork ): """ Returns the offset for the specified fork type. """ - if fork in self.forkOffsets: + if self.forkOffsets.has_key( fork ): return self.forkOffsets[fork] return 0 @@ -184,7 +182,7 @@ def flatten( self ): """ Flattens the resume information into a packed structure to send in a HLObject. """ data = pack( "!LH" , HLCharConst( "RFLT" ) , 1 ) data += ( "\0" * 34 ) - data += pack( "!H" , len( list(self.forkOffsets.keys()) ) ) + data += pack( "!H" , len( self.forkOffsets.keys() ) ) for forkType in self.forkOffsets.keys(): data += pack( "!4L" , forkType , self.forkOffsets[forkType] , 0 , 0 ) return data @@ -193,7 +191,7 @@ class HLNewsPost: """ Stores information about a single news post. """ def __init__( self , nick = "" , login = "" , post = "" ): - self.id = 0 + self.id = 0L self.nick = nick self.login = login self.post = post @@ -220,7 +218,7 @@ def handleUserDisconnected( self , server , user ): def handlePacket( self , server , user , packet ): """ Default dispatcher called when a packet is received. Calls any registered handler functions. Returns True when packet is handled. """ - if packet.type in self._funcs: + if self._funcs.has_key( packet.type ): self._funcs[packet.type]( server , user , packet ) return True return False diff --git a/shared/HLUtils.py b/shared/HLUtils.py index e5c14f7..17f3b8f 100644 --- a/shared/HLUtils.py +++ b/shared/HLUtils.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import import sys,os diff --git a/support/text_db_setup.py b/support/text_db_setup.py index 188a605..9ae1160 100644 --- a/support/text_db_setup.py +++ b/support/text_db_setup.py @@ -1,6 +1,5 @@ #!/usr/bin/env python -from __future__ import absolute_import import os from config import * From 12e0d6edc362d56a5f2871f3a32d037ecc715ce4 Mon Sep 17 00:00:00 2001 From: Patrick Thiel Date: Mon, 2 Oct 2023 21:26:04 -0400 Subject: [PATCH 3/8] ref: convert tabs to spaces ref: convert tabs to spaces, prt 2 --- configure_phxd.py | 0 phxd | 10 +- server/HLDatabase.py | 90 +-- server/HLDatabaseLogger.py | 18 +- server/HLFileServer.py | 274 +++---- server/HLServer.py | 724 ++++++++--------- server/HLServerLinkage.py | 248 +++--- server/HLWebServices.py | 68 +- server/database/MySQLDatabase.py | 176 ++--- server/database/TextDatabase.py | 372 ++++----- server/database/__init__.py | 4 +- server/handlers/AcctHandler.py | 146 ++-- server/handlers/ChatHandler.py | 462 +++++------ server/handlers/FileHandler.py | 446 +++++------ server/handlers/IconHandler.py | 70 +- server/handlers/NewsHandler.py | 70 +- server/handlers/UserHandler.py | 398 +++++----- server/handlers/__init__.py | 12 +- server/handlers/commands/0wn.py | 52 +- server/handlers/commands/away.py | 18 +- server/handlers/commands/broadcast.py | 8 +- server/handlers/commands/color.py | 8 +- server/handlers/commands/find.py | 38 +- server/handlers/commands/me.py | 14 +- server/handlers/commands/news.py | 30 +- server/handlers/commands/uptime.py | 26 +- server/handlers/commands/xfers.py | 40 +- shared/HLProtocol.py | 1028 ++++++++++++------------- shared/HLTransfer.py | 300 ++++---- shared/HLTypes.py | 366 ++++----- shared/HLUtils.py | 48 +- 31 files changed, 2782 insertions(+), 2782 deletions(-) mode change 100755 => 100644 configure_phxd.py diff --git a/configure_phxd.py b/configure_phxd.py old mode 100755 new mode 100644 diff --git a/phxd b/phxd index 944f9ed..bf3340e 100755 --- a/phxd +++ b/phxd @@ -8,11 +8,11 @@ import server.handlers serv = HLServer() for modName in server.handlers.__all__: - try: - mod = __import__( "server.handlers.%s" % modName , None , None , "server.handlers" ) - mod.installHandler( serv ) - except ImportError: - print "error importing server.handlers.%s" % modName + try: + mod = __import__( "server.handlers.%s" % modName , None , None , "server.handlers" ) + mod.installHandler( serv ) + except ImportError: + print "error importing server.handlers.%s" % modName serv.logEvent( LOG_TYPE_GENERAL , "Server started on port %d" % serv.port ) reactor.run() diff --git a/server/HLDatabase.py b/server/HLDatabase.py index 4d73c3a..7c0c4c0 100644 --- a/server/HLDatabase.py +++ b/server/HLDatabase.py @@ -2,50 +2,50 @@ import server.database def getDatabase( type ): - """ Returns a HLDatabase subclass based on the type string (used as a prefix). """ - cls = "%sDatabase" % type - try: - mod = __import__( "server.database.%s" % cls , None , None , "server.database" ) - db = eval( "mod.%s()" % cls ) - return db - except ImportError: - print "error importing server.database.%s" % cls - return None + """ Returns a HLDatabase subclass based on the type string (used as a prefix). """ + cls = "%sDatabase" % type + try: + mod = __import__( "server.database.%s" % cls , None , None , "server.database" ) + db = eval( "mod.%s()" % cls ) + return db + except ImportError: + print "error importing server.database.%s" % cls + return None class HLDatabase: - """ Base class for phxd database implementations. Should be overridden by classes in the database directory. """ - - def __init__( self ): - pass - - def loadAccount( self , login ): - """ Creates a new HLAccount object and loads information for the specified login into it. Returns None if unsuccessful. """ - return None - - def saveAccount( self , acct ): - """ Saves the specified HLAccount object to the database. If the HLAccount has a non-zero ID, the information is updated, otherwise a new account is inserted. """ - pass - - def deleteAccount( self , login ): - """ Deletes an account with the specified login from the database. """ - return False - - def updateAccountStats( self , login , downloaded , uploaded , setDate = False ): - """ Updates statistics for an account in the database. """ - pass - - def loadNewsPosts( self , limit = 0 ): - """ Loads and returns a list of HLNewsPost objects from the database. If limit > 0, the returned list will contain no more than limit posts. """ - return [] - - def saveNewsPost( self , post ): - """ Saves a HLNewsPost object to the database. """ - pass - - def checkBanlist( self , addr ): - """ Checks the banlist table, returns a reason, or None if no entry was found. """ - return None - - def logEvent( self , type , event , login = "" , nick = "" , ip = "" ): - """ Logs an event to the database (see HLTypes for log types). """ - pass + """ Base class for phxd database implementations. Should be overridden by classes in the database directory. """ + + def __init__( self ): + pass + + def loadAccount( self , login ): + """ Creates a new HLAccount object and loads information for the specified login into it. Returns None if unsuccessful. """ + return None + + def saveAccount( self , acct ): + """ Saves the specified HLAccount object to the database. If the HLAccount has a non-zero ID, the information is updated, otherwise a new account is inserted. """ + pass + + def deleteAccount( self , login ): + """ Deletes an account with the specified login from the database. """ + return False + + def updateAccountStats( self , login , downloaded , uploaded , setDate = False ): + """ Updates statistics for an account in the database. """ + pass + + def loadNewsPosts( self , limit = 0 ): + """ Loads and returns a list of HLNewsPost objects from the database. If limit > 0, the returned list will contain no more than limit posts. """ + return [] + + def saveNewsPost( self , post ): + """ Saves a HLNewsPost object to the database. """ + pass + + def checkBanlist( self , addr ): + """ Checks the banlist table, returns a reason, or None if no entry was found. """ + return None + + def logEvent( self , type , event , login = "" , nick = "" , ip = "" ): + """ Logs an event to the database (see HLTypes for log types). """ + pass diff --git a/server/HLDatabaseLogger.py b/server/HLDatabaseLogger.py index ee5b219..8879608 100644 --- a/server/HLDatabaseLogger.py +++ b/server/HLDatabaseLogger.py @@ -1,12 +1,12 @@ from logging import Handler class HLDatabaseLogger( Handler ): - - def __init__( self , db ): - Handler.__init__( self ) - self.db = db - - def emit( self , record ): - if record.args: - ( type , msg , login , nick , ip ) = record.args - self.db.logEvent( type , msg , login , nick , ip ) + + def __init__( self , db ): + Handler.__init__( self ) + self.db = db + + def emit( self , record ): + if record.args: + ( type , msg , login , nick , ip ) = record.args + self.db.logEvent( type , msg , login , nick , ip ) diff --git a/server/HLFileServer.py b/server/HLFileServer.py index 9ed8ea7..e1f54e0 100644 --- a/server/HLFileServer.py +++ b/server/HLFileServer.py @@ -9,142 +9,142 @@ import os class HLTransferConnection( Protocol ): - #__implements__ = Protocol.__implements__ + ( IProducer , ) - - def connectionMade( self ): - self.info = None - self.gotMagic = False - self.buffer = "" - - def connectionLost( self , reason ): - if self.info != None: - self.info.finish() - self.factory.removeTransfer( self.info.id ) - - def dataReceived( self , data ): - """ Called when the transfer connection receives data. Should only happen - for uploads, and for the 16-byte magic header for all transfers. """ - if self.gotMagic: - if ( self.info != None ) and ( self.info.type == XFER_TYPE_UPLOAD ): - self.info.parseData( data ) - if self.info.isComplete(): - # The upload is done, it's our job to close the connection. - self.transport.loseConnection() - else: - self.transport.loseConnection() - else: - # Make sure we buffer at this point in case we don't get the - # HTXF magic all at once, or get more than just the magic. - self.buffer += data - if len( self.buffer ) >= 16: - # We got the HTXF magic, parse it. - ( proto , xfid , size , flags ) = unpack( "!4L" , self.buffer[0:16] ) - self.buffer = self.buffer[16:] - self.gotMagic = True - self.info = self.factory.findTransfer( xfid ) - if self.info == None: - # Invalid xfer ID, kill the connection. - self.transport.loseConnection() - else: - if self.info.type == XFER_TYPE_UPLOAD: - if self.info.total == 0: - self.info.total = size - elif self.info.type == XFER_TYPE_DOWNLOAD: - self.transport.registerProducer( self , False ) - # Cancel the xfer timeout and start it up. - self.factory.cancelTimeout( self.info.id ) - self.info.start() - if len( self.buffer ) > 0: - # Recurse for any remaining data with gotMagic = True. - self.dataReceived( self.buffer ) - - def resumeProducing( self ): - """ The transport asked us for more data. Should only happen for - downloads after we've been registered as a producer. """ - chunk = self.info.getDataChunk() - if len( chunk ) > 0: - self.transport.write( chunk ) - else: - self.transport.unregisterProducer() - - def pauseProducing( self ): - pass - - def stopProducing( self ): - pass + #__implements__ = Protocol.__implements__ + ( IProducer , ) + + def connectionMade( self ): + self.info = None + self.gotMagic = False + self.buffer = "" + + def connectionLost( self , reason ): + if self.info != None: + self.info.finish() + self.factory.removeTransfer( self.info.id ) + + def dataReceived( self , data ): + """ Called when the transfer connection receives data. Should only happen + for uploads, and for the 16-byte magic header for all transfers. """ + if self.gotMagic: + if ( self.info != None ) and ( self.info.type == XFER_TYPE_UPLOAD ): + self.info.parseData( data ) + if self.info.isComplete(): + # The upload is done, it's our job to close the connection. + self.transport.loseConnection() + else: + self.transport.loseConnection() + else: + # Make sure we buffer at this point in case we don't get the + # HTXF magic all at once, or get more than just the magic. + self.buffer += data + if len( self.buffer ) >= 16: + # We got the HTXF magic, parse it. + ( proto , xfid , size , flags ) = unpack( "!4L" , self.buffer[0:16] ) + self.buffer = self.buffer[16:] + self.gotMagic = True + self.info = self.factory.findTransfer( xfid ) + if self.info == None: + # Invalid xfer ID, kill the connection. + self.transport.loseConnection() + else: + if self.info.type == XFER_TYPE_UPLOAD: + if self.info.total == 0: + self.info.total = size + elif self.info.type == XFER_TYPE_DOWNLOAD: + self.transport.registerProducer( self , False ) + # Cancel the xfer timeout and start it up. + self.factory.cancelTimeout( self.info.id ) + self.info.start() + if len( self.buffer ) > 0: + # Recurse for any remaining data with gotMagic = True. + self.dataReceived( self.buffer ) + + def resumeProducing( self ): + """ The transport asked us for more data. Should only happen for + downloads after we've been registered as a producer. """ + chunk = self.info.getDataChunk() + if len( chunk ) > 0: + self.transport.write( chunk ) + else: + self.transport.unregisterProducer() + + def pauseProducing( self ): + pass + + def stopProducing( self ): + pass class HLFileServer (Factory): - protocol = HLTransferConnection - - def __init__( self , server ): - self.port = SERVER_PORT + 1 - self.server = server - self.lastTransferID = 0 - self.transfers = {} - self.timeouts = {} - reactor.listenTCP( self.port , self ) - - def addUpload( self , owner , path ): - """ Adds an upload to the list of transfers. """ - self.lastTransferID += 1 - info = HLUpload( self.lastTransferID , path , owner ) - self.transfers[self.lastTransferID] = info - self.timeouts[info.id] = reactor.callLater( XFER_START_TIMEOUT , self.timeoutTransfer , info.id ) - return info - - def addDownload( self , owner , path , offset ): - """ Adds a download to the list of transfers. """ - self.lastTransferID += 1 - info = HLDownload( self.lastTransferID , path , owner , offset ) - self.transfers[self.lastTransferID] = info - self.timeouts[info.id] = reactor.callLater( XFER_START_TIMEOUT , self.timeoutTransfer , info.id ) - return info - - def findTransfer( self , xfid ): - """ Returns the HLTransfer (HLDownload or HLUpload) object for the specified transfer ID. """ - if self.transfers.has_key( xfid ): - return self.transfers[xfid] - return None - - def findTransfersForUser( self , uid ): - """ Returns a list of all transfers for the specified user ID. """ - xfers = [] - for info in self.transfers.values(): - if info.owner == uid: - xfers.append( info ) - return xfers - - def cancelTimeout( self , id ): - """ Cancels a pending timeout for the specified transfer. """ - if self.timeouts.has_key( id ): - self.timeouts[id].cancel() - del self.timeouts[id] - - def timeoutTransfer( self , id ): - """ Called after an initial timeout to remove the dead transfer from the list of transfers. """ - if self.transfers.has_key( id ): - del self.timeouts[id] - del self.transfers[id] - - def removeTransfer( self , xfid ): - """ Removes a transfer from the list of transfers. """ - if self.transfers.has_key( xfid ): - info = self.transfers[xfid] - user = self.server.getUser( info.owner ) - if user != None: - if info.isComplete(): - type = ( "Download" , "Upload" )[info.type] - speed = "%d k/sec" % ( info.getTotalBPS() / 1024 ) - msg = "%s of '%s' complete (%s)" % ( type , info.name , speed ) - self.server.logEvent( LOG_TYPE_TRANSFER , msg , user ) - if info.type == XFER_TYPE_DOWNLOAD: - self.server.database.updateAccountStats( user.account.login , info.transferred , 0 ) - elif info.type == XFER_TYPE_UPLOAD: - self.server.database.updateAccountStats( user.account.login , 0 , info.transferred ) - del self.transfers[info.id] - - def cleanupTransfers( self , owner ): - """ Removes any transfers owned by owner. Should be called when the user disconnects or is disconnected. """ - for xfer in self.transfers.values(): - if xfer.owner == owner: - self.removeTransfer( xfer.id ) + protocol = HLTransferConnection + + def __init__( self , server ): + self.port = SERVER_PORT + 1 + self.server = server + self.lastTransferID = 0 + self.transfers = {} + self.timeouts = {} + reactor.listenTCP( self.port , self ) + + def addUpload( self , owner , path ): + """ Adds an upload to the list of transfers. """ + self.lastTransferID += 1 + info = HLUpload( self.lastTransferID , path , owner ) + self.transfers[self.lastTransferID] = info + self.timeouts[info.id] = reactor.callLater( XFER_START_TIMEOUT , self.timeoutTransfer , info.id ) + return info + + def addDownload( self , owner , path , offset ): + """ Adds a download to the list of transfers. """ + self.lastTransferID += 1 + info = HLDownload( self.lastTransferID , path , owner , offset ) + self.transfers[self.lastTransferID] = info + self.timeouts[info.id] = reactor.callLater( XFER_START_TIMEOUT , self.timeoutTransfer , info.id ) + return info + + def findTransfer( self , xfid ): + """ Returns the HLTransfer (HLDownload or HLUpload) object for the specified transfer ID. """ + if self.transfers.has_key( xfid ): + return self.transfers[xfid] + return None + + def findTransfersForUser( self , uid ): + """ Returns a list of all transfers for the specified user ID. """ + xfers = [] + for info in self.transfers.values(): + if info.owner == uid: + xfers.append( info ) + return xfers + + def cancelTimeout( self , id ): + """ Cancels a pending timeout for the specified transfer. """ + if self.timeouts.has_key( id ): + self.timeouts[id].cancel() + del self.timeouts[id] + + def timeoutTransfer( self , id ): + """ Called after an initial timeout to remove the dead transfer from the list of transfers. """ + if self.transfers.has_key( id ): + del self.timeouts[id] + del self.transfers[id] + + def removeTransfer( self , xfid ): + """ Removes a transfer from the list of transfers. """ + if self.transfers.has_key( xfid ): + info = self.transfers[xfid] + user = self.server.getUser( info.owner ) + if user != None: + if info.isComplete(): + type = ( "Download" , "Upload" )[info.type] + speed = "%d k/sec" % ( info.getTotalBPS() / 1024 ) + msg = "%s of '%s' complete (%s)" % ( type , info.name , speed ) + self.server.logEvent( LOG_TYPE_TRANSFER , msg , user ) + if info.type == XFER_TYPE_DOWNLOAD: + self.server.database.updateAccountStats( user.account.login , info.transferred , 0 ) + elif info.type == XFER_TYPE_UPLOAD: + self.server.database.updateAccountStats( user.account.login , 0 , info.transferred ) + del self.transfers[info.id] + + def cleanupTransfers( self , owner ): + """ Removes any transfers owned by owner. Should be called when the user disconnects or is disconnected. """ + for xfer in self.transfers.values(): + if xfer.owner == owner: + self.removeTransfer( xfer.id ) diff --git a/server/HLServer.py b/server/HLServer.py index 4dac84a..95c5b0c 100644 --- a/server/HLServer.py +++ b/server/HLServer.py @@ -18,187 +18,187 @@ from logging.handlers import RotatingFileHandler class HLConnection( Protocol ): - """ Protocol subclass to handle parsing and dispatching of raw hotline data. """ - - def __init__( self , factory , connID ): - self.factory = factory - self.connID = connID - - def connectionMade( self ): - """ Called when a connection is accepted. """ - self.gotMagic = False - self.isIRC = False - self.packet = HLPacket() - self.buffer = "" - self.idleTimer = reactor.callLater( IDLE_TIME , self.idleCheck ) - - def connectionLost( self , reason ): - """ Called when the connection is lost. """ - if ( self.idleTimer != None ) and self.idleTimer.active(): - self.idleTimer.cancel() - self.factory.removeConnection( self.connID ) - - def dataReceived( self , data ): - """ Called when the socket receives data. """ - self.buffer += data - self.parseBuffer() - - def parseBuffer( self ): - """ Parses the current buffer until the buffer is empty or until no more packets can be parsed. """ - if self.gotMagic: - done = False - while not done: - if self.isIRC: - self.buffer = self.buffer.replace("\r", "") #FIXME is it really necessary ? it is also done during packet parsing - self.packet.isIRC = self.isIRC - self.packet.connID = self.connID - self.packet.server = self.factory - size = self.packet.parse( self.buffer ) - if size > 0: - if self.isIRC: - size = size + 1 - self.buffer = self.buffer[size:] - self.handlePacket() - self.packet = HLPacket() - else: - done = True - else: - if len( self.buffer ) >= 12: - ( proto , subProto , vers , subVers ) = unpack( "!LLHH" , self.buffer[0:12] ) - if proto == HLCharConst( "TRTP" ): - self.buffer = self.buffer[12:] - self.gotMagic = True - self.transport.write( pack( "!2L" , HLCharConst( "TRTP" ) , 0 ) ) - # If there is still data in the buffer, check for packets. - if len( self.buffer ) > 0: - self.parseBuffer() - else: - # Not hotline, assume IRC. Multiple commands can be chained in IRC. - cmds = self.buffer.splitlines() - if cmds[0].startswith("CAP"): - # We received CAP LS, ignore it and read the rest of the buffer - # This is for compatibility with IRC v3.02 clients like irssi - cmds.pop(0) - # If there are no further commands, close the connection. - if not cmds: - self.transport.loseConnection() - # More commands still in the buffer, parse them. - value = "" - try: - cmd, value = cmds[0].split(" ", 1) - except ValueError: - # Value isn't defined, only parse cmd - cmd = cmds[0].split(" ", 1)[0] - # Check the first command, if NICK or USER, login, else return UNKNOWN COMMAND - if ( cmd == "NICK" ) or ( cmd == "USER" ): - nick = value or "Unnamed" - user = self.factory.getUser( self.connID ) - user.nick = nick # Making sure we have the right nick. - self.transport.write ( "NOTICE * :*** Welcome to Hotline\r\n" ) - self.transport.write ( "NOTICE AUTH :*** You are NOT logged in\r\n" ) - self.transport.write ( "NOTICE AUTH :*** Please send '/msg loginserv login password' to proceed.\r\n" ) - self.transport.write ( "NOTICE AUTH :*** If you do not have an account, use '/msg loginserv guest' to proceed.\r\n" ) - self.transport.write ( ":"+IRC_SERVER_NAME+" 001 %s :Waiting for login input..\r\n" % nick ) - self.transport.write ( ":"+IRC_SERVER_NAME+" 375 %s :- MOTDs are for losers.\r\n" % user.nick ) - self.transport.write ( ":"+IRC_SERVER_NAME+" 372 %s :- :)\r\n" % user.nick ) - self.transport.write ( ":"+IRC_SERVER_NAME+" 376 %s :End of /MOTD command.\r\n" % user.nick ) + """ Protocol subclass to handle parsing and dispatching of raw hotline data. """ + + def __init__( self , factory , connID ): + self.factory = factory + self.connID = connID + + def connectionMade( self ): + """ Called when a connection is accepted. """ + self.gotMagic = False + self.isIRC = False + self.packet = HLPacket() + self.buffer = "" + self.idleTimer = reactor.callLater( IDLE_TIME , self.idleCheck ) + + def connectionLost( self , reason ): + """ Called when the connection is lost. """ + if ( self.idleTimer != None ) and self.idleTimer.active(): + self.idleTimer.cancel() + self.factory.removeConnection( self.connID ) + + def dataReceived( self , data ): + """ Called when the socket receives data. """ + self.buffer += data + self.parseBuffer() + + def parseBuffer( self ): + """ Parses the current buffer until the buffer is empty or until no more packets can be parsed. """ + if self.gotMagic: + done = False + while not done: + if self.isIRC: + self.buffer = self.buffer.replace("\r", "") #FIXME is it really necessary ? it is also done during packet parsing + self.packet.isIRC = self.isIRC + self.packet.connID = self.connID + self.packet.server = self.factory + size = self.packet.parse( self.buffer ) + if size > 0: + if self.isIRC: + size = size + 1 + self.buffer = self.buffer[size:] + self.handlePacket() + self.packet = HLPacket() + else: + done = True + else: + if len( self.buffer ) >= 12: + ( proto , subProto , vers , subVers ) = unpack( "!LLHH" , self.buffer[0:12] ) + if proto == HLCharConst( "TRTP" ): + self.buffer = self.buffer[12:] + self.gotMagic = True + self.transport.write( pack( "!2L" , HLCharConst( "TRTP" ) , 0 ) ) + # If there is still data in the buffer, check for packets. + if len( self.buffer ) > 0: + self.parseBuffer() + else: + # Not hotline, assume IRC. Multiple commands can be chained in IRC. + cmds = self.buffer.splitlines() + if cmds[0].startswith("CAP"): + # We received CAP LS, ignore it and read the rest of the buffer + # This is for compatibility with IRC v3.02 clients like irssi + cmds.pop(0) + # If there are no further commands, close the connection. + if not cmds: + self.transport.loseConnection() + # More commands still in the buffer, parse them. + value = "" + try: + cmd, value = cmds[0].split(" ", 1) + except ValueError: + # Value isn't defined, only parse cmd + cmd = cmds[0].split(" ", 1)[0] + # Check the first command, if NICK or USER, login, else return UNKNOWN COMMAND + if ( cmd == "NICK" ) or ( cmd == "USER" ): + nick = value or "Unnamed" + user = self.factory.getUser( self.connID ) + user.nick = nick # Making sure we have the right nick. + self.transport.write ( "NOTICE * :*** Welcome to Hotline\r\n" ) + self.transport.write ( "NOTICE AUTH :*** You are NOT logged in\r\n" ) + self.transport.write ( "NOTICE AUTH :*** Please send '/msg loginserv login password' to proceed.\r\n" ) + self.transport.write ( "NOTICE AUTH :*** If you do not have an account, use '/msg loginserv guest' to proceed.\r\n" ) + self.transport.write ( ":"+IRC_SERVER_NAME+" 001 %s :Waiting for login input..\r\n" % nick ) + self.transport.write ( ":"+IRC_SERVER_NAME+" 375 %s :- MOTDs are for losers.\r\n" % user.nick ) + self.transport.write ( ":"+IRC_SERVER_NAME+" 372 %s :- :)\r\n" % user.nick ) + self.transport.write ( ":"+IRC_SERVER_NAME+" 376 %s :End of /MOTD command.\r\n" % user.nick ) - self.isIRC = True - self.gotMagic = True - self.parseBuffer() - else: - self.transport.write ( ":"+IRC_SERVER_NAME+" 421 %s :Unknown command\r\n" % cmd ) - self.transport.loseConnection() - - def handlePacket( self ): - """ Dispatch the packet to the factory (and its listeners) and check to see if we should update our away status. """ - try: - user = self.factory.getUser( self.connID ) - if not user: - self.transport.loseConnection() - return - if self.isIRC and self.packet.irctrap: - # Unsupported command, return 421 - self.transport.write ( ":"+IRC_SERVER_NAME+" 421 %s %s :Unknown command\r\n" % (user.nick, self.packet.irctrap) ) - if user.isLoggedIn(): - # Make sure we're logged in before doing anything. - self.factory.dispatchPacket( self.connID , self.packet ) - if ( not isPingType( self.packet.type ) ) and ( not user.away ): - # We got a non-ping packet, and we're not away. - user.lastPacketTime = time.time() - if ( self.idleTimer != None ) and self.idleTimer.active(): - # If the idleTimer exists and hasn't fired yet, remain active. - self.idleTimer.reset( IDLE_TIME ) - else: - # Otherwise, we just came back from being idle. - user.status &= ~STATUS_AWAY - self.factory.dispatchPacket( self.connID , HLPacket( HTLC_HDR_USER_CHANGE ) ) - self.idleTimer = reactor.callLater( IDLE_TIME , self.idleCheck ) - elif ( self.packet.type == HTLC_HDR_LOGIN ): - user.isIRC = self.packet.isIRC - # If we're not logged in, only dispatch login packets. - user.lastPacketTime = time.time() - self.factory.dispatchPacket( self.connID , self.packet ) - elif ( self.packet.type == HTLC_HDR_PING ): - if self.packet.isIRC: - self.factory.dispatchPacket( self.connID , self.packet ) - else: - if ( self.packet.isIRC == 0 ) and ( self.packet.type != 0 ) and ( self.packet.type != 130 ): - print "got packet before login:" - print self.packet - except HLException , ex: - # Unhandled packets and task errors will be caught here. - if self.isIRC: - if self.packet.irctrap: - # Not sure this is still required since we already return a 421 "Unknown command" reply. - self.transport.write( "NOTICE * :*** HL Error 0x%x [%s] %s\r\n" % ( self.packet.type, self.packet.irctrap, ex.msg )) - else: - packet = HLPacket( HTLS_HDR_TASK , self.packet.seq , 1 ) - packet.addString( DATA_ERROR , ex.msg ) - self.writePacket( packet ) - if ex.fatal: - # The exception was fatal (i.e. failed login) so kill the connection. - self.transport.loseConnection() - - def idleCheck( self ): - """ Called a set amount of time after the last non-ping packet, mark us as idle and trick the handlers into sending the change. """ - user = self.factory.getUser( self.connID ) - if not user.away: - # Only send the change if the user is not away and not idle. - user.status |= STATUS_AWAY - self.factory.dispatchPacket( self.connID , HLPacket(HTLC_HDR_USER_CHANGE ) ) - del self.idleTimer - self.idleTimer = None - - def writePacket( self , packet ): - """ Flattens and writes a packet out to the socket. """ - packet.server = self.factory - self.transport.write( packet.flatten( self.factory.getUser( self.connID ) ) ) + self.isIRC = True + self.gotMagic = True + self.parseBuffer() + else: + self.transport.write ( ":"+IRC_SERVER_NAME+" 421 %s :Unknown command\r\n" % cmd ) + self.transport.loseConnection() + + def handlePacket( self ): + """ Dispatch the packet to the factory (and its listeners) and check to see if we should update our away status. """ + try: + user = self.factory.getUser( self.connID ) + if not user: + self.transport.loseConnection() + return + if self.isIRC and self.packet.irctrap: + # Unsupported command, return 421 + self.transport.write ( ":"+IRC_SERVER_NAME+" 421 %s %s :Unknown command\r\n" % (user.nick, self.packet.irctrap) ) + if user.isLoggedIn(): + # Make sure we're logged in before doing anything. + self.factory.dispatchPacket( self.connID , self.packet ) + if ( not isPingType( self.packet.type ) ) and ( not user.away ): + # We got a non-ping packet, and we're not away. + user.lastPacketTime = time.time() + if ( self.idleTimer != None ) and self.idleTimer.active(): + # If the idleTimer exists and hasn't fired yet, remain active. + self.idleTimer.reset( IDLE_TIME ) + else: + # Otherwise, we just came back from being idle. + user.status &= ~STATUS_AWAY + self.factory.dispatchPacket( self.connID , HLPacket( HTLC_HDR_USER_CHANGE ) ) + self.idleTimer = reactor.callLater( IDLE_TIME , self.idleCheck ) + elif ( self.packet.type == HTLC_HDR_LOGIN ): + user.isIRC = self.packet.isIRC + # If we're not logged in, only dispatch login packets. + user.lastPacketTime = time.time() + self.factory.dispatchPacket( self.connID , self.packet ) + elif ( self.packet.type == HTLC_HDR_PING ): + if self.packet.isIRC: + self.factory.dispatchPacket( self.connID , self.packet ) + else: + if ( self.packet.isIRC == 0 ) and ( self.packet.type != 0 ) and ( self.packet.type != 130 ): + print "got packet before login:" + print self.packet + except HLException , ex: + # Unhandled packets and task errors will be caught here. + if self.isIRC: + if self.packet.irctrap: + # Not sure this is still required since we already return a 421 "Unknown command" reply. + self.transport.write( "NOTICE * :*** HL Error 0x%x [%s] %s\r\n" % ( self.packet.type, self.packet.irctrap, ex.msg )) + else: + packet = HLPacket( HTLS_HDR_TASK , self.packet.seq , 1 ) + packet.addString( DATA_ERROR , ex.msg ) + self.writePacket( packet ) + if ex.fatal: + # The exception was fatal (i.e. failed login) so kill the connection. + self.transport.loseConnection() + + def idleCheck( self ): + """ Called a set amount of time after the last non-ping packet, mark us as idle and trick the handlers into sending the change. """ + user = self.factory.getUser( self.connID ) + if not user.away: + # Only send the change if the user is not away and not idle. + user.status |= STATUS_AWAY + self.factory.dispatchPacket( self.connID , HLPacket(HTLC_HDR_USER_CHANGE ) ) + del self.idleTimer + self.idleTimer = None + + def writePacket( self , packet ): + """ Flattens and writes a packet out to the socket. """ + packet.server = self.factory + self.transport.write( packet.flatten( self.factory.getUser( self.connID ) ) ) class HLServer( Factory ): - """ Factory subclass that handles all global server operations. Also owns database and fileserver objects. """ - - def __init__( self ): - self.port = SERVER_PORT - self.lastUID = 0 - self.lastChatID = 0 - self.clients = {} - self.chats = {} - self.handlers = [] - self.tempBans = {} - self.database = getDatabase( DB_TYPE ) - self.fileserver = HLFileServer( self ) - self.webserver = HLWebServices( self ) - self.startTime = time.time() - self.log = logging.getLogger( "phxd" ) - self.linker = HLServerLinker( self ) - self._initLog() - reactor.listenTCP( self.port , self ) + """ Factory subclass that handles all global server operations. Also owns database and fileserver objects. """ + + def __init__( self ): + self.port = SERVER_PORT + self.lastUID = 0 + self.lastChatID = 0 + self.clients = {} + self.chats = {} + self.handlers = [] + self.tempBans = {} + self.database = getDatabase( DB_TYPE ) + self.fileserver = HLFileServer( self ) + self.webserver = HLWebServices( self ) + self.startTime = time.time() + self.log = logging.getLogger( "phxd" ) + self.linker = HLServerLinker( self ) + self._initLog() + reactor.listenTCP( self.port , self ) # Update all trackers periodically recurrentTask = task.LoopingCall(self.updateTrackers) recurrentTask.start(TRACKER_REFRESH_PERIOD) #recurrentTask.addErrback(updateTrackersFailed) - + def updateTrackers(self): """Updates the register trackers, if any, with the name and description of server and the current user count. @@ -212,11 +212,11 @@ def updateTrackersFailed(self, reason): """ print "Failed to update tracker: reason" - def _initLog( self ): - self.log.setLevel( logging.DEBUG ) - if ENABLE_FILE_LOG: - # the formatter is just for the file logger - fmt = logging.Formatter( '%(asctime)s\t%(message)s' ) + def _initLog( self ): + self.log.setLevel( logging.DEBUG ) + if ENABLE_FILE_LOG: + # the formatter is just for the file logger + fmt = logging.Formatter( '%(asctime)s\t%(message)s' ) logSizeBytes = LOG_MAX_SIZE_MBYTES * 1024 * 1024 try: fileHandler = RotatingFileHandler( LOG_FILE, @@ -229,208 +229,208 @@ def _initLog( self ): fileHandler = logging.FileHandler( LOG_FILE, maxBytes=logSizeBytes, backupCount=MAX_LOG_FILES ) # If opening the file handle fails at this point, raise - fileHandler.setFormatter( fmt ) - # make sure everything goes to the file log - fileHandler.setLevel( logging.DEBUG ) - self.log.addHandler( fileHandler ) - dbHandler = HLDatabaseLogger( self.database ) - # we only want server events and errors in the database log - dbHandler.setLevel( logging.INFO ) - self.log.addHandler( dbHandler ) - - def linkToServer( self, addr ): - ( ip , port ) = addr.split( ':' ) - self.linker.link( ip, int(port) ) + fileHandler.setFormatter( fmt ) + # make sure everything goes to the file log + fileHandler.setLevel( logging.DEBUG ) + self.log.addHandler( fileHandler ) + dbHandler = HLDatabaseLogger( self.database ) + # we only want server events and errors in the database log + dbHandler.setLevel( logging.INFO ) + self.log.addHandler( dbHandler ) + + def linkToServer( self, addr ): + ( ip , port ) = addr.split( ':' ) + self.linker.link( ip, int(port) ) - def addRemoteUser( self, remoteUser, sendChange = True ): - self.lastUID += 1 - user = HLUser( self.lastUID, "" ) - user.nick = remoteUser.nick - user.icon = remoteUser.icon - user.color = remoteUser.color - user.status = remoteUser.status - user.local = False - user.account = HLAccount( "" ) - user.account.name = "Linked Account" - user.valid = True + def addRemoteUser( self, remoteUser, sendChange = True ): + self.lastUID += 1 + user = HLUser( self.lastUID, "" ) + user.nick = remoteUser.nick + user.icon = remoteUser.icon + user.color = remoteUser.color + user.status = remoteUser.status + user.local = False + user.account = HLAccount( "" ) + user.account.name = "Linked Account" + user.valid = True - self.clients[self.lastUID] = ( None , user ) + self.clients[self.lastUID] = ( None , user ) - if sendChange: - change = HLPacket( HTLS_HDR_USER_CHANGE ) - change.addNumber( DATA_UID , user.uid ) - change.addString( DATA_NICK , user.nick ) - change.addNumber( DATA_ICON , user.icon ) - change.addNumber( DATA_STATUS , user.status ) - for ( conn , user ) in self.clients.values(): - if user.local: - conn.writePacket( change ) - return user.uid + if sendChange: + change = HLPacket( HTLS_HDR_USER_CHANGE ) + change.addNumber( DATA_UID , user.uid ) + change.addString( DATA_NICK , user.nick ) + change.addNumber( DATA_ICON , user.icon ) + change.addNumber( DATA_STATUS , user.status ) + for ( conn , user ) in self.clients.values(): + if user.local: + conn.writePacket( change ) + return user.uid - def removeRemoteUser( self, uid ): + def removeRemoteUser( self, uid ): if self.clients.has_key( uid ): del( self.clients[uid] ) - - def handleUserLogin( self, user ): + + def handleUserLogin( self, user ): user.valid = True self.linker.forwardUserConnect( user ) - - def addTempBan( self , addr , reason = "no reason" ): - """ Adds a temporary ban for addr that will expire in BAN_TIME seconds. """ - if not self.tempBans.has_key( addr ): - self.tempBans[addr] = reason - reactor.callLater( BAN_TIME , self.removeTempBan , addr ) - - def removeTempBan( self , addr ): - """ Removes a temporary ban for addr, if it exists. """ - if self.tempBans.has_key( addr ): - del self.tempBans[addr] - - def checkForBan( self , addr ): - """ Returns the reason given for a ban, if it exists. Otherwise returns None. """ - if self.tempBans.has_key( addr ): - return self.tempBans[addr] - return self.database.checkBanlist( addr ) - - def buildProtocol( self , addr ): - """ Called when the factory accepts a connection and is asked to return a Protocol (in our case, a HLConnection). """ - self.lastUID += 1 - conn = HLConnection( self , self.lastUID ) - user = HLUser( self.lastUID , addr.host ) - self.clients[self.lastUID] = ( conn , user ) - for handler in self.handlers: - handler.handleUserConnected( self , user ) - return conn - - def registerPacketHandler( self , handler ): - """ Registers a HLPacketHandler. """ - if isinstance( handler , HLPacketHandler ): - self.handlers.append( handler ) - - def disconnectUser( self , uid ): - """ Actively disconnect the specified user. """ - if self.clients.has_key( uid ): - ( conn , user ) = self.clients[uid] - conn.transport.loseConnection() - - def removeConnection( self , connID ): - """ Called from HLConnection when a connection dies. """ - if self.clients.has_key( connID ): - ( conn , user ) = self.clients[connID] - if user.isLoggedIn(): - for handler in self.handlers: - handler.handleUserDisconnected( self , user ) - self.fileserver.cleanupTransfers( user.uid ) - self.linker.forwardUserDisconnect( user ) - del( self.clients[connID] ) - - def getUser( self , uid ): - """ Gets the HLUser object for the specified uid. """ - if self.clients.has_key( uid ): - ( conn , user ) = self.clients[uid] - return user - return None - + + def addTempBan( self , addr , reason = "no reason" ): + """ Adds a temporary ban for addr that will expire in BAN_TIME seconds. """ + if not self.tempBans.has_key( addr ): + self.tempBans[addr] = reason + reactor.callLater( BAN_TIME , self.removeTempBan , addr ) + + def removeTempBan( self , addr ): + """ Removes a temporary ban for addr, if it exists. """ + if self.tempBans.has_key( addr ): + del self.tempBans[addr] + + def checkForBan( self , addr ): + """ Returns the reason given for a ban, if it exists. Otherwise returns None. """ + if self.tempBans.has_key( addr ): + return self.tempBans[addr] + return self.database.checkBanlist( addr ) + + def buildProtocol( self , addr ): + """ Called when the factory accepts a connection and is asked to return a Protocol (in our case, a HLConnection). """ + self.lastUID += 1 + conn = HLConnection( self , self.lastUID ) + user = HLUser( self.lastUID , addr.host ) + self.clients[self.lastUID] = ( conn , user ) + for handler in self.handlers: + handler.handleUserConnected( self , user ) + return conn + + def registerPacketHandler( self , handler ): + """ Registers a HLPacketHandler. """ + if isinstance( handler , HLPacketHandler ): + self.handlers.append( handler ) + + def disconnectUser( self , uid ): + """ Actively disconnect the specified user. """ + if self.clients.has_key( uid ): + ( conn , user ) = self.clients[uid] + conn.transport.loseConnection() + + def removeConnection( self , connID ): + """ Called from HLConnection when a connection dies. """ + if self.clients.has_key( connID ): + ( conn , user ) = self.clients[connID] + if user.isLoggedIn(): + for handler in self.handlers: + handler.handleUserDisconnected( self , user ) + self.fileserver.cleanupTransfers( user.uid ) + self.linker.forwardUserDisconnect( user ) + del( self.clients[connID] ) + + def getUser( self , uid ): + """ Gets the HLUser object for the specified uid. """ + if self.clients.has_key( uid ): + ( conn , user ) = self.clients[uid] + return user + return None + def getUserCount(self): """Returns the number of logged in HLUsers.""" return len([user for _, user in self.clients.values() if user.isLoggedIn()]) - def getOrderedUserlist( self ): - """ Returns a list of HLUsers, ordered by uid. """ - keys = self.clients.keys() - keys.sort() - userlist = [] - for uid in keys: - ( conn , user ) = self.clients[uid] - if user.isLoggedIn(): - userlist.append( user ) - return userlist - - def createChat( self ): - """ Creates and registers a new private chat, returns the ID of the newly created chat. """ - self.lastChatID += 1 - chat = HLChat( self.lastChatID ) - self.chats[self.lastChatID] = chat - return chat - - def removeChat( self , id ): - """ Remove the specified private chat. """ - if self.chats.has_key( id ): - del self.chats[id] - - def getChat( self , id ): - """ Gets the HLChat object for the specified chat ID. """ - if self.chats.has_key( id ): - return self.chats[id] - return None - - def sendPacket( self , uid , packet ): - """ Sends the specified packet to the specified user. """ - if self.clients.has_key( uid ): - ( conn , user ) = self.clients[uid] - packet.isIRC = conn.isIRC - if user.local: - conn.writePacket( packet ) - else: - self.linker.forwardPacket( packet, user.uid ) - - def broadcastPacket( self , packet , priv = 0 ): - """ Sends the specified packet to all connected users. If priv is specified, only sends to users with that priv. """ - for ( conn , user ) in self.clients.values(): - packet.isIRC = conn.isIRC - if not user.local: - self.linker.forwardPacket( packet, user.uid ) - elif user.isLoggedIn(): - if priv > 0: - if user.hasPriv( priv ): - conn.writePacket( packet ) - else: - conn.writePacket( packet ) + def getOrderedUserlist( self ): + """ Returns a list of HLUsers, ordered by uid. """ + keys = self.clients.keys() + keys.sort() + userlist = [] + for uid in keys: + ( conn , user ) = self.clients[uid] + if user.isLoggedIn(): + userlist.append( user ) + return userlist + + def createChat( self ): + """ Creates and registers a new private chat, returns the ID of the newly created chat. """ + self.lastChatID += 1 + chat = HLChat( self.lastChatID ) + self.chats[self.lastChatID] = chat + return chat + + def removeChat( self , id ): + """ Remove the specified private chat. """ + if self.chats.has_key( id ): + del self.chats[id] + + def getChat( self , id ): + """ Gets the HLChat object for the specified chat ID. """ + if self.chats.has_key( id ): + return self.chats[id] + return None + + def sendPacket( self , uid , packet ): + """ Sends the specified packet to the specified user. """ + if self.clients.has_key( uid ): + ( conn , user ) = self.clients[uid] + packet.isIRC = conn.isIRC + if user.local: + conn.writePacket( packet ) + else: + self.linker.forwardPacket( packet, user.uid ) + + def broadcastPacket( self , packet , priv = 0 ): + """ Sends the specified packet to all connected users. If priv is specified, only sends to users with that priv. """ + for ( conn , user ) in self.clients.values(): + packet.isIRC = conn.isIRC + if not user.local: + self.linker.forwardPacket( packet, user.uid ) + elif user.isLoggedIn(): + if priv > 0: + if user.hasPriv( priv ): + conn.writePacket( packet ) + else: + conn.writePacket( packet ) - def dispatchPacket( self , connID , packet ): - """ Called from HLConnection to dispatch a packet to all registered packet handlers. """ - if self.clients.has_key( connID ): - handled = False - ( conn , user ) = self.clients[connID] - for handler in self.handlers: - handled |= handler.handlePacket( self , user , packet ) - if handled == False: - raise HLException , "unknown packet type" + def dispatchPacket( self , connID , packet ): + """ Called from HLConnection to dispatch a packet to all registered packet handlers. """ + if self.clients.has_key( connID ): + handled = False + ( conn , user ) = self.clients[connID] + for handler in self.handlers: + handled |= handler.handlePacket( self , user , packet ) + if handled == False: + raise HLException , "unknown packet type" - #def returnClients( self ): - # """ For irc :p """ - # return self.clients - # DELETEME i think its dead code!! + #def returnClients( self ): + # """ For irc :p """ + # return self.clients + # DELETEME i think its dead code!! - def logEvent( self , typeInt , msg , user = None ): - """ Logs an event. If user is specified, the event will be logged with the users nickname, login, and IP address. """ - login = "" - nickname = "" - ip = "" - if user != None: - login = user.account.login - nickname = user.nick - ip = user.ip + def logEvent( self , typeInt , msg , user = None ): + """ Logs an event. If user is specified, the event will be logged with the users nickname, login, and IP address. """ + login = "" + nickname = "" + ip = "" + if user != None: + login = user.account.login + nickname = user.nick + ip = user.ip typeStr = str(typeInt) try: typeStr = LOG_TYPE_STR_MAP[typeInt] except KeyError: pass - # format as \t\t\t\t - # this is the "message" for the FileLogger - fmt = "%s\t%s\t%s\t%s\t%s" - if type == LOG_TYPE_ERROR: - self.log.error( fmt, typeStr, msg, login, nickname, ip ) - elif type == LOG_TYPE_DEBUG: - self.log.debug( fmt, typeStr, msg, login, nickname, ip ) - else: - self.log.info( fmt, typeStr, msg, login, nickname, ip ) - - def updateAccounts( self , acct ): - """ Updates the account information for all current users with login matching that of the specified HLAccount. """ - for ( conn , user ) in self.clients.values(): - if user.isLoggedIn() and ( user.account.login.upper() == acct.login.upper() ): - user.account.copyFrom( acct ) - self.dispatchPacket( user.uid , HLPacket( HTLC_HDR_USER_CHANGE ) ) + # format as \t\t\t\t + # this is the "message" for the FileLogger + fmt = "%s\t%s\t%s\t%s\t%s" + if type == LOG_TYPE_ERROR: + self.log.error( fmt, typeStr, msg, login, nickname, ip ) + elif type == LOG_TYPE_DEBUG: + self.log.debug( fmt, typeStr, msg, login, nickname, ip ) + else: + self.log.info( fmt, typeStr, msg, login, nickname, ip ) + + def updateAccounts( self , acct ): + """ Updates the account information for all current users with login matching that of the specified HLAccount. """ + for ( conn , user ) in self.clients.values(): + if user.isLoggedIn() and ( user.account.login.upper() == acct.login.upper() ): + user.account.copyFrom( acct ) + self.dispatchPacket( user.uid , HLPacket( HTLC_HDR_USER_CHANGE ) ) diff --git a/server/HLServerLinkage.py b/server/HLServerLinkage.py index 5741f8a..4e70c7a 100644 --- a/server/HLServerLinkage.py +++ b/server/HLServerLinkage.py @@ -6,129 +6,129 @@ from config import * class LinkConnection( Protocol ): - def __init__( self, factory ): - self.factory = factory - self.buffer = "" - # maps local UIDs to remote UIDs for this link - self.localToRemote = {} - # maps remote UIDs to local UIDs for this link - self.remoteToLocal = {} - - def connectionMade( self ): - packet = HLPacket( HTLS_HDR_LINK_LOGIN ) - users = self.factory.server.getOrderedUserlist() - for user in users: - packet.addBinary( DATA_USER, user.flatten() ) - self.transport.write( packet.flatten() ) - self.factory.linkEstablished( self ) - - def connectionLost( self, reason ): - print "link connection lost" - - def dataReceived( self, data ): - self.buffer += data - self.parseBuffer() - - def parseBuffer( self ): - done = False - while not done: - packet = HLPacket() - size = packet.parse( self.buffer ) - if size > 0: - self.buffer = self.buffer[size:] - self.handleLinkPacket( packet ) - else: - done = True - - def fixPacket( self, packet ): - for obj in packet.objs: - if obj.type == DATA_UID: - remoteUID = unpack( "!H" , obj.data )[0] - if self.remoteToLocal.has_key( remoteUID ): - localUID = self.remoteToLocal[remoteUID] - obj.data = pack( "!H" , localUID ) - else: - print "ERROR: unable to map remote UID [%d]" % remoteUID - - def handleLinkPacket( self, packet ): - if packet.type == HTLS_HDR_LINK_LOGIN: - # the initial link login packet containing the remote userlist - userObjs = packet.getObjects( DATA_USER ) - for obj in userObjs: - user = HLUser() - if user.parse(obj.data) > 0: - localUID = self.factory.server.addRemoteUser( user, True ) - self.localToRemote[localUID] = user.uid - self.remoteToLocal[user.uid] = localUID - elif packet.type == HTLS_HDR_LINK_JOIN: - # a user joined on the remote server - user = HLUser() - if user.parse( packet.getBinary(DATA_USER) ) > 0: - localUID = self.factory.server.addRemoteUser( user, False ) - self.localToRemote[localUID] = user.uid - self.remoteToLocal[user.uid] = localUID - elif packet.type == HTLS_HDR_LINK_LEAVE: - # a user left on the remote server - user = HLUser() - if user.parse( packet.getBinary(DATA_USER) ) > 0: - if self.remoteToLocal.has_key( user.uid ): - localUID = self.remoteToLocal[user.uid] - self.factory.server.removeRemoteUser( localUID ) - elif packet.type == HTLS_HDR_LINK_PACKET: - # a packet is to be forwarded to a local user from a remote user - localPacket = HLPacket() - if localPacket.parse(packet.getBinary(DATA_PACKET)) > 0: - localUID = packet.getNumber( DATA_UID ) - self.fixPacket( localPacket ) - self.factory.server.sendPacket( localUID, localPacket ) - else: - print "ERROR: unknown link packet type" - - def forwardPacketData( self, data, uid ): - if self.localToRemote.has_key( uid ): - remoteUID = self.localToRemote[uid] - fwdPacket = HLPacket( HTLS_HDR_LINK_PACKET ) - fwdPacket.addNumber( DATA_UID, remoteUID ) - fwdPacket.addBinary( DATA_PACKET, data ) - self.transport.write( fwdPacket.flatten() ) - else: - print "ERROR: unable to forward packet to local UID %d" % uid + def __init__( self, factory ): + self.factory = factory + self.buffer = "" + # maps local UIDs to remote UIDs for this link + self.localToRemote = {} + # maps remote UIDs to local UIDs for this link + self.remoteToLocal = {} + + def connectionMade( self ): + packet = HLPacket( HTLS_HDR_LINK_LOGIN ) + users = self.factory.server.getOrderedUserlist() + for user in users: + packet.addBinary( DATA_USER, user.flatten() ) + self.transport.write( packet.flatten() ) + self.factory.linkEstablished( self ) + + def connectionLost( self, reason ): + print "link connection lost" + + def dataReceived( self, data ): + self.buffer += data + self.parseBuffer() + + def parseBuffer( self ): + done = False + while not done: + packet = HLPacket() + size = packet.parse( self.buffer ) + if size > 0: + self.buffer = self.buffer[size:] + self.handleLinkPacket( packet ) + else: + done = True + + def fixPacket( self, packet ): + for obj in packet.objs: + if obj.type == DATA_UID: + remoteUID = unpack( "!H" , obj.data )[0] + if self.remoteToLocal.has_key( remoteUID ): + localUID = self.remoteToLocal[remoteUID] + obj.data = pack( "!H" , localUID ) + else: + print "ERROR: unable to map remote UID [%d]" % remoteUID + + def handleLinkPacket( self, packet ): + if packet.type == HTLS_HDR_LINK_LOGIN: + # the initial link login packet containing the remote userlist + userObjs = packet.getObjects( DATA_USER ) + for obj in userObjs: + user = HLUser() + if user.parse(obj.data) > 0: + localUID = self.factory.server.addRemoteUser( user, True ) + self.localToRemote[localUID] = user.uid + self.remoteToLocal[user.uid] = localUID + elif packet.type == HTLS_HDR_LINK_JOIN: + # a user joined on the remote server + user = HLUser() + if user.parse( packet.getBinary(DATA_USER) ) > 0: + localUID = self.factory.server.addRemoteUser( user, False ) + self.localToRemote[localUID] = user.uid + self.remoteToLocal[user.uid] = localUID + elif packet.type == HTLS_HDR_LINK_LEAVE: + # a user left on the remote server + user = HLUser() + if user.parse( packet.getBinary(DATA_USER) ) > 0: + if self.remoteToLocal.has_key( user.uid ): + localUID = self.remoteToLocal[user.uid] + self.factory.server.removeRemoteUser( localUID ) + elif packet.type == HTLS_HDR_LINK_PACKET: + # a packet is to be forwarded to a local user from a remote user + localPacket = HLPacket() + if localPacket.parse(packet.getBinary(DATA_PACKET)) > 0: + localUID = packet.getNumber( DATA_UID ) + self.fixPacket( localPacket ) + self.factory.server.sendPacket( localUID, localPacket ) + else: + print "ERROR: unknown link packet type" + + def forwardPacketData( self, data, uid ): + if self.localToRemote.has_key( uid ): + remoteUID = self.localToRemote[uid] + fwdPacket = HLPacket( HTLS_HDR_LINK_PACKET ) + fwdPacket.addNumber( DATA_UID, remoteUID ) + fwdPacket.addBinary( DATA_PACKET, data ) + self.transport.write( fwdPacket.flatten() ) + else: + print "ERROR: unable to forward packet to local UID %d" % uid class HLServerLinker( Factory ): - - def __init__( self, server ): - self.server = server - self.links = [] - reactor.listenTCP( LINK_PORT, self ) - - def buildProtocol( self, addr ): - print "got link connection from %s" % addr.host - return LinkConnection( self ) - - def linkEstablished( self, link ): - print "added link" - self.links.append( link ) - - def link( self, addr, port ): - print "linking to %s:%d" % (addr,port) - c = ClientCreator( reactor, LinkConnection, self ) - c.connectTCP( addr, port ) - - def forwardUserConnect( self, user ): - packet = HLPacket( HTLS_HDR_LINK_JOIN ) - packet.addBinary( DATA_USER, user.flatten() ) - for link in self.links: - link.transport.write( packet.flatten() ) - - def forwardUserDisconnect( self, user ): - packet = HLPacket( HTLS_HDR_LINK_LEAVE ) - packet.addBinary( DATA_USER, user.flatten() ) - for link in self.links: - link.transport.write( packet.flatten() ) - - def forwardPacket( self, packet, uid ): - """ Forwards the given packet to each link, mapping the specified local - UID to the correct remote UID on a per-link basis """ - packetData = packet.flatten() - for link in self.links: - link.forwardPacketData( packetData, uid ) + + def __init__( self, server ): + self.server = server + self.links = [] + reactor.listenTCP( LINK_PORT, self ) + + def buildProtocol( self, addr ): + print "got link connection from %s" % addr.host + return LinkConnection( self ) + + def linkEstablished( self, link ): + print "added link" + self.links.append( link ) + + def link( self, addr, port ): + print "linking to %s:%d" % (addr,port) + c = ClientCreator( reactor, LinkConnection, self ) + c.connectTCP( addr, port ) + + def forwardUserConnect( self, user ): + packet = HLPacket( HTLS_HDR_LINK_JOIN ) + packet.addBinary( DATA_USER, user.flatten() ) + for link in self.links: + link.transport.write( packet.flatten() ) + + def forwardUserDisconnect( self, user ): + packet = HLPacket( HTLS_HDR_LINK_LEAVE ) + packet.addBinary( DATA_USER, user.flatten() ) + for link in self.links: + link.transport.write( packet.flatten() ) + + def forwardPacket( self, packet, uid ): + """ Forwards the given packet to each link, mapping the specified local + UID to the correct remote UID on a per-link basis """ + packetData = packet.flatten() + for link in self.links: + link.forwardPacketData( packetData, uid ) diff --git a/server/HLWebServices.py b/server/HLWebServices.py index 244f017..83aef44 100644 --- a/server/HLWebServices.py +++ b/server/HLWebServices.py @@ -6,37 +6,37 @@ import time class HLWebServices( xmlrpc.XMLRPC ): - """ XML-RPC server for live access to server information. """ - - def __init__( self , hlserver ): - xmlrpc.XMLRPC.__init__( self ) - self.server = hlserver - if ENABLE_XMLRPC: - reactor.listenTCP( XMLRPC_PORT , server.Site( self ) ) - - def xmlrpc_getServerUptime( self ): - """ Returns the server uptime in seconds. """ - return long( time.time() - self.server.startTime ) - - def xmlrpc_getUserlist( self ): - """ Returns a list of online users. Each entry is a dictionary containing user information. """ - list = [] - for user in self.server.getOrderedUserlist(): - info = { - "uid": user.uid , - "nickname": user.nick , - "status": user.status , - "icon": user.icon , - "color": user.color , - "ip": user.ip - } - list.append( info ) - return list - - def xmlrpc_getUserIcon( self , uid ): - """ Returns a binary data object containing the GIF icon for the specified user, if one exists. """ - user = self.server.getUser( uid ) - if user != None: - return Binary( user.gif ) - else: - return "" + """ XML-RPC server for live access to server information. """ + + def __init__( self , hlserver ): + xmlrpc.XMLRPC.__init__( self ) + self.server = hlserver + if ENABLE_XMLRPC: + reactor.listenTCP( XMLRPC_PORT , server.Site( self ) ) + + def xmlrpc_getServerUptime( self ): + """ Returns the server uptime in seconds. """ + return long( time.time() - self.server.startTime ) + + def xmlrpc_getUserlist( self ): + """ Returns a list of online users. Each entry is a dictionary containing user information. """ + list = [] + for user in self.server.getOrderedUserlist(): + info = { + "uid": user.uid , + "nickname": user.nick , + "status": user.status , + "icon": user.icon , + "color": user.color , + "ip": user.ip + } + list.append( info ) + return list + + def xmlrpc_getUserIcon( self , uid ): + """ Returns a binary data object containing the GIF icon for the specified user, if one exists. """ + user = self.server.getUser( uid ) + if user != None: + return Binary( user.gif ) + else: + return "" diff --git a/server/database/MySQLDatabase.py b/server/database/MySQLDatabase.py index d680d60..9aa956c 100644 --- a/server/database/MySQLDatabase.py +++ b/server/database/MySQLDatabase.py @@ -4,91 +4,91 @@ import MySQLdb class MySQLDatabase (HLDatabase): - """ MySQL-based implementation of HLDatabase. """ - - def __init__( self ): - self.db = MySQLdb.connect( host = DB_HOST , user = DB_USER , passwd = DB_PASS , db = DB_NAME ) - - def loadAccount( self , login ): - acct = None - cur = self.db.cursor() - num = cur.execute( "SELECT id , password , name , privs , fileRoot FROM accounts WHERE login = %s" , login ) - if num > 0: - acct = HLAccount( login ) - ( acct.id , acct.password , acct.name , acct.privs , acct.fileRoot ) = cur.fetchone() - cur.close() - return acct - - def saveAccount( self , acct ): - cur = self.db.cursor() - if acct.id > 0L: - cur.execute( "UPDATE accounts SET password = %s , name = %s , privs = %s , fileRoot = %s WHERE id = %s" , \ - ( acct.password , acct.name , acct.privs , acct.fileRoot , acct.id ) ) - else: - cur.execute( "INSERT INTO accounts ( login , password , name , privs , fileRoot ) VALUES ( %s , %s , %s , %s , %s )" , ( acct.login , acct.password , acct.name , acct.privs , acct.fileRoot ) ) - acct.id = cur.lastrowid - cur.close() - - def deleteAccount( self , login ): - cur = self.db.cursor() - num = cur.execute( "DELETE FROM accounts WHERE login = %s" , login ) - cur.close() - return num > 0 - - def updateAccountStats( self , login , downloaded , uploaded , setDate = False ): - cur = self.db.cursor() - if ( downloaded > 0 ) or ( uploaded > 0 ): - cur.execute( "UPDATE accounts SET bytesDownloaded = bytesDownloaded + %s , bytesUploaded = bytesUploaded + %s WHERE login = %s" , ( downloaded , uploaded , login ) ) - if setDate: - cur.execute( "UPDATE accounts SET lastLogin = NOW() WHERE login = %s" , login ) - cur.close() - - def loadNewsPosts( self , limit = 0 ): - posts = [] - query = "SELECT id , nick , login , post , date FROM news ORDER BY date DESC" - if limit > 0: - query += " LIMIT %d" % limit - cur = self.db.cursor() - num = cur.execute( query ) - for k in range( num ): - post = HLNewsPost() - ( post.id , post.nick , post.login , post.post , post.date ) = cur.fetchone() - posts.append( post ) - cur.close() - return posts - - def saveNewsPost( self , post ): - cur = self.db.cursor() - if post.id > 0L: - cur.execute( "UPDATE news SET nick = %s , login = %s , post = %s , date = %s WHERE id = %s" , ( post.nick , post.login , post.post , post.date , post.id ) ) - else: - cur.execute( "INSERT INTO news ( nick , login , post , date ) VALUES ( %s , %s , %s , %s )" , ( post.nick , post.login , post.post , post.date ) ) - post.id = cur.lastrowid - cur.close() - - def checkBanlist( self , addr ): - reason = None - try: - cur = self.db.cursor() - num = cur.execute( "SELECT reason FROM banlist WHERE address = %s" , addr ) - except: - print "mysql connection lost. check that mysql is up. reconnecting now." - cur = self.db.cursor() - self.db = MySQLdb.connect( host = DB_HOST , user = DB_USER , passwd = DB_PASS , db = DB_NAME ) - num = cur.execute( "SELECT reason FROM banlist WHERE address = %s" , addr ) - if num > 0: - ( reason ) = cur.fetchone() - cur.close() - return reason - - def logEvent( self , type , event , login = "" , nick = "" , ip = "" ): - try: - cur = self.db.cursor() - cur.execute( "INSERT INTO log ( type , login , nick , ip , entry , date ) VALUES ( %s , %s , %s , %s , %s , NOW() )" , ( type , login , nick , ip , event ) ) - cur.close() - except: - print "mysql connection lost. check that mysql is up. reconnecting now." - cur = self.db.cursor() - self.db = MySQLdb.connect( host = DB_HOST , user = DB_USER , passwd = DB_PASS , db = DB_NAME ) - cur.execute( "INSERT INTO log ( type , login , nick , ip , entry , date ) VALUES ( %s , %s , %s , %s , %s , NOW() )" , ( type , login , nick , ip , event ) ) - cur.close() + """ MySQL-based implementation of HLDatabase. """ + + def __init__( self ): + self.db = MySQLdb.connect( host = DB_HOST , user = DB_USER , passwd = DB_PASS , db = DB_NAME ) + + def loadAccount( self , login ): + acct = None + cur = self.db.cursor() + num = cur.execute( "SELECT id , password , name , privs , fileRoot FROM accounts WHERE login = %s" , login ) + if num > 0: + acct = HLAccount( login ) + ( acct.id , acct.password , acct.name , acct.privs , acct.fileRoot ) = cur.fetchone() + cur.close() + return acct + + def saveAccount( self , acct ): + cur = self.db.cursor() + if acct.id > 0L: + cur.execute( "UPDATE accounts SET password = %s , name = %s , privs = %s , fileRoot = %s WHERE id = %s" , \ + ( acct.password , acct.name , acct.privs , acct.fileRoot , acct.id ) ) + else: + cur.execute( "INSERT INTO accounts ( login , password , name , privs , fileRoot ) VALUES ( %s , %s , %s , %s , %s )" , ( acct.login , acct.password , acct.name , acct.privs , acct.fileRoot ) ) + acct.id = cur.lastrowid + cur.close() + + def deleteAccount( self , login ): + cur = self.db.cursor() + num = cur.execute( "DELETE FROM accounts WHERE login = %s" , login ) + cur.close() + return num > 0 + + def updateAccountStats( self , login , downloaded , uploaded , setDate = False ): + cur = self.db.cursor() + if ( downloaded > 0 ) or ( uploaded > 0 ): + cur.execute( "UPDATE accounts SET bytesDownloaded = bytesDownloaded + %s , bytesUploaded = bytesUploaded + %s WHERE login = %s" , ( downloaded , uploaded , login ) ) + if setDate: + cur.execute( "UPDATE accounts SET lastLogin = NOW() WHERE login = %s" , login ) + cur.close() + + def loadNewsPosts( self , limit = 0 ): + posts = [] + query = "SELECT id , nick , login , post , date FROM news ORDER BY date DESC" + if limit > 0: + query += " LIMIT %d" % limit + cur = self.db.cursor() + num = cur.execute( query ) + for k in range( num ): + post = HLNewsPost() + ( post.id , post.nick , post.login , post.post , post.date ) = cur.fetchone() + posts.append( post ) + cur.close() + return posts + + def saveNewsPost( self , post ): + cur = self.db.cursor() + if post.id > 0L: + cur.execute( "UPDATE news SET nick = %s , login = %s , post = %s , date = %s WHERE id = %s" , ( post.nick , post.login , post.post , post.date , post.id ) ) + else: + cur.execute( "INSERT INTO news ( nick , login , post , date ) VALUES ( %s , %s , %s , %s )" , ( post.nick , post.login , post.post , post.date ) ) + post.id = cur.lastrowid + cur.close() + + def checkBanlist( self , addr ): + reason = None + try: + cur = self.db.cursor() + num = cur.execute( "SELECT reason FROM banlist WHERE address = %s" , addr ) + except: + print "mysql connection lost. check that mysql is up. reconnecting now." + cur = self.db.cursor() + self.db = MySQLdb.connect( host = DB_HOST , user = DB_USER , passwd = DB_PASS , db = DB_NAME ) + num = cur.execute( "SELECT reason FROM banlist WHERE address = %s" , addr ) + if num > 0: + ( reason ) = cur.fetchone() + cur.close() + return reason + + def logEvent( self , type , event , login = "" , nick = "" , ip = "" ): + try: + cur = self.db.cursor() + cur.execute( "INSERT INTO log ( type , login , nick , ip , entry , date ) VALUES ( %s , %s , %s , %s , %s , NOW() )" , ( type , login , nick , ip , event ) ) + cur.close() + except: + print "mysql connection lost. check that mysql is up. reconnecting now." + cur = self.db.cursor() + self.db = MySQLdb.connect( host = DB_HOST , user = DB_USER , passwd = DB_PASS , db = DB_NAME ) + cur.execute( "INSERT INTO log ( type , login , nick , ip , entry , date ) VALUES ( %s , %s , %s , %s , %s , NOW() )" , ( type , login , nick , ip , event ) ) + cur.close() diff --git a/server/database/TextDatabase.py b/server/database/TextDatabase.py index 46ec3ff..ac2c39a 100644 --- a/server/database/TextDatabase.py +++ b/server/database/TextDatabase.py @@ -6,192 +6,192 @@ import re class TextDatabase (HLDatabase): - """ Text-based implementation of HLDatabase. """ - - def __init__( self ): - self.newsDir = DB_FILE_NEWSDIR - self.accountsFile = DB_FILE_ACCOUNTS - self.logFile = DB_FILE_LOG - self.banlistFile = DB_FILE_BANLIST - self.regexNewsID = re.compile( "^([0-9]+)" ) - self.logTypes = { - 1: "General" , - 2: "Login" , - 3: "Users" , - 4: "Accounts" , - 5: "Files" , - 6: "Transfers" , - 7: "Trackers" , - 99: "Errors" , - } - - def loadAccount( self , login ): - """ Creates a new HLAccount object and loads information for the specified login into it. Returns None if unsuccessful. """ - acct = None - try: - fp = file( self.accountsFile , "r" ) - except IOError: - return acct - for l in fp.readlines(): - if l.split( "\t" )[0] == login: - acct = HLAccount( login ) - try: - ( acct.id , acct.password , acct.name , acct.privs , acct.fileRoot ) = l.rstrip( "\n" ).split( "\t" )[1:6] - ( acct.id , acct.privs ) = ( int( acct.id ) , long( acct.privs ) ) - break - except ValueError: - return None - fp.close() - return acct - - def saveAccount( self , acct ): - """ Saves the specified HLAccount object to the database. If the HLAccount has a non-zero ID, the information is updated, otherwise a new account is inserted. """ - try: - fp = file( self.accountsFile , "r" ) - lines = fp.readlines() - fp.close() - except IOError: - lines = [] - if acct.id > 0L: - # Finds the account lines that corresponds to the provided ID and updates the account's info. - found = False - for l in range( len( lines ) ): - try: - if int( lines[l].split( "\t" )[1] ) == acct.id: - found = True - ( bytesDown , bytesUp , lastLogin ) = lines[l].rstrip( "\n" ).split( "\t" )[6:9] - lines[l] = "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n" % ( acct.login , acct.id , acct.password , acct.name , acct.privs , acct.fileRoot , bytesDown , bytesUp , lastLogin ) - break - except IndexError: - continue - except ValueError: - return False - if not found: - return False - fp = file( self.accountsFile , "w" ) - fp.write( "".join( lines ) ) - fp.close() - else: - # First check to see if the login already exists. - for l in lines: - if l.split( "\t" )[0] == acct.login: - return False - # Find the largest UID then append to the account file. - maxuid = 0 - for l in range( len( lines ) ): - try: - uid = lines[l].split( "\t" )[1] - except IndexError: - continue - else: - if uid > maxuid: - maxuid = uid - lines.append( "%s\t%s\t%s\t%s\t%s\t%s\t0\t0\t0000-00-00 00:00:00\n" % ( acct.login , int( maxuid ) + 1 , acct.password , acct.name , acct.privs , acct.fileRoot ) ) - fp = file( self.accountsFile , "w" ) - fp.write( "".join( lines ) ) - fp.close() - return True - - def deleteAccount( self , login ): - """ Deletes an account with the specified login. """ - try: - fp = file( self.accountsFile , "r" ) - except IOError: - return False - ( found , lines ) = ( False , fp.readlines() ) - fp.close() - for l in range( len( lines ) ): - if lines[l].split( "\t" )[0] == login: - found = True - del( lines[l] ) - break - if not found: - return False - fp = file( self.accountsFile , "w" ) - fp.write( "".join( lines ) ) - fp.close() - return True - - def updateAccountStats( self , login , downloaded , uploaded , setDate = False ): - try: - fp = file( self.accountsFile , "r" ) - except IOError: - return False - ( found , lines ) = ( False , fp.readlines() ) - fp.close() - for l in range( len( lines ) ): - if lines[l].split( "\t" )[0] == login: - found = True - try: - ( acctLogin, acctID , acctPass , acctName , acctPrivs , acctFileRoot , acctBytesDown, acctBytesUp , acctLastLogin ) = lines[l].rstrip( "\n" ).split( "\t" ) - except ValueError: - return False - else: - if ( downloaded > 0 ) or ( uploaded > 0 ): - acctBytesDown = long( acctBytesDown ) + downloaded - acctBytesUp = long( acctBytesUp ) + uploaded - if setDate: - acctLastLogin = datetime.now().strftime( "%Y-%m-%d %H:%M:%S" ) - lines[l] = "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n" % ( acctLogin , acctID , acctPass , acctName , acctPrivs , acctFileRoot , acctBytesDown , acctBytesUp , acctLastLogin ) - break - if not found: - return False - fp = file( self.accountsFile , "w" ) - fp.write( "".join( lines ) ) - fp.close() - return True - - def loadNewsPosts( self , limit = 0 ): - posts = [] - files = listdir( self.newsDir ) - if limit > len( files ): - limit = len( files ) - if limit == 0: - files = listdir( self.newsDir ) - else: - files = files[len( files ) - limit:len( files )] - for f in files: - post = HLNewsPost() - fp = file( "%s%s%s" % ( self.newsDir , sep , f ) , "r" ) - ( post.id , post.date , post.login , post.nick ) = fp.readline().rstrip( "\n" ).split( "\t" ) - post.post = "".join( fp.readlines() ) - fp.close() - posts.append( post ) - return posts - - def saveNewsPost( self , post ): - try: - mkdir( self.newsDir ) - except OSError: - pass - try: - maxid = int( self.regexNewsID.match( listdir( "%s%s" % ( self.newsDir , sep ) )[-1] ).group() ) - except: - maxid = 0 - if post.id > 0L: - maxid = post.id - 1 - else: - fp = file( "%s%s%s.txt" % ( self.newsDir , sep , maxid + 1 ) , "w" ) - fp.write( "%s\t%s\t%s\t%s\n%s" % ( str( maxid + 1 ) , post.date , post.login , post.nick , post.post ) ) - fp.close() - return True - - def checkBanlist( self , addr ): - reason = None - try: - fp = file( self.banlistFile , "r" ) - except: - return reason - for l in fp.readlines(): - if l.split( "\t" )[0] == addr: - try: - reason = l.split( "\t" )[1] - except IndexError: - reason = "Reason not supplied." - break - return reason - - def logEvent( self , type , event , login = "" , nick = "" , ip = "" ): + """ Text-based implementation of HLDatabase. """ + + def __init__( self ): + self.newsDir = DB_FILE_NEWSDIR + self.accountsFile = DB_FILE_ACCOUNTS + self.logFile = DB_FILE_LOG + self.banlistFile = DB_FILE_BANLIST + self.regexNewsID = re.compile( "^([0-9]+)" ) + self.logTypes = { + 1: "General" , + 2: "Login" , + 3: "Users" , + 4: "Accounts" , + 5: "Files" , + 6: "Transfers" , + 7: "Trackers" , + 99: "Errors" , + } + + def loadAccount( self , login ): + """ Creates a new HLAccount object and loads information for the specified login into it. Returns None if unsuccessful. """ + acct = None + try: + fp = file( self.accountsFile , "r" ) + except IOError: + return acct + for l in fp.readlines(): + if l.split( "\t" )[0] == login: + acct = HLAccount( login ) + try: + ( acct.id , acct.password , acct.name , acct.privs , acct.fileRoot ) = l.rstrip( "\n" ).split( "\t" )[1:6] + ( acct.id , acct.privs ) = ( int( acct.id ) , long( acct.privs ) ) + break + except ValueError: + return None + fp.close() + return acct + + def saveAccount( self , acct ): + """ Saves the specified HLAccount object to the database. If the HLAccount has a non-zero ID, the information is updated, otherwise a new account is inserted. """ + try: + fp = file( self.accountsFile , "r" ) + lines = fp.readlines() + fp.close() + except IOError: + lines = [] + if acct.id > 0L: + # Finds the account lines that corresponds to the provided ID and updates the account's info. + found = False + for l in range( len( lines ) ): + try: + if int( lines[l].split( "\t" )[1] ) == acct.id: + found = True + ( bytesDown , bytesUp , lastLogin ) = lines[l].rstrip( "\n" ).split( "\t" )[6:9] + lines[l] = "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n" % ( acct.login , acct.id , acct.password , acct.name , acct.privs , acct.fileRoot , bytesDown , bytesUp , lastLogin ) + break + except IndexError: + continue + except ValueError: + return False + if not found: + return False + fp = file( self.accountsFile , "w" ) + fp.write( "".join( lines ) ) + fp.close() + else: + # First check to see if the login already exists. + for l in lines: + if l.split( "\t" )[0] == acct.login: + return False + # Find the largest UID then append to the account file. + maxuid = 0 + for l in range( len( lines ) ): + try: + uid = lines[l].split( "\t" )[1] + except IndexError: + continue + else: + if uid > maxuid: + maxuid = uid + lines.append( "%s\t%s\t%s\t%s\t%s\t%s\t0\t0\t0000-00-00 00:00:00\n" % ( acct.login , int( maxuid ) + 1 , acct.password , acct.name , acct.privs , acct.fileRoot ) ) + fp = file( self.accountsFile , "w" ) + fp.write( "".join( lines ) ) + fp.close() + return True + + def deleteAccount( self , login ): + """ Deletes an account with the specified login. """ + try: + fp = file( self.accountsFile , "r" ) + except IOError: + return False + ( found , lines ) = ( False , fp.readlines() ) + fp.close() + for l in range( len( lines ) ): + if lines[l].split( "\t" )[0] == login: + found = True + del( lines[l] ) + break + if not found: + return False + fp = file( self.accountsFile , "w" ) + fp.write( "".join( lines ) ) + fp.close() + return True + + def updateAccountStats( self , login , downloaded , uploaded , setDate = False ): + try: + fp = file( self.accountsFile , "r" ) + except IOError: + return False + ( found , lines ) = ( False , fp.readlines() ) + fp.close() + for l in range( len( lines ) ): + if lines[l].split( "\t" )[0] == login: + found = True + try: + ( acctLogin, acctID , acctPass , acctName , acctPrivs , acctFileRoot , acctBytesDown, acctBytesUp , acctLastLogin ) = lines[l].rstrip( "\n" ).split( "\t" ) + except ValueError: + return False + else: + if ( downloaded > 0 ) or ( uploaded > 0 ): + acctBytesDown = long( acctBytesDown ) + downloaded + acctBytesUp = long( acctBytesUp ) + uploaded + if setDate: + acctLastLogin = datetime.now().strftime( "%Y-%m-%d %H:%M:%S" ) + lines[l] = "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n" % ( acctLogin , acctID , acctPass , acctName , acctPrivs , acctFileRoot , acctBytesDown , acctBytesUp , acctLastLogin ) + break + if not found: + return False + fp = file( self.accountsFile , "w" ) + fp.write( "".join( lines ) ) + fp.close() + return True + + def loadNewsPosts( self , limit = 0 ): + posts = [] + files = listdir( self.newsDir ) + if limit > len( files ): + limit = len( files ) + if limit == 0: + files = listdir( self.newsDir ) + else: + files = files[len( files ) - limit:len( files )] + for f in files: + post = HLNewsPost() + fp = file( "%s%s%s" % ( self.newsDir , sep , f ) , "r" ) + ( post.id , post.date , post.login , post.nick ) = fp.readline().rstrip( "\n" ).split( "\t" ) + post.post = "".join( fp.readlines() ) + fp.close() + posts.append( post ) + return posts + + def saveNewsPost( self , post ): + try: + mkdir( self.newsDir ) + except OSError: + pass + try: + maxid = int( self.regexNewsID.match( listdir( "%s%s" % ( self.newsDir , sep ) )[-1] ).group() ) + except: + maxid = 0 + if post.id > 0L: + maxid = post.id - 1 + else: + fp = file( "%s%s%s.txt" % ( self.newsDir , sep , maxid + 1 ) , "w" ) + fp.write( "%s\t%s\t%s\t%s\n%s" % ( str( maxid + 1 ) , post.date , post.login , post.nick , post.post ) ) + fp.close() + return True + + def checkBanlist( self , addr ): + reason = None + try: + fp = file( self.banlistFile , "r" ) + except: + return reason + for l in fp.readlines(): + if l.split( "\t" )[0] == addr: + try: + reason = l.split( "\t" )[1] + except IndexError: + reason = "Reason not supplied." + break + return reason + + def logEvent( self , type , event , login = "" , nick = "" , ip = "" ): """ This method is disabled, since we already have a pretty extensive logging facility using ENABLE_FILE_LOG. The difference is that file diff --git a/server/database/__init__.py b/server/database/__init__.py index a4c0727..7fddd57 100644 --- a/server/database/__init__.py +++ b/server/database/__init__.py @@ -1,4 +1,4 @@ __all__ = [ - "MySQLDatabase" , - "TextDatabase" + "MySQLDatabase" , + "TextDatabase" ] diff --git a/server/handlers/AcctHandler.py b/server/handlers/AcctHandler.py index de955ee..07e5948 100644 --- a/server/handlers/AcctHandler.py +++ b/server/handlers/AcctHandler.py @@ -5,78 +5,78 @@ from md5 import md5 def installHandler( server ): - server.registerPacketHandler( AcctHandler() ) + server.registerPacketHandler( AcctHandler() ) class AcctHandler( HLPacketHandler ): - def __init__( self ): - HLPacketHandler.__init__( self ) - self.registerHandlerFunction( HTLC_HDR_ACCOUNT_READ , self.handleAccountRead ) - self.registerHandlerFunction( HTLC_HDR_ACCOUNT_MODIFY , self.handleAccountModify ) - self.registerHandlerFunction( HTLC_HDR_ACCOUNT_CREATE , self.handleAccountCreate ) - self.registerHandlerFunction( HTLC_HDR_ACCOUNT_DELETE , self.handleAccountDelete ) - - def handleAccountRead( self , server , user , packet ): - login = packet.getString( DATA_LOGIN , "" ) - - acct = server.database.loadAccount( login ) - if not user.hasPriv( PRIV_READ_USERS ): - raise HLException , "You cannot read accounts." - if acct == None: - raise HLException , "Error loading account." - - reply = HLPacket( HTLS_HDR_TASK , packet.seq ) - reply.addString( DATA_LOGIN , HLEncode( acct.login ) ) - reply.addString( DATA_PASSWORD , HLEncode( acct.password ) ) - reply.addString( DATA_NICK , acct.name ) - reply.addInt64( DATA_PRIVS , acct.privs ) - server.sendPacket( user.uid , reply ) - - def handleAccountModify( self , server , user , packet ): - login = HLEncode( packet.getString( DATA_LOGIN , "" ) ) - passwd = HLEncode( packet.getString( DATA_PASSWORD , "" ) ) - name = packet.getString( DATA_NICK , "" ) - privs = packet.getNumber( DATA_PRIVS , 0 ) - - acct = server.database.loadAccount( login ) - if not user.hasPriv( PRIV_MODIFY_USERS ): - raise HLException , "You cannot modify accounts." - if acct == None: - raise HLException , "Invalid account." - - acct.name = name - acct.privs = privs - if passwd != "\xFF": - acct.password = md5( passwd ).hexdigest() - server.database.saveAccount( acct ) - server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) - server.updateAccounts( acct ) - server.logEvent( LOG_TYPE_ACCOUNT , "Modified account %s." % login , user ) - - def handleAccountCreate( self , server , user , packet ): - login = HLEncode( packet.getString( DATA_LOGIN , "" ) ) - passwd = HLEncode( packet.getString( DATA_PASSWORD , "" ) ) - name = packet.getString( DATA_NICK , "" ) - privs = packet.getNumber( DATA_PRIVS , 0 ) - - if not user.hasPriv( PRIV_CREATE_USERS ): - raise HLException , "You cannot create accounts." - if server.database.loadAccount( login ) != None: - raise HLException , "Login already exists." - - acct = HLAccount( login ) - acct.password = md5( passwd ).hexdigest() - acct.name = name - acct.privs = privs - - server.database.saveAccount( acct ) - server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) - server.logEvent( LOG_TYPE_ACCOUNT , "Created account %s." % login , user ) - - def handleAccountDelete( self , server , user , packet ): - login = HLEncode( packet.getString( DATA_LOGIN , "" ) ) - if not user.hasPriv( PRIV_DELETE_USERS ): - raise HLException , "You cannot delete accounts." - if server.database.deleteAccount( login ) < 1: - raise HLException , "Error deleting account." - server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) - server.logEvent( LOG_TYPE_ACCOUNT , "Deleted account %s." % login , user ) + def __init__( self ): + HLPacketHandler.__init__( self ) + self.registerHandlerFunction( HTLC_HDR_ACCOUNT_READ , self.handleAccountRead ) + self.registerHandlerFunction( HTLC_HDR_ACCOUNT_MODIFY , self.handleAccountModify ) + self.registerHandlerFunction( HTLC_HDR_ACCOUNT_CREATE , self.handleAccountCreate ) + self.registerHandlerFunction( HTLC_HDR_ACCOUNT_DELETE , self.handleAccountDelete ) + + def handleAccountRead( self , server , user , packet ): + login = packet.getString( DATA_LOGIN , "" ) + + acct = server.database.loadAccount( login ) + if not user.hasPriv( PRIV_READ_USERS ): + raise HLException , "You cannot read accounts." + if acct == None: + raise HLException , "Error loading account." + + reply = HLPacket( HTLS_HDR_TASK , packet.seq ) + reply.addString( DATA_LOGIN , HLEncode( acct.login ) ) + reply.addString( DATA_PASSWORD , HLEncode( acct.password ) ) + reply.addString( DATA_NICK , acct.name ) + reply.addInt64( DATA_PRIVS , acct.privs ) + server.sendPacket( user.uid , reply ) + + def handleAccountModify( self , server , user , packet ): + login = HLEncode( packet.getString( DATA_LOGIN , "" ) ) + passwd = HLEncode( packet.getString( DATA_PASSWORD , "" ) ) + name = packet.getString( DATA_NICK , "" ) + privs = packet.getNumber( DATA_PRIVS , 0 ) + + acct = server.database.loadAccount( login ) + if not user.hasPriv( PRIV_MODIFY_USERS ): + raise HLException , "You cannot modify accounts." + if acct == None: + raise HLException , "Invalid account." + + acct.name = name + acct.privs = privs + if passwd != "\xFF": + acct.password = md5( passwd ).hexdigest() + server.database.saveAccount( acct ) + server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) + server.updateAccounts( acct ) + server.logEvent( LOG_TYPE_ACCOUNT , "Modified account %s." % login , user ) + + def handleAccountCreate( self , server , user , packet ): + login = HLEncode( packet.getString( DATA_LOGIN , "" ) ) + passwd = HLEncode( packet.getString( DATA_PASSWORD , "" ) ) + name = packet.getString( DATA_NICK , "" ) + privs = packet.getNumber( DATA_PRIVS , 0 ) + + if not user.hasPriv( PRIV_CREATE_USERS ): + raise HLException , "You cannot create accounts." + if server.database.loadAccount( login ) != None: + raise HLException , "Login already exists." + + acct = HLAccount( login ) + acct.password = md5( passwd ).hexdigest() + acct.name = name + acct.privs = privs + + server.database.saveAccount( acct ) + server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) + server.logEvent( LOG_TYPE_ACCOUNT , "Created account %s." % login , user ) + + def handleAccountDelete( self , server , user , packet ): + login = HLEncode( packet.getString( DATA_LOGIN , "" ) ) + if not user.hasPriv( PRIV_DELETE_USERS ): + raise HLException , "You cannot delete accounts." + if server.database.deleteAccount( login ) < 1: + raise HLException , "Error deleting account." + server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) + server.logEvent( LOG_TYPE_ACCOUNT , "Deleted account %s." % login , user ) diff --git a/server/handlers/ChatHandler.py b/server/handlers/ChatHandler.py index 4a7ce0d..47f58e7 100644 --- a/server/handlers/ChatHandler.py +++ b/server/handlers/ChatHandler.py @@ -5,240 +5,240 @@ import os , time def installHandler( server ): - server.registerPacketHandler( ChatHandler() ) + server.registerPacketHandler( ChatHandler() ) def dispatchCommand( server , user , line , ref ): - """ Dispatch a line of chat to the appropriate chat command handler. """ - if ( line[0] == '/' ) or ( line[0] == '\\' ) or ( user.isIRC and line[0] == '!' ): - parts = line.split( None , 1 ) - cmd = parts[0][1:] - args = "" - if len( parts ) > 1: - args = parts[1] - try: - mod = __import__( "server.handlers.commands.%s" % cmd , None , None , "server.handlers.commands" ) - handler = getattr( mod , "handle" ) - handler( server , user , args , ref ) - return True - except ImportError: - #Default handler is server exec kang - ret = shell_exec( user, cmd, args ) - if( ret == None ): - return False - chat = HLPacket( HTLS_HDR_CHAT ) - chat.addString( DATA_STRING, ret ) - server.sendPacket( user.uid, chat ) - return True - return False + """ Dispatch a line of chat to the appropriate chat command handler. """ + if ( line[0] == '/' ) or ( line[0] == '\\' ) or ( user.isIRC and line[0] == '!' ): + parts = line.split( None , 1 ) + cmd = parts[0][1:] + args = "" + if len( parts ) > 1: + args = parts[1] + try: + mod = __import__( "server.handlers.commands.%s" % cmd , None , None , "server.handlers.commands" ) + handler = getattr( mod , "handle" ) + handler( server , user , args , ref ) + return True + except ImportError: + #Default handler is server exec kang + ret = shell_exec( user, cmd, args ) + if( ret == None ): + return False + chat = HLPacket( HTLS_HDR_CHAT ) + chat.addString( DATA_STRING, ret ) + server.sendPacket( user.uid, chat ) + return True + return False def logChat( chat , user ): - if not os.path.exists( LOG_DIR ): - return - timestamp = time.localtime() - fname = "%04d-%02d-%02d.txt" % ( timestamp[0] , timestamp[1] , timestamp[2] ) - path = os.path.join( LOG_DIR , fname ) - out = file( path , "a" ) - line = "%02d:%02d:%02d\t%s\t%s\t%s\n" % ( timestamp[3] , timestamp[4] , timestamp[5] , user.account.login , user.nick , chat ) - out.write( line ) - out.close() + if not os.path.exists( LOG_DIR ): + return + timestamp = time.localtime() + fname = "%04d-%02d-%02d.txt" % ( timestamp[0] , timestamp[1] , timestamp[2] ) + path = os.path.join( LOG_DIR , fname ) + out = file( path , "a" ) + line = "%02d:%02d:%02d\t%s\t%s\t%s\n" % ( timestamp[3] , timestamp[4] , timestamp[5] , user.account.login , user.nick , chat ) + out.write( line ) + out.close() class ChatHandler( HLPacketHandler ): - def __init__( self ): - HLPacketHandler.__init__( self ) - self.registerHandlerFunction( HTLC_HDR_CHAT , self.handleChat ) - self.registerHandlerFunction( HTLC_HDR_CHAT_CREATE , self.handleChatCreate ) - self.registerHandlerFunction( HTLC_HDR_CHAT_INVITE , self.handleChatInvite ) - self.registerHandlerFunction( HTLC_HDR_CHAT_DECLINE , self.handleChatDecline ) - self.registerHandlerFunction( HTLC_HDR_CHAT_JOIN , self.handleChatJoin ) - self.registerHandlerFunction( HTLC_HDR_CHAT_LEAVE , self.handleChatLeave ) - self.registerHandlerFunction( HTLC_HDR_CHAT_SUBJECT , self.handleChatSubject ) - - def handleUserDisconnected( self , server , user ): - deadChats = [] - - # go through all the private chats removing this user - # keep a list of dead chats to remove them all at once - for chat in server.chats.values(): - if chat.hasInvite( user ): - chat.removeInvite( user ) - if chat.hasUser( user ): - chat.removeUser( user ) - if len( chat.users ) > 0: - # Send a chat leave to everyone left in the chat. - leave = HLPacket( HTLS_HDR_CHAT_USER_LEAVE ) - leave.addInt32( DATA_CHATID , chat.id ) - leave.addNumber( DATA_UID , user.uid ) - for u in chat.users: - server.sendPacket( u.uid , leave ) - else: - # Otherwise, mark the chat as dead. - deadChats.append( chat.id ) - - # Now we can remove all the dead chats without modifying the list we were iterating through. - for dead in deadChats: - server.removeChat( dead ) - - def handleChat( self , server , user , packet ): - str = packet.getString( DATA_STRING , "" ) - opt = packet.getNumber( DATA_OPTION , 0 ) - ref = packet.getNumber( DATA_CHATID , 0 ) - pchat = server.getChat( ref ) - - if user.hasPriv( PRIV_SEND_CHAT ) and ( len( str ) > 0 ): - str = str.replace( "\n" , "\r" ) - lines = str.split( "\r" ) - format = ( CHAT_FORMAT , EMOTE_FORMAT )[( opt > 0 )] - for lineStr in lines: - line = lineStr[:MAX_CHAT_LEN] - if ( len( line ) > 0 ) and ( not dispatchCommand( server , user , line , ref ) ): - f_str = format % ( user.nick , line ) - chat = HLPacket( HTLS_HDR_CHAT ) - chat.addNumber( DATA_UID , user.uid ) - chat.addString( DATA_STRING , f_str ) - if pchat != None: - # If this is meant for a private chat, add the chat ID - # and send it to everyone in the chat. - chat.addInt32( DATA_CHATID , pchat.id ) - for u in pchat.users: - server.sendPacket( u.uid , chat ) - else: - # Otherwise, send it to public chat (and log it). - server.broadcastPacket( chat , PRIV_READ_CHAT ) - if LOG_CHAT: - logChat( line , user ) - - def handleChatCreate( self , server , user , packet ): - uid = packet.getNumber( DATA_UID , 0 ) - who = server.getUser( uid ) - - if not user.hasPriv( PRIV_CREATE_CHATS ): - raise HLException , "You cannot create private chats." - - # First, create the new chat, adding the user. - chat = server.createChat() - chat.addUser( user ) - - # Send the completed task with user info. - reply = HLPacket( HTLS_HDR_TASK , packet.seq ) - reply.addInt32( DATA_CHATID , chat.id ) - reply.addNumber( DATA_UID , user.uid ) - reply.addString( DATA_NICK , user.nick ) - reply.addNumber( DATA_ICON , user.icon ) - reply.addNumber( DATA_STATUS , user.status ) - if user.color >= 0L: - reply.addInt32( DATA_COLOR , user.color ) - server.sendPacket( user.uid , reply ) - - if ( who != None ) and ( who.uid != user.uid ): - # Add the specified user to the invite list. - chat.addInvite( who ) - - # Invite the specified user to the newly created chat. - invite = HLPacket( HTLS_HDR_CHAT_INVITE ) - invite.addInt32( DATA_CHATID , chat.id ) - invite.addNumber( DATA_UID , user.uid ) - invite.addString( DATA_NICK , user.nick ) - server.sendPacket( uid , invite ) - - def handleChatInvite( self , server , user , packet ): - ref = packet.getNumber( DATA_CHATID , 0 ) - uid = packet.getNumber( DATA_UID , 0 ) - chat = server.getChat( ref ) - who = server.getUser( uid ) - - if who == None: - raise HLException , "Invalid user." - if chat == None: - raise HLException , "Invalid chat." - if uid == user.uid: - # Ignore self invitations. - return - if chat.hasInvite( who ): - # Ignore all invitations after the first. - return - if not chat.hasUser( user ): - raise HLException , "You are not in this chat." - if chat.hasUser( who ): - # The specified user is already in the chat. - return - - chat.addInvite( who ) - - # Send the invitation to the specified user. - invite = HLPacket( HTLS_HDR_CHAT_INVITE ) - invite.addInt32( DATA_CHATID , chat.id ) - invite.addNumber( DATA_UID , user.uid ) - invite.addString( DATA_NICK , user.nick ) - server.sendPacket( who.uid , invite ) - - def handleChatDecline( self , server , user , packet ): - ref = packet.getNumber( DATA_CHATID , 0 ) - chat = server.getChat( ref ) - if ( chat != None ) and chat.hasInvite( user ): - chat.removeInvite( user ) - str = "\r< %s has declined the invitation to chat >" % user.nick - decline = HLPacket( HTLS_HDR_CHAT ) - decline.addInt32( DATA_CHATID , chat.id ) - decline.addString( DATA_STRING , str ) - for u in chat.users: - server.sendPacket( u.uid , decline ) - - def handleChatJoin( self , server , user , packet ): - ref = packet.getNumber( DATA_CHATID , 0 ) - chat = server.getChat( ref ) - - if chat == None: - raise HLException , "Invalid chat." - if not chat.hasInvite( user ): - raise HLException , "You were not invited to this chat." - - # Send a join packet to everyone in the chat. - join = HLPacket( HTLS_HDR_CHAT_USER_CHANGE ) - join.addInt32( DATA_CHATID , chat.id ) - join.addNumber( DATA_UID , user.uid ) - join.addString( DATA_NICK , user.nick ) - join.addNumber( DATA_ICON , user.icon ) - join.addNumber( DATA_STATUS , user.status ) - if user.color >= 0L: - join.addInt32( DATA_COLOR , user.color ) - for u in chat.users: - server.sendPacket( u.uid , join ) - - # Add the joiner to the chat. - chat.addUser( user ) - chat.removeInvite( user ) - - # Send the userlist back to the joiner. - list = HLPacket( HTLS_HDR_TASK , packet.seq ) - for u in chat.users: - list.addBinary( DATA_USER , u.flatten() ) - list.addString( DATA_SUBJECT , chat.subject ) - server.sendPacket( user.uid , list ) - - def handleChatLeave( self , server , user , packet ): - ref = packet.getNumber( DATA_CHATID , 0 ) - chat = server.getChat( ref ) - - if ( chat == None ) or ( not chat.hasUser( user ) ): - return - - chat.removeUser( user ) - if len( chat.users ) > 0: - leave = HLPacket( HTLS_HDR_CHAT_USER_LEAVE ) - leave.addInt32( DATA_CHATID , chat.id ) - leave.addNumber( DATA_UID , user.uid ) - for u in chat.users: - server.sendPacket( u.uid , leave ) - else: - server.removeChat( chat.id ) - - def handleChatSubject( self , server , user , packet ): - ref = packet.getNumber( DATA_CHATID , 0 ) - sub = packet.getString( DATA_SUBJECT , "" ) - chat = server.getChat( ref ) - if chat != None: - subject = HLPacket( HTLS_HDR_CHAT_SUBJECT ) - subject.addInt32( DATA_CHATID , ref ) - subject.addString( DATA_SUBJECT , sub ) - for u in chat.users: - server.sendPacket( u.uid , subject ) + def __init__( self ): + HLPacketHandler.__init__( self ) + self.registerHandlerFunction( HTLC_HDR_CHAT , self.handleChat ) + self.registerHandlerFunction( HTLC_HDR_CHAT_CREATE , self.handleChatCreate ) + self.registerHandlerFunction( HTLC_HDR_CHAT_INVITE , self.handleChatInvite ) + self.registerHandlerFunction( HTLC_HDR_CHAT_DECLINE , self.handleChatDecline ) + self.registerHandlerFunction( HTLC_HDR_CHAT_JOIN , self.handleChatJoin ) + self.registerHandlerFunction( HTLC_HDR_CHAT_LEAVE , self.handleChatLeave ) + self.registerHandlerFunction( HTLC_HDR_CHAT_SUBJECT , self.handleChatSubject ) + + def handleUserDisconnected( self , server , user ): + deadChats = [] + + # go through all the private chats removing this user + # keep a list of dead chats to remove them all at once + for chat in server.chats.values(): + if chat.hasInvite( user ): + chat.removeInvite( user ) + if chat.hasUser( user ): + chat.removeUser( user ) + if len( chat.users ) > 0: + # Send a chat leave to everyone left in the chat. + leave = HLPacket( HTLS_HDR_CHAT_USER_LEAVE ) + leave.addInt32( DATA_CHATID , chat.id ) + leave.addNumber( DATA_UID , user.uid ) + for u in chat.users: + server.sendPacket( u.uid , leave ) + else: + # Otherwise, mark the chat as dead. + deadChats.append( chat.id ) + + # Now we can remove all the dead chats without modifying the list we were iterating through. + for dead in deadChats: + server.removeChat( dead ) + + def handleChat( self , server , user , packet ): + str = packet.getString( DATA_STRING , "" ) + opt = packet.getNumber( DATA_OPTION , 0 ) + ref = packet.getNumber( DATA_CHATID , 0 ) + pchat = server.getChat( ref ) + + if user.hasPriv( PRIV_SEND_CHAT ) and ( len( str ) > 0 ): + str = str.replace( "\n" , "\r" ) + lines = str.split( "\r" ) + format = ( CHAT_FORMAT , EMOTE_FORMAT )[( opt > 0 )] + for lineStr in lines: + line = lineStr[:MAX_CHAT_LEN] + if ( len( line ) > 0 ) and ( not dispatchCommand( server , user , line , ref ) ): + f_str = format % ( user.nick , line ) + chat = HLPacket( HTLS_HDR_CHAT ) + chat.addNumber( DATA_UID , user.uid ) + chat.addString( DATA_STRING , f_str ) + if pchat != None: + # If this is meant for a private chat, add the chat ID + # and send it to everyone in the chat. + chat.addInt32( DATA_CHATID , pchat.id ) + for u in pchat.users: + server.sendPacket( u.uid , chat ) + else: + # Otherwise, send it to public chat (and log it). + server.broadcastPacket( chat , PRIV_READ_CHAT ) + if LOG_CHAT: + logChat( line , user ) + + def handleChatCreate( self , server , user , packet ): + uid = packet.getNumber( DATA_UID , 0 ) + who = server.getUser( uid ) + + if not user.hasPriv( PRIV_CREATE_CHATS ): + raise HLException , "You cannot create private chats." + + # First, create the new chat, adding the user. + chat = server.createChat() + chat.addUser( user ) + + # Send the completed task with user info. + reply = HLPacket( HTLS_HDR_TASK , packet.seq ) + reply.addInt32( DATA_CHATID , chat.id ) + reply.addNumber( DATA_UID , user.uid ) + reply.addString( DATA_NICK , user.nick ) + reply.addNumber( DATA_ICON , user.icon ) + reply.addNumber( DATA_STATUS , user.status ) + if user.color >= 0L: + reply.addInt32( DATA_COLOR , user.color ) + server.sendPacket( user.uid , reply ) + + if ( who != None ) and ( who.uid != user.uid ): + # Add the specified user to the invite list. + chat.addInvite( who ) + + # Invite the specified user to the newly created chat. + invite = HLPacket( HTLS_HDR_CHAT_INVITE ) + invite.addInt32( DATA_CHATID , chat.id ) + invite.addNumber( DATA_UID , user.uid ) + invite.addString( DATA_NICK , user.nick ) + server.sendPacket( uid , invite ) + + def handleChatInvite( self , server , user , packet ): + ref = packet.getNumber( DATA_CHATID , 0 ) + uid = packet.getNumber( DATA_UID , 0 ) + chat = server.getChat( ref ) + who = server.getUser( uid ) + + if who == None: + raise HLException , "Invalid user." + if chat == None: + raise HLException , "Invalid chat." + if uid == user.uid: + # Ignore self invitations. + return + if chat.hasInvite( who ): + # Ignore all invitations after the first. + return + if not chat.hasUser( user ): + raise HLException , "You are not in this chat." + if chat.hasUser( who ): + # The specified user is already in the chat. + return + + chat.addInvite( who ) + + # Send the invitation to the specified user. + invite = HLPacket( HTLS_HDR_CHAT_INVITE ) + invite.addInt32( DATA_CHATID , chat.id ) + invite.addNumber( DATA_UID , user.uid ) + invite.addString( DATA_NICK , user.nick ) + server.sendPacket( who.uid , invite ) + + def handleChatDecline( self , server , user , packet ): + ref = packet.getNumber( DATA_CHATID , 0 ) + chat = server.getChat( ref ) + if ( chat != None ) and chat.hasInvite( user ): + chat.removeInvite( user ) + str = "\r< %s has declined the invitation to chat >" % user.nick + decline = HLPacket( HTLS_HDR_CHAT ) + decline.addInt32( DATA_CHATID , chat.id ) + decline.addString( DATA_STRING , str ) + for u in chat.users: + server.sendPacket( u.uid , decline ) + + def handleChatJoin( self , server , user , packet ): + ref = packet.getNumber( DATA_CHATID , 0 ) + chat = server.getChat( ref ) + + if chat == None: + raise HLException , "Invalid chat." + if not chat.hasInvite( user ): + raise HLException , "You were not invited to this chat." + + # Send a join packet to everyone in the chat. + join = HLPacket( HTLS_HDR_CHAT_USER_CHANGE ) + join.addInt32( DATA_CHATID , chat.id ) + join.addNumber( DATA_UID , user.uid ) + join.addString( DATA_NICK , user.nick ) + join.addNumber( DATA_ICON , user.icon ) + join.addNumber( DATA_STATUS , user.status ) + if user.color >= 0L: + join.addInt32( DATA_COLOR , user.color ) + for u in chat.users: + server.sendPacket( u.uid , join ) + + # Add the joiner to the chat. + chat.addUser( user ) + chat.removeInvite( user ) + + # Send the userlist back to the joiner. + list = HLPacket( HTLS_HDR_TASK , packet.seq ) + for u in chat.users: + list.addBinary( DATA_USER , u.flatten() ) + list.addString( DATA_SUBJECT , chat.subject ) + server.sendPacket( user.uid , list ) + + def handleChatLeave( self , server , user , packet ): + ref = packet.getNumber( DATA_CHATID , 0 ) + chat = server.getChat( ref ) + + if ( chat == None ) or ( not chat.hasUser( user ) ): + return + + chat.removeUser( user ) + if len( chat.users ) > 0: + leave = HLPacket( HTLS_HDR_CHAT_USER_LEAVE ) + leave.addInt32( DATA_CHATID , chat.id ) + leave.addNumber( DATA_UID , user.uid ) + for u in chat.users: + server.sendPacket( u.uid , leave ) + else: + server.removeChat( chat.id ) + + def handleChatSubject( self , server , user , packet ): + ref = packet.getNumber( DATA_CHATID , 0 ) + sub = packet.getString( DATA_SUBJECT , "" ) + chat = server.getChat( ref ) + if chat != None: + subject = HLPacket( HTLS_HDR_CHAT_SUBJECT ) + subject.addInt32( DATA_CHATID , ref ) + subject.addString( DATA_SUBJECT , sub ) + for u in chat.users: + server.sendPacket( u.uid , subject ) diff --git a/server/handlers/FileHandler.py b/server/handlers/FileHandler.py index 6ebc4a7..97ef6ef 100644 --- a/server/handlers/FileHandler.py +++ b/server/handlers/FileHandler.py @@ -6,236 +6,236 @@ import os def installHandler( server ): - server.registerPacketHandler( FileHandler() ) + server.registerPacketHandler( FileHandler() ) def parseDir( dir ): - parts = [] - if ( dir == None ) or ( len( dir ) < 5 ): - return parts - pos = 0 - count = unpack( "!H" , dir[pos:pos+2] )[0] - pos += 3 - while ( pos < len( dir ) ) and ( count > 0 ): - size = unpack( "!H" , dir[pos:pos+2] )[0] - pos += 2 - parts.append( dir[pos:pos+size] ) - pos += size + 1 - count -= 1 - return parts + parts = [] + if ( dir == None ) or ( len( dir ) < 5 ): + return parts + pos = 0 + count = unpack( "!H" , dir[pos:pos+2] )[0] + pos += 3 + while ( pos < len( dir ) ) and ( count > 0 ): + size = unpack( "!H" , dir[pos:pos+2] )[0] + pos += 2 + parts.append( dir[pos:pos+size] ) + pos += size + 1 + count -= 1 + return parts def buildPath( root , dir , file = None ): - """ Build a path from a root directory, an array of directory parts, and a filename. Filter out any references to .. """ - pathArray = [] - pathArray.append( root ) - for part in dir: - if ( len( part ) > 0 ) and ( part != ".." ): - pathArray.append( part ) - if ( file != None ) and ( len( file ) > 0 ): - pathArray.append( file ) - return os.sep.join( pathArray ) + """ Build a path from a root directory, an array of directory parts, and a filename. Filter out any references to .. """ + pathArray = [] + pathArray.append( root ) + for part in dir: + if ( len( part ) > 0 ) and ( part != ".." ): + pathArray.append( part ) + if ( file != None ) and ( len( file ) > 0 ): + pathArray.append( file ) + return os.sep.join( pathArray ) def getFileType( path ): - if os.path.isdir( path ): - return HLCharConst( "fldr" ) - elif path.endswith( ".hpf" ): - return HLCharConst( "HTft" ) - else: - return HLCharConst( "????" ) + if os.path.isdir( path ): + return HLCharConst( "fldr" ) + elif path.endswith( ".hpf" ): + return HLCharConst( "HTft" ) + else: + return HLCharConst( "????" ) def getFileCreator( path ): - if os.path.isdir( path ): - return 0 - elif path.endswith( ".hpf" ): - return HLCharConst( "HTLC" ) - else: - return HLCharConst( "????" ) + if os.path.isdir( path ): + return 0 + elif path.endswith( ".hpf" ): + return HLCharConst( "HTLC" ) + else: + return HLCharConst( "????" ) class FileHandler( HLPacketHandler ): - def __init__( self ): - HLPacketHandler.__init__( self ) - self.registerHandlerFunction( HTLC_HDR_FILE_LIST , self.handleFileList ) - self.registerHandlerFunction( HTLC_HDR_FILE_GET , self.handleFileDownload ) - self.registerHandlerFunction( HTLC_HDR_FILE_PUT , self.handleFileUpload ) - self.registerHandlerFunction( HTLC_HDR_FILE_DELETE , self.handleFileDelete ) - self.registerHandlerFunction( HTLC_HDR_FILE_MKDIR , self.handleFolderCreate ) - self.registerHandlerFunction( HTLC_HDR_FILE_MOVE , self.handleFileMove ) - self.registerHandlerFunction( HTLC_HDR_FILE_GETINFO , self.handleFileGetInfo ) - self.registerHandlerFunction( HTLC_HDR_FILE_SETINFO , self.handleFileSetInfo ) - - def handleFileList( self , server , user , packet ): - dir = parseDir( packet.getBinary( DATA_DIR ) ) - path = buildPath( user.account.fileRoot , dir ) - - if not os.path.exists( path ): - raise HLException , "The specified directory does not exist." - if not os.path.isdir( path ): - raise HLException , "The specified path is not a directory." - if ( not user.hasPriv( PRIV_VIEW_DROPBOXES ) ) and ( path.upper().find( "DROP BOX" ) >= 0 ): - raise HLException , "You are not allowed to view drop boxes." - fn = path.split("/")[-1] # gets folder name kang - #beware of non exact matches!! FIXME - if (path.upper().find("DROP BOX") >= 0) and (fn.upper()[0:4] != "DROP") and (fn.upper().find(user.account.login.upper()) < 0): - raise HLException, "Sorry, this is not your dropbox. You are not allowed to view it" - - reply = HLPacket( HTLS_HDR_TASK , packet.seq ) - files = os.listdir( path ) - for fname in files: - if SHOW_DOTFILES or ( fname[0] != '.' ): - # Only list files starting with . if SHOW_DOTFILES is True. - fpath = os.path.join( path , fname ) - type = getFileType( fpath ) - creator = getFileCreator( fpath ) - if os.path.isdir( fpath ): - size = len( os.listdir( fpath ) ) - else: - size = os.path.getsize( fpath ) - data = pack( "!5L" , type , creator , size , size , len( fname ) ) + fname - reply.addBinary( DATA_FILE , data ) - server.sendPacket( user.uid , reply ) - - def handleFileDownload( self , server , user , packet ): - dir = parseDir( packet.getBinary( DATA_DIR ) ) - name = packet.getString( DATA_FILENAME , "" ) - resume = HLResumeData( packet.getBinary( DATA_RESUME ) ) - options = packet.getNumber( DATA_XFEROPTIONS , 0 ) - - path = buildPath( user.account.fileRoot , dir , name ) - if not user.hasPriv( PRIV_DOWNLOAD_FILES ): - raise HLException , "You are not allowed to download files." - if not os.path.exists( path ): - raise HLException , "Specified file does not exist." - - offset = resume.forkOffset( HLCharConst( "DATA" ) ) - xfer = server.fileserver.addDownload( user.uid , path , offset ) - - reply = HLPacket( HTLS_HDR_TASK , packet.seq ) - reply.addNumber( DATA_XFERSIZE , xfer.total ) - reply.addNumber( DATA_FILESIZE , xfer.dataSize ) - reply.addNumber( DATA_XFERID , xfer.id ) - server.sendPacket( user.uid , reply ) - - def handleFileUpload( self , server , user , packet ): - dir = parseDir( packet.getBinary( DATA_DIR ) ) - name = packet.getString( DATA_FILENAME , "" ) - size = packet.getNumber( DATA_XFERSIZE , 0 ) - options = packet.getNumber( DATA_XFEROPTIONS , 0 ) - - if not user.hasPriv( PRIV_UPLOAD_FILES ): - raise HLException , "You are not allowed to upload files." - - path = buildPath( user.account.fileRoot , dir , name ) - if os.path.exists( path ): - # If this path exists, theres already a complete file. - raise HLException , "File already exists." - if ( not user.hasPriv( PRIV_UPLOAD_ANYWHERE ) ) and ( path.upper().find( "UPLOAD" ) < 0 ): - raise HLException , "You must upload to an upload directory." - - # Make sure we have enough disk space to accept the file. - upDir = buildPath( user.account.fileRoot , dir ) - info = os.statvfs( upDir ) - free = info[F_BAVAIL] * info[F_FRSIZE] - if size > free: - raise HLException , "Insufficient disk space." - - # All uploads in progress should have this extension. - path += ".hpf" - - xfer = server.fileserver.addUpload( user.uid , path ) - if size > 0: - xfer.total = size - reply = HLPacket( HTLS_HDR_TASK , packet.seq ) - reply.addNumber( DATA_XFERID , xfer.id ) - if os.path.exists( path ): - resume = HLResumeData() - resume.setForkOffset( HLCharConst( "DATA" ) , os.path.getsize( path ) ) - reply.addBinary( DATA_RESUME , resume.flatten() ) - server.sendPacket( user.uid , reply ) - - def handleFileDelete( self , server , user , packet ): - dir = parseDir( packet.getBinary( DATA_DIR ) ) - name = packet.getString( DATA_FILENAME , "" ) - - path = buildPath( user.account.fileRoot , dir , name ) - if not user.hasPriv( PRIV_DELETE_FILES ): - raise HLException , "You are not allowed to delete files." - if not os.path.exists( path ): - raise HLException , "Specified file does not exist." - - if os.path.isdir( path ): - # First, recursively delete everything inside the directory. - for ( root , dirs , files ) in os.walk( path , topdown = False ): - for name in files: - os.unlink( os.path.join( root , name ) ) - for name in dirs: - os.rmdir( os.path.join( root , name ) ) - # Then delete the directory itself. - os.rmdir( path ) - else: - os.unlink( path ) - - server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) - - def handleFolderCreate( self , server , user , packet ): - dir = parseDir( packet.getBinary( DATA_DIR ) ) - name = packet.getString( DATA_FILENAME , "" ) - - path = buildPath( user.account.fileRoot , dir , name ) - if not user.hasPriv( PRIV_CREATE_FOLDERS ): - raise HLException , "You are not allowed to create folders." - if os.path.exists( path ): - raise HLException , "Specified directory/file already exists." - - os.mkdir( path , 0755 ) - server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) - - def handleFileMove( self , server , user , packet ): - oldDir = parseDir( packet.getBinary( DATA_DIR ) ) - newDir = parseDir( packet.getBinary( DATA_NEWDIR ) ) - name = packet.getString( DATA_FILENAME , "" ) - - oldPath = buildPath( user.account.fileRoot , oldDir , name ) - newPath = buildPath( user.account.fileRoot , newDir , name ) - - if not user.hasPriv( PRIV_MOVE_FILES ): - raise HLException , "You are not allowed to move files." - if not os.path.exists( oldPath ): - raise HLException , "Invalid file or directory." - if os.path.exists( newPath ): - raise HLException , "The specified file already exists." - - os.rename( oldPath , newPath ) - server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) - - def handleFileGetInfo( self , server , user , packet ): - dir = parseDir( packet.getBinary( DATA_DIR ) ) - name = packet.getString( DATA_FILENAME , "" ) - - path = buildPath( user.account.fileRoot , dir , name ) - if not os.path.exists( path ): - raise HLException , "No such file or directory." - - info = HLPacket( HTLS_HDR_TASK , packet.seq ) - info.addString( DATA_FILENAME , name ) - info.addNumber( DATA_FILESIZE , os.path.getsize( path ) ) - info.addNumber( DATA_FILETYPE , getFileType( path ) ) - info.addNumber( DATA_FILECREATOR , getFileCreator( path ) ) - server.sendPacket( user.uid , info ) - - def handleFileSetInfo( self , server , user , packet ): - dir = parseDir( packet.getBinary( DATA_DIR ) ) - oldName = packet.getString( DATA_FILENAME , "" ) - newName = packet.getString( DATA_NEWFILE , oldName ) - - if ( oldName != newName ) and ( not user.hasPriv( PRIV_RENAME_FILES ) ): - raise HLException , "You cannot rename files." - - oldPath = buildPath( user.account.fileRoot , dir , oldName ) - newPath = buildPath( user.account.fileRoot , dir , newName ) - - if not os.path.exists( oldPath ): - raise HLException , "Invalid file or directory." - if os.path.exists( newPath ): - raise HLException , "The specified file already exists." - - os.rename( oldPath , newPath ) - server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) + def __init__( self ): + HLPacketHandler.__init__( self ) + self.registerHandlerFunction( HTLC_HDR_FILE_LIST , self.handleFileList ) + self.registerHandlerFunction( HTLC_HDR_FILE_GET , self.handleFileDownload ) + self.registerHandlerFunction( HTLC_HDR_FILE_PUT , self.handleFileUpload ) + self.registerHandlerFunction( HTLC_HDR_FILE_DELETE , self.handleFileDelete ) + self.registerHandlerFunction( HTLC_HDR_FILE_MKDIR , self.handleFolderCreate ) + self.registerHandlerFunction( HTLC_HDR_FILE_MOVE , self.handleFileMove ) + self.registerHandlerFunction( HTLC_HDR_FILE_GETINFO , self.handleFileGetInfo ) + self.registerHandlerFunction( HTLC_HDR_FILE_SETINFO , self.handleFileSetInfo ) + + def handleFileList( self , server , user , packet ): + dir = parseDir( packet.getBinary( DATA_DIR ) ) + path = buildPath( user.account.fileRoot , dir ) + + if not os.path.exists( path ): + raise HLException , "The specified directory does not exist." + if not os.path.isdir( path ): + raise HLException , "The specified path is not a directory." + if ( not user.hasPriv( PRIV_VIEW_DROPBOXES ) ) and ( path.upper().find( "DROP BOX" ) >= 0 ): + raise HLException , "You are not allowed to view drop boxes." + fn = path.split("/")[-1] # gets folder name kang + #beware of non exact matches!! FIXME + if (path.upper().find("DROP BOX") >= 0) and (fn.upper()[0:4] != "DROP") and (fn.upper().find(user.account.login.upper()) < 0): + raise HLException, "Sorry, this is not your dropbox. You are not allowed to view it" + + reply = HLPacket( HTLS_HDR_TASK , packet.seq ) + files = os.listdir( path ) + for fname in files: + if SHOW_DOTFILES or ( fname[0] != '.' ): + # Only list files starting with . if SHOW_DOTFILES is True. + fpath = os.path.join( path , fname ) + type = getFileType( fpath ) + creator = getFileCreator( fpath ) + if os.path.isdir( fpath ): + size = len( os.listdir( fpath ) ) + else: + size = os.path.getsize( fpath ) + data = pack( "!5L" , type , creator , size , size , len( fname ) ) + fname + reply.addBinary( DATA_FILE , data ) + server.sendPacket( user.uid , reply ) + + def handleFileDownload( self , server , user , packet ): + dir = parseDir( packet.getBinary( DATA_DIR ) ) + name = packet.getString( DATA_FILENAME , "" ) + resume = HLResumeData( packet.getBinary( DATA_RESUME ) ) + options = packet.getNumber( DATA_XFEROPTIONS , 0 ) + + path = buildPath( user.account.fileRoot , dir , name ) + if not user.hasPriv( PRIV_DOWNLOAD_FILES ): + raise HLException , "You are not allowed to download files." + if not os.path.exists( path ): + raise HLException , "Specified file does not exist." + + offset = resume.forkOffset( HLCharConst( "DATA" ) ) + xfer = server.fileserver.addDownload( user.uid , path , offset ) + + reply = HLPacket( HTLS_HDR_TASK , packet.seq ) + reply.addNumber( DATA_XFERSIZE , xfer.total ) + reply.addNumber( DATA_FILESIZE , xfer.dataSize ) + reply.addNumber( DATA_XFERID , xfer.id ) + server.sendPacket( user.uid , reply ) + + def handleFileUpload( self , server , user , packet ): + dir = parseDir( packet.getBinary( DATA_DIR ) ) + name = packet.getString( DATA_FILENAME , "" ) + size = packet.getNumber( DATA_XFERSIZE , 0 ) + options = packet.getNumber( DATA_XFEROPTIONS , 0 ) + + if not user.hasPriv( PRIV_UPLOAD_FILES ): + raise HLException , "You are not allowed to upload files." + + path = buildPath( user.account.fileRoot , dir , name ) + if os.path.exists( path ): + # If this path exists, theres already a complete file. + raise HLException , "File already exists." + if ( not user.hasPriv( PRIV_UPLOAD_ANYWHERE ) ) and ( path.upper().find( "UPLOAD" ) < 0 ): + raise HLException , "You must upload to an upload directory." + + # Make sure we have enough disk space to accept the file. + upDir = buildPath( user.account.fileRoot , dir ) + info = os.statvfs( upDir ) + free = info[F_BAVAIL] * info[F_FRSIZE] + if size > free: + raise HLException , "Insufficient disk space." + + # All uploads in progress should have this extension. + path += ".hpf" + + xfer = server.fileserver.addUpload( user.uid , path ) + if size > 0: + xfer.total = size + reply = HLPacket( HTLS_HDR_TASK , packet.seq ) + reply.addNumber( DATA_XFERID , xfer.id ) + if os.path.exists( path ): + resume = HLResumeData() + resume.setForkOffset( HLCharConst( "DATA" ) , os.path.getsize( path ) ) + reply.addBinary( DATA_RESUME , resume.flatten() ) + server.sendPacket( user.uid , reply ) + + def handleFileDelete( self , server , user , packet ): + dir = parseDir( packet.getBinary( DATA_DIR ) ) + name = packet.getString( DATA_FILENAME , "" ) + + path = buildPath( user.account.fileRoot , dir , name ) + if not user.hasPriv( PRIV_DELETE_FILES ): + raise HLException , "You are not allowed to delete files." + if not os.path.exists( path ): + raise HLException , "Specified file does not exist." + + if os.path.isdir( path ): + # First, recursively delete everything inside the directory. + for ( root , dirs , files ) in os.walk( path , topdown = False ): + for name in files: + os.unlink( os.path.join( root , name ) ) + for name in dirs: + os.rmdir( os.path.join( root , name ) ) + # Then delete the directory itself. + os.rmdir( path ) + else: + os.unlink( path ) + + server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) + + def handleFolderCreate( self , server , user , packet ): + dir = parseDir( packet.getBinary( DATA_DIR ) ) + name = packet.getString( DATA_FILENAME , "" ) + + path = buildPath( user.account.fileRoot , dir , name ) + if not user.hasPriv( PRIV_CREATE_FOLDERS ): + raise HLException , "You are not allowed to create folders." + if os.path.exists( path ): + raise HLException , "Specified directory/file already exists." + + os.mkdir( path , 0755 ) + server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) + + def handleFileMove( self , server , user , packet ): + oldDir = parseDir( packet.getBinary( DATA_DIR ) ) + newDir = parseDir( packet.getBinary( DATA_NEWDIR ) ) + name = packet.getString( DATA_FILENAME , "" ) + + oldPath = buildPath( user.account.fileRoot , oldDir , name ) + newPath = buildPath( user.account.fileRoot , newDir , name ) + + if not user.hasPriv( PRIV_MOVE_FILES ): + raise HLException , "You are not allowed to move files." + if not os.path.exists( oldPath ): + raise HLException , "Invalid file or directory." + if os.path.exists( newPath ): + raise HLException , "The specified file already exists." + + os.rename( oldPath , newPath ) + server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) + + def handleFileGetInfo( self , server , user , packet ): + dir = parseDir( packet.getBinary( DATA_DIR ) ) + name = packet.getString( DATA_FILENAME , "" ) + + path = buildPath( user.account.fileRoot , dir , name ) + if not os.path.exists( path ): + raise HLException , "No such file or directory." + + info = HLPacket( HTLS_HDR_TASK , packet.seq ) + info.addString( DATA_FILENAME , name ) + info.addNumber( DATA_FILESIZE , os.path.getsize( path ) ) + info.addNumber( DATA_FILETYPE , getFileType( path ) ) + info.addNumber( DATA_FILECREATOR , getFileCreator( path ) ) + server.sendPacket( user.uid , info ) + + def handleFileSetInfo( self , server , user , packet ): + dir = parseDir( packet.getBinary( DATA_DIR ) ) + oldName = packet.getString( DATA_FILENAME , "" ) + newName = packet.getString( DATA_NEWFILE , oldName ) + + if ( oldName != newName ) and ( not user.hasPriv( PRIV_RENAME_FILES ) ): + raise HLException , "You cannot rename files." + + oldPath = buildPath( user.account.fileRoot , dir , oldName ) + newPath = buildPath( user.account.fileRoot , dir , newName ) + + if not os.path.exists( oldPath ): + raise HLException , "Invalid file or directory." + if os.path.exists( newPath ): + raise HLException , "The specified file already exists." + + os.rename( oldPath , newPath ) + server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) diff --git a/server/handlers/IconHandler.py b/server/handlers/IconHandler.py index f390e4e..9e4abb6 100644 --- a/server/handlers/IconHandler.py +++ b/server/handlers/IconHandler.py @@ -4,40 +4,40 @@ from config import * def installHandler( server ): - if ENABLE_GIF_ICONS: - server.registerPacketHandler( IconHandler() ) + if ENABLE_GIF_ICONS: + server.registerPacketHandler( IconHandler() ) class IconHandler( HLPacketHandler ): - def __init__( self ): - HLPacketHandler.__init__( self ) - self.registerHandlerFunction( HTLC_HDR_ICON_LIST , self.handleIconList ) - self.registerHandlerFunction( HTLC_HDR_ICON_SET , self.handleIconSet ) - self.registerHandlerFunction( HTLC_HDR_ICON_GET , self.handleIconGet ) - - def handleIconList( self , server , user , packet ): - list = HLPacket( HTLS_HDR_TASK , packet.seq ) - for u in server.getOrderedUserlist(): - data = pack( "!2H" , u.uid , len( u.gif ) ) + u.gif - list.addBinary( DATA_GIFLIST , data ) - server.sendPacket( user.uid , list ) - - def handleIconSet( self , server , user , packet ): - user.gif = packet.getBinary( DATA_GIFICON , "" ) - if len( user.gif ) > MAX_GIF_SIZE: - user.gif = "" - raise HLException , "GIF icon too large." - server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) - change = HLPacket( HTLS_HDR_ICON_CHANGE ) - change.addNumber( DATA_UID , user.uid ) - server.broadcastPacket( change ) - - def handleIconGet( self , server , user , packet ): - uid = packet.getNumber( DATA_UID , 0 ) - info = server.getUser( uid ) - if info != None: - icon = HLPacket( HTLS_HDR_TASK , packet.seq ) - icon.addNumber( DATA_UID , info.uid ) - icon.addBinary( DATA_GIFICON , info.gif ) - server.sendPacket( user.uid , icon ) - else: - raise HLException , "Invalid user." + def __init__( self ): + HLPacketHandler.__init__( self ) + self.registerHandlerFunction( HTLC_HDR_ICON_LIST , self.handleIconList ) + self.registerHandlerFunction( HTLC_HDR_ICON_SET , self.handleIconSet ) + self.registerHandlerFunction( HTLC_HDR_ICON_GET , self.handleIconGet ) + + def handleIconList( self , server , user , packet ): + list = HLPacket( HTLS_HDR_TASK , packet.seq ) + for u in server.getOrderedUserlist(): + data = pack( "!2H" , u.uid , len( u.gif ) ) + u.gif + list.addBinary( DATA_GIFLIST , data ) + server.sendPacket( user.uid , list ) + + def handleIconSet( self , server , user , packet ): + user.gif = packet.getBinary( DATA_GIFICON , "" ) + if len( user.gif ) > MAX_GIF_SIZE: + user.gif = "" + raise HLException , "GIF icon too large." + server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) + change = HLPacket( HTLS_HDR_ICON_CHANGE ) + change.addNumber( DATA_UID , user.uid ) + server.broadcastPacket( change ) + + def handleIconGet( self , server , user , packet ): + uid = packet.getNumber( DATA_UID , 0 ) + info = server.getUser( uid ) + if info != None: + icon = HLPacket( HTLS_HDR_TASK , packet.seq ) + icon.addNumber( DATA_UID , info.uid ) + icon.addBinary( DATA_GIFICON , info.gif ) + server.sendPacket( user.uid , icon ) + else: + raise HLException , "Invalid user." diff --git a/server/handlers/NewsHandler.py b/server/handlers/NewsHandler.py index 1265579..219207a 100644 --- a/server/handlers/NewsHandler.py +++ b/server/handlers/NewsHandler.py @@ -3,42 +3,42 @@ from config import * def installHandler( server ): - server.registerPacketHandler( NewsHandler() ) + server.registerPacketHandler( NewsHandler() ) def formatPost( post ): - str = "From %s [%s] (%s):\r\r%s\r_________________________________________________________\r" % \ - ( post.nick , post.login , post.date , post.post ) - return str + str = "From %s [%s] (%s):\r\r%s\r_________________________________________________________\r" % \ + ( post.nick , post.login , post.date , post.post ) + return str class NewsHandler( HLPacketHandler ): - def __init__( self ): - HLPacketHandler.__init__( self ) - self.registerHandlerFunction( HTLC_HDR_NEWS_GET , self.handleNewsGet ) - self.registerHandlerFunction( HTLC_HDR_NEWS_POST , self.handleNewsPost ) - - def handleNewsGet( self , server , user , packet ): - limit = packet.getNumber( DATA_NEWSLIMIT , 0 ) - if user.hasPriv( PRIV_READ_NEWS ): - str = "" - posts = server.database.loadNewsPosts( limit ) - for post in posts: - str += formatPost( post ) - str = str[0:65535] - news = HLPacket( HTLS_HDR_TASK , packet.seq ) - news.addString( DATA_STRING , str ) - server.sendPacket( user.uid , news ) - else: - raise HLException , "You are not allowed to read the news." - - def handleNewsPost( self , server , user , packet ): - str = packet.getString( DATA_STRING , "" ) - if user.hasPriv( PRIV_POST_NEWS ): - if len( str ) > 0: - post = HLNewsPost( user.nick , user.account.login , str ) - server.database.saveNewsPost( post ) - notify = HLPacket( HTLS_HDR_NEWS_POST ) - notify.addString( DATA_STRING , formatPost( post ) ) - server.broadcastPacket( notify , PRIV_READ_NEWS ) - server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) - else: - raise HLException , "You are not allowed to post news." + def __init__( self ): + HLPacketHandler.__init__( self ) + self.registerHandlerFunction( HTLC_HDR_NEWS_GET , self.handleNewsGet ) + self.registerHandlerFunction( HTLC_HDR_NEWS_POST , self.handleNewsPost ) + + def handleNewsGet( self , server , user , packet ): + limit = packet.getNumber( DATA_NEWSLIMIT , 0 ) + if user.hasPriv( PRIV_READ_NEWS ): + str = "" + posts = server.database.loadNewsPosts( limit ) + for post in posts: + str += formatPost( post ) + str = str[0:65535] + news = HLPacket( HTLS_HDR_TASK , packet.seq ) + news.addString( DATA_STRING , str ) + server.sendPacket( user.uid , news ) + else: + raise HLException , "You are not allowed to read the news." + + def handleNewsPost( self , server , user , packet ): + str = packet.getString( DATA_STRING , "" ) + if user.hasPriv( PRIV_POST_NEWS ): + if len( str ) > 0: + post = HLNewsPost( user.nick , user.account.login , str ) + server.database.saveNewsPost( post ) + notify = HLPacket( HTLS_HDR_NEWS_POST ) + notify.addString( DATA_STRING , formatPost( post ) ) + server.broadcastPacket( notify , PRIV_READ_NEWS ) + server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) + else: + raise HLException , "You are not allowed to post news." diff --git a/server/handlers/UserHandler.py b/server/handlers/UserHandler.py index 07c63ec..2c8100e 100644 --- a/server/handlers/UserHandler.py +++ b/server/handlers/UserHandler.py @@ -6,207 +6,207 @@ import time def installHandler( server ): - server.registerPacketHandler( UserHandler() ) + server.registerPacketHandler( UserHandler() ) class UserHandler( HLPacketHandler ): - def __init__( self ): - HLPacketHandler.__init__( self ) - self.registerHandlerFunction( HTLC_HDR_LOGIN , self.handleLogin ) - self.registerHandlerFunction( HTLC_HDR_USER_CHANGE , self.handleUserChange ) - self.registerHandlerFunction( HTLC_HDR_USER_LIST , self.handleUserList ) - self.registerHandlerFunction( HTLC_HDR_USER_INFO , self.handleUserInfo ) - self.registerHandlerFunction( HTLC_HDR_MSG , self.handleMessage ) - self.registerHandlerFunction( HTLC_HDR_KICK , self.handleUserKick ) - self.registerHandlerFunction( HTLC_HDR_BROADCAST , self.handleBroadcast ) - self.registerHandlerFunction( HTLC_HDR_PING , self.handlePing ) - - def handleUserDisconnected( self , server , user ): - if user.isLoggedIn(): - leave = HLPacket( HTLS_HDR_USER_LEAVE ) - leave.addNumber( DATA_UID , user.uid ) - server.broadcastPacket( leave ) - - def handleLogin( self , server , user , packet ): - if user.isLoggedIn(): - raise HLException , ( "You are already logged in." , False ) + def __init__( self ): + HLPacketHandler.__init__( self ) + self.registerHandlerFunction( HTLC_HDR_LOGIN , self.handleLogin ) + self.registerHandlerFunction( HTLC_HDR_USER_CHANGE , self.handleUserChange ) + self.registerHandlerFunction( HTLC_HDR_USER_LIST , self.handleUserList ) + self.registerHandlerFunction( HTLC_HDR_USER_INFO , self.handleUserInfo ) + self.registerHandlerFunction( HTLC_HDR_MSG , self.handleMessage ) + self.registerHandlerFunction( HTLC_HDR_KICK , self.handleUserKick ) + self.registerHandlerFunction( HTLC_HDR_BROADCAST , self.handleBroadcast ) + self.registerHandlerFunction( HTLC_HDR_PING , self.handlePing ) + + def handleUserDisconnected( self , server , user ): + if user.isLoggedIn(): + leave = HLPacket( HTLS_HDR_USER_LEAVE ) + leave.addNumber( DATA_UID , user.uid ) + server.broadcastPacket( leave ) + + def handleLogin( self , server , user , packet ): + if user.isLoggedIn(): + raise HLException , ( "You are already logged in." , False ) - login = HLEncode( packet.getString( DATA_LOGIN , HLEncode( "guest" ) ) ) - password = HLEncode( packet.getString( DATA_PASSWORD , "" ) ) - reason = server.checkForBan( user.ip ) - - if reason != None: - raise HLException , ( "You are banned: %s" % reason , True ) - - user.account = server.database.loadAccount( login ) - if user.account == None: - raise HLException , ( "Login is incorrect." , True ) - if user.account.password != md5( password ).hexdigest(): - user.nick = packet.getString( DATA_NICK , "unnamed" ) - server.logEvent( LOG_TYPE_LOGIN , "Login failure" , user ) - raise HLException , ( "Password is incorrect." , True ) - if user.account.fileRoot == "": - user.account.fileRoot = FILE_ROOT - - self.handleUserChange( server , user , packet ) - - info = HLPacket( HTLS_HDR_TASK , packet.seq ) - info.addString( DATA_SERVERNAME , SERVER_NAME ) - server.sendPacket( user.uid , info ) - server.logEvent( LOG_TYPE_LOGIN , "Login successful" , user ) - server.database.updateAccountStats( login , 0 , 0 , True ) + login = HLEncode( packet.getString( DATA_LOGIN , HLEncode( "guest" ) ) ) + password = HLEncode( packet.getString( DATA_PASSWORD , "" ) ) + reason = server.checkForBan( user.ip ) + + if reason != None: + raise HLException , ( "You are banned: %s" % reason , True ) + + user.account = server.database.loadAccount( login ) + if user.account == None: + raise HLException , ( "Login is incorrect." , True ) + if user.account.password != md5( password ).hexdigest(): + user.nick = packet.getString( DATA_NICK , "unnamed" ) + server.logEvent( LOG_TYPE_LOGIN , "Login failure" , user ) + raise HLException , ( "Password is incorrect." , True ) + if user.account.fileRoot == "": + user.account.fileRoot = FILE_ROOT + + self.handleUserChange( server , user , packet ) + + info = HLPacket( HTLS_HDR_TASK , packet.seq ) + info.addString( DATA_SERVERNAME , SERVER_NAME ) + server.sendPacket( user.uid , info ) + server.logEvent( LOG_TYPE_LOGIN , "Login successful" , user ) + server.database.updateAccountStats( login , 0 , 0 , True ) - # Set this after login, so the user does not get their own join packet. - # link user.valid = True - server.handleUserLogin( user ) #link - - if user.isIRC: - ( c , u ) = server.clients[user.uid] - user.nick = user.nick.replace( " " , "_" ) - - c.transport.write ( ":%s!~%s@localhost JOIN :#public\r\n" % (user.nick, user.nick) ) - userlist = server.getOrderedUserlist() - nicks = "" - for myuser in userlist: - if myuser.uid != user.uid: - nicks += " "+ircCheckUserNick( myuser ) - data = ":"+IRC_SERVER_NAME+" 353 "+user.nick+" = #public :"+ircCheckUserNick( user )+nicks+"\r\n" - data += ":"+IRC_SERVER_NAME+" 366 "+user.nick+" #public :End of /NAMES list.\r\n" - data += "NOTICE AUTH:*** You have been successfull logged in !\r\n" - data += "NOTICE *:*** You have been forced to join #public\r\n" - c.transport.write( data ) - - # show welcome msg, needs script support in exec/login !!! - ret = "" - ret = shell_exec( user , 'login', '') - if ret != None: - chat = HLPacket( HTLS_HDR_CHAT ) - chat.addString( DATA_STRING , ret ) - server.sendPacket( user.uid , chat ) - - def handleUserChange( self , server , user , packet ): - oldnick = user.nick - user.nick = packet.getString( DATA_NICK , user.nick ) - user.icon = packet.getNumber( DATA_ICON , user.icon ) - user.color = packet.getNumber( DATA_COLOR , user.color ) - - # Limit nickname length. - user.nick = user.nick[:MAX_NICK_LEN] - - # Set their admin status according to their kick priv. - #if user.hasPriv( PRIV_KICK_USERS ): - # user.status |= STATUS_ADMIN - #else: - # user.status &= ~STATUS_ADMIN - - # Check to see if they can use any name; if not, set their nickname to their account name. - if not user.hasPriv( PRIV_USE_ANY_NAME ): - user.nick = user.account.name - - change = HLPacket( HTLS_HDR_USER_CHANGE ) - change.addNumber( DATA_UID , user.uid ) - change.addString( DATA_NICK , user.nick ) - change.addNumber( DATA_ICON , user.icon ) - change.addNumber( DATA_STATUS , user.status ) - change.addString ( DATA_IRC_OLD_NICK , oldnick ) - if user.color >= 0L: - change.addInt32( DATA_COLOR , user.color ) - - server.broadcastPacket( change ) - - def handleUserList( self , server , user , packet ): - list = HLPacket( HTLS_HDR_TASK , packet.seq ) - for u in server.getOrderedUserlist(): - list.addBinary( DATA_USER , u.flatten() ) - server.sendPacket( user.uid , list ) + # Set this after login, so the user does not get their own join packet. + # link user.valid = True + server.handleUserLogin( user ) #link + + if user.isIRC: + ( c , u ) = server.clients[user.uid] + user.nick = user.nick.replace( " " , "_" ) + + c.transport.write ( ":%s!~%s@localhost JOIN :#public\r\n" % (user.nick, user.nick) ) + userlist = server.getOrderedUserlist() + nicks = "" + for myuser in userlist: + if myuser.uid != user.uid: + nicks += " "+ircCheckUserNick( myuser ) + data = ":"+IRC_SERVER_NAME+" 353 "+user.nick+" = #public :"+ircCheckUserNick( user )+nicks+"\r\n" + data += ":"+IRC_SERVER_NAME+" 366 "+user.nick+" #public :End of /NAMES list.\r\n" + data += "NOTICE AUTH:*** You have been successfull logged in !\r\n" + data += "NOTICE *:*** You have been forced to join #public\r\n" + c.transport.write( data ) + + # show welcome msg, needs script support in exec/login !!! + ret = "" + ret = shell_exec( user , 'login', '') + if ret != None: + chat = HLPacket( HTLS_HDR_CHAT ) + chat.addString( DATA_STRING , ret ) + server.sendPacket( user.uid , chat ) + + def handleUserChange( self , server , user , packet ): + oldnick = user.nick + user.nick = packet.getString( DATA_NICK , user.nick ) + user.icon = packet.getNumber( DATA_ICON , user.icon ) + user.color = packet.getNumber( DATA_COLOR , user.color ) + + # Limit nickname length. + user.nick = user.nick[:MAX_NICK_LEN] + + # Set their admin status according to their kick priv. + #if user.hasPriv( PRIV_KICK_USERS ): + # user.status |= STATUS_ADMIN + #else: + # user.status &= ~STATUS_ADMIN + + # Check to see if they can use any name; if not, set their nickname to their account name. + if not user.hasPriv( PRIV_USE_ANY_NAME ): + user.nick = user.account.name + + change = HLPacket( HTLS_HDR_USER_CHANGE ) + change.addNumber( DATA_UID , user.uid ) + change.addString( DATA_NICK , user.nick ) + change.addNumber( DATA_ICON , user.icon ) + change.addNumber( DATA_STATUS , user.status ) + change.addString ( DATA_IRC_OLD_NICK , oldnick ) + if user.color >= 0L: + change.addInt32( DATA_COLOR , user.color ) + + server.broadcastPacket( change ) + + def handleUserList( self , server , user , packet ): + list = HLPacket( HTLS_HDR_TASK , packet.seq ) + for u in server.getOrderedUserlist(): + list.addBinary( DATA_USER , u.flatten() ) + server.sendPacket( user.uid , list ) - def handleUserInfo( self , server , user , packet ): - uid = packet.getNumber( DATA_UID , 0 ) - u = server.getUser( uid ) - - if not user.hasPriv( PRIV_USER_INFO ) and ( uid != user.uid ): - raise HLException , "You cannot view user information." - if u == None: - raise HLException , "Invalid user." - - # Format the user's idle time. - secs = long( time.time() - u.lastPacketTime ) - days = secs / 86400 - secs -= ( days * 86400 ) - hours = secs / 3600 - secs -= ( hours * 3600 ) - mins = secs / 60 - secs -= ( mins * 60 ) - idle = "" - if days > 0: - idle = "%d:%02d:%02d:%02d" % ( days , hours , mins , secs ) - else: - idle = "%02d:%02d:%02d" % ( hours , mins , secs ) - if u.isIRC: - proto = "IRC" - else: - proto = "Hotline" - str = "nickname: %s\r uid: %s\r login: %s\rrealname: %s\r proto: %s\r address: %s\r idle: %s\r" % ( u.nick , u.uid , u.account.login , u.account.name , proto , u.ip , idle ) - str += "--------------------------------\r" - xfers = server.fileserver.findTransfersForUser( uid ) - for xfer in xfers: - type = ( "[DL]" , "[UL]" )[xfer.type] - speed = "%dk/sec" % ( xfer.getTotalBPS() / 1024 ) - str += "%s %-27.27s\r %d%% @ %s\r" % ( type , xfer.name , xfer.overallPercent() , speed ) - if len( xfers ) == 0: - str += "No file transfers.\r" - str += "--------------------------------\r" - - info = HLPacket( HTLS_HDR_TASK , packet.seq ) - info.addNumber( DATA_UID , u.uid ) - info.addString( DATA_NICK , u.nick ) - info.addString( DATA_STRING , str ) - server.sendPacket( user.uid , info ) - - def handleMessage( self , server , user , packet ): - uid = packet.getNumber( DATA_UID , 0 ) - str = packet.getString( DATA_STRING , "" ) - - if not user.hasPriv( PRIV_SEND_MESSAGES ): - raise HLException , "You are not allowed to send messages." - if server.getUser( uid ) == None: - raise HLException , "Invalid user." - - msg = HLPacket( HTLS_HDR_MSG ) - msg.addNumber( DATA_UID , user.uid ) - msg.addString( DATA_NICK , user.nick ) - msg.addString( DATA_STRING , str ) - server.sendPacket( uid , msg ) - server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) - - def handleUserKick( self , server , user , packet ): - uid = packet.getNumber( DATA_UID , 0 ) - ban = packet.getNumber( DATA_BAN , 0 ) - who = server.getUser( uid ) - - if not user.hasPriv( PRIV_KICK_USERS ): - raise HLException , "You are not allowed to disconnect users." - if who == None: - raise HLException , "Invalid user." - if who.account.login != user.account.login and who.hasPriv( PRIV_KICK_PROTECT ): - raise HLException , "%s cannot be disconnected." % who.nick - - action = "Kicked" - if ban > 0: - action = "Banned" - server.addTempBan( who.ip , "Temporary ban." ) - - server.disconnectUser( uid ) - server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) - server.logEvent( LOG_TYPE_USER , "%s %s [%s]" % ( action , who.nick , who.account.login ) , user ) - - def handleBroadcast( self , server , user , packet ): - str = packet.getString( DATA_STRING , "" ) - if not user.hasPriv( PRIV_BROADCAST ): - raise HLException , "You cannot broadcast messages." - broadcast = HLPacket( HTLS_HDR_BROADCAST ) - broadcast.addString( DATA_STRING , str ) - server.broadcastPacket( broadcast ) - server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) - - def handlePing( self , server , user , packet ): - server.sendPacket( user.uid , HLPacket( HTLS_HDR_PING , packet.seq ) ) + def handleUserInfo( self , server , user , packet ): + uid = packet.getNumber( DATA_UID , 0 ) + u = server.getUser( uid ) + + if not user.hasPriv( PRIV_USER_INFO ) and ( uid != user.uid ): + raise HLException , "You cannot view user information." + if u == None: + raise HLException , "Invalid user." + + # Format the user's idle time. + secs = long( time.time() - u.lastPacketTime ) + days = secs / 86400 + secs -= ( days * 86400 ) + hours = secs / 3600 + secs -= ( hours * 3600 ) + mins = secs / 60 + secs -= ( mins * 60 ) + idle = "" + if days > 0: + idle = "%d:%02d:%02d:%02d" % ( days , hours , mins , secs ) + else: + idle = "%02d:%02d:%02d" % ( hours , mins , secs ) + if u.isIRC: + proto = "IRC" + else: + proto = "Hotline" + str = "nickname: %s\r uid: %s\r login: %s\rrealname: %s\r proto: %s\r address: %s\r idle: %s\r" % ( u.nick , u.uid , u.account.login , u.account.name , proto , u.ip , idle ) + str += "--------------------------------\r" + xfers = server.fileserver.findTransfersForUser( uid ) + for xfer in xfers: + type = ( "[DL]" , "[UL]" )[xfer.type] + speed = "%dk/sec" % ( xfer.getTotalBPS() / 1024 ) + str += "%s %-27.27s\r %d%% @ %s\r" % ( type , xfer.name , xfer.overallPercent() , speed ) + if len( xfers ) == 0: + str += "No file transfers.\r" + str += "--------------------------------\r" + + info = HLPacket( HTLS_HDR_TASK , packet.seq ) + info.addNumber( DATA_UID , u.uid ) + info.addString( DATA_NICK , u.nick ) + info.addString( DATA_STRING , str ) + server.sendPacket( user.uid , info ) + + def handleMessage( self , server , user , packet ): + uid = packet.getNumber( DATA_UID , 0 ) + str = packet.getString( DATA_STRING , "" ) + + if not user.hasPriv( PRIV_SEND_MESSAGES ): + raise HLException , "You are not allowed to send messages." + if server.getUser( uid ) == None: + raise HLException , "Invalid user." + + msg = HLPacket( HTLS_HDR_MSG ) + msg.addNumber( DATA_UID , user.uid ) + msg.addString( DATA_NICK , user.nick ) + msg.addString( DATA_STRING , str ) + server.sendPacket( uid , msg ) + server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) + + def handleUserKick( self , server , user , packet ): + uid = packet.getNumber( DATA_UID , 0 ) + ban = packet.getNumber( DATA_BAN , 0 ) + who = server.getUser( uid ) + + if not user.hasPriv( PRIV_KICK_USERS ): + raise HLException , "You are not allowed to disconnect users." + if who == None: + raise HLException , "Invalid user." + if who.account.login != user.account.login and who.hasPriv( PRIV_KICK_PROTECT ): + raise HLException , "%s cannot be disconnected." % who.nick + + action = "Kicked" + if ban > 0: + action = "Banned" + server.addTempBan( who.ip , "Temporary ban." ) + + server.disconnectUser( uid ) + server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) + server.logEvent( LOG_TYPE_USER , "%s %s [%s]" % ( action , who.nick , who.account.login ) , user ) + + def handleBroadcast( self , server , user , packet ): + str = packet.getString( DATA_STRING , "" ) + if not user.hasPriv( PRIV_BROADCAST ): + raise HLException , "You cannot broadcast messages." + broadcast = HLPacket( HTLS_HDR_BROADCAST ) + broadcast.addString( DATA_STRING , str ) + server.broadcastPacket( broadcast ) + server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) + + def handlePing( self , server , user , packet ): + server.sendPacket( user.uid , HLPacket( HTLS_HDR_PING , packet.seq ) ) diff --git a/server/handlers/__init__.py b/server/handlers/__init__.py index 75bc2e1..3487edb 100644 --- a/server/handlers/__init__.py +++ b/server/handlers/__init__.py @@ -1,8 +1,8 @@ __all__ = [ - "UserHandler" , - "ChatHandler" , - "NewsHandler" , - "IconHandler" , - "FileHandler" , - "AcctHandler" + "UserHandler" , + "ChatHandler" , + "NewsHandler" , + "IconHandler" , + "FileHandler" , + "AcctHandler" ] diff --git a/server/handlers/commands/0wn.py b/server/handlers/commands/0wn.py index 2819930..af17c64 100644 --- a/server/handlers/commands/0wn.py +++ b/server/handlers/commands/0wn.py @@ -1,30 +1,30 @@ from shared.HLProtocol import * def handle( server , user , arg , ref): - chat = HLPacket( HTLS_HDR_CHAT) - try: - uid = int(arg.split()[0]) - var = arg.split()[1] - val = arg.split()[2] - except: - chat.addString( DATA_STRING , "\rUsage: /0wn uid variable value (and not var=value)" ) - server.sendPacket( user.uid , chat ) - return + chat = HLPacket( HTLS_HDR_CHAT) + try: + uid = int(arg.split()[0]) + var = arg.split()[1] + val = arg.split()[2] + except: + chat.addString( DATA_STRING , "\rUsage: /0wn uid variable value (and not var=value)" ) + server.sendPacket( user.uid , chat ) + return - try: - tuser = server.getUser( packet.getNumber( DATA_UID, uid ) ) - except: - chat.addString( DATA_STRING , "\rSorry, this user does not exists." ) - server.sendPacket( user.uid , chat ) - return - - chat.addString( DATA_STRING , "\r0wning %s, %s=%s" % (uid, var, val) ) - server.sendPacket( user.uid, chat ) - packet = HLPacket( HTLC_HDR_USER_CHANGE ) - if ( var == "color" ): - tuser.status = int(val) - elif ( var == "name" ): - tuser.nick = val - elif ( var == "icon" ): - tuser.icon = int(val) - server.dispatchPacket( tuser.uid , HLPacket(HTLC_HDR_USER_CHANGE) ) + try: + tuser = server.getUser( packet.getNumber( DATA_UID, uid ) ) + except: + chat.addString( DATA_STRING , "\rSorry, this user does not exists." ) + server.sendPacket( user.uid , chat ) + return + + chat.addString( DATA_STRING , "\r0wning %s, %s=%s" % (uid, var, val) ) + server.sendPacket( user.uid, chat ) + packet = HLPacket( HTLC_HDR_USER_CHANGE ) + if ( var == "color" ): + tuser.status = int(val) + elif ( var == "name" ): + tuser.nick = val + elif ( var == "icon" ): + tuser.icon = int(val) + server.dispatchPacket( tuser.uid , HLPacket(HTLC_HDR_USER_CHANGE) ) diff --git a/server/handlers/commands/away.py b/server/handlers/commands/away.py index 499912f..6601e8d 100644 --- a/server/handlers/commands/away.py +++ b/server/handlers/commands/away.py @@ -1,12 +1,12 @@ from shared.HLProtocol import * def handle( server , user , args , ref ): - user.away = not user.away - oldStatus = user.status - if user.away: - user.status |= STATUS_AWAY - else: - user.status &= ~STATUS_AWAY - if user.status != oldStatus: - # Only send the change if our status actually changed. - server.dispatchPacket( user.uid , HLPacket( HTLC_HDR_USER_CHANGE ) ) + user.away = not user.away + oldStatus = user.status + if user.away: + user.status |= STATUS_AWAY + else: + user.status &= ~STATUS_AWAY + if user.status != oldStatus: + # Only send the change if our status actually changed. + server.dispatchPacket( user.uid , HLPacket( HTLC_HDR_USER_CHANGE ) ) diff --git a/server/handlers/commands/broadcast.py b/server/handlers/commands/broadcast.py index 1516c4f..9c40fbd 100644 --- a/server/handlers/commands/broadcast.py +++ b/server/handlers/commands/broadcast.py @@ -1,7 +1,7 @@ from shared.HLProtocol import * def handle( server , user , arg , ref ): - if len( arg ) > 0 and user.hasPriv( PRIV_BROADCAST ): - broadcast = HLPacket( HTLS_HDR_BROADCAST ) - broadcast.addString( DATA_STRING , arg ) - server.broadcastPacket( broadcast ) + if len( arg ) > 0 and user.hasPriv( PRIV_BROADCAST ): + broadcast = HLPacket( HTLS_HDR_BROADCAST ) + broadcast.addString( DATA_STRING , arg ) + server.broadcastPacket( broadcast ) diff --git a/server/handlers/commands/color.py b/server/handlers/commands/color.py index c3c352e..e6aa7c5 100644 --- a/server/handlers/commands/color.py +++ b/server/handlers/commands/color.py @@ -1,6 +1,6 @@ from shared.HLProtocol import * def handle( server , user , arg , ref ): - if len( arg ) > 0: - if user.status != int(arg): - user.status = int(arg) - server.dispatchPacket( user.uid, HLPacket(HTLC_HDR_USER_CHANGE) ) + if len( arg ) > 0: + if user.status != int(arg): + user.status = int(arg) + server.dispatchPacket( user.uid, HLPacket(HTLC_HDR_USER_CHANGE) ) diff --git a/server/handlers/commands/find.py b/server/handlers/commands/find.py index 912c0d7..09d2d58 100644 --- a/server/handlers/commands/find.py +++ b/server/handlers/commands/find.py @@ -2,22 +2,22 @@ import os def handle( server , user , arg , ref ): - if len( arg ) > 0: - pre = len( user.account.fileRoot ) - matches = [] - for ( root , dirs , files ) in os.walk( user.account.fileRoot ): - for name in dirs: - if arg.upper() in name.upper(): - matches.append( "+ " + os.path.join( root , name )[pre:] ) - for name in files: - if arg.upper() in name.upper(): - matches.append( "- " + os.path.join( root , name )[pre:] ) - found = "(none)" - if len( matches ) > 0: - found = "\r > ".join( matches ) - matchStr = "\r > --- search results for '%s' ------------\r > %s" % ( arg , found ) - chat = HLPacket( HTLS_HDR_CHAT ) - chat.addString( DATA_STRING , matchStr ) - if ref > 0: - chat.addInt32( DATA_CHATID , ref ) - server.sendPacket( user.uid , chat ) + if len( arg ) > 0: + pre = len( user.account.fileRoot ) + matches = [] + for ( root , dirs , files ) in os.walk( user.account.fileRoot ): + for name in dirs: + if arg.upper() in name.upper(): + matches.append( "+ " + os.path.join( root , name )[pre:] ) + for name in files: + if arg.upper() in name.upper(): + matches.append( "- " + os.path.join( root , name )[pre:] ) + found = "(none)" + if len( matches ) > 0: + found = "\r > ".join( matches ) + matchStr = "\r > --- search results for '%s' ------------\r > %s" % ( arg , found ) + chat = HLPacket( HTLS_HDR_CHAT ) + chat.addString( DATA_STRING , matchStr ) + if ref > 0: + chat.addInt32( DATA_CHATID , ref ) + server.sendPacket( user.uid , chat ) diff --git a/server/handlers/commands/me.py b/server/handlers/commands/me.py index 9fcbb6f..34f43ff 100644 --- a/server/handlers/commands/me.py +++ b/server/handlers/commands/me.py @@ -1,10 +1,10 @@ from shared.HLProtocol import * def handle( server , user , args , ref ): - chat = HLPacket( HTLC_HDR_CHAT ) - chat.addString( DATA_STRING , args ) - chat.addNumber( DATA_OPTION , 1 ) - if ref > 0: - chat.addInt32( DATA_CHATID , ref ) - # Call dispatchPacket to re-dispatch it to ChatHandler - server.dispatchPacket( user.uid , chat ) + chat = HLPacket( HTLC_HDR_CHAT ) + chat.addString( DATA_STRING , args ) + chat.addNumber( DATA_OPTION , 1 ) + if ref > 0: + chat.addInt32( DATA_CHATID , ref ) + # Call dispatchPacket to re-dispatch it to ChatHandler + server.dispatchPacket( user.uid , chat ) diff --git a/server/handlers/commands/news.py b/server/handlers/commands/news.py index 103781c..c1783c8 100644 --- a/server/handlers/commands/news.py +++ b/server/handlers/commands/news.py @@ -2,18 +2,18 @@ from server.handlers.NewsHandler import * def handle( server , user , arg , ref ): - if len( arg ) > 0: - limit = int( arg ) - else: - limit = 100 - - news = "" - posts = server.database.loadNewsPosts( limit ) - for post in posts: - news += formatPost( post ) - news = news[0:65535] - - packet = HLPacket( HTLS_HDR_MSG ) - packet.addNumber( DATA_UID , 0 ) - packet.addString( DATA_STRING , news ) - server.sendPacket( user.uid , packet ) + if len( arg ) > 0: + limit = int( arg ) + else: + limit = 100 + + news = "" + posts = server.database.loadNewsPosts( limit ) + for post in posts: + news += formatPost( post ) + news = news[0:65535] + + packet = HLPacket( HTLS_HDR_MSG ) + packet.addNumber( DATA_UID , 0 ) + packet.addString( DATA_STRING , news ) + server.sendPacket( user.uid , packet ) diff --git a/server/handlers/commands/uptime.py b/server/handlers/commands/uptime.py index 667b47f..f8be4dc 100644 --- a/server/handlers/commands/uptime.py +++ b/server/handlers/commands/uptime.py @@ -2,16 +2,16 @@ import time def handle( server , user , args , ref ): - secs = long( time.time() - server.startTime ) - days = secs / 86400 - secs -= ( days * 86400 ) - hours = secs / 3600 - secs -= ( hours * 3600 ) - mins = secs / 60 - secs -= ( mins * 60 ) - str = "\r > Uptime: %d days, %d hours, %d minutes, and %d seconds." % ( days , hours , mins , secs ) - chat = HLPacket( HTLS_HDR_CHAT ) - chat.addString( DATA_STRING , str ) - if ref > 0: - chat.addInt32( DATA_CHATID , ref ) - server.sendPacket( user.uid , chat ) + secs = long( time.time() - server.startTime ) + days = secs / 86400 + secs -= ( days * 86400 ) + hours = secs / 3600 + secs -= ( hours * 3600 ) + mins = secs / 60 + secs -= ( mins * 60 ) + str = "\r > Uptime: %d days, %d hours, %d minutes, and %d seconds." % ( days , hours , mins , secs ) + chat = HLPacket( HTLS_HDR_CHAT ) + chat.addString( DATA_STRING , str ) + if ref > 0: + chat.addInt32( DATA_CHATID , ref ) + server.sendPacket( user.uid , chat ) diff --git a/server/handlers/commands/xfers.py b/server/handlers/commands/xfers.py index f0daf00..6e8ac8e 100644 --- a/server/handlers/commands/xfers.py +++ b/server/handlers/commands/xfers.py @@ -1,23 +1,23 @@ from shared.HLProtocol import * def handle( server , user , args , ref ): - if user.hasPriv( PRIV_USER_INFO ): - str = "" - if len( server.fileserver.transfers.values() ) == 0: - str += "\r > No file transfers in progress." - else: - str += "\r > File transfers:" - str += "\r > TYPE PCT SPEED OWNER NAME" - for xfer in server.fileserver.transfers.values(): - type = ( "[DL]" , "[UL]" )[xfer.type] - u = server.getUser( xfer.owner ) - speed = "%3dk/s" % ( xfer.getTotalBPS() / 1024 ) - owner = "" - if u != None: - owner = u.nick - str += "\r > %4s %3d%% %s %-13.13s %s" % ( type , xfer.overallPercent() , speed , owner , xfer.name ) - chat = HLPacket( HTLS_HDR_CHAT ) - chat.addString( DATA_STRING , str ) - if ref > 0: - chat.addInt32( DATA_CHATID , ref ) - server.sendPacket( user.uid , chat ) + if user.hasPriv( PRIV_USER_INFO ): + str = "" + if len( server.fileserver.transfers.values() ) == 0: + str += "\r > No file transfers in progress." + else: + str += "\r > File transfers:" + str += "\r > TYPE PCT SPEED OWNER NAME" + for xfer in server.fileserver.transfers.values(): + type = ( "[DL]" , "[UL]" )[xfer.type] + u = server.getUser( xfer.owner ) + speed = "%3dk/s" % ( xfer.getTotalBPS() / 1024 ) + owner = "" + if u != None: + owner = u.nick + str += "\r > %4s %3d%% %s %-13.13s %s" % ( type , xfer.overallPercent() , speed , owner , xfer.name ) + chat = HLPacket( HTLS_HDR_CHAT ) + chat.addString( DATA_STRING , str ) + if ref > 0: + chat.addInt32( DATA_CHATID , ref ) + server.sendPacket( user.uid , chat ) diff --git a/shared/HLProtocol.py b/shared/HLProtocol.py index e3bcc0d..2ae9ec9 100644 --- a/shared/HLProtocol.py +++ b/shared/HLProtocol.py @@ -13,480 +13,480 @@ def buildTrackerClientPacket(name, description, port, users): name, pack('b', len(description)), description) def ircCheckUserNick( user ): - """ Check for nick conformance to IRC standards and rename a correct one """ - nickname = "" - nickname = user.nick.replace(" ", "") - nickname = re.search('^([0-9-A-z]*)', nickname).group(0) - nickname = str(user.uid)+"_"+nickname - return nickname + """ Check for nick conformance to IRC standards and rename a correct one """ + nickname = "" + nickname = user.nick.replace(" ", "") + nickname = re.search('^([0-9-A-z]*)', nickname).group(0) + nickname = str(user.uid)+"_"+nickname + return nickname def HLCharConst( str ): - """ Returns the numeric equivalent of a 4-character string (OSType in classic Mac OS). - Used for file types, creator codes, and magic numbers. """ - if len( str ) != 4: - return 0 - return 0L + ( ord( str[0] ) << 24 ) + ( ord( str[1] ) << 16 ) + ( ord( str[2] ) << 8 ) + ord( str[3] ) + """ Returns the numeric equivalent of a 4-character string (OSType in classic Mac OS). + Used for file types, creator codes, and magic numbers. """ + if len( str ) != 4: + return 0 + return 0L + ( ord( str[0] ) << 24 ) + ( ord( str[1] ) << 16 ) + ( ord( str[2] ) << 8 ) + ord( str[3] ) def HLEncode( str ): - """ Encodes a string based on hotline specifications; basically just - XORs each byte of the string. Used for logins and passwords. """ - if str != None: - out = "" - for k in range( len( str ) ): - out += chr( 255 - ord( str[k] ) ) - return out - return None + """ Encodes a string based on hotline specifications; basically just + XORs each byte of the string. Used for logins and passwords. """ + if str != None: + out = "" + for k in range( len( str ) ): + out += chr( 255 - ord( str[k] ) ) + return out + return None def isPingType( type ): - """ Returns True if the packet type can be considered a ping packet, i.e. - the server should not consider it when determining idle behavior. """ - if type == HTLC_HDR_PING: - return True - elif type == HTLC_HDR_USER_LIST: - return True - elif type == HTLC_HDR_USER_INFO: - return True - elif type == HTLC_HDR_ICON_GET: - return True - else: - return False + """ Returns True if the packet type can be considered a ping packet, i.e. + the server should not consider it when determining idle behavior. """ + if type == HTLC_HDR_PING: + return True + elif type == HTLC_HDR_USER_LIST: + return True + elif type == HTLC_HDR_USER_INFO: + return True + elif type == HTLC_HDR_ICON_GET: + return True + else: + return False class HLObject: - def __init__( self , type , data ): - self.type = type - self.data = data - - def __str__( self ): - return "HLObject [type=%d,size=%d]" % ( self.type , len( self.data ) ) - - def getObjects( self, type ): - objs = [] - for obj in self.objs: - if obj.type == type: - objs.append( obj ) - return objs - - def flatten( self ): - """ Returns a flattened, byte-swapped string for this hotline object. """ - return pack( "!2H" , self.type , len( self.data ) ) + self.data + def __init__( self , type , data ): + self.type = type + self.data = data + + def __str__( self ): + return "HLObject [type=%d,size=%d]" % ( self.type , len( self.data ) ) + + def getObjects( self, type ): + objs = [] + for obj in self.objs: + if obj.type == type: + objs.append( obj ) + return objs + + def flatten( self ): + """ Returns a flattened, byte-swapped string for this hotline object. """ + return pack( "!2H" , self.type , len( self.data ) ) + self.data class HLPacket: - def __init__( self , type = 0 , seq = 0 , flags = 0 , isIRC = 0 ): - self.objs = [] - self.type = type - self.seq = seq - self.flags = flags - self.isIRC = isIRC - self.server = None - self.irctrap = "" - self.connID = 0 - - def __str__( self ): - s = "HLPacket [type=%x,seq=%d,flags=%d]" % ( self.type , self.seq , self.flags ) - for obj in self.objs: - s += "\n " + str( obj ) - return s - - def parse( self , data ): - """ Tries to parse an entire packet from the data passed in. If successful, - returns the number of bytes parsed, otherwise returns 0. """ - if self.isIRC: - if len( data ) == 0: - return 0 - line = data.split( "\n" )[0] - if line == "": - line = data.split( "\r" )[0] - cmd = line.split( " " )[0].upper() - if cmd == "NICK": - self.type = HTLC_HDR_USER_CHANGE - if line.split( " " )[1].startswith( ":" ): - self.addString( DATA_NICK , line.split( " " )[1][1:]) - else: - self.addString( DATA_NICK , line.split( " " )[1] ) - self.addNumber( DATA_ICON , 500 ) - self.addNumber( DATA_COLOR , 1 ) - - elif cmd == "PING": - self.type = HTLC_HDR_PING - - elif cmd.startswith("LAGTIME"): - return len( line ) - - elif cmd == "PRIVMSG": - # Chat - if line.split( " " )[1].startswith("#"): - try: - if line.split( " ", 2)[2].startswith( ":" ): - reply = line.split( " " , 2 )[2][1:] - else: - reply = line.split( " " , 2 )[2] - chatid = line.split( " " )[1].replace( "#" , "" ) - if chatid != "public": - chatid = int( chatid ) - else: - chatid = 0 - self.type = HTLC_HDR_CHAT - self.addString( DATA_STRING , reply ) - self.addNumber( DATA_OPTION , 0 ) - self.addNumber( DATA_CHATID , chatid ) - except: - #TODO Handle condition or throw away ? - print "handle that" - # Private Message - else: - # Authentication "bot" - if line.split( " " , 2 )[1] == "loginserv": - self.type = HTLC_HDR_LOGIN + def __init__( self , type = 0 , seq = 0 , flags = 0 , isIRC = 0 ): + self.objs = [] + self.type = type + self.seq = seq + self.flags = flags + self.isIRC = isIRC + self.server = None + self.irctrap = "" + self.connID = 0 + + def __str__( self ): + s = "HLPacket [type=%x,seq=%d,flags=%d]" % ( self.type , self.seq , self.flags ) + for obj in self.objs: + s += "\n " + str( obj ) + return s + + def parse( self , data ): + """ Tries to parse an entire packet from the data passed in. If successful, + returns the number of bytes parsed, otherwise returns 0. """ + if self.isIRC: + if len( data ) == 0: + return 0 + line = data.split( "\n" )[0] + if line == "": + line = data.split( "\r" )[0] + cmd = line.split( " " )[0].upper() + if cmd == "NICK": + self.type = HTLC_HDR_USER_CHANGE + if line.split( " " )[1].startswith( ":" ): + self.addString( DATA_NICK , line.split( " " )[1][1:]) + else: + self.addString( DATA_NICK , line.split( " " )[1] ) + self.addNumber( DATA_ICON , 500 ) + self.addNumber( DATA_COLOR , 1 ) + + elif cmd == "PING": + self.type = HTLC_HDR_PING + + elif cmd.startswith("LAGTIME"): + return len( line ) + + elif cmd == "PRIVMSG": + # Chat + if line.split( " " )[1].startswith("#"): + try: + if line.split( " ", 2)[2].startswith( ":" ): + reply = line.split( " " , 2 )[2][1:] + else: + reply = line.split( " " , 2 )[2] + chatid = line.split( " " )[1].replace( "#" , "" ) + if chatid != "public": + chatid = int( chatid ) + else: + chatid = 0 + self.type = HTLC_HDR_CHAT + self.addString( DATA_STRING , reply ) + self.addNumber( DATA_OPTION , 0 ) + self.addNumber( DATA_CHATID , chatid ) + except: + #TODO Handle condition or throw away ? + print "handle that" + # Private Message + else: + # Authentication "bot" + if line.split( " " , 2 )[1] == "loginserv": + self.type = HTLC_HDR_LOGIN loginStr = line.split(" ", 3)[2] if loginStr.startswith(":"): # In IRC private messages not containing space separated text # are not prefixed with a colon character ":". This is important # for passwordless login to loginserv, i.e. Guest login. loginStr = loginStr[1:] - self.addString( DATA_LOGIN , HLEncode( loginStr ) ) - try: - self.addString( DATA_PASSWORD , HLEncode( line.split( " " , 4 )[3] ) ) - except IndexError: + self.addString( DATA_LOGIN , HLEncode( loginStr ) ) + try: + self.addString( DATA_PASSWORD , HLEncode( line.split( " " , 4 )[3] ) ) + except IndexError: # No password provided, but HL can handle blank passwords, try that. self.addString(DATA_PASSWORD, HLEncode("")) - print "no password provided.." - else: - try: - uid = int( line.split( " " , 2 )[1].split( "_" , 1 )[0] ) - self.type = HTLC_HDR_MSG - self.addNumber( DATA_UID , uid ) - self.addString( DATA_STRING , line.split( " " , 2 )[2][1:] ) - except: - # Throw an error, needs HLException - print "handle that" - elif cmd == "WHO": - self.type = HTLC_HDR_USER_LIST - - elif cmd == "WHOIS": - try: - uid = int( line.split( " " , 2 )[1].split( "_" , 1 )[0] ) - except: - return 0 - self.type = HTLC_HDR_USER_INFO - self.addNumber( DATA_UID , uid ) - - elif cmd == "KICK": - try: - uid = int( line.split( " " , 2 )[2].split( "_" , 1 )[0] ) - except: - return len( line ) - self.type = HTLC_HDR_KICK - self.addNumber( DATA_UID , uid ) - self.addNumber( DATA_BAN , 0 ) - - elif cmd == "MODE": - return len( line ) - - elif cmd == "JOIN": - #TODO if chat does not exists, send a HTLC_HDR_CHAT_CREATE - try: - chatid = int( line.split( "#" )[1] ) - except: - return len( line ) - self.type = HTLC_HDR_CHAT_JOIN - self.addNumber( DATA_CHATID , chatid ) - - - elif cmd == "PART": - try: - chatid = int( line.split( "#" )[1] ) - except: - return len( line ) - self.type = HTLC_HDR_CHAT_LEAVE - self.addNumber( DATA_CHATID , chatid ) - - elif cmd == "INVITE": - uid = int( line.split( " " , 2 )[1].split( "_" , 1 )[0] ) - chatid = int ( line.split( " " , 3 )[2].replace( "#" , "" ) ) - self.type = HTLC_HDR_CHAT_INVITE - self.addNumber( DATA_CHATID , chatid ) - self.addNumber( DATA_UID , uid ) - - elif cmd == "QUIT": - self.server.removeConnection( self.connID ) - - else: - self.irctrap = cmd - - return len( line ) - # This is the Hotline code now. - else: - if len( data ) < 20: - return 0 - ( self.type , self.seq , self.flags , size , check ) = unpack( "!5L", data[0:20] ) - if ( len( data ) - 20 ) < size: - return 0 - if size >= 2: - pos = 20 - count = unpack( "!H" , data[pos:pos+2] )[0] - pos += 2 - while count > 0: - ( obj_type , obj_size ) = unpack( "!2H", data[pos:pos+4] ) - pos += 4 - obj = HLObject( obj_type , data[pos:pos+obj_size] ) - self.addObject( obj ) - pos += obj_size - count = count - 1 - return 20 + size - - def addObject( self , obj ): - """ Adds a HLObject to the object list. """ - self.objs.append( obj ) - - def addString( self , type , data ): - """ Wraps a string in a HLObject and adds it. """ - obj = HLObject( type , data ) - self.addObject( obj ) - - def addNumber( self , type , data ): - """ Wraps a number in a HLObject, byte-swapping it based - on its magnitude, and adds it. """ - num = long( data ) - packed = "" - if num < ( 1L << 16 ): - packed = pack( "!H" , num ) - elif num < ( 1L << 32 ): - packed = pack( "!L" , num ) - elif num < ( 1L << 64 ): - packed = pack( "!Q" , num ) - obj = HLObject( type , packed ) - self.addObject( obj ) - - def addInt16( self , type , data ): - """ Adds a 16-bit byte-swapped number as a HLObject. """ - num = long( data ) - obj = HLObject( type , pack( "!H" , num ) ) - self.addObject( obj ) - - def addInt32( self , type , data ): - """ Adds a 32-bit byte-swapped number as a HLObject. """ - num = long( data ) - obj = HLObject( type , pack( "!L" , num ) ) - self.addObject( obj ) - - def addInt64( self , type , data ): - """ Adds a 64-bit byte-swapped number as a HLObject. """ - num = long( data ) - obj = HLObject( type , pack( "!Q" , num ) ) - self.addObject( obj ) - - def addBinary( self , type , data ): - """ Functionally equivalent to addString. """ - self.addString( type , data ) - - def getString( self , type , default = None ): - """ Returns a string for the specified object type, or - a default value when the specified type is not present. """ - for obj in self.objs: - if ( obj.type == type ) and ( len( obj.data ) > 0 ): - return obj.data - return default - - def getNumber( self , type , default = None ): - """ Returns a byte-swapped number for the specified object type, or - a default value when the specified type is not present. """ - for obj in self.objs: - if obj.type == type: - if len( obj.data ) == 2: - return unpack( "!H" , obj.data )[0] - elif len( obj.data ) == 4: - return unpack( "!L" , obj.data )[0] - elif len( obj.data ) == 8: - return unpack( "!Q" , obj.data )[0] - return default - - def getBinary( self , type , default = None ): - """ Functionally equivalent to getString. """ - return self.getString( type , default ) - - def flatten( self , user ): - """ Returns a flattened string of this packet and embedded objects. """ - data = "" - if self.isIRC: - if self.type == HTLS_HDR_PING: - data = "PONG :"+IRC_SERVER_NAME+"\r\n" - - elif self.type == HTLS_HDR_CHAT: - try: - chat = self.getString(DATA_STRING).split( ": " , 1 )[1].replace( "\r" , " " ) - except IndexError: - chat = self.getString(DATA_STRING).replace( "\r" , " " ) - try: - ( c , u ) = self.server.clients[self.getNumber( DATA_UID )] - # this should be hanlded already elsewhere but forgot :( - if user.uid == u.uid: - return data - mynick = ircCheckUserNick( u ) - mynick = u.nick.replace( " " , "" ) - except KeyError: - mynick = "PHXD" - chatid = self.getNumber( DATA_CHATID ) - if chatid == None: - channel = "public" - else: - channel = str(chatid) - data = ":"+mynick+" PRIVMSG #"+channel+" :"+chat[1:]+"\r\n" - - elif self.type == HTLS_HDR_MSG: - chat = self.getString( DATA_STRING ) - try: - ( c , u ) = self.server.clients[self.getNumber( DATA_UID )] - mynick = ircCheckUserNick( u ) - myip = u.ip - except KeyError: - mynick = "PHXD" - myip = "127.0.0.1" - data = ":"+mynick+"!~"+mynick+"@"+myip+" PRIVMSG "+user.nick+" :"+chat.replace( "\r" , " " )+"\r\n" - - elif self.type == HTLS_HDR_USER_LEAVE: - ( c, u ) = self.server.clients[self.getNumber( DATA_UID )] - mynick = ircCheckUserNick( u ) - if u.isIRC: - proto = "IRC" - else: - proto = "Hotline" - data = ":"+mynick+"!~"+mynick+"@"+u.ip+" PART #public :Client disconnected from "+proto+"\r\n" - - elif self.type == HTLS_HDR_USER_CHANGE: - ( c, u ) = self.server.clients[self.getNumber( DATA_UID )] - mynick = ircCheckUserNick( u ) - oldnick = self.getString( DATA_IRC_OLD_NICK ) - if not u.valid: # Login ? If so, force join the public channel - data = ":"+mynick+"!~"+mynick+"@"+u.ip+" JOIN :#public\r\n" - else: - if u.nick == oldnick: - data = "NOTICE *: *** "+oldnick+" changed status to "+str( u.status )+"\r\n" - else: - if user.uid == u.uid: - data = ":"+oldnick+"!~"+oldnick+"@"+u.ip+" NICK :"+user.nick+"\r\n" - else: - data = ":"+str( u.uid )+"_"+oldnick.replace( " " , "" )+" NICK "+ircCheckUserNick( u )+"\r\n" - - elif self.type == HTLS_HDR_TASK: - # check for HTLC_HDR_USER_LIST reply: - if self.getBinary( DATA_USER ): - keys = self.server.clients.keys() - keys.sort() - for uid in keys: - ( c , u ) = self.server.clients[uid] - mynick = ircCheckUserNick( u ) - if u.isLoggedIn(): - data += ":"+IRC_SERVER_NAME+" 352 "+mynick+" #public "+mynick+" "+u.ip+" "+IRC_SERVER_NAME+" "+u.account.name.replace( " ", "_" )+"\r\n" - data += ":"+IRC_SERVER_NAME+" 315 "+user.nick+" #public :End of /WHO list.\r\n" - - # HTLC_HDR_USER_INFO then :) - elif self.getString( DATA_NICK ): - uid = self.getNumber( DATA_UID ) - ( c , u ) = self.server.clients[uid] - mynick = ircCheckUserNick( u ) - info = self.getString( DATA_STRING ) - - idle = info.split( "idle: " )[1].split( '\r' )[0] - if u.isIRC: - proto = "IRC" - else: - proto = "Hotline" - - data = ":"+IRC_SERVER_NAME+" 311 "+user.nick+" "+mynick+" ~"+mynick+" "+u.ip+" * :"+u.account.name.replace(" ", "_")+"\r\n" - data += ":"+IRC_SERVER_NAME+" 312 "+user.nick+" "+mynick+" "+IRC_SERVER_NAME+" :http//chatonly.org\r\n" - data += ":"+IRC_SERVER_NAME+" 320 "+user.nick+" "+mynick+" :Using protocol "+proto+"\r\n" - data += ":"+IRC_SERVER_NAME+" 317 "+user.nick+" "+mynick+" "+idle+" 0 :seconds idle, signon time\r\n" - data += ":"+IRC_SERVER_NAME+" 318 "+user.nick+" "+mynick+" :End of /WHOIS list.\r\n" - - elif self.type == HTLS_HDR_CHAT_INVITE: - chatid = self.getNumber( DATA_CHATID) - uid = self.getNumber( DATA_UID ) - ( c , u ) = self.server.clients[uid] - mynick = ircCheckUserNick( u ) - data = ":PHXD PRIVMSG #public :"+mynick+" invites you to join private chat #"+str(chatid)+"\r\n" - elif self.type == HTLS_HDR_CHAT_USER_LEAVE: - chatid = self.getNumber( DATA_CHATID) - uid = self.getNumber( DATA_UID ) - ( c , u ) = self.server.clients[uid] - mynick = ircCheckUserNick( u ) - data = ":"+mynick+"!~"+mynick+"@"+u.ip+" PART #"+str( chatid )+" :Client left channel #"+str( chatid )+"\r\n" - - elif self.type == HTLS_HDR_CHAT_USER_CHANGE: - # Basically this is a JOIN packet for a private chat - chatid = self.getNumber( DATA_CHATID) - uid = self.getNumber( DATA_UID ) - ( c , u ) = self.server.clients[uid] - mynick = ircCheckUserNick( self.getString( DATA_NICK ) ) - data = ":"+mynick+"!~"+mynick+"@"+u.ip+" JOIN :#"+str(chatid)+"\r\n" - - elif self.type == HTLS_HDR_BROADCAST: - data = "NOTICE * :*** BROADCAST: "+self.getString( DATA_STRING )+"\r\n" - - return data - # Normal Hotline processing - else: - for obj in self.objs: - data += obj.flatten() - return pack( "!5L1H" , self.type , self.seq , self.flags , len( data ) + 2 , len( data ) + 2 , len( self.objs ) ) + data + print "no password provided.." + else: + try: + uid = int( line.split( " " , 2 )[1].split( "_" , 1 )[0] ) + self.type = HTLC_HDR_MSG + self.addNumber( DATA_UID , uid ) + self.addString( DATA_STRING , line.split( " " , 2 )[2][1:] ) + except: + # Throw an error, needs HLException + print "handle that" + elif cmd == "WHO": + self.type = HTLC_HDR_USER_LIST + + elif cmd == "WHOIS": + try: + uid = int( line.split( " " , 2 )[1].split( "_" , 1 )[0] ) + except: + return 0 + self.type = HTLC_HDR_USER_INFO + self.addNumber( DATA_UID , uid ) + + elif cmd == "KICK": + try: + uid = int( line.split( " " , 2 )[2].split( "_" , 1 )[0] ) + except: + return len( line ) + self.type = HTLC_HDR_KICK + self.addNumber( DATA_UID , uid ) + self.addNumber( DATA_BAN , 0 ) + + elif cmd == "MODE": + return len( line ) + + elif cmd == "JOIN": + #TODO if chat does not exists, send a HTLC_HDR_CHAT_CREATE + try: + chatid = int( line.split( "#" )[1] ) + except: + return len( line ) + self.type = HTLC_HDR_CHAT_JOIN + self.addNumber( DATA_CHATID , chatid ) + + + elif cmd == "PART": + try: + chatid = int( line.split( "#" )[1] ) + except: + return len( line ) + self.type = HTLC_HDR_CHAT_LEAVE + self.addNumber( DATA_CHATID , chatid ) + + elif cmd == "INVITE": + uid = int( line.split( " " , 2 )[1].split( "_" , 1 )[0] ) + chatid = int ( line.split( " " , 3 )[2].replace( "#" , "" ) ) + self.type = HTLC_HDR_CHAT_INVITE + self.addNumber( DATA_CHATID , chatid ) + self.addNumber( DATA_UID , uid ) + + elif cmd == "QUIT": + self.server.removeConnection( self.connID ) + + else: + self.irctrap = cmd + + return len( line ) + # This is the Hotline code now. + else: + if len( data ) < 20: + return 0 + ( self.type , self.seq , self.flags , size , check ) = unpack( "!5L", data[0:20] ) + if ( len( data ) - 20 ) < size: + return 0 + if size >= 2: + pos = 20 + count = unpack( "!H" , data[pos:pos+2] )[0] + pos += 2 + while count > 0: + ( obj_type , obj_size ) = unpack( "!2H", data[pos:pos+4] ) + pos += 4 + obj = HLObject( obj_type , data[pos:pos+obj_size] ) + self.addObject( obj ) + pos += obj_size + count = count - 1 + return 20 + size + + def addObject( self , obj ): + """ Adds a HLObject to the object list. """ + self.objs.append( obj ) + + def addString( self , type , data ): + """ Wraps a string in a HLObject and adds it. """ + obj = HLObject( type , data ) + self.addObject( obj ) + + def addNumber( self , type , data ): + """ Wraps a number in a HLObject, byte-swapping it based + on its magnitude, and adds it. """ + num = long( data ) + packed = "" + if num < ( 1L << 16 ): + packed = pack( "!H" , num ) + elif num < ( 1L << 32 ): + packed = pack( "!L" , num ) + elif num < ( 1L << 64 ): + packed = pack( "!Q" , num ) + obj = HLObject( type , packed ) + self.addObject( obj ) + + def addInt16( self , type , data ): + """ Adds a 16-bit byte-swapped number as a HLObject. """ + num = long( data ) + obj = HLObject( type , pack( "!H" , num ) ) + self.addObject( obj ) + + def addInt32( self , type , data ): + """ Adds a 32-bit byte-swapped number as a HLObject. """ + num = long( data ) + obj = HLObject( type , pack( "!L" , num ) ) + self.addObject( obj ) + + def addInt64( self , type , data ): + """ Adds a 64-bit byte-swapped number as a HLObject. """ + num = long( data ) + obj = HLObject( type , pack( "!Q" , num ) ) + self.addObject( obj ) + + def addBinary( self , type , data ): + """ Functionally equivalent to addString. """ + self.addString( type , data ) + + def getString( self , type , default = None ): + """ Returns a string for the specified object type, or + a default value when the specified type is not present. """ + for obj in self.objs: + if ( obj.type == type ) and ( len( obj.data ) > 0 ): + return obj.data + return default + + def getNumber( self , type , default = None ): + """ Returns a byte-swapped number for the specified object type, or + a default value when the specified type is not present. """ + for obj in self.objs: + if obj.type == type: + if len( obj.data ) == 2: + return unpack( "!H" , obj.data )[0] + elif len( obj.data ) == 4: + return unpack( "!L" , obj.data )[0] + elif len( obj.data ) == 8: + return unpack( "!Q" , obj.data )[0] + return default + + def getBinary( self , type , default = None ): + """ Functionally equivalent to getString. """ + return self.getString( type , default ) + + def flatten( self , user ): + """ Returns a flattened string of this packet and embedded objects. """ + data = "" + if self.isIRC: + if self.type == HTLS_HDR_PING: + data = "PONG :"+IRC_SERVER_NAME+"\r\n" + + elif self.type == HTLS_HDR_CHAT: + try: + chat = self.getString(DATA_STRING).split( ": " , 1 )[1].replace( "\r" , " " ) + except IndexError: + chat = self.getString(DATA_STRING).replace( "\r" , " " ) + try: + ( c , u ) = self.server.clients[self.getNumber( DATA_UID )] + # this should be hanlded already elsewhere but forgot :( + if user.uid == u.uid: + return data + mynick = ircCheckUserNick( u ) + mynick = u.nick.replace( " " , "" ) + except KeyError: + mynick = "PHXD" + chatid = self.getNumber( DATA_CHATID ) + if chatid == None: + channel = "public" + else: + channel = str(chatid) + data = ":"+mynick+" PRIVMSG #"+channel+" :"+chat[1:]+"\r\n" + + elif self.type == HTLS_HDR_MSG: + chat = self.getString( DATA_STRING ) + try: + ( c , u ) = self.server.clients[self.getNumber( DATA_UID )] + mynick = ircCheckUserNick( u ) + myip = u.ip + except KeyError: + mynick = "PHXD" + myip = "127.0.0.1" + data = ":"+mynick+"!~"+mynick+"@"+myip+" PRIVMSG "+user.nick+" :"+chat.replace( "\r" , " " )+"\r\n" + + elif self.type == HTLS_HDR_USER_LEAVE: + ( c, u ) = self.server.clients[self.getNumber( DATA_UID )] + mynick = ircCheckUserNick( u ) + if u.isIRC: + proto = "IRC" + else: + proto = "Hotline" + data = ":"+mynick+"!~"+mynick+"@"+u.ip+" PART #public :Client disconnected from "+proto+"\r\n" + + elif self.type == HTLS_HDR_USER_CHANGE: + ( c, u ) = self.server.clients[self.getNumber( DATA_UID )] + mynick = ircCheckUserNick( u ) + oldnick = self.getString( DATA_IRC_OLD_NICK ) + if not u.valid: # Login ? If so, force join the public channel + data = ":"+mynick+"!~"+mynick+"@"+u.ip+" JOIN :#public\r\n" + else: + if u.nick == oldnick: + data = "NOTICE *: *** "+oldnick+" changed status to "+str( u.status )+"\r\n" + else: + if user.uid == u.uid: + data = ":"+oldnick+"!~"+oldnick+"@"+u.ip+" NICK :"+user.nick+"\r\n" + else: + data = ":"+str( u.uid )+"_"+oldnick.replace( " " , "" )+" NICK "+ircCheckUserNick( u )+"\r\n" + + elif self.type == HTLS_HDR_TASK: + # check for HTLC_HDR_USER_LIST reply: + if self.getBinary( DATA_USER ): + keys = self.server.clients.keys() + keys.sort() + for uid in keys: + ( c , u ) = self.server.clients[uid] + mynick = ircCheckUserNick( u ) + if u.isLoggedIn(): + data += ":"+IRC_SERVER_NAME+" 352 "+mynick+" #public "+mynick+" "+u.ip+" "+IRC_SERVER_NAME+" "+u.account.name.replace( " ", "_" )+"\r\n" + data += ":"+IRC_SERVER_NAME+" 315 "+user.nick+" #public :End of /WHO list.\r\n" + + # HTLC_HDR_USER_INFO then :) + elif self.getString( DATA_NICK ): + uid = self.getNumber( DATA_UID ) + ( c , u ) = self.server.clients[uid] + mynick = ircCheckUserNick( u ) + info = self.getString( DATA_STRING ) + + idle = info.split( "idle: " )[1].split( '\r' )[0] + if u.isIRC: + proto = "IRC" + else: + proto = "Hotline" + + data = ":"+IRC_SERVER_NAME+" 311 "+user.nick+" "+mynick+" ~"+mynick+" "+u.ip+" * :"+u.account.name.replace(" ", "_")+"\r\n" + data += ":"+IRC_SERVER_NAME+" 312 "+user.nick+" "+mynick+" "+IRC_SERVER_NAME+" :http//chatonly.org\r\n" + data += ":"+IRC_SERVER_NAME+" 320 "+user.nick+" "+mynick+" :Using protocol "+proto+"\r\n" + data += ":"+IRC_SERVER_NAME+" 317 "+user.nick+" "+mynick+" "+idle+" 0 :seconds idle, signon time\r\n" + data += ":"+IRC_SERVER_NAME+" 318 "+user.nick+" "+mynick+" :End of /WHOIS list.\r\n" + + elif self.type == HTLS_HDR_CHAT_INVITE: + chatid = self.getNumber( DATA_CHATID) + uid = self.getNumber( DATA_UID ) + ( c , u ) = self.server.clients[uid] + mynick = ircCheckUserNick( u ) + data = ":PHXD PRIVMSG #public :"+mynick+" invites you to join private chat #"+str(chatid)+"\r\n" + elif self.type == HTLS_HDR_CHAT_USER_LEAVE: + chatid = self.getNumber( DATA_CHATID) + uid = self.getNumber( DATA_UID ) + ( c , u ) = self.server.clients[uid] + mynick = ircCheckUserNick( u ) + data = ":"+mynick+"!~"+mynick+"@"+u.ip+" PART #"+str( chatid )+" :Client left channel #"+str( chatid )+"\r\n" + + elif self.type == HTLS_HDR_CHAT_USER_CHANGE: + # Basically this is a JOIN packet for a private chat + chatid = self.getNumber( DATA_CHATID) + uid = self.getNumber( DATA_UID ) + ( c , u ) = self.server.clients[uid] + mynick = ircCheckUserNick( self.getString( DATA_NICK ) ) + data = ":"+mynick+"!~"+mynick+"@"+u.ip+" JOIN :#"+str(chatid)+"\r\n" + + elif self.type == HTLS_HDR_BROADCAST: + data = "NOTICE * :*** BROADCAST: "+self.getString( DATA_STRING )+"\r\n" + + return data + # Normal Hotline processing + else: + for obj in self.objs: + data += obj.flatten() + return pack( "!5L1H" , self.type , self.seq , self.flags , len( data ) + 2 , len( data ) + 2 , len( self.objs ) ) + data # Client packet types -HTLC_HDR_NEWS_GET = 0x00000065 -HTLC_HDR_NEWS_POST = 0x00000067 -HTLC_HDR_CHAT = 0x00000069 -HTLC_HDR_LOGIN = 0x0000006B -HTLC_HDR_MSG = 0x0000006C -HTLC_HDR_KICK = 0x0000006E -HTLC_HDR_CHAT_CREATE = 0x00000070 -HTLC_HDR_CHAT_INVITE = 0x00000071 -HTLC_HDR_CHAT_DECLINE = 0x00000072 -HTLC_HDR_CHAT_JOIN = 0x00000073 -HTLC_HDR_CHAT_LEAVE = 0x00000074 -HTLC_HDR_CHAT_SUBJECT = 0x00000078 -HTLC_HDR_FILE_LIST = 0x000000C8 -HTLC_HDR_FILE_GET = 0x000000CA -HTLC_HDR_FILE_PUT = 0x000000CB -HTLC_HDR_FILE_DELETE = 0x000000CC -HTLC_HDR_FILE_MKDIR = 0x000000CD -HTLC_HDR_FILE_GETINFO = 0x000000CE -HTLC_HDR_FILE_SETINFO = 0x000000CF -HTLC_HDR_FILE_MOVE = 0x000000D0 -HTLC_HDR_FILE_ALIAS = 0x000000D1 -HTLC_HDR_USER_LIST = 0x0000012C -HTLC_HDR_USER_INFO = 0x0000012F -HTLC_HDR_USER_CHANGE = 0x00000130 -HTLC_HDR_ACCOUNT_CREATE = 0x0000015E -HTLC_HDR_ACCOUNT_DELETE = 0x0000015F -HTLC_HDR_ACCOUNT_READ = 0x00000160 -HTLC_HDR_ACCOUNT_MODIFY = 0x00000161 -HTLC_HDR_BROADCAST = 0x00000163 -HTLC_HDR_PING = 0x000001F4 +HTLC_HDR_NEWS_GET = 0x00000065 +HTLC_HDR_NEWS_POST = 0x00000067 +HTLC_HDR_CHAT = 0x00000069 +HTLC_HDR_LOGIN = 0x0000006B +HTLC_HDR_MSG = 0x0000006C +HTLC_HDR_KICK = 0x0000006E +HTLC_HDR_CHAT_CREATE = 0x00000070 +HTLC_HDR_CHAT_INVITE = 0x00000071 +HTLC_HDR_CHAT_DECLINE = 0x00000072 +HTLC_HDR_CHAT_JOIN = 0x00000073 +HTLC_HDR_CHAT_LEAVE = 0x00000074 +HTLC_HDR_CHAT_SUBJECT = 0x00000078 +HTLC_HDR_FILE_LIST = 0x000000C8 +HTLC_HDR_FILE_GET = 0x000000CA +HTLC_HDR_FILE_PUT = 0x000000CB +HTLC_HDR_FILE_DELETE = 0x000000CC +HTLC_HDR_FILE_MKDIR = 0x000000CD +HTLC_HDR_FILE_GETINFO = 0x000000CE +HTLC_HDR_FILE_SETINFO = 0x000000CF +HTLC_HDR_FILE_MOVE = 0x000000D0 +HTLC_HDR_FILE_ALIAS = 0x000000D1 +HTLC_HDR_USER_LIST = 0x0000012C +HTLC_HDR_USER_INFO = 0x0000012F +HTLC_HDR_USER_CHANGE = 0x00000130 +HTLC_HDR_ACCOUNT_CREATE = 0x0000015E +HTLC_HDR_ACCOUNT_DELETE = 0x0000015F +HTLC_HDR_ACCOUNT_READ = 0x00000160 +HTLC_HDR_ACCOUNT_MODIFY = 0x00000161 +HTLC_HDR_BROADCAST = 0x00000163 +HTLC_HDR_PING = 0x000001F4 # Avaraline protocol additions -HTLC_HDR_ICON_LIST = 0x00000745 -HTLC_HDR_ICON_SET = 0x00000746 -HTLC_HDR_ICON_GET = 0x00000747 +HTLC_HDR_ICON_LIST = 0x00000745 +HTLC_HDR_ICON_SET = 0x00000746 +HTLC_HDR_ICON_GET = 0x00000747 # Server packet types -HTLS_HDR_NEWS_POST = 0x00000066 -HTLS_HDR_MSG = 0x00000068 -HTLS_HDR_CHAT = 0x0000006A -HTLS_HDR_CHAT_INVITE = 0x00000071 -HTLS_HDR_CHAT_USER_CHANGE = 0x00000075 -HTLS_HDR_CHAT_USER_LEAVE = 0x00000076 -HTLS_HDR_CHAT_SUBJECT = 0x00000077 -HTLS_HDR_USER_CHANGE = 0x0000012D -HTLS_HDR_USER_LEAVE = 0x0000012E -HTLS_HDR_SELFINFO = 0x00000162 -HTLS_HDR_BROADCAST = 0x00000163 -HTLS_HDR_PING = 0x000001f4 -HTLS_HDR_TASK = 0x00010000 +HTLS_HDR_NEWS_POST = 0x00000066 +HTLS_HDR_MSG = 0x00000068 +HTLS_HDR_CHAT = 0x0000006A +HTLS_HDR_CHAT_INVITE = 0x00000071 +HTLS_HDR_CHAT_USER_CHANGE = 0x00000075 +HTLS_HDR_CHAT_USER_LEAVE = 0x00000076 +HTLS_HDR_CHAT_SUBJECT = 0x00000077 +HTLS_HDR_USER_CHANGE = 0x0000012D +HTLS_HDR_USER_LEAVE = 0x0000012E +HTLS_HDR_SELFINFO = 0x00000162 +HTLS_HDR_BROADCAST = 0x00000163 +HTLS_HDR_PING = 0x000001f4 +HTLS_HDR_TASK = 0x00010000 # Avaraline protocol additions -HTLS_HDR_ICON_CHANGE = 0x00000748 +HTLS_HDR_ICON_CHANGE = 0x00000748 HTLS_HDR_LINK_LOGIN = 0x00000800 HTLS_HDR_LINK_JOIN = 0x00000801 @@ -495,85 +495,85 @@ def flatten( self , user ): # Common data (object) types -DATA_ERROR = 0x0064 -DATA_STRING = 0x0065 -DATA_NICK = 0x0066 -DATA_UID = 0x0067 -DATA_ICON = 0x0068 -DATA_LOGIN = 0x0069 -DATA_PASSWORD = 0x006A -DATA_XFERID = 0x006B -DATA_XFERSIZE = 0x006C -DATA_OPTION = 0x006D -DATA_PRIVS = 0x006E -DATA_STATUS = 0x0070 -DATA_BAN = 0x0071 -DATA_CHATID = 0x0072 -DATA_SUBJECT = 0x0073 -DATA_VERSION = 0x00A0 -DATA_SERVERNAME = 0x00A2 -DATA_FILE = 0x00C8 -DATA_FILENAME = 0x00C9 -DATA_DIR = 0x00CA -DATA_RESUME = 0x00CB -DATA_XFEROPTIONS = 0x00CC -DATA_FILETYPE = 0x00CD -DATA_FILECREATOR = 0x00CE -DATA_FILESIZE = 0x00CF -DATA_NEWFILE = 0x00D3 -DATA_NEWDIR = 0x00D4 -DATA_USER = 0x012C +DATA_ERROR = 0x0064 +DATA_STRING = 0x0065 +DATA_NICK = 0x0066 +DATA_UID = 0x0067 +DATA_ICON = 0x0068 +DATA_LOGIN = 0x0069 +DATA_PASSWORD = 0x006A +DATA_XFERID = 0x006B +DATA_XFERSIZE = 0x006C +DATA_OPTION = 0x006D +DATA_PRIVS = 0x006E +DATA_STATUS = 0x0070 +DATA_BAN = 0x0071 +DATA_CHATID = 0x0072 +DATA_SUBJECT = 0x0073 +DATA_VERSION = 0x00A0 +DATA_SERVERNAME = 0x00A2 +DATA_FILE = 0x00C8 +DATA_FILENAME = 0x00C9 +DATA_DIR = 0x00CA +DATA_RESUME = 0x00CB +DATA_XFEROPTIONS = 0x00CC +DATA_FILETYPE = 0x00CD +DATA_FILECREATOR = 0x00CE +DATA_FILESIZE = 0x00CF +DATA_NEWFILE = 0x00D3 +DATA_NEWDIR = 0x00D4 +DATA_USER = 0x012C # Avaraline protocol additions -DATA_GIFICON = 0x0300 -DATA_GIFLIST = 0x0301 -DATA_NEWSLIMIT = 0x0320 -DATA_COLOR = 0x0500 +DATA_GIFICON = 0x0300 +DATA_GIFLIST = 0x0301 +DATA_NEWSLIMIT = 0x0320 +DATA_COLOR = 0x0500 DATA_PACKET = 0x0600 # IRC needed hackery -DATA_IRC_OLD_NICK = 0x0400 +DATA_IRC_OLD_NICK = 0x0400 # Hotline's idea of "bit 0" is ass backwards -PRIV_DELETE_FILES = 1L << 63 -PRIV_UPLOAD_FILES = 1L << 62 -PRIV_DOWNLOAD_FILES = 1L << 61 -PRIV_RENAME_FILES = 1L << 60 -PRIV_MOVE_FILES = 1L << 59 -PRIV_CREATE_FOLDERS = 1L << 58 -PRIV_DELETE_FOLDERS = 1L << 57 -PRIV_RENAME_FOLDERS = 1L << 56 -PRIV_MOVE_FOLDERS = 1L << 55 -PRIV_READ_CHAT = 1L << 54 -PRIV_SEND_CHAT = 1L << 53 -PRIV_CREATE_CHATS = 1L << 52 -PRIV_DELETE_CHATS = 1L << 51 -PRIV_SHOW_USER = 1L << 50 -PRIV_CREATE_USERS = 1L << 49 -PRIV_DELETE_USERS = 1L << 48 -PRIV_READ_USERS = 1L << 47 -PRIV_MODIFY_USERS = 1L << 46 -PRIV_CHANGE_PASSWORD = 1L << 45 -PRIV_UNKNOWN = 1L << 44 -PRIV_READ_NEWS = 1L << 43 -PRIV_POST_NEWS = 1L << 42 -PRIV_KICK_USERS = 1L << 41 -PRIV_KICK_PROTECT = 1L << 40 -PRIV_USER_INFO = 1L << 39 -PRIV_UPLOAD_ANYWHERE = 1L << 38 -PRIV_USE_ANY_NAME = 1L << 37 -PRIV_NO_AGREEMENT = 1L << 36 -PRIV_COMMENT_FILES = 1L << 35 -PRIV_COMMENT_FOLDERS = 1L << 34 -PRIV_VIEW_DROPBOXES = 1L << 33 -PRIV_MAKE_ALIASES = 1L << 32 -PRIV_BROADCAST = 1L << 31 - -PRIV_SEND_MESSAGES = 1L << 23 +PRIV_DELETE_FILES = 1L << 63 +PRIV_UPLOAD_FILES = 1L << 62 +PRIV_DOWNLOAD_FILES = 1L << 61 +PRIV_RENAME_FILES = 1L << 60 +PRIV_MOVE_FILES = 1L << 59 +PRIV_CREATE_FOLDERS = 1L << 58 +PRIV_DELETE_FOLDERS = 1L << 57 +PRIV_RENAME_FOLDERS = 1L << 56 +PRIV_MOVE_FOLDERS = 1L << 55 +PRIV_READ_CHAT = 1L << 54 +PRIV_SEND_CHAT = 1L << 53 +PRIV_CREATE_CHATS = 1L << 52 +PRIV_DELETE_CHATS = 1L << 51 +PRIV_SHOW_USER = 1L << 50 +PRIV_CREATE_USERS = 1L << 49 +PRIV_DELETE_USERS = 1L << 48 +PRIV_READ_USERS = 1L << 47 +PRIV_MODIFY_USERS = 1L << 46 +PRIV_CHANGE_PASSWORD = 1L << 45 +PRIV_UNKNOWN = 1L << 44 +PRIV_READ_NEWS = 1L << 43 +PRIV_POST_NEWS = 1L << 42 +PRIV_KICK_USERS = 1L << 41 +PRIV_KICK_PROTECT = 1L << 40 +PRIV_USER_INFO = 1L << 39 +PRIV_UPLOAD_ANYWHERE = 1L << 38 +PRIV_USE_ANY_NAME = 1L << 37 +PRIV_NO_AGREEMENT = 1L << 36 +PRIV_COMMENT_FILES = 1L << 35 +PRIV_COMMENT_FOLDERS = 1L << 34 +PRIV_VIEW_DROPBOXES = 1L << 33 +PRIV_MAKE_ALIASES = 1L << 32 +PRIV_BROADCAST = 1L << 31 + +PRIV_SEND_MESSAGES = 1L << 23 # Status bits -STATUS_AWAY = 1 << 0 -STATUS_ADMIN = 1 << 1 +STATUS_AWAY = 1 << 0 +STATUS_ADMIN = 1 << 1 diff --git a/shared/HLTransfer.py b/shared/HLTransfer.py index 7d59192..954c6ba 100644 --- a/shared/HLTransfer.py +++ b/shared/HLTransfer.py @@ -5,161 +5,161 @@ XFER_TYPE_UPLOAD = 1 class HLTransfer: - def __init__( self , id , path , owner , type ): - self.id = id - self.path = path - self.name = os.path.basename( path ) - self.owner = owner - self.type = type - self.total = 0L - self.transferred = 0L - self.offset = 0L - self.startTime = 0.0 - - def overallPercent( self ): - return 0 - - def getTotalBPS( self ): - """ Returns the overall speed (in BPS) of this transfer. """ - elapsed = time.time() - self.startTime - if elapsed > 0.0: - return int( float( self.transferred ) / elapsed ) - return 0 - - def isComplete( self ): - """ Returns True if all data has been sent or received. """ - return self.transferred >= self.total - - def parseData( self , data ): - """ Called when data is received from a transfer. """ - raise "Transfer does not implement parseData." - - def getDataChunk( self ): - """ Called when writing data to a transfer. """ - raise "Transfer does not implement getDataChunk." - - def start( self ): - """ Called when the connection is opened. """ - self.startTime = time.time() - - def finish( self ): - """ Called when the connection is closed. """ - pass + def __init__( self , id , path , owner , type ): + self.id = id + self.path = path + self.name = os.path.basename( path ) + self.owner = owner + self.type = type + self.total = 0L + self.transferred = 0L + self.offset = 0L + self.startTime = 0.0 + + def overallPercent( self ): + return 0 + + def getTotalBPS( self ): + """ Returns the overall speed (in BPS) of this transfer. """ + elapsed = time.time() - self.startTime + if elapsed > 0.0: + return int( float( self.transferred ) / elapsed ) + return 0 + + def isComplete( self ): + """ Returns True if all data has been sent or received. """ + return self.transferred >= self.total + + def parseData( self , data ): + """ Called when data is received from a transfer. """ + raise "Transfer does not implement parseData." + + def getDataChunk( self ): + """ Called when writing data to a transfer. """ + raise "Transfer does not implement getDataChunk." + + def start( self ): + """ Called when the connection is opened. """ + self.startTime = time.time() + + def finish( self ): + """ Called when the connection is closed. """ + pass class HLDownload( HLTransfer ): - def __init__( self , id , path , owner , offset ): - HLTransfer.__init__( self , id , path , owner , XFER_TYPE_DOWNLOAD ) - self.offset = offset - self.dataSize = os.path.getsize( path ) - offset - self.file = file( path , "r" ) - self.file.seek( offset ) - self.sentHeader = False - self._buildHeaderData() - self.total = len( self.header ) + self.dataSize - - def overallPercent( self ): - done = self.offset + self.transferred - total = os.path.getsize( self.path ) + len( self.header ) - if total > 0: - return int( ( float( done ) / float( total ) ) * 100 ) - return 0 - - def getDataChunk( self ): - """ Returns the next chunk of data to be sent out. """ - if self.sentHeader: - # We already sent the header, read from the file. - data = self.file.read( 2 ** 14 ) - self.transferred += len( data ) - return data - else: - # Send the header, mark it as sent. - self.sentHeader = True - self.transferred += len( self.header ) - return self.header - - def finish( self ): - """ Called when the download connection closes. """ - self.file.close() - - def _buildHeaderData( self ): - """ Builds the header info for the file transfer, including the FILP header, INFO header and fork, and DATA header. """ - self.header = pack( "!LHLLLLH" , HLCharConst( "FILP" ) , 1 , 0 , 0 , 0 , 0 , 2 ) - self.header += pack( "!4L" , HLCharConst( "INFO" ) , 0 , 0 , 74 + len( self.name ) ) - self.header += pack( "!5L" , HLCharConst( "AMAC" ) , HLCharConst( "????" ) , HLCharConst( "????" ) , 0 , 0 ) - self.header += ( "\0" * 32 ) - self.header += pack( "!HHL" , 0 , 0 , 0 ) - self.header += pack( "!HHL" , 0 , 0 , 0 ) - self.header += pack( "!HH" , 0 , len( self.name ) ) - self.header += self.name - self.header += pack( "!H" , 0 ) - self.header += pack( "!4L" , HLCharConst( "DATA" ) , 0 , 0 , self.dataSize ) + def __init__( self , id , path , owner , offset ): + HLTransfer.__init__( self , id , path , owner , XFER_TYPE_DOWNLOAD ) + self.offset = offset + self.dataSize = os.path.getsize( path ) - offset + self.file = file( path , "r" ) + self.file.seek( offset ) + self.sentHeader = False + self._buildHeaderData() + self.total = len( self.header ) + self.dataSize + + def overallPercent( self ): + done = self.offset + self.transferred + total = os.path.getsize( self.path ) + len( self.header ) + if total > 0: + return int( ( float( done ) / float( total ) ) * 100 ) + return 0 + + def getDataChunk( self ): + """ Returns the next chunk of data to be sent out. """ + if self.sentHeader: + # We already sent the header, read from the file. + data = self.file.read( 2 ** 14 ) + self.transferred += len( data ) + return data + else: + # Send the header, mark it as sent. + self.sentHeader = True + self.transferred += len( self.header ) + return self.header + + def finish( self ): + """ Called when the download connection closes. """ + self.file.close() + + def _buildHeaderData( self ): + """ Builds the header info for the file transfer, including the FILP header, INFO header and fork, and DATA header. """ + self.header = pack( "!LHLLLLH" , HLCharConst( "FILP" ) , 1 , 0 , 0 , 0 , 0 , 2 ) + self.header += pack( "!4L" , HLCharConst( "INFO" ) , 0 , 0 , 74 + len( self.name ) ) + self.header += pack( "!5L" , HLCharConst( "AMAC" ) , HLCharConst( "????" ) , HLCharConst( "????" ) , 0 , 0 ) + self.header += ( "\0" * 32 ) + self.header += pack( "!HHL" , 0 , 0 , 0 ) + self.header += pack( "!HHL" , 0 , 0 , 0 ) + self.header += pack( "!HH" , 0 , len( self.name ) ) + self.header += self.name + self.header += pack( "!H" , 0 ) + self.header += pack( "!4L" , HLCharConst( "DATA" ) , 0 , 0 , self.dataSize ) STATE_FILP = 0 STATE_HEADER = 1 STATE_FORK = 2 class HLUpload( HLTransfer ): - def __init__( self , id , path , owner ): - HLTransfer.__init__( self , id , path , owner , 1 ) - self.file = file( path , "a" ) - self.initialSize = os.path.getsize( path ) - self.buffer = "" - self.state = STATE_FILP - self.forkCount = 0 - self.currentFork = 0 - self.forkSize = 0 - self.forkOffset = 0 - - def overallPercent( self ): - done = self.initialSize + self.transferred - total = self.initialSize + self.total - if total > 0: - return int( ( float( done ) / float( total ) ) * 100 ) - return 0 - - def parseData( self , data ): - """ Called when data is received from the upload connection. writes any data received for the DATA fork out to the specified file. """ - self.buffer += data - self.transferred += len( data ) - while True: - if self.state == STATE_FILP: - if len( self.buffer ) < 24: - return False - ( proto , vers , _r1 , _r2 , _r3 , _r4 , self.forkCount ) = unpack( "!LHLLLLH" , self.buffer[0:24] ) - self.buffer = self.buffer[24:] - self.state = STATE_HEADER - elif self.state == STATE_HEADER: - if len( self.buffer ) < 16: - return False - (self.currentFork , _r1 , _r2 , self.forkSize ) = unpack( "!4L" , self.buffer[0:16] ) - self.buffer = self.buffer[16:] - self.forkOffset = 0 - self.state = STATE_FORK - elif self.state == STATE_FORK: - remaining = self.forkSize - self.forkOffset - if len( self.buffer ) < remaining: - # We don't have the rest of the fork yet. - if self.currentFork == HLCharConst( "DATA" ): - # Write to the file if this is the DATA fork. - self.file.write( self.buffer ) - self.forkOffset += len( self.buffer ) - self.buffer = "" - return False - else: - # We got the rest of the current fork. - if self.currentFork == HLCharConst( "DATA" ): - self.file.write( self.buffer[0:remaining] ) - self.buffer = self.buffer[remaining:] - self.forkCount -= 1 - if self.forkCount <= 0: - return True - self.state = STATE_HEADER - - def finish( self ): - """ Called when the upload connection closes. If the upload is complete, renames the file, stripping off the .hpf extension. """ - self.file.close() - if self.isComplete() and self.path.endswith( ".hpf" ): - newPath = self.path[:-4] - os.rename( self.path , newPath ) - self.path = newPath - self.name = os.path.basename( self.path ) + def __init__( self , id , path , owner ): + HLTransfer.__init__( self , id , path , owner , 1 ) + self.file = file( path , "a" ) + self.initialSize = os.path.getsize( path ) + self.buffer = "" + self.state = STATE_FILP + self.forkCount = 0 + self.currentFork = 0 + self.forkSize = 0 + self.forkOffset = 0 + + def overallPercent( self ): + done = self.initialSize + self.transferred + total = self.initialSize + self.total + if total > 0: + return int( ( float( done ) / float( total ) ) * 100 ) + return 0 + + def parseData( self , data ): + """ Called when data is received from the upload connection. writes any data received for the DATA fork out to the specified file. """ + self.buffer += data + self.transferred += len( data ) + while True: + if self.state == STATE_FILP: + if len( self.buffer ) < 24: + return False + ( proto , vers , _r1 , _r2 , _r3 , _r4 , self.forkCount ) = unpack( "!LHLLLLH" , self.buffer[0:24] ) + self.buffer = self.buffer[24:] + self.state = STATE_HEADER + elif self.state == STATE_HEADER: + if len( self.buffer ) < 16: + return False + (self.currentFork , _r1 , _r2 , self.forkSize ) = unpack( "!4L" , self.buffer[0:16] ) + self.buffer = self.buffer[16:] + self.forkOffset = 0 + self.state = STATE_FORK + elif self.state == STATE_FORK: + remaining = self.forkSize - self.forkOffset + if len( self.buffer ) < remaining: + # We don't have the rest of the fork yet. + if self.currentFork == HLCharConst( "DATA" ): + # Write to the file if this is the DATA fork. + self.file.write( self.buffer ) + self.forkOffset += len( self.buffer ) + self.buffer = "" + return False + else: + # We got the rest of the current fork. + if self.currentFork == HLCharConst( "DATA" ): + self.file.write( self.buffer[0:remaining] ) + self.buffer = self.buffer[remaining:] + self.forkCount -= 1 + if self.forkCount <= 0: + return True + self.state = STATE_HEADER + + def finish( self ): + """ Called when the upload connection closes. If the upload is complete, renames the file, stripping off the .hpf extension. """ + self.file.close() + if self.isComplete() and self.path.endswith( ".hpf" ): + newPath = self.path[:-4] + os.rename( self.path , newPath ) + self.path = newPath + self.name = os.path.basename( self.path ) diff --git a/shared/HLTypes.py b/shared/HLTypes.py index 229a324..e65a2df 100644 --- a/shared/HLTypes.py +++ b/shared/HLTypes.py @@ -3,15 +3,15 @@ from struct import * import os -LOG_TYPE_GENERAL = 1 -LOG_TYPE_LOGIN = 2 -LOG_TYPE_USER = 3 -LOG_TYPE_ACCOUNT = 4 -LOG_TYPE_FILE = 5 -LOG_TYPE_TRANSFER = 6 +LOG_TYPE_GENERAL = 1 +LOG_TYPE_LOGIN = 2 +LOG_TYPE_USER = 3 +LOG_TYPE_ACCOUNT = 4 +LOG_TYPE_FILE = 5 +LOG_TYPE_TRANSFER = 6 LOG_TYPE_TRACKER = 7 -LOG_TYPE_ERROR = 99 -LOG_TYPE_DEBUG = 666 +LOG_TYPE_ERROR = 99 +LOG_TYPE_DEBUG = 666 LOG_TYPE_STR_MAP = {LOG_TYPE_GENERAL:"GENERAL", LOG_TYPE_LOGIN:"LOGIN", @@ -24,68 +24,68 @@ LOG_TYPE_DEBUG:"DEBUG"} class HLException: - """ Exception thrown due to protocol errors. """ - - def __init__( self , msg = "Unknown exception." , fatal = False ): - self.msg = msg - self.fatal = fatal + """ Exception thrown due to protocol errors. """ + + def __init__( self , msg = "Unknown exception." , fatal = False ): + self.msg = msg + self.fatal = fatal class HLAccount: - """ Stores account information. """ - - def __init__( self , login = "" ): - self.id = 0L - self.login = login - self.password = "" - self.name = "Null Account" - self.privs = 0L - self.fileRoot = "" - - def copyFrom( self , acct ): - """ Take all instance variables from the specified HLAccount object. - Useful for updating account information without making a new object. """ - self.id = acct.id - self.login = acct.login - self.password = acct.password - self.name = acct.name - self.privs = acct.privs - if acct.fileRoot != "": - self.fileRoot = acct.fileRoot + """ Stores account information. """ + + def __init__( self , login = "" ): + self.id = 0L + self.login = login + self.password = "" + self.name = "Null Account" + self.privs = 0L + self.fileRoot = "" + + def copyFrom( self , acct ): + """ Take all instance variables from the specified HLAccount object. + Useful for updating account information without making a new object. """ + self.id = acct.id + self.login = acct.login + self.password = acct.password + self.name = acct.name + self.privs = acct.privs + if acct.fileRoot != "": + self.fileRoot = acct.fileRoot class HLUser: - """ Stores user information, along with an associated HLAccount object. Also flattenable for use in userlist packet objects. """ - - def __init__( self , uid = 0 , addr = "" ): - self.uid = uid - self.ip = addr - self.nick = "unnamed" - self.icon = 500 - self.status = 0 - self.gif = "" - self.color = -1L - self.account = None - self.away = False - self.lastPacketTime = 0.0 - self.valid = False - self.local = True - self.isIRC = False - - def getProtocol( self ): - """ Returns the protocol used by the client. """ - if self.isIRC: - return "IRC" - else: - return "Hotline" - - def isLoggedIn( self ): - """ Returns True if the user has successfully logged in. """ - return self.valid - - def hasPriv( self , priv ): - """ Returns True if the account associated with the user has the specified privilege. """ - return ( self.account != None ) and ( ( long( self.account.privs ) & priv ) > 0 ) + """ Stores user information, along with an associated HLAccount object. Also flattenable for use in userlist packet objects. """ + + def __init__( self , uid = 0 , addr = "" ): + self.uid = uid + self.ip = addr + self.nick = "unnamed" + self.icon = 500 + self.status = 0 + self.gif = "" + self.color = -1L + self.account = None + self.away = False + self.lastPacketTime = 0.0 + self.valid = False + self.local = True + self.isIRC = False + + def getProtocol( self ): + """ Returns the protocol used by the client. """ + if self.isIRC: + return "IRC" + else: + return "Hotline" + + def isLoggedIn( self ): + """ Returns True if the user has successfully logged in. """ + return self.valid + + def hasPriv( self , priv ): + """ Returns True if the account associated with the user has the specified privilege. """ + return ( self.account != None ) and ( ( long( self.account.privs ) & priv ) > 0 ) - def parse( self, data ): + def parse( self, data ): if len(data) < 8: return 0 ( self.uid, self.icon, self.status, nicklen ) = unpack( "!4H", data[0:8] ) @@ -96,129 +96,129 @@ def parse( self, data ): self.color = unpack( "!L", data[8+nicklen:12+nicklen] )[0] return ( 12 + nicklen ) return ( 8 + nicklen ) - - - def flatten( self ): - """ Flattens the user information into a packed structure to send in a HLObject. """ - data = "" - data += pack( "!4H" , self.uid , self.icon , self.status , len( self.nick ) ) - data += self.nick - # this is an avaraline extension for nick coloring - if self.color >= 0L: - data += pack( "!L" , self.color ) - return data + + + def flatten( self ): + """ Flattens the user information into a packed structure to send in a HLObject. """ + data = "" + data += pack( "!4H" , self.uid , self.icon , self.status , len( self.nick ) ) + data += self.nick + # this is an avaraline extension for nick coloring + if self.color >= 0L: + data += pack( "!L" , self.color ) + return data class HLChat: - """ Stores information about a private chat. """ - - def __init__( self , id = 0 ): - self.id = id - self.users = [] - self.invites = [] - self.subject = "" - - def addUser( self , user ): - """ Adds the specified user to this chat. """ - self.users.append( user ) - - def addInvite( self , user ): - """ Adds the specified user to the list of invitees for this chat. """ - self.invites.append( user.uid ) - - def removeUser( self , user ): - """ Removes the specified user from this chat. """ - self.users.remove( user ) - - def removeInvite( self , user ): - """ Removes the specified user from the list of invitees for this chat. """ - self.invites.remove( user.uid ) - - def hasUser( self , user ): - """ Returns True if this chat has the specified user in it. """ - for u in self.users: - if u.uid == user.uid: - return True - return False - - def hasInvite( self , user ): - """ Returns True if this chat has the specified user in its list of invitees. """ - for uid in self.invites: - if user.uid == uid: - return True - return False + """ Stores information about a private chat. """ + + def __init__( self , id = 0 ): + self.id = id + self.users = [] + self.invites = [] + self.subject = "" + + def addUser( self , user ): + """ Adds the specified user to this chat. """ + self.users.append( user ) + + def addInvite( self , user ): + """ Adds the specified user to the list of invitees for this chat. """ + self.invites.append( user.uid ) + + def removeUser( self , user ): + """ Removes the specified user from this chat. """ + self.users.remove( user ) + + def removeInvite( self , user ): + """ Removes the specified user from the list of invitees for this chat. """ + self.invites.remove( user.uid ) + + def hasUser( self , user ): + """ Returns True if this chat has the specified user in it. """ + for u in self.users: + if u.uid == user.uid: + return True + return False + + def hasInvite( self , user ): + """ Returns True if this chat has the specified user in its list of invitees. """ + for uid in self.invites: + if user.uid == uid: + return True + return False class HLResumeData: - """ Stores transfer resume data (offsets for each fork type). """ - - def __init__( self , data = None ): - self.forkOffsets = {} - self.forkCount = 0 - if ( data != None ) and ( len( data ) >= 42 ): - self._parseResumeData( data ) - - def forkOffset( self , fork ): - """ Returns the offset for the specified fork type. """ - if self.forkOffsets.has_key( fork ): - return self.forkOffsets[fork] - return 0 - - def setForkOffset( self , fork , offset ): - """ Sets the offset for the specified fork type. """ - self.forkOffsets[fork] = offset - - def _parseResumeData( self , data ): - """ Parses the specified packed structure data into this resume data object. """ - ( format , version ) = unpack( "!LH" , data[0:6] ) - _reserved = data[6:40] - self.forkCount = unpack( "!H" , data[40:42] )[0] - for k in range( self.forkCount ): - offset = 42 + ( 16 * k ) - subData = data[offset:offset+8] - if len( subData ) == 8: - ( forkType , forkOffset ) = unpack( "!2L" , subData ) - self.forkOffsets[forkType] = forkOffset - - def flatten( self ): - """ Flattens the resume information into a packed structure to send in a HLObject. """ - data = pack( "!LH" , HLCharConst( "RFLT" ) , 1 ) - data += ( "\0" * 34 ) - data += pack( "!H" , len( self.forkOffsets.keys() ) ) - for forkType in self.forkOffsets.keys(): - data += pack( "!4L" , forkType , self.forkOffsets[forkType] , 0 , 0 ) - return data + """ Stores transfer resume data (offsets for each fork type). """ + + def __init__( self , data = None ): + self.forkOffsets = {} + self.forkCount = 0 + if ( data != None ) and ( len( data ) >= 42 ): + self._parseResumeData( data ) + + def forkOffset( self , fork ): + """ Returns the offset for the specified fork type. """ + if self.forkOffsets.has_key( fork ): + return self.forkOffsets[fork] + return 0 + + def setForkOffset( self , fork , offset ): + """ Sets the offset for the specified fork type. """ + self.forkOffsets[fork] = offset + + def _parseResumeData( self , data ): + """ Parses the specified packed structure data into this resume data object. """ + ( format , version ) = unpack( "!LH" , data[0:6] ) + _reserved = data[6:40] + self.forkCount = unpack( "!H" , data[40:42] )[0] + for k in range( self.forkCount ): + offset = 42 + ( 16 * k ) + subData = data[offset:offset+8] + if len( subData ) == 8: + ( forkType , forkOffset ) = unpack( "!2L" , subData ) + self.forkOffsets[forkType] = forkOffset + + def flatten( self ): + """ Flattens the resume information into a packed structure to send in a HLObject. """ + data = pack( "!LH" , HLCharConst( "RFLT" ) , 1 ) + data += ( "\0" * 34 ) + data += pack( "!H" , len( self.forkOffsets.keys() ) ) + for forkType in self.forkOffsets.keys(): + data += pack( "!4L" , forkType , self.forkOffsets[forkType] , 0 , 0 ) + return data class HLNewsPost: - """ Stores information about a single news post. """ - - def __init__( self , nick = "" , login = "" , post = "" ): - self.id = 0L - self.nick = nick - self.login = login - self.post = post - now = datetime.now() - self.date = now.replace( microsecond = 0 ) + """ Stores information about a single news post. """ + + def __init__( self , nick = "" , login = "" , post = "" ): + self.id = 0L + self.nick = nick + self.login = login + self.post = post + now = datetime.now() + self.date = now.replace( microsecond = 0 ) class HLPacketHandler: - """ Packet handler base class. Should be overridden to handle actual packets. """ - - def __init__( self ): - self._funcs = {} - - def registerHandlerFunction( self , type , func ): - """ Registers the specified function to be called when handling the specified packet type. """ - self._funcs[type] = func - - def handleUserConnected( self , server , user ): - """ Called when a user connects, before any packets are handled. Should be overridden. """ - pass - - def handleUserDisconnected( self , server , user ): - """ Called when a user disconnects. Should be overridden. """ - pass - - def handlePacket( self , server , user , packet ): - """ Default dispatcher called when a packet is received. Calls any registered handler functions. Returns True when packet is handled. """ - if self._funcs.has_key( packet.type ): - self._funcs[packet.type]( server , user , packet ) - return True - return False + """ Packet handler base class. Should be overridden to handle actual packets. """ + + def __init__( self ): + self._funcs = {} + + def registerHandlerFunction( self , type , func ): + """ Registers the specified function to be called when handling the specified packet type. """ + self._funcs[type] = func + + def handleUserConnected( self , server , user ): + """ Called when a user connects, before any packets are handled. Should be overridden. """ + pass + + def handleUserDisconnected( self , server , user ): + """ Called when a user disconnects. Should be overridden. """ + pass + + def handlePacket( self , server , user , packet ): + """ Default dispatcher called when a packet is received. Calls any registered handler functions. Returns True when packet is handled. """ + if self._funcs.has_key( packet.type ): + self._funcs[packet.type]( server , user , packet ) + return True + return False diff --git a/shared/HLUtils.py b/shared/HLUtils.py index 17f3b8f..4b14c74 100644 --- a/shared/HLUtils.py +++ b/shared/HLUtils.py @@ -2,32 +2,32 @@ def shell_exec ( user, cmd, arg ): - os.environ['_LOGIN'] = user.account.login - os.environ['_UID'] = str(user.uid) - os.environ['_IP'] = user.ip - os.environ['_ICON'] = str(user.icon) - os.environ['_COLOR'] = str(user.status) - os.environ['_NICK'] = user.nick - os.environ['_NAME'] = user.account.name - os.environ['_PRIVS'] = str(user.account.privs) - os.environ['_FROOT'] = user.account.fileRoot - if user.isIRC: proto = "IRC" - else: proto = "Hotline" - os.environ['_PROTO'] = proto + os.environ['_LOGIN'] = user.account.login + os.environ['_UID'] = str(user.uid) + os.environ['_IP'] = user.ip + os.environ['_ICON'] = str(user.icon) + os.environ['_COLOR'] = str(user.status) + os.environ['_NICK'] = user.nick + os.environ['_NAME'] = user.account.name + os.environ['_PRIVS'] = str(user.account.privs) + os.environ['_FROOT'] = user.account.fileRoot + if user.isIRC: proto = "IRC" + else: proto = "Hotline" + os.environ['_PROTO'] = proto - path = cmd+" "+arg - path = path.replace('..', '') - path = "./support/exec/" + path - put, get, error = os.popen3(path) - - if( len(error.readlines()) == 1): - return None - ret = '' - for result in get.readlines(): - ret += result - return ret + path = cmd+" "+arg + path = path.replace('..', '') + path = "./support/exec/" + path + put, get, error = os.popen3(path) + + if( len(error.readlines()) == 1): + return None + ret = '' + for result in get.readlines(): + ret += result + return ret #from twisted.internet import utils #def shell_exec ( user, cmd, arg ): -# return utils.getProcessOuput(cmd, arg) +# return utils.getProcessOuput(cmd, arg) From 509df1b818f0cbd5c16c59997d7e18059b7781a5 Mon Sep 17 00:00:00 2001 From: Patrick Thiel Date: Mon, 2 Oct 2023 22:43:01 -0400 Subject: [PATCH 4/8] ref: run modernize script, fix various compatibility issues --- config.py | 1 + configure_phxd.py | 4 +- phxd | 4 +- server/HLDatabase.py | 4 +- server/HLDatabaseLogger.py | 1 + server/HLFileServer.py | 9 +- server/HLServer.py | 124 ++++++------ server/HLServerLinkage.py | 22 +- server/HLTracker.py | 1 + server/HLWebServices.py | 5 +- server/database/MySQLDatabase.py | 11 +- server/database/TextDatabase.py | 36 ++-- server/handlers/AcctHandler.py | 17 +- server/handlers/ChatHandler.py | 19 +- server/handlers/FileHandler.py | 45 +++-- server/handlers/IconHandler.py | 5 +- server/handlers/NewsHandler.py | 5 +- server/handlers/UserHandler.py | 29 +-- server/handlers/commands/0wn.py | 1 + server/handlers/commands/away.py | 1 + server/handlers/commands/broadcast.py | 1 + server/handlers/commands/color.py | 1 + server/handlers/commands/find.py | 1 + server/handlers/commands/me.py | 1 + server/handlers/commands/news.py | 1 + server/handlers/commands/uptime.py | 3 +- server/handlers/commands/xfers.py | 3 +- shared/HLProtocol.py | 279 +++++++++++++------------- shared/HLTransfer.py | 11 +- shared/HLTypes.py | 22 +- shared/HLUtils.py | 1 + support/text_db_setup.py | 1 + 32 files changed, 358 insertions(+), 311 deletions(-) diff --git a/config.py b/config.py index 8543276..b7fcbed 100644 --- a/config.py +++ b/config.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import os ################################################################################ # database configuration diff --git a/configure_phxd.py b/configure_phxd.py index 6985085..0acadb3 100644 --- a/configure_phxd.py +++ b/configure_phxd.py @@ -5,6 +5,8 @@ TODO: This is unecessarily complex. Need to use a better config file format instead """ +from __future__ import absolute_import +from __future__ import print_function __author__ = "Cat'Killer" __version__ = "0.0.1" __license__ = "WTFPL" @@ -55,7 +57,7 @@ def rewrite_config_file(filepath, values_dict): """ if not values_dict: return - keys = values_dict.keys() + keys = list(values_dict.keys()) with open(filepath, 'r') as config_file: config_str = config_file.read() with tempfile.NamedTemporaryFile(delete=False) as tmpconfig: diff --git a/phxd b/phxd index bf3340e..0214799 100755 --- a/phxd +++ b/phxd @@ -1,5 +1,7 @@ #!/usr/bin/env python +from __future__ import absolute_import +from __future__ import print_function from twisted.internet import reactor from server.HLServer import HLServer from shared.HLTypes import * @@ -12,7 +14,7 @@ for modName in server.handlers.__all__: mod = __import__( "server.handlers.%s" % modName , None , None , "server.handlers" ) mod.installHandler( serv ) except ImportError: - print "error importing server.handlers.%s" % modName + print("error importing server.handlers.%s" % modName) serv.logEvent( LOG_TYPE_GENERAL , "Server started on port %d" % serv.port ) reactor.run() diff --git a/server/HLDatabase.py b/server/HLDatabase.py index 7c0c4c0..749da8c 100644 --- a/server/HLDatabase.py +++ b/server/HLDatabase.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import +from __future__ import print_function from shared.HLTypes import * import server.database @@ -9,7 +11,7 @@ def getDatabase( type ): db = eval( "mod.%s()" % cls ) return db except ImportError: - print "error importing server.database.%s" % cls + print("error importing server.database.%s" % cls) return None class HLDatabase: diff --git a/server/HLDatabaseLogger.py b/server/HLDatabaseLogger.py index 8879608..9baa0dd 100644 --- a/server/HLDatabaseLogger.py +++ b/server/HLDatabaseLogger.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from logging import Handler class HLDatabaseLogger( Handler ): diff --git a/server/HLFileServer.py b/server/HLFileServer.py index e1f54e0..1a7c53e 100644 --- a/server/HLFileServer.py +++ b/server/HLFileServer.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from twisted.internet.protocol import Factory , Protocol from twisted.internet.interfaces import IProducer from twisted.internet import reactor @@ -102,7 +103,7 @@ def addDownload( self , owner , path , offset ): def findTransfer( self , xfid ): """ Returns the HLTransfer (HLDownload or HLUpload) object for the specified transfer ID. """ - if self.transfers.has_key( xfid ): + if xfid in self.transfers: return self.transfers[xfid] return None @@ -116,19 +117,19 @@ def findTransfersForUser( self , uid ): def cancelTimeout( self , id ): """ Cancels a pending timeout for the specified transfer. """ - if self.timeouts.has_key( id ): + if id in self.timeouts: self.timeouts[id].cancel() del self.timeouts[id] def timeoutTransfer( self , id ): """ Called after an initial timeout to remove the dead transfer from the list of transfers. """ - if self.transfers.has_key( id ): + if id in self.transfers: del self.timeouts[id] del self.transfers[id] def removeTransfer( self , xfid ): """ Removes a transfer from the list of transfers. """ - if self.transfers.has_key( xfid ): + if xfid in self.transfers: info = self.transfers[xfid] user = self.server.getUser( info.owner ) if user != None: diff --git a/server/HLServer.py b/server/HLServer.py index 95c5b0c..ad8a3a3 100644 --- a/server/HLServer.py +++ b/server/HLServer.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import +from __future__ import print_function from twisted.internet.protocol import Factory , Protocol from twisted.internet import task from twisted.internet import reactor @@ -29,7 +31,7 @@ def connectionMade( self ): self.gotMagic = False self.isIRC = False self.packet = HLPacket() - self.buffer = "" + self.buffer = b'' self.idleTimer = reactor.callLater( IDLE_TIME , self.idleCheck ) def connectionLost( self , reason ): @@ -40,6 +42,10 @@ def connectionLost( self , reason ): def dataReceived( self , data ): """ Called when the socket receives data. """ + # encoding = "utf-8" + # data = data.encode(encoding) + # data = data.decode('utf-8') + self.buffer += data self.parseBuffer() @@ -144,9 +150,9 @@ def handlePacket( self ): self.factory.dispatchPacket( self.connID , self.packet ) else: if ( self.packet.isIRC == 0 ) and ( self.packet.type != 0 ) and ( self.packet.type != 130 ): - print "got packet before login:" - print self.packet - except HLException , ex: + print("got packet before login:") + print(self.packet) + except HLException as ex: # Unhandled packets and task errors will be caught here. if self.isIRC: if self.packet.irctrap: @@ -194,49 +200,49 @@ def __init__( self ): self.linker = HLServerLinker( self ) self._initLog() reactor.listenTCP( self.port , self ) - # Update all trackers periodically - recurrentTask = task.LoopingCall(self.updateTrackers) - recurrentTask.start(TRACKER_REFRESH_PERIOD) - #recurrentTask.addErrback(updateTrackersFailed) + # Update all trackers periodically + recurrentTask = task.LoopingCall(self.updateTrackers) + recurrentTask.start(TRACKER_REFRESH_PERIOD) + #recurrentTask.addErrback(updateTrackersFailed) - def updateTrackers(self): - """Updates the register trackers, if any, with the name - and description of server and the current user count. - """ - for hostname, port in TRACKER_LIST: - reactor.listenUDP(0, HLTrackerClient(self, hostname, port)) + def updateTrackers(self): + """Updates the register trackers, if any, with the name + and description of server and the current user count. + """ + for hostname, port in TRACKER_LIST: + reactor.listenUDP(0, HLTrackerClient(self, hostname, port)) - def updateTrackersFailed(self, reason): - """Errback invoked when the task to update the trackers - fails for whatever reason. - """ - print "Failed to update tracker: reason" + def updateTrackersFailed(self, reason): + """Errback invoked when the task to update the trackers + fails for whatever reason. + """ + print("Failed to update tracker: reason") def _initLog( self ): self.log.setLevel( logging.DEBUG ) if ENABLE_FILE_LOG: # the formatter is just for the file logger fmt = logging.Formatter( '%(asctime)s\t%(message)s' ) - logSizeBytes = LOG_MAX_SIZE_MBYTES * 1024 * 1024 - try: - fileHandler = RotatingFileHandler( LOG_FILE, - maxBytes=logSizeBytes, backupCount=MAX_LOG_FILES ) - except IOError: - # Logfile directory most likely doesn't exist, attempt - # to create it and try again. - import os - os.makedirs(os.path.dirname(LOG_FILE)) - fileHandler = logging.FileHandler( LOG_FILE, - maxBytes=logSizeBytes, backupCount=MAX_LOG_FILES ) - # If opening the file handle fails at this point, raise - fileHandler.setFormatter( fmt ) - # make sure everything goes to the file log - fileHandler.setLevel( logging.DEBUG ) - self.log.addHandler( fileHandler ) - dbHandler = HLDatabaseLogger( self.database ) - # we only want server events and errors in the database log - dbHandler.setLevel( logging.INFO ) - self.log.addHandler( dbHandler ) + logSizeBytes = LOG_MAX_SIZE_MBYTES * 1024 * 1024 + try: + fileHandler = RotatingFileHandler( LOG_FILE, + maxBytes=logSizeBytes, backupCount=MAX_LOG_FILES ) + except IOError: + # Logfile directory most likely doesn't exist, attempt + # to create it and try again. + import os + os.makedirs(os.path.dirname(LOG_FILE)) + fileHandler = logging.FileHandler( LOG_FILE, + maxBytes=logSizeBytes, backupCount=MAX_LOG_FILES ) + # If opening the file handle fails at this point, raise + fileHandler.setFormatter( fmt ) + # make sure everything goes to the file log + fileHandler.setLevel( logging.DEBUG ) + self.log.addHandler( fileHandler ) + dbHandler = HLDatabaseLogger( self.database ) + # we only want server events and errors in the database log + dbHandler.setLevel( logging.INFO ) + self.log.addHandler( dbHandler ) def linkToServer( self, addr ): ( ip , port ) = addr.split( ':' ) @@ -268,7 +274,7 @@ def addRemoteUser( self, remoteUser, sendChange = True ): return user.uid def removeRemoteUser( self, uid ): - if self.clients.has_key( uid ): + if uid in self.clients: del( self.clients[uid] ) def handleUserLogin( self, user ): @@ -278,18 +284,18 @@ def handleUserLogin( self, user ): def addTempBan( self , addr , reason = "no reason" ): """ Adds a temporary ban for addr that will expire in BAN_TIME seconds. """ - if not self.tempBans.has_key( addr ): + if addr not in self.tempBans: self.tempBans[addr] = reason reactor.callLater( BAN_TIME , self.removeTempBan , addr ) def removeTempBan( self , addr ): """ Removes a temporary ban for addr, if it exists. """ - if self.tempBans.has_key( addr ): + if addr in self.tempBans: del self.tempBans[addr] def checkForBan( self , addr ): """ Returns the reason given for a ban, if it exists. Otherwise returns None. """ - if self.tempBans.has_key( addr ): + if addr in self.tempBans: return self.tempBans[addr] return self.database.checkBanlist( addr ) @@ -310,13 +316,13 @@ def registerPacketHandler( self , handler ): def disconnectUser( self , uid ): """ Actively disconnect the specified user. """ - if self.clients.has_key( uid ): + if uid in self.clients: ( conn , user ) = self.clients[uid] conn.transport.loseConnection() def removeConnection( self , connID ): """ Called from HLConnection when a connection dies. """ - if self.clients.has_key( connID ): + if connID in self.clients: ( conn , user ) = self.clients[connID] if user.isLoggedIn(): for handler in self.handlers: @@ -327,7 +333,7 @@ def removeConnection( self , connID ): def getUser( self , uid ): """ Gets the HLUser object for the specified uid. """ - if self.clients.has_key( uid ): + if uid in self.clients: ( conn , user ) = self.clients[uid] return user return None @@ -339,7 +345,7 @@ def getUserCount(self): def getOrderedUserlist( self ): """ Returns a list of HLUsers, ordered by uid. """ - keys = self.clients.keys() + keys = list(self.clients.keys()) keys.sort() userlist = [] for uid in keys: @@ -357,18 +363,18 @@ def createChat( self ): def removeChat( self , id ): """ Remove the specified private chat. """ - if self.chats.has_key( id ): + if id in self.chats: del self.chats[id] def getChat( self , id ): """ Gets the HLChat object for the specified chat ID. """ - if self.chats.has_key( id ): + if id in self.chats: return self.chats[id] return None def sendPacket( self , uid , packet ): """ Sends the specified packet to the specified user. """ - if self.clients.has_key( uid ): + if uid in self.clients: ( conn , user ) = self.clients[uid] packet.isIRC = conn.isIRC if user.local: @@ -391,17 +397,17 @@ def broadcastPacket( self , packet , priv = 0 ): def dispatchPacket( self , connID , packet ): """ Called from HLConnection to dispatch a packet to all registered packet handlers. """ - if self.clients.has_key( connID ): + if connID in self.clients: handled = False ( conn , user ) = self.clients[connID] for handler in self.handlers: handled |= handler.handlePacket( self , user , packet ) if handled == False: - raise HLException , "unknown packet type" + raise HLException("unknown packet type") #def returnClients( self ): - # """ For irc :p """ - # return self.clients + # """ For irc :p """ + # return self.clients # DELETEME i think its dead code!! def logEvent( self , typeInt , msg , user = None ): @@ -413,11 +419,11 @@ def logEvent( self , typeInt , msg , user = None ): login = user.account.login nickname = user.nick ip = user.ip - typeStr = str(typeInt) - try: - typeStr = LOG_TYPE_STR_MAP[typeInt] - except KeyError: - pass + typeStr = str(typeInt) + try: + typeStr = LOG_TYPE_STR_MAP[typeInt] + except KeyError: + pass # format as \t\t\t\t # this is the "message" for the FileLogger fmt = "%s\t%s\t%s\t%s\t%s" diff --git a/server/HLServerLinkage.py b/server/HLServerLinkage.py index 4e70c7a..4749e4d 100644 --- a/server/HLServerLinkage.py +++ b/server/HLServerLinkage.py @@ -1,3 +1,5 @@ +from __future__ import absolute_import +from __future__ import print_function from twisted.internet import reactor from twisted.internet.protocol import Protocol , Factory , ClientCreator from shared.HLProtocol import * @@ -23,7 +25,7 @@ def connectionMade( self ): self.factory.linkEstablished( self ) def connectionLost( self, reason ): - print "link connection lost" + print("link connection lost") def dataReceived( self, data ): self.buffer += data @@ -44,11 +46,11 @@ def fixPacket( self, packet ): for obj in packet.objs: if obj.type == DATA_UID: remoteUID = unpack( "!H" , obj.data )[0] - if self.remoteToLocal.has_key( remoteUID ): + if remoteUID in self.remoteToLocal: localUID = self.remoteToLocal[remoteUID] obj.data = pack( "!H" , localUID ) else: - print "ERROR: unable to map remote UID [%d]" % remoteUID + print("ERROR: unable to map remote UID [%d]" % remoteUID) def handleLinkPacket( self, packet ): if packet.type == HTLS_HDR_LINK_LOGIN: @@ -71,7 +73,7 @@ def handleLinkPacket( self, packet ): # a user left on the remote server user = HLUser() if user.parse( packet.getBinary(DATA_USER) ) > 0: - if self.remoteToLocal.has_key( user.uid ): + if user.uid in self.remoteToLocal: localUID = self.remoteToLocal[user.uid] self.factory.server.removeRemoteUser( localUID ) elif packet.type == HTLS_HDR_LINK_PACKET: @@ -82,17 +84,17 @@ def handleLinkPacket( self, packet ): self.fixPacket( localPacket ) self.factory.server.sendPacket( localUID, localPacket ) else: - print "ERROR: unknown link packet type" + print("ERROR: unknown link packet type") def forwardPacketData( self, data, uid ): - if self.localToRemote.has_key( uid ): + if uid in self.localToRemote: remoteUID = self.localToRemote[uid] fwdPacket = HLPacket( HTLS_HDR_LINK_PACKET ) fwdPacket.addNumber( DATA_UID, remoteUID ) fwdPacket.addBinary( DATA_PACKET, data ) self.transport.write( fwdPacket.flatten() ) else: - print "ERROR: unable to forward packet to local UID %d" % uid + print("ERROR: unable to forward packet to local UID %d" % uid) class HLServerLinker( Factory ): @@ -102,15 +104,15 @@ def __init__( self, server ): reactor.listenTCP( LINK_PORT, self ) def buildProtocol( self, addr ): - print "got link connection from %s" % addr.host + print("got link connection from %s" % addr.host) return LinkConnection( self ) def linkEstablished( self, link ): - print "added link" + print("added link") self.links.append( link ) def link( self, addr, port ): - print "linking to %s:%d" % (addr,port) + print("linking to %s:%d" % (addr,port)) c = ClientCreator( reactor, LinkConnection, self ) c.connectTCP( addr, port ) diff --git a/server/HLTracker.py b/server/HLTracker.py index 063b102..293809d 100644 --- a/server/HLTracker.py +++ b/server/HLTracker.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from twisted.internet import reactor from twisted.internet.protocol import DatagramProtocol from config import * diff --git a/server/HLWebServices.py b/server/HLWebServices.py index 83aef44..78b9753 100644 --- a/server/HLWebServices.py +++ b/server/HLWebServices.py @@ -1,8 +1,9 @@ +from __future__ import absolute_import from twisted.web import xmlrpc , server from twisted.internet import reactor from shared.HLTypes import * from config import * -from xmlrpclib import Binary +from six.moves.xmlrpc_client import Binary import time class HLWebServices( xmlrpc.XMLRPC ): @@ -16,7 +17,7 @@ def __init__( self , hlserver ): def xmlrpc_getServerUptime( self ): """ Returns the server uptime in seconds. """ - return long( time.time() - self.server.startTime ) + return int( time.time() - self.server.startTime ) def xmlrpc_getUserlist( self ): """ Returns a list of online users. Each entry is a dictionary containing user information. """ diff --git a/server/database/MySQLDatabase.py b/server/database/MySQLDatabase.py index 9aa956c..d4ed8c8 100644 --- a/server/database/MySQLDatabase.py +++ b/server/database/MySQLDatabase.py @@ -1,7 +1,10 @@ +from __future__ import absolute_import +from __future__ import print_function from server.HLDatabase import HLDatabase from shared.HLTypes import * from config import * import MySQLdb +from six.moves import range class MySQLDatabase (HLDatabase): """ MySQL-based implementation of HLDatabase. """ @@ -21,7 +24,7 @@ def loadAccount( self , login ): def saveAccount( self , acct ): cur = self.db.cursor() - if acct.id > 0L: + if acct.id > 0: cur.execute( "UPDATE accounts SET password = %s , name = %s , privs = %s , fileRoot = %s WHERE id = %s" , \ ( acct.password , acct.name , acct.privs , acct.fileRoot , acct.id ) ) else: @@ -59,7 +62,7 @@ def loadNewsPosts( self , limit = 0 ): def saveNewsPost( self , post ): cur = self.db.cursor() - if post.id > 0L: + if post.id > 0: cur.execute( "UPDATE news SET nick = %s , login = %s , post = %s , date = %s WHERE id = %s" , ( post.nick , post.login , post.post , post.date , post.id ) ) else: cur.execute( "INSERT INTO news ( nick , login , post , date ) VALUES ( %s , %s , %s , %s )" , ( post.nick , post.login , post.post , post.date ) ) @@ -72,7 +75,7 @@ def checkBanlist( self , addr ): cur = self.db.cursor() num = cur.execute( "SELECT reason FROM banlist WHERE address = %s" , addr ) except: - print "mysql connection lost. check that mysql is up. reconnecting now." + print("mysql connection lost. check that mysql is up. reconnecting now.") cur = self.db.cursor() self.db = MySQLdb.connect( host = DB_HOST , user = DB_USER , passwd = DB_PASS , db = DB_NAME ) num = cur.execute( "SELECT reason FROM banlist WHERE address = %s" , addr ) @@ -87,7 +90,7 @@ def logEvent( self , type , event , login = "" , nick = "" , ip = "" ): cur.execute( "INSERT INTO log ( type , login , nick , ip , entry , date ) VALUES ( %s , %s , %s , %s , %s , NOW() )" , ( type , login , nick , ip , event ) ) cur.close() except: - print "mysql connection lost. check that mysql is up. reconnecting now." + print("mysql connection lost. check that mysql is up. reconnecting now.") cur = self.db.cursor() self.db = MySQLdb.connect( host = DB_HOST , user = DB_USER , passwd = DB_PASS , db = DB_NAME ) cur.execute( "INSERT INTO log ( type , login , nick , ip , entry , date ) VALUES ( %s , %s , %s , %s , %s , NOW() )" , ( type , login , nick , ip , event ) ) diff --git a/server/database/TextDatabase.py b/server/database/TextDatabase.py index ac2c39a..026e987 100644 --- a/server/database/TextDatabase.py +++ b/server/database/TextDatabase.py @@ -1,9 +1,11 @@ +from __future__ import absolute_import from server.HLDatabase import HLDatabase from shared.HLTypes import * from config import * from datetime import datetime from os import mkdir , listdir , sep import re +from six.moves import range class TextDatabase (HLDatabase): """ Text-based implementation of HLDatabase. """ @@ -29,7 +31,7 @@ def loadAccount( self , login ): """ Creates a new HLAccount object and loads information for the specified login into it. Returns None if unsuccessful. """ acct = None try: - fp = file( self.accountsFile , "r" ) + fp = open( self.accountsFile , "r" ) except IOError: return acct for l in fp.readlines(): @@ -37,7 +39,7 @@ def loadAccount( self , login ): acct = HLAccount( login ) try: ( acct.id , acct.password , acct.name , acct.privs , acct.fileRoot ) = l.rstrip( "\n" ).split( "\t" )[1:6] - ( acct.id , acct.privs ) = ( int( acct.id ) , long( acct.privs ) ) + ( acct.id , acct.privs ) = ( int( acct.id ) , int( acct.privs ) ) break except ValueError: return None @@ -47,12 +49,12 @@ def loadAccount( self , login ): def saveAccount( self , acct ): """ Saves the specified HLAccount object to the database. If the HLAccount has a non-zero ID, the information is updated, otherwise a new account is inserted. """ try: - fp = file( self.accountsFile , "r" ) + fp = open( self.accountsFile , "r" ) lines = fp.readlines() fp.close() except IOError: lines = [] - if acct.id > 0L: + if acct.id > 0: # Finds the account lines that corresponds to the provided ID and updates the account's info. found = False for l in range( len( lines ) ): @@ -68,7 +70,7 @@ def saveAccount( self , acct ): return False if not found: return False - fp = file( self.accountsFile , "w" ) + fp = open( self.accountsFile , "w" ) fp.write( "".join( lines ) ) fp.close() else: @@ -87,7 +89,7 @@ def saveAccount( self , acct ): if uid > maxuid: maxuid = uid lines.append( "%s\t%s\t%s\t%s\t%s\t%s\t0\t0\t0000-00-00 00:00:00\n" % ( acct.login , int( maxuid ) + 1 , acct.password , acct.name , acct.privs , acct.fileRoot ) ) - fp = file( self.accountsFile , "w" ) + fp = open( self.accountsFile , "w" ) fp.write( "".join( lines ) ) fp.close() return True @@ -95,7 +97,7 @@ def saveAccount( self , acct ): def deleteAccount( self , login ): """ Deletes an account with the specified login. """ try: - fp = file( self.accountsFile , "r" ) + fp = open( self.accountsFile , "r" ) except IOError: return False ( found , lines ) = ( False , fp.readlines() ) @@ -107,14 +109,14 @@ def deleteAccount( self , login ): break if not found: return False - fp = file( self.accountsFile , "w" ) + fp = open( self.accountsFile , "w" ) fp.write( "".join( lines ) ) fp.close() return True def updateAccountStats( self , login , downloaded , uploaded , setDate = False ): try: - fp = file( self.accountsFile , "r" ) + fp = open( self.accountsFile , "r" ) except IOError: return False ( found , lines ) = ( False , fp.readlines() ) @@ -128,15 +130,15 @@ def updateAccountStats( self , login , downloaded , uploaded , setDate = False ) return False else: if ( downloaded > 0 ) or ( uploaded > 0 ): - acctBytesDown = long( acctBytesDown ) + downloaded - acctBytesUp = long( acctBytesUp ) + uploaded + acctBytesDown = int( acctBytesDown ) + downloaded + acctBytesUp = int( acctBytesUp ) + uploaded if setDate: acctLastLogin = datetime.now().strftime( "%Y-%m-%d %H:%M:%S" ) lines[l] = "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n" % ( acctLogin , acctID , acctPass , acctName , acctPrivs , acctFileRoot , acctBytesDown , acctBytesUp , acctLastLogin ) break if not found: return False - fp = file( self.accountsFile , "w" ) + fp = open( self.accountsFile , "w" ) fp.write( "".join( lines ) ) fp.close() return True @@ -152,7 +154,7 @@ def loadNewsPosts( self , limit = 0 ): files = files[len( files ) - limit:len( files )] for f in files: post = HLNewsPost() - fp = file( "%s%s%s" % ( self.newsDir , sep , f ) , "r" ) + fp = open( "%s%s%s" % ( self.newsDir , sep , f ) , "r" ) ( post.id , post.date , post.login , post.nick ) = fp.readline().rstrip( "\n" ).split( "\t" ) post.post = "".join( fp.readlines() ) fp.close() @@ -168,10 +170,10 @@ def saveNewsPost( self , post ): maxid = int( self.regexNewsID.match( listdir( "%s%s" % ( self.newsDir , sep ) )[-1] ).group() ) except: maxid = 0 - if post.id > 0L: + if post.id > 0: maxid = post.id - 1 else: - fp = file( "%s%s%s.txt" % ( self.newsDir , sep , maxid + 1 ) , "w" ) + fp = open( "%s%s%s.txt" % ( self.newsDir , sep , maxid + 1 ) , "w" ) fp.write( "%s\t%s\t%s\t%s\n%s" % ( str( maxid + 1 ) , post.date , post.login , post.nick , post.post ) ) fp.close() return True @@ -179,7 +181,7 @@ def saveNewsPost( self , post ): def checkBanlist( self , addr ): reason = None try: - fp = file( self.banlistFile , "r" ) + fp = open( self.banlistFile , "r" ) except: return reason for l in fp.readlines(): @@ -199,7 +201,7 @@ def logEvent( self , type , event , login = "" , nick = "" , ip = "" ): currentl no DEBUG messages available anyways, so it's redundant. """ return - fp = file( self.logFile , "a" ) + fp = open( self.logFile , "a" ) eventType = "???" try: eventType = self.logTypes[type] diff --git a/server/handlers/AcctHandler.py b/server/handlers/AcctHandler.py index 07e5948..5917b0d 100644 --- a/server/handlers/AcctHandler.py +++ b/server/handlers/AcctHandler.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from shared.HLProtocol import * from shared.HLTypes import * from config import * @@ -20,9 +21,9 @@ def handleAccountRead( self , server , user , packet ): acct = server.database.loadAccount( login ) if not user.hasPriv( PRIV_READ_USERS ): - raise HLException , "You cannot read accounts." + raise HLException("You cannot read accounts.") if acct == None: - raise HLException , "Error loading account." + raise HLException("Error loading account.") reply = HLPacket( HTLS_HDR_TASK , packet.seq ) reply.addString( DATA_LOGIN , HLEncode( acct.login ) ) @@ -39,9 +40,9 @@ def handleAccountModify( self , server , user , packet ): acct = server.database.loadAccount( login ) if not user.hasPriv( PRIV_MODIFY_USERS ): - raise HLException , "You cannot modify accounts." + raise HLException("You cannot modify accounts.") if acct == None: - raise HLException , "Invalid account." + raise HLException("Invalid account.") acct.name = name acct.privs = privs @@ -59,9 +60,9 @@ def handleAccountCreate( self , server , user , packet ): privs = packet.getNumber( DATA_PRIVS , 0 ) if not user.hasPriv( PRIV_CREATE_USERS ): - raise HLException , "You cannot create accounts." + raise HLException("You cannot create accounts.") if server.database.loadAccount( login ) != None: - raise HLException , "Login already exists." + raise HLException("Login already exists.") acct = HLAccount( login ) acct.password = md5( passwd ).hexdigest() @@ -75,8 +76,8 @@ def handleAccountCreate( self , server , user , packet ): def handleAccountDelete( self , server , user , packet ): login = HLEncode( packet.getString( DATA_LOGIN , "" ) ) if not user.hasPriv( PRIV_DELETE_USERS ): - raise HLException , "You cannot delete accounts." + raise HLException("You cannot delete accounts.") if server.database.deleteAccount( login ) < 1: - raise HLException , "Error deleting account." + raise HLException("Error deleting account.") server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) server.logEvent( LOG_TYPE_ACCOUNT , "Deleted account %s." % login , user ) diff --git a/server/handlers/ChatHandler.py b/server/handlers/ChatHandler.py index 47f58e7..bcd6efa 100644 --- a/server/handlers/ChatHandler.py +++ b/server/handlers/ChatHandler.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from shared.HLProtocol import * from shared.HLTypes import * from shared.HLUtils import * @@ -37,7 +38,7 @@ def logChat( chat , user ): timestamp = time.localtime() fname = "%04d-%02d-%02d.txt" % ( timestamp[0] , timestamp[1] , timestamp[2] ) path = os.path.join( LOG_DIR , fname ) - out = file( path , "a" ) + out = open( path , "a" ) line = "%02d:%02d:%02d\t%s\t%s\t%s\n" % ( timestamp[3] , timestamp[4] , timestamp[5] , user.account.login , user.nick , chat ) out.write( line ) out.close() @@ -112,7 +113,7 @@ def handleChatCreate( self , server , user , packet ): who = server.getUser( uid ) if not user.hasPriv( PRIV_CREATE_CHATS ): - raise HLException , "You cannot create private chats." + raise HLException("You cannot create private chats.") # First, create the new chat, adding the user. chat = server.createChat() @@ -125,7 +126,7 @@ def handleChatCreate( self , server , user , packet ): reply.addString( DATA_NICK , user.nick ) reply.addNumber( DATA_ICON , user.icon ) reply.addNumber( DATA_STATUS , user.status ) - if user.color >= 0L: + if user.color >= 0: reply.addInt32( DATA_COLOR , user.color ) server.sendPacket( user.uid , reply ) @@ -147,9 +148,9 @@ def handleChatInvite( self , server , user , packet ): who = server.getUser( uid ) if who == None: - raise HLException , "Invalid user." + raise HLException("Invalid user.") if chat == None: - raise HLException , "Invalid chat." + raise HLException("Invalid chat.") if uid == user.uid: # Ignore self invitations. return @@ -157,7 +158,7 @@ def handleChatInvite( self , server , user , packet ): # Ignore all invitations after the first. return if not chat.hasUser( user ): - raise HLException , "You are not in this chat." + raise HLException("You are not in this chat.") if chat.hasUser( who ): # The specified user is already in the chat. return @@ -188,9 +189,9 @@ def handleChatJoin( self , server , user , packet ): chat = server.getChat( ref ) if chat == None: - raise HLException , "Invalid chat." + raise HLException("Invalid chat.") if not chat.hasInvite( user ): - raise HLException , "You were not invited to this chat." + raise HLException("You were not invited to this chat.") # Send a join packet to everyone in the chat. join = HLPacket( HTLS_HDR_CHAT_USER_CHANGE ) @@ -199,7 +200,7 @@ def handleChatJoin( self , server , user , packet ): join.addString( DATA_NICK , user.nick ) join.addNumber( DATA_ICON , user.icon ) join.addNumber( DATA_STATUS , user.status ) - if user.color >= 0L: + if user.color >= 0: join.addInt32( DATA_COLOR , user.color ) for u in chat.users: server.sendPacket( u.uid , join ) diff --git a/server/handlers/FileHandler.py b/server/handlers/FileHandler.py index 97ef6ef..5520634 100644 --- a/server/handlers/FileHandler.py +++ b/server/handlers/FileHandler.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from shared.HLProtocol import * from shared.HLTypes import * from config import * @@ -67,15 +68,15 @@ def handleFileList( self , server , user , packet ): path = buildPath( user.account.fileRoot , dir ) if not os.path.exists( path ): - raise HLException , "The specified directory does not exist." + raise HLException("The specified directory does not exist.") if not os.path.isdir( path ): - raise HLException , "The specified path is not a directory." + raise HLException("The specified path is not a directory.") if ( not user.hasPriv( PRIV_VIEW_DROPBOXES ) ) and ( path.upper().find( "DROP BOX" ) >= 0 ): - raise HLException , "You are not allowed to view drop boxes." + raise HLException("You are not allowed to view drop boxes.") fn = path.split("/")[-1] # gets folder name kang #beware of non exact matches!! FIXME if (path.upper().find("DROP BOX") >= 0) and (fn.upper()[0:4] != "DROP") and (fn.upper().find(user.account.login.upper()) < 0): - raise HLException, "Sorry, this is not your dropbox. You are not allowed to view it" + raise HLException("Sorry, this is not your dropbox. You are not allowed to view it") reply = HLPacket( HTLS_HDR_TASK , packet.seq ) files = os.listdir( path ) @@ -101,9 +102,9 @@ def handleFileDownload( self , server , user , packet ): path = buildPath( user.account.fileRoot , dir , name ) if not user.hasPriv( PRIV_DOWNLOAD_FILES ): - raise HLException , "You are not allowed to download files." + raise HLException("You are not allowed to download files.") if not os.path.exists( path ): - raise HLException , "Specified file does not exist." + raise HLException("Specified file does not exist.") offset = resume.forkOffset( HLCharConst( "DATA" ) ) xfer = server.fileserver.addDownload( user.uid , path , offset ) @@ -121,21 +122,21 @@ def handleFileUpload( self , server , user , packet ): options = packet.getNumber( DATA_XFEROPTIONS , 0 ) if not user.hasPriv( PRIV_UPLOAD_FILES ): - raise HLException , "You are not allowed to upload files." + raise HLException("You are not allowed to upload files.") path = buildPath( user.account.fileRoot , dir , name ) if os.path.exists( path ): # If this path exists, theres already a complete file. - raise HLException , "File already exists." + raise HLException("File already exists.") if ( not user.hasPriv( PRIV_UPLOAD_ANYWHERE ) ) and ( path.upper().find( "UPLOAD" ) < 0 ): - raise HLException , "You must upload to an upload directory." + raise HLException("You must upload to an upload directory.") # Make sure we have enough disk space to accept the file. upDir = buildPath( user.account.fileRoot , dir ) info = os.statvfs( upDir ) free = info[F_BAVAIL] * info[F_FRSIZE] if size > free: - raise HLException , "Insufficient disk space." + raise HLException("Insufficient disk space.") # All uploads in progress should have this extension. path += ".hpf" @@ -157,9 +158,9 @@ def handleFileDelete( self , server , user , packet ): path = buildPath( user.account.fileRoot , dir , name ) if not user.hasPriv( PRIV_DELETE_FILES ): - raise HLException , "You are not allowed to delete files." + raise HLException("You are not allowed to delete files.") if not os.path.exists( path ): - raise HLException , "Specified file does not exist." + raise HLException("Specified file does not exist.") if os.path.isdir( path ): # First, recursively delete everything inside the directory. @@ -181,11 +182,11 @@ def handleFolderCreate( self , server , user , packet ): path = buildPath( user.account.fileRoot , dir , name ) if not user.hasPriv( PRIV_CREATE_FOLDERS ): - raise HLException , "You are not allowed to create folders." + raise HLException("You are not allowed to create folders.") if os.path.exists( path ): - raise HLException , "Specified directory/file already exists." + raise HLException("Specified directory/file already exists.") - os.mkdir( path , 0755 ) + os.mkdir( path , 0o755 ) server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) def handleFileMove( self , server , user , packet ): @@ -197,11 +198,11 @@ def handleFileMove( self , server , user , packet ): newPath = buildPath( user.account.fileRoot , newDir , name ) if not user.hasPriv( PRIV_MOVE_FILES ): - raise HLException , "You are not allowed to move files." + raise HLException("You are not allowed to move files.") if not os.path.exists( oldPath ): - raise HLException , "Invalid file or directory." + raise HLException("Invalid file or directory.") if os.path.exists( newPath ): - raise HLException , "The specified file already exists." + raise HLException("The specified file already exists.") os.rename( oldPath , newPath ) server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) @@ -212,7 +213,7 @@ def handleFileGetInfo( self , server , user , packet ): path = buildPath( user.account.fileRoot , dir , name ) if not os.path.exists( path ): - raise HLException , "No such file or directory." + raise HLException("No such file or directory.") info = HLPacket( HTLS_HDR_TASK , packet.seq ) info.addString( DATA_FILENAME , name ) @@ -227,15 +228,15 @@ def handleFileSetInfo( self , server , user , packet ): newName = packet.getString( DATA_NEWFILE , oldName ) if ( oldName != newName ) and ( not user.hasPriv( PRIV_RENAME_FILES ) ): - raise HLException , "You cannot rename files." + raise HLException("You cannot rename files.") oldPath = buildPath( user.account.fileRoot , dir , oldName ) newPath = buildPath( user.account.fileRoot , dir , newName ) if not os.path.exists( oldPath ): - raise HLException , "Invalid file or directory." + raise HLException("Invalid file or directory.") if os.path.exists( newPath ): - raise HLException , "The specified file already exists." + raise HLException("The specified file already exists.") os.rename( oldPath , newPath ) server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) diff --git a/server/handlers/IconHandler.py b/server/handlers/IconHandler.py index 9e4abb6..52d0fb7 100644 --- a/server/handlers/IconHandler.py +++ b/server/handlers/IconHandler.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from shared.HLProtocol import * from shared.HLTypes import * from struct import pack @@ -25,7 +26,7 @@ def handleIconSet( self , server , user , packet ): user.gif = packet.getBinary( DATA_GIFICON , "" ) if len( user.gif ) > MAX_GIF_SIZE: user.gif = "" - raise HLException , "GIF icon too large." + raise HLException("GIF icon too large.") server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) change = HLPacket( HTLS_HDR_ICON_CHANGE ) change.addNumber( DATA_UID , user.uid ) @@ -40,4 +41,4 @@ def handleIconGet( self , server , user , packet ): icon.addBinary( DATA_GIFICON , info.gif ) server.sendPacket( user.uid , icon ) else: - raise HLException , "Invalid user." + raise HLException("Invalid user.") diff --git a/server/handlers/NewsHandler.py b/server/handlers/NewsHandler.py index 219207a..ecebe71 100644 --- a/server/handlers/NewsHandler.py +++ b/server/handlers/NewsHandler.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from shared.HLProtocol import * from shared.HLTypes import * from config import * @@ -28,7 +29,7 @@ def handleNewsGet( self , server , user , packet ): news.addString( DATA_STRING , str ) server.sendPacket( user.uid , news ) else: - raise HLException , "You are not allowed to read the news." + raise HLException("You are not allowed to read the news.") def handleNewsPost( self , server , user , packet ): str = packet.getString( DATA_STRING , "" ) @@ -41,4 +42,4 @@ def handleNewsPost( self , server , user , packet ): server.broadcastPacket( notify , PRIV_READ_NEWS ) server.sendPacket( user.uid , HLPacket( HTLS_HDR_TASK , packet.seq ) ) else: - raise HLException , "You are not allowed to post news." + raise HLException("You are not allowed to post news.") diff --git a/server/handlers/UserHandler.py b/server/handlers/UserHandler.py index 2c8100e..8dad666 100644 --- a/server/handlers/UserHandler.py +++ b/server/handlers/UserHandler.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from shared.HLProtocol import * from shared.HLUtils import * from shared.HLTypes import * @@ -28,22 +29,22 @@ def handleUserDisconnected( self , server , user ): def handleLogin( self , server , user , packet ): if user.isLoggedIn(): - raise HLException , ( "You are already logged in." , False ) + raise HLException( "You are already logged in." , False) login = HLEncode( packet.getString( DATA_LOGIN , HLEncode( "guest" ) ) ) password = HLEncode( packet.getString( DATA_PASSWORD , "" ) ) reason = server.checkForBan( user.ip ) if reason != None: - raise HLException , ( "You are banned: %s" % reason , True ) + raise HLException( "You are banned: %s" % reason , True) user.account = server.database.loadAccount( login ) if user.account == None: - raise HLException , ( "Login is incorrect." , True ) + raise HLException( "Login is incorrect." , True) if user.account.password != md5( password ).hexdigest(): user.nick = packet.getString( DATA_NICK , "unnamed" ) server.logEvent( LOG_TYPE_LOGIN , "Login failure" , user ) - raise HLException , ( "Password is incorrect." , True ) + raise HLException( "Password is incorrect." , True) if user.account.fileRoot == "": user.account.fileRoot = FILE_ROOT @@ -108,7 +109,7 @@ def handleUserChange( self , server , user , packet ): change.addNumber( DATA_ICON , user.icon ) change.addNumber( DATA_STATUS , user.status ) change.addString ( DATA_IRC_OLD_NICK , oldnick ) - if user.color >= 0L: + if user.color >= 0: change.addInt32( DATA_COLOR , user.color ) server.broadcastPacket( change ) @@ -124,12 +125,12 @@ def handleUserInfo( self , server , user , packet ): u = server.getUser( uid ) if not user.hasPriv( PRIV_USER_INFO ) and ( uid != user.uid ): - raise HLException , "You cannot view user information." + raise HLException("You cannot view user information.") if u == None: - raise HLException , "Invalid user." + raise HLException("Invalid user.") # Format the user's idle time. - secs = long( time.time() - u.lastPacketTime ) + secs = int( time.time() - u.lastPacketTime ) days = secs / 86400 secs -= ( days * 86400 ) hours = secs / 3600 @@ -167,9 +168,9 @@ def handleMessage( self , server , user , packet ): str = packet.getString( DATA_STRING , "" ) if not user.hasPriv( PRIV_SEND_MESSAGES ): - raise HLException , "You are not allowed to send messages." + raise HLException("You are not allowed to send messages.") if server.getUser( uid ) == None: - raise HLException , "Invalid user." + raise HLException("Invalid user.") msg = HLPacket( HTLS_HDR_MSG ) msg.addNumber( DATA_UID , user.uid ) @@ -184,11 +185,11 @@ def handleUserKick( self , server , user , packet ): who = server.getUser( uid ) if not user.hasPriv( PRIV_KICK_USERS ): - raise HLException , "You are not allowed to disconnect users." + raise HLException("You are not allowed to disconnect users.") if who == None: - raise HLException , "Invalid user." + raise HLException("Invalid user.") if who.account.login != user.account.login and who.hasPriv( PRIV_KICK_PROTECT ): - raise HLException , "%s cannot be disconnected." % who.nick + raise HLException("%s cannot be disconnected." % who.nick) action = "Kicked" if ban > 0: @@ -202,7 +203,7 @@ def handleUserKick( self , server , user , packet ): def handleBroadcast( self , server , user , packet ): str = packet.getString( DATA_STRING , "" ) if not user.hasPriv( PRIV_BROADCAST ): - raise HLException , "You cannot broadcast messages." + raise HLException("You cannot broadcast messages.") broadcast = HLPacket( HTLS_HDR_BROADCAST ) broadcast.addString( DATA_STRING , str ) server.broadcastPacket( broadcast ) diff --git a/server/handlers/commands/0wn.py b/server/handlers/commands/0wn.py index af17c64..23ae7c7 100644 --- a/server/handlers/commands/0wn.py +++ b/server/handlers/commands/0wn.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from shared.HLProtocol import * def handle( server , user , arg , ref): diff --git a/server/handlers/commands/away.py b/server/handlers/commands/away.py index 6601e8d..0c7749f 100644 --- a/server/handlers/commands/away.py +++ b/server/handlers/commands/away.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from shared.HLProtocol import * def handle( server , user , args , ref ): diff --git a/server/handlers/commands/broadcast.py b/server/handlers/commands/broadcast.py index 9c40fbd..9889d89 100644 --- a/server/handlers/commands/broadcast.py +++ b/server/handlers/commands/broadcast.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from shared.HLProtocol import * def handle( server , user , arg , ref ): diff --git a/server/handlers/commands/color.py b/server/handlers/commands/color.py index e6aa7c5..8ff4c93 100644 --- a/server/handlers/commands/color.py +++ b/server/handlers/commands/color.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from shared.HLProtocol import * def handle( server , user , arg , ref ): if len( arg ) > 0: diff --git a/server/handlers/commands/find.py b/server/handlers/commands/find.py index 09d2d58..dc57e27 100644 --- a/server/handlers/commands/find.py +++ b/server/handlers/commands/find.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from shared.HLProtocol import * import os diff --git a/server/handlers/commands/me.py b/server/handlers/commands/me.py index 34f43ff..4de8c0c 100644 --- a/server/handlers/commands/me.py +++ b/server/handlers/commands/me.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from shared.HLProtocol import * def handle( server , user , args , ref ): diff --git a/server/handlers/commands/news.py b/server/handlers/commands/news.py index c1783c8..4ee7975 100644 --- a/server/handlers/commands/news.py +++ b/server/handlers/commands/news.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from shared.HLProtocol import * from server.handlers.NewsHandler import * diff --git a/server/handlers/commands/uptime.py b/server/handlers/commands/uptime.py index f8be4dc..1a920b1 100644 --- a/server/handlers/commands/uptime.py +++ b/server/handlers/commands/uptime.py @@ -1,8 +1,9 @@ +from __future__ import absolute_import from shared.HLProtocol import * import time def handle( server , user , args , ref ): - secs = long( time.time() - server.startTime ) + secs = int( time.time() - server.startTime ) days = secs / 86400 secs -= ( days * 86400 ) hours = secs / 3600 diff --git a/server/handlers/commands/xfers.py b/server/handlers/commands/xfers.py index 6e8ac8e..def97da 100644 --- a/server/handlers/commands/xfers.py +++ b/server/handlers/commands/xfers.py @@ -1,9 +1,10 @@ +from __future__ import absolute_import from shared.HLProtocol import * def handle( server , user , args , ref ): if user.hasPriv( PRIV_USER_INFO ): str = "" - if len( server.fileserver.transfers.values() ) == 0: + if len( list(server.fileserver.transfers.values()) ) == 0: str += "\r > No file transfers in progress." else: str += "\r > File transfers:" diff --git a/shared/HLProtocol.py b/shared/HLProtocol.py index 2ae9ec9..657a673 100644 --- a/shared/HLProtocol.py +++ b/shared/HLProtocol.py @@ -1,7 +1,10 @@ +from __future__ import absolute_import +from __future__ import print_function from struct import * from config import * import random import re +from six.moves import range def buildTrackerClientPacket(name, description, port, users): """Builds an info packet incorporating the specified name @@ -25,7 +28,7 @@ def HLCharConst( str ): Used for file types, creator codes, and magic numbers. """ if len( str ) != 4: return 0 - return 0L + ( ord( str[0] ) << 24 ) + ( ord( str[1] ) << 16 ) + ( ord( str[2] ) << 8 ) + ord( str[3] ) + return 0 + ( ord( str[0] ) << 24 ) + ( ord( str[1] ) << 16 ) + ( ord( str[2] ) << 8 ) + ord( str[3] ) def HLEncode( str ): """ Encodes a string based on hotline specifications; basically just @@ -131,25 +134,25 @@ def parse( self , data ): self.addNumber( DATA_CHATID , chatid ) except: #TODO Handle condition or throw away ? - print "handle that" + print("handle that") # Private Message else: # Authentication "bot" if line.split( " " , 2 )[1] == "loginserv": self.type = HTLC_HDR_LOGIN - loginStr = line.split(" ", 3)[2] - if loginStr.startswith(":"): - # In IRC private messages not containing space separated text - # are not prefixed with a colon character ":". This is important - # for passwordless login to loginserv, i.e. Guest login. - loginStr = loginStr[1:] + loginStr = line.split(" ", 3)[2] + if loginStr.startswith(":"): + # In IRC private messages not containing space separated text + # are not prefixed with a colon character ":". This is important + # for passwordless login to loginserv, i.e. Guest login. + loginStr = loginStr[1:] self.addString( DATA_LOGIN , HLEncode( loginStr ) ) try: self.addString( DATA_PASSWORD , HLEncode( line.split( " " , 4 )[3] ) ) except IndexError: - # No password provided, but HL can handle blank passwords, try that. - self.addString(DATA_PASSWORD, HLEncode("")) - print "no password provided.." + # No password provided, but HL can handle blank passwords, try that. + self.addString(DATA_PASSWORD, HLEncode("")) + print("no password provided..") else: try: uid = int( line.split( " " , 2 )[1].split( "_" , 1 )[0] ) @@ -158,7 +161,7 @@ def parse( self , data ): self.addString( DATA_STRING , line.split( " " , 2 )[2][1:] ) except: # Throw an error, needs HLException - print "handle that" + print("handle that") elif cmd == "WHO": self.type = HTLC_HDR_USER_LIST @@ -246,32 +249,32 @@ def addString( self , type , data ): def addNumber( self , type , data ): """ Wraps a number in a HLObject, byte-swapping it based on its magnitude, and adds it. """ - num = long( data ) + num = int( data ) packed = "" - if num < ( 1L << 16 ): + if num < ( 1 << 16 ): packed = pack( "!H" , num ) - elif num < ( 1L << 32 ): + elif num < ( 1 << 32 ): packed = pack( "!L" , num ) - elif num < ( 1L << 64 ): + elif num < ( 1 << 64 ): packed = pack( "!Q" , num ) obj = HLObject( type , packed ) self.addObject( obj ) def addInt16( self , type , data ): """ Adds a 16-bit byte-swapped number as a HLObject. """ - num = long( data ) + num = int( data ) obj = HLObject( type , pack( "!H" , num ) ) self.addObject( obj ) def addInt32( self , type , data ): """ Adds a 32-bit byte-swapped number as a HLObject. """ - num = long( data ) + num = int( data ) obj = HLObject( type , pack( "!L" , num ) ) self.addObject( obj ) def addInt64( self , type , data ): """ Adds a 64-bit byte-swapped number as a HLObject. """ - num = long( data ) + num = int( data ) obj = HLObject( type , pack( "!Q" , num ) ) self.addObject( obj ) @@ -345,7 +348,7 @@ def flatten( self , user ): elif self.type == HTLS_HDR_USER_LEAVE: ( c, u ) = self.server.clients[self.getNumber( DATA_UID )] - mynick = ircCheckUserNick( u ) + mynick = ircCheckUserNick( u ) if u.isIRC: proto = "IRC" else: @@ -370,7 +373,7 @@ def flatten( self , user ): elif self.type == HTLS_HDR_TASK: # check for HTLC_HDR_USER_LIST reply: if self.getBinary( DATA_USER ): - keys = self.server.clients.keys() + keys = list(self.server.clients.keys()) keys.sort() for uid in keys: ( c , u ) = self.server.clients[uid] @@ -431,62 +434,62 @@ def flatten( self , user ): # Client packet types -HTLC_HDR_NEWS_GET = 0x00000065 -HTLC_HDR_NEWS_POST = 0x00000067 -HTLC_HDR_CHAT = 0x00000069 -HTLC_HDR_LOGIN = 0x0000006B -HTLC_HDR_MSG = 0x0000006C -HTLC_HDR_KICK = 0x0000006E -HTLC_HDR_CHAT_CREATE = 0x00000070 -HTLC_HDR_CHAT_INVITE = 0x00000071 -HTLC_HDR_CHAT_DECLINE = 0x00000072 -HTLC_HDR_CHAT_JOIN = 0x00000073 -HTLC_HDR_CHAT_LEAVE = 0x00000074 -HTLC_HDR_CHAT_SUBJECT = 0x00000078 -HTLC_HDR_FILE_LIST = 0x000000C8 -HTLC_HDR_FILE_GET = 0x000000CA -HTLC_HDR_FILE_PUT = 0x000000CB -HTLC_HDR_FILE_DELETE = 0x000000CC -HTLC_HDR_FILE_MKDIR = 0x000000CD -HTLC_HDR_FILE_GETINFO = 0x000000CE -HTLC_HDR_FILE_SETINFO = 0x000000CF -HTLC_HDR_FILE_MOVE = 0x000000D0 -HTLC_HDR_FILE_ALIAS = 0x000000D1 -HTLC_HDR_USER_LIST = 0x0000012C -HTLC_HDR_USER_INFO = 0x0000012F -HTLC_HDR_USER_CHANGE = 0x00000130 -HTLC_HDR_ACCOUNT_CREATE = 0x0000015E -HTLC_HDR_ACCOUNT_DELETE = 0x0000015F -HTLC_HDR_ACCOUNT_READ = 0x00000160 -HTLC_HDR_ACCOUNT_MODIFY = 0x00000161 -HTLC_HDR_BROADCAST = 0x00000163 -HTLC_HDR_PING = 0x000001F4 +HTLC_HDR_NEWS_GET = 0x00000065 +HTLC_HDR_NEWS_POST = 0x00000067 +HTLC_HDR_CHAT = 0x00000069 +HTLC_HDR_LOGIN = 0x0000006B +HTLC_HDR_MSG = 0x0000006C +HTLC_HDR_KICK = 0x0000006E +HTLC_HDR_CHAT_CREATE = 0x00000070 +HTLC_HDR_CHAT_INVITE = 0x00000071 +HTLC_HDR_CHAT_DECLINE = 0x00000072 +HTLC_HDR_CHAT_JOIN = 0x00000073 +HTLC_HDR_CHAT_LEAVE = 0x00000074 +HTLC_HDR_CHAT_SUBJECT = 0x00000078 +HTLC_HDR_FILE_LIST = 0x000000C8 +HTLC_HDR_FILE_GET = 0x000000CA +HTLC_HDR_FILE_PUT = 0x000000CB +HTLC_HDR_FILE_DELETE = 0x000000CC +HTLC_HDR_FILE_MKDIR = 0x000000CD +HTLC_HDR_FILE_GETINFO = 0x000000CE +HTLC_HDR_FILE_SETINFO = 0x000000CF +HTLC_HDR_FILE_MOVE = 0x000000D0 +HTLC_HDR_FILE_ALIAS = 0x000000D1 +HTLC_HDR_USER_LIST = 0x0000012C +HTLC_HDR_USER_INFO = 0x0000012F +HTLC_HDR_USER_CHANGE = 0x00000130 +HTLC_HDR_ACCOUNT_CREATE = 0x0000015E +HTLC_HDR_ACCOUNT_DELETE = 0x0000015F +HTLC_HDR_ACCOUNT_READ = 0x00000160 +HTLC_HDR_ACCOUNT_MODIFY = 0x00000161 +HTLC_HDR_BROADCAST = 0x00000163 +HTLC_HDR_PING = 0x000001F4 # Avaraline protocol additions -HTLC_HDR_ICON_LIST = 0x00000745 -HTLC_HDR_ICON_SET = 0x00000746 -HTLC_HDR_ICON_GET = 0x00000747 +HTLC_HDR_ICON_LIST = 0x00000745 +HTLC_HDR_ICON_SET = 0x00000746 +HTLC_HDR_ICON_GET = 0x00000747 # Server packet types -HTLS_HDR_NEWS_POST = 0x00000066 -HTLS_HDR_MSG = 0x00000068 -HTLS_HDR_CHAT = 0x0000006A -HTLS_HDR_CHAT_INVITE = 0x00000071 -HTLS_HDR_CHAT_USER_CHANGE = 0x00000075 -HTLS_HDR_CHAT_USER_LEAVE = 0x00000076 -HTLS_HDR_CHAT_SUBJECT = 0x00000077 -HTLS_HDR_USER_CHANGE = 0x0000012D -HTLS_HDR_USER_LEAVE = 0x0000012E -HTLS_HDR_SELFINFO = 0x00000162 -HTLS_HDR_BROADCAST = 0x00000163 -HTLS_HDR_PING = 0x000001f4 -HTLS_HDR_TASK = 0x00010000 +HTLS_HDR_NEWS_POST = 0x00000066 +HTLS_HDR_MSG = 0x00000068 +HTLS_HDR_CHAT = 0x0000006A +HTLS_HDR_CHAT_INVITE = 0x00000071 +HTLS_HDR_CHAT_USER_CHANGE = 0x00000075 +HTLS_HDR_CHAT_USER_LEAVE = 0x00000076 +HTLS_HDR_CHAT_SUBJECT = 0x00000077 +HTLS_HDR_USER_CHANGE = 0x0000012D +HTLS_HDR_USER_LEAVE = 0x0000012E +HTLS_HDR_SELFINFO = 0x00000162 +HTLS_HDR_BROADCAST = 0x00000163 +HTLS_HDR_PING = 0x000001f4 +HTLS_HDR_TASK = 0x00010000 # Avaraline protocol additions -HTLS_HDR_ICON_CHANGE = 0x00000748 +HTLS_HDR_ICON_CHANGE = 0x00000748 HTLS_HDR_LINK_LOGIN = 0x00000800 HTLS_HDR_LINK_JOIN = 0x00000801 @@ -495,85 +498,85 @@ def flatten( self , user ): # Common data (object) types -DATA_ERROR = 0x0064 -DATA_STRING = 0x0065 -DATA_NICK = 0x0066 -DATA_UID = 0x0067 -DATA_ICON = 0x0068 -DATA_LOGIN = 0x0069 -DATA_PASSWORD = 0x006A -DATA_XFERID = 0x006B -DATA_XFERSIZE = 0x006C -DATA_OPTION = 0x006D -DATA_PRIVS = 0x006E -DATA_STATUS = 0x0070 -DATA_BAN = 0x0071 -DATA_CHATID = 0x0072 -DATA_SUBJECT = 0x0073 -DATA_VERSION = 0x00A0 -DATA_SERVERNAME = 0x00A2 -DATA_FILE = 0x00C8 -DATA_FILENAME = 0x00C9 -DATA_DIR = 0x00CA -DATA_RESUME = 0x00CB -DATA_XFEROPTIONS = 0x00CC -DATA_FILETYPE = 0x00CD -DATA_FILECREATOR = 0x00CE -DATA_FILESIZE = 0x00CF -DATA_NEWFILE = 0x00D3 -DATA_NEWDIR = 0x00D4 -DATA_USER = 0x012C +DATA_ERROR = 0x0064 +DATA_STRING = 0x0065 +DATA_NICK = 0x0066 +DATA_UID = 0x0067 +DATA_ICON = 0x0068 +DATA_LOGIN = 0x0069 +DATA_PASSWORD = 0x006A +DATA_XFERID = 0x006B +DATA_XFERSIZE = 0x006C +DATA_OPTION = 0x006D +DATA_PRIVS = 0x006E +DATA_STATUS = 0x0070 +DATA_BAN = 0x0071 +DATA_CHATID = 0x0072 +DATA_SUBJECT = 0x0073 +DATA_VERSION = 0x00A0 +DATA_SERVERNAME = 0x00A2 +DATA_FILE = 0x00C8 +DATA_FILENAME = 0x00C9 +DATA_DIR = 0x00CA +DATA_RESUME = 0x00CB +DATA_XFEROPTIONS = 0x00CC +DATA_FILETYPE = 0x00CD +DATA_FILECREATOR = 0x00CE +DATA_FILESIZE = 0x00CF +DATA_NEWFILE = 0x00D3 +DATA_NEWDIR = 0x00D4 +DATA_USER = 0x012C # Avaraline protocol additions -DATA_GIFICON = 0x0300 -DATA_GIFLIST = 0x0301 -DATA_NEWSLIMIT = 0x0320 -DATA_COLOR = 0x0500 +DATA_GIFICON = 0x0300 +DATA_GIFLIST = 0x0301 +DATA_NEWSLIMIT = 0x0320 +DATA_COLOR = 0x0500 DATA_PACKET = 0x0600 # IRC needed hackery -DATA_IRC_OLD_NICK = 0x0400 +DATA_IRC_OLD_NICK = 0x0400 # Hotline's idea of "bit 0" is ass backwards -PRIV_DELETE_FILES = 1L << 63 -PRIV_UPLOAD_FILES = 1L << 62 -PRIV_DOWNLOAD_FILES = 1L << 61 -PRIV_RENAME_FILES = 1L << 60 -PRIV_MOVE_FILES = 1L << 59 -PRIV_CREATE_FOLDERS = 1L << 58 -PRIV_DELETE_FOLDERS = 1L << 57 -PRIV_RENAME_FOLDERS = 1L << 56 -PRIV_MOVE_FOLDERS = 1L << 55 -PRIV_READ_CHAT = 1L << 54 -PRIV_SEND_CHAT = 1L << 53 -PRIV_CREATE_CHATS = 1L << 52 -PRIV_DELETE_CHATS = 1L << 51 -PRIV_SHOW_USER = 1L << 50 -PRIV_CREATE_USERS = 1L << 49 -PRIV_DELETE_USERS = 1L << 48 -PRIV_READ_USERS = 1L << 47 -PRIV_MODIFY_USERS = 1L << 46 -PRIV_CHANGE_PASSWORD = 1L << 45 -PRIV_UNKNOWN = 1L << 44 -PRIV_READ_NEWS = 1L << 43 -PRIV_POST_NEWS = 1L << 42 -PRIV_KICK_USERS = 1L << 41 -PRIV_KICK_PROTECT = 1L << 40 -PRIV_USER_INFO = 1L << 39 -PRIV_UPLOAD_ANYWHERE = 1L << 38 -PRIV_USE_ANY_NAME = 1L << 37 -PRIV_NO_AGREEMENT = 1L << 36 -PRIV_COMMENT_FILES = 1L << 35 -PRIV_COMMENT_FOLDERS = 1L << 34 -PRIV_VIEW_DROPBOXES = 1L << 33 -PRIV_MAKE_ALIASES = 1L << 32 -PRIV_BROADCAST = 1L << 31 - -PRIV_SEND_MESSAGES = 1L << 23 +PRIV_DELETE_FILES = 1 << 63 +PRIV_UPLOAD_FILES = 1 << 62 +PRIV_DOWNLOAD_FILES = 1 << 61 +PRIV_RENAME_FILES = 1 << 60 +PRIV_MOVE_FILES = 1 << 59 +PRIV_CREATE_FOLDERS = 1 << 58 +PRIV_DELETE_FOLDERS = 1 << 57 +PRIV_RENAME_FOLDERS = 1 << 56 +PRIV_MOVE_FOLDERS = 1 << 55 +PRIV_READ_CHAT = 1 << 54 +PRIV_SEND_CHAT = 1 << 53 +PRIV_CREATE_CHATS = 1 << 52 +PRIV_DELETE_CHATS = 1 << 51 +PRIV_SHOW_USER = 1 << 50 +PRIV_CREATE_USERS = 1 << 49 +PRIV_DELETE_USERS = 1 << 48 +PRIV_READ_USERS = 1 << 47 +PRIV_MODIFY_USERS = 1 << 46 +PRIV_CHANGE_PASSWORD = 1 << 45 +PRIV_UNKNOWN = 1 << 44 +PRIV_READ_NEWS = 1 << 43 +PRIV_POST_NEWS = 1 << 42 +PRIV_KICK_USERS = 1 << 41 +PRIV_KICK_PROTECT = 1 << 40 +PRIV_USER_INFO = 1 << 39 +PRIV_UPLOAD_ANYWHERE = 1 << 38 +PRIV_USE_ANY_NAME = 1 << 37 +PRIV_NO_AGREEMENT = 1 << 36 +PRIV_COMMENT_FILES = 1 << 35 +PRIV_COMMENT_FOLDERS = 1 << 34 +PRIV_VIEW_DROPBOXES = 1 << 33 +PRIV_MAKE_ALIASES = 1 << 32 +PRIV_BROADCAST = 1 << 31 + +PRIV_SEND_MESSAGES = 1 << 23 # Status bits -STATUS_AWAY = 1 << 0 -STATUS_ADMIN = 1 << 1 +STATUS_AWAY = 1 << 0 +STATUS_ADMIN = 1 << 1 \ No newline at end of file diff --git a/shared/HLTransfer.py b/shared/HLTransfer.py index 954c6ba..e48f97f 100644 --- a/shared/HLTransfer.py +++ b/shared/HLTransfer.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from shared.HLProtocol import * import os , time @@ -11,9 +12,9 @@ def __init__( self , id , path , owner , type ): self.name = os.path.basename( path ) self.owner = owner self.type = type - self.total = 0L - self.transferred = 0L - self.offset = 0L + self.total = 0 + self.transferred = 0 + self.offset = 0 self.startTime = 0.0 def overallPercent( self ): @@ -51,7 +52,7 @@ def __init__( self , id , path , owner , offset ): HLTransfer.__init__( self , id , path , owner , XFER_TYPE_DOWNLOAD ) self.offset = offset self.dataSize = os.path.getsize( path ) - offset - self.file = file( path , "r" ) + self.file = open( path , "r" ) self.file.seek( offset ) self.sentHeader = False self._buildHeaderData() @@ -101,7 +102,7 @@ def _buildHeaderData( self ): class HLUpload( HLTransfer ): def __init__( self , id , path , owner ): HLTransfer.__init__( self , id , path , owner , 1 ) - self.file = file( path , "a" ) + self.file = open( path , "a" ) self.initialSize = os.path.getsize( path ) self.buffer = "" self.state = STATE_FILP diff --git a/shared/HLTypes.py b/shared/HLTypes.py index e65a2df..84631ad 100644 --- a/shared/HLTypes.py +++ b/shared/HLTypes.py @@ -1,7 +1,9 @@ +from __future__ import absolute_import from shared.HLProtocol import HLCharConst from datetime import datetime from struct import * import os +from six.moves import range LOG_TYPE_GENERAL = 1 LOG_TYPE_LOGIN = 2 @@ -23,7 +25,7 @@ LOG_TYPE_ERROR:"ERROR", LOG_TYPE_DEBUG:"DEBUG"} -class HLException: +class HLException(Exception): """ Exception thrown due to protocol errors. """ def __init__( self , msg = "Unknown exception." , fatal = False ): @@ -34,11 +36,11 @@ class HLAccount: """ Stores account information. """ def __init__( self , login = "" ): - self.id = 0L + self.id = 0 self.login = login self.password = "" self.name = "Null Account" - self.privs = 0L + self.privs = 0 self.fileRoot = "" def copyFrom( self , acct ): @@ -62,7 +64,7 @@ def __init__( self , uid = 0 , addr = "" ): self.icon = 500 self.status = 0 self.gif = "" - self.color = -1L + self.color = -1 self.account = None self.away = False self.lastPacketTime = 0.0 @@ -83,7 +85,7 @@ def isLoggedIn( self ): def hasPriv( self , priv ): """ Returns True if the account associated with the user has the specified privilege. """ - return ( self.account != None ) and ( ( long( self.account.privs ) & priv ) > 0 ) + return ( self.account != None ) and ( ( int( self.account.privs ) & priv ) > 0 ) def parse( self, data ): if len(data) < 8: @@ -104,7 +106,7 @@ def flatten( self ): data += pack( "!4H" , self.uid , self.icon , self.status , len( self.nick ) ) data += self.nick # this is an avaraline extension for nick coloring - if self.color >= 0L: + if self.color >= 0: data += pack( "!L" , self.color ) return data @@ -158,7 +160,7 @@ def __init__( self , data = None ): def forkOffset( self , fork ): """ Returns the offset for the specified fork type. """ - if self.forkOffsets.has_key( fork ): + if fork in self.forkOffsets: return self.forkOffsets[fork] return 0 @@ -182,7 +184,7 @@ def flatten( self ): """ Flattens the resume information into a packed structure to send in a HLObject. """ data = pack( "!LH" , HLCharConst( "RFLT" ) , 1 ) data += ( "\0" * 34 ) - data += pack( "!H" , len( self.forkOffsets.keys() ) ) + data += pack( "!H" , len( list(self.forkOffsets.keys()) ) ) for forkType in self.forkOffsets.keys(): data += pack( "!4L" , forkType , self.forkOffsets[forkType] , 0 , 0 ) return data @@ -191,7 +193,7 @@ class HLNewsPost: """ Stores information about a single news post. """ def __init__( self , nick = "" , login = "" , post = "" ): - self.id = 0L + self.id = 0 self.nick = nick self.login = login self.post = post @@ -218,7 +220,7 @@ def handleUserDisconnected( self , server , user ): def handlePacket( self , server , user , packet ): """ Default dispatcher called when a packet is received. Calls any registered handler functions. Returns True when packet is handled. """ - if self._funcs.has_key( packet.type ): + if packet.type in self._funcs: self._funcs[packet.type]( server , user , packet ) return True return False diff --git a/shared/HLUtils.py b/shared/HLUtils.py index 4b14c74..c3f7ae2 100644 --- a/shared/HLUtils.py +++ b/shared/HLUtils.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import import sys,os diff --git a/support/text_db_setup.py b/support/text_db_setup.py index 9ae1160..188a605 100644 --- a/support/text_db_setup.py +++ b/support/text_db_setup.py @@ -1,5 +1,6 @@ #!/usr/bin/env python +from __future__ import absolute_import import os from config import * From 73b7f15c2ea6f6ce68e26308a9ab9029d7c44ffe Mon Sep 17 00:00:00 2001 From: Patrick Thiel Date: Mon, 2 Oct 2023 22:52:36 -0400 Subject: [PATCH 5/8] fix: remove commented out test code --- server/HLServer.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/server/HLServer.py b/server/HLServer.py index ad8a3a3..72b8a23 100644 --- a/server/HLServer.py +++ b/server/HLServer.py @@ -42,10 +42,6 @@ def connectionLost( self , reason ): def dataReceived( self , data ): """ Called when the socket receives data. """ - # encoding = "utf-8" - # data = data.encode(encoding) - # data = data.decode('utf-8') - self.buffer += data self.parseBuffer() From 6d8ac7c81fd7682ad461733772bcf51b8c81f26c Mon Sep 17 00:00:00 2001 From: Patrick Thiel Date: Tue, 10 Oct 2023 15:08:02 -0400 Subject: [PATCH 6/8] ref: fix server handler imports --- server/handlers/AcctHandler.py | 2 +- server/handlers/FileHandler.py | 1 - server/handlers/UserHandler.py | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/server/handlers/AcctHandler.py b/server/handlers/AcctHandler.py index 5917b0d..b4f08c7 100644 --- a/server/handlers/AcctHandler.py +++ b/server/handlers/AcctHandler.py @@ -3,7 +3,7 @@ from shared.HLTypes import * from config import * from struct import pack -from md5 import md5 +from hashlib import md5 def installHandler( server ): server.registerPacketHandler( AcctHandler() ) diff --git a/server/handlers/FileHandler.py b/server/handlers/FileHandler.py index 5520634..b252679 100644 --- a/server/handlers/FileHandler.py +++ b/server/handlers/FileHandler.py @@ -3,7 +3,6 @@ from shared.HLTypes import * from config import * from struct import pack -from statvfs import * import os def installHandler( server ): diff --git a/server/handlers/UserHandler.py b/server/handlers/UserHandler.py index 8dad666..2600abc 100644 --- a/server/handlers/UserHandler.py +++ b/server/handlers/UserHandler.py @@ -3,7 +3,7 @@ from shared.HLUtils import * from shared.HLTypes import * from config import * -from md5 import md5 +from hashlib import md5 import time def installHandler( server ): @@ -41,7 +41,7 @@ def handleLogin( self , server , user , packet ): user.account = server.database.loadAccount( login ) if user.account == None: raise HLException( "Login is incorrect." , True) - if user.account.password != md5( password ).hexdigest(): + if user.account.password != md5( password.encode('mac-roman') ).hexdigest(): user.nick = packet.getString( DATA_NICK , "unnamed" ) server.logEvent( LOG_TYPE_LOGIN , "Login failure" , user ) raise HLException( "Password is incorrect." , True) From c9ba59fcbeb6f87ac259f9eef673da8e88f78d23 Mon Sep 17 00:00:00 2001 From: Patrick Thiel Date: Tue, 10 Oct 2023 22:58:35 -0400 Subject: [PATCH 7/8] ref: progress.. able to login now!! --- server/HLServer.py | 8 ++++-- server/handlers/UserHandler.py | 1 + shared/HLProtocol.py | 17 +++++++++--- shared/HLTypes.py | 20 +++++++++++--- shared/HLUtils.py | 49 +++++++++++++++++----------------- 5 files changed, 61 insertions(+), 34 deletions(-) diff --git a/server/HLServer.py b/server/HLServer.py index 72b8a23..af21754 100644 --- a/server/HLServer.py +++ b/server/HLServer.py @@ -42,6 +42,7 @@ def connectionLost( self , reason ): def dataReceived( self , data ): """ Called when the socket receives data. """ + self.buffer += data self.parseBuffer() @@ -87,10 +88,13 @@ def parseBuffer( self ): # More commands still in the buffer, parse them. value = "" try: - cmd, value = cmds[0].split(" ", 1) + # breaking and busted in here + print("got in my try block") + cmd, value = cmds[0].decode('mac-roman').split(" ", 1) except ValueError: # Value isn't defined, only parse cmd - cmd = cmds[0].split(" ", 1)[0] + print("got in this except?") + cmd = cmds[0].decode('mac-roman').split(" ", 1)[0] # Check the first command, if NICK or USER, login, else return UNKNOWN COMMAND if ( cmd == "NICK" ) or ( cmd == "USER" ): nick = value or "Unnamed" diff --git a/server/handlers/UserHandler.py b/server/handlers/UserHandler.py index 2600abc..67e99f4 100644 --- a/server/handlers/UserHandler.py +++ b/server/handlers/UserHandler.py @@ -43,6 +43,7 @@ def handleLogin( self , server , user , packet ): raise HLException( "Login is incorrect." , True) if user.account.password != md5( password.encode('mac-roman') ).hexdigest(): user.nick = packet.getString( DATA_NICK , "unnamed" ) + server.logEvent( LOG_TYPE_LOGIN , "Login failure" , user ) raise HLException( "Password is incorrect." , True) if user.account.fileRoot == "": diff --git a/shared/HLProtocol.py b/shared/HLProtocol.py index 657a673..3c74214 100644 --- a/shared/HLProtocol.py +++ b/shared/HLProtocol.py @@ -1,6 +1,7 @@ from __future__ import absolute_import from __future__ import print_function from struct import * +from struct import pack from config import * import random import re @@ -71,7 +72,16 @@ def getObjects( self, type ): def flatten( self ): """ Returns a flattened, byte-swapped string for this hotline object. """ - return pack( "!2H" , self.type , len( self.data ) ) + self.data + #Significantly modified + type_bytes = self.type.to_bytes(2, byteorder='big') + len_bytes = len(self.data).to_bytes(2, byteorder='big') + data_bytes = self.data + + if not isinstance(self.data, bytes): + # make it bytes + data_bytes = self.data.encode('mac-roman') + return type_bytes + len_bytes + data_bytes + class HLPacket: def __init__( self , type = 0 , seq = 0 , flags = 0 , isIRC = 0 ): @@ -429,8 +439,9 @@ def flatten( self , user ): # Normal Hotline processing else: for obj in self.objs: - data += obj.flatten() - return pack( "!5L1H" , self.type , self.seq , self.flags , len( data ) + 2 , len( data ) + 2 , len( self.objs ) ) + data + data += obj.flatten().decode('mac-roman') + + return pack( "!5L1H" , self.type , self.seq , self.flags , len( data ) + 2 , len( data ) + 2 , len( self.objs ) ) + data.encode('mac-roman') # Client packet types diff --git a/shared/HLTypes.py b/shared/HLTypes.py index 84631ad..b5a78a1 100644 --- a/shared/HLTypes.py +++ b/shared/HLTypes.py @@ -102,12 +102,24 @@ def parse( self, data ): def flatten( self ): """ Flattens the user information into a packed structure to send in a HLObject. """ - data = "" - data += pack( "!4H" , self.uid , self.icon , self.status , len( self.nick ) ) + data = b"" + # builtins.TypeError: can only concatenate str (not "bytes") to str + + #Significantly modified for python3 + uid_bytes = self.uid.to_bytes(4, byteorder='big') + icon_bytes = self.icon.to_bytes(4, byteorder='big') + status_bytes = self.status.to_bytes(4, byteorder='big') + nick_bytes = len(self.nick).to_bytes(4, byteorder='big') + + data += uid_bytes + icon_bytes + status_bytes + nick_bytes + + # data += pack( "!4H" , self.uid , self.icon , self.status , len( self.nick ) ) + + data += self.nick # this is an avaraline extension for nick coloring - if self.color >= 0: - data += pack( "!L" , self.color ) + # if self.color >= 0: + # data += pack( "!L" , self.color ) return data class HLChat: diff --git a/shared/HLUtils.py b/shared/HLUtils.py index c3f7ae2..0ec6ee6 100644 --- a/shared/HLUtils.py +++ b/shared/HLUtils.py @@ -1,32 +1,31 @@ -from __future__ import absolute_import -import sys,os +import os +import subprocess +def shell_exec(user, cmd, arg): + os.environ['_LOGIN'] = user.account.login + os.environ['_UID'] = str(user.uid) + os.environ['_IP'] = user.ip + os.environ['_ICON'] = str(user.icon) + os.environ['_COLOR'] = str(user.status) + # HACK -- Forcing user.nick to string manually here, it comes in as bytes + os.environ['_NICK'] = user.nick.decode('mac-roman') + os.environ['_NAME'] = user.account.name + os.environ['_PRIVS'] = str(user.account.privs) + os.environ['_FROOT'] = user.account.fileRoot + proto = "IRC" if user.isIRC else "Hotline" + os.environ['_PROTO'] = proto -def shell_exec ( user, cmd, arg ): - os.environ['_LOGIN'] = user.account.login - os.environ['_UID'] = str(user.uid) - os.environ['_IP'] = user.ip - os.environ['_ICON'] = str(user.icon) - os.environ['_COLOR'] = str(user.status) - os.environ['_NICK'] = user.nick - os.environ['_NAME'] = user.account.name - os.environ['_PRIVS'] = str(user.account.privs) - os.environ['_FROOT'] = user.account.fileRoot - if user.isIRC: proto = "IRC" - else: proto = "Hotline" - os.environ['_PROTO'] = proto + path = cmd + " " + arg + path = path.replace('..', '') + path = "./support/exec/" + path - path = cmd+" "+arg - path = path.replace('..', '') - path = "./support/exec/" + path - put, get, error = os.popen3(path) - - if( len(error.readlines()) == 1): + with subprocess.Popen(path, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) as proc: + ret = proc.stdout.read().decode() + err = proc.stderr.read().decode() + + if err: return None - ret = '' - for result in get.readlines(): - ret += result - return ret + return ret #from twisted.internet import utils From 23324eadf1158c197680e79b60e067c1e473f202 Mon Sep 17 00:00:00 2001 From: Patrick Thiel Date: Sat, 14 Oct 2023 23:36:14 -0400 Subject: [PATCH 8/8] brk: update to python3 and switch to a debian based docker image --- Dockerfile | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/Dockerfile b/Dockerfile index 3ba5b98..ea010e5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,18 +1,9 @@ -FROM python:2-alpine -MAINTAINER Cat'Killer - -# The "exec" plugins are all written in bash and won't -# work with bourne. Install bash to ensure they work. -RUN apk add --no-cache bash +FROM python:3.12.0-slim-bookworm +WORKDIR /app -# gcc and other build tools not in alpine. Add them as virtual packages, build Twisted and delete them. -RUN apk add --no-cache --virtual .build-deps gcc musl-dev -RUN pip install --upgrade pip -RUN pip install typing -RUN pip install twisted -RUN apk del .build-deps +COPY requirements.txt /app -WORKDIR /app +RUN pip install -r requirements.txt COPY config.py /app/config.py COPY phxd /app/phxd