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

0001 /*
0002     SPDX-FileCopyrightText: 2008 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "itemlinkhandler.h"
0008 
0009 #include "akonadiserver_debug.h"
0010 #include "connection.h"
0011 #include "handlerhelper.h"
0012 #include "storage/collectionqueryhelper.h"
0013 #include "storage/datastore.h"
0014 #include "storage/itemqueryhelper.h"
0015 #include "storage/selectquerybuilder.h"
0016 #include "storage/transaction.h"
0017 
0018 #include "private/scope_p.h"
0019 
0020 using namespace Akonadi;
0021 using namespace Akonadi::Server;
0022 
0023 ItemLinkHandler::ItemLinkHandler(AkonadiServer &akonadi)
0024     : Handler(akonadi)
0025 {
0026 }
0027 
0028 bool ItemLinkHandler::parseStream()
0029 {
0030     const auto &cmd = Protocol::cmdCast<Protocol::LinkItemsCommand>(m_command);
0031 
0032     const Collection collection = HandlerHelper::collectionFromScope(cmd.destination(), connection()->context());
0033     if (!collection.isVirtual()) {
0034         return failureResponse(QStringLiteral("Can't link items to non-virtual collections"));
0035     }
0036 
0037     /* FIXME BIN
0038     Resource originalContext;
0039     Scope::SelectionScope itemSelectionScope = Scope::selectionScopeFromByteArray(m_streamParser->peekString());
0040     if (itemSelectionScope != Scope::None) {
0041         m_streamParser->readString();
0042         // Unset Resource context if destination collection is specified using HRID/RID,
0043         // because otherwise the Resource context is relative to the destination collection
0044         // instead of the source collection (collection context)
0045         if ((mDestinationScope.scope() == Scope::HierarchicalRid || mDestinationScope.scope() == Scope::Rid) && itemSelectionScope == Scope::Rid) {
0046             originalContext = connection()->context()->resource();
0047             connection()->context()->setResource(Resource());
0048         }
0049     }
0050     Scope itemScope(itemSelectionScope);
0051     itemScope.parseScope(m_streamParser);
0052     */
0053 
0054     SelectQueryBuilder<PimItem> qb;
0055     ItemQueryHelper::scopeToQuery(cmd.items(), connection()->context(), qb);
0056 
0057     /*
0058     if (originalContext.isValid()) {
0059         connection()->context()->setResource(originalContext);
0060     }
0061     */
0062 
0063     if (!qb.exec()) {
0064         return failureResponse(QStringLiteral("Unable to execute item query"));
0065     }
0066 
0067     const PimItem::List items = qb.result();
0068     const bool createLinks = (cmd.action() == Protocol::LinkItemsCommand::Link);
0069 
0070     DataStore *store = connection()->storageBackend();
0071     Transaction transaction(store, createLinks ? QStringLiteral("LINK") : QStringLiteral("UNLINK"));
0072 
0073     PimItem::List toLink;
0074     PimItem::List toUnlink;
0075     for (const PimItem &item : items) {
0076         const bool alreadyLinked = collection.relatesToPimItem(item);
0077         bool result = true;
0078         if (createLinks && !alreadyLinked) {
0079             result = collection.addPimItem(item);
0080             toLink << item;
0081         } else if (!createLinks && alreadyLinked) {
0082             result = collection.removePimItem(item);
0083             toUnlink << item;
0084         }
0085         if (!result) {
0086             return failureResponse(QStringLiteral("Failed to modify item reference"));
0087         }
0088     }
0089 
0090     if (!transaction.commit()) {
0091         return failureResponse(QStringLiteral("Cannot commit transaction."));
0092     }
0093 
0094     if (!toLink.isEmpty()) {
0095         store->notificationCollector()->itemsLinked(toLink, collection);
0096     } else if (!toUnlink.isEmpty()) {
0097         store->notificationCollector()->itemsUnlinked(toUnlink, collection);
0098     }
0099 
0100     return successResponse<Protocol::LinkItemsResponse>();
0101 }