From 19ae07d0d443ff8b777f46bcbe97119483356bfd Mon Sep 17 00:00:00 2001 From: tpearson Date: Sat, 13 Mar 2010 05:43:39 +0000 Subject: Added KDE3 version of KDE Guidance utilities git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/kde-guidance@1102646 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- mountconfig/mountconfig.py | 3303 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3303 insertions(+) create mode 100755 mountconfig/mountconfig.py (limited to 'mountconfig/mountconfig.py') diff --git a/mountconfig/mountconfig.py b/mountconfig/mountconfig.py new file mode 100755 index 0000000..1f31f13 --- /dev/null +++ b/mountconfig/mountconfig.py @@ -0,0 +1,3303 @@ +#!/usr/bin/python +# -*- coding: UTF-8 -*- +########################################################################### +# mountconfig.py - description # +# ------------------------------ # +# begin : Fri Nov 30 2003 # +# copyright : (C) 2003 by Simon Edwards # +# email : simon@simonzone.com # +# # +########################################################################### +# # +# This program is free software; you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation; either version 2 of the License, or # +# (at your option) any later version. # +# # +########################################################################### + +from qt import * +from kdeui import * +from kdecore import * +from kfile import * +from kio import * +import sys +import os +import os.path +from types import StringType,UnicodeType +import pwd +import grp +import math +import locale +import codecs +import subprocess +import MicroHAL +from SMBShareSelectDialog import * +from SimpleCommandRunner import * +from fuser import * +import sizeview + +programname = "Disk & Filesystem Configuration" +version = "0.8.0" + +# Are we running as a separate standalone application or in KControl? +standalone = __name__=='__main__' + +# Running as the root user or not? +isroot = os.getuid()==0 +allowuuid = True +allowlabel = True + + +""" +Universal Options +----------------- + +async/sync +atime/noatime +auto/noauto +dev/nodev +exec/noexec +ro/rw +suid/nosuid +dirsync +nouser/user/users + +defaults =>rw, suid, dev, exec, auto, nouser, and async. + +Automatically set +================= +_netdev +The filesystem resides on a device that requires network access (used to +prevent the system from attempting to mount these filesystems until the +network has been enabled on the system). + +remount +Attempt to remount an already-mounted file system. This is commonly used +to change the mount flags for a file system, especially to make a readonly +file system writeable. It does not change device or mount point. + +Supported filesystems +--------------------- +nfs +ext2 +ext3 +reiserfs +vfat +ntfs +udf +iso9660 +supermount +reiser4 +xfs +jfs +hfs +hfsplus + +cifs (replacement for smbfs) +auto + +swap + +proc +sysfs +usbdevfs +procbususb + +TODO +---- +* SMB finished the connection username nad password fields. +* SMB entry: finished writing the config. +* SMBSelector: setting the username and password. + +""" + +############################################################################ +class UserComboBox(KComboBox): + def __init__(self,parent,name=None): + KComboBox.__init__(self,parent,name) + tmplist = [] + users = pwd.getpwall() + for user in users: + uid = int(user[2]) + username = user[4] + tmplist.append( (int(uid),"%s (%s)" % (username,uid)) ) + tmplist.sort(lambda a,b: cmp(a[1],b[1])) + self.userlist = [] + for user in tmplist: + self.insertItem(user[1]) + self.userlist.append(user[0]) + + ######################################################################## + def setUID(self,uid): + if uid in self.userlist: + self.setCurrentItem(self.userlist.index(int(uid))) + return True + else: + return False + + ######################################################################## + def UID(self): + return self.userlist[self.currentItem()] + +############################################################################ +class GroupComboBox(KComboBox): + def __init__(self,parent,name=None): + KComboBox.__init__(self,parent,name) + self.grouplist = [] + groups = grp.getgrall() + tmplist = [] + for group in groups: + gid = group[2] + groupname = group[0] + tmplist.append( (int(gid),"%s (%s)" % (groupname,gid)) ) + tmplist.sort(lambda a,b: cmp(a[1],b[1])) + self.grouplist = [] + for group in tmplist: + self.insertItem(group[1]) + self.grouplist.append(group[0]) + + ######################################################################## + def setGID(self,gid): + if gid in self.grouplist: + self.setCurrentItem(self.grouplist.index(int(gid))) + return True + else: + return False + + ######################################################################## + def GID(self): + return self.grouplist[self.currentItem()] + + +############################################################################ +class MountEntryExt(object): + use_as_device = "devicenode" # Can be one of "devicenode", "uuid" or "label" + showdevice = True + showlabel = False + showuuid = False + + ######################################################################## + # Base can be either a fstab format line of text, of another MountEntry + # object. + def __init__(self,base=None): + if base==None: + self.device = unicode(i18n("")) + self.mountpoint = unicode(i18n("")) + self.mounttype = 'ext2' + self.uuid = "" + self.label = "" + self.extraoptions = "noauto" + self.fs_freq = 0 + self.fs_passno = 0 + self.enabled = False + self.managed = False + self.device_string = "" + + elif isinstance(base,StringType) or isinstance(base,UnicodeType): + parts = base.split() + + device_ref = MountEntry.decodeMountEntryString(parts[0]) + self.uuid = "" + self.label = "" + if device_ref.startswith("UUID="): + self.uuid = device_ref[5:] + self.setUseAsDevice("uuid") + mapped_device = microhal.getDeviceByUUID(self.uuid) + if mapped_device is not None: + self.device = mapped_device.getDev() + else: + self.device = "" + try: + self.label = mapped_device.getLabel() + except AttributeError: + pass + elif device_ref.startswith("LABEL="): + self.label = device_ref[6:] + self.setUseAsDevice("label") + mapped_device = microhal.getDeviceByLabel(self.label) + if mapped_device is not None: + self.device = mapped_device.getDev() + else: + self.device = "" + else: + self.device = device_ref + + self.mountpoint = MountEntry.decodeMountEntryString(parts[1]) + self.mounttype = MountEntry.decodeMountEntryString(parts[2]) + self.extraoptions = MountEntry.decodeMountEntryString(parts[3]) + self.fs_freq = int(parts[4]) + self.fs_passno = int(parts[5]) + self.enabled = False + + options = self.extraoptions.split(",") + self.managed = "managed" in options + try: + options.remove("managed") + except ValueError: + pass + self.extraoptions = ",".join(options) + + else: + # This is a new entry, but it's based on another one. + self.device = base.device + self.mountpoint = base.mountpoint + self.mounttype = base.mounttype + self.extraoptions = base.extraoptions + self.fs_freq = base.fs_freq + self.fs_passno = base.fs_passno + self.uuid = base.uuid + self.enabled = base.enabled + self.managed = False + self.iconname = self.getIconName() + + ######################################################################## + def copy(self,newobject=None): + if newobject is None: + newobject = MountEntryExt() + # FIXME: use "newobject = self.__class__()" and get rid of the newobject parameter. + newobject.device = self.device + newobject.mountpoint = self.mountpoint + newobject.mounttype = self.mounttype + newobject.use_as_device = self.use_as_device + newobject.showlabel = self.showlabel + newobject.showdevice = self.showdevice + newobject.showuuid = self.showuuid + newobject.extraoptions = self.extraoptions + newobject.fs_freq = self.fs_freq + newobject.fs_passno = self.fs_passno + newobject.enabled = self.enabled + newobject.uuid = self.uuid + newobject.label = self.label + return newobject + + ######################################################################## + def cleanup(self): + # This method is called after the entry has been removed from the + # mounttable. + pass + + ######################################################################## + def setMountType(self,mounttypename): self.mounttype = mounttypename + + ######################################################################## + def isFileSystemAvailable(self): + return microhal.isSupportedFileSystem(self.mounttype) + + def getDevice(self): return self.device + def setDevice(self,device): self.device = device + def setUseAsDevice(self,use_as): self.use_as_device = use_as + def getUseAsDevice(self): return self.use_as_device + def setUUID(self,uuid): self.uuid = uuid + def setLabel(self,label): self.label = label + def getMountPoint(self): return self.mountpoint + def setMountPoint(self,mountpoint): self.mountpoint = mountpoint + def getExtraOptions(self): return self.extraoptions + def setExtraOptions(self,extraoptions): self.extraoptions = extraoptions + def getFSFreq(self): return self.fs_freq + def setFSFreq(self,fs_freq): self.fs_freq = fs_freq + def getFSPassno(self): return self.fs_passno + def setFSPassno(self,fs_passno): self.fs_passno = fs_passno + def isManaged(self): return self.managed + + def getUUID(self): + if not self.uuid: + return "" + return self.uuid + + def getLabel(self): + try: + if not self.label: + return "" + return self.label + except AttributeError: + return "" + + def getDeviceString(self): + if self.getUseAsDevice() == "label": + if self.label != "": + return MountEntry.encodeMountEntryString("LABEL="+self.label) + else: + print "No Label set, preventing you from shooting yourself in the foot" + elif self.getUseAsDevice() == "uuid": + if self.uuid != "": + return "UUID="+self.uuid + return MountEntry.encodeMountEntryString("UUID="+self.uuid) + else: + print "No UUID set, preventing you from shooting yourself in the foot" + return MountEntry.encodeMountEntryString(self.device) + + ######################################################################## + def getName(self): + if os.path.basename(self.device).startswith("fd"): + return "Floppy" + else: + return self.mountpoint + + ######################################################################## + def getIconName(self): + if self.device is not None and os.path.basename(self.device).startswith("fd"): + return "hi16-floppy" + else: + return "hi16-blockdevice" + + ######################################################################## + def updateStatus(self,mtablist): + self.enabled = self.mountpoint in mtablist + + ######################################################################## + def getFstabOptions(self): + if self.extraoptions!="": + return self.extraoptions.split(",") + else: + return [] + + ######################################################################## + def getFstabLine(self): + # Construct the options field. + _options = self.getFstabOptions() + options = [] + # Remove whitespace and dupes + for o in _options: + if o.strip() not in options: + options.append(o.strip()) + + return self.getDeviceString() + \ + u" " + MountEntry.encodeMountEntryString(self.mountpoint.replace("%20","\040")) + \ + u" " + MountEntry.encodeMountEntryString(self.mounttype) + \ + u" " + MountEntry.encodeMountEntryString(u",".join(options)) + \ + u" " + unicode(self.fs_freq) + u" " + unicode(self.fs_passno) + + ######################################################################## + def getCategory(self): + return self.device + + ######################################################################## + def isEnabled(self): return self.enabled + + ######################################################################## + def enable(self,parentdialog): + self._setBusy(parentdialog,True) + try: + (rc,output) = SimpleCommandRunner().run(["/bin/mount",self.mountpoint]) + finally: + self._setBusy(parentdialog,False) + if rc!=0: + self.handleMountFailure(parentdialog,rc,output,True) + + ######################################################################## + def disable(self,parentdialog): + self._setBusy(parentdialog,True) + try: + (rc,output) = SimpleCommandRunner().run(["/bin/umount",self.mountpoint]) + finally: + self._setBusy(parentdialog,False) + if rc!=0: + self.handleMountFailure(parentdialog,rc,output,False) + + ######################################################################## + def handleMountFailure(self,parentdialog,rc,output,mount_action=True): + """ + Keyword arguments: + mount_action - True=enable, False=disable + """ + global kapp + if mount_action: + msg = i18n("An error occurred while enabling %1.\n\nThe system reported: %2").arg( \ + self.mountpoint).arg(output) + captionmsg = i18n("Unable to enable %1").arg(self.mountpoint) + else: + msg = i18n("An error occurred while disabling %1.\n\nThe system reported: %2").arg( + self.mountpoint).arg(output) + captionmsg = i18n("Unable to disable %1").arg(self.mountpoint) + + extramsg = unicode(i18n("Return code from mount was %1.\n").arg(rc)) + + if (rc & 1)!=0: + extramsg += unicode(i18n("\"incorrect invocation or permissions\"\n")) + if (rc & 2)!=0: + extramsg += unicode(i18n("\"system error (out of memory, cannot fork, no more loop devices)\"\n")) + if (rc & 4)!=0: + extramsg += unicode(i18n("\"internal mount bug or missing nfs support in mount\"\n")) + if (rc & 8)!=0: + extramsg += unicode(i18n("\"user interrupt\"\n")) + if (rc & 16)!=0: + extramsg += unicode(i18n("\"problems writing or locking /etc/mtab\"\n")) + if (rc & 32)!=0: + extramsg += unicode(i18n("\"mount failure\"\n")) + if (rc & 64)!=0: + extramsg += unicode(i18n("\"some mount succeeded\"\n")) + + in_use = False + if not mount_action: + # Use lsof to find out what is blocking the device. + lsof_bin = '/usr/bin/lsof' + rc, output = SimpleCommandRunner().run([lsof_bin,'-FncL',str(self.mountpoint)]) + if rc==0: + # Check if there is one or more processes using the device. + in_use = len(output.split())>3 + if in_use: + # Start fuser.py which lists open filedescriptors on device and offers to get + # rid of them. + fuser = FUser(str(self.mountpoint),None,lsof_bin,kapp) + fuser.exec_loop() + in_use_message = "" + if fuser.result() != 0: + in_use_message = unicode(i18n("Unmounting %1 failed or was cancelled.").arg(self.device)) + extramsg += in_use_message + else: + extramsg += unicode(i18n("(none)")) + + if not in_use: + KMessageBox.detailedSorry(parentdialog, msg, extramsg, captionmsg) + + ######################################################################## + def _setBusy(self,parentdialog,flag): + global kapp + if flag: + kapp.setOverrideCursor( QCursor(Qt.WaitCursor) ) + parentdialog.setEnabled(False) + + # It is necessary to process some of the events in the event queue. + # Otherwise the user won't see that the window is disabled. + # ( setEnabled() here above doesn't redraw the window immediately. + # Redrawing is done via the event queue.) + kapp.processEvents() + else: + parentdialog.setEnabled(True) + kapp.restoreOverrideCursor() + +############################################################################ +class MountEntryExtCommonUnix(MountEntryExt): + + USERMOUNT_NO = 0 + USERMOUNT_ONE = 1 + USERMOUNT_ANY = 2 + USERMOUNT_OWNER = 3 + + ######################################################################## + # Base can be either a fstab format line of text, or another MountEntry + # object. + def __init__(self,base=None): + super(MountEntryExtCommonUnix,self).__init__(base) + + if isinstance(base,MountEntryExtCommonUnix): + # Being initalised from an existing object. + # Only mess with objects + self.atime = base.atime + self.auto = base.auto + self.writeable = base.writeable + self.usedevpoints = base.usedevpoints + self.showlabel = True + self.showuuid = True + self.allowexecutables = base.allowexecutables + self.allowsuid = base.allowsuid + self.allowusermount = base.allowusermount + + elif isinstance(base,StringType) or isinstance(base,UnicodeType): + options = self.extraoptions.split(",") + + self.atime = True + if "noatime" in options: + self.atime = False + self.auto = True + if "noauto" in options: + self.auto = False + self.writeable = True + if "ro" in options: + self.writeable = False + self.usedevpoints = True + if "nodev" in options: + self.usedevpoints = False + self.allowexecutables = True + if "noexec" in options: + self.allowexecutables = False + self.allowsuid = True + if "nosuid" in options: + self.allowsuid = False + self.allowusermount = self.USERMOUNT_NO + if "user" in options: + self.allowusermount = self.USERMOUNT_ONE + if "users" in options: + self.allowusermount = self.USERMOUNT_ANY + if "owner" in options: + self.allowusermount = self.USERMOUNT_OWNER + + self.showlabel = True + self.showuuid = True + + for x in ["noatime","atime","auto","noauto","dev","nodev","nouser", \ + "owner","users","user","suid","nosuid","exec","noexec","rw","ro"]: + try: + options.remove(x) + except ValueError: + pass + + self.extraoptions = ",".join(options) + + else: + # Set some sane defaults. + self.showlabel = True + self.showuuid = True + self.atime = True + self.auto = False + self.writeable = True + self.usedevpoints = False + self.allowexecutables = False + self.allowsuid = False + self.allowusermount = self.USERMOUNT_NO + + ######################################################################## + def copy(self,newobject=None): + if newobject is None: + newobject = MountEntryExtCommonUnix() + super(MountEntryExtCommonUnix,self).copy(newobject) + newobject.atime = self.atime + newobject.auto = self.auto + newobject.use_as_device = self.use_as_device + newobject.showlabel = self.showlabel + newobject.showdevice = self.showdevice + newobject.showuuid = self.showuuid + newobject.uuid = self.uuid + newobject.label = self.label + newobject.writeable = self.writeable + newobject.usedevpoints = self.usedevpoints + newobject.allowexecutables = self.allowexecutables + newobject.allowsuid = self.allowsuid + newobject.allowusermount = self.allowusermount + return newobject + + ######################################################################## + def getFstabOptions(self): + options = [] + + # These options must appear before the others. 'user', according to the + # mount man page implies 'noexec' too, BUT the noexec can be overridden + # by specifying 'exec' after the 'user' keyword. Therefore 'exec' etc + # must come after 'user', 'users' and friends. + options.append(['nouser','user','users','owner'][self.allowusermount]) + + super_options = super(MountEntryExtCommonUnix,self).getFstabOptions() + options.extend(super_options) + + options.append(['noatime','atime'][self.atime]) + options.append(['noauto','auto'][self.auto]) + options.append(['ro','rw'][self.writeable]) + options.append(['nodev','dev'][self.usedevpoints]) + options.append(['noexec','exec'][self.allowexecutables]) + options.append(['nosuid','suid'][self.allowsuid]) + return options + + ######################################################################## + # atime/noatime + def getAtime(self): return self.atime + def setAtime(self,val): self.atime = val + # auto/noauto + def getMountAtBoot(self): return self.auto + def setMountAtBoot(self,val): self.auto = val + # ro/rw + def getWritable(self): return self.writeable + def setWritable(self,val): self.writeable = val + # dev, nodev + def getUseDevPoints(self): return self.usedevpoints + def setUseDevPoints(self,val): self.usedevpoints = val + # exec/noexec + def getAllowExecutables(self): return self.allowexecutables + def setAllowExecutable(self,val): self.allowexecutables = val + # suid/nosuid + def getSUID(self): return self.allowsuid + def setSUID(self,val): self.allowsuid = val + # nouser/user/users/owner + def setAllowUserMount(self,val): self.allowusermount = val + def getAllowUserMount(self): return self.allowusermount + + +############################################################################ +# Common unix filesystems, but for local hard disks. i.e. partitions. +class MountEntryExtCommonUnixLocal(MountEntryExtCommonUnix): + ######################################################################## + def __init__(self,base=None): + super(MountEntryExtCommonUnixLocal,self).__init__(base) + ######################################################################## + def copy(self,newobject=None): + if newobject is None: + newobject = MountEntryExtCommonUnixLocal() + super(MountEntryExtCommonUnixLocal,self).copy(newobject) + newobject.showlabel = self.showlabel + newobject.showdevice = self.showdevice + newobject.showuuid = self.showuuid + return newobject + + +############################################################################ +class MountEntryExtAlien(MountEntryExt): + + USERMOUNT_NO = 0 + USERMOUNT_ONE = 1 + USERMOUNT_ANY = 2 + USERMOUNT_OWNER = 3 + + ######################################################################## + # Base can be either a fstab format line of text, of another MountEntry + # object. + def __init__(self,base=None): + super(MountEntryExtAlien,self).__init__(base) + + if isinstance(base,MountEntryExtAlien): + self.uid = base.uid + self.gid = base.gid + self.label = base.label + self.writeable = base.writeable + self.auto = base.auto + self.allowusermount = base.allowusermount + + elif isinstance(base,StringType) or isinstance(base,UnicodeType): + self.uid = 0 + self.gid = 0 + options = self.extraoptions.split(",") + newoptions = [] + for line in options: + if line.startswith("uid="): + try: + self.uid = int(line[4:]) + except ValueError: + self.uid = 0 + elif line.startswith("gid="): + try: + self.gid = int(line[4:]) + except ValueError: + self.gid = 0 + else: + # We hang on to unknown options for later. + newoptions.append(line) + options = newoptions + + self.writeable = True + if "ro" in options: + self.writeable = False + self.auto = True + if "noauto" in options: + self.auto = False + self.allowusermount = self.USERMOUNT_NO + if "user" in options: + self.allowusermount = self.USERMOUNT_ONE + if "users" in options: + self.allowusermount = self.USERMOUNT_ANY + if "owner" in options: + self.allowusermount = self.USERMOUNT_OWNER + + for x in ["noatime","atime","auto","noauto","dev","nodev","nouser", \ + "owner","users","user","suid","nosuid","exec","noexec","rw", \ + "ro"]: + try: + options.remove(x) + except ValueError: + pass + self.extraoptions = ",".join(options) + + else: + self.uid = 0 + self.gid = 0 + self.writeable = False + self.auto = False + self.allowusermount = self.USERMOUNT_NO + + ######################################################################## + def copy(self,newobject=None): + if newobject is None: + newobject = MountEntryExtAlien() + super(MountEntryExtAlien,self).copy(newobject) + newobject.uid = self.uid + newobject.gid = self.gid + newobject.use_as_device = self.use_as_device + newobject.showlabel = self.showlabel + newobject.showdevice = self.showdevice + newobject.showuuid = self.showuuid + newobject.writeable = self.writeable + newobject.auto = self.auto + newobject.allowusermount = self.allowusermount + return newobject + + ######################################################################## + def getFstabOptions(self): + # Construct the options field. + options = super(MountEntryExtAlien,self).getFstabOptions() + options.append('uid='+unicode(self.uid)) + options.append('gid='+unicode(self.gid)) + options.append(['noauto','auto'][self.auto]) + options.append(['ro','rw'][self.writeable]) + options.append(['nouser','user','users','owner'][self.allowusermount]) + return options + + ######################################################################## + def getUID(self): return self.uid + def setUID(self,val): self.uid = val + def getGID(self): return self.gid + def setGID(self,val): self.gid = val + + # ro/rw + def getWritable(self): return self.writeable + def setWritable(self,val): self.writeable = val + # auto/noauto + def getMountAtBoot(self): return self.auto + def setMountAtBoot(self,val): self.auto = val + # nouser/user/users/owner + def setAllowUserMount(self,val): self.allowusermount = val + def getAllowUserMount(self): return self.allowusermount + +############################################################################ +class MountEntryExtVFAT(MountEntryExtAlien): + def __init__(self,base=None): + super(MountEntryExtVFAT,self).__init__(base) + + if isinstance(base,MountEntryExtVFAT): + self.suppresspermissionerrors = base.suppresspermissionerrors + elif isinstance(base,StringType) or isinstance(base,UnicodeType): + options = self.extraoptions.split(",") + self.suppresspermissionerrors = "quiet" in options + try: + options.remove("quiet") + except ValueError: + pass + self.extraoptions = ",".join(options) + + else: + self.suppresspermissionerrors = False + + ######################################################################## + def copy(self,newobject=None): + if newobject is None: + newobject = MountEntryExtVFAT() + super(MountEntryExtVFAT,self).copy(newobject) + newobject.suppresspermissionerrors = self.suppresspermissionerrors + newobject.showlabel = self.showlabel + newobject.showdevice = self.showdevice + newobject.showuuid = self.showuuid + return newobject + + ######################################################################## + def getFstabOptions(self): + options = super(MountEntryExtVFAT,self).getFstabOptions() + if self.suppresspermissionerrors: + options.append('quiet') + return options + + def getSuppressPermissionErrors(self): return self.suppresspermissionerrors + def setSuppressPermissionErrors(self,val): self.suppresspermissionerrors = val + +############################################################################ +class MountEntryExtSMB(MountEntryExtAlien): + CREDENTIALSBASENAME = "/etc/fstab_smb_credentials_" + ######################################################################## + def __init__(self,base=None): + super(MountEntryExtSMB,self).__init__(base) + + if isinstance(base,MountEntryExtSMB): + self.username = base.username + self.password = base.password + self.credentialsfile = base.credentialsfile + + elif isinstance(base,StringType) or isinstance(base,UnicodeType): + self.username = None + self.password = "" + self.credentialsfile = None + + newoptions = [] + options = self.extraoptions.split(",") + for line in options: + if line.startswith("username="): + self.username = line[9:] + elif line.startswith("password="): + self.password = line[9:] + elif line.startswith("credentials="): + self.credentialsfile = line[12:] + try: + fhandle = codecs.open(self.credentialsfile,'r',locale.getpreferredencoding()) + for line in fhandle.readlines(): + if line.startswith("username"): + self.username = line[8:].strip()[1:].strip() + elif line.startswith("password"): + self.password = line[8:].strip()[1:].strip() + fhandle.close() + + if not self.credentialsfile.startswith(self.CREDENTIALSBASENAME): + self.credentialsfile = None + + except IOError: + self.credentialsfile = None + + elif line=="guest": + pass + else: + # We hang on to unknown options for later. + newoptions.append(line) + options = newoptions + + if self.username == "": + self.username = None + + self.extraoptions = ",".join(options) + + else: + self.username = None + self.password = "" + self.credentialsfile = None + + ######################################################################## + def copy(self,newobject=None): + if newobject is None: + newobject = MountEntryExtSMB() + super(MountEntryExtSMB,self).copy(newobject) + newobject.username = self.username + newobject.password = self.password + newobject.credentialsfile = self.credentialsfile + newobject.showlabel = self.showlabel + newobject.showdevice = self.showdevice + newobject.showuuid = self.showuuid + return newobject + + ######################################################################## + def cleanup(self): + if (self.credentialsfile is not None) and os.path.exists(self.credentialsfile) and os.path.isfile(self.credentialsfile): + os.remove(self.credentialsfile) + + ######################################################################## + def getIconName(self): + return "hi16-network" + + ######################################################################## + def getFstabOptions(self): + options = super(MountEntryExtSMB,self).getFstabOptions() + if self.username is None: + if (self.credentialsfile is not None) and os.path.exists(self.credentialsfile) and os.path.isfile(self.credentialsfile): + os.remove(self.credentialsfile) + options.append("guest") # This option should stop mount(8) from asking for a password. + else: + # Write out the credentials file + if self.credentialsfile is None: + i = 1 + while os.path.exists(self.CREDENTIALSBASENAME+unicode(i)): + i += 1 + self.credentialsfile = self.CREDENTIALSBASENAME+unicode(i) + fd = os.open(self.credentialsfile,os.O_WRONLY|os.O_CREAT,0600) + fhandle = os.fdopen(fd,'w') + fhandle.write((u"username = %s\npassword = %s\n" % (self.username,self.password)) + .encode(locale.getpreferredencoding(),'replace') ) + fhandle.close() + options.append(u"credentials="+self.credentialsfile) + return options + + ######################################################################## + def getUsername(self): return self.username + def setUsername(self,username): self.username = username + def getPassword(self): return self.password + def setPassword(self,password): self.password = password + +############################################################################ +class MountEntryExtSystem(MountEntryExt): + ######################################################################## + def __init__(self,base=None): + super(MountEntryExtSystem,self).__init__(base) + self.use_as_device = "devicenode" + self.label = "" + self.showuuid = False + self.showlabel = False + + ######################################################################## + def copy(self,newobject=None): + if newobject is None: + newobject = MountEntryExtSystem() + super(MountEntryExtSystem,self).copy(newobject) + return newobject + + ######################################################################## + def getCategory(self): + return "system" + + def disable(self,parentdialog): + """ This shouldn't happen since system entries have the disable button disabled """ + msg = i18n("Disabling %1 is not supported.").arg(self.mountpoint) + extramsg = i18n("""Some system devices cannot be disabled because they are needed for \ + basic functionality of the operating system.""") + KMessageBox.detailedSorry(parentdialog,msg,extramsg,\ + i18n("Error occurred while disabling %1").arg(self.mountpoint)) + +############################################################################ +class MountEntryExtSwap(MountEntryExt): + + ######################################################################## + # Base can be either a fstab format line of text, of another MountEntry + # object. + def __init__(self,base=None): + super(MountEntryExtSwap,self).__init__(base) + + if isinstance(base,StringType) or isinstance(base,UnicodeType): + options = self.extraoptions.split(",") + try: + options.remove('defaults') + except ValueError: + pass + self.extraoptions = u",".join(options) + + ######################################################################## + def copy(self,newobject=None): + if newobject is None: + newobject = MountEntryExtSwap() + super(MountEntryExtSwap,self).copy(newobject) + return newobject + + ######################################################################## + def getFstabOptions(self): + options = super(MountEntryExtSwap,self).getFstabOptions() + if len(options)==0: + # Make sure there is at least one option in the list. + options.append('defaults') + return options + + ######################################################################## + def updateStatus(self,mtablist): + + this_device = self.device + if this_device is None: + # Find the device name by its UUID. + if self.uuid: + hal_device = microhal.getDeviceByUUID(self.uuid) + if self.label: + hal_device = microhal.getDeviceByLabel(self.label) + if hal_device is None: + self.enabled = False + return + this_device = hal_device.getDev() + + # If the device is a symlink, then grab the complete target. + if os.path.islink(this_device): + this_device = os.path.join(os.path.dirname(this_device),os.readlink(this_device)) + + fhandle = open("/proc/swaps") + lines = fhandle.readlines() + fhandle.close() + + try: del lines[0] + except IndexError: pass + + self.enabled = False + for line in lines: + parts = line.split() + if parts[0]==this_device: + self.enabled = True + return + + ######################################################################## + # Returns a list of command+arguments + def enable(self,parentdialog): + self._setBusy(parentdialog,True) + try: + (rc,output) = SimpleCommandRunner().run(['/sbin/swapon',self.device]) + if rc!=0: + msg = i18n("An error occurred while enabling swap partition %1.\n\nThe system reported: %2").arg(self.device).arg(output) + KMessageBox.sorry(parentdialog,msg,\ + i18n("Error occurred while enabling swap partition %1").arg(self.device)) + finally: + self._setBusy(parentdialog,False) + + ######################################################################## + # Returns a list of command+arguments or None. + def disable(self,parentdialog): + self._setBusy(parentdialog,True) + try: + (rc,output) = SimpleCommandRunner().run(['/sbin/swapoff',self.device]) + if rc!=0: + msg = i18n("An error occurred while disabling swap partition %1.\n\nThe system reported: %2").arg(self.device).arg(output) + KMessageBox.sorry(parentdialog,msg,\ + i18n("Error occurred while disabling swap partition %1").arg(self.device)) + finally: + self._setBusy(parentdialog,False) + +############################################################################ +# This represents a mount entry. +# +# It also does a little trick with the MountEntryExt classes. MountEntry +# objects kind of 'change' class under your nose when they are set to +# different mount types. The handling of the different kinds of mount types +# is handled by MountEntryExt objects and subclasses. + +class MountEntry(object): + + MountTypes = { + 'proc' : (MountEntryExtSystem,i18n("proc")), + 'sysfs' : (MountEntryExtSystem,i18n("sysfs")), + 'rootfs' : (MountEntryExtSystem,i18n("rootfs")), + 'bdev' : (MountEntryExtSystem,i18n("bdev")), + 'sockfs' : (MountEntryExtSystem,i18n("sockfs")), + 'tmpfs' : (MountEntryExtSystem,i18n("tmpfs")), + 'shm' : (MountEntryExtSystem,i18n("shm")), + 'pipefs' : (MountEntryExtSystem,i18n("pipefs")), + 'devfs' : (MountEntryExtSystem,i18n("devfs - Device File System")), + 'devpts' : (MountEntryExtSystem,i18n("devpts")), + 'ramfs' : (MountEntryExtSystem,i18n("ramfs")), + 'auto' : (MountEntryExtCommonUnix,i18n("Automatic")), + 'usbdevfs' : (MountEntryExtSystem,i18n("usbdevfs")), + 'procbususb' : (MountEntryExtSystem,i18n("procbususb")), + 'usbfs' : (MountEntryExtSystem,i18n("usbfs")), + 'supermount' : (MountEntryExt,i18n("supermount")), + 'swap' : (MountEntryExtSwap,i18n("Swap - Linux Swap Space")), + + 'nfs' : (MountEntryExtCommonUnix,i18n("NFS - Network File System")), + 'cifs' : (MountEntryExtSMB,i18n("Windows File Sharing")), + + 'ext2' : (MountEntryExtCommonUnixLocal,i18n("Ext2 - Second Extended FS")), + 'ext3' : (MountEntryExtCommonUnixLocal,i18n("Ext3 - Third Extended FS")), + 'reiserfs' : (MountEntryExtCommonUnixLocal,i18n("ReiserFS")), + 'reiser4' : (MountEntryExtCommonUnixLocal,i18n("Reiser4")), + 'xfs' : (MountEntryExtCommonUnixLocal,i18n("XFS - SGI's journaling filesystem")), + 'hfs' : (MountEntryExtCommonUnixLocal,i18n("HFS - Apple's Hierarchical File System")), + 'hfsplus' : (MountEntryExtVFAT,i18n("HFS+ - Apple's modernized Hierarchical File System")), + 'jfs' : (MountEntryExtCommonUnixLocal,i18n("JFS - IBM's Journaled File System")), + 'vfat' : (MountEntryExtVFAT,i18n("VFAT - Microsoft FAT File Systems")), + 'ntfs' : (MountEntryExtVFAT,i18n("NTFS - NT File System")), + 'udf' : (MountEntryExtSystem,i18n("udf")), + 'iso9660' : (MountEntryExt,i18n("iso9660 - CD-ROM")), + } + + notInFstab = False + maydisable = True # Some entries, such as /proc can't be disabled. + + ######################################################################## + # Base can be either a fstab format line of text, of another MountEntry + # object. + def __init__(self,base=None): + try: + self.extensionObjects = {} + if base==None: + self.mounttype = 'auto' + elif isinstance(base,StringType) or isinstance(base,UnicodeType): + parts = base.split() + self.mounttype = parts[2] + # 'udf,iso9660' seems default for some devices in fstab, + # check if all listed filesystems are available, if yes set to 'auto'. + if len(self.mounttype.split(',')) > 1: + """ + # We could check here, but then we'd need a reference to MicroHAL. + #for m in self.mounttype.split(','): + #if m not in supported_fs: + # print "Filesystem ", m, "not supported by the kernel" + # break + """ + self.mounttype = "auto" + else: + # This is a new entry, but it's based on another one. + self.mounttype = base.mounttype + self.extension = self.MountTypes[self.mounttype][0](base) + self.extensionObjects[self.mounttype] = self.extension + except (KeyError,IndexError): + raise InvalidMountEntryError, u"Unable to parse mount entry:"+unicode(base) + + ######################################################################## + def getMountType(self): + return self.mounttype + + ######################################################################## + def setMountType(self,newtypename): + if newtypename not in self.extensionObjects: + try: + self.extensionObjects[newtypename] = self.MountTypes[newtypename][0](self.extension) + except KeyError: + raise NotImplementedError, "Unknown mounttype:"+newtypename + self.mounttype = newtypename + self.extension = self.extensionObjects[newtypename] + self.extension.setMountType(newtypename) + + ######################################################################## + def copy(self): + newentry = MountEntry() + newentry.mounttype = self.mounttype + newext = self.extension.copy() + newentry.use_as_device = self.use_as_device + newentry.showlabel = self.showlabel + newentry.showdevice = self.showdevice + newentry.showuuid = self.showuuid + newentry.extensionObjects[self.mounttype] = newext + newentry.extension = newext + return newentry + + ######################################################################## + def inPlaceCopyFrom(self,sourceentry): + self.extension.cleanup() + + tmpcopy = sourceentry.copy() + self.extensionObjects = tmpcopy.extensionObjects + self.mounttype = tmpcopy.mounttype + self.extension = tmpcopy.extension + + # Override the attribute lookup, set/get, to use the extension object + ######################################################################## + def __getattr__(self,name): + try: + return getattr(self.extension,name) + except AttributeError, a: + print a + + ######################################################################## +# FIXME +## def __setattr__(self,name,value): +## if 'extension' in self.__dict__: +## if name in self.extension.__dict__: +## setattr(self.extension,name,value) +## return +## self.__dict__[name] = value + + ######################################################################## + def getMountTypes(): + return MountEntry.MountTypes.keys() + getMountTypes = staticmethod(getMountTypes) + + ######################################################################## + def getMountTypeLongName(typename): + return MountEntry.MountTypes[typename][1] + getMountTypeLongName = staticmethod(getMountTypeLongName) + + ######################################################################## + def encodeMountEntryString(string): + newstring = u"" + for c in string: + if c==' ': + newstring += "\\040" + elif c=="\t": + newstring += "\\012" + elif c=='\\': + newstring += "\\134" + else: + newstring += c + return newstring + encodeMountEntryString = staticmethod(encodeMountEntryString) + + ######################################################################## + def decodeMountEntryString(string): + newstring = "" + while string!="": + if len(string)>=4 and string[0]=='\\' and isoct(string[1]) \ + and isoct(string[2]) and isoct(string[3]): + newstring += chr(64*(ord(string[1])-ord('0')) + \ + 8*(ord(string[2])-ord('0')) + (ord(string[3])-ord('0'))) + string = string[4:] + else: + newstring += string[0] + string = string[1:] + return newstring + decodeMountEntryString = staticmethod(decodeMountEntryString) + +############################################################################ +class MountEntryComment(MountEntry): + """ This represents a comment mount entry or generally something that we don't + understand (might be comment, might be fstab syntax we don't know, might be + a faulty line in there). We don't want to wipe that stuff out, but we can't + deal with it in a sensible way, so we keep it in a MountEntryComment, + exclude it from most operations, but will write it back to fstab afterwards + + As a result of that we only define the stuff that's necessary, namely saving + the fstab line and returning it when writing.""" + + ######################################################################## + def __init__(self,base=None): + self.row = base + + ######################################################################## + def getFstabLine(self): return self.row + +############################################################################ +def isoct(c): return c in '01234567' + +############################################################################ +class InvalidMountEntryError(Exception): + + ######################################################################## + def __init__(self,arg=None): + self.arg = arg + + ######################################################################## + def __str__(self): + return str(self.arg) + +############################################################################ +class MountTable(object): + + ######################################################################## + def __init__(self,fstab_filename,mtab_filename): + self.fstab_filename = fstab_filename + self.mtab_filename = mtab_filename + + self.entries = [] + self.allentries = [] + + # sysfs does not need an entry in fstab, so we add it even if it's not + # in there, it's mounted automatically anyway and shows up in mtab + sysfs_in_fstab = False + usbdevfs_in_fstab = False + + fhandle = codecs.open(self.fstab_filename,'r',locale.getpreferredencoding()) + for row in fhandle.readlines(): + row = row.strip('\n') # Carefully remove any trailing newline. + if row.strip().startswith("#") or row.strip()=="": + entry = MountEntryComment(row) + else: + try: + entry = MountEntry(row) + self.append(entry) + + if entry.getMountType() == "sysfs": + sysfs_in_fstab = True + if entry.getMountType() == "usbdevfs" or "procbususb": + usbdevfs_in_fstab = True + if entry.getMountType() == "proc": + entry.maydisable = False + except InvalidMountEntryError: + entry = MountEntryComment(row) + # We keep a list with references to _all_ entries, also the comments, + # this is the one we'll use to write out our new fstab, only 'real' + # entries (real == entries we understand) are added to self to let them + # be handled by iterator. + # allentries includes comments and invalid lines, self doesn't. + self.allentries.append(entry) + fhandle.close() + + if not sysfs_in_fstab: + sysfsentry = MountEntry(u"sysfs /sys sysfs defaults 0 0") + sysfsentry.notInFstab = True + sysfsentry.maydisable = False + #self.append(sysfsentry) + + if not usbdevfs_in_fstab: + usbdevfsentry = MountEntry(u"procbususb /proc/bus/usb usbdevfs defaults 0 0") + usbdevfsentry.notInFstab = True + usbdevfsentry.maydisable = False + self.append(usbdevfsentry) + + self.updateStatus() + + ######################################################################## + def append(self,entry): + self.entries.append(entry) + + ######################################################################## + def remove(self,entry): + self.allentries.remove(entry) + entry.cleanup() + + ######################################################################## + def updateStatus(self,entry=None): + mtablist = self.getMtabList() + if entry==None: + for entry in self.entries: + entry.updateStatus(mtablist) + else: + entry.updateStatus(mtablist) + + ######################################################################## + def getMtabList(self): + fhandle = open(self.mtab_filename) + mtablist = [] + for row in fhandle.readlines(): + if row.strip()[0]!='#': + parts = row.split() + mtablist.append(parts[1]) + fhandle.close() + return mtablist + + ######################################################################## + def updateFstabOnDisk(self): + fhandle = None + try: + try: + fhandle = codecs.open(self.fstab_filename+"~","w",locale.getpreferredencoding(),'replace') + for entry in self.allentries: + if not entry.notInFstab: + line = entry.getFstabLine() + fhandle.write(line+u"\n") + print line + fhandle.close() + fhandle = None + + # Move it over the original + os.rename(self.fstab_filename+"~",self.fstab_filename) + return True + finally: + if fhandle: + fhandle.close() + except IOError: + return False + + ######################################################################## + # We make this class look like a container, and just forward everything + # on to the entries attribute. + def __contains__(self,item): + return self.entries.__contains(item) + ######################################################################## + def __delitem__(self,key): + raise NotImplementedError, "No __delitem__ on MountTable." + + ######################################################################## + def __getitem__(self,key): + return self.entries.__getitem__(key) + ######################################################################## + + def __iter__(self): + return self.entries.__iter__() + ######################################################################## + def __len__(self): + return self.entries.__len__() + ######################################################################## + def __setitem__(self,key,value): + raise NotImplementedError, "No __setitem__ on MountTable." + +############################################################################ +class MountEntryDialogOptions(QWidget): + + deviceexample = i18n("(for example /dev/hdb3)") + + ######################################################################## + def __init__(self,parent,showmountpoint=True,showdevice=True, + showfs_freq=True,showfs_passno=True,showuuid=True,showlabel=True): + QWidget.__init__(self,parent) + self.showmountpoint = showmountpoint + self.showdevice = showdevice + self.showfs_freq = showfs_freq + self.showfs_passno = showfs_passno + self.showuuid = showuuid + self.showlabel = showlabel + self._fillPage() + # TODO: KDirSelectDialog needs "Create new Folder" + self.mountpointdialog = KDirSelectDialog("/",True,self,"Select Mount Point",True) + + ######################################################################## + def _fillPage(self): + row = 0 + grid = QGridLayout(self,1,2) + grid.setSpacing(KDialog.spacingHint()) + grid.setColStretch(0,0) + grid.setColStretch(2,0) + + if self.showmountpoint: + + label = QLabel(i18n("Mount Point:"),self) + grid.addWidget(label,row,0) + + hbox = QHBox(self) + hbox.setSpacing(KDialog.spacingHint()) + self.mountpointlineedit = KLineEdit(hbox) + hbox.setStretchFactor(self.mountpointlineedit,1) + #self.connect(self.homediredit, SIGNAL("textChanged(const QString &)"), self.slotHomeDirChanged) + self.mountpointbutton = KPushButton(i18n("Browse..."),hbox) + hbox.setStretchFactor(self.mountpointbutton,0) + self.connect(self.mountpointbutton,SIGNAL("clicked()"),self.slotBrowseMountPointClicked) + grid.addMultiCellWidget(hbox,row,row,1,3) + row += 1 + + if self.showdevice: + hbox = QHBox(self) + hbox.setSpacing(KDialog.spacingHint()) + + label = QLabel(i18n("Device:"),self) + grid.addWidget(label,row,0) + + self.devicecheckbox = QRadioButton(i18n("by name"),hbox) + self.connect(self.devicecheckbox,SIGNAL("clicked()"), \ + self.slotDeviceCheckboxClicked) + self.devicelineedit = KLineEdit(hbox) + grid.addMultiCellWidget(hbox,row,row,1,3) + row += 1 + example = QLabel(self.deviceexample,self) + grid.addMultiCellWidget(example,row,row,1,3) + row += 1 + + if self.showuuid: + hbox = QHBox(self) + hbox.setSpacing(KDialog.spacingHint()) + self.uuidcheckbox = QRadioButton(i18n("by UUID"),hbox) + self.connect(self.uuidcheckbox,SIGNAL("clicked()"), \ + self.slotUUIDCheckboxClicked) + self.uuidlineedit = KLineEdit(hbox) + grid.addMultiCellWidget(hbox,row,row,1,3) + row += 1 + + if self.showlabel: + hbox = QHBox(self) + hbox.setSpacing(KDialog.spacingHint()) + self.labelcheckbox = QRadioButton(i18n("by label"),hbox) + self.connect(self.labelcheckbox,SIGNAL("clicked()"), \ + self.slotLabelCheckboxClicked) + self.labellineedit = KLineEdit(hbox) + grid.addMultiCellWidget(hbox,row,row,1,3) + row += 1 + else: + if self.showdevice: + label = QLabel(i18n("Device:"),self) + grid.addWidget(label,row,0) + self.devicelineedit = KLineEdit(self) + grid.addMultiCellWidget(self.devicelineedit,row,row,1,3) + row += 1 + example = QLabel(self.deviceexample,self) + grid.addWidget(example,row,1) + + if self.showuuid: + label = QLabel(i18n("Device UUID:"),self) + grid.addWidget(label,row,0) + self.uuidlineedit = KLineEdit(self) + grid.addMultiCellWidget(self.uuidlineedit,row,row,1,3) + row += 1 + + if self.showlabel: + label = QLabel(i18n("Device Label:"),self) + grid.addWidget(label,row,0) + self.labellineedit = KLineEdit(self) + grid.addMultiCellWidget(self.labellineedit,row,row,1,3) + row += 1 + + label = QLabel(i18n("Options:"),self) + grid.addWidget(label,row,0) + self.optionslineedit = KLineEdit(self) + grid.addMultiCellWidget(self.optionslineedit,row,row,1,3) + row += 1 + + if self.showfs_freq: + label = QLabel(i18n("fs_freq:"),self) + grid.addWidget(label,row,0) + self.fsfreqspinbox = KIntSpinBox (0,1000,1,0,10,self) + grid.addWidget(self.fsfreqspinbox,row,1) + + if self.showfs_passno: + label = QLabel(i18n("fs_passno:"),self) + grid.addWidget(label,row,2) + self.fspassnospinbox = KIntSpinBox (0,1000,1,0,10,self) + grid.addWidget(self.fspassnospinbox,row,3) + row += 1 + + grid.addWidget(QWidget(self),row,0) + + for x in range(grid.numRows()): + grid.setRowStretch(x,0) + grid.setRowStretch(grid.numRows()-1,1) + + ######################################################################## + def displayMountEntry(self,entry): + global allowuuid, allowlabel + if self.showmountpoint: + self.mountpointlineedit.setText(entry.getMountPoint()) + + uuid = entry.getUUID() + if entry.getDevice() == "" and uuid != "": + device = microhal.getDeviceByUUID(uuid) + self.devicelineedit.setText(uuid) + else: + if self.showdevice: + self.devicelineedit.setText(entry.getDevice()) + + if self.showuuid: + if entry.getUUID()!="": + self.uuidlineedit.setText(entry.getUUID()) + + if self.showlabel: + if entry.getLabel()!="": + self.labellineedit.setText(entry.getLabel()) + + if entry.getUseAsDevice() == "devicenode": + if self.showdevice: + self.devicelineedit.setEnabled(True) + self.devicecheckbox.setChecked(True) + if self.showuuid: + self.uuidcheckbox.setChecked(False) + self.uuidlineedit.setEnabled(False) + if self.showlabel: + self.labelcheckbox.setChecked(False) + self.labellineedit.setEnabled(False) + elif entry.getUseAsDevice() == "label": + if self.showlabel: + self.labellineedit.setEnabled(True) + self.labelcheckbox.setChecked(True) + if self.showdevice: + self.devicelineedit.setEnabled(False) + self.devicecheckbox.setChecked(False) + if self.showuuid: + self.uuidlineedit.setEnabled(False) + self.uuidcheckbox.setChecked(False) + elif entry.getUseAsDevice() == "uuid": + if self.showdevice: + self.devicecheckbox.setChecked(False) + self.devicelineedit.setEnabled(False) + if self.showlabel: + self.labelcheckbox.setChecked(False) + self.labellineedit.setEnabled(False) + if self.showuuid: + self.uuidlineedit.setEnabled(True) + self.uuidcheckbox.setChecked(True) + +## if allowlabel: +## self.labellineedit.setText(entry.getLabel()) +## if allowuuid: +## self.uuidlineedit.setText(entry.getUUID()) +## self.devicelineedit.setText(entry.getDevice()) + + self.optionslineedit.setText(entry.getExtraOptions()) + if self.showfs_freq: + self.fsfreqspinbox.setValue(entry.getFSFreq()) + if self.showfs_passno: + self.fspassnospinbox.setValue(entry.getFSPassno()) + + ######################################################################## + def undisplayMountEntry(self,entry): + if self.showmountpoint: + entry.setMountPoint( unicode(self.mountpointlineedit.text()) ) + if self.showdevice: + entry.setDevice( unicode(self.devicelineedit.text()) ) + + if self.showuuid and self.showdevice: + if self.devicecheckbox.isChecked(): + entry.setUUID(None) + else: + entry.setUUID( unicode(self.uuidlineedit.text()) ) + if self.showlabel and self.showdevice: + if self.devicecheckbox.isChecked(): + entry.setLabel(None) + else: + entry.setLabel( unicode(self.labellineedit.text()) ) + + if allowuuid and self.showuuid: + if self.uuidcheckbox.isChecked(): + entry.setUseAsDevice("uuid") + if allowlabel and self.showlabel: + if self.labelcheckbox.isChecked(): + entry.setUseAsDevice("label") + if self.showdevice: + if self.devicecheckbox.isChecked(): + entry.setUseAsDevice("devicenode") + + entry.setExtraOptions( unicode(self.optionslineedit.text()) ) + if self.showfs_freq: + entry.setFSFreq(self.fsfreqspinbox.value()) + if self.showfs_passno: + entry.setFSPassno(self.fspassnospinbox.value()) + + ######################################################################## + def slotBrowseMountPointClicked(self): + fileurl = KURL() + fileurl.setPath(self.mountpointlineedit.text()) + self.mountpointdialog.setCurrentURL(fileurl) + if self.mountpointdialog.exec_loop()==QDialog.Accepted: + self.mountpointlineedit.setText(self.mountpointdialog.url().path()) + + ######################################################################## + def slotDeviceCheckboxClicked(self): + self.uuidcheckbox.setChecked(False) + self.labelcheckbox.setChecked(False) + self.devicelineedit.setEnabled(True) + self.uuidlineedit.setEnabled(False) + self.labellineedit.setEnabled(False) + + ######################################################################## + def slotUUIDCheckboxClicked(self): + if self.uuidlineedit.text() == "": + label = microhal.getUUIDByDevice(unicode(self.devicelineedit.text())) + self.uuidlineedit.setText(label) + self.devicecheckbox.setChecked(False) + self.devicelineedit.setEnabled(False) + self.uuidlineedit.setEnabled(True) + self.labelcheckbox.setChecked(False) + self.labellineedit.setEnabled(False) + + def slotLabelCheckboxClicked(self): + if self.labellineedit.text() == "": + label = microhal.getLabelByDevice(unicode(self.devicelineedit.text())) + self.labellineedit.setText(label) + self.uuidcheckbox.setChecked(False) + self.devicelineedit.setEnabled(False) + self.uuidlineedit.setEnabled(False) + self.labelcheckbox.setChecked(True) + self.labellineedit.setEnabled(True) + +############################################################################ +class MountEntryDialogOptionsCommonUnix(MountEntryDialogOptions): + + ######################################################################## + def __init__(self,parent): + MountEntryDialogOptions.__init__(self,parent) + self.advanceddialog = MountEntryAdvancedCommonUnixDialog(None) + + ######################################################################## + def _fillPage(self): + + row = 0 + grid = QGridLayout(self,1,2) + grid.setSpacing(KDialog.spacingHint()) + grid.setColStretch(0,0) + grid.setRowStretch(6,1) + + label = QLabel(i18n("Mount Point:"),self) + grid.addWidget(label,row,0) + hbox = QHBox(self) + hbox.setSpacing(KDialog.spacingHint()) + self.mountpointlineedit = KLineEdit(hbox) + hbox.setStretchFactor(self.mountpointlineedit,1) + #self.connect(self.homediredit, SIGNAL("textChanged(const QString &)"), self.slotHomeDirChanged) + self.mountpointbutton = KPushButton(i18n("Browse..."),hbox) + hbox.setStretchFactor(self.mountpointbutton,0) + self.connect(self.mountpointbutton,SIGNAL("clicked()"), \ + self.slotBrowseMountPointClicked) + grid.addWidget(hbox,row,1) + row += 1 + + if self.showuuid or self.showlabel: + + hbox = QHBox(self) + hbox.setSpacing(KDialog.spacingHint()) + + label = QLabel(i18n("Device:"),self) + grid.addWidget(label,row,0) + + self.devicecheckbox = QRadioButton(i18n("by name"),hbox) + self.connect(self.devicecheckbox,SIGNAL("clicked()"), \ + self.slotDeviceCheckboxClicked) + self.devicelineedit = KLineEdit(hbox) + grid.addWidget(hbox,row,1) + row += 1 + example = QLabel(self.deviceexample,self) + grid.addWidget(example,row,1) + row += 1 + + if self.showuuid: + hbox = QHBox(self) + hbox.setSpacing(KDialog.spacingHint()) + self.uuidcheckbox = QRadioButton(i18n("by UUID"),hbox) + self.connect(self.uuidcheckbox,SIGNAL("clicked()"), \ + self.slotUUIDCheckboxClicked) + self.uuidlineedit = KLineEdit(hbox) + grid.addWidget(hbox,row,1) + row += 1 + + if self.showlabel: + hbox = QHBox(self) + hbox.setSpacing(KDialog.spacingHint()) + self.labelcheckbox = QRadioButton(i18n("by label"),hbox) + self.connect(self.labelcheckbox,SIGNAL("clicked()"), \ + self.slotLabelCheckboxClicked) + self.labellineedit = KLineEdit(hbox) + grid.addWidget(hbox,row,1) + row += 1 + + else: + label = QLabel(i18n("Device:"),self) + grid.addWidget(label,row,0) + self.devicelineedit = KLineEdit(self) + grid.addWidget(self.devicelineedit,row,1) + row += 1 + example = QLabel(self.deviceexample,self) + grid.addWidget(example,row,1) + row += 1 + + self.autocheckbox = QCheckBox(i18n("Enable at start up"),self) + grid.addWidget(self.autocheckbox,row,1) + row += 1 + + self.writeablecheckbox = QCheckBox(i18n("Writeable"),self) + grid.addWidget(self.writeablecheckbox,row,1) + row += 1 + + label = QLabel(i18n("Mount Permission:"),self) + grid.addWidget(label,row,0) + self.usermountcombobox = KComboBox(self) + self.usermountcombobox.insertItem(i18n("Root user only may enable/disable")) + self.usermountcombobox.insertItem(i18n("One user at a time may enable/disable")) + self.usermountcombobox.insertItem(i18n("Any user may enable/disable anytime")) + self.usermountcombobox.insertItem(i18n("Device owner may enable/disable")) + grid.addWidget(self.usermountcombobox,row,1) + row += 1 + + #grid.addWidget(,9,0) + button = KPushButton(i18n("Advanced..."),self) + button.setSizePolicy(QSizePolicy.Fixed,QSizePolicy.Fixed) + self.connect(button,SIGNAL("clicked()"),self.slotAdvancedClicked) + grid.addWidget(button,row,1,Qt.AlignRight) + row += 1 + + grid.addWidget(QWidget(self),row,0) + + for x in range(grid.numRows()): + grid.setRowStretch(x,0) + grid.setRowStretch(grid.numRows()-1,1) + + ######################################################################## + def displayMountEntry(self,entry): + self.devicelineedit.setText(entry.getDevice()) + + if self.showuuid: + if entry.getUUID()!="": + self.uuidlineedit.setText(entry.getUUID()) + + if self.showlabel: + if entry.getLabel()!="": + self.labellineedit.setText(entry.getLabel()) + + if entry.getUseAsDevice() == "devicenode": + self.devicelineedit.setEnabled(True) + self.devicecheckbox.setChecked(True) + self.uuidcheckbox.setChecked(False) + self.uuidlineedit.setEnabled(False) + self.labelcheckbox.setChecked(False) + self.labellineedit.setEnabled(False) + elif entry.getUseAsDevice() == "label": + self.labellineedit.setEnabled(True) + self.labelcheckbox.setChecked(True) + self.devicelineedit.setEnabled(False) + self.devicecheckbox.setChecked(False) + self.uuidlineedit.setEnabled(False) + self.uuidcheckbox.setChecked(False) + elif entry.getUseAsDevice() == "uuid": + self.devicecheckbox.setChecked(False) + self.devicelineedit.setEnabled(False) + self.labelcheckbox.setChecked(False) + self.labellineedit.setEnabled(False) + self.uuidlineedit.setEnabled(True) + self.uuidcheckbox.setChecked(True) + + self.devicelineedit.setText(entry.getDevice()) + self.mountpointlineedit.setText(entry.getMountPoint()) + self.options = entry.getExtraOptions() + self.fsfreq = entry.getFSFreq() + self.fspassno = entry.getFSPassno() + self.autocheckbox.setChecked(entry.getMountAtBoot()) + self.writeablecheckbox.setChecked(entry.getWritable()) + self.accesstime = entry.getAtime() + self.allowexecutable = entry.getAllowExecutables() + self.allowsuid = entry.getSUID() + self.usedevpoints = entry.getUseDevPoints() + self.usermountcombobox.setCurrentItem(entry.getAllowUserMount()) + + ######################################################################## + def undisplayMountEntry(self,entry): + + entry.setDevice( unicode(self.devicelineedit.text()) ) + if self.showuuid: + if self.devicecheckbox.isChecked() or self.labelcheckbox.isChecked(): + entry.setUUID(None) + else: + entry.setUUID( unicode(self.uuidlineedit.text()) ) + + if self.showlabel: + if self.devicecheckbox.isChecked() or self.uuidcheckbox.isChecked(): + entry.setLabel(None) + else: + entry.setLabel( unicode(self.labellineedit.text()) ) + + if not self.showlabel and not self.showuuid: + if self.uuidcheckbox.isChecked() or self.labelcheckbox.isChecked(): + entry.setLabel(None) + else: + entry.setLabel( unicode(self.devicelineedit.text()) ) + + if allowuuid: + if self.uuidcheckbox.isChecked(): + entry.setUseAsDevice("uuid") + if allowlabel: + if self.labelcheckbox.isChecked(): + entry.setUseAsDevice("label") + if self.devicecheckbox.isChecked(): + entry.setUseAsDevice("devicenode") + + entry.setMountPoint( unicode(self.mountpointlineedit.text()) ) + entry.setExtraOptions(self.options) + entry.setFSFreq(self.fsfreq) + entry.setFSPassno(self.fspassno) + entry.setAtime(self.accesstime) + entry.setMountAtBoot(self.autocheckbox.isChecked()) + entry.setWritable(self.writeablecheckbox.isChecked()) + entry.setUseDevPoints(self.usedevpoints) + entry.setAllowExecutable(self.allowexecutable) + entry.setSUID(self.allowsuid) + entry.setAllowUserMount(self.usermountcombobox.currentItem()) + + ######################################################################## + def slotAdvancedClicked(self): + (self.accesstime, self.allowexecutable, self.allowsuid, self.usedevpoints, self.options, self.fsfreq, + self.fspassno)\ + = self.advanceddialog.do(self.accesstime, self.allowexecutable, self.allowsuid, self.usedevpoints, + self.options, self.fsfreq, self.fspassno) + + ######################################################################## + def slotDeviceCheckboxClicked(self): + self.uuidcheckbox.setChecked(False) + self.devicelineedit.setEnabled(True) + self.labelcheckbox.setChecked(False) + self.labellineedit.setEnabled(False) + self.uuidlineedit.setEnabled(False) + + ######################################################################## + def slotUUIDCheckboxClicked(self): + if self.uuidlineedit.text() == "": + label = microhal.getUUIDByDevice(unicode(self.devicelineedit.text())) + self.uuidlineedit.setText(label) + self.devicecheckbox.setChecked(False) + self.devicelineedit.setEnabled(False) + self.labelcheckbox.setChecked(False) + self.labellineedit.setEnabled(False) + self.uuidlineedit.setEnabled(True) + + def slotLabelCheckboxClicked(self): + if self.labellineedit.text() == "": + label = microhal.getLabelByDevice(unicode(self.devicelineedit.text())) + self.labellineedit.setText(label) + self.devicecheckbox.setChecked(False) + self.devicelineedit.setEnabled(False) + self.uuidcheckbox.setChecked(False) + self.uuidlineedit.setEnabled(False) + self.labellineedit.setEnabled(True) + +############################################################################ +class MountEntryDialogOptionsSys(MountEntryDialogOptions): + ######################################################################## + def __init__(self,parent): + MountEntryDialogOptions.__init__(self,parent,True,False,False,False,False,False) + +############################################################################ +class MountEntryDialogOptionsSwap(MountEntryDialogOptions): + ######################################################################## + def __init__(self,parent): + MountEntryDialogOptions.__init__(self,parent,False,True,False,False) + +class MountEntryDialogOptionsNfs(MountEntryDialogOptionsCommonUnix): + + deviceexample = i18n("(for example 192.168.1.66:/export)") + +############################################################################ +class MountEntryDialogOptionsVFAT(MountEntryDialogOptions): + ######################################################################## + def __init__(self,parent): + MountEntryDialogOptions.__init__(self,parent) + self.advanceddialog = MountEntryAdvancedPlainDialog(None) + self.updatinggui= False + + ######################################################################## + def _fillPage(self): + global allowuuid, allowlabel + + row = 0 + grid = QGridLayout(self,11,2) + grid.setSpacing(KDialog.spacingHint()) + grid.setColStretch(0,0) + grid.setColStretch(2,0) + grid.setRowStretch(10,1) + + label = QLabel(i18n("Mount Point:"),self) + grid.addWidget(label,row,0) + hbox = QHBox(self) + hbox.setSpacing(KDialog.spacingHint()) + self.mountpointlineedit = KLineEdit(hbox) + hbox.setStretchFactor(self.mountpointlineedit,1) + #self.connect(self.homediredit, SIGNAL("textChanged(const QString &)"), self.slotHomeDirChanged) + self.mountpointbutton = KPushButton(i18n("Browse..."),hbox) + hbox.setStretchFactor(self.mountpointbutton,0) + self.connect(self.mountpointbutton,SIGNAL("clicked()"),self.slotBrowseMountPointClicked) + grid.addMultiCellWidget(hbox,row,row,1,3) + row += 1 + + if allowuuid or allowlabel: + hbox = QHBox(self) + hbox.setSpacing(KDialog.spacingHint()) + + label = QLabel(i18n("Device:"),self) + grid.addWidget(label,row,0) + + self.devicecheckbox = QRadioButton(i18n("by name"),hbox) + self.connect(self.devicecheckbox,SIGNAL("clicked()"), \ + self.slotDeviceCheckboxClicked) + self.devicelineedit = KLineEdit(hbox) + grid.addWidget(hbox,row,1) + row += 1 + example = QLabel(self.deviceexample,self) + grid.addWidget(example,row,1) + row += 1 + + if allowuuid and self.showuuid: + hbox = QHBox(self) + hbox.setSpacing(KDialog.spacingHint()) + self.uuidcheckbox = QRadioButton(i18n("by UUID"),hbox) + self.connect(self.uuidcheckbox,SIGNAL("clicked()"), \ + self.slotUUIDCheckboxClicked) + self.uuidlineedit = KLineEdit(hbox) + grid.addWidget(hbox,row,1) + row += 1 + + if allowlabel and self.showlabel: + hbox = QHBox(self) + hbox.setSpacing(KDialog.spacingHint()) + self.labelcheckbox = QRadioButton(i18n("by label"),hbox) + self.connect(self.labelcheckbox,SIGNAL("clicked()"), \ + self.slotLabelCheckboxClicked) + self.labellineedit = KLineEdit(hbox) + grid.addWidget(hbox,row,1) + row += 1 + + else: + + label = QLabel(i18n("Device:"),self) + grid.addWidget(label,row,0) + self.devicelineedit = KLineEdit(self) + grid.addMultiCellWidget(self.devicelineedit,row,row,1,3) + row += 1 + + example = QLabel(self.deviceexample,self) + grid.addWidget(example,row,1) + row += 1 + + self.autocheckbox = QCheckBox(i18n("Enable at start up"),self) + grid.addMultiCellWidget(self.autocheckbox,row,row,1,3) + row += 1 + + # Security & Safety line. + hbox = QHBox(self) + hbox.setSpacing(KDialog.spacingHint()) + tmplabel = QLabel(hbox) + tmplabel.setPixmap(UserIcon("hi16-lock")) + hbox.setStretchFactor(tmplabel,0) + tmplabel = QLabel(hbox) + tmplabel.setText(i18n("Security & Safety")) + hbox.setStretchFactor(tmplabel,0) + sep = KSeparator(KSeparator.Horizontal,hbox) + hbox.setStretchFactor(sep,1) + grid.addMultiCellWidget(hbox,row,row,0,3) + row += 1 + + self.writeablecheckbox = QCheckBox(i18n("Writeable"),self) + grid.addMultiCellWidget(self.writeablecheckbox,row,row,1,3) + row += 1 + + label = QLabel(i18n("Files belong to user:"),self) + grid.addWidget(label,row,0) + self.uidcombobox = UserComboBox(self) + grid.addMultiCellWidget(self.uidcombobox,row,row,1,3) + row += 1 + + label = QLabel(i18n("Files belong to group:"),self) + grid.addWidget(label,row,0) + self.gidcombobox = GroupComboBox(self) + grid.addMultiCellWidget(self.gidcombobox,row,row,1,3) + row += 1 + + label = QLabel(i18n("Mount Permission:"),self) + grid.addWidget(label,row,0) + self.usermountcombobox = KComboBox(self) + self.usermountcombobox.insertItem(i18n("Root user only may enable/disable")) + self.usermountcombobox.insertItem(i18n("One user at a time may enable/disable")) + self.usermountcombobox.insertItem(i18n("Any user may enable/disable anytime")) + self.usermountcombobox.insertItem(i18n("Device owner may enable/disable")) + grid.addMultiCellWidget(self.usermountcombobox,row,row,1,3) + row += 1 + + self.suppresspermissionerrorcheckbox = QCheckBox(i18n("Suppress permission errors"),self) + grid.addMultiCellWidget(self.suppresspermissionerrorcheckbox,row,row,1,3) + row += 1 + + row += 1 + button = KPushButton(i18n("Advanced..."),self) + button.setSizePolicy(QSizePolicy.Fixed,QSizePolicy.Fixed) + self.connect(button,SIGNAL("clicked()"),self.slotAdvancedClicked) + grid.addMultiCellWidget(button,row,row,1,3,Qt.AlignRight) + + ######################################################################## + def displayMountEntry(self,entry): + global allowuuid, allowlabel + + uuid = entry.getUUID() + if entry.getDevice() == "" and uuid != "": + device = microhal.getDeviceByUUID(uuid) + self.devicelineedit.setText(uuid) + else: + self.devicelineedit.setText(entry.getDevice()) + + if allowuuid: + self.uuidlineedit.setText(uuid) + if entry.getUUID()!="": + self.uuidlineedit.setEnabled(True) + self.devicelineedit.setEnabled(False) + self.devicecheckbox.setChecked(False) + self.uuidcheckbox.setChecked(True) + else: + self.devicelineedit.setEnabled(True) + self.uuidlineedit.setEnabled(False) + self.devicecheckbox.setChecked(True) + self.uuidcheckbox.setChecked(False) + + if allowlabel: # If the filesystem has a label override the UUID settings + self.labellineedit.setText(entry.getLabel()) + if entry.getLabel()!="": + self.labellineedit.setEnabled(True) + self.devicelineedit.setEnabled(False) + self.devicecheckbox.setChecked(False) + self.labelcheckbox.setChecked(True) + self.uuidlineedit.setEnabled(False) + self.uuidcheckbox.setChecked(False) + else: + if entry.getUUID()!="": + self.uuidlineedit.setEnabled(True) + self.devicelineedit.setEnabled(False) + self.devicecheckbox.setChecked(False) + self.uuidcheckbox.setChecked(True) + else: + self.devicelineedit.setEnabled(True) + self.uuidlineedit.setEnabled(False) + self.devicecheckbox.setChecked(True) + self.uuidcheckbox.setChecked(False) + + if allowlabel: + self.labellineedit.setText(entry.getLabel()) + if allowuuid: + self.uuidlineedit.setText(entry.getUUID()) + self.devicelineedit.setText(entry.getDevice()) + + self.mountpointlineedit.setText(entry.getMountPoint()) + self.options = entry.getExtraOptions() + self.fsfreq = entry.getFSFreq() + self.fspassno = entry.getFSPassno() + self.writeablecheckbox.setChecked(entry.getWritable()) + self.autocheckbox.setChecked(entry.getMountAtBoot()) + self.usermountcombobox.setCurrentItem(entry.getAllowUserMount()) + self.uidcombobox.setUID(entry.getUID()) + self.gidcombobox.setGID(entry.getGID()) + self.suppresspermissionerrorcheckbox.setChecked(entry.getSuppressPermissionErrors()) + + ######################################################################## + def undisplayMountEntry(self,entry): + global allowuuid, allowlabel + if allowuuid: + if self.devicecheckbox.isChecked(): + entry.setUUID(None) + else: + if allowlabel: + if self.labelcheckbox.isChecked(): + entry.setLabel( unicode(self.labellineedit.text()) ) + else: + entry.setUUID( unicode(self.uuidlineedit.text()) ) + else: + entry.setUUID( unicode(self.uuidlineedit.text()) ) + + if allowlabel: + if self.devicecheckbox.isChecked(): + entry.setLabel(None) + else: + if allowuuid: + if self.uuidcheckbox.isChecked(): + entry.setUUID( unicode(self.uuidlineedit.text()) ) + else: + entry.setLabel( unicode(self.labellineedit.text()) ) + else: + entry.setLabel( unicode(self.labellineedit.text()) ) + + entry.setDevice( unicode(self.devicelineedit.text()) ) + + entry.setMountPoint( unicode(self.mountpointlineedit.text()) ) + entry.setExtraOptions(self.options) + entry.setFSFreq(self.fsfreq) + entry.setFSPassno(self.fspassno) + entry.setMountAtBoot(self.autocheckbox.isChecked()) + entry.setWritable(self.writeablecheckbox.isChecked()) + entry.setAllowUserMount(self.usermountcombobox.currentItem()) + entry.setUID(self.uidcombobox.UID()) + entry.setGID(self.gidcombobox.GID()) + entry.setSuppressPermissionErrors(self.suppresspermissionerrorcheckbox.isChecked()) + + ######################################################################## + def slotAdvancedClicked(self): + (self.options, self.fsfreq, self.fspassno)\ + = self.advanceddialog.do(self.options, self.fsfreq, self.fspassno) + + ######################################################################## + def slotDeviceCheckboxClicked(self): + self.uuidcheckbox.setChecked(False) + self.devicelineedit.setEnabled(True) + self.uuidlineedit.setEnabled(False) + + ######################################################################## + def slotUUIDCheckboxClicked(self): + if self.uuidlineedit.text() == "": + label = microhal.getUUIDByDevice(unicode(self.devicelineedit.text())) + self.uuidlineedit.setText(label) + self.devicecheckbox.setChecked(False) + self.devicelineedit.setEnabled(False) + self.uuidlineedit.setEnabled(True) + +############################################################################ +class MountEntryDialogOptionsSMB(MountEntryDialogOptions): + + ######################################################################## + def __init__(self,parent): + MountEntryDialogOptions.__init__(self,parent) + self.advanceddialog = MountEntryAdvancedPlainDialog(None) + self.updatinggui= False + + ######################################################################## + def _fillPage(self): + grid = QGridLayout(self,14,4) + grid.setSpacing(KDialog.spacingHint()) + grid.setColStretch(0,0) + grid.setColStretch(2,0) + grid.setRowStretch(12,1) + + label = QLabel(i18n("Mount Point:"),self) + grid.addWidget(label,0,0) + hbox = QHBox(self) + hbox.setSpacing(KDialog.spacingHint()) + self.mountpointlineedit = KLineEdit(hbox) + hbox.setStretchFactor(self.mountpointlineedit,1) + #self.connect(self.homediredit, SIGNAL("textChanged(const QString &)"), self.slotHomeDirChanged) + self.mountpointbutton = KPushButton(i18n("Browse..."),hbox) + hbox.setStretchFactor(self.mountpointbutton,0) + self.connect(self.mountpointbutton,SIGNAL("clicked()"),self.slotBrowseMountPointClicked) + grid.addMultiCellWidget(hbox,0,0,1,3) + + label = QLabel(i18n("Network Share:"),self) + grid.addWidget(label,1,0) + hbox = QHBox(self) + hbox.setSpacing(KDialog.spacingHint()) + self.devicelineedit = KLineEdit(hbox) + hbox.setStretchFactor(self.devicelineedit,1) + self.devicelinebutton = KPushButton(i18n("Scan..."),hbox) + hbox.setStretchFactor(self.devicelinebutton,0) + self.connect(self.devicelinebutton,SIGNAL("clicked()"),self.slotBrowseDeviceLineClicked) + grid.addMultiCellWidget(hbox,1,1,1,3) + + # Connect as: + connectaslabel = QLabel(self) + connectaslabel.setText(i18n("Connect as:")) + grid.addWidget(connectaslabel,2,0) + + self.guestradio = QRadioButton(self) + self.guestradio.setChecked(True) + grid.addWidget(self.guestradio,2,1) + tmplabel = QLabel(self) + tmplabel.setText(i18n("Guest")) + grid.addMultiCellWidget(tmplabel,2,2,2,3) + self.connect(self.guestradio,SIGNAL("stateChanged(int)"),self.slotGuestRadioClicked) + + self.userradio = QRadioButton(self) + grid.addWidget(self.userradio,3,1) + tmplabel = QLabel(self) + tmplabel.setText(i18n("Username:")) + grid.addWidget(tmplabel,3,2) + self.connect(self.userradio,SIGNAL("stateChanged(int)"),self.slotUserRadioClicked) + + self.usernameedit = KLineEdit(self) + grid.addWidget(self.usernameedit,3,3) + + tmplabel = QLabel(self) + tmplabel.setText(i18n("Password:")) + grid.addWidget(tmplabel,4,2) + + self.passwordedit = KLineEdit(self) + grid.addWidget(self.passwordedit,4,3) + + self.autocheckbox = QCheckBox(i18n("Enable at start up"),self) + grid.addMultiCellWidget(self.autocheckbox,5,5,1,3) + + # Security & Safety line. + hbox = QHBox(self) + hbox.setSpacing(KDialog.spacingHint()) + tmplabel = QLabel(hbox) + tmplabel.setPixmap(UserIcon("hi16-lock")) + hbox.setStretchFactor(tmplabel,0) + tmplabel = QLabel(hbox) + tmplabel.setText(i18n("Security & Safety")) + hbox.setStretchFactor(tmplabel,0) + sep = KSeparator(KSeparator.Horizontal,hbox) + hbox.setStretchFactor(sep,1) + grid.addMultiCellWidget(hbox,6,6,0,3) + + self.writeablecheckbox = QCheckBox(i18n("Writeable"),self) + grid.addMultiCellWidget(self.writeablecheckbox,7,7,1,3) + + label = QLabel(i18n("Files belong to user:"),self) + grid.addWidget(label,8,0) + self.uidcombobox = UserComboBox(self) + grid.addMultiCellWidget(self.uidcombobox,8,8,1,3) + + label = QLabel(i18n("Files belong to group:"),self) + grid.addWidget(label,9,0) + self.gidcombobox = GroupComboBox(self) + grid.addMultiCellWidget(self.gidcombobox,9,9,1,3) + + label = QLabel(i18n("Mount Permission:"),self) + grid.addWidget(label,10,0) + self.usermountcombobox = KComboBox(self) + self.usermountcombobox.insertItem(i18n("Root user only may enable/disable")) + self.usermountcombobox.insertItem(i18n("One user at a time may enable/disable")) + self.usermountcombobox.insertItem(i18n("Any user may enable/disable anytime")) + self.usermountcombobox.insertItem(i18n("Device owner may enable/disable")) + grid.addMultiCellWidget(self.usermountcombobox,10,10,1,3) + + button = KPushButton(i18n("Advanced..."),self) + button.setSizePolicy(QSizePolicy.Fixed,QSizePolicy.Fixed) + self.connect(button,SIGNAL("clicked()"),self.slotAdvancedClicked) + grid.addMultiCellWidget(button,13,13,1,3,Qt.AlignRight) + + self.selectsmbdialog = None + + ######################################################################## + def slotBrowseDeviceLineClicked(self): + if self.updatinggui: + return + self.updatinggui = True + + if self.selectsmbdialog is None: + self.selectsmbdialog = SMBShareSelectDialog(None) + + # This just converts a \\zootv\data\ share name to smb:/zootv/data + parts = [x.replace("/",'\\') for x in unicode(self.devicelineedit.text()).split('\\') if x!=""] + oldurl = u"smb:/"+("/".join(parts) ) + + urlobj = KURL(oldurl) + if self.userradio.isChecked(): + urlobj.setUser(self.usernameedit.text()) + urlobj.setPass(self.passwordedit.text()) + + newurlobj = self.selectsmbdialog.choose(urlobj) + # This just converts smb:/zootv/data to \\zootv\data. + plainurl = KURL(newurlobj) + plainurl.setUser(QString.null) + plainurl.setPass(QString.null) + parts = [x.replace('\\',"/") for x in unicode(plainurl.url())[4:].split("/") if x !=""] + #convert the first part to an IP address + nmboutput = subprocess.Popen(["nmblookup",parts[0]], stdout=subprocess.PIPE).stdout + nmboutput.readline() + ipaddress = nmboutput.readline().split(" ")[0] + parts[0] = ipaddress + self.devicelineedit.setText(r'\\'+('\\'.join(parts))) + + if not newurlobj.hasUser(): + self.guestradio.setChecked(True) + self.userradio.setChecked(False) + self.passwordedit.setEnabled(False) + self.usernameedit.setEnabled(False) + self.usernameedit.setText("") + self.passwordedit.setText("") + else: + self.guestradio.setChecked(False) + self.userradio.setChecked(True) + self.passwordedit.setEnabled(True) + self.usernameedit.setEnabled(True) + self.usernameedit.setText(newurlobj.user()) + self.passwordedit.setText(newurlobj.pass_()) + + self.updatinggui = False + + ######################################################################## + def displayMountEntry(self,entry): + self.devicelineedit.setText(entry.getDevice()) + self.mountpointlineedit.setText(entry.getMountPoint()) + self.options = entry.getExtraOptions() + self.fsfreq = entry.getFSFreq() + self.fspassno = entry.getFSPassno() + self.writeablecheckbox.setChecked(entry.getWritable()) + self.autocheckbox.setChecked(entry.getMountAtBoot()) + self.usermountcombobox.setCurrentItem(entry.getAllowUserMount()) + self.uidcombobox.setUID(entry.getUID()) + self.gidcombobox.setGID(entry.getGID()) + + if entry.getUsername() is None: + self.guestradio.setChecked(True) + self.userradio.setChecked(False) + self.passwordedit.setEnabled(False) + self.usernameedit.setEnabled(False) + self.usernameedit.setText("") + self.passwordedit.setText("") + else: + self.guestradio.setChecked(False) + self.userradio.setChecked(True) + self.passwordedit.setEnabled(True) + self.usernameedit.setEnabled(True) + self.usernameedit.setText(entry.getUsername()) + self.passwordedit.setText(entry.getPassword()) + + ######################################################################## + def undisplayMountEntry(self,entry): + entry.setDevice( unicode(self.devicelineedit.text()) ) + entry.setMountPoint( unicode(self.mountpointlineedit.text()) ) + entry.setExtraOptions(self.options) + entry.setFSFreq(self.fsfreq) + entry.setFSPassno(self.fspassno) + entry.setMountAtBoot(self.autocheckbox.isChecked()) + entry.setWritable(self.writeablecheckbox.isChecked()) + entry.setAllowUserMount(self.usermountcombobox.currentItem()) + entry.setUID(self.uidcombobox.UID()) + entry.setGID(self.gidcombobox.GID()) + + if self.guestradio.isChecked(): + entry.setUsername(None) + entry.setPassword(None) + else: + entry.setUsername( unicode(self.usernameedit.text()) ) + entry.setPassword( unicode(self.passwordedit.text()) ) + + ######################################################################## + def slotAdvancedClicked(self): + (self.options, self.fsfreq, self.fspassno)\ + = self.advanceddialog.do(self.options, self.fsfreq, self.fspassno) + + ######################################################################## + def slotGuestRadioClicked(self,state): + if self.updatinggui: + return + self.updatinggui = True + + if state==QButton.Off: + self.guestradio.setChecked(True) + self.userradio.setChecked(False) + + self.passwordedit.setEnabled(False) + self.usernameedit.setEnabled(False) + + self.updatinggui = False + + ######################################################################## + def slotUserRadioClicked(self,state): + if self.updatinggui: + return + self.updatinggui = True + if state==QButton.Off: + self.userradio.setChecked(True) + self.guestradio.setChecked(False) + + self.passwordedit.setEnabled(True) + self.usernameedit.setEnabled(True) + + self.updatinggui = False + +############################################################################ +class ROListBoxItem(QListBoxPixmap): + """A read-only ListBox item that also uses the 'alternate' background colour + as background. + """ + def __init__(self,listbox,pix,text): + QListBoxPixmap.__init__(self,listbox,pix,text) + self.setSelectable(False) + def paint(self,p): + boldfont = QFont(p.font()) + boldfont.setWeight(QFont.Bold) + p.setFont(boldfont) + p.setBackgroundColor(KGlobalSettings.alternateBackgroundColor()) + p.eraseRect(0,0,self.listBox().width(),self.height(self.listBox())) + QListBoxPixmap.paint(self,p) + +############################################################################ +class MountEntryDialog(KDialogBase): + + MountTypeEditorsDisk = { + 'ext2' : MountEntryDialogOptionsCommonUnix, + 'ext3' : MountEntryDialogOptionsCommonUnix, + 'reiserfs' : MountEntryDialogOptionsCommonUnix, + 'reiser4' : MountEntryDialogOptionsCommonUnix, + 'xfs' : MountEntryDialogOptionsCommonUnix, + 'jfs' : MountEntryDialogOptionsCommonUnix, + 'vfat' : MountEntryDialogOptionsVFAT, + 'ntfs' : MountEntryDialogOptionsVFAT, + 'hfsplus' : MountEntryDialogOptionsVFAT, + 'udf' : MountEntryDialogOptions, + 'iso9660' : MountEntryDialogOptions, + } + MountTypeEditorsNetwork = { + 'nfs' : MountEntryDialogOptionsNfs, + 'cifs' : MountEntryDialogOptionsSMB, + } + MountTypeEditorsSystem = { + 'proc' : MountEntryDialogOptionsSys, + 'sysfs' : MountEntryDialogOptionsSys, + 'rootfs' : MountEntryDialogOptions, + 'bdev' : MountEntryDialogOptions, + 'sockfs' : MountEntryDialogOptions, + 'tmpfs' : MountEntryDialogOptions, + 'shm' : MountEntryDialogOptions, + 'pipefs' : MountEntryDialogOptions, + 'ramfs' : MountEntryDialogOptionsSys, + 'devfs' : MountEntryDialogOptions, + 'devpts' : MountEntryDialogOptionsSys, + 'auto' : MountEntryDialogOptionsCommonUnix, + 'usbdevfs' : MountEntryDialogOptions, + 'procbususb' : MountEntryDialogOptions, + 'usbfs' : MountEntryDialogOptions, + 'supermount' : MountEntryDialogOptions, + 'swap' : MountEntryDialogOptionsSwap + } + + ######################################################################## + def __init__(self,parent): + KDialogBase.__init__(self,parent,None,True,"Configuration",KDialogBase.Ok|KDialogBase.Cancel, + KDialogBase.Cancel) + + self.updatingGUI = True + + # Maps MountEntry classes to MountEntryDialogOptions objects + self.mountTypeToOptionWidget = {} + + # Maps indexes in the combobox to mounttypes + self.comboIndexToMountType = [] + self.currentOptionWidget = None + + self.topvbox = QVBox(self) + self.setMainWidget(self.topvbox) + self.topvbox.setSpacing(self.spacingHint()) + + hb = QHBox(self.topvbox) + hb.setSpacing(self.spacingHint()) + self.topvbox.setStretchFactor(hb,0) + + label = QLabel(i18n("Type:"),hb) + hb.setStretchFactor(label,0) + self.mounttypecombo = KComboBox(hb) + + # Disk types + ROListBoxItem(self.mounttypecombo.listBox(),UserIcon("hi16-hdd"),i18n("Disk Filesystems")) + self.comboIndexToMountType.append(None) + items = self.MountTypeEditorsDisk.keys() + items.sort() + for mounttype in items: + self.mounttypecombo.insertItem(MountEntry.getMountTypeLongName(mounttype)) + self.comboIndexToMountType.append(mounttype) + + # Network types + ROListBoxItem(self.mounttypecombo.listBox(),UserIcon("hi16-network"),i18n("Network Filesystems")) + self.comboIndexToMountType.append(None) + items = self.MountTypeEditorsNetwork.keys() + items.sort() + for mounttype in items: + self.mounttypecombo.insertItem(MountEntry.getMountTypeLongName(mounttype)) + self.comboIndexToMountType.append(mounttype) + + # System types + ROListBoxItem(self.mounttypecombo.listBox(),UserIcon("hi16-blockdevice"),i18n("Operating System")) + self.comboIndexToMountType.append(None) + items = self.MountTypeEditorsSystem.keys() + items.sort() + for mounttype in items: + self.mounttypecombo.insertItem(MountEntry.getMountTypeLongName(mounttype)) + self.comboIndexToMountType.append(mounttype) + + self.MountTypeEditors = self.MountTypeEditorsDisk.copy() + self.MountTypeEditors.update(self.MountTypeEditorsNetwork) + self.MountTypeEditors.update(self.MountTypeEditorsSystem) + + #hb.setStretchFactor(self.runlevelcombo,0) + self.connect(self.mounttypecombo, SIGNAL("activated(int)"), self.slotMountTypeChanged) + + widget = QWidget(hb) + hb.setStretchFactor(widget,1) + + # Create the stack of option edit widgets. + gb = QVGroupBox(self.topvbox) + self.topvbox.setStretchFactor(gb,1) + self.optionsstack = QWidgetStack(gb) + + for mounttype in self.MountTypeEditors: + editpage = self.MountTypeEditors[mounttype](self.optionsstack) + self.mountTypeToOptionWidget[mounttype] = editpage + self.optionsstack.addWidget(editpage) + + self.fsunavailablelabel = QHBox(gb) + self.fsunavailablelabel.setSpacing(KDialog.spacingHint()) + tmplabel = QLabel(self.fsunavailablelabel) + self.fsunavailablelabel.setStretchFactor(tmplabel,0) + tmplabel.setPixmap(SmallIcon('info')) + label = QLabel(i18n("This filesystem type is currently unavailable on the running kernel."), + self.fsunavailablelabel) + self.fsunavailablelabel.setStretchFactor(label,1) + self.fsunavailablelabel.hide() + + self.updatingGUI = False + + ####################################################################### + def doEditMount(self,mounttable,mountentry): + self.newEntry = False + self.mounttable = mounttable + self.originalMountEntry = mountentry + self.currentMountEntry = mountentry.copy() + + self.updatingGUI = True + self.selectEntry(self.currentMountEntry.getMountType()) + self.updatingGUI = False + if self.exec_loop()==QDialog.Accepted: + # All of the update stuff is in slotOk() + return True + return False + + ####################################################################### + def doNewMount(self,mounttable,defaultdevice): + self.newEntry = True + self.mounttable = mounttable + self.currentMountEntry = MountEntry() + if defaultdevice is not None: + self.currentMountEntry.setDevice(defaultdevice) + self.updatingGUI = True + self.currentOptionWidget = None + self.selectEntry(self.currentMountEntry.mounttype) + self.updatingGUI = False + if self.exec_loop()==QDialog.Accepted: + self.mounttable.allentries.append(self.currentMountEntry) + self.mounttable.updateFstabOnDisk() + return self.currentMountEntry + return None + + ####################################################################### + def selectEntry(self,mounttype): + #if self.currentOptionWidget!=None: + # # Update the mount entry from the + # self.currentOptionWidget.undisplayMountEntry(self.currentMountEntry) + self.currentMountEntry.setMountType(mounttype) + # Update GUI + self.mounttypecombo.setCurrentItem(self.comboIndexToMountType.index(mounttype)) + self.currentOptionWidget = self.mountTypeToOptionWidget[mounttype] + self.currentOptionWidget.displayMountEntry(self.currentMountEntry) + self.optionsstack.raiseWidget(self.currentOptionWidget) + if microhal.isSupportedFileSystem(mounttype): + self.fsunavailablelabel.hide() + else: + self.fsunavailablelabel.show() + + ####################################################################### + def slotMountTypeChanged(self,index): + if self.updatingGUI==False: + self.updatingGUI = True + self.selectEntry(self.comboIndexToMountType[index]) + self.updatingGUI = False + + ####################################################################### + def slotOk(self): + global allowlabel, allowuuid + self.currentOptionWidget.undisplayMountEntry(self.currentMountEntry) + if allowuuid: + if self.currentOptionWidget.uuidcheckbox.isChecked(): + self.currentMountEntry.setUseAsDevice("uuid") + if allowlabel: + if self.currentOptionWidget.labelcheckbox.isChecked(): + self.currentMountEntry.setUseAsDevice("label") + conflictentry = None + if self.newEntry: + for entry in self.mounttable: + if entry.getMountPoint()==self.currentMountEntry.getMountPoint(): + # Conflict found. + conflictentry = entry + else: + # Check if the mountpoint is already in use elsewhere in the mounttable. + if self.originalMountEntry.getMountPoint()!=self.currentMountEntry.getMountPoint(): + for entry in self.mounttable: + if (entry.getMountPoint()==self.currentMountEntry.getMountPoint() + and entry is not self.originalMountEntry): + # Conflict found. + conflictentry = entry + if conflictentry is not None: + if KMessageBox.warningContinueCancel(self, \ + i18n("The mountpoint '%1' is already in use by another entry?\nContinue?").arg( + self.currentMountEntry.getMountPoint()), \ + i18n("Mountpoint already in use"))!=KMessageBox.Continue: + return + + if self.currentMountEntry.getMountType() in MountEntryDialog.MountTypeEditorsDisk.keys(): + # If device is not in /dev and it's no bind mount, ask if that's meant this way ... + options = self.currentMountEntry.getFstabOptions() + if (not self.currentMountEntry.getDevice().startswith("/dev/") + and not ("loop" in options or "bind" in options)): + ask = KMessageBox.warningYesNoCancel(self, + i18n("'%1' does not seem to be a device and the option 'bind' has not been specified in the \ + \"Advanced\" page?\n Should I add the 'loop' option?").arg(self.currentMountEntry.device), + i18n("Options may be missing")) + if ask==KMessageBox.Cancel: + return + elif ask==KMessageBox.Yes: + # Add loop option + extraoptions = self.currentMountEntry.getExtraOptions().split(',') + extraoptions.append('loop') + self.currentMountEntry.setExtraOptions(','.join(extraoptions)) + + if (not os.path.isdir(self.currentMountEntry.getMountPoint()) + and not os.path.isfile(self.currentMountEntry.getMountPoint()) + and not self.currentMountEntry.mounttype == 'swap'): + ask = KMessageBox.warningYesNoCancel(self, + i18n("""The mountpoint '%1' does not exist. You will not be able to enable it until it is created.\ + \nShould I create the mountpoint?""").arg(self.currentMountEntry.getMountPoint()), + i18n("Mountpoint does not exist")) + if ask==KMessageBox.Cancel: + return + elif ask==KMessageBox.Yes: + os.mkdir(self.currentMountEntry.getMountPoint()) + elif os.path.isfile(self.currentMountEntry.getMountPoint()): + if KMessageBox.warningContinueCancel(self, + i18n("""The mountpoint '%1' is a file, but it has to be a directory. You will probably not \ + be able to enable it.\nContinue?""").arg(self.currentMountEntry.getMountPoint()), + i18n("Invalid mountpoint"))!=KMessageBox.Continue: + return + + if self.newEntry==False: + # How to Change a Mount Entry. + # 1. Disable the exisiting entry (if needed) + # 2. Update existing entry from the mount table. + # 3. Enable the updated entry (if needed) + # 4. Write new fstab file. + # 5. Enable the new entry (if needed) + + # 1. Disable the exisiting entry (if needed) + enabled = self.originalMountEntry.isEnabled() + if enabled: + self.disablingold = True + self.originalMountEntry.disable(self) + self.originalMountEntry.inPlaceCopyFrom(self.currentMountEntry) + self.mounttable.updateFstabOnDisk() + if enabled and self.originalMountEntry.isFileSystemAvailable(): + self.originalMountEntry.enable(self) + self.accept() + +############################################################################ +class MountEntryAdvancedCommonUnixDialog(KDialogBase): + ######################################################################## + def __init__(self,parent,name=None): + KDialogBase.__init__(self,parent,name,1,"",KDialogBase.Ok|KDialogBase.Cancel) + + grid = self.makeGridMainWidget(2,Qt.Horizontal) + grid.setSpacing(self.spacingHint()) + + QWidget(grid) + self.accesstimecheckbox = QCheckBox(i18n("Update file access timestamps"),grid) + + QWidget(grid) + self.allowexecutablecheckbox = QCheckBox(i18n("Allow Executables"),grid) + + QWidget(grid) + self.allowsuidcheckbox = QCheckBox(i18n("Allow the SUID and SGID attributes"),grid) + + QWidget(grid) + self.usedevpointscheckbox = QCheckBox(i18n("Allow device points"),grid) + + label = QLabel(i18n("Options:"),grid) + self.optionslineedit = KLineEdit(grid) + + label = QLabel(i18n("fs_freq:"),grid) + self.fsfreqspinbox = KIntSpinBox (0,1000,1,0,10,grid) + + label = QLabel(i18n("fs_passno:"),grid) + self.fspassnospinbox = KIntSpinBox (0,1000,1,0,10,grid) + + ######################################################################## + def do(self,atime,allowexecutable,allowsuid,usedevpoints,options,fsfreq,fspassno): + + self.accesstimecheckbox.setChecked(atime) + self.allowexecutablecheckbox.setChecked(allowexecutable) + self.allowsuidcheckbox.setChecked(allowsuid) + self.usedevpointscheckbox.setChecked(usedevpoints) + self.optionslineedit.setText(options) + self.fsfreqspinbox.setValue(fsfreq) + self.fspassnospinbox.setValue(fspassno) + self.exec_loop() + return ( self.accesstimecheckbox.isChecked(), + self.allowexecutablecheckbox.isChecked(), + self.allowsuidcheckbox.isChecked(), + self.usedevpointscheckbox.isChecked(), + unicode(self.optionslineedit.text()), + self.fsfreqspinbox.value(), + self.fspassnospinbox.value()) + +############################################################################ +class MountEntryAdvancedPlainDialog(KDialogBase): + ######################################################################## + def __init__(self,parent,name=None): + KDialogBase.__init__(self,parent,name,1,"",KDialogBase.Ok|KDialogBase.Cancel) + + grid = self.makeGridMainWidget(2,Qt.Horizontal) + grid.setSpacing(self.spacingHint()) + + label = QLabel(i18n("Options:"),grid) + self.optionslineedit = KLineEdit(grid) + + label = QLabel(i18n("fs_freq:"),grid) + self.fsfreqspinbox = KIntSpinBox (0,1000,1,0,10,grid) + + label = QLabel(i18n("fs_passno:"),grid) + self.fspassnospinbox = KIntSpinBox (0,1000,1,0,10,grid) + + ######################################################################## + def do(self,options,fsfreq,fspassno): + self.optionslineedit.setText(options) + self.fsfreqspinbox.setValue(fsfreq) + self.fspassnospinbox.setValue(fspassno) + self.exec_loop() + return (unicode(self.optionslineedit.text()), self.fsfreqspinbox.value(), self.fspassnospinbox.value()) + +############################################################################ +class MountListViewItem(KListViewItem): + ######################################################################## + def __init__(self,parentitem,mountentry,haldevice=None): + self.haldevice = haldevice + self.mountentry = mountentry + if self.mountentry is None: + # There is no mount entry right now. This acts as a place holder + # for now. + KListViewItem.__init__(self,parentitem,self.haldevice.getName(),"","",self.haldevice.getDev(),"") + else: + if mountentry.isEnabled(): + enabled = i18n("Enabled") + else: + enabled = i18n("Disabled") + if self.haldevice is not None: + name = self.haldevice.getName() + else: + name = self.mountentry.getName() + KListViewItem.__init__(self, parentitem, \ + name, + self.mountentry.getMountPoint(), \ + self.mountentry.mounttype, \ + self.mountentry.getDevice(), \ + enabled) + + if self.mountentry.isEnabled(): + self.setPixmap(4,UserIcon("greenled")) + else: + self.setPixmap(4,UserIcon("greyled")) + self.__updateIcon() + + ######################################################################## + def hasHAL(self): + return self.haldevice is not None + + ######################################################################## + def getHAL(self): return self.haldevice + + ######################################################################## + def updateDisplay(self): + if self.mountentry is not None: + if self.mountentry.isEnabled(): + enabled = i18n("Enabled") + self.setPixmap(4,UserIcon("greenled")) + else: + enabled = i18n("Disabled") + self.setPixmap(4,UserIcon("greyled")) + + if self.haldevice is not None: + self.setText(0,self.haldevice.getName()) + else: + self.setText(0,self.mountentry.getMountPoint()) + + self.setText(1,self.mountentry.getMountPoint()) + self.setText(2,self.mountentry.mounttype) + + if self.mountentry.getDevice() is not None: + self.setText(3,self.mountentry.getDevice()) + else: + uuid_device = microhal.getDeviceByUUID(self.mountentry.getUUID()) + label_device = microhal.getDeviceByUUID(self.mountentry.getUUID()) + if label_device is not None: + self.setText(3,label_device.getDev()+" (Label)") + elif real_device is not None: + self.setText(3,real_device.getDev()+" (UUID)") + else: + self.setText(3,"UUID="+self.mountentry.getUUID()) + + self.setText(4,enabled) + else: + self.setText(0,self.haldevice.getName()) + self.setText(1,"") + self.setText(2,"") + self.setText(3,self.haldevice.getDev()) + self.setText(4,"") + self.setPixmap(4,QPixmap()) + self.__updateIcon() + + ######################################################################## + def setMountEntry(self,entry): + self.mountentry = entry + self.updateDisplay() + + ######################################################################## + def getMountEntry(self): + return self.mountentry + + ######################################################################## + def getDevice(self): return self.haldevice.getDev() + + ######################################################################## + + def __updateIcon(self): + if self.haldevice is not None: + self.setPixmap(0,UserIcon(self.haldevice.iconname)) + else: + self.setPixmap(0,UserIcon(self.mountentry.getIconName())) + +############################################################################ +class MountGroupListViewItem(KListViewItem): + ######################################################################## + def __init__(self,parentitem,haldevice): + self.haldevice = haldevice + KListViewItem.__init__(self,parentitem,self.haldevice.getName(),"","","","") + + if self.haldevice is not None: + iconname = self.haldevice.iconname + else: + iconname = self.mountentry.getIconName() + self.setPixmap(0,UserIcon(iconname)) + + ######################################################################## + def getMountEntry(self): + return None + + ######################################################################## + def updateDisplay(self): + pass + + def hasHAL(self): + return False + +############################################################################ +# Try translating this code to C++. I dare ya! +if standalone: + programbase = KDialogBase +else: + programbase = KCModule + +class MountConfigApp(programbase): + ######################################################################## + def __init__(self,parent=None,name=None): + global standalone,isroot + KGlobal.locale().insertCatalogue("guidance") + + if standalone: + KDialogBase.__init__(self,KJanusWidget.Plain,i18n("Disk & Filesystems"), + KDialogBase.User1|KDialogBase.Close, KDialogBase.Close) + self.setButtonText(KDialogBase.User1,i18n("About")) + topwidget = self.plainPage() + else: + KCModule.__init__(self,parent,name) + self.setButtons(0) + self.aboutdata = MakeAboutData() + topwidget = self + + # Create a configuration object. + self.config = KConfig("mountconfigrc") + + KGlobal.iconLoader().addAppDir("guidance") + self.updatingGUI = False + self.mounttable = MountTable('/etc/fstab','/etc/mtab') + self.selectedentry = None + self.aboutus = KAboutApplication(self) + self.sizeviewdialogs = {} + toplayout = QVBoxLayout(topwidget, 0, KDialog.spacingHint()) + #topwidget.setEnabled(isroot) + + hb = QHBox(topwidget) + hb.setSpacing(KDialog.spacingHint()) + #if standalone: + # hb.setMargin(KDialog.marginHint()) + + toplayout.addWidget(hb) + + label = QLabel(hb) + label.setPixmap(UserIcon("kcmpartitions")) + hb.setStretchFactor(label,0) + + label = QLabel(i18n("Available Disks and Filesystems:"),hb) + hb.setStretchFactor(label,1) + + self.mountlist = KListView(topwidget,"Mount list") + toplayout.addWidget(self.mountlist) + self.mountlist.addColumn(i18n("Name")) + self.mountlist.addColumn(i18n("Mount Point")) + self.mountlist.addColumn(i18n("Type")) + self.mountlist.addColumn(i18n("Device")) + self.mountlist.addColumn(i18n("Enabled")) + self.mountlist.setAllColumnsShowFocus(True) + self.mountlist.setSelectionMode(QListView.Single) + self.mountlist.setRootIsDecorated(True) + self.mountlist.setSorting(-1) + self.connect(self.mountlist, SIGNAL("selectionChanged(QListViewItem *)"), self.slotListClicked) + # Doubleclick in item opens modify dialogue. + self.connect(self.mountlist, SIGNAL("doubleClicked(QListViewItem *)"), self.slotModifyClicked) + # Rightclick: Open ContextMenu + self.connect(self.mountlist, SIGNAL("contextMenu(KListView*,QListViewItem*,const QPoint&)"), + self.slotContextMenu) + + hbox = QHBox(topwidget) + toplayout.addWidget(hbox) + hbox.setSpacing(KDialog.spacingHint()) + + toplayout.setStretchFactor(hbox,0) + self.newbutton = KPushButton(i18n("New..."),hbox) + hbox.setStretchFactor(self.newbutton,1) + self.connect(self.newbutton,SIGNAL("clicked()"),self.slotNewClicked) + self.newbutton.setEnabled(isroot) + + self.modifybutton = KPushButton(i18n("Modify..."),hbox) + hbox.setStretchFactor(self.modifybutton,1) + self.connect(self.modifybutton,SIGNAL("clicked()"),self.slotModifyClicked) + + self.deletebutton = KPushButton(i18n("Delete..."),hbox) + hbox.setStretchFactor(self.deletebutton,1) + self.connect(self.deletebutton,SIGNAL("clicked()"),self.slotDeleteClicked) + + self.enablebutton = KPushButton(i18n("Enable"),hbox) + hbox.setStretchFactor(self.enablebutton,1) + self.connect(self.enablebutton,SIGNAL("clicked()"),self.slotEnableClicked) + + self.disablebutton = KPushButton(i18n("Disable"),hbox) + hbox.setStretchFactor(self.disablebutton,1) + self.connect(self.disablebutton,SIGNAL("clicked()"),self.slotDisableClicked) + + self.detailsbutton = KPushButton(i18n("Details..."),hbox) + hbox.setStretchFactor(self.detailsbutton,1) + self.connect(self.detailsbutton,SIGNAL("clicked()"),self.slotDetailsClicked) + + self.devstolistitems = None + self.uuidstolistitems = None + self.mountentriestolistitems = None + self.__updateMountList() + self.__selectEntry(self.mounttable[0]) + + self.configuredialog = MountEntryDialog(None) + + ######################################################################## + def exec_loop(self): + global programbase + self.__loadOptions() + programbase.exec_loop(self) + self.__saveOptions() + + ######################################################################## + def slotContextMenu(self,lv,lv_item,p): + + hal_device = lv_item.haldevice + if hal_device is not None and not isinstance(hal_device,MicroHAL.FakeSystemDevice): + + self.cmenu = KPopupMenu(self,"MyActions") + if isinstance(hal_device,MicroHAL.RemovableDisk) or isinstance(lv_item,MountListViewItem): + self.cmenu.insertItem(i18n("Modify..."), self.slotModifyClicked, 0, 0) + self.cmenu.insertItem(i18n("Delete..."), self.slotDeleteClicked, 0, 1) + if not isroot: + self.cmenu.setItemEnabled(0,False) + self.cmenu.setItemEnabled(1,False) + elif isinstance(hal_device,MicroHAL.Disk) or isinstance(hal_device,MicroHAL.USBDisk): + self.cmenu.insertItem(i18n("Show details..."), self.slotDetailsClicked, 0, 0) + self.cmenu.insertItem(i18n("New..."), self.slotNewClicked, 0, 1) + if not isroot: + self.cmenu.setItemEnabled(1,False) + + self.cmenu.exec_loop(p) + + ######################################################################## + def slotUser1(self): + self.aboutus.show() + + ######################################################################## + def slotEnableClicked(self): + if self.selectedentry!=None: + self.selectedentry.enable(self) + self.mounttable.updateStatus(self.selectedentry) + self.__updateEntry(self.selectedentry) + self.enablebutton.setEnabled(not self.selectedentry.isEnabled()) + self.disablebutton.setEnabled(self.selectedentry.isEnabled()) + + ######################################################################## + def slotDisableClicked(self): + if self.selectedentry!=None: + self.__disableEntry() + + ######################################################################## + def slotModifyClicked(self): + global isroot + if not isroot: + return + + if self.selectedentry!=None: + self.configuredialog.doEditMount(self.mounttable,self.selectedentry) + + lvi = self.mountentriestolistitems[self.selectedentry] + if lvi.hasHAL(): + if lvi.getHAL().getDev()!=self.selectedentry.getDevice(): + # The (device-)item in the listview no longer matches this mount entry. + del self.mountentriestolistitems[self.selectedentry] + lvi.setMountEntry(None) + lvi.updateDisplay() + # Reinsert this mount entry into the list view. + self.__insertMountEntryIntoListView(self.selectedentry) + + elif self.selectedentry.getDevice() is not None \ + and self.selectedentry.getDevice() in self.devstolistitems: + # The mount entry can now merged with any existing (HAL-)item. + # Remove the existing lose item. + self.mountlist.takeItem(lvi) + del self.mountentriestolistitems[self.selectedentry] + del self.devstolistitems[self.selectedentry.getDevice()] + del lvi + # Reinsert this mount entry into the list view. + self.__insertMountEntryIntoListView(self.selectedentry) + + elif self.selectedentry.getUUID() is not None \ + and self.selectedentry.getUUID() in self.uuidstolistitems: + # The mount entry can now merged with any existing (HAL-)item. + # Remove the existing lose item. + self.mountlist.takeItem(lvi) + del self.mountentriestolistitems[self.selectedentry] + del self.uuidstolistitems[self.selectedentry.getUUID()] + del lvi + # Reinsert this mount entry into the list view. + self.__insertMountEntryIntoListView(self.selectedentry) + + self.__updateEntry(self.selectedentry) + self.__selectEntry(self.selectedentry) + else: + self.slotNewClicked() + + ######################################################################## + def slotNewClicked(self): + defaultdevice = None + if self.selectedentry is None: + lvi = self.mountlist.selectedItem() + if lvi is not None and lvi.hasHAL() and (lvi.getMountEntry() is None): + defaultdevice = lvi.getDevice() + newentry = self.configuredialog.doNewMount(self.mounttable,defaultdevice) + if newentry!=None: + self.updatingGUI = True + self.__insertMountEntryIntoListView(newentry) + self.__selectEntry(newentry) + self.updatingGUI = False + + ######################################################################## + def slotDeleteClicked(self): + if self.selectedentry!=None: + if self.selectedentry.isEnabled(): + if not self.__disableEntry(): + return # If we couldn't disable it, then we can't continue. + message = i18n("Are you sure you want to delete mount '%1' of type %2 at '%3'?\n " + + "(This will only remove the mount, no data will be deleted.)") \ + .arg(self.selectedentry.getMountPoint()).arg(self.selectedentry.mounttype).arg( + self.selectedentry.getDevice()) + if KMessageBox.warningYesNo(self,message,i18n("Delete Mount?"))==KMessageBox.Yes: + lvi = self.mountentriestolistitems[self.selectedentry] + if not lvi.hasHAL(): + self.mountlist.takeItem(lvi) + del lvi + del self.mountentriestolistitems[self.selectedentry] + else: + lvi.setMountEntry(None) + self.mounttable.remove(self.selectedentry) + self.mounttable.updateFstabOnDisk() + self.__selectEntry(None) + + ######################################################################## + def slotDetailsClicked(self): + # Popup a dialog showing disklayout and a graphical represenation of 'df' + hal_device = self.mountlist.selectedItem().haldevice + if isinstance(hal_device,MicroHAL.Disk): + blk = hal_device.getDev() + devicepath, devicename = ('/'.join(blk.split('/')[0:-1])+'/', blk.split('/')[-1]) + # We keep a dict with those widgets, that saves us some time reading out all the values. + if devicename not in self.sizeviewdialogs.keys(): + self.sizeviewdialogs[devicename] = sizeview.SizeView(self,devicename,devicepath) + self.sizeviewdialogs[devicename].exec_loop() + else: + self.sizeviewdialogs[devicename].exec_loop() + else: + print "Sizeview doesn't support",blk.__class__," yet." + + ######################################################################## + def slotListClicked(self,item): + if self.updatingGUI==False: + self.__selectEntry(item.getMountEntry()) + + ######################################################################## + def __disableEntry(self): + self.selectedentry.disable(self) + self.mounttable.updateStatus(self.selectedentry) + self.__updateEntry(self.selectedentry) + self.enablebutton.setEnabled(not self.selectedentry.isEnabled() and self.selectedentry.isFileSystemAvailable()) + self.disablebutton.setEnabled(self.selectedentry.isEnabled()) + return not self.selectedentry.isEnabled() + + ######################################################################## + def __updateEntry(self,selectedentry): + # Update the display. + lvi = self.mountentriestolistitems[selectedentry] + lvi.updateDisplay() + + ######################################################################## + def __loadOptions(self): + self.config.setGroup("General") + size = self.config.readSizeEntry("Geometry") + if size.isEmpty()==False: + self.resize(size) + + ####################################################################### + def __saveOptions(self): + global isroot + if isroot: + return + self.config.setGroup("General") + self.config.writeEntry("Geometry", self.size()) + self.config.sync() + + ######################################################################## + def __updateMountList(self): + self.mountentriestolistitems = {} + + self.mountlist.clear() + + self.listgroups = {} + self.devstolistitems = {} + self.uuidstolistitems = {} + + lasttopitem = None + + # Find out which disks are installed and should be shown in the + # listview. For real disks we put a 'group' in the listview and + # under the group we list the partitions, whether they are + # mounted or not. + for blockdevice in microhal.getDevices(): + # We are looking for block devices that represent hard disks or + # things that have partitions and are not removable + if (blockdevice.major in microhal.partitionblockdevs and not blockdevice.removable) \ + or isinstance(blockdevice,MicroHAL.USBDisk): + + # We have a not removable block device. + # We want to create a listitem for the device and subitems + # for each partition. + groupitem = MountGroupListViewItem(self.mountlist,blockdevice) + groupitem.setOpen(True) + lasttopitem = groupitem + lvi = None + for partition in blockdevice.getPartitions(): + # Try to find a matching mount entry for this partition. + lastlvi = lvi + lvi = MountListViewItem(groupitem,None,partition) + + if partition.getUUID() is not None: + self.uuidstolistitems[partition.getUUID()] = lvi + if partition.getDev() is not None: + self.devstolistitems[partition.getDev()] = lvi + + if lastlvi is not None: + lvi.moveItem(lastlvi) + elif blockdevice.getMajor() in microhal.cdromsdevs or blockdevice.isRemovable(): + # Removable block device, assume CDROM (even if it's a partitionblockdevice) + lvi = MountListViewItem(self.mountlist,None,blockdevice) + if blockdevice.getUUID() is not None: + self.uuidstolistitems[blockdevice.getUUID()] = lvi + if blockdevice.getDev() is not None: + self.devstolistitems[blockdevice.getDev()] = lvi + lasttopitem = lvi + + + systemdevice = MicroHAL.FakeSystemDevice() + systemdevice.iconname = systemdevice.getIconName() + groupitem = MountGroupListViewItem(self.mountlist,systemdevice) + + if lasttopitem is not None: + groupitem.moveItem(lasttopitem) + lasttopitem = groupitem + + self.listgroups["system"] = groupitem + + self.mountentriestolistitems = {} + for entry in self.mounttable: + self.__insertMountEntryIntoListView(entry) + + ######################################################################## + def __insertMountEntryIntoListView(self,mountentry): + if mountentry.getDevice() in self.devstolistitems: + lvi = self.devstolistitems[mountentry.getDevice()] + lvi.setMountEntry(mountentry) + elif mountentry.getUUID() in self.uuidstolistitems: + lvi = self.uuidstolistitems[mountentry.getUUID()] + lvi.setMountEntry(mountentry) + else: + cat = mountentry.getCategory() # Place it under a special node? + if cat not in self.listgroups: + lvi = MountListViewItem(self.mountlist,mountentry) + item = self.mountlist.firstChild() + else: + lvi = MountListViewItem(self.listgroups[cat],mountentry) + item = self.listgroups[cat].firstChild() + + # Move the item to the end of this (sub-list). + while item.nextSibling() is not None: + item = item.nextSibling() + lvi.moveItem(item) + + self.mountentriestolistitems[mountentry] = lvi + + ######################################################################## + def __selectEntry(self,mountentry): + if mountentry is not None and isroot: + lvi = self.mountentriestolistitems[mountentry] + self.mountlist.setSelected(lvi,True) + self.enablebutton.setEnabled(not mountentry.isEnabled() and mountentry.isFileSystemAvailable()) + self.selectedentry = mountentry + # disable unsupported stuff, such as SystemEntries that canot be disabled and modified + if not mountentry.maydisable: + disable = False + else: + disable = mountentry.isEnabled() + if mountentry.notInFstab: + delete = False + modify = False + else: + delete = True + modify = True + + self.disablebutton.setEnabled(disable) + self.deletebutton.setEnabled(delete) + self.modifybutton.setEnabled(modify) + + else: + self.enablebutton.setEnabled(False) + self.disablebutton.setEnabled(False) + self.deletebutton.setEnabled(False) + self.modifybutton.setEnabled(False) + self.detailsbutton.setEnabled(False) + self.selectedentry = None + selected_item = self.mountlist.selectedItem() + if selected_item is not None: + self.detailsbutton.setEnabled(isinstance(selected_item.haldevice,MicroHAL.Disk) \ + and not isinstance(selected_item.haldevice,MicroHAL.RemovableDisk)) + else: + self.detailsbutton.setEnabled(False) + + ####################################################################### + # KControl virtual void methods + def load(self): + pass + def save(self): + pass + def defaults(self): + pass + def sysdefaults(self): + pass + + def aboutData(self): + # Return the KAboutData object which we created during initialisation. + return self.aboutdata + def buttons(self): + # Only supply a Help button. Other choices are Default and Apply. + return KCModule.Help + +############################################################################ +# Factory function for KControl +def create_mountconfig(parent,name): + global kapp, microhal + microhal = MicroHAL.MicroHAL() + kapp = KApplication.kApplication() + return MountConfigApp(parent, name) + +############################################################################ +def MakeAboutData(): + aboutdata = KAboutData("mountconfig",programname,version,"Disk & Filesystem Configuration Tool", + KAboutData.License_GPL, "Copyright (C) 2003-2007 Simon Edwards") + aboutdata.addAuthor("Simon Edwards","Developer","simon@simonzone.com", + "http://www.simonzone.com/software/guidance") + aboutdata.addAuthor("Sebastian Kügler","Developer","sebas@kde.org","http://vizZzion.org"); + return aboutdata + +if standalone: + aboutdata = MakeAboutData() + KCmdLineArgs.init(sys.argv,aboutdata) + + microhal = MicroHAL.MicroHAL() + kapp = KApplication() + sysvapp = MountConfigApp() + sysvapp.exec_loop() -- cgit v1.2.1