Ali Afshar avatar Ali Afshar committed 3b59a14

moved the actual plugin to a sub-directory

Comments (0)

Files changed (12)

ExternalControl/README.txt

+
+External Control
+
+Version: 1.0

ExternalControl/__init__.py

+###
+# Copyright (c) 2007, Ali Afshar
+# 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.
+
+###
+
+"""
+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/ExternalControl/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:

ExternalControl/config.py

+###
+# Copyright (c) 2007, Ali Afshar
+# 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('ExternalControl', True)
+
+
+ExternalControl = conf.registerPlugin('ExternalControl')
+# This is where your configuration variables (if any) should go.  For example:
+# conf.registerGlobalValue(ExternalControl, 'someConfigVariableName',
+#     registry.Boolean(False, """Help for someConfigVariableName."""))
+
+conf.registerGlobalValue(ExternalControl, 'port',
+    registry.Integer(7766,
+    """The port that the external control server
+    should wait for requests on."""))
+
+
+# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:

ExternalControl/plugin.py

+###
+# Copyright (c) 2007, Ali Afshar
+# 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 threading, xmlrpclib, SimpleXMLRPCServer
+
+
+import supybot.world as world
+import supybot.utils as utils
+from supybot.commands import *
+import supybot.plugins as plugins
+import supybot.ircutils as ircutils
+import supybot.ircmsgs as ircmsgs
+import supybot.callbacks as callbacks
+
+
+HOST = 'localhost'
+
+
+class StoppableRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer):
+
+    stopped = False
+    allow_reuse_address = True
+
+    def __init__(self, *args, **kw):
+        SimpleXMLRPCServer.SimpleXMLRPCServer.__init__(self, *args, **kw)
+        self.register_function(lambda: 'OK', 'ping')
+
+    def serve_forever(self):
+        while not self.stopped:
+            self.handle_request()
+
+    def force_stop(self):
+        self.server_close()
+        self.stopped = True
+        self.create_dummy_request()
+        
+    def create_dummy_request(self):
+        server = xmlrpclib.Server('http://%s:%s' % self.server_address)
+        server.ping()
+
+
+
+
+class ControlInstance(object):
+
+    def privmsg(self, network, personorchannel, message):
+        target_irc, target = self._get_irc_and_target(network, personorchannel)
+        msg = ircmsgs.privmsg(target, message)
+        target_irc.sendMsg(msg)
+        return 'OK'
+
+    def notice(self, network, personorchannel, message):
+        target_irc, target = self._get_irc_and_target(network, personorchannel)
+        msg = ircmsgs.notice(target, message)
+        target_irc.sendMsg(msg)
+        return 'OK'
+
+    def command(self, network, personorchannel, cmd, notice=False):
+        target_irc, target = self._get_irc_and_target(network, personorchannel)
+        msg = ircmsgs.privmsg(target_irc.nick, cmd, prefix='ec!ec@ec')
+        msg.tag('externalcontroller', (target_irc, target, notice))
+        target_irc.feedMsg(msg)
+        return 'OK'
+
+    def _get_irc(self, network):
+        for irc in world.ircs:
+            if irc.network == network:
+                return irc
+
+    def _get_person_or_channel(self, irc, personorchannel):
+        if personorchannel.startswith('#'):
+            for channel in irc.state.channels:
+                if channel == personorchannel:
+                    return channel
+        else:
+            return personorchannel
+
+    def _get_irc_and_target(self, network, personorchannel):
+        target_irc = self._get_irc(network)
+        if target_irc is None:
+            raise Exception('Not on Network: %s' % network)
+        target = self._get_person_or_channel(target_irc, personorchannel)
+        if target is None:
+            raise Exception('Not on Channel: %s' % personorchannel)
+        return target_irc, target
+
+
+
+
+class ExternalControl(callbacks.Plugin):
+    """Add the help for "@plugin help ExternalControl" here
+    This should describe *how* to use this plugin."""
+    threaded = True
+
+    def __init__(self, irc):
+        callbacks.Plugin.__init__(self, irc)
+        self._start_server_in_thread()
+
+    def _start_server_in_thread(self):
+        t = threading.Thread(
+            target = self._start_server
+        )
+        t.start()
+
+    def _start_server(self):
+        self.server = StoppableRPCServer((HOST, self.registryValue('port')))
+        self.server.register_instance(ControlInstance())
+        self.server.serve_forever()
+
+    def die(self):
+        self.server.force_stop()
+
+    def outFilter(self, irc, msg):
+        if msg.inReplyTo:
+            if msg.inReplyTo.externalcontroller:
+                target_irc, target, notice = msg.inReplyTo.externalcontroller
+                self._reply_command(target_irc, target, msg, notice)
+                return None
+            else:
+                return msg
+        else:
+            return msg
+
+    def _reply_command(self, target_irc, target, msg, notice):
+        if notice:
+            factory = ircmsgs.notice
+        else:
+            factory = ircmsgs.privmsg
+        reply_msg = factory(target, msg.args[1])
+        target_irc.sendMsg(reply_msg)
+                
+        
+
+
+Class = ExternalControl
+
+
+# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:

ExternalControl/supybot-external-control

+#! /usr/bin/env python
+
+###
+# Copyright (c) 2007, Ali Afshar
+# 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 sys, xmlrpclib, optparse
+
+
+def rpc_command(port, name, *args):
+    server = xmlrpclib.Server('http://localhost:%s' % port)
+    command = getattr(server, name)
+    try:
+        print 'Success: %s' % command(*args)
+    except xmlrpclib.Fault, e:
+        print 'Error: %s' % e.faultString.split(':', 1)[1]
+
+
+def main(argv=sys.argv):
+    usage = 'usage: %prog [-i] [-d] -n <network> -c <channel> [-t <text> | -s]'
+    parser = optparse.OptionParser(usage=usage)
+    parser.add_option('-p', '--port', dest='port', type='int',
+        help='The port to connect to the controller',
+        default = 7766)
+    parser.add_option('-n', '--network', dest='network',
+        help='Network to send the message to.')
+    parser.add_option('-c', '--channel', dest='channel',
+        help='Channel or nick to send the message to.')
+    parser.add_option('-i', '--notice', dest='notice', action='store_true',
+        default=False,
+        help='Whether the reply will be a notice')
+    parser.add_option('-d', '--command', dest='command', action='store_true',
+        default=False,
+        help='Whether the text to send should be evaluated as a command')
+    parser.add_option('-t', '--text', dest='text',
+        help='The text to send')
+    parser.add_option('-s', '--stdin', dest='stdin',
+        default=False, action='store_true',
+        help='Whether text should be read from stdin')
+    opts, args = parser.parse_args(argv)
+    if not (opts.network and opts.channel and (opts.text or opts.stdin)):
+        parser.error('A network and channel and (text or stdin) must me specified.\n'
+                     'Run with --help for a list of options.')
+
+    if opts.stdin:
+        text = sys.stdin.read().replace('\n', ' ').replace('\r', ' ')
+    else:
+        text = opts.text
+
+    args = [opts.network, opts.channel, text]
+    if opts.command:
+        command = 'command'
+        if opts.notice:
+            args.append(True)
+    elif opts.notice:
+        command = 'notice'
+    else:
+        command = 'privmsg'
+    rpc_command(opts.port, command, *args)
+
+    
+if __name__ == '__main__':
+    main()
+

ExternalControl/test.py

+###
+# Copyright (c) 2007, Ali Afshar
+# 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 ExternalControlTestCase(PluginTestCase):
+    plugins = ('ExternalControl',)
+
+
+# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:

README.txt

-
-External Control
-
-Version: 1.0

__init__.py

-###
-# Copyright (c) 2007, Ali Afshar
-# 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.
-
-###
-
-"""
-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/ExternalControl/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:

config.py

-###
-# Copyright (c) 2007, Ali Afshar
-# 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('ExternalControl', True)
-
-
-ExternalControl = conf.registerPlugin('ExternalControl')
-# This is where your configuration variables (if any) should go.  For example:
-# conf.registerGlobalValue(ExternalControl, 'someConfigVariableName',
-#     registry.Boolean(False, """Help for someConfigVariableName."""))
-
-conf.registerGlobalValue(ExternalControl, 'port',
-    registry.Integer(7766,
-    """The port that the external control server
-    should wait for requests on."""))
-
-
-# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:

plugin.py

-###
-# Copyright (c) 2007, Ali Afshar
-# 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 threading, xmlrpclib, SimpleXMLRPCServer
-
-
-import supybot.world as world
-import supybot.utils as utils
-from supybot.commands import *
-import supybot.plugins as plugins
-import supybot.ircutils as ircutils
-import supybot.ircmsgs as ircmsgs
-import supybot.callbacks as callbacks
-
-
-HOST = 'localhost'
-
-
-class StoppableRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer):
-
-    stopped = False
-    allow_reuse_address = True
-
-    def __init__(self, *args, **kw):
-        SimpleXMLRPCServer.SimpleXMLRPCServer.__init__(self, *args, **kw)
-        self.register_function(lambda: 'OK', 'ping')
-
-    def serve_forever(self):
-        while not self.stopped:
-            self.handle_request()
-
-    def force_stop(self):
-        self.server_close()
-        self.stopped = True
-        self.create_dummy_request()
-        
-    def create_dummy_request(self):
-        server = xmlrpclib.Server('http://%s:%s' % self.server_address)
-        server.ping()
-
-
-
-
-class ControlInstance(object):
-
-    def privmsg(self, network, personorchannel, message):
-        target_irc, target = self._get_irc_and_target(network, personorchannel)
-        msg = ircmsgs.privmsg(target, message)
-        target_irc.sendMsg(msg)
-        return 'OK'
-
-    def notice(self, network, personorchannel, message):
-        target_irc, target = self._get_irc_and_target(network, personorchannel)
-        msg = ircmsgs.notice(target, message)
-        target_irc.sendMsg(msg)
-        return 'OK'
-
-    def command(self, network, personorchannel, cmd, notice=False):
-        target_irc, target = self._get_irc_and_target(network, personorchannel)
-        msg = ircmsgs.privmsg(target_irc.nick, cmd, prefix='ec!ec@ec')
-        msg.tag('externalcontroller', (target_irc, target, notice))
-        target_irc.feedMsg(msg)
-        return 'OK'
-
-    def _get_irc(self, network):
-        for irc in world.ircs:
-            if irc.network == network:
-                return irc
-
-    def _get_person_or_channel(self, irc, personorchannel):
-        if personorchannel.startswith('#'):
-            for channel in irc.state.channels:
-                if channel == personorchannel:
-                    return channel
-        else:
-            return personorchannel
-
-    def _get_irc_and_target(self, network, personorchannel):
-        target_irc = self._get_irc(network)
-        if target_irc is None:
-            raise Exception('Not on Network: %s' % network)
-        target = self._get_person_or_channel(target_irc, personorchannel)
-        if target is None:
-            raise Exception('Not on Channel: %s' % personorchannel)
-        return target_irc, target
-
-
-
-
-class ExternalControl(callbacks.Plugin):
-    """Add the help for "@plugin help ExternalControl" here
-    This should describe *how* to use this plugin."""
-    threaded = True
-
-    def __init__(self, irc):
-        callbacks.Plugin.__init__(self, irc)
-        self._start_server_in_thread()
-
-    def _start_server_in_thread(self):
-        t = threading.Thread(
-            target = self._start_server
-        )
-        t.start()
-
-    def _start_server(self):
-        self.server = StoppableRPCServer((HOST, self.registryValue('port')))
-        self.server.register_instance(ControlInstance())
-        self.server.serve_forever()
-
-    def die(self):
-        self.server.force_stop()
-
-    def outFilter(self, irc, msg):
-        if msg.inReplyTo:
-            if msg.inReplyTo.externalcontroller:
-                target_irc, target, notice = msg.inReplyTo.externalcontroller
-                self._reply_command(target_irc, target, msg, notice)
-                return None
-            else:
-                return msg
-        else:
-            return msg
-
-    def _reply_command(self, target_irc, target, msg, notice):
-        if notice:
-            factory = ircmsgs.notice
-        else:
-            factory = ircmsgs.privmsg
-        reply_msg = factory(target, msg.args[1])
-        target_irc.sendMsg(reply_msg)
-                
-        
-
-
-Class = ExternalControl
-
-
-# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:

supybot-external-control

-#! /usr/bin/env python
-
-###
-# Copyright (c) 2007, Ali Afshar
-# 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 sys, xmlrpclib, optparse
-
-
-def rpc_command(port, name, *args):
-    server = xmlrpclib.Server('http://localhost:%s' % port)
-    command = getattr(server, name)
-    try:
-        print 'Success: %s' % command(*args)
-    except xmlrpclib.Fault, e:
-        print 'Error: %s' % e.faultString.split(':', 1)[1]
-
-
-def main(argv=sys.argv):
-    usage = 'usage: %prog [-i] [-d] -n <network> -c <channel> [-t <text> | -s]'
-    parser = optparse.OptionParser(usage=usage)
-    parser.add_option('-p', '--port', dest='port', type='int',
-        help='The port to connect to the controller',
-        default = 7766)
-    parser.add_option('-n', '--network', dest='network',
-        help='Network to send the message to.')
-    parser.add_option('-c', '--channel', dest='channel',
-        help='Channel or nick to send the message to.')
-    parser.add_option('-i', '--notice', dest='notice', action='store_true',
-        default=False,
-        help='Whether the reply will be a notice')
-    parser.add_option('-d', '--command', dest='command', action='store_true',
-        default=False,
-        help='Whether the text to send should be evaluated as a command')
-    parser.add_option('-t', '--text', dest='text',
-        help='The text to send')
-    parser.add_option('-s', '--stdin', dest='stdin',
-        default=False, action='store_true',
-        help='Whether text should be read from stdin')
-    opts, args = parser.parse_args(argv)
-    if not (opts.network and opts.channel and (opts.text or opts.stdin)):
-        parser.error('A network and channel and (text or stdin) must me specified.\n'
-                     'Run with --help for a list of options.')
-
-    if opts.stdin:
-        text = sys.stdin.read().replace('\n', ' ').replace('\r', ' ')
-    else:
-        text = opts.text
-
-    args = [opts.network, opts.channel, text]
-    if opts.command:
-        command = 'command'
-        if opts.notice:
-            args.append(True)
-    elif opts.notice:
-        command = 'notice'
-    else:
-        command = 'privmsg'
-    rpc_command(opts.port, command, *args)
-
-    
-if __name__ == '__main__':
-    main()
-

test.py

-###
-# Copyright (c) 2007, Ali Afshar
-# 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 ExternalControlTestCase(PluginTestCase):
-    plugins = ('ExternalControl',)
-
-
-# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.