From e817b2379e4c0d242c1fbe20e689c70bf2d72037 Mon Sep 17 00:00:00 2001 From: Jeremy Fincher Date: Fri, 22 Oct 2004 04:49:39 +0000 Subject: [PATCH] Broke out some of the behavior of the Enforcer plugin. --- plugins/AutoMode.py | 127 ++++++++++++++++++++++++++++++++++++++++++++ plugins/Cycler.py | 87 ++++++++++++++++++++++++++++++ plugins/Limiter.py | 97 +++++++++++++++++++++++++++++++++ 3 files changed, 311 insertions(+) create mode 100644 plugins/AutoMode.py create mode 100644 plugins/Cycler.py create mode 100644 plugins/Limiter.py diff --git a/plugins/AutoMode.py b/plugins/AutoMode.py new file mode 100644 index 000000000..20a81a4bb --- /dev/null +++ b/plugins/AutoMode.py @@ -0,0 +1,127 @@ +### +# Copyright (c) 2004, Jeremiah Fincher +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +### + +""" +Automatically ops, voices, or halfops, or bans people when they join a channel, +according to their capabilities. If you want your bot automatically op users +when they join your channel, this is the plugin to load. +""" + +import supybot + +__revision__ = "$Id$" +__author__ = supybot.authors.jemfinch +__contributors__ = {} + + +import supybot.conf as conf +import supybot.utils as utils +import supybot.plugins as plugins +import supybot.privmsgs as privmsgs +import supybot.registry as registry +import supybot.callbacks as callbacks + + +def configure(advanced): + # This will be called by setup.py to configure this module. Advanced is + # a bool that specifies whether the user identified himself as an advanced + # user or not. You should effect your configuration by manipulating the + # registry as appropriate. + from supybot.questions import expect, anything, something, yn + conf.registerPlugin('AutoMode', True) + +AutoMode = conf.registerPlugin('AutoMode') +conf.registerChannelValue(AutoMode, 'enable', + registry.Boolean(True, """Determines whether this plugin is enabled.""")) +conf.registerChannelValue(AutoMode, 'fallthrough', + registry.Boolean(False, """Determines whether the bot will "fall through" to + halfop/voicing when auto-opping is turned off but auto-halfopping/voicing + are turned on.""")) +conf.registerChannelValue(AutoMode, 'op', + registry.Boolean(True, """Determines whether the bot will automatically op + people with the ,op capability when they join the channel.""")) +conf.registerChannelValue(AutoMode, 'halfop', + registry.Boolean(True, """Determines whether the bot will automatically + halfop people with the ,halfop capability when they join the + channel.""")) +conf.registerChannelValue(AutoMode, 'voice', + registry.Boolean(True, """Determines whether the bot will automatically + voice people with the ,voice capability when they join the + channel.""")) +conf.registerChannelValue(AutoMode, 'ban', + registry.Boolean(True, """Determines whether the bot will automatically ban + people who join the channel and are on the banlist.""")) +conf.registerChannelValue(AutoMode.ban, 'period', + registry.PositiveInteger(86400, """Determines how many seconds the bot will + automatically ban a person when banning.""")) + +class Continue(Exception): + pass # Used below, look in the "do" function nested in doJoin. + +class AutoMode(callbacks.Privmsg): + def doJoin(self, irc, msg): + channel = msg.args[0] + if ircutils.strEqual(irc.nick, msg.nick): + return + if not self.registryValue('enable', channel): + return + fallthrough = self.registryValue('fallthrough', channel) + def do(type): + if self.registryValue(type, channel): + cap = ircdb.makeChannelCapability(channel, type) + if ircdb.checkCapability(msg.prefix, cap): + msgmaker = getattr(ircmsgs, type) + irc.queueMsg(msgmaker(channel, msg.nick)) + if fallthrough: + raise Return + try: + do('op') + do('halfop') + do('voice') + except Continue: + return + c = ircdb.channels.getChannel(channel) + if c.checkBan(msg.prefix) and self.registryValue('ban', channel): + period = self.registryValue('ban.period', channel) + if period: + def unban(): + try: + if msg.prefix in irc.state.channels[channel].bans: + irc.queueMsg(ircmsgs.unban(channel, msg.prefix)) + except KeyError: + # We're not in the channel anymore. + pass + schedule.addEvent(unban, time.time()+period) + irc.queueMsg(ircmsgs.ban(channel, msg.prefix)) + irc.queueMsg(irmcsgs.kick(channel, msg.nick)) + + +Class = AutoMode + +# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: diff --git a/plugins/Cycler.py b/plugins/Cycler.py new file mode 100644 index 000000000..a73b49b38 --- /dev/null +++ b/plugins/Cycler.py @@ -0,0 +1,87 @@ +### +# Copyright (c) 2004, Jeremiah Fincher +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +### + +""" +Cycles the channel if no one is in it in an attempt to get ops. +""" + +import supybot + +__revision__ = "$Id$" +__author__ = supybot.authors.jemfinch +__contributors__ = {} + + +import supybot.conf as conf +import supybot.utils as utils +import supybot.plugins as plugins +import supybot.privmsgs as privmsgs +import supybot.registry as registry +import supybot.callbacks as callbacks + + +def configure(advanced): + # This will be called by setup.py to configure this module. Advanced is + # a bool that specifies whether the user identified himself as an advanced + # user or not. You should effect your configuration by manipulating the + # registry as appropriate. + from supybot.questions import expect, anything, something, yn + conf.registerPlugin('Cycler', True) + +conf.registerPlugin('Cycler') +conf.registerChannelValue(conf.supybot.plugins.Cycler, 'enable', + registry.Boolean(False, """Determines whether the bot will cycle the channel + if it doesn't have ops and there's no one else in the channel.""")) + +class Cycler(callbacks.Privmsg): + def _cycle(self, irc, channel): + if self.registryValue('enable', channel) and \ + len(irc.state.channels[channel].users) == 1: + if 'i' not in irc.state.channels[channel].modes and \ + 'k' not in irc.state.channels[channel].modes: + # XXX We should pull these keywords from the registry. + self.log.info('Cycling %s: I\'m the only one left.', channel) + irc.queueMsg(ircmsgs.part(channel)) + irc.queueMsg(ircmsgs.join(channel)) + else: + self.log.info('Not cycling %s: it\'s +i or +k.', channel) + + def doPart(self, irc, msg): + if not ircutils.strEqual(msg.nick, irc.nick): + self._cycle(irc, msg.args[0]) + doKick = doPart + + def doQuit(self, irc, msg): + for (channel, c) in irc.state.channels.iteritems(): + self._cycle(irc, channel) + + +Class = Cycler + +# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: diff --git a/plugins/Limiter.py b/plugins/Limiter.py new file mode 100644 index 000000000..02752c376 --- /dev/null +++ b/plugins/Limiter.py @@ -0,0 +1,97 @@ +### +# Copyright (c) 2004, Jeremiah Fincher +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +### + +""" +This plugin handles channel limits (MODE +l). +""" + +import supybot + +__revision__ = "$Id$" +__author__ = supybot.authors.jemfinch +__contributors__ = {} + + +import supybot.conf as conf +import supybot.utils as utils +import supybot.plugins as plugins +import supybot.privmsgs as privmsgs +import supybot.registry as registry +import supybot.callbacks as callbacks + + +def configure(advanced): + # This will be called by setup.py to configure this module. Advanced is + # a bool that specifies whether the user identified himself as an advanced + # user or not. You should effect your configuration by manipulating the + # registry as appropriate. + from supybot.questions import expect, anything, something, yn + conf.registerPlugin('Limiter', True) + +conf.registerPlugin('Limiter') +conf.registerChannelValue(conf.supybot.plugins.Limiter, 'enable', + registry.Boolean(False, """Determines whether the bot will maintain the + channel limit to be slightly above the current number of people in the + channel, in order to make clone/drone attacks harder.""")) +conf.registerChannelValue(conf.supybot.plugins.Limiter, 'minimumExcess', + registry.PositiveInteger(5, """Determines the minimum number of free + spots that will be saved when limits are being enforced. This should + always be smaller than supybot.plugins.Limiter.limit.maximumExcess.""")) +conf.registerChannelValue(conf.supybot.plugins.Limiter, 'maximumExcess', + registry.PositiveInteger(10, """Determines the maximum number of free spots + that will be saved when limits are being enforced. This should always be + larger than supybot.plugins.Limiter.limit.minimumExcess.""")) + +class Limiter(callbacks.Privmsg): + def _enforceLimit(self, irc, channel): + if self.registryValue('enable', channel): + maximum = self.registryValue('maximumExcess', channel) + minimum = self.registryValue('minimumExcess', channel) + assert maximum > minimum + currentUsers = len(irc.state.channels[channel].users) + currentLimit = irc.state.channels[channel].modes.get('l', 0) + if currentLimit - currentUsers < minimum: + self._enforce(irc, ircmsgs.limit(channel,currentUsers+maximum)) + elif currentLimit - currentUsers > maximum: + self._enforce(irc, ircmsgs.limit(channel,currentUsers+minimum)) + + def doJoin(self, irc, msg): + if not ircutils.strEqual(msg.nick, irc.nick): + self._enforceLimit(irc, msg.args[0]) + doPart = doJoin + doKick = doJoin + + def doQuit(self, irc, msg): + for channel in irc.state.channels: + self._enforceLimit(irc, channel) + + +Class = Limiter + +# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: