Пример #1
0
    def __init__(self):

        # Load window and widgets
        self.scriptName = basename(__file__)
        self.scriptDir = abspath(dirname(__file__))
        self.mediaDir = join(self.scriptDir, '../../share/usb-creator')
        self.builder = Gtk.Builder()
        self.builder.add_from_file(join(self.mediaDir, 'usb-creator.glade'))

        # Main window objects
        go = self.builder.get_object
        self.window = go("usb-creator")
        self.lblDevice = go("lblDevice")
        self.lblIso = go("lblIso")
        self.lblAvailable = go("lblAvailable")
        self.lblRequired = go("lblRequired")
        self.cmbDevice = go("cmbDevice")
        self.cmbDeviceHandler = ComboBoxHandler(self.cmbDevice)
        self.txtIso = go("txtIso")
        self.btnRefresh = go("btnRefresh")
        self.btnUnmount = go("btnUnmount")
        self.btnBrowseIso = go("btnBrowseIso")
        self.btnClear = go("btnClear")
        self.chkFormatDevice = go("chkFormatDevice")
        self.chkRepairDevice = go("chkRepairDevice")
        self.btnExecute = go("btnExecute")
        self.lblUsb = go("lblUsb")
        self.tvUsbIsos = go("tvUsbIsos")
        self.btnDelete = go("btnDelete")
        self.pbUsbCreator = go("pbUsbCreator")
        self.statusbar = go("statusbar")

        # Translations
        self.window.set_title(_("USB Creator"))
        self.lblDevice.set_label(_("Device"))
        self.lblUsb.set_label(_("USB"))
        self.available_text = _("Available")
        self.required_text = _("Required")
        self.chkFormatDevice.set_label(_("Format device"))
        self.chkFormatDevice.set_tooltip_text(_("Warning: all data will be lost"))
        self.chkRepairDevice.set_label(_("Repair device"))
        self.chkRepairDevice.set_tooltip_text(_("Tries to repair an unbootable USB"))
        self.btnExecute.set_label("_{}".format(_("Execute")))
        self.lblIso.set_label(_("ISO"))
        self.btnDelete.set_label("_{}".format(_("Delete")))
        self.btnRefresh.set_tooltip_text(_("Refresh device list"))
        self.btnUnmount.set_tooltip_text(_("Unmount device"))
        self.btnBrowseIso.set_tooltip_text(_("Browse for ISO file"))
        self.btnClear.set_tooltip_text(_("Clear the ISO field"))

        # Log lines to show: check string, percent done (0=pulse, appends last word in log line), show line (translatable)
        self.log_lines = []
        self.log_lines.append(["partitioning usb", 5, _("Partitioning USB...")])
        self.log_lines.append(["searching for bad blocks", 0, _("Searching for bad block")])
        self.log_lines.append(["installing", 15, _("Installing Grub...")])
        self.log_lines.append(["rsync", 25, _("Start copying ISO...")])
        self.log_lines.append(["left to copy", 0, _("kB left to copy:")])
        self.log_lines.append(["check hash", 85, _("Check hash of ISO...")])

        # Initiate variables
        self.devices = []
        self.device = {}
        self.device['path'] = ''
        self.device['size'] = 0
        self.device['has_partition'] = False
        self.device['mount'] = ''
        self.device['available'] = 0
        self.device["new_iso"] = ''
        self.device["new_iso_required"] = 0
        self.logos = self.get_logos()
        self.queue = Queue(-1)
        self.threads = {}
        self.htmlDir = join(self.mediaDir, "html")
        self.helpFile = join(self.get_language_dir(), "help.html")
        log = getoutput("cat /usr/bin/usb-creator | grep 'LOG=' | cut -d'=' -f 2")
        self.log_file = log[0]
        self.log = Logger(self.log_file, addLogTime=False, maxSizeKB=5120)
        self.tvUsbIsosHandler = TreeViewHandler(self.tvUsbIsos)

        self.lblAvailable.set_label('')
        self.lblRequired.set_label('')

        # Connect builder signals and show window
        self.builder.connect_signals(self)
        self.window.show_all()

        # Get attached devices
        self.on_btnRefresh_clicked()

        # Init log
        init_log = ">>> Start USB Creator: {} <<<".format(datetime.now())
        self.log.write(init_log)

        # Version information
        self.version_text = _("Version")
        self.pck_version = getPackageVersion('usb-creator')
        self.set_statusbar_message("{}: {}".format(self.version_text, self.pck_version))
Пример #2
0
    def __init__(self):
        self.scriptDir = os.path.dirname(os.path.realpath(__file__))

        # Load window and widgets
        self.builder = Gtk.Builder()
        self.builder.add_from_file(
            join(self.scriptDir,
                 '../../share/lightdm-manager/lightdm-manager.glade'))
        # Main window objects
        go = self.builder.get_object
        self.window = go('ldmWindow')
        self.swUsers = go('swUsers')
        self.tvUsers = go('tvUsers')
        self.btnSave = go('btnSave')
        self.imgBackground = go('imgBackground')
        self.btnUsers = go('btnUsers')
        self.btnAppearance = go('btnAppearance')
        self.chkHideUsers = go('chkHideUsers')
        self.ebFace = go('ebFace')
        self.imgFace = go('imgFace')
        self.nbLightDM = go('nbLightDM')
        self.cmbThemes = go('cmbThemes')

        # Read from config file
        self.cfg = Config('lightdm-manager.conf')
        self.lightdmConf = self.cfg.getValue('CONFIG', 'lightdmConf')
        self.desktopbaseDir = self.cfg.getValue('CONFIG', 'desktopbaseDir')
        gktGreeterConf = self.cfg.getValue('CONFIG', 'gtkGreeterConf')
        kdeGreeterConf = self.cfg.getValue('CONFIG', 'kdeGreeterConf')
        if exists(gktGreeterConf):
            self.greeterConf = gktGreeterConf
        else:
            self.greeterConf = kdeGreeterConf

        # Translations
        title = _("LightDM Manager")
        self.window.set_title(title)
        self.btnUsers.set_label("_{}".format(_("Users")))
        self.btnAppearance.set_label("_{}".format(_("Appearance")))
        go('lblBackground').set_label(_("Background"))
        go('lblTheme').set_label(_("Theme"))
        go('lblLightDmMenu').set_label(_("Menu"))
        self.chkHideUsers.set_label(_("Hide users"))
        go('lblUsersFace').set_label(_("User icon"))
        go('lblUsersAutologin').set_label(_("Auto-login"))

        # Get current background image
        self.cfgGreeter = Config(self.greeterConf)
        try:
            self.curBgPath = self.cfgGreeter.getValue('greeter', 'background')
            self.curTheme = self.cfgGreeter.getValue('greeter', 'theme-name')
        except:
            self.curBgPath = None
            self.curTheme = None

        # Get current auto-login user
        self.cfgLightdm = Config(self.lightdmConf)
        try:
            self.curAutoUser = self.cfgLightdm.getValue(
                'SeatDefaults', 'autologin-user').strip()
            self.curHideUsers = False
            ghu = self.cfgLightdm.getValue('SeatDefaults',
                                           'greeter-hide-users').strip()
            if 'true' in ghu:
                self.curHideUsers = True
        except:
            self.curAutoUser = None
            self.curHideUsers = False

        # Init
        self.usr = User()
        self.newbgImg = self.curBgPath
        self.newAutoUser = self.curAutoUser
        self.newTheme = self.curTheme
        self.themes = []
        self.selectedMenuItem = None
        self.debug = False
        self.logPath = ''
        self.prevPath = None
        self.tempFace = "/tmp/face"
        self.newFaces = []
        self.loggedUser = functions.getUserLoginName()
        self.curUser = self.loggedUser
        self.selectImg = join(self.scriptDir,
                              '../../share/lightdm-manager/select.png')

        # Handle arguments
        try:
            opts, args = getopt.getopt(sys.argv[1:], 'dl:', ['debug', 'log='])
        except getopt.GetoptError:
            print(("Arguments cannot be parsed: %s" % str(sys.argv[1:])))
            sys.exit(1)

        for opt, arg in opts:
            if opt in ('-d', '--debug'):
                self.debug = True
            elif opt in ('-l', '--log'):
                self.logPath = arg

        # Initialize logging
        if self.debug:
            if not self.logPath:
                self.logPath = 'lightdm-manager.log'
        self.log = Logger(self.logPath, 'debug', True, None, self.window)

        # Backup config files because ConfigParser does not preserve commented lines
        if not exists("%s.org" % self.greeterConf):
            copy(self.greeterConf, "%s.org" % self.greeterConf)
            self.log.write(
                "%(conf1)s copied to %(conf2)s.org" % {
                    "conf1": self.greeterConf,
                    "conf2": self.greeterConf
                }, 'LightDMManager.main', 'debug')
        if not exists("%s.org" % self.lightdmConf):
            copy(self.lightdmConf, "%s.org" % self.lightdmConf)
            self.log.write(
                "%(conf1)s copied to %(conf2)s.org" % {
                    "conf1": self.lightdmConf,
                    "conf2": self.lightdmConf
                }, 'LightDMManager.main', 'debug')

        # Initiate the treeview handler and connect the custom toggle event with usersCheckBoxToggled
        self.tvHandler = TreeViewHandler(self.tvUsers, self.log)
        self.tvHandler.connect('checkbox-toggled', self.usersCheckBoxToggled)

        # Get users
        self.users = self.usr.getUsers()
        self.fillUsers()
        self.tvHandler.selectValue(self.curUser, 1)
        self.setBackground(self.curBgPath)
        self.cmbHandlerThemes = ComboBoxHandler(self.cmbThemes)
        self.listThemes()
        self.chkHideUsers.set_active(self.curHideUsers)

        # Show users menu
        self.on_btnUsers_clicked(None)
        self.on_tvUsers_cursor_changed(None)

        self.version = functions.getPackageVersion('lightdm-manager')

        # Connect the signals and show the window
        self.builder.connect_signals(self)
        self.window.show()
Пример #3
0
class USBCreator(object):

    def __init__(self):

        # Load window and widgets
        self.scriptName = basename(__file__)
        self.scriptDir = abspath(dirname(__file__))
        self.mediaDir = join(self.scriptDir, '../../share/usb-creator')
        self.builder = Gtk.Builder()
        self.builder.add_from_file(join(self.mediaDir, 'usb-creator.glade'))

        # Main window objects
        go = self.builder.get_object
        self.window = go("usb-creator")
        self.lblDevice = go("lblDevice")
        self.lblIso = go("lblIso")
        self.lblAvailable = go("lblAvailable")
        self.lblRequired = go("lblRequired")
        self.cmbDevice = go("cmbDevice")
        self.cmbDeviceHandler = ComboBoxHandler(self.cmbDevice)
        self.txtIso = go("txtIso")
        self.btnRefresh = go("btnRefresh")
        self.btnUnmount = go("btnUnmount")
        self.btnBrowseIso = go("btnBrowseIso")
        self.btnClear = go("btnClear")
        self.chkFormatDevice = go("chkFormatDevice")
        self.chkRepairDevice = go("chkRepairDevice")
        self.btnExecute = go("btnExecute")
        self.lblUsb = go("lblUsb")
        self.tvUsbIsos = go("tvUsbIsos")
        self.btnDelete = go("btnDelete")
        self.pbUsbCreator = go("pbUsbCreator")
        self.statusbar = go("statusbar")

        # Translations
        self.window.set_title(_("USB Creator"))
        self.lblDevice.set_label(_("Device"))
        self.lblUsb.set_label(_("USB"))
        self.available_text = _("Available")
        self.required_text = _("Required")
        self.chkFormatDevice.set_label(_("Format device"))
        self.chkFormatDevice.set_tooltip_text(_("Warning: all data will be lost"))
        self.chkRepairDevice.set_label(_("Repair device"))
        self.chkRepairDevice.set_tooltip_text(_("Tries to repair an unbootable USB"))
        self.btnExecute.set_label("_{}".format(_("Execute")))
        self.lblIso.set_label(_("ISO"))
        self.btnDelete.set_label("_{}".format(_("Delete")))
        self.btnRefresh.set_tooltip_text(_("Refresh device list"))
        self.btnUnmount.set_tooltip_text(_("Unmount device"))
        self.btnBrowseIso.set_tooltip_text(_("Browse for ISO file"))
        self.btnClear.set_tooltip_text(_("Clear the ISO field"))

        # Log lines to show: check string, percent done (0=pulse, appends last word in log line), show line (translatable)
        self.log_lines = []
        self.log_lines.append(["partitioning usb", 5, _("Partitioning USB...")])
        self.log_lines.append(["searching for bad blocks", 0, _("Searching for bad block")])
        self.log_lines.append(["installing", 15, _("Installing Grub...")])
        self.log_lines.append(["rsync", 25, _("Start copying ISO...")])
        self.log_lines.append(["left to copy", 0, _("kB left to copy:")])
        self.log_lines.append(["check hash", 85, _("Check hash of ISO...")])

        # Initiate variables
        self.devices = []
        self.device = {}
        self.device['path'] = ''
        self.device['size'] = 0
        self.device['has_partition'] = False
        self.device['mount'] = ''
        self.device['available'] = 0
        self.device["new_iso"] = ''
        self.device["new_iso_required"] = 0
        self.logos = self.get_logos()
        self.queue = Queue(-1)
        self.threads = {}
        self.htmlDir = join(self.mediaDir, "html")
        self.helpFile = join(self.get_language_dir(), "help.html")
        log = getoutput("cat /usr/bin/usb-creator | grep 'LOG=' | cut -d'=' -f 2")
        self.log_file = log[0]
        self.log = Logger(self.log_file, addLogTime=False, maxSizeKB=5120)
        self.tvUsbIsosHandler = TreeViewHandler(self.tvUsbIsos)

        self.lblAvailable.set_label('')
        self.lblRequired.set_label('')

        # Connect builder signals and show window
        self.builder.connect_signals(self)
        self.window.show_all()

        # Get attached devices
        self.on_btnRefresh_clicked()

        # Init log
        init_log = ">>> Start USB Creator: {} <<<".format(datetime.now())
        self.log.write(init_log)

        # Version information
        self.version_text = _("Version")
        self.pck_version = getPackageVersion('usb-creator')
        self.set_statusbar_message("{}: {}".format(self.version_text, self.pck_version))

    # ===============================================
    # Main window functions
    # ===============================================

    def on_btnExecute_clicked(self, widget):
        if exists(self.device["path"]):
            arguments = []
            arguments.append("-d {}".format(self.device["path"]))
            clear = self.chkFormatDevice.get_active()
            repair = self.chkRepairDevice.get_active()
            iso = self.device["new_iso"]
            iso_path = self.txtIso.get_text().strip()

            # ISO path does not exist
            if iso != iso_path:
                msg = _("Cannot add ISO from path: {}.\n"
                        "Please, remove the ISO path or browse for an existing ISO.")
                WarningDialog(self.btnExecute.get_label(), msg.format(iso_path))
                return True

            # Check if there is enough space
            available = self.device["available"]
            if self.chkFormatDevice.get_active():
                available = self.device["size"]
            if available - self.device["new_iso_required"] < 0:
                msg = _("There is not enough space available on the pen drive.\n"
                        "Please, remove unneeded files before continuing.")
                WarningDialog(self.btnExecute.get_label(), msg)
                return True

            if clear:
                arguments.append("-f")
                arguments.append("-b")
            if repair:
                arguments.append("-r")
                arguments.append("-b")
                arguments.append("-g")
                # This should use the history file to get the original hash
                arguments.append("-s")
            if exists(iso):
                arguments.append("-i \"{}\"".format(iso))
                arguments.append("-s")

            cmd = "usb-creator {}".format(" ".join(arguments))
            self.log.write("Execute command: {}".format(cmd))
            self.exec_command(cmd)

    def on_btnDelete_clicked(self, widget):
        selected_isos = self.tvUsbIsosHandler.getToggledValues(toggleColNr=0, valueColNr=2)
        if selected_isos:
            msg =  _("Are you sure you want to remove the selected ISO from the device?")
            answer = QuestionDialog(self.btnDelete.get_label(), msg)
            if answer:
                for iso in selected_isos:
                    iso_path = join(self.device["mount"], iso)
                    if exists(iso_path):
                        os.remove(iso_path)
                        self.log.write("Remove ISO: {}".format(iso_path))
                shell_exec("usb-creator -d {} -g".format(self.device["path"]))
                self.on_cmbDevice_changed()
                self.fill_treeview_usbcreator(self.device["mount"])

    def on_btnBrowseIso_clicked(self, widget):
        file_filter = Gtk.FileFilter()
        file_filter.set_name("ISO")
        file_filter.add_mime_type("application/x-cd-image")
        file_filter.add_pattern("*.iso")

        start_dir = dirname(self.txtIso.get_text().strip())
        if not exists(start_dir):
            start_dir = expanduser("~")

        iso = SelectFileDialog(title=_('Select ISO'), start_directory=start_dir, gtkFileFilter=file_filter).show()
        if iso is not None:
            self.log.write("Add ISO: {}".format(iso))
            self.txtIso.set_text(iso)

    def on_btnClear_clicked(self, widget):
        self.txtIso.set_text('')

    def on_txtIso_changed(self, widget=None):
        iso_path = self.txtIso.get_text().strip()
        if exists(iso_path):
            if isdir(iso_path):
                isos = glob(join(iso_path, '*.iso'))
                if isos:
                    required = 0
                    for iso in isos:
                        # Check if these ISOs overwrite current USB ISOs
                        check_usb_iso_size = 0
                        if not self.chkFormatDevice.get_active():
                            check_usb_iso = join(self.device["mount"], basename(iso))
                            if exists(check_usb_iso):
                                check_usb_iso_size = self.get_iso_size(check_usb_iso)
                        required += (self.get_iso_size(iso) - check_usb_iso_size)
                    if required < 0:
                        required = 0
                    self.lblRequired.set_label("{}: {} MB".format(self.required_text, int(required / 1024)))
                    # Save the info
                    self.device["new_iso"] = iso_path
                    self.device["new_iso_required"] = required
                    self.log.write("New ISO directory: {}, {}".format(iso_path, required))
                else:
                    self.device["new_iso"] = ''
                    self.device["new_iso_required"] = 0
                    self.log.write("New ISO directory does not contain ISOs: {}".format(iso_path))
            else:
                # Check if this ISO overwrites current USB ISO
                check_usb_iso_size = 0
                if not self.chkFormatDevice.get_active():
                    check_usb_iso = join(self.device["mount"], basename(iso_path))
                    if exists(check_usb_iso):
                        check_usb_iso_size = self.get_iso_size(check_usb_iso)
                required = (self.get_iso_size(iso_path) - check_usb_iso_size)
                self.lblRequired.set_label("{}: {} MB".format(self.required_text, int(required / 1024)))
                # Save the info
                self.device["new_iso"] = iso_path
                self.device["new_iso_required"] = required
                self.log.write("New ISO: {}, {}".format(iso_path, required))
        else:
            self.device["new_iso"] = ''
            self.device["new_iso_required"] = 0
            self.lblRequired.set_text('')

    def on_btnRefresh_clicked(self, widget=None):
        self.devices = self.get_devices()
        self.cmbDeviceHandler.fillComboBox(self.devices, 0)

    def on_btnUnmount_clicked(self, widget):
        unmount_text = _("Unmount")
        device = self.device["path"]
        self.unmount_device(device)
        self.on_btnRefresh_clicked()
        if device in self.devices:
            msg = _("Could not unmount the device.\n"
                    "Please unmount the device manually.")
        else:
            msg = _("You can now safely remove the device.")
        MessageDialog(unmount_text, msg)

    def on_cmbDevice_changed(self, widget=None):
        device = self.cmbDeviceHandler.getValue()
        if device is not None:
            mount = ''
            size = 0
            available = 0

            # Get the size of the USB
            usb_size = getoutput("env LANG=C udisks --show-info {} | grep size".format(device))
            if usb_size:
                # udisks returns bytes, while df returns kbs
                size = int(int(usb_size[0].split(":")[1].strip()) / 1024)

            # Assume that the USB is empty (will check later)
            available = size

            # Get free size on USB
            has_partition = self.device_has_partition(device)
            if has_partition:
                mount = self.get_device_mount(device)
                # This function can be called from on_chkFormatDevice_toggled
                if widget != self.chkFormatDevice:
                    self.chkFormatDevice.set_sensitive(True)
                    self.chkFormatDevice.set_active(False)
                    free_size = getoutput("df --output=avail {}1 | awk 'NR==2'".format(device))
                    if free_size:
                        available = int(free_size[0])
            else:
                self.chkFormatDevice.set_active(True)
                self.chkFormatDevice.set_sensitive(False)

            self.chkRepairDevice.set_active(False)
            self.fill_treeview_usbcreator(mount)
            self.lblAvailable.set_label("{}: {} MB".format(self.available_text, int(available / 1024)))

            # Save the info
            self.device['path'] = device
            self.device['size'] = size
            self.device['has_partition'] = has_partition
            self.device['mount'] = mount
            self.device['available'] = available
            self.log.write("Selected device info: {}".format(self.device))

            # Update info
            iso_path = self.txtIso.get_text().strip()
            if iso_path != "" and exists(iso_path):
                self.on_txtIso_changed()
        else:
            self.fill_treeview_usbcreator()
            self.lblAvailable.set_label('')
            self.lblRequired.set_label('')
            self.txtIso.set_text('')
            self.device['path'] = ''
            self.device['size'] = 0
            self.device['has_partition'] = False
            self.device['mount'] = ''
            self.device['available'] = 0
            self.device["new_iso"] = ''
            self.device["new_iso_required"] = 0

    def on_chkFormatDevice_toggled(self, widget):
        # Recalculate available space and requied space
        self.on_cmbDevice_changed(widget)

    def on_btnHelp_clicked(self, widget):
        # Open the help file as the real user (not root)
        shell_exec("%s/open-as-user \"%s\"" % (self.scriptDir, self.helpFile))

    def fill_treeview_usbcreator(self, mount=''):
        isos_list = []
        # columns: checkbox, image (logo), device, driver
        column_types = ['bool', 'GdkPixbuf.Pixbuf', 'str', 'str']

        if exists(mount):
            isos = glob(join(mount, '*.iso'))
            for iso in isos:
                iso_name = basename(iso)
                iso_name_lower = iso_name.lower()
                iso_size = "{} MB".format(int(self.get_iso_size(iso) / 1024))
                iso_logo = ""
                for key, logo in list(self.logos.items()):
                    if key != "iso":
                        if key in iso_name_lower:
                            if len(logo) > len(iso_logo):
                                iso_logo = logo
                if iso_logo == "":
                    iso_logo = self.logos["iso"]
                self.log.write("ISO on {}: {}, {}, {}".format(mount, iso_name, iso_size, iso_logo))
                isos_list.append([False, iso_logo, iso_name, iso_size])

        # Fill treeview
        self.tvUsbIsosHandler.fillTreeview(contentList=isos_list, columnTypesList=column_types)

    def exec_command(self, command):
        try:
            # Run the command in a separate thread
            self.set_buttons_state(False)
            name = 'cmd'
            t = ExecuteThreadedCommands([command], self.queue)
            self.threads[name] = t
            t.daemon = True
            t.start()
            self.queue.join()
            GObject.timeout_add(1000, self.check_thread, name)

        except Exception as detail:
            ErrorDialog(self.btnExecute.get_label(), detail)

    def check_thread(self, name):
        if self.threads[name].is_alive():
            self.set_progress()
            if not self.queue.empty():
                ret = self.queue.get()
                self.log.write("Queue returns: {}".format(ret), 'check_thread')
                self.queue.task_done()
                self.show_message(ret)
            return True

        # Thread is done
        self.log.write(">> Thread is done", 'check_thread')
        if not self.queue.empty():
            ret = self.queue.get()
            self.queue.task_done()
            self.show_message(ret)
        del self.threads[name]
        self.set_buttons_state(True)
        self.on_cmbDevice_changed()
        self.fill_treeview_usbcreator(self.device["mount"])
        self.set_statusbar_message("{}: {}".format(self.version_text, self.pck_version))
        return False

    def set_buttons_state(self, enable):
        if not enable:
            # Disable buttons
            self.btnExecute.set_sensitive(False)
            self.btnDelete.set_sensitive(False)
            self.btnBrowseIso.set_sensitive(False)
            self.btnRefresh.set_sensitive(False)
            self.btnUnmount.set_sensitive(False)
            self.btnClear.set_sensitive(False)
            self.chkFormatDevice.set_sensitive(False)
            self.chkRepairDevice.set_sensitive(False)
            self.cmbDevice.set_sensitive(False)
            self.txtIso.set_sensitive(False)
        else:
            # Enable buttons and reset progress bar
            self.btnExecute.set_sensitive(True)
            self.btnDelete.set_sensitive(True)
            self.btnBrowseIso.set_sensitive(True)
            self.btnRefresh.set_sensitive(True)
            self.btnUnmount.set_sensitive(True)
            self.btnClear.set_sensitive(True)
            self.chkFormatDevice.set_sensitive(True)
            self.chkRepairDevice.set_sensitive(True)
            self.cmbDevice.set_sensitive(True)
            self.txtIso.set_sensitive(True)
            self.pbUsbCreator.set_fraction(0)

    def get_logos(self):
        logos_dict = {}
        logos_path = join(self.mediaDir, 'logos')
        logos = glob(join(logos_path, '*.png'))
        for logo in logos:
            key = splitext(basename(logo))[0]
            logos_dict[key] = logo
        return logos_dict

    def set_progress(self):
        if exists(self.log_file):
            msg = ''
            last_line = getoutput("tail -50 {} | grep -v DEBUG | grep -v ==".format(self.log_file))
            for line in reversed(last_line):
                # Check for session start line: that is the last line to check
                if ">>>>>" in line and "<<<<<" in line:
                    break
                for chk_line in self.log_lines:
                    if chk_line[0] in line.lower():
                        #print((line))
                        word = ''
                        if chk_line[1] == 0:
                            self.pbUsbCreator.pulse()
                            words = line.split(' ')
                            for word in reversed(words):
                                if word.strip() != '':
                                    break
                        else:
                            self.pbUsbCreator.set_fraction(float(chk_line[1] / 100))
                        msg = "{} {}".format(chk_line[2], word)
                        break
                if msg != '':
                    break
            self.set_statusbar_message(msg)

    def set_statusbar_message(self, message):
        if message is not None:
            context = self.statusbar.get_context_id('message')
            self.statusbar.push(context, message)

    def get_devices(self):
        devices = []
        my_devices = getoutput("udisks --enumerate-device-files | egrep '/dev/sd[a-z]$'")
        for device in my_devices:
            info = getoutput("env LANG=C udisks --show-info {}".format(device))
            detachable = False
            has_partition = False
            for line in info:
                if "detachable" in line and "1" in line:
                    detachable = True
                elif "partition" in line:
                    has_partition = True
                if detachable and has_partition:
                    devices.append(device)
                    break
        devices.sort()
        return devices

    def device_has_partition(self, device):
        part_count = getoutput("udisks --show-info {} | grep count | grep -v block".format(device))
        if part_count:
            if "1" in part_count[0]:
                return True
        return False

    def get_device_mount(self, device):
        shell_exec("udisks --mount {}1".format(device))
        mount = getoutput("grep %s1 /etc/mtab | awk '{print $2}' | sed 's/\\040/ /g'" % device)
        if mount:
            return mount[0]
        return ''

    def get_iso_size(self, iso):
        iso_size = getoutput("du -Lk \"%s\" | awk '{print $1}'" % iso)
        if iso_size:
            return int(iso_size[0])
        return 0

    def unmount_device(self, device):
        shell_exec("udisks --unmount {}1".format(device))
        shell_exec("udisks --detach {}".format(device))

    # Close the gui
    def on_usbcreator_destroy(self, widget):
        # Unmount devices
        for device in self.devices:
            if self.get_device_mount(device) != "":
                self.unmount_device(device)
        # Close the app
        Gtk.main_quit()

    def show_message(self, cmdOutput):
        try:
            self.log.write("Command output: {}".format(cmdOutput), 'show_message')
            ret = int(cmdOutput)
            if ret > 1 and ret != 255:
                if ret == 1:
                    ErrorDialog(self.btnExecute.get_label(), _("Run this application with root permission."))
                elif ret == 2:
                    ErrorDialog(self.btnExecute.get_label(), _("Wrong arguments were passed to usb-creator."))
                elif ret == 3:
                    ErrorDialog(self.btnExecute.get_label(), _("The device was not found or no device was given."))
                elif ret == 4:
                    ErrorDialog(self.btnExecute.get_label(), _("Given ISO path was not found."))
                elif ret == 5:
                    ErrorDialog(self.btnExecute.get_label(), _("Device is in use by another application."))
                elif ret == 6:
                    ErrorDialog(self.btnExecute.get_label(), _("Unable to mount the device."))
                elif ret == 7:
                    ErrorDialog(self.btnExecute.get_label(), _("Hash mismatch."))
                elif ret == 8:
                    ErrorDialog(self.btnExecute.get_label(), _("The device has no fat32 partition."))
                elif ret == 9:
                    ErrorDialog(self.btnExecute.get_label(), _("The device has no bootloader installed."))
                elif ret == 10:
                    ErrorDialog(self.btnExecute.get_label(), _("There is not enough space available on the device."))
                elif ret == 11:
                    ErrorDialog(self.btnExecute.get_label(), _("Unable to guess distribution from ISO name.\n"
                                                               "Make sure you have the distribution name in the ISO name."))
                else:
                    msg = _("An unknown error accured.\n"
                            "Please, visit our forum for support: http://forums.solydxk.com")
                    ErrorDialog(self.window.get_title(), msg)
            else:
                msg = _("The USB was successfully written.")
                MessageDialog(self.window.get_title(), msg)
        except:
            ErrorDialog(self.btnExecute.get_label(), cmdOutput)

    # ===============================================
    # Language specific functions
    # ===============================================

    def get_language_dir(self):
        # First test if full locale directory exists, e.g. html/pt_BR,
        # otherwise perhaps at least the language is there, e.g. html/pt
        # and if that doesn't work, try html/pt_PT
        lang = self.get_current_language()
        path = join(self.htmlDir, lang)
        if not isdir(path):
            base_lang = lang.split('_')[0].lower()
            path = join(self.htmlDir, base_lang)
            if not isdir(path):
                path = join(self.htmlDir, "{}_{}".format(base_lang, base_lang.upper()))
                if not isdir(path):
                    path = join(self.htmlDir, 'en')
        return path

    def get_current_language(self):
        lang = os.environ.get('LANG', 'US').split('.')[0]
        if lang == '':
            lang = 'en'
        return lang
    def __init__(self):
        self.scriptDir = os.path.dirname(os.path.realpath(__file__))

        # Load window and widgets
        self.builder = Gtk.Builder()
        self.builder.add_from_file(join(self.scriptDir, '../../share/lightdm-manager/lightdm-manager.glade'))
        # Main window objects
        go = self.builder.get_object
        self.window = go('ldmWindow')
        self.swUsers = go('swUsers')
        self.tvUsers = go('tvUsers')
        self.btnSave = go('btnSave')
        self.imgBackground = go('imgBackground')
        self.btnUsers = go('btnUsers')
        self.btnAppearance = go('btnAppearance')
        self.chkHideUsers = go('chkHideUsers')
        self.ebFace = go('ebFace')
        self.imgFace = go('imgFace')
        self.nbLightDM = go('nbLightDM')
        self.cmbThemes = go('cmbThemes')

        # Read from config file
        self.cfg = Config('lightdm-manager.conf')
        self.lightdmConf = self.cfg.getValue('CONFIG', 'lightdmConf')
        self.desktopbaseDir = self.cfg.getValue('CONFIG', 'desktopbaseDir')
        gktGreeterConf = self.cfg.getValue('CONFIG', 'gtkGreeterConf')
        kdeGreeterConf = self.cfg.getValue('CONFIG', 'kdeGreeterConf')
        if exists(gktGreeterConf):
            self.greeterConf = gktGreeterConf
        else:
            self.greeterConf = kdeGreeterConf

        # Translations
        title = _("LightDM Manager")
        self.window.set_title(title)
        self.btnUsers.set_label("_{}".format(_("Users")))
        self.btnAppearance.set_label("_{}".format(_("Appearance")))
        go('lblBackground').set_label(_("Background"))
        go('lblTheme').set_label(_("Theme"))
        go('lblLightDmMenu').set_label(_("Menu"))
        self.chkHideUsers.set_label(_("Hide users"))
        go('lblUsersFace').set_label(_("User icon"))
        go('lblUsersAutologin').set_label(_("Auto-login"))

        # Get current background image
        self.cfgGreeter = Config(self.greeterConf)
        try:
            self.curBgPath = self.cfgGreeter.getValue('greeter', 'background')
            self.curTheme = self.cfgGreeter.getValue('greeter', 'theme-name')
        except:
            self.curBgPath = None
            self.curTheme = None

        # Get current auto-login user
        self.cfgLightdm = Config(self.lightdmConf)
        try:
            self.curAutoUser = self.cfgLightdm.getValue('SeatDefaults', 'autologin-user').strip()
            self.curHideUsers = False
            ghu = self.cfgLightdm.getValue('SeatDefaults', 'greeter-hide-users').strip()
            if 'true' in ghu:
                self.curHideUsers = True
        except:
            self.curAutoUser = None
            self.curHideUsers = False

        # Init
        self.usr = User()
        self.newbgImg = self.curBgPath
        self.newAutoUser = self.curAutoUser
        self.newTheme = self.curTheme
        self.themes = []
        self.selectedMenuItem = None
        self.debug = False
        self.logPath = ''
        self.prevPath = None
        self.tempFace = "/tmp/face"
        self.newFaces = []
        self.loggedUser = functions.getUserLoginName()
        self.curUser = self.loggedUser
        self.selectImg = join(self.scriptDir, '../../share/lightdm-manager/select.png')

        # Handle arguments
        try:
            opts, args = getopt.getopt(sys.argv[1:], 'dl:', ['debug', 'log='])
        except getopt.GetoptError:
            print(("Arguments cannot be parsed: %s" % str(sys.argv[1:])))
            sys.exit(1)

        for opt, arg in opts:
            if opt in ('-d', '--debug'):
                self.debug = True
            elif opt in ('-l', '--log'):
                self.logPath = arg

        # Initialize logging
        if self.debug:
            if not self.logPath:
                self.logPath = 'lightdm-manager.log'
        self.log = Logger(self.logPath, 'debug', True, None, self.window)

        # Backup config files because ConfigParser does not preserve commented lines
        if not exists("%s.org" % self.greeterConf):
            copy(self.greeterConf, "%s.org" % self.greeterConf)
            self.log.write("%(conf1)s copied to %(conf2)s.org" % { "conf1": self.greeterConf, "conf2": self.greeterConf }, 'LightDMManager.main', 'debug')
        if not exists("%s.org" % self.lightdmConf):
            copy(self.lightdmConf, "%s.org" % self.lightdmConf)
            self.log.write("%(conf1)s copied to %(conf2)s.org" % { "conf1": self.lightdmConf, "conf2": self.lightdmConf }, 'LightDMManager.main', 'debug')

        # Initiate the treeview handler and connect the custom toggle event with usersCheckBoxToggled
        self.tvHandler = TreeViewHandler(self.tvUsers, self.log)
        self.tvHandler.connect('checkbox-toggled', self.usersCheckBoxToggled)

        # Get users
        self.users = self.usr.getUsers()
        self.fillUsers()
        self.tvHandler.selectValue(self.curUser, 1)
        self.setBackground(self.curBgPath)
        self.cmbHandlerThemes = ComboBoxHandler(self.cmbThemes)
        self.listThemes()
        self.chkHideUsers.set_active(self.curHideUsers)

        # Show users menu
        self.on_btnUsers_clicked(None)
        self.on_tvUsers_cursor_changed(None)

        self.version = functions.getPackageVersion('lightdm-manager')

        # Connect the signals and show the window
        self.builder.connect_signals(self)
        self.window.show()
Пример #5
0
class LightDMManager:
    def __init__(self):
        self.scriptDir = os.path.dirname(os.path.realpath(__file__))

        # Load window and widgets
        self.builder = Gtk.Builder()
        self.builder.add_from_file(
            join(self.scriptDir,
                 '../../share/lightdm-manager/lightdm-manager.glade'))
        # Main window objects
        go = self.builder.get_object
        self.window = go('ldmWindow')
        self.swUsers = go('swUsers')
        self.tvUsers = go('tvUsers')
        self.btnSave = go('btnSave')
        self.imgBackground = go('imgBackground')
        self.btnUsers = go('btnUsers')
        self.btnAppearance = go('btnAppearance')
        self.chkHideUsers = go('chkHideUsers')
        self.ebFace = go('ebFace')
        self.imgFace = go('imgFace')
        self.nbLightDM = go('nbLightDM')
        self.cmbThemes = go('cmbThemes')

        # Read from config file
        self.cfg = Config('lightdm-manager.conf')
        self.lightdmConf = self.cfg.getValue('CONFIG', 'lightdmConf')
        self.desktopbaseDir = self.cfg.getValue('CONFIG', 'desktopbaseDir')
        gktGreeterConf = self.cfg.getValue('CONFIG', 'gtkGreeterConf')
        kdeGreeterConf = self.cfg.getValue('CONFIG', 'kdeGreeterConf')
        if exists(gktGreeterConf):
            self.greeterConf = gktGreeterConf
        else:
            self.greeterConf = kdeGreeterConf

        # Translations
        title = _("LightDM Manager")
        self.window.set_title(title)
        self.btnUsers.set_label("_{}".format(_("Users")))
        self.btnAppearance.set_label("_{}".format(_("Appearance")))
        go('lblBackground').set_label(_("Background"))
        go('lblTheme').set_label(_("Theme"))
        go('lblLightDmMenu').set_label(_("Menu"))
        self.chkHideUsers.set_label(_("Hide users"))
        go('lblUsersFace').set_label(_("User icon"))
        go('lblUsersAutologin').set_label(_("Auto-login"))

        # Get current background image
        self.cfgGreeter = Config(self.greeterConf)
        try:
            self.curBgPath = self.cfgGreeter.getValue('greeter', 'background')
            self.curTheme = self.cfgGreeter.getValue('greeter', 'theme-name')
        except:
            self.curBgPath = None
            self.curTheme = None

        # Get current auto-login user
        self.cfgLightdm = Config(self.lightdmConf)
        try:
            self.curAutoUser = self.cfgLightdm.getValue(
                'SeatDefaults', 'autologin-user').strip()
            self.curHideUsers = False
            ghu = self.cfgLightdm.getValue('SeatDefaults',
                                           'greeter-hide-users').strip()
            if 'true' in ghu:
                self.curHideUsers = True
        except:
            self.curAutoUser = None
            self.curHideUsers = False

        # Init
        self.usr = User()
        self.newbgImg = self.curBgPath
        self.newAutoUser = self.curAutoUser
        self.newTheme = self.curTheme
        self.themes = []
        self.selectedMenuItem = None
        self.debug = False
        self.logPath = ''
        self.prevPath = None
        self.tempFace = "/tmp/face"
        self.newFaces = []
        self.loggedUser = functions.getUserLoginName()
        self.curUser = self.loggedUser
        self.selectImg = join(self.scriptDir,
                              '../../share/lightdm-manager/select.png')

        # Handle arguments
        try:
            opts, args = getopt.getopt(sys.argv[1:], 'dl:', ['debug', 'log='])
        except getopt.GetoptError:
            print(("Arguments cannot be parsed: %s" % str(sys.argv[1:])))
            sys.exit(1)

        for opt, arg in opts:
            if opt in ('-d', '--debug'):
                self.debug = True
            elif opt in ('-l', '--log'):
                self.logPath = arg

        # Initialize logging
        if self.debug:
            if not self.logPath:
                self.logPath = 'lightdm-manager.log'
        self.log = Logger(self.logPath, 'debug', True, None, self.window)

        # Backup config files because ConfigParser does not preserve commented lines
        if not exists("%s.org" % self.greeterConf):
            copy(self.greeterConf, "%s.org" % self.greeterConf)
            self.log.write(
                "%(conf1)s copied to %(conf2)s.org" % {
                    "conf1": self.greeterConf,
                    "conf2": self.greeterConf
                }, 'LightDMManager.main', 'debug')
        if not exists("%s.org" % self.lightdmConf):
            copy(self.lightdmConf, "%s.org" % self.lightdmConf)
            self.log.write(
                "%(conf1)s copied to %(conf2)s.org" % {
                    "conf1": self.lightdmConf,
                    "conf2": self.lightdmConf
                }, 'LightDMManager.main', 'debug')

        # Initiate the treeview handler and connect the custom toggle event with usersCheckBoxToggled
        self.tvHandler = TreeViewHandler(self.tvUsers, self.log)
        self.tvHandler.connect('checkbox-toggled', self.usersCheckBoxToggled)

        # Get users
        self.users = self.usr.getUsers()
        self.fillUsers()
        self.tvHandler.selectValue(self.curUser, 1)
        self.setBackground(self.curBgPath)
        self.cmbHandlerThemes = ComboBoxHandler(self.cmbThemes)
        self.listThemes()
        self.chkHideUsers.set_active(self.curHideUsers)

        # Show users menu
        self.on_btnUsers_clicked(None)
        self.on_tvUsers_cursor_changed(None)

        self.version = functions.getPackageVersion('lightdm-manager')

        # Connect the signals and show the window
        self.builder.connect_signals(self)
        self.window.show()

    # ===============================================
    # Menu section functions
    # ===============================================

    def on_btnUsers_clicked(self, widget, event=None):
        if self.selectedMenuItem != menuItems[0]:
            self.selectedMenuItem = menuItems[0]
            self.nbLightDM.set_current_page(0)

    def on_btnAppearance_clicked(self, widget, event=None):
        if self.selectedMenuItem != menuItems[1]:
            self.selectedMenuItem = menuItems[1]
            self.nbLightDM.set_current_page(1)

    # ===============================================
    # Functions
    # ===============================================

    def on_ebFace_enter_notify_event(self, widget, event):
        self.window.get_window().set_cursor(Gdk.Cursor(Gdk.CursorType.HAND2))

    def on_ebFace_leave_notify_event(self, widget, event):
        self.window.get_window().set_cursor(None)

    def on_ebFace_button_release_event(self, widget, event):
        home = self.usr.getUserHomeDir(self.curUser)
        primaryGroup = self.usr.getUserPrimaryGroupName(self.curUser)
        imagePath = SelectImageDialog(_('Select user image'), home,
                                      self.window).show()
        if imagePath is not None:
            tempUserImg = "%(tempFace)s.%(curUser)s" % {
                "tempFace": self.tempFace,
                "curUser": self.curUser
            }
            self.newFaces.append(
                [tempUserImg,
                 join(home, ".face"), self.curUser, primaryGroup])
            print((">>> self.newFaces = %s" % self.newFaces))
            ih = ImageHandler(imagePath)
            ih.makeFaceImage(tempUserImg)
            if exists(tempUserImg):
                self.imgFace.set_from_pixbuf(ih.pixbuf)
            else:
                # This should never happen
                self.imgFace.set_from_file(self.selectImg)

    def on_tvUsers_cursor_changed(self, widget):
        self.curUser = self.tvHandler.getSelectedValue(1)
        showFace = None
        if self.newFaces:
            for face in self.newFaces:
                if face[2] == self.curUser and exists(face[0]):
                    showFace = GdkPixbuf.Pixbuf.new_from_file(face[0])
        if showFace is None:
            showFace = self.usr.getUserFacePixbuf(self.curUser)
        if showFace is None:
            # Still no user icon found: show select image
            self.imgFace.set_from_file(self.selectImg)
        else:
            self.imgFace.set_from_pixbuf(showFace)

    def on_btnSave_clicked(self, widget):
        saved = False
        saveHideUsers = False
        saveAutoUser = False
        saveFaces = False
        saveBackground = False
        saveTheme = False
        if self.chkHideUsers.get_active() != self.curHideUsers:
            saveHideUsers = True
        if self.curAutoUser != self.newAutoUser:
            saveAutoUser = True
        if self.newFaces:
            saveFaces = True
        if self.curBgPath != self.newbgImg:
            saveBackground = True
        self.newTheme = self.cmbHandlerThemes.getValue()
        if self.curTheme != self.newTheme:
            saveTheme = True

        if saveHideUsers or saveAutoUser or saveFaces or saveBackground or saveTheme:
            qd = QuestionDialog(
                _("LightDM settings"),
                _("Settings have changed\n\nDo you want to save the new settings?"
                  ), self.window)
            answer = qd.show()
            if answer:
                if saveAutoUser:
                    if self.newAutoUser is not None:
                        # Save the auto-login user
                        self.cfgLightdm.setValue('SeatDefaults',
                                                 'autologin-user',
                                                 self.newAutoUser)
                        self.cfgLightdm.setValue('SeatDefaults',
                                                 'autologin-user-timeout', '0')
                        self.curAutoUser = self.newAutoUser
                        self.log.write(
                            "New auto-login user: %(usr)s" %
                            {"usr": self.curAutoUser},
                            'LightDMManager.saveSettings', 'debug')
                    else:
                        self.cfgLightdm.removeOption('SeatDefaults',
                                                     'autologin-user')
                        self.cfgLightdm.removeOption('SeatDefaults',
                                                     'autologin-user-timeout')
                        self.curAutoUser = None
                        self.log.write("Auto-login disabled",
                                       'LightDMManager.saveSettings', 'debug')
                if saveHideUsers:
                    hideUsers = str(self.chkHideUsers.get_active()).lower()
                    self.cfgLightdm.setValue('SeatDefaults',
                                             'greeter-hide-users', hideUsers)
                    self.log.write(
                        "Hide users saved: %(users)s" % {"users": hideUsers},
                        'LightDMManager.saveSettings', 'debug')
                if saveFaces:
                    for face in self.newFaces:
                        if exists(face[0]):
                            copy(face[0], face[1])
                            if exists(face[1]):
                                os.system(
                                    "chown %(owner)s:%(group)s %(path)s" % {
                                        "owner": face[2],
                                        "group": face[3],
                                        "path": face[1]
                                    })
                    self.log.write("User icons saved",
                                   'LightDMManager.saveSettings', 'debug')
                if saveTheme:
                    self.cfgGreeter.setValue('greeter', 'theme-name',
                                             self.newTheme)
                    self.curTheme = self.newTheme
                    self.log.write(
                        "Theme saved: %(theme)s" % {"theme": self.curTheme},
                        'LightDMManager.saveSettings', 'debug')
                if saveBackground:
                    if os.path.exists(self.newbgImg):
                        self.cfgGreeter.setValue('greeter', 'background',
                                                 self.newbgImg)
                        self.curBgPath = self.newbgImg
                        self.log.write(
                            "Background saved: %(background)s" %
                            {"background": self.curBgPath},
                            'LightDMManager.saveSettings', 'debug')
                saved = True
            else:
                if os.path.exists(self.curBgPath):
                    self.setBackground(self.curBgPath)
                    self.log.write(
                        "Current background: %(background)s" %
                        {"background": self.curBgPath},
                        'LightDMManager.saveSettings', 'debug')
                else:
                    self.imgBackground.set_from_file(
                        join(self.scriptDir,
                             '../../share/lightdm-manager/select.png'))
                    self.log.write("No background set",
                                   'LightDMManager.saveSettings', 'debug')
                self.fillUsers()

        if saved:
            self.curHideUsers = self.chkHideUsers.get_active()
            self.curAutoUser = self.newAutoUser
            self.newFaces = []
            self.curBgPath = self.newbgImg
            self.curTheme = self.newTheme
            MessageDialogSafe(_("Saved"),
                              _("LightDM settings saved successfully."),
                              Gtk.MessageType.INFO, self.window).show()

    def on_ebBackground_button_release_event(self, widget, event):
        self.newbgImg = SelectImageDialog(_("Choose background image"),
                                          self.desktopbaseDir,
                                          self.window).show()
        if exists(self.newbgImg) and self.newbgImg != self.curBgPath:
            self.setBackground(self.newbgImg)
            self.log.write(
                _("New background: %(bg)s") % {"bg": self.newbgImg},
                'LightDMManager.chooseFile', 'info')

    def on_ebBackground_enter_notify_event(self, widget, event):
        self.window.get_window().set_cursor(Gdk.Cursor(Gdk.CursorType.HAND2))

    def on_ebBackground_leave_notify_event(self, widget, event):
        self.window.get_window().set_cursor(None)

    # This method is fired by the TreeView.checkbox-toggled event
    def usersCheckBoxToggled(self, obj, path, colNr, toggleValue):
        path = int(path)
        model = self.tvUsers.get_model()
        itr = model.get_iter(path)
        user = model[itr][1]

        if self.prevPath != path or toggleValue:
            # Only one toggle box can be selected (or none)
            self.tvHandler.treeviewToggleAll([0], False, 1, user)
            # Save current path
            self.prevPath = path
            # Save selected user
            self.newAutoUser = user
            self.log.write(
                _("Auto-login user selected: %(usr)s") % {"usr": user},
                'LightDMManager.usersCheckBoxToggled', 'info')
        elif self.prevPath == path and not toggleValue:
            self.newAutoUser = None

    def listThemes(self):
        themeDir = '/usr/share/themes'
        themeDirLocal = '~/.local/share/themes'
        dirs = functions.locate('gtk-*', themeDir, True) + functions.locate(
            'gtk-*', themeDirLocal, True)
        for path in dirs:
            dirList = path.split('/')
            for d in dirList:
                if 'gtk-' in d:
                    break
                themeName = d
            if themeName not in self.themes:
                self.themes.append(themeName)
        if self.themes:
            self.cmbHandlerThemes.fillComboBox(self.themes)
            if self.curTheme in self.themes:
                self.cmbHandlerThemes.selectValue(self.curTheme)

    def fillUsers(self):
        selUsr = False
        contentList = []
        i = 0
        for usr in self.users:
            if usr == self.curAutoUser:
                selUsr = True
                self.prevPath = i
            else:
                selUsr = False
            contentList.append([selUsr, usr])
            i += 1

        # Fill treeview with users
        #fillTreeview(contentList, columnTypesList, columnHideList=[-1], setCursor=0, setCursorWeight=400, firstItemIsColName=False, appendToExisting=False, appendToTop=False)
        columnTypesList = ['bool', 'str']
        self.tvHandler.fillTreeview(contentList, columnTypesList)

    def setBackground(self, path):
        # Set Background
        if path is not None:
            if exists(path):
                ih = ImageHandler(path)
                ih.resizeImage(height=200)
                self.imgBackground.set_from_pixbuf(ih.pixbuf)
            else:
                self.imgBackground.set_from_file(self.selectImg)
        else:
            self.imgBackground.set_from_file(self.selectImg)

    # ===============================================
    # General functions
    # ===============================================

    def on_ldmWindow_destroy(self, widget, data=None):
        # Close the app
        self.on_btnSave_clicked(None)
        for tmp in self.newFaces:
            os.remove(tmp[0])
        Gtk.main_quit()
Пример #6
0
    def __init__(self, partition, mount_as, format_as):
        self.partition = partition

        # Load window and widgets
        self.scriptName = basename(__file__)
        self.scriptDir = abspath(dirname(__file__))
        self.mediaDir = join(self.scriptDir, '../../share/live-installer-3')
        self.builder = Gtk.Builder()
        self.builder.add_from_file(join(self.mediaDir, 'live-installer-3-dialog.glade'))

        # Main window objects
        self.go = self.builder.get_object
        self.window = self.go("dialog")
        self.window.set_transient_for(installer.window)
        self.window.set_destroy_with_parent(True)
        self.window.set_modal(True)
        self.window.set_title(_("Edit partition"))
        self.loading = True
        self.txt_label = self.go("txt_label")
        self.cmb_mount_point = self.go("combobox_mount_point")
        self.cmb_mount_point_handler = ComboBoxHandler(self.cmb_mount_point)
        self.cmb_use_as = self.go("combobox_use_as")
        self.cmb_use_as_handler = ComboBoxHandler(self.cmb_use_as)

        # Translations
        self.go("label_partition").set_markup("<b>%s</b>" % _("Device"))
        self.go("label_use_as").set_markup(_("Format as"))
        self.go("label_mount_point").set_markup(_("Mount point"))
        self.go("label_label").set_markup(_("Label (optional)"))
        self.go("chk_encryption").set_label(_("Encrypt partition"))
        self.go("label_encryption_pwd").set_label(_("Password"))

        # Show the selected partition path
        self.go("label_partition_value").set_label(self.partition.path)

        # Encryption
        self.go("chk_encryption").set_active(partition.encrypt)
        if partition.encrypt:
            self.go("frm_partition_encryption").set_sensitive(True)
            self.go("entry_encpass1").set_text(partition.enc_passphrase)
            self.go("entry_encpass2").set_text(partition.enc_passphrase)
        else:
            self.go("frm_partition_encryption").set_sensitive(False)
            self.go("entry_encpass1").set_text('')
            self.go("entry_encpass2").set_text('')

        # Label
        label_len = 16
        if "fat" in partition.type or "fat" in partition.mount_as:
            label_len = 11
        self.txt_label.set_max_length(label_len)
        self.txt_label.set_text(partition.label)

        # Build list of pre-provided mountpoints
        mounts = ",/,/home,/boot,/boot/efi,/srv,/tmp,/var,swap".split(',')
        self.cmb_mount_point_handler.fillComboBox(mounts)

        # Build supported filesystems list
        filesystems = sorted(['', 'swap'] +
                             [fs[11:] for fs in getoutput('echo /sbin/mkfs.*').split()],
                             key=lambda x: 0 if x in ('', 'ext4') else 1 if x == 'swap' else 2)
        self.cmb_use_as_handler.fillComboBox(filesystems)

        self.cmb_mount_point_handler.selectValue(mount_as)
        self.cmb_use_as_handler.selectValue(format_as)

        # Connect builder signals and show window
        self.builder.connect_signals(self)
        self.window.show_all()

        self.loading = False
class LightDMManager:

    def __init__(self):
        self.scriptDir = os.path.dirname(os.path.realpath(__file__))

        # Load window and widgets
        self.builder = Gtk.Builder()
        self.builder.add_from_file(join(self.scriptDir, '../../share/lightdm-manager/lightdm-manager.glade'))
        # Main window objects
        go = self.builder.get_object
        self.window = go('ldmWindow')
        self.swUsers = go('swUsers')
        self.tvUsers = go('tvUsers')
        self.btnSave = go('btnSave')
        self.imgBackground = go('imgBackground')
        self.btnUsers = go('btnUsers')
        self.btnAppearance = go('btnAppearance')
        self.chkHideUsers = go('chkHideUsers')
        self.ebFace = go('ebFace')
        self.imgFace = go('imgFace')
        self.nbLightDM = go('nbLightDM')
        self.cmbThemes = go('cmbThemes')

        # Read from config file
        self.cfg = Config('lightdm-manager.conf')
        self.lightdmConf = self.cfg.getValue('CONFIG', 'lightdmConf')
        self.desktopbaseDir = self.cfg.getValue('CONFIG', 'desktopbaseDir')
        gktGreeterConf = self.cfg.getValue('CONFIG', 'gtkGreeterConf')
        kdeGreeterConf = self.cfg.getValue('CONFIG', 'kdeGreeterConf')
        if exists(gktGreeterConf):
            self.greeterConf = gktGreeterConf
        else:
            self.greeterConf = kdeGreeterConf

        # Translations
        title = _("LightDM Manager")
        self.window.set_title(title)
        self.btnUsers.set_label("_{}".format(_("Users")))
        self.btnAppearance.set_label("_{}".format(_("Appearance")))
        go('lblBackground').set_label(_("Background"))
        go('lblTheme').set_label(_("Theme"))
        go('lblLightDmMenu').set_label(_("Menu"))
        self.chkHideUsers.set_label(_("Hide users"))
        go('lblUsersFace').set_label(_("User icon"))
        go('lblUsersAutologin').set_label(_("Auto-login"))

        # Get current background image
        self.cfgGreeter = Config(self.greeterConf)
        try:
            self.curBgPath = self.cfgGreeter.getValue('greeter', 'background')
            self.curTheme = self.cfgGreeter.getValue('greeter', 'theme-name')
        except:
            self.curBgPath = None
            self.curTheme = None

        # Get current auto-login user
        self.cfgLightdm = Config(self.lightdmConf)
        try:
            self.curAutoUser = self.cfgLightdm.getValue('SeatDefaults', 'autologin-user').strip()
            self.curHideUsers = False
            ghu = self.cfgLightdm.getValue('SeatDefaults', 'greeter-hide-users').strip()
            if 'true' in ghu:
                self.curHideUsers = True
        except:
            self.curAutoUser = None
            self.curHideUsers = False

        # Init
        self.usr = User()
        self.newbgImg = self.curBgPath
        self.newAutoUser = self.curAutoUser
        self.newTheme = self.curTheme
        self.themes = []
        self.selectedMenuItem = None
        self.debug = False
        self.logPath = ''
        self.prevPath = None
        self.tempFace = "/tmp/face"
        self.newFaces = []
        self.loggedUser = functions.getUserLoginName()
        self.curUser = self.loggedUser
        self.selectImg = join(self.scriptDir, '../../share/lightdm-manager/select.png')

        # Handle arguments
        try:
            opts, args = getopt.getopt(sys.argv[1:], 'dl:', ['debug', 'log='])
        except getopt.GetoptError:
            print(("Arguments cannot be parsed: %s" % str(sys.argv[1:])))
            sys.exit(1)

        for opt, arg in opts:
            if opt in ('-d', '--debug'):
                self.debug = True
            elif opt in ('-l', '--log'):
                self.logPath = arg

        # Initialize logging
        if self.debug:
            if not self.logPath:
                self.logPath = 'lightdm-manager.log'
        self.log = Logger(self.logPath, 'debug', True, None, self.window)

        # Backup config files because ConfigParser does not preserve commented lines
        if not exists("%s.org" % self.greeterConf):
            copy(self.greeterConf, "%s.org" % self.greeterConf)
            self.log.write("%(conf1)s copied to %(conf2)s.org" % { "conf1": self.greeterConf, "conf2": self.greeterConf }, 'LightDMManager.main', 'debug')
        if not exists("%s.org" % self.lightdmConf):
            copy(self.lightdmConf, "%s.org" % self.lightdmConf)
            self.log.write("%(conf1)s copied to %(conf2)s.org" % { "conf1": self.lightdmConf, "conf2": self.lightdmConf }, 'LightDMManager.main', 'debug')

        # Initiate the treeview handler and connect the custom toggle event with usersCheckBoxToggled
        self.tvHandler = TreeViewHandler(self.tvUsers, self.log)
        self.tvHandler.connect('checkbox-toggled', self.usersCheckBoxToggled)

        # Get users
        self.users = self.usr.getUsers()
        self.fillUsers()
        self.tvHandler.selectValue(self.curUser, 1)
        self.setBackground(self.curBgPath)
        self.cmbHandlerThemes = ComboBoxHandler(self.cmbThemes)
        self.listThemes()
        self.chkHideUsers.set_active(self.curHideUsers)

        # Show users menu
        self.on_btnUsers_clicked(None)
        self.on_tvUsers_cursor_changed(None)

        self.version = functions.getPackageVersion('lightdm-manager')

        # Connect the signals and show the window
        self.builder.connect_signals(self)
        self.window.show()

    # ===============================================
    # Menu section functions
    # ===============================================

    def on_btnUsers_clicked(self, widget, event=None):
        if self.selectedMenuItem != menuItems[0]:
            self.selectedMenuItem = menuItems[0]
            self.nbLightDM.set_current_page(0)

    def on_btnAppearance_clicked(self, widget, event=None):
        if self.selectedMenuItem != menuItems[1]:
            self.selectedMenuItem = menuItems[1]
            self.nbLightDM.set_current_page(1)

    # ===============================================
    # Functions
    # ===============================================

    def on_ebFace_enter_notify_event(self, widget, event):
        self.window.get_window().set_cursor(Gdk.Cursor(Gdk.CursorType.HAND2))

    def on_ebFace_leave_notify_event(self, widget, event):
        self.window.get_window().set_cursor(None)

    def on_ebFace_button_release_event(self, widget, event):
        home = self.usr.getUserHomeDir(self.curUser)
        primaryGroup = self.usr.getUserPrimaryGroupName(self.curUser)
        imagePath = SelectImageDialog(_('Select user image'), home, self.window).show()
        if imagePath is not None:
            tempUserImg = "%(tempFace)s.%(curUser)s" % {"tempFace": self.tempFace, "curUser": self.curUser}
            self.newFaces.append([tempUserImg, join(home, ".face"), self.curUser, primaryGroup])
            print((">>> self.newFaces = %s" % self.newFaces))
            ih = ImageHandler(imagePath)
            ih.makeFaceImage(tempUserImg)
            if exists(tempUserImg):
                self.imgFace.set_from_pixbuf(ih.pixbuf)
            else:
                # This should never happen
                self.imgFace.set_from_file(self.selectImg)

    def on_tvUsers_cursor_changed(self, widget):
        self.curUser = self.tvHandler.getSelectedValue(1)
        showFace = None
        if self.newFaces:
            for face in self.newFaces:
                if face[2] == self.curUser and exists(face[0]):
                    showFace = GdkPixbuf.Pixbuf.new_from_file(face[0])
        if showFace is None:
            showFace = self.usr.getUserFacePixbuf(self.curUser)
        if showFace is None:
            # Still no user icon found: show select image
            self.imgFace.set_from_file(self.selectImg)
        else:
            self.imgFace.set_from_pixbuf(showFace)

    def on_btnSave_clicked(self, widget):
        saved = False
        saveHideUsers = False
        saveAutoUser = False
        saveFaces = False
        saveBackground = False
        saveTheme = False
        if self.chkHideUsers.get_active() != self.curHideUsers:
            saveHideUsers = True
        if self.curAutoUser != self.newAutoUser:
            saveAutoUser = True
        if self.newFaces:
            saveFaces = True
        if self.curBgPath != self.newbgImg:
            saveBackground = True
        self.newTheme = self.cmbHandlerThemes.getValue()
        if self.curTheme != self.newTheme:
            saveTheme = True

        if saveHideUsers or saveAutoUser or saveFaces or saveBackground or saveTheme:
            qd = QuestionDialog(_("LightDM settings"), _("Settings have changed\n\nDo you want to save the new settings?"), self.window)
            answer = qd.show()
            if answer:
                if saveAutoUser:
                    if self.newAutoUser is not None:
                        # Save the auto-login user
                        self.cfgLightdm.setValue('SeatDefaults', 'autologin-user', self.newAutoUser)
                        self.cfgLightdm.setValue('SeatDefaults', 'autologin-user-timeout', '0')
                        self.curAutoUser = self.newAutoUser
                        self.log.write("New auto-login user: %(usr)s" % { "usr": self.curAutoUser }, 'LightDMManager.saveSettings', 'debug')
                    else:
                        self.cfgLightdm.removeOption('SeatDefaults', 'autologin-user')
                        self.cfgLightdm.removeOption('SeatDefaults', 'autologin-user-timeout')
                        self.curAutoUser = None
                        self.log.write("Auto-login disabled", 'LightDMManager.saveSettings', 'debug')
                if saveHideUsers:
                    hideUsers = str(self.chkHideUsers.get_active()).lower()
                    self.cfgLightdm.setValue('SeatDefaults', 'greeter-hide-users', hideUsers)
                    self.log.write("Hide users saved: %(users)s" % {"users": hideUsers}, 'LightDMManager.saveSettings', 'debug')
                if saveFaces:
                    for face in self.newFaces:
                        if exists(face[0]):
                            copy(face[0], face[1])
                            if exists(face[1]):
                                os.system("chown %(owner)s:%(group)s %(path)s" % {"owner": face[2], "group": face[3], "path": face[1]})
                    self.log.write("User icons saved", 'LightDMManager.saveSettings', 'debug')
                if saveTheme:
                    self.cfgGreeter.setValue('greeter', 'theme-name', self.newTheme)
                    self.curTheme = self.newTheme
                    self.log.write("Theme saved: %(theme)s" % { "theme": self.curTheme }, 'LightDMManager.saveSettings', 'debug')
                if saveBackground:
                    if os.path.exists(self.newbgImg):
                        self.cfgGreeter.setValue('greeter', 'background', self.newbgImg)
                        self.curBgPath = self.newbgImg
                        self.log.write("Background saved: %(background)s" % { "background": self.curBgPath }, 'LightDMManager.saveSettings', 'debug')
                saved = True
            else:
                if os.path.exists(self.curBgPath):
                    self.setBackground(self.curBgPath)
                    self.log.write("Current background: %(background)s" % { "background": self.curBgPath }, 'LightDMManager.saveSettings', 'debug')
                else:
                    self.imgBackground.set_from_file(join(self.scriptDir, '../../share/lightdm-manager/select.png'))
                    self.log.write("No background set", 'LightDMManager.saveSettings', 'debug')
                self.fillUsers()

        if saved:
            self.curHideUsers = self.chkHideUsers.get_active()
            self.curAutoUser = self.newAutoUser
            self.newFaces = []
            self.curBgPath = self.newbgImg
            self.curTheme = self.newTheme
            MessageDialogSafe(_("Saved"), _("LightDM settings saved successfully."), Gtk.MessageType.INFO, self.window).show()


    def on_ebBackground_button_release_event(self, widget, event):
        self.newbgImg = SelectImageDialog(_("Choose background image"), self.desktopbaseDir, self.window).show()
        if exists(self.newbgImg) and self.newbgImg != self.curBgPath:
            self.setBackground(self.newbgImg)
            self.log.write(_("New background: %(bg)s") % { "bg": self.newbgImg }, 'LightDMManager.chooseFile', 'info')

    def on_ebBackground_enter_notify_event(self, widget, event):
        self.window.get_window().set_cursor(Gdk.Cursor(Gdk.CursorType.HAND2))

    def on_ebBackground_leave_notify_event(self, widget, event):
        self.window.get_window().set_cursor(None)

    # This method is fired by the TreeView.checkbox-toggled event
    def usersCheckBoxToggled(self, obj, path, colNr, toggleValue):
        path = int(path)
        model = self.tvUsers.get_model()
        itr = model.get_iter(path)
        user = model[itr][1]

        if self.prevPath != path or toggleValue:
            # Only one toggle box can be selected (or none)
            self.tvHandler.treeviewToggleAll([0], False, 1, user)
            # Save current path
            self.prevPath = path
            # Save selected user
            self.newAutoUser = user
            self.log.write(_("Auto-login user selected: %(usr)s") % { "usr": user }, 'LightDMManager.usersCheckBoxToggled', 'info')
        elif self.prevPath == path and not toggleValue:
            self.newAutoUser = None

    def listThemes(self):
        themeDir = '/usr/share/themes'
        themeDirLocal = '~/.local/share/themes'
        dirs = functions.locate('gtk-*', themeDir, True) + functions.locate('gtk-*', themeDirLocal, True)
        for path in dirs:
            dirList = path.split('/')
            for d in dirList:
                if 'gtk-' in d:
                    break
                themeName = d
            if themeName not in self.themes:
                self.themes.append(themeName)
        if self.themes:
            self.cmbHandlerThemes.fillComboBox(self.themes)
            if self.curTheme in self.themes:
                self.cmbHandlerThemes.selectValue(self.curTheme)

    def fillUsers(self):
        selUsr = False
        contentList = []
        i = 0
        for usr in self.users:
            if usr == self.curAutoUser:
                selUsr = True
                self.prevPath = i
            else:
                selUsr = False
            contentList.append([selUsr, usr])
            i += 1

        # Fill treeview with users
        #fillTreeview(contentList, columnTypesList, columnHideList=[-1], setCursor=0, setCursorWeight=400, firstItemIsColName=False, appendToExisting=False, appendToTop=False)
        columnTypesList = ['bool', 'str']
        self.tvHandler.fillTreeview(contentList, columnTypesList)

    def setBackground(self, path):
        # Set Background
        if path is not None:
            if exists(path):
                ih = ImageHandler(path)
                ih.resizeImage(height=200)
                self.imgBackground.set_from_pixbuf(ih.pixbuf)
            else:
                self.imgBackground.set_from_file(self.selectImg)
        else:
            self.imgBackground.set_from_file(self.selectImg)

    # ===============================================
    # General functions
    # ===============================================

    def on_ldmWindow_destroy(self, widget, data=None):
        # Close the app
        self.on_btnSave_clicked(None)
        for tmp in self.newFaces:
            os.remove(tmp[0])
        Gtk.main_quit()
Пример #8
0
    def __init__(self):

        # Load window and widgets
        self.scriptName = basename(__file__)
        self.scriptDir = abspath(dirname(__file__))
        self.mediaDir = join(self.scriptDir, '../../share/usb-creator')
        self.builder = Gtk.Builder()
        self.builder.add_from_file(join(self.mediaDir, 'usb-creator.glade'))

        # Main window objects
        go = self.builder.get_object
        self.window = go("usb-creator")
        self.lblDevice = go("lblDevice")
        self.lblIso = go("lblIso")
        self.lblAvailable = go("lblAvailable")
        self.lblRequired = go("lblRequired")
        self.cmbDevice = go("cmbDevice")
        self.cmbDeviceHandler = ComboBoxHandler(self.cmbDevice)
        self.txtIso = go("txtIso")
        self.btnRefresh = go("btnRefresh")
        self.btnUnmount = go("btnUnmount")
        self.btnBrowseIso = go("btnBrowseIso")
        self.btnClear = go("btnClear")
        self.chkFormatDevice = go("chkFormatDevice")
        self.chkRepairDevice = go("chkRepairDevice")
        self.btnExecute = go("btnExecute")
        self.lblUsb = go("lblUsb")
        self.tvUsbIsos = go("tvUsbIsos")
        self.btnDelete = go("btnDelete")
        self.pbUsbCreator = go("pbUsbCreator")
        self.statusbar = go("statusbar")

        # Translations
        self.window.set_title(_("USB Creator"))
        self.lblDevice.set_label(_("Device"))
        self.lblUsb.set_label(_("USB"))
        self.available_text = _("Available")
        self.required_text = _("Required")
        self.chkFormatDevice.set_label(_("Format device"))
        self.chkFormatDevice.set_tooltip_text(
            _("Warning: all data will be lost"))
        self.chkRepairDevice.set_label(_("Repair device"))
        self.chkRepairDevice.set_tooltip_text(
            _("Tries to repair an unbootable USB"))
        self.btnExecute.set_label("_{}".format(_("Execute")))
        self.lblIso.set_label(_("ISO"))
        self.btnDelete.set_label("_{}".format(_("Delete")))
        self.btnRefresh.set_tooltip_text(_("Refresh device list"))
        self.btnUnmount.set_tooltip_text(_("Unmount device"))
        self.btnBrowseIso.set_tooltip_text(_("Browse for ISO file"))
        self.btnClear.set_tooltip_text(_("Clear the ISO field"))

        # Log lines to show: check string, percent done (0=pulse, appends last word in log line), show line (translatable)
        self.log_lines = []
        self.log_lines.append(
            ["partitioning usb", 5,
             _("Partitioning USB...")])
        self.log_lines.append(
            ["searching for bad blocks", 0,
             _("Searching for bad block")])
        self.log_lines.append(["installing", 15, _("Installing Grub...")])
        self.log_lines.append(["rsync", 25, _("Start copying ISO...")])
        self.log_lines.append(["left to copy", 0, _("kB left to copy:")])
        self.log_lines.append(["check hash", 85, _("Check hash of ISO...")])

        # Initiate variables
        self.device = {}
        self.device['path'] = ''
        self.device['mount'] = ''
        self.device['size'] = 0
        self.device['available'] = 0
        self.device["new_iso"] = ''
        self.device["new_iso_required"] = 0
        self.logos = self.get_logos()
        self.queue = Queue(-1)
        self.threads = {}
        self.htmlDir = join(self.mediaDir, "html")
        self.helpFile = join(self.get_language_dir(), "help.html")
        log = getoutput(
            "cat /usr/bin/usb-creator | grep 'LOG=' | cut -d'=' -f 2")
        self.log_file = log[0]
        self.log = Logger(self.log_file, addLogTime=False, maxSizeKB=5120)
        self.tvUsbIsosHandler = TreeViewHandler(self.tvUsbIsos)
        self.udisks2 = Udisks2()

        self.lblAvailable.set_label('')
        self.lblRequired.set_label('')

        # Connect builder signals and show window
        self.builder.connect_signals(self)
        self.window.show_all()

        # Get attached devices
        self.on_btnRefresh_clicked()

        # Init log
        init_log = ">>> Start USB Creator: {} <<<".format(datetime.now())
        self.log.write(init_log)

        # Version information
        self.version_text = _("Version")
        self.pck_version = getPackageVersion('usb-creator')
        self.set_statusbar_message("{}: {}".format(self.version_text,
                                                   self.pck_version))
Пример #9
0
class PartitionDialog(object):
    def __init__(self, partition, mount_as, format_as):
        self.partition = partition

        # Load window and widgets
        self.scriptName = basename(__file__)
        self.scriptDir = abspath(dirname(__file__))
        self.mediaDir = join(self.scriptDir, '../../share/live-installer-3')
        self.builder = Gtk.Builder()
        self.builder.add_from_file(join(self.mediaDir, 'live-installer-3-dialog.glade'))

        # Main window objects
        self.go = self.builder.get_object
        self.window = self.go("dialog")
        self.window.set_transient_for(installer.window)
        self.window.set_destroy_with_parent(True)
        self.window.set_modal(True)
        self.window.set_title(_("Edit partition"))
        self.loading = True
        self.txt_label = self.go("txt_label")
        self.cmb_mount_point = self.go("combobox_mount_point")
        self.cmb_mount_point_handler = ComboBoxHandler(self.cmb_mount_point)
        self.cmb_use_as = self.go("combobox_use_as")
        self.cmb_use_as_handler = ComboBoxHandler(self.cmb_use_as)

        # Translations
        self.go("label_partition").set_markup("<b>%s</b>" % _("Device"))
        self.go("label_use_as").set_markup(_("Format as"))
        self.go("label_mount_point").set_markup(_("Mount point"))
        self.go("label_label").set_markup(_("Label (optional)"))
        self.go("chk_encryption").set_label(_("Encrypt partition"))
        self.go("label_encryption_pwd").set_label(_("Password"))

        # Show the selected partition path
        self.go("label_partition_value").set_label(self.partition.path)

        # Encryption
        self.go("chk_encryption").set_active(partition.encrypt)
        if partition.encrypt:
            self.go("frm_partition_encryption").set_sensitive(True)
            self.go("entry_encpass1").set_text(partition.enc_passphrase)
            self.go("entry_encpass2").set_text(partition.enc_passphrase)
        else:
            self.go("frm_partition_encryption").set_sensitive(False)
            self.go("entry_encpass1").set_text('')
            self.go("entry_encpass2").set_text('')

        # Label
        label_len = 16
        if "fat" in partition.type or "fat" in partition.mount_as:
            label_len = 11
        self.txt_label.set_max_length(label_len)
        self.txt_label.set_text(partition.label)

        # Build list of pre-provided mountpoints
        mounts = ",/,/home,/boot,/boot/efi,/srv,/tmp,/var,swap".split(',')
        self.cmb_mount_point_handler.fillComboBox(mounts)

        # Build supported filesystems list
        filesystems = sorted(['', 'swap'] +
                             [fs[11:] for fs in getoutput('echo /sbin/mkfs.*').split()],
                             key=lambda x: 0 if x in ('', 'ext4') else 1 if x == 'swap' else 2)
        self.cmb_use_as_handler.fillComboBox(filesystems)

        self.cmb_mount_point_handler.selectValue(mount_as)
        self.cmb_use_as_handler.selectValue(format_as)

        # Connect builder signals and show window
        self.builder.connect_signals(self)
        self.window.show_all()

        self.loading = False

    def on_combobox_mount_point_changed(self, widget):
        mount_as = self.cmb_mount_point_handler.getValue()
        if "boot" in mount_as:
            # Cannot encrypt
            self.go("chk_encryption").set_active(False)
            self.go("chk_encryption").set_sensitive(False)
            self.go("frm_partition_encryption").set_sensitive(False)
            self.go("entry_encpass1").set_text('')
            self.go("entry_encpass2").set_text('')
        else:
            # Can encrypt
            self.loading = True
            self.go("chk_encryption").set_sensitive(True)
            self.loading = False

        # Set label for OS
        if self.txt_label.get_text() == '':
            if mount_as == '/':
                self.txt_label.set_text(get_release_name())

        # swap
        if mount_as == 'swap' and self.partition.type != 'swap':
            self.cmb_use_as_handler.selectValue('swap')

        # efi
        if 'efi' in mount_as and 'fat' not in self.partition.type:
            self.cmb_use_as_handler.selectValue('vfat')

    def on_combobox_use_as_changed(self, widget):
        format_as = self.cmb_use_as_handler.getValue()
        mount_as = self.cmb_mount_point_handler.getValue()
        if format_as == 'swap' and mount_as != 'swap':
            self.cmb_mount_point_handler.selectValue('swap')

    def on_button_cancel_clicked(self, widget):
        # Close window without saving
        self.window.hide()

    def on_chk_encryption_toggled(self, widget):
        if self.loading: return
        if widget.get_active():
            # Show warning message
            mount_as = self.cmb_mount_point_handler.getValue()
            if mount_as == '/':
                encrypt = QuestionDialog(_("Encryption"),
                                         _("You chose to encrypt the root partition.\n\n"
                                           "You will need to mount /boot on a separate non-encrypted partition (500 MB).\n"
                                           "Without a non-encrypted /boot partition your system will be unbootable.\n\n"
                                           "Encryption will erase all data from {}\n\n"
                                           "Are you sure you want to continue?").format(self.partition.path))
            else:
                encrypt = QuestionDialog(_("Encryption"),
                                         _("Encryption will erase all data from {}\n\n"
                                           "Are you sure you want to continue?").format(self.partition.path))
            if encrypt:
                format_as = self.cmb_use_as_handler.getValue()
                if not format_as:
                    self.cmb_use_as_handler.selectValue('ext4')
                self.go("frm_partition_encryption").set_sensitive(True)
                self.go("entry_encpass1").set_text(self.partition.enc_passphrase)
                self.go("entry_encpass2").set_text(self.partition.enc_passphrase)
                self.go("entry_encpass1").grab_focus()
            else:
                widget.set_active(False)
                self.go("frm_partition_encryption").set_sensitive(False)
                self.go("entry_encpass1").set_text("")
                self.go("entry_encpass2").set_text("")
        else:
            self.go("frm_partition_encryption").set_sensitive(False)
            self.go("entry_encpass1").set_text("")
            self.go("entry_encpass2").set_text("")

    def on_entry_encpass1_changed(self, widget):
        self.assign_enc_password()

    def on_entry_encpass2_changed(self, widget):
        self.assign_enc_password()

    def assign_enc_password(self):
        encryption_pwd1 = self.go("entry_encpass1").get_text()
        encryption_pwd2 = self.go("entry_encpass2").get_text()
        if(encryption_pwd1 == "" and encryption_pwd2 == ""):
            self.go("image_enc_mismatch").hide()
        else:
            self.go("image_enc_mismatch").show()
        if(encryption_pwd1 != encryption_pwd2):
            self.go("image_enc_mismatch").set_from_stock(Gtk.STOCK_NO, Gtk.IconSize.BUTTON)
        else:
            self.go("image_enc_mismatch").set_from_stock(Gtk.STOCK_OK, Gtk.IconSize.BUTTON)

    def on_button_ok_clicked(self, widget):
        # Collect data
        format_as = self.cmb_use_as_handler.getValue()
        mount_as = self.cmb_mount_point_handler.getValue()
        encrypt = self.go("chk_encryption").get_active()
        enc_passphrase1 = self.go("entry_encpass1").get_text().strip()
        enc_passphrase2 = self.go("entry_encpass2").get_text().strip()
        label = self.txt_label.get_text().strip()

        # Check user input
        if encrypt:
            errorFound = False
            if enc_passphrase1 == "":
                errorFound = True
                errorMessage = _("Please provide an encryption password.")
            elif enc_passphrase1 != enc_passphrase2:
                errorFound = True
                errorMessage = _("Your encryption passwords do not match.")
            elif not format_as:
                errorFound = True
                errorMessage = "{} {}".format(_("You need to choose a format type\n"
                               "for your encrypted partition (default: ext4):"), self.partition.path)
                self.cmb_use_as_handler.selectValue('ext4')
            if not mount_as:
                errorFound = True
                errorMessage = "{} {}".format(_("You need to choose a mount point for partition:"), self.partition.path)

            if errorFound:
                ErrorDialog(_("Encryption"), errorMessage)
                return True
        else:
            # For good measure
            enc_passphrase1 = ''

        # Save the settings and close the window
        assign_mount_point(self.partition, mount_as, format_as, encrypt, enc_passphrase1, label)
        self.window.hide()

    def on_dialog_delete_event(self, widget, data=None):
        self.window.hide()
        return True
Пример #10
0
    def __init__(self):
        self.scriptDir = abspath(dirname(__file__))

        # Load window and widgets
        self.builder = Gtk.Builder()
        self.builder.add_from_file(join(self.scriptDir, '../../share/usermanager/usermanager.glade'))
        # Main window objects
        go = self.builder.get_object
        self.window = go('usermanagerWindow')
        self.tvUsersMain = go('tvUsersMain')
        self.tvUserGroupsMain = go('tvUserGroupsMain')
        self.chkShowSystemUsers = go('chkShowSystemUsers')
        self.btnUserEdit = go('btnUserEdit')
        self.btnUserRemove = go('btnUserRemove')
        # User window objects
        self.windowUser = go('usermanagerUserWindow')
        self.nbUser = go('nbUser')
        self.txtLoginName = go('txtLoginName')
        self.txtRealName = go('txtRealName')
        self.txtUserID = go('txtUserID')
        self.txtHomeDirectory = go('txtHomeDirectory')
        self.cmbShells = go('cmbShells')
        self.cmbPrimaryGroup = go('cmbPrimaryGroup')
        self.cmbPrimaryGroupEntry = go('cmbPrimaryGroupEntry')
        self.tvUserGroups = go('tvUserGroups')
        self.ebFace = go('ebFace')
        self.imgFace = go('imgFace')
        self.lblUserID = go('lblUserID')
        self.txtPassword = go('txtPassword')
        self.txtLastChanged = go('txtLastChanged')
        self.cmbValidUntilMonth = go('cmbValidUntilMonth')
        self.spbValidUntilDay = go('spbValidUntilDay')
        self.spbValidUntilYear = go('spbValidUntilYear')
        self.radEnabled = go('radEnabled')
        self.radDisabled = go('radDisabled')
        self.radValidUntilAlways = go('radValidUntilAlways')
        self.radValidUntilDate = go('radValidUntilDate')
        self.spbRequirePasswordAfter = go('spbRequirePasswordAfter')
        self.spbWarnBeforePasswordExpires = go('spbWarnBeforePasswordExpires')
        self.spbDisableAccountWhenPasswordExpires = go('spbDisableAccountWhenPasswordExpires')
        self.spbEnforceMinimumPasswordAge = go('spbEnforceMinimumPasswordAge')
        self.chkRequirePasswordAfter = go('chkRequirePasswordAfter')
        self.chkEnforceMinimumPasswordAge = go('chkEnforceMinimumPasswordAge')
        self.tvGroupsMain = go('tvGroupsMain')
        # Group window objects
        self.windowGroup = go('usermanagerGroupWindow')
        self.txtGroupName = go('txtGroupName')
        self.txtGroupID = go('txtGroupID')
        self.tvAccounts = go('tvAccounts')
        self.tvSelectedAccounts = go('tvSelectedAccounts')
        self.tvGroupAccounts = go('tvGroupAccounts')

        # Main window translations
        self.window.set_title(_("User manager"))
        self.chkShowSystemUsers.set_label(_("Show system users"))
        self.btnUserEdit.set_label(_("Edit"))
        self.btnUserRemove.set_label(_("Remove"))
        go('btnUserAdd').set_label(_("Add"))
        go('lblUsersTab').set_text(_("Users"))
        go('lblGroupsTab').set_text(_("Groups"))
        go('lblUsersMain').set_text(go('lblUsersTab').get_text())
        go('lblUserGroupsMain').set_text(_("User groups"))
        go('lblGroupsMain').set_text(go('lblGroupsTab').get_text())
        go('lblGroupAccountsMain').set_text(_("Group accounts"))
        # User window translations
        self.windowUser.set_title(_("User settings"))
        go('lblUserDetails').set_text(_("Details"))
        go('lblStatus').set_text(_("Status"))
        go('lblLoginName').set_text(_("Login name"))
        go('lblRealName').set_text(_("Real name"))
        go('lblUserID').set_text(_("User ID"))
        go('lblPrimaryGroup').set_text(_("Primary group"))
        go('lblHomeDirectory').set_text(_("Home directory"))
        go('lblShell').set_text(_("Shell"))
        self.radEnabled.set_label(_("Enabled"))
        self.radDisabled.set_label(_("Disabled"))
        #go('lblPrivilegesAndGroups').set_text(_("Privileges and groups"))
        go('lblPrivilegesAndGroups').set_text(go('lblGroupsTab').get_text())
        go('lblPrivileges').set_text(_("Privileges"))
        go('lblUserGroups').set_text(go('lblGroupsTab').get_text())
        go('lblPasswordSecurity').set_text(_("Password"))
        go('lblPassword').set_text(go('lblPasswordSecurity').get_text())
        go('lblLastChanged').set_text(_("Last changed"))
        go('lblValidUntil').set_text(_("Valid until"))
        self.radValidUntilAlways.set_label(_("Always"))
        go('lblPasswordAging').set_text(_("Password aging"))
        self.chkRequirePasswordAfter.set_label(_("Require password after"))
        go('lblWarnBeforePasswordExpires').set_text(_("Warn before password expires after"))
        go('lblDisableAccountWhenPasswordExpires').set_text(_("Disable account when password expires after"))
        self.chkEnforceMinimumPasswordAge.set_label(_("Enforce minimum password age"))
        go('lblDays1').set_text(_("days"))
        go('lblDays2').set_text(go('lblDays1').get_text())
        go('lblDays3').set_text(go('lblDays1').get_text())
        go('lblDays4').set_text(go('lblDays1').get_text())
        go('btnSaveUser').set_label(_("Save"))
        go('btnCancelUser').set_label(_("Cancel"))
        # Group window translations
        self.windowGroup.set_title(_("Group settings"))
        go('lblGroupName').set_text(_("Group name"))
        go('lblGroupID').set_text(_("Group ID"))
        go('lblAccounts').set_text(_("Available accounts"))
        go('lblSelectedAccounts').set_text(_("Selected accounts"))
        go('btnOkGroup').set_label(go('btnSaveUser').get_label())
        go('btnCancelGroup').set_label(go('btnCancelUser').get_label())
        go('btnAddAccount').set_label(go('btnUserAdd').get_label())
        go('btnRemoveAccount').set_label(self.btnUserRemove.get_label())

        # Init
        self.ec = ExecCmd()
        self.usr = User()
        self.usersInfo = {}
        self.user = {}
        self.users = []
        self.accounts = []
        self.shells = self.usr.getShells()
        self.groups = None
        self.loggedinUser = self.usr.getLoggedinUser()
        self.loggedinUserPrimaryGroup = self.usr.getUserPrimaryGroupName(self.loggedinUser)
        self.selectedUser = None
        self.selectedGroup = None
        self.selectedGroupAccounts = None
        self.userFace = None
        self.radEnabled.set_active(True)
        self.radValidUntilAlways.set_active(True)
        self.setValidUntil(False)
        self.setRequirePasswordAfter(False)
        self.setEnforceMinimumPasswordAge(False)
        self.txtUserID.set_editable(False)
        self.txtUserID.set_can_focus(False)
        self.txtLastChanged.set_editable(False)
        self.txtLastChanged.set_can_focus(False)
        self.txtGroupID.set_editable(False)
        self.txtGroupID.set_can_focus(False)
        self.passwordChanged = False
        self.homeDirChanged = False
        self.tempFace = "/tmp/face.png"

        self.filterText(self.txtLoginName)
        self.filterText(self.txtGroupName)
        self.filterText(self.cmbPrimaryGroupEntry)

        # Treeviews
        self.tvHandlerUsersMain = TreeViewHandler(self.tvUsersMain)
        self.tvHandlerUserGroupsMain = TreeViewHandler(self.tvUserGroupsMain)
        self.tvHandlerUserGroups = TreeViewHandler(self.tvUserGroups)
        self.tvHandlerAccounts = TreeViewHandler(self.tvAccounts)
        self.tvHandlerSelectedAccounts = TreeViewHandler(self.tvSelectedAccounts)
        self.tvHandlerGroupsMain = TreeViewHandler(self.tvGroupsMain)
        self.tvHandlerGroupAccounts = TreeViewHandler(self.tvGroupAccounts)
        # Comboboxes
        self.cmbHandlerShells = ComboBoxHandler(self.cmbShells)
        self.cmbHandlerPrimaryGroup = ComboBoxHandler(self.cmbPrimaryGroup)
        self.cmbHandlerValidUntilMonth = ComboBoxHandler(self.cmbValidUntilMonth)

        # Get data
        self.refreshData()
        self.cmbHandlerShells.fillComboBox(self.shells)
        self.cmbHandlerValidUntilMonth.fillComboBox(functions.getMonthsList())
        year = datetime.now().year
        adj = Gtk.Adjustment(value=year, lower=year, upper=year + 10, step_incr=1, page_incr=0, page_size=0)
        self.spbValidUntilYear.set_adjustment(adj)

        # Connect the signals and show the window
        self.builder.connect_signals(self)
        self.window.show()
Пример #11
0
class USBCreator(object):
    def __init__(self):

        # Load window and widgets
        self.scriptName = basename(__file__)
        self.scriptDir = abspath(dirname(__file__))
        self.mediaDir = join(self.scriptDir, '../../share/usb-creator')
        self.builder = Gtk.Builder()
        self.builder.add_from_file(join(self.mediaDir, 'usb-creator.glade'))

        # Main window objects
        go = self.builder.get_object
        self.window = go("usb-creator")
        self.lblDevice = go("lblDevice")
        self.lblIso = go("lblIso")
        self.lblAvailable = go("lblAvailable")
        self.lblRequired = go("lblRequired")
        self.cmbDevice = go("cmbDevice")
        self.cmbDeviceHandler = ComboBoxHandler(self.cmbDevice)
        self.txtIso = go("txtIso")
        self.btnRefresh = go("btnRefresh")
        self.btnUnmount = go("btnUnmount")
        self.btnBrowseIso = go("btnBrowseIso")
        self.btnClear = go("btnClear")
        self.chkFormatDevice = go("chkFormatDevice")
        self.chkRepairDevice = go("chkRepairDevice")
        self.btnExecute = go("btnExecute")
        self.lblUsb = go("lblUsb")
        self.tvUsbIsos = go("tvUsbIsos")
        self.btnDelete = go("btnDelete")
        self.pbUsbCreator = go("pbUsbCreator")
        self.statusbar = go("statusbar")

        # Translations
        self.window.set_title(_("USB Creator"))
        self.lblDevice.set_label(_("Device"))
        self.lblUsb.set_label(_("USB"))
        self.available_text = _("Available")
        self.required_text = _("Required")
        self.chkFormatDevice.set_label(_("Format device"))
        self.chkFormatDevice.set_tooltip_text(
            _("Warning: all data will be lost"))
        self.chkRepairDevice.set_label(_("Repair device"))
        self.chkRepairDevice.set_tooltip_text(
            _("Tries to repair an unbootable USB"))
        self.btnExecute.set_label("_{}".format(_("Execute")))
        self.lblIso.set_label(_("ISO"))
        self.btnDelete.set_label("_{}".format(_("Delete")))
        self.btnRefresh.set_tooltip_text(_("Refresh device list"))
        self.btnUnmount.set_tooltip_text(_("Unmount device"))
        self.btnBrowseIso.set_tooltip_text(_("Browse for ISO file"))
        self.btnClear.set_tooltip_text(_("Clear the ISO field"))

        # Log lines to show: check string, percent done (0=pulse, appends last word in log line), show line (translatable)
        self.log_lines = []
        self.log_lines.append(
            ["partitioning usb", 5,
             _("Partitioning USB...")])
        self.log_lines.append(
            ["searching for bad blocks", 0,
             _("Searching for bad block")])
        self.log_lines.append(["installing", 15, _("Installing Grub...")])
        self.log_lines.append(["rsync", 25, _("Start copying ISO...")])
        self.log_lines.append(["left to copy", 0, _("kB left to copy:")])
        self.log_lines.append(["check hash", 85, _("Check hash of ISO...")])

        # Initiate variables
        self.device = {}
        self.device['path'] = ''
        self.device['mount'] = ''
        self.device['size'] = 0
        self.device['available'] = 0
        self.device["new_iso"] = ''
        self.device["new_iso_required"] = 0
        self.logos = self.get_logos()
        self.queue = Queue(-1)
        self.threads = {}
        self.htmlDir = join(self.mediaDir, "html")
        self.helpFile = join(self.get_language_dir(), "help.html")
        log = getoutput(
            "cat /usr/bin/usb-creator | grep 'LOG=' | cut -d'=' -f 2")
        self.log_file = log[0]
        self.log = Logger(self.log_file, addLogTime=False, maxSizeKB=5120)
        self.tvUsbIsosHandler = TreeViewHandler(self.tvUsbIsos)
        self.udisks2 = Udisks2()

        self.lblAvailable.set_label('')
        self.lblRequired.set_label('')

        # Connect builder signals and show window
        self.builder.connect_signals(self)
        self.window.show_all()

        # Get attached devices
        self.on_btnRefresh_clicked()

        # Init log
        init_log = ">>> Start USB Creator: {} <<<".format(datetime.now())
        self.log.write(init_log)

        # Version information
        self.version_text = _("Version")
        self.pck_version = getPackageVersion('usb-creator')
        self.set_statusbar_message("{}: {}".format(self.version_text,
                                                   self.pck_version))

    # ===============================================
    # Main window functions
    # ===============================================

    def on_btnExecute_clicked(self, widget):
        if exists(self.device["path"]):
            arguments = []
            arguments.append("-d {}".format(self.device["path"]))
            clear = self.chkFormatDevice.get_active()
            repair = self.chkRepairDevice.get_active()
            iso = self.device["new_iso"]
            iso_path = self.txtIso.get_text().strip()

            # ISO path does not exist
            if iso != iso_path:
                msg = _(
                    "Cannot add ISO from path: {}.\n"
                    "Please, remove the ISO path or browse for an existing ISO."
                )
                WarningDialog(self.btnExecute.get_label(),
                              msg.format(iso_path))
                return True

            # Check if there is enough space
            available = self.device["available"]
            if self.chkFormatDevice.get_active():
                available = self.device["size"]
            if (available) - self.device["new_iso_required"] < 0:
                msg = _(
                    "There is not enough space available on the pen drive.\n"
                    "Please, remove unneeded files before continuing.")
                WarningDialog(self.btnExecute.get_label(), msg)
                return True

            if clear:
                arguments.append("-f")
                arguments.append("-b")
            if repair:
                arguments.append("-r")
                arguments.append("-b")
                arguments.append("-g")
                # This should use the history file to get the original hash
                arguments.append("-s")
            if exists(iso):
                arguments.append("-i \"{}\"".format(iso))
                arguments.append("-s")

            cmd = "usb-creator {}".format(" ".join(arguments))
            self.log.write("Execute command: {}".format(cmd))
            self.exec_command(cmd)

    def on_btnDelete_clicked(self, widget):
        selected_isos = self.tvUsbIsosHandler.getToggledValues(toggleColNr=0,
                                                               valueColNr=2)
        if selected_isos:
            msg = _(
                "Are you sure you want to remove the selected ISO from the device?"
            )
            answer = QuestionDialog(self.btnDelete.get_label(), msg)
            if answer:
                for iso in selected_isos:
                    iso_path = join(self.device["mount"], iso)
                    if exists(iso_path):
                        os.remove(iso_path)
                        self.log.write("Remove ISO: {}".format(iso_path))
                shell_exec("usb-creator -d {} -g".format(self.device["path"]))
                self.on_btnRefresh_clicked()
                self.fill_treeview_usbcreator(self.device["mount"])

    def on_btnBrowseIso_clicked(self, widget):
        file_filter = Gtk.FileFilter()
        file_filter.set_name("ISO")
        file_filter.add_mime_type("application/x-cd-image")
        file_filter.add_pattern("*.iso")

        start_dir = dirname(self.txtIso.get_text().strip())
        if not exists(start_dir):
            start_dir = expanduser("~")

        iso = SelectFileDialog(title=_('Select ISO'),
                               start_directory=start_dir,
                               gtkFileFilter=file_filter).show()
        if iso is not None:
            self.log.write("Add ISO: {}".format(iso))
            self.txtIso.set_text(iso)

    def on_btnClear_clicked(self, widget):
        self.txtIso.set_text('')

    def on_txtIso_changed(self, widget=None):
        iso_path = self.txtIso.get_text().strip()
        if exists(iso_path):
            if isdir(iso_path):
                isos = glob(join(iso_path, '*.iso'))
                if isos:
                    required = 0
                    for iso in isos:
                        # Check if these ISOs overwrite current USB ISOs
                        check_usb_iso_size = 0
                        if not self.chkFormatDevice.get_active():
                            check_usb_iso = join(self.device["mount"],
                                                 basename(iso))
                            if exists(check_usb_iso):
                                check_usb_iso_size = self.get_iso_size(
                                    check_usb_iso)
                        required += (self.get_iso_size(iso) -
                                     check_usb_iso_size)
                    if required < 0:
                        required = 0
                    self.lblRequired.set_label("{}: {} MB".format(
                        self.required_text, int(required / 1024)))
                    # Save the info
                    self.device["new_iso"] = iso_path
                    self.device["new_iso_required"] = required
                    self.log.write("New ISO directory: {}, {}".format(
                        iso_path, required))
                else:
                    self.device["new_iso"] = ''
                    self.device["new_iso_required"] = 0
                    self.log.write(
                        "New ISO directory does not contain ISOs: {}".format(
                            iso_path))
            else:
                # Check if this ISO overwrites current USB ISO
                check_usb_iso_size = 0
                if not self.chkFormatDevice.get_active():
                    check_usb_iso = join(self.device["mount"],
                                         basename(iso_path))
                    if exists(check_usb_iso):
                        check_usb_iso_size = self.get_iso_size(check_usb_iso)
                required = (self.get_iso_size(iso_path) - check_usb_iso_size)
                self.lblRequired.set_label("{}: {} MB".format(
                    self.required_text, int(required / 1024)))
                # Save the info
                self.device["new_iso"] = iso_path
                self.device["new_iso_required"] = required
                self.log.write("New ISO: {}, {}".format(iso_path, required))
        else:
            self.device["new_iso"] = ''
            self.device["new_iso_required"] = 0
            self.lblRequired.set_text('')

    def on_btnRefresh_clicked(self, widget=None):
        self.udisks2.fill_devices()
        drives = self.udisks2.get_drives()
        self.cmbDeviceHandler.fillComboBox(drives, 0)

    def on_btnUnmount_clicked(self, widget):
        unmount_text = _("Unmount")
        device = self.device["path"]
        try:
            self.udisks2.unmount_drive(device)
            self.on_btnRefresh_clicked()
            msg = _("You can now safely remove the device.")
        except Exception as e:
            msg = _("Could not unmount the device.\n"
                    "Please unmount the device manually.")
            self.log.write("ERROR: %s" % str(e))
        MessageDialog(unmount_text, msg)

    def on_cmbDevice_changed(self, widget=None):
        drive_path = self.cmbDeviceHandler.getValue()
        device_paths = []
        if drive_path is not None:
            drive = self.udisks2.devices[drive_path]
            device_paths = self.udisks2.get_drive_device_paths(drive_path)
            device = ''
            if device_paths:
                device = device_paths[0]
            mount = ''
            size = 0
            available = 0

            # Get free size on USB
            size = drive['total_size']
            available = drive['free_size']
            if self.chkFormatDevice.get_active():
                available = size

            if device != '':
                mount = drive[device]['mount_point']
                if not exists(mount):
                    # Mount if not already mounted
                    try:
                        mount = self.udisks2.mount_device(device)
                    except Exception as e:
                        self.show_message(6)
                        self.log.write("ERROR: %s" % str(e))
                if exists(mount) and not self.chkFormatDevice.get_active():
                    size = drive[device]['total_size']
                    available = drive[device]['free_size']
                # This function can be called from on_chkFormatDevice_toggled
                if widget != self.chkFormatDevice:
                    self.chkFormatDevice.set_sensitive(True)
                    self.chkFormatDevice.set_active(False)
            else:
                # No partition: always format the device
                self.chkFormatDevice.set_active(True)
                self.chkFormatDevice.set_sensitive(False)

            self.chkRepairDevice.set_active(False)
            self.fill_treeview_usbcreator(mount)
            self.lblAvailable.set_label("{}: {} MB".format(
                self.available_text, int(available / 1024)))

            # Save the info
            self.device['path'] = drive_path
            self.device['mount'] = mount
            self.device['size'] = size
            self.device['available'] = available
            self.log.write("Selected device info: {}".format(self.device))

            # Update info
            iso_path = self.txtIso.get_text().strip()
            if iso_path != "" and exists(iso_path):
                self.on_txtIso_changed()
        else:
            self.fill_treeview_usbcreator()
            self.lblAvailable.set_label('')
            self.lblRequired.set_label('')
            self.txtIso.set_text('')
            self.device['path'] = ''
            self.device['mount'] = ''
            self.device['size'] = 0
            self.device['available'] = 0
            self.device["new_iso"] = ''
            self.device["new_iso_required"] = 0

    def on_chkFormatDevice_toggled(self, widget):
        # Recalculate available space and requied space
        self.on_cmbDevice_changed(widget)

    def on_btnHelp_clicked(self, widget):
        # Open the help file as the real user (not root)
        shell_exec("%s/open-as-user \"%s\"" % (self.scriptDir, self.helpFile))

    def fill_treeview_usbcreator(self, mount=''):
        isos_list = []
        # columns: checkbox, image (logo), device, driver
        column_types = ['bool', 'GdkPixbuf.Pixbuf', 'str', 'str']

        if exists(mount):
            isos = glob(join(mount, '*.iso'))
            for iso in isos:
                iso_name = basename(iso)
                iso_name_lower = iso_name.lower()
                iso_size = "{} MB".format(int(self.get_iso_size(iso) / 1024))
                iso_logo = ""
                for key, logo in list(self.logos.items()):
                    if key != "iso":
                        if key in iso_name_lower:
                            if len(logo) > len(iso_logo):
                                iso_logo = logo
                if iso_logo == "":
                    iso_logo = self.logos["iso"]
                self.log.write("ISO on {}: {}, {}, {}".format(
                    mount, iso_name, iso_size, iso_logo))
                isos_list.append([False, iso_logo, iso_name, iso_size])

        # Fill treeview
        self.tvUsbIsosHandler.fillTreeview(contentList=isos_list,
                                           columnTypesList=column_types)

    def exec_command(self, command):
        try:
            # Run the command in a separate thread
            self.set_buttons_state(False)
            name = 'cmd'
            t = ExecuteThreadedCommands([command], self.queue)
            self.threads[name] = t
            t.daemon = True
            t.start()
            self.queue.join()
            GObject.timeout_add(1000, self.check_thread, name)

        except Exception as detail:
            ErrorDialog(self.btnExecute.get_label(), detail)

    def check_thread(self, name):
        if self.threads[name].is_alive():
            self.set_progress()
            if not self.queue.empty():
                ret = self.queue.get()
                self.log.write("Queue returns: {}".format(ret), 'check_thread')
                self.queue.task_done()
                self.show_message(ret)
            return True

        # Thread is done
        self.log.write(">> Thread is done", 'check_thread')
        ret = 0
        if not self.queue.empty():
            ret = self.queue.get()
            self.queue.task_done()
        del self.threads[name]
        self.set_buttons_state(True)
        self.on_btnRefresh_clicked()
        self.fill_treeview_usbcreator(self.device["mount"])
        self.set_statusbar_message("{}: {}".format(self.version_text,
                                                   self.pck_version))
        self.show_message(ret)
        return False

    def set_buttons_state(self, enable):
        if not enable:
            # Disable buttons
            self.btnExecute.set_sensitive(False)
            self.btnDelete.set_sensitive(False)
            self.btnBrowseIso.set_sensitive(False)
            self.btnRefresh.set_sensitive(False)
            self.btnUnmount.set_sensitive(False)
            self.btnClear.set_sensitive(False)
            self.chkFormatDevice.set_sensitive(False)
            self.chkRepairDevice.set_sensitive(False)
            self.cmbDevice.set_sensitive(False)
            self.txtIso.set_sensitive(False)
        else:
            # Enable buttons and reset progress bar
            self.btnExecute.set_sensitive(True)
            self.btnDelete.set_sensitive(True)
            self.btnBrowseIso.set_sensitive(True)
            self.btnRefresh.set_sensitive(True)
            self.btnUnmount.set_sensitive(True)
            self.btnClear.set_sensitive(True)
            self.chkFormatDevice.set_sensitive(True)
            self.chkRepairDevice.set_sensitive(True)
            self.cmbDevice.set_sensitive(True)
            self.txtIso.set_sensitive(True)
            self.pbUsbCreator.set_fraction(0)

    def get_logos(self):
        logos_dict = {}
        logos_path = join(self.mediaDir, 'logos')
        logos = glob(join(logos_path, '*.png'))
        for logo in logos:
            key = splitext(basename(logo))[0]
            logos_dict[key] = logo
        return logos_dict

    def set_progress(self):
        if exists(self.log_file):
            msg = ''
            last_line = getoutput(
                "tail -50 {} | grep -v DEBUG | grep -v ==".format(
                    self.log_file))
            for line in reversed(last_line):
                # Check for session start line: that is the last line to check
                if ">>>>>" in line and "<<<<<" in line:
                    break
                for chk_line in self.log_lines:
                    if chk_line[0] in line.lower():
                        #print((line))
                        word = ''
                        if chk_line[1] == 0:
                            self.pbUsbCreator.pulse()
                            words = line.split(' ')
                            for word in reversed(words):
                                if word.strip() != '':
                                    break
                        else:
                            self.pbUsbCreator.set_fraction(
                                float(chk_line[1] / 100))
                        msg = "{} {}".format(chk_line[2], word)
                        break
                if msg != '':
                    break
            self.set_statusbar_message(msg)

    def set_statusbar_message(self, message):
        if message is not None:
            context = self.statusbar.get_context_id('message')
            self.statusbar.push(context, message)

    def get_iso_size(self, iso):
        # Returns kilobytes
        iso_info = os.stat(iso)
        if iso_info:
            return int(iso_info.st_size / 1024)
        return 0

    # Close the gui
    def on_usbcreator_destroy(self, widget):
        # Unmount devices of drive and power-off drive
        try:
            if exists(self.device['path']) and \
               exists(self.device['mount']):
                self.udisks2.unmount_drive(self.device['path'])
                self.udisks2.poweroff_drive(self.device['path'])
        except Exception as e:
            self.log.write("ERROR: %s" % str(e))
        # Close the app
        Gtk.main_quit()

    def show_message(self, cmdOutput):
        try:
            self.log.write("Command output: {}".format(cmdOutput),
                           'show_message')
            ret = int(cmdOutput)
            if ret > 1 and ret != 255:
                if ret == 1:
                    ErrorDialog(
                        self.btnExecute.get_label(),
                        _("Run this application with root permission."))
                elif ret == 2:
                    ErrorDialog(
                        self.btnExecute.get_label(),
                        _("Wrong arguments were passed to usb-creator."))
                elif ret == 3:
                    ErrorDialog(
                        self.btnExecute.get_label(),
                        _("The device was not found or no device was given."))
                elif ret == 4:
                    ErrorDialog(self.btnExecute.get_label(),
                                _("Given ISO path was not found."))
                elif ret == 5:
                    ErrorDialog(self.btnExecute.get_label(),
                                _("Device is in use by another application."))
                elif ret == 6:
                    ErrorDialog(self.btnExecute.get_label(),
                                _("Unable to mount the device."))
                elif ret == 7:
                    ErrorDialog(self.btnExecute.get_label(),
                                _("Hash mismatch."))
                elif ret == 8:
                    ErrorDialog(self.btnExecute.get_label(),
                                _("The device has no fat32 partition."))
                elif ret == 9:
                    ErrorDialog(self.btnExecute.get_label(),
                                _("The device has no bootloader installed."))
                elif ret == 10:
                    ErrorDialog(
                        self.btnExecute.get_label(),
                        _("There is not enough space available on the device.")
                    )
                elif ret == 11:
                    ErrorDialog(
                        self.btnExecute.get_label(),
                        _("Unable to guess distribution from ISO name.\n"
                          "Make sure you have the distribution name in the ISO name."
                          ))
                else:
                    msg = _(
                        "An unknown error accured.\n"
                        "Please, visit our forum for support: http://forums.solydxk.com"
                    )
                    ErrorDialog(self.window.get_title(), msg)
            else:
                msg = _("The USB was successfully written.")
                MessageDialog(self.window.get_title(), msg)
        except:
            ErrorDialog(self.btnExecute.get_label(), cmdOutput)

    # ===============================================
    # Language specific functions
    # ===============================================

    def get_language_dir(self):
        # First test if full locale directory exists, e.g. html/pt_BR,
        # otherwise perhaps at least the language is there, e.g. html/pt
        # and if that doesn't work, try html/pt_PT
        lang = self.get_current_language()
        path = join(self.htmlDir, lang)
        if not isdir(path):
            base_lang = lang.split('_')[0].lower()
            path = join(self.htmlDir, base_lang)
            if not isdir(path):
                path = join(self.htmlDir,
                            "{}_{}".format(base_lang, base_lang.upper()))
                if not isdir(path):
                    path = join(self.htmlDir, 'en')
        return path

    def get_current_language(self):
        lang = os.environ.get('LANG', 'US').split('.')[0]
        if lang == '':
            lang = 'en'
        return lang
Пример #12
0
class UserManager(object):

    def __init__(self):
        self.scriptDir = abspath(dirname(__file__))

        # Load window and widgets
        self.builder = Gtk.Builder()
        self.builder.add_from_file(join(self.scriptDir, '../../share/usermanager/usermanager.glade'))
        # Main window objects
        go = self.builder.get_object
        self.window = go('usermanagerWindow')
        self.tvUsersMain = go('tvUsersMain')
        self.tvUserGroupsMain = go('tvUserGroupsMain')
        self.chkShowSystemUsers = go('chkShowSystemUsers')
        self.btnUserEdit = go('btnUserEdit')
        self.btnUserRemove = go('btnUserRemove')
        # User window objects
        self.windowUser = go('usermanagerUserWindow')
        self.nbUser = go('nbUser')
        self.txtLoginName = go('txtLoginName')
        self.txtRealName = go('txtRealName')
        self.txtUserID = go('txtUserID')
        self.txtHomeDirectory = go('txtHomeDirectory')
        self.cmbShells = go('cmbShells')
        self.cmbPrimaryGroup = go('cmbPrimaryGroup')
        self.cmbPrimaryGroupEntry = go('cmbPrimaryGroupEntry')
        self.tvUserGroups = go('tvUserGroups')
        self.ebFace = go('ebFace')
        self.imgFace = go('imgFace')
        self.lblUserID = go('lblUserID')
        self.txtPassword = go('txtPassword')
        self.txtLastChanged = go('txtLastChanged')
        self.cmbValidUntilMonth = go('cmbValidUntilMonth')
        self.spbValidUntilDay = go('spbValidUntilDay')
        self.spbValidUntilYear = go('spbValidUntilYear')
        self.radEnabled = go('radEnabled')
        self.radDisabled = go('radDisabled')
        self.radValidUntilAlways = go('radValidUntilAlways')
        self.radValidUntilDate = go('radValidUntilDate')
        self.spbRequirePasswordAfter = go('spbRequirePasswordAfter')
        self.spbWarnBeforePasswordExpires = go('spbWarnBeforePasswordExpires')
        self.spbDisableAccountWhenPasswordExpires = go('spbDisableAccountWhenPasswordExpires')
        self.spbEnforceMinimumPasswordAge = go('spbEnforceMinimumPasswordAge')
        self.chkRequirePasswordAfter = go('chkRequirePasswordAfter')
        self.chkEnforceMinimumPasswordAge = go('chkEnforceMinimumPasswordAge')
        self.tvGroupsMain = go('tvGroupsMain')
        # Group window objects
        self.windowGroup = go('usermanagerGroupWindow')
        self.txtGroupName = go('txtGroupName')
        self.txtGroupID = go('txtGroupID')
        self.tvAccounts = go('tvAccounts')
        self.tvSelectedAccounts = go('tvSelectedAccounts')
        self.tvGroupAccounts = go('tvGroupAccounts')

        # Main window translations
        self.window.set_title(_("User manager"))
        self.chkShowSystemUsers.set_label(_("Show system users"))
        self.btnUserEdit.set_label(_("Edit"))
        self.btnUserRemove.set_label(_("Remove"))
        go('btnUserAdd').set_label(_("Add"))
        go('lblUsersTab').set_text(_("Users"))
        go('lblGroupsTab').set_text(_("Groups"))
        go('lblUsersMain').set_text(go('lblUsersTab').get_text())
        go('lblUserGroupsMain').set_text(_("User groups"))
        go('lblGroupsMain').set_text(go('lblGroupsTab').get_text())
        go('lblGroupAccountsMain').set_text(_("Group accounts"))
        # User window translations
        self.windowUser.set_title(_("User settings"))
        go('lblUserDetails').set_text(_("Details"))
        go('lblStatus').set_text(_("Status"))
        go('lblLoginName').set_text(_("Login name"))
        go('lblRealName').set_text(_("Real name"))
        go('lblUserID').set_text(_("User ID"))
        go('lblPrimaryGroup').set_text(_("Primary group"))
        go('lblHomeDirectory').set_text(_("Home directory"))
        go('lblShell').set_text(_("Shell"))
        self.radEnabled.set_label(_("Enabled"))
        self.radDisabled.set_label(_("Disabled"))
        #go('lblPrivilegesAndGroups').set_text(_("Privileges and groups"))
        go('lblPrivilegesAndGroups').set_text(go('lblGroupsTab').get_text())
        go('lblPrivileges').set_text(_("Privileges"))
        go('lblUserGroups').set_text(go('lblGroupsTab').get_text())
        go('lblPasswordSecurity').set_text(_("Password"))
        go('lblPassword').set_text(go('lblPasswordSecurity').get_text())
        go('lblLastChanged').set_text(_("Last changed"))
        go('lblValidUntil').set_text(_("Valid until"))
        self.radValidUntilAlways.set_label(_("Always"))
        go('lblPasswordAging').set_text(_("Password aging"))
        self.chkRequirePasswordAfter.set_label(_("Require password after"))
        go('lblWarnBeforePasswordExpires').set_text(_("Warn before password expires after"))
        go('lblDisableAccountWhenPasswordExpires').set_text(_("Disable account when password expires after"))
        self.chkEnforceMinimumPasswordAge.set_label(_("Enforce minimum password age"))
        go('lblDays1').set_text(_("days"))
        go('lblDays2').set_text(go('lblDays1').get_text())
        go('lblDays3').set_text(go('lblDays1').get_text())
        go('lblDays4').set_text(go('lblDays1').get_text())
        go('btnSaveUser').set_label(_("Save"))
        go('btnCancelUser').set_label(_("Cancel"))
        # Group window translations
        self.windowGroup.set_title(_("Group settings"))
        go('lblGroupName').set_text(_("Group name"))
        go('lblGroupID').set_text(_("Group ID"))
        go('lblAccounts').set_text(_("Available accounts"))
        go('lblSelectedAccounts').set_text(_("Selected accounts"))
        go('btnOkGroup').set_label(go('btnSaveUser').get_label())
        go('btnCancelGroup').set_label(go('btnCancelUser').get_label())
        go('btnAddAccount').set_label(go('btnUserAdd').get_label())
        go('btnRemoveAccount').set_label(self.btnUserRemove.get_label())

        # Init
        self.ec = ExecCmd()
        self.usr = User()
        self.usersInfo = {}
        self.user = {}
        self.users = []
        self.accounts = []
        self.shells = self.usr.getShells()
        self.groups = None
        self.loggedinUser = self.usr.getLoggedinUser()
        self.loggedinUserPrimaryGroup = self.usr.getUserPrimaryGroupName(self.loggedinUser)
        self.selectedUser = None
        self.selectedGroup = None
        self.selectedGroupAccounts = None
        self.userFace = None
        self.radEnabled.set_active(True)
        self.radValidUntilAlways.set_active(True)
        self.setValidUntil(False)
        self.setRequirePasswordAfter(False)
        self.setEnforceMinimumPasswordAge(False)
        self.txtUserID.set_editable(False)
        self.txtUserID.set_can_focus(False)
        self.txtLastChanged.set_editable(False)
        self.txtLastChanged.set_can_focus(False)
        self.txtGroupID.set_editable(False)
        self.txtGroupID.set_can_focus(False)
        self.passwordChanged = False
        self.homeDirChanged = False
        self.tempFace = "/tmp/face.png"

        self.filterText(self.txtLoginName)
        self.filterText(self.txtGroupName)
        self.filterText(self.cmbPrimaryGroupEntry)

        # Treeviews
        self.tvHandlerUsersMain = TreeViewHandler(self.tvUsersMain)
        self.tvHandlerUserGroupsMain = TreeViewHandler(self.tvUserGroupsMain)
        self.tvHandlerUserGroups = TreeViewHandler(self.tvUserGroups)
        self.tvHandlerAccounts = TreeViewHandler(self.tvAccounts)
        self.tvHandlerSelectedAccounts = TreeViewHandler(self.tvSelectedAccounts)
        self.tvHandlerGroupsMain = TreeViewHandler(self.tvGroupsMain)
        self.tvHandlerGroupAccounts = TreeViewHandler(self.tvGroupAccounts)
        # Comboboxes
        self.cmbHandlerShells = ComboBoxHandler(self.cmbShells)
        self.cmbHandlerPrimaryGroup = ComboBoxHandler(self.cmbPrimaryGroup)
        self.cmbHandlerValidUntilMonth = ComboBoxHandler(self.cmbValidUntilMonth)

        # Get data
        self.refreshData()
        self.cmbHandlerShells.fillComboBox(self.shells)
        self.cmbHandlerValidUntilMonth.fillComboBox(functions.getMonthsList())
        year = datetime.now().year
        adj = Gtk.Adjustment(value=year, lower=year, upper=year + 10, step_incr=1, page_incr=0, page_size=0)
        self.spbValidUntilYear.set_adjustment(adj)

        # Connect the signals and show the window
        self.builder.connect_signals(self)
        self.window.show()


    # ===============================================
    # User functions
    # ===============================================

    def on_tvUsersMain_cursor_changed(self, widget, event=None):
        self.showUserData()

    def on_tvUsersMain_row_activated(self, widget, path, column):
        self.on_btnUserEdit_clicked(None)

    def on_btnUserAdd_clicked(self, widget):
        self.imgFace.set_from_pixbuf(self.usr.getUserFacePixbuf())
        self.tvHandlerUserGroups.fillTreeview(contentList=self.getUserGroupsComplete(), columnTypesList=['bool', 'str'])
        self.cmbHandlerShells.selectValue('/bin/bash')
        self.cmbHandlerPrimaryGroup.fillComboBox(self.groups)
        self.txtLoginName.set_editable(True)
        self.txtLoginName.set_can_focus(True)
        self.txtLoginName.set_text("new_user")
        self.txtUserID.set_text(str(self.usr.getNewUserID()))
        self.updateNewLogin()
        self.txtPassword.set_text("")
        self.radValidUntilAlways.set_active(True)
        self.windowUser.show()

    def on_btnUserEdit_clicked(self, widget):
        if self.selectedUser is not None:
            if not self.userFace is None:
                self.imgFace.set_from_pixbuf(self.userFace)
                self.imgFace.show()
                self.nbUser.get_nth_page(2).show()

            else:
                self.imgFace.hide()
                # Hide passwords tab
                self.nbUser.get_nth_page(2).hide()

            self.txtLoginName.set_editable(False)
            self.txtLoginName.set_can_focus(False)
            self.txtLoginName.set_text(self.user['user'].pw_name)
            if ",,," in self.user['user'].pw_gecos:
                self.txtRealName.set_text(self.user['user'].pw_name)
            else:
                self.txtRealName.set_text(self.user['user'].pw_gecos)
            self.txtUserID.set_text(str(self.user['user'].pw_uid))
            self.txtHomeDirectory.set_text(self.user['user'].pw_dir)
            self.tvHandlerUserGroups.fillTreeview(contentList=self.getUserGroupsComplete(self.user['groups']), columnTypesList=['bool', 'str'])
            self.cmbHandlerShells.selectValue(self.user['user'].pw_shell)
            self.cmbHandlerPrimaryGroup.fillComboBox(self.groups, self.user['prgrp'])
            self.txtPassword.set_text("")
            self.txtLastChanged.set_text(self.usr.intToDate(nr_days=self.user['pwd'].sp_lstchg, format_string='%d %B %Y', start_date=datetime(1970, 1, 1)))

            daysMin = self.user['pwd'].sp_min
            print((">>> daysMin = %d" % daysMin))
            if daysMin > 0:
                self.radValidUntilDate.set_active(True)
                dt = self.usr.intToDate(nr_days=daysMin)
                self.spbValidUntilDay.set_value(dt.day)
                self.cmbValidUntilMonth.set_active(dt.month - 1)
                self.spbValidUntilYear.set_value(dt.year)
            else:
                self.radValidUntilAlways.set_active(True)

            daysMax = self.user['pwd'].sp_max
            daysWarn = self.user['pwd'].sp_warn
            daysInact = self.user['pwd'].sp_inact
            print((">>> daysMax = %d" % daysMax))
            print((">>> daysWarn = %d" % daysWarn))
            print((">>> daysInact = %d" % daysInact))
            if daysMax < 1000 and daysWarn >= 0 and daysInact >= 0:
                self.chkRequirePasswordAfter.set_active(True)
                self.spbRequirePasswordAfter.set_value(daysMax)
                self.spbWarnBeforePasswordExpires.set_value(daysWarn)
                self.spbDisableAccountWhenPasswordExpires.set_value(daysInact)
            else:
                self.chkRequirePasswordAfter.set_active(False)

            daysExpire = self.user['pwd'].sp_expire
            print((">>> daysExpire = %d" % daysExpire))
            if daysExpire >= 0:
                self.chkEnforceMinimumPasswordAge.set_active(True)
                self.spbEnforceMinimumPasswordAge.set_value(daysExpire)
            else:
                self.chkEnforceMinimumPasswordAge.set_active(False)

            self.windowUser.show()

    def on_btnUserRemove_clicked(self, widget):
        # Remove user
        if self.selectedUser is not None:
            title = _("Remove user")
            if self.selectedUser != self.loggedinUser:
                qd = QuestionDialog(title, _("Are you sure you want to remove the following user:\n\n'%(user)s'") % { "user": self.selectedUser }, self.window)
                answer = qd.show()
                if answer:
                    # TODO
                    ret = self.usr.deleteUser(self.selectedUser)
                    if ret == "":
                        self.showInfo(title, _("User successfully removed: %(user)s") % {"user": self.selectedUser}, self.window)
                        self.refreshData()
                    else:
                        retMsg = "\n\n%s" % ret
                        self.showError(title, _("Could not remove user: %(user)s %(retmsg)s") % {"user": self.selectedUser, "retmsg": retMsg}, self.window)
            else:
                self.showError(title, _("You cannot remove the currently logged in user"), self.window)

    def on_chkShowSystemUsers_toggled(self, widget):
        self.refreshData()

    def on_btnBrowse_clicked(self, widget):
        directory = SelectDirectoryDialog(_('Select user directory'), self.txtHomeDirectory.get_text(), self.windowUser).show()
        if directory is not None:
            self.user['user'].pw_dir = directory
            self.txtHomeDirectory.set_text(self.user['user'].pw_dir)

    def on_radEnabled_toggled(self, widget):
        if widget.get_active():
            print(">>> Enable user")

    def on_radDisabled_toggled(self, widget):
        if widget.get_active():
            print(">>> Disable user")

    def on_radValidUntilAlways_toggled(self, widget):
        if widget.get_active():
            self.setValidUntil(False)

    def on_radValidUntilDate_toggled(self, widget):
        if widget.get_active():
            self.setValidUntil(True)

    def setValidUntil(self, boolean=True):
        self.spbValidUntilDay.set_sensitive(boolean)
        self.cmbValidUntilMonth.set_sensitive(boolean)
        self.spbValidUntilYear.set_sensitive(boolean)
        if not boolean:
            self.spbValidUntilDay.set_value(0)
            self.cmbValidUntilMonth.set_active(-1)
            self.spbValidUntilYear.set_value(0)

    def on_chkRequirePasswordAfter_toggled(self, widget):
        if widget.get_active():
            self.setRequirePasswordAfter(True)
        else:
            self.setRequirePasswordAfter(False)

    def setRequirePasswordAfter(self, boolean=True):
        self.spbRequirePasswordAfter.set_sensitive(boolean)
        self.spbWarnBeforePasswordExpires.set_sensitive(boolean)
        self.spbDisableAccountWhenPasswordExpires.set_sensitive(boolean)
        if not boolean:
            self.spbRequirePasswordAfter.set_value(0)
            self.spbWarnBeforePasswordExpires.set_value(0)
            self.spbDisableAccountWhenPasswordExpires.set_value(0)

    def on_chkEnforceMinimumPasswordAge_toggled(self, widget):
        if widget.get_active():
            self.setEnforceMinimumPasswordAge(True)
        else:
            self.setEnforceMinimumPasswordAge(False)

    def setEnforceMinimumPasswordAge(self, boolean=True):
        self.spbEnforceMinimumPasswordAge.set_sensitive(boolean)
        if not boolean:
            self.spbEnforceMinimumPasswordAge.set_value(0)

    def on_txtLoginName_changed(self, widget):
        self.updateNewLogin()

    def on_btnSaveUser_clicked(self, widget):
        errMsgs = []
        changed = False
        name = self.txtLoginName.get_text().strip()
        if name != "":
            userExists = self.usr.doesUserExist(name)

            realName = self.txtRealName.get_text().strip()
            if realName != "":
                if self.user['user'].pw_gecos == realName:
                    realName = ""
                else:
                    print(">>> realName changed")
                    changed = True

            prGroup = self.cmbHandlerPrimaryGroup.getValue()
            if prGroup != "":
                if self.user['prgrp'] == prGroup:
                    prGroup = ""
                else:
                    print(">>> prGroup changed")
                    changed = True
            elif not userExists:
                errMsgs.append(_("You need to provide a primary group for a new user"))

            home = self.txtHomeDirectory.get_text().strip()
            facePath = ""
            if home != "":
                if exists(self.tempFace):
                    facePath = join(home, ".face")
                if self.user['user'].pw_dir == home:
                    home = ""
                else:
                    print(">>> home changed")
                    changed = True

            groups = self.tvHandlerUserGroups.getToggledValues()
            if functions.areListsEqual(groups, self.user['groups']):
                groups = []
            else:
                print(">>> groups changed")
                changed = True

            password = self.txtPassword.get_text().strip()
            if password != "":
                encPwd = self.usr.encryptPassword(password)
                if self.user['pwd'].sp_pwd ==  encPwd:
                    password = ""
                else:
                    print(">>> password changed")
                    changed = True
            elif not userExists:
                errMsgs.append(_("You need to provide a password for a new user"))

        else:
            errMsgs.append(_("You need to provide a name for a new user"))

        shell = self.cmbHandlerShells.getValue()

        # TODO
        #if self.radValidUntilDate.get_active():
            #vuDay = self.spbValidUntilDay.get_value_as_int()
            #vuMonth = self.cmbValidUntilMonth.get_active() + 1
            #vuYear = self.spbValidUntilYear.get_value_as_int()
            #(datetime(vuYear, vuMonth, vuDay, 0, 0, 0) - datetime.now()).days

        #manageUser(self, user, primary_group="", group_list=[], shell="", home_dir="", full_name="", password="", expire_date="", inactive_days=""):
        title = _("Save user settings")
        if errMsgs:
            msg = "\n".join(errMsgs)
            self.showError(title, msg, self.windowUser)
        elif changed or facePath != "":
            err = 0
            if changed:
                err = self.usr.manageUser(user=name, full_name=realName, primary_group=prGroup, home_dir=home, group_list=groups, shell=shell, password=password)
            if err == 0:
                if exists(self.tempFace):
                    move(self.tempFace, facePath)
                self.showInfo(title, _("User saved: %(user)s") % {"user": name}, self.windowUser)
                self.refreshData()
            else:
                # TODO
                pass

            if exists(self.tempFace):
                os.remove(self.tempFace)
            self.windowUser.hide()
        else:
            self.showInfo(title, _("Nothing was changed on user: %(user)s") % {"user": name}, self.windowUser)
            self.windowUser.hide()

        if exists(self.tempFace):
            os.remove(self.tempFace)

    def on_cmbValidUntilMonth_changed(self, widget):
        monthDays = functions.getDaysInMonth(widget.get_active() + 1)
        adj = Gtk.Adjustment(value=1, lower=1, upper=monthDays, step_incr=1, page_incr=0, page_size=0)
        self.spbValidUntilDay.set_adjustment(adj)
        self.spbValidUntilDay.set_value(1)

    def updateNewLogin(self):
        txt = self.txtLoginName.get_text()
        self.txtRealName.set_text(txt)
        self.txtHomeDirectory.set_text("/home/%s" % txt)
        self.cmbHandlerPrimaryGroup.setValue(txt)

    def getUsers(self):
        self.users = []
        self.usersInfo = self.usr.getAllUsersInfoDict(self.chkShowSystemUsers.get_active())
        for ui in self.usersInfo:
            self.users.append([ui['face'], ui['user'].pw_name])

    def showUserData(self):
        # Show user groups in tvUserGroupsMain
        self.selectedUser = self.tvHandlerUsersMain.getSelectedValue(1)
        print((">>> selectedUser = %s" % self.selectedUser))
        for ui in self.usersInfo:
            if ui['user'].pw_name == self.selectedUser:
                self.user = ui
                break
        self.tvHandlerUserGroupsMain.fillTreeview(contentList=self.user['groups'], columnTypesList=['str'])
        self.userFace = self.usr.getUserFacePixbuf(self.user['user'].pw_name, None, 32)

    def getUserGroupsComplete(self, userGroups=None):
        ugc = []
        for group in self.groups:
            if group != self.user['prgrp']:
                isUg = False
                if userGroups is not None:
                    for ug in userGroups:
                        if ug == group:
                            isUg = True
                            break
                ugc.append([isUg, group])
        return ugc

    def on_btnCancelUser_clicked(self, widget):
        # Close add share window without saving
        if exists(self.tempFace):
            os.remove(self.tempFace)
        self.windowUser.hide()

    def on_ebFace_button_release_event(self, widget, data=None):
        imagePath = SelectImageDialog(_('Select user image'), self.user['user'].pw_dir, self.windowUser).show()
        if imagePath is not None:
            ih = ImageHandler(imagePath)
            ih.makeFaceImage(self.tempFace)
            if exists(self.tempFace):
                self.imgFace.set_from_pixbuf(ih.pixbuf)

    def on_usermanagerUserWindow_delete_event(self, widget, data=None):
        if exists(self.tempFace):
            os.remove(self.tempFace)
        self.windowUser.hide()
        return True

    def fillTreeViewUsers(self):
        self.tvHandlerUsersMain.fillTreeview(contentList=self.users, columnTypesList=['GdkPixbuf.Pixbuf', 'str'], fixedImgHeight=48)

    def on_ebFace_enter_notify_event(self, widget, data=None):
        self.windowUser.get_window().set_cursor(Gdk.Cursor(Gdk.CursorType.HAND2))

    def on_ebFace_leave_notify_event(self, widget, data=None):
        self.windowUser.get_window().set_cursor(None)


    # ===============================================
    # Group functions
    # ===============================================

    def on_tvGroupsMain_cursor_changed(self, widget, event=None):
        self.selectedGroup = self.tvHandlerGroupsMain.getSelectedValue()
        self.selectedGroupAccounts = self.usr.getGroupAccounts(self.selectedGroup)
        print((">>> selectedGroup 1 =  %s" % str(self.selectedGroup)))
        print((">>> selectedGroupAccounts 1 =  %s" % str(self.selectedGroupAccounts)))
        self.tvHandlerGroupAccounts.fillTreeview(self.selectedGroupAccounts, ['str'])

    def on_tvGroupsMain_row_activated(self, widget, path, column):
        self.on_btnGroupEdit_clicked(None)

    def on_btnGroupAdd_clicked(self, widget):
        self.selectedGroup = None
        self.selectedGroupAccounts = None
        print((">>> selectedGroup 2 =  %s" % str(self.selectedGroup)))
        print((">>> selectedGroupAccounts 2 =  %s" % str(self.selectedGroupAccounts)))
        self.txtGroupName.set_editable(True)
        self.txtGroupName.set_can_focus(True)
        self.txtGroupName.set_text("")
        self.txtGroupID.set_text(str(self.usr.getNewGroupID()))
        self.fillTreeViewAccounts(self.users)
        self.windowGroup.show()

    def on_btnGroupEdit_clicked(self, widget):
        if self.selectedGroup is not None:
            availableAccounts = []
            groupAccounts = []
            for acc in self.users:
                if acc[1] in self.selectedGroupAccounts:
                    groupAccounts.append(acc)
                else:
                    availableAccounts.append(acc)

            self.fillTreeViewAccounts(availableAccounts, groupAccounts)
            self.txtGroupName.set_text(self.selectedGroup)
            self.txtGroupName.set_editable(False)
            self.txtGroupName.set_can_focus(False)
            self.txtGroupID.set_text(str(self.usr.getGroupID(self.selectedGroup)))
            self.tvAccounts.grab_focus()
            self.windowGroup.show()

    def on_btnGroupRemove_clicked(self, widget):
        # Remove group
        if self.selectedGroup is not None:
            title = _("Remove group")
            if self.selectedGroup != self.loggedinUserPrimaryGroup:
                qd = QuestionDialog(title, _("Are you sure you want to remove the following group:\n\n'%(group)s'") % { "group": self.selectedGroup }, self.windowGroup)
                answer = qd.show()
                if answer:
                    ret = self.usr.deleteGroup(self.selectedGroup)
                    if ret == "":
                        self.showInfo(title, _("Group successfully removed: %(group)s") % {"group": self.selectedGroup}, self.windowGroup)
                        self.refreshData()
                    else:
                        retMsg = "\n\n%s" % ret
                        self.showError(title, _("Could not remove group: %(group)s %(retmsg)s") % {"group": self.selectedGroup, "retmsg": retMsg}, self.windowGroup)
            else:
                self.showError(title, _("You cannot remove the currently logged in user's primary group"), self.windowGroup)

    def on_btnAddAccount_clicked(self, widget):
        rows = self.tvHandlerAccounts.getSelectedRows()
        for row in rows:
            self.tvHandlerAccounts.delRow(row[0])
            self.tvHandlerSelectedAccounts.addRow(row[1])

    def on_btnRemoveAccount_clicked(self, widget):
        # TODO: check if you want to remove an account from its own primary group
        rows = self.tvHandlerSelectedAccounts.getSelectedRows()
        for row in rows:
            acc = row[1][1]
            pg = self.usr.getUserPrimaryGroupName(acc)
            if pg != self.selectedGroup:
                self.tvHandlerSelectedAccounts.delRow(row[0])
                self.tvHandlerAccounts.addRow(row[1])
            else:
                self.showError(_("Remove account"), _("You cannot remove an account from its own primary group"), self.windowGroup)

    def on_btnOkGroup_clicked(self, widget):
        group = self.txtGroupName.get_text()
        if group != "":
            newSelAccs = self.tvHandlerSelectedAccounts.getColumnValues(1)

            if self.selectedGroupAccounts is not None:
                # New accounts in group
                for a in newSelAccs:
                    if a not in self.selectedGroupAccounts:
                        # Add group to account
                        self.usr.addGroupToAccount(a, group)

                # Removed accounts in group
                for a in self.selectedGroupAccounts:
                    if a not in newSelAccs:
                        # Remove group from account
                        self.usr.removeGroupFromAccount(a, group)
            else:
                # Create new group
                self.usr.createGroup(group)
                # Add group to each selected account
                for a in newSelAccs:
                    self.usr.addGroupToAccount(a, group)

            # Close the user window
            self.windowGroup.hide()
            self.refreshData()

    def on_btnCancelGroup_clicked(self, widget):
        self.windowGroup.hide()

    def on_usermanagerGroupWindow_delete_event(self, widget, data=None):
        self.windowGroup.hide()
        return True

    def on_tvAccounts_row_activated(self, widget, path, column):
        self.on_btnAddAccount_clicked(None)

    def on_tvSelectedAccounts_row_activated(self, widget, path, column):
        self.on_btnRemoveAccount_clicked(None)

    def fillTreeViewAccounts(self, availableAccounts, selectedAccounts=None):
        if (availableAccounts is None or not availableAccounts) and selectedAccounts:
            # Dirty hack to prepare the available accounts treeview
            self.tvHandlerAccounts.fillTreeview(contentList=selectedAccounts, columnTypesList=['GdkPixbuf.Pixbuf', 'str'], fixedImgHeight=24)
            self.tvHandlerAccounts.clearTreeView()
        else:
            self.tvHandlerAccounts.fillTreeview(contentList=availableAccounts, columnTypesList=['GdkPixbuf.Pixbuf', 'str'], fixedImgHeight=24)

        if (selectedAccounts is None or not selectedAccounts) and availableAccounts:
            # Dirty hack to prepare the selected accounts treeview
            self.tvHandlerSelectedAccounts.fillTreeview(contentList=availableAccounts, columnTypesList=['GdkPixbuf.Pixbuf', 'str'], fixedImgHeight=24)
            self.tvHandlerSelectedAccounts.clearTreeView()
        else:
            self.tvHandlerSelectedAccounts.fillTreeview(contentList=selectedAccounts, columnTypesList=['GdkPixbuf.Pixbuf', 'str'], fixedImgHeight=24)

    def fillTreeViewGroups(self):
        self.tvHandlerGroupsMain.fillTreeview(contentList=self.groups, columnTypesList=['str'])
        self.on_tvGroupsMain_cursor_changed(None)

    # ===============================================
    # General functions
    # ===============================================

    def refreshData(self):
        self.getUsers()
        self.groups = self.usr.getGroups()
        self.fillTreeViewUsers()
        self.fillTreeViewGroups()
        self.showUserData()

    def showInfo(self, title, message, parent):
        MessageDialogSave(title, message, Gtk.MessageType.INFO, parent).show()

    def showError(self, title, message, parent):
        MessageDialogSave(title, message, Gtk.MessageType.ERROR, parent).show()

    def filterText(self, widget):
        def filter(entry, *args):
            text = entry.get_text().strip().lower()
            entry.set_text(''.join([i for i in text if i in '0123456789abcdefghijklmnopqrstuvwxyz-._']))
        widget.connect('changed', filter)

    # Close the gui
    def on_usermanagerWindow_destroy(self, widget):
        # Close the app
        Gtk.main_quit()
Пример #13
0
    def __init__(self, partition, mount_as, format_as):
        self.partition = partition

        # Load window and widgets
        self.scriptName = basename(__file__)
        self.scriptDir = abspath(dirname(__file__))
        self.mediaDir = join(self.scriptDir, '../../share/live-installer-3')
        self.builder = Gtk.Builder()
        self.builder.add_from_file(
            join(self.mediaDir, 'live-installer-3-dialog.glade'))

        # Main window objects
        self.go = self.builder.get_object
        self.window = self.go("dialog")
        self.window.set_transient_for(installer.window)
        self.window.set_destroy_with_parent(True)
        self.window.set_modal(True)
        self.window.set_title(_("Edit partition"))
        self.loading = True
        self.txt_label = self.go("txt_label")
        self.cmb_mount_point = self.go("combobox_mount_point")
        self.cmb_mount_point_handler = ComboBoxHandler(self.cmb_mount_point)
        self.cmb_use_as = self.go("combobox_use_as")
        self.cmb_use_as_handler = ComboBoxHandler(self.cmb_use_as)

        # Translations
        self.go("label_partition").set_markup("<b>%s</b>" % _("Device"))
        self.go("label_use_as").set_markup(_("Format as"))
        self.go("label_mount_point").set_markup(_("Mount point"))
        self.go("label_label").set_markup(_("Label (optional)"))
        self.go("chk_encryption").set_label(_("Encrypt partition"))
        self.go("label_encryption_pwd").set_label(_("Password"))

        # Show the selected partition path
        self.go("label_partition_value").set_label(self.partition.path)

        # Encryption
        self.go("chk_encryption").set_active(partition.encrypt)
        if partition.encrypt:
            self.go("frm_partition_encryption").set_sensitive(True)
            self.go("entry_encpass1").set_text(partition.enc_passphrase)
            self.go("entry_encpass2").set_text(partition.enc_passphrase)
        else:
            self.go("frm_partition_encryption").set_sensitive(False)
            self.go("entry_encpass1").set_text('')
            self.go("entry_encpass2").set_text('')

        # Label
        label_len = 16
        if "fat" in partition.type or "fat" in partition.mount_as:
            label_len = 11
        self.txt_label.set_max_length(label_len)
        self.txt_label.set_text(partition.label)

        # Build list of pre-provided mountpoints
        mounts = ",/,/home,/boot,/boot/efi,/srv,/tmp,/var,swap".split(',')
        self.cmb_mount_point_handler.fillComboBox(mounts)

        # Build supported filesystems list
        filesystems = sorted(
            ['', 'swap'] +
            [fs[11:] for fs in getoutput('echo /sbin/mkfs.*').split()],
            key=lambda x: 0 if x in ('', 'ext4') else 1 if x == 'swap' else 2)
        self.cmb_use_as_handler.fillComboBox(filesystems)

        self.cmb_mount_point_handler.selectValue(mount_as)
        self.cmb_use_as_handler.selectValue(format_as)

        # Connect builder signals and show window
        self.builder.connect_signals(self)
        self.window.show_all()

        self.loading = False
Пример #14
0
class PartitionDialog(object):
    def __init__(self, partition, mount_as, format_as):
        self.partition = partition

        # Load window and widgets
        self.scriptName = basename(__file__)
        self.scriptDir = abspath(dirname(__file__))
        self.mediaDir = join(self.scriptDir, '../../share/live-installer-3')
        self.builder = Gtk.Builder()
        self.builder.add_from_file(
            join(self.mediaDir, 'live-installer-3-dialog.glade'))

        # Main window objects
        self.go = self.builder.get_object
        self.window = self.go("dialog")
        self.window.set_transient_for(installer.window)
        self.window.set_destroy_with_parent(True)
        self.window.set_modal(True)
        self.window.set_title(_("Edit partition"))
        self.loading = True
        self.txt_label = self.go("txt_label")
        self.cmb_mount_point = self.go("combobox_mount_point")
        self.cmb_mount_point_handler = ComboBoxHandler(self.cmb_mount_point)
        self.cmb_use_as = self.go("combobox_use_as")
        self.cmb_use_as_handler = ComboBoxHandler(self.cmb_use_as)

        # Translations
        self.go("label_partition").set_markup("<b>%s</b>" % _("Device"))
        self.go("label_use_as").set_markup(_("Format as"))
        self.go("label_mount_point").set_markup(_("Mount point"))
        self.go("label_label").set_markup(_("Label (optional)"))
        self.go("chk_encryption").set_label(_("Encrypt partition"))
        self.go("label_encryption_pwd").set_label(_("Password"))

        # Show the selected partition path
        self.go("label_partition_value").set_label(self.partition.path)

        # Encryption
        self.go("chk_encryption").set_active(partition.encrypt)
        if partition.encrypt:
            self.go("frm_partition_encryption").set_sensitive(True)
            self.go("entry_encpass1").set_text(partition.enc_passphrase)
            self.go("entry_encpass2").set_text(partition.enc_passphrase)
        else:
            self.go("frm_partition_encryption").set_sensitive(False)
            self.go("entry_encpass1").set_text('')
            self.go("entry_encpass2").set_text('')

        # Label
        label_len = 16
        if "fat" in partition.type or "fat" in partition.mount_as:
            label_len = 11
        self.txt_label.set_max_length(label_len)
        self.txt_label.set_text(partition.label)

        # Build list of pre-provided mountpoints
        mounts = ",/,/home,/boot,/boot/efi,/srv,/tmp,/var,swap".split(',')
        self.cmb_mount_point_handler.fillComboBox(mounts)

        # Build supported filesystems list
        filesystems = sorted(
            ['', 'swap'] +
            [fs[11:] for fs in getoutput('echo /sbin/mkfs.*').split()],
            key=lambda x: 0 if x in ('', 'ext4') else 1 if x == 'swap' else 2)
        self.cmb_use_as_handler.fillComboBox(filesystems)

        self.cmb_mount_point_handler.selectValue(mount_as)
        self.cmb_use_as_handler.selectValue(format_as)

        # Connect builder signals and show window
        self.builder.connect_signals(self)
        self.window.show_all()

        self.loading = False

    def on_combobox_mount_point_changed(self, widget):
        mount_as = self.cmb_mount_point_handler.getValue()
        if "boot" in mount_as:
            # Cannot encrypt
            self.go("chk_encryption").set_active(False)
            self.go("chk_encryption").set_sensitive(False)
            self.go("frm_partition_encryption").set_sensitive(False)
            self.go("entry_encpass1").set_text('')
            self.go("entry_encpass2").set_text('')
        else:
            # Can encrypt
            self.loading = True
            self.go("chk_encryption").set_sensitive(True)
            self.loading = False

        # Set label for OS
        if self.txt_label.get_text() == '':
            if mount_as == '/':
                self.txt_label.set_text(get_release_name())

        # swap
        if mount_as == 'swap' and self.partition.type != 'swap':
            self.cmb_use_as_handler.selectValue('swap')

        # efi
        if 'efi' in mount_as and 'fat' not in self.partition.type:
            self.cmb_use_as_handler.selectValue('vfat')

    def on_combobox_use_as_changed(self, widget):
        format_as = self.cmb_use_as_handler.getValue()
        mount_as = self.cmb_mount_point_handler.getValue()
        if format_as == 'swap' and mount_as != 'swap':
            self.cmb_mount_point_handler.selectValue('swap')

    def on_button_cancel_clicked(self, widget):
        # Close window without saving
        self.window.hide()

    def on_chk_encryption_toggled(self, widget):
        if self.loading: return
        if widget.get_active():
            # Show warning message
            mount_as = self.cmb_mount_point_handler.getValue()
            if mount_as == '/':
                encrypt = QuestionDialog(
                    _("Encryption"),
                    _("You chose to encrypt the root partition.\n\n"
                      "You will need to mount /boot on a separate non-encrypted partition (500 MB).\n"
                      "Without a non-encrypted /boot partition your system will be unbootable.\n\n"
                      "Encryption will erase all data from {}\n\n"
                      "Are you sure you want to continue?").format(
                          self.partition.path))
            else:
                encrypt = QuestionDialog(
                    _("Encryption"),
                    _("Encryption will erase all data from {}\n\n"
                      "Are you sure you want to continue?").format(
                          self.partition.path))
            if encrypt:
                format_as = self.cmb_use_as_handler.getValue()
                if not format_as:
                    self.cmb_use_as_handler.selectValue('ext4')
                self.go("frm_partition_encryption").set_sensitive(True)
                self.go("entry_encpass1").set_text(
                    self.partition.enc_passphrase)
                self.go("entry_encpass2").set_text(
                    self.partition.enc_passphrase)
                self.go("entry_encpass1").grab_focus()
            else:
                widget.set_active(False)
                self.go("frm_partition_encryption").set_sensitive(False)
                self.go("entry_encpass1").set_text("")
                self.go("entry_encpass2").set_text("")
        else:
            self.go("frm_partition_encryption").set_sensitive(False)
            self.go("entry_encpass1").set_text("")
            self.go("entry_encpass2").set_text("")

    def on_entry_encpass1_changed(self, widget):
        self.assign_enc_password()

    def on_entry_encpass2_changed(self, widget):
        self.assign_enc_password()

    def assign_enc_password(self):
        encryption_pwd1 = self.go("entry_encpass1").get_text()
        encryption_pwd2 = self.go("entry_encpass2").get_text()
        if (encryption_pwd1 == "" and encryption_pwd2 == ""):
            self.go("image_enc_mismatch").hide()
        else:
            self.go("image_enc_mismatch").show()
        if (encryption_pwd1 != encryption_pwd2):
            self.go("image_enc_mismatch").set_from_stock(
                Gtk.STOCK_NO, Gtk.IconSize.BUTTON)
        else:
            self.go("image_enc_mismatch").set_from_stock(
                Gtk.STOCK_OK, Gtk.IconSize.BUTTON)

    def on_button_ok_clicked(self, widget):
        # Collect data
        format_as = self.cmb_use_as_handler.getValue()
        mount_as = self.cmb_mount_point_handler.getValue()
        encrypt = self.go("chk_encryption").get_active()
        enc_passphrase1 = self.go("entry_encpass1").get_text().strip()
        enc_passphrase2 = self.go("entry_encpass2").get_text().strip()
        label = self.txt_label.get_text().strip()

        # Check user input
        if encrypt:
            errorFound = False
            if enc_passphrase1 == "":
                errorFound = True
                errorMessage = _("Please provide an encryption password.")
            elif enc_passphrase1 != enc_passphrase2:
                errorFound = True
                errorMessage = _("Your encryption passwords do not match.")
            elif not format_as:
                errorFound = True
                errorMessage = "{} {}".format(
                    _("You need to choose a format type\n"
                      "for your encrypted partition (default: ext4):"),
                    self.partition.path)
                self.cmb_use_as_handler.selectValue('ext4')
            if not mount_as:
                errorFound = True
                errorMessage = "{} {}".format(
                    _("You need to choose a mount point for partition:"),
                    self.partition.path)

            if errorFound:
                ErrorDialog(_("Encryption"), errorMessage)
                return True
        else:
            # For good measure
            enc_passphrase1 = ''

        # Save the settings and close the window
        assign_mount_point(self.partition, mount_as, format_as, encrypt,
                           enc_passphrase1, label)
        self.window.hide()

    def on_dialog_delete_event(self, widget, data=None):
        self.window.hide()
        return True
    def __init__(self):
        super(USBCreator, self).__init__()

        # Where do we live?
        self.scriptDir = abspath(dirname(__file__)) + "/"

        # Now, get our configuration data
        self.settingsData = config.Config(join(self.scriptDir,
                "files/multi-usb-creator.conf"))

        # Get the path to our dialog glade file and then
        # create the object

        self.dialogBox = USBCreatorDialogBox(join(self.scriptDir, self.settingsData.getValue("localfiles", "icon-path")))

        self.builder = Gtk.Builder()
        self.builder.add_from_file(join(self.scriptDir,
                self.settingsData.getValue("localfiles", "glade-file")))

        # Main window objects
        go = self.builder.get_object
        self.USBCreatorWindow = go("USBCreatorWindow")
        self.btnClose = go("btnClose")
        self.btnExecute = go("btnExecute")
        self.btnHelp = go("btnHelp")
        self.btnListDownLoadISOs = go("btnListDownLoadISOs")
        self.btnRefresh = go("btnRefresh")
        self.btnSelectISOFile = go("btnSelectISOFile")
        self.cmbSelectedUSBDevice = go("cmbSelectedUSBDevice")
        self.cmbDeleteISO = go("cmbDeleteISO")
        self.cmbDownLoad = go("cmbDownLoad")
        self.lblAvailable = go("lblAvailable")
        self.lblRequired = go("lblRequired")
        self.lblUSBCreatorWindowTitle = go("lblUSBCreatorWindowTitle")
        self.rbAddISO = go("rbAddISO")
        self.rbCleanUSB = go("rbCleanUSB")
        self.rbDelete = go("rbDelete")
        self.rbDownLoad = go("rbDownLoad")
        self.txtAvailable = go("txtAvailable")
        self.txtISOFileName = go("txtISOFileName")
        self.txtRequired = go("txtRequired")
        self.pbCopy = go("pbCopy")
        self.lblIServerSOListWindowTitle = go("lblIServerSOListWindowTitle")

        # Cleaning the USB device is a function only available to
        # user running as (or logged in as) root. Of course, a note
        # to this effect is in the help!
        self.rbCleanUSB.set_sensitive(bool(os.getuid() == 0))

        # FileChooserDialog objects
        self.FileChooserDialog = go("FileChooserDialog")
        self.btnFileChooserDialogCancel = go("btnFileChooserDialogCancel")
        self.btnFileChooserDialogOpen = go("btnFileChooserDialogOpen")

        # The Server ISO List window
        self.ServerISOListWindow = go("ServerISOListWindow")
        self.lblIServerSOListWindowTitle = go("lblIServerSOListWindowTitle")
        self.btnServerISOListWindowClose = go("btnServerISOListWindowClose")
        self.tvServerISOData = go("tvServerISOData")

        # Help window objects
        self.HelpWindow = go("HelpWindow")
        self.lblHelpWindowTitle = go("lblHelpWindowTitle")
        self.lblHelpWindowHelpText = go("lblHelpWindowHelpText")

        # Create our handlers
        # First, our ComboBox handlers
        self.cmbHandlerSelectUSB = ComboBoxHandler(self.cmbSelectedUSBDevice, None)
        self.cmbHandlerDownLoad = ComboBoxHandler(self.cmbDownLoad, None)
        self.cmbHandlerDeleteISO = ComboBoxHandler(self.cmbDeleteISO, None)
        self.tvHandlerServerISOData = TreeViewHandler(self.tvServerISOData, None)
        self.cmbHandlerServerISO = ComboBoxHandler(self.cmbDownLoad, None)

        # Now, the data handlers
        self.usbDataHandler = USBDataListHandler()
        self.installedFilesHandler = InstalledFilesListHandler()
        self.serverISOHandler = ServerISOListHandler()

        # Might as well get the server ISO list while we're here
        self.serverISOHandler.getServerISOList(self.settingsData.getValue("url", "solydxk-iso-list-URL"), self.settingsData.getValue("localfiles", "local-iso-list"))
        # And populate the Server ISO TreeView
        self.tvHandlerServerISOData.fillTreeview(contentList=self.serverISOHandler.getTreeViewList(),
            columnTypesList=["str", "str", "str", "str", "str", "str"], firstItemIsColName=True)

        self.cmbHandlerDownLoad.fillComboBox(self.serverISOHandler.getComboBoxList())
        if self.serverISOHandler.rowCount > 0:
            self.cmbDownLoad.set_active(0)

        # Get the USB data because it all starts with the USB devices
        # and, then, populate the USB ComboBox
        #self.usbDataHandler.getUSBData()
        self.RefreshUSBSelector()

        # Translations
        self.USBCreatorWindow.set_title(_("SolydXK Multi-Boot USB Creator"))
        self.rbAddISO.set_label(_("Add ISO"))
        self.rbDownLoad.set_label(_("Down Load"))
        self.rbDelete.set_label(_("Delete"))
        self.rbCleanUSB.set_label(_("Clean USB"))
        self.lblAvailable.set_label(_("Space Available (GiB):"))
        self.lblRequired.set_label(_("Required:"))
        self.lblIServerSOListWindowTitle.set_label(_("ISOs Available for Download"))

        self.HelpWindow.set_title(_("Multi-Boot Help"))
        self.lblHelpWindowTitle.set_label(_("Multi-Boot Help"))
        self.HelpWindowPopulateText()

        # Finally, we can connect our signals, hide the FileChooserDialog
        # (just in case) # and show our main window.
        self.FileChooserDialog.hide()
        self.HelpWindow.hide()
        theHeight = self.USBCreatorWindow.get_size()[1]
        #theWidth = self.USBCreatorWindow.get_size()[0]
        self.USBCreatorWindow.resize(626, theHeight)
        self.pbCopy.set_visible(False)

        self.theQ = Queue(-1)

        self.builder.connect_signals(self)
        self.USBCreatorWindow.show()
        Gtk.main()
class USBCreator(Gtk.Window):

    def __init__(self):
        super(USBCreator, self).__init__()

        # Where do we live?
        self.scriptDir = abspath(dirname(__file__)) + "/"

        # Now, get our configuration data
        self.settingsData = config.Config(join(self.scriptDir,
                "files/multi-usb-creator.conf"))

        # Get the path to our dialog glade file and then
        # create the object

        self.dialogBox = USBCreatorDialogBox(join(self.scriptDir, self.settingsData.getValue("localfiles", "icon-path")))

        self.builder = Gtk.Builder()
        self.builder.add_from_file(join(self.scriptDir,
                self.settingsData.getValue("localfiles", "glade-file")))

        # Main window objects
        go = self.builder.get_object
        self.USBCreatorWindow = go("USBCreatorWindow")
        self.btnClose = go("btnClose")
        self.btnExecute = go("btnExecute")
        self.btnHelp = go("btnHelp")
        self.btnListDownLoadISOs = go("btnListDownLoadISOs")
        self.btnRefresh = go("btnRefresh")
        self.btnSelectISOFile = go("btnSelectISOFile")
        self.cmbSelectedUSBDevice = go("cmbSelectedUSBDevice")
        self.cmbDeleteISO = go("cmbDeleteISO")
        self.cmbDownLoad = go("cmbDownLoad")
        self.lblAvailable = go("lblAvailable")
        self.lblRequired = go("lblRequired")
        self.lblUSBCreatorWindowTitle = go("lblUSBCreatorWindowTitle")
        self.rbAddISO = go("rbAddISO")
        self.rbCleanUSB = go("rbCleanUSB")
        self.rbDelete = go("rbDelete")
        self.rbDownLoad = go("rbDownLoad")
        self.txtAvailable = go("txtAvailable")
        self.txtISOFileName = go("txtISOFileName")
        self.txtRequired = go("txtRequired")
        self.pbCopy = go("pbCopy")
        self.lblIServerSOListWindowTitle = go("lblIServerSOListWindowTitle")

        # Cleaning the USB device is a function only available to
        # user running as (or logged in as) root. Of course, a note
        # to this effect is in the help!
        self.rbCleanUSB.set_sensitive(bool(os.getuid() == 0))

        # FileChooserDialog objects
        self.FileChooserDialog = go("FileChooserDialog")
        self.btnFileChooserDialogCancel = go("btnFileChooserDialogCancel")
        self.btnFileChooserDialogOpen = go("btnFileChooserDialogOpen")

        # The Server ISO List window
        self.ServerISOListWindow = go("ServerISOListWindow")
        self.lblIServerSOListWindowTitle = go("lblIServerSOListWindowTitle")
        self.btnServerISOListWindowClose = go("btnServerISOListWindowClose")
        self.tvServerISOData = go("tvServerISOData")

        # Help window objects
        self.HelpWindow = go("HelpWindow")
        self.lblHelpWindowTitle = go("lblHelpWindowTitle")
        self.lblHelpWindowHelpText = go("lblHelpWindowHelpText")

        # Create our handlers
        # First, our ComboBox handlers
        self.cmbHandlerSelectUSB = ComboBoxHandler(self.cmbSelectedUSBDevice, None)
        self.cmbHandlerDownLoad = ComboBoxHandler(self.cmbDownLoad, None)
        self.cmbHandlerDeleteISO = ComboBoxHandler(self.cmbDeleteISO, None)
        self.tvHandlerServerISOData = TreeViewHandler(self.tvServerISOData, None)
        self.cmbHandlerServerISO = ComboBoxHandler(self.cmbDownLoad, None)

        # Now, the data handlers
        self.usbDataHandler = USBDataListHandler()
        self.installedFilesHandler = InstalledFilesListHandler()
        self.serverISOHandler = ServerISOListHandler()

        # Might as well get the server ISO list while we're here
        self.serverISOHandler.getServerISOList(self.settingsData.getValue("url", "solydxk-iso-list-URL"), self.settingsData.getValue("localfiles", "local-iso-list"))
        # And populate the Server ISO TreeView
        self.tvHandlerServerISOData.fillTreeview(contentList=self.serverISOHandler.getTreeViewList(),
            columnTypesList=["str", "str", "str", "str", "str", "str"], firstItemIsColName=True)

        self.cmbHandlerDownLoad.fillComboBox(self.serverISOHandler.getComboBoxList())
        if self.serverISOHandler.rowCount > 0:
            self.cmbDownLoad.set_active(0)

        # Get the USB data because it all starts with the USB devices
        # and, then, populate the USB ComboBox
        #self.usbDataHandler.getUSBData()
        self.RefreshUSBSelector()

        # Translations
        self.USBCreatorWindow.set_title(_("SolydXK Multi-Boot USB Creator"))
        self.rbAddISO.set_label(_("Add ISO"))
        self.rbDownLoad.set_label(_("Down Load"))
        self.rbDelete.set_label(_("Delete"))
        self.rbCleanUSB.set_label(_("Clean USB"))
        self.lblAvailable.set_label(_("Space Available (GiB):"))
        self.lblRequired.set_label(_("Required:"))
        self.lblIServerSOListWindowTitle.set_label(_("ISOs Available for Download"))

        self.HelpWindow.set_title(_("Multi-Boot Help"))
        self.lblHelpWindowTitle.set_label(_("Multi-Boot Help"))
        self.HelpWindowPopulateText()

        # Finally, we can connect our signals, hide the FileChooserDialog
        # (just in case) # and show our main window.
        self.FileChooserDialog.hide()
        self.HelpWindow.hide()
        theHeight = self.USBCreatorWindow.get_size()[1]
        #theWidth = self.USBCreatorWindow.get_size()[0]
        self.USBCreatorWindow.resize(626, theHeight)
        self.pbCopy.set_visible(False)

        self.theQ = Queue(-1)

        self.builder.connect_signals(self)
        self.USBCreatorWindow.show()
        Gtk.main()

    ##########################################
    #
    # USBCreatorWindow Event Handlers
    #
    ##########################################
    def IsEnoughSpace(self):
        if self.requiredSpace > self.availableSpace:
            self.dialogBox.infoDialog(_("Insufficient Space Available"),
            _("The selected USB device has insuffiecient\nspace for the indicate operation."))
            return(False)
        else:
            return(True)

    def on_btnExecute_clicked(self, widget):
        if self.cmbSelectedUSBDevice.get_active() == -1:
            self.dialogBox.infoDialog(_("No USB Device"),
                (_("Please select a USB device to which to copy the .iso file")))
        else:
            if self.rbAddISO.get_active():
                if self.IsEnoughSpace():
                    self.DoISOAdd()

            elif self.rbDownLoad.get_active():
                if self.IsEnoughSpace():
                    self.DoISODownLoad()

            elif self.rbDelete.get_active():
                self.DoISODelete()

            elif self.rbCleanUSB.get_active():
                self.CleanTheUSBDevice()
            else:
                logging.debug(_("Problem with Radio Buttons"))

    def on_btnHelp_clicked(self, widget):
        self.HelpWindow.show()

    def on_btnListDownLoadISOs_clicked(self, widget):
        self.ServerISOListWindow.show()

    def on_btnRefresh_clicked(self, widget):
        self.usbDataHandler.getUSBData()
        self.RefreshUSBSelector()
        self.rbAddISO.set_active(True)

    def on_btnSelectISOFile_clicked(self, widget):
        self.FileChooserDialog.show()

    def on_cmbDeleteISO_changed(self, widget):
        self.rbDelete.set_active(True)
        #self.on_RadioButton_toggled(self.rbDelete)

    def on_cmbDownLoad_changed(self, widget):
        self.rbDownLoad.set_active(True)
        #self.on_RadioButton_toggled(self.rbDownLoad)

    def on_cmbSelectedUSBDevice_changed(self, widget):
        self.DoNewUSBSelected()
        self.rbAddISO.set_active(True)
        #self.on_RadioButton_toggled(self.rbAddISO)

    def on_RadioButton_toggled(self, widget):
        if widget.get_active():
            if self.rbAddISO.get_active():
                # Get the filename from the text entry control (if there is one).
                # Check to see if the text is the path to a file. If it is,
                # then get the size of the file and show it to the user.
                theFileName = self.txtISOFileName.get_text()
                if os.path.isfile(theFileName):
                    self.requiredSpace = int(os.path.getsize(theFileName))
                    self.txtRequired.set_text(self.Convert2Gigs(self.requiredSpace))

            elif self.rbDownLoad.get_active():
                # Get the index of the ComboBox, use that as a pointer to the data
                if self.cmbDownLoad.get_active() != -1:
                    self.requiredSpace = int(self.serverISOHandler.getFileSize(self.cmbDownLoad.get_active()))
                    self.txtRequired.set_text(self.Convert2Gigs(self.requiredSpace))

            elif self.rbDelete.get_active():
                pass
            elif self.rbCleanUSB.get_active():
                pass
            else:
                logging.debug(_("Unknown RadioButton selected"))

    def on_USBCreatorWindow_destroy(self, widget):
        Gtk.main_quit()

    ##########################################
    #
    # USBCreatorWindow utility functions
    #
    ##########################################

    # Clean the USB device indicated in the cmbSelectedUSBDevice
    def CleanTheUSBDeviceCheck(self):
        if self.theThread.is_alive():
            retVal = True
            self.pbCopy.pulse()
            if not self.theQ.empty():
                lst = self.theQ.get(False)
                if lst:
                    if isinstance(lst[0], str):
                        self.dialogBox.errorDialog(_("Error Encountered"),
                            _("MultiBootISOCreator:CleanTheUSBDeviceCheck - Error: {}").format(lst[0]))
                self.theQ.task_done()
        else:
            retVal = False
            try:
                if not self.theQ.empty():
                    lst = self.theQ.get(False)
                    if lst:
                        if isinstance(lst[0], str):
                            self.dialogBox.errorDialog(_("Error Encountered"),
                                _("MultiBootISOCreator:CleanTheUSBDeviceCheck - Error: {}").format(lst[0]))
                        else:
                            if bool(lst[0]):
                                self.dialogBox.infoDialog(_("Cleaning Is Complete"),
                                    _("The USB Device has been re-initialized.\nIt is safe to remove it and re-insert it for\nISO file copy/download operations."))
                            else:
                                self.dialogBox.errorDialog(_("Error Encountered"),
                                    _("MultiBootISOCreator:CleanTheUSBDeviceCheck\n - Error encountered during cleaning operation."))
            except Exception as detail:
                logging.debug(_("Error Encountered"),
                        _("MultiBootISOCreator:CleanTheUSBDeviceCheck - Error: {}").format(detail))
                self.dialogBox.errorDialog("MultiBootISOCreator:CleanTheUSBDeviceCheck - Error: {}".format(detail))
            finally:
                # Save our current index
                localActiveIndex = self.cmbSelectedUSBDevice.get_active()

                # Relaod all the USB related data
                self.RefreshUSBSelector()

                # Point our ComboBox back where it was
                if localActiveIndex <= self.usbDataHandler.rowCount:
                    self.cmbSelectedUSBDevice.set_active(localActiveIndex)
                elif self.usbDataHandler.rowCount > 0:
                    self.cmbSelectedUSBDevice.set_active(0)
                else:
                    self.cmbSelectedUSBDevice.set_active(-1)

                self.DoNewUSBSelected()

                self.rbAddISO.set_active(True)
                self.on_RadioButton_toggled(self.rbAddISO)

                self.SetButtonsSensitive(True)

        return(retVal)

    def CleanTheUSBDevice(self):
        if self.usbDataHandler.rowCount <= 0:
            self.dialogBox.infoDialog(_("Ummm ... No USB device"),
                _("Did you forget to mount a USB device with which we can play?"))
        else:
            response = self.dialogBox.warningDialog(_("Please confirm"),
                _("Please confirm you wish to re-initialize\nthe device\n\n{}").format(self.usbDataHandler.getDevice(self.cmbSelectedUSBDevice.get_active())))
            if response != Gtk.ResponseType.OK:
                self.dialogBox.infoDialog(_("Operation Cancelled"),
                    _("Operation to re-initialize the\n" +
                    "USB device has been cancelled."))
            else:
                theCommandList = []
                theCommandList.clear()

                # The device in the data comes back with the partition number on it.
                theDevice = self.usbDataHandler.getDevice(self.cmbSelectedUSBDevice.get_active())[:-1]

                # This is where we are going to mount the device to install grub. We need to
                # ensure that whatever mount point we choose is not already in use. One way
                # to do that is to create it and then blow it away when we are done.
                while True:
                    rootMountPoint = "/media/{}".format((uuid.uuid1()).hex)
                    if not os.path.exists(rootMountPoint):
                        os.makedirs(rootMountPoint)
                        break

                # The device is mounted at /media/<user>/<usb label>. We want to unmount that puppy so
                # we can do our thang to it.
                theCommandList.append("umount {}".format(self.usbDataHandler.getMountPoint(self.cmbSelectedUSBDevice.get_active())))
                theCommandList.append("dd if=/dev/zero of={} bs=4M count=25".format(theDevice))
                theCommandList.append("parted -a optimal -s {} mklabel msdos".format(theDevice))
                theCommandList.append("parted -a optimal -s {} mkpart primary fat32 0% 100% set 1 boot on".format(theDevice))
                theCommandList.append("mkdosfs -F32 -n 'SOLYDXK' -I {}1".format(theDevice))

                # OK, now mount it where we can find it.
                theCommandList.append("mount {0}1 {1}".format(theDevice, rootMountPoint))
                theCommandList.append("tar zxf {0}/files/solydxk-usb.tar.gz  -C {1}".format(self.scriptDir, rootMountPoint))
                theCommandList.append("grub-install --root-directory={0} --no-floppy --recheck --force {1}".format(rootMountPoint, theDevice))
                theCommandList.append("umount {}1".format(theDevice))
                theCommandList.append("rmdir {0}".format(rootMountPoint))

                self.theThread = ExecuteCommandList(theCommandList, self.theQ)
                self.theThread.daemon = True
                self.theThread.start()
                self.theQ.join()
                self.pbCopy.set_text(_("Cleaning Device"))
                self.pbCopy.set_show_text(True)
                self.SetButtonsSensitive(False)
                GLib.timeout_add(100, self.CleanTheUSBDeviceCheck)

    def Convert2Gigs(self, theSize):
        return("{:.2f}".format((float(theSize) / float(2 ** 30))))

    def CopyCheck(self, destFileName):
        if self.theThread.is_alive():
            retVal = True
            self.pbCopy.pulse()
            if not self.theQ.empty():
                lst = self.theQ.get(False)
                if lst:
                    if isinstance(lst[0], str):
                        self.dialogBox.errorDialog(_("Error Encountered"),
                            _("MultiBootISOCreator:CopyCheck - Error: {}").format(lst[0]))
                        removeFile = True
                self.theQ.task_done()
        else:
            removeFile = False
            retVal = False
            try:
                if not self.theQ.empty():
                    lst = self.theQ.get(False)
                    if lst:
                        if isinstance(lst[0], str):
                            self.dialogBox.errorDialog(_("Error Encountered"),
                                _("MultiBootISOCreator:CopyCheck - Error: {}").format(lst[0]))
                            removeFile = True
                        else:
                            if bool(lst[0]):
                                self.txtISOFileName.set_text("")
                                self.dialogBox.infoDialog(_("Copy Is Complete"),
                                    _("The USB Device has been updated.\n" +
                                    "It is safe to unmount and remove it."))
                            else:
                                self.dialogBox.errorDialog(_("Error Encountered"),
                                    _("MultiBootISOCreator:CopyCheck - Error encountered during copy."))
                                removeFile = True
                    self.theQ.task_done()

            except Exception as detail:
                logging.debug(_("MultiBootISOCreator:CopyCheck - Error: {}").format(detail))
                self.dialogBox.errorDialog(_("Error Encountered"),
                    _("MultiBootISOCreator:CopyCheck - Error: {}").format(detail))
                removeFile = True

            finally:
                if removeFile:
                    if os.path.isfile(destFileName):
                        os.remove(destFileName)
                del self.theThread

                # Save our current index
                localActiveIndex = self.cmbSelectedUSBDevice.get_active()

                # Relaod all the USB related data
                self.RefreshUSBSelector()

                # Point our ComboBox back where it was
                if localActiveIndex <= self.usbDataHandler.rowCount:
                    self.cmbSelectedUSBDevice.set_active(localActiveIndex)
                elif self.usbDataHandler.rowCount > 0:
                    self.cmbSelectedUSBDevice.set_active(0)
                else:
                    self.cmbSelectedUSBDevice.set_active(-1)

                self.DoNewUSBSelected()
                self.UpdateUSBGrubConfig()

                self.rbAddISO.set_active(True)
                self.on_RadioButton_toggled(self.rbAddISO)

                self.SetButtonsSensitive(True)

        return(retVal)

    def CopyFile(self, theFileName):
        commandList = []
        commandList.clear()
        commandList.append("cp {0} {1}".format(self.txtISOFileName.get_text(), theFileName))
        self.theThread = ExecuteCommandList(commandList, self.theQ)
        self.theThread.daemon = True
        self.theThread.start()
        self.theQ.join()
        self.pbCopy.set_text(_("Copying File"))
        self.pbCopy.set_show_text(True)
        self.SetButtonsSensitive(False)
        GLib.timeout_add(100, self.CopyCheck, theFileName)

    def DownLoadCheck(self, destFileName):
        if self.theThread.is_alive():
            retVal = True
            self.pbCopy.pulse()
            if not self.theQ.empty():
                lst = self.theQ.get(False)
                if lst:
                    self.pbCopy.set_text(lst[0])
                    self.pbCopy.set_show_text(True)
                self.theQ.task_done()
        else:
            retVal = False
            removeFile = False
            try:
                if not self.theQ.empty():
                    lst = self.theQ.get(False)
                    if lst:
                        if isinstance(lst[0], str):
                            # We have an error message
                            self.dialogBox.errorDialog(_("Error Encountered"),
                                _("Error encountered during download: {}").format(lst[0]))
                            removeFile = True
                        else:
                            # Take care of the results of the MD5Sum calculation
                            if lst[0]:
                                # All is right in the world
                                self.dialogBox.infoDialog(_("Download Is Complete"),
                                    _("The USB Device has been updated.\nIt is safe to unmount and remove it."))
                            else:
                                # Bad MD5Sum
                                self.dialogBox.errorDialog(_("MD5Sum is not a match"),
                                _("Download complete but appears to be\n" +
                                "corrupted. The computed MD5Sum does\n" +
                                "not match the value from the server.\n\n" +
                                "The file has been removed from the USG device."))
                                removeFile = True

            except Exception as detail:
                logging.debug(_("MultiBootISOCreator:DownLoadCheck - exception: {}").format(detail))
                self.dialogBox(_("Error in DownLoad."), _("MultiBootISOCreator:DownLoadCheck - exception: {}").format(detail))
                removeFile = True

            finally:
                self.theQ.task_done()
                del self.theThread

                if removeFile:
                    if os.path.isfile(destFileName):
                        os.remove(destFileName)

                # No matter whether we were successful or not, we need to clean
                # up our mess and set the controls back to their rightful state.
                # Save our current index
                localActiveIndex = self.cmbSelectedUSBDevice.get_active()

                # Relaod all the USB related data
                self.RefreshUSBSelector()

                # Point our ComboBox back where it was
                if localActiveIndex <= self.usbDataHandler.rowCount:
                    self.cmbSelectedUSBDevice.set_active(localActiveIndex)
                elif self.usbDataHandler.rowCount > 0:
                    self.cmbSelectedUSBDevice.set_active(0)
                else:
                    self.cmbSelectedUSBDevice.set_active(-1)

                self.DoNewUSBSelected()
                self.UpdateUSBGrubConfig()

                self.rbDownLoad.set_active(True)
                self.on_RadioButton_toggled(self.rbDownLoad)

                self.SetButtonsSensitive(True)

        return(retVal)

    def DownLoadFile(self):
        sourceURL = self.serverISOHandler.getDownLoadURL(self.cmbDownLoad.get_active())
        theMD5 = self.serverISOHandler.getMD5Sum(self.cmbDownLoad.get_active())
        destFileName = "{0}/{1}.iso".format(self.usbDataHandler.getMountPoint(self.cmbSelectedUSBDevice.get_active()),
            self.serverISOHandler.getSpinID(self.cmbDownLoad.get_active()))
        self.theThread = DownLoadISO(sourceURL, theMD5, destFileName, self.theQ)
        self.theThread.daemon = True
        self.theThread.start()
        self.theQ.join()

        self.pbCopy.set_show_text(True)
        self.SetButtonsSensitive(False)
        GLib.timeout_add(100, self.DownLoadCheck, destFileName)

    def DoISOAdd(self):
        if self.txtISOFileName.get_text() != "":
            theMessage = _("Please confirm you wish to copy the file\n\n\"{0}\"\n\nto the selected USB device.").format(self.txtISOFileName.get_text())
            response = self.dialogBox.warningDialog("Please Confirm ISO Copy", theMessage)

            if response == Gtk.ResponseType.OK:
                thePattern = re.compile(self.settingsData.getValue("regex-patterns", "solydxk-iso-file-pattern"))
                theBaseName = basename(self.txtISOFileName.get_text())
                if not thePattern.match(theBaseName):
                    self.dialogBox.infoDialog(_("Not a Known SolydXK ISO"),
                        _("The filename supplied does not match that\n" +
                        "of a known SolydXK ISO file.\n\n" +
                        "Please check your information and try again."))
                else:
                    theBaseName = theBaseName[:8] + ".iso"
                    theFileName = "{0}/{1}".format(self.usbDataHandler.getMountPoint(self.cmbSelectedUSBDevice.get_active()), theBaseName)
                    if os.path.isfile(theFileName):
                        response = self.dialogBox.questionDialog(_("Over-Write File?"),
                            _("The selected file already exists on the USB device.\n\nOver-write this file?"))
                    else:
                        response = Gtk.ResponseType.YES

                    if response == Gtk.ResponseType.YES:
                        self.CopyFile(theFileName)
        else:
            self.dialogBox.infoDialog(_("No file selected"),
            _("Please select a file to be copied to the selected USB Device"))

    def DoISODownLoad(self):
        if self.cmbDownLoad.get_active() == -1:
            self.dialogBox.infoDialog(_("No file selected"),
                _("Please select a file to be downloaded to the USB device"))
        else:
            self.DownLoadFile()

    def DoISODelete(self):
        localActiveIndex = self.cmbDeleteISO.get_active()
        if localActiveIndex == -1:
            self.dialogBox.infoDialog(_("No file selected"),
                _("Please select a file to be deleted from the USB device."))
        else:
            theFileName = "{0}/{1}".format(self.usbDataHandler.getMountPoint(self.cmbSelectedUSBDevice.get_active()),
                self.installedFilesHandler.getFileName(localActiveIndex))
            response = self.dialogBox.questionDialog(_("Please confirm file deletion"),
                _("Please confirm you wish to delete the file\n\n{}\n\nfrom the selected USB device.").format(theFileName))
            if response == Gtk.ResponseType.YES:
                if os.path.isfile(theFileName):
                    os.remove(theFileName)

                    # Rebuild all our USB data
                    localActiveIndex = self.cmbSelectedUSBDevice.get_active()
                    self.RefreshUSBSelector()
                    self.cmbSelectedUSBDevice.set_active(localActiveIndex)
                    self.UpdateUSBGrubConfig()
                    self.dialogBox.infoDialog(_("Operation complete"), _("The selected file has been deleted."))
                else:
                    self.dialogBox.errorDialog(_("File not found."),
                        _("The indicated file was not found on the USB device."))

    def DoNewUSBSelected(self):
        if(len(self.usbDataHandler.getList())) > 0:
            self.installedFilesHandler.buildInstalledFilesList(self.usbDataHandler.getMountPoint(self.cmbSelectedUSBDevice.get_active()))
            self.cmbHandlerDeleteISO.fillComboBox(self.installedFilesHandler.getFilesListComboBoxData())
            if self.installedFilesHandler.rowCount > 0:
                self.cmbDeleteISO.set_active(0)

            self.availableSpace = int(self.usbDataHandler.getAvailableSpace(self.cmbSelectedUSBDevice.get_active()))
            self.txtAvailable.set_text(self.Convert2Gigs(self.availableSpace))
            self.requiredSpace = 0
            self.txtRequired.set_text("")
        else:
            self.txtAvailable.set_text("")
            self.availableSpace = int(0)

    # Refresh the cmbSelectedUSBDevice and associated data
    def RefreshUSBSelector(self):
        self.usbDataHandler.getUSBData()
        if len(self.usbDataHandler.getList()) > 0:
            self.cmbHandlerSelectUSB.fillComboBox(self.usbDataHandler.getUSBComboBoxData())
            self.cmbSelectedUSBDevice.set_active(0)
            self.DoNewUSBSelected()
        else:
            self.cmbHandlerSelectUSB.clearComboBox()
            self.DoNewUSBSelected()

    def SetButtonsSensitive(self, newState):
        self.pbCopy.set_visible(not newState)
        self.btnClose.set_sensitive(newState)
        self.btnExecute.set_sensitive(newState)
        self.btnHelp.set_sensitive(newState)
        self.btnListDownLoadISOs.set_sensitive(newState)
        self.btnRefresh.set_sensitive(newState)
        self.btnSelectISOFile.set_sensitive(newState)

    def UpdateUSBGrubConfig(self):
        if self.installedFilesHandler.rowCount <= 0:
            self.dialogBox.infoDialog(_("No USB Device found."), _("It appears you forgot to mount a USB device!"))
        else:
            self.SetButtonsSensitive(False)

            theGrubFile = "{0}/boot/grub/grub.cfg".format(self.usbDataHandler.getMountPoint(self.cmbSelectedUSBDevice.get_active()))
            if os.path.isfile(theGrubFile):
                os.remove(theGrubFile)

            with open(theGrubFile, "w") as outFile:
                outFile.write("# Set the paths to the iso files\n")
                for i in range(self.installedFilesHandler.rowCount):
                    theFileName = self.installedFilesHandler.getFileName(i)
                    outFile.write("set {0}=\"/{1}\"\n".format(theFileName[:-4], theFileName))

                outFile.write("\n# Seconds to wait until starting the default menu entry\n")
                outFile.write("set timeout=10\n\n")
                outFile.write("# Default menu entry (0 = first)\nset default=0\n\n")
                outFile.write("loadfont /boot/grub/fonts/unicode.pf2\n")
                outFile.write("set gfxmode=auto\n")
                outFile.write("#set gfxmode=1024x768\n")
                outFile.write("insmod efi_gop\n")
                outFile.write("insmod efi_uga\n")
                outFile.write("insmod gfxterm\n")
                outFile.write("set gfxpayload=keep\n")
                outFile.write("terminal_output gfxterm\n\n")

                outFile.write("insmod png\n")
                outFile.write("background_image -m stretch /boot/grub/grubbg.png\n")
                outFile.write("set menu_color_normal=white/black\n")
                outFile.write("set menu_color_highlight=dark-gray/white\n\n")
                outFile.write("# Create the menu entries here:\n")

                # This block of code is for the way SolydXK names the various spins, as of 23AUG2014.
                # At some time in the future, Debian will promote Jessie to stable and SolydXK
                # will be changing the names of the spins. At that time, this block of code should
                # be removed from the application and the next (commented) block should be uncommented
                # and tested.
                for i in range(self.installedFilesHandler.rowCount):
                    theFileName = self.installedFilesHandler.getFileName(i)[:-4]

                    if theFileName[-2:] == "be":
                        theEdition = _("Business Edition 64-bit")
                    elif theFileName[-2:] == "bo":
                        theEdition = _("Back Office 64-bit")
                    else:
                        theEdition = _("Home Edition ") + theFileName[-2:] + "-bit"

                    if theFileName[-3:-2] == "k":
                        theDeskTop = "KDE"
                    else:
                        theDeskTop = "Xfce"

                    outFile.write("menuentry \"Solyd{0} {1} (with {2} desktop)\" {3}\n".format(theFileName[-3:-2], theEdition, theDeskTop, "{"))
                    outFile.write("bootoptions=\"findiso=${0} boot=live config username=solydxk hostname=solydxk quite splash\"\n".format(theFileName))
                    outFile.write("search --set -f ${0}\n".format(theFileName))
                    outFile.write("loopback loop ${0}\n".format(theFileName))
                    outFile.write("linux (loop)/live/vmlinuz $bootoptions\n")
                    outFile.write("initrd (loop)/live/initrd.img\n}\n")

                # This is the block of code that should be uncommented when Jessie is promoted to stable.
                # This block assumes that the first two columns of iso-data.csv file will be formatted as:
                # solydk32	SolydK 32-bit
                # solydk64	SolydK 64-bit
                # solydx32	SolydX 32-bit
                # solydx64	SolydX 64-bit
                # solydkbo	SolydK BO 64-bit
                # solydkee32	SolydK EE 32-bit
                # solydkee64	SolydK EE 64-bit
                # solydxee32	SolydX EE 32-bit
                # solydxee64	SolydX EE 64-bit

                #for i in range(self.installedFilesHandler.rowCount):
                    #theFileName = self.installedFilesHandler.getFileName(i)[:-4]

                    #if theFileName[-2:] == "be":
                        #theEdition = _(" Back Office Edition")
                        #theArch = "64"
                    #else:
                        #theArch = theFileName[-2:]
                        #if theFileName[-4:-2] == "ee":
                            #theEdition = _(" Enthusiast's Edition")
                        #else:
                            #theEdition = ""

                    #if theFileName[-3:-2] == "k":
                        #theDeskTop = "KDE"
                    #else:
                        #theDeskTop = "Xfce"

                    #outFile.write("menuentry \"Solyd{} {}-bit (with {} desktop\" {}".format(theEdition, theArch, theDeskTop, "{"))
                    #outFile.write("bootoptions=\"findiso=${0} boot=live config username=solydxk hostname=solydxk quite splash\"\n".format(theFileName))
                    #outFile.write("search --set -f ${0}\n".format(theFileName))
                    #outFile.write("loopback loop ${0}\n".format(theFileName))
                    #outFile.write("linux (loop)/live/vmlinuz $bootoptions\n")
                    #outFile.write("initrd (loop)/live/initrd.img\n}\n")

            self.dialogBox.infoDialog(_("GRUB re-write complete"),
                _("Please remove the USB device.\n\n" +
                "Please re-insert the USB device\n" +
                "If you wish to install ISO files.\n"))
            self.SetButtonsSensitive(True)

    ##########################################
    #
    # FileChooserDialog Event Handlers
    #
    ##########################################
    def on_FileChooserDialog_cancel(self, widget):
        self.txtISOFileName.set_text("")
        self.FileChooserDialog.hide()
        self.rbAddISO.set_active(True)
        self.on_RadioButton_toggled(self.rbAddISO)

    def on_FileChooserDialog_open(self, widget):
        self.txtISOFileName.set_text(self.FileChooserDialog.get_filename())
        self.FileChooserDialog.hide()
        self.rbAddISO.set_active(True)
        self.on_RadioButton_toggled(self.rbAddISO)

    def on_btnHelpWindowOK_clicked(self, widget):
        self.HelpWindow.hide()

    def on_HelpWindow_destroy(self, widget):
        self.HelpWindow.hide()

    def HelpWindowPopulateText(self):
        self.lblHelpWindowHelpText.set_label(
_("""-  Select USB - Using the ComboBox, select the USB device to be used as the Multi-Boot device.

-  Refresh - Clicking this button will cause the list of  USB devices to be refreshed. This can be useful if one starts the application before inserting the intended  target USB device.

-  Add ISO - This option allows for the copying of an already downloaded SolydXK .iso file to the target USB device.

-  File - This button opens a FileChooserDialog to be used to select the source .iso file. The path to the selected .iso file will be written to the TextEntry control.

-  Down Load - This option allows for downloading a SolydXK .iso file from the distro servers. The downloaded file will be written directly to the selected USB device.

-  Information - Opens a window showing a list of all the .iso files available for download, with associated metadata (size, m35sum, etc).

-  Delete - Use this option to remove an .iso file from the target USB device. Can be useful if there are old files there and you need more space for a new file ... or to over-write an old file with an updated version.

-  Clean USB - It sometimes happens that a USB device will need to be completely and thoroughly erased before the created USB will successfully boot. This option (available only run application is run as root) allows the user to completely re-initialize the USB device. All data will be deleted, a new partition table, a new data partition created, all required files written, and grub installed.

-  USB Space - This line indicates the amount of spaces available on the target USB device and the amount of space required to write the selected .iso file to the target USB device.

-  Help - This message

-  Execute - Perform the user selected operation.

-  Close - Exit the program."""))

    ##########################################
    #
    # ServerISOListWindow Event Handlers
    #
    ##########################################
    def on_btnServerISOListWindowClose_clicked(self, widget):
        self.ServerISOListWindow.hide()