Other: introduced bridgepp static C++ library.

This commit is contained in:
Xavier Michelon
2022-08-03 12:03:52 +02:00
committed by Jakub
parent 3f189c430b
commit 345cc45a3e
41 changed files with 1554 additions and 786 deletions

View File

@ -16,13 +16,15 @@
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>. // along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
#include "Pch.h"
#include "AppController.h" #include "AppController.h"
#include "QMLBackend.h" #include "QMLBackend.h"
#include "GRPC/GRPCClient.h"
#include "Log.h"
#include "BridgeMonitor.h" #include "BridgeMonitor.h"
#include "Exception.h" #include <bridgepp/GRPC/GRPCClient.h>
#include <bridgepp/Exception/Exception.h>
#include <bridgepp/Log/Log.h>
using namespace bridgepp;
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
@ -43,7 +45,6 @@ AppController::AppController()
, grpc_(std::make_unique<GRPCClient>()) , grpc_(std::make_unique<GRPCClient>())
, log_(std::make_unique<Log>()) , log_(std::make_unique<Log>())
{ {
} }

View File

@ -21,10 +21,16 @@
class QMLBackend; class QMLBackend;
class GRPCClient; class BridgeMonitor;
namespace bridgepp
{
class Log; class Log;
class Overseer; class Overseer;
class BridgeMonitor; class GRPCClient;
}
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
/// \brief App controller class. /// \brief App controller class.
@ -41,9 +47,9 @@ public: // member functions.
AppController& operator=(AppController const&) = delete; ///< Disabled assignment operator. AppController& operator=(AppController const&) = delete; ///< Disabled assignment operator.
AppController& operator=(AppController&&) = delete; ///< Disabled move assignment operator. AppController& operator=(AppController&&) = delete; ///< Disabled move assignment operator.
QMLBackend& backend() { return *backend_; } ///< Return a reference to the backend. QMLBackend& backend() { return *backend_; } ///< Return a reference to the backend.
GRPCClient& grpc() { return *grpc_; } ///< Return a reference to the GRPC client. bridgepp::GRPCClient& grpc() { return *grpc_; } ///< Return a reference to the GRPC client.
Log& log() { return *log_; } ///< Return a reference to the log. bridgepp::Log& log() { return *log_; } ///< Return a reference to the log.
std::unique_ptr<Overseer>& bridgeOverseer() { return bridgeOverseer_; }; ///< Returns a reference the bridge overseer std::unique_ptr<bridgepp::Overseer>& bridgeOverseer() { return bridgeOverseer_; }; ///< Returns a reference the bridge overseer
BridgeMonitor* bridgeMonitor() const; ///< Return the bridge worker. BridgeMonitor* bridgeMonitor() const; ///< Return the bridge worker.
private: // member functions private: // member functions
@ -51,9 +57,9 @@ private: // member functions
private: // data members private: // data members
std::unique_ptr<QMLBackend> backend_; ///< The backend. std::unique_ptr<QMLBackend> backend_; ///< The backend.
std::unique_ptr<GRPCClient> grpc_; ///< The RPC client. std::unique_ptr<bridgepp::GRPCClient> grpc_; ///< The RPC client.
std::unique_ptr<Log> log_; ///< The log. std::unique_ptr<bridgepp::Log> log_; ///< The log.
std::unique_ptr<Overseer> bridgeOverseer_; ///< The overseer for the bridge monitor worker. std::unique_ptr<bridgepp::Overseer> bridgeOverseer_; ///< The overseer for the bridge monitor worker.
}; };

View File

@ -17,7 +17,10 @@
#include "BridgeMonitor.h" #include "BridgeMonitor.h"
#include "Exception.h" #include <bridgepp/Exception/Exception.h>
using namespace bridgepp;
namespace namespace

View File

@ -21,13 +21,13 @@
#define BRIDGE_GUI_BRIDGE_MONITOR_H #define BRIDGE_GUI_BRIDGE_MONITOR_H
#include "Worker/Worker.h" #include <bridgepp/Worker/Worker.h>
//********************************************************************************************************************** //**********************************************************************************************************************
/// \brief Bridge process launcher and monitor class. /// \brief Bridge process launcher and monitor class.
//********************************************************************************************************************** //**********************************************************************************************************************
class BridgeMonitor: public Worker class BridgeMonitor: public bridgepp::Worker
{ {
Q_OBJECT Q_OBJECT
public: // static member functions public: // static member functions

View File

@ -17,41 +17,16 @@
cmake_minimum_required(VERSION 3.22) 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") set(VCPKG_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../../../extern/vcpkg")
message(STATUS "VCPKG_ROOT is ${VCPKG_ROOT}") include(../bridgepp/bridge_setup.cmake)
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) # Project
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")
project(bridge-gui LANGUAGES CXX) project(bridge-gui LANGUAGES CXX)
@ -61,116 +36,70 @@ else()
message(STATUS "Bridge version is ${BRIDGE_APP_VERSION}") message(STATUS "Bridge version is ${BRIDGE_APP_VERSION}")
endif() 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. if (APPLE) # On macOS, we have some Objective-C++ code in DockIcon to deal with the dock icon.
enable_language(OBJC OBJCXX) enable_language(OBJC OBJCXX)
endif() 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}) 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).") 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() endif()
set(CMAKE_PREFIX_PATH $ENV{QT6DIR} ${CMAKE_PREFIX_PATH}) set(CMAKE_PREFIX_PATH $ENV{QT6DIR} ${CMAKE_PREFIX_PATH})
set(CMAKE_CXX_STANDARD 20) find_package(Qt6 COMPONENTS Core Quick Qml QuickControls2 REQUIRED)
set(CMAKE_CXX_STANDARD_REQUIRED ON) qt_standard_project_setup()
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON) 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}") 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") configure_file(Version.h.in ${CMAKE_SOURCE_DIR}/Version.h)
set(PROTO_FILE "${PROTO_DIR}/bridge.proto")
set(GRPC_OUT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/GRPC") add_subdirectory(../bridgepp bridgepp)
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")
if (APPLE) if (APPLE)
set(DOCK_ICON_SRC_FILE DockIcon/DockIcon.mm) set(DOCK_ICON_SRC_FILE DockIcon/DockIcon.mm)
else() else()
set(DOCK_ICON_SRC_FILE DockIcon/DockIcon.cpp) set(DOCK_ICON_SRC_FILE DockIcon/DockIcon.cpp)
endif() 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 add_executable(bridge-gui
Resources.qrc Resources.qrc
${PROTO_CPP_FILE} ${PROTO_H_FILE} ${GRPC_CPP_FILE} ${GRPC_H_FILE}
AppController.cpp AppController.h AppController.cpp AppController.h
BridgeMonitor.cpp BridgeMonitor.h BridgeMonitor.cpp BridgeMonitor.h
EventStreamWorker.cpp EventStreamWorker.h EventStreamWorker.cpp EventStreamWorker.h
Exception.cpp Exception.h
Log.cpp Log.h
main.cpp main.cpp
Pch.h Pch.h
Version.h Version.h
QMLBackend.cpp QMLBackend.h QMLBackend.cpp QMLBackend.h
UserList.cpp UserList.h
${DOCK_ICON_SRC_FILE} DockIcon/DockIcon.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_precompile_headers(bridge-gui PRIVATE Pch.h)
target_include_directories(bridge-gui PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(bridge-gui target_link_libraries(bridge-gui
Qt6::Core Qt6::Core
Qt6::Quick Qt6::Quick
Qt6::Qml Qt6::Qml
Qt6::QuickControls2 Qt6::QuickControls2
protobuf::libprotobuf bridgepp
gRPC::grpc++
) )
if (APPLE) if (APPLE)

View File

@ -16,7 +16,6 @@
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>. // along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
#include "Pch.h"
#ifndef Q_OS_MACOS #ifndef Q_OS_MACOS

View File

@ -16,7 +16,6 @@
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>. // along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
#include "Pch.h"
#include <Cocoa/Cocoa.h> #include <Cocoa/Cocoa.h>
#include "DockIcon.h" #include "DockIcon.h"

View File

@ -16,11 +16,13 @@
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>. // along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
#include "Pch.h"
#include "EventStreamWorker.h" #include "EventStreamWorker.h"
#include "GRPC/GRPCClient.h" #include <bridgepp/GRPC/GRPCClient.h>
#include "Log.h" #include <bridgepp/Exception/Exception.h>
#include "Exception.h" #include <bridgepp/Log/Log.h>
using namespace bridgepp;
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************

View File

@ -20,14 +20,13 @@
#define BRIDGE_GUI_EVENT_STREAM_WORKER_H #define BRIDGE_GUI_EVENT_STREAM_WORKER_H
#include "GRPC/bridge.grpc.pb.h" #include <bridgepp/Worker/Worker.h>
#include "Worker/Worker.h"
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
/// \brief Stream reader class. /// \brief Stream reader class.
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
class EventStreamReader: public Worker class EventStreamReader: public bridgepp::Worker
{ {
Q_OBJECT Q_OBJECT
public: // member functions public: // member functions

View File

@ -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 <https://www.gnu.org/licenses/>.
#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<User>(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)));
}
}

View File

@ -27,11 +27,4 @@
#include <AppController.h> #include <AppController.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
#endif // BRIDGE_GUI_PCH_H #endif // BRIDGE_GUI_PCH_H

View File

@ -16,13 +16,15 @@
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>. // along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
#include "Pch.h"
#include "QMLBackend.h" #include "QMLBackend.h"
#include "Exception.h"
#include "GRPC/GRPCClient.h"
#include "Worker/Overseer.h"
#include "EventStreamWorker.h" #include "EventStreamWorker.h"
#include "Version.h" #include "Version.h"
#include <bridgepp/GRPC/GRPCClient.h>
#include <bridgepp/Exception/Exception.h>
#include <bridgepp/Worker/Overseer.h>
using namespace bridgepp;
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
@ -30,7 +32,6 @@
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
QMLBackend::QMLBackend() QMLBackend::QMLBackend()
: QObject() : QObject()
, users_(new UserList(this))
{ {
} }
@ -40,6 +41,9 @@ QMLBackend::QMLBackend()
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
void QMLBackend::init() void QMLBackend::init()
{ {
users_ = new UserList(this);
app().grpc().setLog(&app().log());
this->connectGrpcEvents(); this->connectGrpcEvents();
QString error; QString error;
@ -47,10 +51,11 @@ void QMLBackend::init()
app().log().info("Connected to backend via gRPC service."); app().log().info("Connected to backend via gRPC service.");
else else
throw Exception(QString("Cannot connectToServer to go backend via gRPC: %1").arg(error)); throw Exception(QString("Cannot connectToServer to go backend via gRPC: %1").arg(error));
QString bridgeVer; QString bridgeVer;
app().grpc().version(bridgeVer); app().grpc().version(bridgeVer);
if (bridgeVer != PROJECT_VER) 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<Overseer>(new EventStreamReader(nullptr), nullptr); eventStreamOverseer_ = std::make_unique<Overseer>(new EventStreamReader(nullptr), nullptr);
eventStreamOverseer_->startWorker(true); 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 // 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"); app().grpc().showSplashScreen(showSplashScreen_);
logGRPCCallStatus(app().grpc().goos(goos_), "goos"); app().grpc().goos(goos_);
logGRPCCallStatus(app().grpc().logsPath(logsPath_), "logsPath"); app().grpc().logsPath(logsPath_);
logGRPCCallStatus(app().grpc().licensePath(licensePath_), "licensePath"); app().grpc().licensePath(licensePath_);
this->retrieveUserList(); this->retrieveUserList();
} }
@ -147,7 +152,16 @@ void QMLBackend::connectGrpcEvents()
void QMLBackend::retrieveUserList() void QMLBackend::retrieveUserList()
{ {
QList<SPUser> users; QList<SPUser> 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); users_->reset(users);
} }
@ -176,7 +190,7 @@ QPoint QMLBackend::getCursorPos()
bool QMLBackend::isPortFree(int port) bool QMLBackend::isPortFree(int port)
{ {
bool isFree = false; bool isFree = false;
logGRPCCallStatus(app().grpc().isPortFree(port, isFree), "isPortFree"); app().grpc().isPortFree(port, isFree);
return isFree; return isFree;
} }
@ -186,7 +200,7 @@ bool QMLBackend::isPortFree(int port)
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
void QMLBackend::guiReady() void QMLBackend::guiReady()
{ {
logGRPCCallStatus(app().grpc().guiReady(), "guiReady"); app().grpc().guiReady();
} }
@ -195,7 +209,7 @@ void QMLBackend::guiReady()
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
void QMLBackend::quit() void QMLBackend::quit()
{ {
logGRPCCallStatus(app().grpc().quit(), "quit"); app().grpc().quit();
qApp->exit(0); qApp->exit(0);
} }
@ -205,7 +219,7 @@ void QMLBackend::quit()
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
void QMLBackend::restart() void QMLBackend::restart()
{ {
logGRPCCallStatus(app().grpc().restart(), "restart"); app().grpc().restart();
app().log().error("RESTART is not implemented"); /// \todo GODT-1671 implement 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) void QMLBackend::toggleAutostart(bool active)
{ {
logGRPCCallStatus(app().grpc().setIsAutostartOn(active), "setIsAutostartOn"); app().grpc().setIsAutostartOn(active);
emit isAutostartOnChanged(this->isAutostartOn()); emit isAutostartOnChanged(this->isAutostartOn());
} }
@ -225,7 +239,7 @@ void QMLBackend::toggleAutostart(bool active)
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
void QMLBackend::toggleBeta(bool active) void QMLBackend::toggleBeta(bool active)
{ {
logGRPCCallStatus(app().grpc().setisBetaEnabled(active), "setIsBetaEnabled"); app().grpc().setIsBetaEnabled(active);
emit isBetaEnabledChanged(this->isBetaEnabled()); emit isBetaEnabledChanged(this->isBetaEnabled());
} }
@ -235,7 +249,7 @@ void QMLBackend::toggleBeta(bool active)
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
void QMLBackend::changeColorScheme(QString const &scheme) void QMLBackend::changeColorScheme(QString const &scheme)
{ {
logGRPCCallStatus(app().grpc().setColorSchemeName(scheme), "setIsBetaEnabled"); app().grpc().setColorSchemeName(scheme);
emit colorSchemeNameChanged(this->colorSchemeName()); emit colorSchemeNameChanged(this->colorSchemeName());
} }
@ -245,9 +259,7 @@ void QMLBackend::changeColorScheme(QString const &scheme)
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
void QMLBackend::toggleUseSSLforSMTP(bool makeItActive) void QMLBackend::toggleUseSSLforSMTP(bool makeItActive)
{ {
grpc::Status status = app().grpc().setUseSSLForSMTP(makeItActive); if (app().grpc().setUseSSLForSMTP(makeItActive).ok())
logGRPCCallStatus(status, "setUseSSLForSMTP");
if (status.ok())
emit useSSLforSMTPChanged(makeItActive); emit useSSLforSMTPChanged(makeItActive);
} }
@ -258,9 +270,7 @@ void QMLBackend::toggleUseSSLforSMTP(bool makeItActive)
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
void QMLBackend::changePorts(int imapPort, int smtpPort) void QMLBackend::changePorts(int imapPort, int smtpPort)
{ {
grpc::Status status = app().grpc().changePorts(imapPort, smtpPort); if (app().grpc().changePorts(imapPort, smtpPort).ok())
logGRPCCallStatus(status, "changePorts");
if (status.ok())
{ {
emit portIMAPChanged(imapPort); emit portIMAPChanged(imapPort);
emit portSMTPChanged(smtpPort); emit portSMTPChanged(smtpPort);
@ -273,9 +283,7 @@ void QMLBackend::changePorts(int imapPort, int smtpPort)
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
void QMLBackend::toggleDoH(bool active) void QMLBackend::toggleDoH(bool active)
{ {
grpc::Status status = app().grpc().setIsDoHEnabled(active); if (app().grpc().setIsDoHEnabled(active).ok())
logGRPCCallStatus(status, "toggleDoH");
if (status.ok())
emit isDoHEnabledChanged(active); emit isDoHEnabledChanged(active);
} }
@ -285,9 +293,7 @@ void QMLBackend::toggleDoH(bool active)
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
void QMLBackend::changeKeychain(QString const &keychain) void QMLBackend::changeKeychain(QString const &keychain)
{ {
grpc::Status status = app().grpc().setCurrentKeychain(keychain); if (app().grpc().setCurrentKeychain(keychain).ok())
logGRPCCallStatus(status, "setCurrentKeychain");
if (status.ok())
emit currentKeychainChanged(keychain); emit currentKeychainChanged(keychain);
} }
@ -297,9 +303,7 @@ void QMLBackend::changeKeychain(QString const &keychain)
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
void QMLBackend::toggleAutomaticUpdate(bool active) void QMLBackend::toggleAutomaticUpdate(bool active)
{ {
grpc::Status status = app().grpc().setIsAutomaticUpdateOn(active); if (app().grpc().setIsAutomaticUpdateOn(active).ok())
logGRPCCallStatus(status, "toggleAutomaticUpdate");
if (status.ok())
emit isAutomaticUpdateOnChanged(active); emit isAutomaticUpdateOnChanged(active);
} }
@ -309,7 +313,7 @@ void QMLBackend::toggleAutomaticUpdate(bool active)
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
void QMLBackend::checkUpdates() void QMLBackend::checkUpdates()
{ {
logGRPCCallStatus(app().grpc().checkUpdate(), "checkUpdate"); app().grpc().checkUpdate();
} }
@ -318,7 +322,7 @@ void QMLBackend::checkUpdates()
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
void QMLBackend::installUpdate() void QMLBackend::installUpdate()
{ {
logGRPCCallStatus(app().grpc().installUpdate(), "installUpdate"); app().grpc().installUpdate();
} }
@ -327,5 +331,5 @@ void QMLBackend::installUpdate()
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
void QMLBackend::triggerReset() void QMLBackend::triggerReset()
{ {
logGRPCCallStatus(app().grpc().triggerReset(), "triggerReset"); app().grpc().triggerReset();
} }

View File

@ -16,16 +16,15 @@
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>. // along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
#ifndef BRIDGE_GUI_QMLBACKEND_H #ifndef BRIDGE_GUI_QML_BACKEND_H
#define BRIDGE_GUI_QMLBACKEND_H #define BRIDGE_GUI_QML_BACKEND_H
#include <grpcpp/support/status.h>
#include "DockIcon/DockIcon.h" #include "DockIcon/DockIcon.h"
#include "GRPC/GRPCClient.h" #include "UserList.h"
#include "GRPC/GRPCUtils.h" #include <bridgepp/GRPC/GRPCClient.h>
#include "Worker/Overseer.h" #include <bridgepp/GRPC/GRPCUtils.h>
#include "User/UserList.h" #include <bridgepp/Worker/Overseer.h>
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
@ -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` Q_PROPERTY(bool dockIconVisible READ dockIconVisible WRITE setDockIconVisible NOTIFY dockIconVisibleChanged) // _ bool `property:dockIconVisible`
// Qt Property system setters & getters. // 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_; }; bool showSplashScreen() const { return showSplashScreen_; };
void setShowSplashScreen(bool show) { if (show != showSplashScreen_) { showSplashScreen_ = show; emit showSplashScreenChanged(show); } } void setShowSplashScreen(bool show) { if (show != showSplashScreen_) { showSplashScreen_ = show; emit showSplashScreenChanged(show); } }
QString goos() { return goos_; } QString goos() { return goos_; }
QUrl logsPath() const { return logsPath_; } QUrl logsPath() const { return logsPath_; }
QUrl licensePath() const { return licensePath_; } QUrl licensePath() const { return licensePath_; }
QUrl releaseNotesLink() const { QUrl link; logGRPCCallStatus(app().grpc().releaseNotesPageLink(link), "releaseNotesPageLink"); return link; } QUrl releaseNotesLink() const { QUrl link; app().grpc().releaseNotesPageLink(link); return link; }
QUrl dependencyLicensesLink() const { QUrl link; logGRPCCallStatus(app().grpc().dependencyLicensesLink(link), "dependencyLicensesLink"); return link; } QUrl dependencyLicensesLink() const { QUrl link; app().grpc().dependencyLicensesLink(link); return link; }
QUrl landingPageLink() const { QUrl link; logGRPCCallStatus(app().grpc().landingPageLink(link), "landingPageLink"); return link; } QUrl landingPageLink() const { QUrl link; app().grpc().landingPageLink(link); return link; }
QString version() const { QString version; logGRPCCallStatus(app().grpc().version(version), "version"); return version; } QString version() const { QString version; app().grpc().version(version); return version; }
QString hostname() const { QString hostname; logGRPCCallStatus(app().grpc().hostname(hostname), "hostname"); return hostname; } QString hostname() const { QString hostname; app().grpc().hostname(hostname); return hostname; }
bool isAutostartOn() const { bool v; logGRPCCallStatus(app().grpc().isAutostartOn(v), "isAutostartOn"); return v; }; bool isAutostartOn() const { bool v; app().grpc().isAutostartOn(v); return v; };
bool isBetaEnabled() const { bool v; logGRPCCallStatus(app().grpc().isBetaEnabled(v), "isBetaEnabled"); return v; } bool isBetaEnabled() const { bool v; app().grpc().isBetaEnabled(v); return v; }
QString colorSchemeName() const { QString name; logGRPCCallStatus(app().grpc().colorSchemeName(name), "colorSchemeName"); return name; } QString colorSchemeName() const { QString name; app().grpc().colorSchemeName(name); return name; }
bool isDiskCacheEnabled() const { bool enabled; logGRPCCallStatus(app().grpc().isCacheOnDiskEnabled(enabled), "isCacheOnDiskEnabled"); return enabled;} bool isDiskCacheEnabled() const { bool enabled; app().grpc().isCacheOnDiskEnabled(enabled); return enabled;}
QUrl diskCachePath() const { QUrl path; logGRPCCallStatus(app().grpc().diskCachePath(path), "diskCachePath"); return path; } QUrl diskCachePath() const { QUrl path; app().grpc().diskCachePath(path); return path; }
bool useSSLForSMTP() const{ bool useSSL; logGRPCCallStatus(app().grpc().useSSLForSMTP(useSSL), "useSSLForSMTP"); return useSSL; } bool useSSLForSMTP() const{ bool useSSL; app().grpc().useSSLForSMTP(useSSL); return useSSL; }
int portIMAP() const { int port; logGRPCCallStatus(app().grpc().portIMAP(port), "portIMAP"); return port; } int portIMAP() const { int port; app().grpc().portIMAP(port); return port; }
int portSMTP() const { int port; logGRPCCallStatus(app().grpc().portSMTP(port), "portSMTP"); return port; } int portSMTP() const { int port; app().grpc().portSMTP(port); return port; }
bool isDoHEnabled() const { bool isEnabled; logGRPCCallStatus(app().grpc().isDoHEnabled(isEnabled), "isDoHEnabled"); return isEnabled;} bool isDoHEnabled() const { bool isEnabled; app().grpc().isDoHEnabled(isEnabled); return isEnabled;}
bool isFirstGUIStart() const { bool v; logGRPCCallStatus(app().grpc().isFirstGUIStart(v), "isFirstGUIStart"); return v; }; bool isFirstGUIStart() const { bool v; app().grpc().isFirstGUIStart(v); return v; };
bool isAutomaticUpdateOn() const { bool isOn = false; logGRPCCallStatus(app().grpc().isAutomaticUpdateOn(isOn), "isAutomaticUpdateOn"); return isOn; } bool isAutomaticUpdateOn() const { bool isOn = false; app().grpc().isAutomaticUpdateOn(isOn); return isOn; }
QString currentEmailClient() { QString client; logGRPCCallStatus(app().grpc().currentEmailClient(client), "currentEmailClient"); return client;} QString currentEmailClient() { QString client; app().grpc().currentEmailClient(client); return client;}
QStringList availableKeychain() const { QStringList keychains; logGRPCCallStatus(app().grpc().availableKeychains(keychains), "availableKeychain"); return keychains; } QStringList availableKeychain() const { QStringList keychains; app().grpc().availableKeychains(keychains); return keychains; }
QString currentKeychain() const { QString keychain; logGRPCCallStatus(app().grpc().currentKeychain(keychain), "currentKeychain"); return keychain; } QString currentKeychain() const { QString keychain; app().grpc().currentKeychain(keychain); return keychain; }
bool dockIconVisible() const { return getDockIconVisibleState(); }; bool dockIconVisible() const { return getDockIconVisibleState(); };
void setDockIconVisible(bool visible) { setDockIconVisibleState(visible); emit dockIconVisibleChanged(visible); } 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 toggleAutostart(bool active); // _ func(makeItActive bool) `slot:"toggleAutostart"`
void toggleBeta(bool active); // _ func(makeItActive bool) `slot:"toggleBeta"` void toggleBeta(bool active); // _ func(makeItActive bool) `slot:"toggleBeta"`
void changeColorScheme(QString const &scheme); // _ func(string) `slot:"changeColorScheme"` 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 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) { logGRPCCallStatus(app().grpc().login(username, password), "login");} // _ func(username, password string) `slot:"login"` 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) { logGRPCCallStatus(app().grpc().login2FA(username, code), "login2FA");} // _ func(username, code string) `slot:"login2FA"` 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) { logGRPCCallStatus(app().grpc().login2Passwords(username, password), void login2Password(QString const& username, QString const& password) { app().grpc().login2Passwords(username, password);} // _ func(username, password string) `slot:"login2Password"`
"login2Passwords");} // _ func(username, password string) `slot:"login2Password"` void loginAbort(QString const& username){ app().grpc().loginAbort(username);} // _ func(username string) `slot:"loginAbort"`
void loginAbort(QString const& username){ logGRPCCallStatus(app().grpc().loginAbort(username), "loginAbort");} // _ func(username string) `slot:"loginAbort"`
void toggleUseSSLforSMTP(bool makeItActive); // _ func(makeItActive bool) `slot:"toggleUseSSLforSMTP"` void toggleUseSSLforSMTP(bool makeItActive); // _ func(makeItActive bool) `slot:"toggleUseSSLforSMTP"`
void changePorts(int imapPort, int smtpPort); // _ func(imapPort, smtpPort int) `slot:"changePorts"` void changePorts(int imapPort, int smtpPort); // _ func(imapPort, smtpPort int) `slot:"changePorts"`
void toggleDoH(bool active); // _ func(makeItActive bool) `slot:"toggleDoH"` 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 installUpdate(); // _ func() `slot:"installUpdate"`
void triggerReset(); // _ func() `slot:"triggerReset"` void triggerReset(); // _ func() `slot:"triggerReset"`
void reportBug(QString const &description, QString const& address, QString const &emailClient, bool includeLogs) { 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 signals: // Signals received from the Go backend, to be forwarded to QML
void toggleAutostartFinished(); // _ func() `signal:"toggleAutostartFinished"` void toggleAutostartFinished(); // _ func() `signal:"toggleAutostartFinished"`
@ -211,7 +209,7 @@ private: // member functions
private: // data members private: // data members
UserList* users_ { nullptr }; ///< The user list. Owned by backend. UserList* users_ { nullptr }; ///< The user list. Owned by backend.
std::unique_ptr<Overseer> eventStreamOverseer_; ///< The event stream overseer. std::unique_ptr<bridgepp::Overseer> eventStreamOverseer_; ///< The event stream overseer.
bool showSplashScreen_ { false }; ///< The cached version of show splash screen. Retrieved on startup from bridge, and potentially modified locally. 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. QString goos_; ///< The cached version of the GOOS variable.
QUrl logsPath_; ///< The logs path. Retrieved from bridge on startup. 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

View File

@ -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 <https://www.gnu.org/licenses/>.
#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();
}

View File

@ -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 <https://www.gnu.org/licenses/>.
#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<User> SPUser;
#endif // BRIDGE_GUI_USER_H

View File

@ -16,9 +16,10 @@
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>. // along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
#include "Pch.h"
#include "UserList.h" #include "UserList.h"
#include "GRPC/GRPCClient.h"
using namespace bridgepp;
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
@ -36,11 +37,12 @@ UserList::UserList(QObject *parent)
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
void UserList::connectGRPCEvents() const void UserList::connectGRPCEvents() const
{ {
GRPCClient* client = &app().grpc(); GRPCClient& client = app().grpc();
connect(client, &GRPCClient::userChanged, this, &UserList::onUserChanged); connect(&client, &GRPCClient::userChanged, this, &UserList::onUserChanged);
connect(client, &GRPCClient::toggleSplitModeFinished, this, &UserList::onToggleSplitModeFinished); 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. /// 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. /// From the original QtThe recipe QML backend User model, the User is always returned, regardless of the role.
Q_UNUSED(role) Q_UNUSED(role)
int const row = index.row(); int const row = index.row();
if ((row < 0) || (row >= users_.size())) if ((row < 0) || (row >= users_.size()))
return QVariant(); return QVariant();
return QVariant::fromValue(users_[row].get()); return QVariant::fromValue(users_[row].get());
@ -91,6 +93,7 @@ void UserList::reset()
this->endResetModel(); this->endResetModel();
} }
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
/// \param[in] users The new user list. /// \param[in] users The new user list.
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
@ -105,7 +108,7 @@ void UserList::reset(QList<SPUser> const &users)
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
/// \param[in] user The user. /// \param[in] user The user.
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
void UserList::appendUser(SPUser const& user) void UserList::appendUser(SPUser const &user)
{ {
int const size = users_.size(); int const size = users_.size();
this->beginInsertRows(QModelIndex(), size, size); this->beginInsertRows(QModelIndex(), size, size);
@ -135,7 +138,7 @@ void UserList::updateUserAtRow(int row, User const &user)
{ {
if ((row < 0) || (row >= users_.count())) 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; return;
} }
@ -153,11 +156,11 @@ User *UserList::get(int row) const
{ {
if ((row < 0) || (row >= users_.count())) 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; 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(); return users_[row].get();
} }
@ -170,11 +173,13 @@ void UserList::onUserChanged(QString const &userID)
int const index = this->rowOfUserID(userID); int const index = this->rowOfUserID(userID);
SPUser user; SPUser user;
grpc::Status status = app().grpc().getUser(userID, user); grpc::Status status = app().grpc().getUser(userID, user);
QQmlEngine::setObjectOwnership(user.get(), QQmlEngine::CppOwnership);
if ((!user) || (!status.ok())) if ((!user) || (!status.ok()))
{ {
if (index >= 0) // user exists here but not in the go backend. we delete it. 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); this->removeUserAt(index);
} }
return; return;
@ -182,12 +187,12 @@ void UserList::onUserChanged(QString const &userID)
if (index < 0) 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); this->appendUser(user);
return; 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); this->updateUserAtRow(index, *user);
} }

View File

@ -19,45 +19,49 @@
#ifndef BRIDGE_GUI_USER_LIST_H #ifndef BRIDGE_GUI_USER_LIST_H
#define BRIDGE_GUI_USER_LIST_H #define BRIDGE_GUI_USER_LIST_H
#include "User.h"
#include <bridgepp/User/User.h>
#include <bridgepp/Log/Log.h>
#include <bridgepp/GRPC/GRPCClient.h>
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
/// \brief User list class. /// \brief User list class.
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
class UserList: public QAbstractListModel class UserList : public QAbstractListModel
{ {
Q_OBJECT Q_OBJECT
public: // member functions. public: // member functions.
explicit UserList(QObject *parent = nullptr); ///< Default constructor. UserList(QObject *parent); ///< Default constructor.
UserList(UserList const &other) = delete ; ///< Disabled copy-constructor. UserList(UserList const &other) = delete; ///< Disabled copy-constructor.
UserList& operator=(UserList const& other) = delete; ///< Disabled assignment operator. UserList &operator=(UserList const &other) = delete; ///< Disabled assignment operator.
~UserList() override = default; ///< Destructor ~UserList() override = default; ///< Destructor
void connectGRPCEvents() const; ///< Connects gRPC event to the model. void connectGRPCEvents() const; ///< Connects gRPC event to the model.
int rowCount(QModelIndex const &parent) const override; ///< Return the number of row in 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. QVariant data(QModelIndex const &index, int role) const override; ///< Retrieve model data.
void reset(); ///< Reset the user list. void reset(); ///< Reset the user list.
void reset(QList<SPUser> const &users); ///< Replace the user list. void reset(QList<bridgepp::SPUser> const &users); ///< Replace the user list.
int rowOfUserID(QString const &userID) const; int rowOfUserID(QString const &userID) const;
void removeUserAt(int row); ///< Remove the user at a given row void removeUserAt(int row); ///< Remove the user at a given row
void appendUser(SPUser const& user); ///< Add a new user. void appendUser(bridgepp::SPUser const &user); ///< Add a new user.
void updateUserAtRow(int row, User const& user); ///< Update the user at given row. 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) Q_PROPERTY(int count READ count NOTIFY countChanged)
int count() const; ///< The count property getter. int count() const; ///< The userCount property getter.
signals: signals:
void countChanged(int count); ///< Signal for the count property. void countChanged(int count); ///< Signal for the userCount property.
public: 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 public slots: ///< handler for signals coming from the gRPC service
void onUserChanged(QString const &userID); void onUserChanged(QString const &userID);
void onToggleSplitModeFinished(QString const &userID); void onToggleSplitModeFinished(QString const &userID);
private: // data members private: // data members
QList<SPUser> users_; ///< The user list. QList<bridgepp::SPUser> users_; ///< The user list.
}; };

View File

@ -16,12 +16,14 @@
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>. // along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
#include "Pch.h"
#include "Exception.h"
#include "QMLBackend.h" #include "QMLBackend.h"
#include "Log.h"
#include "BridgeMonitor.h" #include "BridgeMonitor.h"
#include "Version.h" #include "Version.h"
#include <bridgepp/Log/Log.h>
#include <bridgepp/Exception/Exception.h>
using namespace bridgepp;
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
@ -49,7 +51,7 @@ Log &initLog()
Log &log = app().log(); Log &log = app().log();
log.setEchoInConsole(true); log.setEchoInConsole(true);
log.setLevel(Log::Level::Debug); log.setLevel(Log::Level::Debug);
Log::installQtMessageHandler(); log.registerAsQtMessageHandler();
return log; return log;
} }
@ -63,7 +65,7 @@ QQmlComponent *createRootQmlComponent(QQmlApplicationEngine &engine)
qmlRegisterSingletonInstance("Proton", 1, 0, "Backend", &app().backend()); qmlRegisterSingletonInstance("Proton", 1, 0, "Backend", &app().backend());
qmlRegisterType<UserList>("Proton", 1, 0, "UserList"); qmlRegisterType<UserList>("Proton", 1, 0, "UserList");
qmlRegisterType<User>("Proton", 1, 0, "User"); qmlRegisterType<bridgepp::User>("Proton", 1, 0, "User");
auto rootComponent = new QQmlComponent(&engine, &engine); auto rootComponent = new QQmlComponent(&engine, &engine);
@ -138,7 +140,7 @@ void parseArguments(int argc, char **argv, bool &outAttach, QString &outExePath)
void closeBridgeApp() void closeBridgeApp()
{ {
UPOverseer& overseer = app().bridgeOverseer(); 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; return;
app().grpc().quit(); // this will cause the grpc service and the bridge app to close. 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; QMetaObject::Connection connection;
if (bridgeMonitor) if (bridgeMonitor)
connection = QObject::connect(bridgeMonitor, &BridgeMonitor::processExited, [&](int returnCode) { 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 bridgeExited = true;// clazy:exclude=lambda-in-connect
qGuiApp->exit(returnCode); qGuiApp->exit(returnCode);
}); });

View File

@ -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 <https://www.gnu.org/licenses/>.
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)

View File

@ -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 <https://www.gnu.org/licenses/>.
#ifndef BRIDGE_PP_PCH_H
#define BRIDGE_PP_PCH_H
#include <QtCore>
#endif // BRIDGE_PP_PCH_H

View File

@ -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 <https://www.gnu.org/licenses/>.
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")

View File

@ -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 <https://www.gnu.org/licenses/>.
#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

View File

@ -16,19 +16,18 @@
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>. // along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
#ifndef BRIDGE_GUI_GRPCUTILS_H #ifndef BRIDGE_GUI_TESTER_BRIDGE_UTILS_H
#define BRIDGE_GUI_GRPCUTILS_H #define BRIDGE_GUI_TESTER_BRIDGE_UTILS_H
#include "Log.h" namespace bridgepp {
#include "GRPC/bridge.grpc.pb.h"
#include "grpc++/grpc++.h"
#include "User/User.h"
void logGRPCCallStatus(grpc::Status const& status, QString const &callName); ///< Log the status of a gRPC code. QString userConfigDir(); ///< Get the path of the user configuration folder.
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.
#endif // BRIDGE_GUI_GRPCUTILS_H } // namespace
#endif // BRIDGE_GUI_TESTER_BRIDGE_UTILS_H

View File

@ -16,10 +16,13 @@
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>. // along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
#include "Pch.h"
#include "Exception.h" #include "Exception.h"
namespace bridgepp
{
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
/// \param[in] what A description of the exception /// \param[in] what A description of the exception
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
@ -66,3 +69,6 @@ const char* Exception::what() const noexcept
{ {
return what_.toLocal8Bit().constData(); return what_.toLocal8Bit().constData();
} }
} // namespace bridgepp

View File

@ -16,31 +16,38 @@
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>. // along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
#ifndef BRIDGE_GUI_EXCEPTION_H #ifndef BRIDGE_PP_EXCEPTION_H
#define BRIDGE_GUI_EXCEPTION_H #define BRIDGE_PP_EXCEPTION_H
#include <stdexcept> #include <stdexcept>
namespace bridgepp
{
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
/// \brief Exception class. /// \brief Exception class.
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
class Exception: public std::exception class Exception : public std::exception
{ {
public: // member functions public: // member functions
explicit Exception(QString what = QString()) noexcept; ///< Constructor explicit Exception(QString what = QString()) noexcept; ///< Constructor
Exception(Exception const& ref) noexcept; ///< copy constructor Exception(Exception const &ref) noexcept; ///< copy constructor
Exception(Exception&& ref) noexcept; ///< copy constructor Exception(Exception &&ref) noexcept; ///< copy constructor
Exception& operator=(Exception const&) = delete; ///< Disabled assignment operator Exception &operator=(Exception const &) = delete; ///< Disabled assignment operator
Exception& operator=(Exception&&) = delete; ///< Disabled assignment operator Exception &operator=(Exception &&) = delete; ///< Disabled assignment operator
~Exception() noexcept override = default; ///< Destructor ~Exception() noexcept override = default; ///< Destructor
QString const& qwhat() const noexcept; ///< Return the description of the exception as a QString 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 const char *what() const noexcept override; ///< Return the description of the exception as C style string
private: // data members private: // data members
QString const what_; ///< The description of the exception QString const what_; ///< The description of the exception
}; };
#endif //BRIDGE_GUI_EXCEPTION_H } // namespace bridgepp
#endif //BRIDGE_PP_EXCEPTION_H

View File

@ -16,56 +16,32 @@
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>. // along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
#include "Pch.h"
#include "GRPCClient.h" #include "GRPCClient.h"
#include "GRPCUtils.h" #include "GRPCUtils.h"
#include "QMLBackend.h" #include "../Exception/Exception.h"
#include "Exception.h"
#include "AppController.h"
using namespace google::protobuf; using namespace google::protobuf;
using namespace grpc; using namespace grpc;
namespace bridgepp
{
namespace namespace
{ {
Empty empty; // re-used across client calls. 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 maxConnectionTimeSecs = 60; ///< Amount of time after which we consider connection attempts to the server have failed.
int const maxCertificateWaitMsecs = 60 * 1000; ///< Ammount of time we wait for he server to generate the certificate. 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 /// \brief wait for certificate generation by Bridge
@ -73,8 +49,9 @@ static const QString _userConfigDir(){
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
std::string GRPCClient::getServerCertificate() std::string GRPCClient::getServerCertificate()
{ {
const QString filename = _userConfigDir() + "/" + certFile; QString const certPath = serverCertificatePath();
QFile file(filename); QString const certFolder = QFileInfo(certPath).absolutePath();
QFile file(certPath);
// TODO : the certificate can exist but still be invalid. // 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 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. // 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 // wait for file creation
QFileSystemWatcher watcher(this); QFileSystemWatcher watcher(this);
if (!watcher.addPath(_userConfigDir())) if (!watcher.addPath(certFolder))
throw Exception("Failed to watch User Config Directory"); throw Exception("Failed to watch User Config Directory");
connect(&watcher, &QFileSystemWatcher::directoryChanged, this, &GRPCClient::configFolderChanged); connect(&watcher, &QFileSystemWatcher::directoryChanged, this, &GRPCClient::configFolderChanged);
@ -96,7 +73,7 @@ std::string GRPCClient::getServerCertificate()
loop.exec(); loop.exec();
// timeout case. // timeout case.
if(!timer.isActive()) if (!timer.isActive())
throw Exception("Server failed to generate certificate on time"); throw Exception("Server failed to generate certificate on time");
//else certIsReadySignal. //else certIsReadySignal.
} }
@ -109,16 +86,26 @@ std::string GRPCClient::getServerCertificate()
return cert; return cert;
} }
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
/// \brief Action on UserConfig directory changes, looking for the certificate creation /// \brief Action on UserConfig directory changes, looking for the certificate creation
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
void GRPCClient::configFolderChanged() void GRPCClient::configFolderChanged()
{ {
QFile cert(_userConfigDir() + "/" + certFile); if (QFileInfo::exists(serverCertificatePath()))
if (cert.exists())
emit certIsReady(); 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. /// \param[out] outError If the function returns false, this variable contains a description of the error.
/// \return true iff the connection was successful. /// \return true iff the connection was successful.
@ -142,7 +129,8 @@ bool GRPCClient::connectToServer(QString &outError)
int i = 0; int i = 0;
while (true) 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)))) if (channel_->WaitForConnected(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_seconds(5, GPR_TIMESPAN))))
break; // connection established. break; // connection established.
@ -154,9 +142,8 @@ bool GRPCClient::connectToServer(QString &outError)
if (channel_->GetState(true) != GRPC_CHANNEL_READY) if (channel_->GetState(true) != GRPC_CHANNEL_READY)
throw Exception("connection check failed."); throw Exception("connection check failed.");
QMLBackend *backend = &app().backend(); if (log_)
QObject::connect(this, &GRPCClient::loginFreeUserError, backend, &QMLBackend::loginFreeUserError); log_->debug("Successfully connected to gRPC server.");
app().log().debug("Successfully connected to gRPC server.");
return true; return true;
} }
catch (Exception const &e) 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 stub_->AddLogEntry(&ctx, request, &empty);
} }
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
/// \return The status for the gRPC call. /// \return The status for the gRPC call.
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
grpc::Status GRPCClient::guiReady() grpc::Status GRPCClient::guiReady()
{ {
grpc::ClientContext ctx; 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) 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) 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) 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) 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. /// \param[in] enabled The new value for the property.
/// \return The status for the gRPC call. /// \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) 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) 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) 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] address The email address.
/// \param[in] emailClient The email client. /// \param[in] emailClient The email client.
/// \param[in] includeLogs Should the report include the logs. /// \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) 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_address(address.toStdString());
request.set_emailclient(emailClient.toStdString()); request.set_emailclient(emailClient.toStdString());
request.set_includelogs(includeLogs); 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) 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) 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) 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) 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; ChangePortsRequest request;
request.set_imapport(portIMAP); request.set_imapport(portIMAP);
request.set_smtpport(portSMTP); 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) 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) 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::Status GRPCClient::quit()
{ {
grpc::ClientContext ctx; 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::Status GRPCClient::restart()
{ {
grpc::ClientContext ctx; 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. /// \return The status for the gRPC call.
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
grpc::Status GRPCClient::triggerReset() grpc::Status GRPCClient::triggerReset()
{ {
grpc::ClientContext ctx; 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); Status result = stub_->IsPortFree(&ctx, p, &isFree);
if (result.ok()) if (result.ok())
outFree = isFree.value(); 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) 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) 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) 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) 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) 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) 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) 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. /// \param[out] outUrl The value for the property.
/// \return The status for the gRPC call. /// \return The status for the gRPC call.
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
grpc::Status GRPCClient::releaseNotesPageLink(QUrl &outUrl) 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. /// \param[out] outUrl The value for the property.
/// \return The status for the gRPC call. /// \return The status for the gRPC call.
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
grpc::Status GRPCClient::landingPageLink(QUrl &outUrl) 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. /// \param[out] outHostname The value for the property.
/// \return The status for the gRPC call. /// \return The status for the gRPC call.
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
grpc::Status GRPCClient::hostname(QString &outHostname) 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) 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) 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; ChangeLocalCacheRequest request;
request.set_enablediskcache(enabled); request.set_enablediskcache(enabled);
request.set_diskcachepath(path.path(QUrl::FullyDecoded).toStdString()); 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; LoginRequest request;
request.set_username(username.toStdString()); request.set_username(username.toStdString());
request.set_password(password.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; LoginRequest request;
request.set_username(username.toStdString()); request.set_username(username.toStdString());
request.set_password(code.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; LoginRequest request;
request.set_username(username.toStdString()); request.set_username(username.toStdString());
request.set_password(password.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; grpc::ClientContext ctx;
LoginAbortRequest request; LoginAbortRequest request;
request.set_username(username.toStdString()); 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() 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() 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) 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) 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) 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) 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; ConfigureAppleMailRequest request;
request.set_userid(userID.toStdString()); request.set_userid(userID.toStdString());
request.set_address(address.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_userid(userID.toStdString());
request.set_active(active); 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<SPUser> &outUsers)
UserListResponse response; UserListResponse response;
Status status = stub_->GetUserList(&ctx, empty, &response); Status status = stub_->GetUserList(&ctx, empty, &response);
if (!status.ok()) if (!status.ok())
return status; return this->logGRPCCallStatus(status, __FUNCTION__);
for (int i = 0; i < response.users_size(); ++i) 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<SPUser> &outUsers)
/// \param[out] outUser The user. /// \param[out] outUser The user.
/// \return The status code for the operation. /// \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; ClientContext ctx;
StringValue s; StringValue s;
@ -728,9 +720,9 @@ grpc::Status GRPCClient::getUser(QString const &userID, ::SPUser &outUser)
Status status = stub_->GetUser(&ctx, s, &grpcUser); Status status = stub_->GetUser(&ctx, s, &grpcUser);
if (status.ok()) 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; AvailableKeychainsResponse response;
Status status = stub_->AvailableKeychains(&ctx, empty, &response); Status status = stub_->AvailableKeychains(&ctx, empty, &response);
if (!status.ok()) if (!status.ok())
return status; return this->logGRPCCallStatus(status, __FUNCTION__);
for (int i = 0; i < response.keychains_size(); ++i) for (int i = 0; i < response.keychains_size(); ++i)
outKeychains.append(QString::fromStdString(response.keychains(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) 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) 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()); this->processUserEvent(event.user());
break; break;
default: 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::Status GRPCClient::stopEventStream()
{ {
grpc::ClientContext ctx; 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. /// \param[in] event The event.
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
@ -985,35 +1033,35 @@ void GRPCClient::processAppEvent(AppEvent const &event)
switch (event.event_case()) switch (event.event_case())
{ {
case AppEvent::kInternetStatus: case AppEvent::kInternetStatus:
app().log().debug("App event received: InternetStatus."); this->logDebug("App event received: InternetStatus.");
emit internetStatus(event.internetstatus().connected()); emit internetStatus(event.internetstatus().connected());
break; break;
case AppEvent::kToggleAutostartFinished: case AppEvent::kToggleAutostartFinished:
app().log().debug("App event received: AutostartFinished."); this->logDebug("App event received: AutostartFinished.");
emit toggleAutostartFinished(); emit toggleAutostartFinished();
break; break;
case AppEvent::kResetFinished: case AppEvent::kResetFinished:
app().log().debug("App event received: ResetFinished."); this->logDebug("App event received: ResetFinished.");
emit resetFinished(); emit resetFinished();
break; break;
case AppEvent::kReportBugFinished: case AppEvent::kReportBugFinished:
app().log().debug("App event received: ReportBugFinished."); this->logDebug("App event received: ReportBugFinished.");
emit reportBugFinished(); emit reportBugFinished();
break; break;
case AppEvent::kReportBugSuccess: case AppEvent::kReportBugSuccess:
app().log().debug("App event received: ReportBugSuccess."); this->logDebug("App event received: ReportBugSuccess.");
emit reportBugSuccess(); emit reportBugSuccess();
break; break;
case AppEvent::kReportBugError: case AppEvent::kReportBugError:
app().log().debug("App event received: ReportBugError."); this->logDebug("App event received: ReportBugError.");
emit reportBugError(); emit reportBugError();
break; break;
case AppEvent::kShowMainWindow: case AppEvent::kShowMainWindow:
app().log().debug("App event received: ShowMainWindow."); this->logDebug("App event received: ShowMainWindow.");
emit showMainWindow(); emit showMainWindow();
break; break;
default: 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: case LoginEvent::kError:
{ {
app().log().debug("Login event received: Error."); this->logDebug("Login event received: Error.");
LoginErrorEvent const &error = event.error(); LoginErrorEvent const &error = event.error();
switch (error.type()) switch (error.type())
{ {
@ -1053,29 +1101,29 @@ void GRPCClient::processLoginEvent(LoginEvent const &event)
emit login2PasswordErrorAbort(QString::fromStdString(error.message())); emit login2PasswordErrorAbort(QString::fromStdString(error.message()));
break; break;
default: default:
app().log().debug("Unknown login error event received."); this->logError("Unknown login error event received.");
break; break;
} }
break; break;
} }
case LoginEvent::kTfaRequested: case LoginEvent::kTfaRequested:
app().log().debug("Login event received: TfaRequested."); this->logDebug("Login event received: TfaRequested.");
emit login2FARequested(QString::fromStdString(event.tfarequested().username())); emit login2FARequested(QString::fromStdString(event.tfarequested().username()));
break; break;
case LoginEvent::kTwoPasswordRequested: case LoginEvent::kTwoPasswordRequested:
app().log().debug("Login event received: TwoPasswordRequested."); this->logDebug("Login event received: TwoPasswordRequested.");
emit login2PasswordRequested(); emit login2PasswordRequested();
break; break;
case LoginEvent::kFinished: case LoginEvent::kFinished:
app().log().debug("Login event received: Finished."); this->logDebug("Login event received: Finished.");
emit loginFinished(QString::fromStdString(event.finished().userid())); emit loginFinished(QString::fromStdString(event.finished().userid()));
break; break;
case LoginEvent::kAlreadyLoggedIn: case LoginEvent::kAlreadyLoggedIn:
app().log().debug("Login event received: AlreadyLoggedIn."); this->logDebug("Login event received: AlreadyLoggedIn.");
emit loginAlreadyLoggedIn(QString::fromStdString(event.finished().userid())); emit loginAlreadyLoggedIn(QString::fromStdString(event.finished().userid()));
break; break;
default: default:
app().log().error("Unknown Login event received."); this->logError("Unknown Login event received.");
break; break;
} }
} }
@ -1090,7 +1138,7 @@ void GRPCClient::processUpdateEvent(UpdateEvent const &event)
{ {
case UpdateEvent::kError: case UpdateEvent::kError:
{ {
app().log().debug("Update event received: Error."); this->logDebug("Update event received: Error.");
UpdateErrorEvent const &errorEvent = event.error(); UpdateErrorEvent const &errorEvent = event.error();
switch (errorEvent.type()) switch (errorEvent.type())
@ -1105,37 +1153,37 @@ void GRPCClient::processUpdateEvent(UpdateEvent const &event)
emit updateSilentError(); emit updateSilentError();
break; break;
default: default:
app().log().error("Unknown update error received."); this->logError("Unknown update error received.");
break; break;
} }
break; break;
} }
case UpdateEvent::kManualReady: case UpdateEvent::kManualReady:
app().log().debug("Update event received: ManualReady."); this->logDebug("Update event received: ManualReady.");
emit updateManualReady(QString::fromStdString(event.manualready().version())); emit updateManualReady(QString::fromStdString(event.manualready().version()));
break; break;
case UpdateEvent::kManualRestartNeeded: case UpdateEvent::kManualRestartNeeded:
app().log().debug("Update event received: kManualRestartNeeded."); this->logDebug("Update event received: kManualRestartNeeded.");
emit updateManualRestartNeeded(); emit updateManualRestartNeeded();
break; break;
case UpdateEvent::kForce: case UpdateEvent::kForce:
app().log().debug("Update event received: kForce."); this->logDebug("Update event received: kForce.");
emit updateForce(QString::fromStdString(event.force().version())); emit updateForce(QString::fromStdString(event.force().version()));
break; break;
case UpdateEvent::kSilentRestartNeeded: case UpdateEvent::kSilentRestartNeeded:
app().log().debug("Update event received: kSilentRestartNeeded."); this->logDebug("Update event received: kSilentRestartNeeded.");
emit updateSilentRestartNeeded(); emit updateSilentRestartNeeded();
break; break;
case UpdateEvent::kIsLatestVersion: case UpdateEvent::kIsLatestVersion:
app().log().debug("Update event received: kIsLatestVersion."); this->logDebug("Update event received: kIsLatestVersion.");
emit updateIsLatestVersion(); emit updateIsLatestVersion();
break; break;
case UpdateEvent::kCheckFinished: case UpdateEvent::kCheckFinished:
app().log().debug("Update event received: kCheckFinished."); this->logDebug("Update event received: kCheckFinished.");
emit checkUpdatesFinished(); emit checkUpdatesFinished();
break; break;
default: default:
app().log().error("Unknown Update event received."); this->logError("Unknown Update event received.");
break; break;
} }
} }
@ -1162,34 +1210,34 @@ void GRPCClient::processCacheEvent(CacheEvent const &event)
emit diskFull(); emit diskFull();
break; break;
default: default:
app().log().error("Unknown cache error event received."); this->logError("Unknown cache error event received.");
break; break;
} }
break; break;
} }
case CacheEvent::kLocationChangedSuccess: case CacheEvent::kLocationChangedSuccess:
app().log().debug("Cache event received: LocationChangedSuccess."); this->logDebug("Cache event received: LocationChangedSuccess.");
emit cacheLocationChangeSuccess(); emit cacheLocationChangeSuccess();
break; break;
case CacheEvent::kChangeLocalCacheFinished: case CacheEvent::kChangeLocalCacheFinished:
emit cacheLocationChangeSuccess(); emit cacheLocationChangeSuccess();
app().log().debug("Cache event received: ChangeLocalCacheFinished."); this->logDebug("Cache event received: ChangeLocalCacheFinished.");
break; break;
case CacheEvent::kIsCacheOnDiskEnabledChanged: case CacheEvent::kIsCacheOnDiskEnabledChanged:
app().log().debug("Cache event received: IsCacheOnDiskEnabledChanged."); this->logDebug("Cache event received: IsCacheOnDiskEnabledChanged.");
emit isCacheOnDiskEnabledChanged(event.iscacheondiskenabledchanged().enabled()); emit isCacheOnDiskEnabledChanged(event.iscacheondiskenabledchanged().enabled());
break; break;
case CacheEvent::kDiskCachePathChanged: 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()))); emit diskCachePathChanged(QUrl::fromLocalFile(QString::fromStdString(event.diskcachepathchanged().path())));
break; break;
default: 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()) switch (event.event_case())
{ {
case MailSettingsEvent::kError: case MailSettingsEvent::kError:
app().log().debug("MailSettings event received: Error."); this->logDebug("MailSettings event received: Error.");
switch (event.error().type()) switch (event.error().type())
{ {
case IMAP_PORT_ISSUE: case IMAP_PORT_ISSUE:
@ -1212,20 +1260,20 @@ void GRPCClient::processMailSettingsEvent(MailSettingsEvent const &event)
emit portIssueSMTP(); emit portIssueSMTP();
break; break;
default: default:
app().log().error("Unknown mail settings error event received."); this->logError("Unknown mail settings error event received.");
break; break;
} }
case MailSettingsEvent::kUseSslForSmtpFinished: case MailSettingsEvent::kUseSslForSmtpFinished:
app().log().debug("MailSettings event received: UseSslForSmtpFinished."); this->logDebug("MailSettings event received: UseSslForSmtpFinished.");
emit toggleUseSSLFinished(); emit toggleUseSSLFinished();
break; break;
case MailSettingsEvent::kChangePortsFinished: case MailSettingsEvent::kChangePortsFinished:
app().log().debug("MailSettings event received: ChangePortsFinished."); this->logDebug("MailSettings event received: ChangePortsFinished.");
emit changePortFinished(); emit changePortFinished();
break; break;
default: 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()) switch (event.event_case())
{ {
case KeychainEvent::kChangeKeychainFinished: case KeychainEvent::kChangeKeychainFinished:
app().log().debug("Keychain event received: ChangeKeychainFinished."); this->logDebug("Keychain event received: ChangeKeychainFinished.");
emit changeKeychainFinished(); emit changeKeychainFinished();
break; break;
case KeychainEvent::kHasNoKeychain: case KeychainEvent::kHasNoKeychain:
app().log().debug("Keychain event received: HasNoKeychain."); this->logDebug("Keychain event received: HasNoKeychain.");
emit hasNoKeychain(); emit hasNoKeychain();
break; break;
case KeychainEvent::kRebuildKeychain: case KeychainEvent::kRebuildKeychain:
app().log().debug("Keychain event received: RebuildKeychain."); this->logDebug("Keychain event received: RebuildKeychain.");
emit rebuildKeychain(); emit rebuildKeychain();
break; break;
default: 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()) switch (event.event_case())
{ {
case MailEvent::kNoActiveKeyForRecipientEvent: case MailEvent::kNoActiveKeyForRecipientEvent:
app().log().debug("Mail event received: kNoActiveKeyForRecipientEvent."); this->logDebug("Mail event received: kNoActiveKeyForRecipientEvent.");
emit noActiveKeyForRecipient(QString::fromStdString(event.noactivekeyforrecipientevent().email())); emit noActiveKeyForRecipient(QString::fromStdString(event.noactivekeyforrecipientevent().email()));
break; break;
case MailEvent::kAddressChanged: case MailEvent::kAddressChanged:
app().log().debug("Mail event received: AddressChanged."); this->logDebug("Mail event received: AddressChanged.");
emit addressChanged(QString::fromStdString(event.addresschanged().address())); emit addressChanged(QString::fromStdString(event.addresschanged().address()));
break; break;
case MailEvent::kAddressChangedLogout: case MailEvent::kAddressChangedLogout:
app().log().debug("Mail event received: AddressChangedLogout."); this->logDebug("Mail event received: AddressChangedLogout.");
emit addressChangedLogout(QString::fromStdString(event.addresschangedlogout().address())); emit addressChangedLogout(QString::fromStdString(event.addresschangedlogout().address()));
break; break;
case MailEvent::kApiCertIssue: case MailEvent::kApiCertIssue:
emit apiCertIssue(); emit apiCertIssue();
app().log().debug("Mail event received: ApiCertIssue."); this->logDebug("Mail event received: ApiCertIssue.");
break; break;
default: 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: case UserEvent::kToggleSplitModeFinished:
{ {
QString const userID = QString::fromStdString(event.togglesplitmodefinished().userid()); 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); emit toggleSplitModeFinished(userID);
break; break;
} }
case UserEvent::kUserDisconnected: case UserEvent::kUserDisconnected:
{ {
QString const username = QString::fromStdString(event.userdisconnected().username()); 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); emit userDisconnected(username);
break; break;
} }
case UserEvent::kUserChanged: case UserEvent::kUserChanged:
{ {
QString const userID = QString::fromStdString(event.userchanged().userid()); 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); emit userChanged(userID);
break; break;
} }
default: default:
app().log().error("Unknown User event received."); this->logError("Unknown User event received.");
} }
} }
} // namespace bridgepp

View File

@ -20,44 +20,49 @@
#define BRIDGE_GUI_RPC_CLIENT_H #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 "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*); namespace bridgepp
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::*SimpleMethod)(grpc::ClientContext *, const google::protobuf::Empty &, google::protobuf::Empty *);
typedef grpc::Status (grpc::Bridge::Stub::*StringGetter)(grpc::ClientContext*, const google::protobuf::Empty&, google::protobuf::StringValue*); typedef grpc::Status (grpc::Bridge::Stub::*BoolSetter)(grpc::ClientContext *, const google::protobuf::BoolValue &, google::protobuf::Empty *);
typedef grpc::Status (grpc::Bridge::Stub::*StringSetter)(grpc::ClientContext*, const google::protobuf::StringValue&, 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::*StringParamMethod)(grpc::ClientContext*, const google::protobuf::StringValue&, google::protobuf::Empty*); 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. /// \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. public: // member functions.
GRPCClient() = default; ///< Default constructor. GRPCClient() = default; ///< Default constructor.
GRPCClient(GRPCClient const&) = delete; ///< Disabled copy-constructor. GRPCClient(GRPCClient const &) = delete; ///< Disabled copy-constructor.
GRPCClient(GRPCClient&&) = delete; ///< Disabled assignment copy-constructor. GRPCClient(GRPCClient &&) = delete; ///< Disabled assignment copy-constructor.
~GRPCClient() override = default; ///< Destructor. ~GRPCClient() override = default; ///< Destructor.
GRPCClient& operator=(GRPCClient const&) = delete; ///< Disabled assignment operator. GRPCClient &operator=(GRPCClient const &) = delete; ///< Disabled assignment operator.
GRPCClient& operator=(GRPCClient&&) = delete; ///< Disabled move 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. 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 guiReady(); ///< performs the "GuiReady" gRPC call.
grpc::Status isFirstGUIStart(bool &outIsFirst); ///< performs the "IsFirstGUIStart" gRPC call. grpc::Status isFirstGUIStart(bool &outIsFirst); ///< performs the "IsFirstGUIStart" gRPC call.
grpc::Status isAutostartOn(bool &outIsOn); ///< Performs the "isAutostartOn" gRPC call. grpc::Status isAutostartOn(bool &outIsOn); ///< Performs the "isAutostartOn" gRPC call.
grpc::Status setIsAutostartOn(bool on); ///< Performs the "setIsAutostartOn" gRPC call. grpc::Status setIsAutostartOn(bool on); ///< Performs the "setIsAutostartOn" gRPC call.
grpc::Status isBetaEnabled(bool &outEnabled); ///< Performs the "isBetaEnabled" 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 colorSchemeName(QString &outName); ///< Performs the "colorSchemeName' gRPC call.
grpc::Status setColorSchemeName(QString const &name); ///< Performs the "setColorSchemeName' gRPC call. grpc::Status setColorSchemeName(QString const &name); ///< Performs the "setColorSchemeName' gRPC call.
grpc::Status currentEmailClient(QString &outName); ///< Performs the 'currentEmailClient' 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. grpc::Status changeLocalCache(bool enabled, QUrl const &path); ///< Performs the 'ChangeLocalCache' call.
signals: signals:
void isCacheOnDiskEnabledChanged(bool enabled); void isCacheOnDiskEnabledChanged(bool enabled);
void diskCachePathChanged(QUrl const&outPath); void diskCachePathChanged(QUrl const &outPath);
void cacheUnavailable(); // _ func() `signal:"cacheUnavailable"` void cacheUnavailable(); // _ func() `signal:"cacheUnavailable"`
void cacheCantMove(); // _ func() `signal:"cacheCantMove"` void cacheCantMove(); // _ func() `signal:"cacheCantMove"`
void cacheLocationChangeSuccess(); // _ func() `signal:"cacheLocationChangeSuccess"` void cacheLocationChangeSuccess(); // _ func() `signal:"cacheLocationChangeSuccess"`
@ -118,9 +123,9 @@ signals:
void changePortFinished(); void changePortFinished();
public: // login related calls public: // login related calls
grpc::Status login(QString const &username, QString const& password); ///< Performs the 'login' 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 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 login2Passwords(QString const &username, QString const &password); ///< Performs the 'login2Passwords' call.
grpc::Status loginAbort(QString const &username); ///< Performs the 'loginAbort' call. grpc::Status loginAbort(QString const &username); ///< Performs the 'loginAbort' call.
signals: signals:
@ -128,13 +133,13 @@ signals:
void loginFreeUserError(); // _ func() `signal:"loginFreeUserError"` void loginFreeUserError(); // _ func() `signal:"loginFreeUserError"`
void loginConnectionError(QString const &errMsg); // _ func(errorMsg string) `signal:"loginConnectionError"` void loginConnectionError(QString const &errMsg); // _ func(errorMsg string) `signal:"loginConnectionError"`
void login2FARequested(QString const &userName); // _ func(username string) `signal:"login2FARequested"` void login2FARequested(QString const &userName); // _ func(username string) `signal:"login2FARequested"`
void login2FAError(QString const& errMsg); // _ func(errorMsg string) `signal:"login2FAError"` void login2FAError(QString const &errMsg); // _ func(errorMsg string) `signal:"login2FAError"`
void login2FAErrorAbort(QString const& errMsg); // _ func(errorMsg string) `signal:"login2FAErrorAbort"` void login2FAErrorAbort(QString const &errMsg); // _ func(errorMsg string) `signal:"login2FAErrorAbort"`
void login2PasswordRequested(); // _ func() `signal:"login2PasswordRequested"` void login2PasswordRequested(); // _ func() `signal:"login2PasswordRequested"`
void login2PasswordError(QString const& errMsg); // _ func(errorMsg string) `signal:"login2PasswordError"` void login2PasswordError(QString const &errMsg); // _ func(errorMsg string) `signal:"login2PasswordError"`
void login2PasswordErrorAbort(QString const& errMsg); // _ func(errorMsg string) `signal:"login2PasswordErrorAbort"` void login2PasswordErrorAbort(QString const &errMsg); // _ func(errorMsg string) `signal:"login2PasswordErrorAbort"`
void loginFinished(QString const &userID); // _ func(index int) `signal:"loginFinished"` void loginFinished(QString const &userID); // _ func(index int) `signal:"loginFinished"`
void loginAlreadyLoggedIn(QString const &userID); // _ func(index int) `signal:"loginAlreadyLoggedIn"` void loginAlreadyLoggedIn(QString const &userID); // _ func(index int) `signal:"loginAlreadyLoggedIn"`
public: // Update related calls public: // Update related calls
grpc::Status checkUpdate(); grpc::Status checkUpdate();
@ -154,17 +159,17 @@ signals:
void checkUpdatesFinished(); void checkUpdatesFinished();
public: // user related calls public: // user related calls
grpc::Status getUserList(QList<SPUser>& outUsers); grpc::Status getUserList(QList<SPUser> &outUsers);
grpc::Status getUser(QString const &userID, SPUser& outUser); grpc::Status getUser(QString const &userID, SPUser &outUser);
grpc::Status logoutUser(QString const &userID); ///< Performs the 'logoutUser' call. grpc::Status logoutUser(QString const &userID); ///< Performs the 'logoutUser' call.
grpc::Status removeUser(QString const &userID); ///< Performs the 'removeUser' 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 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 setUserSplitMode(QString const &userID, bool active); ///< Performs the 'SetUserSplitMode' call.
signals: signals:
void toggleSplitModeFinished(QString const& userID); void toggleSplitModeFinished(QString const &userID);
void userDisconnected(QString const& username); void userDisconnected(QString const &username);
void userChanged(QString const& userID); void userChanged(QString const &userID);
public: // keychain related calls public: // keychain related calls
@ -178,7 +183,7 @@ signals:
void rebuildKeychain(); void rebuildKeychain();
void certIsReady(); void certIsReady();
signals: // mail releated events signals: // mail related events
void noActiveKeyForRecipient(QString const &email); // _ func(email string) `signal:noActiveKeyForRecipient` void noActiveKeyForRecipient(QString const &email); // _ func(email string) `signal:noActiveKeyForRecipient`
void addressChanged(QString const &address); // _ func(address string) `signal:addressChanged` void addressChanged(QString const &address); // _ func(address string) `signal:addressChanged`
void addressChangedLogout(QString const &address); // _ func(address string) `signal:addressChangedLogout` void addressChangedLogout(QString const &address); // _ func(address string) `signal:addressChangedLogout`
@ -192,16 +197,20 @@ private slots:
void configFolderChanged(); void configFolderChanged();
private: 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 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 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 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 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 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 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 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 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 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. std::string getServerCertificate(); ///< Wait until server certificates is generated and retrieve it.
void processAppEvent(grpc::AppEvent const &event); ///< Process an 'App' event. 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. void processUserEvent(grpc::UserEvent const &event); ///< Process a 'User' event.
private: // data members. private: // data members.
Log *log_ { nullptr }; ///< The log for the GRPC client.
std::shared_ptr<grpc::Channel> channel_ { nullptr }; ///< The gRPC channel. std::shared_ptr<grpc::Channel> channel_ { nullptr }; ///< The gRPC channel.
std::shared_ptr<grpc::Bridge::Stub> stub_ { nullptr }; ///< The gRPC stub (a.k.a. client). std::shared_ptr<grpc::Bridge::Stub> stub_ { nullptr }; ///< The gRPC stub (a.k.a. client).
}; };
}
#endif // BRIDGE_GUI_RPC_CLIENT_H #endif // BRIDGE_GUI_RPC_CLIENT_H

View File

@ -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 <https://www.gnu.org/licenses/>.
#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

View File

@ -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 <https://www.gnu.org/licenses/>.
#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

View File

@ -16,13 +16,38 @@
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>. // along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
#include "Pch.h"
#include "Log.h" #include "Log.h"
namespace bridgepp
{
namespace 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. /// \param[in] type The message type.
@ -30,25 +55,27 @@ namespace
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
void qtMessageHandler(QtMsgType type, QMessageLogContext const &, QString const &message) void qtMessageHandler(QtMsgType type, QMessageLogContext const &, QString const &message)
{ {
static Log &log = app().log(); Log *log = qtMessageHandlerLog();
if (!log)
return;
switch (type) switch (type)
{ {
case QtDebugMsg: case QtDebugMsg:
log.debug(message); log->debug(message);
break; break;
case QtWarningMsg: case QtWarningMsg:
log.warn(message); log->warn(message);
break; break;
case QtCriticalMsg: case QtCriticalMsg:
case QtFatalMsg: case QtFatalMsg:
log.error(message); log->error(message);
break; break;
case QtInfoMsg: case QtInfoMsg:
default: default:
log.info(message); log->info(message);
break; break;
} }
} }
@ -62,18 +89,28 @@ QString logLevelToString(Log::Level level)
{ {
switch (level) switch (level)
{ {
case Log::Level::Panic: return "PANIC"; case Log::Level::Panic:
case Log::Level::Fatal: return "FATAL"; return "PANIC";
case Log::Level::Error: return "ERROR"; case Log::Level::Fatal:
case Log::Level::Warn: return "WARN"; return "FATAL";
case Log::Level::Info: return "INFO"; case Log::Level::Error:
case Log::Level::Debug: return "DEBUG"; return "ERROR";
case Log::Level::Trace: return "TRACE"; case Log::Level::Warn:
default: return "UNKNOWN"; 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 /// \brief return a string representing the log entry
@ -82,20 +119,18 @@ QString logLevelToString(Log::Level level)
/// \param[in] message The log entry message. /// \param[in] message The log entry message.
/// \return The string for the log entry /// \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. /// the message handle process the message from the Qt logging system.
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
void Log::installQtMessageHandler() void Log::registerAsQtMessageHandler()
{ {
setQtMessageHandlerLog(this);
qInstallMessageHandler(qtMessageHandler); qInstallMessageHandler(qtMessageHandler);
} }
@ -227,8 +262,11 @@ void Log::addEntry(Log::Level level, QString const &message)
if (echoInConsole_) 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 << logEntryToString(level, message) << "\n";
stream.flush(); stream.flush();
} }
} }
} // namespace bridgepp

View File

@ -16,8 +16,12 @@
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>. // along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
#ifndef BRIDGE_GUI_LOG_H #ifndef BRIDGE_PP_LOG_H
#define BRIDGE_GUI_LOG_H #define BRIDGE_PP_LOG_H
namespace bridgepp
{
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
@ -25,9 +29,9 @@
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
class Log : public QObject class Log : public QObject
{ {
Q_OBJECT Q_OBJECT
public: // data types. 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 enum class Level
{ {
Panic, ///< Panic log level. Panic, ///< Panic log level.
@ -39,8 +43,9 @@ public: // data types.
Trace ///< Trace log level. Trace ///< Trace log level.
}; };
public: // static member functions public: // static member functions.
static void installQtMessageHandler(); ///< Install the Qt message handler. static QString logEntryToString(Log::Level level, QString const &message); ///< Return a string describing a log entry.
public: // member functions. public: // member functions.
Log(); ///< Default constructor. Log(); ///< Default constructor.
@ -54,6 +59,7 @@ public: // member functions.
Level level() const; ///< Get the log level. Level level() const; ///< Get the log level.
void setEchoInConsole(bool value); ///< Set if the log entries should be echoed in STDOUT/STDERR. 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. bool echoInConsole() const; ///< Check if the log entries should be echoed in STDOUT/STDERR.
void registerAsQtMessageHandler(); ///< Install the Qt message handler.
public slots: public slots:
void panic(QString const &message); ///< Adds an panic entry to the log. 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

View File

@ -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 <https://www.gnu.org/licenses/>.
#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

View File

@ -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 <https://www.gnu.org/licenses/>.
#ifndef BRIDGE_GUI_USER_H
#define BRIDGE_GUI_USER_H
namespace bridgepp
{
typedef std::shared_ptr<class User> 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

View File

@ -16,9 +16,12 @@
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>. // along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
#include "Pch.h"
#include "Overseer.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_); worker_->moveToThread(thread_);
connect(thread_, &QThread::started, worker_, &Worker::run); 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(); }); connect(worker_, &Worker::error, [&]() { thread_->quit(); });
if (autorelease) if (autorelease)
@ -112,3 +115,6 @@ Worker *Overseer::worker() const
{ {
return worker_; return worker_;
} }
} // namespace bridgepp

View File

@ -16,26 +16,30 @@
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>. // along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
#ifndef BRIDGE_GUI_OVERSEER_H #ifndef BRIDGE_PP_OVERSEER_H
#define BRIDGE_GUI_OVERSEER_H #define BRIDGE_PP_OVERSEER_H
#include "Worker.h" #include "Worker.h"
namespace bridgepp
{
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
/// \brief Overseer used to manager a worker instance and its associated thread. /// \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. public: // member functions.
explicit Overseer(Worker* worker, QObject* parent); ///< Default constructor. explicit Overseer(Worker *worker, QObject *parent); ///< Default constructor.
Overseer(Overseer const&) = delete; ///< Disabled copy-constructor. Overseer(Overseer const &) = delete; ///< Disabled copy-constructor.
Overseer(Overseer&&) = delete; ///< Disabled assignment copy-constructor. Overseer(Overseer &&) = delete; ///< Disabled assignment copy-constructor.
~Overseer() override; ///< Destructor. ~Overseer() override; ///< Destructor.
Overseer& operator=(Overseer const&) = delete; ///< Disabled assignment operator. Overseer &operator=(Overseer const &) = delete; ///< Disabled assignment operator.
Overseer& operator=(Overseer&&) = delete; ///< Disabled move assignment operator. Overseer &operator=(Overseer &&) = delete; ///< Disabled move assignment operator.
bool isFinished() const; ///< Check if the worker is finished. bool isFinished() const; ///< Check if the worker is finished.
Worker *worker() const; ///< Return worker. Worker *worker() const; ///< Return worker.
@ -44,8 +48,8 @@ public slots:
void release(); ///< Delete the worker and its thread. void release(); ///< Delete the worker and its thread.
public: // data members. public: // data members.
QThread *thread_ { nullptr }; ///< The thread. QThread *thread_{nullptr}; ///< The thread.
Worker *worker_ { nullptr }; ///< The worker. Worker *worker_{nullptr}; ///< The worker.
}; };
@ -53,4 +57,7 @@ typedef std::unique_ptr<Overseer> UPOverseer; ///< Type definition for unique po
typedef std::shared_ptr<Overseer> SPOverseer; ///< Type definition for shared pointer to Overseer. typedef std::shared_ptr<Overseer> SPOverseer; ///< Type definition for shared pointer to Overseer.
#endif //BRIDGE_GUI_OVERSEER_H } // namespace bridgepp
#endif //BRIDGE_PP_OVERSEER_H

View File

@ -16,22 +16,29 @@
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>. // along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
#ifndef BRIDGE_GUI_WORKER_H #ifndef BRIDGE_PP_WORKER_H
#define BRIDGE_GUI_WORKER_H #define BRIDGE_PP_WORKER_H
namespace bridgepp
{
//**************************************************************************************************************************************************** //****************************************************************************************************************************************************
/// \brief Pure virtual class for worker intended to perform a threaded operation. /// \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 public: // member functions
explicit Worker(QObject *parent) : QObject(parent) {} ///< Default constructor. explicit Worker(QObject *parent)
Worker(Worker const&) = delete; ///< Disabled copy-constructor. : QObject(parent)
Worker(Worker&&) = delete; ///< Disabled assignment copy-constructor. {} ///< Default constructor.
Worker(Worker const &) = delete; ///< Disabled copy-constructor.
Worker(Worker &&) = delete; ///< Disabled assignment copy-constructor.
~Worker() override = default; ///< Destructor. ~Worker() override = default; ///< Destructor.
Worker& operator=(Worker const&) = delete; ///< Disabled assignment operator. Worker &operator=(Worker const &) = delete; ///< Disabled assignment operator.
Worker& operator=(Worker&&) = delete; ///< Disabled move assignment operator. Worker &operator=(Worker &&) = delete; ///< Disabled move assignment operator.
public slots: public slots:
virtual void run() = 0; ///< run the worker. virtual void run() = 0; ///< run the worker.
@ -39,8 +46,11 @@ public slots:
signals: signals:
void started(); ///< Signal for the start of the worker void started(); ///< Signal for the start of the worker
void finished(); ///< Signal for the end 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

View File

@ -19,6 +19,7 @@
YEAR=`date +%Y` YEAR=`date +%Y`
MISSING_FILES=$(find . \ MISSING_FILES=$(find . \
-not -path "./extern/*" \
-not -path "./vendor/*" \ -not -path "./vendor/*" \
-not -path "./vendor-cache/*" \ -not -path "./vendor-cache/*" \
-not -path "./.cache/*" \ -not -path "./.cache/*" \