def convrename(bot, event, *args): """renames a single specified conversation""" posix_args = get_posix_args(args) if len(posix_args) > 1: if not posix_args[0].startswith(("id:", "text:")): # always force explicit search for single conversation on vague user request posix_args[0] = "id:" + posix_args[0] convlist = bot.conversations.get(filter=posix_args[0]) title = ' '.join(posix_args[1:]) # only act on the first matching conversation yield from bot._client.rename_conversation( hangups.hangouts_pb2.RenameConversationRequest( request_header = bot._client.get_request_header(), new_name = title, event_request_header = hangups.hangouts_pb2.EventRequestHeader( conversation_id = hangups.hangouts_pb2.ConversationId( id = list(convlist.keys())[0] ), client_generated_id = bot._client.get_client_generated_id() ))) elif len(posix_args) == 1 and posix_args[0].startswith("id:"): """specialised error message for /bot rename (implied convid: <event.conv_id>)""" text = _("<em>missing title</em>") convlist = bot.conversations.get(filter=event.conv_id) yield from command.run(bot, event, *["convecho", "id:" + event.conv_id, text]) else: """general error""" text = _("<em>required parameters: convfilter title</em>") convlist = bot.conversations.get(filter=event.conv_id) yield from command.run(bot, event, *["convecho", "id:" + event.conv_id, text])
def handle_chat_message(self, event): """Handle conversation event""" if logging.root.level == logging.DEBUG: event.print_debug(self.bot) if event.text: if event.user.is_self: event.from_bot = True else: event.from_bot = False """reprocessor - process event with hidden context from handler.attach_reprocessor()""" if len(event.conv_event.segments) > 0: for segment in event.conv_event.segments: if segment.link_target: if segment.link_target.startswith(self._prefix_reprocessor): _id = segment.link_target[len(self._prefix_reprocessor):] if _id in self._reprocessors: logger.info("valid reprocessor uuid found: {}".format(_id)) self._reprocessors[_id](self.bot, event, _id) del self._reprocessors[_id] """auto opt-in - opted-out users who chat with the bot will be opted-in again""" if self.bot.conversations.catalog[event.conv_id]["type"] == "ONE_TO_ONE": if self.bot.memory.exists(["user_data", event.user.id_.chat_id, "optout"]): if self.bot.memory.get_by_path(["user_data", event.user.id_.chat_id, "optout"]): yield from command.run(self.bot, event, *["optout"]) logger.info("auto opt-in for {}".format(event.user.id_.chat_id)) return yield from self.run_pluggable_omnibus("allmessages", self.bot, event, command) if not event.from_bot: yield from self.run_pluggable_omnibus("message", self.bot, event, command) yield from self.handle_command(event)
def echo(bot, event, *args): """echo back text into conversation""" raw_arguments = event.text.split(maxsplit=3) if len(raw_arguments) >= 3: if raw_arguments[2] in bot.conversations.catalog: # e.g. /bot echo <convid> <text> # only admins can echo messages into other conversations admins_list = bot.get_config_suboption(event.conv_id, 'admins') if event.user_id.chat_id in admins_list: convid = raw_arguments[2] else: convid = event.conv_id raw_arguments = [ _("<b>only admins can echo other conversations</b>") ] else: # assumed /bot echo <text> convid = event.conv_id raw_arguments = event.text.split(maxsplit=2) _text = raw_arguments[-1].strip() if _text.startswith("raw:"): _text = _text[4:].strip() else: # emulate pre-2.5 bot behaviour and limitations _text = re.escape(_text) yield from command.run(bot, event, *["convecho", "id:" + convid, _text])
def handle_chat_message(self, event): """Handle conversation event""" if event.text: if event.user.is_self: event.from_bot = True else: event.from_bot = False """reprocessor - process event with hidden context from handler.attach_reprocessor()""" if len(event.conv_event.segments) > 0: for segment in event.conv_event.segments: if segment.link_target: if segment.link_target.startswith( self._prefix_reprocessor): _id = segment.link_target[ len(self._prefix_reprocessor):] yield from self.run_reprocessor(_id, event) """auto opt-in - opted-out users who chat with the bot will be opted-in again""" if self.bot.conversations.catalog[ event.conv_id]["type"] == "ONE_TO_ONE": if self.bot.memory.exists( ["user_data", event.user.id_.chat_id, "optout"]): if self.bot.memory.get_by_path( ["user_data", event.user.id_.chat_id, "optout"]): yield from command.run(self.bot, event, *["optout"]) logger.info("auto opt-in for {}".format( event.user.id_.chat_id)) return yield from self.run_pluggable_omnibus("allmessages", self.bot, event, command) if not event.from_bot: yield from self.run_pluggable_omnibus("message", self.bot, event, command) yield from self.handle_command(event)
def handle_command(self, event): """Handle command messages""" # Test if command handling is enabled if not self.bot.get_config_suboption(event.conv_id, 'commands_enabled'): return # Parse message event.text = event.text.replace( u'\xa0', u' ') # convert non-breaking space in Latin1 (ISO 8859-1) line_args = shlex.split(event.text, posix=False) # Test if command length is sufficient if len(line_args) < 2: self.bot.send_message( event.conv, '{}: missing parameter(s)'.format(event.user.full_name)) return # Test if user has permissions for running command commands_admin_list = self.bot.get_config_suboption( event.conv_id, 'commands_admin') if commands_admin_list and line_args[1].lower() in commands_admin_list: admins_list = self.bot.get_config_suboption( event.conv_id, 'admins') if event.user_id.chat_id not in admins_list: self.bot.send_message( event.conv, '{}: I\'m sorry. I\'m afraid I can\'t do that.'.format( event.user.full_name)) return # Run command yield from command.run(self.bot, event, *line_args[1:])
def handle_chat_message(self, event): """Handle conversation event""" if event.text: if event.user.is_self: event.from_bot = True else: event.from_bot = False """reprocessor - process event with hidden context from handler.attach_reprocessor()""" if len(event.conv_event.segments) > 0: for segment in event.conv_event.segments: if segment.link_target: if segment.link_target.startswith(self._prefix_reprocessor): _id = segment.link_target[len(self._prefix_reprocessor):] yield from self.run_reprocessor(_id, event) """auto opt-in - opted-out users who chat with the bot will be opted-in again""" if not event.from_bot and self.bot.conversations.catalog[event.conv_id]["type"] == "ONE_TO_ONE": if self.bot.memory.exists(["user_data", event.user.id_.chat_id, "optout"]): optout = self.bot.memory.get_by_path(["user_data", event.user.id_.chat_id, "optout"]) if isinstance(optout, bool) and optout: yield from command.run(self.bot, event, *["optout"]) logger.info("auto opt-in for {}".format(event.user.id_.chat_id)) return yield from self.run_pluggable_omnibus("allmessages", self.bot, event, command) if not event.from_bot: yield from self.run_pluggable_omnibus("message", self.bot, event, command) yield from self.handle_command(event)
def approve(bot, event, *args): conn = sqlite3.connect('bot.db') request = args[0] request_number = str(args[1]) if request.lower() == 'poll': if not bot.memory.exists(["requests"]): yield from bot.coro_send_message(event.conv, _("No requests")) return else: path = bot.memory.get_by_path( ["requests", "polls", str(request_number)]) conversation_id = path.split()[0] command_to_run = path.split()[2:] yield from command.run(bot, event, *command_to_run) yield from bot.coro_send_message(conversation_id, _("Poll {} approved").format(request_number)) return elif request.lower() == 'quote': c = conn.cursor() c.execute('SELECT * FROM unapp_quotes WHERE id = ?', [request_number]) q = c.fetchone() c.execute("INSERT INTO quotes(author, quote) VALUES (?, ?)", [q[0], q[1]]) conn.commit() yield from bot.coro_send_message(event.conv, _("Quote {} approved").format(c.lastrowid)) else: yield from bot.coro_send_message(event.conv, _("Approval for that not yet supported"))
def handle_mention(self, event): """handle @mention""" occurrences = [word for word in event.text.split() if word.startswith('@')] if len(occurrences) > 0: for word in occurrences: # strip all special characters cleaned_name = ''.join(e for e in word if e.isalnum()) yield from command.run(self.bot, event, *["mention", cleaned_name])
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 handle_command(self, event): """Handle command messages""" # verify user is an admin admins_list = self.bot.get_config_suboption(event.conv_id, 'admins') initiator_is_admin = False if event.user_id.chat_id in admins_list: initiator_is_admin = True # Test if command handling is enabled # note: admins always bypass this check if not initiator_is_admin: if not self.bot.get_config_suboption(event.conv_id, 'commands_enabled'): return if not isinstance(self.bot_command, list): # always a list self.bot_command = [self.bot_command] 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: print("EXCEPTION in {}: {}".format("handle_command", e)) self.bot.send_message_parsed( event.conv, _("{}: {}").format(event.user.full_name, str(e))) logger.exception(e) return # Test if command length is sufficient if len(line_args) < 2: self.bot.send_message_parsed( event.conv, _('{}: Missing parameter(s)').format(event.user.full_name)) return # only admins can run admin commands commands_admin_list = command.get_admin_commands( self.bot, event.conv_id) if commands_admin_list and line_args[1].lower() in commands_admin_list: if not initiator_is_admin: self.bot.send_message_parsed( event.conv, _('{}: Can\'t do that.').format(event.user.full_name)) return # Run command yield from command.run(self.bot, event, *line_args[1:])
def convrename(bot, event, *args): """renames a single specified conversation""" posix_args = get_posix_args(args) if len(posix_args) > 1: if not posix_args[0].startswith(("id:", "text:")): # always force explicit search for single conversation on vague user request posix_args[0] = "id:" + posix_args[0] convlist = bot.conversations.get(filter=posix_args[0]) title = ' '.join(posix_args[1:]) # only act on the first matching conversation yield from bot._client.setchatname(list(convlist.keys())[0], title) elif len(posix_args) == 1 and posix_args[0].startswith("id:"): """specialised error message for /bot rename (implied convid: <event.conv_id>)""" text = _("<em>missing title</em>") convlist = bot.conversations.get(filter=event.conv_id) yield from command.run(bot, event, *["convecho", "id:" + event.conv_id, text]) else: """general error""" text = _("<em>required parameters: convfilter title</em>") convlist = bot.conversations.get(filter=event.conv_id) yield from command.run(bot, event, *["convecho", "id:" + event.conv_id, text])
def leave(bot, event, conversation_id=None, *args): """exits current or other specified hangout""" arglist = list(args) if conversation_id == "quietly": arglist.append("quietly") conversation_id = False if not conversation_id: conversation_id = event.conv_id yield from command.run(bot, event, *["convleave", "id:" + conversation_id, " ".join(arglist)])
def convrename(bot, event, *args): """renames a single specified conversation""" posix_args = get_posix_args(args) if len(posix_args) > 1: if not posix_args[0].startswith(("id:", "text:")): # always force explicit search for single conversation on vague user request posix_args[0] = "id:" + posix_args[0] convlist = bot.conversations.get(filter=posix_args[0]) title = ' '.join(posix_args[1:]) # only act on the first matching conversation yield from bot._client.setchatname(list(convlist.keys())[0], title) elif len(posix_args) == 1 and posix_args[0].startswith("id:"): """specialised error message for /devilbot rename (implied convid: <event.conv_id>)""" text = _("<em>missing title</em>") convlist = bot.conversations.get(filter=event.conv_id) yield from command.run(bot, event, *["convecho", "id:" + event.conv_id, text]) else: """general error""" text = _("<em>required parameters: convfilter title</em>") convlist = bot.conversations.get(filter=event.conv_id) yield from command.run(bot, event, *["convecho", "id:" + event.conv_id, text])
def handle_command(self, event): """Handle command messages""" # verify user is an admin admins_list = self.bot.get_config_suboption(event.conv_id, 'admins') initiator_is_admin = False if event.user_id.chat_id in admins_list: initiator_is_admin = True # Test if command handling is enabled # note: admins always bypass this check if not initiator_is_admin: if not self.bot.get_config_suboption(event.conv_id, 'commands_enabled'): return if not isinstance(self.bot_command, list): # always a list self.bot_command = [self.bot_command] 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: print("EXCEPTION in {}: {}".format("handle_command", e)) self.bot.send_message_parsed(event.conv, _("{}: {}").format( event.user.full_name, str(e))) logger.exception(e) return # Test if command length is sufficient if len(line_args) < 2: self.bot.send_message_parsed(event.conv, _('{}: Missing parameter(s)').format( event.user.full_name)) return # only admins can run admin commands commands_admin_list = command.get_admin_commands(self.bot, event.conv_id) if commands_admin_list and line_args[1].lower() in commands_admin_list: if not initiator_is_admin: self.bot.send_message_parsed(event.conv, _('{}: Can\'t do that.').format( event.user.full_name)) return # Run command yield from command.run(self.bot, event, *line_args[1:])
def _new_group_conversation(bot, initiator_id): _response = yield from bot._client.create_conversation( hangups.hangouts_pb2.CreateConversationRequest( request_header = bot._client.get_request_header(), type = hangups.hangouts_pb2.CONVERSATION_TYPE_GROUP, client_generated_id = bot._client.get_client_generated_id(), invitee_id = [ hangups.hangouts_pb2.InviteeID(gaia_id = initiator_id) ])) new_conversation_id = _response.conversation.conversation_id.id yield from bot.coro_send_message(new_conversation_id, _("<i>group created</i>")) yield from asyncio.sleep(1) # allow convmem to update yield from command.run( bot, event, *[ "convrename", "id:" + new_conversation_id, _("GROUP: {}").format(datetime.datetime.now().strftime("%Y-%m-%d %H:%M")) ]) return new_conversation_id
def _new_group_conversation(bot, initiator_id): _response = yield from bot._client.create_conversation( hangups.hangouts_pb2.CreateConversationRequest( request_header=bot._client.get_request_header(), type=hangups.hangouts_pb2.CONVERSATION_TYPE_GROUP, client_generated_id=bot._client.get_client_generated_id(), invitee_id=[hangups.hangouts_pb2.InviteeID(gaia_id=initiator_id)])) new_conversation_id = _response.conversation.conversation_id.id yield from bot.coro_send_message(new_conversation_id, _("<i>group created</i>")) yield from asyncio.sleep(1) # allow convmem to update yield from command.run( bot, event, *[ "convrename", "id:" + new_conversation_id, _("GROUP: {}").format( datetime.datetime.now().strftime("%Y-%m-%d %H:%M")) ]) return new_conversation_id
def topic(bot, event, *args): """locks a conversation title. if no parameters supplied, clear and unlock the title""" topic = ' '.join(args).strip() bot.initialise_memory(event.conv_id, "conv_data") bot.memory.set_by_path(["conv_data", event.conv_id, "topic"], topic) bot.memory.save() if(topic == ''): message = _("Removing topic") logger.info("topic cleared from {}".format(event.conv_id)) else: message = _("Setting topic to '{}'").format(topic) logger.info("topic for {} set to: {}".format(event.conv_id, topic)) yield from bot.coro_send_message(event.conv, message) """Rename Hangout""" yield from command.run(bot, event, *["convrename", "id:" + event.conv_id, topic])
def kick(bot, event, *args): """kick users from a conversation Usage: /bot kick [<optional conversation id, current if not specified>] [<user ids, space-separated if more than one>] [quietly]""" parameters = list(args) source_conv = event.conv_id remove = [] test = False quietly = False for parameter in parameters: if parameter in bot.conversations.catalog: source_conv = parameter elif parameter in bot.conversations.catalog[source_conv][ "participants"]: remove.append(parameter) elif parameter == "test": test = True elif parameter == "quietly": quietly = True else: raise ValueError( _("supply optional conversation id and valid user ids to kick") ) if len(remove) <= 0: raise ValueError(_("supply at least one valid user id to kick")) arguments = ["refresh", source_conv, "without"] + remove if test: arguments.append("test") if quietly: arguments.append("quietly") yield from command.run(bot, event, *arguments)
def _watch_rename(bot, event, command): memory_topic_path = ["conv_data", event.conv_id, "topic"] topic = False if bot.memory.exists(memory_topic_path): topic = bot.memory.get_by_path(memory_topic_path) if topic: # seems to be a valid topic set for the current conversation authorised_topic_change = False if not authorised_topic_change and event.user.is_self: # bot is authorised to change the name authorised_topic_change = True if not authorised_topic_change: # admins can always change the name admins_list = bot.get_config_suboption(event.conv_id, 'admins') if event.user_id.chat_id in admins_list: authorised_topic_change = True if authorised_topic_change: bot.memory.set_by_path(memory_topic_path, event.conv_event.new_name) bot.memory.save() topic = event.conv_event.new_name if event.conv_event.new_name != topic: hangups_user = bot.get_hangups_user(event.user_id.chat_id) logger.warning( "unauthorised topic change by {} ({}) in {}, resetting: {} to: {}" .format( hangups_user.full_name, event.user_id.chat_id, event.conv_id, event.conv_event.new_name, topic )) yield from command.run(bot, event, *["convrename", "id:" + event.conv_id, topic])
def kick(bot, event, *args): """kick users from a conversation Usage: /bot kick [<optional conversation id, current if not specified>] [<user ids, space-separated if more than one>] [quietly]""" parameters = list(args) source_conv = event.conv_id remove = [] test = False quietly = False for parameter in parameters: if parameter in bot.conversations.catalog: source_conv = parameter elif parameter in bot.conversations.catalog[source_conv]["participants"]: remove.append(parameter) elif parameter == "test": test = True elif parameter == "quietly": quietly = True else: raise ValueError( _("supply optional conversation id and valid user ids to kick")) if len(remove) <= 0: raise ValueError(_("supply at least one valid user id to kick")) arguments = ["refresh", source_conv, "without"] + remove if test: arguments.append("test") if quietly: arguments.append("quietly") yield from command.run(bot, event, *arguments)
def rename(bot, event, *args): """rename current hangout""" yield from command.run(bot, event, *["convrename", "id:" + event.conv_id, " ".join(args)])
def users(bot, event, *args): """list all users in current hangout (include g+ and email links)""" yield from command.run(bot, event, *["convusers", "id:" + event.conv_id])
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 refresh(bot, event, *args): """refresh a chat Usage: /bot refresh [conversation] <conversation id> [without|remove <user ids, space-separated if more than one>] [with|add <user id(s)>] [quietly] [norename]""" parameters = list(args) test = False quietly = False source_conv = False renameold = True list_removed = [] list_added = [] state = ["conversation"] for parameter in parameters: if parameter == "remove" or parameter == "without": state.append("removeuser") elif parameter == "add" or parameter == "with": state.append("adduser") elif parameter == "conversation": state.append("conversation") elif parameter == "quietly": quietly = True renameold = False elif parameter == "test": test = True elif parameter == "norename": renameold = False else: if state[-1] == "adduser": list_added.append(parameter) if parameter in list_removed: list_removed.remove(parameter) elif state[-1] == "removeuser": list_removed.append(parameter) if parameter in list_added: list_added.remove(parameter) elif state[-1] == "conversation": source_conv = parameter else: raise ValueError("UNKNOWN STATE: {}".format(state[-1])) list_removed = list(set(list_removed)) if not source_conv: raise ValueError("conversation id not supplied") if source_conv not in bot.conversations.catalog: raise ValueError(_("conversation {} not found").format(source_conv)) if bot.conversations.catalog[source_conv]["type"] != "GROUP": raise ValueError(_("conversation {} is not a GROUP").format(source_conv)) new_title = bot.conversations.get_name(source_conv) old_title = _("[DEFUNCT] {}".format(new_title)) text_removed_users = [] list_all_users = bot.get_users_in_conversation(source_conv) for u in list_all_users: if u.id_.chat_id not in list_removed: list_added.append(u.id_.chat_id) else: hangups_user = bot.get_hangups_user(u.id_.chat_id) text_removed_users.append("<pre>{}</pre> ({})".format(hangups_user.full_name, u.id_.chat_id)) list_added = list(set(list_added)) logger.debug("refresh: from conversation {} removed {} added {}".format(source_conv, len(list_removed), len(list_added))) if test: yield from bot.coro_send_message(event.conv_id, _("<b>refresh:</b> {}<br />" "<b>rename old: {}</b><br />" "<b>removed {}:</b> {}<br />" "<b>added {}:</b> {}").format(source_conv, old_title if renameold else _("<em>unchanged</em>"), len(text_removed_users), ", ".join(text_removed_users) or _("<em>none</em>"), len(list_added), " ".join(list_added) or _("<em>none</em>"))) else: if len(list_added) > 1: _response = yield from bot._client.create_conversation( hangups.hangouts_pb2.CreateConversationRequest( request_header = bot._client.get_request_header(), type = hangups.hangouts_pb2.CONVERSATION_TYPE_GROUP, client_generated_id = bot._client.get_client_generated_id(), invitee_id = [])) new_conversation_id = _response.conversation.conversation_id.id yield from bot.coro_send_message(new_conversation_id, _("<i>refreshing group...</i><br />")) yield from asyncio.sleep(1) yield from _batch_add_users(bot, new_conversation_id, list_added) yield from bot.coro_send_message(new_conversation_id, _("<i>all users added</i><br />")) yield from asyncio.sleep(1) yield from command.run(bot, event, *["convrename", "id:" + new_conversation_id, new_title]) if renameold: yield from command.run(bot, event, *["convrename", "id:" + source_conv, old_title]) if not quietly: yield from bot.coro_send_message(source_conv, _("<i>group has been obsoleted</i>")) yield from bot.coro_send_message( event.conv_id, _("refreshed: <b><pre>{}</pre></b> (original id: <pre>{}</pre>).<br />" "new conversation id: <b><pre>{}</pre></b>.<br />" "removed {}: {}").format( new_title, source_conv, new_conversation_id, len(text_removed_users), ", ".join(text_removed_users) or _("<em>none</em>") )) else: yield from bot.coro_send_message(event.conv_id, _("<b>nobody to add in the new conversation</b>"))
def echo(bot, event, *args): """echo back text into current conversation""" yield from command.run(bot, event, *["convecho", "id:" + event.conv_id, " ".join(args)])
def refresh(bot, event, *args): """refresh a chat Usage: /bot refresh [conversation] <conversation id> [without|remove <user ids, space-separated if more than one>] [with|add <user id(s)>] [quietly] [norename]""" parameters = list(args) test = False quietly = False source_conv = False renameold = True list_removed = [] list_added = [] state = ["conversation"] for parameter in parameters: if parameter == "remove" or parameter == "without": state.append("removeuser") elif parameter == "add" or parameter == "with": state.append("adduser") elif parameter == "conversation": state.append("conversation") elif parameter == "quietly": quietly = True renameold = False elif parameter == "test": test = True elif parameter == "norename": renameold = False else: if state[-1] == "adduser": list_added.append(parameter) if parameter in list_removed: list_removed.remove(parameter) elif state[-1] == "removeuser": list_removed.append(parameter) if parameter in list_added: list_added.remove(parameter) elif state[-1] == "conversation": source_conv = parameter else: raise ValueError("UNKNOWN STATE: {}".format(state[-1])) list_removed = list(set(list_removed)) if not source_conv: raise ValueError("conversation id not supplied") if source_conv not in bot.conversations.catalog: raise ValueError(_("conversation {} not found").format(source_conv)) if bot.conversations.catalog[source_conv]["type"] != "GROUP": raise ValueError( _("conversation {} is not a GROUP").format(source_conv)) new_title = bot.conversations.get_name(source_conv) old_title = _("[DEFUNCT] {}".format(new_title)) text_removed_users = [] list_all_users = bot.get_users_in_conversation(source_conv) for u in list_all_users: if u.id_.chat_id not in list_removed: list_added.append(u.id_.chat_id) else: hangups_user = bot.get_hangups_user(u.id_.chat_id) text_removed_users.append("<pre>{}</pre> ({})".format( hangups_user.full_name, u.id_.chat_id)) list_added = list(set(list_added)) logger.debug("refresh: from conversation {} removed {} added {}".format( source_conv, len(list_removed), len(list_added))) if test: yield from bot.coro_send_message( event.conv_id, _("<b>refresh:</b> {}<br />" "<b>rename old: {}</b><br />" "<b>removed {}:</b> {}<br />" "<b>added {}:</b> {}").format( source_conv, old_title if renameold else _("<em>unchanged</em>"), len(text_removed_users), ", ".join(text_removed_users) or _("<em>none</em>"), len(list_added), " ".join(list_added) or _("<em>none</em>"))) else: if len(list_added) > 1: _response = yield from bot._client.create_conversation( hangups.hangouts_pb2.CreateConversationRequest( request_header=bot._client.get_request_header(), type=hangups.hangouts_pb2.CONVERSATION_TYPE_GROUP, client_generated_id=bot._client.get_client_generated_id(), invitee_id=[])) new_conversation_id = _response.conversation.conversation_id.id yield from bot.coro_send_message( new_conversation_id, _("<i>refreshing group...</i><br />")) yield from asyncio.sleep(1) yield from _batch_add_users(bot, new_conversation_id, list_added) yield from bot.coro_send_message(new_conversation_id, _("<i>all users added</i><br />")) yield from asyncio.sleep(1) yield from command.run( bot, event, *["convrename", "id:" + new_conversation_id, new_title]) if renameold: yield from command.run( bot, event, *["convrename", "id:" + source_conv, old_title]) if not quietly: yield from bot.coro_send_message( source_conv, _("<i>group has been obsoleted</i>")) yield from bot.coro_send_message( event.conv_id, _("refreshed: <b><pre>{}</pre></b> (original id: <pre>{}</pre>).<br />" "new conversation id: <b><pre>{}</pre></b>.<br />" "removed {}: {}").format( new_title, source_conv, new_conversation_id, len(text_removed_users), ", ".join(text_removed_users) or _("<em>none</em>"))) else: yield from bot.coro_send_message( event.conv_id, _("<b>nobody to add in the new conversation</b>"))
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 handle_chat_message(self, event): """Handle conversation event""" if event.text: if event.user.is_self: event.from_bot = True else: event.from_bot = False """EventAnnotation - allows metadata to survive a trip to Google""" event.passthru = {} event.context = {} for annotation in event.conv_event._event.chat_message.annotation: if annotation.type == 1025: # reprocessor - process event with hidden context from handler.attach_reprocessor() yield from self.run_reprocessor(annotation.value, event) elif annotation.type == 1026: if annotation.value in self._passthrus: event.passthru = self._passthrus[annotation.value] del self._passthrus[annotation.value] elif annotation.type == 1027: if annotation.value in self._contexts: event.context = self._contexts[annotation.value] del self._contexts[annotation.value] if len(event.conv_event.segments) > 0: for segment in event.conv_event.segments: if segment.link_target: if segment.link_target.startswith( self._prefix_reprocessor): _id = segment.link_target[ len(self._prefix_reprocessor):] yield from self.run_reprocessor(_id, event) """auto opt-in - opted-out users who chat with the bot will be opted-in again""" if not event.from_bot and self.bot.conversations.catalog[ event.conv_id]["type"] == "ONE_TO_ONE": if self.bot.memory.exists( ["user_data", event.user.id_.chat_id, "optout"]): optout = self.bot.memory.get_by_path( ["user_data", event.user.id_.chat_id, "optout"]) if isinstance(optout, bool) and optout: yield from command.run(self.bot, event, *["optout"]) logger.info("auto opt-in for {}".format( event.user.id_.chat_id)) return """map image ids to their public uris in absence of any fixed server api XXX: small memory leak over time as each id gets cached indefinitely""" if (event.passthru and "original_request" in event.passthru and "image_id" in event.passthru["original_request"] and event.passthru["original_request"]["image_id"] and len(event.conv_event.attachments) == 1): _image_id = event.passthru["original_request"]["image_id"] _image_uri = event.conv_event.attachments[0] if _image_id not in self._image_ids: self._image_ids[_image_id] = _image_uri logger.info("associating image_id={} with {}".format( _image_id, _image_uri)) """first occurence of an actual executable id needs to be handled as an event XXX: small memory leak over time as each id gets cached indefinitely""" if (event.passthru and "executable" in event.passthru and event.passthru["executable"]): if event.passthru["executable"] not in self._executables: original_message = event.passthru["original_request"][ "message"] linked_hangups_user = event.passthru["original_request"][ "user"] logger.info("current event is executable: {}".format( original_message)) self._executables[ event.passthru["executable"]] = time.time() event.from_bot = False event.text = original_message event.user = linked_hangups_user yield from self.run_pluggable_omnibus("allmessages", self.bot, event, command) if not event.from_bot: yield from self.run_pluggable_omnibus("message", self.bot, event, command) yield from self.handle_command(event)
def rename(bot, event, *args): """rename current hangout""" yield from command.run( bot, event, *["convrename", "id:" + event.conv_id, " ".join(args)])
async def on_message(msg): if msg.author == client.user: return a = command.run(msg.content.lower()) await msg.channel.send(a)
def handle_chat_message(self, event): """Handle conversation event""" if event.text: if event.user.is_self: event.from_bot = True else: event.from_bot = False """EventAnnotation - allows metadata to survive a trip to Google""" event.passthru = {} event.context = {} for annotation in event.conv_event._event.chat_message.annotation: if annotation.type == 1025: # reprocessor - process event with hidden context from handler.attach_reprocessor() yield from self.run_reprocessor(annotation.value, event) elif annotation.type == 1026: if annotation.value in self._passthrus: event.passthru = self._passthrus[annotation.value] del self._passthrus[annotation.value] elif annotation.type == 1027: if annotation.value in self._contexts: event.context = self._contexts[annotation.value] del self._contexts[annotation.value] if len(event.conv_event.segments) > 0: for segment in event.conv_event.segments: if segment.link_target: if segment.link_target.startswith(self._prefix_reprocessor): _id = segment.link_target[len(self._prefix_reprocessor):] yield from self.run_reprocessor(_id, event) """auto opt-in - opted-out users who chat with the bot will be opted-in again""" if not event.from_bot and self.bot.conversations.catalog[event.conv_id]["type"] == "ONE_TO_ONE": if self.bot.memory.exists(["user_data", event.user.id_.chat_id, "optout"]): optout = self.bot.memory.get_by_path(["user_data", event.user.id_.chat_id, "optout"]) if isinstance(optout, bool) and optout: yield from command.run(self.bot, event, *["optout"]) logger.info("auto opt-in for {}".format(event.user.id_.chat_id)) return """map image ids to their public uris in absence of any fixed server api XXX: small memory leak over time as each id gets cached indefinitely""" if( event.passthru and "original_request" in event.passthru and "image_id" in event.passthru["original_request"] and event.passthru["original_request"]["image_id"] and len(event.conv_event.attachments) == 1 ): _image_id = event.passthru["original_request"]["image_id"] _image_uri = event.conv_event.attachments[0] if _image_id not in self._image_ids: self._image_ids[_image_id] = _image_uri logger.info("associating image_id={} with {}".format(_image_id, _image_uri)) """first occurence of an actual executable id needs to be handled as an event XXX: small memory leak over time as each id gets cached indefinitely""" if( event.passthru and "executable" in event.passthru and event.passthru["executable"] ): if event.passthru["executable"] not in self._executables: original_message = event.passthru["original_request"]["message"] linked_hangups_user = event.passthru["original_request"]["user"] logger.info("current event is executable: {}".format(original_message)) self._executables[event.passthru["executable"]] = time.time() event.from_bot = False event.text = original_message event.user = linked_hangups_user yield from self.run_pluggable_omnibus("allmessages", self.bot, event, command) if not event.from_bot: yield from self.run_pluggable_omnibus("message", self.bot, event, command) yield from self.handle_command(event)