From 345cc45a3eba68e49df880a389b90222c0e398c2 Mon Sep 17 00:00:00 2001 From: Xavier Michelon Date: Wed, 3 Aug 2022 12:03:52 +0200 Subject: [PATCH] Other: introduced bridgepp static C++ library. --- .../frontend/bridge-gui/AppController.cpp | 11 +- internal/frontend/bridge-gui/AppController.h | 22 +- .../frontend/bridge-gui/BridgeMonitor.cpp | 5 +- internal/frontend/bridge-gui/BridgeMonitor.h | 4 +- internal/frontend/bridge-gui/CMakeLists.txt | 133 ++----- .../frontend/bridge-gui/DockIcon/DockIcon.cpp | 1 - .../frontend/bridge-gui/DockIcon/DockIcon.mm | 1 - .../frontend/bridge-gui/EventStreamWorker.cpp | 10 +- .../frontend/bridge-gui/EventStreamWorker.h | 5 +- .../frontend/bridge-gui/GRPC/GRPCUtils.cpp | 84 ---- internal/frontend/bridge-gui/Pch.h | 7 - internal/frontend/bridge-gui/QMLBackend.cpp | 76 ++-- internal/frontend/bridge-gui/QMLBackend.h | 70 ++-- internal/frontend/bridge-gui/User/User.cpp | 95 ----- internal/frontend/bridge-gui/User/User.h | 93 ----- .../bridge-gui/{User => }/UserList.cpp | 31 +- .../frontend/bridge-gui/{User => }/UserList.h | 32 +- internal/frontend/bridge-gui/main.cpp | 16 +- internal/frontend/bridgepp/CMakeLists.txt | 124 ++++++ internal/frontend/bridgepp/Pch.h | 26 ++ internal/frontend/bridgepp/bridge_setup.cmake | 60 +++ .../bridgepp/bridgepp/BridgeUtils.cpp | 56 +++ .../bridgepp/BridgeUtils.h} | 19 +- .../bridgepp/Exception}/Exception.cpp | 8 +- .../bridgepp/Exception}/Exception.h | 27 +- .../bridgepp}/GRPC/GRPCClient.cpp | 359 ++++++++++-------- .../bridgepp}/GRPC/GRPCClient.h | 103 ++--- .../bridgepp/bridgepp/GRPC/GRPCUtils.cpp | 182 +++++++++ .../bridgepp/bridgepp/GRPC/GRPCUtils.h | 42 ++ .../bridgepp}/GRPC/bridge.grpc.pb.cc | 0 .../bridgepp}/GRPC/bridge.grpc.pb.h | 0 .../bridgepp}/GRPC/bridge.pb.cc | 0 .../bridgepp}/GRPC/bridge.pb.h | 0 .../bridgepp/Log}/Log.cpp | 80 +++- .../bridgepp/Log}/Log.h | 23 +- .../frontend/bridgepp/bridgepp/User/User.cpp | 329 ++++++++++++++++ .../frontend/bridgepp/bridgepp/User/User.h | 130 +++++++ .../bridgepp}/Worker/Overseer.cpp | 12 +- .../bridgepp}/Worker/Overseer.h | 31 +- .../bridgepp}/Worker/Worker.h | 32 +- utils/missing_license.sh | 1 + 41 files changed, 1554 insertions(+), 786 deletions(-) delete mode 100644 internal/frontend/bridge-gui/GRPC/GRPCUtils.cpp delete mode 100644 internal/frontend/bridge-gui/User/User.cpp delete mode 100644 internal/frontend/bridge-gui/User/User.h rename internal/frontend/bridge-gui/{User => }/UserList.cpp (90%) rename internal/frontend/bridge-gui/{User => }/UserList.h (69%) create mode 100644 internal/frontend/bridgepp/CMakeLists.txt create mode 100644 internal/frontend/bridgepp/Pch.h create mode 100644 internal/frontend/bridgepp/bridge_setup.cmake create mode 100644 internal/frontend/bridgepp/bridgepp/BridgeUtils.cpp rename internal/frontend/{bridge-gui/GRPC/GRPCUtils.h => bridgepp/bridgepp/BridgeUtils.h} (60%) rename internal/frontend/{bridge-gui => bridgepp/bridgepp/Exception}/Exception.cpp (98%) rename internal/frontend/{bridge-gui => bridgepp/bridgepp/Exception}/Exception.h (70%) rename internal/frontend/{bridge-gui => bridgepp/bridgepp}/GRPC/GRPCClient.cpp (80%) rename internal/frontend/{bridge-gui => bridgepp/bridgepp}/GRPC/GRPCClient.h (77%) create mode 100644 internal/frontend/bridgepp/bridgepp/GRPC/GRPCUtils.cpp create mode 100644 internal/frontend/bridgepp/bridgepp/GRPC/GRPCUtils.h rename internal/frontend/{bridge-gui => bridgepp/bridgepp}/GRPC/bridge.grpc.pb.cc (100%) rename internal/frontend/{bridge-gui => bridgepp/bridgepp}/GRPC/bridge.grpc.pb.h (100%) rename internal/frontend/{bridge-gui => bridgepp/bridgepp}/GRPC/bridge.pb.cc (100%) rename internal/frontend/{bridge-gui => bridgepp/bridgepp}/GRPC/bridge.pb.h (100%) rename internal/frontend/{bridge-gui => bridgepp/bridgepp/Log}/Log.cpp (81%) rename internal/frontend/{bridge-gui => bridgepp/bridgepp/Log}/Log.h (87%) create mode 100644 internal/frontend/bridgepp/bridgepp/User/User.cpp create mode 100644 internal/frontend/bridgepp/bridgepp/User/User.h rename internal/frontend/{bridge-gui => bridgepp/bridgepp}/Worker/Overseer.cpp (94%) rename internal/frontend/{bridge-gui => bridgepp/bridgepp}/Worker/Overseer.h (72%) rename internal/frontend/{bridge-gui => bridgepp/bridgepp}/Worker/Worker.h (69%) diff --git a/internal/frontend/bridge-gui/AppController.cpp b/internal/frontend/bridge-gui/AppController.cpp index 579a9005..0d6fe09d 100644 --- a/internal/frontend/bridge-gui/AppController.cpp +++ b/internal/frontend/bridge-gui/AppController.cpp @@ -16,13 +16,15 @@ // along with Proton Mail Bridge. If not, see . -#include "Pch.h" #include "AppController.h" #include "QMLBackend.h" -#include "GRPC/GRPCClient.h" -#include "Log.h" #include "BridgeMonitor.h" -#include "Exception.h" +#include +#include +#include + + +using namespace bridgepp; //**************************************************************************************************************************************************** @@ -43,7 +45,6 @@ AppController::AppController() , grpc_(std::make_unique()) , log_(std::make_unique()) { - } diff --git a/internal/frontend/bridge-gui/AppController.h b/internal/frontend/bridge-gui/AppController.h index b8117a64..82e93972 100644 --- a/internal/frontend/bridge-gui/AppController.h +++ b/internal/frontend/bridge-gui/AppController.h @@ -21,10 +21,16 @@ class QMLBackend; -class GRPCClient; +class BridgeMonitor; + + +namespace bridgepp +{ class Log; class Overseer; -class BridgeMonitor; +class GRPCClient; +} + //**************************************************************************************************************************************************** /// \brief App controller class. @@ -41,9 +47,9 @@ public: // member functions. AppController& operator=(AppController const&) = delete; ///< Disabled assignment operator. AppController& operator=(AppController&&) = delete; ///< Disabled move assignment operator. QMLBackend& backend() { return *backend_; } ///< Return a reference to the backend. - GRPCClient& grpc() { return *grpc_; } ///< Return a reference to the GRPC client. - Log& log() { return *log_; } ///< Return a reference to the log. - std::unique_ptr& bridgeOverseer() { return bridgeOverseer_; }; ///< Returns a reference the bridge overseer + bridgepp::GRPCClient& grpc() { return *grpc_; } ///< Return a reference to the GRPC client. + bridgepp::Log& log() { return *log_; } ///< Return a reference to the log. + std::unique_ptr& bridgeOverseer() { return bridgeOverseer_; }; ///< Returns a reference the bridge overseer BridgeMonitor* bridgeMonitor() const; ///< Return the bridge worker. private: // member functions @@ -51,9 +57,9 @@ private: // member functions private: // data members std::unique_ptr backend_; ///< The backend. - std::unique_ptr grpc_; ///< The RPC client. - std::unique_ptr log_; ///< The log. - std::unique_ptr bridgeOverseer_; ///< The overseer for the bridge monitor worker. + std::unique_ptr grpc_; ///< The RPC client. + std::unique_ptr log_; ///< The log. + std::unique_ptr bridgeOverseer_; ///< The overseer for the bridge monitor worker. }; diff --git a/internal/frontend/bridge-gui/BridgeMonitor.cpp b/internal/frontend/bridge-gui/BridgeMonitor.cpp index 9750e2db..435ebd6e 100644 --- a/internal/frontend/bridge-gui/BridgeMonitor.cpp +++ b/internal/frontend/bridge-gui/BridgeMonitor.cpp @@ -17,7 +17,10 @@ #include "BridgeMonitor.h" -#include "Exception.h" +#include + + +using namespace bridgepp; namespace diff --git a/internal/frontend/bridge-gui/BridgeMonitor.h b/internal/frontend/bridge-gui/BridgeMonitor.h index be6aee3f..f3e1f640 100644 --- a/internal/frontend/bridge-gui/BridgeMonitor.h +++ b/internal/frontend/bridge-gui/BridgeMonitor.h @@ -21,13 +21,13 @@ #define BRIDGE_GUI_BRIDGE_MONITOR_H -#include "Worker/Worker.h" +#include //********************************************************************************************************************** /// \brief Bridge process launcher and monitor class. //********************************************************************************************************************** -class BridgeMonitor: public Worker +class BridgeMonitor: public bridgepp::Worker { Q_OBJECT public: // static member functions diff --git a/internal/frontend/bridge-gui/CMakeLists.txt b/internal/frontend/bridge-gui/CMakeLists.txt index e07cc397..6740109f 100644 --- a/internal/frontend/bridge-gui/CMakeLists.txt +++ b/internal/frontend/bridge-gui/CMakeLists.txt @@ -17,41 +17,16 @@ cmake_minimum_required(VERSION 3.22) -# We rely on vcpkg for to get gRPC / Protobuf -# run build.sh / build.ps1 to get gRPC / Protobuf and dependencies installed. +include_guard() set(VCPKG_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../../../extern/vcpkg") -message(STATUS "VCPKG_ROOT is ${VCPKG_ROOT}") -if (WIN32) - find_program(VCPKG_EXE "${VCPKG_ROOT}/vcpkg.exe") -else() - find_program(VCPKG_EXE "${VCPKG_ROOT}/vcpkg") -endif() +include(../bridgepp/bridge_setup.cmake) -# For now we support only a single architecture for macOS (ARM64 or x86_64). We need to investigate how to build universal binaries with vcpkg. -if (APPLE) - if (NOT DEFINED CMAKE_OSX_ARCHITECTURES) - execute_process(COMMAND "uname" "-m" OUTPUT_VARIABLE UNAME_RESULT OUTPUT_STRIP_TRAILING_WHITESPACE) - set(CMAKE_OSX_ARCHITECTURES ${UNAME_RESULT} CACHE STRING "osx_architectures") - endif() +#***************************************************************************************************************************************************** +# Project +#***************************************************************************************************************************************************** - if (CMAKE_OSX_ARCHITECTURES STREQUAL "arm64") - message(STATUS "Building for Apple Silicon Mac computers") - set(VCPKG_TARGET_TRIPLET arm64-osx) - elseif (CMAKE_OSX_ARCHITECTURES STREQUAL "x86_64") - message(STATUS "Building for Intel based Mac computers") - set(VCPKG_TARGET_TRIPLET x64-osx) - else () - message(FATAL_ERROR "Unknown value for CMAKE_OSX_ARCHITECTURE. Please use one of \"arm64\" and \"x86_64\". Multiple architectures are not supported.") - endif () -endif() - -if (WIN32) - message(STATUS "Building for Intel x64 Windows computers") - set(VCPKG_TARGET_TRIPLET x64-windows) -endif() -set(CMAKE_TOOLCHAIN_FILE "${VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" CACHE STRING "toolchain") project(bridge-gui LANGUAGES CXX) @@ -61,116 +36,70 @@ else() message(STATUS "Bridge version is ${BRIDGE_APP_VERSION}") endif() -configure_file(Version.h.in ${CMAKE_SOURCE_DIR}/Version.h) if (APPLE) # On macOS, we have some Objective-C++ code in DockIcon to deal with the dock icon. enable_language(OBJC OBJCXX) endif() +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +if (APPLE) # We need to link the Cocoa framework for the dock icon. + find_library(COCOA_LIBRARY Cocoa REQUIRED) +endif() + + +#***************************************************************************************************************************************************** +# Qt +#***************************************************************************************************************************************************** + + if (NOT DEFINED ENV{QT6DIR}) message(FATAL_ERROR "QT6DIR needs to be defined and point to the root of your Qt 6 folder (e.g. /Users/MyName/Qt/6.3.1/clang_64).") endif() set(CMAKE_PREFIX_PATH $ENV{QT6DIR} ${CMAKE_PREFIX_PATH}) -set(CMAKE_CXX_STANDARD 20) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_AUTOMOC ON) +find_package(Qt6 COMPONENTS Core Quick Qml QuickControls2 REQUIRED) +qt_standard_project_setup() set(CMAKE_AUTORCC ON) -set(CMAKE_AUTOUIC ON) -find_package(Protobuf CONFIG REQUIRED) -message(STATUS "Using protobuf ${Protobuf_VERSION}") - - -find_package(gRPC CONFIG REQUIRED) -message(STATUS "Using gRPC ${gRPC_VERSION}") - - -if (APPLE) # We need to link the Cocoa framework for the dock icon. - find_library(COCOA_LIBRARY Cocoa REQ UIRED) -endif() - - -find_package(Qt6 COMPONENTS - Core - Quick - Qml - QuickControls2 - REQUIRED) message(STATUS "Using Qt ${Qt6_VERSION}") -find_program(PROTOC_EXE protoc REQUIRED) -message(STATUS "protoc found ${PROTOC_EXE}") -message(STATUS "grpc_cpp_plugin ${grpc_cpp_plugin}") +#***************************************************************************************************************************************************** +# Source files and output +#***************************************************************************************************************************************************** -find_program(GRPC_CPP_PLUGIN grpc_cpp_plugin) -if(GRPC_CPP_PLUGIN STREQUAL GRPC_CPP_PLUGIN-NOTFOUND) -message(FATAL_ERROR "grpc_cpp_plugin exe could not be found. Please add it to your path. it should be located in \${VCPKG_ROOT}/installed/arm64-osx/tools/grpc") -else() - message(STATUS "grpc_cpp_plugin found at ${GRPC_CPP_PLUGIN}") -endif() -set(PROTO_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../grpc") -set(PROTO_FILE "${PROTO_DIR}/bridge.proto") -set(GRPC_OUT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/GRPC") -set(PROTO_CPP_FILE "${GRPC_OUT_DIR}/bridge.pb.cc") -set(PROTO_H_FILE "${GRPC_OUT_DIR}/bridge.pb.h") -set(GRPC_CPP_FILE "${GRPC_OUT_DIR}/bridge.grpc.pb.cc") -set(GRPC_H_FILE "${GRPC_OUT_DIR}/bridge.grpc.pb.h") +configure_file(Version.h.in ${CMAKE_SOURCE_DIR}/Version.h) + +add_subdirectory(../bridgepp bridgepp) + if (APPLE) set(DOCK_ICON_SRC_FILE DockIcon/DockIcon.mm) else() set(DOCK_ICON_SRC_FILE DockIcon/DockIcon.cpp) endif() -add_custom_command( - OUTPUT - ${PROTO_CPP_FILE} - ${PROTO_H_FILE} - ${GRPC_CPP_FILE} - ${GRPC_H_FILE} - COMMAND - ${PROTOC_EXE} - ARGS - --proto_path=${PROTO_DIR} - --plugin=protoc-gen-grpc="${GRPC_CPP_PLUGIN}" - --cpp_out=${GRPC_OUT_DIR} - --grpc_out=${GRPC_OUT_DIR} - ${PROTO_FILE} - DEPENDS - ${PROTO_FILE} - COMMENT "Generating gPRC/Protobuf C++ code" -) - add_executable(bridge-gui Resources.qrc - ${PROTO_CPP_FILE} ${PROTO_H_FILE} ${GRPC_CPP_FILE} ${GRPC_H_FILE} AppController.cpp AppController.h BridgeMonitor.cpp BridgeMonitor.h EventStreamWorker.cpp EventStreamWorker.h - Exception.cpp Exception.h - Log.cpp Log.h main.cpp Pch.h Version.h QMLBackend.cpp QMLBackend.h + UserList.cpp UserList.h ${DOCK_ICON_SRC_FILE} DockIcon/DockIcon.h - GRPC/GRPCClient.cpp GRPC/GRPCClient.h - GRPC/GRPCUtils.cpp GRPC/GRPCUtils.h - User/User.cpp User/User.h User/UserList.cpp User/UserList.h - Worker/Overseer.cpp Worker/Overseer.h - Worker/Worker.h) - -include_directories(${CMAKE_CURRENT_SOURCE_DIR}) + ) target_precompile_headers(bridge-gui PRIVATE Pch.h) - +target_include_directories(bridge-gui PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(bridge-gui Qt6::Core Qt6::Quick Qt6::Qml Qt6::QuickControls2 - protobuf::libprotobuf - gRPC::grpc++ + bridgepp ) if (APPLE) diff --git a/internal/frontend/bridge-gui/DockIcon/DockIcon.cpp b/internal/frontend/bridge-gui/DockIcon/DockIcon.cpp index d9901910..f7df4372 100644 --- a/internal/frontend/bridge-gui/DockIcon/DockIcon.cpp +++ b/internal/frontend/bridge-gui/DockIcon/DockIcon.cpp @@ -16,7 +16,6 @@ // along with Proton Mail Bridge. If not, see . -#include "Pch.h" #ifndef Q_OS_MACOS diff --git a/internal/frontend/bridge-gui/DockIcon/DockIcon.mm b/internal/frontend/bridge-gui/DockIcon/DockIcon.mm index 0b2bfd4f..471dc77f 100644 --- a/internal/frontend/bridge-gui/DockIcon/DockIcon.mm +++ b/internal/frontend/bridge-gui/DockIcon/DockIcon.mm @@ -16,7 +16,6 @@ // along with Proton Mail Bridge. If not, see . -#include "Pch.h" #include #include "DockIcon.h" diff --git a/internal/frontend/bridge-gui/EventStreamWorker.cpp b/internal/frontend/bridge-gui/EventStreamWorker.cpp index c133582f..63012df3 100644 --- a/internal/frontend/bridge-gui/EventStreamWorker.cpp +++ b/internal/frontend/bridge-gui/EventStreamWorker.cpp @@ -16,11 +16,13 @@ // along with Proton Mail Bridge. If not, see . -#include "Pch.h" #include "EventStreamWorker.h" -#include "GRPC/GRPCClient.h" -#include "Log.h" -#include "Exception.h" +#include +#include +#include + + +using namespace bridgepp; //**************************************************************************************************************************************************** diff --git a/internal/frontend/bridge-gui/EventStreamWorker.h b/internal/frontend/bridge-gui/EventStreamWorker.h index 293dceb1..e9976b19 100644 --- a/internal/frontend/bridge-gui/EventStreamWorker.h +++ b/internal/frontend/bridge-gui/EventStreamWorker.h @@ -20,14 +20,13 @@ #define BRIDGE_GUI_EVENT_STREAM_WORKER_H -#include "GRPC/bridge.grpc.pb.h" -#include "Worker/Worker.h" +#include //**************************************************************************************************************************************************** /// \brief Stream reader class. //**************************************************************************************************************************************************** -class EventStreamReader: public Worker +class EventStreamReader: public bridgepp::Worker { Q_OBJECT public: // member functions diff --git a/internal/frontend/bridge-gui/GRPC/GRPCUtils.cpp b/internal/frontend/bridge-gui/GRPC/GRPCUtils.cpp deleted file mode 100644 index 729e1af2..00000000 --- a/internal/frontend/bridge-gui/GRPC/GRPCUtils.cpp +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) 2022 Proton AG -// -// This file is part of Proton Mail Bridge. -// -// Proton Mail Bridge is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Proton Mail Bridge 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Proton Mail Bridge. If not, see . - - -#include "Pch.h" -#include "Exception.h" -#include "GRPCUtils.h" - - -//**************************************************************************************************************************************************** -/// \param[in] status The status -/// \param[in] callName The call name. -//**************************************************************************************************************************************************** -void logGRPCCallStatus(grpc::Status const& status, QString const &callName) -{ - if (status.ok()) - app().log().debug(QString("%1()").arg(callName)); - else - app().log().error(QString("%1() FAILED").arg(callName)); -} - - -//**************************************************************************************************************************************************** -/// \param[in] grpcUser the gRPC user struct -/// \return a user. -//**************************************************************************************************************************************************** -SPUser parsegrpcUser(grpc::User const &grpcUser) -{ - // As we want to use shared pointers here, we do not want to use the Qt ownership system, so we set parent to nil. - // But: From https://doc.qt.io/qt-5/qtqml-cppintegration-data.html: - // " When data is transferred from C++ to QML, the ownership of the data always remains with C++. The exception to this rule - // is when a QObject is returned from an explicit C++ method call: in this case, the QML engine assumes ownership of the object. " - // This is the case here, so we explicitely indicate that the object is owned by C++. - SPUser user = std::make_shared(nullptr); - QQmlEngine::setObjectOwnership(user.get(), QQmlEngine::CppOwnership); - user->setProperty("username", QString::fromStdString(grpcUser.username())); - user->setProperty("avatarText", QString::fromStdString(grpcUser.avatartext())); - user->setProperty("loggedIn", grpcUser.loggedin()); - user->setProperty("splitMode", grpcUser.splitmode()); - user->setProperty("setupGuideSeen", grpcUser.setupguideseen()); - user->setProperty("usedBytes", float(grpcUser.usedbytes())); - user->setProperty("totalBytes", float(grpcUser.totalbytes())); - user->setProperty("password", QString::fromStdString(grpcUser.password())); - QStringList addresses; - for (int j = 0; j < grpcUser.addresses_size(); ++j) - addresses.append(QString::fromStdString(grpcUser.addresses(j))); - user->setProperty("addresses", addresses); - user->setProperty("id", QString::fromStdString(grpcUser.id())); - return user; -} - - -//**************************************************************************************************************************************************** -/// \param[in] level The log level -//**************************************************************************************************************************************************** -grpc::LogLevel logLevelToGRPC(Log::Level level) -{ - switch (level) - { - case Log::Level::Panic: return grpc::LogLevel::PANIC; - case Log::Level::Fatal: return grpc::LogLevel::FATAL; - case Log::Level::Error: return grpc::LogLevel::ERROR; - case Log::Level::Warn: return grpc::LogLevel::WARN; - case Log::Level::Info: return grpc::LogLevel::INFO; - case Log::Level::Debug: return grpc::LogLevel::DEBUG; - case Log::Level::Trace: return grpc::LogLevel::TRACE; - default: - throw Exception(QString("unknown log level %1.").arg(qint32(level))); - } -} diff --git a/internal/frontend/bridge-gui/Pch.h b/internal/frontend/bridge-gui/Pch.h index a6f1bfcc..d18a9fb3 100644 --- a/internal/frontend/bridge-gui/Pch.h +++ b/internal/frontend/bridge-gui/Pch.h @@ -27,11 +27,4 @@ #include -#if defined(Q_OS_WIN32) && defined(ERROR) -// The folks at Microsoft have decided that it was OK to `#define ERROR 0` in wingdi.h. It is not OK, because -// any occurrence of ERROR, even scoped, will be substituted. For instance Log::Level::ERROR (case imposed by gRPC). -#undef ERROR -#endif - - #endif // BRIDGE_GUI_PCH_H diff --git a/internal/frontend/bridge-gui/QMLBackend.cpp b/internal/frontend/bridge-gui/QMLBackend.cpp index 355edcc4..21fbd80c 100644 --- a/internal/frontend/bridge-gui/QMLBackend.cpp +++ b/internal/frontend/bridge-gui/QMLBackend.cpp @@ -16,13 +16,15 @@ // along with Proton Mail Bridge. If not, see . -#include "Pch.h" #include "QMLBackend.h" -#include "Exception.h" -#include "GRPC/GRPCClient.h" -#include "Worker/Overseer.h" #include "EventStreamWorker.h" #include "Version.h" +#include +#include +#include + + +using namespace bridgepp; //**************************************************************************************************************************************************** @@ -30,7 +32,6 @@ //**************************************************************************************************************************************************** QMLBackend::QMLBackend() : QObject() - , users_(new UserList(this)) { } @@ -40,6 +41,9 @@ QMLBackend::QMLBackend() //**************************************************************************************************************************************************** void QMLBackend::init() { + users_ = new UserList(this); + + app().grpc().setLog(&app().log()); this->connectGrpcEvents(); QString error; @@ -47,10 +51,11 @@ void QMLBackend::init() app().log().info("Connected to backend via gRPC service."); else throw Exception(QString("Cannot connectToServer to go backend via gRPC: %1").arg(error)); + QString bridgeVer; app().grpc().version(bridgeVer); if (bridgeVer != PROJECT_VER) - throw Exception(QString("Version Mismatched from Bridge (%1) and Bridge-GUI (%2)").arg(bridgeVer).arg(PROJECT_VER)); + throw Exception(QString("Version Mismatched from Bridge (%1) and Bridge-GUI (%2)").arg(bridgeVer, PROJECT_VER)); eventStreamOverseer_ = std::make_unique(new EventStreamReader(nullptr), nullptr); eventStreamOverseer_->startWorker(true); @@ -60,10 +65,10 @@ void QMLBackend::init() }); // Grab from bridge the value that will not change during the execution of this app (or that will only change locally - logGRPCCallStatus(app().grpc().showSplashScreen(showSplashScreen_), "showSplashScreen"); - logGRPCCallStatus(app().grpc().goos(goos_), "goos"); - logGRPCCallStatus(app().grpc().logsPath(logsPath_), "logsPath"); - logGRPCCallStatus(app().grpc().licensePath(licensePath_), "licensePath"); + app().grpc().showSplashScreen(showSplashScreen_); + app().grpc().goos(goos_); + app().grpc().logsPath(logsPath_); + app().grpc().licensePath(licensePath_); this->retrieveUserList(); } @@ -147,7 +152,16 @@ void QMLBackend::connectGrpcEvents() void QMLBackend::retrieveUserList() { QList users; - logGRPCCallStatus(app().grpc().getUserList(users), "getUserList"); + app().grpc().getUserList(users); + + // As we want to use shared pointers here, we do not want to use the Qt ownership system, so we set parent to nil. + // But: From https://doc.qt.io/qt-5/qtqml-cppintegration-data.html: + // " When data is transferred from C++ to QML, the ownership of the data always remains with C++. The exception to this rule + // is when a QObject is returned from an explicit C++ method call: in this case, the QML engine assumes ownership of the object. " + // This is the case here, so we explicitly indicate that the object is owned by C++. + for (SPUser const& user: users) + QQmlEngine::setObjectOwnership(user.get(), QQmlEngine::CppOwnership); + users_->reset(users); } @@ -176,7 +190,7 @@ QPoint QMLBackend::getCursorPos() bool QMLBackend::isPortFree(int port) { bool isFree = false; - logGRPCCallStatus(app().grpc().isPortFree(port, isFree), "isPortFree"); + app().grpc().isPortFree(port, isFree); return isFree; } @@ -186,7 +200,7 @@ bool QMLBackend::isPortFree(int port) //**************************************************************************************************************************************************** void QMLBackend::guiReady() { - logGRPCCallStatus(app().grpc().guiReady(), "guiReady"); + app().grpc().guiReady(); } @@ -195,7 +209,7 @@ void QMLBackend::guiReady() //**************************************************************************************************************************************************** void QMLBackend::quit() { - logGRPCCallStatus(app().grpc().quit(), "quit"); + app().grpc().quit(); qApp->exit(0); } @@ -205,7 +219,7 @@ void QMLBackend::quit() //**************************************************************************************************************************************************** void QMLBackend::restart() { - logGRPCCallStatus(app().grpc().restart(), "restart"); + app().grpc().restart(); app().log().error("RESTART is not implemented"); /// \todo GODT-1671 implement restart. } @@ -215,7 +229,7 @@ void QMLBackend::restart() //**************************************************************************************************************************************************** void QMLBackend::toggleAutostart(bool active) { - logGRPCCallStatus(app().grpc().setIsAutostartOn(active), "setIsAutostartOn"); + app().grpc().setIsAutostartOn(active); emit isAutostartOnChanged(this->isAutostartOn()); } @@ -225,7 +239,7 @@ void QMLBackend::toggleAutostart(bool active) //**************************************************************************************************************************************************** void QMLBackend::toggleBeta(bool active) { - logGRPCCallStatus(app().grpc().setisBetaEnabled(active), "setIsBetaEnabled"); + app().grpc().setIsBetaEnabled(active); emit isBetaEnabledChanged(this->isBetaEnabled()); } @@ -235,7 +249,7 @@ void QMLBackend::toggleBeta(bool active) //**************************************************************************************************************************************************** void QMLBackend::changeColorScheme(QString const &scheme) { - logGRPCCallStatus(app().grpc().setColorSchemeName(scheme), "setIsBetaEnabled"); + app().grpc().setColorSchemeName(scheme); emit colorSchemeNameChanged(this->colorSchemeName()); } @@ -245,9 +259,7 @@ void QMLBackend::changeColorScheme(QString const &scheme) //**************************************************************************************************************************************************** void QMLBackend::toggleUseSSLforSMTP(bool makeItActive) { - grpc::Status status = app().grpc().setUseSSLForSMTP(makeItActive); - logGRPCCallStatus(status, "setUseSSLForSMTP"); - if (status.ok()) + if (app().grpc().setUseSSLForSMTP(makeItActive).ok()) emit useSSLforSMTPChanged(makeItActive); } @@ -258,9 +270,7 @@ void QMLBackend::toggleUseSSLforSMTP(bool makeItActive) //**************************************************************************************************************************************************** void QMLBackend::changePorts(int imapPort, int smtpPort) { - grpc::Status status = app().grpc().changePorts(imapPort, smtpPort); - logGRPCCallStatus(status, "changePorts"); - if (status.ok()) + if (app().grpc().changePorts(imapPort, smtpPort).ok()) { emit portIMAPChanged(imapPort); emit portSMTPChanged(smtpPort); @@ -273,9 +283,7 @@ void QMLBackend::changePorts(int imapPort, int smtpPort) //**************************************************************************************************************************************************** void QMLBackend::toggleDoH(bool active) { - grpc::Status status = app().grpc().setIsDoHEnabled(active); - logGRPCCallStatus(status, "toggleDoH"); - if (status.ok()) + if (app().grpc().setIsDoHEnabled(active).ok()) emit isDoHEnabledChanged(active); } @@ -285,9 +293,7 @@ void QMLBackend::toggleDoH(bool active) //**************************************************************************************************************************************************** void QMLBackend::changeKeychain(QString const &keychain) { - grpc::Status status = app().grpc().setCurrentKeychain(keychain); - logGRPCCallStatus(status, "setCurrentKeychain"); - if (status.ok()) + if (app().grpc().setCurrentKeychain(keychain).ok()) emit currentKeychainChanged(keychain); } @@ -297,9 +303,7 @@ void QMLBackend::changeKeychain(QString const &keychain) //**************************************************************************************************************************************************** void QMLBackend::toggleAutomaticUpdate(bool active) { - grpc::Status status = app().grpc().setIsAutomaticUpdateOn(active); - logGRPCCallStatus(status, "toggleAutomaticUpdate"); - if (status.ok()) + if (app().grpc().setIsAutomaticUpdateOn(active).ok()) emit isAutomaticUpdateOnChanged(active); } @@ -309,7 +313,7 @@ void QMLBackend::toggleAutomaticUpdate(bool active) //**************************************************************************************************************************************************** void QMLBackend::checkUpdates() { - logGRPCCallStatus(app().grpc().checkUpdate(), "checkUpdate"); + app().grpc().checkUpdate(); } @@ -318,7 +322,7 @@ void QMLBackend::checkUpdates() //**************************************************************************************************************************************************** void QMLBackend::installUpdate() { - logGRPCCallStatus(app().grpc().installUpdate(), "installUpdate"); + app().grpc().installUpdate(); } @@ -327,5 +331,5 @@ void QMLBackend::installUpdate() //**************************************************************************************************************************************************** void QMLBackend::triggerReset() { - logGRPCCallStatus(app().grpc().triggerReset(), "triggerReset"); + app().grpc().triggerReset(); } diff --git a/internal/frontend/bridge-gui/QMLBackend.h b/internal/frontend/bridge-gui/QMLBackend.h index b586d30e..204b99c5 100644 --- a/internal/frontend/bridge-gui/QMLBackend.h +++ b/internal/frontend/bridge-gui/QMLBackend.h @@ -16,16 +16,15 @@ // along with Proton Mail Bridge. If not, see . -#ifndef BRIDGE_GUI_QMLBACKEND_H -#define BRIDGE_GUI_QMLBACKEND_H +#ifndef BRIDGE_GUI_QML_BACKEND_H +#define BRIDGE_GUI_QML_BACKEND_H -#include #include "DockIcon/DockIcon.h" -#include "GRPC/GRPCClient.h" -#include "GRPC/GRPCUtils.h" -#include "Worker/Overseer.h" -#include "User/UserList.h" +#include "UserList.h" +#include +#include +#include //**************************************************************************************************************************************************** @@ -78,31 +77,31 @@ public: // Qt/QML properties. Note that the NOTIFY-er signal is required even fo Q_PROPERTY(bool dockIconVisible READ dockIconVisible WRITE setDockIconVisible NOTIFY dockIconVisibleChanged) // _ bool `property:dockIconVisible` // Qt Property system setters & getters. - bool showOnStartup() const { bool v = false; logGRPCCallStatus(app().grpc().showOnStartup(v), "showOnStartup"); return v; }; + bool showOnStartup() const { bool v = false; app().grpc().showOnStartup(v); return v; }; bool showSplashScreen() const { return showSplashScreen_; }; void setShowSplashScreen(bool show) { if (show != showSplashScreen_) { showSplashScreen_ = show; emit showSplashScreenChanged(show); } } QString goos() { return goos_; } QUrl logsPath() const { return logsPath_; } QUrl licensePath() const { return licensePath_; } - QUrl releaseNotesLink() const { QUrl link; logGRPCCallStatus(app().grpc().releaseNotesPageLink(link), "releaseNotesPageLink"); return link; } - QUrl dependencyLicensesLink() const { QUrl link; logGRPCCallStatus(app().grpc().dependencyLicensesLink(link), "dependencyLicensesLink"); return link; } - QUrl landingPageLink() const { QUrl link; logGRPCCallStatus(app().grpc().landingPageLink(link), "landingPageLink"); return link; } - QString version() const { QString version; logGRPCCallStatus(app().grpc().version(version), "version"); return version; } - QString hostname() const { QString hostname; logGRPCCallStatus(app().grpc().hostname(hostname), "hostname"); return hostname; } - bool isAutostartOn() const { bool v; logGRPCCallStatus(app().grpc().isAutostartOn(v), "isAutostartOn"); return v; }; - bool isBetaEnabled() const { bool v; logGRPCCallStatus(app().grpc().isBetaEnabled(v), "isBetaEnabled"); return v; } - QString colorSchemeName() const { QString name; logGRPCCallStatus(app().grpc().colorSchemeName(name), "colorSchemeName"); return name; } - bool isDiskCacheEnabled() const { bool enabled; logGRPCCallStatus(app().grpc().isCacheOnDiskEnabled(enabled), "isCacheOnDiskEnabled"); return enabled;} - QUrl diskCachePath() const { QUrl path; logGRPCCallStatus(app().grpc().diskCachePath(path), "diskCachePath"); return path; } - bool useSSLForSMTP() const{ bool useSSL; logGRPCCallStatus(app().grpc().useSSLForSMTP(useSSL), "useSSLForSMTP"); return useSSL; } - int portIMAP() const { int port; logGRPCCallStatus(app().grpc().portIMAP(port), "portIMAP"); return port; } - int portSMTP() const { int port; logGRPCCallStatus(app().grpc().portSMTP(port), "portSMTP"); return port; } - bool isDoHEnabled() const { bool isEnabled; logGRPCCallStatus(app().grpc().isDoHEnabled(isEnabled), "isDoHEnabled"); return isEnabled;} - bool isFirstGUIStart() const { bool v; logGRPCCallStatus(app().grpc().isFirstGUIStart(v), "isFirstGUIStart"); return v; }; - bool isAutomaticUpdateOn() const { bool isOn = false; logGRPCCallStatus(app().grpc().isAutomaticUpdateOn(isOn), "isAutomaticUpdateOn"); return isOn; } - QString currentEmailClient() { QString client; logGRPCCallStatus(app().grpc().currentEmailClient(client), "currentEmailClient"); return client;} - QStringList availableKeychain() const { QStringList keychains; logGRPCCallStatus(app().grpc().availableKeychains(keychains), "availableKeychain"); return keychains; } - QString currentKeychain() const { QString keychain; logGRPCCallStatus(app().grpc().currentKeychain(keychain), "currentKeychain"); return keychain; } + QUrl releaseNotesLink() const { QUrl link; app().grpc().releaseNotesPageLink(link); return link; } + QUrl dependencyLicensesLink() const { QUrl link; app().grpc().dependencyLicensesLink(link); return link; } + QUrl landingPageLink() const { QUrl link; app().grpc().landingPageLink(link); return link; } + QString version() const { QString version; app().grpc().version(version); return version; } + QString hostname() const { QString hostname; app().grpc().hostname(hostname); return hostname; } + bool isAutostartOn() const { bool v; app().grpc().isAutostartOn(v); return v; }; + bool isBetaEnabled() const { bool v; app().grpc().isBetaEnabled(v); return v; } + QString colorSchemeName() const { QString name; app().grpc().colorSchemeName(name); return name; } + bool isDiskCacheEnabled() const { bool enabled; app().grpc().isCacheOnDiskEnabled(enabled); return enabled;} + QUrl diskCachePath() const { QUrl path; app().grpc().diskCachePath(path); return path; } + bool useSSLForSMTP() const{ bool useSSL; app().grpc().useSSLForSMTP(useSSL); return useSSL; } + int portIMAP() const { int port; app().grpc().portIMAP(port); return port; } + int portSMTP() const { int port; app().grpc().portSMTP(port); return port; } + bool isDoHEnabled() const { bool isEnabled; app().grpc().isDoHEnabled(isEnabled); return isEnabled;} + bool isFirstGUIStart() const { bool v; app().grpc().isFirstGUIStart(v); return v; }; + bool isAutomaticUpdateOn() const { bool isOn = false; app().grpc().isAutomaticUpdateOn(isOn); return isOn; } + QString currentEmailClient() { QString client; app().grpc().currentEmailClient(client); return client;} + QStringList availableKeychain() const { QStringList keychains; app().grpc().availableKeychains(keychains); return keychains; } + QString currentKeychain() const { QString keychain; app().grpc().currentKeychain(keychain); return keychain; } bool dockIconVisible() const { return getDockIconVisibleState(); }; void setDockIconVisible(bool visible) { setDockIconVisibleState(visible); emit dockIconVisibleChanged(visible); } @@ -137,12 +136,11 @@ public slots: // slot for signals received from QML -> To be forwarded to Bridge void toggleAutostart(bool active); // _ func(makeItActive bool) `slot:"toggleAutostart"` void toggleBeta(bool active); // _ func(makeItActive bool) `slot:"toggleBeta"` void changeColorScheme(QString const &scheme); // _ func(string) `slot:"changeColorScheme"` - void changeLocalCache(bool enable, QUrl const& path) { logGRPCCallStatus(app().grpc().changeLocalCache(enable, path), "changeLocalCache"); } // _ func(enableDiskCache bool, diskCachePath core.QUrl) `slot:"changeLocalCache"` - void login(QString const& username, QString const& password) { logGRPCCallStatus(app().grpc().login(username, password), "login");} // _ func(username, password string) `slot:"login"` - void login2FA(QString const& username, QString const& code) { logGRPCCallStatus(app().grpc().login2FA(username, code), "login2FA");} // _ func(username, code string) `slot:"login2FA"` - void login2Password(QString const& username, QString const& password) { logGRPCCallStatus(app().grpc().login2Passwords(username, password), - "login2Passwords");} // _ func(username, password string) `slot:"login2Password"` - void loginAbort(QString const& username){ logGRPCCallStatus(app().grpc().loginAbort(username), "loginAbort");} // _ func(username string) `slot:"loginAbort"` + void changeLocalCache(bool enable, QUrl const& path) { app().grpc().changeLocalCache(enable, path); } // _ func(enableDiskCache bool, diskCachePath core.QUrl) `slot:"changeLocalCache"` + void login(QString const& username, QString const& password) { app().grpc().login(username, password);} // _ func(username, password string) `slot:"login"` + void login2FA(QString const& username, QString const& code) { app().grpc().login2FA(username, code);} // _ func(username, code string) `slot:"login2FA"` + void login2Password(QString const& username, QString const& password) { app().grpc().login2Passwords(username, password);} // _ func(username, password string) `slot:"login2Password"` + void loginAbort(QString const& username){ app().grpc().loginAbort(username);} // _ func(username string) `slot:"loginAbort"` void toggleUseSSLforSMTP(bool makeItActive); // _ func(makeItActive bool) `slot:"toggleUseSSLforSMTP"` void changePorts(int imapPort, int smtpPort); // _ func(imapPort, smtpPort int) `slot:"changePorts"` void toggleDoH(bool active); // _ func(makeItActive bool) `slot:"toggleDoH"` @@ -156,7 +154,7 @@ public slots: // slot for signals received from QML -> To be forwarded to Bridge void installUpdate(); // _ func() `slot:"installUpdate"` void triggerReset(); // _ func() `slot:"triggerReset"` void reportBug(QString const &description, QString const& address, QString const &emailClient, bool includeLogs) { - logGRPCCallStatus(app().grpc().reportBug(description, address, emailClient, includeLogs), "reportBug"); } // _ func(description, address, emailClient string, includeLogs bool) `slot:"reportBug"` + app().grpc().reportBug(description, address, emailClient, includeLogs); } // _ func(description, address, emailClient string, includeLogs bool) `slot:"reportBug"` signals: // Signals received from the Go backend, to be forwarded to QML void toggleAutostartFinished(); // _ func() `signal:"toggleAutostartFinished"` @@ -211,7 +209,7 @@ private: // member functions private: // data members UserList* users_ { nullptr }; ///< The user list. Owned by backend. - std::unique_ptr eventStreamOverseer_; ///< The event stream overseer. + std::unique_ptr eventStreamOverseer_; ///< The event stream overseer. bool showSplashScreen_ { false }; ///< The cached version of show splash screen. Retrieved on startup from bridge, and potentially modified locally. QString goos_; ///< The cached version of the GOOS variable. QUrl logsPath_; ///< The logs path. Retrieved from bridge on startup. @@ -221,4 +219,4 @@ private: // data members }; -#endif // BRIDGE_GUI_QMLBACKEND_H +#endif // BRIDGE_GUI_QML_BACKEND_H diff --git a/internal/frontend/bridge-gui/User/User.cpp b/internal/frontend/bridge-gui/User/User.cpp deleted file mode 100644 index 627429e7..00000000 --- a/internal/frontend/bridge-gui/User/User.cpp +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) 2022 Proton AG -// -// This file is part of Proton Mail Bridge. -// -// Proton Mail Bridge is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Proton Mail Bridge 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Proton Mail Bridge. If not, see . - - -#include "Pch.h" -#include "User.h" -#include "GRPC/GRPCUtils.h" -#include "GRPC/GRPCClient.h" - - -//**************************************************************************************************************************************************** -/// \param[in] parent The parent object. -//**************************************************************************************************************************************************** -User::User(QObject *parent) - : QObject(parent) -{ - -} - - -//**************************************************************************************************************************************************** -/// \param[in] user The user to copy from -//**************************************************************************************************************************************************** -void User::update(User const &user) -{ - this->setProperty("username", user.username_); - this->setProperty("avatarText", user.avatarText_); - this->setProperty("loggedIn", user.loggedIn_); - this->setProperty("splitMode", user.splitMode_); - this->setProperty("setupGuideSeen", user.setupGuideSeen_); - this->setProperty("usedBytes", user.usedBytes_); - this->setProperty("totalBytes", user.totalBytes_); - this->setProperty("password", user.password_); - this->setProperty("addresses", user.addresses_); - this->setProperty("id", user.id_); -} - -//**************************************************************************************************************************************************** -/// \param[in] makeItActive Should split mode be made active. -//**************************************************************************************************************************************************** -void User::toggleSplitMode(bool makeItActive) -{ - logGRPCCallStatus(app().grpc().setUserSplitMode(id_, makeItActive), "toggleSplitMode"); -} - -//**************************************************************************************************************************************************** -// -//**************************************************************************************************************************************************** -void User::logout() -{ - logGRPCCallStatus(app().grpc().logoutUser(id_), "logoutUser"); -} - - -//**************************************************************************************************************************************************** -// -//**************************************************************************************************************************************************** -void User::remove() -{ - logGRPCCallStatus(app().grpc().removeUser(id_), "removeUser"); -} - - -//**************************************************************************************************************************************************** -/// \param[in] address The email address to configure Apple Mail for. -//**************************************************************************************************************************************************** -void User::configureAppleMail(QString const &address) -{ - logGRPCCallStatus(app().grpc().configureAppleMail(id_, address), "configureAppleMail"); -} - - -//**************************************************************************************************************************************************** -// The only purpose of this call is to forward to the QML application the toggleSplitModeFinished(userID) event -// that was received by the UserList model. -//**************************************************************************************************************************************************** -void User::emitToggleSplitModeFinished() -{ - this->setProperty("splitMode", QVariant::fromValue(!this->property("splitMode").toBool())); - emit toggleSplitModeFinished(); -} diff --git a/internal/frontend/bridge-gui/User/User.h b/internal/frontend/bridge-gui/User/User.h deleted file mode 100644 index 45163c49..00000000 --- a/internal/frontend/bridge-gui/User/User.h +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) 2022 Proton AG -// -// This file is part of Proton Mail Bridge. -// -// Proton Mail Bridge is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Proton Mail Bridge 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Proton Mail Bridge. If not, see . - - -#ifndef BRIDGE_GUI_USER_H -#define BRIDGE_GUI_USER_H - - -#include "Log.h" - - -//**************************************************************************************************************************************************** -/// \brief User class. -//**************************************************************************************************************************************************** -class User : public QObject -{ -Q_OBJECT -public: // member functions. - explicit User(QObject *parent = nullptr); ///< Default constructor. - User(User const &) = delete; ///< Disabled copy-constructor. - User(User &&) = delete; ///< Disabled assignment copy-constructor. - ~User() override = default; ///< Destructor. - User &operator=(User const &) = delete; ///< Disabled assignment operator. - User &operator=(User &&) = delete; ///< Disabled move assignment operator. - void update(User const &user); ///< Update the user -public slots: - // slots for QML generated calls - void toggleSplitMode(bool makeItActive); // _ func(makeItActive bool) `slot:"toggleSplitMode"` - void logout(); // _ func() `slot:"logout"` - void remove(); // _ func() `slot:"remove"` - void configureAppleMail(QString const &address); // _ func(address string) `slot:"configureAppleMail"` - - // slots for external signals - void emitToggleSplitModeFinished(); - -public: - Q_PROPERTY(QString username MEMBER username_ NOTIFY usernameChanged) // _ string `property:"username"` - Q_PROPERTY(QString avatarText MEMBER avatarText_ NOTIFY avatarTextChanged) // _ string `property:"avatarText"` - Q_PROPERTY(bool loggedIn MEMBER loggedIn_ NOTIFY loggedInChanged) // _ bool `property:"loggedIn"` - Q_PROPERTY(bool splitMode MEMBER splitMode_ NOTIFY splitModeChanged) // _ bool `property:"splitMode"` - Q_PROPERTY(bool setupGuideSeen MEMBER setupGuideSeen_ NOTIFY setupGuideSeenChanged) // _ bool `property:"setupGuideSeen"` - Q_PROPERTY(float usedBytes MEMBER usedBytes_ NOTIFY usedBytesChanged) // _ float32 `property:"usedBytes"` - Q_PROPERTY(float totalBytes MEMBER totalBytes_ NOTIFY totalBytesChanged) // _ float32 `property:"totalBytes"` - Q_PROPERTY(QString password MEMBER password_ NOTIFY passwordChanged) // _ string `property:"password"` - Q_PROPERTY(QStringList addresses MEMBER addresses_ NOTIFY addressesChanged) // _ []string `property:"addresses"` - Q_PROPERTY(QString id MEMBER id_ NOTIFY idChanged) // _ string ID - -signals: - // signals used for Qt properties - void usernameChanged(QString const &username); - void avatarTextChanged(QString const &avatarText); - void loggedInChanged(bool loggedIn); - void splitModeChanged(bool splitMode); - void setupGuideSeenChanged(bool seen); - void usedBytesChanged(float byteCount); - void totalBytesChanged(float byteCount); - void passwordChanged(QString const &); - void addressesChanged(QStringList const &); - void idChanged(QStringList const &id); - void toggleSplitModeFinished(); - -private: - QString id_; ///< The userID. - QString username_; ///< The username - QString avatarText_; ///< The avatar text (i.e. initials of the user) - bool loggedIn_{false}; ///< Is the user logged in. - bool splitMode_{false}; ///< Is split mode active. - bool setupGuideSeen_{false}; ///< Has the setup guide been seen. - float usedBytes_{0.0f}; ///< The storage used by the user. - float totalBytes_{0.0f}; ///< The storage quota of the user. - QString password_; ///< The IMAP password of the user. - QStringList addresses_; ///< The email address list of the user. -}; - - -typedef std::shared_ptr SPUser; - - -#endif // BRIDGE_GUI_USER_H diff --git a/internal/frontend/bridge-gui/User/UserList.cpp b/internal/frontend/bridge-gui/UserList.cpp similarity index 90% rename from internal/frontend/bridge-gui/User/UserList.cpp rename to internal/frontend/bridge-gui/UserList.cpp index 0d7d085c..ac0df9cd 100644 --- a/internal/frontend/bridge-gui/User/UserList.cpp +++ b/internal/frontend/bridge-gui/UserList.cpp @@ -16,9 +16,10 @@ // along with Proton Mail Bridge. If not, see . -#include "Pch.h" #include "UserList.h" -#include "GRPC/GRPCClient.h" + + +using namespace bridgepp; //**************************************************************************************************************************************************** @@ -36,11 +37,12 @@ UserList::UserList(QObject *parent) //**************************************************************************************************************************************************** void UserList::connectGRPCEvents() const { - GRPCClient* client = &app().grpc(); - connect(client, &GRPCClient::userChanged, this, &UserList::onUserChanged); - connect(client, &GRPCClient::toggleSplitModeFinished, this, &UserList::onToggleSplitModeFinished); + GRPCClient& client = app().grpc(); + connect(&client, &GRPCClient::userChanged, this, &UserList::onUserChanged); + connect(&client, &GRPCClient::toggleSplitModeFinished, this, &UserList::onToggleSplitModeFinished); } + //**************************************************************************************************************************************************** // //**************************************************************************************************************************************************** @@ -60,7 +62,7 @@ QVariant UserList::data(QModelIndex const &index, int role) const /// This It does not seem to be used, but the method is required by the base class. /// From the original QtThe recipe QML backend User model, the User is always returned, regardless of the role. Q_UNUSED(role) - int const row = index.row(); + int const row = index.row(); if ((row < 0) || (row >= users_.size())) return QVariant(); return QVariant::fromValue(users_[row].get()); @@ -91,6 +93,7 @@ void UserList::reset() this->endResetModel(); } + //**************************************************************************************************************************************************** /// \param[in] users The new user list. //**************************************************************************************************************************************************** @@ -105,7 +108,7 @@ void UserList::reset(QList const &users) //**************************************************************************************************************************************************** /// \param[in] user The user. //**************************************************************************************************************************************************** -void UserList::appendUser(SPUser const& user) +void UserList::appendUser(SPUser const &user) { int const size = users_.size(); this->beginInsertRows(QModelIndex(), size, size); @@ -135,7 +138,7 @@ void UserList::updateUserAtRow(int row, User const &user) { if ((row < 0) || (row >= users_.count())) { - app().log().error(QString("invalid user at row %2 (user count = %2)").arg(row).arg(users_.count())); + app().log().error(QString("invalid user at row %2 (user userCount = %2)").arg(row).arg(users_.count())); return; } @@ -153,11 +156,11 @@ User *UserList::get(int row) const { if ((row < 0) || (row >= users_.count())) { - app().log().error(QString("Requesting invalid user at row %1 (user count = %2)").arg(row).arg(users_.count())); + app().log().error(QString("Requesting invalid user at row %1 (user userCount = %2)").arg(row).arg(users_.count())); return nullptr; } - app().log().debug(QString("Retrieving user at row %1 (user count = %2)").arg(row).arg(users_.count())); + app().log().debug(QString("Retrieving user at row %1 (user userCount = %2)").arg(row).arg(users_.count())); return users_[row].get(); } @@ -170,11 +173,13 @@ void UserList::onUserChanged(QString const &userID) int const index = this->rowOfUserID(userID); SPUser user; grpc::Status status = app().grpc().getUser(userID, user); + QQmlEngine::setObjectOwnership(user.get(), QQmlEngine::CppOwnership); + if ((!user) || (!status.ok())) { if (index >= 0) // user exists here but not in the go backend. we delete it. { - app().log().debug(QString("Removing user from userlist: %1").arg(userID)); + app().log().debug(QString("Removing user from user list: %1").arg(userID)); this->removeUserAt(index); } return; @@ -182,12 +187,12 @@ void UserList::onUserChanged(QString const &userID) if (index < 0) { - app().log().debug(QString("Adding user in userlist: %1").arg(userID)); + app().log().debug(QString("Adding user in user list: %1").arg(userID)); this->appendUser(user); return; } - app().log().debug(QString("Updating user in userlist: %1").arg(userID)); + app().log().debug(QString("Updating user in user list: %1").arg(userID)); this->updateUserAtRow(index, *user); } diff --git a/internal/frontend/bridge-gui/User/UserList.h b/internal/frontend/bridge-gui/UserList.h similarity index 69% rename from internal/frontend/bridge-gui/User/UserList.h rename to internal/frontend/bridge-gui/UserList.h index 7b7a1d40..0f64b1c6 100644 --- a/internal/frontend/bridge-gui/User/UserList.h +++ b/internal/frontend/bridge-gui/UserList.h @@ -19,45 +19,49 @@ #ifndef BRIDGE_GUI_USER_LIST_H #define BRIDGE_GUI_USER_LIST_H -#include "User.h" + +#include +#include +#include + //**************************************************************************************************************************************************** /// \brief User list class. //**************************************************************************************************************************************************** -class UserList: public QAbstractListModel +class UserList : public QAbstractListModel { - Q_OBJECT +Q_OBJECT public: // member functions. - explicit UserList(QObject *parent = nullptr); ///< Default constructor. - UserList(UserList const &other) = delete ; ///< Disabled copy-constructor. - UserList& operator=(UserList const& other) = delete; ///< Disabled assignment operator. + UserList(QObject *parent); ///< Default constructor. + UserList(UserList const &other) = delete; ///< Disabled copy-constructor. + UserList &operator=(UserList const &other) = delete; ///< Disabled assignment operator. ~UserList() override = default; ///< Destructor void connectGRPCEvents() const; ///< Connects gRPC event to the model. int rowCount(QModelIndex const &parent) const override; ///< Return the number of row in the model QVariant data(QModelIndex const &index, int role) const override; ///< Retrieve model data. void reset(); ///< Reset the user list. - void reset(QList const &users); ///< Replace the user list. + void reset(QList const &users); ///< Replace the user list. int rowOfUserID(QString const &userID) const; void removeUserAt(int row); ///< Remove the user at a given row - void appendUser(SPUser const& user); ///< Add a new user. - void updateUserAtRow(int row, User const& user); ///< Update the user at given row. + void appendUser(bridgepp::SPUser const &user); ///< Add a new user. + void updateUserAtRow(int row, bridgepp::User const &user); ///< Update the user at given row. - // the count property. + // the userCount property. Q_PROPERTY(int count READ count NOTIFY countChanged) - int count() const; ///< The count property getter. + int count() const; ///< The userCount property getter. signals: - void countChanged(int count); ///< Signal for the count property. + void countChanged(int count); ///< Signal for the userCount property. public: - Q_INVOKABLE User* get(int row) const; + Q_INVOKABLE bridgepp::User *get(int row) const; public slots: ///< handler for signals coming from the gRPC service void onUserChanged(QString const &userID); void onToggleSplitModeFinished(QString const &userID); private: // data members - QList users_; ///< The user list. + QList users_; ///< The user list. }; diff --git a/internal/frontend/bridge-gui/main.cpp b/internal/frontend/bridge-gui/main.cpp index da4e2e0d..23d55a29 100644 --- a/internal/frontend/bridge-gui/main.cpp +++ b/internal/frontend/bridge-gui/main.cpp @@ -16,12 +16,14 @@ // along with Proton Mail Bridge. If not, see . -#include "Pch.h" -#include "Exception.h" #include "QMLBackend.h" -#include "Log.h" #include "BridgeMonitor.h" #include "Version.h" +#include +#include + + +using namespace bridgepp; //**************************************************************************************************************************************************** @@ -49,7 +51,7 @@ Log &initLog() Log &log = app().log(); log.setEchoInConsole(true); log.setLevel(Log::Level::Debug); - Log::installQtMessageHandler(); + log.registerAsQtMessageHandler(); return log; } @@ -63,7 +65,7 @@ QQmlComponent *createRootQmlComponent(QQmlApplicationEngine &engine) qmlRegisterSingletonInstance("Proton", 1, 0, "Backend", &app().backend()); qmlRegisterType("Proton", 1, 0, "UserList"); - qmlRegisterType("Proton", 1, 0, "User"); + qmlRegisterType("Proton", 1, 0, "User"); auto rootComponent = new QQmlComponent(&engine, &engine); @@ -138,7 +140,7 @@ void parseArguments(int argc, char **argv, bool &outAttach, QString &outExePath) void closeBridgeApp() { UPOverseer& overseer = app().bridgeOverseer(); - if (!overseer) // The app was ran in 'attach' mode and attached to an existing instance of Bridge. No need to close. + if (!overseer) // The app was run in 'attach' mode and attached to an existing instance of Bridge. No need to close. return; app().grpc().quit(); // this will cause the grpc service and the bridge app to close. @@ -186,7 +188,7 @@ int main(int argc, char *argv[]) QMetaObject::Connection connection; if (bridgeMonitor) connection = QObject::connect(bridgeMonitor, &BridgeMonitor::processExited, [&](int returnCode) { - // GODT-1671 We need to find a 'safe' way to check if brige crashed and restart instead of just quitting. Is returnCode enough? + // GODT-1671 We need to find a 'safe' way to check if Bridge crashed and restart instead of just quitting. Is returnCode enough? bridgeExited = true;// clazy:exclude=lambda-in-connect qGuiApp->exit(returnCode); }); diff --git a/internal/frontend/bridgepp/CMakeLists.txt b/internal/frontend/bridgepp/CMakeLists.txt new file mode 100644 index 00000000..a685dbe0 --- /dev/null +++ b/internal/frontend/bridgepp/CMakeLists.txt @@ -0,0 +1,124 @@ +# Copyright (c) 2022 Proton AG +# +# This file is part of Proton Mail Bridge. +# +# Proton Mail Bridge is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Proton Mail Bridge 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Proton Mail Bridge. If not, see . + + +cmake_minimum_required(VERSION 3.22) + + +include_guard() +set(VCPKG_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../../../extern/vcpkg") +include(bridge_setup.cmake) + + +#**************************************************************************************************************************************************** +# Base project setup +#**************************************************************************************************************************************************** +project(bridgepp LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +if (NOT DEFINED BRIDGE_APP_VERSION) + message(FATAL_ERROR "BRIDGE_APP_VERSION is not defined.") +else() + message(STATUS "Bridge version is ${BRIDGE_APP_VERSION}") +endif() + +#**************************************************************************************************************************************************** +# Qt +#**************************************************************************************************************************************************** +if (NOT DEFINED ENV{QT6DIR}) + message(FATAL_ERROR "QT6DIR needs to be defined and point to the root of your Qt 6 folder (e.g. /Users/MyName/Qt/6.3.1/clang_64).") +endif () +set(CMAKE_PREFIX_PATH $ENV{QT6DIR} ${CMAKE_PREFIX_PATH}) +find_package(Qt6 COMPONENTS Core REQUIRED) +qt_standard_project_setup() + +#**************************************************************************************************************************************************** +# gRPC / Protobuf +#**************************************************************************************************************************************************** +find_package(Protobuf CONFIG REQUIRED) +message(STATUS "Using protobuf ${Protobuf_VERSION}") + +find_package(gRPC CONFIG REQUIRED) +message(STATUS "Using gRPC ${gRPC_VERSION}") + +find_program(PROTOC_EXE protoc REQUIRED) +message(STATUS "protoc found ${PROTOC_EXE}") + +message(STATUS "grpc_cpp_plugin ${grpc_cpp_plugin}") + +find_program(GRPC_CPP_PLUGIN grpc_cpp_plugin) +if (GRPC_CPP_PLUGIN STREQUAL GRPC_CPP_PLUGIN-NOTFOUND) + message(FATAL_ERROR "grpc_cpp_plugin exe could not be found. Please add it to your path. it should be located in \${VCPKG_ROOT}/installed/arm64-osx/tools/grpc") +else () + message(STATUS "grpc_cpp_plugin found at ${GRPC_CPP_PLUGIN}") +endif () + +set(PROTO_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../grpc") +set(PROTO_FILE "${PROTO_DIR}/bridge.proto") +set(GRPC_OUT_DIR "bridgepp/GRPC") +set(PROTO_CPP_FILE "${GRPC_OUT_DIR}/bridge.pb.cc") +set(PROTO_H_FILE "${GRPC_OUT_DIR}/bridge.pb.h") +set(GRPC_CPP_FILE "${GRPC_OUT_DIR}/bridge.grpc.pb.cc") +set(GRPC_H_FILE "${GRPC_OUT_DIR}/bridge.grpc.pb.h") + + +#***************************************************************************************************************************************************** +# Source files and output +#***************************************************************************************************************************************************** + +add_custom_command( + OUTPUT + ${PROTO_CPP_FILE} + ${PROTO_H_FILE} + ${GRPC_CPP_FILE} + ${GRPC_H_FILE} + COMMAND + ${PROTOC_EXE} + ARGS + --proto_path=${PROTO_DIR} + --plugin=protoc-gen-grpc="${GRPC_CPP_PLUGIN}" + --cpp_out=${GRPC_OUT_DIR} + --grpc_out=${GRPC_OUT_DIR} + ${PROTO_FILE} + DEPENDS + ${PROTO_FILE} + COMMENT "Generating gPRC/Protobuf C++ code" + ) + + +add_library(bridgepp + bridgepp/BridgeUtils.cpp bridgepp/BridgeUtils.h + bridgepp/Exception/Exception.h bridgepp/Exception/Exception.cpp + bridgepp/GRPC/GRPCClient.cpp bridgepp/GRPC/GRPCClient.h + bridgepp/GRPC/GRPCUtils.cpp bridgepp/GRPC/GRPCUtils.h + ${PROTO_CPP_FILE} ${PROTO_H_FILE} ${GRPC_CPP_FILE} ${GRPC_H_FILE} + bridgepp/Log/Log.h bridgepp/Log/Log.cpp + bridgepp/User/User.cpp bridgepp/User/User.h + bridgepp/Worker/Worker.h bridgepp/Worker/Overseer.h bridgepp/Worker/Overseer.cpp + ) + +target_include_directories(bridgepp PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + +target_link_libraries(bridgepp + Qt6::Core + protobuf::libprotobuf + gRPC::grpc++ + ) + +target_precompile_headers(bridgepp PRIVATE Pch.h) diff --git a/internal/frontend/bridgepp/Pch.h b/internal/frontend/bridgepp/Pch.h new file mode 100644 index 00000000..fcfed6a4 --- /dev/null +++ b/internal/frontend/bridgepp/Pch.h @@ -0,0 +1,26 @@ +// Copyright (c) 2022 Proton AG +// +// This file is part of Proton Mail Bridge. +// +// Proton Mail Bridge is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Proton Mail Bridge 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Proton Mail Bridge. If not, see . + + +#ifndef BRIDGE_PP_PCH_H +#define BRIDGE_PP_PCH_H + + +#include + + +#endif // BRIDGE_PP_PCH_H \ No newline at end of file diff --git a/internal/frontend/bridgepp/bridge_setup.cmake b/internal/frontend/bridgepp/bridge_setup.cmake new file mode 100644 index 00000000..3ebafcef --- /dev/null +++ b/internal/frontend/bridgepp/bridge_setup.cmake @@ -0,0 +1,60 @@ +# Copyright (c) 2022 Proton AG +# +# This file is part of Proton Mail Bridge. +# +# Proton Mail Bridge is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Proton Mail Bridge 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Proton Mail Bridge. If not, see . + + +include_guard() + + +#**************************************************************************************************************************************************** +# vcpkg, toolchain, and architecture +#**************************************************************************************************************************************************** +# We rely on vcpkg for to get gRPC / Protobuf +# run build.sh / build.ps1 to get gRPC / Protobuf and dependencies installed. + +set(VCPKG_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../../../extern/vcpkg") +message(STATUS "VCPKG_ROOT is ${VCPKG_ROOT}") +if (WIN32) + find_program(VCPKG_EXE "${VCPKG_ROOT}/vcpkg.exe") +else() + find_program(VCPKG_EXE "${VCPKG_ROOT}/vcpkg") +endif() + + +# For now we support only a single architecture for macOS (ARM64 or x86_64). We need to investigate how to build universal binaries with vcpkg. +if (APPLE) + if (NOT DEFINED CMAKE_OSX_ARCHITECTURES) + execute_process(COMMAND "uname" "-m" OUTPUT_VARIABLE UNAME_RESULT OUTPUT_STRIP_TRAILING_WHITESPACE) + set(CMAKE_OSX_ARCHITECTURES ${UNAME_RESULT} CACHE STRING "osx_architectures") + endif() + + if (CMAKE_OSX_ARCHITECTURES STREQUAL "arm64") + message(STATUS "Building for Apple Silicon Mac computers") + set(VCPKG_TARGET_TRIPLET arm64-osx) + elseif (CMAKE_OSX_ARCHITECTURES STREQUAL "x86_64") + message(STATUS "Building for Intel based Mac computers") + set(VCPKG_TARGET_TRIPLET x64-osx) + else () + message(FATAL_ERROR "Unknown value for CMAKE_OSX_ARCHITECTURE. Please use one of \"arm64\" and \"x86_64\". Multiple architectures are not supported.") + endif () +endif() + +if (WIN32) + message(STATUS "Building for Intel x64 Windows computers") + set(VCPKG_TARGET_TRIPLET x64-windows) +endif() + +set(CMAKE_TOOLCHAIN_FILE "${VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" CACHE STRING "toolchain") \ No newline at end of file diff --git a/internal/frontend/bridgepp/bridgepp/BridgeUtils.cpp b/internal/frontend/bridgepp/bridgepp/BridgeUtils.cpp new file mode 100644 index 00000000..d8928cc3 --- /dev/null +++ b/internal/frontend/bridgepp/bridgepp/BridgeUtils.cpp @@ -0,0 +1,56 @@ +// Copyright (c) 2022 Proton AG +// +// This file is part of Proton Mail Bridge. +// +// Proton Mail Bridge is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Proton Mail Bridge 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Proton Mail Bridge. If not, see . + + +#include "BridgeUtils.h" +#include "Exception/Exception.h" + + +namespace bridgepp +{ + +//**************************************************************************************************************************************************** +/// \return user configuration directory used by bridge (based on Golang OS/File's UserConfigDir). +//**************************************************************************************************************************************************** +QString userConfigDir() +{ + QString dir; +#ifdef Q_OS_WIN + dir = qgetenv ("AppData"); + if (dir.isEmpty()) + throw Exception("%AppData% is not defined."); +#elif defined(Q_OS_IOS) || defined(Q_OS_DARWIN) + dir = qgetenv("HOME"); + if (dir.isEmpty()) + throw Exception("$HOME is not defined."); + dir += "/Library/Application Support"; +#else + dir = qgetenv ("XDG_CONFIG_HOME"); + if (dir.isEmpty()) + dir = qgetenv ("HOME"); + if (dir.isEmpty()) + throw Exception("neither $XDG_CONFIG_HOME nor $HOME are defined"); + dir += "/.config"; +#endif + QString folder = dir + "/protonmail/bridge"; + QDir().mkpath(folder); + + return folder; +} + + +} // namespace bridgepp diff --git a/internal/frontend/bridge-gui/GRPC/GRPCUtils.h b/internal/frontend/bridgepp/bridgepp/BridgeUtils.h similarity index 60% rename from internal/frontend/bridge-gui/GRPC/GRPCUtils.h rename to internal/frontend/bridgepp/bridgepp/BridgeUtils.h index 913396ad..cdd607c0 100644 --- a/internal/frontend/bridge-gui/GRPC/GRPCUtils.h +++ b/internal/frontend/bridgepp/bridgepp/BridgeUtils.h @@ -16,19 +16,18 @@ // along with Proton Mail Bridge. If not, see . -#ifndef BRIDGE_GUI_GRPCUTILS_H -#define BRIDGE_GUI_GRPCUTILS_H +#ifndef BRIDGE_GUI_TESTER_BRIDGE_UTILS_H +#define BRIDGE_GUI_TESTER_BRIDGE_UTILS_H -#include "Log.h" -#include "GRPC/bridge.grpc.pb.h" -#include "grpc++/grpc++.h" -#include "User/User.h" +namespace bridgepp { -void logGRPCCallStatus(grpc::Status const& status, QString const &callName); ///< Log the status of a gRPC code. -SPUser parsegrpcUser(grpc::User const& grpcUser); ///< Parse a gRPC user struct and return a User. -grpc::LogLevel logLevelToGRPC(Log::Level level); ///< Convert a Log::Level to gRPC enum value. +QString userConfigDir(); ///< Get the path of the user configuration folder. -#endif // BRIDGE_GUI_GRPCUTILS_H +} // namespace + + + +#endif // BRIDGE_GUI_TESTER_BRIDGE_UTILS_H diff --git a/internal/frontend/bridge-gui/Exception.cpp b/internal/frontend/bridgepp/bridgepp/Exception/Exception.cpp similarity index 98% rename from internal/frontend/bridge-gui/Exception.cpp rename to internal/frontend/bridgepp/bridgepp/Exception/Exception.cpp index 517193c4..c1996993 100644 --- a/internal/frontend/bridge-gui/Exception.cpp +++ b/internal/frontend/bridgepp/bridgepp/Exception/Exception.cpp @@ -16,10 +16,13 @@ // along with Proton Mail Bridge. If not, see . -#include "Pch.h" #include "Exception.h" +namespace bridgepp +{ + + //**************************************************************************************************************************************************** /// \param[in] what A description of the exception //**************************************************************************************************************************************************** @@ -66,3 +69,6 @@ const char* Exception::what() const noexcept { return what_.toLocal8Bit().constData(); } + + +} // namespace bridgepp diff --git a/internal/frontend/bridge-gui/Exception.h b/internal/frontend/bridgepp/bridgepp/Exception/Exception.h similarity index 70% rename from internal/frontend/bridge-gui/Exception.h rename to internal/frontend/bridgepp/bridgepp/Exception/Exception.h index cc1d4984..814e21b8 100644 --- a/internal/frontend/bridge-gui/Exception.h +++ b/internal/frontend/bridgepp/bridgepp/Exception/Exception.h @@ -16,31 +16,38 @@ // along with Proton Mail Bridge. If not, see . -#ifndef BRIDGE_GUI_EXCEPTION_H -#define BRIDGE_GUI_EXCEPTION_H +#ifndef BRIDGE_PP_EXCEPTION_H +#define BRIDGE_PP_EXCEPTION_H #include +namespace bridgepp +{ + + //**************************************************************************************************************************************************** /// \brief Exception class. //**************************************************************************************************************************************************** -class Exception: public std::exception +class Exception : public std::exception { public: // member functions explicit Exception(QString what = QString()) noexcept; ///< Constructor - Exception(Exception const& ref) noexcept; ///< copy constructor - Exception(Exception&& ref) noexcept; ///< copy constructor - Exception& operator=(Exception const&) = delete; ///< Disabled assignment operator - Exception& operator=(Exception&&) = delete; ///< Disabled assignment operator + Exception(Exception const &ref) noexcept; ///< copy constructor + Exception(Exception &&ref) noexcept; ///< copy constructor + Exception &operator=(Exception const &) = delete; ///< Disabled assignment operator + Exception &operator=(Exception &&) = delete; ///< Disabled assignment operator ~Exception() noexcept override = default; ///< Destructor - QString const& qwhat() const noexcept; ///< Return the description of the exception as a QString - const char* what() const noexcept override; ///< Return the description of the exception as C style string + QString const &qwhat() const noexcept; ///< Return the description of the exception as a QString + const char *what() const noexcept override; ///< Return the description of the exception as C style string private: // data members QString const what_; ///< The description of the exception }; -#endif //BRIDGE_GUI_EXCEPTION_H +} // namespace bridgepp + + +#endif //BRIDGE_PP_EXCEPTION_H diff --git a/internal/frontend/bridge-gui/GRPC/GRPCClient.cpp b/internal/frontend/bridgepp/bridgepp/GRPC/GRPCClient.cpp similarity index 80% rename from internal/frontend/bridge-gui/GRPC/GRPCClient.cpp rename to internal/frontend/bridgepp/bridgepp/GRPC/GRPCClient.cpp index 3a91b084..4759217f 100644 --- a/internal/frontend/bridge-gui/GRPC/GRPCClient.cpp +++ b/internal/frontend/bridgepp/bridgepp/GRPC/GRPCClient.cpp @@ -16,56 +16,32 @@ // along with Proton Mail Bridge. If not, see . -#include "Pch.h" #include "GRPCClient.h" #include "GRPCUtils.h" -#include "QMLBackend.h" -#include "Exception.h" -#include "AppController.h" +#include "../Exception/Exception.h" using namespace google::protobuf; using namespace grpc; +namespace bridgepp +{ + + namespace { + + Empty empty; // re-used across client calls. -QString const configFolder = "protonmail/bridge"; -QString const certFile = "cert.pem"; -int const maxConnectionTimeSecs = 60; ///< Amount of time after which we consider connection attemps to the server have failed. -int const maxCertificateWaitMsecs = 60 * 1000; ///< Ammount of time we wait for he server to generate the certificate. +int const maxConnectionTimeSecs = 60; ///< Amount of time after which we consider connection attempts to the server have failed. +int const maxCertificateWaitMsecs = 60 * 1000; ///< Amount of time we wait for he server to generate the certificate. + + } -//**************************************************************************************************************************************************** -/// \return user configuration directory used by bridge (based on Golang OS/File's UserConfigDir). -//**************************************************************************************************************************************************** -static const QString _userConfigDir(){ - QString dir; -#ifdef Q_OS_WIN - dir = qgetenv ("AppData"); - if (dir.isEmpty()) - throw Exception("%AppData% is not defined."); -#elif defined(Q_OS_IOS) || defined(Q_OS_DARWIN) - dir = qgetenv ("HOME"); - if (dir.isEmpty()) - throw Exception("$HOME is not defined."); - dir += "/Library/Application Support"; -#else - dir = qgetenv ("XDG_CONFIG_HOME"); - if (dir.isEmpty()) - dir = qgetenv ("HOME"); - if (dir.isEmpty()) - throw Exception("neither $XDG_CONFIG_HOME nor $HOME are defined"); - dir += "/.config"; -#endif - QString folder = dir + "/" + configFolder; - QDir().mkpath(folder); - - return folder; -} //**************************************************************************************************************************************************** /// \brief wait for certificate generation by Bridge @@ -73,8 +49,9 @@ static const QString _userConfigDir(){ //**************************************************************************************************************************************************** std::string GRPCClient::getServerCertificate() { - const QString filename = _userConfigDir() + "/" + certFile; - QFile file(filename); + QString const certPath = serverCertificatePath(); + QString const certFolder = QFileInfo(certPath).absolutePath(); + QFile file(certPath); // TODO : the certificate can exist but still be invalid. // If the certificate is close to its limit, the bridge will generate a new one. // If we read the certificate before the bridge rewrites it the certificate will be invalid. @@ -82,7 +59,7 @@ std::string GRPCClient::getServerCertificate() { // wait for file creation QFileSystemWatcher watcher(this); - if (!watcher.addPath(_userConfigDir())) + if (!watcher.addPath(certFolder)) throw Exception("Failed to watch User Config Directory"); connect(&watcher, &QFileSystemWatcher::directoryChanged, this, &GRPCClient::configFolderChanged); @@ -96,7 +73,7 @@ std::string GRPCClient::getServerCertificate() loop.exec(); // timeout case. - if(!timer.isActive()) + if (!timer.isActive()) throw Exception("Server failed to generate certificate on time"); //else certIsReadySignal. } @@ -109,16 +86,26 @@ std::string GRPCClient::getServerCertificate() return cert; } + //**************************************************************************************************************************************************** /// \brief Action on UserConfig directory changes, looking for the certificate creation //**************************************************************************************************************************************************** void GRPCClient::configFolderChanged() { - QFile cert(_userConfigDir() + "/" + certFile); - if (cert.exists()) + if (QFileInfo::exists(serverCertificatePath())) emit certIsReady(); } + +//**************************************************************************************************************************************************** +/// \param[in] log The log +//**************************************************************************************************************************************************** +void GRPCClient::setLog(Log *log) +{ + log_ = log; +} + + //**************************************************************************************************************************************************** /// \param[out] outError If the function returns false, this variable contains a description of the error. /// \return true iff the connection was successful. @@ -142,7 +129,8 @@ bool GRPCClient::connectToServer(QString &outError) int i = 0; while (true) { - app().log().debug(QString("Connection to gRPC server. attempt #%1").arg(++i)); + if (log_) + log_->debug(QString("Connection to gRPC server. attempt #%1").arg(++i)); if (channel_->WaitForConnected(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_seconds(5, GPR_TIMESPAN)))) break; // connection established. @@ -154,9 +142,8 @@ bool GRPCClient::connectToServer(QString &outError) if (channel_->GetState(true) != GRPC_CHANNEL_READY) throw Exception("connection check failed."); - QMLBackend *backend = &app().backend(); - QObject::connect(this, &GRPCClient::loginFreeUserError, backend, &QMLBackend::loginFreeUserError); - app().log().debug("Successfully connected to gRPC server."); + if (log_) + log_->debug("Successfully connected to gRPC server."); return true; } catch (Exception const &e) @@ -183,13 +170,14 @@ grpc::Status GRPCClient::addLogEntry(Log::Level level, QString const &package, Q return stub_->AddLogEntry(&ctx, request, &empty); } + //**************************************************************************************************************************************************** /// \return The status for the gRPC call. //**************************************************************************************************************************************************** grpc::Status GRPCClient::guiReady() { grpc::ClientContext ctx; - return stub_->GuiReady(&ctx, empty, &empty); + return this->logGRPCCallStatus(stub_->GuiReady(&ctx, empty, &empty), __FUNCTION__); } @@ -199,7 +187,7 @@ grpc::Status GRPCClient::guiReady() //**************************************************************************************************************************************************** grpc::Status GRPCClient::isFirstGUIStart(bool &outIsFirst) { - return this->getBool(&Bridge::Stub::IsFirstGuiStart, outIsFirst); + return this->logGRPCCallStatus(this->getBool(&Bridge::Stub::IsFirstGuiStart, outIsFirst), __FUNCTION__); } @@ -209,7 +197,7 @@ grpc::Status GRPCClient::isFirstGUIStart(bool &outIsFirst) //**************************************************************************************************************************************************** grpc::Status GRPCClient::isAutostartOn(bool &outIsOn) { - return this->getBool(&Bridge::Stub::IsAutostartOn, outIsOn); + return this->logGRPCCallStatus(this->getBool(&Bridge::Stub::IsAutostartOn, outIsOn), __FUNCTION__); } @@ -219,7 +207,7 @@ grpc::Status GRPCClient::isAutostartOn(bool &outIsOn) //**************************************************************************************************************************************************** grpc::Status GRPCClient::setIsAutostartOn(bool on) { - return this->setBool(&Bridge::Stub::SetIsAutostartOn, on); + return this->logGRPCCallStatus(this->setBool(&Bridge::Stub::SetIsAutostartOn, on), __FUNCTION__); } @@ -229,7 +217,7 @@ grpc::Status GRPCClient::setIsAutostartOn(bool on) //**************************************************************************************************************************************************** grpc::Status GRPCClient::isBetaEnabled(bool &outEnabled) { - return this->getBool(&Bridge::Stub::IsBetaEnabled, outEnabled); + return this->logGRPCCallStatus(this->getBool(&Bridge::Stub::IsBetaEnabled, outEnabled), __FUNCTION__); } @@ -237,9 +225,9 @@ grpc::Status GRPCClient::isBetaEnabled(bool &outEnabled) /// \param[in] enabled The new value for the property. /// \return The status for the gRPC call. //**************************************************************************************************************************************************** -grpc::Status GRPCClient::setisBetaEnabled(bool enabled) +grpc::Status GRPCClient::setIsBetaEnabled(bool enabled) { - return this->setBool(&Bridge::Stub::SetIsBetaEnabled, enabled); + return this->logGRPCCallStatus(this->setBool(&Bridge::Stub::SetIsBetaEnabled, enabled), __FUNCTION__); } @@ -249,7 +237,7 @@ grpc::Status GRPCClient::setisBetaEnabled(bool enabled) //**************************************************************************************************************************************************** grpc::Status GRPCClient::colorSchemeName(QString &outName) { - return this->getString(&Bridge::Stub::ColorSchemeName, outName); + return this->logGRPCCallStatus(this->getString(&Bridge::Stub::ColorSchemeName, outName), __FUNCTION__); } @@ -259,7 +247,7 @@ grpc::Status GRPCClient::colorSchemeName(QString &outName) //**************************************************************************************************************************************************** grpc::Status GRPCClient::setColorSchemeName(QString const &name) { - return this->setString(&Bridge::Stub::SetColorSchemeName, name); + return this->logGRPCCallStatus(this->setString(&Bridge::Stub::SetColorSchemeName, name), __FUNCTION__); } @@ -269,7 +257,7 @@ grpc::Status GRPCClient::setColorSchemeName(QString const &name) //**************************************************************************************************************************************************** grpc::Status GRPCClient::currentEmailClient(QString &outName) { - return this->getString(&Bridge::Stub::CurrentEmailClient, outName); + return this->logGRPCCallStatus(this->getString(&Bridge::Stub::CurrentEmailClient, outName), __FUNCTION__); } @@ -278,7 +266,7 @@ grpc::Status GRPCClient::currentEmailClient(QString &outName) /// \param[in] address The email address. /// \param[in] emailClient The email client. /// \param[in] includeLogs Should the report include the logs. -/// \return The status foer the gRPC call. +/// \return The status for the gRPC call. //**************************************************************************************************************************************************** grpc::Status GRPCClient::reportBug(QString const &description, QString const &address, QString const &emailClient, bool includeLogs) { @@ -290,7 +278,7 @@ grpc::Status GRPCClient::reportBug(QString const &description, QString const &ad request.set_address(address.toStdString()); request.set_emailclient(emailClient.toStdString()); request.set_includelogs(includeLogs); - return stub_->ReportBug(&ctx, request, &empty); + return this->logGRPCCallStatus(stub_->ReportBug(&ctx, request, &empty), __FUNCTION__); } @@ -300,7 +288,7 @@ grpc::Status GRPCClient::reportBug(QString const &description, QString const &ad //**************************************************************************************************************************************************** grpc::Status GRPCClient::useSSLForSMTP(bool &outUseSSL) { - return this->getBool(&Bridge::Stub::UseSslForSmtp, outUseSSL); + return this->logGRPCCallStatus(this->getBool(&Bridge::Stub::UseSslForSmtp, outUseSSL), __FUNCTION__); } @@ -310,7 +298,7 @@ grpc::Status GRPCClient::useSSLForSMTP(bool &outUseSSL) //**************************************************************************************************************************************************** grpc::Status GRPCClient::setUseSSLForSMTP(bool useSSL) { - return this->setBool(&Bridge::Stub::SetUseSslForSmtp, useSSL); + return this->logGRPCCallStatus(this->setBool(&Bridge::Stub::SetUseSslForSmtp, useSSL), __FUNCTION__); } @@ -320,7 +308,7 @@ grpc::Status GRPCClient::setUseSSLForSMTP(bool useSSL) //**************************************************************************************************************************************************** grpc::Status GRPCClient::portIMAP(int &outPort) { - return this->getInt32(&Bridge::Stub::ImapPort, outPort); + return this->logGRPCCallStatus(this->getInt32(&Bridge::Stub::ImapPort, outPort), __FUNCTION__); } @@ -330,7 +318,7 @@ grpc::Status GRPCClient::portIMAP(int &outPort) //**************************************************************************************************************************************************** grpc::Status GRPCClient::portSMTP(int &outPort) { - return this->getInt32(&Bridge::Stub::SmtpPort, outPort); + return this->logGRPCCallStatus(this->getInt32(&Bridge::Stub::SmtpPort, outPort), __FUNCTION__); } @@ -345,7 +333,7 @@ grpc::Status GRPCClient::changePorts(int portIMAP, int portSMTP) ChangePortsRequest request; request.set_imapport(portIMAP); request.set_smtpport(portSMTP); - return stub_->ChangePorts(&ctx, request, &empty); + return this->logGRPCCallStatus(stub_->ChangePorts(&ctx, request, &empty), __FUNCTION__); } @@ -355,7 +343,7 @@ grpc::Status GRPCClient::changePorts(int portIMAP, int portSMTP) //**************************************************************************************************************************************************** grpc::Status GRPCClient::isDoHEnabled(bool &outEnabled) { - return this->getBool(&Bridge::Stub::IsDoHEnabled, outEnabled); + return this->logGRPCCallStatus(this->getBool(&Bridge::Stub::IsDoHEnabled, outEnabled), __FUNCTION__); } @@ -365,7 +353,7 @@ grpc::Status GRPCClient::isDoHEnabled(bool &outEnabled) //**************************************************************************************************************************************************** grpc::Status GRPCClient::setIsDoHEnabled(bool enabled) { - return this->setBool(&Bridge::Stub::SetIsDoHEnabled, enabled); + return this->logGRPCCallStatus(this->setBool(&Bridge::Stub::SetIsDoHEnabled, enabled), __FUNCTION__); } @@ -375,7 +363,7 @@ grpc::Status GRPCClient::setIsDoHEnabled(bool enabled) grpc::Status GRPCClient::quit() { grpc::ClientContext ctx; - return stub_->Quit(&ctx, empty, &empty); + return this->logGRPCCallStatus(stub_->Quit(&ctx, empty, &empty), __FUNCTION__); } @@ -385,16 +373,17 @@ grpc::Status GRPCClient::quit() grpc::Status GRPCClient::restart() { grpc::ClientContext ctx; - return stub_->Restart(&ctx, empty, &empty); + return this->logGRPCCallStatus(stub_->Restart(&ctx, empty, &empty), __FUNCTION__); } + //**************************************************************************************************************************************************** /// \return The status for the gRPC call. //**************************************************************************************************************************************************** grpc::Status GRPCClient::triggerReset() { grpc::ClientContext ctx; - return stub_->TriggerReset(&ctx, empty, &empty); + return this->logGRPCCallStatus(stub_->TriggerReset(&ctx, empty, &empty), __FUNCTION__); } @@ -412,7 +401,7 @@ grpc::Status GRPCClient::isPortFree(qint32 port, bool &outFree) Status result = stub_->IsPortFree(&ctx, p, &isFree); if (result.ok()) outFree = isFree.value(); - return result; + return this->logGRPCCallStatus(result, __FUNCTION__); } @@ -422,7 +411,7 @@ grpc::Status GRPCClient::isPortFree(qint32 port, bool &outFree) //**************************************************************************************************************************************************** grpc::Status GRPCClient::showOnStartup(bool &outValue) { - return this->getBool(&Bridge::Stub::ShowOnStartup, outValue); + return this->logGRPCCallStatus(this->getBool(&Bridge::Stub::ShowOnStartup, outValue), __FUNCTION__); } @@ -432,7 +421,7 @@ grpc::Status GRPCClient::showOnStartup(bool &outValue) //**************************************************************************************************************************************************** grpc::Status GRPCClient::showSplashScreen(bool &outValue) { - return this->getBool(&Bridge::Stub::ShowSplashScreen, outValue); + return this->logGRPCCallStatus(this->getBool(&Bridge::Stub::ShowSplashScreen, outValue), __FUNCTION__); } @@ -442,7 +431,7 @@ grpc::Status GRPCClient::showSplashScreen(bool &outValue) //**************************************************************************************************************************************************** grpc::Status GRPCClient::goos(QString &outGoos) { - return this->getString(&Bridge::Stub::GoOs, outGoos); + return this->logGRPCCallStatus(this->getString(&Bridge::Stub::GoOs, outGoos), __FUNCTION__); } @@ -452,7 +441,7 @@ grpc::Status GRPCClient::goos(QString &outGoos) //**************************************************************************************************************************************************** grpc::Status GRPCClient::logsPath(QUrl &outPath) { - return this->getURLForLocalFile(&Bridge::Stub::LogsPath, outPath); + return this->logGRPCCallStatus(this->getURLForLocalFile(&Bridge::Stub::LogsPath, outPath), __FUNCTION__); } @@ -462,7 +451,7 @@ grpc::Status GRPCClient::logsPath(QUrl &outPath) //**************************************************************************************************************************************************** grpc::Status GRPCClient::licensePath(QUrl &outPath) { - return this->getURLForLocalFile(&Bridge::Stub::LicensePath, outPath); + return this->logGRPCCallStatus(this->getURLForLocalFile(&Bridge::Stub::LicensePath, outPath), __FUNCTION__); } @@ -472,7 +461,7 @@ grpc::Status GRPCClient::licensePath(QUrl &outPath) //**************************************************************************************************************************************************** grpc::Status GRPCClient::dependencyLicensesLink(QUrl &outUrl) { - return this->getURL(&Bridge::Stub::DependencyLicensesLink, outUrl); + return this->logGRPCCallStatus(this->getURL(&Bridge::Stub::DependencyLicensesLink, outUrl), __FUNCTION__); } @@ -482,34 +471,37 @@ grpc::Status GRPCClient::dependencyLicensesLink(QUrl &outUrl) //**************************************************************************************************************************************************** grpc::Status GRPCClient::version(QString &outVersion) { - return this->getString(&Bridge::Stub::Version, outVersion); + return this->logGRPCCallStatus(this->getString(&Bridge::Stub::Version, outVersion), __FUNCTION__); } + //**************************************************************************************************************************************************** /// \param[out] outUrl The value for the property. /// \return The status for the gRPC call. //**************************************************************************************************************************************************** grpc::Status GRPCClient::releaseNotesPageLink(QUrl &outUrl) { - return this->getURL(&Bridge::Stub::ReleaseNotesPageLink, outUrl); + return this->logGRPCCallStatus(this->getURL(&Bridge::Stub::ReleaseNotesPageLink, outUrl), __FUNCTION__); } + //**************************************************************************************************************************************************** /// \param[out] outUrl The value for the property. /// \return The status for the gRPC call. //**************************************************************************************************************************************************** grpc::Status GRPCClient::landingPageLink(QUrl &outUrl) { - return this->getURL(&Bridge::Stub::LandingPageLink, outUrl); + return this->logGRPCCallStatus(this->getURL(&Bridge::Stub::LandingPageLink, outUrl), __FUNCTION__); } + //**************************************************************************************************************************************************** /// \param[out] outHostname The value for the property. /// \return The status for the gRPC call. //**************************************************************************************************************************************************** grpc::Status GRPCClient::hostname(QString &outHostname) { - return this->getString(&Bridge::Stub::Hostname, outHostname); + return this->logGRPCCallStatus(this->getString(&Bridge::Stub::Hostname, outHostname), __FUNCTION__); } @@ -519,7 +511,7 @@ grpc::Status GRPCClient::hostname(QString &outHostname) //**************************************************************************************************************************************************** grpc::Status GRPCClient::isCacheOnDiskEnabled(bool &outEnabled) { - return getBool(&Bridge::Stub::IsCacheOnDiskEnabled, outEnabled); + return this->logGRPCCallStatus(getBool(&Bridge::Stub::IsCacheOnDiskEnabled, outEnabled), __FUNCTION__); } @@ -529,7 +521,7 @@ grpc::Status GRPCClient::isCacheOnDiskEnabled(bool &outEnabled) //**************************************************************************************************************************************************** grpc::Status GRPCClient::diskCachePath(QUrl &outPath) { - return this->getURLForLocalFile(&Bridge::Stub::DiskCachePath, outPath); + return this->logGRPCCallStatus(this->getURLForLocalFile(&Bridge::Stub::DiskCachePath, outPath), __FUNCTION__); } @@ -544,7 +536,7 @@ grpc::Status GRPCClient::changeLocalCache(bool enabled, QUrl const &path) ChangeLocalCacheRequest request; request.set_enablediskcache(enabled); request.set_diskcachepath(path.path(QUrl::FullyDecoded).toStdString()); - return stub_->ChangeLocalCache(&ctx, request, &empty); + return this->logGRPCCallStatus(stub_->ChangeLocalCache(&ctx, request, &empty), __FUNCTION__); } @@ -559,7 +551,7 @@ grpc::Status GRPCClient::login(QString const &username, QString const &password) LoginRequest request; request.set_username(username.toStdString()); request.set_password(password.toStdString()); - return stub_->Login(&ctx, request, &empty); + return this->logGRPCCallStatus(stub_->Login(&ctx, request, &empty), __FUNCTION__); } @@ -574,7 +566,7 @@ grpc::Status GRPCClient::login2FA(QString const &username, QString const &code) LoginRequest request; request.set_username(username.toStdString()); request.set_password(code.toStdString()); - return stub_->Login2FA(&ctx, request, &empty); + return this->logGRPCCallStatus(stub_->Login2FA(&ctx, request, &empty), __FUNCTION__); } @@ -589,7 +581,7 @@ grpc::Status GRPCClient::login2Passwords(QString const &username, QString const LoginRequest request; request.set_username(username.toStdString()); request.set_password(password.toStdString()); - return stub_->Login2Passwords(&ctx, request, &empty); + return this->logGRPCCallStatus(stub_->Login2Passwords(&ctx, request, &empty), __FUNCTION__); } @@ -602,7 +594,7 @@ grpc::Status GRPCClient::loginAbort(QString const &username) grpc::ClientContext ctx; LoginAbortRequest request; request.set_username(username.toStdString()); - return stub_->LoginAbort(&ctx, request, &empty); + return this->logGRPCCallStatus(stub_->LoginAbort(&ctx, request, &empty), __FUNCTION__); } @@ -611,7 +603,7 @@ grpc::Status GRPCClient::loginAbort(QString const &username) //**************************************************************************************************************************************************** grpc::Status GRPCClient::checkUpdate() { - return this->simpleMethod(&Bridge::Stub::CheckUpdate); + return this->logGRPCCallStatus(this->simpleMethod(&Bridge::Stub::CheckUpdate), __FUNCTION__); } @@ -620,7 +612,7 @@ grpc::Status GRPCClient::checkUpdate() //**************************************************************************************************************************************************** grpc::Status GRPCClient::installUpdate() { - return this->simpleMethod(&Bridge::Stub::InstallUpdate); + return this->logGRPCCallStatus(this->simpleMethod(&Bridge::Stub::InstallUpdate), __FUNCTION__); } @@ -629,7 +621,7 @@ grpc::Status GRPCClient::installUpdate() //**************************************************************************************************************************************************** grpc::Status GRPCClient::setIsAutomaticUpdateOn(bool on) { - return this->setBool(&Bridge::Stub::SetIsAutomaticUpdateOn, on); + return this->logGRPCCallStatus(this->setBool(&Bridge::Stub::SetIsAutomaticUpdateOn, on), __FUNCTION__); } @@ -638,7 +630,7 @@ grpc::Status GRPCClient::setIsAutomaticUpdateOn(bool on) //**************************************************************************************************************************************************** grpc::Status GRPCClient::isAutomaticUpdateOn(bool &isOn) { - return this->getBool(&Bridge::Stub::IsAutomaticUpdateOn, isOn); + return this->logGRPCCallStatus(this->getBool(&Bridge::Stub::IsAutomaticUpdateOn, isOn), __FUNCTION__); } @@ -648,7 +640,7 @@ grpc::Status GRPCClient::isAutomaticUpdateOn(bool &isOn) //**************************************************************************************************************************************************** grpc::Status GRPCClient::logoutUser(QString const &userID) { - return methodWithStringParam(&Bridge::Stub::LogoutUser, userID); + return this->logGRPCCallStatus(methodWithStringParam(&Bridge::Stub::LogoutUser, userID), __FUNCTION__); } @@ -658,7 +650,7 @@ grpc::Status GRPCClient::logoutUser(QString const &userID) //**************************************************************************************************************************************************** grpc::Status GRPCClient::removeUser(QString const &userID) { - return methodWithStringParam(&Bridge::Stub::RemoveUser, userID); + return this->logGRPCCallStatus(methodWithStringParam(&Bridge::Stub::RemoveUser, userID), __FUNCTION__); } @@ -673,7 +665,7 @@ grpc::Status GRPCClient::configureAppleMail(QString const &userID, QString const ConfigureAppleMailRequest request; request.set_userid(userID.toStdString()); request.set_address(address.toStdString()); - return stub_->ConfigureUserAppleMail(&ctx, request, &empty); + return this->logGRPCCallStatus(stub_->ConfigureUserAppleMail(&ctx, request, &empty), __FUNCTION__); } @@ -689,7 +681,7 @@ grpc::Status GRPCClient::setUserSplitMode(QString const &userID, bool active) request.set_userid(userID.toStdString()); request.set_active(active); - return stub_->SetUserSplitMode(&ctx, request, &empty); + return this->logGRPCCallStatus(stub_->SetUserSplitMode(&ctx, request, &empty), __FUNCTION__); } @@ -705,12 +697,12 @@ grpc::Status GRPCClient::getUserList(QList &outUsers) UserListResponse response; Status status = stub_->GetUserList(&ctx, empty, &response); if (!status.ok()) - return status; + return this->logGRPCCallStatus(status, __FUNCTION__); for (int i = 0; i < response.users_size(); ++i) - outUsers.append(parsegrpcUser(response.users(i))); + outUsers.append(this->parseGRPCUser(response.users(i))); - return status; + return this->logGRPCCallStatus(status, __FUNCTION__); } @@ -719,7 +711,7 @@ grpc::Status GRPCClient::getUserList(QList &outUsers) /// \param[out] outUser The user. /// \return The status code for the operation. //**************************************************************************************************************************************************** -grpc::Status GRPCClient::getUser(QString const &userID, ::SPUser &outUser) +grpc::Status GRPCClient::getUser(QString const &userID, SPUser &outUser) { ClientContext ctx; StringValue s; @@ -728,9 +720,9 @@ grpc::Status GRPCClient::getUser(QString const &userID, ::SPUser &outUser) Status status = stub_->GetUser(&ctx, s, &grpcUser); if (status.ok()) - outUser = parsegrpcUser(grpcUser); + outUser = parseGRPCUser(grpcUser); - return grpc::Status(); + return this->logGRPCCallStatus(grpc::Status(), __FUNCTION__); } @@ -745,12 +737,12 @@ grpc::Status GRPCClient::availableKeychains(QStringList &outKeychains) AvailableKeychainsResponse response; Status status = stub_->AvailableKeychains(&ctx, empty, &response); if (!status.ok()) - return status; + return this->logGRPCCallStatus(status, __FUNCTION__); for (int i = 0; i < response.keychains_size(); ++i) outKeychains.append(QString::fromStdString(response.keychains(i))); - return status; + return this->logGRPCCallStatus(status, __FUNCTION__); } @@ -760,7 +752,7 @@ grpc::Status GRPCClient::availableKeychains(QStringList &outKeychains) //**************************************************************************************************************************************************** grpc::Status GRPCClient::currentKeychain(QString &outKeychain) { - return this->getString(&Bridge::Stub::CurrentKeychain, outKeychain); + return this->logGRPCCallStatus(this->getString(&Bridge::Stub::CurrentKeychain, outKeychain), __FUNCTION__); } @@ -770,7 +762,7 @@ grpc::Status GRPCClient::currentKeychain(QString &outKeychain) //**************************************************************************************************************************************************** grpc::Status GRPCClient::setCurrentKeychain(QString const &keychain) { - return this->setString(&Bridge::Stub::SetCurrentKeychain, keychain); + return this->logGRPCCallStatus(this->setString(&Bridge::Stub::SetCurrentKeychain, keychain), __FUNCTION__); } @@ -814,11 +806,12 @@ grpc::Status GRPCClient::startEventStream() this->processUserEvent(event.user()); break; default: - app().log().debug(QString("Unknown stream event type: %1").arg(event.event_case())); + if (log_) + log_->debug(QString("Unknown stream event type: %1").arg(event.event_case())); } } - return reader->Finish(); + return this->logGRPCCallStatus(reader->Finish(), __FUNCTION__); } @@ -828,7 +821,44 @@ grpc::Status GRPCClient::startEventStream() grpc::Status GRPCClient::stopEventStream() { grpc::ClientContext ctx; - return stub_->StopEventStream(&ctx, empty, &empty); + return this->logGRPCCallStatus(stub_->StopEventStream(&ctx, empty, &empty), __FUNCTION__); +} + + +//**************************************************************************************************************************************************** +/// \param[in] message The event message. +//**************************************************************************************************************************************************** +void GRPCClient::logDebug(QString const &message) +{ + if (log_) + log_->debug(message); +} + + +//**************************************************************************************************************************************************** +/// \param[in] message The event message. +//**************************************************************************************************************************************************** +void GRPCClient::logError(QString const &message) +{ + if (log_) + log_->error(message); +} + + +//**************************************************************************************************************************************************** +/// \param[in] status The status +/// \param[in] callName The call name. +//**************************************************************************************************************************************************** +grpc::Status GRPCClient::logGRPCCallStatus(Status const &status, QString const &callName) +{ + if (log_) + { + if (status.ok()) + log_->debug(QString("%1()").arg(callName)); + else + log_->error(QString("%1() FAILED").arg(callName)); + } + return status; } @@ -977,6 +1007,24 @@ grpc::Status GRPCClient::methodWithStringParam(StringParamMethod method, QString } +//**************************************************************************************************************************************************** +/// \param[in] grpcUser The gRPC user. +/// \return The user. +//**************************************************************************************************************************************************** +SPUser GRPCClient::parseGRPCUser(grpc::User const &grpcUser) +{ + SPUser user = userFromGRPC(grpcUser); + User *u = user.get(); + + connect(u, &User::toggleSplitModeForUser, [&](QString const &userID, bool makeItActive) { this->setUserSplitMode(userID, makeItActive); }); + connect(u, &User::logoutUser, [&](QString const &userID) { this->logoutUser(userID); }); + connect(u, &User::removeUser, [&](QString const &userID) { this->removeUser(userID); }); + connect(u, &User::configureAppleMailForUser, [&](QString const &userID, QString const& address) { this->configureAppleMail(userID, address); }); + + return user; +} + + //**************************************************************************************************************************************************** /// \param[in] event The event. //**************************************************************************************************************************************************** @@ -985,35 +1033,35 @@ void GRPCClient::processAppEvent(AppEvent const &event) switch (event.event_case()) { case AppEvent::kInternetStatus: - app().log().debug("App event received: InternetStatus."); + this->logDebug("App event received: InternetStatus."); emit internetStatus(event.internetstatus().connected()); break; case AppEvent::kToggleAutostartFinished: - app().log().debug("App event received: AutostartFinished."); + this->logDebug("App event received: AutostartFinished."); emit toggleAutostartFinished(); break; case AppEvent::kResetFinished: - app().log().debug("App event received: ResetFinished."); + this->logDebug("App event received: ResetFinished."); emit resetFinished(); break; case AppEvent::kReportBugFinished: - app().log().debug("App event received: ReportBugFinished."); + this->logDebug("App event received: ReportBugFinished."); emit reportBugFinished(); break; case AppEvent::kReportBugSuccess: - app().log().debug("App event received: ReportBugSuccess."); + this->logDebug("App event received: ReportBugSuccess."); emit reportBugSuccess(); break; case AppEvent::kReportBugError: - app().log().debug("App event received: ReportBugError."); + this->logDebug("App event received: ReportBugError."); emit reportBugError(); break; case AppEvent::kShowMainWindow: - app().log().debug("App event received: ShowMainWindow."); + this->logDebug("App event received: ShowMainWindow."); emit showMainWindow(); break; default: - app().log().error("Unknown App event received."); + this->logError("Unknown App event received."); } } @@ -1027,7 +1075,7 @@ void GRPCClient::processLoginEvent(LoginEvent const &event) { case LoginEvent::kError: { - app().log().debug("Login event received: Error."); + this->logDebug("Login event received: Error."); LoginErrorEvent const &error = event.error(); switch (error.type()) { @@ -1053,29 +1101,29 @@ void GRPCClient::processLoginEvent(LoginEvent const &event) emit login2PasswordErrorAbort(QString::fromStdString(error.message())); break; default: - app().log().debug("Unknown login error event received."); + this->logError("Unknown login error event received."); break; } break; } case LoginEvent::kTfaRequested: - app().log().debug("Login event received: TfaRequested."); + this->logDebug("Login event received: TfaRequested."); emit login2FARequested(QString::fromStdString(event.tfarequested().username())); break; case LoginEvent::kTwoPasswordRequested: - app().log().debug("Login event received: TwoPasswordRequested."); + this->logDebug("Login event received: TwoPasswordRequested."); emit login2PasswordRequested(); break; case LoginEvent::kFinished: - app().log().debug("Login event received: Finished."); + this->logDebug("Login event received: Finished."); emit loginFinished(QString::fromStdString(event.finished().userid())); break; case LoginEvent::kAlreadyLoggedIn: - app().log().debug("Login event received: AlreadyLoggedIn."); + this->logDebug("Login event received: AlreadyLoggedIn."); emit loginAlreadyLoggedIn(QString::fromStdString(event.finished().userid())); break; default: - app().log().error("Unknown Login event received."); + this->logError("Unknown Login event received."); break; } } @@ -1090,7 +1138,7 @@ void GRPCClient::processUpdateEvent(UpdateEvent const &event) { case UpdateEvent::kError: { - app().log().debug("Update event received: Error."); + this->logDebug("Update event received: Error."); UpdateErrorEvent const &errorEvent = event.error(); switch (errorEvent.type()) @@ -1105,37 +1153,37 @@ void GRPCClient::processUpdateEvent(UpdateEvent const &event) emit updateSilentError(); break; default: - app().log().error("Unknown update error received."); + this->logError("Unknown update error received."); break; } break; } case UpdateEvent::kManualReady: - app().log().debug("Update event received: ManualReady."); + this->logDebug("Update event received: ManualReady."); emit updateManualReady(QString::fromStdString(event.manualready().version())); break; case UpdateEvent::kManualRestartNeeded: - app().log().debug("Update event received: kManualRestartNeeded."); + this->logDebug("Update event received: kManualRestartNeeded."); emit updateManualRestartNeeded(); break; case UpdateEvent::kForce: - app().log().debug("Update event received: kForce."); + this->logDebug("Update event received: kForce."); emit updateForce(QString::fromStdString(event.force().version())); break; case UpdateEvent::kSilentRestartNeeded: - app().log().debug("Update event received: kSilentRestartNeeded."); + this->logDebug("Update event received: kSilentRestartNeeded."); emit updateSilentRestartNeeded(); break; case UpdateEvent::kIsLatestVersion: - app().log().debug("Update event received: kIsLatestVersion."); + this->logDebug("Update event received: kIsLatestVersion."); emit updateIsLatestVersion(); break; case UpdateEvent::kCheckFinished: - app().log().debug("Update event received: kCheckFinished."); + this->logDebug("Update event received: kCheckFinished."); emit checkUpdatesFinished(); break; default: - app().log().error("Unknown Update event received."); + this->logError("Unknown Update event received."); break; } } @@ -1162,34 +1210,34 @@ void GRPCClient::processCacheEvent(CacheEvent const &event) emit diskFull(); break; default: - app().log().error("Unknown cache error event received."); + this->logError("Unknown cache error event received."); break; } break; } case CacheEvent::kLocationChangedSuccess: - app().log().debug("Cache event received: LocationChangedSuccess."); + this->logDebug("Cache event received: LocationChangedSuccess."); emit cacheLocationChangeSuccess(); break; case CacheEvent::kChangeLocalCacheFinished: emit cacheLocationChangeSuccess(); - app().log().debug("Cache event received: ChangeLocalCacheFinished."); + this->logDebug("Cache event received: ChangeLocalCacheFinished."); break; case CacheEvent::kIsCacheOnDiskEnabledChanged: - app().log().debug("Cache event received: IsCacheOnDiskEnabledChanged."); + this->logDebug("Cache event received: IsCacheOnDiskEnabledChanged."); emit isCacheOnDiskEnabledChanged(event.iscacheondiskenabledchanged().enabled()); break; case CacheEvent::kDiskCachePathChanged: - app().log().debug("Cache event received: DiskCachePathChanged."); + this->logDebug("Cache event received: DiskCachePathChanged."); emit diskCachePathChanged(QUrl::fromLocalFile(QString::fromStdString(event.diskcachepathchanged().path()))); break; default: - app().log().error("Unknown Cache event received."); + this->logError("Unknown Cache event received."); } } @@ -1202,7 +1250,7 @@ void GRPCClient::processMailSettingsEvent(MailSettingsEvent const &event) switch (event.event_case()) { case MailSettingsEvent::kError: - app().log().debug("MailSettings event received: Error."); + this->logDebug("MailSettings event received: Error."); switch (event.error().type()) { case IMAP_PORT_ISSUE: @@ -1212,20 +1260,20 @@ void GRPCClient::processMailSettingsEvent(MailSettingsEvent const &event) emit portIssueSMTP(); break; default: - app().log().error("Unknown mail settings error event received."); + this->logError("Unknown mail settings error event received."); break; } case MailSettingsEvent::kUseSslForSmtpFinished: - app().log().debug("MailSettings event received: UseSslForSmtpFinished."); + this->logDebug("MailSettings event received: UseSslForSmtpFinished."); emit toggleUseSSLFinished(); break; case MailSettingsEvent::kChangePortsFinished: - app().log().debug("MailSettings event received: ChangePortsFinished."); + this->logDebug("MailSettings event received: ChangePortsFinished."); emit changePortFinished(); break; default: - app().log().error("Unknown MailSettings event received."); + this->logError("Unknown MailSettings event received."); } } @@ -1238,19 +1286,19 @@ void GRPCClient::processKeychainEvent(KeychainEvent const &event) switch (event.event_case()) { case KeychainEvent::kChangeKeychainFinished: - app().log().debug("Keychain event received: ChangeKeychainFinished."); + this->logDebug("Keychain event received: ChangeKeychainFinished."); emit changeKeychainFinished(); break; case KeychainEvent::kHasNoKeychain: - app().log().debug("Keychain event received: HasNoKeychain."); + this->logDebug("Keychain event received: HasNoKeychain."); emit hasNoKeychain(); break; case KeychainEvent::kRebuildKeychain: - app().log().debug("Keychain event received: RebuildKeychain."); + this->logDebug("Keychain event received: RebuildKeychain."); emit rebuildKeychain(); break; default: - app().log().error("Unknown Keychain event received."); + this->logError("Unknown Keychain event received."); } } @@ -1263,23 +1311,23 @@ void GRPCClient::processMailEvent(MailEvent const &event) switch (event.event_case()) { case MailEvent::kNoActiveKeyForRecipientEvent: - app().log().debug("Mail event received: kNoActiveKeyForRecipientEvent."); + this->logDebug("Mail event received: kNoActiveKeyForRecipientEvent."); emit noActiveKeyForRecipient(QString::fromStdString(event.noactivekeyforrecipientevent().email())); break; case MailEvent::kAddressChanged: - app().log().debug("Mail event received: AddressChanged."); + this->logDebug("Mail event received: AddressChanged."); emit addressChanged(QString::fromStdString(event.addresschanged().address())); break; case MailEvent::kAddressChangedLogout: - app().log().debug("Mail event received: AddressChangedLogout."); + this->logDebug("Mail event received: AddressChangedLogout."); emit addressChangedLogout(QString::fromStdString(event.addresschangedlogout().address())); break; case MailEvent::kApiCertIssue: emit apiCertIssue(); - app().log().debug("Mail event received: ApiCertIssue."); + this->logDebug("Mail event received: ApiCertIssue."); break; default: - app().log().error("Unknown Mail event received."); + this->logError("Unknown Mail event received."); } } @@ -1294,25 +1342,28 @@ void GRPCClient::processUserEvent(UserEvent const &event) case UserEvent::kToggleSplitModeFinished: { QString const userID = QString::fromStdString(event.togglesplitmodefinished().userid()); - app().log().debug(QString("User event received: ToggleSplitModeFinished (userID = %1).").arg(userID)); + this->logDebug(QString("User event received: ToggleSplitModeFinished (userID = %1).").arg(userID)); emit toggleSplitModeFinished(userID); break; } case UserEvent::kUserDisconnected: { QString const username = QString::fromStdString(event.userdisconnected().username()); - app().log().debug(QString("User event received: UserDisconnected (username = %1).").arg(username)); + this->logDebug(QString("User event received: UserDisconnected (username = %1).").arg(username)); emit userDisconnected(username); break; } case UserEvent::kUserChanged: { QString const userID = QString::fromStdString(event.userchanged().userid()); - app().log().debug(QString("User event received: UserChanged (userID = %1).").arg(userID)); + this->logDebug(QString("User event received: UserChanged (userID = %1).").arg(userID)); emit userChanged(userID); break; } default: - app().log().error("Unknown User event received."); + this->logError("Unknown User event received."); } } + + +} // namespace bridgepp \ No newline at end of file diff --git a/internal/frontend/bridge-gui/GRPC/GRPCClient.h b/internal/frontend/bridgepp/bridgepp/GRPC/GRPCClient.h similarity index 77% rename from internal/frontend/bridge-gui/GRPC/GRPCClient.h rename to internal/frontend/bridgepp/bridgepp/GRPC/GRPCClient.h index 0721f307..6826dd6d 100644 --- a/internal/frontend/bridge-gui/GRPC/GRPCClient.h +++ b/internal/frontend/bridgepp/bridgepp/GRPC/GRPCClient.h @@ -20,44 +20,49 @@ #define BRIDGE_GUI_RPC_CLIENT_H -#include "GRPC/bridge.grpc.pb.h" +#include "../User/User.h" +#include "../Log/Log.h" +#include "bridge.grpc.pb.h" #include "grpc++/grpc++.h" -#include "User/User.h" -#include "Log.h" -typedef grpc::Status (grpc::Bridge::Stub::*SimpleMethod)(grpc::ClientContext*, const google::protobuf::Empty&, google::protobuf::Empty*); -typedef grpc::Status (grpc::Bridge::Stub::*BoolSetter)(grpc::ClientContext*, const google::protobuf::BoolValue&, google::protobuf::Empty*); -typedef grpc::Status (grpc::Bridge::Stub::*BoolGetter)(grpc::ClientContext*, const google::protobuf::Empty&, google::protobuf::BoolValue*); -typedef grpc::Status (grpc::Bridge::Stub::*Int32Setter)(grpc::ClientContext*, const google::protobuf::Int32Value&, google::protobuf::Empty*); -typedef grpc::Status (grpc::Bridge::Stub::*Int32Getter)(grpc::ClientContext*, const google::protobuf::Empty&, google::protobuf::Int32Value*); -typedef grpc::Status (grpc::Bridge::Stub::*StringGetter)(grpc::ClientContext*, const google::protobuf::Empty&, google::protobuf::StringValue*); -typedef grpc::Status (grpc::Bridge::Stub::*StringSetter)(grpc::ClientContext*, const google::protobuf::StringValue&, google::protobuf::Empty*); -typedef grpc::Status (grpc::Bridge::Stub::*StringParamMethod)(grpc::ClientContext*, const google::protobuf::StringValue&, google::protobuf::Empty*); +namespace bridgepp +{ + + +typedef grpc::Status (grpc::Bridge::Stub::*SimpleMethod)(grpc::ClientContext *, const google::protobuf::Empty &, google::protobuf::Empty *); +typedef grpc::Status (grpc::Bridge::Stub::*BoolSetter)(grpc::ClientContext *, const google::protobuf::BoolValue &, google::protobuf::Empty *); +typedef grpc::Status (grpc::Bridge::Stub::*BoolGetter)(grpc::ClientContext *, const google::protobuf::Empty &, google::protobuf::BoolValue *); +typedef grpc::Status (grpc::Bridge::Stub::*Int32Setter)(grpc::ClientContext *, const google::protobuf::Int32Value &, google::protobuf::Empty *); +typedef grpc::Status (grpc::Bridge::Stub::*Int32Getter)(grpc::ClientContext *, const google::protobuf::Empty &, google::protobuf::Int32Value *); +typedef grpc::Status (grpc::Bridge::Stub::*StringGetter)(grpc::ClientContext *, const google::protobuf::Empty &, google::protobuf::StringValue *); +typedef grpc::Status (grpc::Bridge::Stub::*StringSetter)(grpc::ClientContext *, const google::protobuf::StringValue &, google::protobuf::Empty *); +typedef grpc::Status (grpc::Bridge::Stub::*StringParamMethod)(grpc::ClientContext *, const google::protobuf::StringValue &, google::protobuf::Empty *); //**************************************************************************************************************************************************** /// \brief gRPC client class. This class encapsulate the gRPC service, abstracting all data type conversions. //**************************************************************************************************************************************************** -class GRPCClient: public QObject +class GRPCClient : public QObject { - Q_OBJECT +Q_OBJECT public: // member functions. GRPCClient() = default; ///< Default constructor. - GRPCClient(GRPCClient const&) = delete; ///< Disabled copy-constructor. - GRPCClient(GRPCClient&&) = delete; ///< Disabled assignment copy-constructor. + GRPCClient(GRPCClient const &) = delete; ///< Disabled copy-constructor. + GRPCClient(GRPCClient &&) = delete; ///< Disabled assignment copy-constructor. ~GRPCClient() override = default; ///< Destructor. - GRPCClient& operator=(GRPCClient const&) = delete; ///< Disabled assignment operator. - GRPCClient& operator=(GRPCClient&&) = delete; ///< Disabled move assignment operator. + GRPCClient &operator=(GRPCClient const &) = delete; ///< Disabled assignment operator. + GRPCClient &operator=(GRPCClient &&) = delete; ///< Disabled move assignment operator. + void setLog(Log *log); ///< Set the log for the client. bool connectToServer(QString &outError); ///< Establish connection to the gRPC server. - - grpc::Status addLogEntry(Log::Level level, QString const& package, QString const &message); ///< Performs the "AddLogEntry" gRPC call. + + grpc::Status addLogEntry(Log::Level level, QString const &package, QString const &message); ///< Performs the "AddLogEntry" gRPC call. grpc::Status guiReady(); ///< performs the "GuiReady" gRPC call. grpc::Status isFirstGUIStart(bool &outIsFirst); ///< performs the "IsFirstGUIStart" gRPC call. grpc::Status isAutostartOn(bool &outIsOn); ///< Performs the "isAutostartOn" gRPC call. grpc::Status setIsAutostartOn(bool on); ///< Performs the "setIsAutostartOn" gRPC call. grpc::Status isBetaEnabled(bool &outEnabled); ///< Performs the "isBetaEnabled" gRPC call. - grpc::Status setisBetaEnabled(bool enabled); ///< Performs the 'setIsBetaEnabled' gRPC call. + grpc::Status setIsBetaEnabled(bool enabled); ///< Performs the 'setIsBetaEnabled' gRPC call. grpc::Status colorSchemeName(QString &outName); ///< Performs the "colorSchemeName' gRPC call. grpc::Status setColorSchemeName(QString const &name); ///< Performs the "setColorSchemeName' gRPC call. grpc::Status currentEmailClient(QString &outName); ///< Performs the 'currentEmailClient' gRPC call. @@ -93,7 +98,7 @@ public: grpc::Status changeLocalCache(bool enabled, QUrl const &path); ///< Performs the 'ChangeLocalCache' call. signals: void isCacheOnDiskEnabledChanged(bool enabled); - void diskCachePathChanged(QUrl const&outPath); + void diskCachePathChanged(QUrl const &outPath); void cacheUnavailable(); // _ func() `signal:"cacheUnavailable"` void cacheCantMove(); // _ func() `signal:"cacheCantMove"` void cacheLocationChangeSuccess(); // _ func() `signal:"cacheLocationChangeSuccess"` @@ -118,9 +123,9 @@ signals: void changePortFinished(); public: // login related calls - grpc::Status login(QString const &username, QString const& password); ///< Performs the 'login' call. - grpc::Status login2FA(QString const &username, QString const& code); ///< Performs the 'login2FA' call. - grpc::Status login2Passwords(QString const &username, QString const& password); ///< Performs the 'login2Passwords' call. + grpc::Status login(QString const &username, QString const &password); ///< Performs the 'login' call. + grpc::Status login2FA(QString const &username, QString const &code); ///< Performs the 'login2FA' call. + grpc::Status login2Passwords(QString const &username, QString const &password); ///< Performs the 'login2Passwords' call. grpc::Status loginAbort(QString const &username); ///< Performs the 'loginAbort' call. signals: @@ -128,13 +133,13 @@ signals: void loginFreeUserError(); // _ func() `signal:"loginFreeUserError"` void loginConnectionError(QString const &errMsg); // _ func(errorMsg string) `signal:"loginConnectionError"` void login2FARequested(QString const &userName); // _ func(username string) `signal:"login2FARequested"` - void login2FAError(QString const& errMsg); // _ func(errorMsg string) `signal:"login2FAError"` - void login2FAErrorAbort(QString const& errMsg); // _ func(errorMsg string) `signal:"login2FAErrorAbort"` + void login2FAError(QString const &errMsg); // _ func(errorMsg string) `signal:"login2FAError"` + void login2FAErrorAbort(QString const &errMsg); // _ func(errorMsg string) `signal:"login2FAErrorAbort"` void login2PasswordRequested(); // _ func() `signal:"login2PasswordRequested"` - void login2PasswordError(QString const& errMsg); // _ func(errorMsg string) `signal:"login2PasswordError"` - void login2PasswordErrorAbort(QString const& errMsg); // _ func(errorMsg string) `signal:"login2PasswordErrorAbort"` - void loginFinished(QString const &userID); // _ func(index int) `signal:"loginFinished"` - void loginAlreadyLoggedIn(QString const &userID); // _ func(index int) `signal:"loginAlreadyLoggedIn"` + void login2PasswordError(QString const &errMsg); // _ func(errorMsg string) `signal:"login2PasswordError"` + void login2PasswordErrorAbort(QString const &errMsg); // _ func(errorMsg string) `signal:"login2PasswordErrorAbort"` + void loginFinished(QString const &userID); // _ func(index int) `signal:"loginFinished"` + void loginAlreadyLoggedIn(QString const &userID); // _ func(index int) `signal:"loginAlreadyLoggedIn"` public: // Update related calls grpc::Status checkUpdate(); @@ -154,17 +159,17 @@ signals: void checkUpdatesFinished(); public: // user related calls - grpc::Status getUserList(QList& outUsers); - grpc::Status getUser(QString const &userID, SPUser& outUser); + grpc::Status getUserList(QList &outUsers); + grpc::Status getUser(QString const &userID, SPUser &outUser); grpc::Status logoutUser(QString const &userID); ///< Performs the 'logoutUser' call. grpc::Status removeUser(QString const &userID); ///< Performs the 'removeUser' call. - grpc::Status configureAppleMail(QString const& userID, QString const &address); ///< Performs the 'configureAppleMail' call. - grpc::Status setUserSplitMode(QString const& userID, bool active); ///< Performs the 'SetUserSplitMode' call. + grpc::Status configureAppleMail(QString const &userID, QString const &address); ///< Performs the 'configureAppleMail' call. + grpc::Status setUserSplitMode(QString const &userID, bool active); ///< Performs the 'SetUserSplitMode' call. signals: - void toggleSplitModeFinished(QString const& userID); - void userDisconnected(QString const& username); - void userChanged(QString const& userID); + void toggleSplitModeFinished(QString const &userID); + void userDisconnected(QString const &username); + void userChanged(QString const &userID); public: // keychain related calls @@ -178,7 +183,7 @@ signals: void rebuildKeychain(); void certIsReady(); -signals: // mail releated events +signals: // mail related events void noActiveKeyForRecipient(QString const &email); // _ func(email string) `signal:noActiveKeyForRecipient` void addressChanged(QString const &address); // _ func(address string) `signal:addressChanged` void addressChangedLogout(QString const &address); // _ func(address string) `signal:addressChangedLogout` @@ -192,16 +197,20 @@ private slots: void configFolderChanged(); private: + void logDebug(QString const &message); ///< Log an event. + void logError(QString const &message); ///< Log an event. + grpc::Status logGRPCCallStatus(grpc::Status const &status, QString const &callName); ///< Log the status of a gRPC code. grpc::Status simpleMethod(SimpleMethod method); ///< perform a gRPC call to a bool setter. grpc::Status setBool(BoolSetter setter, bool value); ///< perform a gRPC call to a bool setter. - grpc::Status getBool(BoolGetter getter, bool& outValue); ///< perform a gRPC call to a bool getter. + grpc::Status getBool(BoolGetter getter, bool &outValue); ///< perform a gRPC call to a bool getter. grpc::Status setInt32(Int32Setter setter, int value); ///< perform a gRPC call to an int setter. - grpc::Status getInt32(Int32Getter getter, int& outValue); ///< perform a gRPC call to an int getter. - grpc::Status setString(StringSetter getter, QString const& value); ///< Perform a gRPC call to a string setter. - grpc::Status getString(StringGetter getter, QString& outValue); ///< Perform a gRPC call to a string getter. - grpc::Status getURLForLocalFile(StringGetter getter, QUrl& outValue); ///< Perform a gRPC call to a string getter, with resulted converted to QUrl for a local file path. - grpc::Status getURL(StringGetter getter, QUrl& outValue); ///< Perform a gRPC call to a string getter, with resulted converted to QUrl. - grpc::Status methodWithStringParam(StringParamMethod method, QString const& str); ///< Perfom a gRPC call that takes a string as a parameter and returns an Empty. + grpc::Status getInt32(Int32Getter getter, int &outValue); ///< perform a gRPC call to an int getter. + grpc::Status setString(StringSetter getter, QString const &value); ///< Perform a gRPC call to a string setter. + grpc::Status getString(StringGetter getter, QString &outValue); ///< Perform a gRPC call to a string getter. + grpc::Status getURLForLocalFile(StringGetter getter, QUrl &outValue); ///< Perform a gRPC call to a string getter, with resulted converted to QUrl for a local file path. + grpc::Status getURL(StringGetter getter, QUrl &outValue); ///< Perform a gRPC call to a string getter, with resulted converted to QUrl. + grpc::Status methodWithStringParam(StringParamMethod method, QString const &str); ///< Perform a gRPC call that takes a string as a parameter and returns an Empty. + SPUser parseGRPCUser(grpc::User const &grpcUser); ///< Parse a gRPC user struct and return a User. std::string getServerCertificate(); ///< Wait until server certificates is generated and retrieve it. void processAppEvent(grpc::AppEvent const &event); ///< Process an 'App' event. @@ -214,9 +223,13 @@ private: void processUserEvent(grpc::UserEvent const &event); ///< Process a 'User' event. private: // data members. + Log *log_ { nullptr }; ///< The log for the GRPC client. std::shared_ptr channel_ { nullptr }; ///< The gRPC channel. std::shared_ptr stub_ { nullptr }; ///< The gRPC stub (a.k.a. client). }; +} + + #endif // BRIDGE_GUI_RPC_CLIENT_H diff --git a/internal/frontend/bridgepp/bridgepp/GRPC/GRPCUtils.cpp b/internal/frontend/bridgepp/bridgepp/GRPC/GRPCUtils.cpp new file mode 100644 index 00000000..440bdcd3 --- /dev/null +++ b/internal/frontend/bridgepp/bridgepp/GRPC/GRPCUtils.cpp @@ -0,0 +1,182 @@ +// Copyright (c) 2022 Proton AG +// +// This file is part of Proton Mail Bridge. +// +// Proton Mail Bridge is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Proton Mail Bridge 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Proton Mail Bridge. If not, see . + + +#include "GRPCUtils.h" +#include "../Exception/Exception.h" +#include "../BridgeUtils.h" + + +#if defined(Q_OS_WIN32) && defined(ERROR) +// The folks at Microsoft have decided that it was OK to `#define ERROR 0` in wingdi.h. It is not OK, because +// any occurrence of ERROR, even scoped, will be substituted. For instance Log::Level::ERROR (case imposed by gRPC). +#undef ERROR +#endif + + +namespace bridgepp +{ + + +namespace +{ + + +//**************************************************************************************************************************************************** +/// \return The server certificate file name +//**************************************************************************************************************************************************** +QString serverCertificateFilename() +{ + return "cert.pem"; +} + + +//**************************************************************************************************************************************************** +// +//**************************************************************************************************************************************************** +QString serverKeyFilename() +{ + return "key.pem"; +} + + +} + + +//**************************************************************************************************************************************************** +/// \return The absolute path of the server certificate. +//**************************************************************************************************************************************************** +QString serverCertificatePath() +{ + return QDir(userConfigDir()).absoluteFilePath(serverCertificateFilename()); +} + + +//**************************************************************************************************************************************************** +/// \return The absolute path of the server key. +//**************************************************************************************************************************************************** +QString serverKeyPath() +{ + return QDir(userConfigDir()).absoluteFilePath(serverKeyFilename()); +} + + + +//**************************************************************************************************************************************************** +/// \param[in] level The Log::Level. +/// \return The grpc::LogLevel. +//**************************************************************************************************************************************************** +grpc::LogLevel logLevelToGRPC(Log::Level level) +{ + switch (level) + { + case Log::Level::Panic: + return grpc::LogLevel::PANIC; + case Log::Level::Fatal: + return grpc::LogLevel::FATAL; + case Log::Level::Error: + return grpc::LogLevel::ERROR; + case Log::Level::Warn: + return grpc::LogLevel::WARN; + case Log::Level::Info: + return grpc::LogLevel::INFO; + case Log::Level::Debug: + return grpc::LogLevel::DEBUG; + case Log::Level::Trace: + return grpc::LogLevel::TRACE; + default: + throw Exception(QString("unknown log level %1.").arg(qint32(level))); + } +} + + +//**************************************************************************************************************************************************** +/// \param[in] level The level::LogLevel. +/// \return The Log::Level. +//**************************************************************************************************************************************************** +Log::Level logLevelFromGRPC(grpc::LogLevel level) +{ + switch (level) + { + case grpc::PANIC: + return Log::Level::Panic; + case grpc::FATAL: + return Log::Level::Fatal; + case grpc::ERROR: + return Log::Level::Error; + case grpc::WARN: + return Log::Level::Warn; + case grpc::INFO: + return Log::Level::Info; + case grpc::DEBUG: + return Log::Level::Debug; + case grpc::TRACE: + return Log::Level::Trace; + default: + throw Exception(QString("unknown log level %1.").arg(qint32(level))); + } +} + + +//**************************************************************************************************************************************************** +/// \param[in] grpcUser The gRPC user. +/// \param[in] user The user. +//**************************************************************************************************************************************************** +SPUser userFromGRPC(grpc::User const &grpcUser) +{ + SPUser user = User::newUser(nullptr); + + user->setID(QString::fromStdString(grpcUser.id())); + user->setUsername(QString::fromStdString(grpcUser.username())); + user->setPassword(QString::fromStdString(grpcUser.password())); + QStringList addresses; + for (int j = 0; j < grpcUser.addresses_size(); ++j) + addresses.append(QString::fromStdString(grpcUser.addresses(j))); + user->setAddresses(addresses); + user->setAvatarText(QString::fromStdString(grpcUser.avatartext())); + user->setLoggedIn(grpcUser.loggedin()); + user->setSplitMode(grpcUser.splitmode()); + user->setSetupGuideSeen(grpcUser.setupguideseen()); + user->setUsedBytes(float(grpcUser.usedbytes())); + user->setTotalBytes(float(grpcUser.totalbytes())); + + return user; +} + + +//**************************************************************************************************************************************************** +/// \param[in] user the user. +/// \param[out] outGRPCUser The GRPC user. +//**************************************************************************************************************************************************** +void userToGRPC(User const &user, grpc::User &outGRPCUser) +{ + outGRPCUser.set_id(user.id().toStdString()); + outGRPCUser.set_username(user.username().toStdString()); + outGRPCUser.set_password(user.password().toStdString()); + outGRPCUser.clear_addresses(); + for (QString const& address: user.addresses()) + outGRPCUser.add_addresses(address.toStdString()); + outGRPCUser.set_avatartext(user.avatarText().toStdString()); + outGRPCUser.set_loggedin(user.loggedIn()); + outGRPCUser.set_splitmode(user.splitMode()); + outGRPCUser.set_setupguideseen(user.setupGuideSeen()); + outGRPCUser.set_usedbytes(user.usedBytes()); + outGRPCUser.set_totalbytes(user.totalBytes()); +} + + +} // namespace bridgepp \ No newline at end of file diff --git a/internal/frontend/bridgepp/bridgepp/GRPC/GRPCUtils.h b/internal/frontend/bridgepp/bridgepp/GRPC/GRPCUtils.h new file mode 100644 index 00000000..9fee503a --- /dev/null +++ b/internal/frontend/bridgepp/bridgepp/GRPC/GRPCUtils.h @@ -0,0 +1,42 @@ +// Copyright (c) 2022 Proton AG +// +// This file is part of Proton Mail Bridge. +// +// Proton Mail Bridge is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Proton Mail Bridge 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Proton Mail Bridge. If not, see . + + +#ifndef BRIDGE_GUI_GRPC_UTILS_H +#define BRIDGE_GUI_GRPC_UTILS_H + + +#include "../User/User.h" +#include "../Log/Log.h" +#include "bridge.grpc.pb.h" + + +namespace bridgepp +{ + + +QString serverCertificatePath(); ///< Return the path of the server certificate. +QString serverKeyPath(); ///< Return the path of the server key. +grpc::LogLevel logLevelToGRPC(Log::Level level); ///< Convert a Log::Level to gRPC enum value. +Log::Level logLevelFromGRPC(grpc::LogLevel level); ///< Convert a grpc::LogLevel to a Log::Level. +void userToGRPC(User const &user, grpc::User &outGRPCUser); ///< Convert a bridgepp::User to a grpc::User. +SPUser userFromGRPC(grpc::User const &grpcUser); ///< Create a bridgepp::User from a grpc::User. + +} + + +#endif // BRIDGE_GUI_GRPC_UTILS_H diff --git a/internal/frontend/bridge-gui/GRPC/bridge.grpc.pb.cc b/internal/frontend/bridgepp/bridgepp/GRPC/bridge.grpc.pb.cc similarity index 100% rename from internal/frontend/bridge-gui/GRPC/bridge.grpc.pb.cc rename to internal/frontend/bridgepp/bridgepp/GRPC/bridge.grpc.pb.cc diff --git a/internal/frontend/bridge-gui/GRPC/bridge.grpc.pb.h b/internal/frontend/bridgepp/bridgepp/GRPC/bridge.grpc.pb.h similarity index 100% rename from internal/frontend/bridge-gui/GRPC/bridge.grpc.pb.h rename to internal/frontend/bridgepp/bridgepp/GRPC/bridge.grpc.pb.h diff --git a/internal/frontend/bridge-gui/GRPC/bridge.pb.cc b/internal/frontend/bridgepp/bridgepp/GRPC/bridge.pb.cc similarity index 100% rename from internal/frontend/bridge-gui/GRPC/bridge.pb.cc rename to internal/frontend/bridgepp/bridgepp/GRPC/bridge.pb.cc diff --git a/internal/frontend/bridge-gui/GRPC/bridge.pb.h b/internal/frontend/bridgepp/bridgepp/GRPC/bridge.pb.h similarity index 100% rename from internal/frontend/bridge-gui/GRPC/bridge.pb.h rename to internal/frontend/bridgepp/bridgepp/GRPC/bridge.pb.h diff --git a/internal/frontend/bridge-gui/Log.cpp b/internal/frontend/bridgepp/bridgepp/Log/Log.cpp similarity index 81% rename from internal/frontend/bridge-gui/Log.cpp rename to internal/frontend/bridgepp/bridgepp/Log/Log.cpp index 41cacb9c..38c429e8 100644 --- a/internal/frontend/bridge-gui/Log.cpp +++ b/internal/frontend/bridgepp/bridgepp/Log/Log.cpp @@ -16,13 +16,38 @@ // along with Proton Mail Bridge. If not, see . -#include "Pch.h" #include "Log.h" +namespace bridgepp +{ + + namespace { +Log *qtHandlerLog { nullptr }; ///< The log instance handling qt logs. +QMutex qtHandlerMutex; ///< A mutex used to access qtHandlerLog. + +//**************************************************************************************************************************************************** +/// \param[in] log The log handling qt log entries. Can be null. +//**************************************************************************************************************************************************** +void setQtMessageHandlerLog(Log *log) +{ + QMutexLocker locker(&qtHandlerMutex); + qtHandlerLog = log; +} + + +//**************************************************************************************************************************************************** +/// \return The log handling qt log entries. Can be null. +//**************************************************************************************************************************************************** +Log *qtMessageHandlerLog() +{ + QMutexLocker locker(&qtHandlerMutex); + return qtHandlerLog; +} + //**************************************************************************************************************************************************** /// \param[in] type The message type. @@ -30,25 +55,27 @@ namespace //**************************************************************************************************************************************************** void qtMessageHandler(QtMsgType type, QMessageLogContext const &, QString const &message) { - static Log &log = app().log(); + Log *log = qtMessageHandlerLog(); + if (!log) + return; switch (type) { case QtDebugMsg: - log.debug(message); + log->debug(message); break; case QtWarningMsg: - log.warn(message); + log->warn(message); break; case QtCriticalMsg: case QtFatalMsg: - log.error(message); + log->error(message); break; case QtInfoMsg: default: - log.info(message); + log->info(message); break; } } @@ -62,18 +89,28 @@ QString logLevelToString(Log::Level level) { switch (level) { - case Log::Level::Panic: return "PANIC"; - case Log::Level::Fatal: return "FATAL"; - case Log::Level::Error: return "ERROR"; - case Log::Level::Warn: return "WARN"; - case Log::Level::Info: return "INFO"; - case Log::Level::Debug: return "DEBUG"; - case Log::Level::Trace: return "TRACE"; - default: return "UNKNOWN"; + case Log::Level::Panic: + return "PANIC"; + case Log::Level::Fatal: + return "FATAL"; + case Log::Level::Error: + return "ERROR"; + case Log::Level::Warn: + return "WARN"; + case Log::Level::Info: + return "INFO"; + case Log::Level::Debug: + return "DEBUG"; + case Log::Level::Trace: + return "TRACE"; + default: + return "UNKNOWN"; } } +} // anonymous namespace + //**************************************************************************************************************************************************** /// \brief return a string representing the log entry @@ -82,20 +119,18 @@ QString logLevelToString(Log::Level level) /// \param[in] message The log entry message. /// \return The string for the log entry //**************************************************************************************************************************************************** -QString logEntryToString(Log::Level level, QString const &message) +QString Log::logEntryToString(Log::Level level, QString const &message) { - return QString("[%1] %2").arg(logLevelToString(level)).arg(message); -} - - + return QString("[%1] %2").arg(logLevelToString(level), message); } //**************************************************************************************************************************************************** /// the message handle process the message from the Qt logging system. //**************************************************************************************************************************************************** -void Log::installQtMessageHandler() +void Log::registerAsQtMessageHandler() { + setQtMessageHandlerLog(this); qInstallMessageHandler(qtMessageHandler); } @@ -227,8 +262,11 @@ void Log::addEntry(Log::Level level, QString const &message) if (echoInConsole_) { - QTextStream& stream = (qint32(level) <= (qint32(Level::Warn))) ? stderr_ : stdout_; + QTextStream &stream = (qint32(level) <= (qint32(Level::Warn))) ? stderr_ : stdout_; stream << logEntryToString(level, message) << "\n"; stream.flush(); } } + + +} // namespace bridgepp diff --git a/internal/frontend/bridge-gui/Log.h b/internal/frontend/bridgepp/bridgepp/Log/Log.h similarity index 87% rename from internal/frontend/bridge-gui/Log.h rename to internal/frontend/bridgepp/bridgepp/Log/Log.h index 2112ef58..95ba2f1c 100644 --- a/internal/frontend/bridge-gui/Log.h +++ b/internal/frontend/bridgepp/bridgepp/Log/Log.h @@ -16,8 +16,12 @@ // along with Proton Mail Bridge. If not, see . -#ifndef BRIDGE_GUI_LOG_H -#define BRIDGE_GUI_LOG_H +#ifndef BRIDGE_PP_LOG_H +#define BRIDGE_PP_LOG_H + + +namespace bridgepp +{ //**************************************************************************************************************************************************** @@ -25,9 +29,9 @@ //**************************************************************************************************************************************************** class Log : public QObject { - Q_OBJECT +Q_OBJECT public: // data types. - /// \brief Log level class. The list matches [logrus log levels](https://pkg.go.dev/github.com/sirupsen/logrus). + /// \brief Log level class. The list matches [loggers log levels](https://pkg.go.dev/github.com/sirupsen/logrus). enum class Level { Panic, ///< Panic log level. @@ -39,8 +43,9 @@ public: // data types. Trace ///< Trace log level. }; -public: // static member functions - static void installQtMessageHandler(); ///< Install the Qt message handler. +public: // static member functions. + static QString logEntryToString(Log::Level level, QString const &message); ///< Return a string describing a log entry. + public: // member functions. Log(); ///< Default constructor. @@ -54,6 +59,7 @@ public: // member functions. Level level() const; ///< Get the log level. void setEchoInConsole(bool value); ///< Set if the log entries should be echoed in STDOUT/STDERR. bool echoInConsole() const; ///< Check if the log entries should be echoed in STDOUT/STDERR. + void registerAsQtMessageHandler(); ///< Install the Qt message handler. public slots: void panic(QString const &message); ///< Adds an panic entry to the log. @@ -79,4 +85,7 @@ private: // data members }; -#endif //BRIDGE_GUI_LOG_H +} // namespace bridgepp + + +#endif //BRIDGE_PP_LOG_H diff --git a/internal/frontend/bridgepp/bridgepp/User/User.cpp b/internal/frontend/bridgepp/bridgepp/User/User.cpp new file mode 100644 index 00000000..a1fddf44 --- /dev/null +++ b/internal/frontend/bridgepp/bridgepp/User/User.cpp @@ -0,0 +1,329 @@ +// Copyright (c) 2022 Proton AG +// +// This file is part of Proton Mail Bridge. +// +// Proton Mail Bridge is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Proton Mail Bridge 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Proton Mail Bridge. If not, see . + + +#include "User.h" + + +namespace bridgepp +{ + + +//**************************************************************************************************************************************************** +/// \param[in] parent The parent object of the user. +//**************************************************************************************************************************************************** +SPUser User::newUser(QObject *parent) +{ + return SPUser(new User(parent)); +} + + +//**************************************************************************************************************************************************** +/// \param[in] parent The parent object. +//**************************************************************************************************************************************************** +User::User(QObject *parent) + : QObject(parent) +{ + +} + + +//**************************************************************************************************************************************************** +/// \param[in] user The user to copy from +//**************************************************************************************************************************************************** +void User::update(User const &user) +{ + this->setID(user.id()); + this->setUsername(user.username()); + this->setPassword(user.password()); + this->setAddresses(user.addresses()); + this->setAvatarText(user.avatarText()); + this->setLoggedIn(user.loggedIn()); + this->setSplitMode(user.splitMode()); + this->setSetupGuideSeen(user.setupGuideSeen()); + this->setUsedBytes(user.usedBytes()); + this->setTotalBytes(user.totalBytes()); +} + + +//**************************************************************************************************************************************************** +/// \param[in] makeItActive Should split mode be made active. +//**************************************************************************************************************************************************** +void User::toggleSplitMode(bool makeItActive) +{ + emit toggleSplitModeForUser(id_, makeItActive); +} + + +//**************************************************************************************************************************************************** +// +//**************************************************************************************************************************************************** +void User::logout() +{ + emit logoutUser(id_); +} + + +//**************************************************************************************************************************************************** +// +//**************************************************************************************************************************************************** +void User::remove() +{ + emit removeUser(id_); +} + + +//**************************************************************************************************************************************************** +/// \param[in] address The email address to configure Apple Mail for. +//**************************************************************************************************************************************************** +void User::configureAppleMail(QString const &address) +{ + emit configureAppleMailForUser(id_, address); +} + + +//**************************************************************************************************************************************************** +// The only purpose of this call is to forward to the QML application the toggleSplitModeFinished(userID) event +// that was received by the UserList model. +//**************************************************************************************************************************************************** +void User::emitToggleSplitModeFinished() +{ + emit toggleSplitModeFinished(); +} + + +//**************************************************************************************************************************************************** +/// \return The userID. +//**************************************************************************************************************************************************** +QString User::id() const +{ + return id_; +} + + +//**************************************************************************************************************************************************** +/// \param[in] id The userID. +//**************************************************************************************************************************************************** +void User::setID(QString const &id) +{ + if (id == id_) + return; + + id_ = id; + emit idChanged(id_); +} + + +//**************************************************************************************************************************************************** +/// \return The username. +//**************************************************************************************************************************************************** +QString User::username() const +{ + return username_; +} + + +//**************************************************************************************************************************************************** +/// \param[in] username The username. +//**************************************************************************************************************************************************** +void User::setUsername(QString const &username) +{ + if (username == username_) + return; + + username_ = username; + emit usernameChanged(username_); +} + + +//**************************************************************************************************************************************************** +/// \return The password. +//**************************************************************************************************************************************************** +QString User::password() const +{ + return password_; +} + + +//**************************************************************************************************************************************************** +/// \param[in] password The password. +//**************************************************************************************************************************************************** +void User::setPassword(QString const &password) +{ + if (password == password_) + return; + + password_ = password; + emit passwordChanged(password_); +} + + +//**************************************************************************************************************************************************** +/// \return The addresses. +//**************************************************************************************************************************************************** +QStringList User::addresses() const +{ + return addresses_; +} + + +//**************************************************************************************************************************************************** +/// \param[in] addresses The addresses. +//**************************************************************************************************************************************************** +void User::setAddresses(QStringList const &addresses) +{ + if (addresses == addresses_) + return; + + addresses_ = addresses; + emit addressesChanged(addresses_); +} + + +//**************************************************************************************************************************************************** +/// \return The avatar text. +//**************************************************************************************************************************************************** +QString User::avatarText() const +{ + return avatarText_; +} + + +//**************************************************************************************************************************************************** +/// \param[in] avatarText The avatar text. +//**************************************************************************************************************************************************** +void User::setAvatarText(QString const &avatarText) +{ + if (avatarText == avatarText_) + return; + + avatarText_ = avatarText; + emit usernameChanged(avatarText_); +} + + +//**************************************************************************************************************************************************** +/// \return The login status. +//**************************************************************************************************************************************************** +bool User::loggedIn() const +{ + return loggedIn_; +} + + +//**************************************************************************************************************************************************** +/// \param[in] loggedIn The login status. +//**************************************************************************************************************************************************** +void User::setLoggedIn(bool loggedIn) +{ + if (loggedIn == loggedIn_) + return; + + loggedIn_ = loggedIn; + emit loggedInChanged(loggedIn_); +} + + +//**************************************************************************************************************************************************** +/// \return The split mode status. +//**************************************************************************************************************************************************** +bool User::splitMode() const +{ + return splitMode_; +} + + +//**************************************************************************************************************************************************** +/// \param[in] splitMode The split mode status. +//**************************************************************************************************************************************************** +void User::setSplitMode(bool splitMode) +{ + if (splitMode == splitMode_) + return; + + splitMode_ = splitMode; + emit splitModeChanged(splitMode_); +} + + +//**************************************************************************************************************************************************** +/// \return The 'Setup Guide Seen' status. +//**************************************************************************************************************************************************** +bool User::setupGuideSeen() const +{ + return setupGuideSeen_; +} + + +//**************************************************************************************************************************************************** +/// \param[in] setupGuideSeen The 'Setup Guide Seen' status. +//**************************************************************************************************************************************************** +void User::setSetupGuideSeen(bool setupGuideSeen) +{ + if (setupGuideSeen == setupGuideSeen_) + return; + + setupGuideSeen_ = setupGuideSeen; + emit setupGuideSeenChanged(setupGuideSeen_); +} + + +//**************************************************************************************************************************************************** +/// \return The used bytes. +//**************************************************************************************************************************************************** +float User::usedBytes() const +{ + return usedBytes_; +} + + +//**************************************************************************************************************************************************** +/// \param[in] usedBytes The used bytes. +//**************************************************************************************************************************************************** +void User::setUsedBytes(float usedBytes) +{ + if (usedBytes == usedBytes_) + return; + + usedBytes_ = usedBytes; + emit usedBytesChanged(usedBytes_); +} + + +//**************************************************************************************************************************************************** +/// \return The total bytes. +//**************************************************************************************************************************************************** +float User::totalBytes() const +{ + return totalBytes_; +} + + +//**************************************************************************************************************************************************** +/// \param[in] totalBytes The total bytes. +//**************************************************************************************************************************************************** +void User::setTotalBytes(float totalBytes) +{ + if (totalBytes == totalBytes_) + return; + + totalBytes_ = totalBytes; + emit totalBytesChanged(totalBytes_); +} + + +} // namespace bridgepp diff --git a/internal/frontend/bridgepp/bridgepp/User/User.h b/internal/frontend/bridgepp/bridgepp/User/User.h new file mode 100644 index 00000000..472229e1 --- /dev/null +++ b/internal/frontend/bridgepp/bridgepp/User/User.h @@ -0,0 +1,130 @@ +// Copyright (c) 2022 Proton AG +// +// This file is part of Proton Mail Bridge. +// +// Proton Mail Bridge is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Proton Mail Bridge 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Proton Mail Bridge. If not, see . + + +#ifndef BRIDGE_GUI_USER_H +#define BRIDGE_GUI_USER_H + + +namespace bridgepp +{ + + +typedef std::shared_ptr SPUser; ///< Type definition for shared pointer to user. + + +//**************************************************************************************************************************************************** +/// \brief User class. +//**************************************************************************************************************************************************** +class User : public QObject +{ +Q_OBJECT +public: // static member function + static SPUser newUser(QObject *parent); ///< Create a new user + +public: // member functions. + User(User const &) = delete; ///< Disabled copy-constructor. + User(User &&) = delete; ///< Disabled assignment copy-constructor. + ~User() override = default; ///< Destructor. + User &operator=(User const &) = delete; ///< Disabled assignment operator. + User &operator=(User &&) = delete; ///< Disabled move assignment operator. + void update(User const &user); ///< Update the user. + +public slots: + // slots for QML generated calls + void toggleSplitMode(bool makeItActive); // _ func(makeItActive bool) `slot:"toggleSplitMode"` + void logout(); // _ func() `slot:"logout"` + void remove(); // _ func() `slot:"remove"` + void configureAppleMail(QString const &address); // _ func(address string) `slot:"configureAppleMail"` + void emitToggleSplitModeFinished(); // slot for external signals + +signals: // signal used to forward QML event received in the above slots + void toggleSplitModeForUser(QString const &userID, bool makeItActive); + void logoutUser(QString const &userID); + void removeUser(QString const &userID); + void configureAppleMailForUser(QString const &userID, QString const &address); + + +public: + Q_PROPERTY(QString id READ id WRITE setID NOTIFY idChanged) // _ string ID + Q_PROPERTY(QString username READ username WRITE setUsername NOTIFY usernameChanged) // _ string `property:"username"` + Q_PROPERTY(QString password READ password WRITE setPassword NOTIFY passwordChanged) // _ string `property:"password"` + Q_PROPERTY(QStringList addresses READ addresses WRITE setAddresses NOTIFY addressesChanged) // _ []string `property:"addresses"` + Q_PROPERTY(QString avatarText READ avatarText WRITE setAvatarText NOTIFY avatarTextChanged) // _ string `property:"avatarText"` + Q_PROPERTY(bool loggedIn READ loggedIn WRITE setLoggedIn NOTIFY loggedInChanged) // _ bool `property:"loggedIn"` + Q_PROPERTY(bool splitMode READ splitMode WRITE setSplitMode NOTIFY splitModeChanged) // _ bool `property:"splitMode"` + Q_PROPERTY(bool setupGuideSeen READ setupGuideSeen WRITE setSetupGuideSeen NOTIFY setupGuideSeenChanged) // _ bool `property:"setupGuideSeen"` + Q_PROPERTY(float usedBytes READ usedBytes WRITE setUsedBytes NOTIFY usedBytesChanged) // _ float32 `property:"usedBytes"` + Q_PROPERTY(float totalBytes READ totalBytes WRITE setTotalBytes NOTIFY totalBytesChanged) // _ float32 `property:"totalBytes"` + + QString id() const; + void setID(QString const &id); + QString username() const; + void setUsername(QString const &username); + QString password() const; + void setPassword(QString const &password); + QStringList addresses() const; + void setAddresses(QStringList const &addresses); + QString avatarText() const; + void setAvatarText(QString const &avatarText); + bool loggedIn() const; + void setLoggedIn(bool loggedIn); + bool splitMode() const; + void setSplitMode(bool splitMode); + bool setupGuideSeen() const; + void setSetupGuideSeen(bool setupGuideSeen); + float usedBytes() const; + void setUsedBytes(float usedBytes); + float totalBytes() const; + void setTotalBytes(float totalBytes); + +signals: + // signals used for Qt properties + void idChanged(QString const &id); + void usernameChanged(QString const &username); + void passwordChanged(QString const &); + void addressesChanged(QStringList const &); + void avatarTextChanged(QString const &avatarText); + void loggedInChanged(bool loggedIn); + void splitModeChanged(bool splitMode); + void setupGuideSeenChanged(bool seen); + void usedBytesChanged(float byteCount); + void totalBytesChanged(float byteCount); + + void toggleSplitModeFinished(); + +private: // member functions. + User(QObject *parent); ///< Default constructor. + +private: // data members. + QString id_; ///< The userID. + QString username_; ///< The username + QString password_; ///< The IMAP password of the user. + QStringList addresses_; ///< The email address list of the user. + QString avatarText_; ///< The avatar text (i.e. initials of the user) + bool loggedIn_ { true }; ///< Is the user logged in. + bool splitMode_ { false }; ///< Is split mode active. + bool setupGuideSeen_ { false }; ///< Has the setup guide been seen. + float usedBytes_ { 0.0f }; ///< The storage used by the user. + float totalBytes_ { 1.0f }; ///< The storage quota of the user. +}; + + +} // namespace bridgepp + + +#endif // BRIDGE_GUI_USER_H diff --git a/internal/frontend/bridge-gui/Worker/Overseer.cpp b/internal/frontend/bridgepp/bridgepp/Worker/Overseer.cpp similarity index 94% rename from internal/frontend/bridge-gui/Worker/Overseer.cpp rename to internal/frontend/bridgepp/bridgepp/Worker/Overseer.cpp index 72aa2c43..37121583 100644 --- a/internal/frontend/bridge-gui/Worker/Overseer.cpp +++ b/internal/frontend/bridgepp/bridgepp/Worker/Overseer.cpp @@ -16,9 +16,12 @@ // along with Proton Mail Bridge. If not, see . -#include "Pch.h" #include "Overseer.h" -#include "Exception.h" +#include "../Exception/Exception.h" + + +namespace bridgepp +{ //**************************************************************************************************************************************************** @@ -56,7 +59,7 @@ void Overseer::startWorker(bool autorelease) const worker_->moveToThread(thread_); connect(thread_, &QThread::started, worker_, &Worker::run); - connect(worker_, &Worker::finished, [&]() {thread_->quit(); }); // for unkwown reason, connect to the QThread::quit slot does not work... + connect(worker_, &Worker::finished, [&]() { thread_->quit(); }); // for unkwown reason, connect to the QThread::quit slot does not work... connect(worker_, &Worker::error, [&]() { thread_->quit(); }); if (autorelease) @@ -112,3 +115,6 @@ Worker *Overseer::worker() const { return worker_; } + + +} // namespace bridgepp diff --git a/internal/frontend/bridge-gui/Worker/Overseer.h b/internal/frontend/bridgepp/bridgepp/Worker/Overseer.h similarity index 72% rename from internal/frontend/bridge-gui/Worker/Overseer.h rename to internal/frontend/bridgepp/bridgepp/Worker/Overseer.h index a49d6e22..d193289c 100644 --- a/internal/frontend/bridge-gui/Worker/Overseer.h +++ b/internal/frontend/bridgepp/bridgepp/Worker/Overseer.h @@ -16,26 +16,30 @@ // along with Proton Mail Bridge. If not, see . -#ifndef BRIDGE_GUI_OVERSEER_H -#define BRIDGE_GUI_OVERSEER_H +#ifndef BRIDGE_PP_OVERSEER_H +#define BRIDGE_PP_OVERSEER_H #include "Worker.h" +namespace bridgepp +{ + + //**************************************************************************************************************************************************** /// \brief Overseer used to manager a worker instance and its associated thread. //**************************************************************************************************************************************************** -class Overseer: public QObject +class Overseer : public QObject { - Q_OBJECT +Q_OBJECT public: // member functions. - explicit Overseer(Worker* worker, QObject* parent); ///< Default constructor. - Overseer(Overseer const&) = delete; ///< Disabled copy-constructor. - Overseer(Overseer&&) = delete; ///< Disabled assignment copy-constructor. + explicit Overseer(Worker *worker, QObject *parent); ///< Default constructor. + Overseer(Overseer const &) = delete; ///< Disabled copy-constructor. + Overseer(Overseer &&) = delete; ///< Disabled assignment copy-constructor. ~Overseer() override; ///< Destructor. - Overseer& operator=(Overseer const&) = delete; ///< Disabled assignment operator. - Overseer& operator=(Overseer&&) = delete; ///< Disabled move assignment operator. + Overseer &operator=(Overseer const &) = delete; ///< Disabled assignment operator. + Overseer &operator=(Overseer &&) = delete; ///< Disabled move assignment operator. bool isFinished() const; ///< Check if the worker is finished. Worker *worker() const; ///< Return worker. @@ -44,8 +48,8 @@ public slots: void release(); ///< Delete the worker and its thread. public: // data members. - QThread *thread_ { nullptr }; ///< The thread. - Worker *worker_ { nullptr }; ///< The worker. + QThread *thread_{nullptr}; ///< The thread. + Worker *worker_{nullptr}; ///< The worker. }; @@ -53,4 +57,7 @@ typedef std::unique_ptr UPOverseer; ///< Type definition for unique po typedef std::shared_ptr SPOverseer; ///< Type definition for shared pointer to Overseer. -#endif //BRIDGE_GUI_OVERSEER_H +} // namespace bridgepp + + +#endif //BRIDGE_PP_OVERSEER_H diff --git a/internal/frontend/bridge-gui/Worker/Worker.h b/internal/frontend/bridgepp/bridgepp/Worker/Worker.h similarity index 69% rename from internal/frontend/bridge-gui/Worker/Worker.h rename to internal/frontend/bridgepp/bridgepp/Worker/Worker.h index 6111d943..d893e8bc 100644 --- a/internal/frontend/bridge-gui/Worker/Worker.h +++ b/internal/frontend/bridgepp/bridgepp/Worker/Worker.h @@ -16,22 +16,29 @@ // along with Proton Mail Bridge. If not, see . -#ifndef BRIDGE_GUI_WORKER_H -#define BRIDGE_GUI_WORKER_H +#ifndef BRIDGE_PP_WORKER_H +#define BRIDGE_PP_WORKER_H + + +namespace bridgepp +{ + //**************************************************************************************************************************************************** /// \brief Pure virtual class for worker intended to perform a threaded operation. //**************************************************************************************************************************************************** -class Worker: public QObject +class Worker : public QObject { - Q_OBJECT +Q_OBJECT public: // member functions - explicit Worker(QObject *parent) : QObject(parent) {} ///< Default constructor. - Worker(Worker const&) = delete; ///< Disabled copy-constructor. - Worker(Worker&&) = delete; ///< Disabled assignment copy-constructor. + explicit Worker(QObject *parent) + : QObject(parent) + {} ///< Default constructor. + Worker(Worker const &) = delete; ///< Disabled copy-constructor. + Worker(Worker &&) = delete; ///< Disabled assignment copy-constructor. ~Worker() override = default; ///< Destructor. - Worker& operator=(Worker const&) = delete; ///< Disabled assignment operator. - Worker& operator=(Worker&&) = delete; ///< Disabled move assignment operator. + Worker &operator=(Worker const &) = delete; ///< Disabled assignment operator. + Worker &operator=(Worker &&) = delete; ///< Disabled move assignment operator. public slots: virtual void run() = 0; ///< run the worker. @@ -39,8 +46,11 @@ public slots: signals: void started(); ///< Signal for the start of the worker void finished(); ///< Signal for the end of the worker - void error(QString const& message); ///< Signal for errors. After an error, worker ends and finished is NOT emitted. + void error(QString const &message); ///< Signal for errors. After an error, worker ends and finished is NOT emitted. }; -#endif //BRIDGE_GUI_WORKER_H +} // namespace bridgepp + + +#endif //BRIDGE_PP_WORKER_H diff --git a/utils/missing_license.sh b/utils/missing_license.sh index 72cd76b7..3ac2b86e 100755 --- a/utils/missing_license.sh +++ b/utils/missing_license.sh @@ -19,6 +19,7 @@ YEAR=`date +%Y` MISSING_FILES=$(find . \ + -not -path "./extern/*" \ -not -path "./vendor/*" \ -not -path "./vendor-cache/*" \ -not -path "./.cache/*" \