• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdepim
  • Sitemap
  • Contact Us
 

kmail

folderdialogacltab.cpp

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

kmail

Skip menu "kmail"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages