diff --git a/configscript.py b/configscript.py index 3802361..d58e71e 100755 --- a/configscript.py +++ b/configscript.py @@ -71,22 +71,34 @@ def none_to_blank(text): return '', otherwise it will just return str(text). """ - if text == None or text == "None" or text == "": + if text in (None, "None", ""): return "" else: return str(text) def blank_to_none(text): """ Convert an empty or null string to 'None'. """ - if text == "" or text == None: + if text in ("", None): return "None" else: return str(text) -def get_val(con, network, val, default="None"): - if not con.has_option(network, val): - con.set(network, val, default) - return con.get(network, val) +def get_val(con, network, option, default="None"): + """ Returns the specified option for the given network. + + Returns the value stored in the config file for the given option, + unless the option isn't stored yet, in which case the default value + provided is stored and then returned. + + Keyword arguments: + network -- The section to search. + option -- The option to search for. + deafult -- The default value to store/return if the option isn't found. + + """ + if not con.has_option(network, option): + con.set(network, option, default) + return con.get(network, option) def get_script_info(network, network_type): @@ -169,7 +181,7 @@ def main (argv): script_info["disconnect_entry"] = blank_to_none(disconnect_entry.get_text()) write_scripts(network, network_type, script_info) dialog.destroy() - + if __name__ == '__main__': main(sys.argv) diff --git a/daemon.py b/daemon.py index 47e20e8..1aff173 100644 --- a/daemon.py +++ b/daemon.py @@ -39,11 +39,13 @@ import sys import time import getopt import ConfigParser +import signal # DBUS import gobject import dbus import dbus.service +from dbus.mainloop.glib import DBusGMainLoop if getattr(dbus, 'version', (0, 0, 0)) >= (0, 41, 0): import dbus.glib @@ -191,7 +193,9 @@ class ConnectionWizard(dbus.service.Object): """ Sets the wired interface for the daemon to use. """ print "setting wired interface", str(interface) self.wired.wired_interface = interface + self.wired.SetLiface(interface) self.wifi.wired_interface = interface + self.wifi.SetLiface(interface) config = ConfigParser.ConfigParser() config.read(self.app_conf) config.set("Settings","wired_interface", interface) @@ -202,7 +206,9 @@ class ConnectionWizard(dbus.service.Object): """ Sets the wireless interface the daemon will use. """ print "setting wireless interface" , str(interface) self.wifi.wireless_interface = interface + self.wifi.SetWiface(interface) self.wired.wireless_interface = interface + self.wired.SetWiface(interface) config = ConfigParser.ConfigParser() config.read(self.app_conf) config.set("Settings","wireless_interface", interface) @@ -334,6 +340,11 @@ class ConnectionWizard(dbus.service.Object): self.suspended = val if self.suspended: self.Disconnect() + + @dbus.service.method('org.wicd.daemon') + def GetSuspend(self): + """ Returns True if the computer is in the suspend state. """ + return self.suspended @dbus.service.method('org.wicd.daemon') def AutoConnect(self, fresh): @@ -354,9 +365,9 @@ class ConnectionWizard(dbus.service.Object): def _wired_autoconnect(self): """ Attempts to autoconnect to a wired network. """ if self.GetWiredAutoConnectMethod() == 2 and \ - not self.GetNeedWiredProfileChooser(): - self.LaunchChooser() - elif self.GetWiredAutoConnectMethod == 1: + not self.GetNeedWiredProfileChooser(): + self.LaunchChooser() + elif self.GetWiredAutoConnectMethod() == 1: network = self.GetDefaultWiredNetwork() if not network: print "Couldn't find a default wired connection, wired \ @@ -375,6 +386,10 @@ class ConnectionWizard(dbus.service.Object): self.auto_connecting = True time.sleep(1.5) gobject.timeout_add(3000, self._monitor_wired_autoconnect) + + @dbus.service.method('org.wicd.daemon') + def GetAutoConnecting(self): + return self.auto_connecting def _wireless_autoconnect(self): """ Attempts to autoconnect to a wireless network. """ @@ -439,8 +454,8 @@ class ConnectionWizard(dbus.service.Object): @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 not self.CheckIfWiredConnecting() and \ + not self.CheckIfWirelessConnecting(): return False else: return True @@ -562,6 +577,10 @@ class ConnectionWizard(dbus.service.Object): print 'calling wired profile chooser' self.SetNeedWiredProfileChooser(True) + @dbus.service.method('org.wicd.daemon', in_signature='uav') + def EmitStatusChanged(self, state, info): + self.StatusChanged(state, info) + @dbus.service.signal(dbus_interface='org.wicd.daemon', signature='uav') def StatusChanged(self, state, info): """ Emits a "status changed" dbus signal. @@ -645,8 +664,8 @@ class ConnectionWizard(dbus.service.Object): permitted." return False if self.debug_mode: - print 'setting wireless network', networkid, 'property', property, - 'to value', value + print 'setting wireless network %s property %s to value %s' % \ + (networkid, property, value) self.LastScan[networkid][property] = misc.Noneify(value) #end function SetProperty @@ -654,7 +673,7 @@ class ConnectionWizard(dbus.service.Object): def DetectWirelessInterface(self): """ Returns an automatically detected wireless interface. """ iface = self.wifi.DetectWirelessInterface() - print 'automatically detected wireless interface', iface + print 'automatically detected wireless interface ' + iface return str(iface) @dbus.service.method('org.wicd.daemon.wireless') @@ -843,7 +862,8 @@ class ConnectionWizard(dbus.service.Object): if self.WiredNetwork: value = self.WiredNetwork.get(property) if self.debug_mode == 1: - print 'returned', property, 'with value of', value, 'to client' + print 'returned %s with value of %s to client' % (property, + value) return value else: print 'WiredNetwork does not exist' @@ -1030,7 +1050,7 @@ class ConnectionWizard(dbus.service.Object): profilename = misc.to_unicode(profilename) config = ConfigParser.ConfigParser() config.read(self.wired_conf) - if config.has_section(profilename) == True: + if config.has_section(profilename): for x in config.options(profilename): profile[x] = misc.Noneify(config.get(profilename, x)) profile['use_global_dns'] = bool(profile.get('use_global_dns')) @@ -1094,11 +1114,11 @@ class ConnectionWizard(dbus.service.Object): # Read the essid because we be needing to name those hidden # wireless networks now - but only read it if it is hidden. - if self.LastScan[id]["hidden"] == True: + if self.LastScan[id]["hidden"]: self.LastScan[id]["essid"] = misc.Noneify(config.get(self.LastScan[id]["bssid"], "essid")) for x in config.options(self.LastScan[id]["bssid"]): - if self.LastScan[id].has_key(x) == False or x.endswith("script"): + if not self.LastScan[id].has_key(x) or x.endswith("script"): self.LastScan[id][x] = misc.Noneify(config.get(self.LastScan[id]["bssid"], x)) self.LastScan[id]['use_static_dns'] = bool(self.LastScan[id].get('use_static_dns')) self.LastScan[id]['use_global_dns'] = bool(self.LastScan[id].get('use_global_dns')) @@ -1288,192 +1308,6 @@ class ConnectionWizard(dbus.service.Object): print "autodetected wireless interface...", self.DetectWirelessInterface() print "using wireless interface...", self.GetWirelessInterface() - - -class ConnectionStatus: - """ Class for monitoring the computer's connection status. """ - def __init__(self, connection): - """ Initialize variables needed for the connection status methods. """ - self.last_strength = -2 - self.still_wired = False - self.network = '' - self.tried_reconnect = False - self.connection_lost_counter = 0 - self.conn = connection - self.status_changed = False - self.state = misc.NOT_CONNECTED - - 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 - Returns True if wired connection is active, false if inactive. - - """ - conn = self.conn - if wired_ip is not None and conn.CheckPluggedIn(): - # Only change the interface if it's not already set for wired - if not self.still_wired: - conn.SetCurrentInterface(conn.GetWiredInterface()) - self.still_wired = True - self.status_changed = True - self.state = misc.WIRED - return True - # Wired connection isn't active - self.still_wired = False - return False - - 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. Returns True if wireless connection - is active, and False otherwise. - - """ - conn = self.conn - - # Make sure we have an IP before we do anything else. - if wireless_ip is None: - return False - - # Reset this, just in case. - self.tried_reconnect = False - - # Try getting signal strength, and default to 0 - # if something goes wrong. - try: - if conn.GetSignalDisplayType() == 0: - wifi_signal = int(conn.GetCurrentSignalStrength(self.iwconfig)) - else: - wifi_signal = int(conn.GetCurrentDBMStrength(self.iwconfig)) - except: - wifi_signal = 0 - - if wifi_signal == 0: - # If we have no signal, increment connection loss counter. - # If we haven't gotten any signal 4 runs in a row (12 seconds), - # try to reconnect. - self.connection_lost_counter += 1 - print self.connection_lost_counter - if self.connection_lost_counter >= 4: - self.connection_lost_counter = 0 - return False - else: # If we have a signal, reset the counter - self.connection_lost_counter = 0 - - # Only update if the signal strength has changed because doing I/O - # calls is expensive, and the icon flickers. - if (wifi_signal != self.last_strength or - self.network != conn.GetCurrentNetwork(self.iwconfig)): - self.last_strength = wifi_signal - self.status_changed = True - conn.SetCurrentInterface(conn.GetWirelessInterface()) - self.state = misc.WIRELESS - - return True - - def update_connection_status(self): - """ Updates the tray icon and current connection status. - - Determines the current connection state and sends a dbus signal - announcing when the status changes. Also starts the automatic - reconnection process if necessary. - - """ - conn = self.conn - wired_ip = None - wifi_ip = None - - if conn.suspended: - print "Suspended." - self.state = misc.SUSPENDED - self.update_state() - return True - - # Determine what our current state is. - self.iwconfig = conn.GetIwconfig() - wired_ip = conn.GetWiredIP() - wired_found = self.check_for_wired_connection(wired_ip) - - if not wired_found: - wifi_ip = conn.GetWirelessIP() - wireless_found = self.check_for_wireless_connection(wifi_ip) - if not wireless_found: # No connection at all - if not conn.CheckIfConnecting(): - self.state = misc.NOT_CONNECTED - self.auto_reconnect() - else: - self.state = misc.CONNECTING - self.status_changed = True - self.update_state(wired_ip, wifi_ip) - return True - - def update_state(self, wired_ip=None, wifi_ip=None): - """ Set the current connection state. """ - conn = self.conn - # Set our connection state/info. - if self.state == misc.NOT_CONNECTED: - info = [""] - elif self.state == misc.SUSPENDED: - info = [""] - elif self.state == misc.CONNECTING: - if conn.CheckIfWiredConnecting(): - info = ["wired"] - else: - info = ["wireless", conn.GetCurrentNetwork(self.iwconfig)] - elif self.state == misc.WIRELESS: - info = [wifi_ip, conn.GetCurrentNetwork(self.iwconfig), - str(conn.GetPrintableSignalStrength(self.iwconfig)), - str(conn.GetCurrentNetworkID(self.iwconfig))] - elif self.state == misc.WIRED: - info = [wired_ip] - else: - print 'ERROR: Invalid state!' - return True - conn.SetConnectionStatus(self.state, info) - - # Send a D-Bus signal announcing status has changed if necessary. - if self.status_changed: - conn.StatusChanged(self.state, info) - self.status_changed = False - return True - - def auto_reconnect(self): - """ Automatically reconnects to a network if needed. - - 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() - - """ - conn = self.conn - conn.SetCurrentInterface('') - self.status_changed = True - - if conn.GetAutoReconnect() and not conn.CheckIfConnecting() and \ - not conn.GetForcedDisconnect() and not conn.auto_connecting: - print 'Starting automatic reconnect process' - # First try connecting through ethernet - if conn.CheckPluggedIn(): - print "Wired connection available, trying to connect..." - conn.AutoConnect(False) - return - - # Next try the last wireless network we were connected to - cur_net_id = conn.GetCurrentNetworkID(self.iwconfig) - if cur_net_id > -1: # Needs to be a valid network - if not self.tried_reconnect: - print 'Trying to reconnect to last used wireless \ - network' - conn.ConnectWireless(cur_net_id) - self.tried_reconnect = True - elif conn.CheckIfWirelessConnecting() == False: - print "Couldn't reconnect to last used network, \ - scanning for an autoconnect network..." - conn.AutoConnect(True) - else: - conn.AutoConnect(True) def usage(): @@ -1531,7 +1365,7 @@ def main(argv): argv -- The arguments passed to the script. """ - + global child_pid do_daemonize = True redirect_stderr = True redirect_stdout = True @@ -1569,16 +1403,28 @@ def main(argv): print '---------------------------' # Open the DBUS session - session_bus = dbus.SystemBus() - bus_name = dbus.service.BusName('org.wicd.daemon', bus=session_bus) - object = ConnectionWizard(bus_name, auto_connect=auto_scan) - connection_status = ConnectionStatus(object) - gobject.timeout_add(3000, connection_status.update_connection_status) + d_bus_name = dbus.service.BusName('org.wicd.daemon', bus=dbus.SystemBus()) + obj = ConnectionWizard(d_bus_name, auto_connect=auto_scan) + gobject.threads_init() + (child_pid, x, x, x) = gobject.spawn_async([wpath.bin + "monitor.py"], + flags=gobject.SPAWN_CHILD_INHERITS_STDIN) + + + signal.signal(signal.SIGTERM, sigterm_caught) + # Enter the main loop mainloop = gobject.MainLoop() mainloop.run() +def sigterm_caught(sig, frame): + global child_pid + print 'SIGTERM caught, killing wicd-monitor...' + os.kill(child_pid, signal.SIGTERM) + print 'Shutting down...' + sys.exit(0) + if __name__ == '__main__': + DBusGMainLoop(set_as_default=True) main(sys.argv) diff --git a/gui.py b/gui.py index c1e5278..e28d272 100644 --- a/gui.py +++ b/gui.py @@ -403,14 +403,14 @@ class AdvancedSettingsDialog(gtk.Dialog): 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() == True: + 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() == True: + 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()) @@ -824,7 +824,7 @@ class WiredNetworkEntry(NetworkEntry): config.CreateWiredNetworkProfile(profile_name) self.combo_profile_names.prepend_text(profile_name) self.combo_profile_names.set_active(0) - if self.is_full_gui == True: + if self.is_full_gui: self.button_delete.set_sensitive(True) #self.vbox_ahdvanced.set_sensitive(True) self.connect_button.set_sensitive(True) @@ -839,11 +839,11 @@ class WiredNetworkEntry(NetworkEntry): self.combo_profile_names.remove_text(self.combo_profile_names. get_active()) self.combo_profile_names.set_active(0) - if config.GetWiredProfileList() == None: + if not config.GetWiredProfileList(): self.profile_help.show() entry = self.combo_profile_names.child entry.set_text("") - if self.is_full_gui == True: + if self.is_full_gui: self.button_delete.set_sensitive(False) self.advanced_button.set_sensitive(False) self.script_button.set_sensitive(False) @@ -866,7 +866,7 @@ class WiredNetworkEntry(NetworkEntry): """ 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 self.is_full_gui == False: + if not self.is_full_gui: return profile_name = self.combo_profile_names.get_active_text() @@ -1108,7 +1108,7 @@ class WiredProfileChooser: class appGui: """ The main wicd GUI class. """ - def __init__(self): + def __init__(self, standalone=False): """ Initializes everything needed for the GUI. """ gladefile = "data/wicd.glade" self.windowname = "gtkbench" @@ -1149,6 +1149,7 @@ class appGui: self.vpn_connection_pipe = None self.is_visible = True self.pulse_active = False + self.standalone = standalone self.window.connect('delete_event', self.exit) @@ -1757,7 +1758,7 @@ class appGui: return False return True - def check_encryption_valid(self, entry): + def check_encryption_valid(self, networkid, entry): """ Make sure that encryption settings are properly filled in. """ # Make sure no entries are left blank if entry.chkbox_encryption.get_active(): @@ -1778,7 +1779,8 @@ class appGui: cancel_button = self.wTree.get_widget("cancel_button") cancel_button.set_sensitive(True) if nettype == "wireless": - if not self.check_encryption_valid(networkentry.advanced_dialog): + if not self.check_encryption_valid(networkid, + networkentry.advanced_dialog): return False wireless.ConnectWireless(networkid) elif nettype == "wired": @@ -1787,16 +1789,21 @@ class appGui: def exit(self, widget=None, event=None): """ Hide the wicd GUI. - + This method hides the wicd GUI and writes the current window size - to disc for later use. This method does NOT actually destroy the - GUI, it just hides it. - + to disc for later use. This method normally does NOT actually + destroy the GUI, it just hides it. + """ self.window.hide() - self.is_visible = False [width, height] = self.window.get_size() config.WriteWindowSize(width, height) + + if self.standalone: + self.window.destroy() + sys.exit(0) + + self.is_visible = False daemon.SetGUIOpen(False) while gtk.events_pending(): gtk.main_iteration() @@ -1816,5 +1823,5 @@ class appGui: if __name__ == '__main__': - app = appGui() + app = appGui(standalone=True) gtk.main() diff --git a/misc.py b/misc.py index 29a6908..4cf334c 100644 --- a/misc.py +++ b/misc.py @@ -247,11 +247,10 @@ def get_gettext(): return _ def to_unicode(x): - """ Attempts to convert a string to unicode """ + """ Attempts to convert a string to utf-8. """ try: # This may never fail, but let's be safe default_encoding = locale.getpreferredencoding() except: - print 'Could not get default encoding' default_encoding = None if default_encoding: diff --git a/monitor.py b/monitor.py new file mode 100755 index 0000000..f675317 --- /dev/null +++ b/monitor.py @@ -0,0 +1,249 @@ +#!/usr/bin/env python + +# +# Copyright (C) 2007 Adam Blackburn +# Copyright (C) 2007 Dan O'Reilly +# Copyright (C) 2007 Byron Hillis +# +# 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 dbus +import gobject +import os +import sys + +import wpath +import misc + +if sys.platform == 'linux2': + # Set process name. Only works on Linux >= 2.1.57. + try: + import dl + libc = dl.open('/lib/libc.so.6') + libc.call('prctl', 15, 'wicd-monitor\0', 0, 0, 0) # 15 is PR_SET_NAME + except: + pass + +if __name__ == '__main__': + wpath.chdir(__file__) + +proxy_obj = dbus.SystemBus().get_object('org.wicd.daemon', '/org/wicd/daemon') +daemon = dbus.Interface(proxy_obj, 'org.wicd.daemon') +wired = dbus.Interface(proxy_obj, 'org.wicd.daemon.wired') +wireless = dbus.Interface(proxy_obj, 'org.wicd.daemon.wireless') + +class ConnectionStatus(): + """ Class for monitoring the computer's connection status. """ + def __init__(self): + """ Initialize variables needed for the connection status methods. """ + self.last_strength = -2 + self.displayed_strength = -1 + self.still_wired = False + self.network = '' + self.tried_reconnect = False + self.connection_lost_counter = 0 + self.last_state = misc.NOT_CONNECTED + self.reconnecting = False + self.signal_changed = False + + 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 + Returns True if wired connection is active, false if inactive. + + """ + + if wired_ip and wired.CheckPluggedIn(): + # Only change the interface if it's not already set for wired + if not self.still_wired: + daemon.SetCurrentInterface(daemon.GetWiredInterface()) + self.still_wired = True + return True + # Wired connection isn't active + self.still_wired = False + return False + + 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. Returns True if wireless connection + is active, and False otherwise. + + """ + + # Make sure we have an IP before we do anything else. + if wireless_ip is None: + return False + + # Reset this, just in case. + self.tried_reconnect = False + + # Try getting signal strength, and default to 0 + # if something goes wrong. + try: + if daemon.GetSignalDisplayType() == 0: + wifi_signal = int(wireless.GetCurrentSignalStrength(self.iwconfig)) + else: + wifi_signal = int(wireless.GetCurrentDBMStrength(self.iwconfig)) + except: + wifi_signal = 0 + + if wifi_signal == 0: + # If we have no signal, increment connection loss counter. + # If we haven't gotten any signal 4 runs in a row (12 seconds), + # try to reconnect. + self.connection_lost_counter += 1 + print self.connection_lost_counter + if self.connection_lost_counter >= 4: + self.connection_lost_counter = 0 + return False + else: # If we have a signal, reset the counter + self.connection_lost_counter = 0 + + # Only update if the signal strength has changed because doing I/O + # calls is expensive, and the icon flickers. + if (wifi_signal != self.last_strength or + self.network != wireless.GetCurrentNetwork(self.iwconfig)): + self.last_strength = wifi_signal + self.signal_changed = True + daemon.SetCurrentInterface(daemon.GetWirelessInterface()) + + return True + + def update_connection_status(self): + """ Updates the tray icon and current connection status. + + Determines the current connection state and sends a dbus signal + announcing when the status changes. Also starts the automatic + reconnection process if necessary. + + """ + wired_ip = None + wifi_ip = None + + if daemon.GetSuspend(): + print "Suspended." + state = misc.SUSPENDED + self.update_state(state) + return True + + # Determine what our current state is. + # Check for wired. + wired_ip = wired.GetWiredIP() + wired_found = self.check_for_wired_connection(wired_ip) + if wired_found: + self.update_state(misc.WIRED, wired_ip=wired_ip) + return True + + # Check for wireless + wifi_ip = wireless.GetWirelessIP() + self.iwconfig = wireless.GetIwconfig() + self.signal_changed = False + wireless_found = self.check_for_wireless_connection(wifi_ip) + if wireless_found: + self.update_state(misc.WIRELESS, wifi_ip=wifi_ip) + return True + + # Are we currently connecting? + if daemon.CheckIfConnecting(): + state = misc.CONNECTING + else: # No connection at all. + state = misc.NOT_CONNECTED + self.auto_reconnect() + self.update_state(state) + return True + + def update_state(self, state, wired_ip=None, wifi_ip=None): + """ Set the current connection state. """ + # Set our connection state/info. + if state == misc.NOT_CONNECTED: + info = [""] + elif state == misc.SUSPENDED: + info = [""] + elif state == misc.CONNECTING: + if wired.CheckIfWiredConnecting(): + info = ["wired"] + else: + info = ["wireless", wireless.GetCurrentNetwork(self.iwconfig)] + elif state == misc.WIRELESS: + info = [wifi_ip, wireless.GetCurrentNetwork(self.iwconfig), + str(wireless.GetPrintableSignalStrength(self.iwconfig)), + str(wireless.GetCurrentNetworkID(self.iwconfig))] + elif state == misc.WIRED: + info = [wired_ip] + else: + print 'ERROR: Invalid state!' + return True + daemon.SetConnectionStatus(state, info) + + # Send a D-Bus signal announcing status has changed if necessary. + if state != self.last_state or \ + (state == misc.WIRELESS and self.signal_changed): + daemon.EmitStatusChanged(state, info) + self.last_state = state + return True + + def auto_reconnect(self): + """ Automatically reconnects to a network if needed. + + 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() + + """ + if self.reconnecting: + return + + self.reconnecting = True + daemon.SetCurrentInterface('') + + print 'autoreconnect' + if daemon.GetAutoReconnect() and not daemon.CheckIfConnecting() and \ + not daemon.GetForcedDisconnect() and not daemon.GetAutoConnecting(): + print 'Starting automatic reconnect process' + # First try connecting through ethernet + if wired.CheckPluggedIn(): + print "Wired connection available, trying to connect..." + daemon.AutoConnect(False) + self.reconnecting = False + return + + # Next try the last wireless network we were connected to + cur_net_id = wireless.GetCurrentNetworkID(self.iwconfig) + if cur_net_id > -1: # Needs to be a valid network + if not self.tried_reconnect: + print 'Trying to reconnect to last used wireless \ + network' + wireless.ConnectWireless(cur_net_id) + self.tried_reconnect = True + elif not wireless.CheckIfWirelessConnecting(): + print "Couldn't reconnect to last used network, \ + scanning for an autoconnect network..." + daemon.AutoConnect(True) + else: + daemon.AutoConnect(True) + self.reconnecting = False + + +def main(): + monitor = ConnectionStatus() + gobject.timeout_add(3000, monitor.update_connection_status) + + mainloop = gobject.MainLoop() + mainloop.run() + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/networking.py b/networking.py index 252bd12..7bfe417 100644 --- a/networking.py +++ b/networking.py @@ -73,6 +73,12 @@ class Controller(object): self.global_dns_3 = None def __setattr__(self, attr, value): + """ Provided custom self.variable assignments. + + Calls the appropriate methods if self.wireless_interface or + self.wired_interface is set. + + """ if attr == 'wireless_interface': object.__setattr__(self, attr, value) if self.wiface: @@ -85,17 +91,23 @@ class Controller(object): object.__setattr__(self, attr, value) def SetWiface(self, iface): - self.wiface.SetInterface(iface) + """ Sets the wireless interface for the associated wnettools class. """ + if self.wiface: + self.wiface.SetInterface(iface) def SetLiface(self, iface): - self.liface.SetInterface(iface) + """ Sets the wired interface for the associated wnettools class. """ + if self.liface: + self.liface.SetInterface(iface) class ConnectThread(threading.Thread): """ A class to perform network connections in a multi-threaded way. Useless on it's own, this class provides the generic functions - necessary for connecting using a separate thread. """ + necessary for connecting using a separate thread. + + """ is_connecting = None connecting_thread = None @@ -116,6 +128,7 @@ class ConnectThread(threading.Thread): gdns1 -- global DNS server 1 gdns2 -- global DNS server 2 gdns3 -- global DNS server 3 + debug -- debug mode status """ threading.Thread.__init__(self) @@ -128,6 +141,7 @@ class ConnectThread(threading.Thread): self.before_script = before_script self.after_script = after_script self.disconnect_script = disconnect_script + self.should_die = False self.global_dns_1 = gdns1 self.global_dns_2 = gdns2 @@ -166,6 +180,90 @@ class ConnectThread(threading.Thread): finally: self.lock.release() return message + + def reset_ip_addresses(self, wiface, liface): + """ Resets the IP addresse for both wired/wireless interfaces. + + Sets a false ip so that when we set the real one, the correct + routing entry is created. + + """ + print 'Setting false IP...' + self.SetStatus('resetting_ip_address') + wiface.SetAddress('0.0.0.0') + liface.SetAddress('0.0.0.0') + + def put_iface_down(self, iface): + """ Puts the given interface down. """ + print 'Interface down' + self.SetStatus('interface_down') + iface.Down() + + def run_script_if_needed(self, script, msg): + """ Execute a given script if needed. + + Keyword arguments: + script -- the script to execute, or None/'' if there isn't one. + msg -- the name of the script to display in the log. + + """ + if script: + print 'Executing %s script' % (msg) + misc.ExecuteScript(script) + + def flush_routes(self, wiface, liface): + """ Flush the routes for both wired/wireless interfaces. """ + self.SetStatus('flushing_routing_table') + print 'Flushing the routing table...' + wiface.FlushRoutes() + liface.FlushRoutes() + + def set_broadcast_address(self, iface): + """ Set the broadcast address for the given interface. """ + if not self.network.get('broadcast') == None: + self.SetStatus('setting_broadcast_address') + print 'Setting the broadcast address...' + self.network['broadcast'] + iface.SetAddress(broadcast=self.network['broadcast']) + + def set_ip_address(self, iface): + """ Set the IP address for the given interface. + + Assigns a static IP if one is requested, otherwise calls DHCP. + + """ + if self.network.get('ip'): + self.SetStatus('setting_static_ip') + print 'Setting static IP : ' + self.network['ip'] + iface.SetAddress(self.network['ip'], self.network['netmask']) + print 'Setting default gateway : ' + self.network['gateway'] + iface.SetDefaultRoute(self.network['gateway']) + else: + # Run dhcp... + self.SetStatus('running_dhcp') + print "Running DHCP" + dhcp_status = iface.StartDHCP() + if dhcp_status in ['no_dhcp_offers', 'dhcp_failed']: + self.connect_aborted(dhcp_status) + return + + def set_dns_addresses(self): + """ Set the DNS address(es). + + If static DNS servers or global DNS servers are specified, set them. + Otherwise do nothing. + + """ + if (((self.network.get('dns1') or self.network.get('dns2') or + self.network.get('dns3')) and self.network.get('use_static_dns')) or + self.network.get('use_global_dns')): + self.SetStatus('setting_static_dns') + if self.network.get('use_global_dns'): + wnettools.SetDNS(misc.Noneify(self.global_dns_1), + misc.Noneify(self.global_dns_2), + misc.Noneify(self.global_dns_3)) + else: + wnettools.SetDNS(self.network.get('dns1'), + self.network.get('dns2'), self.network.get('dns3')) def connect_aborted(self, reason): """ Sets the thread status to aborted in a thread-safe way. @@ -179,13 +277,31 @@ class ConnectThread(threading.Thread): self.abort_msg = reason self.is_connecting = False print 'exiting connection thread' + + def stop_dhcp_clients(self, iface): + """ Stop and running DHCP clients, as well as wpa_supplicant. """ + print 'Stopping wpa_supplicant, and any dhcp clients' + iface.StopWPA() + wnettools.StopDHCP() + + def abort_if_needed(self): + """ Abort the thread is it has been requested. """ + if self.should_die: + self.connect_aborted('aborted') + thread.exit() + + def put_iface_up(self, iface): + """ Bring up given interface. """ + print 'Interface up...' + self.SetStatus('interface_up') + iface.Up() class Wireless(Controller): """ A wrapper for common wireless interface functions. """ def __init__(self): - """ Initialise the class. """ + """ Initialize the class. """ Controller.__init__(self) self.wpa_driver = None self.wiface = wnettools.WirelessInterface(self.wireless_interface, @@ -243,6 +359,7 @@ class Wireless(Controller): self.wpa_driver, self.before_script, self.after_script, self.disconnect_script, self.global_dns_1, self.global_dns_2, self.global_dns_3) + self.connecting_thread.setDaemon(True) self.connecting_thread.start() return True @@ -287,7 +404,12 @@ class Wireless(Controller): return self.wiface.GetIwconfig() def IsUp(self): - """ Calls the IsUp method for the wireless interface. """ + """ Calls the IsUp method for the wireless interface. + + Returns: + True if the interface is up, False otherwise. + + """ return self.wiface.IsUp() def CreateAdHocNetwork(self, essid, channel, ip, enctype, key, @@ -359,12 +481,23 @@ class Wireless(Controller): return wnettools.GetWirelessInterfaces() def GetKillSwitchStatus(self): + """ Get the current status of the Killswitch. + + Returns: + True if the killswitch is on, False otherwise. + + """ return self.wiface.GetKillSwitchStatus() def Disconnect(self): - """ Disconnect from the network. """ + """ Disconnect the given iface. + + Executes the disconnect script associated with a given interface, + Resets it's IP address, and puts the interface down then up. + + """ wiface = self.wiface - if self.disconnect_script != None: + if self.disconnect_script not in (None, ""): print 'Running wireless network disconnect script' misc.ExecuteScript(self.disconnect_script) @@ -373,12 +506,15 @@ class Wireless(Controller): wiface.Up() def EnableInterface(self): + """ Puts the interface up. """ return self.wiface.Up() def DisableInterface(self): + """ Puts the interface down. """ return self.wiface.Down() def SetWPADriver(self, driver): + """ Sets the wpa_supplicant driver associated with the interface. """ self.wiface.SetWpaDriver(driver) class WirelessConnectThread(ConnectThread): @@ -430,149 +566,86 @@ class WirelessConnectThread(ConnectThread): wiface = wnettools.WirelessInterface(self.wireless_interface, self.wpa_driver) liface = wnettools.WiredInterface(self.wired_interface) - self.is_connecting = True - - if self.should_die: - self.connect_aborted('aborted') - return - - # Execute pre-connection script if necessary - if self.before_script != '' and self.before_script is not None: - print 'Executing pre-connection script' - misc.ExecuteScript(self.before_script) - if self.should_die: - self.connect_aborted('aborted') - return + # Run pre-connection script. + self.abort_if_needed() + self.run_script_if_needed(self.before_script, 'pre-connection') + self.abort_if_needed() + + # Dake down interface and clean up previous connections. + self.put_iface_down(wiface) + self.abort_if_needed() + self.reset_ip_addresses(wiface, liface) + self.stop_dhcp_clients(wiface) + self.abort_if_needed() + self.flush_routes(wiface, liface) - # Put it down - print 'Interface down' - self.SetStatus('interface_down') - wiface.Down() - - # Set a false ip so that when we set the real one, the correct - # routing entry is created - print 'Setting false IP...' - self.SetStatus('resetting_ip_address') - wiface.SetAddress('0.0.0.0') - liface.SetAddress('0.0.0.0') - - print 'Stopping wpa_supplicant, and any running dhcp clients' - wiface.StopWPA() - wnettools.StopDHCP() - - if self.should_die: - wiface.Up() - self.connect_aborted('aborted') - return - - # Check to see if we need to generate a PSK (only for non-ralink - # cards). + # Generate PSK and authenticate if needed. if self.wpa_driver != 'ralink legacy': - if not self.network.get('key') is None: - self.SetStatus('generating_psk') - - print 'Generating psk...' - key_pattern = re.compile('network={.*?\spsk=(.*?)\n}.*', - re.I | re.M | re.S) - self.network['psk'] = misc.RunRegex(key_pattern, - misc.Run('wpa_passphrase "' + self.network['essid'] + - '" "' + re.escape(self.network['key']) - + '"')) - # Generate the wpa_supplicant file... - if self.network.get('enctype') is not None: - self.SetStatus('generating_wpa_config') - print 'Attempting to authenticate...' - wiface.Authenticate(self.network) - - if self.should_die: - wiface.Up() - self.connect_aborted('aborted') - return - - self.SetStatus('flushing_routing_table') - print 'Flushing the routing table...' - wiface.FlushRoutes() - liface.FlushRoutes() + self.generate_psk_and_authenticate(wiface) + # Put interface up. + self.abort_if_needed() self.SetStatus('configuring_interface') - print 'Configuring the wireless interface...' - - # Bring up the network. - print 'Interface up...' - self.SetStatus('interface_up') - wiface.Up() - - if self.should_die: - self.connect_aborted('aborted') - return - + self.put_iface_up(wiface) + self.abort_if_needed() + + # Associate. wiface.SetMode(self.network['mode']) wiface.Associate(self.network['essid'], self.network['channel'], self.network['bssid']) - if self.network.get('enctype') is not None: + # Authenticate after association for Ralink legacy cards. + if self.wpa_driver == 'ralink legacy': + if self.network.get('key'): + wiface.Authenticate(self.network) + + # Validate Authentication. + if self.network.get('enctype'): self.SetStatus('validating_authentication') - # Make sure wpa_supplicant was able to associate. if not wiface.ValidateAuthentication(time.time()): self.connect_aborted('bad_pass') return - # Authenticate after association for Ralink legacy cards. - if self.wpa_driver == 'ralink legacy': - if self.network.get('key') is not None: - wiface.Authenticate(self.network) - - if self.network.get('broadcast') is not None: - self.SetStatus('setting_broadcast_address') - - print 'Setting the broadcast address...' + self.network['broadcast'] - wiface.SetAddress(broadcast=self.network['broadcast']) - - if self.should_die: - self.connect_aborted('aborted') - return - - if self.network.get('ip'): - self.SetStatus('setting_static_ip') - print 'Setting static IP : ' + self.network['ip'] - wiface.SetAddress(self.network['ip'], self.network['netmask']) - print 'Setting default gateway : ' + self.network['gateway'] - wiface.SetDefaultRoute(self.network['gateway']) - else: - # Run DHCP... - self.SetStatus('running_dhcp') - print "Running DHCP" - dhcp_status = wiface.StartDHCP() - if dhcp_status in ['no_dhcp_offers', 'dhcp_failed']: - self.connect_aborted(dhcp_status) - return - - if ((self.network.get('dns1') or self.network.get('dns2') or - self.network.get('dns3')) and self.network.get('use_static_dns')): - self.SetStatus('setting_static_dns') - if self.network.get('use_global_dns'): - wnettools.SetDNS(misc.Noneify(self.global_dns_1), - misc.Noneify(self.global_dns_2), - misc.Noneify(self.global_dns_3)) - else: - wnettools.SetDNS(self.network.get('dns1'), - self.network.get('dns2'), self.network.get('dns3')) - - if self.should_die: - self.connect_aborted('aborted') - return - - # Execute post-connection script if necessary - if misc.Noneify(self.after_script): - print 'Executing post-connection script' - misc.ExecuteScript(self.after_script) + # Set up gateway, IP address, and DNS servers. + self.set_broadcast_address(wiface) + self.abort_if_needed() + self.set_ip_address(wiface) + self.set_dns_addresses() + + # Run post-connection script. + self.abort_if_needed() + self.run_script_if_needed(self.after_script, 'post-connection') self.SetStatus('done') print 'Connecting thread exiting.' self.is_connecting = False + + def generate_psk_and_authenticate(self, wiface): + """ Generates a PSK and authenticates if necessary. + + Generates a PSK using wpa_passphrase, and starts the authentication + process if encryption is on. + + """ + # Check to see if we need to generate a PSK (only for non-ralink + # cards). + if self.network.get('key'): + self.SetStatus('generating_psk') + print 'Generating psk...' + key_pattern = re.compile('network={.*?\spsk=(.*?)\n}.*', + re.I | re.M | re.S) + self.network['psk'] = misc.RunRegex(key_pattern, + misc.Run(''.join(['wpa_passphrase "', + self.network['essid'], '" "', + re.escape(self.network['key']), '"']))) + # Generate the wpa_supplicant file... + if self.network.get('enctype'): + self.SetStatus('generating_wpa_config') + print 'Attempting to authenticate...' + wiface.Authenticate(self.network) class Wired(Controller): @@ -612,6 +685,7 @@ class Wired(Controller): self.before_script, self.after_script, self.disconnect_script, self.global_dns_1, self.global_dns_2, self.global_dns_3) + self.connecting_thread.setDaemon(True) self.connecting_thread.start() return True @@ -636,13 +710,30 @@ class Wired(Controller): liface.Up() def IsUp(self): - """ Calls the IsUp method for the wired interface. """ + """ Calls the IsUp method for the wired interface. + + Returns: + True if the interface is up, False otherwise. + + """ return self.liface.IsUp() def EnableInterface(self): + """ Puts the interface up. + + Returns: + True if the interface was put up succesfully, False otherwise. + + """ return self.liface.Up() def DisableInterface(self): + """ Puts the interface down. + + Returns: + True if the interface was put down succesfully, False otherwise. + + """ return self.liface.Down() @@ -685,6 +776,7 @@ class WiredConnectThread(ConnectThread): connections. 3. Bring up the interface. 4. Get/set IP address and DNS servers. + 5. Run post-connection script. """ wiface = wnettools.WirelessInterface(self.wireless_interface) @@ -692,97 +784,31 @@ class WiredConnectThread(ConnectThread): self.is_connecting = True - if self.should_die: - self.connect_aborted('aborted') - return - - # Execute pre-connection script if necessary - if self.before_script != '' and self.before_script != None: - print 'executing pre-connection script' - misc.ExecuteScript(self.before_script) - - if self.should_die: - self.connect_aborted('aborted') - return - - # Put it down - print 'Interface down' - self.SetStatus('interface_down') - liface.Down() - - # Set a false ip so that when we set the real one, the correct - # routing entry is created - print 'Setting false IP...' - self.SetStatus('resetting_ip_address') - wiface.SetAddress('0.0.0.0') - liface.SetAddress('0.0.0.0') - - print 'Stopping wpa_supplicant, and any dhcp clients' - wiface.StopWPA() - wnettools.StopDHCP() - - if self.should_die: - liface.Up() - self.connect_aborted('aborted') - return - - self.SetStatus('flushing_routing_table') - print 'Flushing the routing table...' - wiface.FlushRoutes() - liface.FlushRoutes() - - # Bring up the network. - print 'Interface up...' - self.SetStatus('interface_up') - liface.Up() - - if self.should_die: - self.connect_aborted('aborted') - return - - if not self.network.get('broadcast') == None: - self.SetStatus('setting_broadcast_address') - print 'Setting the broadcast address...' + self.network['broadcast'] - liface.SetAddress(broadcast=self.network['broadcast']) - - if self.should_die: - self.connect_aborted('aborted') - return - - if self.network.get('ip'): - self.SetStatus('setting_static_ip') - print 'Setting static IP : ' + self.network['ip'] - liface.SetAddress(self.network['ip'], self.network['netmask']) - print 'Setting default gateway : ' + self.network['gateway'] - liface.SetDefaultRoute(self.network['gateway']) - else: - # Run dhcp... - self.SetStatus('running_dhcp') - print "Running DHCP" - dhcp_status = liface.StartDHCP() - if dhcp_status in ['no_dhcp_offers', 'dhcp_failed']: - self.connect_aborted(dhcp_status) - return - - if ((self.network.get('dns1') or self.network.get('dns2') or - self.network.get('dns3')) and self.network.get('use_static_dns')): - self.SetStatus('setting_static_dns') - if self.network.get('use_global_dns'): - wnettools.SetDNS(misc.Noneify(self.global_dns_1), - misc.Noneify(self.global_dns_2), - misc.Noneify(self.global_dns_3)) - else: - wnettools.SetDNS(self.network.get('dns1'), - self.network.get('dns2'), self.network.get('dns3')) - - if self.should_die: - self.connect_aborted('aborted') - return - - # Execute post-connection script if necessary - if misc.Noneify(self.after_script): - print 'executing post connection script' - misc.ExecuteScript(self.after_script) + # Run pre-connection script. + self.abort_if_needed() + self.run_script_if_needed(self.before_script, 'pre-connection') + self.abort_if_needed() + + # Take down interface and clean up previous connections. + self.put_iface_down(liface) + self.reset_ip_addresses(wiface, liface) + self.stop_dhcp_clients(wiface) + self.abort_if_needed() + self.flush_routes(wiface, liface) + + # Bring up interface. + self.put_iface_up(liface) + self.abort_if_needed() + + # Set gateway, IP adresses, and DNS servers. + self.set_broadcast_address(liface) + self.abort_if_needed() + self.set_ip_address(liface) + self.set_dns_addresses() + self.abort_if_needed() + + # Run post-connection script. + self.run_script_if_needed(self.after_script, 'post-connection') self.SetStatus('done') print 'Connecting thread exiting.' diff --git a/wicd.py b/wicd.py index 509ce59..d8993a5 100755 --- a/wicd.py +++ b/wicd.py @@ -43,6 +43,7 @@ import dbus import dbus.service import getopt import time +import os # Wicd specific imports import wpath @@ -51,8 +52,12 @@ import gui # Import egg.trayicon if we're using an older gtk version if not (gtk.gtk_version[0] >= 2 and gtk.gtk_version[1] >= 10): - import egg.trayicon - USE_EGG = True + try: + import egg.trayicon + USE_EGG = True + except ImportError: + print 'Unable to load wicd.py: Missing egg.trayicon module.' + sys.exit(1) else: USE_EGG = False @@ -137,58 +142,70 @@ class TrayIcon(): """Launch the wired profile chooser.""" gui.WiredProfileChooser() daemon.SetNeedWiredProfileChooser(False) + + def set_wired_state(self, info): + """ Sets the icon info for a wired state. """ + wired_ip = info[0] + self.tr.set_from_file(wpath.images + "wired.png") + self.tr.set_tooltip(language['connected_to_wired'].replace('$A', + wired_ip)) + + def set_wireless_state(self, info): + """ Sets the icon info for a wireless state. """ + lock = '' + wireless_ip = info[0] + self.network = info[1] + strength = info[2] + cur_net_id = int(info[3]) + sig_string = daemon.FormatSignalForPrinting(str(strength)) + + if wireless.GetWirelessProperty(cur_net_id, "encryption"): + lock = "-lock" + + self.tr.set_tooltip(language['connected_to_wireless'] + .replace('$A', self.network) + .replace('$B', sig_string) + .replace('$C', str(wireless_ip))) + self.set_signal_image(strength, lock) + + def set_connecting_state(self, info): + """ Sets the icon info for a connecting state. """ + if info[0] == 'wired' and len(info) == 1: + cur_network = language['wired'] + else: + cur_network = info[1] + self.tr.set_tooltip(language['connecting'] + " to " + + cur_network + "...") + self.tr.set_from_file(wpath.images + "no-signal.png") + + def set_not_connected_state(self, info): + """ Set the icon info for the not connected state. """ + self.tr.set_from_file(wpath.images + "no-signal.png") + if wireless.GetKillSwitchEnabled(): + status = (language['not_connected'] + " (" + + language['killswitch_enabled'] + ")") + else: + status = language['not_connected'] + self.tr.set_tooltip(status) def update_tray_icon(self, state=None, info=None): """ Updates the tray icon and current connection status. """ - if self.use_tray == False: return False + if not self.use_tray: return False if not state or not info: [state, info] = daemon.GetConnectionStatus() if state == misc.WIRED: - wired_ip = info[0] - self.tr.set_from_file(wpath.images + "wired.png") - self.tr.set_tooltip(language['connected_to_wired'].replace('$A', - wired_ip)) - + self.set_wired_state(info) elif state == misc.WIRELESS: - lock = '' - wireless_ip = info[0] - self.network = info[1] - strength = info[2] - cur_net_id = int(info[3]) - sig_string = daemon.FormatSignalForPrinting(str(strength)) - - if wireless.GetWirelessProperty(cur_net_id, "encryption"): - lock = "-lock" - - self.tr.set_tooltip(language['connected_to_wireless'] - .replace('$A', self.network) - .replace('$B', sig_string) - .replace('$C', str(wireless_ip))) - self.set_signal_image(strength, lock) - + self.set_wireless_state(info) elif state == misc.CONNECTING: - if info[0] == 'wired' and len(info) == 1: - cur_network = language['wired'] - else: - cur_network = info[1] - self.tr.set_tooltip(language['connecting'] + " to " + - cur_network + "...") - self.tr.set_from_file(wpath.images + "no-signal.png") - + self.set_connecting_state(info) elif state in (misc.SUSPENDED, misc.NOT_CONNECTED): - self.tr.set_from_file(wpath.images + "no-signal.png") - if wireless.GetKillSwitchEnabled(): - status = (language['not_connected'] + " (" + - language['killswitch_enabled'] + ")") - else: - status = language['not_connected'] - self.tr.set_tooltip(status) + self.set_not_connected_state(info) else: print 'Invalid state returned!!!' return False - return True def set_signal_image(self, wireless_signal, lock): @@ -217,7 +234,7 @@ class TrayIcon(): class TrayIconGUI(): - """ Base Tray Icon class. + """ Base Tray Icon UI class. Implements methods and variables used by both egg/StatusIcon tray icons. @@ -280,9 +297,9 @@ class TrayIcon(): def toggle_wicd_gui(self): """ Toggles the wicd GUI. """ - if self.gui_win == None: + if not self.gui_win: self.gui_win = gui.appGui() - elif self.gui_win.is_visible == False: + elif not self.gui_win.is_visible: self.gui_win.show_win() else: self.gui_win.exit() @@ -408,6 +425,10 @@ def main(argv): elif opt in ('-n', '--no-tray'): use_tray = False + if not use_tray: + os.spawnlp(os.P_NOWAIT, wpath.bin + 'gui.py') + sys.exit(0) + # Set up the tray icon GUI and backend tray_icon = TrayIcon(use_tray) diff --git a/wnettools.py b/wnettools.py index f3364cb..2d6a322 100644 --- a/wnettools.py +++ b/wnettools.py @@ -57,7 +57,7 @@ wpa1_pattern = re.compile('(WPA Version 1)', re.I | re.M | re.S) wpa2_pattern = re.compile('(WPA2)', re.I | re.M | re.S) # Patterns for wpa_cli output -auth_pattern = re.compile('.*wpa_state=(.*?)\n', re.I | re.M | re.S) +auth_pattern = re.compile('.*wpa_state=(.*?)\n', re.I | re.M | re.S) RALINK_DRIVER = 'ralink legacy' @@ -72,19 +72,18 @@ def SetDNS(dns1=None, dns2=None, dns3=None): dns3 -- IP address of DNS server 1 """ - dns_ips = [dns1, dns2, dns3] - resolv = open("/etc/resolv.conf","w") - for dns in dns_ips: + for dns in [dns1, dns2, dns3]: if dns: print 'Setting DNS : ' + dns resolv.write('nameserver ' + dns + '\n') resolv.close() def GetDefaultGateway(): - """Attempts to determine the default gateway by parsing route -n""" + """ Attempts to determine the default gateway by parsing route -n. """ route_info = misc.Run("route -n") lines = route_info.split('\n') + gateway = None for line in lines: words = line.split() print words @@ -94,7 +93,6 @@ def GetDefaultGateway(): if not gateway: print 'couldn\'t retrieve default gateway from route -n' - gateway = None return gateway def StopDHCP(): @@ -125,16 +123,32 @@ class Interface(object): """ self.iface = iface self.verbose = verbose + self.DHCP_CLIENT = None + self.DHCP_CMD = None + self.DHCP_RELEASE = None + self.MIITOOL_FOUND = False + self.ETHTOOL_FOUND = False + self.IP_FOUND = False self.Check() def SetInterface(self, iface): - """ Sets the interface. """ + """ Sets the interface. + + Keyword arguments: + iface -- the name of the interface. + + """ self.iface = iface def CheckDHCP(self): - """ Check that all required tools are available. """ - # TODO: Implement this function. - # THINGS TO CHECK FOR: ethtool, pptp-linux, dhclient, host + """ Check for a valid DHCP client. + + Checks for the existence of a support DHCP client. If one is + found, the appropriate values for DHCP_CMD, DHCP_RELEASE, and + DHCP_CLIENT are set. If a supported client is not found, a + warning is printed. + + """ dhcpclients = ["dhclient", "dhcpcd", "pump"] for client in dhcpclients: if misc.Run("which " + client): @@ -172,8 +186,7 @@ class Interface(object): self.ETHTOOL_FOUND = False def Check(self): - """ Check that all required tools are available.""" - # TODO: Implement this function. + """ Check that all required tools are available. """ # THINGS TO CHECK FOR: ethtool, pptp-linux, dhclient, host self.CheckDHCP() self.CheckWiredTools() @@ -184,66 +197,29 @@ class Interface(object): self.IP_FOUND = False def Up(self): - """ Bring the network interface up. """ + """ Bring the network interface up. + + Returns: + True + + """ cmd = 'ifconfig ' + self.iface + ' up' if self.verbose: print cmd misc.Run(cmd) return True def Down(self): - """ Take down the network interface. """ + """ Take down the network interface. + + Returns: + True + + """ cmd = 'ifconfig ' + self.iface + ' down' if self.verbose: print cmd misc.Run(cmd) return True - def GetDriverName(self): - """ Determine the driver name for the interface. - - Attempt to use ethtool to get the driver associated with a given - interface. If ethtool is not installed or ethtool fails to provide - a driver, None is returned. - - """ - if self.ETHTOOL_FOUND: - cmd = 'ethtool -i ' + self.iface - driver_pattern = re.compile('.*driver: (.*?)\n', re.I | re.M | - re.S) - driver_name = misc.RunRegex(driver_pattern, misc.Run(cmd)) - - if not driver_name or not self.ETHTOOL_FOUND: - print ("Could not determine driver name for iface " + self.iface + - " Is ethtool installed?") - return driver_name - - def LoadDriver(self, driver): - """ Enables the interface by loading the module given by driver. """ - if not driver: - print 'Error: No driver associated with this interface.' - return False - cmd = "modprobe " + driver - if self.verbose: print cmd - output = misc.Run(cmd, True, True) - out = output.readlines() - if out and out[0].startswith("FATAL"): - print "Could not enable Interface: " + out[0] - return False - return True - - def UnloadDriver(self, driver): - """ Disables the interface by removing the module given by driver """ - if not driver: - print 'Error: No driver associated with this interface.' - return False - cmd = "modprobe -r " + driver - if self.verbose: print cmd - output = misc.Run(cmd, True, True) - out = output.readlines() - if out and out[0].startswith("FATAL"): - print "Could not enable Interface: " + out[0] - return False - return True - def SetAddress(self, ip=None, netmask=None, broadcast=None): """ Set the IP addresses of an interface. @@ -253,26 +229,34 @@ class Interface(object): broadcast -- broadcast address in dotted quad form """ - cmd = 'ifconfig ' + self.iface + ' ' + if not self.iface: + return + + cmd = ''.join(['ifconfig ', self.iface, ' ']) if ip: - cmd += ip + ' ' + cmd = ''.join([cmd, ip, ' ']) if netmask: - cmd += 'netmask ' + netmask + ' ' + cmd = ''.join([cmd, 'netmask ', netmask, ' ']) if broadcast: - cmd += 'broadcast ' + broadcast + ' ' + cmd = ''.join([cmd, 'broadcast ', broadcast, ' ']) if self.verbose: print cmd misc.Run(cmd) def _parse_dhclient(self, pipe): - """ Parse the output of dhclient + """ Parse the output of dhclient. Parses the output of dhclient and returns the status of the connection attempt. + + Keyword arguments: + pipe -- stdout pipe to the dhcpcd process. + + Returns: + 'success' if succesful', an error code string otherwise. """ dhclient_complete = False dhclient_success = False - dh_no_offers = False while not dhclient_complete: line = pipe.readline() @@ -283,44 +267,43 @@ class Interface(object): if line.startswith('bound'): dhclient_success = True dhclient_complete = True - if line.startswith('No DHCPOFFERS'): - # We don't break in this case because dhclient will - # try to use an old lease if possible, so we may - # still make a successful connection. - dh_no_offers = True - if dhclient_success: - print 'DHCP connection successful' - return 'success' - if dh_no_offers: - print 'DHCP connection failed: No DHCP offers recieved' - return 'no_dhcp_offers' - else: - print 'DHCP connection failed: Reason unknown' - return 'dhcp_failed' + return self._check_dhcp_result(dhclient_success) def _parse_pump(self, pipe): - """ Determines if obtaining an IP using pump succeeded. """ + """ Determines if obtaining an IP using pump succeeded. + + Keyword arguments: + pipe -- stdout pipe to the dhcpcd process. + + Returns: + 'success' if succesful', an error code string otherwise. + + """ pump_complete = False - pump_succeded = True + pump_success = True while not pump_complete: line = pipe.readline() if line == '': pump_complete = True elif line.strip().lower().startswith('Operation failed.'): - pump_succeded = False + pump_success = False pump_complete = True print line - if pump_succeded: - print "DHCP connection successful" - return "success" - else: - print "DHCP connection failed: Reason unknown" - return 'dhcp_failed' + return self._check_dhcp_result(pump_success) def _parse_dhcpcd(self, pipe): + """ Determines if obtaining an IP using dhcpcd succeeded. + + Keyword arguments: + pipe -- stdout pipe to the dhcpcd process. + + Returns: + 'success' if succesful', an error code string otherwise. + + """ dhcpcd_complete = False dhcpcd_success = True @@ -333,15 +316,33 @@ class Interface(object): dhcpcd_complete = True print line - if dhcpcd_success: - print "DHCP connection successful" - return "success" + return self._check_dhcp_result(dhcpcd_success) + + def _check_dhcp_result(self, success): + """ Print and return the correct DHCP connection result. + + Keyword Arguents: + success -- boolean specifying if DHCP was succesful. + + Returns: + 'success' if success = True, 'dhcp_failed' otherwise. + + """ + if success: + print 'DHCP connection successful' + return 'success' else: - print "DHCP connection failed" - return "dhcp_failed" + print 'DHCP connection failed' + return 'dhcp_failed' def StartDHCP(self): - """ Start the DHCP client to obtain an IP address. """ + """ Start the DHCP client to obtain an IP address. + + Returns: + A string representing the result of the DHCP command. See + _check_dhcp_result for the possible values. + + """ cmd = self.DHCP_CMD + " " + self.iface if self.verbose: print cmd pipe = misc.Run(cmd, include_stderr=True, return_pipe=True) @@ -361,6 +362,8 @@ class Interface(object): def FlushRoutes(self): """ Flush all network routes. """ + if not self.iface: + return if self.IP_FOUND: cmd = "ip route flush dev " + self.iface else: @@ -392,7 +395,12 @@ class Interface(object): return misc.RunRegex(ip_pattern, output) def IsUp(self): - """ Determines if the interface is up. """ + """ Determines if the interface is up. + + Returns: + True if the interface is up, False otherwise. + + """ cmd = "ifconfig " + self.iface output = misc.Run(cmd) lines = output.split('\n') @@ -425,7 +433,12 @@ class WiredInterface(Interface): physical connection state. Should ethtool fail to run properly, mii-tool will be used instead. + Returns: + True if a link is detected, False otherwise. + """ + if not self.iface: + return False if self.ETHTOOL_FOUND: return self._eth_get_plugged_in() elif self.MIITOOL_FOUND: @@ -436,6 +449,12 @@ class WiredInterface(Interface): return False def _eth_get_plugged_in(self): + """ Use ethtool to determine the physical connection state. + + Returns: + True if a link is detected, False otherwise. + + """ link_tool = 'ethtool' if not self.IsUp(): print 'Wired Interface is down, putting it up' @@ -449,6 +468,12 @@ class WiredInterface(Interface): return False def _mii_get_plugged_in(self): + """ Use mii-tool to determine the physical connection state. + + Returns: + True if a link is detected, False otherwise. + + """ link_tool = 'mii-tool' tool_data = misc.Run(link_tool + ' ' + self.iface, True) if misc.RunRegex(re.compile('(Invalid argument)', re.I | re.M | re.S), @@ -500,7 +525,12 @@ class WirelessInterface(Interface): misc.Run(cmd) def GetKillSwitchStatus(self): - """ Determines if the wireless killswitch is enabled. """ + """ Determines if the wireless killswitch is enabled. + + Returns: + True if the killswitch is enabled, False otherwise. + + """ output = misc.Run("iwconfig " + self.iface) killswitch_pattern = re.compile('.*radio off', re.I | re.M | re.S) @@ -554,8 +584,8 @@ class WirelessInterface(Interface): def _FreqToChannel(self, freq): """ Translate the specified frequency to a channel. - Note: This function is simply a lookup table and therefore the - freq argument must be in the table to provide a valid channel. + Note: This function is simply a lookup dict and therefore the + freq argument must be in the dict to provide a valid channel. Keyword arguments: freq -- string containing the specified frequency @@ -565,22 +595,15 @@ class WirelessInterface(Interface): """ ret = None - if freq == '2.412 GHz': ret = 1 - elif freq == '2.417 GHz': ret = 2 - elif freq == '2.422 GHz': ret = 3 - elif freq == '2.427 GHz': ret = 4 - elif freq == '2.432 GHz': ret = 5 - elif freq == '2.437 GHz': ret = 6 - elif freq == '2.442 GHz': ret = 7 - elif freq == '2.447 GHz': ret = 8 - elif freq == '2.452 GHz': ret = 9 - elif freq == '2.457 GHz': ret = 10 - elif freq == '2.462 GHz': ret = 11 - elif freq == '2.467 GHz': ret = 12 - elif freq == '2.472 GHz': ret = 13 - elif freq == '2.484 GHz': ret = 14 - else: - print 'Couldn\'t determine channel number for current network - ' + freq + freq_dict = {'2.412 GHz': 1, '2.417 GHz': 2, '2.422 GHz': 3, + '2.427 GHz': 4, '2.432 GHz': 5, '2.437 GHz': 6, + '2.442 GHz': 7, '2.447 GHz': 8, '2.452 GHz': 9, + '2.457 GHz': 10, '2.462 GHz': 11, '2.467 GHz': 12, + '2.472 GHz': 13, '2.484 GHz': 14 } + try: + ret = freq_dict[freq] + except KeyError: + print "Couldn't determine channel number for frequency: " + freq return ret @@ -606,7 +629,6 @@ class WirelessInterface(Interface): for ralink cards. Returns: - A dictionary containing the cell networks properties. """ @@ -766,11 +788,11 @@ class WirelessInterface(Interface): bssid -- bssid of the network """ - cmd = 'iwconfig ' + self.iface + ' essid "' + essid + '"' + cmd = ''.join(['iwconfig ', self.iface, ' essid "', essid, '"']) if channel: - cmd += ' channel ' + str(channel) + cmd = ''.join([cmd, ' channel ', str(channel)]) if bssid: - cmd += ' ap ' + bssid + cmd = ''.join([cmd, ' ap ', bssid]) if self.verbose: print cmd misc.Run(cmd) @@ -785,9 +807,9 @@ class WirelessInterface(Interface): if self.wpa_driver == RALINK_DRIVER: self._AuthenticateRalinkLegacy(network) else: - cmd = ('wpa_supplicant -B -i ' + self.iface + ' -c "' - + wpath.networks + network['bssid'].replace(':','').lower() - + '" -D ' + self.wpa_driver) + cmd = ''.join(['wpa_supplicant -B -i ', self.iface, ' -c "', + wpath.networks, network['bssid'].replace(':','').lower(), + '" -D ', self.wpa_driver]) if self.verbose: print cmd misc.Run(cmd) @@ -800,6 +822,13 @@ class WirelessInterface(Interface): NOTE: It's possible this could return False, even though in actuality wpa_supplicant just isn't finished yet. + + Keyword arguments: + auth_time -- The time at which authentication began. + + Returns: + True if wpa_supplicant authenticated succesfully, + False otherwise. """ # Right now there's no way to do this for these drivers @@ -923,7 +952,7 @@ class WirelessInterface(Interface): [(strength, max_strength)] = strength_pattern.findall(output) if max_strength and strength: - return 100 * int(strength) / int(max_strength) + return 100 * int(strength) // int(max_strength) if strength == None: strength = misc.RunRegex(altstrength_pattern, output) @@ -962,6 +991,6 @@ class WirelessInterface(Interface): output = iwconfig network = misc.RunRegex(re.compile('.*ESSID:"(.*?)"', re.I | re.M | re.S), output) - if network is not None: + if network: network = misc.to_unicode(network) return network