def handle_command(self, event): """Handle command messages""" # is commands_enabled? config_commands_enabled = self.bot.get_config_suboption(event.conv_id, 'commands_enabled') tagged_ignore = "ignore" in self.bot.tags.useractive(event.user_id.chat_id, event.conv_id) if not config_commands_enabled or tagged_ignore: admins_list = self.bot.get_config_suboption(event.conv_id, 'admins') or [] # admins always have commands enabled if event.user_id.chat_id not in admins_list: return # ensure bot alias is always a list if not isinstance(self.bot_command, list): self.bot_command = [self.bot_command] # check that a bot alias is used e.g. /syrupbot if not event.text.split()[0].lower() in self.bot_command: return # Parse message event.text = event.text.replace(u'\xa0', u' ') # convert non-breaking space in Latin1 (ISO 8859-1) try: line_args = shlex.split(event.text, posix=False) except Exception as e: logger.exception(e) yield from self.bot.coro_send_message(event.conv, _("{}: {}").format( event.user.full_name, str(e))) return # Test if command length is sufficient if len(line_args) < 2: yield from self.bot.coro_send_message(event.conv, _('{}: Missing parameter(s)').format( event.user.full_name)) return commands = command.get_available_commands(self.bot, event.user.id_.chat_id, event.conv_id) supplied_command = line_args[1].lower() if supplied_command in commands["user"]: pass elif supplied_command in commands["admin"]: pass elif supplied_command in command.commands: yield from command.blocked_command(self.bot, event, *line_args[1:]) return else: yield from command.unknown_command(self.bot, event, *line_args[1:]) return # Run command results = yield from command.run(self.bot, event, *line_args[1:]) if "acknowledge" in dir(event): for id in event.acknowledge: yield from self.run_reprocessor(id, event, results)
def help(bot, event, cmd=None, *args): """list supported commands, /devilbot help <command> will show additional details""" help_lines = [] link_to_guide = bot.get_config_suboption(event.conv_id, 'link_to_guide') admins_list = bot.get_config_suboption(event.conv_id, 'admins') if not cmd or (cmd=="impersonate" and event.user.id_.chat_id in admins_list): help_chat_id = event.user.id_.chat_id help_conv_id = event.conv_id if cmd == "impersonate": if len(args) == 1: [help_chat_id] = args elif len(args) == 2: [help_chat_id, help_conv_id] = args else: raise ValueError("impersonation: supply chat id and optional conversation id") help_lines.append(_('<b>Impersonation:</b><br />' '<b><pre>{}</pre></b><br />' '<b><pre>{}</pre></b><br />').format( help_chat_id, help_conv_id )) commands = command.get_available_commands(bot, help_chat_id, help_conv_id) commands_admin = commands["admin"] commands_nonadmin = commands["user"] if len(commands_nonadmin) > 0: help_lines.append(_('<b>User commands:</b>')) help_lines.append(', '.join(sorted(commands_nonadmin))) if link_to_guide: help_lines.append('') help_lines.append(_('<i>For more information, please see: {}</i>').format(link_to_guide)) if len(commands_admin) > 0: help_lines.append('') help_lines.append(_('<b>Admin commands:</b>')) help_lines.append(', '.join(sorted(commands_admin))) else: if cmd in command.commands: command_fn = command.commands[cmd] elif cmd.lower() in command.commands: command_fn = command.commands[cmd.lower()] else: yield from command.unknown_command(bot, event) return help_lines.append("<b>{}</b>: {}".format(command_fn.__name__, command_fn.__doc__)) yield from bot.coro_send_to_user_and_conversation( event.user.id_.chat_id, event.conv_id, "<br />".join(help_lines), # via private message _("<i>{}, I've sent you some help ;)</i>") # public message .format(event.user.full_name))
def help(bot, event, cmd=None, *args): """list supported commands, /bot help <command> will show additional details""" help_lines = [] link_to_guide = bot.get_config_suboption(event.conv_id, 'link_to_guide') admins_list = bot.get_config_suboption(event.conv_id, 'admins') if not cmd or (cmd=="impersonate" and event.user.id_.chat_id in admins_list): help_chat_id = event.user.id_.chat_id help_conv_id = event.conv_id if cmd == "impersonate": if len(args) == 1: [help_chat_id] = args elif len(args) == 2: [help_chat_id, help_conv_id] = args else: raise ValueError("impersonation: supply chat id and optional conversation id") help_lines.append(_('<b>Impersonation:</b><br />' '<b><pre>{}</pre></b><br />' '<b><pre>{}</pre></b><br />').format( help_chat_id, help_conv_id )) commands = command.get_available_commands(bot, help_chat_id, help_conv_id) commands_admin = commands["admin"] commands_nonadmin = commands["user"] if len(commands_nonadmin) > 0: help_lines.append(_('<b>User commands:</b>')) help_lines.append(', '.join(sorted(commands_nonadmin))) if link_to_guide: help_lines.append('') help_lines.append(_('<i>For more information, please see: {}</i>').format(link_to_guide)) if len(commands_admin) > 0: help_lines.append('') help_lines.append(_('<b>Admin commands:</b>')) help_lines.append(', '.join(sorted(commands_admin))) else: if cmd in command.commands: command_fn = command.commands[cmd] elif cmd.lower() in command.commands: command_fn = command.commands[cmd.lower()] else: yield from command.unknown_command(bot, event) return help_lines.append("<b>{}</b>: {}".format(command_fn.__name__, command_fn.__doc__)) yield from bot.coro_send_to_user_and_conversation( event.user.id_.chat_id, event.conv_id, "<br />".join(help_lines), # via private message _("<i>{}, I've sent you some help ;)</i>") # public message .format(event.user.full_name))
def help(bot, event, cmd=None, *args): """list supported commands, /bot help <command> will show additional details""" help_lines = [] link_to_guide = bot.get_config_suboption(event.conv_id, 'link_to_guide') admins_list = bot.get_config_suboption(event.conv_id, 'admins') help_chat_id = event.user.id_.chat_id help_conv_id = event.conv_id commands = command.get_available_commands(bot, help_chat_id, help_conv_id) commands_admin = commands["admin"] commands_nonadmin = commands["user"] if not cmd or (cmd == "impersonate" and event.user.id_.chat_id in admins_list): if cmd == "impersonate": if len(args) == 1: [help_chat_id] = args elif len(args) == 2: [help_chat_id, help_conv_id] = args else: raise ValueError( "impersonation: supply chat id and optional conversation id" ) help_lines.append( _('<b>Impersonation:</b><br />' '<b><pre>{}</pre></b><br />' '<b><pre>{}</pre></b><br />').format(help_chat_id, help_conv_id)) if len(commands_nonadmin) > 0: help_lines.append(_('<b>User commands:</b>')) help_lines.append(', '.join(sorted(commands_nonadmin))) if link_to_guide: help_lines.append('') help_lines.append( _('<i>For more information, please see: {}</i>').format( link_to_guide)) if len(commands_admin) > 0: help_lines.append('') help_lines.append(_('<b>Admin commands:</b>')) help_lines.append(', '.join(sorted(commands_admin))) help_lines.append("") help_lines.append("<b>Command-specific help:</b>") help_lines.append("/bot help <command name>") bot_aliases = [ _alias for _alias in bot._handlers.bot_command if len(_alias) < 9 ] if len(bot_aliases) > 1: help_lines.append("") help_lines.append("<b>My short-hand names:</b>") help_lines.append(', '.join(sorted(bot_aliases))) else: if cmd in command.commands and (cmd in commands_admin or cmd in commands_nonadmin): command_fn = command.commands[cmd] elif cmd.lower() in command.commands and (cmd in commands_admin or cmd in commands_nonadmin): command_fn = command.commands[cmd.lower()] else: yield from command.unknown_command(bot, event) return if "__doc__" in dir(command_fn) and command_fn.__doc__: _docstring = command_fn.__doc__.strip() else: _docstring = "_{}_".format(_("command help not available")) """docstrings: apply (very) limited markdown-like formatting to command help""" # simple bullet lists _docstring = re.sub(r'\n +\* +', '\n* ', _docstring) """docstrings: handle generic whitespace manually parse line-breaks: single break -> space; multiple breaks -> paragraph XXX: the markdown parser is iffy on line-break processing""" # turn standalone linebreaks into space, preserves multiple linebreaks _docstring = re.sub(r"(?<!\n)\n(?= *[^ \t\n\r\f\v\*])", " ", _docstring) # convert multiple consecutive spaces into single space _docstring = re.sub(r" +", " ", _docstring) # convert consecutive linebreaks into double linebreak (pseudo-paragraph) _docstring = re.sub(r" *\n\n+ *(?!\*)", "\n\n", _docstring) help_lines.append("<b>{}</b>: {}".format(command_fn.__name__, _docstring)) # replace /bot with the first alias in the command handler # XXX: [botalias] maintained backward compatibility, please avoid using it help_lines = [ re.sub(r"(?<!\S)\/bot(?!\S)", bot._handlers.bot_command[0], _line) for _line in help_lines ] yield from bot.coro_send_to_user_and_conversation( event.user.id_.chat_id, event.conv_id, "<br />".join(help_lines), # via private message _("<i>{}, I've sent you some help ;), however if we aren't already chatting, we should probably start, go ahead and accept my chat request</i>" ) # public message .format(event.user.full_name))
def help(bot, event, cmd=None, *args): """list supported commands, /bot help <command> will show additional details""" help_lines = [] link_to_guide = bot.get_config_suboption(event.conv_id, 'link_to_guide') admins_list = bot.get_config_suboption(event.conv_id, 'admins') help_chat_id = event.user.id_.chat_id help_conv_id = event.conv_id commands = command.get_available_commands(bot, help_chat_id, help_conv_id) commands_admin = commands["admin"] commands_nonadmin = commands["user"] if not cmd or (cmd=="impersonate" and event.user.id_.chat_id in admins_list): if cmd == "impersonate": if len(args) == 1: [help_chat_id] = args elif len(args) == 2: [help_chat_id, help_conv_id] = args else: raise ValueError("impersonation: supply chat id and optional conversation id") help_lines.append(_('<b>Impersonation:</b><br />' '<b><pre>{}</pre></b><br />' '<b><pre>{}</pre></b><br />').format( help_chat_id, help_conv_id )) if len(commands_nonadmin) > 0: help_lines.append(_('<b>User commands:</b>')) help_lines.append(', '.join(sorted(commands_nonadmin))) if link_to_guide: help_lines.append('') help_lines.append(_('<i>For more information, please see: {}</i>').format(link_to_guide)) if len(commands_admin) > 0: help_lines.append('') help_lines.append(_('<b>Admin commands:</b>')) help_lines.append(', '.join(sorted(commands_admin))) help_lines.append("") help_lines.append("<b>Command-specific help:</b>") help_lines.append("/bot help <command name>") bot_aliases = [ _alias for _alias in bot._handlers.bot_command if len(_alias) < 9 ] if len(bot_aliases) > 1: help_lines.append("") help_lines.append("<b>My short-hand names:</b>") help_lines.append(', '.join(sorted(bot_aliases))) else: if cmd in command.commands and (cmd in commands_admin or cmd in commands_nonadmin): command_fn = command.commands[cmd] elif cmd.lower() in command.commands and (cmd in commands_admin or cmd in commands_nonadmin): command_fn = command.commands[cmd.lower()] else: yield from command.unknown_command(bot, event) return if "__doc__" in dir(command_fn) and command_fn.__doc__: _docstring = command_fn.__doc__.strip() else: _docstring = "_{}_".format(_("command help not available")) """docstrings: apply (very) limited markdown-like formatting to command help""" # simple bullet lists _docstring = re.sub(r'\n +\* +', '\n* ', _docstring) """docstrings: handle generic whitespace manually parse line-breaks: single break -> space; multiple breaks -> paragraph XXX: the markdown parser is iffy on line-break processing""" # turn standalone linebreaks into space, preserves multiple linebreaks _docstring = re.sub(r"(?<!\n)\n(?= *[^ \t\n\r\f\v\*])", " ", _docstring) # convert multiple consecutive spaces into single space _docstring = re.sub(r" +", " ", _docstring) # convert consecutive linebreaks into double linebreak (pseudo-paragraph) _docstring = re.sub(r" *\n\n+ *(?!\*)", "\n\n", _docstring) help_lines.append("<b>{}</b>: {}".format(command_fn.__name__, _docstring)) # replace /bot with the first alias in the command handler # XXX: [botalias] maintained backward compatibility, please avoid using it help_lines = [ re.sub(r"(?<!\S)\/bot(?!\S)", bot._handlers.bot_command[0], _line) for _line in help_lines ] yield from bot.coro_send_to_user_and_conversation( event.user.id_.chat_id, event.conv_id, "<br />".join(help_lines), # via private message _("<i>{}, I've sent you some help ;), however if we aren't already chatting, we should probably start, go ahead and accept my chat request</i>") # public message .format(event.user.full_name))
def config(bot, event, cmd=None, *args): """displays or modifies the configuration Parameters: /bot config get [key] [subkey] [...] /bot config set [key] [subkey] [...] [value] /bot config append [key] [subkey] [...] [value] /bot config remove [key] [subkey] [...] [value]""" # consume arguments and differentiate beginning of a json array or object tokens = list(args) parameters = [] value = [] state = "key" for token in tokens: if token.startswith(("{", "[", '"', "'")): # apparent start of json array/object, consume into a single list item state = "json" if state == "key": parameters.append(token) elif state == "json": value.append(token) else: raise ValueError("unknown state") if value: parameters.append(" ".join(value)) if cmd == 'get' or cmd is None: config_args = list(parameters) value = bot.config.get_by_path(config_args) if config_args else dict(bot.config) elif cmd == 'test': num_parameters = len(parameters) text_parameters = [] last = num_parameters - 1 for num, token in enumerate(parameters): if num == last: try: json.loads(token) token += " <b>(valid json)</b>" except ValueError: token += " <em>(INVALID)</em>" text_parameters.append(str(num + 1) + ": " + token) text_parameters.insert(0, "<b>config test</b>") if num_parameters == 1: text_parameters.append(_("<em>note: testing single parameter as json</em>")) elif num_parameters < 1: yield from command.unknown_command(bot, event) return yield from bot.coro_send_message(event.conv, "<br />".join(text_parameters)) return elif cmd == 'set': config_args = list(parameters[:-1]) if len(parameters) >= 2: bot.config.set_by_path(config_args, json.loads(parameters[-1])) bot.config.save() value = bot.config.get_by_path(config_args) else: yield from command.unknown_command(bot, event) return elif cmd == 'append': config_args = list(parameters[:-1]) if len(parameters) >= 2: value = bot.config.get_by_path(config_args) if isinstance(value, list): value.append(json.loads(parameters[-1])) bot.config.set_by_path(config_args, value) bot.config.save() else: value = _('append failed on non-list') else: yield from command.unknown_command(bot, event) return elif cmd == 'remove': config_args = list(parameters[:-1]) if len(parameters) >= 2: value = bot.config.get_by_path(config_args) if isinstance(value, list): value.remove(json.loads(parameters[-1])) bot.config.set_by_path(config_args, value) bot.config.save() else: value = _('remove failed on non-list') else: yield from command.unknown_command(bot, event) return else: yield from command.unknown_command(bot, event) return if value is None: value = _('Parameter does not exist!') config_path = ' '.join(k for k in ['config'] + config_args) segments = [hangups.ChatMessageSegment('{}:'.format(config_path), is_bold=True), hangups.ChatMessageSegment('\n', hangups.SegmentType.LINE_BREAK)] segments.extend(text_to_segments(json.dumps(value, indent=2, sort_keys=True))) yield from bot.coro_send_message(event.conv, segments)
def handle_command(self, event): """Handle command messages""" # is commands_enabled? if not self.bot.get_config_suboption(event.conv_id, 'commands_enabled'): admins_list = self.bot.get_config_suboption( event.conv_id, 'admins') or [] # admins always have commands enabled if event.user_id.chat_id not in admins_list: return # ensure bot alias is always a list if not isinstance(self.bot_command, list): self.bot_command = [self.bot_command] # check that a bot alias is used e.g. /bot if not event.text.split()[0].lower() in self.bot_command: return # Parse message event.text = event.text.replace( u'\xa0', u' ') # convert non-breaking space in Latin1 (ISO 8859-1) try: line_args = shlex.split(event.text, posix=False) except Exception as e: logger.exception(e) yield from self.bot.coro_send_message( event.conv, _("{}: {}").format(event.user.full_name, str(e))) return # Test if command length is sufficient if len(line_args) < 2: yield from self.bot.coro_send_message( event.conv, _('{}: Missing parameter(s)').format(event.user.full_name)) return commands = command.get_available_commands(self.bot, event.user.id_.chat_id, event.conv_id) supplied_command = line_args[1].lower() if supplied_command in commands["user"]: pass elif supplied_command in commands["admin"]: pass elif supplied_command in command.commands: yield from command.blocked_command(self.bot, event, *line_args[1:]) return else: yield from command.unknown_command(self.bot, event, *line_args[1:]) return # Run command results = yield from command.run(self.bot, event, *line_args[1:]) if "acknowledge" in dir(event): for id in event.acknowledge: yield from self.run_reprocessor(id, event, results)
def handle_command(self, event): """Handle command messages""" # is commands_enabled? config_commands_enabled = self.bot.get_config_suboption( event.conv_id, 'commands_enabled') tagged_ignore = "ignore" in self.bot.tags.useractive( event.user_id.chat_id, event.conv_id) if not config_commands_enabled or tagged_ignore: admins_list = self.bot.get_config_suboption( event.conv_id, 'admins') or [] # admins always have commands enabled if event.user_id.chat_id not in admins_list: return # ensure bot alias is always a list if not isinstance(self.bot_command, list): self.bot_command = [self.bot_command] # check that a bot alias is used e.g. /bot if not event.text.split()[0].lower() in self.bot_command: if self.bot.conversations.catalog[event.conv_id][ "type"] == "ONE_TO_ONE" and self.bot.get_config_option( 'auto_alias_one_to_one'): event.text = u" ".join(( self.bot_command[0], event.text)) # Insert default alias if not already present else: return # Parse message event.text = event.text.replace( u'\xa0', u' ') # convert non-breaking space in Latin1 (ISO 8859-1) try: line_args = shlex.split(event.text, posix=False) except Exception as e: logger.exception(e) yield from self.bot.coro_send_message( event.conv, _("{}: {}").format(event.user.full_name, str(e))) return # Test if command length is sufficient if len(line_args) < 2: config_silent = bot.get_config_suboption(event.conv.id_, 'silentmode') tagged_silent = "silent" in bot.tags.useractive( event.user_id.chat_id, event.conv.id_) if not (config_silent or tagged_silent): yield from self.bot.coro_send_message( event.conv, _('{}: Missing parameter(s)').format(event.user.full_name)) return commands = command.get_available_commands(self.bot, event.user.id_.chat_id, event.conv_id) supplied_command = line_args[1].lower() if supplied_command in commands["user"]: pass elif supplied_command in commands["admin"]: pass elif supplied_command in command.commands: yield from command.blocked_command(self.bot, event, *line_args[1:]) return else: yield from command.unknown_command(self.bot, event, *line_args[1:]) return # Run command results = yield from command.run(self.bot, event, *line_args[1:]) if "acknowledge" in dir(event): for id in event.acknowledge: yield from self.run_reprocessor(id, event, results)
def config(bot, event, cmd=None, *args): """displays or modifies the configuration Parameters: /devilbot config get [key] [subkey] [...] /devilbot config set [key] [subkey] [...] [value] /devilbot config append [key] [subkey] [...] [value] /devilbot config remove [key] [subkey] [...] [value]""" # consume arguments and differentiate beginning of a json array or object tokens = list(args) parameters = [] value = [] state = "key" for token in tokens: if token.startswith(("{", "[", '"', "'")): # apparent start of json array/object, consume into a single list item state = "json" if state == "key": parameters.append(token) elif state == "json": value.append(token) else: raise ValueError("unknown state") if value: parameters.append(" ".join(value)) if cmd == 'get' or cmd is None: config_args = list(parameters) value = bot.config.get_by_path(config_args) if config_args else dict( bot.config) elif cmd == 'test': num_parameters = len(parameters) text_parameters = [] last = num_parameters - 1 for num, token in enumerate(parameters): if num == last: try: json.loads(token) token += " <b>(valid json)</b>" except ValueError: token += " <em>(INVALID)</em>" text_parameters.append(str(num + 1) + ": " + token) text_parameters.insert(0, "<b>config test</b>") if num_parameters == 1: text_parameters.append( _("<em>note: testing single parameter as json</em>")) elif num_parameters < 1: yield from command.unknown_command(bot, event) return yield from bot.coro_send_message(event.conv, "<br />".join(text_parameters)) return elif cmd == 'set': config_args = list(parameters[:-1]) if len(parameters) >= 2: bot.config.set_by_path(config_args, json.loads(parameters[-1])) bot.config.save() value = bot.config.get_by_path(config_args) else: yield from command.unknown_command(bot, event) return elif cmd == 'append': config_args = list(parameters[:-1]) if len(parameters) >= 2: value = bot.config.get_by_path(config_args) if isinstance(value, list): value.append(json.loads(parameters[-1])) bot.config.set_by_path(config_args, value) bot.config.save() else: value = _('append failed on non-list') else: yield from command.unknown_command(bot, event) return elif cmd == 'remove': config_args = list(parameters[:-1]) if len(parameters) >= 2: value = bot.config.get_by_path(config_args) if isinstance(value, list): value.remove(json.loads(parameters[-1])) bot.config.set_by_path(config_args, value) bot.config.save() else: value = _('remove failed on non-list') else: yield from command.unknown_command(bot, event) return else: yield from command.unknown_command(bot, event) return if value is None: value = _('Parameter does not exist!') config_path = ' '.join(k for k in ['config'] + config_args) segments = [ hangups.ChatMessageSegment('{}:'.format(config_path), is_bold=True), hangups.ChatMessageSegment('\n', hangups.SegmentType.LINE_BREAK) ] segments.extend( text_to_segments(json.dumps(value, indent=2, sort_keys=True))) yield from bot.coro_send_message(event.conv, segments)