File indexing completed on 2024-11-24 04:44:34

0001 /*  This file is part of the KDE project
0002     SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.net>
0003     SPDX-FileContributor: Kevin Krammer <krake@kdab.com>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "abstractlocalstore.h"
0009 
0010 #include "akonadifilestore_debug.h"
0011 #include "collectioncreatejob.h"
0012 #include "collectiondeletejob.h"
0013 #include "collectionfetchjob.h"
0014 #include "collectionmodifyjob.h"
0015 #include "collectionmovejob.h"
0016 #include "itemcreatejob.h"
0017 #include "itemdeletejob.h"
0018 #include "itemfetchjob.h"
0019 #include "itemmodifyjob.h"
0020 #include "itemmovejob.h"
0021 #include "sessionimpls_p.h"
0022 #include "storecompactjob.h"
0023 
0024 #include <Akonadi/EntityDisplayAttribute>
0025 
0026 #include <KLocalizedString>
0027 #include <QFileInfo>
0028 
0029 using namespace Akonadi;
0030 
0031 class JobProcessingAdaptor : public FileStore::Job::Visitor
0032 {
0033 public:
0034     explicit JobProcessingAdaptor(FileStore::AbstractJobSession *session)
0035         : mSession(session)
0036     {
0037     }
0038 
0039 public: // Job::Visitor interface implementation
0040     bool visit(FileStore::Job *job) override
0041     {
0042         Q_UNUSED(job)
0043         return false;
0044     }
0045 
0046     bool visit(FileStore::CollectionCreateJob *job) override
0047     {
0048         Q_UNUSED(job)
0049         return false;
0050     }
0051 
0052     bool visit(FileStore::CollectionDeleteJob *job) override
0053     {
0054         Q_UNUSED(job)
0055         return false;
0056     }
0057 
0058     bool visit(FileStore::CollectionFetchJob *job) override
0059     {
0060         Q_UNUSED(job)
0061         return false;
0062     }
0063 
0064     bool visit(FileStore::CollectionModifyJob *job) override
0065     {
0066         Q_UNUSED(job)
0067         return false;
0068     }
0069 
0070     bool visit(FileStore::CollectionMoveJob *job) override
0071     {
0072         Q_UNUSED(job)
0073         return false;
0074     }
0075 
0076     bool visit(FileStore::ItemCreateJob *job) override
0077     {
0078         Q_UNUSED(job)
0079         return false;
0080     }
0081 
0082     bool visit(FileStore::ItemDeleteJob *job) override
0083     {
0084         Q_UNUSED(job)
0085         return false;
0086     }
0087 
0088     bool visit(FileStore::ItemFetchJob *job) override
0089     {
0090         Q_UNUSED(job)
0091         return false;
0092     }
0093 
0094     bool visit(FileStore::ItemModifyJob *job) override
0095     {
0096         Q_UNUSED(job)
0097         return false;
0098     }
0099 
0100     bool visit(FileStore::ItemMoveJob *job) override
0101     {
0102         Q_UNUSED(job)
0103         return false;
0104     }
0105 
0106     bool visit(FileStore::StoreCompactJob *job) override
0107     {
0108         Q_UNUSED(job)
0109         return false;
0110     }
0111 
0112 protected:
0113     FileStore::AbstractJobSession *mSession = nullptr;
0114 };
0115 
0116 class TopLevelCollectionFetcher : public JobProcessingAdaptor
0117 {
0118 public:
0119     explicit TopLevelCollectionFetcher(FileStore::AbstractJobSession *session)
0120         : JobProcessingAdaptor(session)
0121     {
0122     }
0123 
0124     void setTopLevelCollection(const Collection &collection)
0125     {
0126         mTopLevelCollection = collection;
0127     }
0128 
0129 public:
0130     using JobProcessingAdaptor::visit;
0131 
0132     bool visit(FileStore::CollectionFetchJob *job) override
0133     {
0134         if (job->type() == FileStore::CollectionFetchJob::Base && job->collection().remoteId() == mTopLevelCollection.remoteId()) {
0135             mSession->notifyCollectionsReceived(job, Collection::List() << mTopLevelCollection);
0136             return true;
0137         }
0138 
0139         return false;
0140     }
0141 
0142 private:
0143     Collection mTopLevelCollection;
0144 };
0145 
0146 class CollectionsProcessedNotifier : public JobProcessingAdaptor
0147 {
0148 public:
0149     explicit CollectionsProcessedNotifier(FileStore::AbstractJobSession *session)
0150         : JobProcessingAdaptor(session)
0151     {
0152     }
0153 
0154     void setCollections(const Collection::List &collections)
0155     {
0156         mCollections = collections;
0157     }
0158 
0159 public:
0160     using JobProcessingAdaptor::visit;
0161 
0162     bool visit(FileStore::CollectionCreateJob *job) override
0163     {
0164         Q_ASSERT(!mCollections.isEmpty());
0165         if (mCollections.count() > 1) {
0166             qCCritical(AKONADIFILESTORE_LOG) << "Processing collections for CollectionCreateJob "
0167                                                 "encountered more than one collection. Just processing the first one.";
0168         }
0169 
0170         mSession->notifyCollectionCreated(job, mCollections[0]);
0171         return true;
0172     }
0173 
0174     bool visit(FileStore::CollectionDeleteJob *job) override
0175     {
0176         Q_ASSERT(!mCollections.isEmpty());
0177         if (mCollections.count() > 1) {
0178             qCCritical(AKONADIFILESTORE_LOG) << "Processing collections for CollectionDeleteJob "
0179                                                 "encountered more than one collection. Just processing the first one.";
0180         }
0181 
0182         mSession->notifyCollectionDeleted(job, mCollections[0]);
0183         return true;
0184     }
0185 
0186     bool visit(FileStore::CollectionFetchJob *job) override
0187     {
0188         mSession->notifyCollectionsReceived(job, mCollections);
0189         return true;
0190     }
0191 
0192     bool visit(FileStore::CollectionModifyJob *job) override
0193     {
0194         Q_ASSERT(!mCollections.isEmpty());
0195         if (mCollections.count() > 1) {
0196             qCCritical(AKONADIFILESTORE_LOG) << "Processing collections for CollectionModifyJob "
0197                                                 "encountered more than one collection. Just processing the first one.";
0198         }
0199 
0200         mSession->notifyCollectionModified(job, mCollections[0]);
0201         return true;
0202     }
0203 
0204     bool visit(FileStore::CollectionMoveJob *job) override
0205     {
0206         Q_ASSERT(!mCollections.isEmpty());
0207         if (mCollections.count() > 1) {
0208             qCCritical(AKONADIFILESTORE_LOG) << "Processing collections for CollectionMoveJob "
0209                                                 "encountered more than one collection. Just processing the first one.";
0210         }
0211 
0212         mSession->notifyCollectionMoved(job, mCollections[0]);
0213         return true;
0214     }
0215 
0216     bool visit(FileStore::StoreCompactJob *job) override
0217     {
0218         mSession->notifyCollectionsChanged(job, mCollections);
0219         return true;
0220     }
0221 
0222 private:
0223     Collection::List mCollections;
0224 };
0225 
0226 class ItemsProcessedNotifier : public JobProcessingAdaptor
0227 {
0228 public:
0229     explicit ItemsProcessedNotifier(FileStore::AbstractJobSession *session)
0230         : JobProcessingAdaptor(session)
0231     {
0232     }
0233 
0234     void setItems(const Item::List &items)
0235     {
0236         mItems = items;
0237     }
0238 
0239     void clearItems()
0240     {
0241         mItems.clear();
0242     }
0243 
0244 public:
0245     using JobProcessingAdaptor::visit;
0246 
0247     bool visit(FileStore::ItemCreateJob *job) override
0248     {
0249         Q_ASSERT(!mItems.isEmpty());
0250         if (mItems.count() > 1) {
0251             qCCritical(AKONADIFILESTORE_LOG) << "Processing items for ItemCreateJob encountered more than one item. "
0252                                                 "Just processing the first one.";
0253         }
0254 
0255         mSession->notifyItemCreated(job, mItems[0]);
0256         return true;
0257     }
0258 
0259     bool visit(FileStore::ItemFetchJob *job) override
0260     {
0261         mSession->notifyItemsReceived(job, mItems);
0262         return true;
0263     }
0264 
0265     bool visit(FileStore::ItemModifyJob *job) override
0266     {
0267         Q_ASSERT(!mItems.isEmpty());
0268         if (mItems.count() > 1) {
0269             qCCritical(AKONADIFILESTORE_LOG) << "Processing items for ItemModifyJob encountered more than one item. "
0270                                                 "Just processing the first one.";
0271         }
0272 
0273         mSession->notifyItemModified(job, mItems[0]);
0274         return true;
0275     }
0276 
0277     bool visit(FileStore::ItemMoveJob *job) override
0278     {
0279         Q_ASSERT(!mItems.isEmpty());
0280         if (mItems.count() > 1) {
0281             qCCritical(AKONADIFILESTORE_LOG) << "Processing items for ItemMoveJob encountered more than one item. "
0282                                                 "Just processing the first one.";
0283         }
0284 
0285         mSession->notifyItemMoved(job, mItems[0]);
0286         return true;
0287     }
0288 
0289     bool visit(FileStore::StoreCompactJob *job) override
0290     {
0291         mSession->notifyItemsChanged(job, mItems);
0292         return true;
0293     }
0294 
0295 private:
0296     Item::List mItems;
0297 };
0298 
0299 class FileStore::AbstractLocalStorePrivate
0300 {
0301     AbstractLocalStore *const q;
0302 
0303 public:
0304     explicit AbstractLocalStorePrivate(FileStore::AbstractLocalStore *parent)
0305         : q(parent)
0306         , mSession(new FileStore::FiFoQueueJobSession(q))
0307         , mCurrentJob(nullptr)
0308         , mTopLevelCollectionFetcher(mSession)
0309         , mCollectionsProcessedNotifier(mSession)
0310         , mItemsProcessedNotifier(mSession)
0311     {
0312     }
0313 
0314 public:
0315     QFileInfo mPathFileInfo;
0316     Collection mTopLevelCollection;
0317 
0318     FileStore::AbstractJobSession *mSession = nullptr;
0319     FileStore::Job *mCurrentJob = nullptr;
0320 
0321     TopLevelCollectionFetcher mTopLevelCollectionFetcher;
0322     CollectionsProcessedNotifier mCollectionsProcessedNotifier;
0323     ItemsProcessedNotifier mItemsProcessedNotifier;
0324 
0325 public:
0326     void processJobs(const QList<FileStore::Job *> &jobs);
0327 };
0328 
0329 void FileStore::AbstractLocalStorePrivate::processJobs(const QList<FileStore::Job *> &jobs)
0330 {
0331     for (FileStore::Job *job : jobs) {
0332         mCurrentJob = job;
0333 
0334         if (job->error() == 0) {
0335             if (!job->accept(&mTopLevelCollectionFetcher)) {
0336                 q->processJob(job);
0337             }
0338         }
0339         mSession->emitResult(job);
0340         mCurrentJob = nullptr;
0341     }
0342 }
0343 
0344 FileStore::AbstractLocalStore::AbstractLocalStore()
0345     : QObject()
0346     , d(new AbstractLocalStorePrivate(this))
0347 {
0348     connect(d->mSession, &AbstractJobSession::jobsReady, this, [this](const QList<FileStore::Job *> &jobs) {
0349         d->processJobs(jobs);
0350     });
0351 }
0352 
0353 FileStore::AbstractLocalStore::~AbstractLocalStore() = default;
0354 
0355 void FileStore::AbstractLocalStore::setPath(const QString &path)
0356 {
0357     QFileInfo pathFileInfo(path);
0358     if (pathFileInfo.fileName().isEmpty()) {
0359         pathFileInfo = QFileInfo(pathFileInfo.path());
0360     }
0361     pathFileInfo.makeAbsolute();
0362 
0363     if (pathFileInfo.absoluteFilePath() == d->mPathFileInfo.absoluteFilePath()) {
0364         return;
0365     }
0366 
0367     d->mPathFileInfo = pathFileInfo;
0368 
0369     Collection collection;
0370     collection.setRemoteId(d->mPathFileInfo.absoluteFilePath());
0371     collection.setName(d->mPathFileInfo.fileName());
0372 
0373     auto attribute = collection.attribute<EntityDisplayAttribute>();
0374     if (attribute) {
0375         attribute->setDisplayName(d->mPathFileInfo.fileName());
0376     }
0377 
0378     setTopLevelCollection(collection);
0379 }
0380 
0381 QString FileStore::AbstractLocalStore::path() const
0382 {
0383     return d->mPathFileInfo.absoluteFilePath();
0384 }
0385 
0386 Collection FileStore::AbstractLocalStore::topLevelCollection() const
0387 {
0388     return d->mTopLevelCollection;
0389 }
0390 
0391 FileStore::CollectionCreateJob *FileStore::AbstractLocalStore::createCollection(const Collection &collection, const Collection &targetParent)
0392 {
0393     auto job = new FileStore::CollectionCreateJob(collection, targetParent, d->mSession);
0394 
0395     if (d->mTopLevelCollection.remoteId().isEmpty()) {
0396         const QString message = i18nc("@info:status", "Configured storage location is empty");
0397         qCCritical(AKONADIFILESTORE_LOG) << message;
0398         qCCritical(AKONADIFILESTORE_LOG) << collection << targetParent;
0399         d->mSession->setError(job, FileStore::Job::InvalidStoreState, message);
0400     } else if (targetParent.remoteId().isEmpty()) {
0401         const QString message = i18nc("@info:status", "Given folder name is empty");
0402         qCCritical(AKONADIFILESTORE_LOG) << message;
0403         qCCritical(AKONADIFILESTORE_LOG) << collection << targetParent;
0404         d->mSession->setError(job, FileStore::Job::InvalidJobContext, message);
0405     } else if ((targetParent.rights() & Collection::CanCreateCollection) == 0) {
0406         const QString message = i18nc("@info:status", "Access control prohibits folder creation in folder %1", targetParent.name());
0407         qCCritical(AKONADIFILESTORE_LOG) << message;
0408         qCCritical(AKONADIFILESTORE_LOG) << collection << targetParent;
0409         d->mSession->setError(job, FileStore::Job::InvalidJobContext, message);
0410     }
0411 
0412     int errorCode = 0;
0413     QString errorText;
0414     checkCollectionCreate(job, errorCode, errorText);
0415     if (errorCode != 0) {
0416         d->mSession->setError(job, errorCode, errorText);
0417     }
0418 
0419     return job;
0420 }
0421 
0422 FileStore::CollectionDeleteJob *FileStore::AbstractLocalStore::deleteCollection(const Collection &collection)
0423 {
0424     auto job = new FileStore::CollectionDeleteJob(collection, d->mSession);
0425 
0426     if (d->mTopLevelCollection.remoteId().isEmpty()) {
0427         const QString message = i18nc("@info:status", "Configured storage location is empty");
0428         qCCritical(AKONADIFILESTORE_LOG) << message;
0429         qCCritical(AKONADIFILESTORE_LOG) << collection;
0430         d->mSession->setError(job, FileStore::Job::InvalidStoreState, message);
0431     } else if (collection.remoteId().isEmpty() || collection.parentCollection().remoteId().isEmpty()) {
0432         const QString message = i18nc("@info:status", "Given folder name is empty");
0433         qCCritical(AKONADIFILESTORE_LOG) << message;
0434         qCCritical(AKONADIFILESTORE_LOG) << collection;
0435         d->mSession->setError(job, FileStore::Job::InvalidJobContext, message);
0436     } else if ((collection.rights() & Collection::CanDeleteCollection) == 0) {
0437         const QString message = i18nc("@info:status", "Access control prohibits folder deletion in folder %1", collection.name());
0438         qCCritical(AKONADIFILESTORE_LOG) << message;
0439         qCCritical(AKONADIFILESTORE_LOG) << collection;
0440         d->mSession->setError(job, FileStore::Job::InvalidJobContext, message);
0441     }
0442 
0443     int errorCode = 0;
0444     QString errorText;
0445     checkCollectionDelete(job, errorCode, errorText);
0446     if (errorCode != 0) {
0447         d->mSession->setError(job, errorCode, errorText);
0448     }
0449 
0450     return job;
0451 }
0452 
0453 FileStore::CollectionFetchJob *FileStore::AbstractLocalStore::fetchCollections(const Collection &collection, FileStore::CollectionFetchJob::Type type) const
0454 {
0455     auto job = new FileStore::CollectionFetchJob(collection, type, d->mSession);
0456 
0457     if (d->mTopLevelCollection.remoteId().isEmpty()) {
0458         const QString message = i18nc("@info:status", "Configured storage location is empty");
0459         qCCritical(AKONADIFILESTORE_LOG) << message;
0460         qCCritical(AKONADIFILESTORE_LOG) << collection << "FetchType=" << type;
0461         d->mSession->setError(job, FileStore::Job::InvalidStoreState, message);
0462     } else if (collection.remoteId().isEmpty()) {
0463         const QString message = i18nc("@info:status", "Given folder name is empty");
0464         qCCritical(AKONADIFILESTORE_LOG) << message;
0465         qCCritical(AKONADIFILESTORE_LOG) << collection << "FetchType=" << type;
0466         d->mSession->setError(job, FileStore::Job::InvalidJobContext, message);
0467     }
0468 
0469     int errorCode = 0;
0470     QString errorText;
0471     checkCollectionFetch(job, errorCode, errorText);
0472     if (errorCode != 0) {
0473         d->mSession->setError(job, errorCode, errorText);
0474     }
0475 
0476     return job;
0477 }
0478 
0479 FileStore::CollectionModifyJob *FileStore::AbstractLocalStore::modifyCollection(const Collection &collection)
0480 {
0481     auto job = new FileStore::CollectionModifyJob(collection, d->mSession);
0482 
0483     if (d->mTopLevelCollection.remoteId().isEmpty()) {
0484         const QString message = i18nc("@info:status", "Configured storage location is empty");
0485         qCCritical(AKONADIFILESTORE_LOG) << message;
0486         qCCritical(AKONADIFILESTORE_LOG) << collection;
0487         d->mSession->setError(job, FileStore::Job::InvalidStoreState, message);
0488     } else if (collection.remoteId().isEmpty()) {
0489         const QString message = i18nc("@info:status", "Given folder name is empty");
0490         qCCritical(AKONADIFILESTORE_LOG) << message;
0491         qCCritical(AKONADIFILESTORE_LOG) << collection;
0492         d->mSession->setError(job, FileStore::Job::InvalidJobContext, message);
0493     } else if ((collection.rights() & Collection::CanChangeCollection) == 0) {
0494         const QString message = i18nc("@info:status", "Access control prohibits folder modification in folder %1", collection.name());
0495         qCCritical(AKONADIFILESTORE_LOG) << message;
0496         qCCritical(AKONADIFILESTORE_LOG) << collection;
0497         d->mSession->setError(job, FileStore::Job::InvalidJobContext, message);
0498     }
0499 
0500     int errorCode = 0;
0501     QString errorText;
0502     checkCollectionModify(job, errorCode, errorText);
0503     if (errorCode != 0) {
0504         d->mSession->setError(job, errorCode, errorText);
0505     }
0506 
0507     return job;
0508 }
0509 
0510 FileStore::CollectionMoveJob *FileStore::AbstractLocalStore::moveCollection(const Collection &collection, const Collection &targetParent)
0511 {
0512     auto job = new FileStore::CollectionMoveJob(collection, targetParent, d->mSession);
0513 
0514     if (d->mTopLevelCollection.remoteId().isEmpty()) {
0515         const QString message = i18nc("@info:status", "Configured storage location is empty");
0516         qCCritical(AKONADIFILESTORE_LOG) << message;
0517         qCCritical(AKONADIFILESTORE_LOG) << collection << targetParent;
0518         d->mSession->setError(job, FileStore::Job::InvalidStoreState, message);
0519     } else if (collection.remoteId().isEmpty() || collection.parentCollection().remoteId().isEmpty() || targetParent.remoteId().isEmpty()) {
0520         const QString message = i18nc("@info:status", "Given folder name is empty");
0521         qCCritical(AKONADIFILESTORE_LOG) << message;
0522         qCCritical(AKONADIFILESTORE_LOG) << collection << targetParent;
0523         d->mSession->setError(job, FileStore::Job::InvalidJobContext, message);
0524     } else if ((targetParent.rights() & Collection::CanCreateCollection) == 0) {
0525         const QString message = i18nc("@info:status", "Access control prohibits folder creation in folder %1", targetParent.name());
0526         qCCritical(AKONADIFILESTORE_LOG) << message;
0527         qCCritical(AKONADIFILESTORE_LOG) << collection << targetParent;
0528         d->mSession->setError(job, FileStore::Job::InvalidJobContext, message);
0529     }
0530 
0531     int errorCode = 0;
0532     QString errorText;
0533     checkCollectionMove(job, errorCode, errorText);
0534     if (errorCode != 0) {
0535         d->mSession->setError(job, errorCode, errorText);
0536     }
0537 
0538     return job;
0539 }
0540 
0541 FileStore::ItemFetchJob *FileStore::AbstractLocalStore::fetchItems(const Collection &collection) const
0542 {
0543     auto job = new FileStore::ItemFetchJob(collection, d->mSession);
0544 
0545     if (d->mTopLevelCollection.remoteId().isEmpty()) {
0546         const QString message = i18nc("@info:status", "Configured storage location is empty");
0547         qCCritical(AKONADIFILESTORE_LOG) << message;
0548         qCCritical(AKONADIFILESTORE_LOG) << collection;
0549         d->mSession->setError(job, FileStore::Job::InvalidStoreState, message);
0550     } else if (collection.remoteId().isEmpty()) {
0551         const QString message = i18nc("@info:status", "Given folder name is empty");
0552         qCCritical(AKONADIFILESTORE_LOG) << message;
0553         qCCritical(AKONADIFILESTORE_LOG) << collection;
0554         d->mSession->setError(job, FileStore::Job::InvalidJobContext, message);
0555     }
0556 
0557     int errorCode = 0;
0558     QString errorText;
0559     checkItemFetch(job, errorCode, errorText);
0560     if (errorCode != 0) {
0561         d->mSession->setError(job, errorCode, errorText);
0562     }
0563 
0564     return job;
0565 }
0566 
0567 FileStore::ItemFetchJob *FileStore::AbstractLocalStore::fetchItems(const Item::List &items) const
0568 {
0569     auto job = new FileStore::ItemFetchJob(items, d->mSession);
0570 
0571     if (items.size() == 1) {
0572         const Akonadi::Item &item = items[0];
0573         if (d->mTopLevelCollection.remoteId().isEmpty()) {
0574             const QString message = i18nc("@info:status", "Configured storage location is empty");
0575             qCCritical(AKONADIFILESTORE_LOG) << message;
0576             qCCritical(AKONADIFILESTORE_LOG) << "Item(remoteId=" << item.remoteId() << ", mimeType=" << item.mimeType()
0577                                              << ", parentCollection=" << item.parentCollection().remoteId() << ")";
0578             d->mSession->setError(job, FileStore::Job::InvalidStoreState, message);
0579         } else if (item.remoteId().isEmpty()) {
0580             const QString message = i18nc("@info:status", "Given item identifier is empty");
0581             qCCritical(AKONADIFILESTORE_LOG) << message;
0582             qCCritical(AKONADIFILESTORE_LOG) << "Item(remoteId=" << item.remoteId() << ", mimeType=" << item.mimeType()
0583                                              << ", parentCollection=" << item.parentCollection().remoteId() << ")";
0584             d->mSession->setError(job, FileStore::Job::InvalidJobContext, message);
0585         }
0586     }
0587 
0588     int errorCode = 0;
0589     QString errorText;
0590     checkItemFetch(job, errorCode, errorText);
0591     if (errorCode != 0) {
0592         d->mSession->setError(job, errorCode, errorText);
0593     }
0594 
0595     return job;
0596 }
0597 
0598 FileStore::ItemFetchJob *FileStore::AbstractLocalStore::fetchItem(const Item &item) const
0599 {
0600     return fetchItems({item});
0601 }
0602 
0603 FileStore::ItemCreateJob *FileStore::AbstractLocalStore::createItem(const Item &item, const Collection &collection)
0604 {
0605     auto job = new FileStore::ItemCreateJob(item, collection, d->mSession);
0606 
0607     if (d->mTopLevelCollection.remoteId().isEmpty()) {
0608         const QString message = i18nc("@info:status", "Configured storage location is empty");
0609         qCCritical(AKONADIFILESTORE_LOG) << message;
0610         qCCritical(AKONADIFILESTORE_LOG) << collection << "Item(remoteId=" << item.remoteId() << ", mimeType=" << item.mimeType() << ")";
0611         d->mSession->setError(job, FileStore::Job::InvalidStoreState, message);
0612     } else if (collection.remoteId().isEmpty()) {
0613         const QString message = i18nc("@info:status", "Given folder name is empty");
0614         qCCritical(AKONADIFILESTORE_LOG) << message;
0615         qCCritical(AKONADIFILESTORE_LOG) << collection << "Item(remoteId=" << item.remoteId() << ", mimeType=" << item.mimeType() << ")";
0616         d->mSession->setError(job, FileStore::Job::InvalidJobContext, message);
0617     } else if ((collection.rights() & Collection::CanCreateItem) == 0) {
0618         const QString message = i18nc("@info:status", "Access control prohibits item creation in folder %1", collection.name());
0619         qCCritical(AKONADIFILESTORE_LOG) << message;
0620         qCCritical(AKONADIFILESTORE_LOG) << collection << "Item(remoteId=" << item.remoteId() << ", mimeType=" << item.mimeType() << ")";
0621         d->mSession->setError(job, FileStore::Job::InvalidJobContext, message);
0622     }
0623 
0624     int errorCode = 0;
0625     QString errorText;
0626     checkItemCreate(job, errorCode, errorText);
0627     if (errorCode != 0) {
0628         d->mSession->setError(job, errorCode, errorText);
0629     }
0630 
0631     return job;
0632 }
0633 
0634 FileStore::ItemModifyJob *FileStore::AbstractLocalStore::modifyItem(const Item &item)
0635 {
0636     auto job = new FileStore::ItemModifyJob(item, d->mSession);
0637 
0638     if (d->mTopLevelCollection.remoteId().isEmpty()) {
0639         const QString message = i18nc("@info:status", "Configured storage location is empty");
0640         qCCritical(AKONADIFILESTORE_LOG) << message;
0641         qCCritical(AKONADIFILESTORE_LOG) << "Item(remoteId=" << item.remoteId() << ", mimeType=" << item.mimeType()
0642                                          << ", parentCollection=" << item.parentCollection().remoteId() << ")";
0643         d->mSession->setError(job, FileStore::Job::InvalidStoreState, message);
0644     } else if (item.remoteId().isEmpty()) {
0645         const QString message = i18nc("@info:status", "Given item identifier is empty");
0646         qCCritical(AKONADIFILESTORE_LOG) << message;
0647         qCCritical(AKONADIFILESTORE_LOG) << "Item(remoteId=" << item.remoteId() << ", mimeType=" << item.mimeType()
0648                                          << ", parentCollection=" << item.parentCollection().remoteId() << ")";
0649         d->mSession->setError(job, FileStore::Job::InvalidJobContext, message);
0650     } else if ((item.parentCollection().rights() & Collection::CanChangeItem) == 0) {
0651         const QString message = i18nc("@info:status", "Access control prohibits item modification in folder %1", item.parentCollection().name());
0652         qCCritical(AKONADIFILESTORE_LOG) << message;
0653         qCCritical(AKONADIFILESTORE_LOG) << "Item(remoteId=" << item.remoteId() << ", mimeType=" << item.mimeType()
0654                                          << ", parentCollection=" << item.parentCollection().remoteId() << ")";
0655         d->mSession->setError(job, FileStore::Job::InvalidJobContext, message);
0656     }
0657 
0658     int errorCode = 0;
0659     QString errorText;
0660     checkItemModify(job, errorCode, errorText);
0661     if (errorCode != 0) {
0662         d->mSession->setError(job, errorCode, errorText);
0663     }
0664 
0665     return job;
0666 }
0667 
0668 FileStore::ItemDeleteJob *FileStore::AbstractLocalStore::deleteItem(const Item &item)
0669 {
0670     auto job = new FileStore::ItemDeleteJob(item, d->mSession);
0671 
0672     if (d->mTopLevelCollection.remoteId().isEmpty()) {
0673         const QString message = i18nc("@info:status", "Configured storage location is empty");
0674         qCCritical(AKONADIFILESTORE_LOG) << message;
0675         qCCritical(AKONADIFILESTORE_LOG) << "Item(remoteId=" << item.remoteId() << ", mimeType=" << item.mimeType()
0676                                          << ", parentCollection=" << item.parentCollection().remoteId() << ")";
0677         d->mSession->setError(job, FileStore::Job::InvalidStoreState, message);
0678     } else if (item.remoteId().isEmpty()) {
0679         const QString message = i18nc("@info:status", "Given item identifier is empty");
0680         qCCritical(AKONADIFILESTORE_LOG) << message;
0681         qCCritical(AKONADIFILESTORE_LOG) << "Item(remoteId=" << item.remoteId() << ", mimeType=" << item.mimeType()
0682                                          << ", parentCollection=" << item.parentCollection().remoteId() << ")";
0683         d->mSession->setError(job, FileStore::Job::InvalidJobContext, message);
0684     } else if ((item.parentCollection().rights() & Collection::CanDeleteItem) == 0) {
0685         const QString message = i18nc("@info:status", "Access control prohibits item deletion in folder %1", item.parentCollection().name());
0686         qCCritical(AKONADIFILESTORE_LOG) << message;
0687         qCCritical(AKONADIFILESTORE_LOG) << "Item(remoteId=" << item.remoteId() << ", mimeType=" << item.mimeType()
0688                                          << ", parentCollection=" << item.parentCollection().remoteId() << ")";
0689         d->mSession->setError(job, FileStore::Job::InvalidJobContext, message);
0690     }
0691 
0692     int errorCode = 0;
0693     QString errorText;
0694     checkItemDelete(job, errorCode, errorText);
0695     if (errorCode != 0) {
0696         d->mSession->setError(job, errorCode, errorText);
0697     }
0698 
0699     return job;
0700 }
0701 
0702 FileStore::ItemMoveJob *FileStore::AbstractLocalStore::moveItem(const Item &item, const Collection &targetParent)
0703 {
0704     auto job = new FileStore::ItemMoveJob(item, targetParent, d->mSession);
0705 
0706     if (d->mTopLevelCollection.remoteId().isEmpty()) {
0707         const QString message = i18nc("@info:status", "Configured storage location is empty");
0708         qCCritical(AKONADIFILESTORE_LOG) << message;
0709         qCCritical(AKONADIFILESTORE_LOG) << "Item(remoteId=" << item.remoteId() << ", mimeType=" << item.mimeType()
0710                                          << ", parentCollection=" << item.parentCollection().remoteId() << ")" << targetParent;
0711         d->mSession->setError(job, FileStore::Job::InvalidStoreState, message);
0712     } else if (item.parentCollection().remoteId().isEmpty() || targetParent.remoteId().isEmpty()) {
0713         const QString message = i18nc("@info:status", "Given folder name is empty");
0714         qCCritical(AKONADIFILESTORE_LOG) << message;
0715         qCCritical(AKONADIFILESTORE_LOG) << "Item(remoteId=" << item.remoteId() << ", mimeType=" << item.mimeType()
0716                                          << ", parentCollection=" << item.parentCollection().remoteId() << ")" << targetParent;
0717         d->mSession->setError(job, FileStore::Job::InvalidJobContext, message);
0718     } else if ((targetParent.rights() & Collection::CanCreateItem) == 0) {
0719         const QString message = i18nc("@info:status", "Access control prohibits item creation in folder %1", targetParent.name());
0720         qCCritical(AKONADIFILESTORE_LOG) << message;
0721         qCCritical(AKONADIFILESTORE_LOG) << "Item(remoteId=" << item.remoteId() << ", mimeType=" << item.mimeType()
0722                                          << ", parentCollection=" << item.parentCollection().remoteId() << ")" << targetParent;
0723         d->mSession->setError(job, FileStore::Job::InvalidJobContext, message);
0724     } else if ((item.parentCollection().rights() & Collection::CanDeleteItem) == 0) {
0725         const QString message = i18nc("@info:status", "Access control prohibits item deletion in folder %1", item.parentCollection().name());
0726         qCCritical(AKONADIFILESTORE_LOG) << message;
0727         qCCritical(AKONADIFILESTORE_LOG) << "Item(remoteId=" << item.remoteId() << ", mimeType=" << item.mimeType()
0728                                          << ", parentCollection=" << item.parentCollection().remoteId() << ")" << targetParent;
0729         d->mSession->setError(job, FileStore::Job::InvalidJobContext, message);
0730     } else if (item.remoteId().isEmpty()) {
0731         const QString message = i18nc("@info:status", "Given item identifier is empty");
0732         qCCritical(AKONADIFILESTORE_LOG) << message;
0733         qCCritical(AKONADIFILESTORE_LOG) << "Item(remoteId=" << item.remoteId() << ", mimeType=" << item.mimeType()
0734                                          << ", parentCollection=" << item.parentCollection().remoteId() << ")" << targetParent;
0735         d->mSession->setError(job, FileStore::Job::InvalidJobContext, message);
0736     }
0737 
0738     int errorCode = 0;
0739     QString errorText;
0740     checkItemMove(job, errorCode, errorText);
0741     if (errorCode != 0) {
0742         d->mSession->setError(job, errorCode, errorText);
0743     }
0744 
0745     return job;
0746 }
0747 
0748 FileStore::StoreCompactJob *FileStore::AbstractLocalStore::compactStore()
0749 {
0750     auto job = new FileStore::StoreCompactJob(d->mSession);
0751 
0752     if (d->mTopLevelCollection.remoteId().isEmpty()) {
0753         const QString message = i18nc("@info:status", "Configured storage location is empty");
0754         qCCritical(AKONADIFILESTORE_LOG) << message;
0755         d->mSession->setError(job, FileStore::Job::InvalidStoreState, message);
0756     }
0757 
0758     int errorCode = 0;
0759     QString errorText;
0760     checkStoreCompact(job, errorCode, errorText);
0761     if (errorCode != 0) {
0762         d->mSession->setError(job, errorCode, errorText);
0763     }
0764 
0765     return job;
0766 }
0767 
0768 FileStore::Job *FileStore::AbstractLocalStore::currentJob() const
0769 {
0770     return d->mCurrentJob;
0771 }
0772 
0773 void FileStore::AbstractLocalStore::notifyError(int errorCode, const QString &errorText) const
0774 {
0775     Q_ASSERT(d->mCurrentJob != nullptr);
0776 
0777     d->mSession->setError(d->mCurrentJob, errorCode, errorText);
0778 }
0779 
0780 void FileStore::AbstractLocalStore::notifyCollectionsProcessed(const Collection::List &collections) const
0781 {
0782     Q_ASSERT(d->mCurrentJob != nullptr);
0783 
0784     d->mCollectionsProcessedNotifier.setCollections(collections);
0785     d->mCurrentJob->accept(&(d->mCollectionsProcessedNotifier));
0786 }
0787 
0788 void FileStore::AbstractLocalStore::notifyItemsProcessed(const Item::List &items) const
0789 {
0790     Q_ASSERT(d->mCurrentJob != nullptr);
0791 
0792     d->mItemsProcessedNotifier.setItems(items);
0793     d->mCurrentJob->accept(&(d->mItemsProcessedNotifier));
0794     d->mItemsProcessedNotifier.clearItems(); // save memory
0795 }
0796 
0797 void FileStore::AbstractLocalStore::setTopLevelCollection(const Collection &collection)
0798 {
0799     d->mTopLevelCollection = collection;
0800     d->mTopLevelCollectionFetcher.setTopLevelCollection(collection);
0801 }
0802 
0803 void FileStore::AbstractLocalStore::checkCollectionCreate(FileStore::CollectionCreateJob *job, int &errorCode, QString &errorText) const
0804 {
0805     Q_UNUSED(job)
0806     Q_UNUSED(errorCode)
0807     Q_UNUSED(errorText)
0808 }
0809 
0810 void FileStore::AbstractLocalStore::checkCollectionDelete(FileStore::CollectionDeleteJob *job, int &errorCode, QString &errorText) const
0811 {
0812     Q_UNUSED(job)
0813     Q_UNUSED(errorCode)
0814     Q_UNUSED(errorText)
0815 }
0816 
0817 void FileStore::AbstractLocalStore::checkCollectionFetch(FileStore::CollectionFetchJob *job, int &errorCode, QString &errorText) const
0818 {
0819     Q_UNUSED(job)
0820     Q_UNUSED(errorCode)
0821     Q_UNUSED(errorText)
0822 }
0823 
0824 void FileStore::AbstractLocalStore::checkCollectionModify(FileStore::CollectionModifyJob *job, int &errorCode, QString &errorText) const
0825 {
0826     Q_UNUSED(job)
0827     Q_UNUSED(errorCode)
0828     Q_UNUSED(errorText)
0829 }
0830 
0831 void FileStore::AbstractLocalStore::checkCollectionMove(FileStore::CollectionMoveJob *job, int &errorCode, QString &errorText) const
0832 {
0833     Q_UNUSED(job)
0834     Q_UNUSED(errorCode)
0835     Q_UNUSED(errorText)
0836 }
0837 
0838 void FileStore::AbstractLocalStore::checkItemCreate(FileStore::ItemCreateJob *job, int &errorCode, QString &errorText) const
0839 {
0840     Q_UNUSED(job)
0841     Q_UNUSED(errorCode)
0842     Q_UNUSED(errorText)
0843 }
0844 
0845 void FileStore::AbstractLocalStore::checkItemDelete(FileStore::ItemDeleteJob *job, int &errorCode, QString &errorText) const
0846 {
0847     Q_UNUSED(job)
0848     Q_UNUSED(errorCode)
0849     Q_UNUSED(errorText)
0850 }
0851 
0852 void FileStore::AbstractLocalStore::checkItemFetch(FileStore::ItemFetchJob *job, int &errorCode, QString &errorText) const
0853 {
0854     Q_UNUSED(job)
0855     Q_UNUSED(errorCode)
0856     Q_UNUSED(errorText)
0857 }
0858 
0859 void FileStore::AbstractLocalStore::checkItemModify(FileStore::ItemModifyJob *job, int &errorCode, QString &errorText) const
0860 {
0861     Q_UNUSED(job)
0862     Q_UNUSED(errorCode)
0863     Q_UNUSED(errorText)
0864 }
0865 
0866 void FileStore::AbstractLocalStore::checkItemMove(FileStore::ItemMoveJob *job, int &errorCode, QString &errorText) const
0867 {
0868     Q_UNUSED(job)
0869     Q_UNUSED(errorCode)
0870     Q_UNUSED(errorText)
0871 }
0872 
0873 void FileStore::AbstractLocalStore::checkStoreCompact(FileStore::StoreCompactJob *job, int &errorCode, QString &errorText) const
0874 {
0875     Q_UNUSED(job)
0876     Q_UNUSED(errorCode)
0877     Q_UNUSED(errorText)
0878 }
0879 
0880 #include "moc_abstractlocalstore.cpp"