wifi-radar-2.0.s08+dfsg/0000750000175000017500000000000011525244141014266 5ustar winniewinniewifi-radar-2.0.s08+dfsg/wifi-radar.desktop0000640000175000017500000000041711356151665017723 0ustar winniewinnie[Desktop Entry] Version=1.0 Encoding=UTF-8 Type=Application Name=WiFi Radar GenericName=Wireless tool Comment=Tool for connecting to wireless networks Icon=wifi-radar.svg FilePattern=wifi-radar TryExec=wifi-radar Exec=gksudo -S wifi-radar Categories=Application;Network; wifi-radar-2.0.s08+dfsg/wifi-radar0000755000175000017500000041225411356152126016261 0ustar winniewinnie#!/usr/bin/python -OO # # A utility for managing WiFi profiles on GNU/Linux. # # Copyright (C) 2004-2005 Ahmad Baitalmal # Copyright (C) 2005 Nicolas Brouard # Copyright (C) 2005-2009 Brian Elliott Finley # Copyright (C) 2006 David Decotigny # Copyright (C) 2006 Simon Gerber # Copyright (C) 2006-2007 Joey Hurst # Copyright (C) 2006, 2009 Ante Karamatic # Copyright (C) 2009-2010 Sean Robinson # Copyright (C) 2010 Prokhor Shuchalov # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 2 of the License. # # 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 in LICENSE.GPL for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # http://wifi-radar.berlios.de # # See CREDITS file for more contributors. # See HISTORY file for, well, changes. # # NOTE: Remove the '-OO' from '#!/usr/bin/python -OO' in the first line to # turn on console debugging. import ConfigParser import errno import gtk import logging import logging.handlers import os import Queue import re import string import sys import tempfile import threading from shutil import move from signal import SIGTERM from subprocess import call, Popen, PIPE, STDOUT from time import sleep from types import * WIFI_RADAR_VERSION = "2.0.s08" # # Where the conf file should live could be different for your distro. Please change # at install time with "make install sysconfdir=/etc/wifi-radar" or similar. -BEF- # CONF_FILE = "/etc/wifi-radar/wifi-radar.conf" os.environ['LC_MESSAGES'] = 'C' #################################################################################################### #################################################################################################### # Gets the network interface device # #Parameters: # # 'device' -- string - The proposed network device to use # #Returns: # # string -- The actual network device to use def get_network_device(device): #print "get_network_device: %s" % (device, ) if device != "auto_detect": return confFile.get_opt('DEFAULT.interface') else: # auto detect network device # Get a list of 802.11 enabled devices by parsing the output of iwconfig. # If no devices are found, default to eth1. # call iwconfig command and read output iwconfig_info = Popen(confFile.get_opt('DEFAULT.iwconfig_command'), shell=True, stdout=PIPE, stderr=STDOUT).stdout wireless_devices = [(x[0:x.find(" ")]) for x in iwconfig_info if("ESSID" in x)] if len(wireless_devices) > 0: return wireless_devices[0] logger.critical("No WiFi device found, please set this in the preferences.") return "" # Return a blank profile # #Parameters: # # none # #Returns: # # dictionary -- An AP profile with defaults set. def get_new_profile(): return { 'known': False, 'available': False, 'encrypted': False, 'essid': '', 'bssid': '', 'roaming': False, 'protocol': 'g', 'signal': -193, 'channel': 'auto', 'con_prescript': '', 'con_postscript': '', 'dis_prescript': '', 'dis_postscript': '', 'key': '', 'mode': 'auto', 'security': '', 'use_wpa': False, 'wpa_driver': '', 'use_dhcp': True, 'ip': '', 'netmask': '', 'gateway': '', 'domain': '', 'dns1': '', 'dns2': '' } # Combine essid and bssid to make a config file section name # #Parameters: # # 'essid' -- string - AP ESSID # # 'bssid' -- string - AP BSSID # #Returns: # # string -- the bssid concatenated to a colon, concatenated to the essid def make_section_name( essid, bssid ): return essid + ':' + bssid # Split a config file section name into an essid and a bssid # #Parameters: # # 'section' -- string - Config file section name # #Returns: # # list -- the essid and bssid def split_section_name( section ): parts = re.split(':', section) return [ ':'.join(parts[0:len(parts)-6]), ':'.join(parts[len(parts)-6:len(parts)]) ] # Run commands through the shell # #Parameters: # # 'command' -- tuple - The command and arguments to run. # # 'environment' -- dictionary - Environment variables (as keys) and their values. # #Returns: # # boolean -- True on success, otherwise, False def shellcmd( command, environment = None ): try: env_tmp = os.environ env_tmp.update(environment) command = ' '.join(command) return_code = call(command, shell=True, env=env_tmp) if return_code >= 0: return True else: print >>sys.stderr, "Child was terminated by signal", -return_code except OSError, exception: print >>sys.stderr, "Execution failed:", exception return False # Speak feedback message to user # #Parameters: # # 'words' -- string - Message to speak to user # #Returns: # # nothing def say( words ): if not confFile.get_opt_as_bool('DEFAULT.speak_up'): return words = words.replace( "\"", "\\\"" ) shellcmd([confFile.get_opt('DEFAULT.speak_command'), words]) # Scan for a limited time and return AP names and bssid found. # Access points we find will be put on the outgoing Queue, apQueue. # #Parameters: # # 'confFile' -- ConfigFile - Config file object # # 'apQueue' -- Queue - Queue on which to put AP profiles # # 'commandQueue' -- Queue - Queue from which to read commands # # 'logger' -- Logger - Python's logging facility # #Returns: # # nothing def scanning_thread(confFile, apQueue, commandQueue, logger, exit_event): logger.info("Begin thread.") # Setup our essid pattern matcher essid_pattern = re.compile( "ESSID\s*(:|=)\s*\"([^\"]+)\"", re.I | re.M | re.S ) bssid_pattern = re.compile( "Address\s*(:|=)\s*([a-zA-Z0-9:]+)", re.I | re.M | re.S ) protocol_pattern = re.compile( "Protocol\s*(:|=)\s*IEEE 802.11\s*([abgn]+)", re.I | re.M | re.S ) mode_pattern = re.compile( "Mode\s*(:|=)\s*([^\n]+)", re.I | re.M | re.S ) channel_pattern = re.compile( "Channel\s*(:|=)*\s*(\d+)", re.I | re.M | re.S ) enckey_pattern = re.compile( "Encryption key\s*(:|=)\s*(on|off)", re.I | re.M | re.S ) signal_pattern = re.compile( "Signal level\s*(:|=)\s*(-?[0-9]+)", re.I | re.M | re.S ) access_points = {} command = "scan" while True: try: command = commandQueue.get_nowait() logger.info("received command: %s" % (command, )) command_read = True except Queue.Empty: command_read = False device = get_network_device(confFile.get_opt('DEFAULT.interface')) if command == "scan": logger.debug("Beginning scan pass") # Some cards need to have the interface up to scan if confFile.get_opt_as_bool('DEFAULT.ifup_required'): # call ifconfig command and wait for return shellcmd([confFile.get_opt('DEFAULT.ifconfig_command'), device, 'up']) # update the signal strengths try: scandata = Popen([confFile.get_opt('DEFAULT.iwlist_command'), device, 'scan'], stdout=PIPE).stdout.read() except OSError, (errno, strerror): if errno == 2: logger.critical("iwlist command not found, please set this in the preferences.") scandata = "" # zero out the signal levels for all access points for bssid in access_points: access_points[bssid]['signal'] = 0 # split the scan data based on the address line hits = scandata.split(' - ') for hit in hits: # set the defaults for profile template profile = get_new_profile() m = essid_pattern.search( hit ) if m: # we found an essid profile['essid'] = m.groups()[1] m = bssid_pattern.search( hit ) # get BSSID from scan if m: profile['bssid'] = m.groups()[1] m = protocol_pattern.search( hit ) # get protocol from scan if m: profile['protocol'] = m.groups()[1] m = mode_pattern.search( hit ) # get mode from scan if m: profile['mode'] = m.groups()[1] m = channel_pattern.search( hit ) # get channel from scan if m: profile['channel'] = m.groups()[1] m = enckey_pattern.search( hit ) # get encryption key from scan if m: profile['encrypted'] = ( m.groups()[1] == 'on' ) m = signal_pattern.search( hit ) # get signal strength from scan if m: profile['signal'] = m.groups()[1] access_points[ profile['bssid'] ] = profile for bssid in access_points: access_points[bssid]['available'] = ( access_points[bssid]['signal'] > 0 ) # Put all, now or previously, sensed access_points into apQueue try: logger.debug("Scanned profile: %s" % (access_points[ bssid ], )) apQueue.put_nowait( access_points[bssid] ) except Queue.Full: pass if command_read: commandQueue.task_done() if exit_event.isSet(): logger.info("Exiting.") return if device.find('ath') == 0: sleep( 3 ) else: sleep( 1 ) # Manage a connection; including reporting connection state, # connecting/disconnecting from an AP, and returning current IP, ESSID, and BSSID. class ConnectionManager(): # Create a new connection manager which can read a config file and send to scanning thread # command Queue. A new manager checks for a pre-existing connection and takes # its AP profile from the ESSID and BSSID to which it is currently attached. # #Parameters: # # 'confFile' -- ConfigFile - Config file object # # 'commandQueue' -- Queue - The Queue on which to put commands to the scanning thread # # 'logger' -- Logger - Python's logging facility # #Returns: # # ConnectionManager instance def __init__( self, confFile, commandQueue, logger ): self.confFile = confFile self.commQueue = commandQueue self.logger = logger # is connection running? self.state = False if self.get_current_ip(): self.state = True self.profile = self.confFile.get_profile( make_section_name(self.get_current_essid(), self.get_current_bssid()) ) # Change the interface state: up or down. # #Parameters: # # 'state' -- string - The state to which to change the interface. # #Returns: # # nothing def if_change( self, state ): if ( (state.lower() == 'up') or (state.lower() == 'down') ): self.logger.info("changing interface state to %s" % (state, )) # call ifconfig command and wait for return shellcmd([self.confFile.get_opt('DEFAULT.ifconfig_command'), get_network_device(self.confFile.get_opt('DEFAULT.interface')), state]) # Return the WiFi encryption mode from evidence in the profile. # #Parameters: # # 'use_wpa' -- boolean - The use_wpa from the profile. # # 'key' -- string - The WEP key or empty string. # #Returns: # # string - none, wep, or wpa; indicates WiFi encryption mode def _get_enc_mode(self, use_wpa, key): if use_wpa: return 'wpa' elif key == '': return 'none' else: return 'wep' # Connect to the specified AP. # #Parameters: # # 'profile' -- dictionary - The profile for the AP (i.e. network) with which to connect. # # 'status' -- status implementer - Object which implements status interface. # #Returns: # # nothing def connect_to_network( self, profile, status ): self.profile = profile if self.profile['bssid'] == '': raise TypeError("Empty AP address") msg = "Connecting to the %s (%s) network" % ( self.profile['essid'], self.profile['bssid'] ) say( msg ) self.logger.info(msg) # Make a temporary copy of the DEFAULT.interface option. default_interface = self.confFile.get_opt('DEFAULT.interface') device = get_network_device(self.confFile.get_opt('DEFAULT.interface')) # Temporarily set the configured interface to a real one. self.confFile.set_opt('DEFAULT.interface', device) # ready to dance # Let's run the connection prescript if self.profile['con_prescript'].strip() != '': # got something to execute # run connection prescript through shell and wait for return self.logger.info("executing connection prescript: %s" % (self.profile['con_prescript'], )) shellcmd([self.profile['con_prescript']], environment = { "WIFIRADAR_PROFILE": make_section_name(self.profile['essid'], self.profile['bssid']), "WIFIRADAR_ENCMODE": self._get_enc_mode(self.profile['use_wpa'], self.profile['key']), "WIFIRADAR_SECMODE": self.profile['security'], "WIFIRADAR_IF": device or '' } ) status.show() # Some cards need to have the interface up if self.confFile.get_opt_as_bool('DEFAULT.ifup_required'): self.if_change('up') # Start building iwconfig command line, command iwconfig_command = [ self.confFile.get_opt('DEFAULT.iwconfig_command') ] iwconfig_command.append(device) # Setting essid iwconfig_command.append( 'essid' ) iwconfig_command.append( "'" + self.profile['essid'] + "'" ) # Setting nick #iwconfig_commands.append( 'nick "%s"' % self.profile['essid'] ) # Setting key iwconfig_command.append( 'key' ) if self.profile['key'] == '': iwconfig_command.append( 'off' ) else: # Setting this stops association from working, so remove it for now #if self.profile['security'] != '': #iwconfig_command.append(self.profile['security']) iwconfig_command.append( "'" + self.profile['key'] + "'" ) #iwconfig_commands.append( "key %s %s" % ( self.profile['security'], self.profile['key'] ) ) # Setting mode if self.profile['mode'].lower() == 'master' or self.profile['mode'].lower() == 'auto': self.profile['mode'] = 'Managed' iwconfig_command.append( 'mode' ) iwconfig_command.append( self.profile['mode'] ) # Setting channel if self.profile['channel'] != '': iwconfig_command.append( 'channel' ) iwconfig_command.append( self.profile['channel'] ) # Now we do the ap by address (do this last since iwconfig seems to want it only there) iwconfig_command.append( 'ap' ) iwconfig_command.append( self.profile['bssid'] ) # Some cards require a commit if self.confFile.get_opt_as_bool('DEFAULT.commit_required'): iwconfig_command.append( 'commit' ) self.logger.info("iwconfig_command: %s" % (iwconfig_command, )) # call iwconfig command and wait for return if not shellcmd(iwconfig_command): return # Now normal network stuff # Kill off any existing DHCP clients running if os.path.isfile(self.confFile.get_opt('DHCP.pidfile')): self.logger.info("Killing existing DHCP...") try: if self.confFile.get_opt('DHCP.kill_args') != '': # call DHCP client kill command and wait for return shellcmd([self.confFile.get_opt('DHCP.command'), self.confFile.get_opt('DHCP.kill_args')]) else: os.kill(int(open(self.confFile.get_opt('DHCP.pidfile'), mode='r').readline()), SIGTERM) except OSError: print "failed to kill DHCP client" sys.exit() finally: print "Stale pid file. Removing..." os.remove(self.confFile.get_opt('DHCP.pidfile')) # Kill off any existing WPA supplicants running if os.access(self.confFile.get_opt('WPA.pidfile'), os.R_OK): self.logger.info("Killing existing WPA supplicant...") try: if not self.confFile.get_opt('WPA.kill_command') != '': # call WPA supplicant kill command and wait for return shellcmd([self.confFile.get_opt('WPA.kill_command'), self.confFile.get_opt('WPA.kill_command')]) else: os.kill(int(open(self.confFile.get_opt('WPA.pidfile'), mode='r').readline()), SIGTERM) except OSError: print "failed to kill WPA supplicant" sys.exit() finally: print "Stale pid file. Removing..." os.remove(self.confFile.get_opt('WPA.pidfile')) self.logger.debug("Disable scan while connection attempt in progress...") try: self.commQueue.put("pause") except Queue.Full: pass # Begin WPA supplicant if self.profile['use_wpa'] : self.logger.info("WPA args: %s" % (self.confFile.get_opt('WPA.args'), )) status.update_message("WPA supplicant starting") if sys.modules.has_key("gtk"): while gtk.events_pending(): gtk.main_iteration(False) # call WPA supplicant command and do not wait for return try: wpa_proc = shellcmd([self.confFile.get_opt('WPA.command'), self.confFile.get_opt('WPA.args')]) if sys.modules.has_key("gtk"): while gtk.events_pending(): gtk.main_iteration(False) sleep(2) except OSError, (errno, strerror): if errno == 2: logger.critical("WPA supplicant not found, please set this in the preferences.") if self.profile['use_dhcp'] : status.update_message("Acquiring IP Address (DHCP)") if sys.modules.has_key("gtk"): while gtk.events_pending(): gtk.main_iteration(False) # call DHCP client command and do not wait for return dhcp_command = [ self.confFile.get_opt('DHCP.command') ] dhcp_command.extend( self.confFile.get_opt('DHCP.args').split(' ') ) dhcp_command.append(device) self.logger.info("dhcp_command: %s" % (dhcp_command, )) try: dhcp_proc = Popen(dhcp_command, stdout=None) except OSError, (errno, strerror): if errno == 2: logger.critical("DHCP client not found, please set this in the preferences.") timer = self.confFile.get_opt_as_int('DHCP.timeout') + 3 tick = 0.25 waiting = dhcp_proc.poll() while waiting == None: waiting = dhcp_proc.poll() if timer < 0: os.kill(dhcp_proc.pid, SIGTERM) break if sys.modules.has_key("gtk"): while gtk.events_pending(): gtk.main_iteration(False) timer -= tick sleep(tick) if not self.get_current_ip(): status.update_message("Could not get IP address!") if sys.modules.has_key("gtk"): while gtk.events_pending(): gtk.main_iteration(False) sleep(1) if self.state: self.disconnect_interface() status.hide() return else: status.update_message("Got IP address. Done.") self.state = True if sys.modules.has_key("gtk"): while gtk.events_pending(): gtk.main_iteration(False) sleep(2) else: ifconfig_command= "%s %s down; %s %s %s netmask %s" % ( self.confFile.get_opt('DEFAULT.ifconfig_command'), device, self.confFile.get_opt('DEFAULT.ifconfig_command'), device, self.profile['ip'], self.profile['netmask'] ) route_command = "%s add default gw %s" % ( self.confFile.get_opt('DEFAULT.route_command'), self.profile['gateway'] ) resolv_contents = '' if self.profile['domain'] != '': resolv_contents += "domain %s\n" % self.profile['domain'] if self.profile['dns1'] != '': resolv_contents += "nameserver %s\n" % self.profile['dns1'] if self.profile['dns2'] != '': resolv_contents += "nameserver %s\n" % self.profile['dns2'] if ( resolv_contents != '' ): resolv_file=open('/etc/resolv.conf', 'w') resolv_file.write(resolv_contents) resolv_file.close if not shellcmd([ifconfig_command]): return if not shellcmd([route_command]): return self.state = True # Re-enable iwlist try: self.commQueue.put("scan") except Queue.Full: pass # Let's run the connection postscript con_postscript = self.profile['con_postscript'] if self.profile['con_postscript'].strip() != '': self.logger.info("executing connection postscript: %s" % (self.profile['con_postscript'], )) shellcmd([self.profile['con_postscript']], environment = { "WIFIRADAR_IP": self.get_current_ip() or '0.0.0.0', "WIFIRADAR_ESSID": self.get_current_essid() or '', "WIFIRADAR_BSSID": self.get_current_bssid() or '00:00:00:00:00:00', "WIFIRADAR_PROFILE": make_section_name(self.profile['essid'], self.profile['bssid']), "WIFIRADAR_ENCMODE": self._get_enc_mode(self.profile['use_wpa'], self.profile['key']), "WIFIRADAR_SECMODE": self.profile['security'], "WIFIRADAR_IF": device or '' } ) # Set the configured interface back to original value. self.confFile.set_opt('DEFAULT.interface', default_interface) status.hide() # Disconnect from the AP with which a connection has been established/attempted. # #Parameters: # # nothing # #Returns: # # nothing def disconnect_interface( self ): msg = "Disconnecting" say( msg ) self.logger.info(msg) # Make a temporary copy of the DEFAULT.interface option. default_interface = self.confFile.get_opt('DEFAULT.interface') device = get_network_device(self.confFile.get_opt('DEFAULT.interface')) # Temporarily set the configured interface to a real one. self.confFile.set_opt('DEFAULT.interface', device) # Pause scanning while manipulating card try: self.commQueue.put("pause") self.commQueue.join() except Queue.Full: pass if self.state: self.profile = self.confFile.get_profile(make_section_name(self.get_current_essid(), self.get_current_bssid())) if not self.profile: self.profile = self.confFile.get_profile(make_section_name(self.get_current_essid(), '')) if not self.profile: raise KeyError # Let's run the disconnection prescript if self.profile['dis_prescript'].strip() != '': self.logger.info("executing disconnection prescript: %s" % (self.profile['dis_prescript'], )) shellcmd([self.profile['dis_prescript']], environment = { "WIFIRADAR_IP": self.get_current_ip() or '0.0.0.0', "WIFIRADAR_ESSID": self.get_current_essid() or '', "WIFIRADAR_BSSID": self.get_current_bssid() or '00:00:00:00:00:00', "WIFIRADAR_PROFILE": make_section_name(self.profile['essid'], self.profile['bssid']), "WIFIRADAR_ENCMODE": self._get_enc_mode(self.profile['use_wpa'], self.profile['key']), "WIFIRADAR_SECMODE": self.profile['security'], "WIFIRADAR_IF": device or '' } ) self.logger.info("Kill off any existing DHCP clients running...") if os.path.isfile(self.confFile.get_opt('DHCP.pidfile')): self.logger.info("Killing existing DHCP...") try: if self.confFile.get_opt('DHCP.kill_args').strip() != '': dhcp_command = [ self.confFile.get_opt('DHCP.command') ] dhcp_command.extend( self.confFile.get_opt('DHCP.kill_args').split(' ') ) dhcp_command.append(device) self.logger.info("DHCP command: %s" % (dhcp_command, )) # call DHCP client command and wait for return if not shellcmd(dhcp_command): return else: self.logger.info("Killing DHCP manually...") os.kill(int(open(self.confFile.get_opt('DHCP.pidfile'), mode='r').readline()), SIGTERM) except OSError: print "failed to kill DHCP client" self.logger.info("Kill off any existing WPA supplicants running...") if os.access(self.confFile.get_opt('WPA.pidfile'), os.R_OK): self.logger.info("Killing existing WPA supplicant...") try: if self.confFile.get_opt('WPA.kill_command') != '': wpa_command = [ self.confFile.get_opt('WPA.kill_command').split(' ') ] if not shellcmd(wpa_command): return else: os.kill(int(open(self.confFile.get_opt('WPA.pidfile'), mode='r').readline()), SIGTERM) except OSError: print "failed to kill WPA supplicant" self.logger.info("Let's clear out the wireless stuff") shellcmd([self.confFile.get_opt('DEFAULT.iwconfig_command'), device, 'essid', 'any', 'key', 'off', 'mode', 'managed', 'channel', 'auto', 'ap', 'off']) self.logger.info("Now take the interface down") self.logger.info("Since it may be brought back up by the next scan, lets unset its IP") shellcmd([self.confFile.get_opt('DEFAULT.ifconfig_command'), device, '0.0.0.0']) # taking down the interface too quickly can crash my system, so pause a moment sleep(1) self.if_change('down') # Let's run the disconnection postscript if self.profile['dis_postscript'].strip() != '': self.logger.info("executing disconnection postscript: %s" % (self.profile['dis_postscript'], )) shellcmd([self.profile['dis_postscript']], environment = { "WIFIRADAR_PROFILE": make_section_name(self.profile['essid'], self.profile['bssid']), "WIFIRADAR_ENCMODE": self._get_enc_mode(self.profile['use_wpa'], self.profile['key']), "WIFIRADAR_SECMODE": self.profile['security'], "WIFIRADAR_IF": device or '' } ) self.state = False self.logger.info("Disconnect complete.") # Begin scanning again try: self.commQueue.put("scan") except Queue.Full: pass # Set the configured interface back to original value. self.confFile.set_opt('DEFAULT.interface', default_interface) # Returns the current IP, if any, by calling ifconfig. # #Parameters: # # nothing # #Returns: # # string or None -- the IP address or None (if no there is no current connection) def get_current_ip( self ): ifconfig_command = [confFile.get_opt('DEFAULT.ifconfig_command'), get_network_device(confFile.get_opt('DEFAULT.interface'))] try: ifconfig_info = Popen(ifconfig_command, stdout=PIPE).stdout except OSError, (errno, strerror): if errno == 2: logger.critical("ifconfig command not found, please set this in the preferences.") ifconfig_info = open("/dev/null", "r") # Be careful to the language (inet adr: in French for example) # # Hi Brian # # I'm using wifi-radar on a system with German translations (de_CH-UTF-8). # There the string in ifconfig is inet Adresse for the IP which isn't # found by the current get_current_ip function in wifi-radar. I changed # the according line (#289; gentoo, v1.9.6-r1) to # >ip_re = re.compile(r'inet [Aa]d?dr[^.]*:([^.]*\.[^.]*\.[^.]*\.[0-9]*)') # which works on my system (LC_ALL=de_CH.UTF-8) and still works with LC_ALL=C. # # I'd be happy if you could incorporate this small change because as now # I've got to change the file every time it is updated. # # Best wishes # # Simon ip_re = re.compile(r'inet [Aa]d?dr[^.]*:([^.]*\.[^.]*\.[^.]*\.[0-9]*)') line = ifconfig_info.read() if ip_re.search( line ): return ip_re.search( line ).group(1) return None # Returns the current ESSID, if any, by calling iwconfig. # #Parameters: # # nothing # #Returns: # # string or None -- the ESSID or None (if no there is no current association) def get_current_essid( self ): """Returns the current ESSID if any by calling iwconfig""" try: iwconfig_info = Popen([self.confFile.get_opt('DEFAULT.iwconfig_command'), get_network_device(self.confFile.get_opt('DEFAULT.interface'))], stdout=PIPE, stderr=STDOUT).stdout except OSError, (errno, strerror): if errno == 2: logger.critical("iwconfig command not found, please set this in the preferences.") iwconfig_info = open("/dev/null", "r") # Be careful to the language (inet adr: in French for example) essid_re = re.compile( "ESSID\s*(:|=)\s*\"([^\"]+)\"", re.I | re.M | re.S ) line = iwconfig_info.read() if essid_re.search( line ): return essid_re.search( line ).group(2) return None # Returns the current BSSID, if any, by calling iwconfig. # #Parameters: # # nothing # #Returns: # # string or None -- the BSSID or None (if no there is no current association) def get_current_bssid( self ): """Returns the current BSSID if any by calling iwconfig""" try: iwconfig_info = Popen([self.confFile.get_opt('DEFAULT.iwconfig_command'), get_network_device(self.confFile.get_opt('DEFAULT.interface'))], stdout=PIPE, stderr=STDOUT).stdout except OSError, (errno, strerror): if errno == 2: logger.critical("iwconfig command not found, please set this in the preferences.") iwconfig_info = open("/dev/null", "r") bssid_re = re.compile( "Access Point\s*(:|=)\s*([a-zA-Z0-9:]+)", re.I | re.M | re.S ) line = iwconfig_info.read() if bssid_re.search( line ): return bssid_re.search( line ).group(2) return None # The main user interface window for WiFi Radar. This class also is the control # center for most of the rest of the operations. class radar_window: # Create a new radar_window. # #Parameters: # # 'confFile' -- ConfigFile - The config file in which to store/read settings. # # 'apQueue' -- Queue - The Queue from which AP profiles are read. # # 'commQueue' -- Queue - The Queue to which to send commands to the scanning thread. # # 'logger' -- Logger - Python's logging facility # #Returns: # # radar_window instance def __init__(self, confFile, apQueue, commQueue, logger, exit_event): global signal_xpm_none global signal_xpm_low global signal_xpm_barely global signal_xpm_ok global signal_xpm_best global known_profile_icon global unknown_profile_icon global wifi_radar_icon self.confFile = confFile self.apQueue = apQueue self.commandQueue = commQueue self.logger = logger self.access_points = {} self.exit_event = exit_event self.connection = None self.known_profile_icon = gtk.gdk.pixbuf_new_from_inline( len( known_profile_icon[0] ), known_profile_icon[0], False ) self.unknown_profile_icon = gtk.gdk.pixbuf_new_from_inline( len( unknown_profile_icon[0] ), unknown_profile_icon[0], False ) self.signal_none_pb = gtk.gdk.pixbuf_new_from_xpm_data( signal_xpm_none ) self.signal_low_pb = gtk.gdk.pixbuf_new_from_xpm_data( signal_xpm_low ) self.signal_barely_pb = gtk.gdk.pixbuf_new_from_xpm_data( signal_xpm_barely ) self.signal_ok_pb = gtk.gdk.pixbuf_new_from_xpm_data( signal_xpm_ok ) self.signal_best_pb = gtk.gdk.pixbuf_new_from_xpm_data( signal_xpm_best ) self.window = gtk.Dialog('WiFi Radar', None, gtk.DIALOG_MODAL ) icon = gtk.gdk.pixbuf_new_from_inline( len( wifi_radar_icon[0] ), wifi_radar_icon[0], False ) self.window.set_icon( icon ) self.window.set_border_width( 10 ) self.window.set_size_request( 550, 300 ) self.window.set_title( "WiFi Radar" ) self.window.connect( 'delete_event', self.delete_event ) self.window.connect( 'destroy', self.destroy ) # let's create all our widgets self.current_network = gtk.Label() self.current_network.set_property('justify', gtk.JUSTIFY_CENTER) self.current_network.show() self.close_button = gtk.Button( "Close", gtk.STOCK_CLOSE ) self.close_button.show() self.close_button.connect( 'clicked', self.delete_event, None ) self.about_button = gtk.Button( "About", gtk.STOCK_ABOUT ) self.about_button.show() self.about_button.connect( 'clicked', self.show_about_info, None ) self.preferences_button = gtk.Button( "Preferences", gtk.STOCK_PREFERENCES ) self.preferences_button.show() self.preferences_button.connect( 'clicked', self.edit_preferences, None ) # essid + bssid known_icon known available wep_icon signal_level mode protocol channel self.pstore = gtk.ListStore( str, gtk.gdk.Pixbuf, bool, bool, str, gtk.gdk.Pixbuf, str, str, str ) self.plist = gtk.TreeView( self.pstore ) # The icons column, known and encryption self.pix_cell = gtk.CellRendererPixbuf() self.wep_cell = gtk.CellRendererPixbuf() self.icons_cell = gtk.CellRendererText() self.icons_col = gtk.TreeViewColumn() self.icons_col.pack_start( self.pix_cell, False ) self.icons_col.pack_start( self.wep_cell, False ) self.icons_col.add_attribute( self.pix_cell, 'pixbuf', 1 ) self.icons_col.add_attribute( self.wep_cell, 'stock-id', 4 ) self.plist.append_column( self.icons_col ) # The AP column self.ap_cell = gtk.CellRendererText() self.ap_col = gtk.TreeViewColumn( "Access Point" ) self.ap_col.pack_start( self.ap_cell, True ) self.ap_col.add_attribute( self.ap_cell, 'text', 0 ) self.plist.append_column( self.ap_col ) # The signal column self.sig_cell = gtk.CellRendererPixbuf() self.signal_col = gtk.TreeViewColumn( "Signal" ) self.signal_col.pack_start( self.sig_cell, True ) self.signal_col.add_attribute( self.sig_cell, 'pixbuf', 5 ) self.plist.append_column( self.signal_col ) # The mode column self.mode_cell = gtk.CellRendererText() self.mode_col = gtk.TreeViewColumn( "Mode" ) self.mode_col.pack_start( self.mode_cell, True ) self.mode_col.add_attribute( self.mode_cell, 'text', 6 ) self.plist.append_column( self.mode_col ) # The protocol column self.prot_cell = gtk.CellRendererText() self.protocol_col = gtk.TreeViewColumn( "802.11" ) self.protocol_col.pack_start( self.prot_cell, True ) self.protocol_col.add_attribute( self.prot_cell, 'text', 7 ) self.plist.append_column( self.protocol_col ) # The channel column self.channel_cell = gtk.CellRendererText() self.channel_col = gtk.TreeViewColumn( "Channel" ) self.channel_col.pack_start( self.channel_cell, True ) self.channel_col.add_attribute( self.channel_cell, 'text', 8 ) self.plist.append_column( self.channel_col ) # DnD Ordering self.plist.set_reorderable( True ) # detect d-n-d of AP in round-about way, since rows-reordered does not work as advertised self.pstore.connect( 'row-deleted', self.update_auto_profile_order ) # enable/disable buttons based on the selected network self.selected_network = self.plist.get_selection() self.selected_network.connect( 'changed', self.on_network_selection, None ) # the list scroll bar sb = gtk.VScrollbar( self.plist.get_vadjustment() ) sb.show() self.plist.show() # Add New button self.new_button = gtk.Button( "_New" ) self.new_button.connect( 'clicked', self.create_new_profile, get_new_profile(), None ) self.new_button.show() # Add Configure button self.edit_button = gtk.Button( "C_onfigure" ) self.edit_button.connect( 'clicked', self.edit_profile, None ) self.edit_button.show() self.edit_button.set_sensitive(False) # Add Delete button self.delete_button = gtk.Button( "_Delete" ) self.delete_button.connect('clicked', self.delete_profile_with_check, None) self.delete_button.show() self.delete_button.set_sensitive(False) # Add Connect button self.connect_button = gtk.Button( "Co_nnect" ) self.connect_button.connect( 'clicked', self.connect_profile, None ) # Add Disconnect button self.disconnect_button = gtk.Button( "D_isconnect" ) self.disconnect_button.connect( 'clicked', self.disconnect_profile, None ) # lets add our widgets rows = gtk.VBox( False, 3 ) net_list = gtk.HBox( False, 0 ) listcols = gtk.HBox( False, 0 ) prows = gtk.VBox( False, 0 ) # lets start packing # the network list net_list.pack_start( self.plist, True, True, 0 ) net_list.pack_start( sb, False, False, 0 ) # the rows level rows.pack_start( net_list , True, True, 0 ) rows.pack_start( self.current_network, False, True, 0 ) # the list columns listcols.pack_start( rows, True, True, 0 ) listcols.pack_start( prows, False, False, 5 ) # the list buttons prows.pack_start( self.new_button, False, False, 2 ) prows.pack_start( self.edit_button, False, False, 2 ) prows.pack_start( self.delete_button, False, False, 2 ) prows.pack_end( self.connect_button, False, False, 2 ) prows.pack_end( self.disconnect_button, False, False, 2 ) self.window.action_area.pack_start( self.about_button ) self.window.action_area.pack_start( self.preferences_button ) self.window.action_area.pack_start( self.close_button ) rows.show() prows.show() listcols.show() self.window.vbox.add( listcols ) self.window.vbox.set_spacing( 3 ) self.window.show_all() # # Now, immediately hide these two. The proper one will be # displayed later, based on interface state. -BEF- self.disconnect_button.hide() self.connect_button.hide() self.connect_button.set_sensitive(False) # set up connection manager for later use self.connection = ConnectionManager( self.confFile, self.commandQueue, self.logger ) # set up status window for later use self.status_window = StatusWindow( self ) self.status_window.cancel_button.connect('clicked', self.disconnect_profile, "cancel") # Add our known profiles in order for profile_name in self.confFile.auto_profile_order: profile_name = profile_name.strip() self.access_points[profile_name] = self.confFile.get_profile(profile_name) wep = None if self.access_points[profile_name]['encrypted']: wep = gtk.STOCK_DIALOG_AUTHENTICATION if self.access_points[profile_name]['roaming']: ap_name = self.access_points[profile_name]['essid'] + "\n" + ' Multiple APs' else: ap_name = self.access_points[profile_name]['essid'] + "\n" + self.access_points[profile_name]['bssid'] self.pstore.append([ap_name, self.known_profile_icon, self.access_points[profile_name]['known'], self.access_points[profile_name]['available'], wep, self.signal_none_pb, self.access_points[profile_name]['mode'], self.access_points[profile_name]['protocol'], self.access_points[profile_name]['channel'] ] ) # This is the first run (or, at least, no config file was present), so pop up the preferences window if ( self.confFile.get_opt_as_bool('DEFAULT.new_file') == True ): self.confFile.remove_option('DEFAULT', 'new_file') self.edit_preferences(self.preferences_button) # Begin running radar_window in Gtk event loop. # #Parameters: # # nothing # #Returns: # # nothing def main( self ): gtk.main() # Quit application. # #Parameters: # # 'widget' -- gtk.Widget - The widget sending the event. # #Returns: # # nothing def destroy( self, widget = None): if self.status_window: self.status_window.destroy() gtk.main_quit() # Kill scanning thread, update profile order for config file, and ask to be destroyed. # #Parameters: # # 'widget' -- gtk.Widget - The widget sending the event. # # 'data' -- tuple - list of arbitrary arguments (not used) # #Returns: # # boolean -- always return False (i.e. do not propigate the signal which called) def delete_event( self, widget, data = None ): # Let other threads know it is time to exit self.exit_event.set() # Wait for all other threads to exit before continuing while threading.activeCount() > 1: sleep(0.25) self.destroy() return False # Update the current ip and essid shown to user. # #Parameters: # # nothing # #Returns: # # nothing def update_network_info(self): if self.connection and self.connection.state: self.current_network.set_text( "Connected to %s\nIP Address %s" % (make_section_name(self.connection.get_current_essid(), self.connection.get_current_bssid()), self.connection.get_current_ip())) else: self.current_network.set_text("Not Connected.") # Set the state of connect/disconnect buttons based on whether we have a connection. # #Parameters: # # nothing # #Returns: # # nothing def update_connect_buttons(self): if self.connection and self.connection.state: self.connect_button.hide() self.disconnect_button.show() else: self.disconnect_button.hide() self.connect_button.show() # Updates the on-screen profiles list. # #Parameters: # # 'ap' -- dictionary -- The AP found by scanning_thread. # #Returns: # # nothing def update_plist_items(self, ap): # Check for roaming profile. ap_name = make_section_name(ap['essid'], '') profile = self.confFile.get_profile(ap_name) prow_iter = self.get_row_by_ap(ap['essid'], ' Multiple APs') ap_display = ap['essid'] + "\n" + ' Multiple APs' if not profile: # Check for normal profile. ap_name = make_section_name(ap['essid'], ap['bssid']) profile = self.confFile.get_profile(ap_name) prow_iter = self.get_row_by_ap(ap['essid'], ap['bssid']) ap_display = ap['essid'] + "\n" + ap['bssid'] if not profile: # No profile, so make a new one. profile = get_new_profile() wep = None if prow_iter != None: # the AP is in the list of APs on the screen # Set the 'known' values; False is default, overridden to True by self.access_points ap['known'] = self.access_points[ap_name]['known'] self.pstore.set_value(prow_iter, 1, self.pixbuf_from_known(ap['known'])) self.pstore.set_value(prow_iter, 2, ap['known']) self.pstore.set_value(prow_iter, 3, ap['available']) if ap['encrypted']: wep = gtk.STOCK_DIALOG_AUTHENTICATION self.pstore.set_value(prow_iter, 4, wep) self.pstore.set_value(prow_iter, 5, self.pixbuf_from_signal(self.access_points[ap_name]['signal'])) self.pstore.set_value(prow_iter, 6, ap['mode']) self.pstore.set_value(prow_iter, 7, ap['protocol']) self.pstore.set_value(prow_iter, 8, self.access_points[ap_name]['channel']) else: # the AP is not in the list of APs on the screen self.pstore.append([ap_display, self.pixbuf_from_known(ap['known']), ap['known'], ap['available'], wep, self.pixbuf_from_signal(ap['signal']), ap['mode'], ap['protocol'], ap['channel']]) #print "update_plist_items: new ap", ap[ 'essid' ], ap['bssid'] # Updates the record-keeping profiles list. # #Parameters: # # 'ap' -- dictionary -- The AP found by scanning_thread. # #Returns: # # nothing def update_ap_list(self, ap): # Check for roaming profile. ap_name = make_section_name(ap['essid'], '') profile = self.confFile.get_profile(ap_name) if not profile: # Check for normal profile. ap_name = make_section_name(ap['essid'], ap['bssid']) profile = self.confFile.get_profile(ap_name) if not profile: # No profile, so make a new one. profile = get_new_profile() if self.access_points.has_key(ap_name): # This AP has been configured and should be updated self.access_points[ap_name]['known'] = profile['known'] self.access_points[ap_name]['available'] = ap['available'] self.access_points[ap_name]['encrypted'] = ap['encrypted'] self.access_points[ap_name]['mode'] = ap['mode'] self.access_points[ap_name]['protocol'] = ap['protocol'] if self.access_points[ap_name]['roaming']: # Roaming if self.access_points[ap_name]['bssid'] == ap['bssid']: # Same AP for this roaming profile self.access_points[ap_name]['signal'] = ap['signal'] else: # Different AP if int(self.access_points[ap_name]['signal']) < int(ap['signal']): # Stronger signal with this AP, so promote it to preferred self.access_points[ap_name]['signal'] = ap['signal'] self.access_points[ap_name]['channel'] = ap['channel'] self.access_points[ap_name]['bssid'] = ap['bssid'] else: # Not roaming self.access_points[ap_name]['signal'] = ap['signal'] self.access_points[ap_name]['channel'] = ap['channel'] else: # Not seen before, begin tracking it. self.access_points[ap_name] = profile # Updates the main user interface. # #Parameters: # # nothing # #Returns: # # boolean -- always return True def update_window(self): # Indicate to PyGtk that only one Gtk thread should run here gtk.gdk.threads_enter() self.update_network_info() self.update_connect_buttons() while True: # Get APs scanned by iwlist try: ap = self.apQueue.get_nowait() except Queue.Empty: break else: self.update_ap_list(ap) self.update_plist_items(ap) # Allow other Gtk threads to run gtk.gdk.threads_leave() return True # Return the proper icon for a value of known. # #Parameters: # # 'known' -- boolean - Whether the AP is known (i.e. configured) # #Returns: # # gtk.gdk.Pixbuf -- icon for a known or unknown AP def pixbuf_from_known( self, known ): """ return the proper icon for value of known """ if known: return self.known_profile_icon else: return self.unknown_profile_icon # Return an icon indicating the signal level. # #Parameters: # # 'signal' -- integer - signal level reported by iwlist (may be arbitrary scale in 0-100 or -X dBm) # #Returns: # # gtk.gdk.Pixbuf -- 1 of 5 icons indicating signal level def pixbuf_from_signal( self, signal ): signal = int( signal ) # shift signal up by 80 to convert dBm scale to arbitrary scale if signal < 0: signal = signal + 80 #print "signal level:", signal if signal < 3: return self.signal_none_pb elif signal < 12: return self.signal_low_pb elif signal < 20: return self.signal_barely_pb elif signal < 35: return self.signal_ok_pb elif signal >= 35: return self.signal_best_pb else: return None # Return row which holds specified ESSID and BSSID. # #Parameters: # # 'essid' -- string - ESSID to match # # 'bssid' -- string - BSSID to match # #Returns: # # gtk.TreeIter or None -- pointer to the row containing the match or None for no match found def get_row_by_ap( self, essid, bssid ): if bssid == "roaming": for row in self.pstore: if (row[0][:row[0].find("\n")] == essid): #print "roaming match:", row.iter, essid, bssid return row.iter else: for row in self.pstore: if (row[0] == essid + "\n" + bssid): #print "normal match:", row.iter, essid, bssid return row.iter return None # Enable/disable buttons based on the selected network. # #Parameters: # # 'widget' -- gtk.Widget - The widget sending the event. # # 'data' -- tuple - list of arbitrary arguments (not used) # #Returns: # # nothing def on_network_selection( self, widget, data = None ): ( store, selected_iter ) = self.selected_network.get_selected() #print self.access_points[( make_section_name( store.get_value( selected_iter, 0 ), store.get_value( selected_iter, 1 ) ) )] # if no networks are selected, disable all buttons except New # (this occurs after a drag-and-drop) if selected_iter == None: self.edit_button.set_sensitive(False) self.delete_button.set_sensitive(False) self.connect_button.set_sensitive(False) return # enable/disable buttons self.connect_button.set_sensitive(True) if (store.get_value(selected_iter, 2) == True): # is selected network known? self.edit_button.set_sensitive(True) self.delete_button.set_sensitive(True) else: self.edit_button.set_sensitive(True) self.delete_button.set_sensitive(False) # Init and run the about dialog # #Parameters: # # 'widget' -- gtk.Widget - The widget sending the event. # # 'data' -- tuple - list of arbitrary arguments (not used) # #Returns: # # nothing def show_about_info( self, widget, data=None ): about = about_dialog() about.run() about.destroy() # Init and run the preferences dialog # #Parameters: # # 'widget' -- gtk.Widget - The widget sending the event. # # 'data' -- tuple - list of arbitrary arguments (not used) # #Returns: # # nothing def edit_preferences( self, widget, data=None ): # get raw strings from config file self.confFile.raw = True prefs = preferences_dialog( self, self.confFile ) response = prefs.run() if response == int(gtk.RESPONSE_ACCEPT): prefs.save() prefs.destroy() # get cooked strings from config file self.confFile.raw = False # Respond to a request to create a new AP profile # #Parameters: # # 'widget' -- gtk.Widget - The widget sending the event. # # 'profile' -- dictionary - The AP profile to use as basis for new profile. # # 'data' -- tuple - list of arbitrary arguments (not used) # #Returns: # # boolean -- True if a profile was created and False if profile creation was canceled. def create_new_profile( self, widget, profile, data=None ): profile_editor = profile_dialog( self, profile ) try: profile = profile_editor.run() except ValueError: error_dlg = ErrorDialog(None, "Cannot save empty ESSID") del error_dlg return False finally: profile_editor.destroy() if profile: (store, selected_iter) = self.plist.get_selection().get_selected() if selected_iter is not None: store.remove(selected_iter) if profile['roaming']: apname = make_section_name(profile['essid'], '') else: apname = make_section_name(profile['essid'], profile['bssid']) # Check that the ap does not exist already if apname in self.confFile.profiles(): error_dlg = ErrorDialog(None, "A profile for %s already exists" % (apname)) del error_dlg # try again self.access_points[ apname ] = profile self.confFile.set_section( apname, profile ) # if it is not in the auto_profile_order add it if apname not in self.confFile.auto_profile_order: self.confFile.auto_profile_order.insert(0, apname) # add to the store wep = None if profile['encrypted']: wep = gtk.STOCK_DIALOG_AUTHENTICATION try: self.confFile.write() except IOError, (error_number, error_str): if error_number == errno.ENOENT: error_dlg = ErrorDialog( self.window, "Could not save configuration file:\n%s\n\n%s" % (self.confFile.filename, error_str) ) del error_dlg else: raise IOError(error_number, error_str) # Add AP to the list displayed to user if profile['roaming']: ap_name = profile['essid'] + "\n" + ' Multiple APs' while True: prow_iter = self.get_row_by_ap(profile['essid'], 'roaming') if prow_iter: self.pstore.remove(prow_iter) else: break else: ap_name = profile['essid'] + "\n" + profile['bssid'] self.pstore.prepend([ap_name, self.pixbuf_from_known(profile['known']), profile['known'], profile['available'], wep, self.pixbuf_from_signal(profile['signal']), profile['mode'], profile['protocol'], profile['channel']]) return True else: # Did not create new profile return False # Respond to a request to edit an AP profile. Edit selected AP profile if it # is known. Otherwise, create a new profile with the selected ESSID and BSSID. # #Parameters: # # 'widget' -- gtk.Widget - The widget sending the event. # # 'data' -- tuple - list of arbitrary arguments (not used) # #Returns: # # nothing def edit_profile(self, widget, data=None): (store, selected_iter) = self.plist.get_selection().get_selected() if not selected_iter: # No AP is selected return (essid, bssid) = str(self.pstore.get_value(selected_iter, 0)).split("\n") if bssid == ' Multiple APs': # AP list says this is a roaming profile apname = make_section_name(essid, '') else: # AP list says this is NOT a roaming profile apname = make_section_name(essid, bssid) profile = self.confFile.get_profile(apname) if profile: # A profile was found in the config file profile['bssid'] = self.access_points[apname]['bssid'] profile_editor = profile_dialog(self, profile) try: # try editing the profile edited_profile = profile_editor.run() except ValueError: error_dlg = ErrorDialog(None, "Cannot save empty ESSID") del error_dlg return False finally: # Always remove profile editor window from screen profile_editor.destroy() if edited_profile: # A profile was returned by the editor old_index = None row = None if edited_profile['essid'] != profile['essid'] or edited_profile['bssid'] != profile['bssid'] or edited_profile['roaming'] != profile['roaming']: # ESSID, BSSID, or roaming was changed in profile editor try: self.commandQueue.put('pause') self.commandQueue.join() except Queue.Full: pass if profile['roaming']: # The old profile was a roaming profile old_ap = make_section_name(profile['essid'], '') else: # The old profile was NOT a roaming profile old_ap = make_section_name(profile['essid'], profile['bssid']) # Find where old profile was in auto order old_index = self.confFile.auto_profile_order.index(old_ap) # Remove old profile and get its place in AP list row = self.delete_profile(selected_iter, old_ap) self.confFile.remove_section(old_ap) try: # Add AP to the list displayed to user self.apQueue.put_nowait(edited_profile) self.commandQueue.put('scan') except Queue.Full: pass if edited_profile['roaming']: # New profile is a roaming profile apname = make_section_name(edited_profile['essid'], '') ap_display = edited_profile['essid'] + "\n" + ' Multiple APs' # Remove all other profiles that match the new profile ESSID while True: prow_iter = self.get_row_by_ap(edited_profile['essid'], 'roaming') if prow_iter: self.pstore.remove(prow_iter) else: break else: # New profile is NOT a roaming profile apname = make_section_name(edited_profile['essid'], edited_profile['bssid']) ap_display = edited_profile['essid'] + "\n" + edited_profile['bssid'] # Insert the new profile in the same position as the one being replaced if old_index != None: # Old profile was in auto order list self.confFile.auto_profile_order.insert(old_index, apname) if ((row is not None) and (self.pstore.iter_is_valid(row))): self.pstore.insert_before(row, [ap_display, None, None, None, None, None, None, None, None]) self.access_points[apname] = edited_profile self.confFile.set_section(apname, edited_profile) try: # Save updated profile to config file self.confFile.write() except IOError, (error_number, error_str): if error_number == errno.ENOENT: error_dlg = ErrorDialog(self.window, "Could not save configuration file:\n%s\n\n%s" % (self.confFile.filename, error_str)) del error_dlg else: raise IOError(error_number, error_str) else: # The AP does not already have a profile profile = get_new_profile() ( profile['essid'], profile['bssid'] ) = store.get_value( selected_iter, 0 ).split("\n") self.create_new_profile( widget, profile, data ) # Delete an AP profile (i.e. make profile unknown) # #Parameters: # # 'selected_iter' -- gtk.TreeIter - The selected row. # # 'apname' -- string - The configuration file section to remove # #Returns: # # gtk.TreeIter -- the iter for the row removed from the gtk.ListStore def delete_profile(self, selected_iter, apname): # Remove it del self.access_points[apname] self.confFile.remove_section(apname) self.logger.info(apname) if apname in self.confFile.auto_profile_order: self.confFile.auto_profile_order.remove(apname) self.pstore.remove(selected_iter) # Let's save our current state self.update_auto_profile_order() try: self.confFile.write() except IOError, (error_number, error_str): if error_number == errno.ENOENT: error_dlg = ErrorDialog(self.window, "Could not save configuration file:\n%s\n\n%s" % (self.confFile.filename, error_str)) del error_dlg else: raise IOError(error_number, error_str) return selected_iter # Respond to a request to delete an AP profile (i.e. make profile unknown) # Check with user first. # #Parameters: # # 'widget' -- gtk.Widget - The widget sending the event. # # 'data' -- tuple - list of arbitrary arguments (not used) # #Returns: # # nothing def delete_profile_with_check(self, widget, data=None): (store, selected_iter) = self.plist.get_selection().get_selected() if not selected_iter: return (essid, bssid) = store.get_value(selected_iter, 0).split("\n") if bssid == ' Multiple APs': apname = make_section_name(essid, '') else: apname = make_section_name(essid, bssid) profile = self.confFile.get_profile(apname) if profile['roaming']: dlg = gtk.MessageDialog(self.window, gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_MODAL, gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, "Are you sure you want to delete the %s profile?" % (essid, )) else: dlg = gtk.MessageDialog(self.window, gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_MODAL, gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, "Are you sure you want to delete the %s (%s) profile?" % (essid, bssid)) known = store.get_value( selected_iter, 1 ) if not known: return res = dlg.run() dlg.destroy() del dlg if res == gtk.RESPONSE_NO: return self.delete_profile(selected_iter, apname) # Respond to a request to connect to an AP. # #Parameters: # # 'widget' -- gtk.Widget - The widget sending the event. # # 'profile' -- dictionary - The AP profile to which to connect. # # 'data' -- tuple - list of arbitrary arguments (not used) # #Returns: # # nothing def connect_profile( self, widget, profile, data=None ): ( store, selected_iter ) = self.plist.get_selection().get_selected() if not selected_iter: return ( essid, bssid ) = store.get_value( selected_iter, 0 ).split("\n") known = store.get_value( selected_iter, 2 ) if not known: dlg = gtk.MessageDialog(self.window, gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_MODAL, gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, "This network does not have a profile configured.\n\nWould you like to create one now?") res = dlg.run() dlg.destroy() del dlg if res == gtk.RESPONSE_NO: return profile = get_new_profile() profile['essid'] = essid profile['bssid'] = bssid if not self.create_new_profile( widget, profile, data ): return else: # Check for roaming profile. ap_name = make_section_name(essid, '') profile = self.confFile.get_profile(ap_name) if not profile: # Check for normal profile. ap_name = make_section_name(essid, bssid) profile = self.confFile.get_profile(ap_name) if not profile: # No configured profile return profile['bssid'] = self.access_points[ap_name]['bssid'] profile['channel'] = self.access_points[ap_name]['channel'] self.connection.connect_to_network(profile, self.status_window) # Respond to a request to disconnect by calling ConnectionManager disconnect_interface(). # #Parameters: # # 'widget' -- gtk.Widget - The widget sending the event. # # 'data' -- tuple - list of arbitrary arguments (not used) # #Returns: # # nothing def disconnect_profile( self, widget, data=None ): if data == "cancel": self.status_window.update_message("Canceling connection...") if sys.modules.has_key("gtk"): while gtk.events_pending(): gtk.main_iteration(False) sleep(1) self.connection.disconnect_interface() # Update the config file auto profile order from the on-screen order # #Parameters: # # 'widget' -- gtk.Widget - The widget sending the event. # # 'data' -- tuple - list of arbitrary arguments (not used) # # 'data2' -- tuple - list of arbitrary arguments (not used) # #Returns: # # nothing def update_auto_profile_order( self, widget = None, data = None, data2 = None ): # recreate the auto_profile_order auto_profile_order = [] piter = self.pstore.get_iter_first() while piter: # only if it's known if self.pstore.get_value(piter, 2) == True: (essid, bssid) = self.pstore.get_value(piter, 0).split("\n") if bssid == ' Multiple APs': apname = make_section_name(essid, '') else: apname = make_section_name(essid, bssid) auto_profile_order.append(apname) piter = self.pstore.iter_next(piter) self.confFile.auto_profile_order = auto_profile_order try: self.confFile.write() except IOError, (error_number, error_str): if error_number == errno.ENOENT: error_dlg = ErrorDialog( self.window, "Could not save configuration file:\n%s\n\n%s" % (self.confFile.filename, error_str) ) del error_dlg else: raise IOError(error_number, error_str) # Button to allow user to choose a file and put value into specified gtk.Entry class file_browse_button(gtk.Button): # Create a button to simulate a File/Open # #Parameters: # # 'parent' -- gtk.Object -- Usually, the calling window. # # 'entry' -- gtk.Entry -- The text entry to update with user selection. # #Returns: # # file_browse_button instance def __init__( self, parent, entry ): self.parent_window = parent self.entry = entry gtk.Button.__init__(self, "Browse", None) #self. self.browser_dialog = gtk.FileChooserDialog(None, self.parent_window, gtk.FILE_CHOOSER_ACTION_OPEN, ( gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK ), None) self.connect("clicked", self.browse_files) # Show filechooser dialog and get user selection # #Parameters: # # 'widget' -- gtk.Widget -- The widget sending the event. # #Returns: # # nothing # #NOTES: # # updates entry value # def browse_files( self, widget ): self.browser_dialog.set_filename(self.entry.get_text()) self.browser_dialog.run() filename = self.browser_dialog.get_filename() if filename: self.entry.set_text(filename) self.browser_dialog.destroy() # Simple dialog to report an error to the user. class ErrorDialog: # Create a new ErrorDialog. # #Parameters: # # 'parent' -- gtk.Object - Usually, the calling window. # # 'message' -- string - The message to display to the user. # #Returns: # # ErrorDialog instance def __init__( self, parent, message ): dialog = gtk.MessageDialog( parent, gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, message ) dialog.run() dialog.destroy() del dialog # The preferences dialog. Edits non-profile sections of the config file. class preferences_dialog: # Create a new preferences_dialog. # #Parameters: # # 'parent' -- gtk.Object - Usually, the calling window. # # 'confFile' -- ConfigFile - The config file in which to store/read settings. # #Returns: # # preferences_dialog instance def __init__( self, parent, confFile ): global wifi_radar_icon self.parent = parent self.confFile = confFile self.dialog = gtk.Dialog('WiFi Radar Preferences', self.parent.window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, ( gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT ) ) icon = gtk.gdk.pixbuf_new_from_inline( len( wifi_radar_icon[0] ), wifi_radar_icon[0], False ) self.dialog.set_icon( icon ) self.dialog.set_resizable( True ) self.dialog.set_transient_for( self.parent.window ) self.tooltips = gtk.Tooltips() # # set up preferences widgets # # build everything in a tabbed notebook self.prefs_notebook = gtk.Notebook() ### General tab self.general_page = gtk.VBox() # auto detect wireless device self.w_auto_detect = gtk.CheckButton("Auto-detect wireless device") self.w_auto_detect.set_active( self.confFile.get_opt('DEFAULT.interface') == "auto_detect" ) self.w_auto_detect.connect("toggled", self.toggle_auto_detect) self.tooltips.set_tip(self.w_auto_detect, "Automatically select wireless device to configure") self.general_page.pack_start(self.w_auto_detect, False, False, 5) # network interface selecter self.w_interface = gtk.combo_box_entry_new_text() try: iwconfig_info = Popen([self.confFile.get_opt('DEFAULT.iwconfig_command')], stdout=PIPE, stderr=STDOUT).stdout except OSError, (errno, strerror): if errno == 2: logger.critical("iwconfig command not found, please set this in the preferences.") iwconfig_info = "" wireless_devices = [ (x[0:x.find(" ")]) for x in iwconfig_info if ("ESSID" in x)] for device in wireless_devices: if device != self.confFile.get_opt('DEFAULT.interface'): self.w_interface.append_text(device) if self.confFile.get_opt('DEFAULT.interface') != "auto_detect": self.w_interface.prepend_text( self.confFile.get_opt('DEFAULT.interface') ) self.w_interface.set_active(0) self.w_interface_label = gtk.Label("Wireless device") self.w_hbox1 = gtk.HBox(False, 0) self.w_hbox1.pack_start(self.w_interface_label, False, False, 5) self.w_hbox1.pack_start(self.w_interface, True, True, 0) self.w_interface.set_sensitive( self.confFile.get_opt('DEFAULT.interface') != "auto_detect" ) self.general_page.pack_start(self.w_hbox1, False, False, 5) # scan timeout (spin button of integers from 1 to 100) #self.time_in_seconds = gtk.Adjustment( self.confFile.get_opt_as_int('DEFAULT.scan_timeout'),1,100,1,1,0 ) #self.w_scan_timeout = gtk.SpinButton(self.time_in_seconds, 1, 0) #self.w_scan_timeout.set_update_policy(gtk.UPDATE_IF_VALID) #self.w_scan_timeout.set_numeric(True) #self.w_scan_timeout.set_snap_to_ticks(True) #self.w_scan_timeout.set_wrap(False) #self.tooltips.set_tip(self.w_scan_timeout, "How long should WiFi Radar scan for access points?") #self.w_scan_timeout_label = gtk.Label("Scan timeout (seconds)") #self.w_hbox2 = gtk.HBox(False, 0) #self.w_hbox2.pack_start(self.w_scan_timeout_label, False, False, 5) #self.w_hbox2.pack_start(self.w_scan_timeout, True, True, 0) #self.general_page.pack_start(self.w_hbox2, False, False, 5) # speak up self.w_speak_up = gtk.CheckButton("Use speak-up") self.w_speak_up.set_active( self.confFile.get_opt_as_bool('DEFAULT.speak_up') ) self.w_speak_up.connect("toggled", self.toggle_speak) self.tooltips.set_tip(self.w_speak_up, "Should I speak up when connecting to a network? (If you have a speech command)") self.general_page.pack_start(self.w_speak_up, False, False, 5) # speak up command self.w_speak_cmd = gtk.Entry() self.w_speak_cmd.set_width_chars(16) self.tooltips.set_tip(self.w_speak_cmd, "The command to use to speak feedback") self.w_speak_cmd.set_text(self.confFile.get_opt('DEFAULT.speak_command')) self.w_speak_cmd_label = gtk.Label("Speak Command") self.w_speak_cmd_button = file_browse_button(self.dialog, self.w_speak_cmd) self.w_speak_cmd_button.set_sensitive(self.w_speak_up.get_active()) self.w_hbox3 = gtk.HBox(False, 0) self.w_hbox3.pack_start(self.w_speak_cmd_label, True, False, 5) self.w_hbox3.pack_start(self.w_speak_cmd, False, False, 0) self.w_hbox3.pack_start(self.w_speak_cmd_button, False, False, 0) self.w_speak_cmd.set_sensitive(self.w_speak_up.get_active()) self.general_page.pack_start(self.w_hbox3, False, False, 5) # commit required self.w_commit_required = gtk.CheckButton("Commit required") self.w_commit_required.set_active( self.confFile.get_opt_as_bool('DEFAULT.commit_required') ) self.tooltips.set_tip(self.w_commit_required, "Check this box if your card requires a \"commit\" command with iwconfig") self.general_page.pack_start(self.w_commit_required, False, False, 5) # ifup required self.w_ifup_required = gtk.CheckButton("Ifup required") self.w_ifup_required.set_active( self.confFile.get_opt_as_bool('DEFAULT.ifup_required') ) self.tooltips.set_tip(self.w_ifup_required, "Check this box if your system requires the interface to be brought up first") self.general_page.pack_start(self.w_ifup_required, False, False, 5) self.prefs_notebook.append_page(self.general_page, gtk.Label("General")) ### End of General tab ### Advanced tab # table to use for layout of following command configurations self.cmds_table = gtk.Table() # ifconfig command self.ifconfig_cmd = gtk.Entry() self.ifconfig_cmd.set_width_chars(32) self.tooltips.set_tip(self.ifconfig_cmd, "The command to use to configure the network card") self.ifconfig_cmd.set_text(self.confFile.get_opt('DEFAULT.ifconfig_command')) self.ifconfig_cmd_label = gtk.Label("Network interface configure command") self.ifconfig_cmd_button = file_browse_button(self.dialog, self.ifconfig_cmd) # (widget, l, r, t, b, xopt, yopt, xpad, ypad) self.cmds_table.attach(self.ifconfig_cmd_label, 1, 2, 1, 2, gtk.FILL|gtk.EXPAND, 0, 5, 0) self.cmds_table.attach(self.ifconfig_cmd, 2, 3, 1, 2, gtk.FILL|gtk.EXPAND, 0, 0, 0) self.cmds_table.attach(self.ifconfig_cmd_button, 3, 4, 1, 2, gtk.FILL|gtk.EXPAND, 0, 0, 0) # iwconfig command self.iwconfig_cmd = gtk.Entry() self.iwconfig_cmd.set_width_chars(32) self.tooltips.set_tip(self.iwconfig_cmd, "The command to use to configure the wireless connection") self.iwconfig_cmd.set_text(self.confFile.get_opt('DEFAULT.iwconfig_command')) self.iwconfig_cmd_label = gtk.Label("Wireless connection configure command") self.iwconfig_cmd_button = file_browse_button(self.dialog, self.iwconfig_cmd) # (widget, l, r, t, b, xopt, yopt, xpad, ypad) self.cmds_table.attach(self.iwconfig_cmd_label, 1, 2, 2, 3, gtk.FILL|gtk.EXPAND, 0, 5, 0) self.cmds_table.attach(self.iwconfig_cmd, 2, 3, 2, 3, gtk.FILL|gtk.EXPAND, 0, 0, 0) self.cmds_table.attach(self.iwconfig_cmd_button, 3, 4, 2, 3, gtk.FILL|gtk.EXPAND, 0, 0, 0) # iwlist command self.iwlist_cmd = gtk.Entry() self.iwlist_cmd.set_width_chars(32) self.tooltips.set_tip(self.iwlist_cmd, "The command to use to scan for access points") self.iwlist_cmd.set_text(self.confFile.get_opt('DEFAULT.iwlist_command')) self.iwlist_cmd_label = gtk.Label("Wireless scanning command") self.iwlist_cmd_button = file_browse_button(self.dialog, self.iwlist_cmd) # (widget, l, r, t, b, xopt, yopt, xpad, ypad) self.cmds_table.attach(self.iwlist_cmd_label, 1, 2, 3, 4, gtk.FILL|gtk.EXPAND, 0, 5, 0) self.cmds_table.attach(self.iwlist_cmd, 2, 3, 3, 4, gtk.FILL|gtk.EXPAND, 0, 0, 0) self.cmds_table.attach(self.iwlist_cmd_button, 3, 4, 3, 4, gtk.FILL|gtk.EXPAND, 0, 0, 0) # route command self.route_cmd = gtk.Entry() self.route_cmd.set_width_chars(32) self.tooltips.set_tip(self.route_cmd, "The command to use to configure the network routing") self.route_cmd.set_text(self.confFile.get_opt('DEFAULT.route_command')) self.route_cmd_label = gtk.Label("Network route configure command") self.route_cmd_button = file_browse_button(self.dialog, self.route_cmd) # (widget, l, r, t, b, xopt, yopt, xpad, ypad) self.cmds_table.attach(self.route_cmd_label, 1, 2, 4, 5, gtk.FILL|gtk.EXPAND, 0, 5, 0) self.cmds_table.attach(self.route_cmd, 2, 3, 4, 5, gtk.FILL|gtk.EXPAND, 0, 0, 0) self.cmds_table.attach(self.route_cmd_button, 3, 4, 4, 5, gtk.FILL|gtk.EXPAND, 0, 0, 0) # log file self.logfile_entry = gtk.Entry() self.logfile_entry.set_width_chars(32) self.tooltips.set_tip(self.logfile_entry, "The file in which to save logging info") self.logfile_entry.set_text(self.confFile.get_opt('DEFAULT.logfile')) self.logfile_label = gtk.Label("Log file") self.logfile_button = file_browse_button(self.dialog, self.logfile_entry) # (widget, l, r, t, b, xopt, yopt, xpad, ypad) self.cmds_table.attach(self.logfile_label, 1, 2, 5, 6, gtk.FILL|gtk.EXPAND, 0, 5, 0) self.cmds_table.attach(self.logfile_entry, 2, 3, 5, 6, gtk.FILL|gtk.EXPAND, 0, 0, 0) self.cmds_table.attach(self.logfile_button, 3, 4, 5, 6, gtk.FILL|gtk.EXPAND, 0, 0, 0) # log level (spin button of integers from 0 to 50 by 5's) self.loglevel = gtk.SpinButton(gtk.Adjustment(self.confFile.get_opt_as_int('DEFAULT.loglevel'), 1, 50, 5, 5, 0), 1, 0) self.loglevel.set_update_policy(gtk.UPDATE_IF_VALID) self.loglevel.set_numeric(True) self.loglevel.set_snap_to_ticks(True) self.loglevel.set_wrap(False) self.tooltips.set_tip(self.loglevel, "How much detail to save in log file. Larger numbers provide less detail and smaller numbers, more detail.") self.loglevel.set_text(self.confFile.get_opt('DEFAULT.loglevel')) self.loglevel_label = gtk.Label("Log level") # (widget, l, r, t, b, xopt, yopt, xpad, ypad) self.cmds_table.attach(self.loglevel_label, 1, 2, 6, 7, gtk.FILL|gtk.EXPAND, 0, 5, 0) self.cmds_table.attach(self.loglevel, 2, 3, 6, 7, gtk.FILL|gtk.EXPAND, 0, 0, 0) self.prefs_notebook.append_page(self.cmds_table, gtk.Label("Advanced")) ### End of Advanced tab ### DHCP tab # table to use for layout of DHCP prefs self.dhcp_table = gtk.Table() self.dhcp_cmd = gtk.Entry() self.dhcp_cmd.set_width_chars(32) self.tooltips.set_tip(self.dhcp_cmd, "The command to use for automatic network configuration") self.dhcp_cmd.set_text(self.confFile.get_opt('DHCP.command')) self.dhcp_cmd_label = gtk.Label("Command") self.dhcp_cmd_button = file_browse_button(self.dialog, self.dhcp_cmd) self.dhcp_table.attach(self.dhcp_cmd_label, 1, 2, 1, 2, True, False, 5, 0) self.dhcp_table.attach(self.dhcp_cmd, 2, 3, 1, 2, True, False, 0, 0) self.dhcp_table.attach(self.dhcp_cmd_button, 3, 4, 1, 2, False, False, 0, 0) self.dhcp_args = gtk.Entry() self.dhcp_args.set_width_chars(32) self.tooltips.set_tip(self.dhcp_args, "The start-up arguments to the DHCP command") self.dhcp_args.set_text(self.confFile.get_opt('DHCP.args')) self.dhcp_args_label = gtk.Label("Arguments") self.dhcp_table.attach(self.dhcp_args_label, 1, 2, 2, 3, True, False, 5, 0) self.dhcp_table.attach(self.dhcp_args, 2, 3, 2, 3, True, False, 0, 0) self.dhcp_kill_args = gtk.Entry() self.dhcp_kill_args.set_width_chars(32) self.tooltips.set_tip(self.dhcp_kill_args, "The shutdown arguments to the DHCP command") self.dhcp_kill_args.set_text(self.confFile.get_opt('DHCP.kill_args')) self.dhcp_kill_args_label = gtk.Label("Kill arguments") self.dhcp_table.attach(self.dhcp_kill_args_label, 1, 2, 3, 4, True, False, 5, 0) self.dhcp_table.attach(self.dhcp_kill_args, 2, 3, 3, 4, True, False, 0, 0) self.dhcp_timeout = gtk.Entry() self.dhcp_timeout.set_width_chars(32) self.tooltips.set_tip(self.dhcp_timeout, "The amount of time DHCP will spend trying to connect") self.dhcp_timeout.set_text(self.confFile.get_opt('DHCP.timeout')) self.dhcp_timeout_label = gtk.Label("DHCP connect timeout (seconds)") self.dhcp_table.attach(self.dhcp_timeout_label, 1, 2, 4, 5, True, False, 5, 0) self.dhcp_table.attach(self.dhcp_timeout, 2, 3, 4, 5, True, False, 0, 0) self.dhcp_pidfile = gtk.Entry() self.dhcp_pidfile.set_width_chars(32) self.tooltips.set_tip(self.dhcp_pidfile, "The file DHCP uses to store its PID") self.dhcp_pidfile.set_text(self.confFile.get_opt('DHCP.pidfile')) self.dhcp_pidfile_label = gtk.Label("PID file") self.dhcp_table.attach(self.dhcp_pidfile_label, 1, 2, 5, 6, True, False, 5, 0) self.dhcp_table.attach(self.dhcp_pidfile, 2, 3, 5, 6, True, False, 0, 0) self.prefs_notebook.append_page(self.dhcp_table, gtk.Label("DHCP")) ### End of DHCP tab ### WPA tab # table to use for layout of DHCP prefs self.wpa_table = gtk.Table() self.wpa_cmd = gtk.Entry() self.wpa_cmd.set_width_chars(32) self.tooltips.set_tip(self.wpa_cmd, "The command to use for WPA encrypted connections") self.wpa_cmd.set_text(self.confFile.get_opt('WPA.command')) self.wpa_cmd_label = gtk.Label("Command") self.wpa_cmd_button = file_browse_button(self.dialog, self.wpa_cmd) self.wpa_table.attach(self.wpa_cmd_label, 1, 2, 1, 2, True, False, 5, 0) self.wpa_table.attach(self.wpa_cmd, 2, 3, 1, 2, True, False, 0, 0) self.wpa_table.attach(self.wpa_cmd_button, 3, 4, 1, 2, False, False, 0, 0) self.wpa_args = gtk.Entry() self.wpa_args.set_width_chars(32) self.tooltips.set_tip(self.wpa_args, "The start-up arguments to the WPA command") self.wpa_args.set_text(self.confFile.get_opt('WPA.args')) self.wpa_args_label = gtk.Label("Arguments") self.wpa_table.attach(self.wpa_args_label, 1, 2, 2, 3, True, False, 5, 0) self.wpa_table.attach(self.wpa_args, 2, 3, 2, 3, True, False, 0, 0) self.wpa_kill_args = gtk.Entry() self.wpa_kill_args.set_width_chars(32) self.tooltips.set_tip(self.wpa_kill_args, "The shutdown arguments to the DHCP command") self.wpa_kill_args.set_text(self.confFile.get_opt('WPA.kill_command')) self.wpa_kill_args_label = gtk.Label("Kill command") self.wpa_table.attach(self.wpa_kill_args_label, 1, 2, 3, 4, True, False, 5, 0) self.wpa_table.attach(self.wpa_kill_args, 2, 3, 3, 4, True, False, 0, 0) self.wpa_config = gtk.Entry() self.wpa_config.set_width_chars(32) self.tooltips.set_tip(self.wpa_config, "The WPA configuration file to use") self.wpa_config.set_text(self.confFile.get_opt('WPA.configuration')) self.wpa_config_label = gtk.Label("Configuration file") self.wpa_table.attach(self.wpa_config_label, 1, 2, 4, 5, True, False, 5, 0) self.wpa_table.attach(self.wpa_config, 2, 3, 4, 5, True, False, 0, 0) self.wpa_driver = gtk.Entry() self.wpa_driver.set_width_chars(32) self.tooltips.set_tip(self.wpa_driver, "The WPA driver to use") self.wpa_driver.set_text(self.confFile.get_opt('WPA.driver')) self.wpa_driver_label = gtk.Label("Driver") self.wpa_table.attach(self.wpa_driver_label, 1, 2, 5, 6, True, False, 5, 0) self.wpa_table.attach(self.wpa_driver, 2, 3, 5, 6, True, False, 0, 0) self.wpa_pidfile = gtk.Entry() self.wpa_pidfile.set_width_chars(32) self.tooltips.set_tip(self.wpa_pidfile, "The file WPA uses to store its PID") self.wpa_pidfile.set_text(self.confFile.get_opt('WPA.pidfile')) self.wpa_pidfile_label = gtk.Label("PID file") self.wpa_table.attach(self.wpa_pidfile_label, 1, 2, 6, 7, True, False, 5, 0) self.wpa_table.attach(self.wpa_pidfile, 2, 3, 6, 7, True, False, 0, 0) self.prefs_notebook.append_page(self.wpa_table, gtk.Label("WPA")) ### End of WPA tab self.dialog.vbox.pack_start(self.prefs_notebook, False, False, 5) # Respond to Auto-detect checkbox toggle by activating/de-activating the interface combobox. # #Parameters: # # 'auto_detect_toggle' -- gtk.CheckButton - The checkbox sending the signal. # # 'data' -- tuple - list of arbitrary arguments (not used) # #Returns: # # nothing def toggle_auto_detect(self, auto_detect_toggle, data=None): self.w_interface.set_sensitive(not auto_detect_toggle.get_active()) # Respond to Speak-up checkbox toggle by activating/de-activating the Speak Cmd Entry. # #Parameters: # # 'speak_toggle' -- gtk.CheckButton - The checkbox sending the signal. # # 'data' -- tuple - list of arbitrary arguments (not used) # #Returns: # # nothing def toggle_speak(self, speak_toggle, data=None): self.w_speak_cmd.set_sensitive(speak_toggle.get_active()) self.w_speak_cmd_button.set_sensitive(speak_toggle.get_active()) # Display preferences dialog and operate until canceled or okayed. # #Parameters: # # nothing # #Returns: # # integer -- gtk response ID def run(self): self.dialog.show_all() return self.dialog.run() # Write updated values to config file. # #Parameters: # # nothing # #Returns: # # nothing def save(self): if self.w_auto_detect.get_active(): self.confFile.set_opt('DEFAULT.interface', "auto_detect") else: interface = "auto_detect" if self.w_interface.get_active_text() != "": interface = self.w_interface.get_active_text() self.confFile.set_opt('DEFAULT.interface', interface) #self.confFile.set_float_opt('DEFAULT.scan_timeout', self.w_scan_timeout.get_value()) self.confFile.set_bool_opt('DEFAULT.speak_up', self.w_speak_up.get_active()) self.confFile.set_bool_opt('DEFAULT.commit_required', self.w_commit_required.get_active()) self.confFile.set_bool_opt('DEFAULT.ifup_required', self.w_ifup_required.get_active()) self.confFile.set_opt('DEFAULT.speak_command', self.w_speak_cmd.get_text()) self.confFile.set_opt('DEFAULT.ifconfig_command', self.ifconfig_cmd.get_text()) self.confFile.set_opt('DEFAULT.iwconfig_command', self.iwconfig_cmd.get_text()) self.confFile.set_opt('DEFAULT.iwlist_command', self.iwlist_cmd.get_text()) self.confFile.set_opt('DEFAULT.route_command', self.route_cmd.get_text()) self.confFile.set_opt('DEFAULT.logfile', self.logfile_entry.get_text()) self.confFile.set_int_opt('DEFAULT.loglevel', int(self.loglevel.get_value())) self.confFile.set_opt('DHCP.command', self.dhcp_cmd.get_text()) self.confFile.set_opt('DHCP.args', self.dhcp_args.get_text()) self.confFile.set_opt('DHCP.kill_args', self.dhcp_kill_args.get_text()) self.confFile.set_opt('DHCP.timeout', self.dhcp_timeout.get_text()) self.confFile.set_opt('DHCP.pidfile', self.dhcp_pidfile.get_text()) self.confFile.set_opt('WPA.command', self.wpa_cmd.get_text()) self.confFile.set_opt('WPA.args', self.wpa_args.get_text()) self.confFile.set_opt('WPA.kill_command', self.wpa_kill_args.get_text()) self.confFile.set_opt('WPA.configuration', self.wpa_config.get_text()) self.confFile.set_opt('WPA.driver', self.wpa_driver.get_text()) self.confFile.set_opt('WPA.pidfile', self.wpa_pidfile.get_text()) try: self.confFile.write() except IOError, (error_number, error_str): if error_number == errno.ENOENT: error_dlg = ErrorDialog( self.dialog, "Could not save configuration file:\n%s\n\n%s" % (self.confFile.filename, error_str) ) del error_dlg else: raise IOError(error_number, error_str) # Remove preferences window. # #Parameters: # # nothing # #Returns: # # nothing def destroy(self): self.dialog.destroy() del self.dialog # Edit and return an AP profile. class profile_dialog: # Create a new profile_dialog. # #Parameters: # # 'parent' -- gtk.Object - Usually, the calling window. # # 'profile' -- dictionary - The profile to edit. May be mostly-empty default profile. # #Returns: # # profile_dialog instance def __init__( self, parent, profile ): global wifi_radar_icon # Labels self.WIFI_SET_LABEL = "WiFi Options" self.USE_DHCP_LABEL = "Automatic network configuration (DHCP)" self.USE_IP_LABEL = "Manual network configuration" self.USE_WPA_LABEL = "Use WPA" self.NO_WPA_LABEL = "No WPA" self.CON_PP_LABEL = "Connection Commands" self.DIS_PP_LABEL = "Disconnection Commands" self.parent = parent self.profile = profile.copy() self.WIFI_MODES = [ '', 'auto', 'Managed', 'Ad-Hoc', 'Master', 'Repeater', 'Secondary', 'Monitor' ] self.WIFI_SECURITY = [ '', 'open', 'restricted' ] self.WIFI_CHANNELS = [ '', 'auto', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14' ] self.dialog = gtk.Dialog('WiFi Profile', self.parent.window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, ( gtk.STOCK_CANCEL, False, gtk.STOCK_SAVE, True ) ) icon = gtk.gdk.pixbuf_new_from_inline( len( wifi_radar_icon[0] ), wifi_radar_icon[0], False ) self.dialog.set_icon( icon ) self.dialog.set_resizable( False ) self.dialog.set_transient_for( self.parent.window ) #self.dialog.set_size_request( 400, 400 ) ################# self.tooltips = gtk.Tooltips() general_table = gtk.Table() general_table.set_row_spacings(3) general_table.set_col_spacings(3) # The essid labels general_table.attach(gtk.Label('Network Name'), 0, 1, 0, 1) # The essid textboxes self.essid_entry = gtk.Entry(32) self.essid_entry.set_text(self.profile['essid']) general_table.attach(self.essid_entry, 1, 2, 0, 1) # Add the essid table to the dialog self.dialog.vbox.pack_start(general_table, True, True, 5) self.tooltips.set_tip(self.essid_entry, "The name of the network with which to connect.") # The bssid labels general_table.attach(gtk.Label('Network Address'), 0, 1, 1, 2) # The bssid textboxes self.bssid_entry = gtk.Entry(32) self.bssid_entry.set_text(self.profile['bssid']) self.bssid_entry.set_sensitive(not self.profile['roaming']) # Add the bssid table to the dialog general_table.attach(self.bssid_entry, 1, 2, 1, 2) self.tooltips.set_tip(self.bssid_entry, "The address of the network with which to connect.") # Add the roaming checkbox self.roaming_cb = gtk.CheckButton('Roaming') self.roaming_cb.set_active(self.profile['roaming']) self.roaming_cb.connect("toggled", self.toggle_roaming) general_table.attach(self.roaming_cb, 1, 2, 2, 3) self.tooltips.set_tip(self.roaming_cb, "Use the AP in this network which provides strongest signal?") # create the WiFi expander self.wifi_expander = gtk.Expander( self.WIFI_SET_LABEL ) #self.wifi_expander.connect( 'notify::expanded', self.toggle_use_dhcp ) wifi_table = gtk.Table( 4, 2, False ) wifi_table.set_row_spacings( 3 ) wifi_table.set_col_spacings( 3 ) # The WiFi labels wifi_table.attach( gtk.Label( 'Mode' ), 0, 1, 0, 1 ) wifi_table.attach( gtk.Label( 'Channel' ), 0, 1, 1, 2 ) wifi_table.attach( gtk.Label( 'Key' ), 0, 1, 2, 3 ) wifi_table.attach( gtk.Label( 'Security' ), 0, 1, 3, 4 ) # The WiFi text boxes self.mode_combo = gtk.combo_box_new_text() for mode in self.WIFI_MODES: self.mode_combo.append_text( mode ) self.mode_combo.set_active( self.get_array_index( self.profile['mode'], self.WIFI_MODES ) ) wifi_table.attach( self.mode_combo, 1, 2, 0, 1 ) self.tooltips.set_tip(self.mode_combo, "Method to use for connection. You probably want auto mode.") self.channel_combo = gtk.combo_box_new_text() for channel in self.WIFI_CHANNELS: self.channel_combo.append_text( channel ) self.channel_combo.set_active( self.get_array_index( self.profile['channel'], self.WIFI_CHANNELS ) ) wifi_table.attach( self.channel_combo, 1, 2, 1, 2 ) self.tooltips.set_tip(self.channel_combo, "Channel the network uses. You probably want auto mode.") self.key_entry = gtk.Entry( 64 ) self.key_entry.set_text( self.profile['key'] ) wifi_table.attach( self.key_entry, 1, 2, 2, 3 ) self.tooltips.set_tip(self.key_entry, "WEP key: Plain language or hex string to use for encrypted communication with the network.") self.security_combo = gtk.combo_box_new_text() for security in self.WIFI_SECURITY: self.security_combo.append_text( security ) self.security_combo.set_active( self.get_array_index( self.profile['security'], self.WIFI_SECURITY ) ) wifi_table.attach( self.security_combo, 1, 2, 3, 4 ) self.tooltips.set_tip(self.security_combo, "Use Open to allow unencrypted communication and Restricted to force encrypted-only communication.") # Add the wifi table to the expander self.wifi_expander.add( wifi_table ) # Add the expander to the dialog self.dialog.vbox.pack_start( self.wifi_expander, False, False, 5 ) # create the wpa expander self.wpa_expander = gtk.Expander( self.NO_WPA_LABEL ) self.wpa_expander.connect( 'notify::expanded', self.toggle_use_wpa ) wpa_table = gtk.Table( 1, 2, False ) wpa_table.set_row_spacings( 3 ) wpa_table.set_col_spacings( 3 ) # The labels wpa_table.attach( gtk.Label( 'Driver' ), 0, 1, 0, 1 ) # The text boxes self.wpa_driver_entry = gtk.Entry() self.wpa_driver_entry.set_text( self.profile['wpa_driver'] ) wpa_table.attach( self.wpa_driver_entry, 1, 2, 0, 1 ) # Add the wpa table to the expander self.wpa_expander.add( wpa_table ) self.wpa_expander.set_expanded(self.profile['use_wpa']) # Add the expander to the dialog self.dialog.vbox.pack_start( self.wpa_expander, False, False, 5 ) # create the dhcp expander self.dhcp_expander = gtk.Expander( self.USE_DHCP_LABEL ) self.dhcp_expander.connect( 'notify::expanded', self.toggle_use_dhcp ) self.dhcp_expander.set_expanded(not self.profile['use_dhcp']) ip_table = gtk.Table( 6, 2, False ) ip_table.set_row_spacings( 3 ) ip_table.set_col_spacings( 3 ) # The IP labels ip_table.attach( gtk.Label( 'IP' ), 0, 1, 0, 1 ) ip_table.attach( gtk.Label( 'Netmask' ), 0, 1, 1, 2 ) ip_table.attach( gtk.Label( 'Gateway' ), 0, 1, 2, 3 ) ip_table.attach( gtk.Label( 'Domain' ), 0, 1, 3, 4 ) ip_table.attach( gtk.Label( 'DNS' ), 0, 1, 4, 5 ) ip_table.attach( gtk.Label( 'DNS' ), 0, 1, 5, 6 ) # The IP text boxes self.ip_entry = gtk.Entry( 15 ) self.ip_entry.set_text( self.profile['ip'] ) ip_table.attach( self.ip_entry, 1, 2, 0, 1 ) self.netmask_entry = gtk.Entry( 15 ) self.netmask_entry.set_text( self.profile['netmask'] ) ip_table.attach( self.netmask_entry, 1, 2, 1, 2 ) self.gw_entry = gtk.Entry( 15 ) self.gw_entry.set_text( self.profile['gateway'] ) ip_table.attach( self.gw_entry, 1, 2, 2, 3 ) self.domain_entry = gtk.Entry( 32 ) self.domain_entry.set_text( self.profile['domain'] ) ip_table.attach( self.domain_entry, 1, 2, 3, 4 ) self.dns1_entry = gtk.Entry( 15 ) self.dns1_entry.set_text( self.profile['dns1'] ) ip_table.attach( self.dns1_entry, 1, 2, 4, 5 ) self.dns2_entry = gtk.Entry( 15 ) self.dns2_entry.set_text( self.profile['dns2'] ) ip_table.attach( self.dns2_entry, 1, 2, 5, 6 ) # Add the ip table to the expander self.dhcp_expander.add( ip_table ) # Add the expander to the dialog self.dialog.vbox.pack_start( self.dhcp_expander, False, False, 5 ) # create the connection-building postpre expander self.con_pp_expander = gtk.Expander( self.CON_PP_LABEL ) con_pp_table = gtk.Table( 2, 2, False ) con_pp_table.set_row_spacings( 3 ) con_pp_table.set_col_spacings( 3 ) # The labels con_pp_table.attach( gtk.Label( 'Before' ), 0, 1, 0, 1 ) con_pp_table.attach( gtk.Label( 'After' ), 0, 1, 1, 2 ) # The text boxes self.con_prescript_entry = gtk.Entry() self.con_prescript_entry.set_text( self.profile['con_prescript'] ) con_pp_table.attach( self.con_prescript_entry, 1, 2, 0, 1 ) self.tooltips.set_tip(self.con_prescript_entry, "The local command to execute before trying to connect to the network.") self.con_postscript_entry = gtk.Entry() self.con_postscript_entry.set_text( self.profile['con_postscript'] ) con_pp_table.attach( self.con_postscript_entry, 1, 2, 1, 2 ) self.tooltips.set_tip(self.con_postscript_entry, "The local command to execute after connecting to the network.") # Add the pp table to the expander self.con_pp_expander.add( con_pp_table ) # Add the expander to the dialog self.dialog.vbox.pack_start( self.con_pp_expander, False, False, 5 ) # create the disconnection postpre expander self.dis_pp_expander = gtk.Expander( self.DIS_PP_LABEL ) dis_pp_table = gtk.Table( 2, 2, False ) dis_pp_table.set_row_spacings( 3 ) dis_pp_table.set_col_spacings( 3 ) # The labels dis_pp_table.attach( gtk.Label( 'Before' ), 0, 1, 0, 1 ) dis_pp_table.attach( gtk.Label( 'After' ), 0, 1, 1, 2 ) # The text boxes self.dis_prescript_entry = gtk.Entry() self.dis_prescript_entry.set_text( self.profile['dis_prescript'] ) dis_pp_table.attach( self.dis_prescript_entry, 1, 2, 0, 1 ) self.tooltips.set_tip(self.dis_prescript_entry, "The local command to execute before disconnecting from the network.") self.dis_postscript_entry = gtk.Entry() self.dis_postscript_entry.set_text( self.profile['dis_postscript'] ) dis_pp_table.attach( self.dis_postscript_entry, 1, 2, 1, 2 ) self.tooltips.set_tip(self.dis_postscript_entry, "The local command to execute after disconnecting from the network.") # Add the pp table to the expander self.dis_pp_expander.add( dis_pp_table ) # Add the expander to the dialog self.dialog.vbox.pack_start( self.dis_pp_expander, False, False, 5 ) # Display profile dialog, operate until canceled or okayed, and, possibly, return edited profile values. # #Parameters: # # nothing # #Returns: # # dictionary or None -- a profile, or None on cancel # #NOTES: # # Raises ValueError if an attempt is made to save an ESSID with no name. def run( self ): self.dialog.show_all() if self.dialog.run(): if self.essid_entry.get_text().strip() == "": raise ValueError self.profile['known'] = True self.profile['essid'] = self.essid_entry.get_text().strip() if self.roaming_cb.get_active(): self.profile['bssid'] = '' else: self.profile['bssid'] = self.bssid_entry.get_text().strip() self.profile['roaming'] = self.roaming_cb.get_active() self.profile['key'] = self.key_entry.get_text().strip() self.profile['mode'] = self.get_array_item( self.mode_combo.get_active(), self.WIFI_MODES ) self.profile['security'] = self.get_array_item( self.security_combo.get_active(), self.WIFI_SECURITY ) self.profile['encrypted'] = ( self.profile['security'] != '' ) self.profile['channel'] = self.get_array_item( self.channel_combo.get_active(), self.WIFI_CHANNELS ) self.profile['protocol'] = 'g' self.profile['available'] = ( self.profile['signal'] > 0 ) self.profile['con_prescript'] = self.con_prescript_entry.get_text().strip() self.profile['con_postscript'] = self.con_postscript_entry.get_text().strip() self.profile['dis_prescript'] = self.dis_prescript_entry.get_text().strip() self.profile['dis_postscript'] = self.dis_postscript_entry.get_text().strip() # wpa self.profile['use_wpa'] = self.wpa_expander.get_expanded() self.profile['wpa_driver'] = self.wpa_driver_entry.get_text().strip() # dhcp self.profile['use_dhcp'] = not self.dhcp_expander.get_expanded() self.profile['ip'] = self.ip_entry.get_text().strip() self.profile['netmask'] = self.netmask_entry.get_text().strip() self.profile['gateway'] = self.gw_entry.get_text().strip() self.profile['domain'] = self.domain_entry.get_text().strip() self.profile['dns1'] = self.dns1_entry.get_text().strip() self.profile['dns2'] = self.dns2_entry.get_text().strip() return self.profile return None # Remove profile dialog. # #Parameters: # # nothing # #Returns: # # nothing def destroy( self ): self.dialog.destroy() del self.dialog # Respond to roaming checkbox toggle by activating/de-activating the BSSID text entry. # #Parameters: # # 'roaming_toggle' -- gtk.CheckButton - The checkbox sending the signal. # # 'data' -- tuple - list of arbitrary arguments (not used) # #Returns: # # nothing def toggle_roaming(self, roaming_toggle, data=None): self.bssid_entry.set_sensitive(not roaming_toggle.get_active()) # Respond to expanding/hiding IP segment. # #Parameters: # # 'widget' -- gtk.Widget - The widget sending the event. # # 'data' -- tuple - List of arbitrary arguments (not used) # #Returns: # # nothing def toggle_use_dhcp( self, widget, data = None ): expanded = self.dhcp_expander.get_expanded() if expanded: self.dhcp_expander.set_label( self.USE_IP_LABEL ) else: self.dhcp_expander.set_label( self.USE_DHCP_LABEL ) # Respond to expanding/hiding WPA segment. # #Parameters: # # 'widget' -- gtk.Widget - The widget sending the event. # # 'data' -- tuple - List of arbitrary arguments (not used) # #Returns: # # nothing def toggle_use_wpa( self, widget, data = None ): expanded = self.wpa_expander.get_expanded() if expanded: self.wpa_expander.set_label( self.USE_WPA_LABEL ) else: self.wpa_expander.set_label( self.NO_WPA_LABEL ) # Return the index where item matches a cell in array. # #Parameters: # # 'item' -- string - Item to find in array # # 'array' -- list - List in which to find match. # #Returns: # # integer - 0 (no match) or higher (index of match) def get_array_index( self, item, array ): try: return array.index( item.strip() ) except: pass return 0 # Return the value in array[ index ] # #Parameters: # # 'index' -- integer - The index to look up. # # 'array' -- list - List in which to look up value. # #Returns: # # string -- empty string (no match) or looked up value def get_array_item( self, index, array ): try: return array[ index ] except: pass return '' # A simple class for putting up a "Please wait" dialog so the user # doesn't think we've forgotten about them. Implements the status interface. class StatusWindow: # Create a new StatusWindow. # #Parameters: # # 'parent' -- gtk.Object - Usually, the calling window. # #Returns: # # StatusWindow instance # #NOTE: # # Sample implementation of status interface. Status interface #requires .show(), .update_message(message), and .hide() methods. def __init__( self, parent ): global wifi_radar_icon self.parent = parent self.dialog = gtk.Dialog("Working", self.parent.window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT) icon = gtk.gdk.pixbuf_new_from_inline( len( wifi_radar_icon[0] ), wifi_radar_icon[0], False ) self.dialog.set_icon( icon ) self.lbl = gtk.Label("Please wait...") self.bar = gtk.ProgressBar() self.dialog.vbox.pack_start(self.lbl) self.dialog.vbox.pack_start(self.bar) self.cancel_button = self.dialog.add_button(gtk.STOCK_CANCEL, gtk.BUTTONS_CANCEL) self.timer = None # Change the message displayed to the user. # #Parameters: # # 'message' -- string - The message to show to the user. # #Returns: # # nothing def update_message( self, message ): self.lbl.set_text(message) # Update the StatusWindow progress bar. # #Parameters: # # nothing # #Returns: # # True -- always return True def update_window( self ): self.bar.pulse() return True # Display and operate the StatusWindow. # #Parameters: # # nothing # #Returns: # # nothing def run( self ): pass # Show all the widgets of the StatusWindow. # #Parameters: # # nothing # #Returns: # # nothing def show( self ): self.dialog.show_all() self.timer = gobject.timeout_add(250, self.update_window) return False # Hide all the widgets of the StatusWindow. # #Parameters: # # nothing # #Returns: # # nothing def hide( self ): if self.timer: gobject.source_remove(self.timer) self.timer = None self.dialog.hide_all() return False # Remove the StatusWindow. # #Parameters: # # nothing # #Returns: # # nothing def destroy( self ): if self.timer: gobject.source_remove(self.timer) self.dialog.destroy() del self.dialog # Manage a GTK About Dialog class about_dialog(gtk.AboutDialog): # Subclass GTK AboutDialog # #Parameters: # # nothing # #Returns: # # nothing def __init__( self ): global wifi_radar_icon gtk.AboutDialog.__init__(self) self.set_authors(["Ahmad Baitalmal ", "Brian Elliott Finley ", "Sean Robinson ", "", "Contributors", "Douglas Breault", "Jon Collette", "David Decotigny", "Simon Gerber", "Joey Hurst", "Ante Karamatic", "Richard Monk", "Nicolas Brouard", "Kevin Otte", "Nathanael Rebsch", "Andrea Scarpino", "Prokhor Shuchalov", "Patrick Winnertz"]) self.set_comments("WiFi connection manager") self.set_copyright("Copyright 2004-2010 by various authors and contributors\nCurrent Maintainer: Sean Robinson ") self.set_documenters(["Gary Case"]) license = """ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA""" self.set_license(license) logo = gtk.gdk.pixbuf_new_from_inline( len( wifi_radar_icon[0] ), wifi_radar_icon[0], False ) self.set_logo(logo) self.set_name("WiFi Radar") self.set_version(WIFI_RADAR_VERSION) self.set_website("http://wifi-radar.berlios.de") # Manage the configuration for the application, including reading and writing the config from/to a file. class ConfigFile(ConfigParser.SafeConfigParser): # Create a new ConfigFile. # #Parameters: # # 'filename' -- string - The configuration file's name. # # 'defaults' -- dictionary - Default values for the DEFAULT section. # #Returns: # # ConfigFile instance def __init__( self, filename, defaults, raw=False ): self.filename = filename self.raw = raw self.auto_profile_order = [] ConfigParser.SafeConfigParser.__init__(self, defaults) # Set the contents of a section to values from a dictionary. # #Parameters: # # 'section_name' -- string - Configuration file section. # # 'section_dict' -- dictionary - Values to add to section. # #Returns: # # nothing def set_section( self, section_name, section_dict ): try: self.add_section(section_name) except ConfigParser.DuplicateSectionError: pass for key in section_dict.keys(): if type(section_dict[key]) == BooleanType: self.set_bool_opt(section_name + "." + key, section_dict[key]) elif type(section_dict[key]) == IntType: self.set_int_opt(section_name + "." + key, section_dict[key]) elif type(section_dict[key]) == FloatType: self.set_float_opt(section_name + "." + key, section_dict[key]) else: self.set_opt(section_name + "." + key, section_dict[key]) # Return the profile recorded in the specified section. # #Parameters: # # 'section_name' -- string - Configuration file section. # #Returns: # # dictionary or None - The specified profile or None if not found def get_profile( self, section_name ): if section_name in self.profiles(): str_types = [ 'bssid', 'channel', 'essid', 'protocol', 'con_prescript', 'con_postscript', 'dis_prescript', 'dis_postscript', 'key', 'mode', 'security', 'wpa_driver', 'ip', 'netmask', 'gateway', 'domain', 'dns1', 'dns2' ] bool_types = [ 'known', 'available', 'roaming', 'encrypted', 'use_wpa', 'use_dhcp' ] int_types = [ 'signal' ] profile = get_new_profile() for option in bool_types: profile[option] = self.get_opt_as_bool(section_name + "." + option) for option in int_types: option_tmp = self.get_opt_as_int(section_name + "." + option) if option_tmp: profile[option] = option_tmp for option in str_types: option_tmp = self.get_opt(section_name + "." + option) if option_tmp: profile[option] = option_tmp return profile return None # Get a config option and handle exceptions. # #Parameters: # # 'option_path' -- string - Section (a.k.a. profile) name concatenated with a # period and the option key. (E.g. "DEFAULT.interface") # #Returns: # # string or None - option value as string or None on failure def get_opt( self, option_path ): #print "ConfigFile.get_opt: ", option_path (section, option) = option_path.split('.') try: return self.get(section, option, self.raw) except (ConfigParser.NoSectionError, ConfigParser.NoOptionError): return None # Get a config option and return as a boolean type. # #Parameters: # # 'option_path' -- string - Section (a.k.a. profile) name concatenated with a # period and the option key. (E.g. "DEFAULT.interface") # #Returns: # # boolean - option value as boolean def get_opt_as_bool( self, option_path ): option = self.get_opt(option_path) if isinstance(option, BooleanType) or isinstance(option, NoneType): return option if option == 'True': return True if option == 'False': return False raise ValueError, 'boolean option was not True or False' # Get a config option and return as an integer type. # #Parameters: # # 'option_path' -- string - Section (a.k.a. profile) name concatenated with a # period and the option key. (E.g. "DEFAULT.interface") # #Returns: # # integer- option value as integer def get_opt_as_int( self, option_path ): return int(float(self.get_opt(option_path))) # Convert boolean type to string and set config option. # #Parameters: # # 'option_path' -- string - Section (a.k.a. profile) name concatenated with a # period and the option key. (E.g. "DEFAULT.interface") # # 'value' -- boolean - Value to set. # #Returns: # # nothing def set_bool_opt( self, option_path, value ): if ( value == True ) or ( value > 0 ) or ( value == 'True' ): value == 'True' elif ( value == False ) or ( value == 0 ) or ( value == 'False' ): value == 'False' else: raise ValueError, 'cannot convert value to string' self.set_opt(option_path, repr(value)) # Convert integer type to string and set config option. # #Parameters: # # 'option_path' -- string - Section (a.k.a. profile) name concatenated with a # period and the option key. (E.g. "DEFAULT.interface") # # 'value' -- integer - Value to set. # #Returns: # # nothing def set_int_opt( self, option_path, value ): if not isinstance(value, IntType): raise ValueError, 'value is not an integer' self.set_opt(option_path, repr(value)) # Convert float type to string and set config option. # #Parameters: # # 'option_path' -- string - Section (a.k.a. profile) name concatenated with a # period and the option key. (E.g. "DEFAULT.interface") # # 'value' -- float - Value to set. # #Returns: # # nothing def set_float_opt( self, option_path, value ): if not isinstance(value, FloatType): raise ValueError, 'value is not a float' self.set_opt(option_path, repr(int(value))) # Set a config option while handling exceptions. # #Parameters: # # 'option_path' -- string - Section (a.k.a. profile) name concatenated with a # period and the option key. (E.g. "DEFAULT.interface") # # 'value' -- string - Value to set. # #Returns: # # nothing def set_opt( self, option_path, value ): (section, option) = option_path.split('.') try: self.set(section, option, value) except ConfigParser.NoSectionError: self.add_section(section) self.set_opt(option_path, value) # Return a list of the section names which denote AP profiles. # #Parameters: # # nothing # #Returns: # # list - profile names def profiles( self ): profile_list = [] for section in self.sections(): if ':' in section: profile_list.append(section) return profile_list # Read configuration file from disk into instance variables. # #Parameters: # # nothing # #Returns: # # nothing def read( self ): fp = open( self.filename, "r" ) self.readfp(fp) # convert the auto_profile_order to a list for ordering self.auto_profile_order = eval(self.get_opt('DEFAULT.auto_profile_order')) for ap in self.profiles(): self.set_bool_opt( ap + '.known', True) if ap in self.auto_profile_order: continue self.auto_profile_order.append( ap ) fp.close() # Remove any auto_profile_order AP without a matching section. auto_profile_order_copy = self.auto_profile_order[:] for ap in auto_profile_order_copy: if ap not in self.profiles(): self.auto_profile_order.remove(ap) # Write configuration file to disk from instance variables. Copied from # ConfigParser and modified to write options in alphabetical order. # #Parameters: # # nothing # #Returns: # # nothing def write( self ): self.set_opt('DEFAULT.auto_profile_order', str(self.auto_profile_order)) self.set_opt('DEFAULT.version', WIFI_RADAR_VERSION) (fd, tempfilename) = tempfile.mkstemp(prefix="wifi-radar.conf.") fp = os.fdopen(fd, "w") # write DEFAULT section first if self._defaults: fp.write("[DEFAULT]\n") for key in sorted(self._defaults.keys()): fp.write("%s = %s\n" % (key, str(self._defaults[key]).replace('\n','\n\t'))) fp.write("\n") # write other non-profile sections next for section in self._sections: if section not in self.profiles(): fp.write("[%s]\n" % section) for key in sorted(self._sections[section].keys()): if key != "__name__": fp.write("%s = %s\n" % (key, str(self._sections[section][key]).replace('\n', '\n\t'))) fp.write("\n") # write profile sections for section in self._sections: if section in self.profiles(): fp.write("[%s]\n" % section) for key in sorted(self._sections[section].keys()): if key != "__name__": fp.write("%s = %s\n" % (key, str(self._sections[section][key]).replace('\n', '\n\t'))) fp.write("\n") fp.close() move(tempfilename, self.filename) # Load our conf file and known profiles # Defaults, these may get overridden by values found in the conf file. config_defaults = { # The network interface you use. # Specify "auto_detect" as the interface to make wifi-radar automatically detect your wireless card. 'interface': "auto_detect", # How long should the scan for access points last? #'scan_timeout': '5', # X1000 Linux has a say command (text to speech) to announce connecting to networks. # Set the speak_up option to false if you do not have or want this. 'speak_command': '/usr/bin/say', # Should I speak up when connecting to a network? (If you have a speech command) 'speak_up': 'False', # You may set this to true for cards that require a "commit" command with iwconfig 'commit_required': 'False', # You may set this to true for cards that require the interface to be brought up first 'ifup_required': 'False', # set the location and verbosity of the log file 'logfile': '/var/log/wifi-radar.log', 'loglevel': '50', # Set the location of several important programs 'iwlist_command': '/sbin/iwlist', 'iwconfig_command': '/sbin/iwconfig', 'ifconfig_command': '/sbin/ifconfig', 'route_command': '/sbin/route', 'auto_profile_order': '[]', 'version': WIFI_RADAR_VERSION } config_dhcp = { # DHCP client 'command': '/sbin/dhcpcd', # How long to wait for an IP addr from DHCP server 'timeout': '30', # Arguments to use with DHCP client on connect 'args': '-D -o -i dhcp_client -t %(timeout)s', # Argument to use with DHCP client on disconnect 'kill_args': '-k', # The file where DHCP client PID is written 'pidfile': '/etc/dhcpc/dhcpcd-%(interface)s.pid' } config_wpa = { # WPA Supplicant 'command': '/usr/sbin/wpa_supplicant', # Arguments to use with WPA Supplicant on connect 'args': '-B -i %(interface)s -c %(configuration)s -D %(driver)s -P %(pidfile)s', # Arguments to use with WPA Supplicant on disconnect 'kill_command': '', # Where the WPA Supplicant config file can be found 'configuration': '/etc/wpa_supplicant.conf', # Driver to use with WPA Supplicant 'driver': 'wext', # The file where WPA Supplicant PID is written 'pidfile': '/var/run/wpa_supplicant.pid' } # initialize config, with defaults confFile = ConfigFile(CONF_FILE, config_defaults) confFile.set_section("DHCP", config_dhcp) confFile.set_section("WPA", config_wpa) if not os.path.isfile( CONF_FILE ): confFile.set_bool_opt('DEFAULT.new_file', True) else: if not os.access(CONF_FILE, os.R_OK): print "Can't open " + CONF_FILE + "." print "Are you root?" sys.exit() try: confFile.read() except NameError: error_dlg = ErrorDialog(None, "A configuration file from a pre-2.0 version of WiFi Radar was found at %s.\n\nWiFi Radar v2.0.x does not read configuration files from previous versions. Because %s may contain information that you might wish to use when configuring WiFi Radar %s, rename this file and run the program again.\n" % (CONF_FILE, CONF_FILE, WIFI_RADAR_VERSION)) del error_dlg print "ERROR: A configuration file from a pre-2.0 version of WiFi Radar was found at %s.\n\nWiFi Radar v2.0.x does not read configuration files from previous versions. Because %s may contain information that you might wish to use when configuring WiFi Radar %s, rename this file and run the program again.\n" % (CONF_FILE, CONF_FILE, WIFI_RADAR_VERSION) sys.exit() except SyntaxError: error_dlg = ErrorDialog(None, "A configuration file from a pre-2.0 version of WiFi Radar was found at %s.\n\nWiFi Radar v2.0.x does not read configuration files from previous versions. The old configuration file is probably empty and can be removed. Rename %s if you want to be very careful. After removing or renaming %s, run this program again.\n" % (CONF_FILE, CONF_FILE, CONF_FILE)) del error_dlg print "ERROR: A configuration file from a pre-2.0 version of WiFi Radar was found at %s.\n\nWiFi Radar v2.0.x does not read configuration files from previous versions. The old configuration file is probably empty and can be removed. Rename %s if you want to be very careful. After removing or renaming %s, run this program again.\n" % (CONF_FILE, CONF_FILE, CONF_FILE) sys.exit() #################################################################################################### # Embedded Images wifi_radar_icon = [ "" "GdkP" "\0\0\22""7" "\2\1\0\2" "\0\0\1\214" "\0\0\0c" "\0\0\0O" "\377\377\377\377\0\377\377\377\377\0\377\377\377\377\0\377\377\377\377" "\0\377\377\377\377\0\377\377\377\377\0\377\377\377\377\0\261\377\377" "\377\0\7\0\0\0\10\0\0\0\25\0\0\0\35\0\0\0%\0\0\0-\0\0\0\"\0\0\0\11\327" "\377\377\377\0\6\0\0\0\"\0\0\0_\0\0\0\213\0\0\0\266\0\0\0\341\0\0\0\376" "\206\0\0\0\377\6\0\0\0\356\0\0\0\324\0\0\0\265\0\0\0~\0\0\0@\0\0\0\10" "\315\377\377\377\0\4\0\0\0\2\0\0\0;\0\0\0\210\0\0\0\325\221\0\0\0\377" "\4\0\0\0\371\0\0\0\303\0\0\0w\0\0\0\31\310\377\377\377\0\3\0\0\0\6\0" "\0\0m\0\0\0\342\227\0\0\0\377\4\0\0\0\374\0\0\0\264\0\0\0Q\0\0\0\5\303" "\377\377\377\0\3\0\0\0\4\0\0\0d\0\0\0\341\234\0\0\0\377\3\0\0\0\341\0" "\0\0`\0\0\0\2\277\377\377\377\0\3\0\0\0\2\0\0\0[\0\0\0\333\240\0\0\0" "\377\2\0\0\0\323\0\0\0K\274\377\377\377\0\3\0\0\0\1\0\0\0R\0\0\0\324" "\244\0\0\0\377\2\0\0\0\276\0\0\0#\271\377\377\377\0\2\0\0\0\31\0\0\0" "\277\247\0\0\0\377\2\0\0\0\363\0\0\0c\267\377\377\377\0\2\0\0\0/\0\0" "\0\343\252\0\0\0\377\2\0\0\0\257\0\0\0\24\264\377\377\377\0\2\0\0\0M" "\0\0\0\363\220\0\0\0\377\14\0\0\0\357\0\0\0\304\0\0\0\230\0\0\0v\0\0" "\0l\0\0\0c\0\0\0[\0\0\0j\0\0\0\205\0\0\0\240\0\0\0\311\0\0\0\373\220" "\0\0\0\377\2\0\0\0\346\0\0\0""4\262\377\377\377\0\2\0\0\0q\0\0\0\375" "\215\0\0\0\377\4\0\0\0\373\0\0\0\300\0\0\0t\0\0\0)\213\377\377\377\0" "\4\0\0\0\14\0\0\0E\0\0\0\205\0\0\0\334\216\0\0\0\377\2\0\0\0\363\0\0" "\0D\257\377\377\377\0\2\0\0\0\4\0\0\0\230\215\0\0\0\377\3\0\0\0\372\0" "\0\0\231\0\0\0\34\221\377\377\377\0\4\0\0\0\1\0\0\0C\0\0\0\251\0\0\0" "\372\214\0\0\0\377\2\0\0\0\371\0\0\0W\255\377\377\377\0\2\0\0\0\17\0" "\0\0\272\214\0\0\0\377\3\0\0\0\375\0\0\0\241\0\0\0\"\226\377\377\377" "\0\2\0\0\0\"\0\0\0\252\214\0\0\0\377\2\0\0\0\375\0\0\0k\253\377\377\377" "\0\2\0\0\0\25\0\0\0\324\213\0\0\0\377\3\0\0\0\376\0\0\0\252\0\0\0(\232" "\377\377\377\0\2\0\0\0""9\0\0\0\312\214\0\0\0\377\1\0\0\0\200\251\377" "\377\377\0\2\0\0\0\5\0\0\0\303\213\0\0\0\377\2\0\0\0\332\0\0\0""1\235" "\377\377\377\0\3\0\0\0\4\0\0\0\201\0\0\0\374\213\0\0\0\377\1\0\0\0p\250" "\377\377\377\0\1\0\0\0\222\213\0\0\0\377\2\0\0\0\301\0\0\0\22\240\377" "\377\377\0\2\0\0\0:\0\0\0\336\212\0\0\0\377\2\0\0\0\374\0\0\0I\246\377" "\377\377\0\1\0\0\0[\213\0\0\0\377\2\0\0\0\241\0\0\0\6\212\377\377\377" "\0\15\0\0\0\2\0\0\0&\0\0\0U\0\0\0\203\0\0\0\242\0\0\0\243\0\0\0\234\0" "\0\0\225\0\0\0\215\0\0\0\206\0\0\0}\0\0\0\\\0\0\0!\213\377\377\377\0" "\2\0\0\0\22\0\0\0\307\212\0\0\0\377\2\0\0\0\361\0\0\0+\244\377\377\377" "\0\2\0\0\0.\0\0\0\365\211\0\0\0\377\2\0\0\0\376\0\0\0|\211\377\377\377" "\0\4\0\0\0#\0\0\0d\0\0\0\223\0\0\0\277\214\0\0\0\310\4\0\0\0\253\0\0" "\0l\0\0\0-\0\0\0\2\210\377\377\377\0\2\0\0\0\12\0\0\0\267\212\0\0\0\377" "\2\0\0\0\336\0\0\0\24\242\377\377\377\0\2\0\0\0\20\0\0\0\334\211\0\0" "\0\377\2\0\0\0\367\0\0\0W\210\377\377\377\0\2\0\0\0#\0\0\0\211\223\0" "\0\0\310\3\0\0\0\266\0\0\0t\0\0\0\27\207\377\377\377\0\2\0\0\0\5\0\0" "\0\244\212\0\0\0\377\2\0\0\0\302\0\0\0\6\240\377\377\377\0\2\0\0\0\1" "\0\0\0\264\211\0\0\0\377\2\0\0\0\363\0\0\0""9\207\377\377\377\0\3\0\0" "\0\34\0\0\0\201\0\0\0\306\226\0\0\0\310\3\0\0\0\277\0\0\0Y\0\0\0\2\206" "\377\377\377\0\2\0\0\0\1\0\0\0\217\212\0\0\0\377\1\0\0\0\203\240\377" "\377\377\0\1\0\0\0\177\212\0\0\0\377\1\0\0\0T\206\377\377\377\0\3\0\0" "\0\25\0\0\0z\0\0\0\305\232\0\0\0\310\2\0\0\0\242\0\0\0*\207\377\377\377" "\0\1\0\0\0\243\211\0\0\0\377\2\0\0\0\372\0\0\0,\236\377\377\377\0\2\0" "\0\0D\0\0\0\375\211\0\0\0\377\1\0\0\0\213\206\377\377\377\0\2\0\0\0""8" "\0\0\0\274\235\0\0\0\310\3\0\0\0\306\0\0\0u\0\0\0\14\205\377\377\377" "\0\2\0\0\0\7\0\0\0\306\211\0\0\0\377\2\0\0\0\306\0\0\0\2\234\377\377" "\377\0\2\0\0\0\4\0\0\0\331\211\0\0\0\377\2\0\0\0\276\0\0\0\3\205\377" "\377\377\0\2\0\0\0T\0\0\0\306\214\0\0\0\310\10\0\0\0\260\0\0\0\202\0" "\0\0v\0\0\0~\0\0\0\207\0\0\0\217\0\0\0\227\0\0\0\264\214\0\0\0\310\2" "\0\0\0\264\0\0\0""2\205\377\377\377\0\2\0\0\0\27\0\0\0\341\211\0\0\0" "\377\1\0\0\0k\234\377\377\377\0\1\0\0\0c\211\0\0\0\377\2\0\0\0\343\0" "\0\0\26\204\377\377\377\0\2\0\0\0\2\0\0\0s\212\0\0\0\310\4\0\0\0\265" "\0\0\0s\0\0\0D\0\0\0\26\207\377\377\377\0\4\0\0\0\1\0\0\0+\0\0\0j\0\0" "\0\250\212\0\0\0\310\2\0\0\0\303\0\0\0A\205\377\377\377\0\2\0\0\0/\0" "\0\0\364\210\0\0\0\377\2\0\0\0\362\0\0\0\33\232\377\377\377\0\2\0\0\0" "\7\0\0\0\341\210\0\0\0\377\2\0\0\0\371\0\0\0""7\204\377\377\377\0\2\0" "\0\0\12\0\0\0\217\211\0\0\0\310\3\0\0\0\271\0\0\0]\0\0\0\10\216\377\377" "\377\0\3\0\0\0\36\0\0\0t\0\0\0\306\210\0\0\0\310\2\0\0\0\306\0\0\0P\205" "\377\377\377\0\1\0\0\0a\211\0\0\0\377\1\0\0\0\257\232\377\377\377\0\1" "\0\0\0n\211\0\0\0\377\1\0\0\0h\204\377\377\377\0\2\0\0\0\20\0\0\0\245" "\210\0\0\0\310\3\0\0\0\274\0\0\0c\0\0\0\12\222\377\377\377\0\2\0\0\0" "*\0\0\0\242\211\0\0\0\310\1\0\0\0`\205\377\377\377\0\1\0\0\0\276\211" "\0\0\0\377\1\0\0\0:\230\377\377\377\0\2\0\0\0\13\0\0\0\350\210\0\0\0" "\377\1\0\0\0\250\204\377\377\377\0\2\0\0\0\3\0\0\0\230\210\0\0\0\310" "\2\0\0\0\213\0\0\0\15\225\377\377\377\0\3\0\0\0\2\0\0\0Z\0\0\0\277\210" "\0\0\0\310\1\0\0\0U\204\377\377\377\0\2\0\0\0%\0\0\0\370\210\0\0\0\377" "\1\0\0\0\265\230\377\377\377\0\1\0\0\0y\210\0\0\0\377\2\0\0\0\372\0\0" "\0\40\204\377\377\377\0\1\0\0\0o\210\0\0\0\310\2\0\0\0o\0\0\0\2\230\377" "\377\377\0\2\0\0\0\30\0\0\0\226\207\0\0\0\310\2\0\0\0\306\0\0\0""7\204" "\377\377\377\0\1\0\0\0|\211\0\0\0\377\1\0\0\0""0\226\377\377\377\0\2" "\0\0\0\20\0\0\0\356\210\0\0\0\377\1\0\0\0\226\204\377\377\377\0\1\0\0" "\0C\207\0\0\0\310\2\0\0\0\305\0\0\0R\233\377\377\377\0\2\0\0\0\5\0\0" "\0\210\207\0\0\0\310\2\0\0\0\273\0\0\0\37\203\377\377\377\0\2\0\0\0\6" "\0\0\0\325\210\0\0\0\377\1\0\0\0\251\226\377\377\377\0\1\0\0\0\204\210" "\0\0\0\377\2\0\0\0\366\0\0\0\32\203\377\377\377\0\2\0\0\0!\0\0\0\277" "\206\0\0\0\310\2\0\0\0\275\0\0\0""8\235\377\377\377\0\2\0\0\0\2\0\0\0" "|\207\0\0\0\310\2\0\0\0\254\0\0\0\15\203\377\377\377\0\1\0\0\0J\210\0" "\0\0\377\2\0\0\0\375\0\0\0&\224\377\377\377\0\2\0\0\0\26\0\0\0\364\210" "\0\0\0\377\1\0\0\0\214\203\377\377\377\0\2\0\0\0\12\0\0\0\251\206\0\0" "\0\310\2\0\0\0\305\0\0\0""0\240\377\377\377\0\1\0\0\0r\207\0\0\0\310" "\1\0\0\0[\204\377\377\377\0\1\0\0\0\317\210\0\0\0\377\1\0\0\0\236\224" "\377\377\377\0\1\0\0\0\204\210\0\0\0\377\2\0\0\0\362\0\0\0\24\203\377" "\377\377\0\1\0\0\0\206\207\0\0\0\310\1\0\0\0X\214\377\377\377\0\11\0" "\0\0\5\0\0\0$\0\0\0G\0\0\0X\0\0\0T\0\0\0O\0\0\0K\0\0\0B\0\0\0\35\214" "\377\377\377\0\2\0\0\0\2\0\0\0\214\206\0\0\0\310\2\0\0\0\307\0\0\0""1" "\203\377\377\377\0\1\0\0\0V\210\0\0\0\377\2\0\0\0\372\0\0\0\27\223\377" "\377\377\0\1\0\0\0\271\210\0\0\0\377\1\0\0\0\202\203\377\377\377\0\1" "\0\0\0@\207\0\0\0\310\1\0\0\0\204\212\377\377\377\0\4\0\0\0\7\0\0\0E" "\0\0\0u\0\0\0\222\210\0\0\0\226\4\0\0\0\204\0\0\0T\0\0\0$\0\0\0\1\211" "\377\377\377\0\2\0\0\0\12\0\0\0\245\206\0\0\0\310\2\0\0\0\251\0\0\0\5" "\202\377\377\377\0\2\0\0\0\2\0\0\0\331\210\0\0\0\377\1\0\0\0C\223\377" "\377\377\0\1\0\0\0\342\207\0\0\0\377\2\0\0\0\356\0\0\0\17\202\377\377" "\377\0\2\0\0\0\2\0\0\0\246\206\0\0\0\310\2\0\0\0\246\0\0\0\11\210\377" "\377\377\0\3\0\0\0\5\0\0\0D\0\0\0\212\216\0\0\0\226\2\0\0\0z\0\0\0\40" "\211\377\377\377\0\2\0\0\0\32\0\0\0\274\206\0\0\0\310\1\0\0\0d\203\377" "\377\377\0\1\0\0\0a\210\0\0\0\377\1\0\0\0b\222\377\377\377\0\2\0\0\0" "\10\0\0\0\375\207\0\0\0\377\1\0\0\0x\203\377\377\377\0\1\0\0\0G\206\0" "\0\0\310\2\0\0\0\275\0\0\0\36\210\377\377\377\0\2\0\0\0""3\0\0\0\207" "\221\0\0\0\226\3\0\0\0\225\0\0\0X\0\0\0\11\210\377\377\377\0\1\0\0\0" "R\206\0\0\0\310\2\0\0\0\302\0\0\0\23\202\377\377\377\0\2\0\0\0\5\0\0" "\0\342\207\0\0\0\377\1\0\0\0\201\223\377\377\377\0\1\0\0\0m\206\0\0\0" "\377\2\0\0\0\321\0\0\0\12\202\377\377\377\0\2\0\0\0\3\0\0\0\254\206\0" "\0\0\310\1\0\0\0J\207\377\377\377\0\2\0\0\0\1\0\0\0O\210\0\0\0\226\1" "\0\0\0\206\202\0\0\0h\3\0\0\0m\0\0\0s\0\0\0\214\207\0\0\0\226\2\0\0\0" "\210\0\0\0)\207\377\377\377\0\2\0\0\0\1\0\0\0\233\206\0\0\0\310\1\0\0" "\0l\203\377\377\377\0\2\0\0\0P\0\0\0\374\205\0\0\0\377\2\0\0\0\337\0" "\0\0\"\224\377\377\377\0\1\0\0\0s\204\0\0\0\377\2\0\0\0\315\0\0\0\23" "\203\377\377\377\0\1\0\0\0N\206\0\0\0\310\2\0\0\0\245\0\0\0\2\206\377" "\377\377\0\2\0\0\0\6\0\0\0f\206\0\0\0\226\3\0\0\0w\0\0\0""7\0\0\0\23" "\205\377\377\377\0\4\0\0\0\3\0\0\0*\0\0\0[\0\0\0\212\205\0\0\0\226\2" "\0\0\0\222\0\0\0*\207\377\377\377\0\2\0\0\0#\0\0\0\304\205\0\0\0\310" "\2\0\0\0\277\0\0\0\16\203\377\377\377\0\2\0\0\0]\0\0\0\376\203\0\0\0" "\377\2\0\0\0\332\0\0\0\35\226\377\377\377\0\5\0\0\0;\0\0\0j\0\0\0\223" "\0\0\0\244\0\0\0\20\203\377\377\377\0\2\0\0\0\5\0\0\0\260\206\0\0\0\310" "\1\0\0\0>\206\377\377\377\0\2\0\0\0\14\0\0\0z\205\0\0\0\226\2\0\0\0|" "\0\0\0/\213\377\377\377\0\3\0\0\0\10\0\0\0U\0\0\0\224\204\0\0\0\226\2" "\0\0\0\221\0\0\0%\207\377\377\377\0\1\0\0\0s\206\0\0\0\310\1\0\0\0d\204" "\377\377\377\0\5\0\0\0a\0\0\0\240\0\0\0\177\0\0\0]\0\0\0\26\237\377\377" "\377\0\1\0\0\0U\206\0\0\0\310\1\0\0\0\235\206\377\377\377\0\2\0\0\0\2" "\0\0\0r\204\0\0\0\226\3\0\0\0\225\0\0\0J\0\0\0\1\216\377\377\377\0\2" "\0\0\0\35\0\0\0w\204\0\0\0\226\2\0\0\0\217\0\0\0\40\206\377\377\377\0" "\2\0\0\0\27\0\0\0\304\205\0\0\0\310\2\0\0\0\273\0\0\0\12\247\377\377" "\377\0\1\0\0\0\236\206\0\0\0\310\1\0\0\0""5\206\377\377\377\0\1\0\0\0" "T\204\0\0\0\226\2\0\0\0\221\0\0\0""3\221\377\377\377\0\2\0\0\0\4\0\0" "\0l\204\0\0\0\226\2\0\0\0\215\0\0\0\34\206\377\377\377\0\1\0\0\0}\206" "\0\0\0\310\1\0\0\0E\247\377\377\377\0\1\0\0\0\276\205\0\0\0\310\1\0\0" "\0\224\206\377\377\377\0\1\0\0\0""4\204\0\0\0\226\2\0\0\0\214\0\0\0\40" "\223\377\377\377\0\2\0\0\0\5\0\0\0q\204\0\0\0\226\2\0\0\0\211\0\0\0\14" "\205\377\377\377\0\2\0\0\0\37\0\0\0\306\205\0\0\0\310\1\0\0\0`\246\377" "\377\377\0\2\0\0\0\12\0\0\0\277\205\0\0\0\310\1\0\0\0+\205\377\377\377" "\0\2\0\0\0\30\0\0\0\220\203\0\0\0\226\2\0\0\0\225\0\0\0*\225\377\377" "\377\0\2\0\0\0\10\0\0\0v\204\0\0\0\226\1\0\0\0X\206\377\377\377\0\1\0" "\0\0\207\205\0\0\0\310\1\0\0\0m\247\377\377\377\0\2\0\0\0""3\0\0\0\301" "\203\0\0\0\310\1\0\0\0[\206\377\377\377\0\1\0\0\0n\204\0\0\0\226\1\0" "\0\0G\227\377\377\377\0\2\0\0\0\12\0\0\0z\203\0\0\0\226\2\0\0\0\224\0" "\0\0\27\205\377\377\377\0\2\0\0\0\20\0\0\0\246\203\0\0\0\310\2\0\0\0" "\224\0\0\0\11\250\377\377\377\0\4\0\0\0,\0\0\0h\0\0\0\210\0\0\0R\206" "\377\377\377\0\1\0\0\0&\204\0\0\0\226\2\0\0\0f\0\0\0\1\230\377\377\377" "\0\2\0\0\0\26\0\0\0\224\203\0\0\0\226\1\0\0\0g\206\377\377\377\0\5\0" "\0\0\22\0\0\0\206\0\0\0y\0\0\0]\0\0\0\6\263\377\377\377\0\1\0\0\0t\203" "\0\0\0\226\2\0\0\0\216\0\0\0\13\232\377\377\377\0\1\0\0\0X\204\0\0\0" "\226\1\0\0\0#\274\377\377\377\0\1\0\0\0-\204\0\0\0\226\1\0\0\0K\233\377" "\377\377\0\2\0\0\0\15\0\0\0\217\203\0\0\0\226\1\0\0\0v\274\377\377\377" "\0\1\0\0\0t\203\0\0\0\226\2\0\0\0\213\0\0\0\10\213\377\377\377\0\5\0" "\0\0\5\0\0\0\30\0\0\0\40\0\0\0\36\0\0\0\22\214\377\377\377\0\1\0\0\0" "J\204\0\0\0\226\1\0\0\0*\273\377\377\377\0\1\0\0\0`\203\0\0\0\226\1\0" "\0\0E\212\377\377\377\0\3\0\0\0\13\0\0\0@\0\0\0Y\204\0\0\0Z\3\0\0\0Q" "\0\0\0""1\0\0\0\5\211\377\377\377\0\2\0\0\0\6\0\0\0\207\203\0\0\0\226" "\1\0\0\0\26\273\377\377\377\0\5\0\0\0""1\0\0\0\226\0\0\0\224\0\0\0n\0" "\0\0\5\211\377\377\377\0\2\0\0\0$\0\0\0U\202\0\0\0Z\4\0\0\0P\0\0\0E\0" "\0\0I\0\0\0X\202\0\0\0Z\2\0\0\0P\0\0\0\33\211\377\377\377\0\4\0\0\0""3" "\0\0\0\206\0\0\0\226\0\0\0\201\274\377\377\377\0\3\0\0\0\6\0\0\0""8\0" "\0\0\13\211\377\377\377\0\2\0\0\0\7\0\0\0A\202\0\0\0Z\2\0\0\0I\0\0\0" "\20\203\377\377\377\0\6\0\0\0\4\0\0\0\37\0\0\0O\0\0\0Z\0\0\0Y\0\0\0\36" "\212\377\377\377\0\2\0\0\0\34\0\0\0)\310\377\377\377\0\5\0\0\0<\0\0\0" "Z\0\0\0Y\0\0\0.\0\0\0\2\206\377\377\377\0\5\0\0\0\3\0\0\0;\0\0\0Z\0\0" "\0X\0\0\0\32\322\377\377\377\0\1\0\0\0\34\202\0\0\0Z\1\0\0\0\30\211\377" "\377\377\0\5\0\0\0\1\0\0\0>\0\0\0Z\0\0\0W\0\0\0\13\320\377\377\377\0" "\4\0\0\0\5\0\0\0P\0\0\0Z\0\0\0""5\213\377\377\377\0\4\0\0\0\2\0\0\0H" "\0\0\0Z\0\0\0:\320\377\377\377\0\4\0\0\0""4\0\0\0Z\0\0\0P\0\0\0\5\214" "\377\377\377\0\1\0\0\0\26\202\0\0\0Z\1\0\0\0\22\317\377\377\377\0\3\0" "\0\0+\0\0\0X\0\0\0\33\216\377\377\377\0\3\0\0\0>\0\0\0I\0\0\0\23\320" "\377\377\377\0\1\0\0\0\12\217\377\377\377\0\2\0\0\0\6\0\0\0\1\377\377" "\377\377\0\377\377\377\377\0\377\377\377\377\0\377\377\377\377\0\377" "\377\377\377\0\377\377\377\377\0\377\377\377\377\0\377\377\377\377\0" "\377\377\377\377\0\377\377\377\377\0\377\377\377\377\0\234\377\377\377" "\0"] known_profile_icon = [ "" "GdkP" "\0\0\5""0" "\2\1\0\2" "\0\0\0P" "\0\0\0\24" "\0\0\0\24" "\210\0\0\0\0\4\0\0\0\3\0\0\0\16\0\0\0\23\0\0\0\11\216\0\0\0\0\11\0\0" "\0\16\0\0\0h\0\0\0\301\0\0\0\345\0\0\0\352\0\0\0\331\0\0\0\237\0\0\0" "9\0\0\0\3\212\0\0\0\0\13\0\0\0@\0\0\0\323\0\0\0\376\0\0\0\350\0\0\0\304" "\0\0\0\271\0\0\0\323\0\0\0\367\0\0\0\370\0\0\0\227\0\0\0\17\210\0\0\0" "\0\15\0\0\0K\0\0\0\354\0\0\0\365\0\0\0\206\0\0\0#\0\0\0\6\0\0\0\3\0\0" "\0\15\0\0\0C\0\0\0\304\0\0\0\376\0\0\0\260\0\0\0\22\206\0\0\0\0\17\0" "\0\0""2\0\0\0\346\0\0\0\351\0\0\0L\0\0\0#\0\0\0u\0\0\0\246\0\0\0\257" "\0\0\0\223\0\0\0M\0\0\0\27\0\0\0\235\0\0\0\375\0\0\0\242\0\0\0\7\204" "\0\0\0\0\20\0\0\0\13\0\0\0\300\0\0\0\372\0\0\0W\0\0\0O\0\0\0\271\0\0" "\0\233\0\0\0b\0\0\0V\0\0\0z\0\0\0\267\0\0\0\223\0\0\0$\0\0\0\267\0\0" "\0\374\0\0\0X\204\0\0\0\0\7\0\0\0S\0\0\0\374\0\0\0\240\0\0\0H\0\0\0\275" "\0\0\0a\0\0\0\12\202\0\0\0\0\10\0\0\0\1\0\0\0%\0\0\0\240\0\0\0\241\0" "\0\0""9\0\0\0\352\0\0\0\320\0\0\0\12\203\0\0\0\0\21\0\0\0\262\0\0\0\351" "\0\0\0A\0\0\0\272\0\0\0g\0\0\0\6\0\0\0""4\0\0\0e\0\0\0l\0\0\0T\0\0\0" "\25\0\0\0\27\0\0\0\251\0\0\0v\0\0\0\214\0\0\0\367\0\0\0<\203\0\0\0\0" "\21\0\0\0""6\0\0\0G\0\0\0r\0\0\0\244\0\0\0\17\0\0\0P\0\0\0b\0\0\0#\0" "\0\0\27\0\0\0;\0\0\0s\0\0\0\33\0\0\0E\0\0\0\270\0\0\0""6\0\0\0\\\0\0" "\0\15\205\0\0\0\0\15\0\0\0T\0\0\0""8\0\0\0""0\0\0\0f\0\0\0\6\0\0\0\0" "\0\0\0\1\0\0\0\0\0\0\0(\0\0\0l\0\0\0\13\0\0\0k\0\0\0\33\206\0\0\0\0\16" "***;\210\210\210\356\223\223\223\377iii\377\204\204\204\377\216\216\216" "\377~~~\377zzz\377\203\203\203\377\215\215\215\377ddd\377\202\202\202" "\377xxx\356\40\40\40;\205\0\0\0\0\2&&&#\251\251\251\353\202\374\374\374" "\377\202\372\372\372\377\5\335\335\335\377\353\353\353\377\366\366\366" "\377\327\327\327\377\357\357\357\377\202\365\365\365\377\3\362\362\362" "\377\226\226\226\353\27\27\27)\204\0\0\0\0\21,,,p\354\354\354\377\355" "\355\355\377\351\351\351\377\346\346\346\377\342\342\342\377\335\335" "\335\377\334\334\334\377\330\330\330\377\324\324\324\377\320\320\320" "\377\316\316\316\377\313\313\313\377\307\307\307\377\314\314\314\377" "\35\35\35y\0\0\0\1\202\0\0\0\0\14\0\0\0\2(((\203\357\357\357\377\345" "\345\345\377\341\341\341\377\337\337\337\377\333\333\333\377\326\326" "\326\377\322\322\322\377\316\316\316\377\312\312\312\377\306\306\306" "\377\202\302\302\302\377\30\314\314\314\377\311\311\311\377\33\33\33" "\204\0\0\0\5\0\0\0\1\0\0\0\2\0\0\0\10&&&\210\356\356\356\377\342\342" "\342\377\347\347\347\377\346\346\346\377\324GG\377\337\337\337\377\324" "GG\377\333\322\322\377\324GG\377<\341@\377\324GG\377<\341@\377\321\321" "\321\377\276\276\276\377\27\27\27\214\0\0\0\15\202\0\0\0\4+\0\0\0\21" "$$$\221\355\355\355\377\345\345\345\377\344\344\344\377\340\340\340\377" "\334\334\334\377\331\331\331\377\325\325\325\377\321\321\321\377\316" "\316\316\377\312\312\312\377\306\306\306\377\307\307\307\377\313\313" "\313\377\272\272\272\377\24\24\24\226\0\0\0\30\0\0\0\10\0\0\0\5\0\0\0" "\27\"\"\"\231\354\354\354\377\346\346\346\377\342\342\342\377\337\337" "\337\377\333\333\333\377\327\327\327\377\324\324\324\377\320\320\320" "\377\314\314\314\377\310\310\310\377\305\305\305\377\301\301\301\377" "\276\276\276\377\271\271\271\377\23\23\23\235\0\0\0\35\0\0\0\10\0\0\0" "\4\0\0\0\32\40\40\40\223\310\310\310\376\202\274\274\274\377\4\272\272" "\272\377\271\271\271\377\270\270\270\377\267\267\267\377\202\271\271" "\271\377\16\270\270\270\377\266\266\266\377\265\265\265\377\264\264\264" "\377\231\231\231\376\16\16\16\240\0\0\0\35\0\0\0\6\0\0\0\2\0\0\0\12\0" "\0\0/\0\0\0n\0\0\0|\0\0\0\177\202\0\0\0\200\202\0\0\0\201\1\0\0\0\203" "\204\0\0\0\205\12\0\0\0\201\0\0\0y\0\0\0<\0\0\0\15\0\0\0\2\0\0\0\0\0" "\0\0\2\0\0\0\6\0\0\0\14\0\0\0\20\204\0\0\0\24\202\0\0\0\25\203\0\0\0" "\26\6\0\0\0\25\0\0\0\22\0\0\0\15\0\0\0\7\0\0\0\2\0\0\0\0"] unknown_profile_icon = [ "" "GdkP" "\0\0\5\22" "\2\1\0\2" "\0\0\0P" "\0\0\0\24" "\0\0\0\24" "\210\0\0\0\0\4\0\0\0\1\0\0\0\4\0\0\0\6\0\0\0\3\216\0\0\0\0\11\0\0\0\4" "\0\0\0\37\0\0\0""9\0\0\0D\0\0\0F\0\0\0@\0\0\0/\0\0\0\21\0\0\0\1\212\0" "\0\0\0\7\0\0\0\23\0\0\0\77\0\0\0K\0\0\0E\0\0\0:\0\0\0""7\0\0\0\77\202" "\0\0\0I\2\0\0\0-\0\0\0\4\210\0\0\0\0\15\0\0\0\26\0\0\0F\0\0\0I\0\0\0" "(\0\0\0\13\0\0\0\2\0\0\0\1\0\0\0\4\0\0\0\24\0\0\0:\0\0\0K\0\0\0""4\0" "\0\0\6\206\0\0\0\0\17\0\0\0\17\0\0\0D\0\0\0E\0\0\0\26\0\0\0\13\0\0\0" "#\0\0\0""1\0\0\0""4\0\0\0,\0\0\0\27\0\0\0\7\0\0\0/\0\0\0K\0\0\0""0\0" "\0\0\2\204\0\0\0\0\20\0\0\0\3\0\0\0""9\0\0\0J\0\0\0\32\0\0\0\30\0\0\0" "7\0\0\0.\0\0\0\35\0\0\0\32\0\0\0$\0\0\0""6\0\0\0,\0\0\0\13\0\0\0""6\0" "\0\0K\0\0\0\32\204\0\0\0\0\7\0\0\0\31\0\0\0K\0\0\0""0\0\0\0\25\0\0\0" "8\0\0\0\35\0\0\0\3\202\0\0\0\0\2\0\0\0\1\0\0\0\13\202\0\0\0""0\4\0\0" "\0\21\0\0\0F\0\0\0>\0\0\0\3\203\0\0\0\0\21\0\0\0""5\0\0\0E\0\0\0\23\0" "\0\0""7\0\0\0\37\0\0\0\2\0\0\0\20\0\0\0\36\0\0\0\40\0\0\0\31\0\0\0\6" "\0\0\0\7\0\0\0""2\0\0\0#\0\0\0)\0\0\0I\0\0\0\22\203\0\0\0\0\21\0\0\0" "\20\0\0\0\25\0\0\0\"\0\0\0""1\0\0\0\4\0\0\0\30\0\0\0\35\0\0\0\13\0\0" "\0\7\0\0\0\21\0\0\0\"\0\0\0\10\0\0\0\25\0\0\0""6\0\0\0\20\0\0\0\33\0" "\0\0\4\205\0\0\0\0\15\0\0\0\31\0\0\0\21\0\0\0\16\0\0\0\36\0\0\0\2\0\0" "\0\0\0\0\0\1\0\0\0\0\0\0\0\14\0\0\0\40\0\0\0\3\0\0\0\40\0\0\0\10\206" "\0\0\0\0\16***\21\210\210\210G\223\223\223LiiiL\204\204\204L\34=n\300" "\14""1i\361\12""0i\374\20""4j\342CXx}dddL\202\202\202LxxxG\40\40\40\21" "\205\0\0\0\0\2&&&\13\251\251\251F\202\374\374\374L\202\372\372\372L\5" "\"Cv\310Lf\217\226@]\211\245\12""0i\377\22""7n\353\202\365\365\365L\3" "\362\362\362L\226\226\226F\27\27\27\14\204\0\0\0\0\21,,,!\354\354\354" "L\355\355\355L\351\351\351L\346\346\346L\342\342\342L\335\335\335L\334" "\334\334L\210\227\255h\12""0i\377\21""6l\352\316\316\316L\313\313\313" "L\307\307\307L\314\314\314L\35\35\35$\0\0\0\1\202\0\0\0\0\14\0\0\0\1" "((('\357\357\357L\345\345\345L\341\341\341L\337\337\337L\333\333\333" "L\326\326\326L|\215\245l\20""5l\355\12""0i\374Sj\215\205\202\302\302" "\302L\4\314\314\314L\311\311\311L\33\33\33'\0\0\0\2\202\0\0\0\1\22\0" "\0\0\2&&&(\356\356\356L\342\342\342L\347\347\347L\346\346\346L\324GG" "L\337\337\337L\22""0g\351\12""0i\377^9Z\201<\341@L\324GGL<\341@L\321" "\321\321L\276\276\276L\27\27\27)\0\0\0\4\202\0\0\0\1\22\0\0\0\5$$$+\355" "\355\355L\345\345\345L\344\344\344L\340\340\340L\334\334\334L\331\331" "\331Law\227\177`u\226\177\316\316\316L\312\312\312L\306\306\306L\307" "\307\307L\313\313\313L\272\272\272L\24\24\24,\0\0\0\7\202\0\0\0\2\27" "\0\0\0\7\"\"\"-\354\354\354L\346\346\346L\342\342\342L\337\337\337L\333" "\333\333L\327\327\327LSk\217\212Qi\216\212\314\314\314L\310\310\310L" "\305\305\305L\301\301\301L\276\276\276L\271\271\271L\23\23\23/\0\0\0" "\10\0\0\0\2\0\0\0\1\0\0\0\10\40\40\40,\310\310\310K\202\274\274\274L" "\3\272\272\272L\271\271\271L\270\270\270L\202\12""0i\377\16\271\271\271" "L\270\270\270L\266\266\266L\265\265\265L\264\264\264L\231\231\231K\16" "\16\16""0\0\0\0\10\0\0\0\2\0\0\0\1\0\0\0\3\0\0\0\16\0\0\0!\0\0\0%\205" "\0\0\0&\205\0\0\0'\12\0\0\0&\0\0\0$\0\0\0\22\0\0\0\4\0\0\0\1\0\0\0\0" "\0\0\0\1\0\0\0\2\0\0\0\3\0\0\0\4\206\0\0\0\6\203\0\0\0\7\202\0\0\0\6" "\4\0\0\0\4\0\0\0\2\0\0\0\1\0\0\0\0"] signal_xpm_barely = [ "20 20 10 1", " c None", ". c #C6C6C6", "+ c #CCCCCC", "@ c #DBDBDB", "# c #D3D3D3", "$ c #A9B099", "% c #95A173", "& c #6B8428", "* c #B4B7AC", "= c #80924D", " .+++.", " +@@@+", " +@@@+", " +@@@+", " +@@@+", " .++++#@@@+", " +@@@@@@@@+", " +@@@@@@@@+", " +@@@@@@@@+", " +@@@@@@@@+", " $%%%%#@@@@@@@@+", " %&&&&@@@@@@@@@+", " %&&&&@@@@@@@@@+", " %&&&&@@@@@@@@@+", " %&&&&@@@@@@@@@+", "*%%%%=&&&&@@@@@@@@@+", "%&&&&&&&&&@@@@@@@@@+", "%&&&&&&&&&@@@@@@@@@+", "%&&&&&&&&&@@@@@@@@@+", "*%%%%%%%%%+++++++++." ] signal_xpm_best = [ "20 20 6 1", " c None", ". c #9DAABF", "+ c #7B96BF", "@ c #386EBF", "# c #5982BF", "$ c #AEB4BF", " .+++.", " +@@@+", " +@@@+", " +@@@+", " +@@@+", " .++++#@@@+", " +@@@@@@@@+", " +@@@@@@@@+", " +@@@@@@@@+", " +@@@@@@@@+", " .++++#@@@@@@@@+", " +@@@@@@@@@@@@@+", " +@@@@@@@@@@@@@+", " +@@@@@@@@@@@@@+", " +@@@@@@@@@@@@@+", "$++++#@@@@@@@@@@@@@+", "+@@@@@@@@@@@@@@@@@@+", "+@@@@@@@@@@@@@@@@@@+", "+@@@@@@@@@@@@@@@@@@+", "$++++++++++++++++++." ] signal_xpm_none = [ "20 20 6 1", " c None", ". c #C6C6C6", "+ c #CCCCCC", "@ c #DBDBDB", "# c #D3D3D3", "$ c #C2C2C2", " .+++.", " +@@@+", " +@@@+", " +@@@+", " +@@@+", " .++++#@@@+", " +@@@@@@@@+", " +@@@@@@@@+", " +@@@@@@@@+", " +@@@@@@@@+", " .++++#@@@@@@@@+", " +@@@@@@@@@@@@@+", " +@@@@@@@@@@@@@+", " +@@@@@@@@@@@@@+", " +@@@@@@@@@@@@@+", "$++++#@@@@@@@@@@@@@+", "+@@@@@@@@@@@@@@@@@@+", "+@@@@@@@@@@@@@@@@@@+", "+@@@@@@@@@@@@@@@@@@+", "$++++++++++++++++++." ] signal_xpm_ok = [ "20 20 10 1", " c None", ". c #C6C6C6", "+ c #CCCCCC", "@ c #DBDBDB", "# c #A1A5B2", "$ c #848DA5", "% c #D3D3D3", "& c #4A5B8C", "* c #677498", "= c #B0B2B8", " .+++.", " +@@@+", " +@@@+", " +@@@+", " +@@@+", " #$$$$%@@@+", " $&&&&@@@@+", " $&&&&@@@@+", " $&&&&@@@@+", " $&&&&@@@@+", " #$$$$*&&&&@@@@+", " $&&&&&&&&&@@@@+", " $&&&&&&&&&@@@@+", " $&&&&&&&&&@@@@+", " $&&&&&&&&&@@@@+", "=$$$$*&&&&&&&&&@@@@+", "$&&&&&&&&&&&&&&@@@@+", "$&&&&&&&&&&&&&&@@@@+", "$&&&&&&&&&&&&&&@@@@+", "=$$$$$$$$$$$$$$++++." ] signal_xpm_low = [ "20 20 8 1", " c None", ". c #C6C6C6", "+ c #CCCCCC", "@ c #DBDBDB", "# c #D3D3D3", "$ c #BFB0B5", "% c #C18799", "& c #C54F74", " .+++.", " +@@@+", " +@@@+", " +@@@+", " +@@@+", " .++++#@@@+", " +@@@@@@@@+", " +@@@@@@@@+", " +@@@@@@@@+", " +@@@@@@@@+", " .++++#@@@@@@@@+", " +@@@@@@@@@@@@@+", " +@@@@@@@@@@@@@+", " +@@@@@@@@@@@@@+", " +@@@@@@@@@@@@@+", "$%%%%#@@@@@@@@@@@@@+", "%&&&&@@@@@@@@@@@@@@+", "%&&&&@@@@@@@@@@@@@@+", "%&&&&@@@@@@@@@@@@@@+", "$%%%%++++++++++++++." ] #################################################################################################### # Make so we can be imported if __name__ == "__main__": if len( sys.argv ) > 1 and ( sys.argv[1] == '--version' or sys.argv[1] == '-v' ): print "WiFi Radar version %s" % WIFI_RADAR_VERSION elif len( sys.argv ) > 1 and ( sys.argv[1] == '--help' or sys.argv[1] == '-h' ): print "WiFi Radar version %s" % WIFI_RADAR_VERSION print "For help, check man pages for wifi-radar and wifi-radar.conf," print "or visit http://wifi-radar.berlios.de" else: import gtk, gobject gtk.gdk.threads_init() apQueue = Queue.Queue(100) commQueue = Queue.Queue(2) logger = logging.getLogger("wrlog") logger.setLevel(confFile.get_opt_as_int('DEFAULT.loglevel')) try: fileLogHandler = logging.handlers.RotatingFileHandler(confFile.get_opt('DEFAULT.logfile'), maxBytes=64*1024, backupCount=5) except IOError, (error_number, error_str): error_dlg = ErrorDialog(None, "Cannot open log file for writing: %s.\n\nWiFi Radar will work, but a log file will not be recorded." % (error_str)) del error_dlg else: fileLogHandler.setFormatter(logging.Formatter('%(asctime)s: %(levelname)s: %(funcName)s: %(message)s')) logger.addHandler(fileLogHandler) consoleLogHandler = logging.StreamHandler() consoleLogHandler.setFormatter(logging.Formatter('%(asctime)s: %(funcName)s: %(message)s')) logger.addHandler(consoleLogHandler) if __debug__: logger.setLevel(logging.INFO) exit_event = threading.Event() exit_event.clear() threading.Thread(None, scanning_thread, None, (confFile, apQueue, commQueue, logger, exit_event)).start() main_radar_window = radar_window(confFile, apQueue, commQueue, logger, exit_event) gobject.timeout_add( 500, main_radar_window.update_window ) main_radar_window.main() wifi-radar-2.0.s08+dfsg/docs/0000750000175000017500000000000011356151665015230 5ustar winniewinniewifi-radar-2.0.s08+dfsg/docs/DEVELOPER_GUIDELINES0000640000175000017500000000470111356151665020213 0ustar winniewinnie# # WiFi Radar # # DEVELOPER_GUIDELINES 2009-03-30 # Try to mimick the style of the code that you are working in. Include a usage statement with every function/subroutine, no matter how simple and self-explanatory that function is. Example: # Combine essid and bssid to make a config file section name # #Parameters: # # 'essid' -- string - AP ESSID # # 'bssid' -- string - AP BSSID # #Returns: # # string -- the bssid concatenated to a colon, concatenated to the essid def make_section_name( essid, bssid ): return essid + ':' + bssid Always give people credit in the CREDITS file. Have fun! -------------------------------------------------------------------------------- GIT -------------------------------------------------------------------------------- The current development branch is "v2.0.x". It is intended for small feature additions and bug fixes. Unless you're just fixing a bug in the stable release, or updating the stable documentation, this is what you want. Primary repo: git://git.berlios.de/wifi-radar Repo mirror: git://repo.or.cz/wifi-radar.git -------------------------------------------------------------------------------- Submitting Patches -------------------------------------------------------------------------------- Please submit patches through the Patch Manager at http://developer.berlios.de/patch/?group_id=10714 to help me keep track of incoming patches. If you would prefer to email it, then I will try to submit it to the Patch Manager for you. -------------------------------------------------------------------------------- Version Numbering -------------------------------------------------------------------------------- WiFI Radar uses a three stage version numbering (X.Y.Z): * X = major architectural change * Y = feature release no special meaning is given to an odd or even number in feature releases * Z = sub-revision: [abs]nn o [abs] = alpha, beta, or stable o nn : 2-digit serial number o ann : no stability guarantees between releases o bnn : new features are possible, but less wild than alpha o snn : bug fixes only, no non-bug-related development will occur in this line e.g. 2.0.b01 is the first beta release for 2.0; 2.0.s05 is the fifth stable release for 2.0; 2.3.s10 is the tenth stable release for 2.3 Development releases (nightly repository dumps) may be made available unofficially. wifi-radar-2.0.s08+dfsg/docs/BUGS0000640000175000017500000000532411356151665015720 0ustar winniewinnieHow To Report A Bug =================== If you think you've discovered a bug, please read through these guidelines before reporting it. First, make sure it's a new bug: * Please check the list of known bugs at the WiFi Radar Bug Tracker on berliOS to see if it has already been reported. * Are you using the very latest version of WiFi Radar? The bug may have already been fixed. Please get the latest version of WiFi Radar from the web site and check again. Even if your bug has not been fixed, others probably have, and you're better off with the most up-to-date code. If you don't have time to check the latest version, please report the bug anyway. I'd rather tell you that it's already fixed than miss reports of unfixed bugs. * If WiFi Radar does not behave the way you expect, look in the documentation (don't forget the FAQ) and, especially, the mailing list archives for evidence that it should behave the way you expect. If you're not sure, please ask on the WiFi Radar mailing list first. If it's a new bug, the most important thing you can do is to write a simple description and a recipe that reproduces the bug. The easier you make it to understand and track down the bug, the more likely a fix will be. Now you're ready to write the bug report. Please include: * A clear description of the bug. Describe how you expected WiFi Radar to behave, and contrast that with how it actually behaved. While the bug may seem obvious to you, it may not be so obvious to someone else, so it's best to avoid a guessing game. * A complete description of the environment in which you reproduced the bug: - Your operating system & version. - The version of Python ("python -V"). - The version of WiFi Radar (use the "-v" option). - Decrease the logging threshold to 0 and send the resulting wifi-radar.log file. - Any private modifications you made to WiFi Radar. - Anything else that could possibly be relevant. Err on the side of too much information, rather than too little. * A literal transcript of the *exact* command you ran, and the *exact* output. * If you also want to include speculation as to the cause, and even a patch to fix the bug, that would be great! The best place to send your bug report is to the WiFi Radar Bug Tracker on berliOS. That way, it won't be misplaced or forgotten. In fact, an open bug report on berliOS is a constant irritant that begs to be squashed. -- This document was blatantly stolen from Docutils 0.5. The original version was written by David Goodger and placed in the public domain. This version, edited by Sean Robinson, is licensed under the Creative Commons Attribution License. Please attribute both authors if you re-use it. wifi-radar-2.0.s08+dfsg/docs/VERSION0000640000175000017500000000001011356151665016270 0ustar winniewinnie2.0.s08 wifi-radar-2.0.s08+dfsg/docs/developer/0000750000175000017500000000000011356151665017215 5ustar winniewinniewifi-radar-2.0.s08+dfsg/docs/developer/wifi-radar.py/0000750000175000017500000000000011356151665021671 5ustar winniewinniewifi-radar-2.0.s08+dfsg/docs/developer/wifi-radar.py/file_browse_button.html0000640000175000017500000000762211356151665026462 0ustar winniewinnie HappyDoc Generated Documentation
HappyDoc Generated Documentation Class: file_browse_button

wifi-radar.py / file_browse_button 

Button to allow user to choose a file and put value into specified gtk.Entry

Methods   
  browse_files 
browse_files ( self,  widget )

Show filechooser dialog and get user selection

Parameters:

widget
gtk.Widget -- The widget sending the event.

Returns:

nothing

NOTES:

updates entry value

  __init__ 
__init__ (
        self,
        parent,
        entry,
        )

Create a button to simulate a File/Open

Parameters:

parent
gtk.Object -- Usually, the calling window.
entry
gtk.Entry -- The text entry to update with user selection.

Returns:

file_browse_button instance


This document was automatically generated Thu May 21 05:32:36 2009 by HappyDoc version 3.1 wifi-radar-2.0.s08+dfsg/docs/developer/wifi-radar.py/preferences_dialog.html0000640000175000017500000002040211356151665026376 0ustar winniewinnie HappyDoc Generated Documentation
HappyDoc Generated Documentation Class: preferences_dialog

wifi-radar.py / preferences_dialog 

The preferences dialog. Edits non-profile sections of the config file.

Methods   
  toggle_auto_detect 
toggle_auto_detect (
        self,
        auto_detect_toggle,
        data=None,
        )

Respond to Auto-detect checkbox toggle by activating/de-activating the interface combobox.

Parameters:

auto_detect_toggle
gtk.CheckButton - The checkbox sending the signal.
data
tuple - list of arbitrary arguments (not used)

Returns:

nothing

  run 
run ( self )

Display preferences dialog and operate until canceled or okayed.

Parameters:

nothing

Returns:

integer
gtk response ID
  toggle_speak 
toggle_speak (
        self,
        speak_toggle,
        data=None,
        )

Respond to Speak-up checkbox toggle by activating/de-activating the Speak Cmd Entry.

Parameters:

speak_toggle
gtk.CheckButton - The checkbox sending the signal.
data
tuple - list of arbitrary arguments (not used)

Returns:

nothing

  destroy 
destroy ( self )

Remove preferences window.

Parameters:

nothing

Returns:

nothing

  save 
save ( self )

Write updated values to config file.

Parameters:

nothing

Returns:

nothing

Exceptions   

IOError( error_number, error_str )

  __init__ 
__init__ (
        self,
        parent,
        confFile,
        )

Create a new preferences_dialog.

Parameters:

parent
gtk.Object - Usually, the calling window.
confFile
ConfigFile - The config file in which to store/read settings.

Returns:

preferences_dialog instance


This document was automatically generated Thu May 21 05:32:36 2009 by HappyDoc version 3.1 wifi-radar-2.0.s08+dfsg/docs/developer/wifi-radar.py/profile_dialog.html0000640000175000017500000002521011356151665025537 0ustar winniewinnie HappyDoc Generated Documentation
HappyDoc Generated Documentation Class: profile_dialog

wifi-radar.py / profile_dialog 

Edit and return an AP profile.

Methods   
  get_array_index 
get_array_index (
        self,
        item,
        array,
        )

Return the index where item matches a cell in array.

Parameters:

item
string - Item to find in array
array
list - List in which to find match.

Returns:

integer - 0 (no match) or higher (index of match)

  toggle_roaming 
toggle_roaming (
        self,
        roaming_toggle,
        data=None,
        )

Respond to roaming checkbox toggle by activating/de-activating the BSSID text entry.

Parameters:

roaming_toggle
gtk.CheckButton - The checkbox sending the signal.
data
tuple - list of arbitrary arguments (not used)

Returns:

nothing

  run 
run ( self )

Display profile dialog, operate until canceled or okayed, and, possibly, return edited profile values.

Parameters:

nothing

Returns:

dictionary or None
a profile, or None on cancel

NOTES:

Raises ValueError if an attempt is made to save an ESSID with no name.

Exceptions   

ValueError

  toggle_use_dhcp 
toggle_use_dhcp (
        self,
        widget,
        data=None,
        )

Respond to expanding/hiding IP segment.

Parameters:

widget
gtk.Widget - The widget sending the event.
data
tuple - List of arbitrary arguments (not used)

Returns:

nothing

  toggle_use_wpa 
toggle_use_wpa (
        self,
        widget,
        data=None,
        )

Respond to expanding/hiding WPA segment.

Parameters:

widget
gtk.Widget - The widget sending the event.
data
tuple - List of arbitrary arguments (not used)

Returns:

nothing

  destroy 
destroy ( self )

Remove profile dialog.

Parameters:

nothing

Returns:

nothing

  __init__ 
__init__ (
        self,
        parent,
        profile,
        )

Create a new profile_dialog.

Parameters:

parent
gtk.Object - Usually, the calling window.
profile
dictionary - The profile to edit. May be mostly-empty default profile.

Returns:

profile_dialog instance

  get_array_item 
get_array_item (
        self,
        index,
        array,
        )

Return the value in array[ index ]

Parameters:

index
integer - The index to look up.
array
list - List in which to look up value.

Returns:

string
empty string (no match) or looked up value

This document was automatically generated Thu May 21 05:32:36 2009 by HappyDoc version 3.1 wifi-radar-2.0.s08+dfsg/docs/developer/wifi-radar.py/ErrorDialog.html0000640000175000017500000000556411356151665025003 0ustar winniewinnie HappyDoc Generated Documentation
HappyDoc Generated Documentation Class: ErrorDialog

wifi-radar.py / ErrorDialog 

Simple dialog to report an error to the user.

Methods   
  __init__ 
__init__ (
        self,
        parent,
        message,
        )

Create a new ErrorDialog.

Parameters:

parent
gtk.Object - Usually, the calling window.
message
string - The message to display to the user.

Returns:

ErrorDialog instance


This document was automatically generated Thu May 21 05:32:36 2009 by HappyDoc version 3.1 wifi-radar-2.0.s08+dfsg/docs/developer/wifi-radar.py/ConfigFile.html0000640000175000017500000004412311356151665024571 0ustar winniewinnie HappyDoc Generated Documentation
HappyDoc Generated Documentation Class: ConfigFile

wifi-radar.py / ConfigFile 

Manage the configuration for the application, including reading and writing the config from/to a file.

Methods   
  set_opt 
set_opt (
        self,
        option_path,
        value,
        )

Set a config option while handling exceptions.

Parameters:

option_path
string - Section (a.k.a. profile) name concatenated with a period and the option key. (E.g. "DEFAULT.interface")
value
string - Value to set.

Returns:

nothing

  get_opt 
get_opt ( self,  option_path )

Get a config option and handle exceptions.

Parameters:

option_path
string - Section (a.k.a. profile) name concatenated with a period and the option key. (E.g. "DEFAULT.interface")

Returns:

string or None - option value as string or None on failure

  set_section 
set_section (
        self,
        section_name,
        section_dict,
        )

Set the contents of a section to values from a dictionary.

Parameters:

section_name
string - Configuration file section.
section_dict
dictionary - Values to add to section.

Returns:

nothing

  set_float_opt 
set_float_opt (
        self,
        option_path,
        value,
        )

Convert float type to string and set config option.

Parameters:

option_path
string - Section (a.k.a. profile) name concatenated with a period and the option key. (E.g. "DEFAULT.interface")
value
float - Value to set.

Returns:

nothing

Exceptions   

ValueError, 'value is not a float'

  set_int_opt 
set_int_opt (
        self,
        option_path,
        value,
        )

Convert integer type to string and set config option.

Parameters:

option_path
string - Section (a.k.a. profile) name concatenated with a period and the option key. (E.g. "DEFAULT.interface")
value
integer - Value to set.

Returns:

nothing

Exceptions   

ValueError, 'value is not an integer'

  profiles 
profiles ( self )

Return a list of the section names which denote AP profiles.

Parameters:

nothing

Returns:

list - profile names

  write 
write ( self )

Write configuration file to disk from instance variables. Copied from ConfigParser and modified to write options in alphabetical order.

Parameters:

nothing

Returns:

nothing

  set_bool_opt 
set_bool_opt (
        self,
        option_path,
        value,
        )

Convert boolean type to string and set config option.

Parameters:

option_path
string - Section (a.k.a. profile) name concatenated with a period and the option key. (E.g. "DEFAULT.interface")
value
boolean - Value to set.

Returns:

nothing

Exceptions   

ValueError, 'cannot convert value to string'

  read 
read ( self )

Read configuration file from disk into instance variables.

Parameters:

nothing

Returns:

nothing

  get_opt_as_bool 
get_opt_as_bool ( self,  option_path )

Get a config option and return as a boolean type.

Parameters:

option_path
string - Section (a.k.a. profile) name concatenated with a period and the option key. (E.g. "DEFAULT.interface")

Returns:

boolean - option value as boolean

Exceptions   

ValueError, 'boolean option was not True or False'

  get_opt_as_int 
get_opt_as_int ( self,  option_path )

Get a config option and return as an integer type.

Parameters:

option_path
string - Section (a.k.a. profile) name concatenated with a period and the option key. (E.g. "DEFAULT.interface")

Returns:

integer- option value as integer

  __init__ 
__init__ (
        self,
        filename,
        defaults,
        raw=None,
        )

Create a new ConfigFile.

Parameters:

filename
string - The configuration file's name.
defaults
dictionary - Default values for the DEFAULT section.

Returns:

ConfigFile instance

  get_profile 
get_profile ( self,  section_name )

Return the profile recorded in the specified section.

Parameters:

section_name
string - Configuration file section.

Returns:

dictionary or None - The specified profile or None if not found


This document was automatically generated Thu May 21 05:32:36 2009 by HappyDoc version 3.1 wifi-radar-2.0.s08+dfsg/docs/developer/wifi-radar.py/radar_window.html0000640000175000017500000006674611356151665025263 0ustar winniewinnie HappyDoc Generated Documentation
HappyDoc Generated Documentation Class: radar_window

wifi-radar.py / radar_window 

The main user interface window for WiFi Radar. This class also is the control center for most of the rest of the operations.

Methods   
  update_network_info 
update_network_info ( self )

Update the current ip and essid shown to user.

Parameters:

nothing

Returns:

nothing

  on_network_selection 
on_network_selection (
        self,
        widget,
        data=None,
        )

Enable/disable buttons based on the selected network.

Parameters:

widget
gtk.Widget - The widget sending the event.
data
tuple - list of arbitrary arguments (not used)

Returns:

nothing

  __init__ 
__init__ (
        self,
        confFile,
        apQueue,
        commQueue,
        logger,
        exit_event,
        )

Create a new radar_window.

Parameters:

confFile
ConfigFile - The config file in which to store/read settings.
apQueue
Queue - The Queue from which AP profiles are read.
commQueue
Queue - The Queue to which to send commands to the scanning thread.
logger
Logger - Python's logging facility

Returns:

radar_window instance

  disconnect_profile 
disconnect_profile (
        self,
        widget,
        data=None,
        )

Respond to a request to disconnect by calling ConnectionManager disconnect_interface().

Parameters:

widget
gtk.Widget - The widget sending the event.
data
tuple - list of arbitrary arguments (not used)

Returns:

nothing

  edit_preferences 
edit_preferences (
        self,
        widget,
        data=None,
        )

Init and run the preferences dialog

Parameters:

widget
gtk.Widget - The widget sending the event.
data
tuple - list of arbitrary arguments (not used)

Returns:

nothing

  destroy 
destroy ( self,  widget=None )

Quit application.

Parameters:

widget
gtk.Widget - The widget sending the event.

Returns:

nothing

  create_new_profile 
create_new_profile (
        self,
        widget,
        profile,
        data=None,
        )

Respond to a request to create a new AP profile

Parameters:

widget
gtk.Widget - The widget sending the event.
profile
dictionary - The AP profile to use as basis for new profile.
data
tuple - list of arbitrary arguments (not used)

Returns:

boolean
True if a profile was created and False if profile creation was canceled.
Exceptions   

IOError( error_number, error_str )

  pixbuf_from_known 
pixbuf_from_known ( self,  known )

Return the proper icon for a value of known.

Parameters:

known
boolean - Whether the AP is known (i.e. configured)

Returns:

gtk.gdk.Pixbuf
icon for a known or unknown AP
  update_auto_profile_order 
update_auto_profile_order (
        self,
        widget=None,
        data=None,
        data2=None,
        )

Update the config file auto profile order from the on-screen order

Parameters:

widget
gtk.Widget - The widget sending the event.
data
tuple - list of arbitrary arguments (not used)
data2
tuple - list of arbitrary arguments (not used)

Returns:

nothing

Exceptions   

IOError( error_number, error_str )

  delete_profile_with_check 
delete_profile_with_check (
        self,
        widget,
        data=None,
        )

Respond to a request to delete an AP profile (i.e. make profile unknown) Check with user first.

Parameters:

widget
gtk.Widget - The widget sending the event.
data
tuple - list of arbitrary arguments (not used)

Returns:

nothing

  connect_profile 
connect_profile (
        self,
        widget,
        profile,
        data=None,
        )

Respond to a request to connect to an AP.

Parameters:

widget
gtk.Widget - The widget sending the event.
profile
dictionary - The AP profile to which to connect.
data
tuple - list of arbitrary arguments (not used)

Returns:

nothing

  update_ap_list 
update_ap_list ( self,  ap )

Updates the record-keeping profiles list.

Parameters:

ap
dictionary -- The AP found by scanning_thread.

Returns:

nothing

  pixbuf_from_signal 
pixbuf_from_signal ( self,  signal )

Return an icon indicating the signal level.

Parameters:

signal
integer - signal level reported by iwlist (may be arbitrary scale in 0-100 or -X dBm)

Returns:

gtk.gdk.Pixbuf
1 of 5 icons indicating signal level
  delete_event 
delete_event (
        self,
        widget,
        data=None,
        )

Kill scanning thread, update profile order for config file, and ask to be destroyed.

Parameters:

widget
gtk.Widget - The widget sending the event.
data
tuple - list of arbitrary arguments (not used)

Returns:

boolean
always return False (i.e. do not propigate the signal which called)
  edit_profile 
edit_profile (
        self,
        widget,
        data=None,
        )

Respond to a request to edit an AP profile. Edit selected AP profile if it is known. Otherwise, create a new profile with the selected ESSID and BSSID.

Parameters:

widget
gtk.Widget - The widget sending the event.
data
tuple - list of arbitrary arguments (not used)

Returns:

nothing

Exceptions   

IOError( error_number, error_str )

  delete_profile 
delete_profile (
        self,
        selected_iter,
        apname,
        )

Delete an AP profile (i.e. make profile unknown)

Parameters:

selected_iter
gtk.TreeIter - The selected row.
apname
string - The configuration file section to remove

Returns:

gtk.TreeIter
the iter for the row removed from the gtk.ListStore
Exceptions   

IOError( error_number, error_str )

  main 
main ( self )

Begin running radar_window in Gtk event loop.

Parameters:

nothing

Returns:

nothing

  show_about_info 
show_about_info (
        self,
        widget,
        data=None,
        )

Init and run the about dialog

Parameters:

widget
gtk.Widget - The widget sending the event.
data
tuple - list of arbitrary arguments (not used)

Returns:

nothing

  get_row_by_ap 
get_row_by_ap (
        self,
        essid,
        bssid,
        )

Return row which holds specified ESSID and BSSID.

Parameters:

essid
string - ESSID to match
bssid
string - BSSID to match

Returns:

gtk.TreeIter or None
pointer to the row containing the match or None for no match found
  update_connect_buttons 
update_connect_buttons ( self )

Set the state of connect/disconnect buttons based on whether we have a connection.

Parameters:

nothing

Returns:

nothing

  update_plist_items 
update_plist_items ( self,  ap )

Updates the on-screen profiles list.

Parameters:

ap
dictionary -- The AP found by scanning_thread.

Returns:

nothing

  update_window 
update_window ( self )

Updates the main user interface.

Parameters:

nothing

Returns:

boolean
always return True

This document was automatically generated Thu May 21 05:32:36 2009 by HappyDoc version 3.1 wifi-radar-2.0.s08+dfsg/docs/developer/wifi-radar.py/ConnectionManager.html0000640000175000017500000002442211356151665026156 0ustar winniewinnie HappyDoc Generated Documentation
HappyDoc Generated Documentation Class: ConnectionManager

wifi-radar.py / ConnectionManager 

Manage a connection; including reporting connection state, connecting/disconnecting from an AP, and returning current IP, ESSID, and BSSID.

Methods   
  if_change 
if_change ( self,  state )

Change the interface state: up or down.

Parameters:

state
string - The state to which to change the interface.

Returns:

nothing

  get_current_bssid 
get_current_bssid ( self )

Returns the current BSSID, if any, by calling iwconfig.

Parameters:

nothing

Returns:

string or None
the BSSID or None (if no there is no current association)
  connect_to_network 
connect_to_network (
        self,
        profile,
        status,
        )

Connect to the specified AP.

Parameters:

profile
dictionary - The profile for the AP (i.e. network) with which to connect.
status
status implementer - Object which implements status interface.

Returns:

nothing

Exceptions   

TypeError( "Empty AP address" )

  __init__ 
__init__ (
        self,
        confFile,
        commandQueue,
        logger,
        )

Create a new connection manager which can read a config file and send to scanning thread command Queue. A new manager checks for a pre-existing connection and takes its AP profile from the ESSID and BSSID to which it is currently attached.

Parameters:

confFile
ConfigFile - Config file object
commandQueue
Queue - The Queue on which to put commands to the scanning thread
logger
Logger - Python's logging facility

Returns:

ConnectionManager instance

  get_current_essid 
get_current_essid ( self )

Returns the current ESSID, if any, by calling iwconfig.

Parameters:

nothing

Returns:

string or None
the ESSID or None (if no there is no current association)
  get_current_ip 
get_current_ip ( self )

Returns the current IP, if any, by calling ifconfig.

Parameters:

nothing

Returns:

string or None
the IP address or None (if no there is no current connection)
  disconnect_interface 
disconnect_interface ( self )

Disconnect from the AP with which a connection has been established/attempted.

Parameters:

nothing

Returns:

nothing

Exceptions   

KeyError


This document was automatically generated Thu May 21 05:32:36 2009 by HappyDoc version 3.1 wifi-radar-2.0.s08+dfsg/docs/developer/wifi-radar.py/StatusWindow.html0000640000175000017500000001761611356151665025246 0ustar winniewinnie HappyDoc Generated Documentation
HappyDoc Generated Documentation Class: StatusWindow

wifi-radar.py / StatusWindow 

A simple class for putting up a "Please wait" dialog so the user doesn't think we've forgotten about them. Implements the status interface.

Methods   
  hide 
hide ( self )

Hide all the widgets of the StatusWindow.

Parameters:

nothing

Returns:

nothing

  update_message 
update_message ( self,  message )

Change the message displayed to the user.

Parameters:

message
string - The message to show to the user.

Returns:

nothing

  show 
show ( self )

Show all the widgets of the StatusWindow.

Parameters:

nothing

Returns:

nothing

  destroy 
destroy ( self )

Remove the StatusWindow.

Parameters:

nothing

Returns:

nothing

  run 
run ( self )

Display and operate the StatusWindow.

Parameters:

nothing

Returns:

nothing

  __init__ 
__init__ ( self,  parent )

Create a new StatusWindow.

Parameters:

parent
gtk.Object - Usually, the calling window.

Returns:

StatusWindow instance

NOTE:

Sample implementation of status interface. Status interface requires .show(), .update_message(message), and .hide() methods.

  update_window 
update_window ( self )

Update the StatusWindow progress bar.

Parameters:

nothing

Returns:

True
always return True

This document was automatically generated Thu May 21 05:32:36 2009 by HappyDoc version 3.1 wifi-radar-2.0.s08+dfsg/docs/developer/wifi-radar.py/about_dialog.html0000640000175000017500000000517211356151665025216 0ustar winniewinnie HappyDoc Generated Documentation
HappyDoc Generated Documentation Class: about_dialog

wifi-radar.py / about_dialog 

Manage a GTK About Dialog

Methods   
  __init__ 
__init__ ( self )

Subclass GTK AboutDialog

Parameters:

nothing

Returns:

nothing


This document was automatically generated Thu May 21 05:32:36 2009 by HappyDoc version 3.1 wifi-radar-2.0.s08+dfsg/docs/developer/wifi-radar.html0000640000175000017500000002730311356151665022136 0ustar winniewinnie HappyDoc Generated Documentation
HappyDoc Generated Documentation wifi-radar.py
Functions   
  scanning_thread 
scanning_thread (
        confFile,
        apQueue,
        commandQueue,
        logger,
        exit_event,
        )

Scan for a limited time and return AP names and bssid found. Access points we find will be put on the outgoing Queue, apQueue.

Parameters:

confFile
ConfigFile - Config file object
apQueue
Queue - Queue on which to put AP profiles
commandQueue
Queue - Queue from which to read commands
logger
Logger - Python's logging facility

Returns:

nothing

  split_section_name 
split_section_name ( section )

Split a config file section name into an essid and a bssid

Parameters:

section
string - Config file section name

Returns:

list
the essid and bssid
  get_new_profile 
get_new_profile ()

Return a blank profile

Parameters:

none

Returns:

dictionary
An AP profile with defaults set.
  say 
say ( words )

Speak feedback message to user

Parameters:

words
string - Message to speak to user

Returns:

nothing

  get_network_device 
get_network_device ( device )

Gets the network interface device

Parameters:

device
string - The proposed network device to use

Returns:

string
The actual network device to use
  shellcmd 
shellcmd ( command,  environment=None )

Run commands through the shell

Parameters:

command
tuple - The command and arguments to run.
environment
dictionary - Environment variables (as keys) and their values.

Returns:

boolean
True on success, otherwise, False
  make_section_name 
make_section_name ( essid,  bssid )

Combine essid and bssid to make a config file section name

Parameters:

essid
string - AP ESSID
bssid
string - AP BSSID

Returns:

string
the bssid concatenated to a colon, concatenated to the essid
Classes   

StatusWindow

A simple class for putting up a "Please wait" dialog so the user

file_browse_button

Button to allow user to choose a file and put value into specified gtk.Entry

preferences_dialog

The preferences dialog. Edits non-profile sections of the config file.

ConnectionManager

Manage a connection; including reporting connection state,

ConfigFile

Manage the configuration for the application, including reading and writing the config from/to a file.

profile_dialog

Edit and return an AP profile.

about_dialog

Manage a GTK About Dialog

ErrorDialog

Simple dialog to report an error to the user.

radar_window

The main user interface window for WiFi Radar. This class also is the control


This document was automatically generated Thu May 21 05:32:36 2009 by HappyDoc version 3.1 wifi-radar-2.0.s08+dfsg/docs/TODO0000640000175000017500000000113511356151665015721 0ustar winniewinnieTODO * Add a "No IP Config" button. As in, only configure my wifi settings, let my OS configure my IP settings. * True integration of WPA TKIP (wpa_supplicant)? (PARTIALLY done in 0.3.8-6mdk) * Add more ifconfig and iwconfig status info. * Translate. * Hover over help to say drag and drop profiles to set ordered preference. * Add a check box to automatically close the GUI on successful IP acquisition. Wait X seconds before closing. * dbus extension for wifi-radar to make normal users able to start it without having root or sudo. Suggested by Patrick Winnertz. * Age out old networks wifi-radar-2.0.s08+dfsg/docs/INSTALL0000640000175000017500000000001411356151665016255 0ustar winniewinnieSee README. wifi-radar-2.0.s08+dfsg/docs/README.WPA-Mini-HOWTO.txt0000640000175000017500000001347511356151665021157 0ustar winniewinnie# # $Id$ # # WPA Mini-HOWTO # Initial text by Gary Case # 2006.09.26 Brian Elliott Finley # - misc updates # # Here are my directions for installing wpa_supplicant, wifi-radar and all necessary support packages on RHEL4 U2 to enable WPA/WPA2 encrypted wireless ethernet access. 1. Wireless-tools package: I didn't need to update this as the version we ship (v27) was sufficient for use with the latest drivers. 2. Wireless-extensions: I didn't update this. The kernel is using v16 according to iwconfig --version, which is sufficiently new to support everything we need here. 3. Updated wireless card driver, firmware and kernel module precompiled RPMs retrieved from here: http://atrpms.net/dist/el4/ipw2200-testing/ Newer driver: ipw2200-1.0.10-36.el4.at Newer firmware: ipw2200-firmware-2.4-7.at Newer kernel module: ipw2200-kmdl-2.6.9-22.0.2.EL-1.0.10-36.el4.at Be sure to get the packages from the "testing" branch, as the regular ones are the same as the one we ship with RHEL 4 (1.0.0). You need the newer driver and associated files to make WPA work. The web page link I posted will take you to the testing packages. 4. WPA Supplicant, found here: http://hostap.epitest.fi/wpa_supplicant/ 4a. I tried using the precompiled wpa_supplicant RPM packages from the atrpms site, but they were built with all options enabled and needed additional packages to solve dependencies. I decided to build the latest stable version myself (version 0.4.8) instead of playing "find the RPM" to solve the dependencies present in the precompiled package. My home setup is very simple, so all I needed in my .config file were these three lines: CONFIG_IEEE8021X_EAPOL=Y CONFIG_EAP_PSK=y CONFIG_DRIVER_IPW=y If your customer is using PEAP or LEAP or some other external authentication protocol their .config file may vary. All the available options are listed in the README file included in the wpa_supplicant tarball. 4b. After building I copied the wpa_cli and wpa_supplicant binaries to /usr/local/bin (the location suggested in the README. Feel free to relocate if desired.). Then I copied the included wpa_supplicant.conf file to /etc/wpa_supplicant/wpa_supplicant.conf. There's a great deal of information and several example configurations in the supplied .conf file. The customer can use the examples to select the proper options for their config file if their network doesn't match my simple WPA2-PSK setup: #Gary's WPA2 home network network={ ssid="my-secret-ssid" scan_ssid=0 proto=WPA2 key_mgmt=WPA-PSK pairwise=CCMP group=CCMP psk="my-secret-pre-shared-key" priority=2 Be sure to change the SSID and PSK to the real values for your network. All the other options in the file were left at their default state. 5. WPA Supplicant testing With the configuration set up as described, I could issue this command to bring up the interface: wpa_supplicant -Bw -ieth1 -c/etc/wpa_supplicant/wpa_supplicant.conf (The -Bw option runs the daemon in the background and waits for the interface to be added, if necessary. Have the customer change -ieth1 to match their wireless interface.) This command was then used to get a DHCP address on the card. dhclient eth1 I wrote an extremely simple script to do the two commands for me: #!/bin/bash # Script to start WPA Supplicant for secure wireless communication wpa_supplicant -Bw -ieth1 -c/etc/wpa_supplicant/wpa_supplicant.conf sleep 8 dhclient eth1 If the network connection isn't coming up, check /var/log/messages for errors and try dropping the -B option on wpa_supplicant to have the program output information to stdout. 6. Wifi-radar Although it's not needed for wireless or WPA to work, the wifi-radar package can provide users with an alternative method for choosing and connecting to a secure wireless access point. It has no options in the GUI for WPA/WPA2, but it's capable of using a properly configured wpa_supplicant installation to handle the more secure levels of encryption. 6a. After completing steps one through 5 above (step 5 is there to make sure the supplicant is working properly), download and install wifi-radar from the CVS site (directions are present on the CVS site): http://svn.systemimager.org/ 6b. Edit the configuration file to match your installation. An example setup that works with my home network is shown below. The DEFAULT section is already populated by the installer, but make sure that the interface matches your wireless interface. As in all the other examples, change "my-secret-ssid" to match the SSID in use at your site: [DEFAULT] ifup_required = False auto_profile_order = my-secret-ssid speak_up = False scan_timeout = 5 interface = eth1 commit_required = False [my-secret-ssid] use_dhcp = yes wpa_driver = ipw use_wpa = yes mode = Auto 6c. Edit the /usr/sbin/wifi-radar script to use dhclient instead of dhcpcd: The % DHCP_TIMEOUT section from the DHCP_COMMAND line needed commenting out to make the wifi-radar script work. I suspect there's no timeout value for dhclient or it's implemented differently from dhcpcd. 6d. Continue editing the /usr/sbin/wifi-radar script to use wpa_supplicant. You'll need to change the command, conf, and driver lines to match the locations of your command and configuration files as well as the wpa driver you're using in wpa_supplicant. # WPA_SUPPLICANT WPA_SUPPLICANT_COMMAND = "/usr/local/bin/wpa_supplicant" WPA_SUPPLICANT_KILL_COMMAND="" WPA_SUPPLICANT_CONF="/etc/wpa_supplicant/wpa_supplicant.conf" WPA_DRIVER="ipw" WPA_SUPPLICANT_PIDFILE = "/var/run/wpa_supplicant.pid" WPA_SUPPLICANT_ARGS = "-B -i " + INTERFACE + " -c " + WPA_SUPPLICANT_CONF + " -D " + WPA_DRIVER + " -p " + WPA_SUPPLICANT_PIDFILE 7. Run wifi-radar After making those script changes, I could run wifi-radar, select the proper SSID and click the "Connect" button to get a DHCP address. wifi-radar-2.0.s08+dfsg/docs/CREDITS0000640000175000017500000000303011356151665016245 0ustar winniewinnieCREDITS N: Ahmad Baitalmal E: ahmad@bitbuilder.com D: creator N: Douglas Breault E: genkreton@comcast.net D: contributing author N: Nicolas Brouard E: nicolas.brouard@libertysurf.fr D: contributing author N: Gary Case E: gcase@redhat.com D: WPA Mini HOWTO N: Jon Collette E: jonc@etelos.com D: contributing author N: David Decotigny E: com.d2@free.fr D: [FIX] wifi-radar and iwlist interferences N: Brian Elliott Finley E: brian@thefinleys.com D: contributing author D: previous maintainer N: Simon Gerber E: gesimu@gmail.com D: ip_re = re.compile() Internationally compatible patch N: Joey Hurst E: jhurst@lucubrate.org D: contributing author N: Ante Karamatic E: ivoks@ubuntu.com D: Packaging N: Richard Monk E: rmonk@redhat.com D: contributing author N: Kevin Otte E: kotte@redhat.com D: contributing author N: Nathanael Rebsch E: nathanael@dihedral.de D: dhcpcd -> dhclient patch D: wpa patch N: Sean Robinson E: seankrobinson@gmail.com P: 2048g/30154530 8108 67A4 0D3E B3C1 0C77 81A0 6531 A000 118A 449B D: contributing author D: maintainer N: Andrea Scarpino E: andrea@archlinux.org D: Makefile patches N: Prokhor Shuchalov E: p@shuchalov.ru D: contributing author N: Patrick Winnertz E: D: wpa patches D: man page patches D: makefile patches D: debian package maintainer "The fields are: name (N), email (E), web-address (W), PGP key ID and fingerprint (P), description (D), and snail-mail address (S).... (and this file really _is_ supposed to be in alphabetic order)" -- Linus Torvalds in Linux CREDITS file wifi-radar-2.0.s08+dfsg/docs/HISTORY0000640000175000017500000000660311356151665016322 0ustar winniewinnie History of WiFi Radar (or a simplified ChangeLog) 2010-04-04 Version 2.0.s08 released. Fixes crash involving log file, if started by a non-root user. 2010-01-29 Version 2.0.s07 released. Includes bug fixes for non-DHCP use from Prokhor Shuchalov. 2009-08-28 Version 2.0.s06 released. Adds WIFIRADAR_PROFILE, WIFIRADAR_ENCMODE, WIFIRADAR_SECMODE environment variables for connect and disconnect scripts. Explains old configuration file read crashes to user and recommends a resolution. 2009-07-19 Version 2.0.s05 released. Fixes WPA associations and disconnects. Also fixes various bugs in the UI, including bugs 15973 and 15972. 2009-07-06 Version 2.0.s04 released. Fixes a critical bug introduced in 2.0.s03. 2009-07-06 Version 2.0.s03 released. Fixes bugs 15963 (unsafe ConfigFile write) and 15964 (wifi-radar --help). Adds and corrects documentation. 2009-06-02 Version 2.0.s02 released. Fixes bugs 15785 (patch from Andrea Scarpino) and 15787. 2009-05-21 Version 2.0.s01 released. This was the first stable release of version 2.0. 2009-04-19 Version 2.0.b05 released. This version added roaming support for mutliple-AP networks. 2009-04-02 Version 2.0.b04 released. This version added logging output at the suggestion of Roy Wood. 2009-03-20 Version 2.0.b01 released by new maintainer, Sean Robinson. This release incorporated pre and post scripts with some program information available through environment variables. It also added a channel column and displayed the AP address. This version had a new configuration file format and made more preferences editable within the program. It added a simplified threading model, more modular source code, and extended comments. It increased the WEP key length from 32 to 64 bytes. Also added was an About dialog with license and credit information. 2008-03-12 Version 1.9.9 released. This release cleaned up installation and some documentation using patches from Patrick Winnertz. 2007-02-08 Version 1.9.8 released. This version added new features based on user suggestions. Fixed bugs with locking in multi-threaded environment and killing DHCP client. 2006-09-27 Version 1.9.7 released. This version contained multiple interface fixes based on user suggestions. Also the debian directory was added for building .deb packages. Gary Case's WPA Mini-HOWTO was included in this version. 2005-03-27 Version 1.9.6 released. 2005-03-19 Version 1.9.5 released by new maintainer, Brian Elliott Finley. This version made it possible to use any DHCP client and included various fixes. 2005-04-12 Version 1.9.3-3mdk released by Nicolas Brouard. This version offered the first partial WPA support. 2005-04-03 Version 1.9.3-2mdk released by Nicolas Brouard. This version killed dhclient when disconnecting. 2005-03-21 Version 1.9.1 released. This fixed scanning regex patterns for iwlist inconsistencies. 2005-03-20 Version 1.9 released. This added threaded scanning, signal bars, embedded icons, and changed the name from wifi_radar to wifi-radar, per convention. 2004-12-22 Initial import into SVN. 2004-08-04 Version 1.1 released. This version added a disconnect button. 2004-07-04 Initial release by Ahmad Baitalmal. Ahmad is the original author and maintainer of WiFi Radar. wifi-radar-2.0.s08+dfsg/docs/README0000640000175000017500000001360011356151665016111 0ustar winniewinnieWiFi Radar -------------------------------------------------------------------------------- WiFi Radar is a Python/PyGTK2 utility for managing WiFi profiles on GNU/Linux. Maintained by Sean Robinson Created by Ahmad Baitalmal Previously maintained by Brian Elliott Finley http://wifi-radar.berlios.de/ WiFi Radar is released under the GPL license. Quick Usage -------------------------------------------------------------------------------- To show the GUI and manage profiles: sudo wifi-radar Nifty Config Tip for Ubuntu and Debian Based Distributions -------------------------------------------------------------------------------- After initial configuration of your preferred wifi networks by runing the WiFi Radar GUI, you can automatically invoke wifi-radar as part of your systems standard ifup/ifdown proceedures. Find a stanza in /etc/network/interfaces for your wifi device (or create one), and modify it so that it looks like this example: auto eth1 iface eth1 inet static address 0.0.0.1 netmask 255.255.255.0 post-up wifi-radar When you or your system does an "ifup eth1", this stanza will set a temporary static IP address (that should not conflict with anything), then invoke WiFi Radar which will allow you to connect to a preferred wifi network and configure your interface accordingly, with an IP address appropriate for that network. I. Here are Some Important Bits: -------------------------------------------------------------------------------- * The config file defaults to /etc/wifi-radar/wifi-radar.conf. The location of this file can be changed at install time with: "make install sysconfdir=/usr/local/etc/wifi-radar" * The configuration file format changed between v1.9.9 and v2.0.s01. The two formats are not compatible with each other. If you are upgrading from v1.9.9, you will need to re-create your configuration. * If the config file does not exist, it will be created at run-time, so you must always invoke wifi-radar as root or with sudo. * You can change everything else from the config file which is simply a .ini-style file. If you have questions, check the WiFi Radar web site at http://wifi-radar.berlios.de/ for a FAQ, a mailing list, a user manual, and a web forum. Any of which may have your answer. II. Dependencies -------------------------------------------------------------------------------- * Python * PyGtk2 * Wireless Tools for Linux (iwconfig, iwlist) * SpeechD (optional) III. Install -------------------------------------------------------------------------------- 1. Type "sudo make install" (or "sudo make install sysconfdir=/usr/local/etc/wifi-radar") IV. HOWTO: Optional PAM Configuration -------------------------------------------------------------------------------- These instructions allow you to run wifi-radar as a normal user without using sudo. Thanks to Flipp Bunts for this HOWTO. HOWTO get wifi-radar custom launcher to use PAM authentication in Gnome: 1. get wifi-radar and untar 2. put wifi-radar.svg in /usr/share/pixmaps 3. put wifi-radar.py in /usr/local/bin 4. ln -s /usr/bin/consolehelper /usr/local/bin/wifi-radar 5. vi /etc/security/console.apps/wifi-radar USER=root PROGRAM=/usr/local/bin/wifi-radar.py SESSION=true 6. vi /etc/pam.d/wifi-radar #%PAM-1.0 auth sufficient pam_rootok.so auth sufficient pam_timestamp.so auth required pam_stack.so service=system-auth session required pam_permit.so session optional pam_xauth.so session optional pam_timestamp.so account required pam_permit.so 7. check the permissions # ls -lh /etc/security/console.apps/wifi-radar /etc/pam.d/wifi-radar -rw-r--r-- 1 root root /etc/pam.d/wifi-radar -rw-r--r-- 1 root root /etc/security/console.apps/wifi-radar 8. add launcher a. right click on panel b. select 'add to panel' c. click on 'custom application launcher' d. options for 'create launcher' name : wifi-radar command : /usr/local/bin/wifi-radar icon : /usr/share/pixmap/wifi-radar.svg 9. click on the icon, enter the root password, away you go V. HOWTO: Environment Variables Set For Connect and Disconnect Scripts -------------------------------------------------------------------------------- The following environment variables are set for the pre- and post- scipts for connect and disconnect operations (i.e. all four user scripts): 1. WIFIRADAR_IF is the network interface which is dis/connecting The following variables are set in the shell environment in which the post-connect and pre-disconnect scripts are executed. 1. WIFIRADAR_IP is the current IP address 2. WIFIRADAR_ESSID is the current ESSID 3. WIFIRADAR_BSSID is the current BSSID VI. HOWTO: Interpolated Strings in the Configuration File -------------------------------------------------------------------------------- It is possible to use configuration file options in the value of other options. An example: [DEFAULT] interface = wlan1 [DHCP] pidfile = /etc/dhcpc/dhcpcd-%(interface)s.pid means that WiFi Radar will use the file /etc/dhcpc/dhcpcd-wlan1.pid for the DHCP PID file. These interpolated strings can be safely entered into preferences dialog text areas. Have fun! wifi-radar-2.0.s08+dfsg/Makefile0000640000175000017500000000613711356151665015750 0ustar winniewinnie# # Makefile for WiFi Radar # SHELL = /bin/sh # # These settings are what I would expect for most modern Linux distros, # and are what work for me unmodified on Ubuntu. -BEF- # package = wifi-radar sbindir = $(DESTDIR)/sbin initdir = $(DESTDIR)/etc/init.d sysconfdir = $(DESTDIR)/etc/ mandir = $(DESTDIR)/share/man pixmapsdir = $(DESTDIR)/share/pixmaps appsdir = $(DESTDIR)/share/applications srcdir = . top_srcdir = . top_builddir = . VERSION = $(shell cat $(srcdir)/docs/VERSION) BRANCH = $(shell echo v$(shell cat $(srcdir)/docs/VERSION | cut -d. -f1-2).x) TOPDIR := $(CURDIR) .PHONY: all install tarball dev-docs changelog clean distclean all: wifi-radar.localized install: all test -d ${sysconfdir} || install -d -m 755 ${sysconfdir} test -d ${sbindir} || install -d -m 755 ${sbindir} install -m 755 wifi-radar.localized ${sbindir}/wifi-radar test -d ${mandir}/man1 || install -d -m 755 ${mandir}/man1 install -m 644 man/man1/wifi-radar.1 ${mandir}/man1 test -d ${mandir}/man5 || install -d -m 755 ${mandir}/man5 install -m 644 man/man5/wifi-radar.conf.5 ${mandir}/man5 test -d ${pixmapsdir} || install -d -m 755 ${pixmapsdir} install -m 644 pixmaps/wifi-radar.svg ${pixmapsdir} install -m 644 pixmaps/wifi-radar.png ${pixmapsdir} test -d ${appsdir} || install -d -m 755 ${appsdir} install -m 644 wifi-radar.desktop ${appsdir} wifi-radar.localized: wifi-radar cp wifi-radar wifi-radar.tmp perl -pi -e 's#^CONF_FILE\s+=.*#CONF_FILE = "${sysconfdir}/wifi-radar.conf"#' wifi-radar.tmp mv wifi-radar.tmp wifi-radar.localized tarball: $(TOPDIR)/tmp/${package}-$(VERSION).tar.bz2.sign $(TOPDIR)/tmp/${package}-$(VERSION).tar.bz2.sha256 $(TOPDIR)/tmp/${package}-$(VERSION).tar.bz2.sign: $(TOPDIR)/tmp/${package}-$(VERSION).tar.bz2 cd $(TOPDIR)/tmp && gpg --detach-sign -a --output ${package}-$(VERSION).tar.bz2.asc ${package}-$(VERSION).tar.bz2 cd $(TOPDIR)/tmp && chmod 644 ${package}-$(VERSION).tar.bz2.asc cd $(TOPDIR)/tmp && gpg --verify ${package}-$(VERSION).tar.bz2.asc $(TOPDIR)/tmp/${package}-$(VERSION).tar.bz2.sha256: cd $(TOPDIR)/tmp && sha256sum ${package}-$(VERSION).tar.bz2 > ${package}-$(VERSION).tar.bz2.sha256 $(TOPDIR)/tmp/${package}-$(VERSION).tar.bz2: rm -fr $(TOPDIR)/tmp mkdir -p $(TOPDIR)/tmp/ git archive --format=tar --prefix=${package}-$(VERSION)/ $(BRANCH) | (cd $(TOPDIR)/tmp/ && tar xf -) find $(TOPDIR)/tmp/${package}-$(VERSION) -type f -exec chmod ug+r {} \; find $(TOPDIR)/tmp/${package}-$(VERSION) -type d -exec chmod ug+rx {} \; perl -pi -e 's#^WIFI_RADAR_VERSION\s+=.*#WIFI_RADAR_VERSION = "${VERSION}"#' $(TOPDIR)/tmp/${package}-$(VERSION)/wifi-radar chmod 755 $(TOPDIR)/tmp/${package}-$(VERSION)/wifi-radar cd $(TOPDIR)/tmp && tar -ch ${package}-$(VERSION) | bzip2 > ${package}-$(VERSION).tar.bz2 cd $(TOPDIR)/tmp && chmod 644 ${package}-$(VERSION).tar.bz2 ls -l $(TOPDIR)/tmp/ dev-docs: ~/inprogress/HappyDoc3-r3_1/happydoc -d docs/developer/ wifi-radar.py changelog: mkdir -p $(TOPDIR)/tmp/ git log | perl -pi -e 's//>/g; s/@/@/g;' > $(TOPDIR)/tmp/CHANGELOG clean: rm -f wifi-radar.localized rm -fr tmp/ distclean: clean wifi-radar-2.0.s08+dfsg/pixmaps/0000750000175000017500000000000011356151665015761 5ustar winniewinniewifi-radar-2.0.s08+dfsg/pixmaps/unknown_profile.png0000640000175000017500000000155311356151665021713 0ustar winniewinniePNG  IHDR bKGD pHYs  tIME &z|gIDAT8˅Ah\eol6m41]4i9'x'=o"z7J<)x(h DF]n]n|ۄ |0|g  o@w  Pr@<nSQ@z^p,m8/]mlB`/PF"p˒t@X{ 7 29z{Y1b6_M! .yր8dipc}@X1M~K(::ߴ:l@X6Βi}@acouX0fYS}/2###|qQQ>XpŃ}ѣV+]XXhT'Rggg_D3g =7'{ξ g~~>Vŏ1hprr2j48}|}7'UEWVV'&&(l 4 sQZ-s94ű^^HU3'@UEbNT*qҵ]j>|BPle"*ans image/svg+xml wifi-radar-2.0.s08+dfsg/pixmaps/signal_barely.xpm0000640000175000017500000000126211356151665021324 0ustar winniewinnie/* XPM */ static char * signal_barely_xpm[] = { "20 20 10 1", " c None", ". c #C6C6C6", "+ c #CCCCCC", "@ c #DBDBDB", "# c #D3D3D3", "$ c #A9B099", "% c #95A173", "& c #6B8428", "* c #B4B7AC", "= c #80924D", " .+++.", " +@@@+", " +@@@+", " +@@@+", " +@@@+", " .++++#@@@+", " +@@@@@@@@+", " +@@@@@@@@+", " +@@@@@@@@+", " +@@@@@@@@+", " $%%%%#@@@@@@@@+", " %&&&&@@@@@@@@@+", " %&&&&@@@@@@@@@+", " %&&&&@@@@@@@@@+", " %&&&&@@@@@@@@@+", "*%%%%=&&&&@@@@@@@@@+", "%&&&&&&&&&@@@@@@@@@+", "%&&&&&&&&&@@@@@@@@@+", "%&&&&&&&&&@@@@@@@@@+", "*%%%%%%%%%+++++++++."}; wifi-radar-2.0.s08+dfsg/pixmaps/wifi-radar.png0000640000175000017500000000534611356151665020525 0ustar winniewinniePNG  IHDRcOU{sBIT|dtEXtSoftwarewww.inkscape.org< xIDATxyUgS"$$$e eQ@,Q hH J,b0EHD Mɢ !,%!0a߆dB&?Ngx[{*Ꚛ{}{ιIb !Zd-2 BEF"@hQ l̆k9LRg3u_"p3l|&m`)xxHk[ K{Fv5 xFҲȬ G  za ww8V$p_K~ 8XSu |=x$į{ǁ9Ӯ`b#of# kc6p7=PC0C 7q+N`%`B20I󪔓3pw 9ρ*:_Q V#] Ϋ1 dYCn+ `SzN{)/|gEBL߁O9u>?u/I38Vܵ5crtWovvFѵ2 ,8{vyK҂1Ǯ%f0\9 |'`{`{3 |9Pbs20f0|%p2GUasOJz5eA$f㐠^vZafh>p)'Z;3VJ\N9Eٕ*T+2 l~Y r6I Z0< \(?I ZY].D0;I:3A[Un/tIozxyYsYR9TE v h>8PҚ2rO~ 07}C}mpc9彁;qs<8:@Ω.9vdL h2bQCoOb /b  'dN;d WJFt%{pP<cTam .fn`e\0lI_ͥcd\;fn\F>pp)mEi!ed܃=Y[҃UBm,6h:S҄X8;e8_RGn3 @NtS'2.)*O#.|q*DDHt=uffX病C,Y{{eD&y`㌦%?O$a >K*E?Ki$iIIdW:(]*Y&1mYLj$JEIhY{IUxc4)fa%--7d'< ٚl%anKGgi%&! m.DJD;g"er{ck%@ J@-L(8f U'҉@CQ\$6<ȽsہTp9{_kΰ&3ų˸_]u<'j%A1$}:v]8x,=pxp17oәhK|x5D?mgxxIrj%缓sofS<ݍ0ݘ%HfK^Ǹ#x7̢Mǯx<^?5Ő\-s&b>|MNNjքZ-v[ӱ{n^o̙3޽{ͭR!eʲL iee%ztjvt镉}`QŁ]B߶]__wEUUYZZc?55(iX!h4z=!1F!~_3PGEq$*EQ̌V>;kG}#G<~ћ722 !a fl[)%F㒜Sev^'<lrls"8RRTU%$$xzmmm F12hJB#X={6mnnpPJI^+Y^^N~`X˒DzG.i =p|7~NnfW4iRr}Ŀ`s>g&IENDB`wifi-radar-2.0.s08+dfsg/pixmaps/wifi_radar_32x32.png0000640000175000017500000000153611356151665021445 0ustar winniewinniePNG  IHDR szzbKGD pHYs  tIME4O,IDATxKeqc(YMBfZ݅eR D7]0j1d J"!"NB 2pZNe26oVa[$|F`0u[|VSv0wxפ&q-h5qɯ7-/YN>b 7n?yYؠ4cWуC)s#1AG_:*4Q7ĥ]Ĺ+Ex`LuWcI(z^Wpb@8҆qAa>xy5f؍m?;o唽x-E?mٻ7@OV?  c]˪Nm-}Wtb^F캠u` wo73O&7A5g{DXVcԱxV<}GλN9կZeB)5ҎCN\dL%Ň̀f??l6T܋EPqIENDB`wifi-radar-2.0.s08+dfsg/pixmaps/signal_none.xpm0000640000175000017500000000116311356151665021005 0ustar winniewinnie/* XPM */ static char * signal_none_xpm[] = { "20 20 6 1", " c None", ". c #C6C6C6", "+ c #CCCCCC", "@ c #DBDBDB", "# c #D3D3D3", "$ c #C2C2C2", " .+++.", " +@@@+", " +@@@+", " +@@@+", " +@@@+", " .++++#@@@+", " +@@@@@@@@+", " +@@@@@@@@+", " +@@@@@@@@+", " +@@@@@@@@+", " .++++#@@@@@@@@+", " +@@@@@@@@@@@@@+", " +@@@@@@@@@@@@@+", " +@@@@@@@@@@@@@+", " +@@@@@@@@@@@@@+", "$++++#@@@@@@@@@@@@@+", "+@@@@@@@@@@@@@@@@@@+", "+@@@@@@@@@@@@@@@@@@+", "+@@@@@@@@@@@@@@@@@@+", "$++++++++++++++++++."}; wifi-radar-2.0.s08+dfsg/pixmaps/wifi_radar_inkscape.svg0000640000175000017500000000773511356151665022503 0ustar winniewinnie image/svg+xml wifi-radar-2.0.s08+dfsg/pixmaps/strength.xcf0000640000175000017500000000755511356151665020336 0ustar winniewinniegimp xcf file#  BBselection_to_pathApApAp@Ap@Ap@A @A @A @A A A A A A @A @A @A @Ap@Ap@ApApApApAAAAAAAAAAAAAp$gimp-image-grid(style intersections) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches) u ? border     ,<                            @@    ߀@ ߀best      p88888 8 8 8 8 88888r8nnnnn n n n n nnnnnrn r rok      # 7 GmJJJJJ J J J J JJJJJJm[[[[[ [ [ [ [ [[[[[[m m better        kkkkk k k k k k  ((((( ( ( ( ( (  low      V j z,,OOOOO,ttttt,gray         r r r rSelection Mask  !1 rwifi-radar-2.0.s08+dfsg/pixmaps/signal_best.xpm0000640000175000017500000000116311356151665021003 0ustar winniewinnie/* XPM */ static char * signal_best_xpm[] = { "20 20 6 1", " c None", ". c #9DAABF", "+ c #7B96BF", "@ c #386EBF", "# c #5982BF", "$ c #AEB4BF", " .+++.", " +@@@+", " +@@@+", " +@@@+", " +@@@+", " .++++#@@@+", " +@@@@@@@@+", " +@@@@@@@@+", " +@@@@@@@@+", " +@@@@@@@@+", " .++++#@@@@@@@@+", " +@@@@@@@@@@@@@+", " +@@@@@@@@@@@@@+", " +@@@@@@@@@@@@@+", " +@@@@@@@@@@@@@+", "$++++#@@@@@@@@@@@@@+", "+@@@@@@@@@@@@@@@@@@+", "+@@@@@@@@@@@@@@@@@@+", "+@@@@@@@@@@@@@@@@@@+", "$++++++++++++++++++."}; wifi-radar-2.0.s08+dfsg/LICENSE.GPL0000640000175000017500000004311011356151665015726 0ustar winniewinnie GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. wifi-radar-2.0.s08+dfsg/wifi-radar.sh0000740000175000017500000000017311356151665016664 0ustar winniewinnie#!/bin/bash # Shell wrapper that calls wifi-radar using sudo PATH=/sbin:/usr/sbin:/usr/local/sbin:$PATH sudo wifi-radar $* wifi-radar-2.0.s08+dfsg/wifi-radar.ebuild0000640000175000017500000000131011356151665017507 0ustar winniewinnie# Copyright 1999-2005 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # $Header: $ inherit eutils DESCRIPTION="WiFi Radar is a Python/PyGTK2 utility for managing WiFi profiles." HOMEPAGE="http://wifi-radar.berlios.de/" SRC_URI="https://wifi-radar.berlios.de/pub/${PN}-${PV}.tar.bz2" LICENSE="GPL-2" SLOT="0" KEYWORDS="~x86" IUSE="" DEPEND=">=dev-python/pygtk-2 net-wireless/wireless-tools" src_install() { dosbin wifi-radar dobin wifi-radar.sh doicon wifi-radar.svg doicon wifi-radar.png dodoc README dodoc ChangeLog dodoc AUTHORS dodoc INSTALL make_desktop_entry wifi-radar.sh "WiFi Radar" insinto /etc/conf.d ; newins wifi-radar.conf wifi-radar.conf }wifi-radar-2.0.s08+dfsg/man/0000750000175000017500000000000011356151665015053 5ustar winniewinniewifi-radar-2.0.s08+dfsg/man/man1/0000750000175000017500000000000011356151665015707 5ustar winniewinniewifi-radar-2.0.s08+dfsg/man/man1/wifi-radar.10000640000175000017500000000562011356151665020022 0ustar winniewinnie.\" Author: Sean Robinson .\" Copyright 2005 by Nicolas Brouard .\" Copyright 2009 by Sean Robinson .\" ----------------------------------------------------------------- . .TH wifi-radar 1 "July 2009" "WiFi Radar 2.0" . .SH NAME . WiFi Radar \- utility for managing WiFi profiles . .SH SYNOPSIS . .B wifi-radar [\fIOPTION\fR]... . .SH DESCRIPTION . .B WiFi Radar is a PyGTK2 utility for managing WiFi profiles. .PP It will look for the config file in .B /etc/wifi-radar/wifi-radar.conf. You can change that in wifi-radar. .PP If the configuration file does not exist, it will create it, so you must always run it within a correctly permitted account (as root or use sudo or pam). .PP Recent versions partially implement WPA-TKIP with wpa_supplicant. You need a running wpa_supplicant installation with a /etc/wpa_supplicant/wpa_supplicant.conf file. Then by setting in your /etc/wifi-radar/wifi-radar.conf file the "use_wpa = yes" option and "wpa_driver = ipw" for example, wpa_supplicant will be launched when you connect using this profile. .PP But currently you can't set your wpa_supplicant options like the psk, proto, key_mgmt etc. using .B wifi-radar. Your wpa_supplicant configuration file should be set and tested already. If you have different networks set in wpa_supplicant.conf, then you can switch using wifi-radar. .PP The .B wifi-radar script accepts the following command-line options: . .SH OPTIONS . .TP 8 \fB\-v\fR, \fB\-\-version\fR for printing the version. . .SH FILES . .TP 8 .B /etc/wifi-radar/wifi-radar.conf See .i wifi-radar.conf(5) for more information. . .SH BUGS . Probably lots! .PP Because of repeated scanning, WiFi Radar is very power consuming. .PP Please report bugs to the mailing list . .SH MORE INFORMATION . The GIT repository is available at https://git.berlios.de/cgi-bin/gitweb.cgi?p=wifi-radar;a=summary .PP If you have questions, visit http://wifi-radar.berlios.de . .SH AUTHOR . This Python program was originally written by Ahmad Baitaimal . It has been maintained at various times by Brian Elliott Finley and Sean Robinson . Contributions have been provided by: .IP \(bu 4 Douglas Breault .IP \(bu 4 Nicolas Brouard .IP \(bu 4 Gary Case .IP \(bu 4 Jon Collette .IP \(bu 4 David Decotigny .IP \(bu 4 Simon Gerber .IP \(bu 4 Joey Hurst .IP \(bu 4 Ante Karamatic .IP \(bu 4 Richard Monk .IP \(bu 4 Kevin Otte .IP \(bu 4 Nathanael Rebsch .IP \(bu 4 Andrea Scarpino .IP \(bu 4 Patrick Winnertz . .SH SEE ALSO . .I wifi-radar.conf(5) .I wpa_supplicant(8) . wifi-radar-2.0.s08+dfsg/man/man5/0000750000175000017500000000000011356151665015713 5ustar winniewinniewifi-radar-2.0.s08+dfsg/man/man5/wifi-radar.conf.50000640000175000017500000002610311356151665020755 0ustar winniewinnie.\" Author: Sean Robinson .\" Copyright 2009 by Sean Robinson .\" Made available under the Creative Commons Attribution License 3.0 .\" ----------------------------------------------------------------- . .TH wifi-radar.conf 5 "July 2009" "WiFi Radar 2.0" . .SH NAME . wifi-radar.conf \- configuration file for WiFi Radar . .SH SYNOPSIS . .B wifi-radar.conf . .SH DESCRIPTION . wifi-radar.conf is the configuration file for .B WiFi Radar .I (wifi-radar(1)) a PyGTK2 utility for managing WiFi profiles in GNU/Linux. .PP The file is an ini-type format with three global sections: .B [DEFAULT], [DHCP], and .B [WPA]. These are followed by zero or more profile sections. .PP The settings contained in the configuration file can all be edited from within .B WiFi Radar, either through the .B Preferences button or the .B Edit button. But you are free to edit the configuration file manually if you like. . .SH Interpolated Strings . It is possible to use configuration options in the value of other options. To use interpolated strings, surround any option from the configuration file with .B %( and .B )s. So, to use the .I interface option from the .B [DEFAULT] section in the value of any other option, use \fB%(\fIinterface\fB)s\fR in the option's value. . .SH Global Settings . .SS [DEFAULT] General options. . .TP 4 .B auto_profile_order Comma-separated list of profiles, surrounded by square brackets, specifying the order of profiles in the main window. An example value: ['test:00:00:00:00:00:00', 'WinterPalace:'] .IP .B (default: []) . .TP 4 .B commit_required Set to .B True if .I iwconfig(8) commit should be used after each iwconfig command. .IP .B (default: False) . .TP 4 .B ifconfig_command Specify the path to .I ifconfig(8), the command to use when manipulating the IP settings of the NIC. .IP .B (default: /sbin/ifconfig) . .TP 4 .B ifup_required Set to .B True if the NIC must be activated (i.e. ifconfig wlan0 up) before scanning will work. .IP .B (default: False) . .TP 4 .B interface Specifies the interface to scan. Set to the name of your NIC (e.g. eth1 or wlan0). The special value 'auto_detect' will use the first-found WiFi interface. .IP .B (default: auto_detect) .TP 4 .B iwconfig_command Specify the path to .I iwconfig(8), the command to use when trying to associate with a network. .IP .B (default: /sbin/iwconfig) . .TP 4 .B iwlist_command Specify the path to .I iwlist(8), the command to use for scanning for access points. .IP .B (default: /sbin/iwlist) . .TP 4 .B logfile Sets the location of the log file. .IP .B (default: /var/log/wifi-radar.log) . .TP 4 .B loglevel This sets the verbosity of messages sent to the logfile. The number given here is a threshold value, only those messages emitted by .B WiFi Radar which exceed loglevel will be written to the logfile. The maximum (and default) value of 50 means to only save the most critical messages and a loglevel of 0 means to save all messages to the logfile. .IP .B (default: 50) . .TP 4 .B route_command Specify the path to .I route(8), the command to use to set up network routing if DHCP is not used. .IP .B (default: /sbin/route) . .TP 4 .B speak_command Specify the path to the command to use to speak status messages. This can be any program which takes a string on the command line. .IP .B (default: /usr/bin/say) . .TP 4 .B speak_up Set to .B True to use the speak command. .IP .B (default: False) . .TP 4 .B version The version of .B WiFi Radar which created this configuration file. This value is overwritten by .B WiFi Radar each time the configuration file is saved. . .SS [DHCP] Options for the DHCP client used by .B WiFi Radar. . .TP 4 .B args The parameters to pass to the DHCP client when acquiring a lease (i.e. setting up a connection). .IP .B (default: -D -o -i dhcp_client -t %(timeout)s) . .TP 4 .B command The command to use to automatically set up the IP networking. This can be any DHCP client, like .I dhcpcd(8) or .I dhclient(8), which forks into the background or exits when it acquires an IP address or fails. .IP .B (default: /sbin/dhcpcd) . .TP 4 .B kill_args The parameters to pass to the DHCP client when disconnecting from a network. .IP .B (default: -k) . .TP 4 .B pidfile Specify where the DHCP client saves its state info. This file is used if the standard DHCP disconnect does not work and .B WiFi Radar must kill the client on its own. .IP .B (default: /etc/dhcpc/dhcpcd-%(interface)s.pid) . .TP 4 .B timeout The time (in seconds) to allow the DHCP client to try to acquire a lease. If the DHCP client does not stop itself after this length of time plus five seconds, .B WiFi Radar will force the client to end. .IP .B (default: 30) . .SS [WPA] Options for the WPA supplicant used by .B WiFi Radar. . .TP 4 .B args The parameters to pass to the WPA supplicant when associating with the network. .IP .B (default: -B -i %(interface)s -c %(configuration)s -D %(driver)s -P %(pidfile)s) . .TP 4 .B command Specify the command to use as the WPA supplicant. .IP .B (default: /usr/sbin/wpa_supplicant) . .TP 4 .B configuration The WPA supplicant's configuration file. .IP .B (default: /etc/wpa_supplicant.conf) . .TP 4 .B driver The WPA supplicant driver to use. .IP .B (default: wext) . .TP 4 .B kill_command The command to use to end the WPA supplicant. .IP .B The default is an empty value. . .TP 4 .B pidfile Specify where the WPA supplicant saves its state info. .IP .B (default: /var/run/wpa_supplicant.pid) . .SH Per-profile Settings Each profile header consists of the network name (a.k.a. ESSID), followed by a colon, and optionally followed by the network address (a.k.a. BSSID). The BSSID may be blank if the profile is a roaming profile. So a sample roaming profile section name could look like [WinterPalace:]. . .TP 4 .B available Used internally by .B WiFi Radar to indicate whether an access point is currently detected, it should always be False in the configuration file. .IP .B (default: False) . .TP 4 .B bssid A copy of the BSSID in the section name, it is used to calculate the section name. The BSSID is the network address, it usually matches the AP address. It may be blank in a roaming profile. .IP .B (default: 00:00:00:00:00:00) . .TP 4 .B channel The channel to use to connect with the network. .IP .B (default: auto) . .TP 4 .B con_postscript The command to run after connecting to the network. .IP .B The default is an empty value. . .TP 4 .B con_prescript The command to run before connecting to the network. .IP .B The default is an empty value. . .TP 4 .B dis_postscript The command to run after disconnecting from the network. .IP .B The default is an empty value. . .TP 4 .B dis_prescript The command to run before disconnecting from the network. .IP .B The default is an empty value. . .TP 4 .B dns1 The primary DNS server. Part of the static configuration to use when not using DHCP. .IP .B The default is an empty value. . .TP 4 .B dns2 The secondary DNS server. Part of the static configuration to use when not using DHCP. .IP .B The default is an empty value. . .TP 4 .B domain The domain (e.g. winterpalace.org) of the network. Part of the static configuration to use when not using DHCP. .IP .B The default is an empty value. . .TP 4 .B encrypted Whether the network is encrypted. The value for this option is determined by scanning and will be overwritten if changed manually in the configuration file. .IP .B (default: False) . .TP 4 .B essid The network name. This is a copy of the ESSID in the section name and is used to calculate the section name. .IP .B The default is an empty value. . .TP 4 .B gateway The IP address of the gateway to other networks. Part of the static configuration to use when not using DHCP. .IP .B The default is an empty value. . .TP 4 .B ip The fixed IP address to use on this network. Part of the static configuration to use when not using DHCP. .IP .B The default is an empty value. . .TP 4 .B key The WEP encryption key. This is not used with WPA. .IP .B The default is an empty value. . .TP 4 .B known This is used internally by .B WiFi Radar to indicate whether an access point has a configured profile, it should always be True in the configuration file. .IP .B (default: True) . .TP 4 .B mode This is the association mode to use. This is not the same as the mode reported by the AP. In fact, this should be a reflection of the AP mode (i.e. Master mode AP should be Managed mode here). .IP .B (default: auto) . .TP 4 .B netmask The netmask (e.g. 192.168.1.0/255) to use. Part of the static configuration to use when not using DHCP. .IP .B The default is an empty value. . .TP 4 .B protocol The WiFi protocol used by the access point (AP). This is only used as a place to store the protocol read from the AP. This will be overwritten the next time the AP is scanned. .IP .B (default: g) . .TP 4 .B roaming Set to True if this is a roaming profile. .IP .B (default: False) . .TP 4 .B security This should/will be the security mode (i.e. open or restricted), but as it currently causes crashes, it is not used. .IP .B The default is an empty value. . .TP 4 .B signal The signal level read from the access point (AP). This is used internally by .B WiFi Radar, the value will be overwritten each time the configuration file is saved. .IP .B (default: 0) . .TP 4 .B use_dhcp When set to True, .B WiFi Radar will ask the DHCP client to configure the IP settings. .IP .B (default: True) . .TP 4 .B use_wpa When set to True, .B WiFi Radar will ask the WPA supplicant to handle associating with the access point. .IP .B (default: False) . .TP 4 .B wpa_driver The card driver the WPA supplicant should use. .IP .B The default is an empty value. . .SH EXAMPLE . .nf [DEFAULT] auto_profile_order = ['test:00:00:00:00:00:00', 'WinterPalace:'] commit_required = False ifconfig_command = /sbin/ifconfig ifup_required = True interface = auto_detect iwconfig_command = /sbin/iwconfig iwlist_command = /sbin/iwlist logfile = /var/log/wifi-radar.log loglevel = 50 route_command = /sbin/route speak_command = /usr/bin/say speak_up = False version = 2.0.s02 .PP [DHCP] args = -D -o -i dhcp_client -t %(timeout)s command = /sbin/dhcpcd kill_args = -k pidfile = /etc/dhcpc/dhcpcd-%(interface)s.pid timeout = 30 .PP [WPA] args = -B -i %(interface)s -c %(configuration)s -D %(driver)s -P %(pidfile)s command = /usr/sbin/wpa_supplicant configuration = /etc/wpa_supplicant.conf driver = wext kill_command = pidfile = /var/run/wpa_supplicant.pid .PP [test:00:00:00:00:00:00] available = False bssid = 00:00:00:00:00:00 channel = auto con_postscript = con_prescript = dis_postscript = dis_prescript = dns1 = dns2 = domain = encrypted = False essid = test gateway = ip = key = known = True mode = auto netmask = protocol = g roaming = False security = signal = 0 use_dhcp = True use_wpa = False wpa_driver = .PP [WinterPalace:] available = False bssid = channel = auto con_postscript = con_prescript = dis_postscript = dis_prescript = dns1 = dns2 = domain = encrypted = True essid = WinterPalace gateway = ip = key = 123456789ABCDEF known = True mode = auto netmask = protocol = g roaming = True security = signal = 0 use_dhcp = True use_wpa = False wpa_driver = . .SH FILES . .TP 8 .B /etc/wifi-radar/wifi-radar.conf . .SH BUGS . Probably lots! . .SH SEE ALSO . .I wifi-radar(1) .I wpa_supplicant.conf(5) .