File indexing completed on 2024-06-23 05:07:00
0001 /* 0002 SPDX-FileCopyrightText: 2008 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "collectioncopyhandler.h" 0008 0009 #include "akonadi.h" 0010 #include "cachecleaner.h" 0011 #include "connection.h" 0012 #include "handlerhelper.h" 0013 #include "protocol_p.h" 0014 #include "shared/akranges.h" 0015 #include "storage/collectionqueryhelper.h" 0016 #include "storage/datastore.h" 0017 #include "storage/itemretriever.h" 0018 #include "storage/transaction.h" 0019 0020 using namespace Akonadi; 0021 using namespace Akonadi::Server; 0022 using namespace AkRanges; 0023 0024 CollectionCopyHandler::CollectionCopyHandler(AkonadiServer &akonadi) 0025 : ItemCopyHandler(akonadi) 0026 { 0027 } 0028 0029 bool CollectionCopyHandler::copyCollection(const Collection &source, const Collection &target) 0030 { 0031 if (!CollectionQueryHelper::canBeMovedTo(source, target)) { 0032 // We don't accept source==target, or source being an ancestor of target. 0033 return false; 0034 } 0035 0036 // copy the source collection 0037 Collection col = source; 0038 col.setParentId(target.id()); 0039 col.setResourceId(target.resourceId()); 0040 // clear remote id and revision on inter-resource copies 0041 if (source.resourceId() != target.resourceId()) { 0042 col.setRemoteId(QString()); 0043 col.setRemoteRevision(QString()); 0044 } 0045 0046 const auto mimeTypes = source.mimeTypes() | Views::transform(&MimeType::name) | Actions::toQList; 0047 const auto attributes = source.attributes() | Views::transform([](const auto &attr) { 0048 return std::make_pair(attr.type(), attr.value()); 0049 }) 0050 | Actions::toQMap; 0051 0052 if (!storageBackend()->appendCollection(col, mimeTypes, attributes)) { 0053 return false; 0054 } 0055 0056 // copy sub-collections 0057 const Collection::List lstCols = source.children(); 0058 for (const Collection &child : lstCols) { 0059 if (!copyCollection(child, col)) { 0060 return false; 0061 } 0062 } 0063 0064 // copy items 0065 const auto items = source.items(); 0066 for (const auto &item : items) { 0067 if (!copyItem(item, col)) { 0068 return false; 0069 } 0070 } 0071 0072 return true; 0073 } 0074 0075 bool CollectionCopyHandler::parseStream() 0076 { 0077 const auto &cmd = Protocol::cmdCast<Protocol::CopyCollectionCommand>(m_command); 0078 0079 const Collection source = HandlerHelper::collectionFromScope(cmd.collection(), connection()->context()); 0080 if (!source.isValid()) { 0081 return failureResponse(QStringLiteral("No valid source specified")); 0082 } 0083 0084 const Collection target = HandlerHelper::collectionFromScope(cmd.destination(), connection()->context()); 0085 if (!target.isValid()) { 0086 return failureResponse(QStringLiteral("No valid target specified")); 0087 } 0088 0089 CacheCleanerInhibitor inhibitor(akonadi()); 0090 0091 // retrieve all not yet cached items of the source 0092 ItemRetriever retriever(akonadi().itemRetrievalManager(), connection(), connection()->context()); 0093 retriever.setCollection(source, true); 0094 retriever.setRetrieveFullPayload(true); 0095 if (!retriever.exec()) { 0096 return failureResponse(retriever.lastError()); 0097 } 0098 0099 Transaction transaction(storageBackend(), QStringLiteral("CollectionCopyHandler")); 0100 0101 if (!copyCollection(source, target)) { 0102 return failureResponse(QStringLiteral("Failed to copy collection")); 0103 } 0104 0105 if (!transaction.commit()) { 0106 return failureResponse(QStringLiteral("Cannot commit transaction.")); 0107 } 0108 0109 return successResponse<Protocol::CopyCollectionResponse>(); 0110 }