def _runCommandFunction(self, irc, msg, command): """Run a command from message, as if command was sent over IRC.""" tokens = callbacks.tokenize(command) try: self.Proxy(irc.irc, msg, tokens) except Exception, e: log.exception('Uncaught exception in function called by MessageParser:')
def doPrivmsg(self, irc, msg): if self.commandCalled: self.commandCalled = False return channel = msg.args[0] Owner = irc.getCallback('Owner') observers = self.registryValue('observers') active = self.registryValue('observers.active', channel) for name in active: if name not in observers: self.log.error('Active observers for %s include an ' 'invalid observer: %s.', channel, name) continue observer = self.registryValue('observers.%s' % name, value=False) probability = observer.probability() if random.random() > probability: continue r = observer() # The regexp. m = r.search(msg.args[1]) if m is not None: command = observer.command() groups = list(m.groups()) groups.insert(0, m.group(0)) for (i, group) in enumerate(groups): command = command.replace('$%s' % i, group) tokens = callbacks.tokenize(command, channel=channel) Owner.processTokens(irc, msg, tokens)
def _runCommandFunction(self, irc, msg, command): """Run a command from message, as if command was sent over IRC.""" tokens = callbacks.tokenize(command) try: self.Proxy(irc.irc, msg, tokens) except Exception as e: self.log.exception('Uncaught exception in requested function:')
def handle(self): def hash_(data): return hashlib.sha1(str(time.time()) + data).hexdigest() self.request.settimeout(0.5) currentLine = '' prefix = 'a%s!%s@%s.supybot-gui' % tuple([hash_(x)[0:6] for x in 'abc']) while self.server.enabled: if not '\n' in currentLine: try: data = self.request.recv(4096) except socket.timeout: time.sleep(0.1) # in case of odd problem continue if not data: # Server closed connection return if '\n' in data: splitted = (currentLine + data).split('\n') currentLine = splitted[0] nextLines = '\n'.join(splitted[1:]) else: continue splitted = currentLine.split(': ') hash_, command = splitted[0], ': '.join(splitted[1:]) tokens = callbacks.tokenize(command) fakeIrc = FakeIrc(self.server._irc) msg = ircmsgs.privmsg(self.server._irc.nick, currentLine, prefix) self.server._plugin.Proxy(fakeIrc, msg, tokens) self.request.send('%s: %s\n' % (hash_, fakeIrc.message)) currentLine = nextLines
def _slot(self, lastItem): irc = lastItem.irc msg = lastItem.msg channel = lastItem.channel prefix = lastItem.prefix nick = prefix.split('!')[0] kind = lastItem.kind try: ircdb.users.getUser(msg.prefix) # May raise KeyError capability = self.registryValue('exempt') if capability: if ircdb.checkCapability(msg.prefix, capability): return except KeyError: pass punishment = self.registryValue('%s.punishment' % kind, channel) reason = _('%s flood detected') % kind if punishment == 'kick': msg = ircmsgs.kick(channel, nick, reason) irc.queueMsg(msg) elif punishment == 'ban': msg = ircmsgs.ban(channel, prefix) irc.queueMsg(msg) elif punishment == 'kban': msg = ircmsgs.kick(channel, nick, reason) irc.queueMsg(msg) msg = ircmsgs.ban(channel, prefix) irc.queueMsg(msg) elif punishment.startswith('mode'): msg = ircmsgs.mode(channel, punishment[len('mode'):]) irc.queueMsg(msg) elif punishment.startswith('command '): tokens = callbacks.tokenize(punishment[len('command '):]) self.Proxy(irc, msg, tokens)
def doPrivmsg(self, irc, msg): assert self is irc.callbacks[0], \ 'Owner isn\'t first callback: %r' % irc.callbacks if ircmsgs.isCtcp(msg): return s = callbacks.addressed(irc.nick, msg) if s: ignored = ircdb.checkIgnored(msg.prefix) if ignored: self.log.info('Ignoring command from %s.', msg.prefix) return maximum = conf.supybot.abuse.flood.command.maximum() self.commands.enqueue(msg) if conf.supybot.abuse.flood.command() \ and self.commands.len(msg) > maximum \ and not ircdb.checkCapability(msg.prefix, 'owner'): punishment = conf.supybot.abuse.flood.command.punishment() banmask = ircutils.banmask(msg.prefix) self.log.info( 'Ignoring %s for %s seconds due to an apparent ' 'command flood.', banmask, punishment) ircdb.ignores.add(banmask, time.time() + punishment) irc.reply( 'You\'ve given me %s commands within the last ' 'minute; I\'m now ignoring you for %s.' % (maximum, utils.timeElapsed(punishment, seconds=False))) return try: tokens = callbacks.tokenize(s, channel=msg.args[0]) self.Proxy(irc, msg, tokens) except SyntaxError, e: irc.queueMsg(callbacks.error(msg, str(e)))
def cerror(self, irc, msg, args, testcommand): """<testcommand> Runs <testcommand> and returns true if it raises an error; false otherwise. """ tokens = callbacks.tokenize(testcommand) InvalidCommand = collections.namedtuple('InvalidCommand', 'command') replies = [] errors = [] class ErrorReportingProxy(self.Proxy): def reply(self2, s, *args, **kwargs): replies.append(s) def error(self2, s, Raise=False, *args, **kwargs): errors.append(s) if Raise: raise ArgumentError def _callInvalidCommands(self2): errors.append(InvalidCommand(self2.args)) def evalArgs(self2): # We don't want the replies in the nested command to # be stored here. super(ErrorReportingProxy, self2).evalArgs(withClass=self.Proxy) try: ErrorReportingProxy(irc.irc, msg, tokens) except callbacks.ArgumentError as e: pass # TODO: do something with the results if errors: irc.reply('true') else: irc.reply('false')
def doPrivmsg(self, irc, msg): assert self is irc.callbacks[0], \ 'Owner isn\'t first callback: %r' % irc.callbacks if ircmsgs.isCtcp(msg): return s = callbacks.addressed(irc.nick, msg) if s: ignored = ircdb.checkIgnored(msg.prefix) if ignored: self.log.info('Ignoring command from %s.', msg.prefix) return maximum = conf.supybot.abuse.flood.command.maximum() self.commands.enqueue(msg) if conf.supybot.abuse.flood.command() \ and self.commands.len(msg) > maximum \ and not ircdb.checkCapability(msg.prefix, 'trusted'): punishment = conf.supybot.abuse.flood.command.punishment() banmask = ircutils.banmask(msg.prefix) self.log.info('Ignoring %s for %s seconds due to an apparent ' 'command flood.', banmask, punishment) ircdb.ignores.add(banmask, time.time() + punishment) irc.reply('You\'ve given me %s commands within the last ' 'minute; I\'m now ignoring you for %s.' % (maximum, utils.timeElapsed(punishment, seconds=False))) return try: tokens = callbacks.tokenize(s, channel=msg.args[0]) self.Proxy(irc, msg, tokens) except SyntaxError, e: irc.queueMsg(callbacks.error(msg, str(e)))
def handle(self): def hash_(data): return hashlib.sha1(str(time.time()) + data).hexdigest() self.request.settimeout(0.5) currentLine = '' prefix = 'a%s!%s@%s.supybot-gui' % tuple( [hash_(x)[0:6] for x in 'abc']) while self.server.enabled: if not '\n' in currentLine: try: data = self.request.recv(4096) except socket.timeout: time.sleep(0.1) # in case of odd problem continue if not data: # Server closed connection return if '\n' in data: splitted = (currentLine + data).split('\n') currentLine = splitted[0] nextLines = '\n'.join(splitted[1:]) else: continue splitted = currentLine.split(': ') hash_, command = splitted[0], ': '.join(splitted[1:]) tokens = callbacks.tokenize(command) fakeIrc = FakeIrc(self.server._irc) msg = ircmsgs.privmsg(self.server._irc.nick, currentLine, prefix) self.server._plugin.Proxy(fakeIrc, msg, tokens) self.request.send('%s: %s\n' % (hash_, fakeIrc.message)) currentLine = nextLines
def f(irc, msg, args): tokens = callbacks.tokenize(original) if biggestDollar or biggestAt: args = getArgs(args, required=biggestDollar, optional=biggestAt, wildcard=wildcard) remaining_len = conf.supybot.reply.maximumLength() for (i, arg) in enumerate(args): if remaining_len < len(arg): arg = arg[0:remaining_len] args[i + 1:] = [] break remaining_len -= len(arg) def regexpReplace(m): idx = int(m.group(1)) return args[idx - 1] def replace(tokens, replacer): for (i, token) in enumerate(tokens): if isinstance(token, list): replace(token, replacer) else: tokens[i] = replacer(token) replace(tokens, lambda s: dollarRe.sub(regexpReplace, s)) if biggestAt: assert not wildcard args = args[biggestDollar:] replace(tokens, lambda s: atRe.sub(regexpReplace, s)) if wildcard: assert not biggestAt # Gotta remove the things that have already been subbed in. i = biggestDollar args[:] = args[i:] def everythingReplace(tokens): skip = 0 for (i, token) in enumerate(tokens): if skip: skip -= 1 continue if isinstance(token, list): everythingReplace(token) if token == '$*': tokens[i:i + 1] = args skip = len(args) - 1 # do not make replacements in # tokens we just added elif '$*' in token: tokens[i] = token.replace('$*', ' '.join(args)) everythingReplace(tokens) maxNesting = conf.supybot.commands.nested.maximum() if maxNesting and irc.nested + 1 > maxNesting: irc.error(_('You\'ve attempted more nesting than is ' 'currently allowed on this bot.'), Raise=True) self.Proxy(irc, msg, tokens, nested=irc.nested + 1)
def _runCommandFunction(self, irc, msg, command): """Run a command from message, as if command was sent over IRC.""" tokens = callbacks.tokenize(command) try: self.Proxy(irc.irc, msg, tokens) except Exception, e: log.exception( 'Uncaught exception in function called by MessageParser:')
def _makeCommandFunction(self, irc, msg, command, remove=True): """Makes a function suitable for scheduling from command.""" tokens = callbacks.tokenize(command) def f(): if remove: del self.events[str(f.eventId)] self.Proxy(irc.irc, msg, tokens) return f
def f(self, irc, msg, args): alias = original.replace('$nick', msg.nick) if '$channel' in original: channel = getChannel(msg, args) alias = alias.replace('$channel', channel) tokens = callbacks.tokenize(alias) if biggestDollar or biggestAt: args = getArgs(args, required=biggestDollar, optional=biggestAt, wildcard=wildcard) max_len = conf.supybot.reply.maximumLength() args = list([x[:max_len] for x in args]) def regexpReplace(m): idx = int(m.group(1)) return args[idx - 1] def replace(tokens, replacer): for (i, token) in enumerate(tokens): if isinstance(token, list): replace(token, replacer) else: tokens[i] = replacer(token) replace(tokens, lambda s: dollarRe.sub(regexpReplace, s)) if biggestAt: assert not wildcard args = args[biggestDollar:] replace(tokens, lambda s: atRe.sub(regexpReplace, s)) if wildcard: assert not biggestAt # Gotta remove the things that have already been subbed in. i = biggestDollar while i: args.pop(0) i -= 1 def everythingReplace(tokens): for (i, token) in enumerate(tokens): if isinstance(token, list): if everythingReplace(token): return if token == '$*': tokens[i:i + 1] = args return True elif '$*' in token: tokens[i] = token.replace('$*', ' '.join(args)) return True return False everythingReplace(tokens) maxNesting = conf.supybot.commands.nested.maximum() if maxNesting and irc.nested + 1 > maxNesting: irc.error(_('You\'ve attempted more nesting than is ' 'currently allowed on this bot.'), Raise=True) self.Proxy(irc, msg, tokens, nested=irc.nested + 1)
def _run(self, code): """Runs the command using Supybot engine""" tokens = callbacks.tokenize(str(code)) fakeIrc = FakeIrc(self._irc) self._plugin.Proxy(fakeIrc, self._msg, tokens) self.rawData = fakeIrc._rawData # TODO : don't wait if the plugin is not threaded time.sleep(0.1) return fakeIrc._data
def _makeCommandFunction(self, irc, msg, command, remove=True): """Makes a function suitable for scheduling from command.""" tokens = callbacks.tokenize(command, channel=msg.channel, network=irc.network) def f(): if remove: del self.events[str(f.eventId)] self.Proxy(irc.irc, msg, tokens) return f
def f(self, irc, msg, args): alias = original.replace('$nick', msg.nick) if '$channel' in original: channel = getChannel(irc, msg, args) alias = alias.replace('$channel', channel) tokens = callbacks.tokenize(alias) if biggestDollar or biggestAt: args = getArgs(args, required=biggestDollar, optional=biggestAt, wildcard=wildcard) max_len = conf.supybot.reply.maximumLength() args = list([x[:max_len] for x in args]) def regexpReplace(m): idx = int(m.group(1)) return args[idx - 1] def replace(tokens, replacer): for (i, token) in enumerate(tokens): if isinstance(token, list): replace(token, replacer) else: tokens[i] = replacer(token) replace(tokens, lambda s: dollarRe.sub(regexpReplace, s)) if biggestAt: assert not wildcard args = args[biggestDollar:] replace(tokens, lambda s: atRe.sub(regexpReplace, s)) if wildcard: assert not biggestAt # Gotta remove the things that have already been subbed in. i = biggestDollar while i: args.pop(0) i -= 1 def everythingReplace(tokens): for (i, token) in enumerate(tokens): if isinstance(token, list): if everythingReplace(token): return if token == '$*': tokens[i:i + 1] = args return True elif '$*' in token: tokens[i] = token.replace('$*', ' '.join(args)) return True return False everythingReplace(tokens) # Limit memory use by constraining the size of the message being passed # in to the alias. Also tracking nesting to avoid endless recursion. maxLength = conf.supybot.reply.maximumLength() tokens = [t[:maxLength] for t in tokens] self.Proxy(irc, msg, tokens, nested=irc.nested + 1)
def _run(self, irc, msg, triggerName): command = self.registryValue('triggers.%s' % triggerName, msg.args[0]) if command == '': return tokens = callbacks.tokenize(command) try: self.Proxy(irc.irc, msg, tokens) except Exception, e: log.exception('Error occured while running triggered command:')
def fakehostmask(self, irc, msg, args, hostmask, command): """<hostmask> <command> Runs <command> as if you were wearing the <hostmask>. Of course, usage of the command is restricted to the owner.""" log.info('fakehostmask used to run "%s" as %s' % (command, hostmask)) msg.prefix = hostmask tokens = callbacks.tokenize(command) self.Proxy(irc.irc, msg, tokens)
def _createPrivmsg(self, irc, channel, payload, event, hidden=None): bold = ircutils.bold format_ = self.plugin.registryValue('format.%s' % event, channel) if not format_.strip(): return repl = flatten_subdicts(payload) for (key, value) in dict(repl).items(): if isinstance(value, basestring) and \ value.startswith(('http://', 'https://')): host = urlparse(value).netloc # NOTE: Shortening api.github.com URLs causes too much # overhead and it becomes really slow. At some point, we # should probably check which keys are actually referenced # in the format string and only shorten those. #if host == 'github.com' or host.endswith('.github.com'): if host == 'github.com': url = self._shorten_url(value) if url: repl[key + '__tiny'] = url else: repl[key + '__tiny'] = value else: repl[key + '__tiny'] = value elif isinstance(value, basestring) and \ re.search(r'^[a-f0-9]{40}$', value): # Check if it looks like a commit ID, because there are key # names such as "before" and "after" containing commit IDs. repl[key + '__short'] = value[0:7] elif key == 'commits': repl['__num_commits'] = len(value) elif key.endswith('ref'): try: repl[key + '__branch'] = value.split('/', 2)[2] \ if value else None except IndexError: pass elif isinstance(value, str) or \ (sys.version_info[0] < 3 and isinstance(value, unicode)): repl[key + '__firstline'] = value.split('\n', 1)[0] repl.update({'__hidden': hidden or 0}) #if hidden is not None: # s += _(' (+ %i hidden commits)') % hidden #if sys.version_info[0] < 3: # s = s.encode('utf-8') tokens = callbacks.tokenize(format_) if not tokens: return fake_msg = ircmsgs.IrcMsg(command='PRIVMSG', args=(channel, 'GITHUB'), prefix='github!github@github', reply_env=repl) try: self.plugin.Proxy(irc, fake_msg, tokens) except Exception as e: self.plugin.log.exception( 'Error occured while running triggered command:')
def f(): # If the network isn't available, pick any other one irc = world.getIrc(network) or world.ircs[0] tokens = callbacks.tokenize(command, channel=msg.channel, network=irc.network) if remove: del self.events[str(f.eventId)] self.Proxy(irc, msg, tokens)
def _getAutocompleteResponse(irc, msg, payload): """Returns the value of the +draft/autocomplete-response tag for the given +draft/autocomplete-request payload.""" tokens = callbacks.tokenize(payload, channel=msg.channel, network=irc.network) normalized_payload = " ".join(tokens) candidate_commands = _getCandidates(irc, normalized_payload) if len(candidate_commands) == 0: # No result return None elif len(candidate_commands) == 1: # One result, return it directly commands = candidate_commands else: # Multiple results, return only the longest common prefix + one word tokenized_candidates = [ callbacks.tokenize(c, channel=msg.channel, network=irc.network) for c in candidate_commands ] common_prefix = _commonPrefix(tokenized_candidates) words_after_prefix = { candidate[len(common_prefix)] for candidate in tokenized_candidates } commands = [ " ".join(common_prefix + [word]) for word in words_after_prefix ] # strip what the user already typed assert all(command.startswith(normalized_payload) for command in commands) normalized_payload_length = len(normalized_payload) response_items = [ command[normalized_payload_length:] for command in commands ] return "\t".join(sorted(response_items))
def act (self, irc, msg, channel, command, owner): tokens = callbacks.tokenize(command) #if ircdb.checkCapability(owner, 'owner') or ircdb.checkCapability(owner, '%s,op' % channel): # owner = irc.prefix #elif ircdb.checkCapability(irc.prefix, 'owner') or ircdb.checkCapability(irc.prefix, '%s,op' % channel): # owner = irc.prefix msg.command = 'PRIVMSG' (n,i,h) = ircutils.splitHostmask(owner) msg.prefix = ircutils.joinHostmask(irc.nick,i,h) self.Proxy(irc.irc, msg, tokens)
def hadoken(self, irc, msg, args): """takes no arguments Let everyone know that they should come get beat up by Guile.""" users = {'Newfie':'@HWHQNewfie', 'C4':'@ceephour', 'that_guy':'@nliadm'} twitterstr = 'post HADOKEN! ' + " ".join(users.values()) ircstring = 'MY FIGHT MONEY! ' + " ".join(users.keys()) irc.reply(ircstring) self.Proxy(irc.irc, msg, callbacks.tokenize(twitterstr))
def _createPrivmsg(self, irc, channel, payload, event, hidden=None): bold = ircutils.bold format_ = self.plugin.registryValue('format.%s' % event, channel) if not format_.strip(): return repl = flatten_subdicts(payload) for (key, value) in dict(repl).items(): if isinstance(value, basestring) and \ value.startswith(('http://', 'https://')): host = urlparse(value).netloc # NOTE: Shortening api.github.com URLs causes too much # overhead and it becomes really slow. At some point, we # should probably check which keys are actually referenced # in the format string and only shorten those. #if host == 'github.com' or host.endswith('.github.com'): if host == 'github.com': url = self._shorten_url(value) if url: repl[key + '__tiny'] = url else: repl[key + '__tiny'] = value else: repl[key + '__tiny'] = value elif isinstance(value, basestring) and \ re.search(r'^[a-f0-9]{40}$', value): # Check if it looks like a commit ID, because there are key # names such as "before" and "after" containing commit IDs. repl[key + '__short'] = value[0:7] elif key == 'commits': repl['__num_commits'] = len(value) elif key.endswith('ref'): try: repl[key + '__branch'] = value.split('/', 2)[2] \ if value else None except IndexError: pass elif isinstance(value, str) or \ (sys.version_info[0] < 3 and isinstance(value, unicode)): repl[key + '__firstline'] = value.split('\n', 1)[0] repl.update({'__hidden': hidden or 0}) #if hidden is not None: # s += _(' (+ %i hidden commits)') % hidden #if sys.version_info[0] < 3: # s = s.encode('utf-8') tokens = callbacks.tokenize(format_) if not tokens: return fake_msg = ircmsgs.IrcMsg(command='PRIVMSG', args=(channel, 'GITHUB'), prefix='github!github@github', reply_env=repl) try: self.plugin.Proxy(irc, fake_msg, tokens) except Exception as e: self.plugin.log.exception('Error occured while running triggered command:')
def act (self, irc, msg, channel, command, owner): tokens = callbacks.tokenize(command) msg.command = 'PRIVMSG' (n,i,h) = ircutils.splitHostmask(owner) msg.prefix = ircutils.joinHostmask(irc.nick,i,h) def d(): self.Proxy(irc.irc, msg, tokens) # Wait 30 seconds before sending PM schedule.addEvent(d,time.time()+30)
def __getitem__(self, k): try: return self.d[k] except KeyError: if self.cmd_exists(k): cmd = list(map(LispSymbol, callbacks.tokenize(k))) def wrapper(self, ctx, args): return lisp_cmd(self, ctx, cmd + args) return LispBuiltin(wrapper, k) else: raise
def _slot(self, lastItem): irc = lastItem.irc msg = lastItem.msg channel = lastItem.channel prefix = lastItem.prefix nick = prefix.split('!')[0] kind = lastItem.kind if not ircutils.isChannel(channel): return if not self.registryValue('enable', channel): return try: ircdb.users.getUser(msg.prefix) # May raise KeyError capability = self.registryValue('exempt') if capability: if ircdb.checkCapability(msg.prefix, ','.join([channel, capability])): self.log.info('Not punishing %s: they are immune.' % prefix) return except KeyError: pass punishment = self.registryValue('%s.punishment' % kind, channel) reason = _('%s flood detected') % kind if punishment == 'kick': self._eventCatcher(irc, msg, 'kicked', kicked_prefix=prefix) if kind == 'kicked': reason = _('You exceeded your kick quota.') banmaskstyle = conf.supybot.protocols.irc.banmask banmask = banmaskstyle.makeBanmask(prefix) if punishment == 'kick': msg = ircmsgs.kick(channel, nick, reason) irc.queueMsg(msg) elif punishment == 'ban': msg = ircmsgs.ban(channel, banmask) irc.queueMsg(msg) elif punishment == 'kban': msg = ircmsgs.ban(channel, banmask) irc.queueMsg(msg) msg = ircmsgs.kick(channel, nick, reason) irc.queueMsg(msg) elif punishment.startswith('mode'): msg = ircmsgs.mode(channel, punishment[len('mode'):]) irc.queueMsg(msg) elif punishment.startswith('umode'): msg = ircmsgs.mode(channel, (punishment[len('umode'):], nick)) irc.queueMsg(msg) elif punishment.startswith('command '): tokens = callbacks.tokenize(punishment[len('command '):]) self.Proxy(irc, msg, tokens)
def apply(self, irc, msg, args, command, rest): """<command> <text> Tokenizes <text> and calls <command> with the resulting arguments. """ args = [token and token or '""' for token in rest] text = ' '.join(args) commands = command.split() commands = map(callbacks.canonicalName, commands) tokens = callbacks.tokenize(text) allTokens = commands + tokens self.Proxy(irc, msg, allTokens)
def _run(self, irc, msg, triggerName, channel=None): if channel is None: channel = msg.args[0] command = self.registryValue('triggers.%s' % triggerName, channel) if command == '': return tokens = callbacks.tokenize(command) try: msg.args = (channel,) + msg.args[1:] self.Proxy(irc.irc, msg, tokens) except Exception, e: self.log.exception('Error occured while running triggered command:')
def _doPrivmsgs(self, irc, msg): """If the given message is a command, triggers Limnoria's command-dispatching for that command. Takes the same arguments as ``doPrivmsg`` would, but ``msg`` can potentially be an artificial message synthesized in doBatch from a multiline batch. Usually, a command is a single message, so ``payload=msg.params[0]`` However, when ``msg`` is part of a multiline message, the payload is the concatenation of multiple messages. See <https://ircv3.net/specs/extensions/multiline>. """ assert self is irc.callbacks[0], \ 'Owner isn\'t first callback: %r' % irc.callbacks if ircmsgs.isCtcp(msg): return s = callbacks.addressed(irc, msg) if s: ignored = ircdb.checkIgnored(msg.prefix) if ignored: self.log.info('Ignoring command from %s.', msg.prefix) return maximum = conf.supybot.abuse.flood.command.maximum() self.commands.enqueue(msg) if conf.supybot.abuse.flood.command() \ and self.commands.len(msg) > maximum \ and not ircdb.checkCapability(msg.prefix, 'trusted'): punishment = conf.supybot.abuse.flood.command.punishment() banmask = conf.supybot.protocols.irc.banmask \ .makeBanmask(msg.prefix) self.log.info( 'Ignoring %s for %s seconds due to an apparent ' 'command flood.', banmask, punishment) ircdb.ignores.add(banmask, time.time() + punishment) if conf.supybot.abuse.flood.command.notify(): irc.reply('You\'ve given me %s commands within the last ' '%i seconds; I\'m now ignoring you for %s.' % (maximum, conf.supybot.abuse.flood.interval(), utils.timeElapsed(punishment, seconds=False))) return try: tokens = callbacks.tokenize(s, channel=msg.channel, network=irc.network) self.Proxy(irc, msg, tokens) except SyntaxError as e: if conf.supybot.reply.error.detailed(): irc.error(str(e)) else: irc.replyError(msg=msg) self.log.info('Syntax error: %s', e)
def apply(self, irc, msg, args, command, rest): """<command> <text> Tokenizes <text> and calls <command> with the resulting arguments. """ args = [token and token or '""' for token in rest] text = ' '.join(args) commands = command.split() commands = list(map(callbacks.canonicalName, commands)) tokens = callbacks.tokenize(text) allTokens = commands + tokens self.Proxy(irc, msg, allTokens)
def _runCommandFunction(self, irc, msg, command): """Run a command from message, as if command was sent over IRC.""" try: tokens = callbacks.tokenize(command, channel=msg.channel, network=irc.network) except SyntaxError as e: # Emulate what callbacks.py does self.log.debug('Error return: %s', utils.exnToString(e)) irc.error(str(e)) try: self.Proxy(irc.irc, msg, tokens) except Exception as e: log.exception('Uncaught exception in function called by MessageParser:')
def f(self, irc, msg, args): alias = original.replace("$nick", msg.nick) if "$channel" in original: channel = getChannel(msg, args) alias = alias.replace("$channel", channel) tokens = callbacks.tokenize(alias) if not wildcard and biggestDollar or biggestAt: args = getArgs(args, required=biggestDollar, optional=biggestAt) # Gotta have a mutable sequence (for replace). if biggestDollar + biggestAt == 1: # We got a string, no tuple. args = [args] def regexpReplace(m): idx = int(m.group(1)) return args[idx - 1] def replace(tokens, replacer): for (i, token) in enumerate(tokens): if isinstance(token, list): replace(token, replacer) else: tokens[i] = replacer(token) replace(tokens, lambda s: dollarRe.sub(regexpReplace, s)) if biggestAt: assert not wildcard args = args[biggestDollar:] replace(tokens, lambda s: atRe.sub(regexpReplace, s)) if wildcard: assert not biggestAt # Gotta remove the things that have already been subbed in. i = biggestDollar while i: args.pop(0) i -= 1 def everythingReplace(tokens): for (i, token) in enumerate(tokens): if isinstance(token, list): if everythingReplace(token): return if token == "$*": tokens[i : i + 1] = args return True elif "$*" in token: tokens[i] = token.replace("$*", " ".join(args)) return True return False everythingReplace(tokens) self.Proxy(irc, msg, tokens)
def f(irc, msg, args): tokens = callbacks.tokenize(original) if biggestDollar or biggestAt: args = getArgs(args, required=biggestDollar, optional=biggestAt, wildcard=wildcard) remaining_len = conf.supybot.reply.maximumLength() for (i, arg) in enumerate(args): if remaining_len < len(arg): arg = arg[0:remaining_len] args[i+1:] = [] break remaining_len -= len(arg) def regexpReplace(m): idx = int(m.group(1)) return args[idx-1] def replace(tokens, replacer): for (i, token) in enumerate(tokens): if isinstance(token, list): replace(token, replacer) else: tokens[i] = replacer(token) replace(tokens, lambda s: dollarRe.sub(regexpReplace, s)) if biggestAt: assert not wildcard args = args[biggestDollar:] replace(tokens, lambda s: atRe.sub(regexpReplace, s)) if wildcard: assert not biggestAt # Gotta remove the things that have already been subbed in. i = biggestDollar args[:] = args[i:] def everythingReplace(tokens): skip = 0 for (i, token) in enumerate(tokens): if skip: skip -= 1 continue if isinstance(token, list): everythingReplace(token) if token == '$*': tokens[i:i+1] = args skip = len(args)-1 # do not make replacements in # tokens we just added elif '$*' in token: tokens[i] = token.replace('$*', ' '.join(args)) everythingReplace(tokens) maxNesting = conf.supybot.commands.nested.maximum() if maxNesting and irc.nested+1 > maxNesting: irc.error(_('You\'ve attempted more nesting than is ' 'currently allowed on this bot.'), Raise=True) self.Proxy(irc, msg, tokens, nested=irc.nested+1)
def f(self, irc, msg, args): alias = original.replace('$nick', msg.nick) if '$channel' in original: channel = getChannel(msg, args) alias = alias.replace('$channel', channel) tokens = callbacks.tokenize(alias) if biggestDollar or biggestAt: args = getArgs(args, required=biggestDollar, optional=biggestAt, wildcard=wildcard) def regexpReplace(m): idx = int(m.group(1)) return args[idx - 1] def replace(tokens, replacer): for (i, token) in enumerate(tokens): if isinstance(token, list): replace(token, replacer) else: tokens[i] = replacer(token) replace(tokens, lambda s: dollarRe.sub(regexpReplace, s)) if biggestAt: assert not wildcard args = args[biggestDollar:] replace(tokens, lambda s: atRe.sub(regexpReplace, s)) if wildcard: assert not biggestAt # Gotta remove the things that have already been subbed in. i = biggestDollar while i: args.pop(0) i -= 1 def everythingReplace(tokens): for (i, token) in enumerate(tokens): if isinstance(token, list): if everythingReplace(token): return if token == '$*': tokens[i:i + 1] = args return True elif '$*' in token: tokens[i] = token.replace('$*', ' '.join(args)) return True return False everythingReplace(tokens) self.Proxy(irc, msg, tokens)
def f(self, irc, msg, args): alias = original.replace('$nick', msg.nick) if '$channel' in original: channel = getChannel(msg, args) alias = alias.replace('$channel', channel) tokens = callbacks.tokenize(alias) if biggestDollar or biggestAt: args = getArgs(args, required=biggestDollar, optional=biggestAt, wildcard=wildcard) max_len = conf.supybot.reply.maximumLength() args = list([x[:max_len] for x in args]) def regexpReplace(m): idx = int(m.group(1)) return args[idx-1] def replace(tokens, replacer): for (i, token) in enumerate(tokens): if isinstance(token, list): replace(token, replacer) else: tokens[i] = replacer(token) replace(tokens, lambda s: dollarRe.sub(regexpReplace, s)) if biggestAt: assert not wildcard args = args[biggestDollar:] replace(tokens, lambda s: atRe.sub(regexpReplace, s)) if wildcard: assert not biggestAt # Gotta remove the things that have already been subbed in. i = biggestDollar while i: args.pop(0) i -= 1 def everythingReplace(tokens): for (i, token) in enumerate(tokens): if isinstance(token, list): if everythingReplace(token): return if token == '$*': tokens[i:i+1] = args return True elif '$*' in token: tokens[i] = token.replace('$*', ' '.join(args)) return True return False everythingReplace(tokens) # Limit memory use by constraining the size of the message being passed # in to the alias. Also tracking nesting to avoid endless recursion. maxLength = conf.supybot.reply.maximumLength() tokens = [t[:maxLength] for t in tokens] self.Proxy(irc, msg, tokens, nested=irc.nested + 1)
def sudo(self, irc, msg, args, command): """<commande> [<arg1> [<arg2> ...]] Runs the command following the Sudo rules.""" name, rule = self.db.getRuleMatching(command) if name is None: log.warning('Sudo not granted to "%s"' % msg.prefix) irc.error(_('Sudo not granted.')) else: assert rule is not None log.info('Sudo granted to "%s" with rule %s' % (msg.prefix, name)) msg.prefix = rule.hostmask tokens = callbacks.tokenize(command) self.Proxy(irc.irc, msg, tokens)
def f(self, irc, msg, args): alias = original.replace('$nick', msg.nick) if '$channel' in original: channel = getChannel(msg, args) alias = alias.replace('$channel', channel) tokens = callbacks.tokenize(alias) if biggestDollar or biggestAt: args = getArgs(args, required=biggestDollar, optional=biggestAt, wildcard=wildcard) max_len = conf.supybot.reply.maximumLength() args = list([x[:max_len] for x in args]) def regexpReplace(m): idx = int(m.group(1)) return args[idx-1] def replace(tokens, replacer): for (i, token) in enumerate(tokens): if isinstance(token, list): replace(token, replacer) else: tokens[i] = replacer(token) replace(tokens, lambda s: dollarRe.sub(regexpReplace, s)) if biggestAt: assert not wildcard args = args[biggestDollar:] replace(tokens, lambda s: atRe.sub(regexpReplace, s)) if wildcard: assert not biggestAt # Gotta remove the things that have already been subbed in. i = biggestDollar while i: args.pop(0) i -= 1 def everythingReplace(tokens): for (i, token) in enumerate(tokens): if isinstance(token, list): if everythingReplace(token): return if token == '$*': tokens[i:i+1] = args return True elif '$*' in token: tokens[i] = token.replace('$*', ' '.join(args)) return True return False everythingReplace(tokens) maxNesting = conf.supybot.commands.nested.maximum() if maxNesting and irc.nested+1 > maxNesting: irc.error(_('You\'ve attempted more nesting than is ' 'currently allowed on this bot.'), Raise=True) self.Proxy(irc, msg, tokens, nested=irc.nested+1)
def sudo(self, irc, msg, args, command): """<commande> [<arg1> [<arg2> ...]] Runs the command fellowing the Sudo rules.""" name, rule = self.db.getRuleMatching(command) if name is None: log.warning('Sudo not granted to "%s"' % msg.prefix) irc.error(_('Sudo not granted.')) else: assert rule is not None log.info('Sudo granted to "%s" with rule %s' % (msg.prefix, name)) msg.prefix = rule.hostmask tokens = callbacks.tokenize(command) self.Proxy(irc.irc, msg, tokens)
def _run(self, irc, msg, triggerName, channel=None): if channel is None: channel = msg.args[0] command = self.registryValue('triggers.%s' % triggerName, channel) if not list(filter(lambda x: x != ' ', command)): return tokens = callbacks.tokenize(command) if not tokens: return try: msg.args = (channel, ) + msg.args[1:] self.Proxy(irc.irc, msg, tokens) except Exception as e: self.log.exception( 'Error occured while running triggered command:')
def _createPrivmsg(self, irc, channel, payload, event): bold = ircutils.bold format_ = self.plugin.registryValue('format.%s' % event, channel) if not format_.strip(): return repl = flatten_subdicts(payload) for (key, value) in dict(repl).items(): if isinstance(value, basestring) and \ value.startswith(('http://', 'https://')) and \ key + '__tiny' in format_: host = urlparse(value).netloc if host == 'github.com' or host.endswith('.github.com'): url = self._shorten_url(value) if url: repl[key + '__tiny'] = url else: repl[key + '__tiny'] = value else: repl[key + '__tiny'] = value elif isinstance(value, basestring) and \ re.search(r'^[a-f0-9]{40}$', value): # Check if it looks like a commit ID, because there are key # names such as "before" and "after" containing commit IDs. repl[key + '__short'] = value[0:7] elif key == 'commits': repl['__num_commits'] = len(value) elif key.endswith('ref'): try: repl[key + '__branch'] = value.split('/', 2)[2] \ if value else None except IndexError: pass elif isinstance(value, str) or \ (sys.version_info[0] < 3 and isinstance(value, unicode)): repl[key + '__firstline'] = value.split('\n', 1)[0] tokens = callbacks.tokenize(format_) if not tokens: return fake_msg = ircmsgs.IrcMsg(command='PRIVMSG', args=(channel, 'GITHUB'), prefix='github!github@github', reply_env=repl) try: self.plugin.Proxy(irc, fake_msg, tokens) except Exception as e: self.plugin.log.exception( 'Error occured while running triggered command:')
def sudo(self, irc, msg, args, command): """<command> [<arg1> [<arg2> ...]] Runs the command following the Sudo rules.""" name, rule = self.db.getRuleMatching(command) bannedChars = conf.supybot.commands.nested.brackets() if name is None: log.warning('Sudo not granted to "%s"' % msg.prefix) irc.error(_('Sudo not granted.')) else: assert rule is not None log.info('Sudo granted to "%s" with rule %s' % (msg.prefix, name)) msg.prefix = rule.hostmask tokens = callbacks.tokenize(command) msg.nick = msg.prefix.split('!')[0] self.Proxy(irc.irc, msg, tokens)
def _createPrivmsg(self, irc, channel, payload, event): bold = ircutils.bold format_ = self.plugin.registryValue('format.%s' % event, channel) if not format_.strip(): return repl = flatten_subdicts(payload) for (key, value) in dict(repl).items(): if isinstance(value, basestring) and \ value.startswith(('http://', 'https://')) and \ key + '__tiny' in format_: host = urlparse(value).netloc if host == 'github.com' or host.endswith('.github.com'): url = self._shorten_url(value) if url: repl[key + '__tiny'] = url else: repl[key + '__tiny'] = value else: repl[key + '__tiny'] = value elif isinstance(value, basestring) and \ re.search(r'^[a-f0-9]{40}$', value): # Check if it looks like a commit ID, because there are key # names such as "before" and "after" containing commit IDs. repl[key + '__short'] = value[0:7] elif key == 'commits': repl['__num_commits'] = len(value) elif key.endswith('ref'): try: repl[key + '__branch'] = value.split('/', 2)[2] \ if value else None except IndexError: pass elif isinstance(value, str) or \ (sys.version_info[0] < 3 and isinstance(value, unicode)): repl[key + '__firstline'] = value.split('\n', 1)[0] tokens = callbacks.tokenize(format_) if not tokens: return fake_msg = ircmsgs.IrcMsg(command='PRIVMSG', args=(channel, 'GITHUB'), prefix='github!github@github', reply_env=repl) try: self.plugin.Proxy(irc, fake_msg, tokens) except Exception as e: self.plugin.log.exception('Error occured while running triggered command:')
def f(self, irc, msg, args): alias = original.replace('$nick', msg.nick) if '$channel' in original: channel = getChannel(msg, args) alias = alias.replace('$channel', channel) tokens = callbacks.tokenize(alias) if biggestDollar or biggestAt: args = getArgs(args, required=biggestDollar, optional=biggestAt, wildcard=wildcard) def regexpReplace(m): idx = int(m.group(1)) return args[idx-1] def replace(tokens, replacer): for (i, token) in enumerate(tokens): if isinstance(token, list): replace(token, replacer) else: # tokens[i] = replacer(token.encode('utf-8')) tokens[i] = replacer(token) replace(tokens, lambda s: dollarRe.sub(regexpReplace, s)) if biggestAt: assert not wildcard args = args[biggestDollar:] replace(tokens, lambda s: atRe.sub(regexpReplace, s)) if wildcard: assert not biggestAt # Gotta remove the things that have already been subbed in. i = biggestDollar while i: args.pop(0) i -= 1 def everythingReplace(tokens): for (i, token) in enumerate(tokens): if isinstance(token, list): if everythingReplace(token): return if token == '$*': tokens[i:i+1] = args return True elif '$*' in token: tokens[i] = token.replace('$*', ' '.join(args)) return True return False everythingReplace(tokens) self.Proxy(irc, msg, tokens)
def f(irc, msg, args): tokens = callbacks.tokenize(original) if biggestDollar or biggestAt: args = getArgs(args, required=biggestDollar, optional=biggestAt, wildcard=wildcard) def regexpReplace(m): idx = int(m.group(1)) return args[idx - 1] def replace(tokens, replacer): for (i, token) in enumerate(tokens): if isinstance(token, list): replace(token, replacer) else: tokens[i] = replacer(token) replace(tokens, lambda s: dollarRe.sub(regexpReplace, s)) args = args[biggestDollar:] if biggestAt: replace(tokens, lambda s: atRe.sub(regexpReplace, s)) if wildcard: def everythingReplace(tokens): ret = False new_tokens = [] for (i, token) in enumerate(tokens): if isinstance(token, list): (sub_ret, sub_tokens) = everythingReplace(token) new_tokens.append(sub_tokens) if sub_ret: continue if token == '$*': new_tokens.extend(args) ret = True else: new_tokens.append( token.replace('$*', ' '.join(args))) ret = True return (ret, new_tokens) (ret, tokens) = everythingReplace(tokens) self.Proxy(irc, msg, tokens)
def let(self, irc, msg, args, var_name, _, value, __, command): """<variable> = <value> in <command> Defines <variable> to be equal to <value> in the <command> and runs the <command>. '=' and 'in' can be omitted.""" if msg.reply_env and var_name in msg.reply_env: # For security reason (eg. a Sudo-like plugin), we don't want # to make it possible to override stuff like $nick. irc.error(_('Cannot set a variable that already exists.'), Raise=True) fake_msg = ircmsgs.IrcMsg(msg=msg) if fake_msg.reply_env is None: fake_msg.reply_env = {} fake_msg.reply_env[var_name] = value tokens = callbacks.tokenize(command) self.Proxy(irc, fake_msg, tokens)
def f(irc, msg, args): tokens = callbacks.tokenize(original) if biggestDollar or biggestAt: args = getArgs(args, required=biggestDollar, optional=biggestAt, wildcard=wildcard) max_len = conf.supybot.reply.maximumLength() args = list(map(lambda x:x[:max_len], args)) def regexpReplace(m): idx = int(m.group(1)) return args[idx-1] def replace(tokens, replacer): for (i, token) in enumerate(tokens): if isinstance(token, list): replace(token, replacer) else: tokens[i] = replacer(token) replace(tokens, lambda s: dollarRe.sub(regexpReplace, s)) args = args[biggestDollar:] if biggestAt: replace(tokens, lambda s: atRe.sub(regexpReplace, s)) if wildcard: def everythingReplace(tokens): ret = False new_tokens = [] for (i, token) in enumerate(tokens): if isinstance(token, list): (sub_ret, sub_tokens) = everythingReplace(token) new_tokens.append(sub_tokens) if sub_ret: continue if token == '$*': new_tokens.extend(args) ret = True else: new_tokens.append( token.replace('$*', ' '.join(args))) ret = True return (ret, new_tokens) (ret, tokens) = everythingReplace(tokens) maxNesting = conf.supybot.commands.nested.maximum() if maxNesting and irc.nested+1 > maxNesting: irc.error(_('You\'ve attempted more nesting than is ' 'currently allowed on this bot.'), Raise=True) self.Proxy(irc, msg, tokens)
def _createPrivmsg(self, irc, channel, payload, event, hidden=None): bold = ircutils.bold format_ = self.plugin.registryValue('format.%s' % event, channel) if not format_.strip(): return repl = flatten_subdicts(payload) try_gitio = True for (key, value) in dict(repl).items(): if key.endswith(('__commit__url', '__html_url', 'target_url')): if try_gitio: url = self._shorten_url(value) else: url = None if url: repl[key + '__tiny'] = url else: repl[key + '__tiny'] = value try_gitio = False elif key.endswith('ref'): try: repl[key + '__branch'] = value.split('/', 2)[2] \ if value else None except IndexError: pass elif isinstance(value, str) or \ (sys.version_info[0] < 3 and isinstance(value, unicode)): repl[key + '__firstline'] = value.split('\n', 1)[0] repl.update({'__hidden': hidden or 0}) #if hidden is not None: # s += _(' (+ %i hidden commits)') % hidden #if sys.version_info[0] < 3: # s = s.encode('utf-8') tokens = callbacks.tokenize(format_) if not tokens: return fake_msg = ircmsgs.IrcMsg(command='PRIVMSG', args=(channel, 'GITHUB'), prefix='github!github@github', reply_env=repl) try: self.plugin.Proxy(irc, fake_msg, tokens) except Exception as e: self.plugin.log.exception('Error occured while running triggered command:')
def _createPrivmsg(self, irc, channel, payload, event, hidden=None): bold = ircutils.bold format_ = self.plugin.registryValue('format.%s' % event, channel) if not format_.strip(): return repl = flatten_subdicts(payload) try_gitio = True for (key, value) in dict(repl).items(): if key.endswith('url'): if try_gitio: url = self._shorten_url(value) else: url = None if url: repl[key + '__tiny'] = url else: repl[key + '__tiny'] = value try_gitio = False elif key.endswith('ref'): try: repl[key + '__branch'] = value.split('/', 2)[2] except IndexError: pass elif isinstance(value, str) or \ (sys.version_info[0] < 3 and isinstance(value, unicode)): repl[key + '__firstline'] = value.split('\n', 1)[0] repl.update({'__hidden': hidden or 0}) #if hidden is not None: # s += _(' (+ %i hidden commits)') % hidden #if sys.version_info[0] < 3: # s = s.encode('utf-8') tokens = callbacks.tokenize(format_) if not tokens: return fake_msg = ircmsgs.IrcMsg(command='PRIVMSG', args=(channel, 'GITHUB'), prefix='github!github@github', reply_env=repl) try: self.plugin.Proxy(irc, fake_msg, tokens) except Exception as e: self.plugin.log.exception('Error occured while running triggered command:')
def cerror(self, irc, msg, args, testcommand): """<testcommand> Runs <testcommand> and returns true if it raises an error; false otherwise. """ tokens = callbacks.tokenize(testcommand, channel=msg.channel, network=irc.network) InvalidCommand = collections.namedtuple('InvalidCommand', 'command') replies = [] errors = [] class ErrorReportingProxy(self.Proxy): def reply(self2, s, *args, **kwargs): replies.append(s) def error(self2, s, Raise=False, *args, **kwargs): errors.append(s) if Raise: raise ArgumentError def _callInvalidCommands(self2): errors.append(InvalidCommand(self2.args)) def evalArgs(self2): # We don't want the replies in the nested command to # be stored here. super(ErrorReportingProxy, self2).evalArgs(withClass=self.Proxy) try: ErrorReportingProxy(irc.irc, msg, tokens) except callbacks.ArgumentError as e: pass # TODO: do something with the results if errors: irc.reply('true') else: irc.reply('false')
def _createPrivmsg(self, irc, channel, payload, event, hidden=None): bold = ircutils.bold format_ = self.plugin.registryValue("format.%s" % event, channel) if not format_.strip(): return repl = flatten_subdicts(payload) try_gitio = True for (key, value) in dict(repl).items(): if key.endswith("url"): if try_gitio: url = self._shorten_url(value) else: url = None if url: repl[key + "__tiny"] = url else: repl[key + "__tiny"] = value try_gitio = False elif key.endswith("ref"): try: repl[key + "__branch"] = value.split("/", 2)[2] except IndexError: pass elif isinstance(value, str): repl[key + "__firstline"] = value.split("\n", 1)[0] repl.update({"__hidden": hidden or 0}) command = Template(format_).safe_substitute(repl) # if hidden is not None: # s += _(' (+ %i hidden commits)') % hidden # if sys.version_info[0] < 3: # s = s.encode('utf-8') tokens = callbacks.tokenize(command) if not tokens: return fake_msg = ircmsgs.IrcMsg(command="PRIVMSG", args=(channel, "GITHUB")) try: self.plugin.Proxy(irc, fake_msg, tokens) except Exception as e: self.plugin.log.exception("Error occured while running triggered command:")
def doPrivmsg(self, irc, msg): assert self is irc.callbacks[0], \ 'Owner isn\'t first callback: %r' % irc.callbacks if ircmsgs.isCtcp(msg): return s = callbacks.addressed(irc, msg) if s: ignored = ircdb.checkIgnored(msg.prefix) if ignored: self.log.info('Ignoring command from %s.', msg.prefix) return maximum = conf.supybot.abuse.flood.command.maximum() self.commands.enqueue(msg) if conf.supybot.abuse.flood.command() \ and self.commands.len(msg) > maximum \ and not ircdb.checkCapability(msg.prefix, 'trusted'): punishment = conf.supybot.abuse.flood.command.punishment() banmask = conf.supybot.protocols.irc.banmask \ .makeBanmask(msg.prefix) self.log.info( 'Ignoring %s for %s seconds due to an apparent ' 'command flood.', banmask, punishment) ircdb.ignores.add(banmask, time.time() + punishment) if conf.supybot.abuse.flood.command.notify(): irc.reply('You\'ve given me %s commands within the last ' '%i seconds; I\'m now ignoring you for %s.' % (maximum, conf.supybot.abuse.flood.interval(), utils.timeElapsed(punishment, seconds=False))) return try: tokens = callbacks.tokenize(s, channel=msg.channel, network=irc.network) self.Proxy(irc, msg, tokens) except SyntaxError as e: if conf.supybot.reply.error.detailed(): irc.error(str(e)) else: irc.replyError(msg=msg) self.log.info('Syntax error: %s', e)
def makeNewAlias(name, alias): original = alias biggestDollar = findBiggestDollar(original) biggestAt = findBiggestAt(original) wildcard = '$*' in original if biggestAt and wildcard: raise AliasError('Can\'t mix $* and optional args (@1, etc.)') if original.count('$*') > 1: raise AliasError('There can be only one $* in an alias.') testTokens = callbacks.tokenize(original) if testTokens and isinstance(testTokens[0], list): raise AliasError('Commands may not be the result of nesting.') def f(self, irc, msg, args): alias = original.replace('$nick', msg.nick) if '$channel' in original: channel = getChannel(irc, msg, args) alias = alias.replace('$channel', channel) tokens = callbacks.tokenize(alias) if biggestDollar or biggestAt: args = getArgs(args, required=biggestDollar, optional=biggestAt, wildcard=wildcard) max_len = conf.supybot.reply.maximumLength() args = list([x[:max_len] for x in args]) def regexpReplace(m): idx = int(m.group(1)) return args[idx - 1] def replace(tokens, replacer): for (i, token) in enumerate(tokens): if isinstance(token, list): replace(token, replacer) else: tokens[i] = replacer(token) replace(tokens, lambda s: dollarRe.sub(regexpReplace, s)) if biggestAt: assert not wildcard args = args[biggestDollar:] replace(tokens, lambda s: atRe.sub(regexpReplace, s)) if wildcard: assert not biggestAt # Gotta remove the things that have already been subbed in. i = biggestDollar while i: args.pop(0) i -= 1 def everythingReplace(tokens): for (i, token) in enumerate(tokens): if isinstance(token, list): if everythingReplace(token): return if token == '$*': tokens[i:i + 1] = args return True elif '$*' in token: tokens[i] = token.replace('$*', ' '.join(args)) return True return False everythingReplace(tokens) # Limit memory use by constraining the size of the message being passed # in to the alias. Also tracking nesting to avoid endless recursion. maxLength = conf.supybot.reply.maximumLength() tokens = [t[:maxLength] for t in tokens] self.Proxy(irc, msg, tokens, nested=irc.nested + 1) flexargs = '' if biggestDollar and (wildcard or biggestAt): flexargs = _(' at least') try: doc = format(_('<an alias,%s %n>\n\nAlias for %q.'), flexargs, (biggestDollar, _('argument')), alias) except UnicodeDecodeError: if minisix.PY2: alias = alias.decode('utf8') doc = format(_('<an alias,%s %n>\n\nAlias for %q.'), flexargs, (biggestDollar, _('argument')), alias) f = utils.python.changeFunctionName(f, name, doc) return f