TDE Guidance – collection of system administration tools
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

1753 lines
72 KiB

#!/usr/bin/python
# -*- 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 python_tqt.qt 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, SIGNAL("selectionChanged(TQListViewItem *)"), self.slotListClicked)
if isroot:
self.connect(self.userlist, SIGNAL("doubleClicked(TQListViewItem *)"), self.slotModifyClicked)
self.connect(self.userlist, 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,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,SIGNAL("clicked()"),self.slotModifyClicked)
self.newbutton = KPushButton(i18n("New..."),hbox)
hbox.setStretchFactor(self.newbutton,1)
self.connect(self.newbutton,SIGNAL("clicked()"),self.slotNewClicked)
self.deletebutton = KPushButton(i18n("Delete..."),hbox)
hbox.setStretchFactor(self.deletebutton,1)
self.connect(self.deletebutton,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, SIGNAL("selectionChanged(TQListViewItem *)"), self.slotGroupListClicked)
if isroot:
self.connect(self.grouplist, SIGNAL("doubleClicked(TQListViewItem *)"), self.slotModifyGroupClicked)
self.connect(self.grouplist, 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,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,SIGNAL("clicked()"),self.slotModifyGroupClicked)
self.newgroupbutton = KPushButton(i18n("New..."),hbox)
hbox.setStretchFactor(self.newgroupbutton,1)
self.connect(self.newgroupbutton,SIGNAL("clicked()"),self.slotNewGroupClicked)
self.deletegroupbutton = KPushButton(i18n("Delete..."),hbox)
hbox.setStretchFactor(self.deletegroupbutton,1)
self.connect(self.deletegroupbutton,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(),unicode(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,unicode(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(unicode(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(unicode(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(),unicode(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(),unicode(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, 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, SIGNAL("textChanged(const TQString &)"), self.slotHomeDirChanged)
self.homedirbutton = KPushButton(i18n("Browse..."),hbox)
hbox.setStretchFactor(self.homedirbutton,0)
self.connect(self.homedirbutton,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,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,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,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(unicode(pn[group]).encode(locale.getpreferredencoding()))
wid = self.privilegeslistview
else:
name = unicode(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 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 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 = unicode(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 = [ u'dialout',u'cdrom',u'floppy',u'audio',u'video',
u'plugdev',u'lpadmin',u'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 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 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 = unicode(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(unicode(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(unicode(originaluid))
else:
ok = False
else:
self.userobj.setUID(newuid)
if ok:
self.passwordedit.clear()
KDialogBase.slotOk(self)
########################################################################
def slotLoginChanged(self,text):
newtext = unicode(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(unicode(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(unicode(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(99999L))
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 = unicode(self.loginnameedit.text())
userobj.setUsername(username)
userobj.setRealName(unicode(self.realnameedit.text()))
userobj.setHomeDirectory(unicode(self.homediredit.text()))
userobj.setLoginShell(unicode(self.shelledit.currentText()))
self.primarygroupname = unicode(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 + u'_' + unicode(x)) is not None:
x += 1
return basename + u'_' + unicode(x)
#######################################################################
def __fudgeNewHomeDirectory(self,origbasename):
basename = origbasename.replace("/","")
if basename=="":
basename = u"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] is not '/':
dhome = dhome+'/'
if os.path.exists(dhome+basename)==False:
return dhome+basename
else:
x = 1
while os.path.exists(dhome+basename + u'_' + unicode(x)):
x += 1
return dhome+basename
###########################################################################
class LoginNameValidator(TQValidator):
def __init__(self,parent):
TQValidator.__init__(self,parent)
#######################################################################
def validate(self,inputstr,pos):
instr = unicode(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 = unicode(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 = unicode(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 unicode(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,SIGNAL("clicked()"),self.slotAddClicked)
vbox.setStretchFactor(self.addbutton,0)
self.removebutton = KPushButton(i18n("<- Remove"),vbox)
self.connect(self.removebutton,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(unicode(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,SIGNAL("clicked()"),self.slotOkClicked)
cancelbutton = TQPushButton(i18n("Cancel"),buttonbox)
cancelbutton.setDefault(True)
buttonbox.setStretchFactor(cancelbutton,0)
self.connect(cancelbutton,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,SIGNAL("clicked()"),self.slotOkClicked)
cancelbutton = TQPushButton(i18n("Cancel"),buttonbox)
cancelbutton.setDefault(True)
buttonbox.setStretchFactor(cancelbutton,0)
self.connect(cancelbutton,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,SIGNAL("clicked()"),self.slotAddClicked)
vbox.setStretchFactor(self.addbutton,0)
self.removebutton = KPushButton(i18n("<- Remove"),vbox)
self.connect(self.removebutton,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(unicode(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(unicode(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("<Base string for creating new group names>","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(unicode(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(unicode(self.groupnamelabel.text()))
newgroupid = int(unicode(self.groupidlabel.text()))
self.groupobj.setGID(newgroupid)
newmembers = []
for i in range(self.selectedlist.count()):
newmembers.append(unicode(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 + u'_' + unicode(x) in availablegroups:
x += 1
return basename + u'_' + unicode(x)
############################################################################
# Factory function for KControl
def create_userconfig(parent,name):
return UserConfigApp(parent, name)
##########################################################################
def MakeAboutData():
aboutdata = TDEAboutData("guidance", programname, version,
unicode(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()