def _normalize(self, m): if ircmsgs.isAction(m): n = ircmsgs.prettyPrint(m).split(None, 2) try: return [' '.join(n[:2]), n[2]] except IndexError: # empty action return [' '.join(n[:2]), '\x00'] else: pretty = ircmsgs.prettyPrint(m).split(None, 1) if len(pretty) == 1: pretty.append('\x00') return pretty
def _normalize(self, m): if ircmsgs.isAction(m): n = ircmsgs.prettyPrint(m).split(None, 2) try: return [" ".join(n[:2]), n[2]] except IndexError: # empty action return [" ".join(n[:2]), "\x00"] else: pretty = ircmsgs.prettyPrint(m).split(None, 1) if len(pretty) == 1: pretty.append("\x00") return pretty
def doPart(self, irc, msg): channel = msg.args[0] said = ircmsgs.prettyPrint(msg) self.anydb.update(channel, msg.nick, said) try: id = ircdb.users.getUserId(msg.prefix) self.anydb.update(channel, id, said) except KeyError: pass # Not in the database.
def doQuit(self, irc, msg): said = ircmsgs.prettyPrint(msg) try: id = ircdb.users.getUserId(msg.prefix) except KeyError: id = None # Not in the database. for channel in msg.tagged('channels'): self.anydb.update(channel, msg.nick, said) if id is not None: self.anydb.update(channel, id, said)
def doPrivmsg(self, irc, msg): if self.shouldRelay(msg): target = self.registryValue('target') if target and target in irc.state.channels: if self.registryValue('fancy'): s = ircmsgs.prettyPrint(msg) else: s = msg.args[1] s = self.registryValue('prefix') + s irc.queueMsg(ircmsgs.privmsg(target, s))
def twitter_post(self, irc, msg): text = ircmsgs.prettyPrint(msg) text = text[text.find('>') + 2:] if len(text) > 140: text = text[:138] + '...' try: self.twitter.PostUpdate(text) except twitter.TwitterError: self.log.exception('Posting quote to twitter failed')
def doMode(self, irc, msg): # Filter out messages from network Services if msg.nick: try: id = ircdb.users.getUserId(msg.prefix) except KeyError: id = None # Not in the database. channel = msg.args[0] said = ircmsgs.prettyPrint(msg) self.anydb.update(channel, msg.nick, said) if id is not None: self.anydb.update(channel, id, said)
def wat(self, irc, msg, args, nick): """<nick> Grabs the last line said by <nick> and returns it with emojis translated """ chan = msg.args[0] selfCaller = False for m in reversed(irc.state.history): if m.command == 'PRIVMSG' and \ ircutils.nickEqual(m.nick, nick) and \ ircutils.strEqual(m.args[0], chan): if ircutils.nickEqual(nick, msg.nick) and selfCaller: irc.reply(emoji.demojize(ircmsgs.prettyPrint(m))) return elif ircutils.nickEqual(nick, msg.nick): selfCaller = True continue else: irc.reply(emoji.demojize(ircmsgs.prettyPrint(m))) return irc.error(_('I couldn\'t find a proper message to translate.'))
def doPrivmsg(self, irc, msg): ''' Dummy docstring. ''' if self.shouldRelay(msg): target = self.registryValue('target') if target and target in irc.state.channels: if self.registryValue('fancy'): s = ircmsgs.prettyPrint(msg) else: s = msg.args[1] s = self.registryValue('prefix') + s self.log.debug("regexrelay, queuing: " + s) irc.queueMsg(ircmsgs.privmsg(target, s))
def doQuit(self, irc, msg): said = ircmsgs.prettyPrint(msg) if irc not in self.ircstates: return try: id = ircdb.users.getUserId(msg.prefix) except KeyError: id = None # Not in the database. for channel in self.ircstates[irc].channels: if msg.nick in self.ircstates[irc].channels[channel].users: self.anydb.update(channel, msg.nick, said) if id is not None: self.anydb.update(channel, id, said)
def doPrivmsg(self, irc, msg): if ircmsgs.isCtcp(msg) and not ircmsgs.isAction(msg): return if msg.channel: channel = msg.channel said = ircmsgs.prettyPrint(msg) self.db.update(channel, msg.nick, said) self.anydb.update(channel, msg.nick, said) try: id = ircdb.users.getUserId(msg.prefix) self.db.update(channel, id, said) self.anydb.update(channel, id, said) except KeyError: pass # Not in the database.
def doPrivmsg(self, irc, msg): if ircmsgs.isCtcp(msg) and not ircmsgs.isAction(msg): return if irc.isChannel(msg.args[0]): channel = msg.args[0] said = ircmsgs.prettyPrint(msg) self.db.update(channel, msg.nick, said) self.anydb.update(channel, msg.nick, said) try: id = ircdb.users.getUserId(msg.prefix) self.db.update(channel, id, said) self.anydb.update(channel, id, said) except KeyError: pass # Not in the database.
def add(self, channel, msg, by): db = self._getDb(channel) cursor = db.cursor() text = ircmsgs.prettyPrint(msg) # Check to see if the latest quotegrab is identical cursor.execute("""SELECT quote FROM quotegrabs WHERE nick=%s ORDER BY id DESC LIMIT 1""", msg.nick) if cursor.rowcount != 0: if text == cursor.fetchone()[0]: return cursor.execute("""INSERT INTO quotegrabs VALUES (NULL, %s, %s, %s, %s, %s)""", msg.nick, msg.prefix, by, int(time.time()), text) db.commit()
def add(self, channel, msg, by): db = self._getDb(channel) cursor = db.cursor() text = ircmsgs.prettyPrint(msg) # Check to see if the latest quotegrab is identical cursor.execute("""SELECT quote FROM quotegrabs WHERE nick=? ORDER BY id DESC LIMIT 1""", (msg.nick,)) results = cursor.fetchall() if len(results) != 0: if text == results[0][0]: return cursor.execute("""INSERT INTO quotegrabs VALUES (NULL, ?, ?, ?, ?, ?)""", (msg.nick, msg.prefix, by, int(time.time()), text,)) db.commit()
def add(self, msg, by): channel = msg.args[0] db = self.getDb(channel) cursor = db.cursor() text = ircmsgs.prettyPrint(msg) # Check to see if the latest quotegrab is identical cursor.execute("""SELECT quote FROM quotegrabs WHERE nick=? ORDER BY id DESC LIMIT 1""", (msg.nick,)) quote = cursor.fetchone() if quote and text == quote[0]: return cursor.execute("""INSERT INTO quotegrabs VALUES (NULL, ?, ?, ?, ?, ?, 0)""", (msg.nick, msg.prefix, by, int(time.time()), text)) db.commit()
def add(self, channel, msg, by): db = self._getDb(channel) cursor = db.cursor() text = ircmsgs.prettyPrint(msg) # Check to see if the latest quotegrab is identical cursor.execute( """SELECT quote FROM quotegrabs WHERE nick=%s ORDER BY id DESC LIMIT 1""", msg.nick) if cursor.rowcount != 0: if text == cursor.fetchone()[0]: return cursor.execute( """INSERT INTO quotegrabs VALUES (NULL, %s, %s, %s, %s, %s)""", msg.nick, msg.prefix, by, int(time.time()), text) db.commit()
def add(self, msg, by): channel = msg.args[0] db = self.getDb(channel) cursor = db.cursor() text = ircmsgs.prettyPrint(msg) # Check to see if the latest quotegrab is identical cursor.execute( """SELECT quote FROM quotegrabs WHERE nick=? ORDER BY id DESC LIMIT 1""", (msg.nick, )) quote = cursor.fetchone() if quote and text == quote[0]: return cursor.execute( """INSERT INTO quotegrabs VALUES (NULL, ?, ?, ?, ?, ?, 0)""", (msg.nick, msg.prefix, by, int(time.time()), text)) db.commit()
def doPrivmsg(self, irc, msg): __dir__ = os.path.dirname(os.path.abspath(__file__)) if not irc.isChannel(msg.args[0]): return curTime = time.time() channel = msg.args[0] said = ircmsgs.prettyPrint(msg, showNick=False) nick = msg.nick print("Checking %s %s: %s at time %d" % (channel, nick, said, curTime)) if said.find("I CALL UPON THE POWER OF THE SPREADSHEET") != -1: if (self.lastPull + SS_DOWNLOAD_SECONDS) < curTime: irc.reply("loading hacking tools...") os.system("cd " + __dir__ + "; ./get_new_opinions.sh") irc.reply("hacking tools loaded, %d hacks total" % (len(self.opinions), )) self.load_opinions() self.lastPull = time.time() self.lastSent = time.time() - COOL_DOWN_SECONDS # allow test else: print("ignored %s, %d minutes remain" % (said, ((self.lastPull + SS_DOWNLOAD_SECONDS) - curTime) / 60)) return didReply = False for (reg, res) in self.opinions: # match beginning of string/whitespace word end of string/whitespace m = reg.search(said) if m is not None: if (self.lastSent + COOL_DOWN_SECONDS) < curTime: irc.reply(m.group(2) + res) didReply = True else: print( "ignored %s, %d minutes remain" % (said, ((self.lastSent + COOL_DOWN_SECONDS) - curTime) / 60)) if didReply: self.lastSent = time.time()
def doPrivmsg(self, irc, msg): curTime = time.time() if (self.lastSent + COOL_DOWN_SECONDS) > curTime: return # skip, we're cooling down if irc.isChannel(msg.args[0]): channel = msg.args[0] said = ircmsgs.prettyPrint(msg, showNick=False) nick = msg.nick __dir__ = os.path.dirname(os.path.abspath(__file__)) filepath = os.path.join(__dir__, "opinions.csv") opinions = csv.reader(open(filepath, "rb")) for row in opinions: # match beginning of string/whitespace word end of string/whitespace if re.search("(\(|\s|^)" + row[0].lower() + "(\s|\)|\.|\?|\!|$)", said.lower()) is not None: irc.reply(row[0] + "? " + row[1] + ". " + ",".join(row[2:])) self.lastSent = time.time()
def doPrivmsg(self, irc, msg): __dir__ = os.path.dirname(os.path.abspath(__file__)) if not irc.isChannel(msg.args[0]): return curTime = time.time() channel = msg.args[0] said = ircmsgs.prettyPrint(msg, showNick=False) nick = msg.nick print("Checking %s %s: %s at time %d" % (channel, nick, said, curTime)); if said.find("I CALL UPON THE POWER OF THE SPREADSHEET") != -1: if (self.lastPull + SS_DOWNLOAD_SECONDS) < curTime: irc.reply("loading hacking tools...") os.system("cd " + __dir__ + "; ./get_new_opinions.sh") irc.reply("hacking tools loaded, %d hacks total" % (len(self.opinions),)) self.load_opinions() self.lastPull = time.time() self.lastSent = time.time() - COOL_DOWN_SECONDS # allow test else: print("ignored %s, %d minutes remain" % (said, ((self.lastPull + SS_DOWNLOAD_SECONDS) - curTime)/60)) return didReply = False for (reg, res) in self.opinions: # match beginning of string/whitespace word end of string/whitespace m = reg.search(said) if m is not None: if (self.lastSent + COOL_DOWN_SECONDS) < curTime: irc.reply(m.group(2) + res) didReply = True else: print("ignored %s, %d minutes remain" % (said, ((self.lastSent + COOL_DOWN_SECONDS) - curTime)/60)) if didReply: self.lastSent = time.time()
def last(self, irc, msg, args, optlist): """[--{from,in,on,with,without,regexp} <value>] [--nolimit] Returns the last message matching the given criteria. --from requires a nick from whom the message came; --in requires a channel the message was sent to; --on requires a network the message was sent on; --with requires some string that had to be in the message; --regexp requires a regular expression the message must match; --nolimit returns all the messages that can be found. By default, the channel this command is given in is searched. """ predicates = {} nolimit = False skipfirst = True if ircutils.isChannel(msg.args[0]): predicates["in"] = lambda m: ircutils.strEqual(m.args[0], msg.args[0]) else: skipfirst = False for (option, arg) in optlist: if option == "from": def f(m, arg=arg): return ircutils.hostmaskPatternEqual(arg, m.nick) predicates["from"] = f elif option == "in": def f(m, arg=arg): return ircutils.strEqual(m.args[0], arg) predicates["in"] = f if arg != msg.args[0]: skipfirst = False elif option == "on": def f(m, arg=arg): return m.receivedOn == arg predicates["on"] = f elif option == "with": def f(m, arg=arg): return arg.lower() in m.args[1].lower() predicates.setdefault("with", []).append(f) elif option == "without": def f(m, arg=arg): return arg.lower() not in m.args[1].lower() predicates.setdefault("without", []).append(f) elif option == "regexp": def f(m, arg=arg): def f1(s, arg): """Since we can't enqueue match objects into the multiprocessing queue, we'll just wrap the function to return bools.""" if arg.search(s) is not None: return True else: return False if ircmsgs.isAction(m): m1 = ircmsgs.unAction(m) # return arg.search(ircmsgs.unAction(m)) else: m1 = m.args[1] # return arg.search(m.args[1]) try: # use a subprocess here, since specially crafted regexps can # take exponential time and hang up the bot. # timeout of 0.1 should be more than enough for any normal regexp. v = commands.process(f1, m1, arg, timeout=0.1, pn=self.name(), cn="last") return v except commands.ProcessTimeoutError: return False predicates.setdefault("regexp", []).append(f) elif option == "nolimit": nolimit = True iterable = ifilter(self._validLastMsg, reversed(irc.state.history)) if skipfirst: # Drop the first message only if our current channel is the same as # the channel we've been instructed to look at. iterable.next() predicates = list(utils.iter.flatten(predicates.itervalues())) # Make sure the user can't get messages from channels they aren't in def userInChannel(m): return m.args[0] in irc.state.channels and msg.nick in irc.state.channels[m.args[0]].users predicates.append(userInChannel) # Make sure the user can't get messages from a +s channel unless # they're calling the command from that channel or from a query def notSecretMsg(m): return ( not irc.isChannel(msg.args[0]) or msg.args[0] == m.args[0] or (m.args[0] in irc.state.channels and "s" not in irc.state.channels[m.args[0]].modes) ) predicates.append(notSecretMsg) resp = [] if irc.nested and not self.registryValue("last.nested.includeTimestamp"): tsf = None else: tsf = self.registryValue("timestampFormat") if irc.nested and not self.registryValue("last.nested.includeNick"): showNick = False else: showNick = True for m in iterable: for predicate in predicates: try: if not predicate(m): break except RegexpTimeout: irc.error(_("The regular expression timed out.")) return else: if nolimit: resp.append(ircmsgs.prettyPrint(m, timestampFormat=tsf, showNick=showNick)) else: irc.reply(ircmsgs.prettyPrint(m, timestampFormat=tsf, showNick=showNick)) return if not resp: irc.error( _("I couldn't find a message matching that criteria in " "my history of %s messages.") % len(irc.state.history) ) else: irc.reply(format("%L", resp))
def last(self, irc, msg, args, optlist): """[--{from,in,on,with,without,regexp} <value>] [--nolimit] Returns the last message matching the given criteria. --from requires a nick from whom the message came; --in requires a channel the message was sent to; --on requires a network the message was sent on; --with requires some string that had to be in the message; --regexp requires a regular expression the message must match; --nolimit returns all the messages that can be found. By default, the channel this command is given in is searched. """ predicates = {} nolimit = False skipfirst = True if msg.channel: predicates['in'] = lambda m: ircutils.strEqual( m.args[0], msg.channel) else: skipfirst = False final_predicates = [] for (option, arg) in optlist: if option == 'from': def f(m, arg=arg): return ircutils.hostmaskPatternEqual(arg, m.nick) predicates['from'] = f elif option == 'in': def f(m, arg=arg): return ircutils.strEqual(m.args[0], arg) predicates['in'] = f if arg != msg.channel: skipfirst = False elif option == 'on': def f(m, arg=arg): return m.receivedOn == arg predicates['on'] = f elif option == 'with': def f(m, arg=arg): return arg.lower() in m.args[1].lower() predicates.setdefault('with', []).append(f) elif option == 'without': def f(m, arg=arg): return arg.lower() not in m.args[1].lower() predicates.setdefault('without', []).append(f) elif option == 'regexp': def f(messages, arg=arg): reobj = re.compile(arg) # using a queue to return results, so we can return at # least some results in case of timeout q = multiprocessing.Queue() def p(messages): for m in messages: if ircmsgs.isAction(m): s = ircmsgs.unAction(m) else: s = m.args[1] if reobj.search(s): q.put(m) try: process(p, messages, timeout=3., pn=self.name(), cn='last') except ProcessTimeoutError: pass results = [] while True: try: results.append(q.get(False)) except queue.Empty: break return results final_predicates.append(f) elif option == 'nolimit': nolimit = True iterable = filter(functools.partial(self._validLastMsg, irc), reversed(irc.state.history)) if skipfirst: # Drop the first message only if our current channel is the same as # the channel we've been instructed to look at. next(iterable) predicates = list(utils.iter.flatten(predicates.values())) # Make sure the user can't get messages from channels they aren't in def userInChannel(m): return m.args[0] in irc.state.channels \ and msg.nick in irc.state.channels[m.args[0]].users predicates.append(userInChannel) # Make sure the user can't get messages from a +s channel unless # they're calling the command from that channel or from a query # TODO: support statusmsg, but be careful about leaking scopes. def notSecretMsg(m): return not irc.isChannel(msg.args[0]) \ or msg.args[0] == m.args[0] \ or (m.args[0] in irc.state.channels \ and 's' not in irc.state.channels[m.args[0]].modes) predicates.append(notSecretMsg) resp = [] if irc.nested and not \ self.registryValue('last.nested.includeTimestamp'): tsf = None else: tsf = self.registryValue('timestampFormat') if irc.nested and not self.registryValue('last.nested.includeNick'): showNick = False else: showNick = True candidates = [] # Run predicates that filter on individual messages for m in iterable: for predicate in predicates: if not predicate(m): break else: candidates.append(m) # Run predicates that filter lists of messages for predicate in final_predicates: candidates = predicate(candidates) for m in candidates: if nolimit: resp.append( ircmsgs.prettyPrint(m, timestampFormat=tsf, showNick=showNick)) else: irc.reply( ircmsgs.prettyPrint(m, timestampFormat=tsf, showNick=showNick)) return if not resp: irc.error( _('I couldn\'t find a message matching that criteria in ' 'my history of %s messages.') % len(irc.state.history)) else: irc.reply(format('%L', resp))
def last(self, irc, msg, args, optlist): """[--{from,in,on,with,without,regexp} <value>] [--nolimit] Returns the last message matching the given criteria. --from requires a nick from whom the message came; --in requires a channel the message was sent to; --on requires a network the message was sent on; --with requires some string that had to be in the message; --regexp requires a regular expression the message must match; --nolimit returns all the messages that can be found. By default, the channel this command is given in is searched. """ predicates = {} nolimit = False skipfirst = True if ircutils.isChannel(msg.args[0]): predicates["in"] = lambda m: ircutils.strEqual(m.args[0], msg.args[0]) else: skipfirst = False for (option, arg) in optlist: if option == "from": def f(m, arg=arg): return ircutils.hostmaskPatternEqual(arg, m.nick) predicates["from"] = f elif option == "in": def f(m, arg=arg): return ircutils.strEqual(m.args[0], arg) predicates["in"] = f if arg != msg.args[0]: skipfirst = False elif option == "on": def f(m, arg=arg): return m.receivedOn == arg predicates["on"] = f elif option == "with": def f(m, arg=arg): return arg.lower() in m.args[1].lower() predicates.setdefault("with", []).append(f) elif option == "without": def f(m, arg=arg): return arg.lower() not in m.args[1].lower() predicates.setdefault("without", []).append(f) elif option == "regexp": def f(m, arg=arg): if ircmsgs.isAction(m): m1 = ircmsgs.unAction(m) else: m1 = m.args[1] return regexp_wrapper(m1, reobj=arg, timeout=0.1, plugin_name=self.name(), fcn_name="last") predicates.setdefault("regexp", []).append(f) elif option == "nolimit": nolimit = True iterable = ifilter(self._validLastMsg, reversed(irc.state.history)) if skipfirst: # Drop the first message only if our current channel is the same as # the channel we've been instructed to look at. iterable.next() predicates = list(utils.iter.flatten(predicates.itervalues())) # Make sure the user can't get messages from channels they aren't in def userInChannel(m): return m.args[0] in irc.state.channels and msg.nick in irc.state.channels[m.args[0]].users predicates.append(userInChannel) # Make sure the user can't get messages from a +s channel unless # they're calling the command from that channel or from a query def notSecretMsg(m): return ( not irc.isChannel(msg.args[0]) or msg.args[0] == m.args[0] or (m.args[0] in irc.state.channels and "s" not in irc.state.channels[m.args[0]].modes) ) predicates.append(notSecretMsg) resp = [] if irc.nested and not self.registryValue("last.nested.includeTimestamp"): tsf = None else: tsf = self.registryValue("timestampFormat") if irc.nested and not self.registryValue("last.nested.includeNick"): showNick = False else: showNick = True for m in iterable: for predicate in predicates: if not predicate(m): break else: if nolimit: resp.append(ircmsgs.prettyPrint(m, timestampFormat=tsf, showNick=showNick)) else: irc.reply(ircmsgs.prettyPrint(m, timestampFormat=tsf, showNick=showNick)) return if not resp: irc.error( "I couldn't find a message matching that criteria in " "my history of %s messages." % len(irc.state.history) ) else: irc.reply(format("%L", resp))
def last(self, irc, msg, args, optlist): """[--{from,in,on,with,without,regexp} <value>] [--nolimit] Returns the last message matching the given criteria. --from requires a nick from whom the message came; --in requires a channel the message was sent to; --on requires a network the message was sent on; --with requires some string that had to be in the message; --regexp requires a regular expression the message must match; --nolimit returns all the messages that can be found. By default, the channel this command is given in is searched. """ predicates = {} nolimit = False skipfirst = True if ircutils.isChannel(msg.args[0]): predicates['in'] = lambda m: ircutils.strEqual( m.args[0], msg.args[0]) else: skipfirst = False for (option, arg) in optlist: if option == 'from': def f(m, arg=arg): return ircutils.hostmaskPatternEqual(arg, m.nick) predicates['from'] = f elif option == 'in': def f(m, arg=arg): return ircutils.strEqual(m.args[0], arg) predicates['in'] = f if arg != msg.args[0]: skipfirst = False elif option == 'on': def f(m, arg=arg): return m.receivedOn == arg predicates['on'] = f elif option == 'with': def f(m, arg=arg): return arg.lower() in m.args[1].lower() predicates.setdefault('with', []).append(f) elif option == 'without': def f(m, arg=arg): return arg.lower() not in m.args[1].lower() predicates.setdefault('without', []).append(f) elif option == 'regexp': def f(m, arg=arg): if ircmsgs.isAction(m): return arg.search(ircmsgs.unAction(m)) else: return arg.search(m.args[1]) predicates.setdefault('regexp', []).append(f) elif option == 'nolimit': nolimit = True iterable = ifilter(self._validLastMsg, reversed(irc.state.history)) if skipfirst: # Drop the first message only if our current channel is the same as # the channel we've been instructed to look at. iterable.next() predicates = list(utils.iter.flatten(predicates.itervalues())) # Make sure the user can't get messages from channels they aren't in def userInChannel(m): return m.args[0] in irc.state.channels \ and msg.nick in irc.state.channels[m.args[0]].users predicates.append(userInChannel) # Make sure the user can't get messages from a +s channel unless # they're calling the command from that channel or from a query def notSecretMsg(m): return not irc.isChannel(msg.args[0]) \ or msg.args[0] == m.args[0] \ or (m.args[0] in irc.state.channels \ and 's' not in irc.state.channels[m.args[0]].modes) predicates.append(notSecretMsg) resp = [] if irc.nested and not \ self.registryValue('last.nested.includeTimestamp'): tsf = None else: tsf = self.registryValue('timestampFormat') if irc.nested and not self.registryValue('last.nested.includeNick'): showNick = False else: showNick = True for m in iterable: for predicate in predicates: if not predicate(m): break else: if nolimit: resp.append( ircmsgs.prettyPrint(m, timestampFormat=tsf, showNick=showNick)) else: irc.reply( ircmsgs.prettyPrint(m, timestampFormat=tsf, showNick=showNick)) return if not resp: irc.error('I couldn\'t find a message matching that criteria in ' 'my history of %s messages.' % len(irc.state.history)) else: irc.reply(format('%L', resp))
def last(self, irc, msg, args, optlist): """[--{from,in,on,with,without,regexp} <value>] [--nolimit] Returns the last message matching the given criteria. --from requires a nick from whom the message came; --in requires a channel the message was sent to; --on requires a network the message was sent on; --with requires some string that had to be in the message; --regexp requires a regular expression the message must match; --nolimit returns all the messages that can be found. By default, the channel this command is given in is searched. """ predicates = {} nolimit = False skipfirst = True if ircutils.isChannel(msg.args[0]): predicates['in'] = lambda m: ircutils.strEqual(m.args[0], msg.args[0]) else: skipfirst = False for (option, arg) in optlist: if option == 'from': def f(m, arg=arg): return ircutils.hostmaskPatternEqual(arg, m.nick) predicates['from'] = f elif option == 'in': def f(m, arg=arg): return ircutils.strEqual(m.args[0], arg) predicates['in'] = f if arg != msg.args[0]: skipfirst = False elif option == 'on': def f(m, arg=arg): return m.receivedOn == arg predicates['on'] = f elif option == 'with': def f(m, arg=arg): return arg.lower() in m.args[1].lower() predicates.setdefault('with', []).append(f) elif option == 'without': def f(m, arg=arg): return arg.lower() not in m.args[1].lower() predicates.setdefault('without', []).append(f) elif option == 'regexp': def f(m, arg=arg): def f1(s, arg): """Since we can't enqueue match objects into the multiprocessing queue, we'll just wrap the function to return bools.""" if arg.search(s) is not None: return True else: return False if ircmsgs.isAction(m): m1 = ircmsgs.unAction(m) else: m1 = m.args[1] return regexp_wrapper(m1, reobj=arg, timeout=0.1, plugin_name=self.name(), fcn_name='last') predicates.setdefault('regexp', []).append(f) elif option == 'nolimit': nolimit = True iterable = filter(self._validLastMsg, reversed(irc.state.history)) if skipfirst: # Drop the first message only if our current channel is the same as # the channel we've been instructed to look at. next(iterable) predicates = list(utils.iter.flatten(predicates.itervalues())) # Make sure the user can't get messages from channels they aren't in def userInChannel(m): return m.args[0] in irc.state.channels \ and msg.nick in irc.state.channels[m.args[0]].users predicates.append(userInChannel) # Make sure the user can't get messages from a +s channel unless # they're calling the command from that channel or from a query def notSecretMsg(m): return not irc.isChannel(msg.args[0]) \ or msg.args[0] == m.args[0] \ or (m.args[0] in irc.state.channels \ and 's' not in irc.state.channels[m.args[0]].modes) predicates.append(notSecretMsg) resp = [] if irc.nested and not \ self.registryValue('last.nested.includeTimestamp'): tsf = None else: tsf = self.registryValue('timestampFormat') if irc.nested and not self.registryValue('last.nested.includeNick'): showNick = False else: showNick = True for m in iterable: for predicate in predicates: try: if not predicate(m): break except RegexpTimeout: irc.error(_('The regular expression timed out.')) return else: if nolimit: resp.append(ircmsgs.prettyPrint(m, timestampFormat=tsf, showNick=showNick)) else: irc.reply(ircmsgs.prettyPrint(m, timestampFormat=tsf, showNick=showNick)) return if not resp: irc.error(_('I couldn\'t find a message matching that criteria in ' 'my history of %s messages.') % len(irc.state.history)) else: irc.reply(format('%L', resp))
def last(self, irc, msg, args, optlist): """[--{from,in,on,with,without,regexp} <value>] [--nolimit] Returns the last message matching the given criteria. --from requires a nick from whom the message came; --in requires a channel the message was sent to; --on requires a network the message was sent on; --with requires some string that had to be in the message; --regexp requires a regular expression the message must match; --nolimit returns all the messages that can be found. By default, the channel this command is given in is searched. """ predicates = {} nolimit = False skipfirst = True if msg.channel: predicates['in'] = lambda m: ircutils.strEqual( m.args[0], msg.channel) else: skipfirst = False for (option, arg) in optlist: if option == 'from': def f(m, arg=arg): return ircutils.hostmaskPatternEqual(arg, m.nick) predicates['from'] = f elif option == 'in': def f(m, arg=arg): return ircutils.strEqual(m.args[0], arg) predicates['in'] = f if arg != msg.channel: skipfirst = False elif option == 'on': def f(m, arg=arg): return m.receivedOn == arg predicates['on'] = f elif option == 'with': def f(m, arg=arg): return arg.lower() in m.args[1].lower() predicates.setdefault('with', []).append(f) elif option == 'without': def f(m, arg=arg): return arg.lower() not in m.args[1].lower() predicates.setdefault('without', []).append(f) elif option == 'regexp': def f(m, arg=arg): def f1(s, arg): """Since we can't enqueue match objects into the multiprocessing queue, we'll just wrap the function to return bools.""" if process(arg.search, s, timeout=0.1) is not None: return True else: return False if ircmsgs.isAction(m): m1 = ircmsgs.unAction(m) else: m1 = m.args[1] return regexp_wrapper(m1, reobj=arg, timeout=0.1, plugin_name=self.name(), fcn_name='last') predicates.setdefault('regexp', []).append(f) elif option == 'nolimit': nolimit = True iterable = filter(functools.partial(self._validLastMsg, irc), reversed(irc.state.history)) if skipfirst: # Drop the first message only if our current channel is the same as # the channel we've been instructed to look at. next(iterable) predicates = list(utils.iter.flatten(predicates.values())) # Make sure the user can't get messages from channels they aren't in def userInChannel(m): return m.args[0] in irc.state.channels \ and msg.nick in irc.state.channels[m.args[0]].users predicates.append(userInChannel) # Make sure the user can't get messages from a +s channel unless # they're calling the command from that channel or from a query # TODO: support statusmsg, but be careful about leaking scopes. def notSecretMsg(m): return not irc.isChannel(msg.args[0]) \ or msg.args[0] == m.args[0] \ or (m.args[0] in irc.state.channels \ and 's' not in irc.state.channels[m.args[0]].modes) predicates.append(notSecretMsg) resp = [] if irc.nested and not \ self.registryValue('last.nested.includeTimestamp'): tsf = None else: tsf = self.registryValue('timestampFormat') if irc.nested and not self.registryValue('last.nested.includeNick'): showNick = False else: showNick = True for m in iterable: for predicate in predicates: try: if not predicate(m): break except RegexpTimeout: irc.error(_('The regular expression timed out.')) return else: if nolimit: resp.append( ircmsgs.prettyPrint(m, timestampFormat=tsf, showNick=showNick)) else: irc.reply( ircmsgs.prettyPrint(m, timestampFormat=tsf, showNick=showNick)) return if not resp: irc.error( _('I couldn\'t find a message matching that criteria in ' 'my history of %s messages.') % len(irc.state.history)) else: irc.reply(format('%L', resp))