Akonadi

changerecorderjournal.cpp
1/*
2 SPDX-FileCopyrightText: 2007 Volker Krause <vkrause@kde.org>
3 SPDX-FileCopyrightText: 2018 Daniel Vrátil <dvratil@kde.org>
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
16using namespace Akonadi;
17
18namespace
19{
20constexpr quint64 s_currentVersion = Q_UINT64_C(0x000900000000);
21constexpr quint64 s_versionMask = Q_UINT64_C(0xFFFF00000000);
22constexpr quint64 s_sizeMask = Q_UINT64_C(0x0000FFFFFFFF);
23}
24
25Protocol::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
41QQueue<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 // Just load it but discard the result, we don't support relations anymore
88 loadRelationNotification(stream, version);
89 break;
90 default:
91 qCWarning(AKONADICORE_LOG) << "Unknown notification type";
92 break;
93 }
94
95 if (i < startOffset) {
96 continue;
97 }
98
99 if (msg && msg->isValid()) {
100 msg->setSessionId(sessionId);
101 list << msg;
102 }
103 }
104
105 return list;
106}
107
108void ChangeRecorderJournalWriter::saveTo(const QQueue<Protocol::ChangeNotificationPtr> &notifications, QIODevice *device)
109{
110 // Version 0 of this file format was writing a quint64 count, followed by the notifications.
111 // Version 1 bundles a version number into that quint64, to be able to detect a version number at load time.
112
113 const quint64 countAndVersion = static_cast<quint64>(notifications.count()) | s_currentVersion;
114
115 QDataStream stream(device);
116 stream.setVersion(QDataStream::Qt_4_6);
117
118 stream << countAndVersion;
119 stream << quint64(0); // no start offset
120
121 // qCDebug(AKONADICORE_LOG) << "Saving" << pendingNotifications.count() << "notifications (full save)";
122
123 for (int i = 0; i < notifications.count(); ++i) {
124 const Protocol::ChangeNotificationPtr &msg = notifications.at(i);
125
126 // We deliberately don't use Factory::serialize(), because the internal
127 // serialization format could change at any point
128
129 stream << msg->sessionId();
130 stream << int(mapToLegacyType(msg->type()));
131 switch (msg->type()) {
132 case Protocol::Command::ItemChangeNotification:
133 saveItemNotification(stream, Protocol::cmdCast<Protocol::ItemChangeNotification>(msg));
134 break;
135 case Protocol::Command::CollectionChangeNotification:
136 saveCollectionNotification(stream, Protocol::cmdCast<Protocol::CollectionChangeNotification>(msg));
137 break;
138 case Protocol::Command::TagChangeNotification:
139 saveTagNotification(stream, Protocol::cmdCast<Protocol::TagChangeNotification>(msg));
140 break;
141 default:
142 qCWarning(AKONADICORE_LOG) << "Unexpected type?";
143 return;
144 }
145 }
146}
147
148Protocol::ChangeNotificationPtr ChangeRecorderJournalReader::loadQSettingsItemNotification(QSettings *settings)
149{
150 auto msg = Protocol::ItemChangeNotificationPtr::create();
151 msg->setSessionId(settings->value(QStringLiteral("sessionId")).toByteArray());
152 msg->setOperation(mapItemOperation(static_cast<LegacyOp>(settings->value(QStringLiteral("op")).toInt())));
153 Protocol::FetchItemsResponse item;
154 item.setId(settings->value(QStringLiteral("uid")).toLongLong());
155 item.setRemoteId(settings->value(QStringLiteral("rid")).toString());
156 item.setMimeType(settings->value(QStringLiteral("mimeType")).toString());
157 msg->setItems({std::move(item)});
158 msg->addMetadata("FETCH_ITEM");
159 msg->setResource(settings->value(QStringLiteral("resource")).toByteArray());
160 msg->setParentCollection(settings->value(QStringLiteral("parentCol")).toLongLong());
161 msg->setParentDestCollection(settings->value(QStringLiteral("parentDestCol")).toLongLong());
162 const QStringList list = settings->value(QStringLiteral("itemParts")).toStringList();
163 QSet<QByteArray> itemParts;
164 for (const QString &entry : list) {
165 itemParts.insert(entry.toLatin1());
166 }
167 msg->setItemParts(itemParts);
168 return msg;
169}
170
171Protocol::ChangeNotificationPtr ChangeRecorderJournalReader::loadQSettingsCollectionNotification(QSettings *settings)
172{
173 auto msg = Protocol::CollectionChangeNotificationPtr::create();
174 msg->setSessionId(settings->value(QStringLiteral("sessionId")).toByteArray());
175 msg->setOperation(mapCollectionOperation(static_cast<LegacyOp>(settings->value(QStringLiteral("op")).toInt())));
176 Protocol::FetchCollectionsResponse collection;
177 collection.setId(settings->value(QStringLiteral("uid")).toLongLong());
178 collection.setRemoteId(settings->value(QStringLiteral("rid")).toString());
179 msg->setCollection(std::move(collection));
180 msg->addMetadata("FETCH_COLLECTION");
181 msg->setResource(settings->value(QStringLiteral("resource")).toByteArray());
182 msg->setParentCollection(settings->value(QStringLiteral("parentCol")).toLongLong());
183 msg->setParentDestCollection(settings->value(QStringLiteral("parentDestCol")).toLongLong());
184 const QStringList list = settings->value(QStringLiteral("itemParts")).toStringList();
185 QSet<QByteArray> changedParts;
186 for (const QString &entry : list) {
187 changedParts.insert(entry.toLatin1());
188 }
189 msg->setChangedParts(changedParts);
190 return msg;
191}
192
193Protocol::ChangeNotificationPtr ChangeRecorderJournalReader::loadItemNotification(QDataStream &stream, quint64 version)
194{
195 QByteArray resource;
196 QByteArray destinationResource;
197 int operation;
198 int entityCnt;
199 qint64 uid;
200 qint64 parentCollection;
201 qint64 parentDestCollection;
202 QString remoteId;
204 QString remoteRevision;
205 QSet<QByteArray> itemParts;
206 QSet<QByteArray> addedFlags;
207 QSet<QByteArray> removedFlags;
208 QSet<qint64> addedTags;
209 QSet<qint64> removedTags;
211
212 auto msg = Protocol::ItemChangeNotificationPtr::create();
213
214 if (version == 1) {
215 stream >> operation;
216 stream >> uid;
217 stream >> remoteId;
218 stream >> resource;
219 stream >> parentCollection;
220 stream >> parentDestCollection;
221 stream >> mimeType;
222 stream >> itemParts;
223
224 Protocol::FetchItemsResponse item;
225 item.setId(uid);
226 item.setRemoteId(remoteId);
227 item.setMimeType(mimeType);
228 items.push_back(std::move(item));
229 msg->addMetadata("FETCH_ITEM");
230 } else if (version >= 2) {
231 stream >> operation;
232 stream >> entityCnt;
233 if (version >= 7) {
234 QByteArray ba;
235 qint64 i64;
236 int i;
237 QDateTime dt;
238 QString str;
240 QList<qint64> i64v;
242 int cnt;
243 for (int j = 0; j < entityCnt; ++j) {
244 Protocol::FetchItemsResponse item;
245 stream >> i64;
246 item.setId(i64);
247 stream >> i;
248 item.setRevision(i);
249 stream >> i64;
250 item.setParentId(i64);
251 stream >> str;
252 item.setRemoteId(str);
253 stream >> str;
254 item.setRemoteRevision(str);
255 stream >> str;
256 item.setGid(str);
257 stream >> i64;
258 item.setSize(i64);
259 stream >> str;
260 item.setMimeType(str);
261 stream >> dt;
262 item.setMTime(dt);
263 stream >> bav;
264 item.setFlags(bav);
265 stream >> cnt;
267 tags.reserve(cnt);
268 for (int k = 0; k < cnt; ++k) {
269 Protocol::FetchTagsResponse tag;
270 stream >> i64;
271 tag.setId(i64);
272 stream >> i64;
273 tag.setParentId(i64);
274 stream >> ba;
275 tag.setGid(ba);
276 stream >> ba;
277 tag.setType(ba);
278 stream >> ba;
279 tag.setRemoteId(ba);
280 stream >> babaMap;
281 tag.setAttributes(babaMap);
282 tags << tag;
283 }
284 item.setTags(tags);
285 stream >> i64v;
286 item.setVirtualReferences(i64v);
287 stream >> cnt;
288 for (int k = 0; k < cnt; ++k) {
289 stream >> i64; // left
290 stream >> ba; // left mimetype
291 stream >> i64; // right
292 stream >> ba; // right mimetype
293 stream >> ba; // type
294 stream >> ba; // remoteid
295 }
296 stream >> cnt;
298 for (int k = 0; k < cnt; ++k) {
299 Protocol::Ancestor ancestor;
300 stream >> i64;
301 ancestor.setId(i64);
302 stream >> str;
303 ancestor.setRemoteId(str);
304 stream >> str;
305 ancestor.setName(str);
306 stream >> babaMap;
307 ancestor.setAttributes(babaMap);
308 ancestors << ancestor;
309 }
310 item.setAncestors(ancestors);
311 stream >> cnt;
313 for (int k = 0; k < cnt; ++k) {
314 Protocol::StreamPayloadResponse part;
315 stream >> ba;
316 part.setPayloadName(ba);
317 Protocol::PartMetaData metaData;
318 stream >> ba;
319 metaData.setName(ba);
320 stream >> i64;
321 metaData.setSize(i64);
322 stream >> i;
323 metaData.setVersion(i);
324 stream >> i;
325 metaData.setStorageType(static_cast<Protocol::PartMetaData::StorageType>(i));
326 part.setMetaData(metaData);
327 stream >> ba;
328 part.setData(ba);
329 parts << part;
330 }
331 item.setParts(parts);
332 stream >> bav;
333 item.setCachedParts(bav);
334 items.push_back(std::move(item));
335 }
336 } else {
337 for (int j = 0; j < entityCnt; ++j) {
338 stream >> uid;
339 stream >> remoteId;
340 stream >> remoteRevision;
341 stream >> mimeType;
342 if (stream.status() != QDataStream::Ok) {
343 qCWarning(AKONADICORE_LOG) << "Error reading saved notifications! Aborting";
344 return msg;
345 }
346 Protocol::FetchItemsResponse item;
347 item.setId(uid);
348 item.setRemoteId(remoteId);
349 item.setRemoteRevision(remoteRevision);
350 item.setMimeType(mimeType);
351 items.push_back(std::move(item));
352 }
353 msg->addMetadata("FETCH_ITEM");
354 }
355 stream >> resource;
356 stream >> destinationResource;
357 stream >> parentCollection;
358 stream >> parentDestCollection;
359 stream >> itemParts;
360 stream >> addedFlags;
361 stream >> removedFlags;
362 if (version >= 3) {
363 stream >> addedTags;
364 stream >> removedTags;
365 }
366 if (version >= 8) {
367 bool boolean;
368 stream >> boolean;
369 msg->setMustRetrieve(boolean);
370 }
371 } else {
372 qCWarning(AKONADICORE_LOG) << "Error version is not correct here" << version;
373 return msg;
374 }
375 if (version >= 5) {
376 msg->setOperation(static_cast<Protocol::ItemChangeNotification::Operation>(operation));
377 } else {
378 msg->setOperation(mapItemOperation(static_cast<LegacyOp>(operation)));
379 }
380 msg->setItems(items);
381 msg->setResource(resource);
382 msg->setDestinationResource(destinationResource);
383 msg->setParentCollection(parentCollection);
384 msg->setParentDestCollection(parentDestCollection);
385 msg->setItemParts(itemParts);
386 msg->setAddedFlags(addedFlags);
387 msg->setRemovedFlags(removedFlags);
388 msg->setAddedTags(addedTags);
389 msg->setRemovedTags(removedTags);
390 return msg;
391}
392
393void ChangeRecorderJournalWriter::saveItemNotification(QDataStream &stream, const Protocol::ItemChangeNotification &msg)
394{
395 // Version 8
396
397 stream << int(msg.operation());
398 const auto &items = msg.items();
399 stream << static_cast<int>(items.count());
400 for (const auto &item : items) {
401 stream << item.id() << item.revision() << item.parentId() << item.remoteId() << item.remoteRevision() << item.gid() << item.size() << item.mimeType()
402 << item.mTime() << item.flags();
403 const auto tags = item.tags();
404 stream << static_cast<int>(tags.count());
405 for (const auto &tag : tags) {
406 stream << tag.id() << tag.parentId() << tag.gid() << tag.type() << tag.remoteId() << tag.attributes();
407 }
408 stream << item.virtualReferences();
409 const auto ancestors = item.ancestors();
410 stream << static_cast<int>(ancestors.count());
411 for (const auto &ancestor : ancestors) {
412 stream << ancestor.id() << ancestor.remoteId() << ancestor.name() << ancestor.attributes();
413 }
414 const auto parts = item.parts();
415 stream << static_cast<int>(parts.count());
416 for (const auto &part : parts) {
417 const auto metaData = part.metaData();
418 stream << part.payloadName() << metaData.name() << metaData.size() << metaData.version() << static_cast<int>(metaData.storageType()) << part.data();
419 }
420 stream << item.cachedParts();
421 }
422 stream << msg.resource();
423 stream << msg.destinationResource();
424 stream << quint64(msg.parentCollection());
425 stream << quint64(msg.parentDestCollection());
426 stream << msg.itemParts();
427 stream << msg.addedFlags();
428 stream << msg.removedFlags();
429 stream << msg.addedTags();
430 stream << msg.removedTags();
431 stream << msg.mustRetrieve();
432}
433
434Protocol::ChangeNotificationPtr ChangeRecorderJournalReader::loadCollectionNotification(QDataStream &stream, quint64 version)
435{
436 QByteArray resource;
437 QByteArray destinationResource;
438 int operation;
439 int entityCnt;
440 quint64 uid;
441 quint64 parentCollection;
442 quint64 parentDestCollection;
443 QString remoteId;
444 QString remoteRevision;
445 QString dummyString;
446 QSet<QByteArray> changedParts;
447 QSet<QByteArray> dummyBa;
448 QSet<qint64> dummyIv;
449
450 auto msg = Protocol::CollectionChangeNotificationPtr::create();
451
452 if (version == 1) {
453 stream >> operation;
454 stream >> uid;
455 stream >> remoteId;
456 stream >> resource;
457 stream >> parentCollection;
458 stream >> parentDestCollection;
459 stream >> dummyString;
460 stream >> changedParts;
461
462 Protocol::FetchCollectionsResponse collection;
463 collection.setId(uid);
464 collection.setRemoteId(remoteId);
465 msg->setCollection(std::move(collection));
466 msg->addMetadata("FETCH_COLLECTION");
467 } else if (version >= 2) {
468 stream >> operation;
469 stream >> entityCnt;
470 if (version >= 7) {
471 QString str;
472 QStringList stringList;
473 qint64 i64;
474 QList<qint64> vb;
476 bool b;
477 int i;
478 Tristate tristate;
479 Protocol::FetchCollectionsResponse collection;
480 stream >> uid;
481 collection.setId(uid);
482 stream >> uid;
483 collection.setParentId(uid);
484 stream >> str;
485 collection.setName(str);
486 stream >> stringList;
487 collection.setMimeTypes(stringList);
488 stream >> str;
489 collection.setRemoteId(str);
490 stream >> str;
491 collection.setRemoteRevision(str);
492 stream >> str;
493 collection.setResource(str);
494
495 Protocol::FetchCollectionStatsResponse stats;
496 stream >> i64;
497 stats.setCount(i64);
498 stream >> i64;
499 stats.setUnseen(i64);
500 stream >> i64;
501 stats.setSize(i64);
502 collection.setStatistics(stats);
503
504 stream >> str;
505 collection.setSearchQuery(str);
506 stream >> vb;
507 collection.setSearchCollections(vb);
508 stream >> entityCnt;
510 for (int j = 0; j < entityCnt; ++j) {
511 Protocol::Ancestor ancestor;
512 stream >> i64;
513 ancestor.setId(i64);
514 stream >> str;
515 ancestor.setRemoteId(str);
516 stream >> str;
517 ancestor.setName(str);
518 stream >> attrs;
519 ancestor.setAttributes(attrs);
520 ancestors.push_back(ancestor);
521
522 if (stream.status() != QDataStream::Ok) {
523 qCWarning(AKONADICORE_LOG) << "Erorr reading saved notifications! Aborting";
524 return msg;
525 }
526 }
527 collection.setAncestors(ancestors);
528
529 Protocol::CachePolicy cachePolicy;
530 stream >> b;
531 cachePolicy.setInherit(b);
532 stream >> i;
533 cachePolicy.setCheckInterval(i);
534 stream >> i;
535 cachePolicy.setCacheTimeout(i);
536 stream >> b;
537 cachePolicy.setSyncOnDemand(b);
538 stream >> stringList;
539 cachePolicy.setLocalParts(stringList);
540 collection.setCachePolicy(cachePolicy);
541
542 stream >> attrs;
543 collection.setAttributes(attrs);
544 stream >> b;
545 collection.setEnabled(b);
546 stream >> reinterpret_cast<qint8 &>(tristate);
547 collection.setDisplayPref(tristate);
548 stream >> reinterpret_cast<qint8 &>(tristate);
549 collection.setSyncPref(tristate);
550 stream >> reinterpret_cast<qint8 &>(tristate);
551 collection.setIndexPref(tristate);
552 stream >> b; // read the deprecated "isReferenced" value
553 stream >> b;
554 collection.setIsVirtual(b);
555
556 msg->setCollection(std::move(collection));
557 } else {
558 for (int j = 0; j < entityCnt; ++j) {
559 stream >> uid;
560 stream >> remoteId;
561 stream >> remoteRevision;
562 stream >> dummyString;
563 if (stream.status() != QDataStream::Ok) {
564 qCWarning(AKONADICORE_LOG) << "Error reading saved notifications! Aborting";
565 return msg;
566 }
567 Protocol::FetchCollectionsResponse collection;
568 collection.setId(uid);
569 collection.setRemoteId(remoteId);
570 collection.setRemoteRevision(remoteRevision);
571 msg->setCollection(std::move(collection));
572 msg->addMetadata("FETCH_COLLECTION");
573 }
574 }
575 stream >> resource;
576 stream >> destinationResource;
577 stream >> parentCollection;
578 stream >> parentDestCollection;
579 stream >> changedParts;
580 stream >> dummyBa;
581 stream >> dummyBa;
582 if (version >= 3) {
583 stream >> dummyIv;
584 stream >> dummyIv;
585 }
586 } else {
587 qCWarning(AKONADICORE_LOG) << "Error version is not correct here" << version;
588 return msg;
589 }
590
591 if (version >= 5) {
592 msg->setOperation(static_cast<Protocol::CollectionChangeNotification::Operation>(operation));
593 } else {
594 msg->setOperation(mapCollectionOperation(static_cast<LegacyOp>(operation)));
595 }
596 msg->setResource(resource);
597 msg->setDestinationResource(destinationResource);
598 msg->setParentCollection(parentCollection);
599 msg->setParentDestCollection(parentDestCollection);
600 msg->setChangedParts(changedParts);
601 return msg;
602}
603
604void Akonadi::ChangeRecorderJournalWriter::saveCollectionNotification(QDataStream &stream, const Protocol::CollectionChangeNotification &msg)
605{
606 // Version 7
607
608 const auto &col = msg.collection();
609
610 stream << int(msg.operation());
611 stream << int(1);
612 stream << col.id();
613 stream << col.parentId();
614 stream << col.name();
615 stream << col.mimeTypes();
616 stream << col.remoteId();
617 stream << col.remoteRevision();
618 stream << col.resource();
619 const auto stats = col.statistics();
620 stream << stats.count();
621 stream << stats.unseen();
622 stream << stats.size();
623 stream << col.searchQuery();
624 stream << col.searchCollections();
625 const auto ancestors = col.ancestors();
626 stream << static_cast<int>(ancestors.count());
627 for (const auto &ancestor : ancestors) {
628 stream << ancestor.id() << ancestor.remoteId() << ancestor.name() << ancestor.attributes();
629 }
630 const auto cachePolicy = col.cachePolicy();
631 stream << cachePolicy.inherit();
632 stream << cachePolicy.checkInterval();
633 stream << cachePolicy.cacheTimeout();
634 stream << cachePolicy.syncOnDemand();
635 stream << cachePolicy.localParts();
636 stream << col.attributes();
637 stream << col.enabled();
638 stream << static_cast<qint8>(col.displayPref());
639 stream << static_cast<qint8>(col.syncPref());
640 stream << static_cast<qint8>(col.indexPref());
641 stream << false; // write the deprecated "isReferenced" value
642 stream << col.isVirtual();
643
644 stream << msg.resource();
645 stream << msg.destinationResource();
646 stream << quint64(msg.parentCollection());
647 stream << quint64(msg.parentDestCollection());
648 stream << msg.changedParts();
649 stream << QSet<QByteArray>();
650 stream << QSet<QByteArray>();
651 stream << QSet<qint64>();
652 stream << QSet<qint64>();
653}
654
655Protocol::ChangeNotificationPtr ChangeRecorderJournalReader::loadTagNotification(QDataStream &stream, quint64 version)
656{
657 QByteArray resource;
658 QByteArray dummyBa;
659 int operation;
660 int entityCnt;
661 quint64 uid;
662 quint64 dummyI;
663 QString remoteId;
664 QString dummyString;
665 QSet<QByteArray> dummyBaV;
666 QSet<qint64> dummyIv;
667
668 auto msg = Protocol::TagChangeNotificationPtr::create();
669
670 if (version == 1) {
671 stream >> operation;
672 stream >> uid;
673 stream >> remoteId;
674 stream >> dummyBa;
675 stream >> dummyI;
676 stream >> dummyI;
677 stream >> dummyString;
678 stream >> dummyBaV;
679
680 Protocol::FetchTagsResponse tag;
681 tag.setId(uid);
682 tag.setRemoteId(remoteId.toLatin1());
683 msg->setTag(std::move(tag));
684 msg->addMetadata("FETCH_TAG");
685 } else if (version >= 2) {
686 stream >> operation;
687 stream >> entityCnt;
688 if (version >= 7) {
689 QByteArray ba;
691
692 Protocol::FetchTagsResponse tag;
693
694 stream >> uid;
695 tag.setId(uid);
696 stream >> ba;
697 tag.setParentId(uid);
698 stream >> attrs;
699 tag.setGid(ba);
700 stream >> ba;
701 tag.setType(ba);
702 stream >> uid;
703 tag.setRemoteId(ba);
704 stream >> ba;
705 tag.setAttributes(attrs);
706 msg->setTag(std::move(tag));
707
708 stream >> resource;
709 } else {
710 for (int j = 0; j < entityCnt; ++j) {
711 stream >> uid;
712 stream >> remoteId;
713 stream >> dummyString;
714 stream >> dummyString;
715 if (stream.status() != QDataStream::Ok) {
716 qCWarning(AKONADICORE_LOG) << "Error reading saved notifications! Aborting";
717 return msg;
718 }
719 Protocol::FetchTagsResponse tag;
720 tag.setId(uid);
721 tag.setRemoteId(remoteId.toLatin1());
722 msg->setTag(std::move(tag));
723 msg->addMetadata("FETCH_TAG");
724 }
725 stream >> resource;
726 stream >> dummyBa;
727 stream >> dummyI;
728 stream >> dummyI;
729 stream >> dummyBaV;
730 stream >> dummyBaV;
731 stream >> dummyBaV;
732 if (version >= 3) {
733 stream >> dummyIv;
734 stream >> dummyIv;
735 }
736 }
737 if (version >= 5) {
738 msg->setOperation(static_cast<Protocol::TagChangeNotification::Operation>(operation));
739 } else {
740 msg->setOperation(mapTagOperation(static_cast<LegacyOp>(operation)));
741 }
742 }
743 msg->setResource(resource);
744 return msg;
745}
746
747void Akonadi::ChangeRecorderJournalWriter::saveTagNotification(QDataStream &stream, const Protocol::TagChangeNotification &msg)
748{
749 const auto &tag = msg.tag();
750 stream << int(msg.operation());
751 stream << int(1);
752 stream << tag.id();
753 stream << tag.parentId();
754 stream << tag.gid();
755 stream << tag.type();
756 stream << tag.remoteId();
757 stream << tag.attributes();
758 stream << msg.resource();
759}
760
761Protocol::ChangeNotificationPtr ChangeRecorderJournalReader::loadRelationNotification(QDataStream &stream, quint64 version)
762{
763 // NOTE: While relations have been deprecated and removed from Akonadi, we still need to support reading them from
764 // the journal, otherwise we would not be able to read old journals.
765
766 QByteArray dummyBa;
767 int operation;
768 int entityCnt;
769 quint64 dummyI;
770 QString dummyString;
771 QSet<QByteArray> itemParts;
772 QSet<QByteArray> dummyBaV;
773 QSet<qint64> dummyIv;
774
775 if (version == 1) {
776 qCWarning(AKONADICORE_LOG) << "Invalid version of relation notification";
777 return {};
778 } else if (version >= 2) {
779 stream >> operation;
780 stream >> entityCnt;
781 if (version >= 7) {
782 stream >> dummyI; // left
783 stream >> dummyBa; // left mimetype
784 stream >> dummyI; // right
785 stream >> dummyBa; // right mimetype
786 stream >> dummyBa; // remoteid
787 stream >> dummyBa; // type
788 } else {
789 for (int j = 0; j < entityCnt; ++j) {
790 stream >> dummyI;
791 stream >> dummyString;
792 stream >> dummyString;
793 stream >> dummyString;
794 if (stream.status() != QDataStream::Ok) {
795 qCWarning(AKONADICORE_LOG) << "Error reading saved notifications! Aborting";
796 return {};
797 }
798 }
799 stream >> dummyBa;
800 if (version == 5) {
801 // there was a bug in version 5 serializer that serialized this
802 // field as qint64 (8 bytes) instead of empty QByteArray (which is
803 // 4 bytes)
804 stream >> dummyI;
805 } else {
806 stream >> dummyBa;
807 }
808 stream >> dummyI;
809 stream >> dummyI;
810 stream >> itemParts;
811 stream >> dummyBaV;
812 stream >> dummyBaV;
813 if (version >= 3) {
814 stream >> dummyIv;
815 stream >> dummyIv;
816 }
817 }
818 }
819
820 return {};
821}
822
823Protocol::ItemChangeNotification::Operation ChangeRecorderJournalReader::mapItemOperation(LegacyOp op)
824{
825 switch (op) {
826 case Add:
827 return Protocol::ItemChangeNotification::Add;
828 case Modify:
829 return Protocol::ItemChangeNotification::Modify;
830 case Move:
831 return Protocol::ItemChangeNotification::Move;
832 case Remove:
833 return Protocol::ItemChangeNotification::Remove;
834 case Link:
835 return Protocol::ItemChangeNotification::Link;
836 case Unlink:
837 return Protocol::ItemChangeNotification::Unlink;
838 case ModifyFlags:
839 return Protocol::ItemChangeNotification::ModifyFlags;
840 case ModifyTags:
841 return Protocol::ItemChangeNotification::ModifyTags;
842 case ModifyRelations:
843 [[fallthrough]];
844 default:
845 qWarning() << "Unexpected operation type in item notification";
846 return Protocol::ItemChangeNotification::InvalidOp;
847 }
848}
849
850Protocol::CollectionChangeNotification::Operation ChangeRecorderJournalReader::mapCollectionOperation(LegacyOp op)
851{
852 switch (op) {
853 case Add:
854 return Protocol::CollectionChangeNotification::Add;
855 case Modify:
856 return Protocol::CollectionChangeNotification::Modify;
857 case Move:
858 return Protocol::CollectionChangeNotification::Move;
859 case Remove:
860 return Protocol::CollectionChangeNotification::Remove;
861 case Subscribe:
862 return Protocol::CollectionChangeNotification::Subscribe;
863 case Unsubscribe:
864 return Protocol::CollectionChangeNotification::Unsubscribe;
865 default:
866 qCWarning(AKONADICORE_LOG) << "Unexpected operation type in collection notification";
867 return Protocol::CollectionChangeNotification::InvalidOp;
868 }
869}
870
871Protocol::TagChangeNotification::Operation ChangeRecorderJournalReader::mapTagOperation(LegacyOp op)
872{
873 switch (op) {
874 case Add:
875 return Protocol::TagChangeNotification::Add;
876 case Modify:
877 return Protocol::TagChangeNotification::Modify;
878 case Remove:
879 return Protocol::TagChangeNotification::Remove;
880 default:
881 qCWarning(AKONADICORE_LOG) << "Unexpected operation type in tag notification";
882 return Protocol::TagChangeNotification::InvalidOp;
883 }
884}
885
886ChangeRecorderJournalReader::LegacyType ChangeRecorderJournalWriter::mapToLegacyType(Protocol::Command::Type type)
887{
888 switch (type) {
889 case Protocol::Command::ItemChangeNotification:
890 return ChangeRecorderJournalReader::Item;
891 case Protocol::Command::CollectionChangeNotification:
892 return ChangeRecorderJournalReader::Collection;
893 case Protocol::Command::TagChangeNotification:
894 return ChangeRecorderJournalReader::Tag;
895 default:
896 qCWarning(AKONADICORE_LOG) << "Unexpected notification type";
897 return ChangeRecorderJournalReader::InvalidType;
898 }
899}
Represents a collection of PIM items.
Definition collection.h:62
An Akonadi Tag.
Definition tag.h:26
Helper integration between Akonadi and Qt.
char * toString(const EngineQuery &query)
KCALUTILS_EXPORT QString mimeType()
KDB_EXPORT KDbVersionInfo version()
VehicleSection::Type type(QStringView coachNumber, QStringView coachClassification)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
void setVersion(int v)
Status status() const const
int version() const const
virtual QString fileName() const const override
const_reference at(qsizetype i) const const
qsizetype count() const const
void push_back(parameter_type value)
void reserve(qsizetype size)
iterator insert(const T &value)
QVariant value(QAnyStringView key) const const
QByteArray toByteArray() const const
qlonglong toLongLong(bool *ok) const const
QStringList toStringList() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Jul 19 2024 11:58:37 by doxygen 1.11.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.