diff --git a/wicd/__init__.py b/wicd/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/wicd/backend.py b/wicd/backend.py new file mode 100644 index 0000000..5221dda --- /dev/null +++ b/wicd/backend.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python + +""" Backend manager for wicd. + +Manages and loads the pluggable backends for wicd. + +""" + +# +# 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 sys +import os + +import wicd.wpath as wpath + + +class BackendManager(object): + def __init__(self): + """ Initialize the backend manager. """ + self.backend_dir = wpath.backends + self.__loaded_backend = None + + def _valid_backend_file(self, be_file): + """ Make sure the backend file is valid. """ + return (os.access(be_file, os.F_OK) and + os.path.basename(be_file).startswith("be-") and + be_file.endswith(".py")) + + def get_current_backend(self): + if self.__loaded_backend and not self.__loaded_backend is None: + return self.__loaded_backend.NAME + else: + return None + + def get_available_backends(self): + """ Returns a list of all valid backends in the backend directory. """ + be_list = [""] + for f in os.listdir(self.backend_dir): + if self._valid_backend_file(os.path.join(self.backend_dir, f)): + be_list.append(f[3:-3]) + return be_list + + def load_backend(self, backend_name): + """ Load and return a backend module. + + Given a backend name be-foo, attempt to load a python module + in the backends directory called be-foo.py. The module must + include a certain set of classes and variables to be considered + valid. + + """ + def fail(backend_name, reason): + print "Failed to load backend %s: %s" % (backend_name, reason) + + print 'trying to load backend %s' % backend_name + backend_path = os.path.join(self.backend_dir, + 'be-' + backend_name + '.py') + if self._valid_backend_file(backend_path): + sys.path.insert(0, self.backend_dir) + backend = __import__('be-' + backend_name) + else: + fail(backend_name, 'Invalid backend file.') + return None + + if not backend.NAME: + fail(backend_name, 'Missing NAME declaration.') + return None + + if not backend.WiredInterface: + fail(backend_name, "Missing WiredInterface class") + return None + + if not backend.WirelessInterface: + fail(backend_name, "Missing WirelessInterface class") + return None + + self.__loaded_backend = backend + print 'successfully loaded backend %s' % backend_name + return backend + diff --git a/wicd/backends/be-external.py b/wicd/backends/be-external.py new file mode 100644 index 0000000..b1c6fb8 --- /dev/null +++ b/wicd/backends/be-external.py @@ -0,0 +1,491 @@ +#!/usr/bin/env python + +""" Network interface control tools for wicd. + +This module implements functions to control and obtain information from +network interfaces. + +def SetDNS() -- Set the DNS servers of the system. +def GetWirelessInterfaces() -- Get the wireless interfaces available. +class Interface() -- Control a network interface. +class WiredInterface() -- Control a wired network interface. +class WirelessInterface() -- Control a wireless network interface. + +""" + +# +# 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 wicd.misc as misc +import wicd.wnettools as wnettools + +import re +import os +import wicd.wpath as wpath +import time + + +NAME = "external" +DESCRIPTION = """External app (slow) backend + +This backend uses external program calls like ifconfig and +iwconfig to query network information. This makes it a bit +slower and more CPU intensive than the ioctl backend, but +it doesn't require any thirdy 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:"(.*?)"\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' + + +def SetDNS(dns1=None, dns2=None, dns3=None): + return wnettools.SetDNS(dns1, dns2, dns3) + +def GetDefaultGateway(): + return wnettools.GetDefaultGateway() + +def StopDHCP(): + return wnettools.StopDHCP() + +def GetWirelessInterfaces(): + return wnettools.GetWirelessInterfaces() + +def GetWiredInterfaces(): + return wnettools.GetWiredInterfaces() + +def NeedsExternalCalls(): + return True + + +class Interface(wnettools.BaseInterface): + """ Control a network interface. """ + def __init__(self, iface, verbose=False): + """ Initialise the object. + + Keyword arguments: + iface -- the name of the interface + verbose -- whether to print every command run + + """ + 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 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. """ + def __init__(self, iface, verbose=False): + """ Initialise the wired network interface class. + + Keyword arguments: + iface -- name of the interface + verbose -- print all commands + + """ + 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 + if self.ETHTOOL_FOUND and self.link_detect != misc.MIITOOL: + return self._eth_get_plugged_in() + elif self.MIITOOL_FOUND: + 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. + + """ + link_tool = 'ethtool' + if not self.IsUp(): + print 'Wired Interface is down, putting it up' + self.Up() + time.sleep(6) + tool_data = misc.Run(link_tool + ' ' + self.iface, True) + if misc.RunRegex(re.compile('(Link detected: yes)', re.I | re.M | + re.S), tool_data) is not None: + 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. + + """ + 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), + tool_data) is not None: + print 'Wired Interface is down, putting it up' + self.Up() + time.sleep(4) + tool_data = misc.Run(link_tool + ' ' + self.iface, 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. """ + def __init__(self, iface, verbose=False, wpa_driver='wext'): + """ Initialise the wireless network interface class. + + Keyword arguments: + iface -- name of the interface + verbose -- print all commands + + """ + wnettools.BaseWirelessInterface.__init__(self, iface, verbose, + 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 = {} + # ESSID - Switch '' to 'Hidden' to remove + # brackets that can mix up formatting. + 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['essid'] = 'Hidden' + ap['hidden'] = True + 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_FOUND: + return True + + MAX_TIME = 15 + MAX_DISCONNECTED_TIME = 3 + while (time.time() - auth_time) < MAX_TIME: + cmd = 'wpa_cli -i ' + self.iface + ' status' + 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" and \ + (time.time() - auth_time) > MAX_DISCONNECTED_TIME: + # Force a rescan to get wpa_supplicant moving again. + self._ForceSupplicantScan() + MAX_TIME += 5 + 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 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: + return 100 * int(strength) // int(max_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 new file mode 100644 index 0000000..3b53db0 --- /dev/null +++ b/wicd/backends/be-ioctl.py @@ -0,0 +1,538 @@ +#!/usr/bin/env python + +""" ioctl Network interface control tools for wicd. + +This module implements functions to control and obtain information from +network interfaces. It utilizes ioctl calls and python modules to +obtain this information whenever possible. + +def SetDNS() -- Set the DNS servers of the system. +def GetWirelessInterfaces() -- Get the wireless interfaces available. +class Interface() -- Control a network interface. +class WiredInterface() -- Control a wired network interface. +class WirelessInterface() -- Control a wireless network interface. + +""" + +# +# 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 wicd.misc as misc +import wicd.wnettools as wnettools +import wicd.wpath as wpath + +import iwscan +import wpactrl + +import re +import os +import time +import socket +import fcntl +import struct +import array + + +NAME = "ioctl" +DESCRIPTION = """IOCTL (fast) backend + +This backend uses IOCTL calls and python libraries to query +network information whenever possible. This makes it fast, +but it may not work properly on all systems. + +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 +SIOCGIWESSID = 0x8B1B +SIOCGIWRANGE = 0x8B0B +SIOCGIWAP = 0x8B15 +SIOCGIWSTATS = 0x8B0F + +# Got these from /usr/include/sockios.h +SIOCGIFADDR = 0x8915 +SIOCGIFHWADDR = 0x8927 +SIOCGMIIPHY = 0x8947 +SIOCETHTOOL = 0x8946 +SIOCGIFFLAGS = 0x8913 + +def SetDNS(dns1=None, dns2=None, dns3=None): + return wnettools.SetDNS(dns1, dns2, dns3) + +def GetDefaultGateway(): + return wnettools.GetDefaultGateway() + +def StopDHCP(): + return wnettools.StopDHCP() + +def GetWirelessInterfaces(): + return wnettools.GetWirelessInterfaces() + +def GetWiredInterfaces(): + return wnettools.GetWiredInterfaces() + +def get_iw_ioctl_result(iface, call): + """ Makes the given ioctl call and returns the results. + + Keyword arguments: + call -- The ioctl call to make + + Returns: + The results of the ioctl call. + + """ + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + buff = array.array('c', '\0' * 32) + addr, length = buff.buffer_info() + arg = struct.pack('Pi', addr, length) + data = (iface + '\0' * 16)[:16] + arg + try: + result = fcntl.ioctl(s.fileno(), call, data) + except IOError: + return None + except OSError: + return None + return buff.tostring() + +def NeedsExternalCalls(): + return False + + +class Interface(wnettools.BaseInterface): + """ Control a network interface. """ + def __init__(self, iface, verbose=False): + """ Initialise the object. + + Keyword arguments: + iface -- the name of the interface + verbose -- whether to print every command run + + """ + wnettools.BaseInterface.__init__(self, iface, verbose) + self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + self.Check() + + def CheckWirelessTools(self): + """ Check for the existence needed wireless tools """ + # We don't need any external apps so just return + pass + + def GetIP(self, ifconfig=""): + """ Get the IP address of the interface. + + Returns: + The IP address of the interface in dotted quad form. + + """ + ifstruct = struct.pack('256s', self.iface) + try: + raw_ip = fcntl.ioctl(self.sock.fileno(), SIOCGIFADDR, ifstruct) + except IOError: + return None + except OSError: + return None + + return socket.inet_ntoa(raw_ip[20:24]) + + def IsUp(self): + """ Determines if the interface is up. + + Returns: + True if the interface is up, False otherwise. + + """ + if not self.iface: return False + data = (self.iface + '\0' * 16)[:18] + try: + result = fcntl.ioctl(self.sock.fileno(), SIOCGIFFLAGS, data) + except IOError, e: + if self.verbose: + print "SIOCGIFFLAGS failed: " + str(e) + return False + + flags, = struct.unpack('H', result[16:18]) + return bool(flags & 1) + + +class WiredInterface(Interface, wnettools.BaseWiredInterface): + """ Control a wired network interface. """ + def __init__(self, iface, verbose=False): + """ Initialise the wired network interface class. + + Keyword arguments: + iface -- name of the interface + verbose -- print all commands + + """ + 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 + if self.ETHTOOL_FOUND and self.link_detect != misc.MIITOOL: + return self._eth_get_plugged_in() + elif self.MIITOOL_FOUND: + 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. + + """ + if not self.IsUp(): + self.Up() + time.sleep(5) + buff = array.array('i', [0x0000000a, 0x00000000]) + addr, length = buff.buffer_info() + arg = struct.pack('Pi', addr, length) + data = (self.iface + '\0' * 16)[:16] + arg + try: + fcntl.ioctl(self.sock.fileno(), SIOCETHTOOL, data) + except IOError, e: + if self.verbose: + print 'SIOCETHTOOL failed: ' + str(e) + return False + return bool(buff.tolist()[1]) + + def _mii_get_plugged_in(self): + """ Use mii-tool to determine the physical connection state. + + Returns: + True if a link is detected, False otherwise. + + """ + if not self.IsUp(): + self.Up() + time.sleep(2.5) + buff = struct.pack('16shhhh', (self.iface + '\0' * 16)[:16], 0, 1, + 0x0004, 0) + try: + result = fcntl.ioctl(self.sock.fileno(), SIOCGMIIPHY, buff) + except IOError, e: + if self.verbose: + print 'SIOCGMIIPHY failed: ' + str(e) + return False + reg = struct.unpack('16shhhh', result)[-1] + return bool(reg & 0x0004) + + +class WirelessInterface(Interface, wnettools.BaseWirelessInterface): + """ Control a wireless network interface. """ + def __init__(self, iface, verbose=False, wpa_driver='wext'): + """ Initialise the wireless network interface class. + + Keyword arguments: + iface -- name of the interface + verbose -- print all commands + + """ + wnettools.BaseWirelessInterface.__init__(self, iface, verbose, + wpa_driver) + Interface.__init__(self, iface, verbose) + self.scan_iface = None + + def GetNetworks(self): + """ Get a list of available wireless networks. + + Returns: + A list containing available wireless networks. + + """ + if not self.scan_iface: + self.scan_iface = iwscan.WirelessInterface(self.iface) + results = self.scan_iface.Scan() + return [self._parse_ap(cell) for cell in results] + + def _parse_ap(self, cell): + """ Parse a single cell from the python-iwscan list. """ + ap = {} + try: + ap['essid'] = misc.to_unicode(cell['essid']) + except UnicodeError: + print 'Unicode problem with the current network essid, ignoring!!' + return None + + if ap['essid'] in [ "", '']: + ap['essid'] = 'Hidden' + ap['hidden'] = True + else: + ap['hidden'] = False + + ap["channel"] = True and cell["channel"] or \ + self._FreqToChannel(cell["frequency"]) + + ap["bssid"] = cell["bssid"] + ap["mode"] = cell["mode"] + + if cell["enc"]: + ap["encryption"] = True + if cell["ie"]: + if "WPA2" in cell['ie']['type'].upper(): + ap['encryption_method'] = 'WPA2' + elif "WPA" in cell['ie']['type'].upper(): + ap['encryption_method'] = 'WPA' + else: + ap['encryption_method'] = 'WEP' + else: + ap["encryption"] = False + + # Link Quality + ap['qual_found'] = True + try: + [(strength, max_strength)] = strength_pattern.findall(cell["stats"]) + if max_strength: + ap["quality"] = 100 * int(strength) // int(max_strength) + else: + ap["quality"] = int(strength) + except ValueError: + ap['quality'] = misc.RunRegex(altstrength_pattern,cell["stats"]) + if not ap['quality']: + ap['qual_found'] = False + 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["stats"]): + ap['strength'] = misc.RunRegex(signaldbm_pattern, cell["stats"]) + 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. + + """ + def error(): + print "Unable to find ctrl_interface for wpa_supplicant. " + \ + "Could not validate authentication." + + # Right now there's no way to do this for ralink drivers + if self.wpa_driver == RALINK_DRIVER: + return True + + 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() + return True + + wpa = wpactrl.WPACtrl(socket) + + MAX_TIME = 15 + MAX_DISCONNECTED_TIME = 3 + while (time.time() - auth_time) < MAX_TIME: + status = wpa.request("STATUS").split("\n") + if self.verbose: + print 'wpa_supplicant ctrl_interface status query is %s' % str(status) + + try: + [result] = [l for l in status if l.startswith("wpa_state=")] + except ValueError: + return False + + result = result + if result.endswith("COMPLETED"): + return True + elif result.endswith("DISCONNECTED") and \ + (time.time() - auth_time) > MAX_DISCONNECTED_TIME: + # Force a rescan to get wpa_supplicant moving again. + wpa.request("SCAN") + MAX_TIME += 5 + time.sleep(1) + + print 'wpa_supplicant authentication may have failed.' + return False + + def _AuthenticateRalinkLegacy(self, network): + """ Authenticate with the specified wireless network. + + This function handles Ralink legacy cards that cannot use + wpa_supplicant. + + Keyword arguments: + network -- dictionary containing network info + + """ + if network.get('key') != None: + lines = self._GetRalinkInfo() + for x in lines: + info = x.split() + if len(info) < 5: + break + if info[2] == network.get('essid'): + if info[5] == 'WEP' or (info[5] == 'OPEN' and \ + info[4] == 'WEP'): + print 'Setting up WEP' + cmd = ''.join(['iwconfig ', self.iface, ' key ', + network.get('key')]) + if self.verbose: print cmd + misc.Run(cmd) + else: + if info[5] == 'SHARED' and info[4] == 'WEP': + print 'Setting up WEP' + auth_mode = 'SHARED' + key_name = 'Key1' + elif info[5] == 'WPA-PSK': + print 'Setting up WPA-PSK' + auth_mode = 'WPAPSK' + key_name = 'WPAPSK' + elif info[5] == 'WPA2-PSK': + print 'Setting up WPA2-PSK' + auth_mode = 'WPA2PSK' + key_name = 'WPAPSK' + else: + print 'Unknown AuthMode, can\'t complete ' + \ + 'connection process!' + return + + cmd_list = [] + cmd_list.append('NetworkType=' + info[6]) + cmd_list.append('AuthMode=' + auth_mode) + cmd_list.append('EncrypType=' + info[4]) + cmd_list.append('SSID=' + info[2]) + cmd_list.append(key_name + '=' + network.get('key')) + if info[5] == 'SHARED' and info[4] == 'WEP': + cmd_list.append('DefaultKeyID=1') + cmd_list.append('SSID=' + info[2]) + + for cmd in cmd_list: + cmd = 'iwpriv ' + self.iface + ' ' + if self.verbose: print cmd + misc.Run(cmd) + + def GetBSSID(self): + """ Get the MAC address for the interface. """ + if not self.iface: return "" + data = (self.iface + '\0' * 32)[:32] + try: + result = fcntl.ioctl(self.sock.fileno(), SIOCGIWAP, data)[16:] + except IOError, e: + if self.verbose: + print "SIOCGIWAP failed: " + str(e) + return "" + raw_addr = struct.unpack("xxBBBBBB", result[:8]) + return "%02X:%02X:%02X:%02X:%02X:%02X" % raw_addr + + def GetSignalStrength(self, iwconfig=None): + """ Get the signal strength of the current network. + + Returns: + The signal strength. + + """ + if not self.iface: return -1 + buff = get_iw_ioctl_result(self.iface, SIOCGIWSTATS) + strength = ord(buff[2]) + max_strength = self._get_max_strength() + if strength and max_strength: + return 100 * int(strength) // int(max_strength) + + return strength + + def _get_max_strength(self): + """ Gets the maximum possible strength from the wireless driver. """ + buff = array.array('c', '\0' * 700) + addr, length = buff.buffer_info() + arg = struct.pack('Pi', addr, length) + iwfreq = (self.iface + '\0' * 16)[:16] + arg + try: + result = fcntl.ioctl(self.sock.fileno(), SIOCGIWRANGE, iwfreq) + except IOError, e: + if self.verbose: + print "SIOCGIWRANGE failed: " + str(e) + return None + # This defines the iwfreq struct, used to get signal strength. + fmt = "iiihb6ii4B4Bi32i2i2i2i2i3h8h2b2bhi8i2b3h2i2ihB17x" + 32 * "ihbb" + size = struct.calcsize(fmt) + data = buff.tostring() + data = data[0:size] + values = struct.unpack(fmt, data) + return values[12] + + def GetDBMStrength(self, iwconfig=None): + """ Get the dBm signal strength of the current network. + + Returns: + The dBm signal strength. + + """ + if not self.iface: return -100 + buff = misc.get_irwange_ioctl_result(self.iface, SIOCGIWSTATS) + if not buff: + return None + + return str((ord(buff[3]) - 256)) + + def GetCurrentNetwork(self, iwconfig=None): + """ Get the essid of the current network. + + Returns: + The current network essid. + + """ + if not self.iface: return "" + buff = get_iw_ioctl_result(self.iface, SIOCGIWESSID) + if not buff: + return None + + return buff.strip('\x00') + diff --git a/wicd/configmanager.py b/wicd/configmanager.py new file mode 100644 index 0000000..c049eae --- /dev/null +++ b/wicd/configmanager.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python + +""" Wicd Configuration Manager + +Wrapper around ConfigParser for wicd, though it should be +reusable for other purposes as well. + +""" + +# +# Copyright (C) 2007 Adam Blackburn +# Copyright (C) 2007 Dan O'Reilly +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License Version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +from ConfigParser import ConfigParser + +from wicd.misc import stringToNone + + +class ConfigManager(ConfigParser): + """ A class that can be used to manage a given configuration file. """ + def __init__(self, path): + ConfigParser.__init__(self) + self.config_file = path + self.read(path) + + def __repr__(self): + return self.config_file + + def __str__(self): + return self.config_file + + def get_config(self): + return self.config_file + + def set_option(self, section, option, value, save=False): + """ Wrapper around ConfigParser.set + + Adds the option to write the config file change right away. + + """ + if not self.has_section(section): + self.add_section(section) + + ConfigParser.set(self, section, str(option), str(value)) + if save: + self.write() + + def set(self, *args, **kargs): + self.set_option(*args, **kargs) + + def get_option(self, section, option, default=None): + """ Wrapper around ConfigParser.get. + + Automatically adds any missing sections, adds the ability + to write a default value, and if one is provided prints if + the default or a previously saved value is returned. + + """ + if not self.has_section(section): + self.add_section(section) + + if self.has_option(section, option): + ret = ConfigParser.get(self, section, option) + if default: + print ''.join(['found ', option, ' in configuration ', ret]) + else: + print ''.join(['did not find ', option, + ' in configuration, setting default ', str(default)]) + self.set(section, option, str(default), save=True) + ret = default + + # Try to intelligently handle the type of the return value. + try: + ret = int(ret) + except ValueError, TypeError: + ret = stringToNone(ret) + return ret + + def get(self, *args, **kargs): + return self.get_option(*args, **kargs) + + def write(self): + configfile = open(self.config_file, 'w') + ConfigParser.write(self, configfile) + configfile.close() + + def remove_section(self,section): + if self.has_section(section): + ConfigParser.remove_section(self, section) diff --git a/wicd/configscript.py b/wicd/configscript.py index 1a9b188..590eb74 100755 --- a/wicd/configscript.py +++ b/wicd/configscript.py @@ -58,7 +58,6 @@ except Exception: wireless = dbus.Interface(proxy_obj, 'org.wicd.daemon.wireless') wired = dbus.Interface(proxy_obj, 'org.wicd.daemon.wired') -config = dbus.Interface(proxy_obj, 'org.wicd.daemon.config') wireless_conf = wpath.etc + 'wireless-settings.conf' wired_conf = wpath.etc + 'wired-settings.conf' @@ -132,8 +131,8 @@ def write_scripts(network, network_type, script_info): con.set(network, "afterscript", script_info["post_entry"]) con.set(network, "disconnectscript", script_info["disconnect_entry"]) con.write(open(wired_conf, "w")) - config.ReadWiredNetworkProfile(network) - config.SaveWiredNetworkProfile(network) + wired.ReadWiredNetworkProfile(network) + wired.SaveWiredNetworkProfile(network) else: bssid = wireless.GetWirelessProperty(int(network), "bssid") con.read(wireless_conf) @@ -143,8 +142,8 @@ def write_scripts(network, network_type, script_info): con.set(bssid, "afterscript", script_info["post_entry"]) con.set(bssid, "disconnectscript", script_info["disconnect_entry"]) con.write(open(wireless_conf, "w")) - config.ReadWirelessNetworkProfile(int(network)) - config.SaveWirelessNetworkProfile(int(network)) + wireless.ReadWirelessNetworkProfile(int(network)) + wireless.SaveWirelessNetworkProfile(int(network)) def main (argv): """ Runs the script configuration dialog. """ @@ -157,7 +156,7 @@ def main (argv): script_info = get_script_info(network, network_type) - gladefile = wpath.etc + "wicd.glade" + gladefile = wpath.share + "wicd.glade" wTree = gtk.glade.XML(gladefile) dialog = wTree.get_widget("configure_script_dialog") wTree.get_widget("pre_label").set_label(language['before_script'] + ":") diff --git a/wicd/gui.py b/wicd/gui.py index 290f562..26e3801 100644 --- a/wicd/gui.py +++ b/wicd/gui.py @@ -34,9 +34,9 @@ import gtk.glade from dbus import DBusException from dbus import version as dbus_version -import wicd.misc -import wicd.wpath -from wicd.misc import noneToString, noneToBlankString, stringToBoolean, checkboxTextboxToggle +from wicd import misc +from wicd import wpath +from wicd.misc import noneToString from wicd.netentry import WiredNetworkEntry, WirelessNetworkEntry from wicd.prefs import PreferencesDialog from wicd.dbusmanager import DBusManager @@ -56,12 +56,11 @@ else: from dbus.mainloop.glib import DBusGMainLoop DBusGMainLoop(set_as_default=True) -proxy_obj, daemon, wireless, wired, bus, config = [None for x in - range(0, 6)] +proxy_obj, daemon, wireless, wired, bus = [None for x in range(0, 5)] language = misc.get_language_list_gui() def setup_dbus(dbus_man=None): - global bus, daemon, wireless, wired, config, dbus_manager + global bus, daemon, wireless, wired, dbus_manager if dbus_man: dbus_manager = dbus_man else: @@ -83,7 +82,6 @@ def setup_dbus(dbus_man=None): daemon = dbus_ifaces['daemon'] wireless = dbus_ifaces['wireless'] wired = dbus_ifaces['wired'] - config = dbus_ifaces['config'] return True @@ -94,6 +92,14 @@ def error(parent, message): dialog.set_markup(message) dialog.run() dialog.destroy() + +def alert(parent, message): + """ Shows an error dialog """ + dialog = gtk.MessageDialog(parent, gtk.DIALOG_MODAL, gtk.MESSAGE_WARNING, + gtk.BUTTONS_OK) + dialog.set_markup(message) + dialog.run() + dialog.destroy() ######################################## ##### GTK EXTENSION CLASSES @@ -202,7 +208,7 @@ class WiredProfileChooser: response = dialog.run() if response == 1: print 'reading profile ', wired_profiles.get_active_text() - config.ReadWiredNetworkProfile(wired_profiles.get_active_text()) + wired.ReadWiredNetworkProfile(wired_profiles.get_active_text()) wired.ConnectWired() else: if stoppopcheckbox.get_active(): @@ -217,10 +223,10 @@ class appGui(object): if not standalone: setup_dbus(dbus_man) - gladefile = "data/wicd.glade" + gladefile = wpath.share + "wicd.glade" self.wTree = gtk.glade.XML(gladefile) - dic = { "refresh_clicked" : self.refresh_networks, + dic = { "refresh_clicked" : self.refresh_clicked, "quit_clicked" : self.exit, "disconnect_clicked" : self.disconnect_all, "main_exit" : self.exit, @@ -258,7 +264,6 @@ class appGui(object): self.standalone = standalone self.wpadrivercombo = None self.connecting = False - self.fast = True # Use ioctl instead of external program calls self.prev_state = None self.refresh_networks(fresh=False) @@ -274,7 +279,7 @@ class appGui(object): else: self.wTree.get_widget("iface_menu_enable_wired").hide() - size = config.ReadWindowSize("main") + size = daemon.ReadWindowSize("main") width = size[0] height = size[1] if width > -1 and height > -1: @@ -449,7 +454,7 @@ class appGui(object): if not self.is_visible: return True - fast = self.fast + fast = not daemon.NeedsExternalCalls() wired_connecting = wired.CheckIfWiredConnecting() wireless_connecting = wireless.CheckIfWirelessConnecting() self.connecting = wired_connecting or wireless_connecting @@ -467,7 +472,7 @@ class appGui(object): iwconfig = wireless.GetIwconfig() else: iwconfig = '' - self.set_status(wireless.GetCurrentNetwork(iwconfig, fast) + ': ' + + self.set_status(wireless.GetCurrentNetwork(iwconfig) + ': ' + language[str(wireless.CheckWirelessConnectingMessage())]) if wired_connecting: self.set_status(language['wired_network'] + ': ' + @@ -484,14 +489,13 @@ class appGui(object): self.status_bar.remove(1, self.statusID) # Determine connection status. - if self.check_for_wired(wired.GetWiredIP(fast)): + if self.check_for_wired(wired.GetWiredIP("")): return True if not fast: iwconfig = wireless.GetIwconfig() else: iwconfig = '' - if self.check_for_wireless(iwconfig, - wireless.GetWirelessIP(fast)): + if self.check_for_wireless(iwconfig, wireless.GetWirelessIP("")): return True self.set_status(language['not_connected']) return True @@ -510,9 +514,10 @@ class appGui(object): def check_for_wired(self, wired_ip): """ Determine if wired is active, and if yes, set the status. """ - if wired_ip and wired.CheckPluggedIn(self.fast): - self.set_status(language['connected_to_wired'].replace('$A', - wired_ip)) + if wired_ip and wired.CheckPluggedIn(): + self.set_status( + language['connected_to_wired'].replace('$A',wired_ip) + ) return True else: return False @@ -522,15 +527,15 @@ class appGui(object): if not wireless_ip: return False - network = wireless.GetCurrentNetwork(iwconfig, self.fast) + network = wireless.GetCurrentNetwork(iwconfig) if not network: return False network = str(network) if daemon.GetSignalDisplayType() == 0: - strength = wireless.GetCurrentSignalStrength(iwconfig, self.fast) + strength = wireless.GetCurrentSignalStrength(iwconfig) else: - strength = wireless.GetCurrentDBMStrength(iwconfig, self.fast) + strength = wireless.GetCurrentDBMStrength(iwconfig) if strength is None: return False @@ -549,15 +554,19 @@ class appGui(object): def dbus_scan_finished(self): """ Calls for a non-fresh update of the gui window. - This method is called after the daemon runs an automatic - rescan. + This method is called after a wireless scan is completed. """ if not self.connecting: self.refresh_networks(fresh=False) def dbus_scan_started(self): + """ Called when a wireless scan starts. """ self.network_list.set_sensitive(False) + + def refresh_clicked(self, widget=None): + def dummy(x=None):pass + wireless.Scan(reply_handler=dummy, error_handler=dummy) def refresh_networks(self, widget=None, fresh=True, hidden=None): """ Refreshes the network list. @@ -579,7 +588,7 @@ class appGui(object): z.destroy() del z - if wired.CheckPluggedIn(self.fast) or wired.GetAlwaysShowWiredInterface(): + if wired.CheckPluggedIn() or daemon.GetAlwaysShowWiredInterface(): printLine = True # In this case we print a separator. wirednet = WiredNetworkEntry(dbus_manager.get_dbus_ifaces()) self.network_list.pack_start(wirednet, False, False) @@ -691,7 +700,7 @@ class appGui(object): entry.set_net_prop("dns1", '') entry.set_net_prop("dns2", '') entry.set_net_prop("dns3", '') - config.SaveWiredNetworkProfile(entry.prof_name) + wired.SaveWiredNetworkProfile(entry.prof_name) return True def save_wireless_settings(self, networkid, entry, netent): @@ -758,9 +767,9 @@ class appGui(object): entry.set_net_prop('use_settings_globally', True) else: entry.set_net_prop('use_settings_globally', False) - config.RemoveGlobalEssidEntry(networkid) + wireless.RemoveGlobalEssidEntry(networkid) - config.SaveWirelessNetworkProfile(networkid) + wireless.SaveWirelessNetworkProfile(networkid) return True def edit_advanced(self, widget, event, ttype, networkid, networkentry): @@ -864,7 +873,7 @@ class appGui(object): """ self.window.hide() [width, height] = self.window.get_size() - config.WriteWindowSize(width, height, "main") + daemon.WriteWindowSize(width, height, "main") if self.standalone: self.window.destroy() @@ -895,9 +904,9 @@ if __name__ == '__main__': setup_dbus() app = appGui(standalone=True) bus.add_signal_receiver(app.dbus_scan_finished, 'SendEndScanSignal', - 'org.wicd.daemon') + 'org.wicd.daemon.wireless') bus.add_signal_receiver(app.dbus_scan_started, 'SendStartScanSignal', - 'org.wicd.daemon') + 'org.wicd.daemon.wireless') bus.add_signal_receiver(app.update_connect_buttons, 'StatusChanged', - 'org.wicd.daemon') + 'org.wicd.daemon') gtk.main() diff --git a/wicd/logfile.py b/wicd/logfile.py index 1dd2622..df9cf7a 100644 --- a/wicd/logfile.py +++ b/wicd/logfile.py @@ -23,6 +23,8 @@ import sys import os import time +import wicd.wpath as wpath + class SizeError(IOError): pass @@ -89,6 +91,8 @@ class ManagedLog(object): """ def __init__(self, name, maxsize=360000, maxsave=3): + if not os.path.exists(os.path.dirname(name)): + os.makedirs(os.path.dirname(name)) self._lf = LogFile(name, "a", maxsize) self.maxsave = maxsave diff --git a/wicd/misc.py b/wicd/misc.py index 1fc10be..26ea78b 100644 --- a/wicd/misc.py +++ b/wicd/misc.py @@ -21,12 +21,12 @@ import os import locale import gettext import sys -from subprocess import Popen, STDOUT, PIPE -from copy import copy +from subprocess import Popen, STDOUT, PIPE, call import subprocess import commands -import wicd.wpath as wpath +# wicd imports +import wpath if __name__ == '__main__': wpath.chdir(__file__) @@ -76,8 +76,8 @@ def Run(cmd, include_stderr=False, return_pipe=False): else: err = None fds = False - - tmpenv = copy(os.environ) + + tmpenv = os.environ.copy() tmpenv["LC_ALL"] = "C" tmpenv["LANG"] = "C" f = Popen(cmd, shell=True, stdout=PIPE, stderr=err, close_fds=fds, @@ -89,11 +89,15 @@ def Run(cmd, include_stderr=False, return_pipe=False): return f.communicate()[0] def LaunchAndWait(cmd): - """ Launches the given program with the given arguments, then blocks. """ - subprocess.call(cmd) + """ Launches the given program with the given arguments, then blocks. + + cmd : A list contained the program name and its arguments. + + """ + call(cmd) def IsValidIP(ip): - """ Make sure an entered IP is valid """ + """ Make sure an entered IP is valid. """ if ip != None: if ip.count('.') == 3: ipNumbers = ip.split('.') @@ -167,7 +171,7 @@ def ParseEncryption(network): and creating a config file for it """ - enctemplate = open("encryption/templates/" + network["enctype"]) + 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" @@ -206,7 +210,7 @@ def LoadEncryptionMethods(): encryptionTypes = [] try: - enctypes = open("encryption/templates/active","r").readlines() + enctypes = open(wpath.encryption + "active","r").readlines() except IOError, e: print "Fatal Error: template index file is missing." raise IOError(e) @@ -215,7 +219,7 @@ def LoadEncryptionMethods(): for x in enctypes: x = x.strip() try: - f = open("encryption/templates/" + x, "r") + f = open(wpath.encryption + x, "r") except IOError: print 'Failed to load encryption type ' + str(x) continue @@ -424,6 +428,8 @@ def get_language_list_gui(): language["dhcp_client"] = _("DHCP Client") language["wired_detect"] = _("Wired Link Detection") language["route_flush"] = _("Route Table Flushing") + language["backend"] = _("Backend") + language["backend_alert"] = _("Changes to your backend won't occur until the daemon is restarted.") language['0'] = _('0') language['1'] = _('1') @@ -467,7 +473,7 @@ def get_language_list_tray(): language['connecting'] = _('Connecting') language['wired'] = _('Wired Network') language['scanning'] = _('Scanning') - + language['no_wireless_networks_found'] = _('No wireless networks found.') return language def noneToBlankString(text): diff --git a/wicd/monitor.py b/wicd/monitor.py index 25da3f3..f49a6bb 100755 --- a/wicd/monitor.py +++ b/wicd/monitor.py @@ -41,9 +41,14 @@ misc.RenameProcess("wicd-monitor") if __name__ == '__main__': wpath.chdir(__file__) -proxy_obj = dbus.SystemBus().get_object('org.wicd.daemon', '/org/wicd/daemon') +bus = dbus.SystemBus() +proxy_obj = bus.get_object('org.wicd.daemon', '/org/wicd/daemon') daemon = dbus.Interface(proxy_obj, 'org.wicd.daemon') + +proxy_obj = bus.get_object('org.wicd.daemon', '/org/wicd/daemon/wired') wired = dbus.Interface(proxy_obj, 'org.wicd.daemon.wired') + +proxy_obj = bus.get_object('org.wicd.daemon', '/org/wicd/daemon/wireless') wireless = dbus.Interface(proxy_obj, 'org.wicd.daemon.wireless') class ConnectionStatus(object): @@ -61,9 +66,6 @@ class ConnectionStatus(object): self.reconnect_tries = 0 self.last_reconnect_time = time.time() self.signal_changed = False - - # This determines if we use ioctl or external programs - self.fast = True self.iwconfig = "" def check_for_wired_connection(self, wired_ip): @@ -74,7 +76,7 @@ class ConnectionStatus(object): """ - if wired_ip and wired.CheckPluggedIn(self.fast): + 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()) @@ -96,26 +98,15 @@ class ConnectionStatus(object): # Make sure we have an IP before we do anything else. if wireless_ip is None: return False - - if self.fast: - self.iwconfig = '' - else: + + if daemon.NeedsExternalCalls(): self.iwconfig = wireless.GetIwconfig() + else: + self.iwconfig = '' # 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, - self.fast)) - else: - wifi_signal = int(wireless.GetCurrentDBMStrength(self.iwconfig, - self.fast)) - except: - wifi_signal = 0 - + wifi_signal = self._get_printable_sig_strength() 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), @@ -123,6 +114,7 @@ class ConnectionStatus(object): self.connection_lost_counter += 1 print self.connection_lost_counter if self.connection_lost_counter >= 4: + wireless.DisconnectWireless() self.connection_lost_counter = 0 return False else: # If we have a signal, reset the counter @@ -131,8 +123,7 @@ class ConnectionStatus(object): # Only update if the signal strength has changed because doing I/O # calls is expensive, and the icon flickers. if (wifi_signal != self.last_strength or - self.network != wireless.GetCurrentNetwork(self.iwconfig, - self.fast)): + self.network != wireless.GetCurrentNetwork(self.iwconfig)): self.last_strength = wifi_signal self.signal_changed = True daemon.SetCurrentInterface(daemon.GetWirelessInterface()) @@ -159,15 +150,14 @@ class ConnectionStatus(object): # Determine what our current state is. # Check for wired. - wired_ip = wired.GetWiredIP(self.fast) + 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.fast) - #self.iwconfig = wireless.GetIwconfig() + wifi_ip = wireless.GetWirelessIP("") self.signal_changed = False wireless_found = self.check_for_wireless_connection(wifi_ip) if wireless_found: @@ -194,7 +184,6 @@ class ConnectionStatus(object): """ Set the current connection state. """ # Set our connection state/info. iwconfig = self.iwconfig - fast = self.fast if state == misc.NOT_CONNECTED: info = [""] elif state == misc.SUSPENDED: @@ -203,12 +192,12 @@ class ConnectionStatus(object): if wired.CheckIfWiredConnecting(): info = ["wired"] else: - info = ["wireless", wireless.GetCurrentNetwork(iwconfig, fast)] + info = ["wireless", wireless.GetCurrentNetwork(iwconfig)] elif state == misc.WIRELESS: self.reconnect_tries = 0 - info = [wifi_ip, wireless.GetCurrentNetwork(iwconfig, fast), - str(wireless.GetPrintableSignalStrength(iwconfig, fast)), - str(wireless.GetCurrentNetworkID(iwconfig, fast))] + info = [wifi_ip, wireless.GetCurrentNetwork(iwconfig), + str(self._get_printable_sig_strength()), + str(wireless.GetCurrentNetworkID(iwconfig))] elif state == misc.WIRED: self.reconnect_tries = 0 info = [wired_ip] @@ -223,6 +212,18 @@ class ConnectionStatus(object): daemon.EmitStatusChanged(state, info) self.last_state = state return True + + def _get_printable_sig_strength(self): + """ Get the correct signal strength format. """ + try: + if daemon.GetSignalDisplayType() == 0: + wifi_signal = int(wireless.GetCurrentSignalStrength(self.iwconfig)) + else: + wifi_signal = int(wireless.GetCurrentDBMStrength(self.iwconfig)) + except TypeError: + wifi_signal = 0 + + return wifi_signal def auto_reconnect(self, from_wireless=None): """ Automatically reconnects to a network if needed. @@ -250,7 +251,7 @@ class ConnectionStatus(object): # If we just lost a wireless connection, try to connect to that # network again. Otherwise just call Autoconnect. - cur_net_id = wireless.GetCurrentNetworkID(self.iwconfig, self.fast) + cur_net_id = wireless.GetCurrentNetworkID(self.iwconfig) if from_wireless and cur_net_id > -1: print 'Trying to reconnect to last used wireless ' + \ 'network' @@ -278,7 +279,6 @@ def reply_handle(): def err_handle(error): """ Just a dummy function needed for asynchronous dbus calls. """ pass - def main(): """ Starts the connection monitor. @@ -289,8 +289,7 @@ def main(): """ monitor = ConnectionStatus() - gobject.timeout_add(2000, monitor.update_connection_status) - #gobject.timeout_add(120000, monitor.rescan_networks) + gobject.timeout_add(2500, monitor.update_connection_status) mainloop = gobject.MainLoop() mainloop.run() diff --git a/wicd/netentry.py b/wicd/netentry.py index d0fece6..57ff513 100644 --- a/wicd/netentry.py +++ b/wicd/netentry.py @@ -16,15 +16,18 @@ # import gtk +import os -import wicd.misc as misc -from wicd.misc import noneToString, stringToNone, noneToBlankString, stringToBoolean -import wicd.wpath as wpath +import misc +from misc import noneToString, stringToNone, noneToBlankString, stringToBoolean +import wpath language = misc.get_language_list_gui() # These get set when a NetworkEntry is instantiated. -daemon, wireless, wired, vpn_session, config = [None for x in range(0, 5)] +daemon = None +wired = None +wireless = None def error(parent, message): """ Shows an error dialog """ @@ -219,7 +222,7 @@ class AdvancedSettingsDialog(gtk.Dialog): self.txt_dns_2.set_sensitive(not self.chkbox_global_dns.get_active()) self.txt_dns_3.set_sensitive(not self.chkbox_global_dns.get_active()) - def destroy_called(self): + def destroy_called(self, *args): """ Clean up everything. This might look excessive, but it was the only way to prevent @@ -264,7 +267,7 @@ class WiredSettingsDialog(AdvancedSettingsDialog): """ Helper method to fetch and format wired properties. """ return noneToBlankString(wired.GetWiredProperty(label)) - def destroy_called(self): + def destroy_called(self, *args): """ Clean up everything. This might look excessive, but it was the only way to prevent @@ -326,7 +329,7 @@ class WirelessSettingsDialog(AdvancedSettingsDialog): self.combo_encryption.connect("changed", self.change_encrypt_method) self.des = self.connect("destroy", self.destroy_called) - def destroy_called(self): + def destroy_called(self, *args): """ Clean up everything. This might look excessive, but it was the only way to prevent @@ -435,11 +438,10 @@ class NetworkEntry(gtk.HBox): WirelessNetworkEntry classes. """ - global daemon, wired, wireless, config + global daemon, wired, wireless daemon = dbus_ifaces["daemon"] wired = dbus_ifaces["wired"] wireless = dbus_ifaces["wireless"] - config = dbus_ifaces["config"] gtk.HBox.__init__(self, False, 2) self.expander = gtk.Expander() self.image = gtk.Image() @@ -541,7 +543,7 @@ class WiredNetworkEntry(NetworkEntry): # Build the profile list. self.combo_profile_names = gtk.combo_box_entry_new_text() - self.profile_list = config.GetWiredProfileList() + self.profile_list = wired.GetWiredProfileList() if self.profile_list: for x in self.profile_list: self.combo_profile_names.append_text(x) @@ -582,7 +584,7 @@ class WiredNetworkEntry(NetworkEntry): # Display the default profile if it exists. if self.profile_list is not None: - prof = config.GetDefaultWiredNetwork() + prof = wired.GetDefaultWiredNetwork() if prof != None: # Make sure the default profile gets displayed. i = 0 while self.combo_profile_names.get_active_text() != prof: @@ -624,22 +626,26 @@ class WiredNetworkEntry(NetworkEntry): def edit_scripts(self, widget=None, event=None): """ Launch the script editting dialog. """ profile = self.combo_profile_names.get_active_text() - try: - sudo_prog = misc.choose_sudo_prog() - msg = "You must enter your password to configure scripts" - if sudo_prog.endswith("gksu") or sudo_prog.endswith("ktsuss"): - msg_flag = "-m" - else: - msg_flag = "--caption" - misc.LaunchAndWait([sudo_prog, msg_flag, msg, "./configscript.py", - profile, "wired"]) - except misc.WicdError: - error("Could not find a graphical sudo program." + \ - " Script editor could not be launched.") + if os.getuid() != 0: + try: + sudo_prog = misc.choose_sudo_prog() + msg = "You must enter your password to configure scripts" + if sudo_prog.endswith("gksu") or sudo_prog.endswith("ktsuss"): + msg_flag = "-m" + else: + msg_flag = "--caption" + misc.LaunchAndWait([sudo_prog, msg_flag, msg, + wpath.lib + "configscript.py", profile, + "wired"]) + except misc.WicdError: + error(None, "Could not find a graphical sudo program." + \ + " Script editor could not be launched.") + else: + misc.LaunchAndWait([wpath.lib + "configscript.py", profile, "wired"]) def check_enable(self): """ Disable objects if the profile list is empty. """ - profile_list = config.GetWiredProfileList() + profile_list = wired.GetWiredProfileList() if profile_list == None: self.button_delete.set_sensitive(False) self.connect_button.set_sensitive(False) @@ -659,13 +665,13 @@ class WiredNetworkEntry(NetworkEntry): """ Add a profile to the profile list. """ print "adding profile" profile_name = self.combo_profile_names.get_active_text() - profile_list = config.GetWiredProfileList() + profile_list = wired.GetWiredProfileList() if profile_list: if profile_name in profile_list: return False if profile_name != "": self.profile_help.hide() - config.CreateWiredNetworkProfile(profile_name) + wired.CreateWiredNetworkProfile(profile_name) self.combo_profile_names.prepend_text(profile_name) self.combo_profile_names.set_active(0) self.advanced_dialog.prof_name = profile_name @@ -679,12 +685,12 @@ class WiredNetworkEntry(NetworkEntry): """ Remove a profile from the profile list. """ print "removing profile" profile_name = self.combo_profile_names.get_active_text() - config.DeleteWiredNetworkProfile(profile_name) + wired.DeleteWiredNetworkProfile(profile_name) self.combo_profile_names.remove_text(self.combo_profile_names. get_active()) self.combo_profile_names.set_active(0) self.advanced_dialog.prof_name = self.combo_profile_names.get_active_text() - if not config.GetWiredProfileList(): + if not wired.GetWiredProfileList(): self.profile_help.show() entry = self.combo_profile_names.child entry.set_text("") @@ -700,10 +706,10 @@ class WiredNetworkEntry(NetworkEntry): """ Change the default profile. """ if self.chkbox_default_profile.get_active(): # Make sure there is only one default profile at a time - config.UnsetWiredDefault() + wired.UnsetWiredDefault() wired.SetWiredProperty("default", self.chkbox_default_profile.get_active()) - config.SaveWiredNetworkProfile(self.combo_profile_names.get_active_text()) + wired.SaveWiredNetworkProfile(self.combo_profile_names.get_active_text()) def change_profile(self, widget): """ Called when a new profile is chosen from the list. """ @@ -713,7 +719,7 @@ class WiredNetworkEntry(NetworkEntry): return profile_name = self.combo_profile_names.get_active_text() - config.ReadWiredNetworkProfile(profile_name) + wired.ReadWiredNetworkProfile(profile_name) self.advanced_dialog.txt_ip.set_text(self.format_entry("ip")) self.advanced_dialog.txt_netmask.set_text(self.format_entry("netmask")) @@ -906,22 +912,27 @@ class WirelessNetworkEntry(NetworkEntry): def edit_scripts(self, widget=None, event=None): """ Launch the script editting dialog. """ - try: - sudo_prog = misc.choose_sudo_prog() - msg = "You must enter your password to configure scripts" - if sudo_prog.endswith("gksu") or sudo_prog.endswith("ktsuss"): - msg_flag = "-m" - else: - msg_flag = "--caption" - misc.LaunchAndWait([sudo_prog, msg_flag, msg, "./configscript.py", - str(self.networkID), "wireless"]) - except IOError: - error("Could not find a graphical sudo program." + \ - " Script editor could no be launched.") + if os.getuid() != 0: + try: + sudo_prog = misc.choose_sudo_prog() + msg = "You must enter your password to configure scripts" + if sudo_prog.endswith("gksu") or sudo_prog.endswith("ktsuss"): + msg_flag = "-m" + else: + msg_flag = "--caption" + misc.LaunchAndWait([sudo_prog, msg_flag, msg, + wpath.lib + "configscript.py", + str(self.networkID), "wireless"]) + except IOError: + error(None, "Could not find a graphical sudo program." + \ + " Script editor could no be launched.") + else: + misc.LaunchAndWait(["./configscript.py", str(self.networkID), + "wireless"]) def update_autoconnect(self, widget=None): """ Called when the autoconnect checkbox is toggled. """ wireless.SetWirelessProperty(self.networkID, "automatic", noneToString(self.chkbox_autoconnect. get_active())) - config.SaveWirelessNetworkProperty(self.networkID, "automatic") + wireless.SaveWirelessNetworkProperty(self.networkID, "automatic") diff --git a/wicd/networking.py b/wicd/networking.py index 9d67c4e..1783fd2 100644 --- a/wicd/networking.py +++ b/wicd/networking.py @@ -42,18 +42,33 @@ class WiredConnectThread() -- Connection thread for wired # import re +import time import threading import thread -import time -import wicd.misc as misc -import wicd.wnettools as wnettools -import wicd.wpath as wpath +# wicd imports +import misc +import wpath +from backend import BackendManager if __name__ == '__main__': wpath.chdir(__file__) +BACKEND = None +BACKEND_MGR = BackendManager() +def get_backend_list(): + if not BACKEND_MGR: + return [""] + else: + return BACKEND_MGR.get_available_backends() + +def get_current_backend(): + if not BACKEND_MGR: + return None + else: + return BACKEND_MGR.get_current_backend() + class Controller(object): """ Parent class for the different interface types. """ def __init__(self): @@ -66,6 +81,7 @@ class Controller(object): self._dhcp_client = None self._flush_tool = None self._debug = None + self._backend = None self.connecting_thread = None self.before_script = None self.after_script = None @@ -73,6 +89,7 @@ class Controller(object): self.driver = None self.wiface = None self.liface = None + self.backend_manager = BackendManager() def set_wireless_iface(self, value): self._wireless_interface = value @@ -127,6 +144,21 @@ class Controller(object): debug = property(get_debug, set_debug) flush_tool = property(get_flush_tool, set_flush_tool) dhcp_client = property(get_dhcp_client, set_dhcp_client) + + def LoadBackend(self, backend_name): + """ Load the given networking backend. """ + global BACKEND + if backend_name == self._backend: + return + self._backend = BACKEND_MGR.load_backend(backend_name) + BACKEND = self._backend + + def NeedsExternalCalls(self): + """ Returns true if the loaded backend needs external calls. """ + if self._backend: + return self._backend.NeedsExternalCalls() + else: + return True class ConnectThread(threading.Thread): @@ -169,7 +201,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._should_die = False self.abort_reason = "" self.global_dns_1 = gdns1 @@ -183,6 +215,15 @@ class ConnectThread(threading.Thread): self.debug = debug self.SetStatus('interface_down') + + def get_should_die(self): + return self._should_die + + def set_should_die(self, val): + self.lock.acquire() + self._should_die = val + + should_die = property(should_die, get_should_die, set_should_die) def SetStatus(self, status): @@ -286,14 +327,15 @@ class ConnectThread(threading.Thread): """ if self.network.get('use_global_dns'): - wnettools.SetDNS(misc.Noneify(self.global_dns_1), + BACKEND.SetDNS(misc.Noneify(self.global_dns_1), misc.Noneify(self.global_dns_2), misc.Noneify(self.global_dns_3)) elif self.network.get('use_static_dns') and (self.network.get('dns1') or self.network.get('dns2') or self.network.get('dns3')): self.SetStatus('setting_static_dns') - wnettools.SetDNS(self.network.get('dns1'), self.network.get('dns2'), - self.network.get('dns3')) + BACKEND.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. @@ -325,13 +367,18 @@ class ConnectThread(threading.Thread): """ Stop and running DHCP clients, as well as wpa_supplicant. """ print 'Stopping wpa_supplicant and any DHCP clients' iface.StopWPA() - wnettools.StopDHCP() + BACKEND.StopDHCP() def abort_if_needed(self): """ Abort the thread is it has been requested. """ - if self.should_die: - self.connect_aborted('aborted') - thread.exit() + self.lock.acquire() + try: + if self._should_die: + self.connect_aborted('aborted') + self.lock.release() + thread.exit() + finally: + self.lock.release() def put_iface_up(self, iface): """ Bring up given interface. """ @@ -347,8 +394,6 @@ class Wireless(Controller): """ Initialize the class. """ Controller.__init__(self) self._wpa_driver = None - self.wiface = wnettools.WirelessInterface(self.wireless_interface, - self.debug, self.wpa_driver) def set_wpa_driver(self, value): self._wpa_driver = value @@ -359,13 +404,11 @@ class Wireless(Controller): wpa_driver = property(get_wpa_driver, set_wpa_driver) - - #def LoadInterfaces(self, dhcp_client, flush_tool): - # """ Load the wnettools controls for the wired/wireless interfaces. """ - # #self.wiface = wnettools.WirelessInterface(self.wireless_interface, - # # self.debug, self.wpa_driver) - # self.dhcp_client = dhcp_client - # self.flush_tool = flush_tool + def LoadBackend(self, backend): + Controller.LoadBackend(self, backend) + if self._backend: + self.wiface = self._backend.WirelessInterface(self.wireless_interface, + self.debug, self.wpa_driver) def Scan(self, essid=None): """ Scan for available wireless networks. @@ -431,43 +474,43 @@ class Wireless(Controller): self.connecting_thread.start() return True - def GetSignalStrength(self, iwconfig=None, fast=False): + def GetSignalStrength(self, iwconfig=""): """ Get signal strength of the current network. Returns: The current signal strength. """ - return self.wiface.GetSignalStrength(iwconfig, fast) + return self.wiface.GetSignalStrength(iwconfig) - def GetDBMStrength(self, iwconfig=None, fast=False): + def GetDBMStrength(self, iwconfig=""): """ Get the dBm signal strength of the current network. Returns: The current dBm signal strength. """ - return self.wiface.GetDBMStrength(iwconfig, fast) + return self.wiface.GetDBMStrength(iwconfig) - def GetCurrentNetwork(self, iwconfig=None, fast=False): + def GetCurrentNetwork(self, iwconfig=""): """ Get current network name. Returns: The name of the currently connected network. """ - return self.wiface.GetCurrentNetwork(iwconfig, fast) + return self.wiface.GetCurrentNetwork(iwconfig) - def GetIP(self, fast=False): + def GetIP(self, ifconfig=""): """ Get the IP of the interface. Returns: The IP address of the interface in dotted notation. """ - return self.wiface.GetIP(fast) + return self.wiface.GetIP(ifconfig) - def GetBSSID(self, fast=True): + def GetBSSID(self): """ Get the BSSID of the current access point. Returns: @@ -475,7 +518,7 @@ class Wireless(Controller): None the BSSID can't be found. """ - return self.wiface.GetBSSID(fast) + return self.wiface.GetBSSID() def GetIwconfig(self): """ Get the out of iwconfig. """ @@ -507,7 +550,7 @@ class Wireless(Controller): wiface = self.wiface print 'Creating ad-hoc network' print 'Killing dhclient and wpa_supplicant' - wnettools.StopDHCP() + BACKEND.StopDHCP() wiface.StopWPA() print 'Putting wireless interface down' wiface.Down() @@ -556,7 +599,7 @@ class Wireless(Controller): The first available wireless interface. """ - return wnettools.GetWirelessInterfaces() + return BACKEND.GetWirelessInterfaces() def GetKillSwitchStatus(self): """ Get the current status of the Killswitch. @@ -645,7 +688,6 @@ class WirelessConnectThread(ConnectThread): wiface = self.wiface liface = self.liface self.is_connecting = True - self.is_fast = True # Run pre-connection script. self.abort_if_needed() @@ -684,8 +726,7 @@ class WirelessConnectThread(ConnectThread): # Validate Authentication. if self.network.get('enctype'): self.SetStatus('validating_authentication') - if not wiface.ValidateAuthentication(time.time(), - fast=self.is_fast): + if not wiface.ValidateAuthentication(time.time()): self.abort_connection('bad_pass') self.abort_if_needed() @@ -702,7 +743,7 @@ class WirelessConnectThread(ConnectThread): self.SetStatus('done') print 'Connecting thread exiting.' if self.debug: - print "IP Address is: " + str(wiface.GetIP(fast=self.is_fast)) + print "IP Address is: " + str(wiface.GetIP()) self.is_connecting = False def generate_psk_and_authenticate(self, wiface): @@ -756,7 +797,6 @@ class Wired(Controller): Controller.__init__(self) self.wpa_driver = None self._link_detect = None - self.liface = wnettools.WiredInterface(self.wired_interface, self.debug) def set_link_detect(self, value): self._link_detect = value @@ -766,22 +806,22 @@ class Wired(Controller): def get_link_detect(self): return self._link_detect link_detect = property(get_link_detect, set_link_detect) - - #def LoadInterfaces(self, dhcp_client, link_tool, flush_tool): - # """ Load the wnettools controls for the wired/wireless interfaces. """ - # #self.liface = wnettools.WiredInterface(self.wired_interface, self.debug) - # self.dhcp_client = dhcp_client - # self.link_detect = link_tool - # self.flush_tool = flush_tool + + def LoadBackend(self, backend): + """ Load the backend up. """ + Controller.LoadBackend(self, backend) + if self._backend: + self.liface = self._backend.WiredInterface(self.wired_interface, + self.debug) - def CheckPluggedIn(self, fast=False): + def CheckPluggedIn(self): """ Check whether the wired connection is plugged in. Returns: The status of the physical connection link. """ - return self.liface.GetPluggedIn(fast) + return self.liface.GetPluggedIn() def Connect(self, network, debug=False): """ Spawn a connection thread to connect to the network. @@ -804,18 +844,18 @@ class Wired(Controller): def DetectWiredInterface(self): """ Attempts to automatically detect a wired interface. """ try: - return wnettools.GetWiredInterfaces()[0] + return BACKEND.GetWiredInterfaces()[0] except IndexError: return None - def GetIP(self, fast=False): + def GetIP(self, ifconfig=""): """ Get the IP of the interface. Returns: The IP address of the interface in dotted notation. """ - return self.liface.GetIP(fast) + return self.liface.GetIP(ifconfig) def Disconnect(self): """ Disconnect from the network. """ @@ -903,8 +943,6 @@ class WiredConnectThread(ConnectThread): liface = self.liface self.is_connecting = True - #TODO pass is_fast in. - self.is_fast = True # Run pre-connection script. self.abort_if_needed() @@ -936,5 +974,5 @@ class WiredConnectThread(ConnectThread): self.SetStatus('done') print 'Connecting thread exiting.' if self.debug: - print "IP Address is: " + str(liface.GetIP(fast=self.is_fast)) + print "IP Address is: " + str(liface.GetIP()) self.is_connecting = False diff --git a/wicd/prefs.py b/wicd/prefs.py index f472470..57834ec 100644 --- a/wicd/prefs.py +++ b/wicd/prefs.py @@ -27,23 +27,22 @@ import gtk import gobject import pango -import wicd.misc +from wicd import misc +from wicd import gui from wicd.misc import checkboxTextboxToggle, noneToBlankString daemon = None wireless = None wired = None -config = None language = misc.get_language_list_gui() class PreferencesDialog(object): def __init__(self, wTree, dbus): - global daemon, wireless, wired, config + global daemon, wireless, wired daemon = dbus['daemon'] wireless = dbus['wireless'] wired = dbus['wired'] - config = dbus['config'] self.wTree = wTree self.prep_settings_diag() self.build_preferences_diag() @@ -68,7 +67,7 @@ class PreferencesDialog(object): self.dialog = self.wTree.get_widget("pref_dialog") self.dialog.set_title(language['preferences']) - size = config.ReadWindowSize("pref") + size = daemon.ReadWindowSize("pref") width = size[0] height = size[1] if width > -1 and height > -1: @@ -76,7 +75,7 @@ class PreferencesDialog(object): self.wiredcheckbox = setup_label("pref_always_check", 'wired_always_on') - self.wiredcheckbox.set_active(wired.GetAlwaysShowWiredInterface()) + self.wiredcheckbox.set_active(daemon.GetAlwaysShowWiredInterface()) self.reconnectcheckbox = setup_label("pref_auto_check", 'auto_reconnect') self.reconnectcheckbox.set_active(daemon.GetAutoReconnect()) @@ -180,6 +179,25 @@ class PreferencesDialog(object): self.dns1Entry.set_sensitive(False) self.dns2Entry.set_sensitive(False) self.dns3Entry.set_sensitive(False) + + # Load backend combobox + self.backendcombo = build_combobox("pref_backend_combobox") + self.backends = daemon.GetBackendList() + # "" is included as a hack for DBus limitations, so we remove it. + self.backends.remove("") + found = False + cur_backend = daemon.GetSavedBackend() + for i, x in enumerate(self.backends): + if x == cur_backend: + found = True + backend_index = i + self.backendcombo.remove_text(i) + self.backendcombo.append_text(x) + + if found: + self.backendcombo.set_active(backend_index) + else: + self.backendcombo.set_active(0) self.wTree.get_widget("notebook2").set_current_page(0) @@ -199,10 +217,10 @@ class PreferencesDialog(object): daemon.SetWirelessInterface(self.entryWirelessInterface.get_text()) daemon.SetWiredInterface(self.entryWiredInterface.get_text()) daemon.SetWPADriver(self.wpadrivers[self.wpadrivercombo.get_active()]) - wired.SetAlwaysShowWiredInterface(self.wiredcheckbox.get_active()) + daemon.SetAlwaysShowWiredInterface(self.wiredcheckbox.get_active()) daemon.SetAutoReconnect(self.reconnectcheckbox.get_active()) daemon.SetDebugMode(self.debugmodecheckbox.get_active()) - daemon.SetSignalDisplayType(self.displaytypecheckbox.get_active()) + wireless.SetSignalDisplayType(self.displaytypecheckbox.get_active()) if self.showlistradiobutton.get_active(): wired.SetWiredAutoConnectMethod(2) elif self.lastusedradiobutton.get_active(): @@ -210,6 +228,10 @@ class PreferencesDialog(object): else: wired.SetWiredAutoConnectMethod(1) + if self.backends[self.backendcombo.get_active()] != daemon.GetSavedBackend(): + gui.alert(self.dialog, language["backend_alert"]) + daemon.SetBackend(self.backends[self.backendcombo.get_active()]) + # External Programs Tab if self.dhcpautoradio.get_active(): dhcp_client = misc.AUTO @@ -238,7 +260,7 @@ class PreferencesDialog(object): daemon.SetFlushTool(flush_tool) [width, height] = self.dialog.get_size() - config.WriteWindowSize(width, height, "pref") + daemon.WriteWindowSize(width, height, "pref") def set_label(self, glade_str, label): """ Sets the label for the given widget in wicd.glade. """ @@ -252,6 +274,7 @@ class PreferencesDialog(object): self.wTree.get_widget("dhcp_client_label").set_label(language["dhcp_client"]) self.wTree.get_widget("wired_detect_label").set_label(language["wired_detect"]) self.wTree.get_widget("route_flush_label").set_label(language["route_flush"]) + self.wTree.get_widget("pref_backend_label").set_label(language["backend"] + ":") entryWiredAutoMethod = self.wTree.get_widget("pref_wired_auto_label") entryWiredAutoMethod.set_label('Wired Autoconnect Setting:') diff --git a/wicd/wicd.py b/wicd/wicd-client.py similarity index 89% rename from wicd/wicd.py rename to wicd/wicd-client.py index f116fd2..2a460af 100755 --- a/wicd/wicd.py +++ b/wicd/wicd-client.py @@ -42,13 +42,14 @@ import gobject import getopt import os import pango +import time from dbus import DBusException from dbus import version as dbus_version # Wicd specific imports -import wicd.wpath as wpath -import wicd.misc as misc -import wicd.gui as gui +from wicd import wpath +from wicd import misc +from wicd import gui from wicd.dbusmanager import DBusManager # Import egg.trayicon if we're using an older gtk version @@ -78,7 +79,6 @@ daemon = None wireless = None wired = None wired = None -config = None language = misc.get_language_list_tray() @@ -203,7 +203,7 @@ class TrayIcon: if self.animate: prefix = self.get_bandwidth_state() else: - prefix = '' + prefix = 'idle-' if daemon.GetSignalDisplayType() == 0: if wireless_signal > 75: signal_img = "high-signal" @@ -298,7 +298,7 @@ class TrayIcon: return (active, max_gain, last_bytes) - class TrayIconGUI: + class TrayIconGUI(object): """ Base Tray Icon UI class. Implements methods and variables used by both egg/StatusIcon @@ -336,16 +336,24 @@ class TrayIcon: props.parent) self.gui_win = None self.current_icon_path = None - self.dbus_available = True self.use_tray = use_tray - + self._is_scanning = False + net_menuitem = self.manager.get_widget("/Menubar/Menu/Connect/") + net_menuitem.connect("activate", self.on_net_menu_activate) + + def tray_scan_started(self): + """ Callback for when a wireless scan is started. """ + self._is_scanning = True + self.init_network_menu() + + def tray_scan_ended(self): + """ Callback for when a wireless scan finishes. """ + self._is_scanning = False + self.populate_network_menu() + def on_activate(self, data=None): """ Opens the wicd GUI. """ - try: - self.toggle_wicd_gui() - except dbus.DBusException: - self.dbus_available = False - gui.error(None, "Could not connect to wicd daemon. Unable to load GUI") + self.toggle_wicd_gui() def on_quit(self, widget=None): """ Closes the tray icon. """ @@ -361,8 +369,8 @@ class TrayIcon: dialog.run() dialog.destroy() - def _add_item_to_menu(self, net_menu, lbl, type_, - n_id, is_connecting, is_active): + def _add_item_to_menu(self, net_menu, lbl, type_, n_id, is_connecting, + is_active): """ Add an item to the network list submenu. """ def network_selected(widget, net_type, net_id): """ Callback method for a menu item selection. """ @@ -423,6 +431,29 @@ class TrayIcon: signal_img = 'signal-25.png' return wpath.images + signal_img + def on_net_menu_activate(self, item): + """ Trigger a background scan to populate the network menu. + + Called when the network submenu is moused over. We + sleep briefly, clear pending gtk events, and if + we're still being moused over we trigger a scan. + This is to prevent scans when the user is just + mousing past the menu to select another menu item. + + """ + def dummy(x=None): pass + + if self._is_scanning: + return True + + self.init_network_menu() + time.sleep(.4) + while gtk.events_pending(): + gtk.main_iteration() + if item.state != gtk.STATE_PRELIGHT: + return True + wireless.Scan(reply_handler=dummy, error_handler=dummy) + def populate_network_menu(self, data=None): """ Populates the network list submenu. """ def get_prop(net_id, prop): @@ -436,14 +467,14 @@ class TrayIcon: num_networks = wireless.GetNumberOfNetworks() [status, info] = daemon.GetConnectionStatus() - if wired.GetAlwaysShowWiredInterface() or \ - wired.CheckPluggedIn(True): + if daemon.GetAlwaysShowWiredInterface() or \ + wired.CheckPluggedIn(): if status == misc.WIRED: is_active = True else: is_active = False - self._add_item_to_menu(submenu, "Wired Network", "__wired__", - 0, is_connecting, is_active) + self._add_item_to_menu(submenu, "Wired Network", "__wired__", 0, + is_connecting, is_active) sep = gtk.SeparatorMenuItem() submenu.append(sep) sep.show() @@ -457,10 +488,16 @@ class TrayIcon: is_active = False self._add_item_to_menu(submenu, essid, "wifi", x, is_connecting, is_active) + else: + no_nets_item = gtk.MenuItem(language['no_wireless_networks_found']) + no_nets_item.set_sensitive(False) + no_nets_item.show() + submenu.append(no_nets_item) net_menuitem.show() def init_network_menu(self): + """ Set the right-click menu for to the scanning state. """ net_menuitem = self.manager.get_widget("/Menubar/Menu/Connect/") submenu = net_menuitem.get_submenu() self._clear_menu(submenu) @@ -469,10 +506,10 @@ class TrayIcon: loading_item.set_sensitive(False) loading_item.show() submenu.append(loading_item) - #net_menuitem.set_submenu(net_menu) net_menuitem.show() def _clear_menu(self, menu): + """ Clear the right-click menu. """ for item in menu.get_children(): menu.remove(item) item.destroy() @@ -483,11 +520,11 @@ class TrayIcon: self.gui_win = gui.appGui(dbus_manager) bus = dbus_manager.get_bus() bus.add_signal_receiver(self.gui_win.dbus_scan_finished, - 'SendEndScanSignal', - 'org.wicd.daemon') + 'SendEndScanSignal', + 'org.wicd.daemon.wireless') bus.add_signal_receiver(self.gui_win.dbus_scan_started, 'SendStartScanSignal', - 'org.wicd.daemon') + 'org.wicd.daemon.wireless') bus.add_signal_receiver(self.gui_win.update_connect_buttons, 'StatusChanged', 'org.wicd.daemon') elif not self.gui_win.is_visible: @@ -530,7 +567,7 @@ class TrayIcon: if event.button == 1: self.toggle_wicd_gui() elif event.button == 3: - self.populate_network_menu() + self.init_network_menu() self.menu.popup(None, None, None, event.button, event.time) def set_from_file(self, val=None): @@ -574,8 +611,6 @@ class TrayIcon: def on_popup_menu(self, status, button, timestamp): """ Opens the right click menu for the tray icon. """ self.init_network_menu() - wireless.Scan(reply_handler=self.populate_network_menu, - error_handler=lambda x: x) self.menu.popup(None, None, None, button, timestamp) def set_from_file(self, path = None): @@ -599,7 +634,7 @@ Arguments: """ def setup_dbus(): - global bus, daemon, wireless, wired, config, dbus_manager + global bus, daemon, wireless, wired, dbus_manager dbus_manager = DBusManager() try: @@ -617,7 +652,6 @@ def setup_dbus(): daemon = dbus_ifaces['daemon'] wireless = dbus_ifaces['wireless'] wired = dbus_ifaces['wired'] - config = dbus_ifaces['config'] return True def main(argv): @@ -674,23 +708,13 @@ def main(argv): 'LaunchChooser', 'org.wicd.daemon') bus.add_signal_receiver(tray_icon.icon_info.update_tray_icon, 'StatusChanged', 'org.wicd.daemon') + bus.add_signal_receiver(tray_icon.tr.tray_scan_ended, 'SendEndScanSignal', + 'org.wicd.daemon.wireless') + bus.add_signal_receiver(tray_icon.tr.tray_scan_started, + 'SendStartScanSignal', 'org.wicd.daemon.wireless') print 'Done.' - - while 1: - mainloop = gobject.MainLoop() - try: - mainloop.run() - except DBusException: - print 'Warning. Caught a D-Bus exception! Connection to daemon lost.' - print 'Trying to reconnect...' - sleep(10) - try: - setup_dbus() - except: - pass - - - + mainloop = gobject.MainLoop() + mainloop.run() if __name__ == '__main__': diff --git a/wicd/daemon.py b/wicd/wicd-daemon.py similarity index 72% rename from wicd/daemon.py rename to wicd/wicd-daemon.py index c3b24a6..58e585e 100644 --- a/wicd/daemon.py +++ b/wicd/wicd-daemon.py @@ -17,9 +17,9 @@ def main() -- The wicd daemon main loop. """ # -# Copyright (C) 2007 Adam Blackburn -# Copyright (C) 2007 Dan O'Reilly -# Copyright (C) 2007 Byron Hillis +# Copyright (C) 2007 - 2008 Adam Blackburn +# Copyright (C) 2007 - 2008 Dan O'Reilly +# Copyright (C) 2007 - 2008 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 @@ -52,28 +52,29 @@ else: DBusGMainLoop(set_as_default=True) # wicd specific libraries -import wicd.wpath as wpath -import wicd.networking as networking -import wicd.misc as misc +from wicd import wpath +from wicd import networking +from wicd import misc from wicd.logfile import ManagedStdio +from wicd.configmanager import ConfigManager if __name__ == '__main__': wpath.chdir(__file__) -misc.RenameProcess("wicd-daemon") +misc.RenameProcess("wicd") -class ConnectionWizard(dbus.service.Object): - def __init__(self, bus_name, object_path='/org/wicd/daemon', +class WicdDaemon(dbus.service.Object): + def __init__(self, bus_name, object_path="/org/wicd/daemon", auto_connect=True): - dbus.service.Object.__init__(self, bus_name, object_path) - - self.app_conf = wpath.etc + 'manager-settings.conf' - self.wireless_conf = wpath.etc + 'wireless-settings.conf' - self.wired_conf = wpath.etc + 'wired-settings.conf' - self.hidden_essid = None + dbus.service.Object.__init__(self, bus_name=bus_name, + object_path=object_path) self.wifi = networking.Wireless() self.wired = networking.Wired() + self.config = ConfigManager(wpath.etc + "manager-settings.conf") + self.wired_bus= WiredDaemon(bus_name, wired=self.wired, wifi=self.wifi) + self.wireless_bus = WirelessDaemon(bus_name, wired=self.wired, + wifi=self.wifi) self.forced_disconnect = False self.need_profile_chooser = False self.current_interface = None @@ -107,13 +108,10 @@ class ConnectionWizard(dbus.service.Object): print "autoconnecting...", str(self.GetWirelessInterface()) self.AutoConnect(True) else: - self.Scan() + self.wireless_bus.Scan() #self.SetForcedDisconnect(True) print "--no-scan detected, not autoconnecting..." - - ########## DAEMON FUNCTIONS - ################################# - + @dbus.service.method('org.wicd.daemon') def Hello(self): """ Returns the version number. @@ -124,8 +122,7 @@ class ConnectionWizard(dbus.service.Object): anything >= 0. This number is effective starting wicd v1.2.0. """ - version = '1.5.0' - print 'returned version number', version + version = '1.6.0' return version @dbus.service.method('org.wicd.daemon') @@ -134,7 +131,7 @@ class ConnectionWizard(dbus.service.Object): print "setting wired interface %s" % (str(interface)) self.wired.wired_interface = interface self.wifi.wired_interface = interface - self.set_option("Settings", "wired_interface", interface) + self.config.set("Settings", "wired_interface", interface, True) @dbus.service.method('org.wicd.daemon') def SetWirelessInterface(self, interface): @@ -142,21 +139,21 @@ class ConnectionWizard(dbus.service.Object): print "setting wireless interface %s" % (str(interface)) self.wifi.wireless_interface = interface self.wired.wireless_interface = interface - self.set_option("Settings", "wireless_interface", interface) + self.config.set("Settings", "wireless_interface", interface, True) @dbus.service.method('org.wicd.daemon') def SetWPADriver(self, driver): """ Sets the wpa driver the wpa_supplicant will use. """ print "setting wpa driver", str(driver) self.wifi.wpa_driver = driver - self.set_option("Settings", "wpa_driver", driver) + self.config.set("Settings", "wpa_driver", driver, True) @dbus.service.method('org.wicd.daemon') def SetUseGlobalDNS(self, use): """ Sets a boolean which determines if global DNS is enabled. """ print 'setting use global dns to', use use = misc.to_bool(use) - self.set_option("Settings", "use_global_dns", use) + self.config.set("Settings", "use_global_dns", use, True) self.use_global_dns = use self.wifi.use_global_dns = use self.wired.use_global_dns = use @@ -165,19 +162,44 @@ class ConnectionWizard(dbus.service.Object): def SetGlobalDNS(self, dns1=None, dns2=None, dns3=None): """ Sets the global dns addresses. """ print "setting global dns" - self.set_option("Settings", "global_dns_1", misc.noneToString(dns1)) + self.config.set("Settings", "global_dns_1", misc.noneToString(dns1), True) self.dns1 = dns1 self.wifi.global_dns_1 = dns1 self.wired.global_dns_1 = dns1 - self.set_option("Settings", "global_dns_2", misc.noneToString(dns2)) + self.config.set("Settings", "global_dns_2", misc.noneToString(dns2), True) self.dns2 = dns2 self.wifi.global_dns_2 = dns2 self.wired.global_dns_2 = dns2 - self.set_option("Settings", "global_dns_3", misc.noneToString(dns3)) + self.config.set("Settings", "global_dns_3", misc.noneToString(dns3), True) self.dns3 = dns3 self.wifi.global_dns_3 = dns3 self.wired.global_dns_3 = dns3 print 'global dns servers are', dns1, dns2, dns3 + + @dbus.service.method('org.wicd.daemon') + def SetBackend(self, backend): + """ Sets a new backend. """ + print "setting backend to %s" % backend + self.config.set("Settings", "backend", backend, True) + if self.GetCurrentBackend(): + return + self.wifi.LoadBackend(backend) + self.wired.LoadBackend(backend) + + @dbus.service.method('org.wicd.daemon') + def GetCurrentBackend(self): + """ Returns the currently loaded backend. """ + return networking.get_current_backend() + + @dbus.service.method('org.wicd.daemon') + def GetSavedBackend(self): + """ Returns the backend saved to disk. """ + return self.config.get("Settings", "backend") + + @dbus.service.method('org.wicd.daemon') + def GetBackendList(self): + """ Returns a list of all backends available. """ + return networking.get_backend_list() @dbus.service.method('org.wicd.daemon') def GetUseGlobalDNS(self): @@ -198,14 +220,26 @@ class ConnectionWizard(dbus.service.Object): def GetWirelessInterface(self): """ Returns the wireless interface the daemon is using. """ return str(self.wifi.wireless_interface) + + @dbus.service.method('org.wicd.daemon') + def NeedsExternalCalls(self): + """ Returns true if the loaded backend needs external calls. """ + if self.wifi: + return self.wifi.NeedsExternalCalls() + elif self.wired: + return self.wired.NeedsExternalCalls() + else: + return True @dbus.service.method('org.wicd.daemon') def SetDebugMode(self, debug): """ Sets if debugging mode is on or off. """ - self.set_option("Settings", "debug_mode", debug) + self.config.set("Settings", "debug_mode", debug, True) self.debug_mode = misc.to_bool(debug) self.wifi.debug = self.debug_mode self.wired.debug = self.debug_mode + self.wireless_bus.debug_mode = debug + self.wired_bus.debug_mode = debug @dbus.service.method('org.wicd.daemon') def GetDebugMode(self): @@ -219,23 +253,6 @@ class ConnectionWizard(dbus.service.Object): self.wifi.Disconnect() self.wired.Disconnect() - @dbus.service.method('org.wicd.daemon') - def GetSignalDisplayType(self): - """ Returns the signal display type. - - Returns either 0 or 1. - 0 for signal strength as a percentage - 1 for signal strength measured in dBm - - """ - return int(self.signal_display_type) - - @dbus.service.method('org.wicd.daemon') - def SetSignalDisplayType(self, value): - """ Sets the signal display type and writes it the wicd config file. """ - self.set_option("Settings", "signal_display_type", value) - self.signal_display_type = int(value) - @dbus.service.method('org.wicd.daemon') def FormatSignalForPrinting(self, signal): """ Returns the suffix to display after the signal strength number. """ @@ -265,80 +282,11 @@ class ConnectionWizard(dbus.service.Object): """ if fresh: - self.Scan() - if self.CheckPluggedIn(True): - self._wired_autoconnect() + self.wireless_bus.Scan() + if self.wired_bus.CheckPluggedIn(): + self.wired_bus._wired_autoconnect() else: - self._wireless_autoconnect() - - def _wired_autoconnect(self): - """ Attempts to autoconnect to a wired network. """ - if self.GetWiredAutoConnectMethod() == 3 and \ - not self.GetNeedWiredProfileChooser(): - # attempt to smartly connect to a wired network - # by using various wireless networks detected - # and by using plugged in USB devices - print self.LastScan - if self.GetWiredAutoConnectMethod() == 2 and \ - not self.GetNeedWiredProfileChooser(): - self.LaunchChooser() - return - - # Default Profile. - elif self.GetWiredAutoConnectMethod() == 1: - network = self.GetDefaultWiredNetwork() - if not network: - print "Couldn't find a default wired connection," + \ - " wired autoconnect failed." - self._wireless_autoconnect() - return - - # Last-Used. - else: - network = self.GetLastUsedWiredNetwork() - if not network: - print "no previous wired profile available, wired " + \ - "autoconnect failed." - self._wireless_autoconnect() - return - - self.ReadWiredNetworkProfile(network) - self.ConnectWired() - print "Attempting to autoconnect with wired interface..." - self.auto_connecting = True - time.sleep(1.5) - gobject.timeout_add(3000, self._monitor_wired_autoconnect) - - def _wireless_autoconnect(self): - """ Attempts to autoconnect to a wireless network. """ - print "No wired connection present, attempting to autoconnect" + \ - "to wireless network" - if self.GetWirelessInterface() is None: - print 'Autoconnect failed because wireless interface returned None' - return - - for x, network in enumerate(self.LastScan): - if bool(network["has_profile"]): - if self.debug_mode: - print network["essid"] + ' has profile' - if bool(network.get('automatic')): - print 'trying to automatically connect to...' + \ - network["essid"] - self.ConnectWireless(x) - time.sleep(1) - return - print "Unable to autoconnect, you'll have to manually connect" - - def _monitor_wired_autoconnect(self): - if self.CheckIfWiredConnecting(): - return True - elif self.GetWiredIP(): - self.auto_connecting = False - return False - elif not self.CheckIfWirelessConnecting(): - self._wireless_autoconnect() - self.auto_connecting = False - return False + self.wireless_bus._wireless_autoconnect() @dbus.service.method('org.wicd.daemon') def GetAutoReconnect(self): @@ -357,7 +305,7 @@ class ConnectionWizard(dbus.service.Object): """ print 'setting automatically reconnect when connection drops' - self.set_option("Settings", "auto_reconnect", misc.to_bool(value)) + self.config.set("Settings", "auto_reconnect", misc.to_bool(value), True) self.auto_reconnect = misc.to_bool(value) @dbus.service.method('org.wicd.daemon') @@ -369,7 +317,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() or self.CheckIfWirelessConnecting(): + if self.wired_bus.CheckIfWiredConnecting() or \ + self.wireless_bus.CheckIfWirelessConnecting(): return True else: return False @@ -418,7 +367,9 @@ class ConnectionWizard(dbus.service.Object): @dbus.service.method('org.wicd.daemon') def GetForcedDisconnect(self): """ Returns the forced_disconnect status. See SetForcedDisconnect. """ - return bool(self.forced_disconnect) + return (bool(self.forced_disconnect) or + bool(self.wireless_bus.GetForcedDisconnect()) or + bool(self.wired_bus.GetForcedDisconnect())) @dbus.service.method('org.wicd.daemon') def SetForcedDisconnect(self, value): @@ -430,6 +381,26 @@ class ConnectionWizard(dbus.service.Object): """ self.forced_disconnect = bool(value) + self.wireless_bus.SetForcedDisconnect(bool(value)) + self.wired_bus.SetForcedDisconnect(bool(value)) + + @dbus.service.method('org.wicd.daemon') + def GetSignalDisplayType(self): + """ Returns the signal display type. + + Returns either 0 or 1. + 0 for signal strength as a percentage + 1 for signal strength measured in dBm + + """ + return int(self.signal_display_type) + + + @dbus.service.method('org.wicd.daemon') + def SetSignalDisplayType(self, value): + """ Sets the signal display type and writes it the wicd config file. """ + self.config.set("Settings", "signal_display_type", value, True) + self.signal_display_type = int(value) @dbus.service.method('org.wicd.daemon') def GetGUIOpen(self): @@ -454,6 +425,18 @@ class ConnectionWizard(dbus.service.Object): """ Sets the value of gui_open. """ self.gui_open = bool(val) + @dbus.service.method('org.wicd.daemon') + def SetAlwaysShowWiredInterface(self, value): + """ Sets always_show_wired_interface to the given value. """ + self.config.set("Settings", "always_show_wired_interface", + misc.to_bool(value), True) + self.always_show_wired_interface = misc.to_bool(value) + + @dbus.service.method('org.wicd.daemon') + def GetAlwaysShowWiredInterface(self): + """ Returns always_show_wired_interface """ + return bool(self.always_show_wired_interface) + @dbus.service.method('org.wicd.daemon') def SetConnectionStatus(self, state, info): """ Sets the connection status. @@ -505,18 +488,17 @@ class ConnectionWizard(dbus.service.Object): self.dhcp_client = int(client) self.wifi.dhcp_client = int(client) self.wired.dhcp_client = int(client) - self.set_option("Settings", "dhcp_client", client) + self.config.set("Settings", "dhcp_client", client, True) @dbus.service.method('org.wicd.daemon') def GetLinkDetectionTool(self): return self.link_detect_tool - @dbus.service.method('org.wicd.daemon') def SetLinkDetectionTool(self, link_tool): self.link_detect_tool = int(link_tool) self.wired.link_tool = int(link_tool) - self.set_option("Settings", "link_detect_tool", link_tool) + self.config.set("Settings", "link_detect_tool", link_tool, True) @dbus.service.method('org.wicd.daemon') def GetFlushTool(self): @@ -527,7 +509,49 @@ class ConnectionWizard(dbus.service.Object): self.flush_tool = int(flush_tool) self.wired.flush_tool = int(flush_tool) self.wifi.flush_tool = int(flush_tool) - self.set_option("Settings", "flush_tool", flush_tool) + self.config.set("Settings", "flush_tool", flush_tool, True) + + @dbus.service.method('org.wicd.daemon') + def WriteWindowSize(self, width, height, win_name): + """Write the desired default window size""" + if win_name == "main": + height_str = "window_height" + width_str = "window_width" + else: + height_str = "pref_height" + width_str = "pref_width" + + self.config.set("Settings", width_str, width) + self.config.set("Settings", height_str, height) + self.config.write() + + @dbus.service.method('org.wicd.daemon') + def ReadWindowSize(self, win_name): + """Returns a list containing the desired default window size + + Attempts to read the default size from the config file, + and if that fails, returns a default of 605 x 400. + + """ + if win_name == "main": + default_width = 605 + default_height = 400 + width_str = "window_width" + height_str = "window_height" + else: + default_width = 125 + default_height = 500 + width_str = "pref_width" + height_str = "pref_height" + + width = self.config.get("Settings", width_str, default=default_width) + height = self.config.get("Settings", height_str, default=default_height) + self.config.write() + + size = [] + size.append(int(width)) + size.append(int(height)) + return size @dbus.service.signal(dbus_interface='org.wicd.daemon', signature='') def LaunchChooser(self): @@ -548,22 +572,106 @@ class ConnectionWizard(dbus.service.Object): """ pass - @dbus.service.method('org.wicd.daemon') - @dbus.service.signal(dbus_interface='org.wicd.daemon', signature='') - def SendStartScanSignal(self): - """ Emits a signal announcing a scan has started. """ - pass - + def __printReturn(self, text, value): + """prints the specified text and value, then returns the value""" + if self.debug_mode: + print ''.join([text, " ", str(value)]) + return value - @dbus.service.method('org.wicd.daemon') - @dbus.service.signal(dbus_interface='org.wicd.daemon', signature='') - def SendEndScanSignal(self): - """ Emits a signal announcing a scan has finished. """ - pass + def ReadConfig(self): + """ Reads the manager-settings.conf file. + + Reads the manager-settings.conf file and loads the stored + values into memory. + + """ + b_wired = self.wired_bus + b_wifi = self.wireless_bus + app_conf= self.config + verbose = True + # Load the backend. + be_def = 'external' + self.SetBackend(app_conf.get("Settings", "backend", default=be_def)) + + # Load network interfaces. + iface = self.wireless_bus.DetectWirelessInterface() + if not iface: iface = 'wlan0' + self.SetWirelessInterface(app_conf.get("Settings", "wireless_interface", + default=iface)) + iface = self.wired_bus.DetectWiredInterface() + if not iface: iface = 'eth0' + self.SetWiredInterface(app_conf.get("Settings", "wired_interface", + default=iface)) + + self.SetWPADriver(app_conf.get("Settings", "wpa_driver", default="wext")) + self.SetAlwaysShowWiredInterface(app_conf.get("Settings", + "always_show_wired_interface", + default=False)) + self.SetUseGlobalDNS(app_conf.get("Settings", "use_global_dns", + default=False)) + dns1 = app_conf.get("Settings", "global_dns_1", default='None') + dns2 = app_conf.get("Settings", "global_dns_2", default='None') + dns3 = app_conf.get("Settings", "global_dns_3", default='None') + self.SetGlobalDNS(dns1, dns2, dns3) + self.SetAutoReconnect(app_conf.get("Settings", "auto_reconnect", + default=True)) + self.SetDebugMode(app_conf.get("Settings", "debug_mode", default=False)) + b_wired.SetWiredAutoConnectMethod(app_conf.get("Settings", + "wired_connect_mode", + default=1)) + self.SetSignalDisplayType(app_conf.get("Settings", + "signal_display_type", + default=0)) + self.SetDHCPClient(app_conf.get("Settings", "dhcp_client", default=0)) + self.SetLinkDetectionTool(app_conf.get("Settings", "link_detect_tool", + default=0)) + self.SetFlushTool(app_conf.get("Settings", "flush_tool", default=0)) + app_conf.write() - ########## WIRELESS FUNCTIONS - ################################# + if os.path.isfile(wireless_conf): + print "Wireless configuration file found..." + else: + print "Wireless configuration file not found, creating..." + open(wireless_conf, "w").close() + if os.path.isfile(wired_conf): + print "Wired configuration file found..." + else: + print "Wired configuration file not found, creating a default..." + # Create the file and a default profile + open(wired_conf, "w").close() + b_wired.CreateWiredNetworkProfile("wired-default", default=True) + + # Hide the files, so the keys aren't exposed. + print "chmoding configuration files 0600..." + os.chmod(app_conf.get_config(), 0600) + os.chmod(wireless_conf, 0600) + os.chmod(wired_conf, 0600) + + # Make root own them + print "chowning configuration files root:root..." + os.chown(app_conf.get_config(), 0, 0) + os.chown(wireless_conf, 0, 0) + os.chown(wired_conf, 0, 0) + + print "Using wireless interface..." + self.GetWirelessInterface() + print "Using wired interface..." + self.GetWiredInterface() + +############################## +###### Wireless Daemon ####### +############################## + +class WirelessDaemon(dbus.service.Object): + def __init__(self, bus_name, wired=None, wifi=None, debug=False): + dbus.service.Object.__init__(self, bus_name=bus_name, + object_path='/org/wicd/daemon/wireless') + self.hidden_essid = None + self.wired = wired + self.wifi = wifi + self.debug_mode = debug + self.forced_disconnect = False + self.config = ConfigManager(wpath.etc + "wireless-settings.conf") + @dbus.service.method('org.wicd.daemon.wireless') def SetHiddenNetworkESSID(self, essid): """ Sets the ESSID of a hidden network for use with Scan(). """ @@ -581,7 +689,7 @@ class ConnectionWizard(dbus.service.Object): print 'scanning start' self.SendStartScanSignal() time.sleep(.2) - scan = self.wifi.Scan(str(self.hidden_essid), fast=True) + scan = self.wifi.Scan(str(self.hidden_essid)) self.LastScan = scan if self.debug_mode: print 'scanning done' @@ -653,6 +761,22 @@ class ConnectionWizard(dbus.service.Object): """ Disconnects the wireless network. """ self.SetForcedDisconnect(True) self.wifi.Disconnect() + + @dbus.service.method('org.wicd.daemon.wireless') + def GetForcedDisconnect(self): + """ Returns the forced_disconnect status. See SetForcedDisconnect. """ + return bool(self.forced_disconnect) + + @dbus.service.method('org.wicd.daemon.wireless') + def SetForcedDisconnect(self, value): + """ Sets the forced_disconnect status. + + Set to True when a user manually disconnects or cancels a connection. + It gets set to False as soon as the connection process is manually + started. + + """ + self.forced_disconnect = bool(value) @dbus.service.method('org.wicd.daemon.wireless') def IsWirelessUp(self): @@ -660,48 +784,33 @@ class ConnectionWizard(dbus.service.Object): return self.wifi.IsUp() @dbus.service.method('org.wicd.daemon.wireless') - def GetPrintableSignalStrength(self, iwconfig=None, fast=False): - """ Assigns a signal strength appropriate for display - - This is used separately from the raw signal strength retrieving - functions as a way to simply the strength polling process for - the GUI and tray icon, by returning the strength that the user - has requested to be displayed in wicd preferences. - - """ - if self.GetSignalDisplayType() == 0: - return self.GetCurrentSignalStrength(iwconfig, fast) - else: - return self.GetCurrentDBMStrength(iwconfig, fast) - - @dbus.service.method('org.wicd.daemon.wireless') - def GetCurrentSignalStrength(self, iwconfig=None, fast=False): + def GetCurrentSignalStrength(self, iwconfig=None): """ Returns the current signal strength. """ try: - strength = int(self.wifi.GetSignalStrength(iwconfig, fast)) + strength = int(self.wifi.GetSignalStrength(iwconfig)) except: strength = 0 return strength @dbus.service.method('org.wicd.daemon.wireless') - def GetCurrentDBMStrength(self, iwconfig=None, fast=False): + def GetCurrentDBMStrength(self, iwconfig=None): """ Returns the current dbm signal strength. """ try: - dbm_strength = int(self.wifi.GetDBMStrength(iwconfig, fast)) + dbm_strength = int(self.wifi.GetDBMStrength(iwconfig)) except: dbm_strength = 0 return dbm_strength @dbus.service.method('org.wicd.daemon.wireless') - def GetCurrentNetwork(self, iwconfig=None, fast=False): + def GetCurrentNetwork(self, iwconfig=None): """ Returns the current network. """ - current_network = str(self.wifi.GetCurrentNetwork(iwconfig, fast)) + current_network = str(self.wifi.GetCurrentNetwork(iwconfig)) return current_network @dbus.service.method('org.wicd.daemon.wireless') - def GetCurrentNetworkID(self, iwconfig=None, fast=False): + def GetCurrentNetworkID(self, iwconfig=None): """ Returns the id of the current network, or -1 if its not found. """ - currentESSID = self.GetCurrentNetwork(iwconfig, fast) + currentESSID = self.GetCurrentNetwork(iwconfig) for x in xrange(0, len(self.LastScan)): if self.LastScan[x]['essid'] == currentESSID: return x @@ -744,11 +853,9 @@ class ConnectionWizard(dbus.service.Object): return False @dbus.service.method('org.wicd.daemon.wireless') - def GetWirelessIP(self, fast=False): + def GetWirelessIP(self, ifconfig=""): """ Returns the IP associated with the wireless interface. """ - ip = self.wifi.GetIP(fast) - #if self.debug_mode == 1: - #print 'returning wireless ip', ip + ip = self.wifi.GetIP(ifconfig) return ip @dbus.service.method('org.wicd.daemon.wireless') @@ -759,14 +866,147 @@ class ConnectionWizard(dbus.service.Object): return stat else: return False + + @dbus.service.method('org.wicd.daemon.wireless') + def ReadWirelessNetworkProfile(self, id): + """ Reads in wireless profile as the active network """ + cur_network = self.LastScan[id] + essid_key = "essid:" + cur_network["essid"] + bssid_key = cur_network["bssid"] + if self.debug_mode: + print bssid_key + + if self.config.get(essid_key, 'use_settings_globally'): + return self._read_wireless_profile(cur_network, essid_key) + elif self.config.has_section(bssid_key): + return self._read_wireless_profile(cur_network, bssid_key) + else: + cur_network["has_profile"] = False + return "500: Profile Not Found" + + def _read_wireless_profile(self, cur_network, section): + cur_network["has_profile"] = True - ########## WIRED FUNCTIONS - ################################# + # Read the essid because we be needing to name those hidden + # wireless networks now - but only read it if it is hidden. + if cur_network["hidden"]: + cur_network["essid"] = misc.Noneify(self.config.get(section, + "essid")) + for x in self.config.options(section): + if not cur_network.has_key(x) or x.endswith("script"): + cur_network[x] = misc.Noneify(self.config.get(section, x)) + for option in ['use_static_dns', 'use_global_dns', 'encryption', + 'use_settings_globally']: + cur_network[option] = bool(cur_network.get(option)) + return "100: Loaded Profile" + + @dbus.service.method('org.wicd.daemon.wireless') + def SaveWirelessNetworkProfile(self, id): + """ Writes a wireless profile to disk. """ + def write_script_ent(prof, script): + self.config.set(prof, script, None) + cur_network = self.LastScan[id] + bssid_key = cur_network["bssid"] + essid_key = "essid:" + cur_network["essid"] + + self.config.remove_section(bssid_key) + self.config.add_section(bssid_key) + + # We want to write the essid in addition to bssid + # sections if global settings are enabled. + if cur_network["use_settings_globally"]: + self.config.remove_section(essid_key) + self.config.add_section(essid_key) + + for x in cur_network: + self.config.set(bssid_key, x, cur_network[x]) + if cur_network["use_settings_globally"]: + self.config.set(essid_key, x, cur_network[x]) + + write_script_ent(bssid_key, "beforescript") + write_script_ent(bssid_key, "afterscript") + write_script_ent(bssid_key, "disconnect") + + if cur_network["use_settings_globally"]: + write_script_ent(essid_key, "beforescript") + write_script_ent(essid_key, "afterscript") + write_script_ent(essid_key, "disconnect") + + self.config.write() + + @dbus.service.method('org.wicd.daemon.wireless') + def SaveWirelessNetworkProperty(self, id, option): + """ Writes a particular wireless property to disk. """ + if (option.strip()).endswith("script"): + print 'You cannot save script information to disk through ' + \ + 'the daemon.' + return + config = self.config + cur_network = self.LastScan[id] + essid_key = "essid:" + cur_network["essid"] + + config.set(cur_network["bssid"], option, str(cur_network[option])) + + # Write the global section as well, if required. + if config.get(essid_key, 'use_settings_globally'): + config.set(essid_key, option, str(cur_network[option])) + config.write() + + @dbus.service.method('org.wicd.daemon.wireless') + def RemoveGlobalEssidEntry(self, networkid): + """ Removes the global entry for the networkid provided. """ + essid_key = "essid:" + str(self.LastScan[networkid]) + self.config.remove_section(essid_key) + + @dbus.service.signal(dbus_interface='org.wicd.daemon.wireless', signature='') + def SendStartScanSignal(self): + """ Emits a signal announcing a scan has started. """ + pass + + @dbus.service.signal(dbus_interface='org.wicd.daemon.wireless', signature='') + def SendEndScanSignal(self): + """ Emits a signal announcing a scan has finished. """ + pass + + def _wireless_autoconnect(self): + """ Attempts to autoconnect to a wireless network. """ + print "No wired connection present, attempting to autoconnect" + \ + "to wireless network" + if self.wifi.wireless_interface is None: + print 'Autoconnect failed because wireless interface returned None' + return + + for x, network in enumerate(self.LastScan): + if bool(network["has_profile"]): + if self.debug_mode: + print network["essid"] + ' has profile' + if bool(network.get('automatic')): + print 'trying to automatically connect to...' + \ + network["essid"] + self.ConnectWireless(x) + time.sleep(1) + return + print "Unable to autoconnect, you'll have to manually connect" + +########################### +###### Wired Daemon ####### +########################### + +class WiredDaemon(dbus.service.Object): + def __init__(self, bus_name, wired=None, wifi=None, debug=False): + dbus.service.Object.__init__(self, bus_name=bus_name, + object_path="/org/wicd/daemon/wired") + self.wired = wired + self.wifi = wifi + self.debug_mode = debug + self.forced_disconnect = False + self.config = ConfigManager(wpath.etc + "wired-settings") + @dbus.service.method('org.wicd.daemon.wired') - def GetWiredIP(self, fast=False): + def GetWiredIP(self, ifconfig=""): """ Returns the wired interface's ip address. """ - ip = self.wired.GetIP(True) + ip = self.wired.GetIP(ifconfig) return ip @dbus.service.method('org.wicd.daemon.wired') @@ -783,7 +1023,7 @@ class ConnectionWizard(dbus.service.Object): # 1 = default profile # 2 = show list # 3 = last used profile - self.set_option("Settings","wired_connect_mode", int(method)) + self.config.set("Settings","wired_connect_mode", int(method), True) self.wired_connect_mode = int(method) @dbus.service.method('org.wicd.daemon.wired') @@ -848,22 +1088,10 @@ class ConnectionWizard(dbus.service.Object): self.wired.Disconnect() @dbus.service.method('org.wicd.daemon.wired') - def SetAlwaysShowWiredInterface(self, value): - """ Sets always_show_wired_interface to the given value. """ - self.set_option("Settings", "always_show_wired_interface", - misc.to_bool(value)) - self.always_show_wired_interface = misc.to_bool(value) - - @dbus.service.method('org.wicd.daemon.wired') - def GetAlwaysShowWiredInterface(self): - """ Returns always_show_wired_interface """ - return bool(self.always_show_wired_interface) - - @dbus.service.method('org.wicd.daemon.wired') - def CheckPluggedIn(self, fast=False): + def CheckPluggedIn(self): """ Returns True if a ethernet cable is present, False otherwise. """ if self.wired.wired_interface and self.wired.wired_interface != "None": - return self.wired.CheckPluggedIn(fast) + return self.wired.CheckPluggedIn() else: return None @@ -882,6 +1110,22 @@ class ConnectionWizard(dbus.service.Object): """ Calls a method to disable the wired interface. """ return self.wired.DisableInterface() + @dbus.service.method('org.wicd.daemon.wired') + def GetForcedDisconnect(self): + """ Returns the forced_disconnect status. See SetForcedDisconnect. """ + return bool(self.forced_disconnect) + + @dbus.service.method('org.wicd.daemon.wired') + def SetForcedDisconnect(self, value): + """ Sets the forced_disconnect status. + + Set to True when a user manually disconnects or cancels a connection. + It gets set to False as soon as the connection process is manually + started. + + """ + self.forced_disconnect = bool(value) + @dbus.service.method('org.wicd.daemon.wired') def ConnectWired(self): """ Connects to a wired network. """ @@ -890,142 +1134,100 @@ class ConnectionWizard(dbus.service.Object): self.wired.after_script = self.GetWiredProperty("afterscript") self.wired.disconnect_script = self.GetWiredProperty("disconnectscript") self.wired.Connect(self.WiredNetwork, debug=self.debug_mode) - - ########## LOG FILE STUFF - ################################# - - @dbus.service.method('org.wicd.daemon.config') - def DisableLogging(self): - global logging_enabled - logging_enabled = False - - @dbus.service.method('org.wicd.daemon.config') - def EnableLogging(self): - global logging_enabled - logging_enabled = True - - ########## CONFIGURATION FILE FUNCTIONS - ################################# - - @dbus.service.method('org.wicd.daemon.config') + + @dbus.service.method('org.wicd.daemon.wired') def CreateWiredNetworkProfile(self, profilename, default=False): """ Creates a wired network profile. """ profilename = misc.to_unicode(profilename) print "Creating wired profile for " + profilename - config = ConfigParser.ConfigParser() - config.read(self.wired_conf) - if config.has_section(profilename): + if self.config.has_section(profilename): return False - config.add_section(profilename) - config.set(profilename, "ip", None) - config.set(profilename, "broadcast", None) - config.set(profilename, "netmask", None) - config.set(profilename, "gateway", None) - config.set(profilename, "dns1", None) - config.set(profilename, "dns2", None) - config.set(profilename, "dns3", None) - config.set(profilename, "beforescript", None) - config.set(profilename, "afterscript", None) - config.set(profilename, "disconnectscript", None) - config.set(profilename, "default", default) - config.write(open(self.wired_conf, "w")) + + for option in ["ip", "broadcast", "netmask","gateway", "dns1", "dns2", + "dns3", "beforescript", "afterscript", + "disconnectscript"]: + self.config.set(profilename, option, None) + self.config.set(profilename, "default", default) + self.config.write() return True - @dbus.service.method('org.wicd.daemon.config') + @dbus.service.method('org.wicd.daemon.wired') def UnsetWiredLastUsed(self): """ Finds the previous lastused network, and sets lastused to False. """ - config = ConfigParser.ConfigParser() - config.read(self.wired_conf) - profileList = config.sections() + profileList = self.config.sections() for profile in profileList: - if config.has_option(profile, "lastused"): - if misc.to_bool(config.get(profile, "lastused")): - config.set(profile, "lastused", False) + if self.config.has_option(profile, "lastused"): + if misc.to_bool(self.config.get(profile, "lastused")): + self.config.set(profile, "lastused", False) self.SaveWiredNetworkProfile(profile) - @dbus.service.method('org.wicd.daemon.config') + @dbus.service.method('org.wicd.daemon.wired') def UnsetWiredDefault(self): """ Unsets the default option in the current default wired profile. """ - config = ConfigParser.ConfigParser() - config.read(self.wired_conf) - profileList = config.sections() + profileList = self.config.sections() for profile in profileList: - if config.has_option(profile, "default"): - if misc.to_bool(config.get(profile, "default")): - config.set(profile, "default", False) + if self.config.has_option(profile, "default"): + if misc.to_bool(self.config.get(profile, "default")): + self.config.set(profile, "default", False) self.SaveWiredNetworkProfile(profile) - @dbus.service.method('org.wicd.daemon.config') + @dbus.service.method('org.wicd.daemon.wired') def GetDefaultWiredNetwork(self): """ Returns the current default wired network. """ - config = ConfigParser.ConfigParser() - config.read(self.wired_conf) - profileList = config.sections() + profileList = self.config.sections() for profile in profileList: - if config.has_option(profile, "default"): - if misc.to_bool(config.get(profile, "default")): + if self.config.has_option(profile, "default"): + if misc.to_bool(self.config.get(profile, "default")): return profile return None - @dbus.service.method('org.wicd.daemon.config') + @dbus.service.method('org.wicd.daemon.wired') def GetLastUsedWiredNetwork(self): """ Returns the profile of the last used wired network. """ - config = ConfigParser.ConfigParser() - config.read(self.wired_conf) - profileList = config.sections() + profileList = self.config.sections() for profile in profileList: - if config.has_option(profile,"lastused"): - if misc.to_bool(config.get(profile,"lastused")): + if self.config.has_option(profile, "lastused"): + if misc.to_bool(self.config.get(profile, "lastused")): return profile return None - @dbus.service.method('org.wicd.daemon.config') + @dbus.service.method('org.wicd.daemon.wired') def DeleteWiredNetworkProfile(self, profilename): """ Deletes a wired network profile. """ profilename = misc.to_unicode(profilename) print "Deleting wired profile for " + str(profilename) - config = ConfigParser.ConfigParser() - config.read(self.wired_conf) - if config.has_section(profilename): - config.remove_section(profilename) - else: - return "500: Profile does not exist" - config.write(open(self.wired_conf, "w")) - return "100: Profile Deleted" + self.config.remove_section(profilename) + self.config.write() - @dbus.service.method('org.wicd.daemon.config') + @dbus.service.method('org.wicd.daemon.wired') def SaveWiredNetworkProfile(self, profilename): """ Writes a wired network profile to disk. """ - def write_script_ent(prof, conf, script): - if not conf.has_option(prof, script): - conf.set(prof, script, None) + def write_script_ent(prof, script): + if not self.config.has_option(prof, script): + self.config.set(prof, script, None) + if profilename == "": return "500: Bad Profile name" profilename = misc.to_unicode(profilename) - config = ConfigParser.ConfigParser() - config.read(self.wired_conf) - if config.has_section(profilename): - config.remove_section(profilename) - config.add_section(profilename) + self.config.remove_section(profilename) + self.config.add_section(profilename) for x in self.WiredNetwork: - config.set(profilename, x, self.WiredNetwork[x]) + self.config.set(profilename, x, self.WiredNetwork[x]) - write_script_ent(profilename, config, "beforescript") - write_script_ent(profilename, config, "afterscript") - write_script_ent(profilename, config, "disconnectscript") - config.write(open(self.wired_conf, "w")) + write_script_ent(profilename, "beforescript") + write_script_ent(profilename, "afterscript") + write_script_ent(profilename, "disconnectscript") + self.config.write() return "100: Profile Written" - @dbus.service.method('org.wicd.daemon.config') + @dbus.service.method('org.wicd.daemon.wired') def ReadWiredNetworkProfile(self, profilename): """ Reads a wired network profile in as the currently active profile """ profile = {} profilename = misc.to_unicode(profilename) - config = ConfigParser.ConfigParser() - config.read(self.wired_conf) - if config.has_section(profilename): - for x in config.options(profilename): - profile[x] = misc.Noneify(config.get(profilename, x)) + if self.config.has_section(profilename): + for x in self.config.options(profilename): + profile[x] = misc.Noneify(self.config.get(profilename, x)) profile['use_global_dns'] = bool(profile.get('use_global_dns')) profile['use_static_dns'] = bool(profile.get('use_static_dns')) self.WiredNetwork = profile @@ -1034,289 +1236,59 @@ class ConnectionWizard(dbus.service.Object): self.WiredNetwork = None return "500: Profile Not Found" - @dbus.service.method('org.wicd.daemon.config') + @dbus.service.method('org.wicd.daemon.wired') def GetWiredProfileList(self): """ Returns a list of all wired profiles in wired-settings.conf. """ - config = ConfigParser.ConfigParser() - config.read(self.wired_conf) - if config.sections(): - return config.sections() - else: - return None - - @dbus.service.method('org.wicd.daemon.config') - def SaveWirelessNetworkProfile(self, id): - """ Writes a wireless profile to disk. """ - def write_script_ent(prof, conf, script): - if not conf.has_option(prof, script): - conf.set(prof, script, None) - - config = ConfigParser.ConfigParser() - config.read(self.wireless_conf) - cur_network = self.LastScan[id] - bssid_key = cur_network["bssid"] - essid_key = "essid:" + cur_network["essid"] - - if config.has_section(bssid_key): - config.remove_section(bssid_key) - config.add_section(bssid_key) - - # We want to write the essid in addition to bssid - # sections if global settings are enabled. - if cur_network["use_settings_globally"]: - if config.has_section(essid_key): - config.remove_section(essid_key) - config.add_section(essid_key) - - for x in cur_network: - config.set(bssid_key, x, cur_network[x]) - if cur_network["use_settings_globally"]: - config.set(essid_key, x, cur_network[x]) - - write_script_ent(bssid_key, config, "beforescript") - write_script_ent(bssid_key, config, "afterscript") - write_script_ent(bssid_key, config, "disconnect") - - if cur_network["use_settings_globally"]: - write_script_ent(essid_key, config, "beforescript") - write_script_ent(essid_key, config, "afterscript") - write_script_ent(essid_key, config, "disconnect") - - config.write(open(self.wireless_conf, "w")) - - @dbus.service.method('org.wicd.daemon.config') - def SaveWirelessNetworkProperty(self, id, option): - """ Writes a particular wireless property to disk. """ - if (option.strip()).endswith("script"): - print 'You cannot save script information to disk through ' + \ - 'the daemon.' + return self.config.sections() + + def _wired_autoconnect(self): + """ Attempts to autoconnect to a wired network. """ + if self.GetWiredAutoConnectMethod() == 3 and \ + not self.GetNeedWiredProfileChooser(): + # attempt to smartly connect to a wired network + # by using various wireless networks detected + # and by using plugged in USB devices + print self.LastScan + if self.GetWiredAutoConnectMethod() == 2 and \ + not self.GetNeedWiredProfileChooser(): + self.LaunchChooser() return - cur_network = self.LastScan[id] - essid_key = "essid:" + cur_network["essid"] - config = ConfigParser.ConfigParser() - config.read(self.wireless_conf) - if config.has_section(cur_network["bssid"]): - config.set(cur_network["bssid"], option, - str(cur_network[option])) + # Default Profile. + elif self.GetWiredAutoConnectMethod() == 1: + network = self.GetDefaultWiredNetwork() + if not network: + print "Couldn't find a default wired connection," + \ + " wired autoconnect failed." + self._wireless_autoconnect() + return - # Write the global section as well, if required. - if config.has_section(essid_key): - if config.get(essid_key, 'use_settings_globally'): - config.set(essid_key, option, str(cur_network[option])) - - config.write(open(self.wireless_conf, "w")) - - @dbus.service.method('org.wicd.daemon.config') - def RemoveGlobalEssidEntry(self, networkid): - """ Removes the global entry for the networkid provided. """ - config = ConfigParser.ConfigParser() - config.read(self.wireless_conf) - cur_network = self.LastScan[networkid] - essid_key = "essid:" + cur_network["essid"] - if config.has_section(essid_key): - config.remove_section(essid_key) - - @dbus.service.method('org.wicd.daemon.config') - def ReadWirelessNetworkProfile(self, id): - """ Reads in wireless profile as the active network """ - config = ConfigParser.ConfigParser() - config.read(self.wireless_conf) - cur_network = self.LastScan[id] - essid_key = "essid:" + cur_network["essid"] - bssid_key = cur_network["bssid"] - if self.debug_mode: - print bssid_key - if config.has_section(essid_key): - if config.get(essid_key, 'use_settings_globally'): - return self._read_wireless_profile(config, cur_network, - essid_key) - elif config.has_section(bssid_key): - return self._read_wireless_profile(config, cur_network, bssid_key) + # Last-Used. else: - cur_network["has_profile"] = False - return "500: Profile Not Found" - - def _read_wireless_profile(self, config, cur_network, section): - cur_network["has_profile"] = True + network = self.GetLastUsedWiredNetwork() + if not network: + print "no previous wired profile available, wired " + \ + "autoconnect failed." + self._wireless_autoconnect() + return - # Read the essid because we be needing to name those hidden - # wireless networks now - but only read it if it is hidden. - if cur_network["hidden"]: - cur_network["essid"] = misc.Noneify(config.get(section, - "essid")) - for x in config.options(section): - if not cur_network.has_key(x) or x.endswith("script"): - cur_network[x] = misc.Noneify(config.get(section, - x)) - for option in ['use_static_dns', 'use_global_dns', 'encryption', - 'use_settings_globally']: - cur_network[option] = bool(cur_network.get(option)) - return "100: Loaded Profile" + self.ReadWiredNetworkProfile(network) + self.ConnectWired() + print "Attempting to autoconnect with wired interface..." + self.auto_connecting = True + time.sleep(1.5) + gobject.timeout_add(3000, self._monitor_wired_autoconnect) - @dbus.service.method('org.wicd.daemon.config') - def WriteWindowSize(self, width, height, win_name): - """Write the desired default window size""" - if win_name == "main": - height_str = "window_height" - width_str = "window_width" - else: - height_str = "pref_height" - width_str = "pref_width" - config = ConfigParser.ConfigParser() - config.read(self.app_conf) - if config.has_section("Settings"): - config.set("Settings", width_str, width) - config.set("Settings", height_str, height) - config.write(open(self.app_conf, "w")) - - @dbus.service.method('org.wicd.daemon.config') - def ReadWindowSize(self, win_name): - """Returns a list containing the desired default window size - - Attempts to read the default size from the config file, - and if that fails, returns a default of 605 x 400. - - """ - if win_name == "main": - default_width = 605 - default_height = 400 - width_str = "window_width" - height_str = "window_height" - else: - default_width = 125 - default_height = 590 - width_str = "pref_width" - height_str = "pref_height" - - width = self.get_option("Settings", width_str, default_width) - height = self.get_option("Settings", height_str, default_height) - - size = [] - size.append(int(width)) - size.append(int(height)) - return size - - ############################################# - ########## INTERNAL FUNCTIONS ############### - ############################################# - # so don't touch the stuff below # - # it read/writes the configuration files # - # and shouldn't need to be changed # - # unless you add a new property... # - # then be SURE YOU CHANGE IT # - ############################################# - - def __printReturn(self, text, value): - """prints the specified text and value, then returns the value""" - if self.debug_mode: - print ''.join([text, " ", str(value)]) - return value - - def set_option(self, section, option, value): - """ Sets the given option to the given value. """ - config = ConfigParser.ConfigParser() - config.read(self.app_conf) - config.set(section, option, value) - configfile = open(self.app_conf, "w") - config.write(configfile) - - def get_option(self, section, option, default=None): - """ Method for returning an option from manager-settings.conf. - - This method will return a given option from a given section - - """ - config = ConfigParser.ConfigParser() - config.read(self.app_conf) - if not config.has_section(section): - config.add_section(section) - - if config.has_option(section, option): - ret = config.get(section, option) - print ''.join(['found ', option, ' in configuration ', ret]) - else: - config.set(section, option, default) - ret = default - config.write(open(self.app_conf, "w")) - return ret - - def ReadConfig(self): - """ Reads the manager-settings.conf file. - - Reads the manager-settings.conf file and loads the stored - values into memory. - - """ - iface = self.DetectWirelessInterface() - if not iface: iface = 'wlan0' - self.SetWirelessInterface(self.get_option("Settings", - "wireless_interface", - default=iface)) - - iface = self.DetectWiredInterface() - if not iface: iface = 'eth0' - self.SetWiredInterface(self.get_option("Settings", "wired_interface", - default=iface)) - - self.SetWPADriver(self.get_option("Settings", "wpa_driver", - default="wext")) - self.SetAlwaysShowWiredInterface(self.get_option("Settings", - "always_show_wired_interface", - default=False)) - self.SetUseGlobalDNS(self.get_option("Settings", "use_global_dns", - default=False)) - dns1 = self.get_option("Settings", "global_dns_1", default='None') - dns2 = self.get_option("Settings", "global_dns_2", default='None') - dns3 = self.get_option("Settings", "global_dns_3", default='None') - self.SetGlobalDNS(dns1, dns2, dns3) - self.SetAutoReconnect(self.get_option("Settings", "auto_reconnect", - default=True)) - self.SetDebugMode(self.get_option("Settings", "debug_mode", - default=False)) - - self.SetWiredAutoConnectMethod(self.get_option("Settings", - "wired_connect_mode", - default=1)) - self.SetSignalDisplayType(self.get_option("Settings", - "signal_display_type", - default=0)) - self.SetDHCPClient(self.get_option("Settings", "dhcp_client", - default=0)) - self.SetLinkDetectionTool(self.get_option("Settings", - "link_detect_tool", - default=0)) - self.SetFlushTool(self.get_option("Settings", "flush_tool", default=0)) - - if os.path.isfile(self.wireless_conf): - print "Wireless configuration file found..." - else: - print "Wireless configuration file not found, creating..." - open(self.wireless_conf, "w").close() - - if os.path.isfile(self.wired_conf): - print "Wired configuration file found..." - else: - print "Wired configuration file not found, creating a default..." - # Create the file and a default profile - open(self.wired_conf, "w").close() - self.CreateWiredNetworkProfile("wired-default", default=True) - - # Hide the files, so the keys aren't exposed. - print "chmoding configuration files 0600..." - os.chmod(self.app_conf, 0600) - os.chmod(self.wireless_conf, 0600) - os.chmod(self.wired_conf, 0600) - - # Make root own them - print "chowning configuration files root:root..." - os.chown(self.app_conf, 0, 0) - os.chown(self.wireless_conf, 0, 0) - os.chown(self.wired_conf, 0, 0) - - print "Using wireless interface..." + self.GetWirelessInterface() - print "Using wired interface..." + self.GetWiredInterface() - + def _monitor_wired_autoconnect(self): + if self.CheckIfWiredConnecting(): + return True + elif self.GetWiredIP(): + self.auto_connecting = False + return False + elif not self.CheckIfWirelessConnecting(): + self._wireless_autoconnect() + self.auto_connecting = False + return False def usage(): print """ @@ -1362,7 +1334,13 @@ def daemonize(): try: pid = os.fork() if pid > 0: - print "wicd daemon: pid " + str(pid) + print wpath.pidfile + dirname = os.path.dirname(wpath.pidfile) + if not os.path.exists(dirname): + os.makedirs(dirname) + pidfile = open(wpath.pidfile, 'w') + pidfile.write(str(pid) + '\n') + pidfile.close() sys.exit(0) except OSError, e: print >> sys.stderr, "Fork #2 failed: %d (%s)" % (e.errno, e.strerror) @@ -1378,7 +1356,6 @@ def daemonize(): sys.stdin = open('/dev/null', 'r') - def main(argv): """ The main daemon program. @@ -1390,17 +1367,17 @@ def main(argv): do_daemonize = True redirect_stderr = True redirect_stdout = True - auto_scan = True + auto_connect = True try: - opts, args = getopt.getopt(sys.argv[1:], 'fenoah:', + opts, args = getopt.getopt(sys.argv[1:], 'fenoah', ['help', 'no-daemon', 'no-poll', 'no-stderr', 'no-stdout', 'no-autoconnect']) except getopt.GetoptError: # Print help information and exit usage() sys.exit(2) - + no_poll = False for o, a in opts: if o in ('-h', '--help'): @@ -1413,13 +1390,20 @@ def main(argv): if o in ('-f', '--no-daemon'): do_daemonize = False if o in ('-a', '--no-autoconnect'): - auto_scan = False + auto_connect = False if o in ('-n', '--no-poll'): no_poll = True if do_daemonize: daemonize() - if redirect_stderr or redirect_stdout: output = ManagedStdio(wpath.log + 'wicd.log') + if redirect_stderr or redirect_stdout: + logpath = os.path.join(wpath.log, 'wicd.log') + output = ManagedStdio(logpath) + if os.path.exists(logpath): + try: + os.chmod(logpath, 0600) + except: + print 'unable to chmod log file to 0600' if redirect_stdout: sys.stdout = output if redirect_stderr: sys.stderr = output @@ -1428,13 +1412,13 @@ def main(argv): print '---------------------------' # Open the DBUS session - - d_bus_name = dbus.service.BusName('org.wicd.daemon', bus=dbus.SystemBus()) - obj = ConnectionWizard(d_bus_name, auto_connect=auto_scan) + bus = dbus.SystemBus() + wicd_bus = dbus.service.BusName('org.wicd.daemon', bus=bus) + daemon = WicdDaemon(wicd_bus, auto_connect=auto_scan) gobject.threads_init() if not no_poll: - (child_pid, x, x, x) = gobject.spawn_async([wpath.bin + "monitor.py"], + (child_pid, x, x, x) = gobject.spawn_async([wpath.lib + "monitor.py"], flags=gobject.SPAWN_CHILD_INHERITS_STDIN) signal.signal(signal.SIGTERM, sigterm_caught) @@ -1447,6 +1431,9 @@ def sigterm_caught(sig, frame): global child_pid print 'SIGTERM caught, killing wicd-monitor...' os.kill(child_pid, signal.SIGTERM) + print 'Removing PID file...' + if os.path.exists(wpath.pidfile): + os.remove(wpath.pidfile) print 'Shutting down...' sys.exit(0) diff --git a/wicd/wnettools.py b/wicd/wnettools.py index 5674784..3f1035e 100644 --- a/wicd/wnettools.py +++ b/wicd/wnettools.py @@ -31,59 +31,23 @@ class WirelessInterface() -- Control a wireless network interface. # along with this program. If not, see . # -import re import os import time -import socket -import fcntl -import struct -import array +import re -import wicd.wpath as wpath -import wicd.misc as misc - -# Compile the regex patterns that will be used to search the output of iwlist -# scan for info these are well tested, should work on most cards -essid_pattern = re.compile('.*ESSID:"(.*?)"\n', re.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) +import wpath +import misc RALINK_DRIVER = 'ralink legacy' -SIOCGIWESSID = 0x8B1B -SIOCGIFADDR = 0x8915 -SIOCGIWSTATS = 0x8B0F -SIOCGIFHWADDR = 0x8927 -SIOCGMIIPHY = 0x8947 -SIOCGETHTOOL = 0x8946 -SIOCGIFFLAGS = 0x8913 -SIOCGIWRANGE = 0x8B0B -SIOCGIWAP = 0x8B15 + def _sanitize_string(string): blacklist = [';', '`', '$', '!', '*', '|', '>', '<'] new_string = [] - + if not string: return string - + for c in string: if c in blacklist: new_string.append("\\" + c) @@ -102,7 +66,7 @@ def SetDNS(dns1=None, dns2=None, dns3=None): dns3 -- IP address of DNS server 1 """ - resolv = open("/etc/resolv.conf","w") + resolv = open("/etc/resolv.conf", "w") for dns in [dns1, dns2, dns3]: if dns: if misc.IsValidIP(dns): @@ -147,42 +111,24 @@ def GetWirelessInterfaces(): dev_dir = '/sys/class/net/' ifnames = [] - ifnames = [iface for iface in os.listdir(dev_dir) if os.path.isdir(dev_dir + iface) \ + ifnames = [iface for iface in os.listdir(dev_dir) if os.path.isdir(dev_dir + iface) and 'wireless' in os.listdir(dev_dir + iface)] return bool(ifnames) and ifnames[0] or None def GetWiredInterfaces(): basedir = '/sys/class/net/' - return [iface for iface in os.listdir(basedir) if not 'wireless' \ - in os.listdir(basedir + iface) and \ + return [iface for iface in os.listdir(basedir) if not 'wireless' + in os.listdir(basedir + iface) and open(basedir + iface + "/type").readlines()[0].strip() == "1"] +def NeedsExternalCalls(): + print ("NeedsExternalCalls: returning default of True. You should " + + "implement this yourself.") + return True -def get_iw_ioctl_result(iface, call): - """ Makes the given ioctl call and returns the results. - - Keyword arguments: - call -- The ioctl call to make - - Returns: - The results of the ioctl call. - - """ - s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - buff = array.array('c', '\0' * 32) - addr, length = buff.buffer_info() - arg = struct.pack('Pi', addr, length) - data = (iface + '\0' * 16)[:16] + arg - try: - result = fcntl.ioctl(s.fileno(), call, data) - except IOError: - return None - except OSError: - return None - return buff.tostring() -class Interface(object): +class BaseInterface(object): """ Control a network interface. """ def __init__(self, iface, verbose=False): """ Initialise the object. @@ -201,10 +147,8 @@ class Interface(object): self.ETHTOOL_FOUND = False self.IP_FOUND = False self.flush_tool = None - self.link_detect = None - self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - self.Check() - + self.link_detect = None + def SetDebugMode(self, value): """ If True, verbose output is enabled. """ self.verbose = value @@ -548,7 +492,7 @@ class Interface(object): gw -- gateway of the default route in dotted quad form """ - if not self.iface: return + if not self.iface: return if not misc.IsValidIP(gw): print 'WARNING: Invalid gateway found. Aborting!' return False @@ -556,77 +500,28 @@ class Interface(object): if self.verbose: print cmd misc.Run(cmd) - def GetIP(self, fast=False): + def GetIP(self, ifconfig=""): """ Get the IP address of the interface. Returns: The IP address of the interface in dotted quad form. """ - if not self.iface: return False - if fast: - return self._fast_get_ip() - cmd = 'ifconfig ' + self.iface - if self.verbose: print cmd - output = misc.Run(cmd) - return misc.RunRegex(ip_pattern, output) + print 'Implement this in a derived class!' + pass - def _fast_get_ip(self): - """ Gets the IP Address of the interface using ioctl. - - Using ioctl calls to get the IP Address info is MUCH faster - than calling ifconfig and paring it's output. It's less - portable though, so there may be problems with it on some - systems. - - """ - ifstruct = struct.pack('256s', self.iface) - try: - raw_ip = fcntl.ioctl(self.sock.fileno(), SIOCGIFADDR, ifstruct) - except IOError: - return None - except OSError: - return None - - return socket.inet_ntoa(raw_ip[20:24]) - - def IsUp(self, fast=True): + def IsUp(self): """ Determines if the interface is up. Returns: True if the interface is up, False otherwise. """ - if not self.iface: return False - if fast: - return self._fast_is_up() - cmd = "ifconfig " + self.iface - output = misc.Run(cmd) - 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 - - def _fast_is_up(self): - """ Determines if the interfae is up using an ioctl call. """ - data = (self.iface + '\0' * 16)[:18] - try: - result = fcntl.ioctl(self.sock.fileno(), SIOCGIFFLAGS, data) - except IOError, e: - if self.verbose: - print "SIOCGIFFLAGS failed: " + str(e) - return False - - flags, = struct.unpack('H', result[16:18]) - return bool(flags & 1) + print 'Implement this in a derived class!' + pass -class WiredInterface(Interface): +class BaseWiredInterface(BaseInterface): """ Control a wired network interface. """ def __init__(self, iface, verbose=False): """ Initialise the wired network interface class. @@ -636,9 +531,9 @@ class WiredInterface(Interface): verbose -- print all commands """ - Interface.__init__(self, iface, verbose) + BaseInterface.__init__(self, iface, verbose) - def GetPluggedIn(self, fast=False): + def GetPluggedIn(self): """ Get the current physical connection state. The method will first attempt to use ethtool do determine @@ -649,104 +544,11 @@ class WiredInterface(Interface): True if a link is detected, False otherwise. """ - if not self.iface: return False - if self.ETHTOOL_FOUND and self.link_detect != misc.MIITOOL: - return self._eth_get_plugged_in(fast) - elif self.MIITOOL_FOUND: - return self._mii_get_plugged_in(fast) - 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, fast): - """ Use ethtool to determine the physical connection state. - - Returns: - True if a link is detected, False otherwise. - - """ - if fast: - self._fast_eth_get_plugged_in() - link_tool = 'ethtool' - if not self.IsUp(): - print 'Wired Interface is down, putting it up' - self.Up() - time.sleep(6) - tool_data = misc.Run(link_tool + ' ' + self.iface, True) - if misc.RunRegex(re.compile('(Link detected: yes)', re.I | re.M | - re.S), tool_data) is not None: - return True - else: - return False - - def _fast_eth_get_plugged_in(self): - """ Determines link connection status using an ioctl call. - - Uses the SIOCGETHTOOL ioctl call to determine link status. - - Returns: - True if a wire is plugged in, False otherwise. - - """ - if not self.IsUp(): - self.Up() - time.sleep(5) - buff = array.array('i', [0x0000000a, 0x00000000]) - addr, length = buff.buffer_info() - arg = struct.pack('Pi', addr, length) - data = (self.iface + '\0' * 16)[:16] + arg - try: - fcntl.ioctl(self.sock.fileno(), SIOCGETHTOOL, data) - except IOError, e: - if self.verbose: - print 'SIOCGETHTOOL failed: ' + str(e) - return False - return bool(buff.tolist()[1]) - - - def _mii_get_plugged_in(self, fast): - """ Use mii-tool to determine the physical connection state. - - Returns: - True if a link is detected, False otherwise. - - """ - if fast: - return self._fast_mii_get_plugged_in() - 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), - tool_data) is not None: - print 'Wired Interface is down, putting it up' - self.Up() - time.sleep(4) - tool_data = misc.Run(link_tool + ' ' + self.iface, True) - - if misc.RunRegex(re.compile('(link ok)', re.I | re.M | re.S), - tool_data) is not None: - return True - else: - return False - - def _fast_mii_get_plugged_in(self): - """ Get link status using the SIOCGMIIPHY ioctl call. """ - if not self.IsUp(): - self.Up() - time.sleep(2.5) - buff = struct.pack('16shhhh', (self.iface + '\0' * 16)[:16], 0, 1, - 0x0004, 0) - try: - result = fcntl.ioctl(self.sock.fileno(), SIOCGMIIPHY, buff) - except IOError, e: - if self.verbose: - print 'SIOCGMIIPHY failed: ' + str(e) - return False - reg = struct.unpack('16shhhh', result)[-1] - return bool(reg & 0x0004) + print 'Implement this in a derived class!' + pass -class WirelessInterface(Interface): +class BaseWirelessInterface(BaseInterface): """ Control a wireless network interface. """ def __init__(self, iface, verbose=False, wpa_driver='wext'): """ Initialise the wireless network interface class. @@ -756,7 +558,7 @@ class WirelessInterface(Interface): verbose -- print all commands """ - Interface.__init__(self, iface, verbose) + BaseInterface.__init__(self, iface, verbose) self.wpa_driver = wpa_driver self.scan_iface = None @@ -790,7 +592,7 @@ class WirelessInterface(Interface): """ if not self.iface: return False - output = misc.Run("iwconfig " + self.iface) + output = self.GetIwconfig() killswitch_pattern = re.compile('.*radio off', re.I | re.M | re.S) if killswitch_pattern.search(output): @@ -803,43 +605,9 @@ class WirelessInterface(Interface): def GetIwconfig(self): """ Returns the output of iwconfig for this interface. """ if not self.iface: return "" - return misc.Run("iwconfig " + self.iface) - - def GetNetworks(self): - """ Get a list of available wireless networks. - - Returns: - A list containing available wireless networks. - - """ - cmd = 'iwlist ' + self.iface + ' scan' + cmd = "iwconfig " + self.iface 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 + return misc.Run(cmd) def _FreqToChannel(self, freq): """ Translate the specified frequency to a channel. @@ -880,90 +648,6 @@ class WirelessInterface(Interface): lines = lines[2:] return lines - 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 = {} - # ESSID - Switch '' to 'Hidden' to remove - # brackets that can mix up formatting. - 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['essid'] = 'Hidden' - ap['hidden'] = True - 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 _ParseRalinkAccessPoint(self, ap, ralink_info, cell): """ Parse encryption and signal strength info for ralink cards @@ -1101,52 +785,8 @@ class WirelessInterface(Interface): False otherwise. """ - # Right now there's no way to do this for ralink drivers - if self.wpa_driver == RALINK_DRIVER or not self.WPA_CLI_FOUND: - return True - - MAX_TIME = 15 - MAX_DISCONNECTED_TIME = 3 - while (time.time() - auth_time) < MAX_TIME: - cmd = 'wpa_cli -i ' + self.iface + ' status' - output = misc.Run(cmd) - result = misc.RunRegex(auth_pattern, output) - if self.verbose: - print 'WPA_CLI RESULT IS', result - - if not result: - print "WARNING: Received an unexpected result from wpa_cli!" + \ - "\nMake sure you're using the right wpa_supplicant " + \ - "driver (you probably want wext).\nIf the problem " + \ - "persists, please file a bug report." - return False - if result == "COMPLETED": - return True - elif result == "DISCONNECTED" and \ - (time.time() - auth_time) > MAX_DISCONNECTED_TIME: - # Force a rescan to get wpa_supplicant moving again. - self._ForceSupplicantScan() - MAX_TIME += 5 - 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) + print 'Implement this in a derived class!' + pass def _AuthenticateRalinkLegacy(self, network): """ Authenticate with the specified wireless network. @@ -1205,154 +845,38 @@ class WirelessInterface(Interface): if self.verbose: print cmd misc.Run(cmd) - def GetBSSID(self, iwconfig="", fast=True): + def GetBSSID(self, iwconfig=None): """ Get the MAC address for the interface. """ - if not self.iface: return "" - if fast: - return self._fast_get_bssid() - else: - 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 _fast_get_bssid(self): - """ Gets the MAC address for the connected AP using ioctl calls. """ - data = (self.iface + '\0' * 32)[:32] - try: - result = fcntl.ioctl(self.sock.fileno(), SIOCGIWAP, data)[16:] - except IOError, e: - if self.verbose: - print "SIOCGIWAP failed: " + str(e) - return "" - raw_addr = struct.unpack("xxBBBBBB", result[:8]) - return "%02X:%02X:%02X:%02X:%02X:%02X" % raw_addr - + print 'Implement this in a derived class!' + pass - - def GetSignalStrength(self, iwconfig=None, fast=False): + def GetSignalStrength(self, iwconfig=None): """ Get the signal strength of the current network. Returns: The signal strength. """ - if not self.iface: return -1 - if fast: - return self._get_signal_strength_fast() - - 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: - return 100 * int(strength) // int(max_strength) - - if strength is None: - strength = misc.RunRegex(altstrength_pattern, output) - - return strength + print 'Implement this in a derived class!' + pass - def _get_signal_strength_fast(self): - """ Get the link quality using ioctl calls. """ - buff = get_iw_ioctl_result(self.iface, SIOCGIWSTATS) - strength = ord(buff[2]) - max_strength = self._get_max_strength_fast() - if strength and max_strength: - return 100 * int(strength) // int(max_strength) - - return strength - - def _get_max_strength_fast(self): - """ Gets the maximum possible strength from the wireless driver. """ - buff = array.array('c', '\0' * 700) - addr, length = buff.buffer_info() - arg = struct.pack('Pi', addr, length) - iwfreq = (self.iface + '\0' * 16)[:16] + arg - try: - result = fcntl.ioctl(self.sock.fileno(), SIOCGIWRANGE, iwfreq) - except IOError, e: - if self.verbose: - print "SIOCGIWRANGE failed: " + str(e) - return None - # This defines the iwfreq struct, used to get signal strength. - fmt = "iiihb6ii4B4Bi32i2i2i2i2i3h8h2b2bhi8i2b3h2i2ihB17x" + 32 * "ihbb" - size = struct.calcsize(fmt) - data = buff.tostring() - data = data[0:size] - values = struct.unpack(fmt, data) - return values[12] - - def GetDBMStrength(self, iwconfig=None, fast=False): + def GetDBMStrength(self, iwconfig=None): """ Get the dBm signal strength of the current network. Returns: The dBm signal strength. """ - if not self.iface: return -100 - if fast: - return self._get_dbm_strength_fast() - if 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 _get_dbm_strength_fast(self): - """ Uses the SIOCGIWSTATS ioctl call to get dbm signal strength. - - Returns: - The dBm signal strength or None if it can't be found. - - """ - buff = misc.get_irwange_ioctl_result(self.iface, SIOCGIWSTATS) - if not buff: - return None + print 'Implement this in a derived class!' + pass - return str((ord(buff[3]) - 256)) - - - def GetCurrentNetwork(self, iwconfig=None, fast=False): + def GetCurrentNetwork(self, iwconfig=None): """ Get the essid of the current network. Returns: The current network essid. """ - if not self.iface: return "" - if fast: - return self._get_essid_fast() - - 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 - - def _get_essid_fast(self): - """ Get the current essid using ioctl. """ - buff = get_iw_ioctl_result(self.iface, SIOCGIWESSID) - if not buff: - return None - - return buff.strip('\x00') + print 'Implement this in a derived class!' + pass diff --git a/wicd/wpath.py b/wicd/wpath.py index 6c5bd31..d519a50 100644 --- a/wicd/wpath.py +++ b/wicd/wpath.py @@ -12,13 +12,49 @@ current = os.path.dirname(os.path.realpath(__file__)) + '/' # These paths can easily be modified to handle system wide installs, or # they can be left as is if all files remain with the source directory # layout. -lib = current -images = lib + 'images/' -encryption = lib + 'encryption/templates/' -bin = current -etc = current + 'data/' -networks = lib + 'encryption/configurations/' -log = current + 'data/' + +# These paths are replaced when setup.py configure is run + +# All of these paths *MUST* end in a / +# except the python one, of course as it is an executable + +lib = '/usr/lib/wicd/' +share = '/usr/share/wicd/' +etc = '/etc/wicd/' +images = '/usr/share/pixmaps/wicd/' +encryption = '/etc/wicd/encryption/templates/' +bin = '/usr/bin/' +networks = '/var/lib/wicd/configurations/' +log = '/var/log/wicd/' +backends = '/usr/lib/wicd/backends/' + +# other, less useful entries +resume = '/etc/acpi/resume.d/' +suspend = '/etc/acpi/suspend.d/' +sbin = '/usr/sbin/' +dbus = '/etc/dbus-1/system.d/' +desktop = '/usr/share/applications/' +translations = '/usr/share/locale/' +icons = '/usr/share/icons/hicolor/' +autostart = '/etc/xdg/autostart/' +init = '/etc/init.d/' +docdir = '/usr/share/doc/wicd/' +mandir = '/usr/share/man/' +kdedir = '/usr/share/autostart/' + +python = '/usr/bin/python' +pidfile = '/var/run/wicd/wicd.pid' +# stores something like other/wicd +# really only used in the install +initfile = 'init/debian/wicd' +# stores only the file name, i.e. wicd +initfilename = 'wicd' +no_install_init = False +no_install_man = False +no_install_kde = False +no_install_acpi = False +no_install_install = False +no_install_license = False def chdir(file): """Change directory to the location of the specified file.