diff --git a/.bzrignore b/.bzrignore index 4cb9c80..4521dc6 100644 --- a/.bzrignore +++ b/.bzrignore @@ -3,3 +3,23 @@ install.log uninstall.log .bzrignore vcsinfo.py +build +build/* +init/*/* +wpath.py* +man/wicd-curses.8 +man/wicd-manager-settings.conf.5 +man/wicd-wired-settings.conf.5 +man/wicd-wireless-settings.conf.5 +man/wicd.8 +other/50-wicd-suspend.sh +other/55wicd +other/80-wicd-connect.sh +other/WHEREAREMYFILES +other/wicd.conf +other/postinst +scripts/wicd +scripts/wicd-client +scripts/wicd-curses +translations/* +wicd/wpath.py diff --git a/AUTHORS b/AUTHORS index 745b241..0c03fec 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,2 +1,3 @@ -Adam Blackburn (compwiz18@users.sourceforge.net) +Adam Blackburn (compwiz18@gmail.com) Dan O'Reilly (oreilldf@gmail.com) +Andrew Psaltis (ampsaltis@gmail.com) (wicd-curses) diff --git a/curses/curses_misc.py b/curses/curses_misc.py index 9e641fc..e5079c7 100644 --- a/curses/curses_misc.py +++ b/curses/curses_misc.py @@ -110,13 +110,13 @@ class MaskingEdit(urwid.Edit): """ mask_mode = one of: "always" : everything is a '*' all of the time - "on_focus" : everything is a '*' only when not in focus + "no_focus" : everything is a '*' only when not in focus "off" : everything is always unmasked mask_char = the single character that masks all other characters in the field """ def __init__(self, caption = "", edit_text = "", multiline = False, align = 'left', wrap = 'space', allow_tab = False, - edit_pos = None, layout=None, mask_mode="masked",mask_char='*'): + edit_pos = None, layout=None, mask_mode="always",mask_char='*'): self.mask_mode = mask_mode if len(mask_char) > 1: raise MaskingEditException('Masks of more than one character are not supported!') @@ -137,7 +137,7 @@ class MaskingEdit(urwid.Edit): focus. """ # If we aren't masking anything ATM, then act like an Edit. No problems. - if self.mask_mode == "off" or (self.mask_mode == 'on_focus' and focus == True): + if self.mask_mode == "off" or (self.mask_mode == 'no_focus' and focus == True): canv = self.__super.render((maxcol,),focus) # The cache messes this thing up, because I am totally changing what # is displayed. diff --git a/curses/netentry_curses.py b/curses/netentry_curses.py index 7ff07d9..c00c887 100644 --- a/curses/netentry_curses.py +++ b/curses/netentry_curses.py @@ -54,11 +54,11 @@ class AdvancedSettingsDialog(urwid.WidgetWrap): use_static_dns_t = language['use_static_dns'] use_global_dns_t = language['use_global_dns'] - dns_dom_t = ('editcp',language['dns_domain']+': ') - search_dom_t = ('editcp',language['search_domain']+':') - dns1_t = ('editcp',language['dns']+ ' ' + language['1']+':'+' '*8) - dns2_t = ('editcp',language['dns']+ ' ' + language['2']+':'+' '*8) - dns3_t = ('editcp',language['dns']+ ' ' + language['3']+':'+' '*8) + dns_dom_t = ('editcp',language['dns_domain']+': ') + search_dom_t = ('editcp',language['search_domain']+':') + dns1_t = ('editcp',language['dns']+ ' ' + language['1']+':'+' '*8) + dns2_t = ('editcp',language['dns']+ ' ' + language['2']+':'+' '*8) + dns3_t = ('editcp',language['dns']+ ' ' + language['3']+':'+' '*8) cancel_t = 'Cancel' ok_t = 'OK' @@ -105,7 +105,7 @@ class AdvancedSettingsDialog(urwid.WidgetWrap): self._listbox = urwid.ListBox(walker) #self._frame = urwid.Frame(self._listbox) - self._frame = urwid.Frame(self._listbox) + self._frame = urwid.Frame(self._listbox,footer=self.button_cols) self.__super.__init__(self._frame) @@ -192,7 +192,12 @@ class AdvancedSettingsDialog(urwid.WidgetWrap): self.overlay.mouse_event( dim, event, button, col, row, focus=True) - self.overlay.keypress(dim, k) + k = self.overlay.keypress(dim, k) + if k in ('up','page up'): + self._w.set_focus('body') + elif k in ('down','page down'): + self._w.set_focus('footer') + if "window resize" in keys: dim = ui.get_cols_rows() if "esc" in keys or 'Q' in keys: @@ -204,6 +209,7 @@ class AdvancedSettingsDialog(urwid.WidgetWrap): if self.CANCEL_PRESSED: return False + class WiredSettingsDialog(AdvancedSettingsDialog): def __init__(self,name): global wired, daemon @@ -212,7 +218,6 @@ class WiredSettingsDialog(AdvancedSettingsDialog): #self.cur_default = # Add widgets to listbox self._w.body.body.append(self.set_default) - self._w.body.body.append(self.button_cols) self.prof_name = name title = ">"+language['configuring_wired'].replace('$A',self.prof_name) @@ -265,16 +270,19 @@ class WirelessSettingsDialog(AdvancedSettingsDialog): self.networkID = networkID global_settings_t = language['global_settings'] encryption_t = language['use_encryption'] - + autoconnect_t = language['automatic_connect'] + self.global_settings_chkbox = urwid.CheckBox(global_settings_t) self.encryption_chkbox = urwid.CheckBox(encryption_t,on_state_change=self.encryption_toggle) self.encryption_combo = ComboBox(callback=self.combo_on_change) + self.autoconnect_chkbox = urwid.CheckBox(autoconnect_t) self.pile_encrypt = None # _w is a Frame, _w.body is a ListBox, _w.body.body is the ListWalker :-) - self._w.body.body.append(self.global_settings_chkbox) - self._w.body.body.append(self.encryption_chkbox) - self._w.body.body.append(self.encryption_combo) - self._w.body.body.append(self.button_cols) + self._listbox.body.append(urwid.Text("")) + self._listbox.body.append(self.global_settings_chkbox) + self._listbox.body.append(self.autoconnect_chkbox) + self._listbox.body.append(self.encryption_chkbox) + self._listbox.body.append(self.encryption_combo) self.encrypt_types = misc.LoadEncryptionMethods() self.set_values() @@ -306,6 +314,7 @@ class WirelessSettingsDialog(AdvancedSettingsDialog): self.dns_dom_edit.set_edit_text(self.format_entry(networkID, "dns_domain")) self.search_dom_edit.set_edit_text(self.format_entry(networkID, "search_domain")) + self.autoconnect_chkbox.set_state(to_bool(self.format_entry(networkID, "automatic"))) #self.reset_static_checkboxes() self.encryption_chkbox.set_state(bool(wireless.GetWirelessProperty(networkID, @@ -367,6 +376,10 @@ class WirelessSettingsDialog(AdvancedSettingsDialog): #print "no encryption specified..." self.set_net_prop("enctype", "None") AdvancedSettingsDialog.save_settings(self) + + # Save the autoconnect setting. This is not where it originally was + # in the GTK UI. + self.set_net_prop("automatic",self.autoconnect_chkbox.get_state()) if self.global_settings_chkbox.get_state(): self.set_net_prop('use_settings_globally', True) @@ -385,7 +398,7 @@ class WirelessSettingsDialog(AdvancedSettingsDialog): self.encryption_info = {} if self._w.body.body.__contains__(self.pile_encrypt): - self._w.body.body.pop(self._w.body.body.__len__()-2) + self._w.body.body.pop(self._w.body.body.__len__()-1) # If nothing is selected, select the first entry. if ID == -1: @@ -397,9 +410,9 @@ class WirelessSettingsDialog(AdvancedSettingsDialog): for x in opts: edit = None if language.has_key(opts[x][0]): - edit = MaskingEdit(('editcp',language[opts[x][0].lower().replace(' ','_')]+': '),mask_mode='on_focus') + edit = MaskingEdit(('editcp',language[opts[x][0].lower().replace(' ','_')]+': '),mask_mode='no_focus') else: - edit = MaskingEdit(('editcp',opts[x][0].replace('_',' ')+': '),mask_mode='on_focus') + edit = MaskingEdit(('editcp',opts[x][0].replace('_',' ')+': '),mask_mode='no_focus') theList.append(edit) # Add the data to any array, so that the information # can be easily accessed by giving the name of the wanted @@ -410,7 +423,7 @@ class WirelessSettingsDialog(AdvancedSettingsDialog): wireless.GetWirelessProperty(self.networkID, opts[x][1]))) self.pile_encrypt = DynWrap(urwid.Pile(theList),attrs=('editbx','editnfc')) - self._w.body.body.insert(self._w.body.body.__len__()-1,self.pile_encrypt) + self._w.body.body.insert(self._w.body.body.__len__(),self.pile_encrypt) #self._w.body.body.append(self.pile_encrypt) def prerun(self,ui,dim,display): diff --git a/curses/wicd-curses.py b/curses/wicd-curses.py index 3fe5994..0428085 100644 --- a/curses/wicd-curses.py +++ b/curses/wicd-curses.py @@ -86,32 +86,28 @@ class wrap_exceptions: try: return f(*args, **kargs) except KeyboardInterrupt: - gobject.source_remove(redraw_tag) + #gobject.source_remove(redraw_tag) loop.quit() ui.stop() print "\n"+language['terminated'] #raise except DBusException: - gobject.source_remove(redraw_tag) + #gobject.source_remove(redraw_tag) loop.quit() ui.stop() print "\n"+language['dbus_fail'] raise except : - # If the UI isn't inactive (redraw_tag wouldn't normally be - # set), then don't try to stop it, just gracefully die. - if redraw_tag != -1: - # Remove update_ui from the event queue - gobject.source_remove(redraw_tag) - # Quit the loop + # Quit the loop + if 'loop' in locals(): loop.quit() - # Zap the screen - ui.stop() - # Print out standard notification: - print "\n" + language['exception'] - # Flush the buffer so that the notification is always above the - # backtrace - sys.stdout.flush() + # Zap the screen + ui.stop() + # Print out standard notification: + print "\n" + language['exception'] + # Flush the buffer so that the notification is always above the + # backtrace + sys.stdout.flush() # Raise the exception #sleep(2) raise @@ -897,16 +893,16 @@ def main(): ('green','dark green','default'), ('blue','dark blue','default'), ('red','dark red','default'), - ('bold','white','default','bold')]) + ('bold','white','black','bold')]) # This is a wrapper around a function that calls another a function that is a # wrapper around a infinite loop. Fun. + urwid.set_encoding('utf8') ui.run_wrapper(run) def run(): - global loop,redraw_tag + global loop ui.set_mouse_tracking() - redraw_tag = -1 app = appGUI() # Connect signals and whatnot to UI screen control functions @@ -919,7 +915,7 @@ def run(): 'org.wicd.daemon') loop = gobject.MainLoop() # Update what the interface looks like as an idle function - redraw_tag = gobject.idle_add(app.update_ui) + gobject.idle_add(app.update_ui) # Update the connection status on the bottom every 1.5 s. gobject.timeout_add(1500,app.update_status) gobject.idle_add(app.idle_incr) diff --git a/in/init=slackware=rc.wicd.in b/in/init=slackware=rc.wicd.in index b15439c..10b3317 100755 --- a/in/init=slackware=rc.wicd.in +++ b/in/init=slackware=rc.wicd.in @@ -5,6 +5,7 @@ # This is defined in /usr/lib/python2.5/site-packages/wicd/wpath.py PIDFILE="%PIDFILE%" +DAEMON="%SBIN%wicd" # Define start and stop functions @@ -15,7 +16,7 @@ wicd_start() { echo "$PIDFILE and try again..." exit 1 else - echo "Starting wicd daemon..." + echo "Starting wicd daemon: $DAEMON" wicd 2>/dev/null 1>&2 fi } diff --git a/in/man=wicd-curses.8.in b/in/man=wicd-curses.8.in index c38e426..9e0e549 100644 --- a/in/man=wicd-curses.8.in +++ b/in/man=wicd-curses.8.in @@ -64,20 +64,15 @@ Bring up instructions on how to edit the scripts. I have implemented a way to d Raise the Ad-Hoc network creation dialog .SH "FILES" -These are not used yet. .TP .I ~/.wicd/WHEREAREMYFILES Reminder that your network configuration files are not here ;-) -.TP -.I %LIB%keymap.py -Tentative location of the system keymap +.PP +These following are not used yet: .TP .I %LIB%colors.py Tentative location of the system color schemes .TP -.I ~/.wicd/keymap.py -Custom keybindings. Also where you can (later) disable the mouse. -.TP .I ~/.wicd/colors.py Custom color schemes. .SH "SEE ALSO" @@ -87,7 +82,7 @@ Custom color schemes. .SH BUGS Probably lots. ;-) -If you happen to find one, ask about it on #wicd on freenode, or submit a bug report to http://launchpad.net/wicd, branch experimental-nacl. +If you happen to find one, ask about it on #wicd on freenode, or submit a bug report to http://launchpad.net/wicd. .SH WICD-CURSES AUTHOR Andrew Psaltis diff --git a/in/man=wicd.8.in b/in/man=wicd.8.in index 55a5afb..ead0b52 100644 --- a/in/man=wicd.8.in +++ b/in/man=wicd.8.in @@ -157,7 +157,7 @@ Adam Blackburn .br Dan O'Reilly .br -Andrew Psaltis (curses client) +Andrew Psaltis (curses client) .SH MANPAGE AUTHOR Robby Workman diff --git a/setup.py b/setup.py index 5c88c27..92ffc2c 100755 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # -# Copyright (C) 2007 - 2008 Adam Blackburn -# Copyright (C) 2007 - 2008 Dan O'Reilly +# Copyright (C) 2007 - 2009 Adam Blackburn +# Copyright (C) 2007 - 2009 Dan O'Reilly # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License Version 2 as @@ -25,9 +25,10 @@ import subprocess # Be sure to keep this updated! # VERSIONNUMBER -VERSION_NUM = '1.6.0' +VERSION_NUM = '1.6.0a1' +# REVISION_NUM is automatically updated REVISION_NUM = 'unknown' -CURSES_REVNO = 'r273' +CURSES_REVNO = 'r277' try: if not os.path.exists('vcsinfo.py'): diff --git a/wicd/backends/be-external.py b/wicd/backends/be-external.py index 5d74b85..2cce772 100644 --- a/wicd/backends/be-external.py +++ b/wicd/backends/be-external.py @@ -35,9 +35,9 @@ from wicd.wnettools import * import re import os import os.path -import time - +# Regular expressions for wpa_cli output +auth_patten = re.compile('.*wpa_state=(.*?)\n', wnettools.__re_mode) NAME = "external" UPDATE_INTERVAL = 5 DESCRIPTION = """External app (original) backend @@ -49,30 +49,6 @@ it doesn't require any third party libraries and may be more stable for some set ups. """ -# 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:"?(.*?)"?\s*\n', re.I | re.M | re.S) -ap_mac_pattern = re.compile('.*Address: (.*?)\n', re.I | re.M | re.S) -channel_pattern = re.compile('.*Channel:? ?(\d\d?)', re.I | re.M | re.S) -strength_pattern = re.compile('.*Quality:?=? ?(\d+)\s*/?\s*(\d*)', 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 actual signal strength (-xx dBm). -altstrength_pattern = re.compile('.*Signal level:?=? ?(\d\d*)', re.I | re.M | re.S) -signaldbm_pattern = re.compile('.*Signal level:?=? ?(-\d\d*)', re.I | re.M | re.S) -mode_pattern = re.compile('.*Mode:(.*?)\n', re.I | re.M | re.S) -freq_pattern = re.compile('.*Frequency:(.*?)\n', re.I | re.M | re.S) -ip_pattern = re.compile(r'inet [Aa]d?dr[^.]*:([^.]*\.[^.]*\.[^.]*\.[0-9]*)', re.S) -bssid_pattern = re.compile('.*Access Point: (([0-9A-Z]{2}:){5}[0-9A-Z]{2})', re.I | re.M | re.S) - -wep_pattern = re.compile('.*Encryption key:(.*?)\n', re.I | re.M | re.S) -altwpa_pattern = re.compile('(wpa_ie)', re.I | re.M | re.S) -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) - RALINK_DRIVER = 'ralink legacy' @@ -94,54 +70,6 @@ class Interface(wnettools.BaseInterface): wnettools.BaseInterface.__init__(self, iface, verbose) self.Check() - def GetIP(self, ifconfig=""): - """ Get the IP address of the interface. - - Returns: - The IP address of the interface in dotted quad form. - - """ - if not ifconfig: - cmd = 'ifconfig ' + self.iface - if self.verbose: print cmd - output = misc.Run(cmd) - else: - output = ifconfig - return misc.RunRegex(ip_pattern, output) - - def IsUp(self, ifconfig=None): - """ Determines if the interface is up. - - Returns: - True if the interface is up, False otherwise. - - """ - if not self.iface: return False - flags_file = '/sys/class/net/%s/flags' % self.iface - try: - flags = open(flags_file, "r").read().strip() - except IOError: - print "Could not open %s, using ifconfig to determine status" % flags_file - return self._slow_is_up(ifconfig) - return bool(int(flags, 16) & 1) - - - def _slow_is_up(self, ifconfig=None): - """ Determine if an interface is up using ifconfig. """ - if not ifconfig: - cmd = "ifconfig " + self.iface - if self.verbose: print cmd - output = misc.Run(cmd) - else: - output = ifconfig - lines = output.split('\n') - if len(lines) < 5: - return False - for line in lines[1:4]: - if line.strip().startswith('UP'): - return True - return False - class WiredInterface(Interface, wnettools.BaseWiredInterface): """ Control a wired network interface. """ @@ -156,97 +84,6 @@ class WiredInterface(Interface, wnettools.BaseWiredInterface): wnettools.BaseWiredInterface.__init__(self, iface, verbose) Interface.__init__(self, iface, verbose) - def GetPluggedIn(self): - """ Get the current physical connection state. - - The method will first attempt to use ethtool do determine - 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 - # check for link using /sys/class/net/iface/carrier - # is usually more accurate - sys_device = '/sys/class/net/%s/' % self.iface - carrier_path = sys_device + 'carrier' - if not self.IsUp(): - MAX_TRIES = 3 - tries = 0 - self.Up() - while True: - tries += 1 - time.sleep(2) - if self.IsUp() or tries > MAX_TRIES: break - - if os.path.exists(carrier_path): - carrier = open(carrier_path, 'r') - try: - link = carrier.read().strip() - link = int(link) - if link == 1: - return True - elif link == 0: - return False - except (IOError, ValueError, TypeError): - print 'Error checking link using /sys/class/net/%s/carrier' % self.iface - - if self.ethtool_cmd and self.link_detect in [misc.ETHTOOL, misc.AUTO]: - return self._eth_get_plugged_in() - elif self.miitool_cmd and self.link_detect in [misc.MIITOOL, misc.AUTO]: - return self._mii_get_plugged_in() - else: - print ('Error: No way of checking for a wired connection. Make ' + - 'sure that either mii-tool or ethtool is installed.') - 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. - - """ - cmd = "%s %s" % (self.ethtool_cmd, self.iface) - if not self.IsUp(): - print 'Wired Interface is down, putting it up' - self.Up() - time.sleep(6) - if self.verbose: print cmd - tool_data = misc.Run(cmd, include_stderr=True) - if misc.RunRegex(re.compile('(Link detected: yes)', re.I | re.M | re.S), - tool_data): - return True - else: - return False - - def _mii_get_plugged_in(self): - """ Use mii-tool to determine the physical connection state. - - Returns: - True if a link is detected, False otherwise. - - """ - cmd = "%s %s" % (self.miitool_cmd, self.iface) - if self.verbose: print cmd - tool_data = misc.Run(cmd, include_stderr=True) - if misc.RunRegex(re.compile('(Invalid argument)', re.I | re.M | re.S), - tool_data) is not None: - print 'Wired Interface is down, putting it up' - self.Up() - time.sleep(4) - if self.verbose: print cmd - tool_data = misc.Run(cmd, include_stderr=True) - - if misc.RunRegex(re.compile('(link ok)', re.I | re.M | re.S), - tool_data) is not None: - return True - else: - return False - class WirelessInterface(Interface, wnettools.BaseWirelessInterface): """ Control a wireless network interface. """ @@ -262,265 +99,3 @@ class WirelessInterface(Interface, wnettools.BaseWirelessInterface): wpa_driver) Interface.__init__(self, iface, verbose) - def GetNetworks(self): - """ Get a list of available wireless networks. - - Returns: - A list containing available wireless networks. - - """ - cmd = 'iwlist ' + self.iface + ' scan' - if self.verbose: print cmd - results = misc.Run(cmd) - # Split the networks apart, using Cell as our split point - # this way we can look at only one network at a time. - # The spaces around ' Cell ' are to minimize the chance that someone - # has an essid named Cell... - networks = results.split( ' Cell ' ) - - # Get available network info from iwpriv get_site_survey - # if we're using a ralink card (needed to get encryption info) - if self.wpa_driver == RALINK_DRIVER: - ralink_info = self._GetRalinkInfo() - else: - ralink_info = None - - # An array for the access points - access_points = [] - for cell in networks: - # Only use sections where there is an ESSID. - if 'ESSID:' in cell: - # Add this network to the list of networks - entry = self._ParseAccessPoint(cell, ralink_info) - if entry is not None: - access_points.append(entry) - - return access_points - - def _ParseAccessPoint(self, cell, ralink_info): - """ Parse a single cell from the output of iwlist. - - Keyword arguments: - cell -- string containing the cell information - ralink_info -- string contating network information needed - for ralink cards. - - Returns: - A dictionary containing the cell networks properties. - - """ - ap = {} - ap['essid'] = misc.RunRegex(essid_pattern, cell) - try: - ap['essid'] = misc.to_unicode(ap['essid']) - except (UnicodeDecodeError, UnicodeEncodeError): - print 'Unicode problem with current network essid, ignoring!!' - return None - if ap['essid'] in ['', ""]: - ap['hidden'] = True - ap['essid'] = "" - else: - ap['hidden'] = False - - # Channel - For cards that don't have a channel number, - # convert the frequency. - ap['channel'] = misc.RunRegex(channel_pattern, cell) - if ap['channel'] == None: - freq = misc.RunRegex(freq_pattern, cell) - ap['channel'] = self._FreqToChannel(freq) - - # BSSID - ap['bssid'] = misc.RunRegex(ap_mac_pattern, cell) - - # Mode - ap['mode'] = misc.RunRegex(mode_pattern, cell) - - # Break off here if we're using a ralink card - if self.wpa_driver == RALINK_DRIVER: - ap = self._ParseRalinkAccessPoint(ap, ralink_info, cell) - elif misc.RunRegex(wep_pattern, cell) == 'on': - # Encryption - Default to WEP - ap['encryption'] = True - ap['encryption_method'] = 'WEP' - - if misc.RunRegex(wpa1_pattern, cell) == 'WPA Version 1': - ap['encryption_method'] = 'WPA' - - if misc.RunRegex(altwpa_pattern, cell) == 'wpa_ie': - ap['encryption_method'] = 'WPA' - - if misc.RunRegex(wpa2_pattern, cell) == 'WPA2': - ap['encryption_method'] = 'WPA2' - else: - ap['encryption'] = False - - # Link Quality - # Set strength to -1 if the quality is not found - - # more of the patch from - # https://bugs.launchpad.net/wicd/+bug/175104 - if (strength_pattern.match(cell)): - [(strength, max_strength)] = strength_pattern.findall(cell) - if max_strength: - ap["quality"] = 100 * int(strength) // int(max_strength) - else: - ap["quality"] = int(strength) - elif misc.RunRegex(altstrength_pattern,cell): - ap['quality'] = misc.RunRegex(altstrength_pattern, cell) - else: - 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) - elif self.wpa_driver != RALINK_DRIVER: # This is already set for ralink - ap['strength'] = -1 - - return ap - - def ValidateAuthentication(self, auth_time): - """ Validate WPA authentication. - - Validate that the wpa_supplicant authentication - process was successful. - - NOTE: It's possible this could return False, - though in reality wpa_supplicant just isn't - finished yet. - - Keyword arguments: - auth_time -- The time at which authentication began. - - Returns: - True if wpa_supplicant authenticated succesfully, - False otherwise. - - """ - # Right now there's no way to do this for these drivers - if self.wpa_driver == RALINK_DRIVER or not self.wpa_cli_cmd: - return True - - MAX_TIME = 35 - MAX_DISCONNECTED_TIME = 3 - disconnected_time = 0 - while (time.time() - auth_time) < MAX_TIME: - cmd = '%s -i %s status' % (self.wpa_cli_cmd, self.iface) - output = misc.Run(cmd) - result = misc.RunRegex(auth_pattern, output) - if self.verbose: - print 'WPA_CLI RESULT IS', result - - if not result: - return False - if result == "COMPLETED": - return True - elif result == "DISCONNECTED": - disconnected_time += 1 - if disconnected_time > MAX_DISCONNECTED_TIME: - disconnected_time = 0 - # Force a rescan to get wpa_supplicant moving again. - self._ForceSupplicantScan() - MAX_TIME += 5 - else: - disconnected_time = 0 - time.sleep(1) - - print 'wpa_supplicant authentication may have failed.' - return False - - - def _ForceSupplicantScan(self): - """ Force wpa_supplicant to rescan available networks. - - This function forces wpa_supplicant to rescan. - This works around authentication validation sometimes failing for - wpa_supplicant because it remains in a DISCONNECTED state for - quite a while, after which a rescan is required, and then - attempting to authenticate. This whole process takes a long - time, so we manually speed it up if we see it happening. - - """ - print 'wpa_supplicant rescan forced...' - cmd = 'wpa_cli -i' + self.iface + ' scan' - misc.Run(cmd) - - def StopWPA(self): - """ Terminates wpa using wpa_cli""" - cmd = 'wpa_cli -i %s terminate' % self.iface - if self.verbose: print cmd - misc.Run(cmd) - - def GetBSSID(self, iwconfig=None): - """ Get the MAC address for the interface. """ - if not iwconfig: - cmd = 'iwconfig ' + self.iface - if self.verbose: print cmd - output = misc.Run(cmd) - else: - output = iwconfig - - bssid = misc.RunRegex(bssid_pattern, output) - return bssid - - def GetSignalStrength(self, iwconfig=None): - """ Get the signal strength of the current network. - - Returns: - The signal strength. - - """ - if not iwconfig: - cmd = 'iwconfig ' + self.iface - if self.verbose: print cmd - output = misc.Run(cmd) - else: - output = iwconfig - - [(strength, max_strength)] = strength_pattern.findall(output) - if max_strength and strength: - if int(max_strength) != 0: - return 100 * int(strength) // int(max_strength) - else: - # Prevent a divide by zero error. - strength = int(strength) - - if strength is None: - strength = misc.RunRegex(altstrength_pattern, output) - - return strength - - def GetDBMStrength(self, iwconfig=None): - """ Get the dBm signal strength of the current network. - - Returns: - The dBm signal strength. - - """ - if not iwconfig: - cmd = 'iwconfig ' + self.iface - if self.verbose: print cmd - output = misc.Run(cmd) - else: - output = iwconfig - dbm_strength = misc.RunRegex(signaldbm_pattern, output) - return dbm_strength - - def GetCurrentNetwork(self, iwconfig=None): - """ Get the essid of the current network. - - Returns: - The current network essid. - - """ - if not iwconfig: - cmd = 'iwconfig ' + self.iface - if self.verbose: print cmd - output = misc.Run(cmd) - else: - output = iwconfig - network = misc.RunRegex(re.compile('.*ESSID:"(.*?)"', - re.I | re.M | re.S), output) - if network: - network = misc.to_unicode(network) - return network diff --git a/wicd/backends/be-ioctl.py b/wicd/backends/be-ioctl.py index 3ba9a48..e421ced 100644 --- a/wicd/backends/be-ioctl.py +++ b/wicd/backends/be-ioctl.py @@ -33,6 +33,8 @@ from wicd import misc from wicd import wnettools from wicd import wpath from wicd.wnettools import * +from wicd.wnettools import strength_pattern, altstrength_pattern, wep_pattern, \ + signaldbm_pattern import iwscan import wpactrl @@ -58,14 +60,6 @@ Dependencies: python-wpactrl (http://projects.otaku42.de/wiki/PythonWpaCtrl) python-iwscan (http://projects.otaku42.de/browser/python-iwscan/)""" -strength_pattern = re.compile('.*Quality:?=? ?(\d+)\s*/?\s*(\d*)', - re.I | re.M | re.S) -altstrength_pattern = re.compile('.*Signal level:?=? ?(\d\d*)', - re.I | re.M | re.S) -signaldbm_pattern = re.compile('.*Signal level:?=? ?(-\d\d*)', - re.I | re.M | re.S) -wep_pattern = re.compile('.*Encryption key:(.*?)\n', re.I | re.M | re.S) - RALINK_DRIVER = 'ralink legacy' # Got these from /usr/include/linux/wireless.h @@ -341,14 +335,16 @@ class WirelessInterface(Interface, wnettools.BaseWirelessInterface): def _connect_to_wpa_ctrl_iface(self): """ Connect to the wpa ctrl interface. """ ctrl_iface = '/var/run/wpa_supplicant' - try: - socket = [os.path.join(ctrl_iface, s) \ - for s in os.listdir(ctrl_iface) if s == self.iface][0] - except OSError, error: - print error + socket_loc = os.path.join(ctrl_iface, self.iface) + if os.path.exists(socket_loc): + try: + return wpactrl.WPACtrl(socket_loc) + except wpactrl.error, e: + print "Couldn't open ctrl_interface: %s" % e + return None + else: + print "Couldn't find a wpa_supplicant ctrl_interface for iface %s" % self.iface return None - - return wpactrl.WPACtrl(socket) def ValidateAuthentication(self, auth_time): """ Validate WPA authentication. diff --git a/wicd/misc.py b/wicd/misc.py index 0a8f03d..c474ac0 100644 --- a/wicd/misc.py +++ b/wicd/misc.py @@ -223,19 +223,34 @@ def ParseEncryption(network): """ enctemplate = open(wpath.encryption + network["enctype"]) template = enctemplate.readlines() - # Set these to nothing so that we can hold them outside the loop - z = "ap_scan=1\n" - # Loop through the lines in the template, selecting ones to use - for y, x in enumerate(template): - x = x.strip("\n") - if y > 4: - # replace values - x = x.replace("$_SCAN","0") - for t in network: - # Don't bother if z's value is None cause it will cause errors - if Noneify(network[t]) is not None: - x = x.replace("$_" + str(t).upper(), str(network[t])) - z = z + "\n" + x + config_file = "ap_scan=1\n" + should_replace = False + for index, line in enumerate(template): + if not should_replace: + if line.strip().startswith('---'): + should_replace = True + else: + if line.strip().startswith("}"): + # This is the last line, so we just write it. + config_file = ''.join([config_file, line]) + elif "$_" in line: + cur_val = re.findall('\$_([A-Z0-9_]+)', line) + if cur_val: + if cur_val[0] == 'SCAN': + #TODO should this be hardcoded? + line = line.replace("$_SCAN", "0") + config_file = ''.join([config_file, line]) + else: + rep_val = network.get(cur_val[0].lower()) + if rep_val: + line = line.replace("$_%s" % cur_val[0], rep_val) + config_file = ''.join([config_file, line]) + else: + print "Ignoring template line: '%s'" % line + else: + print "Weird parsing error occurred" + else: # Just a regular entry. + config_file = ''.join([config_file, line]) # Write the data to the files then chmod them so they can't be read # by normal users. @@ -244,7 +259,7 @@ def ParseEncryption(network): os.chown(wpath.networks + network["bssid"].replace(":", "").lower(), 0, 0) # We could do this above, but we'd like to read protect # them before we write, so that it can't be read. - f.write(z) + f.write(config_file) f.close() def LoadEncryptionMethods(): @@ -525,7 +540,7 @@ def get_language_list_gui(): language['stop_showing_chooser'] = _('Stop Showing Autoconnect pop-up temporarily') language['display_type_dialog'] = _('Use dBm to measure signal strength') language['scripts'] = _('Scripts') - language['invalid_address'] = _('Invalid address in $A entry.') + #language['invalid_address'] = _('Invalid address in $A entry.') language['global_settings'] = _('Use these settings for all networks sharing this essid') language['encrypt_info_missing'] = _('Required encryption information is missing.') language['enable_encryption'] = _('This network requires encryption to be enabled.') @@ -610,6 +625,14 @@ def get_language_list_gui(): language['wicd_curses'] = _("Wicd Curses Interface") language['dbus_fail'] = _("DBus failure! This is most likely caused by the wicd daemon stopping while wicd-curses is running. Please restart the daemon, and then restart wicd-curses.") + # Fix strings in wicd-curses + for i in language.keys(): + try : + language[i] = language[i].decode('utf8') + except: + print "\"%s\"" % language[i] + raise + return language diff --git a/wicd/monitor.py b/wicd/monitor.py index 8ff56c1..c590a10 100755 --- a/wicd/monitor.py +++ b/wicd/monitor.py @@ -45,7 +45,7 @@ daemon = dbus_dict["daemon"] wired = dbus_dict["wired"] wireless = dbus_dict["wireless"] -monitor = to_time = update_callback = None +monitor = to_time = update_callback = mainloop = None def diewithdbus(func): def wrapper(self, *__args, **__kargs): @@ -54,11 +54,11 @@ def diewithdbus(func): self.__lost_dbus_count = 0 return ret except dbusmanager.DBusException, e: - print "Caught exception %e" % str(e) + print "Caught exception %s" % str(e) if not hasattr(self, "__lost_dbus_count"): self.__lost_dbus_count = 0 if self.__lost_dbus_count > 3: - sys.exit(1) + mainloop.quit() self.__lost_dbus_count += 1 return True @@ -351,7 +351,7 @@ def main(): an amount of time determined by the active backend. """ - global monitor, to_time + global monitor, to_time, mainloop monitor = ConnectionStatus() to_time = daemon.GetBackendUpdateInterval() diff --git a/wicd/networking.py b/wicd/networking.py index 4f9b797..c308790 100644 --- a/wicd/networking.py +++ b/wicd/networking.py @@ -152,7 +152,7 @@ class Controller(object): self.disconnect_script = None self.driver = None self.iface = None - self.backend_manager = BackendManager() + self.backend_manager = BackendManager() def get_debug(self): return self._debug def set_debug(self, value): @@ -226,7 +226,7 @@ class Controller(object): self.iface.dhcp_object = None 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. @@ -999,3 +999,4 @@ class WiredConnectThread(ConnectThread): self.connect_result = "Success" self.is_connecting = False + diff --git a/wicd/wicd-client.py b/wicd/wicd-client.py index 85fcbae..e69c5fd 100755 --- a/wicd/wicd-client.py +++ b/wicd/wicd-client.py @@ -432,7 +432,7 @@ class TrayIcon(object): """ Determines which image to use for the wireless entries. """ def fix_strength(val, default): """ Assigns given strength to a default value if needed. """ - return val is not None and int(val) or default + return val and int(val) or default def get_prop(prop): return wireless.GetWirelessProperty(net_id, prop) diff --git a/wicd/wnettools.py b/wicd/wnettools.py index 1f462d4..2bfe775 100644 --- a/wicd/wnettools.py +++ b/wicd/wnettools.py @@ -34,21 +34,43 @@ class WirelessInterface() -- Control a wireless network interface. import os import re import random +import time from string import maketrans, translate import wpath import misc -from misc import find_path +from misc import find_path + +# Regular expressions. +__re_mode = (re.I | re.M | re.S) +essid_pattern = re.compile('.*ESSID:"?(.*?)"?\s*\n', __re_mode) +ap_mac_pattern = re.compile('.*Address: (.*?)\n', __re_mode) +channel_pattern = re.compile('.*Channel:? ?(\d\d?)', __re_mode) +strength_pattern = re.compile('.*Quality:?=? ?(\d+)\s*/?\s*(\d*)', __re_mode) +altstrength_pattern = re.compile('.*Signal level:?=? ?(\d\d*)', __re_mode) +signaldbm_pattern = re.compile('.*Signal level:?=? ?(-\d\d*)', __re_mode) +mode_pattern = re.compile('.*Mode:(.*?)\n', __re_mode) +freq_pattern = re.compile('.*Frequency:(.*?)\n', __re_mode) +wep_pattern = re.compile('.*Encryption key:(.*?)\n', __re_mode) +altwpa_pattern = re.compile('(wpa_ie)', __re_mode) +wpa1_pattern = re.compile('(WPA Version 1)', __re_mode) +wpa2_pattern = re.compile('(WPA2)', __re_mode) + +#iwconfig-only regular expressions. +ip_pattern = re.compile(r'inet [Aa]d?dr[^.]*:([^.]*\.[^.]*\.[^.]*\.[0-9]*)',re.S) +bssid_pattern = re.compile('.*Access Point: (([0-9A-Z]{2}:){5}[0-9A-Z]{2})', __re_mode) + +# Regular expressions for wpa_cli output +auth_pattern = re.compile('.*wpa_state=(.*?)\n', __re_mode) RALINK_DRIVER = 'ralink legacy' - blacklist_strict = '!"#$%&\'()*+,./:;<=>?@[\\]^`{|}~ ' blacklist_norm = ";`$!*|><&\\" blank_trans = maketrans("", "") __all__ = ["SetDNS", "GetDefaultGateway", "GetWiredInterfaces", - "GetWirelessInterfaces", "IsValidWpaSuppDriver", "NeedsExternalCalls"] + "GetWirelessInterfaces", "IsValidWpaSuppDriver"] def _sanitize_string(string): if string: @@ -135,7 +157,6 @@ def NeedsExternalCalls(): """ Returns True if the backend needs to use an external program. """ raise NotImplementedError - def IsValidWpaSuppDriver(driver): """ Returns True if given string is a valid wpa_supplicant driver. """ output = misc.Run(["wpa_supplicant", "-D%s" % driver, "-iolan19", @@ -161,6 +182,7 @@ class BaseInterface(object): self.DHCP_CLIENT = None self.flush_tool = None self.link_detect = None + self.dhcp_object = None def SetDebugMode(self, value): """ If True, verbose output is enabled. """ @@ -529,16 +551,46 @@ class BaseInterface(object): The IP address of the interface in dotted quad form. """ - raise NotImplementedError + if not ifconfig: + cmd = 'ifconfig ' + self.iface + if self.verbose: print cmd + output = misc.Run(cmd) + else: + output = ifconfig + return misc.RunRegex(ip_pattern, output) - def IsUp(self): + def IsUp(self, ifconfig=None): """ Determines if the interface is up. - + Returns: True if the interface is up, False otherwise. - + """ - raise NotImplementedError + if not self.iface: return False + flags_file = '/sys/class/net/%s/flags' % self.iface + try: + flags = open(flags_file, "r").read().strip() + except IOError: + print "Could not open %s, using ifconfig to determine status" % flags_file + return self._slow_is_up(ifconfig) + return bool(int(flags, 16) & 1) + + + def _slow_is_up(self, ifconfig=None): + """ Determine if an interface is up using ifconfig. """ + if not ifconfig: + cmd = "ifconfig " + self.iface + if self.verbose: print cmd + output = misc.Run(cmd) + else: + output = ifconfig + lines = output.split('\n') + if len(lines) < 5: + return False + for line in lines[1:4]: + if line.strip().startswith('UP'): + return True + return False class BaseWiredInterface(BaseInterface): @@ -555,17 +607,95 @@ class BaseWiredInterface(BaseInterface): def GetPluggedIn(self): """ Get the current physical connection state. - + The method will first attempt to use ethtool do determine 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 + # check for link using /sys/class/net/iface/carrier + # is usually more accurate + sys_device = '/sys/class/net/%s/' % self.iface + carrier_path = sys_device + 'carrier' + if not self.IsUp(): + MAX_TRIES = 3 + tries = 0 + self.Up() + while True: + tries += 1 + time.sleep(2) + if self.IsUp() or tries > MAX_TRIES: break + + if os.path.exists(carrier_path): + carrier = open(carrier_path, 'r') + try: + link = carrier.read().strip() + link = int(link) + if link == 1: + return True + elif link == 0: + return False + except (IOError, ValueError, TypeError): + print 'Error checking link using /sys/class/net/%s/carrier' % self.iface + + if self.ethtool_cmd and self.link_detect in [misc.ETHTOOL, misc.AUTO]: + return self._eth_get_plugged_in() + elif self.miitool_cmd and self.link_detect in [misc.MIITOOL, misc.AUTO]: + return self._mii_get_plugged_in() + else: + print ('Error: No way of checking for a wired connection. Make ' + + 'sure that either mii-tool or ethtool is installed.') + 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. """ - raise NotImplementedError - + cmd = "%s %s" % (self.ethtool_cmd, self.iface) + if not self.IsUp(): + print 'Wired Interface is down, putting it up' + self.Up() + time.sleep(6) + if self.verbose: print cmd + tool_data = misc.Run(cmd, include_stderr=True) + if misc.RunRegex(re.compile('(Link detected: yes)', re.I | re.M | re.S), + tool_data): + return True + else: + return False + + def _mii_get_plugged_in(self): + """ Use mii-tool to determine the physical connection state. + + Returns: + True if a link is detected, False otherwise. + + """ + cmd = "%s %s" % (self.miitool_cmd, self.iface) + if self.verbose: print cmd + tool_data = misc.Run(cmd, include_stderr=True) + if misc.RunRegex(re.compile('(Invalid argument)', re.I | re.M | re.S), + tool_data) is not None: + print 'Wired Interface is down, putting it up' + self.Up() + time.sleep(4) + if self.verbose: print cmd + tool_data = misc.Run(cmd, include_stderr=True) + + if misc.RunRegex(re.compile('(link ok)', re.I | re.M | re.S), + tool_data) is not None: + return True + else: + return False + class BaseWirelessInterface(BaseInterface): """ Control a wireless network interface. """ @@ -596,10 +726,6 @@ class BaseWirelessInterface(BaseInterface): if self.verbose: print str(cmd) misc.Run(cmd) - def StopWPA(self): - """ Stop wireless encryption. """ - raise NotImplementedError - def GetKillSwitchStatus(self): """ Determines if the wireless killswitch is enabled. @@ -823,10 +949,6 @@ class BaseWirelessInterface(BaseInterface): if self.verbose: print cmd misc.Run(cmd) - def ValidateAuthentication(self, auth_time): - """ Validate WPA authentication. """ - raise NotImplementedError - def _AuthenticateRalinkLegacy(self, network): """ Authenticate with the specified wireless network. @@ -866,9 +988,207 @@ class BaseWirelessInterface(BaseInterface): if self.verbose: print ' '.join(cmd) misc.Run(cmd) + def GetNetworks(self): + """ Get a list of available wireless networks. + + Returns: + A list containing available wireless networks. + + """ + cmd = 'iwlist ' + self.iface + ' scan' + if self.verbose: print cmd + results = misc.Run(cmd) + # Split the networks apart, using Cell as our split point + # this way we can look at only one network at a time. + # The spaces around ' Cell ' are to minimize the chance that someone + # has an essid named Cell... + networks = results.split( ' Cell ' ) + + # Get available network info from iwpriv get_site_survey + # if we're using a ralink card (needed to get encryption info) + if self.wpa_driver == RALINK_DRIVER: + ralink_info = self._GetRalinkInfo() + else: + ralink_info = None + + # An array for the access points + access_points = [] + for cell in networks: + # Only use sections where there is an ESSID. + if 'ESSID:' in cell: + # Add this network to the list of networks + entry = self._ParseAccessPoint(cell, ralink_info) + if entry is not None: + access_points.append(entry) + + return access_points + + def _ParseAccessPoint(self, cell, ralink_info): + """ Parse a single cell from the output of iwlist. + + Keyword arguments: + cell -- string containing the cell information + ralink_info -- string contating network information needed + for ralink cards. + + Returns: + A dictionary containing the cell networks properties. + + """ + + ap = {} + ap['essid'] = misc.RunRegex(essid_pattern, cell) + try: + ap['essid'] = misc.to_unicode(ap['essid']) + except (UnicodeDecodeError, UnicodeEncodeError): + print 'Unicode problem with current network essid, ignoring!!' + return None + if ap['essid'] in ['', ""]: + ap['hidden'] = True + ap['essid'] = "" + else: + ap['hidden'] = False + + # Channel - For cards that don't have a channel number, + # convert the frequency. + ap['channel'] = misc.RunRegex(channel_pattern, cell) + if ap['channel'] == None: + freq = misc.RunRegex(freq_pattern, cell) + ap['channel'] = self._FreqToChannel(freq) + + # BSSID + ap['bssid'] = misc.RunRegex(ap_mac_pattern, cell) + + # Mode + ap['mode'] = misc.RunRegex(mode_pattern, cell) + + # Break off here if we're using a ralink card + if self.wpa_driver == RALINK_DRIVER: + ap = self._ParseRalinkAccessPoint(ap, ralink_info, cell) + elif misc.RunRegex(wep_pattern, cell) == 'on': + # Encryption - Default to WEP + ap['encryption'] = True + ap['encryption_method'] = 'WEP' + + if misc.RunRegex(wpa1_pattern, cell) == 'WPA Version 1': + ap['encryption_method'] = 'WPA' + + if misc.RunRegex(altwpa_pattern, cell) == 'wpa_ie': + ap['encryption_method'] = 'WPA' + + if misc.RunRegex(wpa2_pattern, cell) == 'WPA2': + ap['encryption_method'] = 'WPA2' + else: + ap['encryption'] = False + + # Link Quality + # Set strength to -1 if the quality is not found + + # more of the patch from + # https://bugs.launchpad.net/wicd/+bug/175104 + if (strength_pattern.match(cell)): + [(strength, max_strength)] = strength_pattern.findall(cell) + if max_strength: + ap["quality"] = 100 * int(strength) // int(max_strength) + else: + ap["quality"] = int(strength) + elif misc.RunRegex(altstrength_pattern,cell): + ap['quality'] = misc.RunRegex(altstrength_pattern, cell) + else: + 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) + elif self.wpa_driver != RALINK_DRIVER: # This is already set for ralink + ap['strength'] = -1 + + return ap + + def ValidateAuthentication(self, auth_time): + """ Validate WPA authentication. + + Validate that the wpa_supplicant authentication + process was successful. + + NOTE: It's possible this could return False, + though in reality wpa_supplicant just isn't + finished yet. + + Keyword arguments: + auth_time -- The time at which authentication began. + + Returns: + True if wpa_supplicant authenticated succesfully, + False otherwise. + + """ + # Right now there's no way to do this for these drivers + if self.wpa_driver == RALINK_DRIVER or not self.wpa_cli_cmd: + return True + + MAX_TIME = 35 + MAX_DISCONNECTED_TIME = 3 + disconnected_time = 0 + while (time.time() - auth_time) < MAX_TIME: + cmd = '%s -i %s status' % (self.wpa_cli_cmd, self.iface) + output = misc.Run(cmd) + result = misc.RunRegex(auth_pattern, output) + if self.verbose: + print 'WPA_CLI RESULT IS', result + + if not result: + return False + if result == "COMPLETED": + return True + elif result == "DISCONNECTED": + disconnected_time += 1 + if disconnected_time > MAX_DISCONNECTED_TIME: + disconnected_time = 0 + # Force a rescan to get wpa_supplicant moving again. + self._ForceSupplicantScan() + MAX_TIME += 5 + else: + disconnected_time = 0 + time.sleep(1) + + print 'wpa_supplicant authentication may have failed.' + return False + + + def _ForceSupplicantScan(self): + """ Force wpa_supplicant to rescan available networks. + + This function forces wpa_supplicant to rescan. + This works around authentication validation sometimes failing for + wpa_supplicant because it remains in a DISCONNECTED state for + quite a while, after which a rescan is required, and then + attempting to authenticate. This whole process takes a long + time, so we manually speed it up if we see it happening. + + """ + print 'wpa_supplicant rescan forced...' + cmd = 'wpa_cli -i' + self.iface + ' scan' + misc.Run(cmd) + + def StopWPA(self): + """ Terminates wpa using wpa_cli""" + cmd = 'wpa_cli -i %s terminate' % self.iface + if self.verbose: print cmd + misc.Run(cmd) + def GetBSSID(self, iwconfig=None): """ Get the MAC address for the interface. """ - raise NotImplementedError + if not iwconfig: + cmd = 'iwconfig ' + self.iface + if self.verbose: print cmd + output = misc.Run(cmd) + else: + output = iwconfig + + bssid = misc.RunRegex(bssid_pattern, output) + return bssid def GetSignalStrength(self, iwconfig=None): """ Get the signal strength of the current network. @@ -877,7 +1197,28 @@ class BaseWirelessInterface(BaseInterface): The signal strength. """ - raise NotImplementedError + if not iwconfig: + cmd = 'iwconfig ' + self.iface + if self.verbose: print cmd + output = misc.Run(cmd) + else: + output = iwconfig + + strength_pattern = re.compile('.*Quality:?=? ?(\d+)\s*/?\s*(\d*)', + re.I | re.M | re.S) + altstrength_pattern = re.compile('.*Signal level:?=? ?(\d\d*)', re.I | re.M | re.S) + [(strength, max_strength)] = strength_pattern.findall(output) + if max_strength and strength: + if int(max_strength) != 0: + return 100 * int(strength) // int(max_strength) + else: + # Prevent a divide by zero error. + strength = int(strength) + + if strength is None: + strength = misc.RunRegex(altstrength_pattern, output) + + return strength def GetDBMStrength(self, iwconfig=None): """ Get the dBm signal strength of the current network. @@ -886,7 +1227,16 @@ class BaseWirelessInterface(BaseInterface): The dBm signal strength. """ - raise NotImplementedError + if not iwconfig: + cmd = 'iwconfig ' + self.iface + if self.verbose: print cmd + output = misc.Run(cmd) + else: + output = iwconfig + signaldbm_pattern = re.compile('.*Signal level:?=? ?(-\d\d*)', + re.I | re.M | re.S) + dbm_strength = misc.RunRegex(signaldbm_pattern, output) + return dbm_strength def GetCurrentNetwork(self, iwconfig=None): """ Get the essid of the current network. @@ -895,4 +1245,14 @@ class BaseWirelessInterface(BaseInterface): The current network essid. """ - raise NotImplementedError + if not iwconfig: + cmd = 'iwconfig ' + self.iface + if self.verbose: print cmd + output = misc.Run(cmd) + else: + output = iwconfig + network = misc.RunRegex(re.compile('.*ESSID:"(.*?)"', + re.I | re.M | re.S), output) + if network: + network = misc.to_unicode(network) + return network