From e03c65f753f985282a9623543129fe81fb8fefbe Mon Sep 17 00:00:00 2001 From: Jeremy Fincher Date: Tue, 28 Oct 2003 00:22:15 +0000 Subject: [PATCH] Changed the whole handling of nonCommands and ambiguousCommands and whatnot. Now plugins can define an 'invalidCommand' method to be called on invalid commands. --- src/Misc.py | 57 +++--------------------- src/Owner.py | 8 +++- src/callbacks.py | 106 +++++++++++++++++++++------------------------ test/test_Misc.py | 6 ++- test/test_Owner.py | 16 +++---- 5 files changed, 76 insertions(+), 117 deletions(-) diff --git a/src/Misc.py b/src/Misc.py index 57e973e1c..c2e6570a8 100755 --- a/src/Misc.py +++ b/src/Misc.py @@ -43,6 +43,7 @@ from itertools import ifilter import conf import debug import utils +import irclib import ircmsgs import ircutils import privmsgs @@ -73,56 +74,12 @@ def reload(x=None): replyWhenNotCommand = x class Misc(callbacks.Privmsg): - def doPrivmsg(self, irc, msg): - # This exists to be able to respond to attempts to command the bot - # with a "That's not a command!" if the proper conf.variable is set. - callbacks.Privmsg.doPrivmsg(self, irc, msg) - notCommands = [] - ambiguousCommands = {} - s = callbacks.addressed(irc.nick, msg) - if s: - tokens = callbacks.tokenize(s) - commands = callbacks.getCommands(tokens) - for command in commands: - command = callbacks.canonicalName(command) - cbs = callbacks.findCallbackForCommand(irc, command) - if not cbs: - notCommands.append(command) - elif len(cbs) > 1: - ambiguousCommands[command] = [cb.name() for cb in cbs] - if ambiguousCommands: - if len(ambiguousCommands) == 1: # Common case. - (command, names) = ambiguousCommands.popitem() - names.sort() - s = 'The command %r is available in the %s plugins. '\ - 'Please specify the plugin whose command you ' \ - 'wish to call by using its name as a command ' \ - 'before calling it.' % \ - (command, utils.commaAndify(names)) - else: - L = [] - while ambiguousCommands: - (command, names) = ambiguousCommands.popitem() - names.sort() - L.append('The command %r is available in the %s ' - 'plugins' %(command,utils.commaAndify(names))) - s = '%s; please specify from which plugins to ' \ - 'call these commands.' % '; '.join(L) - irc.queueMsg(callbacks.reply(msg, 'Error: ' + s)) - return - if conf.replyWhenNotCommand and msg.nick!=irc.nick and notCommands: - for cb in irc.callbacks: - if isinstance(cb, callbacks.PrivmsgRegexp) or \ - isinstance(cb, callbacks.PrivmsgCommandAndRegexp): - for (r, _) in cb.res: - if r.search(msg.args[1]): - return - if hasattr(cb, 'addressedRes'): - for (r, _) in cb.addressedRes: - if r.search(s): - return - irc = callbacks.IrcObjectProxyRegexp(irc) - replyWhenNotCommand(irc, msg, notCommands) + def invalidCommand(self, irc, msg, tokens): + if conf.replyWhenNotCommand: + irc.error(msg, '%r is not a valid command.' % tokens[0]) + else: + if not isinstance(irc.irc, irclib.Irc): + irc.reply(msg, '[%s]' % ' '.join(tokens)) def list(self, irc, msg, args): """[--private] [] diff --git a/src/Owner.py b/src/Owner.py index 54ed76e49..b94bc039d 100644 --- a/src/Owner.py +++ b/src/Owner.py @@ -88,8 +88,12 @@ class Owner(privmsgs.CapabilityCheckingPrivmsg): def doPrivmsg(self, irc, msg): callbacks.Privmsg.handled = False - super(self.__class__, self).doPrivmsg(irc, msg) - + notCommands = [] + ambiguousCommands = {} + s = callbacks.addressed(irc.nick, msg) + if s: + callbacks.IrcObjectProxy(irc, msg, callbacks.tokenize(s)) + def eval(self, irc, msg, args): """ diff --git a/src/callbacks.py b/src/callbacks.py index 194a0eb22..138ed81a6 100644 --- a/src/callbacks.py +++ b/src/callbacks.py @@ -344,6 +344,35 @@ class IrcObjectProxy: if not args: irc.reply(msg, '[]') else: + if isinstance(irc, irclib.Irc): + # Let's check for {ambiguous,non}Commands. + ambiguousCommands = {} + commands = getCommands(args) + for command in commands: + command = canonicalName(command) + cbs = findCallbackForCommand(irc, command) + if len(cbs) > 1: + ambiguousCommands[command] = [cb.name() for cb in cbs] + if ambiguousCommands: + if len(ambiguousCommands) == 1: # Common case. + (command, names) = ambiguousCommands.popitem() + names.sort() + s = 'The command %r is available in the %s plugins. '\ + 'Please specify the plugin whose command you ' \ + 'wish to call by using its name as a command ' \ + 'before calling it.' % \ + (command, utils.commaAndify(names)) + else: + L = [] + for (command, names) in ambiguousCommands.iteritems(): + names.sort() + L.append('The command %r is available in the %s ' + 'plugins' % + (command, utils.commaAndify(names))) + s = '%s; please specify from which plugins to ' \ + 'call these commands.' % '; '.join(L) + irc.queueMsg(error(msg, s)) + return self.irc = irc self.msg = msg self.args = args @@ -367,23 +396,31 @@ class IrcObjectProxy: self.finalEval() def finalEval(self): - if self.finalEvaled: - raise ValueError, 'finalEval called twice. Odd.' + assert not self.finalEvaled, 'finalEval called twice.' self.finalEvaled = True - originalName = self.args.pop(0) - name = canonicalName(originalName) + name = canonicalName(self.args[0]) cbs = findCallbackForCommand(self, name) if len(cbs) == 0: - self.args.insert(0, originalName) - if not isinstance(self.irc, irclib.Irc): - # If self.irc is an actual irclib.Irc, then this is the - # first command given, and should be ignored as usual. - self.reply(self.msg, '[%s]' % ' '.join(self.args)) - return - elif len(cbs) > 1: - return # Misc.doPrivmsg will handle this. + for cb in self.irc.callbacks: + if isinstance(cb, PrivmsgRegexp): + for (r, _) in cb.res: + if r.search(msg.args[1]): + return + if isinstance(cb, PrivmsgCommandAndRegexp): + for (r, _) in cb.res: + if r.search(msg.args[1]): + return + for (r, _) in cb.addressedRes: + if r.search(msg.args[1]): + return + # Ok, no regexp-based things matched. + for cb in self.irc.callbacks: + if hasattr(cb, 'invalidCommand'): + cb.invalidCommand(self, self.msg, self.args) else: try: + assert len(cbs) == 1 + del self.args[0] cb = cbs[0] anticap = ircdb.makeAntiCapability(name) #debug.printf('Checking for %s' % anticap) @@ -454,22 +491,6 @@ class IrcObjectProxy: elif self.action: self.irc.queueMsg(ircmsgs.action(msg.args[0], s)) else: - # The size of a PRIVMSG is: - # 1 for the colon - # len(prefix) - # 1 for the space - # 7 for the PRIVMSG - # 1 for the space - # len(target) - # 1 for the space - # 1 for the colon - # len(payload) - # 2 for the \r\n - # So non-variable stuff it's 1+1+7+1+1+1+2, or 14 - # We'll estimate the channel length at 30, and we'll know the - # prefix length exactly. We also might append the string - # " (more)" to the end, so that's 7 more characters. - # 512 - 51 == 461. s = ircutils.safeArgument(s) allowedLength = 450 - len(self.irc.prefix) msgs = textwrap.wrap(s, allowedLength-30) # -30 is for "nick:" @@ -689,33 +710,7 @@ class Privmsg(irclib.IrcCallback): debug.msg('%s took %s seconds' % (funcname, elapsed), 'verbose') def doPrivmsg(self, irc, msg, rateLimit=True): - s = addressed(irc.nick, msg) - #debug.printf('Privmsg.doPrivmsg: s == %r' % s) - if s: - recipient = msg.args[0] - if ircdb.checkIgnored(msg.prefix, recipient): - debug.msg('Privmsg.doPrivmsg: ignoring %s.' % msg.prefix) - return - try: - args = tokenize(s) - except SyntaxError, e: - irc.queueMsg(reply(msg, debug.exnToString(e))) - return - if args and isinstance(args[0], str): - args[0] = canonicalName(args[0]) - if self.isCommand(args[0]): - if self.handled and args[0] not in self.alwaysCall: - return - if rateLimit: - self.rateLimiter.put(msg) - msg = self.rateLimiter.get() - if msg: - if conf.replyWhenNotCommand: - for command in getCommands(args): - command = canonicalName(command) - if not findCallbackForCommand(irc, command): - return - self.Proxy(irc, msg, args) + pass class IrcObjectProxyRegexp: @@ -871,7 +866,6 @@ class PrivmsgCommandAndRegexp(Privmsg): if msg: proxy = IrcObjectProxyRegexp(irc) self.callCommand(method,proxy,msg,m,catchErrors=True) - Privmsg.doPrivmsg(self, irc, msg, rateLimit=(not fed)) # vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: diff --git a/test/test_Misc.py b/test/test_Misc.py index 843c14b2c..197f734ea 100644 --- a/test/test_Misc.py +++ b/test/test_Misc.py @@ -38,7 +38,11 @@ class MiscTestCase(ChannelPluginTestCase, PluginDocumentation): conf.replyWhenNotCommand = True self.prefix = 'somethingElse!user@host.domain.tld' self.assertRegexp('foo bar baz', 'not.*command') - self.assertRegexp('foo | bar | baz', 'not.*commands') + try: + conf.enablePipeSyntax = True + self.assertRegexp('foo | bar | baz', 'not.*commands') + finally: + conf.enablePipeSyntax = False self.assertRegexp('baz [foo] [bar]', 'not.*commands') finally: conf.replyWhenNotCommand = False diff --git a/test/test_Owner.py b/test/test_Owner.py index 0b63b7807..6b5442e40 100644 --- a/test/test_Owner.py +++ b/test/test_Owner.py @@ -84,19 +84,19 @@ class OwnerTestCase(PluginTestCase, PluginDocumentation): def testLoad(self): self.assertError('load Owner') self.assertError('load owner') - self.assertNotError('load Misc') + self.assertNotError('load Admin') self.assertNotError('list Owner') def testReload(self): - self.assertError('reload Misc') - self.assertNotError('load Misc') - self.assertNotError('reload Misc') + self.assertError('reload Admin') + self.assertNotError('load Admin') + self.assertNotError('reload Admin') def testUnload(self): - self.assertError('unload Misc') - self.assertNotError('load Misc') - self.assertNotError('unload Misc') - self.assertError('unload Misc') + self.assertError('unload Admin') + self.assertNotError('load Admin') + self.assertNotError('unload Admin') + self.assertError('unload Admin') def testSetconf(self): self.assertRegexp('setconf', 'confDir')