Akonadi

changerecorderjournal.cpp
1 /*
2  SPDX-FileCopyrightText: 2007 Volker Krause <[email protected]>
3  SPDX-FileCopyrightText: 2018 Daniel Vr├ítil <[email protected]>
4 
5  SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7 
8 #include "akonadicore_debug.h"
9 #include "changerecorderjournal_p.h"
10 
11 #include <QDataStream>
12 #include <QFile>
13 #include <QQueue>
14 #include <QSettings>
15 
16 using namespace Akonadi;
17 
18 namespace
19 {
20 constexpr quint64 s_currentVersion = Q_UINT64_C(0x000800000000);
21 constexpr quint64 s_versionMask = Q_UINT64_C(0xFFFF00000000);
22 constexpr quint64 s_sizeMask = Q_UINT64_C(0x0000FFFFFFFF);
23 }
24 
25 Protocol::ChangeNotificationPtr ChangeRecorderJournalReader::loadQSettingsNotification(QSettings *settings)
26 {
27  switch (static_cast<LegacyType>(settings->value(QStringLiteral("type")).toInt())) {
28  case Item:
29  return loadQSettingsItemNotification(settings);
30  case Collection:
31  return loadQSettingsCollectionNotification(settings);
32  case Tag:
33  case Relation:
34  case InvalidType:
35  default:
36  qWarning() << "Unexpected notification type in legacy store";
37  return {};
38  }
39 }
40 
41 QQueue<Protocol::ChangeNotificationPtr> ChangeRecorderJournalReader::loadFrom(QFile *device, bool &needsFullSave)
42 {
43  QDataStream stream(device);
44  stream.setVersion(QDataStream::Qt_4_6);
45 
46  QByteArray sessionId;
47  int type;
48 
50 
51  quint64 sizeAndVersion;
52  stream >> sizeAndVersion;
53 
54  const quint64 size = sizeAndVersion & s_sizeMask;
55  const quint64 version = (sizeAndVersion & s_versionMask) >> 32;
56 
57  quint64 startOffset = 0;
58  if (version >= 1) {
59  stream >> startOffset;
60  }
61 
62  // If we skip the first N items, then we'll need to rewrite the file on saving.
63  // Also, if the file is old, it needs to be rewritten.
64  needsFullSave = startOffset > 0 || version == 0;
65 
66  for (quint64 i = 0; i < size && !stream.atEnd(); ++i) {
68  stream >> sessionId;
69  stream >> type;
70 
71  if (stream.status() != QDataStream::Ok) {
72  qCWarning(AKONADICORE_LOG) << "Error reading saved notifications! Aborting. Corrupt file:" << device->fileName();
73  break;
74  }
75 
76  switch (static_cast<LegacyType>(type)) {
77  case Item:
78  msg = loadItemNotification(stream, version);
79  break;
80  case Collection:
81  msg = loadCollectionNotification(stream, version);
82  break;
83  case Tag:
84  msg = loadTagNotification(stream, version);
85  break;
86  case Relation:
87  msg = loadRelationNotification(stream, version);
88  break;
89  default:
90  qCWarning(AKONADICORE_LOG) << "Unknown notification type";
91  break;
92  }
93 
94  if (i < startOffset) {
95  continue;
96  }
97 
98  if (msg && msg->isValid()) {
99  msg->setSessionId(sessionId);
100  list << msg;
101  }
102  }
103 
104  return list;
105 }
106 
107 void ChangeRecorderJournalWriter::saveTo(const QQueue<Protocol::ChangeNotificationPtr> &notifications, QIODevice *device)
108 {
109  // Version 0 of this file format was writing a quint64 count, followed by the notifications.
110  // Version 1 bundles a version number into that quint64, to be able to detect a version number at load time.
111 
112  const quint64 countAndVersion = static_cast<quint64>(notifications.count()) | s_currentVersion;
113 
114  QDataStream stream(device);
115  stream.setVersion(QDataStream::Qt_4_6);
116 
117  stream << countAndVersion;
118  stream << quint64(0); // no start offset
119 
120  // qCDebug(AKONADICORE_LOG) << "Saving" << pendingNotifications.count() << "notifications (full save)";
121 
122  for (int i = 0; i < notifications.count(); ++i) {
123  const Protocol::ChangeNotificationPtr &msg = notifications.at(i);
124 
125  // We deliberately don't use Factory::serialize(), because the internal
126  // serialization format could change at any point
127 
128  stream << msg->sessionId();
129  stream << int(mapToLegacyType(msg->type()));
130  switch (msg->type()) {
131  case Protocol::Command::ItemChangeNotification:
132  saveItemNotification(stream, Protocol::cmdCast<Protocol::ItemChangeNotification>(msg));
133  break;
134  case Protocol::Command::CollectionChangeNotification:
135  saveCollectionNotification(stream, Protocol::cmdCast<Protocol::CollectionChangeNotification>(msg));
136  break;
137  case Protocol::Command::TagChangeNotification:
138  saveTagNotification(stream, Protocol::cmdCast<Protocol::TagChangeNotification>(msg));
139  break;
140  case Protocol::Command::RelationChangeNotification:
141  saveRelationNotification(stream, Protocol::cmdCast<Protocol::RelationChangeNotification>(msg));
142  break;
143  default:
144  qCWarning(AKONADICORE_LOG) << "Unexpected type?";
145  return;
146  }
147  }
148 }
149 
150 Protocol::ChangeNotificationPtr ChangeRecorderJournalReader::loadQSettingsItemNotification(QSettings *settings)
151 {
152  auto msg = Protocol::ItemChangeNotificationPtr::create();
153  msg->setSessionId(settings->value(QStringLiteral("sessionId")).toByteArray());
154  msg->setOperation(mapItemOperation(static_cast<LegacyOp>(settings->value(QStringLiteral("op")).toInt())));
155  Protocol::FetchItemsResponse item;
156  item.setId(settings->value(QStringLiteral("uid")).toLongLong());
157  item.setRemoteId(settings->value(QStringLiteral("rid")).toString());
158  item.setMimeType(settings->value(QStringLiteral("mimeType")).toString());
159  msg->setItems({std::move(item)});
160  msg->addMetadata("FETCH_ITEM");
161  msg->setResource(settings->value(QStringLiteral("resource")).toByteArray());
162  msg->setParentCollection(settings->value(QStringLiteral("parentCol")).toLongLong());
163  msg->setParentDestCollection(settings->value(QStringLiteral("parentDestCol")).toLongLong());
164  const QStringList list = settings->value(QStringLiteral("itemParts")).toStringList();
165  QSet<QByteArray> itemParts;
166  for (const QString &entry : list) {
167  itemParts.insert(entry.toLatin1());
168  }
169  msg->setItemParts(itemParts);
170  return msg;
171 }
172 
173 Protocol::ChangeNotificationPtr ChangeRecorderJournalReader::loadQSettingsCollectionNotification(QSettings *settings)
174 {
175  auto msg = Protocol::CollectionChangeNotificationPtr::create();
176  msg->setSessionId(settings->value(QStringLiteral("sessionId")).toByteArray());
177  msg->setOperation(mapCollectionOperation(static_cast<LegacyOp>(settings->value(QStringLiteral("op")).toInt())));
178  Protocol::FetchCollectionsResponse collection;
179  collection.setId(settings->value(QStringLiteral("uid")).toLongLong());
180  collection.setRemoteId(settings->value(QStringLiteral("rid")).toString());
181  msg->setCollection(std::move(collection));
182  msg->addMetadata("FETCH_COLLECTION");
183  msg->setResource(settings->value(QStringLiteral("resource")).toByteArray());
184  msg->setParentCollection(settings->value(QStringLiteral("parentCol")).toLongLong());
185  msg->setParentDestCollection(settings->value(QStringLiteral("parentDestCol")).toLongLong());
186  const QStringList list = settings->value(QStringLiteral("itemParts")).toStringList();
187  QSet<QByteArray> changedParts;
188  for (const QString &entry : list) {
189  changedParts.insert(entry.toLatin1());
190  }
191  msg->setChangedParts(changedParts);
192  return msg;
193 }
194 
195 QSet<Protocol::ItemChangeNotification::Relation> ChangeRecorderJournalReader::extractRelations(QSet<QByteArray> &flags)
196 {
198  auto iter = flags.begin();
199  while (iter != flags.end()) {
200  if (iter->startsWith("RELATION")) {
201  const QByteArrayList parts = iter->split(' ');
202  Q_ASSERT(parts.size() == 4);
203  Protocol::ItemChangeNotification::Relation relation;
204  relation.type = QString::fromLatin1(parts[1]);
205  relation.leftId = parts[2].toLongLong();
206  relation.rightId = parts[3].toLongLong();
207  relations.insert(relation);
208  iter = flags.erase(iter);
209  } else {
210  ++iter;
211  }
212  }
213 
214  return relations;
215 }
216 
217 Protocol::ChangeNotificationPtr ChangeRecorderJournalReader::loadItemNotification(QDataStream &stream, quint64 version)
218 {
219  QByteArray resource;
220  QByteArray destinationResource;
221  int operation;
222  int entityCnt;
223  qint64 uid;
224  qint64 parentCollection;
225  qint64 parentDestCollection;
226  QString remoteId;
228  QString remoteRevision;
229  QSet<QByteArray> itemParts;
230  QSet<QByteArray> addedFlags;
231  QSet<QByteArray> removedFlags;
232  QSet<qint64> addedTags;
233  QSet<qint64> removedTags;
235 
236  auto msg = Protocol::ItemChangeNotificationPtr::create();
237 
238  if (version == 1) {
239  stream >> operation;
240  stream >> uid;
241  stream >> remoteId;
242  stream >> resource;
243  stream >> parentCollection;
244  stream >> parentDestCollection;
245  stream >> mimeType;
246  stream >> itemParts;
247 
248  Protocol::FetchItemsResponse item;
249  item.setId(uid);
250  item.setRemoteId(remoteId);
251  item.setMimeType(mimeType);
252  items.push_back(std::move(item));
253  msg->addMetadata("FETCH_ITEM");
254  } else if (version >= 2) {
255  stream >> operation;
256  stream >> entityCnt;
257  if (version >= 7) {
258  QByteArray ba;
259  qint64 i64;
260  int i;
261  QDateTime dt;
262  QString str;
264  QVector<qint64> i64v;
266  int cnt;
267  for (int j = 0; j < entityCnt; ++j) {
268  Protocol::FetchItemsResponse item;
269  stream >> i64;
270  item.setId(i64);
271  stream >> i;
272  item.setRevision(i);
273  stream >> i64;
274  item.setParentId(i64);
275  stream >> str;
276  item.setRemoteId(str);
277  stream >> str;
278  item.setRemoteRevision(str);
279  stream >> str;
280  item.setGid(str);
281  stream >> i64;
282  item.setSize(i64);
283  stream >> str;
284  item.setMimeType(str);
285  stream >> dt;
286  item.setMTime(dt);
287  stream >> bav;
288  item.setFlags(bav);
289  stream >> cnt;
291  tags.reserve(cnt);
292  for (int k = 0; k < cnt; ++k) {
293  Protocol::FetchTagsResponse tag;
294  stream >> i64;
295  tag.setId(i64);
296  stream >> i64;
297  tag.setParentId(i64);
298  stream >> ba;
299  tag.setGid(ba);
300  stream >> ba;
301  tag.setType(ba);
302  stream >> ba;
303  tag.setRemoteId(ba);
304  stream >> babaMap;
305  tag.setAttributes(babaMap);
306  tags << tag;
307  }
308  item.setTags(tags);
309  stream >> i64v;
310  item.setVirtualReferences(i64v);
311  stream >> cnt;
313  for (int k = 0; k < cnt; ++k) {
314  Protocol::FetchRelationsResponse relation;
315  stream >> i64;
316  relation.setLeft(i64);
317  stream >> ba;
318  relation.setLeftMimeType(ba);
319  stream >> i64;
320  relation.setRight(i64);
321  stream >> ba;
322  relation.setRightMimeType(ba);
323  stream >> ba;
324  relation.setType(ba);
325  stream >> ba;
326  relation.setRemoteId(ba);
327  relations << relation;
328  }
329  item.setRelations(relations);
330  stream >> cnt;
331  QVector<Protocol::Ancestor> ancestors;
332  for (int k = 0; k < cnt; ++k) {
333  Protocol::Ancestor ancestor;
334  stream >> i64;
335  ancestor.setId(i64);
336  stream >> str;
337  ancestor.setRemoteId(str);
338  stream >> str;
339  ancestor.setName(str);
340  stream >> babaMap;
341  ancestor.setAttributes(babaMap);
342  ancestors << ancestor;
343  }
344  item.setAncestors(ancestors);
345  stream >> cnt;
347  for (int k = 0; k < cnt; ++k) {
348  Protocol::StreamPayloadResponse part;
349  stream >> ba;
350  part.setPayloadName(ba);
351  Protocol::PartMetaData metaData;
352  stream >> ba;
353  metaData.setName(ba);
354  stream >> i64;
355  metaData.setSize(i64);
356  stream >> i;
357  metaData.setVersion(i);
358  stream >> i;
359  metaData.setStorageType(static_cast<Protocol::PartMetaData::StorageType>(i));
360  part.setMetaData(metaData);
361  stream >> ba;
362  part.setData(ba);
363  parts << part;
364  }
365  item.setParts(parts);
366  stream >> bav;
367  item.setCachedParts(bav);
368  items.push_back(std::move(item));
369  }
370  } else {
371  for (int j = 0; j < entityCnt; ++j) {
372  stream >> uid;
373  stream >> remoteId;
374  stream >> remoteRevision;
375  stream >> mimeType;
376  if (stream.status() != QDataStream::Ok) {
377  qCWarning(AKONADICORE_LOG) << "Error reading saved notifications! Aborting";
378  return msg;
379  }
380  Protocol::FetchItemsResponse item;
381  item.setId(uid);
382  item.setRemoteId(remoteId);
383  item.setRemoteRevision(remoteRevision);
384  item.setMimeType(mimeType);
385  items.push_back(std::move(item));
386  }
387  msg->addMetadata("FETCH_ITEM");
388  }
389  stream >> resource;
390  stream >> destinationResource;
391  stream >> parentCollection;
392  stream >> parentDestCollection;
393  stream >> itemParts;
394  stream >> addedFlags;
395  stream >> removedFlags;
396  if (version >= 3) {
397  stream >> addedTags;
398  stream >> removedTags;
399  }
400  if (version >= 8) {
401  bool boolean;
402  stream >> boolean;
403  msg->setMustRetrieve(boolean);
404  }
405  } else {
406  qCWarning(AKONADICORE_LOG) << "Error version is not correct here" << version;
407  return msg;
408  }
409  if (version >= 5) {
410  msg->setOperation(static_cast<Protocol::ItemChangeNotification::Operation>(operation));
411  } else {
412  msg->setOperation(mapItemOperation(static_cast<LegacyOp>(operation)));
413  }
414  msg->setItems(items);
415  msg->setResource(resource);
416  msg->setDestinationResource(destinationResource);
417  msg->setParentCollection(parentCollection);
418  msg->setParentDestCollection(parentDestCollection);
419  msg->setItemParts(itemParts);
420  msg->setAddedRelations(extractRelations(addedFlags));
421  msg->setAddedFlags(addedFlags);
422  msg->setRemovedRelations(extractRelations(removedFlags));
423  msg->setRemovedFlags(removedFlags);
424  msg->setAddedTags(addedTags);
425  msg->setRemovedTags(removedTags);
426  return msg;
427 }
428 
429 QSet<QByteArray> ChangeRecorderJournalWriter::encodeRelations(const QSet<Protocol::ItemChangeNotification::Relation> &relations)
430 {
431  QSet<QByteArray> rv;
432  for (const auto &rel : relations) {
433  rv.insert("RELATION " + rel.type.toLatin1() + ' ' + QByteArray::number(rel.leftId) + ' ' + QByteArray::number(rel.rightId));
434  }
435  return rv;
436 }
437 
438 void ChangeRecorderJournalWriter::saveItemNotification(QDataStream &stream, const Protocol::ItemChangeNotification &msg)
439 {
440  // Version 8
441 
442  stream << int(msg.operation());
443  const auto &items = msg.items();
444  stream << items.count();
445  for (const auto &item : items) {
446  stream << item.id() << item.revision() << item.parentId() << item.remoteId() << item.remoteRevision() << item.gid() << item.size() << item.mimeType()
447  << item.mTime() << item.flags();
448  const auto tags = item.tags();
449  stream << tags.count();
450  for (const auto &tag : tags) {
451  stream << tag.id() << tag.parentId() << tag.gid() << tag.type() << tag.remoteId() << tag.attributes();
452  }
453  stream << item.virtualReferences();
454  const auto relations = item.relations();
455  stream << relations.count();
456  for (const auto &relation : relations) {
457  stream << relation.left() << relation.leftMimeType() << relation.right() << relation.rightMimeType() << relation.type() << relation.remoteId();
458  }
459  const auto ancestors = item.ancestors();
460  stream << ancestors.count();
461  for (const auto &ancestor : ancestors) {
462  stream << ancestor.id() << ancestor.remoteId() << ancestor.name() << ancestor.attributes();
463  }
464  const auto parts = item.parts();
465  stream << parts.count();
466  for (const auto &part : parts) {
467  const auto metaData = part.metaData();
468  stream << part.payloadName() << metaData.name() << metaData.size() << metaData.version() << static_cast<int>(metaData.storageType()) << part.data();
469  }
470  stream << item.cachedParts();
471  }
472  stream << msg.resource();
473  stream << msg.destinationResource();
474  stream << quint64(msg.parentCollection());
475  stream << quint64(msg.parentDestCollection());
476  stream << msg.itemParts();
477  stream << msg.addedFlags() + encodeRelations(msg.addedRelations());
478  stream << msg.removedFlags() + encodeRelations(msg.removedRelations());
479  stream << msg.addedTags();
480  stream << msg.removedTags();
481  stream << msg.mustRetrieve();
482 }
483 
484 Protocol::ChangeNotificationPtr ChangeRecorderJournalReader::loadCollectionNotification(QDataStream &stream, quint64 version)
485 {
486  QByteArray resource;
487  QByteArray destinationResource;
488  int operation;
489  int entityCnt;
490  quint64 uid;
491  quint64 parentCollection;
492  quint64 parentDestCollection;
493  QString remoteId;
494  QString remoteRevision;
495  QString dummyString;
496  QSet<QByteArray> changedParts;
497  QSet<QByteArray> dummyBa;
498  QSet<qint64> dummyIv;
499 
500  auto msg = Protocol::CollectionChangeNotificationPtr::create();
501 
502  if (version == 1) {
503  stream >> operation;
504  stream >> uid;
505  stream >> remoteId;
506  stream >> resource;
507  stream >> parentCollection;
508  stream >> parentDestCollection;
509  stream >> dummyString;
510  stream >> changedParts;
511 
512  Protocol::FetchCollectionsResponse collection;
513  collection.setId(uid);
514  collection.setRemoteId(remoteId);
515  msg->setCollection(std::move(collection));
516  msg->addMetadata("FETCH_COLLECTION");
517  } else if (version >= 2) {
518  stream >> operation;
519  stream >> entityCnt;
520  if (version >= 7) {
521  QString str;
522  QStringList stringList;
523  qint64 i64;
524  QVector<qint64> vb;
526  bool b;
527  int i;
528  Tristate tristate;
529  Protocol::FetchCollectionsResponse collection;
530  stream >> uid;
531  collection.setId(uid);
532  stream >> uid;
533  collection.setParentId(uid);
534  stream >> str;
535  collection.setName(str);
536  stream >> stringList;
537  collection.setMimeTypes(stringList);
538  stream >> str;
539  collection.setRemoteId(str);
540  stream >> str;
541  collection.setRemoteRevision(str);
542  stream >> str;
543  collection.setResource(str);
544 
545  Protocol::FetchCollectionStatsResponse stats;
546  stream >> i64;
547  stats.setCount(i64);
548  stream >> i64;
549  stats.setUnseen(i64);
550  stream >> i64;
551  stats.setSize(i64);
552  collection.setStatistics(stats);
553 
554  stream >> str;
555  collection.setSearchQuery(str);
556  stream >> vb;
557  collection.setSearchCollections(vb);
558  stream >> entityCnt;
559  QVector<Protocol::Ancestor> ancestors;
560  for (int j = 0; j < entityCnt; ++j) {
561  Protocol::Ancestor ancestor;
562  stream >> i64;
563  ancestor.setId(i64);
564  stream >> str;
565  ancestor.setRemoteId(str);
566  stream >> str;
567  ancestor.setName(str);
568  stream >> attrs;
569  ancestor.setAttributes(attrs);
570  ancestors.push_back(ancestor);
571 
572  if (stream.status() != QDataStream::Ok) {
573  qCWarning(AKONADICORE_LOG) << "Erorr reading saved notifications! Aborting";
574  return msg;
575  }
576  }
577  collection.setAncestors(ancestors);
578 
579  Protocol::CachePolicy cachePolicy;
580  stream >> b;
581  cachePolicy.setInherit(b);
582  stream >> i;
583  cachePolicy.setCheckInterval(i);
584  stream >> i;
585  cachePolicy.setCacheTimeout(i);
586  stream >> b;
587  cachePolicy.setSyncOnDemand(b);
588  stream >> stringList;
589  cachePolicy.setLocalParts(stringList);
590  collection.setCachePolicy(cachePolicy);
591 
592  stream >> attrs;
593  collection.setAttributes(attrs);
594  stream >> b;
595  collection.setEnabled(b);
596  stream >> reinterpret_cast<qint8 &>(tristate);
597  collection.setDisplayPref(tristate);
598  stream >> reinterpret_cast<qint8 &>(tristate);
599  collection.setSyncPref(tristate);
600  stream >> reinterpret_cast<qint8 &>(tristate);
601  collection.setIndexPref(tristate);
602  stream >> b; // read the deprecated "isReferenced" value
603  stream >> b;
604  collection.setIsVirtual(b);
605 
606  msg->setCollection(std::move(collection));
607  } else {
608  for (int j = 0; j < entityCnt; ++j) {
609  stream >> uid;
610  stream >> remoteId;
611  stream >> remoteRevision;
612  stream >> dummyString;
613  if (stream.status() != QDataStream::Ok) {
614  qCWarning(AKONADICORE_LOG) << "Error reading saved notifications! Aborting";
615  return msg;
616  }
617  Protocol::FetchCollectionsResponse collection;
618  collection.setId(uid);
619  collection.setRemoteId(remoteId);
620  collection.setRemoteRevision(remoteRevision);
621  msg->setCollection(std::move(collection));
622  msg->addMetadata("FETCH_COLLECTION");
623  }
624  }
625  stream >> resource;
626  stream >> destinationResource;
627  stream >> parentCollection;
628  stream >> parentDestCollection;
629  stream >> changedParts;
630  stream >> dummyBa;
631  stream >> dummyBa;
632  if (version >= 3) {
633  stream >> dummyIv;
634  stream >> dummyIv;
635  }
636  } else {
637  qCWarning(AKONADICORE_LOG) << "Error version is not correct here" << version;
638  return msg;
639  }
640 
641  if (version >= 5) {
642  msg->setOperation(static_cast<Protocol::CollectionChangeNotification::Operation>(operation));
643  } else {
644  msg->setOperation(mapCollectionOperation(static_cast<LegacyOp>(operation)));
645  }
646  msg->setResource(resource);
647  msg->setDestinationResource(destinationResource);
648  msg->setParentCollection(parentCollection);
649  msg->setParentDestCollection(parentDestCollection);
650  msg->setChangedParts(changedParts);
651  return msg;
652 }
653 
654 void Akonadi::ChangeRecorderJournalWriter::saveCollectionNotification(QDataStream &stream, const Protocol::CollectionChangeNotification &msg)
655 {
656  // Version 7
657 
658  const auto &col = msg.collection();
659 
660  stream << int(msg.operation());
661  stream << int(1);
662  stream << col.id();
663  stream << col.parentId();
664  stream << col.name();
665  stream << col.mimeTypes();
666  stream << col.remoteId();
667  stream << col.remoteRevision();
668  stream << col.resource();
669  const auto stats = col.statistics();
670  stream << stats.count();
671  stream << stats.unseen();
672  stream << stats.size();
673  stream << col.searchQuery();
674  stream << col.searchCollections();
675  const auto ancestors = col.ancestors();
676  stream << ancestors.count();
677  for (const auto &ancestor : ancestors) {
678  stream << ancestor.id() << ancestor.remoteId() << ancestor.name() << ancestor.attributes();
679  }
680  const auto cachePolicy = col.cachePolicy();
681  stream << cachePolicy.inherit();
682  stream << cachePolicy.checkInterval();
683  stream << cachePolicy.cacheTimeout();
684  stream << cachePolicy.syncOnDemand();
685  stream << cachePolicy.localParts();
686  stream << col.attributes();
687  stream << col.enabled();
688  stream << static_cast<qint8>(col.displayPref());
689  stream << static_cast<qint8>(col.syncPref());
690  stream << static_cast<qint8>(col.indexPref());
691  stream << false; // write the deprecated "isReferenced" value
692  stream << col.isVirtual();
693 
694  stream << msg.resource();
695  stream << msg.destinationResource();
696  stream << quint64(msg.parentCollection());
697  stream << quint64(msg.parentDestCollection());
698  stream << msg.changedParts();
699  stream << QSet<QByteArray>();
700  stream << QSet<QByteArray>();
701  stream << QSet<qint64>();
702  stream << QSet<qint64>();
703 }
704 
705 Protocol::ChangeNotificationPtr ChangeRecorderJournalReader::loadTagNotification(QDataStream &stream, quint64 version)
706 {
707  QByteArray resource;
708  QByteArray dummyBa;
709  int operation;
710  int entityCnt;
711  quint64 uid;
712  quint64 dummyI;
713  QString remoteId;
714  QString dummyString;
715  QSet<QByteArray> dummyBaV;
716  QSet<qint64> dummyIv;
717 
718  auto msg = Protocol::TagChangeNotificationPtr::create();
719 
720  if (version == 1) {
721  stream >> operation;
722  stream >> uid;
723  stream >> remoteId;
724  stream >> dummyBa;
725  stream >> dummyI;
726  stream >> dummyI;
727  stream >> dummyString;
728  stream >> dummyBaV;
729 
730  Protocol::FetchTagsResponse tag;
731  tag.setId(uid);
732  tag.setRemoteId(remoteId.toLatin1());
733  msg->setTag(std::move(tag));
734  msg->addMetadata("FETCH_TAG");
735  } else if (version >= 2) {
736  stream >> operation;
737  stream >> entityCnt;
738  if (version >= 7) {
739  QByteArray ba;
741 
742  Protocol::FetchTagsResponse tag;
743 
744  stream >> uid;
745  tag.setId(uid);
746  stream >> ba;
747  tag.setParentId(uid);
748  stream >> attrs;
749  tag.setGid(ba);
750  stream >> ba;
751  tag.setType(ba);
752  stream >> uid;
753  tag.setRemoteId(ba);
754  stream >> ba;
755  tag.setAttributes(attrs);
756  msg->setTag(std::move(tag));
757 
758  stream >> resource;
759  } else {
760  for (int j = 0; j < entityCnt; ++j) {
761  stream >> uid;
762  stream >> remoteId;
763  stream >> dummyString;
764  stream >> dummyString;
765  if (stream.status() != QDataStream::Ok) {
766  qCWarning(AKONADICORE_LOG) << "Error reading saved notifications! Aborting";
767  return msg;
768  }
769  Protocol::FetchTagsResponse tag;
770  tag.setId(uid);
771  tag.setRemoteId(remoteId.toLatin1());
772  msg->setTag(std::move(tag));
773  msg->addMetadata("FETCH_TAG");
774  }
775  stream >> resource;
776  stream >> dummyBa;
777  stream >> dummyI;
778  stream >> dummyI;
779  stream >> dummyBaV;
780  stream >> dummyBaV;
781  stream >> dummyBaV;
782  if (version >= 3) {
783  stream >> dummyIv;
784  stream >> dummyIv;
785  }
786  }
787  if (version >= 5) {
788  msg->setOperation(static_cast<Protocol::TagChangeNotification::Operation>(operation));
789  } else {
790  msg->setOperation(mapTagOperation(static_cast<LegacyOp>(operation)));
791  }
792  }
793  msg->setResource(resource);
794  return msg;
795 }
796 
797 void Akonadi::ChangeRecorderJournalWriter::saveTagNotification(QDataStream &stream, const Protocol::TagChangeNotification &msg)
798 {
799  const auto &tag = msg.tag();
800  stream << int(msg.operation());
801  stream << int(1);
802  stream << tag.id();
803  stream << tag.parentId();
804  stream << tag.gid();
805  stream << tag.type();
806  stream << tag.remoteId();
807  stream << tag.attributes();
808  stream << msg.resource();
809 }
810 
811 Protocol::ChangeNotificationPtr ChangeRecorderJournalReader::loadRelationNotification(QDataStream &stream, quint64 version)
812 {
813  QByteArray dummyBa;
814  int operation;
815  int entityCnt;
816  quint64 dummyI;
817  QString dummyString;
818  QSet<QByteArray> itemParts;
819  QSet<QByteArray> dummyBaV;
820  QSet<qint64> dummyIv;
821 
822  auto msg = Protocol::RelationChangeNotificationPtr::create();
823 
824  if (version == 1) {
825  qCWarning(AKONADICORE_LOG) << "Invalid version of relation notification";
826  return msg;
827  } else if (version >= 2) {
828  stream >> operation;
829  stream >> entityCnt;
830  if (version >= 7) {
831  Protocol::FetchRelationsResponse relation;
832  qint64 i64;
833  QByteArray ba;
834  stream >> i64;
835  relation.setLeft(i64);
836  stream >> ba;
837  relation.setLeftMimeType(ba);
838  stream >> i64;
839  relation.setRight(i64);
840  stream >> ba;
841  relation.setRightMimeType(ba);
842  stream >> ba;
843  relation.setRemoteId(ba);
844  stream >> ba;
845  relation.setType(ba);
846 
847  msg->setRelation(std::move(relation));
848 
849  } else {
850  for (int j = 0; j < entityCnt; ++j) {
851  stream >> dummyI;
852  stream >> dummyString;
853  stream >> dummyString;
854  stream >> dummyString;
855  if (stream.status() != QDataStream::Ok) {
856  qCWarning(AKONADICORE_LOG) << "Error reading saved notifications! Aborting";
857  return msg;
858  }
859  }
860  stream >> dummyBa;
861  if (version == 5) {
862  // there was a bug in version 5 serializer that serialized this
863  // field as qint64 (8 bytes) instead of empty QByteArray (which is
864  // 4 bytes)
865  stream >> dummyI;
866  } else {
867  stream >> dummyBa;
868  }
869  stream >> dummyI;
870  stream >> dummyI;
871  stream >> itemParts;
872  stream >> dummyBaV;
873  stream >> dummyBaV;
874  if (version >= 3) {
875  stream >> dummyIv;
876  stream >> dummyIv;
877  }
878 
879  Protocol::FetchRelationsResponse relation;
880  for (const QByteArray &part : std::as_const(itemParts)) {
881  const QByteArrayList p = part.split(' ');
882  if (p.size() < 2) {
883  continue;
884  }
885  if (p[0] == "LEFT") {
886  relation.setLeft(p[1].toLongLong());
887  } else if (p[0] == "RIGHT") {
888  relation.setRight(p[1].toLongLong());
889  } else if (p[0] == "RID") {
890  relation.setRemoteId(p[1]);
891  } else if (p[0] == "TYPE") {
892  relation.setType(p[1]);
893  }
894  }
895  msg->setRelation(std::move(relation));
896  }
897  if (version >= 5) {
898  msg->setOperation(static_cast<Protocol::RelationChangeNotification::Operation>(operation));
899  } else {
900  msg->setOperation(mapRelationOperation(static_cast<LegacyOp>(operation)));
901  }
902  }
903 
904  return msg;
905 }
906 
907 void Akonadi::ChangeRecorderJournalWriter::saveRelationNotification(QDataStream &stream, const Protocol::RelationChangeNotification &msg)
908 {
909  const auto &rel = msg.relation();
910  stream << int(msg.operation());
911  stream << int(0);
912  stream << rel.left();
913  stream << rel.leftMimeType();
914  stream << rel.right();
915  stream << rel.rightMimeType();
916  stream << rel.remoteId();
917  stream << rel.type();
918 }
919 
920 Protocol::ItemChangeNotification::Operation ChangeRecorderJournalReader::mapItemOperation(LegacyOp op)
921 {
922  switch (op) {
923  case Add:
924  return Protocol::ItemChangeNotification::Add;
925  case Modify:
926  return Protocol::ItemChangeNotification::Modify;
927  case Move:
928  return Protocol::ItemChangeNotification::Move;
929  case Remove:
930  return Protocol::ItemChangeNotification::Remove;
931  case Link:
932  return Protocol::ItemChangeNotification::Link;
933  case Unlink:
934  return Protocol::ItemChangeNotification::Unlink;
935  case ModifyFlags:
936  return Protocol::ItemChangeNotification::ModifyFlags;
937  case ModifyTags:
938  return Protocol::ItemChangeNotification::ModifyTags;
939  case ModifyRelations:
940  return Protocol::ItemChangeNotification::ModifyRelations;
941  default:
942  qWarning() << "Unexpected operation type in item notification";
943  return Protocol::ItemChangeNotification::InvalidOp;
944  }
945 }
946 
947 Protocol::CollectionChangeNotification::Operation ChangeRecorderJournalReader::mapCollectionOperation(LegacyOp op)
948 {
949  switch (op) {
950  case Add:
951  return Protocol::CollectionChangeNotification::Add;
952  case Modify:
953  return Protocol::CollectionChangeNotification::Modify;
954  case Move:
955  return Protocol::CollectionChangeNotification::Move;
956  case Remove:
957  return Protocol::CollectionChangeNotification::Remove;
958  case Subscribe:
959  return Protocol::CollectionChangeNotification::Subscribe;
960  case Unsubscribe:
961  return Protocol::CollectionChangeNotification::Unsubscribe;
962  default:
963  qCWarning(AKONADICORE_LOG) << "Unexpected operation type in collection notification";
964  return Protocol::CollectionChangeNotification::InvalidOp;
965  }
966 }
967 
968 Protocol::TagChangeNotification::Operation ChangeRecorderJournalReader::mapTagOperation(LegacyOp op)
969 {
970  switch (op) {
971  case Add:
972  return Protocol::TagChangeNotification::Add;
973  case Modify:
974  return Protocol::TagChangeNotification::Modify;
975  case Remove:
976  return Protocol::TagChangeNotification::Remove;
977  default:
978  qCWarning(AKONADICORE_LOG) << "Unexpected operation type in tag notification";
979  return Protocol::TagChangeNotification::InvalidOp;
980  }
981 }
982 
983 Protocol::RelationChangeNotification::Operation ChangeRecorderJournalReader::mapRelationOperation(LegacyOp op)
984 {
985  switch (op) {
986  case Add:
987  return Protocol::RelationChangeNotification::Add;
988  case Remove:
989  return Protocol::RelationChangeNotification::Remove;
990  default:
991  qCWarning(AKONADICORE_LOG) << "Unexpected operation type in relation notification";
992  return Protocol::RelationChangeNotification::InvalidOp;
993  }
994 }
995 
996 ChangeRecorderJournalReader::LegacyType ChangeRecorderJournalWriter::mapToLegacyType(Protocol::Command::Type type)
997 {
998  switch (type) {
999  case Protocol::Command::ItemChangeNotification:
1000  return ChangeRecorderJournalReader::Item;
1001  case Protocol::Command::CollectionChangeNotification:
1002  return ChangeRecorderJournalReader::Collection;
1003  case Protocol::Command::TagChangeNotification:
1004  return ChangeRecorderJournalReader::Tag;
1005  case Protocol::Command::RelationChangeNotification:
1006  return ChangeRecorderJournalReader::Relation;
1007  default:
1008  qCWarning(AKONADICORE_LOG) << "Unexpected notification type";
1009  return ChangeRecorderJournalReader::InvalidType;
1010  }
1011 }
void setVersion(int v)
QSet::iterator erase(QSet::iterator pos)
An Akonadi Tag.
Definition: tag.h:25
int count(const T &value) const const
void push_back(const T &value)
QByteArray number(int n, int base)
Represents a collection of PIM items.
Definition: collection.h:61
KCALUTILS_EXPORT QString mimeType()
An Akonadi Relation.
Definition: relation.h:39
QByteArray toByteArray() const const
qlonglong toLongLong(bool *ok) const const
KIOFILEWIDGETS_EXPORT QStringList list(const QString &fileClass)
virtual QString fileName() const const override
int size() const const
char * toString(const T &value)
const T & at(int i) const const
QVariant value(const QString &key, const QVariant &defaultValue) const const
QSet::iterator begin()
void reserve(int size)
VehicleSection::Type type(QStringView coachNumber, QStringView coachClassification)
unsigned int version()
int version() const const
QString fromLatin1(const char *str, int size)
QSet::iterator end()
QSet::iterator insert(const T &value)
int count(const T &value) const const
QDataStream::Status status() const const
QStringList toStringList() const const
Represents a PIM item stored in Akonadi storage.
Definition: item.h:104
Helper integration between Akonadi and Qt.
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Mon Jun 27 2022 04:01:05 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.