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: 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): 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): 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))
class Debian(callbacks.Plugin, PeriodicFileDownloader): threaded = True periodicFiles = { # This file is only updated once a week, so there's no sense in # downloading a new one every day. 'Contents-i386.gz': ('ftp://ftp.us.debian.org/' 'debian/dists/unstable/Contents-i386.gz', 604800, None) } contents = conf.supybot.directories.data.dirize('Contents-i386.gz') def file(self, irc, msg, args, optlist, glob): """[--{regexp,exact} <value>] [<glob>] Returns packages in Debian that includes files matching <glob>. If --regexp is given, returns packages that include files matching the given regexp. If --exact is given, returns packages that include files matching exactly the string given. """ self.getFile('Contents-i386.gz') # Make sure it's anchored, make sure it doesn't have a leading slash # (the filenames don't have leading slashes, and people may not know # that). if not optlist and not glob: raise callbacks.ArgumentError if optlist and glob: irc.error( 'You must specify either a glob or a regexp/exact ' 'search, but not both.', Raise=True) for (option, arg) in optlist: if option == 'exact': regexp = arg.lstrip('/') elif option == 'regexp': regexp = arg if glob: regexp = fnmatch.translate(glob.lstrip('/')) regexp = regexp.rstrip('$') regexp = ".*%s.* " % regexp try: re_obj = re.compile(regexp, re.I) except re.error, e: irc.error(format('Error in regexp: %s', e), Raise=True) if self.registryValue('pythonZgrep'): fd = gzip.open(self.contents) r = imap( lambda tup: tup[0], ifilter(lambda tup: tup[0], imap(lambda line: (re_obj.search(line), line), fd))) else: try: (r, w) = popen2.popen4(['zgrep', '-ie', regexp, self.contents]) w.close() except TypeError: # We're on Windows. irc.error( 'This command won\'t work on this platform. ' 'If you think it should (i.e., you know that you ' 'have a zgrep binary somewhere) then file a bug ' 'about it at http://supybot.sf.net/ .', Raise=True) packages = set() # Make packages unique try: for line in r: if len(packages) > 100: irc.error( 'More than 100 packages matched, ' 'please narrow your search.', Raise=True) try: if hasattr(line, 'group'): # we're actually using line = line.group(0) # pythonZgrep :( (filename, pkg_list) = line.split() if filename == 'FILE': # This is the last line before the actual files. continue except ValueError: # Unpack list of wrong size. continue # We've not gotten to the files yet. packages.update(pkg_list.split(',')) finally: if hasattr(r, 'close'): r.close() if len(packages) == 0: irc.reply('I found no packages with that file.') else: irc.reply(format('%L', sorted(packages)))