Example #1
0
    def __init__(self, config, verbose=False, debug=False):
        super(James, self).__init__(config, verbose=verbose)

        self.version = VERSION
        self.debug = debug

        # Bot state and logger.
        self.state = ServerState(self)
        self.config = config
        self.style = Styler()
        self.defaultcolor = self.style.gray
        self.hicolor = self.style.pink

        # event stuff
        self.state.events.update({list(i.keys())[0]: Event(list(i.values())[0])
            for i in utils.events.Standard})

        self.state.apikeys = json.loads(open("apikeys.conf").read())
        self.state.data = {"autojoin_channels": []}
        self.state.data["autojoin_channels"].extend(self.config["autojoin"])
        for entry in self.config["admins"]:
            self.state.admins.add(entry.lower())
        self.state.nick = self.config["nick"]

        for user in self.config["muted"]:
            self.state.mute(user)

        # Various things
        self.cmdhandler = CommandHandler(self, plugins.get_plugins())
        self.cmd_thread = HandlerThread(self)
        self.cmd_thread.daemon = True

        self.state.messages[self.state.nick] = deque([], MAX_MESSAGE_STORAGE)
        self.register_callbacks()
Example #2
0
    def __init__(self, config):
        print("Infobot version %s" % (VERSION))
        super().__init__(config, verbose=False)

        self.config = config
        self.nick = config["nick"]

        # Arbitrary bot data
        self.data = {}
        self.auth = None

        self.lock = threading.Lock()
        self.lock.acquire()

        self.events = DotDict({list(i.keys())[0]: Event(list(i.values())[0])
            for i in StandardEvents})

        self.cmd_thread = HandlerThread(self, self.lock)
        self.cmd_thread.daemon = True
        self.register_callbacks()
        self.register_plugins(plugins.get_plugins())

        for item in self.config["admins"]:
            self.auth.addadmin(User(item[0], item[1], item[2]))
Example #3
0
class James(IRCHandler):
    """ James main bot executable thingy class """
    @startinfo(VERSION)
    def __init__(self, config, verbose=False, debug=False):
        super(James, self).__init__(config, verbose=verbose)

        self.version = VERSION
        self.debug = debug

        # Bot state and logger.
        self.state = ServerState(self)
        self.config = config
        self.style = Styler()
        self.defaultcolor = self.style.gray
        self.hicolor = self.style.pink

        # event stuff
        self.state.events.update({list(i.keys())[0]: Event(list(i.values())[0])
            for i in utils.events.Standard})

        self.state.apikeys = json.loads(open("apikeys.conf").read())
        self.state.data = {"autojoin_channels": []}
        self.state.data["autojoin_channels"].extend(self.config["autojoin"])
        for entry in self.config["admins"]:
            self.state.admins.add(entry.lower())
        self.state.nick = self.config["nick"]

        for user in self.config["muted"]:
            self.state.mute(user)

        # Various things
        self.cmdhandler = CommandHandler(self, plugins.get_plugins())
        self.cmd_thread = HandlerThread(self)
        self.cmd_thread.daemon = True

        self.state.messages[self.state.nick] = deque([], MAX_MESSAGE_STORAGE)
        self.register_callbacks()

    def __repr__(self):
        return ("James(server=%r, chans=%s)"
            % (self.config["server"].split(":")[0],
               list(self.state.channels.keys())))

    def _msg(self, chan, msg):
        """ _msg(string chan, string msg) - Sends a PRIVMSG. """
        msg = str(msg).replace("\r", "").replace("\x07", "")
        if "\n" in msg:
            for item in msg.split("\n"):
                self._msg(chan, item)
                try:
                    mesg = utils.message.Message(self.state.nick, self.state.channels[chan], item)
                    self.state.messages[self.state.nick].appendleft(mesg)
                except:
                    pass
        else:
            self._send("PRIVMSG %s :%s" % (chan, msg))
            try:
                mesg = utils.message.Message(self.state.nick, self.state.channels[chan], msg)
                self.state.messages[self.state.nick].appendleft(mesg)
            except:
                pass


    def _check_for_command(self, msg, nick, chan):
        """ Check for a command """
        cmd_splitmsg = msg.split(" ", 1)
        if len(cmd_splitmsg) > 1:
            cmd_args = cmd_splitmsg[1]
        else:
            cmd_args = ""

        trig_short = self.cmdhandler.trigger_short(cmd_splitmsg[0])
        if trig_short and self.config["short_enabled"]:
            if hasattr(trig_short.function, "_require_admin"):
                if nick.lower() in self.state.admins:
                    self.cmd_thread.handle(partial(trig_short,
                        self, nick, chan, cmd_args))
                    self.state.events["CommandCalledEvent"].fire(self,
                        trig_short, cmd_args)
            else:
                self.cmd_thread.handle(partial(trig_short,
                        self, nick, chan, cmd_args))
                self.state.events["CommandCalledEvent"].fire(self,
                    trig_short, cmd_args)

        if msg.startswith(self.config["cmdchar"]):
            cmd_name = cmd_splitmsg[0][1:]
            callback = self.cmdhandler.trigger(cmd_name)
            if not callback:
                return

            if hasattr(callback.function, "_require_admin"):
                if nick.lower() in self.state.admins:
                    self.cmd_thread.handle(partial(callback,
                        self, nick, chan, cmd_args))
                    self.state.events["CommandCalledEvent"].fire(self,
                        callback, cmd_args)
            else:
                self.cmd_thread.handle(partial(callback,
                        self, nick, chan, cmd_args))
                self.state.events["CommandCalledEvent"].fire(self,
                    callback, cmd_args)

    def _check_for_re_command(self, msg, nick, chan):
        for cmd in self.cmdhandler.commands_with_re:
            match = cmd.is_re_triggered_by(msg)
            if match:
                cmd(self, nick, chan, match.groups())
                self.state.events["CommandCalledEvent"].fire(self,
                    cmd, match.groups())

    @staticmethod
    def ctcp(msg):
        """ Turn a message into a CTCP """
        return "\x01%s\x01" % (msg)

    def set_topic(self, channel, topic):
        self.state.channels[channel].topic = topic
        return self._send("TOPIC %s :%s" % (channel, topic))

    @IRCCallback("MODE")
    def mode(self, msg):
        """ Handle MODE. """
        if not msg["arg"].startswith("#"):
            self.state.nick = msg["arg"].split(" ", 1)[0]

    @IRCCallback("332") # RPL_TOPIC
    def newtopic(self, msg):
        nick, chan, topic = msg["arg"].split(" ", 2)
        topic = topic[1:]
        print(chan)
        print(topic)
        self.state.channels.add(chan)

        self.state.channels[chan].topic = topic

    def connect(self):
        """ Connect the bot to the server """
        self.cmd_thread.start()
        if self.getconfig()["ssl"] == True:
            self.sock = ssl.wrap_socket(self.sock)
        super().connect()

    def getconfig(self):
        """ Get the botconfig from another module """
        return self.config

    def gracefully_terminate(self):
        """ Handles the quit routine, then exits. """
        super(James, self).gracefully_terminate()
        self.state.events["ShutdownEvent"].fire()

    @IRCCallback("INVITE")
    def invite(self, msg):
        chan = msg["arg"].split(":", 1)[1]
        bot._send("JOIN %s" % (chan))

    @IRCCallback("JOIN")
    def join(self, msg):
        """ Handles people joining channels """
        user = msg["host"].split("!")[0].strip().lower()
        channel = msg["arg"][1:].strip().lower()
        if user == self.state.nick.lower().strip():
            self.state.channels.add(channel)
            self._send("MODE %s" % (channel))
        self.state.channels[channel].add_user(user)
        self.state.events["JoinEvent"].fire(self, user, channel)
        #self.log.log("[%s] JOIN %s" % (channel, user))

    def msg(self, chan, msg):
        """ msg(string chan, string msg) - Sends a PRIVMSG. """
        msg = msg.strip('\r')
        msg = msg.strip(' ')
        lines = [self.style.merge_colors(self.defaultcolor, line) for line in msg.split('\n')]
        for i in lines:
            print("%r" % (i))
        msg = '\n'.join(lines)
        self._msg(chan, msg)

    @IRCCallback("353") # RPL_NAMREPLY
    def names(self, msg):
        """ Executed on NAMES reply """
        chantype = re.match(r"(=|@|\*).*", msg["arg"].split(" ", 1)[1])
        chantype = chantype.groups()[0]
        args = msg["arg"].split(chantype)[1]
        chan = args.split(":")[0][:-1].strip().lower()
        users = args.split(":")[1].split()
        modes = ["+", "%", "@", "&", "~"]

        users = set([u for u in users if not u[:1] in modes]
            + [u[1:] for u in users if u[:1] in modes])

        channel = self.state.channels.get(chan, False)
        channel.update_users(users)

    @IRCCallback("NOTICE")
    def notice(self, msg):
        """ Handle notices """
        actualargs = msg["arg"].split(" ", 1)[1][1:]
        sender = msg["host"].split("!")[0]
        self.state.notices.append({"sender": sender, "message": actualargs})
        self.state.events["NoticeEvent"].fire(self, sender, actualargs)

    @IRCCallback("NICK")
    def nick(self, msg):
        """ Handles nickchanges """
        oldnick = msg["host"].split("!")[0].lower()
        newnick = msg["arg"][1:].lower()

        if oldnick in self.state.admins:
            self.state.admins.replace(oldnick, newnick)

        if oldnick in self.state.muted:
            self.state.muted.replace(oldnick, newnick)

        if oldnick == self.state.nick:
            self.state.nick = newnick

        for chan in self.state.channels.get_channels_for(oldnick).values():
            chan.change_user((oldnick, newnick))

        if oldnick in self.state.users.keys() and oldnick != newnick:
            self.state.users[newnick] = self.state.users[oldnick]
            del self.state.users[oldnick]

    @IRCCallback("PART")
    def part(self, msg):
        """ Handles people parting channels. """
        channel = msg["arg"].split()[0].strip().lower()
        user = msg["host"].split("!")[0].strip().lower()
        self.state.channels[channel].remove_user(user)
        try:
            #self.log.log("[%s] PART %s" % (channel, user))
            self.state.events["PartEvent"].fire(self, user, channel)
        except BaseException:
            traceback.print_exc()

    @IRCCallback("PRIVMSG")
    def privmsg(self, msg):
        """ Handles messages. """
        # Split msg into parts

        if re.match("\x01(.+?)\x01", msg["arg"]):
            # ctcp
            self.handle_ctcp()
        nick = msg["host"].split("!")[0].lower()  # get sender
        nick_exact = msg["host"].split("!")[0]
        chan = msg["arg"].split()[0]  # get chan
        if not chan.startswith("#"):
            chan = nick  # if chan is a private message, file under them
            self.state.channels.add(chan)
            self.state.channels[chan].update_users({nick})
        chan = chan.lower()
        msg = msg["arg"].split(":", 1)[1]  # get msg

        self.state.events["MessageEvent"].fire(self, nick, chan, msg)

        if nick in self.state.muted and chan.startswith('#'):
            # In this case, we act like the message never happened
            # We ignore mute status in private message, as mute is usually
            # used to make the bot leave people alone.
            return

        self._check_for_command(msg, nick, chan)
        self._check_for_re_command(msg, nick, chan)

        msg = utils.message.Message(nick, self.state.channels[chan], msg)
        if nick in self.state.messages.keys():
            self.state.messages[nick].appendleft(msg)
        else:
            self.state.messages[nick] = deque([msg], MAX_MESSAGE_STORAGE)

        try:
            self.state.users[nick].exactnick = nick_exact
        except:
            traceback.print_exc()

    @IRCCallback("QUIT")
    def quit(self, msg):
        """ Handles quits. """
        nick = msg["host"].split("!")[0].lower()
        for channel in self.state.channels.get_channels_for(nick).values():
            channel.remove_user(nick)
        if self.state.users.get(nick, False):
            del self.state.users[nick]

    @IRCCallback("KICK")
    def kick(self, msg):
        """ Handles kicks. """
        nick = msg["arg"].split()[1].lower()
        chan = msg["arg"].split()[0].lower()
        channel = self.state.channels.get(chan, False)
        if channel:
            try:
                channel.remove_user(nick)
            except:
                traceback.print_exc()
        self.state.events["KickEvent"].fire(self, nick, chan)

    @IRCCallback("376", "422") # ENDOFMOTD or NOMOTD
    def welcome(self, *args):
        """ welcome(msg) - handles on-login actions """
        if self.config["ident_pass"]:
            self._msg(self.config["identify_service"], "identify %s"
                % (self.config["ident_pass"]))
        self._send("MODE %s +B" % (self.state.nick))
        self.state.events["WelcomeEvent"].fire(self)
Example #4
0
class Infobot(IRCHandler):
    """ Infobot main class """
    def __init__(self, config):
        print("Infobot version %s" % (VERSION))
        super().__init__(config, verbose=False)

        self.config = config
        self.nick = config["nick"]

        # Arbitrary bot data
        self.data = {}
        self.auth = None

        self.lock = threading.Lock()
        self.lock.acquire()

        self.events = DotDict({list(i.keys())[0]: Event(list(i.values())[0])
            for i in StandardEvents})

        self.cmd_thread = HandlerThread(self, self.lock)
        self.cmd_thread.daemon = True
        self.register_callbacks()
        self.register_plugins(plugins.get_plugins())

        for item in self.config["admins"]:
            self.auth.addadmin(User(item[0], item[1], item[2]))

    def __repr__(self):
        return "Infobot(server=%r)" % (self.config["server"].split(':')[0])

    def register_callback(self, ctype, func):
        if ctype in self.__irccallbacks__:
            self.__irccallbacks__[ctype].append(func)
        else:
            self.__irccallbacks__[ctype] = [func]

    def _msg(self, chan, msg):
        self.sock.send(b"PRIVMSG ")
        self.sock.send(("%s :%s" % (chan, msg)).encode('utf-8'))
        self.sock.send(b"\r\n")

    def notice(self, chan, msg):
        self.sock.send(b"NOTICE ")
        self.sock.send(("%s :%s" % (chan, msg)).encode('utf-8'))
        self.sock.send(b"\r\n")

    def msg(self, chan, msg):
        msg = str(msg).replace("\r", "")
        if '\n' in msg:
            for item in msg.split("\n"):
                self._msg(chan, item)
        else:
            self._msg(chan, msg)

    @IRCCallback("INVITE")
    def handleinvite(self, pmsg):
        bot._send("JOIN :" + pmsg["arg"].split(":")[1])

    def switch(self):
        self.lock.release()
        time.sleep(0.01)
        self.lock.acquire()

    @IRCCallback("MODE")
    def mode(self, msg):
        """ Handle MODE. """
        if not msg["arg"].startswith("#"):
            self.nick = msg["arg"].split(" ", 1)[0]

    def connect(self):
        self.cmd_thread.start()
        if self.config["ssl"]:
            self.sock = ssl.wrap_socket(self.sock)
        super().connect()

    def msg(self, chan, msg):
        """ Send a message to a channel. """
        self._msg(chan, msg)

    @IRCCallback("PRIVMSG")
    def privmsg(self, msg):
        """ Handles messages. """
        nick = msg["host"].split('!')[0]
        chan = msg["arg"].split()[0]
        chan = chan.lower()
        if not chan.startswith("#"):
            # Private message. File under sender.
            chan = nick
        msg = msg["arg"].split(":", 1)[1]

        self.events.MessageEvent.fire(self, nick, chan, msg)
        print("[main thread:%s] [%s] <%s> %s" % (now(), chan, nick, msg))

    @IRCCallback("NOTICE")
    def notice_listener(self, msg):
        sys.__stdout__.write("[main thread:%s] *%s* %s\n" % (now(), msg["host"], msg["arg"].split(" ", 1)[1][1:]))
        sys.__stdout__.flush()


    def register_plugins(self, plugins):
        for plugin in plugins:
            print("[main thread:%s] processing plugin %s" % (now(), plugin.__file__))
            if hasattr(plugin, "__callbacks__"):
                for k, v in plugin.__callbacks__.items():
                    for i in v:
                        try:
                            self.__irccallbacks__[k].append(i)
                        except KeyError:
                            self.__irccallbacks__[k] = [i]
            if hasattr(plugin, "__inits__"):
                for init in plugin.__inits__:
                    init(self)

    @IRCCallback("376", "422")
    def welcome(self, msg):
        if self.config.get("ident_pass", None):
            self._msg(self.config["ident_service"], "identify %s"
                % (self.config["ident_pass"]))
        self._send("MODE %s +B" % (self.nick))

        for channel in self.config["autojoin"]:
            self._send("JOIN :%s" % (channel))

    def gracefully_terminate(self):
        super().gracefully_terminate()