aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSaturneric <[email protected]>2023-01-07 14:20:07 +0000
committerSaturneric <[email protected]>2023-01-07 14:20:07 +0000
commit225d435423888c38e0c75f63c1d7a41283839bd5 (patch)
tree4c575375dde858e9391e585f9bf47d65090c70cc
parentfix: continue to solve ubuntu 18.04 build issues (diff)
downloadGpgFrontend-225d435423888c38e0c75f63c1d7a41283839bd5.tar.gz
GpgFrontend-225d435423888c38e0c75f63c1d7a41283839bd5.zip
feat: add advanced gnupg operations
1.fix some issues 2. add advanced gnupg operations 3. add configurations information in Gnupg Help Tab
-rw-r--r--src/core/GpgContext.cpp167
-rw-r--r--src/core/GpgContext.h3
-rw-r--r--src/core/GpgInfo.h7
-rw-r--r--src/core/function/gpg/GpgAdvancedOperator.cpp114
-rw-r--r--src/core/function/gpg/GpgAdvancedOperator.h67
-rw-r--r--src/core/function/gpg/GpgCommandExecutor.cpp128
-rw-r--r--src/core/function/gpg/GpgCommandExecutor.h13
-rw-r--r--src/core/function/gpg/GpgKeyOpera.cpp62
-rw-r--r--src/core/thread/Task.cpp4
-rw-r--r--src/core/thread/Task.h12
-rw-r--r--src/core/thread/TaskRunner.cpp7
-rw-r--r--src/core/thread/TaskRunner.h2
-rw-r--r--src/core/thread/TaskRunnerGetter.h1
-rw-r--r--src/ui/UserInterfaceUtils.cpp40
-rw-r--r--src/ui/UserInterfaceUtils.h11
-rw-r--r--src/ui/dialog/help/AboutDialog.cpp4
-rw-r--r--src/ui/dialog/help/GnupgTab.cpp123
-rw-r--r--src/ui/dialog/help/GnupgTab.h6
-rw-r--r--src/ui/dialog/settings/SettingsGeneral.cpp28
-rw-r--r--src/ui/main_window/MainWindow.cpp25
-rw-r--r--src/ui/main_window/MainWindow.h5
-rw-r--r--src/ui/main_window/MainWindowSlotFunction.cpp4
-rw-r--r--src/ui/main_window/MainWindowUI.cpp51
-rw-r--r--src/ui/struct/SoftwareVersion.cpp67
-rw-r--r--src/ui/struct/SoftwareVersion.h20
-rw-r--r--ui/GeneralSettings.ui11
-rw-r--r--ui/GnuPGInfo.ui55
27 files changed, 836 insertions, 201 deletions
diff --git a/src/core/GpgContext.cpp b/src/core/GpgContext.cpp
index 7ebd9fa9..59e21b84 100644
--- a/src/core/GpgContext.cpp
+++ b/src/core/GpgContext.cpp
@@ -31,11 +31,8 @@
#include <gpg-error.h>
#include <gpgme.h>
-#include <functional>
-#include <string>
-#include <utility>
-
#include "GpgConstants.h"
+#include "core/function/gpg/GpgCommandExecutor.h"
#ifdef _WIN32
#include <windows.h>
@@ -240,6 +237,168 @@ gpgme_error_t GpgContext::test_status_cb(void *hook, const char *keyword,
return GPG_ERR_NO_ERROR;
}
+const GpgInfo &GpgContext::GetInfo(bool refresh) {
+ if (!extend_info_loaded_ || refresh) {
+ GpgCommandExecutor::GetInstance().Execute(
+ info_.GpgConfPath, {"--list-components"},
+ [=](int exit_code, const std::string &p_out, const std::string &p_err) {
+ LOG(INFO) << "gpgconf components exit_code" << exit_code
+ << "process stdout size" << p_out.size();
+
+ if (exit_code != 0) {
+ LOG(ERROR) << "gpgconf execute error, process stderr:" << p_err
+ << ", process stdout:" << p_out;
+ return;
+ }
+
+ auto &components_info = info_.ComponentsInfo;
+ components_info["gpgme"] = {"GPG Made Easy", info_.GpgMEVersion,
+ _("Embedded In")};
+ components_info["gpgconf"] = {"GPG Configure", "/",
+ info_.GpgConfPath};
+
+ std::vector<std::string> line_split_list;
+ boost::split(line_split_list, p_out, boost::is_any_of("\n"));
+
+ for (const auto &line : line_split_list) {
+ std::vector<std::string> info_split_list;
+ boost::split(info_split_list, line, boost::is_any_of(":"));
+ LOG(INFO) << "gpgconf info line" << line << "info size"
+ << info_split_list.size();
+
+ if (info_split_list.size() != 3) continue;
+
+ auto component_name = info_split_list[0];
+ if (component_name == "gpg") {
+ components_info[component_name] = {
+ info_split_list[1], info_.GnupgVersion, info_split_list[2]};
+ } else {
+ components_info[component_name] = {info_split_list[1], "/",
+ info_split_list[2]};
+ }
+ }
+ });
+
+ GpgCommandExecutor::GetInstance().Execute(
+ info_.GpgConfPath, {"--list-dirs"},
+ [=](int exit_code, const std::string &p_out, const std::string &p_err) {
+ LOG(INFO) << "gpgconf configurations exit_code" << exit_code
+ << "process stdout size" << p_out.size();
+
+ if (exit_code != 0) {
+ LOG(ERROR) << "gpgconf execute error, process stderr:" << p_err
+ << ", process stdout:" << p_out;
+ return;
+ }
+
+ auto &configurations_info = info_.ConfigurationsInfo;
+
+ std::vector<std::string> line_split_list;
+ boost::split(line_split_list, p_out, boost::is_any_of("\n"));
+
+ for (const auto &line : line_split_list) {
+ std::vector<std::string> info_split_list;
+ boost::split(info_split_list, line, boost::is_any_of(":"));
+ LOG(INFO) << "gpgconf info line" << line << "info size"
+ << info_split_list.size();
+
+ if (info_split_list.size() != 2) continue;
+
+ auto configuration_name = info_split_list[0];
+ configurations_info[configuration_name] = {info_split_list[1]};
+ }
+ });
+
+ for (const auto &component : info_.ComponentsInfo) {
+ LOG(INFO) << "gpgconf check options ready"
+ << "component" << component.first;
+
+ if (component.first == "gpgme" || component.first == "gpgconf") continue;
+
+ GpgCommandExecutor::GetInstance().Execute(
+ info_.GpgConfPath, {"--check-options", component.first},
+ [=](int exit_code, const std::string &p_out,
+ const std::string &p_err) {
+ LOG(INFO) << "gpgconf options exit_code" << exit_code
+ << "process stdout size" << p_out.size() << "component"
+ << component.first;
+
+ if (exit_code != 0) {
+ LOG(ERROR) << "gpgconf execute error, process stderr:" << p_err
+ << ", process stdout:" << p_out;
+ return;
+ }
+
+ auto &options_info = info_.OptionsInfo;
+
+ std::vector<std::string> line_split_list;
+ boost::split(line_split_list, p_out, boost::is_any_of("\n"));
+
+ for (const auto &line : line_split_list) {
+ std::vector<std::string> info_split_list;
+ boost::split(info_split_list, line, boost::is_any_of(":"));
+
+ LOG(INFO) << "gpgconf info line" << line << "info size"
+ << info_split_list.size();
+
+ if (info_split_list.size() != 6) continue;
+
+ auto configuration_name = info_split_list[0];
+ options_info[configuration_name] = {
+ info_split_list[1], info_split_list[2], info_split_list[3],
+ info_split_list[4], info_split_list[5]};
+ }
+ });
+ }
+
+ for (const auto &component : info_.ComponentsInfo) {
+ LOG(INFO) << "gpgconf list options ready"
+ << "component" << component.first;
+
+ if (component.first == "gpgme" || component.first == "gpgconf") continue;
+
+ GpgCommandExecutor::GetInstance().Execute(
+ info_.GpgConfPath, {"--list-options", component.first},
+ [=](int exit_code, const std::string &p_out,
+ const std::string &p_err) {
+ LOG(INFO) << "gpgconf options exit_code" << exit_code
+ << "process stdout size" << p_out.size() << "component"
+ << component.first;
+
+ if (exit_code != 0) {
+ LOG(ERROR) << "gpgconf execute error, process stderr:" << p_err
+ << ", process stdout:" << p_out;
+ return;
+ }
+
+ auto &available_options_info = info_.AvailableOptionsInfo;
+
+ std::vector<std::string> line_split_list;
+ boost::split(line_split_list, p_out, boost::is_any_of("\n"));
+
+ for (const auto &line : line_split_list) {
+ std::vector<std::string> info_split_list;
+ boost::split(info_split_list, line, boost::is_any_of(":"));
+
+ LOG(INFO) << "gpgconf info line" << line << "info size"
+ << info_split_list.size();
+
+ if (info_split_list.size() != 10) continue;
+
+ auto configuration_name = info_split_list[0];
+ available_options_info[configuration_name] = {
+ info_split_list[1], info_split_list[2], info_split_list[3],
+ info_split_list[4], info_split_list[5], info_split_list[6],
+ info_split_list[7], info_split_list[8], info_split_list[9]};
+ }
+ });
+ }
+
+ extend_info_loaded_ = true;
+ }
+ return info_;
+}
+
void GpgContext::_ctx_ref_deleter::operator()(gpgme_ctx_t _ctx) {
if (_ctx != nullptr) gpgme_release(_ctx);
}
diff --git a/src/core/GpgContext.h b/src/core/GpgContext.h
index e1f1bda4..12a0fe1c 100644
--- a/src/core/GpgContext.h
+++ b/src/core/GpgContext.h
@@ -92,7 +92,7 @@ class GPGFRONTEND_CORE_EXPORT GpgContext
*
* @return const GpgInfo&
*/
- [[nodiscard]] const GpgInfo& GetInfo() const { return info_; }
+ [[nodiscard]] const GpgInfo& GetInfo(bool refresh = false);
/**
* @brief
@@ -104,6 +104,7 @@ class GPGFRONTEND_CORE_EXPORT GpgContext
private:
GpgInfo info_; ///<
GpgContextInitArgs args_; ///<
+ bool extend_info_loaded_ = false;
/**
* @brief
diff --git a/src/core/GpgInfo.h b/src/core/GpgInfo.h
index d0453b9f..53c5c3f5 100644
--- a/src/core/GpgInfo.h
+++ b/src/core/GpgInfo.h
@@ -42,9 +42,14 @@ class GpgInfo {
std::string DatabasePath; ///<
std::string GnupgVersion; ///<
std::string GpgConfPath; ///<
- std::string AssuanPath; ///<
+ std::string AssuanPath; ///<
std::string CMSPath; ///<
std::string GpgMEVersion; ///<
+
+ std::map<std::string, std::vector<std::string>> ComponentsInfo; ///<
+ std::map<std::string, std::vector<std::string>> ConfigurationsInfo; ///<
+ std::map<std::string, std::vector<std::string>> OptionsInfo; ///<
+ std::map<std::string, std::vector<std::string>> AvailableOptionsInfo; ///<
};
} // namespace GpgFrontend
diff --git a/src/core/function/gpg/GpgAdvancedOperator.cpp b/src/core/function/gpg/GpgAdvancedOperator.cpp
new file mode 100644
index 00000000..0ec447fe
--- /dev/null
+++ b/src/core/function/gpg/GpgAdvancedOperator.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2023. 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 <https://www.gnu.org/licenses/>.
+ *
+ * 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<[email protected]> starting on May 12, 2021.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+//
+// Created by eric on 07.01.2023.
+//
+
+#include "GpgAdvancedOperator.h"
+
+#include "core/function/gpg/GpgCommandExecutor.h"
+
+GpgFrontend::GpgAdvancedOperator::GpgAdvancedOperator(int channel)
+ : SingletonFunctionObject(channel) {}
+
+bool GpgFrontend::GpgAdvancedOperator::ClearGpgPasswordCache() {
+ bool success = false;
+ GpgFrontend::GpgCommandExecutor::GetInstance().Execute(
+ ctx_.GetInfo().GpgConfPath, {"--reload", "gpg-agent"},
+ [&](int exit_code, const std::string &p_out, const std::string &p_err) {
+ if (exit_code == 0) {
+ success = true;
+ }
+ });
+
+ return success;
+}
+
+bool GpgFrontend::GpgAdvancedOperator::ReloadGpgComponents() {
+ bool success = false;
+ GpgFrontend::GpgCommandExecutor::GetInstance().Execute(
+ ctx_.GetInfo().GpgConfPath, {"--reload"},
+ [&](int exit_code, const std::string &p_out, const std::string &p_err) {
+ if (exit_code == 0) {
+ success = true;
+ } else {
+ LOG(ERROR) << "gpgconf execute error, process stderr:" << p_err
+ << ", process stdout:" << p_out;
+ return;
+ }
+ });
+
+ return success;
+}
+
+bool GpgFrontend::GpgAdvancedOperator::RestartGpgComponents() {
+ bool success = false;
+ GpgFrontend::GpgCommandExecutor::GetInstance().Execute(
+ ctx_.GetInfo().GpgConfPath, {"--kill", "all"},
+ [&](int exit_code, const std::string &p_out, const std::string &p_err) {
+ if (exit_code == 0) {
+ success = true;
+ } else {
+ LOG(ERROR) << "gpgconf execute error, process stderr:" << p_err
+ << ", process stdout:" << p_out;
+ return;
+ }
+ });
+
+ GpgFrontend::GpgCommandExecutor::GetInstance().Execute(
+ ctx_.GetInfo().GpgConfPath, {"--launch", "all"},
+ [&](int exit_code, const std::string &p_out, const std::string &p_err) {
+ if (exit_code == 0) {
+ success = true;
+ } else {
+ success = false;
+ LOG(ERROR) << "gpgconf execute error, process stderr:" << p_err
+ << ", process stdout:" << p_out;
+ return;
+ }
+ });
+
+ return success;
+}
+
+bool GpgFrontend::GpgAdvancedOperator::ResetConfigures() {
+ bool success = false;
+ GpgFrontend::GpgCommandExecutor::GetInstance().Execute(
+ ctx_.GetInfo().GpgConfPath, {"--apply-defaults"},
+ [&](int exit_code, const std::string &p_out, const std::string &p_err) {
+ if (exit_code == 0) {
+ success = true;
+ } else {
+ LOG(ERROR) << "gpgconf execute error, process stderr:" << p_err
+ << ", process stdout:" << p_out;
+ return;
+ }
+ });
+
+ return success;
+}
diff --git a/src/core/function/gpg/GpgAdvancedOperator.h b/src/core/function/gpg/GpgAdvancedOperator.h
new file mode 100644
index 00000000..267f1614
--- /dev/null
+++ b/src/core/function/gpg/GpgAdvancedOperator.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2023. 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 <https://www.gnu.org/licenses/>.
+ *
+ * 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<[email protected]> starting on May 12, 2021.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+//
+// Created by eric on 07.01.2023.
+//
+
+#ifndef GPGFRONTEND_GPGADVANCEDOPERATOR_H
+#define GPGFRONTEND_GPGADVANCEDOPERATOR_H
+
+#include "core/GpgConstants.h"
+#include "core/GpgContext.h"
+#include "core/GpgFunctionObject.h"
+
+namespace GpgFrontend {
+
+class GPGFRONTEND_CORE_EXPORT GpgAdvancedOperator
+ : public SingletonFunctionObject<GpgAdvancedOperator> {
+ public:
+ /**
+ * @brief Construct a new Basic Operator object
+ *
+ * @param channel Channel corresponding to the context
+ */
+ explicit GpgAdvancedOperator(
+ int channel = SingletonFunctionObject::GetDefaultChannel());
+
+ bool ClearGpgPasswordCache();
+
+ bool ReloadGpgComponents();
+
+ bool RestartGpgComponents();
+
+ bool ResetConfigures();
+
+ private:
+ GpgContext& ctx_ = GpgContext::GetInstance(
+ SingletonFunctionObject::GetChannel()); ///< Corresponding context
+};
+
+} // namespace GpgFrontend
+
+#endif // GPGFRONTEND_GPGADVANCEDOPERATOR_H
diff --git a/src/core/function/gpg/GpgCommandExecutor.cpp b/src/core/function/gpg/GpgCommandExecutor.cpp
index 2292ed0e..0fe9b5c3 100644
--- a/src/core/function/gpg/GpgCommandExecutor.cpp
+++ b/src/core/function/gpg/GpgCommandExecutor.cpp
@@ -27,41 +27,119 @@
*/
#include "GpgCommandExecutor.h"
+#include "GpgFunctionObject.h"
+#include "core/thread/TaskRunnerGetter.h"
+
GpgFrontend::GpgCommandExecutor::GpgCommandExecutor(int channel)
: SingletonFunctionObject<GpgCommandExecutor>(channel) {}
-#ifndef WINDOWS
-#include <boost/asio.hpp>
-#endif
+void GpgFrontend::GpgCommandExecutor::Execute(
+ std::string cmd, std::vector<std::string> arguments,
+ std::function<void(int, std::string, std::string)> callback,
+ std::function<void(QProcess *)> interact_func) {
+ LOG(INFO) << "called"
+ << "cmd" << cmd << "arguments size" << arguments.size();
-#ifndef WINDOWS
+ Thread::Task::TaskCallback result_callback =
+ [](int rtn, Thread::Task::DataObjectPtr data_object) {
+ LOG(INFO) << "called";
-using boost::process::async_pipe;
+ if (data_object->GetObjectSize() != 4)
+ throw std::runtime_error("invalid data object size");
-void GpgFrontend::GpgCommandExecutor::Execute(
- StringArgsRef arguments,
- const std::function<void(async_pipe& in, async_pipe& out)>& interact_func) {
- using namespace boost::process;
+ auto exit_code = data_object->PopObject<int>();
+ auto process_stdout = data_object->PopObject<std::string>();
+ auto process_stderr = data_object->PopObject<std::string>();
+ auto callback = data_object->PopObject<
+ std::function<void(int, std::string, std::string)>>();
- boost::asio::io_service ios;
+ // call callback
+ callback(exit_code, process_stdout, process_stderr);
+ };
- std::vector<char> buf;
+ Thread::Task::TaskRunnable runner =
+ [](GpgFrontend::Thread::Task::DataObjectPtr data_object) -> int {
+ LOG(INFO) << "process runner called, data object size"
+ << data_object->GetObjectSize();
- async_pipe in_pipe_stream(ios);
- async_pipe out_pipe_stream(ios);
+ if (data_object->GetObjectSize() != 4)
+ throw std::runtime_error("invalid data object size");
- child child_process(ctx_.GetInfo().AppPath.c_str(), arguments,
- std_out > in_pipe_stream, std_in < out_pipe_stream);
+ // get arguments
+ auto cmd = data_object->PopObject<std::string>();
+ LOG(INFO) << "get cmd" << cmd;
+ auto arguments = data_object->PopObject<std::vector<std::string>>();
+ auto interact_func =
+ data_object->PopObject<std::function<void(QProcess *)>>();
- boost::asio::async_read(
- in_pipe_stream, boost::asio::buffer(buf),
- [&](const boost::system::error_code& ec, std::size_t size) {
- interact_func(in_pipe_stream, out_pipe_stream);
- });
+ auto *cmd_process = new QProcess();
+ cmd_process->setProcessChannelMode(QProcess::MergedChannels);
- ios.run();
- child_process.wait();
- child_process.exit_code();
-}
+ QObject::connect(cmd_process, &QProcess::started,
+ []() -> void { LOG(INFO) << "process started"; });
+ QObject::connect(
+ cmd_process, &QProcess::readyReadStandardOutput,
+ [interact_func, cmd_process]() { interact_func(cmd_process); });
+ QObject::connect(cmd_process, &QProcess::errorOccurred, [=]() {
+ LOG(ERROR) << "error in executing command:" << cmd;
+ });
+ QObject::connect(cmd_process,
+ qOverload<int, QProcess::ExitStatus>(&QProcess::finished),
+ [=](int, QProcess::ExitStatus status) {
+ if (status == QProcess::NormalExit)
+ LOG(INFO) << "succeed in executing command:" << cmd;
+ else
+ LOG(WARNING) << "error in executing command:" << cmd;
+ });
+
+ cmd_process->setProgram(QString::fromStdString(cmd));
+
+ QStringList q_arguments;
+ for (const auto &argument : arguments)
+ q_arguments.append(QString::fromStdString(argument));
+ cmd_process->setArguments(q_arguments);
+
+ LOG(INFO) << "process execute ready";
+
+ cmd_process->start();
+ cmd_process->waitForFinished(30);
+
+ std::string process_stdout =
+ cmd_process->readAllStandardOutput().toStdString(),
+ process_stderr =
+ cmd_process->readAllStandardError().toStdString();
+ int exit_code = cmd_process->exitCode();
-#endif
+ cmd_process->close();
+ cmd_process->deleteLater();
+
+ // transfer result
+ data_object->AppendObject(std::move(process_stderr));
+ data_object->AppendObject(std::move(process_stdout));
+ data_object->AppendObject(std::move(exit_code));
+
+ return 0;
+ };
+
+ // data transfer into task
+ auto data_object = std::make_shared<Thread::Task::DataObject>();
+ data_object->AppendObject(std::move(callback));
+ data_object->AppendObject(std::move(interact_func));
+ data_object->AppendObject(std::move(arguments));
+ data_object->AppendObject(std::move(cmd));
+
+ auto *process_task = new GpgFrontend::Thread::Task(
+ std::move(runner), std::move(result_callback), data_object);
+
+ QEventLoop looper;
+ QObject::connect(process_task, &Thread::Task::SignalTaskFinished, &looper,
+ &QEventLoop::quit);
+
+ GpgFrontend::Thread::TaskRunnerGetter::GetInstance()
+ .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_External_Process)
+ ->PostTask(process_task);
+
+ // block until task finished
+ // this is to keep reference vaild until task finished
+ looper.exec();
+}
diff --git a/src/core/function/gpg/GpgCommandExecutor.h b/src/core/function/gpg/GpgCommandExecutor.h
index 40ee22df..c597feac 100644
--- a/src/core/function/gpg/GpgCommandExecutor.h
+++ b/src/core/function/gpg/GpgCommandExecutor.h
@@ -35,6 +35,7 @@
#include "core/GpgContext.h"
#include "core/GpgFunctionObject.h"
+#include "core/thread/Task.h"
namespace GpgFrontend {
@@ -53,19 +54,17 @@ class GPGFRONTEND_CORE_EXPORT GpgCommandExecutor
explicit GpgCommandExecutor(
int channel = SingletonFunctionObject::GetDefaultChannel());
-#ifndef WINDOWS
-
/**
* @brief Excuting an order
*
* @param arguments Command parameters
* @param interact_func Command answering function
*/
- void Execute(StringArgsRef arguments,
- const std::function<void(boost::process::async_pipe &in,
- boost::process::async_pipe &out)>
- &interact_func);
-#endif
+ void Execute(
+ std::string cmd, std::vector<std::string> arguments,
+ std::function<void(int, std::string, std::string)> callback =
+ [](int, std::string, std::string) {},
+ std::function<void(QProcess *)> interact_func = [](QProcess *) {});
private:
GpgContext &ctx_ = GpgContext::GetInstance(
diff --git a/src/core/function/gpg/GpgKeyOpera.cpp b/src/core/function/gpg/GpgKeyOpera.cpp
index 0839c132..08103bbb 100644
--- a/src/core/function/gpg/GpgKeyOpera.cpp
+++ b/src/core/function/gpg/GpgKeyOpera.cpp
@@ -103,59 +103,7 @@ GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::SetExpire(
* @return the process doing this job
*/
void GpgFrontend::GpgKeyOpera::GenerateRevokeCert(
- const GpgKey& key, const std::string& output_file_name) {
- auto args = std::vector<std::string>{"--no-tty",
- "--command-fd",
- "0",
- "--status-fd",
- "1",
- "-o",
- output_file_name,
- "--gen-revoke",
- key.GetFingerprint()};
-
- using boost::asio::async_write;
- using boost::process::async_pipe;
-#ifndef WINDOWS
- GpgCommandExecutor::GetInstance().Execute(
- args, [](async_pipe& in, async_pipe& out) -> void {
- // boost::asio::streambuf buff;
- // boost::asio::read_until(in, buff, '\n');
- //
- // std::istream is(&buff);
- //
- // while (!is.eof()) {
- // std::string line;
- // is >> line;
- // LOG(INFO) << "line" << line;
- // boost::algorithm::trim(line);
- // if (line == std::string("[GNUPG:] GET_BOOL
- // gen_revoke.okay")) {
- //
- // } else if (line ==
- // std::string(
- // "[GNUPG:] GET_LINE
- // ask_revocation_reason.code")) {
- //
- // } else if (line ==
- // std::string(
- // "[GNUPG:] GET_LINE
- // ask_revocation_reason.text")) {
- //
- // } else if (line ==
- // std::string("[GNUPG:] GET_BOOL
- // openfile.overwrite.okay")) {
- //
- // } else if (line ==
- // std::string(
- // "[GNUPG:] GET_BOOL
- // ask_revocation_reason.okay")) {
- //
- // }
- // }
- });
-#endif
-}
+ const GpgKey& key, const std::string& output_file_name) {}
/**
* Generate a new key pair
@@ -181,9 +129,9 @@ GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::GenerateKey(
GpgError err;
- LOG(INFO) << "ctx version" << ctx_.GetInfo().GnupgVersion;
+ LOG(INFO) << "ctx version" << ctx_.GetInfo(false).GnupgVersion;
- if (ctx_.GetInfo().GnupgVersion >= "2.1.0") {
+ if (ctx_.GetInfo(false).GnupgVersion >= "2.1.0") {
unsigned int flags = 0;
if (!params->IsSubKey()) flags |= GPGME_CREATE_CERT;
@@ -278,7 +226,7 @@ GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::GenerateSubkey(
GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::ModifyPassword(
const GpgFrontend::GpgKey& key) {
- if (ctx_.GetInfo().GnupgVersion < "2.0.15") {
+ if (ctx_.GetInfo(false).GnupgVersion < "2.0.15") {
LOG(ERROR) << _("operator not support");
return GPG_ERR_NOT_SUPPORTED;
}
@@ -287,7 +235,7 @@ GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::ModifyPassword(
}
GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::ModifyTOFUPolicy(
const GpgFrontend::GpgKey& key, gpgme_tofu_policy_t tofu_policy) {
- if (ctx_.GetInfo().GnupgVersion < "2.1.10") {
+ if (ctx_.GetInfo(false).GnupgVersion < "2.1.10") {
LOG(ERROR) << _("operator not support");
return GPG_ERR_NOT_SUPPORTED;
}
diff --git a/src/core/thread/Task.cpp b/src/core/thread/Task.cpp
index 6b1a27a1..669334d5 100644
--- a/src/core/thread/Task.cpp
+++ b/src/core/thread/Task.cpp
@@ -139,8 +139,8 @@ size_t GpgFrontend::Thread::Task::DataObject::GetObjectSize() {
}
void GpgFrontend::Thread::Task::DataObject::free_heap_ptr(Destructor *ptr) {
- DLOG(TRACE) << "p_obj: " << ptr->p_obj << "destructor: " << ptr->destroy
- << "DataObject:" << this;
+ LOG(TRACE) << "p_obj: " << ptr->p_obj << "destructor: " << ptr->destroy
+ << "DataObject:" << this;
if (ptr->destroy != nullptr) {
ptr->destroy(ptr->p_obj);
}
diff --git a/src/core/thread/Task.h b/src/core/thread/Task.h
index c94baea6..163e1507 100644
--- a/src/core/thread/Task.h
+++ b/src/core/thread/Task.h
@@ -80,7 +80,8 @@ class GPGFRONTEND_CORE_EXPORT Task : public QObject, public QRunnable {
void AppendObject(T &&obj) {
DLOG(TRACE) << "called:" << this;
auto *obj_dstr = this->get_heap_ptr(sizeof(T));
- auto *ptr_heap = new ((void *)obj_dstr->p_obj) T(std::move(obj));
+ new ((void *)obj_dstr->p_obj) T(std::forward<T>(obj));
+
if (std::is_class_v<T>) {
auto destructor = [](const void *x) {
static_cast<const T *>(x)->~T();
@@ -89,7 +90,8 @@ class GPGFRONTEND_CORE_EXPORT Task : public QObject, public QRunnable {
} else {
obj_dstr->destroy = nullptr;
}
- data_objects_.push(std::move(obj_dstr));
+
+ data_objects_.push(obj_dstr);
}
/**
@@ -169,16 +171,16 @@ class GPGFRONTEND_CORE_EXPORT Task : public QObject, public QRunnable {
*
* @param callback The callback function to be executed.
*/
- Task(TaskCallback callback, DataObjectPtr data_object = nullptr);
+ explicit Task(TaskCallback callback, DataObjectPtr data_object = nullptr);
/**
* @brief Construct a new Task object
*
* @param runnable
*/
- Task(
+ explicit Task(
TaskRunnable runnable,
- TaskCallback callback = [](int, std::shared_ptr<DataObject>) {},
+ TaskCallback callback = [](int, const std::shared_ptr<DataObject> &) {},
DataObjectPtr data = nullptr);
/**
diff --git a/src/core/thread/TaskRunner.cpp b/src/core/thread/TaskRunner.cpp
index f70b2d4c..ffbeb495 100644
--- a/src/core/thread/TaskRunner.cpp
+++ b/src/core/thread/TaskRunner.cpp
@@ -36,10 +36,11 @@ GpgFrontend::Thread::TaskRunner::TaskRunner() = default;
GpgFrontend::Thread::TaskRunner::~TaskRunner() = default;
void GpgFrontend::Thread::TaskRunner::PostTask(Task* task) {
+ if (task == nullptr) return;
+
std::string uuid = task->GetUUID();
LOG(TRACE) << "Post Task" << uuid;
- if (task == nullptr) return;
task->setParent(nullptr);
task->moveToThread(this);
@@ -59,7 +60,7 @@ void GpgFrontend::Thread::TaskRunner::PostTask(Task* task) {
quit();
}
-void GpgFrontend::Thread::TaskRunner::run() {
+[[noreturn]] void GpgFrontend::Thread::TaskRunner::run() {
LOG(TRACE) << "called"
<< "thread id:" << QThread::currentThreadId();
while (true) {
@@ -91,7 +92,7 @@ void GpgFrontend::Thread::TaskRunner::run() {
task->deleteLater();
pending_tasks_.erase(task->GetUUID());
} catch (...) {
- LOG(ERROR) << "TaskRunner: Unknwon Exception in Task"
+ LOG(ERROR) << "TaskRunner: Unknown Exception in Task"
<< task->GetUUID();
// destroy the task, remove the task from the pending tasks
diff --git a/src/core/thread/TaskRunner.h b/src/core/thread/TaskRunner.h
index f18efca6..565c123c 100644
--- a/src/core/thread/TaskRunner.h
+++ b/src/core/thread/TaskRunner.h
@@ -55,7 +55,7 @@ class GPGFRONTEND_CORE_EXPORT TaskRunner : public QThread {
* @brief
*
*/
- void run() override;
+ [[noreturn]] void run() override;
public slots:
diff --git a/src/core/thread/TaskRunnerGetter.h b/src/core/thread/TaskRunnerGetter.h
index afbf63af..80b25c3e 100644
--- a/src/core/thread/TaskRunnerGetter.h
+++ b/src/core/thread/TaskRunnerGetter.h
@@ -41,6 +41,7 @@ class GPGFRONTEND_CORE_EXPORT TaskRunnerGetter
kTaskRunnerType_GPG,
kTaskRunnerType_IO,
kTaskRunnerType_Network,
+ kTaskRunnerType_External_Process,
};
TaskRunnerGetter(int channel = SingletonFunctionObject::GetDefaultChannel());
diff --git a/src/ui/UserInterfaceUtils.cpp b/src/ui/UserInterfaceUtils.cpp
index f2659e9d..db28b312 100644
--- a/src/ui/UserInterfaceUtils.cpp
+++ b/src/ui/UserInterfaceUtils.cpp
@@ -213,6 +213,41 @@ void CommonUtils::SlotImportKeyFromClipboard(QWidget *parent) {
cb->text(QClipboard::Clipboard).toUtf8().toStdString());
}
+void CommonUtils::SlotExecuteCommand(
+ const std::string& cmd,
+ const QStringList &arguments,
+ const std::function<void(QProcess *)> &interact_func) {
+ QEventLoop looper;
+ auto *cmd_process = new QProcess(&looper);
+ cmd_process->setProcessChannelMode(QProcess::MergedChannels);
+
+ connect(cmd_process,
+ qOverload<int, QProcess::ExitStatus>(&QProcess::finished), &looper,
+ &QEventLoop::quit);
+ connect(cmd_process, &QProcess::errorOccurred, &looper, &QEventLoop::quit);
+ connect(cmd_process, &QProcess::started,
+ []() -> void { LOG(INFO) << "process started"; });
+ connect(cmd_process, &QProcess::readyReadStandardOutput,
+ [interact_func, cmd_process]() { interact_func(cmd_process); });
+ connect(cmd_process, &QProcess::errorOccurred, this, [=]() -> void {
+ LOG(ERROR) << "Error in Process";
+ });
+ connect(cmd_process,
+ qOverload<int, QProcess::ExitStatus>(&QProcess::finished), this,
+ [=](int, QProcess::ExitStatus status) {
+ if (status == QProcess::NormalExit)
+ LOG(INFO) << "succeed in executing command:" << cmd;
+ else
+ LOG(WARNING) << "error in executing command:" << cmd;
+ });
+
+ cmd_process->setProgram(QString::fromStdString(cmd));
+ cmd_process->setArguments(arguments);
+ cmd_process->start();
+ looper.exec();
+}
+
+
void CommonUtils::SlotExecuteGpgCommand(
const QStringList &arguments,
const std::function<void(QProcess *)> &interact_func) {
@@ -230,7 +265,7 @@ void CommonUtils::SlotExecuteGpgCommand(
&WaitingDialog::deleteLater);
connect(gpg_process, &QProcess::errorOccurred, &looper, &QEventLoop::quit);
connect(gpg_process, &QProcess::started,
- []() -> void { LOG(ERROR) << "Gpg Process Started Success"; });
+ []() -> void { LOG(INFO) << "gpg process started"; });
connect(gpg_process, &QProcess::readyReadStandardOutput,
[interact_func, gpg_process]() { interact_func(gpg_process); });
connect(gpg_process, &QProcess::errorOccurred, this, [=]() -> void {
@@ -251,7 +286,8 @@ void CommonUtils::SlotExecuteGpgCommand(
_("Finished executing command."));
});
- gpg_process->setProgram(GpgContext::GetInstance().GetInfo().AppPath.c_str());
+ gpg_process->setProgram(
+ GpgContext::GetInstance().GetInfo(false).AppPath.c_str());
gpg_process->setArguments(arguments);
gpg_process->start();
looper.exec();
diff --git a/src/ui/UserInterfaceUtils.h b/src/ui/UserInterfaceUtils.h
index bcfa28d2..d11ae9a2 100644
--- a/src/ui/UserInterfaceUtils.h
+++ b/src/ui/UserInterfaceUtils.h
@@ -214,6 +214,17 @@ class CommonUtils : public QWidget {
const QStringList& arguments,
const std::function<void(QProcess*)>& interact_func);
+ /**
+ * @brief
+ *
+ * @param arguments
+ * @param interact_func
+ */
+ void SlotExecuteCommand(
+ const std::string& cmd,
+ const QStringList& arguments,
+ const std::function<void(QProcess*)>& interact_func);
+
private slots:
/**
diff --git a/src/ui/dialog/help/AboutDialog.cpp b/src/ui/dialog/help/AboutDialog.cpp
index 6b6e4356..25ace162 100644
--- a/src/ui/dialog/help/AboutDialog.cpp
+++ b/src/ui/dialog/help/AboutDialog.cpp
@@ -95,7 +95,9 @@ InfoTab::InfoTab(QWidget* parent) : QWidget(parent) {
_("or send a mail to my mailing list at") + " <a " +
"href=\"mailto:[email protected]\">[email protected]</a>." + "<br><br> " +
_("Built with Qt") + " " + qVersion() + " " + _("and GPGME") + " " +
- GpgFrontend::GpgContext::GetInstance().GetInfo().GpgMEVersion.c_str() +
+ GpgFrontend::GpgContext::GetInstance()
+ .GetInfo(false)
+ .GpgMEVersion.c_str() +
"<br>" + _("Built at") + " " + BUILD_TIMESTAMP + "</center>");
auto* layout = new QGridLayout();
diff --git a/src/ui/dialog/help/GnupgTab.cpp b/src/ui/dialog/help/GnupgTab.cpp
index 9d783367..8be35416 100644
--- a/src/ui/dialog/help/GnupgTab.cpp
+++ b/src/ui/dialog/help/GnupgTab.cpp
@@ -31,103 +31,102 @@
#include "GnupgTab.h"
-#include "easylogging++.h"
+#include "ui/UserInterfaceUtils.h"
#include "ui_GnuPGInfo.h"
GpgFrontend::UI::GnupgTab::GnupgTab(QWidget* parent)
- : QWidget(parent),
- ui_(std::make_shared<Ui_GnuPGInfo>()),
- gpgconf_process_(new QProcess(this)) {
+ : QWidget(parent), ui_(std::make_shared<Ui_GnuPGInfo>()) {
GpgContext& ctx = GpgContext::GetInstance();
- auto info = ctx.GetInfo();
+ auto info = ctx.GetInfo(false);
ui_->setupUi(this);
- QStringList column_titles;
- column_titles << _("Name") << _("Description") << _("Version") << _("Path");
+ QStringList components_column_titles;
+ components_column_titles << _("Name") << _("Description") << _("Version")
+ << _("Path");
- ui_->conponentDetailsTable->setColumnCount(column_titles.length());
- ui_->conponentDetailsTable->setHorizontalHeaderLabels(column_titles);
- ui_->conponentDetailsTable->horizontalHeader()->setStretchLastSection(false);
- ui_->conponentDetailsTable->setSelectionBehavior(
+ ui_->componentDetailsTable->setColumnCount(components_column_titles.length());
+ ui_->componentDetailsTable->setHorizontalHeaderLabels(
+ components_column_titles);
+ ui_->componentDetailsTable->horizontalHeader()->setStretchLastSection(false);
+ ui_->componentDetailsTable->setSelectionBehavior(
QAbstractItemView::SelectRows);
+ QStringList configurations_column_titles;
+ configurations_column_titles << _("Name") << _("Path");
+
+ ui_->configurationDetailsTable->setColumnCount(
+ configurations_column_titles.length());
+ ui_->configurationDetailsTable->setHorizontalHeaderLabels(
+ configurations_column_titles);
+ ui_->configurationDetailsTable->horizontalHeader()->setStretchLastSection(
+ false);
+ ui_->configurationDetailsTable->setSelectionBehavior(
+ QAbstractItemView::SelectRows);
+
+ ui_->softwareDetailsTableTitle->setText(_("Software Information"));
+
// tableitems not editable
- ui_->conponentDetailsTable->setEditTriggers(
+ ui_->componentDetailsTable->setEditTriggers(
QAbstractItemView::NoEditTriggers);
// no focus (rectangle around tableitems)
// may be it should focus on whole row
- ui_->conponentDetailsTable->setFocusPolicy(Qt::NoFocus);
- ui_->conponentDetailsTable->setAlternatingRowColors(true);
-
- gpgconf_process_->start(QString::fromStdString(info.GpgConfPath),
- QStringList() << "--list-components");
+ ui_->componentDetailsTable->setFocusPolicy(Qt::NoFocus);
+ ui_->componentDetailsTable->setAlternatingRowColors(true);
- connect(gpgconf_process_,
- qOverload<int, QProcess::ExitStatus>(&QProcess::finished), this,
- &GnupgTab::process_components_info);
+ process_software_info();
}
-void GpgFrontend::UI::GnupgTab::process_components_info(
- int exit_code, QProcess::ExitStatus exit_status) {
+void GpgFrontend::UI::GnupgTab::process_software_info() {
LOG(INFO) << "called";
- GpgContext& ctx = GpgContext::GetInstance();
- auto info = ctx.GetInfo();
+ auto ctx_info = GpgContext::GetInstance().GetInfo(true);
- std::vector<std::vector<std::string>> components_info = {
- {"gpgme", "GPG Made Easy", info.GpgMEVersion, "/"},
- {"gpgconf", "GPG Configure", "/", info.GpgConfPath},
+ ui_->componentDetailsTable->setRowCount(ctx_info.ComponentsInfo.size());
- };
+ int row = 0;
+ for (const auto& info : ctx_info.ComponentsInfo) {
+ if (info.second.size() != 3) continue;
- if (gpgconf_process_ != nullptr) {
- QString data = gpgconf_process_->readAllStandardOutput();
+ auto* tmp0 = new QTableWidgetItem(QString::fromStdString(info.first));
+ tmp0->setTextAlignment(Qt::AlignCenter);
+ ui_->componentDetailsTable->setItem(row, 0, tmp0);
- std::vector<std::string> line_split_list;
- boost::split(line_split_list, data.toStdString(), boost::is_any_of("\n"));
+ auto* tmp1 = new QTableWidgetItem(QString::fromStdString(info.second[0]));
+ tmp1->setTextAlignment(Qt::AlignCenter);
+ ui_->componentDetailsTable->setItem(row, 1, tmp1);
- for (const auto& line : line_split_list) {
- std::vector<std::string> info_split_list;
- boost::split(info_split_list, line, boost::is_any_of(":"));
- LOG(INFO) << "gpgconf info line" << line << "info size"
- << info_split_list.size();
+ auto* tmp2 = new QTableWidgetItem(QString::fromStdString(info.second[1]));
+ tmp2->setTextAlignment(Qt::AlignCenter);
+ ui_->componentDetailsTable->setItem(row, 2, tmp2);
- if (info_split_list.size() != 3) continue;
+ auto* tmp3 = new QTableWidgetItem(QString::fromStdString(info.second[2]));
+ tmp3->setTextAlignment(Qt::AlignLeft);
+ ui_->componentDetailsTable->setItem(row, 3, tmp3);
- if (info_split_list[0] == "gpg") {
- components_info.push_back({info_split_list[0], info_split_list[1],
- info.GnupgVersion, info_split_list[2]});
- } else {
- components_info.push_back(
- {info_split_list[0], info_split_list[1], "/", info_split_list[2]});
- }
- }
+ row++;
}
- ui_->conponentDetailsTable->setRowCount(components_info.size());
+ ui_->componentDetailsTable->resizeColumnsToContents();
- int row = 0;
- for (const auto& info : components_info) {
- if (info.size() != 4) continue;
+ ui_->configurationDetailsTable->setRowCount(
+ ctx_info.ConfigurationsInfo.size());
- auto* tmp0 = new QTableWidgetItem(QString::fromStdString(info[0]));
+ row = 0;
+ for (const auto& info : ctx_info.ConfigurationsInfo) {
+ if (info.second.size() != 1) continue;
+
+ auto* tmp0 = new QTableWidgetItem(QString::fromStdString(info.first));
tmp0->setTextAlignment(Qt::AlignCenter);
- ui_->conponentDetailsTable->setItem(row, 0, tmp0);
+ ui_->configurationDetailsTable->setItem(row, 0, tmp0);
- auto* tmp1 = new QTableWidgetItem(QString::fromStdString(info[1]));
+ auto* tmp1 = new QTableWidgetItem(QString::fromStdString(info.second[0]));
tmp1->setTextAlignment(Qt::AlignCenter);
- ui_->conponentDetailsTable->setItem(row, 1, tmp1);
-
- auto* tmp2 = new QTableWidgetItem(QString::fromStdString(info[2]));
- tmp2->setTextAlignment(Qt::AlignCenter);
- ui_->conponentDetailsTable->setItem(row, 2, tmp2);
-
- auto* tmp3 = new QTableWidgetItem(QString::fromStdString(info[3]));
- tmp3->setTextAlignment(Qt::AlignLeft);
- ui_->conponentDetailsTable->setItem(row, 3, tmp3);
+ ui_->configurationDetailsTable->setItem(row, 1, tmp1);
row++;
}
+
+ ui_->configurationDetailsTable->resizeColumnsToContents();
}
diff --git a/src/ui/dialog/help/GnupgTab.h b/src/ui/dialog/help/GnupgTab.h
index c143bae3..9195dee0 100644
--- a/src/ui/dialog/help/GnupgTab.h
+++ b/src/ui/dialog/help/GnupgTab.h
@@ -48,11 +48,9 @@ class GnupgTab : public QWidget {
explicit GnupgTab(QWidget* parent = nullptr);
private:
- std::shared_ptr<Ui_GnuPGInfo> ui_;
- QProcess* gpgconf_process_;
+ std::shared_ptr<Ui_GnuPGInfo> ui_; ///<
- private slots:
- void process_components_info(int, QProcess::ExitStatus);
+ void process_software_info();
};
} // namespace GpgFrontend::UI
diff --git a/src/ui/dialog/settings/SettingsGeneral.cpp b/src/ui/dialog/settings/SettingsGeneral.cpp
index 680ed014..7c7f254d 100644
--- a/src/ui/dialog/settings/SettingsGeneral.cpp
+++ b/src/ui/dialog/settings/SettingsGeneral.cpp
@@ -43,9 +43,12 @@ GeneralTab::GeneralTab(QWidget* parent)
: QWidget(parent), ui_(std::make_shared<Ui_GeneralSettings>()) {
ui_->setupUi(this);
- ui_->saveCheckedKeysBox->setTitle(_("Save Checked Keys"));
+ ui_->cacheBox->setTitle(_("Cache"));
ui_->saveCheckedKeysCheckBox->setText(
_("Save checked private keys on exit and restore them on next start."));
+ ui_->clearGpgPasswordCacheCheckBox->setText(
+ "Clear gpg password cache when closing GpgFrontend.");
+
ui_->longerKeyExpirationDateBox->setTitle(_("Longer Key Expiration Date"));
ui_->longerKeyExpirationDateCheckBox->setText(
_("Unlock key expiration date setting up to 30 years."));
@@ -63,6 +66,10 @@ GeneralTab::GeneralTab(QWidget* parent)
"<b>" + QString(_("NOTE")) + _(": ") + "</b>" +
_("GpgFrontend will restart automatically if you change the language!"));
+ ui_->gnupgDatabaseBox->setTitle(_("GnuPG Key Database Path"));
+ ui_->keyDatabseUseCustomCheckBox->setText(_("Use Custom Path"));
+ ui_->customKeyDatabasePathSelectButton->setText(_("Select Custom Path"));
+
#ifdef MULTI_LANG_SUPPORT
lang_ = SettingsDialog::ListLanguages();
for (const auto& l : lang_) {
@@ -136,6 +143,15 @@ void GeneralTab::SetSettings() {
}
try {
+ bool clear_gpg_password_cache =
+ settings.lookup("general.clear_gpg_password_cache");
+ if (clear_gpg_password_cache)
+ ui_->clearGpgPasswordCacheCheckBox->setCheckState(Qt::Checked);
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("clear_gpg_password_cache");
+ }
+
+ try {
bool longer_expiration_date =
settings.lookup("general.longer_expiration_date");
LOG(INFO) << "longer_expiration_date" << longer_expiration_date;
@@ -223,6 +239,14 @@ void GeneralTab::ApplySettings() {
general["save_key_checked"] = ui_->saveCheckedKeysCheckBox->isChecked();
}
+ if (!general.exists("clear_gpg_password_cache"))
+ general.add("clear_gpg_password_cache", libconfig::Setting::TypeBoolean) =
+ ui_->clearGpgPasswordCacheCheckBox->isChecked();
+ else {
+ general["clear_gpg_password_cache"] =
+ ui_->saveCheckedKeysCheckBox->isChecked();
+ }
+
if (!general.exists("non_ascii_when_export"))
general.add("non_ascii_when_export", libconfig::Setting::TypeBoolean) =
ui_->asciiModeCheckBox->isChecked();
@@ -265,7 +289,7 @@ void GeneralTab::slot_language_changed() { emit SignalRestartNeeded(true); }
void GeneralTab::slot_update_custom_key_database_path_label(int state) {
if (state != Qt::CheckState::Checked) {
ui_->currentKeyDatabasePathLabel->setText(QString::fromStdString(
- GpgContext::GetInstance().GetInfo().DatabasePath));
+ GpgContext::GetInstance().GetInfo(false).DatabasePath));
// hide label (not necessary to show the default path)
this->ui_->currentKeyDatabasePathLabel->setHidden(true);
diff --git a/src/ui/main_window/MainWindow.cpp b/src/ui/main_window/MainWindow.cpp
index b0273d86..a5df66f0 100644
--- a/src/ui/main_window/MainWindow.cpp
+++ b/src/ui/main_window/MainWindow.cpp
@@ -29,6 +29,7 @@
#include "MainWindow.h"
#include "core/function/GlobalSettingStation.h"
+#include "core/function/gpg/GpgAdvancedOperator.h"
#include "ui/SignalStation.h"
#include "ui/UserInterfaceUtils.h"
#include "ui/struct/SettingsObject.h"
@@ -128,6 +129,30 @@ void MainWindow::Init() noexcept {
->PostTask(version_task);
}
+ // before application exit
+ connect(qApp, &QCoreApplication::aboutToQuit, this, []() {
+ LOG(INFO) << "about to quit process started";
+
+ auto &settings = GlobalSettingStation::GetInstance().GetUISettings();
+ try {
+ bool clear_gpg_password_cache =
+ settings.lookup("general.clear_gpg_password_cache");
+
+ if (clear_gpg_password_cache) {
+ if (GpgFrontend::GpgAdvancedOperator::GetInstance()
+ .ClearGpgPasswordCache()) {
+ LOG(INFO) << "clear gpg password cache done";
+ } else {
+ LOG(ERROR) << "clear gpg password cache error";
+ }
+ }
+
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error")
+ << _("clear_gpg_password_cache");
+ }
+ });
+
} catch (...) {
LOG(FATAL) << _("Critical error occur while loading GpgFrontend.");
QMessageBox::critical(nullptr, _("Loading Failed"),
diff --git a/src/ui/main_window/MainWindow.h b/src/ui/main_window/MainWindow.h
index 2e24cecd..e32a02ff 100644
--- a/src/ui/main_window/MainWindow.h
+++ b/src/ui/main_window/MainWindow.h
@@ -328,6 +328,7 @@ class MainWindow : public GeneralMainWindow {
QMenu* file_menu_{}; ///< Submenu for file-operations
QMenu* edit_menu_{}; ///< Submenu for text-operations
QMenu* crypt_menu_{}; ///< Submenu for crypt-operations
+ QMenu* gpg_menu_{}; ///< Submenu for help-operations
QMenu* help_menu_{}; ///< Submenu for help-operations
QMenu* key_menu_{}; ///< Submenu for key-operations
QMenu* view_menu_{}; ///< Submenu for view operations
@@ -369,6 +370,10 @@ class MainWindow : public GeneralMainWindow {
QAction* clean_double_line_breaks_act_{}; ///< Action to remove double line
///< breaks
+ QAction* clean_gpg_password_cache_act_{}; ///<
+ QAction* reload_components_act_{}; ///<
+ QAction* restart_components_act_{}; ///<
+
QAction*
append_selected_keys_act_{}; ///< Action to append selected keys to edit
QAction* copy_mail_address_to_clipboard_act_{}; ///< Action to copy mail to
diff --git a/src/ui/main_window/MainWindowSlotFunction.cpp b/src/ui/main_window/MainWindowSlotFunction.cpp
index f715046c..4a7f721a 100644
--- a/src/ui/main_window/MainWindowSlotFunction.cpp
+++ b/src/ui/main_window/MainWindowSlotFunction.cpp
@@ -36,9 +36,9 @@
#include "core/function/gpg/GpgBasicOperator.h"
#include "core/function/gpg/GpgKeyGetter.h"
#include "core/function/gpg/GpgKeyImportExporter.h"
+#include "dialog/SignersPicker.h"
#include "ui/UserInterfaceUtils.h"
#include "ui/dialog/help/AboutDialog.h"
-#include "dialog/SignersPicker.h"
namespace GpgFrontend::UI {
/**
@@ -662,7 +662,7 @@ void MainWindow::SlotOpenFile(QString& path) { edit_->SlotOpenFile(path); }
void MainWindow::slot_version_upgrade(const SoftwareVersion& version) {
LOG(INFO) << _("Called");
- if (!version.InfoVaild()) {
+ if (!version.InfoValid()) {
LOG(INFO) << "Invalid version info";
return;
}
diff --git a/src/ui/main_window/MainWindowUI.cpp b/src/ui/main_window/MainWindowUI.cpp
index 1470b731..77bf2e14 100644
--- a/src/ui/main_window/MainWindowUI.cpp
+++ b/src/ui/main_window/MainWindowUI.cpp
@@ -27,6 +27,7 @@
*/
#include "MainWindow.h"
+#include "core/function/gpg/GpgAdvancedOperator.h"
#include "ui/UserInterfaceUtils.h"
namespace GpgFrontend::UI {
@@ -241,6 +242,48 @@ void MainWindow::create_actions() {
connect(open_key_management_act_, &QAction::triggered, this,
&MainWindow::slot_open_key_management);
+ clean_gpg_password_cache_act_ = new QAction(_("Clear Password Cache"), this);
+ clean_gpg_password_cache_act_->setIcon(QIcon(":configure.png"));
+ clean_gpg_password_cache_act_->setToolTip(_("Clear Password Cache of GnuPG"));
+ connect(clean_gpg_password_cache_act_, &QAction::triggered, this, [=]() {
+ if (GpgFrontend::GpgAdvancedOperator::GetInstance()
+ .ClearGpgPasswordCache()) {
+ QMessageBox::information(this, _("Successful Operation"),
+ _("Clear password cache successfully"));
+ } else {
+ QMessageBox::critical(this, _("Failed Operation"),
+ _("Failed to clear password cache of GnuPG"));
+ }
+ });
+
+ reload_components_act_ = new QAction(_("Reload All Components"), this);
+ reload_components_act_->setIcon(QIcon(":configure.png"));
+ reload_components_act_->setToolTip(_("Reload All GnuPG's Components"));
+ connect(reload_components_act_, &QAction::triggered, this, [=]() {
+ if (GpgFrontend::GpgAdvancedOperator::GetInstance()
+ .ReloadGpgComponents()) {
+ QMessageBox::information(this, _("Successful Operation"),
+ _("Reload all the GnuPG's components successfully"));
+ } else {
+ QMessageBox::critical(this, _("Failed Operation"),
+ _("Failed to reload all or one of the GnuPG's component(s)"));
+ }
+ });
+
+ restart_components_act_ = new QAction(_("Restart All Components"), this);
+ restart_components_act_->setIcon(QIcon(":configure.png"));
+ restart_components_act_->setToolTip(_("Restart All GnuPG's Components"));
+ connect(restart_components_act_, &QAction::triggered, this, [=]() {
+ if (GpgFrontend::GpgAdvancedOperator::GetInstance()
+ .RestartGpgComponents()) {
+ QMessageBox::information(this, _("Successful Operation"),
+ _("Restart all the GnuPG's components successfully"));
+ } else {
+ QMessageBox::critical(this, _("Failed Operation"),
+ _("Failed to restart all or one of the GnuPG's component(s)"));
+ }
+ });
+
/*
* About Menu
*/
@@ -270,7 +313,7 @@ void MainWindow::create_actions() {
check_update_act_->setIcon(QIcon(":help.png"));
check_update_act_->setToolTip(_("Check for updates"));
connect(check_update_act_, &QAction::triggered, this,
- [=]() { new AboutDialog(2, this); });
+ [=]() { new AboutDialog(3, this); });
start_wizard_act_ = new QAction(_("Open Wizard"), this);
start_wizard_act_->setToolTip(_("Open the wizard"));
@@ -372,6 +415,12 @@ void MainWindow::create_menus() {
import_key_menu_->addAction(import_key_from_key_server_act_);
key_menu_->addAction(open_key_management_act_);
+ gpg_menu_ = menuBar()->addMenu(_("GnuPG"));
+ gpg_menu_->addAction(clean_gpg_password_cache_act_);
+ gpg_menu_->addSeparator();
+ gpg_menu_->addAction(reload_components_act_);
+ gpg_menu_->addAction(restart_components_act_);
+
steganography_menu_ = menuBar()->addMenu(_("Steganography"));
steganography_menu_->addAction(cut_pgp_header_act_);
steganography_menu_->addAction(add_pgp_header_act_);
diff --git a/src/ui/struct/SoftwareVersion.cpp b/src/ui/struct/SoftwareVersion.cpp
index ecccf7c0..0059715a 100644
--- a/src/ui/struct/SoftwareVersion.cpp
+++ b/src/ui/struct/SoftwareVersion.cpp
@@ -27,3 +27,70 @@
*/
#include "SoftwareVersion.h"
+
+int GpgFrontend::UI::SoftwareVersion::version_compare(const std::string& a,
+ const std::string& b) {
+
+ auto temp_a = a, temp_b = b;
+
+ if (!temp_a.empty() && temp_a.front() == 'v') {
+ temp_a = temp_a.erase(0, 1);
+ LOG(INFO) << "real version a" << temp_a;
+ }
+
+ if (!temp_b.empty() && temp_b.front() == 'v') {
+ temp_b.erase(0, 1);
+ LOG(INFO) << "real version b" << temp_b;
+ }
+
+ // First, split the string.
+ std::vector<std::string> va, vb;
+ boost::split(va, temp_a, boost::is_any_of("."));
+ boost::split(vb, temp_b, boost::is_any_of("."));
+
+ // Compare the numbers step by step, but only as deep as the version
+ // with the least elements allows.
+ const int depth =
+ std::min(static_cast<int>(va.size()), static_cast<int>(vb.size()));
+ int ia = 0, ib = 0;
+ for (int i = 0; i < depth; ++i) {
+ try {
+ ia = boost::lexical_cast<int>(va[i]);
+ ib = boost::lexical_cast<int>(vb[i]);
+ } catch (boost::bad_lexical_cast& ignored) {
+ break;
+ }
+ if (ia != ib) break;
+ }
+
+ // Return the required number.
+ if (ia > ib)
+ return 1;
+ else if (ia < ib)
+ return -1;
+ else {
+ // In case of equal versions, assumes that the version
+ // with the most elements is the highest version.
+ if (va.size() > vb.size())
+ return 1;
+ else if (va.size() < vb.size())
+ return -1;
+ }
+
+ // Everything is equal, return 0.
+ return 0;
+}
+
+bool GpgFrontend::UI::SoftwareVersion::NeedUpgrade() const {
+ return load_info_done && !latest_prerelease && !latest_draft &&
+ version_compare(current_version, latest_version) < 0;
+}
+
+bool GpgFrontend::UI::SoftwareVersion::VersionWithDrawn() const {
+ return load_info_done && !current_version_found && current_prerelease &&
+ !current_draft;
+}
+
+bool GpgFrontend::UI::SoftwareVersion::CurrentVersionReleased() const {
+ return load_info_done && current_version_found;
+}
diff --git a/src/ui/struct/SoftwareVersion.h b/src/ui/struct/SoftwareVersion.h
index da93f8c6..942efec9 100644
--- a/src/ui/struct/SoftwareVersion.h
+++ b/src/ui/struct/SoftwareVersion.h
@@ -54,7 +54,7 @@ struct SoftwareVersion {
* @return true
* @return false
*/
- [[nodiscard]] bool InfoVaild() const { return load_info_done; }
+ [[nodiscard]] bool InfoValid() const { return load_info_done; }
/**
* @brief
@@ -62,10 +62,7 @@ struct SoftwareVersion {
* @return true
* @return false
*/
- [[nodiscard]] bool NeedUpgrade() const {
- return load_info_done && !latest_prerelease && !latest_draft &&
- current_version < latest_version;
- }
+ [[nodiscard]] bool NeedUpgrade() const;
/**
* @brief
@@ -73,10 +70,7 @@ struct SoftwareVersion {
* @return true
* @return false
*/
- [[nodiscard]] bool VersionWithDrawn() const {
- return load_info_done && !current_version_found && current_prerelease &&
- !current_draft;
- }
+ [[nodiscard]] bool VersionWithDrawn() const;
/**
* @brief
@@ -84,9 +78,11 @@ struct SoftwareVersion {
* @return true
* @return false
*/
- [[nodiscard]] bool CurrentVersionReleased() const {
- return load_info_done && current_version_found;
- }
+ [[nodiscard]] bool CurrentVersionReleased() const;
+
+ private:
+
+ static int version_compare(const std::string& a, const std::string& b);
};
} // namespace GpgFrontend::UI
diff --git a/ui/GeneralSettings.ui b/ui/GeneralSettings.ui
index 4121e762..678f02a9 100644
--- a/ui/GeneralSettings.ui
+++ b/ui/GeneralSettings.ui
@@ -37,9 +37,9 @@
</widget>
</item>
<item>
- <widget class="QGroupBox" name="saveCheckedKeysBox">
+ <widget class="QGroupBox" name="cacheBox">
<property name="title">
- <string>Save Checked Keys</string>
+ <string>Cache</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
@@ -51,6 +51,13 @@
</property>
</widget>
</item>
+ <item>
+ <widget class="QCheckBox" name="clearGpgPasswordCacheCheckBox">
+ <property name="text">
+ <string>Clear gpg password cache when closing GpgFrontend.</string>
+ </property>
+ </widget>
+ </item>
</layout>
</item>
</layout>
diff --git a/ui/GnuPGInfo.ui b/ui/GnuPGInfo.ui
index f907874f..3a778dc2 100644
--- a/ui/GnuPGInfo.ui
+++ b/ui/GnuPGInfo.ui
@@ -16,17 +16,20 @@
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,0,0">
+ <property name="spacing">
+ <number>0</number>
+ </property>
<property name="leftMargin">
- <number>5</number>
+ <number>0</number>
</property>
<property name="topMargin">
- <number>5</number>
+ <number>0</number>
</property>
<property name="rightMargin">
- <number>5</number>
+ <number>0</number>
</property>
<property name="bottomMargin">
- <number>5</number>
+ <number>0</number>
</property>
<item>
<widget class="QLabel" name="label">
@@ -64,7 +67,7 @@
</widget>
</item>
<item>
- <widget class="QLabel" name="componentDetailsTableTitle">
+ <widget class="QLabel" name="softwareDetailsTableTitle">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
@@ -72,7 +75,7 @@
</sizepolicy>
</property>
<property name="text">
- <string>Components Information</string>
+ <string>Software Information</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
@@ -83,7 +86,45 @@
</widget>
</item>
<item>
- <widget class="QTableWidget" name="conponentDetailsTable"/>
+ <widget class="QTabWidget" name="tabWidget">
+ <property name="currentIndex">
+ <number>1</number>
+ </property>
+ <widget class="QWidget" name="tab">
+ <attribute name="title">
+ <string>Components</string>
+ </attribute>
+ <layout class="QGridLayout" name="gridLayout_3">
+ <item row="0" column="0">
+ <widget class="QTableWidget" name="componentDetailsTable">
+ <property name="sizeAdjustPolicy">
+ <enum>QAbstractScrollArea::AdjustToContents</enum>
+ </property>
+ <property name="editTriggers">
+ <set>QAbstractItemView::NoEditTriggers</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="tab_2">
+ <attribute name="title">
+ <string>Configurations</string>
+ </attribute>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="0" column="0">
+ <widget class="QTableWidget" name="configurationDetailsTable">
+ <property name="sizeAdjustPolicy">
+ <enum>QAbstractScrollArea::AdjustToContents</enum>
+ </property>
+ <property name="editTriggers">
+ <set>QAbstractItemView::NoEditTriggers</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
</item>
</layout>
</item>