kacleditwidget.cpp
00001 /*************************************************************************** 00002 * Copyright (C) 2005 by Sean Harmer <sh@rama.homelinux.org> * 00003 * Till Adam <adam@kde.org> * 00004 * * 00005 * This program is free software; you can redistribute it and/or modify * 00006 * it under the terms of the GNU Library General Public License as * 00007 * published by the Free Software Foundation; either version 2 of the * 00008 * License, or (at your option) any later version. * 00009 * * 00010 * This program is distributed in the hope that it will be useful, * 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00013 * GNU General Public License for more details. * 00014 * * 00015 * You should have received a copy of the GNU General Public License * 00016 * along with this program; if not, write to the * 00017 * Free Software Foundation, Inc., * 00018 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * 00019 ***************************************************************************/ 00020 00021 00022 #include "kacleditwidget.h" 00023 #include "kacleditwidget_p.h" 00024 00025 #ifdef USE_POSIX_ACL 00026 00027 #include <tqpainter.h> 00028 #include <tqptrlist.h> 00029 #include <tqvbox.h> 00030 #include <tqhbox.h> 00031 #include <tqpushbutton.h> 00032 #include <tqvbuttongroup.h> 00033 #include <tqradiobutton.h> 00034 #include <tqcombobox.h> 00035 #include <tqlabel.h> 00036 #include <tqcheckbox.h> 00037 #include <tqlayout.h> 00038 #include <tqwidgetstack.h> 00039 #include <tqheader.h> 00040 00041 #include <klocale.h> 00042 #include <kfileitem.h> 00043 #include <kdebug.h> 00044 #include <kdialog.h> 00045 #include <kdialogbase.h> 00046 00047 #ifdef HAVE_ACL_LIBACL_H 00048 # include <acl/libacl.h> 00049 #endif 00050 extern "C" { 00051 #include <pwd.h> 00052 #include <grp.h> 00053 } 00054 #include <assert.h> 00055 00056 #include "images.h" 00057 00058 static struct { 00059 const char* label; 00060 const char* pixmapName; 00061 TQPixmap* pixmap; 00062 } s_itemAttributes[] = { 00063 { I18N_NOOP( "Owner" ), "user-grey", 0 }, 00064 { I18N_NOOP( "Owning Group" ), "group-grey", 0 }, 00065 { I18N_NOOP( "Others" ), "others-grey", 0 }, 00066 { I18N_NOOP( "Mask" ), "mask", 0 }, 00067 { I18N_NOOP( "Named User" ), "user", 0 }, 00068 { I18N_NOOP( "Named Group" ), "group", 0 }, 00069 }; 00070 00071 KACLEditWidget::KACLEditWidget( TQWidget *parent, const char *name ) 00072 :TQWidget( parent, name ) 00073 { 00074 TQHBox *hbox = new TQHBox( parent ); 00075 hbox->setSpacing( KDialog::spacingHint() ); 00076 m_listView = new KACLListView( hbox, "acl_listview" ); 00077 connect( m_listView, TQT_SIGNAL( selectionChanged() ), 00078 this, TQT_SLOT( slotUpdateButtons() ) ); 00079 TQVBox *vbox = new TQVBox( hbox ); 00080 vbox->setSpacing( KDialog::spacingHint() ); 00081 m_AddBtn = new TQPushButton( i18n( "Add Entry..." ), vbox, "add_entry_button" ); 00082 connect( m_AddBtn, TQT_SIGNAL( clicked() ), m_listView, TQT_SLOT( slotAddEntry() ) ); 00083 m_EditBtn = new TQPushButton( i18n( "Edit Entry..." ), vbox, "edit_entry_button" ); 00084 connect( m_EditBtn, TQT_SIGNAL( clicked() ), m_listView, TQT_SLOT( slotEditEntry() ) ); 00085 m_DelBtn = new TQPushButton( i18n( "Delete Entry" ), vbox, "delete_entry_button" ); 00086 connect( m_DelBtn, TQT_SIGNAL( clicked() ), m_listView, TQT_SLOT( slotRemoveEntry() ) ); 00087 TQWidget *spacer = new TQWidget( vbox ); 00088 spacer->setSizePolicy( TQSizePolicy::Minimum, TQSizePolicy::Expanding ); 00089 slotUpdateButtons(); 00090 } 00091 00092 void KACLEditWidget::slotUpdateButtons() 00093 { 00094 bool atLeastOneIsNotDeletable = false; 00095 bool atLeastOneIsNotAllowedToChangeType = false; 00096 int selectedCount = 0; 00097 TQListViewItemIterator it( m_listView, TQListViewItemIterator::Selected ); 00098 while ( KACLListViewItem *item = dynamic_cast<KACLListViewItem*>( it.current() ) ) { 00099 ++it; ++selectedCount; 00100 if ( !item->isDeletable() ) 00101 atLeastOneIsNotDeletable = true; 00102 if ( !item->isAllowedToChangeType() ) 00103 atLeastOneIsNotAllowedToChangeType = true; 00104 } 00105 m_EditBtn->setEnabled( selectedCount && !atLeastOneIsNotAllowedToChangeType ); 00106 m_DelBtn->setEnabled( selectedCount && !atLeastOneIsNotDeletable ); 00107 } 00108 00109 KACL KACLEditWidget::getACL() const 00110 { 00111 return m_listView->getACL(); 00112 } 00113 00114 KACL KACLEditWidget::getDefaultACL() const 00115 { 00116 return m_listView->getDefaultACL(); 00117 } 00118 00119 void KACLEditWidget::setACL( const KACL &acl ) 00120 { 00121 return m_listView->setACL( acl ); 00122 } 00123 00124 void KACLEditWidget::setDefaultACL( const KACL &acl ) 00125 { 00126 return m_listView->setDefaultACL( acl ); 00127 } 00128 00129 void KACLEditWidget::setAllowDefaults( bool value ) 00130 { 00131 m_listView->setAllowDefaults( value ); 00132 } 00133 00134 void KACLEditWidget::setReadOnly( bool on ) 00135 { 00136 m_listView->setEnabled( !on ); 00137 m_AddBtn->setEnabled( !on ); 00138 if ( !on ) 00139 slotUpdateButtons(); 00140 } 00141 00142 KACLListViewItem::KACLListViewItem( TQListView* parent, 00143 KACLListView::EntryType _type, 00144 unsigned short _value, bool defaults, 00145 const TQString& _qualifier ) 00146 : KListViewItem( parent, parent->lastItem() ), // we want to append 00147 type( _type ), value( _value ), isDefault( defaults ), 00148 qualifier( _qualifier ), isPartial( false ) 00149 { 00150 m_pACLListView = dynamic_cast<KACLListView*>( parent ); 00151 repaint(); 00152 } 00153 00154 00155 KACLListViewItem::~ KACLListViewItem() 00156 { 00157 00158 } 00159 00160 TQString KACLListViewItem::key( int, bool ) const 00161 { 00162 TQString key; 00163 if ( !isDefault ) 00164 key = "A"; 00165 else 00166 key = "B"; 00167 switch ( type ) 00168 { 00169 case KACLListView::User: 00170 key += "A"; 00171 break; 00172 case KACLListView::Group: 00173 key += "B"; 00174 break; 00175 case KACLListView::Others: 00176 key += "C"; 00177 break; 00178 case KACLListView::Mask: 00179 key += "D"; 00180 break; 00181 case KACLListView::NamedUser: 00182 key += "E" + text( 1 ); 00183 break; 00184 case KACLListView::NamedGroup: 00185 key += "F" + text( 1 ); 00186 break; 00187 default: 00188 key += text( 0 ); 00189 break; 00190 } 00191 return key; 00192 } 00193 00194 void KACLListViewItem::paintCell( TQPainter* p, const TQColorGroup &cg, 00195 int column, int width, int alignment ) 00196 { 00197 TQColorGroup mycg = cg; 00198 if ( isDefault ) { 00199 mycg.setColor( TQColorGroup::Text, TQColor( 0, 0, 255 ) ); 00200 } 00201 if ( isPartial ) { 00202 TQFont font = p->font(); 00203 font.setItalic( true ); 00204 mycg.setColor( TQColorGroup::Text, TQColor( 100, 100, 100 ) ); 00205 p->setFont( font ); 00206 } 00207 KListViewItem::paintCell( p, mycg, column, width, alignment ); 00208 00209 KACLListViewItem *below =0; 00210 if ( itemBelow() ) 00211 below = static_cast<KACLListViewItem*>( itemBelow() ); 00212 const bool lastUser = type == KACLListView::NamedUser && below && below->type == KACLListView::NamedGroup; 00213 const bool lastNonDefault = !isDefault && below && below->isDefault; 00214 if ( type == KACLListView::Mask || lastUser || lastNonDefault ) 00215 { 00216 p->setPen( TQPen( Qt::gray, 0, TQPen::DotLine ) ); 00217 if ( type == KACLListView::Mask ) 00218 p->drawLine( 0, 0, width - 1, 0 ); 00219 p->drawLine( 0, height() - 1, width - 1, height() - 1 ); 00220 } 00221 } 00222 00223 00224 void KACLListViewItem::updatePermPixmaps() 00225 { 00226 unsigned int partialPerms = value; 00227 00228 if ( value & ACL_READ ) 00229 setPixmap( 2, m_pACLListView->getYesPixmap() ); 00230 else if ( partialPerms & ACL_READ ) 00231 setPixmap( 2, m_pACLListView->getYesPartialPixmap() ); 00232 else 00233 setPixmap( 2, TQPixmap() ); 00234 00235 if ( value & ACL_WRITE ) 00236 setPixmap( 3, m_pACLListView->getYesPixmap() ); 00237 else if ( partialPerms & ACL_WRITE ) 00238 setPixmap( 3, m_pACLListView->getYesPartialPixmap() ); 00239 else 00240 setPixmap( 3, TQPixmap() ); 00241 00242 if ( value & ACL_EXECUTE ) 00243 setPixmap( 4, m_pACLListView->getYesPixmap() ); 00244 else if ( partialPerms & ACL_EXECUTE ) 00245 setPixmap( 4, m_pACLListView->getYesPartialPixmap() ); 00246 else 00247 setPixmap( 4, TQPixmap() ); 00248 } 00249 00250 void KACLListViewItem::repaint() 00251 { 00252 int idx = 0; 00253 switch ( type ) 00254 { 00255 case KACLListView::User: 00256 idx = KACLListView::OWNER_IDX; 00257 break; 00258 case KACLListView::Group: 00259 idx = KACLListView::GROUP_IDX; 00260 break; 00261 case KACLListView::Others: 00262 idx = KACLListView::OTHERS_IDX; 00263 break; 00264 case KACLListView::Mask: 00265 idx = KACLListView::MASK_IDX; 00266 break; 00267 case KACLListView::NamedUser: 00268 idx = KACLListView::NAMED_USER_IDX; 00269 break; 00270 case KACLListView::NamedGroup: 00271 idx = KACLListView::NAMED_GROUP_IDX; 00272 break; 00273 default: 00274 idx = KACLListView::OWNER_IDX; 00275 break; 00276 } 00277 setText( 0, i18n(s_itemAttributes[idx].label) ); 00278 setPixmap( 0, *s_itemAttributes[idx].pixmap ); 00279 if ( isDefault ) 00280 setText( 0, text( 0 ) + i18n( " (Default)" ) ); 00281 setText( 1, qualifier ); 00282 // Set the pixmaps for which of the perms are set 00283 updatePermPixmaps(); 00284 } 00285 00286 void KACLListViewItem::calcEffectiveRights() 00287 { 00288 TQString strEffective = TQString( "---" ); 00289 00290 // Do we need to worry about the mask entry? It applies to named users, 00291 // owning group, and named groups 00292 if ( m_pACLListView->hasMaskEntry() 00293 && ( type == KACLListView::NamedUser 00294 || type == KACLListView::Group 00295 || type == KACLListView::NamedGroup ) 00296 && !isDefault ) 00297 { 00298 00299 strEffective[0] = ( m_pACLListView->maskPermissions() & value & ACL_READ ) ? 'r' : '-'; 00300 strEffective[1] = ( m_pACLListView->maskPermissions() & value & ACL_WRITE ) ? 'w' : '-'; 00301 strEffective[2] = ( m_pACLListView->maskPermissions() & value & ACL_EXECUTE ) ? 'x' : '-'; 00302 /* 00303 // What about any partial perms? 00304 if ( maskPerms & partialPerms & ACL_READ || // Partial perms on entry 00305 maskPartialPerms & perms & ACL_READ || // Partial perms on mask 00306 maskPartialPerms & partialPerms & ACL_READ ) // Partial perms on mask and entry 00307 strEffective[0] = 'R'; 00308 if ( maskPerms & partialPerms & ACL_WRITE || // Partial perms on entry 00309 maskPartialPerms & perms & ACL_WRITE || // Partial perms on mask 00310 maskPartialPerms & partialPerms & ACL_WRITE ) // Partial perms on mask and entry 00311 strEffective[1] = 'W'; 00312 if ( maskPerms & partialPerms & ACL_EXECUTE || // Partial perms on entry 00313 maskPartialPerms & perms & ACL_EXECUTE || // Partial perms on mask 00314 maskPartialPerms & partialPerms & ACL_EXECUTE ) // Partial perms on mask and entry 00315 strEffective[2] = 'X'; 00316 */ 00317 } 00318 else 00319 { 00320 // No, the effective value are just the value in this entry 00321 strEffective[0] = ( value & ACL_READ ) ? 'r' : '-'; 00322 strEffective[1] = ( value & ACL_WRITE ) ? 'w' : '-'; 00323 strEffective[2] = ( value & ACL_EXECUTE ) ? 'x' : '-'; 00324 00325 /* 00326 // What about any partial perms? 00327 if ( partialPerms & ACL_READ ) 00328 strEffective[0] = 'R'; 00329 if ( partialPerms & ACL_WRITE ) 00330 strEffective[1] = 'W'; 00331 if ( partialPerms & ACL_EXECUTE ) 00332 strEffective[2] = 'X'; 00333 */ 00334 } 00335 setText( 5, strEffective ); 00336 } 00337 00338 bool KACLListViewItem::isDeletable() const 00339 { 00340 bool isMaskAndDeletable = false; 00341 if (type == KACLListView::Mask ) { 00342 if ( !isDefault && m_pACLListView->maskCanBeDeleted() ) 00343 isMaskAndDeletable = true; 00344 else if ( isDefault && m_pACLListView->defaultMaskCanBeDeleted() ) 00345 isMaskAndDeletable = true; 00346 } 00347 return type != KACLListView::User && 00348 type != KACLListView::Group && 00349 type != KACLListView::Others && 00350 ( type != KACLListView::Mask || isMaskAndDeletable ); 00351 } 00352 00353 bool KACLListViewItem::isAllowedToChangeType() const 00354 { 00355 return type != KACLListView::User && 00356 type != KACLListView::Group && 00357 type != KACLListView::Others && 00358 type != KACLListView::Mask; 00359 } 00360 00361 void KACLListViewItem::togglePerm( acl_perm_t perm ) 00362 { 00363 value ^= perm; // Toggle the perm 00364 if ( type == KACLListView::Mask && !isDefault ) { 00365 m_pACLListView->setMaskPermissions( value ); 00366 } 00367 calcEffectiveRights(); 00368 updatePermPixmaps(); 00369 /* 00370 // If the perm is in the partial perms then remove it. i.e. Once 00371 // a user changes a partial perm it then applies to all selected files. 00372 if ( m_pEntry->m_partialPerms & perm ) 00373 m_pEntry->m_partialPerms ^= perm; 00374 00375 m_pEntry->setPartialEntry( false ); 00376 // Make sure that all entries have their effective rights calculated if 00377 // we are changing the ACL_MASK entry. 00378 if ( type == Mask ) 00379 { 00380 m_pACLListView->setMaskPartialPermissions( m_pEntry->m_partialPerms ); 00381 m_pACLListView->setMaskPermissions( value ); 00382 m_pACLListView->calculateEffectiveRights(); 00383 } 00384 */ 00385 } 00386 00387 00388 00389 EditACLEntryDialog::EditACLEntryDialog( KACLListView *listView, KACLListViewItem *item, 00390 const TQStringList &users, 00391 const TQStringList &groups, 00392 const TQStringList &defaultUsers, 00393 const TQStringList &defaultGroups, 00394 int allowedTypes, int allowedDefaultTypes, 00395 bool allowDefaults ) 00396 : KDialogBase( listView, "edit_entry_dialog", true, 00397 i18n( "Edit ACL Entry" ), KDialogBase::Ok|KDialogBase::Cancel, 00398 KDialogBase::Ok, false ), 00399 m_listView( listView ), m_item( item ), m_users( users ), m_groups( groups ), 00400 m_defaultUsers( defaultUsers ), m_defaultGroups( defaultGroups ), 00401 m_allowedTypes( allowedTypes ), m_allowedDefaultTypes( allowedDefaultTypes ), 00402 m_defaultCB( 0 ) 00403 { 00404 TQWidget *page = new TQWidget( this ); 00405 setMainWidget( page ); 00406 TQVBoxLayout *mainLayout = new TQVBoxLayout( page, 0, spacingHint(), "mainLayout" ); 00407 m_buttonGroup = new TQVButtonGroup( i18n("Entry Type"), page, "bg" ); 00408 00409 if ( allowDefaults ) { 00410 m_defaultCB = new TQCheckBox( i18n("Default for new files in this folder"), page, "defaultCB" ); 00411 mainLayout->addWidget( m_defaultCB ); 00412 connect( m_defaultCB, TQT_SIGNAL( toggled( bool ) ), 00413 this, TQT_SLOT( slotUpdateAllowedUsersAndGroups() ) ); 00414 connect( m_defaultCB, TQT_SIGNAL( toggled( bool ) ), 00415 this, TQT_SLOT( slotUpdateAllowedTypes() ) ); 00416 00417 } 00418 00419 mainLayout->addWidget( m_buttonGroup ); 00420 00421 TQRadioButton *ownerType = new TQRadioButton( i18n("Owner"), m_buttonGroup, "ownerType" ); 00422 m_buttonGroup->insert( ownerType, KACLListView::User ); 00423 TQRadioButton *owningGroupType = new TQRadioButton( i18n("Owning Group"), m_buttonGroup, "owningGroupType" ); 00424 m_buttonGroup->insert( owningGroupType, KACLListView::Group ); 00425 TQRadioButton *othersType = new TQRadioButton( i18n("Others"), m_buttonGroup, "othersType" ); 00426 m_buttonGroup->insert( othersType, KACLListView::Others ); 00427 TQRadioButton *maskType = new TQRadioButton( i18n("Mask"), m_buttonGroup, "maskType" ); 00428 m_buttonGroup->insert( maskType, KACLListView::Mask ); 00429 TQRadioButton *namedUserType = new TQRadioButton( i18n("Named User"), m_buttonGroup, "namesUserType" ); 00430 m_buttonGroup->insert( namedUserType, KACLListView::NamedUser ); 00431 TQRadioButton *namedGroupType = new TQRadioButton( i18n("Named Group"), m_buttonGroup, "namedGroupType" ); 00432 m_buttonGroup->insert( namedGroupType, KACLListView::NamedGroup ); 00433 00434 connect( m_buttonGroup, TQT_SIGNAL( clicked( int ) ), 00435 this, TQT_SLOT( slotSelectionChanged( int ) ) ); 00436 00437 m_widgetStack = new TQWidgetStack( page ); 00438 mainLayout->addWidget( m_widgetStack ); 00439 00440 TQHBox *usersBox = new TQHBox( m_widgetStack ); 00441 m_widgetStack->addWidget( usersBox, KACLListView::NamedUser ); 00442 00443 TQHBox *groupsBox = new TQHBox( m_widgetStack ); 00444 m_widgetStack->addWidget( groupsBox, KACLListView::NamedGroup ); 00445 00446 TQLabel *usersLabel = new TQLabel( i18n( "User: " ), usersBox ); 00447 m_usersCombo = new TQComboBox( false, usersBox, "users" ); 00448 usersLabel->setBuddy( m_usersCombo ); 00449 00450 TQLabel *groupsLabel = new TQLabel( i18n( "Group: " ), groupsBox ); 00451 m_groupsCombo = new TQComboBox( false, groupsBox, "groups" ); 00452 groupsLabel->setBuddy( m_groupsCombo ); 00453 00454 if ( m_item ) { 00455 m_buttonGroup->setButton( m_item->type ); 00456 if ( m_defaultCB ) 00457 m_defaultCB->setChecked( m_item->isDefault ); 00458 slotUpdateAllowedTypes(); 00459 slotSelectionChanged( m_item->type ); 00460 slotUpdateAllowedUsersAndGroups(); 00461 if ( m_item->type == KACLListView::NamedUser ) { 00462 m_usersCombo->setCurrentText( m_item->qualifier ); 00463 } else if ( m_item->type == KACLListView::NamedGroup ) { 00464 m_groupsCombo->setCurrentText( m_item->qualifier ); 00465 } 00466 } else { 00467 // new entry, preselect "named user", arguably the most common one 00468 m_buttonGroup->setButton( KACLListView::NamedUser ); 00469 slotUpdateAllowedTypes(); 00470 slotSelectionChanged( KACLListView::NamedUser ); 00471 slotUpdateAllowedUsersAndGroups(); 00472 } 00473 incInitialSize( TQSize( 100, 0 ) ); 00474 } 00475 00476 void EditACLEntryDialog::slotUpdateAllowedTypes() 00477 { 00478 int allowedTypes = m_allowedTypes; 00479 if ( m_defaultCB && m_defaultCB->isChecked() ) { 00480 allowedTypes = m_allowedDefaultTypes; 00481 } 00482 for ( int i=1; i < KACLListView::AllTypes; i=i*2 ) { 00483 if ( allowedTypes & i ) 00484 m_buttonGroup->find( i )->show(); 00485 else 00486 m_buttonGroup->find( i )->hide(); 00487 } 00488 } 00489 00490 void EditACLEntryDialog::slotUpdateAllowedUsersAndGroups() 00491 { 00492 const TQString oldUser = m_usersCombo->currentText(); 00493 const TQString oldGroup = m_groupsCombo->currentText(); 00494 m_usersCombo->clear(); 00495 m_groupsCombo->clear(); 00496 if ( m_defaultCB && m_defaultCB->isChecked() ) { 00497 m_usersCombo->insertStringList( m_defaultUsers ); 00498 if ( m_defaultUsers.find( oldUser ) != m_defaultUsers.end() ) 00499 m_usersCombo->setCurrentText( oldUser ); 00500 m_groupsCombo->insertStringList( m_defaultGroups ); 00501 if ( m_defaultGroups.find( oldGroup ) != m_defaultGroups.end() ) 00502 m_groupsCombo->setCurrentText( oldGroup ); 00503 } else { 00504 m_usersCombo->insertStringList( m_users ); 00505 if ( m_users.find( oldUser ) != m_users.end() ) 00506 m_usersCombo->setCurrentText( oldUser ); 00507 m_groupsCombo->insertStringList( m_groups ); 00508 if ( m_groups.find( oldGroup ) != m_groups.end() ) 00509 m_groupsCombo->setCurrentText( oldGroup ); 00510 } 00511 } 00512 void EditACLEntryDialog::slotOk() 00513 { 00514 KACLListView::EntryType type = static_cast<KACLListView::EntryType>( m_buttonGroup->selectedId() ); 00515 00516 TQString qualifier; 00517 if ( type == KACLListView::NamedUser ) 00518 qualifier = m_usersCombo->currentText(); 00519 if ( type == KACLListView::NamedGroup ) 00520 qualifier = m_groupsCombo->currentText(); 00521 00522 if ( !m_item ) { 00523 m_item = new KACLListViewItem( m_listView, type, ACL_READ | ACL_WRITE | ACL_EXECUTE, false, qualifier ); 00524 } else { 00525 m_item->type = type; 00526 m_item->qualifier = qualifier; 00527 } 00528 if ( m_defaultCB ) 00529 m_item->isDefault = m_defaultCB->isChecked(); 00530 m_item->repaint(); 00531 00532 KDialogBase::slotOk(); 00533 } 00534 00535 void EditACLEntryDialog::slotSelectionChanged( int id ) 00536 { 00537 switch ( id ) { 00538 case KACLListView::User: 00539 case KACLListView::Group: 00540 case KACLListView::Others: 00541 case KACLListView::Mask: 00542 m_widgetStack->setEnabled( false ); 00543 break; 00544 case KACLListView::NamedUser: 00545 m_widgetStack->setEnabled( true ); 00546 m_widgetStack->raiseWidget( KACLListView::NamedUser ); 00547 break; 00548 case KACLListView::NamedGroup: 00549 m_widgetStack->setEnabled( true ); 00550 m_widgetStack->raiseWidget( KACLListView::NamedGroup ); 00551 break; 00552 default: 00553 break; 00554 } 00555 } 00556 00557 00558 KACLListView::KACLListView( TQWidget* parent, const char* name ) 00559 : KListView( parent, name ), 00560 m_hasMask( false ), m_allowDefaults( false ) 00561 { 00562 // Add the columns 00563 addColumn( i18n( "Type" ) ); 00564 addColumn( i18n( "Name" ) ); 00565 addColumn( i18n( "read permission", "r" ) ); 00566 addColumn( i18n( "write permission", "w" ) ); 00567 addColumn( i18n( "execute permission", "x" ) ); 00568 addColumn( i18n( "Effective" ) ); 00569 00570 header()->setClickEnabled( false ); 00571 00572 // Load the avatars 00573 for ( int i=0; i < LAST_IDX; ++i ) { 00574 s_itemAttributes[i].pixmap = new TQPixmap( qembed_findImage( s_itemAttributes[i].pixmapName ) ); 00575 } 00576 m_yesPixmap = new TQPixmap( qembed_findImage( "yes" ) ); 00577 m_yesPartialPixmap = new TQPixmap( qembed_findImage( "yespartial" ) ); 00578 00579 setSelectionMode( TQListView::Extended ); 00580 00581 // fill the lists of all legal users and groups 00582 struct passwd *user = 0; 00583 setpwent(); 00584 while ( ( user = getpwent() ) != 0 ) { 00585 m_allUsers << TQString::fromLatin1( user->pw_name ); 00586 } 00587 endpwent(); 00588 00589 struct group *gr = 0; 00590 setgrent(); 00591 while ( ( gr = getgrent() ) != 0 ) { 00592 m_allGroups << TQString::fromLatin1( gr->gr_name ); 00593 } 00594 endgrent(); 00595 m_allUsers.sort(); 00596 m_allGroups.sort(); 00597 } 00598 00599 00600 KACLListView::~KACLListView() 00601 { 00602 for ( int i=0; i < LAST_IDX; ++i ) { 00603 delete s_itemAttributes[i].pixmap; 00604 } 00605 delete m_yesPixmap; 00606 delete m_yesPartialPixmap; 00607 } 00608 00609 TQStringList KACLListView::allowedUsers( bool defaults, KACLListViewItem *allowedItem ) 00610 { 00611 TQStringList allowedUsers = m_allUsers; 00612 TQListViewItemIterator it( this ); 00613 while ( it.current() ) { 00614 const KACLListViewItem *item = static_cast<const KACLListViewItem*>( *it ); 00615 ++it; 00616 if ( !item->type == NamedUser || item->isDefault != defaults ) continue; 00617 if ( allowedItem && item == allowedItem && allowedItem->isDefault == defaults ) continue; 00618 allowedUsers.remove( item->qualifier ); 00619 } 00620 return allowedUsers; 00621 } 00622 00623 TQStringList KACLListView::allowedGroups( bool defaults, KACLListViewItem *allowedItem ) 00624 { 00625 TQStringList allowedGroups = m_allGroups; 00626 TQListViewItemIterator it( this ); 00627 while ( it.current() ) { 00628 const KACLListViewItem *item = static_cast<const KACLListViewItem*>( *it ); 00629 ++it; 00630 if ( !item->type == NamedGroup || item->isDefault != defaults ) continue; 00631 if ( allowedItem && item == allowedItem && allowedItem->isDefault == defaults ) continue; 00632 allowedGroups.remove( item->qualifier ); 00633 } 00634 return allowedGroups; 00635 } 00636 00637 void KACLListView::fillItemsFromACL( const KACL &pACL, bool defaults ) 00638 { 00639 // clear out old entries of that ilk 00640 TQListViewItemIterator it( this ); 00641 while ( KACLListViewItem *item = static_cast<KACLListViewItem*>( it.current() ) ) { 00642 ++it; 00643 if ( item->isDefault == defaults ) 00644 delete item; 00645 } 00646 KACLListViewItem *item = 00647 new KACLListViewItem( this, User, pACL.ownerPermissions(), defaults ); 00648 00649 item = new KACLListViewItem( this, Group, pACL.owningGroupPermissions(), defaults ); 00650 00651 item = new KACLListViewItem( this, Others, pACL.othersPermissions(), defaults ); 00652 00653 bool hasMask = false; 00654 unsigned short mask = pACL.maskPermissions( hasMask ); 00655 if ( hasMask ) { 00656 item = new KACLListViewItem( this, Mask, mask, defaults ); 00657 } 00658 00659 // read all named user entries 00660 const ACLUserPermissionsList &userList = pACL.allUserPermissions(); 00661 ACLUserPermissionsConstIterator itu = userList.begin(); 00662 while ( itu != userList.end() ) { 00663 new KACLListViewItem( this, NamedUser, (*itu).second, defaults, (*itu).first ); 00664 ++itu; 00665 } 00666 00667 // and now all named groups 00668 const ACLUserPermissionsList &groupList = pACL.allGroupPermissions(); 00669 ACLUserPermissionsConstIterator itg = groupList.begin(); 00670 while ( itg != groupList.end() ) { 00671 new KACLListViewItem( this, NamedGroup, (*itg).second, defaults, (*itg).first ); 00672 ++itg; 00673 } 00674 } 00675 00676 void KACLListView::setACL( const KACL &acl ) 00677 { 00678 if ( !acl.isValid() ) return; 00679 // Remove any entries left over from displaying a previous ACL 00680 m_ACL = acl; 00681 fillItemsFromACL( m_ACL ); 00682 00683 m_mask = acl.maskPermissions( m_hasMask ); 00684 calculateEffectiveRights(); 00685 } 00686 00687 void KACLListView::setDefaultACL( const KACL &acl ) 00688 { 00689 if ( !acl.isValid() ) return; 00690 m_defaultACL = acl; 00691 fillItemsFromACL( m_defaultACL, true ); 00692 calculateEffectiveRights(); 00693 } 00694 00695 KACL KACLListView::itemsToACL( bool defaults ) const 00696 { 00697 KACL newACL( 0 ); 00698 bool atLeastOneEntry = false; 00699 ACLUserPermissionsList users; 00700 ACLGroupPermissionsList groups; 00701 TQListViewItemIterator it( const_cast<KACLListView*>( this ) ); 00702 while ( TQListViewItem* qlvi = it.current() ) { 00703 ++it; 00704 const KACLListViewItem* item = static_cast<KACLListViewItem*>( qlvi ); 00705 if ( item->isDefault != defaults ) continue; 00706 atLeastOneEntry = true; 00707 switch ( item->type ) { 00708 case User: 00709 newACL.setOwnerPermissions( item->value ); 00710 break; 00711 case Group: 00712 newACL.setOwningGroupPermissions( item->value ); 00713 break; 00714 case Others: 00715 newACL.setOthersPermissions( item->value ); 00716 break; 00717 case Mask: 00718 newACL.setMaskPermissions( item->value ); 00719 break; 00720 case NamedUser: 00721 users.append( qMakePair( item->text( 1 ), item->value ) ); 00722 break; 00723 case NamedGroup: 00724 groups.append( qMakePair( item->text( 1 ), item->value ) ); 00725 break; 00726 default: 00727 break; 00728 } 00729 } 00730 if ( atLeastOneEntry ) { 00731 newACL.setAllUserPermissions( users ); 00732 newACL.setAllGroupPermissions( groups ); 00733 if ( newACL.isValid() ) 00734 return newACL; 00735 } 00736 return KACL(); 00737 } 00738 00739 KACL KACLListView::getACL() 00740 { 00741 return itemsToACL( false ); 00742 } 00743 00744 00745 KACL KACLListView::getDefaultACL() 00746 { 00747 return itemsToACL( true ); 00748 } 00749 00750 void KACLListView::contentsMousePressEvent( TQMouseEvent * e ) 00751 { 00752 TQListViewItem *clickedItem = itemAt( contentsToViewport( e->pos() ) ); 00753 if ( !clickedItem ) return; 00754 // if the click is on an as yet unselected item, select it first 00755 if ( !clickedItem->isSelected() ) 00756 KListView::contentsMousePressEvent( e ); 00757 00758 if ( !currentItem() ) return; 00759 int column = header()->sectionAt( e->x() ); 00760 acl_perm_t perm; 00761 switch ( column ) 00762 { 00763 case 2: 00764 perm = ACL_READ; 00765 break; 00766 case 3: 00767 perm = ACL_WRITE; 00768 break; 00769 case 4: 00770 perm = ACL_EXECUTE; 00771 break; 00772 default: 00773 return KListView::contentsMousePressEvent( e ); 00774 } 00775 KACLListViewItem* referenceItem = static_cast<KACLListViewItem*>( clickedItem ); 00776 unsigned short referenceHadItSet = referenceItem->value & perm; 00777 TQListViewItemIterator it( this ); 00778 while ( KACLListViewItem* item = static_cast<KACLListViewItem*>( it.current() ) ) { 00779 ++it; 00780 if ( !item->isSelected() ) continue; 00781 // toggle those with the same value as the clicked item, leave the others 00782 if ( referenceHadItSet == ( item->value & perm ) ) 00783 item->togglePerm( perm ); 00784 } 00785 } 00786 00787 void KACLListView::entryClicked( TQListViewItem* pItem, const TQPoint& /*pt*/, int col ) 00788 { 00789 if ( !pItem ) return; 00790 00791 TQListViewItemIterator it( this ); 00792 while ( KACLListViewItem* item = static_cast<KACLListViewItem*>( it.current() ) ) { 00793 ++it; 00794 if ( !item->isSelected() ) continue; 00795 switch ( col ) 00796 { 00797 case 2: 00798 item->togglePerm( ACL_READ ); 00799 break; 00800 case 3: 00801 item->togglePerm( ACL_WRITE ); 00802 break; 00803 case 4: 00804 item->togglePerm( ACL_EXECUTE ); 00805 break; 00806 00807 default: 00808 ; // Do nothing 00809 } 00810 } 00811 /* 00812 // Has the user changed one of the required entries in a default ACL? 00813 if ( m_pACL->aclType() == ACL_TYPE_DEFAULT && 00814 ( col == 2 || col == 3 || col == 4 ) && 00815 ( pACLItem->entryType() == ACL_USER_OBJ || 00816 pACLItem->entryType() == ACL_GROUP_OBJ || 00817 pACLItem->entryType() == ACL_OTHER ) ) 00818 { 00819 // Mark the required entries as no longer being partial entries. 00820 // That is, they will get applied to all selected directories. 00821 KACLListViewItem* pUserObj = findACLEntryByType( this, ACL_USER_OBJ ); 00822 pUserObj->entry()->setPartialEntry( false ); 00823 00824 KACLListViewItem* pGroupObj = findACLEntryByType( this, ACL_GROUP_OBJ ); 00825 pGroupObj->entry()->setPartialEntry( false ); 00826 00827 KACLListViewItem* pOther = findACLEntryByType( this, ACL_OTHER ); 00828 pOther->entry()->setPartialEntry( false ); 00829 00830 update(); 00831 } 00832 */ 00833 } 00834 00835 00836 void KACLListView::calculateEffectiveRights() 00837 { 00838 TQListViewItemIterator it( this ); 00839 KACLListViewItem* pItem; 00840 while ( ( pItem = dynamic_cast<KACLListViewItem*>( it.current() ) ) != 0 ) 00841 { 00842 ++it; 00843 pItem->calcEffectiveRights(); 00844 } 00845 } 00846 00847 00848 unsigned short KACLListView::maskPermissions() const 00849 { 00850 return m_mask; 00851 } 00852 00853 00854 void KACLListView::setMaskPermissions( unsigned short maskPerms ) 00855 { 00856 m_mask = maskPerms; 00857 calculateEffectiveRights(); 00858 } 00859 00860 00861 acl_perm_t KACLListView::maskPartialPermissions() const 00862 { 00863 // return m_pMaskEntry->m_partialPerms; 00864 return 0; 00865 } 00866 00867 00868 void KACLListView::setMaskPartialPermissions( acl_perm_t /*maskPartialPerms*/ ) 00869 { 00870 //m_pMaskEntry->m_partialPerms = maskPartialPerms; 00871 calculateEffectiveRights(); 00872 } 00873 00874 bool KACLListView::hasDefaultEntries() const 00875 { 00876 TQListViewItemIterator it( const_cast<KACLListView*>( this ) ); 00877 while ( it.current() ) { 00878 const KACLListViewItem *item = static_cast<const KACLListViewItem*>( it.current() ); 00879 ++it; 00880 if ( item->isDefault ) return true; 00881 } 00882 return false; 00883 } 00884 00885 const KACLListViewItem* KACLListView::findDefaultItemByType( EntryType type ) const 00886 { 00887 return findItemByType( type, true ); 00888 } 00889 00890 const KACLListViewItem* KACLListView::findItemByType( EntryType type, bool defaults ) const 00891 { 00892 TQListViewItemIterator it( const_cast<KACLListView*>( this ) ); 00893 while ( it.current() ) { 00894 const KACLListViewItem *item = static_cast<const KACLListViewItem*>( it.current() ); 00895 ++it; 00896 if ( item->isDefault == defaults && item->type == type ) { 00897 return item; 00898 } 00899 } 00900 return 0; 00901 } 00902 00903 00904 unsigned short KACLListView::calculateMaskValue( bool defaults ) const 00905 { 00906 // KACL auto-adds the relevant maks entries, so we can simply query 00907 bool dummy; 00908 return itemsToACL( defaults ).maskPermissions( dummy ); 00909 } 00910 00911 void KACLListView::slotAddEntry() 00912 { 00913 int allowedTypes = NamedUser | NamedGroup; 00914 if ( !m_hasMask ) 00915 allowedTypes |= Mask; 00916 int allowedDefaultTypes = NamedUser | NamedGroup; 00917 if ( !findDefaultItemByType( Mask ) ) 00918 allowedDefaultTypes |= Mask; 00919 if ( !hasDefaultEntries() ) 00920 allowedDefaultTypes |= User | Group; 00921 EditACLEntryDialog dlg( this, 0, 00922 allowedUsers( false ), allowedGroups( false ), 00923 allowedUsers( true ), allowedGroups( true ), 00924 allowedTypes, allowedDefaultTypes, m_allowDefaults ); 00925 dlg.exec(); 00926 KACLListViewItem *item = dlg.item(); 00927 if ( !item ) return; // canceled 00928 if ( item->type == Mask && !item->isDefault ) { 00929 m_hasMask = true; 00930 m_mask = item->value; 00931 } 00932 if ( item->isDefault && !hasDefaultEntries() ) { 00933 // first default entry, fill in what is needed 00934 if ( item->type != User ) { 00935 unsigned short v = findDefaultItemByType( User )->value; 00936 new KACLListViewItem( this, User, v, true ); 00937 } 00938 if ( item->type != Group ) { 00939 unsigned short v = findDefaultItemByType( Group )->value; 00940 new KACLListViewItem( this, Group, v, true ); 00941 } 00942 if ( item->type != Others ) { 00943 unsigned short v = findDefaultItemByType( Others )->value; 00944 new KACLListViewItem( this, Others, v, true ); 00945 } 00946 } 00947 const KACLListViewItem *defaultMaskItem = findDefaultItemByType( Mask ); 00948 if ( item->isDefault && !defaultMaskItem ) { 00949 unsigned short v = calculateMaskValue( true ); 00950 new KACLListViewItem( this, Mask, v, true ); 00951 } 00952 if ( !item->isDefault && !m_hasMask && 00953 ( item->type == Group 00954 || item->type == NamedUser 00955 || item->type == NamedGroup ) ) { 00956 // auto-add a mask entry 00957 unsigned short v = calculateMaskValue( false ); 00958 new KACLListViewItem( this, Mask, v, false ); 00959 m_hasMask = true; 00960 m_mask = v; 00961 } 00962 calculateEffectiveRights(); 00963 sort(); 00964 setCurrentItem( item ); 00965 // TQListView doesn't seem to emit, in this case, and we need to update 00966 // the buttons... 00967 if ( childCount() == 1 ) 00968 emit currentChanged( item ); 00969 } 00970 00971 void KACLListView::slotEditEntry() 00972 { 00973 TQListViewItem * current = currentItem(); 00974 if ( !current ) return; 00975 KACLListViewItem *item = static_cast<KACLListViewItem*>( current ); 00976 int allowedTypes = item->type | NamedUser | NamedGroup; 00977 bool itemWasMask = item->type == Mask; 00978 if ( !m_hasMask || itemWasMask ) 00979 allowedTypes |= Mask; 00980 int allowedDefaultTypes = item->type | NamedUser | NamedGroup; 00981 if ( !findDefaultItemByType( Mask ) ) 00982 allowedDefaultTypes |= Mask; 00983 if ( !hasDefaultEntries() ) 00984 allowedDefaultTypes |= User | Group; 00985 00986 EditACLEntryDialog dlg( this, item, 00987 allowedUsers( false, item ), allowedGroups( false, item ), 00988 allowedUsers( true, item ), allowedGroups( true, item ), 00989 allowedTypes, allowedDefaultTypes, m_allowDefaults ); 00990 dlg.exec(); 00991 if ( itemWasMask && item->type != Mask ) { 00992 m_hasMask = false; 00993 m_mask = 0; 00994 } 00995 if ( !itemWasMask && item->type == Mask ) { 00996 m_mask = item->value; 00997 m_hasMask = true; 00998 } 00999 calculateEffectiveRights(); 01000 sort(); 01001 } 01002 01003 void KACLListView::slotRemoveEntry() 01004 { 01005 TQListViewItemIterator it( this, TQListViewItemIterator::Selected ); 01006 while ( it.current() ) { 01007 KACLListViewItem *item = static_cast<KACLListViewItem*>( it.current() ); 01008 ++it; 01009 /* First check if it's a mask entry and if so, make sure that there is 01010 * either no name user or group entry, which means the mask can be 01011 * removed, or don't remove it, but reset it. That is allowed. */ 01012 if ( item->type == Mask ) { 01013 bool itemWasDefault = item->isDefault; 01014 if ( !itemWasDefault && maskCanBeDeleted() ) { 01015 m_hasMask= false; 01016 m_mask = 0; 01017 delete item; 01018 } else if ( itemWasDefault && defaultMaskCanBeDeleted() ) { 01019 delete item; 01020 } else { 01021 item->value = 0; 01022 item->repaint(); 01023 } 01024 if ( !itemWasDefault ) 01025 calculateEffectiveRights(); 01026 } else { 01027 // for the base permissions, disable them, which is what libacl does 01028 if ( !item->isDefault && 01029 ( item->type == User 01030 || item->type == Group 01031 || item->type == Others ) ) { 01032 item->value = 0; 01033 item->repaint(); 01034 } else { 01035 delete item; 01036 } 01037 } 01038 } 01039 } 01040 01041 bool KACLListView::maskCanBeDeleted() const 01042 { 01043 return !findItemByType( NamedUser ) && !findItemByType( NamedGroup ); 01044 } 01045 01046 bool KACLListView::defaultMaskCanBeDeleted() const 01047 { 01048 return !findDefaultItemByType( NamedUser ) && !findDefaultItemByType( NamedGroup ); 01049 } 01050 01051 #include "kacleditwidget.moc" 01052 #include "kacleditwidget_p.moc" 01053 #endif 01054 // vim:set ts=8 sw=4: