kmail

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