Files
proton-bridge/internal/frontend/bridge-gui/GRPC/GRPCClient.cpp
2022-09-01 13:21:31 +02:00

1310 lines
57 KiB
C++

// 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 "GRPCClient.h"
#include "GRPCUtils.h"
#include "QMLBackend.h"
#include "Exception.h"
#include "AppController.h"
using namespace google::protobuf;
using namespace grpc;
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.
}
//****************************************************************************************************************************************************
/// \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
/// \return server certificate generated by Bridge
//****************************************************************************************************************************************************
std::string GRPCClient::getServerCertificate()
{
const QString filename = _userConfigDir() + "/" + certFile;
QFile file(filename);
// 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.
if (!file.exists())
{
// wait for file creation
QFileSystemWatcher watcher(this);
if (!watcher.addPath(_userConfigDir()))
throw Exception("Failed to watch User Config Directory");
connect(&watcher, &QFileSystemWatcher::directoryChanged, this, &GRPCClient::configFolderChanged);
// set up an eventLoop to wait for the certIsReady signal or timeout.
QTimer timer;
timer.setSingleShot(true);
QEventLoop loop;
connect(this, &GRPCClient::certIsReady, &loop, &QEventLoop::quit);
connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
timer.start(maxCertificateWaitMsecs);
loop.exec();
// timeout case.
if(!timer.isActive())
throw Exception("Server failed to generate certificate on time");
//else certIsReadySignal.
}
if (!file.open(QFile::ReadOnly))
throw Exception("Failed to read the server certificate");
QByteArray qbaCert = file.readAll();
std::string cert(qbaCert.constData(), qbaCert.length());
file.close();
return cert;
}
//****************************************************************************************************************************************************
/// \brief Action on UserConfig directory changes, looking for the certificate creation
//****************************************************************************************************************************************************
void GRPCClient::configFolderChanged()
{
QFile cert(_userConfigDir() + "/" + certFile);
if (cert.exists())
emit certIsReady();
}
//****************************************************************************************************************************************************
/// \param[out] outError If the function returns false, this variable contains a description of the error.
/// \return true iff the connection was successful.
//****************************************************************************************************************************************************
bool GRPCClient::connectToServer(QString &outError)
{
try
{
SslCredentialsOptions opts;
opts.pem_root_certs += this->getServerCertificate();
channel_ = CreateChannel("127.0.0.1:9292", grpc::SslCredentials(opts));
if (!channel_)
throw Exception("Channel creation failed.");
stub_ = Bridge::NewStub(channel_);
if (!stub_)
throw Exception("Stub creation failed.");
QDateTime const giveUpTime = QDateTime::currentDateTime().addSecs(maxConnectionTimeSecs); // if we reach giveUpTime without connecting, we give up
int i = 0;
while (true)
{
app().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.
if (QDateTime::currentDateTime() > giveUpTime)
throw Exception("Connection to the RPC server failed.");
}
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.");
return true;
}
catch (Exception const &e)
{
outError = e.qwhat();
return false;
}
}
//****************************************************************************************************************************************************
/// \param[in] level The level of the log entry.
/// \param[in] package The package (component) that triggered the entry.
/// \param[in] message The message.
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::addLogEntry(Log::Level level, QString const &package, QString const &message)
{
grpc::ClientContext ctx;
AddLogEntryRequest request;
request.set_level(logLevelToGRPC(level));
request.set_package(package.toStdString());
request.set_message(message.toStdString());
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);
}
//****************************************************************************************************************************************************
/// \param[out] outIsFirst The value for the property.
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::isFirstGUIStart(bool &outIsFirst)
{
return this->getBool(&Bridge::Stub::IsFirstGuiStart, outIsFirst);
}
//****************************************************************************************************************************************************
/// \param[out] outIsOn The value for the property.
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::isAutostartOn(bool &outIsOn)
{
return this->getBool(&Bridge::Stub::IsAutostartOn, outIsOn);
}
//****************************************************************************************************************************************************
/// \param[in] on The new value for the property.
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::setIsAutostartOn(bool on)
{
return this->setBool(&Bridge::Stub::SetIsAutostartOn, on);
}
//****************************************************************************************************************************************************
/// \param[out] outEnabled The new value for the property.
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::isBetaEnabled(bool &outEnabled)
{
return this->getBool(&Bridge::Stub::IsBetaEnabled, outEnabled);
}
//****************************************************************************************************************************************************
/// \param[in] enabled The new value for the property.
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::setisBetaEnabled(bool enabled)
{
return this->setBool(&Bridge::Stub::SetIsBetaEnabled, enabled);
}
//****************************************************************************************************************************************************
/// \param[out] outName The value for the property.
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::colorSchemeName(QString &outName)
{
return this->getString(&Bridge::Stub::ColorSchemeName, outName);
}
//****************************************************************************************************************************************************
/// \param[in] name The new value for the property.
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::setColorSchemeName(QString const &name)
{
return this->setString(&Bridge::Stub::SetColorSchemeName, name);
}
//****************************************************************************************************************************************************
/// \param[out] outName The value for the property.
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::currentEmailClient(QString &outName)
{
return this->getString(&Bridge::Stub::CurrentEmailClient, outName);
}
//****************************************************************************************************************************************************
/// \param[in] description The description of the bug.
/// \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.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::reportBug(QString const &description, QString const &address, QString const &emailClient, bool includeLogs)
{
grpc::ClientContext ctx;
ReportBugRequest request;
request.set_ostype(QSysInfo::productType().toStdString());
request.set_osversion(QSysInfo::prettyProductName().toStdString());
request.set_description(description.toStdString());
request.set_address(address.toStdString());
request.set_emailclient(emailClient.toStdString());
request.set_includelogs(includeLogs);
return stub_->ReportBug(&ctx, request, &empty);
}
//****************************************************************************************************************************************************
/// \param[out] outUseSSL The value for the property.
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::useSSLForSMTP(bool &outUseSSL)
{
return this->getBool(&Bridge::Stub::UseSslForSmtp, outUseSSL);
}
//****************************************************************************************************************************************************
/// \param[in] useSSL The new value for the property.
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::setUseSSLForSMTP(bool useSSL)
{
return this->setBool(&Bridge::Stub::SetUseSslForSmtp, useSSL);
}
//****************************************************************************************************************************************************
/// \param[out] outPort The port.
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::portIMAP(int &outPort)
{
return this->getInt32(&Bridge::Stub::ImapPort, outPort);
}
//****************************************************************************************************************************************************
/// \param[out] outPort The port.
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::portSMTP(int &outPort)
{
return this->getInt32(&Bridge::Stub::SmtpPort, outPort);
}
//****************************************************************************************************************************************************
/// \param[in] portIMAP The IMAP port.
/// \param[in] portSMTP The SMTP port.
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::changePorts(int portIMAP, int portSMTP)
{
ClientContext ctx;
ChangePortsRequest request;
request.set_imapport(portIMAP);
request.set_smtpport(portSMTP);
return stub_->ChangePorts(&ctx, request, &empty);
}
//****************************************************************************************************************************************************
/// \param[in] outEnabled The value for the property.
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::isDoHEnabled(bool &outEnabled)
{
return this->getBool(&Bridge::Stub::IsDoHEnabled, outEnabled);
}
//****************************************************************************************************************************************************
/// \param[in] enabled The new value for the property.
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::setIsDoHEnabled(bool enabled)
{
return this->setBool(&Bridge::Stub::SetIsDoHEnabled, enabled);
}
//****************************************************************************************************************************************************
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::quit()
{
grpc::ClientContext ctx;
return stub_->Quit(&ctx, empty, &empty);
}
//****************************************************************************************************************************************************
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::restart()
{
grpc::ClientContext ctx;
return stub_->Restart(&ctx, empty, &empty);
}
//****************************************************************************************************************************************************
/// \param[in] port The port to check.
/// \param[out] outFree The result of the check.
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::isPortFree(qint32 port, bool &outFree)
{
grpc::ClientContext ctx;
Int32Value p;
p.set_value(port);
BoolValue isFree;
Status result = stub_->IsPortFree(&ctx, p, &isFree);
if (result.ok())
outFree = isFree.value();
return result;
}
//****************************************************************************************************************************************************
/// \param[out] outValue The value for the property.
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::showOnStartup(bool &outValue)
{
return this->getBool(&Bridge::Stub::ShowOnStartup, outValue);
}
//****************************************************************************************************************************************************
/// \param[out] outValue The value for the property.
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::showSplashScreen(bool &outValue)
{
return this->getBool(&Bridge::Stub::ShowSplashScreen, outValue);
}
//****************************************************************************************************************************************************
/// \param[out] outGoos The value for the property.
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::goos(QString &outGoos)
{
return this->getString(&Bridge::Stub::GoOs, outGoos);
}
//****************************************************************************************************************************************************
/// \param[out] outPath The value for the property.
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::logsPath(QUrl &outPath)
{
return this->getURLForLocalFile(&Bridge::Stub::LogsPath, outPath);
}
//****************************************************************************************************************************************************
/// \param[out] outPath The value for the property.
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::licensePath(QUrl &outPath)
{
return this->getURLForLocalFile(&Bridge::Stub::LicensePath, outPath);
}
//****************************************************************************************************************************************************
/// \param[out] outUrl The value for the property.
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::dependencyLicensesLink(QUrl &outUrl)
{
return this->getURL(&Bridge::Stub::DependencyLicensesLink, outUrl);
}
//****************************************************************************************************************************************************
/// \param[out] outVersion The value for the property.
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::version(QString &outVersion)
{
return this->getString(&Bridge::Stub::Version, outVersion);
}
//****************************************************************************************************************************************************
/// \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);
}
//****************************************************************************************************************************************************
/// \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);
}
//****************************************************************************************************************************************************
/// \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);
}
//****************************************************************************************************************************************************
/// \param[out] outEnabled The value for the property.
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::isCacheOnDiskEnabled(bool &outEnabled)
{
return getBool(&Bridge::Stub::IsCacheOnDiskEnabled, outEnabled);
}
//****************************************************************************************************************************************************
/// \param[out] outPath The value for the property.
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::diskCachePath(QUrl &outPath)
{
return this->getURLForLocalFile(&Bridge::Stub::DiskCachePath, outPath);
}
//****************************************************************************************************************************************************
/// \param[in] enabled Should the cache be enabled.
/// \param[in] path The value for the property.
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::changeLocalCache(bool enabled, QUrl const &path)
{
grpc::ClientContext ctx;
ChangeLocalCacheRequest request;
request.set_enablediskcache(enabled);
request.set_diskcachepath(path.path(QUrl::FullyDecoded).toStdString());
return stub_->ChangeLocalCache(&ctx, request, &empty);
}
//****************************************************************************************************************************************************
/// \param[in] username The username.
/// \param[in] password The password.
/// \return the status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::login(QString const &username, QString const &password)
{
grpc::ClientContext ctx;
LoginRequest request;
request.set_username(username.toStdString());
request.set_password(password.toStdString());
return stub_->Login(&ctx, request, &empty);
}
//****************************************************************************************************************************************************
/// \param[in] username The username.
/// \param[in] code The The 2FA code.
/// \return the status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::login2FA(QString const &username, QString const &code)
{
grpc::ClientContext ctx;
LoginRequest request;
request.set_username(username.toStdString());
request.set_password(code.toStdString());
return stub_->Login2FA(&ctx, request, &empty);
}
//****************************************************************************************************************************************************
/// \param[in] username The username.
/// \param[in] password The password.
/// \return the status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::login2Passwords(QString const &username, QString const &password)
{
grpc::ClientContext ctx;
LoginRequest request;
request.set_username(username.toStdString());
request.set_password(password.toStdString());
return stub_->Login2Passwords(&ctx, request, &empty);
}
//****************************************************************************************************************************************************
/// \param[in] username The username.
/// \return the status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::loginAbort(QString const &username)
{
grpc::ClientContext ctx;
LoginAbortRequest request;
request.set_username(username.toStdString());
return stub_->LoginAbort(&ctx, request, &empty);
}
//****************************************************************************************************************************************************
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::checkUpdate()
{
return this->simpleMethod(&Bridge::Stub::CheckUpdate);
}
//****************************************************************************************************************************************************
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::installUpdate()
{
return this->simpleMethod(&Bridge::Stub::InstallUpdate);
}
//****************************************************************************************************************************************************
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::setIsAutomaticUpdateOn(bool on)
{
return this->setBool(&Bridge::Stub::SetIsAutomaticUpdateOn, on);
}
//****************************************************************************************************************************************************
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::isAutomaticUpdateOn(bool &isOn)
{
return this->getBool(&Bridge::Stub::IsAutomaticUpdateOn, isOn);
}
//****************************************************************************************************************************************************
/// \param[in] userID The user ID.
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::logoutUser(QString const &userID)
{
return methodWithStringParam(&Bridge::Stub::LogoutUser, userID);
}
//****************************************************************************************************************************************************
/// \param[in] userID The user ID.
/// \return the status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::removeUser(QString const &userID)
{
return methodWithStringParam(&Bridge::Stub::RemoveUser, userID);
}
//****************************************************************************************************************************************************
/// \param[in] userID The user ID.
/// \param[in] address The email address.
/// \return the status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::configureAppleMail(QString const &userID, QString const &address)
{
ClientContext ctx;
ConfigureAppleMailRequest request;
request.set_userid(userID.toStdString());
request.set_address(address.toStdString());
return stub_->ConfigureUserAppleMail(&ctx, request, &empty);
}
//****************************************************************************************************************************************************
/// \param[in] userID The userID.
/// \param[in] active the new status for the mode.
/// \return The status for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::setUserSplitMode(QString const &userID, bool active)
{
ClientContext ctx;
UserSplitModeRequest request;
request.set_userid(userID.toStdString());
request.set_active(active);
return stub_->SetUserSplitMode(&ctx, request, &empty);
}
//****************************************************************************************************************************************************
/// \param[out] outUsers The user list.
/// \return The status code for the gRPC call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::getUserList(QList<SPUser> &outUsers)
{
outUsers.clear();
ClientContext ctx;
UserListResponse response;
Status status = stub_->GetUserList(&ctx, empty, &response);
if (!status.ok())
return status;
for (int i = 0; i < response.users_size(); ++i)
outUsers.append(parsegrpcUser(response.users(i)));
return status;
}
//****************************************************************************************************************************************************
/// \param[in] userID The userID.
/// \param[out] outUser The user.
/// \return The status code for the operation.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::getUser(QString const &userID, ::SPUser &outUser)
{
ClientContext ctx;
StringValue s;
s.set_value(userID.toStdString());
grpc::User grpcUser;
Status status = stub_->GetUser(&ctx, s, &grpcUser);
if (status.ok())
outUser = parsegrpcUser(grpcUser);
return grpc::Status();
}
//****************************************************************************************************************************************************
/// \param[out] outKeychains The list of available keychains.
/// \return The status for the gRPC coll.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::availableKeychains(QStringList &outKeychains)
{
outKeychains.clear();
ClientContext ctx;
AvailableKeychainsResponse response;
Status status = stub_->AvailableKeychains(&ctx, empty, &response);
if (!status.ok())
return status;
for (int i = 0; i < response.keychains_size(); ++i)
outKeychains.append(QString::fromStdString(response.keychains(i)));
return status;
}
//****************************************************************************************************************************************************
/// \param[out] outKeychain The current keychain.
/// \return The status for the gRPC coll.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::currentKeychain(QString &outKeychain)
{
return this->getString(&Bridge::Stub::CurrentKeychain, outKeychain);
}
//****************************************************************************************************************************************************
/// \param[in] keychain The new current keychain.
/// \return The status for the gRPC coll.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::setCurrentKeychain(QString const &keychain)
{
return this->setString(&Bridge::Stub::SetCurrentKeychain, keychain);
}
//****************************************************************************************************************************************************
/// \return The status for the gRPC coll.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::startEventStream()
{
grpc::ClientContext ctx;
EventStreamRequest request;
request.set_clientplatform(QSysInfo::prettyProductName().toStdString());
std::unique_ptr<grpc::ClientReader<grpc::StreamEvent>> reader(stub_->StartEventStream(&ctx, request));
grpc::StreamEvent event;
while (reader->Read(&event))
{
switch (event.event_case())
{
case grpc::StreamEvent::kApp:
this->processAppEvent(event.app());
break;
case grpc::StreamEvent::kLogin:
this->processLoginEvent(event.login());
break;
case grpc::StreamEvent::kUpdate:
this->processUpdateEvent(event.update());
break;
case grpc::StreamEvent::kCache:
this->processCacheEvent(event.cache());
break;
case grpc::StreamEvent::kMailSettings:
this->processMailSettingsEvent(event.mailsettings());
break;
case grpc::StreamEvent::kKeychain:
this->processKeychainEvent(event.keychain());
break;
case grpc::StreamEvent::kMail:
this->processMailEvent(event.mail());
break;
case grpc::StreamEvent::kUser:
this->processUserEvent(event.user());
break;
default:
app().log().debug(QString("Unknown stream event type: %1").arg(event.event_case()));
}
}
return reader->Finish();
}
//****************************************************************************************************************************************************
/// \return The status for the call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::stopEventStream()
{
grpc::ClientContext ctx;
return stub_->StopEventStream(&ctx, empty, &empty);
}
//****************************************************************************************************************************************************
/// \param[in] method the gRPC method to call.
/// \return The status for the call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::simpleMethod(SimpleMethod method)
{
ClientContext ctx;
return ((*stub_).*method)(&ctx, empty, &empty);
}
//****************************************************************************************************************************************************
/// \param[in] setter The setter member function.
/// \param[in] value The bool value.
/// \return The status code for the call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::setBool(BoolSetter setter, bool value)
{
grpc::ClientContext ctx;
BoolValue v;
v.set_value(value);
return ((*stub_).*setter)(&ctx, v, &empty);
}
//****************************************************************************************************************************************************
/// \param[in] getter The getter member function.
/// \param[out] outValue The boolean value.
/// \return The status code for the call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::getBool(BoolGetter getter, bool &outValue)
{
grpc::ClientContext ctx;
BoolValue v;
Status result = ((*stub_).*getter)(&ctx, empty, &v);
if (result.ok())
outValue = v.value();
return result;
}
//****************************************************************************************************************************************************
/// \param[in] setter The setter member function.
/// \param[in] value The bool value.
/// \return The status code for the call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::setInt32(Int32Setter setter, int value)
{
grpc::ClientContext ctx;
Int32Value i;
i.set_value(value);
return ((*stub_).*setter)(&ctx, i, &empty);
}
//****************************************************************************************************************************************************
/// \param[in] getter The getter member function.
/// \param[out] outValue The boolean value.
/// \return The status code for the call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::getInt32(Int32Getter getter, int &outValue)
{
grpc::ClientContext ctx;
Int32Value i;
Status result = ((*stub_).*getter)(&ctx, empty, &i);
if (result.ok())
outValue = i.value();
return result;
}
//****************************************************************************************************************************************************
/// \param[in] setter The setter member function.
/// \param[in] value The string value.
/// \return The status code for the call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::setString(StringSetter setter, QString const &value)
{
grpc::ClientContext ctx;
StringValue s;
s.set_value(value.toStdString());
return ((*stub_).*setter)(&ctx, s, &empty);
}
//****************************************************************************************************************************************************
/// \param[in] getter The getter member function.
/// \param[out] outValue The string value.
/// \return The status code for the call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::getString(StringGetter getter, QString &outValue)
{
grpc::ClientContext ctx;
StringValue v;
Status result = ((*stub_).*getter)(&ctx, empty, &v);
if (result.ok())
outValue = QString::fromStdString(v.value());
return result;
}
//****************************************************************************************************************************************************
/// \param[in] getter The getter member function.
/// \param[out] outValue The URL value.
/// \return The status code for the call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::getURLForLocalFile(StringGetter getter, QUrl &outValue)
{
QString str;
grpc::Status status = this->getString(getter, str);
if (status.ok())
outValue = QUrl::fromLocalFile(str);
return status;
}
//****************************************************************************************************************************************************
/// \param[in] getter The getter member function.
/// \param[out] outValue The URL value.
/// \return The status code for the call.
//****************************************************************************************************************************************************
grpc::Status GRPCClient::getURL(StringGetter getter, QUrl &outValue)
{
QString str;
grpc::Status status = this->getString(getter, str);
if (status.ok())
outValue = QUrl(str);
return status;
}
//****************************************************************************************************************************************************
/// \param[in] method The method to call.
/// \param[in] str The string parameter.
/// \return The status code for the call
//****************************************************************************************************************************************************
grpc::Status GRPCClient::methodWithStringParam(StringParamMethod method, QString const &str)
{
ClientContext ctx;
StringValue s;
s.set_value(str.toStdString());
return ((*stub_).*method)(&ctx, s, &empty);
}
//****************************************************************************************************************************************************
/// \param[in] event The event.
//****************************************************************************************************************************************************
void GRPCClient::processAppEvent(AppEvent const &event)
{
switch (event.event_case())
{
case AppEvent::kInternetStatus:
app().log().debug("App event received: InternetStatus.");
emit internetStatus(event.internetstatus().connected());
break;
case AppEvent::kToggleAutostartFinished:
app().log().debug("App event received: AutostartFinished.");
emit toggleAutostartFinished();
break;
case AppEvent::kResetFinished:
app().log().debug("App event received: ResetFinished.");
emit resetFinished();
break;
case AppEvent::kReportBugFinished:
app().log().debug("App event received: ReportBugFinished.");
emit reportBugFinished();
break;
case AppEvent::kReportBugSuccess:
app().log().debug("App event received: ReportBugSuccess.");
emit reportBugSuccess();
break;
case AppEvent::kReportBugError:
app().log().debug("App event received: ReportBugError.");
emit reportBugError();
break;
case AppEvent::kShowMainWindow:
app().log().debug("App event received: ShowMainWindow.");
emit showMainWindow();
break;
default:
app().log().error("Unknown App event received.");
}
}
//****************************************************************************************************************************************************
/// \param[in] event The event.
//****************************************************************************************************************************************************
void GRPCClient::processLoginEvent(LoginEvent const &event)
{
switch (event.event_case())
{
case LoginEvent::kError:
{
app().log().debug("Login event received: Error.");
LoginErrorEvent const &error = event.error();
switch (error.type())
{
case USERNAME_PASSWORD_ERROR:
emit loginUsernamePasswordError(QString::fromStdString(error.message()));
break;
case FREE_USER:
emit loginFreeUserError();
break;
case CONNECTION_ERROR:
emit loginConnectionError(QString::fromStdString(error.message()));
break;
case TFA_ERROR:
emit login2FAError(QString::fromStdString(error.message()));
break;
case TFA_ABORT:
emit login2FAErrorAbort(QString::fromStdString(error.message()));
break;
case TWO_PASSWORDS_ERROR:
emit login2PasswordError(QString::fromStdString(error.message()));
break;
case TWO_PASSWORDS_ABORT:
emit login2PasswordErrorAbort(QString::fromStdString(error.message()));
break;
default:
app().log().debug("Unknown login error event received.");
break;
}
break;
}
case LoginEvent::kTfaRequested:
app().log().debug("Login event received: TfaRequested.");
emit login2FARequested(QString::fromStdString(event.tfarequested().username()));
break;
case LoginEvent::kTwoPasswordRequested:
app().log().debug("Login event received: TwoPasswordRequested.");
emit login2PasswordRequested();
break;
case LoginEvent::kFinished:
app().log().debug("Login event received: Finished.");
emit loginFinished(QString::fromStdString(event.finished().userid()));
break;
case LoginEvent::kAlreadyLoggedIn:
app().log().debug("Login event received: AlreadyLoggedIn.");
emit loginAlreadyLoggedIn(QString::fromStdString(event.finished().userid()));
break;
default:
app().log().error("Unknown Login event received.");
break;
}
}
//****************************************************************************************************************************************************
/// \param[in] event The event.
//****************************************************************************************************************************************************
void GRPCClient::processUpdateEvent(UpdateEvent const &event)
{
switch (event.event_case())
{
case UpdateEvent::kError:
{
app().log().debug("Update event received: Error.");
UpdateErrorEvent const &errorEvent = event.error();
switch (errorEvent.type())
{
case UPDATE_MANUAL_ERROR:
emit updateManualError();
break;
case UPDATE_FORCE_ERROR:
emit updateForceError();
break;
case UPDATE_SILENT_ERROR:
emit updateSilentError();
break;
default:
app().log().error("Unknown update error received.");
break;
}
break;
}
case UpdateEvent::kManualReady:
app().log().debug("Update event received: ManualReady.");
emit updateManualReady(QString::fromStdString(event.manualready().version()));
break;
case UpdateEvent::kManualRestartNeeded:
app().log().debug("Update event received: kManualRestartNeeded.");
emit updateManualRestartNeeded();
break;
case UpdateEvent::kForce:
app().log().debug("Update event received: kForce.");
emit updateForce(QString::fromStdString(event.force().version()));
break;
case UpdateEvent::kSilentRestartNeeded:
app().log().debug("Update event received: kSilentRestartNeeded.");
emit updateSilentRestartNeeded();
break;
case UpdateEvent::kIsLatestVersion:
app().log().debug("Update event received: kIsLatestVersion.");
emit updateIsLatestVersion();
break;
case UpdateEvent::kCheckFinished:
app().log().debug("Update event received: kCheckFinished.");
emit checkUpdatesFinished();
break;
default:
app().log().error("Unknown Update event received.");
break;
}
}
//****************************************************************************************************************************************************
/// \param[in] event The event.
//****************************************************************************************************************************************************
void GRPCClient::processCacheEvent(CacheEvent const &event)
{
switch (event.event_case())
{
case CacheEvent::kError:
{
switch (event.error().type())
{
case CACHE_UNAVAILABLE_ERROR:
emit cacheUnavailable();
break;
case CACHE_CANT_MOVE_ERROR:
emit cacheCantMove();
break;
case DISK_FULL:
emit diskFull();
break;
default:
app().log().error("Unknown cache error event received.");
break;
}
break;
}
case CacheEvent::kLocationChangedSuccess:
app().log().debug("Cache event received: LocationChangedSuccess.");
emit cacheLocationChangeSuccess();
break;
case CacheEvent::kChangeLocalCacheFinished:
emit cacheLocationChangeSuccess();
app().log().debug("Cache event received: ChangeLocalCacheFinished.");
break;
case CacheEvent::kIsCacheOnDiskEnabledChanged:
app().log().debug("Cache event received: IsCacheOnDiskEnabledChanged.");
emit isCacheOnDiskEnabledChanged(event.iscacheondiskenabledchanged().enabled());
break;
case CacheEvent::kDiskCachePathChanged:
app().log().debug("Cache event received: DiskCachePathChanged.");
emit diskCachePathChanged(QUrl::fromLocalFile(QString::fromStdString(event.diskcachepathchanged().path())));
break;
default:
app().log().error("Unknown Cache event received.");
}
}
//****************************************************************************************************************************************************
/// \param[in] event The event.
//****************************************************************************************************************************************************
void GRPCClient::processMailSettingsEvent(MailSettingsEvent const &event)
{
switch (event.event_case())
{
case MailSettingsEvent::kError:
app().log().debug("MailSettings event received: Error.");
switch (event.error().type())
{
case IMAP_PORT_ISSUE:
emit portIssueIMAP();
break;
case SMTP_PORT_ISSUE:
emit portIssueSMTP();
break;
default:
app().log().error("Unknown mail settings error event received.");
break;
}
case MailSettingsEvent::kUseSslForSmtpFinished:
app().log().debug("MailSettings event received: UseSslForSmtpFinished.");
emit toggleUseSSLFinished();
break;
case MailSettingsEvent::kChangePortsFinished:
app().log().debug("MailSettings event received: ChangePortsFinished.");
emit changePortFinished();
break;
default:
app().log().error("Unknown MailSettings event received.");
}
}
//****************************************************************************************************************************************************
/// \param[in] event The event.
//****************************************************************************************************************************************************
void GRPCClient::processKeychainEvent(KeychainEvent const &event)
{
switch (event.event_case())
{
case KeychainEvent::kChangeKeychainFinished:
app().log().debug("Keychain event received: ChangeKeychainFinished.");
emit changeKeychainFinished();
break;
case KeychainEvent::kHasNoKeychain:
app().log().debug("Keychain event received: HasNoKeychain.");
emit hasNoKeychain();
break;
case KeychainEvent::kRebuildKeychain:
app().log().debug("Keychain event received: RebuildKeychain.");
emit rebuildKeychain();
break;
default:
app().log().error("Unknown Keychain event received.");
}
}
//****************************************************************************************************************************************************
/// \param[in] event The event.
//****************************************************************************************************************************************************
void GRPCClient::processMailEvent(MailEvent const &event)
{
switch (event.event_case())
{
case MailEvent::kNoActiveKeyForRecipientEvent:
app().log().debug("Mail event received: kNoActiveKeyForRecipientEvent.");
emit noActiveKeyForRecipient(QString::fromStdString(event.noactivekeyforrecipientevent().email()));
break;
case MailEvent::kAddressChanged:
app().log().debug("Mail event received: AddressChanged.");
emit addressChanged(QString::fromStdString(event.addresschanged().address()));
break;
case MailEvent::kAddressChangedLogout:
app().log().debug("Mail event received: AddressChangedLogout.");
emit addressChangedLogout(QString::fromStdString(event.addresschangedlogout().address()));
break;
case MailEvent::kApiCertIssue:
emit apiCertIssue();
app().log().debug("Mail event received: ApiCertIssue.");
break;
default:
app().log().error("Unknown Mail event received.");
}
}
//****************************************************************************************************************************************************
/// \param[in] event The event.
//****************************************************************************************************************************************************
void GRPCClient::processUserEvent(UserEvent const &event)
{
switch (event.event_case())
{
case UserEvent::kToggleSplitModeFinished:
{
QString const userID = QString::fromStdString(event.togglesplitmodefinished().userid());
app().log().debug(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));
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));
emit userChanged(userID);
break;
}
default:
app().log().error("Unknown User event received.");
}
}