From 9fa8748432cfc8c58572603192696be9765855cc Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Wed, 27 Apr 2011 22:06:13 +0100 Subject: [PATCH] Fix some clean config dir issues. Moved some auth stuff to `deluge.common` because they're also used on the GTK UI. Now, if a user starts deluge in classic mode and tries to change it to client/daemon mode, he see's a dialog stating that the current session will be stopped. If he answers no, nothing is done, the classic mode pref is set back as it was. If he answers yes, all components are stopped and client is disconnected. At this stage the user can open the connection manager to start the daemon and connect. If the user starts in client/daemon mode and switches to classic mode he see's a dialog stating that deluge must be restarted. The GTK UI connection manager now loads it's default config with the localclient username and password. If not present in the auth file, the auth file will be recreated. --- deluge/common.py | 40 +++++++++++++++++++++++++ deluge/core/authmanager.py | 43 +++++---------------------- deluge/core/daemon.py | 9 ++++-- deluge/ui/client.py | 1 + deluge/ui/common.py | 44 +++++++++++++++------------- deluge/ui/gtkui/connectionmanager.py | 32 +++++++++++++------- deluge/ui/gtkui/preferences.py | 34 +++++++++++++++++++-- 7 files changed, 132 insertions(+), 71 deletions(-) diff --git a/deluge/common.py b/deluge/common.py index 7246cd3fe..ef9a5aad7 100644 --- a/deluge/common.py +++ b/deluge/common.py @@ -631,3 +631,43 @@ class VersionSplit(object): v1 = [self.version, self.suffix or 'z', self.dev] v2 = [ver.version, ver.suffix or 'z', ver.dev] return cmp(v1, v2) + + +# Common AUTH stuff +AUTH_LEVEL_NONE = 0 +AUTH_LEVEL_READONLY = 1 +AUTH_LEVEL_NORMAL = 5 +AUTH_LEVEL_ADMIN = 10 +AUTH_LEVEL_DEFAULT = AUTH_LEVEL_NORMAL + +def create_auth_file(): + import stat, configmanager + auth_file = configmanager.get_config_dir("auth") + # Check for auth file and create if necessary + if not os.path.exists(auth_file): + fd = open(auth_file, "w") + fd.flush() + os.fsync(fd.fileno()) + fd.close() + # Change the permissions on the file so only this user can read/write it + os.chmod(auth_file, stat.S_IREAD | stat.S_IWRITE) + +def create_localclient_account(): + import configmanager, random + auth_file = configmanager.get_config_dir("auth") + if not os.path.exists(auth_file): + create_auth_file() + + try: + from hashlib import sha1 as sha_hash + except ImportError: + from sha import new as sha_hash + fd = open(auth_file, "w") + fd.write(":".join([ + "localclient", + sha_hash(str(random.random())).hexdigest(), + str(AUTH_LEVEL_ADMIN) + ]) + '\n') + fd.flush() + os.fsync(fd.fileno()) + fd.close() diff --git a/deluge/core/authmanager.py b/deluge/core/authmanager.py index 3ec723b43..1f9528fcc 100644 --- a/deluge/core/authmanager.py +++ b/deluge/core/authmanager.py @@ -42,17 +42,14 @@ import logging import deluge.component as component import deluge.configmanager as configmanager +from deluge.common import (AUTH_LEVEL_ADMIN, AUTH_LEVEL_NONE, AUTH_LEVEL_NORMAL, + AUTH_LEVEL_READONLY, AUTH_LEVEL_DEFAULT, + create_auth_file, create_localclient_account) + from deluge.error import AuthManagerError, AuthenticationRequired, BadLoginError log = logging.getLogger(__name__) -AUTH_LEVEL_NONE = 0 -AUTH_LEVEL_READONLY = 1 -AUTH_LEVEL_NORMAL = 5 -AUTH_LEVEL_ADMIN = 10 - -AUTH_LEVEL_DEFAULT = AUTH_LEVEL_NORMAL - AUTH_LEVELS_MAPPING = { 'NONE': AUTH_LEVEL_NONE, 'READONLY': AUTH_LEVEL_READONLY, @@ -218,28 +215,13 @@ class AuthManager(component.Component): self.__load_auth_file() - def __create_localclient_account(self): - """ - Returns the string. - """ - # We create a 'localclient' account with a random password - try: - from hashlib import sha1 as sha_hash - except ImportError: - from sha import new as sha_hash - self.__auth["localclient"] = Account( - "localclient", - sha_hash(str(random.random())).hexdigest(), - AUTH_LEVEL_ADMIN - ) - def __load_auth_file(self): save_and_reload = False auth_file = configmanager.get_config_dir("auth") # Check for auth file and create if necessary if not os.path.exists(auth_file): - self.__create_auth_file() - self.__create_localclient_account() + create_auth_file() + create_localclient_account() self.write_auth_file() auth_file_modification_time = os.stat(auth_file).st_mtime @@ -295,7 +277,7 @@ class AuthManager(component.Component): self.__auth[username] = Account(username, password, authlevel) if "localclient" not in self.__auth: - self.__create_localclient_account() + create_localclient_account() self.write_auth_file() if save_and_reload: @@ -303,14 +285,3 @@ class AuthManager(component.Component): self.write_auth_file() self.__auth_modification_time = auth_file_modification_time - - def __create_auth_file(self): - auth_file = configmanager.get_config_dir("auth") - # Check for auth file and create if necessary - if not os.path.exists(auth_file): - fd = open(auth_file, "w") - fd.flush() - os.fsync(fd.fileno()) - fd.close() - # Change the permissions on the file so only this user can read/write it - os.chmod(auth_file, stat.S_IREAD | stat.S_IWRITE) diff --git a/deluge/core/daemon.py b/deluge/core/daemon.py index 383264dbd..0343febe5 100644 --- a/deluge/core/daemon.py +++ b/deluge/core/daemon.py @@ -54,7 +54,9 @@ class Daemon(object): if os.path.isfile(deluge.configmanager.get_config_dir("deluged.pid")): # Get the PID and the port of the supposedly running daemon try: - (pid, port) = open(deluge.configmanager.get_config_dir("deluged.pid")).read().strip().split(";") + (pid, port) = open( + deluge.configmanager.get_config_dir("deluged.pid") + ).read().strip().split(";") pid = int(pid) port = int(port) except ValueError: @@ -93,7 +95,10 @@ class Daemon(object): else: # This is a deluged! s.close() - raise deluge.error.DaemonRunningError("There is a deluge daemon running with this config directory!") + raise deluge.error.DaemonRunningError( + "There is a deluge daemon running with this config " + "directory!" + ) # Initialize gettext try: diff --git a/deluge/ui/client.py b/deluge/ui/client.py index e59df470d..a6b17b922 100644 --- a/deluge/ui/client.py +++ b/deluge/ui/client.py @@ -515,6 +515,7 @@ class DaemonClassicProxy(DaemonProxy): self.__daemon.core.eventmanager.register_event_handler(event, handler) def disconnect(self): + self.connected = False self.__daemon = None def call(self, method, *args, **kwargs): diff --git a/deluge/ui/common.py b/deluge/ui/common.py index fb9048d01..239bb84c9 100644 --- a/deluge/ui/common.py +++ b/deluge/ui/common.py @@ -407,26 +407,28 @@ def get_localhost_auth(): :rtype: tuple """ auth_file = deluge.configmanager.get_config_dir("auth") - if os.path.exists(auth_file): - for line in open(auth_file): - if line.startswith("#"): - # This is a comment line - continue - line = line.strip() - try: - lsplit = line.split(":") - except Exception, e: - log.error("Your auth file is malformed: %s", e) - continue + if not os.path.exists(auth_file): + from deluge.common import create_localclient_account + create_localclient_account() - if len(lsplit) == 2: - username, password = lsplit - elif len(lsplit) == 3: - username, password, level = lsplit - else: - log.error("Your auth file is malformed: Incorrect number of fields!") - continue + for line in open(auth_file): + if line.startswith("#"): + # This is a comment line + continue + line = line.strip() + try: + lsplit = line.split(":") + except Exception, e: + log.error("Your auth file is malformed: %s", e) + continue - if username == "localclient": - return (username, password) - return ("", "") + if len(lsplit) == 2: + username, password = lsplit + elif len(lsplit) == 3: + username, password, level = lsplit + else: + log.error("Your auth file is malformed: Incorrect number of fields!") + continue + + if username == "localclient": + return (username, password) diff --git a/deluge/ui/gtkui/connectionmanager.py b/deluge/ui/gtkui/connectionmanager.py index bbe7e42e8..e28c0b751 100644 --- a/deluge/ui/gtkui/connectionmanager.py +++ b/deluge/ui/gtkui/connectionmanager.py @@ -33,6 +33,7 @@ # # +import os import gtk import pkg_resources import time @@ -56,11 +57,6 @@ log = logging.getLogger(__name__) DEFAULT_HOST = "127.0.0.1" DEFAULT_PORT = 58846 -DEFAULT_CONFIG = { - "hosts": [(hashlib.sha1(str(time.time())).hexdigest(), DEFAULT_HOST, - DEFAULT_PORT, "localclient", "")] -} - HOSTLIST_COL_ID = 0 HOSTLIST_COL_HOST = 1 HOSTLIST_COL_PORT = 2 @@ -99,15 +95,11 @@ class ConnectionManager(component.Component): def __init__(self): component.Component.__init__(self, "ConnectionManager") self.gtkui_config = ConfigManager("gtkui.conf") - - self.config = ConfigManager("hostlist.conf.1.2", DEFAULT_CONFIG) - self.config.run_converter((0, 1), 2, self.__migrate_config_1_to_2) - self.running = False # Component overrides def start(self): - pass + self.config = self.__load_config() def stop(self): # Close this dialog when we are shutting down @@ -117,6 +109,26 @@ class ConnectionManager(component.Component): def shutdown(self): pass + def __load_config(self): + auth_file = deluge.configmanager.get_config_dir("auth") + if not os.path.exists(auth_file): + from deluge.common import create_localclient_account + create_localclient_account() + + localclient_username, localclient_password = get_localhost_auth() + DEFAULT_CONFIG = { + "hosts": [( + hashlib.sha1(str(time.time())).hexdigest(), + DEFAULT_HOST, + DEFAULT_PORT, + localclient_username, + localclient_password + )] + } + config = ConfigManager("hostlist.conf.1.2", DEFAULT_CONFIG) + config.run_converter((0, 1), 2, self.__migrate_config_1_to_2) + return config + # Public methods def show(self): """ diff --git a/deluge/ui/gtkui/preferences.py b/deluge/ui/gtkui/preferences.py index 83f681f76..d40e486ab 100644 --- a/deluge/ui/gtkui/preferences.py +++ b/deluge/ui/gtkui/preferences.py @@ -546,6 +546,8 @@ class Preferences(component.Component): except ImportError: from sha import new as sha_hash + classic_mode_was_set = self.gtkui_config["classic_mode"] + # Get the values from the dialog new_core_config = {} new_gtkui_config = {} @@ -666,8 +668,10 @@ class Preferences(component.Component): self.glade.get_widget("txt_tray_password").get_text()).hexdigest() if passhex != "c07eb5a8c0dc7bb81c217b67f11c3b7a5e95ffd7": new_gtkui_config["tray_password"] = passhex - new_gtkui_config["classic_mode"] = \ - self.glade.get_widget("chk_classic_mode").get_active() + + new_gtkui_in_classic_mode = self.glade.get_widget("chk_classic_mode").get_active() + new_gtkui_config["classic_mode"] = new_gtkui_in_classic_mode + new_gtkui_config["show_rate_in_title"] = \ self.glade.get_widget("chk_show_rate_in_title").get_active() @@ -763,6 +767,32 @@ class Preferences(component.Component): # Re-show the dialog to make sure everything has been updated self.show() + if classic_mode_was_set==True and new_gtkui_in_classic_mode==False: + def on_response(response): + if response == gtk.RESPONSE_NO: + # Set each changed config value in the core + self.gtkui_config["classic_mode"] = True + client.core.set_config({"classic_mode": True}) + client.force_call(True) + # Update the configuration + self.core_config.update({"classic_mode": True}) + self.glade.get_widget("chk_classic_mode").set_active(True) + else: + client.disconnect() + if client.is_classicmode(): + component.stop() + dialog = dialogs.YesNoDialog( + _("Attention"), + _("Your current session will be stopped. Continue?") + ) + dialog.run().addCallback(on_response) + elif classic_mode_was_set==False and new_gtkui_in_classic_mode==True: + dialog = dialogs.InformationDialog( + _("Attention"), + _("You must now restart the deluge UI") + ) + dialog.run() + def hide(self): self.glade.get_widget("port_img").hide() self.pref_dialog.hide()