kmail

folderdiaacltab.cpp
1 
32 #include <config.h> // FOR TDEPIM_NEW_DISTRLISTS
33 
34 #include "folderdiaacltab.h"
35 #include "acljobs.h"
36 #include "kmfolderimap.h"
37 #include "kmfoldercachedimap.h"
38 #include "kmacctcachedimap.h"
39 #include "kmfolder.h"
40 
41 #include <addressesdialog.h>
42 #include <tdeabc/addresseelist.h>
43 #ifdef TDEPIM_NEW_DISTRLISTS
44 #include <libtdepim/distributionlist.h> // libtdepim
45 #else
46 #include <tdeabc/distributionlist.h>
47 #endif
48 #include <tdeabc/stdaddressbook.h>
49 #include <kaddrbook.h>
50 #include <kpushbutton.h>
51 #include <kdebug.h>
52 #include <tdelocale.h>
53 
54 #include <tqlayout.h>
55 #include <tqlabel.h>
56 #include <tqvbox.h>
57 #include <tqvbuttongroup.h>
58 #include <tqwidgetstack.h>
59 #include <tqradiobutton.h>
60 #include <tqwhatsthis.h>
61 
62 #include <assert.h>
63 #include <tdemessagebox.h>
64 
65 using namespace KMail;
66 
67 // In case your tdelibs is < 3.3
68 #ifndef I18N_NOOP2
69 #define I18N_NOOP2( comment,x ) x
70 #endif
71 
72 // The set of standard permission sets
73 static const struct {
74  unsigned int permissions;
75  const char* userString;
76 } standardPermissions[] = {
77  { 0, I18N_NOOP2( "Permissions", "None" ) },
78  { ACLJobs::List | ACLJobs::Read | ACLJobs::WriteSeenFlag, I18N_NOOP2( "Permissions", "Read" ) },
79  { ACLJobs::List | ACLJobs::Read | ACLJobs::WriteSeenFlag | ACLJobs::Insert | ACLJobs::Post, I18N_NOOP2( "Permissions", "Append" ) },
80  { ACLJobs::AllWrite, I18N_NOOP2( "Permissions", "Write" ) },
81  { ACLJobs::All, I18N_NOOP2( "Permissions", "All" ) }
82 };
83 
84 
85 KMail::ACLEntryDialog::ACLEntryDialog( IMAPUserIdFormat userIdFormat, const TQString& caption, TQWidget* parent, const char* name )
86  : KDialogBase( parent, name, true /*modal*/, caption,
87  KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok, true /*sep*/ )
88  , mUserIdFormat( userIdFormat )
89 {
90  TQWidget *page = new TQWidget( this );
91  setMainWidget(page);
92  TQGridLayout *topLayout = new TQGridLayout( page, 4 /*rows*/, 3 /*cols*/, 0, spacingHint() );
93 
94  TQLabel *label = new TQLabel( i18n( "&User identifier:" ), page );
95  topLayout->addWidget( label, 0, 0 );
96 
97  mUserIdLineEdit = new KLineEdit( page );
98  topLayout->addWidget( mUserIdLineEdit, 0, 1 );
99  label->setBuddy( mUserIdLineEdit );
100  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." ) );
101 
102  TQPushButton* kabBtn = new TQPushButton( i18n( "Se&lect..." ), page );
103  topLayout->addWidget( kabBtn, 0, 2 );
104 
105  mButtonGroup = new TQVButtonGroup( i18n( "Permissions" ), page );
106  topLayout->addMultiCellWidget( mButtonGroup, 1, 1, 0, 2 );
107 
108  for ( unsigned int i = 0;
109  i < sizeof( standardPermissions ) / sizeof( *standardPermissions );
110  ++i ) {
111  TQRadioButton* cb = new TQRadioButton( i18n( "Permissions", standardPermissions[i].userString ), mButtonGroup );
112  // We store the permission value (bitfield) as the id of the radiobutton in the group
113  mButtonGroup->insert( cb, standardPermissions[i].permissions );
114  }
115  topLayout->setRowStretch(2, 10);
116 
117  TQLabel *noteLabel = new TQLabel( i18n( "<b>Note: </b>Renaming requires write permissions on the parent folder." ), page );
118  topLayout->addMultiCellWidget( noteLabel, 2, 2, 0, 2 );
119 
120  connect( mUserIdLineEdit, TQ_SIGNAL( textChanged( const TQString& ) ), TQ_SLOT( slotChanged() ) );
121  connect( kabBtn, TQ_SIGNAL( clicked() ), TQ_SLOT( slotSelectAddresses() ) );
122  connect( mButtonGroup, TQ_SIGNAL( clicked( int ) ), TQ_SLOT( slotChanged() ) );
123  enableButtonOK( false );
124 
125  mUserIdLineEdit->setFocus();
126  // Ensure the lineedit is rather wide so that email addresses can be read in it
127  incInitialSize( TQSize( 200, 0 ) );
128 }
129 
130 void KMail::ACLEntryDialog::slotChanged()
131 {
132  enableButtonOK( !mUserIdLineEdit->text().isEmpty() && mButtonGroup->selected() != 0 );
133 }
134 
135 static TQString addresseeToUserId( const TDEABC::Addressee& addr, IMAPUserIdFormat userIdFormat )
136 {
137  TQString email = addr.preferredEmail();
138  if ( userIdFormat == FullEmail )
139  return email;
140  else { // mUserIdFormat == UserName
141  email.truncate( email.find( '@' ) );
142  return email;
143  }
144 }
145 
146 void KMail::ACLEntryDialog::slotSelectAddresses()
147 {
148  KPIM::AddressesDialog dlg( this );
149  dlg.setShowCC( false );
150  dlg.setShowBCC( false );
151  if ( mUserIdFormat == FullEmail ) // otherwise we have no way to go back from userid to email
152  dlg.setSelectedTo( userIds() );
153  if ( dlg.exec() != TQDialog::Accepted )
154  return;
155 
156  const TQStringList distrLists = dlg.toDistributionLists();
157  TQString txt = distrLists.join( ", " );
158  const TDEABC::Addressee::List lst = dlg.toAddresses();
159  if ( !lst.isEmpty() ) {
160  for( TQValueList<TDEABC::Addressee>::ConstIterator it = lst.begin(); it != lst.end(); ++it ) {
161  if ( !txt.isEmpty() )
162  txt += ", ";
163  txt += addresseeToUserId( *it, mUserIdFormat );
164  }
165  }
166  mUserIdLineEdit->setText( txt );
167 }
168 
169 void KMail::ACLEntryDialog::setValues( const TQString& userId, unsigned int permissions )
170 {
171  mUserIdLineEdit->setText( userId );
172  mButtonGroup->setButton( permissions );
173  enableButtonOK( !userId.isEmpty() );
174 }
175 
176 TQString KMail::ACLEntryDialog::userId() const
177 {
178  return mUserIdLineEdit->text();
179 }
180 
181 TQStringList KMail::ACLEntryDialog::userIds() const
182 {
183  return KPIM::splitEmailAddrList( mUserIdLineEdit->text() );
184 }
185 
186 unsigned int KMail::ACLEntryDialog::permissions() const
187 {
188  return mButtonGroup->selectedId();
189 }
190 
191 // class KMail::FolderDiaACLTab::ListView : public TDEListView
192 // {
193 // public:
194 // ListView( TQWidget* parent, const char* name = 0 ) : TDEListView( parent, name ) {}
195 // };
196 
197 class KMail::FolderDiaACLTab::ListViewItem : public TDEListViewItem
198 {
199 public:
200  ListViewItem( TQListView* listview )
201  : TDEListViewItem( listview, listview->lastItem() ),
202  mModified( false ), mNew( false ) {}
203 
204  void load( const ACLListEntry& entry );
205  void save( ACLList& list,
206 #ifdef TDEPIM_NEW_DISTRLISTS
207  TDEABC::AddressBook* abook,
208 #else
209  TDEABC::DistributionListManager& manager,
210 #endif
211  IMAPUserIdFormat userIdFormat );
212 
213  TQString userId() const { return text( 0 ); }
214  void setUserId( const TQString& userId ) { setText( 0, userId ); }
215 
216  unsigned int permissions() const { return mPermissions; }
217  void setPermissions( unsigned int permissions );
218 
219  bool isModified() const { return mModified; }
220  void setModified( bool b ) { mModified = b; }
221 
222  // The fact that an item is new doesn't matter much.
223  // This bool is only used to handle deletion differently
224  bool isNew() const { return mNew; }
225  void setNew( bool b ) { mNew = b; }
226 
227 private:
228  unsigned int mPermissions;
229  TQString mInternalRightsList;
230  bool mModified;
231  bool mNew;
232 };
233 
234 // internalRightsList is only used if permissions doesn't match the standard set
235 static TQString permissionsToUserString( unsigned int permissions, const TQString& internalRightsList )
236 {
237  for ( unsigned int i = 0;
238  i < sizeof( standardPermissions ) / sizeof( *standardPermissions );
239  ++i ) {
240  if ( permissions == standardPermissions[i].permissions )
241  return i18n( "Permissions", standardPermissions[i].userString );
242  }
243  if ( internalRightsList.isEmpty() )
244  return i18n( "Custom Permissions" ); // not very helpful, but shouldn't happen
245  else
246  return i18n( "Custom Permissions (%1)" ).arg( internalRightsList );
247 }
248 
249 void KMail::FolderDiaACLTab::ListViewItem::setPermissions( unsigned int permissions )
250 {
251  mPermissions = permissions;
252  setText( 1, permissionsToUserString( permissions, TQString() ) );
253 }
254 
255 void KMail::FolderDiaACLTab::ListViewItem::load( const ACLListEntry& entry )
256 {
257  // Don't allow spaces in userids. If you need this, fix the slave->app communication,
258  // since it uses space as a separator (imap4.cpp, look for GETACL)
259  // It's ok in distribution list names though, that's why this check is only done here
260  // and also why there's no validator on the lineedit.
261  if ( entry.userId.contains( ' ' ) )
262  kdWarning(5006) << "Userid contains a space!!! '" << entry.userId << "'" << endl;
263 
264  setUserId( entry.userId );
265  mPermissions = entry.permissions;
266  mInternalRightsList = entry.internalRightsList;
267  setText( 1, permissionsToUserString( entry.permissions, entry.internalRightsList ) );
268  mModified = entry.changed; // for dimap, so that earlier changes are still marked as changes
269 }
270 
271 void KMail::FolderDiaACLTab::ListViewItem::save( ACLList& aclList,
272 #ifdef TDEPIM_NEW_DISTRLISTS
273  TDEABC::AddressBook* addressBook,
274 #else
275  TDEABC::DistributionListManager& manager,
276 #endif
277  IMAPUserIdFormat userIdFormat )
278 {
279  // expand distribution lists
280 #ifdef TDEPIM_NEW_DISTRLISTS
281  KPIM::DistributionList list = KPIM::DistributionList::findByName( addressBook, userId(), false );
282  if ( !list.isEmpty() ) {
283  Q_ASSERT( mModified ); // it has to be new, it couldn't be stored as a distr list name....
284  KPIM::DistributionList::Entry::List entryList = list.entries(addressBook);
285  KPIM::DistributionList::Entry::List::ConstIterator it;
286  // (we share for loop with the old-distrlist-code)
287 #else
288  // kaddrbook.cpp has a strange two-pass case-insensitive lookup; is it ok to be case sensitive?
289  TDEABC::DistributionList* list = manager.list( userId() );
290  if ( list ) {
291  Q_ASSERT( mModified ); // it has to be new, it couldn't be stored as a distr list name....
292  TDEABC::DistributionList::Entry::List entryList = list->entries();
293  TDEABC::DistributionList::Entry::List::ConstIterator it; // nice number of "::"!
294 #endif
295  for( it = entryList.begin(); it != entryList.end(); ++it ) {
296  TQString email = (*it).email;
297  if ( email.isEmpty() )
298  email = addresseeToUserId( (*it).addressee, userIdFormat );
299  ACLListEntry entry( email, TQString(), mPermissions );
300  entry.changed = true;
301  aclList.append( entry );
302  }
303  } else { // it wasn't a distribution list
304  ACLListEntry entry( userId(), mInternalRightsList, mPermissions );
305  if ( mModified ) {
306  entry.internalRightsList = TQString();
307  entry.changed = true;
308  }
309  aclList.append( entry );
310  }
311 }
312 
314 
315 KMail::FolderDiaACLTab::FolderDiaACLTab( KMFolderDialog* dlg, TQWidget* parent, const char* name )
316  : FolderDiaTab( parent, name ),
317  mImapAccount( 0 ),
318  mUserRights( 0 ),
319  mUserRightsState( KMail::ACLJobs::NotFetchedYet ),
320  mDlg( dlg ),
321  mChanged( false ), mAccepting( false ), mSaving( false )
322 {
323  TQVBoxLayout* topLayout = new TQVBoxLayout( this );
324  // We need a widget stack to show either a label ("no acl support", "please wait"...)
325  // or a listview.
326  mStack = new TQWidgetStack( this );
327  topLayout->addWidget( mStack );
328 
329  mLabel = new TQLabel( mStack );
330  mLabel->setAlignment( AlignHCenter | AlignVCenter | WordBreak );
331  mStack->addWidget( mLabel );
332 
333  mACLWidget = new TQHBox( mStack );
334  mACLWidget->setSpacing( KDialog::spacingHint() );
335  mListView = new TDEListView( mACLWidget );
336  mListView->setAllColumnsShowFocus( true );
337  mStack->addWidget( mACLWidget );
338  mListView->addColumn( i18n( "User Id" ) );
339  mListView->addColumn( i18n( "Permissions" ) );
340 
341  connect( mListView, TQ_SIGNAL(doubleClicked(TQListViewItem*,const TQPoint&,int)),
342  TQ_SLOT(slotEditACL(TQListViewItem*)) );
343  connect( mListView, TQ_SIGNAL(returnPressed(TQListViewItem*)),
344  TQ_SLOT(slotEditACL(TQListViewItem*)) );
345  connect( mListView, TQ_SIGNAL(currentChanged(TQListViewItem*)),
346  TQ_SLOT(slotSelectionChanged(TQListViewItem*)) );
347 
348  TQVBox* buttonBox = new TQVBox( mACLWidget );
349  buttonBox->setSpacing( KDialog::spacingHint() );
350  mAddACL = new KPushButton( i18n( "Add Entry..." ), buttonBox );
351  mEditACL = new KPushButton( i18n( "Modify Entry..." ), buttonBox );
352  mRemoveACL = new KPushButton( i18n( "Remove Entry" ), buttonBox );
353  TQWidget *spacer = new TQWidget( buttonBox );
354  spacer->setSizePolicy( TQSizePolicy::Minimum, TQSizePolicy::Expanding );
355 
356  connect( mAddACL, TQ_SIGNAL( clicked() ), TQ_SLOT( slotAddACL() ) );
357  connect( mEditACL, TQ_SIGNAL( clicked() ), TQ_SLOT( slotEditACL() ) );
358  connect( mRemoveACL, TQ_SIGNAL( clicked() ), TQ_SLOT( slotRemoveACL() ) );
359  mEditACL->setEnabled( false );
360  mRemoveACL->setEnabled( false );
361 
362  connect( this, TQ_SIGNAL( changed(bool) ), TQ_SLOT( slotChanged(bool) ) );
363 }
364 
365 // Warning before save() this will return the url of the _parent_ folder, when creating a new one
366 KURL KMail::FolderDiaACLTab::imapURL() const
367 {
368  KURL url = mImapAccount->getUrl();
369  url.setPath( mImapPath );
370  return url;
371 }
372 
373 void KMail::FolderDiaACLTab::initializeWithValuesFromFolder( KMFolder* folder )
374 {
375  // This can be simplified once KMFolderImap and KMFolderCachedImap have a common base class
376  mFolderType = folder->folderType();
377  if ( mFolderType == KMFolderTypeImap ) {
378  KMFolderImap* folderImap = static_cast<KMFolderImap*>( folder->storage() );
379  mImapPath = folderImap->imapPath();
380  mImapAccount = folderImap->account();
381  mUserRights = folderImap->userRights();
382  mUserRightsState = folderImap->userRightsState();
383  }
384  else if ( mFolderType == KMFolderTypeCachedImap ) {
385  KMFolderCachedImap* folderImap = static_cast<KMFolderCachedImap*>( folder->storage() );
386  mImapPath = folderImap->imapPath();
387  mImapAccount = folderImap->account();
388  mUserRights = folderImap->userRights();
389  mUserRightsState = folderImap->userRightsState();
390  }
391  else
392  assert( 0 ); // see KMFolderDialog constructor
393 }
394 
395 void KMail::FolderDiaACLTab::load()
396 {
397  if ( mDlg->folder() ) {
398  // existing folder
399  initializeWithValuesFromFolder( mDlg->folder() );
400  } else if ( mDlg->parentFolder() ) {
401  // new folder
402  initializeWithValuesFromFolder( mDlg->parentFolder() );
403  mChanged = true; // ensure that saving happens
404  }
405 
406  // KABC knows email addresses.
407  // We want LDAP userids.
408  // Depending on the IMAP server setup, the userid can be the full email address,
409  // or just the username part of it.
410  // To know which one it is, we currently have a hidden config option,
411  // but the default value is determined from the current user's own id.
412  TQString defaultFormat = "fullemail";
413  // warning mImapAccount can be 0 if creating a subsubsubfolder with dimap... (bug?)
414  if ( mImapAccount && mImapAccount->login().find('@') == -1 )
415  defaultFormat = "username"; // no @ found, so we assume it's just the username
416  TDEConfigGroup configGroup( kmkernel->config(), "IMAP" );
417  TQString str = configGroup.readEntry( "UserIdFormat", defaultFormat );
418  mUserIdFormat = FullEmail;
419  if ( str == "username" )
420  mUserIdFormat = UserName;
421 
422  if ( mFolderType == KMFolderTypeCachedImap ) {
423  KMFolder* folder = mDlg->folder() ? mDlg->folder() : mDlg->parentFolder();
424  KMFolderCachedImap* folderImap = static_cast<KMFolderCachedImap*>( folder->storage() );
425  if ( mUserRightsState == KMail::ACLJobs::FetchFailed ||
426  folderImap->aclListState() == KMail::ACLJobs::FetchFailed ) {
427  TQString text = i18n( "Error retrieving user permissions." );
428  if ( mUserRightsState == KMail::ACLJobs::Ok ) {
429  text += "\n" + i18n( "You might not have enough permissions to see the permissions of this folder." );
430  }
431  mLabel->setText( text );
432  } else if ( mUserRightsState == KMail::ACLJobs::NotFetchedYet ||
433  folderImap->aclListState() == KMail::ACLJobs::NotFetchedYet ) {
434  mLabel->setText( i18n( "Information not retrieved from server, you need to use \"Check Mail\" and have administrative privileges on the folder."));
435  } else {
436  loadFinished( folderImap->aclList() );
437  }
438  return;
439  }
440 
441  // Loading, for online IMAP, consists of four steps:
442  // 1) connect
443  // 2) get user rights
444  // 3) load ACLs
445 
446  // First ensure we are connected
447  mStack->raiseWidget( mLabel );
448  if ( !mImapAccount ) { // hmmm?
449  mLabel->setText( i18n( "Error: no IMAP account defined for this folder" ) );
450  return;
451  }
452  KMFolder* folder = mDlg->folder() ? mDlg->folder() : mDlg->parentFolder();
453  if ( folder && folder->storage() == mImapAccount->rootFolder() )
454  return; // nothing to be done for the (virtual) account folder
455  mLabel->setText( i18n( "Connecting to server %1, please wait..." ).arg( mImapAccount->host() ) );
456  ImapAccountBase::ConnectionState state = mImapAccount->makeConnection();
457  if ( state == ImapAccountBase::Error ) { // Cancelled by user, or slave can't start
458  slotConnectionResult( -1, TQString() );
459  } else if ( state == ImapAccountBase::Connecting ) {
460  connect( mImapAccount, TQ_SIGNAL( connectionResult(int, const TQString&) ),
461  this, TQ_SLOT( slotConnectionResult(int, const TQString&) ) );
462  } else { // Connected
463  slotConnectionResult( 0, TQString() );
464  }
465 }
466 
467 void KMail::FolderDiaACLTab::slotConnectionResult( int errorCode, const TQString& errorMsg )
468 {
469  disconnect( mImapAccount, TQ_SIGNAL( connectionResult(int, const TQString&) ),
470  this, TQ_SLOT( slotConnectionResult(int, const TQString&) ) );
471  if ( errorCode ) {
472  if ( errorCode == -1 ) // unspecified error
473  mLabel->setText( i18n( "Error connecting to server %1" ).arg( mImapAccount->host() ) );
474  else
475  // Connection error (error message box already shown by the account)
476  mLabel->setText( TDEIO::buildErrorString( errorCode, errorMsg ) );
477  return;
478  }
479 
480  if ( mUserRightsState != KMail::ACLJobs::Ok ) {
481  connect( mImapAccount, TQ_SIGNAL( receivedUserRights( KMFolder* ) ),
482  this, TQ_SLOT( slotReceivedUserRights( KMFolder* ) ) );
483  KMFolder* folder = mDlg->folder() ? mDlg->folder() : mDlg->parentFolder();
484  mImapAccount->getUserRights( folder, mImapPath );
485  }
486  else
487  startListing();
488 }
489 
490 void KMail::FolderDiaACLTab::slotReceivedUserRights( KMFolder* folder )
491 {
492  if ( !mImapAccount->hasACLSupport() ) {
493  mLabel->setText( i18n( "This IMAP server does not have support for access control lists (ACL)" ) );
494  return;
495  }
496 
497  if ( folder == mDlg->folder() ? mDlg->folder() : mDlg->parentFolder() ) {
498  KMFolderImap* folderImap = static_cast<KMFolderImap*>( folder->storage() );
499  mUserRights = folderImap->userRights();
500  mUserRightsState = folderImap->userRightsState();
501  startListing();
502  }
503 }
504 
505 void KMail::FolderDiaACLTab::startListing()
506 {
507  // List ACLs of folder - or its parent, if creating a new folder
508  mImapAccount->getACL( mDlg->folder() ? mDlg->folder() : mDlg->parentFolder(), mImapPath );
509  connect( mImapAccount, TQ_SIGNAL(receivedACL( KMFolder*, TDEIO::Job*, const KMail::ACLList& )),
510  this, TQ_SLOT(slotReceivedACL( KMFolder*, TDEIO::Job*, const KMail::ACLList& )) );
511 }
512 
513 void KMail::FolderDiaACLTab::slotReceivedACL( KMFolder* folder, TDEIO::Job* job, const KMail::ACLList& aclList )
514 {
515  if ( folder == ( mDlg->folder() ? mDlg->folder() : mDlg->parentFolder() ) ) {
516  disconnect( mImapAccount, TQ_SIGNAL(receivedACL( KMFolder*, TDEIO::Job*, const KMail::ACLList& )),
517  this, TQ_SLOT(slotReceivedACL( KMFolder*, TDEIO::Job*, const KMail::ACLList& )) );
518 
519  if ( job && job->error() ) {
520  if ( job->error() == TDEIO::ERR_UNSUPPORTED_ACTION )
521  mLabel->setText( i18n( "This IMAP server does not have support for access control lists (ACL)" ) );
522  else
523  mLabel->setText( i18n( "Error retrieving access control list (ACL) from server\n%1" ).arg( job->errorString() ) );
524  return;
525  }
526 
527  loadFinished( aclList );
528  }
529 }
530 
531 void KMail::FolderDiaACLTab::loadListView( const ACLList& aclList )
532 {
533  mListView->clear();
534  for( ACLList::const_iterator it = aclList.begin(); it != aclList.end(); ++it ) {
535  // -1 means deleted (for cachedimap), don't show those
536  if ( (*it).permissions > -1 ) {
537  ListViewItem* item = new ListViewItem( mListView );
538  item->load( *it );
539  if ( !mDlg->folder() ) // new folder? everything is new then
540  item->setModified( true );
541  }
542  }
543 }
544 
545 void KMail::FolderDiaACLTab::loadFinished( const ACLList& aclList )
546 {
547  loadListView( aclList );
548  if ( mDlg->folder() ) // not when creating a new folder
549  mInitialACLList = aclList;
550  mStack->raiseWidget( mACLWidget );
551  slotSelectionChanged( mListView->selectedItem() );
552 }
553 
554 void KMail::FolderDiaACLTab::slotEditACL(TQListViewItem* item)
555 {
556  if ( !item ) return;
557  bool canAdmin = ( mUserRights & ACLJobs::Administer );
558  // Same logic as in slotSelectionChanged, but this is also needed for double-click IIRC
559  if ( canAdmin && mImapAccount && item ) {
560  // Don't allow users to remove their own admin permissions - there's no way back
561  ListViewItem* ACLitem = static_cast<ListViewItem *>( item );
562  if ( mImapAccount->login() == ACLitem->userId() && ACLitem->permissions() == ACLJobs::All )
563  canAdmin = false;
564  }
565  if ( !canAdmin ) return;
566 
567  ListViewItem* ACLitem = static_cast<ListViewItem *>( mListView->currentItem() );
568  ACLEntryDialog dlg( mUserIdFormat, i18n( "Modify Permissions" ), this );
569  dlg.setValues( ACLitem->userId(), ACLitem->permissions() );
570  if ( dlg.exec() == TQDialog::Accepted ) {
571  TQStringList userIds = dlg.userIds();
572  Q_ASSERT( !userIds.isEmpty() ); // impossible, the OK button is disabled in that case
573  ACLitem->setUserId( dlg.userIds().front() );
574  ACLitem->setPermissions( dlg.permissions() );
575  ACLitem->setModified( true );
576  emit changed(true);
577  if ( userIds.count() > 1 ) { // more emails were added, append them
578  userIds.pop_front();
579  addACLs( userIds, dlg.permissions() );
580  }
581  }
582 }
583 
584 void KMail::FolderDiaACLTab::slotEditACL()
585 {
586  slotEditACL( mListView->currentItem() );
587 }
588 
589 void KMail::FolderDiaACLTab::addACLs( const TQStringList& userIds, unsigned int permissions )
590 {
591  for( TQStringList::const_iterator it = userIds.begin(); it != userIds.end(); ++it ) {
592  ListViewItem* ACLitem = new ListViewItem( mListView );
593  ACLitem->setUserId( *it );
594  ACLitem->setPermissions( permissions );
595  ACLitem->setModified( true );
596  ACLitem->setNew( true );
597  }
598 }
599 
600 void KMail::FolderDiaACLTab::slotAddACL()
601 {
602  ACLEntryDialog dlg( mUserIdFormat, i18n( "Add Permissions" ), this );
603  if ( dlg.exec() == TQDialog::Accepted ) {
604  const TQStringList userIds = dlg.userIds();
605  addACLs( dlg.userIds(), dlg.permissions() );
606  emit changed(true);
607  }
608 }
609 
610 void KMail::FolderDiaACLTab::slotSelectionChanged(TQListViewItem* item)
611 {
612  bool canAdmin = ( mUserRights & ACLJobs::Administer );
613  bool canAdminThisItem = canAdmin;
614  if ( canAdmin && mImapAccount && item ) {
615  // Don't allow users to remove their own admin permissions - there's no way back
616  ListViewItem* ACLitem = static_cast<ListViewItem *>( item );
617  if ( mImapAccount->login() == ACLitem->userId() && ACLitem->permissions() == ACLJobs::All )
618  canAdminThisItem = false;
619  }
620 
621  bool lvVisible = mStack->visibleWidget() == mACLWidget;
622  mAddACL->setEnabled( lvVisible && canAdmin && !mSaving );
623  mEditACL->setEnabled( item && lvVisible && canAdminThisItem && !mSaving );
624  mRemoveACL->setEnabled( item && lvVisible && canAdminThisItem && !mSaving );
625 }
626 
627 void KMail::FolderDiaACLTab::slotRemoveACL()
628 {
629  ListViewItem* ACLitem = static_cast<ListViewItem *>( mListView->currentItem() );
630  if ( !ACLitem )
631  return;
632  if ( !ACLitem->isNew() ) {
633  if ( mImapAccount && mImapAccount->login() == ACLitem->userId() ) {
634  if ( KMessageBox::Cancel == KMessageBox::warningContinueCancel( topLevelWidget(),
635  i18n( "Do you really want to remove your own permissions for this folder? You will not be able to access it afterwards." ), i18n( "Remove" ) ) )
636  return;
637  }
638  mRemovedACLs.append( ACLitem->userId() );
639  }
640  delete ACLitem;
641  emit changed(true);
642 }
643 
644 KMail::FolderDiaTab::AccepStatus KMail::FolderDiaACLTab::accept()
645 {
646  if ( !mChanged || !mImapAccount )
647  return Accepted; // (no change made), ok for accepting the dialog immediately
648  // If there were changes, we need to apply them first (which is async)
649  save();
650  if ( mFolderType == KMFolderTypeCachedImap )
651  return Accepted; // cached imap: changes saved immediately into the folder
652  // disconnected imap: async job[s] running
653  mAccepting = true;
654  return Delayed;
655 }
656 
658 {
659  if ( !mChanged || !mImapAccount ) // no changes
660  return true;
661  assert( mDlg->folder() ); // should have been created already
662 
663  // Expand distribution lists. This is necessary because after Apply
664  // we would otherwise be able to "modify" the permissions for a distr list,
665  // which wouldn't work since the ACLList and the server only know about the
666  // individual addresses.
667  // slotACLChanged would have trouble matching the item too.
668  // After reloading we'd see the list expanded anyway,
669  // so this is more consistent.
670  // But we do it now and not when inserting it, because this allows to
671  // immediately remove a wrongly inserted distr list without having to
672  // remove 100 items.
673  // Now, how to expand them? Playing with listviewitem iterators and inserting
674  // listviewitems at the same time sounds dangerous, so let's just save into
675  // ACLList and reload that.
676  TDEABC::AddressBook *addressBook = TDEABC::StdAddressBook::self( true );
677 #ifndef TDEPIM_NEW_DISTRLISTS
678  TDEABC::DistributionListManager manager( addressBook );
679  manager.load();
680 #endif
681  ACLList aclList;
682  for ( TQListViewItem* item = mListView->firstChild(); item; item = item->nextSibling() ) {
683  ListViewItem* ACLitem = static_cast<ListViewItem *>( item );
684  ACLitem->save( aclList,
685 #ifdef TDEPIM_NEW_DISTRLISTS
686  addressBook,
687 #else
688  manager,
689 #endif
690  mUserIdFormat );
691  }
692  loadListView( aclList );
693 
694  // Now compare with the initial ACLList, because if the user renamed a userid
695  // we have to add the old userid to the "to be deleted" list.
696  for( ACLList::ConstIterator init = mInitialACLList.begin(); init != mInitialACLList.end(); ++init ) {
697  bool isInNewList = false;
698  TQString uid = (*init).userId;
699  for( ACLList::ConstIterator it = aclList.begin(); it != aclList.end() && !isInNewList; ++it )
700  isInNewList = uid == (*it).userId;
701  if ( !isInNewList && !mRemovedACLs.contains(uid) )
702  mRemovedACLs.append( uid );
703  }
704 
705  for ( TQStringList::ConstIterator rit = mRemovedACLs.begin(); rit != mRemovedACLs.end(); ++rit ) {
706  // We use permissions == -1 to signify deleting. At least on cyrus, setacl(0) or deleteacl are the same,
707  // but I'm not sure if that's true for all servers.
708  ACLListEntry entry( *rit, TQString(), -1 );
709  entry.changed = true;
710  aclList.append( entry );
711  }
712 
713  // aclList is finally ready. We can save it (dimap) or apply it (imap).
714 
715  if ( mFolderType == KMFolderTypeCachedImap ) {
716  // Apply the changes to the aclList stored in the folder.
717  // We have to do this now and not before, so that cancel really cancels.
718  KMFolderCachedImap* folderImap = static_cast<KMFolderCachedImap*>( mDlg->folder()->storage() );
719  folderImap->setACLList( aclList );
720  return true;
721  }
722 
723  mACLList = aclList;
724 
725  KMFolderImap* parentImap = mDlg->parentFolder() ? static_cast<KMFolderImap*>( mDlg->parentFolder()->storage() ) : 0;
726 
727  if ( mDlg->isNewFolder() ) {
728  // The folder isn't created yet, wait for it
729  // It's a two-step process (mkdir+listDir) so we wait for the dir listing to be complete
730  connect( parentImap, TQ_SIGNAL( directoryListingFinished(KMFolderImap*) ),
731  this, TQ_SLOT( slotDirectoryListingFinished(KMFolderImap*) ) );
732  } else {
733  slotDirectoryListingFinished( parentImap );
734  }
735  return true;
736 }
737 
738 void KMail::FolderDiaACLTab::slotDirectoryListingFinished(KMFolderImap* f)
739 {
740  if ( !f ||
741  f != static_cast<KMFolderImap*>( mDlg->parentFolder()->storage() ) ||
742  !mDlg->folder() ||
743  !mDlg->folder()->storage() ) {
744  emit readyForAccept();
745  return;
746  }
747 
748  // When creating a new folder with online imap, update mImapPath
749  KMFolderImap* folderImap = static_cast<KMFolderImap*>( mDlg->folder()->storage() );
750  if ( !folderImap || folderImap->imapPath().isEmpty() )
751  return;
752  mImapPath = folderImap->imapPath();
753 
754  TDEIO::Job* job = ACLJobs::multiSetACL( mImapAccount->slave(), imapURL(), mACLList );
756  jd.total = 1; jd.done = 0; jd.parent = 0;
757  mImapAccount->insertJob(job, jd);
758 
759  connect(job, TQ_SIGNAL(result(TDEIO::Job *)),
760  TQ_SLOT(slotMultiSetACLResult(TDEIO::Job *)));
761  connect(job, TQ_SIGNAL(aclChanged( const TQString&, int )),
762  TQ_SLOT(slotACLChanged( const TQString&, int )) );
763 }
764 
765 void KMail::FolderDiaACLTab::slotMultiSetACLResult(TDEIO::Job* job)
766 {
767  ImapAccountBase::JobIterator it = mImapAccount->findJob( job );
768  if ( it == mImapAccount->jobsEnd() ) return;
769  mImapAccount->removeJob( it );
770 
771  if ( job->error() ) {
772  job->showErrorDialog( this );
773  if ( mAccepting ) {
774  emit cancelAccept();
775  mAccepting = false; // don't emit readyForAccept anymore
776  }
777  } else {
778  if ( mAccepting )
779  emit readyForAccept();
780  }
781 }
782 
783 void KMail::FolderDiaACLTab::slotACLChanged( const TQString& userId, int permissions )
784 {
785  // The job indicates success in changing the permissions for this user
786  // -> we note that it's been done.
787  bool ok = false;
788  if ( permissions > -1 ) {
789  for ( TQListViewItem* item = mListView->firstChild(); item; item = item->nextSibling() ) {
790  ListViewItem* ACLitem = static_cast<ListViewItem *>( item );
791  if ( ACLitem->userId() == userId ) {
792  ACLitem->setModified( false );
793  ACLitem->setNew( false );
794  ok = true;
795  break;
796  }
797  }
798  } else {
799  uint nr = mRemovedACLs.remove( userId );
800  ok = ( nr > 0 );
801  }
802  if ( !ok )
803  kdWarning(5006) << k_funcinfo << " no item found for userId " << userId << endl;
804 }
805 
806 void KMail::FolderDiaACLTab::slotChanged( bool b )
807 {
808  mChanged = b;
809 }
810 
811 bool KMail::FolderDiaACLTab::supports( KMFolder* refFolder )
812 {
813  ImapAccountBase* imapAccount = 0;
814  if ( refFolder->folderType() == KMFolderTypeImap )
815  imapAccount = static_cast<KMFolderImap*>( refFolder->storage() )->account();
816  else
817  imapAccount = static_cast<KMFolderCachedImap*>( refFolder->storage() )->account();
818  return imapAccount && imapAccount->hasACLSupport(); // support for ACLs (or not tried connecting yet)
819 }
820 
821 #include "folderdiaacltab.moc"
Dialog for handling the properties of a mail folder.
Definition: kmfolderdia.h:199
Mail folder.
Definition: kmfolder.h:69
KMFolderType folderType() const
Returns the type of this folder.
Definition: kmfolder.cpp:233
"New Access Control Entry" dialog.
virtual bool save()
Unlike ConfigModuleTab, we return a bool from save.
virtual AccepStatus accept()
Called when clicking OK.
This is the base class for tabs in the folder dialog.
Definition: kmfolderdia.h:70
@ NotFetchedYet
The user rights/ACL have not been fetched from the server yet, we don't know them.
Definition: acljobs.h:65
@ Ok
The user rights/ACL have been fetched from the server sucessfully.
Definition: acljobs.h:66
@ FetchFailed
The attempt to fetch the user rights/ACL from the server failed.
Definition: acljobs.h:67
MultiSetACLJob * multiSetACL(TDEIO::Slave *slave, const KURL &url, const ACLList &acl)
Set and delete a list of permissions for different users on a given url.
Definition: acljobs.cpp:258
folderdiaquotatab.h
Definition: aboutdata.cpp:40
One entry in the ACL list: user and permissions.
Definition: acljobs.h:41
TQString internalRightsList
protocol-dependent string (e.g. IMAP rights list)
Definition: acljobs.h:46
int permissions
based on the ACLPermissions enum
Definition: acljobs.h:47
bool changed
special flag for KMFolderCachedImap
Definition: acljobs.h:48