Beispiel #1
0
    def __init__(self):
        logutils.setup_logging("mustikkabot")
        self.log = logging.getLogger("mustikkabot")

        self.basepath = tools.find_basepath()
        self.confdir = os.path.join(self.basepath, "config")
        self.datadir = os.path.join(self.basepath, "data")
        self.srcdir = os.path.join(self.basepath, "src")

        setup.setup(self)
        setup.do_migrations(self)

        self.ircsock = None
        self.lastReceived = None

        self.user = None
        self.channel = None

        self.eventmanager = EventManager()
        """ :type: EventManager"""
        self.modulemanager = ModuleManager()
        """ :type: ModuleManager"""
        self.accessmanager = AccessManager()
        """ :type: AccessManager"""
        self.timemanager = TimeManager()
        """ :type: TimeManager"""

        self.run = True
Beispiel #2
0
class Bot:
    """
    Mainclass for the application, everything goes through here
    """

    def __init__(self):
        logutils.setup_logging("mustikkabot")
        self.log = logging.getLogger("mustikkabot")

        self.basepath = tools.find_basepath()
        self.confdir = os.path.join(self.basepath, "config")
        self.datadir = os.path.join(self.basepath, "data")
        self.srcdir = os.path.join(self.basepath, "src")

        setup.setup(self)
        setup.do_migrations(self)

        self.ircsock = None
        self.lastReceived = None

        self.user = None
        self.channel = None

        self.eventmanager = EventManager()
        """ :type: EventManager"""
        self.modulemanager = ModuleManager()
        """ :type: ModuleManager"""
        self.accessmanager = AccessManager()
        """ :type: AccessManager"""
        self.timemanager = TimeManager()
        """ :type: TimeManager"""

        self.run = True

    def parse_config(self):
        """
        :return: list of strings describing parameters
        :rtype: list(string, string, string, string)

        Parse the config file, and read the different defined parameters. Return them as a list
        """
        try:
            settings_f = open(os.path.join(self.confdir, "config.txt"))
        except IOError:
            self.log.error("Config not found, please make a copy of"
                           " \"config/config.txt.template\" as \"config/config.txt\"")
            sys.exit()

        host = None
        username = None
        password = None
        channel = None

        try:
            for line in settings_f:
                line = line.strip("\n\r")
                if line.find('host') != -1:
                    host = line.split(":")[1]
                if line.find('user') != -1:
                    username = line.split(":")[1]
                if line.find('pass') != -1:
                    password = ':'.join(line.split(":")[1:])
                if line.find('chnl') != -1:
                    channel = line.split(":")[1]
        except IndexError:
            self.log.error("Malformed config file, please fix")
            sys.exit()

        settings_f.close()

        passwd_hidden = ""

        for c in password:            # Hide auth token/password from log messages
            passwd_hidden += '*'

        self.log.info("PARAMETERS: Host: %s, username: %s, password: %s, channel: %s" %
                      (host, username, passwd_hidden, channel))

        return host, username, password, channel

    def connect(self, params):
        """
        :param params: A list of the params to be used to connect
        :type params: list(string, string, string, string)

        Try to connect to the IRC server using the provided parameters
        """
        try:
            self.ircsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.ircsock.settimeout(30)

            self.ircsock.connect((params[0], 6667))

            self.ircsock.setblocking(0)

            self.send_data("PASS %s" % (params[2]), dontLog=True)
            self.send_data("NICK %s" % (params[1]))
            self.send_data("USER %s mustikkaBot 127.0.0.1 :mustikkaBot" % (params[1]))
            self.send_data("JOIN %s" % (params[3]))
        except Exception as e:
            traceback.print_exc()

            self.log.error("\n\nError connecting: %s" % e)
            sys.exit()

    def get_data(self):
        """
        :return: Data received from the socket
        :rtype: str

        Return any data that has been received
        """

        try:
            data = self.ircsock.recv(1024)
            data = data.decode("utf-8", "replace").strip('\r\n')
            if not len(data) == 0:
                self.log.debug("RECV: <>" + data + "<>")
            return data
        except socket.error as e:
            err = e.args[0]
            if err == errno.EAGAIN or err == errno.EWOULDBLOCK:
                return ""  # no data

    def send_data(self, data, dontLog=False):
        """
        :param data: String to be sent
        :type data: str
        :param dontLog: Will the string be logged?
        :type dontLog: bool

        Send data appended with a newline
        """
        if not (data is "" or data is None):
            if not dontLog:
                self.log.debug("SEND: " + data)
            self.ircsock.send(bytes(data + "\n", "UTF-8"))

    def send_message(self, msg):
        """
        :param msg: Message to be sent
        :type msg: str

        Send a message to the channel
        """
        self.send_data("PRIVMSG " + self.channel + " :" + msg)

    def sigint(self, signal, frame):
        """
        :param signal: Signal received
        :param frame: ...

        A signal handler to trap ^C
        """
        self.log.info("^C received, stopping")
        self.run = False

    def main(self):
        """
        The startpoint of the bot
        """
        settings = self.parse_config()

        self.user = settings[1]
        self.channel = settings[3]

        self.accessmanager.init(self)
        self.modulemanager.init(self)

        try:
            self.connect(settings)
            self.lastReceived = datetime.datetime.now()
        except:
            self.log.error("Error connecting to IRC")
            sleep(3)

        signal.signal(signal.SIGINT, self.sigint)

        sleep(1)

        while self.run:
            # Get new data
            ircmsg = self.get_data()

            # Process CLI
            if platform.system() != "Windows":
                cli = select.select([sys.stdin], [], [], 0)[0]
            else:
                cli = False         # No cli on windows because you can't select stdin
            if cli:
                data = sys.stdin.readline().strip()
                if len(data) > 0:
                    self.eventmanager.handle_message(":[email protected] PRIVMSG " + self.channel + " :" + data)

            # Handle data if received
            if not (ircmsg is None or len(ircmsg) == 0):
                for line in ircmsg.split('\n'):
                    self.lastReceived = datetime.datetime.now()
                    if line.find(' PRIVMSG ') != -1:
                        self.eventmanager.handle_message(line)
                    else:
                        self.eventmanager.handle_special(line)

            # Provied timed events to timemanager
            self.timemanager.handle_events()

            # Check "watchdog"
            if self.lastReceived and datetime.datetime.now() - self.lastReceived > datetime.timedelta(minutes=15):
                self.log.warning("No messages received within 15 minutesr, trying to reconnect")
                try:
                    self.connect(settings)  # Reconnect
                    self.lastReceived = datetime.datetime.now()
                except:
                    self.log.error("Error connecting to IRC")
                    sleep(3)

            sleep(0.01)

        # Shut down
        self.modulemanager.dispose()
        self.accessmanager.dispose()