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

Experimental:

- Add new logging system which rotates the log file once it reaches a set size.
- Merge in fixes and new features from pluggablebackends and trunk
- Right click network menu in tray icon now bolds the active network.
This commit is contained in:
imdano
2008-08-19 19:06:26 +00:00
parent 1c2fbd4918
commit 57b03dd434
9 changed files with 398 additions and 159 deletions

107
daemon.py
View File

@@ -55,72 +55,13 @@ else:
import wpath import wpath
import networking import networking
import misc import misc
from logfile import ManagedStdio
if __name__ == '__main__': if __name__ == '__main__':
wpath.chdir(__file__) wpath.chdir(__file__)
misc.RenameProcess("wicd-daemon") misc.RenameProcess("wicd-daemon")
logging_enabled = True
class LogWriter:
""" A class to provide timestamped logging. """
def __init__(self):
self.file = open(wpath.log + 'wicd.log', 'a')
self.eol = True
def __del__(self):
self.file.close()
def write(self, data):
""" Writes the data to the log with a timestamp.
This function handles writing of data to a log file. In order to
handle output redirection, we need to be careful with how we
handle the addition of timestamps. In any set of data that is
written, we replace the newlines with a timestamp + new line,
except for newlines that are the final character in data.
When a newline is the last character in data, we set a flag to
indicate that the next write should have a timestamp prepended
as well, which ensures that the timestamps match the time at
which the data is written, rather than the previous write.
Keyword arguments:
data -- The string to write to the log.
"""
global logging_enabled
data = data.decode('utf-8').encode('utf-8')
if len(data) <= 0: return
if logging_enabled:
if self.eol:
self.file.write(self.get_time() + ' :: ')
self.eol = False
if data[-1] == '\n':
self.eol = True
data = data[:-1]
self.file.write(
data.replace('\n', '\n' + self.get_time() + ' :: '))
if self.eol: self.file.write('\n')
self.file.flush()
def get_time(self):
""" Return a string with the current time nicely formatted.
The format of the returned string is yyyy/mm/dd HH:MM:SS
"""
x = time.localtime()
return ''.join([
str(x[0]).rjust(4, '0'), '/', str(x[1]).rjust(2, '0'), '/',
str(x[2]).rjust(2, '0'), ' ', str(x[3]).rjust(2, '0'), ':',
str(x[4]).rjust(2, '0'), ':', str(x[5]).rjust(2, '0')])
class ConnectionWizard(dbus.service.Object): class ConnectionWizard(dbus.service.Object):
def __init__(self, bus_name, object_path='/org/wicd/daemon', def __init__(self, bus_name, object_path='/org/wicd/daemon',
@@ -353,7 +294,6 @@ class ConnectionWizard(dbus.service.Object):
""" """
if fresh: if fresh:
self.Scan() self.Scan()
#self.AutoConnectScan() # Also scans for hidden networks
if self.CheckPluggedIn(True): if self.CheckPluggedIn(True):
self._wired_autoconnect() self._wired_autoconnect()
else: else:
@@ -382,7 +322,7 @@ class ConnectionWizard(dbus.service.Object):
return return
# Last-Used. # Last-Used.
else: # Assume its last-used. else:
network = self.GetLastUsedWiredNetwork() network = self.GetLastUsedWiredNetwork()
if not network: if not network:
print "no previous wired profile available, wired " + \ print "no previous wired profile available, wired " + \
@@ -650,8 +590,15 @@ class ConnectionWizard(dbus.service.Object):
@dbus.service.method('org.wicd.daemon') @dbus.service.method('org.wicd.daemon')
@dbus.service.signal(dbus_interface='org.wicd.daemon', signature='') @dbus.service.signal(dbus_interface='org.wicd.daemon', signature='')
def SendScanSignal(self): def SendStartScanSignal(self):
""" Emits a signal announcing a scan has occurred. """ """ Emits a signal announcing a scan has started. """
pass
@dbus.service.method('org.wicd.daemon')
@dbus.service.signal(dbus_interface='org.wicd.daemon', signature='')
def SendEndScanSignal(self):
""" Emits a signal announcing a scan has finished. """
pass pass
########## WIRELESS FUNCTIONS ########## WIRELESS FUNCTIONS
@@ -672,13 +619,16 @@ class ConnectionWizard(dbus.service.Object):
""" """
if self.debug_mode: if self.debug_mode:
print 'scanning start' print 'scanning start'
scan = self.wifi.Scan(str(self.hidden_essid)) self.SendStartScanSignal()
time.sleep(.2)
scan = self.wifi.Scan(str(self.hidden_essid), fast=True)
self.LastScan = scan self.LastScan = scan
if self.debug_mode: if self.debug_mode:
print 'scanning done' print 'scanning done'
print 'found ' + str(len(scan)) + ' networks:' print 'found ' + str(len(scan)) + ' networks:'
for i, network in enumerate(scan): for i, network in enumerate(scan):
self.ReadWirelessNetworkProfile(i) self.ReadWirelessNetworkProfile(i)
self.SendEndScanSignal()
@dbus.service.method('org.wicd.daemon.wireless') @dbus.service.method('org.wicd.daemon.wireless')
def GetIwconfig(self): def GetIwconfig(self):
@@ -1353,7 +1303,6 @@ class ConnectionWizard(dbus.service.Object):
self.SetAlwaysShowWiredInterface(self.get_option("Settings", self.SetAlwaysShowWiredInterface(self.get_option("Settings",
"always_show_wired_interface", "always_show_wired_interface",
default=False)) default=False))
self.SetUseGlobalDNS(self.get_option("Settings", "use_global_dns", self.SetUseGlobalDNS(self.get_option("Settings", "use_global_dns",
default=False)) default=False))
dns1 = self.get_option("Settings", "global_dns_1", default='None') dns1 = self.get_option("Settings", "global_dns_1", default='None')
@@ -1507,6 +1456,17 @@ def daemonize():
print >> sys.stderr, "Fork #2 failed: %d (%s)" % (e.errno, e.strerror) print >> sys.stderr, "Fork #2 failed: %d (%s)" % (e.errno, e.strerror)
sys.exit(1) sys.exit(1)
sys.stdout.flush()
sys.stderr.flush()
os.close(sys.__stdin__.fileno())
os.close(sys.__stdout__.fileno())
os.close(sys.__stderr__.fileno())
# stdin always from /dev/null
sys.stdin = open('/dev/null', 'r')
def main(argv): def main(argv):
""" The main daemon program. """ The main daemon program.
@@ -1521,15 +1481,16 @@ def main(argv):
auto_scan = True auto_scan = True
try: try:
opts, args = getopt.getopt(sys.argv[1:], 'fenosP:', opts, args = getopt.getopt(sys.argv[1:], 'fenoahi:',
['help', 'no-daemon', 'no-poll', 'no-stderr', 'no-stdout', ['help', 'no-daemon', 'no-poll', 'no-stderr', 'no-stdout',
'no-scan']) 'no-autoconnect', 'scan-interval'])
except getopt.GetoptError: except getopt.GetoptError:
# Print help information and exit # Print help information and exit
usage() usage()
sys.exit(2) sys.exit(2)
no_poll = False no_poll = False
scan_interval = "120000"
for o, a in opts: for o, a in opts:
if o in ('-h', '--help'): if o in ('-h', '--help'):
usage() usage()
@@ -1540,17 +1501,18 @@ def main(argv):
redirect_stdout = False redirect_stdout = False
if o in ('-f', '--no-daemon'): if o in ('-f', '--no-daemon'):
do_daemonize = False do_daemonize = False
if o in ('-s', '--no-scan'): if o in ('-a', '--no-autoconnect'):
auto_scan = False auto_scan = False
if o in ('-n', '--no-poll'): if o in ('-n', '--no-poll'):
no_poll = True no_poll = True
if o in ('i', '--scan-interval'):
scan_interval = a
if do_daemonize: daemonize() if do_daemonize: daemonize()
if redirect_stderr or redirect_stdout: output = LogWriter() if redirect_stderr or redirect_stdout: output = ManagedStdio(wpath.log + 'wicd.log')
if redirect_stdout: sys.stdout = output if redirect_stdout: sys.stdout = output
if redirect_stderr: sys.stderr = output if redirect_stderr: sys.stderr = output
time.sleep(1)
print '---------------------------' print '---------------------------'
print 'wicd initializing...' print 'wicd initializing...'
@@ -1563,7 +1525,8 @@ def main(argv):
gobject.threads_init() gobject.threads_init()
if not no_poll: if not no_poll:
(child_pid, x, x, x) = gobject.spawn_async([wpath.bin + "monitor.py"], (child_pid, x, x, x) = gobject.spawn_async([wpath.bin + "monitor.py",
scan_interval],
flags=gobject.SPAWN_CHILD_INHERITS_STDIN) flags=gobject.SPAWN_CHILD_INHERITS_STDIN)
signal.signal(signal.SIGTERM, sigterm_caught) signal.signal(signal.SIGTERM, sigterm_caught)

16
gui.py
View File

@@ -706,7 +706,6 @@ class appGui:
state, x = daemon.GetConnectionStatus() state, x = daemon.GetConnectionStatus()
if self.prev_state != state or force_check: if self.prev_state != state or force_check:
print 'we actually update now'
apbssid = wireless.GetApBssid() apbssid = wireless.GetApBssid()
for entry in self.network_list: for entry in self.network_list:
if hasattr(entry, "update_connect_button"): if hasattr(entry, "update_connect_button"):
@@ -751,7 +750,7 @@ class appGui:
""" Sets the status bar message for the GUI. """ """ Sets the status bar message for the GUI. """
self.statusID = self.status_bar.push(1, msg) self.statusID = self.status_bar.push(1, msg)
def dbus_refresh_networks(self): def dbus_scan_finished(self):
""" Calls for a non-fresh update of the gui window. """ Calls for a non-fresh update of the gui window.
This method is called after the daemon runs an automatic This method is called after the daemon runs an automatic
@@ -761,6 +760,9 @@ class appGui:
if not self.connecting: if not self.connecting:
self.refresh_networks(fresh=False) self.refresh_networks(fresh=False)
def dbus_scan_started(self):
self.network_list.set_sensitive(False)
def refresh_networks(self, widget=None, fresh=True, hidden=None): def refresh_networks(self, widget=None, fresh=True, hidden=None):
""" Refreshes the network list. """ Refreshes the network list.
@@ -799,7 +801,6 @@ class appGui:
wireless.Scan() wireless.Scan()
num_networks = wireless.GetNumberOfNetworks() num_networks = wireless.GetNumberOfNetworks()
instruct_label = self.wTree.get_widget("label_instructions") instruct_label = self.wTree.get_widget("label_instructions")
if num_networks > 0: if num_networks > 0:
instruct_label.show() instruct_label.show()
@@ -840,7 +841,7 @@ class appGui:
# First make sure all the Addresses entered are valid. # First make sure all the Addresses entered are valid.
if entry.chkbox_static_ip.get_active(): if entry.chkbox_static_ip.get_active():
enlist = [ent for ent in [entry.txt_ip, entry.txt_netmask, entlist = [ent for ent in [entry.txt_ip, entry.txt_netmask,
entry.txt_gateway]] entry.txt_gateway]]
if entry.chkbox_static_dns.get_active() and \ if entry.chkbox_static_dns.get_active() and \
@@ -850,7 +851,6 @@ class appGui:
for ent in [entry.txt_dns_2, entry.txt_dns_3]: for ent in [entry.txt_dns_2, entry.txt_dns_3]:
if ent.get_text() != "": if ent.get_text() != "":
entlist.append(ent) entlist.append(ent)
for lblent in entlist: for lblent in entlist:
if not misc.IsValidIP(lblent.get_text()): if not misc.IsValidIP(lblent.get_text()):
error(self.window, language['invalid_address']. error(self.window, language['invalid_address'].
@@ -1103,6 +1103,10 @@ if __name__ == '__main__':
sys.exit(1) sys.exit(1)
app = appGui(standalone=True) app = appGui(standalone=True)
bus.add_signal_receiver(app.dbus_refresh_networks, 'SendScanSignal', bus.add_signal_receiver(app.dbus_scan_finished, 'SendEndScanSignal',
'org.wicd.daemon')
bus.add_signal_receiver(app.dbus_scan_started, 'SendStartScanSignal',
'org.wicd.daemon')
bus.add_signal_receiver(app.update_connect_buttons, 'StatusChanged',
'org.wicd.daemon') 'org.wicd.daemon')
gtk.main() gtk.main()

175
logfile.py Normal file
View File

@@ -0,0 +1,175 @@
#!/usr/bin/python
#
# Copyright (C) 1999-2006 Keith Dart <keith@kdart.com>
# Copyright (C) 2008 Dan O'Reilly <oreilldf@gmail.com>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library 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
# Lesser General Public License for more details.
"""
Managing logfile rotation. A ManagedLog object is a file-like object that
rotates itself when a maximum size is reached.
"""
import sys
import os
import time
class SizeError(IOError):
pass
class LogFile(file):
"""LogFile(name, [mode="w"], [maxsize=360000])
Opens a new file object. After writing <maxsize> bytes a SizeError will be
raised. """
def __init__(self, name, mode="a", maxsize=360000):
super(LogFile, self).__init__(name, mode)
self.maxsize = maxsize
self.eol = True
try:
self.written = os.fstat(self.fileno())[6]
except OSError:
self.written = 0
def write(self, data):
self.written += len(data)
data = data.decode('utf-8').encode('utf-8')
if len(data) <= 0: return
if self.eol:
super(LogFile, self).write(self.get_time() + ' :: ')
self.eol = False
if data[-1] == '\n':
self.eol = True
data = data[:-1]
super(LogFile, self).write(data.replace(
'\n', '\n' + self.get_time() + ' :: '))
if self.eol:
super(LogFile, self).write('\n')
self.flush()
if self.written > self.maxsize:
raise SizeError
def get_time(self):
""" Return a string with the current time nicely formatted.
The format of the returned string is yyyy/mm/dd HH:MM:SS
"""
x = time.localtime()
return ''.join([
str(x[0]).rjust(4, '0'), '/', str(x[1]).rjust(2, '0'), '/',
str(x[2]).rjust(2, '0'), ' ', str(x[3]).rjust(2, '0'), ':',
str(x[4]).rjust(2, '0'), ':', str(x[5]).rjust(2, '0')])
def rotate(self):
return rotate(self)
def note(self, text):
"""Writes a specially formated note text to the file.The note starts
with the string '\\n#*=' so you can easily filter them. """
self.write("\n#*===== %s =====\n" % (text,))
class ManagedLog(object):
"""ManagedLog(name, [maxsize=360000], [maxsave=9])
A ManagedLog instance is a persistent log object. Write data with the
write() method. The log size and rotation is handled automatically.
"""
def __init__(self, name, maxsize=360000, maxsave=3):
self._lf = LogFile(name, "a", maxsize)
self.maxsave = maxsave
def __repr__(self):
return "%s(%r, %r, %r)" % (self.__class__.__name__, self._lf.name,
self._lf.maxsize, self.maxsave)
def write(self, data):
try:
self._lf.write(data)
except SizeError:
self._lf = rotate(self._lf, self.maxsave)
def note(self, data):
try:
self._lf.note(data)
except SizeError:
self._lf = rotate(self._lf, self.maxsave)
def written(self):
return self._lf.written
def rotate(self):
self._lf = rotate(self._lf, self.maxsave)
# auto-delegate remaining methods (but you should not read or seek an open
# log file).
def __getattr__(self, name):
return getattr(self._lf, name)
# useful for logged stdout for daemon processes
class ManagedStdio(ManagedLog):
def write(self, data):
try:
self._lf.write(data)
except SizeError:
sys.stdout.flush()
sys.stderr.flush()
self._lf = rotate(self._lf, self.maxsave)
fd = self._lf.fileno()
os.dup2(fd, 1)
os.dup2(fd, 2)
sys.stdout = sys.stderr = self
def rotate(fileobj, maxsave=9):
name = fileobj.name
mode = fileobj.mode
maxsize = fileobj.maxsize
fileobj.close()
shiftlogs(name, maxsave)
return LogFile(name, mode, maxsize)
# assumes basename logfile is closed.
def shiftlogs(basename, maxsave):
topname = "%s.%d" % (basename, maxsave)
if os.path.isfile(topname):
os.unlink(topname)
for i in range(maxsave, 0, -1):
oldname = "%s.%d" % (basename, i)
newname = "%s.%d" % (basename, i+1)
try:
os.rename(oldname, newname)
except OSError:
pass
try:
os.rename(basename, "%s.1" % (basename))
except OSError:
pass
def open(name, maxsize=360000, maxsave=9):
return ManagedLog(name, maxsize, maxsave)
def writelog(logobj, data):
try:
logobj.write(data)
except SizeError:
return rotate(logobj)
else:
return logobj

View File

@@ -107,7 +107,7 @@ def PromptToStartDaemon():
msg = '--caption' msg = '--caption'
sudo_args = [sudo_prog, msg, sudo_args = [sudo_prog, msg,
'Wicd needs to access your computer\'s network cards.', 'Wicd needs to access your computer\'s network cards.',
'--', daemonloc] daemonloc]
os.spawnvpe(os.P_WAIT, sudo_prog, sudo_args, os.environ) os.spawnvpe(os.P_WAIT, sudo_prog, sudo_args, os.environ)
def RunRegex(regex, string): def RunRegex(regex, string):

View File

@@ -8,8 +8,8 @@ when appropriate.
""" """
# #
# Copyright (C) 2007 Adam Blackburn # Copyright (C) 2007 - 2008 Adam Blackburn
# Copyright (C) 2007 Dan O'Reilly # Copyright (C) 2007 - 2008 Dan O'Reilly
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License Version 2 as
@@ -46,7 +46,7 @@ daemon = dbus.Interface(proxy_obj, 'org.wicd.daemon')
wired = dbus.Interface(proxy_obj, 'org.wicd.daemon.wired') wired = dbus.Interface(proxy_obj, 'org.wicd.daemon.wired')
wireless = dbus.Interface(proxy_obj, 'org.wicd.daemon.wireless') wireless = dbus.Interface(proxy_obj, 'org.wicd.daemon.wireless')
class ConnectionStatus(): class ConnectionStatus(object):
""" Class for monitoring the computer's connection status. """ """ Class for monitoring the computer's connection status. """
def __init__(self): def __init__(self):
""" Initialize variables needed for the connection status methods. """ """ Initialize variables needed for the connection status methods. """
@@ -266,9 +266,8 @@ class ConnectionStatus():
if daemon.GetSuspend() or daemon.CheckIfConnecting(): if daemon.GetSuspend() or daemon.CheckIfConnecting():
return True return True
wireless.Scan() wireless.Scan()
daemon.SendScanSignal() except dbus.exceptions.DBusException, e:
except dbus.exceptions.DBusException: print 'dbus exception while attempting rescan: %s' % str(e)
print 'dbus exception while attempting rescan'
finally: finally:
return True return True

View File

@@ -356,18 +356,18 @@ class WirelessSettingsDialog(AdvancedSettingsDialog):
self.txt_netmask.set_text(self.format_entry(networkID,"netmask")) self.txt_netmask.set_text(self.format_entry(networkID,"netmask"))
self.txt_gateway.set_text(self.format_entry(networkID,"gateway")) self.txt_gateway.set_text(self.format_entry(networkID,"gateway"))
self.chkbox_global_dns.set_active(wireless.GetWirelessProperty(networkID, self.chkbox_global_dns.set_active(bool(wireless.GetWirelessProperty(networkID,
'use_global_dns')) 'use_global_dns')))
self.txt_dns_1.set_text(self.format_entry(networkID, "dns1")) self.txt_dns_1.set_text(self.format_entry(networkID, "dns1"))
self.txt_dns_2.set_text(self.format_entry(networkID, "dns2")) self.txt_dns_2.set_text(self.format_entry(networkID, "dns2"))
self.txt_dns_3.set_text(self.format_entry(networkID, "dns3")) self.txt_dns_3.set_text(self.format_entry(networkID, "dns3"))
self.reset_static_checkboxes() self.reset_static_checkboxes()
self.chkbox_encryption.set_active(wireless.GetWirelessProperty(networkID, self.chkbox_encryption.set_active(bool(wireless.GetWirelessProperty(networkID,
'encryption')) 'encryption')))
self.chkbox_global_settings.set_active(wireless.GetWirelessProperty(networkID, self.chkbox_global_settings.set_active(bool(wireless.GetWirelessProperty(networkID,
'use_settings_globally')) 'use_settings_globally')))
activeID = -1 # Set the menu to this item when we are done activeID = -1 # Set the menu to this item when we are done
@@ -628,7 +628,7 @@ class WiredNetworkEntry(NetworkEntry):
try: try:
sudo_prog = misc.choose_sudo_prog() sudo_prog = misc.choose_sudo_prog()
msg = "You must enter your password to configure scripts" msg = "You must enter your password to configure scripts"
if sudo_prog.endswith("gksu"): if sudo_prog.endswith("gksu") or sudo_prog.endswith("ktsuss"):
msg_flag = "-m" msg_flag = "-m"
else: else:
msg_flag = "--caption" msg_flag = "--caption"
@@ -636,7 +636,7 @@ class WiredNetworkEntry(NetworkEntry):
profile, "wired"]) profile, "wired"])
except misc.WicdError: except misc.WicdError:
error("Could not find a graphical sudo program." + \ error("Could not find a graphical sudo program." + \
" Script editor could no be launched.") " Script editor could not be launched.")
def check_enable(self): def check_enable(self):
""" Disable objects if the profile list is empty. """ """ Disable objects if the profile list is empty. """
@@ -870,8 +870,10 @@ class WirelessNetworkEntry(NetworkEntry):
def update_connect_button(self, state, apbssid): def update_connect_button(self, state, apbssid):
""" Update the connection/disconnect button for this entry. """ """ Update the connection/disconnect button for this entry. """
if state == misc.WIRELESS and apbssid == \ if not apbssid:
wireless.GetWirelessProperty(self.networkID, "bssid"): apbssid = wireless.GetApBssid()
if state == misc.WIRELESS and \
apbssid == wireless.GetWirelessProperty(self.networkID, "bssid"):
self.disconnect_button.show() self.disconnect_button.show()
self.connect_button.hide() self.connect_button.hide()
else: else:
@@ -908,7 +910,7 @@ class WirelessNetworkEntry(NetworkEntry):
try: try:
sudo_prog = misc.choose_sudo_prog() sudo_prog = misc.choose_sudo_prog()
msg = "You must enter your password to configure scripts" msg = "You must enter your password to configure scripts"
if sudo_prog.endswith("gksu"): if sudo_prog.endswith("gksu") or sudo_prog.endswith("ktsuss"):
msg_flag = "-m" msg_flag = "-m"
else: else:
msg_flag = "--caption" msg_flag = "--caption"

View File

@@ -309,7 +309,7 @@ class ConnectThread(threading.Thread):
self.is_connecting = False self.is_connecting = False
print 'exiting connection thread' print 'exiting connection thread'
def abort_connection(self, reason): def abort_connection(self, reason=""):
""" Schedule a connection abortion for the given reason. """ """ Schedule a connection abortion for the given reason. """
self.abort_reason = reason self.abort_reason = reason
self.should_die = True self.should_die = True
@@ -392,6 +392,8 @@ class Wireless(Controller):
else: else:
return 0 return 0
if not self.wireless_interface: return []
wiface = self.wiface wiface = self.wiface
# Prepare the interface for scanning # Prepare the interface for scanning
@@ -416,6 +418,8 @@ class Wireless(Controller):
network -- network to connect to network -- network to connect to
""" """
if not self.wireless_interface: return False
self.connecting_thread = WirelessConnectThread(network, self.connecting_thread = WirelessConnectThread(network,
self.wireless_interface, self.wired_interface, self.wireless_interface, self.wired_interface,
self.wpa_driver, self.before_script, self.after_script, self.wpa_driver, self.before_script, self.after_script,
@@ -785,6 +789,7 @@ class Wired(Controller):
network -- network to connect to network -- network to connect to
""" """
if not self.wired_interface: return False
self.connecting_thread = WiredConnectThread(network, self.connecting_thread = WiredConnectThread(network,
self.wireless_interface, self.wired_interface, self.wireless_interface, self.wired_interface,
self.before_script, self.after_script, self.before_script, self.after_script,

79
wicd.py
View File

@@ -20,8 +20,8 @@ def main() -- Runs the wicd frontend main loop.
""" """
# #
# Copyright (C) 2007 Adam Blackburn # Copyright (C) 2007 - 2008 Adam Blackburn
# Copyright (C) 2007 Dan O'Reilly # Copyright (C) 2007 - 2008 Dan O'Reilly
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License Version 2 as
@@ -43,6 +43,7 @@ import dbus
import dbus.service import dbus.service
import getopt import getopt
import os import os
import pango
# Wicd specific imports # Wicd specific imports
import wpath import wpath
@@ -66,7 +67,7 @@ else:
from dbus.mainloop.glib import DBusGMainLoop from dbus.mainloop.glib import DBusGMainLoop
DBusGMainLoop(set_as_default=True) DBusGMainLoop(set_as_default=True)
misc.RenameProcess("wicd") misc.RenameProcess("wicd-client")
if __name__ == '__main__': if __name__ == '__main__':
wpath.chdir(__file__) wpath.chdir(__file__)
@@ -80,6 +81,20 @@ config = None
language = misc.get_language_list_tray() language = misc.get_language_list_tray()
class NetworkMenuItem(gtk.ImageMenuItem):
def __init__(self, lbl, is_active=False):
gtk.ImageMenuItem.__init__(self)
self.label = gtk.Label(lbl)
if is_active:
atrlist = pango.AttrList()
atrlist.insert(pango.AttrWeight(pango.WEIGHT_BOLD, 0, 50))
self.label.set_attributes(atrlist)
self.label.set_justify(gtk.JUSTIFY_LEFT)
self.label.set_alignment(0, 0)
self.add(self.label)
self.label.show()
class TrayIcon: class TrayIcon:
""" Base Tray Icon class. """ Base Tray Icon class.
@@ -320,11 +335,16 @@ class TrayIcon:
props.parent) props.parent)
self.gui_win = None self.gui_win = None
self.current_icon_path = None self.current_icon_path = None
self.dbus_available = True
self.use_tray = use_tray self.use_tray = use_tray
def on_activate(self, data=None): def on_activate(self, data=None):
""" Opens the wicd GUI. """ """ Opens the wicd GUI. """
try:
self.toggle_wicd_gui() self.toggle_wicd_gui()
except dbus.DBusException:
self.dbus_available = False
gui.error(None, "Could not connect to wicd daemon. Unable to load GUI")
def on_quit(self, widget=None): def on_quit(self, widget=None):
""" Closes the tray icon. """ """ Closes the tray icon. """
@@ -340,19 +360,20 @@ class TrayIcon:
dialog.run() dialog.run()
dialog.destroy() dialog.destroy()
def _add_item_to_menu(self, net_menu, lbl, type_, n_id, is_connecting): def _add_item_to_menu(self, net_menu, lbl, type_,
n_id, is_connecting, is_active):
""" Add an item to the network list submenu. """ """ Add an item to the network list submenu. """
def network_selected(widget, net_type, net_id): def network_selected(widget, net_type, net_id):
""" Callback method for a menu item selection. """ """ Callback method for a menu item selection. """
if net_type == "wired": if net_type == "__wired__":
wired.ConnectWired() wired.ConnectWired()
else: else:
wireless.ConnectWireless(net_id) wireless.ConnectWireless(net_id)
item = gtk.ImageMenuItem(lbl) item = NetworkMenuItem(lbl, is_active)
image = gtk.Image() image = gtk.Image()
if type_ == "wired": if type_ == "__wired__":
image.set_from_icon_name("network-wired", 2) image.set_from_icon_name("network-wired", 2)
else: else:
pb = gtk.gdk.pixbuf_new_from_file_at_size(self._get_img(n_id), pb = gtk.gdk.pixbuf_new_from_file_at_size(self._get_img(n_id),
@@ -411,21 +432,29 @@ class TrayIcon:
net_menu = gtk.Menu() net_menu = gtk.Menu()
is_connecting = daemon.CheckIfConnecting() is_connecting = daemon.CheckIfConnecting()
num_networks = wireless.GetNumberOfNetworks() num_networks = wireless.GetNumberOfNetworks()
#TODO Eventually do something to indicate the active network. [status, info] = daemon.GetConnectionStatus()
#[status, info] = daemon.GetConnectionStatus()
if wired.GetAlwaysShowWiredInterface() or \ if wired.GetAlwaysShowWiredInterface() or \
wired.CheckPluggedIn(True): wired.CheckPluggedIn(True):
self._add_item_to_menu(net_menu, "Wired Network", "wired", 0, if status == misc.WIRED:
is_connecting) is_active = True
else:
is_active = False
self._add_item_to_menu(net_menu, "Wired Network", "__wired__",
0, is_connecting, is_active)
sep = gtk.SeparatorMenuItem() sep = gtk.SeparatorMenuItem()
net_menu.append(sep) net_menu.append(sep)
sep.show() sep.show()
if num_networks > 0: if num_networks > 0:
for x in range(0, num_networks): for x in range(0, num_networks):
self._add_item_to_menu(net_menu, get_prop(x, "essid"), essid = get_prop(x, "essid")
"wifi", x, is_connecting) if status == misc.WIRELESS and info[1] == essid:
is_active = True
else:
is_active = False
self._add_item_to_menu(net_menu, essid, "wifi", x,
is_connecting, is_active)
net_menuitem.set_submenu(net_menu) net_menuitem.set_submenu(net_menu)
net_menuitem.show() net_menuitem.show()
@@ -434,8 +463,12 @@ class TrayIcon:
""" Toggles the wicd GUI. """ """ Toggles the wicd GUI. """
if not self.gui_win: if not self.gui_win:
self.gui_win = gui.appGui() self.gui_win = gui.appGui()
bus.add_signal_receiver(self.gui_win.dbus_refresh_networks, bus.add_signal_receiver(self.gui_win.dbus_scan_finished,
'SendScanSignal', 'org.wicd.daemon') 'SendEndScanSignal',
'org.wicd.daemon')
bus.add_signal_receiver(self.gui_win.dbus_scan_started,
'SendStartScanSignal',
'org.wicd.daemon')
bus.add_signal_receiver(self.gui_win.update_connect_buttons, bus.add_signal_receiver(self.gui_win.update_connect_buttons,
'StatusChanged', 'org.wicd.daemon') 'StatusChanged', 'org.wicd.daemon')
elif not self.gui_win.is_visible: elif not self.gui_win.is_visible:
@@ -591,7 +624,7 @@ def main(argv):
for opt, a in opts: for opt, a in opts:
if opt in ('-h', '--help'): if opt in ('-h', '--help'):
usage() usage()
sys.exit() sys.exit(0)
elif opt in ('-n', '--no-tray'): elif opt in ('-n', '--no-tray'):
use_tray = False use_tray = False
elif opt in ('-a', '--no-animate'): elif opt in ('-a', '--no-animate'):
@@ -625,8 +658,22 @@ def main(argv):
bus.add_signal_receiver(tray_icon.icon_info.update_tray_icon, bus.add_signal_receiver(tray_icon.icon_info.update_tray_icon,
'StatusChanged', 'org.wicd.daemon') 'StatusChanged', 'org.wicd.daemon')
print 'Done.' print 'Done.'
while 1:
mainloop = gobject.MainLoop() mainloop = gobject.MainLoop()
try:
mainloop.run() mainloop.run()
except dbus.exceptions.DBusException:
print 'Warning. Caught a D-Bus exception! Connection to daemon lost.'
print 'Trying to reconnect...'
sleep(10)
try:
connect_to_dbus()
except:
pass
if __name__ == '__main__': if __name__ == '__main__':

View File

@@ -14,9 +14,9 @@ class WirelessInterface() -- Control a wireless network interface.
""" """
# #
# Copyright (C) 2007 Adam Blackburn # Copyright (C) 2007 - 2008 Adam Blackburn
# Copyright (C) 2007 Dan O'Reilly # Copyright (C) 2007 - 2008 Dan O'Reilly
# Copyright (C) 2007 Byron Hillis # Copyright (C) 2007 - 2008 Byron Hillis
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License Version 2 as
@@ -31,16 +31,17 @@ class WirelessInterface() -- Control a wireless network interface.
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
import misc
import re import re
import os import os
import wpath
import time import time
import socket import socket
import fcntl import fcntl
import struct import struct
import array import array
import wpath
import misc
# Compile the regex patterns that will be used to search the output of iwlist # 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 # scan for info these are well tested, should work on most cards
essid_pattern = re.compile('.*ESSID:"(.*?)"\n', re.I | re.M | re.S) essid_pattern = re.compile('.*ESSID:"(.*?)"\n', re.I | re.M | re.S)
@@ -76,6 +77,16 @@ SIOCGIFFLAGS = 0x8913
SIOCGIWRANGE = 0x8B0B SIOCGIWRANGE = 0x8B0B
SIOCGIWAP = 0x8B15 SIOCGIWAP = 0x8B15
def _sanitize_string(string):
blacklist = [';', '`', '$', '!', '*', '|', '>', '<']
new_string = []
for c in string:
if c in blacklist:
new_string.append("\\" + c)
else:
new_string.append(c)
return ''.join(new_string)
def SetDNS(dns1=None, dns2=None, dns3=None): def SetDNS(dns1=None, dns2=None, dns3=None):
""" Set the DNS of the system to the specified DNS servers. """ Set the DNS of the system to the specified DNS servers.
@@ -90,8 +101,11 @@ def SetDNS(dns1=None, dns2=None, dns3=None):
resolv = open("/etc/resolv.conf","w") resolv = open("/etc/resolv.conf","w")
for dns in [dns1, dns2, dns3]: for dns in [dns1, dns2, dns3]:
if dns: if dns:
if misc.IsValidIP(dns):
print 'Setting DNS : ' + dns print 'Setting DNS : ' + dns
resolv.write('nameserver ' + dns + '\n') resolv.write('nameserver ' + dns + '\n')
else:
print 'DNS IP is not a valid IP address, not writing to resolv.conf'
resolv.close() resolv.close()
def GetDefaultGateway(): def GetDefaultGateway():
@@ -126,12 +140,13 @@ def GetWirelessInterfaces():
The first interface available. The first interface available.
""" """
iface = _fast_get_wifi_interfaces() dev_dir = '/sys/class/net/'
if not iface: ifnames = []
output = misc.Run('iwconfig')
iface = misc.RunRegex(re.compile('(\w*)\s*\w*\s*[a-zA-Z0-9.-_]*\s*(?=ESSID)', ifnames = [iface for iface in os.listdir(dev_dir) if os.path.isdir(dev_dir + iface) \
re.I | re.M | re.S), output) and 'wireless' in os.listdir(dev_dir + iface)]
return iface
return bool(ifnames) and ifnames[0] or None
def GetWiredInterfaces(): def GetWiredInterfaces():
basedir = '/sys/class/net/' basedir = '/sys/class/net/'
@@ -139,15 +154,6 @@ def GetWiredInterfaces():
in os.listdir(basedir + iface) and \ in os.listdir(basedir + iface) and \
open(basedir + iface + "/type").readlines()[0].strip() == "1"] open(basedir + iface + "/type").readlines()[0].strip() == "1"]
def _fast_get_wifi_interfaces():
""" Tries to get a wireless interface using /sys/class/net. """
dev_dir = '/sys/class/net/'
ifnames = []
ifnames = [iface for iface in os.listdir(dev_dir) if 'wireless' \
in os.listdir(dev_dir + iface)]
return bool(ifnames) and ifnames[0] or None
def get_iw_ioctl_result(iface, call): def get_iw_ioctl_result(iface, call):
""" Makes the given ioctl call and returns the results. """ Makes the given ioctl call and returns the results.
@@ -182,7 +188,7 @@ class Interface(object):
verbose -- whether to print every command run verbose -- whether to print every command run
""" """
self.iface = iface self.iface = _sanitize_string(iface)
self.verbose = verbose self.verbose = verbose
self.DHCP_CLIENT = None self.DHCP_CLIENT = None
self.DHCP_CMD = None self.DHCP_CMD = None
@@ -206,7 +212,7 @@ class Interface(object):
iface -- the name of the interface. iface -- the name of the interface.
""" """
self.iface = str(iface) self.iface = _sanitize_string(str(iface))
def _find_client_path(self, client): def _find_client_path(self, client):
""" Determines the full path for the given program. """ Determines the full path for the given program.
@@ -238,6 +244,7 @@ class Interface(object):
True if the program exists, False otherwise. True if the program exists, False otherwise.
""" """
client = _sanitize_string(client)
output = misc.Run("which " + client) output = misc.Run("which " + client)
if output and not ("no " + client) in output: if output and not ("no " + client) in output:
return True return True
@@ -353,6 +360,7 @@ class Interface(object):
True True
""" """
if not self.iface: return False
cmd = 'ifconfig ' + self.iface + ' up' cmd = 'ifconfig ' + self.iface + ' up'
if self.verbose: print cmd if self.verbose: print cmd
misc.Run(cmd) misc.Run(cmd)
@@ -365,6 +373,7 @@ class Interface(object):
True True
""" """
if not self.iface: return False
cmd = 'ifconfig ' + self.iface + ' down' cmd = 'ifconfig ' + self.iface + ' down'
if self.verbose: print cmd if self.verbose: print cmd
misc.Run(cmd) misc.Run(cmd)
@@ -382,6 +391,13 @@ class Interface(object):
if not self.iface: if not self.iface:
return return
for val in [ip, netmask, broadcast]:
if not val:
continue
if not misc.IsValidIP(val):
print 'WARNING: Invalid IP address found, aborting!'
return False
cmd = ''.join(['ifconfig ', self.iface, ' ']) cmd = ''.join(['ifconfig ', self.iface, ' '])
if ip: if ip:
cmd = ''.join([cmd, ip, ' ']) cmd = ''.join([cmd, ip, ' '])
@@ -493,6 +509,8 @@ class Interface(object):
_check_dhcp_result for the possible values. _check_dhcp_result for the possible values.
""" """
if not self.iface: return False
cmd = self.DHCP_CMD + " " + self.iface cmd = self.DHCP_CMD + " " + self.iface
if self.verbose: print cmd if self.verbose: print cmd
pipe = misc.Run(cmd, include_stderr=True, return_pipe=True) pipe = misc.Run(cmd, include_stderr=True, return_pipe=True)
@@ -507,13 +525,13 @@ class Interface(object):
def ReleaseDHCP(self): def ReleaseDHCP(self):
""" Release the DHCP lease for this interface. """ """ Release the DHCP lease for this interface. """
if not self.iface: return False
cmd = self.DHCP_RELEASE + " " + self.iface + " 2>/dev/null" cmd = self.DHCP_RELEASE + " " + self.iface + " 2>/dev/null"
misc.Run(cmd) misc.Run(cmd)
def FlushRoutes(self): def FlushRoutes(self):
""" Flush all network routes. """ """ Flush all network routes. """
if not self.iface: if not self.iface: return False
return
if self.IP_FOUND and self.flush_tool != misc.ROUTE: if self.IP_FOUND and self.flush_tool != misc.ROUTE:
cmd = "ip route flush dev " + self.iface cmd = "ip route flush dev " + self.iface
else: else:
@@ -528,6 +546,9 @@ class Interface(object):
gw -- gateway of the default route in dotted quad form gw -- gateway of the default route in dotted quad form
""" """
if not misc.IsValidIP(gw):
print 'WARNING: Invalid gateway found. Aborting!'
return False
cmd = 'route add default gw ' + gw cmd = 'route add default gw ' + gw
if self.verbose: print cmd if self.verbose: print cmd
misc.Run(cmd) misc.Run(cmd)
@@ -539,6 +560,7 @@ class Interface(object):
The IP address of the interface in dotted quad form. The IP address of the interface in dotted quad form.
""" """
if not self.iface: return False
if fast: if fast:
return self._fast_get_ip() return self._fast_get_ip()
cmd = 'ifconfig ' + self.iface cmd = 'ifconfig ' + self.iface
@@ -572,6 +594,7 @@ class Interface(object):
True if the interface is up, False otherwise. True if the interface is up, False otherwise.
""" """
if not self.iface: return False
if fast: if fast:
return self._fast_is_up() return self._fast_is_up()
cmd = "ifconfig " + self.iface cmd = "ifconfig " + self.iface
@@ -623,8 +646,7 @@ class WiredInterface(Interface):
True if a link is detected, False otherwise. True if a link is detected, False otherwise.
""" """
if not self.iface: if not self.iface: return False
return False
if self.ETHTOOL_FOUND and self.link_detect != misc.MIITOOL: if self.ETHTOOL_FOUND and self.link_detect != misc.MIITOOL:
return self._eth_get_plugged_in(fast) return self._eth_get_plugged_in(fast)
elif self.MIITOOL_FOUND: elif self.MIITOOL_FOUND:
@@ -720,6 +742,7 @@ class WiredInterface(Interface):
reg = struct.unpack('16shhhh', result)[-1] reg = struct.unpack('16shhhh', result)[-1]
return bool(reg & 0x0004) return bool(reg & 0x0004)
class WirelessInterface(Interface): class WirelessInterface(Interface):
""" Control a wireless network interface. """ """ Control a wireless network interface. """
def __init__(self, iface, verbose=False, wpa_driver='wext'): def __init__(self, iface, verbose=False, wpa_driver='wext'):
@@ -736,7 +759,7 @@ class WirelessInterface(Interface):
def SetWpaDriver(self, driver): def SetWpaDriver(self, driver):
""" Sets the wpa_driver. """ """ Sets the wpa_driver. """
self.wpa_driver = driver self.wpa_driver = _sanitize_string(driver)
def SetEssid(self, essid): def SetEssid(self, essid):
""" Set the essid of the wireless interface. """ Set the essid of the wireless interface.
@@ -745,6 +768,7 @@ class WirelessInterface(Interface):
essid -- essid to set the interface to essid -- essid to set the interface to
""" """
essid = _sanitize_string(essid)
cmd = 'iwconfig %s essid "%s"' % (self.iface, essid) cmd = 'iwconfig %s essid "%s"' % (self.iface, essid)
if self.verbose: print cmd if self.verbose: print cmd
misc.Run(cmd) misc.Run(cmd)
@@ -762,6 +786,7 @@ class WirelessInterface(Interface):
True if the killswitch is enabled, False otherwise. True if the killswitch is enabled, False otherwise.
""" """
if not self.iface: return False
output = misc.Run("iwconfig " + self.iface) output = misc.Run("iwconfig " + self.iface)
killswitch_pattern = re.compile('.*radio off', re.I | re.M | re.S) killswitch_pattern = re.compile('.*radio off', re.I | re.M | re.S)
@@ -774,6 +799,7 @@ class WirelessInterface(Interface):
def GetIwconfig(self): def GetIwconfig(self):
""" Returns the output of iwconfig for this interface. """ """ Returns the output of iwconfig for this interface. """
if not self.iface: return ""
return misc.Run("iwconfig " + self.iface) return misc.Run("iwconfig " + self.iface)
def GetNetworks(self): def GetNetworks(self):
@@ -834,7 +860,7 @@ class WirelessInterface(Interface):
try: try:
ret = freq_dict[freq] ret = freq_dict[freq]
except KeyError: except KeyError:
print "Couldn't determine channel number for frequency: " + freq print "Couldn't determine channel number for frequency: " + str(freq)
return ret return ret
@@ -982,6 +1008,8 @@ class WirelessInterface(Interface):
mode -- mode to set the interface to mode -- mode to set the interface to
""" """
if not self.iface: return False
mode = _sanitize_string(mode)
if mode.lower() == 'master': if mode.lower() == 'master':
mode = 'managed' mode = 'managed'
cmd = 'iwconfig %s mode %s' % (self.iface, mode) cmd = 'iwconfig %s mode %s' % (self.iface, mode)
@@ -995,6 +1023,11 @@ class WirelessInterface(Interface):
channel -- channel to set the interface to channel -- channel to set the interface to
""" """
if not self.iface: return False
if not channel.isdigit():
print 'WARNING: Invalid channel found. Aborting!'
return False
cmd = 'iwconfig %s channel %s' % (self.iface, str(channel)) cmd = 'iwconfig %s channel %s' % (self.iface, str(channel))
if self.verbose: print cmd if self.verbose: print cmd
misc.Run(cmd) misc.Run(cmd)
@@ -1006,6 +1039,8 @@ class WirelessInterface(Interface):
key -- encryption key to set key -- encryption key to set
""" """
if not self.iface: return False
key = _sanitize_string(key)
cmd = 'iwconfig %s key %s' % (self.iface, key) cmd = 'iwconfig %s key %s' % (self.iface, key)
if self.verbose: print cmd if self.verbose: print cmd
misc.Run(cmd) misc.Run(cmd)
@@ -1019,6 +1054,7 @@ class WirelessInterface(Interface):
bssid -- bssid of the network bssid -- bssid of the network
""" """
if not self.iface: return False
cmd = 'iwconfig %s essid "%s"' % (self.iface, essid) cmd = 'iwconfig %s essid "%s"' % (self.iface, essid)
if channel: if channel:
cmd = ''.join([cmd, ' channel ', str(channel)]) cmd = ''.join([cmd, ' channel ', str(channel)])
@@ -1062,7 +1098,7 @@ class WirelessInterface(Interface):
False otherwise. False otherwise.
""" """
# Right now there's no way to do this for these drivers # Right now there's no way to do this for ralink drivers
if self.wpa_driver == RALINK_DRIVER or not self.WPA_CLI_FOUND: if self.wpa_driver == RALINK_DRIVER or not self.WPA_CLI_FOUND:
return True return True
@@ -1076,6 +1112,10 @@ class WirelessInterface(Interface):
print 'WPA_CLI RESULT IS', result print 'WPA_CLI RESULT IS', result
if not result: if not result:
print "WARNING: Received an unexpected result from wpa_cli!" + \
"\nMake sure you're using the right wpa_supplicant " + \
"driver (you probably want wext).\nIf the problem " + \
"persists, please file a bug report."
return False return False
if result == "COMPLETED": if result == "COMPLETED":
return True return True
@@ -1162,8 +1202,9 @@ class WirelessInterface(Interface):
if self.verbose: print cmd if self.verbose: print cmd
misc.Run(cmd) misc.Run(cmd)
def GetBSSID(self, iwconfig=None, fast=True): def GetBSSID(self, iwconfig="", fast=True):
""" Get the MAC address for the interface. """ """ Get the MAC address for the interface. """
if not self.iface: return ""
if fast: if fast:
return self._fast_get_bssid() return self._fast_get_bssid()
else: else:
@@ -1198,6 +1239,7 @@ class WirelessInterface(Interface):
The signal strength. The signal strength.
""" """
if not self.iface: return -1
if fast: if fast:
return self._get_signal_strength_fast() return self._get_signal_strength_fast()
@@ -1254,6 +1296,7 @@ class WirelessInterface(Interface):
The dBm signal strength. The dBm signal strength.
""" """
if not self.iface: return -100
if fast: if fast:
return self._get_dbm_strength_fast() return self._get_dbm_strength_fast()
if iwconfig: if iwconfig:
@@ -1286,6 +1329,7 @@ class WirelessInterface(Interface):
The current network essid. The current network essid.
""" """
if not self.iface: return ""
if fast: if fast:
return self._get_essid_fast() return self._get_essid_fast()