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) {
68 Protocol::ChangeNotificationPtr msg;
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 tags.reserve(cnt);
200 for (int i = 0; i < cnt; ++i) {
201 qint64 id;
202 qint64 parentId;
203 QByteArray gid;
205 QByteArray remoteId;
207 stream >> id >> parentId >> gid >> type >> remoteId >> attributes;
208 Protocol::FetchTagsResponse tag;
209 tag.setId(id);
210 tag.setParentId(parentId);
211 tag.setGid(gid);
212 tag.setType(type);
213 tag.setRemoteId(remoteId);
214 tag.setAttributes(attributes);
215 tags.emplace_back(std::move(tag));
216 }
217 return tags;
218}
219
220Protocol::ChangeNotificationPtr ChangeRecorderJournalReader::loadItemNotification(QDataStream &stream, quint64 version)
221{
222 QByteArray resource;
223 QByteArray destinationResource;
224 int operation;
225 int entityCnt;
226 qint64 uid;
227 qint64 parentCollection;
228 qint64 parentDestCollection;
229 QString remoteId;
231 QString remoteRevision;
232 QSet<QByteArray> itemParts;
233 QSet<QByteArray> addedFlags;
234 QSet<QByteArray> removedFlags;
238
239 auto msg = Protocol::ItemChangeNotificationPtr::create();
240
241 if (version == 1) {
242 stream >> operation;
243 stream >> uid;
244 stream >> remoteId;
245 stream >> resource;
246 stream >> parentCollection;
247 stream >> parentDestCollection;
248 stream >> mimeType;
249 stream >> itemParts;
250
251 Protocol::FetchItemsResponse item;
252 item.setId(uid);
253 item.setRemoteId(remoteId);
254 item.setMimeType(mimeType);
255 items.push_back(std::move(item));
256 msg->addMetadata("FETCH_ITEM");
257 } else if (version >= 2) {
258 stream >> operation;
259 stream >> entityCnt;
260 if (version >= 7) {
261 QByteArray ba;
262 qint64 i64;
263 int i;
264 QDateTime dt;
265 QString str;
267 QList<qint64> i64v;
269 int cnt;
270 for (int j = 0; j < entityCnt; ++j) {
271 Protocol::FetchItemsResponse item;
272 stream >> i64;
273 item.setId(i64);
274 stream >> i;
275 item.setRevision(i);
276 stream >> i64;
277 item.setParentId(i64);
278 stream >> str;
279 item.setRemoteId(str);
280 stream >> str;
281 item.setRemoteRevision(str);
282 stream >> str;
283 item.setGid(str);
284 stream >> i64;
285 item.setSize(i64);
286 stream >> str;
287 item.setMimeType(str);
288 stream >> dt;
289 item.setMTime(dt);
290 stream >> bav;
291 item.setFlags(bav);
292 stream >> cnt;
293 item.setTags(loadTags(stream));
294 stream >> i64v;
295 item.setVirtualReferences(i64v);
296 stream >> cnt;
297 for (int k = 0; k < cnt; ++k) {
298 stream >> i64; // left
299 stream >> ba; // left mimetype
300 stream >> i64; // right
301 stream >> ba; // right mimetype
302 stream >> ba; // type
303 stream >> ba; // remoteid
304 }
305 stream >> cnt;
307 for (int k = 0; k < cnt; ++k) {
308 Protocol::Ancestor ancestor;
309 stream >> i64;
310 ancestor.setId(i64);
311 stream >> str;
312 ancestor.setRemoteId(str);
313 stream >> str;
314 ancestor.setName(str);
315 stream >> babaMap;
316 ancestor.setAttributes(babaMap);
317 ancestors << ancestor;
318 }
319 item.setAncestors(ancestors);
320 stream >> cnt;
322 for (int k = 0; k < cnt; ++k) {
323 Protocol::StreamPayloadResponse part;
324 stream >> ba;
325 part.setPayloadName(ba);
326 Protocol::PartMetaData metaData;
327 stream >> ba;
328 metaData.setName(ba);
329 stream >> i64;
330 metaData.setSize(i64);
331 stream >> i;
332 metaData.setVersion(i);
333 stream >> i;
334 metaData.setStorageType(static_cast<Protocol::PartMetaData::StorageType>(i));
335 part.setMetaData(metaData);
336 stream >> ba;
337 part.setData(ba);
338 parts << part;
339 }
340 item.setParts(parts);
341 stream >> bav;
342 item.setCachedParts(bav);
343 items.push_back(std::move(item));
344 }
345 } else {
346 for (int j = 0; j < entityCnt; ++j) {
347 stream >> uid;
348 stream >> remoteId;
349 stream >> remoteRevision;
350 stream >> mimeType;
351 if (stream.status() != QDataStream::Ok) {
352 qCWarning(AKONADICORE_LOG) << "Error reading saved notifications! Aborting";
353 return msg;
354 }
355 Protocol::FetchItemsResponse item;
356 item.setId(uid);
357 item.setRemoteId(remoteId);
358 item.setRemoteRevision(remoteRevision);
359 item.setMimeType(mimeType);
360 items.push_back(std::move(item));
361 }
362 msg->addMetadata("FETCH_ITEM");
363 }
364 stream >> resource;
365 stream >> destinationResource;
366 stream >> parentCollection;
367 stream >> parentDestCollection;
368 stream >> itemParts;
369 stream >> addedFlags;
370 stream >> removedFlags;
371 if (version >= 0xA) {
372 addedTags = loadTags(stream);
373 removedTags = loadTags(stream);
374 } else if (version >= 3) {
375 QSet<qint64> tagIds;
376 stream >> tagIds;
377 for (const auto &tagId : tagIds) {
378 addedTags.emplace_back(tagId);
379 }
380 tagIds.clear();
381 stream >> tagIds;
382 for (const auto &tagId : tagIds) {
383 removedTags.emplace_back(tagId);
384 }
385 }
386 if (version >= 8) {
387 bool boolean;
388 stream >> boolean;
389 msg->setMustRetrieve(boolean);
390 }
391 } else {
392 qCWarning(AKONADICORE_LOG) << "Error version is not correct here" << version;
393 return msg;
394 }
395 if (version >= 5) {
396 msg->setOperation(static_cast<Protocol::ItemChangeNotification::Operation>(operation));
397 } else {
398 msg->setOperation(mapItemOperation(static_cast<LegacyOp>(operation)));
399 }
400 msg->setItems(items);
401 msg->setResource(resource);
402 msg->setDestinationResource(destinationResource);
403 msg->setParentCollection(parentCollection);
404 msg->setParentDestCollection(parentDestCollection);
405 msg->setItemParts(itemParts);
406 msg->setAddedFlags(addedFlags);
407 msg->setRemovedFlags(removedFlags);
408 msg->setAddedTags(addedTags);
409 msg->setRemovedTags(removedTags);
410 return msg;
411}
412
413void saveTags(QDataStream &stream, const QList<Protocol::FetchTagsResponse> &tags)
414{
415 stream << static_cast<int>(tags.count());
416 for (const auto &tag : tags) {
417 stream << tag.id() << tag.parentId() << tag.gid() << tag.type() << tag.remoteId() << tag.attributes();
418 }
419}
420
421void ChangeRecorderJournalWriter::saveItemNotification(QDataStream &stream, const Protocol::ItemChangeNotification &msg)
422{
423 // Version 10
424
425 stream << int(msg.operation());
426 const auto &items = msg.items();
427 stream << static_cast<int>(items.count());
428 for (const auto &item : items) {
429 stream << item.id() << item.revision() << item.parentId() << item.remoteId() << item.remoteRevision() << item.gid() << item.size() << item.mimeType()
430 << item.mTime() << item.flags();
431 saveTags(stream, item.tags());
432 stream << item.virtualReferences();
433 const auto ancestors = item.ancestors();
434 stream << static_cast<int>(ancestors.count());
435 for (const auto &ancestor : ancestors) {
436 stream << ancestor.id() << ancestor.remoteId() << ancestor.name() << ancestor.attributes();
437 }
438 const auto parts = item.parts();
439 stream << static_cast<int>(parts.count());
440 for (const auto &part : parts) {
441 const auto metaData = part.metaData();
442 stream << part.payloadName() << metaData.name() << metaData.size() << metaData.version() << static_cast<int>(metaData.storageType()) << part.data();
443 }
444 stream << item.cachedParts();
445 }
446 stream << msg.resource();
447 stream << msg.destinationResource();
448 stream << quint64(msg.parentCollection());
449 stream << quint64(msg.parentDestCollection());
450 stream << msg.itemParts();
451 stream << msg.addedFlags();
452 stream << msg.removedFlags();
453 saveTags(stream, msg.addedTags());
454 saveTags(stream, msg.removedTags());
455 stream << msg.mustRetrieve();
456}
457
458Protocol::ChangeNotificationPtr ChangeRecorderJournalReader::loadCollectionNotification(QDataStream &stream, quint64 version)
459{
460 QByteArray resource;
461 QByteArray destinationResource;
462 int operation;
463 int entityCnt;
464 quint64 uid;
465 quint64 parentCollection;
466 quint64 parentDestCollection;
467 QString remoteId;
468 QString remoteRevision;
469 QString dummyString;
470 QSet<QByteArray> changedParts;
471 QSet<QByteArray> dummyBa;
472 QSet<qint64> dummyIv;
473
474 auto msg = Protocol::CollectionChangeNotificationPtr::create();
475
476 if (version == 1) {
477 stream >> operation;
478 stream >> uid;
479 stream >> remoteId;
480 stream >> resource;
481 stream >> parentCollection;
482 stream >> parentDestCollection;
483 stream >> dummyString;
484 stream >> changedParts;
485
486 Protocol::FetchCollectionsResponse collection;
487 collection.setId(uid);
488 collection.setRemoteId(remoteId);
489 msg->setCollection(std::move(collection));
490 msg->addMetadata("FETCH_COLLECTION");
491 } else if (version >= 2) {
492 stream >> operation;
493 stream >> entityCnt;
494 if (version >= 7) {
495 QString str;
496 QStringList stringList;
497 qint64 i64;
498 QList<qint64> vb;
500 bool b;
501 int i;
502 Tristate tristate;
503 Protocol::FetchCollectionsResponse collection;
504 stream >> uid;
505 collection.setId(uid);
506 stream >> uid;
507 collection.setParentId(uid);
508 stream >> str;
509 collection.setName(str);
510 stream >> stringList;
511 collection.setMimeTypes(stringList);
512 stream >> str;
513 collection.setRemoteId(str);
514 stream >> str;
515 collection.setRemoteRevision(str);
516 stream >> str;
517 collection.setResource(str);
518
519 Protocol::FetchCollectionStatsResponse stats;
520 stream >> i64;
521 stats.setCount(i64);
522 stream >> i64;
523 stats.setUnseen(i64);
524 stream >> i64;
525 stats.setSize(i64);
526 collection.setStatistics(stats);
527
528 stream >> str;
529 collection.setSearchQuery(str);
530 stream >> vb;
531 collection.setSearchCollections(vb);
532 stream >> entityCnt;
534 for (int j = 0; j < entityCnt; ++j) {
535 Protocol::Ancestor ancestor;
536 stream >> i64;
537 ancestor.setId(i64);
538 stream >> str;
539 ancestor.setRemoteId(str);
540 stream >> str;
541 ancestor.setName(str);
542 stream >> attrs;
543 ancestor.setAttributes(attrs);
544 ancestors.push_back(ancestor);
545
546 if (stream.status() != QDataStream::Ok) {
547 qCWarning(AKONADICORE_LOG) << "Erorr reading saved notifications! Aborting";
548 return msg;
549 }
550 }
551 collection.setAncestors(ancestors);
552
553 Protocol::CachePolicy cachePolicy;
554 stream >> b;
555 cachePolicy.setInherit(b);
556 stream >> i;
557 cachePolicy.setCheckInterval(i);
558 stream >> i;
559 cachePolicy.setCacheTimeout(i);
560 stream >> b;
561 cachePolicy.setSyncOnDemand(b);
562 stream >> stringList;
563 cachePolicy.setLocalParts(stringList);
564 collection.setCachePolicy(cachePolicy);
565
566 stream >> attrs;
567 collection.setAttributes(attrs);
568 stream >> b;
569 collection.setEnabled(b);
570 stream >> reinterpret_cast<qint8 &>(tristate);
571 collection.setDisplayPref(tristate);
572 stream >> reinterpret_cast<qint8 &>(tristate);
573 collection.setSyncPref(tristate);
574 stream >> reinterpret_cast<qint8 &>(tristate);
575 collection.setIndexPref(tristate);
576 stream >> b; // read the deprecated "isReferenced" value
577 stream >> b;
578 collection.setIsVirtual(b);
579
580 msg->setCollection(std::move(collection));
581 } else {
582 for (int j = 0; j < entityCnt; ++j) {
583 stream >> uid;
584 stream >> remoteId;
585 stream >> remoteRevision;
586 stream >> dummyString;
587 if (stream.status() != QDataStream::Ok) {
588 qCWarning(AKONADICORE_LOG) << "Error reading saved notifications! Aborting";
589 return msg;
590 }
591 Protocol::FetchCollectionsResponse collection;
592 collection.setId(uid);
593 collection.setRemoteId(remoteId);
594 collection.setRemoteRevision(remoteRevision);
595 msg->setCollection(std::move(collection));
596 msg->addMetadata("FETCH_COLLECTION");
597 }
598 }
599 stream >> resource;
600 stream >> destinationResource;
601 stream >> parentCollection;
602 stream >> parentDestCollection;
603 stream >> changedParts;
604 stream >> dummyBa;
605 stream >> dummyBa;
606 if (version >= 3) {
607 stream >> dummyIv;
608 stream >> dummyIv;
609 }
610 } else {
611 qCWarning(AKONADICORE_LOG) << "Error version is not correct here" << version;
612 return msg;
613 }
614
615 if (version >= 5) {
616 msg->setOperation(static_cast<Protocol::CollectionChangeNotification::Operation>(operation));
617 } else {
618 msg->setOperation(mapCollectionOperation(static_cast<LegacyOp>(operation)));
619 }
620 msg->setResource(resource);
621 msg->setDestinationResource(destinationResource);
622 msg->setParentCollection(parentCollection);
623 msg->setParentDestCollection(parentDestCollection);
624 msg->setChangedParts(changedParts);
625 return msg;
626}
627
628void Akonadi::ChangeRecorderJournalWriter::saveCollectionNotification(QDataStream &stream, const Protocol::CollectionChangeNotification &msg)
629{
630 // Version 7
631
632 const auto &col = msg.collection();
633
634 stream << int(msg.operation());
635 stream << int(1);
636 stream << col.id();
637 stream << col.parentId();
638 stream << col.name();
639 stream << col.mimeTypes();
640 stream << col.remoteId();
641 stream << col.remoteRevision();
642 stream << col.resource();
643 const auto stats = col.statistics();
644 stream << stats.count();
645 stream << stats.unseen();
646 stream << stats.size();
647 stream << col.searchQuery();
648 stream << col.searchCollections();
649 const auto ancestors = col.ancestors();
650 stream << static_cast<int>(ancestors.count());
651 for (const auto &ancestor : ancestors) {
652 stream << ancestor.id() << ancestor.remoteId() << ancestor.name() << ancestor.attributes();
653 }
654 const auto cachePolicy = col.cachePolicy();
655 stream << cachePolicy.inherit();
656 stream << cachePolicy.checkInterval();
657 stream << cachePolicy.cacheTimeout();
658 stream << cachePolicy.syncOnDemand();
659 stream << cachePolicy.localParts();
660 stream << col.attributes();
661 stream << col.enabled();
662 stream << static_cast<qint8>(col.displayPref());
663 stream << static_cast<qint8>(col.syncPref());
664 stream << static_cast<qint8>(col.indexPref());
665 stream << false; // write the deprecated "isReferenced" value
666 stream << col.isVirtual();
667
668 stream << msg.resource();
669 stream << msg.destinationResource();
670 stream << quint64(msg.parentCollection());
671 stream << quint64(msg.parentDestCollection());
672 stream << msg.changedParts();
673 stream << QSet<QByteArray>();
674 stream << QSet<QByteArray>();
675 stream << QSet<qint64>();
676 stream << QSet<qint64>();
677}
678
679Protocol::ChangeNotificationPtr ChangeRecorderJournalReader::loadTagNotification(QDataStream &stream, quint64 version)
680{
681 QByteArray resource;
682 QByteArray dummyBa;
683 int operation;
684 int entityCnt;
685 quint64 uid;
686 quint64 dummyI;
687 QString remoteId;
688 QString dummyString;
689 QSet<QByteArray> dummyBaV;
690 QSet<qint64> dummyIv;
691
692 auto msg = Protocol::TagChangeNotificationPtr::create();
693
694 if (version == 1) {
695 stream >> operation;
696 stream >> uid;
697 stream >> remoteId;
698 stream >> dummyBa;
699 stream >> dummyI;
700 stream >> dummyI;
701 stream >> dummyString;
702 stream >> dummyBaV;
703
704 Protocol::FetchTagsResponse tag;
705 tag.setId(uid);
706 tag.setRemoteId(remoteId.toLatin1());
707 msg->setTag(std::move(tag));
708 msg->addMetadata("FETCH_TAG");
709 } else if (version >= 2) {
710 stream >> operation;
711 stream >> entityCnt;
712 if (version >= 7) {
713 QByteArray ba;
715
716 Protocol::FetchTagsResponse tag;
717
718 stream >> uid;
719 tag.setId(uid);
720 stream >> ba;
721 tag.setParentId(uid);
722 stream >> attrs;
723 tag.setGid(ba);
724 stream >> ba;
725 tag.setType(ba);
726 stream >> uid;
727 tag.setRemoteId(ba);
728 stream >> ba;
729 tag.setAttributes(attrs);
730 msg->setTag(std::move(tag));
731
732 stream >> resource;
733 } else {
734 for (int j = 0; j < entityCnt; ++j) {
735 stream >> uid;
736 stream >> remoteId;
737 stream >> dummyString;
738 stream >> dummyString;
739 if (stream.status() != QDataStream::Ok) {
740 qCWarning(AKONADICORE_LOG) << "Error reading saved notifications! Aborting";
741 return msg;
742 }
743 Protocol::FetchTagsResponse tag;
744 tag.setId(uid);
745 tag.setRemoteId(remoteId.toLatin1());
746 msg->setTag(std::move(tag));
747 msg->addMetadata("FETCH_TAG");
748 }
749 stream >> resource;
750 stream >> dummyBa;
751 stream >> dummyI;
752 stream >> dummyI;
753 stream >> dummyBaV;
754 stream >> dummyBaV;
755 stream >> dummyBaV;
756 if (version >= 3) {
757 stream >> dummyIv;
758 stream >> dummyIv;
759 }
760 }
761 if (version >= 5) {
762 msg->setOperation(static_cast<Protocol::TagChangeNotification::Operation>(operation));
763 } else {
764 msg->setOperation(mapTagOperation(static_cast<LegacyOp>(operation)));
765 }
766 }
767 msg->setResource(resource);
768 return msg;
769}
770
771void Akonadi::ChangeRecorderJournalWriter::saveTagNotification(QDataStream &stream, const Protocol::TagChangeNotification &msg)
772{
773 const auto &tag = msg.tag();
774 stream << int(msg.operation());
775 stream << int(1);
776 stream << tag.id();
777 stream << tag.parentId();
778 stream << tag.gid();
779 stream << tag.type();
780 stream << tag.remoteId();
781 stream << tag.attributes();
782 stream << msg.resource();
783}
784
785Protocol::ChangeNotificationPtr ChangeRecorderJournalReader::loadRelationNotification(QDataStream &stream, quint64 version)
786{
787 // NOTE: While relations have been deprecated and removed from Akonadi, we still need to support reading them from
788 // the journal, otherwise we would not be able to read old journals.
789
790 QByteArray dummyBa;
791 int operation;
792 int entityCnt;
793 quint64 dummyI;
794 QString dummyString;
795 QSet<QByteArray> itemParts;
796 QSet<QByteArray> dummyBaV;
797 QSet<qint64> dummyIv;
798
799 if (version == 1) {
800 qCWarning(AKONADICORE_LOG) << "Invalid version of relation notification";
801 return {};
802 } else if (version >= 2) {
803 stream >> operation;
804 stream >> entityCnt;
805 if (version >= 7) {
806 stream >> dummyI; // left
807 stream >> dummyBa; // left mimetype
808 stream >> dummyI; // right
809 stream >> dummyBa; // right mimetype
810 stream >> dummyBa; // remoteid
811 stream >> dummyBa; // type
812 } else {
813 for (int j = 0; j < entityCnt; ++j) {
814 stream >> dummyI;
815 stream >> dummyString;
816 stream >> dummyString;
817 stream >> dummyString;
818 if (stream.status() != QDataStream::Ok) {
819 qCWarning(AKONADICORE_LOG) << "Error reading saved notifications! Aborting";
820 return {};
821 }
822 }
823 stream >> dummyBa;
824 if (version == 5) {
825 // there was a bug in version 5 serializer that serialized this
826 // field as qint64 (8 bytes) instead of empty QByteArray (which is
827 // 4 bytes)
828 stream >> dummyI;
829 } else {
830 stream >> dummyBa;
831 }
832 stream >> dummyI;
833 stream >> dummyI;
834 stream >> itemParts;
835 stream >> dummyBaV;
836 stream >> dummyBaV;
837 if (version >= 3) {
838 stream >> dummyIv;
839 stream >> dummyIv;
840 }
841 }
842 }
843
844 return {};
845}
846
847Protocol::ItemChangeNotification::Operation ChangeRecorderJournalReader::mapItemOperation(LegacyOp op)
848{
849 switch (op) {
850 case Add:
851 return Protocol::ItemChangeNotification::Add;
852 case Modify:
853 return Protocol::ItemChangeNotification::Modify;
854 case Move:
855 return Protocol::ItemChangeNotification::Move;
856 case Remove:
857 return Protocol::ItemChangeNotification::Remove;
858 case Link:
859 return Protocol::ItemChangeNotification::Link;
860 case Unlink:
861 return Protocol::ItemChangeNotification::Unlink;
862 case ModifyFlags:
863 return Protocol::ItemChangeNotification::ModifyFlags;
864 case ModifyTags:
865 return Protocol::ItemChangeNotification::ModifyTags;
866 case ModifyRelations:
867 [[fallthrough]];
868 default:
869 qWarning() << "Unexpected operation type in item notification";
870 return Protocol::ItemChangeNotification::InvalidOp;
871 }
872}
873
874Protocol::CollectionChangeNotification::Operation ChangeRecorderJournalReader::mapCollectionOperation(LegacyOp op)
875{
876 switch (op) {
877 case Add:
878 return Protocol::CollectionChangeNotification::Add;
879 case Modify:
880 return Protocol::CollectionChangeNotification::Modify;
881 case Move:
882 return Protocol::CollectionChangeNotification::Move;
883 case Remove:
884 return Protocol::CollectionChangeNotification::Remove;
885 case Subscribe:
886 return Protocol::CollectionChangeNotification::Subscribe;
887 case Unsubscribe:
888 return Protocol::CollectionChangeNotification::Unsubscribe;
889 default:
890 qCWarning(AKONADICORE_LOG) << "Unexpected operation type in collection notification";
891 return Protocol::CollectionChangeNotification::InvalidOp;
892 }
893}
894
895Protocol::TagChangeNotification::Operation ChangeRecorderJournalReader::mapTagOperation(LegacyOp op)
896{
897 switch (op) {
898 case Add:
899 return Protocol::TagChangeNotification::Add;
900 case Modify:
901 return Protocol::TagChangeNotification::Modify;
902 case Remove:
903 return Protocol::TagChangeNotification::Remove;
904 default:
905 qCWarning(AKONADICORE_LOG) << "Unexpected operation type in tag notification";
906 return Protocol::TagChangeNotification::InvalidOp;
907 }
908}
909
910ChangeRecorderJournalReader::LegacyType ChangeRecorderJournalWriter::mapToLegacyType(Protocol::Command::Type type)
911{
912 switch (type) {
913 case Protocol::Command::ItemChangeNotification:
914 return ChangeRecorderJournalReader::Item;
915 case Protocol::Command::CollectionChangeNotification:
916 return ChangeRecorderJournalReader::Collection;
917 case Protocol::Command::TagChangeNotification:
918 return ChangeRecorderJournalReader::Tag;
919 default:
920 qCWarning(AKONADICORE_LOG) << "Unexpected notification type";
921 return ChangeRecorderJournalReader::InvalidType;
922 }
923}
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()
VehicleSection::Type type(QStringView coachNumber, QStringView coachClassification)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
NETWORKMANAGERQT_EXPORT QString version()
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 reserve(qsizetype size)
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-2025 The KDE developers.
Generated on Fri Jan 24 2025 11:49:56 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.