diff --git a/wicd/dbusmanager.py b/wicd/dbusmanager.py index 11a8d78..cc05e10 100644 --- a/wicd/dbusmanager.py +++ b/wicd/dbusmanager.py @@ -2,7 +2,7 @@ """ The wicd DBus Manager. -A module for storing wicd's dbus interfaces. +A module for managing wicd's dbus interfaces. """ @@ -24,6 +24,31 @@ A module for storing wicd's dbus interfaces. # import dbus +if getattr(dbus, "version", (0, 0, 0)) < (0, 80, 0): + import dbus.glib +else: + from dbus.mainloop.glib import DBusGMainLoop + DBusGMainLoop(set_as_default=True) + +DBUS_MANAGER = None + +def get_dbus_ifaces(): + return DBUS_MANAGER.get_dbus_ifaces() + +def get_interface(iface): + return DBUS_MANAGER.get_interface(iface) + +def get_bus(): + return DBUS_MANAGER.get_bus() + +def set_mainloop(): + return DBUS_MANAGER.connect_to_mainloop() + +def connect_to_dbus(): + return DBUS_MANAGER.connect_to_dbus() + +def threads_init(): + dbus.mainloop.glib.threads_init() class DBusManager(object): """ Manages the DBus objects used by wicd. """ @@ -43,6 +68,9 @@ class DBusManager(object): """ Returns the loaded SystemBus. """ return self._bus + def set_mainloop(self, loop): + dbus.set_default_main_loop(loop) + def connect_to_dbus(self): """ Connects to wicd's dbus interfaces and loads them into a dict. """ proxy_obj = self._bus.get_object("org.wicd.daemon", '/org/wicd/daemon') @@ -57,4 +85,6 @@ class DBusManager(object): wired = dbus.Interface(proxy_obj, 'org.wicd.daemon.wired') self._dbus_ifaces = {"daemon" : daemon, "wireless" : wireless, - "wired" : wired} + "wired" : wired} + +DBUS_MANAGER = DBusManager() \ No newline at end of file diff --git a/wicd/gui.py b/wicd/gui.py index 6c4de68..6b69fea 100644 --- a/wicd/gui.py +++ b/wicd/gui.py @@ -36,9 +36,9 @@ from dbus import version as dbus_version from wicd import misc from wicd import wpath +from wicd import dbusmanager from wicd.misc import noneToString from wicd.netentry import WiredNetworkEntry, WirelessNetworkEntry -from wicd.dbusmanager import DBusManager from wicd.prefs import PreferencesDialog if __name__ == '__main__': @@ -50,41 +50,32 @@ try: except: pass -if not dbus_version or (dbus_version < (0, 80, 0)): - import dbus.glib -else: - from dbus.mainloop.glib import DBusGMainLoop - DBusGMainLoop(set_as_default=True) - proxy_obj = daemon = wireless = wired = bus = None language = misc.get_language_list_gui() -def setup_dbus(dbus_man=None): - global bus, daemon, wireless, wired, dbus_manager - if dbus_man: - dbus_manager = dbus_man - else: - dbus_manager = DBusManager() +def setup_dbus(): + global bus, daemon, wireless, wired + + try: + dbusmanager.connect_to_dbus() + except DBusException: + print "Can't connect to the daemon, trying to start it automatically..." + misc.PromptToStartDaemon() try: - dbus_manager.connect_to_dbus() + dbusmanager.connect_to_dbus() except DBusException: - print "Can't connect to the daemon, trying to start it automatically..." - misc.PromptToStartDaemon() - try: - dbus_manager.connect_to_dbus() - except DBusException: - error(None, "Could not connect to wicd's D-Bus interface. " + - "Make sure the daemon is started.") - sys.exit(1) + error(None, "Could not connect to wicd's D-Bus interface. " + + "Make sure the daemon is started.") + sys.exit(1) - bus = dbus_manager.get_bus() - dbus_ifaces = dbus_manager.get_dbus_ifaces() + bus = dbusmanager.get_bus() + dbus_ifaces = dbusmanager.get_dbus_ifaces() daemon = dbus_ifaces['daemon'] wireless = dbus_ifaces['wireless'] wired = dbus_ifaces['wired'] + return True - - + def error(parent, message): """ Shows an error dialog """ dialog = gtk.MessageDialog(parent, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, @@ -172,7 +163,7 @@ class WiredProfileChooser: """ Initializes and runs the wired profile chooser. """ # Import and init WiredNetworkEntry to steal some of the # functions and widgets it uses. - wired_net_entry = WiredNetworkEntry(dbus_manager.get_dbus_ifaces()) + wired_net_entry = WiredNetworkEntry(dbusmanager.get_dbus_ifaces()) dialog = gtk.Dialog(title = language['wired_network_found'], flags = gtk.DIALOG_MODAL, @@ -220,20 +211,21 @@ class WiredProfileChooser: class appGui(object): """ The main wicd GUI class. """ - def __init__(self, dbus_man=None, standalone=False): + def __init__(self, standalone=False): """ Initializes everything needed for the GUI. """ - if dbus_man: - setup_dbus(dbus_man) - if standalone: - bus.add_signal_receiver(self.dbus_scan_finished, 'SendEndScanSignal', - 'org.wicd.daemon.wireless') - bus.add_signal_receiver(self.dbus_scan_started, 'SendStartScanSignal', - 'org.wicd.daemon.wireless') - bus.add_signal_receiver(self.update_connect_buttons, 'StatusChanged', - 'org.wicd.daemon') + setup_dbus() gladefile = wpath.share + "wicd.glade" self.wTree = gtk.glade.XML(gladefile) + self.window = self.wTree.get_widget("window1") + size = daemon.ReadWindowSize("main") + width = size[0] + height = size[1] + if width > -1 and height > -1: + self.window.resize(int(width), int(height)) + else: + self.window.resize(gtk.gdk.screen_width() / 3, + gtk.gdk.screen_height() / 2) dic = { "refresh_clicked" : self.refresh_clicked, "quit_clicked" : self.exit, @@ -254,7 +246,6 @@ class appGui(object): probar = self.wTree.get_widget("progressbar") probar.set_text(language['connecting']) - self.window = self.wTree.get_widget("window1") self.network_list = self.wTree.get_widget("network_list_vbox") self.status_area = self.wTree.get_widget("connecting_hbox") self.status_bar = self.wTree.get_widget("statusbar") @@ -271,28 +262,27 @@ class appGui(object): self.standalone = standalone self.wpadrivercombo = None self.connecting = False + self.refreshing = False self.prev_state = None + self.network_list.set_sensitive(False) label = gtk.Label("%s..." % language['scanning']) self.network_list.pack_start(label) label.show() - self.network_list.set_sensitive(False) self.wait_for_events(0.2) self.window.connect('delete_event', self.exit) self.window.connect('key-release-event', self.key_event) - - size = daemon.ReadWindowSize("main") - width = size[0] - height = size[1] - if width > -1 and height > -1: - self.window.resize(int(width), int(height)) - else: - self.window.resize(gtk.gdk.screen_width() / 3, - gtk.gdk.screen_height() / 2) - + bus.add_signal_receiver(self.dbus_scan_finished, 'SendEndScanSignal', + 'org.wicd.daemon.wireless') + bus.add_signal_receiver(self.dbus_scan_started, 'SendStartScanSignal', + 'org.wicd.daemon.wireless') + bus.add_signal_receiver(self.update_connect_buttons, 'StatusChanged', + 'org.wicd.daemon') + bus.add_signal_receiver(setup_dbus, "DaemonClosing", "org.wicd.daemon") try: gobject.timeout_add_seconds(1, self.update_statusbar) except: gobject.timeout_add(1000, self.update_statusbar) + self.refresh_clicked() def create_adhoc_network(self, widget=None): @@ -367,7 +357,7 @@ class appGui(object): def settings_dialog(self, widget, event=None): """ Displays a general settings dialog. """ - pref = PreferencesDialog(self.wTree, dbus_manager.get_dbus_ifaces()) + pref = PreferencesDialog(self.wTree, dbusmanager.get_dbus_ifaces()) if pref.run() == 1: pref.save_results() pref.hide() @@ -408,7 +398,7 @@ class appGui(object): if not self.is_visible: return True try: - self.wTree.get_widget("progressbar").pulse() + gobject.idle_add(self.wTree.get_widget("progressbar").pulse) except: pass return True @@ -420,9 +410,9 @@ class appGui(object): updates the GUI status bar based on the results. """ - if not self.is_visible: + if not self.is_visible or self.refreshing: return True - + fast = not daemon.NeedsExternalCalls() wired_connecting = wired.CheckIfWiredConnecting() wireless_connecting = wireless.CheckIfWirelessConnecting() @@ -432,30 +422,29 @@ class appGui(object): if not self.pulse_active: self.pulse_active = True gobject.timeout_add(100, self.pulse_progress_bar) - self.network_list.set_sensitive(False) - self.status_area.show_all() + gobject.idle_add(self.network_list.set_sensitive, False) + gobject.idle_add(self.status_area.show_all) if self.statusID: - self.status_bar.remove(1, self.statusID) + gobject.idle_add(self.status_bar.remove, 1, self.statusID) if wireless_connecting: if not fast: iwconfig = wireless.GetIwconfig() else: iwconfig = '' - self.set_status(wireless.GetCurrentNetwork(iwconfig) + ': ' + + gobject.idle_add(self.set_status, wireless.GetCurrentNetwork(iwconfig) + ': ' + language[str(wireless.CheckWirelessConnectingMessage())]) if wired_connecting: - self.set_status(language['wired_network'] + ': ' + + gobject.idle_add(self.set_status, language['wired_network'] + ': ' + language[str(wired.CheckWiredConnectingMessage())]) return True else: if self.pulse_active: - self.pulse_progress_bar() self.pulse_active = False - self.network_list.set_sensitive(True) - self.status_area.hide_all() + gobject.idle_add(self.network_list.set_sensitive, True) + gobject.idle_add(self.status_area.hide_all) if self.statusID: - self.status_bar.remove(1, self.statusID) + gobject.idle_add(self.status_bar.remove, 1, self.statusID) # Determine connection status. if self.check_for_wired(wired.GetWiredIP("")): @@ -532,15 +521,16 @@ class appGui(object): """ if not self.connecting: - self.refresh_networks(fresh=False) + gobject.idle_add(self.refresh_networks, None, False, None) def dbus_scan_started(self): """ Called when a wireless scan starts. """ self.network_list.set_sensitive(False) - + def refresh_clicked(self, widget=None): """ Kick off an asynchronous wireless scan. """ - wireless.Scan(reply_handler=dummy, error_handler=dummy) + self.refreshing = True + wireless.Scan(reply_handler=None, error_handler=None) def refresh_networks(self, widget=None, fresh=True, hidden=None): """ Refreshes the network list. @@ -552,6 +542,11 @@ class appGui(object): iwconfig essid . """ + if fresh: + # Even if it is None, it can still be passed. + wireless.SetHiddenNetworkESSID(noneToString(hidden)) + self.refresh_clicked() + return print "refreshing..." self.network_list.set_sensitive(False) self.wait_for_events() @@ -564,7 +559,7 @@ class appGui(object): if wired.CheckPluggedIn() or daemon.GetAlwaysShowWiredInterface(): printLine = True # In this case we print a separator. - wirednet = WiredNetworkEntry(dbus_manager.get_dbus_ifaces()) + wirednet = WiredNetworkEntry(dbusmanager.get_dbus_ifaces()) self.network_list.pack_start(wirednet, False, False) wirednet.connect_button.connect("button-press-event", self.connect, "wired", 0, wirednet) @@ -573,11 +568,6 @@ class appGui(object): wirednet.advanced_button.connect("button-press-event", self.edit_advanced, "wired", 0, wirednet) - # Scan - if fresh: - # Even if it is None, it can still be passed. - wireless.SetHiddenNetworkESSID(noneToString(hidden)) - wireless.Scan() num_networks = wireless.GetNumberOfNetworks() instruct_label = self.wTree.get_widget("label_instructions") @@ -591,7 +581,7 @@ class appGui(object): sep.show() else: printLine = True - tempnet = WirelessNetworkEntry(x, dbus_manager.get_dbus_ifaces()) + tempnet = WirelessNetworkEntry(x, dbusmanager.get_dbus_ifaces()) self.network_list.pack_start(tempnet, False, False) tempnet.connect_button.connect("button-press-event", self.connect, "wireless", x, @@ -612,6 +602,7 @@ class appGui(object): label.show() self.update_connect_buttons(force_check=True) self.network_list.set_sensitive(True) + self.refreshing = False def save_settings(self, nettype, networkid, networkentry): """ Verifies and saves the settings for the network entry. """ @@ -823,7 +814,10 @@ class appGui(object): """ self.window.hide() [width, height] = self.window.get_size() - daemon.WriteWindowSize(width, height, "main") + try: + daemon.WriteWindowSize(width, height, "main") + except: + pass if self.standalone: sys.exit(0) diff --git a/wicd/misc.py b/wicd/misc.py index 286ddfc..a76bd46 100644 --- a/wicd/misc.py +++ b/wicd/misc.py @@ -21,6 +21,7 @@ import os import locale import gettext import sys +from threading import Thread from subprocess import Popen, STDOUT, PIPE, call from commands import getoutput @@ -94,7 +95,7 @@ def LaunchAndWait(cmd): cmd : A list contained the program name and its arguments. """ - call(cmd, shell=True) + call(cmd, shell=False) def IsValidIP(ip): """ Make sure an entered IP is valid. """ @@ -111,7 +112,7 @@ def PromptToStartDaemon(): """ Prompt the user to start the daemon """ daemonloc = wpath.sbin + 'wicd' sudo_prog = choose_sudo_prog() - if sudo_prog.endswith("gksu") or sudo_prog.endswith("ktsuss"): + if "gksu" in sudo_prog or "ktsuss" in sudo_prog: msg = '--message' else: msg = '--caption' @@ -344,6 +345,16 @@ def detect_desktop_environment(): pass return desktop_environment +def get_sudo_cmd(msg): + """ Returns a graphical sudo command for generic use. """ + sudo_prog = misc.choose_sudo_prog() + if not sudo_prog: return None + if sudo_prog.endswith("gksu") or sudo_prog.endswith("ktsuss"): + msg_flag = "-m" + else: + msg_flag = "--caption" + misc.LaunchAndWait([sudo_prog, msg_flag, msg]) + def choose_sudo_prog(): """ Try to intelligently decide which graphical sudo program to use. """ desktop_env = detect_desktop_environment() @@ -361,7 +372,7 @@ def choose_sudo_prog(): if os.access(path, os.F_OK): return path - raise WicdError("Couldn't find graphical sudo program.") + return None def find_path(cmd): """ Try to find a full path for a given file name. @@ -459,6 +470,8 @@ def get_language_list_gui(): language["backend_alert"] = _("Changes to your backend won't occur until the daemon is restarted.") language['search_domain'] = _("Search Domain") language['scripts_need_pass'] = _('You must enter your password to configure scripts') + language['no_sudo_prog'] = _("Could not find a graphical sudo program. The script editor could not be launched." + + "You'll have to edit scripts directly your configuration file.") language['0'] = _('0') language['1'] = _('1') @@ -490,6 +503,9 @@ def get_language_list_gui(): language['bad_pass'] = _('Connection Failed: Bad password') language['done'] = _('Done connecting...') language['scanning'] = _('Scanning') + language['cannot_start_daemon'] = _("Unable to connect to wicd daemon DBus interface." + \ + "This typically means there was a problem starting the daemon." + \ + "Check the wicd log for more info") return language @@ -510,6 +526,10 @@ def get_language_list_tray(): language['wired'] = _('Wired Network') language['scanning'] = _('Scanning') language['no_wireless_networks_found'] = _('No wireless networks found.') + language['daemon_unavailable'] = _("The wicd daemon is unavailable, so your request cannot be completed") + language['cannot_start_daemon'] = _("Unable to connect to wicd daemon DBus interface." + \ + "This typically means there was a problem starting the daemon." + \ + "Check the wicd log for more info") return language def noneToBlankString(text): @@ -537,3 +557,17 @@ def stringToBoolean(text): def checkboxTextboxToggle(checkbox, textboxes): for textbox in textboxes: textbox.set_sensitive(checkbox.get_active()) + +def threaded(f): + """ A decorator that will make any function run in a new thread. """ + + def wrapper(*args, **kwargs): + t = Thread(target=f, args=args, kwargs=kwargs) + t.setDaemon(True) + t.start() + + wrapper.__name__ = f.__name__ + wrapper.__dict__ = f.__dict__ + wrapper.__doc__ = f.__doc__ + + return wrapper diff --git a/wicd/monitor.py b/wicd/monitor.py index 462a669..d19a9e5 100755 --- a/wicd/monitor.py +++ b/wicd/monitor.py @@ -24,32 +24,24 @@ when appropriate. # along with this program. If not, see . # -import dbus import gobject import time -if getattr(dbus, 'version', (0, 0, 0)) < (0, 80, 0): - import dbus.glib -else: - from dbus.mainloop.glib import DBusGMainLoop - DBusGMainLoop(set_as_default=True) -import wicd.wpath as wpath -import wicd.misc as misc +from wicd import wpath +from wicd import misc +from wicd import dbusmanager misc.RenameProcess("wicd-monitor") if __name__ == '__main__': wpath.chdir(__file__) - -bus = dbus.SystemBus() -proxy_obj = bus.get_object('org.wicd.daemon', '/org/wicd/daemon') -daemon = dbus.Interface(proxy_obj, 'org.wicd.daemon') - -proxy_obj = bus.get_object('org.wicd.daemon', '/org/wicd/daemon/wired') -wired = dbus.Interface(proxy_obj, 'org.wicd.daemon.wired') - -proxy_obj = bus.get_object('org.wicd.daemon', '/org/wicd/daemon/wireless') -wireless = dbus.Interface(proxy_obj, 'org.wicd.daemon.wireless') + +dbusmanager.connect_to_dbus() +dbus_dict = dbusmanager.get_dbus_ifaces() +daemon = dbus_dict["daemon"] +wired = dbus_dict["wired"] +wireless = dbus_dict["wireless"] +bus = dbusmanager.get_bus() class ConnectionStatus(object): """ Class for monitoring the computer's connection status. """ @@ -120,8 +112,6 @@ class ConnectionStatus(object): else: # If we have a signal, reset the counter self.connection_lost_counter = 0 - # Only update if the signal strength has changed because doing I/O - # calls is expensive, and the icon flickers. if (wifi_signal != self.last_strength or self.network != wireless.GetCurrentNetwork(self.iwconfig)): self.last_strength = wifi_signal diff --git a/wicd/netentry.py b/wicd/netentry.py index 185aba2..f2f0b54 100644 --- a/wicd/netentry.py +++ b/wicd/netentry.py @@ -225,20 +225,7 @@ class AdvancedSettingsDialog(gtk.Dialog): w.set_sensitive(not self.chkbox_global_dns.get_active()) def destroy_called(self, *args): - """ Clean up everything. - - This might look excessive, but it was the only way to prevent - memory leakage. - - """ - for obj in vars(self): - obj = self.__dict__[obj] - if hasattr(obj, "destroy"): - obj.destroy() - if hasattr(obj, "__del__"): - obj.__del__() - else: - del obj + """ Clean up everything. """ super(AdvancedSettingsDialog, self).destroy() self.destroy() del self @@ -273,21 +260,8 @@ class WiredSettingsDialog(AdvancedSettingsDialog): return noneToBlankString(wired.GetWiredProperty(label)) def destroy_called(self, *args): - """ Clean up everything. - - This might look excessive, but it was the only way to prevent - memory leakage. - - """ + """ Clean up everything. """ self.disconnect(self.des) - for obj in vars(self): - obj = self.__dict__[obj] - if hasattr(obj, "destroy"): - obj.destroy() - if hasattr(obj, "__del__"): - obj.__del__() - else: - del obj super(WiredSettingsDialog, self).destroy_called() self.destroy() del self @@ -336,21 +310,8 @@ class WirelessSettingsDialog(AdvancedSettingsDialog): self.des = self.connect("destroy", self.destroy_called) def destroy_called(self, *args): - """ Clean up everything. - - This might look excessive, but it was the only way to prevent - memory leakage. - - """ + """ Clean up everything. """ self.disconnect(self.des) - for obj in vars(self): - obj = self.__dict__[obj] - if hasattr(obj, "destroy"): - obj.destroy() - if hasattr(obj, "__del__"): - obj.__del__() - else: - del obj super(WirelessSettingsDialog, self).destroy_called() self.destroy() del self @@ -506,30 +467,10 @@ class NetworkEntry(gtk.HBox): self.expander.add(aligner) def destroy_called(self, *args): - """ Clean up everything. - - This might look excessive, but it was the only way to prevent - memory leakage. - - """ - for obj in vars(self): - obj = self.__dict__[obj] - try: obj.destroy() - except: pass - if hasattr(obj, '__del__'): - obj.__del__() - else: - del obj - for obj in vars(super(NetworkEntry, self)): - obj = self.__dict__[obj] - try: obj.destroy() - except: pass - if hasattr(obj, '__del__'): - obj.__del__() - else: - del obj + """ Clean up everything. """ super(NetworkEntry, self).destroy() self.destroy() + del self class WiredNetworkEntry(NetworkEntry): @@ -616,23 +557,10 @@ class WiredNetworkEntry(NetworkEntry): self.wireddis = self.connect("destroy", self.destroy_called) def destroy_called(self, *args): - """ Clean up everything. - - This might look excessive, but it was the only way to prevent - memory leakage. - - """ + """ Clean up everything. """ self.disconnect(self.wireddis) self.advanced_dialog.destroy_called() del self.advanced_dialog - for obj in vars(self): - obj = self.__dict__[obj] - if hasattr(obj, "destroy"): - obj.destroy() - if hasattr(obj, '__del__'): - obj.__del__() - else: - del obj super(WiredNetworkEntry, self).destroy_called() self.destroy() del self @@ -640,28 +568,20 @@ class WiredNetworkEntry(NetworkEntry): def edit_scripts(self, widget=None, event=None): """ Launch the script editting dialog. """ profile = self.combo_profile_names.get_active_text() + cmdend = [os.path.join(wpath.lib, "configscript.py"), profile, "wired"] if os.getuid() != 0: - try: - sudo_prog = misc.choose_sudo_prog() - msg = msg = "'%s'" % language["scripts_need_pass"] - if sudo_prog.endswith("gksu") or sudo_prog.endswith("ktsuss"): - msg_flag = "-m" - else: - msg_flag = "--caption" - misc.LaunchAndWait(' '.join([sudo_prog, msg_flag, msg, - os.path.join(wpath.lib, "configscript.py"), - profile, "wired"])) - except misc.WicdError: - error(None, "Could not find a graphical sudo program." + \ - " Script editor could not be launched.") + cmdbase = misc.get_sudo_cmd() + if not cmdbase: + error(None, language["no_sudo_prog"]) + return + cmdbase.extend(cmdend) else: - misc.LaunchAndWait(' '.join([os.path.join(wpath.lib, "configscript.py"), - profile, "wired"])) + misc.LaunchAndWait(cmdend) def check_enable(self): """ Disable objects if the profile list is empty. """ profile_list = wired.GetWiredProfileList() - if profile_list == None: + if not profile_list: self.button_delete.set_sensitive(False) self.connect_button.set_sensitive(False) self.advanced_button.set_sensitive(False) @@ -823,31 +743,14 @@ class WirelessNetworkEntry(NetworkEntry): def _escape(self, val): """ Escapes special characters so they're displayed correctly. """ - #try: return val.replace("&", "&").replace("<", "<").\ replace(">",">").replace("'", "'").replace('"', """) - #except ValueError: - # return val def destroy_called(self, *args): - """ Clean up everything. - - This might look excessive, but it was the only way to prevent - memory leakage. - - """ + """ Clean up everything. """ self.disconnect(self.wifides) self.advanced_dialog.destroy_called() del self.advanced_dialog - for obj in vars(self): - obj = self.__dict__[obj] - if hasattr(obj, "destroy"): - obj.destroy() - - if hasattr(obj, '__del__'): - obj.__del__() - else: - del obj super(WirelessNetworkEntry, self).destroy_called() self.destroy() del self @@ -933,23 +836,16 @@ class WirelessNetworkEntry(NetworkEntry): def edit_scripts(self, widget=None, event=None): """ Launch the script editting dialog. """ + cmdend = [os.path.join(wpath.lib, "configscript.py"), + str(self.networkID), "wireless"] if os.getuid() != 0: - try: - sudo_prog = misc.choose_sudo_prog() - msg = "'%s'" % language["scripts_need_pass"] - if sudo_prog.endswith("gksu") or sudo_prog.endswith("ktsuss"): - msg_flag = "-m" - else: - msg_flag = "--caption" - misc.LaunchAndWait(' '.join([sudo_prog, msg_flag, msg, - os.path.join(wpath.lib, "configscript.py"), - str(self.networkID), "wireless"])) - except misc.WicdError: - error(None, "Could not find a graphical sudo program." + \ - " Script editor could no be launched.") + cmdbase = misc.get_sudo_cmd() + if not cmdbase: + error(None, language["no_sudo_prog"]) + return + cmdbase.extend(cmdend) else: - misc.LaunchAndWait(' '.join([os.path.join(wpath.lib, "configscript.py"), - str(self.networkID), "wireless"])) + misc.LaunchAndWait(cmdend) def update_autoconnect(self, widget=None): """ Called when the autoconnect checkbox is toggled. """ diff --git a/wicd/prefs.py b/wicd/prefs.py index 888d966..3709d97 100644 --- a/wicd/prefs.py +++ b/wicd/prefs.py @@ -248,9 +248,7 @@ class PreferencesDialog(object): daemon.SetWiredAutoConnectMethod(3) else: daemon.SetWiredAutoConnectMethod(1) - - if self.backends[self.backendcombo.get_active()] != daemon.GetSavedBackend(): - alert(self.dialog, language["backend_alert"]) + daemon.SetBackend(self.backends[self.backendcombo.get_active()]) # External Programs Tab diff --git a/wicd/suspend.py b/wicd/suspend.py index 59271b7..792bd86 100755 --- a/wicd/suspend.py +++ b/wicd/suspend.py @@ -2,7 +2,7 @@ """ Suspends the wicd daemon. -Sets a flag in the daemon that will stop it from monitoring networkg status. +Sets a flag in the daemon that will stop it from monitoring network status. Used for when a laptop enters hibernation/suspension. """ diff --git a/wicd/wicd-client.py b/wicd/wicd-client.py index 10f52a1..c88ea0e 100755 --- a/wicd/wicd-client.py +++ b/wicd/wicd-client.py @@ -44,13 +44,12 @@ import os import pango import time from dbus import DBusException -from dbus import version as dbus_version # Wicd specific imports from wicd import wpath from wicd import misc from wicd import gui -from wicd.dbusmanager import DBusManager +from wicd import dbusmanager ICON_AVAIL = True # Import egg.trayicon if we're using an older gtk version @@ -66,22 +65,16 @@ if not (gtk.gtk_version[0] >= 2 and gtk.gtk_version[1] >= 10): else: USE_EGG = False -if not dbus_version or (dbus_version < (0, 80, 0)): - import dbus.glib -else: - from dbus.mainloop.glib import DBusGMainLoop - DBusGMainLoop(set_as_default=True) - misc.RenameProcess("wicd-client") if __name__ == '__main__': wpath.chdir(__file__) - -dbus_manager = None + daemon = None wireless = None wired = None wired = None +DBUS_AVAIL = False language = misc.get_language_list_tray() @@ -353,10 +346,23 @@ class TrayIcon(object): """ Callback for when a wireless scan finishes. """ self._is_scanning = False self.populate_network_menu() + + def dbus_lost(self): + """ Callback for when the daemon is going down. """ + global DBUS_AVAIL + print "The daemon is going down!!" + DBUS_AVAIL = False + time.sleep(1) + while not setup_dbus(): + time.sleep(20) def on_activate(self, data=None): """ Opens the wicd GUI. """ - self.toggle_wicd_gui() + global DBUS_AVAIL + if DBUS_AVAIL: + self.toggle_wicd_gui() + else: + gui.error(None, language["daemon_unavailable"]) def on_quit(self, widget=None): """ Closes the tray icon. """ @@ -520,16 +526,7 @@ class TrayIcon(object): def toggle_wicd_gui(self): """ Toggles the wicd GUI. """ if not self.gui_win: - self.gui_win = gui.appGui(dbus_manager) - bus = dbus_manager.get_bus() - bus.add_signal_receiver(self.gui_win.dbus_scan_finished, - 'SendEndScanSignal', - 'org.wicd.daemon.wireless') - bus.add_signal_receiver(self.gui_win.dbus_scan_started, - 'SendStartScanSignal', - 'org.wicd.daemon.wireless') - bus.add_signal_receiver(self.gui_win.update_connect_buttons, - 'StatusChanged', 'org.wicd.daemon') + self.gui_win = gui.appGui() elif not self.gui_win.is_visible: self.gui_win.show_win() else: @@ -637,24 +634,23 @@ Arguments: """ def setup_dbus(): - global daemon, wireless, wired, dbus_manager + global daemon, wireless, wired, DBUS_AVAIL - dbus_manager = DBusManager() try: - dbus_manager.connect_to_dbus() + dbusmanager.connect_to_dbus() except DBusException: print "Can't connect to the daemon, trying to start it automatically..." misc.PromptToStartDaemon() try: - dbus_manager.connect_to_dbus() + dbusmanager.connect_to_dbus() except DBusException: - gui.error(None, "Could not connect to wicd's D-Bus interface. " + - "Make sure the daemon is started.") + gui.error(None, language['cannot_start_daemon']) sys.exit(1) - dbus_ifaces = dbus_manager.get_dbus_ifaces() + dbus_ifaces = dbusmanager.get_dbus_ifaces() daemon = dbus_ifaces['daemon'] wireless = dbus_ifaces['wireless'] wired = dbus_ifaces['wired'] + DBUS_AVAIL = True return True def main(argv): @@ -691,7 +687,7 @@ def main(argv): setup_dbus() if not use_tray or not ICON_AVAIL: - the_gui = gui.appGui(dbus_man=dbus_manager, standalone=True) + the_gui = gui.appGui(standalone=True) mainloop = gobject.MainLoop() mainloop.run() sys.exit(0) @@ -705,7 +701,7 @@ def main(argv): daemon.SetNeedWiredProfileChooser(False) tray_icon.icon_info.wired_profile_chooser() - bus = dbus_manager.get_bus() + bus = dbusmanager.get_bus() bus.add_signal_receiver(tray_icon.icon_info.wired_profile_chooser, 'LaunchChooser', 'org.wicd.daemon') bus.add_signal_receiver(tray_icon.icon_info.update_tray_icon, @@ -714,6 +710,8 @@ def main(argv): 'org.wicd.daemon.wireless') bus.add_signal_receiver(tray_icon.tr.tray_scan_started, 'SendStartScanSignal', 'org.wicd.daemon.wireless') + bus.add_signal_receiver(tray_icon.tr.dbus_lost, + "DaemonClosing", 'org.wicd.daemon') print 'Done.' mainloop = gobject.MainLoop() mainloop.run() diff --git a/wicd/wicd-daemon.py b/wicd/wicd-daemon.py index 4e243e5..be5317e 100644 --- a/wicd/wicd-daemon.py +++ b/wicd/wicd-daemon.py @@ -111,6 +111,8 @@ class WicdDaemon(dbus.service.Object): #TODO remove the need for this. self.wifi.liface = self.wired.liface self.wired.wiface = self.wifi.wiface + + signal.signal(signal.SIGTERM, self.DaemonClosing) # Scan since we just got started if auto_connect: @@ -199,10 +201,11 @@ class WicdDaemon(dbus.service.Object): """ Sets a new backend. """ print "setting backend to %s" % backend self.config.set("Settings", "backend", backend, True) - if self.GetCurrentBackend(): - return - self.wifi.LoadBackend(backend) - self.wired.LoadBackend(backend) + if backend != self.GetCurrentBackend(): + self.suspended = True + self.wifi.LoadBackend(backend) + self.wired.LoadBackend(backend) + self.SetSuspend(False) @dbus.service.method('org.wicd.daemon') def GetCurrentBackend(self): @@ -702,6 +705,11 @@ class WicdDaemon(dbus.service.Object): print 'calling wired profile chooser' self.SetNeedWiredProfileChooser(True) + @dbus.service.signal(dbus_interface='org.wicd.daemon', signature='') + def DaemonClosing(self): + """ Emits a signal indicating the daemon will be closing. """ + pass + @dbus.service.method('org.wicd.daemon', in_signature='uav') def EmitStatusChanged(self, state, info): """ Calls the StatusChanged signal method. """ @@ -826,6 +834,7 @@ class WirelessDaemon(dbus.service.Object): """ Sets the ESSID of a hidden network for use with Scan(). """ self.hidden_essid = str(misc.Noneify(essid)) + @dbus.service.method('org.wicd.daemon.wireless') def Scan(self): """ Scan for wireless networks. @@ -837,7 +846,10 @@ class WirelessDaemon(dbus.service.Object): if self.debug_mode: print 'scanning start' self.SendStartScanSignal() - time.sleep(.2) + self._Scan() + + @misc.threaded + def _Scan(self): scan = self.wifi.Scan(str(self.hidden_essid)) self.LastScan = scan if self.debug_mode: @@ -1520,12 +1532,17 @@ def main(argv): # Enter the main loop mainloop = gobject.MainLoop() - mainloop.run() + try: + mainloop.run() + except KeyboardInterrupt: + pass + daemon.DaemonClosing() + sigterm_caught() -def sigterm_caught(sig, frame): +def sigterm_caught(sig=None, frame=None): """ Called when a SIGTERM is caught, kills monitor.py before exiting. """ global child_pid - print 'SIGTERM caught, killing wicd-monitor...' + print 'Daemon going down, killing wicd-monitor...' os.kill(child_pid, signal.SIGTERM) print 'Removing PID file...' if os.path.exists(wpath.pidfile): @@ -1536,7 +1553,7 @@ def sigterm_caught(sig, frame): if __name__ == '__main__': if os.getuid() != 0: - print ("Root priviledges are required for the daemon to run properly." + + print ("Root privileges are required for the daemon to run properly." + " Exiting.") sys.exit(1) main(sys.argv) diff --git a/wicd/wnettools.py b/wicd/wnettools.py index 8414e5f..2969890 100644 --- a/wicd/wnettools.py +++ b/wicd/wnettools.py @@ -129,9 +129,7 @@ def GetWiredInterfaces(): def NeedsExternalCalls(): """ Returns True if the backend needs to use an external program. """ - print ("NeedsExternalCalls: returning default of True. You should " + - "implement this yourself.") - return True + raise NotImplementedError class BaseInterface(object): @@ -498,7 +496,7 @@ class BaseInterface(object): The IP address of the interface in dotted quad form. """ - print 'Implement this in a derived class!' + raise NotImplementedError def IsUp(self): """ Determines if the interface is up. @@ -507,7 +505,7 @@ class BaseInterface(object): True if the interface is up, False otherwise. """ - print 'Implement this in a derived class!' + raise NotImplementedError class BaseWiredInterface(BaseInterface): @@ -533,7 +531,7 @@ class BaseWiredInterface(BaseInterface): True if a link is detected, False otherwise. """ - print 'Implement this in a derived class!' + raise NotImplementedError class BaseWirelessInterface(BaseInterface): @@ -623,14 +621,16 @@ class BaseWirelessInterface(BaseInterface): return ret def _GetRalinkInfo(self): - """ Get a network info dict used for ralink drivers - + """ Get a network info list used for ralink drivers + Calls iwpriv get_site_survey, which on some ralink cards will return encryption and signal strength info for wireless networks in the area. - + """ iwpriv = misc.Run('iwpriv ' + self.iface + ' get_site_survey') + if self.verbose: + print iwpriv lines = iwpriv.splitlines()[2:] aps = {} patt = re.compile("((?:[0-9A-Z]{2}:){5}[0-9A-Z]{2})") @@ -638,6 +638,8 @@ class BaseWirelessInterface(BaseInterface): ap = {} info = x.split(" ") info = filter(None, [x.strip() for x in info]) + if len(info) < 5: + continue if re.match(patt, info[2].upper()): bssid = info[2].upper() offset = -1 @@ -647,17 +649,30 @@ class BaseWirelessInterface(BaseInterface): else: # Invalid print 'Invalid iwpriv line. Skipping it.' continue + ap['nettype'] = info[-1] ap['strength'] = info[1] - if info[5 + offset] == 'WEP' or info[4 + offset] == 'WEP': + if info[4 + offset] == 'WEP': ap['encryption_method'] = 'WEP' + ap['enctype'] = 'WEP' + ap['keyname'] = 'Key1' + ap['authmode'] = info[5 + offset] elif info[5 + offset] in ['WPA-PSK', 'WPA']: ap['encryption_method'] = 'WPA' + ap['authmode'] = "WPAPSK" + ap['keyname'] = "WPAPSK" + ap['enctype'] = info[4 + offset] elif info[5 + offset] == 'WPA2-PSK': ap['encryption_method'] = 'WPA2' + ap['authmode'] ="WPA2PSK" + ap['keyname'] = "WPA2PSK" + ap['enctype'] = info[4 + offset] + elif info[4 + offset] == "NONE": + ap['encryption_method'] = None else: print "Unknown AuthMode, can't assign encryption_method!" ap['encryption_method'] = 'Unknown' aps[bssid] = ap + if self.verbose: print str(aps) return aps def _ParseRalinkAccessPoint(self, ap, ralink_info, cell): @@ -776,24 +791,8 @@ class BaseWirelessInterface(BaseInterface): misc.Run(cmd) def ValidateAuthentication(self, auth_time): - """ Validate WPA authentication. - - Validate that the wpa_supplicant authentication - process was successful. - - NOTE: It's possible this could return False, - though in reality wpa_supplicant just isn't - finished yet. - - Keyword arguments: - auth_time -- The time at which authentication began. - - Returns: - True if wpa_supplicant authenticated succesfully, - False otherwise. - - """ - print 'Implement this in a derived class!' + """ Validate WPA authentication. """ + raise NotImplementedError def _AuthenticateRalinkLegacy(self, network): """ Authenticate with the specified wireless network. @@ -806,55 +805,38 @@ class BaseWirelessInterface(BaseInterface): """ if network.get('key') != None: - lines = self._GetRalinkInfo() - for x in lines: - info = x.split() - if len(info) < 5: - break - if info[2] == network.get('essid'): - if info[5] == 'WEP' or (info[5] == 'OPEN' and \ - info[4] == 'WEP'): - print 'Setting up WEP' - cmd = ''.join(['iwconfig ', self.iface, ' key ', - network.get('key')]) - if self.verbose: print cmd - misc.Run(cmd) - else: - if info[5] == 'SHARED' and info[4] == 'WEP': - print 'Setting up WEP' - auth_mode = 'SHARED' - key_name = 'Key1' - elif info[5] == 'WPA-PSK': - print 'Setting up WPA-PSK' - auth_mode = 'WPAPSK' - key_name = 'WPAPSK' - elif info[5] == 'WPA2-PSK': - print 'Setting up WPA2-PSK' - auth_mode = 'WPA2PSK' - key_name = 'WPAPSK' - else: - print 'Unknown AuthMode, can\'t complete ' + \ - 'connection process!' - return - - cmd_list = [] - cmd_list.append('NetworkType=' + info[6]) - cmd_list.append('AuthMode=' + auth_mode) - cmd_list.append('EncrypType=' + info[4]) - cmd_list.append('SSID=' + info[2]) - cmd_list.append(key_name + '=' + network.get('key')) - if info[5] == 'SHARED' and info[4] == 'WEP': - cmd_list.append('DefaultKeyID=1') - cmd_list.append('SSID=' + info[2]) - - for cmd in cmd_list: - cmd = 'iwpriv ' + self.iface + ' ' + cmd - if self.verbose: print cmd - misc.Run(cmd) + try: + info = self._GetRalinkInfo()[network.get('bssid')] + except KeyError: + print "Could not find current network in iwpriv " + \ + "get_site_survey results. Cannot authenticate." + return + + if info['enctype'] == "WEP" and info['authtype'] == 'OPEN': + print 'Setting up WEP' + cmd = ''.join(['iwconfig ', self.iface, ' key ', + network.get('key')]) + if self.verbose: print cmd + misc.Run(cmd) + else: + cmd_list = [] + cmd_list.append('NetworkType=' + info['nettype']) + cmd_list.append('AuthMode=' + info['authmode']) + cmd_list.append('EncrypType=' + info['enctype']) + cmd_list.append('SSID=' + info['essid']) + cmd_list.append(info['keyname'] + '=' + network.get('key')) + if info['nettype'] == 'SHARED' and info['enctype'] == 'WEP': + cmd_list.append('DefaultKeyID=1') + cmd_list.append('SSID=' + info['essid']) + + for cmd in cmd_list: + cmd = 'iwpriv ' + self.iface + ' ' + cmd + if self.verbose: print cmd + misc.Run(cmd) def GetBSSID(self, iwconfig=None): """ Get the MAC address for the interface. """ - print 'Implement this in a derived class!' + raise NotImplementedError def GetSignalStrength(self, iwconfig=None): """ Get the signal strength of the current network. @@ -863,7 +845,7 @@ class BaseWirelessInterface(BaseInterface): The signal strength. """ - print 'Implement this in a derived class!' + raise NotImplementedError def GetDBMStrength(self, iwconfig=None): """ Get the dBm signal strength of the current network. @@ -872,7 +854,7 @@ class BaseWirelessInterface(BaseInterface): The dBm signal strength. """ - print 'Implement this in a derived class!' + raise NotImplementedError def GetCurrentNetwork(self, iwconfig=None): """ Get the essid of the current network. @@ -881,4 +863,4 @@ class BaseWirelessInterface(BaseInterface): The current network essid. """ - print 'Implement this in a derived class!' + raise NotImplementedError