/*************************************************************************** * Copyright (C) 2005 by Sean Harmer * * 2005 - 2007 Till Adam * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "kacleditwidget.h" #include "kacleditwidget_p.h" #include #ifdef HAVE_POSIX_ACL #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_ACL_LIBACL_H # include #endif static struct { const char* label; const char* pixmapName; QPixmap* pixmap; } s_itemAttributes[] = { { I18N_NOOP( "Owner" ), "user-grey", 0 }, { I18N_NOOP( "Owning Group" ), "group-grey", 0 }, { I18N_NOOP( "Others" ), "others-grey", 0 }, { I18N_NOOP( "Mask" ), "mask", 0 }, { I18N_NOOP( "Named User" ), "user", 0 }, { I18N_NOOP( "Named Group" ), "group", 0 }, }; class KACLEditWidget::KACLEditWidgetPrivate { public: KACLEditWidgetPrivate() { } // slots void _k_slotUpdateButtons(); KACLListView *m_listView; QPushButton *m_AddBtn; QPushButton *m_EditBtn; QPushButton *m_DelBtn; }; KACLEditWidget::KACLEditWidget(QWidget *parent) : QWidget(parent), d(new KACLEditWidgetPrivate()) { QHBoxLayout *hbox = new QHBoxLayout(this); hbox->setMargin( 0 ); d->m_listView = new KACLListView(this); hbox->addWidget(d->m_listView); connect(d->m_listView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(_k_slotUpdateButtons())); QVBoxLayout *vbox = new QVBoxLayout(); hbox->addLayout( vbox ); d->m_AddBtn = new QPushButton(i18n("Add Entry..."), this); vbox->addWidget(d->m_AddBtn); d->m_AddBtn->setObjectName(QLatin1String("add_entry_button")); connect(d->m_AddBtn, SIGNAL(clicked()), d->m_listView, SLOT(slotAddEntry())); d->m_EditBtn = new QPushButton(i18n("Edit Entry..."), this); vbox->addWidget(d->m_EditBtn); d->m_EditBtn->setObjectName(QLatin1String("edit_entry_button")); connect(d->m_EditBtn, SIGNAL(clicked()), d->m_listView, SLOT(slotEditEntry())); d->m_DelBtn = new QPushButton(i18n("Delete Entry"), this); vbox->addWidget(d->m_DelBtn); d->m_DelBtn->setObjectName(QLatin1String("delete_entry_button")); connect(d->m_DelBtn, SIGNAL(clicked()), d->m_listView, SLOT(slotRemoveEntry())); vbox->addItem( new QSpacerItem( 10, 10, QSizePolicy::Fixed, QSizePolicy::Expanding ) ); d->_k_slotUpdateButtons(); } KACLEditWidget::~KACLEditWidget() { delete d; } void KACLEditWidget::KACLEditWidgetPrivate::_k_slotUpdateButtons() { bool atLeastOneIsNotDeletable = false; bool atLeastOneIsNotAllowedToChangeType = false; int selectedCount = 0; QList selected = m_listView->selectedItems(); QListIterator it(selected); while (it.hasNext()) { KACLListViewItem *item = static_cast(it.next()); ++selectedCount; if (!item->isDeletable()) { atLeastOneIsNotDeletable = true; } if (!item->isAllowedToChangeType()) { atLeastOneIsNotAllowedToChangeType = true; } } m_EditBtn->setEnabled(selectedCount && !atLeastOneIsNotAllowedToChangeType); m_DelBtn->setEnabled(selectedCount && !atLeastOneIsNotDeletable); } KACL KACLEditWidget::getACL() const { return d->m_listView->getACL(); } KACL KACLEditWidget::getDefaultACL() const { return d->m_listView->getDefaultACL(); } void KACLEditWidget::setACL(const KACL &acl) { return d->m_listView->setACL(acl); } void KACLEditWidget::setDefaultACL(const KACL &acl) { return d->m_listView->setDefaultACL(acl); } void KACLEditWidget::setAllowDefaults(bool value) { d->m_listView->setAllowDefaults(value); } KACLListViewItem::KACLListViewItem(QTreeWidget *parent, KACLListView::EntryType _type, unsigned short _value, bool defaults, const QString &_qualifier) : QTreeWidgetItem(parent), type(_type), value(_value), isDefault(defaults), qualifier(_qualifier), isPartial(false) { m_pACLListView = qobject_cast(parent); repaint(); } KACLListViewItem::~ KACLListViewItem() { } QString KACLListViewItem::key() const { QString key; if (!isDefault) { key = 'A'; } else { key = 'B'; } switch (type) { case KACLListView::User: { key += 'A'; break; } case KACLListView::Group: { key += 'B'; break; } case KACLListView::Others: { key += 'C'; break; } case KACLListView::Mask: { key += 'D'; break; } case KACLListView::NamedUser: { key += 'E' + text(1); break; } case KACLListView::NamedGroup: { key += 'F' + text(1); break; } default: { key += text(0); break; } } return key; } bool KACLListViewItem::operator< (const QTreeWidgetItem &other) const { return key() < static_cast(other).key(); } void KACLListViewItem::updatePermPixmaps() { unsigned int partialPerms = value; if (value & ACL_READ) setIcon( 2, m_pACLListView->getYesPixmap() ); else if (partialPerms & ACL_READ) setIcon(2, m_pACLListView->getYesPartialPixmap()); else setIcon(2, QIcon()); if (value & ACL_WRITE) { setIcon(3, m_pACLListView->getYesPixmap()); } else if (partialPerms & ACL_WRITE) { setIcon(3, m_pACLListView->getYesPartialPixmap()); } else { setIcon(3, QIcon()); } if (value & ACL_EXECUTE) { setIcon(4, m_pACLListView->getYesPixmap()); } else if (partialPerms & ACL_EXECUTE) { setIcon(4, m_pACLListView->getYesPartialPixmap()); } else { setIcon(4, QIcon()); } } void KACLListViewItem::repaint() { int idx = 0; switch (type) { case KACLListView::User: { idx = KACLListView::OWNER_IDX; break; } case KACLListView::Group: { idx = KACLListView::GROUP_IDX; break; } case KACLListView::Others: { idx = KACLListView::OTHERS_IDX; break; } case KACLListView::Mask: { idx = KACLListView::MASK_IDX; break; } case KACLListView::NamedUser: { idx = KACLListView::NAMED_USER_IDX; break; } case KACLListView::NamedGroup: { idx = KACLListView::NAMED_GROUP_IDX; break; } default: { idx = KACLListView::OWNER_IDX; break; } } setText(0, i18n(s_itemAttributes[idx].label)); setIcon(0, *s_itemAttributes[idx].pixmap); if (isDefault) { setText(0, text(0) + i18n(" (Default)")); } setText(1, qualifier); // Set the pixmaps for which of the perms are set updatePermPixmaps(); } void KACLListViewItem::calcEffectiveRights() { QString strEffective = QString::fromLatin1("---"); // Do we need to worry about the mask entry? It applies to named users, // owning group, and named groups if (m_pACLListView->hasMaskEntry() && ( type == KACLListView::NamedUser || type == KACLListView::Group || type == KACLListView::NamedGroup) && !isDefault) { strEffective[0] = (m_pACLListView->maskPermissions() & value & ACL_READ) ? 'r' : '-'; strEffective[1] = (m_pACLListView->maskPermissions() & value & ACL_WRITE) ? 'w' : '-'; strEffective[2] = (m_pACLListView->maskPermissions() & value & ACL_EXECUTE) ? 'x' : '-'; /* // What about any partial perms? if (maskPerms & partialPerms & ACL_READ || // Partial perms on entry maskPartialPerms & perms & ACL_READ || // Partial perms on mask maskPartialPerms & partialPerms & ACL_READ) // Partial perms on mask and entry strEffective[0] = 'R'; if (maskPerms & partialPerms & ACL_WRITE || // Partial perms on entry maskPartialPerms & perms & ACL_WRITE || // Partial perms on mask maskPartialPerms & partialPerms & ACL_WRITE) // Partial perms on mask and entry strEffective[1] = 'W'; if (maskPerms & partialPerms & ACL_EXECUTE || // Partial perms on entry maskPartialPerms & perms & ACL_EXECUTE || // Partial perms on mask maskPartialPerms & partialPerms & ACL_EXECUTE) // Partial perms on mask and entry strEffective[2] = 'X'; */ } else { // No, the effective value are just the value in this entry strEffective[0] = (value & ACL_READ) ? 'r' : '-'; strEffective[1] = (value & ACL_WRITE) ? 'w' : '-'; strEffective[2] = (value & ACL_EXECUTE) ? 'x' : '-'; /* // What about any partial perms? if (partialPerms & ACL_READ) strEffective[0] = 'R'; if (partialPerms & ACL_WRITE) strEffective[1] = 'W'; if (partialPerms & ACL_EXECUTE) strEffective[2] = 'X'; */ } setText(5, strEffective); } bool KACLListViewItem::isDeletable() const { bool isMaskAndDeletable = false; if (type == KACLListView::Mask) { if (!isDefault && m_pACLListView->maskCanBeDeleted()) { isMaskAndDeletable = true; } else if (isDefault && m_pACLListView->defaultMaskCanBeDeleted()) { isMaskAndDeletable = true; } } return (type != KACLListView::User && type != KACLListView::Group && type != KACLListView::Others && (type != KACLListView::Mask || isMaskAndDeletable)); } bool KACLListViewItem::isAllowedToChangeType() const { return (type != KACLListView::User && type != KACLListView::Group && type != KACLListView::Others && type != KACLListView::Mask); } void KACLListViewItem::togglePerm(acl_perm_t perm) { value ^= perm; // Toggle the perm if (type == KACLListView::Mask && !isDefault) { m_pACLListView->setMaskPermissions(value); } calcEffectiveRights(); updatePermPixmaps(); /* // If the perm is in the partial perms then remove it. i.e. Once // a user changes a partial perm it then applies to all selected files. if ( m_pEntry->m_partialPerms & perm ) m_pEntry->m_partialPerms ^= perm; m_pEntry->setPartialEntry( false ); // Make sure that all entries have their effective rights calculated if // we are changing the ACL_MASK entry. if ( type == Mask ) { m_pACLListView->setMaskPartialPermissions( m_pEntry->m_partialPerms ); m_pACLListView->setMaskPermissions( value ); m_pACLListView->calculateEffectiveRights(); } */ } EditACLEntryDialog::EditACLEntryDialog(KACLListView *listView, KACLListViewItem *item, const QStringList &users, const QStringList &groups, const QStringList &defaultUsers, const QStringList &defaultGroups, int allowedTypes, int allowedDefaultTypes, bool allowDefaults) : KDialog(listView), m_listView(listView), m_item(item), m_users(users), m_groups(groups), m_defaultUsers(defaultUsers), m_defaultGroups(defaultGroups), m_allowedTypes(allowedTypes), m_allowedDefaultTypes(allowedDefaultTypes), m_defaultCB(0) { setObjectName("edit_entry_dialog"); setModal(true); setCaption(i18n("Edit ACL Entry")); setButtons(KDialog::Ok | KDialog::Cancel); setDefaultButton(KDialog::Ok); QWidget *page = new QWidget( this ); setMainWidget( page ); QVBoxLayout *mainLayout = new QVBoxLayout( page ); mainLayout->setMargin( 0 ); QGroupBox *gb = new QGroupBox( i18n("Entry Type"), page ); QVBoxLayout *gbLayout = new QVBoxLayout( gb ); m_buttonGroup = new QButtonGroup( page ); if ( allowDefaults ) { m_defaultCB = new QCheckBox( i18n("Default for new files in this folder"), page ); m_defaultCB->setObjectName( QLatin1String( "defaultCB" ) ); mainLayout->addWidget( m_defaultCB ); connect( m_defaultCB, SIGNAL(toggled(bool)), this, SLOT(slotUpdateAllowedUsersAndGroups()) ); connect( m_defaultCB, SIGNAL(toggled(bool)), this, SLOT(slotUpdateAllowedTypes()) ); } QRadioButton *ownerType = new QRadioButton( i18n("Owner"), gb ); ownerType->setObjectName( QLatin1String( "ownerType" ) ); gbLayout->addWidget( ownerType ); m_buttonGroup->addButton( ownerType ); m_buttonIds.insert( ownerType, KACLListView::User ); QRadioButton *owningGroupType = new QRadioButton( i18n("Owning Group"), gb ); owningGroupType->setObjectName( QLatin1String( "owningGroupType" ) ); gbLayout->addWidget( owningGroupType ); m_buttonGroup->addButton( owningGroupType ); m_buttonIds.insert( owningGroupType, KACLListView::Group ); QRadioButton *othersType = new QRadioButton( i18n("Others"), gb ); othersType->setObjectName( QLatin1String( "othersType" ) ); gbLayout->addWidget( othersType ); m_buttonGroup->addButton( othersType ); m_buttonIds.insert( othersType, KACLListView::Others ); QRadioButton *maskType = new QRadioButton( i18n("Mask"), gb ); maskType->setObjectName( QLatin1String( "maskType" ) ); gbLayout->addWidget( maskType ); m_buttonGroup->addButton( maskType ); m_buttonIds.insert( maskType, KACLListView::Mask ); QRadioButton *namedUserType = new QRadioButton( i18n("Named user"), gb ); namedUserType->setObjectName( QLatin1String( "namesUserType" ) ); gbLayout->addWidget( namedUserType ); m_buttonGroup->addButton( namedUserType ); m_buttonIds.insert( namedUserType, KACLListView::NamedUser ); QRadioButton *namedGroupType = new QRadioButton( i18n("Named group"), gb ); namedGroupType->setObjectName( QLatin1String( "namedGroupType" ) ); gbLayout->addWidget( namedGroupType ); m_buttonGroup->addButton( namedGroupType ); m_buttonIds.insert( namedGroupType, KACLListView::NamedGroup ); mainLayout->addWidget( gb ); connect( m_buttonGroup, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(slotSelectionChanged(QAbstractButton*)) ); m_widgetStack = new QStackedWidget( page ); mainLayout->addWidget( m_widgetStack ); KHBox *usersBox = new KHBox( m_widgetStack ); m_widgetStack->addWidget( usersBox ); KHBox *groupsBox = new KHBox( m_widgetStack ); m_widgetStack->addWidget( groupsBox ); QLabel *usersLabel = new QLabel( i18n( "User: " ), usersBox ); m_usersCombo = new KComboBox( usersBox ); m_usersCombo->setEditable( false ); m_usersCombo->setObjectName( QLatin1String( "users" ) ); usersLabel->setBuddy( m_usersCombo ); QLabel *groupsLabel = new QLabel( i18n( "Group: " ), groupsBox ); m_groupsCombo = new KComboBox( groupsBox ); m_groupsCombo->setEditable( false ); m_groupsCombo->setObjectName( QLatin1String( "groups" ) ); groupsLabel->setBuddy( m_groupsCombo ); if ( m_item ) { m_buttonIds.key( m_item->type )->setChecked( true ); if ( m_defaultCB ) m_defaultCB->setChecked( m_item->isDefault ); slotUpdateAllowedTypes(); slotSelectionChanged( m_buttonIds.key( m_item->type ) ); slotUpdateAllowedUsersAndGroups(); if ( m_item->type == KACLListView::NamedUser ) { m_usersCombo->setItemText( m_usersCombo->currentIndex(), m_item->qualifier ); } else if ( m_item->type == KACLListView::NamedGroup ) { m_groupsCombo->setItemText( m_groupsCombo->currentIndex(), m_item->qualifier ); } } else { // new entry, preselect "named user", arguably the most common one m_buttonIds.key( KACLListView::NamedUser )->setChecked( true ); slotUpdateAllowedTypes(); slotSelectionChanged( m_buttonIds.key( KACLListView::NamedUser ) ); slotUpdateAllowedUsersAndGroups(); } incrementInitialSize( QSize( 100, 0 ) ); connect(this,SIGNAL(okClicked()), this, SLOT(slotOk())); } void EditACLEntryDialog::slotUpdateAllowedTypes() { int allowedTypes = m_allowedTypes; if ( m_defaultCB && m_defaultCB->isChecked() ) { allowedTypes = m_allowedDefaultTypes; } for ( int i=1; i < KACLListView::AllTypes; i=i*2 ) { if ( allowedTypes & i ) m_buttonIds.key( i )->show(); else m_buttonIds.key( i )->hide(); } } void EditACLEntryDialog::slotUpdateAllowedUsersAndGroups() { const QString oldUser = m_usersCombo->currentText(); const QString oldGroup = m_groupsCombo->currentText(); m_usersCombo->clear(); m_groupsCombo->clear(); if ( m_defaultCB && m_defaultCB->isChecked() ) { m_usersCombo->addItems( m_defaultUsers ); if ( m_defaultUsers.contains( oldUser ) ) m_usersCombo->setItemText( m_usersCombo->currentIndex(), oldUser ); m_groupsCombo->addItems( m_defaultGroups ); if ( m_defaultGroups.contains( oldGroup ) ) m_groupsCombo->setItemText( m_groupsCombo->currentIndex(), oldGroup ); } else { m_usersCombo->addItems( m_users ); if ( m_users.contains( oldUser ) ) m_usersCombo->setItemText( m_usersCombo->currentIndex(), oldUser ); m_groupsCombo->addItems( m_groups ); if ( m_groups.contains( oldGroup ) ) m_groupsCombo->setItemText( m_groupsCombo->currentIndex(), oldGroup ); } } void EditACLEntryDialog::slotOk() { KACLListView::EntryType type = static_cast( m_buttonIds[m_buttonGroup->checkedButton()] ); kWarning() << "Type 2: " << type; QString qualifier; if ( type == KACLListView::NamedUser ) qualifier = m_usersCombo->currentText(); if ( type == KACLListView::NamedGroup ) qualifier = m_groupsCombo->currentText(); if ( !m_item ) { m_item = new KACLListViewItem( m_listView, type, ACL_READ | ACL_WRITE | ACL_EXECUTE, false, qualifier ); } else { m_item->type = type; m_item->qualifier = qualifier; } if ( m_defaultCB ) m_item->isDefault = m_defaultCB->isChecked(); m_item->repaint(); KDialog::accept(); } void EditACLEntryDialog::slotSelectionChanged( QAbstractButton *button ) { switch ( m_buttonIds[ button ] ) { case KACLListView::User: case KACLListView::Group: case KACLListView::Others: case KACLListView::Mask: m_widgetStack->setEnabled( false ); break; case KACLListView::NamedUser: m_widgetStack->setEnabled( true ); m_widgetStack->setCurrentIndex( 0 /* User */ ); break; case KACLListView::NamedGroup: m_widgetStack->setEnabled( true ); m_widgetStack->setCurrentIndex( 1 /* Group */ ); break; default: break; } } static QString kfileIconPath(const char* const name) { return KStandardDirs::locate("data", QString::fromLatin1("kio/pics/%1.png").arg(name)); } KACLListView::KACLListView( QWidget* parent ) : QTreeWidget( parent ), m_hasMask( false ), m_allowDefaults( false ) { // Add the columns setColumnCount( 6 ); QStringList headers; headers << i18n( "Type" ); headers << i18n( "Name" ); headers << i18nc( "read permission", "r" ); headers << i18nc( "write permission", "w" ); headers << i18nc( "execute permission", "x" ); headers << i18n( "Effective" ); setHeaderLabels( headers ); setSortingEnabled( false ); setSelectionMode( QAbstractItemView::ExtendedSelection ); header()->setResizeMode( QHeaderView::ResizeToContents ); setRootIsDecorated( false ); // Load the avatars for ( int i=0; i < LAST_IDX; ++i ) { s_itemAttributes[i].pixmap = new QPixmap( kfileIconPath(s_itemAttributes[i].pixmapName) ); } m_yesPixmap = new QPixmap( kfileIconPath("yes") ); m_yesPartialPixmap = new QPixmap( kfileIconPath("yespartial") ); // fill the lists of all legal users and groups m_allUsers = KUser::allUserNames(); m_allGroups << KUserGroup::allGroupNames(); m_allUsers.sort(); m_allGroups.sort(); connect( this, SIGNAL(itemClicked(QTreeWidgetItem*,int)), this, SLOT(slotItemClicked(QTreeWidgetItem*,int)) ); } KACLListView::~KACLListView() { for ( int i=0; i < LAST_IDX; ++i ) { delete s_itemAttributes[i].pixmap; } delete m_yesPixmap; delete m_yesPartialPixmap; } QStringList KACLListView::allowedUsers( bool defaults, KACLListViewItem *allowedItem ) { QStringList allowedUsers = m_allUsers; QTreeWidgetItemIterator it( this ); while ( *it ) { const KACLListViewItem *item = static_cast( *it ); ++it; if ( item->type != NamedUser || item->isDefault != defaults ) continue; if ( allowedItem && item == allowedItem && allowedItem->isDefault == defaults ) continue; allowedUsers.removeAll( item->qualifier ); } return allowedUsers; } QStringList KACLListView::allowedGroups( bool defaults, KACLListViewItem *allowedItem ) { QStringList allowedGroups = m_allGroups; QTreeWidgetItemIterator it( this ); while ( *it ) { const KACLListViewItem *item = static_cast( *it ); ++it; if ( item->type != NamedGroup || item->isDefault != defaults ) continue; if ( allowedItem && item == allowedItem && allowedItem->isDefault == defaults ) continue; allowedGroups.removeAll( item->qualifier ); } return allowedGroups; } void KACLListView::fillItemsFromACL( const KACL &pACL, bool defaults ) { // clear out old entries of that ilk QTreeWidgetItemIterator it( this ); while ( KACLListViewItem *item = static_cast( *it ) ) { ++it; if ( item->isDefault == defaults ) delete item; } new KACLListViewItem( this, User, pACL.ownerPermissions(), defaults ); new KACLListViewItem( this, Group, pACL.owningGroupPermissions(), defaults ); new KACLListViewItem( this, Others, pACL.othersPermissions(), defaults ); bool hasMask = false; unsigned short mask = pACL.maskPermissions( hasMask ); if ( hasMask ) { new KACLListViewItem( this, Mask, mask, defaults ); } // read all named user entries const ACLUserPermissionsList &userList = pACL.allUserPermissions(); ACLUserPermissionsConstIterator itu = userList.begin(); while ( itu != userList.end() ) { new KACLListViewItem( this, NamedUser, (*itu).second, defaults, (*itu).first ); ++itu; } // and now all named groups const ACLUserPermissionsList &groupList = pACL.allGroupPermissions(); ACLUserPermissionsConstIterator itg = groupList.begin(); while ( itg != groupList.end() ) { new KACLListViewItem( this, NamedGroup, (*itg).second, defaults, (*itg).first ); ++itg; } } void KACLListView::setACL( const KACL &acl ) { if ( !acl.isValid() ) return; // Remove any entries left over from displaying a previous ACL m_ACL = acl; fillItemsFromACL( m_ACL ); m_mask = acl.maskPermissions( m_hasMask ); calculateEffectiveRights(); } void KACLListView::setDefaultACL( const KACL &acl ) { if ( !acl.isValid() ) return; m_defaultACL = acl; fillItemsFromACL( m_defaultACL, true ); calculateEffectiveRights(); } KACL KACLListView::itemsToACL( bool defaults ) const { KACL newACL( 0 ); bool atLeastOneEntry = false; ACLUserPermissionsList users; ACLGroupPermissionsList groups; QTreeWidgetItemIterator it( const_cast( this ) ); while ( QTreeWidgetItem* qlvi = *it ) { ++it; const KACLListViewItem* item = static_cast( qlvi ); if ( item->isDefault != defaults ) continue; atLeastOneEntry = true; switch ( item->type ) { case User: newACL.setOwnerPermissions( item->value ); break; case Group: newACL.setOwningGroupPermissions( item->value ); break; case Others: newACL.setOthersPermissions( item->value ); break; case Mask: newACL.setMaskPermissions( item->value ); break; case NamedUser: users.append( qMakePair( item->text( 1 ), item->value ) ); break; case NamedGroup: groups.append( qMakePair( item->text( 1 ), item->value ) ); break; default: break; } } if ( atLeastOneEntry ) { newACL.setAllUserPermissions( users ); newACL.setAllGroupPermissions( groups ); if ( newACL.isValid() ) return newACL; } return KACL(); } KACL KACLListView::getACL() { return itemsToACL( false ); } KACL KACLListView::getDefaultACL() { return itemsToACL( true ); } void KACLListView::slotItemClicked( QTreeWidgetItem* pItem, int col ) { if ( !pItem ) return; QTreeWidgetItemIterator it( this ); while ( KACLListViewItem* item = static_cast( *it ) ) { ++it; if ( !item->isSelected() ) continue; switch ( col ) { case 2: item->togglePerm( ACL_READ ); break; case 3: item->togglePerm( ACL_WRITE ); break; case 4: item->togglePerm( ACL_EXECUTE ); break; default: ; // Do nothing } } /* // Has the user changed one of the required entries in a default ACL? if ( m_pACL->aclType() == ACL_TYPE_DEFAULT && ( col == 2 || col == 3 || col == 4 ) && ( pACLItem->entryType() == ACL_USER_OBJ || pACLItem->entryType() == ACL_GROUP_OBJ || pACLItem->entryType() == ACL_OTHER ) ) { // Mark the required entries as no longer being partial entries. // That is, they will get applied to all selected directories. KACLListViewItem* pUserObj = findACLEntryByType( this, ACL_USER_OBJ ); pUserObj->entry()->setPartialEntry( false ); KACLListViewItem* pGroupObj = findACLEntryByType( this, ACL_GROUP_OBJ ); pGroupObj->entry()->setPartialEntry( false ); KACLListViewItem* pOther = findACLEntryByType( this, ACL_OTHER ); pOther->entry()->setPartialEntry( false ); update(); } */ } void KACLListView::calculateEffectiveRights() { QTreeWidgetItemIterator it( this ); KACLListViewItem* pItem; while ( ( pItem = dynamic_cast( *it ) ) != 0 ) { ++it; pItem->calcEffectiveRights(); } } unsigned short KACLListView::maskPermissions() const { return m_mask; } void KACLListView::setMaskPermissions( unsigned short maskPerms ) { m_mask = maskPerms; calculateEffectiveRights(); } acl_perm_t KACLListView::maskPartialPermissions() const { // return m_pMaskEntry->m_partialPerms; return 0; } void KACLListView::setMaskPartialPermissions( acl_perm_t /*maskPartialPerms*/ ) { //m_pMaskEntry->m_partialPerms = maskPartialPerms; calculateEffectiveRights(); } bool KACLListView::hasDefaultEntries() const { QTreeWidgetItemIterator it( const_cast( this ) ); while ( *it ) { const KACLListViewItem *item = static_cast( *it ); ++it; if ( item->isDefault ) return true; } return false; } const KACLListViewItem* KACLListView::findDefaultItemByType( EntryType type ) const { return findItemByType( type, true ); } const KACLListViewItem* KACLListView::findItemByType( EntryType type, bool defaults ) const { QTreeWidgetItemIterator it( const_cast( this ) ); while ( *it ) { const KACLListViewItem *item = static_cast( *it ); ++it; if ( item->isDefault == defaults && item->type == type ) { return item; } } return 0; } unsigned short KACLListView::calculateMaskValue( bool defaults ) const { // KACL auto-adds the relevant maks entries, so we can simply query bool dummy; return itemsToACL( defaults ).maskPermissions( dummy ); } void KACLListView::slotAddEntry() { int allowedTypes = NamedUser | NamedGroup; if ( !m_hasMask ) allowedTypes |= Mask; int allowedDefaultTypes = NamedUser | NamedGroup; if ( !findDefaultItemByType( Mask ) ) allowedDefaultTypes |= Mask; if ( !hasDefaultEntries() ) allowedDefaultTypes |= User | Group; EditACLEntryDialog dlg( this, 0, allowedUsers( false ), allowedGroups( false ), allowedUsers( true ), allowedGroups( true ), allowedTypes, allowedDefaultTypes, m_allowDefaults ); dlg.exec(); KACLListViewItem *item = dlg.item(); if ( !item ) return; // canceled if ( item->type == Mask && !item->isDefault ) { m_hasMask = true; m_mask = item->value; } if ( item->isDefault && !hasDefaultEntries() ) { // first default entry, fill in what is needed if ( item->type != User ) { unsigned short v = findDefaultItemByType( User )->value; new KACLListViewItem( this, User, v, true ); } if ( item->type != Group ) { unsigned short v = findDefaultItemByType( Group )->value; new KACLListViewItem( this, Group, v, true ); } if ( item->type != Others ) { unsigned short v = findDefaultItemByType( Others )->value; new KACLListViewItem( this, Others, v, true ); } } const KACLListViewItem *defaultMaskItem = findDefaultItemByType( Mask ); if ( item->isDefault && !defaultMaskItem ) { unsigned short v = calculateMaskValue( true ); new KACLListViewItem( this, Mask, v, true ); } if ( !item->isDefault && !m_hasMask && ( item->type == Group || item->type == NamedUser || item->type == NamedGroup ) ) { // auto-add a mask entry unsigned short v = calculateMaskValue( false ); new KACLListViewItem( this, Mask, v, false ); m_hasMask = true; m_mask = v; } calculateEffectiveRights(); sortItems( sortColumn(), Qt::AscendingOrder ); setCurrentItem( item ); // QTreeWidget doesn't seem to emit, in this case, and we need to update // the buttons... if ( topLevelItemCount() == 1 ) emit currentItemChanged( item, item ); } void KACLListView::slotEditEntry() { QTreeWidgetItem * current = currentItem(); if ( !current ) return; KACLListViewItem *item = static_cast( current ); int allowedTypes = item->type | NamedUser | NamedGroup; bool itemWasMask = item->type == Mask; if ( !m_hasMask || itemWasMask ) allowedTypes |= Mask; int allowedDefaultTypes = item->type | NamedUser | NamedGroup; if ( !findDefaultItemByType( Mask ) ) allowedDefaultTypes |= Mask; if ( !hasDefaultEntries() ) allowedDefaultTypes |= User | Group; EditACLEntryDialog dlg( this, item, allowedUsers( false, item ), allowedGroups( false, item ), allowedUsers( true, item ), allowedGroups( true, item ), allowedTypes, allowedDefaultTypes, m_allowDefaults ); dlg.exec(); if ( itemWasMask && item->type != Mask ) { m_hasMask = false; m_mask = 0; } if ( !itemWasMask && item->type == Mask ) { m_mask = item->value; m_hasMask = true; } calculateEffectiveRights(); sortItems( sortColumn(), Qt::AscendingOrder ); } void KACLListView::slotRemoveEntry() { QTreeWidgetItemIterator it( this, QTreeWidgetItemIterator::Selected ); while ( *it ) { KACLListViewItem *item = static_cast( *it ); ++it; /* First check if it's a mask entry and if so, make sure that there is * either no name user or group entry, which means the mask can be * removed, or don't remove it, but reset it. That is allowed. */ if ( item->type == Mask ) { bool itemWasDefault = item->isDefault; if ( !itemWasDefault && maskCanBeDeleted() ) { m_hasMask= false; m_mask = 0; delete item; } else if ( itemWasDefault && defaultMaskCanBeDeleted() ) { delete item; } else { item->value = 0; item->repaint(); } if ( !itemWasDefault ) calculateEffectiveRights(); } else { // for the base permissions, disable them, which is what libacl does if ( !item->isDefault && ( item->type == User || item->type == Group || item->type == Others ) ) { item->value = 0; item->repaint(); } else { delete item; } } } } bool KACLListView::maskCanBeDeleted() const { return !findItemByType( NamedUser ) && !findItemByType( NamedGroup ); } bool KACLListView::defaultMaskCanBeDeleted() const { return !findDefaultItemByType( NamedUser ) && !findDefaultItemByType( NamedGroup ); } #include "moc_kacleditwidget.cpp" #include "moc_kacleditwidget_p.cpp" #endif // vim:set ts=8 sw=4: