예제 #1
0
    def handle_events(self, msg):
        if msg["command"] != "PRIVMSG" or not msg["origin"]:
            return

        sender_nick = msg["origin"].split('@')[0].split('!')[0]
        recipient = msg["args"][0]
        text = msg["args"][1]

        if recipient != self.config.get("nick"):
            return

        #: HANDLE CTCP ANTI FLOOD/BOT PROTECTION
        if text[0] == '\x01' and text[-1] == '\x01':  #: CTCP
            ctcp_data = text[1:-1].split(' ', 1)
            ctcp_command = ctcp_data[0]
            ctcp_args = ctcp_data[1] if len(ctcp_data) > 1 else ""

            if ctcp_command == "VERSION":
                self.log_debug("Sending CTCP VERSION")
                self.sock.send(
                    to_bytes("NOTICE {} :{}\r\n".format(
                        msg["origin"], "pyLoad! IRC Interface")))
                return
            elif ctcp_command == "TIME":
                self.log_debug("Sending CTCP TIME")
                self.sock.send(
                    to_bytes("NOTICE {} :{}\r\n".format(
                        msg["origin"], time.time())))
                return
            elif ctcp_command == "PING":
                self.log_debug("[{}] Ping? Pong!".format(sender_nick))
                self.sock.send(
                    to_bytes("NOTICE {} :\x01PING {}\x01\r\n".format(
                        sender_nick, ctcp_args)))  #@NOTE: PING is not a typo
            elif ctcp_command == "LAG":
                self.log_debug(
                    "Received CTCP LAG")  #: don't know how to answer
                return

        if sender_nick not in self.config.get("owner").split():
            return

        temp = text.split()
        try:
            command = temp[0]
            args = text.split()[1:]

        except IndexError:
            command = "error"
            args = []

        try:
            res = self.do_bot_command(command, args)

            for line in res:
                self.response(line, msg["origin"])
                time.sleep(1)  #: avoid Excess Flood

        except Exception as exc:
            self.log_error(exc)
예제 #2
0
    def run(self):
        #: Connect to IRC etc.
        self.sock = socket.socket()
        host = self.config.get("host")
        self.sock.connect((host, self.config.get("port")))

        if self.config.get("ssl"):
            self.sock = ssl.wrap_socket(
                self.sock,
                cert_reqs=ssl.CERT_NONE)  # TODO: support certificate

        nick = self.config.get("nick")
        self.log_info(self._("Connecting as"), nick)
        self.sock.send(to_bytes("NICK {}\r\n".format(nick)))
        self.sock.send(
            to_bytes("USER {} {} bla :{}\r\n".format(nick, host, nick)))
        self.log_info(self._("Connected to"), host)
        for t in self.config.get("owner").split():
            if t.startswith("#"):
                self.sock.send(to_bytes("JOIN {}\r\n".format(t)))
                self.log_info(self._("Joined channel {}").format(to_str(t)))
        self.log_info(self._("Switching to listening mode!"))
        try:
            self.main_loop()

        except IRCError:
            self.sock.send(b"QUIT :byebye\r\n")
            self.sock.close()
예제 #3
0
 def response(self, msg, origin=""):
     if origin == "":
         for t in self.config.get("owner").split():
             self.sock.send(
                 to_bytes("PRIVMSG {} :{}\r\n".format(t.strip(), msg)))
     else:
         self.sock.send(
             to_bytes("PRIVMSG {} :{}\r\n".format(
                 origin.split("!", 1)[0], msg)))
예제 #4
0
파일: XDCC.py 프로젝트: saschawitte/pyload
    def get_irc_command(self):
        origin, command, args = None, None, None
        while True:
            line = self._get_response_line()
            origin, command, args = self._parse_irc_msg(line)

            if command == "PING":
                self.plugin.log_debug(f"[{args[0]}] Ping? Pong!")
                self.irc_sock.send(to_bytes("PONG :{}\r\n".format(args[0])))

            elif origin and command == "PRIVMSG":
                sender_nick = origin.split("@")[0].split("!")[0]
                recipient = args[0]
                text = args[1]

                if text[0] == "\x01" and text[-1] == "\x01":  #: CTCP
                    ctcp_data = text[1:-1].split(" ", 1)
                    ctcp_command = ctcp_data[0]
                    ctcp_args = ctcp_data[1] if len(ctcp_data) > 1 else ""

                    if recipient[0:len(self.nick)] == self.nick:
                        if ctcp_command == "VERSION":
                            self.plugin.log_debug(
                                self._("[{}] CTCP VERSION").format(
                                    sender_nick))
                            self.irc_sock.send(
                                to_bytes(
                                    "NOTICE {} :\x01VERSION {}\x01\r\n".format(
                                        sender_nick, "pyLoad! IRC Interface")))

                        elif ctcp_command == "TIME":
                            self.plugin.log_debug(
                                self._("[{}] CTCP TIME").format(sender_nick))
                            self.irc_sock.send(
                                to_bytes("NOTICE {} :\x01{}\x01\r\n".format(
                                    sender_nick,
                                    time.strftime("%a %b %d %H:%M:%S %Y"))))

                        elif ctcp_command == "PING":
                            self.plugin.log_debug(
                                self._("[{}] Ping? Pong!").format(sender_nick))
                            self.irc_sock.send(
                                to_bytes(
                                    "NOTICE {} :\x01PING {}\x01\r\n".format(
                                        sender_nick, ctcp_args))
                            )  # NOTE: PING is not a typo

                        else:
                            break

                else:
                    break

            else:
                break

        return origin, command, args
예제 #5
0
    def main_loop(self):
        readbuffer = b""
        while True:
            time.sleep(1)
            fdset = select.select([self.sock], [], [], 0)
            if self.sock not in fdset[0]:
                continue

            if self.abort:
                raise IRCError("quit")

            readbuffer += self.sock.recv(1 << 10)
            temp = readbuffer.split(b"\n")
            readbuffer = temp.pop()

            for line in temp:
                line = line.rstrip()
                origin, command, args = parse_irc_msg(line)

                if command == "PING":
                    self.log_debug("[{}] Ping? Pong!".format(args[0]))
                    self.sock.send(to_bytes("PONG :{}\r\n".format(args[0])))

                if command == "ERROR":
                    raise IRCError(line)

                msg = {
                    "origin": origin,
                    "command": command,
                    "args": args,
                }

                self.handle_events(msg)
예제 #6
0
    def is_bot_online(self, bot):
        self.plugin.log_info(self._("Checking if bot '{}' is online").format(bot))
        self.irc_sock.send(to_bytes("WHOIS {}\r\n".format(bot)))

        start_time = time.time()
        while time.time() - start_time < 30:
            origin, command, args = self.get_irc_command()
            if (
                command == "401"
                and args[0] == self.nick
                and args[1].lower() == bot.lower()
            ):  #: ERR_NOSUCHNICK
                self.plugin.log_debug(f"Bot '{bot}' is offline")
                return False

            #: RPL_WHOISUSER
            elif (
                command == "311"
                and args[0] == self.nick
                and args[1].lower() == bot.lower()
            ):
                self.plugin.log_debug(f"Bot '{bot}' is online")
                self.bot_host[bot] = args[3]  #: bot host
                return True

            else:
                time.sleep(0.1)

        else:
            self.plugin.log_error(self._("Server did not respond in a reasonable time"))
            return False
예제 #7
0
    def join_channel(self, chan):
        chan = "#" + chan if chan[0] != "#" else chan

        self.plugin.log_info(self._("Joining channel {}").format(chan))
        self.irc_sock.send(to_bytes("JOIN {}\r\n".format(chan)))

        start_time = time.time()
        while time.time() - start_time < 30:
            origin, command, args = self.get_irc_command()

            #: ERR_KEYSET, ERR_CHANNELISFULL, ERR_INVITEONLYCHAN, ERR_BANNEDFROMCHAN, ERR_BADCHANNELKEY
            if (
                command in ("467", "471", "473", "474", "475")
                and args[1].lower() == chan.lower()
            ):
                self.plugin.log_error(
                    self._("Cannot join channel {} (error {}: '{}')").format(
                        chan, command, args[2]
                    )
                )
                return False

            elif command == "353" and args[2].lower() == chan.lower():  #: RPL_NAMREPLY
                self.plugin.log_debug(f"Successfully joined channel {chan}")
                return True

        return False
예제 #8
0
    def xdcc_get_pack_info(self, bot, pack):
        bot_host = self.get_bot_host(bot)

        self.plugin.log_info(self._("Requesting pack #{} info").format(pack))
        self.irc_sock.send(to_bytes("PRIVMSG {} :xdcc info #{}\r\n".format(bot, pack)))

        info = {}
        start_time = time.time()
        while time.time() - start_time < 90:
            origin, command, args = self.get_irc_command()

            # Private message from bot to us?
            if (
                origin
                and command
                and args
                and (
                    origin[0 : len(bot)] == bot
                    or bot_host
                    and origin.split("@")[1] == bot_host
                )
                and args[0][0 : len(self.nick)] == self.nick
                and command in ("PRIVMSG", "NOTICE")
            ):

                try:
                    text = str(args[1], "utf-8")
                except UnicodeDecodeError:
                    text = str(args[1], "latin1", "replace")

                pack_info = text.split()
                if pack_info[0].lower() == "filename":
                    self.plugin.log_debug(f"Filename: '{pack_info[1]}'")
                    info.update({"status": "online", "name": pack_info[1]})

                elif pack_info[0].lower() == "filesize":
                    self.plugin.log_debug(f"Filesize: '{pack_info[1]}'")
                    info.update({"status": "online", "size": pack_info[1]})

                else:
                    sender_nick = origin.split("@")[0].split("!")[0]
                    self.plugin.log_debug(
                        self._("PrivMsg: <{}> {}").format(sender_nick, text)
                    )

            else:
                if len(info) > 2:  #: got both name and size
                    break

                time.sleep(0.1)

        else:
            if len(info) == 0:
                self.plugin.log_error(
                    self._("XDCC Bot '{}' did not answer").format(bot)
                )
                return {"status": "offline", "msg": "XDCC Bot did not answer"}

        return info
예제 #9
0
파일: XDCC.py 프로젝트: saschawitte/pyload
    def xdcc_request_resume(self, bot, dcc_port, file_name, resume_position):
        if self.xdcc_request_time:
            bot_host = self.get_bot_host(bot)

            self.plugin.log_info(
                self._("Requesting XDCC resume of '{}' at position {}").format(
                    file_name, resume_position))

            self.irc_sock.send(
                to_bytes(
                    'PRIVMSG {} :\x01DCC RESUME "{}" {} {}\x01\r\n'.format(
                        bot, os.fsdecode(file_name), dcc_port,
                        resume_position)))

            start_time = time.time()
            while time.time() - start_time < 30:
                origin, command, args = self.get_irc_command()

                # Private message from bot to us?
                if (origin and command and args and "@" in origin
                        and (origin[0:len(bot)] == bot
                             or bot_host and origin.split("@")[1] == bot_host)
                        and args[0][0:len(self.nick)] == self.nick
                        and command in ("PRIVMSG", "NOTICE")):

                    try:
                        text = str(args[1], "utf-8")
                    except UnicodeDecodeError:
                        text = str(args[1], "latin1", "replace")

                    sender_nick = origin.split("@")[0].split("!")[0]
                    self.plugin.log_debug(
                        self._("PrivMsg: <{}> {}").format(sender_nick, text))

                    m = re.match(
                        r"\x01DCC ACCEPT .*? {} (?P<RESUME_POS>\d+)\x01".
                        format(dcc_port),
                        text,
                    )
                    if m:
                        self.plugin.log_debug(
                            self._(
                                "Bot '{}' acknowledged resume at position {}").
                            format(sender_nick, m.group("RESUME_POS")))
                        return int(m.group("RESUME_POS"))

                else:
                    time.sleep(0.1)

            self.plugin.log_warning(
                self.
                _("Timeout while waiting for resume acknowledge, not resuming"
                  ))

        else:
            self.plugin.log_error(
                self._("No XDCC request pending, cannot resume"))

        return 0
예제 #10
0
    def xdcc_cancel_pack(self, bot):
        if self.xdcc_request_time:
            self.plugin.log_info(self._("Requesting XDCC cancellation"))
            self.xdcc_request_time = None
            self.irc_sock.send(to_bytes("PRIVMSG {} :xdcc cancel\r\n".format(bot)))

        else:
            self.plugin.log_warning(self._("No XDCC request pending, cannot cancel"))
예제 #11
0
    def connect_server(self, host, port):
        """
        Connect to the IRC server and wait for RPL_WELCOME message.
        """
        if self.connected:
            self.plugin.log_warning(
                self._("Already connected to server, not connecting")
            )
            return False

        self.plugin.log_info(self._("Connecting to: {}:{}").format(host, port))

        self.irc_sock.settimeout(30)
        self.irc_sock.connect((host, port))
        self.irc_sock.settimeout(None)

        self.irc_sock.send(to_bytes("NICK {}\r\n".format(self.nick)))
        self.irc_sock.send(
            to_bytes("USER {} {} bla :{}\r\n".format(self.ident, host, self.realname))
        )

        start_time = time.time()
        while time.time() - start_time < 30:
            origin, command, args = self.get_irc_command()
            if command == "001":  #: RPL_WELCOME
                self.connected = True
                self.host = host
                self.port = port

                start_time = time.time()
                while (
                    self._get_response_line() and time.time() - start_time < 30
                ):  #: Skip MOTD
                    pass

                self.plugin.log_debug(
                    self._("Successfully connected to {}:{}").format(host, port)
                )

                return True

        self.plugin.log_error(self._("Connection to {}:{} failed").format(host, port))

        return False
예제 #12
0
    def check_download(self):
        check = self.scan_download(
            {"dl_limit": to_bytes(self.DL_LIMIT_PATTERN)})

        if check == "dl_limit":
            self.log_warning(self._("Free download limit reached"))
            os.remove(self.last_download)
            self.retry(wait=10800, msg=self._("Free download limit reached"))

        return super().check_download()
예제 #13
0
    def send_invite_request(self, bot, chan, password):
        bot_host = self.get_bot_host(bot)
        if bot_host:
            self.plugin.log_info(
                self._("Sending invite request for #{} to '{}'").format(chan, bot)
            )
        else:
            self.plugin.log_warning(self._("Cannot send invite request"))
            return

        self.irc_sock.send(
            to_bytes("PRIVMSG {} :enter #{} {} {}\r\n".format(bot, chan, self.nick, password))
        )
        start_time = time.time()
        while time.time() - start_time < 30:
            origin, command, args = self.get_irc_command()

            if origin is None or command is None or args is None:
                return

            # Private message from bot to us?
            if (
                "@" not in origin
                or (origin[0 : len(bot)] != bot and origin.split("@")[1] != bot_host)
                or args[0][0 : len(self.nick)] != self.nick
                or command not in ("PRIVMSG", "NOTICE", "INVITE")
            ):
                continue

            try:
                text = str(args[1], "utf-8")
            except UnicodeDecodeError:
                text = str(args[1], "latin1", "replace")

            sender_nick = origin.split("@")[0].split("!")[0]
            if command == "INVITE":
                self.plugin.log_info(self._("Got invite to #{}").format(chan))

            else:
                self.plugin.log_info(
                    self._("PrivMsg: <{}> {}").format(sender_nick, text)
                )

            break

        else:
            self.plugin.log_warning(
                self._("'{}' did not respond to the request").format(bot)
            )
예제 #14
0
    def nickserv_identify(self, password):
        self.plugin.log_info(self._("Authenticating nickname"))

        bot = "nickserv"
        bot_host = self.get_bot_host(bot)

        if not bot_host:
            self.plugin.log_warning(
                self._("Server does not seems to support nickserv commands")
            )
            return

        self.irc_sock.send(to_bytes("PRIVMSG {} :identify {}\r\n".format(bot, password)))

        start_time = time.time()
        while time.time() - start_time < 30:
            origin, command, args = self.get_irc_command()

            if origin is None or command is None or args is None:
                return

            # Private message from bot to us?
            if (
                "@" not in origin
                or (origin[0 : len(bot)] != bot and origin.split("@")[1] != bot_host)
                or args[0][0 : len(self.nick)] != self.nick
                or command not in ("PRIVMSG", "NOTICE")
            ):
                continue

            try:
                text = str(args[1], "utf-8")
            except UnicodeDecodeError:
                text = str(args[1], "latin1", "replace")

            sender_nick = origin.split("@")[0].split("!")[0]
            self.plugin.log_info(self._("PrivMsg: <{}> {}").format(sender_nick, text))
            break

        else:
            self.plugin.log_warning(
                self._("'{}' did not respond to the request").format(bot)
            )
예제 #15
0
 def xdcc_request_pack(self, bot, pack):
     self.plugin.log_info(self._("Requesting pack #{}").format(pack))
     self.xdcc_request_time = time.time()
     self.irc_sock.send(to_bytes("PRIVMSG {} :xdcc send #{}\r\n".format(bot, pack)))