1
0
mirror of https://github.com/gryf/wicd.git synced 2025-12-20 12:58:07 +01:00

Changed misc.Run to use subprocess.Popen instead of os.popen. Also altered Run to optionally return a pipe to the command run, instead of just the output.

The output of dhclient is now parsed by wicd and used to determine why the connection failed.
All the wpa_supplicant conf files will now generate a ctrl_interface, so that they can be accessed by wpa_cli.  wpa_cli now is used by wicd to attempt to determine is wpa_supplicant authentication was successful.  This is still experimental, and might have to be tweaked to work properly.
If wicd.py is started and the daemon isn't present, it will autolaunch it by calling launchdaemon.sh, instead of asking the user to start the daemon manually.
Cleaned up some comments, formatting, etc.
Probably a couple of other little bug fixes I'm forgetting.
This commit is contained in:
imdano
2008-01-06 13:55:23 +00:00
parent 4e0dfc8e22
commit d64850dfd3
16 changed files with 354 additions and 155 deletions

View File

@@ -6,18 +6,9 @@ import dbus.service
if getattr(dbus, 'version', (0,0,0)) >= (0,41,0):
import dbus.glib
#############
#declare our connections to our daemon.
#without them nothing useful will happen
#the daemon should be running as root
bus = dbus.SystemBus()
proxy_obj = bus.get_object('org.wicd.daemon', '/org/wicd/daemon')
##we don't need some of these, so I just comment them out
daemon = dbus.Interface(proxy_obj, 'org.wicd.daemon')
#wireless = dbus.Interface(proxy_obj, 'org.wicd.daemon.wireless')
#wired = dbus.Interface(proxy_obj, 'org.wicd.daemon.wired')
#config = dbus.Interface(proxy_obj, 'org.wicd.daemon.config')
#############
print daemon.Hello()
if daemon.CheckIfConnecting() == False:

View File

@@ -25,6 +25,7 @@ run as the current user.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import os
import sys
import gtk

View File

@@ -143,6 +143,7 @@ class ConnectionWizard(dbus.service.Object):
self.need_profile_chooser = False
self.current_interface = None
self.vpn_session = None
self.user_init_connect = False
# Load the config file
self.ReadConfig()
@@ -177,7 +178,7 @@ class ConnectionWizard(dbus.service.Object):
#micro is for everything else.
#and micro may be anything >= 0
#this number is effective starting wicd v1.2.0
version = '1.4.0'
version = '1.4.2'
print 'returned version number',version
return version
@@ -295,6 +296,13 @@ class ConnectionWizard(dbus.service.Object):
return int(self.debug_mode)
#end function GetDebugMode
@dbus.service.method('org.wicd.daemon')
def Disconnect(self):
'''disconnects all networks'''
self.SetForcedDisconnect(True)
self.wifi.Disconnect()
self.wired.Disconnect()
@dbus.service.method('org.wicd.daemon')
def GetSignalDisplayType(self):
''' Returns the signal display type
@@ -381,17 +389,36 @@ class ConnectionWizard(dbus.service.Object):
@dbus.service.method('org.wicd.daemon')
def GetCurrentInterface(self):
""" Returns the active interface """
return self.current_interface
@dbus.service.method('org.wicd.daemon')
def SetCurrentInterface(self, iface):
""" Sets the current active interface """
self.current_interface = str(iface)
@dbus.service.method('org.wicd.daemon')
def SetNeedWiredProfileChooser(self,val):
""" Sets the need_wired_profile_chooser variable.
If set to true, that alerts the wicd frontend to display the chooser,
if false the frontend will do nothing. This function is only needed
when the frontend starts up, to determine if the chooser was requested
before the frontend was launched.
"""
self.need_profile_chooser = val
#end function SetNeedWiredProfileChooser
@dbus.service.method('org.wicd.daemon')
def SetUserInitConnect(self, val):
""" Specifies if the last connection attempt was user/cpu initiated """
self.user_init_connect = val
@dbus.service.method('org.wicd.daemon')
def GetUserInitConnect(self):
return self.user_init_connect
@dbus.service.method('org.wicd.daemon')
def GetNeedWiredProfileChooser(self):
return bool(self.need_profile_chooser)
@@ -459,13 +486,6 @@ class ConnectionWizard(dbus.service.Object):
break
self.LastScan = master_scan
@dbus.service.method('org.wicd.daemon.wireless')
def DisconnectWireless(self):
'''disconnects all wireless networks'''
self.SetForcedDisconnect(True)
self.wifi.Disconnect()
self.wired.Disconnect()
#end function DisconnectWireless
@dbus.service.method('org.wicd.daemon.wireless')
def GetNumberOfNetworks(self):
@@ -587,12 +607,13 @@ class ConnectionWizard(dbus.service.Object):
#end function GetCurrentNetwork
@dbus.service.method('org.wicd.daemon.wireless')
def ConnectWireless(self,id):
def ConnectWireless(self,id, user_init=False):
'''connects the the wireless network specified by id'''
# Will returned instantly, that way we don't hold up dbus.
# CheckIfWirelessConnecting can be used to test if the connection
# is done.
self.SetForcedDisconnect(False)
self.SetUserInitConnect(user_init)
self.wifi.before_script = self.GetWirelessProperty(id,'beforescript')
self.wifi.after_script = self.GetWirelessProperty(id,'afterscript')
self.wifi.disconnect_script = self.GetWirelessProperty(id,'disconnectscript')
@@ -772,8 +793,9 @@ class ConnectionWizard(dbus.service.Object):
#end function CheckPluggedIn
@dbus.service.method('org.wicd.daemon.wired')
def ConnectWired(self):
def ConnectWired(self, user_init=False):
'''connects to a wired network'''
self.SetUserInitConnect(user_init)
self.wired.before_script = self.GetWiredProperty("beforescript")
self.wired.after_script = self.GetWiredProperty("afterscript")
self.wired.disconnect_script = self.GetWiredProperty("disconnectscript")

View File

@@ -3,6 +3,7 @@ author = Adam Blackburn
version = 2
require username *Username password *Password pac_file *Path_To_PAC_File
-----
ctrl_interface=/var/run/wpa_supplicant
network={
ssid="$_ESSID"
scan_ssid=$_SCAN

View File

@@ -3,6 +3,7 @@ author = Adam Blackburn
version = 1
require username *Username password *Password
-----
ctrl_interface=/var/run/wpa_supplicant
network={
ssid="$_ESSID"
scan_ssid=$_SCAN

View File

@@ -3,6 +3,7 @@ author = Adam Blackburn
version = 2
require identity *Identity password *Password
-----
ctrl_interface=/var/run/wpa_supplicant
network={
ssid="$_ESSID"
proto=RSN

View File

@@ -3,6 +3,7 @@ author = Fralaltro
version = 1
require identity *Identity password *Password ca_cert *Path_to_CA_Cert
-----
ctrl_interface=/var/run/wpa_supplicant
network={
ssid="$_ESSID"
scan_ssid=$_SCAN

View File

@@ -3,6 +3,7 @@ author = Adam Blackburn
version = 1
require anonymous_identity *Anonymous_Identity identity *Identity password *Password auth *Authentication
-----
ctrl_interface=/var/run/wpa_supplicant
network={
ssid="$_ESSID"
scan_ssid=$_SCAN

View File

@@ -3,6 +3,7 @@ author = Adam Blackburn
version = 1
require key *Key
-----
ctrl_interface=/var/run/wpa_supplicant
network={
ssid="$_ESSID"
scan_ssid=$_SCAN

View File

@@ -3,6 +3,7 @@ author = Adam Blackburn
version = 1
require key *Key
-----
ctrl_interface=/var/run/wpa_supplicant
network={
ssid="$_ESSID"
scan_ssid=$_SCAN

122
gui.py
View File

@@ -21,6 +21,8 @@ import os
import sys
import wpath
import signal
import time
if __name__ == '__main__':
wpath.chdir(__file__)
try:
@@ -39,21 +41,24 @@ import time, os, misc, gettext, locale, gobject, dbus, dbus.service,pango
if getattr(dbus, 'version', (0,0,0)) >= (0,41,0):
import dbus.glib
#declare the connections to the daemon, so that they may be accessed
#in any class
# Declare the connections to the daemon, so that they may be accessed
# in any class.
bus = dbus.SystemBus()
try:
print 'Attempting to connect daemon to gui...'
print 'Attempting to connect daemon to GUI...'
proxy_obj = bus.get_object('org.wicd.daemon', '/org/wicd/daemon')
print 'success'
print 'Success'
except:
print 'daemon not running, running gksudo ./daemon.py...'
print 'Daemon not running, trying to start it automatically.'
misc.PromptToStartDaemon()
time.sleep(1)
try:
proxy_obj = bus.get_object('org.wicd.daemon', '/org/wicd/daemon')
print 'Daemon started succesfully'
except:
print 'daemon still not running, aborting.'
print 'Daemon still not running, aborting.'
sys.exit(1)
daemon = dbus.Interface(proxy_obj, 'org.wicd.daemon')
wireless = dbus.Interface(proxy_obj, 'org.wicd.daemon.wireless')
wired = dbus.Interface(proxy_obj, 'org.wicd.daemon.wired')
@@ -65,19 +70,19 @@ config = dbus.Interface(proxy_obj, 'org.wicd.daemon.config')
#http://www.learningpython.com/2006/12/03/translating-your-pythonpygtk-application/
#which is also under GPLv2
#Get the local directory since we are not installing anything
# Get the local directory since we are not installing anything.
local_path = os.path.realpath(os.path.dirname(sys.argv[0])) + '/translations'
# Init the list of languages to support
# Init the list of languages to support.
langs = list()
#Check the default locale
# Check the default locale.
lc, encoding = locale.getdefaultlocale()
if (lc):
#If we have a default, it's the first in the list
# If we have a default, it's the first in the list.
langs = [lc]
# Now lets get all of the supported languages on the system
osLanguage = os.environ.get('LANGUAGE', None)
if (osLanguage):
#langage comes back something like en_CA:en_US:en_GB:en
# Language comes back something like en_CA:en_US:en_GB:en
#on linuxy systems, on Win32 it's nothing, so we need to
#split it up into a list
langs += osLanguage.split(":")
@@ -97,8 +102,8 @@ lang = gettext.translation('wicd', local_path, languages=langs, fallback = True)
#map _() to self.lang.gettext() which will translate them.
_ = lang.gettext
#keep all the language strings in a dictionary
#by the english words
# Keep all the language strings in a dictionary
# by the english words.
# I'm not sure this is the best way to do it
# but it works and makes it easy for me :)
##########
@@ -190,7 +195,11 @@ language['setting_broadcast_address'] = _('Setting broadcast address...')
language['setting_static_dns'] = _('Setting static DNS servers...')
language['setting_static_ip'] = _('Setting static IP addresses...')
language['running_dhcp'] = _('Obtaining IP address...')
language['no_dhcp_offers'] = _('Connection Failed: No DHCP offers received. \
Couldn\'t get an IP Address.')
language['dhcp_failed'] = _('Connection Failed: Unable to Get IP Address')
language['aborted'] = _('Connection cancelled')
language['bad_pass'] = _('Connection Failed: Bad password')
language['done'] = _('Done connecting...')
########################################
@@ -210,7 +219,7 @@ class LinkButton(gtk.EventBox):
self.show_all()
def __setHandCursor(self,widget):
#we need this to set the cursor to a hand for the link labels
# We need this to set the cursor to a hand for the link labels.
#I'm not entirely sure what it does :P
hand = gtk.gdk.Cursor(gtk.gdk.HAND1)
widget.window.set_cursor(hand)
@@ -239,7 +248,7 @@ class LabelEntry(gtk.HBox):
self.show()
def set_text(self,text):
#for compatibility...
# For compatibility...
self.entry.set_text(text)
def get_text(self):
@@ -259,7 +268,7 @@ class LabelEntry(gtk.HBox):
self.label.set_sensitive(value)
def hide_characters(self,widget=None,event=None):
#when the box looses focus, hide them
# When the box looses focus, hide them
if self.auto_hide_text and widget:
self.entry.set_visibility(False)
@@ -282,7 +291,7 @@ def noneToString(text):
return str(text)
def noneToBlankString(text):
'''if text is None, 'None', or '' then return '', otherwise return str(text)'''
'''If text is None, 'None', or '' then return '', otherwise return str(text)'''
if text == None or text == "None" or text == "":
return ""
else:
@@ -296,7 +305,7 @@ def stringToNone(text):
return str(text)
def stringToBoolean(text):
'''turns a "True" to True or a "False" to False otherwise returns the text'''
'''Turns a "True" to True or a "False" to False otherwise returns the text'''
if text == "True":
return True
if text == "False":
@@ -304,7 +313,7 @@ def stringToBoolean(text):
return text
def checkboxTextboxToggle(checkbox,textboxes):
#really bad practice, but checkbox == self
# Really bad practice, but checkbox == self
for textbox in textboxes:
textbox.set_sensitive(checkbox.get_active())
@@ -314,7 +323,7 @@ def checkboxTextboxToggle(checkbox,textboxes):
class PrettyNetworkEntry(gtk.HBox):
'''adds an image and a connect button to a NetworkEntry'''
'''Adds an image and a connect button to a NetworkEntry'''
def __init__(self,expander):
gtk.HBox.__init__(self)
# Add the stuff to the hbox (self)
@@ -333,10 +342,9 @@ class PrettyNetworkEntry(gtk.HBox):
class PrettyWiredNetworkEntry(PrettyNetworkEntry):
def __init__(self):
PrettyNetworkEntry.__init__(self,WiredNetworkEntry())
#center the picture and pad it a bit
# Center the picture and pad it a bit
self.image = gtk.Image()
self.image.set_alignment(.5,0)
self.image.set_size_request(60,-1)
self.image.set_from_icon_name("network-wired",6)
self.image.show()
@@ -381,23 +389,24 @@ class PrettyWirelessNetworkEntry(PrettyNetworkEntry):
# "converted" to strength bars, so suggestions from people
# for a better way would be welcome.
if dbm_strength >= -60:
self.image.set_from_file(wpath.images + 'signal-100.png')
signal_img = 'signal-100.png'
elif dbm_strength >= -70:
self.image.set_from_file(wpath.images + 'signal-75.png')
signal_img = 'signal-75.png'
elif dbm_strength >= -80:
self.image.set_from_file(wpath.images + 'signal-50.png')
signal_img = 'signal-50.png'
else:
self.image.set_from_file(wpath.images + 'signal-25.png')
signal_img = 'signal-25.png'
else:
# Uses normal link quality, should be fine in most cases
if strength > 75:
self.image.set_from_file(wpath.images + 'signal-100.png')
signal_img = 'signal-100.png'
elif strength > 50:
self.image.set_from_file(wpath.images + 'signal-75.png')
signal_img = 'signal-75.png'
elif strength > 25:
self.image.set_from_file(wpath.images + 'signal-50.png')
signal_img = 'signal-50.png'
else:
self.image.set_from_file(wpath.images + 'signal-25.png')
signal_img = 'signal-25.png'
self.image.set_from_file(wpath.images + signal_img)
self.expander.setSignalStrength(strength, dbm_strength)
def setMACAddress(self,address):
@@ -412,10 +421,11 @@ class PrettyWirelessNetworkEntry(PrettyNetworkEntry):
def setMode(self,mode):
self.expander.setMode(mode)
class NetworkEntry(gtk.Expander):
'''the basis for the entries in the network list'''
'''The basis for the entries in the network list'''
def __init__(self):
#make stuff exist, this is pretty long and boring
# Make stuff exist, this is pretty long and boring.
gtk.Expander.__init__(self)
self.txtIP = LabelEntry(language['ip'])
self.txtIP.entry.connect('focus-out-event',self.setDefaults)
@@ -449,27 +459,27 @@ class NetworkEntry(gtk.Expander):
self.checkboxStaticDNS.connect("toggled",self.toggleDNSCheckbox)
self.checkboxGlobalDNS.connect("toggled",self.toggleGlobalDNSCheckbox)
self.add(self.vboxTop)
#start with all disabled, then they will be enabled later
# Start with all disabled, then they will be enabled later.
self.checkboxStaticIP.set_active(False)
self.checkboxStaticDNS.set_active(False)
def setDefaults(self,widget=None,event=None):
#after the user types in the IP address,
#help them out a little
ipAddress = self.txtIP.get_text() #for easy typing :)
# After the user types in the IP address,
# help them out a little.
ipAddress = self.txtIP.get_text() # For easy typing :)
netmask = self.txtNetmask
gateway = self.txtGateway
ip_parts = misc.IsValidIP(ipAddress)
if ip_parts:
if stringToNone(gateway.get_text()) == None: #make sure the gateway box is blank
#fill it in with a .1 at the end
if stringToNone(gateway.get_text()) == None: # Make sure the gateway box is blank
# Fill it in with a .1 at the end
gateway.set_text('.'.join(ip_parts[0:3]) + '.1')
if stringToNone(netmask.get_text()) == None: # Make sure the netmask is blank
netmask.set_text('255.255.255.0') # Fill in the most common one
def resetStaticCheckboxes(self):
#enable the right stuff
# Enable the right stuff
if not stringToNone(self.txtIP.get_text()) == None:
self.checkboxStaticIP.set_active(True)
self.checkboxStaticDNS.set_active(True)
@@ -492,10 +502,9 @@ class NetworkEntry(gtk.Expander):
self.toggleGlobalDNSCheckbox()
def toggleIPCheckbox(self,widget=None):
#should disable the static IP text boxes
# Should disable the static IP text boxes,
# and also enable the DNS checkbox when
#disabled and disable when enabled
# disabled and disable when enabled.
if self.checkboxStaticIP.get_active():
self.checkboxStaticDNS.set_active(True)
self.checkboxStaticDNS.set_sensitive(False)
@@ -532,7 +541,7 @@ class NetworkEntry(gtk.Expander):
self.txtDNS3.set_sensitive(not self.checkboxGlobalDNS.get_active())
class WiredNetworkEntry(NetworkEntry):
#creates the wired network expander
# Creates the wired network expander.
def __init__(self):
NetworkEntry.__init__(self)
self.set_label(language['wired_network'])
@@ -541,8 +550,8 @@ class WiredNetworkEntry(NetworkEntry):
self.isFullGUI = True
self.profileList = config.GetWiredProfileList()
if self.profileList: #make sure there is something in it...
for x in config.GetWiredProfileList(): #add all the names to the combobox
if self.profileList: # Make sure there is something in it...
for x in config.GetWiredProfileList(): # Add all the names to the combobox
self.comboProfileNames.append_text(x)
self.hboxTemp = gtk.HBox(False,0)
hboxDef = gtk.HBox(False,0)
@@ -668,19 +677,19 @@ class WiredNetworkEntry(NetworkEntry):
self.resetStaticCheckboxes()
class WirelessNetworkEntry(NetworkEntry):
#this class is respsponsible for creating the expander
#in each wirelessnetwork entry
# This class is respsponsible for creating the expander
# in each wirelessnetwork entry.
def __init__(self,networkID):
self.networkID = networkID
#create the data labels
# Create the data labels
NetworkEntry.__init__(self)
print "ESSID : " + wireless.GetWirelessProperty(networkID,"essid")
self.set_label(wireless.GetWirelessProperty(networkID,"essid"))
self.essid = wireless.GetWirelessProperty(networkID,"essid")
#make the vbox to hold the encryption stuff
# Make the vbox to hold the encryption stuff.
self.vboxEncryptionInformation = gtk.VBox(False,0)
#make the combo box
# Make the combo box.
self.comboEncryption = gtk.combo_box_new_text()
self.checkboxEncryption = gtk.CheckButton(language['use_encryption'])
self.lblStrength = GreyLabel()
@@ -888,7 +897,7 @@ class appGui:
dic = { "refresh_clicked" : self.refresh_networks,
"quit_clicked" : self.exit,
"disconnect_clicked" : self.disconnect_wireless,
"disconnect_clicked" : self.disconnect,
"main_exit" : self.exit,
"cancel_clicked" : self.cancel_connect,
"connect_clicked" : self.connect_hidden,
@@ -981,8 +990,8 @@ class appGui:
def toggleEncryptionCheck(self,widget=None):
self.keyEntry.set_sensitive(self.useEncryptionCheckbox.get_active())
def disconnect_wireless(self,widget=None):
wireless.DisconnectWireless()
def disconnect(self,widget=None):
daemon.Disconnect()
def about_dialog(self,widget,event=None):
dialog = gtk.AboutDialog()
@@ -1289,7 +1298,7 @@ class appGui:
# if it exists. maybe kept as a value in the network entry? Not sure...
print "connecting to wireless network..."
config.SaveWirelessNetworkProfile(networkid)
wireless.ConnectWireless(networkid)
wireless.ConnectWireless(networkid, True)
if type == "wired":
print "wired"
@@ -1314,7 +1323,7 @@ class appGui:
wired.SetWiredProperty("dns3",'')
config.SaveWiredNetworkProfile(networkentry.expander.comboProfileNames.get_active_text())
wired.ConnectWired()
wired.ConnectWired(True)
def exit(self, widget=None, event=None):
self.window.hide()
@@ -1327,9 +1336,6 @@ class appGui:
def show_win(self):
self.window.show()
# hide the status bar, as it might be confusing if it
# pops up randomly :)
self.status_area.hide_all()
self.is_visible = True
if __name__ == '__main__':

4
launchdaemon.sh Executable file
View File

@@ -0,0 +1,4 @@
#!/bin/bash
echo "Starting wicd daemon..."
/opt/wicd/daemon.py 2> /dev/null

94
misc.py
View File

@@ -1,14 +1,20 @@
''' Misc - miscellaneous functions for wicd '''
# Pretty much useless to anyone else...
# But if it is useful, feel free to use under the terms of the GPL
#
# This is released under the
# GNU General Public License
# The terms can be found at
# http://www.gnu.org/copyleft/gpl.html
#
# Copyright (C) 2007 Adam Blackburn
# Copyright (C) 2007 Dan O'Reilly
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License Version 2 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import os
@@ -17,18 +23,42 @@ import locale
import gettext
import time
import sys
from subprocess import *
if __name__ == '__main__':
wpath.chdir(__file__)
def Run(cmd, include_std_error = False):
''' Run a command '''
if not include_std_error:
f = os.popen( cmd , "r")
return f.read()
def Run(cmd, include_stderr=False, return_pipe=False):
''' Run a command
Runs the given command, returning either the output
of the program, or a pipe to read output from.
keyword arguments --
cmd - The command to execute
include_std_err - Boolean specifying if stderr should
be included in the pipe to the cmd.
return_pipe - Boolean specifying if a pipe to the
command should be returned. If it is
false, all that will be returned is
one output string from the command.
'''
cmd = to_unicode(str(cmd))
if include_stderr:
err = STDOUT
fds = True
else:
input, out_err = os.popen4( cmd, 'r')
return out_err.read()
err = None
fds = False
f = Popen(cmd, shell=True, stdout=PIPE, stderr=err, close_fds=fds)
if return_pipe:
return f.stdout
else:
return f.communicate()[0]
def IsValidIP(ip):
''' Make sure an entered IP is valid '''
@@ -41,10 +71,11 @@ def IsValidIP(ip):
def PromptToStartDaemon():
''' Prompt the user to start the daemon '''
# script execution doesn't work correctly if daemon gets autostarted,
# so just prompt user to start manually
print 'You need to start the daemon before using the gui or tray. Use \
the command \'sudo /etc/init.d/wicd start\'.'
daemonloc = wpath.bin + 'launchdaemon.sh'
gksudo_args = ['gksudo', '--message',
'Wicd needs to access your computer\'s network cards.',
'--', daemonloc]
os.spawnvpe(os.P_WAIT, 'gksudo', gksudo_args, os.environ)
def RunRegex(regex, string):
''' runs a regex search on a string '''
@@ -63,24 +94,8 @@ def WriteLine(my_file, text):
my_file.write(text + "\n")
def ExecuteScript(script):
''' Execute a command
Executes a given command by forking a new process and
calling run-script.py
'''
pid = os.fork()
if not pid:
os.setsid()
os.umask(0)
pid = os.fork()
if not pid:
print Run('./run-script.py ' + script)
os._exit(0)
os._exit(0)
os.wait()
''' Execute a command '''
os.system(script + ' &')
def ReadFile(filename):
''' read in a file and return it's contents as a string '''
@@ -227,6 +242,13 @@ def to_unicode(x):
else:
return x.decode('utf-8').encode('utf-8')
def error(parent, message):
""" Shows an error dialog """
dialog = gtk.MessageDialog(parent, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR,
gtk.BUTTONS_OK)
dialog.set_markup(message)
dialog.run()
dialog.destroy()
class LogWriter():

View File

@@ -48,6 +48,7 @@ import misc
import wnettools
import wpath
import os
import time
if __name__ == '__main__':
wpath.chdir(__file__)
@@ -104,6 +105,8 @@ class ConnectThread(threading.Thread):
self.wireless_interface = wireless
self.wired_interface = wired
self.is_connecting = False
self.is_aborted = False
self.abort_msg = None
self.before_script = before_script
self.after_script = after_script
self.disconnect_script = disconnect_script
@@ -123,7 +126,9 @@ class ConnectThread(threading.Thread):
"""
self.lock.acquire()
try:
self.connecting_message = status
finally:
self.lock.release()
@@ -135,7 +140,9 @@ class ConnectThread(threading.Thread):
"""
self.lock.acquire()
try:
message = self.connecting_message
finally:
self.lock.release()
return message
@@ -147,11 +154,12 @@ class ConnectThread(threading.Thread):
"""
self.SetStatus(reason)
self.is_aborted = True
self.abort_msg = reason
self.is_connecting = False
print 'exiting connection thread'
class Wireless(Controller):
""" A wrapper for common wireless interface functions. """
@@ -394,7 +402,7 @@ class WirelessConnectThread(ConnectThread):
return
# Execute pre-connection script if necessary
if self.before_script != '' and self.before_script != None:
if self.before_script != '' and self.before_script is not None:
print 'Executing pre-connection script'
misc.ExecuteScript(self.before_script)
@@ -427,7 +435,7 @@ class WirelessConnectThread(ConnectThread):
# Check to see if we need to generate a PSK (only for non-ralink
# cards).
if self.wpa_driver != 'ralink legacy':
if not self.network.get('key') == None:
if not self.network.get('key') is None:
self.SetStatus('generating_psk')
print 'Generating psk...'
@@ -437,10 +445,11 @@ class WirelessConnectThread(ConnectThread):
misc.Run('wpa_passphrase "' + self.network['essid'] +
'" "' + self.network['key'] + '"'))
# Generate the wpa_supplicant file...
if not self.network.get('enctype') == None:
if self.network.get('enctype') is not None:
self.SetStatus('generating_wpa_config')
print 'Attempting to authenticate...'
wiface.Authenticate(self.network)
auth_time = time.time()
if self.should_die:
wiface.Up()
@@ -464,16 +473,30 @@ class WirelessConnectThread(ConnectThread):
self.connect_aborted('aborted')
return
if self.network.get('enctype') is not None:
# Allow some time for wpa_supplicant to associate.
# Hopefully 3 sec is enough. If it proves to be inconsistent,
# we might have to try to monitor wpa_supplicant more closely,
# so we can tell exactly when it fails/succeeds.
elapsed = time.time() - auth_time
if elapsed < 3 and elapsed >= 0:
time.sleep(3 - elapsed)
# Make sure wpa_supplicant was able to associate.
if not wiface.ValidateAuthentication():
self.connect_aborted('bad_pass')
return
wiface.SetMode(self.network['mode'])
wiface.Associate(self.network['essid'],
self.network['channel'], self.network['bssid'])
wiface.Associate(self.network['essid'], self.network['channel'],
self.network['bssid'])
# Authenticate after association for Ralink legacy cards.
if self.wpa_driver == 'ralink legacy':
if self.network.get('key') != None:
if self.network.get('key') is not None:
wiface.Authenticate(self.network)
if not self.network.get('broadcast') == None:
if self.network.get('broadcast') is not None:
self.SetStatus('setting_broadcast_address')
print 'Setting the broadcast address...' + self.network['broadcast']
@@ -483,18 +506,20 @@ class WirelessConnectThread(ConnectThread):
self.connect_aborted('aborted')
return
if not self.network.get('ip') == None:
if self.network.get('ip') is not None:
self.SetStatus('setting_static_ip')
print 'Setting static IP : ' + self.network['ip']
wiface.SetAddress(self.network['ip'], self.network['netmask'])
print 'Setting default gateway : ' + self.network['gateway']
wiface.SetDefaultRoute(self.network['gateway'])
else:
# Run dhcp...
# Run DHCP...
self.SetStatus('running_dhcp')
print "Running DHCP"
if not self.should_die:
wiface.StartDHCP()
dhcp_status = wiface.StartDHCP()
if dhcp_status in ['no_dhcp_offers', 'dhcp_failed']:
self.connect_aborted(dhcp_status)
return
if ((self.network.get('dns1') or self.network.get('dns2') or
self.network.get('dns3')) and self.network.get('use_static_dns')):
@@ -697,8 +722,10 @@ class WiredConnectThread(ConnectThread):
# Run dhcp...
self.SetStatus('running_dhcp')
print "Running DHCP"
if not self.should_die:
liface.StartDHCP()
dhcp_status = liface.StartDHCP()
if dhcp_status in ['no_dhcp_offers', 'dhcp_failed']:
self.connect_aborted(dhcp_status)
return
if ((self.network.get('dns1') or self.network.get('dns2') or
self.network.get('dns3')) and self.network.get('use_static_dns')):

27
wicd.py
View File

@@ -42,6 +42,7 @@ import gobject
import dbus
import dbus.service
import getopt
import time
# Import egg.trayicon if we're using an older gtk version
if not (gtk.gtk_version[0] >= 2 and gtk.gtk_version[1] >= 10):
@@ -80,8 +81,15 @@ try:
proxy_obj = bus.get_object('org.wicd.daemon', '/org/wicd/daemon')
print 'Success.'
except Exception:
print 'Daemon not running...'
print 'Can\'t connect to the daemon, trying to start it automatically...'
misc.PromptToStartDaemon()
time.sleep(1)
try:
print 'Attempting to connect tray to daemon...'
proxy_obj = bus.get_object('org.wicd.daemon', '/org/wicd/daemon')
print 'Success.'
except:
print 'Failed to start daemon. Aborting.'
sys.exit(1)
daemon = dbus.Interface(proxy_obj, 'org.wicd.daemon')
@@ -108,12 +116,12 @@ class TrayIcon():
self.tr = self.EggTrayIconGUI(use_tray)
else:
self.tr = self.StatusTrayIconGUI(use_tray)
self.icon_info = self.TrayConnectionInfo(self.tr)
self.icon_info = self.TrayConnectionInfo(self.tr, use_tray)
class TrayConnectionInfo():
"""Class for updating the tray icon status"""
def __init__(self, tr):
def __init__(self, tr, use_tray=True):
"""Initialize variables needed for the icon status methods."""
self.last_strength = -2
self.still_wired = False
@@ -121,6 +129,7 @@ class TrayIcon():
self.tried_reconnect = False
self.connection_lost_counter = 0
self.tr = tr
self.use_tray = use_tray
self.update_tray_icon()
def wired_profile_chooser(self):
@@ -130,6 +139,7 @@ class TrayIcon():
def update_tray_icon(self):
"""Updates the tray icon and current connection status"""
if self.use_tray == False: return False
# If we're currently connecting, we can shortcut all other checks
if daemon.CheckIfConnecting():
@@ -205,7 +215,9 @@ class TrayIcon():
class TrayIconGUI():
"""Base Tray Icon class
Implements methods and variables used by both egg/StatusIcon tray icons.
Implements methods and variables used by both egg/StatusIcon
tray icons.
"""
def __init__(self, use_tray):
menu = """
@@ -396,20 +408,18 @@ def main(argv):
if opt in ('-h', '--help'):
usage()
sys.exit()
if opt in ('-n', '--no-tray'):
elif opt in ('-n', '--no-tray'):
use_tray = False
# Redirect stderr and stdout for logging purposes
#sys.stderr = log
#sys.stdout = log
print 'Done initalizing, starting...'
# Set up the tray icon GUI and backend
tray_icon = TrayIcon(use_tray)
# Check to see if wired profile chooser was called before icon
# was launched (typically happens on startup or daemon restart)
# was launched (typically happens on startup or daemon restart).
if daemon.GetNeedWiredProfileChooser():
daemon.SetNeedWiredProfileChooser(False)
tray_icon.icon_info.wired_profile_chooser()
@@ -419,6 +429,7 @@ def main(argv):
bus.add_signal_receiver(tray_icon.icon_info.update_tray_icon,
'StatusChanged', 'org.wicd.daemon')
print 'Done.'
mainloop = gobject.MainLoop()
mainloop.run()

View File

@@ -33,6 +33,7 @@ class WirelessInterface() -- Control a wireless network interface.
import misc
import re
import wpath
import time
# Compile the regex patterns that will be used to search the output of iwlist
# scan for info these are well tested, should work on most cards
@@ -54,6 +55,11 @@ altwpa_pattern = re.compile('(wpa_ie)', re.I | re.M | re.S)
wpa1_pattern = re.compile('(WPA Version 1)', re.I | re.M | re.S)
wpa2_pattern = re.compile('(WPA2)', re.I | re.M | re.S)
# Patterns for wpa_cli output
auth_pattern = re.compile('.*wpa_state=(.*?)\n', re.I | re.M | re.S)
RALINK_DRIVER = 'ralink legacy'
def SetDNS(dns1=None, dns2=None, dns3=None):
""" Set the DNS of the system to the specified DNS servers.
@@ -140,12 +146,53 @@ class Interface(object):
if self.verbose: print cmd
misc.Run(cmd)
def _parse_dhclient(self, pipe):
""" Parse the output of dhclient
Parses the output of dhclient and returns the status of
the connection attempt.
"""
dhclient_complete = False
dhclient_success = False
dh_no_offers = False
while not dhclient_complete:
line = pipe.readline()
if line == '': # Empty string means dhclient is done.
dhclient_complete = True
else:
print line.strip('\n')
if line.startswith('bound'):
dhclient_success = True
dhclient_complete = True
if line.startswith('No DHCPOFFERS'):
# We don't break in this case because dhclient will
# try to use an old lease if possible, so we may
# still make a successful connection.
dh_no_offers = True
if dhclient_success:
print 'DHCP connection successful'
return 'success'
if dh_no_offers:
print 'DHCP connection failed: No DHCP offers recieved'
return 'no_dhcp_offers'
else:
print 'DHCP connection failed: Reason unknown'
return 'dhcp_failed'
def StartDHCP(self):
""" Start the DHCP client to obtain an IP address. """
# TODO: Not all distros use dhclient to get an IP. We should
# add a way to determine what method is used (or let the user tell
# us), and run the cmd based on that.
cmd = 'dhclient ' + self.iface
if self.verbose: print cmd
misc.Run(cmd)
pipe = misc.Run(cmd, include_stderr=True, return_pipe=True)
return self._parse_dhclient(pipe)
def StopDHCP(self):
@@ -202,19 +249,34 @@ class WiredInterface(Interface):
def GetPluggedIn(self):
""" Get the current physical connection state. """
mii_tool_data = misc.Run( 'mii-tool ' + self.iface,True)
if not misc.RunRegex(re.compile('(Invalid argument)',re.DOTALL | re.I | re.M | re.S),mii_tool_data) == None:
""" Get the current physical connection state.
The method will first attempt to use ethtool do determine
physical connection state. Should ethtool fail to run properly,
mii-tool will be used instead.
"""
link_tool = 'ethtool'
tool_data = misc.Run(link_tool + ' ' + self.iface, True)
if misc.RunRegex(re.compile('(Operation not supported)|\
(ethtool: command not found)', re.I),
tool_data) is not None:
print "ethtool check failed, falling back to mii-tool"
link_tool = 'mii-tool'
if misc.RunRegex(re.compile('(Invalid argument)', re.I | re.M | re.S),
tool_data) is not None:
print 'wired interface appears down, putting up for mii-tool check'
misc.Run( 'ifconfig ' + self.iface + ' up' )
mii_tool_data = misc.Run( 'mii-tool ' + self.iface)
if not misc.RunRegex(re.compile('(link ok)',re.DOTALL | re.I | re.M | re.S),mii_tool_data) == None:
self.Up()
tool_data = misc.Run(link_tool + ' ' + self.iface)
if misc.RunRegex(re.compile('(Link detected: yes)|(link ok)',
re.I | re.M | re.S), tool_data) is not None:
return True
else:
return False
class WirelessInterface(Interface):
""" Control a wireless network interface. """
def __init__(self, iface, verbose=False, wpa_driver='wext'):
@@ -267,7 +329,7 @@ class WirelessInterface(Interface):
# Get available network info from iwpriv get_site_survey
# if we're using a ralink card (needed to get encryption info)
if self.wpa_driver == 'ralink legacy':
if self.wpa_driver == RALINK_DRIVER:
ralink_info = self._GetRalinkScanInfo()
else:
ralink_info = None
@@ -372,7 +434,7 @@ class WirelessInterface(Interface):
ap['mode'] = misc.RunRegex(mode_pattern, cell)
# Break off here if we're using a ralink card
if self.wpa_driver == 'ralink legacy':
if self.wpa_driver == RALINK_DRIVER:
ap = self._ParseRalinkAccessPoint(ap, ralink_info, cell)
elif misc.RunRegex(wep_pattern, cell) == 'on':
# Encryption - Default to WEP
@@ -410,7 +472,7 @@ class WirelessInterface(Interface):
# quality displayed or it isn't found)
if misc.RunRegex(signaldbm_pattern, cell):
ap['strength'] = misc.RunRegex(signaldbm_pattern, cell)
elif self.wpa_driver != 'ralink legacy': # This is already set for ralink
elif self.wpa_driver != RALINK_DRIVER: # This is already set for ralink
ap['strength'] = -1
return ap
@@ -521,7 +583,7 @@ class WirelessInterface(Interface):
"""
misc.ParseEncryption(network)
if self.wpa_driver == 'ralink legacy':
if self.wpa_driver == RALINK_DRIVER:
self._AuthenticateRalinkLegacy(network)
else:
cmd = ('wpa_supplicant -B -i ' + self.iface + ' -c "'
@@ -530,6 +592,52 @@ class WirelessInterface(Interface):
if self.verbose: print cmd
misc.Run(cmd)
def ValidateAuthentication(self):
""" Validate WPA authentication.
Validate that the wpa_supplicant authentication
process was successful.
NOTE: It's possible this could return False,
even though in actuality wpa_supplicant just isn't
finished yet.
"""
# Right now there's no way to do this for these drivers
if self.wpa_driver == RALINK_DRIVER:
return True
cmd = 'wpa_cli -i ' + self.iface + ' status'
if self.verbose: print cmd
output = misc.Run(cmd)
result = misc.RunRegex(auth_pattern, output)
if result == "COMPLETED":
return True
elif result =="DISCONNECTED":
# Force a rescan to get wpa_supplicant moving again.
self._ForceSupplicantScan()
return self.ValidateAuthentication()
else:
print 'wpa_supplicant authentication may have failed.'
return False
pass
def _ForceSupplicantScan(self):
""" Force wpa_supplicant to rescan available networks.
This function forces wpa_supplicant to rescan, then sleeps
to allow the scan to finish and reassociation to take place.
This works around authentication validation failing for
wpa_supplicant sometimes becaues it remains in a DISCONNECTED
state for quite a while, before a rescan takes places, all before
even attempting to authenticate.
"""
print 'wpa_supplicant rescan forced...'
cmd = 'wpa_cli -i' + self.iface + ' scan'
misc.Run(cmd)
time.sleep(5)
print 'Trying to validate authentication again'
def _AuthenticateRalinkLegacy(self, network):
""" Authenticate with the specified wireless network.