#!/usr/bin/python3 # -*- coding: UTF-8 -*- ########################################################################### # userconfig.py - description # # ------------------------------ # # begin : Wed Apr 30 2003 # # copyright : (C) 2003-2006 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. # # # ########################################################################### import sys import os.path from PyTQt.tqt import * from tdeui import * from tdecore import * from tdefile import * import shutil import unixauthdb import locale programname = "userconfig" 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 #isroot = True ########################################################################### def SptimeToQDate(sptime): t = TQDateTime() t.setTime_t(0) return t.addDays(sptime).date() ########################################################################### def TQDateToSptime(tqdate): x = TQDateTime() x.setTime_t(0) return x.daysTo(TQDateTime(tqdate)) ########################################################################### # Try translating this code to C++. I dare ya! if standalone: programbase = KDialogBase else: programbase = TDECModule class UserConfigApp(programbase): def __init__(self,parent=None,name=None): global standalone,isroot TDEGlobal.locale().insertCatalogue("guidance") if standalone: KDialogBase.__init__(self,KJanusWidget.Tabbed,i18n("User Accounts and Groups"), KDialogBase.User1|KDialogBase.Close, KDialogBase.Close) self.setButtonText(KDialogBase.User1,i18n("About")) else: TDECModule.__init__(self,parent,name) self.setButtons(0) self.aboutdata = MakeAboutData() toplayout = TQVBoxLayout( self, 0, KDialog.spacingHint() ) tabcontrol = TQTabWidget(self) toplayout.addWidget(tabcontrol) toplayout.setStretchFactor(tabcontrol,1) # Create a configuration object. self.config = TDEConfig("userconfigrc") TDEGlobal.iconLoader().addAppDir("guidance") self.usersToListItems = None self.selecteduserid = None self.selectedgroupid = None self.showsystemaccounts = False self.showsystemgroups = False self.updatingGUI = True self.aboutus = TDEAboutApplication(self) # --- User Tab --- if standalone: usershbox = self.addHBoxPage("Users") vbox = TQVBox(usershbox) else: vbox = TQVBox(tabcontrol) vbox.setMargin(KDialog.marginHint()) vbox.setSpacing(KDialog.spacingHint()) hb = TQHBox(vbox) hb.setSpacing(KDialog.spacingHint()) vbox.setStretchFactor(hb,0) label = TQLabel(hb) label.setPixmap(UserIcon("hi32-user")) hb.setStretchFactor(label,0) label = TQLabel(i18n("User Accounts:"),hb) hb.setStretchFactor(label,1) self.userlist = TDEListView(vbox) self.userlist.addColumn(i18n("Login Name")) self.userlist.addColumn(i18n("Real Name")) self.userlist.addColumn(i18n("UID")) self.userlist.setAllColumnsShowFocus(True) self.userlist.setSelectionMode(TQListView.Single) self.connect(self.userlist, TQ_SIGNAL("selectionChanged(TQListViewItem *)"), self.slotListClicked) if isroot: self.connect(self.userlist, TQ_SIGNAL("doubleClicked(TQListViewItem *)"), self.slotModifyClicked) self.connect(self.userlist, TQ_SIGNAL("contextMenu(TDEListView*,TQListViewItem*,const TQPoint&)"), self.slotUserContext) self.showspecialcheckbox = TQCheckBox(i18n("Show system accounts"),vbox) vbox.setStretchFactor(self.showspecialcheckbox,0) self.connect(self.showspecialcheckbox,TQ_SIGNAL("toggled(bool)"), self.slotShowSystemToggled) hbox = TQHBox(vbox) hbox.setSpacing(KDialog.spacingHint()) vbox.setStretchFactor(hbox,0) self.modifybutton = KPushButton(i18n("Modify..."),hbox) hbox.setStretchFactor(self.modifybutton,1) self.connect(self.modifybutton,TQ_SIGNAL("clicked()"),self.slotModifyClicked) self.newbutton = KPushButton(i18n("New..."),hbox) hbox.setStretchFactor(self.newbutton,1) self.connect(self.newbutton,TQ_SIGNAL("clicked()"),self.slotNewClicked) self.deletebutton = KPushButton(i18n("Delete..."),hbox) hbox.setStretchFactor(self.deletebutton,1) self.connect(self.deletebutton,TQ_SIGNAL("clicked()"),self.slotDeleteClicked) detailsbox = TQVGroupBox(i18n("Details"),vbox) userinfovbox = TQWidget(detailsbox) infogrid = TQGridLayout(userinfovbox,3,4) infogrid.setSpacing(KDialog.spacingHint()) label = TQLabel(i18n("Login Name:"),userinfovbox) infogrid.addWidget(label,0,0) self.loginnamelabel = KLineEdit("",userinfovbox) self.loginnamelabel.setReadOnly(True) infogrid.addWidget(self.loginnamelabel,0,1) label = TQLabel(i18n("Real Name:"),userinfovbox) infogrid.addWidget(label,0,2) self.realnamelabel = KLineEdit("",userinfovbox) self.realnamelabel.setReadOnly(True) infogrid.addWidget(self.realnamelabel,0,3) label = TQLabel(i18n("UID:"),userinfovbox) infogrid.addWidget(label,1,0) self.uidlabel = KLineEdit("",userinfovbox) self.uidlabel.setReadOnly(True) infogrid.addWidget(self.uidlabel,1,1) label = TQLabel(i18n("Status:"),userinfovbox) infogrid.addWidget(label,1,2) self.statuslabel = KLineEdit("",userinfovbox) self.statuslabel.setReadOnly(True) infogrid.addWidget(self.statuslabel,1,3) label = TQLabel(i18n("Primary Group:"),userinfovbox) infogrid.addWidget(label,2,0) self.primarygrouplabel = KLineEdit("",userinfovbox) self.primarygrouplabel.setReadOnly(True) infogrid.addWidget(self.primarygrouplabel,2,1) label = TQLabel(i18n("Secondary Groups:"),userinfovbox) infogrid.addWidget(label,2,2) self.secondarygrouplabel = KLineEdit("",userinfovbox) self.secondarygrouplabel.setReadOnly(True) infogrid.addWidget(self.secondarygrouplabel,2,3) if not standalone: tabcontrol.addTab(vbox,i18n("Users")) #--- Groups Tab --- if standalone: groupsvbox = self.addVBoxPage(i18n("Groups")) hb = TQHBox(groupsvbox) else: groupsvbox = TQVBox(tabcontrol) groupsvbox.setMargin(KDialog.marginHint()) hb = TQHBox(groupsvbox) topframe = TQFrame(groupsvbox) groupsvbox.setSpacing(KDialog.spacingHint()) hb.setSpacing(KDialog.spacingHint()) groupsvbox.setStretchFactor(hb,0) label = TQLabel(hb) label.setPixmap(UserIcon("hi32-group")) hb.setStretchFactor(label,0) label = TQLabel(i18n("Groups:"),hb) hb.setStretchFactor(label,1) groupsplitter = TQSplitter(TQt.Vertical,groupsvbox) self.grouplist = TDEListView(groupsplitter) self.grouplist.addColumn(i18n("Group Name")) self.grouplist.addColumn(i18n("GID")) self.grouplist.setAllColumnsShowFocus(True) self.connect(self.grouplist, TQ_SIGNAL("selectionChanged(TQListViewItem *)"), self.slotGroupListClicked) if isroot: self.connect(self.grouplist, TQ_SIGNAL("doubleClicked(TQListViewItem *)"), self.slotModifyGroupClicked) self.connect(self.grouplist, TQ_SIGNAL("contextMenu(TDEListView*,TQListViewItem*,const TQPoint&)"), self.slotGroupContext) groupbottomvbox = TQVBox(groupsplitter) groupbottomvbox.setSizePolicy(TQSizePolicy.Expanding,TQSizePolicy.Expanding) self.showspecialgroupscheckbox = TQCheckBox(i18n("Show system groups"),groupbottomvbox) vbox.setStretchFactor(self.showspecialgroupscheckbox,0) self.connect(self.showspecialgroupscheckbox,TQ_SIGNAL("toggled(bool)"), self.slotShowSystemGroupsToggled) hbox = TQHBox(groupbottomvbox) hbox.setSpacing(KDialog.spacingHint()) groupsvbox.setStretchFactor(hbox,0) self.modifygroupbutton = KPushButton(i18n("Modify..."),hbox) hbox.setStretchFactor(self.modifygroupbutton,1) self.connect(self.modifygroupbutton,TQ_SIGNAL("clicked()"),self.slotModifyGroupClicked) self.newgroupbutton = KPushButton(i18n("New..."),hbox) hbox.setStretchFactor(self.newgroupbutton,1) self.connect(self.newgroupbutton,TQ_SIGNAL("clicked()"),self.slotNewGroupClicked) self.deletegroupbutton = KPushButton(i18n("Delete..."),hbox) hbox.setStretchFactor(self.deletegroupbutton,1) self.connect(self.deletegroupbutton,TQ_SIGNAL("clicked()"),self.slotDeleteGroupClicked) if not isroot: disablebuttons = ( self.modifybutton, self.modifygroupbutton, self.deletebutton, self.deletegroupbutton, self.newbutton, self.newgroupbutton) for widget in disablebuttons: widget.setDisabled(True) label = TQLabel(i18n("Group Members:"),groupbottomvbox) groupsvbox.setStretchFactor(label,0) self.groupmemberlist = TDEListView(groupbottomvbox) self.groupmemberlist.addColumn(i18n("Login Name")) self.groupmemberlist.addColumn(i18n("Real Name")) self.groupmemberlist.addColumn(i18n("UID")) self.groupmemberlist.setAllColumnsShowFocus(True) if not standalone: tabcontrol.addTab(groupsvbox,i18n("Groups")) self.admincontext = unixauthdb.getContext(isroot) self.updatingGUI = True self.showspecialcheckbox.setChecked(self.showsystemaccounts) self.showspecialgroupscheckbox.setChecked(self.showsystemgroups) self.__updateUserList() self.__updateGroupList() self.updatingGUI = False self.usereditdialog = UserEditDialog(None,self.admincontext) self.userdeletedialog = UserDeleteDialog(None,self.admincontext) self.groupeditdialog = GroupEditDialog(None,self.admincontext) ####################################################################### def exec_loop(self): global programbase self.__loadOptions() self.updatingGUI = True self.__updateUserList() self.__updateGroupList() self.updatingGUI = False programbase.exec_loop(self) self.__saveOptions() ####################################################################### def slotUser1(self): self.aboutus.show() ####################################################################### def slotUserContext(self,l,v,p): cmenu = TDEPopupMenu(self,"MyActions") cmenu.insertItem(i18n("Modify..."), self.slotModifyClicked, 0, 0) cmenu.insertItem(i18n("Delete..."), self.slotDeleteClicked, 0, 1) if not isroot: cmenu.setItemEnabled(0,False) cmenu.setItemEnabled(1,False) cmenu.exec_loop(p) ####################################################################### def slotGroupContext(self,l,v,p): cmenu = TDEPopupMenu(self,"MyActions") cmenu.insertItem(i18n("Modify..."), self.slotModifyGroupClicked, 0, 0) cmenu.insertItem(i18n("Delete..."), self.slotDeleteGroupClicked, 0, 1) if not isroot: cmenu.setItemEnabled(0,False) cmenu.setItemEnabled(1,False) cmenu.exec_loop(p) ####################################################################### def sizeHint(self): global programbase size_hint = programbase.sizeHint(self) # Just make the dialog a little shorter by default. size_hint.setHeight(size_hint.height()-200) return size_hint ####################################################################### def slotCloseButton(self): self.close() ####################################################################### def slotListClicked(self,item): if self.updatingGUI==False: for userid in self.useridsToListItems: if self.useridsToListItems[userid]==item: self.updatingGUI = True self.__selectUser(userid) self.updatingGUI = False return ####################################################################### def slotShowSystemToggled(self,on): self.showsystemaccounts = on if self.updatingGUI==False: self.updatingGUI = True self.__updateUserList() self.updatingGUI = False ####################################################################### def slotModifyClicked(self): self.usereditdialog.showEditUser(self.selecteduserid) self.updatingGUI = True self.__updateUser(self.selecteduserid) self.__selectUser(self.selecteduserid) self.updatingGUI = False ####################################################################### def slotNewClicked(self): newuid = self.usereditdialog.showNewUser() if newuid!=None: self.updatingGUI = True self.__updateUserList() self.__selectUser(newuid) self.updatingGUI = False ####################################################################### def slotDeleteClicked(self): if self.userdeletedialog.deleteUser(self.selecteduserid): self.updatingGUI = True self.selecteduserid = None self.__updateUserList() self.updatingGUI = False ####################################################################### def slotGroupListClicked(self,item): if self.updatingGUI==False: for groupid in self.groupidsToListItems: if groupid and self.groupidsToListItems[groupid]==item: self.updatingGUI = True self.__selectGroup(groupid) self.updatingGUI = False return ####################################################################### def slotShowSystemGroupsToggled(self,on): self.showsystemgroups = on if self.updatingGUI==False: self.updatingGUI = True self.__updateGroupList() self.updatingGUI = False ####################################################################### def slotModifyGroupClicked(self): if self.selectedgroupid!=None: if self.groupeditdialog.showEditGroup(self.selectedgroupid): self.__selectGroup(self.selectedgroupid) self.updatingGUI = True self.__updateUser(self.selecteduserid) self.__selectUser(self.selecteduserid) self.updatingGUI = False ####################################################################### def slotNewGroupClicked(self): newgroupid = self.groupeditdialog.showNewGroup() if newgroupid!=None: self.updatingGUI = True self.__updateGroupList() self.__updateGroupList() self.__selectGroup(newgroupid) self.__updateUser(self.selecteduserid) self.__selectUser(self.selecteduserid) self.updatingGUI = False ####################################################################### def slotDeleteGroupClicked(self): if self.selectedgroupid!=None: groupobj = self.admincontext.lookupGID(self.selectedgroupid) groupname = groupobj.getGroupname() gid = groupobj.getGID() nummembers = len(groupobj.getUsers()) message = i18n("Are you sure you want to delete group '%1' (%2)?\nIt currently has %3 members.").arg(groupname).arg(gid).arg(nummembers) if KMessageBox.warningYesNo(self,message,i18n("Delete Group?"))==KMessageBox.Yes: self.admincontext.removeGroup(groupobj) self.admincontext.save() self.updatingGUI = True self.__updateGroupList() self.__updateUser(self.selecteduserid) self.__selectUser(self.selecteduserid) self.updatingGUI = False ####################################################################### def __updateUserList(self): self.userlist.clear() self.useridsToListItems = {} firstselecteduserid = None users = self.admincontext.getUsers() for userobj in users: uid = userobj.getUID() if self.showsystemaccounts or not userobj.isSystemUser(): lvi = TDEListViewItem(self.userlist,userobj.getUsername(),userobj.getRealName(),str(uid)) if userobj.isLocked(): lvi.setPixmap(0,UserIcon("hi16-encrypted")) self.useridsToListItems[uid] = lvi if self.selecteduserid==uid: firstselecteduserid = uid elif firstselecteduserid==None: firstselecteduserid = uid self.selecteduserid = firstselecteduserid self.__selectUser(self.selecteduserid) self.userlist.ensureItemVisible(self.userlist.currentItem()) ####################################################################### def __updateUser(self,userid): lvi = self.useridsToListItems[userid] userobj = self.admincontext.lookupUID(userid) lvi.setText(0,userobj.getUsername()) lvi.setText(1,userobj.getRealName()) lvi.setText(2,str(userobj.getUID())) if userobj.isLocked(): lvi.setPixmap(0,UserIcon("hi16-encrypted")) else: lvi.setPixmap(0,TQPixmap()) ####################################################################### def __selectUser(self,userid): self.selecteduserid = userid # Only go on if there are actual users. if len(self.useridsToListItems)>0: lvi = self.useridsToListItems[userid] self.userlist.setSelected(lvi,True) self.userlist.setCurrentItem(lvi) userobj = self.admincontext.lookupUID(userid) username = userobj.getUsername() self.loginnamelabel.setText(username) self.realnamelabel.setText(userobj.getRealName()) self.uidlabel.setText(str(userid)) if userobj.isLocked(): self.statuslabel.setText(i18n("Disabled")) else: self.statuslabel.setText(i18n("Enabled")) # Primary Group primarygroupobj = userobj.getPrimaryGroup() primarygroupname = primarygroupobj.getGroupname() self.primarygrouplabel.setText(primarygroupname) # Secondary Groups secondarygroups = [g.getGroupname() for g in userobj.getGroups() if g is not userobj.getPrimaryGroup()] self.secondarygrouplabel.setText(str(i18n(", ")).join(secondarygroups)) if isroot: self.deletebutton.setDisabled(userobj.getUID()==0) ####################################################################### def __updateGroupList(self): self.grouplist.clear() self.groupidsToListItems = {} firstselectedgroupid = None groups = self.admincontext.getGroups() for groupobj in groups: gid = groupobj.getGID() if self.showsystemgroups or not groupobj.isSystemGroup(): lvi = TQListViewItem(self.grouplist,groupobj.getGroupname(),str(gid)) self.groupidsToListItems[gid] = lvi if self.selectedgroupid==gid: firstselectedgroupid = gid elif firstselectedgroupid==None: firstselectedgroupid = gid self.selectedgroupid = firstselectedgroupid self.__selectGroup(self.selectedgroupid) self.grouplist.ensureItemVisible(self.grouplist.currentItem()) ####################################################################### def __selectGroup(self,groupid): if groupid: self.selectedgroupid = groupid lvi = self.groupidsToListItems[groupid] self.grouplist.setSelected(lvi,True) self.grouplist.setCurrentItem(lvi) groupobj = self.admincontext.lookupGID(groupid) members = groupobj.getUsers() self.groupmemberlist.clear() for userobj in members: if userobj!=None: lvi = TQListViewItem(self.groupmemberlist,userobj.getUsername(),userobj.getRealName(),str(userobj.getUID())) if isroot: self.deletegroupbutton.setDisabled(groupobj.getGID()==0) ####################################################################### def __loadOptions(self): self.config.setGroup("General") size = self.config.readSizeEntry("Geometry") if size.isEmpty()==False: self.resize(size) self.config.setGroup("Options") self.showsystemaccounts = self.config.readBoolEntry("ShowSystemAccounts") self.showspecialcheckbox.setChecked(self.showsystemaccounts) self.showsystemgroups = self.config.readBoolEntry("ShowSystemGroups") self.showspecialgroupscheckbox.setChecked(self.showsystemgroups) ####################################################################### def __saveOptions(self): global isroot if isroot: return self.config.setGroup("General") self.config.writeEntry("Geometry", self.size()) self.config.setGroup("Options") self.config.writeEntry("ShowSystemAccounts",self.showsystemaccounts) self.config.writeEntry("ShowSystemGroups",self.showsystemgroups) self.config.sync() ####################################################################### # 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 TDEAboutData object which we created during initialisation. return self.aboutdata def buttons(self): # Only supply a Help button. Other choices are Default and Apply. return TDECModule.Help ########################################################################### # Rudd-O convenience class to map groups to privilege names class PrivilegeNames(dict): """Convenience dict-derived class: map known secondary groups to privilege names, provide default mapping for groups that do not have a description. This could be replaced by a simple dict() but I simply preferred the class declaration. FIXME This should ideally be included in a more general module so it can be reused.""" def __init__(self): dict.__init__(self, { "plugdev":i18n("Access external storage devices automatically"), "adm":i18n("Administer the system"), "ltsp":i18n("Allow use of FUSE filesystems like LTSP thin client block devices"), "dialout":i18n("Connect to the Internet using a modem"), "syslog":i18n("Monitor system logs"), "fax":i18n("Send and receive faxes"), "cdrom":i18n("Use CD-ROM and DVD drives"), "floppy":i18n("Use floppy drives"), "modem":i18n("Use modems"), "scanner":i18n("Use scanners"), }) def __getitem__(self,name): # This is cruft but I couldn't bring myself to kill it bua! if name in self: return dict.__getitem__(self,name) return i18n("Be a member of the %s group")%name class UserEditDialog(KDialogBase): def __init__(self,parent,admincontext): KDialogBase.__init__(self,KJanusWidget.Tabbed,i18n("User Account"),KDialogBase.Ok|KDialogBase.Cancel, KDialogBase.Cancel,parent) self.admincontext = admincontext self.updatingGUI = True detailsvbox = self.addHBoxPage(i18n("Details")) detailspace = TQWidget(detailsvbox) infogrid = TQGridLayout(detailspace,9,2) infogrid.setSpacing(self.spacingHint()) infogrid.setColStretch(0,0) infogrid.setColStretch(1,1) self.enabledradiogroup = TQButtonGroup() self.enabledradiogroup.setRadioButtonExclusive(True) hb = TQHBox(detailspace) hb.setSpacing(self.spacingHint()) label = TQLabel(hb) label.setPixmap(UserIcon("hi32-identity")) hb.setStretchFactor(label,0) label = TQLabel(i18n("Status:"),hb) hb.setStretchFactor(label,1) infogrid.addMultiCellWidget(hb,0,1,0,0) self.enabledradio = TQRadioButton(i18n("Enabled"),detailspace) infogrid.addWidget(self.enabledradio,0,1) hbox = TQHBox(detailspace) hbox.setSpacing(self.spacingHint()) self.disabledradio = TQRadioButton(i18n("Disabled"),hbox) hbox.setStretchFactor(self.disabledradio,0) label = TQLabel(hbox) label.setPixmap(UserIcon("hi16-encrypted")) hbox.setStretchFactor(label,1) infogrid.addWidget(hbox,1,1) self.enabledradiogroup.insert(self.enabledradio,0) self.enabledradiogroup.insert(self.disabledradio,1) label = TQLabel(i18n("Login Name:"),detailspace) infogrid.addWidget(label,2,0) self.loginnameedit = KLineEdit("",detailspace) self.loginnameedit.setValidator(LoginNameValidator(self.loginnameedit)) infogrid.addWidget(self.loginnameedit,2,1) self.connect(self.loginnameedit, TQ_SIGNAL("textChanged(const TQString &)"), self.slotLoginChanged) label = TQLabel(i18n("Real Name:"),detailspace) infogrid.addWidget(label,3,0) self.realnameedit = KLineEdit("",detailspace) self.realnameedit.setValidator(RealUserNameValidator(self.realnameedit)) infogrid.addWidget(self.realnameedit,3,1) label = TQLabel(i18n("User ID:"),detailspace) infogrid.addWidget(label,4,0) self.uidedit = KLineEdit("",detailspace) self.uidedit.setValidator(TQIntValidator(0,65535,detailspace)) infogrid.addWidget(self.uidedit,4,1) label = TQLabel(i18n("Primary Group:"),detailspace) infogrid.addWidget(label,5,0) self.primarygroupedit = KComboBox(False,detailspace) infogrid.addWidget(self.primarygroupedit,5,1) label = TQLabel(i18n("Home Directory:"),detailspace) infogrid.addWidget(label,7,0) hbox = TQHBox(detailspace) hbox.setSpacing(self.spacingHint()) self.homediredit = KLineEdit("",hbox) hbox.setStretchFactor(self.homediredit,1) self.connect(self.homediredit, TQ_SIGNAL("textChanged(const TQString &)"), self.slotHomeDirChanged) self.homedirbutton = KPushButton(i18n("Browse..."),hbox) hbox.setStretchFactor(self.homedirbutton,0) self.connect(self.homedirbutton,TQ_SIGNAL("clicked()"),self.slotBrowseHomeDirClicked) infogrid.addWidget(hbox,7,1) label = TQLabel(i18n("Shell:"),detailspace) infogrid.addWidget(label,8,0) self.shelledit = KComboBox(True,detailspace) for shell in self.admincontext.getUserShells(): self.shelledit.insertItem(shell) infogrid.addWidget(self.shelledit,8,1) # Rudd-O rules. Not so much, but enough to rule. # yeah it's not my finest hour, but it works like a charm over here. Please feel free to clean up dead code that I commented # I extend my deepest thanks to the people that have worked hard to construct this tool in the first place. I have no idea who the authors and contributors are, but it would make sense to have all the contributors listed on top of the file. # Privileges and groups tab groupsvbox = self.addHBoxPage(i18n("Privileges and groups")) # Rudd-O now here we create the widget that will hold the group listing, and fill it with the groups. self.privilegeslistview = TQListView(groupsvbox) self.privilegeslistview.addColumn(i18n("Privilege"),-1) self.groupslistview = TQListView(groupsvbox) self.groupslistview.addColumn(i18n("Secondary group"),-1) groupsvbox.setStretchFactor(self.privilegeslistview,3) groupsvbox.setStretchFactor(self.groupslistview,2) # Password and Security Tab. passwordvbox = self.addVBoxPage(i18n("Password && Security")) passwordspace = TQWidget(passwordvbox) passwordgrid = TQGridLayout(passwordspace,8,3) passwordgrid.setSpacing(self.spacingHint()) passwordgrid.setColStretch(0,0) passwordgrid.setColStretch(1,0) passwordgrid.setColStretch(2,1) passwordvbox.setStretchFactor(passwordspace,0) hb = TQHBox(passwordspace) hb.setSpacing(self.spacingHint()) label = TQLabel(hb) label.setPixmap(UserIcon("hi32-password")) hb.setStretchFactor(label,0) label = TQLabel(i18n("Password:"),hb) hb.setStretchFactor(label,1) passwordgrid.addWidget(hb,0,0) self.passwordedit = KPasswordEdit(passwordspace) passwordgrid.addWidget(self.passwordedit,0,1) # Last Change label = TQLabel(i18n("Last changed:"),passwordspace) passwordgrid.addWidget(label,1,0) self.lastchangelabel = KLineEdit("",passwordspace) self.lastchangelabel.setReadOnly(True) passwordgrid.addWidget(self.lastchangelabel,1,1) self.validradiogroup = TQButtonGroup() self.validradiogroup.setRadioButtonExclusive(True) # Valid until. label = TQLabel(i18n("Valid until:"),passwordspace) passwordgrid.addWidget(label,2,0) self.validalwaysradio = TQRadioButton(i18n("Always"),passwordspace) passwordgrid.addWidget(self.validalwaysradio,2,1) hbox = TQHBox(passwordspace) hbox.setSpacing(self.spacingHint()) self.expireradio = TQRadioButton(hbox) hbox.setStretchFactor(self.expireradio,0) self.expiredate = KDateWidget(hbox) hbox.setStretchFactor(self.expiredate,1) passwordgrid.addWidget(hbox,3,1) self.validradiogroup.insert(self.validalwaysradio,0) self.validradiogroup.insert(self.expireradio,1) self.connect(self.validradiogroup,TQ_SIGNAL("clicked(int)"),self.slotValidUntilClicked) # Password Aging & Expiration. passwordaginggroup = TQVGroupBox(i18n("Password Aging"),passwordvbox) passwordaginggroup.setInsideSpacing(self.spacingHint()) passwordvbox.setStretchFactor(passwordaginggroup,0) passwordagingwidget = TQWidget(passwordaginggroup) passwordaginggrid = TQGridLayout(passwordagingwidget,4,3) passwordaginggrid.setSpacing(self.spacingHint()) # [*] Require new password after: [_____5 days] self.forcepasswordchangecheckbox = TQCheckBox(passwordagingwidget) self.connect(self.forcepasswordchangecheckbox,TQ_SIGNAL("toggled(bool)"),self.slotForcePasswordChangeToggled) passwordaginggrid.addWidget(self.forcepasswordchangecheckbox,0,0) label = TQLabel(i18n("Require new password after:"),passwordagingwidget) passwordaginggrid.addWidget(label,0,1) self.maximumpasswordedit = TQSpinBox(passwordagingwidget) self.maximumpasswordedit.setSuffix(i18n(" days")) self.maximumpasswordedit.setMinValue(1) self.maximumpasswordedit.setMaxValue(365*5) passwordaginggrid.addWidget(self.maximumpasswordedit,0,2) label = TQLabel(i18n("Warn before password expires:"),passwordagingwidget) passwordaginggrid.addWidget(label,1,1) self.warningedit = TQSpinBox(passwordagingwidget) self.warningedit.setPrefix(i18n("After ")) self.warningedit.setSuffix(i18n(" days")) self.warningedit.setMinValue(0) self.warningedit.setMaxValue(365*5) self.warningedit.setSpecialValueText(i18n("Never")) passwordaginggrid.addWidget(self.warningedit,1,2) label = TQLabel(i18n("Disable account after password expires:"),passwordagingwidget) passwordaginggrid.addWidget(label,2,1) self.disableexpireedit = TQSpinBox(passwordagingwidget) self.disableexpireedit.setPrefix(i18n("After ")) self.disableexpireedit.setSuffix(i18n(" days")) self.disableexpireedit.setMinValue(0) self.disableexpireedit.setMaxValue(365*5) self.disableexpireedit.setSpecialValueText(i18n("Never")) passwordaginggrid.addWidget(self.disableexpireedit,2,2) self.enforcepasswordminagecheckbox = TQCheckBox(passwordagingwidget) self.connect(self.enforcepasswordminagecheckbox,TQ_SIGNAL("toggled(bool)"),self.slotEnforePasswordAgeToggled) passwordaginggrid.addWidget(self.enforcepasswordminagecheckbox,3,0) label = TQLabel(i18n("Enforce minimum password age:"),passwordagingwidget) passwordaginggrid.addWidget(label,3,1) self.minimumpasswordedit = TQSpinBox(passwordagingwidget) self.minimumpasswordedit.setSuffix(i18n(" days")) passwordaginggrid.addWidget(self.minimumpasswordedit,3,2) spacer = TQWidget(passwordvbox) passwordvbox.setStretchFactor(spacer,1) self.homedirdialog = KDirSelectDialog("/",True,self,"Select Home Directory",True) self.createhomedirectorydialog = OverwriteHomeDirectoryDialog(None) self.updatingGUI = False def _repopulateGroupsPrivileges(self,excludegroups=None): # needs listviews to be constructed. Expects a list of PwdGroups to be excluded # rehash everything self.privilegeslistview.clear() self.groupslistview.clear() self.secondarygroupcheckboxes = {} pn = PrivilegeNames() if excludegroups: excludegroups = [ g.getGroupname() for g in excludegroups ] else: excludegroups = [] for group in [g.getGroupname() for g in self.admincontext.getGroups()]: if group in excludegroups: continue if group in pn: name = i18n(str(pn[group]).encode(locale.getpreferredencoding())) wid = self.privilegeslistview else: name = str(group).encode(locale.getpreferredencoding()) wid = self.groupslistview self.secondarygroupcheckboxes[group] = TQCheckListItem(wid,name,TQCheckListItem.CheckBox) ######################################################################## def showEditUser(self,userid): self.updatingGUI = True self.newusermode = False self.userobj = self.admincontext.lookupUID(userid) self.userid = userid self.passwordedit.erase() self.selectedgroups = [g.getGroupname() for g in self.userobj.getGroups() if g is not self.userobj.getPrimaryGroup()] # Rudd-O: now here we tick the appropriate group listing checkbox, and hide the currently active primary group of the user. We are repopulating because if the user to edit changes, we need to hide the user's secondary group. FIXME we should repopulate the groups privileges list when the primary group is changed in the other tab -- that is, on the change slot of the primary group drop down. self._repopulateGroupsPrivileges(excludegroups=[self.userobj.getPrimaryGroup()]) for group,checkbox in list(self.secondarygroupcheckboxes.items()): if group in self.selectedgroups: checkbox.setState(TQCheckListItem.On) else: checkbox.setState(TQCheckListItem.Off) self.originalgroups = self.selectedgroups[:] self.selectedgroups.sort() self.__syncGUI() self.uidedit.setReadOnly(True) self.updatingGUI = False self.homedirectoryislinked = False if self.exec_loop()==TQDialog.Accepted: self.__updateObjectFromGUI(self.userobj) # Set the password. if self.passwordedit.password()!="": self.userobj.setPassword(self.passwordedit.password()) # Update the groups for this user object. Rudd-O here's when you go in, stud. # we collect the selected groups self.selectedgroups = [ group for group,checkbox in list(self.secondarygroupcheckboxes.items()) if checkbox.isOn() ] for g in self.userobj.getGroups(): # this seems wasteful to remove the user from all groups then re-add, why not a cross check? self.userobj.removeFromGroup(g) for gn in self.selectedgroups: self.userobj.addToGroup(self.admincontext.lookupGroupname(gn)) primarygroupname = str(self.primarygroupedit.currentText()) self.userobj.setPrimaryGroup(self.admincontext.lookupGroupname(primarygroupname)) # Enable/Disable the account self.userobj.setLocked(self.enabledradiogroup.id(self.enabledradiogroup.selected())!=0) self.admincontext.save() ######################################################################## def showNewUser(self): self.updatingGUI = True self.newusermode = True self.userobj = self.admincontext.newUser(True) self.newgroup = self.admincontext.newGroup(True) self.newgroup.setGroupname(self.__fudgeNewGroupName(self.userobj.getUsername())) self.userobj.setPrimaryGroup(self.newgroup) self.selectedgroups = [ 'dialout','cdrom','floppy','audio','video', 'plugdev','lpadmin','scanner'] homedir = self.__fudgeNewHomeDirectory(self.userobj.getUsername()) # Rudd-O FIXME: now here we tick the proper groups that should be allowed. Now it selects what userconfig selected before. FIXME consider adding a drop down that will select the appropriate profile Limited User, Advanced User or Administrator (and see if there is a config file where these profiles can be read). We are repopulating because if the user to edit changes, we need to hide the user's secondary group. FIXME we should repopulate the groups privileges list when the primary group is changed in the other tab -- that is, on the change slot of the primary group drop down. self._repopulateGroupsPrivileges() for group,checkbox in list(self.secondarygroupcheckboxes.items()): if group in self.selectedgroups: checkbox.setState(TQCheckListItem.On) else: checkbox.setState(TQCheckListItem.Off) self.userobj.setHomeDirectory(homedir) self.homediredit.setText(homedir) shells = self.admincontext.getUserShells() dshell = self.admincontext.dshell if dshell and (dshell in shells): self.userobj.setLoginShell(dshell) elif '/bin/bash' in shells: self.userobj.setLoginShell('/bin/bash') elif '/bin/sh' in shells: self.userobj.setLoginShell('/bin/sh') elif len(shells)!=0: self.userobj.setLoginShell(shells[0]) self.__syncGUI() self.uidedit.setReadOnly(False) self.updatingGUI = False self.homedirectoryislinked = True self.passwordedit.erase() if self.exec_loop()==TQDialog.Accepted: self.__updateObjectFromGUI(self.userobj) makehomedir = True deleteoldhomedir = False if os.path.exists(self.userobj.getHomeDirectory()): rc = self.createhomedirectorydialog.do(self.userobj) if rc==OverwriteHomeDirectoryDialog.CANCEL: return None if rc==OverwriteHomeDirectoryDialog.OK_KEEP: makehomedir = False else: deleteoldhomedir = True self.admincontext.addUser(self.userobj) if self.admincontext.lookupGroupname(self.primarygroupname) is None: # Create a new group newgroup = self.admincontext.newGroup(True) newgroup.setGroupname(self.primarygroupname) self.admincontext.addGroup(newgroup) self.userobj.setPrimaryGroup(newgroup) # Update the groups for this user object. Rudd-O here's when you go in, stud. # we collect the selected groups self.selectedgroups = [ group for group,checkbox in list(self.secondarygroupcheckboxes.items()) if checkbox.isOn() ] for gn in self.selectedgroups: self.userobj.addToGroup(self.admincontext.lookupGroupname(gn)) # Set the password. if self.passwordedit.password()!="": self.userobj.setPassword(self.passwordedit.password()) # Enable/Disable the account self.userobj.setLocked(self.enabledradiogroup.id(self.enabledradiogroup.selected())!=0) self.admincontext.save() if deleteoldhomedir: if os.path.exists(self.userobj.getHomeDirectory()): shutil.rmtree(self.userobj.getHomeDirectory()) if makehomedir: self.admincontext.createHomeDirectory(self.userobj) return self.userobj.getUID() else: return None ######################################################################## def slotOk(self): ok = True # Sanity check all values. if self.newusermode: newusername = str(self.realnameedit.text()) if self.admincontext.lookupUsername(newusername)!=None: KMessageBox.sorry(self,i18n("Sorry, you must choose a different user name.\n'%1' is already being used.").arg(newusername)) ok = False else: newuid = int(str(self.uidedit.text())) originaluid = self.userobj.getUID() if self.admincontext.lookupUID(newuid)!=None: rc = KMessageBox.questionYesNo(self,i18n("User ID in use"), i18n("Sorry, the UID %1 is already in use. Should %2 be used instead?").arg(newuid).arg(originaluid)) if rc==KMessageBox.Yes: self.uidedit.setValue(str(originaluid)) else: ok = False else: self.userobj.setUID(newuid) if ok: self.passwordedit.clear() KDialogBase.slotOk(self) ######################################################################## def slotLoginChanged(self,text): newtext = str(text) if not self.updatingGUI: if self.newusermode: self.newprimarygroupname = self.__fudgeNewGroupName(newtext) self.updatingGUI = True self.primarygroupedit.changeItem(self.newprimarygroupname,0) if self.homedirectoryislinked: homedir = self.__fudgeNewHomeDirectory(newtext) self.homediredit.setText(homedir) self.updatingGUI = False ######################################################################## def slotHomeDirChanged(self,text): if self.updatingGUI==False: self.homedirectoryislinked = False ######################################################################## def __syncGUI(self): if self.userobj.isLocked(): self.enabledradiogroup.setButton(1) else: self.enabledradiogroup.setButton(0) self.loginnameedit.setText(self.userobj.getUsername()) self.realnameedit.setText(self.userobj.getRealName()) self.uidedit.setText(str(self.userobj.getUID())) self.homediredit.setText(self.userobj.getHomeDirectory()) self.shelledit.setCurrentText(self.userobj.getLoginShell()) # Primary Group self.primarygroupedit.clear() allgroups = [g.getGroupname() for g in self.admincontext.getGroups()] allgroups.sort() self.availablegroups = allgroups[:] try: self.availablegroups.remove(self.userobj.getPrimaryGroup().getGroupname()) except ValueError: pass if self.newusermode: # New user mode self.newprimarygroupname = self.__fudgeNewGroupName(str(self.userobj.getUsername())) primarygroupname = self.newprimarygroupname self.primarygroupedit.insertItem(self.newprimarygroupname) else: # Existing user mode primarygroupname = self.userobj.getPrimaryGroup().getGroupname() for group in allgroups: self.primarygroupedit.insertItem(group) self.primarygroupedit.setCurrentText(primarygroupname) # If ShadowExpire is turn off then we change the radio box. if self.userobj.getExpirationDate() is None: self.validradiogroup.setButton(0) self.expiredate.setDisabled(True) self.expiredate.setDate(SptimeToQDate(99999)) else: self.validradiogroup.setButton(1) self.expiredate.setDisabled(False) self.expiredate.setDate(SptimeToQDate(self.userobj.getExpirationDate())) if self.userobj.getMaximumPasswordAge() is None: # Password aging is turn off self.forcepasswordchangecheckbox.setChecked(False) d = True else: # Password aging is turn on self.forcepasswordchangecheckbox.setChecked(True) d = False self.warningedit.setDisabled(d) self.maximumpasswordedit.setDisabled(d) self.disableexpireedit.setDisabled(d) if self.userobj.getPasswordExpireWarning() is None: self.warningedit.setValue(0) else: self.warningedit.setValue(self.userobj.getPasswordExpireWarning()) if self.userobj.getMaximumPasswordAge() is None: self.maximumpasswordedit.setValue(30) else: self.maximumpasswordedit.setValue(self.userobj.getMaximumPasswordAge()) if self.userobj.getPasswordDisableAfterExpire() is None: self.disableexpireedit.setValue(0) else: self.disableexpireedit.setValue(self.userobj.getPasswordDisableAfterExpire()) minage = self.userobj.getMinimumPasswordAgeBeforeChange() self.enforcepasswordminagecheckbox.setChecked(minage>0) self.minimumpasswordedit.setDisabled(minage<=0) if minage<=0: minage = 1 self.minimumpasswordedit.setValue(minage) if self.userobj.getLastPasswordChange() in (None,0): self.lastchangelabel.setText('-'); else: self.lastchangelabel.setText(TDEGlobal.locale().formatDate(SptimeToQDate(int(self.userobj.getLastPasswordChange())))) ######################################################################## def __updateObjectFromGUI(self,userobj): username = str(self.loginnameedit.text()) userobj.setUsername(username) userobj.setRealName(str(self.realnameedit.text())) userobj.setHomeDirectory(str(self.homediredit.text())) userobj.setLoginShell(str(self.shelledit.currentText())) self.primarygroupname = str(self.primarygroupedit.currentText()) groupobj = self.admincontext.lookupGroupname(self.primarygroupname) if groupobj is not None: userobj.setPrimaryGroup(groupobj) # Password expiration. if self.validradiogroup.id(self.validradiogroup.selected())==0: # Password is always valid. userobj.setExpirationDate(None) else: # Password will expire at... userobj.setExpirationDate(TQDateToSptime(self.expiredate.date())) if self.forcepasswordchangecheckbox.isChecked(): userobj.setMaximumPasswordAge(self.maximumpasswordedit.value()) else: userobj.setMaximumPasswordAge(None) if self.disableexpireedit.value()==0: userobj.setPasswordDisableAfterExpire(None) else: userobj.setPasswordDisableAfterExpire(self.disableexpireedit.value()) if self.enforcepasswordminagecheckbox.isChecked(): userobj.setMinimumPasswordAgeBeforeChange(self.minimumpasswordedit.value()) else: userobj.setMinimumPasswordAgeBeforeChange(0) userobj.setPasswordExpireWarning(self.warningedit.value()) ######################################################################## def slotBrowseHomeDirClicked(self): fileurl = KURL() fileurl.setPath(self.homediredit.text()) self.homedirdialog.setCurrentURL(fileurl) if self.homedirdialog.exec_loop()==TQDialog.Accepted: self.homediredit.setText(self.homedirdialog.url().path()) self.homedirectoryislinked = False ######################################################################## def slotValidUntilClicked(self,id): if id==0: self.expiredate.setDisabled(True) else: self.expiredate.setDisabled(False) ######################################################################## def slotForcePasswordChangeToggled(self,on): on = not on self.warningedit.setDisabled(on) self.maximumpasswordedit.setDisabled(on) self.disableexpireedit.setDisabled(on) ######################################################################## def slotEnforePasswordAgeToggled(self,on): self.minimumpasswordedit.setDisabled(not on) ####################################################################### def __fudgeNewGroupName(self,basename): if self.admincontext.lookupGroupname(basename) is None: return basename x = 1 while self.admincontext.lookupGroupname(basename + '_' + str(x)) is not None: x += 1 return basename + '_' + str(x) ####################################################################### def __fudgeNewHomeDirectory(self,origbasename): basename = origbasename.replace("/","") if basename=="": basename = "user" dhome = self.admincontext.dhome if not os.path.isdir(dhome): raise OSError(dhome+" does not exist, is it correctly set in "+ \ self.admincontext.adduserconf+" ?") else: # Make sure there's a trailing / if dhome[-1] != '/': dhome = dhome+'/' if os.path.exists(dhome+basename)==False: return dhome+basename else: x = 1 while os.path.exists(dhome+basename + '_' + str(x)): x += 1 return dhome+basename ########################################################################### class LoginNameValidator(TQValidator): def __init__(self,parent): TQValidator.__init__(self,parent) ####################################################################### def validate(self,inputstr,pos): instr = str(inputstr) if len(instr)==0: return (TQValidator.Intermediate,pos) for c in instr: if ord(c)<0x20 or ord(c)>0x7f or c.isspace() or c==":" or c=="," or c==".": return (TQValidator.Invalid,pos) # Try to encode this string in the system encoding. try: instr.encode(locale.getpreferredencoding()) except UnicodeEncodeError: # won't encode -> reject it. return (TQValidator.Invalid,pos) return (TQValidator.Acceptable,pos) ####################################################################### def fixup(self,inputstr): instr = str(inputstr) newstr = "" for c in instr: if (ord(c)<0x20 or ord(c)>0x7f or c.isspace() or c==":" or c=="," or c==".")==False: newstr += c if newstr=="": return "user" else: return newstr ########################################################################### class RealUserNameValidator(TQValidator): def __init__(self,parent): TQValidator.__init__(self,parent) ####################################################################### def validate(self,inputstr,pos): instr = str(inputstr) for c in instr: if c==":": return (TQValidator.Invalid,pos) # Try to encode this string in the system encoding. try: instr.encode(locale.getpreferredencoding()) except UnicodeEncodeError: # won't encode -> reject it. return (TQValidator.Invalid,pos) return (TQValidator.Acceptable,pos) ####################################################################### def fixup(self,inputstr): return str(inputstr).replace(":","") ########################################################################### class ListPickerDialog(KDialogBase): def __init__(self,parent,caption,leftlabel,rightlabel): KDialogBase.__init__(self,parent,None,True,caption,KDialogBase.Ok|KDialogBase.Cancel, KDialogBase.Cancel) self.tophbox = TQHBox(self) self.setMainWidget(self.tophbox) self.tophbox.setSpacing(self.spacingHint()) # Available Groups vbox = TQVBox(self.tophbox) self.tophbox.setStretchFactor(vbox,1) label = TQLabel(leftlabel,vbox) vbox.setStretchFactor(label,0) self.availablelist = TDEListBox(vbox) vbox.setStretchFactor(self.availablelist,1) # ->, <- Buttons vbox = TQVBox(self.tophbox) self.tophbox.setStretchFactor(vbox,0) spacer = TQWidget(vbox); vbox.setStretchFactor(spacer,1) self.addbutton = KPushButton(i18n("Add ->"),vbox) self.connect(self.addbutton,TQ_SIGNAL("clicked()"),self.slotAddClicked) vbox.setStretchFactor(self.addbutton,0) self.removebutton = KPushButton(i18n("<- Remove"),vbox) self.connect(self.removebutton,TQ_SIGNAL("clicked()"),self.slotRemoveClicked) vbox.setStretchFactor(self.removebutton,0) spacer = TQWidget(vbox); vbox.setStretchFactor(spacer,1) # Selected Groups vbox = TQVBox(self.tophbox) self.tophbox.setStretchFactor(vbox,1) label = TQLabel(rightlabel,vbox) vbox.setStretchFactor(label,0) self.selectedlist = TDEListBox(vbox) vbox.setStretchFactor(self.selectedlist,1) ####################################################################### def do(self,grouplist,selectedlist): self.selectedlist.clear() for item in selectedlist: self.selectedlist.insertItem(item) self.selectedlist.sort() self.availablelist.clear() for item in grouplist: if item not in selectedlist: self.availablelist.insertItem(item) self.availablelist.sort() self._selectFirstAvailable() self.addbutton.setDisabled(self.availablelist.selectedItem()==None) self._selectFirstSelected() self.removebutton.setDisabled(self.selectedlist.selectedItem()==None) if self.exec_loop()==TQDialog.Accepted: newlist = [] for i in range(self.selectedlist.count()): newlist.append(str(self.selectedlist.item(i).text())) return newlist else: return selectedlist ####################################################################### def slotAddClicked(self): item = self.availablelist.selectedItem() if item!=None: self.selectedlist.insertItem(item.text()) self.availablelist.removeItem(self.availablelist.index(item)) self._selectFirstAvailable() self._selectFirstSelected() self.addbutton.setDisabled(self.availablelist.selectedItem()==None) self.removebutton.setDisabled(self.selectedlist.selectedItem()==None) ####################################################################### def slotRemoveClicked(self): item = self.selectedlist.selectedItem() if item!=None: self.availablelist.insertItem(item.text()) self.selectedlist.removeItem(self.selectedlist.index(item)) self._selectFirstAvailable() self._selectFirstSelected() self.addbutton.setDisabled(self.availablelist.selectedItem()==None) self.removebutton.setDisabled(self.selectedlist.selectedItem()==None) ####################################################################### def _selectFirstAvailable(self): if self.availablelist.count()!=0: if self.availablelist.selectedItem()==None: self.availablelist.setSelected(0,True) ####################################################################### def _selectFirstSelected(self): if self.selectedlist.count()!=0: if self.selectedlist.selectedItem()==None: self.selectedlist.setSelected(0,True) ########################################################################### class UserDeleteDialog(KDialog): def __init__(self,parent,admincontext): KDialog.__init__(self,parent,"Delete user dialog",True,TQt.WType_Dialog) self.setCaption(i18n("Delete User Account")) self.admincontext = admincontext self.updatingGUI = True toplayout = TQVBoxLayout(self) toplayout.setSpacing(self.spacingHint()) toplayout.setMargin(self.marginHint()) contentbox = TQHBox(self) contentbox.setSpacing(self.spacingHint()) toplayout.addWidget(contentbox) toplayout.setStretchFactor(contentbox,1) label = TQLabel(contentbox) label.setPixmap(TDEGlobal.iconLoader().loadIcon("messagebox_warning", TDEIcon.NoGroup, TDEIcon.SizeMedium, TDEIcon.DefaultState, None, True)) contentbox.setStretchFactor(label,0) textbox = TQVBox(contentbox) textbox.setSpacing(self.spacingHint()) textbox.setMargin(self.marginHint()) self.usernamelabel = TQLabel("",textbox) textbox.setStretchFactor(self.usernamelabel,0) # Remove directory checkbox. self.deletedirectorycheckbox = TQCheckBox(i18n("Delete home directory ()"),textbox) textbox.setStretchFactor(self.deletedirectorycheckbox,0) # Delete the User's private group. self.deletegroupcheckbox = TQCheckBox(i18n("Delete group ()"),textbox) textbox.setStretchFactor(self.deletegroupcheckbox ,0) # Buttons buttonbox = TQHBox(self) toplayout.addWidget(buttonbox) buttonbox.setSpacing(self.spacingHint()) toplayout.setStretchFactor(buttonbox,0) spacer = TQWidget(buttonbox) buttonbox.setStretchFactor(spacer,1) okbutton = TQPushButton(i18n("OK"),buttonbox) buttonbox.setStretchFactor(okbutton,0) self.connect(okbutton,TQ_SIGNAL("clicked()"),self.slotOkClicked) cancelbutton = TQPushButton(i18n("Cancel"),buttonbox) cancelbutton.setDefault(True) buttonbox.setStretchFactor(cancelbutton,0) self.connect(cancelbutton,TQ_SIGNAL("clicked()"),self.slotCancelClicked) def deleteUser(self,userid): # Setup the userobj = self.admincontext.lookupUID(userid) self.usernamelabel.setText(i18n("Are you sure want to delete user account '%1' (%2)?").arg(userobj.getUsername()).arg(userobj.getUID()) ) self.deletedirectorycheckbox.setChecked(False) self.deletedirectorycheckbox.setText(i18n("Delete home directory (%1)").arg(userobj.getHomeDirectory())) primarygroupobj = userobj.getPrimaryGroup() primarygroupname = primarygroupobj.getGroupname() self.deletegroupcheckbox.setText(i18n("Delete group '%1' (%2)").arg(primarygroupname).arg(primarygroupobj.getGID())) self.deletegroupcheckbox.setChecked(len(primarygroupobj.getUsers())==1) if self.exec_loop()==TQDialog.Accepted: self.admincontext.removeUser(userobj) if self.deletedirectorycheckbox.isChecked(): self.admincontext.removeHomeDirectory(userobj) # FIXME #self.admincontext.removeMail(userobj) if self.deletegroupcheckbox.isChecked(): self.admincontext.removeGroup(primarygroupobj) self.admincontext.save() return True else: return False def slotOkClicked(self): self.accept() def slotCancelClicked(self): self.reject() ########################################################################### class OverwriteHomeDirectoryDialog(KDialog): CANCEL = 0 OK_KEEP = 1 OK_REPLACE = 2 def __init__(self,parent): KDialog.__init__(self,parent,"Create home directory",True,TQt.WType_Dialog) self.setCaption(i18n("Create home directory")) self.updatingGUI = True toplayout = TQVBoxLayout(self) toplayout.setSpacing(self.spacingHint()) toplayout.setMargin(self.marginHint()) contentbox = TQHBox(self) contentbox.setSpacing(self.spacingHint()) toplayout.addWidget(contentbox) toplayout.setStretchFactor(contentbox,1) label = TQLabel(contentbox) label.setPixmap(TDEGlobal.iconLoader().loadIcon("messagebox_warning", TDEIcon.NoGroup, TDEIcon.SizeMedium, TDEIcon.DefaultState, None, True)) contentbox.setStretchFactor(label,0) textbox = TQVBox(contentbox) textbox.setSpacing(self.spacingHint()) textbox.setMargin(self.marginHint()) # "%dir was selected as the home directory for %user. This directory already exists. Shall I:." self.toplabel = TQLabel("",textbox) textbox.setStretchFactor(self.toplabel,0) self.radiogroup = TQButtonGroup() self.radiogroup.setRadioButtonExclusive(True) # Use Existing home directory radio button. self.usehomedirectoryradio = TQRadioButton(i18n("Use the existing directory without changing it."),textbox) textbox.setStretchFactor(self.usehomedirectoryradio,0) # Replace home directory radio button self.replacehomedirectoryradio = TQRadioButton(i18n("Delete the directory and replace it with a new home directory."),textbox) textbox.setStretchFactor(self.replacehomedirectoryradio ,0) self.radiogroup.insert(self.usehomedirectoryradio,0) self.radiogroup.insert(self.replacehomedirectoryradio,1) # Buttons buttonbox = TQHBox(self) toplayout.addWidget(buttonbox) buttonbox.setSpacing(self.spacingHint()) toplayout.setStretchFactor(buttonbox,0) spacer = TQWidget(buttonbox) buttonbox.setStretchFactor(spacer,1) okbutton = TQPushButton(i18n("OK"),buttonbox) buttonbox.setStretchFactor(okbutton,0) self.connect(okbutton,TQ_SIGNAL("clicked()"),self.slotOkClicked) cancelbutton = TQPushButton(i18n("Cancel"),buttonbox) cancelbutton.setDefault(True) buttonbox.setStretchFactor(cancelbutton,0) self.connect(cancelbutton,TQ_SIGNAL("clicked()"),self.slotCancelClicked) def do(self,userobj): # Setup the self.toplabel.setText(i18n("The directory '%1' was entered as the home directory for new user '%2'.\n This directory already exists.") \ .arg(userobj.getHomeDirectory()).arg(userobj.getUsername()) ) self.radiogroup.setButton(0) if self.exec_loop()==TQDialog.Accepted: if self.radiogroup.selectedId()==0: return OverwriteHomeDirectoryDialog.OK_KEEP else: return OverwriteHomeDirectoryDialog.OK_REPLACE else: return OverwriteHomeDirectoryDialog.CANCEL def slotOkClicked(self): self.accept() def slotCancelClicked(self): self.reject() ########################################################################### class GroupEditDialog(KDialogBase): def __init__(self,parent,admincontext): KDialogBase.__init__(self,parent,None,True,i18n("Edit Group"),KDialogBase.Ok|KDialogBase.Cancel, KDialogBase.Cancel) self.admincontext = admincontext topvbox = TQVBox(self) topvbox.setSpacing(self.spacingHint()) self.setMainWidget(topvbox) detailspace = TQWidget(topvbox) # Info about the group. editgrid = TQGridLayout(detailspace,2,2) editgrid.setSpacing(self.spacingHint()) label = TQLabel(i18n("Group Name:"),detailspace) editgrid.addWidget(label,0,0) self.groupnamelabel = KLineEdit("",detailspace) self.groupnamelabel.setReadOnly(True) editgrid.addWidget(self.groupnamelabel,0,1) label = TQLabel(i18n("Group ID:"),detailspace) editgrid.addWidget(label,1,0) self.groupidlabel = KLineEdit("",detailspace) self.groupidlabel.setReadOnly(True) editgrid.addWidget(self.groupidlabel,1,1) # Available Groups tophbox = TQHBox(topvbox) tophbox.setSpacing(self.spacingHint()) hbox = tophbox vbox = TQVBox(hbox) vbox.setSpacing(self.spacingHint()) hbox.setStretchFactor(vbox,1) label = TQLabel(i18n("Available Accounts"),vbox) vbox.setStretchFactor(label,0) self.availablelist = TDEListBox(vbox) vbox.setStretchFactor(self.availablelist,1) # ->, <- Buttons vbox = TQVBox(hbox) vbox.setSpacing(self.spacingHint()) hbox.setStretchFactor(vbox,0) spacer = TQWidget(vbox); vbox.setStretchFactor(spacer,1) self.addbutton = KPushButton(i18n("Add ->"),vbox) self.connect(self.addbutton,TQ_SIGNAL("clicked()"),self.slotAddClicked) vbox.setStretchFactor(self.addbutton,0) self.removebutton = KPushButton(i18n("<- Remove"),vbox) self.connect(self.removebutton,TQ_SIGNAL("clicked()"),self.slotRemoveClicked) vbox.setStretchFactor(self.removebutton,0) spacer = TQWidget(vbox); vbox.setStretchFactor(spacer,1) # Selected Groups vbox = TQVBox(hbox) vbox.setSpacing(self.spacingHint()) hbox.setStretchFactor(vbox,1) label = TQLabel(i18n("Selected Accounts"),vbox) vbox.setStretchFactor(label,0) self.selectedlist = TDEListBox(vbox) vbox.setStretchFactor(self.selectedlist,1) ####################################################################### def showEditGroup(self,groupid): self.groupid = groupid self.newgroupmode = False groupobj = self.admincontext.lookupGID(groupid) self.groupnamelabel.setText(groupobj.getGroupname()) self.groupidlabel.setText(str(groupid)) availablemembers = [u.getUsername() for u in self.admincontext.getUsers()] originalmembers = [u.getUsername() for u in groupobj.getUsers()] self.__updateLists(availablemembers,originalmembers) if self.exec_loop()==TQDialog.Accepted: newmembers = [] for i in range(self.selectedlist.count()): newmembers.append(str(self.selectedlist.item(i).text())) # Remove from the group object any unselected users. for member in originalmembers: if u not in newmembers: self.admincontext.lookupUsername(member).removeFromGroup(groupobj) # Put the additional members in the group for member in newmembers: self.admincontext.lookupUsername(member).addToGroup(groupobj) self.admincontext.save() return True else: return False ####################################################################### def showNewGroup(self): self.updatingGUI = True self.newgroupmode = True groupname = self.__fudgeNewGroupName(i18n("","new_group")) self.groupobj = self.admincontext.newGroup(True) self.groupobj.setGroupname(groupname) groupname = self.groupobj.getGroupname() self.groupnamelabel.setText(groupname) self.groupnamelabel.setReadOnly(False) self.groupidlabel.setText(str(self.groupobj.getGID())) self.groupidlabel.setReadOnly(False) availablemembers = [u.getUsername() for u in self.admincontext.getUsers()] self.__updateLists(availablemembers,[]) if self.exec_loop()==TQDialog.Accepted: self.groupobj.setGroupname(str(self.groupnamelabel.text())) newgroupid = int(str(self.groupidlabel.text())) self.groupobj.setGID(newgroupid) newmembers = [] for i in range(self.selectedlist.count()): newmembers.append(str(self.selectedlist.item(i).text())) self.admincontext.addGroup(self.groupobj) # Put the additional members in the group for member in newmembers: self.admincontext.lookupUsername(member).addToGroup(self.groupobj) self.admincontext.save() return newgroupid else: return None ####################################################################### def slotAddClicked(self): item = self.availablelist.selectedItem() if item!=None: self.selectedlist.insertItem(item.text()) self.availablelist.removeItem(self.availablelist.index(item)) self._selectFirstAvailable() self._selectFirstSelected() self.addbutton.setDisabled(self.availablelist.selectedItem()==None) self.removebutton.setDisabled(self.selectedlist.selectedItem()==None) ####################################################################### def slotRemoveClicked(self): item = self.selectedlist.selectedItem() if item!=None: self.availablelist.insertItem(item.text()) self.selectedlist.removeItem(self.selectedlist.index(item)) self._selectFirstAvailable() self._selectFirstSelected() self.addbutton.setDisabled(self.availablelist.selectedItem()==None) self.removebutton.setDisabled(self.selectedlist.selectedItem()==None) ####################################################################### def __updateLists(self,grouplist,selectedlist): self.selectedlist.clear() for item in selectedlist: self.selectedlist.insertItem(item) self.selectedlist.sort() self.availablelist.clear() for item in grouplist: if item not in selectedlist: self.availablelist.insertItem(item) self.availablelist.sort() self._selectFirstAvailable() self.addbutton.setDisabled(self.availablelist.selectedItem()==None) self._selectFirstSelected() self.removebutton.setDisabled(self.selectedlist.selectedItem()==None) ####################################################################### def _selectFirstAvailable(self): if self.availablelist.count()!=0: if self.availablelist.selectedItem()==None: self.availablelist.setSelected(0,True) ####################################################################### def _selectFirstSelected(self): if self.selectedlist.count()!=0: if self.selectedlist.selectedItem()==None: self.selectedlist.setSelected(0,True) ####################################################################### def __fudgeNewGroupName(self,basename): availablegroups = [g.getGroupname() for g in self.admincontext.getGroups()] if basename not in availablegroups: return basename x = 1 while basename + '_' + str(x) in availablegroups: x += 1 return basename + '_' + str(x) ############################################################################ # Factory function for KControl def create_userconfig(parent,name): return UserConfigApp(parent, name) ########################################################################## def MakeAboutData(): aboutdata = TDEAboutData("guidance", programname, version, str(i18n("User and Group Configuration Tool")).encode(locale.getpreferredencoding()), TDEAboutData.License_GPL, "Copyright (C) 2003-2007 Simon Edwards") aboutdata.addAuthor("Simon Edwards", "Developer", "simon@simonzone.com", "http://www.simonzone.com/software/") aboutdata.addAuthor("Sebastian Kügler", "Developer", "sebas@kde.org", "http://vizZzion.org") return aboutdata if standalone: aboutdata = MakeAboutData() TDECmdLineArgs.init(sys.argv,aboutdata) kapp = TDEApplication() userconfigapp = UserConfigApp() userconfigapp.exec_loop()