File indexing completed on 2024-11-17 04:45:07

0001 /*
0002     SPDX-FileCopyrightText: 2014 Christian Mollekopf <mollekopf@kolabsys.com>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "replacemessagejob.h"
0008 
0009 #include "imapresource_debug.h"
0010 #include <KIMAP/AppendJob>
0011 #include <KIMAP/SearchJob>
0012 #include <KIMAP/SelectJob>
0013 #include <KIMAP/StoreJob>
0014 
0015 #include "imapflags.h"
0016 
0017 ReplaceMessageJob::ReplaceMessageJob(const KMime::Message::Ptr &msg,
0018                                      KIMAP::Session *session,
0019                                      const QString &mailbox,
0020                                      qint64 uidNext,
0021                                      const KIMAP::ImapSet &oldUids,
0022                                      QObject *parent)
0023     : KJob(parent)
0024     , mSession(session)
0025     , mMessage(msg)
0026     , mMailbox(mailbox)
0027     , mUidNext(uidNext)
0028     , mOldUids(oldUids)
0029     , mMessageId(msg->messageID()->asUnicodeString().toUtf8())
0030 {
0031 }
0032 
0033 void ReplaceMessageJob::start()
0034 {
0035     auto job = new KIMAP::AppendJob(mSession);
0036     job->setMailBox(mMailbox);
0037     job->setContent(mMessage->encodedContent(true));
0038     job->setInternalDate(mMessage->date()->dateTime());
0039     connect(job, &KJob::result, this, &ReplaceMessageJob::onAppendMessageDone);
0040     job->start();
0041 }
0042 
0043 void ReplaceMessageJob::onAppendMessageDone(KJob *job)
0044 {
0045     auto append = qobject_cast<KIMAP::AppendJob *>(job);
0046 
0047     if (append->error()) {
0048         qCWarning(IMAPRESOURCE_LOG) << append->errorString();
0049         setError(KJob::UserDefinedError);
0050         emitResult();
0051         return;
0052     }
0053 
0054     // We get it directly if UIDPLUS is supported...
0055     mNewUid = append->uid();
0056 
0057     if (mNewUid > 0 && mOldUids.isEmpty()) {
0058         // We have the uid an no message to delete, we're done
0059         emitResult();
0060         return;
0061     }
0062 
0063     if (mSession->selectedMailBox() != mMailbox) {
0064         // For search and delete we need to select the right mailbox first
0065         auto select = new KIMAP::SelectJob(mSession);
0066         select->setMailBox(mMailbox);
0067         connect(select, &KJob::result, this, &ReplaceMessageJob::onSelectDone);
0068         select->start();
0069     } else {
0070         if (mNewUid > 0) {
0071             triggerDeleteJobIfNecessary();
0072         } else {
0073             triggerSearchJob();
0074         }
0075     }
0076 }
0077 
0078 void ReplaceMessageJob::onSelectDone(KJob *job)
0079 {
0080     if (job->error()) {
0081         qCWarning(IMAPRESOURCE_LOG) << job->errorString();
0082         setError(KJob::UserDefinedError);
0083         emitResult();
0084     } else {
0085         if (mNewUid > 0) {
0086             triggerDeleteJobIfNecessary();
0087         } else {
0088             triggerSearchJob();
0089         }
0090     }
0091 }
0092 
0093 void ReplaceMessageJob::triggerSearchJob()
0094 {
0095     auto search = new KIMAP::SearchJob(mSession);
0096 
0097     search->setUidBased(true);
0098 
0099     if (!mMessageId.isEmpty()) {
0100         search->setTerm(KIMAP::Term(QStringLiteral("Message-ID"), QString::fromLatin1(mMessageId)));
0101     } else {
0102         if (mUidNext < 0) {
0103             qCWarning(IMAPRESOURCE_LOG) << "Could not determine the UID for the newly created message on the server";
0104             search->deleteLater();
0105             setError(KJob::UserDefinedError);
0106             emitResult();
0107             return;
0108         }
0109         search->setTerm(KIMAP::Term(KIMAP::Term::And, {KIMAP::Term(KIMAP::Term::New), KIMAP::Term(KIMAP::Term::Uid, KIMAP::ImapSet(mUidNext, 0))}));
0110     }
0111 
0112     connect(search, &KJob::result, this, &ReplaceMessageJob::onSearchDone);
0113 
0114     search->start();
0115 }
0116 
0117 void ReplaceMessageJob::onSearchDone(KJob *job)
0118 {
0119     if (job->error()) {
0120         qCWarning(IMAPRESOURCE_LOG) << job->errorString();
0121         setError(KJob::UserDefinedError);
0122         emitResult();
0123         return;
0124     }
0125 
0126     auto search = static_cast<KIMAP::SearchJob *>(job);
0127 
0128     if (search->results().count() == 1) {
0129         mNewUid = search->results().at(0);
0130     } else {
0131         qCWarning(IMAPRESOURCE_LOG) << "Failed to find uid for message. Got 0 or too many results: " << search->results().count();
0132         setError(KJob::UserDefinedError);
0133         emitResult();
0134         return;
0135     }
0136     triggerDeleteJobIfNecessary();
0137 }
0138 
0139 void ReplaceMessageJob::triggerDeleteJobIfNecessary()
0140 {
0141     if (mOldUids.isEmpty()) {
0142         // Nothing to do, we're done
0143         emitResult();
0144     } else {
0145         auto store = new KIMAP::StoreJob(mSession);
0146         store->setUidBased(true);
0147         store->setSequenceSet(mOldUids);
0148         store->setFlags(QList<QByteArray>() << ImapFlags::Deleted);
0149         store->setMode(KIMAP::StoreJob::AppendFlags);
0150         connect(store, &KJob::result, this, &ReplaceMessageJob::onDeleteDone);
0151         store->start();
0152     }
0153 }
0154 
0155 void ReplaceMessageJob::onDeleteDone(KJob *job)
0156 {
0157     if (job->error()) {
0158         qCWarning(IMAPRESOURCE_LOG) << job->errorString();
0159     }
0160     emitResult();
0161 }
0162 
0163 qint64 ReplaceMessageJob::newUid() const
0164 {
0165     return mNewUid;
0166 }
0167 
0168 #include "moc_replacemessagejob.cpp"