mirror of
https://github.com/gryf/wicd.git
synced 2025-12-29 01:42:33 +01:00
Move GTK-client files from wicd/ to gtk/
This commit is contained in:
@@ -1,195 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
""" configscript -- 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
|
||||
editing scripts requires root access, and the GUI/Tray are typically
|
||||
run as the current user.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# Copyright (C) 2007-2009 Adam Blackburn
|
||||
# Copyright (C) 2007-2009 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 sys
|
||||
import os
|
||||
import gtk
|
||||
import ConfigParser
|
||||
import gtk.glade
|
||||
|
||||
from wicd import wpath
|
||||
from wicd import translations
|
||||
from wicd import dbusmanager
|
||||
|
||||
_ = translations.get_gettext()
|
||||
|
||||
language = {}
|
||||
language['configure_scripts'] = _("Configure Scripts")
|
||||
language['before_script'] = _("Pre-connection Script")
|
||||
language['after_script'] = _("Post-connection Script")
|
||||
language['pre_disconnect_script'] = _("Pre-disconnection Script")
|
||||
language['post_disconnect_script'] = _("Post-disconnection Script")
|
||||
|
||||
dbus = dbusmanager.DBusManager()
|
||||
dbus.connect_to_dbus()
|
||||
|
||||
wireless = dbus.get_interface("wireless")
|
||||
wired = dbus.get_interface("wired")
|
||||
|
||||
wireless_conf = wpath.etc + 'wireless-settings.conf'
|
||||
wired_conf = wpath.etc + 'wired-settings.conf'
|
||||
|
||||
|
||||
def none_to_blank(text):
|
||||
""" Converts special string cases to a blank string.
|
||||
|
||||
If text is None, 'None', or '' then this method will
|
||||
return '', otherwise it will just return str(text).
|
||||
|
||||
"""
|
||||
if text in (None, "None", ""):
|
||||
return ""
|
||||
else:
|
||||
return str(text)
|
||||
|
||||
def blank_to_none(text):
|
||||
""" Convert an empty or null string to 'None'. """
|
||||
if text in ("", None):
|
||||
return "None"
|
||||
else:
|
||||
return str(text)
|
||||
|
||||
def get_val(con, network, option, default="None"):
|
||||
""" Returns the specified option for the given network.
|
||||
|
||||
Returns the value stored in the config file for the given option,
|
||||
unless the option isn't stored yet, in which case the default value
|
||||
provided is stored and then returned.
|
||||
|
||||
Keyword arguments:
|
||||
network -- The section to search.
|
||||
option -- The option to search for.
|
||||
deafult -- The default value to store/return if the option isn't found.
|
||||
|
||||
"""
|
||||
if not con.has_option(network, option):
|
||||
con.set(network, option, default)
|
||||
return con.get(network, option)
|
||||
|
||||
|
||||
def get_script_info(network, network_type):
|
||||
""" Read script info from disk and load it into the configuration dialog """
|
||||
info = {}
|
||||
con = ConfigParser.ConfigParser()
|
||||
if network_type == "wired":
|
||||
con.read(wired_conf)
|
||||
if con.has_section(network):
|
||||
info["pre_entry"] = get_val(con, network, "beforescript")
|
||||
info["post_entry"] = get_val(con, network, "afterscript")
|
||||
info["pre_disconnect_entry"] = get_val(con, network, "predisconnectscript")
|
||||
info["post_disconnect_entry"] = get_val(con, network, "postdisconnectscript")
|
||||
else:
|
||||
bssid = wireless.GetWirelessProperty(int(network), "bssid")
|
||||
con.read(wireless_conf)
|
||||
if con.has_section(bssid):
|
||||
info["pre_entry"] = get_val(con, bssid, "beforescript")
|
||||
info["post_entry"] = get_val(con, bssid, "afterscript")
|
||||
info["pre_disconnect_entry"] = get_val(con, bssid, "predisconnectscript")
|
||||
info["post_disconnect_entry"] = get_val(con, bssid, "postdisconnectscript")
|
||||
return info
|
||||
|
||||
def write_scripts(network, network_type, script_info):
|
||||
""" Writes script info to disk and loads it into the daemon. """
|
||||
con = ConfigParser.ConfigParser()
|
||||
|
||||
if network_type == "wired":
|
||||
con.read(wired_conf)
|
||||
if not con.has_section(network):
|
||||
con.add_section(network)
|
||||
con.set(network, "beforescript", script_info["pre_entry"])
|
||||
con.set(network, "afterscript", script_info["post_entry"])
|
||||
con.set(network, "predisconnectscript", script_info["pre_disconnect_entry"])
|
||||
con.set(network, "postdisconnectscript", script_info["post_disconnect_entry"])
|
||||
con.write(open(wired_conf, "w"))
|
||||
wired.ReloadConfig()
|
||||
wired.ReadWiredNetworkProfile(network)
|
||||
wired.SaveWiredNetworkProfile(network)
|
||||
else:
|
||||
bssid = wireless.GetWirelessProperty(int(network), "bssid")
|
||||
con.read(wireless_conf)
|
||||
if not con.has_section(bssid):
|
||||
con.add_section(bssid)
|
||||
con.set(bssid, "beforescript", script_info["pre_entry"])
|
||||
con.set(bssid, "afterscript", script_info["post_entry"])
|
||||
con.set(bssid, "predisconnectscript", script_info["pre_disconnect_entry"])
|
||||
con.set(bssid, "postdisconnectscript", script_info["post_disconnect_entry"])
|
||||
con.write(open(wireless_conf, "w"))
|
||||
wireless.ReloadConfig()
|
||||
wireless.ReadWirelessNetworkProfile(int(network))
|
||||
wireless.SaveWirelessNetworkProfile(int(network))
|
||||
|
||||
|
||||
def main (argv):
|
||||
""" Runs the script configuration dialog. """
|
||||
if len(argv) < 2:
|
||||
print 'Network id to configure is missing, aborting.'
|
||||
sys.exit(1)
|
||||
|
||||
network = argv[1]
|
||||
network_type = argv[2]
|
||||
|
||||
script_info = get_script_info(network, network_type)
|
||||
|
||||
gladefile = wpath.share + "wicd.glade"
|
||||
wTree = gtk.glade.XML(gladefile)
|
||||
dialog = wTree.get_widget("configure_script_dialog")
|
||||
wTree.get_widget("pre_label").set_label(language['before_script'] + ":")
|
||||
wTree.get_widget("post_label").set_label(language['after_script'] + ":")
|
||||
wTree.get_widget("pre_disconnect_label").set_label(language['pre_disconnect_script']
|
||||
+ ":")
|
||||
wTree.get_widget("post_disconnect_label").set_label(language['post_disconnect_script']
|
||||
+ ":")
|
||||
wTree.get_widget("window1").hide()
|
||||
|
||||
pre_entry = wTree.get_widget("pre_entry")
|
||||
post_entry = wTree.get_widget("post_entry")
|
||||
pre_disconnect_entry = wTree.get_widget("pre_disconnect_entry")
|
||||
post_disconnect_entry = wTree.get_widget("post_disconnect_entry")
|
||||
|
||||
pre_entry.set_text(none_to_blank(script_info.get("pre_entry")))
|
||||
post_entry.set_text(none_to_blank(script_info.get("post_entry")))
|
||||
pre_disconnect_entry.set_text(none_to_blank(script_info.get("pre_disconnect_entry")))
|
||||
post_disconnect_entry.set_text(none_to_blank(script_info.get("post_disconnect_entry")))
|
||||
|
||||
dialog.show_all()
|
||||
|
||||
result = dialog.run()
|
||||
if result == 1:
|
||||
script_info["pre_entry"] = blank_to_none(pre_entry.get_text())
|
||||
script_info["post_entry"] = blank_to_none(post_entry.get_text())
|
||||
script_info["pre_disconnect_entry"] = blank_to_none(pre_disconnect_entry.get_text())
|
||||
script_info["post_disconnect_entry"] = blank_to_none(post_disconnect_entry.get_text())
|
||||
write_scripts(network, network_type, script_info)
|
||||
dialog.destroy()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if os.getuid() != 0:
|
||||
print "Root privileges are required to configure scripts. Exiting."
|
||||
sys.exit(0)
|
||||
main(sys.argv)
|
||||
810
wicd/gui.py
810
wicd/gui.py
@@ -1,810 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
""" gui -- The main wicd GUI module.
|
||||
|
||||
Module containing the code for the main wicd GUI.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# Copyright (C) 2007-2009 Adam Blackburn
|
||||
# Copyright (C) 2007-2009 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
|
||||
import sys
|
||||
import time
|
||||
import gobject
|
||||
import pango
|
||||
import gtk
|
||||
import gtk.glade
|
||||
from itertools import chain
|
||||
from dbus import DBusException
|
||||
|
||||
from wicd import misc
|
||||
from wicd import wpath
|
||||
from wicd import dbusmanager
|
||||
from wicd.misc import noneToString
|
||||
import prefs
|
||||
from prefs import PreferencesDialog
|
||||
import netentry
|
||||
from netentry import WiredNetworkEntry, WirelessNetworkEntry
|
||||
from guiutil import error, LabelEntry
|
||||
from wicd.translations import language
|
||||
|
||||
if __name__ == '__main__':
|
||||
wpath.chdir(__file__)
|
||||
|
||||
proxy_obj = daemon = wireless = wired = bus = None
|
||||
DBUS_AVAIL = False
|
||||
|
||||
def setup_dbus(force=True):
|
||||
global bus, daemon, wireless, wired, DBUS_AVAIL
|
||||
try:
|
||||
dbusmanager.connect_to_dbus()
|
||||
except DBusException:
|
||||
if force:
|
||||
print "Can't connect to the daemon, trying to start it automatically..."
|
||||
if not misc.PromptToStartDaemon():
|
||||
print "Failed to find a graphical sudo program, cannot continue."
|
||||
return False
|
||||
try:
|
||||
dbusmanager.connect_to_dbus()
|
||||
except DBusException:
|
||||
error(None, "Could not connect to wicd's D-Bus interface. " +
|
||||
"Check the wicd log for error messages.")
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
prefs.setup_dbus()
|
||||
netentry.setup_dbus()
|
||||
bus = dbusmanager.get_bus()
|
||||
dbus_ifaces = dbusmanager.get_dbus_ifaces()
|
||||
daemon = dbus_ifaces['daemon']
|
||||
wireless = dbus_ifaces['wireless']
|
||||
wired = dbus_ifaces['wired']
|
||||
DBUS_AVAIL = True
|
||||
|
||||
return True
|
||||
|
||||
def handle_no_dbus(from_tray=False):
|
||||
global DBUS_AVAIL
|
||||
DBUS_AVAIL = False
|
||||
if from_tray: return False
|
||||
print "Wicd daemon is shutting down!"
|
||||
error(None, language['lost_dbus'], block=False)
|
||||
return False
|
||||
|
||||
|
||||
class WiredProfileChooser:
|
||||
""" Class for displaying the wired profile chooser. """
|
||||
def __init__(self):
|
||||
""" Initializes and runs the wired profile chooser. """
|
||||
# Import and init WiredNetworkEntry to steal some of the
|
||||
# functions and widgets it uses.
|
||||
wired_net_entry = WiredNetworkEntry()
|
||||
|
||||
dialog = gtk.Dialog(title = language['wired_network_found'],
|
||||
flags = gtk.DIALOG_MODAL,
|
||||
buttons = (gtk.STOCK_CONNECT, 1,
|
||||
gtk.STOCK_CANCEL, 2))
|
||||
dialog.set_has_separator(False)
|
||||
dialog.set_size_request(400, 150)
|
||||
instruct_label = gtk.Label(language['choose_wired_profile'] + ':\n')
|
||||
stoppopcheckbox = gtk.CheckButton(language['stop_showing_chooser'])
|
||||
|
||||
wired_net_entry.is_full_gui = False
|
||||
instruct_label.set_alignment(0, 0)
|
||||
stoppopcheckbox.set_active(False)
|
||||
|
||||
# Remove widgets that were added to the normal WiredNetworkEntry
|
||||
# so that they can be added to the pop-up wizard.
|
||||
wired_net_entry.vbox_top.remove(wired_net_entry.hbox_temp)
|
||||
wired_net_entry.vbox_top.remove(wired_net_entry.profile_help)
|
||||
|
||||
dialog.vbox.pack_start(instruct_label, fill=False, expand=False)
|
||||
dialog.vbox.pack_start(wired_net_entry.profile_help, False, False)
|
||||
dialog.vbox.pack_start(wired_net_entry.hbox_temp, False, False)
|
||||
dialog.vbox.pack_start(stoppopcheckbox, False, False)
|
||||
dialog.show_all()
|
||||
|
||||
wired_profiles = wired_net_entry.combo_profile_names
|
||||
wired_net_entry.profile_help.hide()
|
||||
if wired_net_entry.profile_list != None:
|
||||
wired_profiles.set_active(0)
|
||||
print "wired profiles found"
|
||||
else:
|
||||
print "no wired profiles found"
|
||||
wired_net_entry.profile_help.show()
|
||||
|
||||
response = dialog.run()
|
||||
if response == 1:
|
||||
print 'reading profile ', wired_profiles.get_active_text()
|
||||
wired.ReadWiredNetworkProfile(wired_profiles.get_active_text())
|
||||
wired.ConnectWired()
|
||||
else:
|
||||
if stoppopcheckbox.get_active():
|
||||
daemon.SetForcedDisconnect(True)
|
||||
dialog.destroy()
|
||||
|
||||
|
||||
class appGui(object):
|
||||
""" The main wicd GUI class. """
|
||||
def __init__(self, standalone=False, tray=None):
|
||||
""" Initializes everything needed for the GUI. """
|
||||
setup_dbus()
|
||||
|
||||
self.tray = tray
|
||||
|
||||
gladefile = os.path.join(wpath.gtk, "wicd.glade")
|
||||
self.wTree = gtk.glade.XML(gladefile)
|
||||
self.window = self.wTree.get_widget("window1")
|
||||
self.window.set_icon_name("wicd-client")
|
||||
size = daemon.ReadWindowSize("main")
|
||||
width = size[0]
|
||||
height = size[1]
|
||||
if width > -1 and height > -1:
|
||||
self.window.resize(int(width), int(height))
|
||||
else:
|
||||
width = int(gtk.gdk.screen_width() / 2)
|
||||
if width > 530:
|
||||
width = 530
|
||||
self.window.resize(width, int(gtk.gdk.screen_height() / 1.7))
|
||||
|
||||
dic = { "refresh_clicked" : self.refresh_clicked,
|
||||
"quit_clicked" : self.exit,
|
||||
"disconnect_clicked" : self.disconnect_all,
|
||||
"main_exit" : self.exit,
|
||||
"cancel_clicked" : self.cancel_connect,
|
||||
"hidden_clicked" : self.connect_hidden,
|
||||
"preferences_clicked" : self.settings_dialog,
|
||||
"about_clicked" : self.about_dialog,
|
||||
"create_adhoc_clicked" : self.create_adhoc_network,
|
||||
}
|
||||
self.wTree.signal_autoconnect(dic)
|
||||
|
||||
# Set some strings in the GUI - they may be translated
|
||||
label_instruct = self.wTree.get_widget("label_instructions")
|
||||
label_instruct.set_label(language['select_a_network'])
|
||||
|
||||
probar = self.wTree.get_widget("progressbar")
|
||||
probar.set_text(language['connecting'])
|
||||
|
||||
self.all_network_list = self.wTree.get_widget("network_list_vbox")
|
||||
self.all_network_list.show_all()
|
||||
self.wired_network_box = gtk.VBox(False, 0)
|
||||
self.wired_network_box.show_all()
|
||||
self.network_list = gtk.VBox(False, 0)
|
||||
self.all_network_list.pack_start(self.wired_network_box, False, False)
|
||||
self.all_network_list.pack_start(self.network_list, True, True)
|
||||
self.network_list.show_all()
|
||||
self.status_area = self.wTree.get_widget("connecting_hbox")
|
||||
self.status_bar = self.wTree.get_widget("statusbar")
|
||||
menu = self.wTree.get_widget("menu1")
|
||||
|
||||
self.status_area.hide_all()
|
||||
|
||||
if os.path.exists(os.path.join(wpath.images, "wicd.png")):
|
||||
self.window.set_icon_from_file(os.path.join(wpath.images, "wicd.png"))
|
||||
self.statusID = None
|
||||
self.first_dialog_load = True
|
||||
self.is_visible = True
|
||||
self.pulse_active = False
|
||||
self.pref = None
|
||||
self.standalone = standalone
|
||||
self.wpadrivercombo = None
|
||||
self.connecting = False
|
||||
self.refreshing = False
|
||||
self.prev_state = None
|
||||
self.update_cb = None
|
||||
self.network_list.set_sensitive(False)
|
||||
label = gtk.Label("%s..." % language['scanning'])
|
||||
self.network_list.pack_start(label)
|
||||
label.show()
|
||||
self.wait_for_events(0.2)
|
||||
self.window.connect('delete_event', self.exit)
|
||||
self.window.connect('key-release-event', self.key_event)
|
||||
daemon.SetGUIOpen(True)
|
||||
bus.add_signal_receiver(self.dbus_scan_finished, 'SendEndScanSignal',
|
||||
'org.wicd.daemon.wireless')
|
||||
bus.add_signal_receiver(self.dbus_scan_started, 'SendStartScanSignal',
|
||||
'org.wicd.daemon.wireless')
|
||||
bus.add_signal_receiver(self.update_connect_buttons, 'StatusChanged',
|
||||
'org.wicd.daemon')
|
||||
bus.add_signal_receiver(self.handle_connection_results,
|
||||
'ConnectResultsSent', 'org.wicd.daemon')
|
||||
bus.add_signal_receiver(lambda: setup_dbus(force=False),
|
||||
"DaemonStarting", "org.wicd.daemon")
|
||||
bus.add_signal_receiver(self._do_statusbar_update, 'StatusChanged',
|
||||
'org.wicd.daemon')
|
||||
if standalone:
|
||||
bus.add_signal_receiver(handle_no_dbus, "DaemonClosing",
|
||||
"org.wicd.daemon")
|
||||
|
||||
self._do_statusbar_update(*daemon.GetConnectionStatus())
|
||||
self.wait_for_events(0.1)
|
||||
self.update_cb = misc.timeout_add(2, self.update_statusbar)
|
||||
self.refresh_clicked()
|
||||
|
||||
def handle_connection_results(self, results):
|
||||
if results not in ['Success', 'aborted'] and self.is_visible:
|
||||
error(self.window, language[results], block=False)
|
||||
|
||||
def create_adhoc_network(self, widget=None):
|
||||
""" Shows a dialog that creates a new adhoc network. """
|
||||
print "Starting the Ad-Hoc Network Creation Process..."
|
||||
dialog = gtk.Dialog(title = language['create_adhoc_network'],
|
||||
flags = gtk.DIALOG_MODAL,
|
||||
buttons=(gtk.STOCK_CANCEL, 2, gtk.STOCK_OK, 1))
|
||||
dialog.set_has_separator(False)
|
||||
dialog.set_size_request(400, -1)
|
||||
self.chkbox_use_encryption = gtk.CheckButton(language['use_wep_encryption'])
|
||||
self.chkbox_use_encryption.set_active(False)
|
||||
ip_entry = LabelEntry(language['ip'] + ':')
|
||||
essid_entry = LabelEntry(language['essid'] + ':')
|
||||
channel_entry = LabelEntry(language['channel'] + ':')
|
||||
self.key_entry = LabelEntry(language['key'] + ':')
|
||||
self.key_entry.set_auto_hidden(True)
|
||||
self.key_entry.set_sensitive(False)
|
||||
|
||||
chkbox_use_ics = gtk.CheckButton(language['use_ics'])
|
||||
|
||||
self.chkbox_use_encryption.connect("toggled",
|
||||
self.toggle_encrypt_check)
|
||||
channel_entry.entry.set_text('3')
|
||||
essid_entry.entry.set_text('My_Adhoc_Network')
|
||||
ip_entry.entry.set_text('169.254.12.10') # Just a random IP
|
||||
|
||||
vbox_ah = gtk.VBox(False, 0)
|
||||
self.wired_network_box = gtk.VBox(False, 0)
|
||||
vbox_ah.pack_start(self.chkbox_use_encryption, False, False)
|
||||
vbox_ah.pack_start(self.key_entry, False, False)
|
||||
vbox_ah.show()
|
||||
dialog.vbox.pack_start(essid_entry)
|
||||
dialog.vbox.pack_start(ip_entry)
|
||||
dialog.vbox.pack_start(channel_entry)
|
||||
dialog.vbox.pack_start(chkbox_use_ics)
|
||||
dialog.vbox.pack_start(vbox_ah)
|
||||
dialog.vbox.set_spacing(5)
|
||||
dialog.show_all()
|
||||
response = dialog.run()
|
||||
if response == 1:
|
||||
wireless.CreateAdHocNetwork(essid_entry.entry.get_text(),
|
||||
channel_entry.entry.get_text(),
|
||||
ip_entry.entry.get_text().strip(),
|
||||
"WEP",
|
||||
self.key_entry.entry.get_text(),
|
||||
self.chkbox_use_encryption.get_active(),
|
||||
False) #chkbox_use_ics.get_active())
|
||||
dialog.destroy()
|
||||
|
||||
def toggle_encrypt_check(self, widget=None):
|
||||
""" Toggles the encryption key entry box for the ad-hoc dialog. """
|
||||
self.key_entry.set_sensitive(self.chkbox_use_encryption.get_active())
|
||||
|
||||
def disconnect_all(self, widget=None):
|
||||
""" Disconnects from any active network. """
|
||||
def handler(*args):
|
||||
gobject.idle_add(self.all_network_list.set_sensitive, True)
|
||||
|
||||
self.all_network_list.set_sensitive(False)
|
||||
daemon.Disconnect(reply_handler=handler, error_handler=handler)
|
||||
|
||||
def about_dialog(self, widget, event=None):
|
||||
""" Displays an about dialog. """
|
||||
dialog = gtk.AboutDialog()
|
||||
dialog.set_name("Wicd")
|
||||
dialog.set_version(daemon.Hello())
|
||||
dialog.set_authors([ "Adam Blackburn", "Dan O'Reilly", "Andrew Psaltis" ])
|
||||
dialog.set_website("http://wicd.sourceforge.net")
|
||||
dialog.run()
|
||||
dialog.destroy()
|
||||
|
||||
def key_event (self, widget, event=None):
|
||||
""" Handle key-release-events. """
|
||||
if event.state & gtk.gdk.CONTROL_MASK and \
|
||||
gtk.gdk.keyval_name(event.keyval) in ["w", "q"]:
|
||||
self.exit()
|
||||
|
||||
def settings_dialog(self, widget, event=None):
|
||||
""" Displays a general settings dialog. """
|
||||
if not self.pref:
|
||||
self.pref = PreferencesDialog(self, self.wTree)
|
||||
else:
|
||||
self.pref.load_preferences_diag()
|
||||
if self.pref.run() == 1:
|
||||
self.pref.save_results()
|
||||
self.pref.hide()
|
||||
|
||||
def connect_hidden(self, widget):
|
||||
""" Prompts the user for a hidden network, then scans for it. """
|
||||
dialog = gtk.Dialog(title=language['hidden_network'],
|
||||
flags=gtk.DIALOG_MODAL,
|
||||
buttons=(gtk.STOCK_CONNECT, 1, gtk.STOCK_CANCEL, 2))
|
||||
dialog.set_has_separator(False)
|
||||
lbl = gtk.Label(language['hidden_network_essid'])
|
||||
textbox = gtk.Entry()
|
||||
dialog.vbox.pack_start(lbl)
|
||||
dialog.vbox.pack_start(textbox)
|
||||
dialog.show_all()
|
||||
button = dialog.run()
|
||||
if button == 1:
|
||||
answer = textbox.get_text()
|
||||
dialog.destroy()
|
||||
self.refresh_networks(None, True, answer)
|
||||
else:
|
||||
dialog.destroy()
|
||||
|
||||
def cancel_connect(self, widget):
|
||||
""" Alerts the daemon to cancel the connection process. """
|
||||
#should cancel a connection if there
|
||||
#is one in progress
|
||||
cancel_button = self.wTree.get_widget("cancel_button")
|
||||
cancel_button.set_sensitive(False)
|
||||
daemon.CancelConnect()
|
||||
# Prevents automatic reconnecting if that option is enabled
|
||||
daemon.SetForcedDisconnect(True)
|
||||
|
||||
def pulse_progress_bar(self):
|
||||
""" Pulses the progress bar while connecting to a network. """
|
||||
if not self.pulse_active:
|
||||
return False
|
||||
if not self.is_visible:
|
||||
return True
|
||||
try:
|
||||
gobject.idle_add(self.wTree.get_widget("progressbar").pulse)
|
||||
except:
|
||||
pass
|
||||
return True
|
||||
|
||||
def update_statusbar(self):
|
||||
""" Triggers a status update in wicd-monitor. """
|
||||
if not self.is_visible:
|
||||
return True
|
||||
|
||||
daemon.UpdateState()
|
||||
if self.connecting:
|
||||
# If we're connecting, don't wait for the monitor to send
|
||||
# us a signal, since it won't until the connection is made.
|
||||
self._do_statusbar_update(*daemon.GetConnectionStatus())
|
||||
return True
|
||||
|
||||
def _do_statusbar_update(self, state, info):
|
||||
if not self.is_visible:
|
||||
return True
|
||||
|
||||
if state == misc.WIRED:
|
||||
return self.set_wired_state(info)
|
||||
elif state == misc.WIRELESS:
|
||||
return self.set_wireless_state(info)
|
||||
elif state == misc.CONNECTING:
|
||||
return self.set_connecting_state(info)
|
||||
elif state in (misc.SUSPENDED, misc.NOT_CONNECTED):
|
||||
return self.set_not_connected_state(info)
|
||||
return True
|
||||
|
||||
def set_wired_state(self, info):
|
||||
if self.connecting:
|
||||
# Adjust our state from connecting->connected.
|
||||
self._set_not_connecting_state()
|
||||
self.set_status(language['connected_to_wired'].replace('$A', info[0]))
|
||||
return True
|
||||
|
||||
def set_wireless_state(self, info):
|
||||
if self.connecting:
|
||||
# Adjust our state from connecting->connected.
|
||||
self._set_not_connecting_state()
|
||||
self.set_status(language['connected_to_wireless'].replace
|
||||
('$A', info[1]).replace
|
||||
('$B', daemon.FormatSignalForPrinting(info[2])).replace
|
||||
('$C', info[0]))
|
||||
return True
|
||||
|
||||
def set_not_connected_state(self, info):
|
||||
if self.connecting:
|
||||
# Adjust our state from connecting->not-connected.
|
||||
self._set_not_connecting_state()
|
||||
self.set_status(language['not_connected'])
|
||||
return True
|
||||
|
||||
def _set_not_connecting_state(self):
|
||||
if self.connecting:
|
||||
if self.update_cb:
|
||||
gobject.source_remove(self.update_cb)
|
||||
self.update_cb = misc.timeout_add(2, self.update_statusbar)
|
||||
self.connecting = False
|
||||
if self.pulse_active:
|
||||
self.pulse_active = False
|
||||
gobject.idle_add(self.all_network_list.set_sensitive, True)
|
||||
gobject.idle_add(self.status_area.hide_all)
|
||||
if self.statusID:
|
||||
gobject.idle_add(self.status_bar.remove, 1, self.statusID)
|
||||
|
||||
def set_connecting_state(self, info):
|
||||
if not self.connecting:
|
||||
if self.update_cb:
|
||||
gobject.source_remove(self.update_cb)
|
||||
self.update_cb = misc.timeout_add(500, self.update_statusbar,
|
||||
milli=True)
|
||||
self.connecting = True
|
||||
if not self.pulse_active:
|
||||
self.pulse_active = True
|
||||
misc.timeout_add(100, self.pulse_progress_bar, milli=True)
|
||||
gobject.idle_add(self.all_network_list.set_sensitive, False)
|
||||
gobject.idle_add(self.status_area.show_all)
|
||||
if self.statusID:
|
||||
gobject.idle_add(self.status_bar.remove, 1, self.statusID)
|
||||
if info[0] == "wireless":
|
||||
gobject.idle_add(self.set_status, str(info[1]) + ': ' +
|
||||
language[str(wireless.CheckWirelessConnectingMessage())])
|
||||
elif info[0] == "wired":
|
||||
gobject.idle_add(self.set_status, language['wired_network'] + ': ' +
|
||||
language[str(wired.CheckWiredConnectingMessage())])
|
||||
return True
|
||||
|
||||
def update_connect_buttons(self, state=None, x=None, force_check=False):
|
||||
""" Updates the connect/disconnect buttons for each network entry.
|
||||
|
||||
If force_check is given, update the buttons even if the
|
||||
current network state is the same as the previous.
|
||||
|
||||
"""
|
||||
if not DBUS_AVAIL: return
|
||||
if not state:
|
||||
state, x = daemon.GetConnectionStatus()
|
||||
|
||||
if self.prev_state != state or force_check:
|
||||
apbssid = wireless.GetApBssid()
|
||||
for entry in chain(self.network_list, self.wired_network_box):
|
||||
if hasattr(entry, "update_connect_button"):
|
||||
entry.update_connect_button(state, apbssid)
|
||||
self.prev_state = state
|
||||
|
||||
def set_status(self, msg):
|
||||
""" Sets the status bar message for the GUI. """
|
||||
self.statusID = self.status_bar.push(1, msg)
|
||||
|
||||
def dbus_scan_finished(self):
|
||||
""" Calls for a non-fresh update of the gui window.
|
||||
|
||||
This method is called after a wireless scan is completed.
|
||||
|
||||
"""
|
||||
if not DBUS_AVAIL: return
|
||||
gobject.idle_add(self.refresh_networks, None, False, None)
|
||||
|
||||
def dbus_scan_started(self):
|
||||
""" Called when a wireless scan starts. """
|
||||
if not DBUS_AVAIL: return
|
||||
self.network_list.set_sensitive(False)
|
||||
|
||||
def _remove_items_from_vbox(self, vbox):
|
||||
for z in vbox:
|
||||
vbox.remove(z)
|
||||
z.destroy()
|
||||
del z
|
||||
|
||||
|
||||
def refresh_clicked(self, widget=None):
|
||||
""" Kick off an asynchronous wireless scan. """
|
||||
if not DBUS_AVAIL or self.connecting: return
|
||||
self.refreshing = True
|
||||
|
||||
# Remove stuff already in there.
|
||||
self._remove_items_from_vbox(self.wired_network_box)
|
||||
self._remove_items_from_vbox(self.network_list)
|
||||
label = gtk.Label("%s..." % language['scanning'])
|
||||
self.network_list.pack_start(label)
|
||||
self.network_list.show_all()
|
||||
if wired.CheckPluggedIn() or daemon.GetAlwaysShowWiredInterface():
|
||||
printLine = True # In this case we print a separator.
|
||||
wirednet = WiredNetworkEntry()
|
||||
self.wired_network_box.pack_start(wirednet, False, False)
|
||||
wirednet.connect_button.connect("clicked", self.connect,
|
||||
"wired", 0, wirednet)
|
||||
wirednet.disconnect_button.connect("clicked", self.disconnect,
|
||||
"wired", 0, wirednet)
|
||||
wirednet.advanced_button.connect("clicked",
|
||||
self.edit_advanced, "wired", 0,
|
||||
wirednet)
|
||||
state, x = daemon.GetConnectionStatus()
|
||||
wirednet.update_connect_button(state)
|
||||
|
||||
self._wired_showing = True
|
||||
else:
|
||||
self._wired_showing = False
|
||||
|
||||
wireless.Scan(False)
|
||||
|
||||
def refresh_networks(self, widget=None, fresh=True, hidden=None):
|
||||
""" Refreshes the network list.
|
||||
|
||||
If fresh=True, scans for wireless networks and displays the results.
|
||||
If a ethernet connection is available, or the user has chosen to,
|
||||
displays a Wired Network entry as well.
|
||||
If hidden isn't None, will scan for networks after running
|
||||
iwconfig <wireless interface> essid <hidden>.
|
||||
|
||||
"""
|
||||
if fresh:
|
||||
if hidden:
|
||||
wireless.SetHiddenNetworkESSID(noneToString(hidden))
|
||||
self.refresh_clicked()
|
||||
return
|
||||
print "refreshing..."
|
||||
self.network_list.set_sensitive(False)
|
||||
self._remove_items_from_vbox(self.network_list)
|
||||
self.wait_for_events()
|
||||
printLine = False # We don't print a separator by default.
|
||||
if self._wired_showing:
|
||||
printLine = True
|
||||
num_networks = wireless.GetNumberOfNetworks()
|
||||
instruct_label = self.wTree.get_widget("label_instructions")
|
||||
if num_networks > 0:
|
||||
instruct_label.show()
|
||||
for x in range(0, num_networks):
|
||||
if printLine:
|
||||
sep = gtk.HSeparator()
|
||||
self.network_list.pack_start(sep, padding=10, fill=False,
|
||||
expand=False)
|
||||
sep.show()
|
||||
else:
|
||||
printLine = True
|
||||
tempnet = WirelessNetworkEntry(x)
|
||||
self.network_list.pack_start(tempnet, False, False)
|
||||
tempnet.connect_button.connect("clicked",
|
||||
self.connect, "wireless", x,
|
||||
tempnet)
|
||||
tempnet.disconnect_button.connect("clicked",
|
||||
self.disconnect, "wireless",
|
||||
x, tempnet)
|
||||
tempnet.advanced_button.connect("clicked",
|
||||
self.edit_advanced, "wireless",
|
||||
x, tempnet)
|
||||
else:
|
||||
instruct_label.hide()
|
||||
if wireless.GetKillSwitchEnabled():
|
||||
label = gtk.Label(language['killswitch_enabled'] + ".")
|
||||
else:
|
||||
label = gtk.Label(language['no_wireless_networks_found'])
|
||||
self.network_list.pack_start(label)
|
||||
label.show()
|
||||
self.update_connect_buttons(force_check=True)
|
||||
self.network_list.set_sensitive(True)
|
||||
self.refreshing = False
|
||||
|
||||
def save_settings(self, nettype, networkid, networkentry):
|
||||
""" Verifies and saves the settings for the network entry. """
|
||||
entry = networkentry.advanced_dialog
|
||||
opt_entlist = []
|
||||
req_entlist = []
|
||||
|
||||
# First make sure all the Addresses entered are valid.
|
||||
if entry.chkbox_static_ip.get_active():
|
||||
req_entlist = [entry.txt_ip, entry.txt_netmask]
|
||||
opt_entlist = [entry.txt_gateway]
|
||||
|
||||
if entry.chkbox_static_dns.get_active() and \
|
||||
not entry.chkbox_global_dns.get_active():
|
||||
req_entlist.append(entry.txt_dns_1)
|
||||
# Only append additional dns entries if they're entered.
|
||||
for ent in [entry.txt_dns_2, entry.txt_dns_3]:
|
||||
if ent.get_text() != "":
|
||||
opt_entlist.append(ent)
|
||||
|
||||
# Required entries.
|
||||
for lblent in req_entlist:
|
||||
lblent.set_text(lblent.get_text().strip())
|
||||
if not misc.IsValidIP(lblent.get_text()):
|
||||
error(self.window, language['invalid_address'].
|
||||
replace('$A', lblent.label.get_label()))
|
||||
return False
|
||||
|
||||
# Optional entries, only check for validity if they're entered.
|
||||
for lblent in opt_entlist:
|
||||
lblent.set_text(lblent.get_text().strip())
|
||||
if lblent.get_text() and not misc.IsValidIP(lblent.get_text()):
|
||||
error(self.window, language['invalid_address'].
|
||||
replace('$A', lblent.label.get_label()))
|
||||
return False
|
||||
|
||||
# Now save the settings.
|
||||
if nettype == "wireless":
|
||||
if not networkentry.save_wireless_settings(networkid):
|
||||
return False
|
||||
|
||||
elif nettype == "wired":
|
||||
if not networkentry.save_wired_settings():
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def edit_advanced(self, widget, ttype, networkid, networkentry):
|
||||
""" Display the advanced settings dialog.
|
||||
|
||||
Displays the advanced settings dialog and saves any changes made.
|
||||
If errors occur in the settings, an error message will be displayed
|
||||
and the user won't be able to save the changes until the errors
|
||||
are fixed.
|
||||
|
||||
"""
|
||||
dialog = networkentry.advanced_dialog
|
||||
dialog.set_values()
|
||||
dialog.show_all()
|
||||
while True:
|
||||
if self.run_settings_dialog(dialog, ttype, networkid, networkentry):
|
||||
break
|
||||
dialog.hide()
|
||||
|
||||
def run_settings_dialog(self, dialog, nettype, networkid, networkentry):
|
||||
""" Runs the settings dialog.
|
||||
|
||||
Runs the settings dialog and returns True if settings are saved
|
||||
successfully, and false otherwise.
|
||||
|
||||
"""
|
||||
result = dialog.run()
|
||||
if result == gtk.RESPONSE_ACCEPT:
|
||||
if self.save_settings(nettype, networkid, networkentry):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
return True
|
||||
|
||||
def check_encryption_valid(self, networkid, entry):
|
||||
""" Make sure that encryption settings are properly filled in. """
|
||||
# Make sure no entries are left blank
|
||||
if entry.chkbox_encryption.get_active():
|
||||
encryption_info = entry.encryption_info
|
||||
for entry_info in encryption_info.itervalues():
|
||||
if entry_info[0].entry.get_text() == "" and \
|
||||
entry_info[1] == 'required':
|
||||
error(self.window, "%s (%s)" % (language['encrypt_info_missing'],
|
||||
entry_info[0].label.get_label())
|
||||
)
|
||||
return False
|
||||
# Make sure the checkbox is checked when it should be
|
||||
elif not entry.chkbox_encryption.get_active() and \
|
||||
wireless.GetWirelessProperty(networkid, "encryption"):
|
||||
error(self.window, language['enable_encryption'])
|
||||
return False
|
||||
return True
|
||||
|
||||
def _wait_for_connect_thread_start(self):
|
||||
self.wTree.get_widget("progressbar").pulse()
|
||||
if not self._connect_thread_started:
|
||||
return True
|
||||
else:
|
||||
misc.timeout_add(2, self.update_statusbar)
|
||||
self.update_statusbar()
|
||||
return False
|
||||
|
||||
def connect(self, widget, nettype, networkid, networkentry):
|
||||
""" Initiates the connection process in the daemon. """
|
||||
def handler(*args):
|
||||
self._connect_thread_started = True
|
||||
|
||||
def setup_interface_for_connection():
|
||||
cancel_button = self.wTree.get_widget("cancel_button")
|
||||
cancel_button.set_sensitive(True)
|
||||
self.all_network_list.set_sensitive(False)
|
||||
if self.statusID:
|
||||
gobject.idle_add(self.status_bar.remove, 1, self.statusID)
|
||||
gobject.idle_add(self.set_status, language["disconnecting_active"])
|
||||
gobject.idle_add(self.status_area.show_all)
|
||||
self.wait_for_events()
|
||||
self._connect_thread_started = False
|
||||
|
||||
if nettype == "wireless":
|
||||
if not self.check_encryption_valid(networkid,
|
||||
networkentry.advanced_dialog):
|
||||
self.edit_advanced(None, nettype, networkid, networkentry)
|
||||
return False
|
||||
setup_interface_for_connection()
|
||||
wireless.ConnectWireless(networkid, reply_handler=handler,
|
||||
error_handler=handler)
|
||||
elif nettype == "wired":
|
||||
setup_interface_for_connection()
|
||||
wired.ConnectWired(reply_handler=handler, error_handler=handler)
|
||||
|
||||
gobject.source_remove(self.update_cb)
|
||||
misc.timeout_add(100, self._wait_for_connect_thread_start, milli=True)
|
||||
|
||||
def disconnect(self, widget, nettype, networkid, networkentry):
|
||||
""" Disconnects from the given network.
|
||||
|
||||
Keyword arguments:
|
||||
widget -- The disconnect button that was pressed.
|
||||
event -- unused
|
||||
nettype -- "wired" or "wireless", depending on the network entry type.
|
||||
networkid -- unused
|
||||
networkentry -- The NetworkEntry containing the disconnect button.
|
||||
|
||||
"""
|
||||
def handler(*args):
|
||||
gobject.idle_add(self.all_network_list.set_sensitive, True)
|
||||
gobject.idle_add(self.network_list.set_sensitive, True)
|
||||
|
||||
widget.hide()
|
||||
networkentry.connect_button.show()
|
||||
daemon.SetForcedDisconnect(True)
|
||||
self.network_list.set_sensitive(False)
|
||||
if nettype == "wired":
|
||||
wired.DisconnectWired(reply_handler=handler, error_handler=handler)
|
||||
else:
|
||||
wireless.DisconnectWireless(reply_handler=handler,
|
||||
error_handler=handler)
|
||||
|
||||
def wait_for_events(self, amt=0):
|
||||
""" Wait for any pending gtk events to finish before moving on.
|
||||
|
||||
Keyword arguments:
|
||||
amt -- a number specifying the number of ms to wait before checking
|
||||
for pending events.
|
||||
|
||||
"""
|
||||
time.sleep(amt)
|
||||
while gtk.events_pending():
|
||||
gtk.main_iteration()
|
||||
|
||||
def exit(self, widget=None, event=None):
|
||||
""" Hide the wicd GUI.
|
||||
|
||||
This method hides the wicd GUI and writes the current window size
|
||||
to disc for later use. This method normally does NOT actually
|
||||
destroy the GUI, it just hides it.
|
||||
|
||||
"""
|
||||
self.window.hide()
|
||||
gobject.source_remove(self.update_cb)
|
||||
bus.remove_signal_receiver(self._do_statusbar_update, 'StatusChanged',
|
||||
'org.wicd.daemon')
|
||||
[width, height] = self.window.get_size()
|
||||
try:
|
||||
daemon.WriteWindowSize(width, height, "main")
|
||||
daemon.SetGUIOpen(False)
|
||||
except DBusException:
|
||||
pass
|
||||
|
||||
if self.standalone:
|
||||
sys.exit(0)
|
||||
|
||||
self.is_visible = False
|
||||
return True
|
||||
|
||||
def show_win(self):
|
||||
""" Brings the GUI out of the hidden state.
|
||||
|
||||
Method to show the wicd GUI, alert the daemon that it is open,
|
||||
and refresh the network list.
|
||||
|
||||
"""
|
||||
self.window.present()
|
||||
self.wait_for_events()
|
||||
self.is_visible = True
|
||||
daemon.SetGUIOpen(True)
|
||||
self.wait_for_events(0.1)
|
||||
gobject.idle_add(self.refresh_clicked)
|
||||
self._do_statusbar_update(*daemon.GetConnectionStatus())
|
||||
bus.add_signal_receiver(self._do_statusbar_update, 'StatusChanged',
|
||||
'org.wicd.daemon')
|
||||
self.update_cb = misc.timeout_add(2, self.update_statusbar)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
setup_dbus()
|
||||
app = appGui(standalone=True)
|
||||
mainloop = gobject.MainLoop()
|
||||
mainloop.run()
|
||||
178
wicd/guiutil.py
178
wicd/guiutil.py
@@ -1,178 +0,0 @@
|
||||
""" guiutil - A collection of commonly used gtk/gui functions and classes. """
|
||||
#
|
||||
# Copyright (C) 2007 - 2009 Adam Blackburn
|
||||
# Copyright (C) 2007 - 2009 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 gtk
|
||||
import os.path
|
||||
|
||||
import wicd.wpath as wpath
|
||||
|
||||
HAS_NOTIFY = True
|
||||
try:
|
||||
import pynotify
|
||||
if not pynotify.init("Wicd"):
|
||||
print 'Could not initalize pynotify'
|
||||
HAS_NOTIFY = False
|
||||
except ImportError:
|
||||
print "Importing pynotify failed, notifications disabled."
|
||||
HAS_NOTIFY = False
|
||||
|
||||
print "Has notifications support", HAS_NOTIFY
|
||||
|
||||
if wpath.no_use_notifications:
|
||||
print 'Notifications disabled during setup.py configure'
|
||||
|
||||
def can_use_notify():
|
||||
use_notify = os.path.exists(os.path.join(os.path.expanduser('~/.wicd'),
|
||||
'USE_NOTIFICATIONS')
|
||||
)
|
||||
return use_notify and HAS_NOTIFY and not wpath.no_use_notifications
|
||||
|
||||
def error(parent, message, block=True):
|
||||
""" Shows an error dialog. """
|
||||
def delete_event(dialog, id):
|
||||
dialog.destroy()
|
||||
if can_use_notify() and not block:
|
||||
notification = pynotify.Notification("ERROR", message, "error")
|
||||
notification.show()
|
||||
return
|
||||
dialog = gtk.MessageDialog(parent, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR,
|
||||
gtk.BUTTONS_OK)
|
||||
dialog.set_markup(message)
|
||||
if not block:
|
||||
dialog.present()
|
||||
dialog.connect("response", delete_event)
|
||||
else:
|
||||
dialog.run()
|
||||
dialog.destroy()
|
||||
|
||||
def alert(parent, message, block=True):
|
||||
""" Shows an warning dialog. """
|
||||
def delete_event(dialog, id):
|
||||
dialog.destroy()
|
||||
dialog = gtk.MessageDialog(parent, gtk.DIALOG_MODAL, gtk.MESSAGE_WARNING,
|
||||
gtk.BUTTONS_OK)
|
||||
dialog.set_markup(message)
|
||||
if not block:
|
||||
dialog.present()
|
||||
dialog.connect("response", delete_event)
|
||||
else:
|
||||
dialog.run()
|
||||
dialog.destroy()
|
||||
|
||||
def string_input(prompt, secondary, textbox_label):
|
||||
# based on a version of a PyGTK text entry from
|
||||
# http://ardoris.wordpress.com/2008/07/05/pygtk-text-entry-dialog/
|
||||
|
||||
def dialog_response(entry, dialog, response):
|
||||
dialog.response(response)
|
||||
|
||||
dialog = gtk.MessageDialog(
|
||||
None,
|
||||
gtk.DIALOG_MODAL,
|
||||
gtk.MESSAGE_QUESTION,
|
||||
gtk.BUTTONS_OK_CANCEL,
|
||||
None)
|
||||
|
||||
# set the text
|
||||
dialog.set_markup("<span size='larger'><b>" + prompt + "</b></span>")
|
||||
# add the secondary text
|
||||
dialog.format_secondary_markup(secondary)
|
||||
|
||||
entry = gtk.Entry()
|
||||
# allow the user to press enter instead of clicking OK
|
||||
entry.connect("activate", dialog_response, dialog, gtk.RESPONSE_OK)
|
||||
|
||||
# create an hbox and pack the label and entry in
|
||||
hbox = gtk.HBox()
|
||||
hbox.pack_start(gtk.Label(textbox_label), False, 4, 4)
|
||||
hbox.pack_start(entry)
|
||||
|
||||
# pack the boxes and show the dialog
|
||||
dialog.vbox.pack_end(hbox, True, True, 0)
|
||||
dialog.show_all()
|
||||
|
||||
if dialog.run() == gtk.RESPONSE_OK:
|
||||
text = entry.get_text()
|
||||
dialog.destroy()
|
||||
return text
|
||||
else:
|
||||
dialog.destroy()
|
||||
return None
|
||||
|
||||
class SmallLabel(gtk.Label):
|
||||
def __init__(self, text=''):
|
||||
gtk.Label.__init__(self, text)
|
||||
self.set_size_request(50, -1)
|
||||
|
||||
class LeftAlignedLabel(gtk.Label):
|
||||
def __init__(self, label=None):
|
||||
gtk.Label.__init__(self, label)
|
||||
self.set_alignment(0.0, 0.5)
|
||||
|
||||
class LabelEntry(gtk.HBox):
|
||||
""" A label on the left with a textbox on the right. """
|
||||
def __init__(self,text):
|
||||
gtk.HBox.__init__(self)
|
||||
self.entry = gtk.Entry()
|
||||
self.entry.set_size_request(200, -1)
|
||||
self.label = LeftAlignedLabel()
|
||||
self.label.set_text(text)
|
||||
self.label.set_size_request(170, -1)
|
||||
self.pack_start(self.label, fill=True, expand=True)
|
||||
self.pack_start(self.entry, fill=False, expand=False)
|
||||
self.label.show()
|
||||
self.entry.show()
|
||||
self.entry.connect('focus-out-event', self.hide_characters)
|
||||
self.entry.connect('focus-in-event', self.show_characters)
|
||||
self.auto_hide_text = False
|
||||
self.show()
|
||||
|
||||
def set_text(self, text):
|
||||
# For compatibility...
|
||||
self.entry.set_text(text)
|
||||
|
||||
def get_text(self):
|
||||
return self.entry.get_text()
|
||||
|
||||
def set_auto_hidden(self, value):
|
||||
self.entry.set_visibility(False)
|
||||
self.auto_hide_text = value
|
||||
|
||||
def show_characters(self, widget=None, event=None):
|
||||
# When the box has focus, show the characters
|
||||
if self.auto_hide_text and widget:
|
||||
self.entry.set_visibility(True)
|
||||
|
||||
def set_sensitive(self, value):
|
||||
self.entry.set_sensitive(value)
|
||||
self.label.set_sensitive(value)
|
||||
|
||||
def hide_characters(self, widget=None, event=None):
|
||||
# When the box looses focus, hide them
|
||||
if self.auto_hide_text and widget:
|
||||
self.entry.set_visibility(False)
|
||||
|
||||
|
||||
class GreyLabel(gtk.Label):
|
||||
""" Creates a grey gtk.Label. """
|
||||
def __init__(self):
|
||||
gtk.Label.__init__(self)
|
||||
|
||||
def set_label(self, text):
|
||||
self.set_markup(text)
|
||||
self.set_alignment(0, 0)
|
||||
1074
wicd/netentry.py
1074
wicd/netentry.py
File diff suppressed because it is too large
Load Diff
414
wicd/prefs.py
414
wicd/prefs.py
@@ -1,414 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
""" prefs -- Wicd Preferences Dialog.
|
||||
|
||||
Displays the main settings dialog window for wicd and
|
||||
handles recieving/sendings the settings from/to the daemon.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# Copyright (C) 2008-2009 Adam Blackburn
|
||||
# Copyright (C) 2008-2009 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 gtk
|
||||
import gobject
|
||||
#import pango
|
||||
import os
|
||||
import gtk.glade
|
||||
|
||||
from wicd import misc
|
||||
from wicd import wpath
|
||||
from wicd import dbusmanager
|
||||
from wicd.misc import checkboxTextboxToggle, noneToBlankString
|
||||
|
||||
daemon = None
|
||||
wireless = None
|
||||
wired = None
|
||||
|
||||
from wicd.translations import language
|
||||
|
||||
USER_SETTINGS_DIR = os.path.expanduser('~/.wicd/')
|
||||
|
||||
def setup_dbus():
|
||||
global daemon, wireless, wired
|
||||
daemon = dbusmanager.get_interface('daemon')
|
||||
wireless = dbusmanager.get_interface('wireless')
|
||||
wired = dbusmanager.get_interface('wired')
|
||||
|
||||
class PreferencesDialog(object):
|
||||
""" Class for handling the wicd preferences dialog window. """
|
||||
def __init__(self, parent, wTree):
|
||||
setup_dbus()
|
||||
self.parent = parent
|
||||
self.wTree = wTree
|
||||
self.prep_settings_diag()
|
||||
self.load_preferences_diag()
|
||||
|
||||
def _setup_external_app_radios(self, radio_list, get_method, set_method):
|
||||
""" Generic function for setting up external app radios. """
|
||||
# Disable radios for apps that aren't installed.
|
||||
for app in radio_list[1:]:
|
||||
app.set_sensitive(daemon.GetAppAvailable(app.get_label()))
|
||||
selected_app = get_method()
|
||||
# Make sure the app we want to select is actually available.
|
||||
if radio_list[selected_app].get_property("sensitive"):
|
||||
radio_list[selected_app].set_active(True)
|
||||
else:
|
||||
# If it isn't, default to Automatic.
|
||||
set_method(misc.AUTO)
|
||||
radio_list[misc.AUTO].set_active(True)
|
||||
|
||||
def load_preferences_diag(self):
|
||||
""" Loads data into the preferences Dialog. """
|
||||
|
||||
self.wiredcheckbox.set_active(daemon.GetAlwaysShowWiredInterface())
|
||||
self.reconnectcheckbox.set_active(daemon.GetAutoReconnect())
|
||||
self.debugmodecheckbox.set_active(daemon.GetDebugMode())
|
||||
self.displaytypecheckbox.set_active(daemon.GetSignalDisplayType())
|
||||
self.verifyapcheckbox.set_active(daemon.GetShouldVerifyAp())
|
||||
self.preferwiredcheckbox.set_active(daemon.GetPreferWiredNetwork())
|
||||
|
||||
dhcp_list = [self.dhcpautoradio, self.dhclientradio, self.dhcpcdradio,
|
||||
self.pumpradio, self.udhcpcradio]
|
||||
self._setup_external_app_radios(dhcp_list, daemon.GetDHCPClient,
|
||||
daemon.SetDHCPClient)
|
||||
|
||||
wired_link_list = [self.linkautoradio, self.ethtoolradio,
|
||||
self.miitoolradio]
|
||||
self._setup_external_app_radios(wired_link_list,
|
||||
daemon.GetLinkDetectionTool,
|
||||
daemon.SetLinkDetectionTool)
|
||||
|
||||
flush_list = [self.flushautoradio, self.ipflushradio,
|
||||
self.routeflushradio]
|
||||
self._setup_external_app_radios(flush_list, daemon.GetFlushTool,
|
||||
daemon.SetFlushTool)
|
||||
|
||||
sudo_list = [self.sudoautoradio, self.gksudoradio, self.kdesuradio,
|
||||
self.ktsussradio]
|
||||
self._setup_external_app_radios(sudo_list, daemon.GetSudoApp,
|
||||
daemon.SetSudoApp)
|
||||
|
||||
auto_conn_meth = daemon.GetWiredAutoConnectMethod()
|
||||
if auto_conn_meth == 1:
|
||||
self.usedefaultradiobutton.set_active(True)
|
||||
elif auto_conn_meth == 2:
|
||||
self.showlistradiobutton.set_active(True)
|
||||
elif auto_conn_meth == 3:
|
||||
self.lastusedradiobutton.set_active(True)
|
||||
|
||||
self.entryWirelessInterface.set_text(daemon.GetWirelessInterface())
|
||||
self.entryWiredInterface.set_text(daemon.GetWiredInterface())
|
||||
|
||||
def_driver = daemon.GetWPADriver()
|
||||
try:
|
||||
self.wpadrivercombo.set_active(self.wpadrivers.index(def_driver))
|
||||
except ValueError:
|
||||
self.wpadrivercombo.set_active(0)
|
||||
|
||||
self.useGlobalDNSCheckbox.connect("toggled", checkboxTextboxToggle,
|
||||
(self.dns1Entry, self.dns2Entry,
|
||||
self.dns3Entry, self.dnsDomEntry,
|
||||
self.searchDomEntry))
|
||||
|
||||
dns_addresses = daemon.GetGlobalDNSAddresses()
|
||||
self.useGlobalDNSCheckbox.set_active(daemon.GetUseGlobalDNS())
|
||||
self.dns1Entry.set_text(noneToBlankString(dns_addresses[0]))
|
||||
self.dns2Entry.set_text(noneToBlankString(dns_addresses[1]))
|
||||
self.dns3Entry.set_text(noneToBlankString(dns_addresses[2]))
|
||||
self.dnsDomEntry.set_text(noneToBlankString(dns_addresses[3]))
|
||||
self.searchDomEntry.set_text(noneToBlankString(dns_addresses[4]))
|
||||
|
||||
if not daemon.GetUseGlobalDNS():
|
||||
self.searchDomEntry.set_sensitive(False)
|
||||
self.dnsDomEntry.set_sensitive(False)
|
||||
self.dns1Entry.set_sensitive(False)
|
||||
self.dns2Entry.set_sensitive(False)
|
||||
self.dns3Entry.set_sensitive(False)
|
||||
|
||||
cur_backend = daemon.GetSavedBackend()
|
||||
try:
|
||||
self.backendcombo.set_active(self.backends.index(cur_backend))
|
||||
except ValueError:
|
||||
self.backendcombo.set_active(0)
|
||||
|
||||
self.notificationscheckbox.set_active(
|
||||
os.path.exists(
|
||||
os.path.join(USER_SETTINGS_DIR, 'USE_NOTIFICATIONS')
|
||||
))
|
||||
|
||||
# if pynotify isn't installed disable the option
|
||||
try:
|
||||
import pynotify
|
||||
except ImportError:
|
||||
self.notificationscheckbox.set_active(False)
|
||||
self.notificationscheckbox.set_sensitive(False)
|
||||
|
||||
# if notifications were disabled with the configure flag
|
||||
if wpath.no_use_notifications:
|
||||
self.notificationscheckbox.set_active(False)
|
||||
self.notificationscheckbox.hide()
|
||||
self.wTree.get_widget('label2').hide()
|
||||
|
||||
self.wTree.get_widget("notebook2").set_current_page(0)
|
||||
|
||||
def run(self):
|
||||
""" Runs the preferences dialog window. """
|
||||
return self.dialog.run()
|
||||
|
||||
def hide(self):
|
||||
""" Hides the preferences dialog window. """
|
||||
self.dialog.hide()
|
||||
|
||||
def destroy(self):
|
||||
self.dialog.destroy()
|
||||
|
||||
def show_all(self):
|
||||
""" Shows the preferences dialog window. """
|
||||
self.dialog.show()
|
||||
|
||||
def save_results(self):
|
||||
""" Pushes the selected settings to the daemon. """
|
||||
daemon.SetUseGlobalDNS(self.useGlobalDNSCheckbox.get_active())
|
||||
# Strip whitespace from DNS entries
|
||||
for i in [self.dns1Entry, self.dns2Entry, self.dns3Entry,
|
||||
self.dnsDomEntry, self.searchDomEntry]:
|
||||
i.set_text(i.get_text().strip())
|
||||
daemon.SetGlobalDNS(self.dns1Entry.get_text(), self.dns2Entry.get_text(),
|
||||
self.dns3Entry.get_text(), self.dnsDomEntry.get_text(),
|
||||
self.searchDomEntry.get_text())
|
||||
daemon.SetWirelessInterface(self.entryWirelessInterface.get_text())
|
||||
daemon.SetWiredInterface(self.entryWiredInterface.get_text())
|
||||
daemon.SetWPADriver(self.wpadrivers[self.wpadrivercombo.get_active()])
|
||||
daemon.SetAlwaysShowWiredInterface(self.wiredcheckbox.get_active())
|
||||
daemon.SetAutoReconnect(self.reconnectcheckbox.get_active())
|
||||
daemon.SetDebugMode(self.debugmodecheckbox.get_active())
|
||||
daemon.SetSignalDisplayType(int(self.displaytypecheckbox.get_active()))
|
||||
daemon.SetShouldVerifyAp(bool(self.verifyapcheckbox.get_active()))
|
||||
daemon.SetPreferWiredNetwork(bool(self.preferwiredcheckbox.get_active()))
|
||||
if self.showlistradiobutton.get_active():
|
||||
daemon.SetWiredAutoConnectMethod(2)
|
||||
elif self.lastusedradiobutton.get_active():
|
||||
daemon.SetWiredAutoConnectMethod(3)
|
||||
else:
|
||||
daemon.SetWiredAutoConnectMethod(1)
|
||||
|
||||
daemon.SetBackend(self.backends[self.backendcombo.get_active()])
|
||||
|
||||
# External Programs Tab
|
||||
if self.dhcpautoradio.get_active():
|
||||
dhcp_client = misc.AUTO
|
||||
elif self.dhclientradio.get_active():
|
||||
dhcp_client = misc.DHCLIENT
|
||||
elif self.dhcpcdradio.get_active():
|
||||
dhcp_client = misc.DHCPCD
|
||||
elif self.pumpradio.get_active():
|
||||
dhcp_client = misc.PUMP
|
||||
else:
|
||||
dhcp_client = misc.UDHCPC
|
||||
daemon.SetDHCPClient(dhcp_client)
|
||||
|
||||
if self.linkautoradio.get_active():
|
||||
link_tool = misc.AUTO
|
||||
elif self.ethtoolradio.get_active():
|
||||
link_tool = misc.ETHTOOL
|
||||
else:
|
||||
link_tool = misc.MIITOOL
|
||||
daemon.SetLinkDetectionTool(link_tool)
|
||||
|
||||
if self.flushautoradio.get_active():
|
||||
flush_tool = misc.AUTO
|
||||
elif self.ipflushradio.get_active():
|
||||
flush_tool = misc.IP
|
||||
else:
|
||||
flush_tool = misc.ROUTE
|
||||
daemon.SetFlushTool(flush_tool)
|
||||
|
||||
if self.sudoautoradio.get_active():
|
||||
sudo_tool = misc.AUTO
|
||||
elif self.gksudoradio.get_active():
|
||||
sudo_tool = misc.GKSUDO
|
||||
elif self.kdesuradio.get_active():
|
||||
sudo_tool = misc.KDESU
|
||||
else:
|
||||
sudo_tool = misc.KTSUSS
|
||||
daemon.SetSudoApp(sudo_tool)
|
||||
|
||||
[width, height] = self.dialog.get_size()
|
||||
daemon.WriteWindowSize(width, height, "pref")
|
||||
|
||||
not_path = os.path.join(USER_SETTINGS_DIR, 'USE_NOTIFICATIONS')
|
||||
if self.notificationscheckbox.get_active():
|
||||
if not os.path.exists(not_path):
|
||||
open(not_path, 'w')
|
||||
else:
|
||||
if os.path.exists(not_path):
|
||||
os.remove(not_path)
|
||||
# if this GUI was started by a tray icon,
|
||||
# instantly change the notifications there
|
||||
if self.parent.tray:
|
||||
self.parent.tray.icon_info.use_notify = \
|
||||
self.notificationscheckbox.get_active()
|
||||
|
||||
def set_label(self, glade_str, label):
|
||||
""" Sets the label for the given widget in wicd.glade. """
|
||||
self.wTree.get_widget(glade_str).set_label(label)
|
||||
|
||||
def prep_settings_diag(self):
|
||||
""" Set up anything that doesn't have to be persisted later. """
|
||||
def build_combobox(lbl):
|
||||
""" Sets up a ComboBox using the given widget name. """
|
||||
liststore = gtk.ListStore(gobject.TYPE_STRING)
|
||||
combobox = self.wTree.get_widget(lbl)
|
||||
combobox.clear()
|
||||
combobox.set_model(liststore)
|
||||
cell = gtk.CellRendererText()
|
||||
combobox.pack_start(cell, True)
|
||||
combobox.add_attribute(cell, 'text', 0)
|
||||
return combobox
|
||||
|
||||
def setup_label(name, lbl=""):
|
||||
""" Sets up a label for the given widget name. """
|
||||
widget = self.wTree.get_widget(name)
|
||||
# if lbl:
|
||||
# widget.set_label(language[lbl])
|
||||
if widget is None:
|
||||
raise ValueError('widget %s does not exist' % name)
|
||||
return widget
|
||||
|
||||
# External Programs tab
|
||||
# self.wTree.get_widget("gen_settings_label").set_label(language["gen_settings"])
|
||||
# self.wTree.get_widget("ext_prog_label").set_label(language["ext_programs"])
|
||||
# self.wTree.get_widget("dhcp_client_label").set_label(language["dhcp_client"])
|
||||
# self.wTree.get_widget("wired_detect_label").set_label(language["wired_detect"])
|
||||
# self.wTree.get_widget("route_flush_label").set_label(language["route_flush"])
|
||||
# self.wTree.get_widget("pref_backend_label").set_label(language["backend"] + ":")
|
||||
|
||||
# entryWiredAutoMethod = self.wTree.get_widget("pref_wired_auto_label")
|
||||
# entryWiredAutoMethod.set_label('Wired Autoconnect Setting:')
|
||||
# entryWiredAutoMethod.set_alignment(0, 0)
|
||||
# atrlist = pango.AttrList()
|
||||
# atrlist.insert(pango.AttrWeight(pango.WEIGHT_BOLD, 0, 50))
|
||||
# entryWiredAutoMethod.set_attributes(atrlist)
|
||||
|
||||
# self.set_label("pref_dns1_label", "%s %s" % (language['dns'], language['1']))
|
||||
# self.set_label("pref_dns2_label", "%s %s" % (language['dns'], language['2']))
|
||||
# self.set_label("pref_dns3_label", "%s %s" % (language['dns'], language['3']))
|
||||
# self.set_label("pref_search_dom_label", "%s:" % language['search_domain'])
|
||||
# self.set_label("pref_wifi_label", "%s:" % language['wireless_interface'])
|
||||
# self.set_label("pref_wired_label", "%s:" % language['wired_interface'])
|
||||
# self.set_label("pref_driver_label", "%s:" % language['wpa_supplicant_driver'])
|
||||
|
||||
self.dialog = self.wTree.get_widget("pref_dialog")
|
||||
self.dialog.set_title(language['preferences'])
|
||||
if os.path.exists(os.path.join(wpath.images, "wicd.png")):
|
||||
self.dialog.set_icon_from_file(os.path.join(wpath.images, "wicd.png"))
|
||||
size = daemon.ReadWindowSize("pref")
|
||||
width = size[0]
|
||||
height = size[1]
|
||||
if width > -1 and height > -1:
|
||||
self.dialog.resize(int(width), int(height))
|
||||
else:
|
||||
width = int(gtk.gdk.screen_width() / 2.4)
|
||||
if width > 450:
|
||||
width = 450
|
||||
self.dialog.resize(width, int(gtk.gdk.screen_height() / 2))
|
||||
|
||||
self.wiredcheckbox = setup_label("pref_always_check",
|
||||
'wired_always_on')
|
||||
self.preferwiredcheckbox = setup_label("pref_prefer_wired_check",
|
||||
"prefer_wired")
|
||||
|
||||
self.reconnectcheckbox = setup_label("pref_auto_check",
|
||||
'auto_reconnect')
|
||||
self.debugmodecheckbox = setup_label("pref_debug_check",
|
||||
'use_debug_mode')
|
||||
self.displaytypecheckbox = setup_label("pref_dbm_check",
|
||||
'display_type_dialog')
|
||||
self.verifyapcheckbox = setup_label("pref_verify_ap_check",
|
||||
'verify_ap_dialog')
|
||||
self.usedefaultradiobutton = setup_label("pref_use_def_radio",
|
||||
'use_default_profile')
|
||||
self.showlistradiobutton = setup_label("pref_prompt_radio",
|
||||
'show_wired_list')
|
||||
self.lastusedradiobutton = setup_label("pref_use_last_radio",
|
||||
'use_last_used_profile')
|
||||
|
||||
|
||||
self.notificationscheckbox = setup_label("pref_use_libnotify",
|
||||
'display_notifications')
|
||||
|
||||
# DHCP Clients
|
||||
self.dhcpautoradio = setup_label("dhcp_auto_radio", "wicd_auto_config")
|
||||
self.dhclientradio = self.wTree.get_widget("dhclient_radio")
|
||||
self.pumpradio = self.wTree.get_widget("pump_radio")
|
||||
self.dhcpcdradio = self.wTree.get_widget("dhcpcd_radio")
|
||||
self.udhcpcradio = self.wTree.get_widget("udhcpc_radio")
|
||||
|
||||
# Wired Link Detection Apps
|
||||
self.linkautoradio = setup_label("link_auto_radio", 'wicd_auto_config')
|
||||
self.linkautoradio = setup_label("link_auto_radio")
|
||||
self.ethtoolradio = setup_label("ethtool_radio")
|
||||
self.miitoolradio = setup_label("miitool_radio")
|
||||
|
||||
# Route Flushing Apps
|
||||
self.flushautoradio = setup_label("flush_auto_radio",
|
||||
'wicd_auto_config')
|
||||
self.ipflushradio = setup_label("ip_flush_radio")
|
||||
self.routeflushradio = setup_label("route_flush_radio")
|
||||
|
||||
# Graphical Sudo Apps
|
||||
self.sudoautoradio = setup_label("sudo_auto_radio", "wicd_auto_config")
|
||||
self.gksudoradio = setup_label("gksudo_radio")
|
||||
self.kdesuradio = setup_label("kdesu_radio")
|
||||
self.ktsussradio = setup_label("ktsuss_radio")
|
||||
|
||||
# Replacement for the combo box hack
|
||||
self.wpadrivercombo = build_combobox("pref_wpa_combobox")
|
||||
self.wpadrivers = wireless.GetWpaSupplicantDrivers()
|
||||
self.wpadrivers.append("ralink_legacy")
|
||||
|
||||
for x in self.wpadrivers:
|
||||
self.wpadrivercombo.append_text(x)
|
||||
|
||||
self.entryWirelessInterface = self.wTree.get_widget("pref_wifi_entry")
|
||||
self.entryWiredInterface = self.wTree.get_widget("pref_wired_entry")
|
||||
|
||||
# Set up global DNS stuff
|
||||
self.useGlobalDNSCheckbox = setup_label("pref_global_check",
|
||||
'use_global_dns')
|
||||
self.searchDomEntry = self.wTree.get_widget("pref_search_dom_entry")
|
||||
self.dnsDomEntry = self.wTree.get_widget("pref_dns_dom_entry")
|
||||
self.dns1Entry = self.wTree.get_widget("pref_dns1_entry")
|
||||
self.dns2Entry = self.wTree.get_widget("pref_dns2_entry")
|
||||
self.dns3Entry = self.wTree.get_widget("pref_dns3_entry")
|
||||
|
||||
self.backendcombo = build_combobox("pref_backend_combobox")
|
||||
self.backendcombo.connect("changed", self.be_combo_changed)
|
||||
# Load backend combobox
|
||||
self.backends = daemon.GetBackendList()
|
||||
self.be_descriptions = daemon.GetBackendDescriptionDict()
|
||||
|
||||
for x in self.backends:
|
||||
if x:
|
||||
self.backendcombo.append_text(x)
|
||||
|
||||
def be_combo_changed(self, combo):
|
||||
""" Update the description label for the given backend. """
|
||||
self.backendcombo.set_tooltip_text(
|
||||
self.be_descriptions[combo.get_active_text()]
|
||||
)
|
||||
1036
wicd/wicd-client.py
1036
wicd/wicd-client.py
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user