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

KDE's Doxygen guidelines are available online.