mirror of
https://github.com/Mikaela/Limnoria.git
synced 2025-01-25 19:44:13 +01:00
Move MegaHAL and SupySandbox to the Supybot-plugins repository
This commit is contained in:
parent
b7651b06a1
commit
424f5acebe
@ -1 +0,0 @@
|
|||||||
Insert a description of your plugin here, with any notes, etc. about using it.
|
|
@ -1,67 +0,0 @@
|
|||||||
###
|
|
||||||
# Copyright (c) 2010, Valentin Lorentz
|
|
||||||
# All rights reserved.
|
|
||||||
#
|
|
||||||
# Redistribution and use in source and binary forms, with or without
|
|
||||||
# modification, are permitted provided that the following conditions are met:
|
|
||||||
#
|
|
||||||
# * Redistributions of source code must retain the above copyright notice,
|
|
||||||
# this list of conditions, and the following disclaimer.
|
|
||||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
# this list of conditions, and the following disclaimer in the
|
|
||||||
# documentation and/or other materials provided with the distribution.
|
|
||||||
# * Neither the name of the author of this software nor the name of
|
|
||||||
# contributors to this software may be used to endorse or promote products
|
|
||||||
# derived from this software without specific prior written consent.
|
|
||||||
#
|
|
||||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
||||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
# POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
"""
|
|
||||||
This plugins provides a MegaHAL integration for Supybot.
|
|
||||||
MegaHAL must be installed ('apt-get install megahal' on Debian)
|
|
||||||
"""
|
|
||||||
|
|
||||||
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.Author('Valentin Lorentz', 'ProgVal',
|
|
||||||
'progval@gmail.com')
|
|
||||||
|
|
||||||
# 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/MegaHAL/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:
|
|
@ -1,72 +0,0 @@
|
|||||||
###
|
|
||||||
# Copyright (c) 2010, Valentin Lorentz
|
|
||||||
# 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
|
|
||||||
try:
|
|
||||||
from supybot.i18n import PluginInternationalization
|
|
||||||
from supybot.i18n import internationalizeDocstring
|
|
||||||
_ = PluginInternationalization('MegaHAL')
|
|
||||||
except:
|
|
||||||
_ = lambda x:x
|
|
||||||
internationalizeDocstring = lambda x:x
|
|
||||||
|
|
||||||
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('MegaHAL', True)
|
|
||||||
|
|
||||||
|
|
||||||
MegaHAL = conf.registerPlugin('MegaHAL')
|
|
||||||
# This is where your configuration variables (if any) should go. For example:
|
|
||||||
# conf.registerGlobalValue(MegaHAL, 'someConfigVariableName',
|
|
||||||
# registry.Boolean(False, """Help for someConfigVariableName."""))
|
|
||||||
|
|
||||||
conf.registerGroup(MegaHAL, 'learn')
|
|
||||||
conf.registerGlobalValue(MegaHAL.learn, 'commands',
|
|
||||||
registry.Boolean(False, _("""Determines whether the bot answers to messages
|
|
||||||
beginning by a non-alphanumeric char.""")))
|
|
||||||
conf.registerGroup(MegaHAL, 'answer')
|
|
||||||
conf.registerChannelValue(MegaHAL.answer, 'commands',
|
|
||||||
registry.Boolean(False, _("""Determines whether messages beginning by a
|
|
||||||
non-alphanumeric char are learned.""")))
|
|
||||||
conf.registerChannelValue(MegaHAL.answer, 'probability',
|
|
||||||
registry.Integer(10, _("""Determines the percent of messages the bot will
|
|
||||||
answer (zero is recommended if you have a tiny database).""")))
|
|
||||||
conf.registerChannelValue(MegaHAL.answer, 'probabilityWhenAddressed',
|
|
||||||
registry.Integer(100, _("""Determines the percent of messages adressed to
|
|
||||||
the bot the bot will answer.""")))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:
|
|
@ -1,155 +0,0 @@
|
|||||||
###
|
|
||||||
# Copyright (c) 2010, Valentin Lorentz
|
|
||||||
# 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 os
|
|
||||||
import sys
|
|
||||||
import random
|
|
||||||
import supybot.conf as conf
|
|
||||||
import supybot.utils as utils
|
|
||||||
from cStringIO import StringIO
|
|
||||||
from supybot.commands import *
|
|
||||||
import supybot.plugins as plugins
|
|
||||||
import supybot.ircutils as ircutils
|
|
||||||
import supybot.callbacks as callbacks
|
|
||||||
|
|
||||||
try:
|
|
||||||
import mh_python as megahal
|
|
||||||
except ImportError:
|
|
||||||
raise callbacks.Error, 'You need to have MegaHAL installed to use this ' \
|
|
||||||
'plugin. Download it at ' \
|
|
||||||
'<http://megahal.alioth.debian.org/>' \
|
|
||||||
'or with <apt-get install megahal>'
|
|
||||||
|
|
||||||
try:
|
|
||||||
from supybot.i18n import PluginInternationalization
|
|
||||||
from supybot.i18n import internationalizeDocstring
|
|
||||||
_ = PluginInternationalization('MegaHAL')
|
|
||||||
except:
|
|
||||||
# This are useless function that's allow to run the plugin on a bot
|
|
||||||
# without the i18n plugin
|
|
||||||
_ = lambda x:x
|
|
||||||
internationalizeDocstring = lambda x:x
|
|
||||||
|
|
||||||
class MegaHAL(callbacks.Plugin):
|
|
||||||
"""This plugins provides a MegaHAL integration for Supybot.
|
|
||||||
MegaHAL must be installed ('apt-get install megahal' on Debian)"""
|
|
||||||
callAfter = ['MoobotFactoids', 'Factoids', 'Infobot']
|
|
||||||
callBefore = ['Dunno']
|
|
||||||
|
|
||||||
def __init__(self, irc):
|
|
||||||
# Call Supybot's scripts
|
|
||||||
self.__parent = super(MegaHAL, self)
|
|
||||||
self.__parent.__init__(irc)
|
|
||||||
|
|
||||||
# Save state
|
|
||||||
saved = (sys.stdout, os.getcwd())
|
|
||||||
|
|
||||||
# Create proxy for MegaHAL
|
|
||||||
os.chdir(conf.supybot.directories.data())
|
|
||||||
sys.stdout = StringIO()
|
|
||||||
|
|
||||||
# Initialize MegaHAL
|
|
||||||
megahal.initbrain()
|
|
||||||
|
|
||||||
# Restore state
|
|
||||||
sys.stdout, cwd = saved
|
|
||||||
os.chdir(cwd)
|
|
||||||
|
|
||||||
random.seed()
|
|
||||||
|
|
||||||
_dontKnow = [
|
|
||||||
'I don\'t know enough to answer you yet!',
|
|
||||||
'I am utterly speechless!',
|
|
||||||
'I forgot what I was going to say!'
|
|
||||||
]
|
|
||||||
_translations = {
|
|
||||||
'I don\'t know enough to answer you yet!':
|
|
||||||
_('I don\'t know enough to answer you yet!'),
|
|
||||||
'I am utterly speechless!':
|
|
||||||
_('I am utterly speechless!'),
|
|
||||||
'I forgot what I was going to say!':
|
|
||||||
_('I forgot what I was going to say!'),
|
|
||||||
}
|
|
||||||
|
|
||||||
def _response(self, msg, prb, reply):
|
|
||||||
if random.randint(0, 100) < prb:
|
|
||||||
response = megahal.doreply(msg)
|
|
||||||
if self._translations.has_key(response):
|
|
||||||
response = self._translations[response]
|
|
||||||
reply(response, prefixNick=False)
|
|
||||||
else:
|
|
||||||
megahal.learn(msg)
|
|
||||||
|
|
||||||
def doPrivmsg(self, irc, msg):
|
|
||||||
if not msg.args[0].startswith('#'): # It is a private message
|
|
||||||
return
|
|
||||||
message = msg.args[1]
|
|
||||||
|
|
||||||
if message.startswith(irc.nick) or re.match('\W.*', message):
|
|
||||||
# Managed by invalidCommand
|
|
||||||
return
|
|
||||||
|
|
||||||
probability = self.registryValue('answer.probability', msg.args[0])
|
|
||||||
self._response(message, probability, irc.reply)
|
|
||||||
|
|
||||||
def invalidCommand(self, irc, msg, tokens):
|
|
||||||
if not msg.args[0].startswith('#'): # It is a private message
|
|
||||||
# Actually, we would like to answer, but :
|
|
||||||
# 1) It may be a mistyped identify command (or whatever)
|
|
||||||
# 2) MegaHAL can't reply without learning
|
|
||||||
return
|
|
||||||
message = msg.args[1]
|
|
||||||
usedToStartWithNick = False
|
|
||||||
if message.startswith(message):
|
|
||||||
parsed = re.match('(.+ |\W)?(?P<message>\w.*)', message)
|
|
||||||
message = parsed.group('message')
|
|
||||||
usedToStartWithNick = True
|
|
||||||
if self.registryValue('answer.commands') or usedToStartWithNick:
|
|
||||||
print msg.args[0]
|
|
||||||
self._response(message,
|
|
||||||
self.registryValue('answer.probabilityWhenAddressed',
|
|
||||||
msg.args[0]),
|
|
||||||
irc.reply)
|
|
||||||
elif self.registryValue('learn.commands'):
|
|
||||||
megahal.learn(message)
|
|
||||||
|
|
||||||
@internationalizeDocstring
|
|
||||||
def cleanup(self, irc, msg, args):
|
|
||||||
"""takes no argument
|
|
||||||
|
|
||||||
Saves MegaHAL brain to disk."""
|
|
||||||
megahal.cleanup()
|
|
||||||
irc.replySuccess()
|
|
||||||
|
|
||||||
Class = MegaHAL
|
|
||||||
|
|
||||||
|
|
||||||
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:
|
|
@ -1,43 +0,0 @@
|
|||||||
###
|
|
||||||
# Copyright (c) 2010, Valentin Lorentz
|
|
||||||
# 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 MegaHALTestCase(PluginTestCase):
|
|
||||||
plugins = ('MegaHAL',)
|
|
||||||
|
|
||||||
def testCleanup(self):
|
|
||||||
self.assertNotError('cleanup')
|
|
||||||
|
|
||||||
def testAnswer(self):
|
|
||||||
self.assertNotRegexp('foo', '.*not a valid.*')
|
|
||||||
|
|
||||||
|
|
||||||
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:
|
|
@ -1 +0,0 @@
|
|||||||
Insert a description of your plugin here, with any notes, etc. about using it.
|
|
@ -1,68 +0,0 @@
|
|||||||
# -*- coding: utf8 -*-
|
|
||||||
###
|
|
||||||
# Copyright (c) 2010, Valentin Lorentz
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
"""
|
|
||||||
Ce plugin est un portage du robot IRC Fschfsch, servant à fournir un accès
|
|
||||||
à la pysandbox sur IRC.
|
|
||||||
"""
|
|
||||||
|
|
||||||
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__ = "0.1"
|
|
||||||
|
|
||||||
# XXX Replace this with an appropriate author or supybot.Author instance.
|
|
||||||
__author__ = supybot.Author('Valentin Lorentz', 'ProgVal',
|
|
||||||
'progval@gmail.com')
|
|
||||||
|
|
||||||
# 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-fr.tk/SupySandbox'
|
|
||||||
|
|
||||||
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:
|
|
@ -1,50 +0,0 @@
|
|||||||
# -*- coding: utf8 -*-
|
|
||||||
###
|
|
||||||
# Copyright (c) 2010, Valentin Lorentz
|
|
||||||
# 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('SupySandbox', True)
|
|
||||||
|
|
||||||
|
|
||||||
PySandbox = conf.registerPlugin('SupySandbox')
|
|
||||||
# This is where your configuration variables (if any) should go. For example:
|
|
||||||
# conf.registerGlobalValue(PySandbox, 'someConfigVariableName',
|
|
||||||
# registry.Boolean(False, """Help for someConfigVariableName."""))
|
|
||||||
|
|
||||||
|
|
||||||
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:
|
|
@ -1 +0,0 @@
|
|||||||
# Stub so local is a module, used for third-party modules
|
|
@ -1,279 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# this file is under the WTFPLv2 [http://sam.zoy.org/wtfpl]
|
|
||||||
# v1: 2010/05/23
|
|
||||||
# Author: Tila
|
|
||||||
|
|
||||||
# You need a configuration file: ~/.fschfsch.py. Config example:
|
|
||||||
# ---
|
|
||||||
# host = 'irc.freenode.net'
|
|
||||||
# port = 7000
|
|
||||||
# ssl = True
|
|
||||||
# nickname = 'botnickname'
|
|
||||||
# password = 'secret'
|
|
||||||
# channels = ['##fschfsch', '#channel2', '#channel3']
|
|
||||||
# texts = {'help': 'I am fschfsch, a robot snake that evals python code',
|
|
||||||
# 'sandbox': "I am powered by setrlimit and pysandbox [http://github.com/haypo/pysandbox], I don't fear you"}
|
|
||||||
# ---
|
|
||||||
|
|
||||||
'''
|
|
||||||
fschfsch is a Python-evaluating bot. fschfsch is pronounced "fssshh! fssshh!".
|
|
||||||
'''
|
|
||||||
|
|
||||||
IN_MAXLEN = 300 # bytes
|
|
||||||
OUT_MAXLEN = 300 # bytes
|
|
||||||
TIMEOUT = 3 # seconds
|
|
||||||
|
|
||||||
EVAL_MAXTIMESECONDS = TIMEOUT
|
|
||||||
EVAL_MAXMEMORYBYTES = 10 * 1024 * 1024 # 10 MiB
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
|
||||||
import sandbox as S
|
|
||||||
except ImportError:
|
|
||||||
print 'You need pysandbox in order to run fschfsch [http://github.com/haypo/pysandbox].'
|
|
||||||
raise
|
|
||||||
try:
|
|
||||||
import twisted
|
|
||||||
except ImportError:
|
|
||||||
print 'You need twisted in order to run fschfsch.'
|
|
||||||
raise
|
|
||||||
from twisted.internet.protocol import ReconnectingClientFactory
|
|
||||||
from twisted.internet import ssl, reactor
|
|
||||||
from twisted.words.im.ircsupport import IRCProto
|
|
||||||
from twisted.words.protocols.irc import IRCClient
|
|
||||||
# other imports
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
import resource as R
|
|
||||||
import select
|
|
||||||
import signal
|
|
||||||
import time
|
|
||||||
import threading
|
|
||||||
import random
|
|
||||||
|
|
||||||
def createSandboxConfig():
|
|
||||||
cfg = S.SandboxConfig(
|
|
||||||
'stdout',
|
|
||||||
'stderr',
|
|
||||||
'regex',
|
|
||||||
'unicodedata', # flow wants u'\{ATOM SYMBOL}' :-)
|
|
||||||
'future',
|
|
||||||
'code',
|
|
||||||
'time',
|
|
||||||
'datetime',
|
|
||||||
'math',
|
|
||||||
'itertools',
|
|
||||||
'random',
|
|
||||||
'encodings',
|
|
||||||
)
|
|
||||||
cfg.allowModule('sys',
|
|
||||||
'version', 'hexversion', 'version_info')
|
|
||||||
return cfg
|
|
||||||
|
|
||||||
def _evalPython(line, locals):
|
|
||||||
locals = dict(locals)
|
|
||||||
try:
|
|
||||||
if "\n" in line:
|
|
||||||
raise SyntaxError()
|
|
||||||
code = compile(line, "<irc>", "single")
|
|
||||||
except SyntaxError:
|
|
||||||
code = compile(line, "<irc>", "exec")
|
|
||||||
exec code in locals
|
|
||||||
|
|
||||||
def evalPython(line, locals=None):
|
|
||||||
sandbox = S.Sandbox(config=createSandboxConfig())
|
|
||||||
|
|
||||||
if locals is not None:
|
|
||||||
locals = dict(locals)
|
|
||||||
else:
|
|
||||||
locals = dict()
|
|
||||||
try:
|
|
||||||
sandbox.call(_evalPython, line, locals)
|
|
||||||
except BaseException, e:
|
|
||||||
print 'Error: [%s] %s' % (e.__class__.__name__, str(e))
|
|
||||||
except:
|
|
||||||
print 'Error: <unknown exception>'
|
|
||||||
sys.stdout.flush()
|
|
||||||
|
|
||||||
def childProcess(line, w, locals):
|
|
||||||
# reseed after a fork to avoid generating the same sequence for each child
|
|
||||||
random.seed()
|
|
||||||
|
|
||||||
sys.stdout = sys.stderr = os.fdopen(w, 'w')
|
|
||||||
|
|
||||||
R.setrlimit(R.RLIMIT_CPU, (EVAL_MAXTIMESECONDS, EVAL_MAXTIMESECONDS))
|
|
||||||
R.setrlimit(R.RLIMIT_AS, (EVAL_MAXMEMORYBYTES, EVAL_MAXMEMORYBYTES))
|
|
||||||
R.setrlimit(R.RLIMIT_NPROC, (0, 0)) # 0 forks
|
|
||||||
|
|
||||||
evalPython(line, locals)
|
|
||||||
|
|
||||||
def handleChild(childpid, r):
|
|
||||||
txt = ''
|
|
||||||
if any(select.select([r], [], [], TIMEOUT)):
|
|
||||||
txt = os.read(r, OUT_MAXLEN + 1)
|
|
||||||
os.close(r)
|
|
||||||
if OUT_MAXLEN < len(txt):
|
|
||||||
txt = txt[:OUT_MAXLEN] + '...'
|
|
||||||
|
|
||||||
n = 0
|
|
||||||
while n < 6:
|
|
||||||
pid, status = os.waitpid(childpid, os.WNOHANG)
|
|
||||||
if pid:
|
|
||||||
break
|
|
||||||
time.sleep(.5)
|
|
||||||
n += 1
|
|
||||||
if not pid:
|
|
||||||
os.kill(childpid, signal.SIGKILL)
|
|
||||||
return 'Timeout'
|
|
||||||
elif os.WIFEXITED(status):
|
|
||||||
txts = txt.rstrip().split('\n')
|
|
||||||
if len(txts) > 1:
|
|
||||||
txt = txts[0].rstrip() + ' [+ %d line(s)]' % (len(txts) - 1)
|
|
||||||
else:
|
|
||||||
txt = txts[0].rstrip()
|
|
||||||
return 'Output: ' + txt
|
|
||||||
elif os.WIFSIGNALED(status):
|
|
||||||
return 'Killed'
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class EvalJob(threading.Thread):
|
|
||||||
def __init__(self, line, irc, channel):
|
|
||||||
super(EvalJob, self).__init__()
|
|
||||||
self.line = line
|
|
||||||
self.irc = irc
|
|
||||||
self.channel = channel
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
output = self.handle_line(self.line)
|
|
||||||
reactor.callFromThread(self.irc.say, self.channel, output)
|
|
||||||
self.irc.executionLock.release()
|
|
||||||
|
|
||||||
def handle_line(self, line):
|
|
||||||
if IN_MAXLEN < len(line):
|
|
||||||
return '(command is too long: %s bytes, the maximum is %s)' % (len(line), IN_MAXLEN)
|
|
||||||
|
|
||||||
print("Process %s" % repr(line))
|
|
||||||
r, w = os.pipe()
|
|
||||||
childpid = os.fork()
|
|
||||||
if not childpid:
|
|
||||||
os.close(r)
|
|
||||||
childProcess(line, w, self.irc.factory.morevars)
|
|
||||||
os._exit(0)
|
|
||||||
else:
|
|
||||||
os.close(w)
|
|
||||||
result = handleChild(childpid, r)
|
|
||||||
print("=> %s" % repr(result))
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class EvalBot(IRCClient):
|
|
||||||
versionName = 'fschfsch'
|
|
||||||
versionNum = '0.1'
|
|
||||||
|
|
||||||
#~ def __init__(self, *a, **k):
|
|
||||||
def connectionMade(self):
|
|
||||||
self.nickname = self.factory.nick
|
|
||||||
self.password = self.factory.password
|
|
||||||
self.talkre = re.compile('^%s[>:,] (.*)$' % self.nickname)
|
|
||||||
|
|
||||||
self.executionLock = threading.Semaphore()
|
|
||||||
self.pingSelfId = None
|
|
||||||
|
|
||||||
IRCClient.connectionMade(self)
|
|
||||||
|
|
||||||
def signedOn(self):
|
|
||||||
self.pingSelfId = reactor.callLater(180, self.pingSelf)
|
|
||||||
for chan in self.factory.channels:
|
|
||||||
self.join(chan)
|
|
||||||
|
|
||||||
def pingSelf(self):
|
|
||||||
# used to avoid some timeouts where fschfsch does not reconnect
|
|
||||||
self.ping(self.nickname)
|
|
||||||
self.pingSelfId = reactor.callLater(180, self.pingSelf)
|
|
||||||
|
|
||||||
def privmsg(self, user, channel, message):
|
|
||||||
if self.pingSelfId is not None:
|
|
||||||
self.pingSelfId.reset(180)
|
|
||||||
if user.startswith('haypo') and message.startswith('exit'):
|
|
||||||
os._exit(0)
|
|
||||||
if not channel:
|
|
||||||
return
|
|
||||||
if not message.startswith(self.nickname):
|
|
||||||
return
|
|
||||||
if not self.talkre.match(message):
|
|
||||||
return
|
|
||||||
if not self.executionLock.acquire(blocking=False):
|
|
||||||
return
|
|
||||||
|
|
||||||
pyline = self.talkre.match(message).group(1)
|
|
||||||
pyline = pyline.replace(' $$ ', '\n')
|
|
||||||
|
|
||||||
self.handleThread = EvalJob(pyline, self, channel)
|
|
||||||
self.handleThread.start()
|
|
||||||
|
|
||||||
|
|
||||||
class MyFactory(ReconnectingClientFactory):
|
|
||||||
def __init__(self, **kw):
|
|
||||||
for k in kw:
|
|
||||||
if k in ('nick', 'password', 'channels', 'morevars'):
|
|
||||||
setattr(self, k, kw[k])
|
|
||||||
protocol = EvalBot
|
|
||||||
|
|
||||||
def check_output(expr, expected, locals=None):
|
|
||||||
from cStringIO import StringIO
|
|
||||||
original_stdout = sys.stdout
|
|
||||||
try:
|
|
||||||
output = StringIO()
|
|
||||||
sys.stdout = output
|
|
||||||
evalPython(expr, locals)
|
|
||||||
stdout = output.getvalue()
|
|
||||||
assert stdout == expected, "%r != %r" % (stdout, expected)
|
|
||||||
finally:
|
|
||||||
sys.stdout = original_stdout
|
|
||||||
|
|
||||||
def runTests():
|
|
||||||
# single
|
|
||||||
check_output('1+1', '2\n')
|
|
||||||
check_output('1; 2', '1\n2\n')
|
|
||||||
check_output(
|
|
||||||
# written in a single line
|
|
||||||
"prime=lambda n,i=2:"
|
|
||||||
"False if n%i==0 else prime(n,i+1) if i*i<n else True; "
|
|
||||||
"prime(17)",
|
|
||||||
"True\n")
|
|
||||||
|
|
||||||
# exec
|
|
||||||
check_output('def f(): print("hello")\nf()', 'hello\n')
|
|
||||||
check_output('print 1\nprint 2', '1\n2\n')
|
|
||||||
check_output('text', "'abc'\n", {'text': 'abc'})
|
|
||||||
return True
|
|
||||||
|
|
||||||
def main():
|
|
||||||
if len(sys.argv) == 2 and sys.argv[1] == 'tests':
|
|
||||||
ok = runTests()
|
|
||||||
if ok:
|
|
||||||
print("no failure")
|
|
||||||
else:
|
|
||||||
print("failure!")
|
|
||||||
sys.exit(int(not ok))
|
|
||||||
elif len(sys.argv) != 1:
|
|
||||||
print 'usage: %s -- run the bot' % sys.argv[0]
|
|
||||||
print ' or: %s tests -- run self tests' % sys.argv[0]
|
|
||||||
print
|
|
||||||
print 'Edit ~/.fschfschrc.py first'
|
|
||||||
sys.exit(4)
|
|
||||||
|
|
||||||
conf = {}
|
|
||||||
execfile(os.path.expanduser('~/.fschfschrc.py'), conf)
|
|
||||||
factory = MyFactory(nick=conf['nickname'], password=conf.get('password', None), channels=conf.get('channels', []), morevars=conf.get('texts', {}))
|
|
||||||
if conf.get('ssl', 0):
|
|
||||||
reactor.connectSSL(conf['host'], conf['port'], factory, ssl.ClientContextFactory())
|
|
||||||
else:
|
|
||||||
reactor.connectTCP(conf['host'], conf['port'], factory)
|
|
||||||
reactor.run()
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
@ -1,199 +0,0 @@
|
|||||||
###
|
|
||||||
# Copyright (c) 2010, Valentin Lorentz
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
# pysandbox were originally writen by haypo (under the BSD license),
|
|
||||||
# and fschfsch by Tila (under the WTFPL license).
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
IN_MAXLEN = 1000 # bytes
|
|
||||||
OUT_MAXLEN = 1000 # bytes
|
|
||||||
TIMEOUT = 3 # seconds
|
|
||||||
|
|
||||||
EVAL_MAXTIMESECONDS = TIMEOUT
|
|
||||||
EVAL_MAXMEMORYBYTES = 75 * 1024 * 1024 # 10 MiB
|
|
||||||
|
|
||||||
try:
|
|
||||||
import sandbox as S
|
|
||||||
except ImportError:
|
|
||||||
print 'You need pysandbox in order to run fschfsch ' + \
|
|
||||||
'[http://github.com/haypo/pysandbox].'
|
|
||||||
raise
|
|
||||||
import re
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
import random
|
|
||||||
import select
|
|
||||||
import resource as R
|
|
||||||
import supybot.utils as utils
|
|
||||||
from supybot.commands import *
|
|
||||||
import supybot.plugins as plugins
|
|
||||||
import supybot.ircutils as ircutils
|
|
||||||
import supybot.callbacks as callbacks
|
|
||||||
from cStringIO import StringIO
|
|
||||||
|
|
||||||
|
|
||||||
def createSandboxConfig():
|
|
||||||
cfg = S.SandboxConfig(
|
|
||||||
'stdout',
|
|
||||||
'stderr',
|
|
||||||
'regex',
|
|
||||||
'unicodedata', # flow wants u'\{ATOM SYMBOL}' :-)
|
|
||||||
'future',
|
|
||||||
'code',
|
|
||||||
'time',
|
|
||||||
'datetime',
|
|
||||||
'math',
|
|
||||||
'itertools',
|
|
||||||
'random',
|
|
||||||
'encodings',
|
|
||||||
)
|
|
||||||
cfg.allowModule('sys',
|
|
||||||
'version', 'hexversion', 'version_info')
|
|
||||||
return cfg
|
|
||||||
|
|
||||||
def _evalPython(line, locals):
|
|
||||||
locals = dict(locals)
|
|
||||||
try:
|
|
||||||
if "\n" in line:
|
|
||||||
raise SyntaxError()
|
|
||||||
code = compile(line, "<irc>", "single")
|
|
||||||
except SyntaxError:
|
|
||||||
code = compile(line, "<irc>", "exec")
|
|
||||||
exec code in locals
|
|
||||||
|
|
||||||
def evalPython(line, locals=None):
|
|
||||||
sandbox = S.Sandbox(config=createSandboxConfig())
|
|
||||||
|
|
||||||
if locals is not None:
|
|
||||||
locals = dict(locals)
|
|
||||||
else:
|
|
||||||
locals = dict()
|
|
||||||
try:
|
|
||||||
sandbox.call(_evalPython, line, locals)
|
|
||||||
except BaseException, e:
|
|
||||||
print 'Error: [%s] %s' % (e.__class__.__name__, str(e))
|
|
||||||
except:
|
|
||||||
print 'Error: <unknown exception>'
|
|
||||||
sys.stdout.flush()
|
|
||||||
|
|
||||||
def check_output(expr, expected, locals=None):
|
|
||||||
from cStringIO import StringIO
|
|
||||||
original_stdout = sys.stdout
|
|
||||||
try:
|
|
||||||
output = StringIO()
|
|
||||||
sys.stdout = output
|
|
||||||
evalPython(expr, locals)
|
|
||||||
stdout = output.getvalue()
|
|
||||||
assert stdout == expected, "%r != %r" % (stdout, expected)
|
|
||||||
finally:
|
|
||||||
sys.stdout = original_stdout
|
|
||||||
|
|
||||||
def runTests():
|
|
||||||
# single
|
|
||||||
check_output('1+1', '2\n')
|
|
||||||
check_output('1; 2', '1\n2\n')
|
|
||||||
check_output(
|
|
||||||
# written in a single line
|
|
||||||
"prime=lambda n,i=2:"
|
|
||||||
"False if n%i==0 else prime(n,i+1) if i*i<n else True; "
|
|
||||||
"prime(17)",
|
|
||||||
"True\n")
|
|
||||||
|
|
||||||
# exec
|
|
||||||
check_output('def f(): print("hello")\nf()', 'hello\n')
|
|
||||||
check_output('print 1\nprint 2', '1\n2\n')
|
|
||||||
check_output('text', "'abc'\n", {'text': 'abc'})
|
|
||||||
return True
|
|
||||||
|
|
||||||
def childProcess(line, w, locals):
|
|
||||||
# reseed after a fork to avoid generating the same sequence for each child
|
|
||||||
random.seed()
|
|
||||||
|
|
||||||
sys.stdout = sys.stderr = os.fdopen(w, 'w')
|
|
||||||
|
|
||||||
R.setrlimit(R.RLIMIT_CPU, (EVAL_MAXTIMESECONDS, EVAL_MAXTIMESECONDS))
|
|
||||||
R.setrlimit(R.RLIMIT_AS, (EVAL_MAXMEMORYBYTES, EVAL_MAXMEMORYBYTES))
|
|
||||||
R.setrlimit(R.RLIMIT_NPROC, (0, 0)) # 0 forks
|
|
||||||
|
|
||||||
evalPython(line, locals)
|
|
||||||
|
|
||||||
def handleChild(childpid, r):
|
|
||||||
txt = ''
|
|
||||||
if __import__("__builtin__").any(select.select([r], [], [], TIMEOUT)):
|
|
||||||
txt = os.read(r, OUT_MAXLEN + 1)
|
|
||||||
os.close(r)
|
|
||||||
|
|
||||||
n = 0
|
|
||||||
while n < 6:
|
|
||||||
pid, status = os.waitpid(childpid, os.WNOHANG)
|
|
||||||
if pid:
|
|
||||||
break
|
|
||||||
time.sleep(.5)
|
|
||||||
n += 1
|
|
||||||
if not pid:
|
|
||||||
os.kill(childpid, signal.SIGKILL)
|
|
||||||
return 'Timeout'
|
|
||||||
elif os.WIFEXITED(status):
|
|
||||||
return txt.rstrip()
|
|
||||||
elif os.WIFSIGNALED(status):
|
|
||||||
return 'Killed'
|
|
||||||
|
|
||||||
def handle_line(line):
|
|
||||||
r, w = os.pipe()
|
|
||||||
childpid = os.fork()
|
|
||||||
if not childpid:
|
|
||||||
os.close(r)
|
|
||||||
childProcess(line, w, {})
|
|
||||||
os._exit(0)
|
|
||||||
else:
|
|
||||||
os.close(w)
|
|
||||||
result = handleChild(childpid, r)
|
|
||||||
return result
|
|
||||||
|
|
||||||
class SupySandbox(callbacks.Plugin):
|
|
||||||
"""Add the help for "@plugin help SupySandbox" here
|
|
||||||
This should describe *how* to use this plugin."""
|
|
||||||
|
|
||||||
_parser = re.compile(r'(.?sandbox)? (?P<code>.*)')
|
|
||||||
def sandbox(self, irc, msg, args):
|
|
||||||
"""<code>
|
|
||||||
|
|
||||||
Runs Python code safely thanks to pysandbox"""
|
|
||||||
code = self._parser.match(msg.args[1]).group('code')
|
|
||||||
irc.reply(handle_line(code.replace(' $$ ', '\n')))
|
|
||||||
|
|
||||||
def runtests(self, irc, msg, args):
|
|
||||||
irc.reply(runTests())
|
|
||||||
|
|
||||||
|
|
||||||
Class = SupySandbox
|
|
||||||
|
|
||||||
|
|
||||||
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:
|
|
@ -1,56 +0,0 @@
|
|||||||
# -*- coding: utf8 -*-
|
|
||||||
###
|
|
||||||
# Copyright (c) 2010, Valentin Lorentz
|
|
||||||
# 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 SupySandboxTestCase(PluginTestCase):
|
|
||||||
plugins = ('SupySandbox',)
|
|
||||||
|
|
||||||
def testFschfschTestcase(self):
|
|
||||||
self.assertResponse('runtests', 'True')
|
|
||||||
|
|
||||||
def testCodeIsSuccessfullyRunned(self):
|
|
||||||
self.assertResponse('sandbox 1+1', "2")
|
|
||||||
self.assertResponse('sandbox print 1+1', "2")
|
|
||||||
self.assertResponse('sandbox print \'toto\'', "toto")
|
|
||||||
|
|
||||||
def testMultine(self):
|
|
||||||
self.assertResponse('sandbox print 1; print 2', "'1\\n2'")
|
|
||||||
self.assertResponse('sandbox print 1 $$ print 2', "'1\\n2'")
|
|
||||||
self.assertResponse('sandbox toto=True $$ while toto: $$ print "foo"'
|
|
||||||
' $$ toto=False', "foo")
|
|
||||||
|
|
||||||
def testProtections(self):
|
|
||||||
#self.assertResponse('sandbox while True: print 1', "Timeout")
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:
|
|
Loading…
Reference in New Issue
Block a user