Use ConfigFile helper methods throughout program
[wifi-radar.git] / wifi-radar
blobce55c6491bc48af3bbbed6121e7190d90ef45b47
1 #!/usr/bin/python
3 # $Id$
4 # vi:set filetype=python noet:
6 # A wireless profile manager for Linux
8 # Originally created for x1000 Linux:
9 # http://x1000.bitbuilder.com
11 # Created by:
12 # Ahmad Baitalmal <ahmad@baitalmal.com>
14 # Maintained by:
15 # Brian Elliott Finley <brian@thefinleys.com>
17 # License:
18 # GPL
20 # http://www.bitbuilder.com/wifi_radar
21 # http://svn.systemimager.org
23 # See CREDITS file for more contributors.
24 # See ChangeLog file for, well, changes.
27 import time, os, signal, sys, re, ConfigParser, threading, socket, string
28 from types import *
30 WIFI_RADAR_VERSION = "0.0.0"
32 if __debug__:
33 print '__debug__ is True'
34 # NOTE: Remove the '-OO' from '#!/usr/bin/python -OO' in the first line to
35 # turn on debugging.
38 # Where the conf file should live could be different for your distro. Please change
39 # at install time with "make install sysconfdir=/etc/wifi-radar" or similar. -BEF-
41 CONF_FILE = "/etc/wifi-radar.conf"
43 os.environ['LC_MESSAGES'] = 'C'
45 if os.path.isfile(CONF_FILE) and not os.access(CONF_FILE, os.R_OK):
46 print "Can't open " + CONF_FILE + "."
47 print "Are you root?"
48 sys.exit()
50 # get our hostname
51 HOSTNAME = socket.gethostname()
54 #####################################
55 # Labels
56 USE_DHCP_LABEL = "Automatic network configuration (DHCP)"
57 USE_IP_LABEL = "Manual network configuration"
58 WIFI_SET_LABEL = "WiFi Options"
59 CON_PP_LABEL = "Connection Commands"
60 DIS_PP_LABEL = "Disconnection Commands"
61 USE_WPA_LABEL = "Use WPA"
62 NO_WPA_LABEL = "No WPA"
63 WIFI_MODES = [ '', 'auto', 'Managed', 'Ad-Hoc', 'Master', 'Repeater', 'Secondary', 'Monitor' ]
64 WIFI_SECURITY = [ '', 'open', 'restricted' ]
65 WIFI_CHANNELS = [ '', 'auto', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14' ]
66 ####################################################################################################
68 ####################################################################################################
69 ####################################################################################################
71 # Sets the interface to the specified network device
72 def set_network_device(device):
73 #print "set_network_device: ", device
74 if device != "auto_detect":
75 confFile.set_opt('DEFAULT.interface', device)
76 else: # auto detect network device
77 # Get a list of 802.11 enabled devices by parsing the output of iwconfig.
78 # If no devices are found, default to eth1.
79 iwconfig_info = os.popen(confFile.get_opt('DEFAULT.iwconfig_command') + " 2>&1", 'r')
80 wireless_devices = [ (x[0:x.find(" ")]) for x in iwconfig_info if("ESSID" in x)]
81 if len(wireless_devices) > 0:
82 confFile.set_opt('DEFAULT.interface', wireless_devices[0])
83 else:
84 print "No wifi-device found. Exiting."
85 sys.exit()
87 # Scan for a limited time, return ap names and bssid found
88 def scanning_thread( confFile, lock = None ):
89 global access_points
90 global main_radar_window
91 global exit_flag
92 # Setup our essid pattern matcher
93 essid_pattern = re.compile( "ESSID\s*(:|=)\s*\"([^\"]+)\"", re.I | re.M | re.S )
94 protocol_pattern = re.compile( "Protocol\s*(:|=)\s*IEEE 802.11\s*([abg]+)", re.I | re.M | re.S )
95 mode_pattern = re.compile( "Mode\s*(:|=)\s*([^\n]+)", re.I | re.M | re.S )
96 channel_pattern = re.compile( "Channel\s*(:|=)*\s*(\d+)", re.I | re.M | re.S )
97 enckey_pattern = re.compile( "Encryption key\s*(:|=)\s*(on|off)", re.I | re.M | re.S )
98 signal_pattern = re.compile( "Signal level\s*(:|=)\s*-?([0-9]+)", re.I | re.M | re.S )
99 # Access points we find will be added to the access_points dictionary
100 # Some cards neet to have the interface up to scan
101 if confFile.get_opt_as_bool('DEFAULT.ifup_required'):
102 os.spawnlp(os.P_WAIT, 'ifconfig', confFile.get_opt('DEFAULT.ifconfig_command'), confFile.get_opt('DEFAULT.interface'), "up")
103 trial = 0
104 while True:
105 # we may not be running in a thread
106 if None != lock:
107 lock.acquire()
108 else:
109 trial = trial + 1
110 if trial > confFile.get_opt_as_int('DEFAULT.scan_timeout'):
111 return
113 if exit_flag:
114 if __debug__:
115 print "Ending scan"
116 if None != lock: lock.release()
117 return
119 if __debug__:
120 print ".",
122 # update the signal strengths
123 scan_command = "%s %s scan" % ( confFile.get_opt('DEFAULT.iwlist_command'), confFile.get_opt('DEFAULT.interface') )
124 f = os.popen(scan_command, "r")
125 scandata = f.read()
126 f.close()
127 if __debug__:
128 print "Current IP ", get_current_ip()
129 print "Current ESSID ", get_current_essid()
130 print "Current BSSID ", get_current_bssid()
131 for ap in access_points:
132 access_points[ ap ]['signal'] = '0'
133 # split the scan data based on the address
134 hits = scandata.split( '- Address:' )
135 for hit in hits:
136 foundvalues = False
137 essid = ''
138 protocol = 'b'
139 mode = ''
140 channel = ''
141 encrypted = 'off'
142 signal = '0'
143 m = essid_pattern.search( hit )
144 if m:
145 # we found an essid
146 foundvalues = True
147 essid = m.groups()[1]
148 m = bssid_pattern.search( hit ) # get BSSID from scan
149 if m:
150 bssid = m.groups()[1]
151 m = protocol_pattern.search( hit ) # get protocol from scan
152 if m:
153 protocol = m.groups()[1]
154 m = mode_pattern.search( hit ) # get Mode from scan
155 if m:
156 mode = m.groups()[1]
157 m = channel_pattern.search( hit ) # get channel from scan
158 if m:
159 channel = m.groups()[1]
160 m = enckey_pattern.search( hit ) # get Encryption Key from scan
161 if m:
162 encrypted = m.groups()[1]
163 m = signal_pattern.search( hit ) # get signal strength from scan
164 if m:
165 signal = m.groups()[1]
166 ap = make_section_name( essid, bssid )
167 # Set the values we found
168 if access_points.has_key( ap ):
169 # We know this AP, make it available
170 access_points[ ap ]['available'] = True
171 else:
172 # Add it to the available networks
173 new_ap = {}
174 new_ap['known'] = False
175 new_ap['available'] = True
176 access_points[ ap ] = new_ap
177 access_points[ ap ]['essid'] = essid
178 access_points[ ap ]['bssid'] = bssid
179 access_points[ ap ]['protocol'] = protocol
180 access_points[ ap ]['mode'] = mode
181 access_points[ ap ]['channel'] = channel
182 access_points[ ap ]['encrypted'] = ( encrypted == 'on' )
183 access_points[ ap ]['signal'] = signal
184 if None != lock:
185 lock.release()
187 if confFile.get_opt('DEFAULT.interface').find('ath') == 0:
188 time.sleep( 30 )
189 else:
190 time.sleep( 0.5 )
191 return
193 # Connects to the first matching network
194 def connect_to_preferred():
195 global access_points
196 global auto_profile_order
197 global lock
199 lock = threading.RLock()
201 found_one = False
202 for ap in auto_profile_order:
203 ap = ap.strip()
204 if access_points.has_key( ap ) \
205 and access_points[ ap ]['known'] \
206 and access_points[ ap ]['available']:
207 found_one = True
208 connect_to_network( access_points[ ap ]['essid'], access_points[ ap ]['bssid'], None )
209 break
211 if not found_one:
212 say( "No preferred network found" )
213 if __debug__:
214 print " No preferred network found"
215 print access_points
217 def get_current_ip():
218 """Returns the current IP if any by calling ifconfig"""
219 ifconfig_info = os.popen(confFile.get_opt('DEFAULT.ifconfig_command') + " " + confFile.get_opt('DEFAULT.interface'), 'r')
220 # Be careful to the language (inet adr: in French for example)
222 # Hi Brian
224 # I'm using wifi-radar on a system with German translations (de_CH-UTF-8).
225 # There the string in ifconfig is inet Adresse for the IP which isn't
226 # found by the current get_current_ip function in wifi-radar. I changed
227 # the according line (#289; gentoo, v1.9.6-r1) to
228 # >ip_re = re.compile(r'inet [Aa]d?dr[^.]*:([^.]*\.[^.]*\.[^.]*\.[0-9]*)')
229 # which works on my system (LC_ALL=de_CH.UTF-8) and still works with LC_ALL=C.
231 # I'd be happy if you could incorporate this small change because as now
232 # I've got to change the file every time it is updated.
234 # Best wishes
236 # Simon
237 ip_re = re.compile(r'inet [Aa]d?dr[^.]*:([^.]*\.[^.]*\.[^.]*\.[0-9]*)')
238 for line in ifconfig_info:
239 if ip_re.search( line ):
240 return ip_re.search( line ).group(1)
241 return None
243 def get_current_essid():
244 """Returns the current ESSID if any by calling iwconfig"""
245 iwconfig_info = os.popen(confFile.get_opt('DEFAULT.iwconfig_command') + " " + confFile.get_opt('DEFAULT.interface'), 'r')
246 # Be careful to the language (inet adr: in French for example)
247 essid_re = re.compile( "ESSID\s*(:|=)\s*\"([^\"]+)\"", re.I | re.M | re.S )
248 for line in iwconfig_info:
249 if essid_re.search( line ):
250 return essid_re.search( line ).group(2)
251 return None
253 def get_current_bssid():
254 """Returns the current BSSID if any by calling iwconfig"""
255 iwconfig_info = os.popen(confFile.get_opt('DEFAULT.iwconfig_command') + " " + confFile.get_opt('DEFAULT.interface'), 'r')
256 bssid_re = re.compile( "Access Point\s*(:|=)\s*([a-zA-Z0-9:]+)", re.I | re.M | re.S )
257 for line in iwconfig_info:
258 if bssid_re.search( line ):
259 return bssid_re.search( line ).group(2)
260 return None
262 def connect_to_network( essid, bssid, status_win ):
263 msg = "Connecting to the %s (%s) network" % (essid, bssid)
264 say( msg )
265 if __debug__:
266 print " %s" % msg
267 profile = get_profile_from_conf_file( essid, bssid )
268 if not profile:
269 if __debug__:
270 print "Unknown ESSID"
271 say( "Unknown ESSID" )
272 return
273 # ready to dance
274 # Let's run the connection prescript
275 con_prescript = profile['con_prescript']
276 if con_prescript.strip() != '':
277 # got something to execute
278 if __debug__:
279 print "executing connection prescript:", con_prescript
280 os.system(con_prescript)
281 # Some cards need to have the interface up
282 if confFile.get_opt_as_bool('DEFAULT.ifup_required'):
283 os.spawnlp(os.P_WAIT, 'ifconfig', confFile.get_opt('DEFAULT.ifconfig_command'), confFile.get_opt('DEFAULT.interface'), "up")
284 iwconfig_args = [ confFile.get_opt('DEFAULT.interface') ]
285 # Let's start with the essid
286 if __debug__:
287 print "Setting essid ", essid
288 iwconfig_args.append( 'essid' )
289 iwconfig_args.append( '"%s"' % essid )
290 iwconfig_args.append( 'nick' )
291 iwconfig_args.append( '"%s"' % essid )
292 #os.spawnlp(os.P_WAIT, 'iwconfig', confFile.get_opt('DEFAULT.iwconfig_command'), confFile.get_opt('DEFAULT.interface'), 'essid', "%s" % essid)
293 # Now we do the key
294 key = profile['key']
295 if key == '':
296 key = 'off'
297 else:
298 key = "%s %s" % ( profile['security'], profile['key'], )
299 if __debug__:
300 print "Setting key", key
301 #os.spawnlp(os.P_WAIT, 'iwconfig', confFile.get_opt('DEFAULT.iwconfig_command'), confFile.get_opt('DEFAULT.interface'), 'key', key)
302 iwconfig_args.append( 'key' )
303 iwconfig_args.append( key )
304 # Now, the mode
305 mode = profile['mode']
306 if mode != '':
307 if __debug__:
308 print "Setting mode ", mode
309 #os.spawnlp(os.P_WAIT, 'iwconfig', confFile.get_opt('DEFAULT.iwconfig_command'), confFile.get_opt('DEFAULT.interface'), 'mode', mode)
310 iwconfig_args.append( 'mode' )
311 iwconfig_args.append( mode )
312 # Now the channel
313 channel = profile['channel']
314 if channel != '':
315 if __debug__:
316 print "Setting channel ", channel
317 #os.spawnlp(os.P_WAIT, 'iwconfig', confFile.get_opt('DEFAULT.iwconfig_command'), confFile.get_opt('DEFAULT.interface'), 'channel', channel)
318 iwconfig_args.append( 'channel' )
319 iwconfig_args.append( channel )
320 # Now we do the ap by address (do this last since iwconfig seems to want it only there)
321 if __debug__:
322 print "Setting bssid ", profile['bssid']
323 iwconfig_args.append( 'ap' )
324 iwconfig_args.append( '"%s"' % profile['bssid'] )
325 # Some cards require a commit
326 if confFile.get_opt_as_bool('DEFAULT.commit_required'):
327 if __debug__:
328 print "Setting commit "
329 #os.spawnlp(os.P_WAIT, 'iwconfig', confFile.get_opt('DEFAULT.iwconfig_command'), confFile.get_opt('DEFAULT.interface'), 'commit')
330 iwconfig_args.append( 'commit' )
331 if __debug__:
332 print "iwconfig_args %s " % ( iwconfig_args, )
333 iwconfig_command = confFile.get_opt('DEFAULT.iwconfig_command') + ' ' + ' '.join( iwconfig_args )
334 #os.spawnvp(os.P_WAIT, 'iwconfig', iwconfig_args)
335 if __debug__:
336 print "iwconfig_command ", iwconfig_command
337 os.system(iwconfig_command)
338 # Now normal network stuff
339 # Kill off any existing DHCP clients running
340 if os.access(confFile.get_opt('DHCP.pidfile'), os.R_OK):
341 if __debug__:
342 print "Killing existing DHCP..."
343 try:
344 if confFile.get_opt('DHCP.kill_args') != '':
345 if __debug__:
346 print confFile.get_opt('DHCP.command') + " " + confFile.get_opt('DHCP.kill_args')
347 os.popen(confFile.get_opt('DHCP.command') + " " + confFile.get_opt('DHCP.kill_args'))
348 else:
349 os.kill(int(open(confFile.get_opt('DHCP.pidfile'), mode='r').readline()), signal.SIGTERM)
350 except OSError:
351 print "Stale pid file. Removing"
352 os.remove(confFile.get_opt('DHCP.pidfile'))
353 if os.path.isfile(confFile.get_opt('DHCP.pidfile')):
354 print "Stale pid file. Removing"
355 os.remove(confFile.get_opt('DHCP.pidfile'))
356 if os.access(confFile.get_opt('WPA.pidfile'), os.R_OK):
357 if __debug__:
358 print "Killing existing WPA_SUPPLICANT..."
359 try:
360 if not confFile.get_opt('WPA.kill_command') == '':
361 os.spawnlp(os.P_WAIT, confFile.get_opt('WPA.kill_command'), confFile.get_opt('WPA.kill_command'))
362 os.kill(int(open(confFile.get_opt('WPA.pidfile'), mode='r').readline()), signal.SIGTERM)
363 except OSError:
364 print "Stale pid file. Removing"
365 os.remove(confFile.get_opt('WPA.pidfile'))
366 if os.path.isfile(confFile.get_opt('WPA.pidfile')):
367 print "Stale pid file. Removing"
368 os.remove(confFile.get_opt('WPA.pidfile'))
369 use_wpa = profile['use_wpa']
370 if use_wpa :
371 wpa_options = list()
372 wpa_options.append( confFile.get_opt('WPA.command') )
373 wpa_args = "-B -i " + confFile.get_opt('DEFAULT.interface') + " -c " + confFile.get_opt('WPA.configuration') + " -D " + profile['wpa_driver'] + " -P " + confFile.get_opt('WPA.pidfile')
374 wpa_options.extend( wpa_args.split() )
375 wpa_options.append( confFile.get_opt('DEFAULT.interface') )
376 if __debug__:
377 print "WPA args: %s" % ( wpa_options, )
378 if status_win:
379 status_win.update_message("wpa supplicant")
380 wpa_pid = os.spawnvp(os.P_NOWAIT, confFile.get_opt('WPA.command'), wpa_options)
382 use_dhcp = profile['use_dhcp']
383 if use_dhcp :
384 dhcp_options = list()
385 dhcp_options.append(confFile.get_opt('DHCP.command'))
386 dhcp_options.extend(confFile.get_opt('DHCP.args').split())
387 dhcp_options.append(confFile.get_opt('DEFAULT.interface'))
388 if __debug__:
389 print "DHCP args: %s" % ( dhcp_options, )
390 if status_win:
391 status_win.update_message("Acquiring IP Address")
393 # Disable iwlist while dhcp in progress
394 if __debug__:
395 print "Disable iwlist while dhcp in progress..."
396 global lock
397 lock.acquire()
399 dhcp_pid = os.spawnvp(os.P_NOWAIT, confFile.get_opt('DHCP.command'), dhcp_options)
400 timer = confFile.get_opt_as_int('DHCP.timeout')
401 tick = 0.25
402 while os.waitpid(dhcp_pid, os.WNOHANG) == (0,0):
403 if timer < 0:
404 os.kill(dhcp_pid, signal.SIGTERM)
405 break
406 if sys.modules.has_key("gtk"):
407 while gtk.events_pending():
408 gtk.main_iteration(False)
409 timer -= tick
410 time.sleep(tick)
412 # Re-enable iwlist
413 lock.release()
415 if not get_current_ip():
416 if status_win:
417 status_win.update_message("Could not get IP address!")
418 if sys.modules.has_key("gtk"):
419 while gtk.events_pending():
420 gtk.main_iteration(False)
421 time.sleep(3)
422 else:
423 print "Could not get IP address!"
424 return
425 else:
426 if status_win:
427 status_win.update_message("Got IP address. Done")
428 if sys.modules.has_key("gtk"):
429 while gtk.events_pending():
430 gtk.main_iteration(False)
431 time.sleep(2)
432 else:
433 ip = profile['ip']
434 netmask = profile['netmask']
435 gateway = profile['gateway']
436 domain = profile['domain']
437 dns1 = profile['dns1']
438 dns2 = profile['dns2']
439 ifconfig_command= "%s %s down; %s %s %s netmask %s" % \
440 ( confFile.get_opt('DEFAULT.ifconfig_command'), confFile.get_opt('DEFAULT.interface'), confFile.get_opt('DEFAULT.ifconfig_command'), confFile.get_opt('DEFAULT.interface'), ip, netmask )
441 route_command = "%s add default gw %s" % ( confFile.get_opt('DEFAULT.route_command'), gateway )
442 s = ''
443 if domain != '':
444 s += "domain %s\n" % domain
445 if dns1 != '':
446 s += "nameserver %s\n" % dns1
447 if dns2 != '':
448 s += "nameserver %s\n" % dns2
449 if ( s != '' ):
450 f=open('/etc/resolv.conf', 'w')
451 f.write(s)
452 f.close
454 os.system(ifconfig_command)
455 os.system(route_command)
457 # Let's run the connection postscript
458 con_postscript = profile['con_postscript']
459 if con_postscript.strip() != '':
460 # got something to execute
461 if __debug__:
462 print "executing connection postscript:", con_postscript
463 os.system(con_postscript)
465 def disconnect_interface():
466 msg = "Disconnecting"
467 say( msg )
468 if __debug__:
469 print msg
470 profile = get_profile_from_conf_file( get_current_essid(), get_current_bssid() )
471 if not profile:
472 if __debug__:
473 print "Unknown ESSID"
474 say( "Unknown ESSID" )
475 return
476 # Kill off any existing DHCP clients running
477 # Let's run the disconnection prescript
478 dis_prescript = profile['dis_prescript']
479 if dis_prescript.strip() != '':
480 # got something to execute
481 if __debug__:
482 print "executing disconnection prescript:", dis_prescript
483 os.system(dis_prescript)
484 # Kill off any existing DHCP clients running
485 try:
486 if confFile.get_opt('DHCP.kill_args') != '':
487 if __debug__:
488 print confFile.get_opt('DHCP.command') + " " + confFile.get_opt('DHCP.kill_args')
489 os.popen(confFile.get_opt('DHCP.command') + " " + confFile.get_opt('DHCP.kill_args'))
490 except:
491 if os.access(confFile.get_opt('DHCP.pidfile'), os.R_OK):
492 if __debug__:
493 print "Killing existing DHCP..."
494 try:
495 os.kill(int(open(confFile.get_opt('DHCP.pidfile'), mode='r').readline()), signal.SIGTERM)
496 except OSError:
497 print "Stale pid file. Removing"
498 os.remove(confFile.get_opt('DHCP.pidfile'))
499 if os.path.isfile(confFile.get_opt('DHCP.pidfile')):
500 print "Stale pid file. Removing"
501 os.remove(confFile.get_opt('DHCP.pidfile'))
502 # Kill off any existing WPA_SUPPLICANT clients running
503 if os.access(confFile.get_opt('WPA.pidfile'), os.R_OK):
504 if __debug__:
505 print "Killing existing WPA_SUPPLICANT..."
506 try:
507 if not confFile.get_opt('WPA.kill_command') == '':
508 os.spawnlp(os.P_WAIT, confFile.get_opt('WPA.kill_command'), confFile.get_opt('WPA.kill_command'))
509 os.kill(int(open(confFile.get_opt('WPA.pidfile'), mode='r').readline()), signal.SIGTERM)
510 except OSError:
511 print "Stale pid file. Removing"
512 os.remove(confFile.get_opt('WPA.pidfile'))
513 if os.path.isfile(confFile.get_opt('WPA.pidfile')):
514 print "Stale pid file. Removing"
515 os.remove(confFile.get_opt('WPA.pidfile'))
516 # Lets clear out the wireless stuff
517 if __debug__:
518 print "Let's clear out the wireless stuff"
519 os.spawnlp(os.P_WAIT, 'iwconfig', confFile.get_opt('DEFAULT.iwconfig_command'), confFile.get_opt('DEFAULT.interface'), 'essid', 'off')
520 os.spawnlp(os.P_WAIT, 'iwconfig', confFile.get_opt('DEFAULT.iwconfig_command'), confFile.get_opt('DEFAULT.interface'), 'key', 'off')
521 os.spawnlp(os.P_WAIT, 'iwconfig', confFile.get_opt('DEFAULT.iwconfig_command'), confFile.get_opt('DEFAULT.interface'), 'mode', 'auto')
522 os.spawnlp(os.P_WAIT, 'iwconfig', confFile.get_opt('DEFAULT.iwconfig_command'), confFile.get_opt('DEFAULT.interface'), 'channel', 'auto')
523 os.spawnlp(os.P_WAIT, 'iwconfig', confFile.get_opt('DEFAULT.iwconfig_command'), confFile.get_opt('DEFAULT.interface'), 'ap', 'off')
524 # Now take the interface down
525 if __debug__:
526 print 'Now take the interface down'
527 os.spawnlp(os.P_WAIT, 'ifconfig', confFile.get_opt('DEFAULT.ifconfig_command'), confFile.get_opt('DEFAULT.interface'), 'down')
528 # Since it may be brought back up by the next scan, let's unset it's IP
529 if __debug__:
530 print 'Since it may be brought back up by the next scan, lets unset its IP'
531 os.spawnlp(os.P_WAIT, 'ifconfig', confFile.get_opt('DEFAULT.ifconfig_command'), confFile.get_opt('DEFAULT.interface'), '0.0.0.0')
532 # Let's run the disconnection postscript
533 dis_postscript = profile['dis_postscript']
534 if dis_postscript.strip() != '':
535 # got something to execute
536 if __debug__:
537 print "executing disconnection postscript:", dis_postscript
538 os.system(dis_postscript)
539 if __debug__:
540 print 'Disconnect complete.'
542 def get_profile_from_conf_file( essid, bssid ):
543 global config_options
544 # We got the essid, get the key
545 profile = {}
546 section_name = make_section_name( essid, bssid )
547 if not confFile.has_section( section_name ):
548 return None
549 profile['essid'] = essid
550 profile['bssid'] = bssid
551 profile['key'] = ''
552 profile['mode'] = ''
553 profile['security'] = ''
554 profile['con_prescript']= ''
555 profile['con_postscript']= ''
556 profile['dis_prescript']= ''
557 profile['dis_postscript']= ''
558 profile['channel'] = ''
559 profile['signal'] = '0'
560 profile['protocol'] = 'b'
562 #if confFile.has_option( section_name, "bssid" ):
563 #possible_bssid = confFile.get( section_name, "bssid" )
564 #if bssid == possible_bssid:
565 #profile['bssid'] = possible_bssid
566 #else:
567 #return None
569 if confFile.has_option( section_name, "key" ):
570 profile['key'] = confFile.get( section_name, "key" )
571 if confFile.has_option( section_name, "mode" ):
572 profile['mode'] = confFile.get( section_name, "mode" )
573 if confFile.has_option( section_name, "security" ):
574 profile['security'] = confFile.get( section_name, "security" )
575 if confFile.has_option( section_name, "con_prescript" ):
576 profile['con_prescript']= confFile.get( section_name, "con_prescript" )
577 if confFile.has_option( section_name, "con_postscript" ):
578 profile['con_postscript']= confFile.get( section_name, "con_postscript" )
579 if confFile.has_option( section_name, "dis_prescript" ):
580 profile['dis_prescript']= confFile.get( section_name, "dis_prescript" )
581 if confFile.has_option( section_name, "dis_postscript" ):
582 profile['dis_postscript']= confFile.get( section_name, "dis_postscript" )
583 if confFile.has_option( section_name, "channel" ):
584 profile['channel'] = confFile.get( section_name, "channel" )
585 # Now normal network
586 profile['use_wpa'] = False
587 if confFile.has_option( section_name, "use_wpa" ):
588 profile['use_wpa'] = confFile.getboolean( section_name, "use_wpa" )
589 profile['wpa_driver'] = ''
590 if confFile.has_option( section_name, "wpa_driver" ):
591 profile['wpa_driver'] = confFile.get( section_name, "wpa_driver" )
592 profile['use_dhcp'] = False
593 if confFile.has_option( section_name, "use_dhcp" ):
594 profile['use_dhcp'] = confFile.getboolean( section_name, "use_dhcp" )
595 profile['ip'] = ''
596 if confFile.has_option( section_name, "ip" ):
597 profile['ip'] = confFile.get( section_name, "ip" )
598 profile['netmask'] = ''
599 if confFile.has_option( section_name, "netmask" ):
600 profile['netmask'] = confFile.get( section_name, "netmask" )
601 profile['gateway'] = ''
602 if confFile.has_option( section_name, "gateway" ):
603 profile['gateway'] = confFile.get( section_name, "gateway" )
604 profile['domain'] = ''
605 if confFile.has_option( section_name, "domain" ):
606 profile['domain'] = confFile.get( section_name, "domain" )
607 profile['dns1'] = ''
608 if confFile.has_option( section_name, "dns1" ):
609 profile['dns1'] = confFile.get( section_name, "dns1" )
610 profile['dns2'] = ''
611 if confFile.has_option( section_name, "dns2" ):
612 profile['dns2'] = confFile.get( section_name, "dns2" )
613 return profile
615 def set_profile_to_conf_file( profile ):
616 section_name = make_section_name( profile['essid'], profile['bssid'] )
617 if not confFile.has_section( section_name ):
618 confFile.add_section( section_name )
619 #confFile.set( section_name, 'essid', profile['essid'] )
620 #confFile.set( section_name, 'bssid', profile['bssid'] )
621 confFile.set( section_name, 'key', profile['key'] )
622 confFile.set( section_name, 'security', profile['security'] )
623 confFile.set( section_name, 'con_prescript', profile['con_prescript'] )
624 confFile.set( section_name, 'con_postscript', profile['con_postscript'] )
625 confFile.set( section_name, 'dis_prescript', profile['dis_prescript'] )
626 confFile.set( section_name, 'dis_postscript', profile['dis_postscript'] )
627 confFile.set( section_name, 'mode', profile['mode'] )
628 confFile.set( section_name, 'channel', profile['channel'] )
629 # wpa
630 if profile['use_wpa']:
631 confFile.set( section_name, 'use_wpa', 'yes' )
632 confFile.set( section_name, 'wpa_driver', profile['wpa_driver'] )
633 else:
634 confFile.set( section_name, 'use_wpa', 'no' )
635 # dhcp
636 if profile['use_dhcp']:
637 confFile.set( section_name, 'use_dhcp', 'yes' )
638 try: confFile.remove_option( section_name, 'ip' )
639 except: pass
640 try: confFile.remove_option( section_name, 'netmask' )
641 except: pass
642 try: confFile.remove_option( section_name, 'gateway' )
643 except: pass
644 try: confFile.remove_option( section_name, 'domain' )
645 except: pass
646 try: confFile.remove_option( section_name, 'dns1' )
647 except: pass
648 try: confFile.remove_option( section_name, 'dns2' )
649 except: pass
650 else:
651 confFile.set( section_name, 'use_dhcp', 'no' )
652 confFile.set( section_name, 'ip', profile['ip'] )
653 confFile.set( section_name, 'netmask', profile['netmask'] )
654 confFile.set( section_name, 'gateway', profile['gateway'] )
655 confFile.set( section_name, 'domain', profile['domain'] )
656 confFile.set( section_name, 'dns1', profile['dns1'] )
657 confFile.set( section_name, 'dns2', profile['dns2'] )
658 confFile.write()
660 def make_section_name( essid, bssid ):
661 return essid + ':' + bssid
663 def split_section_name( section ):
664 parts = re.split(':', section)
665 return [ ':'.join(parts[0:len(parts)-6]), ':'.join(parts[len(parts)-6:len(parts)]) ]
667 def convert_confFile():
668 for apname in confFile.sections():
669 if confFile.has_option( apname, 'prescript' ):
670 confFile.set( apname, 'con_prescript', confFile.get( apname, 'prescript' ) )
671 confFile.remove_option( apname, 'prescript' )
672 if confFile.has_option( apname, 'postscript' ):
673 confFile.set( apname, 'con_postscript', confFile.get( apname, 'postscript' ) )
674 confFile.remove_option( apname, 'postscript' )
675 confFile.set( apname, 'dis_prescript', '' )
676 confFile.set( apname, 'dis_postscript', '' )
679 ##################
680 # The main window
681 class radar_window:
682 def __init__( self, confFile ):
683 # create the main window and connect the normal events
684 global signal_xpm_none
685 global signal_xpm_low
686 global signal_xpm_barely
687 global signal_xpm_ok
688 global signal_xpm_best
689 global known_profile_icon
690 global unknown_profile_icon
691 global wifi_radar_icon
692 self.signal_none_pb = gtk.gdk.pixbuf_new_from_xpm_data( signal_xpm_none )
693 self.known_profile_icon = gtk.gdk.pixbuf_new_from_inline( len( known_profile_icon[0] ), known_profile_icon[0], False )
694 self.unknown_profile_icon = gtk.gdk.pixbuf_new_from_inline( len( unknown_profile_icon[0] ), unknown_profile_icon[0], False )
695 self.signal_low_pb = gtk.gdk.pixbuf_new_from_xpm_data( signal_xpm_low )
696 self.signal_barely_pb = gtk.gdk.pixbuf_new_from_xpm_data( signal_xpm_barely )
697 self.signal_ok_pb = gtk.gdk.pixbuf_new_from_xpm_data( signal_xpm_ok )
698 self.signal_best_pb = gtk.gdk.pixbuf_new_from_xpm_data( signal_xpm_best )
699 self.window = gtk.Dialog('WiFi Radar', None, gtk.DIALOG_MODAL )
700 icon = gtk.gdk.pixbuf_new_from_inline( len( wifi_radar_icon[0] ), wifi_radar_icon[0], False )
701 self.window.set_icon( icon )
702 self.window.set_border_width( 10 )
703 self.window.set_size_request( 720, 300 )
704 self.window.set_title( "WiFi Radar" )
705 self.window.connect( 'delete_event', self.delete_event )
706 self.window.connect( 'destroy', self.destroy, )
707 # let's create all our widgets
708 self.current_network = gtk.Label()
709 self.current_network.show()
710 self.close_button = gtk.Button( "Close", gtk.STOCK_CLOSE )
711 self.close_button.show()
712 self.close_button.connect( 'clicked', self.delete_event, None )
713 self.preferences_button = gtk.Button( "Preferences", gtk.STOCK_PREFERENCES )
714 self.preferences_button.show()
715 self.preferences_button.connect( 'clicked', self.edit_preferences, None )
716 # essid bssid known_icon known available wep_icon signal_level mode protocol channel
717 self.pstore = gtk.ListStore( str, str, gtk.gdk.Pixbuf, int, int, str, gtk.gdk.Pixbuf, str, str, str )
718 self.rebuild_plist_items()
719 self.plist = gtk.TreeView( self.pstore )
720 # The essid column
721 self.pix_cell = gtk.CellRendererPixbuf()
722 self.wep_cell = gtk.CellRendererPixbuf()
723 self.essid_cell = gtk.CellRendererText()
724 self.bssid_cell = gtk.CellRendererText()
725 self.bssid_cell.set_property("width-chars", 20)
726 self.pcol = gtk.TreeViewColumn( "SSID" )
727 self.pcol.pack_start( self.pix_cell, False )
728 self.pcol.pack_start( self.wep_cell, False )
729 self.pcol.pack_start( self.essid_cell, True )
730 self.pcol.pack_start( self.bssid_cell, True )
731 self.pcol.add_attribute( self.wep_cell, 'stock-id', 5 )
732 self.pcol.add_attribute( self.pix_cell, 'pixbuf', 2 )
733 self.pcol.add_attribute( self.essid_cell, 'text', 0 )
734 self.pcol.add_attribute( self.bssid_cell, 'text', 1 )
735 self.plist.append_column( self.pcol )
736 # The signal column
737 self.sig_cell = gtk.CellRendererPixbuf()
738 self.scol = gtk.TreeViewColumn( "Signal" )
739 self.scol.pack_start( self.sig_cell, True )
740 self.scol.add_attribute( self.sig_cell, 'pixbuf', 6 )
741 self.plist.append_column( self.scol )
742 # The mode column
743 self.mode_cell = gtk.CellRendererText()
744 self.mcol = gtk.TreeViewColumn( "Mode" )
745 self.mcol.pack_start( self.mode_cell, True )
746 self.mcol.add_attribute( self.mode_cell, 'text', 7 )
747 self.plist.append_column( self.mcol )
748 # The protocol column
749 self.prot_cell = gtk.CellRendererText()
750 self.protcol = gtk.TreeViewColumn( "802.11" )
751 self.protcol.pack_start( self.prot_cell, True )
752 self.protcol.add_attribute( self.prot_cell, 'text', 8 )
753 self.plist.append_column( self.protcol )
754 # The channel column
755 self.channel_cell = gtk.CellRendererText()
756 self.channel = gtk.TreeViewColumn( "Channel" )
757 self.channel.pack_start( self.channel_cell, True )
758 self.channel.add_attribute( self.channel_cell, 'text', 9 )
759 self.plist.append_column( self.channel )
760 # DnD Ordering
761 self.plist.set_reorderable( True )
762 self.pstore.connect( 'row-changed', self.update_auto_profile_order )
763 # enable/disable buttons based on the selected network
764 self.selected_network = self.plist.get_selection()
765 self.selected_network.connect( 'changed', self.on_network_selection, None )
766 # the list scroll bar
767 sb = gtk.VScrollbar( self.plist.get_vadjustment() )
768 sb.show()
769 self.plist.show()
771 self.new_button = gtk.Button( "_New" )
772 self.new_button.connect( 'clicked', self.create_new_profile, None )
773 self.new_button.show()
775 self.edit_button = gtk.Button( "C_onfigure" )
776 self.edit_button.connect( 'clicked', self.edit_profile, None )
777 self.edit_button.show()
779 self.delete_button = gtk.Button( "_Delete" )
780 self.delete_button.connect( 'clicked', self.delete_profile, None )
781 self.delete_button.show()
783 self.connect_button = gtk.Button( "Co_nnect" )
784 self.connect_button.connect( 'clicked', self.connect_profile, None )
786 self.disconnect_button = gtk.Button( "D_isconnect" )
787 self.disconnect_button.connect( 'clicked', self.disconnect_profile, None )
788 # lets add our widgets
789 rows = gtk.VBox( False, 3 )
790 net_list = gtk.HBox( False, 0 )
791 listcols = gtk.HBox( False, 0 )
792 prows = gtk.VBox( False, 0 )
793 # lets start packing
794 # the network list
795 net_list.pack_start( self.plist, True, True, 0 )
796 net_list.pack_start( sb, False, False, 0 )
797 # the rows level
798 rows.pack_start( net_list , True, True, 0 )
799 rows.pack_start( self.current_network, False, True, 0 )
800 # the list columns
801 listcols.pack_start( rows, True, True, 0 )
802 listcols.pack_start( prows, False, False, 5 )
803 # the list buttons
804 prows.pack_start( self.new_button, False, False, 2 )
805 prows.pack_start( self.edit_button, False, False, 2 )
806 prows.pack_start( self.delete_button, False, False, 2 )
807 prows.pack_end( self.connect_button, False, False, 2 )
808 prows.pack_end( self.disconnect_button, False, False, 2 )
810 self.window.action_area.pack_start( self.preferences_button )
811 self.window.action_area.pack_start( self.close_button )
813 rows.show()
814 prows.show()
815 listcols.show()
816 self.window.vbox.add( listcols )
817 self.window.vbox.set_spacing( 3 )
818 self.window.show_all()
820 # Now, immediately hide these two. The proper one will be
821 # displayed later, based on interface state. -BEF-
822 self.disconnect_button.hide()
823 self.connect_button.hide()
825 def main( self ):
826 gtk.main()
828 def destroy( self, widget = None):
829 global lock
830 lock.acquire()
831 confFile.write()
832 gtk.main_quit()
833 lock.release()
835 def delete_event( self, widget, event, data=None ):
836 # Save the preferred networks order
837 global exit_flag
838 exit_flag = True
839 self.update_auto_profile_order()
840 self.destroy()
841 return False
843 def rebuild_plist_items( self ):
844 # Add our known profiles in order
845 global lock
846 if (None != lock):
847 lock.acquire()
849 #print "rebuild_plist_items (1): ", confFile.auto_profile_order
850 for ap in confFile.auto_profile_order:
851 ap = ap.strip()
852 if access_points.has_key( ap ) and access_points[ ap ]['known']:
853 wep = None
854 if access_points[ ap ]['encrypted']: wep = gtk.STOCK_DIALOG_AUTHENTICATION
855 # 1 here means that we know this ap -----------------------------------------------------------------------v
856 self.pstore.append( [ access_points[ ap ]['essid'], access_points[ ap ]['bssid'], self.known_profile_icon, 1, 0, wep, self.signal_none_pb, access_points[ ap ]['mode'], access_points[ ap ]['protocol'], access_points[ ap ]['channel'] ] )
857 # Now add any known profiles not in the profile order
858 for ap in access_points:
859 #print "rebuild_plist_items (2): ", ap, ":", confFile.auto_profile_order
860 if ap in confFile.auto_profile_order: continue
861 wep = None
862 if access_points[ ap ]['encrypted']: wep = gtk.STOCK_DIALOG_AUTHENTICATION
863 # 1 here means that we know this ap -------------------------------------------------------------------------v
864 self.pstore.append( [ access_points[ ap ]['essid'], access_points[ ap ]['bssid'], self.unknown_profile_icon, 0, 0, wep, self.signal_none_pb, access_points[ ap ]['mode'], access_points[ ap ]['protocol'], access_points[ ap ]['channel'] ] )
865 if (None != lock):
866 lock.release()
868 def update_plist_items( self ):
869 """Updates the profiles list"""
870 global lock
871 #if __debug__:
872 # print "updating profile list"
873 gtk.gdk.threads_enter()
875 lock.acquire()
877 # update the current ip and essid
878 self.current_network.set_text( "Connected to %s ip(%s)" % ( get_current_essid(), get_current_ip() ) )
879 if get_current_ip():
880 self.connect_button.hide()
881 self.disconnect_button.show()
882 else:
883 self.disconnect_button.hide()
884 self.connect_button.show()
886 for ap in access_points:
887 wep = None
888 if access_points[ ap ]['encrypted']: wep = gtk.STOCK_DIALOG_AUTHENTICATION
889 prow = self.get_row_by_ap( access_points[ ap ][ 'essid' ], access_points[ ap ][ 'bssid' ] )
890 if prow:
891 #if __debug__:
892 # print "Setting prow", ap, access_points[ ap ]
893 #profile = get_profile_from_conf_file( access_points[ ap ][ 'essid' ], access_points[ ap ][ 'bssid' ] )
894 #if profile:
895 prow[1] = access_points[ ap ][ 'bssid' ]
896 prow[5] = wep
897 prow[6] = self.pixbuf_from_signal( access_points[ ap ][ 'signal' ] )
898 prow[7] = access_points[ ap ][ 'mode' ]
899 prow[8] = access_points[ ap ][ 'protocol' ]
900 prow[9] = access_points[ ap ]['channel']
901 #for val in prow:
902 # print val
903 else:
904 #if __debug__:
905 # print "New profile", ap, access_points[ ap ]
906 # 1 here means that we know this ap ---------------------------------------------------------------------------v
907 self.pstore.append( [ access_points[ ap ][ 'essid' ], access_points[ ap ]['bssid'], self.unknown_profile_icon, 0, 0, wep, self.pixbuf_from_signal( access_points[ ap ]['signal'] ), access_points[ ap ]['mode'], access_points[ ap ]['protocol'], access_points[ ap ]['channel'] ] )
908 # give the list a chance to update
909 #while gtk.events_pending():
910 # gtk.main_iteration()
912 lock.release()
914 gtk.gdk.threads_leave()
915 return True
917 def pixbuf_from_signal( self, signal ):
918 signal = int( signal )
919 #print signal
920 if signal >= 80 or signal == 0:
921 return self.signal_none_pb
922 elif signal >= 78:
923 return self.signal_low_pb
924 elif signal >= 75:
925 return self.signal_barely_pb
926 elif signal >= 60:
927 return self.signal_ok_pb
928 elif signal < 60:
929 return self.signal_best_pb
930 else:
931 return None
933 def get_row_by_ap( self, essid, bssid ):
934 for row in self.pstore:
935 if ( (row[0] == essid) and (row[1] == bssid) ):
936 #print row
937 return row
938 return None
940 # enable/disable buttons based on the selected network
941 def on_network_selection( self, widget, data=None ):
942 ( store, selected_iter ) = self.selected_network.get_selected()
944 # if no networks are selected, disable all buttons except New
945 # (this occurs after a drag-and-drop)
946 if selected_iter==None:
947 self.new_button.set_sensitive(True)
948 self.edit_button.set_sensitive(False)
949 self.delete_button.set_sensitive(False)
950 return
952 # determine if the selected network is configured
953 is_configured = (store.get_value(selected_iter, 2) == 1)
955 # enable/disable buttons
956 if is_configured:
957 self.new_button.set_sensitive(False)
958 self.edit_button.set_sensitive(True)
959 self.delete_button.set_sensitive(True)
960 else:
961 self.new_button.set_sensitive(True)
962 self.edit_button.set_sensitive(True)
963 self.delete_button.set_sensitive(False)
967 # init and run the preferences dialog
968 def edit_preferences( self, widget, data=None ):
969 p = preferences_dialog( self )
970 ok = p.run()
971 p.destroy()
973 def create_new_profile( self, widget, data=None ):
974 global lock
975 p = profile_dialog( self )
976 while True:
977 ok = p.run()
978 if ok:
979 profile = p.get_profile()
980 # Check that the ap does not exist already
981 apname = make_section_name( profile['essid'], profile['bssid'] )
982 if apname in access_points:
983 dlg = gtk.MessageDialog(
984 self.window,
985 gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_MODAL,
986 gtk.MESSAGE_ERROR,
987 gtk.BUTTONS_OK,
988 "A profile for %s already exists" % (apname) )
989 dlg.run()
990 dlg.destroy()
991 del dlg
992 # try again
993 continue
994 set_profile_to_conf_file( profile )
995 # And let's add it up
996 ap = {}
997 ap['known'] = True
998 ap['available'] = False
999 ap['encrypted'] = False
1000 ap['essid'] = ''
1001 ap['bssid'] = ''
1002 ap['mode'] = ''
1003 ap['security'] = ''
1004 ap['con_prescript'] = ''
1005 ap['con_postscript'] = ''
1006 ap['dis_prescript'] = ''
1007 ap['dis_postscript'] = ''
1008 ap['channel'] = ''
1009 ap['protocol'] = 'b'
1010 ap['signal'] = '0'
1011 if confFile.has_option( apname, 'key'):
1012 if len( confFile.get( apname, 'key' ) ) > 0:
1013 ap['encrypted'] = True
1015 lock.acquire()
1017 access_points[ apname ] = ap
1018 # if it is not in the auto_profile_order add it
1019 #print "create_new_profile: ", apname, ":", confFile.auto_profile_order
1020 if not apname in confFile.auto_profile_order:
1021 confFile.auto_profile_order.append(apname)
1022 lock.release()
1023 # add to the store
1024 wep = None
1025 if ap['encrypted']: wep = gtk.STOCK_DIALOG_AUTHENTICATION
1026 self.pstore.append( [ profile['essid'], profile['bssid'], self.known_profile_icon, 1, 0, wep, self.pixbuf_from_signal( ap['signal'] ), ap['mode'], ap['protocol'] ] )
1027 break
1028 p.destroy()
1030 def edit_profile( self, widget, data=None ):
1031 ( store, selected_iter ) = self.plist.get_selection().get_selected()
1032 if not selected_iter: return
1033 essid = store.get_value( selected_iter, 0 )
1034 bssid = store.get_value( selected_iter, 1 )
1035 known = store.get_value( selected_iter, 3 )
1036 if not known:
1037 self.connect_profile(widget, 'noconnect')
1038 return
1039 profile = get_profile_from_conf_file( essid, bssid )
1040 p = profile_dialog( self )
1041 p.set_profile( profile, True )
1042 ok = p.run()
1043 if ok:
1044 profile = p.get_profile()
1045 if __debug__:
1046 print "Got edited profile ", profile
1047 set_profile_to_conf_file( profile )
1048 p.destroy()
1050 def delete_profile( self, widget, data=None ):
1051 ( store, selected_iter ) = self.plist.get_selection().get_selected()
1052 if not selected_iter: return
1053 essid = store.get_value( selected_iter, 0 )
1054 bssid = store.get_value( selected_iter, 1 )
1055 known = store.get_value( selected_iter, 3 )
1056 if not known: return
1057 dlg = gtk.MessageDialog(
1058 self.window,
1059 gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_MODAL,
1060 gtk.MESSAGE_QUESTION,
1061 gtk.BUTTONS_YES_NO,
1062 "Are you sure you want to delete the %s (%s) profile?" % (essid, bssid) )
1063 res = dlg.run()
1064 dlg.destroy()
1065 del dlg
1066 if res == gtk.RESPONSE_NO: return
1067 # Remove it
1068 apname = make_section_name( essid, bssid )
1069 confFile.remove_section( apname )
1070 #print "delete_profile: ", apname, ":", confFile.auto_profile_order
1071 if apname in confFile.auto_profile_order: confFile.auto_profile_order.remove(apname)
1072 if access_points.has_key( apname ): access_points.pop( apname )
1073 self.pstore.remove( selected_iter )
1074 # Let's save our current state
1075 self.update_auto_profile_order()
1077 def connect_profile( self, widget, data=None ):
1078 ( store, selected_iter ) = self.plist.get_selection().get_selected()
1079 if not selected_iter: return
1080 essid = store.get_value( selected_iter, 0 )
1081 bssid = store.get_value( selected_iter, 1 )
1082 known = store.get_value( selected_iter, 3 )
1083 if not known:
1084 if data != 'noconnect':
1085 dlg = gtk.MessageDialog(
1086 self.window,
1087 gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_MODAL,
1088 gtk.MESSAGE_QUESTION,
1089 gtk.BUTTONS_YES_NO,
1090 "This network does not have a profile configured.\n\nWould you like to create one now?" )
1091 res = dlg.run()
1092 dlg.destroy()
1093 del dlg
1094 if res == gtk.RESPONSE_NO: return
1095 p = profile_dialog( self )
1096 # get a blank profile from the dialog
1097 profile = p.get_profile()
1098 profile['essid'] = essid
1099 profile['bssid'] = bssid
1100 p.set_profile( profile, True )
1101 ok = p.run()
1102 if ok:
1103 profile = p.get_profile()
1104 set_profile_to_conf_file( profile )
1105 # change the icon
1106 self.pstore.set_value( selected_iter, 2, self.known_profile_icon )
1107 # make it known
1108 self.pstore.set_value( selected_iter, 3, 1 )
1109 # if it is not in the auto_profile_order add it
1110 apname = make_section_name( essid, bssid )
1111 #print "connect_profile: ", apname, ":", confFile.auto_profile_order
1112 if not apname in confFile.auto_profile_order:
1113 confFile.auto_profile_order.append( apname )
1114 self.update_auto_profile_order()
1115 p.destroy()
1116 else:
1117 p.destroy()
1118 return
1119 if data != 'noconnect':
1120 connect_status_window = status_window( self )
1121 connect_status_window.run()
1122 connect_to_network( essid, bssid, connect_status_window )
1123 connect_status_window.destroy()
1125 def disconnect_profile( self, widget, data=None ):
1126 disconnect_interface()
1128 def update_auto_profile_order( self, widget = None, data = None, data2 = None ):
1129 # recreate the auto_profile_order
1130 auto_profile_order = []
1131 piter = self.pstore.get_iter_first()
1132 while piter:
1133 # only if it's known
1134 if self.pstore.get_value( piter, 3 ) == 1:
1135 auto_profile_order.append( make_section_name( self.pstore.get_value( piter, 0 ), self.pstore.get_value( piter, 1 ) ) )
1136 piter = self.pstore.iter_next( piter )
1137 confFile.auto_profile_order = auto_profile_order
1139 ###################################
1140 # the preferences dialog
1141 class preferences_dialog:
1142 def __init__( self, parent ):
1143 # set up the preferences window
1144 global wifi_radar_icon
1145 self.parent = parent
1146 self.dialog = gtk.Dialog('WiFi Radar Preferences', self.parent.window,
1147 gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
1148 ( gtk.STOCK_CLOSE, True ) )
1149 icon = gtk.gdk.pixbuf_new_from_inline( len( wifi_radar_icon[0] ), wifi_radar_icon[0], False )
1150 self.dialog.set_icon( icon )
1151 self.dialog.set_resizable( True )
1152 self.dialog.set_transient_for( self.parent.window )
1153 self.tooltips = gtk.Tooltips()
1156 # set up preferences widgets
1159 # auto detect wireless device
1160 self.w_auto_detect = gtk.CheckButton("Auto-detect wireless device")
1161 self.w_auto_detect.set_active(confFile.get_opt('DEFAULT.interface') == "auto_detect")
1162 self.w_auto_detect.connect("toggled", self.toggle_auto_detect)
1163 self.tooltips.set_tip(self.w_auto_detect, "Automatically select wireless device to configure")
1164 self.dialog.vbox.pack_start(self.w_auto_detect, False, False, 5)
1165 # network interface selecter
1166 self.w_interface = gtk.combo_box_entry_new_text()
1167 iwconfig_info = os.popen(confFile.get_opt('DEFAULT.iwconfig_command') + " 2>&1", 'r')
1168 wireless_devices = [ (x[0:x.find(" ")]) for x in iwconfig_info if("ESSID" in x)]
1169 for device in wireless_devices:
1170 if device != confFile.get_opt('DEFAULT.interface'):
1171 self.w_interface.append_text(device)
1172 self.w_interface.prepend_text(confFile.get_opt('DEFAULT.interface'))
1173 self.w_interface.set_active(0)
1174 self.w_interface_label = gtk.Label("Wireless device")
1175 self.w_hbox1 = gtk.HBox(False, 0)
1176 self.w_hbox1.pack_start(self.w_interface_label, False, False, 5)
1177 self.w_hbox1.pack_start(self.w_interface, True, True, 0)
1178 self.w_interface.set_sensitive(confFile.get_opt('DEFAULT.interface') != "auto_detect")
1179 self.dialog.vbox.pack_start(self.w_hbox1, False, False, 5)
1180 # scan timeout (spin button of integers from 1 to 100)
1181 self.time_in_seconds = gtk.Adjustment(confFile.get_opt_as_int('DEFAULT.scan_timeout'),1,100,1,1,1)
1182 self.w_scan_timeout = gtk.SpinButton(self.time_in_seconds, 1, 0)
1183 self.w_scan_timeout.set_update_policy(gtk.UPDATE_IF_VALID)
1184 self.w_scan_timeout.set_numeric(True)
1185 self.w_scan_timeout.set_snap_to_ticks(True)
1186 self.w_scan_timeout.set_wrap(False)
1187 self.tooltips.set_tip(self.w_scan_timeout, "How long should WiFi Radar scan for access points?")
1188 self.w_scan_timeout_label = gtk.Label("Scan timeout (seconds)")
1189 self.w_hbox2 = gtk.HBox(False, 0)
1190 self.w_hbox2.pack_start(self.w_scan_timeout_label, False, False, 5)
1191 self.w_hbox2.pack_start(self.w_scan_timeout, True, True, 0)
1192 self.dialog.vbox.pack_start(self.w_hbox2, False, False, 5)
1193 # speak up
1194 self.w_speak_up = gtk.CheckButton("Use speak-up")
1195 self.w_speak_up.set_active(confFile.get_opt_as_bool('DEFAULT.speak_up'))
1196 self.tooltips.set_tip(self.w_speak_up, "Should I speak up when connecting to a network? (If you have a speech command)")
1197 self.dialog.vbox.pack_start(self.w_speak_up, False, False, 5)
1198 # commit required
1199 self.w_commit_required = gtk.CheckButton("Commit required")
1200 self.w_commit_required.set_active(confFile.get_opt_as_bool('DEFAULT.commit_required'))
1201 self.tooltips.set_tip(self.w_commit_required, "Check this box if your card requires a \"commit\" command with iwconfig")
1202 self.dialog.vbox.pack_start(self.w_commit_required, False, False, 5)
1203 # ifup required
1204 self.w_ifup_required = gtk.CheckButton("Ifup required")
1205 self.w_ifup_required.set_active(confFile.get_opt_as_bool('DEFAULT.ifup_required'))
1206 self.tooltips.set_tip(self.w_ifup_required, "Check this box if your system requires the interface to be brought up first")
1208 self.dialog.vbox.pack_start(self.w_ifup_required, False, False, 5)
1210 def toggle_auto_detect(self, auto_detect_toggle, data=None):
1211 self.w_interface.set_sensitive(not auto_detect_toggle.get_active())
1213 def run(self):
1214 self.dialog.show_all()
1215 return self.dialog.run()
1217 def destroy(self):
1218 # save preferences to config file
1219 if self.w_auto_detect.get_active():
1220 set_network_device("auto_detect")
1221 confFile.set_opt('DEFAULT.interface', "auto_detect")
1222 else:
1223 set_network_device(self.w_interface.child.get_text())
1224 confFile.set_opt('DEFAULT.interface', self.w_interface.child.get_text())
1225 # reconfigure the dhcp commands in case the network device was changed
1226 confFile.set_float_opt('DEFAULT.scan_timeout', self.w_scan_timeout.get_value())
1227 confFile.set_bool_opt('DEFAULT.speak_up', self.w_speak_up.get_active())
1228 confFile.set_bool_opt('DEFAULT.commit_required', self.w_commit_required.get_active())
1229 confFile.set_bool_opt('DEFAULT.ifup_required', self.w_ifup_required.get_active())
1230 if confFile.get_opt_as_bool('DEFAULT.ifup_required'):
1231 os.spawnlp(os.P_WAIT, 'ifconfig', confFile.get_opt('DEFAULT.ifconfig_command'), confFile.get_opt('DEFAULT.interface'), "up")
1232 confFile.write()
1233 self.dialog.destroy()
1234 del self.dialog
1237 ###################################
1238 class profile_dialog:
1239 def __init__( self, parent ):
1240 global wifi_radar_icon
1241 self.parent = parent
1242 self.dialog = gtk.Dialog('WiFi Profile', self.parent.window,
1243 gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
1244 ( gtk.STOCK_CANCEL, False, gtk.STOCK_SAVE, True ) )
1245 icon = gtk.gdk.pixbuf_new_from_inline( len( wifi_radar_icon[0] ), wifi_radar_icon[0], False )
1246 self.dialog.set_icon( icon )
1247 self.dialog.set_resizable( False )
1248 self.dialog.set_transient_for( self.parent.window )
1249 #self.dialog.set_size_request( 400, 400 )
1250 #################
1251 essid_table = gtk.Table( 1, 2, False )
1252 essid_table.set_row_spacings( 3 )
1253 essid_table.set_col_spacings( 3 )
1255 # The essid labels
1256 l = gtk.Label( 'Network Name' )
1257 essid_table.attach( l, 0, 1, 0, 1 )
1258 # The essid textboxes
1259 self.essid = gtk.Entry( 32 )
1260 self.essid.set_text('essid')
1261 essid_table.attach( self.essid, 1, 2, 0, 1 )
1262 #self.key = gtk.Entry( 32 )
1263 #essid_table.attach( self.key, 1, 2, 1, 2 )
1264 # Add the essid table to the dialog
1265 self.dialog.vbox.pack_start( essid_table, True, True, 5 )
1267 bssid_table = gtk.Table( 1, 2, False )
1268 bssid_table.set_row_spacings( 3 )
1269 bssid_table.set_col_spacings( 3 )
1270 # The bssid labels
1271 l = gtk.Label( 'Network bssid' )
1272 bssid_table.attach( l, 0, 1, 0, 1 )
1273 # The bssid textboxes
1274 self.bssid = gtk.Entry( 32 )
1275 self.bssid.set_text('')
1276 bssid_table.attach( self.bssid, 1, 2, 0, 1 )
1277 #self.key = gtk.Entry( 32 )
1278 #bssid_table.attach( self.key, 1, 2, 1, 2 )
1279 # Add the bssid table to the dialog
1280 self.dialog.vbox.pack_start( bssid_table, True, True, 5 )
1282 # create the wifi expander
1283 self.wifi_expander = gtk.Expander( WIFI_SET_LABEL )
1284 #self.wifi_expander.connect( 'notify::expanded', self.toggle_use_dhcp )
1285 wifi_table = gtk.Table( 4, 2, False )
1286 wifi_table.set_row_spacings( 3 )
1287 wifi_table.set_col_spacings( 3 )
1288 # The Wifi labels
1289 l = gtk.Label( 'Mode' )
1290 wifi_table.attach( l, 0, 1, 0, 1 )
1291 l = gtk.Label( 'Channel' )
1292 wifi_table.attach( l, 0, 1, 1, 2 )
1293 l = gtk.Label( 'Key' )
1294 wifi_table.attach( l, 0, 1, 2, 3 )
1295 l = gtk.Label( 'Security' )
1296 wifi_table.attach( l, 0, 1, 3, 4 )
1297 # The Wifi text boxes
1298 self.mode = gtk.combo_box_new_text()
1299 for mode in WIFI_MODES:
1300 self.mode.append_text( mode )
1301 self.mode.set_active( 0 )
1302 wifi_table.attach( self.mode, 1, 2, 0, 1 )
1303 self.channel = gtk.combo_box_new_text()
1304 for channel in WIFI_CHANNELS:
1305 self.channel.append_text( channel )
1306 self.channel.set_active( 0 )
1307 wifi_table.attach( self.channel, 1, 2, 1, 2 )
1308 self.key = gtk.Entry( 32 )
1309 #self.key.set_text('0.0.0.0')
1310 wifi_table.attach( self.key, 1, 2, 2, 3 )
1311 self.security = gtk.combo_box_new_text()
1312 for security in WIFI_SECURITY:
1313 self.security.append_text( security )
1314 self.security.set_active( 0 )
1315 wifi_table.attach( self.security, 1, 2, 3, 4 )
1316 # Add the wifi table to the expander
1317 self.wifi_expander.add( wifi_table )
1318 # Add the expander to the dialog
1319 self.dialog.vbox.pack_start( self.wifi_expander, False, False, 5 )
1321 # create the wpa expander
1322 self.wpa_expander = gtk.Expander( NO_WPA_LABEL )
1323 self.wpa_expander.connect( 'notify::expanded', self.toggle_use_wpa )
1324 wpa_table = gtk.Table( 1, 2, False )
1325 wpa_table.set_row_spacings( 3 )
1326 wpa_table.set_col_spacings( 3 )
1327 # The labels
1328 l = gtk.Label( 'Driver' )
1329 wpa_table.attach( l, 0, 1, 0, 1 )
1330 # The text boxes
1331 self.wpa_driver = gtk.Entry()
1332 wpa_table.attach( self.wpa_driver, 1, 2, 0, 1 )
1333 # Add the wpa table to the expander
1334 self.wpa_expander.add( wpa_table )
1335 # Add the expander to the dialog
1336 self.dialog.vbox.pack_start( self.wpa_expander, False, False, 5 )
1338 # create the dhcp expander
1339 self.dhcp_expander = gtk.Expander( USE_DHCP_LABEL )
1340 self.dhcp_expander.connect( 'notify::expanded', self.toggle_use_dhcp )
1341 ip_table = gtk.Table( 6, 2, False )
1342 ip_table.set_row_spacings( 3 )
1343 ip_table.set_col_spacings( 3 )
1344 # The IP labels
1345 l = gtk.Label( 'IP' )
1346 ip_table.attach( l, 0, 1, 0, 1 )
1347 l = gtk.Label( 'Netmask' )
1348 ip_table.attach( l, 0, 1, 1, 2 )
1349 l = gtk.Label( 'Gateway' )
1350 ip_table.attach( l, 0, 1, 2, 3 )
1351 l = gtk.Label( 'Domain' )
1352 ip_table.attach( l, 0, 1, 3, 4 )
1353 l = gtk.Label( 'DNS' )
1354 ip_table.attach( l, 0, 1, 4, 5 )
1355 l = gtk.Label( 'DNS' )
1356 ip_table.attach( l, 0, 1, 5, 6 )
1357 # The IP text boxes
1358 self.ip = gtk.Entry( 15 )
1359 self.ip.set_text('0.0.0.0')
1360 ip_table.attach( self.ip, 1, 2, 0, 1 )
1361 self.netmask = gtk.Entry( 15 )
1362 self.netmask.set_text('255.255.255.0')
1363 ip_table.attach( self.netmask, 1, 2, 1, 2 )
1364 self.gw = gtk.Entry( 15 )
1365 self.gw.set_text('0.0.0.0')
1366 ip_table.attach( self.gw, 1, 2, 2, 3 )
1367 self.domain = gtk.Entry( 32 )
1368 self.domain.set_text('domain.com')
1369 ip_table.attach( self.domain, 1, 2, 3, 4 )
1370 self.dns1 = gtk.Entry( 15 )
1371 self.dns1.set_text('0.0.0.0')
1372 ip_table.attach( self.dns1, 1, 2, 4, 5 )
1373 self.dns2 = gtk.Entry( 15 )
1374 self.dns2.set_text('0.0.0.0')
1375 ip_table.attach( self.dns2, 1, 2, 5, 6 )
1376 # Add the ip table to the expander
1377 self.dhcp_expander.add( ip_table )
1378 # Add the expander to the dialog
1379 self.dialog.vbox.pack_start( self.dhcp_expander, False, False, 5 )
1381 # create the connection-building postpre expander
1382 self.con_pp_expander = gtk.Expander( CON_PP_LABEL )
1383 con_pp_table = gtk.Table( 2, 2, False )
1384 con_pp_table.set_row_spacings( 3 )
1385 con_pp_table.set_col_spacings( 3 )
1386 # The labels
1387 l = gtk.Label( 'Before' )
1388 con_pp_table.attach( l, 0, 1, 0, 1 )
1389 l = gtk.Label( 'After' )
1390 con_pp_table.attach( l, 0, 1, 1, 2 )
1391 # The text boxes
1392 self.con_prescript = gtk.Entry()
1393 con_pp_table.attach( self.con_prescript, 1, 2, 0, 1 )
1394 self.con_postscript = gtk.Entry()
1395 con_pp_table.attach( self.con_postscript, 1, 2, 1, 2 )
1396 # Add the pp table to the expander
1397 self.con_pp_expander.add( con_pp_table )
1398 # Add the expander to the dialog
1399 self.dialog.vbox.pack_start( self.con_pp_expander, False, False, 5 )
1401 # create the disconnection postpre expander
1402 self.dis_pp_expander = gtk.Expander( DIS_PP_LABEL )
1403 dis_pp_table = gtk.Table( 2, 2, False )
1404 dis_pp_table.set_row_spacings( 3 )
1405 dis_pp_table.set_col_spacings( 3 )
1406 # The labels
1407 l = gtk.Label( 'Before' )
1408 dis_pp_table.attach( l, 0, 1, 0, 1 )
1409 l = gtk.Label( 'After' )
1410 dis_pp_table.attach( l, 0, 1, 1, 2 )
1411 # The text boxes
1412 self.dis_prescript = gtk.Entry()
1413 dis_pp_table.attach( self.dis_prescript, 1, 2, 0, 1 )
1414 self.dis_postscript = gtk.Entry()
1415 dis_pp_table.attach( self.dis_postscript, 1, 2, 1, 2 )
1416 # Add the pp table to the expander
1417 self.dis_pp_expander.add( dis_pp_table )
1418 # Add the expander to the dialog
1419 self.dialog.vbox.pack_start( self.dis_pp_expander, False, False, 5 )
1421 def run( self ):
1422 self.dialog.show_all()
1423 return self.dialog.run()
1425 def destroy( self ):
1426 self.dialog.destroy()
1427 del self.dialog
1429 def toggle_use_dhcp( self, widget, data = None ):
1430 expanded = self.dhcp_expander.get_expanded()
1431 if expanded:
1432 self.dhcp_expander.set_label( USE_IP_LABEL )
1433 else:
1434 self.dhcp_expander.set_label( USE_DHCP_LABEL )
1436 def toggle_use_wpa( self, widget, data = None ):
1437 expanded = self.wpa_expander.get_expanded()
1438 if expanded:
1439 self.wpa_expander.set_label( USE_WPA_LABEL )
1440 else:
1441 self.wpa_expander.set_label( NO_WPA_LABEL )
1443 def get_profile( self ):
1444 profile = {}
1445 profile['essid'] = self.essid.get_text().strip()
1446 profile['bssid'] = self.bssid.get_text().strip()
1447 profile['key'] = self.key.get_text().strip()
1448 profile['mode'] = self.get_array_item( self.mode.get_active(), WIFI_MODES )
1449 profile['security'] = self.get_array_item( self.security.get_active(), WIFI_SECURITY )
1450 profile['channel'] = self.get_array_item( self.channel.get_active(), WIFI_CHANNELS )
1451 profile['protocol'] = 'b'
1452 profile['signal'] = '0'
1453 profile['con_prescript'] = self.con_prescript.get_text().strip()
1454 profile['con_postscript'] = self.con_postscript.get_text().strip()
1455 profile['dis_prescript'] = self.dis_prescript.get_text().strip()
1456 profile['dis_postscript'] = self.dis_postscript.get_text().strip()
1457 # wpa
1458 use_wpa = ( self.wpa_expander.get_expanded() == False )
1459 if use_wpa:
1460 profile['use_wpa'] = False
1461 else:
1462 profile['use_wpa'] = True
1463 profile['wpa_driver']= self.wpa_driver.get_text().strip()
1464 # dhcp
1465 use_dhcp = ( self.dhcp_expander.get_expanded() == False )
1466 if use_dhcp:
1467 profile['use_dhcp'] = True
1468 else:
1469 profile['use_dhcp'] = False
1470 profile['ip'] = self.ip.get_text().strip()
1471 profile['netmask'] = self.netmask.get_text().strip()
1472 profile['gateway'] = self.gw.get_text().strip()
1473 profile['domain'] = self.domain.get_text().strip()
1474 profile['dns1'] = self.dns1.get_text().strip()
1475 profile['dns2'] = self.dns2.get_text().strip()
1476 return profile
1478 def set_profile( self, profile, known ):
1479 if __debug__:
1480 print "set profile: ", profile
1481 self.essid.set_text( profile['essid'] )
1482 if known:
1483 self.essid.set_editable( False )
1484 self.dialog.set_title( "WiFi Profile for %s" % profile['essid'] )
1485 self.bssid.set_text( profile['bssid'] )
1486 self.bssid.set_editable( False )
1487 self.key.set_text( profile['key'] )
1488 self.mode.set_active( self.get_array_index( profile['mode'], WIFI_MODES ) )
1489 self.channel.set_active( self.get_array_index( profile['channel'], WIFI_CHANNELS ) )
1490 self.security.set_active( self.get_array_index( profile['security'], WIFI_SECURITY ) )
1491 #self.protocol.set_text( profile['protocol'] )
1492 self.con_prescript.set_text( profile['con_prescript'] )
1493 self.con_postscript.set_text( profile['con_postscript'] )
1494 self.dis_prescript.set_text( profile['dis_prescript'] )
1495 self.dis_postscript.set_text( profile['dis_postscript'] )
1496 # wpa
1497 if profile['use_wpa'] == True:
1498 self.wpa_expander.set_expanded( True )
1499 self.wpa_driver.set_text( profile['wpa_driver'] )
1500 else:
1501 self.wpa_expander.set_expanded( False )
1502 # dhcp
1503 if profile['use_dhcp'] == True:
1504 self.dhcp_expander.set_expanded( False)
1505 else:
1506 self.dhcp_expander.set_expanded( True )
1507 self.ip.set_text( profile['ip'] )
1508 self.netmask.set_text( profile['netmask'] )
1509 self.gw.set_text( profile['gateway'] )
1510 self.domain.set_text( profile['domain'] )
1511 self.dns1.set_text( profile['dns1'] )
1512 self.dns2.set_text( profile['dns2'] )
1514 def get_array_index( self, item, array ):
1515 try:
1516 return array.index( item.strip() )
1517 except:
1518 pass
1519 return 0
1521 def get_array_item( self, index, array ):
1522 try:
1523 return array[ index ]
1524 except:
1525 pass
1526 return ''
1528 ### status_window
1530 ### A simple class for putting up a "Please wait" dialog so the user
1531 ### doesn't think we've forgotten about them.
1532 class status_window:
1533 def __init__( self, parent ):
1534 global wifi_radar_icon
1535 self.parent = parent
1536 self.dialog = gtk.Dialog("Working", self.parent.window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT)
1537 icon = gtk.gdk.pixbuf_new_from_inline( len( wifi_radar_icon[0] ), wifi_radar_icon[0], False )
1538 self.dialog.set_icon( icon )
1539 self.lbl = gtk.Label("Please wait...")
1540 self.bar = gtk.ProgressBar()
1541 self.dialog.vbox.pack_start(self.lbl)
1542 self.dialog.vbox.pack_start(self.bar)
1543 self.dialog.show_all()
1544 #self.dialog.connect("delete_event",self.inhibit_close)
1546 def update_message( self, message ):
1547 self.lbl.set_text(message)
1549 def inhibit_close( self, widget, signal ):
1550 return True
1552 def update_window( self ):
1553 # Do stuff
1554 self.bar.pulse()
1555 return True
1557 def run( self ):
1558 self.dialog.show_all()
1559 self.timer = gobject.timeout_add(250,self.update_window)
1560 return
1562 def destroy( self ):
1563 gobject.source_remove(self.timer)
1564 self.dialog.destroy()
1565 del self.dialog
1567 ### ConfigFile
1568 ### class to manage the configuration file
1569 class ConfigFile(ConfigParser.SafeConfigParser):
1570 def __init__( self, filename, defaults ):
1571 self.filename = filename
1572 self.auto_profile_order = []
1573 ConfigParser.SafeConfigParser.__init__(self, defaults)
1575 def set_section( self, section_name, section_dict ):
1576 """ set the contents of a section to values from a dictionary """
1577 self.add_section(section_name)
1578 for key in section_dict.keys():
1579 self.set_opt(section_name + "." + key, section_dict[key])
1581 def get_opt( self, option_path ):
1582 """ get a config option and handle exceptions """
1583 #print "ConfigFile.get_opt: ", option_path
1584 (section, option) = option_path.split('.')
1585 try:
1586 return self.get(section, option)
1587 except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
1588 return None
1590 def get_opt_as_bool( self, option_path ):
1591 """ get a config option and return as a boolean type """
1592 option = self.get_opt(option_path)
1593 if isinstance(option, BooleanType):
1594 return option
1595 if option == 'True':
1596 return True
1597 if option == 'False':
1598 return False
1599 raise ValueError, 'boolean option was not True or False'
1601 def get_opt_as_int( self, option_path ):
1602 """ get a config option and return as an integer type """
1603 return int(float(self.get_opt(option_path)))
1605 def set_bool_opt( self, option_path, value ):
1606 """ convert boolean type to string and set config option """
1607 print "bool_opt: ", value
1608 if ( value == True ) or ( value > 0 ) or ( value == 'True' ):
1609 value == 'True'
1610 elif ( value == False ) or ( value == 0 ) or ( value == 'False' ):
1611 value == 'False'
1612 else:
1613 raise ValueError, 'cannot convert value to string'
1614 self.set_opt(option_path, repr(value))
1616 def set_int_opt( self, option_path, value ):
1617 """ convert integer type to string and set config option """
1618 if not isinstance(value, IntType):
1619 raise ValueError, 'value is not an integer'
1620 self.set_opt(option_path, repr(value))
1622 def set_float_opt( self, option_path, value ):
1623 """ convert float type to string and set config option """
1624 if not isinstance(value, FloatType):
1625 raise ValueError, 'value is not a float'
1626 self.set_opt(option_path, repr(int(value)))
1628 def set_opt( self, option_path, value ):
1629 """ set a config option and handle exceptions """
1630 (section, option) = option_path.split('.')
1631 try:
1632 self.set(section, option, value)
1633 except ConfigParser.NoSectionError:
1634 self.add_section(section)
1635 self.set_opt(option_path, value)
1637 def profiles( self ):
1638 """ return a list of the section names which denote AP profiles """
1639 profile_list = []
1640 for section in self.sections():
1641 if ':' in section:
1642 profile_list.append(section)
1643 return profile_list
1645 def read ( self ):
1646 fp = open( self.filename, "r" )
1647 self.readfp(fp)
1648 # convert the auto_profile_order to a list for ordering
1649 self.auto_profile_order = eval(self.get_opt('DEFAULT.auto_profile_order'))
1650 print self.auto_profile_order
1652 def write( self ):
1653 """ Copied from ConfigParser and modified to write options in alphabetical order """
1654 print self.auto_profile_order
1655 self.set_opt('DEFAULT.auto_profile_order', str(self.auto_profile_order))
1656 fp = open( self.filename, "w" )
1657 # write DEFAULT section first
1658 if self._defaults:
1659 fp.write("[DEFAULT]\n")
1660 for key in sorted(self._defaults.keys()):
1661 fp.write("%s = %s\n" % (key, str(self._defaults[key]).replace('\n','\n\t')))
1662 fp.write("\n")
1663 # write non-profile sections first
1664 for section in self._sections:
1665 if not section in self.profiles():
1666 fp.write("[%s]\n" % section)
1667 for key in sorted(self._sections[section].keys()):
1668 if key != "__name__":
1669 fp.write("%s = %s\n" %
1670 (key, str(self._sections[section][key]).replace('\n', '\n\t')))
1671 fp.write("\n")
1672 # write profile sections
1673 for section in self._sections:
1674 if section in self.profiles():
1675 fp.write("[%s]\n" % section)
1676 for key in sorted(self._sections[section].keys()):
1677 if key != "__name__":
1678 fp.write("%s = %s\n" %
1679 (key, str(self._sections[section][key]).replace('\n', '\n\t')))
1680 fp.write("\n")
1683 ####################################################################################################
1684 # Speaking up
1685 def say( words ):
1686 if not confFile.get_opt_as_bool('DEFAULT.speak_up'): return
1687 words = words.replace( "\"", "\\\"" )
1688 os.system("%s \"%s\"" % ( confFile.get_opt('DEFAULT.speak_command'), words ))
1689 #os.spawnlp(os.P_WAIT, confFile.get_opt('DEFAULT.speak_command'), confFile.get_opt('DEFAULT.speak_command'), words)
1691 # Configure
1692 def configure( confFile ):
1693 global main_radar_window
1694 global scanner
1695 global lock
1696 main_radar_window = radar_window(confFile)
1697 lock = threading.RLock()
1698 threading.Thread( None, scanning_thread, None, ( confFile, lock) ).start()
1699 gobject.timeout_add( 500, main_radar_window.update_plist_items )
1700 main_radar_window.main()
1703 ####################################################################################################
1704 # Initializers
1705 access_points = {}
1706 auto_profile_order = []
1707 lock = None
1708 s = None
1711 # load our conf file and known profiles
1712 ####################################################################################################
1713 # Defaults, these may get overridden by values found in the conf file.
1714 # The network interface you use.
1715 # Specify "auto_detect" as the interface to make wifi-radar automatically detect your wireless card.
1716 config_defaults = { 'interface': "auto_detect",
1717 # How long should the scan for access points last?
1718 'scan_timeout': '5',
1719 # X1000 Linux has a say command (text to speech) to announce connecting to networks.
1720 # Set the speak_up option to false if you do not have or want this.
1721 'speak_command': '/usr/bin/say',
1722 # Should I speak up when connecting to a network? (If you have a speech command)
1723 'speak_up': 'False',
1724 # You may set this to true for cards that require a "commit" command with iwconfig
1725 'commit_required': 'False',
1726 # You may set this to true for cards that require the interface to be brought up first
1727 'ifup_required': 'False',
1728 # Set the location of several important programs
1729 'iwlist_command': '/sbin/iwlist',
1730 'iwconfig_command': '/sbin/iwconfig',
1731 'ifconfig_command': '/sbin/ifconfig',
1732 'route_command': '/sbin/route',
1733 'auto_profile_order': '[]',
1734 'version': WIFI_RADAR_VERSION }
1736 config_dhcp = { 'command': 'dhcpcd',
1737 'timeout': '30',
1738 'args': '-D -H -o -i dhcp_client -t %(timeout)s',
1739 'kill_args': '-k',
1740 'pidfile': '/var/run/dhcpcd-%(interface)s.pid' }
1742 config_wpa = { 'command': '/usr/sbin/wpa_supplicant',
1743 'kill_command': '',
1744 'configuration': '/etc/wpa_supplicant.conf',
1745 'driver': 'wext',
1746 'pidfile': '/var/run/wpa_supplicant.pid' }
1748 # initialize config, with defaults
1749 confFile = ConfigFile(CONF_FILE, config_defaults)
1750 confFile.set_section("DCHP", config_dhcp)
1751 confFile.set_section("WPA", config_wpa)
1753 if not os.path.isfile( CONF_FILE ):
1754 confFile.write()
1755 else:
1756 confFile.read()
1757 # set the defaults
1758 ap_defaults = { 'known': 'False',
1759 'available': 'False',
1760 'encrypted': 'False',
1761 'essid': '',
1762 'bssid': '',
1763 'protocol': 'g',
1764 'signal': '0',
1765 'channel': '',
1766 'con_prescript': '',
1767 'con_postscript': '',
1768 'dis_prescript': '',
1769 'dis_postscript': '',
1770 'key': '',
1771 'mode': '',
1772 'security': '',
1773 'use_dhcp': 'True',
1774 'use_wpa': 'False'
1776 # First, we add our known profiles
1777 for apname in confFile.profiles():
1778 ap = ap_defaults.copy()
1779 (ap['essid'], ap['bssid']) = split_section_name( apname )
1780 # read the important values
1781 for key in ap.keys():
1782 ap[key] = confFile.get_opt(apname + "." + key)
1783 access_points[ apname ] = ap
1784 # if it is not in the auto_profile_order add it
1785 if not apname in confFile.auto_profile_order:
1786 confFile.auto_profile_order.append( apname )
1788 set_network_device(confFile.get_opt('DEFAULT.interface'))
1790 ####################################################################################################
1791 # Embedded Images
1792 wifi_radar_icon = [ ""
1793 "GdkP"
1794 "\0\0\22""7"
1795 "\2\1\0\2"
1796 "\0\0\1\214"
1797 "\0\0\0c"
1798 "\0\0\0O"
1799 "\377\377\377\377\0\377\377\377\377\0\377\377\377\377\0\377\377\377\377"
1800 "\0\377\377\377\377\0\377\377\377\377\0\377\377\377\377\0\261\377\377"
1801 "\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"
1802 "\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"
1803 "\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"
1804 "\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"
1805 "\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"
1806 "\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"
1807 "\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"
1808 "\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"
1809 "\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"
1810 "\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"
1811 "\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"
1812 "\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"
1813 "\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"
1814 "\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"
1815 "\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"
1816 "\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"
1817 "\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"
1818 "\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"
1819 "\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"
1820 "\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"
1821 "\0\0\272\214\0\0\0\377\3\0\0\0\375\0\0\0\241\0\0\0\"\226\377\377\377"
1822 "\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"
1823 "\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"
1824 "\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"
1825 "\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"
1826 "\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"
1827 "\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"
1828 "\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"
1829 "\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"
1830 "\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"
1831 "\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"
1832 "\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"
1833 "\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"
1834 "\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"
1835 "\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"
1836 "\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"
1837 "\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"
1838 "\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"
1839 "\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"
1840 "\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"
1841 "\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"
1842 "\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"
1843 "\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"
1844 "\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"
1845 "\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"
1846 "\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"
1847 "\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"
1848 "\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"
1849 "\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"
1850 "\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"
1851 "\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"
1852 "\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"
1853 "\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"
1854 "\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"
1855 "\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"
1856 "\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"
1857 "\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"
1858 "\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"
1859 "\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"
1860 "\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"
1861 "\377\377\377\0\1\0\0\0a\211\0\0\0\377\1\0\0\0\257\232\377\377\377\0\1"
1862 "\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"
1863 "\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"
1864 "*\0\0\0\242\211\0\0\0\310\1\0\0\0`\205\377\377\377\0\1\0\0\0\276\211"
1865 "\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"
1866 "\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"
1867 "\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"
1868 "\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"
1869 "\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"
1870 "\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"
1871 "\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"
1872 "\377\377\377\0\1\0\0\0|\211\0\0\0\377\1\0\0\0""0\226\377\377\377\0\2"
1873 "\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"
1874 "\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"
1875 "\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"
1876 "\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"
1877 "\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"
1878 "\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"
1879 "|\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"
1880 "\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"
1881 "\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"
1882 "\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"
1883 "\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"
1884 "\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"
1885 "\377\377\0\1\0\0\0\206\207\0\0\0\310\1\0\0\0X\214\377\377\377\0\11\0"
1886 "\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"
1887 "\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"
1888 "\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"
1889 "\377\377\0\1\0\0\0\271\210\0\0\0\377\1\0\0\0\202\203\377\377\377\0\1"
1890 "\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"
1891 "\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"
1892 "\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"
1893 "\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"
1894 "\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"
1895 "\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"
1896 "\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"
1897 "\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"
1898 "\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"
1899 "\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"
1900 "\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"
1901 "\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"
1902 "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"
1903 "\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"
1904 "\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"
1905 "\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"
1906 "\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"
1907 "\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"
1908 "\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"
1909 "\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"
1910 "\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"
1911 "\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"
1912 "\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"
1913 "\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"
1914 "\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"
1915 "\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"
1916 "\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"
1917 "\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|"
1918 "\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"
1919 "\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"
1920 "\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"
1921 "\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"
1922 "\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"
1923 "\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"
1924 "\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"
1925 "\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"
1926 "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"
1927 "\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"
1928 "\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"
1929 "\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"
1930 "\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"
1931 "\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"
1932 "\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"
1933 "\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"
1934 "\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"
1935 "\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"
1936 "\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"
1937 "\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"
1938 "\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"
1939 "\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"
1940 "\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"
1941 "\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"
1942 "\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"
1943 "\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"
1944 "\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"
1945 "\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"
1946 "\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"
1947 "\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"
1948 "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"
1949 "\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"
1950 "\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"
1951 "\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"
1952 "\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"
1953 "\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"
1954 "\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"
1955 "\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"
1956 "\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"
1957 "\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"
1958 "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"
1959 "\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"
1960 "\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"
1961 "\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"
1962 "\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"
1963 "\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"
1964 "\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"
1965 "\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"
1966 "\377\377\0\377\377\377\377\0\377\377\377\377\0\377\377\377\377\0\377"
1967 "\377\377\377\0\377\377\377\377\0\377\377\377\377\0\377\377\377\377\0"
1968 "\377\377\377\377\0\377\377\377\377\0\377\377\377\377\0\234\377\377\377"
1969 "\0"]
1971 known_profile_icon = [ ""
1972 "GdkP"
1973 "\0\0\5""0"
1974 "\2\1\0\2"
1975 "\0\0\0P"
1976 "\0\0\0\24"
1977 "\0\0\0\24"
1978 "\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"
1979 "\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"
1980 "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"
1981 "\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"
1982 "\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"
1983 "\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"
1984 "\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"
1985 "\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"
1986 "\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"
1987 "\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"
1988 "\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"
1989 "\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"
1990 "\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"
1991 "\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"
1992 "\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"
1993 "\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"
1994 "\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"
1995 "\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"
1996 "\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"
1997 "***;\210\210\210\356\223\223\223\377iii\377\204\204\204\377\216\216\216"
1998 "\377~~~\377zzz\377\203\203\203\377\215\215\215\377ddd\377\202\202\202"
1999 "\377xxx\356\40\40\40;\205\0\0\0\0\2&&&#\251\251\251\353\202\374\374\374"
2000 "\377\202\372\372\372\377\5\335\335\335\377\353\353\353\377\366\366\366"
2001 "\377\327\327\327\377\357\357\357\377\202\365\365\365\377\3\362\362\362"
2002 "\377\226\226\226\353\27\27\27)\204\0\0\0\0\21,,,p\354\354\354\377\355"
2003 "\355\355\377\351\351\351\377\346\346\346\377\342\342\342\377\335\335"
2004 "\335\377\334\334\334\377\330\330\330\377\324\324\324\377\320\320\320"
2005 "\377\316\316\316\377\313\313\313\377\307\307\307\377\314\314\314\377"
2006 "\35\35\35y\0\0\0\1\202\0\0\0\0\14\0\0\0\2(((\203\357\357\357\377\345"
2007 "\345\345\377\341\341\341\377\337\337\337\377\333\333\333\377\326\326"
2008 "\326\377\322\322\322\377\316\316\316\377\312\312\312\377\306\306\306"
2009 "\377\202\302\302\302\377\30\314\314\314\377\311\311\311\377\33\33\33"
2010 "\204\0\0\0\5\0\0\0\1\0\0\0\2\0\0\0\10&&&\210\356\356\356\377\342\342"
2011 "\342\377\347\347\347\377\346\346\346\377\324GG\377\337\337\337\377\324"
2012 "GG\377\333\322\322\377\324GG\377<\341@\377\324GG\377<\341@\377\321\321"
2013 "\321\377\276\276\276\377\27\27\27\214\0\0\0\15\202\0\0\0\4+\0\0\0\21"
2014 "$$$\221\355\355\355\377\345\345\345\377\344\344\344\377\340\340\340\377"
2015 "\334\334\334\377\331\331\331\377\325\325\325\377\321\321\321\377\316"
2016 "\316\316\377\312\312\312\377\306\306\306\377\307\307\307\377\313\313"
2017 "\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"
2018 "\27\"\"\"\231\354\354\354\377\346\346\346\377\342\342\342\377\337\337"
2019 "\337\377\333\333\333\377\327\327\327\377\324\324\324\377\320\320\320"
2020 "\377\314\314\314\377\310\310\310\377\305\305\305\377\301\301\301\377"
2021 "\276\276\276\377\271\271\271\377\23\23\23\235\0\0\0\35\0\0\0\10\0\0\0"
2022 "\4\0\0\0\32\40\40\40\223\310\310\310\376\202\274\274\274\377\4\272\272"
2023 "\272\377\271\271\271\377\270\270\270\377\267\267\267\377\202\271\271"
2024 "\271\377\16\270\270\270\377\266\266\266\377\265\265\265\377\264\264\264"
2025 "\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"
2026 "\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"
2027 "\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"
2028 "\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"
2029 "\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"]
2031 unknown_profile_icon = [ ""
2032 "GdkP"
2033 "\0\0\5\22"
2034 "\2\1\0\2"
2035 "\0\0\0P"
2036 "\0\0\0\24"
2037 "\0\0\0\24"
2038 "\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"
2039 "\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"
2040 "\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"
2041 "\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"
2042 "(\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"
2043 "\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"
2044 "#\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"
2045 "\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"
2046 "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"
2047 "\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"
2048 "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"
2049 "\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"
2050 "\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"
2051 "\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"
2052 "\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"
2053 "\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"
2054 "\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"
2055 "\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"
2056 "\0\0\0\0\16***\21\210\210\210G\223\223\223LiiiL\204\204\204L\34=n\300"
2057 "\14""1i\361\12""0i\374\20""4j\342CXx}dddL\202\202\202LxxxG\40\40\40\21"
2058 "\205\0\0\0\0\2&&&\13\251\251\251F\202\374\374\374L\202\372\372\372L\5"
2059 "\"Cv\310Lf\217\226@]\211\245\12""0i\377\22""7n\353\202\365\365\365L\3"
2060 "\362\362\362L\226\226\226F\27\27\27\14\204\0\0\0\0\21,,,!\354\354\354"
2061 "L\355\355\355L\351\351\351L\346\346\346L\342\342\342L\335\335\335L\334"
2062 "\334\334L\210\227\255h\12""0i\377\21""6l\352\316\316\316L\313\313\313"
2063 "L\307\307\307L\314\314\314L\35\35\35$\0\0\0\1\202\0\0\0\0\14\0\0\0\1"
2064 "((('\357\357\357L\345\345\345L\341\341\341L\337\337\337L\333\333\333"
2065 "L\326\326\326L|\215\245l\20""5l\355\12""0i\374Sj\215\205\202\302\302"
2066 "\302L\4\314\314\314L\311\311\311L\33\33\33'\0\0\0\2\202\0\0\0\1\22\0"
2067 "\0\0\2&&&(\356\356\356L\342\342\342L\347\347\347L\346\346\346L\324GG"
2068 "L\337\337\337L\22""0g\351\12""0i\377^9Z\201<\341@L\324GGL<\341@L\321"
2069 "\321\321L\276\276\276L\27\27\27)\0\0\0\4\202\0\0\0\1\22\0\0\0\5$$$+\355"
2070 "\355\355L\345\345\345L\344\344\344L\340\340\340L\334\334\334L\331\331"
2071 "\331Law\227\177`u\226\177\316\316\316L\312\312\312L\306\306\306L\307"
2072 "\307\307L\313\313\313L\272\272\272L\24\24\24,\0\0\0\7\202\0\0\0\2\27"
2073 "\0\0\0\7\"\"\"-\354\354\354L\346\346\346L\342\342\342L\337\337\337L\333"
2074 "\333\333L\327\327\327LSk\217\212Qi\216\212\314\314\314L\310\310\310L"
2075 "\305\305\305L\301\301\301L\276\276\276L\271\271\271L\23\23\23/\0\0\0"
2076 "\10\0\0\0\2\0\0\0\1\0\0\0\10\40\40\40,\310\310\310K\202\274\274\274L"
2077 "\3\272\272\272L\271\271\271L\270\270\270L\202\12""0i\377\16\271\271\271"
2078 "L\270\270\270L\266\266\266L\265\265\265L\264\264\264L\231\231\231K\16"
2079 "\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"
2080 "\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"
2081 "\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"
2082 "\4\0\0\0\4\0\0\0\2\0\0\0\1\0\0\0\0"]
2084 signal_xpm_barely = [
2085 "20 20 10 1",
2086 " c None",
2087 ". c #C6C6C6",
2088 "+ c #CCCCCC",
2089 "@ c #DBDBDB",
2090 "# c #D3D3D3",
2091 "$ c #A9B099",
2092 "% c #95A173",
2093 "& c #6B8428",
2094 "* c #B4B7AC",
2095 "= c #80924D",
2096 " .+++.",
2097 " +@@@+",
2098 " +@@@+",
2099 " +@@@+",
2100 " +@@@+",
2101 " .++++#@@@+",
2102 " +@@@@@@@@+",
2103 " +@@@@@@@@+",
2104 " +@@@@@@@@+",
2105 " +@@@@@@@@+",
2106 " $%%%%#@@@@@@@@+",
2107 " %&&&&@@@@@@@@@+",
2108 " %&&&&@@@@@@@@@+",
2109 " %&&&&@@@@@@@@@+",
2110 " %&&&&@@@@@@@@@+",
2111 "*%%%%=&&&&@@@@@@@@@+",
2112 "%&&&&&&&&&@@@@@@@@@+",
2113 "%&&&&&&&&&@@@@@@@@@+",
2114 "%&&&&&&&&&@@@@@@@@@+",
2115 "*%%%%%%%%%+++++++++."
2119 signal_xpm_best = [
2120 "20 20 6 1",
2121 " c None",
2122 ". c #9DAABF",
2123 "+ c #7B96BF",
2124 "@ c #386EBF",
2125 "# c #5982BF",
2126 "$ c #AEB4BF",
2127 " .+++.",
2128 " +@@@+",
2129 " +@@@+",
2130 " +@@@+",
2131 " +@@@+",
2132 " .++++#@@@+",
2133 " +@@@@@@@@+",
2134 " +@@@@@@@@+",
2135 " +@@@@@@@@+",
2136 " +@@@@@@@@+",
2137 " .++++#@@@@@@@@+",
2138 " +@@@@@@@@@@@@@+",
2139 " +@@@@@@@@@@@@@+",
2140 " +@@@@@@@@@@@@@+",
2141 " +@@@@@@@@@@@@@+",
2142 "$++++#@@@@@@@@@@@@@+",
2143 "+@@@@@@@@@@@@@@@@@@+",
2144 "+@@@@@@@@@@@@@@@@@@+",
2145 "+@@@@@@@@@@@@@@@@@@+",
2146 "$++++++++++++++++++."
2149 signal_xpm_none = [
2150 "20 20 6 1",
2151 " c None",
2152 ". c #C6C6C6",
2153 "+ c #CCCCCC",
2154 "@ c #DBDBDB",
2155 "# c #D3D3D3",
2156 "$ c #C2C2C2",
2157 " .+++.",
2158 " +@@@+",
2159 " +@@@+",
2160 " +@@@+",
2161 " +@@@+",
2162 " .++++#@@@+",
2163 " +@@@@@@@@+",
2164 " +@@@@@@@@+",
2165 " +@@@@@@@@+",
2166 " +@@@@@@@@+",
2167 " .++++#@@@@@@@@+",
2168 " +@@@@@@@@@@@@@+",
2169 " +@@@@@@@@@@@@@+",
2170 " +@@@@@@@@@@@@@+",
2171 " +@@@@@@@@@@@@@+",
2172 "$++++#@@@@@@@@@@@@@+",
2173 "+@@@@@@@@@@@@@@@@@@+",
2174 "+@@@@@@@@@@@@@@@@@@+",
2175 "+@@@@@@@@@@@@@@@@@@+",
2176 "$++++++++++++++++++."
2179 signal_xpm_ok = [
2180 "20 20 10 1",
2181 " c None",
2182 ". c #C6C6C6",
2183 "+ c #CCCCCC",
2184 "@ c #DBDBDB",
2185 "# c #A1A5B2",
2186 "$ c #848DA5",
2187 "% c #D3D3D3",
2188 "& c #4A5B8C",
2189 "* c #677498",
2190 "= c #B0B2B8",
2191 " .+++.",
2192 " +@@@+",
2193 " +@@@+",
2194 " +@@@+",
2195 " +@@@+",
2196 " #$$$$%@@@+",
2197 " $&&&&@@@@+",
2198 " $&&&&@@@@+",
2199 " $&&&&@@@@+",
2200 " $&&&&@@@@+",
2201 " #$$$$*&&&&@@@@+",
2202 " $&&&&&&&&&@@@@+",
2203 " $&&&&&&&&&@@@@+",
2204 " $&&&&&&&&&@@@@+",
2205 " $&&&&&&&&&@@@@+",
2206 "=$$$$*&&&&&&&&&@@@@+",
2207 "$&&&&&&&&&&&&&&@@@@+",
2208 "$&&&&&&&&&&&&&&@@@@+",
2209 "$&&&&&&&&&&&&&&@@@@+",
2210 "=$$$$$$$$$$$$$$++++."
2214 signal_xpm_low = [
2215 "20 20 8 1",
2216 " c None",
2217 ". c #C6C6C6",
2218 "+ c #CCCCCC",
2219 "@ c #DBDBDB",
2220 "# c #D3D3D3",
2221 "$ c #BFB0B5",
2222 "% c #C18799",
2223 "& c #C54F74",
2224 " .+++.",
2225 " +@@@+",
2226 " +@@@+",
2227 " +@@@+",
2228 " +@@@+",
2229 " .++++#@@@+",
2230 " +@@@@@@@@+",
2231 " +@@@@@@@@+",
2232 " +@@@@@@@@+",
2233 " +@@@@@@@@+",
2234 " .++++#@@@@@@@@+",
2235 " +@@@@@@@@@@@@@+",
2236 " +@@@@@@@@@@@@@+",
2237 " +@@@@@@@@@@@@@+",
2238 " +@@@@@@@@@@@@@+",
2239 "$%%%%#@@@@@@@@@@@@@+",
2240 "%&&&&@@@@@@@@@@@@@@+",
2241 "%&&&&@@@@@@@@@@@@@@+",
2242 "%&&&&@@@@@@@@@@@@@@+",
2243 "$%%%%++++++++++++++."
2245 signal_none_pb = None
2246 signal_low_pb = None
2247 signal_barely_pb= None
2248 signal_ok_pb = None
2249 signal_best_pb = None
2250 exit_flag = False
2252 ####################################################################################################
2253 # Make so we can be imported
2254 if __name__ == "__main__":
2255 # Are we in configure mode?
2256 if len( sys.argv ) > 1 and ( sys.argv[1] == '--version' or sys.argv[1] == '-v' ):
2257 print "WiFi-Radar version %s" % WIFI_RADAR_VERSION
2258 elif len( sys.argv ) > 1 and ( sys.argv[1] == '--daemon' or sys.argv[1] == '-d' ):
2259 scanning_thread()
2260 connect_to_preferred()
2261 else:
2262 import gtk, gobject
2263 gtk.gdk.threads_init()
2264 configure(confFile)