# -*- coding: utf-8 -*- # # # Copyright (C) Martijn Voncken 2007 # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, write to: # The Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor # Boston, MA 02110-1301, USA. # # In addition, as a special exception, the copyright holders give # permission to link the code of portions of this program with the OpenSSL # library. # You must obey the GNU General Public License in all respects for all of # the code used other than OpenSSL. If you modify file(s) with this # exception, you may extend this exception to your version of the file(s), # but you are not obligated to do so. If you do not wish to do so, delete # this exception statement from your version. If you delete this exception plugin_name = "Web User Interface" plugin_author = "Martijn Voncken" plugin_version = "rev." plugin_description = """A Web based User Interface Firefox greasemonkey script: http://userscripts.org/scripts/show/12639 Remotely add a file: "curl -F torrent=@./test1.torrent -F pwd=deluge http://localhost:8112/remote/torrent/add" Advanced template is only tested on firefox and garanteed not to work in IE6 ssl keys are located in WebUi/ssl/ Other contributors: *somedude : template enhancements. *markybob : stability : synced with his changes in deluge-svn. """ import deluge.common try: import deluge.pref from deluge.dialogs import show_popup_warning import webserver_common except ImportError: print 'WebUi:not imported as a plugin' try: from dbus_interface import get_dbus_manager except: print 'error importing dbus-interface!' pass #for unit-test. import time import gtk import os from subprocess import Popen from md5 import md5 from threading import Thread import random random.seed() plugin_version += open(os.path.join(os.path.dirname(__file__),'revno')).read() plugin_description += ( open(os.path.join(os.path.dirname(__file__),'version')).read()) def deluge_init(deluge_path): global path path = deluge_path def enable(core, interface): global path return plugin_WebUi(path, core, interface) class plugin_WebUi(object): def __init__(self, path, deluge_core, deluge_interface): self.path = path self.core = deluge_core self.interface = deluge_interface self.proc = None self.web_server = None if not deluge.common.windows_check(): import commands status = commands.getstatusoutput( 'ps x |grep -v grep |grep run_webserver') if status[0] == 0: os.kill(int(status[1].split()[0]), 9) time.sleep(1) #safe time to wait for kill to finish. self.config_file = deluge.common.CONFIG_DIR + "/webui.conf" self.config = deluge.pref.Preferences(self.config_file, False) try: self.config.load() except IOError: # File does not exist pass if not self.config.get('port'): #ugly way to detect new config file. #set default values: self.config.set("port", 8112) self.config.set("button_style", 2) self.config.set("auto_refresh", False) self.config.set("auto_refresh_secs", 4) self.config.set("template", "advanced") self.config.save(self.config_file) if not self.config.get("pwd_salt"): self.config.set("pwd_salt", "invalid") self.config.set("pwd_md5", "invalid") if self.config.get("cache_templates") == None: self.config.set("cache_templates", True) if deluge.common.windows_check(): self.config.set("run_in_thread", True) else: self.config.set("run_in_thread", False) if self.config.get("use_https") == None: self.config.set("use_https", False) self.dbus_manager = get_dbus_manager(deluge_core, deluge_interface, self.config, self.config_file) self.start_server() def unload(self): print 'WebUI:unload..' self.kill_server() def update(self): pass ## This will be only called if your plugin is configurable def configure(self,parent_dialog): d = ConfigDialog(self.config, self, parent_dialog) if d.run() == gtk.RESPONSE_OK: d.save_config() d.destroy() def start_server(self): self.kill_server() if self.config.get("run_in_thread"): print 'Start Webui(inside gtk)..' webserver_common.init_gtk_05() #reload changed config. from deluge_webserver import WebServer #only import in threaded mode self.web_server = WebServer() self.web_server.start_gtk() else: print 'Start Webui(in process)..' server_bin = os.path.dirname(__file__) + '/run_webserver' self.proc = Popen((server_bin,'env=0.5')) def kill_server(self): if self.web_server: print "webserver: stop" self.web_server.stop_gtk() self.web_server = None if self.proc: print "webserver: kill %i" % self.proc.pid os.system("kill -9 %i" % self.proc.pid) time.sleep(1) #safe time to wait for kill to finish. self.proc = None def __del__(self): self.kill_server() class ConfigDialog(gtk.Dialog): """ sorry, can't get used to gui builders. from what I read glade is better, but i dont want to invest time in them. """ def __init__(self, config, plugin, parent): print "Found WebUI plugin..." gtk.Dialog.__init__(self ,parent=parent) self.config = config self.plugin = plugin self.vb = gtk.VBox() self.set_title(_("WebUi Config")) template_path = os.path.join(os.path.dirname(__file__), 'templates') self.templates = [dirname for dirname in os.listdir(template_path) if os.path.isdir(os.path.join(template_path, dirname)) and not dirname.startswith('.')] self.port = self.add_widget(_('Port Number'), gtk.SpinButton()) self.pwd1 = self.add_widget(_('New Password'), gtk.Entry()) self.pwd2 = self.add_widget(_('New Password(confirm)'), gtk.Entry()) self.template = self.add_widget(_('Template'), gtk.combo_box_new_text()) self.button_style = self.add_widget(_('Button Style'), gtk.combo_box_new_text()) self.cache_templates = self.add_widget(_('Cache Templates'), gtk.CheckButton()) self.use_https = self.add_widget(_('https://'), gtk.CheckButton()) #self.share_downloads = self.add_widget(_('Share Download Directory'), # gtk.CheckButton()) self.port.set_range(80, 65536) self.port.set_increments(1, 10) self.pwd1.set_visibility(False) self.pwd2.set_visibility(False) for item in self.templates: self.template.append_text(item) if not self.config.get("template") in self.templates: self.config.set("template","deluge") for item in [_('Text and image'), _('Image Only'), _('Text Only')]: self.button_style.append_text(item) if self.config.get("button_style") == None: self.config.set("button_style", 2) self.port.set_value(int(self.config.get("port"))) self.template.set_active( self.templates.index(self.config.get("template"))) self.button_style.set_active(self.config.get("button_style")) #self.share_downloads.set_active( # bool(self.config.get("share_downloads"))) self.cache_templates.set_active(self.config.get("cache_templates")) self.use_https.set_active(self.config.get("use_https")) self.vbox.pack_start(self.vb, True, True, 0) self.vb.show_all() self.add_buttons(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL ,gtk.STOCK_OK, gtk.RESPONSE_OK) #disable https if pyopenssl is not installed try: import OpenSSL except: self.use_https.set_sensitive(False) def add_widget(self,label,w=None): hb = gtk.HBox() lbl = gtk.Label(label) lbl.set_size_request(200,20) hb.pack_start(lbl,False,False, 0) hb.pack_start(w,True,True, 0) self.vb.pack_start(hb,False,False, 0) return w self.add_buttons(dgtk.STOCK_CLOSE, dgtk.RESPONSE_CLOSE) def save_config(self): if self.pwd1.get_text() > '': if self.pwd1.get_text() <> self.pwd2.get_text(): show_popup_warning(self,_("Confirmed Password <> New Password\n" + "Password was not changed")) else: sm = md5() sm.update(str(random.getrandbits(5000))) salt = sm.digest() self.config.set("pwd_salt", salt) # m = md5() m.update(salt) m.update(unicode(self.pwd1.get_text())) self.config.set("pwd_md5", m.digest()) self.config.set("port", int(self.port.get_value())) self.config.set("template", self.template.get_active_text()) self.config.set("button_style", self.button_style.get_active()) self.config.set("cache_templates", self.cache_templates.get_active()) self.config.set("use_https", self.use_https.get_active()) #self.config.set("share_downloads", self.share_downloads.get_active()) self.config.save(self.plugin.config_file) self.plugin.start_server() #restarts server