From 805dff2b4fbccc8f2c2f5a72797166b866b436db Mon Sep 17 00:00:00 2001 From: David Faure Date: Tue, 8 Mar 2005 14:34:39 +0000 Subject: [PATCH] Fix for deletion of folders with subfolders: those need to be removed first (thanks Carsten for the hint). This is simply achieved by adding the imap paths of all subfolders to the account's mDeletedFolders list, and at sync time, asking the server to delete all those at the same time - in reverse order. Kolab issue678. svn path=/branches/proko2/kdepim/; revision=395795 --- cachedimapjob.cpp | 2 ++ kmacctcachedimap.cpp | 39 +++++++++++++++++++++++++++++++++++++-- kmacctcachedimap.h | 8 +++++++- kmfoldercachedimap.cpp | 4 ++-- kmmainwidget.cpp | 2 +- 5 files changed, 49 insertions(+), 6 deletions(-) diff --git a/cachedimapjob.cpp b/cachedimapjob.cpp index 4983803b8..400d7fadf 100644 --- a/cachedimapjob.cpp +++ b/cachedimapjob.cpp @@ -545,6 +545,8 @@ void CachedImapJob::slotDeleteNextFolder( KIO::Job *job ) return; } + mAccount->removeDeletedFolder( (*it).path ); + if( job->error() ) { mAccount->handleJobError( job, i18n( "Error while deleting folder %1 on the server: " ).arg( (*it).path ) + '\n' ); delete this; diff --git a/kmacctcachedimap.cpp b/kmacctcachedimap.cpp index 1c3b856cf..00df169df 100644 --- a/kmacctcachedimap.cpp +++ b/kmacctcachedimap.cpp @@ -277,7 +277,10 @@ void KMAcctCachedImap::postProcessNewMail( KMFolderCachedImap* folder, bool ) // instead of the user being stuck with "can't delete" every time. // And we do it for _all_ deleted folders, even those that were deleted on the server in the first place (slotListResult). // Otherwise this might have side effects much later (e.g. when regaining permissions to a folder we could see before) + +#if 0 // this opens a race: delete a folder during a sync (after the sync checked that folder), and it'll be forgotten... mDeletedFolders.clear(); +#endif mPreviouslyDeletedFolders.clear(); } @@ -379,9 +382,41 @@ void KMAcctCachedImap::invalidateIMAPFolders( KMFolderCachedImap* folder ) } //----------------------------------------------------------------------------- -void KMAcctCachedImap::addDeletedFolder( const QString& subFolderPath ) +void KMAcctCachedImap::addDeletedFolder( KMFolder* folder ) +{ + if ( folder->folderType() != KMFolderTypeCachedImap ) + return; + KMFolderCachedImap* storage = static_cast(folder->storage()); + mDeletedFolders << storage->imapPath(); + kdDebug(5006) << k_funcinfo << storage->imapPath() << endl; + + // Add all child folders too + if( folder && folder->child() ) { + KMFolderNode *node = folder->child()->first(); + while( node ) { + if( !node->isDir() ) { + addDeletedFolder( static_cast( node ) ); // recurse + } + node = folder->child()->next(); + } + } +} + +QStringList KMAcctCachedImap::deletedFolderPaths( const QString& subFolderPath ) const { - mDeletedFolders.append( subFolderPath ); + QStringList lst; + for ( QStringList::const_iterator it = mDeletedFolders.begin(); it != mDeletedFolders.end(); ++it ) { + if ( (*it).startsWith( subFolderPath ) ) + // We must reverse the order, so that sub sub sub folders are deleted first + lst.prepend( *it ); + } + for ( QStringList::const_iterator it = mPreviouslyDeletedFolders.begin(); it != mPreviouslyDeletedFolders.end(); ++it ) { + if ( (*it).startsWith( subFolderPath ) ) + lst.prepend( *it ); + } + kdDebug(5006) << "KMAcctCachedImap::deletedFolderPaths for " << subFolderPath << " returning: " << lst << endl; + Q_ASSERT( !lst.isEmpty() ); + return lst; } bool KMAcctCachedImap::isDeletedFolder( const QString& subFolderPath ) const diff --git a/kmacctcachedimap.h b/kmacctcachedimap.h index f81d432ad..0e9155309 100644 --- a/kmacctcachedimap.h +++ b/kmacctcachedimap.h @@ -38,6 +38,7 @@ class KMFolderCachedImap; class KMFolderTreeItem; +class KMFolder; namespace KMail { class FolderJob; class ImapJob; @@ -113,7 +114,7 @@ public: /** * Remember that a folder got explicitely deleted */ - void addDeletedFolder( const QString& subFolderPath ); + void addDeletedFolder( KMFolder* folder ); /** * Ask if a folder was explicitely deleted in this session @@ -125,6 +126,11 @@ public: */ bool isPreviouslyDeletedFolder( const QString& subFolderPath ) const; + /** + * return the imap path to the deleted folder, as well as the paths for any child folders + */ + QStringList deletedFolderPaths( const QString& subFolderPath ) const; + /** * Remove folder from the "deleted folders" list */ diff --git a/kmfoldercachedimap.cpp b/kmfoldercachedimap.cpp index 32b7a0900..282e212c9 100644 --- a/kmfoldercachedimap.cpp +++ b/kmfoldercachedimap.cpp @@ -400,7 +400,7 @@ int KMFolderCachedImap::rename( const QString& aName, // Make the change appear to the user with setLabel, but we'll do the change // on the server during the next sync. The name() is the name at the time of - // the last sync. Only rename if the new one is different. If it's the same, + // the last sync. Only rename if the new one is different. If it's the same, // don't rename, but also make sure the rename is reset, in the case of // A -> B -> A renames. if ( name() != aName ) @@ -1563,7 +1563,7 @@ void KMFolderCachedImap::listDirectory2() { if ( locallyDeleted ) { kdDebug(5006) << subfolderPath << " was deleted locally => delete on server." << endl; - foldersForDeletionOnServer << subfolderPath; + foldersForDeletionOnServer += mAccount->deletedFolderPaths( subfolderPath ); // grab all subsubfolders too } else { kdDebug(5006) << subfolderPath << " is a new folder on the server => create local cache" << endl; KMFolder* newFolder = folder()->child()->createFolder(mSubfolderNames[i], false, KMFolderTypeCachedImap); diff --git a/kmmainwidget.cpp b/kmmainwidget.cpp index abfd1dd05..e83492fba 100644 --- a/kmmainwidget.cpp +++ b/kmmainwidget.cpp @@ -1020,7 +1020,7 @@ void KMMainWidget::slotRemoveFolder() KMFolderCachedImap* storage = static_cast( mFolder->storage() ); KMAcctCachedImap* acct = storage->account(); if ( acct ) - acct->addDeletedFolder( storage->imapPath() ); + acct->addDeletedFolder( mFolder ); kmkernel->dimapFolderMgr()->remove(mFolder); }