def process_message(self, message, modified=False, initial_salvo=False, user_banned=False): """ Called by the communicator when a new or updated message has been received. :type message: vbcbbot.chatbox_connector.ChatboxMessage """ if modified or initial_salvo: return lower_sender_name = message.user_name.lower() # parse and strip body = remove_control_characters_and_strip(message.decompiled_body()) if not user_banned: self.potential_stats(message, body) self.potential_spy(message, body) # spy on messages from banned users too if lower_sender_name in self.lowercase_user_names_to_triggers: for trigger in self.lowercase_user_names_to_triggers[lower_sender_name]: cursor = self.database.cursor() for match in trigger.pattern.finditer(body): # trigger matched. log this. cursor.execute( "INSERT INTO incidents (trigger_id, message_id, timestamp) VALUES (?, ?, ?)", (trigger.trigger_id, message.id, message.timestamp) ) self.database.commit()
def process_message(self, message, modified=False, initial_salvo=False, user_banned=False): if modified or initial_salvo or user_banned: return body = remove_control_characters_and_strip(message.decompiled_body()) if is_down_re.match(body) is None: return response = ur.urlopen(self.api_url) response_data = response.read().decode("us-ascii") pieces = response_data.split(" ") if len(pieces) != 3: logger.debug("unexpected server answer {0} for nickname {1}".format( repr(response_data) )) self.connector.send_message( random.choice(self.unknown_messages).format(sender=message.user_name) ) return (status, since_string, last_update_string) = pieces try: since = time.strftime("%Y-%m-%d %H:%M", time.localtime(int(since_string))) except ValueError: since = -1 try: last_update = time.strftime("%Y-%m-%d %H:%M", time.localtime(int(last_update_string))) except ValueError: last_update = -1 pick_one = self.unknown_messages if status == "0": pick_one = self.up_messages elif status == "1": pick_one = self.down_messages outgoing = random.choice(pick_one) self.connector.send_message( outgoing.format(sender=message.user_name, since=since, last_update=last_update) )
def potential_message_send(self, message, body, lower_sender_name): match = msg_trigger.match(body) if match is None: return recipient_and_message = match.group(3) try: (target_name, send_body) = split_recipient_and_message(recipient_and_message) except ValueError as e: self.connector.send_message("{0}: {1}".format(message.user_name, str(e))) return target_name = remove_control_characters_and_strip(target_name) lower_target_name = target_name.lower() send_body = remove_control_characters_and_strip(send_body) if len(lower_target_name) == 0: self.connector.send_message("{0}: You must specify a name to deliver to!".format(message.user_name)) return elif len(send_body) == 0: self.connector.send_message("{0}: You must specify a message to deliver!".format(message.user_name)) return elif lower_target_name == self.connector.username.lower(): self.connector.send_message("{0}: Sorry, I don\u2019t deliver to myself!".format(message.user_name)) return try: user_info = self.connector.get_user_id_and_nickname_for_uncased_name(target_name) except chatbox_connector.TransferError: self.connector.send_message( "[noparse]{1}[/noparse]: Sorry, I couldn\u2019t verify if \u201c{0}\u201d exists because the forum " "isn\u2019t being cooperative. Please try again later!".format(target_name, message.user_name) ) return if user_info is None: colon_info = "" if ":" in send_body: colon_info = " (You may escape colons in usernames using a backslash.)" elif len(target_name) > 32: colon_info = " (You must place a colon between the username and the message.)" self.connector.send_message( "[noparse]{1}[/noparse]: Sorry, I don\u2019t know \u201c{0}\u201d.{2}".format( target_name, message.user_name, colon_info ) ) return # check ignore list cursor = self.database.cursor() cursor.execute( "SELECT COUNT(*) FROM ignore_list WHERE sender_folded=? AND recipient_folded=?", (lower_sender_name, lower_target_name) ) ignore_count = None for row in cursor: ignore_count = row[0] cursor.close() if ignore_count != 0: logger.debug("{0} wants to send a message {1} to {2}, but the recipient is ignoring the sender".format( repr(message.user_name), repr(send_body), repr(target_name) )) self.connector.send_message( ( "[noparse]{0}[/noparse]: Can\u2019t send a message to [i][noparse]{1}[/noparse][/i]\u2014" "they\u2019re ignoring you." ).format( message.user_name, user_info[1] ) ) return logger.debug("{0} sending message {1} to {2}".format( repr(message.user_name), repr(send_body), repr(target_name) )) cursor = self.database.cursor() cursor.execute( "INSERT INTO messages " "(message_id, timestamp, sender_original, recipient_folded, body) " "VALUES (?, ?, ?, ?, ?)", (message.id, message.timestamp, message.user_name, lower_target_name, send_body) ) self.database.commit() if match.group(1) == "": if lower_target_name == lower_sender_name: self.connector.send_message( ("[noparse]{0}[/noparse]: Talking to ourselves? Well, no skin off my back. I\u2019ll deliver your " "message to you right away. ;)").format(message.user_name) ) else: sent_template = ( "[noparse]{1}[/noparse]: Aye-aye! I\u2019ll deliver your message to [i][noparse]{0}[/noparse][/i] next " "time I see \u2019em!" ) self.connector.send_message(sent_template.format(user_info[1], message.user_name))
def process_message(self, message, modified=False, initial_salvo=False, user_banned=False): """ Called by the communicator when a new or updated message has been received. :type message: vbcbbot.chatbox_connector.ChatboxMessage """ if modified or initial_salvo or message.user_name == self.connector.username: return lower_sender_name = message.user_name.lower() # parse and strip body = remove_control_characters_and_strip(message.decompiled_body()) if not user_banned: # process potential message send self.potential_message_send(message, body, lower_sender_name) # process potential deliver request self.potential_deliver_request(message, body, lower_sender_name) # process potential ignore/unignore request self.potential_ignore_list_request(message, body, lower_sender_name) # process potential replay request self.potential_replay_request(message, body, lower_sender_name) # even banned users get messages; they just can't respond to them if self.connector.should_stfu(): # don't bother just yet return # check if the sender should get any messages cursor = self.database.cursor() cursor.execute( "SELECT timestamp, sender_original, body, message_id FROM messages " "WHERE recipient_folded=? ORDER BY message_id ASC", (lower_sender_name,) ) messages = [] for bin_row in cursor: # skip messages that the user is directly responding to # (0: the !msg call, 1: the confirmation, 2: the response) delta = message.id - bin_row[3] if delta < 1 or delta > 2: messages.append((bin_row[0], bin_row[1], bin_row[2], bin_row[3])) else: logger.debug("dropping {0}'s message #{1} for {2} ({3}) due to proximity to #{4}".format( bin_row[1], bin_row[3], message.user_name, bin_row[2], message.id )) cursor.close() # check how many messages the user has on retainer cursor = self.database.cursor() cursor.execute( "SELECT COUNT(*) FROM messages_on_retainer WHERE recipient_folded=?", (lower_sender_name,) ) on_retainer = 0 for row in cursor: on_retainer = row[0] retainer_text = "" if on_retainer > 0: retainer_text = " (and {0} pending !delivermsg)".format(on_retainer) if len(messages) == 0: # meh # (pass instead of return to delete the skipped "responded directly to" messages) pass elif len(messages) == 1: # one message (the_timestamp, the_sender, the_body, the_message_id) = messages[0] logger.debug("delivering {0}'s message #{3} {1} to {2}".format( repr(the_sender), repr(the_body), repr(message.user_name), repr(the_message_id) )) self.connector.send_message( "Message for [noparse]{0}[/noparse]{4}! {1} <[noparse]{2}[/noparse]> {3}".format( message.user_name, self.format_timestamp(the_message_id, the_timestamp), the_sender, the_body, retainer_text ) ) elif len(messages) >= self.too_many_messages: logger.debug("{0} got {1} messages; putting on retainer".format(message.user_name, len(messages))) self.connector.send_message( "{0} new messages for [noparse]{1}[/noparse]{2}! Use \u201c!delivermsg [i]maxnumber[/i]\u201d to get " "them!".format( len(messages), message.user_name, retainer_text ) ) # put on retainer cursor = self.database.cursor() cursor.execute( "INSERT INTO messages_on_retainer SELECT * FROM messages WHERE recipient_folded=? " "ORDER BY message_id ASC", (lower_sender_name,) ) self.database.commit() cursor.close() # non-retained messages will be deleted below else: # multiple but not too many messages self.connector.send_message("{0} new messages for [noparse]{1}[/noparse]{2}!".format( len(messages), message.user_name, retainer_text )) for (the_timestamp, the_sender, the_body, the_message_id) in messages: logger.debug("delivering {0}'s message #{3} {1} to {2} as part of a chunk".format( repr(the_sender), repr(the_body), repr(message.user_name), repr(the_message_id) )) self.connector.send_message("{0} <[noparse]{1}[/noparse]> {2}".format( self.format_timestamp(the_message_id, the_timestamp), the_sender, the_body )) self.connector.send_message("[noparse]{0}[/noparse]: Have a nice day!".format(message.user_name)) # place them on the repeat heap cursor = self.database.cursor() cursor.execute( "INSERT INTO replayable_messages SELECT * FROM messages WHERE recipient_folded=? " "ORDER BY message_id ASC", (lower_sender_name,) ) self.database.commit() # purge the repeat heap if necessary cursor.execute("SELECT COUNT(*) FROM replayable_messages WHERE recipient_folded=?", (lower_sender_name,)) count = 0 for row in cursor: count = row[0] if count > self.max_messages_to_replay: cursor.execute( "SELECT message_id FROM replayable_messages WHERE recipient_folded=? ORDER BY message_id ASC", (lower_sender_name,) ) replayable_message_ids = [] for row in cursor: replayable_message_ids.append(row[0]) # lst[:-10] =^= everything but the last 10 elements for replayable_message_id_to_purge in replayable_message_ids[:-self.max_messages_to_replay]: cursor.execute("DELETE FROM replayable_messages WHERE message_id=?", (replayable_message_id_to_purge,)) self.database.commit() # delete delivered/skipped messages cursor.execute("DELETE FROM messages WHERE recipient_folded=?", (lower_sender_name,)) self.database.commit() cursor.close()