File indexing completed on 2024-06-02 05:21:11

0001 /*
0002     SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
0003     SPDX-FileContributor: Kevin Ottens <kevin@kdab.com>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "movecollectiontask.h"
0009 
0010 #include <KLocalizedString>
0011 
0012 #include <KIMAP/RenameJob>
0013 #include <KIMAP/SelectJob>
0014 #include <KIMAP/Session>
0015 #include <KIMAP/SubscribeJob>
0016 
0017 #include <QUuid>
0018 
0019 MoveCollectionTask::MoveCollectionTask(const ResourceStateInterface::Ptr &resource, QObject *parent)
0020     : ResourceTask(DeferIfNoSession, resource, parent)
0021 {
0022 }
0023 
0024 MoveCollectionTask::~MoveCollectionTask() = default;
0025 
0026 void MoveCollectionTask::doStart(KIMAP::Session *session)
0027 {
0028     if (collection().remoteId().isEmpty()) {
0029         emitError(i18n("Cannot move IMAP folder '%1', it does not exist on the server.", collection().name()));
0030         changeProcessed();
0031         return;
0032     }
0033 
0034     if (sourceCollection().remoteId().isEmpty()) {
0035         emitError(i18n("Cannot move IMAP folder '%1' out of '%2', '%2' does not exist on the server.", collection().name(), sourceCollection().name()));
0036         changeProcessed();
0037         return;
0038     }
0039 
0040     if (targetCollection().remoteId().isEmpty()) {
0041         emitError(i18n("Cannot move IMAP folder '%1' to '%2', '%2' does not exist on the server.", collection().name(), sourceCollection().name()));
0042         changeProcessed();
0043         return;
0044     }
0045 
0046     if (session->selectedMailBox() != mailBoxForCollection(collection())) {
0047         doRename(session);
0048         return;
0049     }
0050 
0051     // Some IMAP servers don't allow moving an opened mailbox, so make sure
0052     // it's not opened (https://bugs.kde.org/show_bug.cgi?id=324932) by examining
0053     // a non-existent mailbox. We don't use CLOSE in order not to trigger EXPUNGE
0054     auto examine = new KIMAP::SelectJob(session);
0055     examine->setOpenReadOnly(true); // use EXAMINE instead of SELECT
0056     examine->setMailBox(QStringLiteral("IMAP Resource non existing folder %1").arg(QUuid::createUuid().toString()));
0057     connect(examine, &KIMAP::SelectJob::result, this, &MoveCollectionTask::onExamineDone);
0058     examine->start();
0059 }
0060 
0061 void MoveCollectionTask::onExamineDone(KJob *job)
0062 {
0063     // We deliberately ignore any error here, because the SelectJob will always fail
0064     // when examining a non-existent mailbox
0065 
0066     auto examine = static_cast<KIMAP::SelectJob *>(job);
0067     doRename(examine->session());
0068 }
0069 
0070 QString MoveCollectionTask::mailBoxForCollections(const Akonadi::Collection &parent, const Akonadi::Collection &child) const
0071 {
0072     const QString parentMailbox = mailBoxForCollection(parent);
0073     if (parentMailbox.isEmpty()) {
0074         return child.remoteId().mid(1); // Strip separator on toplevel mailboxes
0075     }
0076     return parentMailbox + child.remoteId();
0077 }
0078 
0079 void MoveCollectionTask::doRename(KIMAP::Session *session)
0080 {
0081     // collection.remoteId() already includes the separator
0082     const QString oldMailBox = mailBoxForCollections(sourceCollection(), collection());
0083     const QString newMailBox = mailBoxForCollections(targetCollection(), collection());
0084 
0085     if (oldMailBox != newMailBox) {
0086         auto job = new KIMAP::RenameJob(session);
0087         job->setSourceMailBox(oldMailBox);
0088         job->setDestinationMailBox(newMailBox);
0089 
0090         connect(job, &KIMAP::RenameJob::result, this, &MoveCollectionTask::onRenameDone);
0091 
0092         job->start();
0093     } else {
0094         changeProcessed();
0095     }
0096 }
0097 
0098 void MoveCollectionTask::onRenameDone(KJob *job)
0099 {
0100     if (job->error()) {
0101         cancelTask(job->errorString());
0102     } else {
0103         // Automatically subscribe to the new mailbox name
0104         auto rename = static_cast<KIMAP::RenameJob *>(job);
0105 
0106         auto subscribe = new KIMAP::SubscribeJob(rename->session());
0107         subscribe->setMailBox(rename->destinationMailBox());
0108 
0109         connect(subscribe, &KIMAP::SubscribeJob::result, this, &MoveCollectionTask::onSubscribeDone);
0110 
0111         subscribe->start();
0112     }
0113 }
0114 
0115 void MoveCollectionTask::onSubscribeDone(KJob *job)
0116 {
0117     if (job->error()) {
0118         emitWarning(
0119             i18n("Failed to subscribe to the folder '%1' on the IMAP server. "
0120                  "It will disappear on next sync. Use the subscription dialog to overcome that",
0121                  collection().name()));
0122     }
0123 
0124     changeCommitted(collection());
0125 }
0126 
0127 #include "moc_movecollectiontask.cpp"