diff --git a/daemon.py b/daemon.py index e872546..3c2c72d 100644 --- a/daemon.py +++ b/daemon.py @@ -287,15 +287,49 @@ class ConnectionWizard(dbus.service.Object): return int(self.debug_mode) #end function GetDebugMode + @dbus.service.method('org.wicd.daemon') + def GetSignalDisplayType(self): + ''' returns the signal display type + + Returns either 0 or 1. + 0 for signal strength as a percentage + 1 for signal strength measured in dBm + + ''' + return int(self.signal_display_type) + # end function GetSignalDisplayType + + @dbus.service.method('org.wicd.daemon') + def SetSignalDisplayType(self, value): + ''' Sets the signal display type and writes it the wicd config file ''' + config = ConfigParser.ConfigParser() + config.read(self.app_conf) + config.set("Settings","signal_display_type",value) + configfile = open(self.app_conf,"w") + config.write(configfile) + self.signal_display_type = value + # end function SetSignalDisplayType + + @dbus.service.method('org.wicd.daemon') + def FormatSignalForPrinting(self, signal): + ''' Returns the suffix to display after the signal strength number ''' + if self.GetSignalDisplayType() == 1: + return ("-" + signal + " dBm") + else: + return (signal + "%") + # End function GetSignalSuffix + + @dbus.service.method('org.wicd.daemon') def AutoConnect(self,fresh): '''first tries to autoconnect to a wired network, if that fails it tries a wireless connection''' if fresh: self.Scan() + #self.AutoConnectScan() # Also scans for hidden networks if self.CheckPluggedIn() == True: if self.GetWiredAutoConnectMethod() == 2: - self.SetNeedWiredProfileChooser(True) - print 'alerting tray to display wired autoconnect wizard' + #self.SetNeedWiredProfileChooser(True) + self.LaunchChooser() else: defaultNetwork = self.GetDefaultWiredNetwork() if defaultNetwork != None: @@ -358,13 +392,15 @@ class ConnectionWizard(dbus.service.Object): def GetGlobalDNSAddresses(self): '''returns the global dns addresses''' print 'returning global dns addresses to client' - return (misc.noneToString(self.dns1),misc.noneToString(self.dns2),misc.noneToString(self.dns3)) + return (misc.noneToString(self.dns1), misc.noneToString(self.dns2), + misc.noneToString(self.dns3)) #end function GetWirelessInterface @dbus.service.method('org.wicd.daemon') def CheckIfConnecting(self): '''returns if a network connection is being made''' - if self.CheckIfWiredConnecting() == False and self.CheckIfWirelessConnecting() == False: + if self.CheckIfWiredConnecting() == False and \ + self.CheckIfWirelessConnecting() == False: return False else: return True @@ -380,6 +416,25 @@ class ConnectionWizard(dbus.service.Object): return self.need_profile_chooser #end function GetNeedWiredProfileChooser + @dbus.service.signal(dbus_interface='org.wicd.daemon', signature='') + def LaunchChooser(self): + print 'calling wired profile chooser' + + @dbus.service.signal(dbus_interface='org.wicd.daemon',signature='') + def CloseGui(self): + ''' Sends a dbus signal announcing the GUI is closing ''' + print 'sending close signal' + @dbus.service.method('org.wicd.daemon') + def close_gui(self): + ''' Calls the CloseGui method + + intermediary method to send a signal announcing gui.py is being + closed. It's needed because a method can't be both a + service.method and service.signal + + ''' + self.CloseGui() + ########## WIRELESS FUNCTIONS ################################# @@ -400,6 +455,39 @@ class ConnectionWizard(dbus.service.Object): for i, network in enumerate(scan): self.ReadWirelessNetworkProfile(i) print + + # This is unfinished so not on dbus yet + def AutoConnectScan(self): + ''' Scan for networks and for known hidden networks + + Scans for wireless networks and also for hidden networks defined in + wireless-settings.conf + + + ''' + hidden_network_list = self.GetHiddenNetworkList() + master_scan = self.Scan() + + if hidden_network_list is None: + return + else: + # If we find hidden networks, run a scan for each one found, + # parsing out the hidden network info if it's in the scan + # results, and appending it to a master scan list + for hidden_network in hidden_network_list: + print 'Scanning for hidden network:', hidden_network + self.SetHiddenESSID(hidden_network['essid']) + temp_scan = self.Scan() + for i, network in enumerate(temp_scan): + print 'Searching scan results for ' + hidden_network['essid'] + # Make sure both the essid and bssid match + if temp_scan[i]['essid'] == hidden_network['essid'] and \ + temp_scan[i]['bssid'] == hidden_network['bssid']: + print 'Hidden network found, adding to master list' + master_scan[len(master_scan)] = temp_scan[i] + # Break once the network is found + break + self.LastScan = master_scan #end function FreshScan @dbus.service.method('org.wicd.daemon.wireless') @@ -743,6 +831,7 @@ class ConnectionWizard(dbus.service.Object): @dbus.service.method('org.wicd.daemon.config') def CreateWiredNetworkProfile(self,profilename): + ''' Creates a wired network profile ''' #should include: profilename,ip,netmask,gateway,dns1,dns2,dns3 profilename = profilename.encode('utf-8') print "creating profile for " + profilename @@ -784,6 +873,7 @@ class ConnectionWizard(dbus.service.Object): @dbus.service.method('org.wicd.daemon.config') def GetDefaultWiredNetwork(self): + ''' Returns the current default wired network ''' config = ConfigParser.ConfigParser() config.read(self.wired_conf) profileList = config.sections() @@ -795,6 +885,7 @@ class ConnectionWizard(dbus.service.Object): @dbus.service.method('org.wicd.daemon.config') def DeleteWiredNetworkProfile(self,profilename): + ''' Deletes a wired network profile ''' profilename = profilename.encode('utf-8') print "deleting profile for " + str(profilename) config = ConfigParser.ConfigParser() @@ -809,6 +900,7 @@ class ConnectionWizard(dbus.service.Object): @dbus.service.method('org.wicd.daemon.config') def SaveWiredNetworkProfile(self,profilename): + ''' Writes a wired network profile to disk ''' #should include: profilename,ip,netmask,gateway,dns1,dns2 profilename = profilename.encode('utf-8') print "setting profile for " + str(profilename) @@ -825,6 +917,7 @@ class ConnectionWizard(dbus.service.Object): @dbus.service.method('org.wicd.daemon.config') def ReadWiredNetworkProfile(self,profilename): + ''' Reads a wired network profile in as the currently active profile ''' profile = {} profilename = profilename.encode('utf-8') config = ConfigParser.ConfigParser() @@ -841,6 +934,7 @@ class ConnectionWizard(dbus.service.Object): @dbus.service.method('org.wicd.daemon.config') def GetWiredProfileList(self): + ''' Returns a list of all wired profiles in wired-settings.conf ''' config = ConfigParser.ConfigParser() config.read(self.wired_conf) print config.sections() @@ -852,6 +946,7 @@ class ConnectionWizard(dbus.service.Object): @dbus.service.method('org.wicd.daemon.config') def SaveWirelessNetworkProfile(self,id): + ''' Writes a wireless profile to disk ''' print "setting network profile" config = ConfigParser.ConfigParser() config.read(self.wireless_conf) @@ -867,6 +962,7 @@ class ConnectionWizard(dbus.service.Object): @dbus.service.method('org.wicd.daemon.config') def SaveWirelessNetworkProperty(self,id,option): + ''' Writes a particular wireless property to disk ''' print "setting network option " + str(option) + " to " + str(self.LastScan[id][option]) config = ConfigParser.ConfigParser() config.read(self.wireless_conf) @@ -877,6 +973,7 @@ class ConnectionWizard(dbus.service.Object): @dbus.service.method('org.wicd.daemon.config') def ReadWirelessNetworkProfile(self,id): + ''' Reads in wireless profile as the active network ''' config = ConfigParser.ConfigParser() config.read(self.wireless_conf) print self.LastScan[id]["bssid"] @@ -887,11 +984,13 @@ class ConnectionWizard(dbus.service.Object): else: self.LastScan[id]["beforescript"]= None if config.has_option(self.LastScan[id]["bssid"],"afterscript"): - self.LastScan[id]["afterscript"]=misc.Noneify(config.get(self.LastScan[id]["bssid"],"afterscript")) + self.LastScan[id]["afterscript"] = misc.Noneify(config.get(self.LastScan[id]["bssid"], + "afterscript")) else: self.LastScan[id]["afterscript"] = None if config.has_option(self.LastScan[id]["bssid"],"disconnectscript"): - self.LastScan[id]["disconnectscript"]=misc.Noneify(config.get(self.LastScan[id]["bssid"],"disconnectscript")) + self.LastScan[id]["disconnectscript"] = misc.Noneify(config.get(self.LastScan[id]["bssid"], + "disconnectscript")) else: self.LastScan[id]["disconnectscript"] = None @@ -933,22 +1032,27 @@ class ConnectionWizard(dbus.service.Object): if config.has_section("Settings"): if config.has_option("Settings","wireless_interface"): print "found wireless interface in configuration...", - self.SetWirelessInterface(config.get("Settings","wireless_interface")) + self.SetWirelessInterface(config.get("Settings", + "wireless_interface")) if config.has_option("Settings","wired_interface"): print "found wired interface in configuration...", - self.SetWiredInterface(config.get("Settings","wired_interface")) + self.SetWiredInterface(config.get("Settings", + "wired_interface")) if config.has_option("Settings","wpa_driver"): print "found wpa driver in configuration...", self.SetWPADriver(config.get("Settings","wpa_driver")) if config.has_option("Settings","always_show_wired_interface"): - self.always_show_wired_interface = config.get("Settings","always_show_wired_interface") + self.always_show_wired_interface = config.get("Settings", + "always_show_wired_interface") else: - config.set("Settings","always_show_wired_interface","False") + config.set("Settings", "always_show_wired_interface", + "False") self.always_show_wired_interface = 0 if config.has_option("Settings","use_global_dns"): print config.get("Settings","use_global_dns") - self.SetUseGlobalDNS(int(config.get("Settings","use_global_dns"))) - dns1, dns2, dns3 = ('None','None','None') #so we can access them later + self.SetUseGlobalDNS(int(config.get("Settings", + "use_global_dns"))) + dns1, dns2, dns3 = ('None','None','None') # So we can access them later if config.has_option("Settings","global_dns_1"): dns1 = config.get('Settings','global_dns_1') if config.has_option("Settings","global_dns_2"): @@ -960,7 +1064,8 @@ class ConnectionWizard(dbus.service.Object): self.SetUseGlobalDNS(False) self.SetGlobalDNS(False,False,False) if config.has_option("Settings","auto_reconnect"): - self.auto_reconnect = config.get("Settings","auto_reconnect") + self.auto_reconnect = config.get("Settings", + "auto_reconnect") else: config.set("Settings","auto_reconnect","0") self.auto_reconnect = False @@ -970,10 +1075,17 @@ class ConnectionWizard(dbus.service.Object): self.debug_mode = 0 config.set("Settings","debug_mode","0") if config.has_option("Settings","wired_connect_mode"): - self.SetWiredAutoConnectMethod(config.get("Settings","wired_connect_mode")) + self.SetWiredAutoConnectMethod(config.get("Settings", + "wired_connect_mode")) else: config.set("Settings","wired_connect_mode","1") - self.SetWiredAutoConnectMethod(config.get("Settings","wired_connect_mode")) + self.SetWiredAutoConnectMethod(config.get("Settings", + "wired_connect_mode")) + if config.has_option("Settings", "signal_display_type"): + self.signal_display_type = config.get("Settings", "signal_display_type") + else: + config.set("Settings", "signal_display_type", "0") + self.SetSignalDisplayType(0) else: print "configuration file exists, no settings found, adding defaults..." configfile = open(self.app_conf,"w") @@ -989,8 +1101,15 @@ class ConnectionWizard(dbus.service.Object): config.set("Settings","dns1","None") config.set("Settings","dns2","None") config.set("Settings","dns3","None") + config.set("Settings", "signal_display_type", "0") self.SetUseGlobalDNS(False) - self.SetGlobalDNS(config.get('Settings','dns1'),config.get('Settings','dns2'),config.get('Settings','dns3')) + self.SetGlobalDNS(config.get('Settings', 'dns1'), + config.get('Settings', 'dns2'), + config.get('Settings', 'dns3')) + iface = self.DetectWirelessInterface() + if iface: + self.SetWirelessInterface(iface) + else: self.SetWirelessInterface("wlan0") self.SetWiredInterface("eth0") self.SetWPADriver("wext") @@ -998,6 +1117,7 @@ class ConnectionWizard(dbus.service.Object): self.SetAutoReconnect(1) self.SetDebugMode(0) self.SetWiredAutoConnectMethod(1) + self.SetSignalDisplayType(0) config.write(configfile) else: @@ -1012,24 +1132,29 @@ class ConnectionWizard(dbus.service.Object): config.set("Settings","auto_reconnect","0") config.set("Settings","debug_mode","0") config.set("Settings","wired_connect_mode","1") + config.set("Settings", "signal_display_type", "0") config.set("Settings","dns1","None") config.set("Settings","dns2","None") config.set("Settings","dns3","None") iface = self.DetectWirelessInterface() - if iface: + if iface is not None: config.set("Settings","wireless_interface",iface) else: print "couldn't detect a wireless interface, using wlan0..." config.set("Settings","wireless_interface","wlan0") config.set("Settings","wpa_driver","wext") config.write(open(self.app_conf,"w")) - self.SetWirelessInterface(config.get("Settings","wireless_interface")) - self.SetWiredInterface(config.get("Settings","wired_interface")) - self.SetWPADriver(config.get("Settings","wpa_driver")) + self.SetWirelessInterface(config.get("Settings", + "wireless_interface")) + self.SetWiredInterface(config.get("Settings", + "wired_interface")) + self.SetWPADriver(config.get("Settings", + "wpa_driver")) self.SetAlwaysShowWiredInterface(0) self.SetAutoReconnect(1) self.SetDebugMode(0) self.SetWiredAutoConnectMethod(1) + self.SetSignalDisplayType(0) self.SetUseGlobalDNS(False) self.SetGlobalDNS(None,None,None) #end If diff --git a/edgy.py b/edgy.py index 391b44f..3e325e2 100755 --- a/edgy.py +++ b/edgy.py @@ -1,3 +1,11 @@ +''' edgy - implements a tray icon + +Creates and updates the tray icon on systems with pygtk above a certain version +Also calls the wired profile chooser when needed and attempts to auto +reconnect when needed + +''' + ######## ## DO NOT RUN THIS FILE DIRECTLY ## USE TRAY.PY INSTEAD @@ -19,7 +27,13 @@ import sys import wpath if __name__ == '__main__': wpath.chdir(__file__) -import gtk, gobject, dbus, dbus.service, os, sys, locale, gettext, signal, time +import gtk +import gobject +import dbus +import dbus.service +import locale +import gettext +import signal if getattr(dbus, 'version', (0,0,0)) >= (0,41,0): import dbus.glib @@ -53,94 +67,109 @@ osLanguage = os.environ.get('LANGUAGE', None) if (osLanguage): langs += osLanguage.split(":") langs += ["en_US"] -lang = gettext.translation('wicd', local_path, languages=langs, fallback = True) +lang = gettext.translation('wicd', local_path, languages=langs, + fallback = True) _ = lang.gettext language = {} -language['connected_to_wireless'] = _('Connected to $A at $B% (IP: $C)') +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') -tr=None -tooltip = gtk.Tooltips() -pic=None -lastWinId = 0 +class TrayIconInfo(): + ''' class for updating the tray icon status ''' + def __init__(self): + ''' initialize variables needed for the icon status methods ''' + self.last_strength = -2 + self.still_wired = False + self.network = '' + self.tried_reconnect = False + self.last_win_id = 0 -def open_wicd_gui(): - global lastWinId - ret = 0 - if lastWinId != 0: - os.kill(lastWinId,signal.SIGQUIT) - ret = os.waitpid(lastWinId,0)[1] - lastWinId = 0 - if ret == 0: - lastWinId = os.spawnlpe(os.P_NOWAIT, './gui.py', os.environ) - -def wired_profile_chooser(): - print 'profile chooser is running' + def wired_profile_chooser(self): + ''' Launched the wired profile chooser ''' + print 'profile chooser is be launched...' + daemon.SetNeedWiredProfileChooser(True) os.spawnlpe(os.P_WAIT, './gui.py', os.environ) -def set_signal_image(): - global LastStrength - global stillWired # Keeps us from resetting the wired info over and over - global network # Declared as global so it gets initialized before first use + def check_for_wired_connection(self, wired_ip): + ''' Checks for an active wired connection + + Checks for and updates the tray icon for an active wired connection + + ''' + # Only set image/tooltip if it hasn't been set already + if self.still_wired == False: + tr.set_from_file("images/wired.png") + tr.set_tooltip(language['connected_to_wired'].replace('$A', + wired_ip)) + self.still_wired = True + + def check_for_wireless_connection(self, wireless_ip): + ''' Checks for an active wireless connection + + Checks for and updates the tray icon for an active wireless connection + + ''' + wireless_signal = int(wireless.GetCurrentSignalStrength()) + + # Only update if the signal strength has changed because doing I/O + # calls is expensive, and the icon flickers + if (wireless_signal != self.last_strength or + self.network != wireless.GetCurrentNetwork() or + wireless_signal == 0): + self.last_strength = wireless_signal + # Set the string to '' so that when it is put in "high-signal" + + # lock + ".png", there will be nothing + lock = '' + + # cur_net_id needs to be checked because a negative value + # will break the tray when passed to GetWirelessProperty. + cur_net_id = wireless.GetCurrentNetworkID() + + if cur_net_id > -1 and \ + wireless.GetWirelessProperty(cur_net_id, "encryption"): + # Set the string to '-lock' so that it will display the + # lock picture + lock = '-lock' + # Update the tooltip and icon picture + self.network = str(wireless.GetCurrentNetwork()) + tr.set_tooltip(language['connected_to_wireless'].replace + ('$A', self.network).replace + ('$B', daemon.FormatSignalForPrinting + (str(wireless_signal))).replace + ('$C', str(wireless_ip))) + self.set_signal_image(wireless_signal, lock) + + def update_tray_icon(self): + ''' updates tray icon and checks if wired profile chooser should run ''' # Disable logging if debugging isn't on to prevent log spam if not daemon.GetDebugMode(): config.DisableLogging() - # Check if wired profile chooser should be launched - if daemon.GetNeedWiredProfileChooser() == True: - wired_profile_chooser() - daemon.SetNeedWiredProfileChooser(False) - - # Check for active wired connection + # First check for an active wired network, then for an + # active wireless network. If neither is found, change + # icon to reflect that and run auto_reconnect() wired_ip = wired.GetWiredIP() - if wired.CheckPluggedIn() == True and wired_ip != None: - # Only set image/tooltip if it hasn't been set already - if stillWired == False: - tr.set_from_file("images/wired.png") - tr.set_tooltip(language['connected_to_wired'].replace('$A', - wired_ip)) - stillWired = True - lock = '' + if wired_ip is not None and wired.CheckPluggedIn(): + self.check_for_wired_connection(wired_ip) else: - # Check to see if we were using a wired connection that has now become - # unplugged or disabled. - if stillWired == True: + self.still_wired = False # We're not wired any more + wireless_ip = wireless.GetWirelessIP() + if wireless_ip is not None: + self.check_for_wireless_connection(wireless_ip) + else: tr.set_from_file("images/no-signal.png") tr.set_tooltip(language['not_connected']) - stillWired = False + self.auto_reconnect() - wireless_ip = wireless.GetWirelessIP() - # If ip returns as None, we are probably returning from hibernation - # and need to force signal to 0 to avoid crashing. - if wireless_ip != None: - wireless_signal = int(wireless.GetCurrentSignalStrength()) - else: - wireless_signal = 0 + if not daemon.GetDebugMode(): + config.EnableLogging() - # Only update if the signal strength has changed because doing I/O - # calls is expensive, and the icon flickers - if (wireless_signal != LastStrength or - network != wireless.GetCurrentNetwork() or wireless_signal == 0) \ - and wireless_ip != None: - LastStrength = wireless_signal - # Set the string to '' so that when it is put in "high-signal" + - # lock + ".png", there will be nothing - lock = '' - # curNetID needs to be checked because a negative value - # will break the tray when passed to GetWirelessProperty. - curNetID = wireless.GetCurrentNetworkID() - if wireless_signal > 0 and curNetID > -1 and \ - wireless.GetWirelessProperty(curNetID,"encryption"): - # Set the string to '-lock' so that it will display the - # lock picture - lock = '-lock' - network = str(wireless.GetCurrentNetwork()) - tr.set_tooltip(language['connected_to_wireless'].replace - ('$A',network).replace - ('$B',str(wireless_signal)).replace - ('$C',str(wireless_ip))) + return True + + def set_signal_image(self, wireless_signal, lock): + ''' Sets the tray icon picture for an active wireless connection ''' if wireless_signal > 75: tr.set_from_file("images/high-signal" + lock + ".png") elif wireless_signal > 50: @@ -151,37 +180,30 @@ def set_signal_image(): tr.set_from_file("images/bad-signal" + lock + ".png") elif wireless_signal == 0: tr.set_from_file("images/no-signal.png") - auto_reconnect() + # If we have no signal, we should try to reconnect. + self.auto_reconnect() - elif wireless_ip is None and wired_ip is None: - tr.set_from_file("images/no-signal.png") - tr.set_tooltip(language['not_connected']) - auto_reconnect() + def auto_reconnect(self): + ''' Automatically reconnects to a network if needed - if not daemon.GetDebugMode(): - config.EnableLogging() + If automatic reconnection is turned on, this method will + attempt to first reconnect to the last used wireless network, and + should that fail will simply run AutoConnect() - return True - -def auto_reconnect(): + ''' # Auto-reconnect code - not sure how well this works. I know that # without the ForcedDisconnect check it reconnects you when a # disconnect is forced. People who have disconnection problems need # to test it to determine if it actually works. - # - # First it will attempt to reconnect to the last known wireless network - # and if that fails it should run a scan and try to connect to a wired - # network or any wireless network set to autoconnect. - global triedReconnect - if wireless.GetAutoReconnect() == True and \ - daemon.CheckIfConnecting() == False: - curNetID = wireless.GetCurrentNetworkID() - if curNetID > -1: # Needs to be a valid network to try to connect to - if triedReconnect == False: + daemon.CheckIfConnecting() == False and \ + wireless.GetForcedDisconnect() == False: + cur_net_id = wireless.GetCurrentNetworkID() + if cur_net_id > -1: # Needs to be a valid network + if self.tried_reconnect == False: print 'Trying to autoreconnect to last used network' - wireless.ConnectWireless(curNetID) - triedReconnect = True + wireless.ConnectWireless(cur_net_id) + self.tried_reconnect = True elif wireless.CheckIfWirelessConnecting() == False: print "Couldn't reconnect to last used network,\ scanning for an autoconnect network..." @@ -190,6 +212,7 @@ def auto_reconnect(): daemon.AutoConnect(True) class TrackerStatusIcon(gtk.StatusIcon): + ''' Class for creating the wicd tray icon ''' def __init__(self): gtk.StatusIcon.__init__(self) menu = ''' @@ -213,10 +236,10 @@ class TrackerStatusIcon(gtk.StatusIcon): ('Quit',gtk.STOCK_QUIT,'_Quit',None,'Quit wicd-tray-icon', self.on_quit), ] - ag = gtk.ActionGroup('Actions') - ag.add_actions(actions) + actg = gtk.ActionGroup('Actions') + actg.add_actions(actions) self.manager = gtk.UIManager() - self.manager.insert_action_group(ag, 0) + self.manager.insert_action_group(actg, 0) self.manager.add_ui_from_string(menu) self.menu = self.manager.get_widget('/Menubar/Menu/About').props.parent self.current_icon_path = '' @@ -226,40 +249,60 @@ class TrackerStatusIcon(gtk.StatusIcon): self.connect('popup-menu', self.on_popup_menu) self.set_from_file("images/no-signal.png") self.set_tooltip("Initializing wicd...") - + self.last_win_id = 0 wireless.SetForcedDisconnect(False) - def on_activate(self, data): - open_wicd_gui() + def on_activate(self, data=None): + ''' Opens the wicd GUI ''' + self.toggle_wicd_gui() - def on_quit(self,widget): + def on_quit(self, widget=None): + ''' Closes the tray icon ''' sys.exit() def on_popup_menu(self, status, button, time): + ''' Opens the right click menu for the tray icon ''' self.menu.popup(None, None, None, button, time) - def on_preferences(self, data): - open_wicd_gui() + def on_preferences(self, data=None): + ''' Opens the wicd GUI ''' + self.toggle_wicd_gui() - def on_about(self, data): + def on_about(self, data = None): + ''' Opens the About Dialog ''' dialog = gtk.AboutDialog() dialog.set_name('wicd tray icon') - dialog.set_version('0.2') # Might be time to move the version number up? + dialog.set_version('0.2') dialog.set_comments('an icon that shows your network connectivity') dialog.set_website('http://wicd.sourceforge.net') dialog.run() dialog.destroy() - def set_from_file(self,path): + def set_from_file(self, path = None): + ''' Sets a new tray icon picture ''' if path != self.current_icon_path: self.current_icon_path = path gtk.StatusIcon.set_from_file(self,path) -LastStrength = -2 -stillWired = False -network = '' -triedReconnect = False + def toggle_wicd_gui(self): + ''' Toggles the wicd GUI ''' + ret = 0 + if self.last_win_id != 0: + os.kill(self.last_win_id, signal.SIGQUIT) + ret = os.waitpid(self.last_win_id, 0)[1] + self.last_win_id = 0 + if ret == 0: + self.last_win_id = os.spawnlpe(os.P_NOWAIT, './gui.py', os.environ) + tr=TrackerStatusIcon() -gobject.timeout_add(3000,set_signal_image) -gtk.main() +icon_info = TrayIconInfo() + +# Signal receivers for launching the wired profile chooser, and +# for cleaning up child gui.py processes when they're closed. +bus.add_signal_receiver(icon_info.wired_profile_chooser, 'LaunchChooser', + 'org.wicd.daemon') +bus.add_signal_receiver(tr.toggle_wicd_gui, 'CloseGui', 'org.wicd.daemon') + +gobject.timeout_add(3000, icon_info.update_tray_icon) +gobject.MainLoop().run() diff --git a/gui.py b/gui.py index 293a37c..6e251ed 100644 --- a/gui.py +++ b/gui.py @@ -108,7 +108,7 @@ 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_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.') @@ -139,6 +139,7 @@ language['show_wired_list'] = _('Prompt for 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['0'] = _('0') language['1'] = _('1') @@ -327,26 +328,38 @@ class PrettyWirelessNetworkEntry(PrettyNetworkEntry): self.image.set_size_request(60,-1) self.image.set_from_icon_name("network-wired",6) self.pack_start(self.image,fill=False,expand=False) - self.setSignalStrength(wireless.GetWirelessProperty(networkID,'quality')) + self.setSignalStrength(wireless.GetWirelessProperty(networkID,'quality'), + wireless.GetWirelessProperty(networkID,'strength')) self.setMACAddress(wireless.GetWirelessProperty(networkID,'bssid')) self.setMode(wireless.GetWirelessProperty(networkID,'mode')) self.setChannel(wireless.GetWirelessProperty(networkID,'channel')) - self.setEncryption(wireless.GetWirelessProperty(networkID,'encryption'),wireless.GetWirelessProperty(networkID,'encryption_method')) + self.setEncryption(wireless.GetWirelessProperty(networkID,'encryption'), + wireless.GetWirelessProperty(networkID,'encryption_method')) #show everything self.show_all() - def setSignalStrength(self,strength): + def setSignalStrength(self,strength, dbm_strength): strength = int(strength) - if daemon.GetWPADriver() == 'ralink legacy': - if strength <= 60: + if dbm_strength is not None: + dbm_strength = int(dbm_strength) + else: + dbm_strength = -1 + 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: self.image.set_from_file(wpath.images + 'signal-100.png') - elif strength <= 70: + elif dbm_strength >= -70: self.image.set_from_file(wpath.images + 'signal-75.png') - elif strength <= 80: + elif dbm_strength >= -80: self.image.set_from_file(wpath.images + 'signal-50.png') else: self.image.set_from_file(wpath.images + 'signal-25.png') else: + # Uses normal link quality, should be fine in most cases if strength > 75: self.image.set_from_file(wpath.images + 'signal-100.png') elif strength > 50: @@ -355,7 +368,7 @@ class PrettyWirelessNetworkEntry(PrettyNetworkEntry): self.image.set_from_file(wpath.images + 'signal-50.png') else: self.image.set_from_file(wpath.images + 'signal-25.png') - self.expander.setSignalStrength(strength) + self.expander.setSignalStrength(strength, dbm_strength) def setMACAddress(self,address): self.expander.setMACAddress(address) @@ -774,8 +787,9 @@ class WirelessNetworkEntry(NetworkEntry): box.entry.set_text(noneToBlankString(wireless.GetWirelessProperty(self.networkID,methods[ID][2][x][1]))) self.vboxEncryptionInformation.show_all() - def setSignalStrength(self,strength): - if daemon.GetWPADriver() == 'ralink legacy': + def setSignalStrength(self,strength, dbm_strength): + display_type = daemon.GetSignalDisplayType() + if daemon.GetWPADriver() == 'ralink legacy' or display_type == 1: ending = "dBm" start = "-" else: @@ -806,16 +820,22 @@ class WirelessNetworkEntry(NetworkEntry): class appGui: def __init__(self): - print "starting..." - #two possibilities here, one is that the normal GUI should be opened, the other is that wired auto-connect - #is set to prompt the user to select a profile. It's kind of hacked together, but it'll do. + print "starting gui.py..." + # Two possibilities here, one is that the normal GUI should be opened, + # the other is that wired auto-connect is set to prompt the user to + # select a profile. It's kind of hacked together, but it'll do. if daemon.GetNeedWiredProfileChooser() == True: - #profile chooser init block - #import and init WiredNetworkEntry to steal some of the functions and widgets it uses + daemon.SetNeedWiredProfileChooser(False) + # Profile chooser init block. + # Import and init WiredNetworkEntry to steal some of the + # functions and widgets it uses. wiredNetEntry = WiredNetworkEntry() wiredNetEntry.__init__() - dialog = gtk.Dialog(title=language['wired_network_found'], flags = gtk.DIALOG_MODAL, buttons=(gtk.STOCK_CONNECT,1,gtk.STOCK_CANCEL,2)) + dialog = gtk.Dialog(title = language['wired_network_found'], + flags = gtk.DIALOG_MODAL, + buttons = (gtk.STOCK_CONNECT, 1, + gtk.STOCK_CANCEL, 2)) dialog.set_has_separator(False) dialog.set_size_request(400,150) instructLabel = gtk.Label(language['choose_wired_profile'] + ':\n') @@ -825,7 +845,9 @@ class appGui: instructLabel.set_alignment(0,0) stoppopcheckbox.set_active(False) - #remove widgets that were added to the normal WiredNetworkEntry so that they can be added to the pop-up wizard + # Remove widgets that were added to the normal + # WiredNetworkEntry so that they can be added to + # the pop-up wizard. wiredNetEntry.vboxTop.remove(wiredNetEntry.hboxTemp) wiredNetEntry.vboxTop.remove(wiredNetEntry.profileHelp) @@ -852,7 +874,8 @@ class appGui: sys.exit(0) else: if stoppopcheckbox.get_active() == True: - wired.use_default_profile = 1 #so that the pop-up doesn't keep appearing if you cancel it + # Stops the pop-up from reappearing if cancelled + wired.use_default_profile = 1 dialog.destroy() sys.exit(0) else: @@ -869,7 +892,7 @@ class appGui: self.wTree.get_widget("label_instructions").set_label(language['select_a_network']) #I don't know how to translate a menu entry #more specifically, I don't know how to set a menu entry's text - #self.wTree.get_widget("connect_button").modify_text(language['hidden_network']) + #self.wTree.get_widget("connect_button").modify_text(language['_network']) self.wTree.get_widget("progressbar").set_text(language['connecting']) self.network_list = self.wTree.get_widget("network_list_vbox") @@ -918,7 +941,12 @@ class appGui: dialog.show_all() response = dialog.run() if response == 1: - wireless.CreateAdHocNetwork(essidEntry.entry.get_text(),channelEntry.entry.get_text(),ipEntry.entry.get_text(),"WEP",self.keyEntry.entry.get_text(),self.useEncryptionCheckbox.get_active(),False) #useICSCheckbox.get_active()) + wireless.CreateAdHocNetwork(essidEntry.entry.get_text(), + channelEntry.entry.get_text(), + ipEntry.entry.get_text(), "WEP", + self.keyEntry.entry.get_text(), + self.useEncryptionCheckbox.get_active(), + False) #useICSCheckbox.get_active()) dialog.destroy() def toggleEncryptionCheck(self,widget=None): @@ -946,6 +974,8 @@ class appGui: reconnectcheckbox.set_active(wireless.GetAutoReconnect()) debugmodecheckbox = gtk.CheckButton(language['use_debug_mode']) debugmodecheckbox.set_active(daemon.GetDebugMode()) + displaytypecheckbox = gtk.CheckButton(language['display_type_dialog']) + displaytypecheckbox.set_active(daemon.GetSignalDisplayType()) sepline = gtk.HSeparator() usedefaultradiobutton = gtk.RadioButton(None,language['use_default_profile'],False) showlistradiobutton = gtk.RadioButton(usedefaultradiobutton,language['show_wired_list'],False) @@ -1024,6 +1054,7 @@ class appGui: dialog.vbox.pack_start(wiredcheckbox) dialog.vbox.pack_start(reconnectcheckbox) dialog.vbox.pack_start(debugmodecheckbox) + dialog.vbox.pack_start(displaytypecheckbox) dialog.vbox.pack_start(sepline) dialog.vbox.pack_start(entryWiredAutoMethod) dialog.vbox.pack_start(usedefaultradiobutton) @@ -1042,6 +1073,7 @@ class appGui: wired.SetAlwaysShowWiredInterface(wiredcheckbox.get_active()) wireless.SetAutoReconnect(reconnectcheckbox.get_active()) daemon.SetDebugMode(debugmodecheckbox.get_active()) + daemon.SetSignalDisplayType(displaytypecheckbox.get_active()) wired.SetWiredAutoConnectMethod(int(showlistradiobutton.get_active())+1) #if option is default profile, showlist will be 0, so 0 + 1 = 1 #if option is showlist, showlist will be 1, so 1+1 = 2 :) dialog.destroy() @@ -1049,7 +1081,7 @@ class appGui: dialog.destroy() def connect_hidden(self,widget): - #should display a dialog asking + # Should display a dialog asking #for the ssid of a hidden network #and displaying connect/cancel buttons dialog = gtk.Dialog(title=language['hidden_network'], flags=gtk.DIALOG_MODAL, buttons=(gtk.STOCK_CONNECT,1,gtk.STOCK_CANCEL,2)) @@ -1073,7 +1105,8 @@ class appGui: cancelButton = self.wTree.get_widget("cancel_button") cancelButton.set_sensitive(False) wireless.CancelConnect() - wireless.SetForcedDisconnect(True) #Prevents automatic reconnecting if that option is enabled + # Prevents automatic reconnecting if that option is enabled + wireless.SetForcedDisconnect(True) def pulse_progress_bar(self): self.wTree.get_widget("progressbar").pulse() @@ -1112,7 +1145,9 @@ class appGui: network = str(network) strength = str(strength) ip = str(wireless_ip) - self.statusID=self.status_bar.push(1,language['connected_to_wireless'].replace('$A',network).replace('$B',strength).replace('$C',wireless_ip)) + self.statusID=self.status_bar.push(1, language['connected_to_wireless'].replace + ('$A',network).replace('$B',daemon.FormatSignalForPrinting(strength)).replace + ('$C',wireless_ip)) if not daemon.GetDebugMode(): config.EnableLogging() return True @@ -1137,7 +1172,7 @@ class appGui: z.destroy() if wired.CheckPluggedIn() or wired.GetAlwaysShowWiredInterface(): - printLine = True #so that a horizontal line is printed if there are wireless networks + printLine = True # So that a horizontal line is printed if there are wireless networks wiredNetwork = PrettyWiredNetworkEntry() self.network_list.pack_start(wiredNetwork,fill=False,expand=False) wiredNetwork.connectButton.connect("button-press-event",self.connect,"wired",0,wiredNetwork) @@ -1254,6 +1289,9 @@ class appGui: wired.ConnectWired() def exit(self,widget,event=None): + # Call close_gui so the daemon can send a signal to alert + # the tray that the gui has closed (prevents zombies) + daemon.close_gui() sys.exit(0) #start the app diff --git a/misc.py b/misc.py index 81f92e8..bdfd94d 100644 --- a/misc.py +++ b/misc.py @@ -1,4 +1,5 @@ -#misc functions for wicd +''' Misc - miscellaneous functions for wicd ''' + #pretty much useless to anyone else... #but if it is useful, feel free to use under the terms of the GPL # @@ -11,12 +12,11 @@ # import os -import sys import wpath if __name__ == '__main__': wpath.chdir(__file__) -import re def Run(cmd,include_std_error=False): + ''' Run a command ''' if not include_std_error: f = os.popen( cmd , "r") return f.read() @@ -25,28 +25,41 @@ def Run(cmd,include_std_error=False): return out_err.read() def IsValidIP(ip): - if ip != None: #make sure there is an IP - if ip.count('.') == 3: #make sure the IP can be parsed (or at least it has the proper dots) - ipNumbers = ip.split('.') #split it up - if not '' in ipNumbers: #make sure the IP isn't something like 127..0.1 + ''' Make sure an entered IP is valid ''' + if ip != None: # Make sure there is an IP + if ip.count('.') == 3: # Make sure there are 3 periods + ipNumbers = ip.split('.') # Split it up + if not '' in ipNumbers: # Make sure the ip was split into 3 groups return ipNumbers return False def PromptToStartDaemon(): - #script execution doesn't work correctly if daemon gets autostarted, so just prompt user to start manually - print 'You need to start the daemon before using the gui or tray. Use the command \'sudo /etc/init.d/wicd start\'.' + ''' Prompt the user to start the daemon ''' + # script execution doesn't work correctly if daemon gets autostarted, + # so just prompt user to start manually + print 'You need to start the daemon before using the gui or tray. Use \ + the command \'sudo /etc/init.d/wicd start\'.' def RunRegex(regex,string): + ''' runs a regex search on a string ''' m = regex.search(string) if m: return m.groups()[0] else: return None -def WriteLine(file,text): - file.write(text + "\n") +def WriteLine(my_file, text): + ''' write a line to a file ''' + my_file.write(text + "\n") def ExecuteScript(script): + ''' Execute a command + + Executes a given command by forking a new process and + calling run-script.py + + ''' + pid = os.fork() if not pid: os.setsid() @@ -60,14 +73,16 @@ def ExecuteScript(script): def ReadFile(filename): + ''' read in a file and return it's contents as a string ''' if not os.path.exists(filename): return None - file = open(filename,'r') - data = file.read().strip() - file.close() + my_file = open(filename,'r') + data = my_file.read().strip() + my_file.close() return str(data) def Noneify(variable): + ''' convert string types to either None or booleans''' #set string Nones to real Nones if variable == "None" or variable == "": return None @@ -85,45 +100,62 @@ def Noneify(variable): return variable def ParseEncryption(network): + ''' Parse through an encryption template file + + Parses an encryption template, reading in a network's info + and creating a config file for it + + ''' #list = open("encryption/templates/active","r") #types = list.readlines() #for i in types: enctemplate = open("encryption/templates/" + network["enctype"]) template = enctemplate.readlines() - #set these to nothing so that we can hold them outside the loop + # Set these to nothing so that we can hold them outside the loop z = "ap_scan=1\n" y = 0 - #loop through the lines in the template, selecting ones to use + # Loop through the lines in the template, selecting ones to use for x in template: x = x.strip("\n") if y>4: #blah blah replace stuff x = x.replace("$_SCAN","0") for t in network: - if Noneify(network[t]) != None: #don't bother if z's value is None cause it will cause errors + # Don't bother if z's value is None cause it will cause errors + if Noneify(network[t]) != None: x = x.replace("$_" + str(t).upper(),str(network[t])) z = z + "\n" + x y+=1 - #write the data to the files + # Write the data to the files #then chmod them so they can't be read by evil little munchkins - fileness = open(wpath.networks + network["bssid"].replace(":","").lower(),"w") + fileness = 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 permod (permission mod) them before we write, so that it can't be read + # We could do this above, but we'd like to permod (permission mod) + # them before we write, so that it can't be read. fileness.write(z) fileness.close() def LoadEncryptionMethods(): + ''' Load encryption methods from configuration files + + Loads all the encryption methods from the template files + in /encryption/templates into a data structure. To be + loaded, the template must be listed in the "active" file. + + ''' encryptionTypes = {} types = open("encryption/templates/active","r") enctypes = types.readlines() for x in enctypes: - #skip some lines, we don't care who the author is/was, etc - #we don't care about version either + # Skip some lines, we don't care who the author is/was, etc + # we don't care about version either. x = x.strip("\n") current = open("encryption/templates/" + x,"r") line = current.readlines() - typeID = len(encryptionTypes) #this is so we know where in the array to add data + # Get the length so we know where in the array to add data + typeID = len(encryptionTypes) encryptionTypes[typeID] = {} encryptionTypes[typeID][0] = line[0][7:].strip("\n") encryptionTypes[typeID][1] = x @@ -133,21 +165,26 @@ def LoadEncryptionMethods(): requiredFields = requiredFields.split(" ") index = -1 for current in requiredFields: - #the pretty names will start with an * so we can + # The pretty names will start with an * so we can #seperate them with that if current[0] == "*": - #make underscores spaces + # Make underscores spaces #and remove the * - encryptionTypes[typeID][2][index][0] = current.replace("_"," ").lstrip("*") + encryptionTypes[typeID][2][index][0] = current.replace("_", + " ").lstrip("*") else: - #add to the list of things that are required + # Add to the list of things that are required index = len(encryptionTypes[typeID][2]) encryptionTypes[typeID][2][index] = {} encryptionTypes[typeID][2][index][1] = current return encryptionTypes def noneToString(text): - '''used for putting text in a text box if the value to put in is 'None' the box will be blank''' + ''' Convert None, "None", or "" to string type "None" + + used for putting text in a text box if the value to put in is 'None' the box will be blank + + ''' if text == None or text == "None" or text == "": return "None" else: diff --git a/networking.py b/networking.py index 09517ab..18480d1 100644 --- a/networking.py +++ b/networking.py @@ -248,18 +248,24 @@ class Wireless(Controller): """ wiface = wnettools.WirelessInterface(self.wireless_interface, self.wpa_driver) + print 'Creating ad-hoc network' + print 'Killing dhclient and wpa_supplicant' wiface.StopDHCP() wiface.StopWPA() + print 'Putting wireless interface down' wiface.Down() + print 'Setting mode, channel, and essid' wiface.SetMode('ad-hoc') wiface.SetChannel(channel) wiface.SetEssid(essid) #Right now it just assumes you're using WEP if enc_used: + print 'Setting encryption key' wiface.SetKey(key) - + print 'Putting interface up' wiface.Up() # Just assume that the netmask is 255.255.255.0, it simplifies ICS + print 'Setting IP address' wiface.SetAddress(ip, '255.255.255.0') ip_parts = misc.IsValidIP(ip) diff --git a/wnettools.py b/wnettools.py index 2b95d0d..5510a44 100644 --- a/wnettools.py +++ b/wnettools.py @@ -34,13 +34,17 @@ import misc import re import wpath -# Compile the regex patterns that will be used to search the output of iwlist scan for info -# these are well tested, should work on most cards +# Compile the regex patterns that will be used to search the output of iwlist +# scan for info these are well tested, should work on most cards essid_pattern = re.compile('.*ESSID:"(.*?)"\n', re.DOTALL | re.I | re.M | re.S) ap_mac_pattern = re.compile('.*Address: (.*?)\n',re.DOTALL | re.I | re.M | re.S) channel_pattern = re.compile('.*Channel:? ?(\d\d?)',re.DOTALL | re.I | re.M | re.S) +# These next two look a lot a like, altstrength is for Signal level = xx/100, +# which is just an alternate way of displaying link quality,signaldbm is +# for displaying actualy signal strength (-xx dBm). strength_pattern = re.compile('.*Quality:?=? ?(\d\d*)',re.DOTALL | re.I | re.M | re.S) altstrength_pattern = re.compile('.*Signal level:?=? ?(\d\d*)',re.DOTALL | re.I | re.M | re.S) +signaldbm_pattern = re.compile('.*Signal level:?=? ?(-\d\d*)',re.DOTALL | re.I | re.M | re.S) mode_pattern = re.compile('.*Mode:(.*?)\n',re.DOTALL | re.I | re.M | re.S) freq_pattern = re.compile('.*Frequency:(.*?)\n',re.DOTALL | re.I | re.M | re.S) ip_pattern = re.compile(r'inet [Aa]d?dr[^.]*:([^.]*\.[^.]*\.[^.]*\.[0-9]*)',re.S) @@ -375,19 +379,27 @@ class WirelessInterface(Interface): print 'Unknown AuthMode, can\'t assign encryption_method!!' ap['encryption_method'] = 'Unknown' - # Set signal strength here (in dBm, not %) - ap['quality'] = info[1][1:] + # Set signal strength here (in dBm, not %), + # ralink drivers don't return link quality + ap['strength'] = info[1] else: ap['encryption'] = False - if self.wpa_driver != 'ralink legacy': + # Link Quality # Set strength to -1 if the quality is not found if misc.RunRegex(strength_pattern,cell): - ap['quality'] = misc.RunRegex(strength_pattern,cell) + ap['quality'] = misc.RunRegex(strength_pattern,cell) elif misc.RunRegex(altstrength_pattern,cell): - ap['quality'] = misc.RunRegex(altstrength_pattern,cell) + ap['quality'] = misc.RunRegex(altstrength_pattern,cell) else: - ap['quality'] = -1 + ap['quality'] = -1 + + # Signal Strength (only used if user doesn't want link + # quality displayed or it isn't found) + if misc.RunRegex(signaldbm_pattern, cell): + ap['strength'] = misc.RunRegex(signaldbm_pattern, cell) + else: + ap['strength'] = -1 return ap