diff --git a/CMakeLists.txt b/CMakeLists.txt index c72dcf7..03a07f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,62 +1,63 @@ # SPDX-FileCopyrightText: 2023 g10 code Gmbh # SPDX-Contributor: Carl Schwan # SPDX-License-Identifier: BSD-2-Clause cmake_minimum_required(VERSION 3.16) project(gpgoljs) set(KF_MIN_VERSION "5.240.0") find_package(ECM ${KF_MIN_VERSION} CONFIG REQUIRED) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} ) find_package(ECM ${KF_MIN_VERSION} REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake) include(FeatureSummary) include(KDEInstallDirs) include(KDECMakeSettings) include(ECMQtDeclareLoggingCategory) include(ECMAddTests) include(KDECompilerSettings NO_POLICY_SCOPE) set(QT_MIN_VERSION "6.5") set(KF_MIN_VERSION "5.240") set(MIMETREEPARSER_VERSION "5.240.40") set(LIBKLEO_VERSION "5.240.46") set(KLDAP_VERSION "5.240.40") set(LIBKDEPIM_VERSION "5.240.40") set(PIMTEXTEDIT_VERSION "5.240.40") set(PIMIDENTITYMANAGEMENT_VERSION "5.240.40") find_package(Qt6 ${QT_MIN_VERSION} NO_MODULE COMPONENTS Core HttpServer Widgets PrintSupport) set_package_properties(Qt6 PROPERTIES TYPE REQUIRED PURPOSE "Basic application components" ) find_package(KF6 ${KF_MIN_VERSION} COMPONENTS Contacts Completion CoreAddons WidgetsAddons Config ColorScheme Codecs KIO XmlGui GuiAddons Kio Sonnet CalendarCore Archive) set_package_properties(KF6 PROPERTIES TYPE REQUIRED PURPOSE "Basic application components" ) find_package(KPim6Libkleo ${LIBKLEO_VERSION} CONFIG REQUIRED) find_package(KPim6LdapWidgets ${KLDAP_VERSION} CONFIG REQUIRED) find_package(KPim6Libkdepim ${LIBKDEPIM_LIB_VERSION} CONFIG REQUIRED) find_package(KPim6MimeTreeParserWidgets ${MIMETREEPARSER_VERSION} CONFIG REQUIRED) find_package(KPim6TextEdit ${PIMTEXTEDIT_VERSION} CONFIG REQUIRED) find_package(KPim6IdentityManagementWidgets ${PIMIDENTITYMANAGEMENT_VERSION} CONFIG REQUIRED) find_package(KPim6IdentityManagementCore ${PIMIDENTITYMANAGEMENT_VERSION} CONFIG REQUIRED) find_package(KF6TextAutoCorrectionCore CONFIG REQUIRED) if (BUILD_TESTING) find_package(Qt6 ${QT_MIN_VERSION} NO_MODULE COMPONENTS Test) endif() +add_subdirectory(common) add_subdirectory(broker) add_subdirectory(server) diff --git a/broker/CMakeLists.txt b/broker/CMakeLists.txt index bcecaf4..fc4ec1e 100644 --- a/broker/CMakeLists.txt +++ b/broker/CMakeLists.txt @@ -1,45 +1,45 @@ # SPDX-FileCopyrightText: 2023 g10 code GmbH # SPDX-Contributor: Carl Schwan # SPDX-License-Identifier: BSD-2-Clause add_executable(gpgol-broker) target_sources(gpgol-broker PRIVATE # Controllers controllers/abstractcontroller.cpp controllers/abstractcontroller.h controllers/registrationcontroller.cpp controllers/registrationcontroller.h controllers/staticcontroller.h controllers/staticcontroller.cpp controllers/emailcontroller.cpp controllers/emailcontroller.h # State model/serverstate.cpp model/serverstate.h # web sever webserver.cpp webserver.h main.cpp ) qt_add_resources(gpgol-broker PREFIX "/" FILES assets/certificate.crt assets/private.key assets/document-decrypt-16.png assets/document-decrypt-32.png assets/document-decrypt-64.png assets/document-decrypt-80.png assets/script.js web/index.html ) -target_link_libraries(gpgol-broker PRIVATE Qt6::HttpServer Qt6::Core) +target_link_libraries(gpgol-broker PRIVATE Qt6::HttpServer Qt6::Core common) diff --git a/broker/controllers/abstractcontroller.cpp b/broker/controllers/abstractcontroller.cpp index 083a508..71265c7 100644 --- a/broker/controllers/abstractcontroller.cpp +++ b/broker/controllers/abstractcontroller.cpp @@ -1,59 +1,47 @@ // SPDX-FileCopyrightText: 2023 g10 code GmbH // SPDX-Contributor: Carl Schwan // SPDX-License-Identifier: GPL-2.0-or-later #include "abstractcontroller.h" #include "../model/serverstate.h" #include #include +#include using namespace Qt::Literals::StringLiterals; -QByteArray AbstractController::findHeader(QList> headers, const QByteArray &key) -{ - const auto it = std::find_if(std::cbegin(headers), std::cend(headers), [&key](auto header) { - return header.first == key; - }); - - if (it == std::cend(headers)) { - return {}; - } - - return it->second; -} - QHttpServerResponse AbstractController::badRequest(const QString &reason) { if (reason.isEmpty()) { return QHttpServerResponse(QJsonObject { { "errorMessage"_L1, "Invalid request"_L1 } }, QHttpServerResponse::StatusCode::BadRequest); } else { return QHttpServerResponse(QJsonObject { { "errorMessage"_L1, QJsonValue("Invalid request: "_L1 + reason) } }, QHttpServerResponse::StatusCode::BadRequest); } } QHttpServerResponse AbstractController::forbidden() { return QHttpServerResponse(QJsonObject { { "errorMessage"_L1, "Unable to authentificate"_L1 } }, QHttpServerResponse::StatusCode::Forbidden); } std::optional AbstractController::checkAuthentification(const QHttpServerRequest &request) { const auto &state = ServerState::instance(); - const auto email = QString::fromUtf8(findHeader(request.headers(), "X-EMAIL")); + const auto email = QString::fromUtf8(Utils::findHeader(request.headers(), "X-EMAIL")); if (email.isEmpty() || !state.servers.contains(email)) { qWarning() << "no email found" << email; return std::nullopt; } return state.servers[email]; } diff --git a/broker/controllers/abstractcontroller.h b/broker/controllers/abstractcontroller.h index 4491971..771490f 100644 --- a/broker/controllers/abstractcontroller.h +++ b/broker/controllers/abstractcontroller.h @@ -1,21 +1,20 @@ // SPDX-FileCopyrightText: 2023 g10 code GmbH // SPDX-Contributor: Carl Schwan // SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include #include #include "../model/serverstate.h" class AbstractController { protected: Q_REQUIRED_RESULT static QHttpServerResponse badRequest(const QString &reason = {}); static QHttpServerResponse forbidden(); static std::optional checkAuthentification(const QHttpServerRequest &request); - static QByteArray findHeader(QList> headers, const QByteArray &key); }; diff --git a/broker/controllers/emailcontroller.cpp b/broker/controllers/emailcontroller.cpp index 6e7db8b..39e67e7 100644 --- a/broker/controllers/emailcontroller.cpp +++ b/broker/controllers/emailcontroller.cpp @@ -1,162 +1,163 @@ // SPDX-FileCopyrightText: 2023 g10 code GmbH // SPDX-Contributor: Carl Schwan // SPDX-License-Identifier: GPL-2.0-or-later #include "emailcontroller.h" #include #include #include #include #include #include #include #include +#include #include "webserver.h" using namespace Qt::Literals::StringLiterals; QHttpServerResponse EmailController::abstractEmailAction(const QHttpServerRequest &request, const QString &action, QHttpServerRequest::Method method) { const auto server = checkAuthentification(request); if (!server) { return forbidden(); } QNetworkRequest viewEmailRequest(QUrl(u"http://127.0.0.1:"_s + QString::number(server->port) + u'/' + action)); viewEmailRequest.setHeader(QNetworkRequest::ContentTypeHeader, u"application/json"_s); - auto email = AbstractController::findHeader(request.headers(), "X-EMAIL"); - auto displayName = AbstractController::findHeader(request.headers(), "X-NAME"); + auto email = Utils::findHeader(request.headers(), "X-EMAIL"); + auto displayName = Utils::findHeader(request.headers(), "X-NAME"); auto token = QUuid::createUuid().toString(QUuid::WithoutBraces).toUtf8(); viewEmailRequest.setRawHeader("X-EMAIL", email); viewEmailRequest.setRawHeader("X-TOKEN", token); viewEmailRequest.setRawHeader("X-NAME", displayName); auto &serverState = ServerState::instance(); serverState.composerRequest[token] = QString::fromUtf8(email); auto &state = ServerState::instance(); QNetworkReply *reply; if (method == QHttpServerRequest::Method::Post) { const auto body = request.body(); reply = state.qnam.post(viewEmailRequest, body); } else { reply = state.qnam.deleteResource(viewEmailRequest); } QObject::connect(reply, &QNetworkReply::finished, reply, [reply]() { if (reply->error() != QNetworkReply::NoError) { qWarning() << reply->error() << reply->errorString(); } else { qWarning() << "sent request to view message to server"; } }); return QHttpServerResponse(QJsonObject { {"status"_L1, "ok"_L1}, }); } QHttpServerResponse EmailController::viewEmailAction(const QHttpServerRequest &request) { if (request.method() != QHttpServerRequest::Method::Post) { return badRequest(u"Endpoint only supports POST request"_s); } return abstractEmailAction(request, u"view"_s); } QHttpServerResponse EmailController::newEmailAction(const QHttpServerRequest &request) { if (request.method() != QHttpServerRequest::Method::Post) { return badRequest(u"Endpoint only supports POST request"_s); } return abstractEmailAction(request, u"new"_s); } QHttpServerResponse EmailController::draftAction(QString, const QHttpServerRequest &request) { if (request.method() != QHttpServerRequest::Method::Post && request.method() != QHttpServerRequest::Method::Delete) { return badRequest(u"Endpoint only supports POST request"_s); } return abstractEmailAction(request, request.url().path(), request.method()); } QHttpServerResponse EmailController::replyEmailAction(const QHttpServerRequest &request) { if (request.method() != QHttpServerRequest::Method::Post) { return badRequest(u"Endpoint only supports POST request"_s); } return abstractEmailAction(request, u"reply"_s); } QHttpServerResponse EmailController::forwardEmailAction(const QHttpServerRequest &request) { if (request.method() != QHttpServerRequest::Method::Post) { return badRequest(u"Endpoint only supports POST request"_s); } return abstractEmailAction(request, u"forward"_s); } QHttpServerResponse checkStatus(int port, const QByteArray &body) { QNetworkRequest infoEmailRequest(QUrl(u"http://127.0.0.1:"_s + QString::number(port) + u"/info"_s)); infoEmailRequest.setHeader(QNetworkRequest::ContentTypeHeader, u"application/json"_s); auto &state = ServerState::instance(); QEventLoop eventLoop; auto reply = state.qnam.post(infoEmailRequest, body); QObject::connect(reply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit); eventLoop.exec(); QJsonParseError error; const auto resultBody = QJsonDocument::fromJson(reply->readAll(), &error); if (resultBody.isNull()) { return QHttpServerResponse(QHttpServerResponse::StatusCode::BadRequest); } if (!resultBody.isObject()) { return QHttpServerResponse(QHttpServerResponse::StatusCode::BadRequest); } return QHttpServerResponse{resultBody.object()}; } QHttpServerResponse EmailController::infoEmailAction(const QHttpServerRequest &request) { if (request.method() != QHttpServerRequest::Method::Post) { return badRequest(u"Endpoint only supports POST request"_s); } const auto server = checkAuthentification(request); if (!server) { return forbidden(); } return checkStatus(server->port, request.body()); } QHttpServerResponse EmailController::socketWebAction(const QHttpServerRequest &request) { - const auto email = QString::fromUtf8(findHeader(request.headers(), "X-EMAIL")); - const auto token = findHeader(request.headers(), "X-TOKEN"); + const auto email = QString::fromUtf8(Utils::findHeader(request.headers(), "X-EMAIL")); + const auto token = Utils::findHeader(request.headers(), "X-TOKEN"); const auto &serverState = ServerState::instance(); qDebug() << serverState.composerRequest << email << token; if (serverState.composerRequest[token] != email) { return forbidden(); } WebServer::self().sendMessageToWebClient(email, request.body()); return QHttpServerResponse(QJsonObject{ { "status"_L1, "OK"_L1 }, }); } diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt new file mode 100644 index 0000000..6536d9b --- /dev/null +++ b/common/CMakeLists.txt @@ -0,0 +1,10 @@ +# SPDX-FileCopyrightText: 2023 g10 code Gmbh +# SPDX-Contributor: Carl Schwan +# SPDX-License-Identifier: BSD-2-Clause + +add_library(common STATIC + utils.cpp + utils.h +) + +target_link_libraries(common PRIVATE Qt6::Core) diff --git a/common/utils.cpp b/common/utils.cpp new file mode 100644 index 0000000..173fe21 --- /dev/null +++ b/common/utils.cpp @@ -0,0 +1,19 @@ +// SPDX-FileCopyrightText: 2023 g10 code GmbH +// SPDX-Contributor: Carl Schwan +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "utils.h" +#include + +QByteArray Utils::findHeader(QList> headers, const QByteArray &key) +{ + const auto it = std::find_if(std::cbegin(headers), std::cend(headers), [&key](auto header) { + return header.first == key; + }); + + if (it == std::cend(headers)) { + return {}; + } + + return it->second; +} diff --git a/common/utils.h b/common/utils.h new file mode 100644 index 0000000..6e0f097 --- /dev/null +++ b/common/utils.h @@ -0,0 +1,10 @@ +// SPDX-FileCopyrightText: 2023 g10 code GmbH +// SPDX-Contributor: Carl Schwan +// SPDX-License-Identifier: GPL-2.0-or-later + +#include + +namespace Utils +{ +QByteArray findHeader(QList> headers, const QByteArray &key); +} diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index 6592e18..e4dd26a 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -1,290 +1,292 @@ # SPDX-FileCopyrightText: 2023 g10 code GmbH # SPDX-Contributor: Carl Schwan # SPDX-License-Identifier: BSD-2-Clause add_library(gpgol-server-static) target_sources(gpgol-server-static PUBLIC websocketclient.cpp websocketclient.h webserver.h webserver.cpp # Identity identity/addressvalidationjob.cpp identity/addressvalidationjob.h identity/identitymanager.cpp identity/identitymanager.h identity/identitydialog.cpp identity/identitydialog.h identity/identityaddvcarddialog.cpp identity/identityaddvcarddialog.h # HTTP Controller controllers/emailcontroller.cpp controllers/emailcontroller.h # Draft draft/draft.cpp draft/draft.h draft/draftmanager.cpp draft/draftmanager.h # EWS integration ews/ewsattachment.cpp ews/ewsattachment.h ews/ewsattendee.cpp ews/ewsattendee.h ews/ewsclient_debug.cpp ews/ewsclient_debug.h ews/ewsid.cpp ews/ewsid.h ews/ewsitem.cpp ews/ewsitem.h ews/ewsitembase.cpp ews/ewsitembase.h ews/ewsitembase_p.h ews/ewsmailbox.cpp ews/ewsmailbox.h ews/ewsmailfactory.cpp ews/ewsmailfactory.h ews/ewsoccurrence.cpp ews/ewsoccurrence.h ews/ewspropertyfield.cpp ews/ewspropertyfield.h ews/ewsrecurrence.cpp ews/ewsrecurrence.h ews/ewsserverversion.cpp ews/ewsserverversion.h ews/ewstypes.cpp ews/ewstypes.h ews/ewsxml.cpp ews/ewsxml.h # Editor editor/composer.cpp editor/composer.h editor/composerviewbase.cpp editor/composerviewbase.h editor/composerwindow.cpp editor/composerwindow.h editor/composerwindowfactory.cpp editor/composerwindowfactory.h editor/cryptostateindicatorwidget.cpp editor/cryptostateindicatorwidget.h editor/encryptionstate.cpp editor/encryptionstate.h editor/kmcomposerglobalaction.cpp editor/kmcomposerglobalaction.h editor/nearexpirywarning.cpp editor/nearexpirywarning.h editor/mailtemplates.cpp editor/mailtemplates.h editor/recipient.cpp editor/recipient.h editor/recipientline.cpp editor/recipientline.h editor/recipientseditor.cpp editor/recipientseditor.h editor/util.h editor/util.cpp editor/richtextcomposerng.cpp editor/richtextcomposerng.h editor/richtextcomposersignatures.cpp editor/richtextcomposersignatures.h editor/nodehelper.cpp editor/nodehelper.h editor/signaturecontroller.cpp editor/signaturecontroller.h editor/spellcheckerconfigdialog.cpp editor/spellcheckerconfigdialog.h # Editor job editor/job/abstractencryptjob.h editor/job/autocryptheadersjob.h editor/job/contentjobbase.h editor/job/contentjobbase_p.h editor/job/dndfromarkjob.cpp editor/job/dndfromarkjob.h editor/job/encryptjob.h editor/job/inserttextfilejob.h editor/job/itipjob.h editor/job/jobbase.h editor/job/jobbase_p.h editor/job/maintextjob.h editor/job/multipartjob.h editor/job/protectedheadersjob.h editor/job/signencryptjob.h editor/job/signjob.h editor/job/singlepartjob.h editor/job/skeletonmessagejob.h editor/job/transparentjob.h editor/job/autocryptheadersjob.cpp editor/job/contentjobbase.cpp editor/job/encryptjob.cpp editor/job/inserttextfilejob.cpp editor/job/itipjob.cpp editor/job/jobbase.cpp editor/job/maintextjob.cpp editor/job/multipartjob.cpp editor/job/protectedheadersjob.cpp editor/job/saveasfilejob.cpp editor/job/saveasfilejob.h editor/job/signencryptjob.cpp editor/job/signjob.cpp editor/job/singlepartjob.cpp editor/job/skeletonmessagejob.cpp editor/job/transparentjob.cpp ## Editor Part editor/part/globalpart.h editor/part/infopart.h editor/part/itippart.h editor/part/messagepart.h editor/part/textpart.h editor/part/globalpart.cpp editor/part/infopart.cpp editor/part/itippart.cpp editor/part/messagepart.cpp editor/part/textpart.cpp ## Attachment editor/attachment/attachmentjob.cpp editor/attachment/attachmentjob.h editor/attachment/attachmentclipboardjob.cpp editor/attachment/attachmentclipboardjob.h editor/attachment/attachmentcompressjob.cpp editor/attachment/attachmentcompressjob.h editor/attachment/attachmentcontroller.cpp editor/attachment/attachmentcontroller.h editor/attachment/attachmentcontrollerbase.cpp editor/attachment/attachmentcontrollerbase.h editor/attachment/attachmentfromfolderjob.cpp editor/attachment/attachmentfromfolderjob.h editor/attachment/attachmentfrommimecontentjob.cpp editor/attachment/attachmentfrommimecontentjob.h editor/attachment/attachmentfromurlbasejob.cpp editor/attachment/attachmentfromurlbasejob.h editor/attachment/attachmentfromurljob.cpp editor/attachment/attachmentfromurljob.h editor/attachment/attachmentfromurlutils.cpp editor/attachment/attachmentfromurlutils.h editor/attachment/attachmentfrompublickeyjob.cpp editor/attachment/attachmentfrompublickeyjob.h editor/attachment/attachmentloadjob.cpp editor/attachment/attachmentloadjob.h editor/attachment/attachmentmodel.cpp editor/attachment/attachmentmodel.h editor/attachment/attachmentpart.cpp editor/attachment/attachmentpart.h editor/attachment/attachmentpropertiesdialog.cpp editor/attachment/attachmentpropertiesdialog.h editor/attachment/attachmentupdatejob.cpp editor/attachment/attachmentupdatejob.h editor/attachment/attachmentview.cpp editor/attachment/attachmentview.h editor/attachment/editorwatcher.cpp editor/attachment/editorwatcher.h ) qt_add_resources(gpgol-server-static PREFIX "/" FILES assets/certificate.crt ) ki18n_wrap_ui(gpgol-server-static editor/attachment/ui/attachmentpropertiesdialog.ui editor/attachment/ui/attachmentpropertiesdialog_readonly.ui ) ecm_qt_declare_logging_category(gpgol-server-static_SRCS HEADER websocket_debug.h IDENTIFIER WEBSOCKET_LOG CATEGORY_NAME org.gpgol.server.websocket DESCRIPTION "Websocket connection in the server" EXPORT GPGOL ) ecm_qt_declare_logging_category(gpgol-server-static_SRCS HEADER ewsresource_debug.h IDENTIFIER EWSRES_LOG CATEGORY_NAME org.gpgol.ews DESCRIPTION "Ews mail client" EXPORT GPGOL ) ecm_qt_declare_logging_category(gpgol-server-static_SRCS HEADER ewscli_debug.h IDENTIFIER EWSCLI_LOG CATEGORY_NAME org.gpgol.ews.client DESCRIPTION "ews client (gpgol-server)" EXPORT GPGOL ) ecm_qt_declare_logging_category(gpgol-server-static_SRCS HEADER editor_debug.h IDENTIFIER EDITOR_LOG CATEGORY_NAME org.gpgol.editor DESCRIPTION "mail composer" EXPORT GPGOL ) set(WARN_TOOMANY_RECIPIENTS_DEFAULT true) set(ALLOW_SEMICOLON_AS_ADDRESS_SEPARATOR_DEFAULT true) configure_file(editor/settings/messagecomposer.kcfg.in ${CMAKE_CURRENT_BINARY_DIR}/messagecomposer.kcfg) kconfig_add_kcfg_files(gpgol-server-static_SRCS editor/settings/messagecomposersettings.kcfgc ) install(FILES composerui.rc DESTINATION ${KDE_INSTALL_KXMLGUIDIR}/gpgol-server) target_sources(gpgol-server-static PUBLIC ${gpgol-server-static_SRCS}) target_link_libraries(gpgol-server-static PUBLIC + common + Qt6::HttpServer Qt6::Widgets Qt6::PrintSupport KF6::CalendarCore KF6::ConfigCore KF6::ConfigGui KF6::Contacts KF6::Completion KF6::CoreAddons KF6::ColorScheme KF6::Codecs KF6::GuiAddons KF6::SonnetUi KF6::WidgetsAddons KF6::XmlGui KF6::KIOFileWidgets KF6::Archive KF6::TextAutoCorrectionCore KPim6::MimeTreeParserWidgets KPim6::Libkleo KPim6::Libkdepim KPim6::LdapWidgets KPim6::PimTextEdit KPim6::IdentityManagementCore KPim6::IdentityManagementWidgets ) add_executable(gpgol-server main.cpp) target_link_libraries(gpgol-server PRIVATE gpgol-server-static) qt_add_resources(gpgol-server PREFIX "/" FILES assets/certificate.crt ) if (BUILD_TESTING) add_subdirectory(autotests) endif() diff --git a/server/controllers/emailcontroller.cpp b/server/controllers/emailcontroller.cpp index 4f5f77b..7188bec 100644 --- a/server/controllers/emailcontroller.cpp +++ b/server/controllers/emailcontroller.cpp @@ -1,193 +1,178 @@ // SPDX-FileCopyrightText: 2023 g10 code GmbH // SPDX-Contributor: Carl Schwan // SPDX-License-Identifier: GPL-2.0-or-later #include "emailcontroller.h" #include #include #include #include #include #include #include #include #include #include "editor/composerwindow.h" #include "editor/composerwindowfactory.h" #include "draft/draftmanager.h" +#include using namespace Qt::Literals::StringLiterals; -namespace -{ -QByteArray findHeader(QList> headers, const QByteArray &key) -{ - const auto it = std::find_if(std::cbegin(headers), std::cend(headers), [&key](auto header) { - return header.first == key; - }); - - if (it == std::cend(headers)) { - return {}; - } - - return it->second; -} -} - QHttpServerResponse EmailController::viewEmailAction(const QHttpServerRequest &request) { - const auto email = QString::fromUtf8(findHeader(request.headers(), "X-EMAIL")); - const auto displayName = QString::fromUtf8(findHeader(request.headers(), "X-NAME")); - const auto bearerToken = findHeader(request.headers(), "X-TOKEN"); + const auto email = QString::fromUtf8(Utils::findHeader(request.headers(), "X-EMAIL")); + const auto displayName = QString::fromUtf8(Utils::findHeader(request.headers(), "X-NAME")); + const auto bearerToken = Utils::findHeader(request.headers(), "X-TOKEN"); const auto content = request.body(); KMime::Message::Ptr message(new KMime::Message()); message->setContent(KMime::CRLFtoLF(content)); message->parse(); auto dialog = new MimeTreeParser::Widgets::MessageViewerDialog({ message }); dialog->setAttribute(Qt::WA_DeleteOnClose); auto toolBar = dialog->toolBar(); toolBar->show(); // spacer QWidget* spacer = new QWidget(); spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); toolBar->addWidget(spacer); // reply auto replyAction = new QAction(QIcon::fromTheme(u"mail-reply-sender-symbolic"_s), i18nc("@action:button", "Reply"), toolBar); QObject::connect(replyAction, &QAction::triggered, dialog, [message, email, displayName, bearerToken](bool) { auto dialog = ComposerWindowFactory::self().create(email, displayName, bearerToken); dialog->reply(message); dialog->show(); }); toolBar->addAction(replyAction); auto widget = qobject_cast(toolBar->widgetForAction(replyAction)); widget->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); // forward auto forwardAction = new QAction(QIcon::fromTheme(u"mail-forward-symbolic"_s), i18nc("@action:button", "Forward"), toolBar); QObject::connect(forwardAction, &QAction::triggered, dialog, [message, email, displayName, bearerToken](bool) { auto dialog = ComposerWindowFactory::self().create(email, displayName, bearerToken); dialog->reply(message); dialog->show(); }); toolBar->addAction(forwardAction); widget = qobject_cast(toolBar->widgetForAction(forwardAction)); widget->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); dialog->show(); return QHttpServerResponse(QJsonObject { { "status"_L1, "200"_L1 } }); } QHttpServerResponse EmailController::infoEmailAction(const QHttpServerRequest &request) { qDebug() << "request received"; const auto content = request.body(); KMime::Message::Ptr message(new KMime::Message()); message->setContent(KMime::CRLFtoLF(content)); message->parse(); MimeTreeParser::ObjectTreeParser treeParser; treeParser.parseObjectTree(message.get()); return QHttpServerResponse(QJsonObject { { "status"_L1, "200"_L1 }, { "encrypted"_L1, treeParser.hasEncryptedParts() }, { "signed"_L1, treeParser.hasSignedParts() }, { "drafts"_L1, DraftManager::self().toJson() }, }); } QHttpServerResponse EmailController::newEmailAction(const QHttpServerRequest &request) { - const auto email = QString::fromUtf8(findHeader(request.headers(), "X-EMAIL")); - const auto displayName = QString::fromUtf8(findHeader(request.headers(), "X-NAME")); - const auto bearerToken = findHeader(request.headers(), "X-TOKEN"); + const auto email = QString::fromUtf8(Utils::findHeader(request.headers(), "X-EMAIL")); + const auto displayName = QString::fromUtf8(Utils::findHeader(request.headers(), "X-NAME")); + const auto bearerToken = Utils::findHeader(request.headers(), "X-TOKEN"); auto dialog = ComposerWindowFactory::self().create(email, displayName, bearerToken); dialog->show(); return QHttpServerResponse(QJsonObject { { "status"_L1, "200"_L1 } }); } QHttpServerResponse EmailController::replyEmailAction(const QHttpServerRequest &request) { - const auto email = QString::fromUtf8(findHeader(request.headers(), "X-EMAIL")); - const auto displayName = QString::fromUtf8(findHeader(request.headers(), "X-NAME")); - const auto bearerToken = findHeader(request.headers(), "X-TOKEN"); + const auto email = QString::fromUtf8(Utils::findHeader(request.headers(), "X-EMAIL")); + const auto displayName = QString::fromUtf8(Utils::findHeader(request.headers(), "X-NAME")); + const auto bearerToken = Utils::findHeader(request.headers(), "X-TOKEN"); const auto content = request.body(); KMime::Message::Ptr message(new KMime::Message()); message->setContent(KMime::CRLFtoLF(content)); message->parse(); auto dialog = ComposerWindowFactory::self().create(email, displayName, bearerToken); dialog->reply(message); dialog->show(); return QHttpServerResponse(QJsonObject { { "status"_L1, "200"_L1 } }); } QHttpServerResponse EmailController::forwardEmailAction(const QHttpServerRequest &request) { - const auto email = QString::fromUtf8(findHeader(request.headers(), "X-EMAIL")); - const auto displayName = QString::fromUtf8(findHeader(request.headers(), "X-NAME")); - const auto bearerToken = findHeader(request.headers(), "X-TOKEN"); + const auto email = QString::fromUtf8(Utils::findHeader(request.headers(), "X-EMAIL")); + const auto displayName = QString::fromUtf8(Utils::findHeader(request.headers(), "X-NAME")); + const auto bearerToken = Utils::findHeader(request.headers(), "X-TOKEN"); const auto content = request.body(); KMime::Message::Ptr message(new KMime::Message()); message->setContent(KMime::CRLFtoLF(content)); message->parse(); auto dialog = ComposerWindowFactory::self().create(email, displayName, bearerToken); dialog->forward(message); dialog->show(); return QHttpServerResponse(QJsonObject { { "status"_L1, "200"_L1 } }); } QHttpServerResponse EmailController::draftAction(QString draftId, const QHttpServerRequest &request) { - const auto email = QString::fromUtf8(findHeader(request.headers(), "X-EMAIL")); - const auto displayName = QString::fromUtf8(findHeader(request.headers(), "X-NAME")); - const auto bearerToken = findHeader(request.headers(), "X-TOKEN"); + const auto email = QString::fromUtf8(Utils::findHeader(request.headers(), "X-EMAIL")); + const auto displayName = QString::fromUtf8(Utils::findHeader(request.headers(), "X-NAME")); + const auto bearerToken = Utils::findHeader(request.headers(), "X-TOKEN"); const auto draft = DraftManager::self().draftById(draftId.toUtf8()); if (!draft.isValid()) { return QHttpServerResponse(QJsonObject { { "status"_L1, "404"_L1 } }, QHttpServerResponse::StatusCode::NotFound); } if (request.method() == QHttpServerRequest::Method::Post) { // POST auto dialog = ComposerWindowFactory::self().create(email, displayName, bearerToken); dialog->setMessage(draft.mime()); dialog->show(); } else { // DELETE if (!DraftManager::self().remove(draft)) { return QHttpServerResponse(QJsonObject { { "status"_L1, "500"_L1 } }, QHttpServerResponse::StatusCode::InternalServerError); } } return QHttpServerResponse(QJsonObject { { "status"_L1, "200"_L1 } }); }