From 66ac089a535159ab9df7f7df8c845aef15eac2d9 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Sun, 20 May 2012 20:57:13 -0400 Subject: [PATCH 01/15] Channel: Perform proper capability checks in devoice. Closes: Sf#3524393 Signed-off-by: James McCoy --- plugins/Channel/plugin.py | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/plugins/Channel/plugin.py b/plugins/Channel/plugin.py index b89647478..bc1bf2d14 100644 --- a/plugins/Channel/plugin.py +++ b/plugins/Channel/plugin.py @@ -1,6 +1,6 @@ ### # Copyright (c) 2002-2005, Jeremiah Fincher -# Copyright (c) 2009, James Vega +# Copyright (c) 2009-2012, James McCoy # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -153,14 +153,7 @@ class Channel(callbacks.Plugin): halfop = wrap(halfop, ['halfop', ('haveOp', 'halfop someone'), any('nickInChannel')]) - def voice(self, irc, msg, args, channel, nicks): - """[] [ ...] - - If you have the #channel,voice capability, this will voice all the - s you provide. If you don't provide any s, this will - voice you. is only necessary if the message isn't sent in the - channel itself. - """ + def _voice(self, irc, msg, args, channel, nicks, fn): if nicks: if len(nicks) == 1 and msg.nick in nicks: capability = 'voice' @@ -172,10 +165,20 @@ class Channel(callbacks.Plugin): capability = ircdb.makeChannelCapability(channel, capability) if ircdb.checkCapability(msg.prefix, capability): def f(L): - return ircmsgs.voices(channel, L) + return fn(channel, L) self._sendMsgs(irc, nicks, f) else: irc.errorNoCapability(capability) + + def voice(self, irc, msg, args, channel, nicks): + """[] [ ...] + + If you have the #channel,voice capability, this will voice all the + s you provide. If you don't provide any s, this will + voice you. is only necessary if the message isn't sent in the + channel itself. + """ + self._voice(irc, msg, args, channel, nicks, ircmsgs.voices) voice = wrap(voice, ['channel', ('haveOp', 'voice someone'), any('nickInChannel')]) @@ -228,12 +231,8 @@ class Channel(callbacks.Plugin): irc.error('I cowardly refuse to devoice myself. If you really ' 'want me devoiced, tell me to op you and then devoice ' 'me yourself.', Raise=True) - if not nicks: - nicks = [msg.nick] - def f(L): - return ircmsgs.devoices(channel, L) - self._sendMsgs(irc, nicks, f) - devoice = wrap(devoice, ['voice', ('haveOp', 'devoice someone'), + self._voice(irc, msg, args, channel, nicks, ircmsgs.devoices) + devoice = wrap(devoice, ['channel', ('haveOp', 'devoice someone'), any('nickInChannel')]) def cycle(self, irc, msg, args, channel): From 1fe4cef61bdac2e81ef08298c2014ad291d27064 Mon Sep 17 00:00:00 2001 From: Valentin Lorentz Date: Wed, 2 May 2012 20:48:49 +0200 Subject: [PATCH 02/15] Import os before using it. --- src/dbi.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dbi.py b/src/dbi.py index de542131e..ee19a9104 100644 --- a/src/dbi.py +++ b/src/dbi.py @@ -31,6 +31,7 @@ Module for some slight database-independence for simple databases. """ +import os import csv import math From 14609b3bb2f625b4ca3dc65b3eeb59cccfc097b5 Mon Sep 17 00:00:00 2001 From: Valentin Lorentz Date: Wed, 2 May 2012 20:50:06 +0200 Subject: [PATCH 03/15] Add self as an argument to methos in src/dbi.py --- src/dbi.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dbi.py b/src/dbi.py index ee19a9104..94dce6355 100644 --- a/src/dbi.py +++ b/src/dbi.py @@ -114,7 +114,7 @@ class DirMapping(MappingInterface): def _makeFilename(self, id): return os.path.join(self.dirname, str(id)) - def get(id): + def get(self, id): try: fd = file(self._makeFilename(id)) return fd.read() @@ -123,7 +123,7 @@ class DirMapping(MappingInterface): exn.realException = e raise exn - def set(id, s): + def set(self, id, s): fd = file(self._makeFilename(id), 'w') fd.write(s) fd.close() From 97e71bd2cdf60592404c2421532ab90292e99be5 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Tue, 22 May 2012 22:11:41 -0400 Subject: [PATCH 04/15] Just create schedule.schedule/drivers.Twisted.poller without any guard These module-level variables had historically been created such that reloading the module wouldn't redefine the variable. However, none of our code reloads the modules and the guard to prevent redefining the variable was broken so it would've been redefined anyway. Signed-off-by: James McCoy --- src/drivers/Twisted.py | 5 +---- src/schedule.py | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/drivers/Twisted.py b/src/drivers/Twisted.py index c91d80d6b..b6d72fc90 100644 --- a/src/drivers/Twisted.py +++ b/src/drivers/Twisted.py @@ -155,9 +155,6 @@ class SupyReconnectingFactory(ReconnectingClientFactory, drivers.ServersMixin): return protocol Driver = SupyReconnectingFactory +poller = TwistedRunnerDriver() -try: - ignore(poller) -except NameError: - poller = TwistedRunnerDriver() # vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: diff --git a/src/schedule.py b/src/schedule.py index 3b36a8a7a..677661201 100644 --- a/src/schedule.py +++ b/src/schedule.py @@ -131,11 +131,8 @@ class Schedule(drivers.IrcDriver): except Exception, e: log.exception('Uncaught exception in scheduled function:') -try: - ignore(schedule) -except NameError: - schedule = Schedule() +schedule = Schedule() addEvent = schedule.addEvent removeEvent = schedule.removeEvent rescheduleEvent = schedule.rescheduleEvent From 8ab33bccb420b17efc4497d3d426e144ad69f8a6 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Tue, 22 May 2012 22:46:35 -0400 Subject: [PATCH 05/15] registry: Use the correct variable name setName creates the child entry Signed-off-by: James McCoy --- src/registry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registry.py b/src/registry.py index 48f94caba..228bf9ee9 100644 --- a/src/registry.py +++ b/src/registry.py @@ -231,7 +231,7 @@ class Group(object): parts = split(rest) if len(parts) == 1 and parts[0] == name: try: - self.__makeChild(group, v) + self.__makeChild(name, v) except InvalidRegistryValue: # It's probably supposed to be registered later. pass From b7bc11deea4e52074d104c5c2412c188cb42dfc9 Mon Sep 17 00:00:00 2001 From: Valentin Lorentz Date: Tue, 27 Dec 2011 11:55:50 +0100 Subject: [PATCH 06/15] Prevent the 'hostmask' converter from returning '*!*@*' while 'foo!*@*' was given. --- plugins/Channel/test.py | 14 +++++++++++--- src/conf.py | 3 +++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/plugins/Channel/test.py b/plugins/Channel/test.py index 67ba108a3..e33b3b51f 100644 --- a/plugins/Channel/test.py +++ b/plugins/Channel/test.py @@ -205,11 +205,19 @@ class ChannelTestCase(ChannelPluginTestCase): def testIgnore(self): orig = conf.supybot.protocols.irc.banmask() + def ignore(given, expect=None): + if expect is None: + expect = given + self.assertNotError('channel ignore add %s' % given) + self.assertResponse('channel ignore list', "'%s'" % expect) + self.assertNotError('channel ignore remove %s' % expect) + self.assertRegexp('channel ignore list', 'not currently') try: + ignore('foo!bar@baz', '*!bar@baz') + ignore('foo!*@*') conf.supybot.protocols.irc.banmask.setValue(['exact']) - self.assertNotError('channel ignore add foo!bar@baz') - self.assertResponse('channel ignore list', "'foo!bar@baz'") - self.assertNotError('channel ignore remove foo!bar@baz') + ignore('foo!bar@baz') + ignore('foo!*@*') self.assertError('ban add not!a.hostmask') finally: conf.supybot.protocols.irc.banmask.setValue(orig) diff --git a/src/conf.py b/src/conf.py index efc87aadd..89111a010 100644 --- a/src/conf.py +++ b/src/conf.py @@ -946,6 +946,9 @@ class Banmask(registry.SpaceSeparatedSetOfStrings): bhost = host elif option == 'exact': return hostmask + if (bnick, buser, bhost) == ('*', '*', '*') and \ + ircutils.isUserHostmask(hostmask): + return hostmask return ircutils.joinHostmask(bnick, buser, bhost) registerChannelValue(supybot.protocols.irc, 'banmask', From a1acde1f02450cdd8e42b251deab6428d3bc6032 Mon Sep 17 00:00:00 2001 From: Valentin Lorentz Date: Tue, 17 Jan 2012 20:51:42 +0000 Subject: [PATCH 07/15] Use log.critical instead of log.fatal (which does not exist). Signed-off-by: James McCoy --- scripts/supybot | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/supybot b/scripts/supybot index ebd85e3f7..83c1eefe4 100644 --- a/scripts/supybot +++ b/scripts/supybot @@ -303,7 +303,7 @@ if __name__ == '__main__': log.error('Could not remove pid file: %s', e) atexit.register(removePidFile) except EnvironmentError, e: - log.fatal('Error opening/writing pid file %s: %s', pidFile, e) + log.critical('Error opening/writing pid file %s: %s', pidFile, e) sys.exit(-1) conf.allowDefaultOwner = options.allowDefaultOwner From c574203bab843f2abf357bfa10b3afff919151b5 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Wed, 23 May 2012 00:34:11 -0400 Subject: [PATCH 08/15] Add a test to verify the nick converter honors strictRfc Signed-off-by: James McCoy --- test/test_commands.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/test_commands.py b/test/test_commands.py index 1c3f2d681..290ae5c93 100644 --- a/test/test_commands.py +++ b/test/test_commands.py @@ -30,6 +30,7 @@ from supybot.test import * from supybot.commands import * +import supybot.conf as conf import supybot.irclib as irclib import supybot.ircmsgs as ircmsgs import supybot.callbacks as callbacks @@ -72,6 +73,16 @@ class GeneralContextTestCase(CommandsTestCase): self.assertState(['int'], ['1'], [1]) self.assertState(['int', 'int', 'int'], ['1', '2', '3'], [1, 2, 3]) + def testSpecNick(self): + strict = conf.supybot.protocols.irc.strictRfc() + try: + conf.supybot.protocols.irc.strictRfc.setValue(True) + self.assertError(['nick'], ['1abc']) + conf.supybot.protocols.irc.strictRfc.setValue(False) + self.assertState(['nick'], ['1abc'], ['1abc']) + finally: + conf.supybot.protocols.irc.strictRfc.setValue(strict) + def testSpecLong(self): self.assertState(['long'], ['1'], [1L]) self.assertState(['long', 'long', 'long'], ['1', '2', '3'], From f3a09ce684fa0bc4e79a6ea82781c8a543fe925a Mon Sep 17 00:00:00 2001 From: James McCoy Date: Wed, 23 May 2012 00:52:24 -0400 Subject: [PATCH 09/15] Success: Allow the plugin to be loaded from a query Closes: Sf#3513915 Signed-off-by: James McCoy --- plugins/Success/plugin.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/plugins/Success/plugin.py b/plugins/Success/plugin.py index ec6adbcf0..b9f011472 100644 --- a/plugins/Success/plugin.py +++ b/plugins/Success/plugin.py @@ -47,7 +47,7 @@ class Success(plugins.ChannelIdDatabasePlugin): self.originalClass = conf.supybot.replies.success.__class__ class MySuccessClass(self.originalClass): def __call__(self): - ret = pluginSelf.db.random(pluginSelf.target) + ret = pluginSelf.db.random(dynamic.msg.args[0]) if ret is None: try: self.__class__ = pluginSelf.originalClass @@ -68,14 +68,6 @@ class Success(plugins.ChannelIdDatabasePlugin): self.__parent.die() conf.supybot.replies.success.__class__ = self.originalClass - def inFilter(self, irc, msg): - # We need the target, but we need it before Owner.doPrivmsg is called, - # so this seems like the only way to do it. - self.target = msg.args[0] - return msg - - Class = Success - # vim:set shiftwidth=4 softtabstop=8 expandtab textwidth=78: From 6f1b60c0f3ae3dfda2385c8a58f8df4bfe58ccdd Mon Sep 17 00:00:00 2001 From: Mika Suomalainen Date: Sat, 31 Mar 2012 20:40:19 +0300 Subject: [PATCH 10/15] INSTALL: use --user... Signed-off-by: James McCoy --- INSTALL | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/INSTALL b/INSTALL index 3a85c7beb..4392a4a2a 100644 --- a/INSTALL +++ b/INSTALL @@ -41,17 +41,12 @@ registry file for your bot. Local Install - You can install Supybot in a local directory by using the '--prefix' + You can install Supybot in a local directory by using the '--user' option when running 'setup.py'. E.g., 'python setup.py install - --prefix=$HOME' to install into your home directory. You'll now have - a $HOME/bin directory containing Supybot programs ('supybot', - 'supybot-wizard', etc.) and a $HOME/lib directory containing the - Supybot libraries. It is also recommended that you setup a proper - PYTHONPATH environment variable in your shell's init file. - - bash -- 'export PYTHONPATH=$HOME/lib/python2.x/site-packages' - - (t)csh -- 'setenv PYTHONPATH $HOME/lib/python2.x/site-packages' + --user' to install into your home directory. You'll now have + a $HOME/.local/bin directory containing Supybot programs ('supybot', + 'supybot-wizard', etc.) and a $HOME/.local/lib directory containing the + Supybot libraries. Windows From 741599c94767b9d1f5f25fb5969cfd81b72fe31f Mon Sep 17 00:00:00 2001 From: Valentin Lorentz Date: Sun, 18 Mar 2012 20:45:17 +0100 Subject: [PATCH 11/15] Add the channel where a command has been called in the logs ('XXX called by XXX'). Signed-off-by: James McCoy --- src/callbacks.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/callbacks.py b/src/callbacks.py index a2afdcd46..eaf43cce7 100644 --- a/src/callbacks.py +++ b/src/callbacks.py @@ -1166,7 +1166,12 @@ class Commands(BasePlugin): method(irc, msg, *args, **kwargs) def _callCommand(self, command, irc, msg, *args, **kwargs): - self.log.info('%s called by %q.', formatCommand(command), msg.prefix) + if irc.nick == msg.args[0]: + self.log.info('%s called in private by %q.', formatCommand(command), + msg.prefix) + else: + self.log.info('%s called on %s by %q.', formatCommand(command), + msg.args[0], msg.prefix) # XXX I'm being extra-special-careful here, but we need to refactor # this. try: From a630cc34d8c99647604a29eff2843efa3b7766df Mon Sep 17 00:00:00 2001 From: Valentin Lorentz Date: Tue, 3 Apr 2012 21:01:10 +0200 Subject: [PATCH 12/15] Use ircutils.joinModes() instead of hacky str.join()s in ircmsgs.unbans. Signed-off-by: James McCoy --- src/ircmsgs.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ircmsgs.py b/src/ircmsgs.py index 911a2290b..c655d770a 100644 --- a/src/ircmsgs.py +++ b/src/ircmsgs.py @@ -519,11 +519,11 @@ def unbans(channel, hostmasks, prefix='', msg=None): if conf.supybot.protocols.irc.strictRfc(): assert isChannel(channel), repr(channel) assert all(isUserHostmask, hostmasks), hostmasks + modes = [('-b', s) for s in hostmasks] if msg and not prefix: prefix = msg.prefix - return IrcMsg(prefix=prefix, command='MODE', msg=msg, - args=(channel, '-' + ('b'*len(hostmasks)), - ' '.join(hostmasks))) + return IrcMsg(prefix=prefix, command='MODE', + args=[channel] + ircutils.joinModes(modes), msg=msg) def kick(channel, nick, s='', prefix='', msg=None): """Returns a KICK to kick nick from channel with the message msg.""" From e45b9abd232b869fc7d42eae3def249bf8b724b6 Mon Sep 17 00:00:00 2001 From: Valentin Lorentz Date: Mon, 7 May 2012 15:16:20 +0000 Subject: [PATCH 13/15] Math: Block factorial() in calc functions. Signed-off-by: James McCoy --- plugins/Math/plugin.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/Math/plugin.py b/plugins/Math/plugin.py index d3bb5aeb0..c34891461 100644 --- a/plugins/Math/plugin.py +++ b/plugins/Math/plugin.py @@ -103,6 +103,7 @@ class Math(callbacks.Plugin): _mathEnv['abs'] = abs _mathEnv['max'] = max _mathEnv['min'] = min + _mathEnv.pop('factorial') _mathRe = re.compile(r'((?:(? Date: Mon, 7 May 2012 17:52:02 +0200 Subject: [PATCH 14/15] Math: Allow 'factorial()' in icalc. Signed-off-by: James McCoy --- plugins/Math/plugin.py | 5 +++-- plugins/Math/test.py | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/plugins/Math/plugin.py b/plugins/Math/plugin.py index c34891461..01c9261fc 100644 --- a/plugins/Math/plugin.py +++ b/plugins/Math/plugin.py @@ -103,7 +103,8 @@ class Math(callbacks.Plugin): _mathEnv['abs'] = abs _mathEnv['max'] = max _mathEnv['min'] = min - _mathEnv.pop('factorial') + _mathSafeEnv = dict([(x,y) for x,y in _mathEnv.items() + if x not in ['factorial']]) _mathRe = re.compile(r'((?:(? Date: Wed, 6 Jun 2012 06:00:48 -0400 Subject: [PATCH 15/15] irclib: Modes aren't case insenstive Signed-off-by: James McCoy --- src/irclib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/irclib.py b/src/irclib.py index 164f23050..c4292e880 100644 --- a/src/irclib.py +++ b/src/irclib.py @@ -240,7 +240,7 @@ class ChannelState(utils.python.Object): self.users = ircutils.IrcSet() self.voices = ircutils.IrcSet() self.halfops = ircutils.IrcSet() - self.modes = ircutils.IrcDict() + self.modes = {} def isOp(self, nick): return nick in self.ops