folderdiaacltab.cpp
00001 // -*- mode: C++; c-file-style: "gnu" -*- 00033 #include <config.h> // FOR TDEPIM_NEW_DISTRLISTS 00034 00035 #include "folderdiaacltab.h" 00036 #include "acljobs.h" 00037 #include "kmfolderimap.h" 00038 #include "kmfoldercachedimap.h" 00039 #include "kmacctcachedimap.h" 00040 #include "kmfolder.h" 00041 00042 #include <addressesdialog.h> 00043 #include <tdeabc/addresseelist.h> 00044 #ifdef TDEPIM_NEW_DISTRLISTS 00045 #include <libtdepim/distributionlist.h> // libtdepim 00046 #else 00047 #include <tdeabc/distributionlist.h> 00048 #endif 00049 #include <tdeabc/stdaddressbook.h> 00050 #include <kaddrbook.h> 00051 #include <kpushbutton.h> 00052 #include <kdebug.h> 00053 #include <tdelocale.h> 00054 00055 #include <tqlayout.h> 00056 #include <tqlabel.h> 00057 #include <tqvbox.h> 00058 #include <tqvbuttongroup.h> 00059 #include <tqwidgetstack.h> 00060 #include <tqradiobutton.h> 00061 #include <tqwhatsthis.h> 00062 00063 #include <assert.h> 00064 #include <tdemessagebox.h> 00065 00066 using namespace KMail; 00067 00068 // In case your tdelibs is < 3.3 00069 #ifndef I18N_NOOP2 00070 #define I18N_NOOP2( comment,x ) x 00071 #endif 00072 00073 // The set of standard permission sets 00074 static const struct { 00075 unsigned int permissions; 00076 const char* userString; 00077 } standardPermissions[] = { 00078 { 0, I18N_NOOP2( "Permissions", "None" ) }, 00079 { ACLJobs::List | ACLJobs::Read | ACLJobs::WriteSeenFlag, I18N_NOOP2( "Permissions", "Read" ) }, 00080 { ACLJobs::List | ACLJobs::Read | ACLJobs::WriteSeenFlag | ACLJobs::Insert | ACLJobs::Post, I18N_NOOP2( "Permissions", "Append" ) }, 00081 { ACLJobs::AllWrite, I18N_NOOP2( "Permissions", "Write" ) }, 00082 { ACLJobs::All, I18N_NOOP2( "Permissions", "All" ) } 00083 }; 00084 00085 00086 KMail::ACLEntryDialog::ACLEntryDialog( IMAPUserIdFormat userIdFormat, const TQString& caption, TQWidget* parent, const char* name ) 00087 : KDialogBase( parent, name, true /*modal*/, caption, 00088 KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok, true /*sep*/ ) 00089 , mUserIdFormat( userIdFormat ) 00090 { 00091 TQWidget *page = new TQWidget( this ); 00092 setMainWidget(page); 00093 TQGridLayout *topLayout = new TQGridLayout( page, 4 /*rows*/, 3 /*cols*/, 0, spacingHint() ); 00094 00095 TQLabel *label = new TQLabel( i18n( "&User identifier:" ), page ); 00096 topLayout->addWidget( label, 0, 0 ); 00097 00098 mUserIdLineEdit = new KLineEdit( page ); 00099 topLayout->addWidget( mUserIdLineEdit, 0, 1 ); 00100 label->setBuddy( mUserIdLineEdit ); 00101 TQWhatsThis::add( mUserIdLineEdit, i18n( "The User Identifier is the login of the user on the IMAP server. This can be a simple user name or the full email address of the user; the login for your own account on the server will tell you which one it is." ) ); 00102 00103 TQPushButton* kabBtn = new TQPushButton( i18n( "Se&lect..." ), page ); 00104 topLayout->addWidget( kabBtn, 0, 2 ); 00105 00106 mButtonGroup = new TQVButtonGroup( i18n( "Permissions" ), page ); 00107 topLayout->addMultiCellWidget( mButtonGroup, 1, 1, 0, 2 ); 00108 00109 for ( unsigned int i = 0; 00110 i < sizeof( standardPermissions ) / sizeof( *standardPermissions ); 00111 ++i ) { 00112 TQRadioButton* cb = new TQRadioButton( i18n( "Permissions", standardPermissions[i].userString ), mButtonGroup ); 00113 // We store the permission value (bitfield) as the id of the radiobutton in the group 00114 mButtonGroup->insert( cb, standardPermissions[i].permissions ); 00115 } 00116 topLayout->setRowStretch(2, 10); 00117 00118 TQLabel *noteLabel = new TQLabel( i18n( "<b>Note: </b>Renaming requires write permissions on the parent folder." ), page ); 00119 topLayout->addMultiCellWidget( noteLabel, 2, 2, 0, 2 ); 00120 00121 connect( mUserIdLineEdit, TQT_SIGNAL( textChanged( const TQString& ) ), TQT_SLOT( slotChanged() ) ); 00122 connect( kabBtn, TQT_SIGNAL( clicked() ), TQT_SLOT( slotSelectAddresses() ) ); 00123 connect( mButtonGroup, TQT_SIGNAL( clicked( int ) ), TQT_SLOT( slotChanged() ) ); 00124 enableButtonOK( false ); 00125 00126 mUserIdLineEdit->setFocus(); 00127 // Ensure the lineedit is rather wide so that email addresses can be read in it 00128 incInitialSize( TQSize( 200, 0 ) ); 00129 } 00130 00131 void KMail::ACLEntryDialog::slotChanged() 00132 { 00133 enableButtonOK( !mUserIdLineEdit->text().isEmpty() && mButtonGroup->selected() != 0 ); 00134 } 00135 00136 static TQString addresseeToUserId( const TDEABC::Addressee& addr, IMAPUserIdFormat userIdFormat ) 00137 { 00138 TQString email = addr.preferredEmail(); 00139 if ( userIdFormat == FullEmail ) 00140 return email; 00141 else { // mUserIdFormat == UserName 00142 email.truncate( email.find( '@' ) ); 00143 return email; 00144 } 00145 } 00146 00147 void KMail::ACLEntryDialog::slotSelectAddresses() 00148 { 00149 KPIM::AddressesDialog dlg( this ); 00150 dlg.setShowCC( false ); 00151 dlg.setShowBCC( false ); 00152 if ( mUserIdFormat == FullEmail ) // otherwise we have no way to go back from userid to email 00153 dlg.setSelectedTo( userIds() ); 00154 if ( dlg.exec() != TQDialog::Accepted ) 00155 return; 00156 00157 const TQStringList distrLists = dlg.toDistributionLists(); 00158 TQString txt = distrLists.join( ", " ); 00159 const TDEABC::Addressee::List lst = dlg.toAddresses(); 00160 if ( !lst.isEmpty() ) { 00161 for( TQValueList<TDEABC::Addressee>::ConstIterator it = lst.begin(); it != lst.end(); ++it ) { 00162 if ( !txt.isEmpty() ) 00163 txt += ", "; 00164 txt += addresseeToUserId( *it, mUserIdFormat ); 00165 } 00166 } 00167 mUserIdLineEdit->setText( txt ); 00168 } 00169 00170 void KMail::ACLEntryDialog::setValues( const TQString& userId, unsigned int permissions ) 00171 { 00172 mUserIdLineEdit->setText( userId ); 00173 mButtonGroup->setButton( permissions ); 00174 enableButtonOK( !userId.isEmpty() ); 00175 } 00176 00177 TQString KMail::ACLEntryDialog::userId() const 00178 { 00179 return mUserIdLineEdit->text(); 00180 } 00181 00182 TQStringList KMail::ACLEntryDialog::userIds() const 00183 { 00184 return KPIM::splitEmailAddrList( mUserIdLineEdit->text() ); 00185 } 00186 00187 unsigned int KMail::ACLEntryDialog::permissions() const 00188 { 00189 return mButtonGroup->selectedId(); 00190 } 00191 00192 // class KMail::FolderDiaACLTab::ListView : public TDEListView 00193 // { 00194 // public: 00195 // ListView( TQWidget* parent, const char* name = 0 ) : TDEListView( parent, name ) {} 00196 // }; 00197 00198 class KMail::FolderDiaACLTab::ListViewItem : public TDEListViewItem 00199 { 00200 public: 00201 ListViewItem( TQListView* listview ) 00202 : TDEListViewItem( listview, listview->lastItem() ), 00203 mModified( false ), mNew( false ) {} 00204 00205 void load( const ACLListEntry& entry ); 00206 void save( ACLList& list, 00207 #ifdef TDEPIM_NEW_DISTRLISTS 00208 TDEABC::AddressBook* abook, 00209 #else 00210 TDEABC::DistributionListManager& manager, 00211 #endif 00212 IMAPUserIdFormat userIdFormat ); 00213 00214 TQString userId() const { return text( 0 ); } 00215 void setUserId( const TQString& userId ) { setText( 0, userId ); } 00216 00217 unsigned int permissions() const { return mPermissions; } 00218 void setPermissions( unsigned int permissions ); 00219 00220 bool isModified() const { return mModified; } 00221 void setModified( bool b ) { mModified = b; } 00222 00223 // The fact that an item is new doesn't matter much. 00224 // This bool is only used to handle deletion differently 00225 bool isNew() const { return mNew; } 00226 void setNew( bool b ) { mNew = b; } 00227 00228 private: 00229 unsigned int mPermissions; 00230 TQString mInternalRightsList; 00231 bool mModified; 00232 bool mNew; 00233 }; 00234 00235 // internalRightsList is only used if permissions doesn't match the standard set 00236 static TQString permissionsToUserString( unsigned int permissions, const TQString& internalRightsList ) 00237 { 00238 for ( unsigned int i = 0; 00239 i < sizeof( standardPermissions ) / sizeof( *standardPermissions ); 00240 ++i ) { 00241 if ( permissions == standardPermissions[i].permissions ) 00242 return i18n( "Permissions", standardPermissions[i].userString ); 00243 } 00244 if ( internalRightsList.isEmpty() ) 00245 return i18n( "Custom Permissions" ); // not very helpful, but shouldn't happen 00246 else 00247 return i18n( "Custom Permissions (%1)" ).arg( internalRightsList ); 00248 } 00249 00250 void KMail::FolderDiaACLTab::ListViewItem::setPermissions( unsigned int permissions ) 00251 { 00252 mPermissions = permissions; 00253 setText( 1, permissionsToUserString( permissions, TQString() ) ); 00254 } 00255 00256 void KMail::FolderDiaACLTab::ListViewItem::load( const ACLListEntry& entry ) 00257 { 00258 // Don't allow spaces in userids. If you need this, fix the slave->app communication, 00259 // since it uses space as a separator (imap4.cc, look for GETACL) 00260 // It's ok in distribution list names though, that's why this check is only done here 00261 // and also why there's no validator on the lineedit. 00262 if ( entry.userId.contains( ' ' ) ) 00263 kdWarning(5006) << "Userid contains a space!!! '" << entry.userId << "'" << endl; 00264 00265 setUserId( entry.userId ); 00266 mPermissions = entry.permissions; 00267 mInternalRightsList = entry.internalRightsList; 00268 setText( 1, permissionsToUserString( entry.permissions, entry.internalRightsList ) ); 00269 mModified = entry.changed; // for dimap, so that earlier changes are still marked as changes 00270 } 00271 00272 void KMail::FolderDiaACLTab::ListViewItem::save( ACLList& aclList, 00273 #ifdef TDEPIM_NEW_DISTRLISTS 00274 TDEABC::AddressBook* addressBook, 00275 #else 00276 TDEABC::DistributionListManager& manager, 00277 #endif 00278 IMAPUserIdFormat userIdFormat ) 00279 { 00280 // expand distribution lists 00281 #ifdef TDEPIM_NEW_DISTRLISTS 00282 KPIM::DistributionList list = KPIM::DistributionList::findByName( addressBook, userId(), false ); 00283 if ( !list.isEmpty() ) { 00284 Q_ASSERT( mModified ); // it has to be new, it couldn't be stored as a distr list name.... 00285 KPIM::DistributionList::Entry::List entryList = list.entries(addressBook); 00286 KPIM::DistributionList::Entry::List::ConstIterator it; 00287 // (we share for loop with the old-distrlist-code) 00288 #else 00289 // kaddrbook.cpp has a strange two-pass case-insensitive lookup; is it ok to be case sensitive? 00290 TDEABC::DistributionList* list = manager.list( userId() ); 00291 if ( list ) { 00292 Q_ASSERT( mModified ); // it has to be new, it couldn't be stored as a distr list name.... 00293 TDEABC::DistributionList::Entry::List entryList = list->entries(); 00294 TDEABC::DistributionList::Entry::List::ConstIterator it; // nice number of "::"! 00295 #endif 00296 for( it = entryList.begin(); it != entryList.end(); ++it ) { 00297 TQString email = (*it).email; 00298 if ( email.isEmpty() ) 00299 email = addresseeToUserId( (*it).addressee, userIdFormat ); 00300 ACLListEntry entry( email, TQString(), mPermissions ); 00301 entry.changed = true; 00302 aclList.append( entry ); 00303 } 00304 } else { // it wasn't a distribution list 00305 ACLListEntry entry( userId(), mInternalRightsList, mPermissions ); 00306 if ( mModified ) { 00307 entry.internalRightsList = TQString(); 00308 entry.changed = true; 00309 } 00310 aclList.append( entry ); 00311 } 00312 } 00313 00315 00316 KMail::FolderDiaACLTab::FolderDiaACLTab( KMFolderDialog* dlg, TQWidget* parent, const char* name ) 00317 : FolderDiaTab( parent, name ), 00318 mImapAccount( 0 ), 00319 mUserRights( 0 ), 00320 mUserRightsState( KMail::ACLJobs::NotFetchedYet ), 00321 mDlg( dlg ), 00322 mChanged( false ), mAccepting( false ), mSaving( false ) 00323 { 00324 TQVBoxLayout* topLayout = new TQVBoxLayout( this ); 00325 // We need a widget stack to show either a label ("no acl support", "please wait"...) 00326 // or a listview. 00327 mStack = new TQWidgetStack( this ); 00328 topLayout->addWidget( mStack ); 00329 00330 mLabel = new TQLabel( mStack ); 00331 mLabel->setAlignment( AlignHCenter | AlignVCenter | WordBreak ); 00332 mStack->addWidget( mLabel ); 00333 00334 mACLWidget = new TQHBox( mStack ); 00335 mACLWidget->setSpacing( KDialog::spacingHint() ); 00336 mListView = new TDEListView( mACLWidget ); 00337 mListView->setAllColumnsShowFocus( true ); 00338 mStack->addWidget( mACLWidget ); 00339 mListView->addColumn( i18n( "User Id" ) ); 00340 mListView->addColumn( i18n( "Permissions" ) ); 00341 00342 connect( mListView, TQT_SIGNAL(doubleClicked(TQListViewItem*,const TQPoint&,int)), 00343 TQT_SLOT(slotEditACL(TQListViewItem*)) ); 00344 connect( mListView, TQT_SIGNAL(returnPressed(TQListViewItem*)), 00345 TQT_SLOT(slotEditACL(TQListViewItem*)) ); 00346 connect( mListView, TQT_SIGNAL(currentChanged(TQListViewItem*)), 00347 TQT_SLOT(slotSelectionChanged(TQListViewItem*)) ); 00348 00349 TQVBox* buttonBox = new TQVBox( mACLWidget ); 00350 buttonBox->setSpacing( KDialog::spacingHint() ); 00351 mAddACL = new KPushButton( i18n( "Add Entry..." ), buttonBox ); 00352 mEditACL = new KPushButton( i18n( "Modify Entry..." ), buttonBox ); 00353 mRemoveACL = new KPushButton( i18n( "Remove Entry" ), buttonBox ); 00354 TQWidget *spacer = new TQWidget( buttonBox ); 00355 spacer->setSizePolicy( TQSizePolicy::Minimum, TQSizePolicy::Expanding ); 00356 00357 connect( mAddACL, TQT_SIGNAL( clicked() ), TQT_SLOT( slotAddACL() ) ); 00358 connect( mEditACL, TQT_SIGNAL( clicked() ), TQT_SLOT( slotEditACL() ) ); 00359 connect( mRemoveACL, TQT_SIGNAL( clicked() ), TQT_SLOT( slotRemoveACL() ) ); 00360 mEditACL->setEnabled( false ); 00361 mRemoveACL->setEnabled( false ); 00362 00363 connect( this, TQT_SIGNAL( changed(bool) ), TQT_SLOT( slotChanged(bool) ) ); 00364 } 00365 00366 // Warning before save() this will return the url of the _parent_ folder, when creating a new one 00367 KURL KMail::FolderDiaACLTab::imapURL() const 00368 { 00369 KURL url = mImapAccount->getUrl(); 00370 url.setPath( mImapPath ); 00371 return url; 00372 } 00373 00374 void KMail::FolderDiaACLTab::initializeWithValuesFromFolder( KMFolder* folder ) 00375 { 00376 // This can be simplified once KMFolderImap and KMFolderCachedImap have a common base class 00377 mFolderType = folder->folderType(); 00378 if ( mFolderType == KMFolderTypeImap ) { 00379 KMFolderImap* folderImap = static_cast<KMFolderImap*>( folder->storage() ); 00380 mImapPath = folderImap->imapPath(); 00381 mImapAccount = folderImap->account(); 00382 mUserRights = folderImap->userRights(); 00383 mUserRightsState = folderImap->userRightsState(); 00384 } 00385 else if ( mFolderType == KMFolderTypeCachedImap ) { 00386 KMFolderCachedImap* folderImap = static_cast<KMFolderCachedImap*>( folder->storage() ); 00387 mImapPath = folderImap->imapPath(); 00388 mImapAccount = folderImap->account(); 00389 mUserRights = folderImap->userRights(); 00390 mUserRightsState = folderImap->userRightsState(); 00391 } 00392 else 00393 assert( 0 ); // see KMFolderDialog constructor 00394 } 00395 00396 void KMail::FolderDiaACLTab::load() 00397 { 00398 if ( mDlg->folder() ) { 00399 // existing folder 00400 initializeWithValuesFromFolder( mDlg->folder() ); 00401 } else if ( mDlg->parentFolder() ) { 00402 // new folder 00403 initializeWithValuesFromFolder( mDlg->parentFolder() ); 00404 mChanged = true; // ensure that saving happens 00405 } 00406 00407 // KABC knows email addresses. 00408 // We want LDAP userids. 00409 // Depending on the IMAP server setup, the userid can be the full email address, 00410 // or just the username part of it. 00411 // To know which one it is, we currently have a hidden config option, 00412 // but the default value is determined from the current user's own id. 00413 TQString defaultFormat = "fullemail"; 00414 // warning mImapAccount can be 0 if creating a subsubsubfolder with dimap... (bug?) 00415 if ( mImapAccount && mImapAccount->login().find('@') == -1 ) 00416 defaultFormat = "username"; // no @ found, so we assume it's just the username 00417 TDEConfigGroup configGroup( kmkernel->config(), "IMAP" ); 00418 TQString str = configGroup.readEntry( "UserIdFormat", defaultFormat ); 00419 mUserIdFormat = FullEmail; 00420 if ( str == "username" ) 00421 mUserIdFormat = UserName; 00422 00423 if ( mFolderType == KMFolderTypeCachedImap ) { 00424 KMFolder* folder = mDlg->folder() ? mDlg->folder() : mDlg->parentFolder(); 00425 KMFolderCachedImap* folderImap = static_cast<KMFolderCachedImap*>( folder->storage() ); 00426 if ( mUserRightsState == KMail::ACLJobs::FetchFailed || 00427 folderImap->aclListState() == KMail::ACLJobs::FetchFailed ) { 00428 TQString text = i18n( "Error retrieving user permissions." ); 00429 if ( mUserRightsState == KMail::ACLJobs::Ok ) { 00430 text += "\n" + i18n( "You might not have enough permissions to see the permissions of this folder." ); 00431 } 00432 mLabel->setText( text ); 00433 } else if ( mUserRightsState == KMail::ACLJobs::NotFetchedYet || 00434 folderImap->aclListState() == KMail::ACLJobs::NotFetchedYet ) { 00435 mLabel->setText( i18n( "Information not retrieved from server, you need to use \"Check Mail\" and have administrative privileges on the folder.")); 00436 } else { 00437 loadFinished( folderImap->aclList() ); 00438 } 00439 return; 00440 } 00441 00442 // Loading, for online IMAP, consists of four steps: 00443 // 1) connect 00444 // 2) get user rights 00445 // 3) load ACLs 00446 00447 // First ensure we are connected 00448 mStack->raiseWidget( mLabel ); 00449 if ( !mImapAccount ) { // hmmm? 00450 mLabel->setText( i18n( "Error: no IMAP account defined for this folder" ) ); 00451 return; 00452 } 00453 KMFolder* folder = mDlg->folder() ? mDlg->folder() : mDlg->parentFolder(); 00454 if ( folder && folder->storage() == mImapAccount->rootFolder() ) 00455 return; // nothing to be done for the (virtual) account folder 00456 mLabel->setText( i18n( "Connecting to server %1, please wait..." ).arg( mImapAccount->host() ) ); 00457 ImapAccountBase::ConnectionState state = mImapAccount->makeConnection(); 00458 if ( state == ImapAccountBase::Error ) { // Cancelled by user, or slave can't start 00459 slotConnectionResult( -1, TQString() ); 00460 } else if ( state == ImapAccountBase::Connecting ) { 00461 connect( mImapAccount, TQT_SIGNAL( connectionResult(int, const TQString&) ), 00462 this, TQT_SLOT( slotConnectionResult(int, const TQString&) ) ); 00463 } else { // Connected 00464 slotConnectionResult( 0, TQString() ); 00465 } 00466 } 00467 00468 void KMail::FolderDiaACLTab::slotConnectionResult( int errorCode, const TQString& errorMsg ) 00469 { 00470 disconnect( mImapAccount, TQT_SIGNAL( connectionResult(int, const TQString&) ), 00471 this, TQT_SLOT( slotConnectionResult(int, const TQString&) ) ); 00472 if ( errorCode ) { 00473 if ( errorCode == -1 ) // unspecified error 00474 mLabel->setText( i18n( "Error connecting to server %1" ).arg( mImapAccount->host() ) ); 00475 else 00476 // Connection error (error message box already shown by the account) 00477 mLabel->setText( TDEIO::buildErrorString( errorCode, errorMsg ) ); 00478 return; 00479 } 00480 00481 if ( mUserRightsState != KMail::ACLJobs::Ok ) { 00482 connect( mImapAccount, TQT_SIGNAL( receivedUserRights( KMFolder* ) ), 00483 this, TQT_SLOT( slotReceivedUserRights( KMFolder* ) ) ); 00484 KMFolder* folder = mDlg->folder() ? mDlg->folder() : mDlg->parentFolder(); 00485 mImapAccount->getUserRights( folder, mImapPath ); 00486 } 00487 else 00488 startListing(); 00489 } 00490 00491 void KMail::FolderDiaACLTab::slotReceivedUserRights( KMFolder* folder ) 00492 { 00493 if ( !mImapAccount->hasACLSupport() ) { 00494 mLabel->setText( i18n( "This IMAP server does not have support for access control lists (ACL)" ) ); 00495 return; 00496 } 00497 00498 if ( folder == mDlg->folder() ? mDlg->folder() : mDlg->parentFolder() ) { 00499 KMFolderImap* folderImap = static_cast<KMFolderImap*>( folder->storage() ); 00500 mUserRights = folderImap->userRights(); 00501 mUserRightsState = folderImap->userRightsState(); 00502 startListing(); 00503 } 00504 } 00505 00506 void KMail::FolderDiaACLTab::startListing() 00507 { 00508 // List ACLs of folder - or its parent, if creating a new folder 00509 mImapAccount->getACL( mDlg->folder() ? mDlg->folder() : mDlg->parentFolder(), mImapPath ); 00510 connect( mImapAccount, TQT_SIGNAL(receivedACL( KMFolder*, TDEIO::Job*, const KMail::ACLList& )), 00511 this, TQT_SLOT(slotReceivedACL( KMFolder*, TDEIO::Job*, const KMail::ACLList& )) ); 00512 } 00513 00514 void KMail::FolderDiaACLTab::slotReceivedACL( KMFolder* folder, TDEIO::Job* job, const KMail::ACLList& aclList ) 00515 { 00516 if ( folder == ( mDlg->folder() ? mDlg->folder() : mDlg->parentFolder() ) ) { 00517 disconnect( mImapAccount, TQT_SIGNAL(receivedACL( KMFolder*, TDEIO::Job*, const KMail::ACLList& )), 00518 this, TQT_SLOT(slotReceivedACL( KMFolder*, TDEIO::Job*, const KMail::ACLList& )) ); 00519 00520 if ( job && job->error() ) { 00521 if ( job->error() == TDEIO::ERR_UNSUPPORTED_ACTION ) 00522 mLabel->setText( i18n( "This IMAP server does not have support for access control lists (ACL)" ) ); 00523 else 00524 mLabel->setText( i18n( "Error retrieving access control list (ACL) from server\n%1" ).arg( job->errorString() ) ); 00525 return; 00526 } 00527 00528 loadFinished( aclList ); 00529 } 00530 } 00531 00532 void KMail::FolderDiaACLTab::loadListView( const ACLList& aclList ) 00533 { 00534 mListView->clear(); 00535 for( ACLList::const_iterator it = aclList.begin(); it != aclList.end(); ++it ) { 00536 // -1 means deleted (for cachedimap), don't show those 00537 if ( (*it).permissions > -1 ) { 00538 ListViewItem* item = new ListViewItem( mListView ); 00539 item->load( *it ); 00540 if ( !mDlg->folder() ) // new folder? everything is new then 00541 item->setModified( true ); 00542 } 00543 } 00544 } 00545 00546 void KMail::FolderDiaACLTab::loadFinished( const ACLList& aclList ) 00547 { 00548 loadListView( aclList ); 00549 if ( mDlg->folder() ) // not when creating a new folder 00550 mInitialACLList = aclList; 00551 mStack->raiseWidget( mACLWidget ); 00552 slotSelectionChanged( mListView->selectedItem() ); 00553 } 00554 00555 void KMail::FolderDiaACLTab::slotEditACL(TQListViewItem* item) 00556 { 00557 if ( !item ) return; 00558 bool canAdmin = ( mUserRights & ACLJobs::Administer ); 00559 // Same logic as in slotSelectionChanged, but this is also needed for double-click IIRC 00560 if ( canAdmin && mImapAccount && item ) { 00561 // Don't allow users to remove their own admin permissions - there's no way back 00562 ListViewItem* ACLitem = static_cast<ListViewItem *>( item ); 00563 if ( mImapAccount->login() == ACLitem->userId() && ACLitem->permissions() == ACLJobs::All ) 00564 canAdmin = false; 00565 } 00566 if ( !canAdmin ) return; 00567 00568 ListViewItem* ACLitem = static_cast<ListViewItem *>( mListView->currentItem() ); 00569 ACLEntryDialog dlg( mUserIdFormat, i18n( "Modify Permissions" ), this ); 00570 dlg.setValues( ACLitem->userId(), ACLitem->permissions() ); 00571 if ( dlg.exec() == TQDialog::Accepted ) { 00572 TQStringList userIds = dlg.userIds(); 00573 Q_ASSERT( !userIds.isEmpty() ); // impossible, the OK button is disabled in that case 00574 ACLitem->setUserId( dlg.userIds().front() ); 00575 ACLitem->setPermissions( dlg.permissions() ); 00576 ACLitem->setModified( true ); 00577 emit changed(true); 00578 if ( userIds.count() > 1 ) { // more emails were added, append them 00579 userIds.pop_front(); 00580 addACLs( userIds, dlg.permissions() ); 00581 } 00582 } 00583 } 00584 00585 void KMail::FolderDiaACLTab::slotEditACL() 00586 { 00587 slotEditACL( mListView->currentItem() ); 00588 } 00589 00590 void KMail::FolderDiaACLTab::addACLs( const TQStringList& userIds, unsigned int permissions ) 00591 { 00592 for( TQStringList::const_iterator it = userIds.begin(); it != userIds.end(); ++it ) { 00593 ListViewItem* ACLitem = new ListViewItem( mListView ); 00594 ACLitem->setUserId( *it ); 00595 ACLitem->setPermissions( permissions ); 00596 ACLitem->setModified( true ); 00597 ACLitem->setNew( true ); 00598 } 00599 } 00600 00601 void KMail::FolderDiaACLTab::slotAddACL() 00602 { 00603 ACLEntryDialog dlg( mUserIdFormat, i18n( "Add Permissions" ), this ); 00604 if ( dlg.exec() == TQDialog::Accepted ) { 00605 const TQStringList userIds = dlg.userIds(); 00606 addACLs( dlg.userIds(), dlg.permissions() ); 00607 emit changed(true); 00608 } 00609 } 00610 00611 void KMail::FolderDiaACLTab::slotSelectionChanged(TQListViewItem* item) 00612 { 00613 bool canAdmin = ( mUserRights & ACLJobs::Administer ); 00614 bool canAdminThisItem = canAdmin; 00615 if ( canAdmin && mImapAccount && item ) { 00616 // Don't allow users to remove their own admin permissions - there's no way back 00617 ListViewItem* ACLitem = static_cast<ListViewItem *>( item ); 00618 if ( mImapAccount->login() == ACLitem->userId() && ACLitem->permissions() == ACLJobs::All ) 00619 canAdminThisItem = false; 00620 } 00621 00622 bool lvVisible = mStack->visibleWidget() == mACLWidget; 00623 mAddACL->setEnabled( lvVisible && canAdmin && !mSaving ); 00624 mEditACL->setEnabled( item && lvVisible && canAdminThisItem && !mSaving ); 00625 mRemoveACL->setEnabled( item && lvVisible && canAdminThisItem && !mSaving ); 00626 } 00627 00628 void KMail::FolderDiaACLTab::slotRemoveACL() 00629 { 00630 ListViewItem* ACLitem = static_cast<ListViewItem *>( mListView->currentItem() ); 00631 if ( !ACLitem ) 00632 return; 00633 if ( !ACLitem->isNew() ) { 00634 if ( mImapAccount && mImapAccount->login() == ACLitem->userId() ) { 00635 if ( KMessageBox::Cancel == KMessageBox::warningContinueCancel( topLevelWidget(), 00636 i18n( "Do you really want to remove your own permissions for this folder? You will not be able to access it afterwards." ), i18n( "Remove" ) ) ) 00637 return; 00638 } 00639 mRemovedACLs.append( ACLitem->userId() ); 00640 } 00641 delete ACLitem; 00642 emit changed(true); 00643 } 00644 00645 KMail::FolderDiaTab::AccepStatus KMail::FolderDiaACLTab::accept() 00646 { 00647 if ( !mChanged || !mImapAccount ) 00648 return Accepted; // (no change made), ok for accepting the dialog immediately 00649 // If there were changes, we need to apply them first (which is async) 00650 save(); 00651 if ( mFolderType == KMFolderTypeCachedImap ) 00652 return Accepted; // cached imap: changes saved immediately into the folder 00653 // disconnected imap: async job[s] running 00654 mAccepting = true; 00655 return Delayed; 00656 } 00657 00658 bool KMail::FolderDiaACLTab::save() 00659 { 00660 if ( !mChanged || !mImapAccount ) // no changes 00661 return true; 00662 assert( mDlg->folder() ); // should have been created already 00663 00664 // Expand distribution lists. This is necessary because after Apply 00665 // we would otherwise be able to "modify" the permissions for a distr list, 00666 // which wouldn't work since the ACLList and the server only know about the 00667 // individual addresses. 00668 // slotACLChanged would have trouble matching the item too. 00669 // After reloading we'd see the list expanded anyway, 00670 // so this is more consistent. 00671 // But we do it now and not when inserting it, because this allows to 00672 // immediately remove a wrongly inserted distr list without having to 00673 // remove 100 items. 00674 // Now, how to expand them? Playing with listviewitem iterators and inserting 00675 // listviewitems at the same time sounds dangerous, so let's just save into 00676 // ACLList and reload that. 00677 TDEABC::AddressBook *addressBook = TDEABC::StdAddressBook::self( true ); 00678 #ifndef TDEPIM_NEW_DISTRLISTS 00679 TDEABC::DistributionListManager manager( addressBook ); 00680 manager.load(); 00681 #endif 00682 ACLList aclList; 00683 for ( TQListViewItem* item = mListView->firstChild(); item; item = item->nextSibling() ) { 00684 ListViewItem* ACLitem = static_cast<ListViewItem *>( item ); 00685 ACLitem->save( aclList, 00686 #ifdef TDEPIM_NEW_DISTRLISTS 00687 addressBook, 00688 #else 00689 manager, 00690 #endif 00691 mUserIdFormat ); 00692 } 00693 loadListView( aclList ); 00694 00695 // Now compare with the initial ACLList, because if the user renamed a userid 00696 // we have to add the old userid to the "to be deleted" list. 00697 for( ACLList::ConstIterator init = mInitialACLList.begin(); init != mInitialACLList.end(); ++init ) { 00698 bool isInNewList = false; 00699 TQString uid = (*init).userId; 00700 for( ACLList::ConstIterator it = aclList.begin(); it != aclList.end() && !isInNewList; ++it ) 00701 isInNewList = uid == (*it).userId; 00702 if ( !isInNewList && !mRemovedACLs.contains(uid) ) 00703 mRemovedACLs.append( uid ); 00704 } 00705 00706 for ( TQStringList::ConstIterator rit = mRemovedACLs.begin(); rit != mRemovedACLs.end(); ++rit ) { 00707 // We use permissions == -1 to signify deleting. At least on cyrus, setacl(0) or deleteacl are the same, 00708 // but I'm not sure if that's true for all servers. 00709 ACLListEntry entry( *rit, TQString(), -1 ); 00710 entry.changed = true; 00711 aclList.append( entry ); 00712 } 00713 00714 // aclList is finally ready. We can save it (dimap) or apply it (imap). 00715 00716 if ( mFolderType == KMFolderTypeCachedImap ) { 00717 // Apply the changes to the aclList stored in the folder. 00718 // We have to do this now and not before, so that cancel really cancels. 00719 KMFolderCachedImap* folderImap = static_cast<KMFolderCachedImap*>( mDlg->folder()->storage() ); 00720 folderImap->setACLList( aclList ); 00721 return true; 00722 } 00723 00724 mACLList = aclList; 00725 00726 KMFolderImap* parentImap = mDlg->parentFolder() ? static_cast<KMFolderImap*>( mDlg->parentFolder()->storage() ) : 0; 00727 00728 if ( mDlg->isNewFolder() ) { 00729 // The folder isn't created yet, wait for it 00730 // It's a two-step process (mkdir+listDir) so we wait for the dir listing to be complete 00731 connect( parentImap, TQT_SIGNAL( directoryListingFinished(KMFolderImap*) ), 00732 this, TQT_SLOT( slotDirectoryListingFinished(KMFolderImap*) ) ); 00733 } else { 00734 slotDirectoryListingFinished( parentImap ); 00735 } 00736 return true; 00737 } 00738 00739 void KMail::FolderDiaACLTab::slotDirectoryListingFinished(KMFolderImap* f) 00740 { 00741 if ( !f || 00742 f != static_cast<KMFolderImap*>( mDlg->parentFolder()->storage() ) || 00743 !mDlg->folder() || 00744 !mDlg->folder()->storage() ) { 00745 emit readyForAccept(); 00746 return; 00747 } 00748 00749 // When creating a new folder with online imap, update mImapPath 00750 KMFolderImap* folderImap = static_cast<KMFolderImap*>( mDlg->folder()->storage() ); 00751 if ( !folderImap || folderImap->imapPath().isEmpty() ) 00752 return; 00753 mImapPath = folderImap->imapPath(); 00754 00755 TDEIO::Job* job = ACLJobs::multiSetACL( mImapAccount->slave(), imapURL(), mACLList ); 00756 ImapAccountBase::jobData jd; 00757 jd.total = 1; jd.done = 0; jd.parent = 0; 00758 mImapAccount->insertJob(job, jd); 00759 00760 connect(job, TQT_SIGNAL(result(TDEIO::Job *)), 00761 TQT_SLOT(slotMultiSetACLResult(TDEIO::Job *))); 00762 connect(job, TQT_SIGNAL(aclChanged( const TQString&, int )), 00763 TQT_SLOT(slotACLChanged( const TQString&, int )) ); 00764 } 00765 00766 void KMail::FolderDiaACLTab::slotMultiSetACLResult(TDEIO::Job* job) 00767 { 00768 ImapAccountBase::JobIterator it = mImapAccount->findJob( job ); 00769 if ( it == mImapAccount->jobsEnd() ) return; 00770 mImapAccount->removeJob( it ); 00771 00772 if ( job->error() ) { 00773 job->showErrorDialog( this ); 00774 if ( mAccepting ) { 00775 emit cancelAccept(); 00776 mAccepting = false; // don't emit readyForAccept anymore 00777 } 00778 } else { 00779 if ( mAccepting ) 00780 emit readyForAccept(); 00781 } 00782 } 00783 00784 void KMail::FolderDiaACLTab::slotACLChanged( const TQString& userId, int permissions ) 00785 { 00786 // The job indicates success in changing the permissions for this user 00787 // -> we note that it's been done. 00788 bool ok = false; 00789 if ( permissions > -1 ) { 00790 for ( TQListViewItem* item = mListView->firstChild(); item; item = item->nextSibling() ) { 00791 ListViewItem* ACLitem = static_cast<ListViewItem *>( item ); 00792 if ( ACLitem->userId() == userId ) { 00793 ACLitem->setModified( false ); 00794 ACLitem->setNew( false ); 00795 ok = true; 00796 break; 00797 } 00798 } 00799 } else { 00800 uint nr = mRemovedACLs.remove( userId ); 00801 ok = ( nr > 0 ); 00802 } 00803 if ( !ok ) 00804 kdWarning(5006) << k_funcinfo << " no item found for userId " << userId << endl; 00805 } 00806 00807 void KMail::FolderDiaACLTab::slotChanged( bool b ) 00808 { 00809 mChanged = b; 00810 } 00811 00812 bool KMail::FolderDiaACLTab::supports( KMFolder* refFolder ) 00813 { 00814 ImapAccountBase* imapAccount = 0; 00815 if ( refFolder->folderType() == KMFolderTypeImap ) 00816 imapAccount = static_cast<KMFolderImap*>( refFolder->storage() )->account(); 00817 else 00818 imapAccount = static_cast<KMFolderCachedImap*>( refFolder->storage() )->account(); 00819 return imapAccount && imapAccount->hasACLSupport(); // support for ACLs (or not tried connecting yet) 00820 } 00821 00822 #include "folderdiaacltab.moc"