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))
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()
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()
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()
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()
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))
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): 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()
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
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()
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 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()