Akonadi

protocolhelper.cpp
1 /*
2  SPDX-FileCopyrightText: 2008 Volker Krause <[email protected]>
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 "itemserializerplugin.h"
16 #include "persistentsearchattribute.h"
17 #include "protocolhelper_p.h"
18 #include "servermanager.h"
19 #include "tag_p.h"
20 #include "tagfetchscope.h"
21 
22 #include "private/externalpartstorage_p.h"
23 #include "private/protocol_p.h"
24 
25 #include <shared/akranges.h>
26 
27 #include <QFile>
28 #include <QVarLengthArray>
29 
30 using namespace Akonadi;
31 using namespace AkRanges;
32 
33 CachePolicy ProtocolHelper::parseCachePolicy(const Protocol::CachePolicy &policy)
34 {
35  CachePolicy cp;
36  cp.setCacheTimeout(policy.cacheTimeout());
37  cp.setIntervalCheckTime(policy.checkInterval());
38  cp.setInheritFromParent(policy.inherit());
39  cp.setSyncOnDemand(policy.syncOnDemand());
40  cp.setLocalParts(policy.localParts());
41  return cp;
42 }
43 
44 Protocol::CachePolicy ProtocolHelper::cachePolicyToProtocol(const CachePolicy &policy)
45 {
46  Protocol::CachePolicy proto;
47  proto.setCacheTimeout(policy.cacheTimeout());
48  proto.setCheckInterval(policy.intervalCheckTime());
49  proto.setInherit(policy.inheritFromParent());
50  proto.setSyncOnDemand(policy.syncOnDemand());
51  proto.setLocalParts(policy.localParts());
52  return proto;
53 }
54 
55 template<typename T> inline static void parseAttributesImpl(const Protocol::Attributes &attributes, T *entity)
56 {
57  for (auto iter = attributes.cbegin(), end = attributes.cend(); iter != end; ++iter) {
58  Attribute *attribute = AttributeFactory::createAttribute(iter.key());
59  if (!attribute) {
60  qCWarning(AKONADICORE_LOG) << "Warning: unknown attribute" << iter.key();
61  continue;
62  }
63  attribute->deserialize(iter.value());
64  entity->addAttribute(attribute);
65  }
66 }
67 
68 template<typename T>
69 inline static void
70 parseAncestorsCachedImpl(const QVector<Protocol::Ancestor> &ancestors, T *entity, Collection::Id parentCollection, ProtocolHelperValuePool *pool)
71 {
72  if (!pool || parentCollection == -1) {
73  // if no pool or parent collection id is provided we can't cache anything, so continue as usual
74  ProtocolHelper::parseAncestors(ancestors, entity);
75  return;
76  }
77 
78  if (pool->ancestorCollections.contains(parentCollection)) {
79  // ancestor chain is cached already, so use the cached value
80  entity->setParentCollection(pool->ancestorCollections.value(parentCollection));
81  } else {
82  // not cached yet, parse the chain
83  ProtocolHelper::parseAncestors(ancestors, entity);
84  pool->ancestorCollections.insert(parentCollection, entity->parentCollection());
85  }
86 }
87 
88 template<typename T> inline 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 
99 void ProtocolHelper::parseAncestorsCached(const QVector<Protocol::Ancestor> &ancestors,
100  Item *item,
101  Collection::Id parentCollection,
102  ProtocolHelperValuePool *pool)
103 {
104  parseAncestorsCachedImpl(ancestors, item, parentCollection, pool);
105 }
106 
107 void ProtocolHelper::parseAncestorsCached(const QVector<Protocol::Ancestor> &ancestors,
108  Collection *collection,
109  Collection::Id parentCollection,
110  ProtocolHelperValuePool *pool)
111 {
112  parseAncestorsCachedImpl(ancestors, collection, parentCollection, pool);
113 }
114 
115 void ProtocolHelper::parseAncestors(const QVector<Protocol::Ancestor> &ancestors, Item *item)
116 {
117  Collection fakeCollection;
118  parseAncestors(ancestors, &fakeCollection);
119 
120  item->setParentCollection(fakeCollection.parentCollection());
121 }
122 
123 void ProtocolHelper::parseAncestors(const QVector<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 
143 static 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 
158 CollectionStatistics 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 
167 void ProtocolHelper::parseAttributes(const Protocol::Attributes &attributes, Item *item)
168 {
169  parseAttributesImpl(attributes, item);
170 }
171 
172 void ProtocolHelper::parseAttributes(const Protocol::Attributes &attributes, Collection *collection)
173 {
174  parseAttributesImpl(attributes, collection);
175 }
176 
177 void ProtocolHelper::parseAttributes(const Protocol::Attributes &attributes, Tag *tag)
178 {
179  parseAttributesImpl(attributes, tag);
180 }
181 
182 Protocol::Attributes ProtocolHelper::attributesToProtocol(const Item &item, bool ns)
183 {
184  return attributesToProtocolImpl(item, ns);
185 }
186 
187 Protocol::Attributes ProtocolHelper::attributesToProtocol(const Collection &collection, bool ns)
188 {
189  return attributesToProtocolImpl(collection, ns);
190 }
191 
192 Protocol::Attributes ProtocolHelper::attributesToProtocol(const Tag &tag, bool ns)
193 {
194  return attributesToProtocolImpl(tag, ns);
195 }
196 
197 Protocol::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 
207 Collection 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 
245 Tag 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 
258 QByteArray 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 
273 QByteArray 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 
287 Protocol::ScopeContext
288 ProtocolHelper::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 
310 Scope 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  QVector<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 + QVector<Scope::HRID>{Scope::HRID(0)});
326 }
327 
328 Scope ProtocolHelper::hierarchicalRidToScope(const Item &item)
329 {
330  return Scope(QVector<Scope::HRID>({Scope::HRID(item.id(), item.remoteId())}) + hierarchicalRidToScope(item.parentCollection()).hridChain());
331 }
332 
333 Protocol::ItemFetchScope ProtocolHelper::itemFetchScopeToProtocol(const ItemFetchScope &fetchScope)
334 {
335  Protocol::ItemFetchScope fs;
336  QVector<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()) {
353  fs.setAncestorDepth(Protocol::ItemFetchScope::ParentAncestor);
354  break;
355  case ItemFetchScope::All:
356  fs.setAncestorDepth(Protocol::ItemFetchScope::AllAncestors);
357  break;
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  fs.setFetch(Protocol::ItemFetchScope::Relations, fetchScope.fetchRelations());
377 
378  return fs;
379 }
380 
381 ItemFetchScope ProtocolHelper::parseItemFetchScope(const Protocol::ItemFetchScope &fetchScope)
382 {
383  ItemFetchScope ifs;
384  const auto parts = fetchScope.requestedParts();
385  for (const auto &part : parts) {
386  if (part.startsWith("PLD:")) {
387  ifs.fetchPayloadPart(part.mid(4), true);
388  } else if (part.startsWith("ATR:")) {
389  ifs.fetchAttribute(part.mid(4), true);
390  }
391  }
392 
393  if (fetchScope.fetch(Protocol::ItemFetchScope::FullPayload)) {
394  ifs.fetchFullPayload(true);
395  }
396  if (fetchScope.fetch(Protocol::ItemFetchScope::AllAttributes)) {
397  ifs.fetchAllAttributes(true);
398  }
399  if (fetchScope.fetch(Protocol::ItemFetchScope::CacheOnly)) {
400  ifs.setCacheOnly(true);
401  }
402  if (fetchScope.fetch(Protocol::ItemFetchScope::CheckCachedPayloadPartsOnly)) {
404  }
405  if (fetchScope.fetch(Protocol::ItemFetchScope::IgnoreErrors)) {
406  ifs.setIgnoreRetrievalErrors(true);
407  }
408  switch (fetchScope.ancestorDepth()) {
409  case Protocol::ItemFetchScope::ParentAncestor:
411  break;
412  case Protocol::ItemFetchScope::AllAncestors:
414  break;
415  default:
417  break;
418  }
419  if (fetchScope.changedSince().isValid()) {
420  ifs.setFetchChangedSince(fetchScope.changedSince());
421  }
422  if (fetchScope.fetch(Protocol::ItemFetchScope::RemoteID) || fetchScope.fetch(Protocol::ItemFetchScope::RemoteRevision)) {
424  }
425  if (fetchScope.fetch(Protocol::ItemFetchScope::GID)) {
426  ifs.setFetchGid(true);
427  }
428  if (fetchScope.fetch(Protocol::ItemFetchScope::Tags)) {
429  ifs.setFetchTags(true);
430  }
431  if (fetchScope.fetch(Protocol::ItemFetchScope::VirtReferences)) {
432  ifs.setFetchVirtualReferences(true);
433  }
434  if (fetchScope.fetch(Protocol::ItemFetchScope::MTime)) {
435  ifs.setFetchModificationTime(true);
436  }
437  if (fetchScope.fetch(Protocol::ItemFetchScope::Relations)) {
438  ifs.setFetchRelations(true);
439  }
440 
441  return ifs;
442 }
443 
444 Protocol::CollectionFetchScope ProtocolHelper::collectionFetchScopeToProtocol(const CollectionFetchScope &fetchScope)
445 {
446  Protocol::CollectionFetchScope cfs;
447  switch (fetchScope.listFilter()) {
449  cfs.setListFilter(Protocol::CollectionFetchScope::NoFilter);
450  break;
452  cfs.setListFilter(Protocol::CollectionFetchScope::Display);
453  break;
455  cfs.setListFilter(Protocol::CollectionFetchScope::Sync);
456  break;
458  cfs.setListFilter(Protocol::CollectionFetchScope::Index);
459  break;
461  cfs.setListFilter(Protocol::CollectionFetchScope::Enabled);
462  break;
463  }
464  cfs.setIncludeStatistics(fetchScope.includeStatistics());
465  cfs.setResource(fetchScope.resource());
466  cfs.setContentMimeTypes(fetchScope.contentMimeTypes());
467  cfs.setAttributes(fetchScope.attributes());
468  cfs.setFetchIdOnly(fetchScope.fetchIdOnly());
469  switch (fetchScope.ancestorRetrieval()) {
471  cfs.setAncestorRetrieval(Protocol::CollectionFetchScope::None);
472  break;
474  cfs.setAncestorRetrieval(Protocol::CollectionFetchScope::Parent);
475  break;
477  cfs.setAncestorRetrieval(Protocol::CollectionFetchScope::All);
478  break;
479  }
480  if (cfs.ancestorRetrieval() != Protocol::CollectionFetchScope::None) {
481  cfs.setAncestorAttributes(fetchScope.ancestorFetchScope().attributes());
482  cfs.setAncestorFetchIdOnly(fetchScope.ancestorFetchScope().fetchIdOnly());
483  }
484  cfs.setIgnoreRetrievalErrors(fetchScope.ignoreRetrievalErrors());
485 
486  return cfs;
487 }
488 
489 CollectionFetchScope ProtocolHelper::parseCollectionFetchScope(const Protocol::CollectionFetchScope &fetchScope)
490 {
492  switch (fetchScope.listFilter()) {
493  case Protocol::CollectionFetchScope::NoFilter:
495  break;
496  case Protocol::CollectionFetchScope::Display:
498  break;
499  case Protocol::CollectionFetchScope::Sync:
501  break;
502  case Protocol::CollectionFetchScope::Index:
504  break;
505  case Protocol::CollectionFetchScope::Enabled:
507  break;
508  }
509  cfs.setIncludeStatistics(fetchScope.includeStatistics());
510  cfs.setResource(fetchScope.resource());
511  cfs.setContentMimeTypes(fetchScope.contentMimeTypes());
512  switch (fetchScope.ancestorRetrieval()) {
513  case Protocol::CollectionFetchScope::None:
515  break;
516  case Protocol::CollectionFetchScope::Parent:
518  break;
519  case Protocol::CollectionFetchScope::All:
521  break;
522  }
524  cfs.ancestorFetchScope().setFetchIdOnly(fetchScope.ancestorFetchIdOnly());
525  const auto attrs = fetchScope.ancestorAttributes();
526  for (const auto &attr : attrs) {
527  cfs.ancestorFetchScope().fetchAttribute(attr, true);
528  }
529  }
530  const auto attrs = fetchScope.attributes();
531  for (const auto &attr : attrs) {
532  cfs.fetchAttribute(attr, true);
533  }
534  cfs.setFetchIdOnly(fetchScope.fetchIdOnly());
535  cfs.setIgnoreRetrievalErrors(fetchScope.ignoreRetrievalErrors());
536 
537  return cfs;
538 }
539 
540 Protocol::TagFetchScope ProtocolHelper::tagFetchScopeToProtocol(const TagFetchScope &fetchScope)
541 {
542  Protocol::TagFetchScope tfs;
543  tfs.setFetchIdOnly(fetchScope.fetchIdOnly());
544  tfs.setAttributes(fetchScope.attributes());
545  tfs.setFetchRemoteID(fetchScope.fetchRemoteId());
546  tfs.setFetchAllAttributes(fetchScope.fetchAllAttributes());
547  return tfs;
548 }
549 
550 TagFetchScope ProtocolHelper::parseTagFetchScope(const Protocol::TagFetchScope &fetchScope)
551 {
552  TagFetchScope tfs;
553  tfs.setFetchIdOnly(fetchScope.fetchIdOnly());
554  tfs.setFetchRemoteId(fetchScope.fetchRemoteID());
555  tfs.setFetchAllAttributes(fetchScope.fetchAllAttributes());
556  const auto attrs = fetchScope.attributes();
557  for (const auto &attr : attrs) {
558  tfs.fetchAttribute(attr, true);
559  }
560  return tfs;
561 }
562 
563 static Item::Flags convertFlags(const QVector<QByteArray> &flags, ProtocolHelperValuePool *valuePool)
564 {
565 #if __cplusplus >= 201103L || defined(__GNUC__) || defined(__clang__)
566  // When the compiler supports thread-safe static initialization (mandated by the C++11 memory model)
567  // then use it to share the common case of a single-item set only containing the \SEEN flag.
568  // NOTE: GCC and clang has threadsafe static initialization for some time now, even without C++11.
569  if (flags.size() == 1 && flags.first() == "\\SEEN") {
570  static const Item::Flags sharedSeen = Item::Flags() << QByteArray("\\SEEN");
571  return sharedSeen;
572  }
573 #endif
574 
575  Item::Flags convertedFlags;
576  convertedFlags.reserve(flags.size());
577  for (const QByteArray &flag : flags) {
578  if (valuePool) {
579  convertedFlags.insert(valuePool->flagPool.sharedValue(flag));
580  } else {
581  convertedFlags.insert(flag);
582  }
583  }
584  return convertedFlags;
585 }
586 
587 Item ProtocolHelper::parseItemFetchResult(const Protocol::FetchItemsResponse &data,
588  const Akonadi::ItemFetchScope *fetchScope,
589  ProtocolHelperValuePool *valuePool)
590 {
591  Item item;
592  item.setId(data.id());
593  item.setRevision(data.revision());
594  if (!fetchScope || fetchScope->fetchRemoteIdentification()) {
595  item.setRemoteId(data.remoteId());
596  item.setRemoteRevision(data.remoteRevision());
597  }
598  item.setGid(data.gid());
599  item.setStorageCollectionId(data.parentId());
600 
601  if (valuePool) {
602  item.setMimeType(valuePool->mimeTypePool.sharedValue(data.mimeType()));
603  } else {
604  item.setMimeType(data.mimeType());
605  }
606 
607  if (!item.isValid()) {
608  return Item();
609  }
610 
611  item.setFlags(convertFlags(data.flags(), valuePool));
612 
613  const auto fetchedTags = data.tags();
614  if ((!fetchScope || fetchScope->fetchTags()) && !fetchedTags.isEmpty()) {
615  Tag::List tags;
616  tags.reserve(fetchedTags.size());
617  for (const Protocol::FetchTagsResponse &tag : fetchedTags) {
618  tags.append(parseTagFetchResult(tag));
619  }
620  item.setTags(tags);
621  }
622 
623  const auto fetchedRelations = data.relations();
624  if ((!fetchScope || fetchScope->fetchRelations()) && !fetchedRelations.isEmpty()) {
625  Relation::List relations;
626  relations.reserve(fetchedRelations.size());
627  for (const Protocol::FetchRelationsResponse &rel : fetchedRelations) {
628  relations.append(parseRelationFetchResult(rel));
629  }
630  item.d_ptr->mRelations = relations;
631  }
632 
633  const auto virtualReferences = data.virtualReferences();
634  if ((!fetchScope || fetchScope->fetchVirtualReferences()) && !virtualReferences.isEmpty()) {
635  Collection::List virtRefs;
636  virtRefs.reserve(virtualReferences.size());
637  for (qint64 colId : virtualReferences) {
638  virtRefs.append(Collection(colId));
639  }
640  item.setVirtualReferences(virtRefs);
641  }
642 
643  const auto cachedParts = data.cachedParts();
644  if (!cachedParts.isEmpty()) {
645  QSet<QByteArray> cp;
646  cp.reserve(cachedParts.size());
647  for (const QByteArray &ba : cachedParts) {
648  cp.insert(ba);
649  }
650  item.setCachedPayloadParts(cp);
651  }
652 
653  item.setSize(data.size());
654  item.setModificationTime(data.mTime());
655  parseAncestorsCached(data.ancestors(), &item, data.parentId(), valuePool);
656  const auto parts = data.parts();
657  for (const Protocol::StreamPayloadResponse &part : parts) {
658  ProtocolHelper::PartNamespace ns;
659  const QByteArray plainKey = decodePartIdentifier(part.payloadName(), ns);
660  const auto metaData = part.metaData();
661  switch (ns) {
662  case ProtocolHelper::PartPayload:
663  if (fetchScope && !fetchScope->fullPayload() && !fetchScope->payloadParts().contains(plainKey)) {
664  continue;
665  }
666  ItemSerializer::deserialize(item, plainKey, part.data(), metaData.version(), static_cast<ItemSerializer::PayloadStorage>(metaData.storageType()));
667  if (metaData.storageType() == Protocol::PartMetaData::Foreign) {
668  item.d_ptr->mPayloadPath = QString::fromUtf8(part.data());
669  }
670  break;
671  case ProtocolHelper::PartAttribute: {
672  if (fetchScope && !fetchScope->allAttributes() && !fetchScope->attributes().contains(plainKey)) {
673  continue;
674  }
676  Q_ASSERT(attr);
677  if (metaData.storageType() == Protocol::PartMetaData::External) {
678  const QString filename = ExternalPartStorage::resolveAbsolutePath(part.data());
679  QFile file(filename);
680  if (file.open(QFile::ReadOnly)) {
681  attr->deserialize(file.readAll());
682  } else {
683  qCWarning(AKONADICORE_LOG) << "Failed to open attribute file: " << filename;
684  delete attr;
685  attr = nullptr;
686  }
687  } else {
688  attr->deserialize(part.data());
689  }
690  if (attr) {
691  item.addAttribute(attr);
692  }
693  break;
694  }
695  case ProtocolHelper::PartGlobal:
696  default:
697  qCWarning(AKONADICORE_LOG) << "Unknown item part type:" << part.payloadName();
698  }
699  }
700 
701  item.d_ptr->resetChangeLog();
702  return item;
703 }
704 
705 Tag ProtocolHelper::parseTagFetchResult(const Protocol::FetchTagsResponse &data)
706 {
707  Tag tag;
708  tag.setId(data.id());
709  tag.setGid(data.gid());
710  tag.setRemoteId(data.remoteId());
711  tag.setType(data.type());
712  tag.setParent(data.parentId() > 0 ? Tag(data.parentId()) : Tag());
713 
714  parseAttributes(data.attributes(), &tag);
715  tag.d_ptr->resetChangeLog();
716  return tag;
717 }
718 
719 Relation ProtocolHelper::parseRelationFetchResult(const Protocol::FetchRelationsResponse &data)
720 {
721  Relation relation;
722  relation.setLeft(Item(data.left()));
723  relation.setRight(Item(data.right()));
724  relation.setRemoteId(data.remoteId());
725  relation.setType(data.type());
726  return relation;
727 }
728 
729 bool ProtocolHelper::streamPayloadToFile(const QString &fileName, const QByteArray &data, QByteArray &error)
730 {
731  const QString filePath = ExternalPartStorage::resolveAbsolutePath(fileName);
732  // qCDebug(AKONADICORE_LOG) << filePath << fileName;
733  if (!filePath.startsWith(ExternalPartStorage::akonadiStoragePath())) {
734  qCWarning(AKONADICORE_LOG) << "Invalid file path" << fileName;
735  error = "Invalid file path";
736  return false;
737  }
738  QFile file(filePath);
739  if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
740  qCWarning(AKONADICORE_LOG) << "Failed to open destination payload file" << file.errorString();
741  error = "Failed to store payload into file";
742  return false;
743  }
744  if (file.write(data) != data.size()) {
745  qCWarning(AKONADICORE_LOG) << "Failed to write all payload data to file";
746  error = "Failed to store payload into file";
747  return false;
748  }
749  // qCDebug(AKONADICORE_LOG) << "Wrote" << data.size() << "bytes to " << file.fileName();
750 
751  // Make sure stuff is written to disk
752  file.close();
753  return true;
754 }
755 
756 Akonadi::Tristate ProtocolHelper::listPreference(Collection::ListPreference pref)
757 {
758  switch (pref) {
760  return Tristate::True;
762  return Tristate::False;
764  return Tristate::Undefined;
765  }
766 
767  Q_ASSERT(false);
768  return Tristate::Undefined;
769 }
bool isValid() const
Returns whether the item is valid.
Definition: item.cpp:88
bool ignoreRetrievalErrors() const
Returns whether retrieval errors should be ignored.
int cacheTimeout() const
Returns the cache timeout for non-permanently cached parts in minutes; -1 means indefinitely.
Definition: cachepolicy.cpp:75
Provides statistics information of a Collection.
@ Parent
Only retrieve the immediate parent collection.
@ Sync
Only retrieve collections for synchronization, taking the local preference and enabled into account.
void setSize(qint64 size)
Set the size of the item in bytes.
Definition: item.cpp:336
void setRevision(int revision)
Sets the revision number of the item.
Definition: item.cpp:316
QSet< QByteArray > Flags
Describes a set of flag names.
Definition: item.h:125
Specifies which parts of a tag should be fetched from the Akonadi storage.
Definition: tagfetchscope.h:22
bool cacheOnly() const
Returns whether payload data should be requested from remote sources or just from the local cache.
QString fromUtf8(const char *str, int size)
@ All
Retrieve all ancestors, up to Collection::root()
void setFetchIdOnly(bool fetchIdOnly)
Sets whether only the id or the complete tag should be fetched.
An Akonadi Tag.
Definition: tag.h:25
void fetchPayloadPart(const QByteArray &part, bool fetch=true)
Sets which payload parts shall be fetched.
void append(const T &value)
bool fetchModificationTime() const
Returns whether item modification time should be retrieved.
void reserve(int size)
void setCacheOnly(bool cacheOnly)
Sets whether payload data should be requested from remote sources or just from the local cache.
void setType(const QByteArray &type)
Sets the type of the relation.
Definition: relation.cpp:80
void setParentCollection(const Collection &parent)
Set the parent collection of this object.
Definition: item.cpp:170
Represents a collection of PIM items.
Definition: collection.h:61
@ Display
Only retrieve collections for display, taking the local preference and enabled into account.
void setStatistics(const CollectionStatistics &statistics)
Sets the collection statistics for the collection.
Definition: collection.cpp:331
bool fetchTags() const
Returns whether tags should be retrieved.
void setVirtualReferences(const Collection::List &collections)
Sets the virtual collections that this item is linked into.
Definition: item.cpp:362
bool fetchAllAttributes() const
Returns whether to fetch all attributes.
void setMimeType(const QString &mimeType)
Sets the mime type of the item to mimeType.
Definition: item.cpp:347
bool fetchIdOnly() const
Sets whether only the id of the tags should be retrieved or the complete tag.
QStringList contentMimeTypes() const
Returns the content mimetypes filter.
Provides interface for custom attributes for Entity.
Definition: attribute.h:124
An Akonadi Relation.
Definition: relation.h:39
@ NoFilter
No filtering, retrieve all collections.
void error(QWidget *parent, const QString &text, const QString &caption=QString(), Options options=Notify)
void fetchFullPayload(bool fetch=true)
Sets whether the full payload shall be fetched.
void setGid(const QString &gid)
Sets the gid of the entity.
Definition: item.cpp:352
AncestorRetrieval ancestorRetrieval() const
Returns the ancestor retrieval depth.
void setFetchRemoteId(bool fetchRemoteId)
Sets whether to fetch tag remote ID.
int intervalCheckTime() const
Returns the interval check time in minutes, -1 for never.
Definition: cachepolicy.cpp:85
T & first()
ListFilter listFilter() const
Returns the list filter.
Represents the caching policy for a collection.
Definition: cachepolicy.h:59
int size() const const
QVector< Item > List
Describes a list of items.
Definition: item.h:115
Attribute * attribute(const QByteArray &name)
Returns the attribute of the given type name if available, 0 otherwise.
Definition: collection.cpp:176
bool fetchRelations() const
Returns whether relations should be retrieved.
CollectionFetchScope ancestorFetchScope() const
Returns the fetch scope for ancestor retrieval.
void setInheritFromParent(bool inherit)
Sets whether the cache policy should be inherited from the parent collection.
Definition: cachepolicy.cpp:60
Specifies which parts of a collection should be fetched from the Akonadi storage.
bool ignoreRetrievalErrors() const
Returns whether retrieval errors should be ignored.
void setModificationTime(const QDateTime &datetime)
Sets the timestamp of the last modification of this item.
Definition: item.cpp:225
void setLocalListPreference(ListPurpose purpose, ListPreference preference)
Sets the local list preference for the specified purpose.
Definition: collection.cpp:368
void setListFilter(ListFilter)
Sets a filter for the collections to be listed.
void setQueryString(const QString &query)
Sets the query string to be used for this search.
bool checkForCachedPayloadPartsOnly() const
Returns whether payload data should be fetched or only checked for presence in the cache.
void setFetchModificationTime(bool retrieveMtime)
Enables retrieval of the item modification time.
void setRemoteId(const QByteArray &type)
Sets the remote id of the relation.
Definition: relation.cpp:90
void setFetchChangedSince(const QDateTime &changedSince)
Only fetch items that were added or modified after given timestamp.
void setIgnoreRetrievalErrors(bool enabled)
Ignore retrieval errors while fetching collections, and always deliver what is available.
@ ListEnabled
Enable collection for specified purpose.
Definition: collection.h:465
@ ListDisplay
Listing for display to the user.
Definition: collection.h:477
bool fetchIdOnly() const
Sets whether only the id of the tags should be retrieved or the complete tag.
@ ListDefault
Fallback to enabled state.
Definition: collection.h:467
bool includeStatistics() const
Returns whether collection statistics should be included in the retrieved results.
void setLeft(const Item &item)
Sets the item of the left side of the relation.
Definition: relation.cpp:60
QByteArray mid(int pos, int len) const const
bool isEmpty() const const
void setCachePolicy(const CachePolicy &policy)
Sets the cache policy of the collection.
Definition: collection.cpp:341
void setRemoteId(const QString &id)
Sets the remote id of the collection.
Definition: collection.cpp:101
void setResource(const QString &resource)
Sets a resource filter, that is only collections owned by the specified resource are retrieved.
@ Enabled
Only retrieve enabled collections, ignoring the local preference.
Base class for exceptions used by the Akonadi library.
Definition: exceptionbase.h:29
Collection parentCollection() const
Returns the parent collection of this object.
Definition: item.cpp:153
void setEnabled(bool enabled)
Sets the collection's enabled state.
Definition: collection.cpp:357
void setRemoteId(const QString &id)
Sets the remote id of the item.
Definition: item.cpp:68
bool startsWith(const QByteArray &ba) const const
QStringList localParts() const
Returns the parts to permanently cache locally.
Definition: cachepolicy.cpp:65
@ Index
Only retrieve collections for indexing, taking the local preference and enabled into account.
QString resource() const
Returns the resource identifier that is used as filter.
void setRight(const Akonadi::Item &item)
Sets the item of the right side of the relation.
Definition: relation.cpp:70
void setFetchTags(bool fetchTags)
Fetch tags for items.
An attribute to store query properties of persistent search collections.
bool syncOnDemand() const
Returns whether the collection will be synced automatically when necessary, i.e.
Definition: cachepolicy.cpp:95
void setContentMimeTypes(const QStringList &types)
Sets the list of possible content mime types.
Definition: collection.cpp:245
void setSyncOnDemand(bool enable)
Sets whether the collection shall be synced automatically when necessary, i.e.
void setCheckForCachedPayloadPartsOnly(bool check=true)
Sets whether payload will be fetched or there will be only a test performed if the requested payload ...
void setIncludeStatistics(bool include)
Sets whether collection statistics should be included in the retrieved results.
void reserve(int size)
static Collection root()
Returns the root collection.
Definition: collection.cpp:287
bool fetchVirtualReferences() const
Returns whether virtual references should be retrieved.
@ ListSync
Listing for synchronization.
Definition: collection.h:476
bool fetchRemoteId() const
Returns whether tag remote ID should be fetched.
bool contains(const T &value) const const
QString remoteId() const
Returns the remote id of the collection.
Definition: collection.cpp:106
QSet< QByteArray > attributes() const
Returns all explicitly fetched attributes.
Collection parentCollection() const
Returns the parent collection of this object.
Definition: collection.cpp:187
bool fetchRemoteIdentification() const
Returns whether item remote identification should be retrieved.
void setRemoteRevision(const QString &revision)
Sets the remote revision of the item.
Definition: item.cpp:78
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
bool fetchGid() const
Returns whether item GID should be retrieved.
QString label(StandardShortcut id)
void setCount(qint64 count)
Sets the number of items in this collection.
void setCacheTimeout(int timeout)
Sets cache timeout for non-permanently cached parts.
Definition: cachepolicy.cpp:80
@ All
Retrieve all ancestors, up to Collection::root()
QDateTime fetchChangedSince() const
Returns timestamp of the oldest item to fetch.
void setFetchVirtualReferences(bool fetchVRefs)
Returns whether to fetch list of virtual collections the item is linked to.
@ ListDisabled
Disable collection for specified purpose.
Definition: collection.h:466
void setFetchRelations(bool fetchRelations)
Fetch relations for items.
Id id() const
Returns the unique identifier of the item.
Definition: item.cpp:63
void setVirtual(bool isVirtual)
Sets whether the collection is virtual or not.
Definition: collection.cpp:352
@ None
No ancestor retrieval at all (the default)
void setIgnoreRetrievalErrors(bool enabled)
Ignore retrieval errors while fetching items, and always deliver what is available.
@ ListIndex
Listing for indexing the content.
Definition: collection.h:478
void setIntervalCheckTime(int time)
Sets interval check time.
Definition: cachepolicy.cpp:90
Id id() const
Returns the unique identifier of the tag.
Definition: tag.cpp:139
void setFetchGid(bool retrieveGID)
Enables retrieval of the item GID.
void setId(Id identifier)
Sets the unique identifier of the tag.
Definition: tag.cpp:134
void addAttribute(Attribute *attribute)
Adds an attribute to the item.
Definition: item.cpp:118
void fetchAttribute(const QByteArray &type, bool fetch=true)
Sets whether the attribute of the given type should be fetched.
bool inheritFromParent() const
Returns whether it inherits cache policy from the parent collection.
Definition: cachepolicy.cpp:55
void setAncestorRetrieval(AncestorRetrieval ancestorDepth)
Sets how many levels of ancestor collections should be included in the retrieval.
QSet< QByteArray > attributes() const
Returns all explicitly fetched attributes.
bool isValid() const const
void setUnreadCount(qint64 count)
Sets the number of unread items in this collection.
void setContentMimeTypes(const QStringList &mimeTypes)
Sets a content mimetypes filter, that is only collections that contain at least one of the given mime...
QSet::iterator insert(const T &value)
void fetchAttribute(const QByteArray &type, bool fetch=true)
Sets whether the attribute of the given type should be fetched.
static Attribute * createAttribute(const QByteArray &type)
Creates an entity attribute object of the given type.
bool fullPayload() const
Returns whether the full payload should be fetched.
int size() const const
@ AddIfMissing
Creates the attribute if it is missing.
Definition: collection.h:281
int size() const const
void setParentCollection(const Collection &parent)
Set the parent collection of this object.
Definition: collection.cpp:204
void setFetchAllAttributes(bool fetchAllAttributes)
Sets whether to fetch all attributes.
void setSize(qint64 size)
Sets the total size of the items in this collection.
void setAncestorRetrieval(AncestorRetrieval ancestorDepth)
Sets how many levels of ancestor collections should be included in the retrieval.
void setResource(const QString &identifier)
Sets the identifier of the resource owning the collection.
Definition: collection.cpp:307
@ None
No ancestor retrieval at all (the default)
void setFlags(const Flags &flags)
Overwrites all flags of the item by the given flags.
Definition: item.cpp:208
void fetchAttribute(const QByteArray &type, bool fetch=true)
Sets whether the attribute of the given type should be fetched.
bool allAttributes() const
Returns whether all available attributes should be fetched.
void setId(Id identifier)
Sets the unique identifier of the item.
Definition: item.cpp:58
void fetchAllAttributes(bool fetch=true)
Sets whether all available attributes should be fetched.
qint64 Id
Describes the unique id type.
Definition: collection.h:79
void setName(const QString &name)
Sets the i18n'ed name of the collection.
Definition: collection.cpp:221
virtual void deserialize(const QByteArray &data)=0
Sets the data of this attribute, using the same encoding as returned by toByteArray().
QSet< QByteArray > payloadParts() const
Returns the payload parts that should be fetched.
void setFetchIdOnly(bool fetchIdOnly)
Sets whether only the id or the complete tag should be fetched.
QString remoteId() const
Returns the remote id of the item.
Definition: item.cpp:73
void setRemoteRevision(const QString &revision)
Sets the remote revision of the collection.
Definition: collection.cpp:111
Represents a PIM item stored in Akonadi storage.
Definition: item.h:104
void setFetchRemoteIdentification(bool retrieveRid)
Fetch remote identification for items.
QSet< QByteArray > attributes() const
Returns all explicitly fetched attributes.
ListPreference
Describes the list preference value.
Definition: collection.h:464
Specifies which parts of an item should be fetched from the Akonadi storage.
AncestorRetrieval ancestorRetrieval() const
Returns the ancestor retrieval depth.
@ Parent
Only retrieve the immediate parent collection.
Helper integration between Akonadi and Qt.
void setLocalParts(const QStringList &parts)
Specifies the parts to permanently cache locally.
Definition: cachepolicy.cpp:70
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Sat Jun 25 2022 06:00:32 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.