diff --git a/autoconnect.py b/autoconnect.py
index 810eb09..84336ba 100644
--- a/autoconnect.py
+++ b/autoconnect.py
@@ -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:
diff --git a/configscript.py b/configscript.py
index 648dbf3..791aeef 100755
--- a/configscript.py
+++ b/configscript.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
-"""Configure the scripts for a particular network
+""" Configure the scripts for a particular network
Script for configuring the scripts for a network passed in as a
command line argument. This needs to run a separate process because
@@ -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 .
#
+
import os
import sys
import gtk
diff --git a/daemon.py b/daemon.py
index 6b7678a..88b6280 100644
--- a/daemon.py
+++ b/daemon.py
@@ -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")
diff --git a/encryption/templates/eap b/encryption/templates/eap
index 243b104..6a6e649 100644
--- a/encryption/templates/eap
+++ b/encryption/templates/eap
@@ -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
diff --git a/encryption/templates/leap b/encryption/templates/leap
index c1478ed..3427e75 100644
--- a/encryption/templates/leap
+++ b/encryption/templates/leap
@@ -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
diff --git a/encryption/templates/peap b/encryption/templates/peap
index fd5a763..9010a2c 100644
--- a/encryption/templates/peap
+++ b/encryption/templates/peap
@@ -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
diff --git a/encryption/templates/peap-tkip b/encryption/templates/peap-tkip
index fbcf3fe..df141ae 100755
--- a/encryption/templates/peap-tkip
+++ b/encryption/templates/peap-tkip
@@ -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
diff --git a/encryption/templates/ttls b/encryption/templates/ttls
index ad396ac..c4e8af4 100644
--- a/encryption/templates/ttls
+++ b/encryption/templates/ttls
@@ -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
diff --git a/encryption/templates/wep b/encryption/templates/wep
index 12c019a..1fdac19 100644
--- a/encryption/templates/wep
+++ b/encryption/templates/wep
@@ -3,6 +3,7 @@ author = Adam Blackburn
version = 1
require key *Key
-----
+ctrl_interface=/var/run/wpa_supplicant
network={
ssid="$_ESSID"
scan_ssid=$_SCAN
diff --git a/encryption/templates/wpa b/encryption/templates/wpa
index 97c3271..c618bcb 100644
--- a/encryption/templates/wpa
+++ b/encryption/templates/wpa
@@ -3,6 +3,7 @@ author = Adam Blackburn
version = 1
require key *Key
-----
+ctrl_interface=/var/run/wpa_supplicant
network={
ssid="$_ESSID"
scan_ssid=$_SCAN
diff --git a/gui.py b/gui.py
index 7199a9f..49d5f48 100644
--- a/gui.py
+++ b/gui.py
@@ -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,10 +102,10 @@ 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
-#I'm not sure this is the best way to do it
-#but it works and makes it easy for me :)
+# 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 :)
##########
# translations are done at
# http://wicd.net/translator
@@ -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
- #and also enable the DNS checkbox when
- #disabled and disable when enabled
-
+ # Should disable the static IP text boxes,
+ # and also enable the DNS checkbox when
+ # 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__':
diff --git a/launchdaemon.sh b/launchdaemon.sh
new file mode 100755
index 0000000..814e670
--- /dev/null
+++ b/launchdaemon.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+echo "Starting wicd daemon..."
+/opt/wicd/daemon.py 2> /dev/null
+
diff --git a/misc.py b/misc.py
index c8f014c..adca870 100644
--- a/misc.py
+++ b/misc.py
@@ -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 .
#
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():
diff --git a/networking.py b/networking.py
index 36b3ed8..79c3a9f 100644
--- a/networking.py
+++ b/networking.py
@@ -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,8 +126,10 @@ class ConnectThread(threading.Thread):
"""
self.lock.acquire()
- self.connecting_message = status
- self.lock.release()
+ try:
+ self.connecting_message = status
+ finally:
+ self.lock.release()
def GetStatus(self):
@@ -135,8 +140,10 @@ class ConnectThread(threading.Thread):
"""
self.lock.acquire()
- message = self.connecting_message
- self.lock.release()
+ try:
+ message = self.connecting_message
+ finally:
+ self.lock.release()
return message
def connect_aborted(self, reason):
@@ -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')):
diff --git a/wicd.py b/wicd.py
index 542fff2..dc54e86 100755
--- a/wicd.py
+++ b/wicd.py
@@ -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()
diff --git a/wnettools.py b/wnettools.py
index 0337063..3db01b8 100644
--- a/wnettools.py
+++ b/wnettools.py
@@ -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.