diff --git a/framework/src/sinkfabric.cpp b/framework/src/sinkfabric.cpp index 5110c2af..8da9d241 100644 --- a/framework/src/sinkfabric.cpp +++ b/framework/src/sinkfabric.cpp @@ -1,281 +1,283 @@ /* Copyright (c) 2016 Christian Mollekopf This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "sinkfabric.h" #include #include #include #include #include #include #include "fabric.h" #include "keyring.h" using namespace Kube; using namespace Sink; using namespace Sink::ApplicationDomain; class SinkListener : public Kube::Fabric::Listener { public: SinkListener() = default; void notify(const QString &id, const QVariantMap &message) { SinkLog() << "Received message: " << id << message; if (id == "synchronize"/*Kube::Messages::synchronize*/) { if (auto folder = message["folder"].value()) { SinkLog() << "Synchronizing folder " << folder->resourceInstanceIdentifier() << folder->identifier(); auto scope = SyncScope().resourceFilter(folder->resourceInstanceIdentifier()).filter(QVariant::fromValue(folder->identifier())); scope.setType(); Store::synchronize(scope).exec(); } else if (message.contains("specialPurpose")) { auto specialPurpose = message["specialPurpose"].value(); //Synchronize all drafts folders if (specialPurpose == "drafts") { //TODO or rather just synchronize draft mails and have resource figure out what that means? Sink::Query folderQuery{}; folderQuery.containsFilter(Sink::ApplicationDomain::SpecialPurpose::Mail::drafts); folderQuery.request(); folderQuery.request(); Store::fetch(folderQuery) .then([] (const QList &folders) { for (const auto f : folders) { auto scope = SyncScope().resourceFilter(f->resourceInstanceIdentifier()).filter(QVariant::fromValue(f->identifier())); scope.setType(); Store::synchronize(scope).exec(); } }).exec(); } } else { const auto accountId = message["accountId"].value(); const auto type = message["type"].value(); SyncScope scope; if (!accountId.isEmpty()) { //FIXME this should work with either string or bytearray, but is apparently very picky scope.resourceFilter(accountId.toLatin1()); } scope.setType(type.toUtf8()); SinkLog() << "Synchronizing... AccountId: " << accountId << " Type: " << scope.type(); Store::synchronize(scope).exec(); } } if (id == "abortSynchronization"/*Kube::Messages::abortSynchronization*/) { const auto accountId = message["accountId"].value(); SyncScope scope; if (!accountId.isEmpty()) { //FIXME this should work with either string or bytearray, but is apparently very picky scope.resourceFilter(accountId.toLatin1()); } Store::abortSynchronization(scope).exec(); } if (id == "sendOutbox"/*Kube::Messages::synchronize*/) { Query query; query.containsFilter(ResourceCapabilities::Mail::transport); auto job = Store::fetchAll(query) .each([=](const SinkResource::Ptr &resource) -> KAsync::Job { return Store::synchronize(SyncScope{}.resourceFilter(resource->identifier())); }); job.exec(); } if (id == "markAsRead"/*Kube::Messages::synchronize*/) { if (auto mail = message["mail"].value()) { mail->setUnread(false); Store::modify(*mail).exec(); } } if (id == "markAsUnread"/*Kube::Messages::synchronize*/) { if (auto mail = message["mail"].value()) { mail->setUnread(true); Store::modify(*mail).exec(); } } if (id == "setImportant"/*Kube::Messages::synchronize*/) { if (auto mail = message["mail"].value()) { mail->setImportant(message["important"].toBool()); Store::modify(*mail).exec(); } } if (id == "moveToTrash"/*Kube::Messages::synchronize*/) { if (auto mail = message["mail"].value()) { mail->setTrash(true); Store::modify(*mail).exec(); } } if (id == "restoreFromTrash") { if (auto mail = message["mail"].value()) { mail->setTrash(false); Store::modify(*mail).exec(); } } if (id == "moveToDrafts"/*Kube::Messages::synchronize*/) { if (auto mail = message["mail"].value()) { mail->setDraft(true); Store::modify(*mail).exec(); } } if (id == "moveToFolder"/*Kube::Messages::synchronize*/) { if (auto mail = message["mail"].value()) { auto folder = message["folder"].value(); mail->setFolder(*folder); Store::modify(*mail).exec(); } } if (id == "unlockKeyring") { auto accountId = message["accountId"].value(); Kube::AccountKeyring{accountId}.unlock(); } } }; class SinkNotifier { public: + + static QVariantList toVariantList(const QByteArrayList &list) + { + QVariantList entities; + for(const auto &entity : list) { + entities << entity; + } + return entities; + } + + static void sendErrorNotification(const Sink::Notification ¬ification) + { + QVariantMap message{ + {"type", "error"}, + {"resource", QString{notification.resource}}, + {"details", notification.message} + }; + + switch(notification.code) { + case Sink::ApplicationDomain::ConnectionError: + message["message"] = QObject::tr("Failed to connect to server."); + message["subtype"] = "connectionError"; + break; + case Sink::ApplicationDomain::NoServerError: + message["message"] = QObject::tr("Host not found."); + message["subtype"] = "hostNotFoundError"; + break; + case Sink::ApplicationDomain::LoginError: + message["message"] = QObject::tr("Failed to login."); + message["subtype"] = "loginError"; + break; + case Sink::ApplicationDomain::ConfigurationError: + message["message"] = QObject::tr("Configuration error."); + break; + case Sink::ApplicationDomain::ConnectionLostError: + //Ignore connection lost errors. We don't need them in the log view. + return; + case Sink::ApplicationDomain::MissingCredentialsError: + message["message"] = QObject::tr("No credentials available."); + break; + default: + //Ignore unknown errors, they are not going to help. + return; + } + Fabric::Fabric{}.postMessage("errorNotification", message); + } + + static void sendProgressNotification(int progress, int total, const QList &entities, const QByteArray &resourceId) + { + QVariantMap message{ + {"type", "progress"}, + {"progress", progress}, + {"total", total}, + {"resourceId", resourceId} + }; + + if (!entities.isEmpty()) { + message["folderId"] = entities.first(); + } + Fabric::Fabric{}.postMessage("progressNotification", message); + } + SinkNotifier() : mNotifier{Sink::Query{Sink::Query::LiveQuery}} { mNotifier.registerHandler([] (const Sink::Notification ¬ification) { - Notification n; SinkLog() << "Received notification: " << notification; - QVariantMap message; - if (notification.type == Sink::Notification::Warning) { - message["type"] = "warning"; - - QVariantList entities; - for(const auto &entity : notification.entities) { - entities << entity; - } - message["entities"] = entities; - message["resource"] = QString{notification.resource}; + if (notification.type == Sink::Notification::Warning) { if (notification.code == Sink::ApplicationDomain::TransmissionError) { - message["message"] = QObject::tr("Failed to send message."); - message["subtype"] = "transmissionError"; - } else { - return; + Fabric::Fabric{}.postMessage("notification", { + {"type", "warning"}, + {"message", QObject::tr("Failed to send message.")}, + {"subtype", "transmissionError"}, + {"entities", toVariantList(notification.entities)}, + {"resource", QString{notification.resource}} + }); } } else if (notification.type == Sink::Notification::Status) { return; } else if (notification.type == Sink::Notification::Error) { - message["type"] = "error"; - message["resource"] = QString{notification.resource}; - message["details"] = notification.message; - switch(notification.code) { - case Sink::ApplicationDomain::ConnectionError: - message["message"] = QObject::tr("Failed to connect to server."); - message["subtype"] = "connectionError"; - break; - case Sink::ApplicationDomain::NoServerError: - message["message"] = QObject::tr("Host not found."); - message["subtype"] = "hostNotFoundError"; - break; - case Sink::ApplicationDomain::LoginError: - message["message"] = QObject::tr("Failed to login."); - message["subtype"] = "loginError"; - break; - case Sink::ApplicationDomain::ConfigurationError: - message["message"] = QObject::tr("Configuration error."); - break; - case Sink::ApplicationDomain::ConnectionLostError: - //Ignore connection lost errors. We don't need them in the log view. - return; - case Sink::ApplicationDomain::MissingCredentialsError: - message["message"] = QObject::tr("No credentials available."); - break; - default: - //Ignore unknown errors, they are not going to help. - return; - } - Fabric::Fabric{}.postMessage("errorNotification", message); + sendErrorNotification(notification); } else if (notification.type == Sink::Notification::Info) { if (notification.code == Sink::ApplicationDomain::TransmissionSuccess) { - message["type"] = "info"; - message["message"] = QObject::tr("A message has been sent."); - message["subtype"] = "messageSent"; - - QVariantList entities; - for(const auto &entity : notification.entities) { - entities << entity; - } - message["entities"] = entities; - - message["resource"] = QString{notification.resource}; + Fabric::Fabric{}.postMessage("notification", { + {"type", "info"}, + {"message", QObject::tr("A message has been sent.")}, + {"subtype", "messageSent"}, + {"entities", toVariantList(notification.entities)}, + {"resource", QString{notification.resource}} + }); } else if (notification.code == Sink::ApplicationDomain::NewContentAvailable) { - message["type"] = "info"; if (!notification.entities.isEmpty()) { - message["folderId"] = notification.entities.first(); + Fabric::Fabric{}.postMessage("notification", { + {"type", "info"}, + {"folderId", notification.entities.first()}, + }); } } else if (notification.code == Sink::ApplicationDomain::SyncInProgress) { - message["type"] = "progress"; - message["progress"] = 0; - message["total"] = 1; - if (!notification.entities.isEmpty()) { - message["folderId"] = notification.entities.first(); - } - message["resourceId"] = notification.resource; - Fabric::Fabric{}.postMessage("progressNotification", message); - return; - } else { - return; + sendProgressNotification(0, 1, notification.entities, notification.resource); } } else if (notification.type == Sink::Notification::Progress) { - message["type"] = "progress"; - message["progress"] = notification.progress; - message["total"] = notification.total; - if (!notification.entities.isEmpty()) { - message["folderId"] = notification.entities.first(); - } - message["resourceId"] = notification.resource; - Fabric::Fabric{}.postMessage("progressNotification", message); - return; - } else { - return; + sendProgressNotification(notification.progress, notification.total, notification.entities, notification.resource); } - Fabric::Fabric{}.postMessage("notification", message); - }); } Sink::Notifier mNotifier; }; class SinkFabric::Private { SinkNotifier notifier; SinkListener listener; }; SinkFabric::SinkFabric() : QObject(), d(new SinkFabric::Private) { } SinkFabric::~SinkFabric() { delete d; } SinkFabric &SinkFabric::instance() { static SinkFabric instance; return instance; }