aboutsummaryrefslogtreecommitdiffstats
path: root/src/ui/dialog
diff options
context:
space:
mode:
authorSaturn&Eric <[email protected]>2022-07-23 14:54:51 +0000
committerGitHub <[email protected]>2022-07-23 14:54:51 +0000
commitb244320b2d228189767aa6d59febceb6b64527fb (patch)
tree179d34e2a3e84231fad72c4bbe9f74673d0b74d0 /src/ui/dialog
parentMerge pull request #68 from saturneric/develop-2.0.8 (diff)
parentfeat(project): add rpm package support (diff)
downloadGpgFrontend-2.0.9.tar.gz
GpgFrontend-2.0.9.zip
Merge pull request #70 from saturneric/dev/2.0.8/saturnericv2.0.9
Develop 2.0.9.1
Diffstat (limited to 'src/ui/dialog')
-rw-r--r--src/ui/dialog/GeneralDialog.cpp88
-rw-r--r--src/ui/dialog/GeneralDialog.h66
-rwxr-xr-xsrc/ui/dialog/QuitDialog.cpp4
-rwxr-xr-xsrc/ui/dialog/QuitDialog.h3
-rw-r--r--src/ui/dialog/SignersPicker.cpp83
-rw-r--r--src/ui/dialog/SignersPicker.h73
-rw-r--r--src/ui/dialog/Wizard.h6
-rw-r--r--src/ui/dialog/details/SignatureDetailsDialog.cpp29
-rw-r--r--src/ui/dialog/details/SignatureDetailsDialog.h39
-rw-r--r--src/ui/dialog/details/VerifyDetailsDialog.cpp97
-rw-r--r--src/ui/dialog/details/VerifyDetailsDialog.h75
-rw-r--r--src/ui/dialog/help/AboutDialog.cpp259
-rw-r--r--src/ui/dialog/help/AboutDialog.h146
-rw-r--r--src/ui/dialog/help/GnupgTab.cpp66
-rw-r--r--src/ui/dialog/help/GnupgTab.h53
-rw-r--r--src/ui/dialog/import_export/ExportKeyPackageDialog.cpp145
-rw-r--r--src/ui/dialog/import_export/ExportKeyPackageDialog.h62
-rw-r--r--src/ui/dialog/import_export/KeyImportDetailDialog.cpp204
-rw-r--r--src/ui/dialog/import_export/KeyImportDetailDialog.h92
-rw-r--r--src/ui/dialog/import_export/KeyServerImportDialog.cpp550
-rw-r--r--src/ui/dialog/import_export/KeyServerImportDialog.h182
-rw-r--r--src/ui/dialog/import_export/KeyUploadDialog.cpp159
-rw-r--r--src/ui/dialog/import_export/KeyUploadDialog.h83
-rw-r--r--src/ui/dialog/key_generate/KeygenDialog.cpp407
-rw-r--r--src/ui/dialog/key_generate/KeygenDialog.h184
-rw-r--r--src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp344
-rw-r--r--src/ui/dialog/key_generate/SubkeyGenerateDialog.h152
-rw-r--r--src/ui/dialog/keypair_details/KeyDetailsDialog.cpp62
-rw-r--r--src/ui/dialog/keypair_details/KeyDetailsDialog.h49
-rw-r--r--src/ui/dialog/keypair_details/KeyNewUIDDialog.cpp114
-rw-r--r--src/ui/dialog/keypair_details/KeyNewUIDDialog.h88
-rw-r--r--src/ui/dialog/keypair_details/KeyPairDetailTab.cpp276
-rw-r--r--src/ui/dialog/keypair_details/KeyPairDetailTab.h99
-rw-r--r--src/ui/dialog/keypair_details/KeyPairOperaTab.cpp360
-rw-r--r--src/ui/dialog/keypair_details/KeyPairOperaTab.h113
-rw-r--r--src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp338
-rw-r--r--src/ui/dialog/keypair_details/KeyPairSubkeyTab.h139
-rw-r--r--src/ui/dialog/keypair_details/KeyPairUIDTab.cpp583
-rw-r--r--src/ui/dialog/keypair_details/KeyPairUIDTab.h207
-rw-r--r--src/ui/dialog/keypair_details/KeySetExpireDateDialog.cpp145
-rw-r--r--src/ui/dialog/keypair_details/KeySetExpireDateDialog.h99
-rw-r--r--src/ui/dialog/keypair_details/KeyUIDSignDialog.cpp134
-rw-r--r--src/ui/dialog/keypair_details/KeyUIDSignDialog.h78
-rw-r--r--src/ui/dialog/settings/SettingsAdvanced.cpp104
-rw-r--r--src/ui/dialog/settings/SettingsAdvanced.h55
-rw-r--r--src/ui/dialog/settings/SettingsAppearance.cpp207
-rw-r--r--src/ui/dialog/settings/SettingsAppearance.h83
-rw-r--r--src/ui/dialog/settings/SettingsDialog.cpp146
-rw-r--r--src/ui/dialog/settings/SettingsDialog.h112
-rw-r--r--src/ui/dialog/settings/SettingsGeneral.cpp196
-rw-r--r--src/ui/dialog/settings/SettingsGeneral.h99
-rw-r--r--src/ui/dialog/settings/SettingsKeyServer.cpp301
-rw-r--r--src/ui/dialog/settings/SettingsKeyServer.h111
-rw-r--r--src/ui/dialog/settings/SettingsNetwork.cpp338
-rw-r--r--src/ui/dialog/settings/SettingsNetwork.h94
55 files changed, 8375 insertions, 6 deletions
diff --git a/src/ui/dialog/GeneralDialog.cpp b/src/ui/dialog/GeneralDialog.cpp
new file mode 100644
index 00000000..d07c2497
--- /dev/null
+++ b/src/ui/dialog/GeneralDialog.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2022. 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
+ */
+
+#include "GeneralDialog.h"
+
+#include "ui/struct/SettingsObject.h"
+
+GpgFrontend::UI::GeneralDialog::GeneralDialog(std::string name, QWidget *parent)
+ : name_(std::move(name)), QDialog(parent) {
+ slot_restore_settings();
+ connect(this, &QDialog::finished, this, &GeneralDialog::slot_save_settings);
+}
+
+GpgFrontend::UI::GeneralDialog::~GeneralDialog() = default;
+
+void GpgFrontend::UI::GeneralDialog::slot_restore_settings() noexcept {
+ try {
+ LOG(INFO) << name_ << _("Called");
+
+ SettingsObject general_windows_state(name_ + "_dialog_state");
+
+ bool window_save = general_windows_state.Check("window_save", true);
+
+ // Restore window size & location
+ if (window_save) {
+ int x = general_windows_state.Check("window_pos").Check("x", 100),
+ y = general_windows_state.Check("window_pos").Check("y", 100);
+
+ this->move({x, y});
+ pos_ = {x, y};
+
+ int width =
+ general_windows_state.Check("window_size").Check("width", 400),
+ height =
+ general_windows_state.Check("window_size").Check("height", 247);
+
+ this->resize({width, height});
+ size_ = {width, height};
+
+ }
+
+ } catch (...) {
+ LOG(ERROR) << name_ << "error";
+ }
+}
+
+void GpgFrontend::UI::GeneralDialog::slot_save_settings() noexcept {
+ try {
+ LOG(INFO) << name_ << _("Called");
+
+ SettingsObject general_windows_state(name_ + "_dialog_state");
+
+ // window position and size
+ general_windows_state["window_pos"]["x"] = pos().x();
+ general_windows_state["window_pos"]["y"] = pos().y();
+
+ general_windows_state["window_size"]["width"] = size_.width();
+ general_windows_state["window_size"]["height"] = size_.height();
+ general_windows_state["window_save"] = true;
+
+ } catch (...) {
+ LOG(ERROR) << name_ << "error";
+ }
+}
diff --git a/src/ui/dialog/GeneralDialog.h b/src/ui/dialog/GeneralDialog.h
new file mode 100644
index 00000000..ca480c8b
--- /dev/null
+++ b/src/ui/dialog/GeneralDialog.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2022. 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
+ */
+
+#ifndef GPGFRONTEND_GENERALDIALOG_H
+#define GPGFRONTEND_GENERALDIALOG_H
+
+#include "ui/GpgFrontendUI.h"
+
+namespace GpgFrontend::UI {
+
+class GeneralDialog : public QDialog {
+ public:
+ /**
+ *
+ * @param name
+ */
+ explicit GeneralDialog(std::string name, QWidget* parent = nullptr);
+
+ /**
+ *
+ */
+ ~GeneralDialog() override;
+
+ private slots:
+ /**
+ *
+ */
+ void slot_restore_settings() noexcept;
+
+ /**
+ *
+ */
+ void slot_save_settings() noexcept;
+
+ private:
+ std::string name_; ///<
+ QPoint pos_; ///<
+ QSize size_; ///<
+};
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_GENERALDIALOG_H
diff --git a/src/ui/dialog/QuitDialog.cpp b/src/ui/dialog/QuitDialog.cpp
index da0be488..87b1c1e1 100755
--- a/src/ui/dialog/QuitDialog.cpp
+++ b/src/ui/dialog/QuitDialog.cpp
@@ -33,7 +33,7 @@
namespace GpgFrontend::UI {
QuitDialog::QuitDialog(QWidget* parent, const QHash<int, QString>& unsavedDocs)
- : QDialog(parent) {
+ : GeneralDialog("quit_dialog", parent) {
setWindowTitle(_("Unsaved Files"));
setModal(true);
discarded_ = false;
@@ -111,7 +111,7 @@ QuitDialog::QuitDialog(QWidget* parent, const QHash<int, QString>& unsavedDocs)
connect(buttonBox, &QDialogButtonBox::accepted, this, &QuitDialog::accept);
connect(buttonBox, &QDialogButtonBox::rejected, this, &QuitDialog::reject);
QPushButton* btnNoKey = buttonBox->button(QDialogButtonBox::Discard);
- connect(btnNoKey, &QPushButton::clicked, this,&QuitDialog::slot_my_discard);
+ connect(btnNoKey, &QPushButton::clicked, this, &QuitDialog::slot_my_discard);
/*
* Set the layout
diff --git a/src/ui/dialog/QuitDialog.h b/src/ui/dialog/QuitDialog.h
index 2d09790b..2fd9e382 100755
--- a/src/ui/dialog/QuitDialog.h
+++ b/src/ui/dialog/QuitDialog.h
@@ -30,6 +30,7 @@
#define __QUITDIALOG_H__
#include "ui/GpgFrontendUI.h"
+#include "ui/dialog/GeneralDialog.h"
namespace GpgFrontend::UI {
@@ -37,7 +38,7 @@ namespace GpgFrontend::UI {
* @brief
*
*/
-class QuitDialog : public QDialog {
+class QuitDialog : public GeneralDialog {
Q_OBJECT
public:
diff --git a/src/ui/dialog/SignersPicker.cpp b/src/ui/dialog/SignersPicker.cpp
new file mode 100644
index 00000000..a670e514
--- /dev/null
+++ b/src/ui/dialog/SignersPicker.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2022. 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
+ */
+
+#include "SignersPicker.h"
+
+#include "ui/widgets/KeyList.h"
+
+namespace GpgFrontend::UI {
+
+SignersPicker::SignersPicker(QWidget* parent)
+ : GeneralDialog(typeid(SignersPicker).name(), parent) {
+ auto confirm_button = new QPushButton(_("Confirm"));
+ auto cancel_button = new QPushButton(_("Cancel"));
+
+ connect(confirm_button, &QPushButton::clicked, [=]() {
+ this->accepted_ = true;
+ });
+ connect(confirm_button, &QPushButton::clicked, this, &QDialog::accept);
+ connect(cancel_button, &QPushButton::clicked, this, &QDialog::reject);
+
+ /*Setup KeyList*/
+ key_list_ = new KeyList(false, this);
+ key_list_->AddListGroupTab(
+ _("Signers"), KeyListRow::ONLY_SECRET_KEY,
+ KeyListColumn::NAME | KeyListColumn::EmailAddress | KeyListColumn::Usage,
+ [](const GpgKey& key) -> bool {
+ return key.IsHasActualSigningCapability();
+ });
+ key_list_->SlotRefresh();
+
+ auto* vbox2 = new QVBoxLayout();
+ vbox2->addWidget(new QLabel(QString(_("Select Signer(s)")) + ": "));
+ vbox2->addWidget(key_list_);
+ vbox2->addWidget(new QLabel(
+ QString(
+ _("Please select one or more private keys you use for signing.")) +
+ "\n" +
+ _("If no key is selected, the default key will be used for signing.")));
+ vbox2->addWidget(confirm_button);
+ vbox2->addWidget(cancel_button);
+ vbox2->addStretch(0);
+ setLayout(vbox2);
+
+ this->setWindowFlags(Qt::Window | Qt::WindowTitleHint |
+ Qt::CustomizeWindowHint);
+
+ this->setModal(true);
+ this->setWindowTitle("Signers Picker");
+ this->setMinimumWidth(480);
+ this->show();
+}
+
+GpgFrontend::KeyIdArgsListPtr SignersPicker::GetCheckedSigners() {
+ return key_list_->GetPrivateChecked();
+}
+
+bool SignersPicker::GetStatus() const { return this->accepted_; }
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/dialog/SignersPicker.h b/src/ui/dialog/SignersPicker.h
new file mode 100644
index 00000000..5533f9d8
--- /dev/null
+++ b/src/ui/dialog/SignersPicker.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2022. 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
+ */
+
+#ifndef GPGFRONTEND_ZH_CN_TS_SIGNERSPIRCKER_H
+#define GPGFRONTEND_ZH_CN_TS_SIGNERSPIRCKER_H
+
+#include "GpgFrontendUI.h"
+#include "ui/dialog//GeneralDialog.h"
+
+namespace GpgFrontend::UI {
+
+class KeyList;
+
+/**
+ * @brief
+ *
+ */
+class SignersPicker : public GeneralDialog {
+ Q_OBJECT
+
+ public:
+ /**
+ * @brief Construct a new Signers Picker object
+ *
+ * @param parent
+ */
+ explicit SignersPicker(QWidget* parent = nullptr);
+
+ /**
+ * @brief Get the Checked Signers object
+ *
+ * @return GpgFrontend::KeyIdArgsListPtr
+ */
+ GpgFrontend::KeyIdArgsListPtr GetCheckedSigners();
+
+ /**
+ *
+ * @return
+ */
+ [[nodiscard]] bool GetStatus() const;
+
+ private:
+ KeyList* key_list_; ///<
+ bool accepted_ = false;
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_ZH_CN_TS_SIGNERSPIRCKER_H
diff --git a/src/ui/dialog/Wizard.h b/src/ui/dialog/Wizard.h
index eb093550..879dc5d9 100644
--- a/src/ui/dialog/Wizard.h
+++ b/src/ui/dialog/Wizard.h
@@ -30,10 +30,10 @@
#define WIZARD_H
#include "core/GpgConstants.h"
+#include "main_window/KeyMgmt.h"
#include "ui/GpgFrontendUI.h"
-#include "ui/KeyMgmt.h"
-#include "ui/key_generate/KeygenDialog.h"
-#include "ui/settings/SettingsDialog.h"
+#include "ui/dialog/key_generate/KeygenDialog.h"
+#include "ui/dialog/settings/SettingsDialog.h"
namespace GpgFrontend::UI {
diff --git a/src/ui/dialog/details/SignatureDetailsDialog.cpp b/src/ui/dialog/details/SignatureDetailsDialog.cpp
new file mode 100644
index 00000000..a3ad03b3
--- /dev/null
+++ b/src/ui/dialog/details/SignatureDetailsDialog.cpp
@@ -0,0 +1,29 @@
+/**
+ * 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 <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
+ *
+ */
+
+#include "SignatureDetailsDialog.h"
diff --git a/src/ui/dialog/details/SignatureDetailsDialog.h b/src/ui/dialog/details/SignatureDetailsDialog.h
new file mode 100644
index 00000000..7b01d054
--- /dev/null
+++ b/src/ui/dialog/details/SignatureDetailsDialog.h
@@ -0,0 +1,39 @@
+/**
+ * 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 <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
+ *
+ */
+
+#ifndef GPGFRONTEND_SIGNATUREDETAILSDIALOG_H
+#define GPGFRONTEND_SIGNATUREDETAILSDIALOG_H
+
+#include "ui/GpgFrontendUI.h"
+
+class SignatureDetailsDialog : public QDialog {
+ Q_OBJECT
+ public:
+};
+
+#endif // GPGFRONTEND_SIGNATUREDETAILSDIALOG_H
diff --git a/src/ui/dialog/details/VerifyDetailsDialog.cpp b/src/ui/dialog/details/VerifyDetailsDialog.cpp
new file mode 100644
index 00000000..d2af4ee1
--- /dev/null
+++ b/src/ui/dialog/details/VerifyDetailsDialog.cpp
@@ -0,0 +1,97 @@
+/**
+ * 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 <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
+ *
+ */
+
+#include "VerifyDetailsDialog.h"
+
+#include <boost/format.hpp>
+
+namespace GpgFrontend::UI {
+
+VerifyDetailsDialog::VerifyDetailsDialog(QWidget* parent, GpgError error,
+ GpgVerifyResult result)
+ : QDialog(parent), m_result_(std::move(result)), error_(error) {
+ this->setWindowTitle(_("Signatures Details"));
+
+ main_layout_ = new QHBoxLayout();
+ this->setLayout(main_layout_);
+
+ slot_refresh();
+
+ this->exec();
+}
+
+void VerifyDetailsDialog::slot_refresh() {
+ m_vbox_ = new QWidget();
+ auto* mVboxLayout = new QVBoxLayout(m_vbox_);
+ main_layout_->addWidget(m_vbox_);
+
+ // Button Box for close button
+ button_box_ = new QDialogButtonBox(QDialogButtonBox::Close);
+ connect(button_box_, &QDialogButtonBox::rejected, this,
+ &VerifyDetailsDialog::close);
+
+ auto sign = m_result_->signatures;
+
+ if (sign == nullptr) {
+ mVboxLayout->addWidget(new QLabel(_("No valid input found")));
+ mVboxLayout->addWidget(button_box_);
+ return;
+ }
+
+ // Get timestamp of signature of current text
+ QDateTime timestamp;
+ timestamp.setTime_t(sign->timestamp);
+
+ // Set the title widget depending on sign status
+ if (gpg_err_code(sign->status) == GPG_ERR_BAD_SIGNATURE) {
+ mVboxLayout->addWidget(new QLabel(_("Error Validating signature")));
+ } else if (input_signature_ != nullptr) {
+ const auto info = (boost::format(_("File was signed on %1%")) %
+ QLocale::system().toString(timestamp).toStdString())
+ .str() +
+ "<br/>" + _("It Contains") + ": " + "<br/><br/>";
+ mVboxLayout->addWidget(new QLabel(info.c_str()));
+ } else {
+ const auto info = (boost::format(_("Signed on %1%")) %
+ QLocale::system().toString(timestamp).toStdString())
+ .str() +
+ "<br/>" + _("It Contains") + ": " + "<br/><br/>";
+ mVboxLayout->addWidget(new QLabel(info.c_str()));
+ }
+ // Add information box for every single key
+ while (sign) {
+ GpgSignature signature(sign);
+ auto* sign_box = new VerifyKeyDetailBox(signature, this);
+ sign = sign->next;
+ mVboxLayout->addWidget(sign_box);
+ }
+
+ mVboxLayout->addWidget(button_box_);
+}
+
+} // namespace GpgFrontend::UI \ No newline at end of file
diff --git a/src/ui/dialog/details/VerifyDetailsDialog.h b/src/ui/dialog/details/VerifyDetailsDialog.h
new file mode 100644
index 00000000..97e2cc2d
--- /dev/null
+++ b/src/ui/dialog/details/VerifyDetailsDialog.h
@@ -0,0 +1,75 @@
+/**
+ * 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 <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
+ *
+ */
+
+#ifndef __VERIFYDETAILSDIALOG_H__
+#define __VERIFYDETAILSDIALOG_H__
+
+#include "ui/GpgFrontendUI.h"
+#include "ui/widgets/PlainTextEditorPage.h"
+#include "ui/widgets/VerifyKeyDetailBox.h"
+
+namespace GpgFrontend::UI {
+/**
+ * @brief
+ *
+ */
+class VerifyDetailsDialog : public QDialog {
+ Q_OBJECT
+ public:
+ /**
+ * @brief Construct a new Verify Details Dialog object
+ *
+ * @param parent
+ * @param error
+ * @param result
+ */
+ explicit VerifyDetailsDialog(QWidget* parent, GpgError error,
+ GpgVerifyResult result);
+
+ private slots:
+
+ /**
+ * @brief
+ *
+ */
+ void slot_refresh();
+
+ private:
+ KeyList* key_list_; ///<
+ QHBoxLayout* main_layout_; ///<
+ QWidget* m_vbox_{}; ///<
+ QByteArray* input_data_{}; ///<
+ QByteArray* input_signature_{}; ///<
+ QDialogButtonBox* button_box_{}; ///<
+ GpgVerifyResult m_result_; ///<
+ gpgme_error_t error_; ///<
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // __VERIFYDETAILSDIALOG_H__
diff --git a/src/ui/dialog/help/AboutDialog.cpp b/src/ui/dialog/help/AboutDialog.cpp
new file mode 100644
index 00000000..6b6e4356
--- /dev/null
+++ b/src/ui/dialog/help/AboutDialog.cpp
@@ -0,0 +1,259 @@
+/**
+ * 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 <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
+ *
+ */
+
+#include "AboutDialog.h"
+
+#include "GpgFrontendBuildInfo.h"
+#include "core/function/GlobalSettingStation.h"
+#include "core/thread/TaskRunnerGetter.h"
+#include "ui/dialog/help/GnupgTab.h"
+#include "ui/thread/VersionCheckTask.h"
+
+namespace GpgFrontend::UI {
+
+AboutDialog::AboutDialog(int defaultIndex, QWidget* parent)
+ : GeneralDialog(typeid(AboutDialog).name(), parent) {
+ this->setWindowTitle(QString(_("About")) + " " + qApp->applicationName());
+
+ auto* tab_widget = new QTabWidget;
+ auto* info_tab = new InfoTab();
+ auto* gnupg_tab = new GnupgTab();
+ auto* translators_tab = new TranslatorsTab();
+ update_tab_ = new UpdateTab();
+
+ tab_widget->addTab(info_tab, _("About GpgFrontend"));
+ tab_widget->addTab(gnupg_tab, _("GnuPG"));
+ tab_widget->addTab(translators_tab, _("Translators"));
+ tab_widget->addTab(update_tab_, _("Update"));
+
+ connect(tab_widget, &QTabWidget::currentChanged, this,
+ [&](int index) { LOG(INFO) << "Current Index" << index; });
+
+ if (defaultIndex < tab_widget->count() && defaultIndex >= 0) {
+ tab_widget->setCurrentIndex(defaultIndex);
+ }
+
+ auto* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok);
+ connect(buttonBox, &QDialogButtonBox::accepted, this, &AboutDialog::close);
+
+ auto* mainLayout = new QVBoxLayout;
+ mainLayout->addWidget(tab_widget);
+ mainLayout->addWidget(buttonBox);
+ setLayout(mainLayout);
+
+ this->resize(450, 580);
+ this->setMinimumWidth(450);
+ this->show();
+}
+
+void AboutDialog::showEvent(QShowEvent* ev) {
+ QDialog::showEvent(ev);
+ update_tab_->getLatestVersion();
+}
+
+InfoTab::InfoTab(QWidget* parent) : QWidget(parent) {
+ auto* pixmap = new QPixmap(":gpgfrontend-logo.png");
+ auto* text = new QString(
+ "<center><h2>" + qApp->applicationName() + "</h2></center>" +
+ "<center><b>" + qApp->applicationVersion() + "</b></center>" +
+ "<center>" + GIT_VERSION + "</center>" + "<br><center>" +
+ _("GpgFrontend is an easy-to-use, compact, cross-platform, "
+ "and installation-free gpg front-end tool."
+ "It visualizes most of the common operations of gpg commands."
+ "It's licensed under the GPL v3") +
+ "<br><br>"
+ "<b>" +
+ _("Developer:") + "</b><br>" + "Saturneric" + "<br><br>" +
+ _("If you have any questions or suggestions, raise an issue at") +
+ "<br/>"
+ " <a href=\"https://github.com/saturneric/GpgFrontend\">GitHub</a> " +
+ _("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() +
+ "<br>" + _("Built at") + " " + BUILD_TIMESTAMP + "</center>");
+
+ auto* layout = new QGridLayout();
+ auto* pixmapLabel = new QLabel();
+ pixmapLabel->setPixmap(*pixmap);
+ layout->addWidget(pixmapLabel, 0, 0, 1, -1, Qt::AlignCenter);
+ auto* aboutLabel = new QLabel();
+ aboutLabel->setText(*text);
+ aboutLabel->setWordWrap(true);
+ aboutLabel->setOpenExternalLinks(true);
+ layout->addWidget(aboutLabel, 1, 0, 1, -1);
+ layout->addItem(
+ new QSpacerItem(20, 10, QSizePolicy::Minimum, QSizePolicy::Fixed), 2, 1,
+ 1, 1);
+
+ setLayout(layout);
+}
+
+TranslatorsTab::TranslatorsTab(QWidget* parent) : QWidget(parent) {
+ QFile translators_qfile;
+ auto translators_file =
+ GlobalSettingStation::GetInstance().GetResourceDir() / "TRANSLATORS";
+ translators_qfile.setFileName(translators_file.u8string().c_str());
+#ifdef LINUX
+ if (!translators_qfile.exists()) {
+ translators_qfile.setFileName("/usr/local/share/GpgFrontend/TRANSLATORS");
+ }
+#endif
+
+ translators_qfile.open(QIODevice::ReadOnly);
+ QByteArray in_buffer = translators_qfile.readAll();
+
+ auto* label = new QLabel(in_buffer);
+
+ auto* main_layout = new QVBoxLayout(this);
+ main_layout->addWidget(label);
+ main_layout->addStretch();
+
+ auto notice_label = new QLabel(
+ _("If you think there are any problems with the translation, why not "
+ "participate in the translation work? If you want to participate, "
+ "please "
+ "read the document or contact me via email."),
+ this);
+ notice_label->setWordWrap(true);
+ main_layout->addWidget(notice_label);
+
+ setLayout(main_layout);
+}
+
+UpdateTab::UpdateTab(QWidget* parent) : QWidget(parent) {
+ auto* pixmap = new QPixmap(":gpgfrontend-logo.png");
+ auto* layout = new QGridLayout();
+ auto* pixmap_label = new QLabel();
+ pixmap_label->setPixmap(*pixmap);
+ layout->addWidget(pixmap_label, 0, 0, 1, -1, Qt::AlignCenter);
+
+ current_version_ = "v" + QString::number(VERSION_MAJOR) + "." +
+ QString::number(VERSION_MINOR) + "." +
+ QString::number(VERSION_PATCH);
+
+ auto tips_label = new QLabel();
+ tips_label->setText(
+ "<center>" +
+ QString(_("It is recommended that you always check the version "
+ "of GpgFrontend and upgrade to the latest version.")) +
+ "</center><center>" +
+ _("New versions not only represent new features, but "
+ "also often represent functional and security fixes.") +
+ "</center>");
+ tips_label->setWordWrap(true);
+
+ current_version_label_ = new QLabel();
+ current_version_label_->setText("<center>" + QString(_("Current Version")) +
+ _(": ") + "<b>" + current_version_ +
+ "</b></center>");
+ current_version_label_->setWordWrap(true);
+
+ latest_version_label_ = new QLabel();
+ latest_version_label_->setWordWrap(true);
+
+ upgrade_label_ = new QLabel();
+ upgrade_label_->setWordWrap(true);
+ upgrade_label_->setOpenExternalLinks(true);
+ upgrade_label_->setHidden(true);
+
+ pb_ = new QProgressBar();
+ pb_->setRange(0, 0);
+ pb_->setTextVisible(false);
+
+ layout->addWidget(tips_label, 1, 0, 1, -1);
+ layout->addWidget(current_version_label_, 2, 0, 1, -1);
+ layout->addWidget(latest_version_label_, 3, 0, 1, -1);
+ layout->addWidget(upgrade_label_, 4, 0, 1, -1);
+ layout->addWidget(pb_, 5, 0, 1, -1);
+ layout->addItem(
+ new QSpacerItem(20, 10, QSizePolicy::Minimum, QSizePolicy::Fixed), 2, 1,
+ 1, 1);
+
+ setLayout(layout);
+}
+
+void UpdateTab::getLatestVersion() {
+ this->pb_->setHidden(false);
+
+ LOG(INFO) << _("try to get latest version");
+
+ auto* version_task = new VersionCheckTask();
+
+ connect(version_task, &VersionCheckTask::SignalUpgradeVersion, this,
+ &UpdateTab::slot_show_version_status);
+
+ Thread::TaskRunnerGetter::GetInstance()
+ .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Network)
+ ->PostTask(version_task);
+}
+
+void UpdateTab::slot_show_version_status(const SoftwareVersion& version) {
+ this->pb_->setHidden(true);
+ latest_version_label_->setText(
+ "<center><b>" + QString(_("Latest Version From Github")) + ": " +
+ version.latest_version.c_str() + "</b></center>");
+
+ if (version.NeedUpgrade()) {
+ upgrade_label_->setText(
+ "<center>" +
+ QString(_("The current version is less than the latest version on "
+ "github.")) +
+ "</center><center>" + _("Please click") +
+ " <a "
+ "href=\"https://www.gpgfrontend.pub/#/downloads\">" +
+ _("Here") + "</a> " + _("to download the latest stable version.") +
+ "</center>");
+ upgrade_label_->show();
+ } else if (version.VersionWithDrawn()) {
+ upgrade_label_->setText(
+ "<center>" +
+ QString(_("This version has serious problems and has been withdrawn. "
+ "Please stop using it immediately.")) +
+ "</center><center>" + _("Please click") +
+ " <a "
+ "href=\"https://github.com/saturneric/GpgFrontend/releases\">" +
+ _("Here") + "</a> " + _("to download the latest stable version.") +
+ "</center>");
+ upgrade_label_->show();
+ } else if (!version.CurrentVersionReleased()) {
+ upgrade_label_->setText(
+ "<center>" +
+ QString(_("This version has not been released yet, it may be a beta "
+ "version. If you are not a tester and care about version "
+ "stability, please do not use this version.")) +
+ "</center><center>" + _("Please click") +
+ " <a "
+ "href=\"https://www.gpgfrontend.pub/#/downloads\">" +
+ _("Here") + "</a> " + _("to download the latest stable version.") +
+ "</center>");
+ upgrade_label_->show();
+ }
+}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/dialog/help/AboutDialog.h b/src/ui/dialog/help/AboutDialog.h
new file mode 100644
index 00000000..09a63734
--- /dev/null
+++ b/src/ui/dialog/help/AboutDialog.h
@@ -0,0 +1,146 @@
+/**
+ * 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 <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
+ *
+ */
+
+#ifndef __ABOUTDIALOG_H__
+#define __ABOUTDIALOG_H__
+
+#include "core/GpgContext.h"
+#include "ui/GpgFrontendUI.h"
+#include "ui/dialog/GeneralDialog.h"
+#include "ui/struct/SoftwareVersion.h"
+
+namespace GpgFrontend::UI {
+
+/**
+ * @brief Class containing the main tab of about dialog
+ *
+ */
+class InfoTab : public QWidget {
+ Q_OBJECT
+
+ public:
+ /**
+ * @brief Construct a new Info Tab object
+ *
+ * @param parent
+ */
+ explicit InfoTab(QWidget* parent = nullptr);
+};
+
+/**
+ * @brief Class containing the translator tab of about dialog
+ *
+ */
+class TranslatorsTab : public QWidget {
+ Q_OBJECT
+
+ public:
+ /**
+ * @brief Construct a new Translators Tab object
+ *
+ * @param parent
+ */
+ explicit TranslatorsTab(QWidget* parent = nullptr);
+};
+
+/**
+ * @brief Class containing the main tab of about dialog
+ *
+ */
+class UpdateTab : public QWidget {
+ Q_OBJECT
+
+ QLabel* current_version_label_; ///<
+ QLabel* latest_version_label_; ///<
+ QLabel* upgrade_label_; ///<
+ QProgressBar* pb_; ///<
+ QString current_version_; ///<
+ QPushButton* download_button_; ///<
+
+ public:
+ /**
+ * @brief Construct a new Update Tab object
+ *
+ * @param parent
+ */
+ explicit UpdateTab(QWidget* parent = nullptr);
+
+ /**
+ * @brief Get the Latest Version object
+ *
+ */
+ void getLatestVersion();
+
+ private slots:
+ /**
+ * @brief
+ *
+ * @param version
+ */
+ void slot_show_version_status(const SoftwareVersion& version);
+
+ signals:
+ /**
+ * @brief
+ *
+ * @param data
+ */
+ void SignalReplyFromUpdateServer(QByteArray data);
+};
+
+/**
+ * @brief Class for handling the about dialog
+ *
+ */
+class AboutDialog : public GeneralDialog {
+ Q_OBJECT
+
+ public:
+ /**
+ * @brief Construct a new About Dialog object
+ *
+ * @param defaultIndex
+ * @param parent
+ */
+ explicit AboutDialog(int defaultIndex, QWidget* parent);
+
+ protected:
+ /**
+ * @brief
+ *
+ * @param ev
+ */
+ void showEvent(QShowEvent* ev) override;
+
+ private:
+ UpdateTab* update_tab_; ///<
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // __ABOUTDIALOG_H__
diff --git a/src/ui/dialog/help/GnupgTab.cpp b/src/ui/dialog/help/GnupgTab.cpp
new file mode 100644
index 00000000..48787987
--- /dev/null
+++ b/src/ui/dialog/help/GnupgTab.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2022. 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 2022/7/23.
+//
+
+#include "GnupgTab.h"
+
+GpgFrontend::UI::GnupgTab::GnupgTab(QWidget* parent) : QWidget(parent) {
+ GpgContext& ctx = GpgContext::GetInstance();
+ auto info = ctx.GetInfo();
+
+ auto* pixmap = new QPixmap(":gnupg.png");
+ auto* text = new QString(
+ "<center><h2>" + QString(_("GnuPG")) + "</h2></center>" + "<center><b>" +
+ QString(_("GnuPG Version")) + ": " +
+ QString::fromStdString(info.GnupgVersion) + "</b></center>" +
+ "<center><b>" + +"</b></center>" + "<center>" +
+ QString(_("GpgME Version")) + ": " +
+ QString::fromStdString(info.GpgMEVersion) + "</center><br /><hr />" +
+ "<h3>" + QString(_("PATHs")) + "</h3>" + QString(_("GpgConf")) + ": " +
+ QString::fromStdString(info.GpgConfPath) + "<br />" +
+ QString(_("GnuPG")) + ": " + QString::fromStdString(info.AppPath) +
+ "<br />" + QString(_("CMS")) + ": " +
+ QString::fromStdString(info.CMSPath) + "<br />");
+
+ auto* layout = new QGridLayout();
+ auto* pixmapLabel = new QLabel();
+ pixmapLabel->setPixmap(*pixmap);
+ layout->addWidget(pixmapLabel, 0, 0, 1, -1, Qt::AlignCenter);
+ auto* aboutLabel = new QLabel();
+ aboutLabel->setText(*text);
+ aboutLabel->setWordWrap(true);
+ aboutLabel->setOpenExternalLinks(true);
+ layout->addWidget(aboutLabel, 1, 0, 1, -1);
+ layout->addItem(
+ new QSpacerItem(20, 10, QSizePolicy::Minimum, QSizePolicy::Fixed), 2, 1,
+ 1, 1);
+
+ setLayout(layout);
+}
diff --git a/src/ui/dialog/help/GnupgTab.h b/src/ui/dialog/help/GnupgTab.h
new file mode 100644
index 00000000..4fc7ff22
--- /dev/null
+++ b/src/ui/dialog/help/GnupgTab.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2022. 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 2022/7/23.
+//
+
+#ifndef GPGFRONTEND_GNUPGTAB_H
+#define GPGFRONTEND_GNUPGTAB_H
+
+#include "core/GpgContext.h"
+#include "ui/GpgFrontendUI.h"
+
+namespace GpgFrontend::UI{
+class GnupgTab: public QWidget {
+ Q_OBJECT
+ public:
+ /**
+ * @brief Construct a new Info Tab object
+ *
+ * @param parent
+ */
+ explicit GnupgTab(QWidget* parent = nullptr);
+};
+}
+
+
+
+#endif // GPGFRONTEND_GNUPGTAB_H
diff --git a/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp b/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp
new file mode 100644
index 00000000..312cd946
--- /dev/null
+++ b/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp
@@ -0,0 +1,145 @@
+/**
+ * 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 <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
+ *
+ */
+
+#include "ExportKeyPackageDialog.h"
+
+#include <boost/format.hpp>
+
+#include "core/function/KeyPackageOperator.h"
+#include "core/function/gpg/GpgKeyGetter.h"
+#include "ui_ExportKeyPackageDialog.h"
+
+GpgFrontend::UI::ExportKeyPackageDialog::ExportKeyPackageDialog(
+ KeyIdArgsListPtr key_ids, QWidget* parent)
+ : GeneralDialog(typeid(ExportKeyPackageDialog).name(), parent),
+ ui_(std::make_shared<Ui_exportKeyPackageDialog>()),
+ key_ids_(std::move(key_ids)) {
+ ui_->setupUi(this);
+
+ ui_->nameValueLabel->setText(
+ KeyPackageOperator::GenerateKeyPackageName().c_str());
+
+ connect(ui_->gnerateNameButton, &QPushButton::clicked, this, [=]() {
+ ui_->nameValueLabel->setText(
+ KeyPackageOperator::GenerateKeyPackageName().c_str());
+ });
+
+ connect(ui_->setOutputPathButton, &QPushButton::clicked, this, [=]() {
+ auto file_name = QFileDialog::getSaveFileName(
+ this, _("Export Key Package"), ui_->nameValueLabel->text() + ".gfepack",
+ QString(_("Key Package")) + " (*.gfepack);;All Files (*)");
+ ui_->outputPathLabel->setText(file_name);
+ });
+
+ connect(ui_->generatePassphraseButton, &QPushButton::clicked, this, [=]() {
+ auto file_name = QFileDialog::getSaveFileName(
+ this, _("Export Key Package Passphrase"),
+ ui_->nameValueLabel->text() + ".key",
+ QString(_("Key File")) + " (*.key);;All Files (*)");
+
+ if (!KeyPackageOperator::GeneratePassphrase(file_name.toStdString(),
+ passphrase_)) {
+ QMessageBox::critical(
+ this, _("Error"),
+ _("An error occurred while generating the passphrase file."));
+ return;
+ }
+ ui_->passphraseValueLabel->setText(file_name);
+ });
+
+ connect(ui_->button_box_, &QDialogButtonBox::accepted, this, [=]() {
+ if (ui_->outputPathLabel->text().isEmpty()) {
+ QMessageBox::critical(
+ this, _("Forbidden"),
+ _("Please select an output path before exporting."));
+ return;
+ }
+
+ if (ui_->passphraseValueLabel->text().isEmpty()) {
+ QMessageBox::critical(
+ this, _("Forbidden"),
+ _("Please generate a password to protect your key before exporting, "
+ "it is very important. Don't forget to back up your password in a "
+ "safe place."));
+ return;
+ }
+
+ // get suitable key ids
+ auto key_id_exported = std::make_unique<KeyIdArgsList>();
+ auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids_);
+ for (const auto& key : *keys) {
+ if (ui_->noPublicKeyCheckBox->isChecked() && !key.IsPrivateKey())
+ continue;
+ key_id_exported->push_back(key.GetId());
+ }
+
+ if (KeyPackageOperator::GenerateKeyPackage(
+ ui_->outputPathLabel->text().toStdString(),
+ ui_->nameValueLabel->text().toStdString(), key_id_exported,
+ passphrase_, ui_->includeSecretKeyCheckBox->isChecked())) {
+ QMessageBox::information(
+ this, _("Success"),
+ QString(
+ _("The Key Package has been successfully generated and has been "
+ "protected by encryption algorithms(AES-256-ECB). You can "
+ "safely transfer your Key Package.")) +
+ "<br /><br />" + "<b>" +
+ _("But the key file cannot be leaked under any "
+ "circumstances. Please delete the Key Package and key file as "
+ "soon "
+ "as possible after completing the transfer operation.") +
+ "</b>");
+ accept();
+ } else {
+ QMessageBox::critical(
+ this, _("Error"),
+ _("An error occurred while exporting the key package."));
+ }
+ });
+
+ connect(ui_->button_box_, &QDialogButtonBox::rejected, this,
+ [=]() { this->close(); });
+
+ ui_->nameLabel->setText(_("Key Package Name"));
+ ui_->selectOutputPathLabel->setText(_("Output Path"));
+ ui_->passphraseLabel->setText(_("Passphrase"));
+ ui_->tipsLabel->setText(
+ _("Tips: You can use Key Package to safely and conveniently transfer "
+ "your public and private keys between devices."));
+ ui_->generatePassphraseButton->setText(_("Generate and Save Passphrase"));
+ ui_->gnerateNameButton->setText(_("Generate Key Package Name"));
+ ui_->setOutputPathButton->setText(_("Select Output Path"));
+
+ ui_->includeSecretKeyCheckBox->setText(
+ _("Include secret key (Think twice before acting)"));
+ ui_->noPublicKeyCheckBox->setText(
+ _("Exclude keys that do not have a private key"));
+
+ setAttribute(Qt::WA_DeleteOnClose);
+ setWindowTitle(_("Export As Key Package"));
+}
diff --git a/src/ui/dialog/import_export/ExportKeyPackageDialog.h b/src/ui/dialog/import_export/ExportKeyPackageDialog.h
new file mode 100644
index 00000000..c5f9a2b1
--- /dev/null
+++ b/src/ui/dialog/import_export/ExportKeyPackageDialog.h
@@ -0,0 +1,62 @@
+/**
+ * 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 <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
+ *
+ */
+
+#ifndef GPGFRONTEND_EXPORTKEYPACKAGEDIALOG_H
+#define GPGFRONTEND_EXPORTKEYPACKAGEDIALOG_H
+
+#include "GpgFrontendUI.h"
+#include "ui/dialog/GeneralDialog.h"
+
+class Ui_exportKeyPackageDialog;
+
+namespace GpgFrontend::UI {
+
+/**
+ * @brief
+ *
+ */
+class ExportKeyPackageDialog : public GeneralDialog {
+ Q_OBJECT
+
+ public:
+ /**
+ * @brief Construct a new Export Key Package Dialog object
+ *
+ * @param key_ids
+ * @param parent
+ */
+ explicit ExportKeyPackageDialog(KeyIdArgsListPtr key_ids, QWidget* parent);
+
+ private:
+ std::shared_ptr<Ui_exportKeyPackageDialog> ui_; ///<
+ KeyIdArgsListPtr key_ids_; ///<
+ std::string passphrase_; ///<
+};
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_EXPORTKEYPACKAGEDIALOG_H
diff --git a/src/ui/dialog/import_export/KeyImportDetailDialog.cpp b/src/ui/dialog/import_export/KeyImportDetailDialog.cpp
new file mode 100644
index 00000000..31183a34
--- /dev/null
+++ b/src/ui/dialog/import_export/KeyImportDetailDialog.cpp
@@ -0,0 +1,204 @@
+/**
+ * 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 <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
+ *
+ */
+
+#include "KeyImportDetailDialog.h"
+
+#include "core/function/gpg/GpgKeyGetter.h"
+
+namespace GpgFrontend::UI {
+KeyImportDetailDialog::KeyImportDetailDialog(GpgImportInformation result,
+ bool automatic, QWidget* parent)
+ : GeneralDialog(typeid(KeyImportDetailDialog).name(), parent),
+ m_result_(std::move(result)) {
+ // If no key for import found, just show a message
+ if (m_result_.considered == 0) {
+ if (automatic)
+ QMessageBox::information(parent, _("Key Update Details"),
+ _("No keys found"));
+ else
+ QMessageBox::information(parent, _("Key Import Details"),
+ _("No keys found to import"));
+ emit finished(0);
+ this->close();
+ this->deleteLater();
+ } else {
+ auto* mv_box = new QVBoxLayout();
+
+ this->create_general_info_box();
+ mv_box->addWidget(general_info_box_);
+ this->create_keys_table();
+ mv_box->addWidget(keys_table_);
+ this->create_button_box();
+ mv_box->addWidget(button_box_);
+
+ this->setLayout(mv_box);
+ if (automatic)
+ this->setWindowTitle(_("Key Update Details"));
+ else
+ this->setWindowTitle(_("Key Import Details"));
+
+ auto pos = QPoint(100, 100);
+ if (parent) pos += parent->pos();
+ this->move(pos);
+
+ this->setMinimumSize(QSize(600, 300));
+ this->adjustSize();
+
+ this->setModal(true);
+ this->show();
+ }
+}
+
+void KeyImportDetailDialog::create_general_info_box() {
+ // GridBox for general import information
+ general_info_box_ = new QGroupBox(_("General key info"));
+ auto* generalInfoBoxLayout = new QGridLayout(general_info_box_);
+
+ generalInfoBoxLayout->addWidget(new QLabel(QString(_("Considered")) + ": "),
+ 1, 0);
+ generalInfoBoxLayout->addWidget(
+ new QLabel(QString::number(m_result_.considered)), 1, 1);
+ int row = 2;
+ if (m_result_.unchanged != 0) {
+ generalInfoBoxLayout->addWidget(
+ new QLabel(QString(_("Public unchanged")) + ": "), row, 0);
+ generalInfoBoxLayout->addWidget(
+ new QLabel(QString::number(m_result_.unchanged)), row, 1);
+ row++;
+ }
+ if (m_result_.imported != 0) {
+ generalInfoBoxLayout->addWidget(new QLabel(QString(_("Imported")) + ": "),
+ row, 0);
+ generalInfoBoxLayout->addWidget(
+ new QLabel(QString::number(m_result_.imported)), row, 1);
+ row++;
+ }
+ if (m_result_.not_imported != 0) {
+ generalInfoBoxLayout->addWidget(
+ new QLabel(QString(_("Not Imported")) + ": "), row, 0);
+ generalInfoBoxLayout->addWidget(
+ new QLabel(QString::number(m_result_.not_imported)), row, 1);
+ row++;
+ }
+ if (m_result_.secret_read != 0) {
+ generalInfoBoxLayout->addWidget(
+ new QLabel(QString(_("Private Read")) + ": "), row, 0);
+ generalInfoBoxLayout->addWidget(
+ new QLabel(QString::number(m_result_.secret_read)), row, 1);
+ row++;
+ }
+ if (m_result_.secret_imported != 0) {
+ generalInfoBoxLayout->addWidget(
+ new QLabel(QString(_("Private Imported")) + ": "), row, 0);
+ generalInfoBoxLayout->addWidget(
+ new QLabel(QString::number(m_result_.secret_imported)), row, 1);
+ row++;
+ }
+ if (m_result_.secret_unchanged != 0) {
+ generalInfoBoxLayout->addWidget(
+ new QLabel(QString(_("Private Unchanged")) + ": "), row, 0);
+ generalInfoBoxLayout->addWidget(
+ new QLabel(QString::number(m_result_.secret_unchanged)), row, 1);
+ row++;
+ }
+}
+
+void KeyImportDetailDialog::create_keys_table() {
+ LOG(INFO) << "KeyImportDetailDialog::create_keys_table() Called";
+
+ keys_table_ = new QTableWidget(this);
+ keys_table_->setRowCount(0);
+ keys_table_->setColumnCount(4);
+ keys_table_->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ // Nothing is selectable
+ keys_table_->setSelectionMode(QAbstractItemView::NoSelection);
+
+ QStringList headerLabels;
+ headerLabels << _("Name") << _("Email") << _("Status") << _("Fingerprint");
+ keys_table_->verticalHeader()->hide();
+
+ keys_table_->setHorizontalHeaderLabels(headerLabels);
+ int row = 0;
+ for (const auto& imp_key : m_result_.importedKeys) {
+ keys_table_->setRowCount(row + 1);
+ GpgKey key = GpgKeyGetter::GetInstance().GetKey(imp_key.fpr);
+ if (!key.IsGood()) continue;
+ keys_table_->setItem(
+ row, 0, new QTableWidgetItem(QString::fromStdString(key.GetName())));
+ keys_table_->setItem(
+ row, 1, new QTableWidgetItem(QString::fromStdString(key.GetEmail())));
+ keys_table_->setItem(
+ row, 2, new QTableWidgetItem(get_status_string(imp_key.import_status)));
+ keys_table_->setItem(
+ row, 3, new QTableWidgetItem(QString::fromStdString(imp_key.fpr)));
+ row++;
+ }
+ keys_table_->horizontalHeader()->setSectionResizeMode(
+ 0, QHeaderView::ResizeToContents);
+ keys_table_->horizontalHeader()->setStretchLastSection(true);
+ keys_table_->resizeColumnsToContents();
+}
+
+QString KeyImportDetailDialog::get_status_string(int keyStatus) {
+ QString statusString;
+ // keystatus is greater than 15, if key is private
+ if (keyStatus > 15) {
+ statusString.append(_("Private"));
+ keyStatus = keyStatus - 16;
+ } else {
+ statusString.append(_("Public"));
+ }
+ if (keyStatus == 0) {
+ statusString.append(", " + QString(_("Unchanged")));
+ } else {
+ if (keyStatus == 1) {
+ statusString.append(", " + QString(_("New Key")));
+ } else {
+ if (keyStatus > 7) {
+ statusString.append(", " + QString(_("New Subkey")));
+ keyStatus = keyStatus - 8;
+ }
+ if (keyStatus > 3) {
+ statusString.append(", " + QString(_("New Signature")));
+ keyStatus = keyStatus - 4;
+ }
+ if (keyStatus > 1) {
+ statusString.append(", " + QString(_("New UID")));
+ keyStatus = keyStatus - 2;
+ }
+ }
+ }
+ return statusString;
+}
+
+void KeyImportDetailDialog::create_button_box() {
+ button_box_ = new QDialogButtonBox(QDialogButtonBox::Ok);
+ connect(button_box_, &QDialogButtonBox::accepted, this,
+ &KeyImportDetailDialog::close);
+}
+} // namespace GpgFrontend::UI
diff --git a/src/ui/dialog/import_export/KeyImportDetailDialog.h b/src/ui/dialog/import_export/KeyImportDetailDialog.h
new file mode 100644
index 00000000..06f44e94
--- /dev/null
+++ b/src/ui/dialog/import_export/KeyImportDetailDialog.h
@@ -0,0 +1,92 @@
+/**
+ * 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 <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
+ *
+ */
+
+#ifndef __KEYIMPORTDETAILSDIALOG_H__
+#define __KEYIMPORTDETAILSDIALOG_H__
+
+#include "core/GpgContext.h"
+#include "core/function/gpg/GpgKeyImportExporter.h"
+#include "ui/GpgFrontendUI.h"
+#include "ui/dialog/GeneralDialog.h"
+
+namespace GpgFrontend::UI {
+
+/**
+ * @brief
+ *
+ */
+class KeyImportDetailDialog : public GeneralDialog {
+ Q_OBJECT
+
+ public:
+ /**
+ * @brief Construct a new Key Import Detail Dialog object
+ *
+ * @param result
+ * @param automatic
+ * @param parent
+ */
+ KeyImportDetailDialog(GpgImportInformation result, bool automatic,
+ QWidget* parent = nullptr);
+
+ private:
+ /**
+ * @brief Create a general info box object
+ *
+ */
+ void create_general_info_box();
+
+ /**
+ * @brief Create a keys table object
+ *
+ */
+ void create_keys_table();
+
+ /**
+ * @brief Create a button box object
+ *
+ */
+ void create_button_box();
+
+ /**
+ * @brief Get the status string object
+ *
+ * @param keyStatus
+ * @return QString
+ */
+ static QString get_status_string(int keyStatus);
+
+ QTableWidget* keys_table_{}; ///<
+ QGroupBox* general_info_box_{}; ///<
+ QGroupBox* key_info_box_{}; ///<
+ QDialogButtonBox* button_box_{}; ///<
+ GpgImportInformation m_result_; ///<
+};
+} // namespace GpgFrontend::UI
+
+#endif // __KEYIMPORTDETAILSDIALOG_H__
diff --git a/src/ui/dialog/import_export/KeyServerImportDialog.cpp b/src/ui/dialog/import_export/KeyServerImportDialog.cpp
new file mode 100644
index 00000000..6430a22e
--- /dev/null
+++ b/src/ui/dialog/import_export/KeyServerImportDialog.cpp
@@ -0,0 +1,550 @@
+/**
+ * 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 <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
+ *
+ */
+
+#include "KeyServerImportDialog.h"
+
+#include <string>
+#include <utility>
+
+#include "core/function/GlobalSettingStation.h"
+#include "core/function/gpg/GpgKeyImportExporter.h"
+#include "thread/KeyServerImportTask.h"
+#include "ui/SignalStation.h"
+#include "ui/struct/SettingsObject.h"
+#include "ui/thread/KeyServerSearchTask.h"
+
+namespace GpgFrontend::UI {
+
+KeyServerImportDialog::KeyServerImportDialog(bool automatic, QWidget* parent)
+ : GeneralDialog("key_server_import_dialog", parent),
+ m_automatic_(automatic) {
+ // Layout for messagebox
+ auto* message_layout = new QHBoxLayout();
+
+ if (automatic) {
+ setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::CustomizeWindowHint);
+ } else {
+ // Buttons
+
+ close_button_ = new QPushButton(_("Close"));
+ connect(close_button_, &QPushButton::clicked, this,
+ &KeyServerImportDialog::close);
+ import_button_ = new QPushButton(_("Import ALL"));
+ connect(import_button_, &QPushButton::clicked, this,
+ &KeyServerImportDialog::slot_import);
+ import_button_->setDisabled(true);
+ search_button_ = new QPushButton(_("Search"));
+ connect(search_button_, &QPushButton::clicked, this,
+ &KeyServerImportDialog::slot_search);
+
+ // Line edits for search string
+ search_label_ = new QLabel(QString(_("Search String")) + _(": "));
+ search_line_edit_ = new QLineEdit();
+
+ // combobox for keyserver list
+ key_server_label_ = new QLabel(QString(_("Key Server")) + _(": "));
+ key_server_combo_box_ = create_comboBox();
+
+ // table containing the keys found
+ create_keys_table();
+ message_ = new QLabel();
+ message_->setFixedHeight(24);
+ icon_ = new QLabel();
+ icon_->setFixedHeight(24);
+
+ message_layout->addWidget(icon_);
+ message_layout->addWidget(message_);
+ message_layout->addStretch();
+ }
+
+ // Network Waiting
+ waiting_bar_ = new QProgressBar();
+ waiting_bar_->setVisible(false);
+ waiting_bar_->setRange(0, 0);
+ waiting_bar_->setFixedWidth(200);
+ message_layout->addWidget(waiting_bar_);
+
+ auto* mainLayout = new QGridLayout;
+
+ // 自动化调用界面布局
+ if (automatic) {
+ mainLayout->addLayout(message_layout, 0, 0, 1, 3);
+ } else {
+ mainLayout->addWidget(search_label_, 1, 0);
+ mainLayout->addWidget(search_line_edit_, 1, 1);
+ mainLayout->addWidget(search_button_, 1, 2);
+ mainLayout->addWidget(key_server_label_, 2, 0);
+ mainLayout->addWidget(key_server_combo_box_, 2, 1);
+ mainLayout->addWidget(keys_table_, 3, 0, 1, 3);
+ mainLayout->addLayout(message_layout, 4, 0, 1, 3);
+
+ // Layout for import and close button
+ auto* buttonsLayout = new QHBoxLayout;
+ buttonsLayout->addStretch();
+ buttonsLayout->addWidget(import_button_);
+ buttonsLayout->addWidget(close_button_);
+ mainLayout->addLayout(buttonsLayout, 6, 0, 1, 3);
+ }
+
+ this->setLayout(mainLayout);
+ if (automatic)
+ this->setWindowTitle(_("Update Keys from Keyserver"));
+ else
+ this->setWindowTitle(_("Import Keys from Keyserver"));
+
+ if (automatic) {
+ this->setFixedSize(240, 42);
+ }
+
+ this->setModal(true);
+
+ connect(this, &KeyServerImportDialog::SignalKeyImported,
+ SignalStation::GetInstance(),
+ &SignalStation::SignalKeyDatabaseRefresh);
+}
+
+KeyServerImportDialog::KeyServerImportDialog(QWidget* parent)
+ : GeneralDialog("key_server_import_dialog", parent), m_automatic_(true) {
+ setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::CustomizeWindowHint);
+
+ // Network Waiting
+ waiting_bar_ = new QProgressBar();
+ waiting_bar_->setVisible(false);
+ waiting_bar_->setRange(0, 0);
+ waiting_bar_->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
+ waiting_bar_->setTextVisible(false);
+
+ // Layout for messagebox
+ auto* layout = new QHBoxLayout();
+ layout->setContentsMargins(0, 0, 0, 0);
+ layout->setSpacing(0);
+ layout->addWidget(waiting_bar_);
+
+ key_server_combo_box_ = create_comboBox();
+
+ this->setLayout(layout);
+ this->setWindowTitle(_("Update Keys from Keyserver"));
+ this->setFixedSize(240, 42);
+ this->setModal(true);
+}
+
+QComboBox* KeyServerImportDialog::create_comboBox() {
+ auto* comboBox = new QComboBox;
+ comboBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+
+ try {
+ SettingsObject key_server_json("key_server");
+
+ const auto key_server_list =
+ key_server_json.Check("server_list", nlohmann::json::array());
+
+ for (const auto& key_server : key_server_list) {
+ const auto key_server_str = key_server.get<std::string>();
+ comboBox->addItem(key_server_str.c_str());
+ }
+
+ int default_key_server_index = key_server_json.Check("default_server", 0);
+ if (default_key_server_index >= key_server_list.size()) {
+ throw std::runtime_error("default_server index out of range");
+ }
+ std::string default_key_server =
+ key_server_list[default_key_server_index].get<std::string>();
+
+ comboBox->setCurrentText(default_key_server.c_str());
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << "server_list"
+ << "default_server";
+ }
+
+ return comboBox;
+}
+
+void KeyServerImportDialog::create_keys_table() {
+ keys_table_ = new QTableWidget();
+ keys_table_->setColumnCount(4);
+
+ // always a whole row is marked
+ keys_table_->setSelectionBehavior(QAbstractItemView::SelectRows);
+ keys_table_->setEditTriggers(QAbstractItemView::NoEditTriggers);
+
+ // Make just one row selectable
+ keys_table_->setSelectionMode(QAbstractItemView::SingleSelection);
+
+ QStringList labels;
+ labels << _("UID") << _("Creation date") << _("KeyID") << _("Tag");
+ keys_table_->horizontalHeader()->setSectionResizeMode(
+ 0, QHeaderView::ResizeToContents);
+ keys_table_->setHorizontalHeaderLabels(labels);
+ keys_table_->verticalHeader()->hide();
+
+ connect(keys_table_, &QTableWidget::cellActivated, this,
+ &KeyServerImportDialog::slot_import);
+}
+
+void KeyServerImportDialog::set_message(const QString& text, bool error) {
+ if (m_automatic_) return;
+
+ message_->setText(text);
+ if (error) {
+ icon_->setPixmap(
+ QPixmap(":error.png").scaled(QSize(24, 24), Qt::KeepAspectRatio));
+ } else {
+ icon_->setPixmap(
+ QPixmap(":info.png").scaled(QSize(24, 24), Qt::KeepAspectRatio));
+ }
+}
+
+void KeyServerImportDialog::slot_search() {
+ if (search_line_edit_->text().isEmpty()) {
+ set_message("<h4>" + QString(_("Text is empty.")) + "</h4>", false);
+ return;
+ }
+
+ auto* task = new KeyServerSearchTask(
+ key_server_combo_box_->currentText().toStdString(),
+ search_line_edit_->text().toStdString());
+
+ connect(task, &KeyServerSearchTask::SignalKeyServerSearchResult, this,
+ &KeyServerImportDialog::slot_search_finished);
+
+ connect(task, &KeyServerSearchTask::SignalKeyServerSearchResult, this, [=]() {
+ this->search_button_->setDisabled(false);
+ this->key_server_combo_box_->setDisabled(false);
+ this->search_line_edit_->setReadOnly(false);
+ this->import_button_->setDisabled(false);
+ set_loading(false);
+ });
+
+ set_loading(true);
+ this->search_button_->setDisabled(true);
+ this->key_server_combo_box_->setDisabled(true);
+ this->search_line_edit_->setReadOnly(true);
+ this->import_button_->setDisabled(true);
+
+ Thread::TaskRunnerGetter::GetInstance()
+ .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Network)
+ ->PostTask(task);
+}
+
+void KeyServerImportDialog::slot_search_finished(
+ QNetworkReply::NetworkError error, QByteArray buffer) {
+ LOG(INFO) << "Called" << error << buffer.size();
+ LOG(INFO) << buffer.toStdString();
+
+ keys_table_->clearContents();
+ keys_table_->setRowCount(0);
+
+ auto stream = QTextStream(buffer);
+
+ if (error != QNetworkReply::NoError) {
+ LOG(INFO) << "Error From Reply" << error;
+
+ switch (error) {
+ case QNetworkReply::ContentNotFoundError:
+ set_message(_("Not Key Found"), true);
+ break;
+ case QNetworkReply::TimeoutError:
+ set_message(_("Timeout"), true);
+ break;
+ case QNetworkReply::HostNotFoundError:
+ set_message(_("Key Server Not Found"), true);
+ break;
+ default:
+ set_message(_("Connection Error"), true);
+ }
+ return;
+ }
+
+ if (stream.readLine().contains("Error")) {
+ auto text = stream.readLine(1024);
+
+ if (text.contains("Too many responses")) {
+ set_message(
+ "<h4>" + QString(_("Too many responses from keyserver!")) + "</h4>",
+ true);
+ return;
+ } else if (text.contains("No keys found")) {
+ // if string looks like hex string, search again with 0x prepended
+ QRegExp rx("[0-9A-Fa-f]*");
+ QString query = search_line_edit_->text();
+ if (rx.exactMatch(query)) {
+ set_message(
+ "<h4>" +
+ QString(_("No keys found, input may be kexId, retrying search "
+ "with 0x.")) +
+ "</h4>",
+ true);
+ search_line_edit_->setText(query.prepend("0x"));
+ this->slot_search();
+ return;
+ } else {
+ set_message(
+ "<h4>" + QString(_("No keys found containing the search string!")) +
+ "</h4>",
+ true);
+ return;
+ }
+ } else if (text.contains("Insufficiently specific words")) {
+ set_message("<h4>" +
+ QString(_("Insufficiently specific search string!")) +
+ "</h4>",
+ true);
+ return;
+ } else {
+ set_message(text, true);
+ return;
+ }
+ } else {
+ int row = 0;
+ bool strikeout = false;
+
+ // read lines until end of steam
+ while (!stream.atEnd()) {
+ QStringList line =
+ QString::fromUtf8(QByteArray::fromPercentEncoding(
+ stream.readLine().trimmed().toUtf8()))
+ .split(":");
+
+ // TODO: have a look at two following pub lines
+ if (line[0] == "pub") {
+ strikeout = false;
+
+ QString flags = line[line.size() - 1];
+ keys_table_->setRowCount(row + 1);
+
+ // flags can be "d" for disabled, "r" for revoked
+ // or "e" for expired
+ if (flags.contains("r") or flags.contains("d") or flags.contains("e")) {
+ strikeout = true;
+ if (flags.contains("e")) {
+ keys_table_->setItem(row, 3,
+ new QTableWidgetItem(QString("expired")));
+ }
+ if (flags.contains("r")) {
+ keys_table_->setItem(row, 3,
+ new QTableWidgetItem(QString(_("revoked"))));
+ }
+ if (flags.contains("d")) {
+ keys_table_->setItem(row, 3,
+ new QTableWidgetItem(QString(_("disabled"))));
+ }
+ }
+
+ QStringList line2 = QString(QByteArray::fromPercentEncoding(
+ stream.readLine().trimmed().toUtf8()))
+ .split(":");
+
+ auto* uid = new QTableWidgetItem();
+ if (line2.size() > 1) {
+ uid->setText(line2[1]);
+ keys_table_->setItem(row, 0, uid);
+ }
+ auto* creation_date = new QTableWidgetItem(
+ QDateTime::fromTime_t(line[4].toInt()).toString("dd. MMM. yyyy"));
+ keys_table_->setItem(row, 1, creation_date);
+ auto* keyid = new QTableWidgetItem(line[1]);
+ keys_table_->setItem(row, 2, keyid);
+ if (strikeout) {
+ QFont strike = uid->font();
+ strike.setStrikeOut(true);
+ uid->setFont(strike);
+ creation_date->setFont(strike);
+ keyid->setFont(strike);
+ }
+ row++;
+ } else {
+ if (line[0] == "uid") {
+ QStringList l;
+ int height = keys_table_->rowHeight(row - 1);
+ keys_table_->setRowHeight(row - 1, height + 16);
+ QString tmp = keys_table_->item(row - 1, 0)->text();
+ tmp.append(QString("\n") + line[1]);
+ auto* tmp1 = new QTableWidgetItem(tmp);
+ keys_table_->setItem(row - 1, 0, tmp1);
+ if (strikeout) {
+ QFont strike = tmp1->font();
+ strike.setStrikeOut(true);
+ tmp1->setFont(strike);
+ }
+ }
+ }
+ set_message(
+ QString("<h4>") +
+ QString(_("%1 keys found. Double click a key to import it."))
+ .arg(row) +
+ "</h4>",
+ false);
+ }
+ keys_table_->resizeColumnsToContents();
+ import_button_->setDisabled(keys_table_->size().isEmpty());
+ }
+}
+
+void KeyServerImportDialog::slot_import() {
+ std::vector<std::string> key_ids;
+ const int row_count = keys_table_->rowCount();
+ for (int i = 0; i < row_count; ++i) {
+ if (keys_table_->item(i, 2)->isSelected()) {
+ QString keyid = keys_table_->item(i, 2)->text();
+ key_ids.push_back(keyid.toStdString());
+ }
+ }
+ if (!key_ids.empty())
+ SlotImport(key_ids, key_server_combo_box_->currentText().toStdString());
+}
+
+void KeyServerImportDialog::SlotImport(const KeyIdArgsListPtr& keys) {
+ // keyserver host url
+ std::string target_keyserver;
+
+ if (key_server_combo_box_ != nullptr) {
+ target_keyserver = key_server_combo_box_->currentText().toStdString();
+ }
+ if (target_keyserver.empty()) {
+ try {
+ SettingsObject key_server_json("key_server");
+ const auto key_server_list =
+ key_server_json.Check("server_list", nlohmann::json::array());
+
+ int default_key_server_index = key_server_json.Check("default_server", 0);
+ if (default_key_server_index >= key_server_list.size()) {
+ throw std::runtime_error("default_server index out of range");
+ }
+ std::string default_key_server =
+ key_server_list[default_key_server_index].get<std::string>();
+
+ target_keyserver = default_key_server;
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << "server_list"
+ << "default_server";
+ QMessageBox::critical(
+ nullptr, _("Default Keyserver Not Found"),
+ _("Cannot read default keyserver from your settings, "
+ "please set a default keyserver first"));
+ return;
+ }
+ }
+ std::vector<std::string> key_ids;
+ for (const auto& key_id : *keys) {
+ key_ids.push_back(key_id);
+ }
+ SlotImport(key_ids, target_keyserver);
+}
+
+void KeyServerImportDialog::SlotImport(std::vector<std::string> key_ids,
+ std::string keyserver_url) {
+ auto* task = new KeyServerImportTask(keyserver_url, key_ids);
+
+ connect(task, &KeyServerImportTask::SignalKeyServerImportResult, this,
+ &KeyServerImportDialog::slot_import_finished);
+
+ Thread::TaskRunnerGetter::GetInstance()
+ .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Network)
+ ->PostTask(task);
+}
+
+void KeyServerImportDialog::slot_import_finished(
+ QNetworkReply::NetworkError error, QByteArray buffer) {
+ LOG(INFO) << _("Called");
+
+ if (error != QNetworkReply::NoError) {
+ LOG(ERROR) << "Error From Reply" << buffer.toStdString();
+ if (!m_automatic_) {
+ switch (error) {
+ case QNetworkReply::ContentNotFoundError:
+ set_message(_("Key Not Found"), true);
+ break;
+ case QNetworkReply::TimeoutError:
+ set_message(_("Timeout"), true);
+ break;
+ case QNetworkReply::HostNotFoundError:
+ set_message(_("Key Server Not Found"), true);
+ break;
+ default:
+ set_message(_("Connection Error"), true);
+ }
+ } else {
+ switch (error) {
+ case QNetworkReply::ContentNotFoundError:
+ QMessageBox::critical(nullptr, _("Key Not Found"),
+ QString(_("key not found in the Keyserver")));
+ break;
+ case QNetworkReply::TimeoutError:
+ QMessageBox::critical(nullptr, _("Timeout"), "Connection timeout");
+ break;
+ case QNetworkReply::HostNotFoundError:
+ QMessageBox::critical(nullptr, _("Host Not Found"),
+ "cannot resolve the default Keyserver");
+ break;
+ default:
+ QMessageBox::critical(nullptr, _("Connection Error"),
+ _("General Connection Error"));
+ }
+ }
+ if (m_automatic_) {
+ setWindowFlags(Qt::Window | Qt::WindowTitleHint |
+ Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint);
+ }
+ return;
+ }
+
+ this->import_keys(
+ std::make_unique<ByteArray>(buffer.constData(), buffer.length()));
+
+ if (!m_automatic_) {
+ set_message(QString("<h4>") + _("Key Imported") + "</h4>", false);
+ }
+}
+
+void KeyServerImportDialog::import_keys(ByteArrayPtr in_data) {
+ GpgImportInformation result =
+ GpgKeyImportExporter::GetInstance().ImportKey(std::move(in_data));
+
+ // refresh the key database
+ emit SignalKeyImported();
+
+ QWidget* _parent = qobject_cast<QWidget*>(parent());
+ if (m_automatic_) {
+ auto dialog = new KeyImportDetailDialog(result, true, _parent);
+ dialog->show();
+ this->accept();
+ } else {
+ auto dialog = new KeyImportDetailDialog(result, false, this);
+ dialog->exec();
+ }
+}
+
+void KeyServerImportDialog::set_loading(bool status) {
+ waiting_bar_->setVisible(status);
+ if (!m_automatic_) {
+ icon_->setVisible(!status);
+ message_->setVisible(!status);
+ }
+}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/dialog/import_export/KeyServerImportDialog.h b/src/ui/dialog/import_export/KeyServerImportDialog.h
new file mode 100644
index 00000000..fd912bdd
--- /dev/null
+++ b/src/ui/dialog/import_export/KeyServerImportDialog.h
@@ -0,0 +1,182 @@
+/**
+ * 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 <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
+ *
+ */
+
+#ifndef __KEY_SERVER_IMPORT_DIALOG_H__
+#define __KEY_SERVER_IMPORT_DIALOG_H__
+
+#include <string>
+
+#include "KeyImportDetailDialog.h"
+#include "core/GpgContext.h"
+#include "ui/GpgFrontendUI.h"
+#include "ui/dialog/GeneralDialog.h"
+#include "ui/widgets/KeyList.h"
+
+namespace GpgFrontend::UI {
+
+/**
+ * @brief
+ *
+ */
+class KeyServerImportDialog : public GeneralDialog {
+ Q_OBJECT
+
+ public:
+ /**
+ * @brief Construct a new Key Server Import Dialog object
+ *
+ * @param automatic
+ * @param parent
+ */
+ KeyServerImportDialog(bool automatic, QWidget* parent);
+
+ /**
+ * @brief Construct a new Key Server Import Dialog object
+ *
+ * @param parent
+ */
+ explicit KeyServerImportDialog(QWidget* parent);
+
+ public slots:
+
+ /**
+ * @brief
+ *
+ * @param keys
+ */
+ void SlotImport(const KeyIdArgsListPtr& keys);
+
+ /**
+ * @brief
+ *
+ * @param keyIds
+ * @param keyserverUrl
+ */
+ void SlotImport(std::vector<std::string> key_ids_list,
+ std::string keyserver_url);
+
+ signals:
+
+ /**
+ * @brief
+ *
+ */
+ void SignalKeyImported();
+
+ private slots:
+
+ /**
+ * @brief import key(s) for the key table selection
+ *
+ */
+ void slot_import();
+
+ /**
+ * @brief
+ *
+ */
+ void slot_search_finished(QNetworkReply::NetworkError reply,
+ QByteArray buffer);
+
+ /**
+ * @brief
+ *
+ * @param keyid
+ */
+ void slot_import_finished(QNetworkReply::NetworkError error,
+ QByteArray buffer);
+
+ /**
+ * @brief
+ *
+ */
+ void slot_search();
+
+ private:
+ /**
+ * @brief Create a keys table object
+ *
+ */
+ void create_keys_table();
+
+ /**
+ * @brief Set the message object
+ *
+ * @param text
+ * @param error
+ */
+ void set_message(const QString& text, bool error);
+
+ /**
+ * @brief
+ *
+ * @param in_data
+ */
+ void import_keys(ByteArrayPtr in_data);
+
+ /**
+ * @brief Set the loading object
+ *
+ * @param status
+ */
+ void set_loading(bool status);
+
+ /**
+ * @brief Create a button object
+ *
+ * @param text
+ * @param member
+ * @return QPushButton*
+ */
+ QPushButton* create_button(const QString& text, const char* member);
+
+ /**
+ * @brief Create a comboBox object
+ *
+ * @return QComboBox*
+ */
+ QComboBox* create_comboBox();
+
+ bool m_automatic_ = false; ///<
+
+ QLineEdit* search_line_edit_{}; ///<
+ QComboBox* key_server_combo_box_{}; ///<
+ QProgressBar* waiting_bar_; ///<
+ QLabel* search_label_{}; ///<
+ QLabel* key_server_label_{}; ///<
+ QLabel* message_{}; ///<
+ QLabel* icon_{}; ///<
+ QPushButton* close_button_{}; ///<
+ QPushButton* import_button_{}; ///<
+ QPushButton* search_button_{}; ///<
+ QTableWidget* keys_table_{}; ///<
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // __KEY_SERVER_IMPORT_DIALOG_H__
diff --git a/src/ui/dialog/import_export/KeyUploadDialog.cpp b/src/ui/dialog/import_export/KeyUploadDialog.cpp
new file mode 100644
index 00000000..055f2e1f
--- /dev/null
+++ b/src/ui/dialog/import_export/KeyUploadDialog.cpp
@@ -0,0 +1,159 @@
+/**
+ * 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 <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
+ *
+ */
+
+#include "KeyUploadDialog.h"
+
+#include <algorithm>
+
+#include "core/function/GlobalSettingStation.h"
+#include "core/function/gpg/GpgKeyGetter.h"
+#include "core/function/gpg/GpgKeyImportExporter.h"
+
+namespace GpgFrontend::UI {
+
+KeyUploadDialog::KeyUploadDialog(const KeyIdArgsListPtr& keys_ids,
+ QWidget* parent)
+ : GeneralDialog(typeid(KeyUploadDialog).name(), parent),
+ m_keys_(GpgKeyGetter::GetInstance().GetKeys(keys_ids)) {
+ auto* pb = new QProgressBar();
+ pb->setRange(0, 0);
+ pb->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
+ pb->setTextVisible(false);
+
+ auto* layout = new QVBoxLayout();
+ layout->addWidget(pb);
+ layout->setContentsMargins(0, 0, 0, 0);
+ layout->setSpacing(0);
+ this->setLayout(layout);
+
+ this->setModal(true);
+ this->setWindowTitle(_("Uploading Public Key"));
+ this->setFixedSize(240, 42);
+}
+
+void KeyUploadDialog::SlotUpload() {
+ auto out_data = std::make_unique<ByteArray>();
+ GpgKeyImportExporter::GetInstance().ExportKeys(*m_keys_, out_data);
+ slot_upload_key_to_server(*out_data);
+}
+
+void KeyUploadDialog::slot_upload_key_to_server(
+ const GpgFrontend::ByteArray& keys_data) {
+ 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;
+ }
+ }
+
+ QUrl req_url(QString::fromStdString(target_keyserver + "/pks/add"));
+ auto qnam = new QNetworkAccessManager(this);
+
+ // Building Post Data
+ QByteArray postData;
+
+ auto data = std::string(keys_data);
+
+ boost::algorithm::replace_all(data, "\n", "%0A");
+ boost::algorithm::replace_all(data, "\r", "%0D");
+ boost::algorithm::replace_all(data, "(", "%28");
+ boost::algorithm::replace_all(data, ")", "%29");
+ boost::algorithm::replace_all(data, "/", "%2F");
+ boost::algorithm::replace_all(data, ":", "%3A");
+ boost::algorithm::replace_all(data, "+", "%2B");
+ boost::algorithm::replace_all(data, "=", "%3D");
+ boost::algorithm::replace_all(data, " ", "+");
+
+ QNetworkRequest request(req_url);
+ request.setHeader(QNetworkRequest::ContentTypeHeader,
+ "application/x-www-form-urlencoded");
+
+ postData.append("keytext").append("=").append(
+ QString::fromStdString(data).toUtf8());
+
+ // Send Post Data
+ QNetworkReply* reply = qnam->post(request, postData);
+ connect(reply, &QNetworkReply::finished, this,
+ &KeyUploadDialog::slot_upload_finished);
+
+ // Keep Waiting
+ while (reply->isRunning()) {
+ QApplication::processEvents();
+ }
+
+ // Done
+ this->hide();
+ this->close();
+}
+
+void KeyUploadDialog::slot_upload_finished() {
+ auto* reply = qobject_cast<QNetworkReply*>(sender());
+
+ QByteArray response = reply->readAll();
+ LOG(INFO) << "Response: " << response.toStdString();
+
+ auto error = reply->error();
+ if (error != QNetworkReply::NoError) {
+ LOG(INFO) << "Error From Reply" << reply->errorString().toStdString();
+ QString message;
+ switch (error) {
+ case QNetworkReply::ContentNotFoundError:
+ message = _("Key Not Found");
+ break;
+ case QNetworkReply::TimeoutError:
+ message = _("Timeout");
+ break;
+ case QNetworkReply::HostNotFoundError:
+ message = _("Key Server Not Found");
+ break;
+ default:
+ message = _("Connection Error");
+ }
+ QMessageBox::critical(this, "Upload Failed", message);
+ return;
+ } else {
+ QMessageBox::information(this, _("Upload Success"),
+ _("Upload Public Key Successfully"));
+ LOG(INFO) << "Success while contacting keyserver!";
+ }
+ reply->deleteLater();
+}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/dialog/import_export/KeyUploadDialog.h b/src/ui/dialog/import_export/KeyUploadDialog.h
new file mode 100644
index 00000000..d621f33a
--- /dev/null
+++ b/src/ui/dialog/import_export/KeyUploadDialog.h
@@ -0,0 +1,83 @@
+/**
+ * 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 <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
+ *
+ */
+
+#ifndef GPGFRONTEND_KEYUPLOADWIDGET_H
+#define GPGFRONTEND_KEYUPLOADWIDGET_H
+
+#include "core/GpgContext.h"
+#include "ui/GpgFrontendUI.h"
+#include "ui/dialog/GeneralDialog.h"
+
+namespace GpgFrontend::UI {
+
+/**
+ * @brief
+ *
+ */
+class KeyUploadDialog : public GeneralDialog {
+ Q_OBJECT
+ public:
+ /**
+ * @brief Construct a new Key Upload Dialog object
+ *
+ * @param keys_ids
+ * @param parent
+ */
+ explicit KeyUploadDialog(const KeyIdArgsListPtr& keys_ids, QWidget* parent);
+
+ public slots:
+
+ /**
+ * @brief
+ *
+ */
+ void SlotUpload();
+
+ private slots:
+
+ /**
+ * @brief
+ *
+ * @param keys_data
+ */
+ void slot_upload_key_to_server(const GpgFrontend::ByteArray& keys_data);
+
+ /**
+ * @brief
+ *
+ */
+ void slot_upload_finished();
+
+ private:
+ KeyListPtr m_keys_; ///<
+ QByteArray m_key_data_; ///<
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_KEYUPLOADWIDGET_H
diff --git a/src/ui/dialog/key_generate/KeygenDialog.cpp b/src/ui/dialog/key_generate/KeygenDialog.cpp
new file mode 100644
index 00000000..42160ec9
--- /dev/null
+++ b/src/ui/dialog/key_generate/KeygenDialog.cpp
@@ -0,0 +1,407 @@
+/**
+ * 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 <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
+ *
+ */
+
+#include "KeygenDialog.h"
+
+#include "core/function/GlobalSettingStation.h"
+#include "core/function/gpg/GpgKeyOpera.h"
+#include "dialog/WaitingDialog.h"
+#include "ui/SignalStation.h"
+
+namespace GpgFrontend::UI {
+
+KeyGenDialog::KeyGenDialog(QWidget* parent)
+ : GeneralDialog(typeid(KeyGenDialog).name(), parent) {
+ button_box_ =
+ new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+
+ auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
+
+ // max expire date time
+ bool longer_expiration_date = false;
+ try {
+ longer_expiration_date = settings.lookup("general.longer_expiration_date");
+ LOG(INFO) << "longer_expiration_date" << longer_expiration_date;
+
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("longer_expiration_date");
+ }
+
+ max_date_time_ = longer_expiration_date
+ ? QDateTime::currentDateTime().toLocalTime().addYears(30)
+ : QDateTime::currentDateTime().toLocalTime().addYears(2);
+
+ this->setWindowTitle(_("Generate Key"));
+ this->setModal(true);
+
+ connect(this, &KeyGenDialog::SignalKeyGenerated, SignalStation::GetInstance(),
+ &SignalStation::SignalKeyDatabaseRefresh);
+
+ generate_key_dialog();
+}
+
+void KeyGenDialog::generate_key_dialog() {
+ key_usage_group_box_ = create_key_usage_group_box();
+
+ auto* groupGrid = new QGridLayout(this);
+ groupGrid->addWidget(create_basic_info_group_box(), 0, 0);
+ groupGrid->addWidget(key_usage_group_box_, 1, 0);
+
+ auto* nameList = new QWidget(this);
+ nameList->setLayout(groupGrid);
+
+ auto* vbox2 = new QVBoxLayout();
+ vbox2->addWidget(nameList);
+ vbox2->addWidget(error_label_);
+ vbox2->addWidget(button_box_);
+
+ this->setLayout(vbox2);
+
+ set_signal_slot();
+
+ refresh_widgets_state();
+}
+
+void KeyGenDialog::slot_key_gen_accept() {
+ std::stringstream error_stream;
+
+ /**
+ * check for errors in keygen dialog input
+ */
+ if ((name_edit_->text()).size() < 5) {
+ error_stream << " " << _("Name must contain at least five characters.")
+ << std::endl;
+ }
+ if (email_edit_->text().isEmpty() ||
+ !check_email_address(email_edit_->text())) {
+ error_stream << " " << _("Please give a email address.") << std::endl;
+ }
+
+ /**
+ * primary keys should have a reasonable expiration date (no more than 2 years
+ * in the future)
+ */
+ if (date_edit_->dateTime() > max_date_time_) {
+ error_stream << " " << _("Expiration time too long.") << std::endl;
+ }
+
+ auto err_string = error_stream.str();
+
+ if (err_string.empty()) {
+ /**
+ * create the string for key generation
+ */
+ gen_key_info_->SetName(name_edit_->text().toStdString());
+ gen_key_info_->SetEmail(email_edit_->text().toStdString());
+ gen_key_info_->SetComment(comment_edit_->text().toStdString());
+
+ gen_key_info_->SetKeyLength(key_size_spin_box_->value());
+
+ if (expire_check_box_->checkState()) {
+ gen_key_info_->SetNonExpired(true);
+ } else {
+ gen_key_info_->SetExpireTime(
+ boost::posix_time::from_time_t(date_edit_->dateTime().toTime_t()));
+ }
+
+ GpgGenKeyResult result;
+ gpgme_error_t error = false;
+ auto thread = QThread::create([&]() {
+ error = GpgKeyOpera::GetInstance().GenerateKey(gen_key_info_, result);
+ });
+ thread->start();
+
+ auto* dialog = new WaitingDialog(_("Generating"), this);
+ dialog->show();
+
+ while (thread->isRunning()) {
+ QCoreApplication::processEvents();
+ }
+
+ dialog->close();
+
+ LOG(INFO) << "generate done";
+
+ if (gpgme_err_code(error) == GPG_ERR_NO_ERROR) {
+ auto* msg_box = new QMessageBox((QWidget*)this->parent());
+ msg_box->setAttribute(Qt::WA_DeleteOnClose);
+ msg_box->setStandardButtons(QMessageBox::Ok);
+ msg_box->setWindowTitle(_("Success"));
+ msg_box->setText(_("The new key pair has been generated."));
+ msg_box->setModal(true);
+ msg_box->open();
+
+ LOG(INFO) << "generate success";
+
+ emit SignalKeyGenerated();
+ this->close();
+ } else {
+ QMessageBox::critical(this, _("Failure"), _("Key generation failed."));
+ }
+
+ } else {
+ /**
+ * create error message
+ */
+ error_label_->setAutoFillBackground(true);
+ QPalette error = error_label_->palette();
+ error.setColor(QPalette::Window, "#ff8080");
+ error_label_->setPalette(error);
+ error_label_->setText(err_string.c_str());
+
+ this->show();
+ }
+}
+
+void KeyGenDialog::slot_expire_box_changed() {
+ if (expire_check_box_->checkState()) {
+ date_edit_->setEnabled(false);
+ } else {
+ date_edit_->setEnabled(true);
+ }
+}
+
+QGroupBox* KeyGenDialog::create_key_usage_group_box() {
+ auto* groupBox = new QGroupBox(this);
+ auto* grid = new QGridLayout(this);
+
+ groupBox->setTitle(_("Key Usage"));
+
+ auto* encrypt = new QCheckBox(_("Encryption"), groupBox);
+ encrypt->setTristate(false);
+
+ auto* sign = new QCheckBox(_("Signing"), groupBox);
+ sign->setTristate(false);
+
+ auto* cert = new QCheckBox(_("Certification"), groupBox);
+ cert->setTristate(false);
+
+ auto* auth = new QCheckBox(_("Authentication"), groupBox);
+ auth->setTristate(false);
+
+ key_usage_check_boxes_.push_back(encrypt);
+ key_usage_check_boxes_.push_back(sign);
+ key_usage_check_boxes_.push_back(cert);
+ key_usage_check_boxes_.push_back(auth);
+
+ grid->addWidget(encrypt, 0, 0);
+ grid->addWidget(sign, 0, 1);
+ grid->addWidget(cert, 1, 0);
+ grid->addWidget(auth, 1, 1);
+
+ groupBox->setLayout(grid);
+
+ return groupBox;
+}
+
+void KeyGenDialog::slot_encryption_box_changed(int state) {
+ if (state == 0) {
+ gen_key_info_->SetAllowEncryption(false);
+ } else {
+ gen_key_info_->SetAllowEncryption(true);
+ }
+}
+
+void KeyGenDialog::slot_signing_box_changed(int state) {
+ if (state == 0) {
+ gen_key_info_->SetAllowSigning(false);
+ } else {
+ gen_key_info_->SetAllowSigning(true);
+ }
+}
+
+void KeyGenDialog::slot_certification_box_changed(int state) {
+ if (state == 0) {
+ gen_key_info_->SetAllowCertification(false);
+ } else {
+ gen_key_info_->SetAllowCertification(true);
+ }
+}
+
+void KeyGenDialog::slot_authentication_box_changed(int state) {
+ if (state == 0) {
+ gen_key_info_->SetAllowAuthentication(false);
+ } else {
+ gen_key_info_->SetAllowAuthentication(true);
+ }
+}
+
+void KeyGenDialog::slot_activated_key_type(int index) {
+ qDebug() << "key type index changed " << index;
+
+ gen_key_info_->SetAlgo(
+ this->key_type_combo_box_->itemText(index).toStdString());
+ refresh_widgets_state();
+}
+
+void KeyGenDialog::refresh_widgets_state() {
+ qDebug() << "refresh_widgets_state called";
+
+ if (gen_key_info_->IsAllowEncryption())
+ key_usage_check_boxes_[0]->setCheckState(Qt::CheckState::Checked);
+ else
+ key_usage_check_boxes_[0]->setCheckState(Qt::CheckState::Unchecked);
+
+ if (gen_key_info_->IsAllowChangeEncryption())
+ key_usage_check_boxes_[0]->setDisabled(false);
+ else
+ key_usage_check_boxes_[0]->setDisabled(true);
+
+ if (gen_key_info_->IsAllowSigning())
+ key_usage_check_boxes_[1]->setCheckState(Qt::CheckState::Checked);
+ else
+ key_usage_check_boxes_[1]->setCheckState(Qt::CheckState::Unchecked);
+
+ if (gen_key_info_->IsAllowChangeSigning())
+ key_usage_check_boxes_[1]->setDisabled(false);
+ else
+ key_usage_check_boxes_[1]->setDisabled(true);
+
+ if (gen_key_info_->IsAllowCertification())
+ key_usage_check_boxes_[2]->setCheckState(Qt::CheckState::Checked);
+ else
+ key_usage_check_boxes_[2]->setCheckState(Qt::CheckState::Unchecked);
+
+ if (gen_key_info_->IsAllowChangeCertification())
+ key_usage_check_boxes_[2]->setDisabled(false);
+ else
+ key_usage_check_boxes_[2]->setDisabled(true);
+
+ if (gen_key_info_->IsAllowAuthentication())
+ key_usage_check_boxes_[3]->setCheckState(Qt::CheckState::Checked);
+ else
+ key_usage_check_boxes_[3]->setCheckState(Qt::CheckState::Unchecked);
+
+ if (gen_key_info_->IsAllowChangeAuthentication())
+ key_usage_check_boxes_[3]->setDisabled(false);
+ else
+ key_usage_check_boxes_[3]->setDisabled(true);
+
+ if (gen_key_info_->IsAllowNoPassPhrase())
+ no_pass_phrase_check_box_->setDisabled(false);
+ else
+ no_pass_phrase_check_box_->setDisabled(true);
+
+ key_size_spin_box_->setRange(gen_key_info_->GetSuggestMinKeySize(),
+ gen_key_info_->GetSuggestMaxKeySize());
+ key_size_spin_box_->setValue(gen_key_info_->GetKeyLength());
+ key_size_spin_box_->setSingleStep(gen_key_info_->GetSizeChangeStep());
+}
+
+void KeyGenDialog::set_signal_slot() {
+ connect(button_box_, &QDialogButtonBox::accepted, this,
+ &KeyGenDialog::slot_key_gen_accept);
+ connect(button_box_, &QDialogButtonBox::rejected, this,
+ &KeyGenDialog::reject);
+
+ connect(expire_check_box_, &QCheckBox::stateChanged, this,
+ &KeyGenDialog::slot_expire_box_changed);
+
+ connect(key_usage_check_boxes_[0], &QCheckBox::stateChanged, this,
+ &KeyGenDialog::slot_encryption_box_changed);
+ connect(key_usage_check_boxes_[1], &QCheckBox::stateChanged, this,
+ &KeyGenDialog::slot_signing_box_changed);
+ connect(key_usage_check_boxes_[2], &QCheckBox::stateChanged, this,
+ &KeyGenDialog::slot_certification_box_changed);
+ connect(key_usage_check_boxes_[3], &QCheckBox::stateChanged, this,
+ &KeyGenDialog::slot_authentication_box_changed);
+
+ connect(key_type_combo_box_, qOverload<int>(&QComboBox::currentIndexChanged),
+ this, &KeyGenDialog::slot_activated_key_type);
+
+ connect(no_pass_phrase_check_box_, &QCheckBox::stateChanged, this,
+ [this](int state) -> void {
+ if (state == 0) {
+ gen_key_info_->SetNonPassPhrase(false);
+ } else {
+ gen_key_info_->SetNonPassPhrase(true);
+ }
+ });
+}
+
+bool KeyGenDialog::check_email_address(const QString& str) {
+ return re_email_.match(str).hasMatch();
+}
+
+QGroupBox* KeyGenDialog::create_basic_info_group_box() {
+ error_label_ = new QLabel();
+ name_edit_ = new QLineEdit(this);
+ email_edit_ = new QLineEdit(this);
+ comment_edit_ = new QLineEdit(this);
+ key_size_spin_box_ = new QSpinBox(this);
+ key_type_combo_box_ = new QComboBox(this);
+
+ for (auto& algo : GenKeyInfo::GetSupportedKeyAlgo()) {
+ key_type_combo_box_->addItem(QString::fromStdString(algo));
+ }
+ if (!GenKeyInfo::GetSupportedKeyAlgo().empty()) {
+ key_type_combo_box_->setCurrentIndex(0);
+ }
+
+ date_edit_ =
+ new QDateTimeEdit(QDateTime::currentDateTime().addYears(2), this);
+ date_edit_->setMinimumDateTime(QDateTime::currentDateTime());
+ date_edit_->setMaximumDateTime(max_date_time_);
+ date_edit_->setDisplayFormat("dd/MM/yyyy hh:mm:ss");
+ date_edit_->setCalendarPopup(true);
+ date_edit_->setEnabled(true);
+
+ expire_check_box_ = new QCheckBox(this);
+ expire_check_box_->setCheckState(Qt::Unchecked);
+
+ no_pass_phrase_check_box_ = new QCheckBox(this);
+ no_pass_phrase_check_box_->setCheckState(Qt::Unchecked);
+
+ auto* vbox1 = new QGridLayout;
+
+ vbox1->addWidget(new QLabel(QString(_("Name")) + ": "), 0, 0);
+ vbox1->addWidget(new QLabel(QString(_("Email Address")) + ": "), 1, 0);
+ vbox1->addWidget(new QLabel(QString(_("Comment")) + ": "), 2, 0);
+ vbox1->addWidget(new QLabel(QString(_("Expiration Date")) + ": "), 3, 0);
+ vbox1->addWidget(new QLabel(QString(_("Never Expire")) + ": "), 3, 3);
+ vbox1->addWidget(new QLabel(QString(_("KeySize (in Bit)")) + ": "), 4, 0);
+ vbox1->addWidget(new QLabel(QString(_("Key Type")) + ": "), 5, 0);
+ vbox1->addWidget(new QLabel(QString(_("Non Pass Phrase")) + ": "), 6, 0);
+
+ vbox1->addWidget(name_edit_, 0, 1, 1, 3);
+ vbox1->addWidget(email_edit_, 1, 1, 1, 3);
+ vbox1->addWidget(comment_edit_, 2, 1, 1, 3);
+ vbox1->addWidget(date_edit_, 3, 1);
+ vbox1->addWidget(expire_check_box_, 3, 2);
+ vbox1->addWidget(key_size_spin_box_, 4, 1);
+ vbox1->addWidget(key_type_combo_box_, 5, 1);
+ vbox1->addWidget(no_pass_phrase_check_box_, 6, 1);
+
+ auto basicInfoGroupBox = new QGroupBox();
+ basicInfoGroupBox->setLayout(vbox1);
+ basicInfoGroupBox->setTitle(_("Basic Information"));
+
+ return basicInfoGroupBox;
+}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/dialog/key_generate/KeygenDialog.h b/src/ui/dialog/key_generate/KeygenDialog.h
new file mode 100644
index 00000000..baf10dbf
--- /dev/null
+++ b/src/ui/dialog/key_generate/KeygenDialog.h
@@ -0,0 +1,184 @@
+/**
+ * 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 <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.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef __KEYGENDIALOG_H__
+#define __KEYGENDIALOG_H__
+
+#include "core/GpgContext.h"
+#include "core/GpgGenKeyInfo.h"
+#include "ui/GpgFrontendUI.h"
+#include "ui/dialog/GeneralDialog.h"
+
+namespace GpgFrontend::UI {
+
+/**
+ * @brief
+ *
+ */
+class KeyGenDialog : public GeneralDialog {
+ Q_OBJECT
+
+ public:
+ /**
+ * @details Constructor of this class
+ *
+ * @param ctx The current GpgME context
+ * @param key The key to show details of
+ * @param parent The parent of this widget
+ */
+ explicit KeyGenDialog(QWidget* parent = nullptr);
+
+ signals:
+ /**
+ * @brief
+ *
+ */
+ void SignalKeyGenerated();
+
+ private:
+ /**
+ * @brief Create a key usage group box object
+ *
+ * @return QGroupBox*
+ */
+ QGroupBox* create_key_usage_group_box();
+
+ /**
+ * @brief Create a basic info group box object
+ *
+ * @return QGroupBox*
+ */
+ QGroupBox* create_basic_info_group_box();
+
+ /**
+ * @brief
+ *
+ */
+ QRegularExpression re_email_{
+ R"((?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\]))"};
+
+ /**
+ * @brief
+ *
+ */
+ QStringList error_messages_; ///< List of errors occurring when checking
+ ///< entries of line edits
+ std::unique_ptr<GenKeyInfo> gen_key_info_ =
+ std::make_unique<GenKeyInfo>(); ///<
+ QDialogButtonBox* button_box_; ///< Box for standard buttons
+ QLabel* error_label_{}; ///< Label containing error message
+ QLineEdit* name_edit_{}; ///< Line edit for the keys name
+ QLineEdit* email_edit_{}; ///< Line edit for the keys email
+ QLineEdit* comment_edit_{}; ///< Line edit for the keys comment
+ QSpinBox* key_size_spin_box_{}; ///< Spinbox for the keys size (in bit)
+ QComboBox* key_type_combo_box_{}; ///< Combobox for Key type
+ QDateTimeEdit* date_edit_{}; ///< Date edit for expiration date
+ QCheckBox* expire_check_box_{}; ///< Checkbox, if key should expire
+ QCheckBox* no_pass_phrase_check_box_{};
+ QGroupBox* key_usage_group_box_{}; ///< Group of Widgets detecting the usage
+ ///< of the Key
+ QDateTime max_date_time_; ///<
+ std::vector<QCheckBox*> key_usage_check_boxes_; ///< ENCR, SIGN, CERT, AUTH
+
+ /**
+ * @brief
+ *
+ */
+ void generate_key_dialog();
+
+ /**
+ * @details Refresh widgets state by GenKeyInfo
+ */
+ void refresh_widgets_state();
+
+ /**
+ * @brief Set the signal slot object
+ *
+ */
+ void set_signal_slot();
+
+ /**
+ * @brief
+ *
+ * @param str
+ * @return true
+ * @return false
+ */
+ bool check_email_address(const QString& str);
+
+ private slots:
+
+ /**
+ * @details when expirebox was checked/unchecked, enable/disable the
+ * expiration date box
+ */
+ void slot_expire_box_changed();
+
+ /**
+ * @details check all lineedits for false entries. Show error, when there is
+ * one, otherwise generate the key
+ */
+ void slot_key_gen_accept();
+
+ /**
+ * @brief
+ *
+ * @param state
+ */
+ void slot_encryption_box_changed(int state);
+
+ /**
+ * @brief
+ *
+ * @param state
+ */
+ void slot_signing_box_changed(int state);
+
+ /**
+ * @brief
+ *
+ * @param state
+ */
+ void slot_certification_box_changed(int state);
+
+ /**
+ * @brief
+ *
+ * @param state
+ */
+ void slot_authentication_box_changed(int state);
+
+ /**
+ * @brief
+ *
+ * @param index
+ */
+ void slot_activated_key_type(int index);
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // __KEYGENDIALOG_H__
diff --git a/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp b/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp
new file mode 100644
index 00000000..806c0e50
--- /dev/null
+++ b/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp
@@ -0,0 +1,344 @@
+/**
+ * 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 <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.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "SubkeyGenerateDialog.h"
+
+#include "core/function/GlobalSettingStation.h"
+#include "core/function/gpg/GpgKeyGetter.h"
+#include "core/function/gpg/GpgKeyOpera.h"
+#include "dialog/WaitingDialog.h"
+#include "ui/SignalStation.h"
+
+namespace GpgFrontend::UI {
+
+SubkeyGenerateDialog::SubkeyGenerateDialog(const KeyId& key_id, QWidget* parent)
+ : GeneralDialog(typeid(SubkeyGenerateDialog).name(), parent),
+ key_(GpgKeyGetter::GetInstance().GetKey(key_id)) {
+ auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
+
+ // max expire date time
+ bool longer_expiration_date = false;
+ try {
+ longer_expiration_date = settings.lookup("general.longer_expiration_date");
+ LOG(INFO) << "longer_expiration_date" << longer_expiration_date;
+
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("longer_expiration_date");
+ }
+
+ max_date_time_ = longer_expiration_date
+ ? QDateTime::currentDateTime().toLocalTime().addYears(30)
+ : QDateTime::currentDateTime().toLocalTime().addYears(2);
+
+ button_box_ =
+ new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+
+ key_usage_group_box_ = create_key_usage_group_box();
+
+ auto* groupGrid = new QGridLayout(this);
+ groupGrid->addWidget(create_basic_info_group_box(), 0, 0);
+ groupGrid->addWidget(key_usage_group_box_, 1, 0);
+
+ auto* nameList = new QWidget(this);
+ nameList->setLayout(groupGrid);
+
+ auto* vbox2 = new QVBoxLayout();
+ vbox2->addWidget(nameList);
+ vbox2->addWidget(error_label_);
+ vbox2->addWidget(button_box_);
+
+ this->setWindowTitle(_("Generate New Subkey"));
+ this->setLayout(vbox2);
+ this->setModal(true);
+
+ connect(this, &SubkeyGenerateDialog::SignalSubKeyGenerated,
+ SignalStation::GetInstance(),
+ &SignalStation::SignalKeyDatabaseRefresh);
+
+ set_signal_slot();
+ refresh_widgets_state();
+}
+
+QGroupBox* SubkeyGenerateDialog::create_key_usage_group_box() {
+ auto* groupBox = new QGroupBox(this);
+ auto* grid = new QGridLayout(this);
+
+ groupBox->setTitle(_("Key Usage"));
+
+ auto* encrypt = new QCheckBox(_("Encryption"), groupBox);
+ encrypt->setTristate(false);
+
+ auto* sign = new QCheckBox(_("Signing"), groupBox);
+ sign->setTristate(false);
+
+ auto* cert = new QCheckBox(_("Certification"), groupBox);
+ cert->setTristate(false);
+
+ auto* auth = new QCheckBox(_("Authentication"), groupBox);
+ auth->setTristate(false);
+
+ key_usage_check_boxes_.push_back(encrypt);
+ key_usage_check_boxes_.push_back(sign);
+ key_usage_check_boxes_.push_back(cert);
+ key_usage_check_boxes_.push_back(auth);
+
+ grid->addWidget(encrypt, 0, 0);
+ grid->addWidget(sign, 0, 1);
+ grid->addWidget(cert, 1, 0);
+ grid->addWidget(auth, 1, 1);
+
+ groupBox->setLayout(grid);
+
+ return groupBox;
+}
+
+QGroupBox* SubkeyGenerateDialog::create_basic_info_group_box() {
+ error_label_ = new QLabel();
+ key_size_spin_box_ = new QSpinBox(this);
+ key_type_combo_box_ = new QComboBox(this);
+
+ for (auto& algo : GenKeyInfo::GetSupportedKeyAlgo()) {
+ key_type_combo_box_->addItem(QString::fromStdString(algo));
+ }
+ if (!GenKeyInfo::GetSupportedKeyAlgo().empty()) {
+ key_type_combo_box_->setCurrentIndex(0);
+ }
+
+ date_edit_ =
+ new QDateTimeEdit(QDateTime::currentDateTime().addYears(2), this);
+ date_edit_->setMinimumDateTime(QDateTime::currentDateTime());
+ date_edit_->setMaximumDateTime(max_date_time_);
+ date_edit_->setDisplayFormat("dd/MM/yyyy hh:mm:ss");
+ date_edit_->setCalendarPopup(true);
+ date_edit_->setEnabled(true);
+
+ expire_check_box_ = new QCheckBox(this);
+ expire_check_box_->setCheckState(Qt::Unchecked);
+
+ auto* vbox1 = new QGridLayout;
+
+ vbox1->addWidget(new QLabel(QString(_("Expiration Date")) + ": "), 2, 0);
+ vbox1->addWidget(new QLabel(QString(_("Never Expire")) + ": "), 2, 3);
+ vbox1->addWidget(new QLabel(QString(_("KeySize (in Bit)")) + ": "), 1, 0);
+ vbox1->addWidget(new QLabel(QString(_("Key Type")) + ": "), 0, 0);
+
+ vbox1->addWidget(date_edit_, 2, 1);
+ vbox1->addWidget(expire_check_box_, 2, 2);
+ vbox1->addWidget(key_size_spin_box_, 1, 1);
+ vbox1->addWidget(key_type_combo_box_, 0, 1);
+
+ auto basicInfoGroupBox = new QGroupBox();
+ basicInfoGroupBox->setLayout(vbox1);
+ basicInfoGroupBox->setTitle(_("Basic Information"));
+
+ return basicInfoGroupBox;
+}
+
+void SubkeyGenerateDialog::set_signal_slot() {
+ connect(button_box_, &QDialogButtonBox::accepted, this,
+ &SubkeyGenerateDialog::slot_key_gen_accept);
+ connect(button_box_, &QDialogButtonBox::rejected, this,
+ &SubkeyGenerateDialog::reject);
+
+ connect(expire_check_box_, &QCheckBox::stateChanged, this,
+ &SubkeyGenerateDialog::slot_expire_box_changed);
+
+ connect(key_usage_check_boxes_[0], &QCheckBox::stateChanged, this,
+ &SubkeyGenerateDialog::slot_encryption_box_changed);
+ connect(key_usage_check_boxes_[1], &QCheckBox::stateChanged, this,
+ &SubkeyGenerateDialog::slot_signing_box_changed);
+ connect(key_usage_check_boxes_[2], &QCheckBox::stateChanged, this,
+ &SubkeyGenerateDialog::slot_certification_box_changed);
+ connect(key_usage_check_boxes_[3], &QCheckBox::stateChanged, this,
+ &SubkeyGenerateDialog::slot_authentication_box_changed);
+
+ connect(key_type_combo_box_, qOverload<int>(&QComboBox::currentIndexChanged),
+ this, &SubkeyGenerateDialog::slot_activated_key_type);
+}
+
+void SubkeyGenerateDialog::slot_expire_box_changed() {
+ if (expire_check_box_->checkState()) {
+ date_edit_->setEnabled(false);
+ } else {
+ date_edit_->setEnabled(true);
+ }
+}
+
+void SubkeyGenerateDialog::refresh_widgets_state() {
+ qDebug() << "refresh_widgets_state called";
+
+ if (gen_key_info_->IsAllowEncryption())
+ key_usage_check_boxes_[0]->setCheckState(Qt::CheckState::Checked);
+ else
+ key_usage_check_boxes_[0]->setCheckState(Qt::CheckState::Unchecked);
+
+ if (gen_key_info_->IsAllowChangeEncryption())
+ key_usage_check_boxes_[0]->setDisabled(false);
+ else
+ key_usage_check_boxes_[0]->setDisabled(true);
+
+ if (gen_key_info_->IsAllowSigning())
+ key_usage_check_boxes_[1]->setCheckState(Qt::CheckState::Checked);
+ else
+ key_usage_check_boxes_[1]->setCheckState(Qt::CheckState::Unchecked);
+
+ if (gen_key_info_->IsAllowChangeSigning())
+ key_usage_check_boxes_[1]->setDisabled(false);
+ else
+ key_usage_check_boxes_[1]->setDisabled(true);
+
+ if (gen_key_info_->IsAllowCertification())
+ key_usage_check_boxes_[2]->setCheckState(Qt::CheckState::Checked);
+ else
+ key_usage_check_boxes_[2]->setCheckState(Qt::CheckState::Unchecked);
+
+ if (gen_key_info_->IsAllowChangeCertification())
+ key_usage_check_boxes_[2]->setDisabled(false);
+ else
+ key_usage_check_boxes_[2]->setDisabled(true);
+
+ if (gen_key_info_->IsAllowAuthentication())
+ key_usage_check_boxes_[3]->setCheckState(Qt::CheckState::Checked);
+ else
+ key_usage_check_boxes_[3]->setCheckState(Qt::CheckState::Unchecked);
+
+ if (gen_key_info_->IsAllowChangeAuthentication())
+ key_usage_check_boxes_[3]->setDisabled(false);
+ else
+ key_usage_check_boxes_[3]->setDisabled(true);
+
+ key_size_spin_box_->setRange(gen_key_info_->GetSuggestMinKeySize(),
+ gen_key_info_->GetSuggestMaxKeySize());
+ key_size_spin_box_->setValue(gen_key_info_->GetKeyLength());
+ key_size_spin_box_->setSingleStep(gen_key_info_->GetSizeChangeStep());
+}
+
+void SubkeyGenerateDialog::slot_key_gen_accept() {
+ std::stringstream err_stream;
+
+ /**
+ * primary keys should have a reasonable expiration date (no more than 2 years
+ * in the future)
+ */
+ if (date_edit_->dateTime() > QDateTime::currentDateTime().addYears(2)) {
+ err_stream << " " << _("Expiration time no more than 2 years.") << " ";
+ }
+
+ auto err_string = err_stream.str();
+
+ if (err_string.empty()) {
+ gen_key_info_->SetKeyLength(key_size_spin_box_->value());
+
+ if (expire_check_box_->checkState()) {
+ gen_key_info_->SetNonExpired(true);
+ } else {
+ gen_key_info_->SetExpireTime(
+ boost::posix_time::from_time_t(date_edit_->dateTime().toTime_t()));
+ }
+
+ GpgError error;
+ auto thread = QThread::create([&]() {
+ LOG(INFO) << "Thread Started";
+ error = GpgKeyOpera::GetInstance().GenerateSubkey(key_, gen_key_info_);
+ });
+ thread->start();
+
+ auto* dialog = new WaitingDialog(_("Generating"), this);
+ dialog->show();
+
+ while (thread->isRunning()) {
+ QCoreApplication::processEvents();
+ }
+ dialog->close();
+
+ if (check_gpg_error_2_err_code(error) == GPG_ERR_NO_ERROR) {
+ auto* msg_box = new QMessageBox((QWidget*)this->parent());
+ msg_box->setAttribute(Qt::WA_DeleteOnClose);
+ msg_box->setStandardButtons(QMessageBox::Ok);
+ msg_box->setWindowTitle(_("Success"));
+ msg_box->setText(_("The new subkey has been generated."));
+ msg_box->setModal(true);
+ msg_box->open();
+
+ emit SignalSubKeyGenerated();
+ this->close();
+ } else
+ QMessageBox::critical(this, _("Failure"), _("Failed to generate key."));
+
+ } else {
+ /**
+ * create error message
+ */
+ error_label_->setAutoFillBackground(true);
+ QPalette error = error_label_->palette();
+ error.setColor(QPalette::Window, "#ff8080");
+ error_label_->setPalette(error);
+ error_label_->setText(err_string.c_str());
+
+ this->show();
+ }
+}
+
+void SubkeyGenerateDialog::slot_encryption_box_changed(int state) {
+ if (state == 0) {
+ gen_key_info_->SetAllowEncryption(false);
+ } else {
+ gen_key_info_->SetAllowEncryption(true);
+ }
+}
+
+void SubkeyGenerateDialog::slot_signing_box_changed(int state) {
+ if (state == 0) {
+ gen_key_info_->SetAllowSigning(false);
+ } else {
+ gen_key_info_->SetAllowSigning(true);
+ }
+}
+
+void SubkeyGenerateDialog::slot_certification_box_changed(int state) {
+ if (state == 0) {
+ gen_key_info_->SetAllowCertification(false);
+ } else {
+ gen_key_info_->SetAllowCertification(true);
+ }
+}
+
+void SubkeyGenerateDialog::slot_authentication_box_changed(int state) {
+ if (state == 0) {
+ gen_key_info_->SetAllowAuthentication(false);
+ } else {
+ gen_key_info_->SetAllowAuthentication(true);
+ }
+}
+
+void SubkeyGenerateDialog::slot_activated_key_type(int index) {
+ qDebug() << "key type index changed " << index;
+ gen_key_info_->SetAlgo(
+ this->key_type_combo_box_->itemText(index).toStdString());
+ refresh_widgets_state();
+}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/dialog/key_generate/SubkeyGenerateDialog.h b/src/ui/dialog/key_generate/SubkeyGenerateDialog.h
new file mode 100644
index 00000000..1e6608b2
--- /dev/null
+++ b/src/ui/dialog/key_generate/SubkeyGenerateDialog.h
@@ -0,0 +1,152 @@
+/**
+ * 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 <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.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef GPGFRONTEND_SUBKEYGENERATEDIALOG_H
+#define GPGFRONTEND_SUBKEYGENERATEDIALOG_H
+
+#include "core/GpgContext.h"
+#include "core/GpgGenKeyInfo.h"
+#include "ui/GpgFrontendUI.h"
+#include "ui/dialog/GeneralDialog.h"
+
+namespace GpgFrontend::UI {
+/**
+ * @brief
+ *
+ */
+class SubkeyGenerateDialog : public GeneralDialog {
+ Q_OBJECT
+
+ public:
+ /**
+ * @brief Construct a new Subkey Generate Dialog object
+ *
+ * @param key_id
+ * @param parent
+ */
+ explicit SubkeyGenerateDialog(const KeyId& key_id, QWidget* parent);
+
+ signals:
+ /**
+ * @brief
+ *
+ */
+ void SignalSubKeyGenerated();
+
+ private:
+ GpgKey key_; ///<
+
+ std::unique_ptr<GenKeyInfo> gen_key_info_ =
+ std::make_unique<GenKeyInfo>(true); ///<
+
+ QGroupBox* key_usage_group_box_{};
+ QDialogButtonBox* button_box_; ///< Box for standard buttons
+ QLabel* error_label_{}; ///< Label containing error message
+ QSpinBox* key_size_spin_box_{}; ///< Spinbox for the keys size (in bit)
+ QComboBox* key_type_combo_box_{}; ///< Combobox for Key tpe
+ QDateTimeEdit* date_edit_{}; ///< Date edit for expiration date
+ QCheckBox* expire_check_box_{}; ///< Checkbox, if key should expire
+
+ std::vector<QCheckBox*> key_usage_check_boxes_; ///< ENCR, SIGN, CERT, AUTH
+ QDateTime max_date_time_; ///<
+
+ /**
+ * @brief Create a key usage group box object
+ *
+ * @return QGroupBox*
+ */
+ QGroupBox* create_key_usage_group_box();
+
+ /**
+ * @brief Create a basic info group box object
+ *
+ * @return QGroupBox*
+ */
+ QGroupBox* create_basic_info_group_box();
+ /**
+ * @brief Set the signal slot object
+ *
+ */
+ void set_signal_slot();
+
+ /**
+ * @details Refresh widgets state by GenKeyInfo
+ */
+ void refresh_widgets_state();
+
+ private slots:
+
+ /**
+ * @details when expire box was checked/unchecked, enable/disable the
+ * expiration date box
+ */
+ void slot_expire_box_changed();
+
+ /**
+ * @details check all line edits for false entries. Show error, when there is
+ * one, otherwise generate the key
+ */
+ void slot_key_gen_accept();
+
+ /**
+ * @brief
+ *
+ * @param state
+ */
+ void slot_encryption_box_changed(int state);
+
+ /**
+ * @brief
+ *
+ * @param state
+ */
+ void slot_signing_box_changed(int state);
+
+ /**
+ * @brief
+ *
+ * @param state
+ */
+ void slot_certification_box_changed(int state);
+
+ /**
+ * @brief
+ *
+ * @param state
+ */
+ void slot_authentication_box_changed(int state);
+
+ /**
+ * @brief
+ *
+ * @param index
+ */
+ void slot_activated_key_type(int index);
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_SUBKEYGENERATEDIALOG_H
diff --git a/src/ui/dialog/keypair_details/KeyDetailsDialog.cpp b/src/ui/dialog/keypair_details/KeyDetailsDialog.cpp
new file mode 100644
index 00000000..9c2f8003
--- /dev/null
+++ b/src/ui/dialog/keypair_details/KeyDetailsDialog.cpp
@@ -0,0 +1,62 @@
+/**
+ * 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 <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
+ *
+ */
+
+#include "KeyDetailsDialog.h"
+
+#include "KeyPairDetailTab.h"
+#include "KeyPairOperaTab.h"
+#include "KeyPairSubkeyTab.h"
+#include "KeyPairUIDTab.h"
+
+namespace GpgFrontend::UI {
+KeyDetailsDialog::KeyDetailsDialog(const GpgKey& key, QWidget* parent)
+ : GeneralDialog(typeid(KeyDetailsDialog).name(), parent) {
+ tab_widget_ = new QTabWidget();
+ tab_widget_->addTab(new KeyPairDetailTab(key.GetId(), tab_widget_),
+ _("KeyPair"));
+ tab_widget_->addTab(new KeyPairUIDTab(key.GetId(), tab_widget_), _("UIDs"));
+ tab_widget_->addTab(new KeyPairSubkeyTab(key.GetId(), tab_widget_),
+ _("Subkeys"));
+ tab_widget_->addTab(new KeyPairOperaTab(key.GetId(), tab_widget_),
+ _("Operations"));
+
+ auto* mainLayout = new QVBoxLayout;
+ mainLayout->addWidget(tab_widget_);
+
+#ifdef MACOS
+ setAttribute(Qt::WA_LayoutUsesWidgetRect);
+#endif
+ this->setAttribute(Qt::WA_DeleteOnClose, true);
+ this->setLayout(mainLayout);
+ this->setWindowTitle(_("Key Details"));
+ this->setModal(true);
+ this->setMinimumSize({520, 600});
+ this->resize(this->minimumSize());
+ this->show();
+}
+} // namespace GpgFrontend::UI
diff --git a/src/ui/dialog/keypair_details/KeyDetailsDialog.h b/src/ui/dialog/keypair_details/KeyDetailsDialog.h
new file mode 100644
index 00000000..1ddcda00
--- /dev/null
+++ b/src/ui/dialog/keypair_details/KeyDetailsDialog.h
@@ -0,0 +1,49 @@
+/**
+ * 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 <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
+ *
+ */
+
+#ifndef __KEYDETAILSDIALOG_H__
+#define __KEYDETAILSDIALOG_H__
+
+#include "core/GpgContext.h"
+#include "ui/GpgFrontendUI.h"
+#include "ui/dialog/GeneralDialog.h"
+
+namespace GpgFrontend::UI {
+
+class KeyDetailsDialog : public GeneralDialog {
+ Q_OBJECT
+
+ public:
+ explicit KeyDetailsDialog(const GpgKey& key, QWidget* parent = nullptr);
+
+ private:
+ QTabWidget* tab_widget_{};
+};
+} // namespace GpgFrontend::UI
+
+#endif // __KEYDETAILSDIALOG_H__
diff --git a/src/ui/dialog/keypair_details/KeyNewUIDDialog.cpp b/src/ui/dialog/keypair_details/KeyNewUIDDialog.cpp
new file mode 100644
index 00000000..18dd1967
--- /dev/null
+++ b/src/ui/dialog/keypair_details/KeyNewUIDDialog.cpp
@@ -0,0 +1,114 @@
+/**
+ * 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 <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.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "KeyNewUIDDialog.h"
+
+#include "core/function/gpg/GpgKeyGetter.h"
+#include "core/function/gpg/GpgUIDOperator.h"
+#include "ui/SignalStation.h"
+
+namespace GpgFrontend::UI {
+KeyNewUIDDialog::KeyNewUIDDialog(const KeyId& key_id, QWidget* parent)
+ : GeneralDialog(typeid(KeyNewUIDDialog).name(), parent),
+ m_key_(GpgKeyGetter::GetInstance().GetKey(key_id)) {
+ name_ = new QLineEdit();
+ name_->setMinimumWidth(240);
+ email_ = new QLineEdit();
+ email_->setMinimumWidth(240);
+ comment_ = new QLineEdit();
+ comment_->setMinimumWidth(240);
+ create_button_ = new QPushButton("Create");
+ error_label_ = new QLabel();
+
+ auto gridLayout = new QGridLayout();
+ gridLayout->addWidget(new QLabel(_("Name")), 0, 0);
+ gridLayout->addWidget(new QLabel(_("Email")), 1, 0);
+ gridLayout->addWidget(new QLabel(_("Comment")), 2, 0);
+
+ gridLayout->addWidget(name_, 0, 1);
+ gridLayout->addWidget(email_, 1, 1);
+ gridLayout->addWidget(comment_, 2, 1);
+
+ gridLayout->addWidget(create_button_, 3, 0, 1, 2);
+ gridLayout->addWidget(
+ new QLabel(_("Notice: The New UID Created will be set as Primary.")), 4,
+ 0, 1, 2);
+ gridLayout->addWidget(error_label_, 5, 0, 1, 2);
+
+ connect(create_button_, &QPushButton::clicked, this,
+ &KeyNewUIDDialog::slot_create_new_uid);
+
+ this->setLayout(gridLayout);
+ this->setWindowTitle(_("Create New UID"));
+ this->setAttribute(Qt::WA_DeleteOnClose, true);
+ this->setModal(true);
+
+ connect(this, &KeyNewUIDDialog::SignalUIDCreated,
+ SignalStation::GetInstance(),
+ &SignalStation::SignalKeyDatabaseRefresh);
+}
+
+void KeyNewUIDDialog::slot_create_new_uid() {
+ std::stringstream error_stream;
+
+ /**
+ * check for errors in keygen dialog input
+ */
+ if ((name_->text()).size() < 5) {
+ error_stream << " " << _("Name must contain at least five characters.")
+ << std::endl;
+ }
+ if (email_->text().isEmpty() || !check_email_address(email_->text())) {
+ error_stream << " " << _("Please give a email address.") << std::endl;
+ }
+ auto error_string = error_stream.str();
+ if (error_string.empty()) {
+ if (GpgUIDOperator::GetInstance().AddUID(
+ m_key_, name_->text().toStdString(), comment_->text().toStdString(),
+ email_->text().toStdString())) {
+ emit finished(1);
+ emit SignalUIDCreated();
+ } else
+ emit finished(-1);
+
+ } else {
+ /**
+ * create error message
+ */
+ error_label_->setAutoFillBackground(true);
+ QPalette error = error_label_->palette();
+ error.setColor(QPalette::Window, "#ff8080");
+ error_label_->setPalette(error);
+ error_label_->setText(error_string.c_str());
+
+ this->show();
+ }
+}
+
+bool KeyNewUIDDialog::check_email_address(const QString& str) {
+ return re_email_.match(str).hasMatch();
+}
+} // namespace GpgFrontend::UI
diff --git a/src/ui/dialog/keypair_details/KeyNewUIDDialog.h b/src/ui/dialog/keypair_details/KeyNewUIDDialog.h
new file mode 100644
index 00000000..291b59c4
--- /dev/null
+++ b/src/ui/dialog/keypair_details/KeyNewUIDDialog.h
@@ -0,0 +1,88 @@
+/**
+ * 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 <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.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef GPGFRONTEND_KEYNEWUIDDIALOG_H
+#define GPGFRONTEND_KEYNEWUIDDIALOG_H
+
+#include "core/GpgContext.h"
+#include "ui/GpgFrontendUI.h"
+#include "ui/dialog/GeneralDialog.h"
+
+namespace GpgFrontend::UI {
+class KeyNewUIDDialog : public GeneralDialog {
+ Q_OBJECT
+
+ public:
+ /**
+ * @brief Construct a new Key New U I D Dialog object
+ *
+ * @param key
+ * @param parent
+ */
+ KeyNewUIDDialog(const KeyId& key, QWidget* parent = nullptr);
+
+ signals:
+ /**
+ * @brief
+ *
+ */
+ void SignalUIDCreated();
+
+ private slots:
+
+ /**
+ * @brief
+ *
+ */
+ void slot_create_new_uid();
+
+ private:
+ GpgKey m_key_; ///<
+
+ QLineEdit* name_{}; ///<
+ QLineEdit* email_{}; ///<
+ QLineEdit* comment_{}; ///<
+
+ QPushButton* create_button_{}; ///<
+
+ QStringList error_messages_; ///<
+ QLabel* error_label_{}; ///<
+
+ QRegularExpression re_email_{
+ R"((?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\]))"};
+
+ /**
+ * @brief
+ *
+ * @param str
+ * @return true
+ * @return false
+ */
+ bool check_email_address(const QString& str);
+};
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_KEYNEWUIDDIALOG_H
diff --git a/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp b/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp
new file mode 100644
index 00000000..4a6e4b52
--- /dev/null
+++ b/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp
@@ -0,0 +1,276 @@
+/**
+ * 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 <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.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "KeyPairDetailTab.h"
+
+#include "core/function/gpg/GpgKeyGetter.h"
+#include "core/function/gpg/GpgKeyImportExporter.h"
+#include "dialog/WaitingDialog.h"
+#include "ui/SignalStation.h"
+
+namespace GpgFrontend::UI {
+KeyPairDetailTab::KeyPairDetailTab(const std::string& key_id, QWidget* parent)
+ : QWidget(parent), key_(GpgKeyGetter::GetInstance().GetKey(key_id)) {
+ LOG(INFO) << key_.GetEmail() << key_.IsPrivateKey() << key_.IsHasMasterKey()
+ << key_.GetSubKeys()->front().IsPrivateKey();
+
+ owner_box_ = new QGroupBox(_("Owner"));
+ key_box_ = new QGroupBox(_("Primary Key"));
+ fingerprint_box_ = new QGroupBox(_("Fingerprint"));
+ additional_uid_box_ = new QGroupBox(_("Additional UIDs"));
+
+ name_var_label_ = new QLabel();
+ name_var_label_->setTextInteractionFlags(Qt::TextSelectableByMouse);
+ email_var_label_ = new QLabel();
+ email_var_label_->setTextInteractionFlags(Qt::TextSelectableByMouse);
+
+ comment_var_label_ = new QLabel();
+ comment_var_label_->setTextInteractionFlags(Qt::TextSelectableByMouse);
+ key_id_var_label = new QLabel();
+ key_id_var_label->setTextInteractionFlags(Qt::TextSelectableByMouse);
+
+ usage_var_label_ = new QLabel();
+ actual_usage_var_label_ = new QLabel();
+
+ key_size_var_label_ = new QLabel();
+ expire_var_label_ = new QLabel();
+ created_var_label_ = new QLabel();
+ last_update_var_label_ = new QLabel();
+ algorithm_var_label_ = new QLabel();
+ primary_key_exist_var_label_ = new QLabel();
+
+ auto* mvbox = new QVBoxLayout();
+ auto* vboxKD = new QGridLayout();
+ auto* vboxOD = new QGridLayout();
+
+ vboxOD->addWidget(new QLabel(QString(_("Name")) + ": "), 0, 0);
+ vboxOD->addWidget(new QLabel(QString(_("Email Address")) + ": "), 1, 0);
+ vboxOD->addWidget(new QLabel(QString(_("Comment")) + ": "), 2, 0);
+ vboxOD->addWidget(name_var_label_, 0, 1);
+ vboxOD->addWidget(email_var_label_, 1, 1);
+ vboxOD->addWidget(comment_var_label_, 2, 1);
+
+ vboxKD->addWidget(new QLabel(QString(_("Key ID")) + ": "), 0, 0);
+ vboxKD->addWidget(new QLabel(QString(_("Algorithm")) + ": "), 1, 0);
+ vboxKD->addWidget(new QLabel(QString(_("Key Size")) + ": "), 2, 0);
+ vboxKD->addWidget(new QLabel(QString(_("Nominal Usage")) + ": "), 3, 0);
+ vboxKD->addWidget(new QLabel(QString(_("Actual Usage")) + ": "), 4, 0);
+ vboxKD->addWidget(new QLabel(QString(_("Create Date (Local Time)")) + ": "),
+ 5, 0);
+ vboxKD->addWidget(new QLabel(QString(_("Expires on (Local Time)")) + ": "), 6,
+ 0);
+ vboxKD->addWidget(new QLabel(QString(_("Last Update (Local Time)")) + ": "),
+ 7, 0);
+ vboxKD->addWidget(new QLabel(QString(_("Primary Key Existence")) + ": "), 8,
+ 0);
+
+ key_id_var_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ vboxKD->addWidget(key_id_var_label, 0, 1, 1, 1);
+ vboxKD->addWidget(algorithm_var_label_, 1, 1, 1, 2);
+ vboxKD->addWidget(key_size_var_label_, 2, 1, 1, 2);
+ vboxKD->addWidget(usage_var_label_, 3, 1, 1, 2);
+ vboxKD->addWidget(actual_usage_var_label_, 4, 1, 1, 2);
+ vboxKD->addWidget(created_var_label_, 5, 1, 1, 2);
+ vboxKD->addWidget(expire_var_label_, 6, 1, 1, 2);
+ vboxKD->addWidget(last_update_var_label_, 7, 1, 1, 2);
+ vboxKD->addWidget(primary_key_exist_var_label_, 8, 1, 1, 2);
+
+ auto* copyKeyIdButton = new QPushButton(_("Copy"));
+ copyKeyIdButton->setFlat(true);
+ copyKeyIdButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
+ vboxKD->addWidget(copyKeyIdButton, 0, 2);
+ connect(copyKeyIdButton, &QPushButton::clicked, this, [=]() {
+ QString fpr = key_id_var_label->text().trimmed();
+ QClipboard* cb = QApplication::clipboard();
+ cb->setText(fpr);
+ });
+
+ owner_box_->setLayout(vboxOD);
+ mvbox->addWidget(owner_box_);
+ key_box_->setLayout(vboxKD);
+ mvbox->addWidget(key_box_);
+
+ fingerprint_var_label_ = new QLabel();
+ fingerprint_var_label_->setWordWrap(false);
+ fingerprint_var_label_->setTextInteractionFlags(Qt::TextSelectableByMouse);
+ fingerprint_var_label_->setStyleSheet("margin-left: 0; margin-right: 5;");
+ fingerprint_var_label_->setAlignment(Qt::AlignCenter);
+ auto* hboxFP = new QHBoxLayout();
+
+ hboxFP->addStretch();
+ hboxFP->addWidget(fingerprint_var_label_);
+
+ auto* copyFingerprintButton = new QPushButton(_("Copy"));
+ copyFingerprintButton->setFlat(true);
+ copyFingerprintButton->setToolTip(_("copy fingerprint to clipboard"));
+ connect(copyFingerprintButton, &QPushButton::clicked, this,
+ &KeyPairDetailTab::slot_copy_fingerprint);
+
+ hboxFP->addWidget(copyFingerprintButton);
+ hboxFP->addStretch();
+
+ fingerprint_box_->setLayout(hboxFP);
+ mvbox->addWidget(fingerprint_box_);
+ mvbox->addStretch();
+
+ auto* expBox = new QHBoxLayout();
+ QPixmap pixmap(":warning.png");
+
+ exp_label_ = new QLabel();
+ icon_label_ = new QLabel();
+
+ icon_label_->setPixmap(pixmap.scaled(24, 24, Qt::KeepAspectRatio));
+ exp_label_->setAlignment(Qt::AlignCenter);
+ expBox->addStretch();
+ expBox->addWidget(icon_label_);
+ expBox->addWidget(exp_label_);
+ expBox->addStretch();
+ mvbox->addLayout(expBox);
+ mvbox->setContentsMargins(0, 0, 0, 0);
+
+ // when key database updated
+ connect(SignalStation::GetInstance(),
+ &SignalStation::SignalKeyDatabaseRefreshDone, this,
+ &KeyPairDetailTab::slot_refresh_key);
+
+ slot_refresh_key_info();
+ setAttribute(Qt::WA_DeleteOnClose, true);
+ setLayout(mvbox);
+}
+
+void KeyPairDetailTab::slot_copy_fingerprint() {
+ QString fpr =
+ fingerprint_var_label_->text().trimmed().replace(" ", QString());
+ QClipboard* cb = QApplication::clipboard();
+ cb->setText(fpr);
+}
+
+void KeyPairDetailTab::slot_refresh_key_info() {
+ // Show the situation that primary key not exists.
+ primary_key_exist_var_label_->setText(
+ key_.IsHasMasterKey() ? _("Exists") : _("Not Exists"));
+ if (!key_.IsHasMasterKey()) {
+ auto palette_expired = primary_key_exist_var_label_->palette();
+ palette_expired.setColor(primary_key_exist_var_label_->foregroundRole(),
+ Qt::red);
+ primary_key_exist_var_label_->setPalette(palette_expired);
+ } else {
+ auto palette_valid = primary_key_exist_var_label_->palette();
+ palette_valid.setColor(primary_key_exist_var_label_->foregroundRole(),
+ Qt::darkGreen);
+ primary_key_exist_var_label_->setPalette(palette_valid);
+ }
+
+ if (key_.IsExpired()) {
+ auto paletteExpired = expire_var_label_->palette();
+ paletteExpired.setColor(expire_var_label_->foregroundRole(), Qt::red);
+ expire_var_label_->setPalette(paletteExpired);
+ } else {
+ auto paletteValid = expire_var_label_->palette();
+ paletteValid.setColor(expire_var_label_->foregroundRole(), Qt::darkGreen);
+ expire_var_label_->setPalette(paletteValid);
+ }
+
+ name_var_label_->setText(QString::fromStdString(key_.GetName()));
+ email_var_label_->setText(QString::fromStdString(key_.GetEmail()));
+
+ comment_var_label_->setText(QString::fromStdString(key_.GetComment()));
+ key_id_var_label->setText(QString::fromStdString(key_.GetId()));
+
+ std::stringstream usage_steam;
+
+ if (key_.IsHasCertificationCapability())
+ usage_steam << _("Certificate") << " ";
+ if (key_.IsHasEncryptionCapability()) usage_steam << _("Encrypt") << " ";
+ if (key_.IsHasSigningCapability()) usage_steam << _("Sign") << " ";
+ if (key_.IsHasAuthenticationCapability()) usage_steam << _("Auth") << " ";
+
+ usage_var_label_->setText(usage_steam.str().c_str());
+
+ std::stringstream actual_usage_steam;
+
+ if (key_.IsHasActualCertificationCapability())
+ actual_usage_steam << _("Certificate") << " ";
+ if (key_.IsHasActualEncryptionCapability())
+ actual_usage_steam << _("Encrypt") << " ";
+ if (key_.IsHasActualSigningCapability())
+ actual_usage_steam << _("Sign") << " ";
+ if (key_.IsHasActualAuthenticationCapability())
+ actual_usage_steam << _("Auth") << " ";
+
+ actual_usage_var_label_->setText(actual_usage_steam.str().c_str());
+
+ std::string key_size_val, key_expire_val, key_create_time_val, key_algo_val,
+ key_last_update_val;
+
+ key_size_val = std::to_string(key_.GetPrimaryKeyLength());
+
+ if (to_time_t(boost::posix_time::ptime(key_.GetExpireTime())) == 0) {
+ expire_var_label_->setText(_("Never Expire"));
+ } else {
+ expire_var_label_->setText(QLocale::system().toString(
+ QDateTime::fromTime_t(to_time_t(key_.GetExpireTime()))));
+ }
+
+ key_algo_val = key_.GetPublicKeyAlgo();
+
+ created_var_label_->setText(QLocale::system().toString(
+ QDateTime::fromTime_t(to_time_t(key_.GetCreateTime()))));
+
+ if (to_time_t(boost::posix_time::ptime(key_.GetLastUpdateTime())) == 0) {
+ last_update_var_label_->setText(_("No Data"));
+ } else {
+ last_update_var_label_->setText(QLocale::system().toString(
+ QDateTime::fromTime_t(to_time_t(key_.GetLastUpdateTime()))));
+ }
+
+ key_size_var_label_->setText(key_size_val.c_str());
+ algorithm_var_label_->setText(key_algo_val.c_str());
+ fingerprint_var_label_->setText(
+ beautify_fingerprint(key_.GetFingerprint()).c_str());
+
+ icon_label_->hide();
+ exp_label_->hide();
+
+ if (key_.IsExpired()) {
+ icon_label_->show();
+ exp_label_->show();
+ exp_label_->setText(_("Warning: The primary key has expired."));
+ }
+ if (key_.IsRevoked()) {
+ icon_label_->show();
+ exp_label_->show();
+ exp_label_->setText(_("Warning: The primary key has been revoked."));
+ }
+}
+
+void KeyPairDetailTab::slot_refresh_key() {
+ LOG(INFO) << _("Called");
+ this->key_ = GpgKeyGetter::GetInstance().GetKey(key_.GetId());
+ this->slot_refresh_key_info();
+}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/dialog/keypair_details/KeyPairDetailTab.h b/src/ui/dialog/keypair_details/KeyPairDetailTab.h
new file mode 100644
index 00000000..91ccdab8
--- /dev/null
+++ b/src/ui/dialog/keypair_details/KeyPairDetailTab.h
@@ -0,0 +1,99 @@
+/**
+ * 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 <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.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef GPGFRONTEND_KEYPAIRDETAILTAB_H
+#define GPGFRONTEND_KEYPAIRDETAILTAB_H
+
+#include "KeySetExpireDateDialog.h"
+#include "core/GpgContext.h"
+#include "ui/GpgFrontendUI.h"
+#include "ui/dialog/import_export/KeyServerImportDialog.h"
+#include "ui/dialog/import_export/KeyUploadDialog.h"
+
+namespace GpgFrontend::UI {
+
+class KeyPairDetailTab : public QWidget {
+ Q_OBJECT
+
+ private slots:
+
+ /**
+ * @details Copy the fingerprint to clipboard
+ */
+ void slot_copy_fingerprint();
+
+ /**
+ * @brief
+ *
+ */
+ void slot_refresh_key_info();
+
+ /**
+ * @brief
+ *
+ */
+ void slot_refresh_key();
+
+ private:
+ GpgKey key_; ///<
+
+ QGroupBox* owner_box_; ///< Groupbox containing owner information
+ QGroupBox* key_box_; ///< Groupbox containing key information
+ QGroupBox* fingerprint_box_; ///< Groupbox containing fingerprint information
+ QGroupBox* additional_uid_box_; ///< Groupbox containing information about
+ ///< additional uids
+
+ QLabel* name_var_label_; ///< Label containing the keys name
+ QLabel* email_var_label_; ///< Label containing the keys email
+ QLabel* comment_var_label_; ///< Label containing the keys comment
+ QLabel* key_size_var_label_; ///< Label containing the keys key size
+ QLabel* expire_var_label_; ///< Label containing the keys expiration date
+ QLabel* created_var_label_; ///< Label containing the keys creation date
+ QLabel* last_update_var_label_; ///<
+ QLabel* algorithm_var_label_; ///< Label containing the keys algorithm
+ QLabel* key_id_var_label; ///< Label containing the keys keyid
+ QLabel* fingerprint_var_label_; ///< Label containing the keys fingerprint
+ QLabel* usage_var_label_;
+ QLabel* actual_usage_var_label_;
+ QLabel* primary_key_exist_var_label_;
+
+ QLabel* icon_label_; ///<
+ QLabel* exp_label_; ///<
+
+ public:
+ /**
+ * @brief Construct a new Key Pair Detail Tab object
+ *
+ * @param key_id
+ * @param parent
+ */
+ explicit KeyPairDetailTab(const std::string& key_id,
+ QWidget* parent = nullptr);
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_KEYPAIRDETAILTAB_H
diff --git a/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp b/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp
new file mode 100644
index 00000000..77eba0bc
--- /dev/null
+++ b/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp
@@ -0,0 +1,360 @@
+/**
+ * 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 <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.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "KeyPairOperaTab.h"
+
+#include "KeySetExpireDateDialog.h"
+#include "core/function/gpg/GpgKeyImportExporter.h"
+#include "core/function/gpg/GpgKeyOpera.h"
+#include "ui/SignalStation.h"
+#include "ui/UserInterfaceUtils.h"
+#include "ui/dialog/import_export/KeyUploadDialog.h"
+
+namespace GpgFrontend::UI {
+
+KeyPairOperaTab::KeyPairOperaTab(const std::string& key_id, QWidget* parent)
+ : QWidget(parent), m_key_(GpgKeyGetter::GetInstance().GetKey(key_id)) {
+ // Set Menu
+ CreateOperaMenu();
+ auto m_vbox = new QVBoxLayout(this);
+
+ auto* opera_key_box = new QGroupBox(_("General Operations"));
+ auto* vbox_p_k = new QVBoxLayout();
+
+ auto export_h_box_layout = new QHBoxLayout();
+ vbox_p_k->addLayout(export_h_box_layout);
+
+ auto* export_public_button = new QPushButton(_("Export Public Key"));
+ export_h_box_layout->addWidget(export_public_button);
+ connect(export_public_button, &QPushButton::clicked, this,
+ &KeyPairOperaTab::slot_export_public_key);
+
+ if (m_key_.IsPrivateKey()) {
+ auto* export_private_button = new QPushButton(_("Export Private Key"));
+ export_private_button->setStyleSheet("text-align:center;");
+ export_private_button->setMenu(secret_key_export_opera_menu_);
+ export_h_box_layout->addWidget(export_private_button);
+
+ if (m_key_.IsHasMasterKey()) {
+ auto* edit_expires_button =
+ new QPushButton(_("Modify Expiration Datetime (Primary Key)"));
+ connect(edit_expires_button, &QPushButton::clicked, this,
+ &KeyPairOperaTab::slot_modify_edit_datetime);
+ auto* edit_password_button = new QPushButton(_("Modify Password"));
+ connect(edit_password_button, &QPushButton::clicked, this,
+ &KeyPairOperaTab::slot_modify_password);
+
+ vbox_p_k->addWidget(edit_expires_button);
+ vbox_p_k->addWidget(edit_password_button);
+ }
+ }
+
+ auto advance_h_box_layout = new QHBoxLayout();
+ auto* key_server_opera_button =
+ new QPushButton(_("Key Server Operation (Pubkey)"));
+ key_server_opera_button->setStyleSheet("text-align:center;");
+ key_server_opera_button->setMenu(key_server_opera_menu_);
+ advance_h_box_layout->addWidget(key_server_opera_button);
+
+ if (m_key_.IsPrivateKey() && m_key_.IsHasMasterKey()) {
+ auto* revoke_cert_gen_button =
+ new QPushButton(_("Generate Revoke Certificate"));
+ connect(revoke_cert_gen_button, &QPushButton::clicked, this,
+ &KeyPairOperaTab::slot_gen_revoke_cert);
+ advance_h_box_layout->addWidget(revoke_cert_gen_button);
+ }
+
+ auto* modify_tofu_button = new QPushButton(_("Modify TOFU Policy"));
+ connect(modify_tofu_button, &QPushButton::clicked, this,
+ &KeyPairOperaTab::slot_modify_tofu_policy);
+
+ vbox_p_k->addLayout(advance_h_box_layout);
+ opera_key_box->setLayout(vbox_p_k);
+ m_vbox->addWidget(opera_key_box);
+ vbox_p_k->addWidget(modify_tofu_button);
+ m_vbox->addStretch(0);
+
+ setLayout(m_vbox);
+}
+
+void KeyPairOperaTab::CreateOperaMenu() {
+ key_server_opera_menu_ = new QMenu(this);
+
+ auto* uploadKeyPair = new QAction(_("Upload Key Pair to Key Server"), this);
+ connect(uploadKeyPair, &QAction::triggered, this,
+ &KeyPairOperaTab::slot_upload_key_to_server);
+ if (!(m_key_.IsPrivateKey() && m_key_.IsHasMasterKey()))
+ uploadKeyPair->setDisabled(true);
+
+ auto* updateKeyPair = new QAction(_("Sync Key Pair From Key Server"), this);
+ connect(updateKeyPair, &QAction::triggered, this,
+ &KeyPairOperaTab::slot_update_key_from_server);
+
+ // when a key has primary key, it should always upload to keyserver.
+ if (m_key_.IsHasMasterKey()) {
+ updateKeyPair->setDisabled(true);
+ }
+
+ key_server_opera_menu_->addAction(uploadKeyPair);
+ key_server_opera_menu_->addAction(updateKeyPair);
+
+ secret_key_export_opera_menu_ = new QMenu(this);
+
+ auto* exportFullSecretKey = new QAction(_("Export Full Secret Key"), this);
+ connect(exportFullSecretKey, &QAction::triggered, this,
+ &KeyPairOperaTab::slot_export_private_key);
+ if (!m_key_.IsPrivateKey()) exportFullSecretKey->setDisabled(true);
+
+ auto* exportShortestSecretKey =
+ new QAction(_("Export Shortest Secret Key"), this);
+ connect(exportShortestSecretKey, &QAction::triggered, this,
+ &KeyPairOperaTab::slot_export_short_private_key);
+
+ secret_key_export_opera_menu_->addAction(exportFullSecretKey);
+ secret_key_export_opera_menu_->addAction(exportShortestSecretKey);
+}
+
+void KeyPairOperaTab::slot_export_public_key() {
+ ByteArrayPtr keyArray = nullptr;
+
+ if (!GpgKeyImportExporter::GetInstance().ExportKey(m_key_, keyArray)) {
+ QMessageBox::critical(this, _("Error"),
+ _("An error occurred during the export operation."));
+ return;
+ }
+
+ // generate a file name
+ auto file_string = m_key_.GetName() + "<" + m_key_.GetEmail() + ">(" +
+ m_key_.GetId() + ")_pub.asc";
+ std::replace(file_string.begin(), file_string.end(), ' ', '_');
+
+ auto file_name =
+ QFileDialog::getSaveFileName(
+ this, _("Export Key To File"), QString::fromStdString(file_string),
+ QString(_("Key Files")) + " (*.asc *.txt);;All Files (*)")
+ .toStdString();
+
+ if (file_name.empty()) return;
+
+ if (!write_buffer_to_file(file_name, *keyArray)) {
+ QMessageBox::critical(
+ this, _("Export Error"),
+ QString(_("Couldn't open %1 for writing")).arg(file_name.c_str()));
+ return;
+ }
+}
+
+void KeyPairOperaTab::slot_export_short_private_key() {
+ // Show a information box with explanation about private key
+ int ret = QMessageBox::information(
+ this, _("Exporting short private Key"),
+ "<h3>" + QString(_("You are about to export your")) +
+ "<font color=\"red\">" + _(" PRIVATE KEY ") + "</font>!</h3>\n" +
+ _("This is NOT your Public Key, so DON'T give it away.") + "<br />" +
+ _("Do you REALLY want to export your PRIVATE KEY in a Minimum "
+ "Size?") +
+ "<br />" +
+ _("For OpenPGP keys it removes all signatures except for the latest "
+ "self-signatures."),
+ QMessageBox::Cancel | QMessageBox::Ok);
+
+ // export key, if ok was clicked
+ if (ret == QMessageBox::Ok) {
+ ByteArrayPtr keyArray = nullptr;
+
+ if (!GpgKeyImportExporter::GetInstance().ExportSecretKeyShortest(
+ m_key_, keyArray)) {
+ QMessageBox::critical(
+ this, _("Error"),
+ _("An error occurred during the export operation."));
+ return;
+ }
+
+ auto file_string = m_key_.GetName() + "<" + m_key_.GetEmail() + ">(" +
+ m_key_.GetId() + ")_short_secret.asc";
+ std::replace(file_string.begin(), file_string.end(), ' ', '_');
+
+ auto file_name =
+ QFileDialog::getSaveFileName(
+ this, _("Export Key To File"), QString::fromStdString(file_string),
+ QString(_("Key Files")) + " (*.asc *.txt);;All Files (*)")
+ .toStdString();
+
+ if (file_name.empty()) return;
+
+ if (!write_buffer_to_file(file_name, *keyArray)) {
+ QMessageBox::critical(
+ this, _("Export Error"),
+ QString(_("Couldn't open %1 for writing")).arg(file_name.c_str()));
+ return;
+ }
+ }
+}
+
+void KeyPairOperaTab::slot_export_private_key() {
+ // Show a information box with explanation about private key
+ int ret = QMessageBox::information(
+ this, _("Exporting private Key"),
+ "<h3>" + QString(_("You are about to export your")) +
+ "<font color=\"red\">" + _(" PRIVATE KEY ") + "</font>!</h3>\n" +
+ _("This is NOT your Public Key, so DON'T give it away.") + "<br />" +
+ _("Do you REALLY want to export your PRIVATE KEY?"),
+ QMessageBox::Cancel | QMessageBox::Ok);
+
+ // export key, if ok was clicked
+ if (ret == QMessageBox::Ok) {
+ ByteArrayPtr keyArray = nullptr;
+
+ if (!GpgKeyImportExporter::GetInstance().ExportSecretKey(m_key_,
+ keyArray)) {
+ QMessageBox::critical(
+ this, _("Error"),
+ _("An error occurred during the export operation."));
+ return;
+ }
+ auto file_string = m_key_.GetName() + "<" + m_key_.GetEmail() + ">(" +
+ m_key_.GetId() + ")_full_secret.asc";
+ std::replace(file_string.begin(), file_string.end(), ' ', '_');
+
+ auto file_name =
+ QFileDialog::getSaveFileName(
+ this, _("Export Key To File"), QString::fromStdString(file_string),
+ QString(_("Key Files")) + " (*.asc *.txt);;All Files (*)")
+ .toStdString();
+
+ if (file_name.empty()) return;
+
+ if (!write_buffer_to_file(file_name, *keyArray)) {
+ QMessageBox::critical(
+ this, _("Export Error"),
+ QString(_("Couldn't open %1 for writing")).arg(file_name.c_str()));
+ return;
+ }
+ }
+}
+
+void KeyPairOperaTab::slot_modify_edit_datetime() {
+ auto dialog = new KeySetExpireDateDialog(m_key_.GetId(), this);
+ dialog->show();
+}
+
+void KeyPairOperaTab::slot_upload_key_to_server() {
+ auto keys = std::make_unique<KeyIdArgsList>();
+ keys->push_back(m_key_.GetId());
+ auto* dialog = new KeyUploadDialog(keys, this);
+ dialog->show();
+ dialog->SlotUpload();
+}
+
+void KeyPairOperaTab::slot_update_key_from_server() {
+ auto keys = std::make_unique<KeyIdArgsList>();
+ keys->push_back(m_key_.GetId());
+ auto* dialog = new KeyServerImportDialog(this);
+ dialog->show();
+ dialog->SlotImport(keys);
+}
+
+void KeyPairOperaTab::slot_gen_revoke_cert() {
+ auto literal = QString("%1 (*.rev)").arg(_("Revocation Certificates"));
+ QString m_output_file_name;
+
+ QFileDialog dialog(this, "Generate revocation certificate", QString(),
+ literal);
+ dialog.setDefaultSuffix(".rev");
+ dialog.setAcceptMode(QFileDialog::AcceptSave);
+
+ if (dialog.exec()) m_output_file_name = dialog.selectedFiles().front();
+
+ if (!m_output_file_name.isEmpty())
+ CommonUtils::GetInstance()->SlotExecuteGpgCommand(
+ {"--command-fd", "0", "--status-fd", "1", "--no-tty", "-o",
+ m_output_file_name, "--gen-revoke", m_key_.GetFingerprint().c_str()},
+ [](QProcess* proc) -> void {
+ // Code From Gpg4Win
+ while (proc->canReadLine()) {
+ const QString line = QString::fromUtf8(proc->readLine()).trimmed();
+ LOG(INFO) << "line" << line.toStdString();
+ if (line == QLatin1String("[GNUPG:] GET_BOOL gen_revoke.okay")) {
+ proc->write("y\n");
+ } else if (line == QLatin1String("[GNUPG:] GET_LINE "
+ "ask_revocation_reason.code")) {
+ proc->write("0\n");
+ } else if (line == QLatin1String("[GNUPG:] GET_LINE "
+ "ask_revocation_reason.text")) {
+ proc->write("\n");
+ } else if (line ==
+ QLatin1String(
+ "[GNUPG:] GET_BOOL openfile.overwrite.okay")) {
+ // We asked before
+ proc->write("y\n");
+ } else if (line == QLatin1String("[GNUPG:] GET_BOOL "
+ "ask_revocation_reason.okay")) {
+ proc->write("y\n");
+ }
+ }
+ });
+}
+
+void KeyPairOperaTab::slot_modify_password() {
+ auto err = GpgKeyOpera::GetInstance().ModifyPassword(m_key_);
+ if (check_gpg_error_2_err_code(err) != GPG_ERR_NO_ERROR) {
+ QMessageBox::critical(this, _("Not Successful"),
+ QString(_("Modify password not successfully.")));
+ }
+}
+
+void KeyPairOperaTab::slot_modify_tofu_policy() {
+ QStringList items;
+ items << _("Policy Auto") << _("Policy Good") << _("Policy Bad")
+ << _("Policy Ask") << _("Policy Unknown");
+
+ bool ok;
+ QString item = QInputDialog::getItem(
+ this, _("Modify TOFU Policy(Default is Auto)"),
+ _("Policy for the Key Pair:"), items, 0, false, &ok);
+ if (ok && !item.isEmpty()) {
+ LOG(INFO) << "selected policy" << item.toStdString();
+ gpgme_tofu_policy_t tofu_policy = GPGME_TOFU_POLICY_AUTO;
+ if (item == _("Policy Auto")) {
+ tofu_policy = GPGME_TOFU_POLICY_AUTO;
+ } else if (item == _("Policy Good")) {
+ tofu_policy = GPGME_TOFU_POLICY_GOOD;
+ } else if (item == _("Policy Bad")) {
+ tofu_policy = GPGME_TOFU_POLICY_BAD;
+ } else if (item == _("Policy Ask")) {
+ tofu_policy = GPGME_TOFU_POLICY_ASK;
+ } else if (item == _("Policy Unknown")) {
+ tofu_policy = GPGME_TOFU_POLICY_UNKNOWN;
+ }
+ auto err = GpgKeyOpera::GetInstance().ModifyTOFUPolicy(m_key_, tofu_policy);
+ if (check_gpg_error_2_err_code(err) != GPG_ERR_NO_ERROR) {
+ QMessageBox::critical(this, _("Not Successful"),
+ QString(_("Modify TOFU policy not successfully.")));
+ }
+ }
+}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/dialog/keypair_details/KeyPairOperaTab.h b/src/ui/dialog/keypair_details/KeyPairOperaTab.h
new file mode 100644
index 00000000..af6b1eee
--- /dev/null
+++ b/src/ui/dialog/keypair_details/KeyPairOperaTab.h
@@ -0,0 +1,113 @@
+/**
+ * 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 <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.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef GPGFRONTEND_KEYPAIROPERATAB_H
+#define GPGFRONTEND_KEYPAIROPERATAB_H
+
+#include "core/function/gpg/GpgKeyGetter.h"
+#include "ui/GpgFrontendUI.h"
+
+namespace GpgFrontend::UI {
+class KeyPairOperaTab : public QWidget {
+ Q_OBJECT
+ public:
+ /**
+ * @brief Construct a new Key Pair Opera Tab object
+ *
+ * @param key_id
+ * @param parent
+ */
+ KeyPairOperaTab(const std::string& key_id, QWidget* parent);
+
+ /**
+ * @brief Create a Opera Menu object
+ *
+ */
+ void CreateOperaMenu();
+
+ private slots:
+
+ /**
+ * @details Export the key to a file, which is chosen in a file dialog
+ */
+ void slot_export_private_key();
+
+ /**
+ * @brief
+ *
+ */
+ void slot_export_short_private_key();
+
+ /**
+ * @brief
+ *
+ */
+ void slot_export_public_key();
+
+ /**
+ * @brief
+ *
+ */
+ void slot_modify_edit_datetime();
+
+ /**
+ * @brief
+ *
+ */
+ void slot_modify_password();
+
+ /**
+ * @brief
+ *
+ */
+ void slot_upload_key_to_server();
+
+ /**
+ * @brief
+ *
+ */
+ void slot_update_key_from_server();
+
+ /**
+ * @brief
+ *
+ */
+ void slot_gen_revoke_cert();
+
+ /**
+ * @brief
+ *
+ */
+ void slot_modify_tofu_policy();
+
+ private:
+ GpgKey m_key_; ///<
+ QMenu* key_server_opera_menu_{}; ///<
+ QMenu* secret_key_export_opera_menu_{}; ///<
+};
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_KEYPAIROPERATAB_H
diff --git a/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp b/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp
new file mode 100644
index 00000000..fe1d0798
--- /dev/null
+++ b/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp
@@ -0,0 +1,338 @@
+/**
+ * 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 <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
+ *
+ */
+
+#include "KeyPairSubkeyTab.h"
+
+#include "core/function/gpg/GpgKeyGetter.h"
+#include "ui/SignalStation.h"
+
+namespace GpgFrontend::UI {
+
+KeyPairSubkeyTab::KeyPairSubkeyTab(const std::string& key_id, QWidget* parent)
+ : QWidget(parent), key_(GpgKeyGetter::GetInstance().GetKey(key_id)) {
+ LOG(INFO) << key_.GetEmail() << key_.IsPrivateKey() << key_.IsHasMasterKey()
+ << key_.GetSubKeys()->front().IsPrivateKey();
+
+ create_subkey_list();
+ create_subkey_opera_menu();
+
+ list_box_ = new QGroupBox(_("Subkey List"));
+ detail_box_ = new QGroupBox(_("Detail of Selected Subkey"));
+
+ auto uidButtonsLayout = new QGridLayout();
+
+ auto addSubkeyButton = new QPushButton(_("Generate A New Subkey"));
+ if (!key_.IsPrivateKey() || !key_.IsHasMasterKey()) {
+ addSubkeyButton->setDisabled(true);
+ setHidden(addSubkeyButton);
+ }
+
+ uidButtonsLayout->addWidget(addSubkeyButton, 0, 1);
+
+ auto* baseLayout = new QVBoxLayout();
+
+ auto subkeyListLayout = new QGridLayout();
+ subkeyListLayout->addWidget(subkey_list_, 0, 0);
+ subkeyListLayout->addLayout(uidButtonsLayout, 1, 0);
+ subkeyListLayout->setContentsMargins(0, 10, 0, 0);
+
+ auto* subkeyDetailLayout = new QGridLayout();
+
+ subkeyDetailLayout->addWidget(new QLabel(QString(_("Key ID")) + ": "), 0, 0);
+ subkeyDetailLayout->addWidget(new QLabel(QString(_("Algorithm")) + ": "), 1,
+ 0);
+ subkeyDetailLayout->addWidget(new QLabel(QString(_("Key Size")) + ": "), 2,
+ 0);
+ subkeyDetailLayout->addWidget(new QLabel(QString(_("Usage")) + ": "), 3, 0);
+ subkeyDetailLayout->addWidget(
+ new QLabel(QString(_("Expires On (Local Time)")) + ": "), 4, 0);
+ subkeyDetailLayout->addWidget(
+ new QLabel(QString(_("Create Date (Local Time)")) + ": "), 5, 0);
+ subkeyDetailLayout->addWidget(new QLabel(QString(_("Existence")) + ": "), 6,
+ 0);
+ subkeyDetailLayout->addWidget(
+ new QLabel(QString(_("Key in Smart Card")) + ": "), 7, 0);
+ subkeyDetailLayout->addWidget(new QLabel(QString(_("Fingerprint")) + ": "), 8,
+ 0);
+
+ key_id_var_label_ = new QLabel(this);
+ key_size_var_label_ = new QLabel(this);
+ expire_var_label_ = new QLabel(this);
+ algorithm_var_label_ = new QLabel(this);
+ created_var_label_ = new QLabel(this);
+ usage_var_label_ = new QLabel(this);
+ master_key_exist_var_label_ = new QLabel(this);
+ fingerprint_var_label_ = new QLabel(this);
+ card_key_label_ = new QLabel(this);
+
+ subkeyDetailLayout->addWidget(key_id_var_label_, 0, 1, 1, 1);
+ subkeyDetailLayout->addWidget(key_size_var_label_, 2, 1, 1, 2);
+ subkeyDetailLayout->addWidget(expire_var_label_, 4, 1, 1, 2);
+ subkeyDetailLayout->addWidget(algorithm_var_label_, 1, 1, 1, 2);
+ subkeyDetailLayout->addWidget(created_var_label_, 5, 1, 1, 2);
+ subkeyDetailLayout->addWidget(usage_var_label_, 3, 1, 1, 2);
+ subkeyDetailLayout->addWidget(master_key_exist_var_label_, 6, 1, 1, 2);
+ subkeyDetailLayout->addWidget(card_key_label_, 7, 1, 1, 2);
+ subkeyDetailLayout->addWidget(fingerprint_var_label_, 8, 1, 1, 2);
+
+ auto* copyKeyIdButton = new QPushButton(_("Copy"));
+ copyKeyIdButton->setFlat(true);
+ subkeyDetailLayout->addWidget(copyKeyIdButton, 0, 2);
+ connect(copyKeyIdButton, &QPushButton::clicked, this, [=]() {
+ QString fpr = key_id_var_label_->text().trimmed();
+ QClipboard* cb = QApplication::clipboard();
+ cb->setText(fpr);
+ });
+
+ list_box_->setLayout(subkeyListLayout);
+ list_box_->setContentsMargins(0, 12, 0, 0);
+ detail_box_->setLayout(subkeyDetailLayout);
+
+ baseLayout->addWidget(list_box_);
+ baseLayout->addWidget(detail_box_);
+ baseLayout->addStretch();
+
+ connect(addSubkeyButton, &QPushButton::clicked, this,
+ &KeyPairSubkeyTab::slot_add_subkey);
+ connect(subkey_list_, &QTableWidget::itemSelectionChanged, this,
+ &KeyPairSubkeyTab::slot_refresh_subkey_detail);
+
+ // key database refresh signal
+ connect(SignalStation::GetInstance(),
+ &SignalStation::SignalKeyDatabaseRefreshDone, this,
+ &KeyPairSubkeyTab::slot_refresh_key_info);
+ connect(SignalStation::GetInstance(),
+ &SignalStation::SignalKeyDatabaseRefreshDone, this,
+ &KeyPairSubkeyTab::slot_refresh_subkey_list);
+
+ baseLayout->setContentsMargins(0, 0, 0, 0);
+
+ setLayout(baseLayout);
+ setAttribute(Qt::WA_DeleteOnClose, true);
+
+ slot_refresh_subkey_list();
+}
+
+void KeyPairSubkeyTab::create_subkey_list() {
+ subkey_list_ = new QTableWidget(this);
+
+ subkey_list_->setColumnCount(5);
+ subkey_list_->horizontalHeader()->setSectionResizeMode(
+ QHeaderView::ResizeToContents);
+ subkey_list_->verticalHeader()->hide();
+ subkey_list_->setShowGrid(false);
+ subkey_list_->setSelectionBehavior(QAbstractItemView::SelectRows);
+
+ // tableitems not editable
+ subkey_list_->setEditTriggers(QAbstractItemView::NoEditTriggers);
+
+ // no focus (rectangle around tableitems)
+ // may be it should focus on whole row
+ subkey_list_->setFocusPolicy(Qt::NoFocus);
+ subkey_list_->setAlternatingRowColors(true);
+
+ QStringList labels;
+ labels << _("Subkey ID") << _("Key Size") << _("Algo")
+ << _("Create Date (UTC)") << _("Expire Date (UTC)");
+
+ subkey_list_->setHorizontalHeaderLabels(labels);
+ subkey_list_->horizontalHeader()->setStretchLastSection(false);
+}
+
+void KeyPairSubkeyTab::slot_refresh_subkey_list() {
+ LOG(INFO) << "Called";
+ int row = 0;
+
+ subkey_list_->setSelectionMode(QAbstractItemView::SingleSelection);
+
+ this->buffered_subkeys_.clear();
+ auto sub_keys = key_.GetSubKeys();
+ for (auto& sub_key : *sub_keys) {
+ if (sub_key.IsDisabled() || sub_key.IsRevoked()) continue;
+ this->buffered_subkeys_.push_back(std::move(sub_key));
+ }
+
+ subkey_list_->setRowCount(buffered_subkeys_.size());
+
+ for (const auto& subkeys : buffered_subkeys_) {
+ auto* tmp0 = new QTableWidgetItem(QString::fromStdString(subkeys.GetID()));
+ tmp0->setTextAlignment(Qt::AlignCenter);
+ subkey_list_->setItem(row, 0, tmp0);
+
+ auto* tmp1 = new QTableWidgetItem(QString::number(subkeys.GetKeyLength()));
+ tmp1->setTextAlignment(Qt::AlignCenter);
+ subkey_list_->setItem(row, 1, tmp1);
+
+ auto* tmp2 =
+ new QTableWidgetItem(QString::fromStdString(subkeys.GetPubkeyAlgo()));
+ tmp2->setTextAlignment(Qt::AlignCenter);
+ subkey_list_->setItem(row, 2, tmp2);
+
+ auto* tmp3 = new QTableWidgetItem(
+ QString::fromStdString(to_iso_string(subkeys.GetCreateTime())));
+ tmp3->setTextAlignment(Qt::AlignCenter);
+ subkey_list_->setItem(row, 3, tmp3);
+
+ auto* tmp4 = new QTableWidgetItem(
+ boost::posix_time::to_time_t(
+ boost::posix_time::ptime(subkeys.GetExpireTime())) == 0
+ ? _("Never Expire")
+ : QString::fromStdString(to_iso_string(subkeys.GetExpireTime())));
+ tmp4->setTextAlignment(Qt::AlignCenter);
+ subkey_list_->setItem(row, 4, tmp4);
+
+ if (!row) {
+ for (auto i = 0; i < subkey_list_->columnCount(); i++) {
+ subkey_list_->item(row, i)->setForeground(QColor(65, 105, 255));
+ }
+ }
+
+ row++;
+ }
+
+ if (subkey_list_->rowCount() > 0) {
+ subkey_list_->selectRow(0);
+ }
+}
+
+void KeyPairSubkeyTab::slot_add_subkey() {
+ auto dialog = new SubkeyGenerateDialog(key_.GetId(), this);
+ dialog->show();
+}
+
+void KeyPairSubkeyTab::slot_refresh_subkey_detail() {
+ auto& subkey = get_selected_subkey();
+
+ key_id_var_label_->setText(QString::fromStdString(subkey.GetID()));
+ key_size_var_label_->setText(QString::number(subkey.GetKeyLength()));
+
+ time_t subkey_time_t = boost::posix_time::to_time_t(
+ boost::posix_time::ptime(subkey.GetExpireTime()));
+
+ expire_var_label_->setText(
+ subkey_time_t == 0 ? _("Never Expires")
+ : QLocale::system().toString(QDateTime::fromTime_t(
+ to_time_t(subkey.GetExpireTime()))));
+ if (subkey_time_t != 0 &&
+ subkey.GetExpireTime() < boost::posix_time::second_clock::local_time()) {
+ auto paletteExpired = expire_var_label_->palette();
+ paletteExpired.setColor(expire_var_label_->foregroundRole(), Qt::red);
+ expire_var_label_->setPalette(paletteExpired);
+ } else {
+ auto paletteValid = expire_var_label_->palette();
+ paletteValid.setColor(expire_var_label_->foregroundRole(), Qt::darkGreen);
+ expire_var_label_->setPalette(paletteValid);
+ }
+
+ algorithm_var_label_->setText(QString::fromStdString(subkey.GetPubkeyAlgo()));
+ created_var_label_->setText(QLocale::system().toString(
+ QDateTime::fromTime_t(to_time_t(subkey.GetCreateTime()))));
+
+ std::stringstream usage_steam;
+
+ if (subkey.IsHasCertificationCapability())
+ usage_steam << _("Certificate") << " ";
+ if (subkey.IsHasEncryptionCapability()) usage_steam << _("Encrypt") << " ";
+ if (subkey.IsHasSigningCapability()) usage_steam << _("Sign") << " ";
+ if (subkey.IsHasAuthenticationCapability()) usage_steam << _("Auth") << " ";
+
+ usage_var_label_->setText(usage_steam.str().c_str());
+
+ // Show the situation that secret key not exists.
+ master_key_exist_var_label_->setText(subkey.IsSecretKey() ? _("Exists")
+ : _("Not Exists"));
+
+ // Show the situation if key in a smart card.
+ card_key_label_->setText(subkey.IsCardKey() ? _("Yes") : _("No"));
+
+ if (!subkey.IsSecretKey()) {
+ auto palette_expired = master_key_exist_var_label_->palette();
+ palette_expired.setColor(master_key_exist_var_label_->foregroundRole(),
+ Qt::red);
+ master_key_exist_var_label_->setPalette(palette_expired);
+ } else {
+ auto palette_valid = master_key_exist_var_label_->palette();
+ palette_valid.setColor(master_key_exist_var_label_->foregroundRole(),
+ Qt::darkGreen);
+ master_key_exist_var_label_->setPalette(palette_valid);
+ }
+
+ if (!subkey.IsCardKey()) {
+ auto palette_expired = card_key_label_->palette();
+ palette_expired.setColor(card_key_label_->foregroundRole(), Qt::red);
+ card_key_label_->setPalette(palette_expired);
+ } else {
+ auto palette_valid = card_key_label_->palette();
+ palette_valid.setColor(card_key_label_->foregroundRole(), Qt::darkGreen);
+ card_key_label_->setPalette(palette_valid);
+ }
+
+ fingerprint_var_label_->setText(
+ QString::fromStdString(subkey.GetFingerprint()));
+}
+
+void KeyPairSubkeyTab::create_subkey_opera_menu() {
+ subkey_opera_menu_ = new QMenu(this);
+ auto* editSubkeyAct = new QAction(_("Edit Expire Date"));
+ connect(editSubkeyAct, &QAction::triggered, this,
+ &KeyPairSubkeyTab::slot_edit_subkey);
+
+ subkey_opera_menu_->addAction(editSubkeyAct);
+}
+
+void KeyPairSubkeyTab::slot_edit_subkey() {
+ LOG(INFO) << "Fpr" << get_selected_subkey().GetFingerprint();
+
+ auto dialog = new KeySetExpireDateDialog(
+ key_.GetId(), get_selected_subkey().GetFingerprint(), this);
+ dialog->show();
+}
+
+void KeyPairSubkeyTab::slot_revoke_subkey() {}
+
+void KeyPairSubkeyTab::contextMenuEvent(QContextMenuEvent* event) {
+ if (!subkey_list_->selectedItems().isEmpty()) {
+ subkey_opera_menu_->exec(event->globalPos());
+ }
+}
+
+const GpgSubKey& KeyPairSubkeyTab::get_selected_subkey() {
+ int row = 0;
+
+ for (int i = 0; i < subkey_list_->rowCount(); i++) {
+ if (subkey_list_->item(row, 0)->isSelected()) break;
+ row++;
+ }
+
+ return buffered_subkeys_[row];
+}
+void KeyPairSubkeyTab::slot_refresh_key_info() {
+ key_ = GpgKeyGetter::GetInstance().GetKey(key_.GetId());
+}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/dialog/keypair_details/KeyPairSubkeyTab.h b/src/ui/dialog/keypair_details/KeyPairSubkeyTab.h
new file mode 100644
index 00000000..a93ebca5
--- /dev/null
+++ b/src/ui/dialog/keypair_details/KeyPairSubkeyTab.h
@@ -0,0 +1,139 @@
+/**
+ * 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 <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
+ *
+ */
+
+#ifndef GPGFRONTEND_KEYPAIRSUBKEYTAB_H
+#define GPGFRONTEND_KEYPAIRSUBKEYTAB_H
+
+#include "KeySetExpireDateDialog.h"
+#include "core/GpgContext.h"
+#include "ui/GpgFrontendUI.h"
+#include "ui/dialog/key_generate/SubkeyGenerateDialog.h"
+
+namespace GpgFrontend::UI {
+
+class KeyPairSubkeyTab : public QWidget {
+ Q_OBJECT
+
+ public:
+ /**
+ * @brief Construct a new Key Pair Subkey Tab object
+ *
+ * @param key
+ * @param parent
+ */
+ KeyPairSubkeyTab(const std::string& key, QWidget* parent);
+
+ private:
+ /**
+ * @brief Create a subkey list object
+ *
+ */
+ void create_subkey_list();
+
+ /**
+ * @brief Create a subkey opera menu object
+ *
+ */
+ void create_subkey_opera_menu();
+
+ /**
+ * @brief Get the selected subkey object
+ *
+ * @return const GpgSubKey&
+ */
+ const GpgSubKey& get_selected_subkey();
+
+ GpgKey key_; ///<
+ QTableWidget* subkey_list_{}; ///<
+ std::vector<GpgSubKey> buffered_subkeys_; ///<
+
+ QGroupBox* list_box_; ///<
+ QGroupBox* detail_box_; ///<
+
+ QMenu* subkey_opera_menu_{}; ///<
+
+ QLabel* key_size_var_label_; ///< Label containing the keys key size
+ QLabel* expire_var_label_; ///< Label containing the keys expiration date
+ QLabel* created_var_label_; ///< Label containing the keys creation date
+ QLabel* algorithm_var_label_; ///< Label containing the keys algorithm
+ QLabel* key_id_var_label_; ///< Label containing the keys keyid
+ QLabel* fingerprint_var_label_; ///< Label containing the keys fingerprint
+ QLabel* usage_var_label_; ///<
+ QLabel* master_key_exist_var_label_; ///<
+ QLabel* card_key_label_; ///<
+
+ private slots:
+
+ /**
+ * @brief
+ *
+ */
+ void slot_add_subkey();
+
+ /**
+ * @brief
+ *
+ */
+ void slot_refresh_subkey_list();
+
+ /**
+ * @brief
+ *
+ */
+ void slot_refresh_subkey_detail();
+
+ /**
+ * @brief
+ *
+ */
+ void slot_edit_subkey();
+
+ /**
+ * @brief
+ *
+ */
+ void slot_revoke_subkey();
+
+ /**
+ * @brief
+ *
+ */
+ void slot_refresh_key_info();
+
+ protected:
+ /**
+ * @brief
+ *
+ * @param event
+ */
+ void contextMenuEvent(QContextMenuEvent* event) override;
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_KEYPAIRSUBKEYTAB_H
diff --git a/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp b/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp
new file mode 100644
index 00000000..b923dbec
--- /dev/null
+++ b/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp
@@ -0,0 +1,583 @@
+/**
+ * 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 <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.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "KeyPairUIDTab.h"
+
+#include "core/function/gpg/GpgKeyGetter.h"
+#include "core/function/gpg/GpgKeyManager.h"
+#include "core/function/gpg/GpgUIDOperator.h"
+#include "ui/SignalStation.h"
+#include "ui/widgets/TOFUInfoPage.h"
+
+namespace GpgFrontend::UI {
+
+KeyPairUIDTab::KeyPairUIDTab(const std::string& key_id, QWidget* parent)
+ : QWidget(parent), m_key_(GpgKeyGetter::GetInstance().GetKey(key_id)) {
+ create_uid_list();
+ create_sign_list();
+ create_manage_uid_menu();
+ create_uid_popup_menu();
+ create_sign_popup_menu();
+
+ auto uidButtonsLayout = new QGridLayout();
+
+ auto addUIDButton = new QPushButton(_("New UID"));
+ auto manageUIDButton = new QPushButton(_("UID Management"));
+
+ if (m_key_.IsHasMasterKey()) {
+ manageUIDButton->setMenu(manage_selected_uid_menu_);
+ } else {
+ manageUIDButton->setDisabled(true);
+ }
+
+ uidButtonsLayout->addWidget(addUIDButton, 0, 1);
+ uidButtonsLayout->addWidget(manageUIDButton, 0, 2);
+
+ auto grid_layout = new QGridLayout();
+
+ grid_layout->addWidget(uid_list_, 0, 0);
+ grid_layout->addLayout(uidButtonsLayout, 1, 0);
+ grid_layout->setContentsMargins(0, 10, 0, 0);
+
+ auto uid_group_box = new QGroupBox();
+ uid_group_box->setLayout(grid_layout);
+ uid_group_box->setTitle(_("UIDs"));
+
+ auto tofu_group_box = new QGroupBox();
+ auto tofu_vbox_layout = new QVBoxLayout();
+ tofu_group_box->setLayout(tofu_vbox_layout);
+ tofu_group_box->setTitle(_("TOFU"));
+#if !defined(RELEASE)
+ tofu_tabs_ = new QTabWidget(this);
+ tofu_vbox_layout->addWidget(tofu_tabs_);
+#endif
+
+ auto sign_grid_layout = new QGridLayout();
+ sign_grid_layout->addWidget(sig_list_, 0, 0);
+ sign_grid_layout->setContentsMargins(0, 10, 0, 0);
+
+ auto sign_group_box = new QGroupBox();
+ sign_group_box->setLayout(sign_grid_layout);
+ sign_group_box->setTitle(_("Signature of Selected UID"));
+
+ auto vboxLayout = new QVBoxLayout();
+ vboxLayout->addWidget(uid_group_box);
+#if !defined(RELEASE)
+ // Function needed testing
+ vboxLayout->addWidget(tofu_group_box);
+#endif
+ vboxLayout->addWidget(sign_group_box);
+
+ vboxLayout->setContentsMargins(0, 0, 0, 0);
+
+ connect(addUIDButton, &QPushButton::clicked, this,
+ &KeyPairUIDTab::slot_add_uid);
+ connect(uid_list_, &QTableWidget::itemSelectionChanged, this,
+ &KeyPairUIDTab::slot_refresh_tofu_info);
+ connect(uid_list_, &QTableWidget::itemSelectionChanged, this,
+ &KeyPairUIDTab::slot_refresh_sig_list);
+
+ // Key Database Refresh
+ connect(SignalStation::GetInstance(),
+ &SignalStation::SignalKeyDatabaseRefreshDone, this,
+ &KeyPairUIDTab::slot_refresh_key);
+
+ connect(this, &KeyPairUIDTab::SignalUpdateUIDInfo,
+ SignalStation::GetInstance(),
+ &SignalStation::SignalKeyDatabaseRefresh);
+
+ setLayout(vboxLayout);
+ setAttribute(Qt::WA_DeleteOnClose, true);
+
+ slot_refresh_uid_list();
+}
+
+void KeyPairUIDTab::create_uid_list() {
+ uid_list_ = new QTableWidget(this);
+ uid_list_->setColumnCount(4);
+ uid_list_->horizontalHeader()->setSectionResizeMode(
+ QHeaderView::ResizeToContents);
+ uid_list_->verticalHeader()->hide();
+ uid_list_->setShowGrid(false);
+ uid_list_->setSelectionBehavior(QAbstractItemView::SelectRows);
+ uid_list_->setSelectionMode(QAbstractItemView::SingleSelection);
+
+ // tableitems not editable
+ uid_list_->setEditTriggers(QAbstractItemView::NoEditTriggers);
+
+ // no focus (rectangle around tableitems)
+ // may be it should focus on whole row
+ uid_list_->setFocusPolicy(Qt::NoFocus);
+ uid_list_->setAlternatingRowColors(true);
+
+ QStringList labels;
+ labels << _("Select") << _("Name") << _("Email") << _("Comment");
+ uid_list_->setHorizontalHeaderLabels(labels);
+ uid_list_->horizontalHeader()->setStretchLastSection(true);
+}
+
+void KeyPairUIDTab::create_sign_list() {
+ sig_list_ = new QTableWidget(this);
+ sig_list_->setColumnCount(5);
+ sig_list_->horizontalHeader()->setSectionResizeMode(
+ QHeaderView::ResizeToContents);
+ sig_list_->verticalHeader()->hide();
+ sig_list_->setShowGrid(false);
+ sig_list_->setSelectionBehavior(QAbstractItemView::SelectRows);
+
+ // table items not editable
+ sig_list_->setEditTriggers(QAbstractItemView::NoEditTriggers);
+
+ // no focus (rectangle around table items)
+ // may be it should focus on whole row
+ sig_list_->setFocusPolicy(Qt::NoFocus);
+ sig_list_->setAlternatingRowColors(true);
+
+ QStringList labels;
+ labels << _("Key ID") << _("Name") << _("Email") << _("Create Date (UTC)")
+ << _("Expired Date (UTC)");
+ sig_list_->setHorizontalHeaderLabels(labels);
+ sig_list_->horizontalHeader()->setStretchLastSection(false);
+}
+
+void KeyPairUIDTab::slot_refresh_uid_list() {
+ int row = 0;
+
+ uid_list_->setSelectionMode(QAbstractItemView::SingleSelection);
+
+ this->buffered_uids_.clear();
+
+ auto uids = m_key_.GetUIDs();
+ for (auto& uid : *uids) {
+ if (uid.GetInvalid() || uid.GetRevoked()) {
+ continue;
+ }
+ this->buffered_uids_.push_back(std::move(uid));
+ }
+
+ uid_list_->setRowCount(buffered_uids_.size());
+
+ for (const auto& uid : buffered_uids_) {
+ auto* tmp0 = new QTableWidgetItem(QString::fromStdString(uid.GetUID()));
+ uid_list_->setItem(row, 1, tmp0);
+
+ auto* tmp1 = new QTableWidgetItem(QString::fromStdString(uid.GetUID()));
+ uid_list_->setItem(row, 2, tmp1);
+
+ auto* tmp2 = new QTableWidgetItem(QString::fromStdString(uid.GetUID()));
+ uid_list_->setItem(row, 3, tmp2);
+
+ auto* tmp3 = new QTableWidgetItem(QString::number(row));
+ tmp3->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled |
+ Qt::ItemIsSelectable);
+ tmp3->setTextAlignment(Qt::AlignCenter);
+ tmp3->setCheckState(Qt::Unchecked);
+ uid_list_->setItem(row, 0, tmp3);
+
+ if (!row) {
+ for (auto i = 0; i < uid_list_->columnCount(); i++) {
+ uid_list_->item(row, i)->setForeground(QColor(65, 105, 255));
+ }
+ }
+
+ row++;
+ }
+
+ if (uid_list_->rowCount() > 0) {
+ uid_list_->selectRow(0);
+ }
+
+ slot_refresh_sig_list();
+ slot_refresh_tofu_info();
+}
+
+void KeyPairUIDTab::slot_refresh_tofu_info() {
+ if (this->tofu_tabs_ == nullptr) return;
+
+ int uidRow = 0;
+ tofu_tabs_->clear();
+ for (const auto& uid : buffered_uids_) {
+ // Only Show Selected UID Signatures
+ if (!uid_list_->item(uidRow++, 0)->isSelected()) {
+ continue;
+ }
+ auto tofu_infos = uid.GetTofuInfos();
+ LOG(INFO) << "tofu info size" << tofu_infos->size();
+ if (tofu_infos->empty()) {
+ tofu_tabs_->hide();
+ } else {
+ tofu_tabs_->show();
+ }
+ int index = 1;
+ for (const auto& tofu_info : *tofu_infos) {
+ tofu_tabs_->addTab(new TOFUInfoPage(tofu_info, this),
+ QString(_("TOFU %1")).arg(index++));
+ }
+ }
+}
+
+void KeyPairUIDTab::slot_refresh_sig_list() {
+ int uidRow = 0, sigRow = 0;
+ for (const auto& uid : buffered_uids_) {
+ // Only Show Selected UID Signatures
+ if (!uid_list_->item(uidRow++, 0)->isSelected()) {
+ continue;
+ }
+
+ buffered_signatures_.clear();
+ auto signatures = uid.GetSignatures();
+ for (auto& sig : *signatures) {
+ if (sig.IsInvalid() || sig.IsRevoked()) {
+ continue;
+ }
+ buffered_signatures_.push_back(std::move(sig));
+ }
+
+ sig_list_->setRowCount(buffered_signatures_.size());
+
+ for (const auto& sig : buffered_signatures_) {
+ auto* tmp0 = new QTableWidgetItem(QString::fromStdString(sig.GetKeyID()));
+ sig_list_->setItem(sigRow, 0, tmp0);
+
+ if (gpgme_err_code(sig.GetStatus()) == GPG_ERR_NO_PUBKEY) {
+ auto* tmp2 = new QTableWidgetItem("<Unknown>");
+ sig_list_->setItem(sigRow, 1, tmp2);
+
+ auto* tmp3 = new QTableWidgetItem("<Unknown>");
+ sig_list_->setItem(sigRow, 2, tmp3);
+ } else {
+ auto* tmp2 =
+ new QTableWidgetItem(QString::fromStdString(sig.GetName()));
+ sig_list_->setItem(sigRow, 1, tmp2);
+
+ auto* tmp3 =
+ new QTableWidgetItem(QString::fromStdString(sig.GetEmail()));
+ sig_list_->setItem(sigRow, 2, tmp3);
+ }
+
+ auto* tmp4 = new QTableWidgetItem(QLocale::system().toString(
+ QDateTime::fromTime_t(to_time_t(sig.GetCreateTime()))));
+ sig_list_->setItem(sigRow, 3, tmp4);
+
+ auto* tmp5 = new QTableWidgetItem(
+ boost::posix_time::to_time_t(
+ boost::posix_time::ptime(sig.GetExpireTime())) == 0
+ ? _("Never Expires")
+ : QLocale::system().toString(
+ QDateTime::fromTime_t(to_time_t(sig.GetExpireTime()))));
+ tmp5->setTextAlignment(Qt::AlignCenter);
+ sig_list_->setItem(sigRow, 4, tmp5);
+
+ sigRow++;
+ }
+
+ break;
+ }
+}
+
+void KeyPairUIDTab::slot_add_sign() {
+ auto selected_uids = get_uid_checked();
+
+ if (selected_uids->empty()) {
+ QMessageBox::information(
+ nullptr, _("Invalid Operation"),
+ _("Please select one or more UIDs before doing this operation."));
+ return;
+ }
+
+ auto keySignDialog =
+ new KeyUIDSignDialog(m_key_, std::move(selected_uids), this);
+ keySignDialog->show();
+}
+
+UIDArgsListPtr KeyPairUIDTab::get_uid_checked() {
+ auto selected_uids = std::make_unique<UIDArgsList>();
+ for (int i = 0; i < uid_list_->rowCount(); i++) {
+ if (uid_list_->item(i, 0)->checkState() == Qt::Checked)
+ selected_uids->push_back(buffered_uids_[i].GetUID());
+ }
+ return selected_uids;
+}
+
+void KeyPairUIDTab::create_manage_uid_menu() {
+ manage_selected_uid_menu_ = new QMenu(this);
+
+ auto* signUIDAct = new QAction(_("Sign Selected UID(s)"), this);
+ connect(signUIDAct, &QAction::triggered, this, &KeyPairUIDTab::slot_add_sign);
+ auto* delUIDAct = new QAction(_("Delete Selected UID(s)"), this);
+ connect(delUIDAct, &QAction::triggered, this, &KeyPairUIDTab::slot_del_uid);
+
+ if (m_key_.IsHasMasterKey()) {
+ manage_selected_uid_menu_->addAction(signUIDAct);
+ manage_selected_uid_menu_->addAction(delUIDAct);
+ }
+}
+
+void KeyPairUIDTab::slot_add_uid() {
+ auto keyNewUIDDialog = new KeyNewUIDDialog(m_key_.GetId(), this);
+ connect(keyNewUIDDialog, &KeyNewUIDDialog::finished, this,
+ &KeyPairUIDTab::slot_add_uid_result);
+ connect(keyNewUIDDialog, &KeyNewUIDDialog::finished, keyNewUIDDialog,
+ &KeyPairUIDTab::deleteLater);
+ keyNewUIDDialog->show();
+}
+
+void KeyPairUIDTab::slot_add_uid_result(int result) {
+ if (result == 1) {
+ QMessageBox::information(nullptr, _("Successful Operation"),
+ _("Successfully added a new UID."));
+ } else if (result == -1) {
+ QMessageBox::critical(nullptr, _("Operation Failed"),
+ _("An error occurred during the operation."));
+ }
+}
+
+void KeyPairUIDTab::slot_del_uid() {
+ auto selected_uids = get_uid_checked();
+
+ if (selected_uids->empty()) {
+ QMessageBox::information(
+ nullptr, _("Invalid Operation"),
+ _("Please select one or more UIDs before doing this operation."));
+ return;
+ }
+
+ QString keynames;
+ for (auto& uid : *selected_uids) {
+ keynames.append(QString::fromStdString(uid));
+ keynames.append("<br/>");
+ }
+
+ int ret = QMessageBox::warning(
+ this, _("Deleting UIDs"),
+ "<b>" +
+ QString(
+ _("Are you sure that you want to delete the following UIDs?")) +
+ "</b><br/><br/>" + keynames + +"<br/>" +
+ _("The action can not be undone."),
+ QMessageBox::No | QMessageBox::Yes);
+
+ if (ret == QMessageBox::Yes) {
+ for (const auto& uid : *selected_uids) {
+ LOG(INFO) << "KeyPairUIDTab::slot_del_uid UID" << uid;
+ if (!GpgUIDOperator::GetInstance().RevUID(m_key_, uid)) {
+ QMessageBox::critical(
+ nullptr, _("Operation Failed"),
+ QString(_("An error occurred during the delete %1 operation."))
+ .arg(uid.c_str()));
+ }
+ }
+ emit SignalUpdateUIDInfo();
+ }
+}
+
+void KeyPairUIDTab::slot_set_primary_uid() {
+ auto selected_uids = get_uid_selected();
+
+ if (selected_uids->empty()) {
+ auto emptyUIDMsg = new QMessageBox();
+ emptyUIDMsg->setText("Please select one UID before doing this operation.");
+ emptyUIDMsg->exec();
+ return;
+ }
+
+ QString keynames;
+
+ keynames.append(QString::fromStdString(selected_uids->front()));
+ keynames.append("<br/>");
+
+ int ret = QMessageBox::warning(
+ this, _("Set Primary UID"),
+ "<b>" +
+ QString(_("Are you sure that you want to set the Primary UID to?")) +
+ "</b><br/><br/>" + keynames + +"<br/>" +
+ _("The action can not be undone."),
+ QMessageBox::No | QMessageBox::Yes);
+
+ if (ret == QMessageBox::Yes) {
+ if (!GpgUIDOperator::GetInstance().SetPrimaryUID(m_key_,
+ selected_uids->front())) {
+ QMessageBox::critical(nullptr, _("Operation Failed"),
+ _("An error occurred during the operation."));
+ } else {
+ emit SignalUpdateUIDInfo();
+ }
+ }
+}
+
+UIDArgsListPtr KeyPairUIDTab::get_uid_selected() {
+ auto uids = std::make_unique<UIDArgsList>();
+ for (int i = 0; i < uid_list_->rowCount(); i++) {
+ if (uid_list_->item(i, 0)->isSelected()) {
+ uids->push_back(buffered_uids_[i].GetUID());
+ }
+ }
+ return uids;
+}
+
+SignIdArgsListPtr KeyPairUIDTab::get_sign_selected() {
+ auto signatures = std::make_unique<SignIdArgsList>();
+ for (int i = 0; i < sig_list_->rowCount(); i++) {
+ if (sig_list_->item(i, 0)->isSelected()) {
+ auto& sign = buffered_signatures_[i];
+ signatures->push_back({sign.GetKeyID(), sign.GetUID()});
+ }
+ }
+ return signatures;
+}
+
+void KeyPairUIDTab::create_uid_popup_menu() {
+ uid_popup_menu_ = new QMenu(this);
+
+ auto* serPrimaryUIDAct = new QAction(_("Set As Primary"), this);
+ connect(serPrimaryUIDAct, &QAction::triggered, this,
+ &KeyPairUIDTab::slot_set_primary_uid);
+ auto* signUIDAct = new QAction(_("Sign UID"), this);
+ connect(signUIDAct, &QAction::triggered, this,
+ &KeyPairUIDTab::slot_add_sign_single);
+ auto* delUIDAct = new QAction(_("Delete UID"), this);
+ connect(delUIDAct, &QAction::triggered, this,
+ &KeyPairUIDTab::slot_del_uid_single);
+
+ if (m_key_.IsHasMasterKey()) {
+ uid_popup_menu_->addAction(serPrimaryUIDAct);
+ uid_popup_menu_->addAction(signUIDAct);
+ uid_popup_menu_->addAction(delUIDAct);
+ }
+}
+
+void KeyPairUIDTab::contextMenuEvent(QContextMenuEvent* event) {
+ if (uid_list_->selectedItems().length() > 0 &&
+ sig_list_->selectedItems().isEmpty()) {
+ uid_popup_menu_->exec(event->globalPos());
+ }
+}
+
+void KeyPairUIDTab::slot_add_sign_single() {
+ auto selected_uids = get_uid_selected();
+
+ if (selected_uids->empty()) {
+ QMessageBox::information(
+ nullptr, _("Invalid Operation"),
+ _("Please select one UID before doing this operation."));
+ return;
+ }
+
+ auto keySignDialog =
+ new KeyUIDSignDialog(m_key_, std::move(selected_uids), this);
+ keySignDialog->show();
+}
+
+void KeyPairUIDTab::slot_del_uid_single() {
+ auto selected_uids = get_uid_selected();
+ if (selected_uids->empty()) {
+ QMessageBox::information(
+ nullptr, _("Invalid Operation"),
+ _("Please select one UID before doing this operation."));
+ return;
+ }
+
+ QString keynames;
+
+ keynames.append(QString::fromStdString(selected_uids->front()));
+ keynames.append("<br/>");
+
+ int ret = QMessageBox::warning(
+ this, _("Deleting UID"),
+ "<b>" +
+ QString(
+ _("Are you sure that you want to delete the following uid?")) +
+ "</b><br/><br/>" + keynames + +"<br/>" +
+ _("The action can not be undone."),
+ QMessageBox::No | QMessageBox::Yes);
+
+ if (ret == QMessageBox::Yes) {
+ if (!GpgUIDOperator::GetInstance().RevUID(m_key_, selected_uids->front())) {
+ QMessageBox::critical(nullptr, _("Operation Failed"),
+ _("An error occurred during the operation."));
+ } else {
+ emit SignalUpdateUIDInfo();
+ }
+ }
+}
+
+void KeyPairUIDTab::create_sign_popup_menu() {
+ sign_popup_menu_ = new QMenu(this);
+
+ auto* delSignAct = new QAction(_("Delete(Revoke) Key Signature"), this);
+ connect(delSignAct, &QAction::triggered, this, &KeyPairUIDTab::slot_del_sign);
+
+ sign_popup_menu_->addAction(delSignAct);
+}
+
+void KeyPairUIDTab::slot_del_sign() {
+ auto selected_signs = get_sign_selected();
+ if (selected_signs->empty()) {
+ QMessageBox::information(
+ nullptr, _("Invalid Operation"),
+ _("Please select one Key Signature before doing this operation."));
+ return;
+ }
+
+ if (!GpgKeyGetter::GetInstance()
+ .GetKey(selected_signs->front().first)
+ .IsGood()) {
+ QMessageBox::critical(
+ nullptr, _("Invalid Operation"),
+ _("To delete the signature, you need to have its corresponding public "
+ "key in the local database."));
+ return;
+ }
+
+ QString keynames;
+
+ keynames.append(QString::fromStdString(selected_signs->front().second));
+ keynames.append("<br/>");
+
+ int ret =
+ QMessageBox::warning(this, _("Deleting Key Signature"),
+ "<b>" +
+ QString(_("Are you sure that you want to delete "
+ "the following signature?")) +
+ "</b><br/><br/>" + keynames + +"<br/>" +
+ _("The action can not be undone."),
+ QMessageBox::No | QMessageBox::Yes);
+
+ if (ret == QMessageBox::Yes) {
+ if (!GpgKeyManager::GetInstance().RevSign(m_key_, selected_signs)) {
+ QMessageBox::critical(nullptr, _("Operation Failed"),
+ _("An error occurred during the operation."));
+ }
+ }
+}
+void KeyPairUIDTab::slot_refresh_key() {
+ this->m_key_ = GpgKeyGetter::GetInstance().GetKey(this->m_key_.GetId());
+ this->slot_refresh_uid_list();
+ this->slot_refresh_tofu_info();
+ this->slot_refresh_sig_list();
+}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/dialog/keypair_details/KeyPairUIDTab.h b/src/ui/dialog/keypair_details/KeyPairUIDTab.h
new file mode 100644
index 00000000..fae8f9f2
--- /dev/null
+++ b/src/ui/dialog/keypair_details/KeyPairUIDTab.h
@@ -0,0 +1,207 @@
+/**
+ * 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 <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
+ *
+ */
+
+#ifndef GPGFRONTEND_KEYPAIRUIDTAB_H
+#define GPGFRONTEND_KEYPAIRUIDTAB_H
+
+#include "KeyNewUIDDialog.h"
+#include "KeyUIDSignDialog.h"
+#include "core/GpgContext.h"
+#include "ui/GpgFrontendUI.h"
+
+namespace GpgFrontend::UI {
+
+class KeyPairUIDTab : public QWidget {
+ Q_OBJECT
+
+ public:
+ /**
+ * @brief Construct a new Key Pair U I D Tab object
+ *
+ * @param key_id
+ * @param parent
+ */
+ KeyPairUIDTab(const std::string& key_id, QWidget* parent);
+
+ signals:
+
+ /**
+ * @brief
+ *
+ */
+ void SignalUpdateUIDInfo();
+
+ private:
+ GpgKey m_key_;
+ QTableWidget* uid_list_{}; ///<
+ QTableWidget* sig_list_{}; ///<
+ QTabWidget* tofu_tabs_{}; ///<
+ QMenu* manage_selected_uid_menu_{}; ///<
+ QMenu* uid_popup_menu_{}; ///<
+ QMenu* sign_popup_menu_{}; ///<
+ std::vector<GpgUID> buffered_uids_; ///<
+ std::vector<GpgKeySignature> buffered_signatures_; ///<
+
+ /**
+ * @brief Create a uid list object
+ *
+ */
+ void create_uid_list();
+
+ /**
+ * @brief Create a sign list object
+ *
+ */
+ void create_sign_list();
+
+ /**
+ * @brief Create a manage uid menu object
+ *
+ */
+ void create_manage_uid_menu();
+
+ /**
+ * @brief Create a uid popup menu object
+ *
+ */
+ void create_uid_popup_menu();
+
+ /**
+ * @brief Create a sign popup menu object
+ *
+ */
+ void create_sign_popup_menu();
+
+ /**
+ * @brief Get the uid checked object
+ *
+ * @return UIDArgsListPtr
+ */
+ UIDArgsListPtr get_uid_checked();
+
+ /**
+ * @brief Get the uid selected object
+ *
+ * @return UIDArgsListPtr
+ */
+ UIDArgsListPtr get_uid_selected();
+
+ /**
+ * @brief Get the sign selected object
+ *
+ * @return SignIdArgsListPtr
+ */
+ SignIdArgsListPtr get_sign_selected();
+
+ private slots:
+
+ /**
+ * @brief
+ *
+ */
+ void slot_refresh_uid_list();
+
+ /**
+ * @brief
+ *
+ */
+ void slot_refresh_tofu_info();
+
+ /**
+ * @brief
+ *
+ */
+ void slot_refresh_sig_list();
+
+ /**
+ * @brief
+ *
+ */
+ void slot_add_sign();
+
+ /**
+ * @brief
+ *
+ */
+ void slot_add_sign_single();
+
+ /**
+ * @brief
+ *
+ */
+ void slot_add_uid();
+
+ /**
+ * @brief
+ *
+ */
+ void slot_del_uid();
+
+ /**
+ * @brief
+ *
+ */
+ void slot_del_uid_single();
+
+ /**
+ * @brief
+ *
+ */
+ void slot_set_primary_uid();
+
+ /**
+ * @brief
+ *
+ */
+ void slot_del_sign();
+
+ /**
+ * @brief
+ *
+ */
+ void slot_refresh_key();
+
+ /**
+ * @brief
+ *
+ * @param result
+ */
+ static void slot_add_uid_result(int result);
+
+ protected:
+ /**
+ * @brief
+ *
+ * @param event
+ */
+ void contextMenuEvent(QContextMenuEvent* event) override;
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_KEYPAIRUIDTAB_H
diff --git a/src/ui/dialog/keypair_details/KeySetExpireDateDialog.cpp b/src/ui/dialog/keypair_details/KeySetExpireDateDialog.cpp
new file mode 100644
index 00000000..2c10b895
--- /dev/null
+++ b/src/ui/dialog/keypair_details/KeySetExpireDateDialog.cpp
@@ -0,0 +1,145 @@
+/**
+ * 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 <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
+ *
+ */
+
+#include "KeySetExpireDateDialog.h"
+
+#include <utility>
+
+#include "core/function/GlobalSettingStation.h"
+#include "core/function/gpg/GpgKeyGetter.h"
+#include "core/function/gpg/GpgKeyOpera.h"
+#include "ui/SignalStation.h"
+#include "ui_ModifiedExpirationDateTime.h"
+
+namespace GpgFrontend::UI {
+
+KeySetExpireDateDialog::KeySetExpireDateDialog(const KeyId& key_id,
+ QWidget* parent)
+ : GeneralDialog(typeid(KeySetExpireDateDialog).name(), parent),
+ ui_(std::make_shared<Ui_ModifiedExpirationDateTime>()),
+ m_key_(GpgKeyGetter::GetInstance().GetKey(key_id)) {
+ init();
+}
+
+KeySetExpireDateDialog::KeySetExpireDateDialog(const KeyId& key_id,
+ std::string subkey_fpr,
+ QWidget* parent)
+ : GeneralDialog(typeid(KeySetExpireDateDialog).name(), parent),
+ ui_(std::make_shared<Ui_ModifiedExpirationDateTime>()),
+ m_key_(GpgKeyGetter::GetInstance().GetKey(key_id)),
+ m_subkey_(std::move(subkey_fpr)) {
+ init();
+}
+
+void KeySetExpireDateDialog::slot_confirm() {
+ LOG(INFO) << "Called" << ui_->dateEdit->date().toString().toStdString()
+ << ui_->timeEdit->time().toString().toStdString();
+ auto datetime = QDateTime(ui_->dateEdit->date(), ui_->timeEdit->time());
+ std::unique_ptr<boost::posix_time::ptime> expires = nullptr;
+ if (ui_->noExpirationCheckBox->checkState() == Qt::Unchecked) {
+ expires = std::make_unique<boost::posix_time::ptime>(
+ boost::posix_time::from_time_t(datetime.toLocalTime().toTime_t()));
+ LOG(INFO) << "keyid" << m_key_.GetId() << m_subkey_ << *expires;
+ } else {
+ LOG(INFO) << "keyid" << m_key_.GetId() << m_subkey_ << "Non Expired";
+ }
+
+ auto err = GpgKeyOpera::GetInstance().SetExpire(m_key_, m_subkey_, expires);
+
+ if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) {
+ auto* msg_box = new QMessageBox((QWidget*)this->parent());
+ msg_box->setAttribute(Qt::WA_DeleteOnClose);
+ msg_box->setStandardButtons(QMessageBox::Ok);
+ msg_box->setWindowTitle(_("Success"));
+ msg_box->setText(_("The expire date of the key pair has been updated."));
+ msg_box->setModal(true);
+ msg_box->open();
+
+ emit SignalKeyExpireDateUpdated();
+
+ this->close();
+ } else {
+ QMessageBox::critical(
+ this, _("Failure"),
+ _("Failed to update the expire date of the key pair."));
+ }
+}
+
+void KeySetExpireDateDialog::init() {
+ ui_->setupUi(this);
+
+ auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
+
+ bool longer_expiration_date = false;
+ try {
+ longer_expiration_date = settings.lookup("general.longer_expiration_date");
+ LOG(INFO) << "longer_expiration_date" << longer_expiration_date;
+
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("longer_expiration_date");
+ }
+
+ auto max_date_time =
+ longer_expiration_date
+ ? QDateTime::currentDateTime().toLocalTime().addYears(30)
+ : QDateTime::currentDateTime().toLocalTime().addYears(2);
+
+ auto min_date_time = QDateTime::currentDateTime().addDays(7);
+
+ ui_->dateEdit->setMaximumDateTime(max_date_time);
+ ui_->dateEdit->setMinimumDateTime(min_date_time);
+
+ // set default date time to expire date time
+ auto current_expire_time =
+ QDateTime::fromTime_t(to_time_t(m_key_.GetExpireTime()));
+ ui_->dateEdit->setDateTime(current_expire_time);
+ ui_->timeEdit->setDateTime(current_expire_time);
+
+ connect(ui_->noExpirationCheckBox, &QCheckBox::stateChanged, this,
+ &KeySetExpireDateDialog::slot_non_expired_checked);
+ connect(ui_->button_box_, &QDialogButtonBox::accepted, this,
+ &KeySetExpireDateDialog::slot_confirm);
+ connect(this, &KeySetExpireDateDialog::SignalKeyExpireDateUpdated,
+ SignalStation::GetInstance(),
+ &SignalStation::SignalKeyDatabaseRefresh);
+
+ ui_->titleLabel->setText(_("Modified Expiration Date (Local Time)"));
+ ui_->label->setText(
+ _("Tips: For the sake of security, the key is valid for up to two years. "
+ "If you are an expert user, please unlock it for a longer time in the "
+ "settings."));
+ ui_->noExpirationCheckBox->setText(_("No Expiration"));
+ this->setWindowTitle(_("Modified Expiration Date"));
+}
+
+void KeySetExpireDateDialog::slot_non_expired_checked(int state) {
+ ui_->dateEdit->setDisabled(state == Qt::Checked);
+ ui_->timeEdit->setDisabled(state == Qt::Checked);
+}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/dialog/keypair_details/KeySetExpireDateDialog.h b/src/ui/dialog/keypair_details/KeySetExpireDateDialog.h
new file mode 100644
index 00000000..3cd6cd01
--- /dev/null
+++ b/src/ui/dialog/keypair_details/KeySetExpireDateDialog.h
@@ -0,0 +1,99 @@
+/**
+ * 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 <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
+ *
+ */
+
+#ifndef GPGFRONTEND_KEYSETEXPIREDATEDIALOG_H
+#define GPGFRONTEND_KEYSETEXPIREDATEDIALOG_H
+
+#include "core/GpgContext.h"
+#include "core/model/GpgKey.h"
+#include "core/model/GpgSubKey.h"
+#include "ui/GpgFrontendUI.h"
+#include "ui/dialog/GeneralDialog.h"
+
+class Ui_ModifiedExpirationDateTime;
+
+namespace GpgFrontend::UI {
+
+class KeySetExpireDateDialog : public GeneralDialog {
+ Q_OBJECT
+ public:
+ /**
+ * @brief Construct a new Key Set Expire Date Dialog object
+ *
+ * @param key_id
+ * @param parent
+ */
+ explicit KeySetExpireDateDialog(const KeyId& key_id,
+ QWidget* parent = nullptr);
+
+ /**
+ * @brief Construct a new Key Set Expire Date Dialog object
+ *
+ * @param key_id
+ * @param subkey_fpr
+ * @param parent
+ */
+ explicit KeySetExpireDateDialog(const KeyId& key_id, std::string subkey_fpr,
+ QWidget* parent = nullptr);
+
+ signals:
+ /**
+ * @brief
+ *
+ */
+ void SignalKeyExpireDateUpdated();
+
+ private:
+ /**
+ * @brief
+ *
+ */
+ void init();
+
+ std::shared_ptr<Ui_ModifiedExpirationDateTime> ui_; ///<
+ const GpgKey m_key_; ///<
+ const SubkeyId m_subkey_; ///<
+
+ private slots:
+ /**
+ * @brief
+ *
+ */
+ void slot_confirm();
+
+ /**
+ * @brief
+ *
+ * @param state
+ */
+ void slot_non_expired_checked(int state);
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_KEYSETEXPIREDATEDIALOG_H
diff --git a/src/ui/dialog/keypair_details/KeyUIDSignDialog.cpp b/src/ui/dialog/keypair_details/KeyUIDSignDialog.cpp
new file mode 100644
index 00000000..0f7de587
--- /dev/null
+++ b/src/ui/dialog/keypair_details/KeyUIDSignDialog.cpp
@@ -0,0 +1,134 @@
+/**
+ * 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 <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.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "KeyUIDSignDialog.h"
+
+#include "core/function/gpg/GpgKeyGetter.h"
+#include "core/function/gpg/GpgKeyManager.h"
+#include "ui/SignalStation.h"
+
+namespace GpgFrontend::UI {
+
+KeyUIDSignDialog::KeyUIDSignDialog(const GpgKey& key, UIDArgsListPtr uid,
+ QWidget* parent)
+ : GeneralDialog(typeid(KeyUIDSignDialog).name(), parent),
+ m_uids_(std::move(uid)),
+ m_key_(key) {
+ const auto key_id = m_key_.GetId();
+ m_key_list_ = new KeyList(KeyMenuAbility::NONE, this);
+ m_key_list_->AddListGroupTab(
+ _("Signers"), KeyListRow::ONLY_SECRET_KEY,
+ KeyListColumn::NAME | KeyListColumn::EmailAddress,
+ [key_id](const GpgKey& key) -> bool {
+ if (key.IsDisabled() || !key.IsHasCertificationCapability() ||
+ !key.IsHasMasterKey() || key.IsExpired() || key.IsRevoked() ||
+ key_id == key.GetId())
+ return false;
+ else
+ return true;
+ });
+ m_key_list_->SlotRefresh();
+
+ sign_key_button_ = new QPushButton("Sign");
+
+ /**
+ * A DateTime after 5 Years is recommend.
+ */
+ expires_edit_ = new QDateTimeEdit(QDateTime::currentDateTime().addYears(5));
+ expires_edit_->setMinimumDateTime(QDateTime::currentDateTime());
+
+ /**
+ * Note further that the OpenPGP protocol uses 32 bit values for timestamps
+ * and thus can only encode dates up to the year 2106.
+ */
+ expires_edit_->setMaximumDate(QDate(2106, 1, 1));
+
+ non_expire_check_ = new QCheckBox("Non Expired");
+ non_expire_check_->setTristate(false);
+
+ connect(non_expire_check_, &QCheckBox::stateChanged, this,
+ [this](int state) -> void {
+ if (state == 0)
+ expires_edit_->setDisabled(false);
+ else
+ expires_edit_->setDisabled(true);
+ });
+
+ auto layout = new QGridLayout();
+
+ auto timeLayout = new QGridLayout();
+
+ layout->addWidget(m_key_list_, 0, 0);
+ layout->addWidget(sign_key_button_, 2, 0, Qt::AlignRight);
+ timeLayout->addWidget(new QLabel(_("Expire Date")), 0, 0);
+ timeLayout->addWidget(expires_edit_, 0, 1);
+ timeLayout->addWidget(non_expire_check_, 0, 2);
+ layout->addLayout(timeLayout, 1, 0);
+
+ connect(sign_key_button_, &QPushButton::clicked, this,
+ &KeyUIDSignDialog::slot_sign_key);
+
+ this->setLayout(layout);
+ this->setModal(true);
+ this->setWindowTitle(_("Sign For Key's UID(s)"));
+ this->adjustSize();
+
+ setAttribute(Qt::WA_DeleteOnClose, true);
+
+ connect(this, &KeyUIDSignDialog::SignalKeyUIDSignUpdate,
+ SignalStation::GetInstance(),
+ &SignalStation::SignalKeyDatabaseRefresh);
+}
+
+void KeyUIDSignDialog::slot_sign_key(bool clicked) {
+ LOG(INFO) << "Called";
+
+ // Set Signers
+ auto key_ids = m_key_list_->GetChecked();
+ auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids);
+
+ LOG(INFO) << "Key Info Got";
+ auto expires = std::make_unique<boost::posix_time::ptime>(
+ boost::posix_time::from_time_t(expires_edit_->dateTime().toTime_t()));
+
+ LOG(INFO) << "Sign Start";
+ for (const auto& uid : *m_uids_) {
+ LOG(INFO) << "Sign UID" << uid;
+ // Sign For mKey
+ if (!GpgKeyManager::GetInstance().SignKey(m_key_, *keys, uid, expires)) {
+ QMessageBox::critical(
+ nullptr, _("Unsuccessful Operation"),
+ QString(_("Signature operation failed for UID %1")).arg(uid.c_str()));
+ }
+ }
+
+ QMessageBox::information(nullptr, _("Operation Complete"),
+ _("The signature operation of the UID is complete"));
+ this->close();
+ emit SignalKeyUIDSignUpdate();
+}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/dialog/keypair_details/KeyUIDSignDialog.h b/src/ui/dialog/keypair_details/KeyUIDSignDialog.h
new file mode 100644
index 00000000..bfaff6d2
--- /dev/null
+++ b/src/ui/dialog/keypair_details/KeyUIDSignDialog.h
@@ -0,0 +1,78 @@
+/**
+ * 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 <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.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef GPGFRONTEND_KEYUIDSIGNDIALOG_H
+#define GPGFRONTEND_KEYUIDSIGNDIALOG_H
+
+#include "core/GpgContext.h"
+#include "ui/GpgFrontendUI.h"
+#include "ui/dialog/GeneralDialog.h"
+#include "ui/widgets/KeyList.h"
+
+namespace GpgFrontend::UI {
+
+class KeyUIDSignDialog : public GeneralDialog {
+ Q_OBJECT
+
+ public:
+ /**
+ * @brief Construct a new Key U I D Sign Dialog object
+ *
+ * @param key
+ * @param uid
+ * @param parent
+ */
+ explicit KeyUIDSignDialog(const GpgKey& key, UIDArgsListPtr uid,
+ QWidget* parent = nullptr);
+
+ signals:
+ /**
+ * @brief
+ *
+ */
+ void SignalKeyUIDSignUpdate();
+
+ private:
+ KeyList* m_key_list_; ///<
+ QPushButton* sign_key_button_; ///<
+ QDateTimeEdit* expires_edit_; ///<
+ QCheckBox* non_expire_check_; ///<
+ UIDArgsListPtr m_uids_; ///<
+
+ const GpgKey& m_key_; ///<
+
+ private slots:
+ /**
+ * @brief
+ *
+ * @param clicked
+ */
+ void slot_sign_key(bool clicked);
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_KEYUIDSIGNDIALOG_H
diff --git a/src/ui/dialog/settings/SettingsAdvanced.cpp b/src/ui/dialog/settings/SettingsAdvanced.cpp
new file mode 100644
index 00000000..516d4d02
--- /dev/null
+++ b/src/ui/dialog/settings/SettingsAdvanced.cpp
@@ -0,0 +1,104 @@
+/**
+ * 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 <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
+ *
+ */
+
+#include "SettingsAdvanced.h"
+
+#include "core/function/GlobalSettingStation.h"
+
+namespace GpgFrontend::UI {
+
+AdvancedTab::AdvancedTab(QWidget* parent) : QWidget(parent) {
+ auto* stegano_box = new QGroupBox(_("Show Steganography Options"));
+ auto* stegano_box_layout = new QHBoxLayout();
+ stegano_check_box_ = new QCheckBox(_("Show Steganography Options."), this);
+ stegano_box_layout->addWidget(stegano_check_box_);
+ stegano_box->setLayout(stegano_box_layout);
+
+ auto* pubkey_exchange_box = new QGroupBox(_("Pubkey Exchange"));
+ auto* pubkey_exchange_box_layout = new QHBoxLayout();
+ auto_pubkey_exchange_check_box_ =
+ new QCheckBox(_("Auto Pubkey Exchange"), this);
+ pubkey_exchange_box_layout->addWidget(auto_pubkey_exchange_check_box_);
+ pubkey_exchange_box->setLayout(pubkey_exchange_box_layout);
+
+ auto* main_layout = new QVBoxLayout;
+ main_layout->addWidget(stegano_box);
+ main_layout->addWidget(pubkey_exchange_box);
+ SetSettings();
+ main_layout->addStretch(1);
+ setLayout(main_layout);
+}
+
+void AdvancedTab::SetSettings() {
+ auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
+ try {
+ bool stegano_checked = settings.lookup("advanced.stegano_checked");
+ if (stegano_checked) stegano_check_box_->setCheckState(Qt::Checked);
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("stegano_checked");
+ }
+
+ try {
+ bool auto_pubkey_exchange_checked =
+ settings.lookup("advanced.auto_pubkey_exchange_checked");
+ if (auto_pubkey_exchange_checked)
+ auto_pubkey_exchange_check_box_->setCheckState(Qt::Checked);
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error")
+ << _("auto_pubkey_exchange_checked");
+ }
+}
+
+void AdvancedTab::ApplySettings() {
+ auto& settings =
+ GpgFrontend::GlobalSettingStation::GetInstance().GetUISettings();
+
+ if (!settings.exists("advanced") ||
+ settings.lookup("advanced").getType() != libconfig::Setting::TypeGroup)
+ settings.add("advanced", libconfig::Setting::TypeGroup);
+
+ auto& advanced = settings["advanced"];
+
+ if (!advanced.exists("stegano_checked"))
+ advanced.add("stegano_checked", libconfig::Setting::TypeBoolean) =
+ stegano_check_box_->isChecked();
+ else {
+ advanced["stegano_checked"] = stegano_check_box_->isChecked();
+ }
+
+ if (!advanced.exists("auto_pubkey_exchange_checked"))
+ advanced.add("auto_pubkey_exchange_checked",
+ libconfig::Setting::TypeBoolean) =
+ auto_pubkey_exchange_check_box_->isChecked();
+ else {
+ advanced["auto_pubkey_exchange_checked"] =
+ auto_pubkey_exchange_check_box_->isChecked();
+ }
+}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/dialog/settings/SettingsAdvanced.h b/src/ui/dialog/settings/SettingsAdvanced.h
new file mode 100644
index 00000000..c1a3d5a6
--- /dev/null
+++ b/src/ui/dialog/settings/SettingsAdvanced.h
@@ -0,0 +1,55 @@
+/**
+ * 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 <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
+ *
+ */
+
+#ifndef GPGFRONTEND_SETTINGSADVANCED_H
+#define GPGFRONTEND_SETTINGSADVANCED_H
+
+#include "ui/GpgFrontendUI.h"
+
+namespace GpgFrontend::UI {
+class AdvancedTab : public QWidget {
+ Q_OBJECT
+
+ public:
+ explicit AdvancedTab(QWidget* parent = nullptr);
+
+ void SetSettings();
+
+ void ApplySettings();
+
+ private:
+ QCheckBox* stegano_check_box_;
+ QCheckBox* auto_pubkey_exchange_check_box_;
+
+ signals:
+
+ void SignalRestartNeeded(bool needed);
+};
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_SETTINGSADVANCED_H
diff --git a/src/ui/dialog/settings/SettingsAppearance.cpp b/src/ui/dialog/settings/SettingsAppearance.cpp
new file mode 100644
index 00000000..17471a0d
--- /dev/null
+++ b/src/ui/dialog/settings/SettingsAppearance.cpp
@@ -0,0 +1,207 @@
+/**
+ * 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 <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
+ *
+ */
+
+#include "SettingsAppearance.h"
+
+#include "core/function/GlobalSettingStation.h"
+#include "ui/struct/SettingsObject.h"
+
+namespace GpgFrontend::UI {
+
+AppearanceTab::AppearanceTab(QWidget* parent) : QWidget(parent) {
+ /*****************************************
+ * Icon-Size-Box
+ *****************************************/
+ auto* iconSizeBox = new QGroupBox(_("Icon Size"));
+ icon_size_group_ = new QButtonGroup();
+ icon_size_small_ = new QRadioButton(_("small"));
+ icon_size_medium_ = new QRadioButton(_("medium"));
+ icon_size_large_ = new QRadioButton(_("large"));
+
+ icon_size_group_->addButton(icon_size_small_, 1);
+ icon_size_group_->addButton(icon_size_medium_, 2);
+ icon_size_group_->addButton(icon_size_large_, 3);
+
+ auto* iconSizeBoxLayout = new QHBoxLayout();
+ iconSizeBoxLayout->addWidget(icon_size_small_);
+ iconSizeBoxLayout->addWidget(icon_size_medium_);
+ iconSizeBoxLayout->addWidget(icon_size_large_);
+
+ iconSizeBox->setLayout(iconSizeBoxLayout);
+
+ /*****************************************
+ * Icon-Style-Box
+ *****************************************/
+ auto* iconStyleBox = new QGroupBox(_("Icon Style"));
+ icon_style_group_ = new QButtonGroup();
+ icon_text_button_ = new QRadioButton(_("just text"));
+ icon_icons_button_ = new QRadioButton(_("just icons"));
+ icon_all_button_ = new QRadioButton(_("text and icons"));
+
+ icon_style_group_->addButton(icon_text_button_, 1);
+ icon_style_group_->addButton(icon_icons_button_, 2);
+ icon_style_group_->addButton(icon_all_button_, 3);
+
+ auto* iconStyleBoxLayout = new QHBoxLayout();
+ iconStyleBoxLayout->addWidget(icon_text_button_);
+ iconStyleBoxLayout->addWidget(icon_icons_button_);
+ iconStyleBoxLayout->addWidget(icon_all_button_);
+
+ iconStyleBox->setLayout(iconStyleBoxLayout);
+
+ /*****************************************
+ * Window-Size-Box
+ *****************************************/
+ auto* windowSizeBox = new QGroupBox(_("Window State"));
+ auto* windowSizeBoxLayout = new QHBoxLayout();
+ window_size_check_box_ =
+ new QCheckBox(_("Save window size and position on exit."), this);
+ windowSizeBoxLayout->addWidget(window_size_check_box_);
+ windowSizeBox->setLayout(windowSizeBoxLayout);
+
+ /*****************************************
+ * Info-Board-Font-Size-Box
+ *****************************************/
+
+ auto* infoBoardBox = new QGroupBox(_("Information Board"));
+ auto* infoBoardLayout = new QHBoxLayout();
+ info_board_font_size_spin_ = new QSpinBox();
+ info_board_font_size_spin_->setRange(9, 18);
+ info_board_font_size_spin_->setValue(10);
+ info_board_font_size_spin_->setSingleStep(1);
+ infoBoardLayout->addWidget(new QLabel(_("Font Size in Information Board")));
+ infoBoardLayout->addWidget(info_board_font_size_spin_);
+ infoBoardBox->setLayout(infoBoardLayout);
+
+ auto* mainLayout = new QVBoxLayout;
+ mainLayout->addWidget(iconSizeBox);
+ mainLayout->addWidget(iconStyleBox);
+ mainLayout->addWidget(windowSizeBox);
+ mainLayout->addWidget(infoBoardBox);
+ mainLayout->addStretch(1);
+ SetSettings();
+ setLayout(mainLayout);
+}
+
+/**********************************
+ * Read the settings from config
+ * and set the buttons and checkboxes
+ * appropriately
+ **********************************/
+void AppearanceTab::SetSettings() {
+ SettingsObject general_settings_state("general_settings_state");
+
+ int width = general_settings_state.Check("icon_size").Check("width", 24),
+ height = general_settings_state.Check("icon_size").Check("height", 24);
+
+ auto icon_size = QSize(width, height);
+
+ switch (icon_size.width()) {
+ case 12:
+ icon_size_small_->setChecked(true);
+ break;
+ case 24:
+ icon_size_medium_->setChecked(true);
+ break;
+ case 32:
+ icon_size_large_->setChecked(true);
+ break;
+ }
+
+ // icon_style
+ int s_icon_style =
+ general_settings_state.Check("icon_style", Qt::ToolButtonTextUnderIcon);
+ auto icon_style = static_cast<Qt::ToolButtonStyle>(s_icon_style);
+
+ switch (icon_style) {
+ case Qt::ToolButtonTextOnly:
+ icon_text_button_->setChecked(true);
+ break;
+ case Qt::ToolButtonIconOnly:
+ icon_icons_button_->setChecked(true);
+ break;
+ case Qt::ToolButtonTextUnderIcon:
+ icon_all_button_->setChecked(true);
+ break;
+ default:
+ break;
+ }
+
+ bool window_save = general_settings_state.Check("window_save", true);
+ if (window_save) window_size_check_box_->setCheckState(Qt::Checked);
+
+ auto info_font_size = general_settings_state.Check("font_size", 10);
+ if (info_font_size < 9 || info_font_size > 18) info_font_size = 10;
+ info_board_font_size_spin_->setValue(info_font_size);
+}
+
+/***********************************
+ * get the values of the buttons and
+ * write them to settings-file
+ *************************************/
+void AppearanceTab::ApplySettings() {
+
+ SettingsObject general_settings_state("general_settings_state");
+
+ int icon_size = 24;
+ switch (icon_size_group_->checkedId()) {
+ case 1:
+ icon_size = 12;
+ break;
+ case 2:
+ icon_size = 24;
+ break;
+ case 3:
+ icon_size = 32;
+ break;
+ }
+
+ general_settings_state["icon_size"]["width"] = icon_size;
+ general_settings_state["icon_size"]["height"] = icon_size;
+
+ auto icon_style = Qt::ToolButtonTextUnderIcon;
+ switch (icon_style_group_->checkedId()) {
+ case 1:
+ icon_style = Qt::ToolButtonTextOnly;
+ break;
+ case 2:
+ icon_style = Qt::ToolButtonIconOnly;
+ break;
+ case 3:
+ icon_style = Qt::ToolButtonTextUnderIcon;
+ break;
+ }
+
+ general_settings_state["icon_style"] = icon_style;
+
+ general_settings_state["window_save"] = window_size_check_box_->isChecked();
+
+ general_settings_state["info_font_size"] = info_board_font_size_spin_->value();
+}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/dialog/settings/SettingsAppearance.h b/src/ui/dialog/settings/SettingsAppearance.h
new file mode 100644
index 00000000..7110d992
--- /dev/null
+++ b/src/ui/dialog/settings/SettingsAppearance.h
@@ -0,0 +1,83 @@
+/**
+ * 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 <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
+ *
+ */
+
+#ifndef GPGFRONTEND_SETTINGSAPPEARANCE_H
+#define GPGFRONTEND_SETTINGSAPPEARANCE_H
+
+#include "ui/GpgFrontendUI.h"
+
+namespace GpgFrontend::UI {
+
+class AppearanceTab : public QWidget {
+ Q_OBJECT
+
+ public:
+ /**
+ * @brief Construct a new Appearance Tab object
+ *
+ * @param parent
+ */
+ explicit AppearanceTab(QWidget* parent = nullptr);
+
+ /**
+ * @brief Set the Settings object
+ *
+ */
+ void SetSettings();
+
+ /**
+ * @brief
+ *
+ */
+ void ApplySettings();
+
+ private:
+ QButtonGroup* icon_style_group_; ///<
+ QRadioButton* icon_size_small_; ///<
+ QRadioButton* icon_size_medium_; ///<
+ QRadioButton* icon_size_large_; ///<
+ QButtonGroup* icon_size_group_; ///<
+ QRadioButton* icon_text_button_; ///<
+ QRadioButton* icon_icons_button_; ///<
+ QRadioButton* icon_all_button_; ///<
+ QSpinBox* info_board_font_size_spin_; ///<
+ QCheckBox* window_size_check_box_; ///<
+
+ signals:
+
+ /**
+ * @brief
+ *
+ * @param needed
+ */
+ void signalRestartNeeded(bool needed);
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_SETTINGSAPPEARANCE_H
diff --git a/src/ui/dialog/settings/SettingsDialog.cpp b/src/ui/dialog/settings/SettingsDialog.cpp
new file mode 100644
index 00000000..e2677a0f
--- /dev/null
+++ b/src/ui/dialog/settings/SettingsDialog.cpp
@@ -0,0 +1,146 @@
+/**
+ * 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 <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
+ *
+ */
+
+#include "SettingsDialog.h"
+
+#include "SettingsAdvanced.h"
+#include "SettingsAppearance.h"
+#include "SettingsGeneral.h"
+#include "SettingsKeyServer.h"
+#include "SettingsNetwork.h"
+#include "core/function/GlobalSettingStation.h"
+#include "ui/main_window/MainWindow.h"
+
+namespace GpgFrontend::UI {
+
+SettingsDialog::SettingsDialog(QWidget* parent)
+ : GeneralDialog(typeid(SettingsDialog).name(), parent) {
+ tab_widget_ = new QTabWidget();
+ general_tab_ = new GeneralTab();
+ appearance_tab_ = new AppearanceTab();
+ key_server_tab_ = new KeyserverTab();
+ network_tab_ = new NetworkTab();
+
+ auto* mainLayout = new QVBoxLayout;
+ mainLayout->addWidget(tab_widget_);
+ mainLayout->stretch(0);
+
+ tab_widget_->addTab(general_tab_, _("General"));
+ tab_widget_->addTab(appearance_tab_, _("Appearance"));
+ tab_widget_->addTab(key_server_tab_, _("Key Server"));
+ tab_widget_->addTab(network_tab_, _("Network"));
+
+#ifndef MACOS
+ button_box_ =
+ new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+ connect(button_box_, &QDialogButtonBox::accepted, this,
+ &SettingsDialog::SlotAccept);
+ connect(button_box_, &QDialogButtonBox::rejected, this,
+ &SettingsDialog::reject);
+ mainLayout->addWidget(button_box_);
+ mainLayout->stretch(0);
+ setWindowTitle(_("Settings"));
+#else
+ connect(this, &QDialog::finished, this, &SettingsDialog::SlotAccept);
+ connect(this, &QDialog::finished, this, &SettingsDialog::deleteLater);
+ setWindowTitle(_("Preference"));
+#endif
+
+ setLayout(mainLayout);
+
+ // slots for handling the restart needed member
+ this->slot_set_restart_needed(false);
+ connect(general_tab_, &GeneralTab::SignalRestartNeeded, this,
+ &SettingsDialog::slot_set_restart_needed);
+ connect(this, &SettingsDialog::SignalRestartNeeded,
+ qobject_cast<MainWindow*>(parent), &MainWindow::SlotSetRestartNeeded);
+
+ this->setMinimumSize(480, 680);
+ this->adjustSize();
+ this->show();
+}
+
+bool SettingsDialog::get_restart_needed() const {
+ return this->restart_needed_;
+}
+
+void SettingsDialog::slot_set_restart_needed(bool needed) {
+ this->restart_needed_ = needed;
+}
+
+void SettingsDialog::SlotAccept() {
+ LOG(INFO) << "Called";
+
+ general_tab_->ApplySettings();
+ appearance_tab_->ApplySettings();
+ key_server_tab_->ApplySettings();
+ network_tab_->ApplySettings();
+
+ LOG(INFO) << "apply done";
+
+ // write settings to filesystem
+ GlobalSettingStation::GetInstance().SyncSettings();
+
+ LOG(INFO) << "restart needed" << get_restart_needed();
+ if (get_restart_needed()) {
+ emit SignalRestartNeeded(true);
+ }
+ close();
+}
+
+QHash<QString, QString> SettingsDialog::ListLanguages() {
+ QHash<QString, QString> languages;
+
+ languages.insert(QString(), _("System Default"));
+
+ auto locale_path = GlobalSettingStation::GetInstance().GetLocaleDir();
+
+ auto locale_dir = QDir(QString::fromStdString(locale_path.string()));
+ QStringList file_names = locale_dir.entryList(QStringList("*"));
+
+ for (int i = 0; i < file_names.size(); ++i) {
+ QString locale = file_names[i];
+ LOG(INFO) << "locale" << locale.toStdString();
+ if (locale == "." || locale == "..") continue;
+
+ // this works in qt 4.8
+ QLocale q_locale(locale);
+ if (q_locale.nativeCountryName().isEmpty()) continue;
+#if QT_VERSION < 0x040800
+ QString language =
+ QLocale::languageToString(q_locale.language()) + " (" + locale +
+ ")"; //+ " (" + QLocale::languageToString(q_locale.language()) + ")";
+#else
+ auto language = q_locale.nativeLanguageName() + " (" + locale + ")";
+#endif
+ languages.insert(locale, language);
+ }
+ return languages;
+}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/dialog/settings/SettingsDialog.h b/src/ui/dialog/settings/SettingsDialog.h
new file mode 100644
index 00000000..172370d0
--- /dev/null
+++ b/src/ui/dialog/settings/SettingsDialog.h
@@ -0,0 +1,112 @@
+/**
+ * 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 <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
+ *
+ */
+
+#ifndef __SETTINGSDIALOG_H__
+#define __SETTINGSDIALOG_H__
+
+#include "ui/GpgFrontendUI.h"
+#include "ui/dialog/GeneralDialog.h"
+#include "ui/widgets/KeyList.h"
+
+namespace GpgFrontend::UI {
+
+class GeneralTab;
+class AppearanceTab;
+class KeyserverTab;
+class NetworkTab;
+
+/**
+ * @brief
+ *
+ */
+class SettingsDialog : public GeneralDialog {
+ Q_OBJECT
+
+ public:
+ /**
+ * @brief Construct a new Settings Dialog object
+ *
+ * @param parent
+ */
+ explicit SettingsDialog(QWidget* parent = nullptr);
+
+ GeneralTab* general_tab_; ///<
+ AppearanceTab* appearance_tab_; ///<
+ KeyserverTab* key_server_tab_; ///<
+ NetworkTab* network_tab_; ///<
+
+ /**
+ * @brief
+ *
+ * @return QHash<QString, QString>
+ */
+ static QHash<QString, QString> ListLanguages();
+
+ public slots:
+
+ /**
+ * @brief
+ *
+ */
+ void SlotAccept();
+
+ signals:
+
+ /**
+ * @brief
+ *
+ * @param needed
+ */
+ void SignalRestartNeeded(bool needed);
+
+ private:
+ QTabWidget* tab_widget_; ///<
+ QDialogButtonBox* button_box_; ///<
+ bool restart_needed_{}; ///<
+
+ /**
+ * @brief Get the Restart Needed object
+ *
+ * @return true
+ * @return false
+ */
+ bool get_restart_needed() const;
+
+ private slots:
+
+ /**
+ * @brief
+ *
+ * @param needed
+ */
+ void slot_set_restart_needed(bool needed);
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // __SETTINGSDIALOG_H__
diff --git a/src/ui/dialog/settings/SettingsGeneral.cpp b/src/ui/dialog/settings/SettingsGeneral.cpp
new file mode 100644
index 00000000..3c7bca32
--- /dev/null
+++ b/src/ui/dialog/settings/SettingsGeneral.cpp
@@ -0,0 +1,196 @@
+/**
+ * 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 <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
+ *
+ */
+
+#include "SettingsGeneral.h"
+
+#ifdef MULTI_LANG_SUPPORT
+#include "SettingsDialog.h"
+#endif
+
+#include "core/function/GlobalSettingStation.h"
+#include "ui_GeneralSettings.h"
+
+namespace GpgFrontend::UI {
+
+GeneralTab::GeneralTab(QWidget* parent)
+ : QWidget(parent), ui_(std::make_shared<Ui_GeneralSettings>()) {
+ ui_->setupUi(this);
+
+ ui_->saveCheckedKeysBox->setTitle(_("Save Checked Keys"));
+ ui_->saveCheckedKeysCheckBox->setText(
+ _("Save checked private keys on exit and restore them on next start."));
+ ui_->longerKeyExpirationDateBox->setTitle(_("Longer Key Expiration Date"));
+ ui_->longerKeyExpirationDateCheckBox->setText(
+ _("Unlock key expiration date setting up to 30 years."));
+ ui_->importConfirmationBox->setTitle(_("Confirm drag'n'drop key import"));
+ ui_->importConfirmationCheckBox->setText(
+ _("Import files dropped on the Key List without confirmation."));
+
+ ui_->asciiModeBox->setTitle(_("ASCII Mode"));
+ ui_->asciiModeCheckBox->setText(
+ _("ASCII encoding is not used when file encrypting and "
+ "signing."));
+
+ ui_->langBox->setTitle(_("Language"));
+ ui_->langNoteLabel->setText(
+ "<b>" + QString(_("NOTE")) + _(": ") + "</b>" +
+ _("GpgFrontend will restart automatically if you change the language!"));
+
+#ifdef MULTI_LANG_SUPPORT
+ lang_ = SettingsDialog::ListLanguages();
+ for (const auto& l : lang_) {
+ ui_->langSelectBox->addItem(l);
+ }
+ connect(ui_->langSelectBox, qOverload<int>(&QComboBox::currentIndexChanged),
+ this, &GeneralTab::slot_language_changed);
+#endif
+
+ SetSettings();
+}
+
+/**********************************
+ * Read the settings from config
+ * and set the buttons and checkboxes
+ * appropriately
+ **********************************/
+void GeneralTab::SetSettings() {
+ auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
+ try {
+ bool save_key_checked = settings.lookup("general.save_key_checked");
+ if (save_key_checked)
+ ui_->saveCheckedKeysCheckBox->setCheckState(Qt::Checked);
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("save_key_checked");
+ }
+
+ try {
+ bool longer_expiration_date =
+ settings.lookup("general.longer_expiration_date");
+ LOG(INFO) << "longer_expiration_date" << longer_expiration_date;
+ if (longer_expiration_date)
+ ui_->longerKeyExpirationDateCheckBox->setCheckState(Qt::Checked);
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("longer_expiration_date");
+ }
+
+#ifdef MULTI_LANG_SUPPORT
+ try {
+ std::string lang_key = settings.lookup("general.lang");
+ QString lang_value = lang_.value(lang_key.c_str());
+ LOG(INFO) << "lang settings current" << lang_value.toStdString();
+ if (!lang_.empty()) {
+ ui_->langSelectBox->setCurrentIndex(
+ ui_->langSelectBox->findText(lang_value));
+ } else {
+ ui_->langSelectBox->setCurrentIndex(0);
+ }
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("lang");
+ }
+#endif
+
+ try {
+ bool confirm_import_keys = settings.lookup("general.confirm_import_keys");
+ LOG(INFO) << "confirm_import_keys" << confirm_import_keys;
+ if (confirm_import_keys)
+ ui_->importConfirmationCheckBox->setCheckState(Qt::Checked);
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("confirm_import_keys");
+ }
+
+ try {
+ bool non_ascii_when_export =
+ settings.lookup("general.non_ascii_when_export");
+ LOG(INFO) << "non_ascii_when_export" << non_ascii_when_export;
+ if (non_ascii_when_export)
+ ui_->asciiModeCheckBox->setCheckState(Qt::Checked);
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("non_ascii_when_export");
+ }
+}
+
+/***********************************
+ * get the values of the buttons and
+ * write them to settings-file
+ *************************************/
+void GeneralTab::ApplySettings() {
+ auto& settings =
+ GpgFrontend::GlobalSettingStation::GetInstance().GetUISettings();
+
+ if (!settings.exists("general") ||
+ settings.lookup("general").getType() != libconfig::Setting::TypeGroup)
+ settings.add("general", libconfig::Setting::TypeGroup);
+
+ auto& general = settings["general"];
+
+ if (!general.exists("longer_expiration_date"))
+ general.add("longer_expiration_date", libconfig::Setting::TypeBoolean) =
+ ui_->longerKeyExpirationDateCheckBox->isChecked();
+ else {
+ general["longer_expiration_date"] =
+ ui_->longerKeyExpirationDateCheckBox->isChecked();
+ }
+
+ if (!general.exists("save_key_checked"))
+ general.add("save_key_checked", libconfig::Setting::TypeBoolean) =
+ ui_->saveCheckedKeysCheckBox->isChecked();
+ else {
+ general["save_key_checked"] = ui_->saveCheckedKeysCheckBox->isChecked();
+ }
+
+ if (!general.exists("non_ascii_when_export"))
+ general.add("non_ascii_when_export", libconfig::Setting::TypeBoolean) =
+ ui_->asciiModeCheckBox->isChecked();
+ else {
+ general["non_ascii_when_export"] = ui_->asciiModeCheckBox->isChecked();
+ }
+
+#ifdef MULTI_LANG_SUPPORT
+ if (!general.exists("lang"))
+ general.add("lang", libconfig::Setting::TypeBoolean) =
+ lang_.key(ui_->langSelectBox->currentText()).toStdString();
+ else {
+ general["lang"] =
+ lang_.key(ui_->langSelectBox->currentText()).toStdString();
+ }
+#endif
+
+ if (!general.exists("confirm_import_keys"))
+ general.add("confirm_import_keys", libconfig::Setting::TypeBoolean) =
+ ui_->importConfirmationCheckBox->isChecked();
+ else {
+ general["confirm_import_keys"] =
+ ui_->importConfirmationCheckBox->isChecked();
+ }
+}
+
+#ifdef MULTI_LANG_SUPPORT
+void GeneralTab::slot_language_changed() { emit SignalRestartNeeded(true); }
+#endif
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/dialog/settings/SettingsGeneral.h b/src/ui/dialog/settings/SettingsGeneral.h
new file mode 100644
index 00000000..b3e7d904
--- /dev/null
+++ b/src/ui/dialog/settings/SettingsGeneral.h
@@ -0,0 +1,99 @@
+/**
+ * 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 <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
+ *
+ */
+
+#ifndef GPGFRONTEND_SETTINGSGENERAL_H
+#define GPGFRONTEND_SETTINGSGENERAL_H
+
+#include "ui/GpgFrontendUI.h"
+
+class Ui_GeneralSettings;
+
+namespace GpgFrontend::UI {
+class KeyList;
+
+/**
+ * @brief
+ *
+ */
+class GeneralTab : public QWidget {
+ Q_OBJECT
+
+ public:
+ /**
+ * @brief Construct a new General Tab object
+ *
+ * @param parent
+ */
+ explicit GeneralTab(QWidget* parent = nullptr);
+
+ /**
+ * @brief Set the Settings object
+ *
+ */
+ void SetSettings();
+
+ /**
+ * @brief
+ *
+ */
+ void ApplySettings();
+
+ signals:
+
+ /**
+ * @brief
+ *
+ * @param needed
+ */
+ void SignalRestartNeeded(bool needed);
+
+ private:
+ std::shared_ptr<Ui_GeneralSettings> ui_; ///<
+
+#ifdef MULTI_LANG_SUPPORT
+ QHash<QString, QString> lang_; ///<
+#endif
+
+ std::vector<std::string> key_ids_list_; ///<
+
+ KeyList* m_key_list_{}; ///<
+
+ private slots:
+
+#ifdef MULTI_LANG_SUPPORT
+ /**
+ * @brief
+ *
+ */
+ void slot_language_changed();
+
+#endif
+};
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_SETTINGSGENERAL_H
diff --git a/src/ui/dialog/settings/SettingsKeyServer.cpp b/src/ui/dialog/settings/SettingsKeyServer.cpp
new file mode 100644
index 00000000..2c09b66c
--- /dev/null
+++ b/src/ui/dialog/settings/SettingsKeyServer.cpp
@@ -0,0 +1,301 @@
+/**
+ * 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 <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
+ *
+ */
+
+#include "SettingsKeyServer.h"
+
+#include "core/function/GlobalSettingStation.h"
+#include "core/thread/Task.h"
+#include "core/thread/TaskRunnerGetter.h"
+#include "ui/struct/SettingsObject.h"
+#include "ui/thread/ListedKeyServerTestTask.h"
+#include "ui_KeyServerSettings.h"
+
+namespace GpgFrontend::UI {
+
+KeyserverTab::KeyserverTab(QWidget* parent)
+ : QWidget(parent), ui_(std::make_shared<Ui_KeyServerSettings>()) {
+ ui_->setupUi(this);
+ ui_->keyServerListTable->setSizeAdjustPolicy(
+ QAbstractScrollArea::AdjustToContents);
+
+ connect(ui_->addKeyServerPushButton, &QPushButton::clicked, this,
+ &KeyserverTab::slot_add_key_server);
+ connect(ui_->testKeyServerButton, &QPushButton::clicked, this,
+ &KeyserverTab::slot_test_listed_key_server);
+
+ ui_->keyServerListGroupBox->setTitle(_("Keyserver List"));
+ ui_->operationsGroupBox->setTitle(_("Operations"));
+
+ ui_->keyServerListTable->horizontalHeaderItem(0)->setText(_("Default"));
+ ui_->keyServerListTable->horizontalHeaderItem(1)->setText(
+ _("Keyserver Address"));
+ ui_->keyServerListTable->horizontalHeaderItem(2)->setText(_("Security"));
+ ui_->keyServerListTable->horizontalHeaderItem(3)->setText(_("Available"));
+
+ ui_->addKeyServerPushButton->setText(_("Add"));
+ ui_->testKeyServerButton->setText(_("Test Listed Keyserver"));
+
+ ui_->tipsLabel->setText(
+ _("Tips: Please Double-click table item to edit it."));
+ ui_->actionDelete_Selected_Key_Server->setText(_("Delete Selected"));
+ ui_->actionDelete_Selected_Key_Server->setToolTip(
+ _("Delete Selected Key Server"));
+ ui_->actionSet_As_Default->setText(_("Set As Default"));
+ ui_->actionSet_As_Default->setToolTip(_("Set As Default"));
+
+ popup_menu_ = new QMenu(this);
+ popup_menu_->addAction(ui_->actionSet_As_Default);
+ popup_menu_->addAction(ui_->actionDelete_Selected_Key_Server);
+
+ connect(ui_->keyServerListTable, &QTableWidget::itemChanged,
+ [=](QTableWidgetItem* item) {
+ LOG(INFO) << "item edited" << item->column();
+ if (item->column() != 1) return;
+ const auto row_size = ui_->keyServerListTable->rowCount();
+ // Update Actions
+ if (row_size > 0) {
+ key_server_str_list_.clear();
+ for (int i = 0; i < row_size; i++) {
+ const auto key_server =
+ ui_->keyServerListTable->item(i, 1)->text();
+ key_server_str_list_.append(key_server);
+ }
+ }
+ });
+
+ connect(ui_->actionSet_As_Default, &QAction::triggered, [=]() {
+ const auto row_size = ui_->keyServerListTable->rowCount();
+ for (int i = 0; i < row_size; i++) {
+ const auto item = ui_->keyServerListTable->item(i, 1);
+ if (!item->isSelected()) continue;
+ this->default_key_server_ = item->text();
+ }
+ this->slot_refresh_table();
+ });
+
+ connect(ui_->actionDelete_Selected_Key_Server, &QAction::triggered, [=]() {
+ const auto row_size = ui_->keyServerListTable->rowCount();
+ for (int i = 0; i < row_size; i++) {
+ const auto item = ui_->keyServerListTable->item(i, 1);
+ if (!item->isSelected()) continue;
+ this->key_server_str_list_.removeAt(i);
+ break;
+ }
+ this->slot_refresh_table();
+ });
+
+ // Read key-list from ini-file and fill it into combobox
+ SetSettings();
+ slot_refresh_table();
+}
+
+/**********************************
+ * Read the settings from config
+ * and set the buttons and checkboxes
+ * appropriately
+ **********************************/
+void KeyserverTab::SetSettings() {
+ try {
+ SettingsObject key_server_json("key_server");
+
+ const auto key_server_list =
+ key_server_json.Check("server_list", nlohmann::json::array());
+
+ for (const auto& key_server : key_server_list) {
+ const auto key_server_str = key_server.get<std::string>();
+ this->key_server_str_list_.append(key_server_str.c_str());
+ }
+
+ int default_key_server_index = key_server_json.Check("default_server", 0);
+ if (default_key_server_index >= key_server_list.size()) {
+ throw std::runtime_error("default_server index out of range");
+ }
+ std::string default_key_server =
+ key_server_list[default_key_server_index].get<std::string>();
+
+ if (!key_server_str_list_.contains(default_key_server.c_str()))
+ key_server_str_list_.append(default_key_server.c_str());
+ default_key_server_ = QString::fromStdString(default_key_server);
+ } catch (const std::exception& e) {
+ LOG(ERROR) << "Error reading key-server settings: " << e.what();
+ }
+}
+
+void KeyserverTab::slot_add_key_server() {
+ auto target_url = ui_->addKeyServerEdit->text();
+ if (url_reg_.match(target_url).hasMatch()) {
+ if (target_url.startsWith("https://")) {
+ ;
+ } else if (target_url.startsWith("http://")) {
+ QMessageBox::warning(
+ this, _("Insecure keyserver address"),
+ _("For security reasons, using HTTP as the communication protocol "
+ "with "
+ "the key server is not recommended. It is recommended to use "
+ "HTTPS."));
+ }
+ key_server_str_list_.append(ui_->addKeyServerEdit->text());
+ } else {
+ auto ret = QMessageBox::warning(
+ this, _("Warning"),
+ _("You may not use HTTPS or HTTP as the protocol for communicating "
+ "with the key server, which may not be wrong. But please check the "
+ "address you entered again to make sure it is correct. Are you "
+ "sure "
+ "that want to add it into the keyserver list?"),
+ QMessageBox::Ok | QMessageBox::Cancel);
+
+ if (ret == QMessageBox::Cancel)
+ return;
+ else
+ key_server_str_list_.append(ui_->addKeyServerEdit->text());
+ }
+ slot_refresh_table();
+}
+
+void KeyserverTab::ApplySettings() {
+ SettingsObject key_server_json("key_server");
+ key_server_json["server_list"] = nlohmann::json::array();
+ auto& key_server_list = key_server_json["server_list"];
+
+ const auto list_size = key_server_str_list_.size();
+ for (int i = 0; i < list_size; i++) {
+ const auto key_server = key_server_str_list_[i];
+ if (default_key_server_ == key_server)
+ key_server_json["default_server"] = i;
+ key_server_list.insert(key_server_list.end(), key_server.toStdString());
+ }
+}
+
+void KeyserverTab::slot_refresh_table() {
+ LOG(INFO) << "Start Refreshing Key Server Table";
+
+ ui_->keyServerListTable->blockSignals(true);
+ ui_->keyServerListTable->setRowCount(key_server_str_list_.size());
+
+ int index = 0;
+ for (const auto& server : key_server_str_list_) {
+ auto* tmp1 =
+ new QTableWidgetItem(server == default_key_server_ ? "*" : QString{});
+ tmp1->setTextAlignment(Qt::AlignCenter);
+ ui_->keyServerListTable->setItem(index, 0, tmp1);
+ tmp1->setFlags(tmp1->flags() ^ Qt::ItemIsEditable);
+
+ auto* tmp2 = new QTableWidgetItem(server);
+ tmp2->setTextAlignment(Qt::AlignCenter);
+ ui_->keyServerListTable->setItem(index, 1, tmp2);
+
+ auto* tmp3 = new QTableWidgetItem(server.startsWith("https") ? _("true")
+ : _("false"));
+ tmp3->setTextAlignment(Qt::AlignCenter);
+ ui_->keyServerListTable->setItem(index, 2, tmp3);
+ tmp3->setFlags(tmp3->flags() ^ Qt::ItemIsEditable);
+
+ auto* tmp4 = new QTableWidgetItem(_("unknown"));
+ tmp4->setTextAlignment(Qt::AlignCenter);
+ ui_->keyServerListTable->setItem(index, 3, tmp4);
+ tmp4->setFlags(tmp3->flags() ^ Qt::ItemIsEditable);
+ index++;
+ }
+ const auto column_count = ui_->keyServerListTable->columnCount();
+ for (int i = 0; i < column_count; i++) {
+ ui_->keyServerListTable->resizeColumnToContents(i);
+ }
+ ui_->keyServerListTable->blockSignals(false);
+}
+
+void KeyserverTab::slot_test_listed_key_server() {
+ auto timeout = QInputDialog::getInt(this, _("Set TCP Timeout"),
+ tr("timeout(ms): "), 2500, 200, 16000);
+
+ QStringList urls;
+ const auto row_size = ui_->keyServerListTable->rowCount();
+ for (int i = 0; i < row_size; i++) {
+ const auto keyserver_url = ui_->keyServerListTable->item(i, 1)->text();
+ urls.push_back(keyserver_url);
+ }
+
+ auto* task = new ListedKeyServerTestTask(urls, timeout, this);
+
+ connect(
+ task,
+ &GpgFrontend::UI::ListedKeyServerTestTask::SignalKeyServerListTestResult,
+ this,
+ [=](std::vector<ListedKeyServerTestTask::KeyServerTestResultType>
+ result) {
+ const auto row_size = ui_->keyServerListTable->rowCount();
+ if (result.size() != row_size) return;
+ ui_->keyServerListTable->blockSignals(true);
+ for (int i = 0; i < row_size; i++) {
+ const auto status = result[i];
+ auto status_iem = ui_->keyServerListTable->item(i, 3);
+ if (status == ListedKeyServerTestTask::kTestResultType_Success) {
+ status_iem->setText(_("Reachable"));
+ status_iem->setForeground(QBrush(QColor::fromRgb(0, 255, 0)));
+ } else {
+ status_iem->setText(_("Not Reachable"));
+ status_iem->setForeground(QBrush(QColor::fromRgb(255, 0, 0)));
+ }
+ }
+ ui_->keyServerListTable->blockSignals(false);
+ });
+
+ // Waiting Dialog
+ auto* waiting_dialog = new QProgressDialog(this);
+ waiting_dialog->setMaximum(0);
+ waiting_dialog->setMinimum(0);
+ auto waiting_dialog_label =
+ new QLabel(QString(_("Test Key Server Connection...")) + "<br /><br />" +
+ _("This test only tests the network connectivity of the key "
+ "server. Passing the test does not mean that the key server "
+ "is functionally available."));
+ waiting_dialog_label->setWordWrap(true);
+ waiting_dialog->setLabel(waiting_dialog_label);
+ waiting_dialog->resize(420, 120);
+ waiting_dialog->setModal(true);
+ connect(task, &Thread::Task::SignalTaskFinished, [=]() {
+ waiting_dialog->close();
+ waiting_dialog->deleteLater();
+ });
+ // Show Waiting Dialog
+ waiting_dialog->show();
+ waiting_dialog->setFocus();
+
+ Thread::TaskRunnerGetter::GetInstance()
+ .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Network)
+ ->PostTask(task);
+}
+
+void KeyserverTab::contextMenuEvent(QContextMenuEvent* event) {
+ QWidget::contextMenuEvent(event);
+ if (ui_->keyServerListTable->selectedItems().length() > 0) {
+ popup_menu_->exec(event->globalPos());
+ }
+}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/dialog/settings/SettingsKeyServer.h b/src/ui/dialog/settings/SettingsKeyServer.h
new file mode 100644
index 00000000..f983e69b
--- /dev/null
+++ b/src/ui/dialog/settings/SettingsKeyServer.h
@@ -0,0 +1,111 @@
+/**
+ * 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 <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
+ *
+ */
+
+#ifndef GPGFRONTEND_SETTINGSKEYSERVER_H
+#define GPGFRONTEND_SETTINGSKEYSERVER_H
+
+#include "ui/GpgFrontendUI.h"
+
+class Ui_KeyServerSettings;
+
+namespace GpgFrontend::UI {
+/**
+ * @brief
+ *
+ */
+class KeyserverTab : public QWidget {
+ Q_OBJECT
+
+ public:
+ /**
+ * @brief Construct a new Keyserver Tab object
+ *
+ * @param parent
+ */
+ explicit KeyserverTab(QWidget* parent = nullptr);
+
+ /**
+ * @brief Set the Settings object
+ *
+ */
+ void SetSettings();
+
+ /**
+ * @brief
+ *
+ */
+ void ApplySettings();
+
+ private:
+ std::shared_ptr<Ui_KeyServerSettings> ui_;
+ QString default_key_server_;
+ QStringList key_server_str_list_;
+ QMenu* popup_menu_{};
+
+ QRegularExpression url_reg_{
+ R"(^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)$)"};
+
+ private slots:
+
+ /**
+ * @brief
+ *
+ */
+ void slot_add_key_server();
+
+ /**
+ * @brief
+ *
+ */
+ void slot_refresh_table();
+
+ /**
+ * @brief
+ *
+ */
+ void slot_test_listed_key_server();
+
+ signals:
+ /**
+ * @brief
+ *
+ * @param needed
+ */
+ void SignalRestartNeeded(bool needed);
+
+ protected:
+ /**
+ * @brief
+ *
+ * @param event
+ */
+ void contextMenuEvent(QContextMenuEvent* event) override;
+};
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_SETTINGSKEYSERVER_H
diff --git a/src/ui/dialog/settings/SettingsNetwork.cpp b/src/ui/dialog/settings/SettingsNetwork.cpp
new file mode 100644
index 00000000..d4edae42
--- /dev/null
+++ b/src/ui/dialog/settings/SettingsNetwork.cpp
@@ -0,0 +1,338 @@
+/**
+ * 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 <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
+ *
+ */
+
+#include "SettingsNetwork.h"
+
+#include "core/function/GlobalSettingStation.h"
+#include "ui/thread/ProxyConnectionTestThread.h"
+#include "ui_NetworkSettings.h"
+
+GpgFrontend::UI::NetworkTab::NetworkTab(QWidget *parent)
+ : QWidget(parent), ui_(std::make_shared<Ui_NetworkSettings>()) {
+ ui_->setupUi(this);
+
+ connect(ui_->enableProxyCheckBox, &QCheckBox::stateChanged, this,
+ [=](int state) { switch_ui_enabled(state == Qt::Checked); });
+
+ connect(
+ ui_->proxyTypeComboBox, &QComboBox::currentTextChanged, this,
+ [=](const QString &current_text) { switch_ui_proxy_type(current_text); });
+
+ connect(ui_->checkProxyConnectionButton, &QPushButton::clicked, this,
+ &NetworkTab::slot_test_proxy_connection_result);
+
+ ui_->proxyGroupBox->setTitle(_("Proxy"));
+ ui_->capabilityGroupBox->setTitle(_("Network Capability"));
+ ui_->operationsGroupBox->setTitle(_("Operations"));
+
+ ui_->enableProxyCheckBox->setText(_("Enable Proxy"));
+ ui_->proxyServerPortLabel->setText(_("Port"));
+
+ ui_->proxyServerAddressLabel->setText(_("Host Address"));
+ ui_->proxyServerPortLabel->setText(_("Port"));
+ ui_->proxyTypeLabel->setText(_("Proxy Type"));
+ ui_->usernameLabel->setText(_("Username"));
+ ui_->passwordLabel->setText(_("Password"));
+
+ ui_->forbidALLCheckBox->setText(_("Forbid all network connection."));
+ ui_->forbidALLCheckBox->setDisabled(true);
+
+ ui_->prohibitUpdateCheck->setText(
+ _("Prohibit checking for version updates when the program starts."));
+ ui_->checkProxyConnectionButton->setText(_("Check Proxy Connection"));
+
+ SetSettings();
+}
+
+void GpgFrontend::UI::NetworkTab::SetSettings() {
+ auto &settings = GlobalSettingStation::GetInstance().GetUISettings();
+
+ try {
+ std::string proxy_host = settings.lookup("proxy.proxy_host");
+ ui_->proxyServerAddressEdit->setText(proxy_host.c_str());
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("proxy_host");
+ }
+
+ try {
+ std::string std_username = settings.lookup("proxy.username");
+ ui_->usernameEdit->setText(std_username.c_str());
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("username");
+ }
+
+ try {
+ std::string std_password = settings.lookup("proxy.password");
+ ui_->passwordEdit->setText(std_password.c_str());
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("password");
+ }
+
+ try {
+ int port = settings.lookup("proxy.port");
+ ui_->portSpin->setValue(port);
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("port");
+ }
+
+ ui_->proxyTypeComboBox->setCurrentText("HTTP");
+ try {
+ std::string proxy_type = settings.lookup("proxy.proxy_type");
+ ui_->proxyTypeComboBox->setCurrentText(proxy_type.c_str());
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("proxy_type");
+ }
+ switch_ui_proxy_type(ui_->proxyTypeComboBox->currentText());
+
+ ui_->enableProxyCheckBox->setCheckState(Qt::Unchecked);
+ try {
+ bool proxy_enable = settings.lookup("proxy.enable");
+ if (proxy_enable)
+ ui_->enableProxyCheckBox->setCheckState(Qt::Checked);
+ else
+ ui_->enableProxyCheckBox->setCheckState(Qt::Unchecked);
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("proxy_enable");
+ }
+
+ {
+ auto state = ui_->enableProxyCheckBox->checkState();
+ switch_ui_enabled(state == Qt::Checked);
+ }
+
+ ui_->forbidALLCheckBox->setCheckState(Qt::Unchecked);
+ try {
+ bool forbid_all_connection =
+ settings.lookup("network.forbid_all_connection");
+ if (forbid_all_connection)
+ ui_->forbidALLCheckBox->setCheckState(Qt::Checked);
+ else
+ ui_->forbidALLCheckBox->setCheckState(Qt::Unchecked);
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("forbid_all_connection");
+ }
+
+ ui_->prohibitUpdateCheck->setCheckState(Qt::Unchecked);
+ try {
+ bool prohibit_update_checking =
+ settings.lookup("network.prohibit_update_checking");
+ if (prohibit_update_checking)
+ ui_->prohibitUpdateCheck->setCheckState(Qt::Checked);
+ else
+ ui_->prohibitUpdateCheck->setCheckState(Qt::Unchecked);
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("prohibit_update_checking");
+ }
+}
+
+void GpgFrontend::UI::NetworkTab::ApplySettings() {
+ LOG(INFO) << "called";
+
+ auto &settings =
+ GpgFrontend::GlobalSettingStation::GetInstance().GetUISettings();
+
+ if (!settings.exists("proxy") ||
+ settings.lookup("proxy").getType() != libconfig::Setting::TypeGroup)
+ settings.add("proxy", libconfig::Setting::TypeGroup);
+
+ auto &proxy = settings["proxy"];
+
+ if (!proxy.exists("proxy_host"))
+ proxy.add("proxy_host", libconfig::Setting::TypeString) =
+ ui_->proxyServerAddressEdit->text().toStdString();
+ else {
+ proxy["proxy_host"] = ui_->proxyServerAddressEdit->text().toStdString();
+ }
+
+ if (!proxy.exists("username"))
+ proxy.add("username", libconfig::Setting::TypeString) =
+ ui_->usernameEdit->text().toStdString();
+ else {
+ proxy["username"] = ui_->usernameEdit->text().toStdString();
+ }
+
+ if (!proxy.exists("password"))
+ proxy.add("password", libconfig::Setting::TypeString) =
+ ui_->passwordEdit->text().toStdString();
+ else {
+ proxy["password"] = ui_->passwordEdit->text().toStdString();
+ }
+
+ if (!proxy.exists("port"))
+ proxy.add("port", libconfig::Setting::TypeInt) = ui_->portSpin->value();
+ else {
+ proxy["port"] = ui_->portSpin->value();
+ }
+
+ if (!proxy.exists("proxy_type"))
+ proxy.add("proxy_type", libconfig::Setting::TypeString) =
+ ui_->proxyTypeComboBox->currentText().toStdString();
+ else {
+ proxy["proxy_type"] = ui_->proxyTypeComboBox->currentText().toStdString();
+ }
+
+ if (!proxy.exists("enable"))
+ proxy.add("enable", libconfig::Setting::TypeBoolean) =
+ ui_->enableProxyCheckBox->isChecked();
+ else {
+ proxy["enable"] = ui_->enableProxyCheckBox->isChecked();
+ }
+
+ if (!settings.exists("network") ||
+ settings.lookup("network").getType() != libconfig::Setting::TypeGroup)
+ settings.add("network", libconfig::Setting::TypeGroup);
+
+ auto &network = settings["network"];
+
+ if (!network.exists("forbid_all_connection"))
+ network.add("forbid_all_connection", libconfig::Setting::TypeBoolean) =
+ ui_->forbidALLCheckBox->isChecked();
+ else {
+ network["forbid_all_connection"] = ui_->forbidALLCheckBox->isChecked();
+ }
+
+ if (!network.exists("prohibit_update_checking"))
+ network.add("prohibit_update_checking", libconfig::Setting::TypeBoolean) =
+ ui_->prohibitUpdateCheck->isChecked();
+ else {
+ network["prohibit_update_checking"] = ui_->prohibitUpdateCheck->isChecked();
+ }
+
+ apply_proxy_settings();
+
+ LOG(INFO) << "done";
+}
+
+void GpgFrontend::UI::NetworkTab::slot_test_proxy_connection_result() {
+ apply_proxy_settings();
+
+ bool ok;
+ auto url = QInputDialog::getText(this, _("Test Server Url Accessibility"),
+ tr("Server Url"), QLineEdit::Normal,
+ "https://", &ok);
+ if (ok && !url.isEmpty()) {
+ auto thread = new ProxyConnectionTestThread(url, 800, this);
+ connect(thread,
+ &GpgFrontend::UI::ProxyConnectionTestThread::
+ SignalProxyConnectionTestResult,
+ this, [=](const QString &result) {
+ if (result == "Reachable") {
+ QMessageBox::information(this, _("Success"),
+ _("Successfully connect to the target "
+ "server through the proxy server."));
+ } else {
+ QMessageBox::critical(
+ this, _("Failed"),
+ _("Unable to connect to the target server through the "
+ "proxy server. Proxy settings may be invalid."));
+ }
+ });
+ connect(thread, &QThread::finished, thread, &QThread::deleteLater);
+
+ // Waiting Dialog
+ auto *waiting_dialog = new QProgressDialog(this);
+ waiting_dialog->setMaximum(0);
+ waiting_dialog->setMinimum(0);
+ auto waiting_dialog_label = new QLabel(
+ QString(_("Test Proxy Server Connection...")) + "<br /><br />" +
+ _("Is using your proxy settings to access the url. Note that this test "
+ "operation will apply your proxy settings to the entire software."));
+ waiting_dialog_label->setWordWrap(true);
+ waiting_dialog->setLabel(waiting_dialog_label);
+ waiting_dialog->resize(420, 120);
+ connect(thread, &QThread::finished, [=]() {
+ waiting_dialog->finished(0);
+ waiting_dialog->deleteLater();
+ });
+ connect(waiting_dialog, &QProgressDialog::canceled, [=]() {
+ LOG(INFO) << "cancel clicked";
+ if (thread->isRunning()) thread->terminate();
+ });
+
+ // Show Waiting Dialog
+ waiting_dialog->show();
+ waiting_dialog->setFocus();
+
+ thread->start();
+ QEventLoop loop;
+ connect(thread, &QThread::finished, &loop, &QEventLoop::quit);
+ loop.exec();
+ }
+}
+
+void GpgFrontend::UI::NetworkTab::apply_proxy_settings() {
+ // apply settings
+ QNetworkProxy _proxy;
+ if (ui_->enableProxyCheckBox->isChecked() &&
+ proxy_type_ != QNetworkProxy::DefaultProxy) {
+ _proxy.setType(proxy_type_);
+ _proxy.setHostName(ui_->proxyServerAddressEdit->text());
+ _proxy.setPort(ui_->portSpin->value());
+ if (!ui_->usernameEdit->text().isEmpty()) {
+ _proxy.setUser(ui_->usernameEdit->text());
+ _proxy.setPassword(ui_->passwordEdit->text());
+ }
+ } else {
+ _proxy.setType(proxy_type_);
+ }
+
+ QNetworkProxy::setApplicationProxy(_proxy);
+}
+
+void GpgFrontend::UI::NetworkTab::switch_ui_enabled(bool enabled) {
+ ui_->proxyServerAddressEdit->setDisabled(!enabled);
+ ui_->portSpin->setDisabled(!enabled);
+ ui_->proxyTypeComboBox->setDisabled(!enabled);
+ ui_->usernameEdit->setDisabled(!enabled);
+ ui_->passwordEdit->setDisabled(!enabled);
+ ui_->checkProxyConnectionButton->setDisabled(!enabled);
+ if (!enabled) proxy_type_ = QNetworkProxy::NoProxy;
+}
+
+void GpgFrontend::UI::NetworkTab::switch_ui_proxy_type(
+ const QString &type_text) {
+ if (type_text == "HTTP") {
+ ui_->proxyServerAddressEdit->setDisabled(false);
+ ui_->portSpin->setDisabled(false);
+ ui_->usernameEdit->setDisabled(false);
+ ui_->passwordEdit->setDisabled(false);
+ proxy_type_ = QNetworkProxy::HttpProxy;
+ } else if (type_text == "Socks5") {
+ ui_->proxyServerAddressEdit->setDisabled(false);
+ ui_->portSpin->setDisabled(false);
+ ui_->usernameEdit->setDisabled(false);
+ ui_->passwordEdit->setDisabled(false);
+ proxy_type_ = QNetworkProxy::Socks5Proxy;
+ } else {
+ ui_->proxyServerAddressEdit->setDisabled(true);
+ ui_->portSpin->setDisabled(true);
+ ui_->usernameEdit->setDisabled(true);
+ ui_->passwordEdit->setDisabled(true);
+ proxy_type_ = QNetworkProxy::DefaultProxy;
+ }
+}
diff --git a/src/ui/dialog/settings/SettingsNetwork.h b/src/ui/dialog/settings/SettingsNetwork.h
new file mode 100644
index 00000000..d4c0d00d
--- /dev/null
+++ b/src/ui/dialog/settings/SettingsNetwork.h
@@ -0,0 +1,94 @@
+/**
+ * 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 <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
+ *
+ */
+
+#ifndef GPGFRONTEND_SETTINGSNETWORK_H
+#define GPGFRONTEND_SETTINGSNETWORK_H
+
+#include "ui/GpgFrontendUI.h"
+
+class Ui_NetworkSettings;
+
+namespace GpgFrontend::UI {
+class NetworkTab : public QWidget {
+ Q_OBJECT
+
+ public:
+ /**
+ * @brief Construct a new Network Tab object
+ *
+ * @param parent
+ */
+ explicit NetworkTab(QWidget* parent = nullptr);
+
+ /**
+ * @brief Set the Settings object
+ *
+ */
+ void SetSettings();
+
+ /**
+ * @brief
+ *
+ */
+ void ApplySettings();
+
+ private slots:
+
+ /**
+ * @brief
+ *
+ */
+ void slot_test_proxy_connection_result();
+
+ private:
+ std::shared_ptr<Ui_NetworkSettings> ui_; ///<
+ QNetworkProxy::ProxyType proxy_type_ = QNetworkProxy::HttpProxy; ///<
+
+ /**
+ * @brief
+ *
+ */
+ void apply_proxy_settings();
+
+ /**
+ * @brief
+ *
+ * @param enabled
+ */
+ void switch_ui_enabled(bool enabled);
+
+ /**
+ * @brief
+ *
+ * @param type_text
+ */
+ void switch_ui_proxy_type(const QString& type_text);
+};
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_SETTINGSNETWORK_H