File indexing completed on 2024-11-10 04:40:44
0001 /* 0002 SPDX-FileCopyrightText: 2008 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "akonadicore_debug.h" 0008 #include "attributefactory.h" 0009 #include "collection_p.h" 0010 #include "collectionstatistics.h" 0011 #include "exceptionbase.h" 0012 #include "item_p.h" 0013 #include "itemfetchscope.h" 0014 #include "itemserializer_p.h" 0015 #include "persistentsearchattribute.h" 0016 #include "protocolhelper_p.h" 0017 #include "tag_p.h" 0018 #include "tagfetchscope.h" 0019 0020 #include "private/externalpartstorage_p.h" 0021 #include "private/protocol_p.h" 0022 0023 #include "shared/akranges.h" 0024 0025 #include <QFile> 0026 #include <QVarLengthArray> 0027 0028 using namespace Akonadi; 0029 using namespace AkRanges; 0030 0031 CachePolicy ProtocolHelper::parseCachePolicy(const Protocol::CachePolicy &policy) 0032 { 0033 CachePolicy cp; 0034 cp.setCacheTimeout(policy.cacheTimeout()); 0035 cp.setIntervalCheckTime(policy.checkInterval()); 0036 cp.setInheritFromParent(policy.inherit()); 0037 cp.setSyncOnDemand(policy.syncOnDemand()); 0038 cp.setLocalParts(policy.localParts()); 0039 return cp; 0040 } 0041 0042 Protocol::CachePolicy ProtocolHelper::cachePolicyToProtocol(const CachePolicy &policy) 0043 { 0044 Protocol::CachePolicy proto; 0045 proto.setCacheTimeout(policy.cacheTimeout()); 0046 proto.setCheckInterval(policy.intervalCheckTime()); 0047 proto.setInherit(policy.inheritFromParent()); 0048 proto.setSyncOnDemand(policy.syncOnDemand()); 0049 proto.setLocalParts(policy.localParts()); 0050 return proto; 0051 } 0052 0053 template<typename T> 0054 inline static void parseAttributesImpl(const Protocol::Attributes &attributes, T *entity) 0055 { 0056 for (auto iter = attributes.cbegin(), end = attributes.cend(); iter != end; ++iter) { 0057 Attribute *attribute = AttributeFactory::createAttribute(iter.key()); 0058 if (!attribute) { 0059 qCWarning(AKONADICORE_LOG) << "Warning: unknown attribute" << iter.key(); 0060 continue; 0061 } 0062 attribute->deserialize(iter.value()); 0063 entity->addAttribute(attribute); 0064 } 0065 } 0066 0067 template<typename T> 0068 inline static void 0069 parseAncestorsCachedImpl(const QList<Protocol::Ancestor> &ancestors, T *entity, Collection::Id parentCollection, ProtocolHelperValuePool *pool) 0070 { 0071 if (!pool || parentCollection == -1) { 0072 // if no pool or parent collection id is provided we can't cache anything, so continue as usual 0073 ProtocolHelper::parseAncestors(ancestors, entity); 0074 return; 0075 } 0076 0077 if (pool->ancestorCollections.contains(parentCollection)) { 0078 // ancestor chain is cached already, so use the cached value 0079 entity->setParentCollection(pool->ancestorCollections.value(parentCollection)); 0080 } else { 0081 // not cached yet, parse the chain 0082 ProtocolHelper::parseAncestors(ancestors, entity); 0083 pool->ancestorCollections.insert(parentCollection, entity->parentCollection()); 0084 } 0085 } 0086 0087 template<typename T> 0088 inline static Protocol::Attributes attributesToProtocolImpl(const T &entity, bool ns) 0089 { 0090 Protocol::Attributes attributes; 0091 const auto attrs = entity.attributes(); 0092 for (const auto attr : attrs) { 0093 attributes.insert(ProtocolHelper::encodePartIdentifier(ns ? ProtocolHelper::PartAttribute : ProtocolHelper::PartGlobal, attr->type()), 0094 attr->serialized()); 0095 } 0096 return attributes; 0097 } 0098 0099 void ProtocolHelper::parseAncestorsCached(const QList<Protocol::Ancestor> &ancestors, 0100 Item *item, 0101 Collection::Id parentCollection, 0102 ProtocolHelperValuePool *pool) 0103 { 0104 parseAncestorsCachedImpl(ancestors, item, parentCollection, pool); 0105 } 0106 0107 void ProtocolHelper::parseAncestorsCached(const QList<Protocol::Ancestor> &ancestors, 0108 Collection *collection, 0109 Collection::Id parentCollection, 0110 ProtocolHelperValuePool *pool) 0111 { 0112 parseAncestorsCachedImpl(ancestors, collection, parentCollection, pool); 0113 } 0114 0115 void ProtocolHelper::parseAncestors(const QList<Protocol::Ancestor> &ancestors, Item *item) 0116 { 0117 Collection fakeCollection; 0118 parseAncestors(ancestors, &fakeCollection); 0119 0120 item->setParentCollection(fakeCollection.parentCollection()); 0121 } 0122 0123 void ProtocolHelper::parseAncestors(const QList<Protocol::Ancestor> &ancestors, Collection *collection) 0124 { 0125 static const Collection::Id rootCollectionId = Collection::root().id(); 0126 0127 Collection *current = collection; 0128 for (const Protocol::Ancestor &ancestor : ancestors) { 0129 if (ancestor.id() == rootCollectionId) { 0130 current->setParentCollection(Collection::root()); 0131 break; 0132 } 0133 0134 Akonadi::Collection parentCollection(ancestor.id()); 0135 parentCollection.setName(ancestor.name()); 0136 parentCollection.setRemoteId(ancestor.remoteId()); 0137 parseAttributesImpl(ancestor.attributes(), &parentCollection); 0138 current->setParentCollection(parentCollection); 0139 current = ¤t->parentCollection(); 0140 } 0141 } 0142 0143 static Collection::ListPreference parsePreference(Tristate value) 0144 { 0145 switch (value) { 0146 case Tristate::True: 0147 return Collection::ListEnabled; 0148 case Tristate::False: 0149 return Collection::ListDisabled; 0150 case Tristate::Undefined: 0151 return Collection::ListDefault; 0152 } 0153 0154 Q_ASSERT(false); 0155 return Collection::ListDefault; 0156 } 0157 0158 CollectionStatistics ProtocolHelper::parseCollectionStatistics(const Protocol::FetchCollectionStatsResponse &stats) 0159 { 0160 CollectionStatistics cs; 0161 cs.setCount(stats.count()); 0162 cs.setSize(stats.size()); 0163 cs.setUnreadCount(stats.unseen()); 0164 return cs; 0165 } 0166 0167 void ProtocolHelper::parseAttributes(const Protocol::Attributes &attributes, Item *item) 0168 { 0169 parseAttributesImpl(attributes, item); 0170 } 0171 0172 void ProtocolHelper::parseAttributes(const Protocol::Attributes &attributes, Collection *collection) 0173 { 0174 parseAttributesImpl(attributes, collection); 0175 } 0176 0177 void ProtocolHelper::parseAttributes(const Protocol::Attributes &attributes, Tag *tag) 0178 { 0179 parseAttributesImpl(attributes, tag); 0180 } 0181 0182 Protocol::Attributes ProtocolHelper::attributesToProtocol(const Item &item, bool ns) 0183 { 0184 return attributesToProtocolImpl(item, ns); 0185 } 0186 0187 Protocol::Attributes ProtocolHelper::attributesToProtocol(const Collection &collection, bool ns) 0188 { 0189 return attributesToProtocolImpl(collection, ns); 0190 } 0191 0192 Protocol::Attributes ProtocolHelper::attributesToProtocol(const Tag &tag, bool ns) 0193 { 0194 return attributesToProtocolImpl(tag, ns); 0195 } 0196 0197 Protocol::Attributes ProtocolHelper::attributesToProtocol(const std::vector<Attribute *> &modifiedAttributes, bool ns) 0198 { 0199 Protocol::Attributes attributes; 0200 for (const Attribute *attr : modifiedAttributes) { 0201 attributes.insert(ProtocolHelper::encodePartIdentifier(ns ? ProtocolHelper::PartAttribute : ProtocolHelper::PartGlobal, attr->type()), 0202 attr->serialized()); 0203 } 0204 return attributes; 0205 } 0206 0207 Collection ProtocolHelper::parseCollection(const Protocol::FetchCollectionsResponse &data, bool requireParent) 0208 { 0209 Collection collection(data.id()); 0210 0211 if (requireParent) { 0212 collection.setParentCollection(Collection(data.parentId())); 0213 } 0214 0215 collection.setName(data.name()); 0216 collection.setRemoteId(data.remoteId()); 0217 collection.setRemoteRevision(data.remoteRevision()); 0218 collection.setResource(data.resource()); 0219 collection.setContentMimeTypes(data.mimeTypes()); 0220 collection.setVirtual(data.isVirtual()); 0221 collection.setStatistics(parseCollectionStatistics(data.statistics())); 0222 collection.setCachePolicy(parseCachePolicy(data.cachePolicy())); 0223 parseAncestors(data.ancestors(), &collection); 0224 collection.setEnabled(data.enabled()); 0225 collection.setLocalListPreference(Collection::ListDisplay, parsePreference(data.displayPref())); 0226 collection.setLocalListPreference(Collection::ListIndex, parsePreference(data.indexPref())); 0227 collection.setLocalListPreference(Collection::ListSync, parsePreference(data.syncPref())); 0228 0229 if (!data.searchQuery().isEmpty()) { 0230 auto attr = collection.attribute<PersistentSearchAttribute>(Collection::AddIfMissing); 0231 attr->setQueryString(data.searchQuery()); 0232 const auto cols = data.searchCollections() | Views::transform([](const auto id) { 0233 return Collection{id}; 0234 }) 0235 | Actions::toQVector; 0236 attr->setQueryCollections(cols); 0237 } 0238 0239 parseAttributes(data.attributes(), &collection); 0240 0241 collection.d_ptr->resetChangeLog(); 0242 return collection; 0243 } 0244 0245 Tag ProtocolHelper::parseTag(const Protocol::FetchTagsResponse &data) 0246 { 0247 Tag tag(data.id()); 0248 tag.setRemoteId(data.remoteId()); 0249 tag.setGid(data.gid()); 0250 tag.setType(data.type()); 0251 tag.setParent(Tag(data.parentId())); 0252 parseAttributes(data.attributes(), &tag); 0253 tag.d_ptr->resetChangeLog(); 0254 0255 return tag; 0256 } 0257 0258 QByteArray ProtocolHelper::encodePartIdentifier(PartNamespace ns, const QByteArray &label) 0259 { 0260 switch (ns) { 0261 case PartGlobal: 0262 return label; 0263 case PartPayload: 0264 return "PLD:" + label; 0265 case PartAttribute: 0266 return "ATR:" + label; 0267 default: 0268 Q_ASSERT(false); 0269 } 0270 return QByteArray(); 0271 } 0272 0273 QByteArray ProtocolHelper::decodePartIdentifier(const QByteArray &data, PartNamespace &ns) 0274 { 0275 if (data.startsWith("PLD:")) { // krazy:exclude=strings 0276 ns = PartPayload; 0277 return data.mid(4); 0278 } else if (data.startsWith("ATR:")) { // krazy:exclude=strings 0279 ns = PartAttribute; 0280 return data.mid(4); 0281 } else { 0282 ns = PartGlobal; 0283 return data; 0284 } 0285 } 0286 0287 Protocol::ScopeContext 0288 ProtocolHelper::commandContextToProtocol(const Akonadi::Collection &collection, const Akonadi::Tag &tag, const Item::List &requestedItems) 0289 { 0290 Protocol::ScopeContext ctx; 0291 if (tag.isValid()) { 0292 ctx.setContext(Protocol::ScopeContext::Tag, tag.id()); 0293 } 0294 0295 if (collection == Collection::root()) { 0296 if (requestedItems.isEmpty() && !tag.isValid()) { // collection content listing 0297 throw Exception("Cannot perform item operations on root collection."); 0298 } 0299 } else { 0300 if (collection.isValid()) { 0301 ctx.setContext(Protocol::ScopeContext::Collection, collection.id()); 0302 } else if (!collection.remoteId().isEmpty()) { 0303 ctx.setContext(Protocol::ScopeContext::Collection, collection.remoteId()); 0304 } 0305 } 0306 0307 return ctx; 0308 } 0309 0310 Scope ProtocolHelper::hierarchicalRidToScope(const Collection &col) 0311 { 0312 if (col == Collection::root()) { 0313 return Scope({Scope::HRID(0)}); 0314 } 0315 if (col.remoteId().isEmpty()) { 0316 return Scope(); 0317 } 0318 0319 QList<Scope::HRID> chain; 0320 Collection c = col; 0321 while (!c.remoteId().isEmpty()) { 0322 chain.append(Scope::HRID(c.id(), c.remoteId())); 0323 c = c.parentCollection(); 0324 } 0325 return Scope(chain + QList<Scope::HRID>{Scope::HRID(0)}); 0326 } 0327 0328 Scope ProtocolHelper::hierarchicalRidToScope(const Item &item) 0329 { 0330 return Scope(QList<Scope::HRID>({Scope::HRID(item.id(), item.remoteId())}) + hierarchicalRidToScope(item.parentCollection()).hridChain()); 0331 } 0332 0333 Protocol::ItemFetchScope ProtocolHelper::itemFetchScopeToProtocol(const ItemFetchScope &fetchScope) 0334 { 0335 Protocol::ItemFetchScope fs; 0336 QList<QByteArray> parts; 0337 parts.reserve(fetchScope.payloadParts().size() + fetchScope.attributes().size()); 0338 parts += fetchScope.payloadParts() | Views::transform(std::bind(encodePartIdentifier, PartPayload, std::placeholders::_1)) | Actions::toQVector; 0339 parts += fetchScope.attributes() | Views::transform(std::bind(encodePartIdentifier, PartAttribute, std::placeholders::_1)) | Actions::toQVector; 0340 fs.setRequestedParts(parts); 0341 0342 // The default scope 0343 fs.setFetch(Protocol::ItemFetchScope::Flags | Protocol::ItemFetchScope::Size | Protocol::ItemFetchScope::RemoteID | Protocol::ItemFetchScope::RemoteRevision 0344 | Protocol::ItemFetchScope::MTime); 0345 0346 fs.setFetch(Protocol::ItemFetchScope::FullPayload, fetchScope.fullPayload()); 0347 fs.setFetch(Protocol::ItemFetchScope::AllAttributes, fetchScope.allAttributes()); 0348 fs.setFetch(Protocol::ItemFetchScope::CacheOnly, fetchScope.cacheOnly()); 0349 fs.setFetch(Protocol::ItemFetchScope::CheckCachedPayloadPartsOnly, fetchScope.checkForCachedPayloadPartsOnly()); 0350 fs.setFetch(Protocol::ItemFetchScope::IgnoreErrors, fetchScope.ignoreRetrievalErrors()); 0351 switch (fetchScope.ancestorRetrieval()) { 0352 case ItemFetchScope::Parent: 0353 fs.setAncestorDepth(Protocol::ItemFetchScope::ParentAncestor); 0354 break; 0355 case ItemFetchScope::All: 0356 fs.setAncestorDepth(Protocol::ItemFetchScope::AllAncestors); 0357 break; 0358 case ItemFetchScope::None: 0359 fs.setAncestorDepth(Protocol::ItemFetchScope::NoAncestor); 0360 break; 0361 default: 0362 Q_ASSERT(false); 0363 break; 0364 } 0365 0366 if (fetchScope.fetchChangedSince().isValid()) { 0367 fs.setChangedSince(fetchScope.fetchChangedSince()); 0368 } 0369 0370 fs.setFetch(Protocol::ItemFetchScope::RemoteID, fetchScope.fetchRemoteIdentification()); 0371 fs.setFetch(Protocol::ItemFetchScope::RemoteRevision, fetchScope.fetchRemoteIdentification()); 0372 fs.setFetch(Protocol::ItemFetchScope::GID, fetchScope.fetchGid()); 0373 fs.setFetch(Protocol::ItemFetchScope::Tags, fetchScope.fetchTags()); 0374 fs.setFetch(Protocol::ItemFetchScope::VirtReferences, fetchScope.fetchVirtualReferences()); 0375 fs.setFetch(Protocol::ItemFetchScope::MTime, fetchScope.fetchModificationTime()); 0376 fs.setFetch(Protocol::ItemFetchScope::Relations, fetchScope.fetchRelations()); 0377 0378 return fs; 0379 } 0380 0381 ItemFetchScope ProtocolHelper::parseItemFetchScope(const Protocol::ItemFetchScope &fetchScope) 0382 { 0383 ItemFetchScope ifs; 0384 const auto parts = fetchScope.requestedParts(); 0385 for (const auto &part : parts) { 0386 if (part.startsWith("PLD:")) { 0387 ifs.fetchPayloadPart(part.mid(4), true); 0388 } else if (part.startsWith("ATR:")) { 0389 ifs.fetchAttribute(part.mid(4), true); 0390 } 0391 } 0392 0393 if (fetchScope.fetch(Protocol::ItemFetchScope::FullPayload)) { 0394 ifs.fetchFullPayload(true); 0395 } 0396 if (fetchScope.fetch(Protocol::ItemFetchScope::AllAttributes)) { 0397 ifs.fetchAllAttributes(true); 0398 } 0399 if (fetchScope.fetch(Protocol::ItemFetchScope::CacheOnly)) { 0400 ifs.setCacheOnly(true); 0401 } 0402 if (fetchScope.fetch(Protocol::ItemFetchScope::CheckCachedPayloadPartsOnly)) { 0403 ifs.setCheckForCachedPayloadPartsOnly(true); 0404 } 0405 if (fetchScope.fetch(Protocol::ItemFetchScope::IgnoreErrors)) { 0406 ifs.setIgnoreRetrievalErrors(true); 0407 } 0408 switch (fetchScope.ancestorDepth()) { 0409 case Protocol::ItemFetchScope::ParentAncestor: 0410 ifs.setAncestorRetrieval(ItemFetchScope::Parent); 0411 break; 0412 case Protocol::ItemFetchScope::AllAncestors: 0413 ifs.setAncestorRetrieval(ItemFetchScope::All); 0414 break; 0415 default: 0416 ifs.setAncestorRetrieval(ItemFetchScope::None); 0417 break; 0418 } 0419 if (fetchScope.changedSince().isValid()) { 0420 ifs.setFetchChangedSince(fetchScope.changedSince()); 0421 } 0422 if (fetchScope.fetch(Protocol::ItemFetchScope::RemoteID) || fetchScope.fetch(Protocol::ItemFetchScope::RemoteRevision)) { 0423 ifs.setFetchRemoteIdentification(true); 0424 } 0425 if (fetchScope.fetch(Protocol::ItemFetchScope::GID)) { 0426 ifs.setFetchGid(true); 0427 } 0428 if (fetchScope.fetch(Protocol::ItemFetchScope::Tags)) { 0429 ifs.setFetchTags(true); 0430 } 0431 if (fetchScope.fetch(Protocol::ItemFetchScope::VirtReferences)) { 0432 ifs.setFetchVirtualReferences(true); 0433 } 0434 if (fetchScope.fetch(Protocol::ItemFetchScope::MTime)) { 0435 ifs.setFetchModificationTime(true); 0436 } 0437 if (fetchScope.fetch(Protocol::ItemFetchScope::Relations)) { 0438 ifs.setFetchRelations(true); 0439 } 0440 0441 return ifs; 0442 } 0443 0444 Protocol::CollectionFetchScope ProtocolHelper::collectionFetchScopeToProtocol(const CollectionFetchScope &fetchScope) 0445 { 0446 Protocol::CollectionFetchScope cfs; 0447 switch (fetchScope.listFilter()) { 0448 case CollectionFetchScope::NoFilter: 0449 cfs.setListFilter(Protocol::CollectionFetchScope::NoFilter); 0450 break; 0451 case CollectionFetchScope::Display: 0452 cfs.setListFilter(Protocol::CollectionFetchScope::Display); 0453 break; 0454 case CollectionFetchScope::Sync: 0455 cfs.setListFilter(Protocol::CollectionFetchScope::Sync); 0456 break; 0457 case CollectionFetchScope::Index: 0458 cfs.setListFilter(Protocol::CollectionFetchScope::Index); 0459 break; 0460 case CollectionFetchScope::Enabled: 0461 cfs.setListFilter(Protocol::CollectionFetchScope::Enabled); 0462 break; 0463 } 0464 cfs.setIncludeStatistics(fetchScope.includeStatistics()); 0465 cfs.setResource(fetchScope.resource()); 0466 cfs.setContentMimeTypes(fetchScope.contentMimeTypes()); 0467 cfs.setAttributes(fetchScope.attributes()); 0468 cfs.setFetchIdOnly(fetchScope.fetchIdOnly()); 0469 switch (fetchScope.ancestorRetrieval()) { 0470 case CollectionFetchScope::None: 0471 cfs.setAncestorRetrieval(Protocol::CollectionFetchScope::None); 0472 break; 0473 case CollectionFetchScope::Parent: 0474 cfs.setAncestorRetrieval(Protocol::CollectionFetchScope::Parent); 0475 break; 0476 case CollectionFetchScope::All: 0477 cfs.setAncestorRetrieval(Protocol::CollectionFetchScope::All); 0478 break; 0479 } 0480 if (cfs.ancestorRetrieval() != Protocol::CollectionFetchScope::None) { 0481 cfs.setAncestorAttributes(fetchScope.ancestorFetchScope().attributes()); 0482 cfs.setAncestorFetchIdOnly(fetchScope.ancestorFetchScope().fetchIdOnly()); 0483 } 0484 cfs.setIgnoreRetrievalErrors(fetchScope.ignoreRetrievalErrors()); 0485 0486 return cfs; 0487 } 0488 0489 CollectionFetchScope ProtocolHelper::parseCollectionFetchScope(const Protocol::CollectionFetchScope &fetchScope) 0490 { 0491 CollectionFetchScope cfs; 0492 switch (fetchScope.listFilter()) { 0493 case Protocol::CollectionFetchScope::NoFilter: 0494 cfs.setListFilter(CollectionFetchScope::NoFilter); 0495 break; 0496 case Protocol::CollectionFetchScope::Display: 0497 cfs.setListFilter(CollectionFetchScope::Display); 0498 break; 0499 case Protocol::CollectionFetchScope::Sync: 0500 cfs.setListFilter(CollectionFetchScope::Sync); 0501 break; 0502 case Protocol::CollectionFetchScope::Index: 0503 cfs.setListFilter(CollectionFetchScope::Index); 0504 break; 0505 case Protocol::CollectionFetchScope::Enabled: 0506 cfs.setListFilter(CollectionFetchScope::Enabled); 0507 break; 0508 } 0509 cfs.setIncludeStatistics(fetchScope.includeStatistics()); 0510 cfs.setResource(fetchScope.resource()); 0511 cfs.setContentMimeTypes(fetchScope.contentMimeTypes()); 0512 switch (fetchScope.ancestorRetrieval()) { 0513 case Protocol::CollectionFetchScope::None: 0514 cfs.setAncestorRetrieval(CollectionFetchScope::None); 0515 break; 0516 case Protocol::CollectionFetchScope::Parent: 0517 cfs.setAncestorRetrieval(CollectionFetchScope::Parent); 0518 break; 0519 case Protocol::CollectionFetchScope::All: 0520 cfs.setAncestorRetrieval(CollectionFetchScope::All); 0521 break; 0522 } 0523 if (cfs.ancestorRetrieval() != CollectionFetchScope::None) { 0524 cfs.ancestorFetchScope().setFetchIdOnly(fetchScope.ancestorFetchIdOnly()); 0525 const auto attrs = fetchScope.ancestorAttributes(); 0526 for (const auto &attr : attrs) { 0527 cfs.ancestorFetchScope().fetchAttribute(attr, true); 0528 } 0529 } 0530 const auto attrs = fetchScope.attributes(); 0531 for (const auto &attr : attrs) { 0532 cfs.fetchAttribute(attr, true); 0533 } 0534 cfs.setFetchIdOnly(fetchScope.fetchIdOnly()); 0535 cfs.setIgnoreRetrievalErrors(fetchScope.ignoreRetrievalErrors()); 0536 0537 return cfs; 0538 } 0539 0540 Protocol::TagFetchScope ProtocolHelper::tagFetchScopeToProtocol(const TagFetchScope &fetchScope) 0541 { 0542 Protocol::TagFetchScope tfs; 0543 tfs.setFetchIdOnly(fetchScope.fetchIdOnly()); 0544 tfs.setAttributes(fetchScope.attributes()); 0545 tfs.setFetchRemoteID(fetchScope.fetchRemoteId()); 0546 tfs.setFetchAllAttributes(fetchScope.fetchAllAttributes()); 0547 return tfs; 0548 } 0549 0550 TagFetchScope ProtocolHelper::parseTagFetchScope(const Protocol::TagFetchScope &fetchScope) 0551 { 0552 TagFetchScope tfs; 0553 tfs.setFetchIdOnly(fetchScope.fetchIdOnly()); 0554 tfs.setFetchRemoteId(fetchScope.fetchRemoteID()); 0555 tfs.setFetchAllAttributes(fetchScope.fetchAllAttributes()); 0556 const auto attrs = fetchScope.attributes(); 0557 for (const auto &attr : attrs) { 0558 tfs.fetchAttribute(attr, true); 0559 } 0560 return tfs; 0561 } 0562 0563 static Item::Flags convertFlags(const QList<QByteArray> &flags, ProtocolHelperValuePool *valuePool) 0564 { 0565 #if __cplusplus >= 201103L || defined(__GNUC__) || defined(__clang__) 0566 // When the compiler supports thread-safe static initialization (mandated by the C++11 memory model) 0567 // then use it to share the common case of a single-item set only containing the \SEEN flag. 0568 // NOTE: GCC and clang has threadsafe static initialization for some time now, even without C++11. 0569 if (flags.size() == 1 && flags.first() == "\\SEEN") { 0570 static const Item::Flags sharedSeen = Item::Flags() << QByteArray("\\SEEN"); 0571 return sharedSeen; 0572 } 0573 #endif 0574 0575 Item::Flags convertedFlags; 0576 convertedFlags.reserve(flags.size()); 0577 for (const QByteArray &flag : flags) { 0578 if (valuePool) { 0579 convertedFlags.insert(valuePool->flagPool.sharedValue(flag)); 0580 } else { 0581 convertedFlags.insert(flag); 0582 } 0583 } 0584 return convertedFlags; 0585 } 0586 0587 Item ProtocolHelper::parseItemFetchResult(const Protocol::FetchItemsResponse &data, 0588 const Akonadi::ItemFetchScope *fetchScope, 0589 ProtocolHelperValuePool *valuePool) 0590 { 0591 Item item; 0592 item.setId(data.id()); 0593 item.setRevision(data.revision()); 0594 if (!fetchScope || fetchScope->fetchRemoteIdentification()) { 0595 item.setRemoteId(data.remoteId()); 0596 item.setRemoteRevision(data.remoteRevision()); 0597 } 0598 item.setGid(data.gid()); 0599 item.setStorageCollectionId(data.parentId()); 0600 0601 if (valuePool) { 0602 item.setMimeType(valuePool->mimeTypePool.sharedValue(data.mimeType())); 0603 } else { 0604 item.setMimeType(data.mimeType()); 0605 } 0606 0607 if (!item.isValid()) { 0608 return Item(); 0609 } 0610 0611 item.setFlags(convertFlags(data.flags(), valuePool)); 0612 0613 const auto fetchedTags = data.tags(); 0614 if ((!fetchScope || fetchScope->fetchTags()) && !fetchedTags.isEmpty()) { 0615 Tag::List tags; 0616 tags.reserve(fetchedTags.size()); 0617 for (const Protocol::FetchTagsResponse &tag : fetchedTags) { 0618 tags.append(parseTagFetchResult(tag)); 0619 } 0620 item.setTags(tags); 0621 } 0622 0623 const auto fetchedRelations = data.relations(); 0624 if ((!fetchScope || fetchScope->fetchRelations()) && !fetchedRelations.isEmpty()) { 0625 Relation::List relations; 0626 relations.reserve(fetchedRelations.size()); 0627 for (const Protocol::FetchRelationsResponse &rel : fetchedRelations) { 0628 relations.append(parseRelationFetchResult(rel)); 0629 } 0630 item.d_ptr->mRelations = relations; 0631 } 0632 0633 const auto virtualReferences = data.virtualReferences(); 0634 if ((!fetchScope || fetchScope->fetchVirtualReferences()) && !virtualReferences.isEmpty()) { 0635 Collection::List virtRefs; 0636 virtRefs.reserve(virtualReferences.size()); 0637 for (qint64 colId : virtualReferences) { 0638 virtRefs.append(Collection(colId)); 0639 } 0640 item.setVirtualReferences(virtRefs); 0641 } 0642 0643 const auto cachedParts = data.cachedParts(); 0644 if (!cachedParts.isEmpty()) { 0645 QSet<QByteArray> cp; 0646 cp.reserve(cachedParts.size()); 0647 for (const QByteArray &ba : cachedParts) { 0648 cp.insert(ba); 0649 } 0650 item.setCachedPayloadParts(cp); 0651 } 0652 0653 item.setSize(data.size()); 0654 item.setModificationTime(data.mTime()); 0655 parseAncestorsCached(data.ancestors(), &item, data.parentId(), valuePool); 0656 const auto parts = data.parts(); 0657 for (const Protocol::StreamPayloadResponse &part : parts) { 0658 ProtocolHelper::PartNamespace ns; 0659 const QByteArray plainKey = decodePartIdentifier(part.payloadName(), ns); 0660 const auto metaData = part.metaData(); 0661 switch (ns) { 0662 case ProtocolHelper::PartPayload: 0663 if (fetchScope && !fetchScope->fullPayload() && !fetchScope->payloadParts().contains(plainKey)) { 0664 continue; 0665 } 0666 ItemSerializer::deserialize(item, plainKey, part.data(), metaData.version(), static_cast<ItemSerializer::PayloadStorage>(metaData.storageType())); 0667 if (metaData.storageType() == Protocol::PartMetaData::Foreign) { 0668 item.d_ptr->mPayloadPath = QString::fromUtf8(part.data()); 0669 } 0670 break; 0671 case ProtocolHelper::PartAttribute: { 0672 if (fetchScope && !fetchScope->allAttributes() && !fetchScope->attributes().contains(plainKey)) { 0673 continue; 0674 } 0675 Attribute *attr = AttributeFactory::createAttribute(plainKey); 0676 Q_ASSERT(attr); 0677 if (metaData.storageType() == Protocol::PartMetaData::External) { 0678 const QString filename = ExternalPartStorage::resolveAbsolutePath(part.data()); 0679 QFile file(filename); 0680 if (file.open(QFile::ReadOnly)) { 0681 attr->deserialize(file.readAll()); 0682 } else { 0683 qCWarning(AKONADICORE_LOG) << "Failed to open attribute file: " << filename; 0684 delete attr; 0685 attr = nullptr; 0686 } 0687 } else { 0688 attr->deserialize(part.data()); 0689 } 0690 if (attr) { 0691 item.addAttribute(attr); 0692 } 0693 break; 0694 } 0695 case ProtocolHelper::PartGlobal: 0696 default: 0697 qCWarning(AKONADICORE_LOG) << "Unknown item part type:" << part.payloadName(); 0698 } 0699 } 0700 0701 item.d_ptr->resetChangeLog(); 0702 return item; 0703 } 0704 0705 Tag ProtocolHelper::parseTagFetchResult(const Protocol::FetchTagsResponse &data) 0706 { 0707 Tag tag; 0708 tag.setId(data.id()); 0709 tag.setGid(data.gid()); 0710 tag.setRemoteId(data.remoteId()); 0711 tag.setType(data.type()); 0712 tag.setParent(data.parentId() > 0 ? Tag(data.parentId()) : Tag()); 0713 0714 parseAttributes(data.attributes(), &tag); 0715 tag.d_ptr->resetChangeLog(); 0716 return tag; 0717 } 0718 0719 Relation ProtocolHelper::parseRelationFetchResult(const Protocol::FetchRelationsResponse &data) 0720 { 0721 Relation relation; 0722 relation.setLeft(Item(data.left())); 0723 relation.setRight(Item(data.right())); 0724 relation.setRemoteId(data.remoteId()); 0725 relation.setType(data.type()); 0726 return relation; 0727 } 0728 0729 bool ProtocolHelper::streamPayloadToFile(const QString &fileName, const QByteArray &data, QByteArray &error) 0730 { 0731 const QString filePath = ExternalPartStorage::resolveAbsolutePath(fileName); 0732 // qCDebug(AKONADICORE_LOG) << filePath << fileName; 0733 if (!filePath.startsWith(ExternalPartStorage::akonadiStoragePath())) { 0734 qCWarning(AKONADICORE_LOG) << "Invalid file path" << fileName; 0735 error = "Invalid file path"; 0736 return false; 0737 } 0738 QFile file(filePath); 0739 if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { 0740 qCWarning(AKONADICORE_LOG) << "Failed to open destination payload file" << file.errorString(); 0741 error = "Failed to store payload into file"; 0742 return false; 0743 } 0744 if (file.write(data) != data.size()) { 0745 qCWarning(AKONADICORE_LOG) << "Failed to write all payload data to file"; 0746 error = "Failed to store payload into file"; 0747 return false; 0748 } 0749 // qCDebug(AKONADICORE_LOG) << "Wrote" << data.size() << "bytes to " << file.fileName(); 0750 0751 // Make sure stuff is written to disk 0752 file.close(); 0753 return true; 0754 } 0755 0756 Akonadi::Tristate ProtocolHelper::listPreference(Collection::ListPreference pref) 0757 { 0758 switch (pref) { 0759 case Collection::ListEnabled: 0760 return Tristate::True; 0761 case Collection::ListDisabled: 0762 return Tristate::False; 0763 case Collection::ListDefault: 0764 return Tristate::Undefined; 0765 } 0766 0767 Q_ASSERT(false); 0768 return Tristate::Undefined; 0769 }