Public feed #599001

failbot

public python v1 · immutable
Raw Edit
·published 2007-07-01 19:08 UTC
rendered paste body
#! /usr/bin/python2.5# Kilgame server as an IRC client.# Based on ircbot.py by bsmntbombdood. http://abacus.kwzs.be/~bsmnt_bot/import socketimport reimport sysimport tracebackimport threadimport pprintimport inspectimport timeimport osimport threadingimport copyimport pickleimport marshalimport typesimport mathfrom cStringIO import StringIOclass StopHandlingCallbacks:    passclass QuitIRC:    passclass RemoveCallback:    passclass IRCbot:    def __init__(self, host, nick, ident, owner, realname="", port=6667,                 chan=None, verbose=True, exec_chans=[],                 command_char="#", threading=True, error_in_chan=True, ban_file="/bans"):        self.host = host        self.port = port        self.nick = nick        self.ident= ident        self.realname = realname        self.chan = chan        self.verbose = verbose        self.owner = owner        self.error_in_chan = error_in_chan        self.errorchan = "#%s_errors" % self.nick        self.connected = False;        self.raw_regex_queue = [];        self.ban_file = ban_file        self.banlist = self.read_bans()                self.COMMAND_CHAR = command_char        self.THREADING = threading                self.commands_running = []        self.commands_running_lock = thread.allocate_lock()        self.gameInited = False        self.gameStarted = False        self.gamePlayerDict = {}        self.locals = {"self": self}                self.message_re = re.compile(r"^:(?P<nick>\S+)!(?P<ident>\S+)@(?P<host>\S+) (?P<command>\S+) (?P<channel>\S+) :(?P<message>.*)")        #default callbacks:        self.register_raw("^PING (.*)$", self.pong)        self.register_raw(            r"^:%s PRIVMSG \S* :\+%squit ?(.*)" % (self.owner, self.COMMAND_CHAR),            self.do_quit)        self.register_raw(            r"^:%s PRIVMSG \S* :\+%sraw (.*)" % (self.owner, self.COMMAND_CHAR),            self.do_raw)        self.register_raw(            r"^\S+ PRIVMSG \S+ :.%sctcp (\S+) (.+)" % self.COMMAND_CHAR,            self.do_ctcp)        self.register_raw(            r"^:%s PRIVMSG (\S*) :\+%spexec (.*)" % (self.owner, self.COMMAND_CHAR),            self.do_exec)        self.register_raw(            r"\S+ PRIVMSG (%s) :.%sexec (.*)" % ("|".join(exec_chans+[self.errorchan]), self.COMMAND_CHAR),            self.do_exec)                                                         self.register_raw(            r"\S+ PRIVMSG \S+ :.%sps" % self.COMMAND_CHAR,            self.do_ps)        self.register_raw(            r"^\S+ PRIVMSG (%s) :.%skill (.*)" % ("|".join(exec_chans+[self.errorchan]), self.COMMAND_CHAR),            self.do_kill)        self.register_raw(            r"^\S+ PRIVMSG %s :.%sinit" % (self.chan, self.COMMAND_CHAR),            self.do_init)        self.register_raw(            r"^(\S+)!\S*@\S* PRIVMSG %s :(.)%sjoin" % (self.chan, self.COMMAND_CHAR),            self.do_join)        self.register_raw(            r"^\S+ PRIVMSG %s :.%sstart" % (self.chan, self.COMMAND_CHAR),            self.do_start)        self.register_raw(            r"^(\S+)!\S*@\S* PRIVMSG %s :(.)%sstatus" % (self.chan, self.COMMAND_CHAR),            self.do_status)        self.register_raw(            r"^(\S+)!\S*@\S* PRIVMSG %s :(.)%sshoot (\S{1,16})" % (self.chan, self.COMMAND_CHAR),            self.do_shoot)        self.register_raw(            r"^(\S+)!\S*@\S* PRIVMSG %s :(.)%sfriend (\S{1,16})" % (self.chan, self.COMMAND_CHAR),            self.do_friend)        self.register_raw(            r"^\S+ PRIVMSG %s :.%send" % (self.chan, self.COMMAND_CHAR),            self.do_end)                self.register_raw(r"^ERROR :Closing Link:.*", lambda x : True)    def raw(self, message):        message += "\r\n"        x = self.socket.send(message)        while x < len(message):            message = message[x:]            x = self.socket.send(message)    def connect(self):        self.socket = socket.socket();        self.socket.connect((self.host, self.port))        self.raw("NICK %s" % self.nick)        self.raw("USER %s %s bla :%s" % (self.ident, self.host,                                         self.realname))        self.raw("CAPAB :IDENTIFY-MSG")        if isinstance(self.chan, list):            for i in self.chan:                self.raw("JOIN :%s" % i)        else:            self.raw("JOIN :%s" % self.chan)                self.raw("JOIN :%s" % self.errorchan)        self.sockfile = self.socket.makefile("rw")        self.connected = True;    def listen(self):        if not self.connected:            self.connect()        while self.connected:            line = self.sockfile.readline()            line = line.strip()            if not line: continue                        if self.verbose: sys.__stdout__.write(line + "\n")            if hasattr(self, "onmsg"):                if self.onmsg(message):                    self.connected = False                    break;                            self.do_callbacks(line)                def disconnect(self, message):        self.raw("QUIT :%s" % message)        self.socket.close()        self.sockfile.close()        self.connected = False        return True    def register_raw(self, regex, callback):        if isinstance(regex, str):            self.raw_regex_queue.append((re.compile(regex), callback))        else:            self.raw_regex_queue.append((regex, callback))    def do_callbacks(self, message):        # each entry in self.raw_regex_queue is (regex, callback)        for ban in self.banlist:            if ban.match(message):                print "%s is banned by %r" % (message, ban.pattern)                return        for i in self.raw_regex_queue:            if not self.connected: break            m = i[0].match(message)            if m:                try:                    self.exec_execer("self.handle_callback(message, m, i)", (globals(), locals()))                except StopHandlingCallbacks:                    break                except RemoveCallback:                    self.raw_regex_queue.remove(i)                except QuitIRC:                    self.disconnect("Disconnected.")                    return    def handle_callback(self, message, m, i):        try:            retval = i[1](message, m)        except TypeError:            try:                retval = i[1](message)            except TypeError:                self.raw("PRIVMSG %s :TypeError for callback %s, %r. Removing." %                         (self.errorchan, i[1].__name__, i[0].pattern))                self.raw_regex_queue.remove(i)                return            if retval:                self.disconnect("Disconnected.")                return    def pong(self, message, r):        self.raw("PONG %s" %  r.group(1))    def do_quit(self, message, r):        self.disconnect(r.group(1))        return True    def do_raw(self, message, r):        self.raw(r.group(1))    def do_ctcp(self, message, r):        self.raw("PRIVMSG %s :\x01%s\x01" % (r.group(1), r.group(2)))            def exec_execer(self, command, env):        info = (command, time.time(), env, threading.Event())        self.commands_running_lock.acquire()        self.commands_running.append(info)        self.commands_running_lock.release()                thread_info.info = info        sys.settrace(exec_global_tracer)                try:            exec command in env[0], env[1]        except SystemExit:            pass        except Exception:            stuff = traceback.format_exc()            if self.error_in_chan:                env[0]["sys"].stdout.write(stuff.rstrip().split("\n")[-1])            env[0]["sys"].stderr.write(stuff)        sys.settrace(None)        self.commands_running_lock.acquire()        self.commands_running.remove(info)        self.commands_running_lock.release()            def do_exec(self, message, r):        command = r.group(2)        # what to expose in exec        env = (globals(), locals())        env[0]["sys"] = SysWrapper(            stdout = IRCFileWrapper(self.raw, r.group(1)),            stderr = IRCFileWrapper(self.raw, self.errorchan))                if self.THREADING:            thread.start_new_thread(self.exec_execer, (command, env))        else:            self.exec_execer(command, env)    def get_message(self, line):        return self.message_re.match(line).group("message")        def print_callbacks(self, fd = sys.stdout):        pprint.pprint(            [(i[0].pattern, i[1].__name__) for i in self.raw_regex_queue], fd)    def do_ps(self, message, r):        channel = self.message_re.match(message).group("channel")        for i in range(len(self.commands_running)):            info = self.commands_running[i]            if info[3].isSet():                killed = ", killed"            else:                killed = ""            self.raw("PRIVMSG %s :%s: %r, %.2f seconds%s" %                     (channel, i, info[0], time.time() - info[1], killed))        if not self.commands_running and self.verbose:            self.raw("PRIVMSG %s :None" % channel)    def do_kill(self, message, r):        channel = r.group(1)        try:            pid = int(r.group(2))        except ValueError:            self.raw("PRIVMSG %s :Argument to kill must be a number" % channel)            return                self.commands_running_lock.acquire()        try:            self.commands_running[pid][3].set()        except IndexError:            self.commands_running_lock.release()            self.raw("PRIVMSG %s :Proccess %s does not exist" % (channel, r.group(1)))            return        self.commands_running_lock.release()    def do_init(self, message, r):        if self.gameInited:            sys.stdout("The game has already been initialized. Say #join to join; #start to start; #end to abort the game.")        else:            self.gameInited = True            sys.stdout("Game initialized. Say #join to join; #start to start; #end to abort the game.")    def do_join(self, message, r):        if r.group(2) == "-":            sys.stdout("%s, please identify to NickServ first." % r.group(1))        elif r.group(1) in self.gamePlayerDict:            sys.stdout("%s, you are already in the game. Say #end to abort the game." % r.group(1))        elif not self.gameInited:            sys.stdout("%s, the game has not yet been initialized. Say #init to initialize the game." % r.group(1))        elif self.gameStarted:            sys.stdout("%s, the game has already started. Say #status to view status; #end to abort the game." % r.group(1))        else:            self.gamePlayerDict[r.group(1)] = 2, datetime.min, []            sys.stdout("%s, you have joined the game. Say #start to start; #end to abort the game." % r.group(1))    def do_start(self, message, r):        if not self.gameInited:            sys.stdout("The game has not yet been initialized. Say #init to initialize the game.")        elif self.gameStarted:            sys.stdout("The game has already started. Say #status to view status; #end to abort the game.")        elif len(self.gamePlayerDict) < 2:            sys.stdout("The game doesn't yet have enough players. Say #join to join; #end to abort the game.")        else:            self.gameStarted = True            sys.stdout("Game started. Say #status to view status; #end to abort the game.")    def listInit(self, l):        return reduce(lambda x, y: x + ", " + y, l[:-1])    def do_status(self, message, r):        if not self.gameInited:            sys.stdout("%s, the game has not yet been initialized. Say #init to initialize the game." % r.group(1))        if not self.gameStarted:            if self.gamePlayerDict == []:                sys.stdout("%s, currently there are no players. Say #join to join." % r.group(1))            elif len(self.gamePlayerDict) == 1:                sys.stdout("%s, currently the only player is %s. Say #join to join." % (r.group(1), self.gamePlayerDict.keys()[0]))            else:                sys.stdout("%s, the current players are %s and %s. Say #join to join; #start to start." % (r.group(1), listInit(playerList), playerList[-1]))        else:            playerList = []            for name, (lives, nextShootTime, noShootList) in self.gamePlayerDict.iteritems():                timeToShoot = 0 if nextShootTime < datetime.now() else (nextShootTime - datetime.now()).seconds                playerList.append("%s (%s lives, must wait %s seconds before shooting)" % (name, lives, timeToShoot))            sys.stdout("%s, the current players are %s and %s." % (r.group(1), self.listInit(playerList), playerList[-1]))            noShootList = self.gamePlayerDict[r.group(1)][2]            if noShootList == []:                sys.stdout("%s, you are currently able to shoot anybody." % r.group(1))            elif len(noShootList) == 1:                sys.stdout("%s, you are unable to shoot %s." % (r.group(1), noShootList[0]))            sys.stdout("%s, you are unable to shoot %s and %s." % (r.group(1) + self.listInit(noShootList), noShootList[-1]))            sys.stdout("%s, say #shoot to shoot a player; #friend to promise to not shoot a player; #end to abort the game." % r.group(1))    def do_shoot(self, message, r):        sys.stdout("Not yet implemented.")    def do_friend(self, message, r):        sys.stdout("Not yet implemented.")    def do_end(self, message, r):        sys.stdout("Not yet implemented.")    def save_callbacks(self, f):        if not hasattr(f, "write"):            f = open(f, "wb")        data = [(i[0], marshal.dumps(i[1].func_code), inspect.ismethod(i[1])) for i in self.raw_regex_queue]        pickle.dump(data, f)    def load_callbacks(self, f):        if not hasattr(f, "read"):            f = open(f, "rb")        callbacks = pickle.load(f)        self.raw_regex_queue = []        for i in callbacks:            fn = types.FunctionType(marshal.loads(i[1]), globals())            if i[2]:                # method, this only works for methods on IRCbot                callback = types.MethodType(fn, self, self.__class__)            else:                callback = fn            self.raw_regex_queue.append((i[0], callback))    def read_bans(self):        try:            fd = open(self.ban_file, "r")        except IOError:            fd = open(self.ban_file, "w+")        bans = fd.read()        fd.close()                    self.banlist = [re.compile(i) for i in bans.split("\n") if i]        return self.banlist    def write_bans(self):        fd = open(self.ban_file, "w+")        fd.write("\n".join([i.pattern for i in self.banlist]))        fd.close()                def ban(self, pattern):        self.banlist.append(re.compile(pattern))        self.write_bans()            def unban(self, pattern):        for i in self.banlist:            if i.pattern == pattern:                self.banlist.remove(i)        self.write_bans()    # to kill threadsdef exec_global_tracer(frame, event, arg):    if event == "call":        return exec_local_tracer    else:        return exec_global_tracerdef exec_local_tracer(frame, event, arg):    try:        info=frame.f_globals["thread_info"].info    except KeyError:        return exec_local_tracer    if info[3].isSet():        thread.exit()            return exec_local_tracer    class IRCFileWrapper:    def __init__(self, raw, channel, rate_limit = None):        """ rate_limit is function of one argument (the number of        lines sent so far), and must return a number (the number of        seconds to wait before sending the next line)"""        self.raw = raw        self.channel = channel        self.rate_limit = rate_limit or (lambda x: (x > 2 and min([x/5., 2])) or 0)    def write(self, s):        if not self.channel:            return        s = str(s)        s = s.split("\n")        lines_sent = 0        for i in s:            if i.isspace() or not i:                continue            sent = 0            while sent < len(i):                self.raw("PRIVMSG %s :%s" % (self.channel, i[sent:sent+375]))                sent += 375                lines_sent += 1                time.sleep(self.rate_limit(lines_sent))    __call__ = writeclass SysWrapper:    """wrap the sys module with our own stdout and stderr"""    def __init__(self, stdout, stderr):        self.__sys = __import__("sys")        self.stdout = stdout        self.stderr = stderr            def __getattr__(self, what):        if what == "stdout":            return self.stdout        elif what == "stderr":            return self.stderr        else:            # this is the only branch ever called            return getattr(self.__sys, what)args = {    "host": "85.188.1.26",    "nick": "EagleBot",    "ident": "bsmnt",    "realname": "bsmntbombdood bot",    "chan": "#kilbot",    "exec_chans": ["#kilbot"],    "owner": r"ihope!\S*@\S*"    }if os.getuid() == 0:    os.setgid(1005)    os.setuid(1005)thread_info = threading.local()bot = IRCbot(**args)bot.listen()def hack_closure(func, locals, globals):    code = func.func_code    env = globals.copy()    needed = [i for i in code.co_names if i not in code.co_varnames]    print needed    for var in needed:        env[var] = locals[var]    for k in locals:        print env[k]    return types.FunctionType(code, env)