/**
* Copyright (C) 2021 Saturneric
*
* This file is part of GpgFrontend.
*
* GpgFrontend 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.
*
* GpgFrontend 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 GpgFrontend. If not, see .
*
* The initial version of the source code is inherited from
* the gpg4usb project, which is under GPL-3.0-or-later.
*
* All the source code of GpgFrontend was modified and released by
* Saturneric starting on May 12, 2021.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
*/
#include "UserInterfaceUtils.h"
#include
#include "dialog/WaitingDialog.h"
#include "core/result_analyse/GpgResultAnalyse.h"
#include "ui/SignalStation.h"
#include "ui/mail/SendMailDialog.h"
#include "ui/settings/GlobalSettingStation.h"
#include "ui/widgets/InfoBoardWidget.h"
#include "ui/widgets/TextEdit.h"
namespace GpgFrontend::UI {
std::unique_ptr
GpgFrontend::UI::CommonUtils::instance_ = nullptr;
#ifdef SMTP_SUPPORT
void send_an_email(QWidget* parent, InfoBoardWidget* info_board,
const QString& text, bool attach_signature) {
info_board->AddOptionalAction(_("Send Encrypted Mail"), [=]() {
bool smtp_enabled = false;
try {
smtp_enabled = GlobalSettingStation::GetInstance().GetUISettings().lookup(
"smtp.enable");
} catch (...) {
LOG(INFO) << "Reading smtp settings error";
}
if (smtp_enabled) {
auto dialog = new SendMailDialog(text, parent);
dialog->SetContentEncryption(false);
dialog->SetAttachSignature(attach_signature);
dialog->show();
} else {
QMessageBox::warning(nullptr, _("Function Disabled"),
_("Please go to the settings interface to "
"enable and configure this function."));
}
});
}
#endif
void show_verify_details(QWidget* parent, InfoBoardWidget* info_board,
GpgError error, const GpgVerifyResult& verify_result) {
// take out result
info_board->ResetOptionActionsMenu();
info_board->AddOptionalAction("Show Verify Details", [=]() {
VerifyDetailsDialog(parent, error, verify_result);
});
}
void import_unknown_key_from_keyserver(QWidget* parent,
const GpgVerifyResultAnalyse& verify_res) {
QMessageBox::StandardButton reply;
reply = QMessageBox::question(
parent, _("Public key not found locally"),
_("There is no target public key content in local for GpgFrontend to "
"gather enough information about this Signature. Do you want to "
"import the public key from Keyserver now?"),
QMessageBox::Yes | QMessageBox::No);
if (reply == QMessageBox::Yes) {
auto dialog = KeyServerImportDialog(true, parent);
auto key_ids = std::make_unique();
auto* signature = verify_res.GetSignatures();
while (signature != nullptr) {
LOG(INFO) << "signature fpr" << signature->fpr;
key_ids->push_back(signature->fpr);
signature = signature->next;
}
dialog.show();
dialog.SlotImport(key_ids);
}
}
void refresh_info_board(InfoBoardWidget* info_board, int status,
const std::string& report_text) {
if (status < 0)
info_board->SlotRefresh(QString::fromStdString(report_text),
INFO_ERROR_CRITICAL);
else if (status > 0)
info_board->SlotRefresh(QString::fromStdString(report_text), INFO_ERROR_OK);
else
info_board->SlotRefresh(QString::fromStdString(report_text),
INFO_ERROR_WARN);
}
void process_result_analyse(TextEdit* edit, InfoBoardWidget* info_board,
const GpgResultAnalyse& result_analyse) {
info_board->AssociateTabWidget(edit->tab_widget_);
refresh_info_board(info_board, result_analyse.GetStatus(),
result_analyse.GetResultReport());
}
void process_result_analyse(TextEdit* edit, InfoBoardWidget* info_board,
const GpgResultAnalyse& result_analyse_a,
const GpgResultAnalyse& result_analyse_b) {
LOG(INFO) << "process_result_analyse Started";
info_board->AssociateTabWidget(edit->tab_widget_);
refresh_info_board(
info_board,
std::min(result_analyse_a.GetStatus(), result_analyse_b.GetStatus()),
result_analyse_a.GetResultReport() + result_analyse_b.GetResultReport());
}
void process_operation(QWidget* parent, const std::string& waiting_title,
const std::function& func) {
auto thread = QThread::create(func);
QApplication::connect(thread, &QThread::finished, thread,
&QThread::deleteLater);
thread->start();
auto* dialog =
new WaitingDialog(QString::fromStdString(waiting_title), parent);
while (thread->isRunning()) {
QApplication::processEvents();
}
dialog->close();
}
CommonUtils* CommonUtils::GetInstance() {
if (instance_ == nullptr) {
instance_ = std::make_unique();
}
return instance_.get();
}
CommonUtils::CommonUtils() : QWidget(nullptr) {
connect(this, &CommonUtils::SignalKeyStatusUpdated, SignalStation::GetInstance(),
&SignalStation::SignalKeyDatabaseRefresh);
connect(this, &CommonUtils::SignalGnupgNotInstall, this, []() {
QMessageBox::critical(
nullptr, _("ENV Loading Failed"),
_("Gnupg(gpg) is not installed correctly, please follow the "
"ReadME "
"instructions in Github to install Gnupg and then open "
"GpgFrontend."));
QCoreApplication::quit();
});
}
void CommonUtils::SlotImportKeys(QWidget* parent,
const std::string& in_buffer) {
GpgImportInformation result = GpgKeyImportExporter::GetInstance().ImportKey(
std::make_unique(in_buffer));
emit SignalKeyStatusUpdated();
new KeyImportDetailDialog(result, false, parent);
}
void CommonUtils::SlotImportKeyFromFile(QWidget* parent) {
QString file_name = QFileDialog::getOpenFileName(
this, _("Open Key"), QString(),
QString(_("Key Files")) + " (*.asc *.txt);;" + _("Keyring files") +
" (*.gpg);;All Files (*)");
if (!file_name.isNull()) {
SlotImportKeys(parent, read_all_data_in_file(file_name.toStdString()));
}
}
void CommonUtils::SlotImportKeyFromKeyServer(QWidget* parent) {
auto dialog = new KeyServerImportDialog(false, parent);
dialog->show();
}
void CommonUtils::SlotImportKeyFromClipboard(QWidget* parent) {
QClipboard* cb = QApplication::clipboard();
SlotImportKeys(parent,
cb->text(QClipboard::Clipboard).toUtf8().toStdString());
}
void CommonUtils::SlotExecuteGpgCommand(
const QStringList& arguments,
const std::function& interact_func) {
QEventLoop looper;
auto dialog = new WaitingDialog(_("Processing"), nullptr);
dialog->show();
auto* gpg_process = new QProcess(&looper);
gpg_process->setProcessChannelMode(QProcess::MergedChannels);
connect(gpg_process,
qOverload(&QProcess::finished), &looper,
&QEventLoop::quit);
connect(gpg_process,
qOverload(&QProcess::finished), dialog,
&WaitingDialog::deleteLater);
connect(gpg_process, &QProcess::errorOccurred, &looper, &QEventLoop::quit);
connect(gpg_process, &QProcess::started,
[]() -> void { LOG(ERROR) << "Gpg Process Started Success"; });
connect(gpg_process, &QProcess::readyReadStandardOutput,
[interact_func, gpg_process]() { interact_func(gpg_process); });
connect(gpg_process, &QProcess::errorOccurred, this, [=]() -> void {
LOG(ERROR) << "Error in Process";
dialog->close();
QMessageBox::critical(nullptr, _("Failure"),
_("Failed to execute command."));
});
connect(gpg_process,
qOverload(&QProcess::finished), this,
[=](int, QProcess::ExitStatus status) {
dialog->close();
if (status == QProcess::NormalExit)
QMessageBox::information(nullptr, _("Success"),
_("Succeed in executing command."));
else
QMessageBox::information(nullptr, _("Warning"),
_("Finished executing command."));
});
gpg_process->setProgram(GpgContext::GetInstance().GetInfo().AppPath.c_str());
gpg_process->setArguments(arguments);
gpg_process->start();
looper.exec();
dialog->close();
dialog->deleteLater();
}
void CommonUtils::SlotImportKeyFromKeyServer(
int ctx_channel, const KeyIdArgsList& key_ids,
const ImportCallbackFunctiopn& callback) {
std::string target_keyserver;
if (target_keyserver.empty()) {
try {
auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
target_keyserver = settings.lookup("keyserver.default_server").c_str();
LOG(INFO) << _("Set target Key Server to default Key Server")
<< target_keyserver;
} catch (...) {
LOG(ERROR) << _("Cannot read default_keyserver From Settings");
QMessageBox::critical(
nullptr, _("Default Keyserver Not Found"),
_("Cannot read default keyserver from your settings, "
"please set a default keyserver first"));
return;
}
}
auto thread =
QThread::create([target_keyserver, key_ids, callback, ctx_channel]() {
QUrl target_keyserver_url(target_keyserver.c_str());
auto network_manager = std::make_unique();
// LOOP
decltype(key_ids.size()) current_index = 1, all_index = key_ids.size();
for (const auto& key_id : key_ids) {
// New Req Url
QUrl req_url(target_keyserver_url.scheme() + "://" +
target_keyserver_url.host() +
"/pks/lookup?op=get&search=0x" + key_id.c_str() +
"&options=mr");
LOG(INFO) << "request url" << req_url.toString().toStdString();
// Waiting for reply
QNetworkReply* reply = network_manager->get(QNetworkRequest(req_url));
QEventLoop loop;
connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
loop.exec();
// Get Data
auto key_data = reply->readAll();
auto key_data_ptr =
std::make_unique(key_data.data(), key_data.size());
// Detect status
std::string status;
auto error = reply->error();
if (error != QNetworkReply::NoError) {
switch (error) {
case QNetworkReply::ContentNotFoundError:
status = _("Key Not Found");
break;
case QNetworkReply::TimeoutError:
status = _("Timeout");
break;
case QNetworkReply::HostNotFoundError:
status = _("Key Server Not Found");
break;
default:
status = _("Connection Error");
}
}
reply->deleteLater();
// Try importing
GpgImportInformation result =
GpgKeyImportExporter::GetInstance(ctx_channel)
.ImportKey(std::move(key_data_ptr));
if (result.imported == 1) {
status = _("The key has been updated");
} else {
status = _("No need to update the key");
}
callback(key_id, status, current_index, all_index);
current_index++;
}
});
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
thread->start();
}
} // namespace GpgFrontend::UI