diff --git a/gui.py b/gui.py index 6ca667e..48c881c 100644 --- a/gui.py +++ b/gui.py @@ -35,10 +35,13 @@ import gtk import gtk.glade import misc +from misc import noneToString, noneToBlankString, stringToBoolean, checkboxTextboxToggle +from netentry import WiredNetworkEntry, WirelessNetworkEntry import wpath if __name__ == '__main__': wpath.chdir(__file__) + try: import pygtk pygtk.require("2.0") @@ -48,163 +51,38 @@ except: if getattr(dbus, 'version', (0, 0, 0)) >= (0, 41, 0): import dbus.glib -# Declare the connections to the daemon, so that they may be accessed -# in any class. bus = dbus.SystemBus() try: - print 'Attempting to connect daemon to GUI...' - proxy_obj = bus.get_object('org.wicd.daemon', '/org/wicd/daemon') - print 'Success' -except: - print 'Daemon not running, trying to start it automatically.' + proxy_obj = bus.get_object("org.wicd.daemon", '/org/wicd/daemon') +except dbus.DBusException, e: misc.PromptToStartDaemon() time.sleep(1) try: - proxy_obj = bus.get_object('org.wicd.daemon', '/org/wicd/daemon') - print 'Daemon started succesfully' + proxy_obj = bus.get_object("org.wicd.daemon", '/org/wicd/daemon') + daemon = dbus.Interface(proxy_obj, 'org.wicd.daemon') + wireless = dbus.Interface(proxy_obj, 'org.wicd.daemon.wireless') + wired = dbus.Interface(proxy_obj, 'org.wicd.daemon.wired') + vpn_session = dbus.Interface(proxy_obj, 'org.wicd.daemon.vpn') + config = dbus.Interface(proxy_obj, 'org.wicd.daemon.config') + dbus_ifaces = {"daemon" : daemon, "wireless" : wireless, "wired" : wired, + "vpn_session" : vpn_session, "config" : config} except: - print 'Daemon still not running, aborting.' - sys.exit(1) + proxy_obj = None -daemon = dbus.Interface(proxy_obj, 'org.wicd.daemon') -wireless = dbus.Interface(proxy_obj, 'org.wicd.daemon.wireless') -wired = dbus.Interface(proxy_obj, 'org.wicd.daemon.wired') -config = dbus.Interface(proxy_obj, 'org.wicd.daemon.config') +language = misc.get_language_list_gui() -_ = misc.get_gettext() - -# Keep all the language strings in a dictionary -# by the english words. -# I'm not sure this is the best way to do it -# but it works and makes it easy for me :) -########## -# translations are done at -# http://wicd.net/translator -# please translate if you can! -########## -language = {} -language['connect'] = _("Connect") -language['ip'] = _("IP") -language['netmask'] = _("Netmask") -language['gateway'] = _('Gateway') -language['dns'] = _('DNS') -language['use_static_ip'] = _('Use Static IPs') -language['use_static_dns'] = _('Use Static DNS') -language['use_encryption'] = _('Use Encryption') -language['advanced_settings'] = _('Advanced Settings') -language['wired_network'] = _('Wired Network') -language['wired_network_instructions'] = _('To connect to a wired network, you' -' must create a network profile. To create a network profile, type a name that' -' describes this network, and press Add.') -language['automatic_connect'] = _('Automatically connect to this network') -language['secured'] = _('Secured') -language['unsecured'] = _('Unsecured') -language['channel'] = _('Channel') -language['preferences'] = _('Preferences') -language['wpa_supplicant_driver'] = _('WPA Supplicant Driver') -language['wireless_interface'] = _('Wireless Interface') -language['wired_interface'] = _('Wired Interface') -language['hidden_network'] = _('Hidden Network') -language['hidden_network_essid'] = _('Hidden Network ESSID') -language['connected_to_wireless'] = _('Connected to $A at $B (IP: $C)') -language['connected_to_wired'] = _('Connected to wired network (IP: $A)') -language['not_connected'] = _('Not connected') -language['no_wireless_networks_found'] = _('No wireless networks found.') -language['killswitch_enabled'] = _('Wireless Kill Switch Enabled') -language['key'] = _('Key') -language['username'] = _('Username') -language['password'] = _('Password') -language['anonymous_identity'] = _('Anonymous Identity') -language['identity'] = _('Identity') -language['authentication'] = _('Authentication') -language['path_to_pac_file'] = _('Path to PAC File') -language['select_a_network'] = _('Choose from the networks below:') -language['connecting'] = _('Connecting...') -language['wired_always_on'] = _('Always show wired interface') -language['auto_reconnect'] = _('Automatically reconnect on connection loss') -language['create_adhoc_network'] = _('Create an Ad-Hoc Network') -language['essid'] = _('ESSID') -language['use_wep_encryption'] = _('Use Encryption (WEP only)') -language['before_script'] = _('Run script before connect') -language['after_script'] = _('Run script after connect') -language['disconnect_script'] = _('Run disconnect script') -language['script_settings'] = _('Scripts') -language['use_ics'] = _('Activate Internet Connection Sharing') -language['madwifi_for_adhoc'] = _('Check if using madwifi/atheros drivers') -language['default_wired'] = _('Use as default profile (overwrites any previous default)') -language['use_debug_mode'] = _('Enable debug mode') -language['use_global_dns'] = _('Use global DNS servers') -language['use_default_profile'] = _('Use default profile on wired autoconnect') -language['show_wired_list'] = _('Prompt for profile on wired autoconnect') -language['use_last_used_profile'] = _('Use last used profile on wired autoconnect') -language['choose_wired_profile'] = _('Select or create a wired profile to connect with') -language['wired_network_found'] = _('Wired connection detected') -language['stop_showing_chooser'] = _('Stop Showing Autoconnect pop-up temporarily') -language['display_type_dialog'] = _('Use dBm to measure signal strength') -language['scripts'] = _('Scripts') -language['invalid_address'] = _('Invalid address in $A entry.') -language['global_settings'] = _('Use these settings for all networks sharing this essid') -language['encrypt_info_missing'] = _('Required encryption information is missing.') -language['enable_encryption'] = _('This network requires encryption to be enabled.') -language['wicd_auto_config'] = _('Automatic (recommended)') -language["gen_settings"] = _("General Settings") -language["ext_programs"] = _("External Programs") -language["dhcp_client"] = _("DHCP Client") -language["wired_detect"] = _("Wired Link Detection") -language["route_flush"] = _("Route Table Flushing") - -language['0'] = _('0') -language['1'] = _('1') -language['2'] = _('2') -language['3'] = _('3') -language['4'] = _('4') -language['5'] = _('5') -language['6'] = _('6') -language['7'] = _('7') -language['8'] = _('8') -language['9'] = _('9') - -language['interface_down'] = _('Putting interface down...') -language['resetting_ip_address'] = _('Resetting IP address...') -language['interface_up'] = _('Putting interface up...') -language['setting_encryption_info'] = _('Setting encryption info') -language['removing_old_connection'] = _('Removing old connection...') -language['generating_psk'] = _('Generating PSK...') -language['generating_wpa_config'] = _('Generating WPA configuration file...') -language['flushing_routing_table'] = _('Flushing the routing table...') -language['configuring_interface'] = _('Configuring wireless interface...') -language['validating_authentication'] = _('Validating authentication...') -language['setting_broadcast_address'] = _('Setting broadcast address...') -language['setting_static_dns'] = _('Setting static DNS servers...') -language['setting_static_ip'] = _('Setting static IP addresses...') -language['running_dhcp'] = _('Obtaining IP address...') -language['dhcp_failed'] = _('Connection Failed: Unable to Get IP Address') -language['aborted'] = _('Connection Cancelled') -language['bad_pass'] = _('Connection Failed: Bad password') -language['done'] = _('Done connecting...') +def error(parent, message): + """ Shows an error dialog """ + dialog = gtk.MessageDialog(parent, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, + gtk.BUTTONS_OK) + dialog.set_markup(message) + dialog.run() + dialog.destroy() ######################################## ##### GTK EXTENSION CLASSES ######################################## -class LinkButton(gtk.EventBox): - label = None - def __init__(self, txt): - gtk.EventBox.__init__(self) - self.connect("realize", self.__setHandCursor) #set the hand cursor when the box is initalized - label = gtk.Label() - label.set_markup("[ " + txt + " ]") - label.set_alignment(0,.5) - label.show() - self.add(label) - self.show_all() - - def __setHandCursor(self, widget): - # We need this to set the cursor to a hand for the link labels. - # I'm not entirely sure what it does :P - hand = gtk.gdk.Cursor(gtk.gdk.HAND1) - widget.window.set_cursor(hand) - class SmallLabel(gtk.Label): def __init__(self, text=''): gtk.Label.__init__(self, text) @@ -253,6 +131,7 @@ class LabelEntry(gtk.HBox): if self.auto_hide_text and widget: self.entry.set_visibility(False) + class GreyLabel(gtk.Label): """ Creates a grey gtk.Label. """ def __init__(self): @@ -262,878 +141,6 @@ class GreyLabel(gtk.Label): self.set_markup("" + text + "") self.set_alignment(0, 0) -######################################## -##### OTHER RANDOM FUNCTIONS -######################################## - -def noneToString(text): - """ Converts a blank string to "None". """ - if text == "": - return "None" - else: - return str(text) - -def noneToBlankString(text): - """ Converts NoneType or "None" to a blank string. """ - if text in (None, "None"): - return "" - else: - return str(text) - -def stringToNone(text): - """ Performs opposite function of noneToString. """ - if text in ("", None, "None"): - return None - else: - return str(text) - -def stringToBoolean(text): - """ Turns a string representation of a bool to a boolean if needed. """ - if text in ("True", "1"): - return True - if text in ("False", "0"): - return False - return text - -def checkboxTextboxToggle(checkbox, textboxes): - # Really bad practice, but checkbox == self - for textbox in textboxes: - textbox.set_sensitive(checkbox.get_active()) - - -def error(parent, message): - """ Shows an error dialog """ - dialog = gtk.MessageDialog(parent, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, - gtk.BUTTONS_OK) - dialog.set_markup(message) - dialog.run() - dialog.destroy() - -######################################## -##### NETWORK LIST CLASSES -######################################## - -class AdvancedSettingsDialog(gtk.Dialog): - def __init__(self): - """ Build the base advanced settings dialog. - - This class isn't used by itself, instead it is used as a parent for - the WiredSettingsDialog and WirelessSettingsDialog. - - """ - gtk.Dialog.__init__(self, title=language['advanced_settings'], - flags=gtk.DIALOG_MODAL, buttons=(gtk.STOCK_CANCEL, - gtk.RESPONSE_REJECT, - gtk.STOCK_OK, - gtk.RESPONSE_ACCEPT)) - # Set up the Advanced Settings Dialog. - self.txt_ip = LabelEntry(language['ip']) - self.txt_ip.entry.connect('focus-out-event', self.set_defaults) - self.txt_netmask = LabelEntry(language['netmask']) - self.txt_gateway = LabelEntry(language['gateway']) - self.txt_dns_1 = LabelEntry(language['dns'] + ' ' + language['1']) - self.txt_dns_2 = LabelEntry(language['dns'] + ' ' + language['2']) - self.txt_dns_3 = LabelEntry(language['dns'] + ' ' + language['3']) - self.chkbox_static_ip = gtk.CheckButton(language['use_static_ip']) - self.chkbox_static_dns = gtk.CheckButton(language['use_static_dns']) - self.chkbox_global_dns = gtk.CheckButton(language['use_global_dns']) - self.hbox_dns = gtk.HBox(False, 0) - self.hbox_dns.pack_start(self.chkbox_static_dns) - self.hbox_dns.pack_start(self.chkbox_global_dns) - - self.vbox.pack_start(self.chkbox_static_ip, fill=False, expand=False) - self.vbox.pack_start(self.txt_ip, fill=False, expand=False) - self.vbox.pack_start(self.txt_netmask, fill=False, expand=False) - self.vbox.pack_start(self.txt_gateway, fill=False, expand=False) - self.vbox.pack_start(self.hbox_dns, fill=False, expand=False) - self.vbox.pack_start(self.txt_dns_1, fill=False, expand=False) - self.vbox.pack_start(self.txt_dns_2, fill=False, expand=False) - self.vbox.pack_start(self.txt_dns_3, fill=False, expand=False) - - # Connect the events to the actions - self.chkbox_static_ip.connect("toggled", self.toggle_ip_checkbox) - self.chkbox_static_dns.connect("toggled", self.toggle_dns_checkbox) - self.chkbox_global_dns.connect("toggled", self.toggle_global_dns_checkbox) - - # Start with all disabled, then they will be enabled later. - self.chkbox_static_ip.set_active(False) - self.chkbox_static_dns.set_active(False) - - def set_defaults(self, widget=None, event=None): - """ Put some default values into entries to help the user out. """ - ipAddress = self.txt_ip.get_text() # For easy typing :) - netmask = self.txt_netmask - gateway = self.txt_gateway - ip_parts = misc.IsValidIP(ipAddress) - if ip_parts: - if stringToNone(gateway.get_text()) is None: # Make sure the gateway box is blank - # Fill it in with a .1 at the end - gateway.set_text('.'.join(ip_parts[0:3]) + '.1') - - if stringToNone(netmask.get_text()) is None: # Make sure the netmask is blank - netmask.set_text('255.255.255.0') # Fill in the most common one - elif ipAddress != "": - error(None, "Invalid IP Address Entered.") - - def reset_static_checkboxes(self): - # Enable the right stuff - if stringToNone(self.txt_ip.get_text()) is not None: - self.chkbox_static_ip.set_active(True) - self.chkbox_static_dns.set_active(True) - self.chkbox_static_dns.set_sensitive(False) - else: - self.chkbox_static_ip.set_active(False) - self.chkbox_static_dns.set_active(False) - self.chkbox_static_dns.set_sensitive(True) - - if stringToNone(self.txt_dns_1.get_text()) is not None: - self.chkbox_static_dns.set_active(True) - else: - self.chkbox_static_dns.set_active(False) - - # This will properly disable unused boxes. - self.toggle_ip_checkbox() - self.toggle_dns_checkbox() - self.toggle_global_dns_checkbox() - - def toggle_ip_checkbox(self, widget=None): - """Toggle entries/checkboxes based on the static IP checkbox. """ - # Should disable the static IP text boxes, and also enable the DNS - # checkbox when disabled and disable when enabled. - if self.chkbox_static_ip.get_active(): - self.chkbox_static_dns.set_active(True) - self.chkbox_static_dns.set_sensitive(False) - else: - self.chkbox_static_dns.set_sensitive(True) - self.chkbox_static_dns.set_active(False) - - self.txt_ip.set_sensitive(self.chkbox_static_ip.get_active()) - self.txt_netmask.set_sensitive(self.chkbox_static_ip.get_active()) - self.txt_gateway.set_sensitive(self.chkbox_static_ip.get_active()) - - def toggle_dns_checkbox(self, widget=None): - """ Toggle entries and checkboxes based on the static dns checkbox. """ - # Should disable the static DNS boxes - if self.chkbox_static_ip.get_active(): - self.chkbox_static_dns.set_active(self.chkbox_static_ip. - get_active()) - self.chkbox_static_dns.set_sensitive(False) - - self.chkbox_global_dns.set_sensitive(self.chkbox_static_dns. - get_active()) - if self.chkbox_static_dns.get_active(): - # If global dns is on, don't use local dns - self.txt_dns_1.set_sensitive(not self.chkbox_global_dns.get_active()) - self.txt_dns_2.set_sensitive(not self.chkbox_global_dns.get_active()) - self.txt_dns_3.set_sensitive(not self.chkbox_global_dns.get_active()) - else: - self.txt_dns_1.set_sensitive(False) - self.txt_dns_2.set_sensitive(False) - self.txt_dns_3.set_sensitive(False) - self.chkbox_global_dns.set_active(False) - - def toggle_global_dns_checkbox(self, widget=None): - """ Set the DNS entries' sensitivity based on the Global checkbox. """ - if daemon.GetUseGlobalDNS() and self.chkbox_static_dns.get_active(): - self.txt_dns_1.set_sensitive(not self.chkbox_global_dns.get_active()) - self.txt_dns_2.set_sensitive(not self.chkbox_global_dns.get_active()) - self.txt_dns_3.set_sensitive(not self.chkbox_global_dns.get_active()) - - def destroy_called(self): - """ Clean up everything. - - This might look excessive, but it was the only way to prevent - memory leakage. - - """ - for obj in vars(self): - if hasattr(obj, "destroy"): - obj.destroy() - if hasattr(obj, "__del__"): - obj.__del__() - else: - del obj - super(AdvancedSettingsDialog, self).destroy() - self.destroy() - del self - - -class WiredSettingsDialog(AdvancedSettingsDialog): - def __init__(self, name): - """ Build the wired settings dialog. """ - AdvancedSettingsDialog.__init__(self) - self.des = self.connect("destroy", self.destroy_called) - self.prof_name = name - - def set_net_prop(self, option, value): - """ Sets the given option to the given value for this network. """ - wired.SetWiredProperty(option, value) - - def set_values(self): - """ Fill in the Gtk.Entry objects with the correct values. """ - self.txt_ip.set_text(self.format_entry("ip")) - self.txt_netmask.set_text(self.format_entry("netmask")) - self.txt_gateway.set_text(self.format_entry("gateway")) - - self.txt_dns_1.set_text(self.format_entry("dns1")) - self.txt_dns_2.set_text(self.format_entry("dns2")) - self.txt_dns_3.set_text(self.format_entry("dns3")) - self.reset_static_checkboxes() - - def format_entry(self, label): - """ Helper method to fetch and format wired properties. """ - return noneToBlankString(wired.GetWiredProperty(label)) - - def destroy_called(self): - """ Clean up everything. - - This might look excessive, but it was the only way to prevent - memory leakage. - - """ - self.disconnect(self.des) - for obj in vars(self): - if hasattr(obj, "destroy"): - obj.destroy() - if hasattr(obj, "__del__"): - obj.__del__() - else: - del obj - super(WiredSettingsDialog, self).destroy_called() - self.destroy() - del self - - -class WirelessSettingsDialog(AdvancedSettingsDialog): - def __init__(self, networkID): - """ Build the wireless settings dialog. """ - AdvancedSettingsDialog.__init__(self) - # Set up encryption stuff - self.networkID = networkID - self.combo_encryption = gtk.combo_box_new_text() - self.chkbox_encryption = gtk.CheckButton(language['use_encryption']) - self.chkbox_global_settings = gtk.CheckButton(language['global_settings']) - # Make the vbox to hold the encryption stuff. - self.vbox_encrypt_info = gtk.VBox(False, 0) - self.toggle_encryption() - self.chkbox_encryption.set_active(False) - self.combo_encryption.set_sensitive(False) - self.encrypt_types = misc.LoadEncryptionMethods() - - # Build the encryption menu - activeID = -1 # Set the menu to this item when we are done - for x, enc_type in enumerate(self.encrypt_types): - self.combo_encryption.append_text(enc_type[0]) - if enc_type[1] == wireless.GetWirelessProperty(networkID, - "enctype"): - activeID = x - self.combo_encryption.set_active(activeID) - if activeID != -1: - self.chkbox_encryption.set_active(True) - self.combo_encryption.set_sensitive(True) - self.vbox_encrypt_info.set_sensitive(True) - else: - self.combo_encryption.set_active(0) - self.change_encrypt_method() - self.vbox.pack_start(self.chkbox_global_settings, False, False) - self.vbox.pack_start(self.chkbox_encryption, False, False) - self.vbox.pack_start(self.combo_encryption) - self.vbox.pack_start(self.vbox_encrypt_info) - - # Connect signals. - self.chkbox_encryption.connect("toggled", self.toggle_encryption) - self.combo_encryption.connect("changed", self.change_encrypt_method) - self.des = self.connect("destroy", self.destroy_called) - - def destroy_called(self): - """ Clean up everything. - - This might look excessive, but it was the only way to prevent - memory leakage. - - """ - self.disconnect(self.des) - for obj in vars(self): - if hasattr(obj, "destroy"): - obj.destroy() - if hasattr(obj, "__del__"): - obj.__del__() - else: - del obj - super(WirelessSettingsDialog, self).destroy_called() - self.destroy() - del self - - def set_net_prop(self, option, value): - """ Sets the given option to the given value for this network. """ - wireless.SetWirelessProperty(self.networkID, option, value) - - def set_values(self): - """ Set the various network settings to the right values. """ - networkID = self.networkID - self.txt_ip.set_text(self.format_entry(networkID,"ip")) - self.txt_netmask.set_text(self.format_entry(networkID,"netmask")) - self.txt_gateway.set_text(self.format_entry(networkID,"gateway")) - - if wireless.GetWirelessProperty(networkID,'use_global_dns'): - self.chkbox_global_dns.set_active(True) - if wireless.GetWirelessProperty(networkID, "dns1") is not None: - self.txt_dns_1.set_text(self.format_entry(networkID, "dns1")) - if wireless.GetWirelessProperty(networkID, 'dns2') is not None: - self.txt_dns_2.set_text(self.format_entry(networkID, "dns2")) - if wireless.GetWirelessProperty(networkID, 'dns3') is not None: - self.txt_dns_3.set_text(self.format_entry(networkID, "dns3")) - - self.reset_static_checkboxes() - if wireless.GetWirelessProperty(networkID, 'encryption'): - self.chkbox_encryption.set_active(True) - else: - self.chkbox_encryption.set_active(False) - - if wireless.GetWirelessProperty(networkID, 'use_settings_globally'): - self.chkbox_global_settings.set_active(True) - else: - self.chkbox_global_settings.set_active(False) - - def format_entry(self, networkid, label): - """ Helper method for fetching/formatting wireless properties. """ - return noneToBlankString(wireless.GetWirelessProperty(networkid, label)) - - def toggle_encryption(self, widget=None): - """ Toggle the encryption combobox based on the encryption checkbox. """ - active = self.chkbox_encryption.get_active() - self.vbox_encrypt_info.set_sensitive(active) - self.combo_encryption.set_sensitive(active) - - def change_encrypt_method(self, widget=None): - """ Load all the entries for a given encryption method. """ - for z in self.vbox_encrypt_info: - z.destroy() # Remove stuff in there already - ID = self.combo_encryption.get_active() - methods = misc.LoadEncryptionMethods() - self.encryption_info = {} - - # If nothing is selected, select the first entry. - if ID == -1: - self.combo_encryption.set_active(0) - ID = 0 - - opts = methods[ID][2] - for x in opts: - box = None - if language.has_key(opts[x][0]): - box = LabelEntry(language[opts[x][0].lower().replace(' ','_')]) - else: - box = LabelEntry(opts[x][0].replace('_',' ')) - box.set_auto_hidden(True) - self.vbox_encrypt_info.pack_start(box) - #add the data to any array, so that the information - #can be easily accessed by giving the name of the wanted - #data - self.encryption_info[opts[x][1]] = box.entry - - box.entry.set_text(noneToBlankString( - wireless.GetWirelessProperty(self.networkID, opts[x][1]))) - self.vbox_encrypt_info.show_all() - - -class NetworkEntry(gtk.HBox): - def __init__(self): - """ Base network entry class. - - Provides gtk objects used by both the WiredNetworkEntry and - WirelessNetworkEntry classes. - - """ - gtk.HBox.__init__(self, False, 2) - self.expander = gtk.Expander() - self.image = gtk.Image() - self.pack_start(self.image, False, False) - - # Set up the Connect button - self.connect_button = gtk.Button(stock=gtk.STOCK_CONNECT) - self.connect_hbox = gtk.HBox(False, 2) - self.connect_hbox.pack_start(self.connect_button, False, False) - self.connect_hbox.show() - - # Set up the Disconnect button - self.disconnect_button = gtk.Button(stock=gtk.STOCK_DISCONNECT) - self.connect_hbox.pack_start(self.disconnect_button, False, False) - - # Set up the VBox that goes in the gtk.Expander - self.expander_vbox = gtk.VBox(False, 1) - self.expander_vbox.show() - self.expander_vbox.pack_start(self.expander) - self.expander_vbox.pack_start(self.connect_hbox, False, False) - self.pack_end(self.expander_vbox) - - # Set up the advanced settings button - self.advanced_button = gtk.Button() - self.advanced_image = gtk.Image() - self.advanced_image.set_from_stock(gtk.STOCK_EDIT, 4) - self.advanced_image.set_padding(4, 0) - self.advanced_button.set_alignment(.5, .5) - self.advanced_button.set_label(language['advanced_settings']) - self.advanced_button.set_image(self.advanced_image) - - # Set up the script settings button - self.script_button = gtk.Button() - self.script_image = gtk.Image() - self.script_image.set_from_icon_name('execute', 4) - self.script_image.set_padding(4, 0) - self.script_button.set_alignment(.5, .5) - self.script_button.set_image(self.script_image) - self.script_button.set_label(language['scripts']) - - self.settings_hbox = gtk.HBox(False, 3) - self.settings_hbox.set_border_width(5) - self.settings_hbox.pack_start(self.script_button, False, False) - self.settings_hbox.pack_start(self.advanced_button, False, False) - - self.vbox_top = gtk.VBox(False, 0) - self.vbox_top.pack_end(self.settings_hbox, False, False) - - aligner = gtk.Alignment(xscale=1.0) - aligner.add(self.vbox_top) - aligner.set_padding(0, 0, 15, 0) - 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): - try: obj.destroy() - except: pass - if hasattr(obj, '__del__'): - obj.__del__() - else: - del obj - for obj in vars(super(NetworkEntry, self)): - try: obj.destroy() - except: pass - if hasattr(obj, '__del__'): - obj.__del__() - else: - del obj - super(NetworkEntry, self).destroy() - self.destroy() - - -class WiredNetworkEntry(NetworkEntry): - def __init__(self): - """ Load the wired network entry. """ - NetworkEntry.__init__(self) - # Center the picture and pad it a bit - self.image.set_alignment(.5, 0) - self.image.set_size_request(60, -1) - self.image.set_from_icon_name("network-wired", 6) - self.image.show() - self.expander.show() - self.connect_button.show() - - self.expander.set_label(language['wired_network']) - #self.reset_static_checkboxes() - self.is_full_gui = True - - self.button_add = gtk.Button(stock=gtk.STOCK_ADD) - self.button_delete = gtk.Button(stock=gtk.STOCK_DELETE) - self.profile_help = gtk.Label(language['wired_network_instructions']) - self.chkbox_default_profile = gtk.CheckButton(language['default_wired']) - - # Build the profile list. - self.combo_profile_names = gtk.combo_box_entry_new_text() - self.profile_list = config.GetWiredProfileList() - if self.profile_list: - for x in self.profile_list: - self.combo_profile_names.append_text(x) - - # Format the profile help label. - self.profile_help.set_justify(gtk.JUSTIFY_LEFT) - self.profile_help.set_line_wrap(True) - - # Pack the various VBox objects. - self.hbox_temp = gtk.HBox(False, 0) - self.hbox_def = gtk.HBox(False, 0) - self.vbox_top.pack_start(self.profile_help, True, True) - self.vbox_top.pack_start(self.hbox_def) - self.vbox_top.pack_start(self.hbox_temp) - self.hbox_temp.pack_start(self.combo_profile_names, True, True) - self.hbox_temp.pack_start(self.button_add, False, False) - self.hbox_temp.pack_start(self.button_delete, False, False) - self.hbox_def.pack_start(self.chkbox_default_profile, False, False) - - # Connect events - self.button_add.connect("clicked", self.add_profile) - self.button_delete.connect("clicked", self.remove_profile) - self.chkbox_default_profile.connect("toggled", - self.toggle_default_profile) - self.combo_profile_names.connect("changed", self.change_profile) - self.script_button.connect("button-press-event", self.edit_scripts) - - # Toggle the default profile checkbox to the correct state. - if stringToBoolean(wired.GetWiredProperty("default")): - self.chkbox_default_profile.set_active(True) - else: - self.chkbox_default_profile.set_active(False) - - # Show everything, but hide the profile help label. - self.show_all() - self.profile_help.hide() - self.advanced_dialog = WiredSettingsDialog(self.combo_profile_names.get_active_text()) - - # Display the default profile if it exists. - if self.profile_list is not None: - prof = config.GetDefaultWiredNetwork() - if prof != None: # Make sure the default profile gets displayed. - i = 0 - while self.combo_profile_names.get_active_text() != prof: - self.combo_profile_names.set_active(i) - i += 1 - else: - self.combo_profile_names.set_active(0) - print "wired profiles found" - self.expander.set_expanded(False) - else: - print "no wired profiles found" - if not wired.GetAlwaysShowWiredInterface(): - self.expander.set_expanded(True) - self.profile_help.show() - self.check_enable() - self.update_connect_button() - 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. - - """ - self.disconnect(self.wireddis) - self.advanced_dialog.destroy_called() - del self.advanced_dialog - for obj in vars(self): - if hasattr(obj, "destroy"): - obj.destroy() - if hasattr(obj, '__del__'): - obj.__del__() - else: - del obj - super(WiredNetworkEntry, self).destroy_called() - self.destroy() - del self - - def edit_scripts(self, widget=None, event=None): - """ Launch the script editting dialog. """ - profile = self.combo_profile_names.get_active_text() - try: - sudo_prog = misc.choose_sudo_prog() - if sudo_prog.endswith("gksu"): - msg = "-m" - else: - msg = "--caption" - os.spawnlpe(os.P_WAIT, sudo_prog, msg, - "You must enter your password to configure scripts.", - "./configscript.py", profile, "wired", os.environ) - except IOError: - gui.error("Could not find a graphical sudo program." + \ - " Script editor could no be launched.") - - def check_enable(self): - """ Disable objects if the profile list is empty. """ - profile_list = config.GetWiredProfileList() - if profile_list == None: - self.button_delete.set_sensitive(False) - self.connect_button.set_sensitive(False) - self.advanced_button.set_sensitive(False) - self.script_button.set_sensitive(False) - - def update_connect_button(self, apbssid=None): - """ Update the connection/disconnect button for this entry. """ - state, x = daemon.GetConnectionStatus() - if state == misc.WIRED: - self.disconnect_button.show() - self.connect_button.hide() - else: - self.disconnect_button.hide() - self.connect_button.show() - - def add_profile(self, widget): - """ Add a profile to the profile list. """ - print "adding profile" - profile_name = self.combo_profile_names.get_active_text() - profile_list = config.GetWiredProfileList() - if profile_list: - if profile_name in profile_list: - return False - if profile_name != "": - self.profile_help.hide() - config.CreateWiredNetworkProfile(profile_name) - self.combo_profile_names.prepend_text(profile_name) - self.combo_profile_names.set_active(0) - self.advanced_dialog.prof_name = profile_name - if self.is_full_gui: - self.button_delete.set_sensitive(True) - self.connect_button.set_sensitive(True) - self.advanced_button.set_sensitive(True) - self.script_button.set_sensitive(True) - - def remove_profile(self, widget): - """ Remove a profile from the profile list. """ - print "removing profile" - profile_name = self.combo_profile_names.get_active_text() - config.DeleteWiredNetworkProfile(profile_name) - self.combo_profile_names.remove_text(self.combo_profile_names. - get_active()) - self.combo_profile_names.set_active(0) - self.advanced_dialog.prof_name = self.combo_profile_names.get_active_text() - if not config.GetWiredProfileList(): - self.profile_help.show() - entry = self.combo_profile_names.child - entry.set_text("") - if self.is_full_gui: - self.button_delete.set_sensitive(False) - self.advanced_button.set_sensitive(False) - self.script_button.set_sensitive(False) - self.connect_button.set_sensitive(False) - else: - self.profile_help.hide() - - def toggle_default_profile(self, widget): - """ Change the default profile. """ - if self.chkbox_default_profile.get_active(): - # Make sure there is only one default profile at a time - config.UnsetWiredDefault() - wired.SetWiredProperty("default", - self.chkbox_default_profile.get_active()) - config.SaveWiredNetworkProfile(self.combo_profile_names.get_active_text()) - - def change_profile(self, widget): - """ Called when a new profile is chosen from the list. """ - # Make sure the name doesn't change everytime someone types something - if self.combo_profile_names.get_active() > -1: - if not self.is_full_gui: - return - - profile_name = self.combo_profile_names.get_active_text() - config.ReadWiredNetworkProfile(profile_name) - - self.advanced_dialog.txt_ip.set_text(self.format_entry("ip")) - self.advanced_dialog.txt_netmask.set_text(self.format_entry("netmask")) - self.advanced_dialog.txt_gateway.set_text(self.format_entry("gateway")) - self.advanced_dialog.txt_dns_1.set_text(self.format_entry("dns1")) - self.advanced_dialog.txt_dns_2.set_text(self.format_entry("dns2")) - self.advanced_dialog.txt_dns_3.set_text(self.format_entry("dns3")) - self.advanced_dialog.prof_name = profile_name - - is_default = wired.GetWiredProperty("default") - self.chkbox_default_profile.set_active(stringToBoolean(is_default)) - - def format_entry(self, label): - """ Help method for fetching/formatting wired properties. """ - return noneToBlankString(wired.GetWiredProperty(label)) - - -class WirelessNetworkEntry(NetworkEntry): - def __init__(self, networkID): - """ Build the wireless network entry. """ - NetworkEntry.__init__(self) - - self.networkID = networkID - self.image.set_padding(0, 0) - self.image.set_alignment(.5, 0) - self.image.set_size_request(60, -1) - self.image.set_from_icon_name("network-wired", 6) - self.essid = wireless.GetWirelessProperty(networkID, "essid") - print "ESSID : " + self.essid - # Make the combo box. - self.lbl_strength = GreyLabel() - self.lbl_encryption = GreyLabel() - self.lbl_mac = GreyLabel() - self.lbl_channel = GreyLabel() - self.lbl_mode = GreyLabel() - self.hbox_status = gtk.HBox(False, 5) - self.chkbox_autoconnect = gtk.CheckButton(language['automatic_connect']) - - # Set the values of the network info labels. - self.set_signal_strength(wireless.GetWirelessProperty(networkID, - 'quality'), - wireless.GetWirelessProperty(networkID, - 'strength')) - self.set_mac_address(wireless.GetWirelessProperty(networkID, 'bssid')) - self.set_mode(wireless.GetWirelessProperty(networkID, 'mode')) - self.set_channel(wireless.GetWirelessProperty(networkID, 'channel')) - self.set_encryption(wireless.GetWirelessProperty(networkID, - 'encryption'), - wireless.GetWirelessProperty(networkID, - 'encryption_method')) - - # The the expander label. - self.expander.set_use_markup(True) - - self.expander.set_label(self._escape(self.essid) + " " + - self.lbl_strength.get_label() + " " + - self.lbl_encryption.get_label() + " " + - self.lbl_mac.get_label()) - - # Pack the network status HBox. - self.hbox_status.pack_start(self.lbl_strength, True, True) - self.hbox_status.pack_start(self.lbl_encryption, True, True) - self.hbox_status.pack_start(self.lbl_mac, True, True) - self.hbox_status.pack_start(self.lbl_mode, True, True) - self.hbox_status.pack_start(self.lbl_channel, True, True) - - # Add the wireless network specific parts to the NetworkEntry - # VBox objects. - self.vbox_top.pack_start(self.chkbox_autoconnect, False, False) - self.vbox_top.pack_start(self.hbox_status, True, True) - - if stringToBoolean(self.format_entry(networkID, "automatic")): - self.chkbox_autoconnect.set_active(True) - else: - self.chkbox_autoconnect.set_active(False) - - # Connect signals. - self.chkbox_autoconnect.connect("toggled", self.update_autoconnect) - self.script_button.connect("button-press-event", self.edit_scripts) - - # Show everything - self.show_all() - self.advanced_dialog = WirelessSettingsDialog(networkID) - self.update_connect_button(wireless.GetApBssid()) - self.wifides = self.connect("destroy", self.destroy_called) - - def _escape(self, val): - return val.replace("&", "&").replace("<", "<").\ - replace(">",">").replace("'", "'").replace('"', """) - - def destroy_called(self, *args): - """ Clean up everything. - - This might look excessive, but it was the only way to prevent - memory leakage. - - """ - self.disconnect(self.wifides) - self.advanced_dialog.destroy_called() - del self.advanced_dialog - for obj in vars(self): - if hasattr(obj, "destroy"): - obj.destroy() - - if hasattr(obj, '__del__'): - obj.__del__() - else: - del obj - super(WirelessNetworkEntry, self).destroy_called() - self.destroy() - del self - - def set_signal_strength(self, strength, dbm_strength): - """ Set the signal strength displayed in the WirelessNetworkEntry. """ - if strength is not None: - strength = int(strength) - else: - strength = -1 - if dbm_strength is not None: - dbm_strength = int(dbm_strength) - else: - dbm_strength = -100 - display_type = daemon.GetSignalDisplayType() - if daemon.GetWPADriver() == 'ralink legacy' or display_type == 1: - # Use the -xx dBm signal strength to display a signal icon - # I'm not sure how accurately the dBm strength is being - # "converted" to strength bars, so suggestions from people - # for a better way would be welcome. - if dbm_strength >= -60: - signal_img = 'signal-100.png' - elif dbm_strength >= -70: - signal_img = 'signal-75.png' - elif dbm_strength >= -80: - signal_img = 'signal-50.png' - else: - signal_img = 'signal-25.png' - ending = "dBm" - disp_strength = str(dbm_strength) - else: - # Uses normal link quality, should be fine in most cases - if strength > 75: - signal_img = 'signal-100.png' - elif strength > 50: - signal_img = 'signal-75.png' - elif strength > 25: - signal_img = 'signal-50.png' - else: - signal_img = 'signal-25.png' - ending = "%" - disp_strength = str(strength) - - self.image.set_from_file(wpath.images + signal_img) - self.lbl_strength.set_label(disp_strength + ending) - - def update_connect_button(self, apbssid): - """ Update the connection/disconnect button for this entry. """ - state, x = daemon.GetConnectionStatus() - if state == misc.WIRELESS and apbssid == \ - wireless.GetWirelessProperty(self.networkID, "bssid"): - self.disconnect_button.show() - self.connect_button.hide() - else: - self.disconnect_button.hide() - self.connect_button.show() - - def set_mac_address(self, address): - """ Set the MAC address for the WirelessNetworkEntry. """ - self.lbl_mac.set_label(str(address)) - - def set_encryption(self, on, ttype): - """ Set the encryption value for the WirelessNetworkEntry. """ - if on and ttype: - self.lbl_encryption.set_label(str(ttype)) - if on and not ttype: - self.lbl_encryption.set_label(language['secured']) - if not on: - self.lbl_encryption.set_label(language['unsecured']) - - def set_channel(self, channel): - """ Set the channel value for the WirelessNetworkEntry. """ - self.lbl_channel.set_label(language['channel'] + ' ' + str(channel)) - - def set_mode(self, mode): - """ Set the mode value for the WirelessNetworkEntry. """ - self.lbl_mode.set_label(str(mode)) - - def format_entry(self, networkid, label): - """ Helper method for fetching/formatting wireless properties. """ - return noneToBlankString(wireless.GetWirelessProperty(networkid, label)) - - def edit_scripts(self, widget=None, event=None): - """ Launch the script editting dialog. """ - try: - sudo_prog = misc.choose_sudo_prog() - if sudo_prog.endswith("gksu"): - msg = "-m" - else: - msg = "--caption" - os.spawnlpe(os.P_WAIT, sudo_prog, msg, - "You must enter your password to configure scripts.", - "./configscript.py", str(self.networkID), "wireless", - os.environ) - except IOError: - gui.error("Could not find a graphical sudo program." + \ - " Script editor could no be launched.") - - def update_autoconnect(self, widget=None): - """ Called when the autoconnect checkbox is toggled. """ - wireless.SetWirelessProperty(self.networkID, "automatic", - noneToString(self.chkbox_autoconnect. - get_active())) - config.SaveWirelessNetworkProperty(self.networkID, "automatic") - class WiredProfileChooser: """ Class for displaying the wired profile chooser. """ @@ -1141,7 +148,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() + wired_net_entry = WiredNetworkEntry(dbus_ifaces) dialog = gtk.Dialog(title = language['wired_network_found'], flags = gtk.DIALOG_MODAL, @@ -1233,6 +240,7 @@ class appGui: self.pulse_active = False self.standalone = standalone self.wpadrivercombo = None + self.connecting = False self.fast = True # Use ioctl instead of external program calls self.refresh_networks(fresh=False) @@ -1625,9 +633,9 @@ class appGui: fast = self.fast wired_connecting = wired.CheckIfWiredConnecting() wireless_connecting = wireless.CheckIfWirelessConnecting() - connecting = wired_connecting or wireless_connecting + self.connecting = wired_connecting or wireless_connecting - if connecting: + if self.connecting: if not self.pulse_active: self.pulse_active = True gobject.timeout_add(100, self.pulse_progress_bar) @@ -1723,7 +731,8 @@ class appGui: """ print 'got rescan signal' - self.refresh_networks(fresh=False) + if not self.connecting: + self.refresh_networks(fresh=False) def refresh_networks(self, widget=None, fresh=True, hidden=None): """ Refreshes the network list. @@ -1747,7 +756,7 @@ class appGui: if wired.CheckPluggedIn(self.fast) or wired.GetAlwaysShowWiredInterface(): printLine = True # In this case we print a separator. - wirednet = WiredNetworkEntry() + wirednet = WiredNetworkEntry(dbus_ifaces) self.network_list.pack_start(wirednet, False, False) wirednet.connect_button.connect("button-press-event", self.connect, "wired", 0, wirednet) @@ -1775,7 +784,7 @@ class appGui: sep.show() else: printLine = True - tempnet = WirelessNetworkEntry(x) + tempnet = WirelessNetworkEntry(x, dbus_ifaces) self.network_list.pack_start(tempnet, False, False) tempnet.connect_button.connect("button-press-event", self.connect, "wireless", x, @@ -2062,6 +1071,11 @@ class appGui: if __name__ == '__main__': + if not proxy_obj: + error("Could not connect to wicd's D-Bus interface. Make sure the " + + "daemon is started") + sys.exit(1) + app = appGui(standalone=True) bus.add_signal_receiver(app.dbus_refresh_networks, 'SendScanSignal', 'org.wicd.daemon') diff --git a/misc.py b/misc.py index ef16c03..fb7edb2 100644 --- a/misc.py +++ b/misc.py @@ -21,9 +21,10 @@ import os import wpath import locale import gettext -import time import sys from subprocess import * +import subprocess +import commands if __name__ == '__main__': wpath.chdir(__file__) @@ -45,6 +46,10 @@ MIITOOL = 2 IP = 1 ROUTE = 2 +class WicdError(Exception): + pass + + def Run(cmd, include_stderr=False, return_pipe=False): """ Run a command. @@ -76,6 +81,10 @@ def Run(cmd, include_stderr=False, return_pipe=False): return f.stdout else: return f.communicate()[0] + +def LaunchAndWait(cmd): + """ Launches the given program with the given arguments, then blocks. """ + subprocess.call(cmd) def IsValidIP(ip): """ Make sure an entered IP is valid """ @@ -91,15 +100,15 @@ def IsValidIP(ip): def PromptToStartDaemon(): """ Prompt the user to start the daemon """ daemonloc = wpath.bin + 'launchdaemon.sh' - sudo_prog = choose_sudo_prog + sudo_prog = choose_sudo_prog() if sudo_prog.endswith("gksu"): msg = '--message' else: msg = '-- caption' - gksudo_args = [sudo_prog, msg, + sudo_args = [sudo_prog, msg, 'Wicd needs to access your computer\'s network cards.', '--', daemonloc] - os.spawnvpe(os.P_WAIT, 'gksudo', gksudo_args, os.environ) + os.spawnvpe(os.P_WAIT, sudo_prog, sudo_args, os.environ) def RunRegex(regex, string): """ runs a regex search on a string """ @@ -108,10 +117,6 @@ def RunRegex(regex, string): return m.groups()[0] else: return None - -def log(text): - log = LogWriter() - log.write(text + "\n") def WriteLine(my_file, text): """ write a line to a file """ @@ -174,8 +179,7 @@ def ParseEncryption(network): # Write the data to the files then chmod them so they can't be read # by normal users. - file = open(wpath.networks + network["bssid"].replace(":", "").lower(), - "w") + file = open(wpath.networks + network["bssid"].replace(":", "").lower(), "w") os.chmod(wpath.networks + network["bssid"].replace(":", "").lower(), 0600) os.chown(wpath.networks + network["bssid"].replace(":", "").lower(), 0, 0) # We could do this above, but we'd like to read protect @@ -259,8 +263,7 @@ def noneToString(text): def get_gettext(): """ Set up gettext for translations. """ - # Translation stuff - # borrowed from an excellent post on how to do this on + # Borrowed from an excellent post on how to do this at # http://www.learningpython.com/2006/12/03/translating-your-pythonpygtk-application/ local_path = os.path.realpath(os.path.dirname(sys.argv[0])) + \ '/translations' @@ -305,14 +308,185 @@ def RenameProcess(new_name): return True except: return False + +def detect_desktop_environment(): + desktop_environment = 'generic' + if os.environ.get('KDE_FULL_SESSION') == 'true': + desktop_environment = 'kde' + elif os.environ.get('GNOME_DESKTOP_SESSION_ID'): + desktop_environment = 'gnome' + else: + try: + info = commands.getoutput('xprop -root _DT_SAVE_MODE') + if ' = "xfce4"' in info: + desktop_environment = 'xfce' + except (OSError, RuntimeError): + pass + + return desktop_environment def choose_sudo_prog(): - paths = ["/usr/bin/", "/usr/local/bin/"] - progs = ["gksu", "kdesu"] - choices = [] + desktop_env = detect_desktop_environment() + gk_paths = ["/usr/bin/gksu", "/usr/local/bin/gksu", "/bin/gksu"] + kde_paths = ["/usr/bin/kdesu", "/usr/local/bin/kdesu", "/bin/kdesu"] + if desktop_env == "kde": + paths = kde_paths + paths.extend(gk_paths) + else: + paths = gk_paths + paths.extend(kde_paths) for path in paths: - for prog in progs: - if os.access(path, os.F_OK): - return path + prog + if os.access(path, os.F_OK): + return path - raise IOError("Couldn't find graphic sudo program") + raise WicdError("Couldn't find graphical sudo program.") + +def get_language_list_gui(): + """ Returns a dict of translatable strings used by the GUI. + + translations are done at http://wicd.net/translator. Please + translate if you can. + + """ + _ = get_gettext() + language = {} + language['connect'] = _("Connect") + language['ip'] = _("IP") + language['netmask'] = _("Netmask") + language['gateway'] = _('Gateway') + language['dns'] = _('DNS') + language['use_static_ip'] = _('Use Static IPs') + language['use_static_dns'] = _('Use Static DNS') + language['use_encryption'] = _('Use Encryption') + language['advanced_settings'] = _('Advanced Settings') + language['wired_network'] = _('Wired Network') + language['wired_network_instructions'] = _('To connect to a wired network,' + ' you must create a network profile. To create a network profile, type a' + ' name that describes this network, and press Add.') + language['automatic_connect'] = _('Automatically connect to this network') + language['secured'] = _('Secured') + language['unsecured'] = _('Unsecured') + language['channel'] = _('Channel') + language['preferences'] = _('Preferences') + language['wpa_supplicant_driver'] = _('WPA Supplicant Driver') + language['wireless_interface'] = _('Wireless Interface') + language['wired_interface'] = _('Wired Interface') + language['hidden_network'] = _('Hidden Network') + language['hidden_network_essid'] = _('Hidden Network ESSID') + language['connected_to_wireless'] = _('Connected to $A at $B (IP: $C)') + language['connected_to_wired'] = _('Connected to wired network (IP: $A)') + language['not_connected'] = _('Not connected') + language['no_wireless_networks_found'] = _('No wireless networks found.') + language['killswitch_enabled'] = _('Wireless Kill Switch Enabled') + language['key'] = _('Key') + language['username'] = _('Username') + language['password'] = _('Password') + language['anonymous_identity'] = _('Anonymous Identity') + language['identity'] = _('Identity') + language['authentication'] = _('Authentication') + language['path_to_pac_file'] = _('Path to PAC File') + language['select_a_network'] = _('Choose from the networks below:') + language['connecting'] = _('Connecting...') + language['wired_always_on'] = _('Always show wired interface') + language['auto_reconnect'] = _('Automatically reconnect on connection loss') + language['create_adhoc_network'] = _('Create an Ad-Hoc Network') + language['essid'] = _('ESSID') + language['use_wep_encryption'] = _('Use Encryption (WEP only)') + language['before_script'] = _('Run script before connect') + language['after_script'] = _('Run script after connect') + language['disconnect_script'] = _('Run disconnect script') + language['script_settings'] = _('Scripts') + language['use_ics'] = _('Activate Internet Connection Sharing') + language['madwifi_for_adhoc'] = _('Check if using madwifi/atheros drivers') + language['default_wired'] = _('Use as default profile (overwrites any previous default)') + language['use_debug_mode'] = _('Enable debug mode') + language['use_global_dns'] = _('Use global DNS servers') + language['use_default_profile'] = _('Use default profile on wired autoconnect') + language['show_wired_list'] = _('Prompt for profile on wired autoconnect') + language['use_last_used_profile'] = _('Use last used profile on wired autoconnect') + language['choose_wired_profile'] = _('Select or create a wired profile to connect with') + language['wired_network_found'] = _('Wired connection detected') + language['stop_showing_chooser'] = _('Stop Showing Autoconnect pop-up temporarily') + language['display_type_dialog'] = _('Use dBm to measure signal strength') + language['scripts'] = _('Scripts') + language['invalid_address'] = _('Invalid address in $A entry.') + language['global_settings'] = _('Use these settings for all networks sharing this essid') + language['encrypt_info_missing'] = _('Required encryption information is missing.') + language['enable_encryption'] = _('This network requires encryption to be enabled.') + language['wicd_auto_config'] = _('Automatic (recommended)') + language["gen_settings"] = _("General Settings") + language["ext_programs"] = _("External Programs") + language["dhcp_client"] = _("DHCP Client") + language["wired_detect"] = _("Wired Link Detection") + language["route_flush"] = _("Route Table Flushing") + + language['0'] = _('0') + language['1'] = _('1') + language['2'] = _('2') + language['3'] = _('3') + language['4'] = _('4') + language['5'] = _('5') + language['6'] = _('6') + language['7'] = _('7') + language['8'] = _('8') + language['9'] = _('9') + + language['interface_down'] = _('Putting interface down...') + language['resetting_ip_address'] = _('Resetting IP address...') + language['interface_up'] = _('Putting interface up...') + language['setting_encryption_info'] = _('Setting encryption info') + language['removing_old_connection'] = _('Removing old connection...') + language['generating_psk'] = _('Generating PSK...') + language['generating_wpa_config'] = _('Generating WPA configuration file...') + language['flushing_routing_table'] = _('Flushing the routing table...') + language['configuring_interface'] = _('Configuring wireless interface...') + language['validating_authentication'] = _('Validating authentication...') + language['setting_broadcast_address'] = _('Setting broadcast address...') + language['setting_static_dns'] = _('Setting static DNS servers...') + language['setting_static_ip'] = _('Setting static IP addresses...') + language['running_dhcp'] = _('Obtaining IP address...') + language['dhcp_failed'] = _('Connection Failed: Unable to Get IP Address') + language['aborted'] = _('Connection Cancelled') + language['bad_pass'] = _('Connection Failed: Bad password') + language['done'] = _('Done connecting...') + + return language + +def get_language_list_tray(): + _ = get_gettext() + language = {} + language['connected_to_wireless'] = _('Connected to $A at $B (IP: $C)') + language['connected_to_wired'] = _('Connected to wired network (IP: $A)') + language['not_connected'] = _('Not connected') + language['killswitch_enabled'] = _('Wireless Kill Switch Enabled') + language['connecting'] = _('Connecting') + language['wired'] = _('Wired Network') + + return language + +def noneToBlankString(text): + """ Converts NoneType or "None" to a blank string. """ + if text in (None, "None"): + return "" + else: + return str(text) + +def stringToNone(text): + """ Performs opposite function of noneToString. """ + if text in ("", None, "None"): + return None + else: + return str(text) + +def stringToBoolean(text): + """ Turns a string representation of a bool to a boolean if needed. """ + if text in ("True", "1"): + return True + if text in ("False", "0"): + return False + return text + +def checkboxTextboxToggle(checkbox, textboxes): + # Really bad practice, but checkbox == self + for textbox in textboxes: + textbox.set_sensitive(checkbox.get_active()) diff --git a/monitor.py b/monitor.py index 793a018..f2c17dd 100755 --- a/monitor.py +++ b/monitor.py @@ -6,7 +6,6 @@ This process is spawned as a child of the daemon, and is responsible for monitoring connection status and initiating autoreconnection when appropriate. - """ # # Copyright (C) 2007 Adam Blackburn @@ -27,7 +26,6 @@ when appropriate. import dbus import gobject -import sys import time from dbus.mainloop.glib import DBusGMainLoop @@ -130,7 +128,8 @@ class ConnectionStatus(): # 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.fast)): + self.network != wireless.GetCurrentNetwork(self.iwconfig, + self.fast)): self.last_strength = wifi_signal self.signal_changed = True daemon.SetCurrentInterface(daemon.GetWirelessInterface()) @@ -154,7 +153,7 @@ class ConnectionStatus(): state = misc.SUSPENDED self.update_state(state) return True - + # Determine what our current state is. # Check for wired. wired_ip = wired.GetWiredIP(self.fast) @@ -162,7 +161,7 @@ class ConnectionStatus(): if wired_found: self.update_state(misc.WIRED, wired_ip=wired_ip) return True - + # Check for wireless wifi_ip = wireless.GetWirelessIP(self.fast) #self.iwconfig = wireless.GetIwconfig() diff --git a/netentry.py b/netentry.py new file mode 100644 index 0000000..0d065a6 --- /dev/null +++ b/netentry.py @@ -0,0 +1,920 @@ +# +# Copyright (C) 2007 Adam Blackburn +# Copyright (C) 2007 Dan O'Reilly +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License Version 2 as +# published by the Free Software Foundation. +# +# 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, see . +# + +import gtk + +import misc +from misc import noneToString, stringToNone, noneToBlankString, stringToBoolean +import wpath + +language = misc.get_language_list_gui() + +# These get set when a NetworkEntry is instantiated. +daemon, wireless, wired, vpn_session, config = [None for x in range(0, 5)] + +def error(parent, message): + """ Shows an error dialog """ + dialog = gtk.MessageDialog(parent, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, + gtk.BUTTONS_OK) + dialog.set_markup(message) + dialog.run() + dialog.destroy() + +class SmallLabel(gtk.Label): + def __init__(self, text=''): + gtk.Label.__init__(self, text) + self.set_size_request(50, -1) + +class LabelEntry(gtk.HBox): + """ A label on the left with a textbox on the right. """ + def __init__(self, text): + gtk.HBox.__init__(self) + self.entry = gtk.Entry() + self.entry.set_size_request(200, -1) + self.label = SmallLabel() + self.label.set_text(text) + self.label.set_size_request(170, -1) + self.pack_start(self.label, fill=False, expand=False) + self.pack_start(self.entry, fill=False, expand=False) + self.label.show() + self.entry.show() + self.entry.connect('focus-out-event', self.hide_characters) + self.entry.connect('focus-in-event', self.show_characters) + self.auto_hide_text = False + self.show() + + def set_text(self, text): + # For compatibility... + self.entry.set_text(text) + + def get_text(self): + return self.entry.get_text() + + def set_auto_hidden(self, value): + self.entry.set_visibility(False) + self.auto_hide_text = value + + def show_characters(self, widget=None, event=None): + # When the box has focus, show the characters + if self.auto_hide_text and widget: + self.entry.set_visibility(True) + + def set_sensitive(self, value): + self.entry.set_sensitive(value) + self.label.set_sensitive(value) + + def hide_characters(self, widget=None, event=None): + # When the box looses focus, hide them + if self.auto_hide_text and widget: + self.entry.set_visibility(False) + + +class GreyLabel(gtk.Label): + """ Creates a grey gtk.Label. """ + def __init__(self): + gtk.Label.__init__(self) + + def set_label(self, text): + self.set_markup("" + text + "") + self.set_alignment(0, 0) + + +class AdvancedSettingsDialog(gtk.Dialog): + def __init__(self): + """ Build the base advanced settings dialog. + + This class isn't used by itself, instead it is used as a parent for + the WiredSettingsDialog and WirelessSettingsDialog. + + """ + gtk.Dialog.__init__(self, title=language['advanced_settings'], + flags=gtk.DIALOG_MODAL, buttons=(gtk.STOCK_CANCEL, + gtk.RESPONSE_REJECT, + gtk.STOCK_OK, + gtk.RESPONSE_ACCEPT)) + # Set up the Advanced Settings Dialog. + self.txt_ip = LabelEntry(language['ip']) + self.txt_ip.entry.connect('focus-out-event', self.set_defaults) + self.txt_netmask = LabelEntry(language['netmask']) + self.txt_gateway = LabelEntry(language['gateway']) + self.txt_dns_1 = LabelEntry(language['dns'] + ' ' + language['1']) + self.txt_dns_2 = LabelEntry(language['dns'] + ' ' + language['2']) + self.txt_dns_3 = LabelEntry(language['dns'] + ' ' + language['3']) + self.chkbox_static_ip = gtk.CheckButton(language['use_static_ip']) + self.chkbox_static_dns = gtk.CheckButton(language['use_static_dns']) + self.chkbox_global_dns = gtk.CheckButton(language['use_global_dns']) + self.hbox_dns = gtk.HBox(False, 0) + self.hbox_dns.pack_start(self.chkbox_static_dns) + self.hbox_dns.pack_start(self.chkbox_global_dns) + + self.vbox.pack_start(self.chkbox_static_ip, fill=False, expand=False) + self.vbox.pack_start(self.txt_ip, fill=False, expand=False) + self.vbox.pack_start(self.txt_netmask, fill=False, expand=False) + self.vbox.pack_start(self.txt_gateway, fill=False, expand=False) + self.vbox.pack_start(self.hbox_dns, fill=False, expand=False) + self.vbox.pack_start(self.txt_dns_1, fill=False, expand=False) + self.vbox.pack_start(self.txt_dns_2, fill=False, expand=False) + self.vbox.pack_start(self.txt_dns_3, fill=False, expand=False) + + # Connect the events to the actions + self.chkbox_static_ip.connect("toggled", self.toggle_ip_checkbox) + self.chkbox_static_dns.connect("toggled", self.toggle_dns_checkbox) + self.chkbox_global_dns.connect("toggled", self.toggle_global_dns_checkbox) + + # Start with all disabled, then they will be enabled later. + self.chkbox_static_ip.set_active(False) + self.chkbox_static_dns.set_active(False) + + def set_defaults(self, widget=None, event=None): + """ Put some default values into entries to help the user out. """ + ipAddress = self.txt_ip.get_text() # For easy typing :) + netmask = self.txt_netmask + gateway = self.txt_gateway + ip_parts = misc.IsValidIP(ipAddress) + if ip_parts: + if stringToNone(gateway.get_text()) is None: # Make sure the gateway box is blank + # Fill it in with a .1 at the end + gateway.set_text('.'.join(ip_parts[0:3]) + '.1') + + if stringToNone(netmask.get_text()) is None: # Make sure the netmask is blank + netmask.set_text('255.255.255.0') # Fill in the most common one + elif ipAddress != "": + error(None, "Invalid IP Address Entered.") + + def reset_static_checkboxes(self): + # Enable the right stuff + if stringToNone(self.txt_ip.get_text()) is not None: + self.chkbox_static_ip.set_active(True) + self.chkbox_static_dns.set_active(True) + self.chkbox_static_dns.set_sensitive(False) + else: + self.chkbox_static_ip.set_active(False) + self.chkbox_static_dns.set_active(False) + self.chkbox_static_dns.set_sensitive(True) + + if stringToNone(self.txt_dns_1.get_text()) is not None: + self.chkbox_static_dns.set_active(True) + else: + self.chkbox_static_dns.set_active(False) + + # This will properly disable unused boxes. + self.toggle_ip_checkbox() + self.toggle_dns_checkbox() + self.toggle_global_dns_checkbox() + + def toggle_ip_checkbox(self, widget=None): + """Toggle entries/checkboxes based on the static IP checkbox. """ + # Should disable the static IP text boxes, and also enable the DNS + # checkbox when disabled and disable when enabled. + if self.chkbox_static_ip.get_active(): + self.chkbox_static_dns.set_active(True) + self.chkbox_static_dns.set_sensitive(False) + else: + self.chkbox_static_dns.set_sensitive(True) + self.chkbox_static_dns.set_active(False) + + self.txt_ip.set_sensitive(self.chkbox_static_ip.get_active()) + self.txt_netmask.set_sensitive(self.chkbox_static_ip.get_active()) + self.txt_gateway.set_sensitive(self.chkbox_static_ip.get_active()) + + def toggle_dns_checkbox(self, widget=None): + """ Toggle entries and checkboxes based on the static dns checkbox. """ + # Should disable the static DNS boxes + if self.chkbox_static_ip.get_active(): + self.chkbox_static_dns.set_active(self.chkbox_static_ip. + get_active()) + self.chkbox_static_dns.set_sensitive(False) + + self.chkbox_global_dns.set_sensitive(self.chkbox_static_dns. + get_active()) + if self.chkbox_static_dns.get_active(): + # If global dns is on, don't use local dns + self.txt_dns_1.set_sensitive(not self.chkbox_global_dns.get_active()) + self.txt_dns_2.set_sensitive(not self.chkbox_global_dns.get_active()) + self.txt_dns_3.set_sensitive(not self.chkbox_global_dns.get_active()) + else: + self.txt_dns_1.set_sensitive(False) + self.txt_dns_2.set_sensitive(False) + self.txt_dns_3.set_sensitive(False) + self.chkbox_global_dns.set_active(False) + + def toggle_global_dns_checkbox(self, widget=None): + """ Set the DNS entries' sensitivity based on the Global checkbox. """ + if daemon.GetUseGlobalDNS() and self.chkbox_static_dns.get_active(): + self.txt_dns_1.set_sensitive(not self.chkbox_global_dns.get_active()) + self.txt_dns_2.set_sensitive(not self.chkbox_global_dns.get_active()) + self.txt_dns_3.set_sensitive(not self.chkbox_global_dns.get_active()) + + def destroy_called(self): + """ Clean up everything. + + This might look excessive, but it was the only way to prevent + memory leakage. + + """ + for obj in vars(self): + if hasattr(obj, "destroy"): + obj.destroy() + if hasattr(obj, "__del__"): + obj.__del__() + else: + del obj + super(AdvancedSettingsDialog, self).destroy() + self.destroy() + del self + + +class WiredSettingsDialog(AdvancedSettingsDialog): + def __init__(self, name): + """ Build the wired settings dialog. """ + AdvancedSettingsDialog.__init__(self) + self.des = self.connect("destroy", self.destroy_called) + self.prof_name = name + + def set_net_prop(self, option, value): + """ Sets the given option to the given value for this network. """ + wired.SetWiredProperty(option, value) + + def set_values(self): + """ Fill in the Gtk.Entry objects with the correct values. """ + self.txt_ip.set_text(self.format_entry("ip")) + self.txt_netmask.set_text(self.format_entry("netmask")) + self.txt_gateway.set_text(self.format_entry("gateway")) + + self.txt_dns_1.set_text(self.format_entry("dns1")) + self.txt_dns_2.set_text(self.format_entry("dns2")) + self.txt_dns_3.set_text(self.format_entry("dns3")) + self.reset_static_checkboxes() + + def format_entry(self, label): + """ Helper method to fetch and format wired properties. """ + return noneToBlankString(wired.GetWiredProperty(label)) + + def destroy_called(self): + """ Clean up everything. + + This might look excessive, but it was the only way to prevent + memory leakage. + + """ + self.disconnect(self.des) + for obj in vars(self): + if hasattr(obj, "destroy"): + obj.destroy() + if hasattr(obj, "__del__"): + obj.__del__() + else: + del obj + super(WiredSettingsDialog, self).destroy_called() + self.destroy() + del self + + +class WirelessSettingsDialog(AdvancedSettingsDialog): + def __init__(self, networkID): + """ Build the wireless settings dialog. """ + AdvancedSettingsDialog.__init__(self) + # Set up encryption stuff + self.networkID = networkID + self.combo_encryption = gtk.combo_box_new_text() + self.chkbox_encryption = gtk.CheckButton(language['use_encryption']) + self.chkbox_global_settings = gtk.CheckButton(language['global_settings']) + # Make the vbox to hold the encryption stuff. + self.vbox_encrypt_info = gtk.VBox(False, 0) + self.toggle_encryption() + self.chkbox_encryption.set_active(False) + self.combo_encryption.set_sensitive(False) + self.encrypt_types = misc.LoadEncryptionMethods() + + # Build the encryption menu + activeID = -1 # Set the menu to this item when we are done + for x, enc_type in enumerate(self.encrypt_types): + self.combo_encryption.append_text(enc_type[0]) + if enc_type[1] == wireless.GetWirelessProperty(networkID, + "enctype"): + activeID = x + self.combo_encryption.set_active(activeID) + if activeID != -1: + self.chkbox_encryption.set_active(True) + self.combo_encryption.set_sensitive(True) + self.vbox_encrypt_info.set_sensitive(True) + else: + self.combo_encryption.set_active(0) + self.change_encrypt_method() + self.vbox.pack_start(self.chkbox_global_settings, False, False) + self.vbox.pack_start(self.chkbox_encryption, False, False) + self.vbox.pack_start(self.combo_encryption) + self.vbox.pack_start(self.vbox_encrypt_info) + + # Connect signals. + self.chkbox_encryption.connect("toggled", self.toggle_encryption) + self.combo_encryption.connect("changed", self.change_encrypt_method) + self.des = self.connect("destroy", self.destroy_called) + + def destroy_called(self): + """ Clean up everything. + + This might look excessive, but it was the only way to prevent + memory leakage. + + """ + self.disconnect(self.des) + for obj in vars(self): + if hasattr(obj, "destroy"): + obj.destroy() + if hasattr(obj, "__del__"): + obj.__del__() + else: + del obj + super(WirelessSettingsDialog, self).destroy_called() + self.destroy() + del self + + def set_net_prop(self, option, value): + """ Sets the given option to the given value for this network. """ + wireless.SetWirelessProperty(self.networkID, option, value) + + def set_values(self): + """ Set the various network settings to the right values. """ + networkID = self.networkID + self.txt_ip.set_text(self.format_entry(networkID,"ip")) + self.txt_netmask.set_text(self.format_entry(networkID,"netmask")) + self.txt_gateway.set_text(self.format_entry(networkID,"gateway")) + + if wireless.GetWirelessProperty(networkID,'use_global_dns'): + self.chkbox_global_dns.set_active(True) + if wireless.GetWirelessProperty(networkID, "dns1") is not None: + self.txt_dns_1.set_text(self.format_entry(networkID, "dns1")) + if wireless.GetWirelessProperty(networkID, 'dns2') is not None: + self.txt_dns_2.set_text(self.format_entry(networkID, "dns2")) + if wireless.GetWirelessProperty(networkID, 'dns3') is not None: + self.txt_dns_3.set_text(self.format_entry(networkID, "dns3")) + + self.reset_static_checkboxes() + if wireless.GetWirelessProperty(networkID, 'encryption'): + self.chkbox_encryption.set_active(True) + else: + self.chkbox_encryption.set_active(False) + + if wireless.GetWirelessProperty(networkID, 'use_settings_globally'): + self.chkbox_global_settings.set_active(True) + else: + self.chkbox_global_settings.set_active(False) + + def format_entry(self, networkid, label): + """ Helper method for fetching/formatting wireless properties. """ + return noneToBlankString(wireless.GetWirelessProperty(networkid, label)) + + def toggle_encryption(self, widget=None): + """ Toggle the encryption combobox based on the encryption checkbox. """ + active = self.chkbox_encryption.get_active() + self.vbox_encrypt_info.set_sensitive(active) + self.combo_encryption.set_sensitive(active) + + def change_encrypt_method(self, widget=None): + """ Load all the entries for a given encryption method. """ + for z in self.vbox_encrypt_info: + z.destroy() # Remove stuff in there already + ID = self.combo_encryption.get_active() + methods = misc.LoadEncryptionMethods() + self.encryption_info = {} + + # If nothing is selected, select the first entry. + if ID == -1: + self.combo_encryption.set_active(0) + ID = 0 + + opts = methods[ID][2] + for x in opts: + box = None + if language.has_key(opts[x][0]): + box = LabelEntry(language[opts[x][0].lower().replace(' ','_')]) + else: + box = LabelEntry(opts[x][0].replace('_',' ')) + box.set_auto_hidden(True) + self.vbox_encrypt_info.pack_start(box) + #add the data to any array, so that the information + #can be easily accessed by giving the name of the wanted + #data + self.encryption_info[opts[x][1]] = box.entry + + box.entry.set_text(noneToBlankString( + wireless.GetWirelessProperty(self.networkID, opts[x][1]))) + self.vbox_encrypt_info.show_all() + + +class NetworkEntry(gtk.HBox): + def __init__(self, dbus_ifaces): + """ Base network entry class. + + Provides gtk objects used by both the WiredNetworkEntry and + WirelessNetworkEntry classes. + + """ + global daemon, wired, wireless, config, vpn_session + daemon = dbus_ifaces["daemon"] + wired = dbus_ifaces["wired"] + wireless = dbus_ifaces["wireless"] + vpn_session = dbus_ifaces["vpn_session"] + config = dbus_ifaces["config"] + gtk.HBox.__init__(self, False, 2) + self.expander = gtk.Expander() + self.image = gtk.Image() + self.pack_start(self.image, False, False) + + # Set up the Connect button + self.connect_button = gtk.Button(stock=gtk.STOCK_CONNECT) + self.connect_hbox = gtk.HBox(False, 2) + self.connect_hbox.pack_start(self.connect_button, False, False) + self.connect_hbox.show() + + # Set up the Disconnect button + self.disconnect_button = gtk.Button(stock=gtk.STOCK_DISCONNECT) + self.connect_hbox.pack_start(self.disconnect_button, False, False) + + # Set up the VBox that goes in the gtk.Expander + self.expander_vbox = gtk.VBox(False, 1) + self.expander_vbox.show() + self.expander_vbox.pack_start(self.expander) + self.expander_vbox.pack_start(self.connect_hbox, False, False) + self.pack_end(self.expander_vbox) + + # Set up the advanced settings button + self.advanced_button = gtk.Button() + self.advanced_image = gtk.Image() + self.advanced_image.set_from_stock(gtk.STOCK_EDIT, 4) + self.advanced_image.set_padding(4, 0) + self.advanced_button.set_alignment(.5, .5) + self.advanced_button.set_label(language['advanced_settings']) + self.advanced_button.set_image(self.advanced_image) + + # Set up the script settings button + self.script_button = gtk.Button() + self.script_image = gtk.Image() + self.script_image.set_from_icon_name('execute', 4) + self.script_image.set_padding(4, 0) + self.script_button.set_alignment(.5, .5) + self.script_button.set_image(self.script_image) + self.script_button.set_label(language['scripts']) + + self.settings_hbox = gtk.HBox(False, 3) + self.settings_hbox.set_border_width(5) + self.settings_hbox.pack_start(self.script_button, False, False) + self.settings_hbox.pack_start(self.advanced_button, False, False) + + self.vbox_top = gtk.VBox(False, 0) + self.vbox_top.pack_end(self.settings_hbox, False, False) + + aligner = gtk.Alignment(xscale=1.0) + aligner.add(self.vbox_top) + aligner.set_padding(0, 0, 15, 0) + 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): + try: obj.destroy() + except: pass + if hasattr(obj, '__del__'): + obj.__del__() + else: + del obj + for obj in vars(super(NetworkEntry, self)): + try: obj.destroy() + except: pass + if hasattr(obj, '__del__'): + obj.__del__() + else: + del obj + super(NetworkEntry, self).destroy() + self.destroy() + + +class WiredNetworkEntry(NetworkEntry): + def __init__(self, dbus_ifaces): + """ Load the wired network entry. """ + NetworkEntry.__init__(self, dbus_ifaces) + # Center the picture and pad it a bit + self.image.set_alignment(.5, 0) + self.image.set_size_request(60, -1) + self.image.set_from_icon_name("network-wired", 6) + self.image.show() + self.expander.show() + self.connect_button.show() + + self.expander.set_label(language['wired_network']) + #self.reset_static_checkboxes() + self.is_full_gui = True + + self.button_add = gtk.Button(stock=gtk.STOCK_ADD) + self.button_delete = gtk.Button(stock=gtk.STOCK_DELETE) + self.profile_help = gtk.Label(language['wired_network_instructions']) + self.chkbox_default_profile = gtk.CheckButton(language['default_wired']) + + # Build the profile list. + self.combo_profile_names = gtk.combo_box_entry_new_text() + self.profile_list = config.GetWiredProfileList() + if self.profile_list: + for x in self.profile_list: + self.combo_profile_names.append_text(x) + + # Format the profile help label. + self.profile_help.set_justify(gtk.JUSTIFY_LEFT) + self.profile_help.set_line_wrap(True) + + # Pack the various VBox objects. + self.hbox_temp = gtk.HBox(False, 0) + self.hbox_def = gtk.HBox(False, 0) + self.vbox_top.pack_start(self.profile_help, True, True) + self.vbox_top.pack_start(self.hbox_def) + self.vbox_top.pack_start(self.hbox_temp) + self.hbox_temp.pack_start(self.combo_profile_names, True, True) + self.hbox_temp.pack_start(self.button_add, False, False) + self.hbox_temp.pack_start(self.button_delete, False, False) + self.hbox_def.pack_start(self.chkbox_default_profile, False, False) + + # Connect events + self.button_add.connect("clicked", self.add_profile) + self.button_delete.connect("clicked", self.remove_profile) + self.chkbox_default_profile.connect("toggled", + self.toggle_default_profile) + self.combo_profile_names.connect("changed", self.change_profile) + self.script_button.connect("button-press-event", self.edit_scripts) + + # Toggle the default profile checkbox to the correct state. + if stringToBoolean(wired.GetWiredProperty("default")): + self.chkbox_default_profile.set_active(True) + else: + self.chkbox_default_profile.set_active(False) + + # Show everything, but hide the profile help label. + self.show_all() + self.profile_help.hide() + self.advanced_dialog = WiredSettingsDialog(self.combo_profile_names.get_active_text()) + + # Display the default profile if it exists. + if self.profile_list is not None: + prof = config.GetDefaultWiredNetwork() + if prof != None: # Make sure the default profile gets displayed. + i = 0 + while self.combo_profile_names.get_active_text() != prof: + self.combo_profile_names.set_active(i) + i += 1 + else: + self.combo_profile_names.set_active(0) + print "wired profiles found" + self.expander.set_expanded(False) + else: + print "no wired profiles found" + if not wired.GetAlwaysShowWiredInterface(): + self.expander.set_expanded(True) + self.profile_help.show() + self.check_enable() + self.update_connect_button() + 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. + + """ + self.disconnect(self.wireddis) + self.advanced_dialog.destroy_called() + del self.advanced_dialog + for obj in vars(self): + if hasattr(obj, "destroy"): + obj.destroy() + if hasattr(obj, '__del__'): + obj.__del__() + else: + del obj + super(WiredNetworkEntry, self).destroy_called() + self.destroy() + del self + + def edit_scripts(self, widget=None, event=None): + """ Launch the script editting dialog. """ + profile = self.combo_profile_names.get_active_text() + try: + sudo_prog = misc.choose_sudo_prog() + msg = "You must enter your password to configure scripts" + if sudo_prog.endswith("gksu"): + msg_flag = "-m" + else: + msg_flag = "--caption" + misc.LaunchAndWait([sudo_prog, msg_flag, msg, "./configscript.py", + profile, "wired"]) + except misc.WicdError: + error("Could not find a graphical sudo program." + \ + " Script editor could no be launched.") + + def check_enable(self): + """ Disable objects if the profile list is empty. """ + profile_list = config.GetWiredProfileList() + if profile_list == None: + self.button_delete.set_sensitive(False) + self.connect_button.set_sensitive(False) + self.advanced_button.set_sensitive(False) + self.script_button.set_sensitive(False) + + def update_connect_button(self, apbssid=None): + """ Update the connection/disconnect button for this entry. """ + state, x = daemon.GetConnectionStatus() + if state == misc.WIRED: + self.disconnect_button.show() + self.connect_button.hide() + else: + self.disconnect_button.hide() + self.connect_button.show() + + def add_profile(self, widget): + """ Add a profile to the profile list. """ + print "adding profile" + profile_name = self.combo_profile_names.get_active_text() + profile_list = config.GetWiredProfileList() + if profile_list: + if profile_name in profile_list: + return False + if profile_name != "": + self.profile_help.hide() + config.CreateWiredNetworkProfile(profile_name) + self.combo_profile_names.prepend_text(profile_name) + self.combo_profile_names.set_active(0) + self.advanced_dialog.prof_name = profile_name + if self.is_full_gui: + self.button_delete.set_sensitive(True) + self.connect_button.set_sensitive(True) + self.advanced_button.set_sensitive(True) + self.script_button.set_sensitive(True) + + def remove_profile(self, widget): + """ Remove a profile from the profile list. """ + print "removing profile" + profile_name = self.combo_profile_names.get_active_text() + config.DeleteWiredNetworkProfile(profile_name) + self.combo_profile_names.remove_text(self.combo_profile_names. + get_active()) + self.combo_profile_names.set_active(0) + self.advanced_dialog.prof_name = self.combo_profile_names.get_active_text() + if not config.GetWiredProfileList(): + self.profile_help.show() + entry = self.combo_profile_names.child + entry.set_text("") + if self.is_full_gui: + self.button_delete.set_sensitive(False) + self.advanced_button.set_sensitive(False) + self.script_button.set_sensitive(False) + self.connect_button.set_sensitive(False) + else: + self.profile_help.hide() + + def toggle_default_profile(self, widget): + """ Change the default profile. """ + if self.chkbox_default_profile.get_active(): + # Make sure there is only one default profile at a time + config.UnsetWiredDefault() + wired.SetWiredProperty("default", + self.chkbox_default_profile.get_active()) + config.SaveWiredNetworkProfile(self.combo_profile_names.get_active_text()) + + def change_profile(self, widget): + """ Called when a new profile is chosen from the list. """ + # Make sure the name doesn't change everytime someone types something + if self.combo_profile_names.get_active() > -1: + if not self.is_full_gui: + return + + profile_name = self.combo_profile_names.get_active_text() + config.ReadWiredNetworkProfile(profile_name) + + self.advanced_dialog.txt_ip.set_text(self.format_entry("ip")) + self.advanced_dialog.txt_netmask.set_text(self.format_entry("netmask")) + self.advanced_dialog.txt_gateway.set_text(self.format_entry("gateway")) + self.advanced_dialog.txt_dns_1.set_text(self.format_entry("dns1")) + self.advanced_dialog.txt_dns_2.set_text(self.format_entry("dns2")) + self.advanced_dialog.txt_dns_3.set_text(self.format_entry("dns3")) + self.advanced_dialog.prof_name = profile_name + + is_default = wired.GetWiredProperty("default") + self.chkbox_default_profile.set_active(stringToBoolean(is_default)) + + def format_entry(self, label): + """ Help method for fetching/formatting wired properties. """ + return noneToBlankString(wired.GetWiredProperty(label)) + + +class WirelessNetworkEntry(NetworkEntry): + def __init__(self, networkID, dbus_ifaces): + """ Build the wireless network entry. """ + NetworkEntry.__init__(self, dbus_ifaces) + + self.networkID = networkID + self.image.set_padding(0, 0) + self.image.set_alignment(.5, 0) + self.image.set_size_request(60, -1) + self.image.set_from_icon_name("network-wired", 6) + self.essid = wireless.GetWirelessProperty(networkID, "essid") + print "ESSID : " + self.essid + # Make the combo box. + self.lbl_strength = GreyLabel() + self.lbl_encryption = GreyLabel() + self.lbl_mac = GreyLabel() + self.lbl_channel = GreyLabel() + self.lbl_mode = GreyLabel() + self.hbox_status = gtk.HBox(False, 5) + self.chkbox_autoconnect = gtk.CheckButton(language['automatic_connect']) + + # Set the values of the network info labels. + self.set_signal_strength(wireless.GetWirelessProperty(networkID, + 'quality'), + wireless.GetWirelessProperty(networkID, + 'strength')) + self.set_mac_address(wireless.GetWirelessProperty(networkID, 'bssid')) + self.set_mode(wireless.GetWirelessProperty(networkID, 'mode')) + self.set_channel(wireless.GetWirelessProperty(networkID, 'channel')) + self.set_encryption(wireless.GetWirelessProperty(networkID, + 'encryption'), + wireless.GetWirelessProperty(networkID, + 'encryption_method')) + + # The the expander label. + self.expander.set_use_markup(True) + + self.expander.set_label(self._escape(self.essid) + " " + + self.lbl_strength.get_label() + " " + + self.lbl_encryption.get_label() + " " + + self.lbl_mac.get_label()) + + # Pack the network status HBox. + self.hbox_status.pack_start(self.lbl_strength, True, True) + self.hbox_status.pack_start(self.lbl_encryption, True, True) + self.hbox_status.pack_start(self.lbl_mac, True, True) + self.hbox_status.pack_start(self.lbl_mode, True, True) + self.hbox_status.pack_start(self.lbl_channel, True, True) + + # Add the wireless network specific parts to the NetworkEntry + # VBox objects. + self.vbox_top.pack_start(self.chkbox_autoconnect, False, False) + self.vbox_top.pack_start(self.hbox_status, True, True) + + if stringToBoolean(self.format_entry(networkID, "automatic")): + self.chkbox_autoconnect.set_active(True) + else: + self.chkbox_autoconnect.set_active(False) + + # Connect signals. + self.chkbox_autoconnect.connect("toggled", self.update_autoconnect) + self.script_button.connect("button-press-event", self.edit_scripts) + + # Show everything + self.show_all() + self.advanced_dialog = WirelessSettingsDialog(networkID) + self.update_connect_button(wireless.GetApBssid()) + self.wifides = self.connect("destroy", self.destroy_called) + + def _escape(self, val): + return val.replace("&", "&").replace("<", "<").\ + replace(">",">").replace("'", "'").replace('"', """) + + def destroy_called(self, *args): + """ Clean up everything. + + This might look excessive, but it was the only way to prevent + memory leakage. + + """ + self.disconnect(self.wifides) + self.advanced_dialog.destroy_called() + del self.advanced_dialog + for obj in vars(self): + if hasattr(obj, "destroy"): + obj.destroy() + + if hasattr(obj, '__del__'): + obj.__del__() + else: + del obj + super(WirelessNetworkEntry, self).destroy_called() + self.destroy() + del self + + def set_signal_strength(self, strength, dbm_strength): + """ Set the signal strength displayed in the WirelessNetworkEntry. """ + if strength is not None: + strength = int(strength) + else: + strength = -1 + if dbm_strength is not None: + dbm_strength = int(dbm_strength) + else: + dbm_strength = -100 + display_type = daemon.GetSignalDisplayType() + if daemon.GetWPADriver() == 'ralink legacy' or display_type == 1: + # Use the -xx dBm signal strength to display a signal icon + # I'm not sure how accurately the dBm strength is being + # "converted" to strength bars, so suggestions from people + # for a better way would be welcome. + if dbm_strength >= -60: + signal_img = 'signal-100.png' + elif dbm_strength >= -70: + signal_img = 'signal-75.png' + elif dbm_strength >= -80: + signal_img = 'signal-50.png' + else: + signal_img = 'signal-25.png' + ending = "dBm" + disp_strength = str(dbm_strength) + else: + # Uses normal link quality, should be fine in most cases + if strength > 75: + signal_img = 'signal-100.png' + elif strength > 50: + signal_img = 'signal-75.png' + elif strength > 25: + signal_img = 'signal-50.png' + else: + signal_img = 'signal-25.png' + ending = "%" + disp_strength = str(strength) + + self.image.set_from_file(wpath.images + signal_img) + self.lbl_strength.set_label(disp_strength + ending) + + def update_connect_button(self, apbssid): + """ Update the connection/disconnect button for this entry. """ + state, x = daemon.GetConnectionStatus() + if state == misc.WIRELESS and apbssid == \ + wireless.GetWirelessProperty(self.networkID, "bssid"): + self.disconnect_button.show() + self.connect_button.hide() + else: + self.disconnect_button.hide() + self.connect_button.show() + + def set_mac_address(self, address): + """ Set the MAC address for the WirelessNetworkEntry. """ + self.lbl_mac.set_label(str(address)) + + def set_encryption(self, on, ttype): + """ Set the encryption value for the WirelessNetworkEntry. """ + if on and ttype: + self.lbl_encryption.set_label(str(ttype)) + if on and not ttype: + self.lbl_encryption.set_label(language['secured']) + if not on: + self.lbl_encryption.set_label(language['unsecured']) + + def set_channel(self, channel): + """ Set the channel value for the WirelessNetworkEntry. """ + self.lbl_channel.set_label(language['channel'] + ' ' + str(channel)) + + def set_mode(self, mode): + """ Set the mode value for the WirelessNetworkEntry. """ + self.lbl_mode.set_label(str(mode)) + + def format_entry(self, networkid, label): + """ Helper method for fetching/formatting wireless properties. """ + return noneToBlankString(wireless.GetWirelessProperty(networkid, label)) + + def edit_scripts(self, widget=None, event=None): + """ Launch the script editting dialog. """ + try: + sudo_prog = misc.choose_sudo_prog() + msg = "You must enter your password to configure scripts" + if sudo_prog.endswith("gksu"): + msg_flag = "-m" + else: + msg_flag = "--caption" + misc.LaunchAndWait([sudo_prog, msg_flag, msg, "./configscript.py", + str(self.networkID), "wireless"]) + except IOError: + error("Could not find a graphical sudo program." + \ + " Script editor could no be launched.") + + def update_autoconnect(self, widget=None): + """ Called when the autoconnect checkbox is toggled. """ + wireless.SetWirelessProperty(self.networkID, "automatic", + noneToString(self.chkbox_autoconnect. + get_active())) + config.SaveWirelessNetworkProperty(self.networkID, "automatic") diff --git a/networking.py b/networking.py index 0c2ef97..67b71b6 100644 --- a/networking.py +++ b/networking.py @@ -676,8 +676,15 @@ class WirelessConnectThread(ConnectThread): """ def _sanitize(key): """ Escapes characters wpa_supplicant doesn't handle properly. """ - return key.replace("$", "\$").replace("`", "\`").replace("\"", - "\\\"") + new_key = [] + blacklist = ["$", "`", "\""] + for c in key: + if c in blacklist: + new_key.append("\\" + c) + else: + new_key.append(c) + return ''.join(new_key) + # Check to see if we need to generate a PSK (only for non-ralink # cards). if self.network.get('key'): diff --git a/wicd.py b/wicd.py index a2b51b3..1220cf3 100755 --- a/wicd.py +++ b/wicd.py @@ -42,7 +42,6 @@ import gobject import dbus import dbus.service import getopt -import time import os # Wicd specific imports @@ -69,39 +68,14 @@ misc.RenameProcess("wicd") if __name__ == '__main__': wpath.chdir(__file__) -bus = dbus.SystemBus() - -# Connect to the daemon -try: - print 'Attempting to connect tray to daemon...' - proxy_obj = bus.get_object('org.wicd.daemon', '/org/wicd/daemon') - print 'Success.' -except Exception: - print 'Can\'t connect to the daemon, trying to start it automatically...' - misc.PromptToStartDaemon() - time.sleep(1) - try: - print 'Attempting to connect tray to daemon...' - proxy_obj = bus.get_object('org.wicd.daemon', '/org/wicd/daemon') - print 'Success.' - except: - print 'Failed to start daemon. Aborting.' - sys.exit(1) - -daemon = dbus.Interface(proxy_obj, 'org.wicd.daemon') -wireless = dbus.Interface(proxy_obj, 'org.wicd.daemon.wireless') -wired = dbus.Interface(proxy_obj, 'org.wicd.daemon.wired') -config = dbus.Interface(proxy_obj, 'org.wicd.daemon.config') - -_ = misc.get_gettext() -language = {} -language['connected_to_wireless'] = _('Connected to $A at $B (IP: $C)') -language['connected_to_wired'] = _('Connected to wired network (IP: $A)') -language['not_connected'] = _('Not connected') -language['killswitch_enabled'] = _('Wireless Kill Switch Enabled') -language['connecting'] = _('Connecting') -language['wired'] = _('Wired Network') +bus = None +daemon = None +wireless = None +wired = None +wired = None +config = None +language = misc.get_language_list_tray() class TrayIcon: """ Base Tray Icon class. @@ -289,7 +263,7 @@ class TrayIcon: A tuple containing three elements: 1) a boolean specifying if the network is active. 2) an int specifying the maximum gain the network has had. - 3) an int specifying the last record number of bytes sent. + 3) an int specifying the last recorded number of bytes sent. """ active = False @@ -564,6 +538,31 @@ Arguments: \t-h\t--help\t\tPrint this help information. \t-a\t--no-animate\tRun the tray without network traffic tray animations. """ + +def connect_to_dbus(): + global bus, daemon, wireless, wired, config + # Connect to the daemon + bus = dbus.SystemBus() + try: + print 'Attempting to connect tray to daemon...' + proxy_obj = bus.get_object('org.wicd.daemon', '/org/wicd/daemon') + print 'Success.' + except dbus.DBusException: + print "Can't connect to the daemon, trying to start it automatically..." + misc.PromptToStartDaemon() + try: + print 'Attempting to connect tray to daemon...' + proxy_obj = bus.get_object('org.wicd.daemon', '/org/wicd/daemon') + print 'Success.' + except dbus.DBusException: + gui.error("Could not connect to wicd's D-Bus interface. " + + "Make sure the daemon is started.") + sys.exit(1) + + daemon = dbus.Interface(proxy_obj, 'org.wicd.daemon') + wireless = dbus.Interface(proxy_obj, 'org.wicd.daemon.wireless') + wired = dbus.Interface(proxy_obj, 'org.wicd.daemon.wired') + config = dbus.Interface(proxy_obj, 'org.wicd.daemon.config') def main(argv): """ The main frontend program. @@ -572,12 +571,11 @@ def main(argv): argv -- The arguments passed to the script. """ - print 'Loading...' use_tray = True animate = True try: - opts, args = getopt.getopt(sys.argv[1:], 'nha', ['help', 'no-tray', + opts, args = getopt.getopt(sys.argv[1:], 'nha', ['help', 'no-tray', 'no-animate']) except getopt.GetoptError: # Print help information and exit @@ -592,6 +590,9 @@ def main(argv): use_tray = False elif opt in ('-a', '--no-animate'): animate = False + + print 'Loading...' + connect_to_dbus() if not use_tray: os.spawnlp(os.P_NOWAIT, wpath.bin + 'gui.py') @@ -612,7 +613,6 @@ def main(argv): bus.add_signal_receiver(tray_icon.icon_info.update_tray_icon, 'StatusChanged', 'org.wicd.daemon') print 'Done.' - mainloop = gobject.MainLoop() mainloop.run()