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
65using 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
73static 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
85KMail::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
130void KMail::ACLEntryDialog::slotChanged()
131{
132 enableButtonOK( !mUserIdLineEdit->text().isEmpty() && mButtonGroup->selected() != 0 );
133}
134
135static 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
146void 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
169void KMail::ACLEntryDialog::setValues( const TQString& userId, unsigned int permissions )
170{
171 mUserIdLineEdit->setText( userId );
172 mButtonGroup->setButton( permissions );
173 enableButtonOK( !userId.isEmpty() );
174}
175
176TQString KMail::ACLEntryDialog::userId() const
177{
178 return mUserIdLineEdit->text();
179}
180
181TQStringList KMail::ACLEntryDialog::userIds() const
182{
183 return KPIM::splitEmailAddrList( mUserIdLineEdit->text() );
184}
185
186unsigned 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
197class KMail::FolderDiaACLTab::ListViewItem : public TDEListViewItem
198{
199public:
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
227private:
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
235static 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
249void KMail::FolderDiaACLTab::ListViewItem::setPermissions( unsigned int permissions )
250{
251 mPermissions = permissions;
252 setText( 1, permissionsToUserString( permissions, TQString() ) );
253}
254
255void 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
271void 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
315KMail::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
366KURL KMail::FolderDiaACLTab::imapURL() const
367{
368 KURL url = mImapAccount->getUrl();
369 url.setPath( mImapPath );
370 return url;
371}
372
373void 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
395void 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
467void 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
490void 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
505void 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
513void 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
531void 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
545void 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
554void 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
584void KMail::FolderDiaACLTab::slotEditACL()
585{
586 slotEditACL( mListView->currentItem() );
587}
588
589void 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
600void 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
610void 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
627void 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
644KMail::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
738void 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
765void 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
783void 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
806void KMail::FolderDiaACLTab::slotChanged( bool b )
807{
808 mChanged = b;
809}
810
811bool 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