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

294 lines
9.8 KiB
C++

/*
Copyright (c) 2010 Klarälvdalens Datakonsult AB,
a KDAB Group company <info@kdab.com>
Author: Kevin Ottens <kevin@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 "changecollectiontask.h"
#include <kimap/renamejob.h>
#include <kimap/setacljob.h>
#include <kimap/setmetadatajob.h>
#include <kimap/session.h>
#include <kimap/subscribejob.h>
#include "collectionannotationsattribute.h"
#include "imapaclattribute.h"
#include "imapquotaattribute.h"
#include <KLocalizedString>
ChangeCollectionTask::ChangeCollectionTask( ResourceStateInterface::Ptr resource, QObject *parent )
: ResourceTask( DeferIfNoSession, resource, parent ), m_pendingJobs(0)
{
}
ChangeCollectionTask::~ChangeCollectionTask()
{
}
void ChangeCollectionTask::doStart( KIMAP::Session *session )
{
if ( collection().remoteId().isEmpty() ) {
emitError( i18n( "Cannot modify IMAP folder '%1', it does not exist on the server.",
collection().name() ) );
changeProcessed();
return;
}
m_collection = collection();
m_pendingJobs = 0;
if ( parts().contains( "AccessRights" ) ) {
Akonadi::ImapAclAttribute *aclAttribute = collection().attribute<Akonadi::ImapAclAttribute>();
if ( aclAttribute==0 ) {
emitWarning( i18n( "ACLs for '%1' need to be retrieved from the IMAP server first. Skipping ACL change",
collection().name() ) );
} else {
KIMAP::Acl::Rights imapRights = aclAttribute->rights()[userName().toUtf8()];
Akonadi::Collection::Rights newRights = collection().rights();
if ( newRights & Akonadi::Collection::CanChangeItem ) {
imapRights|= KIMAP::Acl::Write;
} else {
imapRights&= ~KIMAP::Acl::Write;
}
if ( newRights & Akonadi::Collection::CanCreateItem ) {
imapRights|= KIMAP::Acl::Insert;
} else {
imapRights&= ~KIMAP::Acl::Insert;
}
if ( newRights & Akonadi::Collection::CanDeleteItem ) {
imapRights|= KIMAP::Acl::DeleteMessage;
} else {
imapRights&= ~KIMAP::Acl::DeleteMessage;
}
if ( newRights & ( Akonadi::Collection::CanChangeCollection | Akonadi::Collection::CanCreateCollection ) ) {
imapRights|= KIMAP::Acl::CreateMailbox;
imapRights|= KIMAP::Acl::Create;
} else {
imapRights&= ~KIMAP::Acl::CreateMailbox;
imapRights&= ~KIMAP::Acl::Create;
}
if ( newRights & Akonadi::Collection::CanDeleteCollection ) {
imapRights|= KIMAP::Acl::DeleteMailbox;
} else {
imapRights&= ~KIMAP::Acl::DeleteMailbox;
}
if ( ( newRights & Akonadi::Collection::CanDeleteItem )
&& ( newRights & Akonadi::Collection::CanDeleteCollection ) ) {
imapRights|= KIMAP::Acl::Delete;
} else {
imapRights&= ~KIMAP::Acl::Delete;
}
kDebug( 5327 ) << "imapRights:" << imapRights
<< "newRights:" << newRights;
KIMAP::SetAclJob *job = new KIMAP::SetAclJob( session );
job->setMailBox( mailBoxForCollection( collection() ) );
job->setRights( KIMAP::SetAclJob::Change, imapRights );
job->setIdentifier( userName().toUtf8() );
connect( job, SIGNAL(result(KJob*)),
this, SLOT(onSetAclDone(KJob*)) );
job->start();
m_pendingJobs++;
}
}
if ( parts().contains( "collectionannotations" ) && serverSupportsAnnotations() ) {
Akonadi::CollectionAnnotationsAttribute *annotationsAttribute =
collection().attribute<Akonadi::CollectionAnnotationsAttribute>();
if ( annotationsAttribute ) { // No annotations it seems... server is lieing to us?
QMap<QByteArray, QByteArray> annotations = annotationsAttribute->annotations();
kDebug( 5327 ) << "All annotations: " << annotations;
foreach ( const QByteArray &entry, annotations.keys() ) { //krazy:exclude=foreach
KIMAP::SetMetaDataJob *job = new KIMAP::SetMetaDataJob( session );
if ( serverCapabilities().contains( QLatin1String("METADATA") ) ) {
job->setServerCapability( KIMAP::MetaDataJobBase::Metadata );
} else {
job->setServerCapability( KIMAP::MetaDataJobBase::Annotatemore );
}
job->setMailBox( mailBoxForCollection( collection() ) );
if ( !entry.startsWith( "/shared" ) && !entry.startsWith( "/private" ) ) {
//Support for legacy annotations that don't include the prefix
job->addMetaData( QByteArray("/shared") + entry, annotations[entry] );
} else {
job->addMetaData( entry, annotations[entry] );
}
kDebug( 5327 ) << "Job got entry:" << entry << "value:" << annotations[entry];
connect( job, SIGNAL(result(KJob*)),
this, SLOT(onSetMetaDataDone(KJob*)) );
job->start();
m_pendingJobs++;
}
}
}
if ( parts().contains( "imapacl" ) ) {
Akonadi::ImapAclAttribute *aclAttribute = collection().attribute<Akonadi::ImapAclAttribute>();
if ( aclAttribute ) {
const QMap<QByteArray, KIMAP::Acl::Rights> rights = aclAttribute->rights();
const QMap<QByteArray, KIMAP::Acl::Rights> oldRights = aclAttribute->oldRights();
const QList<QByteArray> oldIds = oldRights.keys();
const QList<QByteArray> ids = rights.keys();
// remove all ACL entries that have been deleted
foreach ( const QByteArray &oldId, oldIds ) {
if ( !ids.contains( oldId ) ) {
KIMAP::SetAclJob *job = new KIMAP::SetAclJob( session );
job->setMailBox( mailBoxForCollection( collection() ) );
job->setIdentifier( oldId );
job->setRights( KIMAP::SetAclJob::Remove, oldRights[oldId] );
connect( job, SIGNAL(result(KJob*)),
this, SLOT(onSetAclDone(KJob*)) );
job->start();
m_pendingJobs++;
}
}
foreach ( const QByteArray &id, ids ) {
KIMAP::SetAclJob *job = new KIMAP::SetAclJob( session );
job->setMailBox( mailBoxForCollection( collection() ) );
job->setIdentifier( id );
job->setRights( KIMAP::SetAclJob::Change, rights[id] );
connect( job, SIGNAL(result(KJob*)),
this, SLOT(onSetAclDone(KJob*)) );
job->start();
m_pendingJobs++;
}
}
}
// Check if we need to rename the mailbox
// This one goes last on purpose, we don't want the previous jobs
// we triggered to act on the wrong mailbox name
if ( parts().contains( "NAME" ) ) {
const QChar separator = separatorCharacter();
m_collection.setName( m_collection.name().replace( separator, QString() ) );
m_collection.setRemoteId( separator + m_collection.name() );
const QString oldMailBox = mailBoxForCollection( collection() );
const QString newMailBox = mailBoxForCollection( m_collection );
if ( oldMailBox != newMailBox ) {
KIMAP::RenameJob *renameJob = new KIMAP::RenameJob( session );
renameJob->setSourceMailBox( oldMailBox );
renameJob->setDestinationMailBox( newMailBox );
connect( renameJob, SIGNAL(result(KJob*)),
this, SLOT(onRenameDone(KJob*)) );
renameJob->start();
m_pendingJobs++;
}
}
// we scheduled no change on the server side, probably we got only
// unsupported part, so just declare the task done
if ( m_pendingJobs == 0 ) {
changeCommitted( collection() );
}
}
void ChangeCollectionTask::onRenameDone( KJob *job )
{
if ( job->error() ) {
const QString prevRid = collection().remoteId();
Q_ASSERT( !prevRid.isEmpty() );
emitWarning( i18n( "Failed to rename the folder, restoring folder list." ) );
m_collection.setName( prevRid.mid( 1 ) );
m_collection.setRemoteId( prevRid );
endTaskIfNeeded();
} else {
KIMAP::RenameJob *renameJob = static_cast<KIMAP::RenameJob*>( job );
KIMAP::SubscribeJob *subscribeJob = new KIMAP::SubscribeJob( renameJob->session() );
subscribeJob->setMailBox( renameJob->destinationMailBox() );
connect( subscribeJob, SIGNAL(result(KJob*)),
this, SLOT(onSubscribeDone(KJob*)) );
subscribeJob->start();
}
}
void ChangeCollectionTask::onSubscribeDone( KJob *job )
{
if ( job->error() && isSubscriptionEnabled() ) {
emitWarning( i18n( "Failed to subscribe to the renamed folder '%1' on the IMAP server. "
"It will disappear on next sync. Use the subscription dialog to overcome that",
m_collection.name() ) );
}
endTaskIfNeeded();
}
void ChangeCollectionTask::onSetAclDone( KJob *job )
{
if ( job->error() ) {
emitWarning( i18n( "Failed to write some ACLs for '%1' on the IMAP server. %2",
collection().name(), job->errorText() ) );
}
endTaskIfNeeded();
}
void ChangeCollectionTask::onSetMetaDataDone( KJob *job )
{
if ( job->error() ) {
emitWarning( i18n( "Failed to write some annotations for '%1' on the IMAP server. %2",
collection().name(), job->errorText() ) );
}
endTaskIfNeeded();
}
void ChangeCollectionTask::endTaskIfNeeded()
{
if ( --m_pendingJobs == 0 ) {
// the others have ended, we're done, the next one can go
changeCommitted( m_collection );
}
}