8#include "akonadicore_debug.h"
9#include "changerecorderjournal_p.h"
20constexpr quint64 s_currentVersion = Q_UINT64_C(0x000800000000);
21constexpr quint64 s_versionMask = Q_UINT64_C(0xFFFF00000000);
22constexpr quint64 s_sizeMask = Q_UINT64_C(0x0000FFFFFFFF);
27 switch (
static_cast<LegacyType
>(settings->
value(QStringLiteral(
"type")).toInt())) {
29 return loadQSettingsItemNotification(settings);
31 return loadQSettingsCollectionNotification(settings);
36 qWarning() <<
"Unexpected notification type in legacy store";
51 quint64 sizeAndVersion;
52 stream >> sizeAndVersion;
54 const quint64 size = sizeAndVersion & s_sizeMask;
55 const quint64
version = (sizeAndVersion & s_versionMask) >> 32;
57 quint64 startOffset = 0;
59 stream >> startOffset;
64 needsFullSave = startOffset > 0 ||
version == 0;
66 for (quint64 i = 0; i < size && !stream.atEnd(); ++i) {
72 qCWarning(AKONADICORE_LOG) <<
"Error reading saved notifications! Aborting. Corrupt file:" << device->
fileName();
76 switch (
static_cast<LegacyType
>(type)) {
78 msg = loadItemNotification(stream, version);
81 msg = loadCollectionNotification(stream, version);
84 msg = loadTagNotification(stream, version);
87 msg = loadRelationNotification(stream, version);
90 qCWarning(AKONADICORE_LOG) <<
"Unknown notification type";
94 if (i < startOffset) {
98 if (msg && msg->isValid()) {
99 msg->setSessionId(sessionId);
112 const quint64 countAndVersion =
static_cast<quint64
>(notifications.
count()) | s_currentVersion;
117 stream << countAndVersion;
118 stream << quint64(0);
122 for (
int i = 0; i < notifications.
count(); ++i) {
128 stream << msg->sessionId();
129 stream << int(mapToLegacyType(msg->type()));
130 switch (msg->type()) {
131 case Protocol::Command::ItemChangeNotification:
132 saveItemNotification(stream, Protocol::cmdCast<Protocol::ItemChangeNotification>(msg));
134 case Protocol::Command::CollectionChangeNotification:
135 saveCollectionNotification(stream, Protocol::cmdCast<Protocol::CollectionChangeNotification>(msg));
137 case Protocol::Command::TagChangeNotification:
138 saveTagNotification(stream, Protocol::cmdCast<Protocol::TagChangeNotification>(msg));
140 case Protocol::Command::RelationChangeNotification:
141 saveRelationNotification(stream, Protocol::cmdCast<Protocol::RelationChangeNotification>(msg));
144 qCWarning(AKONADICORE_LOG) <<
"Unexpected type?";
152 auto msg = Protocol::ItemChangeNotificationPtr::create();
153 msg->setSessionId(settings->
value(QStringLiteral(
"sessionId")).toByteArray());
154 msg->setOperation(mapItemOperation(
static_cast<LegacyOp
>(settings->
value(QStringLiteral(
"op")).toInt())));
155 Protocol::FetchItemsResponse item;
156 item.setId(settings->
value(QStringLiteral(
"uid")).toLongLong());
157 item.setRemoteId(settings->
value(QStringLiteral(
"rid")).
toString());
158 item.setMimeType(settings->
value(QStringLiteral(
"mimeType")).
toString());
159 msg->setItems({std::move(item)});
160 msg->addMetadata(
"FETCH_ITEM");
161 msg->setResource(settings->
value(QStringLiteral(
"resource")).
toByteArray());
162 msg->setParentCollection(settings->
value(QStringLiteral(
"parentCol")).
toLongLong());
163 msg->setParentDestCollection(settings->
value(QStringLiteral(
"parentDestCol")).
toLongLong());
167 itemParts.
insert(entry.toLatin1());
169 msg->setItemParts(itemParts);
175 auto msg = Protocol::CollectionChangeNotificationPtr::create();
176 msg->setSessionId(settings->
value(QStringLiteral(
"sessionId")).toByteArray());
177 msg->setOperation(mapCollectionOperation(
static_cast<LegacyOp
>(settings->
value(QStringLiteral(
"op")).toInt())));
178 Protocol::FetchCollectionsResponse collection;
179 collection.setId(settings->
value(QStringLiteral(
"uid")).toLongLong());
180 collection.setRemoteId(settings->
value(QStringLiteral(
"rid")).
toString());
181 msg->setCollection(std::move(collection));
182 msg->addMetadata(
"FETCH_COLLECTION");
183 msg->setResource(settings->
value(QStringLiteral(
"resource")).toByteArray());
184 msg->setParentCollection(settings->
value(QStringLiteral(
"parentCol")).toLongLong());
185 msg->setParentDestCollection(settings->
value(QStringLiteral(
"parentDestCol")).toLongLong());
189 changedParts.
insert(entry.toLatin1());
191 msg->setChangedParts(changedParts);
198 auto iter = flags.
begin();
199 while (iter != flags.
end()) {
200 if (iter->startsWith(
"RELATION")) {
202 Q_ASSERT(parts.
size() == 4);
203 Protocol::ItemChangeNotification::Relation relation;
205 relation.leftId = parts[2].toLongLong();
206 relation.rightId = parts[3].toLongLong();
207 relations.
insert(relation);
208 iter = flags.
erase(iter);
224 qint64 parentCollection;
225 qint64 parentDestCollection;
236 auto msg = Protocol::ItemChangeNotificationPtr::create();
243 stream >> parentCollection;
244 stream >> parentDestCollection;
248 Protocol::FetchItemsResponse item;
250 item.setRemoteId(remoteId);
251 item.setMimeType(mimeType);
253 msg->addMetadata(
"FETCH_ITEM");
254 }
else if (version >= 2) {
267 for (
int j = 0; j < entityCnt; ++j) {
268 Protocol::FetchItemsResponse item;
274 item.setParentId(i64);
276 item.setRemoteId(str);
278 item.setRemoteRevision(str);
284 item.setMimeType(str);
292 for (
int k = 0; k < cnt; ++k) {
293 Protocol::FetchTagsResponse tag;
297 tag.setParentId(i64);
305 tag.setAttributes(babaMap);
310 item.setVirtualReferences(i64v);
313 for (
int k = 0; k < cnt; ++k) {
314 Protocol::FetchRelationsResponse relation;
316 relation.setLeft(i64);
318 relation.setLeftMimeType(ba);
320 relation.setRight(i64);
322 relation.setRightMimeType(ba);
324 relation.setType(ba);
326 relation.setRemoteId(ba);
327 relations << relation;
329 item.setRelations(relations);
332 for (
int k = 0; k < cnt; ++k) {
333 Protocol::Ancestor ancestor;
337 ancestor.setRemoteId(str);
339 ancestor.setName(str);
341 ancestor.setAttributes(babaMap);
342 ancestors << ancestor;
344 item.setAncestors(ancestors);
347 for (
int k = 0; k < cnt; ++k) {
348 Protocol::StreamPayloadResponse part;
350 part.setPayloadName(ba);
351 Protocol::PartMetaData metaData;
353 metaData.setName(ba);
355 metaData.setSize(i64);
359 metaData.setStorageType(
static_cast<Protocol::PartMetaData::StorageType
>(i));
360 part.setMetaData(metaData);
365 item.setParts(parts);
367 item.setCachedParts(bav);
371 for (
int j = 0; j < entityCnt; ++j) {
374 stream >> remoteRevision;
377 qCWarning(AKONADICORE_LOG) <<
"Error reading saved notifications! Aborting";
380 Protocol::FetchItemsResponse item;
382 item.setRemoteId(remoteId);
383 item.setRemoteRevision(remoteRevision);
384 item.setMimeType(mimeType);
387 msg->addMetadata(
"FETCH_ITEM");
390 stream >> destinationResource;
391 stream >> parentCollection;
392 stream >> parentDestCollection;
394 stream >> addedFlags;
395 stream >> removedFlags;
398 stream >> removedTags;
403 msg->setMustRetrieve(
boolean);
406 qCWarning(AKONADICORE_LOG) <<
"Error version is not correct here" <<
version;
410 msg->setOperation(
static_cast<Protocol::ItemChangeNotification::Operation
>(operation));
412 msg->setOperation(mapItemOperation(
static_cast<LegacyOp
>(operation)));
414 msg->setItems(items);
415 msg->setResource(resource);
416 msg->setDestinationResource(destinationResource);
417 msg->setParentCollection(parentCollection);
418 msg->setParentDestCollection(parentDestCollection);
419 msg->setItemParts(itemParts);
420 msg->setAddedRelations(extractRelations(addedFlags));
421 msg->setAddedFlags(addedFlags);
422 msg->setRemovedRelations(extractRelations(removedFlags));
423 msg->setRemovedFlags(removedFlags);
424 msg->setAddedTags(addedTags);
425 msg->setRemovedTags(removedTags);
432 for (
const auto &rel : relations) {
438void ChangeRecorderJournalWriter::saveItemNotification(
QDataStream &stream,
const Protocol::ItemChangeNotification &msg)
442 stream << int(msg.operation());
443 const auto &items = msg.items();
444 stream << static_cast<int>(items.
count());
445 for (
const auto &item : items) {
446 stream << item.id() << item.revision() << item.parentId() << item.remoteId() << item.remoteRevision() << item.gid() << item.size() << item.mimeType()
447 << item.mTime() << item.flags();
448 const auto tags = item.tags();
449 stream << static_cast<int>(tags.
count());
450 for (
const auto &tag : tags) {
451 stream << tag.id() << tag.parentId() << tag.gid() << tag.type() << tag.remoteId() << tag.attributes();
453 stream << item.virtualReferences();
454 const auto relations = item.relations();
455 stream << static_cast<int>(relations.
count());
456 for (
const auto &relation : relations) {
457 stream << relation.left() << relation.leftMimeType() << relation.right() << relation.rightMimeType() << relation.type() << relation.remoteId();
459 const auto ancestors = item.ancestors();
460 stream << static_cast<int>(ancestors.
count());
461 for (
const auto &ancestor : ancestors) {
462 stream << ancestor.id() << ancestor.remoteId() << ancestor.name() << ancestor.attributes();
464 const auto parts = item.parts();
465 stream << static_cast<int>(parts.
count());
466 for (
const auto &part : parts) {
467 const auto metaData = part.metaData();
468 stream << part.payloadName() << metaData.name() << metaData.size() << metaData.
version() <<
static_cast<int>(metaData.storageType()) << part.data();
470 stream << item.cachedParts();
472 stream << msg.resource();
473 stream << msg.destinationResource();
474 stream << quint64(msg.parentCollection());
475 stream << quint64(msg.parentDestCollection());
476 stream << msg.itemParts();
477 stream << msg.addedFlags() + encodeRelations(msg.addedRelations());
478 stream << msg.removedFlags() + encodeRelations(msg.removedRelations());
479 stream << msg.addedTags();
480 stream << msg.removedTags();
481 stream << msg.mustRetrieve();
491 quint64 parentCollection;
492 quint64 parentDestCollection;
500 auto msg = Protocol::CollectionChangeNotificationPtr::create();
507 stream >> parentCollection;
508 stream >> parentDestCollection;
509 stream >> dummyString;
510 stream >> changedParts;
512 Protocol::FetchCollectionsResponse collection;
513 collection.setId(uid);
514 collection.setRemoteId(remoteId);
515 msg->setCollection(std::move(collection));
516 msg->addMetadata(
"FETCH_COLLECTION");
517 }
else if (version >= 2) {
529 Protocol::FetchCollectionsResponse collection;
531 collection.setId(uid);
533 collection.setParentId(uid);
535 collection.setName(str);
536 stream >> stringList;
537 collection.setMimeTypes(stringList);
539 collection.setRemoteId(str);
541 collection.setRemoteRevision(str);
543 collection.setResource(str);
545 Protocol::FetchCollectionStatsResponse stats;
549 stats.setUnseen(i64);
552 collection.setStatistics(stats);
555 collection.setSearchQuery(str);
557 collection.setSearchCollections(vb);
560 for (
int j = 0; j < entityCnt; ++j) {
561 Protocol::Ancestor ancestor;
565 ancestor.setRemoteId(str);
567 ancestor.setName(str);
569 ancestor.setAttributes(attrs);
573 qCWarning(AKONADICORE_LOG) <<
"Erorr reading saved notifications! Aborting";
577 collection.setAncestors(ancestors);
579 Protocol::CachePolicy cachePolicy;
581 cachePolicy.setInherit(b);
583 cachePolicy.setCheckInterval(i);
585 cachePolicy.setCacheTimeout(i);
587 cachePolicy.setSyncOnDemand(b);
588 stream >> stringList;
589 cachePolicy.setLocalParts(stringList);
590 collection.setCachePolicy(cachePolicy);
593 collection.setAttributes(attrs);
595 collection.setEnabled(b);
596 stream >>
reinterpret_cast<qint8 &
>(
tristate);
597 collection.setDisplayPref(
tristate);
598 stream >>
reinterpret_cast<qint8 &
>(
tristate);
600 stream >>
reinterpret_cast<qint8 &
>(
tristate);
604 collection.setIsVirtual(b);
606 msg->setCollection(std::move(collection));
608 for (
int j = 0; j < entityCnt; ++j) {
611 stream >> remoteRevision;
612 stream >> dummyString;
614 qCWarning(AKONADICORE_LOG) <<
"Error reading saved notifications! Aborting";
617 Protocol::FetchCollectionsResponse collection;
618 collection.setId(uid);
619 collection.setRemoteId(remoteId);
620 collection.setRemoteRevision(remoteRevision);
621 msg->setCollection(std::move(collection));
622 msg->addMetadata(
"FETCH_COLLECTION");
626 stream >> destinationResource;
627 stream >> parentCollection;
628 stream >> parentDestCollection;
629 stream >> changedParts;
637 qCWarning(AKONADICORE_LOG) <<
"Error version is not correct here" <<
version;
642 msg->setOperation(
static_cast<Protocol::CollectionChangeNotification::Operation
>(operation));
644 msg->setOperation(mapCollectionOperation(
static_cast<LegacyOp
>(operation)));
646 msg->setResource(resource);
647 msg->setDestinationResource(destinationResource);
648 msg->setParentCollection(parentCollection);
649 msg->setParentDestCollection(parentDestCollection);
650 msg->setChangedParts(changedParts);
654void Akonadi::ChangeRecorderJournalWriter::saveCollectionNotification(
QDataStream &stream,
const Protocol::CollectionChangeNotification &msg)
658 const auto &col = msg.collection();
660 stream << int(msg.operation());
663 stream << col.parentId();
664 stream << col.name();
665 stream << col.mimeTypes();
666 stream << col.remoteId();
667 stream << col.remoteRevision();
668 stream << col.resource();
669 const auto stats = col.statistics();
670 stream << stats.count();
671 stream << stats.unseen();
672 stream << stats.size();
673 stream << col.searchQuery();
674 stream << col.searchCollections();
675 const auto ancestors = col.ancestors();
676 stream << static_cast<int>(ancestors.
count());
677 for (
const auto &ancestor : ancestors) {
678 stream << ancestor.id() << ancestor.remoteId() << ancestor.name() << ancestor.attributes();
680 const auto cachePolicy = col.cachePolicy();
681 stream << cachePolicy.inherit();
682 stream << cachePolicy.checkInterval();
683 stream << cachePolicy.cacheTimeout();
684 stream << cachePolicy.syncOnDemand();
685 stream << cachePolicy.localParts();
686 stream << col.attributes();
687 stream << col.enabled();
688 stream << static_cast<qint8>(col.displayPref());
689 stream << static_cast<qint8>(col.syncPref());
690 stream << static_cast<qint8>(col.indexPref());
692 stream << col.isVirtual();
694 stream << msg.resource();
695 stream << msg.destinationResource();
696 stream << quint64(msg.parentCollection());
697 stream << quint64(msg.parentDestCollection());
698 stream << msg.changedParts();
699 stream << QSet<QByteArray>();
700 stream << QSet<QByteArray>();
701 stream << QSet<qint64>();
702 stream << QSet<qint64>();
718 auto msg = Protocol::TagChangeNotificationPtr::create();
727 stream >> dummyString;
730 Protocol::FetchTagsResponse tag;
732 tag.setRemoteId(remoteId.toLatin1());
733 msg->setTag(std::move(tag));
734 msg->addMetadata(
"FETCH_TAG");
735 }
else if (version >= 2) {
742 Protocol::FetchTagsResponse tag;
747 tag.setParentId(uid);
755 tag.setAttributes(attrs);
756 msg->setTag(std::move(tag));
760 for (
int j = 0; j < entityCnt; ++j) {
763 stream >> dummyString;
764 stream >> dummyString;
766 qCWarning(AKONADICORE_LOG) <<
"Error reading saved notifications! Aborting";
769 Protocol::FetchTagsResponse tag;
771 tag.setRemoteId(remoteId.toLatin1());
772 msg->setTag(std::move(tag));
773 msg->addMetadata(
"FETCH_TAG");
788 msg->setOperation(
static_cast<Protocol::TagChangeNotification::Operation
>(operation));
790 msg->setOperation(mapTagOperation(
static_cast<LegacyOp
>(operation)));
793 msg->setResource(resource);
797void Akonadi::ChangeRecorderJournalWriter::saveTagNotification(
QDataStream &stream,
const Protocol::TagChangeNotification &msg)
799 const auto &tag = msg.tag();
800 stream << int(msg.operation());
803 stream << tag.parentId();
805 stream << tag.type();
806 stream << tag.remoteId();
807 stream << tag.attributes();
808 stream << msg.resource();
822 auto msg = Protocol::RelationChangeNotificationPtr::create();
825 qCWarning(AKONADICORE_LOG) <<
"Invalid version of relation notification";
827 }
else if (version >= 2) {
831 Protocol::FetchRelationsResponse relation;
835 relation.setLeft(i64);
837 relation.setLeftMimeType(ba);
839 relation.setRight(i64);
841 relation.setRightMimeType(ba);
843 relation.setRemoteId(ba);
845 relation.setType(ba);
847 msg->setRelation(std::move(relation));
850 for (
int j = 0; j < entityCnt; ++j) {
852 stream >> dummyString;
853 stream >> dummyString;
854 stream >> dummyString;
856 qCWarning(AKONADICORE_LOG) <<
"Error reading saved notifications! Aborting";
879 Protocol::FetchRelationsResponse relation;
885 if (p[0] ==
"LEFT") {
886 relation.setLeft(p[1].toLongLong());
887 }
else if (p[0] ==
"RIGHT") {
888 relation.setRight(p[1].toLongLong());
889 }
else if (p[0] ==
"RID") {
890 relation.setRemoteId(p[1]);
891 }
else if (p[0] ==
"TYPE") {
892 relation.setType(p[1]);
895 msg->setRelation(std::move(relation));
898 msg->setOperation(
static_cast<Protocol::RelationChangeNotification::Operation
>(operation));
900 msg->setOperation(mapRelationOperation(
static_cast<LegacyOp
>(operation)));
907void Akonadi::ChangeRecorderJournalWriter::saveRelationNotification(
QDataStream &stream,
const Protocol::RelationChangeNotification &msg)
909 const auto &rel = msg.relation();
910 stream << int(msg.operation());
912 stream << rel.left();
913 stream << rel.leftMimeType();
914 stream << rel.right();
915 stream << rel.rightMimeType();
916 stream << rel.remoteId();
917 stream << rel.type();
920Protocol::ItemChangeNotification::Operation ChangeRecorderJournalReader::mapItemOperation(LegacyOp op)
924 return Protocol::ItemChangeNotification::Add;
926 return Protocol::ItemChangeNotification::Modify;
928 return Protocol::ItemChangeNotification::Move;
930 return Protocol::ItemChangeNotification::Remove;
932 return Protocol::ItemChangeNotification::Link;
934 return Protocol::ItemChangeNotification::Unlink;
936 return Protocol::ItemChangeNotification::ModifyFlags;
938 return Protocol::ItemChangeNotification::ModifyTags;
939 case ModifyRelations:
940 return Protocol::ItemChangeNotification::ModifyRelations;
942 qWarning() <<
"Unexpected operation type in item notification";
943 return Protocol::ItemChangeNotification::InvalidOp;
947Protocol::CollectionChangeNotification::Operation ChangeRecorderJournalReader::mapCollectionOperation(LegacyOp op)
951 return Protocol::CollectionChangeNotification::Add;
953 return Protocol::CollectionChangeNotification::Modify;
955 return Protocol::CollectionChangeNotification::Move;
957 return Protocol::CollectionChangeNotification::Remove;
959 return Protocol::CollectionChangeNotification::Subscribe;
961 return Protocol::CollectionChangeNotification::Unsubscribe;
963 qCWarning(AKONADICORE_LOG) <<
"Unexpected operation type in collection notification";
964 return Protocol::CollectionChangeNotification::InvalidOp;
968Protocol::TagChangeNotification::Operation ChangeRecorderJournalReader::mapTagOperation(LegacyOp op)
972 return Protocol::TagChangeNotification::Add;
974 return Protocol::TagChangeNotification::Modify;
976 return Protocol::TagChangeNotification::Remove;
978 qCWarning(AKONADICORE_LOG) <<
"Unexpected operation type in tag notification";
979 return Protocol::TagChangeNotification::InvalidOp;
983Protocol::RelationChangeNotification::Operation ChangeRecorderJournalReader::mapRelationOperation(LegacyOp op)
987 return Protocol::RelationChangeNotification::Add;
989 return Protocol::RelationChangeNotification::Remove;
991 qCWarning(AKONADICORE_LOG) <<
"Unexpected operation type in relation notification";
992 return Protocol::RelationChangeNotification::InvalidOp;
996ChangeRecorderJournalReader::LegacyType ChangeRecorderJournalWriter::mapToLegacyType(Protocol::Command::Type type)
999 case Protocol::Command::ItemChangeNotification:
1000 return ChangeRecorderJournalReader::Item;
1001 case Protocol::Command::CollectionChangeNotification:
1002 return ChangeRecorderJournalReader::Collection;
1003 case Protocol::Command::TagChangeNotification:
1004 return ChangeRecorderJournalReader::Tag;
1005 case Protocol::Command::RelationChangeNotification:
1006 return ChangeRecorderJournalReader::Relation;
1008 qCWarning(AKONADICORE_LOG) <<
"Unexpected notification type";
1009 return ChangeRecorderJournalReader::InvalidType;
Represents a collection of PIM items.
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)
A glue between Qt and the standard library.
QByteArray number(double n, char format, int precision)
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)
qsizetype size() const const
qsizetype count() const const
iterator erase(const_iterator pos)
iterator insert(const T &value)
QVariant value(QAnyStringView key) const const
QString fromLatin1(QByteArrayView str)
QByteArray toByteArray() const const
qlonglong toLongLong(bool *ok) const const
QStringList toStringList() const const