Akonadi

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

KDE's Doxygen guidelines are available online.