From 8594116630e8e36ac00000aa8adfc84b2d7e1b5c Mon Sep 17 00:00:00 2001 From: Dan O'Reilly Date: Sun, 1 Feb 2009 23:10:11 -0500 Subject: [PATCH 1/6] Make it possible for the user to select which graphical sudo application to use. Make any external apps not installed on the system unselectable in the GUI. Rework the app selection code in the backend to fall back to auto-selection if a requested app isn't installed. Tweak the autoconnect attempt throttle in wicd-monitor to not be as aggressive. Made sure the preferences dialog would reconnect to dbus when a DaemonStarting signal was sent. --- data/wicd.glade | 92 ++++++++++++++- wicd/backends/be-external.py | 27 +++-- wicd/backends/be-ioctl.py | 4 +- wicd/gui.py | 8 +- wicd/misc.py | 33 ++++-- wicd/monitor.py | 5 +- wicd/netentry.py | 6 +- wicd/networking.py | 56 ++++----- wicd/prefs.py | 82 +++++++++++--- wicd/wicd-daemon.py | 27 ++++- wicd/wnettools.py | 213 +++++++++++++++++------------------ 11 files changed, 365 insertions(+), 188 deletions(-) diff --git a/data/wicd.glade b/data/wicd.glade index dd69932..0fe8d7a 100644 --- a/data/wicd.glade +++ b/data/wicd.glade @@ -1,6 +1,6 @@ - + 450 @@ -895,7 +895,7 @@ is already active. True - 6 + 8 True @@ -961,7 +961,7 @@ is already active. True True - route + route 0 True True @@ -1125,6 +1125,92 @@ is already active. + + + True + 0 + <b>Graphical Sudo Application</b> + True + + + 6 + 7 + + + + + + True + 12 + + + True + + + True + True + Automatic (recommended) + 0 + True + True + + + False + + + + + True + True + gksudo + 0 + True + True + sudo_auto_radio + + + False + 1 + + + + + True + True + kdesu + 0 + True + True + sudo_auto_radio + + + False + 2 + + + + + True + True + ktsuss + 0 + True + True + sudo_auto_radio + + + False + 3 + + + + + + + 7 + 8 + + diff --git a/wicd/backends/be-external.py b/wicd/backends/be-external.py index 3a3dac3..4d56be1 100644 --- a/wicd/backends/be-external.py +++ b/wicd/backends/be-external.py @@ -220,10 +220,10 @@ class WiredInterface(Interface, wnettools.BaseWiredInterface): except (IOError, ValueError, TypeError): print 'Error checking link using /sys/class/net/%s/carrier' % self.iface - if self.ETHTOOL_FOUND and self.link_detect != misc.MIITOOL: - return self._eth_get_plugged_in() - elif self.MIITOOL_FOUND: + if self.miitool_cmd and self.link_detect == misc.MIITOOL: return self._mii_get_plugged_in() + elif self.ethtool_cmd: + return self._eth_get_plugged_in() else: print 'Error: No way of checking for a wired connection. Make ' + \ 'sure that either mii-tool or ethtool is installed.' @@ -236,14 +236,15 @@ class WiredInterface(Interface, wnettools.BaseWiredInterface): True if a link is detected, False otherwise. """ - link_tool = 'ethtool' + cmd = "%s %s" % (self.ethtool_cmd, self.iface) if not self.IsUp(): print 'Wired Interface is down, putting it up' self.Up() time.sleep(6) - tool_data = misc.Run(link_tool + ' ' + self.iface, True) - if misc.RunRegex(re.compile('(Link detected: yes)', re.I | re.M | - re.S), tool_data) is not None: + if self.verbose: print cmd + tool_data = misc.Run(cmd, include_stderr=True) + if misc.RunRegex(re.compile('(Link detected: yes)', re.I | re.M | re.S), + tool_data): return True else: return False @@ -255,14 +256,16 @@ class WiredInterface(Interface, wnettools.BaseWiredInterface): True if a link is detected, False otherwise. """ - link_tool = 'mii-tool' - tool_data = misc.Run(link_tool + ' ' + self.iface, True) + cmd = "%s %s" % (self.miitool_cmd, self.iface) + if self.verbose: print cmd + tool_data = misc.Run(cmd, include_stderr=True) if misc.RunRegex(re.compile('(Invalid argument)', re.I | re.M | re.S), tool_data) is not None: print 'Wired Interface is down, putting it up' self.Up() time.sleep(4) - tool_data = misc.Run(link_tool + ' ' + self.iface, True) + if self.verbose: print cmd + tool_data = misc.Run(cmd, include_stderr=True) if misc.RunRegex(re.compile('(link ok)', re.I | re.M | re.S), tool_data) is not None: @@ -421,14 +424,14 @@ class WirelessInterface(Interface, wnettools.BaseWirelessInterface): """ # Right now there's no way to do this for these drivers - if self.wpa_driver == RALINK_DRIVER or not self.WPA_CLI_FOUND: + if self.wpa_driver == RALINK_DRIVER or not self.wpa_cli_cmd: return True MAX_TIME = 35 MAX_DISCONNECTED_TIME = 3 disconnected_time = 0 while (time.time() - auth_time) < MAX_TIME: - cmd = 'wpa_cli -i ' + self.iface + ' status' + cmd = '%s -i %s status' % (self.wpa_cli_cmd, self.iface) output = misc.Run(cmd) result = misc.RunRegex(auth_pattern, output) if self.verbose: diff --git a/wicd/backends/be-ioctl.py b/wicd/backends/be-ioctl.py index eb5f807..bfcfece 100644 --- a/wicd/backends/be-ioctl.py +++ b/wicd/backends/be-ioctl.py @@ -215,9 +215,9 @@ class WiredInterface(Interface, wnettools.BaseWiredInterface): """ if not self.iface: return False - if self.ETHTOOL_FOUND and self.link_detect != misc.MIITOOL: + if self.ethtool_cmd and self.link_detect != misc.MIITOOL: return self._eth_get_plugged_in() - elif self.MIITOOL_FOUND: + elif self.miitool_cmd: return self._mii_get_plugged_in() else: print 'Error: No way of checking for a wired connection. Make \ diff --git a/wicd/gui.py b/wicd/gui.py index 162cbec..8cb6497 100644 --- a/wicd/gui.py +++ b/wicd/gui.py @@ -37,6 +37,7 @@ from dbus import version as dbus_version from wicd import misc from wicd import wpath from wicd import dbusmanager +from wicd import prefs from wicd.misc import noneToString from wicd.netentry import WiredNetworkEntry, WirelessNetworkEntry from wicd.prefs import PreferencesDialog @@ -45,12 +46,6 @@ from wicd.guiutil import error, GreyLabel, LabelEntry, SmallLabel if __name__ == '__main__': wpath.chdir(__file__) -try: - import pygtk - pygtk.require("2.0") -except: - pass - proxy_obj = daemon = wireless = wired = bus = None language = misc.get_language_list_gui() DBUS_AVAIL = False @@ -71,6 +66,7 @@ def setup_dbus(force=True): return False else: return False + prefs.setup_dbus() bus = dbusmanager.get_bus() dbus_ifaces = dbusmanager.get_dbus_ifaces() daemon = dbus_ifaces['daemon'] diff --git a/wicd/misc.py b/wicd/misc.py index c4bc0d7..8922074 100644 --- a/wicd/misc.py +++ b/wicd/misc.py @@ -29,26 +29,40 @@ from commands import getoutput # wicd imports import wpath -if __name__ == '__main__': - wpath.chdir(__file__) - +# Connection state constants NOT_CONNECTED = 0 CONNECTING = 1 WIRELESS = 2 WIRED = 3 SUSPENDED = 4 +# Automatic app selection constant AUTO = 0 + +# DHCP Clients DHCLIENT = 1 DHCPCD = 2 PUMP = 3 +# Link detection tools ETHTOOL = 1 MIITOOL = 2 +# Route flushing tools IP = 1 ROUTE = 2 +# Graphical sudo apps +GKSUDO = 1 +KDESU = 2 +KTSUSS = 3 +sudo_dict = { + AUTO : "", + GKSUDO : "gksudo", + KDESU : "kdesu", + KTSUSS: "ktsuss", +} + class WicdError(Exception): pass @@ -375,9 +389,9 @@ def detect_desktop_environment(): pass return desktop_environment -def get_sudo_cmd(msg): +def get_sudo_cmd(msg, prog_num=0): """ Returns a graphical sudo command for generic use. """ - sudo_prog = choose_sudo_prog() + sudo_prog = choose_sudo_prog(prog_num) if not sudo_prog: return None if re.search("(ktsuss|gksu|gksudo)$", sudo_prog): msg_flag = "-m" @@ -385,8 +399,10 @@ def get_sudo_cmd(msg): msg_flag = "--caption" return [sudo_prog, msg_flag, msg] -def choose_sudo_prog(): +def choose_sudo_prog(prog_num=0): """ Try to intelligently decide which graphical sudo program to use. """ + if prog_num: + return find_path(sudo_dict[prog_num]) desktop_env = detect_desktop_environment() env_path = os.environ['PATH'].split(":") @@ -412,7 +428,10 @@ def find_path(cmd): the file can not be found. """ - paths = os.getenv("PATH", default="/usr/bin:/usr/local/bin").split(':') + paths = os.getenv("PATH").split(':') + if not paths: + paths = ["/usr/local/sbin", "/usr/local/bin", "/usr/sbin", "/usr/bin", + "/sbin", "/bin"] for path in paths: if os.path.exists(os.path.join(path, cmd)): return os.path.join(path, cmd) diff --git a/wicd/monitor.py b/wicd/monitor.py index ef7f104..2e4bac7 100755 --- a/wicd/monitor.py +++ b/wicd/monitor.py @@ -275,8 +275,9 @@ class ConnectionStatus(object): return # Some checks to keep reconnect retries from going crazy. - if self.reconnect_tries > 2 and \ - (time.time() - self.last_reconnect_time) < 300: + if (self.reconnect_tries > 3 and + (time.time() - self.last_reconnect_time) < 200): + print "Throttling autoreconnect" return self.reconnecting = True diff --git a/wicd/netentry.py b/wicd/netentry.py index 0616e5b..8b4f541 100644 --- a/wicd/netentry.py +++ b/wicd/netentry.py @@ -237,7 +237,8 @@ class WiredSettingsDialog(AdvancedSettingsDialog): profile = self.prof_name cmdend = [os.path.join(wpath.lib, "configscript.py"), profile, "wired"] if os.getuid() != 0: - cmdbase = misc.get_sudo_cmd(language['scripts_need_pass']) + cmdbase = misc.get_sudo_cmd(language['scripts_need_pass'], + prog_num=daemon.GetSudoApp()) if not cmdbase: error(None, language["no_sudo_prog"]) return @@ -336,7 +337,8 @@ class WirelessSettingsDialog(AdvancedSettingsDialog): cmdend = [os.path.join(wpath.lib, "configscript.py"), str(self.networkID), "wireless"] if os.getuid() != 0: - cmdbase = misc.get_sudo_cmd(language['scripts_need_pass']) + cmdbase = misc.get_sudo_cmd(language['scripts_need_pass'], + prog_num=daemon.GetSudoApp()) if not cmdbase: error(None, language["no_sudo_prog"]) return diff --git a/wicd/networking.py b/wicd/networking.py index 6e3e8c2..cc6a118 100644 --- a/wicd/networking.py +++ b/wicd/networking.py @@ -105,6 +105,30 @@ def get_backend_description_dict(): if be: d[be] = get_backend_description(be) return d + +def expand_script_macros(script, msg, bssid, essid): + """Expands any supported macros in a script. + + Keyword arguments: + script -- the script to execute. + msg -- the name of the script, %{script} will be expanded to this. + bssid -- the bssid of the network we connect to, defaults to 'wired'. + essid -- the essid of the network we connect to, defaults to 'wired'.""" + def repl(match): + macro = match.group(1).lower() + if macro_dict.has_key(macro): + return macro_dict[macro] + print 'Warning: found illegal macro %s in %s script' % (macro, msg) + return match.group() + + macro_dict = { 'script' : msg, + 'bssid' : bssid, + 'essid' : essid } + regex = re.compile(r'%\{([a-zA-Z0-9]+)\}') + expanded = regex.sub(repl, script) + print "Expanded '%s' to '%s'" % (script, expanded) + return expanded + class Controller(object): """ Parent class for the different interface types. """ @@ -138,8 +162,6 @@ class Controller(object): self._dhcp_client = value if self.iface: self.iface.DHCP_CLIENT = value - self.iface.CheckDHCP() - def get_dhcp_client(self): return self._dhcp_client dhcp_client = property(get_dhcp_client, set_dhcp_client) @@ -166,6 +188,7 @@ class Controller(object): return True def StopDHCP(self): + """ Stops all running DHCP clients. """ return BACKEND.StopDHCP() def GetIP(self, ifconfig=""): @@ -214,32 +237,11 @@ class Controller(object): """ return self.iface.Down() - -def expand_script_macros(script, msg, bssid, essid): - """Expands any supported macros in a script. - - Keyword arguments: - script -- the script to execute. - msg -- the name of the script, %{script} will be expanded to this. - bssid -- the bssid of the network we connect to, defaults to 'wired'. - essid -- the essid of the network we connect to, defaults to 'wired'.""" - - macro_dict = { 'script' : msg, - 'bssid' : bssid, - 'essid' : essid } - # Define a replacement function, this is done here so that %{script} will be substituted correctly - def repl(match): - macro = match.group( 1 ).lower() - if macro_dict.has_key( macro ): - return macro_dict[macro] - print 'Warning: found illegal macro %s in %s script' % (macro, msg) - return match.group() - - regex = re.compile( r'%\{([a-zA-Z0-9]+)\}' ) - expanded = regex.sub( repl, script ) - print "Expanded '%s' to '%s'" % (script, expanded) - return expanded + def AppAvailable(self, app): + """ Determine if the given application is installed. """ + return self.iface.AppAvailable(app) + class ConnectThread(threading.Thread): """ A class to perform network connections in a multi-threaded way. diff --git a/wicd/prefs.py b/wicd/prefs.py index a674ea1..20ff564 100644 --- a/wicd/prefs.py +++ b/wicd/prefs.py @@ -32,6 +32,7 @@ import gtk.glade from wicd import misc from wicd import wpath +from wicd import dbusmanager from wicd.misc import checkboxTextboxToggle, noneToBlankString daemon = None @@ -40,17 +41,37 @@ wired = None language = misc.get_language_list_gui() +def setup_dbus(): + global daemon, wireless, wired + daemon = dbusmanager.get_interface('daemon') + wireless = dbusmanager.get_interface('wireless') + wired = dbusmanager.get_interface('wired') + class PreferencesDialog(object): """ Class for handling the wicd preferences dialog window. """ def __init__(self, wTree, dbus): - global daemon, wireless, wired - daemon = dbus['daemon'] - wireless = dbus['wireless'] - wired = dbus['wired'] + setup_dbus() self.wTree = wTree self.prep_settings_diag() self.load_preferences_diag() + def _setup_external_app_radios(self, radio_list, get_method, set_method): + """ Generic function for setting up external app radios. """ + def set_available(apps): + for app in apps: + app.set_sensitive(daemon.GetAppAvailable(app.get_label())) + + # Disable radios for apps that aren't installed. + set_available(radio_list[1:]) + selected_app = get_method() + # Make sure the app we want to select is actually available. + if radio_list[selected_app].get_property("sensitive"): + radio_list[selected_app].set_active(True) + else: + # If it isn't, default to Automatic. + set_method(misc.AUTO) + radio_list[misc.AUTO].set_active(True) + def load_preferences_diag(self): """ Loads data into the preferences Dialog. """ @@ -62,19 +83,37 @@ class PreferencesDialog(object): dhcp_list = [self.dhcpautoradio, self.dhclientradio, self.dhcpcdradio, self.pumpradio] - dhcp_method = daemon.GetDHCPClient() - print 'DHCP method is %s' % daemon.GetDHCPClient() - dhcp_list[dhcp_method].set_active(True) + self._setup_external_app_radios(dhcp_list, daemon.GetDHCPClient, + daemon.SetDHCPClient) + #set_available(dhcp_list[1:]) + #dhcp_method = daemon.GetDHCPClient() + #if dhcp_list[dhcp_method].get_sensitive(): + #dhcp_list[dhcp_method].set_active(True) + #else: + #daemon.SetDHCPClient(misc.AUTO) + #self.dhcpautoradio.set_active(True) wired_link_list = [self.linkautoradio, self.ethtoolradio, self.miitoolradio] - wired_link_method = daemon.GetLinkDetectionTool() - wired_link_list[wired_link_method].set_active(True) + self._setup_external_app_radios(wired_link_list, + daemon.GetLinkDetectionTool, + daemon.SetLinkDetectionTool) + #set_available(wired_link_list[1:]) + #wired_link_method = daemon.GetLinkDetectionTool() + #if wired_link_list[wired_link_method].get_sensitive(): + #wired_link_list[wired_link_method].set_active(True) flush_list = [self.flushautoradio, self.ipflushradio, self.routeflushradio] - flush_method = daemon.GetFlushTool() - flush_list[flush_method].set_active(True) + self._setup_external_app_radios(flush_list, daemon.GetFlushTool, + daemon.SetFlushTool) + #flush_method = daemon.GetFlushTool() + #flush_list[flush_method].set_active(True) + + sudo_list = [self.sudoautoradio, self.gksudoradio, self.kdesuradio, + self.ktsussradio] + self._setup_external_app_radios(sudo_list, daemon.GetSudoApp, + daemon.SetAudoApp) auto_conn_meth = daemon.GetWiredAutoConnectMethod() if auto_conn_meth == 1: @@ -185,6 +224,16 @@ class PreferencesDialog(object): else: flush_tool = misc.ROUTE daemon.SetFlushTool(flush_tool) + + if self.sudoautoradio.get_active(): + sudo_tool = misc.AUTO + elif self.gksudoradio.get_active(): + sudo_tool = misc.GKSUDO + elif self.kdesuradio.get_active(): + sudo_tool = misc.KDESU + else: + sudo_tool = misc.KTSUSS + daemon.SetSudoApp(sudo_tool) [width, height] = self.dialog.get_size() daemon.WriteWindowSize(width, height, "pref") @@ -289,6 +338,12 @@ class PreferencesDialog(object): 'wicd_auto_config') self.ipflushradio = setup_label("ip_flush_radio") self.routeflushradio = setup_label("route_flush_radio") + + # Graphical Sudo Apps + self.sudoautoradio = setup_label("sudo_auto_radio", "wicd_auto_config") + self.gksudoradio = setup_label("gksudo_radio") + self.kdesuradio = setup_label("kdesu_radio") + self.ktsussradio = setup_label("ktsuss_radio") # Replacement for the combo box hack self.wpadrivercombo = build_combobox("pref_wpa_combobox") @@ -317,11 +372,10 @@ class PreferencesDialog(object): # Load backend combobox self.backends = daemon.GetBackendList() self.be_descriptions = daemon.GetBackendDescriptionDict() - # "" is included as a hack for DBus limitations, so we remove it. - self.backends.remove("") for x in self.backends: - self.backendcombo.append_text(x) + if x: + self.backendcombo.append_text(x) def be_combo_changed(self, combo): """ Update the description label for the given backend. """ diff --git a/wicd/wicd-daemon.py b/wicd/wicd-daemon.py index acf8683..f0daf91 100644 --- a/wicd/wicd-daemon.py +++ b/wicd/wicd-daemon.py @@ -99,6 +99,7 @@ class WicdDaemon(dbus.service.Object): self.dhcp_client = 0 self.link_detect_tool = 0 self.flush_tool = 0 + self.sudo_app = 0 # This will speed up the scanning process - if a client doesn't # need a fresh scan, just feed them the old one. A fresh scan @@ -569,6 +570,11 @@ class WicdDaemon(dbus.service.Object): """ return bool(self.need_profile_chooser) + + @dbus.service.method("org.wicd.daemon") + def GetAppAvailable(self, app): + """ Determine if a given application is available.""" + return bool(self.wifi.AppAvailable(app) or self.wired.AppAvailable(app)) @dbus.service.method('org.wicd.daemon') def GetDHCPClient(self): @@ -630,6 +636,17 @@ class WicdDaemon(dbus.service.Object): self.wired.flush_tool = int(flush_tool) self.wifi.flush_tool = int(flush_tool) self.config.set("Settings", "flush_tool", flush_tool, write=True) + + @dbus.service.method('org.wicd.daemon') + def GetSudoApp(self): + """ Get the preferred sudo app. """ + return self.sudo_app + + @dbus.service.method('org.wicd.daemon') + def SetSudoApp(self, sudo_app): + """ Set the preferred sudo app. """ + self.sudo_app = sudo_app + self.config.set("Settings", "sudo_app", sudo_app, write=True) @dbus.service.method('org.wicd.daemon') def WriteWindowSize(self, width, height, win_name): @@ -814,7 +831,6 @@ class WicdDaemon(dbus.service.Object): b_wired = self.wired_bus b_wifi = self.wireless_bus app_conf= self.config - verbose = True # Load the backend. be_def = 'external' self.SetBackend(app_conf.get("Settings", "backend", default=be_def)) @@ -845,15 +861,16 @@ class WicdDaemon(dbus.service.Object): default=True)) self.SetDebugMode(app_conf.get("Settings", "debug_mode", default=False)) self.SetWiredAutoConnectMethod(app_conf.get("Settings", - "wired_connect_mode", - default=1)) + "wired_connect_mode", + default=1)) self.SetSignalDisplayType(app_conf.get("Settings", - "signal_display_type", - default=0)) + "signal_display_type", + default=0)) self.SetDHCPClient(app_conf.get("Settings", "dhcp_client", default=0)) self.SetLinkDetectionTool(app_conf.get("Settings", "link_detect_tool", default=0)) self.SetFlushTool(app_conf.get("Settings", "flush_tool", default=0)) + self.SetSudoApp(app_conf.get("Settings", "sudo_app", default=0)) self.SetPreferWiredNetwork(app_conf.get("Settings", "prefer_wired", default=False)) app_conf.write() diff --git a/wicd/wnettools.py b/wicd/wnettools.py index ac52d31..421742c 100644 --- a/wicd/wnettools.py +++ b/wicd/wnettools.py @@ -38,6 +38,7 @@ from string import maketrans, translate import wpath import misc +from misc import find_path RALINK_DRIVER = 'ralink legacy' @@ -160,11 +161,6 @@ class BaseInterface(object): self.iface = _sanitize_string_strict(iface) self.verbose = verbose self.DHCP_CLIENT = None - self.DHCP_CMD = None - self.DHCP_RELEASE = None - self.MIITOOL_FOUND = False - self.ETHTOOL_FOUND = False - self.IP_FOUND = False self.flush_tool = None self.link_detect = None @@ -181,29 +177,94 @@ class BaseInterface(object): """ self.iface = _sanitize_string_strict(str(iface)) - def _find_client_path(self, client): + def _find_program_path(self, program): """ Determines the full path for the given program. - Searches a hardcoded list of paths for a given program name. + Searches for a given program name on the PATH. Keyword arguments: - client -- The name of the program to search for + program -- The name of the program to search for Returns: The full path of the program or None """ - paths = ['/sbin/', '/usr/sbin/', '/bin/', '/usr/bin/', - '/usr/local/sbin/', '/usr/local/bin/'] - for path in paths: - if os.path.exists("%s%s" % (path, client)): - return "%s%s" % (path, client) - if self.verbose: - print "WARNING: No path found for %s" % (client) - return None + path = find_path(program) + if not path and self.verbose: + print "WARNING: No path found for %s" % program + return path + + def _get_dhcp_command(self, flavor=None): + """ Returns the correct DHCP client command. + + Given a type of DHCP request (create or release a lease), + this method will build a command to complete the request + using the correct dhcp client, and cli options. + + """ + def get_client_name(cl): + """ Converts the integer value for a dhcp client to a string. """ + if (cl in [misc.DHCLIENT, "dhclient"] or + (cl == misc.AUTO and self.dhclient_cmd)): + client = "dhclient" + cmd = self.dhclient_cmd + elif (cl in [misc.DHCPCD, "dhcpcd"] or + (cl == misc.AUTO and self.dhcpcd_cmd)): + client = "dhcpcd" + cmd = self.dhcpcd_cmd + elif (cl in [misc.PUMP, "pump"] or + (cl == misc.AUTO and self.pump_cmd)): + client = "pump" + cmd = self.pump_cmd + else: + client = None + cmd = "" + return (client, cmd) + + connect_dict = { + "dhclient" : r"%s %s", + "pump" : r"%s -i %s", + "dhcpcd" : r"%s %s", + } + release_dict = { + "dhclient" : r"%s -r %s", + "pump" : r"%s -r -i %s", + "dhcpcd" : r"%s -k %s", + } + (client_name, cmd) = get_client_name(self.DHCP_CLIENT) + if not client_name or not cmd: + print "WARNING: Failed to find a valid dhcp client!" + return "" + + if flavor == "connect": + return connect_dict[client_name] % (cmd, self.iface) + elif flavor == "release": + return release_dict[client_name] % (cmd, self.iface) + else: + return str(cmd) + + def AppAvailable(self, app): + """ Return whether a given app is available. + + Given the name of an executable, determines if it is + available for use by checking for a defined 'app'_cmd + instance variable. + + """ + return bool(self.__dict__.get("%s_cmd" % app.replace("-", ""))) + + def Check(self): + """ Check that all required tools are available. """ + # THINGS TO CHECK FOR: ethtool, pptp-linux, dhclient, host + self.CheckDHCP() + self.CheckWiredTools() + self.CheckWirelessTools() + self.CheckSudoApplications() + self.CheckRouteFlushTool() + def CheckDHCP(self): - """ Check for a valid DHCP client. + """ Check for the existence of valid DHCP clients. Checks for the existence of a supported DHCP client. If one is found, the appropriate values for DHCP_CMD, DHCP_RELEASE, and @@ -211,97 +272,31 @@ class BaseInterface(object): warning is printed. """ - def get_client_name(cl): - """ Converts the integer value for a dhcp client to a string. """ - if cl in [misc.DHCLIENT, "dhclient"]: - client = "dhclient" - elif cl in [misc.DHCPCD, "dhcpcd"]: - client = "dhcpcd" - else: - client = "pump" - return client - if self.DHCP_CLIENT: - dhcp_client = get_client_name(self.DHCP_CLIENT) - dhcp_path = self._find_client_path(dhcp_client) - if not dhcp_path: - print "WARNING: Could not find selected dhcp client. Wicd " + \ - " will try to find another supported client." - if not self.DHCP_CLIENT or not dhcp_path: - dhcp_client = None - dhcp_path = None - dhcpclients = ["dhclient", "dhcpcd", "pump"] - for client in dhcpclients: - dhcp_path = self._find_client_path(client) - if dhcp_path: - dhcp_client = client - break - - if not dhcp_client: - print "WARNING: No supported DHCP Client could be found!" - return - elif dhcp_client in [misc.DHCLIENT, "dhclient"]: - dhcp_client = misc.DHCLIENT - dhcp_cmd = dhcp_path - dhcp_release = dhcp_cmd + " -r" - elif dhcp_client in [misc.PUMP, "pump"]: - dhcp_client = misc.PUMP - dhcp_cmd = dhcp_path + " -i" - dhcp_release = dhcp_cmd + " -r -i" - elif dhcp_client in [misc.DHCPCD, "dhcpcd"]: - dhcp_client = misc.DHCPCD - dhcp_cmd = dhcp_path - dhcp_release = dhcp_cmd + " -k" - else: - dhcp_client = None - dhcp_cmd = None - dhcp_release = None - - self.DHCP_CMD = dhcp_cmd - self.DHCP_RELEASE = dhcp_release - self.DHCP_CLIENT = dhcp_client - + self.dhclient_cmd = self._find_program_path("dhclient") + self.dhcpcd_cmd = self._find_program_path("dhcpcd") + self.pump_cmd = self._find_program_path("pump") + def CheckWiredTools(self): """ Check for the existence of ethtool and mii-tool. """ - miitool_path = self._find_client_path("mii-tool") - if miitool_path: - self.miitool_cmd = miitool_path - self.MIITOOL_FOUND = True - else: - self.miitool_cmd = None - self.MIITOOL_FOUND = False - - ethtool_path = self._find_client_path("ethtool") - if ethtool_path: - self.ethtool_cmd = ethtool_path - self.ETHTOOL_FOUND = True - else: - self.ethtool_cmd = None - self.ETHTOOL_FOUND = False + self.miitool_cmd = self._find_program_path("mii-tool") + self.ethtool_cmd = self._find_program_path("ethtool") def CheckWirelessTools(self): """ Check for the existence of wpa_cli """ - wpa_cli_path = self._find_client_path("wpa_cli") - if wpa_cli_path: - self.WPA_CLI_FOUND = True - else: - self.WPA_CLI_FOUND = False + self.wpa_cli_cmd = self._find_program_path("wpa_cli") + if not self.wpa_cli_cmd: print "wpa_cli not found. Authentication will not be validated." - - def Check(self): - """ Check that all required tools are available. """ - # THINGS TO CHECK FOR: ethtool, pptp-linux, dhclient, host - self.CheckDHCP() - self.CheckWiredTools() - self.CheckWirelessTools() - - ip_path = self._find_client_path("ip") - if ip_path: - self.ip_cmd = ip_path - self.IP_FOUND = True - else: - self.ip_cmd = None - self.IP_FOUND = False + + def CheckRouteFlushTool(self): + """ Check for a route flush tool. """ + self.ip_cmd = self._find_program_path("ip") + self.route_cmd = self._find_program_path("route") + + def CheckSudoApplications(self): + self.gksudo_cmd = self._find_program_path("gksudo") + self.kdesu_cmd = self._find_program_path("kdesu") + self.ktsuss_cmd = self._find_program_path("ktsuss") def Up(self): """ Bring the network interface up. @@ -461,7 +456,8 @@ class BaseInterface(object): """ if not self.iface: return False - cmd = self.DHCP_CMD + " " + self.iface + cmd = "%s %s" % (self._get_dhcp_command('connect'), self.iface) + #cmd = self.DHCP_CMD + " " + self.iface if self.verbose: print cmd pipe = misc.Run(cmd, include_stderr=True, return_pipe=True) @@ -476,19 +472,20 @@ class BaseInterface(object): def ReleaseDHCP(self): """ Release the DHCP lease for this interface. """ if not self.iface: return False - cmd = self.DHCP_RELEASE + " " + self.iface + cmd = "%s %s" % (self._get_dhcp_command("release"), self.iface) + #cmd = self.DHCP_RELEASE + " " + self.iface if self.verbose: print cmd misc.Run(cmd) def FlushRoutes(self): """ Flush all network routes. """ if not self.iface: return False - if self.IP_FOUND and self.flush_tool == misc.IP: - #cmd = "ip route flush dev " + self.iface - cmds = ['ip route flush all'] - else: - cmds = ['route del default'] + if self.route_cmd and self.flush_tool == misc.ROUTE: + cmds = ['%s del default' % self.route_cmd] cmds.append('route del dev %s' % self.iface) + elif self.ip_cmd and self.flush_tool == misc.IP: + #cmd = "ip route flush dev " + self.iface + cmds = ['%s route flush all' % self.ip_cmd] for cmd in cmds: if self.verbose: print cmd misc.Run(cmd) From 28b6aac2dbe154f6d349224ef28f20b30006a4ff Mon Sep 17 00:00:00 2001 From: Dan O'Reilly Date: Sun, 1 Feb 2009 23:32:28 -0500 Subject: [PATCH 2/6] Remove some comments. --- wicd/prefs.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/wicd/prefs.py b/wicd/prefs.py index 20ff564..8ec7ae1 100644 --- a/wicd/prefs.py +++ b/wicd/prefs.py @@ -85,30 +85,17 @@ class PreferencesDialog(object): self.pumpradio] self._setup_external_app_radios(dhcp_list, daemon.GetDHCPClient, daemon.SetDHCPClient) - #set_available(dhcp_list[1:]) - #dhcp_method = daemon.GetDHCPClient() - #if dhcp_list[dhcp_method].get_sensitive(): - #dhcp_list[dhcp_method].set_active(True) - #else: - #daemon.SetDHCPClient(misc.AUTO) - #self.dhcpautoradio.set_active(True) wired_link_list = [self.linkautoradio, self.ethtoolradio, self.miitoolradio] self._setup_external_app_radios(wired_link_list, daemon.GetLinkDetectionTool, daemon.SetLinkDetectionTool) - #set_available(wired_link_list[1:]) - #wired_link_method = daemon.GetLinkDetectionTool() - #if wired_link_list[wired_link_method].get_sensitive(): - #wired_link_list[wired_link_method].set_active(True) flush_list = [self.flushautoradio, self.ipflushradio, self.routeflushradio] self._setup_external_app_radios(flush_list, daemon.GetFlushTool, daemon.SetFlushTool) - #flush_method = daemon.GetFlushTool() - #flush_list[flush_method].set_active(True) sudo_list = [self.sudoautoradio, self.gksudoradio, self.kdesuradio, self.ktsussradio] From 315ff97d87b3dd22c15900151b1ae5be5726ce06 Mon Sep 17 00:00:00 2001 From: Dan O'Reilly Date: Mon, 2 Feb 2009 23:05:29 -0500 Subject: [PATCH 3/6] Simplify the inheritance of static wnettools functions in the backends. Make sure we select a default route flushing tool. --- wicd/backends/be-external.py | 30 +++--------------------------- wicd/backends/be-ioctl.py | 30 ++++-------------------------- wicd/wnettools.py | 8 +++++++- 3 files changed, 14 insertions(+), 54 deletions(-) diff --git a/wicd/backends/be-external.py b/wicd/backends/be-external.py index 4d56be1..d6b891c 100644 --- a/wicd/backends/be-external.py +++ b/wicd/backends/be-external.py @@ -31,9 +31,9 @@ class WirelessInterface() -- Control a wireless network interface. # along with this program. If not, see . # -import wicd.misc as misc -import wicd.wnettools as wnettools - +from wicd import misc +from wicd import wnettools +from wicd.wnettools import * import re import os import os.path @@ -78,30 +78,6 @@ auth_pattern = re.compile('.*wpa_state=(.*?)\n', re.I | re.M | re.S) RALINK_DRIVER = 'ralink legacy' -def SetDNS(*args, **kargs): - """ Call the wnettools SetDNS method. """ - return wnettools.SetDNS(*args, **kargs) - -def GetDefaultGateway(*args, **kargs): - """ Call the wnettools GetDefaultGateway method. """ - return wnettools.GetDefaultGateway(*args, **kargs) - -def StopDHCP(*args, **kargs): - """ Call the wnettools StopDHCP method. """ - return wnettools.StopDHCP(*args, **kargs) - -def GetWirelessInterfaces(*args, **kargs): - """ Call the wnettools GetWirelessInterfaces method. """ - return wnettools.GetWirelessInterfaces(*args, **kargs) - -def GetWiredInterfaces(*args, **kargs): - """ Call the wnettools GetWiredInterfaces method. """ - return wnettools.GetWiredInterfaces(*args, **kargs) - -def IsValidWpaSuppDriver(*args, **kargs): - """ Call the wnettools IsValidWpaSuppDrive method. """ - return wnettools.IsValidWpaSuppDriver(*args, **kargs) - def NeedsExternalCalls(*args, **kargs): """ Return True, since this backend using iwconfig/ifconfig. """ return True diff --git a/wicd/backends/be-ioctl.py b/wicd/backends/be-ioctl.py index bfcfece..b930688 100644 --- a/wicd/backends/be-ioctl.py +++ b/wicd/backends/be-ioctl.py @@ -31,9 +31,10 @@ class WirelessInterface() -- Control a wireless network interface. # along with this program. If not, see . # -import wicd.misc as misc -import wicd.wnettools as wnettools -import wicd.wpath as wpath +from wicd import misc +from wicd import wnettools +from wicd import wpath +from wicd.wnettools import * import iwscan import wpactrl @@ -82,29 +83,6 @@ SIOCGMIIPHY = 0x8947 SIOCETHTOOL = 0x8946 SIOCGIFFLAGS = 0x8913 -def SetDNS(*args, **kargs): - """ Call the wnettools SetDNS method. """ - return wnettools.SetDNS(*args, **kargs) - -def GetDefaultGateway(*args, **kargs): - """ Call the wnettools GetDefaultGateway method. """ - return wnettools.GetDefaultGateway(*args, **kargs) - -def StopDHCP(*args, **kargs): - """ Call the wnettools StopDHCP method. """ - return wnettools.StopDHCP(*args, **kargs) - -def GetWirelessInterfaces(*args, **kargs): - """ Call the wnettools GetWirelessInterfaces method. """ - return wnettools.GetWirelessInterfaces(*args, **kargs) - -def GetWiredInterfaces(*args, **kargs): - """ Call the wnettools GetWiredInterfaces method. """ - return wnettools.GetWiredInterfaces(*args, **kargs) - -def IsValidWpaSuppDriver(*args, **kargs): - """ Call the wnettools IsValidWpaSuppDrive method. """ - return wnettools.IsValidWpaSuppDriver(*args, **kargs) def get_iw_ioctl_result(iface, call): """ Makes the given ioctl call and returns the results. diff --git a/wicd/wnettools.py b/wicd/wnettools.py index 421742c..3030b4e 100644 --- a/wicd/wnettools.py +++ b/wicd/wnettools.py @@ -47,6 +47,9 @@ blacklist_strict = '!"#$%&\'()*+,./:;<=>?@[\\]^`{|}~ ' blacklist_norm = ";`$!*|><&\\" blank_trans = maketrans("", "") +__all__ = ["SetDNS", "GetDefaultGateway", "GetWiredInterfaces", "StopDHCP", + "GetWirelessInterfaces", "IsValidWpaSuppDriver", "NeedsExternalCalls"] + def _sanitize_string(string): if string: return translate(str(string), blank_trans, blacklist_norm) @@ -483,9 +486,12 @@ class BaseInterface(object): if self.route_cmd and self.flush_tool == misc.ROUTE: cmds = ['%s del default' % self.route_cmd] cmds.append('route del dev %s' % self.iface) - elif self.ip_cmd and self.flush_tool == misc.IP: + elif self.ip_cmd: #cmd = "ip route flush dev " + self.iface cmds = ['%s route flush all' % self.ip_cmd] + else: + print "No flush command available!" + cmds = [] for cmd in cmds: if self.verbose: print cmd misc.Run(cmd) From 63478420008940ac54d6a955e6a10a4b6ca17926 Mon Sep 17 00:00:00 2001 From: Dan O'Reilly Date: Mon, 2 Feb 2009 23:39:52 -0500 Subject: [PATCH 4/6] Minor formatting tweak --- wicd/wnettools.py | 1 - 1 file changed, 1 deletion(-) diff --git a/wicd/wnettools.py b/wicd/wnettools.py index 3030b4e..7d6dbe4 100644 --- a/wicd/wnettools.py +++ b/wicd/wnettools.py @@ -275,7 +275,6 @@ class BaseInterface(object): warning is printed. """ - self.dhclient_cmd = self._find_program_path("dhclient") self.dhcpcd_cmd = self._find_program_path("dhcpcd") self.pump_cmd = self._find_program_path("pump") From e23af9b41388b14d38aefd95d2919a35208aff8d Mon Sep 17 00:00:00 2001 From: Dan O'Reilly Date: Mon, 2 Feb 2009 23:47:54 -0500 Subject: [PATCH 5/6] Make GetWirelessInterfaces() return a list instead of the first interface. Also make the networking.py layer pull the first entry from the list. Some documentation cleanup. --- wicd/backends/be-external.py | 2 -- wicd/backends/be-ioctl.py | 2 -- wicd/networking.py | 6 +++++- wicd/wnettools.py | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/wicd/backends/be-external.py b/wicd/backends/be-external.py index d6b891c..b96880c 100644 --- a/wicd/backends/be-external.py +++ b/wicd/backends/be-external.py @@ -6,8 +6,6 @@ This module implements functions to control and obtain information from network interfaces. -def SetDNS() -- Set the DNS servers of the system. -def GetWirelessInterfaces() -- Get the wireless interfaces available. class Interface() -- Control a network interface. class WiredInterface() -- Control a wired network interface. class WirelessInterface() -- Control a wireless network interface. diff --git a/wicd/backends/be-ioctl.py b/wicd/backends/be-ioctl.py index b930688..b43f6d6 100644 --- a/wicd/backends/be-ioctl.py +++ b/wicd/backends/be-ioctl.py @@ -6,8 +6,6 @@ This module implements functions to control and obtain information from network interfaces. It utilizes ioctl calls and python modules to obtain this information whenever possible. -def SetDNS() -- Set the DNS servers of the system. -def GetWirelessInterfaces() -- Get the wireless interfaces available. class Interface() -- Control a network interface. class WiredInterface() -- Control a wired network interface. class WirelessInterface() -- Control a wireless network interface. diff --git a/wicd/networking.py b/wicd/networking.py index cc6a118..5ee9d05 100644 --- a/wicd/networking.py +++ b/wicd/networking.py @@ -668,7 +668,11 @@ class Wireless(Controller): The first available wireless interface. """ - return BACKEND.GetWirelessInterfaces() + ifaces = BACKEND.GetWirelessInterfaces() + if ifaces: + return ifaces[0] + else: + return None def GetKillSwitchStatus(self): """ Get the current status of the Killswitch. diff --git a/wicd/wnettools.py b/wicd/wnettools.py index 7d6dbe4..b4bb5f6 100644 --- a/wicd/wnettools.py +++ b/wicd/wnettools.py @@ -127,7 +127,7 @@ def GetWirelessInterfaces(): ifnames = [iface for iface in os.listdir(dev_dir) if os.path.isdir(dev_dir + iface) and 'wireless' in os.listdir(dev_dir + iface)] - return bool(ifnames) and ifnames[0] or None + return ifnames def GetWiredInterfaces(): """ Returns a list of wired interfaces on the system. """ From b54dbcff926df05772dc3190909536d7b18cdb2c Mon Sep 17 00:00:00 2001 From: Dan O'Reilly Date: Tue, 3 Feb 2009 00:05:11 -0500 Subject: [PATCH 6/6] Make sure debug settings are propogated down the stack as soon a the daemon loads. --- wicd/networking.py | 12 ++++++------ wicd/wicd-daemon.py | 9 +++++---- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/wicd/networking.py b/wicd/networking.py index 5ee9d05..02a659f 100644 --- a/wicd/networking.py +++ b/wicd/networking.py @@ -132,7 +132,7 @@ def expand_script_macros(script, msg, bssid, essid): class Controller(object): """ Parent class for the different interface types. """ - def __init__(self): + def __init__(self, debug=False): """ Initialise the class. """ self.global_dns_1 = None self.global_dns_2 = None @@ -141,7 +141,7 @@ class Controller(object): self.global_search_dom = None self._dhcp_client = None self._flush_tool = None - self._debug = None + self._debug = debug self._backend = None self.connecting_thread = None self.before_script = None @@ -477,9 +477,9 @@ class ConnectThread(threading.Thread): class Wireless(Controller): """ A wrapper for common wireless interface functions. """ - def __init__(self): + def __init__(self, debug=False): """ Initialize the class. """ - Controller.__init__(self) + Controller.__init__(self, debug=debug) self._wpa_driver = None self._wireless_interface = None self.wiface = None @@ -844,9 +844,9 @@ class WirelessConnectThread(ConnectThread): class Wired(Controller): """ A wrapper for common wired interface functions. """ - def __init__(self): + def __init__(self, debug=False): """ Initialise the class. """ - Controller.__init__(self) + Controller.__init__(self, debug=debug) self.wpa_driver = None self._link_detect = None self._wired_interface = None diff --git a/wicd/wicd-daemon.py b/wicd/wicd-daemon.py index f0daf91..876c33f 100644 --- a/wicd/wicd-daemon.py +++ b/wicd/wicd-daemon.py @@ -79,10 +79,11 @@ class WicdDaemon(dbus.service.Object): """ Initializes the daemon DBus object. """ dbus.service.Object.__init__(self, bus_name=bus_name, object_path=object_path) - self.wifi = networking.Wireless() - self.wired = networking.Wired() self.config = ConfigManager(os.path.join(wpath.etc, "manager-settings.conf")) + self._debug_mode = bool(self.config.get("Settings", "debug_mode")) + self.wifi = networking.Wireless(debug=self._debug_mode) + self.wired = networking.Wired(debug=self._debug_mode) self.wired_bus= WiredDaemon(bus_name, self, wired=self.wired) self.wireless_bus = WirelessDaemon(bus_name, self, wifi=self.wifi) self.forced_disconnect = False @@ -274,8 +275,8 @@ class WicdDaemon(dbus.service.Object): """ Sets if debugging mode is on or off. """ self.config.set("Settings", "debug_mode", debug, write=True) self.debug_mode = misc.to_bool(debug) - self.wifi.debug = self.debug_mode - self.wired.debug = self.debug_mode + self.wifi.debug = debug + self.wired.debug = debug self.wireless_bus.debug_mode = debug self.wired_bus.debug_mode = debug