def on_whoisuser(self, connection, raw_msg): """ called by super() when WHOIS response arrives """ self._call_plugins_methods('whoisuser', raw_msg=raw_msg, nick=irc_nickname(raw_msg.arguments[0]), user=irc_nickname(raw_msg.arguments[1]), host=irc_nickname(raw_msg.arguments[2]))
def on_nick(self, connection, raw_msg): """ called by super() when somebody changes nickname """ self._call_plugins_methods('nick', raw_msg=raw_msg, source=raw_msg.source, old_nickname=irc_nickname( raw_msg.source.nick), new_nickname=irc_nickname(raw_msg.target))
def get_ops(self) -> list: with self._db_mutex: self._db_cursor.execute( f"SELECT nickname FROM '{self._db_ops_tablename}'") result = self._db_cursor.fetchall() return [irc_nickname(n[0]) for n in result] + [self.config['superop']]
def command_impl(self, sender_nick, **kwargs): sender_nick = irc_nickname(sender_nick) if hasattr(command_impl, '__superadmin' ) and sender_nick != self.bot.config['superop']: self.logger.info( f'{sender_nick} is not superop, skipping command') self.bot.say(f"{sender_nick}: you're not bot owner, sorry!") return if hasattr(command_impl, '__admin') and not self.bot.is_user_op(sender_nick): self.logger.info(f'{sender_nick} is not op, skipping command') self.bot.say(f"{sender_nick}: you're not bot operator, sorry!") return if hasattr(command_impl, '__channel_op' ) and not self.bot.get_channel().is_oper(sender_nick): self.logger.info( f'{sender_nick} is not channel operator, skipping command') self.bot.say( f"{sender_nick}: you're not channel operator, sorry!") return try: function(self, sender_nick=sender_nick, **kwargs) except Exception as e: self.logger.error( f'exception caught calling {function.__qualname__}: {type(e).__name__}: {e}' ) self.bot.say('internal error, sorry :(') if self.bot.is_debug_mode_enabled(): raise
def get_ignored_users(self) -> list: with self._db_mutex: self._db_cursor.execute( f"SELECT nickname FROM '{self._db_ignored_users_tablename}'") result = self._db_cursor.fetchall() return [irc_nickname(n[0]) for n in result]
def on_mode(self, _, raw_msg): """ called by super() when someone's mode changed """ self._call_plugins_methods('mode', raw_msg=raw_msg, source=raw_msg.source, who=irc_nickname(raw_msg.arguments[1]), mode_change=raw_msg.arguments[0])
def on_nicknameinuse(self, connection, raw_msg): """ called by super() when given nickname is reserved """ nickname = irc_nickname(self.config['nickname'][self._nickname_id]) self._nickname_id += 1 if self._nickname_id >= len(self.config['nickname']): self.logger.critical( f'nickname {nickname} is busy, no more nicknames to use') sys.exit(2) new_nickname = irc_nickname(self.config['nickname'][self._nickname_id]) self.logger.warning( f'nickname {nickname} is busy, using {new_nickname}') self._call_plugins_methods('nicknameinuse', raw_msg=raw_msg, busy_nickname=nickname) self.connection.nick(new_nickname) self._login()
def add_op(self, nickname): if self.is_user_ignored(nickname): self.unignore_user(nickname) if irc_nickname(nickname) == self.config['superop']: return with self._db_mutex: self._db_cursor.execute( f"INSERT OR REPLACE INTO '{self._db_ops_tablename}' VALUES (?)", (nickname, )) self._db_connection.commit()
def on_pubmsg(self, connection, raw_msg): """ called by super() when msg received """ full_msg = raw_msg.arguments[0].strip() sender_nick = irc_nickname(raw_msg.source.nick) if self.is_user_ignored(sender_nick): self.logger.debug(f'user {sender_nick} is ignored, skipping msg') return self._call_plugins_methods('pubmsg', raw_msg=raw_msg, source=raw_msg.source, msg=full_msg) raw_cmd = msg_parser.trim_msg(self.config['command_prefix'], full_msg) if not raw_cmd: raw_cmd = msg_parser.trim_msg(self.get_nickname() + ':', full_msg) if not raw_cmd: raw_cmd = msg_parser.trim_msg(self.get_nickname() + ',', full_msg) args_list = raw_cmd.split() cmd = args_list[0].strip() if len(args_list) > 0 else '' args_list = args_list[1:] assert raw_cmd.startswith(cmd) raw_cmd = raw_cmd[len(cmd):].strip() if cmd in self.commands: func = self.commands[cmd] self.logger.debug( f'calling command {func.__qualname__}(sender_nick={sender_nick}, args={args_list}, msg=\'{raw_cmd}\', raw_msg=...)...' ) func(sender_nick=sender_nick, args=args_list, msg=raw_cmd, raw_msg=raw_msg) elif self.config['try_autocorrect'] and cmd: possible_cmd = self._get_best_command_match(cmd, sender_nick) if possible_cmd: self.say( f"no such command: {cmd}, did you mean '{possible_cmd}'?") else: self.say(f'no such command: {cmd}') for reg in self.msg_regexes: regex_search_result = reg.findall(full_msg) if regex_search_result: for func in self.msg_regexes[reg]: self.logger.debug( f'calling message regex handler {func.__qualname__}(sender_nick={sender_nick}, msg=\'{full_msg}\', reg_res={regex_search_result}, raw_msg=...)...' ) func(sender_nick=sender_nick, msg=full_msg, reg_res=regex_search_result, raw_msg=raw_msg)
def rm_op(self, nickname): """ throws RuntimeError when nickname is superop """ if irc_nickname(nickname) == self.config['superop']: raise RuntimeError('cannot remove superop') with self._db_mutex: self._db_cursor.execute( f"DELETE FROM '{self._db_ops_tablename}' WHERE nickname = ? COLLATE NOCASE", (nickname, )) self._db_connection.commit()
def on_namreply(self, _, raw_msg): """ called by super() when NAMES response arrives """ nickname_prefixes = '~&@%+' nicks = raw_msg.arguments[2].split() for i in range(0, len(nicks)): for prefix in nickname_prefixes: if nicks[i].startswith(prefix): nicks[i] = nicks[i][1:].strip() nicks[i] = irc_nickname(nicks[i]) self._call_plugins_methods('namreply', raw_msg=raw_msg, nicknames=nicks)
def _can_user_call_command(self, nickname, command_name): nickname = irc_nickname(nickname) func = self.get_commands()[command_name] if hasattr(func, '__admin') and not self.is_user_op(nickname): return False if hasattr(func, '__superadmin') and nickname != self.config['superop']: return False if hasattr( func, '__channel_op') and not self.get_channel().is_oper(nickname): return False return True
def on_privmsg(self, connection, raw_msg): """ called by super() when private msg received """ full_msg = raw_msg.arguments[0] sender_nick = irc_nickname(raw_msg.source.nick) logging.info(f'[PRIVATE MSG] {sender_nick}: {full_msg}') if self.is_user_ignored(sender_nick): self.logger.debug(f'user {sender_nick} is ignored, skipping msg') return self._call_plugins_methods('privmsg', raw_msg=raw_msg, source=raw_msg.source, msg=full_msg)
def admin_impl(self, sender_nick, **kwargs): sender_nick = irc_nickname(sender_nick) if sender_nick in self.bot.config['ops']: function(self, sender_nick=sender_nick, **kwargs) else: self.logger.info(f'{sender_nick} is not op, skipping command')
def get_nickname(self): return irc_nickname(self.connection.get_nickname())
def is_user_ignored(self, nickname): nickname = irc_nickname(nickname) return ('ignored_users' in self.config and nickname in self.config['ignored_users']) and ( nickname not in self.config['ops'])
def on_pubmsg(self, _, raw_msg): """ called by super() when msg received """ full_msg = raw_msg.arguments[0].strip() sender_nick = irc_nickname(raw_msg.source.nick) self._call_plugins_methods('pubmsg', raw_msg=raw_msg, source=raw_msg.source, msg=full_msg) if self.is_user_ignored(sender_nick): self._logger.debug(f'user {sender_nick} is ignored, skipping msg') return args = msg_parser.trim_msg(self.get_command_prefix(), full_msg) if not args: args = msg_parser.trim_msg(self.get_nickname() + ':', full_msg) if not args: args = msg_parser.trim_msg(self.get_nickname() + ',', full_msg) # fix should not affect msg regexps reg_raw_msg = raw_msg reg_full_msg = full_msg if args and args.split()[0].strip() == 'fix': fixed_command = self._get_fixed_command() if 'builtins' not in self.get_plugins_names( ) or 'fix' not in self.get_plugin_commands('builtins'): pass elif not self._can_user_call_command(sender_nick, 'fix'): pass elif not fixed_command: self.say('no fix available') args = '' # to disable further cmd executing else: self._logger.info( f'fixing command for {sender_nick}: {fixed_command}') args = fixed_command self.register_fixed_command(None) raw_msg = None full_msg = None else: if self.config['use_fix_tip']: with self._fixed_command_lock: fixed_command = self._get_fixed_command() if not self._use_fix_tip_given and fixed_command and self.get_command_prefix( ) + fixed_command.strip() == full_msg.strip(): self._use_fix_tip_given = True use_fix_responses = [ '%s: why u no %s?', 'hey, %s, use %s!', '%s: use %s to fix your previous command', "%s: you're making %s feature sad" ] self.say( random.choice(use_fix_responses) % (sender_nick, f'{self.get_command_prefix()}fix')) args_list = args.split() cmd = args_list[0].strip() if args_list else '' args_list = args_list[1:] assert args.startswith(cmd) args = args[len(cmd):].strip() # !set entry some msg # cmd == "set" # full_msg == "!set entry some msg" # args == "entry some msg" # args_list == ["some", "msg"] # raw_msg == IRC Event class if cmd in self.get_commands(): func = self.get_commands()[cmd] self._logger.debug( f'calling command {func.__qualname__}(sender_nick={sender_nick}, args={args_list}, msg=\'{args}\', raw_msg=...)...' ) func(sender_nick=sender_nick, args=args_list, msg=args, raw_msg=raw_msg) elif self.config['try_autocorrect'] and cmd and len( cmd) > 0 and cmd[0].isalpha(): possible_cmd = self._get_best_command_match(cmd, sender_nick) if possible_cmd: self.say( f"no such command: {cmd}, did you mean '{possible_cmd}'?") if possible_cmd != 'fix': self.register_fixed_command(f'{possible_cmd} {args}') else: self.say(f'no such command: {cmd}') with self._plugins_lock: for reg in self._msg_regexps: regex_search_result = reg.findall(reg_full_msg) if regex_search_result: for func in self._msg_regexps[reg]: self._logger.debug( f'calling message regex handler {func.__qualname__}(sender_nick={sender_nick}, msg=\'{reg_full_msg}\', reg_res={regex_search_result}, raw_msg=...)...' ) func(sender_nick=sender_nick, msg=reg_full_msg, reg_res=regex_search_result, raw_msg=reg_raw_msg)
def is_user_op(self, nickname): return irc_nickname(nickname) in self.get_ops()
def is_user_ignored(self, nickname): return irc_nickname(nickname) in self.get_ignored_users( ) and not self.is_user_op(nickname)
def get_usernames_on_channel(self) -> list: """ :return: names of users in channel """ return [irc_nickname(x) for x in list(self.get_channel().users())]