#!/usr/bin/python
#	wifi_radar.py
#	A wireless profile manager for X1000 Linux
#	http://x1000.bitbuilder.com
#
#	Ahmad Baitalmal <ahmad@baitalmal.com>
#	This software is under the GPL license
import time, os, sys, re, ConfigParser, thread
####################################################################################################
# Defaults, these could be different for your distro.
CONF_FILE		= "/etc/conf.d/wifi_radar.conf"
IWLIST_COMMAND	= "/usr/sbin/iwlist"
IWCONFIG_COMMAND= "/usr/sbin/iwconfig"
IFCONFIG_COMMAND= "/sbin/ifconfig"
DHCP_COMMAND	= "/sbin/dhcpcd -S"
ROUTE_COMMAND	= "/sbin/route"
# X1000 Linux has a say command (text to speach) to accounce connecting to networks.
# Set the SPEAK_UP to false if you do not have or want this.
SAY_COMMAND		= "/usr/local/bin/say"
######################################
# More defaults, these may get overridden by values found in the conf file
# The icon file, it is an svg file
ICON_FILE		= "/usr/share/pixmaps/wifi_radar.svg"
# The interface you use
INTERFACE		= "eth1"
# How long should the scan last?
SCAN_TIMEOUT	= 5
# Should I speak up when connecting to a network? (If you have a speach command)
SPEAK_UP		= True
#####################################
# Labels
USE_DHCP_LABEL	= "Automatic network configuration (DHCP)"
USE_IP_LABEL	= "Manual network configuration"
WIFI_SET_LABEL	= "WiFi Options"
WIFI_MODES		= [ 'Auto', 'Managed', 'Ad-Hoc', 'Master', 'Repeater', 'Secondary', 'Monitor' ]
WIFI_SECURITY	= [ 'Auto', 'open', 'restricted' ]
WIFI_CHANNELS	= [ 'Auto', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14' ]
####################################################################################################
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",
"               .+++.",
"               +@@@+",
"               +@@@+",
"               +@@@+",
"               +@@@+",
"          .++++#@@@+",
"          +@@@@@@@@+",
"          +@@@@@@@@+",
"          +@@@@@@@@+",
"          +@@@@@@@@+",
"     .++++#@@@@@@@@+",
"     +@@@@@@@@@@@@@+",
"     +@@@@@@@@@@@@@+",
"     +@@@@@@@@@@@@@+",
"     +@@@@@@@@@@@@@+",
"$%%%%#@@@@@@@@@@@@@+",
"%&&&&@@@@@@@@@@@@@@+",
"%&&&&@@@@@@@@@@@@@@+",
"%&&&&@@@@@@@@@@@@@@+",
"$%%%%++++++++++++++."
]
signal_none_pb	= None
signal_low_pb	= None
signal_barely_pb= None
signal_ok_pb	= None
signal_best_pb	= None
exit_flag		= False
####################################################################################################
####################################################################################################
# Speaking up
def	say( words ):
	if not SPEAK_UP: return
	words = words.replace( "\"", "\\\"" )
	os.system( "%s \"%s\"" % ( SAY_COMMAND, words ) )

# Scan for a limited time, return ap names found
def scanning_thread( lock ):
	global access_points
	global main_radar_window
	global exit_flag
	# Setup our essid pattern matcher
	essid_pattern		= re.compile( "ESSID:\"([^\"]+)\".*Protocol:IEEE 802.11([abg]+).*Mode:([^\n]+).*Encryption key:(on|off).*Signal level=-?([0-9]+)", re.I | re.M  | re.S )
	ekey_pattern		= re.compile( "", re.I | re.M  | re.S )
	# Access points we find will be added to the access_points dictionary
	scan_command 		= "%s %s scan" % ( IWLIST_COMMAND, INTERFACE )
	trial = 0
	while True:
		# reset the signal strengths
		print "."
		if exit_flag:
			print "Ending scan"
			thread.exit()
			return
		for ap in access_points:
			access_points[ ap ]['signal'] = '0'
		# we may not be running in a thread
		try: 
			lock.acquire()
		except: 
			trial = trial + 1
			if trial > SCAN_TIMEOUT:
				return
		f = os.popen( scan_command, "r" )
		scandata = f.read()
		f.close()
		try: lock.release()
		except: pass
		# split the scan data based on the address
		hits = scandata.split( '- Address:' )
		for hit in hits:
			m = essid_pattern.search( hit )
			while m:
				token		= m.group()
				apname		= m.groups()[0]
				protocol	= m.groups()[1]
				mode		= m.groups()[2]
				encrypted	= m.groups()[3]
				signal		= m.groups()[4]
				lock.acquire()
				if access_points.has_key( apname ):
					# We know this ssid, make it available
					access_points[ apname ]['available'] = True
				else:
					# Add it to the available networks
					ap = {}
					ap['known']		= False
					ap['available']	= True
					access_points[ apname ] = ap
				access_points[ apname ]['protocol']	= protocol
				access_points[ apname ]['mode']		= mode
				access_points[ apname ]['encrypted']= ( encrypted == 'on' )
				access_points[ apname ]['signal'] 	= signal
				lock.release()
				scandata = scandata.replace( token, '' )
				m = essid_pattern.search( scandata )
		# Update the list
		try:
			lock.acquire()
			main_radar_window.update_plist_items()
			lock.release()
		except:
			pass
		time.sleep( 0.1 )
	return

# Connects to the first matching network
def connect_to_preferred():
	global access_points
	global auto_profile_order
	found_one = False
	for ssid in auto_profile_order:
		ssid = ssid.strip()
		if 	access_points.has_key( ssid )	\
			and	access_points[ ssid ]['known'] \
			and access_points[ ssid ]['available']:
			found_one = True
			connect_to_network( ssid )
			break
	if not found_one:
		say( "No preferred network found" )
		print "   No preferred network found"
		print access_points

def	connect_to_network( essid ):
	msg = "Connecting to the %s network" % essid
	say( msg )
	print "   %s" % msg
	profile = get_profile_from_conf_file( essid )
	if not profile:
		print "Unknown SSID"
		say( "Unknown SSID" )
		return
	# We got the essid, get the key
	key = profile['key']
	if  key == '':
		key 		= "key off"
	else:
		key 		= "key %s" % profile['key']
	# Lets set the wireless stuff
	iwconfig_command= "%s %s essid \'%s\' %s" 	% ( IWCONFIG_COMMAND, INTERFACE, essid, key )
	os.system( iwconfig_command )
	# Now normal network stuff
	use_dhcp = profile['use_dhcp']
	if use_dhcp:
		os.system( "%s %s" % ( DHCP_COMMAND, INTERFACE ) )
	else:
		ip 		= profile['ip']
		netmask = profile['netmask']
		gateway = profile['gateway']
		domain	= profile['domain']
		dns1	= profile['dns1']
		dns2 	= profile['dns2']
		ifconfig_command= "%s %s down; /sbin/ifconfig %s %s netmask %s" % \
			( IFCONFIG_COMMAND, INTERFACE, INTERFACE, ip, netmask )
		route_command 	= "%s add default gw %s" % ( ROUTE_COMMAND, gateway )
		if domain != '':
			domain 		= "domain %s\n" % domain
		if dns1 != '':
			dns1 		= "nameserver %s\n" % dns1
		if dns2 != '':
			dns2 		= "nameserver %s\n" % dns2
		if ( domain != '' ) or ( dns1 != '' ) or ( dns2 != '' ):
			dns_command	= "echo \"%s%s%s\" > /etc/resolv.conf" % ( domain, dns1, dns2 )
			os.system( dns_command )
		os.system( ifconfig_command )
		os.system( route_command )

def	disconnect_interface():
	msg = "Disconnecting"
	say( msg )
	print msg
	# Lets clear out the wireless stuff
	iwconfig_command= "%s %s essid any key off" % ( IWCONFIG_COMMAND, INTERFACE )
	os.system( iwconfig_command )
	# Now take the interface down
	ifconfig_command= "%s %s down" % ( IFCONFIG_COMMAND, INTERFACE )
	os.system( ifconfig_command )

def get_profile_from_conf_file( essid ):
	# We got the essid, get the key
	profile = {}
	if not confFile.has_section( essid ):
		return None
	profile['ssid']		= essid
	profile['key']		= ''
	profile['mode']		= 'Auto'
	profile['security']	= 'Auto'
	profile['channel']	= 'Auto'
	if confFile.has_option( essid, "key" ):
		profile['key']	= confFile.get( essid, "key" )
	if confFile.has_option( essid, "mode" ):
		profile['mode']	= confFile.get( essid, "mode" )
	if confFile.has_option( essid, "security" ):
		profile['security']	= confFile.get( essid, "security" )
	if confFile.has_option( essid, "channel" ):
		profile['channel']	= confFile.get( essid, "channel" )
	# Now normal network stuff
	profile['use_dhcp']	= False
	if confFile.has_option( essid, "use_dhcp" ):
		profile['use_dhcp'] = confFile.getboolean( essid, "use_dhcp" )
	profile['ip'] 		= ''
	if confFile.has_option( essid, "ip" ):
		profile['ip']	= confFile.get( essid, "ip" )
	profile['netmask']	= ''
	if confFile.has_option( essid, "netmask" ):
		profile['netmask'] = confFile.get( essid, "netmask" )
	profile['gateway']	= ''
	if confFile.has_option( essid, "gateway" ):
		profile['gateway'] = confFile.get( essid, "gateway" )
	profile['domain']	= ''
	if confFile.has_option( essid, "domain" ):
		profile['domain'] = confFile.get( essid, "domain" )
	profile['dns1']		= ''
	if confFile.has_option( essid, "dns1" ):
		profile['dns1'] = confFile.get( essid, "dns1" )
	profile['dns2']		= ''
	if confFile.has_option( essid, "dns2" ):
		profile['dns2'] = confFile.get( essid, "dns2" )
	return profile

def set_profile_to_conf_file( profile ):
	if not confFile.has_section( profile['ssid'] ):
		confFile.add_section( profile['ssid'] )
	confFile.set( profile['ssid'], 'key', profile['key'] )
	confFile.set( profile['ssid'], 'mode', profile['mode'] )
	if profile['use_dhcp']:
		confFile.set( profile['ssid'], 'use_dhcp', 'yes' )
		try: confFile.remove_option( profile['ssid'], 'ip' )
		except: pass
		try: confFile.remove_option( profile['ssid'], 'netmask' )
		except: pass
		try: confFile.remove_option( profile['ssid'], 'gateway' )
		except: pass
		try: confFile.remove_option( profile['ssid'], 'domain' )
		except: pass
		try: confFile.remove_option( profile['ssid'], 'dns1' )
		except: pass
		try: confFile.remove_option( profile['ssid'], 'dns2' )
		except: pass
	else:
		confFile.set( profile['ssid'], 'use_dhcp', 'no' )
		confFile.set( profile['ssid'], 'ip', profile['ip'] )
		confFile.set( profile['ssid'], 'netmask', profile['netmask'] )
		confFile.set( profile['ssid'], 'gateway', profile['gateway'] )
		confFile.set( profile['ssid'], 'domain', profile['domain'] )
		confFile.set( profile['ssid'], 'dns1', profile['dns1'] )
		confFile.set( profile['ssid'], 'dns2', profile['dns2'] )
	confFile.write( open( CONF_FILE, "w" ) )

##################
# The main window
class radar_window:
	def __init__( self ):
		# create the main window and connect the normal events
		global	signal_xpm_none
		global	signal_xpm_low
		global	signal_xpm_barely
		global	signal_xpm_ok
		global	signal_xpm_best
		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_file( ICON_FILE )
		self.window.set_icon( icon )
		self.window.set_border_width( 10 )
		self.window.set_size_request( 450, 250 )
		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.instructions = gtk.Label("My preferred WiFi networks")
		self.instructions.show()
		#
		#self.scan_button = gtk.Button( "Scan" )
		#self.scan_button.set_flags( gtk.CAN_DEFAULT )
		#self.window.set_default( self.scan_button )
		#self.scan_button.connect( 'clicked', self.scan, None  )
		#self.scan_button.show()
		#
		self.close_button = gtk.Button( "Close", gtk.STOCK_CLOSE )
		self.close_button.connect( 'clicked', self.delete_event, None  )
		self.close_button.show()
		#                            apname  known_icon known available wep_icon signal_level mode protocol
		self.pstore = gtk.ListStore( str,    str,       int,  int,      str,     gtk.gdk.Pixbuf,         str, str )
		self.rebuild_plist_items()
		self.plist = gtk.TreeView( self.pstore )
		self.pcol	= gtk.TreeViewColumn( "SSID" )
		# The ssid column
		self.plist.append_column( self.pcol )
		self.pix_cell 	= gtk.CellRendererPixbuf()
		self.wep_cell 	= gtk.CellRendererPixbuf()
		self.ssid_cell 	= gtk.CellRendererText()
		self.pcol.pack_start( self.pix_cell, False )
		self.pcol.pack_start( self.wep_cell, False )
		self.pcol.pack_start( self.ssid_cell, True )
		self.pcol.add_attribute( self.wep_cell, 'stock-id', 4 )
		self.pcol.add_attribute( self.pix_cell, 'stock-id', 1 )
		self.pcol.add_attribute( self.ssid_cell, 'text', 0 )
		#self.pcol.set_attribute( self.ssid_cell, 'markup', True )
		#self.ssid_cell.markup = True
		# The wep column
		#self.wep_cell 	= gtk.CellRendererPixbuf()
		#self.wcol	= gtk.TreeViewColumn( "WEP" )
		#self.wcol.pack_start( self.wep_cell, True )
		#self.wcol.add_attribute( self.wep_cell, 'stock-id', 4 )
		#self.plist.append_column( self.wcol )
		# The signal column
		
		#self.sig_cell 	= gtk.CellRendererText()
		#self.scol	= gtk.TreeViewColumn( "Signal" )
		#self.scol.pack_start( self.sig_cell, True )
		#self.scol.add_attribute( self.sig_cell, 'text', 5 )
		#self.plist.append_column( self.scol )
		
		self.sig_cell 	= gtk.CellRendererPixbuf()
		self.scol	= gtk.TreeViewColumn( "Signal" )
		self.scol.pack_start( self.sig_cell, True )
		self.scol.add_attribute( self.sig_cell, 'pixbuf', 5 )
		self.plist.append_column( self.scol )
		
		# The mode column
		self.mode_cell 	= gtk.CellRendererText()
		self.mcol	= gtk.TreeViewColumn( "Mode" )
		self.mcol.pack_start( self.mode_cell, True )
		self.mcol.add_attribute( self.mode_cell, 'text', 6 )
		self.plist.append_column( self.mcol )
		# The protocol column
		self.prot_cell 	= gtk.CellRendererText()
		self.protcol	= gtk.TreeViewColumn( "802.11" )
		self.protcol.pack_start( self.prot_cell, True )
		self.protcol.add_attribute( self.prot_cell, 'text', 7 )
		self.plist.append_column( self.protcol )
		# DnD Ordering
		self.plist.set_reorderable( True )
		self.pstore.connect( 'row-changed', self.save_auto_profile_order )
		# the list scroll bar
		sb = gtk.VScrollbar( self.plist.get_vadjustment() )
		sb.show()
		self.plist.show()
		#
		self.new_button = gtk.Button( "New" )
		self.new_button.connect( 'clicked', self.create_new_profile, None  )
		self.new_button.show()
		#
		self.edit_button = gtk.Button( "Edit" )
		self.edit_button.connect( 'clicked', self.edit_profile, None  )
		self.edit_button.show()
		#
		self.delete_button = gtk.Button( "Delete" )
		self.delete_button.connect( 'clicked', self.delete_profile, None  )
		self.delete_button.show()
		#
		self.connect_button = gtk.Button( "Connect" )
		self.connect_button.connect( 'clicked', self.connect_profile, None  )
		self.connect_button.show()
		#
		self.disconnect_button = gtk.Button( "Disconnect" )
		self.disconnect_button.connect( 'clicked', self.disconnect_profile, None  )
		self.disconnect_button.show()
		# lets add our widgets
		rows		= gtk.VBox( gtk.FALSE, 3 )
		listcols	= gtk.HBox( gtk.FALSE, 0 )
		prows		= gtk.VBox( gtk.FALSE, 0 )
		# lets start packing
		# the rows level
		rows.pack_start( self.instructions, gtk.FALSE, gtk.TRUE, 0 )
		rows.pack_start( listcols, gtk.TRUE, gtk.TRUE, 0 )
		# the list columns
		listcols.pack_start( self.plist, gtk.TRUE, gtk.TRUE, 0 )
		listcols.pack_start( sb, gtk.FALSE, gtk.FALSE, 0 )
		listcols.pack_start( prows, gtk.FALSE, gtk.FALSE, 5 )
		# the list buttons
		prows.pack_start( self.new_button, gtk.FALSE, gtk.FALSE, 2 )
		prows.pack_start( self.edit_button, gtk.FALSE, gtk.FALSE, 2 )
		prows.pack_start( self.delete_button, gtk.FALSE, gtk.FALSE, 2 )
		prows.pack_start( gtk.HSeparator(), gtk.FALSE, gtk.FALSE, 4 )
		prows.pack_start( self.connect_button, gtk.FALSE, gtk.FALSE, 2 )
		prows.pack_start( self.disconnect_button, gtk.FALSE, gtk.FALSE, 2 )
		#
		self.window.action_area.pack_start( self.close_button )
		#self.window.action_area.pack_start( self.scan_button )
		#
		rows.show()
		listcols.show()
		prows.show()

		self.window.vbox.add( rows )
		self.window.vbox.set_spacing( 3 )
		self.window.show_all()
		# set the scan button as the default
		#self.scan_button.grab_focus()

	def main( self ):
		gtk.main()

	def destroy( self, widget = None):
		print "gtk.main_quit"
		gtk.main_quit()

	def delete_event( self, widget, event, data=None ):
		# Save the preferred networks order
		global exit_flag
		global lock
		print "Exiting"
		#lock.acquire()
		print "entered threads lock"
		exit_flag = True
		print "flag set to true"
		#gtk.threads_enter()
		self.save_auto_profile_order()
		self.destroy()
		#gtk.threads_leave()
		#lock.release()
		return gtk.FALSE

	def scan( self, widget, data=None ):
		#global lock
		# start the scanning therad
		#lock = thread.allocate_lock()
		#thread.start_new( scanning_thread, () )
		#print "rebuilding the list"
		#self.pstore.clear()
		#self.rebuild_plist_items()
		#print self.get_row_by_ssid( 'test' )
		pass

	def rebuild_plist_items( self ):
		# Add our known profiles in order
		for ssid in auto_profile_order:
			ssid = ssid.strip()
			if access_points.has_key( ssid ) and access_points[ ssid ]['known']:
				wep = None
				if access_points[ ssid ]['encrypted']: wep = gtk.STOCK_DIALOG_AUTHENTICATION
				# 1 here means that we know this ssid -------------v
				self.pstore.append( [ ssid, gtk.STOCK_DIALOG_INFO, 1, 0, wep, self.signal_none_pb, access_points[ ssid ]['mode'], access_points[ ssid ]['protocol'] ] )
		# Now add any known profiles not in the profile order
		for ap in access_points:
			if ap in auto_profile_order: continue
			wep = None
			if access_points[ ap ]['encrypted']: wep = gtk.STOCK_DIALOG_AUTHENTICATION
			# 1 here means that we know this ssid ---------------v
			self.pstore.append( [ ap, gtk.STOCK_DIALOG_QUESTION, 0, 0, wep, self.signal_none_pb, access_points[ ap ]['mode'], access_points[ ap ]['protocol'] ] )
			
	def update_plist_items( self ):
		"""Updates the profiles list"""
		gtk.threads_enter()
		for ap in access_points:
			wep = None
			if access_points[ ap ]['encrypted']: wep = gtk.STOCK_DIALOG_AUTHENTICATION
			prow = self.get_row_by_ssid( ap )
			if prow:
				#print "Setting prow", access_points[ ap ]
				prow[4] = wep
				prow[5] = self.pixbuf_from_signal( access_points[ ap ][ 'signal' ] )
				prow[6] = access_points[ ap ][ 'mode' ]
				prow[7] = access_points[ ap ][ 'protocol' ]
				#for val in prow:
				#	print val
			else:
				# 1 here means that we know this ssid ---------------v
				self.pstore.append( [ ap, gtk.STOCK_DIALOG_QUESTION, 0, 0, wep, self.pixbuf_from_signal( access_points[ ap ]['signal'] ), access_points[ ap ]['mode'], access_points[ ap ]['protocol'] ] )
			# give the list a chance to update
			while gtk.events_pending():
				gtk.main_iteration()
		gtk.threads_leave()
	
	def pixbuf_from_signal( self, signal ):
		signal = int( signal )
		#print signal
		if signal >= 80 or signal == 0:
			return self.signal_none_pb
		elif signal >= 78:
			return self.signal_low_pb
		elif signal >= 75:
			return self.signal_barely_pb
		elif signal >= 40:
			return self.signal_ok_pb
		elif signal < 40:
			return self.signal_best_pb
		else:
			return None
	
	def get_row_by_ssid( self, ssid ):
		for row in self.pstore:
			if row[0] == ssid: 
				#print row
				return row
		return None
		
	def create_new_profile( self, widget, data=None ):
		p = profile_dialog( self )
		while True:
			ok = p.run()
			if ok:
				profile = p.get_profile()
				# Check that the ssid does not exist already
				if profile['ssid'] in access_points:
					dlg = gtk.MessageDialog(
						self.window,
						gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_MODAL,
						gtk.MESSAGE_ERROR,
						gtk.BUTTONS_OK,
						"A profile for %s already exists" % profile['ssid'] )
					dlg.run()
					dlg.destroy()
					del dlg
					# try again
					continue
				set_profile_to_conf_file( profile )
				# Add lets add it up
				ap = {}
				ap['known']		= True
				ap['available']	= False
				ap['encrypted'] = False
				ap['mode']		= 'Auto'
				ap['security']	= 'Auto'
				ap['channel']	= 'Auto'
				ap['protocal']	= 'b'
				if confFile.has_option( profile['ssid'], 'key'):
					if len( confFile.get( profile['ssid'], 'key' ) ) > 0:
						ap['encrypted'] = True
				access_points[ profile['ssid'] ] = ap
				# if it is not in the auto_profile_order add it
				if not profile['ssid'] in auto_profile_order:
					auto_profile_order.append( profile['ssid'] )
				# add to the store
				wep = None
				if ap['encrypted']: wep = gtk.STOCK_DIALOG_AUTHENTICATION
				self.pstore.append( [ profile['ssid'], gtk.STOCK_REFRESH, 1, 0, wep, ap['signal'], ap['mode'], ap['protocol'] ] )
			break
		p.destroy()

	def edit_profile( self, widget, data=None ):
		( store, selected_iter ) = self.plist.get_selection().get_selected()
		if not selected_iter: return
		ssid	= store.get_value( selected_iter, 0 )
		known	= store.get_value( selected_iter, 2 )
		if not known: return
		profile = get_profile_from_conf_file( ssid )
		p = profile_dialog( self )
		p.set_profile( profile, True )
		ok = p.run()
		if ok:
			profile = p.get_profile()
			set_profile_to_conf_file( profile )
		p.destroy()

	def delete_profile( self, widget, data=None ):
		( store, selected_iter ) = self.plist.get_selection().get_selected()
		if not selected_iter: return
		ssid	= store.get_value( selected_iter, 0 )
		known	= store.get_value( selected_iter, 2 )
		if not known: return
		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?" % ssid )
		res = dlg.run()
		dlg.destroy()
		del dlg
		if res == gtk.RESPONSE_NO: return
		# Remove it
		confFile.remove_section( ssid )
		if ssid in auto_profile_order: auto_profile_order.remove( ssid )
		if access_points.has_key( ssid ): access_points.pop( ssid )
		self.pstore.remove( selected_iter )
		# Let's save our current state
		self.save_auto_profile_order()

	def connect_profile( self, widget, data=None ):
		( store, selected_iter ) = self.plist.get_selection().get_selected()
		if not selected_iter: return
		ssid	= store.get_value( selected_iter, 0 )
		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
			p = profile_dialog( self )
			# get a blank profile from the dialog
			profile = p.get_profile()
			profile['ssid'] = ssid
			p.set_profile( profile, True )
			ok = p.run()
			if ok:
				profile = p.get_profile()
				set_profile_to_conf_file( profile )
				# change the icon
				self.pstore.set_value( selected_iter, 1, gtk.STOCK_DIALOG_INFO )
				# make it known
				self.pstore.set_value( selected_iter, 2, 1 )
				# if it is not in the auto_profile_order add it
				if not profile['ssid'] in auto_profile_order:
					auto_profile_order.append( profile['ssid'] )
				self.save_auto_profile_order()
				p.destroy()
				connect_to_network( ssid )
			else:
				p.destroy()
		else:
			connect_to_network( ssid )

	def disconnect_profile( self, widget, data=None ):
		disconnect_interface()

	def get_ssid_iter( self, ssid ):
		piter = self.pstore.get_iter_first()
		while piter:
			# only if it's known
			if self.pstore.get_value( piter, 0 ) == ssid: break
		return piter

	def save_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 ) == 1:
				auto_profile_order.append( self.pstore.get_value( piter, 0 ) )
			piter = self.pstore.iter_next( piter )
		# save it
		apo = ','.join( auto_profile_order )
		confFile.set( 'DEFAULT', 'auto_profile_order', apo )
		confFile.write( open( CONF_FILE, 'w' ) )

###################################
class profile_dialog:
	def __init__( self, parent ):
		self.parent = parent
		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_file( ICON_FILE )
		self.dialog.set_icon( icon )
		self.dialog.set_resizable( gtk.FALSE )
		self.dialog.set_transient_for( self.parent.window )
		#self.dialog.set_size_request( 400, 400 )
		ssid_table = gtk.Table( 1, 2, gtk.FALSE )
		ssid_table.set_row_spacings( 3 )
		ssid_table.set_col_spacings( 3 )
		#################
		# The ssid labels
		l = gtk.Label( 'Network Name' )
		ssid_table.attach( l, 0, 1, 0, 1 )
		# The ssid textboxes
		self.ssid = gtk.Entry( 32 )
		self.ssid.set_text('ssid')
		ssid_table.attach( self.ssid, 1, 2, 0, 1 )
		#self.key = gtk.Entry( 32 )
		#ssid_table.attach( self.key, 1, 2, 1, 2 )
		# Add the ssid table to the dialog
		self.dialog.vbox.pack_start( ssid_table, gtk.TRUE, gtk.TRUE, 5 )
		
		
		# create the wifi expander
		self.wifi_expander = gtk.Expander( WIFI_SET_LABEL )
		#self.wifi_expander.connect( 'notify::expanded', self.toggle_use_dhcp )
		wifi_table = gtk.Table( 4, 2, gtk.FALSE )
		wifi_table.set_row_spacings( 3 )
		wifi_table.set_col_spacings( 3 )
		# The Wifi labels
		l = gtk.Label( 'Mode' )
		wifi_table.attach( l, 0, 1, 0, 1 )
		l = gtk.Label( 'Channel' )
		wifi_table.attach( l, 0, 1, 1, 2 )
		l = gtk.Label( 'Key' )
		wifi_table.attach( l, 0, 1, 2, 3 )
		l = gtk.Label( 'Security' )
		wifi_table.attach( l, 0, 1, 3, 4 )
		# The Wifi text boxes
		self.mode = gtk.combo_box_new_text()
		for mode in WIFI_MODES:
			self.mode.append_text( mode )
		self.mode.set_active( 0 )
		wifi_table.attach( self.mode, 1, 2, 0, 1 )
		self.channel = gtk.combo_box_new_text()
		for channel in WIFI_CHANNELS:
			self.channel.append_text( channel )
		self.channel.set_active( 0 )
		wifi_table.attach( self.channel, 1, 2, 1, 2 )
		self.key = gtk.Entry( 32 )
		#self.key.set_text('0.0.0.0')
		wifi_table.attach( self.key, 1, 2, 2, 3 )
		self.security = gtk.combo_box_new_text()
		for security in WIFI_SECURITY:
			self.security.append_text( security )
		self.security.set_active( 0 )
		wifi_table.attach( self.security, 1, 2, 3, 4 )
		# 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, gtk.FALSE, gtk.FALSE, 5 )
		
		# create the dhcp expander
		self.dhcp_expander = gtk.Expander( USE_DHCP_LABEL )
		self.dhcp_expander.connect( 'notify::expanded', self.toggle_use_dhcp )
		ip_table = gtk.Table( 6, 2, gtk.FALSE )
		ip_table.set_row_spacings( 3 )
		ip_table.set_col_spacings( 3 )
		# The IP labels
		l = gtk.Label( 'IP' )
		ip_table.attach( l, 0, 1, 0, 1 )
		l = gtk.Label( 'Netmask' )
		ip_table.attach( l, 0, 1, 1, 2 )
		l = gtk.Label( 'Gateway' )
		ip_table.attach( l, 0, 1, 2, 3 )
		l = gtk.Label( 'Domain' )
		ip_table.attach( l, 0, 1, 3, 4 )
		l = gtk.Label( 'DNS' )
		ip_table.attach( l, 0, 1, 4, 5 )
		l = gtk.Label( 'DNS' )
		ip_table.attach( l, 0, 1, 5, 6 )
		# The IP text boxes
		self.ip = gtk.Entry( 15 )
		self.ip.set_text('0.0.0.0')
		ip_table.attach( self.ip, 1, 2, 0, 1 )
		self.netmask = gtk.Entry( 15 )
		self.netmask.set_text('255.255.255.0')
		ip_table.attach( self.netmask, 1, 2, 1, 2 )
		self.gw = gtk.Entry( 15 )
		self.gw.set_text('0.0.0.0')
		ip_table.attach( self.gw, 1, 2, 2, 3 )
		self.domain = gtk.Entry( 32 )
		self.domain.set_text('domain.com')
		ip_table.attach( self.domain, 1, 2, 3, 4 )
		self.dns1 = gtk.Entry( 15 )
		self.dns1.set_text('0.0.0.0')
		ip_table.attach( self.dns1, 1, 2, 4, 5 )
		self.dns2 = gtk.Entry( 15 )
		self.dns2.set_text('0.0.0.0')
		ip_table.attach( self.dns2, 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, gtk.FALSE, gtk.FALSE, 5 )
				
	def run( self ):
		self.dialog.show_all()
		return self.dialog.run()

	def destroy( self ):
		self.dialog.destroy()
		del self.dialog

	def toggle_use_dhcp( self, widget, data = None ):
		expanded = self.dhcp_expander.get_expanded()
		if expanded:
			self.dhcp_expander.set_label( USE_IP_LABEL )
		else:
			self.dhcp_expander.set_label( USE_DHCP_LABEL )

	def get_profile( self ):
		profile					= {}
		profile['ssid']			= self.ssid.get_text().strip()
		profile['key']			= self.key.get_text().strip()
		profile['mode']			= self.get_array_item( self.mode.get_active(), WIFI_MODES )
		profile['security']		= self.get_array_item( self.security.get_active(), WIFI_SECURITY )
		profile['channel']		= self.get_array_item( self.channel.get_active(), WIFI_CHANNELS )
		profile['protocol']		= 'b'
		use_dhcp 				= ( self.dhcp_expander.get_expanded() == gtk.FALSE )
		if use_dhcp:
			profile['use_dhcp'] = True
		else:
			profile['use_dhcp'] = False
			profile['ip']		= self.ip.get_text().strip()
			profile['netmask']	= self.netmask.get_text().strip()
			profile['gateway']	= self.gw.get_text().strip()
			profile['domain']	= self.domain.get_text().strip()
			profile['dns1']		= self.dns1.get_text().strip()
			profile['dns2']		= self.dns2.get_text().strip()
		return profile

	def set_profile( self, profile, known ):
		print profile
		self.ssid.set_text( profile['ssid'] )
		if known:
			self.ssid.set_editable( False )
			self.dialog.set_title( "WiFi Profile for %s" % profile['ssid'] )
		self.key.set_text( profile['key'] )
		self.mode.set_active( self.get_array_index( profile['mode'], WIFI_MODES ) )
		self.channel.set_active( self.get_array_index( profile['channel'], WIFI_CHANNELS ) )
		self.security.set_active( self.get_array_index( profile['security'], WIFI_SECURITY ) )
		#self.protocol.set_text( profile['protocol'] )
		if profile['use_dhcp'] == True:
			self.dhcp_expander.set_expanded( gtk.FALSE)
		else:
			self.dhcp_expander.set_expanded( gtk.TRUE )
			self.ip.set_text( profile['ip'] )
			self.netmask.set_text( profile['netmask']	)
			self.gw.set_text( profile['gateway'] )
			self.domain.set_text( profile['domain'] )
			self.dns1.set_text( profile['dns1'] )
			self.dns2.set_text( profile['dns2'] )
			
	def get_array_index( self, item, array ):
		try:
			return array.index( item.strip() )
		except:
			pass
		return 0
		
	def get_array_item( self, index, array ):
		try:
			return array[ index ]
		except:
			pass
		return 'Auto'
		
	def enable_network_stuff( self, yes ):
		self.ip.set_sensitive( yes )
		self.netmask.set_sensitive( yes )
		self.gw.set_sensitive( yes )
		self.domain.set_sensitive( yes )
		self.dns1.set_sensitive( yes )
		self.dns2.set_sensitive( yes )
		
def configure():
	global main_radar_window
	global scanner
	global lock
	main_radar_window = radar_window()
	lock = thread.allocate_lock()
	thread.start_new( scanning_thread, ( lock, ) )
	main_radar_window.main()


####################################################################################################
# Initializers
access_points		= {}
auto_profile_order	= ""
lock				= None
s					= None
#sys.setcheckinterval( 100 )
# First load our conf file and know profiles
confFile			= ConfigParser.ConfigParser()
if not os.path.isfile( CONF_FILE ):
	# No config file exists, build one real quick
	confFile.set("DEFAULT", "interface", INTERFACE )
	confFile.set("DEFAULT", "scan_timeout", SCAN_TIMEOUT )
	confFile.set("DEFAULT", "speak_up", SPEAK_UP )
	confFile.set("DEFAULT", "auto_profile_order", '' )
	confFile.set("DEFAULT", "icon_file", ICON_FILE )
	confFile.write( open( CONF_FILE, "w" ) )
else:
	confFile.readfp( open( CONF_FILE ) )
	# Override the defaults
	try: INTERFACE		= confFile.get			( "DEFAULT", "interface" )
	except: confFile.set("DEFAULT", "interface", INTERFACE )
	try: SCAN_TIMEOUT	= confFile.getint		( "DEFAULT", "scan_timeout" )
	except: confFile.set("DEFAULT", "scan_timeout", SCAN_TIMEOUT )
	try: SPEAK_UP		= confFile.getboolean	( "DEFAULT", "speak_up" )
	except: confFile.set("DEFAULT", "speak_up", SPEAK_UP )
	try: auto_profile_order	= confFile.get	( "DEFAULT", "auto_profile_order" )
	except: confFile.set("DEFAULT", "auto_profile_order", auto_profile_order )
	try: ICON_FILE		= confFile.get	( "DEFAULT", "icon_file" )
	except: confFile.set("DEFAULT", "icon_file", ICON_FILE )
	# convert the auto_profile_order to a list for ordering
	if auto_profile_order == '':
		auto_profile_order = []
	else:
		auto_profile_order = auto_profile_order.split( ',' )
	# First, we add our known profiles
	for apname in confFile.sections():
		ap = {}
		# set the defaults
		ap['known']		= True
		ap['available']	= False
		ap['encrypted'] = False
		ap['mode']		= 'Auto'
		ap['security']	= 'Auto'
		ap['channel']	= 'Auto'
		ap['protocol']	= 'g'
		# read the important values
		if confFile.has_option( apname, 'key'):
			if len( confFile.get( apname, 'key' ) ) > 0:
				ap['encrypted'] = True
		if confFile.has_option( apname, 'mode'):
			apmode = confFile.get( apname, 'mode' )
			if len( apmode ) > 0:
				ap['mode'] = apmode
		if confFile.has_option( apname, 'security'):
			apsec = confFile.get( apname, 'security' )
			if len( apsec ) > 0:
				ap['security'] = apsec
		if confFile.has_option( apname, 'channel'):
			apchan = confFile.get( apname, 'channel' )
			if len( apchan ) > 0:
				ap['channel'] = apchan
		if confFile.has_option( apname, 'protocol'):
			approt = confFile.get( apname, 'protocol' )
			if len( approt ) > 0:
				ap['protocol'] = approt
		access_points[ apname ] = ap
		# if it is not in the auto_profile_order add it
		if not apname in auto_profile_order:
			auto_profile_order.append( apname )
# Are we in configure mode?
if len( sys.argv ) > 1 and sys.argv[1] == '--config':
	import gtk
	gtk.threads_init()
	#gtk.threads_enter()
	configure()
else:
	scanning_thread()
	connect_to_preferred()
