File indexing completed on 2024-11-10 04:40:38
0001 /* 0002 SPDX-FileCopyrightText: 2007 Volker Krause <vkrause@kde.org> 0003 SPDX-FileCopyrightText: 2018 Daniel Vrátil <dvratil@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "akonadicore_debug.h" 0009 #include "changerecorderjournal_p.h" 0010 0011 #include <QDataStream> 0012 #include <QFile> 0013 #include <QQueue> 0014 #include <QSettings> 0015 0016 using namespace Akonadi; 0017 0018 namespace 0019 { 0020 constexpr quint64 s_currentVersion = Q_UINT64_C(0x000800000000); 0021 constexpr quint64 s_versionMask = Q_UINT64_C(0xFFFF00000000); 0022 constexpr quint64 s_sizeMask = Q_UINT64_C(0x0000FFFFFFFF); 0023 } 0024 0025 Protocol::ChangeNotificationPtr ChangeRecorderJournalReader::loadQSettingsNotification(QSettings *settings) 0026 { 0027 switch (static_cast<LegacyType>(settings->value(QStringLiteral("type")).toInt())) { 0028 case Item: 0029 return loadQSettingsItemNotification(settings); 0030 case Collection: 0031 return loadQSettingsCollectionNotification(settings); 0032 case Tag: 0033 case Relation: 0034 case InvalidType: 0035 default: 0036 qWarning() << "Unexpected notification type in legacy store"; 0037 return {}; 0038 } 0039 } 0040 0041 QQueue<Protocol::ChangeNotificationPtr> ChangeRecorderJournalReader::loadFrom(QFile *device, bool &needsFullSave) 0042 { 0043 QDataStream stream(device); 0044 stream.setVersion(QDataStream::Qt_4_6); 0045 0046 QByteArray sessionId; 0047 int type; 0048 0049 QQueue<Protocol::ChangeNotificationPtr> list; 0050 0051 quint64 sizeAndVersion; 0052 stream >> sizeAndVersion; 0053 0054 const quint64 size = sizeAndVersion & s_sizeMask; 0055 const quint64 version = (sizeAndVersion & s_versionMask) >> 32; 0056 0057 quint64 startOffset = 0; 0058 if (version >= 1) { 0059 stream >> startOffset; 0060 } 0061 0062 // If we skip the first N items, then we'll need to rewrite the file on saving. 0063 // Also, if the file is old, it needs to be rewritten. 0064 needsFullSave = startOffset > 0 || version == 0; 0065 0066 for (quint64 i = 0; i < size && !stream.atEnd(); ++i) { 0067 Protocol::ChangeNotificationPtr msg; 0068 stream >> sessionId; 0069 stream >> type; 0070 0071 if (stream.status() != QDataStream::Ok) { 0072 qCWarning(AKONADICORE_LOG) << "Error reading saved notifications! Aborting. Corrupt file:" << device->fileName(); 0073 break; 0074 } 0075 0076 switch (static_cast<LegacyType>(type)) { 0077 case Item: 0078 msg = loadItemNotification(stream, version); 0079 break; 0080 case Collection: 0081 msg = loadCollectionNotification(stream, version); 0082 break; 0083 case Tag: 0084 msg = loadTagNotification(stream, version); 0085 break; 0086 case Relation: 0087 msg = loadRelationNotification(stream, version); 0088 break; 0089 default: 0090 qCWarning(AKONADICORE_LOG) << "Unknown notification type"; 0091 break; 0092 } 0093 0094 if (i < startOffset) { 0095 continue; 0096 } 0097 0098 if (msg && msg->isValid()) { 0099 msg->setSessionId(sessionId); 0100 list << msg; 0101 } 0102 } 0103 0104 return list; 0105 } 0106 0107 void ChangeRecorderJournalWriter::saveTo(const QQueue<Protocol::ChangeNotificationPtr> ¬ifications, QIODevice *device) 0108 { 0109 // Version 0 of this file format was writing a quint64 count, followed by the notifications. 0110 // Version 1 bundles a version number into that quint64, to be able to detect a version number at load time. 0111 0112 const quint64 countAndVersion = static_cast<quint64>(notifications.count()) | s_currentVersion; 0113 0114 QDataStream stream(device); 0115 stream.setVersion(QDataStream::Qt_4_6); 0116 0117 stream << countAndVersion; 0118 stream << quint64(0); // no start offset 0119 0120 // qCDebug(AKONADICORE_LOG) << "Saving" << pendingNotifications.count() << "notifications (full save)"; 0121 0122 for (int i = 0; i < notifications.count(); ++i) { 0123 const Protocol::ChangeNotificationPtr &msg = notifications.at(i); 0124 0125 // We deliberately don't use Factory::serialize(), because the internal 0126 // serialization format could change at any point 0127 0128 stream << msg->sessionId(); 0129 stream << int(mapToLegacyType(msg->type())); 0130 switch (msg->type()) { 0131 case Protocol::Command::ItemChangeNotification: 0132 saveItemNotification(stream, Protocol::cmdCast<Protocol::ItemChangeNotification>(msg)); 0133 break; 0134 case Protocol::Command::CollectionChangeNotification: 0135 saveCollectionNotification(stream, Protocol::cmdCast<Protocol::CollectionChangeNotification>(msg)); 0136 break; 0137 case Protocol::Command::TagChangeNotification: 0138 saveTagNotification(stream, Protocol::cmdCast<Protocol::TagChangeNotification>(msg)); 0139 break; 0140 case Protocol::Command::RelationChangeNotification: 0141 saveRelationNotification(stream, Protocol::cmdCast<Protocol::RelationChangeNotification>(msg)); 0142 break; 0143 default: 0144 qCWarning(AKONADICORE_LOG) << "Unexpected type?"; 0145 return; 0146 } 0147 } 0148 } 0149 0150 Protocol::ChangeNotificationPtr ChangeRecorderJournalReader::loadQSettingsItemNotification(QSettings *settings) 0151 { 0152 auto msg = Protocol::ItemChangeNotificationPtr::create(); 0153 msg->setSessionId(settings->value(QStringLiteral("sessionId")).toByteArray()); 0154 msg->setOperation(mapItemOperation(static_cast<LegacyOp>(settings->value(QStringLiteral("op")).toInt()))); 0155 Protocol::FetchItemsResponse item; 0156 item.setId(settings->value(QStringLiteral("uid")).toLongLong()); 0157 item.setRemoteId(settings->value(QStringLiteral("rid")).toString()); 0158 item.setMimeType(settings->value(QStringLiteral("mimeType")).toString()); 0159 msg->setItems({std::move(item)}); 0160 msg->addMetadata("FETCH_ITEM"); 0161 msg->setResource(settings->value(QStringLiteral("resource")).toByteArray()); 0162 msg->setParentCollection(settings->value(QStringLiteral("parentCol")).toLongLong()); 0163 msg->setParentDestCollection(settings->value(QStringLiteral("parentDestCol")).toLongLong()); 0164 const QStringList list = settings->value(QStringLiteral("itemParts")).toStringList(); 0165 QSet<QByteArray> itemParts; 0166 for (const QString &entry : list) { 0167 itemParts.insert(entry.toLatin1()); 0168 } 0169 msg->setItemParts(itemParts); 0170 return msg; 0171 } 0172 0173 Protocol::ChangeNotificationPtr ChangeRecorderJournalReader::loadQSettingsCollectionNotification(QSettings *settings) 0174 { 0175 auto msg = Protocol::CollectionChangeNotificationPtr::create(); 0176 msg->setSessionId(settings->value(QStringLiteral("sessionId")).toByteArray()); 0177 msg->setOperation(mapCollectionOperation(static_cast<LegacyOp>(settings->value(QStringLiteral("op")).toInt()))); 0178 Protocol::FetchCollectionsResponse collection; 0179 collection.setId(settings->value(QStringLiteral("uid")).toLongLong()); 0180 collection.setRemoteId(settings->value(QStringLiteral("rid")).toString()); 0181 msg->setCollection(std::move(collection)); 0182 msg->addMetadata("FETCH_COLLECTION"); 0183 msg->setResource(settings->value(QStringLiteral("resource")).toByteArray()); 0184 msg->setParentCollection(settings->value(QStringLiteral("parentCol")).toLongLong()); 0185 msg->setParentDestCollection(settings->value(QStringLiteral("parentDestCol")).toLongLong()); 0186 const QStringList list = settings->value(QStringLiteral("itemParts")).toStringList(); 0187 QSet<QByteArray> changedParts; 0188 for (const QString &entry : list) { 0189 changedParts.insert(entry.toLatin1()); 0190 } 0191 msg->setChangedParts(changedParts); 0192 return msg; 0193 } 0194 0195 QSet<Protocol::ItemChangeNotification::Relation> ChangeRecorderJournalReader::extractRelations(QSet<QByteArray> &flags) 0196 { 0197 QSet<Protocol::ItemChangeNotification::Relation> relations; 0198 auto iter = flags.begin(); 0199 while (iter != flags.end()) { 0200 if (iter->startsWith("RELATION")) { 0201 const QByteArrayList parts = iter->split(' '); 0202 Q_ASSERT(parts.size() == 4); 0203 Protocol::ItemChangeNotification::Relation relation; 0204 relation.type = QString::fromLatin1(parts[1]); 0205 relation.leftId = parts[2].toLongLong(); 0206 relation.rightId = parts[3].toLongLong(); 0207 relations.insert(relation); 0208 iter = flags.erase(iter); 0209 } else { 0210 ++iter; 0211 } 0212 } 0213 0214 return relations; 0215 } 0216 0217 Protocol::ChangeNotificationPtr ChangeRecorderJournalReader::loadItemNotification(QDataStream &stream, quint64 version) 0218 { 0219 QByteArray resource; 0220 QByteArray destinationResource; 0221 int operation; 0222 int entityCnt; 0223 qint64 uid; 0224 qint64 parentCollection; 0225 qint64 parentDestCollection; 0226 QString remoteId; 0227 QString mimeType; 0228 QString remoteRevision; 0229 QSet<QByteArray> itemParts; 0230 QSet<QByteArray> addedFlags; 0231 QSet<QByteArray> removedFlags; 0232 QSet<qint64> addedTags; 0233 QSet<qint64> removedTags; 0234 QList<Protocol::FetchItemsResponse> items; 0235 0236 auto msg = Protocol::ItemChangeNotificationPtr::create(); 0237 0238 if (version == 1) { 0239 stream >> operation; 0240 stream >> uid; 0241 stream >> remoteId; 0242 stream >> resource; 0243 stream >> parentCollection; 0244 stream >> parentDestCollection; 0245 stream >> mimeType; 0246 stream >> itemParts; 0247 0248 Protocol::FetchItemsResponse item; 0249 item.setId(uid); 0250 item.setRemoteId(remoteId); 0251 item.setMimeType(mimeType); 0252 items.push_back(std::move(item)); 0253 msg->addMetadata("FETCH_ITEM"); 0254 } else if (version >= 2) { 0255 stream >> operation; 0256 stream >> entityCnt; 0257 if (version >= 7) { 0258 QByteArray ba; 0259 qint64 i64; 0260 int i; 0261 QDateTime dt; 0262 QString str; 0263 QList<QByteArray> bav; 0264 QList<qint64> i64v; 0265 QMap<QByteArray, QByteArray> babaMap; 0266 int cnt; 0267 for (int j = 0; j < entityCnt; ++j) { 0268 Protocol::FetchItemsResponse item; 0269 stream >> i64; 0270 item.setId(i64); 0271 stream >> i; 0272 item.setRevision(i); 0273 stream >> i64; 0274 item.setParentId(i64); 0275 stream >> str; 0276 item.setRemoteId(str); 0277 stream >> str; 0278 item.setRemoteRevision(str); 0279 stream >> str; 0280 item.setGid(str); 0281 stream >> i64; 0282 item.setSize(i64); 0283 stream >> str; 0284 item.setMimeType(str); 0285 stream >> dt; 0286 item.setMTime(dt); 0287 stream >> bav; 0288 item.setFlags(bav); 0289 stream >> cnt; 0290 QList<Protocol::FetchTagsResponse> tags; 0291 tags.reserve(cnt); 0292 for (int k = 0; k < cnt; ++k) { 0293 Protocol::FetchTagsResponse tag; 0294 stream >> i64; 0295 tag.setId(i64); 0296 stream >> i64; 0297 tag.setParentId(i64); 0298 stream >> ba; 0299 tag.setGid(ba); 0300 stream >> ba; 0301 tag.setType(ba); 0302 stream >> ba; 0303 tag.setRemoteId(ba); 0304 stream >> babaMap; 0305 tag.setAttributes(babaMap); 0306 tags << tag; 0307 } 0308 item.setTags(tags); 0309 stream >> i64v; 0310 item.setVirtualReferences(i64v); 0311 stream >> cnt; 0312 QList<Protocol::FetchRelationsResponse> relations; 0313 for (int k = 0; k < cnt; ++k) { 0314 Protocol::FetchRelationsResponse relation; 0315 stream >> i64; 0316 relation.setLeft(i64); 0317 stream >> ba; 0318 relation.setLeftMimeType(ba); 0319 stream >> i64; 0320 relation.setRight(i64); 0321 stream >> ba; 0322 relation.setRightMimeType(ba); 0323 stream >> ba; 0324 relation.setType(ba); 0325 stream >> ba; 0326 relation.setRemoteId(ba); 0327 relations << relation; 0328 } 0329 item.setRelations(relations); 0330 stream >> cnt; 0331 QList<Protocol::Ancestor> ancestors; 0332 for (int k = 0; k < cnt; ++k) { 0333 Protocol::Ancestor ancestor; 0334 stream >> i64; 0335 ancestor.setId(i64); 0336 stream >> str; 0337 ancestor.setRemoteId(str); 0338 stream >> str; 0339 ancestor.setName(str); 0340 stream >> babaMap; 0341 ancestor.setAttributes(babaMap); 0342 ancestors << ancestor; 0343 } 0344 item.setAncestors(ancestors); 0345 stream >> cnt; 0346 QList<Protocol::StreamPayloadResponse> parts; 0347 for (int k = 0; k < cnt; ++k) { 0348 Protocol::StreamPayloadResponse part; 0349 stream >> ba; 0350 part.setPayloadName(ba); 0351 Protocol::PartMetaData metaData; 0352 stream >> ba; 0353 metaData.setName(ba); 0354 stream >> i64; 0355 metaData.setSize(i64); 0356 stream >> i; 0357 metaData.setVersion(i); 0358 stream >> i; 0359 metaData.setStorageType(static_cast<Protocol::PartMetaData::StorageType>(i)); 0360 part.setMetaData(metaData); 0361 stream >> ba; 0362 part.setData(ba); 0363 parts << part; 0364 } 0365 item.setParts(parts); 0366 stream >> bav; 0367 item.setCachedParts(bav); 0368 items.push_back(std::move(item)); 0369 } 0370 } else { 0371 for (int j = 0; j < entityCnt; ++j) { 0372 stream >> uid; 0373 stream >> remoteId; 0374 stream >> remoteRevision; 0375 stream >> mimeType; 0376 if (stream.status() != QDataStream::Ok) { 0377 qCWarning(AKONADICORE_LOG) << "Error reading saved notifications! Aborting"; 0378 return msg; 0379 } 0380 Protocol::FetchItemsResponse item; 0381 item.setId(uid); 0382 item.setRemoteId(remoteId); 0383 item.setRemoteRevision(remoteRevision); 0384 item.setMimeType(mimeType); 0385 items.push_back(std::move(item)); 0386 } 0387 msg->addMetadata("FETCH_ITEM"); 0388 } 0389 stream >> resource; 0390 stream >> destinationResource; 0391 stream >> parentCollection; 0392 stream >> parentDestCollection; 0393 stream >> itemParts; 0394 stream >> addedFlags; 0395 stream >> removedFlags; 0396 if (version >= 3) { 0397 stream >> addedTags; 0398 stream >> removedTags; 0399 } 0400 if (version >= 8) { 0401 bool boolean; 0402 stream >> boolean; 0403 msg->setMustRetrieve(boolean); 0404 } 0405 } else { 0406 qCWarning(AKONADICORE_LOG) << "Error version is not correct here" << version; 0407 return msg; 0408 } 0409 if (version >= 5) { 0410 msg->setOperation(static_cast<Protocol::ItemChangeNotification::Operation>(operation)); 0411 } else { 0412 msg->setOperation(mapItemOperation(static_cast<LegacyOp>(operation))); 0413 } 0414 msg->setItems(items); 0415 msg->setResource(resource); 0416 msg->setDestinationResource(destinationResource); 0417 msg->setParentCollection(parentCollection); 0418 msg->setParentDestCollection(parentDestCollection); 0419 msg->setItemParts(itemParts); 0420 msg->setAddedRelations(extractRelations(addedFlags)); 0421 msg->setAddedFlags(addedFlags); 0422 msg->setRemovedRelations(extractRelations(removedFlags)); 0423 msg->setRemovedFlags(removedFlags); 0424 msg->setAddedTags(addedTags); 0425 msg->setRemovedTags(removedTags); 0426 return msg; 0427 } 0428 0429 QSet<QByteArray> ChangeRecorderJournalWriter::encodeRelations(const QSet<Protocol::ItemChangeNotification::Relation> &relations) 0430 { 0431 QSet<QByteArray> rv; 0432 for (const auto &rel : relations) { 0433 rv.insert("RELATION " + rel.type.toLatin1() + ' ' + QByteArray::number(rel.leftId) + ' ' + QByteArray::number(rel.rightId)); 0434 } 0435 return rv; 0436 } 0437 0438 void ChangeRecorderJournalWriter::saveItemNotification(QDataStream &stream, const Protocol::ItemChangeNotification &msg) 0439 { 0440 // Version 8 0441 0442 stream << int(msg.operation()); 0443 const auto &items = msg.items(); 0444 stream << items.count(); 0445 for (const auto &item : items) { 0446 stream << item.id() << item.revision() << item.parentId() << item.remoteId() << item.remoteRevision() << item.gid() << item.size() << item.mimeType() 0447 << item.mTime() << item.flags(); 0448 const auto tags = item.tags(); 0449 stream << tags.count(); 0450 for (const auto &tag : tags) { 0451 stream << tag.id() << tag.parentId() << tag.gid() << tag.type() << tag.remoteId() << tag.attributes(); 0452 } 0453 stream << item.virtualReferences(); 0454 const auto relations = item.relations(); 0455 stream << relations.count(); 0456 for (const auto &relation : relations) { 0457 stream << relation.left() << relation.leftMimeType() << relation.right() << relation.rightMimeType() << relation.type() << relation.remoteId(); 0458 } 0459 const auto ancestors = item.ancestors(); 0460 stream << ancestors.count(); 0461 for (const auto &ancestor : ancestors) { 0462 stream << ancestor.id() << ancestor.remoteId() << ancestor.name() << ancestor.attributes(); 0463 } 0464 const auto parts = item.parts(); 0465 stream << parts.count(); 0466 for (const auto &part : parts) { 0467 const auto metaData = part.metaData(); 0468 stream << part.payloadName() << metaData.name() << metaData.size() << metaData.version() << static_cast<int>(metaData.storageType()) << part.data(); 0469 } 0470 stream << item.cachedParts(); 0471 } 0472 stream << msg.resource(); 0473 stream << msg.destinationResource(); 0474 stream << quint64(msg.parentCollection()); 0475 stream << quint64(msg.parentDestCollection()); 0476 stream << msg.itemParts(); 0477 stream << msg.addedFlags() + encodeRelations(msg.addedRelations()); 0478 stream << msg.removedFlags() + encodeRelations(msg.removedRelations()); 0479 stream << msg.addedTags(); 0480 stream << msg.removedTags(); 0481 stream << msg.mustRetrieve(); 0482 } 0483 0484 Protocol::ChangeNotificationPtr ChangeRecorderJournalReader::loadCollectionNotification(QDataStream &stream, quint64 version) 0485 { 0486 QByteArray resource; 0487 QByteArray destinationResource; 0488 int operation; 0489 int entityCnt; 0490 quint64 uid; 0491 quint64 parentCollection; 0492 quint64 parentDestCollection; 0493 QString remoteId; 0494 QString remoteRevision; 0495 QString dummyString; 0496 QSet<QByteArray> changedParts; 0497 QSet<QByteArray> dummyBa; 0498 QSet<qint64> dummyIv; 0499 0500 auto msg = Protocol::CollectionChangeNotificationPtr::create(); 0501 0502 if (version == 1) { 0503 stream >> operation; 0504 stream >> uid; 0505 stream >> remoteId; 0506 stream >> resource; 0507 stream >> parentCollection; 0508 stream >> parentDestCollection; 0509 stream >> dummyString; 0510 stream >> changedParts; 0511 0512 Protocol::FetchCollectionsResponse collection; 0513 collection.setId(uid); 0514 collection.setRemoteId(remoteId); 0515 msg->setCollection(std::move(collection)); 0516 msg->addMetadata("FETCH_COLLECTION"); 0517 } else if (version >= 2) { 0518 stream >> operation; 0519 stream >> entityCnt; 0520 if (version >= 7) { 0521 QString str; 0522 QStringList stringList; 0523 qint64 i64; 0524 QList<qint64> vb; 0525 QMap<QByteArray, QByteArray> attrs; 0526 bool b; 0527 int i; 0528 Tristate tristate; 0529 Protocol::FetchCollectionsResponse collection; 0530 stream >> uid; 0531 collection.setId(uid); 0532 stream >> uid; 0533 collection.setParentId(uid); 0534 stream >> str; 0535 collection.setName(str); 0536 stream >> stringList; 0537 collection.setMimeTypes(stringList); 0538 stream >> str; 0539 collection.setRemoteId(str); 0540 stream >> str; 0541 collection.setRemoteRevision(str); 0542 stream >> str; 0543 collection.setResource(str); 0544 0545 Protocol::FetchCollectionStatsResponse stats; 0546 stream >> i64; 0547 stats.setCount(i64); 0548 stream >> i64; 0549 stats.setUnseen(i64); 0550 stream >> i64; 0551 stats.setSize(i64); 0552 collection.setStatistics(stats); 0553 0554 stream >> str; 0555 collection.setSearchQuery(str); 0556 stream >> vb; 0557 collection.setSearchCollections(vb); 0558 stream >> entityCnt; 0559 QList<Protocol::Ancestor> ancestors; 0560 for (int j = 0; j < entityCnt; ++j) { 0561 Protocol::Ancestor ancestor; 0562 stream >> i64; 0563 ancestor.setId(i64); 0564 stream >> str; 0565 ancestor.setRemoteId(str); 0566 stream >> str; 0567 ancestor.setName(str); 0568 stream >> attrs; 0569 ancestor.setAttributes(attrs); 0570 ancestors.push_back(ancestor); 0571 0572 if (stream.status() != QDataStream::Ok) { 0573 qCWarning(AKONADICORE_LOG) << "Erorr reading saved notifications! Aborting"; 0574 return msg; 0575 } 0576 } 0577 collection.setAncestors(ancestors); 0578 0579 Protocol::CachePolicy cachePolicy; 0580 stream >> b; 0581 cachePolicy.setInherit(b); 0582 stream >> i; 0583 cachePolicy.setCheckInterval(i); 0584 stream >> i; 0585 cachePolicy.setCacheTimeout(i); 0586 stream >> b; 0587 cachePolicy.setSyncOnDemand(b); 0588 stream >> stringList; 0589 cachePolicy.setLocalParts(stringList); 0590 collection.setCachePolicy(cachePolicy); 0591 0592 stream >> attrs; 0593 collection.setAttributes(attrs); 0594 stream >> b; 0595 collection.setEnabled(b); 0596 stream >> reinterpret_cast<qint8 &>(tristate); 0597 collection.setDisplayPref(tristate); 0598 stream >> reinterpret_cast<qint8 &>(tristate); 0599 collection.setSyncPref(tristate); 0600 stream >> reinterpret_cast<qint8 &>(tristate); 0601 collection.setIndexPref(tristate); 0602 stream >> b; // read the deprecated "isReferenced" value 0603 stream >> b; 0604 collection.setIsVirtual(b); 0605 0606 msg->setCollection(std::move(collection)); 0607 } else { 0608 for (int j = 0; j < entityCnt; ++j) { 0609 stream >> uid; 0610 stream >> remoteId; 0611 stream >> remoteRevision; 0612 stream >> dummyString; 0613 if (stream.status() != QDataStream::Ok) { 0614 qCWarning(AKONADICORE_LOG) << "Error reading saved notifications! Aborting"; 0615 return msg; 0616 } 0617 Protocol::FetchCollectionsResponse collection; 0618 collection.setId(uid); 0619 collection.setRemoteId(remoteId); 0620 collection.setRemoteRevision(remoteRevision); 0621 msg->setCollection(std::move(collection)); 0622 msg->addMetadata("FETCH_COLLECTION"); 0623 } 0624 } 0625 stream >> resource; 0626 stream >> destinationResource; 0627 stream >> parentCollection; 0628 stream >> parentDestCollection; 0629 stream >> changedParts; 0630 stream >> dummyBa; 0631 stream >> dummyBa; 0632 if (version >= 3) { 0633 stream >> dummyIv; 0634 stream >> dummyIv; 0635 } 0636 } else { 0637 qCWarning(AKONADICORE_LOG) << "Error version is not correct here" << version; 0638 return msg; 0639 } 0640 0641 if (version >= 5) { 0642 msg->setOperation(static_cast<Protocol::CollectionChangeNotification::Operation>(operation)); 0643 } else { 0644 msg->setOperation(mapCollectionOperation(static_cast<LegacyOp>(operation))); 0645 } 0646 msg->setResource(resource); 0647 msg->setDestinationResource(destinationResource); 0648 msg->setParentCollection(parentCollection); 0649 msg->setParentDestCollection(parentDestCollection); 0650 msg->setChangedParts(changedParts); 0651 return msg; 0652 } 0653 0654 void Akonadi::ChangeRecorderJournalWriter::saveCollectionNotification(QDataStream &stream, const Protocol::CollectionChangeNotification &msg) 0655 { 0656 // Version 7 0657 0658 const auto &col = msg.collection(); 0659 0660 stream << int(msg.operation()); 0661 stream << int(1); 0662 stream << col.id(); 0663 stream << col.parentId(); 0664 stream << col.name(); 0665 stream << col.mimeTypes(); 0666 stream << col.remoteId(); 0667 stream << col.remoteRevision(); 0668 stream << col.resource(); 0669 const auto stats = col.statistics(); 0670 stream << stats.count(); 0671 stream << stats.unseen(); 0672 stream << stats.size(); 0673 stream << col.searchQuery(); 0674 stream << col.searchCollections(); 0675 const auto ancestors = col.ancestors(); 0676 stream << ancestors.count(); 0677 for (const auto &ancestor : ancestors) { 0678 stream << ancestor.id() << ancestor.remoteId() << ancestor.name() << ancestor.attributes(); 0679 } 0680 const auto cachePolicy = col.cachePolicy(); 0681 stream << cachePolicy.inherit(); 0682 stream << cachePolicy.checkInterval(); 0683 stream << cachePolicy.cacheTimeout(); 0684 stream << cachePolicy.syncOnDemand(); 0685 stream << cachePolicy.localParts(); 0686 stream << col.attributes(); 0687 stream << col.enabled(); 0688 stream << static_cast<qint8>(col.displayPref()); 0689 stream << static_cast<qint8>(col.syncPref()); 0690 stream << static_cast<qint8>(col.indexPref()); 0691 stream << false; // write the deprecated "isReferenced" value 0692 stream << col.isVirtual(); 0693 0694 stream << msg.resource(); 0695 stream << msg.destinationResource(); 0696 stream << quint64(msg.parentCollection()); 0697 stream << quint64(msg.parentDestCollection()); 0698 stream << msg.changedParts(); 0699 stream << QSet<QByteArray>(); 0700 stream << QSet<QByteArray>(); 0701 stream << QSet<qint64>(); 0702 stream << QSet<qint64>(); 0703 } 0704 0705 Protocol::ChangeNotificationPtr ChangeRecorderJournalReader::loadTagNotification(QDataStream &stream, quint64 version) 0706 { 0707 QByteArray resource; 0708 QByteArray dummyBa; 0709 int operation; 0710 int entityCnt; 0711 quint64 uid; 0712 quint64 dummyI; 0713 QString remoteId; 0714 QString dummyString; 0715 QSet<QByteArray> dummyBaV; 0716 QSet<qint64> dummyIv; 0717 0718 auto msg = Protocol::TagChangeNotificationPtr::create(); 0719 0720 if (version == 1) { 0721 stream >> operation; 0722 stream >> uid; 0723 stream >> remoteId; 0724 stream >> dummyBa; 0725 stream >> dummyI; 0726 stream >> dummyI; 0727 stream >> dummyString; 0728 stream >> dummyBaV; 0729 0730 Protocol::FetchTagsResponse tag; 0731 tag.setId(uid); 0732 tag.setRemoteId(remoteId.toLatin1()); 0733 msg->setTag(std::move(tag)); 0734 msg->addMetadata("FETCH_TAG"); 0735 } else if (version >= 2) { 0736 stream >> operation; 0737 stream >> entityCnt; 0738 if (version >= 7) { 0739 QByteArray ba; 0740 QMap<QByteArray, QByteArray> attrs; 0741 0742 Protocol::FetchTagsResponse tag; 0743 0744 stream >> uid; 0745 tag.setId(uid); 0746 stream >> ba; 0747 tag.setParentId(uid); 0748 stream >> attrs; 0749 tag.setGid(ba); 0750 stream >> ba; 0751 tag.setType(ba); 0752 stream >> uid; 0753 tag.setRemoteId(ba); 0754 stream >> ba; 0755 tag.setAttributes(attrs); 0756 msg->setTag(std::move(tag)); 0757 0758 stream >> resource; 0759 } else { 0760 for (int j = 0; j < entityCnt; ++j) { 0761 stream >> uid; 0762 stream >> remoteId; 0763 stream >> dummyString; 0764 stream >> dummyString; 0765 if (stream.status() != QDataStream::Ok) { 0766 qCWarning(AKONADICORE_LOG) << "Error reading saved notifications! Aborting"; 0767 return msg; 0768 } 0769 Protocol::FetchTagsResponse tag; 0770 tag.setId(uid); 0771 tag.setRemoteId(remoteId.toLatin1()); 0772 msg->setTag(std::move(tag)); 0773 msg->addMetadata("FETCH_TAG"); 0774 } 0775 stream >> resource; 0776 stream >> dummyBa; 0777 stream >> dummyI; 0778 stream >> dummyI; 0779 stream >> dummyBaV; 0780 stream >> dummyBaV; 0781 stream >> dummyBaV; 0782 if (version >= 3) { 0783 stream >> dummyIv; 0784 stream >> dummyIv; 0785 } 0786 } 0787 if (version >= 5) { 0788 msg->setOperation(static_cast<Protocol::TagChangeNotification::Operation>(operation)); 0789 } else { 0790 msg->setOperation(mapTagOperation(static_cast<LegacyOp>(operation))); 0791 } 0792 } 0793 msg->setResource(resource); 0794 return msg; 0795 } 0796 0797 void Akonadi::ChangeRecorderJournalWriter::saveTagNotification(QDataStream &stream, const Protocol::TagChangeNotification &msg) 0798 { 0799 const auto &tag = msg.tag(); 0800 stream << int(msg.operation()); 0801 stream << int(1); 0802 stream << tag.id(); 0803 stream << tag.parentId(); 0804 stream << tag.gid(); 0805 stream << tag.type(); 0806 stream << tag.remoteId(); 0807 stream << tag.attributes(); 0808 stream << msg.resource(); 0809 } 0810 0811 Protocol::ChangeNotificationPtr ChangeRecorderJournalReader::loadRelationNotification(QDataStream &stream, quint64 version) 0812 { 0813 QByteArray dummyBa; 0814 int operation; 0815 int entityCnt; 0816 quint64 dummyI; 0817 QString dummyString; 0818 QSet<QByteArray> itemParts; 0819 QSet<QByteArray> dummyBaV; 0820 QSet<qint64> dummyIv; 0821 0822 auto msg = Protocol::RelationChangeNotificationPtr::create(); 0823 0824 if (version == 1) { 0825 qCWarning(AKONADICORE_LOG) << "Invalid version of relation notification"; 0826 return msg; 0827 } else if (version >= 2) { 0828 stream >> operation; 0829 stream >> entityCnt; 0830 if (version >= 7) { 0831 Protocol::FetchRelationsResponse relation; 0832 qint64 i64; 0833 QByteArray ba; 0834 stream >> i64; 0835 relation.setLeft(i64); 0836 stream >> ba; 0837 relation.setLeftMimeType(ba); 0838 stream >> i64; 0839 relation.setRight(i64); 0840 stream >> ba; 0841 relation.setRightMimeType(ba); 0842 stream >> ba; 0843 relation.setRemoteId(ba); 0844 stream >> ba; 0845 relation.setType(ba); 0846 0847 msg->setRelation(std::move(relation)); 0848 0849 } else { 0850 for (int j = 0; j < entityCnt; ++j) { 0851 stream >> dummyI; 0852 stream >> dummyString; 0853 stream >> dummyString; 0854 stream >> dummyString; 0855 if (stream.status() != QDataStream::Ok) { 0856 qCWarning(AKONADICORE_LOG) << "Error reading saved notifications! Aborting"; 0857 return msg; 0858 } 0859 } 0860 stream >> dummyBa; 0861 if (version == 5) { 0862 // there was a bug in version 5 serializer that serialized this 0863 // field as qint64 (8 bytes) instead of empty QByteArray (which is 0864 // 4 bytes) 0865 stream >> dummyI; 0866 } else { 0867 stream >> dummyBa; 0868 } 0869 stream >> dummyI; 0870 stream >> dummyI; 0871 stream >> itemParts; 0872 stream >> dummyBaV; 0873 stream >> dummyBaV; 0874 if (version >= 3) { 0875 stream >> dummyIv; 0876 stream >> dummyIv; 0877 } 0878 0879 Protocol::FetchRelationsResponse relation; 0880 for (const QByteArray &part : std::as_const(itemParts)) { 0881 const QByteArrayList p = part.split(' '); 0882 if (p.size() < 2) { 0883 continue; 0884 } 0885 if (p[0] == "LEFT") { 0886 relation.setLeft(p[1].toLongLong()); 0887 } else if (p[0] == "RIGHT") { 0888 relation.setRight(p[1].toLongLong()); 0889 } else if (p[0] == "RID") { 0890 relation.setRemoteId(p[1]); 0891 } else if (p[0] == "TYPE") { 0892 relation.setType(p[1]); 0893 } 0894 } 0895 msg->setRelation(std::move(relation)); 0896 } 0897 if (version >= 5) { 0898 msg->setOperation(static_cast<Protocol::RelationChangeNotification::Operation>(operation)); 0899 } else { 0900 msg->setOperation(mapRelationOperation(static_cast<LegacyOp>(operation))); 0901 } 0902 } 0903 0904 return msg; 0905 } 0906 0907 void Akonadi::ChangeRecorderJournalWriter::saveRelationNotification(QDataStream &stream, const Protocol::RelationChangeNotification &msg) 0908 { 0909 const auto &rel = msg.relation(); 0910 stream << int(msg.operation()); 0911 stream << int(0); 0912 stream << rel.left(); 0913 stream << rel.leftMimeType(); 0914 stream << rel.right(); 0915 stream << rel.rightMimeType(); 0916 stream << rel.remoteId(); 0917 stream << rel.type(); 0918 } 0919 0920 Protocol::ItemChangeNotification::Operation ChangeRecorderJournalReader::mapItemOperation(LegacyOp op) 0921 { 0922 switch (op) { 0923 case Add: 0924 return Protocol::ItemChangeNotification::Add; 0925 case Modify: 0926 return Protocol::ItemChangeNotification::Modify; 0927 case Move: 0928 return Protocol::ItemChangeNotification::Move; 0929 case Remove: 0930 return Protocol::ItemChangeNotification::Remove; 0931 case Link: 0932 return Protocol::ItemChangeNotification::Link; 0933 case Unlink: 0934 return Protocol::ItemChangeNotification::Unlink; 0935 case ModifyFlags: 0936 return Protocol::ItemChangeNotification::ModifyFlags; 0937 case ModifyTags: 0938 return Protocol::ItemChangeNotification::ModifyTags; 0939 case ModifyRelations: 0940 return Protocol::ItemChangeNotification::ModifyRelations; 0941 default: 0942 qWarning() << "Unexpected operation type in item notification"; 0943 return Protocol::ItemChangeNotification::InvalidOp; 0944 } 0945 } 0946 0947 Protocol::CollectionChangeNotification::Operation ChangeRecorderJournalReader::mapCollectionOperation(LegacyOp op) 0948 { 0949 switch (op) { 0950 case Add: 0951 return Protocol::CollectionChangeNotification::Add; 0952 case Modify: 0953 return Protocol::CollectionChangeNotification::Modify; 0954 case Move: 0955 return Protocol::CollectionChangeNotification::Move; 0956 case Remove: 0957 return Protocol::CollectionChangeNotification::Remove; 0958 case Subscribe: 0959 return Protocol::CollectionChangeNotification::Subscribe; 0960 case Unsubscribe: 0961 return Protocol::CollectionChangeNotification::Unsubscribe; 0962 default: 0963 qCWarning(AKONADICORE_LOG) << "Unexpected operation type in collection notification"; 0964 return Protocol::CollectionChangeNotification::InvalidOp; 0965 } 0966 } 0967 0968 Protocol::TagChangeNotification::Operation ChangeRecorderJournalReader::mapTagOperation(LegacyOp op) 0969 { 0970 switch (op) { 0971 case Add: 0972 return Protocol::TagChangeNotification::Add; 0973 case Modify: 0974 return Protocol::TagChangeNotification::Modify; 0975 case Remove: 0976 return Protocol::TagChangeNotification::Remove; 0977 default: 0978 qCWarning(AKONADICORE_LOG) << "Unexpected operation type in tag notification"; 0979 return Protocol::TagChangeNotification::InvalidOp; 0980 } 0981 } 0982 0983 Protocol::RelationChangeNotification::Operation ChangeRecorderJournalReader::mapRelationOperation(LegacyOp op) 0984 { 0985 switch (op) { 0986 case Add: 0987 return Protocol::RelationChangeNotification::Add; 0988 case Remove: 0989 return Protocol::RelationChangeNotification::Remove; 0990 default: 0991 qCWarning(AKONADICORE_LOG) << "Unexpected operation type in relation notification"; 0992 return Protocol::RelationChangeNotification::InvalidOp; 0993 } 0994 } 0995 0996 ChangeRecorderJournalReader::LegacyType ChangeRecorderJournalWriter::mapToLegacyType(Protocol::Command::Type type) 0997 { 0998 switch (type) { 0999 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; 1007 default: 1008 qCWarning(AKONADICORE_LOG) << "Unexpected notification type"; 1009 return ChangeRecorderJournalReader::InvalidType; 1010 } 1011 }