summaryrefslogtreecommitdiffstats
path: root/tdeio/tdefile/kacleditwidget.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tdeio/tdefile/kacleditwidget.cpp')
-rw-r--r--tdeio/tdefile/kacleditwidget.cpp1054
1 files changed, 1054 insertions, 0 deletions
diff --git a/tdeio/tdefile/kacleditwidget.cpp b/tdeio/tdefile/kacleditwidget.cpp
new file mode 100644
index 000000000..94ee0d4c4
--- /dev/null
+++ b/tdeio/tdefile/kacleditwidget.cpp
@@ -0,0 +1,1054 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Sean Harmer <sh@rama.homelinux.org> *
+ * Till Adam <adam@kde.org> *
+ * *
+ * 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"
+
+#ifdef USE_POSIX_ACL
+
+#include <tqpainter.h>
+#include <tqptrlist.h>
+#include <tqvbox.h>
+#include <tqhbox.h>
+#include <tqpushbutton.h>
+#include <tqvbuttongroup.h>
+#include <tqradiobutton.h>
+#include <tqcombobox.h>
+#include <tqlabel.h>
+#include <tqcheckbox.h>
+#include <tqlayout.h>
+#include <tqwidgetstack.h>
+#include <tqheader.h>
+
+#include <klocale.h>
+#include <tdefileitem.h>
+#include <kdebug.h>
+#include <kdialog.h>
+#include <kdialogbase.h>
+
+#ifdef HAVE_ACL_LIBACL_H
+# include <acl/libacl.h>
+#endif
+extern "C" {
+#include <pwd.h>
+#include <grp.h>
+}
+#include <assert.h>
+
+#include "images.h"
+
+static struct {
+ const char* label;
+ const char* pixmapName;
+ TQPixmap* 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 },
+};
+
+KACLEditWidget::KACLEditWidget( TQWidget *parent, const char *name )
+ :TQWidget( parent, name )
+{
+ TQHBox *hbox = new TQHBox( parent );
+ hbox->setSpacing( KDialog::spacingHint() );
+ m_listView = new KACLListView( hbox, "acl_listview" );
+ connect( m_listView, TQT_SIGNAL( selectionChanged() ),
+ this, TQT_SLOT( slotUpdateButtons() ) );
+ TQVBox *vbox = new TQVBox( hbox );
+ vbox->setSpacing( KDialog::spacingHint() );
+ m_AddBtn = new TQPushButton( i18n( "Add Entry..." ), vbox, "add_entry_button" );
+ connect( m_AddBtn, TQT_SIGNAL( clicked() ), m_listView, TQT_SLOT( slotAddEntry() ) );
+ m_EditBtn = new TQPushButton( i18n( "Edit Entry..." ), vbox, "edit_entry_button" );
+ connect( m_EditBtn, TQT_SIGNAL( clicked() ), m_listView, TQT_SLOT( slotEditEntry() ) );
+ m_DelBtn = new TQPushButton( i18n( "Delete Entry" ), vbox, "delete_entry_button" );
+ connect( m_DelBtn, TQT_SIGNAL( clicked() ), m_listView, TQT_SLOT( slotRemoveEntry() ) );
+ TQWidget *spacer = new TQWidget( vbox );
+ spacer->setSizePolicy( TQSizePolicy::Minimum, TQSizePolicy::Expanding );
+ slotUpdateButtons();
+}
+
+void KACLEditWidget::slotUpdateButtons()
+{
+ bool atLeastOneIsNotDeletable = false;
+ bool atLeastOneIsNotAllowedToChangeType = false;
+ int selectedCount = 0;
+ TQListViewItemIterator it( m_listView, TQListViewItemIterator::Selected );
+ while ( KACLListViewItem *item = dynamic_cast<KACLListViewItem*>( it.current() ) ) {
+ ++it; ++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 m_listView->getACL();
+}
+
+KACL KACLEditWidget::getDefaultACL() const
+{
+ return m_listView->getDefaultACL();
+}
+
+void KACLEditWidget::setACL( const KACL &acl )
+{
+ return m_listView->setACL( acl );
+}
+
+void KACLEditWidget::setDefaultACL( const KACL &acl )
+{
+ return m_listView->setDefaultACL( acl );
+}
+
+void KACLEditWidget::setAllowDefaults( bool value )
+{
+ m_listView->setAllowDefaults( value );
+}
+
+void KACLEditWidget::setReadOnly( bool on )
+{
+ m_listView->setEnabled( !on );
+ m_AddBtn->setEnabled( !on );
+ if ( !on )
+ slotUpdateButtons();
+}
+
+KACLListViewItem::KACLListViewItem( TQListView* parent,
+ KACLListView::EntryType _type,
+ unsigned short _value, bool defaults,
+ const TQString& _qualifier )
+ : KListViewItem( parent, parent->lastItem() ), // we want to append
+ type( _type ), value( _value ), isDefault( defaults ),
+ qualifier( _qualifier ), isPartial( false )
+{
+ m_pACLListView = dynamic_cast<KACLListView*>( parent );
+ repaint();
+}
+
+
+KACLListViewItem::~ KACLListViewItem()
+{
+
+}
+
+TQString KACLListViewItem::key( int, bool ) const
+{
+ TQString 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;
+}
+
+void KACLListViewItem::paintCell( TQPainter* p, const TQColorGroup &cg,
+ int column, int width, int alignment )
+{
+ TQColorGroup mycg = cg;
+ if ( isDefault ) {
+ mycg.setColor( TQColorGroup::Text, TQColor( 0, 0, 255 ) );
+ }
+ if ( isPartial ) {
+ TQFont font = p->font();
+ font.setItalic( true );
+ mycg.setColor( TQColorGroup::Text, TQColor( 100, 100, 100 ) );
+ p->setFont( font );
+ }
+ KListViewItem::paintCell( p, mycg, column, width, alignment );
+
+ KACLListViewItem *below =0;
+ if ( itemBelow() )
+ below = static_cast<KACLListViewItem*>( itemBelow() );
+ const bool lastUser = type == KACLListView::NamedUser && below && below->type == KACLListView::NamedGroup;
+ const bool lastNonDefault = !isDefault && below && below->isDefault;
+ if ( type == KACLListView::Mask || lastUser || lastNonDefault )
+ {
+ p->setPen( TQPen( Qt::gray, 0, TQPen::DotLine ) );
+ if ( type == KACLListView::Mask )
+ p->drawLine( 0, 0, width - 1, 0 );
+ p->drawLine( 0, height() - 1, width - 1, height() - 1 );
+ }
+}
+
+
+void KACLListViewItem::updatePermPixmaps()
+{
+ unsigned int partialPerms = value;
+
+ if ( value & ACL_READ )
+ setPixmap( 2, m_pACLListView->getYesPixmap() );
+ else if ( partialPerms & ACL_READ )
+ setPixmap( 2, m_pACLListView->getYesPartialPixmap() );
+ else
+ setPixmap( 2, TQPixmap() );
+
+ if ( value & ACL_WRITE )
+ setPixmap( 3, m_pACLListView->getYesPixmap() );
+ else if ( partialPerms & ACL_WRITE )
+ setPixmap( 3, m_pACLListView->getYesPartialPixmap() );
+ else
+ setPixmap( 3, TQPixmap() );
+
+ if ( value & ACL_EXECUTE )
+ setPixmap( 4, m_pACLListView->getYesPixmap() );
+ else if ( partialPerms & ACL_EXECUTE )
+ setPixmap( 4, m_pACLListView->getYesPartialPixmap() );
+ else
+ setPixmap( 4, TQPixmap() );
+}
+
+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) );
+ setPixmap( 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()
+{
+ TQString strEffective = TQString( "---" );
+
+ // 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 TQStringList &users,
+ const TQStringList &groups,
+ const TQStringList &defaultUsers,
+ const TQStringList &defaultGroups,
+ int allowedTypes, int allowedDefaultTypes,
+ bool allowDefaults )
+ : KDialogBase( listView, "edit_entry_dialog", true,
+ i18n( "Edit ACL Entry" ), KDialogBase::Ok|KDialogBase::Cancel,
+ KDialogBase::Ok, false ),
+ 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 )
+{
+ TQWidget *page = new TQWidget( this );
+ setMainWidget( page );
+ TQVBoxLayout *mainLayout = new TQVBoxLayout( page, 0, spacingHint(), "mainLayout" );
+ m_buttonGroup = new TQVButtonGroup( i18n("Entry Type"), page, "bg" );
+
+ if ( allowDefaults ) {
+ m_defaultCB = new TQCheckBox( i18n("Default for new files in this folder"), page, "defaultCB" );
+ mainLayout->addWidget( m_defaultCB );
+ connect( m_defaultCB, TQT_SIGNAL( toggled( bool ) ),
+ this, TQT_SLOT( slotUpdateAllowedUsersAndGroups() ) );
+ connect( m_defaultCB, TQT_SIGNAL( toggled( bool ) ),
+ this, TQT_SLOT( slotUpdateAllowedTypes() ) );
+
+ }
+
+ mainLayout->addWidget( m_buttonGroup );
+
+ TQRadioButton *ownerType = new TQRadioButton( i18n("Owner"), m_buttonGroup, "ownerType" );
+ m_buttonGroup->insert( ownerType, KACLListView::User );
+ TQRadioButton *owningGroupType = new TQRadioButton( i18n("Owning Group"), m_buttonGroup, "owningGroupType" );
+ m_buttonGroup->insert( owningGroupType, KACLListView::Group );
+ TQRadioButton *othersType = new TQRadioButton( i18n("Others"), m_buttonGroup, "othersType" );
+ m_buttonGroup->insert( othersType, KACLListView::Others );
+ TQRadioButton *maskType = new TQRadioButton( i18n("Mask"), m_buttonGroup, "maskType" );
+ m_buttonGroup->insert( maskType, KACLListView::Mask );
+ TQRadioButton *namedUserType = new TQRadioButton( i18n("Named User"), m_buttonGroup, "namesUserType" );
+ m_buttonGroup->insert( namedUserType, KACLListView::NamedUser );
+ TQRadioButton *namedGroupType = new TQRadioButton( i18n("Named Group"), m_buttonGroup, "namedGroupType" );
+ m_buttonGroup->insert( namedGroupType, KACLListView::NamedGroup );
+
+ connect( m_buttonGroup, TQT_SIGNAL( clicked( int ) ),
+ this, TQT_SLOT( slotSelectionChanged( int ) ) );
+
+ m_widgetStack = new TQWidgetStack( page );
+ mainLayout->addWidget( m_widgetStack );
+
+ TQHBox *usersBox = new TQHBox( m_widgetStack );
+ m_widgetStack->addWidget( usersBox, KACLListView::NamedUser );
+
+ TQHBox *groupsBox = new TQHBox( m_widgetStack );
+ m_widgetStack->addWidget( groupsBox, KACLListView::NamedGroup );
+
+ TQLabel *usersLabel = new TQLabel( i18n( "User: " ), usersBox );
+ m_usersCombo = new TQComboBox( false, usersBox, "users" );
+ usersLabel->setBuddy( m_usersCombo );
+
+ TQLabel *groupsLabel = new TQLabel( i18n( "Group: " ), groupsBox );
+ m_groupsCombo = new TQComboBox( false, groupsBox, "groups" );
+ groupsLabel->setBuddy( m_groupsCombo );
+
+ if ( m_item ) {
+ m_buttonGroup->setButton( m_item->type );
+ if ( m_defaultCB )
+ m_defaultCB->setChecked( m_item->isDefault );
+ slotUpdateAllowedTypes();
+ slotSelectionChanged( m_item->type );
+ slotUpdateAllowedUsersAndGroups();
+ if ( m_item->type == KACLListView::NamedUser ) {
+ m_usersCombo->setCurrentText( m_item->qualifier );
+ } else if ( m_item->type == KACLListView::NamedGroup ) {
+ m_groupsCombo->setCurrentText( m_item->qualifier );
+ }
+ } else {
+ // new entry, preselect "named user", arguably the most common one
+ m_buttonGroup->setButton( KACLListView::NamedUser );
+ slotUpdateAllowedTypes();
+ slotSelectionChanged( KACLListView::NamedUser );
+ slotUpdateAllowedUsersAndGroups();
+ }
+ incInitialSize( TQSize( 100, 0 ) );
+}
+
+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_buttonGroup->find( i )->show();
+ else
+ m_buttonGroup->find( i )->hide();
+ }
+}
+
+void EditACLEntryDialog::slotUpdateAllowedUsersAndGroups()
+{
+ const TQString oldUser = m_usersCombo->currentText();
+ const TQString oldGroup = m_groupsCombo->currentText();
+ m_usersCombo->clear();
+ m_groupsCombo->clear();
+ if ( m_defaultCB && m_defaultCB->isChecked() ) {
+ m_usersCombo->insertStringList( m_defaultUsers );
+ if ( m_defaultUsers.find( oldUser ) != m_defaultUsers.end() )
+ m_usersCombo->setCurrentText( oldUser );
+ m_groupsCombo->insertStringList( m_defaultGroups );
+ if ( m_defaultGroups.find( oldGroup ) != m_defaultGroups.end() )
+ m_groupsCombo->setCurrentText( oldGroup );
+ } else {
+ m_usersCombo->insertStringList( m_users );
+ if ( m_users.find( oldUser ) != m_users.end() )
+ m_usersCombo->setCurrentText( oldUser );
+ m_groupsCombo->insertStringList( m_groups );
+ if ( m_groups.find( oldGroup ) != m_groups.end() )
+ m_groupsCombo->setCurrentText( oldGroup );
+ }
+}
+void EditACLEntryDialog::slotOk()
+{
+ KACLListView::EntryType type = static_cast<KACLListView::EntryType>( m_buttonGroup->selectedId() );
+
+ TQString 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();
+
+ KDialogBase::slotOk();
+}
+
+void EditACLEntryDialog::slotSelectionChanged( int id )
+{
+ switch ( id ) {
+ 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->raiseWidget( KACLListView::NamedUser );
+ break;
+ case KACLListView::NamedGroup:
+ m_widgetStack->setEnabled( true );
+ m_widgetStack->raiseWidget( KACLListView::NamedGroup );
+ break;
+ default:
+ break;
+ }
+}
+
+
+KACLListView::KACLListView( TQWidget* parent, const char* name )
+ : KListView( parent, name ),
+ m_hasMask( false ), m_allowDefaults( false )
+{
+ // Add the columns
+ addColumn( i18n( "Type" ) );
+ addColumn( i18n( "Name" ) );
+ addColumn( i18n( "read permission", "r" ) );
+ addColumn( i18n( "write permission", "w" ) );
+ addColumn( i18n( "execute permission", "x" ) );
+ addColumn( i18n( "Effective" ) );
+
+ header()->setClickEnabled( false );
+
+ // Load the avatars
+ for ( int i=0; i < LAST_IDX; ++i ) {
+ s_itemAttributes[i].pixmap = new TQPixmap( qembed_findImage( s_itemAttributes[i].pixmapName ) );
+ }
+ m_yesPixmap = new TQPixmap( qembed_findImage( "yes" ) );
+ m_yesPartialPixmap = new TQPixmap( qembed_findImage( "yespartial" ) );
+
+ setSelectionMode( TQListView::Extended );
+
+ // fill the lists of all legal users and groups
+ struct passwd *user = 0;
+ setpwent();
+ while ( ( user = getpwent() ) != 0 ) {
+ m_allUsers << TQString::fromLatin1( user->pw_name );
+ }
+ endpwent();
+
+ struct group *gr = 0;
+ setgrent();
+ while ( ( gr = getgrent() ) != 0 ) {
+ m_allGroups << TQString::fromLatin1( gr->gr_name );
+ }
+ endgrent();
+ m_allUsers.sort();
+ m_allGroups.sort();
+}
+
+
+KACLListView::~KACLListView()
+{
+ for ( int i=0; i < LAST_IDX; ++i ) {
+ delete s_itemAttributes[i].pixmap;
+ }
+ delete m_yesPixmap;
+ delete m_yesPartialPixmap;
+}
+
+TQStringList KACLListView::allowedUsers( bool defaults, KACLListViewItem *allowedItem )
+{
+ TQStringList allowedUsers = m_allUsers;
+ TQListViewItemIterator it( this );
+ while ( it.current() ) {
+ const KACLListViewItem *item = static_cast<const KACLListViewItem*>( *it );
+ ++it;
+ if ( !item->type == NamedUser || item->isDefault != defaults ) continue;
+ if ( allowedItem && item == allowedItem && allowedItem->isDefault == defaults ) continue;
+ allowedUsers.remove( item->qualifier );
+ }
+ return allowedUsers;
+}
+
+TQStringList KACLListView::allowedGroups( bool defaults, KACLListViewItem *allowedItem )
+{
+ TQStringList allowedGroups = m_allGroups;
+ TQListViewItemIterator it( this );
+ while ( it.current() ) {
+ const KACLListViewItem *item = static_cast<const KACLListViewItem*>( *it );
+ ++it;
+ if ( !item->type == NamedGroup || item->isDefault != defaults ) continue;
+ if ( allowedItem && item == allowedItem && allowedItem->isDefault == defaults ) continue;
+ allowedGroups.remove( item->qualifier );
+ }
+ return allowedGroups;
+}
+
+void KACLListView::fillItemsFromACL( const KACL &pACL, bool defaults )
+{
+ // clear out old entries of that ilk
+ TQListViewItemIterator it( this );
+ while ( KACLListViewItem *item = static_cast<KACLListViewItem*>( it.current() ) ) {
+ ++it;
+ if ( item->isDefault == defaults )
+ delete item;
+ }
+ KACLListViewItem *item =
+ new KACLListViewItem( this, User, pACL.ownerPermissions(), defaults );
+
+ item = new KACLListViewItem( this, Group, pACL.owningGroupPermissions(), defaults );
+
+ item = new KACLListViewItem( this, Others, pACL.othersPermissions(), defaults );
+
+ bool hasMask = false;
+ unsigned short mask = pACL.maskPermissions( hasMask );
+ if ( hasMask ) {
+ item = 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;
+ TQListViewItemIterator it( const_cast<KACLListView*>( this ) );
+ while ( TQListViewItem* qlvi = it.current() ) {
+ ++it;
+ const KACLListViewItem* item = static_cast<KACLListViewItem*>( 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::contentsMousePressEvent( TQMouseEvent * e )
+{
+ TQListViewItem *clickedItem = itemAt( contentsToViewport( e->pos() ) );
+ if ( !clickedItem ) return;
+ // if the click is on an as yet unselected item, select it first
+ if ( !clickedItem->isSelected() )
+ KListView::contentsMousePressEvent( e );
+
+ if ( !currentItem() ) return;
+ int column = header()->sectionAt( e->x() );
+ acl_perm_t perm;
+ switch ( column )
+ {
+ case 2:
+ perm = ACL_READ;
+ break;
+ case 3:
+ perm = ACL_WRITE;
+ break;
+ case 4:
+ perm = ACL_EXECUTE;
+ break;
+ default:
+ return KListView::contentsMousePressEvent( e );
+ }
+ KACLListViewItem* referenceItem = static_cast<KACLListViewItem*>( clickedItem );
+ unsigned short referenceHadItSet = referenceItem->value & perm;
+ TQListViewItemIterator it( this );
+ while ( KACLListViewItem* item = static_cast<KACLListViewItem*>( it.current() ) ) {
+ ++it;
+ if ( !item->isSelected() ) continue;
+ // toggle those with the same value as the clicked item, leave the others
+ if ( referenceHadItSet == ( item->value & perm ) )
+ item->togglePerm( perm );
+ }
+}
+
+void KACLListView::entryClicked( TQListViewItem* pItem, const TQPoint& /*pt*/, int col )
+{
+ if ( !pItem ) return;
+
+ TQListViewItemIterator it( this );
+ while ( KACLListViewItem* item = static_cast<KACLListViewItem*>( it.current() ) ) {
+ ++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()
+{
+ TQListViewItemIterator it( this );
+ KACLListViewItem* pItem;
+ while ( ( pItem = dynamic_cast<KACLListViewItem*>( it.current() ) ) != 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
+{
+ TQListViewItemIterator it( const_cast<KACLListView*>( this ) );
+ while ( it.current() ) {
+ const KACLListViewItem *item = static_cast<const KACLListViewItem*>( it.current() );
+ ++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
+{
+ TQListViewItemIterator it( const_cast<KACLListView*>( this ) );
+ while ( it.current() ) {
+ const KACLListViewItem *item = static_cast<const KACLListViewItem*>( it.current() );
+ ++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();
+ sort();
+ setCurrentItem( item );
+ // TQListView doesn't seem to emit, in this case, and we need to update
+ // the buttons...
+ if ( childCount() == 1 )
+ emit currentChanged( item );
+}
+
+void KACLListView::slotEditEntry()
+{
+ TQListViewItem * current = currentItem();
+ if ( !current ) return;
+ KACLListViewItem *item = static_cast<KACLListViewItem*>( 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();
+ sort();
+}
+
+void KACLListView::slotRemoveEntry()
+{
+ TQListViewItemIterator it( this, TQListViewItemIterator::Selected );
+ while ( it.current() ) {
+ KACLListViewItem *item = static_cast<KACLListViewItem*>( it.current() );
+ ++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 "kacleditwidget.moc"
+#include "kacleditwidget_p.moc"
+#endif
+// vim:set ts=8 sw=4: