Akonadi

protocolhelper.cpp
1/*
2 SPDX-FileCopyrightText: 2008 Volker Krause <vkrause@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "akonadicore_debug.h"
8#include "attributefactory.h"
9#include "collection_p.h"
10#include "collectionstatistics.h"
11#include "exceptionbase.h"
12#include "item_p.h"
13#include "itemfetchscope.h"
14#include "itemserializer_p.h"
15#include "persistentsearchattribute.h"
16#include "protocolhelper_p.h"
17#include "tag_p.h"
18#include "tagfetchscope.h"
19
20#include "private/externalpartstorage_p.h"
21#include "private/protocol_p.h"
22
23#include "shared/akranges.h"
24
25#include <QFile>
26#include <QVarLengthArray>
27
28using namespace Akonadi;
29using namespace AkRanges;
30
31CachePolicy ProtocolHelper::parseCachePolicy(const Protocol::CachePolicy &policy)
32{
33 CachePolicy cp;
34 cp.setCacheTimeout(policy.cacheTimeout());
35 cp.setIntervalCheckTime(policy.checkInterval());
36 cp.setInheritFromParent(policy.inherit());
37 cp.setSyncOnDemand(policy.syncOnDemand());
38 cp.setLocalParts(policy.localParts());
39 return cp;
40}
41
42Protocol::CachePolicy ProtocolHelper::cachePolicyToProtocol(const CachePolicy &policy)
43{
44 Protocol::CachePolicy proto;
45 proto.setCacheTimeout(policy.cacheTimeout());
46 proto.setCheckInterval(policy.intervalCheckTime());
47 proto.setInherit(policy.inheritFromParent());
48 proto.setSyncOnDemand(policy.syncOnDemand());
49 proto.setLocalParts(policy.localParts());
50 return proto;
51}
52
53template<typename T>
54inline static void parseAttributesImpl(const Protocol::Attributes &attributes, T *entity)
55{
56 for (auto iter = attributes.cbegin(), end = attributes.cend(); iter != end; ++iter) {
57 Attribute *attribute = AttributeFactory::createAttribute(iter.key());
58 if (!attribute) {
59 qCWarning(AKONADICORE_LOG) << "Warning: unknown attribute" << iter.key();
60 continue;
61 }
62 attribute->deserialize(iter.value());
63 entity->addAttribute(attribute);
64 }
65}
66
67template<typename T>
68inline static void
69parseAncestorsCachedImpl(const QList<Protocol::Ancestor> &ancestors, T *entity, Collection::Id parentCollection, ProtocolHelperValuePool *pool)
70{
71 if (!pool || parentCollection == -1) {
72 // if no pool or parent collection id is provided we can't cache anything, so continue as usual
73 ProtocolHelper::parseAncestors(ancestors, entity);
74 return;
75 }
76
77 if (pool->ancestorCollections.contains(parentCollection)) {
78 // ancestor chain is cached already, so use the cached value
79 entity->setParentCollection(pool->ancestorCollections.value(parentCollection));
80 } else {
81 // not cached yet, parse the chain
82 ProtocolHelper::parseAncestors(ancestors, entity);
83 pool->ancestorCollections.insert(parentCollection, entity->parentCollection());
84 }
85}
86
87template<typename T>
88inline static Protocol::Attributes attributesToProtocolImpl(const T &entity, bool ns)
89{
90 Protocol::Attributes attributes;
91 const auto attrs = entity.attributes();
92 for (const auto attr : attrs) {
93 attributes.insert(ProtocolHelper::encodePartIdentifier(ns ? ProtocolHelper::PartAttribute : ProtocolHelper::PartGlobal, attr->type()),
94 attr->serialized());
95 }
96 return attributes;
97}
98
99void ProtocolHelper::parseAncestorsCached(const QList<Protocol::Ancestor> &ancestors,
100 Item *item,
101 Collection::Id parentCollection,
102 ProtocolHelperValuePool *pool)
103{
104 parseAncestorsCachedImpl(ancestors, item, parentCollection, pool);
105}
106
107void ProtocolHelper::parseAncestorsCached(const QList<Protocol::Ancestor> &ancestors,
108 Collection *collection,
109 Collection::Id parentCollection,
110 ProtocolHelperValuePool *pool)
111{
112 parseAncestorsCachedImpl(ancestors, collection, parentCollection, pool);
113}
114
115void ProtocolHelper::parseAncestors(const QList<Protocol::Ancestor> &ancestors, Item *item)
116{
117 Collection fakeCollection;
118 parseAncestors(ancestors, &fakeCollection);
119
120 item->setParentCollection(fakeCollection.parentCollection());
121}
122
123void ProtocolHelper::parseAncestors(const QList<Protocol::Ancestor> &ancestors, Collection *collection)
124{
125 static const Collection::Id rootCollectionId = Collection::root().id();
126
127 Collection *current = collection;
128 for (const Protocol::Ancestor &ancestor : ancestors) {
129 if (ancestor.id() == rootCollectionId) {
131 break;
132 }
133
134 Akonadi::Collection parentCollection(ancestor.id());
135 parentCollection.setName(ancestor.name());
136 parentCollection.setRemoteId(ancestor.remoteId());
137 parseAttributesImpl(ancestor.attributes(), &parentCollection);
138 current->setParentCollection(parentCollection);
139 current = &current->parentCollection();
140 }
141}
142
143static Collection::ListPreference parsePreference(Tristate value)
144{
145 switch (value) {
146 case Tristate::True:
148 case Tristate::False:
150 case Tristate::Undefined:
152 }
153
154 Q_ASSERT(false);
156}
157
158CollectionStatistics ProtocolHelper::parseCollectionStatistics(const Protocol::FetchCollectionStatsResponse &stats)
159{
161 cs.setCount(stats.count());
162 cs.setSize(stats.size());
163 cs.setUnreadCount(stats.unseen());
164 return cs;
165}
166
167void ProtocolHelper::parseAttributes(const Protocol::Attributes &attributes, Item *item)
168{
169 parseAttributesImpl(attributes, item);
170}
171
172void ProtocolHelper::parseAttributes(const Protocol::Attributes &attributes, Collection *collection)
173{
174 parseAttributesImpl(attributes, collection);
175}
176
177void ProtocolHelper::parseAttributes(const Protocol::Attributes &attributes, Tag *tag)
178{
179 parseAttributesImpl(attributes, tag);
180}
181
182Protocol::Attributes ProtocolHelper::attributesToProtocol(const Item &item, bool ns)
183{
184 return attributesToProtocolImpl(item, ns);
185}
186
187Protocol::Attributes ProtocolHelper::attributesToProtocol(const Collection &collection, bool ns)
188{
189 return attributesToProtocolImpl(collection, ns);
190}
191
192Protocol::Attributes ProtocolHelper::attributesToProtocol(const Tag &tag, bool ns)
193{
194 return attributesToProtocolImpl(tag, ns);
195}
196
197Protocol::Attributes ProtocolHelper::attributesToProtocol(const std::vector<Attribute *> &modifiedAttributes, bool ns)
198{
199 Protocol::Attributes attributes;
200 for (const Attribute *attr : modifiedAttributes) {
201 attributes.insert(ProtocolHelper::encodePartIdentifier(ns ? ProtocolHelper::PartAttribute : ProtocolHelper::PartGlobal, attr->type()),
202 attr->serialized());
203 }
204 return attributes;
205}
206
207Collection ProtocolHelper::parseCollection(const Protocol::FetchCollectionsResponse &data, bool requireParent)
208{
209 Collection collection(data.id());
210
211 if (requireParent) {
212 collection.setParentCollection(Collection(data.parentId()));
213 }
214
215 collection.setName(data.name());
216 collection.setRemoteId(data.remoteId());
217 collection.setRemoteRevision(data.remoteRevision());
218 collection.setResource(data.resource());
219 collection.setContentMimeTypes(data.mimeTypes());
220 collection.setVirtual(data.isVirtual());
221 collection.setStatistics(parseCollectionStatistics(data.statistics()));
222 collection.setCachePolicy(parseCachePolicy(data.cachePolicy()));
223 parseAncestors(data.ancestors(), &collection);
224 collection.setEnabled(data.enabled());
225 collection.setLocalListPreference(Collection::ListDisplay, parsePreference(data.displayPref()));
226 collection.setLocalListPreference(Collection::ListIndex, parsePreference(data.indexPref()));
227 collection.setLocalListPreference(Collection::ListSync, parsePreference(data.syncPref()));
228
229 if (!data.searchQuery().isEmpty()) {
231 attr->setQueryString(data.searchQuery());
232 const auto cols = data.searchCollections() | Views::transform([](const auto id) {
233 return Collection{id};
234 })
235 | Actions::toQVector;
236 attr->setQueryCollections(cols);
237 }
238
239 parseAttributes(data.attributes(), &collection);
240
241 collection.d_ptr->resetChangeLog();
242 return collection;
243}
244
245Tag ProtocolHelper::parseTag(const Protocol::FetchTagsResponse &data)
246{
247 Tag tag(data.id());
248 tag.setRemoteId(data.remoteId());
249 tag.setGid(data.gid());
250 tag.setType(data.type());
251 tag.setParent(Tag(data.parentId()));
252 parseAttributes(data.attributes(), &tag);
253 tag.d_ptr->resetChangeLog();
254
255 return tag;
256}
257
258QByteArray ProtocolHelper::encodePartIdentifier(PartNamespace ns, const QByteArray &label)
259{
260 switch (ns) {
261 case PartGlobal:
262 return label;
263 case PartPayload:
264 return "PLD:" + label;
265 case PartAttribute:
266 return "ATR:" + label;
267 default:
268 Q_ASSERT(false);
269 }
270 return QByteArray();
271}
272
273QByteArray ProtocolHelper::decodePartIdentifier(const QByteArray &data, PartNamespace &ns)
274{
275 if (data.startsWith("PLD:")) { // krazy:exclude=strings
276 ns = PartPayload;
277 return data.mid(4);
278 } else if (data.startsWith("ATR:")) { // krazy:exclude=strings
279 ns = PartAttribute;
280 return data.mid(4);
281 } else {
282 ns = PartGlobal;
283 return data;
284 }
285}
286
287Protocol::ScopeContext
288ProtocolHelper::commandContextToProtocol(const Akonadi::Collection &collection, const Akonadi::Tag &tag, const Item::List &requestedItems)
289{
290 Protocol::ScopeContext ctx;
291 if (tag.isValid()) {
292 ctx.setContext(Protocol::ScopeContext::Tag, tag.id());
293 }
294
295 if (collection == Collection::root()) {
296 if (requestedItems.isEmpty() && !tag.isValid()) { // collection content listing
297 throw Exception("Cannot perform item operations on root collection.");
298 }
299 } else {
300 if (collection.isValid()) {
301 ctx.setContext(Protocol::ScopeContext::Collection, collection.id());
302 } else if (!collection.remoteId().isEmpty()) {
303 ctx.setContext(Protocol::ScopeContext::Collection, collection.remoteId());
304 }
305 }
306
307 return ctx;
308}
309
310Scope ProtocolHelper::hierarchicalRidToScope(const Collection &col)
311{
312 if (col == Collection::root()) {
313 return Scope({Scope::HRID(0)});
314 }
315 if (col.remoteId().isEmpty()) {
316 return Scope();
317 }
318
319 QList<Scope::HRID> chain;
320 Collection c = col;
321 while (!c.remoteId().isEmpty()) {
322 chain.append(Scope::HRID(c.id(), c.remoteId()));
323 c = c.parentCollection();
324 }
325 return Scope(chain + QList<Scope::HRID>{Scope::HRID(0)});
326}
327
328Scope ProtocolHelper::hierarchicalRidToScope(const Item &item)
329{
330 return Scope(QList<Scope::HRID>({Scope::HRID(item.id(), item.remoteId())}) + hierarchicalRidToScope(item.parentCollection()).hridChain());
331}
332
333Protocol::ItemFetchScope ProtocolHelper::itemFetchScopeToProtocol(const ItemFetchScope &fetchScope)
334{
335 Protocol::ItemFetchScope fs;
336 QList<QByteArray> parts;
337 parts.reserve(fetchScope.payloadParts().size() + fetchScope.attributes().size());
338 parts += fetchScope.payloadParts() | Views::transform(std::bind(encodePartIdentifier, PartPayload, std::placeholders::_1)) | Actions::toQVector;
339 parts += fetchScope.attributes() | Views::transform(std::bind(encodePartIdentifier, PartAttribute, std::placeholders::_1)) | Actions::toQVector;
340 fs.setRequestedParts(parts);
341
342 // The default scope
343 fs.setFetch(Protocol::ItemFetchScope::Flags | Protocol::ItemFetchScope::Size | Protocol::ItemFetchScope::RemoteID | Protocol::ItemFetchScope::RemoteRevision
344 | Protocol::ItemFetchScope::MTime);
345
346 fs.setFetch(Protocol::ItemFetchScope::FullPayload, fetchScope.fullPayload());
347 fs.setFetch(Protocol::ItemFetchScope::AllAttributes, fetchScope.allAttributes());
348 fs.setFetch(Protocol::ItemFetchScope::CacheOnly, fetchScope.cacheOnly());
349 fs.setFetch(Protocol::ItemFetchScope::CheckCachedPayloadPartsOnly, fetchScope.checkForCachedPayloadPartsOnly());
350 fs.setFetch(Protocol::ItemFetchScope::IgnoreErrors, fetchScope.ignoreRetrievalErrors());
351 switch (fetchScope.ancestorRetrieval()) {
352 case ItemFetchScope::Parent:
353 fs.setAncestorDepth(Protocol::ItemFetchScope::ParentAncestor);
354 break;
355 case ItemFetchScope::All:
356 fs.setAncestorDepth(Protocol::ItemFetchScope::AllAncestors);
357 break;
358 case ItemFetchScope::None:
359 fs.setAncestorDepth(Protocol::ItemFetchScope::NoAncestor);
360 break;
361 default:
362 Q_ASSERT(false);
363 break;
364 }
365
366 if (fetchScope.fetchChangedSince().isValid()) {
367 fs.setChangedSince(fetchScope.fetchChangedSince());
368 }
369
370 fs.setFetch(Protocol::ItemFetchScope::RemoteID, fetchScope.fetchRemoteIdentification());
371 fs.setFetch(Protocol::ItemFetchScope::RemoteRevision, fetchScope.fetchRemoteIdentification());
372 fs.setFetch(Protocol::ItemFetchScope::GID, fetchScope.fetchGid());
373 fs.setFetch(Protocol::ItemFetchScope::Tags, fetchScope.fetchTags());
374 fs.setFetch(Protocol::ItemFetchScope::VirtReferences, fetchScope.fetchVirtualReferences());
375 fs.setFetch(Protocol::ItemFetchScope::MTime, fetchScope.fetchModificationTime());
376
377 return fs;
378}
379
380ItemFetchScope ProtocolHelper::parseItemFetchScope(const Protocol::ItemFetchScope &fetchScope)
381{
382 ItemFetchScope ifs;
383 const auto parts = fetchScope.requestedParts();
384 for (const auto &part : parts) {
385 if (part.startsWith("PLD:")) {
386 ifs.fetchPayloadPart(part.mid(4), true);
387 } else if (part.startsWith("ATR:")) {
388 ifs.fetchAttribute(part.mid(4), true);
389 }
390 }
391
392 if (fetchScope.fetch(Protocol::ItemFetchScope::FullPayload)) {
393 ifs.fetchFullPayload(true);
394 }
395 if (fetchScope.fetch(Protocol::ItemFetchScope::AllAttributes)) {
396 ifs.fetchAllAttributes(true);
397 }
398 if (fetchScope.fetch(Protocol::ItemFetchScope::CacheOnly)) {
399 ifs.setCacheOnly(true);
400 }
401 if (fetchScope.fetch(Protocol::ItemFetchScope::CheckCachedPayloadPartsOnly)) {
403 }
404 if (fetchScope.fetch(Protocol::ItemFetchScope::IgnoreErrors)) {
405 ifs.setIgnoreRetrievalErrors(true);
406 }
407 switch (fetchScope.ancestorDepth()) {
408 case Protocol::ItemFetchScope::ParentAncestor:
409 ifs.setAncestorRetrieval(ItemFetchScope::Parent);
410 break;
411 case Protocol::ItemFetchScope::AllAncestors:
412 ifs.setAncestorRetrieval(ItemFetchScope::All);
413 break;
414 default:
415 ifs.setAncestorRetrieval(ItemFetchScope::None);
416 break;
417 }
418 if (fetchScope.changedSince().isValid()) {
419 ifs.setFetchChangedSince(fetchScope.changedSince());
420 }
421 if (fetchScope.fetch(Protocol::ItemFetchScope::RemoteID) || fetchScope.fetch(Protocol::ItemFetchScope::RemoteRevision)) {
423 }
424 if (fetchScope.fetch(Protocol::ItemFetchScope::GID)) {
425 ifs.setFetchGid(true);
426 }
427 if (fetchScope.fetch(Protocol::ItemFetchScope::Tags)) {
428 ifs.setFetchTags(true);
429 }
430 if (fetchScope.fetch(Protocol::ItemFetchScope::VirtReferences)) {
432 }
433 if (fetchScope.fetch(Protocol::ItemFetchScope::MTime)) {
434 ifs.setFetchModificationTime(true);
435 }
436
437 return ifs;
438}
439
440Protocol::CollectionFetchScope ProtocolHelper::collectionFetchScopeToProtocol(const CollectionFetchScope &fetchScope)
441{
442 Protocol::CollectionFetchScope cfs;
443 switch (fetchScope.listFilter()) {
444 case CollectionFetchScope::NoFilter:
445 cfs.setListFilter(Protocol::CollectionFetchScope::NoFilter);
446 break;
447 case CollectionFetchScope::Display:
448 cfs.setListFilter(Protocol::CollectionFetchScope::Display);
449 break;
450 case CollectionFetchScope::Sync:
451 cfs.setListFilter(Protocol::CollectionFetchScope::Sync);
452 break;
453 case CollectionFetchScope::Index:
454 cfs.setListFilter(Protocol::CollectionFetchScope::Index);
455 break;
456 case CollectionFetchScope::Enabled:
457 cfs.setListFilter(Protocol::CollectionFetchScope::Enabled);
458 break;
459 }
460 cfs.setIncludeStatistics(fetchScope.includeStatistics());
461 cfs.setResource(fetchScope.resource());
462 cfs.setContentMimeTypes(fetchScope.contentMimeTypes());
463 cfs.setAttributes(fetchScope.attributes());
464 cfs.setFetchIdOnly(fetchScope.fetchIdOnly());
465 switch (fetchScope.ancestorRetrieval()) {
466 case CollectionFetchScope::None:
467 cfs.setAncestorRetrieval(Protocol::CollectionFetchScope::None);
468 break;
469 case CollectionFetchScope::Parent:
470 cfs.setAncestorRetrieval(Protocol::CollectionFetchScope::Parent);
471 break;
472 case CollectionFetchScope::All:
473 cfs.setAncestorRetrieval(Protocol::CollectionFetchScope::All);
474 break;
475 }
476 if (cfs.ancestorRetrieval() != Protocol::CollectionFetchScope::None) {
477 cfs.setAncestorAttributes(fetchScope.ancestorFetchScope().attributes());
478 cfs.setAncestorFetchIdOnly(fetchScope.ancestorFetchScope().fetchIdOnly());
479 }
481
482 return cfs;
483}
484
485CollectionFetchScope ProtocolHelper::parseCollectionFetchScope(const Protocol::CollectionFetchScope &fetchScope)
486{
488 switch (fetchScope.listFilter()) {
489 case Protocol::CollectionFetchScope::NoFilter:
490 cfs.setListFilter(CollectionFetchScope::NoFilter);
491 break;
492 case Protocol::CollectionFetchScope::Display:
493 cfs.setListFilter(CollectionFetchScope::Display);
494 break;
495 case Protocol::CollectionFetchScope::Sync:
496 cfs.setListFilter(CollectionFetchScope::Sync);
497 break;
498 case Protocol::CollectionFetchScope::Index:
499 cfs.setListFilter(CollectionFetchScope::Index);
500 break;
501 case Protocol::CollectionFetchScope::Enabled:
502 cfs.setListFilter(CollectionFetchScope::Enabled);
503 break;
504 }
505 cfs.setIncludeStatistics(fetchScope.includeStatistics());
506 cfs.setResource(fetchScope.resource());
507 cfs.setContentMimeTypes(fetchScope.contentMimeTypes());
508 switch (fetchScope.ancestorRetrieval()) {
509 case Protocol::CollectionFetchScope::None:
510 cfs.setAncestorRetrieval(CollectionFetchScope::None);
511 break;
512 case Protocol::CollectionFetchScope::Parent:
513 cfs.setAncestorRetrieval(CollectionFetchScope::Parent);
514 break;
515 case Protocol::CollectionFetchScope::All:
516 cfs.setAncestorRetrieval(CollectionFetchScope::All);
517 break;
518 }
519 if (cfs.ancestorRetrieval() != CollectionFetchScope::None) {
520 cfs.ancestorFetchScope().setFetchIdOnly(fetchScope.ancestorFetchIdOnly());
521 const auto attrs = fetchScope.ancestorAttributes();
522 for (const auto &attr : attrs) {
523 cfs.ancestorFetchScope().fetchAttribute(attr, true);
524 }
525 }
526 const auto attrs = fetchScope.attributes();
527 for (const auto &attr : attrs) {
528 cfs.fetchAttribute(attr, true);
529 }
530 cfs.setFetchIdOnly(fetchScope.fetchIdOnly());
531 cfs.setIgnoreRetrievalErrors(fetchScope.ignoreRetrievalErrors());
532
533 return cfs;
534}
535
536Protocol::TagFetchScope ProtocolHelper::tagFetchScopeToProtocol(const TagFetchScope &fetchScope)
537{
538 Protocol::TagFetchScope tfs;
539 tfs.setFetchIdOnly(fetchScope.fetchIdOnly());
540 tfs.setAttributes(fetchScope.attributes());
541 tfs.setFetchRemoteID(fetchScope.fetchRemoteId());
542 tfs.setFetchAllAttributes(fetchScope.fetchAllAttributes());
543 return tfs;
544}
545
546TagFetchScope ProtocolHelper::parseTagFetchScope(const Protocol::TagFetchScope &fetchScope)
547{
548 TagFetchScope tfs;
549 tfs.setFetchIdOnly(fetchScope.fetchIdOnly());
550 tfs.setFetchRemoteId(fetchScope.fetchRemoteID());
551 tfs.setFetchAllAttributes(fetchScope.fetchAllAttributes());
552 const auto attrs = fetchScope.attributes();
553 for (const auto &attr : attrs) {
554 tfs.fetchAttribute(attr, true);
555 }
556 return tfs;
557}
558
559static Item::Flags convertFlags(const QList<QByteArray> &flags, ProtocolHelperValuePool *valuePool)
560{
561#if __cplusplus >= 201103L || defined(__GNUC__) || defined(__clang__)
562 // When the compiler supports thread-safe static initialization (mandated by the C++11 memory model)
563 // then use it to share the common case of a single-item set only containing the \SEEN flag.
564 // NOTE: GCC and clang has threadsafe static initialization for some time now, even without C++11.
565 if (flags.size() == 1 && flags.first() == "\\SEEN") {
566 static const Item::Flags sharedSeen = Item::Flags() << QByteArray("\\SEEN");
567 return sharedSeen;
568 }
569#endif
570
571 Item::Flags convertedFlags;
572 convertedFlags.reserve(flags.size());
573 for (const QByteArray &flag : flags) {
574 if (valuePool) {
575 convertedFlags.insert(valuePool->flagPool.sharedValue(flag));
576 } else {
577 convertedFlags.insert(flag);
578 }
579 }
580 return convertedFlags;
581}
582
583Item ProtocolHelper::parseItemFetchResult(const Protocol::FetchItemsResponse &data,
584 const Akonadi::ItemFetchScope *fetchScope,
585 ProtocolHelperValuePool *valuePool)
586{
587 Item item;
588 item.setId(data.id());
589 item.setRevision(data.revision());
590 if (!fetchScope || fetchScope->fetchRemoteIdentification()) {
591 item.setRemoteId(data.remoteId());
592 item.setRemoteRevision(data.remoteRevision());
593 }
594 item.setGid(data.gid());
595 item.setStorageCollectionId(data.parentId());
596
597 if (valuePool) {
598 item.setMimeType(valuePool->mimeTypePool.sharedValue(data.mimeType()));
599 } else {
600 item.setMimeType(data.mimeType());
601 }
602
603 if (!item.isValid()) {
604 return Item();
605 }
606
607 item.setFlags(convertFlags(data.flags(), valuePool));
608
609 const auto fetchedTags = data.tags();
610 if ((!fetchScope || fetchScope->fetchTags()) && !fetchedTags.isEmpty()) {
611 Tag::List tags;
612 tags.reserve(fetchedTags.size());
613 for (const Protocol::FetchTagsResponse &tag : fetchedTags) {
614 tags.append(parseTagFetchResult(tag));
615 }
616 item.setTags(tags);
617 }
618
619 const auto virtualReferences = data.virtualReferences();
620 if ((!fetchScope || fetchScope->fetchVirtualReferences()) && !virtualReferences.isEmpty()) {
621 Collection::List virtRefs;
622 virtRefs.reserve(virtualReferences.size());
623 for (qint64 colId : virtualReferences) {
624 virtRefs.append(Collection(colId));
625 }
626 item.setVirtualReferences(virtRefs);
627 }
628
629 const auto cachedParts = data.cachedParts();
630 if (!cachedParts.isEmpty()) {
632 cp.reserve(cachedParts.size());
633 for (const QByteArray &ba : cachedParts) {
634 cp.insert(ba);
635 }
636 item.setCachedPayloadParts(cp);
637 }
638
639 item.setSize(data.size());
640 item.setModificationTime(data.mTime());
641 parseAncestorsCached(data.ancestors(), &item, data.parentId(), valuePool);
642 const auto parts = data.parts();
643 for (const Protocol::StreamPayloadResponse &part : parts) {
644 ProtocolHelper::PartNamespace ns;
645 const QByteArray plainKey = decodePartIdentifier(part.payloadName(), ns);
646 const auto metaData = part.metaData();
647 switch (ns) {
648 case ProtocolHelper::PartPayload:
649 if (fetchScope && !fetchScope->fullPayload() && !fetchScope->payloadParts().contains(plainKey)) {
650 continue;
651 }
652 ItemSerializer::deserialize(item, plainKey, part.data(), metaData.version(), static_cast<ItemSerializer::PayloadStorage>(metaData.storageType()));
653 if (metaData.storageType() == Protocol::PartMetaData::Foreign) {
654 item.d_ptr->mPayloadPath = QString::fromUtf8(part.data());
655 }
656 break;
657 case ProtocolHelper::PartAttribute: {
658 if (fetchScope && !fetchScope->allAttributes() && !fetchScope->attributes().contains(plainKey)) {
659 continue;
660 }
662 Q_ASSERT(attr);
663 if (metaData.storageType() == Protocol::PartMetaData::External) {
664 const QString filename = ExternalPartStorage::resolveAbsolutePath(part.data());
665 QFile file(filename);
666 if (file.open(QFile::ReadOnly)) {
667 attr->deserialize(file.readAll());
668 } else {
669 qCWarning(AKONADICORE_LOG) << "Failed to open attribute file: " << filename;
670 delete attr;
671 attr = nullptr;
672 }
673 } else {
674 attr->deserialize(part.data());
675 }
676 if (attr) {
677 item.addAttribute(attr);
678 }
679 break;
680 }
681 case ProtocolHelper::PartGlobal:
682 default:
683 qCWarning(AKONADICORE_LOG) << "Unknown item part type:" << part.payloadName();
684 }
685 }
686
687 item.d_ptr->resetChangeLog();
688 return item;
689}
690
691Tag ProtocolHelper::parseTagFetchResult(const Protocol::FetchTagsResponse &data)
692{
693 Tag tag;
694 tag.setId(data.id());
695 tag.setGid(data.gid());
696 tag.setRemoteId(data.remoteId());
697 tag.setType(data.type());
698 tag.setParent(data.parentId() > 0 ? Tag(data.parentId()) : Tag());
699
700 parseAttributes(data.attributes(), &tag);
701 tag.d_ptr->resetChangeLog();
702 return tag;
703}
704
705bool ProtocolHelper::streamPayloadToFile(const QString &fileName, const QByteArray &data, QByteArray &error)
706{
707 const QString filePath = ExternalPartStorage::resolveAbsolutePath(fileName);
708 // qCDebug(AKONADICORE_LOG) << filePath << fileName;
709 if (!filePath.startsWith(ExternalPartStorage::akonadiStoragePath())) {
710 qCWarning(AKONADICORE_LOG) << "Invalid file path" << fileName;
711 error = "Invalid file path";
712 return false;
713 }
714 QFile file(filePath);
715 if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
716 qCWarning(AKONADICORE_LOG) << "Failed to open destination payload file" << file.errorString();
717 error = "Failed to store payload into file";
718 return false;
719 }
720 if (file.write(data) != data.size()) {
721 qCWarning(AKONADICORE_LOG) << "Failed to write all payload data to file";
722 error = "Failed to store payload into file";
723 return false;
724 }
725 // qCDebug(AKONADICORE_LOG) << "Wrote" << data.size() << "bytes to " << file.fileName();
726
727 // Make sure stuff is written to disk
728 file.close();
729 return true;
730}
731
732Akonadi::Tristate ProtocolHelper::listPreference(Collection::ListPreference pref)
733{
734 switch (pref) {
736 return Tristate::True;
738 return Tristate::False;
740 return Tristate::Undefined;
741 }
742
743 Q_ASSERT(false);
744 return Tristate::Undefined;
745}
static Attribute * createAttribute(const QByteArray &type)
Creates an entity attribute object of the given type.
Provides interface for custom attributes for Entity.
Definition attribute.h:132
virtual void deserialize(const QByteArray &data)=0
Sets the data of this attribute, using the same encoding as returned by toByteArray().
Represents the caching policy for a collection.
Definition cachepolicy.h:60
int cacheTimeout() const
Returns the cache timeout for non-permanently cached parts in minutes; -1 means indefinitely.
bool inheritFromParent() const
Returns whether it inherits cache policy from the parent collection.
int intervalCheckTime() const
Returns the interval check time in minutes, -1 for never.
void setLocalParts(const QStringList &parts)
Specifies the parts to permanently cache locally.
QStringList localParts() const
Returns the parts to permanently cache locally.
bool syncOnDemand() const
Returns whether the collection will be synced automatically when necessary, i.e.
void setIntervalCheckTime(int time)
Sets interval check time.
void setCacheTimeout(int timeout)
Sets cache timeout for non-permanently cached parts.
void setInheritFromParent(bool inherit)
Sets whether the cache policy should be inherited from the parent collection.
void setSyncOnDemand(bool enable)
Sets whether the collection shall be synced automatically when necessary, i.e.
Specifies which parts of a collection should be fetched from the Akonadi storage.
QSet< QByteArray > attributes() const
Returns all explicitly fetched attributes.
void setIncludeStatistics(bool include)
Sets whether collection statistics should be included in the retrieved results.
void setResource(const QString &resource)
Sets a resource filter, that is only collections owned by the specified resource are retrieved.
ListFilter listFilter() const
Returns the list filter.
void setIgnoreRetrievalErrors(bool enabled)
Ignore retrieval errors while fetching collections, and always deliver what is available.
void fetchAttribute(const QByteArray &type, bool fetch=true)
Sets whether the attribute of the given type should be fetched.
void setFetchIdOnly(bool fetchIdOnly)
Sets whether only the id or the complete tag should be fetched.
void setContentMimeTypes(const QStringList &mimeTypes)
Sets a content mimetypes filter, that is only collections that contain at least one of the given mime...
CollectionFetchScope ancestorFetchScope() const
Returns the fetch scope for ancestor retrieval.
QStringList contentMimeTypes() const
Returns the content mimetypes filter.
void setAncestorRetrieval(AncestorRetrieval ancestorDepth)
Sets how many levels of ancestor collections should be included in the retrieval.
bool includeStatistics() const
Returns whether collection statistics should be included in the retrieved results.
QString resource() const
Returns the resource identifier that is used as filter.
bool ignoreRetrievalErrors() const
Returns whether retrieval errors should be ignored.
void setListFilter(ListFilter)
Sets a filter for the collections to be listed.
AncestorRetrieval ancestorRetrieval() const
Returns the ancestor retrieval depth.
bool fetchIdOnly() const
Sets whether only the id of the tags should be retrieved or the complete tag.
Provides statistics information of a Collection.
void setUnreadCount(qint64 count)
Sets the number of unread items in this collection.
void setSize(qint64 size)
Sets the total size of the items in this collection.
void setCount(qint64 count)
Sets the number of items in this collection.
Represents a collection of PIM items.
Definition collection.h:62
void setVirtual(bool isVirtual)
Sets whether the collection is virtual or not.
qint64 Id
Describes the unique id type.
Definition collection.h:79
void setParentCollection(const Collection &parent)
Set the parent collection of this object.
void setLocalListPreference(ListPurpose purpose, ListPreference preference)
Sets the local list preference for the specified purpose.
@ ListSync
Listing for synchronization.
Definition collection.h:480
@ ListIndex
Listing for indexing the content.
Definition collection.h:482
@ ListDisplay
Listing for display to the user.
Definition collection.h:481
static Collection root()
Returns the root collection.
void setName(const QString &name)
Sets the i18n'ed name of the collection.
@ AddIfMissing
Creates the attribute if it is missing.
Definition collection.h:281
void setRemoteId(const QString &id)
Sets the remote id of the collection.
void setResource(const QString &identifier)
Sets the identifier of the resource owning the collection.
void setEnabled(bool enabled)
Sets the collection's enabled state.
void setCachePolicy(const CachePolicy &policy)
Sets the cache policy of the collection.
Collection parentCollection() const
Returns the parent collection of this object.
void setContentMimeTypes(const QStringList &types)
Sets the list of possible content mime types.
void setStatistics(const CollectionStatistics &statistics)
Sets the collection statistics for the collection.
Attribute * attribute(const QByteArray &name)
Returns the attribute of the given type name if available, 0 otherwise.
void setRemoteRevision(const QString &revision)
Sets the remote revision of the collection.
QString remoteId() const
Returns the remote id of the collection.
ListPreference
Describes the list preference value.
Definition collection.h:468
@ ListDefault
Fallback to enabled state.
Definition collection.h:471
@ ListDisabled
Disable collection for specified purpose.
Definition collection.h:470
@ ListEnabled
Enable collection for specified purpose.
Definition collection.h:469
Base class for exceptions used by the Akonadi library.
Specifies which parts of an item should be fetched from the Akonadi storage.
bool fetchVirtualReferences() const
Returns whether virtual references should be retrieved.
void setFetchTags(bool fetchTags)
Fetch tags for items.
void setFetchRemoteIdentification(bool retrieveRid)
Fetch remote identification for items.
bool allAttributes() const
Returns whether all available attributes should be fetched.
void setCacheOnly(bool cacheOnly)
Sets whether payload data should be requested from remote sources or just from the local cache.
bool fetchRemoteIdentification() const
Returns whether item remote identification should be retrieved.
bool fullPayload() const
Returns whether the full payload should be fetched.
void fetchAttribute(const QByteArray &type, bool fetch=true)
Sets whether the attribute of the given type should be fetched.
void setAncestorRetrieval(AncestorRetrieval ancestorDepth)
Sets how many levels of ancestor collections should be included in the retrieval.
bool fetchTags() const
Returns whether tags should be retrieved.
bool cacheOnly() const
Returns whether payload data should be requested from remote sources or just from the local cache.
QDateTime fetchChangedSince() const
Returns timestamp of the oldest item to fetch.
bool fetchModificationTime() const
Returns whether item modification time should be retrieved.
void setFetchGid(bool retrieveGID)
Enables retrieval of the item GID.
bool checkForCachedPayloadPartsOnly() const
Returns whether payload data should be fetched or only checked for presence in the cache.
void fetchAllAttributes(bool fetch=true)
Sets whether all available attributes should be fetched.
QSet< QByteArray > attributes() const
Returns all explicitly fetched attributes.
bool ignoreRetrievalErrors() const
Returns whether retrieval errors should be ignored.
QSet< QByteArray > payloadParts() const
Returns the payload parts that should be fetched.
void setFetchModificationTime(bool retrieveMtime)
Enables retrieval of the item modification time.
bool fetchGid() const
Returns whether item GID should be retrieved.
AncestorRetrieval ancestorRetrieval() const
Returns the ancestor retrieval depth.
void setCheckForCachedPayloadPartsOnly(bool check=true)
Sets whether payload will be fetched or there will be only a test performed if the requested payload ...
void setFetchVirtualReferences(bool fetchVRefs)
Returns whether to fetch list of virtual collections the item is linked to.
void setFetchChangedSince(const QDateTime &changedSince)
Only fetch items that were added or modified after given timestamp.
void fetchFullPayload(bool fetch=true)
Sets whether the full payload shall be fetched.
void fetchPayloadPart(const QByteArray &part, bool fetch=true)
Sets which payload parts shall be fetched.
void setIgnoreRetrievalErrors(bool enabled)
Ignore retrieval errors while fetching items, and always deliver what is available.
An attribute to store query properties of persistent search collections.
void setQueryString(const QString &query)
Sets the query string to be used for this search.
Specifies which parts of a tag should be fetched from the Akonadi storage.
void setFetchRemoteId(bool fetchRemoteId)
Sets whether to fetch tag remote ID.
void setFetchAllAttributes(bool fetchAllAttributes)
Sets whether to fetch all attributes.
void fetchAttribute(const QByteArray &type, bool fetch=true)
Sets whether the attribute of the given type should be fetched.
bool fetchIdOnly() const
Sets whether only the id of the tags should be retrieved or the complete tag.
bool fetchAllAttributes() const
Returns whether to fetch all attributes.
void setFetchIdOnly(bool fetchIdOnly)
Sets whether only the id or the complete tag should be fetched.
QSet< QByteArray > attributes() const
Returns all explicitly fetched attributes.
bool fetchRemoteId() const
Returns whether tag remote ID should be fetched.
An Akonadi Tag.
Definition tag.h:26
Id id() const
Returns the unique identifier of the tag.
Definition tag.cpp:139
void setId(Id identifier)
Sets the unique identifier of the tag.
Definition tag.cpp:134
Helper integration between Akonadi and Qt.
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
QString label(StandardShortcut id)
QByteArray mid(qsizetype pos, qsizetype len) const const
qsizetype size() const const
bool startsWith(QByteArrayView bv) const const
bool isValid() const const
void append(QList< T > &&value)
T & first()
bool isEmpty() const const
void reserve(qsizetype size)
qsizetype size() const const
void setFlags(Flags flags)
void setSize(const QSizeF &size)
bool contains(const QSet< T > &other) const const
iterator insert(const T &value)
void reserve(qsizetype size)
qsizetype size() const const
QString fromUtf8(QByteArrayView str)
bool isEmpty() const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 4 2024 16:31:58 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.