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/>.
#include "Pch.h"
#include "AppController.h"
#include "QMLBackend.h"
#include "GRPC/GRPCClient.h"
#include "Log.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>())
, log_(std::make_unique<Log>())
{
}

View File

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

View File

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

View File

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

View File

@ -17,41 +17,16 @@
cmake_minimum_required(VERSION 3.22)
# We rely on vcpkg for to get gRPC / Protobuf
# run build.sh / build.ps1 to get gRPC / Protobuf and dependencies installed.
include_guard()
set(VCPKG_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../../../extern/vcpkg")
message(STATUS "VCPKG_ROOT is ${VCPKG_ROOT}")
if (WIN32)
find_program(VCPKG_EXE "${VCPKG_ROOT}/vcpkg.exe")
else()
find_program(VCPKG_EXE "${VCPKG_ROOT}/vcpkg")
endif()
include(../bridgepp/bridge_setup.cmake)
# For now we support only a single architecture for macOS (ARM64 or x86_64). We need to investigate how to build universal binaries with vcpkg.
if (APPLE)
if (NOT DEFINED CMAKE_OSX_ARCHITECTURES)
execute_process(COMMAND "uname" "-m" OUTPUT_VARIABLE UNAME_RESULT OUTPUT_STRIP_TRAILING_WHITESPACE)
set(CMAKE_OSX_ARCHITECTURES ${UNAME_RESULT} CACHE STRING "osx_architectures")
endif()
#*****************************************************************************************************************************************************
# Project
#*****************************************************************************************************************************************************
if (CMAKE_OSX_ARCHITECTURES STREQUAL "arm64")
message(STATUS "Building for Apple Silicon Mac computers")
set(VCPKG_TARGET_TRIPLET arm64-osx)
elseif (CMAKE_OSX_ARCHITECTURES STREQUAL "x86_64")
message(STATUS "Building for Intel based Mac computers")
set(VCPKG_TARGET_TRIPLET x64-osx)
else ()
message(FATAL_ERROR "Unknown value for CMAKE_OSX_ARCHITECTURE. Please use one of \"arm64\" and \"x86_64\". Multiple architectures are not supported.")
endif ()
endif()
if (WIN32)
message(STATUS "Building for Intel x64 Windows computers")
set(VCPKG_TARGET_TRIPLET x64-windows)
endif()
set(CMAKE_TOOLCHAIN_FILE "${VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" CACHE STRING "toolchain")
project(bridge-gui LANGUAGES CXX)
@ -61,116 +36,70 @@ else()
message(STATUS "Bridge version is ${BRIDGE_APP_VERSION}")
endif()
configure_file(Version.h.in ${CMAKE_SOURCE_DIR}/Version.h)
if (APPLE) # On macOS, we have some Objective-C++ code in DockIcon to deal with the dock icon.
enable_language(OBJC OBJCXX)
endif()
if (NOT DEFINED ENV{QT6DIR})
message(FATAL_ERROR "QT6DIR needs to be defined and point to the root of your Qt 6 folder (e.g. /Users/MyName/Qt/6.3.1/clang_64).")
endif()
set(CMAKE_PREFIX_PATH $ENV{QT6DIR} ${CMAKE_PREFIX_PATH})
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_AUTOMOC ON)
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 REQUIRED)
endif()
find_package(Qt6 COMPONENTS
Core
Quick
Qml
QuickControls2
REQUIRED)
message(STATUS "Using Qt ${Qt6_VERSION}")
#*****************************************************************************************************************************************************
# Qt
#*****************************************************************************************************************************************************
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}")
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(PROTO_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../grpc")
set(PROTO_FILE "${PROTO_DIR}/bridge.proto")
set(GRPC_OUT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/GRPC")
set(PROTO_CPP_FILE "${GRPC_OUT_DIR}/bridge.pb.cc")
set(PROTO_H_FILE "${GRPC_OUT_DIR}/bridge.pb.h")
set(GRPC_CPP_FILE "${GRPC_OUT_DIR}/bridge.grpc.pb.cc")
set(GRPC_H_FILE "${GRPC_OUT_DIR}/bridge.grpc.pb.h")
set(CMAKE_PREFIX_PATH $ENV{QT6DIR} ${CMAKE_PREFIX_PATH})
find_package(Qt6 COMPONENTS Core Quick Qml QuickControls2 REQUIRED)
qt_standard_project_setup()
set(CMAKE_AUTORCC ON)
message(STATUS "Using Qt ${Qt6_VERSION}")
#*****************************************************************************************************************************************************
# Source files and output
#*****************************************************************************************************************************************************
configure_file(Version.h.in ${CMAKE_SOURCE_DIR}/Version.h)
add_subdirectory(../bridgepp bridgepp)
if (APPLE)
set(DOCK_ICON_SRC_FILE DockIcon/DockIcon.mm)
else()
set(DOCK_ICON_SRC_FILE DockIcon/DockIcon.cpp)
endif()
add_custom_command(
OUTPUT
${PROTO_CPP_FILE}
${PROTO_H_FILE}
${GRPC_CPP_FILE}
${GRPC_H_FILE}
COMMAND
${PROTOC_EXE}
ARGS
--proto_path=${PROTO_DIR}
--plugin=protoc-gen-grpc="${GRPC_CPP_PLUGIN}"
--cpp_out=${GRPC_OUT_DIR}
--grpc_out=${GRPC_OUT_DIR}
${PROTO_FILE}
DEPENDS
${PROTO_FILE}
COMMENT "Generating gPRC/Protobuf C++ code"
)
add_executable(bridge-gui
Resources.qrc
${PROTO_CPP_FILE} ${PROTO_H_FILE} ${GRPC_CPP_FILE} ${GRPC_H_FILE}
AppController.cpp AppController.h
BridgeMonitor.cpp BridgeMonitor.h
EventStreamWorker.cpp EventStreamWorker.h
Exception.cpp Exception.h
Log.cpp Log.h
main.cpp
Pch.h
Version.h
QMLBackend.cpp QMLBackend.h
UserList.cpp UserList.h
${DOCK_ICON_SRC_FILE} DockIcon/DockIcon.h
GRPC/GRPCClient.cpp GRPC/GRPCClient.h
GRPC/GRPCUtils.cpp GRPC/GRPCUtils.h
User/User.cpp User/User.h User/UserList.cpp User/UserList.h
Worker/Overseer.cpp Worker/Overseer.h
Worker/Worker.h)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
)
target_precompile_headers(bridge-gui PRIVATE Pch.h)
target_include_directories(bridge-gui PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(bridge-gui
Qt6::Core
Qt6::Quick
Qt6::Qml
Qt6::QuickControls2
protobuf::libprotobuf
gRPC::grpc++
bridgepp
)
if (APPLE)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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/>.
#include "Pch.h"
#include "UserList.h"
#include "GRPC/GRPCClient.h"
using namespace bridgepp;
//****************************************************************************************************************************************************
@ -36,11 +37,12 @@ UserList::UserList(QObject *parent)
//****************************************************************************************************************************************************
void UserList::connectGRPCEvents() const
{
GRPCClient* client = &app().grpc();
connect(client, &GRPCClient::userChanged, this, &UserList::onUserChanged);
connect(client, &GRPCClient::toggleSplitModeFinished, this, &UserList::onToggleSplitModeFinished);
GRPCClient& client = app().grpc();
connect(&client, &GRPCClient::userChanged, this, &UserList::onUserChanged);
connect(&client, &GRPCClient::toggleSplitModeFinished, this, &UserList::onToggleSplitModeFinished);
}
//****************************************************************************************************************************************************
//
//****************************************************************************************************************************************************
@ -91,6 +93,7 @@ void UserList::reset()
this->endResetModel();
}
//****************************************************************************************************************************************************
/// \param[in] users The new user list.
//****************************************************************************************************************************************************
@ -135,7 +138,7 @@ void UserList::updateUserAtRow(int row, User const &user)
{
if ((row < 0) || (row >= users_.count()))
{
app().log().error(QString("invalid user at row %2 (user count = %2)").arg(row).arg(users_.count()));
app().log().error(QString("invalid user at row %2 (user userCount = %2)").arg(row).arg(users_.count()));
return;
}
@ -153,11 +156,11 @@ User *UserList::get(int row) const
{
if ((row < 0) || (row >= users_.count()))
{
app().log().error(QString("Requesting invalid user at row %1 (user count = %2)").arg(row).arg(users_.count()));
app().log().error(QString("Requesting invalid user at row %1 (user userCount = %2)").arg(row).arg(users_.count()));
return nullptr;
}
app().log().debug(QString("Retrieving user at row %1 (user count = %2)").arg(row).arg(users_.count()));
app().log().debug(QString("Retrieving user at row %1 (user userCount = %2)").arg(row).arg(users_.count()));
return users_[row].get();
}
@ -170,6 +173,8 @@ void UserList::onUserChanged(QString const &userID)
int const index = this->rowOfUserID(userID);
SPUser user;
grpc::Status status = app().grpc().getUser(userID, user);
QQmlEngine::setObjectOwnership(user.get(), QQmlEngine::CppOwnership);
if ((!user) || (!status.ok()))
{
if (index >= 0) // user exists here but not in the go backend. we delete it.

View File

@ -19,7 +19,11 @@
#ifndef 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.
@ -28,7 +32,7 @@ class UserList: public QAbstractListModel
{
Q_OBJECT
public: // member functions.
explicit UserList(QObject *parent = nullptr); ///< Default constructor.
UserList(QObject *parent); ///< Default constructor.
UserList(UserList const &other) = delete; ///< Disabled copy-constructor.
UserList &operator=(UserList const &other) = delete; ///< Disabled assignment operator.
~UserList() override = default; ///< Destructor
@ -36,28 +40,28 @@ public: // member functions.
int rowCount(QModelIndex const &parent) const override; ///< Return the number of row in the model
QVariant data(QModelIndex const &index, int role) const override; ///< Retrieve model data.
void reset(); ///< Reset the user list.
void reset(QList<SPUser> const &users); ///< Replace the user list.
void reset(QList<bridgepp::SPUser> const &users); ///< Replace the user list.
int rowOfUserID(QString const &userID) const;
void removeUserAt(int row); ///< Remove the user at a given row
void appendUser(SPUser const& user); ///< Add a new user.
void updateUserAtRow(int row, User const& user); ///< Update the user at given row.
void appendUser(bridgepp::SPUser const &user); ///< Add a new user.
void updateUserAtRow(int row, bridgepp::User const &user); ///< Update the user at given row.
// the count property.
// the userCount property.
Q_PROPERTY(int count READ count NOTIFY countChanged)
int count() const; ///< The count property getter.
int count() const; ///< The userCount property getter.
signals:
void countChanged(int count); ///< Signal for the count property.
void countChanged(int count); ///< Signal for the userCount property.
public:
Q_INVOKABLE User* get(int row) const;
Q_INVOKABLE bridgepp::User *get(int row) const;
public slots: ///< handler for signals coming from the gRPC service
void onUserChanged(QString const &userID);
void onToggleSplitModeFinished(QString const &userID);
private: // data members
QList<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/>.
#include "Pch.h"
#include "Exception.h"
#include "QMLBackend.h"
#include "Log.h"
#include "BridgeMonitor.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.setEchoInConsole(true);
log.setLevel(Log::Level::Debug);
Log::installQtMessageHandler();
log.registerAsQtMessageHandler();
return log;
}
@ -63,7 +65,7 @@ QQmlComponent *createRootQmlComponent(QQmlApplicationEngine &engine)
qmlRegisterSingletonInstance("Proton", 1, 0, "Backend", &app().backend());
qmlRegisterType<UserList>("Proton", 1, 0, "UserList");
qmlRegisterType<User>("Proton", 1, 0, "User");
qmlRegisterType<bridgepp::User>("Proton", 1, 0, "User");
auto rootComponent = new QQmlComponent(&engine, &engine);
@ -138,7 +140,7 @@ void parseArguments(int argc, char **argv, bool &outAttach, QString &outExePath)
void closeBridgeApp()
{
UPOverseer& overseer = app().bridgeOverseer();
if (!overseer) // The app was ran in 'attach' mode and attached to an existing instance of Bridge. No need to close.
if (!overseer) // The app was run in 'attach' mode and attached to an existing instance of Bridge. No need to close.
return;
app().grpc().quit(); // this will cause the grpc service and the bridge app to close.
@ -186,7 +188,7 @@ int main(int argc, char *argv[])
QMetaObject::Connection connection;
if (bridgeMonitor)
connection = QObject::connect(bridgeMonitor, &BridgeMonitor::processExited, [&](int returnCode) {
// GODT-1671 We need to find a 'safe' way to check if brige crashed and restart instead of just quitting. Is returnCode enough?
// GODT-1671 We need to find a 'safe' way to check if Bridge crashed and restart instead of just quitting. Is returnCode enough?
bridgeExited = true;// clazy:exclude=lambda-in-connect
qGuiApp->exit(returnCode);
});

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/>.
#ifndef BRIDGE_GUI_GRPCUTILS_H
#define BRIDGE_GUI_GRPCUTILS_H
#ifndef BRIDGE_GUI_TESTER_BRIDGE_UTILS_H
#define BRIDGE_GUI_TESTER_BRIDGE_UTILS_H
#include "Log.h"
#include "GRPC/bridge.grpc.pb.h"
#include "grpc++/grpc++.h"
#include "User/User.h"
namespace bridgepp {
void logGRPCCallStatus(grpc::Status const& status, QString const &callName); ///< Log the status of a gRPC code.
SPUser parsegrpcUser(grpc::User const& grpcUser); ///< Parse a gRPC user struct and return a User.
grpc::LogLevel logLevelToGRPC(Log::Level level); ///< Convert a Log::Level to gRPC enum value.
QString userConfigDir(); ///< Get the path of the user configuration folder.
#endif // BRIDGE_GUI_GRPCUTILS_H
} // namespace
#endif // BRIDGE_GUI_TESTER_BRIDGE_UTILS_H

View File

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

View File

@ -16,13 +16,17 @@
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
#ifndef BRIDGE_GUI_EXCEPTION_H
#define BRIDGE_GUI_EXCEPTION_H
#ifndef BRIDGE_PP_EXCEPTION_H
#define BRIDGE_PP_EXCEPTION_H
#include <stdexcept>
namespace bridgepp
{
//****************************************************************************************************************************************************
/// \brief Exception class.
//****************************************************************************************************************************************************
@ -43,4 +47,7 @@ private: // data members
};
#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/>.
#include "Pch.h"
#include "GRPCClient.h"
#include "GRPCUtils.h"
#include "QMLBackend.h"
#include "Exception.h"
#include "AppController.h"
#include "../Exception/Exception.h"
using namespace google::protobuf;
using namespace grpc;
namespace bridgepp
{
namespace
{
Empty empty; // re-used across client calls.
QString const configFolder = "protonmail/bridge";
QString const certFile = "cert.pem";
int const maxConnectionTimeSecs = 60; ///< Amount of time after which we consider connection attemps to the server have failed.
int const maxCertificateWaitMsecs = 60 * 1000; ///< Ammount of time we wait for he server to generate the certificate.
int const maxConnectionTimeSecs = 60; ///< Amount of time after which we consider connection attempts to the server have failed.
int const maxCertificateWaitMsecs = 60 * 1000; ///< Amount of time we wait for he server to generate the certificate.
}
//****************************************************************************************************************************************************
/// \return user configuration directory used by bridge (based on Golang OS/File's UserConfigDir).
//****************************************************************************************************************************************************
static const QString _userConfigDir(){
QString dir;
#ifdef Q_OS_WIN
dir = qgetenv ("AppData");
if (dir.isEmpty())
throw Exception("%AppData% is not defined.");
#elif defined(Q_OS_IOS) || defined(Q_OS_DARWIN)
dir = qgetenv ("HOME");
if (dir.isEmpty())
throw Exception("$HOME is not defined.");
dir += "/Library/Application Support";
#else
dir = qgetenv ("XDG_CONFIG_HOME");
if (dir.isEmpty())
dir = qgetenv ("HOME");
if (dir.isEmpty())
throw Exception("neither $XDG_CONFIG_HOME nor $HOME are defined");
dir += "/.config";
#endif
QString folder = dir + "/" + configFolder;
QDir().mkpath(folder);
return folder;
}
//****************************************************************************************************************************************************
/// \brief wait for certificate generation by Bridge
@ -73,8 +49,9 @@ static const QString _userConfigDir(){
//****************************************************************************************************************************************************
std::string GRPCClient::getServerCertificate()
{
const QString filename = _userConfigDir() + "/" + certFile;
QFile file(filename);
QString const certPath = serverCertificatePath();
QString const certFolder = QFileInfo(certPath).absolutePath();
QFile file(certPath);
// TODO : the certificate can exist but still be invalid.
// If the certificate is close to its limit, the bridge will generate a new one.
// If we read the certificate before the bridge rewrites it the certificate will be invalid.
@ -82,7 +59,7 @@ std::string GRPCClient::getServerCertificate()
{
// wait for file creation
QFileSystemWatcher watcher(this);
if (!watcher.addPath(_userConfigDir()))
if (!watcher.addPath(certFolder))
throw Exception("Failed to watch User Config Directory");
connect(&watcher, &QFileSystemWatcher::directoryChanged, this, &GRPCClient::configFolderChanged);
@ -109,16 +86,26 @@ std::string GRPCClient::getServerCertificate()
return cert;
}
//****************************************************************************************************************************************************
/// \brief Action on UserConfig directory changes, looking for the certificate creation
//****************************************************************************************************************************************************
void GRPCClient::configFolderChanged()
{
QFile cert(_userConfigDir() + "/" + certFile);
if (cert.exists())
if (QFileInfo::exists(serverCertificatePath()))
emit certIsReady();
}
//****************************************************************************************************************************************************
/// \param[in] log The log
//****************************************************************************************************************************************************
void GRPCClient::setLog(Log *log)
{
log_ = log;
}
//****************************************************************************************************************************************************
/// \param[out] outError If the function returns false, this variable contains a description of the error.
/// \return true iff the connection was successful.
@ -142,7 +129,8 @@ bool GRPCClient::connectToServer(QString &outError)
int i = 0;
while (true)
{
app().log().debug(QString("Connection to gRPC server. attempt #%1").arg(++i));
if (log_)
log_->debug(QString("Connection to gRPC server. attempt #%1").arg(++i));
if (channel_->WaitForConnected(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_seconds(5, GPR_TIMESPAN))))
break; // connection established.
@ -154,9 +142,8 @@ bool GRPCClient::connectToServer(QString &outError)
if (channel_->GetState(true) != GRPC_CHANNEL_READY)
throw Exception("connection check failed.");
QMLBackend *backend = &app().backend();
QObject::connect(this, &GRPCClient::loginFreeUserError, backend, &QMLBackend::loginFreeUserError);
app().log().debug("Successfully connected to gRPC server.");
if (log_)
log_->debug("Successfully connected to gRPC server.");
return true;
}
catch (Exception const &e)
@ -183,13 +170,14 @@ grpc::Status GRPCClient::addLogEntry(Log::Level level, QString const &package, Q
return stub_->AddLogEntry(&ctx, request, &empty);
}
//****************************************************************************************************************************************************
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::guiReady()
{
grpc::ClientContext ctx;
return stub_->GuiReady(&ctx, empty, &empty);
return this->logGRPCCallStatus(stub_->GuiReady(&ctx, empty, &empty), __FUNCTION__);
}
@ -199,7 +187,7 @@ grpc::Status GRPCClient::guiReady()
//****************************************************************************************************************************************************
grpc::Status GRPCClient::isFirstGUIStart(bool &outIsFirst)
{
return this->getBool(&Bridge::Stub::IsFirstGuiStart, outIsFirst);
return this->logGRPCCallStatus(this->getBool(&Bridge::Stub::IsFirstGuiStart, outIsFirst), __FUNCTION__);
}
@ -209,7 +197,7 @@ grpc::Status GRPCClient::isFirstGUIStart(bool &outIsFirst)
//****************************************************************************************************************************************************
grpc::Status GRPCClient::isAutostartOn(bool &outIsOn)
{
return this->getBool(&Bridge::Stub::IsAutostartOn, outIsOn);
return this->logGRPCCallStatus(this->getBool(&Bridge::Stub::IsAutostartOn, outIsOn), __FUNCTION__);
}
@ -219,7 +207,7 @@ grpc::Status GRPCClient::isAutostartOn(bool &outIsOn)
//****************************************************************************************************************************************************
grpc::Status GRPCClient::setIsAutostartOn(bool on)
{
return this->setBool(&Bridge::Stub::SetIsAutostartOn, on);
return this->logGRPCCallStatus(this->setBool(&Bridge::Stub::SetIsAutostartOn, on), __FUNCTION__);
}
@ -229,7 +217,7 @@ grpc::Status GRPCClient::setIsAutostartOn(bool on)
//****************************************************************************************************************************************************
grpc::Status GRPCClient::isBetaEnabled(bool &outEnabled)
{
return this->getBool(&Bridge::Stub::IsBetaEnabled, outEnabled);
return this->logGRPCCallStatus(this->getBool(&Bridge::Stub::IsBetaEnabled, outEnabled), __FUNCTION__);
}
@ -237,9 +225,9 @@ grpc::Status GRPCClient::isBetaEnabled(bool &outEnabled)
/// \param[in] enabled The new value for the property.
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::setisBetaEnabled(bool enabled)
grpc::Status GRPCClient::setIsBetaEnabled(bool enabled)
{
return this->setBool(&Bridge::Stub::SetIsBetaEnabled, enabled);
return this->logGRPCCallStatus(this->setBool(&Bridge::Stub::SetIsBetaEnabled, enabled), __FUNCTION__);
}
@ -249,7 +237,7 @@ grpc::Status GRPCClient::setisBetaEnabled(bool enabled)
//****************************************************************************************************************************************************
grpc::Status GRPCClient::colorSchemeName(QString &outName)
{
return this->getString(&Bridge::Stub::ColorSchemeName, outName);
return this->logGRPCCallStatus(this->getString(&Bridge::Stub::ColorSchemeName, outName), __FUNCTION__);
}
@ -259,7 +247,7 @@ grpc::Status GRPCClient::colorSchemeName(QString &outName)
//****************************************************************************************************************************************************
grpc::Status GRPCClient::setColorSchemeName(QString const &name)
{
return this->setString(&Bridge::Stub::SetColorSchemeName, name);
return this->logGRPCCallStatus(this->setString(&Bridge::Stub::SetColorSchemeName, name), __FUNCTION__);
}
@ -269,7 +257,7 @@ grpc::Status GRPCClient::setColorSchemeName(QString const &name)
//****************************************************************************************************************************************************
grpc::Status GRPCClient::currentEmailClient(QString &outName)
{
return this->getString(&Bridge::Stub::CurrentEmailClient, outName);
return this->logGRPCCallStatus(this->getString(&Bridge::Stub::CurrentEmailClient, outName), __FUNCTION__);
}
@ -278,7 +266,7 @@ grpc::Status GRPCClient::currentEmailClient(QString &outName)
/// \param[in] address The email address.
/// \param[in] emailClient The email client.
/// \param[in] includeLogs Should the report include the logs.
/// \return The status foer the gRPC call.
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::reportBug(QString const &description, QString const &address, QString const &emailClient, bool includeLogs)
{
@ -290,7 +278,7 @@ grpc::Status GRPCClient::reportBug(QString const &description, QString const &ad
request.set_address(address.toStdString());
request.set_emailclient(emailClient.toStdString());
request.set_includelogs(includeLogs);
return stub_->ReportBug(&ctx, request, &empty);
return this->logGRPCCallStatus(stub_->ReportBug(&ctx, request, &empty), __FUNCTION__);
}
@ -300,7 +288,7 @@ grpc::Status GRPCClient::reportBug(QString const &description, QString const &ad
//****************************************************************************************************************************************************
grpc::Status GRPCClient::useSSLForSMTP(bool &outUseSSL)
{
return this->getBool(&Bridge::Stub::UseSslForSmtp, outUseSSL);
return this->logGRPCCallStatus(this->getBool(&Bridge::Stub::UseSslForSmtp, outUseSSL), __FUNCTION__);
}
@ -310,7 +298,7 @@ grpc::Status GRPCClient::useSSLForSMTP(bool &outUseSSL)
//****************************************************************************************************************************************************
grpc::Status GRPCClient::setUseSSLForSMTP(bool useSSL)
{
return this->setBool(&Bridge::Stub::SetUseSslForSmtp, useSSL);
return this->logGRPCCallStatus(this->setBool(&Bridge::Stub::SetUseSslForSmtp, useSSL), __FUNCTION__);
}
@ -320,7 +308,7 @@ grpc::Status GRPCClient::setUseSSLForSMTP(bool useSSL)
//****************************************************************************************************************************************************
grpc::Status GRPCClient::portIMAP(int &outPort)
{
return this->getInt32(&Bridge::Stub::ImapPort, outPort);
return this->logGRPCCallStatus(this->getInt32(&Bridge::Stub::ImapPort, outPort), __FUNCTION__);
}
@ -330,7 +318,7 @@ grpc::Status GRPCClient::portIMAP(int &outPort)
//****************************************************************************************************************************************************
grpc::Status GRPCClient::portSMTP(int &outPort)
{
return this->getInt32(&Bridge::Stub::SmtpPort, outPort);
return this->logGRPCCallStatus(this->getInt32(&Bridge::Stub::SmtpPort, outPort), __FUNCTION__);
}
@ -345,7 +333,7 @@ grpc::Status GRPCClient::changePorts(int portIMAP, int portSMTP)
ChangePortsRequest request;
request.set_imapport(portIMAP);
request.set_smtpport(portSMTP);
return stub_->ChangePorts(&ctx, request, &empty);
return this->logGRPCCallStatus(stub_->ChangePorts(&ctx, request, &empty), __FUNCTION__);
}
@ -355,7 +343,7 @@ grpc::Status GRPCClient::changePorts(int portIMAP, int portSMTP)
//****************************************************************************************************************************************************
grpc::Status GRPCClient::isDoHEnabled(bool &outEnabled)
{
return this->getBool(&Bridge::Stub::IsDoHEnabled, outEnabled);
return this->logGRPCCallStatus(this->getBool(&Bridge::Stub::IsDoHEnabled, outEnabled), __FUNCTION__);
}
@ -365,7 +353,7 @@ grpc::Status GRPCClient::isDoHEnabled(bool &outEnabled)
//****************************************************************************************************************************************************
grpc::Status GRPCClient::setIsDoHEnabled(bool enabled)
{
return this->setBool(&Bridge::Stub::SetIsDoHEnabled, enabled);
return this->logGRPCCallStatus(this->setBool(&Bridge::Stub::SetIsDoHEnabled, enabled), __FUNCTION__);
}
@ -375,7 +363,7 @@ grpc::Status GRPCClient::setIsDoHEnabled(bool enabled)
grpc::Status GRPCClient::quit()
{
grpc::ClientContext ctx;
return stub_->Quit(&ctx, empty, &empty);
return this->logGRPCCallStatus(stub_->Quit(&ctx, empty, &empty), __FUNCTION__);
}
@ -385,16 +373,17 @@ grpc::Status GRPCClient::quit()
grpc::Status GRPCClient::restart()
{
grpc::ClientContext ctx;
return stub_->Restart(&ctx, empty, &empty);
return this->logGRPCCallStatus(stub_->Restart(&ctx, empty, &empty), __FUNCTION__);
}
//****************************************************************************************************************************************************
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::triggerReset()
{
grpc::ClientContext ctx;
return stub_->TriggerReset(&ctx, empty, &empty);
return this->logGRPCCallStatus(stub_->TriggerReset(&ctx, empty, &empty), __FUNCTION__);
}
@ -412,7 +401,7 @@ grpc::Status GRPCClient::isPortFree(qint32 port, bool &outFree)
Status result = stub_->IsPortFree(&ctx, p, &isFree);
if (result.ok())
outFree = isFree.value();
return result;
return this->logGRPCCallStatus(result, __FUNCTION__);
}
@ -422,7 +411,7 @@ grpc::Status GRPCClient::isPortFree(qint32 port, bool &outFree)
//****************************************************************************************************************************************************
grpc::Status GRPCClient::showOnStartup(bool &outValue)
{
return this->getBool(&Bridge::Stub::ShowOnStartup, outValue);
return this->logGRPCCallStatus(this->getBool(&Bridge::Stub::ShowOnStartup, outValue), __FUNCTION__);
}
@ -432,7 +421,7 @@ grpc::Status GRPCClient::showOnStartup(bool &outValue)
//****************************************************************************************************************************************************
grpc::Status GRPCClient::showSplashScreen(bool &outValue)
{
return this->getBool(&Bridge::Stub::ShowSplashScreen, outValue);
return this->logGRPCCallStatus(this->getBool(&Bridge::Stub::ShowSplashScreen, outValue), __FUNCTION__);
}
@ -442,7 +431,7 @@ grpc::Status GRPCClient::showSplashScreen(bool &outValue)
//****************************************************************************************************************************************************
grpc::Status GRPCClient::goos(QString &outGoos)
{
return this->getString(&Bridge::Stub::GoOs, outGoos);
return this->logGRPCCallStatus(this->getString(&Bridge::Stub::GoOs, outGoos), __FUNCTION__);
}
@ -452,7 +441,7 @@ grpc::Status GRPCClient::goos(QString &outGoos)
//****************************************************************************************************************************************************
grpc::Status GRPCClient::logsPath(QUrl &outPath)
{
return this->getURLForLocalFile(&Bridge::Stub::LogsPath, outPath);
return this->logGRPCCallStatus(this->getURLForLocalFile(&Bridge::Stub::LogsPath, outPath), __FUNCTION__);
}
@ -462,7 +451,7 @@ grpc::Status GRPCClient::logsPath(QUrl &outPath)
//****************************************************************************************************************************************************
grpc::Status GRPCClient::licensePath(QUrl &outPath)
{
return this->getURLForLocalFile(&Bridge::Stub::LicensePath, outPath);
return this->logGRPCCallStatus(this->getURLForLocalFile(&Bridge::Stub::LicensePath, outPath), __FUNCTION__);
}
@ -472,7 +461,7 @@ grpc::Status GRPCClient::licensePath(QUrl &outPath)
//****************************************************************************************************************************************************
grpc::Status GRPCClient::dependencyLicensesLink(QUrl &outUrl)
{
return this->getURL(&Bridge::Stub::DependencyLicensesLink, outUrl);
return this->logGRPCCallStatus(this->getURL(&Bridge::Stub::DependencyLicensesLink, outUrl), __FUNCTION__);
}
@ -482,34 +471,37 @@ grpc::Status GRPCClient::dependencyLicensesLink(QUrl &outUrl)
//****************************************************************************************************************************************************
grpc::Status GRPCClient::version(QString &outVersion)
{
return this->getString(&Bridge::Stub::Version, outVersion);
return this->logGRPCCallStatus(this->getString(&Bridge::Stub::Version, outVersion), __FUNCTION__);
}
//****************************************************************************************************************************************************
/// \param[out] outUrl The value for the property.
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::releaseNotesPageLink(QUrl &outUrl)
{
return this->getURL(&Bridge::Stub::ReleaseNotesPageLink, outUrl);
return this->logGRPCCallStatus(this->getURL(&Bridge::Stub::ReleaseNotesPageLink, outUrl), __FUNCTION__);
}
//****************************************************************************************************************************************************
/// \param[out] outUrl The value for the property.
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::landingPageLink(QUrl &outUrl)
{
return this->getURL(&Bridge::Stub::LandingPageLink, outUrl);
return this->logGRPCCallStatus(this->getURL(&Bridge::Stub::LandingPageLink, outUrl), __FUNCTION__);
}
//****************************************************************************************************************************************************
/// \param[out] outHostname The value for the property.
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::hostname(QString &outHostname)
{
return this->getString(&Bridge::Stub::Hostname, outHostname);
return this->logGRPCCallStatus(this->getString(&Bridge::Stub::Hostname, outHostname), __FUNCTION__);
}
@ -519,7 +511,7 @@ grpc::Status GRPCClient::hostname(QString &outHostname)
//****************************************************************************************************************************************************
grpc::Status GRPCClient::isCacheOnDiskEnabled(bool &outEnabled)
{
return getBool(&Bridge::Stub::IsCacheOnDiskEnabled, outEnabled);
return this->logGRPCCallStatus(getBool(&Bridge::Stub::IsCacheOnDiskEnabled, outEnabled), __FUNCTION__);
}
@ -529,7 +521,7 @@ grpc::Status GRPCClient::isCacheOnDiskEnabled(bool &outEnabled)
//****************************************************************************************************************************************************
grpc::Status GRPCClient::diskCachePath(QUrl &outPath)
{
return this->getURLForLocalFile(&Bridge::Stub::DiskCachePath, outPath);
return this->logGRPCCallStatus(this->getURLForLocalFile(&Bridge::Stub::DiskCachePath, outPath), __FUNCTION__);
}
@ -544,7 +536,7 @@ grpc::Status GRPCClient::changeLocalCache(bool enabled, QUrl const &path)
ChangeLocalCacheRequest request;
request.set_enablediskcache(enabled);
request.set_diskcachepath(path.path(QUrl::FullyDecoded).toStdString());
return stub_->ChangeLocalCache(&ctx, request, &empty);
return this->logGRPCCallStatus(stub_->ChangeLocalCache(&ctx, request, &empty), __FUNCTION__);
}
@ -559,7 +551,7 @@ grpc::Status GRPCClient::login(QString const &username, QString const &password)
LoginRequest request;
request.set_username(username.toStdString());
request.set_password(password.toStdString());
return stub_->Login(&ctx, request, &empty);
return this->logGRPCCallStatus(stub_->Login(&ctx, request, &empty), __FUNCTION__);
}
@ -574,7 +566,7 @@ grpc::Status GRPCClient::login2FA(QString const &username, QString const &code)
LoginRequest request;
request.set_username(username.toStdString());
request.set_password(code.toStdString());
return stub_->Login2FA(&ctx, request, &empty);
return this->logGRPCCallStatus(stub_->Login2FA(&ctx, request, &empty), __FUNCTION__);
}
@ -589,7 +581,7 @@ grpc::Status GRPCClient::login2Passwords(QString const &username, QString const
LoginRequest request;
request.set_username(username.toStdString());
request.set_password(password.toStdString());
return stub_->Login2Passwords(&ctx, request, &empty);
return this->logGRPCCallStatus(stub_->Login2Passwords(&ctx, request, &empty), __FUNCTION__);
}
@ -602,7 +594,7 @@ grpc::Status GRPCClient::loginAbort(QString const &username)
grpc::ClientContext ctx;
LoginAbortRequest request;
request.set_username(username.toStdString());
return stub_->LoginAbort(&ctx, request, &empty);
return this->logGRPCCallStatus(stub_->LoginAbort(&ctx, request, &empty), __FUNCTION__);
}
@ -611,7 +603,7 @@ grpc::Status GRPCClient::loginAbort(QString const &username)
//****************************************************************************************************************************************************
grpc::Status GRPCClient::checkUpdate()
{
return this->simpleMethod(&Bridge::Stub::CheckUpdate);
return this->logGRPCCallStatus(this->simpleMethod(&Bridge::Stub::CheckUpdate), __FUNCTION__);
}
@ -620,7 +612,7 @@ grpc::Status GRPCClient::checkUpdate()
//****************************************************************************************************************************************************
grpc::Status GRPCClient::installUpdate()
{
return this->simpleMethod(&Bridge::Stub::InstallUpdate);
return this->logGRPCCallStatus(this->simpleMethod(&Bridge::Stub::InstallUpdate), __FUNCTION__);
}
@ -629,7 +621,7 @@ grpc::Status GRPCClient::installUpdate()
//****************************************************************************************************************************************************
grpc::Status GRPCClient::setIsAutomaticUpdateOn(bool on)
{
return this->setBool(&Bridge::Stub::SetIsAutomaticUpdateOn, on);
return this->logGRPCCallStatus(this->setBool(&Bridge::Stub::SetIsAutomaticUpdateOn, on), __FUNCTION__);
}
@ -638,7 +630,7 @@ grpc::Status GRPCClient::setIsAutomaticUpdateOn(bool on)
//****************************************************************************************************************************************************
grpc::Status GRPCClient::isAutomaticUpdateOn(bool &isOn)
{
return this->getBool(&Bridge::Stub::IsAutomaticUpdateOn, isOn);
return this->logGRPCCallStatus(this->getBool(&Bridge::Stub::IsAutomaticUpdateOn, isOn), __FUNCTION__);
}
@ -648,7 +640,7 @@ grpc::Status GRPCClient::isAutomaticUpdateOn(bool &isOn)
//****************************************************************************************************************************************************
grpc::Status GRPCClient::logoutUser(QString const &userID)
{
return methodWithStringParam(&Bridge::Stub::LogoutUser, userID);
return this->logGRPCCallStatus(methodWithStringParam(&Bridge::Stub::LogoutUser, userID), __FUNCTION__);
}
@ -658,7 +650,7 @@ grpc::Status GRPCClient::logoutUser(QString const &userID)
//****************************************************************************************************************************************************
grpc::Status GRPCClient::removeUser(QString const &userID)
{
return methodWithStringParam(&Bridge::Stub::RemoveUser, userID);
return this->logGRPCCallStatus(methodWithStringParam(&Bridge::Stub::RemoveUser, userID), __FUNCTION__);
}
@ -673,7 +665,7 @@ grpc::Status GRPCClient::configureAppleMail(QString const &userID, QString const
ConfigureAppleMailRequest request;
request.set_userid(userID.toStdString());
request.set_address(address.toStdString());
return stub_->ConfigureUserAppleMail(&ctx, request, &empty);
return this->logGRPCCallStatus(stub_->ConfigureUserAppleMail(&ctx, request, &empty), __FUNCTION__);
}
@ -689,7 +681,7 @@ grpc::Status GRPCClient::setUserSplitMode(QString const &userID, bool active)
request.set_userid(userID.toStdString());
request.set_active(active);
return stub_->SetUserSplitMode(&ctx, request, &empty);
return this->logGRPCCallStatus(stub_->SetUserSplitMode(&ctx, request, &empty), __FUNCTION__);
}
@ -705,12 +697,12 @@ grpc::Status GRPCClient::getUserList(QList<SPUser> &outUsers)
UserListResponse response;
Status status = stub_->GetUserList(&ctx, empty, &response);
if (!status.ok())
return status;
return this->logGRPCCallStatus(status, __FUNCTION__);
for (int i = 0; i < response.users_size(); ++i)
outUsers.append(parsegrpcUser(response.users(i)));
outUsers.append(this->parseGRPCUser(response.users(i)));
return status;
return this->logGRPCCallStatus(status, __FUNCTION__);
}
@ -719,7 +711,7 @@ grpc::Status GRPCClient::getUserList(QList<SPUser> &outUsers)
/// \param[out] outUser The user.
/// \return The status code for the operation.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::getUser(QString const &userID, ::SPUser &outUser)
grpc::Status GRPCClient::getUser(QString const &userID, SPUser &outUser)
{
ClientContext ctx;
StringValue s;
@ -728,9 +720,9 @@ grpc::Status GRPCClient::getUser(QString const &userID, ::SPUser &outUser)
Status status = stub_->GetUser(&ctx, s, &grpcUser);
if (status.ok())
outUser = parsegrpcUser(grpcUser);
outUser = parseGRPCUser(grpcUser);
return grpc::Status();
return this->logGRPCCallStatus(grpc::Status(), __FUNCTION__);
}
@ -745,12 +737,12 @@ grpc::Status GRPCClient::availableKeychains(QStringList &outKeychains)
AvailableKeychainsResponse response;
Status status = stub_->AvailableKeychains(&ctx, empty, &response);
if (!status.ok())
return status;
return this->logGRPCCallStatus(status, __FUNCTION__);
for (int i = 0; i < response.keychains_size(); ++i)
outKeychains.append(QString::fromStdString(response.keychains(i)));
return status;
return this->logGRPCCallStatus(status, __FUNCTION__);
}
@ -760,7 +752,7 @@ grpc::Status GRPCClient::availableKeychains(QStringList &outKeychains)
//****************************************************************************************************************************************************
grpc::Status GRPCClient::currentKeychain(QString &outKeychain)
{
return this->getString(&Bridge::Stub::CurrentKeychain, outKeychain);
return this->logGRPCCallStatus(this->getString(&Bridge::Stub::CurrentKeychain, outKeychain), __FUNCTION__);
}
@ -770,7 +762,7 @@ grpc::Status GRPCClient::currentKeychain(QString &outKeychain)
//****************************************************************************************************************************************************
grpc::Status GRPCClient::setCurrentKeychain(QString const &keychain)
{
return this->setString(&Bridge::Stub::SetCurrentKeychain, keychain);
return this->logGRPCCallStatus(this->setString(&Bridge::Stub::SetCurrentKeychain, keychain), __FUNCTION__);
}
@ -814,11 +806,12 @@ grpc::Status GRPCClient::startEventStream()
this->processUserEvent(event.user());
break;
default:
app().log().debug(QString("Unknown stream event type: %1").arg(event.event_case()));
if (log_)
log_->debug(QString("Unknown stream event type: %1").arg(event.event_case()));
}
}
return reader->Finish();
return this->logGRPCCallStatus(reader->Finish(), __FUNCTION__);
}
@ -828,7 +821,44 @@ grpc::Status GRPCClient::startEventStream()
grpc::Status GRPCClient::stopEventStream()
{
grpc::ClientContext ctx;
return stub_->StopEventStream(&ctx, empty, &empty);
return this->logGRPCCallStatus(stub_->StopEventStream(&ctx, empty, &empty), __FUNCTION__);
}
//****************************************************************************************************************************************************
/// \param[in] message The event message.
//****************************************************************************************************************************************************
void GRPCClient::logDebug(QString const &message)
{
if (log_)
log_->debug(message);
}
//****************************************************************************************************************************************************
/// \param[in] message The event message.
//****************************************************************************************************************************************************
void GRPCClient::logError(QString const &message)
{
if (log_)
log_->error(message);
}
//****************************************************************************************************************************************************
/// \param[in] status The status
/// \param[in] callName The call name.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::logGRPCCallStatus(Status const &status, QString const &callName)
{
if (log_)
{
if (status.ok())
log_->debug(QString("%1()").arg(callName));
else
log_->error(QString("%1() FAILED").arg(callName));
}
return status;
}
@ -977,6 +1007,24 @@ grpc::Status GRPCClient::methodWithStringParam(StringParamMethod method, QString
}
//****************************************************************************************************************************************************
/// \param[in] grpcUser The gRPC user.
/// \return The user.
//****************************************************************************************************************************************************
SPUser GRPCClient::parseGRPCUser(grpc::User const &grpcUser)
{
SPUser user = userFromGRPC(grpcUser);
User *u = user.get();
connect(u, &User::toggleSplitModeForUser, [&](QString const &userID, bool makeItActive) { this->setUserSplitMode(userID, makeItActive); });
connect(u, &User::logoutUser, [&](QString const &userID) { this->logoutUser(userID); });
connect(u, &User::removeUser, [&](QString const &userID) { this->removeUser(userID); });
connect(u, &User::configureAppleMailForUser, [&](QString const &userID, QString const& address) { this->configureAppleMail(userID, address); });
return user;
}
//****************************************************************************************************************************************************
/// \param[in] event The event.
//****************************************************************************************************************************************************
@ -985,35 +1033,35 @@ void GRPCClient::processAppEvent(AppEvent const &event)
switch (event.event_case())
{
case AppEvent::kInternetStatus:
app().log().debug("App event received: InternetStatus.");
this->logDebug("App event received: InternetStatus.");
emit internetStatus(event.internetstatus().connected());
break;
case AppEvent::kToggleAutostartFinished:
app().log().debug("App event received: AutostartFinished.");
this->logDebug("App event received: AutostartFinished.");
emit toggleAutostartFinished();
break;
case AppEvent::kResetFinished:
app().log().debug("App event received: ResetFinished.");
this->logDebug("App event received: ResetFinished.");
emit resetFinished();
break;
case AppEvent::kReportBugFinished:
app().log().debug("App event received: ReportBugFinished.");
this->logDebug("App event received: ReportBugFinished.");
emit reportBugFinished();
break;
case AppEvent::kReportBugSuccess:
app().log().debug("App event received: ReportBugSuccess.");
this->logDebug("App event received: ReportBugSuccess.");
emit reportBugSuccess();
break;
case AppEvent::kReportBugError:
app().log().debug("App event received: ReportBugError.");
this->logDebug("App event received: ReportBugError.");
emit reportBugError();
break;
case AppEvent::kShowMainWindow:
app().log().debug("App event received: ShowMainWindow.");
this->logDebug("App event received: ShowMainWindow.");
emit showMainWindow();
break;
default:
app().log().error("Unknown App event received.");
this->logError("Unknown App event received.");
}
}
@ -1027,7 +1075,7 @@ void GRPCClient::processLoginEvent(LoginEvent const &event)
{
case LoginEvent::kError:
{
app().log().debug("Login event received: Error.");
this->logDebug("Login event received: Error.");
LoginErrorEvent const &error = event.error();
switch (error.type())
{
@ -1053,29 +1101,29 @@ void GRPCClient::processLoginEvent(LoginEvent const &event)
emit login2PasswordErrorAbort(QString::fromStdString(error.message()));
break;
default:
app().log().debug("Unknown login error event received.");
this->logError("Unknown login error event received.");
break;
}
break;
}
case LoginEvent::kTfaRequested:
app().log().debug("Login event received: TfaRequested.");
this->logDebug("Login event received: TfaRequested.");
emit login2FARequested(QString::fromStdString(event.tfarequested().username()));
break;
case LoginEvent::kTwoPasswordRequested:
app().log().debug("Login event received: TwoPasswordRequested.");
this->logDebug("Login event received: TwoPasswordRequested.");
emit login2PasswordRequested();
break;
case LoginEvent::kFinished:
app().log().debug("Login event received: Finished.");
this->logDebug("Login event received: Finished.");
emit loginFinished(QString::fromStdString(event.finished().userid()));
break;
case LoginEvent::kAlreadyLoggedIn:
app().log().debug("Login event received: AlreadyLoggedIn.");
this->logDebug("Login event received: AlreadyLoggedIn.");
emit loginAlreadyLoggedIn(QString::fromStdString(event.finished().userid()));
break;
default:
app().log().error("Unknown Login event received.");
this->logError("Unknown Login event received.");
break;
}
}
@ -1090,7 +1138,7 @@ void GRPCClient::processUpdateEvent(UpdateEvent const &event)
{
case UpdateEvent::kError:
{
app().log().debug("Update event received: Error.");
this->logDebug("Update event received: Error.");
UpdateErrorEvent const &errorEvent = event.error();
switch (errorEvent.type())
@ -1105,37 +1153,37 @@ void GRPCClient::processUpdateEvent(UpdateEvent const &event)
emit updateSilentError();
break;
default:
app().log().error("Unknown update error received.");
this->logError("Unknown update error received.");
break;
}
break;
}
case UpdateEvent::kManualReady:
app().log().debug("Update event received: ManualReady.");
this->logDebug("Update event received: ManualReady.");
emit updateManualReady(QString::fromStdString(event.manualready().version()));
break;
case UpdateEvent::kManualRestartNeeded:
app().log().debug("Update event received: kManualRestartNeeded.");
this->logDebug("Update event received: kManualRestartNeeded.");
emit updateManualRestartNeeded();
break;
case UpdateEvent::kForce:
app().log().debug("Update event received: kForce.");
this->logDebug("Update event received: kForce.");
emit updateForce(QString::fromStdString(event.force().version()));
break;
case UpdateEvent::kSilentRestartNeeded:
app().log().debug("Update event received: kSilentRestartNeeded.");
this->logDebug("Update event received: kSilentRestartNeeded.");
emit updateSilentRestartNeeded();
break;
case UpdateEvent::kIsLatestVersion:
app().log().debug("Update event received: kIsLatestVersion.");
this->logDebug("Update event received: kIsLatestVersion.");
emit updateIsLatestVersion();
break;
case UpdateEvent::kCheckFinished:
app().log().debug("Update event received: kCheckFinished.");
this->logDebug("Update event received: kCheckFinished.");
emit checkUpdatesFinished();
break;
default:
app().log().error("Unknown Update event received.");
this->logError("Unknown Update event received.");
break;
}
}
@ -1162,34 +1210,34 @@ void GRPCClient::processCacheEvent(CacheEvent const &event)
emit diskFull();
break;
default:
app().log().error("Unknown cache error event received.");
this->logError("Unknown cache error event received.");
break;
}
break;
}
case CacheEvent::kLocationChangedSuccess:
app().log().debug("Cache event received: LocationChangedSuccess.");
this->logDebug("Cache event received: LocationChangedSuccess.");
emit cacheLocationChangeSuccess();
break;
case CacheEvent::kChangeLocalCacheFinished:
emit cacheLocationChangeSuccess();
app().log().debug("Cache event received: ChangeLocalCacheFinished.");
this->logDebug("Cache event received: ChangeLocalCacheFinished.");
break;
case CacheEvent::kIsCacheOnDiskEnabledChanged:
app().log().debug("Cache event received: IsCacheOnDiskEnabledChanged.");
this->logDebug("Cache event received: IsCacheOnDiskEnabledChanged.");
emit isCacheOnDiskEnabledChanged(event.iscacheondiskenabledchanged().enabled());
break;
case CacheEvent::kDiskCachePathChanged:
app().log().debug("Cache event received: DiskCachePathChanged.");
this->logDebug("Cache event received: DiskCachePathChanged.");
emit diskCachePathChanged(QUrl::fromLocalFile(QString::fromStdString(event.diskcachepathchanged().path())));
break;
default:
app().log().error("Unknown Cache event received.");
this->logError("Unknown Cache event received.");
}
}
@ -1202,7 +1250,7 @@ void GRPCClient::processMailSettingsEvent(MailSettingsEvent const &event)
switch (event.event_case())
{
case MailSettingsEvent::kError:
app().log().debug("MailSettings event received: Error.");
this->logDebug("MailSettings event received: Error.");
switch (event.error().type())
{
case IMAP_PORT_ISSUE:
@ -1212,20 +1260,20 @@ void GRPCClient::processMailSettingsEvent(MailSettingsEvent const &event)
emit portIssueSMTP();
break;
default:
app().log().error("Unknown mail settings error event received.");
this->logError("Unknown mail settings error event received.");
break;
}
case MailSettingsEvent::kUseSslForSmtpFinished:
app().log().debug("MailSettings event received: UseSslForSmtpFinished.");
this->logDebug("MailSettings event received: UseSslForSmtpFinished.");
emit toggleUseSSLFinished();
break;
case MailSettingsEvent::kChangePortsFinished:
app().log().debug("MailSettings event received: ChangePortsFinished.");
this->logDebug("MailSettings event received: ChangePortsFinished.");
emit changePortFinished();
break;
default:
app().log().error("Unknown MailSettings event received.");
this->logError("Unknown MailSettings event received.");
}
}
@ -1238,19 +1286,19 @@ void GRPCClient::processKeychainEvent(KeychainEvent const &event)
switch (event.event_case())
{
case KeychainEvent::kChangeKeychainFinished:
app().log().debug("Keychain event received: ChangeKeychainFinished.");
this->logDebug("Keychain event received: ChangeKeychainFinished.");
emit changeKeychainFinished();
break;
case KeychainEvent::kHasNoKeychain:
app().log().debug("Keychain event received: HasNoKeychain.");
this->logDebug("Keychain event received: HasNoKeychain.");
emit hasNoKeychain();
break;
case KeychainEvent::kRebuildKeychain:
app().log().debug("Keychain event received: RebuildKeychain.");
this->logDebug("Keychain event received: RebuildKeychain.");
emit rebuildKeychain();
break;
default:
app().log().error("Unknown Keychain event received.");
this->logError("Unknown Keychain event received.");
}
}
@ -1263,23 +1311,23 @@ void GRPCClient::processMailEvent(MailEvent const &event)
switch (event.event_case())
{
case MailEvent::kNoActiveKeyForRecipientEvent:
app().log().debug("Mail event received: kNoActiveKeyForRecipientEvent.");
this->logDebug("Mail event received: kNoActiveKeyForRecipientEvent.");
emit noActiveKeyForRecipient(QString::fromStdString(event.noactivekeyforrecipientevent().email()));
break;
case MailEvent::kAddressChanged:
app().log().debug("Mail event received: AddressChanged.");
this->logDebug("Mail event received: AddressChanged.");
emit addressChanged(QString::fromStdString(event.addresschanged().address()));
break;
case MailEvent::kAddressChangedLogout:
app().log().debug("Mail event received: AddressChangedLogout.");
this->logDebug("Mail event received: AddressChangedLogout.");
emit addressChangedLogout(QString::fromStdString(event.addresschangedlogout().address()));
break;
case MailEvent::kApiCertIssue:
emit apiCertIssue();
app().log().debug("Mail event received: ApiCertIssue.");
this->logDebug("Mail event received: ApiCertIssue.");
break;
default:
app().log().error("Unknown Mail event received.");
this->logError("Unknown Mail event received.");
}
}
@ -1294,25 +1342,28 @@ void GRPCClient::processUserEvent(UserEvent const &event)
case UserEvent::kToggleSplitModeFinished:
{
QString const userID = QString::fromStdString(event.togglesplitmodefinished().userid());
app().log().debug(QString("User event received: ToggleSplitModeFinished (userID = %1).").arg(userID));
this->logDebug(QString("User event received: ToggleSplitModeFinished (userID = %1).").arg(userID));
emit toggleSplitModeFinished(userID);
break;
}
case UserEvent::kUserDisconnected:
{
QString const username = QString::fromStdString(event.userdisconnected().username());
app().log().debug(QString("User event received: UserDisconnected (username = %1).").arg(username));
this->logDebug(QString("User event received: UserDisconnected (username = %1).").arg(username));
emit userDisconnected(username);
break;
}
case UserEvent::kUserChanged:
{
QString const userID = QString::fromStdString(event.userchanged().userid());
app().log().debug(QString("User event received: UserChanged (userID = %1).").arg(userID));
this->logDebug(QString("User event received: UserChanged (userID = %1).").arg(userID));
emit userChanged(userID);
break;
}
default:
app().log().error("Unknown User event received.");
this->logError("Unknown User event received.");
}
}
} // namespace bridgepp

View File

@ -20,10 +20,14 @@
#define BRIDGE_GUI_RPC_CLIENT_H
#include "GRPC/bridge.grpc.pb.h"
#include "../User/User.h"
#include "../Log/Log.h"
#include "bridge.grpc.pb.h"
#include "grpc++/grpc++.h"
#include "User/User.h"
#include "Log.h"
namespace bridgepp
{
typedef grpc::Status (grpc::Bridge::Stub::*SimpleMethod)(grpc::ClientContext *, const google::protobuf::Empty &, google::protobuf::Empty *);
@ -49,6 +53,7 @@ public: // member functions.
~GRPCClient() override = default; ///< Destructor.
GRPCClient &operator=(GRPCClient const &) = delete; ///< Disabled assignment operator.
GRPCClient &operator=(GRPCClient &&) = delete; ///< Disabled move assignment operator.
void setLog(Log *log); ///< Set the log for the client.
bool connectToServer(QString &outError); ///< Establish connection to the gRPC server.
grpc::Status addLogEntry(Log::Level level, QString const &package, QString const &message); ///< Performs the "AddLogEntry" gRPC call.
@ -57,7 +62,7 @@ public: // member functions.
grpc::Status isAutostartOn(bool &outIsOn); ///< Performs the "isAutostartOn" gRPC call.
grpc::Status setIsAutostartOn(bool on); ///< Performs the "setIsAutostartOn" gRPC call.
grpc::Status isBetaEnabled(bool &outEnabled); ///< Performs the "isBetaEnabled" gRPC call.
grpc::Status setisBetaEnabled(bool enabled); ///< Performs the 'setIsBetaEnabled' gRPC call.
grpc::Status setIsBetaEnabled(bool enabled); ///< Performs the 'setIsBetaEnabled' gRPC call.
grpc::Status colorSchemeName(QString &outName); ///< Performs the "colorSchemeName' gRPC call.
grpc::Status setColorSchemeName(QString const &name); ///< Performs the "setColorSchemeName' gRPC call.
grpc::Status currentEmailClient(QString &outName); ///< Performs the 'currentEmailClient' gRPC call.
@ -178,7 +183,7 @@ signals:
void rebuildKeychain();
void certIsReady();
signals: // mail releated events
signals: // mail related events
void noActiveKeyForRecipient(QString const &email); // _ func(email string) `signal:noActiveKeyForRecipient`
void addressChanged(QString const &address); // _ func(address string) `signal:addressChanged`
void addressChangedLogout(QString const &address); // _ func(address string) `signal:addressChangedLogout`
@ -192,6 +197,9 @@ private slots:
void configFolderChanged();
private:
void logDebug(QString const &message); ///< Log an event.
void logError(QString const &message); ///< Log an event.
grpc::Status logGRPCCallStatus(grpc::Status const &status, QString const &callName); ///< Log the status of a gRPC code.
grpc::Status simpleMethod(SimpleMethod method); ///< perform a gRPC call to a bool setter.
grpc::Status setBool(BoolSetter setter, bool value); ///< perform a gRPC call to a bool setter.
grpc::Status getBool(BoolGetter getter, bool &outValue); ///< perform a gRPC call to a bool getter.
@ -201,7 +209,8 @@ private:
grpc::Status getString(StringGetter getter, QString &outValue); ///< Perform a gRPC call to a string getter.
grpc::Status getURLForLocalFile(StringGetter getter, QUrl &outValue); ///< Perform a gRPC call to a string getter, with resulted converted to QUrl for a local file path.
grpc::Status getURL(StringGetter getter, QUrl &outValue); ///< Perform a gRPC call to a string getter, with resulted converted to QUrl.
grpc::Status methodWithStringParam(StringParamMethod method, QString const& str); ///< Perfom a gRPC call that takes a string as a parameter and returns an Empty.
grpc::Status methodWithStringParam(StringParamMethod method, QString const &str); ///< Perform a gRPC call that takes a string as a parameter and returns an Empty.
SPUser parseGRPCUser(grpc::User const &grpcUser); ///< Parse a gRPC user struct and return a User.
std::string getServerCertificate(); ///< Wait until server certificates is generated and retrieve it.
void processAppEvent(grpc::AppEvent const &event); ///< Process an 'App' event.
@ -214,9 +223,13 @@ private:
void processUserEvent(grpc::UserEvent const &event); ///< Process a 'User' event.
private: // data members.
Log *log_ { nullptr }; ///< The log for the GRPC client.
std::shared_ptr<grpc::Channel> channel_ { nullptr }; ///< The gRPC channel.
std::shared_ptr<grpc::Bridge::Stub> stub_ { nullptr }; ///< The gRPC stub (a.k.a. client).
};
}
#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/>.
#include "Pch.h"
#include "Log.h"
namespace bridgepp
{
namespace
{
Log *qtHandlerLog { nullptr }; ///< The log instance handling qt logs.
QMutex qtHandlerMutex; ///< A mutex used to access qtHandlerLog.
//****************************************************************************************************************************************************
/// \param[in] log The log handling qt log entries. Can be null.
//****************************************************************************************************************************************************
void setQtMessageHandlerLog(Log *log)
{
QMutexLocker locker(&qtHandlerMutex);
qtHandlerLog = log;
}
//****************************************************************************************************************************************************
/// \return The log handling qt log entries. Can be null.
//****************************************************************************************************************************************************
Log *qtMessageHandlerLog()
{
QMutexLocker locker(&qtHandlerMutex);
return qtHandlerLog;
}
//****************************************************************************************************************************************************
/// \param[in] type The message type.
@ -30,25 +55,27 @@ namespace
//****************************************************************************************************************************************************
void qtMessageHandler(QtMsgType type, QMessageLogContext const &, QString const &message)
{
static Log &log = app().log();
Log *log = qtMessageHandlerLog();
if (!log)
return;
switch (type)
{
case QtDebugMsg:
log.debug(message);
log->debug(message);
break;
case QtWarningMsg:
log.warn(message);
log->warn(message);
break;
case QtCriticalMsg:
case QtFatalMsg:
log.error(message);
log->error(message);
break;
case QtInfoMsg:
default:
log.info(message);
log->info(message);
break;
}
}
@ -62,18 +89,28 @@ QString logLevelToString(Log::Level level)
{
switch (level)
{
case Log::Level::Panic: return "PANIC";
case Log::Level::Fatal: return "FATAL";
case Log::Level::Error: return "ERROR";
case Log::Level::Warn: return "WARN";
case Log::Level::Info: return "INFO";
case Log::Level::Debug: return "DEBUG";
case Log::Level::Trace: return "TRACE";
default: return "UNKNOWN";
case Log::Level::Panic:
return "PANIC";
case Log::Level::Fatal:
return "FATAL";
case Log::Level::Error:
return "ERROR";
case Log::Level::Warn:
return "WARN";
case Log::Level::Info:
return "INFO";
case Log::Level::Debug:
return "DEBUG";
case Log::Level::Trace:
return "TRACE";
default:
return "UNKNOWN";
}
}
} // anonymous namespace
//****************************************************************************************************************************************************
/// \brief return a string representing the log entry
@ -82,20 +119,18 @@ QString logLevelToString(Log::Level level)
/// \param[in] message The log entry message.
/// \return The string for the log entry
//****************************************************************************************************************************************************
QString logEntryToString(Log::Level level, QString const &message)
QString Log::logEntryToString(Log::Level level, QString const &message)
{
return QString("[%1] %2").arg(logLevelToString(level)).arg(message);
}
return QString("[%1] %2").arg(logLevelToString(level), message);
}
//****************************************************************************************************************************************************
/// the message handle process the message from the Qt logging system.
//****************************************************************************************************************************************************
void Log::installQtMessageHandler()
void Log::registerAsQtMessageHandler()
{
setQtMessageHandlerLog(this);
qInstallMessageHandler(qtMessageHandler);
}
@ -232,3 +267,6 @@ void Log::addEntry(Log::Level level, QString const &message)
stream.flush();
}
}
} // namespace bridgepp

View File

@ -16,8 +16,12 @@
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
#ifndef BRIDGE_GUI_LOG_H
#define BRIDGE_GUI_LOG_H
#ifndef BRIDGE_PP_LOG_H
#define BRIDGE_PP_LOG_H
namespace bridgepp
{
//****************************************************************************************************************************************************
@ -27,7 +31,7 @@ class Log : public QObject
{
Q_OBJECT
public: // data types.
/// \brief Log level class. The list matches [logrus log levels](https://pkg.go.dev/github.com/sirupsen/logrus).
/// \brief Log level class. The list matches [loggers log levels](https://pkg.go.dev/github.com/sirupsen/logrus).
enum class Level
{
Panic, ///< Panic log level.
@ -39,8 +43,9 @@ public: // data types.
Trace ///< Trace log level.
};
public: // static member functions
static void installQtMessageHandler(); ///< Install the Qt message handler.
public: // static member functions.
static QString logEntryToString(Log::Level level, QString const &message); ///< Return a string describing a log entry.
public: // member functions.
Log(); ///< Default constructor.
@ -54,6 +59,7 @@ public: // member functions.
Level level() const; ///< Get the log level.
void setEchoInConsole(bool value); ///< Set if the log entries should be echoed in STDOUT/STDERR.
bool echoInConsole() const; ///< Check if the log entries should be echoed in STDOUT/STDERR.
void registerAsQtMessageHandler(); ///< Install the Qt message handler.
public slots:
void panic(QString const &message); ///< Adds an panic entry to the log.
@ -79,4 +85,7 @@ private: // data members
};
#endif //BRIDGE_GUI_LOG_H
} // namespace bridgepp
#endif //BRIDGE_PP_LOG_H

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/>.
#include "Pch.h"
#include "Overseer.h"
#include "Exception.h"
#include "../Exception/Exception.h"
namespace bridgepp
{
//****************************************************************************************************************************************************
@ -112,3 +115,6 @@ Worker *Overseer::worker() const
{
return worker_;
}
} // namespace bridgepp

View File

@ -16,13 +16,17 @@
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
#ifndef BRIDGE_GUI_OVERSEER_H
#define BRIDGE_GUI_OVERSEER_H
#ifndef BRIDGE_PP_OVERSEER_H
#define BRIDGE_PP_OVERSEER_H
#include "Worker.h"
namespace bridgepp
{
//****************************************************************************************************************************************************
/// \brief Overseer used to manager a worker instance and its associated thread.
//****************************************************************************************************************************************************
@ -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.
#endif //BRIDGE_GUI_OVERSEER_H
} // namespace bridgepp
#endif //BRIDGE_PP_OVERSEER_H

View File

@ -16,8 +16,13 @@
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
#ifndef BRIDGE_GUI_WORKER_H
#define BRIDGE_GUI_WORKER_H
#ifndef BRIDGE_PP_WORKER_H
#define BRIDGE_PP_WORKER_H
namespace bridgepp
{
//****************************************************************************************************************************************************
/// \brief Pure virtual class for worker intended to perform a threaded operation.
@ -26,7 +31,9 @@ class Worker: public QObject
{
Q_OBJECT
public: // member functions
explicit Worker(QObject *parent) : QObject(parent) {} ///< Default constructor.
explicit Worker(QObject *parent)
: QObject(parent)
{} ///< Default constructor.
Worker(Worker const &) = delete; ///< Disabled copy-constructor.
Worker(Worker &&) = delete; ///< Disabled assignment copy-constructor.
~Worker() override = default; ///< Destructor.
@ -43,4 +50,7 @@ signals:
};
#endif //BRIDGE_GUI_WORKER_H
} // namespace bridgepp
#endif //BRIDGE_PP_WORKER_H

View File

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