File indexing completed on 2024-06-02 05:20:39

0001 /*
0002     SPDX-FileCopyrightText: 2013 Christian Mollekopf <mollekopf@kolabsys.com>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "gidmigrationjob.h"
0008 #include <Akonadi/CollectionFetchJob>
0009 #include <Akonadi/CollectionFetchScope>
0010 #include <Akonadi/ItemFetchJob>
0011 #include <Akonadi/ItemFetchScope>
0012 #include <Akonadi/ItemModifyJob>
0013 
0014 using namespace Akonadi;
0015 
0016 UpdateJob::UpdateJob(const Collection &col, QObject *parent)
0017     : Job(parent)
0018     , mCollection(col)
0019     , mModJobRunning(false)
0020 {
0021 }
0022 
0023 UpdateJob::~UpdateJob() = default;
0024 
0025 void UpdateJob::doStart()
0026 {
0027     auto fetchJob = new ItemFetchJob(mCollection, this);
0028     fetchJob->fetchScope().setCacheOnly(true);
0029     fetchJob->fetchScope().setIgnoreRetrievalErrors(true);
0030     fetchJob->fetchScope().setFetchModificationTime(false);
0031     fetchJob->fetchScope().setFetchRemoteIdentification(false);
0032     fetchJob->fetchScope().fetchFullPayload(true);
0033     // Limit scope to envelope only for mail
0034     connect(fetchJob, &ItemFetchJob::itemsReceived, this, &UpdateJob::itemsReceived);
0035 }
0036 
0037 void UpdateJob::itemsReceived(const Akonadi::Item::List &items)
0038 {
0039     // We're queuing items rather than creating ItemModifyJobs directly due to memory concerns
0040     // I'm not sure if that would indeed be a problem (a ModifyJob shouldn't be much larger than the item) but we'd have to compare memory usage first when
0041     // creating large amounts of ItemModifyJobs.
0042     for (const Akonadi::Item &item : items) {
0043         mItemQueue.enqueue(item);
0044     }
0045     processNext();
0046 }
0047 
0048 void UpdateJob::slotResult(KJob *job)
0049 {
0050     // This slot is automatically called for all subjobs by KCompositeJob
0051     // FIXME the fetch job emits result before itemsReceived, because itemsReceived is triggered using the result signal (which is wrong IMO). See
0052     // ItemFetchJob::timeout If result was emitted at the end we could avoid having to call processNext in itemsReceived and locking it.
0053     auto const fetchJob = qobject_cast<ItemFetchJob *>(job);
0054     const bool fetchReturnedNoItems = fetchJob && fetchJob->items().isEmpty();
0055     Job::slotResult(job);
0056     if (fetchReturnedNoItems) {
0057         emitResult();
0058     } else if (!fetchJob) {
0059         mModJobRunning = false;
0060         if (!hasSubjobs()) {
0061             if (!processNext()) {
0062                 emitResult();
0063             }
0064         }
0065     }
0066 }
0067 
0068 bool UpdateJob::processNext()
0069 {
0070     if (mModJobRunning || mItemQueue.isEmpty()) {
0071         return false;
0072     }
0073     const Akonadi::Item &item = mItemQueue.dequeue();
0074     // Only the single item modifyjob updates the gid
0075     auto modJob = new ItemModifyJob(item, this);
0076     modJob->setUpdateGid(true);
0077     modJob->setIgnorePayload(true);
0078     mModJobRunning = true;
0079     return true;
0080 }
0081 
0082 GidMigrationJob::GidMigrationJob(const QStringList &mimeTypeFilter, QObject *parent)
0083     : Job(parent)
0084     , mMimeTypeFilter(mimeTypeFilter)
0085 {
0086 }
0087 
0088 GidMigrationJob::~GidMigrationJob() = default;
0089 
0090 void GidMigrationJob::doStart()
0091 {
0092     auto fetchJob = new CollectionFetchJob(Collection::root(), CollectionFetchJob::Recursive, this);
0093     fetchJob->fetchScope().setContentMimeTypes(mMimeTypeFilter);
0094     connect(fetchJob, &CollectionFetchJob::collectionsReceived, this, &GidMigrationJob::collectionsReceived);
0095     connect(fetchJob, &CollectionFetchJob::result, this, &GidMigrationJob::collectionsFetched);
0096 }
0097 
0098 void GidMigrationJob::collectionsReceived(const Collection::List &collections)
0099 {
0100     mCollections << collections;
0101 }
0102 
0103 void GidMigrationJob::collectionsFetched(KJob *job)
0104 {
0105     // Errors are propagated by KCompositeJob
0106     if (!job->error()) {
0107         processCollection();
0108     }
0109 }
0110 
0111 void GidMigrationJob::processCollection()
0112 {
0113     if (mCollections.isEmpty()) {
0114         emitResult();
0115         return;
0116     }
0117     const Collection col = mCollections.takeLast();
0118     auto updateJob = new UpdateJob(col, this);
0119     connect(updateJob, &UpdateJob::result, this, &GidMigrationJob::itemsUpdated);
0120 }
0121 
0122 void GidMigrationJob::itemsUpdated(KJob *job)
0123 {
0124     // Errors are propagated by KCompositeJob
0125     if (!job->error()) {
0126         processCollection();
0127     }
0128 }
0129 
0130 #include "moc_gidmigrationjob.cpp"