commit d66203e1ea40d3d6249920375d1347d7fce8e9eb Author: Tim Windelschmidt Date: Fri Oct 23 16:46:09 2015 +0200 Initial Release diff --git a/plugins/Anonymous/README.txt b/plugins/Anonymous/README.txt new file mode 100644 index 0000000..d60b47a --- /dev/null +++ b/plugins/Anonymous/README.txt @@ -0,0 +1 @@ +Insert a description of your plugin here, with any notes, etc. about using it. diff --git a/plugins/Anonymous/__init__.py b/plugins/Anonymous/__init__.py new file mode 100644 index 0000000..5e491b2 --- /dev/null +++ b/plugins/Anonymous/__init__.py @@ -0,0 +1,61 @@ +### +# Copyright (c) 2005, Daniel DiPaolo +# 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. +### + +""" +Allows folks to talk through the bot anonymously. +""" + +import supybot +import supybot.world as world + +# Use this for the version of this plugin. You may wish to put a CVS keyword +# in here if you're keeping the plugin in CVS or some similar system. +__version__ = "%%VERSION%%" + +# XXX Replace this with an appropriate author or supybot.Author instance. +__author__ = supybot.authors.strike + +# This is a dictionary mapping supybot.Author instances to lists of +# contributions. +__contributors__ = {} + +import config +import plugin +reload(plugin) # In case we're being reloaded. +# Add more reloads here if you add third-party modules and want them to be +# reloaded when this plugin is reloaded. Don't forget to import them as well! + +if world.testing: + import test + +Class = plugin.Class +configure = config.configure + + +# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: diff --git a/plugins/Anonymous/__init__.pyc b/plugins/Anonymous/__init__.pyc new file mode 100644 index 0000000..b2237ee Binary files /dev/null and b/plugins/Anonymous/__init__.pyc differ diff --git a/plugins/Anonymous/config.py b/plugins/Anonymous/config.py new file mode 100644 index 0000000..6fbd758 --- /dev/null +++ b/plugins/Anonymous/config.py @@ -0,0 +1,63 @@ +### +# Copyright (c) 2005, Daniel DiPaolo +# 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. +### + +import supybot.conf as conf +import supybot.registry as registry + +def configure(advanced): + # This will be called by supybot 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('Anonymous', True) + + +Anonymous = conf.registerPlugin('Anonymous') +# This is where your configuration variables (if any) should go. For example: +# conf.registerGlobalValue(Anonymous, 'someConfigVariableName', +# registry.Boolean(False, """Help for someConfigVariableName.""")) +conf.registerChannelValue(conf.supybot.plugins.Anonymous, + 'requirePresenceInChannel', registry.Boolean(True, """Determines whether + the bot should require people trying to use this plugin to be in the + channel they wish to anonymously send to.""")) +conf.registerGlobalValue(conf.supybot.plugins.Anonymous, 'requireRegistration', + registry.Boolean(True, """Determines whether the bot should require people + trying to use this plugin to be registered.""")) +conf.registerGlobalValue(conf.supybot.plugins.Anonymous, 'requireCapability', + registry.String('', """Determines what capability (if any) the bot should + require people trying to use this plugin to have.""")) +conf.registerGlobalValue(conf.supybot.plugins.Anonymous, 'allowPrivateTarget', + registry.Boolean(False, """Determines whether the bot will require targets + of the "say" command to be public (i.e., channels). If this is True, the + bot will allow people to use the "say" command to send private messages to + other users.""")) + + +# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: diff --git a/plugins/Anonymous/config.pyc b/plugins/Anonymous/config.pyc new file mode 100644 index 0000000..a4e3e8c Binary files /dev/null and b/plugins/Anonymous/config.pyc differ diff --git a/plugins/Anonymous/plugin.py b/plugins/Anonymous/plugin.py new file mode 100644 index 0000000..1820530 --- /dev/null +++ b/plugins/Anonymous/plugin.py @@ -0,0 +1,96 @@ +### +# Copyright (c) 2005, Daniel DiPaolo +# 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. +### + +import supybot.ircdb as ircdb +import supybot.utils as utils +from supybot.commands import * +import supybot.ircmsgs as ircmsgs +import supybot.callbacks as callbacks + +class Anonymous(callbacks.Plugin): + """This plugin allows users to act through the bot anonymously. The 'do' + command has the bot perform an anonymous action in a given channel, and + the 'say' command allows other people to speak through the bot. Since + this can be fairly well abused, you might want to set + supybot.plugins.Anonymous.requireCapability so only users with that + capability can use this plugin. For extra security, you can require that + the user be *in* the channel they are trying to address anonymously with + supybot.plugins.Anonymous.requirePresenceInChannel, or you can require + that the user be registered by setting + supybot.plugins.Anonymous.requireRegistration. + """ + def _preCheck(self, irc, msg, channel): + if self.registryValue('requireRegistration'): + try: + _ = ircdb.users.getUser(msg.prefix) + except KeyError: + irc.errorNotRegistered(Raise=True) + capability = self.registryValue('requireCapability') + if capability: + if not ircdb.checkCapability(msg.prefix, capability): + irc.errorNoCapability(capability, Raise=True) + if self.registryValue('requirePresenceInChannel', channel) and \ + msg.nick not in irc.state.channels[channel].users: + irc.error(format('You must be in %s to %q in there.', + channel, 'say'), Raise=True) + c = ircdb.channels.getChannel(channel) + if c.lobotomized: + irc.error(format('I\'m lobotomized in %s.', channel), Raise=True) + if not c._checkCapability(self.name()): + irc.error('That channel has set its capabilities so as to ' + 'disallow the use of this plugin.', Raise=True) + + def say(self, irc, msg, args, channel, text): + """ + + Sends to . + """ + self._preCheck(irc, msg, channel) + self.log.info('Saying %q in %s due to %s.', + text, channel, msg.prefix) + irc.queueMsg(ircmsgs.privmsg(channel, text)) + irc.noReply() + say = wrap(say, ['inChannel', 'text']) + + def do(self, irc, msg, args, channel, text): + """ + + Performs in . + """ + self._preCheck(irc, msg, channel) + self.log.info('Performing %q in %s due to %s.', + text, channel, msg.prefix) + irc.queueMsg(ircmsgs.action(channel, text)) + irc.noReply() + do = wrap(do, ['inChannel', 'text']) + +Class = Anonymous + + +# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: diff --git a/plugins/Anonymous/plugin.pyc b/plugins/Anonymous/plugin.pyc new file mode 100644 index 0000000..2766507 Binary files /dev/null and b/plugins/Anonymous/plugin.pyc differ diff --git a/plugins/Anonymous/test.py b/plugins/Anonymous/test.py new file mode 100644 index 0000000..e2a9ab0 --- /dev/null +++ b/plugins/Anonymous/test.py @@ -0,0 +1,56 @@ +### +# Copyright (c) 2005, Daniel DiPaolo +# 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. +### + +from supybot.test import * + +class AnonymousTestCase(ChannelPluginTestCase): + plugins = ('Anonymous',) + def testSay(self): + m = self.assertError('anonymous say %s I love you!' % self.channel) + try: + orig = conf.supybot.plugins.Anonymous.requireRegistration() + conf.supybot.plugins.Anonymous.requireRegistration.setValue(False) + m = self.assertNotError('anonymous say %s foo!'%self.channel) + self.failUnless(m.args[1] == 'foo!') + finally: + conf.supybot.plugins.Anonymous.requireRegistration.setValue(orig) + + def testAction(self): + m = self.assertError('anonymous do %s loves you!' % self.channel) + try: + orig = conf.supybot.plugins.Anonymous.requireRegistration() + conf.supybot.plugins.Anonymous.requireRegistration.setValue(False) + m = self.assertNotError('anonymous do %s loves you!'%self.channel) + self.assertEqual(m.args, ircmsgs.action(self.channel, + 'loves you!').args) + finally: + conf.supybot.plugins.Anonymous.requireRegistration.setValue(orig) + + +# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: diff --git a/plugins/Flipdot/README.txt b/plugins/Flipdot/README.txt new file mode 100644 index 0000000..d60b47a --- /dev/null +++ b/plugins/Flipdot/README.txt @@ -0,0 +1 @@ +Insert a description of your plugin here, with any notes, etc. about using it. diff --git a/plugins/Flipdot/__init__.py b/plugins/Flipdot/__init__.py new file mode 100644 index 0000000..240b28a --- /dev/null +++ b/plugins/Flipdot/__init__.py @@ -0,0 +1,43 @@ +### +# Copyright (c) 2011, Fuck You +# All rights reserved. +# +# +### + +""" +Add a description of the plugin (to be presented to the user inside the wizard) +here. This should describe *what* the plugin does. +""" + +import supybot +import supybot.world as world + +# Use this for the version of this plugin. You may wish to put a CVS keyword +# in here if you're keeping the plugin in CVS or some similar system. +__version__ = "" + +# XXX Replace this with an appropriate author or supybot.Author instance. +__author__ = supybot.authors.unknown + +# This is a dictionary mapping supybot.Author instances to lists of +# contributions. +__contributors__ = {} + +# This is a url where the most recent plugin package can be downloaded. +__url__ = '' # 'http://supybot.com/Members/yourname/Raumstatus/download' + +import config +import plugin +reload(plugin) # In case we're being reloaded. +# Add more reloads here if you add third-party modules and want them to be +# reloaded when this plugin is reloaded. Don't forget to import them as well! + +#if world.testing: +# import test + +Class = plugin.Flipdot +configure = config.configure + + +# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: diff --git a/plugins/Flipdot/__init__.pyc b/plugins/Flipdot/__init__.pyc new file mode 100644 index 0000000..9d3f440 Binary files /dev/null and b/plugins/Flipdot/__init__.pyc differ diff --git a/plugins/Flipdot/config.py b/plugins/Flipdot/config.py new file mode 100644 index 0000000..a047c5c --- /dev/null +++ b/plugins/Flipdot/config.py @@ -0,0 +1,27 @@ +### +# Copyright (c) 2011, Fuck You +# All rights reserved. +# +# +### + +import supybot.conf as conf +import supybot.registry as registry + +def configure(advanced): + # This will be called by supybot 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('Flipdot', True) + + +Flipdot = conf.registerPlugin('Flipdot') +# This is where your configuration variables (if any) should go. For example: +conf.registerGlobalValue(Flipdot, 'host', + registry.String("2001:67c:275c:a9::c", """Host of Flipdot""")) +conf.registerGlobalValue(Flipdot, 'port', + registry.Integer(2323, """Port number of Flipdot""")) + +# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: diff --git a/plugins/Flipdot/config.pyc b/plugins/Flipdot/config.pyc new file mode 100644 index 0000000..1c32750 Binary files /dev/null and b/plugins/Flipdot/config.pyc differ diff --git a/plugins/Flipdot/plugin.py b/plugins/Flipdot/plugin.py new file mode 100644 index 0000000..e80d9c2 --- /dev/null +++ b/plugins/Flipdot/plugin.py @@ -0,0 +1,75 @@ +### +# Copyright (c) 2011, henne +# All rights reserved. +# +# +### +from threading import Event, Thread +import subprocess +import supybot.utils as utils +from supybot.commands import * +import supybot.plugins as plugins +import supybot.ircutils as ircutils +import supybot.callbacks as callbacks +import supybot.ircmsgs as ircmsgs +import socket, time +import Image, ImageFont, ImageDraw, sys +import fileinput + +class Flipdot(callbacks.Plugin): + sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) + def list2byte(l): + byte = 0 + i = 0 + for i in range(8): + byte += 2**(7-i) if l[i] else 0 + return byte + + def array2packet(a): + return str(bytearray([list2byte(a[i*8:i*8+8]) for i in range(len(a)/8)])) + + def str2array(s): + IMG_SIZE = (80,16) + FONT_SIZE = 11 + FONT_OFFSET= (1, 3) + + C_BLACK = (0, 0, 0) + C_WHITE = (255, 255, 255) + + image = Image.new("RGBA", IMG_SIZE, C_BLACK) + draw = ImageDraw.Draw(image) + draw.fontmode = "1" # No AA + #font = ImageFont.load_default() + font = ImageFont.truetype("/usr/share/fonts/truetype/freefont/FreeSans.ttf", FONT_SIZE) + + draw.text(FONT_OFFSET, s, font=font, fill=C_WHITE) + + imgmap = [] + for pixel in image.getdata(): + r, g, b, a = pixel + if r == 255: + imgmap.append(1) + else: + imgmap.append(0) + return imgmap + + def __init__(self, irc): + self.__parent = super(Flipdot, self) + self.__parent.__init__(irc) + # def __del__(self, irc): + # ampel.connection.close() + def start(self, irc, msg, args): + irc.reply("Lampel kann nun gesteuert werden (noch nicht.....)") + # ampel.connection.open(self.registryValue('host'), self.registryValue('port')) + # ampel.connection.write("io get port 2\n") + # buf = ampel.connection.read_until("\n", 1) + # self.state = buf[-2] + # irc.reply(self.state) + start = wrap(start) + def hilfe(self, irc, msg, args): + irc.reply("hilfe: Hilft dir...") + hilfe = wrap(hilfe) + def send(self, irc, msg, args): + sock.sendto(array2packet(str2array(msg.strip())), (self.registryValue('host'), self.registryValue('port'))) + send = wrap(send) +# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: diff --git a/plugins/Flipdot/plugin.pyc b/plugins/Flipdot/plugin.pyc new file mode 100644 index 0000000..c7fc82e Binary files /dev/null and b/plugins/Flipdot/plugin.pyc differ diff --git a/plugins/Gem/__init__.py b/plugins/Gem/__init__.py new file mode 100644 index 0000000..f406012 --- /dev/null +++ b/plugins/Gem/__init__.py @@ -0,0 +1,41 @@ +### +# Copyright (c) 2011, Fuck You +# All rights reserved. +# +# +### + +""" +Add a description of the plugin (to be presented to the user inside the wizard) +here. This should describe *what* the plugin does. +""" + +import supybot +import supybot.world as world + +# Use this for the version of this plugin. You may wish to put a CVS keyword +# in here if you're keeping the plugin in CVS or some similar system. +__version__ = "" + +# XXX Replace this with an appropriate author or supybot.Author instance. +__author__ = supybot.authors.unknown + +# This is a dictionary mapping supybot.Author instances to lists of +# contributions. +__contributors__ = {} + +# This is a url where the most recent plugin package can be downloaded. +__url__ = '' # 'http://supybot.com/Members/yourname/Raumstatus/download' + +import plugin +reload(plugin) # In case we're being reloaded. +# Add more reloads here if you add third-party modules and want them to be +# reloaded when this plugin is reloaded. Don't forget to import them as well! + +#if world.testing: +# import test + +Class = plugin.Gem + + +# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: diff --git a/plugins/Gem/__init__.pyc b/plugins/Gem/__init__.pyc new file mode 100644 index 0000000..5ed4f90 Binary files /dev/null and b/plugins/Gem/__init__.pyc differ diff --git a/plugins/Gem/plugin.py b/plugins/Gem/plugin.py new file mode 100644 index 0000000..d038db0 --- /dev/null +++ b/plugins/Gem/plugin.py @@ -0,0 +1,35 @@ +### +# Copyright (c) 2011, henne +# All rights reserved. +# +# +### +from threading import Event, Thread +import subprocess +import supybot.utils as utils +from supybot.commands import * +import supybot.plugins as plugins +import supybot.ircutils as ircutils +import supybot.callbacks as callbacks +import supybot.ircmsgs as ircmsgs +import random +class Gem(callbacks.Plugin): + gemActive = False + def __init__(self, irc): + self.__parent = super(Gem, self) + self.__parent.__init__(irc) + def gem(self, irc, msg, args): + if self.gemActive: + irc.reply("Gem Deactivated") + else: + c = random.randint(1,100) + if c>99: + irc.reply("Perfect Gem Activated") + elif c>90: + irc.reply("Mooooooooooooo!") + else: + irc.reply("Gem Activated") + self.gemActive = not self.gemActive + gem = wrap(gem) + +# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: diff --git a/plugins/Gem/plugin.pyc b/plugins/Gem/plugin.pyc new file mode 100644 index 0000000..5eb886d Binary files /dev/null and b/plugins/Gem/plugin.pyc differ diff --git a/plugins/Lampel/README.txt b/plugins/Lampel/README.txt new file mode 100644 index 0000000..d60b47a --- /dev/null +++ b/plugins/Lampel/README.txt @@ -0,0 +1 @@ +Insert a description of your plugin here, with any notes, etc. about using it. diff --git a/plugins/Lampel/__init__.py b/plugins/Lampel/__init__.py new file mode 100644 index 0000000..215dd8c --- /dev/null +++ b/plugins/Lampel/__init__.py @@ -0,0 +1,43 @@ +### +# Copyright (c) 2011, Fuck You +# All rights reserved. +# +# +### + +""" +Add a description of the plugin (to be presented to the user inside the wizard) +here. This should describe *what* the plugin does. +""" + +import supybot +import supybot.world as world + +# Use this for the version of this plugin. You may wish to put a CVS keyword +# in here if you're keeping the plugin in CVS or some similar system. +__version__ = "" + +# XXX Replace this with an appropriate author or supybot.Author instance. +__author__ = supybot.authors.unknown + +# This is a dictionary mapping supybot.Author instances to lists of +# contributions. +__contributors__ = {} + +# This is a url where the most recent plugin package can be downloaded. +__url__ = '' # 'http://supybot.com/Members/yourname/Raumstatus/download' + +import config +import plugin +reload(plugin) # In case we're being reloaded. +# Add more reloads here if you add third-party modules and want them to be +# reloaded when this plugin is reloaded. Don't forget to import them as well! + +#if world.testing: +# import test + +Class = plugin.Lampel +configure = config.configure + + +# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: diff --git a/plugins/Lampel/__init__.pyc b/plugins/Lampel/__init__.pyc new file mode 100644 index 0000000..9d3f440 Binary files /dev/null and b/plugins/Lampel/__init__.pyc differ diff --git a/plugins/Lampel/ampel.py b/plugins/Lampel/ampel.py new file mode 100644 index 0000000..25acd60 --- /dev/null +++ b/plugins/Lampel/ampel.py @@ -0,0 +1,2 @@ +import telnetlib +connection = telnetlib.Telnet() diff --git a/plugins/Lampel/ampel.pyc b/plugins/Lampel/ampel.pyc new file mode 100644 index 0000000..2a1e3f8 Binary files /dev/null and b/plugins/Lampel/ampel.pyc differ diff --git a/plugins/Lampel/config.py b/plugins/Lampel/config.py new file mode 100644 index 0000000..cde7821 --- /dev/null +++ b/plugins/Lampel/config.py @@ -0,0 +1,27 @@ +### +# Copyright (c) 2011, Fuck You +# All rights reserved. +# +# +### + +import supybot.conf as conf +import supybot.registry as registry + +def configure(advanced): + # This will be called by supybot 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('Lampel', True) + + +Lampel = conf.registerPlugin('Lampel') +# This is where your configuration variables (if any) should go. For example: +conf.registerGlobalValue(Lampel, 'host', + registry.String("lampel.raum.ctdo.de", """Host of Lampel""")) +conf.registerGlobalValue(Lampel, 'port', + registry.Integer(2701, """Port number of Lampel""")) + +# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: diff --git a/plugins/Lampel/config.pyc b/plugins/Lampel/config.pyc new file mode 100644 index 0000000..1c32750 Binary files /dev/null and b/plugins/Lampel/config.pyc differ diff --git a/plugins/Lampel/plugin.py b/plugins/Lampel/plugin.py new file mode 100644 index 0000000..18d8e28 --- /dev/null +++ b/plugins/Lampel/plugin.py @@ -0,0 +1,171 @@ +### +# Copyright (c) 2011, henne +# All rights reserved. +# +# +### +from threading import Event, Thread +import subprocess +import supybot.utils as utils +from supybot.commands import * +import supybot.plugins as plugins +import supybot.ircutils as ircutils +import supybot.callbacks as callbacks +import supybot.ircmsgs as ircmsgs +import ampel +import random +import time +class Lampel(callbacks.Plugin): +# state = 00 + threaded = True + discoan = False + def __init__(self, irc): + self.__parent = super(Lampel, self) + self.__parent.__init__(irc) + # def __del__(self, irc): + # ampel.connection.close() + def start(self, irc, msg, args): + irc.reply("Lampel kann nun gesteuert werden (noch nicht.....)") + # ampel.connection.open(self.registryValue('host'), self.registryValue('port')) + # ampel.connection.write("io get port 2\n") + # buf = ampel.connection.read_until("\n", 1) + # self.state = buf[-2] + # irc.reply(self.state) + start = wrap(start) + def rot(self, irc, msg, args): + ampel.connection.open(self.registryValue('host'), self.registryValue('port')) + ampel.connection.write("io set port 2 04\n") + ampel.connection.close() + rot = wrap(rot) + red = wrap(rot) + def gelb(self, irc, msg, args): + ampel.connection.open(self.registryValue('host'), self.registryValue('port')) + ampel.connection.write("io set port 2 02\n") + ampel.connection.close() + gelb = wrap(gelb) + yellow = wrap(gelb) + def gruen(self, irc, msg, args): + ampel.connection.open(self.registryValue('host'), self.registryValue('port')) + ampel.connection.write("io set port 2 01\n") + ampel.connection.close() + gruen = wrap(gruen) + green = wrap(gruen) + def rotgelbgruen(self, irc, msg, args): + ampel.connection.open(self.registryValue('host'), self.registryValue('port')) + ampel.connection.write("io set port 2 07\n") + ampel.connection.close() + rotgelbgruen = wrap(rotgelbgruen) + allcolors = wrap(rotgelbgruen) + allefarben = wrap(rotgelbgruen) + alle = wrap(rotgelbgruen) + def rotgelb(self, irc, msg, args): + ampel.connection.open(self.registryValue('host'), self.registryValue('port')) + ampel.connection.write("io set port 2 06\n") + ampel.connection.close() + rotgelb = wrap(rotgelb) + gelbrot = wrap(rotgelb) + redyellow = wrap(rotgelb) + yellowred = wrap(rotgelb) + def rotgruen(self, irc, msg, args): + ampel.connection.open(self.registryValue('host'), self.registryValue('port')) + ampel.connection.write("io set port 2 05\n") + ampel.connection.close() + rotgruen = wrap(rotgruen) + redgreen = wrap(rotgruen) + gruenrot = wrap(rotgruen) + greenred = wrap(rotgruen) + def gelbgruen(self, irc, msg, args): + ampel.connection.open(self.registryValue('host'), self.registryValue('port')) + ampel.connection.write("io set port 2 03\n") + ampel.connection.close() + gelbgruen = wrap(gelbgruen) + yellowgreen = wrap(gelbgruen) + gruengelb = wrap(gelbgruen) + greenyellow = wrap(gelbgruen) + def aus(self, irc, msg, args): + ampel.connection.open(self.registryValue('host'), self.registryValue('port')) + ampel.connection.write("io set port 2 00\n") + ampel.connection.close() + aus = wrap(aus) + off = wrap(aus) + def hilfe(self, irc, msg, args): + irc.reply("Help for the Lampelcontrol") + irc.reply("rot: Nur rot an (oder red)") + irc.reply("gelb: Nur gelb an (oder yellow)") + irc.reply("gruen: Nur gruen an (oder gruen)") + irc.reply("rotgelb: Rot und Gelb an (oder gelbrot, redyellow, yellowred)") + irc.reply("rotgruen: Rot und Gruen an (oder gruenrot, greenred, redgreen)") + irc.reply("gelbgruen: Gelb und Gruen an (oder gruengelb, greenyellow, yellowgreen)") + irc.reply("rotgelbgruen: alle an (oder alle, allefarben, allcolors)") + irc.reply("aus: alle aus (oder off)") + irc.reply("hilfe: Hilft dir...") + + hilfe = wrap(hilfe) + def ampelaus(self, irc, msg, args): + ampel.connection.open(self.registryValue('host'), self.registryValue('port')) + for i in range(1, 5): + ampel.connection.write("io set port 2 00\n") + time.sleep(1) + ampel.connection.write("io set port 2 02\n") + time.sleep(1) + ampel.connection.close() + def moo(self, irc, msg, args): + ampel.connection.open(self.registryValue('host'), self.registryValue('port')) + ampel.connection.write("io set port 2 00\n") + time.sleep(1) + ampel.connection.write("io set port 2 01\n") + time.sleep(1) + ampel.connection.write("io set port 2 02\n") + time.sleep(1) + ampel.connection.write("io set port 2 04\n") + time.sleep(1) + ampel.connection.write("io set port 2 00\n") + ampel.connection.close() + moo = wrap(moo) + def disco(self, irc, msg, args): + if not self.discoan: + irc.reply("And the Party begins") + self.discoTimer = meinTimer(2, self.discof, 0, [irc]) + self.discoTimer.daemon = True + self.discoan = True + self.discoTimer.start() + else: + irc.reply("The Party is over") + self.discoTimer.cancel() + self.discoan = False + disco = wrap(disco) + def discof(self, irc): + ampel.connection.open(self.registryValue('host'), self.registryValue('port')) + ampel.connection.write("io set port 2 0" + str(random.randint(0, 7)) + "\n") +# ampel.connection.write("io set port 2 01\n") + ampel.connection.close() +# def getState(self, irc, msg, args): +# ampel.connection.write("io get port 2\n") +# buf = ampel.connection.read_until("\n", 1) +# self.state = buf[-2] +# irc.reply(buf) +# getstate = wrap(getState) + + +class meinTimer(Thread): + def __init__(self, interval, function, iterations=0, args=[], kwargs={}): + Thread.__init__(self) + self.interval = interval + self.function = function + self.iterations = iterations + self.args = args + self.kwargs = kwargs + self.finished = Event() + + def run(self): + count = 0 + while not self.finished.isSet() and (self.iterations <= 0 or count < self.iterations): + self.finished.wait(self.interval) + if not self.finished.isSet(): + self.function(*self.args, **self.kwargs) + count += 1 + + def cancel(self): + self.finished.set() + +# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: diff --git a/plugins/Lampel/plugin.pyc b/plugins/Lampel/plugin.pyc new file mode 100644 index 0000000..c7fc82e Binary files /dev/null and b/plugins/Lampel/plugin.pyc differ diff --git a/plugins/Raumstatus/README.txt b/plugins/Raumstatus/README.txt new file mode 100644 index 0000000..d60b47a --- /dev/null +++ b/plugins/Raumstatus/README.txt @@ -0,0 +1 @@ +Insert a description of your plugin here, with any notes, etc. about using it. diff --git a/plugins/Raumstatus/__init__.py b/plugins/Raumstatus/__init__.py new file mode 100644 index 0000000..a6cb9ef --- /dev/null +++ b/plugins/Raumstatus/__init__.py @@ -0,0 +1,43 @@ +### +# Copyright (c) 2011, Fuck You +# All rights reserved. +# +# +### + +""" +Add a description of the plugin (to be presented to the user inside the wizard) +here. This should describe *what* the plugin does. +""" + +import supybot +import supybot.world as world + +# Use this for the version of this plugin. You may wish to put a CVS keyword +# in here if you're keeping the plugin in CVS or some similar system. +__version__ = "" + +# XXX Replace this with an appropriate author or supybot.Author instance. +__author__ = supybot.authors.unknown + +# This is a dictionary mapping supybot.Author instances to lists of +# contributions. +__contributors__ = {} + +# This is a url where the most recent plugin package can be downloaded. +__url__ = '' # 'http://supybot.com/Members/yourname/Raumstatus/download' + +import config +import plugin +reload(plugin) # In case we're being reloaded. +# Add more reloads here if you add third-party modules and want them to be +# reloaded when this plugin is reloaded. Don't forget to import them as well! + +if world.testing: + import test + +Class = plugin.Class +configure = config.configure + + +# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: diff --git a/plugins/Raumstatus/__init__.pyc b/plugins/Raumstatus/__init__.pyc new file mode 100644 index 0000000..84e139e Binary files /dev/null and b/plugins/Raumstatus/__init__.pyc differ diff --git a/plugins/Raumstatus/config.py b/plugins/Raumstatus/config.py new file mode 100644 index 0000000..4d006fb --- /dev/null +++ b/plugins/Raumstatus/config.py @@ -0,0 +1,34 @@ +### +# Copyright (c) 2011, Fuck You +# All rights reserved. +# +# +### + +import supybot.conf as conf +import supybot.registry as registry + +def configure(advanced): + # This will be called by supybot 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('Raumstatus', True) + + +Raumstatus = conf.registerPlugin('Raumstatus') +# This is where your configuration variables (if any) should go. For example: +conf.registerGlobalValue(Raumstatus, 'target', + registry.String("switch2.raum.chaostreff-dortmund.de", """IP Address to ping.""")) +conf.registerGlobalValue(Raumstatus, 'interval', + registry.Integer(30, """Checking interval.""")) +conf.registerGlobalValue(Raumstatus, 'channel', + registry.String("#ccc.do", """Channel to set topic.""")) + + + + + + +# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: diff --git a/plugins/Raumstatus/config.pyc b/plugins/Raumstatus/config.pyc new file mode 100644 index 0000000..f950d6c Binary files /dev/null and b/plugins/Raumstatus/config.pyc differ diff --git a/plugins/Raumstatus/local/__init__.py b/plugins/Raumstatus/local/__init__.py new file mode 100644 index 0000000..e86e97b --- /dev/null +++ b/plugins/Raumstatus/local/__init__.py @@ -0,0 +1 @@ +# Stub so local is a module, used for third-party modules diff --git a/plugins/Raumstatus/plugin.py b/plugins/Raumstatus/plugin.py new file mode 100644 index 0000000..eccc096 --- /dev/null +++ b/plugins/Raumstatus/plugin.py @@ -0,0 +1,100 @@ +### +# Copyright (c) 2011, xleave +# All rights reserved. +# +# +### +from threading import Event, Thread +import subprocess +import supybot.utils as utils +from supybot.commands import * +import supybot.plugins as plugins +import supybot.ircutils as ircutils +import supybot.callbacks as callbacks +import supybot.ircmsgs as ircmsgs +import re + +raum_in_str = re.compile(".*(raum:|r:).*", re.I).match +raumstatus_is_open = re.compile("(raum: |r: )(auf|offen|open)", re.I).match +raumstatus_is_closed = re.compile("(raum: |r: )(zu|geschlossen|closed)", re.I).match +raumstatus_replace = re.compile("((raum: |r: ))[^ ]*", re.I).sub + +class Raumstatus(callbacks.Plugin): + threaded = True + foo = "2" + def __init__(self, irc): + self.__parent = super(Raumstatus, self) + self.__parent.__init__(irc) + self.meinTimer = RepeatTimer(2, self.Bla, 0, [irc]) + self.meinTimer.daemon = True + def start(self, irc, msg, args): + irc.reply("starting timer") + self.meinTimer.start() + irc.reply("MUST DESTROY UNIVERSE!!!") + start = wrap(start) + + def stop(self, irc, msg, args): + irc.reply("stopping timer") + self.meinTimer.cancel() + irc.reply("FUCKED") + stop = wrap(stop) + + def Bla(self, irc): + c = currentTopic = irc.state.getTopic(self.registryValue('channel')) +# import pdb;pdb.set_trace() +# c = currentTopic = irc.state.channels["#ccc.do"].topic + + # raise Exception("%s %s %s %s"%("fuck you", type(c), dir(c), c)) +# print "blabla %s " % self.registryValue('target') + ret = subprocess.call("ping -c6 -i .2 %s" % self.registryValue('target'), + shell=True, + stdout=open('/dev/null','w'), + stderr=subprocess.STDOUT) + x = raum_in_str(c) + if ret == 0: + if not x: + currentTopic = "Raum: auf | %s"%currentTopic + else: + if not raumstatus_is_open(currentTopic): + currentTopic = raumstatus_replace('\\1auf', currentTopic) + + else: + if not x: + currentTopic = "Raum: zu | %s"%currentTopic + else: + if not raumstatus_is_closed(currentTopic): + currentTopic = raumstatus_replace('\\1zu', currentTopic) + + if c != currentTopic: + irc.queueMsg(ircmsgs.topic(self.registryValue('channel'), currentTopic[:159])) +# irc.sendMsg(ircmsgs.privmsg("#ccc.do", "reset topic")) + + + + + +class RepeatTimer(Thread): + def __init__(self, interval, function, iterations=0, args=[], kwargs={}): + Thread.__init__(self) + self.interval = interval + self.function = function + self.iterations = iterations + self.args = args + self.kwargs = kwargs + self.finished = Event() + + def run(self): + count = 0 + while not self.finished.isSet() and (self.iterations <= 0 or count < self.iterations): + self.finished.wait(self.interval) + if not self.finished.isSet(): + self.function(*self.args, **self.kwargs) + count += 1 + + def cancel(self): + self.finished.set() + +Class = Raumstatus + + +# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: diff --git a/plugins/Raumstatus/plugin.pyc b/plugins/Raumstatus/plugin.pyc new file mode 100644 index 0000000..c912def Binary files /dev/null and b/plugins/Raumstatus/plugin.pyc differ diff --git a/plugins/Raumstatus/test.py b/plugins/Raumstatus/test.py new file mode 100644 index 0000000..2845cb1 --- /dev/null +++ b/plugins/Raumstatus/test.py @@ -0,0 +1,14 @@ +### +# Copyright (c) 2011, Fuck You +# All rights reserved. +# +# +### + +from supybot.test import * + +class RaumstatusTestCase(PluginTestCase): + plugins = ('Raumstatus',) + + +# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: diff --git a/plugins/Web/__init__.py b/plugins/Web/__init__.py new file mode 100644 index 0000000..68e4db1 --- /dev/null +++ b/plugins/Web/__init__.py @@ -0,0 +1,58 @@ +### +# Copyright (c) 2005, 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. +### + +""" +Includes various web-related commands. +""" + +import supybot +import supybot.world as world + +__version__ = "%%VERSION%%" + +__author__ = supybot.authors.jemfinch + +# This is a dictionary mapping supybot.Author instances to lists of +# contributions. +__contributors__ = {} + +import config +import plugin +reload(plugin) # In case we're being reloaded. +# Add more reloads here if you add third-party modules and want them to be +# reloaded when this plugin is reloaded. Don't forget to import them as well! + +if world.testing: + import test + +Class = plugin.Class +configure = config.configure + + +# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: diff --git a/plugins/Web/__init__.pyc b/plugins/Web/__init__.pyc new file mode 100644 index 0000000..f873ac0 Binary files /dev/null and b/plugins/Web/__init__.pyc differ diff --git a/plugins/Web/config.py b/plugins/Web/config.py new file mode 100644 index 0000000..2ce3e3b --- /dev/null +++ b/plugins/Web/config.py @@ -0,0 +1,61 @@ +### +# Copyright (c) 2005, 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. +### + +import supybot.conf as conf +import supybot.registry as registry + +def configure(advanced): + # This will be called by supybot 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 + Web = conf.registerPlugin('Web', True) + if yn("""This plugin also offers a snarfer that will try to fetch the + title of URLs that it sees in the channel. Would like you this + snarfer to be enabled?""", default=False): + Web.titleSnarfer.setValue(True) + + +Web = conf.registerPlugin('Web') +conf.registerChannelValue(Web, 'titleSnarfer', + registry.Boolean(False, """Determines whether the bot will output the HTML + title of URLs it sees in the channel.""")) +conf.registerChannelValue(Web, 'nonSnarfingRegexp', + registry.Regexp(None, """Determines what URLs are to be snarfed and stored + in the database in the channel; URLs matching the regexp given will not be + snarfed. Give the empty string if you have no URLs that you'd like to + exclude from being snarfed.""")) + +conf.registerGroup(Web, 'fetch') +conf.registerGlobalValue(Web.fetch, 'maximum', + registry.NonNegativeInteger(0, """Determines the maximum number of + bytes the bot will download via the 'fetch' command in this plugin.""")) + +# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: diff --git a/plugins/Web/config.pyc b/plugins/Web/config.pyc new file mode 100644 index 0000000..512756a Binary files /dev/null and b/plugins/Web/config.pyc differ diff --git a/plugins/Web/plugin.py b/plugins/Web/plugin.py new file mode 100644 index 0000000..2e1d178 --- /dev/null +++ b/plugins/Web/plugin.py @@ -0,0 +1,244 @@ +### +# Copyright (c) 2005, 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. +### + +import re +import HTMLParser +import htmlentitydefs + +import supybot.conf as conf +import supybot.utils as utils +from supybot.commands import * +import supybot.plugins as plugins +import supybot.ircutils as ircutils +import supybot.callbacks as callbacks + +class Title(HTMLParser.HTMLParser): + entitydefs = htmlentitydefs.entitydefs.copy() + entitydefs['nbsp'] = ' ' + entitydefs['apos'] = '\'' + def __init__(self): + self.inTitle = False + self.title = '' + HTMLParser.HTMLParser.__init__(self) + + def handle_starttag(self, tag, attrs): + if tag == 'title': + self.inTitle = True + + def handle_endtag(self, tag): + if tag == 'title': + self.inTitle = False + + def handle_data(self, data): + if self.inTitle: + self.title += data + + def handle_entityref(self, name): + if self.inTitle: + if name in self.entitydefs: + self.title += self.entitydefs[name] + +class Web(callbacks.PluginRegexp): + """Add the help for "@help Web" here.""" + threaded = True + regexps = ['titleSnarfer'] + def callCommand(self, command, irc, msg, *args, **kwargs): + try: + super(Web, self).callCommand(command, irc, msg, *args, **kwargs) + except utils.web.Error, e: + irc.reply(str(e)) + + def titleSnarfer(self, irc, msg, match): + r"https?://[^\])>\s]+" + channel = msg.args[0] + if not irc.isChannel(channel): + return + if callbacks.addressed(irc.nick, msg): + return + if self.registryValue('titleSnarfer', channel): + url = match.group(0) + r = self.registryValue('nonSnarfingRegexp', channel) + if r and r.search(url): + self.log.debug('Not titleSnarfing %q.', url) + return + try: + size = conf.supybot.protocols.http.peekSize() + text = utils.web.getUrl(url, size=size) + except utils.web.Error, e: + self.log.info('Couldn\'t snarf title of %u: %s.', url, e) + return + parser = Title() + try: + parser.feed(text) + except HTMLParser.HTMLParseError: + self.log.debug('Encountered a problem parsing %u. Title may ' + 'already be set, though', url) + if parser.title: + domain = utils.web.getDomain(url) + title = utils.web.htmlToText(parser.title.strip()) + s = format('Title: %s (at %s)', title, domain) + irc.reply(s, prefixNick=False) + titleSnarfer = urlSnarfer(titleSnarfer) + + def headers(self, irc, msg, args, url): + """ + + Returns the HTTP headers of . Only HTTP urls are valid, of + course. + """ + fd = utils.web.getUrlFd(url) + try: + s = ', '.join([format('%s: %s', k, v) + for (k, v) in fd.headers.items()]) + irc.reply(s) + finally: + fd.close() + headers = wrap(headers, ['httpUrl']) + + _doctypeRe = re.compile(r'(]+>)', re.M) + def doctype(self, irc, msg, args, url): + """ + + Returns the DOCTYPE string of . Only HTTP urls are valid, of + course. + """ + size = conf.supybot.protocols.http.peekSize() + s = utils.web.getUrl(url, size=size) + m = self._doctypeRe.search(s) + if m: + s = utils.str.normalizeWhitespace(m.group(0)) + irc.reply(s) + else: + irc.reply('That URL has no specified doctype.') + doctype = wrap(doctype, ['httpUrl']) + + def size(self, irc, msg, args, url): + """ + + Returns the Content-Length header of . Only HTTP urls are valid, + of course. + """ + fd = utils.web.getUrlFd(url) + try: + try: + size = fd.headers['Content-Length'] + irc.reply(format('%u is %i bytes long.', url, size)) + except KeyError: + size = conf.supybot.protocols.http.peekSize() + s = fd.read(size) + if len(s) != size: + irc.reply(format('%u is %i bytes long.', url, len(s))) + else: + irc.reply(format('The server didn\'t tell me how long %u ' + 'is but it\'s longer than %i bytes.', + url, size)) + finally: + fd.close() + size = wrap(size, ['httpUrl']) + + def title(self, irc, msg, args, url): + """ + + Returns the HTML ... of a URL. + """ + size = conf.supybot.protocols.http.peekSize() + text = utils.web.getUrl(url, size=size) + parser = Title() + try: + parser.feed(text) + except HTMLParser.HTMLParseError: + self.log.debug('Encountered a problem parsing %u. Title may ' + 'already be set, though', url) + if parser.title: + irc.reply(utils.web.htmlToText(parser.title.strip())) + elif len(text) < size: + irc.reply('That URL appears to have no HTML title.') + else: + irc.reply(format('That URL appears to have no HTML title ' + 'within the first %i bytes.', size)) + title = wrap(title, ['httpUrl']) + + _netcraftre = re.compile(r'td align="left">\s+]+>(.*?) + + Returns Netcraft.com's determination of what operating system and + webserver is running on the host given. + """ + url = 'http://uptime.netcraft.com/up/graph/?host=' + hostname + html = utils.web.getUrl(url) + m = self._netcraftre.search(html) + if m: + html = m.group(1) + s = utils.web.htmlToText(html, tagReplace='').strip() + s = s.rstrip('-').strip() + irc.reply(s) # Snip off "the site" + elif 'We could not get any results' in html: + irc.reply('No results found for %s.' % hostname) + else: + irc.error('The format of page the was odd.') + netcraft = wrap(netcraft, ['text']) + + def urlquote(self, irc, msg, args, text): + """ + + Returns the URL quoted form of the text. + """ + irc.reply(utils.web.urlquote(text)) + urlquote = wrap(urlquote, ['text']) + + def urlunquote(self, irc, msg, args, text): + """ + + Returns the text un-URL quoted. + """ + s = utils.web.urlunquote(text) + irc.reply(s) + urlunquote = wrap(urlunquote, ['text']) + + def fetch(self, irc, msg, args, url): + """ + + Returns the contents of , or as much as is configured in + supybot.plugins.Web.fetch.maximum. If that configuration variable is + set to 0, this command will be effectively disabled. + """ + max = self.registryValue('fetch.maximum') + if not max: + irc.error('This command is disabled ' + '(supybot.plugins.Web.fetch.maximum is set to 0).', + Raise=True) + fd = utils.web.getUrlFd(url) + irc.reply(fd.read(max)) + fetch = wrap(fetch, ['url']) + +Class = Web + +# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: diff --git a/plugins/Web/plugin.pyc b/plugins/Web/plugin.pyc new file mode 100644 index 0000000..38d94ba Binary files /dev/null and b/plugins/Web/plugin.pyc differ diff --git a/plugins/Web/test.py b/plugins/Web/test.py new file mode 100644 index 0000000..9e6ff4f --- /dev/null +++ b/plugins/Web/test.py @@ -0,0 +1,130 @@ +### +# Copyright (c) 2005, 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. +### + +from supybot.test import * + +class WebTestCase(ChannelPluginTestCase): + plugins = ('Web',) + timeout = 10 + if network: + def testHeaders(self): + self.assertError('headers ftp://ftp.cdrom.com/pub/linux') + self.assertNotError('headers http://www.slashdot.org/') + + def testDoctype(self): + self.assertError('doctype ftp://ftp.cdrom.com/pub/linux') + self.assertNotError('doctype http://www.slashdot.org/') + m = self.getMsg('doctype http://moobot.sf.net/') + self.failUnless(m.args[1].endswith('>')) + + def testSize(self): + self.assertError('size ftp://ftp.cdrom.com/pub/linux') + self.assertNotError('size http://supybot.sf.net/') + self.assertNotError('size http://www.slashdot.org/') + + def testTitle(self): + self.assertResponse('title http://www.slashdot.org/', + 'Slashdot - News for nerds, stuff that matters') + # Amazon add a bunch of scripting stuff to the top of their page, + # so we need to allow for a larger peekSize +# Actually, screw Amazon. Even bumping this up to 10k doesn't give us enough +# info. +# try: +# orig = conf.supybot.protocols.http.peekSize() +# conf.supybot.protocols.http.peekSize.setValue(8192) +# self.assertNotRegexp('title ' +# 'http://www.amazon.com/exec/obidos/tg/detail/-/' +# '1884822312/qid=1063140754/sr=8-1/ref=sr_8_1/' +# '002-9802970-2308826?v=glance&s=books&n=507846', +# 'no HTML title') +# finally: +# conf.supybot.protocols.http.peekSize.setValue(orig) + # Checks the non-greediness of the regexp + self.assertResponse('title ' + 'http://www.space.com/scienceastronomy/' + 'jupiter_dark_spot_031023.html', + 'SPACE.com -- Mystery Spot on Jupiter Baffles ' + 'Astronomers') + # Checks for @title not-working correctly + self.assertResponse('title ' + 'http://www.catb.org/~esr/jargon/html/F/foo.html', + 'foo') + # Checks for only grabbing the real title tags instead of title + # tags inside, for example, script tags. Bug #1190350 + self.assertNotRegexp('title ' + 'http://www.irinnews.org/report.asp?ReportID=45910&' + 'SelectRegion=West_Africa&SelectCountry=CHAD', + r'document\.write\(') + # Checks that title parser grabs the full title instead of just + # part of it. + self.assertRegexp('title http://www.n-e-r-d.com/', 'N.*E.*R.*D') + # Checks that the parser doesn't hang on invalid tags + print + print "If we have not fixed a bug with the parser, the following", + print "test will hang the test-suite." + self.assertNotError( + 'title http://www.youtube.com/watch?v=x4BtiqPN4u8') + + def testNetcraft(self): + self.assertNotError('netcraft slashdot.org') + + def testTitleSnarfer(self): + try: + conf.supybot.plugins.Web.titleSnarfer.setValue(True) + self.assertSnarfResponse('http://microsoft.com/', + 'Title: Microsoft Corporation' + ' (at microsoft.com)') + finally: + conf.supybot.plugins.Web.titleSnarfer.setValue(False) + + def testNonSnarfing(self): + snarf = conf.supybot.plugins.Web.nonSnarfingRegexp() + title = conf.supybot.plugins.Web.titleSnarfer() + try: + conf.supybot.plugins.Web.nonSnarfingRegexp.set('m/sf/') + try: + conf.supybot.plugins.Web.titleSnarfer.setValue(True) + self.assertSnarfNoResponse('http://sf.net/', 2) + self.assertSnarfRegexp('http://www.sourceforge.net/', + r'Sourceforge\.net') + finally: + conf.supybot.plugins.Web.titleSnarfer.setValue(title) + finally: + conf.supybot.plugins.Web.nonSnarfingRegexp.setValue(snarf) + + def testNonSnarfingRegexpConfigurable(self): + self.assertSnarfNoResponse('http://foo.bar.baz/', 2) + try: + conf.supybot.plugins.Web.nonSnarfingRegexp.set('m/biff/') + self.assertSnarfNoResponse('http://biff.bar.baz/', 2) + finally: + conf.supybot.plugins.Web.nonSnarfingRegexp.set('') + + +# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: diff --git a/supifoo.conf b/supifoo.conf new file mode 100644 index 0000000..08a0672 --- /dev/null +++ b/supifoo.conf @@ -0,0 +1,1341 @@ +### +# Determines the bot's default nick. +# +# Default value: supybot +### +supybot.nick: raumgirl + +### +# Determines what alternative nicks will be used if the primary nick +# (supybot.nick) isn't available. A %s in this nick is replaced by the +# value of supybot.nick when used. If no alternates are given, or if all +# are used, the supybot.nick will be perturbed appropriately until an +# unused nick is found. +# +# Default value: %s` %s_ +### +supybot.nick.alternates: %s` %s_ + +### +# Determines the bot's ident string, if the server doesn't provide one +# by default. +# +# Default value: supybot +### +supybot.ident: raumgirl + +### +# Determines the user the bot sends to the server. A standard user using +# the current version of the bot will be generated if this is left +# empty. +# +# Default value: +### +supybot.user: + +### +# Determines what networks the bot will connect to. +# +# Default value: +### +supybot.networks: hackint + +### +# Determines what password will be used on hackint. Yes, we know that +# technically passwords are server-specific and not network-specific, +# but this is the best we can do right now. +# +# Default value: +### +supybot.networks.hackint.password: + +### +# Determines what servers the bot will connect to for hackint. Each will +# be tried in order, wrapping back to the first when the cycle is +# completed. +# +# Default value: +### +supybot.networks.hackint.servers: 195.160.168.7:9999 + +### +# Determines what channels the bot will join only on hackint. +# +# Default value: +### +supybot.networks.hackint.channels: #ctdo + +### +# Determines what key (if any) will be used to join the channel. +# +# Default value: +### +supybot.networks.hackint.channels.key: + +### +# Determines whether the bot will attempt to connect with SSL sockets to +# hackint. +# +# Default value: False +### +supybot.networks.hackint.ssl: True + +### +# Determines how timestamps printed for human reading should be +# formatted. Refer to the Python documentation for the time module to +# see valid formatting characters for time formats. +# +# Default value: %I:%M %p, %B %d, %Y +### +supybot.reply.format.time: %I:%M %p, %B %d, %Y + +### +# Determines whether elapsed times will be given as "1 day, 2 hours, 3 +# minutes, and 15 seconds" or as "1d 2h 3m 15s". +# +# Default value: False +### +supybot.reply.format.time.elapsed.short: False + +### +# Determines the absolute maximum length of the bot's reply -- no reply +# will be passed through the bot with a length greater than this. +# +# Default value: 131072 +### +supybot.reply.maximumLength: 131072 + +### +# Determines whether the bot will break up long messages into chunks and +# allow users to use the 'more' command to get the remaining chunks. +# +# Default value: True +### +supybot.reply.mores: True + +### +# Determines what the maximum number of chunks (for use with the 'more' +# command) will be. +# +# Default value: 50 +### +supybot.reply.mores.maximum: 50 + +### +# Determines how long individual chunks will be. If set to 0, uses our +# super-tweaked, get-the-most-out-of-an-individual-message default. +# +# Default value: 0 +### +supybot.reply.mores.length: 0 + +### +# Determines how many mores will be sent instantly (i.e., without the +# use of the more command, immediately when they are formed). Defaults +# to 1, which means that a more command will be required for all but the +# first chunk. +# +# Default value: 1 +### +supybot.reply.mores.instant: 1 + +### +# Determines whether the bot will send multi-message replies in a single +# message or in multiple messages. For safety purposes (so the bot is +# less likely to flood) it will normally send everything in a single +# message, using mores if necessary. +# +# Default value: True +### +supybot.reply.oneToOne: True + +### +# Determines whether the bot will reply with an error message when it is +# addressed but not given a valid command. If this value is False, the +# bot will remain silent, as long as no other plugins override the +# normal behavior. +# +# Default value: True +### +supybot.reply.whenNotCommand: False + +### +# Determines whether error messages that result from bugs in the bot +# will show a detailed error message (the uncaught exception) or a +# generic error message. +# +# Default value: False +### +supybot.reply.error.detailed: False + +### +# Determines whether the bot will send error messages to users in +# private. You might want to do this in order to keep channel traffic to +# minimum. This can be used in combination with +# supybot.reply.error.withNotice. +# +# Default value: False +### +supybot.reply.error.inPrivate: False + +### +# Determines whether the bot will send error messages to users via +# NOTICE instead of PRIVMSG. You might want to do this so users can +# ignore NOTICEs from the bot and not have to see error messages; or you +# might want to use it in combination with supybot.reply.errorInPrivate +# so private errors don't open a query window in most IRC clients. +# +# Default value: False +### +supybot.reply.error.withNotice: False + +### +# Determines whether the bot will send an error message to users who +# attempt to call a command for which they do not have the necessary +# capability. You may wish to make this True if you don't want users to +# understand the underlying security system preventing them from running +# certain commands. +# +# Default value: False +### +supybot.reply.error.noCapability: False + +### +# Determines whether the bot will reply privately when replying in a +# channel, rather than replying to the whole channel. +# +# Default value: False +### +supybot.reply.inPrivate: False + +### +# Determines whether the bot will reply with a notice when replying in a +# channel, rather than replying with a privmsg as normal. +# +# Default value: False +### +supybot.reply.withNotice: False + +### +# Determines whether the bot will reply with a notice when it is sending +# a private message, in order not to open a /query window in clients. +# This can be overridden by individual users via the user configuration +# variable reply.withNoticeWhenPrivate. +# +# Default value: False +### +supybot.reply.withNoticeWhenPrivate: False + +### +# Determines whether the bot will always prefix the user's nick to its +# reply to that user's command. +# +# Default value: True +### +supybot.reply.withNickPrefix: True + +### +# Determines whether the bot should attempt to reply to all messages +# even if they don't address it (either via its nick or a prefix +# character). If you set this to True, you almost certainly want to set +# supybot.reply.whenNotCommand to False. +# +# Default value: False +### +supybot.reply.whenNotAddressed: False + +### +# Determines whether the bot will allow you to send channel-related +# commands outside of that channel. Sometimes people find it confusing +# if a channel-related command (like Filter.outfilter) changes the +# behavior of the channel but was sent outside the channel itself. +# +# Default value: False +### +supybot.reply.requireChannelCommandsToBeSentInChannel: False + +### +# Supybot normally replies with the full help whenever a user misuses a +# command. If this value is set to True, the bot will only reply with +# the syntax of the command (the first line of the help) rather than the +# full help. +# +# Default value: False +### +supybot.reply.showSimpleSyntax: False + +### +# Determines what prefix characters the bot will reply to. A prefix +# character is a single character that the bot will use to determine +# what messages are addressed to it; when there are no prefix characters +# set, it just uses its nick. Each character in this string is +# interpreted individually; you can have multiple prefix chars +# simultaneously, and if any one of them is used as a prefix the bot +# will assume it is being addressed. +# +# Default value: +### +supybot.reply.whenAddressedBy.chars: + +### +# Determines what strings the bot will reply to when they are at the +# beginning of the message. Whereas prefix.chars can only be one +# character (although there can be many of them), this variable is a +# space-separated list of strings, so you can set something like '@@ ??' +# and the bot will reply when a message is prefixed by either @@ or ??. +# +# Default value: +### +supybot.reply.whenAddressedBy.strings: + +### +# Determines whether the bot will reply when people address it by its +# nick, rather than with a prefix character. +# +# Default value: True +### +supybot.reply.whenAddressedBy.nick: True + +### +# Determines whether the bot will reply when people address it by its +# nick at the end of the message, rather than at the beginning. +# +# Default value: False +### +supybot.reply.whenAddressedBy.nick.atEnd: False + +### +# Determines what extra nicks the bot will always respond to when +# addressed by, even if its current nick is something else. +# +# Default value: +### +supybot.reply.whenAddressedBy.nicks: + +### +# Determines whether the bot will unidentify someone when that person +# changes his or her nick. Setting this to True will cause the bot to +# track such changes. It defaults to False for a little greater +# security. +# +# Default value: False +### +supybot.followIdentificationThroughNickChanges: False + +### +# Determines whether the bot will always join a channel when it's +# invited. If this value is False, the bot will only join a channel if +# the user inviting it has the 'admin' capability (or if it's explicitly +# told to join the channel using the Admin.join command) +# +# Default value: False +### +supybot.alwaysJoinOnInvite: False + +### +# Determines what message the bot replies with when a command succeeded. +# If this configuration variable is empty, no success message will be +# sent. +### +supybot.replies.success: The operation succeeded. + +### +# Determines what error message the bot gives when it wants to be +# ambiguous. +### +supybot.replies.error: An error has occurred and has been logged. Please\ + contact this bot's administrator for more\ + information. + +### +# Determines what message the bot replies with when someone tries to use +# a command that requires being identified or having a password and +# neither credential is correct. +### +supybot.replies.incorrectAuthentication: Your hostmask doesn't match or your\ + password is wrong. + +### +# Determines what error message the bot replies with when someone tries +# to accessing some information on a user the bot doesn't know about. +### +supybot.replies.noUser: I can't find %s in my user database. If you didn't\ + give a user name, then I might not know what your\ + user is, and you'll need to identify before this\ + command might work. + +### +# Determines what error message the bot replies with when someone tries +# to do something that requires them to be registered but they're not +# currently recognized. +### +supybot.replies.notRegistered: You must be registered to use this command.\ + If you are already registered, you must\ + either identify (using the identify command)\ + or add a hostmask matching your current\ + hostmask (using the "hostmask add" command). + +### +# Determines what error message is given when the bot is telling someone +# they aren't cool enough to use the command they tried to use. +### +supybot.replies.noCapability: You don't have the %s capability. If you think\ + that you should have this capability, be sure\ + that you are identified before trying again.\ + The 'whoami' command can tell you if you're\ + identified. + +### +# Determines what generic error message is given when the bot is telling +# someone that they aren't cool enough to use the command they tried to +# use, and the author of the code calling errorNoCapability didn't +# provide an explicit capability for whatever reason. +### +supybot.replies.genericNoCapability: You're missing some capability you\ + need. This could be because you\ + actually possess the anti-capability\ + for the capability that's required of\ + you, or because the channel provides\ + that anti-capability by default, or\ + because the global capabilities include\ + that anti-capability. Or, it could be\ + because the channel or\ + supybot.capabilities.default is set to\ + False, meaning that no commands are\ + allowed unless explicitly in your\ + capabilities. Either way, you can't do\ + what you want to do. + +### +# Determines what error messages the bot sends to people who try to do +# things in a channel that really should be done in private. +### +supybot.replies.requiresPrivacy: That operation cannot be done in a channel. + +### +# Determines what message the bot sends when it thinks you've +# encountered a bug that the developers don't know about. +### +supybot.replies.possibleBug: This may be a bug. If you think it is, please\ + file a bug report at . + +### +# A floating point number of seconds to throttle snarfed URLs, in order +# to prevent loops between two bots snarfing the same URLs and having +# the snarfed URL in the output of the snarf message. +# +# Default value: 10.0 +### +supybot.snarfThrottle: 10.0 + +### +# Determines the number of seconds between running the upkeep function +# that flushes (commits) open databases, collects garbage, and records +# some useful statistics at the debugging level. +# +# Default value: 3600 +### +supybot.upkeepInterval: 3600 + +### +# Determines whether the bot will periodically flush data and +# configuration files to disk. Generally, the only time you'll want to +# set this to False is when you want to modify those configuration files +# by hand and don't want the bot to flush its current version over your +# modifications. Do note that if you change this to False inside the +# bot, your changes won't be flushed. To make this change permanent, you +# must edit the registry yourself. +# +# Default value: True +### +supybot.flush: True + +### +# Determines what characters are valid for quoting arguments to commands +# in order to prevent them from being tokenized. +# +# Default value: " +### +supybot.commands.quotes: " + +### +# Determines whether the bot will allow nested commands, which rule. You +# definitely should keep this on. +# +# Default value: True +### +supybot.commands.nested: True + +### +# Determines what the maximum number of nested commands will be; users +# will receive an error if they attempt commands more nested than this. +# +# Default value: 10 +### +supybot.commands.nested.maximum: 10 + +### +# Supybot allows you to specify what brackets are used for your nested +# commands. Valid sets of brackets include [], <>, and {} (). [] has +# strong historical motivation, as well as being the brackets that don't +# require shift. <> or () might be slightly superior because they cannot +# occur in a nick. If this string is empty, nested commands will not be +# allowed in this channel. +# +# Default value: [] +### +supybot.commands.nested.brackets: [] + +### +# Supybot allows nested commands. Enabling this option will allow nested +# commands with a syntax similar to UNIX pipes, for example: 'bot: foo | +# bar'. +# +# Default value: False +### +supybot.commands.nested.pipeSyntax: False + +### +# Determines what commands have default plugins set, and which plugins +# are set to be the default for each of those commands. +### +supybot.commands.defaultPlugins.addcapability: Admin +supybot.commands.defaultPlugins.capabilities: User +supybot.commands.defaultPlugins.disable: Owner +supybot.commands.defaultPlugins.enable: Owner +supybot.commands.defaultPlugins.help: Misc +supybot.commands.defaultPlugins.ignore: Admin + +### +# Determines what plugins automatically get precedence over all other +# plugins when selecting a default plugin for a command. By default, +# this includes the standard loaded plugins. You probably shouldn't +# change this if you don't know what you're doing; if you do know what +# you're doing, then also know that this set is case-sensitive. +# +# Default value: Plugin Admin Misc User Owner Config Channel +### +supybot.commands.defaultPlugins.importantPlugins: Plugin Admin Misc User Owner Config Channel +supybot.commands.defaultPlugins.list: Misc +supybot.commands.defaultPlugins.reload: Owner +supybot.commands.defaultPlugins.removecapability: Admin +supybot.commands.defaultPlugins.unignore: Admin + +### +# Determines what commands are currently disabled. Such commands will +# not appear in command lists, etc. They will appear not even to exist. +# +# Default value: +### +supybot.commands.disabled: + +### +# Determines whether the bot will defend itself against command- +# flooding. +# +# Default value: True +### +supybot.abuse.flood.command: True + +### +# Determines how many commands users are allowed per minute. If a user +# sends more than this many commands in any 60 second period, he or she +# will be ignored for supybot.abuse.flood.command.punishment seconds. +# +# Default value: 12 +### +supybot.abuse.flood.command.maximum: 500 + +### +# Determines how many seconds the bot will ignore users who flood it +# with commands. +# +# Default value: 300 +### +supybot.abuse.flood.command.punishment: 300 + +### +# Determines whether the bot will defend itself against invalid command- +# flooding. +# +# Default value: True +### +supybot.abuse.flood.command.invalid: True + +### +# Determines how many invalid commands users are allowed per minute. If +# a user sends more than this many invalid commands in any 60 second +# period, he or she will be ignored for +# supybot.abuse.flood.command.invalid.punishment seconds. Typically, +# this value is lower than supybot.abuse.flood.command.maximum, since +# it's far less likely (and far more annoying) for users to flood with +# invalid commands than for them to flood with valid commands. +# +# Default value: 5 +### +supybot.abuse.flood.command.invalid.maximum: 5 + +### +# Determines how many seconds the bot will ignore users who flood it +# with invalid commands. Typically, this value is higher than +# supybot.abuse.flood.command.punishment, since it's far less likely +# (and far more annoying) for users to flood witih invalid commands than +# for them to flood with valid commands. +# +# Default value: 600 +### +supybot.abuse.flood.command.invalid.punishment: 30 + +### +# Determines the default length of time a driver should block waiting +# for input. +# +# Default value: 1.0 +### +supybot.drivers.poll: 1.0 + +### +# Determines what driver module the bot will use. Socket, a simple +# driver based on timeout sockets, is used by default because it's +# simple and stable. Twisted is very stable and simple, and if you've +# got Twisted installed, is probably your best bet. +# +# Default value: default +### +supybot.drivers.module: Twisted + +### +# Determines the maximum time the bot will wait before attempting to +# reconnect to an IRC server. The bot may, of course, reconnect earlier +# if possible. +# +# Default value: 300.0 +### +supybot.drivers.maxReconnectWait: 300.0 + +### +# Determines what directory configuration data is put into. +# +# Default value: conf +### +supybot.directories.conf: /home/blechhaufen/raumgirl/conf + +### +# Determines what directory data is put into. +# +# Default value: data +### +supybot.directories.data: /home/blechhaufen/raumgirl/data + +### +# Determines what directory temporary files are put into. +# +# Default value: tmp +### +supybot.directories.data.tmp: /home/blechhaufen/raumgirl/data/tmp + +### +# Determines what directory backup data is put into. +# +# Default value: backup +### +supybot.directories.backup: /home/blechhaufen/raumgirl/backup + +### +# Determines what directories the bot will look for plugins in. Accepts +# a comma-separated list of strings. This means that to add another +# directory, you can nest the former value and add a new one. E.g. you +# can say: bot: 'config supybot.directories.plugins [config +# supybot.directories.plugins], newPluginDirectory'. +# +# Default value: +### +supybot.directories.plugins: /home/blechhaufen/raumgirl/plugins + +### +# Determines what directory the bot will store its logfiles in. +# +# Default value: logs +### +supybot.directories.log: /home/blechhaufen/raumgirl/logs + +### +# Determines what plugins will be loaded. +# +# Default value: +### +supybot.plugins: Web Admin Misc Raumstatus Channel User Anonymous Owner Lampel Config Gem lampel + +### +# Determines whether this plugin is loaded by default. +### +supybot.plugins.Admin: True + +### +# Determines whether this plugin is publicly visible. +# +# Default value: True +### +supybot.plugins.Admin.public: True + +### +# Determines whether this plugin is loaded by default. +### +supybot.plugins.Anonymous: True + +### +# Determines whether this plugin is publicly visible. +# +# Default value: True +### +supybot.plugins.Anonymous.public: True + +### +# Determines whether the bot should require people trying to use this +# plugin to be in the channel they wish to anonymously send to. +# +# Default value: True +### +supybot.plugins.Anonymous.requirePresenceInChannel: False + +### +# Determines whether the bot should require people trying to use this +# plugin to be registered. +# +# Default value: True +### +supybot.plugins.Anonymous.requireRegistration: True + +### +# Determines what capability (if any) the bot should require people +# trying to use this plugin to have. +# +# Default value: +### +supybot.plugins.Anonymous.requireCapability: + +### +# Determines whether the bot will require targets of the "say" command +# to be public (i.e., channels). If this is True, the bot will allow +# people to use the "say" command to send private messages to other +# users. +# +# Default value: False +### +supybot.plugins.Anonymous.allowPrivateTarget: False + +### +# Determines whether this plugin is loaded by default. +### +supybot.plugins.Channel: True + +### +# Determines whether this plugin is publicly visible. +# +# Default value: True +### +supybot.plugins.Channel.public: True + +### +# Determines whether the bot will always try to rejoin a channel +# whenever it's kicked from the channel. +# +# Default value: True +### +supybot.plugins.Channel.alwaysRejoin: True + +### +# Determines whether this plugin is loaded by default. +### +supybot.plugins.Config: True + +### +# Determines whether this plugin is publicly visible. +# +# Default value: True +### +supybot.plugins.Config.public: True + +### +# Determines whether this plugin is loaded by default. +### +supybot.plugins.Gem: True + +### +# Determines whether this plugin is publicly visible. +# +# Default value: True +### +supybot.plugins.Gem.public: True + +### +# Determines whether this plugin is loaded by default. +### +supybot.plugins.Lampel: True + +### +# Determines whether this plugin is publicly visible. +# +# Default value: True +### +supybot.plugins.Lampel.public: True + +### +# Host of Lampel +# +# Default value: lampel.raum.ctdo.de +### +supybot.plugins.Lampel.host: lampel.raum.ctdo.de + +### +# Port number of Lampel +# +# Default value: 2701 +### +supybot.plugins.Lampel.port: 2701 + +### +# Determines whether this plugin is loaded by default. +### +supybot.plugins.Misc: True + +### +# Determines whether this plugin is publicly visible. +# +# Default value: True +### +supybot.plugins.Misc.public: True + +### +# Determines whether the bot will list private plugins with the list +# command if given the --private switch. If this is disabled, non-owner +# users should be unable to see what private plugins are loaded. +# +# Default value: True +### +supybot.plugins.Misc.listPrivatePlugins: True + +### +# Determines the format string for timestamps in the Misc.last command. +# Refer to the Python documentation for the time module to see what +# formats are accepted. If you set this variable to the empty string, +# the timestamp will not be shown. +# +# Default value: [%H:%M:%S] +### +supybot.plugins.Misc.timestampFormat: [%H:%M:%S] + +### +# Determines whether or not the timestamp will be included in the output +# of last when it is part of a nested command +# +# Default value: False +### +supybot.plugins.Misc.last.nested.includeTimestamp: False + +### +# Determines whether or not the nick will be included in the output of +# last when it is part of a nested command +# +# Default value: False +### +supybot.plugins.Misc.last.nested.includeNick: False + +### +# Determines whether this plugin is loaded by default. +### +supybot.plugins.Owner: True + +### +# Determines whether this plugin is publicly visible. +# +# Default value: True +### +supybot.plugins.Owner.public: True + +### +# Determines what quit message will be used by default. If the quit +# command is called without a quit message, this will be used. If this +# value is empty, the nick of the person giving the quit command will be +# used. +# +# Default value: +### +supybot.plugins.Owner.quitMsg: + +### +# Determines whether this plugin is loaded by default. +### +supybot.plugins.Raumstatus: True + +### +# Determines whether this plugin is publicly visible. +# +# Default value: True +### +supybot.plugins.Raumstatus.public: True + +### +# IP Address to ping. +# +# Default value: switch2.raum.chaostreff-dortmund.de +### +supybot.plugins.Raumstatus.target: switch2.raum.chaostreff-dortmund.de + +### +# Checking interval. +# +# Default value: 30 +### +supybot.plugins.Raumstatus.interval: 5 + +### +# Channel to set topic. +#### +supybot.plugins.Raumstatus.channel: #ctdo + +### +# Determines whether this plugin is loaded by default. +### +supybot.plugins.User: True + +### +# Determines whether this plugin is publicly visible. +# +# Default value: True +### +supybot.plugins.User.public: True + +### +# Determines whether this plugin is loaded by default. +### +supybot.plugins.Web: True + +### +# Determines whether this plugin is publicly visible. +# +# Default value: True +### +supybot.plugins.Web.public: True + +### +# Determines whether the bot will output the HTML title of URLs it sees +# in the channel. +# +# Default value: False +### +supybot.plugins.Web.titleSnarfer: True + +### +# Determines what URLs are to be snarfed and stored in the database in +# the channel; URLs matching the regexp given will not be snarfed. Give +# the empty string if you have no URLs that you'd like to exclude from +# being snarfed. +# +# Default value: +### +supybot.plugins.Web.nonSnarfingRegexp: + +### +# Determines the maximum number of bytes the bot will download via the +# 'fetch' command in this plugin. +# +# Default value: 0 +### +supybot.plugins.Web.fetch.maximum: 0 + +### +# Determines whether the bot will always load important plugins (Admin, +# Channel, Config, Misc, Owner, and User) regardless of what their +# configured state is. Generally, if these plugins are configured not to +# load, you didn't do it on purpose, and you still want them to load. +# Users who don't want to load these plugins are smart enough to change +# the value of this variable appropriately :) +# +# Default value: True +### +supybot.plugins.alwaysLoadImportant: True + +### +# Determines what databases are available for use. If this value is not +# configured (that is, if its value is empty) then sane defaults will be +# provided. +# +# Default value: anydbm cdb flat pickle +### +supybot.databases: + +### +# Determines what filename will be used for the users database. This +# file will go into the directory specified by the +# supybot.directories.conf variable. +# +# Default value: users.conf +### +supybot.databases.users.filename: users.conf + +### +# Determines how long it takes identification to time out. If the value +# is less than or equal to zero, identification never times out. +# +# Default value: 0 +### +supybot.databases.users.timeoutIdentification: 0 + +### +# Determines whether the bot will allow users to unregister their users. +# This can wreak havoc with already-existing databases, so by default we +# don't allow it. Enable this at your own risk. (Do also note that this +# does not prevent the owner of the bot from using the unregister +# command.) +# +# Default value: False +### +supybot.databases.users.allowUnregistration: False + +### +# Determines what filename will be used for the ignores database. This +# file will go into the directory specified by the +# supybot.directories.conf variable. +# +# Default value: ignores.conf +### +supybot.databases.ignores.filename: ignores.conf + +### +# Determines what filename will be used for the channels database. This +# file will go into the directory specified by the +# supybot.directories.conf variable. +# +# Default value: channels.conf +### +supybot.databases.channels.filename: channels.conf + +### +# Determines whether database-based plugins that can be channel-specific +# will be so. This can be overridden by individual channels. Do note +# that the bot needs to be restarted immediately after changing this +# variable or your db plugins may not work for your channel; also note +# that you may wish to set +# supybot.databases.plugins.channelSpecific.link appropriately if you +# wish to share a certain channel's databases globally. +# +# Default value: True +### +supybot.databases.plugins.channelSpecific: True + +### +# Determines what channel global (non-channel-specific) databases will +# be considered a part of. This is helpful if you've been running +# channel-specific for awhile and want to turn the databases for your +# primary channel into global databases. If +# supybot.databases.plugins.channelSpecific.link.allow prevents linking, +# the current channel will be used. Do note that the bot needs to be +# restarted immediately after changing this variable or your db plugins +# may not work for your channel. +# +# Default value: # +### +supybot.databases.plugins.channelSpecific.link: # + +### +# Determines whether another channel's global (non-channel-specific) +# databases will be allowed to link to this channel's databases. Do note +# that the bot needs to be restarted immediately after changing this +# variable or your db plugins may not work for your channel. +# +# Default value: True +### +supybot.databases.plugins.channelSpecific.link.allow: True + +### +# Determines whether CDB databases will be allowed as a database +# implementation. +# +# Default value: True +### +supybot.databases.types.cdb: True + +### +# Determines how often CDB databases will have their modifications +# flushed to disk. When the number of modified records is greater than +# this part of the number of unmodified records, the database will be +# entirely flushed to disk. +# +# Default value: 0.5 +### +supybot.databases.types.cdb.maximumModifications: 0.5 + +### +# Determines what will be used as the default banmask style. +# +# Default value: host user +### +supybot.protocols.irc.banmask: host user + +### +# Determines whether the bot will strictly follow the RFC; currently +# this only affects what strings are considered to be nicks. If you're +# using a server or a network that requires you to message a nick such +# as services@this.network.server then you you should set this to False. +# +# Default value: False +### +supybot.protocols.irc.strictRfc: False + +### +# Determines what user modes the bot will request from the server when +# it first connects. Many people might choose +i; some networks allow +# +x, which indicates to the auth services on those networks that you +# should be given a fake host. +# +# Default value: +### +supybot.protocols.irc.umodes: + +### +# Determines what vhost the bot will bind to before connecting to the +# IRC server. +# +# Default value: +### +supybot.protocols.irc.vhost: + +### +# Determines how many old messages the bot will keep around in its +# history. Changing this variable will not take effect until the bot is +# restarted. +# +# Default value: 1000 +### +supybot.protocols.irc.maxHistoryLength: 1000 + +### +# A floating point number of seconds to throttle queued messages -- that +# is, messages will not be sent faster than once per throttleTime +# seconds. +# +# Default value: 1.0 +### +supybot.protocols.irc.throttleTime: 1.0 + +### +# Determines whether the bot will send PINGs to the server it's +# connected to in order to keep the connection alive and discover +# earlier when it breaks. Really, this option only exists for debugging +# purposes: you always should make it True unless you're testing some +# strange server issues. +# +# Default value: True +### +supybot.protocols.irc.ping: True + +### +# Determines the number of seconds between sending pings to the server, +# if pings are being sent to the server. +# +# Default value: 120 +### +supybot.protocols.irc.ping.interval: 120 + +### +# Determines whether the bot will refuse duplicate messages to be queued +# for delivery to the server. This is a safety mechanism put in place to +# prevent plugins from sending the same message multiple times; most of +# the time it doesn't matter, unless you're doing certain kinds of +# plugin hacking. +# +# Default value: False +### +supybot.protocols.irc.queuing.duplicates: False + +### +# Determines how many seconds must elapse between JOINs sent to the +# server. +# +# Default value: 0.0 +### +supybot.protocols.irc.queuing.rateLimit.join: 0.0 + +### +# Determines how many bytes the bot will 'peek' at when looking through +# a URL for a doctype or title or something similar. It'll give up after +# it reads this many bytes, even if it hasn't found what it was looking +# for. +# +# Default value: 4096 +### +supybot.protocols.http.peekSize: 4096 + +### +# Determines what proxy all HTTP requests should go through. The value +# should be of the form 'host:port'. +# +# Default value: +### +supybot.protocols.http.proxy: + +### +# Determines whether the bot will ignore unregistered users by default. +# Of course, that'll make it particularly hard for those users to +# register or identify with the bot, but that's your problem to solve. +# +# Default value: False +### +supybot.defaultIgnore: False + +### +# A string that is the external IP of the bot. If this is the empty +# string, the bot will attempt to find out its IP dynamically (though +# sometimes that doesn't work, hence this variable). +# +# Default value: +### +supybot.externalIP: + +### +# Determines what the default timeout for socket objects will be. This +# means that *all* sockets will timeout when this many seconds has gone +# by (unless otherwise modified by the author of the code that uses the +# sockets). +# +# Default value: 10 +### +supybot.defaultSocketTimeout: 10 + +### +# Determines what file the bot should write its PID (Process ID) to, so +# you can kill it more easily. If it's left unset (as is the default) +# then no PID file will be written. A restart is required for changes to +# this variable to take effect. +# +# Default value: +### +supybot.pidFile: + +### +# Determines whether the bot will automatically thread all commands. +# +# Default value: False +### +supybot.debug.threadAllCommands: False + +### +# Determines whether the bot will automatically flush all flushers +# *very* often. Useful for debugging when you don't know what's breaking +# or when, but think that it might be logged. +# +# Default value: False +### +supybot.debug.flushVeryOften: False + +### +# Determines what the bot's logging format will be. The relevant +# documentation on the available formattings is Python's documentation +# on its logging module. +# +# Default value: %(levelname)s %(asctime)s %(name)s %(message)s +### +supybot.log.format: %(levelname)s %(asctime)s %(name)s %(message)s + +### +# Determines what the minimum priority level logged to file will be. Do +# note that this value does not affect the level logged to stdout; for +# that, you should set the value of supybot.log.stdout.level. Valid +# values are DEBUG, INFO, WARNING, ERROR, and CRITICAL, in order of +# increasing priority. +# +# Default value: INFO +### +supybot.log.level: INFO + +### +# Determines the format string for timestamps in logfiles. Refer to the +# Python documentation for the time module to see what formats are +# accepted. If you set this variable to the empty string, times will be +# logged in a simple seconds-since-epoch format. +# +# Default value: %Y-%m-%dT%H:%M:%S +### +supybot.log.timestampFormat: %Y-%m-%dT%H:%M:%S + +### +# Determines whether the bot will log to stdout. +# +# Default value: True +### +supybot.log.stdout: True + +### +# Determines whether the bot's logs to stdout (if enabled) will be +# colorized with ANSI color. +# +# Default value: False +### +supybot.log.stdout.colorized: False + +### +# Determines whether the bot will wrap its logs when they're output to +# stdout. +# +# Default value: True +### +supybot.log.stdout.wrap: True + +### +# Determines what the bot's logging format will be. The relevant +# documentation on the available formattings is Python's documentation +# on its logging module. +# +# Default value: %(levelname)s %(asctime)s %(message)s +### +supybot.log.stdout.format: %(levelname)s %(asctime)s %(message)s + +### +# Determines what the minimum priority level logged will be. Valid +# values are DEBUG, INFO, WARNING, ERROR, and CRITICAL, in order of +# increasing priority. +# +# Default value: INFO +### +supybot.log.stdout.level: INFO + +### +# Determines whether the bot will separate plugin logs into their own +# individual logfiles. +# +# Default value: False +### +supybot.log.plugins.individualLogfiles: False + +### +# Determines what the bot's logging format will be. The relevant +# documentation on the available formattings is Python's documentation +# on its logging module. +# +# Default value: %(levelname)s %(asctime)s %(message)s +### +supybot.log.plugins.format: %(levelname)s %(asctime)s %(message)s + +### +# These are the capabilities that are given to everyone by default. If +# they are normal capabilities, then the user will have to have the +# appropriate anti-capability if you want to override these +# capabilities; if they are anti-capabilities, then the user will have +# to have the actual capability to override these capabilities. See +# docs/CAPABILITIES if you don't understand why these default to what +# they do. +# +# Default value: -owner -admin -trusted +### +supybot.capabilities: -owner -admin -trusted + +### +# Determines whether the bot by default will allow users to have a +# capability. If this is disabled, a user must explicitly have the +# capability for whatever command he wishes to run. +# +# Default value: True +### +supybot.capabilities.default: True