mirror of
https://bitbucket.org/smil3y/kde-playground.git
synced 2025-02-24 19:02:51 +00:00
835 lines
26 KiB
C++
835 lines
26 KiB
C++
/* This file is part of the KDE project
|
|
Copyright (c) 2007 Till Adam <adam@kde.org>
|
|
Copyright (C) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net
|
|
Author: Kevin Krammer, krake@kdab.com
|
|
Copyright (C) 2011 Kevin Krammer <kevin.krammer@gmx.at>
|
|
|
|
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 "mixedmaildirresource.h"
|
|
|
|
#include "compactchangehelper.h"
|
|
#include "configdialog.h"
|
|
#include "mixedmaildirstore.h"
|
|
#include "settings.h"
|
|
#include "settingsadaptor.h"
|
|
#include "retrieveitemsjob.h"
|
|
#include "createandsettagsjob.h"
|
|
|
|
|
|
#include "filestore/collectioncreatejob.h"
|
|
#include "filestore/collectiondeletejob.h"
|
|
#include "filestore/collectionfetchjob.h"
|
|
#include "filestore/collectionmodifyjob.h"
|
|
#include "filestore/collectionmovejob.h"
|
|
#include "filestore/entitycompactchangeattribute.h"
|
|
#include "filestore/itemcreatejob.h"
|
|
#include "filestore/itemdeletejob.h"
|
|
#include "filestore/itemfetchjob.h"
|
|
#include "filestore/itemmodifyjob.h"
|
|
#include "filestore/itemmovejob.h"
|
|
#include "filestore/storecompactjob.h"
|
|
|
|
#include <akonadi/kmime/messageparts.h>
|
|
#include <akonadi/kmime/messagestatus.h>
|
|
|
|
#include <akonadi/changerecorder.h>
|
|
#include <akonadi/itemfetchjob.h>
|
|
#include <akonadi/itemfetchscope.h>
|
|
#include <akonadi/itemmodifyjob.h>
|
|
#include <akonadi/collectionfetchscope.h>
|
|
|
|
#include <kmime/kmime_message.h>
|
|
|
|
#include <KDebug>
|
|
#include <KLocalizedString>
|
|
#include <KWindowSystem>
|
|
|
|
#include <QtCore/QDir>
|
|
#include <QtDBus/QDBusConnection>
|
|
|
|
#include <Akonadi/Tag>
|
|
|
|
using namespace Akonadi;
|
|
|
|
|
|
|
|
MixedMaildirResource::MixedMaildirResource( const QString &id )
|
|
: ResourceBase( id ), mStore( new MixedMaildirStore() ), mCompactHelper( 0 )
|
|
{
|
|
new SettingsAdaptor( Settings::self() );
|
|
QDBusConnection::sessionBus().registerObject( QLatin1String( "/Settings" ),
|
|
Settings::self(), QDBusConnection::ExportAdaptors );
|
|
connect( this, SIGNAL(reloadConfiguration()), SLOT(reapplyConfiguration()) );
|
|
|
|
// We need to enable this here, otherwise we neither get the remote ID of the
|
|
// parent collection when a collection changes, nor the full item when an item
|
|
// is added.
|
|
changeRecorder()->fetchCollection( true );
|
|
changeRecorder()->itemFetchScope().fetchFullPayload( true );
|
|
changeRecorder()->itemFetchScope().setAncestorRetrieval( ItemFetchScope::All );
|
|
changeRecorder()->collectionFetchScope().setAncestorRetrieval( CollectionFetchScope::All );
|
|
|
|
setHierarchicalRemoteIdentifiersEnabled( true );
|
|
|
|
if ( ensureSaneConfiguration() ) {
|
|
const bool changeName = name().isEmpty() || name() == identifier() ||
|
|
name() == mStore->topLevelCollection().name();
|
|
mStore->setPath( Settings::self()->path() );
|
|
if ( changeName ) {
|
|
setName( mStore->topLevelCollection().name() );
|
|
}
|
|
}
|
|
|
|
const QByteArray compactHelperSessionId = id.toUtf8() + "-compacthelper";
|
|
mCompactHelper = new CompactChangeHelper( compactHelperSessionId, this );
|
|
}
|
|
|
|
MixedMaildirResource::~MixedMaildirResource()
|
|
{
|
|
delete mStore;
|
|
}
|
|
|
|
void MixedMaildirResource::aboutToQuit()
|
|
{
|
|
// The settings may not have been saved if e.g. they have been modified via
|
|
// DBus instead of the config dialog.
|
|
Settings::self()->writeConfig();
|
|
}
|
|
|
|
void MixedMaildirResource::configure( WId windowId )
|
|
{
|
|
ConfigDialog dlg;
|
|
if ( windowId ) {
|
|
KWindowSystem::setMainWindow( &dlg, windowId );
|
|
}
|
|
dlg.setWindowIcon( KIcon( "message-rfc822" ) );
|
|
|
|
bool fullSync = false;
|
|
|
|
if ( dlg.exec() ) {
|
|
const bool changeName = name().isEmpty() || name() == identifier() ||
|
|
name() == mStore->topLevelCollection().name();
|
|
|
|
const QString oldPath = mStore->path();
|
|
mStore->setPath( Settings::self()->path() );
|
|
|
|
fullSync = oldPath != mStore->path();
|
|
|
|
if ( changeName ) {
|
|
setName( mStore->topLevelCollection().name() );
|
|
}
|
|
emit configurationDialogAccepted();
|
|
} else {
|
|
emit configurationDialogRejected();
|
|
}
|
|
|
|
if ( ensureDirExists() ) {
|
|
if ( fullSync ) {
|
|
mSynchronizedCollections.clear();
|
|
mPendingSynchronizeCollections.clear();
|
|
}
|
|
synchronizeCollectionTree();
|
|
}
|
|
}
|
|
|
|
void MixedMaildirResource::itemAdded( const Item &item, const Collection& collection )
|
|
{
|
|
/* kDebug() << "item.id=" << item.id() << "col=" << collection.remoteId();*/
|
|
if ( !ensureSaneConfiguration() ) {
|
|
const QString message = i18nc( "@info:status", "Unusable configuration." );
|
|
kError() << message;
|
|
cancelTask( message );
|
|
return;
|
|
}
|
|
|
|
FileStore::ItemCreateJob *job = mStore->createItem( item, collection );
|
|
connect( job, SIGNAL(result(KJob*)), SLOT(itemAddedResult(KJob*)) );
|
|
}
|
|
|
|
void MixedMaildirResource::itemChanged( const Item &item, const QSet<QByteArray>& parts )
|
|
{
|
|
/* kDebug() << "item.id=" << item.id() << "col=" << item.parentCollection().remoteId()
|
|
<< "parts=" << parts;*/
|
|
if ( !ensureSaneConfiguration() ) {
|
|
const QString message = i18nc( "@info:status", "Unusable configuration." );
|
|
kError() << message;
|
|
cancelTask( message );
|
|
return;
|
|
}
|
|
|
|
if ( Settings::self()->readOnly() ) {
|
|
changeProcessed();
|
|
return;
|
|
}
|
|
|
|
Item storeItem( item );
|
|
storeItem.setRemoteId( mCompactHelper->currentRemoteId( item ) );
|
|
|
|
FileStore::ItemModifyJob *job = mStore->modifyItem( storeItem );
|
|
job->setIgnorePayload( !item.hasPayload<KMime::Message::Ptr>() );
|
|
job->setParts( parts );
|
|
job->setProperty( "originalRemoteId", storeItem.remoteId() );
|
|
connect( job, SIGNAL(result(KJob*)), SLOT(itemChangedResult(KJob*)) );
|
|
}
|
|
|
|
void MixedMaildirResource::itemMoved( const Item &item, const Collection &source, const Collection &destination )
|
|
{
|
|
/* kDebug() << "item.id=" << item.id() << "remoteId=" << item.remoteId()
|
|
<< "source=" << source.remoteId() << "dest=" << destination.remoteId();*/
|
|
if ( source == destination ) {
|
|
changeProcessed();
|
|
return;
|
|
}
|
|
|
|
if ( !ensureSaneConfiguration() ) {
|
|
const QString message = i18nc( "@info:status", "Unusable configuration." );
|
|
kError() << message;
|
|
cancelTask( message );
|
|
return;
|
|
}
|
|
|
|
Item moveItem = item;
|
|
moveItem.setRemoteId( mCompactHelper->currentRemoteId( item ) );
|
|
moveItem.setParentCollection( source );
|
|
|
|
FileStore::ItemMoveJob *job = mStore->moveItem( moveItem, destination );
|
|
job->setProperty( "originalRemoteId", moveItem.remoteId() );
|
|
connect( job, SIGNAL(result(KJob*)), SLOT(itemMovedResult(KJob*)) );
|
|
}
|
|
|
|
void MixedMaildirResource::itemRemoved(const Item &item)
|
|
{
|
|
/* kDebug() << "item.id=" << item.id() << "col=" << collection.remoteId()
|
|
<< "collection.remoteRevision=" << item.parentCollection().remoteRevision();*/
|
|
Q_ASSERT( !item.remoteId().isEmpty() );
|
|
Q_ASSERT( item.parentCollection().isValid() );
|
|
if ( item.parentCollection().remoteId().isEmpty() ) {
|
|
const QString message = i18nc( "@info:status", "Item %1 belongs to invalid collection %2. Maybe it was deleted meanwhile?", item.id(), item.parentCollection().id() );
|
|
kError() << message;
|
|
cancelTask( message );
|
|
return;
|
|
}
|
|
|
|
if ( !ensureSaneConfiguration() ) {
|
|
const QString message = i18nc( "@info:status", "Unusable configuration." );
|
|
kError() << message;
|
|
cancelTask( message );
|
|
return;
|
|
}
|
|
|
|
Item storeItem( item );
|
|
storeItem.setRemoteId( mCompactHelper->currentRemoteId( item ) );
|
|
FileStore::ItemDeleteJob *job = mStore->deleteItem( storeItem );
|
|
connect( job, SIGNAL(result(KJob*)), SLOT(itemRemovedResult(KJob*)) );
|
|
}
|
|
|
|
void MixedMaildirResource::retrieveCollections()
|
|
{
|
|
if ( !ensureSaneConfiguration() ) {
|
|
const QString message = i18nc( "@info:status", "Unusable configuration." );
|
|
kError() << message;
|
|
cancelTask( message );
|
|
return;
|
|
}
|
|
|
|
FileStore::CollectionFetchJob *job = mStore->fetchCollections( mStore->topLevelCollection(), FileStore::CollectionFetchJob::Recursive );
|
|
connect( job, SIGNAL(result(KJob*)), SLOT(retrieveCollectionsResult(KJob*)) );
|
|
|
|
status( Running, i18nc( "@info:status", "Synchronizing email folders" ) );
|
|
}
|
|
|
|
void MixedMaildirResource::retrieveItems( const Collection & col )
|
|
{
|
|
if ( !ensureSaneConfiguration() ) {
|
|
const QString message = i18nc( "@info:status", "Unusable configuration." );
|
|
kError() << message;
|
|
cancelTask( message );
|
|
return;
|
|
}
|
|
|
|
RetrieveItemsJob *job = new RetrieveItemsJob( col, mStore, this );
|
|
connect( job, SIGNAL(result(KJob*)), SLOT(retrieveItemsResult(KJob*)) );
|
|
|
|
status( Running, i18nc( "@info:status", "Synchronizing email folder %1", col.name() ) );
|
|
}
|
|
|
|
bool MixedMaildirResource::retrieveItem( const Item &item, const QSet<QByteArray> &parts )
|
|
{
|
|
Q_UNUSED( parts );
|
|
|
|
FileStore::ItemFetchJob *job = mStore->fetchItem( item );
|
|
if ( parts.contains( Item::FullPayload ) ) {
|
|
job->fetchScope().fetchFullPayload( true );
|
|
} else {
|
|
Q_FOREACH( const QByteArray &part, parts ) {
|
|
job->fetchScope().fetchPayloadPart( part, true );
|
|
}
|
|
}
|
|
connect( job, SIGNAL(result(KJob*)), SLOT(retrieveItemResult(KJob*)) );
|
|
|
|
return true;
|
|
}
|
|
|
|
void MixedMaildirResource::collectionAdded(const Collection &collection, const Collection &parent)
|
|
{
|
|
if ( !ensureSaneConfiguration() ) {
|
|
const QString message = i18nc( "@info:status", "Unusable configuration." );
|
|
kError() << message;
|
|
cancelTask( message );
|
|
return;
|
|
}
|
|
|
|
FileStore::CollectionCreateJob *job = mStore->createCollection( collection, parent );
|
|
connect( job, SIGNAL(result(KJob*)), SLOT(collectionAddedResult(KJob*)) );
|
|
}
|
|
|
|
void MixedMaildirResource::collectionChanged(const Collection &collection)
|
|
{
|
|
if ( !ensureSaneConfiguration() ) {
|
|
const QString message = i18nc( "@info:status", "Unusable configuration." );
|
|
kError() << message;
|
|
cancelTask( message );
|
|
return;
|
|
}
|
|
|
|
// when the top level collection gets renamed, we do not rename the directory
|
|
// but rename the resource.
|
|
if ( collection.remoteId() == mStore->topLevelCollection().remoteId() ) {
|
|
if ( collection.name() != name() ) {
|
|
kDebug() << "TopLevel collection name differs from resource name: collection="
|
|
<< collection.name() << "resource=" << name() << ". Renaming resource";
|
|
setName( collection.name() );
|
|
}
|
|
changeCommitted( collection );
|
|
return;
|
|
}
|
|
|
|
mCompactHelper->checkCollectionChanged( collection );
|
|
|
|
FileStore::CollectionModifyJob *job = mStore->modifyCollection( collection );
|
|
connect( job, SIGNAL(result(KJob*)), SLOT(collectionChangedResult(KJob*)) );
|
|
}
|
|
|
|
void MixedMaildirResource::collectionChanged(const Collection &collection, const QSet<QByteArray> &changedAttributes )
|
|
{
|
|
if ( !ensureSaneConfiguration() ) {
|
|
const QString message = i18nc( "@info:status", "Unusable configuration." );
|
|
kError() << message;
|
|
cancelTask( message );
|
|
return;
|
|
}
|
|
|
|
// when the top level collection gets renamed, we do not rename the directory
|
|
// but rename the resource.
|
|
if ( collection.remoteId() == mStore->topLevelCollection().remoteId() ) {
|
|
if ( collection.name() != name() ) {
|
|
kDebug() << "TopLevel collection name differs from resource name: collection="
|
|
<< collection.name() << "resource=" << name() << ". Renaming resource";
|
|
setName( collection.name() );
|
|
}
|
|
changeCommitted( collection );
|
|
return;
|
|
}
|
|
|
|
mCompactHelper->checkCollectionChanged( collection );
|
|
|
|
Q_UNUSED( changedAttributes );
|
|
|
|
FileStore::CollectionModifyJob *job = mStore->modifyCollection( collection );
|
|
connect( job, SIGNAL(result(KJob*)), SLOT(collectionChangedResult(KJob*)) );
|
|
}
|
|
|
|
void MixedMaildirResource::collectionMoved( const Collection &collection, const Collection &source, const Collection &dest )
|
|
{
|
|
//kDebug( KDE_DEFAULT_DEBUG_AREA ) << collection << source << dest;
|
|
|
|
if ( !ensureSaneConfiguration() ) {
|
|
const QString message = i18nc( "@info:status", "Unusable configuration." );
|
|
kError() << message;
|
|
cancelTask( message );
|
|
return;
|
|
}
|
|
|
|
if ( collection.parentCollection() == Collection::root() ) {
|
|
const QString message = i18nc( "@info:status", "Cannot move root maildir folder '%1'." ,collection.remoteId() );
|
|
kError() << message;
|
|
cancelTask( message );
|
|
return;
|
|
}
|
|
|
|
if ( source == dest ) { // should not happen, but who knows...
|
|
changeProcessed();
|
|
return;
|
|
}
|
|
|
|
Collection moveCollection = collection;
|
|
moveCollection.setParentCollection( source );
|
|
|
|
FileStore::CollectionMoveJob *job = mStore->moveCollection( moveCollection, dest );
|
|
connect( job, SIGNAL(result(KJob*)), SLOT(collectionMovedResult(KJob*)) );
|
|
}
|
|
|
|
void MixedMaildirResource::collectionRemoved( const Collection &collection )
|
|
{
|
|
if ( !ensureSaneConfiguration() ) {
|
|
const QString message = i18nc( "@info:status", "Unusable configuration." );
|
|
kError() << message;
|
|
cancelTask( message );
|
|
return;
|
|
}
|
|
|
|
if ( collection.parentCollection() == Collection::root() ) {
|
|
emit error( i18n( "Cannot delete top-level maildir folder '%1'.", Settings::self()->path() ) );
|
|
changeProcessed();
|
|
return;
|
|
}
|
|
|
|
FileStore::CollectionDeleteJob *job = mStore->deleteCollection( collection );
|
|
connect( job, SIGNAL(result(KJob*)), SLOT(collectionRemovedResult(KJob*)) );
|
|
}
|
|
|
|
bool MixedMaildirResource::ensureDirExists()
|
|
{
|
|
QDir dir( Settings::self()->path() );
|
|
if ( !dir.exists() ) {
|
|
if ( !dir.mkpath( Settings::self()->path() ) ) {
|
|
const QString message = i18nc( "@info:status", "Unable to create maildir '%1'.", Settings::self()->path() );
|
|
kError() << message;
|
|
status( Broken, message );
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool MixedMaildirResource::ensureSaneConfiguration()
|
|
{
|
|
if ( Settings::self()->path().isEmpty() ) {
|
|
const QString message = i18nc( "@info:status", "No usable storage location configured." );
|
|
kError() << message;
|
|
status( NotConfigured, message );
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void MixedMaildirResource::checkForInvalidatedIndexCollections( KJob * job )
|
|
{
|
|
// when operations invalidate the on-disk index, we need to make sure all index
|
|
// data has been transferred into Akonadi by synchronizing the collections
|
|
const QVariant var = job->property( "onDiskIndexInvalidated" );
|
|
if ( var.isValid() ) {
|
|
const Collection::List collections = var.value<Collection::List>();
|
|
kDebug( KDE_DEFAULT_DEBUG_AREA ) << "On disk index of" << collections.count()
|
|
<< "collections invalidated after" << job->metaObject()->className();
|
|
|
|
Q_FOREACH( const Collection &collection, collections ) {
|
|
const Collection::Id id = collection.id();
|
|
if ( !mSynchronizedCollections.contains( id ) && !mPendingSynchronizeCollections.contains( id ) ) {
|
|
kDebug( KDE_DEFAULT_DEBUG_AREA ) << "Requesting sync of collection" << collection.name()
|
|
<< ", id=" << collection.id();
|
|
mPendingSynchronizeCollections << id;
|
|
synchronizeCollection( id );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void MixedMaildirResource::reapplyConfiguration()
|
|
{
|
|
if ( ensureSaneConfiguration() && ensureDirExists() ) {
|
|
const QString oldPath = mStore->path();
|
|
mStore->setPath( Settings::self()->path() );
|
|
|
|
if ( oldPath != mStore->path() ) {
|
|
mSynchronizedCollections.clear();
|
|
mPendingSynchronizeCollections.clear();
|
|
}
|
|
synchronizeCollectionTree();
|
|
}
|
|
}
|
|
|
|
void MixedMaildirResource::retrieveCollectionsResult( KJob *job )
|
|
{
|
|
if ( job->error() != 0 ) {
|
|
kError() << job->errorString();
|
|
status( Broken, job->errorString() );
|
|
cancelTask( job->errorString() );
|
|
return;
|
|
}
|
|
|
|
FileStore::CollectionFetchJob *fetchJob = qobject_cast<FileStore::CollectionFetchJob*>( job );
|
|
Q_ASSERT( fetchJob != 0 );
|
|
|
|
Collection topLevelCollection = mStore->topLevelCollection();
|
|
if ( !name().isEmpty() && name() != identifier() ) {
|
|
topLevelCollection.setName( name() );
|
|
}
|
|
|
|
Collection::List collections;
|
|
collections << topLevelCollection;
|
|
collections << fetchJob->collections();
|
|
collectionsRetrieved( collections );
|
|
}
|
|
|
|
void MixedMaildirResource::retrieveItemsResult( KJob *job )
|
|
{
|
|
if ( job->error() != 0 ) {
|
|
kError() << job->errorString();
|
|
status( Broken, job->errorString() );
|
|
cancelTask( job->errorString() );
|
|
return;
|
|
}
|
|
|
|
RetrieveItemsJob *retrieveJob = qobject_cast<RetrieveItemsJob*>( job );
|
|
Q_ASSERT( retrieveJob != 0 );
|
|
|
|
// messages marked as deleted have been deleted from mbox files but never got purged
|
|
// TODO FileStore could provide deleteItems() to deleted all filtered items in one go
|
|
KJob* deleteJob = 0;
|
|
kDebug( KDE_DEFAULT_DEBUG_AREA ) << retrieveJob->itemsMarkedAsDeleted().count()
|
|
<< "items marked as Deleted";
|
|
Q_FOREACH( const Item &item, retrieveJob->itemsMarkedAsDeleted() ) {
|
|
deleteJob = mStore->deleteItem( item );
|
|
}
|
|
|
|
if ( deleteJob != 0 ) {
|
|
// last item delete triggers mbox purge, i.e. store compact
|
|
const bool connected = connect( deleteJob, SIGNAL(result(KJob*)), this, SLOT(itemsDeleted(KJob*)) );
|
|
Q_ASSERT( connected );
|
|
Q_UNUSED( connected );
|
|
}
|
|
|
|
// if some items have tags, we need to complete the retrieval and schedule tagging
|
|
// to a later time so we can then fetch the items to get their Akonadi URLs
|
|
const Item::List items = retrieveJob->availableItems();
|
|
const QVariant var = retrieveJob->property( "remoteIdToTagList" );
|
|
if ( var.isValid() ) {
|
|
const QHash<QString, QVariant> tagListHash = var.value< QHash<QString, QVariant> >();
|
|
if ( !tagListHash.isEmpty() ) {
|
|
kDebug() << tagListHash.count() << "of" << items.count()
|
|
<< "items in collection" << retrieveJob->collection().remoteId() << "have tags";
|
|
|
|
TagContextList taggedItems;
|
|
Q_FOREACH( const Item &item, items ) {
|
|
const QVariant tagListVar = tagListHash[ item.remoteId() ];
|
|
if ( tagListVar.isValid() ) {
|
|
const QStringList tagList = tagListVar.value<QStringList>();
|
|
if ( !tagListHash.isEmpty() ) {
|
|
TagContext tag;
|
|
tag.mItem = item;
|
|
tag.mTagList = tagList;
|
|
|
|
taggedItems << tag;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !taggedItems.isEmpty() ) {
|
|
mTagContextByColId.insert( retrieveJob->collection().id(), taggedItems );
|
|
|
|
scheduleCustomTask( this, "restoreTags", QVariant::fromValue<Collection>( retrieveJob->collection() ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
mSynchronizedCollections << retrieveJob->collection().id();
|
|
mPendingSynchronizeCollections.remove( retrieveJob->collection().id() );
|
|
|
|
itemsRetrievalDone();
|
|
}
|
|
|
|
void MixedMaildirResource::retrieveItemResult( KJob *job )
|
|
{
|
|
if ( job->error() != 0 ) {
|
|
kError() << job->errorString();
|
|
status( Broken, job->errorString() );
|
|
cancelTask( job->errorString() );
|
|
return;
|
|
}
|
|
|
|
FileStore::ItemFetchJob *fetchJob = qobject_cast<FileStore::ItemFetchJob*>( job );
|
|
Q_ASSERT( fetchJob != 0 );
|
|
Q_ASSERT( !fetchJob->items().isEmpty() );
|
|
|
|
itemRetrieved( fetchJob->items()[ 0 ] );
|
|
}
|
|
|
|
void MixedMaildirResource::itemAddedResult( KJob *job )
|
|
{
|
|
if ( job->error() != 0 ) {
|
|
kError() << job->errorString();
|
|
status( Broken, job->errorString() );
|
|
cancelTask( job->errorString() );
|
|
return;
|
|
}
|
|
|
|
FileStore::ItemCreateJob *itemJob = qobject_cast<FileStore::ItemCreateJob*>( job );
|
|
Q_ASSERT( itemJob != 0 );
|
|
|
|
/* kDebug() << "item.id=" << itemJob->item().id() << "remoteId=" << itemJob->item().remoteId();*/
|
|
changeCommitted( itemJob->item() );
|
|
|
|
checkForInvalidatedIndexCollections( job );
|
|
}
|
|
|
|
void MixedMaildirResource::itemChangedResult( KJob *job )
|
|
{
|
|
if ( job->error() != 0 ) {
|
|
kError() << job->errorString();
|
|
status( Broken, job->errorString() );
|
|
cancelTask( job->errorString() );
|
|
return;
|
|
}
|
|
|
|
FileStore::ItemModifyJob *itemJob = qobject_cast<FileStore::ItemModifyJob*>( job );
|
|
Q_ASSERT( itemJob != 0 );
|
|
|
|
changeCommitted( itemJob->item() );
|
|
|
|
const QString remoteId = itemJob->property( "originalRemoteId" ).value<QString>();
|
|
|
|
const QVariant compactStoreVar = itemJob->property( "compactStore" );
|
|
if ( compactStoreVar.isValid() && compactStoreVar.toBool() ) {
|
|
scheduleCustomTask( this, "compactStore", QVariant() );
|
|
}
|
|
|
|
checkForInvalidatedIndexCollections( job );
|
|
}
|
|
|
|
void MixedMaildirResource::itemMovedResult( KJob *job )
|
|
{
|
|
if ( job->error() != 0 ) {
|
|
kError() << job->errorString();
|
|
status( Broken, job->errorString() );
|
|
cancelTask( job->errorString() );
|
|
return;
|
|
}
|
|
|
|
FileStore::ItemMoveJob *itemJob = qobject_cast<FileStore::ItemMoveJob*>( job );
|
|
Q_ASSERT( itemJob != 0 );
|
|
|
|
changeCommitted( itemJob->item() );
|
|
|
|
const QString remoteId = itemJob->property( "originalRemoteId" ).value<QString>();
|
|
// kDebug() << "item.id=" << itemJob->item().id() << "remoteId=" << itemJob->item().remoteId()
|
|
// << "old remoteId=" << remoteId;
|
|
|
|
const QVariant compactStoreVar = itemJob->property( "compactStore" );
|
|
if ( compactStoreVar.isValid() && compactStoreVar.toBool() ) {
|
|
scheduleCustomTask( this, "compactStore", QVariant() );
|
|
}
|
|
|
|
checkForInvalidatedIndexCollections( job );
|
|
}
|
|
|
|
void MixedMaildirResource::itemRemovedResult( KJob *job )
|
|
{
|
|
if ( job->error() != 0 ) {
|
|
kError() << job->errorString();
|
|
status( Broken, job->errorString() );
|
|
cancelTask( job->errorString() );
|
|
return;
|
|
}
|
|
|
|
FileStore::ItemDeleteJob *itemJob = qobject_cast<FileStore::ItemDeleteJob*>( job );
|
|
Q_ASSERT( itemJob != 0 );
|
|
|
|
changeCommitted( itemJob->item() );
|
|
|
|
const QString remoteId = itemJob->item().remoteId();
|
|
|
|
const QVariant compactStoreVar = itemJob->property( "compactStore" );
|
|
if ( compactStoreVar.isValid() && compactStoreVar.toBool() ) {
|
|
scheduleCustomTask( this, "compactStore", QVariant() );
|
|
}
|
|
|
|
checkForInvalidatedIndexCollections( job );
|
|
}
|
|
|
|
void MixedMaildirResource::itemsDeleted( KJob *job )
|
|
{
|
|
Q_UNUSED( job );
|
|
scheduleCustomTask( this, "compactStore", QVariant() );
|
|
}
|
|
|
|
void MixedMaildirResource::collectionAddedResult( KJob *job )
|
|
{
|
|
if ( job->error() != 0 ) {
|
|
kError() << job->errorString();
|
|
status( Broken, job->errorString() );
|
|
cancelTask( job->errorString() );
|
|
return;
|
|
}
|
|
|
|
FileStore::CollectionCreateJob *colJob = qobject_cast<FileStore::CollectionCreateJob*>( job );
|
|
Q_ASSERT( colJob != 0 );
|
|
|
|
changeCommitted( colJob->collection() );
|
|
}
|
|
|
|
void MixedMaildirResource::collectionChangedResult( KJob *job )
|
|
{
|
|
if ( job->error() != 0 ) {
|
|
kError() << job->errorString();
|
|
status( Broken, job->errorString() );
|
|
cancelTask( job->errorString() );
|
|
return;
|
|
}
|
|
|
|
FileStore::CollectionModifyJob *colJob = qobject_cast<FileStore::CollectionModifyJob*>( job );
|
|
Q_ASSERT( colJob != 0 );
|
|
|
|
changeCommitted( colJob->collection() );
|
|
|
|
checkForInvalidatedIndexCollections( job );
|
|
}
|
|
|
|
void MixedMaildirResource::collectionMovedResult( KJob *job )
|
|
{
|
|
if ( job->error() != 0 ) {
|
|
kError() << job->errorString();
|
|
status( Broken, job->errorString() );
|
|
cancelTask( job->errorString() );
|
|
return;
|
|
}
|
|
|
|
FileStore::CollectionMoveJob *colJob = qobject_cast<FileStore::CollectionMoveJob*>( job );
|
|
Q_ASSERT( colJob != 0 );
|
|
|
|
changeCommitted( colJob->collection() );
|
|
|
|
checkForInvalidatedIndexCollections( job );
|
|
}
|
|
|
|
void MixedMaildirResource::collectionRemovedResult( KJob *job )
|
|
{
|
|
if ( job->error() != 0 ) {
|
|
kError() << job->errorString();
|
|
status( Broken, job->errorString() );
|
|
cancelTask( job->errorString() );
|
|
return;
|
|
}
|
|
|
|
FileStore::CollectionDeleteJob *colJob = qobject_cast<FileStore::CollectionDeleteJob*>( job );
|
|
Q_ASSERT( colJob != 0 );
|
|
|
|
changeCommitted( colJob->collection() );
|
|
}
|
|
|
|
void MixedMaildirResource::compactStore( const QVariant &arg )
|
|
{
|
|
Q_UNUSED( arg );
|
|
|
|
FileStore::StoreCompactJob *job = mStore->compactStore();
|
|
connect( job, SIGNAL(result(KJob*)), SLOT(compactStoreResult(KJob*)) );
|
|
}
|
|
|
|
void MixedMaildirResource::compactStoreResult( KJob *job )
|
|
{
|
|
if ( job->error() != 0 ) {
|
|
kError() << job->errorString();
|
|
status( Broken, job->errorString() );
|
|
cancelTask( job->errorString() );
|
|
return;
|
|
}
|
|
|
|
FileStore::StoreCompactJob *compactJob = qobject_cast<FileStore::StoreCompactJob*>( job );
|
|
Q_ASSERT( compactJob != 0 );
|
|
|
|
const Item::List items = compactJob->changedItems();
|
|
kDebug( KDE_DEFAULT_DEBUG_AREA ) << "Compacting store resulted in" << items.count() << "changed items";
|
|
|
|
mCompactHelper->addChangedItems( items );
|
|
|
|
taskDone();
|
|
|
|
checkForInvalidatedIndexCollections( job );
|
|
}
|
|
|
|
void MixedMaildirResource::restoreTags( const QVariant &arg )
|
|
{
|
|
if ( !arg.isValid() ) {
|
|
kError() << "Given variant is not valid";
|
|
cancelTask();
|
|
return;
|
|
}
|
|
|
|
const Collection collection = arg.value<Collection>();
|
|
if ( !collection.isValid() ) {
|
|
kError() << "Given variant is not valid";
|
|
cancelTask();
|
|
return;
|
|
}
|
|
|
|
const TagContextList taggedItems = mTagContextByColId[ collection.id() ];
|
|
mPendingTagContexts << taggedItems;
|
|
|
|
QMetaObject::invokeMethod( this, "processNextTagContext", Qt::QueuedConnection );
|
|
taskDone();
|
|
}
|
|
|
|
void MixedMaildirResource::processNextTagContext()
|
|
{
|
|
kDebug() << mPendingTagContexts.count() << "items to go";
|
|
if ( mPendingTagContexts.isEmpty() ) {
|
|
return;
|
|
}
|
|
|
|
const TagContext tagContext = mPendingTagContexts.front();
|
|
mPendingTagContexts.pop_front();
|
|
|
|
ItemFetchJob *fetchJob = new ItemFetchJob( tagContext.mItem );
|
|
fetchJob->setProperty( "tagList", tagContext.mTagList );
|
|
connect( fetchJob, SIGNAL(result(KJob*)), SLOT(tagFetchJobResult(KJob*)) );
|
|
}
|
|
|
|
void MixedMaildirResource::tagFetchJobResult( KJob *job )
|
|
{
|
|
if ( job->error() != 0 ) {
|
|
kError() << job->errorString();
|
|
processNextTagContext();
|
|
return;
|
|
}
|
|
|
|
ItemFetchJob *fetchJob = qobject_cast<ItemFetchJob*>( job );
|
|
Q_ASSERT( fetchJob != 0 );
|
|
|
|
Q_ASSERT( !fetchJob->items().isEmpty() );
|
|
|
|
const Item item = fetchJob->items()[ 0 ];
|
|
const QStringList tagList = job->property( "tagList" ).value<QStringList>();
|
|
kDebug() << "Tagging item" << item.url() << "with" << tagList;
|
|
|
|
Akonadi::Tag::List tags;
|
|
Q_FOREACH( const QString &tag, tagList ) {
|
|
if ( tag.isEmpty() ) {
|
|
kWarning() << "TagList for item" << item.url() << "contains an empty tag";
|
|
} else {
|
|
tags << Akonadi::Tag(tag);
|
|
}
|
|
}
|
|
new CreateAndSetTagsJob(item, tags);
|
|
|
|
processNextTagContext();
|
|
}
|
|
|
|
|
|
AKONADI_RESOURCE_MAIN( MixedMaildirResource )
|
|
|
|
// kate: space-indent on; indent-width 2; replace-tabs on;
|