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

0001 /*
0002     SPDX-FileCopyrightText: 2013 Daniel Vrátil <dvratil@redhat.com>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "changeitemsflagstask.h"
0008 
0009 #include "imapresource_debug.h"
0010 #include <KIMAP/SelectJob>
0011 #include <KIMAP/Session>
0012 #include <KIMAP/StoreJob>
0013 
0014 ChangeItemsFlagsTask::ChangeItemsFlagsTask(const ResourceStateInterface::Ptr &resource, QObject *parent)
0015     : ResourceTask(ResourceTask::DeferIfNoSession, resource, parent)
0016 {
0017 }
0018 
0019 ChangeItemsFlagsTask::~ChangeItemsFlagsTask() = default;
0020 
0021 void ChangeItemsFlagsTask::doStart(KIMAP::Session *session)
0022 {
0023     const QString mailBox = mailBoxForCollection(items().at(0).parentCollection());
0024     qCDebug(IMAPRESOURCE_LOG) << mailBox;
0025 
0026     if (session->selectedMailBox() != mailBox) {
0027         auto select = new KIMAP::SelectJob(session);
0028         select->setMailBox(mailBox);
0029 
0030         connect(select, &KJob::result, this, &ChangeItemsFlagsTask::onSelectDone);
0031 
0032         select->start();
0033     } else {
0034         if (!addedFlags().isEmpty()) {
0035             triggerAppendFlagsJob(session);
0036         } else if (!removedFlags().isEmpty()) {
0037             triggerRemoveFlagsJob(session);
0038         } else {
0039             qCDebug(IMAPRESOURCE_LOG) << "nothing to do";
0040             changeProcessed();
0041         }
0042     }
0043 }
0044 
0045 void ChangeItemsFlagsTask::onSelectDone(KJob *job)
0046 {
0047     if (job->error()) {
0048         qCWarning(IMAPRESOURCE_LOG) << "Select failed: " << job->errorString();
0049         cancelTask(job->errorString());
0050     } else {
0051         auto select = static_cast<KIMAP::SelectJob *>(job);
0052         qCDebug(IMAPRESOURCE_LOG) << addedFlags();
0053         if (!addedFlags().isEmpty()) {
0054             triggerAppendFlagsJob(select->session());
0055         } else if (!removedFlags().isEmpty()) {
0056             triggerRemoveFlagsJob(select->session());
0057         } else {
0058             qCDebug(IMAPRESOURCE_LOG) << "nothing to do";
0059             changeProcessed();
0060         }
0061     }
0062 }
0063 
0064 KIMAP::StoreJob *ChangeItemsFlagsTask::prepareJob(KIMAP::Session *session)
0065 {
0066     KIMAP::ImapSet set;
0067     const Akonadi::Item::List &allItems = items();
0068     // Split the request to multiple smaller requests of 2000 UIDs each - various IMAP
0069     // servers have various limits on maximum size of a request
0070     // 2000 is a random number that sounds like a good compromise between performance
0071     // and functionality (i.e. 2000 UIDs should be supported by any server out there)
0072     for (int i = 0, count = qMin(2000, allItems.count() - m_processedItems); i < count; ++i) {
0073         set.add(allItems[m_processedItems].remoteId().toLong());
0074         ++m_processedItems;
0075     }
0076 
0077     auto store = new KIMAP::StoreJob(session);
0078     store->setUidBased(true);
0079     store->setSequenceSet(set);
0080 
0081     return store;
0082 }
0083 
0084 void ChangeItemsFlagsTask::triggerAppendFlagsJob(KIMAP::Session *session)
0085 {
0086     const auto supportedFlags = fromAkonadiToSupportedImapFlags(addedFlags().values(), items().at(0).parentCollection());
0087     if (supportedFlags.isEmpty()) {
0088         if (!removedFlags().isEmpty()) {
0089             m_processedItems = 0;
0090             triggerRemoveFlagsJob(session);
0091         } else {
0092             changeProcessed();
0093         }
0094     } else {
0095         KIMAP::StoreJob *store = prepareJob(session);
0096         store->setFlags(supportedFlags);
0097         store->setMode(KIMAP::StoreJob::AppendFlags);
0098         connect(store, &KIMAP::StoreJob::result, this, &ChangeItemsFlagsTask::onAppendFlagsDone);
0099         store->start();
0100     }
0101 }
0102 
0103 void ChangeItemsFlagsTask::triggerRemoveFlagsJob(KIMAP::Session *session)
0104 {
0105     const auto supportedFlags = fromAkonadiToSupportedImapFlags(removedFlags().values(), items().at(0).parentCollection());
0106     if (supportedFlags.isEmpty()) {
0107         changeProcessed();
0108     } else {
0109         KIMAP::StoreJob *store = prepareJob(session);
0110         store->setFlags(supportedFlags);
0111         store->setMode(KIMAP::StoreJob::RemoveFlags);
0112         connect(store, &KIMAP::StoreJob::result, this, &ChangeItemsFlagsTask::onRemoveFlagsDone);
0113         store->start();
0114     }
0115 }
0116 
0117 void ChangeItemsFlagsTask::onAppendFlagsDone(KJob *job)
0118 {
0119     if (job->error()) {
0120         qCWarning(IMAPRESOURCE_LOG) << "Flag append failed: " << job->errorString();
0121         cancelTask(job->errorString());
0122     } else {
0123         KIMAP::Session *session = qobject_cast<KIMAP::Job *>(job)->session();
0124         if (m_processedItems < items().count()) {
0125             triggerAppendFlagsJob(session);
0126         } else if (removedFlags().isEmpty()) {
0127             changeProcessed();
0128         } else {
0129             qCDebug(IMAPRESOURCE_LOG) << removedFlags();
0130             m_processedItems = 0;
0131             triggerRemoveFlagsJob(session);
0132         }
0133     }
0134 }
0135 
0136 void ChangeItemsFlagsTask::onRemoveFlagsDone(KJob *job)
0137 {
0138     if (job->error()) {
0139         qCWarning(IMAPRESOURCE_LOG) << "Flag remove failed: " << job->errorString();
0140         cancelTask(job->errorString());
0141     } else {
0142         if (m_processedItems < items().count()) {
0143             triggerRemoveFlagsJob(qobject_cast<KIMAP::Job *>(job)->session());
0144         } else {
0145             changeProcessed();
0146         }
0147     }
0148 }
0149 
0150 #include "moc_changeitemsflagstask.cpp"