diff --git a/GUI/README.txt b/GUI/README.txt
new file mode 100644
index 0000000..d60b47a
--- /dev/null
+++ b/GUI/README.txt
@@ -0,0 +1 @@
+Insert a description of your plugin here, with any notes, etc. about using it.
diff --git a/GUI/__init__.py b/GUI/__init__.py
new file mode 100644
index 0000000..17b4535
--- /dev/null
+++ b/GUI/__init__.py
@@ -0,0 +1,69 @@
+###
+# Copyright (c) 2011, 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.
+
+###
+
+"""
+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.
+if not hasattr(supybot.authors, 'progval'):
+ supybot.authors.progval =supybot.Author('Valentin Lorentz', 'ProgVal',
+ 'progval@gmail.com')
+__author__ = supybot.authors.progval
+
+# 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/GUI/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/GUI/config.py b/GUI/config.py
new file mode 100644
index 0000000..a022eaf
--- /dev/null
+++ b/GUI/config.py
@@ -0,0 +1,52 @@
+###
+# Copyright (c) 2011, 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
+from supybot.i18n import PluginInternationalization, internationalizeDocstring
+
+_ = PluginInternationalization('GUI')
+
+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('GUI', True)
+
+
+GUI = conf.registerPlugin('GUI')
+# This is where your configuration variables (if any) should go. For example:
+# conf.registerGlobalValue(GUI, 'someConfigVariableName',
+# registry.Boolean(False, _("""Help for someConfigVariableName.""")))
+
+
+# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:
diff --git a/GUI/frontend/__init__.py b/GUI/frontend/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/GUI/frontend/frontend.py b/GUI/frontend/frontend.py
new file mode 100755
index 0000000..484f47d
--- /dev/null
+++ b/GUI/frontend/frontend.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+# -*- coding: utf8 -*-
+
+###
+# Copyright (c) 2011, 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.
+###
+
+# Standard library
+from __future__ import print_function
+import sys
+
+# Third-party modules
+from PyQt4 import QtCore, QtGui
+
+# Local modules
+import window as windowSetup
+
+
+
+# FIXME: internationalize
+_ = lambda x:x
+
+
+if __name__ == "__main__":
+ import sys
+ app = QtGui.QApplication(sys.argv)
+ window = QtGui.QTabWidget()
+ ui = windowSetup.Ui_window()
+ ui.setupUi(window)
+ window.show()
+ sys.exit(app.exec_())
diff --git a/GUI/frontend/window.py b/GUI/frontend/window.py
new file mode 100644
index 0000000..ac1127f
--- /dev/null
+++ b/GUI/frontend/window.py
@@ -0,0 +1,77 @@
+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'window.ui'
+#
+# Created: Sat Feb 5 09:08:12 2011
+# by: PyQt4 UI code generator 4.7.3
+#
+# WARNING! All changes made in this file will be lost!
+
+from PyQt4 import QtCore, QtGui
+
+class Ui_window(object):
+ def setupUi(self, window):
+ window.setObjectName("window")
+ window.resize(761, 591)
+ self.configurationTab = QtGui.QWidget()
+ self.configurationTab.setObjectName("configurationTab")
+ self.horizontalLayout = QtGui.QHBoxLayout(self.configurationTab)
+ self.horizontalLayout.setObjectName("horizontalLayout")
+ self.configurationTree = QtGui.QTreeView(self.configurationTab)
+ self.configurationTree.setObjectName("configurationTree")
+ self.horizontalLayout.addWidget(self.configurationTree)
+ self.configurationDetailsLayout = QtGui.QVBoxLayout()
+ self.configurationDetailsLayout.setObjectName("configurationDetailsLayout")
+ self.configurationEditLayout = QtGui.QVBoxLayout()
+ self.configurationEditLayout.setObjectName("configurationEditLayout")
+ self.configurationVariableLabel = QtGui.QLabel(self.configurationTab)
+ self.configurationVariableLabel.setObjectName("configurationVariableLabel")
+ self.configurationEditLayout.addWidget(self.configurationVariableLabel)
+ self.configurationValueEdit = QtGui.QPlainTextEdit(self.configurationTab)
+ self.configurationValueEdit.setObjectName("configurationValueEdit")
+ self.configurationEditLayout.addWidget(self.configurationValueEdit)
+ self.configurationEditButtonsLayout = QtGui.QHBoxLayout()
+ self.configurationEditButtonsLayout.setObjectName("configurationEditButtonsLayout")
+ self.configurationDefaultButton = QtGui.QPushButton(self.configurationTab)
+ self.configurationDefaultButton.setObjectName("configurationDefaultButton")
+ self.configurationEditButtonsLayout.addWidget(self.configurationDefaultButton)
+ self.configurationSetButton = QtGui.QPushButton(self.configurationTab)
+ self.configurationSetButton.setObjectName("configurationSetButton")
+ self.configurationEditButtonsLayout.addWidget(self.configurationSetButton)
+ self.configurationEditLayout.addLayout(self.configurationEditButtonsLayout)
+ self.configurationDetailsLayout.addLayout(self.configurationEditLayout)
+ self.configurationHelpLabel = QtGui.QLabel(self.configurationTab)
+ self.configurationHelpLabel.setObjectName("configurationHelpLabel")
+ self.configurationDetailsLayout.addWidget(self.configurationHelpLabel)
+ self.configurationHelp = QtGui.QPlainTextEdit(self.configurationTab)
+ self.configurationHelp.setObjectName("configurationHelp")
+ self.configurationDetailsLayout.addWidget(self.configurationHelp)
+ self.horizontalLayout.addLayout(self.configurationDetailsLayout)
+ window.addTab(self.configurationTab, "")
+ self.commandsTab = QtGui.QWidget()
+ self.commandsTab.setObjectName("commandsTab")
+ window.addTab(self.commandsTab, "")
+
+ self.retranslateUi(window)
+ window.setCurrentIndex(0)
+ QtCore.QMetaObject.connectSlotsByName(window)
+
+ def retranslateUi(self, window):
+ window.setWindowTitle(QtGui.QApplication.translate("window", "TabWidget", None, QtGui.QApplication.UnicodeUTF8))
+ self.configurationVariableLabel.setText(QtGui.QApplication.translate("window", "Value", None, QtGui.QApplication.UnicodeUTF8))
+ self.configurationDefaultButton.setText(QtGui.QApplication.translate("window", "Default", None, QtGui.QApplication.UnicodeUTF8))
+ self.configurationSetButton.setText(QtGui.QApplication.translate("window", "Set", None, QtGui.QApplication.UnicodeUTF8))
+ self.configurationHelpLabel.setText(QtGui.QApplication.translate("window", "Help", None, QtGui.QApplication.UnicodeUTF8))
+ window.setTabText(window.indexOf(self.configurationTab), QtGui.QApplication.translate("window", "Configuration", None, QtGui.QApplication.UnicodeUTF8))
+ window.setTabText(window.indexOf(self.commandsTab), QtGui.QApplication.translate("window", "Commands", None, QtGui.QApplication.UnicodeUTF8))
+
+
+if __name__ == "__main__":
+ import sys
+ app = QtGui.QApplication(sys.argv)
+ window = QtGui.QTabWidget()
+ ui = Ui_window()
+ ui.setupUi(window)
+ window.show()
+ sys.exit(app.exec_())
+
diff --git a/GUI/frontend/window.ui b/GUI/frontend/window.ui
new file mode 100644
index 0000000..7f2d4de
--- /dev/null
+++ b/GUI/frontend/window.ui
@@ -0,0 +1,83 @@
+
+
+ window
+
+
+
+ 0
+ 0
+ 761
+ 591
+
+
+
+ TabWidget
+
+
+ 0
+
+
+
+ Configuration
+
+
+ -
+
+
+ -
+
+
-
+
+
-
+
+
+ Value
+
+
+
+ -
+
+
+ -
+
+
-
+
+
+ Default
+
+
+
+ -
+
+
+ Set
+
+
+
+
+
+
+
+ -
+
+
+ Help
+
+
+
+ -
+
+
+
+
+
+
+
+
+ Commands
+
+
+
+
+
+
diff --git a/GUI/local/__init__.py b/GUI/local/__init__.py
new file mode 100644
index 0000000..e86e97b
--- /dev/null
+++ b/GUI/local/__init__.py
@@ -0,0 +1 @@
+# Stub so local is a module, used for third-party modules
diff --git a/GUI/plugin.py b/GUI/plugin.py
new file mode 100644
index 0000000..34dc645
--- /dev/null
+++ b/GUI/plugin.py
@@ -0,0 +1,140 @@
+###
+# Copyright (c) 2011, 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 time
+import socket
+import SocketServer
+import supybot.utils as utils
+from supybot.commands import *
+import supybot.plugins as plugins
+import supybot.ircmsgs as ircmsgs
+import supybot.ircutils as ircutils
+import supybot.callbacks as callbacks
+from supybot.i18n import PluginInternationalization, internationalizeDocstring
+
+_ = PluginInternationalization('GUI')
+
+parseMessage = re.compile('\w+: (?P.*)')
+class FakeIrc:
+ def __init__(self, irc):
+ self.message = ''
+ self._irc = irc
+ def reply(self, message):
+ self.message += 'Reply: %s\n' % message
+ def error(self, message=''):
+ self.message += 'Error: %s\n' % message
+ def queueMsg(self, message):
+ self._rawData = message
+ if message.command in ('PRIVMSG', 'NOTICE'):
+ parsed = parseMessage.match(message.args[1])
+ if parsed is not None:
+ message = parsed.group('content')
+ else:
+ message = message.args[1]
+ self.message = message
+ def __getattr__(self, name):
+ return getattr(self.__dict__['_irc'], name)
+
+class ThreadedTCPServer(SocketServer.TCPServer):
+ pass
+
+class RequestHandler(SocketServer.StreamRequestHandler):
+ def handle(self):
+ currentLine = ''
+ while self.server.enabled:
+ if not '\n' in currentLine:
+ try:
+ data = self.request.recv(4096)
+ except socket.timeout:
+ continue
+ if '\n' in data:
+ splitted = (currentLine + data).split('\r\n')
+ currentLine = splitted[0]
+ nextLines = '\r\n'.join(splitted[1:])
+ else:
+ continue
+ tokens = callbacks.tokenize(currentLine)
+ fakeIrc = FakeIrc(self.server._irc)
+ msg = ircmsgs.privmsg('#supybot-gui', currentLine + '\n')
+ self.server._plugin.Proxy(fakeIrc, msg, tokens)
+ self.request.send(fakeIrc.message)
+ currentLine = nextLines
+
+
+class GUI(callbacks.Plugin):
+ threaded = True
+ def __init__(self, irc):
+ self.__parent = super(GUI, self)
+ callbacks.Plugin.__init__(self, irc)
+ while True:
+ try:
+ self._server = ThreadedTCPServer(('127.0.0.1', 14789),
+ RequestHandler)
+ break
+ except socket.error: # Address already in use
+ time.sleep(1)
+ self._server._irc = irc
+ self._server._plugin = self
+ self._server.enabled = True
+
+ @internationalizeDocstring
+ def start(self, irc, msg, args):
+ """takes no arguments
+
+ Starts the GUI server."""
+ irc.replySuccess()
+ self._server.handle_request()
+ start = wrap(start, [('checkCapability', 'owner')])
+
+ @internationalizeDocstring
+ def stop(self, irc, msg, args):
+ """takes no arguments
+
+ Stopss the GUI server."""
+ if not hasattr(self, '_server'):
+ irc.error(_('Server not enabled'))
+ return
+ irc.replySuccess()
+ stop = wrap(stop, [('checkCapability', 'owner')])
+
+ def __die__(self, irc):
+ self.__parent = super(GUI, self)
+ callbacks.Plugin.__die__(self, irc)
+ self._server.enabled = False
+ self._server.shutdown()
+ del self._server
+
+
+
+Class = GUI
+
+
+# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:
diff --git a/GUI/test.py b/GUI/test.py
new file mode 100644
index 0000000..76f410f
--- /dev/null
+++ b/GUI/test.py
@@ -0,0 +1,37 @@
+###
+# Copyright (c) 2011, 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 GUITestCase(PluginTestCase):
+ plugins = ('GUI',)
+
+
+# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: