kmail Library API Documentation

folderdiaacltab.cpp

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