Akonadi

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

KDE's Doxygen guidelines are available online.