From 61a06afe8ef87056b067fbe578a72bf564123222 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Sun, 29 May 2016 20:08:51 +0200 Subject: The imap resource is back --- examples/CMakeLists.txt | 1 + examples/imapresource/imapresource.cpp | 558 ++++++++++++++++----------- examples/imapresource/imapresource.h | 11 +- examples/maildirresource/maildirresource.cpp | 2 +- 4 files changed, 344 insertions(+), 228 deletions(-) (limited to 'examples') diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 59753bb..d6f2d90 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -7,6 +7,7 @@ add_subdirectory(dummyresource) if (BUILD_MAILDIR) # a maildir resource implementation add_subdirectory(maildirresource) + # an imap resource implementation add_subdirectory(imapresource) endif() add_subdirectory(mailtransportresource) diff --git a/examples/imapresource/imapresource.cpp b/examples/imapresource/imapresource.cpp index 61031d8..72cc058 100644 --- a/examples/imapresource/imapresource.cpp +++ b/examples/imapresource/imapresource.cpp @@ -35,6 +35,10 @@ #include "facadefactory.h" #include "indexupdater.h" #include "inspection.h" +#include "synchronizer.h" +#include "sourcewriteback.h" +#include "entitystore.h" +#include "remoteidmap.h" #include #include #include @@ -51,14 +55,26 @@ using namespace Imap; -class FolderUpdater : public Sink::Preprocessor +class MailPropertyExtractor : public Sink::Preprocessor { public: - FolderUpdater(const QByteArray &drafts) {} + MailPropertyExtractor() {} void updatedIndexedProperties(Sink::ApplicationDomain::BufferAdaptor &newEntity) { const auto mimeMessagePath = newEntity.getProperty("mimeMessage").toString(); + // auto parts = mimeMessagePath.split('/'); + // const auto key = parts.takeLast(); + // const auto path = parts.join("/") + "/cur/"; + // + // QDir dir(path); + // const QFileInfoList list = dir.entryInfoList(QStringList() << (key+"*"), QDir::Files); + // if (list.size() != 1) { + // Warning() << "Failed to find message " << path << key << list.size(); + // return; + // } + + // QString file; QFile f(mimeMessagePath); if (!f.open(QIODevice::ReadOnly)) { Warning() << "Failed to open the file: " << mimeMessagePath; @@ -74,6 +90,7 @@ public: msg->setHead(KMime::CRLFtoLF(QByteArray::fromRawData(reinterpret_cast(mapped), f.size()))); msg->parse(); + newEntity.setProperty("subject", msg->subject(true)->asUnicodeString()); newEntity.setProperty("subject", msg->subject(true)->asUnicodeString()); newEntity.setProperty("sender", msg->from(true)->asUnicodeString()); newEntity.setProperty("senderName", msg->from(true)->asUnicodeString()); @@ -95,257 +112,268 @@ public: { } - QSharedPointer mFolderAdaptorFactory; }; -ImapResource::ImapResource(const QByteArray &instanceIdentifier, const QSharedPointer &pipeline) - : Sink::GenericResource(instanceIdentifier, pipeline), - mMailAdaptorFactory(QSharedPointer::create()), - mFolderAdaptorFactory(QSharedPointer::create()) -{ - auto config = ResourceConfig::getConfiguration(instanceIdentifier); - mServer = config.value("server").toString(); - mPort = config.value("port").toInt(); - mUser = config.value("user").toString(); - mPassword = config.value("password").toString(); - - auto folderUpdater = new FolderUpdater(QByteArray()); - folderUpdater->mFolderAdaptorFactory = mFolderAdaptorFactory; +class ImapSynchronizer : public Sink::Synchronizer { +public: + ImapSynchronizer(const QByteArray &resourceType, const QByteArray &resourceInstanceIdentifier) + : Sink::Synchronizer(resourceType, resourceInstanceIdentifier) + { - addType(ENTITY_TYPE_MAIL, mMailAdaptorFactory, - QVector() << folderUpdater << new DefaultIndexUpdater); - addType(ENTITY_TYPE_FOLDER, mFolderAdaptorFactory, - QVector() << new DefaultIndexUpdater); -} + } -QByteArray ImapResource::createFolder(const QString &folderPath, const QByteArray &icon, Sink::Storage::Transaction &transaction, Sink::Storage::Transaction &synchronizationTransaction) -{ - auto remoteId = folderPath.toUtf8(); - auto bufferType = ENTITY_TYPE_FOLDER; - Sink::ApplicationDomain::Folder folder; - auto folderPathParts = folderPath.split('/'); - const auto name = folderPathParts.takeLast(); - folder.setProperty("name", name); - folder.setProperty("icon", icon); - - if (!folderPathParts.isEmpty()) { - folder.setProperty("parent", resolveRemoteId(ENTITY_TYPE_FOLDER, folderPathParts.join('/').toUtf8(), synchronizationTransaction)); + QByteArray createFolder(const QString &folderPath, const QByteArray &icon) + { + auto remoteId = folderPath.toUtf8(); + auto bufferType = ENTITY_TYPE_FOLDER; + Sink::ApplicationDomain::Folder folder; + auto folderPathParts = folderPath.split('/'); + const auto name = folderPathParts.takeLast(); + folder.setProperty("name", name); + folder.setProperty("icon", icon); + + if (!folderPathParts.isEmpty()) { + folder.setProperty("parent", syncStore().resolveRemoteId(ENTITY_TYPE_FOLDER, folderPathParts.join('/').toUtf8())); + } + createOrModify(bufferType, remoteId, folder); + return remoteId; } - createOrModify(transaction, synchronizationTransaction, *mFolderAdaptorFactory, bufferType, remoteId, folder); - return remoteId; -} -void ImapResource::synchronizeFolders(const QVector &folderList, Sink::Storage::Transaction &transaction, Sink::Storage::Transaction &synchronizationTransaction) -{ - const QByteArray bufferType = ENTITY_TYPE_FOLDER; - Trace() << "Found folders " << folderList.size(); - - scanForRemovals(transaction, synchronizationTransaction, bufferType, - [&bufferType, &transaction](const std::function &callback) { - //TODO Instead of iterating over all entries in the database, which can also pick up the same item multiple times, - //we should rather iterate over an index that contains every uid exactly once. The remoteId index would be such an index, - //but we currently fail to iterate over all entries in an index it seems. - // auto remoteIds = synchronizationTransaction.openDatabase("rid.mapping." + bufferType, std::function(), true); - auto mainDatabase = Sink::Storage::mainDatabase(transaction, bufferType); - mainDatabase.scan("", [&](const QByteArray &key, const QByteArray &) { - callback(key); - return true; - }); - }, - [&folderList](const QByteArray &remoteId) -> bool { - //folderList.contains(remoteId) - for (const auto folderPath : folderList) { - if (folderPath.pathParts.join('/') == remoteId) { + void synchronizeFolders(const QVector &folderList) + { + const QByteArray bufferType = ENTITY_TYPE_FOLDER; + Trace() << "Found folders " << folderList.size(); + + scanForRemovals(bufferType, + [this, &bufferType](const std::function &callback) { + //TODO Instead of iterating over all entries in the database, which can also pick up the same item multiple times, + //we should rather iterate over an index that contains every uid exactly once. The remoteId index would be such an index, + //but we currently fail to iterate over all entries in an index it seems. + // auto remoteIds = synchronizationTransaction.openDatabase("rid.mapping." + bufferType, std::function(), true); + auto mainDatabase = Sink::Storage::mainDatabase(transaction(), bufferType); + mainDatabase.scan("", [&](const QByteArray &key, const QByteArray &) { + callback(key); return true; + }); + }, + [&folderList](const QByteArray &remoteId) -> bool { + //folderList.contains(remoteId) + for (const auto folderPath : folderList) { + if (folderPath.pathParts.join('/') == remoteId) { + return true; + } } + return false; } - return false; + ); + + for (const auto folderPath : folderList) { + createFolder(folderPath.pathParts.join('/'), "folder"); } - ); + } - for (const auto folderPath : folderList) { - createFolder(folderPath.pathParts.join('/'), "folder", transaction, synchronizationTransaction); + static QByteArray remoteIdForMessage(const QString &path, qint64 uid) + { + return path.toUtf8() + "/" + QByteArray::number(uid); } -} -static QByteArray remoteIdForMessage(const QString &path, qint64 uid) -{ - return path.toUtf8() + "/" + QByteArray::number(uid); -} + static qint64 uidFromMessageRemoteId(const QByteArray &remoteId) + { + return remoteId.split('/').last().toLongLong(); + } -static qint64 uidFromMessageRemoteId(const QByteArray &remoteId) -{ - return remoteId.split('/').last().toLongLong(); -} -void ImapResource::synchronizeMails(Sink::Storage::Transaction &transaction, Sink::Storage::Transaction &synchronizationTransaction, const QString &path, const QVector &messages) -{ - auto time = QSharedPointer::create(); - time->start(); - const QByteArray bufferType = ENTITY_TYPE_MAIL; + void synchronizeMails(const QString &path, const QVector &messages) + { + auto time = QSharedPointer::create(); + time->start(); + const QByteArray bufferType = ENTITY_TYPE_MAIL; - Trace() << "Importing new mail."; + Trace() << "Importing new mail."; - // Trace() << "Looking into " << listingPath; + // Trace() << "Looking into " << listingPath; - const auto folderLocalId = resolveRemoteId(ENTITY_TYPE_FOLDER, path.toUtf8(), synchronizationTransaction); + const auto folderLocalId = syncStore().resolveRemoteId(ENTITY_TYPE_FOLDER, path.toUtf8()); - mSynchronizerQueue.startTransaction(); - int count = 0; - for (const auto &message : messages) { - count++; - const auto remoteId = path.toUtf8() + "/" + QByteArray::number(message.uid); + int count = 0; + for (const auto &message : messages) { + count++; + const auto remoteId = path.toUtf8() + "/" + QByteArray::number(message.uid); - Trace() << "Found a mail " << remoteId << message.msg->subject(true)->asUnicodeString() << message.flags; + Trace() << "Found a mail " << remoteId << message.msg->subject(true)->asUnicodeString() << message.flags; - Sink::ApplicationDomain::Mail mail; - mail.setFolder(folderLocalId); - //FIXME this should come from the mime message, extracted in the pipeline - mail.setExtractedSubject(message.msg->subject(true)->asUnicodeString()); + Sink::ApplicationDomain::Mail mail; + mail.setFolder(folderLocalId); + //FIXME this should come from the mime message, extracted in the pipeline + mail.setExtractedSubject(message.msg->subject(true)->asUnicodeString()); - auto filePath = Sink::resourceStorageLocation(mResourceInstanceIdentifier) + "/" + remoteId; - QDir().mkpath(Sink::resourceStorageLocation(mResourceInstanceIdentifier) + "/" + path.toUtf8()); - QFile file(filePath); - if (!file.open(QIODevice::WriteOnly)) { - Warning() << "Failed to open file for writing: " << file.errorString(); + auto filePath = Sink::resourceStorageLocation(mResourceInstanceIdentifier) + "/" + remoteId; + QDir().mkpath(Sink::resourceStorageLocation(mResourceInstanceIdentifier) + "/" + path.toUtf8()); + QFile file(filePath); + if (!file.open(QIODevice::WriteOnly)) { + Warning() << "Failed to open file for writing: " << file.errorString(); + } + const auto content = message.msg->encodedContent(); + file.write(content); + mail.setMimeMessagePath(filePath); + //FIXME Not sure if these are the actual flags + mail.setUnread(!message.flags.contains(Imap::Flags::Seen)); + mail.setImportant(message.flags.contains(Imap::Flags::Flagged)); + + createOrModify(bufferType, remoteId, mail); } - const auto content = message.msg->encodedContent(); - file.write(content); - mail.setMimeMessagePath(filePath); - //FIXME Not sure if these are the actual flags - mail.setUnread(!message.flags.contains(Imap::Flags::Seen)); - mail.setImportant(message.flags.contains(Imap::Flags::Flagged)); - - createOrModify(transaction, synchronizationTransaction, *mMailAdaptorFactory, bufferType, remoteId, mail); + commitSync(); + const auto elapsed = time->elapsed(); + Log() << "Synchronized " << count << " mails in " << path << Sink::Log::TraceTime(elapsed) << " " << elapsed/qMax(count, 1) << " [ms/mail]"; } - mSynchronizerQueue.commit(); - const auto elapsed = time->elapsed(); - Log() << "Synchronized " << count << " mails in " << path << Sink::Log::TraceTime(elapsed) << " " << elapsed/qMax(count, 1) << " [ms/mail]"; -} - -void ImapResource::synchronizeRemovals(Sink::Storage::Transaction &transaction, Sink::Storage::Transaction &synchronizationTransaction, const QString &path, const QSet &messages) -{ - auto time = QSharedPointer::create(); - time->start(); - const QByteArray bufferType = ENTITY_TYPE_MAIL; - - Trace() << "Finding removed mail."; - - const auto folderLocalId = resolveRemoteId(ENTITY_TYPE_FOLDER, path.toUtf8(), synchronizationTransaction); - int count = 0; - auto property = Sink::ApplicationDomain::Mail::Folder::name; - scanForRemovals(transaction, synchronizationTransaction, bufferType, - [&](const std::function &callback) { - Index index(bufferType + ".index." + property, transaction); - index.lookup(folderLocalId, [&](const QByteArray &sinkId) { - callback(sinkId); + void synchronizeRemovals(const QString &path, const QSet &messages) + { + auto time = QSharedPointer::create(); + time->start(); + const QByteArray bufferType = ENTITY_TYPE_MAIL; + + Trace() << "Finding removed mail."; + + const auto folderLocalId = syncStore().resolveRemoteId(ENTITY_TYPE_FOLDER, path.toUtf8()); + + int count = 0; + auto property = Sink::ApplicationDomain::Mail::Folder::name; + scanForRemovals(bufferType, + [&](const std::function &callback) { + Index index(bufferType + ".index." + property, transaction()); + index.lookup(folderLocalId, [&](const QByteArray &sinkId) { + callback(sinkId); + }, + [&](const Index::Error &error) { + Warning() << "Error in index: " << error.message << property; + }); }, - [&](const Index::Error &error) { - Warning() << "Error in index: " << error.message << property; - }); - }, - [messages, path, &count](const QByteArray &remoteId) -> bool { - if (messages.contains(uidFromMessageRemoteId(remoteId))) { - return true; + [messages, path, &count](const QByteArray &remoteId) -> bool { + if (messages.contains(uidFromMessageRemoteId(remoteId))) { + return true; + } + count++; + return false; } - count++; - return false; - } - ); - - const auto elapsed = time->elapsed(); - Log() << "Removed " << count << " mails in " << path << Sink::Log::TraceTime(elapsed) << " " << elapsed/qMax(count, 1) << " [ms/mail]"; -} + ); -KAsync::Job ImapResource::synchronizeWithSource(Sink::Storage &mainStore, Sink::Storage &synchronizationStore) -{ - Log() << " Synchronizing"; - return KAsync::start([this, &mainStore, &synchronizationStore](KAsync::Future future) { - ImapServerProxy imap(mServer, mPort); - auto loginFuture = imap.login(mUser, mPassword).exec(); - loginFuture.waitForFinished(); - if (loginFuture.errorCode()) { - Warning() << "Login failed."; - future.setError(1, "Login failed"); - return; - } else { - Trace() << "Login was successful"; - } + const auto elapsed = time->elapsed(); + Log() << "Removed " << count << " mails in " << path << Sink::Log::TraceTime(elapsed) << " " << elapsed/qMax(count, 1) << " [ms/mail]"; + } - QVector folderList; - auto folderFuture = imap.fetchFolders([this, &imap, &mainStore, &synchronizationStore, &folderList](const QVector &folders) { - auto transaction = mainStore.createTransaction(Sink::Storage::ReadOnly); - auto syncTransaction = synchronizationStore.createTransaction(Sink::Storage::ReadWrite); - synchronizeFolders(folders, transaction, syncTransaction); - transaction.commit(); - syncTransaction.commit(); - folderList << folders; + KAsync::Job synchronizeWithSource() Q_DECL_OVERRIDE + { + Log() << " Synchronizing"; + return KAsync::start([this](KAsync::Future future) { + ImapServerProxy imap(mServer, mPort); + auto loginFuture = imap.login(mUser, mPassword).exec(); + loginFuture.waitForFinished(); + if (loginFuture.errorCode()) { + Warning() << "Login failed."; + future.setError(1, "Login failed"); + return; + } else { + Trace() << "Login was successful"; + } - }); - folderFuture.waitForFinished(); - if (folderFuture.errorCode()) { - Warning() << "Folder sync failed."; - future.setError(1, "Folder list sync failed"); - return; - } else { - Trace() << "Folder sync was successful"; - } + QVector folderList; + auto folderFuture = imap.fetchFolders([this, &imap, &folderList](const QVector &folders) { + synchronizeFolders(folders); + commit(); + commitSync(); + folderList << folders; - for (const auto &folder : folderList) { - // auto transaction = mainStore.createTransaction(Sink::Storage::ReadOnly); - // auto syncTransaction = synchronizationStore.createTransaction(Sink::Storage::ReadOnly); - - //TODO load entity to read sync settings should we have some (if the folder is existing already) - //Note that this will not work if we change any of those settings in the pipeline - // - // auto mainDatabase = Sink::Storage::mainDatabase(transaction, ENTITY_TYPE_FOLDER); - // const auto sinkId = resolveRemoteId(ENTITY_TYPE_FOLDER, folder.toUtf8(), syncTransaction); - // const auto found = mainDatabase.contains(sinkId); - // if (found) { - // if (auto current = getLatest(mainDatabase, sinkId, mFolderAdaptorFactory)) { - // - // } - // } - - // transaction.commit(); - // syncTransaction.commit(); - - QSet uids; - auto messagesFuture = imap.fetchMessages(folder, [this, &mainStore, &synchronizationStore, folder, &uids](const QVector &messages) { - auto transaction = mainStore.createTransaction(Sink::Storage::ReadOnly); - auto syncTransaction = synchronizationStore.createTransaction(Sink::Storage::ReadWrite); - Trace() << "Synchronizing mails" << folder.normalizedPath(); - for (const auto &msg : messages) { - uids << msg.uid; - } - synchronizeMails(transaction, syncTransaction, folder.normalizedPath(), messages); - transaction.commit(); - syncTransaction.commit(); }); - messagesFuture.waitForFinished(); - if (messagesFuture.errorCode()) { - future.setError(1, "Folder sync failed: " + folder.normalizedPath()); + folderFuture.waitForFinished(); + if (folderFuture.errorCode()) { + Warning() << "Folder sync failed."; + future.setError(1, "Folder list sync failed"); return; + } else { + Trace() << "Folder sync was successful"; } - //Remove what there is to remove - auto transaction = mainStore.createTransaction(Sink::Storage::ReadOnly); - auto syncTransaction = synchronizationStore.createTransaction(Sink::Storage::ReadWrite); - synchronizeRemovals(transaction, syncTransaction, folder.normalizedPath(), uids); - transaction.commit(); - syncTransaction.commit(); - Trace() << "Folder synchronized: " << folder.normalizedPath(); - } - Log() << "Done Synchronizing"; - future.setFinished(); - }); -} + for (const auto &folder : folderList) { + // auto transaction = mainStore.createTransaction(Sink::Storage::ReadOnly); + // auto syncTransaction = synchronizationStore.createTransaction(Sink::Storage::ReadOnly); + + //TODO load entity to read sync settings should we have some (if the folder is existing already) + //Note that this will not work if we change any of those settings in the pipeline + // + // auto mainDatabase = Sink::Storage::mainDatabase(transaction, ENTITY_TYPE_FOLDER); + // const auto sinkId = resolveRemoteId(ENTITY_TYPE_FOLDER, folder.toUtf8(), syncTransaction); + // const auto found = mainDatabase.contains(sinkId); + // if (found) { + // if (auto current = getLatest(mainDatabase, sinkId, mFolderAdaptorFactory)) { + // + // } + // } + + // transaction.commit(); + // syncTransaction.commit(); + + QSet uids; + auto messagesFuture = imap.fetchMessages(folder, [this, folder, &uids](const QVector &messages) { + Trace() << "Synchronizing mails" << folder.normalizedPath(); + for (const auto &msg : messages) { + uids << msg.uid; + } + synchronizeMails(folder.normalizedPath(), messages); + commit(); + commitSync(); + }); + messagesFuture.waitForFinished(); + if (messagesFuture.errorCode()) { + future.setError(1, "Folder sync failed: " + folder.normalizedPath()); + return; + } + //Remove what there is to remove + synchronizeRemovals(folder.normalizedPath(), uids); + commit(); + commitSync(); + Trace() << "Folder synchronized: " << folder.normalizedPath(); + } + + Log() << "Done Synchronizing"; + future.setFinished(); + }); + } -KAsync::Job ImapResource::replay(Sink::Storage &synchronizationStore, const QByteArray &type, const QByteArray &key, const QByteArray &value) +public: + QString mServer; + int mPort; + QString mUser; + QString mPassword; + QByteArray mResourceInstanceIdentifier; +}; + +ImapResource::ImapResource(const QByteArray &instanceIdentifier, const QSharedPointer &pipeline) + : Sink::GenericResource(PLUGIN_NAME, instanceIdentifier, pipeline) { - //TODO implement - return KAsync::null(); + auto config = ResourceConfig::getConfiguration(instanceIdentifier); + mServer = config.value("server").toString(); + mPort = config.value("port").toInt(); + mUser = config.value("user").toString(); + mPassword = config.value("password").toString(); + + auto synchronizer = QSharedPointer::create(PLUGIN_NAME, instanceIdentifier); + synchronizer->mServer = mServer; + synchronizer->mPort = mPort; + synchronizer->mUser = mUser; + synchronizer->mPassword = mPassword; + synchronizer->mResourceInstanceIdentifier = instanceIdentifier; + setupSynchronizer(synchronizer); + auto changereplay = QSharedPointer::create(); + // auto changereplay = QSharedPointer::create(PLUGIN_NAME, instanceIdentifier); + // changereplay->mServer = mServer; + // changereplay->mPort = mPort; + // changereplay->mUser = mUser; + // changereplay->mPassword = mPassword; + setupChangereplay(changereplay); + + setupPreprocessors(ENTITY_TYPE_MAIL, QVector() << new MailPropertyExtractor << new DefaultIndexUpdater); + setupPreprocessors(ENTITY_TYPE_FOLDER, QVector() << new DefaultIndexUpdater); } void ImapResource::removeFromDisk(const QByteArray &instanceIdentifier) @@ -356,7 +384,98 @@ void ImapResource::removeFromDisk(const QByteArray &instanceIdentifier) KAsync::Job ImapResource::inspect(int inspectionType, const QByteArray &inspectionId, const QByteArray &domainType, const QByteArray &entityId, const QByteArray &property, const QVariant &expectedValue) { - //TODO + auto synchronizationStore = QSharedPointer::create(Sink::storageLocation(), mResourceInstanceIdentifier + ".synchronization", Sink::Storage::ReadOnly); + auto synchronizationTransaction = synchronizationStore->createTransaction(Sink::Storage::ReadOnly); + + auto mainStore = QSharedPointer::create(Sink::storageLocation(), mResourceInstanceIdentifier, Sink::Storage::ReadOnly); + auto transaction = mainStore->createTransaction(Sink::Storage::ReadOnly); + + auto entityStore = QSharedPointer::create(mResourceType, mResourceInstanceIdentifier, transaction); + auto syncStore = QSharedPointer::create(synchronizationTransaction); + + Trace() << "Inspecting " << inspectionType << domainType << entityId << property << expectedValue; + + // if (domainType == ENTITY_TYPE_MAIL) { + // const auto mail = entityStore->read(entityId); + // const auto folder = entityStore->read(mail.getFolder()); + // const auto folderRemoteId = syncStore->resolveLocalId(ENTITY_TYPE_FOLDER, mail.getFolder()); + // const auto mailRemoteId = syncStore->resolveLocalId(ENTITY_TYPE_MAIL, mail.identifier()); + // // const auto filePath = getFilePathFromMimeMessagePath(mail.getMimeMessagePath()); + // ImapServerProxy imap(mServer, mPort); + // imap.login(mUser, mPassword).exec().waitForFinished(); + // imap.select(folderRemoteId).exec().waitForFinished(); + // KIMAP::ImapSet set; + // set.add(mailRemoteId.toLongLong()); + // KIMAP::FetchJob::FetchScope scope; + // scope.mode = KIMAP::FetchJob::FetchScope::Full; + // imap.fetch(set, scope, [](const QVector &messages) { + // + // }).exec().waitForFinished(); + // + // if (inspectionType == Sink::ResourceControl::Inspection::PropertyInspectionType) { + // if (property == "unread") { + // // const auto flags = KPIM::Maildir::readEntryFlags(filePath.split('/').last()); + // // if (expectedValue.toBool() && (flags & KPIM::Maildir::Seen)) { + // // return KAsync::error(1, "Expected unread but couldn't find it."); + // // } + // // if (!expectedValue.toBool() && !(flags & KPIM::Maildir::Seen)) { + // // return KAsync::error(1, "Expected read but couldn't find it."); + // // } + // return KAsync::null(); + // } + // if (property == "subject") { + // // KMime::Message *msg = new KMime::Message; + // // msg->setHead(KMime::CRLFtoLF(KPIM::Maildir::readEntryHeadersFromFile(filePath))); + // // msg->parse(); + // // + // // if (msg->subject(true)->asUnicodeString() != expectedValue.toString()) { + // // return KAsync::error(1, "Subject not as expected: " + msg->subject(true)->asUnicodeString()); + // // } + // return KAsync::null(); + // } + // } + // if (inspectionType == Sink::ResourceControl::Inspection::ExistenceInspectionType) { + // // if (QFileInfo(filePath).exists() != expectedValue.toBool()) { + // // return KAsync::error(1, "Wrong file existence: " + filePath); + // // } + // } + // } + // if (domainType == ENTITY_TYPE_FOLDER) { + // const auto remoteId = syncStore->resolveLocalId(ENTITY_TYPE_FOLDER, entityId); + // const auto folder = entityStore->read(entityId); + // + // if (inspectionType == Sink::ResourceControl::Inspection::CacheIntegrityInspectionType) { + // // Warning() << "Inspecting cache integrity" << remoteId; + // // if (!QDir(remoteId).exists()) { + // // return KAsync::error(1, "The directory is not existing: " + remoteId); + // // } + // // + // // int expectedCount = 0; + // // Index index("mail.index.folder", transaction); + // // index.lookup(entityId, [&](const QByteArray &sinkId) { + // // expectedCount++; + // // }, + // // [&](const Index::Error &error) { + // // Warning() << "Error in index: " << error.message << property; + // // }); + // // + // // QDir dir(remoteId + "/cur"); + // // const QFileInfoList list = dir.entryInfoList(QDir::Files); + // // if (list.size() != expectedCount) { + // // return KAsync::error(1, QString("Wrong number of files; found %1 instead of %2.").arg(list.size()).arg(expectedCount)); + // // } + // // if (inspectionType == Sink::ResourceControl::Inspection::ExistenceInspectionType) { + // // if (!remoteId.endsWith(folder.getName().toUtf8())) { + // // return KAsync::error(1, "Wrong folder name: " + remoteId); + // // } + // // //TODO we shouldn't use the remoteId here to figure out the path, it could be gone/changed already + // // if (QDir(remoteId).exists() != expectedValue.toBool()) { + // // return KAsync::error(1, "Wrong folder existence: " + remoteId); + // // } + // // } + // } + // + // } return KAsync::null(); } @@ -377,3 +496,8 @@ void ImapResourceFactory::registerFacades(Sink::FacadeFactory &factory) factory.registerFacade(PLUGIN_NAME); } +void ImapResourceFactory::registerAdaptorFactories(Sink::AdaptorFactoryRegistry ®istry) +{ + registry.registerFactory(PLUGIN_NAME); + registry.registerFactory(PLUGIN_NAME); +} diff --git a/examples/imapresource/imapresource.h b/examples/imapresource/imapresource.h index 82f96a4..0c3b541 100644 --- a/examples/imapresource/imapresource.h +++ b/examples/imapresource/imapresource.h @@ -43,19 +43,9 @@ class ImapResource : public Sink::GenericResource { public: ImapResource(const QByteArray &instanceIdentifier, const QSharedPointer &pipeline = QSharedPointer()); - KAsync::Job synchronizeWithSource(Sink::Storage &mainStore, Sink::Storage &synchronizationStore) Q_DECL_OVERRIDE; KAsync::Job inspect(int inspectionType, const QByteArray &inspectionId, const QByteArray &domainType, const QByteArray &entityId, const QByteArray &property, const QVariant &expectedValue) Q_DECL_OVERRIDE; static void removeFromDisk(const QByteArray &instanceIdentifier); -private: - KAsync::Job replay(Sink::Storage &synchronizationStore, const QByteArray &type, const QByteArray &key, const QByteArray &value) Q_DECL_OVERRIDE; - - QByteArray createFolder(const QString &folderPath, const QByteArray &icon, Sink::Storage::Transaction &transaction, Sink::Storage::Transaction &synchronizationTransaction); - void synchronizeFolders(const QVector &folderList, Sink::Storage::Transaction &transaction, Sink::Storage::Transaction &synchronizationTransaction); - void synchronizeMails(Sink::Storage::Transaction &transaction, Sink::Storage::Transaction &synchronizationTransaction, const QString &path, const QVector &messages); - void synchronizeRemovals(Sink::Storage::Transaction &transaction, Sink::Storage::Transaction &synchronizationTransaction, const QString &path, const QSet &messages); - QSharedPointer mMailAdaptorFactory; - QSharedPointer mFolderAdaptorFactory; private: QString mServer; int mPort; @@ -74,5 +64,6 @@ public: Sink::Resource *createResource(const QByteArray &instanceIdentifier) Q_DECL_OVERRIDE; void registerFacades(Sink::FacadeFactory &factory) Q_DECL_OVERRIDE; + void registerAdaptorFactories(Sink::AdaptorFactoryRegistry ®istry) Q_DECL_OVERRIDE; }; diff --git a/examples/maildirresource/maildirresource.cpp b/examples/maildirresource/maildirresource.cpp index feccefc..eb35d39 100644 --- a/examples/maildirresource/maildirresource.cpp +++ b/examples/maildirresource/maildirresource.cpp @@ -367,7 +367,7 @@ public: Log() << "Synchronized " << count << " mails in " << listingPath << Sink::Log::TraceTime(elapsed) << " " << elapsed/qMax(count, 1) << " [ms/mail]"; } - KAsync::Job synchronizeWithSource() + KAsync::Job synchronizeWithSource() Q_DECL_OVERRIDE { Log() << " Synchronizing"; return KAsync::start([this]() { -- cgit v1.2.3