File indexing completed on 2024-06-23 05:07:01

0001 /*
0002     SPDX-FileCopyrightText: 2008 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "itemcopyhandler.h"
0008 
0009 #include "akonadi.h"
0010 #include "cachecleaner.h"
0011 #include "connection.h"
0012 #include "handlerhelper.h"
0013 #include "storage/datastore.h"
0014 #include "storage/itemqueryhelper.h"
0015 #include "storage/itemretriever.h"
0016 #include "storage/parthelper.h"
0017 #include "storage/selectquerybuilder.h"
0018 #include "storage/transaction.h"
0019 
0020 #include "private/imapset_p.h"
0021 
0022 using namespace Akonadi;
0023 using namespace Akonadi::Server;
0024 
0025 ItemCopyHandler::ItemCopyHandler(AkonadiServer &akonadi)
0026     : Handler(akonadi)
0027 {
0028 }
0029 
0030 bool ItemCopyHandler::copyItem(const PimItem &item, const Collection &target)
0031 {
0032     PimItem newItem = item;
0033     newItem.setId(-1);
0034     newItem.setRev(0);
0035     newItem.setDatetime(QDateTime::currentDateTimeUtc());
0036     newItem.setAtime(QDateTime::currentDateTimeUtc());
0037     newItem.setRemoteId(QString());
0038     newItem.setRemoteRevision(QString());
0039     newItem.setCollectionId(target.id());
0040     Part::List newParts;
0041     const auto parts = item.parts();
0042     newParts.reserve(parts.size());
0043     for (const Part &part : parts) {
0044         Part newPart(part);
0045         newPart.setData(PartHelper::translateData(newPart.data(), part.storage()));
0046         newPart.setPimItemId(-1);
0047         newPart.setStorage(Part::Internal);
0048         newParts << newPart;
0049     }
0050 
0051     DataStore *store = connection()->storageBackend();
0052     return store->appendPimItem(newParts, item.flags(), item.mimeType(), target, QDateTime::currentDateTimeUtc(), QString(), QString(), item.gid(), newItem);
0053 }
0054 
0055 void ItemCopyHandler::processItems(const QList<qint64> &ids)
0056 {
0057     SelectQueryBuilder<PimItem> qb;
0058     ItemQueryHelper::itemSetToQuery(ImapSet(ids), qb);
0059     if (!qb.exec()) {
0060         failureResponse(QStringLiteral("Unable to retrieve items"));
0061         return;
0062     }
0063     const PimItem::List items = qb.result();
0064     qb.query().finish();
0065 
0066     DataStore *store = connection()->storageBackend();
0067     Transaction transaction(store, QStringLiteral("COPY"));
0068 
0069     for (const PimItem &item : items) {
0070         if (!copyItem(item, mTargetCollection)) {
0071             failureResponse(QStringLiteral("Unable to copy item"));
0072             return;
0073         }
0074     }
0075 
0076     if (!transaction.commit()) {
0077         failureResponse(QStringLiteral("Cannot commit transaction."));
0078         return;
0079     }
0080 }
0081 
0082 bool ItemCopyHandler::parseStream()
0083 {
0084     const auto &cmd = Protocol::cmdCast<Protocol::CopyItemsCommand>(m_command);
0085 
0086     if (!checkScopeConstraints(cmd.items(), Scope::Uid)) {
0087         return failureResponse(QStringLiteral("Only UID copy is allowed"));
0088     }
0089 
0090     if (cmd.items().isEmpty()) {
0091         return failureResponse(QStringLiteral("No items specified"));
0092     }
0093 
0094     mTargetCollection = HandlerHelper::collectionFromScope(cmd.destination(), connection()->context());
0095     if (!mTargetCollection.isValid()) {
0096         return failureResponse(QStringLiteral("No valid target specified"));
0097     }
0098     if (mTargetCollection.isVirtual()) {
0099         return failureResponse(QStringLiteral("Copying items into virtual collections is not allowed"));
0100     }
0101 
0102     CacheCleanerInhibitor inhibitor(akonadi());
0103 
0104     ItemRetriever retriever(akonadi().itemRetrievalManager(), connection(), connection()->context());
0105     retriever.setItemSet(cmd.items().uidSet());
0106     retriever.setRetrieveFullPayload(true);
0107     QObject::connect(&retriever, &ItemRetriever::itemsRetrieved, &retriever, [this](const QList<qint64> &ids) {
0108         processItems(ids);
0109     });
0110     if (!retriever.exec()) {
0111         return failureResponse(retriever.lastError());
0112     }
0113 
0114     return successResponse<Protocol::CopyItemsResponse>();
0115 }