Collection HandlerHelper::collectionFromIdOrName(const QByteArray &id) { // id is a number bool ok = false; qint64 collectionId = id.toLongLong(&ok); if (ok) { return Collection::retrieveById(collectionId); } // id is a path QString path = QString::fromUtf8(id); // ### should be UTF-7 for real IMAP compatibility const QStringList pathParts = path.split(QLatin1Char('/'), QString::SkipEmptyParts); Collection col; for (const QString &part : pathParts) { SelectQueryBuilder<Collection> qb; qb.addValueCondition(Collection::nameColumn(), Query::Equals, part); if (col.isValid()) { qb.addValueCondition(Collection::parentIdColumn(), Query::Equals, col.id()); } else { qb.addValueCondition(Collection::parentIdColumn(), Query::Is, QVariant()); } if (!qb.exec()) { return Collection(); } Collection::List list = qb.result(); if (list.count() != 1) { return Collection(); } col = list.first(); } return col; }
bool Link::parseStream() { Protocol::LinkItemsCommand cmd(m_command); const Collection collection = HandlerHelper::collectionFromScope(cmd.destination(), connection()); if (!collection.isVirtual()) { return failureResponse("Can't link items to non-virtual collections"); } /* FIXME BIN Resource originalContext; Scope::SelectionScope itemSelectionScope = Scope::selectionScopeFromByteArray(m_streamParser->peekString()); if (itemSelectionScope != Scope::None) { m_streamParser->readString(); // Unset Resource context if destination collection is specified using HRID/RID, // because otherwise the Resource context is relative to the destination collection // instead of the source collection (collection context) if ((mDestinationScope.scope() == Scope::HierarchicalRid || mDestinationScope.scope() == Scope::Rid) && itemSelectionScope == Scope::Rid) { originalContext = connection()->context()->resource(); connection()->context()->setResource(Resource()); } } Scope itemScope(itemSelectionScope); itemScope.parseScope(m_streamParser); */ SelectQueryBuilder<PimItem> qb; ItemQueryHelper::scopeToQuery(cmd.items(), connection()->context(), qb); /* if (originalContext.isValid()) { connection()->context()->setResource(originalContext); } */ if (!qb.exec()) { return failureResponse("Unable to execute item query"); } const PimItem::List items = qb.result(); DataStore *store = connection()->storageBackend(); Transaction transaction(store); PimItem::List toLink, toUnlink; const bool createLinks = (cmd.action() == Protocol::LinkItemsCommand::Link); for (const PimItem &item : items) { const bool alreadyLinked = collection.relatesToPimItem(item); bool result = true; if (createLinks && !alreadyLinked) { result = collection.addPimItem(item); toLink << item; } else if (!createLinks && alreadyLinked) { result = collection.removePimItem(item); toUnlink << item; } if (!result) { return failureResponse("Failed to modify item reference"); } } if (!toLink.isEmpty()) { store->notificationCollector()->itemsLinked(toLink, collection); } else if (!toUnlink.isEmpty()) { store->notificationCollector()->itemsUnlinked(toUnlink, collection); } if (!transaction.commit()) { return failureResponse("Cannot commit transaction."); } return successResponse<Protocol::LinkItemsResponse>(); }
bool Store::parseStream() { Protocol::ModifyItemsCommand cmd(m_command); //parseCommand(); DataStore *store = connection()->storageBackend(); Transaction transaction(store); ExternalPartStorageTransaction storageTrx; // Set the same modification time for each item. QDateTime modificationtime = QDateTime::currentDateTimeUtc(); if (DbType::type(store->database()) != DbType::Sqlite) { // Remove milliseconds from the modificationtime. PSQL and MySQL don't // support milliseconds in DATETIME column, so FETCHed Items will report // time without milliseconds, while this command would return answer // with milliseconds modificationtime = modificationtime.addMSecs(-modificationtime.time().msec()); } // retrieve selected items SelectQueryBuilder<PimItem> qb; ItemQueryHelper::scopeToQuery(cmd.items(), connection()->context(), qb); if (!qb.exec()) { return failureResponse("Unable to retrieve items"); } PimItem::List pimItems = qb.result(); if (pimItems.isEmpty()) { return failureResponse("No items found"); } for (int i = 0; i < pimItems.size(); ++i) { if (cmd.oldRevision() > -1) { // check for conflicts if a resources tries to overwrite an item with dirty payload const PimItem &pimItem = pimItems.at(i); if (connection()->isOwnerResource(pimItem)) { if (pimItem.dirty()) { const QString error = QStringLiteral("[LRCONFLICT] Resource %1 tries to modify item %2 (%3) (in collection %4) with dirty payload, aborting STORE."); return failureResponse( error.arg(pimItem.collection().resource().name()) .arg(pimItem.id()) .arg(pimItem.remoteId()).arg(pimItem.collectionId())); } } // check and update revisions if (pimItems.at(i).rev() != (int) cmd.oldRevision()) { return failureResponse("[LLCONFLICT] Item was modified elsewhere, aborting STORE."); } } } PimItem &item = pimItems.first(); QSet<QByteArray> changes; qint64 partSizes = 0; qint64 size = 0; bool flagsChanged = false; bool tagsChanged = false; if (cmd.modifiedParts() & Protocol::ModifyItemsCommand::AddedFlags) { if (!addFlags(pimItems, cmd.addedFlags(), flagsChanged)) { return failureResponse("Unable to add item flags"); } } if (cmd.modifiedParts() & Protocol::ModifyItemsCommand::RemovedFlags) { if (!deleteFlags(pimItems, cmd.removedFlags(), flagsChanged)) { return failureResponse("Unable to remove item flags"); } } if (cmd.modifiedParts() & Protocol::ModifyItemsCommand::Flags) { if (!replaceFlags(pimItems, cmd.flags(), flagsChanged)) { return failureResponse("Unable to reset flags"); } } if (flagsChanged) { changes << AKONADI_PARAM_FLAGS; } if (cmd.modifiedParts() & Protocol::ModifyItemsCommand::AddedTags) { if (!addTags(pimItems, cmd.addedTags(), tagsChanged)) { return failureResponse("Unable to add item tags"); } } if (cmd.modifiedParts() & Protocol::ModifyItemsCommand::RemovedTags) { if (!deleteTags(pimItems, cmd.removedTags(), tagsChanged)) { return failureResponse("Unabel to remove item tags"); } } if (cmd.modifiedParts() & Protocol::ModifyItemsCommand::Tags) { if (!replaceTags(pimItems, cmd.tags(), tagsChanged)) { return failureResponse("Unable to reset item tags"); } } if (tagsChanged) { changes << AKONADI_PARAM_TAGS; } if (item.isValid() && cmd.modifiedParts() & Protocol::ModifyItemsCommand::RemoteID) { if (item.remoteId() != cmd.remoteId()) { if (!connection()->isOwnerResource(item)) { return failureResponse("Only resources can modify remote identifiers"); } item.setRemoteId(cmd.remoteId()); changes << AKONADI_PARAM_REMOTEID; } } if (item.isValid() && cmd.modifiedParts() & Protocol::ModifyItemsCommand::GID) { if (item.gid() != cmd.gid()) { item.setGid(cmd.gid()); } changes << AKONADI_PARAM_GID; } if (item.isValid() && cmd.modifiedParts() & Protocol::ModifyItemsCommand::RemoteRevision) { if (item.remoteRevision() != cmd.remoteRevision()) { if (!connection()->isOwnerResource(item)) { return failureResponse("Only resources can modify remote revisions"); } item.setRemoteRevision(cmd.remoteRevision()); changes << AKONADI_PARAM_REMOTEREVISION; } } if (item.isValid() && !cmd.dirty()) { item.setDirty(false); } if (item.isValid() && cmd.modifiedParts() & Protocol::ModifyItemsCommand::Size) { size = cmd.itemSize(); changes << AKONADI_PARAM_SIZE; } if (item.isValid() && cmd.modifiedParts() & Protocol::ModifyItemsCommand::RemovedParts) { if (!cmd.removedParts().isEmpty()) { if (!store->removeItemParts(item, cmd.removedParts())) { return failureResponse("Unable to remove item parts"); } Q_FOREACH (const QByteArray &part, cmd.removedParts()) { changes.insert(part); } } } if (item.isValid() && cmd.modifiedParts() & Protocol::ModifyItemsCommand::Parts) { PartStreamer streamer(connection(), item, this); connect(&streamer, &PartStreamer::responseAvailable, this, static_cast<void(Handler::*)(const Protocol::Command &)>(&Handler::sendResponse)); Q_FOREACH (const QByteArray &partName, cmd.parts()) { qint64 partSize = 0; if (!streamer.stream(true, partName, partSize)) { return failureResponse(streamer.error()); } changes.insert(partName); partSizes += partSize; } }