kde-playground/kdepim-runtime/resources/imap/removecollectionrecursivetask.cpp
2015-04-14 22:08:21 +00:00

170 lines
6.2 KiB
C++

/*
Copyright (c) 2010 Klarälvdalens Datakonsult AB,
a KDAB Group company <info@kdab.com>
Author: Tobias Koenig <tokoe@kdab.com>
This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This library is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
*/
#include "removecollectionrecursivetask.h"
#include <akonadi/kmime/messageflags.h>
#include <kimap/deletejob.h>
#include <kimap/expungejob.h>
#include <kimap/selectjob.h>
#include <kimap/storejob.h>
#include <kimap/closejob.h>
#include <klocale.h>
Q_DECLARE_METATYPE( KIMAP::DeleteJob* )
RemoveCollectionRecursiveTask::RemoveCollectionRecursiveTask( ResourceStateInterface::Ptr resource, QObject *parent )
: ResourceTask( CancelIfNoSession, resource, parent ),
mSession( 0 ), mFolderFound( false )
{
}
RemoveCollectionRecursiveTask::~RemoveCollectionRecursiveTask()
{
}
void RemoveCollectionRecursiveTask::doStart( KIMAP::Session *session )
{
mSession = session;
mFolderFound = false;
KIMAP::ListJob *listJob = new KIMAP::ListJob( session );
listJob->setIncludeUnsubscribed( !isSubscriptionEnabled() );
listJob->setQueriedNamespaces( serverNamespaces() );
connect( listJob, SIGNAL(mailBoxesReceived(QList<KIMAP::MailBoxDescriptor>,QList<QList<QByteArray> >)),
this, SLOT(onMailBoxesReceived(QList<KIMAP::MailBoxDescriptor>,QList<QList<QByteArray> >)) );
connect( listJob, SIGNAL(result(KJob*)), SLOT(onJobDone(KJob*)) );
listJob->start();
}
void RemoveCollectionRecursiveTask::onMailBoxesReceived( const QList< KIMAP::MailBoxDescriptor > &descriptors,
const QList< QList<QByteArray> >& )
{
const QString mailBox = mailBoxForCollection( collection() );
// We have to delete the deepest-nested folders first, so
// we use a map here that has the level of nesting as key.
QMultiMap<int, KIMAP::MailBoxDescriptor > foldersToDelete;
for ( int i = 0; i < descriptors.size(); ++i ) {
const KIMAP::MailBoxDescriptor descriptor = descriptors[ i ];
if ( descriptor.name == mailBox || descriptor.name.startsWith( mailBox + descriptor.separator ) ) { // a sub folder to delete
const QStringList pathParts = descriptor.name.split( descriptor.separator );
foldersToDelete.insert( pathParts.count(), descriptor );
}
}
if ( foldersToDelete.isEmpty() ) {
return;
}
mFolderFound = true;
// Now start the actual deletion work
mFolderIterator.reset( new QMapIterator<int, KIMAP::MailBoxDescriptor >( foldersToDelete ) );
mFolderIterator->toBack(); // we start with largest nesting value first
deleteNextMailbox();
}
void RemoveCollectionRecursiveTask::deleteNextMailbox()
{
if ( !mFolderIterator->hasPrevious() ) {
changeProcessed(); // finish the job
return;
}
mFolderIterator->previous();
const KIMAP::MailBoxDescriptor &descriptor = mFolderIterator->value();
kDebug() << descriptor.name;
// first select the mailbox
KIMAP::SelectJob *selectJob = new KIMAP::SelectJob( mSession );
selectJob->setMailBox( descriptor.name );
connect( selectJob, SIGNAL(result(KJob*)), SLOT(onJobDone(KJob*)) );
selectJob->start();
// mark all items as deleted
// This step shouldn't be required, but apparently some servers don't allow deleting, non empty mailboxes (although they should).
KIMAP::ImapSet allItems;
allItems.add( KIMAP::ImapInterval( 1, 0 ) ); // means 1:*
KIMAP::StoreJob *storeJob = new KIMAP::StoreJob( mSession );
storeJob->setSequenceSet( allItems );
storeJob->setFlags( KIMAP::MessageFlags() << Akonadi::MessageFlags::Deleted );
storeJob->setMode( KIMAP::StoreJob::AppendFlags );
// The result is explicitly ignored, since this can fail in the case of an empty folder
storeJob->start();
// Some IMAP servers don't allow deleting an opened mailbox, so make sure
// it's not opened (https://bugs.kde.org/show_bug.cgi?id=324932). CLOSE will
// also trigger EXPUNGE to take care of the messages deleted above
KIMAP::CloseJob *closeJob = new KIMAP::CloseJob( mSession );
closeJob->setProperty( "folderDescriptor", descriptor.name );
connect( closeJob, SIGNAL(result(KJob*)), SLOT(onCloseJobDone(KJob*)) );
closeJob->start();
}
void RemoveCollectionRecursiveTask::onCloseJobDone( KJob* job )
{
if ( job->error() ) {
changeProcessed();
kDebug( 5327 ) << "Failed to close the folder, resync the folder tree";
emitWarning( i18n( "Failed to delete the folder, restoring folder list." ) );
synchronizeCollectionTree();
} else {
KIMAP::DeleteJob *deleteJob = new KIMAP::DeleteJob( mSession );
deleteJob->setMailBox( job->property( "folderDescriptor" ).toString() );
connect( deleteJob, SIGNAL(result(KJob*)), SLOT(onDeleteJobDone(KJob*)) );
deleteJob->start();
}
}
void RemoveCollectionRecursiveTask::onDeleteJobDone( KJob* job )
{
if ( job->error() ) {
changeProcessed();
kDebug( 5327 ) << "Failed to delete the folder, resync the folder tree";
emitWarning( i18n( "Failed to delete the folder, restoring folder list." ) );
synchronizeCollectionTree();
} else {
deleteNextMailbox();
}
}
void RemoveCollectionRecursiveTask::onJobDone( KJob* job )
{
if ( job->error() ) {
changeProcessed();
kDebug( 5327 ) << "Failed to delete the folder, resync the folder tree";
emitWarning( i18n( "Failed to delete the folder, restoring folder list." ) );
synchronizeCollectionTree();
} else if ( !mFolderFound ) {
changeProcessed();
kDebug( 5327 ) << "Failed to find the folder to be deleted, resync the folder tree";
emitWarning( i18n( "Failed to find the folder to be deleted, restoring folder list." ) );
synchronizeCollectionTree();
}
}