aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt21
-rw-r--r--src/MainWindow.cpp2
-rw-r--r--src/advance/CMakeLists.txt6
-rw-r--r--src/advance/UnknownSignersChecker.cpp81
-rw-r--r--src/gpg/CMakeLists.txt1
-rw-r--r--src/gpg/GpgConstants.cpp1
-rw-r--r--src/gpg/GpgContext.cpp1234
-rw-r--r--src/gpg/GpgFileOpera.cpp7
-rw-r--r--src/gpg/GpgInfo.cpp (renamed from src/ui/keygen/KeygenThread.cpp)13
-rw-r--r--src/gpg/GpgUID.cpp26
-rw-r--r--src/gpg/gpg_context/GpgContext.cpp410
-rw-r--r--src/gpg/gpg_context/GpgContextBasicOpera.cpp315
-rw-r--r--src/gpg/gpg_context/GpgContextKeyInfo.cpp110
-rw-r--r--src/gpg/gpg_context/GpgContextKeyOpera.cpp410
-rw-r--r--src/gpg/gpg_context/GpgContextSubkeyOpera.cpp61
-rw-r--r--src/gpg/gpg_context/GpgContextUIDOpera.cpp80
-rw-r--r--src/gpg/result_analyse/DecryptResultAnalyse.cpp67
-rw-r--r--src/gpg/result_analyse/EncryptResultAnalyse.cpp49
-rw-r--r--src/gpg/result_analyse/ResultAnalyse.cpp26
-rw-r--r--src/gpg/result_analyse/SignResultAnalyse.cpp53
-rw-r--r--src/gpg/result_analyse/VerifyResultAnalyse.cpp76
-rw-r--r--src/main.cpp4
-rw-r--r--src/server/BaseAPI.cpp70
-rw-r--r--src/server/CMakeLists.txt7
-rw-r--r--src/server/ComUtils.cpp197
-rw-r--r--src/server/api/PubkeyGetter.cpp96
-rw-r--r--src/server/api/PubkeyUploader.cpp106
-rw-r--r--src/ui/CMakeLists.txt1
-rwxr-xr-xsrc/ui/FileEncryptionDialog.cpp2
-rwxr-xr-xsrc/ui/KeyMgmt.cpp106
-rw-r--r--src/ui/KeyUploadDialog.cpp2
-rwxr-xr-xsrc/ui/SettingsDialog.cpp777
-rw-r--r--src/ui/ShowCopyDialog.cpp53
-rw-r--r--src/ui/Wizard.cpp242
-rw-r--r--src/ui/help/AboutDialog.cpp54
-rw-r--r--src/ui/help/VersionCheckThread.cpp26
-rw-r--r--src/ui/keygen/KeygenDialog.cpp42
-rw-r--r--src/ui/keygen/SubkeyGenerateDialog.cpp41
-rw-r--r--src/ui/keygen/SubkeyGenerateThread.cpp36
-rw-r--r--src/ui/keypair_details/EditSubKeyDialog.cpp26
-rw-r--r--src/ui/keypair_details/KeyPairDetailTab.cpp18
-rw-r--r--src/ui/keypair_details/KeyPairSubkeyTab.cpp3
-rw-r--r--src/ui/keypair_details/KeyUIDSignDialog.cpp3
-rw-r--r--src/ui/main_window/MainWindowFileSlotFunction.cpp610
-rw-r--r--src/ui/main_window/MainWindowServerSlotFunction.cpp238
-rw-r--r--src/ui/main_window/MainWindowSlotFunction.cpp774
-rw-r--r--src/ui/settings/SettingsAdvanced.cpp67
-rw-r--r--src/ui/settings/SettingsAppearance.cpp187
-rw-r--r--src/ui/settings/SettingsDialog.cpp205
-rw-r--r--src/ui/settings/SettingsGeneral.cpp358
-rw-r--r--src/ui/settings/SettingsKeyServer.cpp148
-rw-r--r--src/ui/settings/SettingsSendMail.cpp193
-rw-r--r--src/ui/widgets/EditorPage.cpp2
-rw-r--r--src/ui/widgets/InfoBoardWidget.cpp37
-rw-r--r--src/ui/widgets/KeyList.cpp150
-rw-r--r--src/ui/widgets/SignersPicker.cpp59
56 files changed, 4730 insertions, 3259 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 3b225a09..200f5beb 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,8 +1,8 @@
-set(ALL_SOURCE_FILE)
-
add_subdirectory(gpg)
add_subdirectory(ui)
add_subdirectory(smtp)
+add_subdirectory(server)
+add_subdirectory(advance)
aux_source_directory(. BASE_SOURCE)
@@ -90,7 +90,7 @@ if(${CMAKE_BUILD_TYPE} STREQUAL "Release")
add_executable(${AppName} MACOSX_BUNDLE ${ICON_RESOURCE} ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS})
set_target_properties(${AppName} PROPERTIES
BUNDLE True
- MACOSX_BUNDLE_GUI_IDENTIFIER org.gnupg.gpgfrontend
+ MACOSX_BUNDLE_GUI_IDENTIFIER pub.gpgfrontend.gpgfrontend
MACOSX_BUNDLE_BUNDLE_NAME ${AppName}
MACOSX_BUNDLE_LONG_VERSION_STRING ${BUILD_VERSION}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION}
@@ -121,23 +121,26 @@ else()
add_executable(${AppName} ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS})
endif()
+set(GPGFRONTEND_LIBS smtp gpgfrontend-ui advance server gpg)
+set(QT_DEPENDENCY_LIBS Qt5::Network Qt5::PrintSupport Qt5::Widgets Qt5::Test Qt5::Core)
+
IF (MINGW)
message(STATUS "Link Application Static Library For MINGW")
target_link_libraries(${AppName}
- smtp gpgfrontend-ui gpg
- Qt5::Network Qt5::PrintSupport Qt5::Widgets Qt5::Test Qt5::Core
+ ${GPGFRONTEND_LIBS}
+ ${QT_DEPENDENCY_LIBS}
crypto ssl)
elseif(APPLE)
message(STATUS "Link Application Static Library For macOS")
target_link_libraries(${AppName}
- smtp gpgfrontend-ui gpg
- Qt5::Network Qt5::PrintSupport Qt5::Widgets Qt5::Test Qt5::Core
+ ${GPGFRONTEND_LIBS}
+ ${QT_DEPENDENCY_LIBS}
crypto ssl)
else()
message(STATUS "Link Application Static Library For UNIX")
target_link_libraries(${AppName}
- smtp gpgfrontend-ui gpg
- Qt5::Network Qt5::PrintSupport Qt5::Widgets Qt5::Test Qt5::Core
+ ${GPGFRONTEND_LIBS}
+ ${QT_DEPENDENCY_LIBS}
crypto ssl pthread)
endif()
diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp
index eb8b96b1..73f55672 100644
--- a/src/MainWindow.cpp
+++ b/src/MainWindow.cpp
@@ -51,7 +51,7 @@ MainWindow::MainWindow()
auto version_thread = new VersionCheckThread(replay);
- connect(version_thread, SIGNAL(finished(QPrivateSignal)), version_thread, SLOT(deleteLater()));
+ connect(version_thread, SIGNAL(finished()), version_thread, SLOT(deleteLater()));
connect(version_thread, SIGNAL(upgradeVersion(const QString &, const QString &)), this, SLOT(slotVersionUpgrade(const QString &, const QString &)));
version_thread->start();
diff --git a/src/advance/CMakeLists.txt b/src/advance/CMakeLists.txt
new file mode 100644
index 00000000..696fc8e5
--- /dev/null
+++ b/src/advance/CMakeLists.txt
@@ -0,0 +1,6 @@
+aux_source_directory(. ADVANCE_SOURCE)
+
+add_library(advance STATIC ${ADVANCE_SOURCE})
+
+target_link_libraries(advance
+ Qt5::Network Qt5::Widgets Qt5::Core) \ No newline at end of file
diff --git a/src/advance/UnknownSignersChecker.cpp b/src/advance/UnknownSignersChecker.cpp
new file mode 100644
index 00000000..1b087b5c
--- /dev/null
+++ b/src/advance/UnknownSignersChecker.cpp
@@ -0,0 +1,81 @@
+/**
+ * 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.
+ *
+ * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "advance/UnknownSignersChecker.h"
+
+
+UnknownSignersChecker::UnknownSignersChecker(GpgME::GpgContext *ctx, gpgme_verify_result_t result) :
+ appPath(qApp->applicationDirPath()), settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini"), mCtx(ctx),
+ mResult(result) {
+
+}
+
+void UnknownSignersChecker::start() {
+
+ auto sign = mResult->signatures;
+ bool canContinue = true;
+
+ while (sign && canContinue) {
+
+ switch (gpg_err_code(sign->status)) {
+ case GPG_ERR_BAD_SIGNATURE:
+ break;
+ case GPG_ERR_NO_ERROR:
+ if (!(sign->status & GPGME_SIGSUM_KEY_MISSING))
+ check_signer(sign);
+ break;
+ case GPG_ERR_NO_PUBKEY:
+
+ case GPG_ERR_CERT_REVOKED:
+ case GPG_ERR_SIG_EXPIRED:
+ case GPG_ERR_KEY_EXPIRED:
+ check_signer(sign);
+ break;
+ case GPG_ERR_GENERAL:
+ canContinue = false;
+ break;
+ default:
+ break;
+ }
+ sign = sign->next;
+ }
+
+ if(!unknownFprs.isEmpty()) {
+ PubkeyGetter pubkeyGetter(mCtx, unknownFprs);
+ pubkeyGetter.start();
+ if (!pubkeyGetter.result()) {
+
+ }
+ }
+}
+
+void UnknownSignersChecker::check_signer(gpgme_signature_t sign) {
+
+ auto key = mCtx->getKeyByFpr(sign->fpr);
+ if (!key.good) {
+ qDebug() << "Find Unknown FingerPrint " << sign->fpr;
+ unknownFprs.append(sign->fpr);
+ }
+
+}
diff --git a/src/gpg/CMakeLists.txt b/src/gpg/CMakeLists.txt
index 49e98b23..2bcacade 100644
--- a/src/gpg/CMakeLists.txt
+++ b/src/gpg/CMakeLists.txt
@@ -1,4 +1,5 @@
aux_source_directory(./result_analyse GPG_SOURCE)
+aux_source_directory(./gpg_context GPG_SOURCE)
aux_source_directory(. GPG_SOURCE)
add_library(gpg STATIC ${GPG_SOURCE})
diff --git a/src/gpg/GpgConstants.cpp b/src/gpg/GpgConstants.cpp
index 1ed06182..1d59dab5 100644
--- a/src/gpg/GpgConstants.cpp
+++ b/src/gpg/GpgConstants.cpp
@@ -30,4 +30,5 @@ const char *GpgConstants::PGP_SIGNED_BEGIN = "-----BEGIN PGP SIGNED MESSAGE-----
const char *GpgConstants::PGP_SIGNED_END = "-----END PGP SIGNATURE-----";
const char *GpgConstants::PGP_SIGNATURE_BEGIN = "-----BEGIN PGP SIGNATURE-----";
const char *GpgConstants::PGP_SIGNATURE_END = "-----END PGP SIGNATURE-----";
+const char *GpgConstants::GPG_FRONTEND_SHORT_CRYPTO_HEAD = "GpgF_Scpt://";
diff --git a/src/gpg/GpgContext.cpp b/src/gpg/GpgContext.cpp
deleted file mode 100644
index 0462433d..00000000
--- a/src/gpg/GpgContext.cpp
+++ /dev/null
@@ -1,1234 +0,0 @@
-/**
- * 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.
- *
- * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
- *
- * The initial version of the source code is inherited from gpg4usb-team.
- * Their source code version also complies with GNU General Public License.
- *
- * The source code version of this software was modified and released
- * by Saturneric<[email protected]> starting on May 12, 2021.
- *
- */
-
-#include "gpg/GpgContext.h"
-
-#include <functional>
-#include <unistd.h> /* contains read/write */
-
-#ifdef _WIN32
-
-#include <windows.h>
-
-#endif
-
-#define INT2VOIDP(i) (void*)(uintptr_t)(i)
-
-namespace GpgME {
-
-/** Constructor
- * Set up gpgme-context, set paths to app-run path
- */
- GpgContext::GpgContext() {
- /** get application path */
- QString appPath = qApp->applicationDirPath();
-
- /** The function `gpgme_check_version' must be called before any other
- * function in the library, because it initializes the thread support
- * subsystem in GPGME. (from the info page) */
- gpgme_check_version(nullptr);
-
- // the locale set here is used for the other setlocale calls which have nullptr
- // -> nullptr means use default, which is configured here
- setlocale(LC_ALL, settings.value("int/lang").toLocale().name().toUtf8().constData());
-
- /** set locale, because tests do also */
- gpgme_set_locale(nullptr, LC_CTYPE, setlocale(LC_CTYPE, nullptr));
- //qDebug() << "Locale set to" << LC_CTYPE << " - " << setlocale(LC_CTYPE, nullptr);
-#ifndef _WIN32
- gpgme_set_locale(nullptr, LC_MESSAGES, setlocale(LC_MESSAGES, nullptr));
-#endif
-
- err = gpgme_new(&mCtx);
- checkErr(err);
-
- gpgme_engine_info_t engineInfo;
- engineInfo = gpgme_ctx_get_engine_info(mCtx);
-
- // Check ENV before running
- bool check_pass = false, find_openpgp = false, find_gpgconf = false, find_assuan = false, find_cms = false;
- while (engineInfo != nullptr) {
- qDebug() << gpgme_get_protocol_name(engineInfo->protocol) << engineInfo->file_name << engineInfo->protocol
- << engineInfo->home_dir << engineInfo->version;
- if (engineInfo->protocol == GPGME_PROTOCOL_GPGCONF && strcmp(engineInfo->version, "1.0.0") != 0)
- find_gpgconf = true;
- if (engineInfo->protocol == GPGME_PROTOCOL_OpenPGP && strcmp(engineInfo->version, "1.0.0") != 0) {
- gpgExec = engineInfo->file_name;
- find_openpgp = true;
- }
- if (engineInfo->protocol == GPGME_PROTOCOL_CMS && strcmp(engineInfo->version, "1.0.0") != 0)
- find_cms = true;
- if (engineInfo->protocol == GPGME_PROTOCOL_ASSUAN)
- find_assuan = true;
-
- engineInfo = engineInfo->next;
- }
-
- if (find_gpgconf && find_openpgp && find_cms && find_assuan)
- check_pass = true;
-
- if (!check_pass) {
- good = false;
- return;
- } else good = true;
-
-
- /** Setting the output type must be done at the beginning */
- /** think this means ascii-armor --> ? */
- gpgme_set_armor(mCtx, 1);
- /** passphrase-callback */
- gpgme_set_passphrase_cb(mCtx, passphraseCb, this);
-
- /** check if app is called with -d from command line */
- if (qApp->arguments().contains("-d")) {
- qDebug() << "gpgme_data_t debug on";
- debug = true;
- } else {
- debug = false;
- }
-
- connect(this, SIGNAL(signalKeyDBChanged()),
- this, SLOT(slotRefreshKeyList()), Qt::DirectConnection);
- connect(this, SIGNAL(signalKeyUpdated(QString)),
- this, SLOT(slotUpdateKeyList(QString)), Qt::DirectConnection);
- slotRefreshKeyList();
- }
-
-/** Destructor
- * Release gpgme-context
- */
- GpgContext::~GpgContext() {
- if (mCtx) gpgme_release(mCtx);
- mCtx = nullptr;
- }
-
- bool GpgContext::isGood() const {
- return good;
- }
-
-/** Import Key from QByteArray
- *
- */
- GpgImportInformation GpgContext::importKey(QByteArray inBuffer) {
- auto *importInformation = new GpgImportInformation();
- err = gpgme_data_new_from_mem(&in, inBuffer.data(), inBuffer.size(), 1);
- checkErr(err);
- err = gpgme_op_import(mCtx, in);
- gpgme_import_result_t result;
-
- result = gpgme_op_import_result(mCtx);
- if (result->unchanged) {
- importInformation->unchanged = result->unchanged;
- }
- if (result->considered) {
- importInformation->considered = result->considered;
- }
- if (result->no_user_id) {
- importInformation->no_user_id = result->no_user_id;
- }
- if (result->imported) {
- importInformation->imported = result->imported;
- }
- if (result->imported_rsa) {
- importInformation->imported_rsa = result->imported_rsa;
- }
- if (result->unchanged) {
- importInformation->unchanged = result->unchanged;
- }
- if (result->new_user_ids) {
- importInformation->new_user_ids = result->new_user_ids;
- }
- if (result->new_sub_keys) {
- importInformation->new_sub_keys = result->new_sub_keys;
- }
- if (result->new_signatures) {
- importInformation->new_signatures = result->new_signatures;
- }
- if (result->new_revocations) {
- importInformation->new_revocations = result->new_revocations;
- }
- if (result->secret_read) {
- importInformation->secret_read = result->secret_read;
- }
- if (result->secret_imported) {
- importInformation->secret_imported = result->secret_imported;
- }
- if (result->secret_unchanged) {
- importInformation->secret_unchanged = result->secret_unchanged;
- }
- if (result->not_imported) {
- importInformation->not_imported = result->not_imported;
- }
- gpgme_import_status_t status = result->imports;
- while (status != nullptr) {
- GpgImportedKey key;
- key.importStatus = static_cast<int>(status->status);
- key.fpr = status->fpr;
- importInformation->importedKeys.emplace_back(key);
- status = status->next;
- }
- checkErr(err);
- emit signalKeyDBChanged();
- gpgme_data_release(in);
- return *importInformation;
- }
-
-/** Generate New Key with values params
- *
- */
- bool GpgContext::generateKey(GenKeyInfo *params) {
-
- auto userid_utf8 = params->getUserid().toUtf8();
- const char *userid = userid_utf8.constData();
- auto algo_utf8 = (params->getAlgo() + params->getKeySizeStr()).toUtf8();
- const char *algo = algo_utf8.constData();
- unsigned long expires = QDateTime::currentDateTime().secsTo(params->getExpired());
- unsigned int flags = 0;
-
- if (!params->isSubKey()) {
- flags |= GPGME_CREATE_CERT;
- }
-
- if (params->isAllowEncryption()) {
- flags |= GPGME_CREATE_ENCR;
- }
-
- if (params->isAllowSigning()) {
- flags |= GPGME_CREATE_SIGN;
- }
-
- if (params->isAllowAuthentication()) {
- flags |= GPGME_CREATE_AUTH;
- }
-
- if (params->isNonExpired()) {
- flags |= GPGME_CREATE_NOEXPIRE;
- }
-
- if (params->isNoPassPhrase()) {
- flags |= GPGME_CREATE_NOPASSWD;
- }
-
- err = gpgme_op_createkey(mCtx, userid, algo, 0, expires, nullptr, flags);
-
- if (err != GPG_ERR_NO_ERROR) {
- checkErr(err);
- return false;
- } else {
- emit signalKeyDBChanged();
- return true;
- }
- }
-
-/** Export Key to QByteArray
- *
- */
- bool GpgContext::exportKeys(QStringList *uidList, QByteArray *outBuffer) {
- size_t read_bytes;
- gpgme_data_t dataOut = nullptr;
- outBuffer->resize(0);
-
- if (uidList->count() == 0) {
- QMessageBox::critical(nullptr, "Export Keys Error", "No Keys Selected");
- return false;
- }
-
- for (int i = 0; i < uidList->count(); i++) {
- err = gpgme_data_new(&dataOut);
- checkErr(err);
-
- err = gpgme_op_export(mCtx, uidList->at(i).toUtf8().constData(), 0, dataOut);
- checkErr(err);
-
- read_bytes = gpgme_data_seek(dataOut, 0, SEEK_END);
-
- err = readToBuffer(dataOut, outBuffer);
- checkErr(err);
- gpgme_data_release(dataOut);
- }
- return true;
- }
-
- /**
- * List all availabe Keys (VERY much like kgpgme)
- */
- void GpgContext::fetch_keys() {
-
- gpgme_error_t gpgmeError;
-
- gpgme_key_t key;
-
- qDebug() << "Clear List and Map";
-
- mKeyList.clear();
- mKeyMap.clear();
-
- auto &keys = mKeyList;
- auto &keys_map = mKeyMap;
-
- qDebug() << "Set Keylist Mode";
-
- gpgmeError = gpgme_set_keylist_mode(mCtx,
- GPGME_KEYLIST_MODE_LOCAL
- | GPGME_KEYLIST_MODE_WITH_SECRET
- | GPGME_KEYLIST_MODE_SIGS
- | GPGME_KEYLIST_MODE_SIG_NOTATIONS
- | GPGME_KEYLIST_MODE_WITH_TOFU);
- if (gpg_err_code(gpgmeError) != GPG_ERR_NO_ERROR) {
- checkErr(gpgmeError);
- return;
- }
-
- qDebug() << "Operate KeyList Start";
-
- gpgmeError = gpgme_op_keylist_start(mCtx, nullptr, 0);
- if (gpg_err_code(gpgmeError) != GPG_ERR_NO_ERROR) {
- checkErr(gpgmeError);
- return;
- }
-
- qDebug() << "Start Loop";
-
- while ((gpgmeError = gpgme_op_keylist_next(mCtx, &key)) == GPG_ERR_NO_ERROR) {
- if (!key->subkeys)
- continue;
-
- qDebug() << "Append Key" << key->subkeys->keyid;
-
- keys.emplace_back(key);
- keys_map.insert(keys.back().id, &keys.back());
- gpgme_key_unref(key);
- }
-
-
- if (gpg_err_code(gpgmeError) != GPG_ERR_EOF) {
- checkErr(gpgmeError);
- return;
- }
-
- qDebug() << "Operate KeyList End";
-
- gpgmeError = gpgme_op_keylist_end(mCtx);
- if (gpg_err_code(gpgmeError) != GPG_ERR_NO_ERROR) {
- checkErr(gpgmeError);
- return;
- }
-
- gpgmeError = gpgme_op_keylist_end(mCtx);
- if (gpg_err_code(gpgmeError) != GPG_ERR_NO_ERROR) {
- checkErr(gpgmeError);
- return;
- }
-
- mKeyList = keys;
- }
-
-/** Delete keys
- */
-
- void GpgContext::deleteKeys(QStringList *uidList) {
-
- gpgme_error_t error;
- gpgme_key_t key;
-
- for (const auto &tmp : *uidList) {
-
- error = gpgme_op_keylist_start(mCtx, tmp.toUtf8().constData(), 0);
- if (error != GPG_ERR_NO_ERROR) {
- checkErr(error);
- continue;
- }
-
- error = gpgme_op_keylist_next(mCtx, &key);
- if (error != GPG_ERR_NO_ERROR) {
- checkErr(error);
- continue;
- }
-
- error = gpgme_op_keylist_end(mCtx);
- if (error != GPG_ERR_NO_ERROR) {
- checkErr(error);
- continue;
- }
-
- error = gpgme_op_delete(mCtx, key, 1);
- if (error != GPG_ERR_NO_ERROR) {
- checkErr(error);
- continue;
- }
-
- }
- emit signalKeyDBChanged();
- }
-
-/** Encrypt inBuffer for reciepients-uids, write
- * result to outBuffer
- */
- gpg_error_t GpgContext::encrypt(QVector<GpgKey> &keys, const QByteArray &inBuffer, QByteArray *outBuffer,
- gpgme_encrypt_result_t *result) {
-
- gpgme_data_t dataIn = nullptr, dataOut = nullptr;
- outBuffer->resize(0);
-
- //gpgme_encrypt_result_t e_result;
- gpgme_key_t recipients[keys.count() + 1];
-
- int index = 0;
- for (const auto &key : keys) {
- recipients[index++] = key.key_refer;
- }
-
- //Last entry dataIn array has to be nullptr
- recipients[keys.count()] = nullptr;
-
- //If the last parameter isnt 0, a private copy of data is made
- if (mCtx) {
- err = gpgme_data_new_from_mem(&dataIn, inBuffer.data(), inBuffer.size(), 1);
- checkErr(err);
- if (!err) {
- err = gpgme_data_new(&dataOut);
- checkErr(err);
- if (!err) {
- err = gpgme_op_encrypt(mCtx, recipients, GPGME_ENCRYPT_ALWAYS_TRUST, dataIn, dataOut);
- checkErr(err);
- if (!err) {
- err = readToBuffer(dataOut, outBuffer);
- checkErr(err);
- }
- }
- }
- }
- if (dataIn) {
- gpgme_data_release(dataIn);
- }
- if (dataOut) {
- gpgme_data_release(dataOut);
- }
-
- if (result != nullptr) {
- *result = gpgme_op_encrypt_result(mCtx);
- }
- return err;
- }
-
-/** Decrypt QByteAarray, return QByteArray
- * mainly from http://basket.kde.org/ (kgpgme.cpp)
- */
- gpgme_error_t
- GpgContext::decrypt(const QByteArray &inBuffer, QByteArray *outBuffer, gpgme_decrypt_result_t *result) {
- gpgme_data_t dataIn = nullptr, dataOut = nullptr;
- gpgme_decrypt_result_t m_result = nullptr;
-
- outBuffer->resize(0);
- if (mCtx != nullptr) {
- err = gpgme_data_new_from_mem(&dataIn, inBuffer.data(), inBuffer.size(), 1);
- if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) {
- err = gpgme_data_new(&dataOut);
- if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) {
- err = gpgme_op_decrypt(mCtx, dataIn, dataOut);
- m_result = gpgme_op_decrypt_result(mCtx);
- if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) {
- err = readToBuffer(dataOut, outBuffer);
- }
- }
- }
- }
-
- if (!settings.value("general/rememberPassword").toBool()) {
- clearPasswordCache();
- }
-
- if (dataIn) {
- gpgme_data_release(dataIn);
- }
- if (dataOut) {
- gpgme_data_release(dataOut);
- }
-
- if (result != nullptr) {
- *result = m_result;
- }
- return err;
- }
-
-/** Read gpgme-Data to QByteArray
- * mainly from http://basket.kde.org/ (kgpgme.cpp)
- */
-#define BUF_SIZE (32 * 1024)
-
- gpgme_error_t GpgContext::readToBuffer(gpgme_data_t dataIn, QByteArray *outBuffer) {
- off_t ret;
- gpgme_error_t gpgErrNoError = GPG_ERR_NO_ERROR;
-
- ret = gpgme_data_seek(dataIn, 0, SEEK_SET);
- if (ret) {
- gpgErrNoError = gpgme_err_code_from_errno(errno);
- checkErr(gpgErrNoError, "failed dataseek dataIn readToBuffer");
- } else {
- char buf[BUF_SIZE + 2];
-
- while ((ret = gpgme_data_read(dataIn, buf, BUF_SIZE)) > 0) {
- const size_t size = outBuffer->size();
- outBuffer->resize(static_cast<int>(size + ret));
- memcpy(outBuffer->data() + size, buf, ret);
- }
- if (ret < 0) {
- gpgErrNoError = gpgme_err_code_from_errno(errno);
- checkErr(gpgErrNoError, "failed data_read dataIn readToBuffer");
- }
- }
- return gpgErrNoError;
- }
-
-/** The Passphrase window, if not provided by env-Var GPG_AGENT_INFO
- * originally copied from http://basket.kde.org/ (kgpgme.cpp), but modified
- */
- gpgme_error_t GpgContext::passphraseCb(void *hook, const char *uid_hint,
- const char *passphrase_info,
- int last_was_bad, int fd) {
- auto *gpg = static_cast<GpgContext *>(hook);
- return gpg->passphrase(uid_hint, passphrase_info, last_was_bad, fd);
- }
-
- gpgme_error_t GpgContext::passphrase(const char *uid_hint,
- const char * /*passphrase_info*/,
- int last_was_bad, int fd) {
- gpgme_error_t returnValue = GPG_ERR_CANCELED;
- QString passwordDialogMessage;
- QString gpgHint = QString::fromUtf8(uid_hint);
- bool result;
-
-#ifdef _WIN32
- DWORD written;
- auto hd = INT2VOIDP(fd);
-#endif
-
- if (last_was_bad) {
- passwordDialogMessage += "<i>" + tr("Wrong password") + ".</i><br><br>\n\n";
- clearPasswordCache();
- }
-
- /** if uid provided */
- if (!gpgHint.isEmpty()) {
- // remove UID, leave only username & email
- gpgHint.remove(0, gpgHint.indexOf(" "));
- passwordDialogMessage += "<b>" + tr("Enter Password for") + "</b><br>" + gpgHint + "<br>";
- }
-
- if (mPasswordCache.isEmpty()) {
- QString password = QInputDialog::getText(QApplication::activeWindow(), tr("Enter Password"),
- passwordDialogMessage, QLineEdit::Password,
- "", &result);
-
- if (result) mPasswordCache = password.toUtf8();
- } else {
- result = true;
- }
-
- if (result) {
-
-#ifndef _WIN32
- if (write(fd, mPasswordCache.data(), mPasswordCache.length()) == -1) {
- qDebug() << "something is terribly broken";
- }
-#else
- WriteFile(hd, mPasswordCache.data(), mPasswordCache.length(), &written, 0);
-#endif
-
- returnValue = GPG_ERR_NO_ERROR;
- }
-
-#ifndef _WIN32
- if (write(fd, "\n", 1) == -1) {
- qDebug() << "something is terribly broken";
- }
-#else
- WriteFile(hd, "\n", 1, &written, 0);
-
- /* program will hang on cancel if hd not closed */
- if (!result) {
- CloseHandle(hd);
- }
-#endif
-
- return returnValue;
- }
-
-/** also from kgpgme.cpp, seems to clear password from mem */
- void GpgContext::clearPasswordCache() {
- if (mPasswordCache.size() > 0) {
- mPasswordCache.fill('\0');
- mPasswordCache.truncate(0);
- }
- }
-
-// error-handling
- void GpgContext::checkErr(gpgme_error_t gpgmeError, const QString &comment) {
- //if (gpgmeError != GPG_ERR_NO_ERROR && gpgmeError != GPG_ERR_CANCELED) {
- if (gpgmeError != GPG_ERR_NO_ERROR) {
- qDebug() << "[Error " << gpg_err_code(gpgmeError)
- << "] Source: " << gpgme_strsource(gpgmeError) << " Description: " << gpgErrString(gpgmeError);
- }
- }
-
- void GpgContext::checkErr(gpgme_error_t gpgmeError) {
- //if (gpgmeError != GPG_ERR_NO_ERROR && gpgmeError != GPG_ERR_CANCELED) {
- if (gpg_err_code(gpgmeError) != GPG_ERR_NO_ERROR) {
- qDebug() << "[Error " << gpg_err_code(gpgmeError)
- << "] Source: " << gpgme_strsource(gpgmeError) << " Description: " << gpgErrString(gpgmeError);
- }
- }
-
- QString GpgContext::gpgErrString(gpgme_error_t err) {
- return QString::fromUtf8(gpgme_strerror(err));
- }
-
- bool GpgContext::exportSecretKey(const GpgKey &key, QByteArray *outBuffer) {
- qDebug() << "Export Secret Key" << key.id;
- gpgme_key_t target_key[2] = {
- key.key_refer,
- nullptr
- };
-
- gpgme_data_t dataOut;
- gpgme_data_new(&dataOut);
- // export private key to outBuffer
- gpgme_error_t error = gpgme_op_export_keys(mCtx, target_key, GPGME_EXPORT_MODE_SECRET, dataOut);
-
- if (gpgme_err_code(error) != GPG_ERR_NO_ERROR) {
- checkErr(error);
- gpgme_data_release(dataOut);
- return false;
- }
-
- readToBuffer(dataOut, outBuffer);
- gpgme_data_release(dataOut);
- return true;
- }
-
-/** return type should be gpgme_error_t*/
- QProcess * GpgContext::executeGpgCommand(const QStringList &arguments, QByteArray *stdOut, QByteArray *stdErr,
- const std::function<void(QProcess *)> &interactFunc) {
- QStringList args;
- args << arguments;
-
- auto *gpgProcess = new QProcess(this);
- qDebug() << "gpgExec" << gpgExec << args;
-
- gpgProcess->setReadChannel(QProcess::StandardOutput);
- connect(gpgProcess, SIGNAL(finished(int,QProcess::ExitStatus)),
- gpgProcess, SLOT(deleteLater()));
- connect(gpgProcess, &QProcess::readyReadStandardOutput, this, [gpgProcess, interactFunc]() {
- qDebug() << "Function Called" << &gpgProcess;
- // interactFunc(gpgProcess);
- });
-
- gpgProcess->start(gpgExec, args);
-
- if (gpgProcess->waitForStarted()){
- qDebug() << "Gpg Process Started Success";
- } else {
- qDebug() << "Gpg Process Started Failed";
- }
-
- return gpgProcess;
- }
-
-/***
- * if sigbuffer not set, the inbuffer should contain signed text
- *
- * TODO: return type should contain:
- * -> list of sigs
- * -> valid
- * -> errors
- */
- gpgme_error_t GpgContext::verify(QByteArray *inBuffer, QByteArray *sigBuffer, gpgme_verify_result_t *result) {
-
- gpgme_data_t dataIn;
- gpgme_error_t gpgmeError;
- gpgme_signature_t sign;
- gpgme_verify_result_t m_result;
-
- gpgmeError = gpgme_data_new_from_mem(&dataIn, inBuffer->data(), inBuffer->size(), 1);
- checkErr(gpgmeError);
-
- if (sigBuffer != nullptr) {
- gpgme_data_t sigdata;
- gpgmeError = gpgme_data_new_from_mem(&sigdata, sigBuffer->data(), sigBuffer->size(), 1);
- checkErr(gpgmeError);
- gpgmeError = gpgme_op_verify(mCtx, sigdata, dataIn, nullptr);
- } else {
- gpgmeError = gpgme_op_verify(mCtx, dataIn, nullptr, dataIn);
- }
-
- checkErr(gpgmeError);
-
- m_result = gpgme_op_verify_result(mCtx);
-
- if (result != nullptr) {
- *result = m_result;
- }
-
- return gpgmeError;
- }
-
- gpg_error_t
- GpgContext::sign(const QVector<GpgKey> &keys, const QByteArray &inBuffer, QByteArray *outBuffer, bool detached,
- gpgme_sign_result_t *result) {
-
- gpgme_error_t gpgmeError;
- gpgme_data_t dataIn, dataOut;
- gpgme_sign_result_t m_result;
- gpgme_sig_mode_t mode;
-
- if (keys.isEmpty()) {
- QMessageBox::critical(nullptr, tr("Key Selection"), tr("No Private Key Selected"));
- return false;
- }
-
- // at start or end?
-
- setSigners(keys);
-
- gpgmeError = gpgme_data_new_from_mem(&dataIn, inBuffer.data(), inBuffer.size(), 1);
- checkErr(gpgmeError);
- gpgmeError = gpgme_data_new(&dataOut);
- checkErr(gpgmeError);
-
- /*
- `GPGME_SIG_MODE_NORMAL'
- A normal signature is made, the output includes the plaintext
- and the signature.
-
- `GPGME_SIG_MODE_DETACH'
- A detached signature is made.
-
- `GPGME_SIG_MODE_CLEAR'
- A clear text signature is made. The ASCII armor and text
- mode settings of the context are ignored.
- */
-
- if (detached) {
- mode = GPGME_SIG_MODE_DETACH;
- } else {
- mode = GPGME_SIG_MODE_CLEAR;
- }
-
- gpgmeError = gpgme_op_sign(mCtx, dataIn, dataOut, mode);
- checkErr(gpgmeError);
-
- if (gpgmeError == GPG_ERR_CANCELED) {
- return false;
- }
-
- if (gpgmeError != GPG_ERR_NO_ERROR) {
- QMessageBox::critical(nullptr, tr("Error in signing:"), QString::fromUtf8(gpgme_strerror(gpgmeError)));
- return false;
- }
-
- m_result = gpgme_op_sign_result(mCtx);
-
- if (result != nullptr) {
- *result = m_result;
- }
-
- gpgmeError = readToBuffer(dataOut, outBuffer);
- checkErr(gpgmeError);
-
- gpgme_data_release(dataIn);
- gpgme_data_release(dataOut);
-
- if (!settings.value("general/rememberPassword").toBool()) {
- clearPasswordCache();
- }
-
- return gpgmeError;
- }
-
- /*
- * if there is no '\n' before the PGP-Begin-Block, but for example a whitespace,
- * GPGME doesn't recognise the Message as encrypted. This function adds '\n'
- * before the PGP-Begin-Block, if missing.
- */
- void GpgContext::preventNoDataErr(QByteArray *in) {
- int block_start = in->indexOf(GpgConstants::PGP_CRYPT_BEGIN);
- if (block_start > 0 && in->at(block_start - 1) != '\n') {
- in->insert(block_start, '\n');
- }
- block_start = in->indexOf(GpgConstants::PGP_SIGNED_BEGIN);
- if (block_start > 0 && in->at(block_start - 1) != '\n') {
- in->insert(block_start, '\n');
- }
- }
-
- /*
- * isSigned returns:
- * - 0, if text isn't signed at all
- * - 1, if text is partially signed
- * - 2, if text is completly signed
- */
- int GpgContext::textIsSigned(const QByteArray &text) {
- if (text.trimmed().startsWith(GpgConstants::PGP_SIGNED_BEGIN) &&
- text.trimmed().endsWith(GpgConstants::PGP_SIGNED_END)) {
- return 2;
- }
- if (text.contains(GpgConstants::PGP_SIGNED_BEGIN) && text.contains(GpgConstants::PGP_SIGNED_END)) {
- return 1;
- }
- return 0;
- }
-
- QString GpgContext::beautifyFingerprint(QString fingerprint) {
- uint len = fingerprint.length();
- if ((len > 0) && (len % 4 == 0))
- for (uint n = 0; 4 * (n + 1) < len; ++n)
- fingerprint.insert(static_cast<int>(5u * n + 4u), ' ');
- return fingerprint;
- }
-
- void GpgContext::slotRefreshKeyList() {
- qDebug() << "Refreshing Keys";
- this->fetch_keys();
- emit signalKeyInfoChanged();
- }
-
-/**
- * note: is_private_key status is not returned
- */
- GpgKey GpgContext::getKeyByFpr(const QString &fpr) {
- for (const auto &key : mKeyList) {
- if (key.fpr == fpr) {
- return key;
- } else {
- for (auto &subkey : key.subKeys) {
- if (subkey.fpr == fpr) {
- return key;
- }
- }
- }
- }
- return GpgKey(nullptr);
- }
-
- /**
- * note: is_private_key status is not returned
- */
- const GpgKey &GpgContext::getKeyById(const QString &id) {
-
- for (const auto &key : mKeyList) {
- if (key.id == id) {
- return key;
- } else {
- auto subkeys = key.subKeys;
- for (const auto &subkey : subkeys) {
- if (subkey.id == id) {
- return key;
- }
- }
- }
- }
-
- throw std::runtime_error("key not found");
- }
-
- QString GpgContext::getGpgmeVersion() {
- return QString(gpgme_check_version(nullptr));
- }
-
- bool GpgContext::signKey(const GpgKey &target, const QString &uid, const QDateTime *expires) {
-
- unsigned int flags = 0;
-
- unsigned int expires_time_t = 0;
- if (expires == nullptr) {
- flags |= GPGME_KEYSIGN_NOEXPIRE;
- } else {
- expires_time_t = QDateTime::currentDateTime().secsTo(*expires);
- }
-
- auto gpgmeError =
- gpgme_op_keysign(mCtx, target.key_refer, uid.toUtf8().constData(), expires_time_t, flags);
-
- if (gpgmeError == GPG_ERR_NO_ERROR) {
- emit signalKeyUpdated(target.id);
- return true;
- } else {
- checkErr(gpgmeError);
- return false;
- }
- }
-
- const GpgKeyList &GpgContext::getKeys() const {
- return mKeyList;
- }
-
- void GpgContext::getSigners(QVector<GpgKey> &signer) {
- auto count = gpgme_signers_count(mCtx);
- signer.clear();
- for (auto i = 0; i < count; i++) {
- auto key = gpgme_signers_enum(mCtx, i);
- auto it = mKeyMap.find(key->subkeys->keyid);
- if (it == mKeyMap.end()) {
- qDebug() << "Inconsistent state";
- signer.push_back(GpgKey(key));
- } else {
- signer.push_back(*it.value());
- }
- }
- }
-
- void GpgContext::setSigners(const QVector<GpgKey> &keys) {
- gpgme_signers_clear(mCtx);
- for (const auto &key : keys) {
- if (checkIfKeyCanSign(key)) {
- auto gpgmeError = gpgme_signers_add(mCtx, key.key_refer);
- checkErr(gpgmeError);
- }
- }
- if (keys.length() != gpgme_signers_count(mCtx)) {
- qDebug() << "No All Keys Added";
- }
- }
-
- void GpgContext::slotUpdateKeyList(const QString &key_id) {
- auto it = mKeyMap.find(key_id);
- if (it != mKeyMap.end()) {
- gpgme_key_t new_key_refer;
- auto gpgmeErr = gpgme_get_key(mCtx, key_id.toUtf8().constData(), &new_key_refer, 0);
-
- if (gpgme_err_code(gpgmeErr) == GPG_ERR_EOF) {
- gpgmeErr = gpgme_get_key(mCtx, key_id.toUtf8().constData(), &new_key_refer, 1);
-
- if (gpgme_err_code(gpgmeErr) == GPG_ERR_EOF) {
- throw std::runtime_error("key_id not found in key database");
- }
-
- }
-
- if (new_key_refer != nullptr) {
- it.value()->swapKeyRefer(new_key_refer);
- emit signalKeyInfoChanged();
- }
-
- }
- }
-
- bool GpgContext::addUID(const GpgKey &key, const GpgUID &uid) {
- QString userid = QString("%1 (%3) <%2>").arg(uid.name, uid.email, uid.comment);
- auto gpgmeError = gpgme_op_adduid(mCtx, key.key_refer, userid.toUtf8().constData(), 0);
- if (gpgmeError == GPG_ERR_NO_ERROR) {
- emit signalKeyUpdated(key.id);
- return true;
- } else {
- checkErr(gpgmeError);
- return false;
- }
-
- }
-
- bool GpgContext::revUID(const GpgKey &key, const GpgUID &uid) {
- auto gpgmeError = gpgme_op_revuid(mCtx, key.key_refer, uid.uid.toUtf8().constData(), 0);
- if (gpgmeError == GPG_ERR_NO_ERROR) {
- emit signalKeyUpdated(key.id);
- return true;
- } else {
- checkErr(gpgmeError);
- return false;
- }
- }
-
- bool GpgContext::setPrimaryUID(const GpgKey &key, const GpgUID &uid) {
- auto gpgmeError = gpgme_op_set_uid_flag(mCtx, key.key_refer,
- uid.uid.toUtf8().constData(), "primary", nullptr);
- if (gpgmeError == GPG_ERR_NO_ERROR) {
- emit signalKeyUpdated(key.id);
- return true;
- } else {
- checkErr(gpgmeError);
- return false;
- }
- }
-
- bool GpgContext::revSign(const GpgKey &key, const GpgKeySignature &signature) {
-
- auto signing_key = getKeyById(signature.keyid);
-
- auto gpgmeError = gpgme_op_revsig(mCtx, key.key_refer,
- signing_key.key_refer,
- signature.uid.toUtf8().constData(), 0);
- if (gpg_err_code(gpgmeError) == GPG_ERR_NO_ERROR) {
- emit signalKeyUpdated(key.id);
- return true;
- } else {
- checkErr(gpgmeError);
- return false;
- }
- }
-
- bool GpgContext::generateSubkey(const GpgKey &key, GenKeyInfo *params) {
-
- if (!params->isSubKey()) {
- return false;
- }
-
- auto algo_utf8 = (params->getAlgo() + params->getKeySizeStr()).toUtf8();
- const char *algo = algo_utf8.constData();
- unsigned long expires = QDateTime::currentDateTime().secsTo(params->getExpired());
- unsigned int flags = 0;
-
- if (!params->isSubKey()) {
- flags |= GPGME_CREATE_CERT;
- }
-
- if (params->isAllowEncryption()) {
- flags |= GPGME_CREATE_ENCR;
- }
-
- if (params->isAllowSigning()) {
- flags |= GPGME_CREATE_SIGN;
- }
-
- if (params->isAllowAuthentication()) {
- flags |= GPGME_CREATE_AUTH;
- }
-
- if (params->isNonExpired()) {
- flags |= GPGME_CREATE_NOEXPIRE;
- }
-
- flags |= GPGME_CREATE_NOPASSWD;
-
-
- auto gpgmeError = gpgme_op_createsubkey(mCtx, key.key_refer,
- algo, 0, expires, flags);
- if (gpgmeError == GPG_ERR_NO_ERROR) {
- emit signalKeyUpdated(key.id);
- return true;
- } else {
- checkErr(gpgmeError);
- return false;
- }
- }
-
- bool GpgContext::setExpire(const GpgKey &key, const GpgSubKey *subkey, QDateTime *expires) {
- unsigned long expires_time = 0;
- if (expires != nullptr) {
- qDebug() << "Expire Datetime" << expires->toString();
- expires_time = QDateTime::currentDateTime().secsTo(*expires);
- }
-
- const char *subfprs = nullptr;
-
- if (subkey != nullptr) {
- subfprs = subkey->fpr.toUtf8().constData();
- }
-
- auto gpgmeError = gpgme_op_setexpire(mCtx, key.key_refer,
- expires_time, subfprs, 0);
- if (gpgmeError == GPG_ERR_NO_ERROR) {
- emit signalKeyUpdated(key.id);
- return true;
- } else {
- checkErr(gpgmeError);
- return false;
- }
- }
-
- bool GpgContext::checkIfKeyCanSign(const GpgKey &key) {
- if (std::any_of(key.subKeys.begin(), key.subKeys.end(), [](const GpgSubKey &subkey) -> bool {
- return subkey.secret && subkey.can_sign && !subkey.disabled && !subkey.revoked && !subkey.expired;
- }))
- return true;
- return false;
- }
-
- bool GpgContext::checkIfKeyCanCert(const GpgKey &key) {
- return key.has_master_key && !key.expired && !key.revoked && !key.disabled;
- }
-
- bool GpgContext::checkIfKeyCanAuth(const GpgKey &key) {
- if (std::any_of(key.subKeys.begin(), key.subKeys.end(), [](const GpgSubKey &subkey) -> bool {
- return subkey.secret && subkey.can_authenticate && !subkey.disabled && !subkey.revoked && !subkey.expired;
- }))
- return true;
- return false;
- }
-
- bool GpgContext::checkIfKeyCanEncr(const GpgKey &key) {
- if (std::any_of(key.subKeys.begin(), key.subKeys.end(), [](const GpgSubKey &subkey) -> bool {
- return subkey.can_encrypt && !subkey.disabled && !subkey.revoked && !subkey.expired;
- }))
- return true;
- return false;
- }
-
- gpgme_error_t GpgContext::encryptSign(QVector<GpgKey> &keys, const QByteArray &inBuffer, QByteArray *outBuffer,
- gpgme_encrypt_result_t *encr_result, gpgme_sign_result_t *sign_result) {
- gpgme_data_t dataIn = nullptr, dataOut = nullptr;
- outBuffer->resize(0);
-
- setSigners(keys);
-
- //gpgme_encrypt_result_t e_result;
- gpgme_key_t recipients[keys.count() + 1];
-
- /* set key for user */
- int index = 0;
- for (const auto &key : keys) {
- recipients[index++] = key.key_refer;
- }
- //Last entry dataIn array has to be nullptr
- recipients[keys.count()] = nullptr;
-
- //If the last parameter isnt 0, a private copy of data is made
- if (mCtx != nullptr) {
- err = gpgme_data_new_from_mem(&dataIn, inBuffer.data(), inBuffer.size(), 1);
- if (gpg_err_code(err) == GPG_ERR_NO_ERROR) {
- err = gpgme_data_new(&dataOut);
- if (gpg_err_code(err) == GPG_ERR_NO_ERROR) {
- err = gpgme_op_encrypt_sign(mCtx, recipients, GPGME_ENCRYPT_ALWAYS_TRUST, dataIn, dataOut);
- if (encr_result != nullptr)
- *encr_result = gpgme_op_encrypt_result(mCtx);
- if (sign_result != nullptr)
- *sign_result = gpgme_op_sign_result(mCtx);
- if (gpg_err_code(err) == GPG_ERR_NO_ERROR) {
- err = readToBuffer(dataOut, outBuffer);
- }
- }
- }
- }
-
- if (gpgme_err_code(err) != GPG_ERR_NO_ERROR)
- checkErr(err);
-
- if (dataIn) {
- gpgme_data_release(dataIn);
- }
- if (dataOut) {
- gpgme_data_release(dataOut);
- }
-
- return err;
- }
-
- gpgme_error_t
- GpgContext::decryptVerify(const QByteArray &inBuffer, QByteArray *outBuffer, gpgme_decrypt_result_t *decrypt_result,
- gpgme_verify_result_t *verify_result) {
- gpgme_data_t dataIn = nullptr, dataOut = nullptr;
-
- outBuffer->resize(0);
- if (mCtx != nullptr) {
- err = gpgme_data_new_from_mem(&dataIn, inBuffer.data(), inBuffer.size(), 1);
- if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) {
- err = gpgme_data_new(&dataOut);
- if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) {
- err = gpgme_op_decrypt_verify(mCtx, dataIn, dataOut);
- if (decrypt_result != nullptr)
- *decrypt_result = gpgme_op_decrypt_result(mCtx);
- if (verify_result != nullptr)
- *verify_result = gpgme_op_verify_result(mCtx);
- if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) {
- err = readToBuffer(dataOut, outBuffer);
- }
- }
- }
- }
-
- if (!settings.value("general/rememberPassword").toBool()) {
- clearPasswordCache();
- }
-
- if (dataIn) {
- gpgme_data_release(dataIn);
- }
- if (dataOut) {
- gpgme_data_release(dataOut);
- }
-
- return err;
- }
-
- bool GpgContext::exportKeys(const QVector<GpgKey> &keys, QByteArray &outBuffer) {
- size_t read_bytes;
- gpgme_data_t dataOut = nullptr;
- outBuffer.resize(0);
-
- if (keys.count() == 0) {
- QMessageBox::critical(nullptr, "Export Keys Error", "No Keys Selected");
- return false;
- }
-
- for (const auto &key : keys) {
- err = gpgme_data_new(&dataOut);
- checkErr(err);
-
- err = gpgme_op_export(mCtx, key.id.toUtf8().constData(), 0, dataOut);
- checkErr(err);
-
- read_bytes = gpgme_data_seek(dataOut, 0, SEEK_END);
-
- err = readToBuffer(dataOut, &outBuffer);
- checkErr(err);
- gpgme_data_release(dataOut);
- }
- return true;
- }
-
- QProcess * GpgContext::generateRevokeCert(const GpgKey &key, const QString &outputFileName) {
- QByteArray out, stdErr;
- auto process = executeGpgCommand({
- "--command-fd",
- "0",
- "--status-fd", "1",
- "-o",
- outputFileName,
- "--gen-revoke",
- key.fpr
- }, &out, &stdErr,
- [](QProcess *proc) {
- qDebug() << "Function Called" << proc;
- while (proc->canReadLine()) {
- const QString line = QString::fromUtf8(proc->readLine()).trimmed();
- // Command-fd is a stable interface, while this is all kind of hacky we
- // are on a deadline :-/
- 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");
- }
- }
- });
-
- qDebug() << "GenerateRevokeCert Process" << process;
-
- return process;
- }
-}
diff --git a/src/gpg/GpgFileOpera.cpp b/src/gpg/GpgFileOpera.cpp
index 9395bd17..af50c79a 100644
--- a/src/gpg/GpgFileOpera.cpp
+++ b/src/gpg/GpgFileOpera.cpp
@@ -114,7 +114,7 @@ gpgme_error_t GpgFileOpera::signFile(GpgME::GpgContext *ctx, QVector<GpgKey> &ke
auto outBuffer = QByteArray();
infile.close();
- auto error = ctx->sign(keys, inBuffer, &outBuffer, true, result);
+ auto error = ctx->sign(keys, inBuffer, &outBuffer, GPGME_SIG_MODE_DETACH, result);
if (gpg_err_code(error) != GPG_ERR_NO_ERROR) return error;
@@ -185,7 +185,10 @@ gpg_error_t GpgFileOpera::encryptSignFile(GpgME::GpgContext *ctx, QVector<GpgKey
auto outBuffer = QByteArray();
infile.close();
- auto error = ctx->encryptSign(keys, inBuffer, &outBuffer, encr_res, sign_res);
+ QVector<GpgKey> signerKeys;
+
+ // TODO dealing with signer keys
+ auto error = ctx->encryptSign(keys, signerKeys, inBuffer, &outBuffer, encr_res, sign_res);
if (gpg_err_code(error) != GPG_ERR_NO_ERROR)
return error;
diff --git a/src/ui/keygen/KeygenThread.cpp b/src/gpg/GpgInfo.cpp
index d7b9d840..00a15ef9 100644
--- a/src/ui/keygen/KeygenThread.cpp
+++ b/src/gpg/GpgInfo.cpp
@@ -22,15 +22,4 @@
*
*/
-#include "ui/keygen/KeygenThread.h"
-
-KeyGenThread::KeyGenThread(GenKeyInfo* keyGenParams, GpgME::GpgContext *ctx)
-: mCtx(ctx), keyGenParams(keyGenParams), QThread(nullptr) {
- connect(this, &KeyGenThread::finished, this, &KeyGenThread::deleteLater);
-}
-
-void KeyGenThread::run() {
- bool success = mCtx->generateKey(keyGenParams);
- emit signalKeyGenerated(success);
- emit finished({});
-}
+#include "gpg/GpgInfo.h"
diff --git a/src/gpg/GpgUID.cpp b/src/gpg/GpgUID.cpp
index f8f7e8fa..0dc6abfd 100644
--- a/src/gpg/GpgUID.cpp
+++ b/src/gpg/GpgUID.cpp
@@ -1,6 +1,26 @@
-//
-// Created by eric on 2021/5/22.
-//
+/**
+ * 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.
+ *
+ * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
#include "gpg/GpgUID.h"
diff --git a/src/gpg/gpg_context/GpgContext.cpp b/src/gpg/gpg_context/GpgContext.cpp
new file mode 100644
index 00000000..14b54b32
--- /dev/null
+++ b/src/gpg/gpg_context/GpgContext.cpp
@@ -0,0 +1,410 @@
+/**
+ * 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.
+ *
+ * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "gpg/GpgContext.h"
+#include "ui/WaitingDialog.h"
+
+#include <functional>
+#include <unistd.h> /* contains read/write */
+
+#ifdef _WIN32
+
+#include <windows.h>
+
+#endif
+
+#define INT2VOIDP(i) (void*)(uintptr_t)(i)
+
+namespace GpgME {
+
+ /** Constructor
+ * Set up gpgme-context, set paths to app-run path
+ */
+ GpgContext::GpgContext() {
+
+ /** The function `gpgme_check_version' must be called before any other
+ * function in the library, because it initializes the thread support
+ * subsystem in GPGME. (from the info page) */
+ gpgme_check_version(nullptr);
+
+ // the locale set here is used for the other setlocale calls which have nullptr
+ // -> nullptr means use default, which is configured here
+ setlocale(LC_ALL, settings.value("int/lang").toLocale().name().toUtf8().constData());
+
+ /** set locale, because tests do also */
+ gpgme_set_locale(nullptr, LC_CTYPE, setlocale(LC_CTYPE, nullptr));
+ //qDebug() << "Locale set to" << LC_CTYPE << " - " << setlocale(LC_CTYPE, nullptr);
+#ifndef _WIN32
+ gpgme_set_locale(nullptr, LC_MESSAGES, setlocale(LC_MESSAGES, nullptr));
+#endif
+
+ err = gpgme_new(&mCtx);
+ checkErr(err);
+
+ gpgme_engine_info_t engineInfo;
+ engineInfo = gpgme_ctx_get_engine_info(mCtx);
+
+// Check ENV before running
+ bool check_pass = false, find_openpgp = false, find_gpgconf = false, find_assuan = false, find_cms = false;
+ while (engineInfo != nullptr) {
+ qDebug() << gpgme_get_protocol_name(engineInfo->protocol) << engineInfo->file_name << engineInfo->protocol
+ << engineInfo->home_dir << engineInfo->version;
+ if (engineInfo->protocol == GPGME_PROTOCOL_GPGCONF && strcmp(engineInfo->version, "1.0.0") != 0)
+ find_gpgconf = true;
+ if (engineInfo->protocol == GPGME_PROTOCOL_OpenPGP && strcmp(engineInfo->version, "1.0.0") != 0)
+ find_openpgp = true, info.appPath = engineInfo->file_name;
+ if (engineInfo->protocol == GPGME_PROTOCOL_CMS && strcmp(engineInfo->version, "1.0.0") != 0)
+ find_cms = true;
+ if (engineInfo->protocol == GPGME_PROTOCOL_ASSUAN)
+ find_assuan = true;
+
+ engineInfo = engineInfo->next;
+ }
+
+ if (find_gpgconf && find_openpgp && find_cms && find_assuan)
+ check_pass = true;
+
+ if (!check_pass) {
+ good = false;
+ return;
+ } else good = true;
+
+
+/** Setting the output type must be done at the beginning */
+/** think this means ascii-armor --> ? */
+ gpgme_set_armor(mCtx, 1);
+/** passphrase-callback */
+ gpgme_set_passphrase_cb(mCtx, passphraseCb, this);
+
+/** check if app is called with -d from command line */
+ if (qApp->arguments().contains("-d")) {
+ qDebug() << "gpgme_data_t debug on";
+ debug = true;
+ } else {
+ debug = false;
+ }
+
+ connect(this, SIGNAL(signalKeyDBChanged()),
+ this, SLOT(slotRefreshKeyList()), Qt::DirectConnection);
+ connect(this, SIGNAL(signalKeyUpdated(QString)),
+ this, SLOT(slotUpdateKeyList(QString)), Qt::DirectConnection);
+ slotRefreshKeyList();
+ }
+
+ /** Destructor
+ * Release gpgme-context
+ */
+ GpgContext::~GpgContext() {
+ if (mCtx) gpgme_release(mCtx);
+ mCtx = nullptr;
+ }
+
+ bool GpgContext::isGood() const {
+ return good;
+ }
+
+ /** Read gpgme-Data to QByteArray
+ * mainly from http://basket.kde.org/ (kgpgme.cpp)
+ */
+#define BUF_SIZE (32 * 1024)
+
+ gpgme_error_t GpgContext::readToBuffer(gpgme_data_t dataIn, QByteArray *outBuffer) {
+ gpgme_off_t ret;
+ gpgme_error_t gpgErrNoError = GPG_ERR_NO_ERROR;
+
+ ret = gpgme_data_seek(dataIn, 0, SEEK_SET);
+ if (ret) {
+ gpgErrNoError = gpgme_err_code_from_errno(errno);
+ checkErr(gpgErrNoError, "failed dataseek dataIn readToBuffer");
+ } else {
+ char buf[BUF_SIZE + 2];
+
+ while ((ret = gpgme_data_read(dataIn, buf, BUF_SIZE)) > 0) {
+ const size_t size = outBuffer->size();
+ outBuffer->resize(static_cast<int>(size + ret));
+ memcpy(outBuffer->data() + size, buf, ret);
+ }
+ if (ret < 0) {
+ gpgErrNoError = gpgme_err_code_from_errno(errno);
+ checkErr(gpgErrNoError, "failed data_read dataIn readToBuffer");
+ }
+ }
+ return gpgErrNoError;
+ }
+
+ /**
+ * The Passphrase window, if not provided by env-Var GPG_AGENT_INFO
+ * originally copied from http://basket.kde.org/ (kgpgme.cpp), but modified
+ */
+ gpgme_error_t GpgContext::passphraseCb(void *hook, const char *uid_hint,
+ const char *passphrase_info,
+ int last_was_bad, int fd) {
+ auto *gpg = static_cast<GpgContext *>(hook);
+ return gpg->passphrase(uid_hint, passphrase_info, last_was_bad, fd);
+ }
+
+ gpgme_error_t GpgContext::passphrase(const char *uid_hint,
+ const char * /*passphrase_info*/,
+ int last_was_bad, int fd) {
+
+ gpgme_error_t returnValue = GPG_ERR_CANCELED;
+ QString passwordDialogMessage;
+ QString gpgHint = QString::fromUtf8(uid_hint);
+ bool result;
+
+#ifdef _WIN32
+ DWORD written;
+ auto hd = INT2VOIDP(fd);
+#endif
+
+ if (last_was_bad) {
+ passwordDialogMessage += "<i>" + tr("Wrong password") + ".</i><br><br>\n\n";
+ clearPasswordCache();
+ }
+
+ /** if uid provided */
+ if (!gpgHint.isEmpty()) {
+ // remove UID, leave only username & email
+ gpgHint.remove(0, gpgHint.indexOf(" "));
+ passwordDialogMessage += "<b>" + tr("Enter Password for") + "</b><br>" + gpgHint + "<br>";
+ }
+
+ if (mPasswordCache.isEmpty()) {
+ QString password = QInputDialog::getText(QApplication::activeWindow(), tr("Enter Password"),
+ passwordDialogMessage, QLineEdit::Password,
+ "", &result);
+
+ if (result) mPasswordCache = password.toUtf8();
+ } else result = true;
+
+ if (result) {
+
+#ifndef _WIN32
+ if (write(fd, mPasswordCache.data(), mPasswordCache.length()) == -1) qDebug() << "something is terribly broken";
+#else
+ WriteFile(hd, mPasswordCache.data(), mPasswordCache.length(), &written, 0);
+#endif
+ returnValue = GPG_ERR_NO_ERROR;
+ }
+
+#ifndef _WIN32
+ if (write(fd, "\n", 1) == -1) qDebug() << "something is terribly broken";
+#else
+ WriteFile(hd, "\n", 1, &written, 0);
+
+ /* program will hang on cancel if hd not closed */
+ if (!result) CloseHandle(hd);
+#endif
+
+ return returnValue;
+ }
+
+ /** also from kgpgme.cpp, seems to clear password from mem */
+ void GpgContext::clearPasswordCache() {
+ if (mPasswordCache.size() > 0) {
+ mPasswordCache.fill('\0');
+ mPasswordCache.truncate(0);
+ }
+ }
+
+ // error-handling
+ void GpgContext::checkErr(gpgme_error_t gpgmeError, const QString &comment) {
+ //if (gpgmeError != GPG_ERR_NO_ERROR && gpgmeError != GPG_ERR_CANCELED) {
+ if (gpgmeError != GPG_ERR_NO_ERROR) {
+ qDebug() << "[Error " << gpg_err_code(gpgmeError)
+ << "] Source: " << gpgme_strsource(gpgmeError) << " Description: " << gpgErrString(gpgmeError);
+ }
+ }
+
+ void GpgContext::checkErr(gpgme_error_t gpgmeError) {
+ //if (gpgmeError != GPG_ERR_NO_ERROR && gpgmeError != GPG_ERR_CANCELED) {
+ if (gpg_err_code(gpgmeError) != GPG_ERR_NO_ERROR) {
+ qDebug() << "[Error " << gpg_err_code(gpgmeError)
+ << "] Source: " << gpgme_strsource(gpgmeError) << " Description: " << gpgErrString(gpgmeError);
+ }
+ }
+
+ QString GpgContext::gpgErrString(gpgme_error_t err) {
+ return QString::fromUtf8(gpgme_strerror(err));
+ }
+
+ /** return type should be gpgme_error_t*/
+ void
+ GpgContext::executeGpgCommand(const QStringList &arguments, const std::function<void(QProcess *)> &interactFunc) {
+ QEventLoop looper;
+ auto dialog = new WaitingDialog(tr("Processing"), nullptr);
+ dialog->show();
+ auto *gpgProcess = new QProcess(&looper);
+ gpgProcess->setProcessChannelMode(QProcess::MergedChannels);
+ connect(gpgProcess, qOverload<int, QProcess::ExitStatus>(&QProcess::finished), &looper, &QEventLoop::quit);
+ connect(gpgProcess, qOverload<int, QProcess::ExitStatus>(&QProcess::finished), dialog,
+ &WaitingDialog::deleteLater);
+ connect(gpgProcess, &QProcess::errorOccurred, []() -> void { qDebug("Error in Process"); });
+ connect(gpgProcess, &QProcess::errorOccurred, &looper, &QEventLoop::quit);
+ connect(gpgProcess, &QProcess::started, []() -> void { qDebug() << "Gpg Process Started Success"; });
+ connect(gpgProcess, &QProcess::readyReadStandardOutput, [interactFunc, gpgProcess]() {
+ qDebug() << "Function Called";
+ interactFunc(gpgProcess);
+ });
+ gpgProcess->setProgram(info.appPath);
+ gpgProcess->setArguments(arguments);
+ gpgProcess->start();
+ looper.exec();
+ dialog->close();
+
+ }
+
+
+ /*
+ * if there is no '\n' before the PGP-Begin-Block, but for example a whitespace,
+ * GPGME doesn't recognise the Message as encrypted. This function adds '\n'
+ * before the PGP-Begin-Block, if missing.
+ */
+ void GpgContext::preventNoDataErr(QByteArray *in) {
+ int block_start = in->indexOf(GpgConstants::PGP_CRYPT_BEGIN);
+ if (block_start > 0 && in->at(block_start - 1) != '\n') {
+ in->insert(block_start, '\n');
+ }
+ block_start = in->indexOf(GpgConstants::PGP_SIGNED_BEGIN);
+ if (block_start > 0 && in->at(block_start - 1) != '\n') {
+ in->insert(block_start, '\n');
+ }
+ }
+
+ /*
+ * isSigned returns:
+ * - 0, if text isn't signed at all
+ * - 1, if text is partially signed
+ * - 2, if text is completly signed
+ */
+ int GpgContext::textIsSigned(const QByteArray &text) {
+ if (text.trimmed().startsWith(GpgConstants::PGP_SIGNED_BEGIN) &&
+ text.trimmed().endsWith(GpgConstants::PGP_SIGNED_END))
+ return 2;
+ else if (text.contains(GpgConstants::PGP_SIGNED_BEGIN) && text.contains(GpgConstants::PGP_SIGNED_END))
+ return 1;
+
+ else return 0;
+ }
+
+ QString GpgContext::beautifyFingerprint(QString fingerprint) {
+ uint len = fingerprint.length();
+ if ((len > 0) && (len % 4 == 0))
+ for (uint n = 0; 4 * (n + 1) < len; ++n) fingerprint.insert(static_cast<int>(5u * n + 4u), ' ');
+ return fingerprint;
+ }
+
+ void GpgContext::slotRefreshKeyList() {
+ qDebug() << "Refreshing Keys";
+ this->fetch_keys();
+ emit signalKeyInfoChanged();
+ }
+
+ QString GpgContext::getGpgmeVersion() {
+ return {gpgme_check_version(nullptr)};
+ }
+
+ const GpgKeyList &GpgContext::getKeys() const {
+ return mKeyList;
+ }
+
+ void GpgContext::getSigners(QVector<GpgKey> &signer, gpgme_ctx_t ctx) {
+ auto count = gpgme_signers_count(ctx);
+ signer.clear();
+ for (auto i = 0; i < count; i++) {
+ auto key = gpgme_signers_enum(ctx, i);
+ auto it = mKeyMap.find(key->subkeys->keyid);
+ if (it == mKeyMap.end()) {
+ qDebug() << "Inconsistent state";
+ signer.push_back(GpgKey(key));
+ } else {
+ signer.push_back(*it.value());
+ }
+ }
+ }
+
+ void GpgContext::setSigners(const QVector<GpgKey> &keys, gpgme_ctx_t ctx) {
+ gpgme_signers_clear(ctx);
+ for (const auto &key : keys) {
+ if (checkIfKeyCanSign(key)) {
+ auto gpgmeError = gpgme_signers_add(ctx, key.key_refer);
+ checkErr(gpgmeError);
+ }
+ }
+ if (keys.length() != gpgme_signers_count(ctx)) {
+ qDebug() << "No All Keys Added";
+ }
+ }
+
+ void GpgContext::slotUpdateKeyList(const QString &key_id) {
+ auto it = mKeyMap.find(key_id);
+ if (it != mKeyMap.end()) {
+ gpgme_key_t new_key_refer;
+ auto gpgmeErr = gpgme_get_key(mCtx, key_id.toUtf8().constData(), &new_key_refer, 0);
+
+ if (gpgme_err_code(gpgmeErr) == GPG_ERR_EOF) {
+ gpgmeErr = gpgme_get_key(mCtx, key_id.toUtf8().constData(), &new_key_refer, 1);
+
+ if (gpgme_err_code(gpgmeErr) == GPG_ERR_EOF) {
+ throw std::runtime_error("key_id not found in key database");
+ }
+
+ }
+
+ if (new_key_refer != nullptr) {
+ it.value()->swapKeyRefer(new_key_refer);
+ emit signalKeyInfoChanged();
+ }
+
+ }
+ }
+
+ bool GpgContext::revSign(const GpgKey &key, const GpgKeySignature &signature) {
+
+ auto signing_key = getKeyById(signature.keyid);
+
+ auto gpgmeError = gpgme_op_revsig(mCtx, key.key_refer,
+ signing_key.key_refer,
+ signature.uid.toUtf8().constData(), 0);
+ if (gpg_err_code(gpgmeError) == GPG_ERR_NO_ERROR) {
+ emit signalKeyUpdated(key.id);
+ return true;
+ } else {
+ checkErr(gpgmeError);
+ return false;
+ }
+ }
+
+ gpgme_ctx_t GpgME::GpgContext::create_ctx() {
+ gpgme_ctx_t ctx;
+ err = gpgme_new(&ctx);
+ checkErr(err);
+
+ gpgme_set_armor(ctx, 1);
+ gpgme_set_passphrase_cb(ctx, passphraseCb, this);
+ return ctx;
+ }
+
+
+}
diff --git a/src/gpg/gpg_context/GpgContextBasicOpera.cpp b/src/gpg/gpg_context/GpgContextBasicOpera.cpp
new file mode 100644
index 00000000..d9bf0bdb
--- /dev/null
+++ b/src/gpg/gpg_context/GpgContextBasicOpera.cpp
@@ -0,0 +1,315 @@
+/**
+ * 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.
+ *
+ * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "gpg/GpgContext.h"
+
+/**
+ * Encrypt data
+ * @param keys keys used
+ * @param inBuffer input byte array
+ * @param outBuffer output byte array
+ * @param result opera result
+ * @return error information
+ */
+gpg_error_t GpgME::GpgContext::encrypt(QVector<GpgKey> &keys, const QByteArray &inBuffer, QByteArray *outBuffer,
+ gpgme_encrypt_result_t *result) {
+
+ gpgme_data_t dataIn = nullptr, dataOut = nullptr;
+ outBuffer->resize(0);
+
+ // gpgme_encrypt_result_t e_result;
+ gpgme_key_t recipients[keys.count() + 1];
+
+ int index = 0;
+ for (const auto &key : keys) recipients[index++] = key.key_refer;
+
+ // Last entry dataIn array has to be nullptr
+ recipients[keys.count()] = nullptr;
+
+ // If the last parameter isnt 0, a private copy of data is made
+ if (mCtx) {
+ err = gpgme_data_new_from_mem(&dataIn, inBuffer.data(), inBuffer.size(), 1);
+ checkErr(err);
+ if (!err) {
+ err = gpgme_data_new(&dataOut);
+ checkErr(err);
+ if (!err) {
+ err = gpgme_op_encrypt(mCtx, recipients, GPGME_ENCRYPT_ALWAYS_TRUST, dataIn, dataOut);
+ checkErr(err);
+ if (!err) {
+ err = readToBuffer(dataOut, outBuffer);
+ checkErr(err);
+ }
+ }
+ }
+ }
+ if (dataIn) gpgme_data_release(dataIn);
+ if (dataOut) gpgme_data_release(dataOut);
+
+ if (result != nullptr) *result = gpgme_op_encrypt_result(mCtx);
+ return err;
+}
+
+/**
+ * Decrypt data
+ * @param keys keys used
+ * @param inBuffer input byte array
+ * @param outBuffer output byte array
+ * @param result opera result
+ * @return error information
+ */
+gpgme_error_t GpgME::GpgContext::decrypt(const QByteArray &inBuffer, QByteArray *outBuffer,
+ gpgme_decrypt_result_t *result) {
+ gpgme_data_t dataIn = nullptr, dataOut = nullptr;
+ gpgme_decrypt_result_t m_result = nullptr;
+
+ outBuffer->resize(0);
+ if (mCtx != nullptr) {
+ err = gpgme_data_new_from_mem(&dataIn, inBuffer.data(), inBuffer.size(), 1);
+ if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) {
+ err = gpgme_data_new(&dataOut);
+ if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) {
+ err = gpgme_op_decrypt(mCtx, dataIn, dataOut);
+ m_result = gpgme_op_decrypt_result(mCtx);
+ if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) err = readToBuffer(dataOut, outBuffer);
+ }
+ }
+ }
+
+ if (!settings.value("general/rememberPassword").toBool()) clearPasswordCache();
+
+ if (dataIn) gpgme_data_release(dataIn);
+ if (dataOut) gpgme_data_release(dataOut);
+
+ if (result != nullptr) *result = m_result;
+
+ return err;
+}
+
+/**
+ * Verify data
+ * @param keys keys used
+ * @param inBuffer input byte array
+ * @param sigBuffer signature byte array (detected by format)
+ * @param result opera result
+ * @return error information
+ */
+gpgme_error_t GpgME::GpgContext::verify(QByteArray *inBuffer, QByteArray *sigBuffer, gpgme_verify_result_t *result) {
+
+ gpgme_data_t dataIn;
+ gpgme_error_t gpgmeError;
+ gpgme_verify_result_t m_result;
+
+ gpgmeError = gpgme_data_new_from_mem(&dataIn, inBuffer->data(), inBuffer->size(), 1);
+ checkErr(gpgmeError);
+
+ if (sigBuffer != nullptr) {
+ gpgme_data_t sigdata;
+ gpgmeError = gpgme_data_new_from_mem(&sigdata, sigBuffer->data(), sigBuffer->size(), 1);
+ checkErr(gpgmeError);
+ gpgmeError = gpgme_op_verify(mCtx, sigdata, dataIn, nullptr);
+ } else {
+ gpgmeError = gpgme_op_verify(mCtx, dataIn, nullptr, dataIn);
+ }
+
+ checkErr(gpgmeError);
+
+ m_result = gpgme_op_verify_result(mCtx);
+
+ if (result != nullptr) {
+ *result = m_result;
+ }
+
+ return gpgmeError;
+}
+
+/**
+ * Sign data
+ * @param keys keys used
+ * @param inBuffer input byte array
+ * @param outBuffer output byte array
+ * @param mode sign mode
+ * @param result opera result
+ * @return
+ */
+gpg_error_t GpgME::GpgContext::sign(const QVector<GpgKey> &keys, const QByteArray &inBuffer, QByteArray *outBuffer,
+ gpgme_sig_mode_t mode, gpgme_sign_result_t *result, bool default_ctx) {
+
+ gpgme_error_t gpgmeError;
+ gpgme_data_t dataIn, dataOut;
+ gpgme_sign_result_t m_result;
+
+ auto _ctx = mCtx;
+
+ if(!default_ctx)
+ _ctx = create_ctx();
+
+ if (keys.isEmpty()) {
+ QMessageBox::critical(nullptr, tr("Key Selection"), tr("No Private Key Selected"));
+ return false;
+ }
+
+ // Set Singers of this opera
+ setSigners(keys, _ctx);
+
+ gpgmeError = gpgme_data_new_from_mem(&dataIn, inBuffer.data(), inBuffer.size(), 1);
+ checkErr(gpgmeError);
+ gpgmeError = gpgme_data_new(&dataOut);
+ checkErr(gpgmeError);
+
+ /**
+ `GPGME_SIG_MODE_NORMAL'
+ A normal signature is made, the output includes the plaintext
+ and the signature.
+
+ `GPGME_SIG_MODE_DETACH'
+ A detached signature is made.
+
+ `GPGME_SIG_MODE_CLEAR'
+ A clear text signature is made. The ASCII armor and text
+ mode settings of the context are ignored.
+ */
+
+ gpgmeError = gpgme_op_sign(_ctx, dataIn, dataOut, mode);
+ checkErr(gpgmeError);
+
+ if (gpgmeError == GPG_ERR_CANCELED) return false;
+
+ if (gpgmeError != GPG_ERR_NO_ERROR) {
+ QMessageBox::critical(nullptr, tr("Error in signing:"), QString::fromUtf8(gpgme_strerror(gpgmeError)));
+ return false;
+ }
+
+ if(default_ctx)
+ m_result = gpgme_op_sign_result(_ctx);
+ else m_result = nullptr;
+
+ if (result != nullptr) *result = m_result;
+
+ if(!default_ctx) gpgme_release(_ctx);
+
+ gpgmeError = readToBuffer(dataOut, outBuffer);
+ checkErr(gpgmeError);
+
+ gpgme_data_release(dataIn);
+ gpgme_data_release(dataOut);
+
+ // Of no use yet
+ if (!settings.value("general/rememberPassword").toBool()) clearPasswordCache();
+
+ return gpgmeError;
+}
+
+/**
+ * Encrypt and sign data
+ * @param keys keys used
+ * @param inBuffer input byte array
+ * @param outBuffer output byte array
+ * @param encr_result encrypt opera result
+ * @param sign_result sign opera result
+ * @return
+ */
+gpgme_error_t
+GpgME::GpgContext::encryptSign(QVector<GpgKey> &keys, QVector<GpgKey> &signers, const QByteArray &inBuffer,
+ QByteArray *outBuffer, gpgme_encrypt_result_t *encr_result,
+ gpgme_sign_result_t *sign_result) {
+ gpgme_data_t data_in = nullptr, data_out = nullptr;
+ outBuffer->resize(0);
+
+ setSigners(signers, mCtx);
+
+ //gpgme_encrypt_result_t e_result;
+ gpgme_key_t recipients[keys.count() + 1];
+
+ // set key for user
+ int index = 0;
+ for (const auto &key : keys) recipients[index++] = key.key_refer;
+
+ // Last entry dataIn array has to be nullptr
+ recipients[keys.count()] = nullptr;
+
+ // If the last parameter isnt 0, a private copy of data is made
+ if (mCtx != nullptr) {
+ err = gpgme_data_new_from_mem(&data_in, inBuffer.data(), inBuffer.size(), 1);
+ if (gpg_err_code(err) == GPG_ERR_NO_ERROR) {
+ err = gpgme_data_new(&data_out);
+ if (gpg_err_code(err) == GPG_ERR_NO_ERROR) {
+ err = gpgme_op_encrypt_sign(mCtx, recipients, GPGME_ENCRYPT_ALWAYS_TRUST, data_in, data_out);
+ if (encr_result != nullptr)
+ *encr_result = gpgme_op_encrypt_result(mCtx);
+ if (sign_result != nullptr)
+ *sign_result = gpgme_op_sign_result(mCtx);
+ if (gpg_err_code(err) == GPG_ERR_NO_ERROR) {
+ err = readToBuffer(data_out, outBuffer);
+ }
+ }
+ }
+ }
+
+ if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) checkErr(err);
+
+ if (data_in) gpgme_data_release(data_in);
+ if (data_out) gpgme_data_release(data_out);
+
+ return err;
+}
+
+/**
+ * Decrypt and verify data
+ * @param inBuffer input byte array
+ * @param outBuffer output byte array
+ * @param decrypt_result decrypt opera result
+ * @param verify_result verify opera result
+ * @return error info
+ */
+gpgme_error_t GpgME::GpgContext::decryptVerify(const QByteArray &inBuffer, QByteArray *outBuffer,
+ gpgme_decrypt_result_t *decrypt_result,
+ gpgme_verify_result_t *verify_result) {
+ gpgme_data_t data_in = nullptr, data_out = nullptr;
+
+ outBuffer->resize(0);
+ if (mCtx != nullptr) {
+ err = gpgme_data_new_from_mem(&data_in, inBuffer.data(), inBuffer.size(), 1);
+ if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) {
+ err = gpgme_data_new(&data_out);
+ if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) {
+ err = gpgme_op_decrypt_verify(mCtx, data_in, data_out);
+ if (decrypt_result != nullptr)
+ *decrypt_result = gpgme_op_decrypt_result(mCtx);
+ if (verify_result != nullptr)
+ *verify_result = gpgme_op_verify_result(mCtx);
+ if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) {
+ err = readToBuffer(data_out, outBuffer);
+ }
+ }
+ }
+ }
+
+ if (!settings.value("general/rememberPassword").toBool()) clearPasswordCache();
+
+ if (data_in) gpgme_data_release(data_in);
+ if (data_out) gpgme_data_release(data_out);
+
+ return err;
+}
diff --git a/src/gpg/gpg_context/GpgContextKeyInfo.cpp b/src/gpg/gpg_context/GpgContextKeyInfo.cpp
new file mode 100644
index 00000000..f6942e4e
--- /dev/null
+++ b/src/gpg/gpg_context/GpgContextKeyInfo.cpp
@@ -0,0 +1,110 @@
+/**
+ * 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.
+ *
+ * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "gpg/GpgContext.h"
+
+/**
+ * check if key can sign(actually)
+ * @param key target key
+ * @return if key sign
+ */
+bool GpgME::GpgContext::checkIfKeyCanSign(const GpgKey &key) {
+ if (std::any_of(key.subKeys.begin(), key.subKeys.end(), [](const GpgSubKey &subkey) -> bool {
+ return subkey.secret && subkey.can_sign && !subkey.disabled && !subkey.revoked && !subkey.expired;
+ }))
+ return true;
+ else return false;
+}
+
+/**
+ * check if key can certify(actually)
+ * @param key target key
+ * @return if key certify
+ */
+bool GpgME::GpgContext::checkIfKeyCanCert(const GpgKey &key) {
+ return key.has_master_key && !key.expired && !key.revoked && !key.disabled;
+}
+
+/**
+ * check if key can authenticate(actually)
+ * @param key target key
+ * @return if key authenticate
+ */
+bool GpgME::GpgContext::checkIfKeyCanAuth(const GpgKey &key) {
+ if (std::any_of(key.subKeys.begin(), key.subKeys.end(), [](const GpgSubKey &subkey) -> bool {
+ return subkey.secret && subkey.can_authenticate && !subkey.disabled && !subkey.revoked && !subkey.expired;
+ }))
+ return true;
+ else return false;
+}
+
+/**
+ * check if key can encrypt(actually)
+ * @param key target key
+ * @return if key encrypt
+ */
+bool GpgME::GpgContext::checkIfKeyCanEncr(const GpgKey &key) {
+ if (std::any_of(key.subKeys.begin(), key.subKeys.end(), [](const GpgSubKey &subkey) -> bool {
+ return subkey.can_encrypt && !subkey.disabled && !subkey.revoked && !subkey.expired;
+ }))
+ return true;
+ else return false;
+}
+
+/**
+ * Get target key
+ * @param fpr master key's fingerprint
+ * @return the key
+ */
+GpgKey GpgME::GpgContext::getKeyByFpr(const QString &fpr) {
+ for (const auto &key : mKeyList) {
+ if (key.fpr == fpr) return key;
+ else
+ for (auto &subkey : key.subKeys) {
+ if (subkey.fpr == fpr) return key;
+ }
+ }
+ return GpgKey(nullptr);
+}
+
+
+/**
+ * Get target key
+ * @param id master key's id
+ * @return the key
+ */
+GpgKey GpgME::GpgContext::getKeyById(const QString &id) {
+
+ for (const auto &key : mKeyList) {
+ if (key.id == id) return key;
+ else {
+ auto sub_keys = key.subKeys;
+ for (const auto &subkey : sub_keys) {
+ if (subkey.id == id) return key;
+ }
+ }
+ }
+
+ return GpgKey(nullptr);
+}
diff --git a/src/gpg/gpg_context/GpgContextKeyOpera.cpp b/src/gpg/gpg_context/GpgContextKeyOpera.cpp
new file mode 100644
index 00000000..a224231d
--- /dev/null
+++ b/src/gpg/gpg_context/GpgContextKeyOpera.cpp
@@ -0,0 +1,410 @@
+/**
+ * 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.
+ *
+ * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "gpg/GpgContext.h"
+
+/**
+ * Import key pair
+ * @param inBuffer input byte array
+ * @return Import information
+ */
+GpgImportInformation GpgME::GpgContext::importKey(QByteArray inBuffer) {
+ auto *importInformation = new GpgImportInformation();
+ err = gpgme_data_new_from_mem(&in, inBuffer.data(), inBuffer.size(), 1);
+ checkErr(err);
+ err = gpgme_op_import(mCtx, in);
+ gpgme_import_result_t result;
+
+ result = gpgme_op_import_result(mCtx);
+
+ if (result->unchanged) importInformation->unchanged = result->unchanged;
+ if (result->considered) importInformation->considered = result->considered;
+ if (result->no_user_id) importInformation->no_user_id = result->no_user_id;
+ if (result->imported) importInformation->imported = result->imported;
+ if (result->imported_rsa) importInformation->imported_rsa = result->imported_rsa;
+ if (result->unchanged) importInformation->unchanged = result->unchanged;
+ if (result->new_user_ids) importInformation->new_user_ids = result->new_user_ids;
+ if (result->new_sub_keys) importInformation->new_sub_keys = result->new_sub_keys;
+ if (result->new_signatures) importInformation->new_signatures = result->new_signatures;
+ if (result->new_revocations) importInformation->new_revocations = result->new_revocations;
+ if (result->secret_read) importInformation->secret_read = result->secret_read;
+ if (result->secret_imported) importInformation->secret_imported = result->secret_imported;
+ if (result->secret_unchanged) importInformation->secret_unchanged = result->secret_unchanged;
+ if (result->not_imported) importInformation->not_imported = result->not_imported;
+
+ gpgme_import_status_t status = result->imports;
+ while (status != nullptr) {
+ GpgImportedKey key;
+ key.importStatus = static_cast<int>(status->status);
+ key.fpr = status->fpr;
+ importInformation->importedKeys.emplace_back(key);
+ status = status->next;
+ }
+ checkErr(err);
+ emit signalKeyDBChanged();
+ gpgme_data_release(in);
+ return *importInformation;
+}
+
+/**
+ * Generate a new key pair
+ * @param params key generation args
+ * @return error information
+ */
+gpgme_error_t GpgME::GpgContext::generateKey(GenKeyInfo *params) {
+
+ auto userid_utf8 = params->getUserid().toUtf8();
+ const char *userid = userid_utf8.constData();
+ auto algo_utf8 = (params->getAlgo() + params->getKeySizeStr()).toUtf8();
+ const char *algo = algo_utf8.constData();
+ unsigned long expires = QDateTime::currentDateTime().secsTo(params->getExpired());
+ unsigned int flags = 0;
+
+ if (!params->isSubKey()) flags |= GPGME_CREATE_CERT;
+ if (params->isAllowEncryption()) flags |= GPGME_CREATE_ENCR;
+ if (params->isAllowSigning()) flags |= GPGME_CREATE_SIGN;
+ if (params->isAllowAuthentication()) flags |= GPGME_CREATE_AUTH;
+ if (params->isNonExpired()) flags |= GPGME_CREATE_NOEXPIRE;
+ if (params->isNoPassPhrase()) flags |= GPGME_CREATE_NOPASSWD;
+
+ err = gpgme_op_createkey(mCtx, userid, algo, 0, expires, nullptr, flags);
+
+ if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) {
+ checkErr(err);
+ return err;
+ } else {
+ emit signalKeyDBChanged();
+ return err;
+ }
+}
+
+/**
+ * Export Key
+ * @param uidList key ids
+ * @param outBuffer output byte array
+ * @return if success
+ */
+bool GpgME::GpgContext::exportKeys(QStringList *uidList, QByteArray *outBuffer) {
+ gpgme_data_t dataOut = nullptr;
+ outBuffer->resize(0);
+
+ if (uidList->count() == 0) {
+ QMessageBox::critical(nullptr, "Export Keys Error", "No Keys Selected");
+ return false;
+ }
+
+ // Alleviate another crash problem caused by an unknown array out-of-bounds access
+ gpgme_ctx_t ctx = create_ctx();
+
+ for (int i = 0; i < uidList->count(); i++) {
+ err = gpgme_data_new(&dataOut);
+ checkErr(err);
+
+ err = gpgme_op_export(ctx, uidList->at(i).toUtf8().constData(), 0, dataOut);
+ checkErr(err);
+
+ qDebug() << "exportKeys read_bytes" << gpgme_data_seek(dataOut, 0, SEEK_END);
+
+ err = readToBuffer(dataOut, outBuffer);
+ checkErr(err);
+ gpgme_data_release(dataOut);
+ }
+
+ gpgme_release(ctx);
+
+ return true;
+}
+
+/**
+ * Get and store all key pairs info
+ */
+void GpgME::GpgContext::fetch_keys() {
+
+ gpgme_error_t gpgmeError;
+
+ gpgme_key_t key;
+
+ qDebug() << "Clear List and Map";
+
+ mKeyList.clear();
+ mKeyMap.clear();
+
+ auto &keys = mKeyList;
+ auto &keys_map = mKeyMap;
+
+ qDebug() << "Set Key Listing Mode";
+
+ gpgmeError = gpgme_set_keylist_mode(mCtx,
+ GPGME_KEYLIST_MODE_LOCAL
+ | GPGME_KEYLIST_MODE_WITH_SECRET
+ | GPGME_KEYLIST_MODE_SIGS
+ | GPGME_KEYLIST_MODE_SIG_NOTATIONS
+ | GPGME_KEYLIST_MODE_WITH_TOFU);
+ if (gpg_err_code(gpgmeError) != GPG_ERR_NO_ERROR) {
+ checkErr(gpgmeError);
+ return;
+ }
+
+ qDebug() << "Operate KeyList Start";
+
+ gpgmeError = gpgme_op_keylist_start(mCtx, nullptr, 0);
+ if (gpg_err_code(gpgmeError) != GPG_ERR_NO_ERROR) {
+ checkErr(gpgmeError);
+ return;
+ }
+
+ qDebug() << "Start Loop";
+
+ while ((gpgmeError = gpgme_op_keylist_next(mCtx, &key)) == GPG_ERR_NO_ERROR) {
+ if (!key->subkeys)
+ continue;
+
+ qDebug() << "Append Key" << key->subkeys->keyid;
+
+ keys.emplace_back(key);
+ keys_map.insert(keys.back().id, &keys.back());
+ gpgme_key_unref(key);
+ }
+
+
+ if (gpg_err_code(gpgmeError) != GPG_ERR_EOF) {
+ checkErr(gpgmeError);
+ return;
+ }
+
+ gpgmeError = gpgme_op_keylist_end(mCtx);
+ if (gpg_err_code(gpgmeError) != GPG_ERR_NO_ERROR) {
+ checkErr(gpgmeError);
+ return;
+ }
+
+ qDebug() << "Operate KeyList End";
+
+ mKeyList = keys;
+}
+
+/**
+ * Delete keys
+ * @param uidList key ids
+ */
+void GpgME::GpgContext::deleteKeys(QStringList *uidList) {
+
+ gpgme_error_t error;
+ gpgme_key_t key;
+
+ for (const auto &tmp : *uidList) {
+
+ error = gpgme_op_keylist_start(mCtx, tmp.toUtf8().constData(), 0);
+ if (error != GPG_ERR_NO_ERROR) {
+ checkErr(error);
+ continue;
+ }
+
+ error = gpgme_op_keylist_next(mCtx, &key);
+ if (error != GPG_ERR_NO_ERROR) {
+ checkErr(error);
+ continue;
+ }
+
+ error = gpgme_op_keylist_end(mCtx);
+ if (error != GPG_ERR_NO_ERROR) {
+ checkErr(error);
+ continue;
+ }
+
+ error = gpgme_op_delete(mCtx, key, 1);
+ if (error != GPG_ERR_NO_ERROR) {
+ checkErr(error);
+ continue;
+ }
+
+ }
+ emit signalKeyDBChanged();
+}
+
+/**
+ * Export keys
+ * @param keys keys used
+ * @param outBuffer output byte array
+ * @return if success
+ */
+bool GpgME::GpgContext::exportKeys(const QVector<GpgKey> &keys, QByteArray &outBuffer) {
+ gpgme_data_t data_out = nullptr;
+ outBuffer.resize(0);
+
+ if (keys.empty()) {
+ QMessageBox::critical(nullptr, "Export Keys Error", "No Keys Selected");
+ return false;
+ }
+
+ for (const auto &key : keys) {
+ err = gpgme_data_new(&data_out);
+ checkErr(err);
+
+ err = gpgme_op_export(mCtx, key.id.toUtf8().constData(), 0, data_out);
+ checkErr(err);
+
+ gpgme_data_seek(data_out, 0, SEEK_END);
+
+ err = readToBuffer(data_out, &outBuffer);
+ checkErr(err);
+ gpgme_data_release(data_out);
+ }
+
+ return true;
+}
+
+/**
+ * Set the expire date and time of a key pair(actually the master key) or subkey
+ * @param key target key pair
+ * @param subkey null if master key
+ * @param expires date and time
+ * @return if successful
+ */
+bool GpgME::GpgContext::setExpire(const GpgKey &key, const GpgSubKey *subkey, QDateTime *expires) {
+ unsigned long expires_time = 0;
+ if (expires != nullptr) {
+ qDebug() << "Expire Datetime" << expires->toString();
+ expires_time = QDateTime::currentDateTime().secsTo(*expires);
+ }
+
+ const char *subfprs = nullptr;
+
+ if (subkey != nullptr) subfprs = subkey->fpr.toUtf8().constData();
+
+ auto gpgmeError = gpgme_op_setexpire(mCtx, key.key_refer,
+ expires_time, subfprs, 0);
+ if (gpgmeError == GPG_ERR_NO_ERROR) {
+ emit signalKeyUpdated(key.id);
+ return true;
+ } else {
+ checkErr(gpgmeError);
+ return false;
+ }
+}
+
+/**
+ * Export the secret key of a key pair(including subkeys)
+ * @param key target key pair
+ * @param outBuffer output byte array
+ * @return if successful
+ */
+bool GpgME::GpgContext::exportSecretKey(const GpgKey &key, QByteArray *outBuffer) {
+ qDebug() << "Export Secret Key" << key.id;
+ gpgme_key_t target_key[2] = {
+ key.key_refer,
+ nullptr
+ };
+
+ gpgme_data_t dataOut;
+ gpgme_data_new(&dataOut);
+
+ // export private key to outBuffer
+ gpgme_error_t error = gpgme_op_export_keys(mCtx, target_key, GPGME_EXPORT_MODE_SECRET, dataOut);
+
+ if (gpgme_err_code(error) != GPG_ERR_NO_ERROR) {
+ checkErr(error);
+ gpgme_data_release(dataOut);
+ return false;
+ }
+
+ readToBuffer(dataOut, outBuffer);
+ gpgme_data_release(dataOut);
+ return true;
+}
+
+/**
+ * Sign a key pair(actually a certain uid)
+ * @param target target key pair
+ * @param uid target
+ * @param expires expire date and time of the signature
+ * @return if successful
+ */
+bool GpgME::GpgContext::signKey(const GpgKey &target, const QVector<GpgKey> &keys, const QString &uid,
+ const QDateTime *expires) {
+
+ setSigners(keys, mCtx);
+
+ unsigned int flags = 0;
+
+ unsigned int expires_time_t = 0;
+ if (expires == nullptr) flags |= GPGME_KEYSIGN_NOEXPIRE;
+ else expires_time_t = QDateTime::currentDateTime().secsTo(*expires);
+
+ auto gpgmeError =
+ gpgme_op_keysign(mCtx, target.key_refer, uid.toUtf8().constData(), expires_time_t, flags);
+
+ if (gpgmeError == GPG_ERR_NO_ERROR) {
+ emit signalKeyUpdated(target.id);
+ return true;
+ } else {
+ checkErr(gpgmeError);
+ return false;
+ }
+}
+
+/**
+ * Generate revoke cert of a key pair
+ * @param key target key pair
+ * @param outputFileName out file name(path)
+ * @return the process doing this job
+ */
+void GpgME::GpgContext::generateRevokeCert(const GpgKey &key, const QString &outputFileName) {
+ executeGpgCommand({
+ "--command-fd",
+ "0",
+ "--status-fd",
+ "1",
+ //"--no-tty",
+ "-o",
+ outputFileName,
+ "--gen-revoke",
+ key.fpr
+ },
+ [](QProcess *proc) -> void {
+ qDebug() << "Function Called" << proc;
+ // Code From Gpg4Win
+ while (proc->canReadLine()) {
+ const QString line = QString::fromUtf8(proc->readLine()).trimmed();
+ 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");
+ }
+ }
+ // Code From Gpg4Win
+ }
+ );
+}
diff --git a/src/gpg/gpg_context/GpgContextSubkeyOpera.cpp b/src/gpg/gpg_context/GpgContextSubkeyOpera.cpp
new file mode 100644
index 00000000..10243f5e
--- /dev/null
+++ b/src/gpg/gpg_context/GpgContextSubkeyOpera.cpp
@@ -0,0 +1,61 @@
+/**
+ * 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.
+ *
+ * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "gpg/GpgContext.h"
+
+/**
+ * Generate a new subkey of a certain key pair
+ * @param key target key pair
+ * @param params opera args
+ * @return error info
+ */
+gpgme_error_t GpgME::GpgContext::generateSubkey(const GpgKey &key, GenKeyInfo *params) {
+
+ if (!params->isSubKey()) return GPG_ERR_CANCELED;
+
+ auto algo_utf8 = (params->getAlgo() + params->getKeySizeStr()).toUtf8();
+ const char *algo = algo_utf8.constData();
+ unsigned long expires = QDateTime::currentDateTime().secsTo(params->getExpired());
+ unsigned int flags = 0;
+
+ if (!params->isSubKey()) flags |= GPGME_CREATE_CERT;
+ if (params->isAllowEncryption()) flags |= GPGME_CREATE_ENCR;
+ if (params->isAllowSigning()) flags |= GPGME_CREATE_SIGN;
+ if (params->isAllowAuthentication()) flags |= GPGME_CREATE_AUTH;
+ if (params->isNonExpired()) flags |= GPGME_CREATE_NOEXPIRE;
+
+ flags |= GPGME_CREATE_NOPASSWD;
+
+
+ auto gpgmeError = gpgme_op_createsubkey(mCtx, key.key_refer,
+ algo, 0, expires, flags);
+ if (gpgme_err_code(gpgmeError) == GPG_ERR_NO_ERROR) {
+ emit signalKeyUpdated(key.id);
+ return gpgmeError;
+ } else {
+ checkErr(gpgmeError);
+ return gpgmeError;
+ }
+}
+
diff --git a/src/gpg/gpg_context/GpgContextUIDOpera.cpp b/src/gpg/gpg_context/GpgContextUIDOpera.cpp
new file mode 100644
index 00000000..b96f5f8f
--- /dev/null
+++ b/src/gpg/gpg_context/GpgContextUIDOpera.cpp
@@ -0,0 +1,80 @@
+/**
+ * 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.
+ *
+ * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "gpg/GpgContext.h"
+
+/**
+ * create a new uid in certain key pair
+ * @param key target key pair
+ * @param uid uid args
+ * @return if successful
+ */
+bool GpgME::GpgContext::addUID(const GpgKey &key, const GpgUID &uid) {
+ QString userid = QString("%1 (%3) <%2>").arg(uid.name, uid.email, uid.comment);
+ auto gpgmeError = gpgme_op_adduid(mCtx, key.key_refer, userid.toUtf8().constData(), 0);
+ if (gpgmeError == GPG_ERR_NO_ERROR) {
+ emit signalKeyUpdated(key.id);
+ return true;
+ } else {
+ checkErr(gpgmeError);
+ return false;
+ }
+
+}
+
+/**
+ * Revoke(Delete) UID from certain key pair
+ * @param key target key pair
+ * @param uid target uid
+ * @return if successful
+ */
+bool GpgME::GpgContext::revUID(const GpgKey &key, const GpgUID &uid) {
+ auto gpgmeError = gpgme_op_revuid(mCtx, key.key_refer, uid.uid.toUtf8().constData(), 0);
+ if (gpgmeError == GPG_ERR_NO_ERROR) {
+ emit signalKeyUpdated(key.id);
+ return true;
+ } else {
+ checkErr(gpgmeError);
+ return false;
+ }
+}
+
+/**
+ * Set one of a uid of a key pair as primary
+ * @param key target key pair
+ * @param uid target uid
+ * @return if successful
+ */
+bool GpgME::GpgContext::setPrimaryUID(const GpgKey &key, const GpgUID &uid) {
+ auto gpgmeError = gpgme_op_set_uid_flag(mCtx, key.key_refer,
+ uid.uid.toUtf8().constData(), "primary", nullptr);
+ if (gpgmeError == GPG_ERR_NO_ERROR) {
+ emit signalKeyUpdated(key.id);
+ return true;
+ } else {
+ checkErr(gpgmeError);
+ return false;
+ }
+}
+
diff --git a/src/gpg/result_analyse/DecryptResultAnalyse.cpp b/src/gpg/result_analyse/DecryptResultAnalyse.cpp
index 7eda4027..b4d0b14f 100644
--- a/src/gpg/result_analyse/DecryptResultAnalyse.cpp
+++ b/src/gpg/result_analyse/DecryptResultAnalyse.cpp
@@ -1,59 +1,86 @@
-//
-// Created by eric on 2021/6/9.
-//
+/**
+ * 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.
+ *
+ * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
#include "gpg/result_analyse/DecryptResultAnalyse.h"
DecryptResultAnalyse::DecryptResultAnalyse(GpgME::GpgContext *ctx, gpgme_error_t error, gpgme_decrypt_result_t result)
: mCtx(ctx) {
- stream << "Decrypt Report: " << Qt::endl << "-----" << Qt::endl;
+ stream << tr("[#] Decrypt Operation ");
if (gpgme_err_code(error) == GPG_ERR_NO_ERROR) {
- stream << "Status: Success" << Qt::endl;
+ stream << tr("[Success]") << Qt::endl;
} else {
+ stream << tr("[Failed] ") << gpgme_strerror(error) << Qt::endl;
setStatus(-1);
- stream << "Status: " << gpgme_strerror(error) << Qt::endl;
-
- if (result != nullptr && result->unsupported_algorithm != nullptr)
- stream << "Unsupported algo: " << result->unsupported_algorithm << Qt::endl;
+ if (result != nullptr && result->unsupported_algorithm != nullptr) {
+ stream << "------------>" << Qt::endl;
+ stream << tr("Unsupported Algo: ") << result->unsupported_algorithm << Qt::endl;
+ }
}
- if(result != nullptr) {
- if (result->file_name != nullptr)
- stream << "File name: " << result->file_name << Qt::endl;
- stream << Qt::endl;
+ if (result != nullptr && result->recipients != nullptr) {
+ stream << "------------>" << Qt::endl;
+ if (result->file_name != nullptr) {
+ stream << tr("File Name: ") << result->file_name << Qt::endl;
+ stream << Qt::endl;
+ }
auto reci = result->recipients;
if (reci != nullptr)
- stream << "Recipient(s): " << Qt::endl;
+ stream << tr("Recipient(s): ") << Qt::endl;
while (reci != nullptr) {
printReci(stream, reci);
reci = reci->next;
}
+ stream << "<------------" << Qt::endl;
}
- stream << "-----" << Qt::endl << Qt::endl;
+ stream << Qt::endl;
}
bool DecryptResultAnalyse::printReci(QTextStream &stream, gpgme_recipient_t reci) {
bool keyFound = true;
- stream << QApplication::tr(">Recipient: ");
+ stream << QApplication::tr(" {>} Recipient: ");
- try {
- auto key = mCtx->getKeyById(reci->keyid);
+ auto key = mCtx->getKeyById(reci->keyid);
+ if(key.good) {
stream << key.name;
if (!key.email.isEmpty()) {
stream << "<" << key.email << ">";
}
- } catch(std::runtime_error &ignored) {
+ } else {
stream << "<Unknown>";
setStatus(0);
keyFound = false;
}
+
stream << Qt::endl;
- stream << "Public algo: " << gpgme_pubkey_algo_name(reci->pubkey_algo) << Qt::endl << Qt::endl;
+ stream << tr(" Keu ID: ") << reci->keyid << Qt::endl;
+ stream << tr(" Public Algo: ") << gpgme_pubkey_algo_name(reci->pubkey_algo) << Qt::endl;
+
return keyFound;
}
diff --git a/src/gpg/result_analyse/EncryptResultAnalyse.cpp b/src/gpg/result_analyse/EncryptResultAnalyse.cpp
index dfcad1ac..1ba685c9 100644
--- a/src/gpg/result_analyse/EncryptResultAnalyse.cpp
+++ b/src/gpg/result_analyse/EncryptResultAnalyse.cpp
@@ -1,33 +1,58 @@
-//
-// Created by eric on 2021/6/9.
-//
+/**
+ * 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.
+ *
+ * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
#include "gpg/result_analyse/EncryptResultAnalyse.h"
EncryptResultAnalyse::EncryptResultAnalyse(gpgme_error_t error, gpgme_encrypt_result_t result) {
- stream << "# Encrypt Report: " << Qt::endl << "-----" << Qt::endl;
+ qDebug() << "Start Encrypt Result Analyse";
- if(gpgme_err_code(error) == GPG_ERR_NO_ERROR) {
- stream << "Status: Encrypt Success" << Qt::endl;
- }
+ stream << "[#] Encrypt Operation ";
+
+ if(gpgme_err_code(error) == GPG_ERR_NO_ERROR)
+ stream << "[Success]" << Qt::endl;
else {
- stream << "Status:" << gpgme_strerror(error) << Qt::endl;
+ stream << "[Failed] " << gpgme_strerror(error) << Qt::endl;
setStatus(-1);
+ }
+
+ if(!~status) {
+ stream << "------------>" << Qt::endl;
if (result != nullptr) {
- stream << "Invalid Recipients: " << Qt::endl;
+ stream << tr("Invalid Recipients: ") << Qt::endl;
auto inv_reci = result->invalid_recipients;
while (inv_reci != nullptr) {
- stream << "Fingerprint: " << inv_reci->fpr << Qt::endl;
- stream << "Reason: " << gpgme_strerror(inv_reci->reason) << Qt::endl;
+ stream << tr("Fingerprint: ") << inv_reci->fpr << Qt::endl;
+ stream << tr("Reason: ") << gpgme_strerror(inv_reci->reason) << Qt::endl;
stream << Qt::endl;
inv_reci = inv_reci->next;
}
}
+ stream << "<------------" << Qt::endl;
}
- stream << "-----" << Qt::endl;
stream << Qt::endl;
}
diff --git a/src/gpg/result_analyse/ResultAnalyse.cpp b/src/gpg/result_analyse/ResultAnalyse.cpp
index 960c24cd..7186d21a 100644
--- a/src/gpg/result_analyse/ResultAnalyse.cpp
+++ b/src/gpg/result_analyse/ResultAnalyse.cpp
@@ -1,6 +1,26 @@
-//
-// Created by eric on 2021/6/8.
-//
+/**
+ * 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.
+ *
+ * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
#include "gpg/result_analyse/ResultAnalyse.h"
diff --git a/src/gpg/result_analyse/SignResultAnalyse.cpp b/src/gpg/result_analyse/SignResultAnalyse.cpp
index fac598d5..10d76678 100644
--- a/src/gpg/result_analyse/SignResultAnalyse.cpp
+++ b/src/gpg/result_analyse/SignResultAnalyse.cpp
@@ -24,58 +24,73 @@
#include "gpg/result_analyse/SignResultAnalyse.h"
-SignResultAnalyse::SignResultAnalyse(gpgme_error_t error, gpgme_sign_result_t result) {
+SignResultAnalyse::SignResultAnalyse(GpgME::GpgContext *ctx, gpgme_error_t error, gpgme_sign_result_t result) {
- stream << "# Sign Report: " << Qt::endl
- << "-----" << Qt::endl;
- stream << "Status: " << gpgme_strerror(error) << Qt::endl << Qt::endl;
+ qDebug() << "Start Sign Result Analyse";
- if(gpg_err_code(error) != GPG_ERR_NO_ERROR) {
+ stream << tr("[#] Sign Operation ");
+
+ if (gpgme_err_code(error) == GPG_ERR_NO_ERROR)
+ stream << tr("[Success]") << Qt::endl;
+ else {
+ stream << tr("[Failed] ") << gpgme_strerror(error) << Qt::endl;
setStatus(-1);
}
- if(result != nullptr) {
+ if (result != nullptr && (result->signatures != nullptr || result->invalid_signers != nullptr)) {
+ qDebug() << "Sign Result Analyse Getting Result";
+ stream << "------------>" << Qt::endl;
auto new_sign = result->signatures;
while (new_sign != nullptr) {
- stream << "> A New Signature: " << Qt::endl;
+ stream << tr("[>] New Signature: ") << Qt::endl;
+
+ qDebug() << "Signers Fingerprint: " << new_sign->fpr;
- stream << "Sign mode: ";
+ stream << tr(" Sign Mode: ");
if (new_sign->type == GPGME_SIG_MODE_NORMAL)
- stream << "Normal";
+ stream << tr("Normal");
else if (new_sign->type == GPGME_SIG_MODE_CLEAR)
- stream << "Clear";
+ stream << tr("Clear");
else if (new_sign->type == GPGME_SIG_MODE_DETACH)
- stream << "Detach";
+ stream << tr("Detach");
stream << Qt::endl;
- stream << "Public key algo: " << gpgme_pubkey_algo_name(new_sign->pubkey_algo) << Qt::endl;
- stream << "Hash algo: " << gpgme_hash_algo_name(new_sign->hash_algo) << Qt::endl;
- stream << "Date of signature: " << QDateTime::fromTime_t(new_sign->timestamp).toString() << Qt::endl;
+ GpgKey singerKey = ctx->getKeyByFpr(new_sign->fpr);
+ if(singerKey.good) {
+ stream << tr(" Signer: ") << singerKey.uids.first().uid << Qt::endl;
+ } else {
+ stream << tr(" Signer: ") << tr("<unknown>") << Qt::endl;
+ }
+ stream << tr(" Public Key Algo: ") << gpgme_pubkey_algo_name(new_sign->pubkey_algo) << Qt::endl;
+ stream << tr(" Hash Algo: ") << gpgme_hash_algo_name(new_sign->hash_algo) << Qt::endl;
+ stream << tr(" Date & Time: ") << QDateTime::fromTime_t(new_sign->timestamp).toString() << Qt::endl;
stream << Qt::endl;
new_sign = new_sign->next;
}
+ qDebug() << "Sign Result Analyse Getting Invalid Signer";
+
auto invalid_signer = result->invalid_signers;
if (invalid_signer != nullptr)
- stream << "Invalid Signers: " << Qt::endl;
+ stream << tr("Invalid Signers: ") << Qt::endl;
while (invalid_signer != nullptr) {
setStatus(0);
- stream << "Fingerprint: " << invalid_signer->fpr << Qt::endl;
- stream << "Reason: " << gpgme_strerror(invalid_signer->reason) << Qt::endl;
+ stream << tr("[>] Signer: ") << Qt::endl;
+ stream << tr(" Fingerprint: ") << invalid_signer->fpr << Qt::endl;
+ stream << tr(" Reason: ") << gpgme_strerror(invalid_signer->reason) << Qt::endl;
stream << Qt::endl;
invalid_signer = invalid_signer->next;
}
+ stream << "<------------" << Qt::endl;
}
- stream << "-----" << Qt::endl << Qt::endl;
-
}
diff --git a/src/gpg/result_analyse/VerifyResultAnalyse.cpp b/src/gpg/result_analyse/VerifyResultAnalyse.cpp
index 59c7e3ef..75e07d33 100644
--- a/src/gpg/result_analyse/VerifyResultAnalyse.cpp
+++ b/src/gpg/result_analyse/VerifyResultAnalyse.cpp
@@ -1,6 +1,26 @@
-//
-// Created by eric on 2021/6/7.
-//
+/**
+ * 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.
+ *
+ * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
#include "GpgFrontend.h"
#include "gpg/result_analyse/VerifyResultAnalyse.h"
@@ -8,23 +28,31 @@
VerifyResultAnalyse::VerifyResultAnalyse(GpgME::GpgContext *ctx, gpgme_error_t error, gpgme_verify_result_t result)
: mCtx(ctx) {
- stream << "# Verify Report: " << Qt::endl << "-----" << Qt::endl;
- stream << "Status: " << gpgme_strerror(error) << Qt::endl;
+ qDebug() << "Verify Result Analyse Started";
- if(result != nullptr) {
+ stream << tr("[#] Verify Operation ");
+ if (gpgme_err_code(error) == GPG_ERR_NO_ERROR)
+ stream << tr("[Success]") << Qt::endl;
+ else {
+ stream << tr("[Failed] ") << gpgme_strerror(error) << Qt::endl;
+ setStatus(-1);
+ }
+
+
+ if (result != nullptr && result->signatures) {
+ stream << "------------>" << Qt::endl;
auto sign = result->signatures;
if (sign == nullptr) {
- stream << "> Not Signature Found" << Qt::endl;
+ stream << "[>] Not Signature Found" << Qt::endl;
setStatus(0);
return;
}
+ stream << "[>] Signed On " << QDateTime::fromTime_t(sign->timestamp).toString() << Qt::endl;
- stream << "> It was Signed ON " << QDateTime::fromTime_t(sign->timestamp).toString() << Qt::endl;
-
- stream << Qt::endl << "> It Contains:" << Qt::endl;
+ stream << Qt::endl << "[>] Signatures:" << Qt::endl;
bool canContinue = true;
@@ -63,13 +91,11 @@ VerifyResultAnalyse::VerifyResultAnalyse(GpgME::GpgContext *ctx, gpgme_error_t e
if (sign->summary & GPGME_SIGSUM_VALID) {
stream << QApplication::tr("Signature Fully Valid.") << Qt::endl;
} else {
- stream << QApplication::tr("Signature NOT Fully Valid.") << Qt::endl;
+ stream << QApplication::tr("Signature Not Fully Valid.") << Qt::endl;
}
if (!(sign->status & GPGME_SIGSUM_KEY_MISSING)) {
- if (!printSigner(stream, sign)) {
- setStatus(0);
- }
+ if (!printSigner(stream, sign)) setStatus(0);
} else {
stream << QApplication::tr("Key is NOT present with ID 0x") << QString(sign->fpr) << Qt::endl;
}
@@ -117,26 +143,26 @@ VerifyResultAnalyse::VerifyResultAnalyse(GpgME::GpgContext *ctx, gpgme_error_t e
stream << Qt::endl;
sign = sign->next;
}
+ stream << "<------------" << Qt::endl;
}
-
- stream << "-----" << Qt::endl;
- stream << Qt::endl;
}
bool VerifyResultAnalyse::printSigner(QTextStream &stream, gpgme_signature_t sign) {
bool keyFound = true;
- stream << QApplication::tr("Signed By: ");
auto key = mCtx->getKeyByFpr(sign->fpr);
- if(!key.good) {
- stream << "<Unknown>";
+
+ key = mCtx->getKeyByFpr(sign->fpr);
+
+ if (!key.good) {
+ stream << tr(" Signed By: ") << tr("<unknown>") << Qt::endl;
setStatus(0);
keyFound = false;
+ } else {
+ stream << tr(" Signed By: ") << key.uids.first().uid << Qt::endl;
}
- stream << key.name;
- if (!key.email.isEmpty()) {
- stream << "<" << key.email << ">";
- }
+ stream << tr(" Public Key Algo: ") << gpgme_pubkey_algo_name(sign->pubkey_algo) << Qt::endl;
+ stream << tr(" Hash Algo: ") << gpgme_hash_algo_name(sign->hash_algo) << Qt::endl;
+ stream << tr(" Date & Time: ") << QDateTime::fromTime_t(sign->timestamp).toString() << Qt::endl;
stream << Qt::endl;
return keyFound;
-
} \ No newline at end of file
diff --git a/src/main.cpp b/src/main.cpp
index ff3b0bb4..1ec264e7 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -43,12 +43,14 @@ int main(int argc, char *argv[]) {
// unicode in source
QTextCodec::setCodecForLocale(QTextCodec::codecForName("utf-8"));
- // css
+#if OS_PLATFORM == WINDOWS
+ // load css file
QFile file(RESOURCE_DIR(qApp->applicationDirPath()) + "/css/default.qss");
file.open(QFile::ReadOnly);
QString styleSheet = QLatin1String(file.readAll());
qApp->setStyleSheet(styleSheet);
file.close();
+#endif
/**
* internationalisation. loop to restart mainwindow
diff --git a/src/server/BaseAPI.cpp b/src/server/BaseAPI.cpp
new file mode 100644
index 00000000..be388df9
--- /dev/null
+++ b/src/server/BaseAPI.cpp
@@ -0,0 +1,70 @@
+/**
+ * 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.
+ *
+ * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "server/BaseAPI.h"
+#include "rapidjson/writer.h"
+
+BaseAPI::BaseAPI(ComUtils::ServiceType serviceType) : utils(new ComUtils(nullptr)),
+ reqUrl(utils->getUrl(serviceType)), request(reqUrl) {
+ request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
+}
+
+BaseAPI::~BaseAPI() {
+ utils->deleteLater();
+}
+
+QNetworkReply *BaseAPI::send_json_data() {
+ rapidjson::StringBuffer sb;
+ rapidjson::Writer<rapidjson::StringBuffer> writer(sb);
+ document.Accept(writer);
+
+ QByteArray postData(sb.GetString());
+ qDebug() << "postData" << QString::fromUtf8(postData);
+
+ auto reply = utils->getNetworkManager().post(request, postData);
+
+ while (reply->isRunning()) QApplication::processEvents();
+
+ QByteArray replyData = reply->readAll().constData();
+ if (utils->checkServerReply(replyData)) {
+ good = true, deal_reply();
+ }
+
+ return reply;
+}
+
+void BaseAPI::start() {
+ construct_json();
+ send_json_data()->deleteLater();
+}
+
+void BaseAPI::refresh() {
+ document.Clear();
+ utils->clear();
+ good = false;
+}
+
+bool BaseAPI::result() const {
+ return good;
+}
diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt
new file mode 100644
index 00000000..423e9d1e
--- /dev/null
+++ b/src/server/CMakeLists.txt
@@ -0,0 +1,7 @@
+aux_source_directory(./api SERVER_SOURCE)
+aux_source_directory(. SERVER_SOURCE)
+
+add_library(server STATIC ${SERVER_SOURCE})
+
+target_link_libraries(server
+ Qt5::Network Qt5::Widgets Qt5::Core)
diff --git a/src/server/ComUtils.cpp b/src/server/ComUtils.cpp
new file mode 100644
index 00000000..01be4ea7
--- /dev/null
+++ b/src/server/ComUtils.cpp
@@ -0,0 +1,197 @@
+/**
+ * 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.
+ *
+ * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "server/ComUtils.h"
+
+/**
+ * check server reply if it can parse into a json object
+ * @param reply reply data in byte array
+ * @return if successful
+ */
+bool ComUtils::checkServerReply(const QByteArray &reply) {
+
+ if(reply.isEmpty()) {
+ QMessageBox::critical(this, tr("Error"), tr("Nothing Reply. Please check the Internet connection."));
+ return false;
+ }
+
+ qDebug() << "Reply" << reply;
+
+ /**
+ * Server Reply Format(Except Timeout)
+ * {
+ * "status": 200,
+ * "msg": "OK",
+ * "timestamp": 1628652783895
+ * "data" : {
+ * ...
+ * }
+ * }
+ */
+
+ // check if reply is a json object
+ if (replyDoc.Parse(reply).HasParseError() || !replyDoc.IsObject()) {
+ QMessageBox::critical(this, tr("Error"), tr("Unknown Error"));
+ return false;
+ }
+
+ // check status(int) and message(string)
+ if (replyDoc.HasMember("status") && replyDoc.HasMember("msg") && replyDoc.HasMember("timestamp") &&
+ replyDoc.HasMember("data")
+ && replyDoc["status"].IsNumber() && replyDoc["msg"].IsString() && replyDoc["timestamp"].IsNumber() &&
+ replyDoc["data"].IsObject()) {
+
+ int status = replyDoc["status"].GetInt();
+ QDateTime time;
+ time.setMSecsSinceEpoch(replyDoc["timestamp"].GetInt64());
+ auto message = replyDoc["msg"].GetString();
+ dataVal = replyDoc["data"].GetObject();
+
+ qDebug() << "Reply Date & Time" << time;
+
+ // check reply timestamp
+ if (time < QDateTime::currentDateTime().addSecs(-10)) {
+ QMessageBox::critical(this, tr("Network Error"), tr("Outdated Reply"));
+ return false;
+ }
+
+ // check status code if successful (200-299)
+ // check data object
+ if (status / 100 == 2) {
+ is_good = true;
+ return true;
+ } else {
+ if (dataVal.HasMember("exceptionMessage") && dataVal["exceptionMessage"].IsString())
+ QMessageBox::critical(this, message, dataVal["exceptionMessage"].GetString());
+ else QMessageBox::critical(this, message, tr("Unknown Reason"));
+ }
+
+ } else QMessageBox::critical(this, tr("Network Error"), tr("Unknown Reply Format"));
+
+ return false;
+}
+
+/**
+ * get value in data
+ * @param key key of value
+ * @return value in string format
+ */
+QString ComUtils::getDataValueStr(const QString &key) const {
+ if (is_good) {
+ auto k_byte_array = key.toUtf8();
+ if (dataVal.HasMember(k_byte_array.data())) {
+ return dataVal[k_byte_array.data()].GetString();
+ } else return {};
+ } else return {};
+}
+
+/**
+ * Get eventually url by service type
+ * @param type service which server provides
+ * @return url
+ */
+QString ComUtils::getUrl(ComUtils::ServiceType type) const {
+ auto host = settings.value("general/currentGpgfrontendServer",
+ "service.gpgfrontend.pub").toString();
+
+ auto protocol = QString();
+ // Localhost Debug Server
+ if (host == "localhost") protocol = "http://";
+ else protocol = "https://";
+
+ auto url = protocol + host + ":9049/";
+
+ switch (type) {
+ case GetServiceToken:
+ url += "/user";
+ break;
+ case ShortenCryptText:
+ url += "/text/new";
+ break;
+ case GetFullCryptText:
+ url += "/text/get";
+ break;
+ case UploadPubkey:
+ url += "/key/upload";
+ break;
+ case GetPubkey:
+ url += "/key/get";
+ break;
+ }
+
+ qDebug() << "ComUtils getUrl" << url;
+
+ return url;
+}
+
+bool ComUtils::checkDataValueStr(const QString &key) const {
+ auto key_byte_array_data = key.toUtf8().constData();
+ if (is_good) {
+ return dataVal.HasMember(key_byte_array_data) && dataVal[key_byte_array_data].IsString();
+ } else return false;
+}
+
+bool ComUtils::checkServiceTokenFormat(const QString &uuid) const {
+ return re_uuid.match(uuid).hasMatch();
+}
+
+QByteArray ComUtils::getSignStringBase64(GpgME::GpgContext *ctx, const QString &str, const GpgKey &key) {
+ QVector<GpgKey> keys{key};
+ QByteArray outSignText;
+ auto signData = str.toUtf8();
+
+ // The use of multi-threading brings an improvement in UI smoothness
+ gpgme_error_t error;
+ auto thread = QThread::create([&]() {
+ error = ctx->sign(keys, signData, &outSignText, GPGME_SIG_MODE_NORMAL, nullptr, false);
+ });
+ thread->start();
+ while (thread->isRunning()) QApplication::processEvents();
+ thread->deleteLater();
+
+ return outSignText.toBase64();
+}
+
+const rapidjson::Value &ComUtils::getDataValue(const QString &key) const {
+ if (is_good) {
+ auto k_byte_array = key.toUtf8();
+ if (dataVal.HasMember(k_byte_array.data())) {
+ return dataVal[k_byte_array.data()];
+ }
+ }
+ throw std::runtime_error("Inner Error");
+}
+
+bool ComUtils::checkDataValue(const QString &key) const{
+ auto key_byte_array_data = key.toUtf8().constData();
+ if (is_good) {
+ return dataVal.HasMember(key_byte_array_data);
+ } else return false;
+}
+
+void ComUtils::clear() {
+ this->dataVal.Clear();
+ this->replyDoc.Clear();
+ is_good = false;
+} \ No newline at end of file
diff --git a/src/server/api/PubkeyGetter.cpp b/src/server/api/PubkeyGetter.cpp
new file mode 100644
index 00000000..2ba55d11
--- /dev/null
+++ b/src/server/api/PubkeyGetter.cpp
@@ -0,0 +1,96 @@
+/**
+ * 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.
+ *
+ * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "server/api/PubkeyGetter.h"
+
+PubkeyGetter::PubkeyGetter(GpgME::GpgContext *ctx, const QVector<QString> &fprs) : BaseAPI(ComUtils::GetPubkey),
+ mCtx(ctx), mFprs(fprs) {
+}
+
+void PubkeyGetter::construct_json() {
+ document.SetArray();
+ QStringList keyIds;
+
+ rapidjson::Document::AllocatorType &allocator = document.GetAllocator();
+
+ for (const auto &fprStr : mFprs) {
+ rapidjson::Value fpr;
+
+ auto fprByteArray = fprStr.toUtf8();
+ fpr.SetString(fprByteArray.constData(), fprByteArray.count());
+
+ document.PushBack(fpr, allocator);
+ keyIds.clear();
+ }
+}
+
+void PubkeyGetter::deal_reply() {
+
+ const auto &utils = getUtils();
+
+ /**
+ * {
+ * "pubkeys" : [
+ * {
+ * "publicKey" : ...,
+ * "fpr" : ...,
+ * "sha" : ...
+ * },
+ * ...
+ * ]
+ * }
+ */
+
+ if (!utils.checkDataValue("pubkeys")) {
+ QMessageBox::critical(nullptr, tr("Error"),
+ tr("The communication content with the server does not meet the requirements"));
+ } else {
+ auto &pubkeys = utils.getDataValue("pubkeys");
+ qDebug() << "Pubkey Getter" << pubkeys.IsArray() << pubkeys.GetArray().Size();
+ if (pubkeys.IsArray()) {
+ for (const auto &pubkey : pubkeys.GetArray()) {
+ if (pubkey.IsObject()
+ && pubkey.HasMember("publicKey") && pubkey.HasMember("fpr") && pubkey.HasMember("sha")
+ && pubkey["publicKey"].IsString() && pubkey["fpr"].IsString() && pubkey["sha"].IsString()) {
+
+ auto pubkeyData = QString(pubkey["publicKey"].GetString());
+
+ QCryptographicHash shaGen(QCryptographicHash::Sha256);
+ shaGen.addData(pubkeyData.toUtf8());
+
+ if (shaGen.result().toHex() == pubkey["sha"].GetString()) {
+ mCtx->importKey(pubkeyData.toUtf8());
+ }
+
+ }
+ }
+
+ } else {
+ QMessageBox::critical(nullptr, tr("Error"),
+ tr("The communication content with the server does not meet the requirements"));
+ }
+ }
+}
+
+
diff --git a/src/server/api/PubkeyUploader.cpp b/src/server/api/PubkeyUploader.cpp
new file mode 100644
index 00000000..c6101c65
--- /dev/null
+++ b/src/server/api/PubkeyUploader.cpp
@@ -0,0 +1,106 @@
+/**
+ * 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.
+ *
+ * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "server/api/PubkeyUploader.h"
+
+PubkeyUploader::PubkeyUploader(GpgME::GpgContext *ctx, const QVector<GpgKey> &keys) : BaseAPI(ComUtils::UploadPubkey),
+ mCtx(ctx),
+ mKeys(keys) {
+}
+
+void PubkeyUploader::construct_json() {
+ document.SetArray();
+ QStringList keyIds;
+ QCryptographicHash shaGen(QCryptographicHash::Sha256);
+
+ auto &allocator = document.GetAllocator();
+
+ QVector<QByteArray> keysData;
+ for (const auto &key : mKeys) {
+ QByteArray keyDataBuf;
+ keyIds << key.id;
+
+ // The use of multi-threading brings an improvement in UI smoothness
+ gpgme_error_t error;
+ auto thread = QThread::create([&]() {
+ error = mCtx->exportKeys(&keyIds, &keyDataBuf);
+ });
+ thread->start();
+ while (thread->isRunning()) QApplication::processEvents();
+ thread->deleteLater();
+ keysData.push_back(keyDataBuf);
+ keyIds.clear();
+ }
+
+ int index = 0;
+ for (const auto &keyData : keysData) {
+ rapidjson::Value publicKeyObj, pubkey, sha, signedFpr;
+
+ shaGen.addData(keyData);
+ auto shaStr = shaGen.result().toHex();
+ shaGen.reset();
+
+ auto signFprStr = ComUtils::getSignStringBase64(mCtx, mKeys[index].fpr, mKeys[index]);
+ qDebug() << "signFprStr" << signFprStr;
+
+ pubkey.SetString(keyData.data(), keyData.count(), allocator);
+ sha.SetString(shaStr.data(), shaStr.count(), allocator);
+ signedFpr.SetString(signFprStr.data(), signFprStr.count(), allocator);
+
+ publicKeyObj.SetObject();
+ publicKeyObj.AddMember("publicKey", pubkey, allocator);
+ publicKeyObj.AddMember("sha", sha, allocator);
+ publicKeyObj.AddMember("signedFpr", signedFpr, allocator);
+
+ document.PushBack(publicKeyObj, allocator);
+ index++;
+ }
+}
+
+void PubkeyUploader::deal_reply() {
+
+ const auto &utils = getUtils();
+
+ /**
+ * {
+ * "strings" : [
+ * "...",
+ * "..."
+ * ]
+ * }
+ */
+
+ if (!utils.checkDataValue("strings")) {
+ QMessageBox::critical(nullptr, tr("Error"),
+ tr("The communication content with the server does not meet the requirements"));
+ } else {
+ auto &strings = utils.getDataValue("strings");
+ qDebug() << "Pubkey Uploader" << strings.IsArray() << strings.GetArray().Size();
+ if (strings.IsArray() && strings.GetArray().Size() == mKeys.size()) {
+ good = true;
+ } else {
+ good = false;
+ }
+ }
+}
diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt
index 618b5d28..b6552227 100644
--- a/src/ui/CMakeLists.txt
+++ b/src/ui/CMakeLists.txt
@@ -4,6 +4,7 @@ aux_source_directory(./widgets UI_SOURCE)
aux_source_directory(./keygen UI_SOURCE)
aux_source_directory(./main_window UI_SOURCE)
aux_source_directory(./help UI_SOURCE)
+aux_source_directory(./settings UI_SOURCE)
add_library(gpgfrontend-ui STATIC ${UI_SOURCE})
diff --git a/src/ui/FileEncryptionDialog.cpp b/src/ui/FileEncryptionDialog.cpp
index e92dfc90..23ec0b2a 100755
--- a/src/ui/FileEncryptionDialog.cpp
+++ b/src/ui/FileEncryptionDialog.cpp
@@ -229,7 +229,7 @@ void FileEncryptionDialog::slotExecuteAction() {
if (mAction == Sign) {
qDebug() << "Action Sign";
- gpgme_error_t err = mCtx->sign(keys, inBuffer, outBuffer, true);
+ gpgme_error_t err = mCtx->sign(keys, inBuffer, outBuffer, GPGME_SIG_MODE_DETACH, nullptr);
if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) {
qDebug() << "Error" << gpgme_strerror(err);
QMessageBox::warning(this, tr("Error"),
diff --git a/src/ui/KeyMgmt.cpp b/src/ui/KeyMgmt.cpp
index ce5343bf..77f3b760 100755
--- a/src/ui/KeyMgmt.cpp
+++ b/src/ui/KeyMgmt.cpp
@@ -26,9 +26,9 @@
#include <utility>
-KeyMgmt::KeyMgmt(GpgME::GpgContext *ctx, QWidget *parent ) :
- QMainWindow(parent), appPath(qApp->applicationDirPath()), settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", QSettings::IniFormat)
-{
+KeyMgmt::KeyMgmt(GpgME::GpgContext *ctx, QWidget *parent) :
+ QMainWindow(parent), appPath(qApp->applicationDirPath()),
+ settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", QSettings::IniFormat) {
mCtx = ctx;
/* the list of Keys available*/
@@ -36,14 +36,14 @@ KeyMgmt::KeyMgmt(GpgME::GpgContext *ctx, QWidget *parent ) :
mKeyList->setColumnWidth(2, 250);
mKeyList->setColumnWidth(3, 250);
setCentralWidget(mKeyList);
- mKeyList->setDoubleClickedAction([this] (const GpgKey &key, QWidget *parent) {
+ mKeyList->setDoubleClickedAction([this](const GpgKey &key, QWidget *parent) {
new KeyDetailsDialog(mCtx, key, parent);
});
createActions();
createMenus();
createToolBars();
- connect(this,SIGNAL(signalStatusBarChanged(QString)),this->parent(),SLOT(slotSetStatusBarText(QString)));
+ connect(this, SIGNAL(signalStatusBarChanged(QString)), this->parent(), SLOT(slotSetStatusBarText(QString)));
/* Restore the iconstyle */
this->settings.sync();
@@ -51,7 +51,8 @@ KeyMgmt::KeyMgmt(GpgME::GpgContext *ctx, QWidget *parent ) :
QSize iconSize = settings.value("toolbar/iconsize", QSize(24, 24)).toSize();
settings.setValue("toolbar/iconsize", iconSize);
- Qt::ToolButtonStyle buttonStyle = static_cast<Qt::ToolButtonStyle>(settings.value("toolbar/iconstyle", Qt::ToolButtonTextUnderIcon).toUInt());
+ Qt::ToolButtonStyle buttonStyle = static_cast<Qt::ToolButtonStyle>(settings.value("toolbar/iconstyle",
+ Qt::ToolButtonTextUnderIcon).toUInt());
this->setIconSize(iconSize);
this->setToolButtonStyle(buttonStyle);
@@ -83,8 +84,7 @@ KeyMgmt::KeyMgmt(GpgME::GpgContext *ctx, QWidget *parent ) :
mKeyList->addMenuAction(showKeyDetailsAct);
}
-void KeyMgmt::createActions()
-{
+void KeyMgmt::createActions() {
openKeyFileAct = new QAction(tr("&Open"), this);
openKeyFileAct->setShortcut(tr("Ctrl+O"));
openKeyFileAct->setToolTip(tr("Open Key File"));
@@ -147,8 +147,7 @@ void KeyMgmt::createActions()
connect(showKeyDetailsAct, SIGNAL(triggered()), this, SLOT(slotShowKeyDetails()));
}
-void KeyMgmt::createMenus()
-{
+void KeyMgmt::createMenus() {
fileMenu = menuBar()->addMenu(tr("&File"));
fileMenu->addAction(openKeyFileAct);
fileMenu->addAction(closeAct);
@@ -168,13 +167,12 @@ void KeyMgmt::createMenus()
keyMenu->addAction(deleteCheckedKeysAct);
}
-void KeyMgmt::createToolBars()
-{
+void KeyMgmt::createToolBars() {
QToolBar *keyToolBar = addToolBar(tr("Key"));
keyToolBar->setObjectName("keytoolbar");
// add button with popup menu for import
- auto* generateToolButton = new QToolButton(this);
+ auto *generateToolButton = new QToolButton(this);
generateToolButton->setMenu(generateKeyMenu);
generateToolButton->setPopupMode(QToolButton::InstantPopup);
generateToolButton->setIcon(QIcon(":key_generate.png"));
@@ -184,7 +182,7 @@ void KeyMgmt::createToolBars()
keyToolBar->addWidget(generateToolButton);
// add button with popup menu for import
- auto* toolButton = new QToolButton(this);
+ auto *toolButton = new QToolButton(this);
toolButton->setMenu(importKeyMenu);
toolButton->setPopupMode(QToolButton::InstantPopup);
toolButton->setIcon(QIcon(":key_import.png"));
@@ -201,17 +199,17 @@ void KeyMgmt::createToolBars()
}
-void KeyMgmt::slotImportKeys(QByteArray inBuffer)
-{
+void KeyMgmt::slotImportKeys(QByteArray inBuffer) {
GpgImportInformation result = mCtx->importKey(std::move(inBuffer));
new KeyImportDetailDialog(mCtx, result, false, this);
}
-void KeyMgmt::slotImportKeyFromFile()
-{
- QString fileName = QFileDialog::getOpenFileName(this, tr("Open Key"), "", tr("Key Files") + " (*.asc *.txt);;"+tr("Keyring files")+" (*.gpg);;All Files (*)");
- if (! fileName.isNull()) {
+void KeyMgmt::slotImportKeyFromFile() {
+ QString fileName = QFileDialog::getOpenFileName(this, tr("Open Key"), "",
+ tr("Key Files") + " (*.asc *.txt);;" + tr("Keyring files") +
+ " (*.gpg);;All Files (*)");
+ if (!fileName.isNull()) {
QFile file;
file.setFileName(fileName);
if (!file.open(QIODevice::ReadOnly)) {
@@ -224,30 +222,25 @@ void KeyMgmt::slotImportKeyFromFile()
}
}
-void KeyMgmt::slotImportKeyFromKeyServer()
-{
+void KeyMgmt::slotImportKeyFromKeyServer() {
importDialog = new KeyServerImportDialog(mCtx, mKeyList, false, this);
importDialog->show();
}
-void KeyMgmt::slotImportKeyFromClipboard()
-{
+void KeyMgmt::slotImportKeyFromClipboard() {
QClipboard *cb = QApplication::clipboard();
slotImportKeys(cb->text(QClipboard::Clipboard).toUtf8());
}
-void KeyMgmt::slotDeleteSelectedKeys()
-{
+void KeyMgmt::slotDeleteSelectedKeys() {
deleteKeysWithWarning(mKeyList->getSelected());
}
-void KeyMgmt::slotDeleteCheckedKeys()
-{
+void KeyMgmt::slotDeleteCheckedKeys() {
deleteKeysWithWarning(mKeyList->getChecked());
}
-void KeyMgmt::deleteKeysWithWarning(QStringList *uidList)
-{
+void KeyMgmt::deleteKeysWithWarning(QStringList *uidList) {
/**
* TODO: Different Messages for private/public key, check if
* more than one selected... compare to seahorse "delete-dialog"
@@ -258,7 +251,8 @@ void KeyMgmt::deleteKeysWithWarning(QStringList *uidList)
}
QString keynames;
for (const auto &uid : *uidList) {
- auto &key = mCtx->getKeyById(uid);
+ auto key = mCtx->getKeyById(uid);
+ if (!key.good) continue;
keynames.append(key.name);
keynames.append("<i> &lt;");
keynames.append(key.email);
@@ -266,8 +260,9 @@ void KeyMgmt::deleteKeysWithWarning(QStringList *uidList)
}
int ret = QMessageBox::warning(this, tr("Deleting Keys"),
- "<b>"+tr("Are you sure that you want to delete the following keys?")+"</b><br/><br/>"+keynames+
- +"<br/>"+tr("The action can not be undone."),
+ "<b>" + tr("Are you sure that you want to delete the following keys?") +
+ "</b><br/><br/>" + keynames +
+ +"<br/>" + tr("The action can not be undone."),
QMessageBox::No | QMessageBox::Yes);
if (ret == QMessageBox::Yes) {
@@ -275,28 +270,36 @@ void KeyMgmt::deleteKeysWithWarning(QStringList *uidList)
}
}
-void KeyMgmt::slotShowKeyDetails()
-{
+void KeyMgmt::slotShowKeyDetails() {
if (mKeyList->getSelected()->isEmpty()) {
return;
}
- auto &key = mCtx->getKeyById(mKeyList->getSelected()->first());
+ auto key = mCtx->getKeyById(mKeyList->getSelected()->first());
+
+ if (!key.good) {
+ QMessageBox::critical(nullptr, tr("Error"), tr("Key Not Found."));
+ return;
+ }
new KeyDetailsDialog(mCtx, key);
}
-void KeyMgmt::slotExportKeyToFile()
-{
+void KeyMgmt::slotExportKeyToFile() {
auto *keyArray = new QByteArray();
if (!mCtx->exportKeys(mKeyList->getChecked(), keyArray)) {
delete keyArray;
return;
}
- auto &key = mCtx->getKeyById(mKeyList->getSelected()->first());
- QString fileString = key.name + " " + key.email+ "(" + key.id+ ")_pub.asc";
+ auto key = mCtx->getKeyById(mKeyList->getSelected()->first());
+ if (!key.good) {
+ QMessageBox::critical(nullptr, tr("Error"), tr("Key Not Found."));
+ return;
+ }
+ QString fileString = key.name + " " + key.email + "(" + key.id + ")_pub.asc";
- QString fileName = QFileDialog::getSaveFileName(this, tr("Export Key To File"), fileString, tr("Key Files") + " (*.asc *.txt);;All Files (*)");
+ QString fileName = QFileDialog::getSaveFileName(this, tr("Export Key To File"), fileString,
+ tr("Key Files") + " (*.asc *.txt);;All Files (*)");
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
delete keyArray;
@@ -309,8 +312,7 @@ void KeyMgmt::slotExportKeyToFile()
emit signalStatusBarChanged(QString(tr("key(s) exported")));
}
-void KeyMgmt::slotExportKeyToClipboard()
-{
+void KeyMgmt::slotExportKeyToClipboard() {
auto *keyArray = new QByteArray();
QClipboard *cb = QApplication::clipboard();
if (!mCtx->exportKeys(mKeyList->getChecked(), keyArray)) {
@@ -320,27 +322,29 @@ void KeyMgmt::slotExportKeyToClipboard()
delete keyArray;
}
-void KeyMgmt::slotGenerateKeyDialog()
-{
- auto *keyGenDialog = new KeyGenDialog(mCtx,this);
+void KeyMgmt::slotGenerateKeyDialog() {
+ auto *keyGenDialog = new KeyGenDialog(mCtx, this);
keyGenDialog->show();
}
-void KeyMgmt::closeEvent(QCloseEvent *event)
-{
+void KeyMgmt::closeEvent(QCloseEvent *event) {
QMainWindow::closeEvent(event);
}
void KeyMgmt::slotGenerateSubKey() {
auto selectedList = mKeyList->getSelected();
- if(selectedList->empty()) {
+ if (selectedList->empty()) {
QMessageBox::information(nullptr,
tr("Invalid Operation"),
tr("Please select one KeyPair before doing this operation."));
return;
}
- const auto &key = mCtx->getKeyById(selectedList->first());
- if(!key.is_private_key) {
+ const auto key = mCtx->getKeyById(selectedList->first());
+ if (!key.good) {
+ QMessageBox::critical(nullptr, tr("Error"), tr("Key Not Found."));
+ return;
+ }
+ if (!key.is_private_key) {
QMessageBox::critical(nullptr,
tr("Invalid Operation"),
tr("If a key pair does not have a private key then it will not be able to generate sub-keys."));
diff --git a/src/ui/KeyUploadDialog.cpp b/src/ui/KeyUploadDialog.cpp
index faf892f0..ab38569f 100644
--- a/src/ui/KeyUploadDialog.cpp
+++ b/src/ui/KeyUploadDialog.cpp
@@ -24,8 +24,6 @@
#include "ui/KeyUploadDialog.h"
-#include <utility>
-
KeyUploadDialog::KeyUploadDialog(GpgME::GpgContext *ctx, const QVector<GpgKey> &keys, QWidget *parent)
: appPath(qApp->applicationDirPath()),
settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", QSettings::IniFormat),
diff --git a/src/ui/SettingsDialog.cpp b/src/ui/SettingsDialog.cpp
deleted file mode 100755
index 1732d718..00000000
--- a/src/ui/SettingsDialog.cpp
+++ /dev/null
@@ -1,777 +0,0 @@
-/**
- * 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.
- *
- * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
- *
- * The initial version of the source code is inherited from gpg4usb-team.
- * Their source code version also complies with GNU General Public License.
- *
- * The source code version of this software was modified and released
- * by Saturneric<[email protected]> starting on May 12, 2021.
- *
- */
-
-#include "ui/SettingsDialog.h"
-#include "smtp/SmtpMime"
-#include "ui/WaitingDialog.h"
-
-SettingsDialog::SettingsDialog(GpgME::GpgContext *ctx, QWidget *parent)
- : QDialog(parent) {
- mCtx = ctx;
- tabWidget = new QTabWidget;
- generalTab = new GeneralTab(mCtx);
- appearanceTab = new AppearanceTab;
- sendMailTab = new SendMailTab;
- keyserverTab = new KeyserverTab;
- advancedTab = new AdvancedTab;
- gpgPathsTab = new GpgPathsTab;
-
- tabWidget->addTab(generalTab, tr("General"));
- tabWidget->addTab(appearanceTab, tr("Appearance"));
- tabWidget->addTab(sendMailTab, tr("Send Mail"));
- tabWidget->addTab(keyserverTab, tr("Key Server"));
- // tabWidget->addTab(gpgPathsTab, tr("Gpg paths"));
- tabWidget->addTab(advancedTab, tr("Advanced"));
-
- buttonBox =
- new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
-
- connect(buttonBox, SIGNAL(accepted()), this, SLOT(slotAccept()));
- connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
-
- auto *mainLayout = new QVBoxLayout;
- mainLayout->addWidget(tabWidget);
- mainLayout->addWidget(buttonBox);
- setLayout(mainLayout);
-
- setWindowTitle(tr("Settings"));
-
- // slots for handling the restartneeded member
- this->slotSetRestartNeeded(false);
- connect(generalTab, SIGNAL(signalRestartNeeded(bool)), this,
- SLOT(slotSetRestartNeeded(bool)));
- connect(appearanceTab, SIGNAL(signalRestartNeeded(bool)), this,
- SLOT(slotSetRestartNeeded(bool)));
- connect(sendMailTab, SIGNAL(signalRestartNeeded(bool)), this,
- SLOT(slotSetRestartNeeded(bool)));
- connect(keyserverTab, SIGNAL(signalRestartNeeded(bool)), this,
- SLOT(slotSetRestartNeeded(bool)));
- connect(advancedTab, SIGNAL(signalRestartNeeded(bool)), this,
- SLOT(slotSetRestartNeeded(bool)));
-
- connect(this, SIGNAL(signalRestartNeeded(bool)), parent,
- SLOT(slotSetRestartNeeded(bool)));
-
- this->show();
-}
-
-bool SettingsDialog::getRestartNeeded() const { return this->restartNeeded; }
-
-void SettingsDialog::slotSetRestartNeeded(bool needed) {
- this->restartNeeded = needed;
-}
-
-void SettingsDialog::slotAccept() {
- generalTab->applySettings();
- sendMailTab->applySettings();
- appearanceTab->applySettings();
- keyserverTab->applySettings();
- advancedTab->applySettings();
- gpgPathsTab->applySettings();
- if (getRestartNeeded()) {
- emit signalRestartNeeded(true);
- }
- close();
-}
-
-// http://www.informit.com/articles/article.aspx?p=1405555&seqNum=3
-// http://developer.qt.nokia.com/wiki/How_to_create_a_multi_language_application
-QHash<QString, QString> SettingsDialog::listLanguages() {
- QHash<QString, QString> languages;
-
- languages.insert("", tr("System Default"));
-
- QString appPath = qApp->applicationDirPath();
- QDir qmDir = QDir(RESOURCE_DIR(appPath) + "/ts/");
- QStringList fileNames = qmDir.entryList(QStringList("gpgfrontend_*.qm"));
-
- for (int i = 0; i < fileNames.size(); ++i) {
- QString locale = fileNames[i];
- locale.truncate(locale.lastIndexOf('.'));
- locale.remove(0, locale.indexOf('_') + 1);
-
- // this works in qt 4.8
- QLocale qloc(locale);
-#if QT_VERSION < 0x040800
- QString language =
- QLocale::languageToString(qloc.language()) + " (" + locale +
- ")"; //+ " (" + QLocale::languageToString(qloc.language()) + ")";
-#else
- QString language = qloc.nativeLanguageName() + " (" + locale + ")";
-#endif
- languages.insert(locale, language);
- }
- return languages;
-}
-
-GeneralTab::GeneralTab(GpgME::GpgContext *ctx, QWidget *parent)
- : QWidget(parent), appPath(qApp->applicationDirPath()),
- settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
- QSettings::IniFormat) {
- mCtx = ctx;
-
- /*****************************************
- * remember Password-Box
- *****************************************/
- auto *rememberPasswordBox = new QGroupBox(tr("Remember Password"));
- auto *rememberPasswordBoxLayout = new QHBoxLayout();
- rememberPasswordCheckBox =
- new QCheckBox(tr("Remember password until closing gpg4usb"), this);
- rememberPasswordBoxLayout->addWidget(rememberPasswordCheckBox);
- rememberPasswordBox->setLayout(rememberPasswordBoxLayout);
-
- /*****************************************
- * Save-Checked-Keys-Box
- *****************************************/
- auto *saveCheckedKeysBox = new QGroupBox(tr("Save Checked Keys"));
- auto *saveCheckedKeysBoxLayout = new QHBoxLayout();
- saveCheckedKeysCheckBox = new QCheckBox(
- tr("Save checked private keys on exit and restore them on next start."),
- this);
- saveCheckedKeysBoxLayout->addWidget(saveCheckedKeysCheckBox);
- saveCheckedKeysBox->setLayout(saveCheckedKeysBoxLayout);
-
- /*****************************************
- * Key-Impport-Confirmation Box
- *****************************************/
- auto *importConfirmationBox =
- new QGroupBox(tr("Confirm drag'n'drop key import"));
- auto *importConfirmationBoxLayout = new QHBoxLayout();
- importConfirmationCheckBox = new QCheckBox(
- tr("Import files dropped on the keylist without confirmation."), this);
- importConfirmationBoxLayout->addWidget(importConfirmationCheckBox);
- importConfirmationBox->setLayout(importConfirmationBoxLayout);
-
- /*****************************************
- * Language Select Box
- *****************************************/
- auto *langBox = new QGroupBox(tr("Language"));
- auto *langBoxLayout = new QVBoxLayout();
- langSelectBox = new QComboBox;
- lang = SettingsDialog::listLanguages();
-
- foreach (QString l, lang) { langSelectBox->addItem(l); }
-
- langBoxLayout->addWidget(langSelectBox);
- langBoxLayout->addWidget(
- new QLabel(tr("<b>NOTE: </b> GpgFrontend will restart automatically if "
- "you change the language!")));
- langBox->setLayout(langBoxLayout);
- connect(langSelectBox, SIGNAL(currentIndexChanged(int)), this,
- SLOT(slotLanguageChanged()));
-
- /*****************************************
- * Own Key Select Box
- *****************************************/
- auto *ownKeyBox = new QGroupBox(tr("Own key"));
- auto *ownKeyBoxLayout = new QVBoxLayout();
- ownKeySelectBox = new QComboBox;
-
- ownKeyBox->setLayout(ownKeyBoxLayout);
- mKeyList = new KeyList(mCtx);
-
- // Fill the keyid hashmap
- keyIds.insert("", tr("<none>"));
-
- for (const auto &keyid : *mKeyList->getAllPrivateKeys()) {
- auto &key = mCtx->getKeyById(keyid);
- keyIds.insert(key.id, key.uids.first().uid);
- }
- for (const auto &k : keyIds.keys()) {
- ownKeySelectBox->addItem(keyIds.find(k).value());
- keyIdsList.append(k);
- }
- connect(ownKeySelectBox, SIGNAL(currentIndexChanged(int)), this,
- SLOT(slotOwnKeyIdChanged()));
-
- ownKeyBoxLayout->addWidget(new QLabel(
- tr("Key pair for synchronization and identity authentication")));
- ownKeyBoxLayout->addWidget(ownKeySelectBox);
-
- /*****************************************
- * Mainlayout
- *****************************************/
- auto *mainLayout = new QVBoxLayout;
- mainLayout->addWidget(rememberPasswordBox);
- mainLayout->addWidget(saveCheckedKeysBox);
- mainLayout->addWidget(importConfirmationBox);
- mainLayout->addWidget(langBox);
- mainLayout->addWidget(ownKeyBox);
-
- setSettings();
- mainLayout->addStretch(1);
- setLayout(mainLayout);
-}
-
-/**********************************
- * Read the settings from config
- * and set the buttons and checkboxes
- * appropriately
- **********************************/
-void GeneralTab::setSettings() {
- // Keysaving
- if (settings.value("keys/saveKeyChecked").toBool()) {
- saveCheckedKeysCheckBox->setCheckState(Qt::Checked);
- }
-
- // Language setting
- QString langKey = settings.value("int/lang").toString();
- QString langValue = lang.value(langKey);
- if (langKey != "") {
- langSelectBox->setCurrentIndex(langSelectBox->findText(langValue));
- }
-
- QString ownKeyId = settings.value("general/ownKeyId").toString();
- qDebug() << "OwnKeyId" << ownKeyId;
- if (ownKeyId.isEmpty()) {
- ownKeySelectBox->setCurrentText("<none>");
- } else {
- const auto text = keyIds.find(ownKeyId).value();
- qDebug() << "OwnKey" << ownKeyId << text;
- ownKeySelectBox->setCurrentText(text);
- }
-
- // Get own key information from keydb/gpg.conf (if contained)
- if (settings.value("general/confirmImportKeys", Qt::Checked).toBool()) {
- importConfirmationCheckBox->setCheckState(Qt::Checked);
- }
-}
-
-/***********************************
- * get the values of the buttons and
- * write them to settings-file
- *************************************/
-void GeneralTab::applySettings() {
- settings.setValue("keys/saveKeyChecked",
- saveCheckedKeysCheckBox->isChecked());
- // TODO: clear passwordCache instantly on unset rememberPassword
- settings.setValue("general/rememberPassword",
- rememberPasswordCheckBox->isChecked());
- settings.setValue("int/lang", lang.key(langSelectBox->currentText()));
- settings.setValue("general/ownKeyId",
- keyIdsList[ownKeySelectBox->currentIndex()]);
- settings.setValue("general/confirmImportKeys",
- importConfirmationCheckBox->isChecked());
-}
-
-void GeneralTab::slotLanguageChanged() { emit signalRestartNeeded(true); }
-
-void GeneralTab::slotOwnKeyIdChanged() {
- // Set ownKeyId to currently selected
-}
-
-SendMailTab::SendMailTab(QWidget *parent)
- : QWidget(parent), appPath(qApp->applicationDirPath()),
- settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
- QSettings::IniFormat) {
-
- enableCheckBox = new QCheckBox(tr("Enable"));
- enableCheckBox->setTristate(false);
-
- smtpAddress = new QLineEdit();
- username = new QLineEdit();
- password = new QLineEdit();
- password->setEchoMode(QLineEdit::Password);
-
- portSpin = new QSpinBox();
- portSpin->setMinimum(1);
- portSpin->setMaximum(65535);
- connectionTypeComboBox = new QComboBox();
- connectionTypeComboBox->addItem("None");
- connectionTypeComboBox->addItem("SSL");
- connectionTypeComboBox->addItem("TLS");
- connectionTypeComboBox->addItem("STARTTLS");
-
- defaultSender = new QLineEdit();;
- checkConnectionButton = new QPushButton("Check Connection");
-
- auto layout = new QGridLayout();
- layout->addWidget(enableCheckBox, 0, 0);
- layout->addWidget(new QLabel(tr("SMTP Address")), 1, 0);
- layout->addWidget(smtpAddress, 1, 1, 1, 4);
- layout->addWidget(new QLabel(tr("Username")), 2, 0);
- layout->addWidget(username, 2, 1, 1, 4);
- layout->addWidget(new QLabel(tr("Password")), 3, 0);
- layout->addWidget(password, 3, 1, 1, 4);
- layout->addWidget(new QLabel(tr("Port")), 4, 0);
- layout->addWidget(portSpin, 4, 1, 1, 1);
- layout->addWidget(new QLabel(tr("Connection Security")), 5, 0);
- layout->addWidget(connectionTypeComboBox, 5, 1, 1, 1);
-
- layout->addWidget(new QLabel(tr("Default Sender")), 6, 0);
- layout->addWidget(defaultSender, 6, 1, 1, 4);
- layout->addWidget(checkConnectionButton, 7, 0);
-
- connect(enableCheckBox, SIGNAL(stateChanged(int)), this, SLOT(slotCheckBoxSetEnableDisable(int)));
- connect(checkConnectionButton, SIGNAL(clicked(bool)), this, SLOT(slotCheckConnection()));
-
-
- this->setLayout(layout);
- setSettings();
-}
-
-/**********************************
- * Read the settings from config
- * and set the buttons and checkboxes
- * appropriately
- **********************************/
-void SendMailTab::setSettings() {
-
- if (settings.value("sendMail/enable", false).toBool())
- enableCheckBox->setCheckState(Qt::Checked);
- else {
- enableCheckBox->setCheckState(Qt::Unchecked);
- smtpAddress->setDisabled(true);
- username->setDisabled(true);
- password->setDisabled(true);
- portSpin->setDisabled(true);
- connectionTypeComboBox->setDisabled(true);
- defaultSender->setDisabled(true);
- checkConnectionButton->setDisabled(true);
- }
-
- smtpAddress->setText(settings.value("sendMail/smtpAddress", QString()).toString());
- username->setText(settings.value("sendMail/username", QString()).toString());
- password->setText(settings.value("sendMail/password", QString()).toString());
- portSpin->setValue(settings.value("sendMail/port", 25).toInt());
- connectionTypeComboBox->setCurrentText(settings.value("sendMail/connectionType", "None").toString());
- defaultSender->setText(settings.value("sendMail/defaultSender", QString()).toString());
-
-}
-
-/***********************************
- * get the values of the buttons and
- * write them to settings-file
- *************************************/
-void SendMailTab::applySettings() {
-
- settings.setValue("sendMail/smtpAddress", smtpAddress->text());
- settings.setValue("sendMail/username", username->text());
- settings.setValue("sendMail/password", password->text());
- settings.setValue("sendMail/port", portSpin->value());
- settings.setValue("sendMail/connectionType", connectionTypeComboBox->currentText());
- settings.setValue("sendMail/defaultSender", defaultSender->text());
-
- settings.setValue("sendMail/enable", enableCheckBox->isChecked());
-}
-
-void SendMailTab::slotCheckConnection() {
-
- SmtpClient::ConnectionType connectionType = SmtpClient::ConnectionType::TcpConnection;
-
- if (connectionTypeComboBox->currentText() == "SSL") {
- connectionType = SmtpClient::ConnectionType::SslConnection;
- } else if (connectionTypeComboBox->currentText() == "TLS") {
- connectionType = SmtpClient::ConnectionType::TlsConnection;
- } else if (connectionTypeComboBox->currentText() == "STARTTLS") {
- connectionType = SmtpClient::ConnectionType::TlsConnection;
- } else {
- connectionType = SmtpClient::ConnectionType::TcpConnection;
- }
-
- SmtpClient smtp(smtpAddress->text(), portSpin->value(), connectionType);
-
- // We need to set the username (your email address) and the password
- // for smtp authentification.
-
- smtp.setUser(username->text());
- smtp.setPassword(password->text());
-
- bool if_success = true;
-
- if (!smtp.connectToHost()) {
- QMessageBox::critical(this, tr("Fail"), tr("Fail to Connect SMTP Server"));
- if_success = false;
- }
- if (if_success && !smtp.login()) {
- QMessageBox::critical(this, tr("Fail"), tr("Fail to Login"));
- if_success = false;
- }
-
- if (if_success)
- QMessageBox::information(this, tr("Success"), tr("Succeed in connecting and login"));
-
-}
-
-void SendMailTab::slotCheckBoxSetEnableDisable(int state) {
- if (state == Qt::Checked) {
- smtpAddress->setEnabled(true);
- username->setEnabled(true);
- password->setEnabled(true);
- portSpin->setEnabled(true);
- connectionTypeComboBox->setEnabled(true);
- defaultSender->setEnabled(true);
- checkConnectionButton->setEnabled(true);
- } else {
- smtpAddress->setDisabled(true);
- username->setDisabled(true);
- password->setDisabled(true);
- portSpin->setDisabled(true);
- connectionTypeComboBox->setDisabled(true);
- defaultSender->setDisabled(true);
- checkConnectionButton->setDisabled(true);
- }
-}
-
-AppearanceTab::AppearanceTab(QWidget *parent)
- : QWidget(parent), appPath(qApp->applicationDirPath()),
- settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
- QSettings::IniFormat) {
- /*****************************************
- * Icon-Size-Box
- *****************************************/
- auto *iconSizeBox = new QGroupBox(tr("Iconsize"));
- iconSizeGroup = new QButtonGroup();
- iconSizeSmall = new QRadioButton(tr("small"));
- iconSizeMedium = new QRadioButton(tr("medium"));
- iconSizeLarge = new QRadioButton(tr("large"));
-
- iconSizeGroup->addButton(iconSizeSmall, 1);
- iconSizeGroup->addButton(iconSizeMedium, 2);
- iconSizeGroup->addButton(iconSizeLarge, 3);
-
- auto *iconSizeBoxLayout = new QHBoxLayout();
- iconSizeBoxLayout->addWidget(iconSizeSmall);
- iconSizeBoxLayout->addWidget(iconSizeMedium);
- iconSizeBoxLayout->addWidget(iconSizeLarge);
-
- iconSizeBox->setLayout(iconSizeBoxLayout);
-
- /*****************************************
- * Icon-Style-Box
- *****************************************/
- auto *iconStyleBox = new QGroupBox(tr("Iconstyle"));
- iconStyleGroup = new QButtonGroup();
- iconTextButton = new QRadioButton(tr("just text"));
- iconIconsButton = new QRadioButton(tr("just icons"));
- iconAllButton = new QRadioButton(tr("text and icons"));
-
- iconStyleGroup->addButton(iconTextButton, 1);
- iconStyleGroup->addButton(iconIconsButton, 2);
- iconStyleGroup->addButton(iconAllButton, 3);
-
- auto *iconStyleBoxLayout = new QHBoxLayout();
- iconStyleBoxLayout->addWidget(iconTextButton);
- iconStyleBoxLayout->addWidget(iconIconsButton);
- iconStyleBoxLayout->addWidget(iconAllButton);
-
- iconStyleBox->setLayout(iconStyleBoxLayout);
-
- /*****************************************
- * Window-Size-Box
- *****************************************/
- auto *windowSizeBox = new QGroupBox(tr("Windowstate"));
- auto *windowSizeBoxLayout = new QHBoxLayout();
- windowSizeCheckBox =
- new QCheckBox(tr("Save window size and position on exit."), this);
- windowSizeBoxLayout->addWidget(windowSizeCheckBox);
- windowSizeBox->setLayout(windowSizeBoxLayout);
-
- /*****************************************
- * Info-Board-Font-Size-Box
- *****************************************/
-
- auto *infoBoardBox = new QGroupBox(tr("Information Board"));
- auto *infoBoardLayout = new QHBoxLayout();
- infoBoardFontSizeSpin = new QSpinBox();
- infoBoardFontSizeSpin->setRange(9, 18);
- infoBoardFontSizeSpin->setValue(10);
- infoBoardFontSizeSpin->setSingleStep(1);
- infoBoardLayout->addWidget(new QLabel(tr(" Front Size")));
- infoBoardLayout->addWidget(infoBoardFontSizeSpin);
- 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() {
-
- // Iconsize
- QSize iconSize = settings.value("toolbar/iconsize", QSize(24, 24)).toSize();
- switch (iconSize.height()) {
- case 12:
- iconSizeSmall->setChecked(true);
- break;
- case 24:
- iconSizeMedium->setChecked(true);
- break;
- case 32:
- iconSizeLarge->setChecked(true);
- break;
- }
- // Iconstyle
- Qt::ToolButtonStyle iconStyle = static_cast<Qt::ToolButtonStyle>(
- settings.value("toolbar/iconstyle", Qt::ToolButtonTextUnderIcon)
- .toUInt());
- switch (iconStyle) {
- case Qt::ToolButtonTextOnly:
- iconTextButton->setChecked(true);
- break;
- case Qt::ToolButtonIconOnly:
- iconIconsButton->setChecked(true);
- break;
- case Qt::ToolButtonTextUnderIcon:
- iconAllButton->setChecked(true);
- break;
- default:
- break;
- }
-
- // Window Save and Position
- if (settings.value("window/windowSave").toBool())
- windowSizeCheckBox->setCheckState(Qt::Checked);
-
- // infoBoardFontSize
- auto infoBoardFontSize = settings.value("informationBoard/fontSize", 10).toInt();
- if (infoBoardFontSize < 9 || infoBoardFontSize > 18)
- infoBoardFontSize = 10;
- infoBoardFontSizeSpin->setValue(infoBoardFontSize);
-}
-
-/***********************************
- * get the values of the buttons and
- * write them to settings-file
- *************************************/
-void AppearanceTab::applySettings() {
- switch (iconSizeGroup->checkedId()) {
- case 1:
- settings.setValue("toolbar/iconsize", QSize(12, 12));
- break;
- case 2:
- settings.setValue("toolbar/iconsize", QSize(24, 24));
- break;
- case 3:
- settings.setValue("toolbar/iconsize", QSize(32, 32));
- break;
- }
-
- switch (iconStyleGroup->checkedId()) {
- case 1:
- settings.setValue("toolbar/iconstyle", Qt::ToolButtonTextOnly);
- break;
- case 2:
- settings.setValue("toolbar/iconstyle", Qt::ToolButtonIconOnly);
- break;
- case 3:
- settings.setValue("toolbar/iconstyle", Qt::ToolButtonTextUnderIcon);
- break;
- }
-
- settings.setValue("window/windowSave", windowSizeCheckBox->isChecked());
-
- settings.setValue("informationBoard/fontSize", infoBoardFontSizeSpin->value());
-}
-
-KeyserverTab::KeyserverTab(QWidget *parent)
- : QWidget(parent), appPath(qApp->applicationDirPath()),
- settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
- QSettings::IniFormat) {
-
- auto keyServerList = settings.value("keyserver/keyServerList").toStringList();
-
- auto *mainLayout = new QVBoxLayout(this);
-
- auto *label = new QLabel(tr("Default Key Server for import:"));
- comboBox = new QComboBox;
- comboBox->setEditable(false);
- comboBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
-
- for (const auto &keyServer : keyServerList) {
- comboBox->addItem(keyServer);
- qDebug() << "KeyserverTab Get ListItemText" << keyServer;
- }
-
- comboBox->setCurrentText(
- settings.value("keyserver/defaultKeyServer").toString());
-
- auto *addKeyServerBox = new QWidget(this);
- auto *addKeyServerLayout = new QHBoxLayout(addKeyServerBox);
- auto *http = new QLabel("URL: ");
- newKeyServerEdit = new QLineEdit(this);
- auto *newKeyServerButton = new QPushButton(tr("Add"), this);
- connect(newKeyServerButton, SIGNAL(clicked()), this, SLOT(addKeyServer()));
- addKeyServerLayout->addWidget(http);
- addKeyServerLayout->addWidget(newKeyServerEdit);
- addKeyServerLayout->addWidget(newKeyServerButton);
-
- mainLayout->addWidget(label);
- mainLayout->addWidget(comboBox);
- mainLayout->addWidget(addKeyServerBox);
- mainLayout->addStretch(1);
-
- // Read keylist from ini-file and fill it into combobox
- setSettings();
-}
-
-/**********************************
- * Read the settings from config
- * and set the buttons and checkboxes
- * appropriately
- **********************************/
-void KeyserverTab::setSettings() {
- auto *keyServerList = new QStringList();
- for (int i = 0; i < comboBox->count(); i++) {
- keyServerList->append(comboBox->itemText(i));
- qDebug() << "KeyserverTab ListItemText" << comboBox->itemText(i);
- }
- settings.setValue("keyserver/keyServerList", *keyServerList);
- settings.setValue("keyserver/defaultKeyServer", comboBox->currentText());
-}
-
-void KeyserverTab::addKeyServer() {
- if (newKeyServerEdit->text().startsWith("http://") ||
- newKeyServerEdit->text().startsWith("https://")) {
- comboBox->addItem(newKeyServerEdit->text());
- } else {
- comboBox->addItem("http://" + newKeyServerEdit->text());
- }
- comboBox->setCurrentIndex(comboBox->count() - 1);
-}
-
-/***********************************
- * get the values of the buttons and
- * write them to settings-file
- *************************************/
-void KeyserverTab::applySettings() {
- settings.setValue("keyserver/defaultKeyServer", comboBox->currentText());
-}
-
-AdvancedTab::AdvancedTab(QWidget *parent)
- : QWidget(parent), appPath(qApp->applicationDirPath()),
- settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
- QSettings::IniFormat) {
- /*****************************************
- * Steganography Box
- *****************************************/
- auto *steganoBox = new QGroupBox(tr("Show Steganography Options [Advanced]"));
- auto *steganoBoxLayout = new QHBoxLayout();
- steganoCheckBox = new QCheckBox(tr("Show Steganographic Options."), this);
- steganoBoxLayout->addWidget(steganoCheckBox);
- steganoBox->setLayout(steganoBoxLayout);
-
- auto *mainLayout = new QVBoxLayout;
- mainLayout->addWidget(steganoBox);
- setSettings();
- mainLayout->addStretch(1);
- setLayout(mainLayout);
-}
-
-void AdvancedTab::setSettings() {
- if (settings.value("advanced/steganography").toBool()) {
- steganoCheckBox->setCheckState(Qt::Checked);
- }
-}
-
-void AdvancedTab::applySettings() {
- settings.setValue("advanced/steganography", steganoCheckBox->isChecked());
-}
-
-GpgPathsTab::GpgPathsTab(QWidget *parent)
- : QWidget(parent), appPath(qApp->applicationDirPath()),
- settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
- QSettings::IniFormat) {
- setSettings();
-
- /*****************************************
- * Keydb Box
- *****************************************/
- auto *keydbBox = new QGroupBox(tr("Relative path to keydb"));
- auto *keydbBoxLayout = new QGridLayout();
-
- // Label containing the current keydbpath relative to default keydb path
- keydbLabel = new QLabel(accKeydbPath, this);
-
- auto *keydbButton = new QPushButton("Change keydb path", this);
- connect(keydbButton, SIGNAL(clicked()), this, SLOT(chooseKeydbDir()));
- auto *keydbDefaultButton = new QPushButton("Set keydb to default path", this);
- connect(keydbDefaultButton, SIGNAL(clicked()), this,
- SLOT(setKeydbPathToDefault()));
-
- keydbBox->setLayout(keydbBoxLayout);
- keydbBoxLayout->addWidget(new QLabel(tr("Current keydb path: ")), 1, 1);
- keydbBoxLayout->addWidget(keydbLabel, 1, 2);
- keydbBoxLayout->addWidget(keydbButton, 1, 3);
- keydbBoxLayout->addWidget(keydbDefaultButton, 2, 3);
- keydbBoxLayout->addWidget(
- new QLabel(tr("<b>NOTE: </b> Gpg4usb will restart automatically if you "
- "change the keydb path!")),
- 3, 1, 1, 3);
-
- auto *mainLayout = new QVBoxLayout;
- mainLayout->addWidget(keydbBox);
- mainLayout->addStretch(1);
- setLayout(mainLayout);
-}
-
-QString GpgPathsTab::getRelativePath(const QString &dir1, const QString &dir2) {
- QDir dir(dir1);
- QString s;
-
- s = dir.relativeFilePath(dir2);
- qDebug() << "relative path: " << s;
- if (s.isEmpty()) {
- s = ".";
- }
- return s;
-}
-
-void GpgPathsTab::setKeydbPathToDefault() {
- accKeydbPath = ".";
- keydbLabel->setText(".");
-}
-
-QString GpgPathsTab::chooseKeydbDir() {
- QString dir = QFileDialog::getExistingDirectory(
- this, tr("Choose keydb directory"), accKeydbPath,
- QFileDialog::ShowDirsOnly);
-
- accKeydbPath = getRelativePath(defKeydbPath, dir);
- keydbLabel->setText(accKeydbPath);
- return "";
-}
-
-void GpgPathsTab::setSettings() {
- defKeydbPath = qApp->applicationDirPath() + "/keydb";
-
- accKeydbPath = settings.value("gpgpaths/keydbpath").toString();
- if (accKeydbPath.isEmpty()) {
- accKeydbPath = ".";
- }
-}
-
-void GpgPathsTab::applySettings() {
- settings.setValue("gpgpaths/keydbpath", accKeydbPath);
-}
diff --git a/src/ui/ShowCopyDialog.cpp b/src/ui/ShowCopyDialog.cpp
new file mode 100644
index 00000000..3286f6c4
--- /dev/null
+++ b/src/ui/ShowCopyDialog.cpp
@@ -0,0 +1,53 @@
+/**
+ * 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.
+ *
+ * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "ui/ShowCopyDialog.h"
+
+ShowCopyDialog::ShowCopyDialog(const QString &text, const QString &info, QWidget *parent) : QDialog(parent) {
+ textEdit = new QTextEdit();
+ textEdit->setReadOnly(true);
+ textEdit->setLineWrapMode(QTextEdit::WidgetWidth);
+ textEdit->setText(text);
+ copyButton = new QPushButton("Copy");
+ connect(copyButton, SIGNAL(clicked(bool)), this, SLOT(slotCopyText()));
+
+ infoLabel = new QLabel();
+ infoLabel->setText(info);
+ infoLabel->setWordWrap(true);
+
+ auto *layout = new QVBoxLayout();
+ layout->addWidget(textEdit);
+ layout->addWidget(copyButton);
+ layout->addWidget(infoLabel);
+
+ this->setWindowTitle("Short Ciphertext");
+ this->resize(320, 120);
+ this->setModal(true);
+ this->setLayout(layout);
+}
+
+void ShowCopyDialog::slotCopyText() {
+ QClipboard *cb = QApplication::clipboard();
+ cb->setText(textEdit->toPlainText());
+}
diff --git a/src/ui/Wizard.cpp b/src/ui/Wizard.cpp
index b0486cc9..8b482675 100644
--- a/src/ui/Wizard.cpp
+++ b/src/ui/Wizard.cpp
@@ -24,10 +24,6 @@
#include "ui/Wizard.h"
-#ifdef Q_OS_WIN
-#include "windows.h"
-#endif
-
Wizard::Wizard(GpgME::GpgContext *ctx, KeyMgmt *keyMgmt, QWidget *parent)
: QWizard(parent), appPath(qApp->applicationDirPath()),
settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", QSettings::IniFormat) {
@@ -36,8 +32,6 @@ Wizard::Wizard(GpgME::GpgContext *ctx, KeyMgmt *keyMgmt, QWidget *parent)
setPage(Page_Intro, new IntroPage(this));
setPage(Page_Choose, new ChoosePage(this));
- setPage(Page_ImportFromGpg4usb, new ImportFromGpg4usbPage(mCtx, mKeyMgmt, this));
- setPage(Page_ImportFromGnupg, new ImportFromGnupgPage(mCtx, mKeyMgmt, this));
setPage(Page_GenKey, new KeyGenPage(mCtx, this));
setPage(Page_Conclusion, new ConclusionPage(this));
#ifndef Q_WS_MAC
@@ -54,7 +48,6 @@ Wizard::Wizard(GpgME::GpgContext *ctx, KeyMgmt *keyMgmt, QWidget *parent)
settings.remove("wizard/nextPage");
connect(this, SIGNAL(accepted()), this, SLOT(slotWizardAccepted()));
- // connect(this, SIGNAL(signalOpenHelp(QString)), parentWidget(), SLOT(signalOpenHelp(QString)));
}
@@ -67,57 +60,20 @@ void Wizard::slotWizardAccepted() {
}
}
-bool Wizard::importPubAndSecKeysFromDir(const QString &dir, KeyMgmt *keyMgmt) {
- QFile secRingFile(dir + "/secring.gpg");
- QFile pubRingFile(dir + "/pubring.gpg");
-
- // Return, if no keyrings are found in subdir of chosen dir
- if (!(pubRingFile.exists() or secRingFile.exists())) {
- QMessageBox::critical(0, tr("Import Error"), tr("Couldn't locate any keyring file in %1").arg(dir));
- return false;
- }
-
- QByteArray inBuffer;
- if (secRingFile.exists()) {
- // write content of secringfile to inBuffer
- if (!secRingFile.open(QIODevice::ReadOnly)) {
- QMessageBox::critical(nullptr, tr("Import error"),
- tr("Couldn't open private keyringfile: %1").arg(secRingFile.fileName()));
- return false;
- }
- inBuffer = secRingFile.readAll();
- secRingFile.close();
- }
-
- if (pubRingFile.exists()) {
- // try to import public keys
- if (!pubRingFile.open(QIODevice::ReadOnly)) {
- QMessageBox::critical(nullptr, tr("Import error"),
- tr("Couldn't open public keyringfile: %1").arg(pubRingFile.fileName()));
- return false;
- }
- inBuffer.append(pubRingFile.readAll());
- pubRingFile.close();
- }
- keyMgmt->slotImportKeys(inBuffer);
- inBuffer.clear();
-
- return true;
-}
-
IntroPage::IntroPage(QWidget *parent)
: QWizardPage(parent), appPath(qApp->applicationDirPath()),
settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", QSettings::IniFormat) {
setTitle(tr("Getting Started..."));
setSubTitle(tr("... with GPGFrontend"));
- auto *topLabel = new QLabel(tr("Welcome to use GPGFrontend for decrypting and signing text or file!")+
- " <br><br><a href='https://github.com/saturneric/GpgFrontend'>GpgFrontend</a> " +
- tr("is a Powerful, Easy-to-Use, Compact, Cross-Platform, and Installation-Free OpenPGP Crypto Tool.") +
- tr("For brief information have a look at the") + "<a href='https://saturneric.github.io/GpgFrontend/index.html#/overview'>"+
- tr("Overview") +"</a> (" +
- tr("by clicking the link, the page will open in the web browser") +
- "). <br>");
+ auto *topLabel = new QLabel(tr("Welcome to use GPGFrontend for decrypting and signing text or file!") +
+ " <br><br><a href='https://gpgfrontend.pub'>GpgFrontend</a> " +
+ tr("is a Powerful, Easy-to-Use, Compact, Cross-Platform, and Installation-Free OpenPGP Crypto Tool.") +
+ tr("For brief information have a look at the") +
+ " <a href='https://gpgfrontend.pub/index.html#/overview'>" +
+ tr("Overview") + "</a> (" +
+ tr("by clicking the link, the page will open in the web browser") +
+ "). <br>");
topLabel->setTextFormat(Qt::RichText);
topLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
topLabel->setOpenExternalLinks(true);
@@ -130,7 +86,7 @@ IntroPage::IntroPage(QWidget *parent)
languages = SettingsDialog::listLanguages();
auto *langSelectBox = new QComboBox();
- for(const auto &l : languages) {
+ for (const auto &l : languages) {
langSelectBox->addItem(l);
}
// selected entry from config
@@ -166,19 +122,21 @@ ChoosePage::ChoosePage(QWidget *parent)
setSubTitle(tr("...by clicking on the appropriate link."));
auto *keygenLabel = new QLabel(tr("If you have never used GPGFrontend before and also don't own a gpg key yet you "
- "may possibly want to read how to") + " <a href=\"https://saturneric.github.io/GpgFrontend/index.html#/manual/generate-key\">"
+ "may possibly want to read how to") +
+ " <a href=\"https://gpgfrontend.pub/index.html#/manual/generate-key\">"
+ tr("Generate Key") + "</a><hr>");
keygenLabel->setTextFormat(Qt::RichText);
keygenLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
keygenLabel->setOpenExternalLinks(true);
keygenLabel->setWordWrap(true);
- auto *encrDecyTextLabel = new QLabel(tr("If you want to learn how to encrypt, decrypt, sign and verify text, you can read ")
- + "<a href=\"https://saturneric.github.io/GpgFrontend/index.html#/manual/encrypt-decrypt-text\">"
- + tr("Encrypt & Decrypt Text") + "</a> " + tr("or")
- + " <a href=\"https://saturneric.github.io/GpgFrontend/index.html#/manual/sign-verify-text\">"
- + tr("Sign & Verify Text")
- +"</a><hr>");
+ auto *encrDecyTextLabel = new QLabel(
+ tr("If you want to learn how to encrypt, decrypt, sign and verify text, you can read ")
+ + "<a href=\"https://gpgfrontend.pub/index.html#/manual/encrypt-decrypt-text\">"
+ + tr("Encrypt & Decrypt Text") + "</a> " + tr("or")
+ + " <a href=\"https://gpgfrontend.pub/index.html#/manual/sign-verify-text\">"
+ + tr("Sign & Verify Text")
+ + "</a><hr>");
encrDecyTextLabel->setTextFormat(Qt::RichText);
encrDecyTextLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
@@ -186,11 +144,13 @@ ChoosePage::ChoosePage(QWidget *parent)
encrDecyTextLabel->setWordWrap(true);
auto *signVerifyTextLabel = new QLabel(tr("If you want to operate file, you can read ")
- + "<a href=\"https://saturneric.github.io/GpgFrontend/index.html#/manual/encrypt-decrypt-file\">"
- + tr("Encrypt & Sign File") + "</a> " + tr("or")
- + " <a href=\"https://saturneric.github.io/GpgFrontend/index.html#/manual/sign-verify-file\">"
- + tr("Sign & Verify File")
- +"</a><hr>");
+ +
+ "<a href=\"https://gpgfrontend.pub/index.html#/manual/encrypt-decrypt-file\">"
+ + tr("Encrypt & Sign File") + "</a> " + tr("or")
+ +
+ " <a href=\"https://gpgfrontend.pub/index.html#/manual/sign-verify-file\">"
+ + tr("Sign & Verify File")
+ + "</a><hr>");
signVerifyTextLabel->setTextFormat(Qt::RichText);
signVerifyTextLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
signVerifyTextLabel->setOpenExternalLinks(true);
@@ -217,149 +177,6 @@ void ChoosePage::slotJumpPage(const QString &page) {
wizard()->next();
}
-ImportFromGpg4usbPage::ImportFromGpg4usbPage(GpgME::GpgContext *ctx, KeyMgmt *keyMgmt, QWidget *parent)
- : QWizardPage(parent), appPath(qApp->applicationDirPath()),
- settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", QSettings::IniFormat) {
- mCtx = ctx;
- mKeyMgmt = keyMgmt;
- setTitle(tr("Import from..."));
- setSubTitle(tr("...existing GPGFrontend"));
-
- auto *topLabel = new QLabel(tr("You can import keys and/or settings from existing GPGFrontend. <br><br>"
- "Just check what you want to import, click the import button and choose "
- "the directory of your other GPGFrontend in the appearing file dialog."), this);
- topLabel->setWordWrap(true);
-
- gpg4usbKeyCheckBox = new QCheckBox();
- gpg4usbKeyCheckBox->setChecked(true);
- auto *keyLabel = new QLabel(tr("Keys"));
-
- gpg4usbConfigCheckBox = new QCheckBox();
- gpg4usbConfigCheckBox->setChecked(true);
- auto *configLabel = new QLabel(tr("Configuration"));
-
- auto *importFromGpg4usbButton = new QPushButton(tr("Import from GPGFrontend"));
- connect(importFromGpg4usbButton, SIGNAL(clicked()), this, SLOT(slotImportFromOlderGpg4usb()));
-
- auto *gpg4usbLayout = new QGridLayout();
- gpg4usbLayout->addWidget(topLabel, 1, 1, 1, 2);
- gpg4usbLayout->addWidget(gpg4usbKeyCheckBox, 2, 1, Qt::AlignRight);
- gpg4usbLayout->addWidget(keyLabel, 2, 2);
- gpg4usbLayout->addWidget(gpg4usbConfigCheckBox, 3, 1, Qt::AlignRight);
- gpg4usbLayout->addWidget(configLabel, 3, 2);
- gpg4usbLayout->addWidget(importFromGpg4usbButton, 4, 2);
-
- this->setLayout(gpg4usbLayout);
-}
-
-void ImportFromGpg4usbPage::slotImportFromOlderGpg4usb() {
- QString dir = QFileDialog::getExistingDirectory(this, tr("Other GPGFrontend directory"));
-
- // Return, if cancel was hit
- if (dir.isEmpty()) {
- return;
- }
-
- // try to import keys, if appropriate box is checked, return, if import was unsuccessful
- if (gpg4usbKeyCheckBox->isChecked()) {
- if (!Wizard::importPubAndSecKeysFromDir(dir + "/keydb", mKeyMgmt)) {
- return;
- }
- }
-
- // try to import config, if appropriate box is checked
- if (gpg4usbConfigCheckBox->isChecked()) {
- slotImportConfFromGpg4usb(dir);
-
- settings.setValue("wizard/nextPage", this->nextId());
- QMessageBox::information(nullptr, tr("Configuration Imported"),
- tr("Imported Configuration from old GPGFrontend.<br>"
- "Will now restart to activate the configuration."));
- // TODO: edit->maybesave?
- qApp->exit(RESTART_CODE);
- }
- wizard()->next();
-}
-
-bool ImportFromGpg4usbPage::slotImportConfFromGpg4usb(const QString &dir) {
- QString path = dir + "/conf/gpgfrontend.ini";
- QSettings oldconf(path, QSettings::IniFormat, this);
- QSettings actualConf;
- foreach(QString key, oldconf.allKeys()) {
- actualConf.setValue(key, oldconf.value(key));
- }
- return true;
-}
-
-int ImportFromGpg4usbPage::nextId() const {
- return Wizard::Page_Conclusion;
-}
-
-ImportFromGnupgPage::ImportFromGnupgPage(GpgME::GpgContext *ctx, KeyMgmt *keyMgmt, QWidget *parent)
- : QWizardPage(parent) {
- mCtx = ctx;
- mKeyMgmt = keyMgmt;
- setTitle(tr("Import keys..."));
- setSubTitle(tr("...from existing GnuPG installation"));
-
- auto *gnupgLabel = new QLabel(tr("You can import keys from a locally installed GnuPG.<br><br> The location is read "
- "from registry in Windows or assumed to be the .gnupg folder in the your home directory in Linux.<br>"));
- gnupgLabel->setWordWrap(true);
-
- importFromGnupgButton = new QPushButton(tr("Import keys from GnuPG"));
- connect(importFromGnupgButton, SIGNAL(clicked()), this, SLOT(slotrImportKeysFromGnupg()));
-
- auto *layout = new QGridLayout();
- layout->addWidget(gnupgLabel);
- layout->addWidget(importFromGnupgButton);
-
- this->setLayout(layout);
-}
-
-void ImportFromGnupgPage::slotrImportKeysFromGnupg() {
- // first get gnupghomedir and check, if it exists
- QString gnuPGHome = getGnuPGHome();
- if (gnuPGHome == nullptr) {
- QMessageBox::critical(0, tr("Import Error"), tr("Couldn't locate GnuPG home directory"));
- return;
- }
-
- // Try to import the keyring files and return the return value of the method
- Wizard::importPubAndSecKeysFromDir(gnuPGHome, mKeyMgmt);
- wizard()->next();
-}
-
-QString ImportFromGnupgPage::getGnuPGHome() {
- QString gnuPGHome = "";
-#ifdef _WIN32
- bool existsAndSuccess = false;
-
- HKEY hKey;
-
- existsAndSuccess = (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\GNU\\GNUPG", 0, KEY_READ, &hKey) == ERROR_SUCCESS);
-
- if (existsAndSuccess) {
- QSettings gnuPGsettings("HKEY_CURRENT_USER\\Software\\GNU\\GNUPG", QSettings::NativeFormat);
- if (gnuPGsettings.contains("HomeDir")) {
- gnuPGHome = gnuPGsettings.value("HomeDir").toString();
- } else {
- return NULL;
- }
- }
-#else
- gnuPGHome = QDir::homePath() + "/.gnupg";
- if (!QFile(gnuPGHome).exists()) {
- return nullptr;
- }
-#endif
-
- return gnuPGHome;
-}
-
-int ImportFromGnupgPage::nextId() const {
- return Wizard::Page_Conclusion;
-}
-
KeyGenPage::KeyGenPage(GpgME::GpgContext *ctx, QWidget *parent)
: QWizardPage(parent) {
mCtx = ctx;
@@ -407,10 +224,11 @@ ConclusionPage::ConclusionPage(QWidget *parent)
setTitle(tr("Ready."));
setSubTitle(tr("Have fun with GPGFrontend!"));
- auto *bottomLabel = new QLabel(tr("You are ready to use GPGFrontend now.<br><br>")+
- "<a href=\"https://saturneric.github.io/GpgFrontend/index.html#/overview\">"
- + tr("The Online Document") + "</a>"
- + tr(" will get you started with GPGFrontend. It will open in the main window.<br>"));
+ auto *bottomLabel = new QLabel(tr("You are ready to use GPGFrontend now.<br><br>") +
+ "<a href=\"https://saturneric.github.io/GpgFrontend/index.html#/overview\">"
+ + tr("The Online Document") + "</a>"
+ +
+ tr(" will get you started with GPGFrontend. It will open in the main window.<br>"));
bottomLabel->setTextFormat(Qt::RichText);
bottomLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
diff --git a/src/ui/help/AboutDialog.cpp b/src/ui/help/AboutDialog.cpp
index 807c509d..8fb504db 100644
--- a/src/ui/help/AboutDialog.cpp
+++ b/src/ui/help/AboutDialog.cpp
@@ -37,7 +37,7 @@ AboutDialog::AboutDialog(int defaultIndex, QWidget *parent)
auto *tabWidget = new QTabWidget;
auto *infoTab = new InfoTab();
auto *translatorsTab = new TranslatorsTab();
- auto *updateTab = new UpdateTab();
+ updateTab = new UpdateTab();
tabWidget->addTab(infoTab, tr("General"));
tabWidget->addTab(translatorsTab, tr("Translators"));
@@ -45,9 +45,6 @@ AboutDialog::AboutDialog(int defaultIndex, QWidget *parent)
connect(tabWidget, &QTabWidget::currentChanged, this, [&](int index) {
qDebug() << "Current Index" << index;
- if(index == 2) {
- updateTab->getLatestVersion();
- }
});
if(defaultIndex < tabWidget->count() && defaultIndex >= 0) {
@@ -62,7 +59,14 @@ AboutDialog::AboutDialog(int defaultIndex, QWidget *parent)
mainLayout->addWidget(buttonBox);
setLayout(mainLayout);
- this->exec();
+ this->resize(320, 580);
+
+ this->show();
+}
+
+void AboutDialog::showEvent(QShowEvent *ev) {
+ QDialog::showEvent(ev);
+ updateTab->getLatestVersion();
}
InfoTab::InfoTab(QWidget *parent)
@@ -157,6 +161,8 @@ UpdateTab::UpdateTab(QWidget *parent) {
layout->addItem(new QSpacerItem(20, 10, QSizePolicy::Minimum,
QSizePolicy::Fixed), 2, 1, 1, 1);
+ connect(this, SIGNAL(replyFromUpdateServer(QByteArray)), this, SLOT(processReplyDataFromUpdateServer(QByteArray)));
+
setLayout(layout);
}
@@ -172,44 +178,42 @@ void UpdateTab::getLatestVersion() {
QNetworkRequest request;
request.setUrl(QUrl(baseUrl));
-
QNetworkReply *replay = manager->get(request);
+ auto thread = QThread::create([replay, this]() {
+ while(replay->isRunning()) QApplication::processEvents();
+ emit replyFromUpdateServer(replay->readAll());
+ });
+ connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
+ thread->start();
- while(replay->isRunning()) {
- QApplication::processEvents();
- }
+}
+
+void UpdateTab::processReplyDataFromUpdateServer(const QByteArray& data) {
- this->pb->setHidden(true);
+ qDebug() << "Try to Process Reply Data From Update Server";
- if(replay->error() != QNetworkReply::NoError) {
+ this->pb->setHidden(true);
+
+ Document d;
+ if (d.Parse(data.constData()).HasParseError() || !d.IsObject()) {
qDebug() << "VersionCheckThread Found Network Error";
auto latestVersion = "Unknown";
latestVersionLabel->setText("<center><b>" + tr("Latest Version From Github: ") + latestVersion + "</b></center>");
return;
}
- QByteArray bytes = replay->readAll();
-
- Document d;
- d.Parse(bytes.constData());
-
QString latestVersion = d["tag_name"].GetString();
qDebug() << "Latest Version From Github" << latestVersion;
- QRegularExpression re("^[vV](\\d+\\.)?(\\d+\\.)?(\\*|\\d+)");
+ QRegularExpression re(R"(^[vV](\d+\.)?(\d+\.)?(\*|\d+))");
QRegularExpressionMatch match = re.match(latestVersion);
if (match.hasMatch()) {
- latestVersion = match.captured(0); // matched == "23 def"
+ latestVersion = match.captured(0);
qDebug() << "Latest Version Matched" << latestVersion;
- } else {
- latestVersion = "Unknown";
- }
+ } else latestVersion = "Unknown";
latestVersionLabel->setText("<center><b>" + tr("Latest Version From Github: ") + latestVersion + "</b></center>");
- if(latestVersion > currentVersion) {
- upgradeLabel->setHidden(false);
- }
-
+ if(latestVersion > currentVersion) upgradeLabel->setHidden(false);
}
diff --git a/src/ui/help/VersionCheckThread.cpp b/src/ui/help/VersionCheckThread.cpp
index c7c77d1c..bf1bbeda 100644
--- a/src/ui/help/VersionCheckThread.cpp
+++ b/src/ui/help/VersionCheckThread.cpp
@@ -1,6 +1,26 @@
-//
-// Created by Administrator on 2021/7/12.
-//
+/**
+ * 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.
+ *
+ * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
#include "ui/help/VersionCheckThread.h"
#include "GpgFrontendBuildInfo.h"
diff --git a/src/ui/keygen/KeygenDialog.cpp b/src/ui/keygen/KeygenDialog.cpp
index 7991ddd1..98216dc6 100644
--- a/src/ui/keygen/KeygenDialog.cpp
+++ b/src/ui/keygen/KeygenDialog.cpp
@@ -23,6 +23,7 @@
*/
#include "ui/keygen/KeygenDialog.h"
+#include "ui/WaitingDialog.h"
KeyGenDialog::KeyGenDialog(GpgME::GpgContext *ctx, QWidget *parent)
: QDialog(parent), mCtx(ctx) {
@@ -92,34 +93,28 @@ void KeyGenDialog::slotKeyGenAccept() {
genKeyInfo.setExpired(dateEdit->dateTime());
}
- kg = new KeyGenThread(&genKeyInfo, mCtx);
- connect(kg, SIGNAL(signalKeyGenerated(bool)), this, SLOT(slotKeyGenResult(bool)));
- kg->start();
-
- this->accept();
-
- auto *dialog = new QDialog(this, Qt::CustomizeWindowHint | Qt::WindowTitleHint);
- dialog->setModal(true);
- dialog->setWindowTitle(tr("Generating Key..."));
-
- auto *waitMessage = new QLabel(
- tr("Collecting random data for key generation.\n This may take a while.\n To speed up the process use your computer\n (e.g. browse the net, listen to music,...)"));
- auto *pb = new QProgressBar();
- pb->setRange(0, 0);
-
- auto *layout = new QVBoxLayout(dialog);
- layout->addWidget(waitMessage);
- layout->addWidget(pb);
- dialog->setLayout(layout);
+ gpgme_error_t error = false;
+ auto thread = QThread::create([&]() {
+ error = mCtx->generateKey(&genKeyInfo);
+ });
+ thread->start();
+ auto *dialog = new WaitingDialog("Generating", this);
dialog->show();
- while (kg->isRunning()) {
+ while (thread->isRunning()) {
QCoreApplication::processEvents();
}
dialog->close();
+ if(gpgme_err_code(error) == GPG_ERR_NO_ERROR) {
+ QMessageBox::information(this, tr("Success"), tr("The new key pair has been generated."));
+ this->close();
+ }
+ else
+ QMessageBox::critical(this, tr("Failure"), tr(gpgme_strerror(error)));
+
} else {
/**
* create error message
@@ -307,13 +302,6 @@ bool KeyGenDialog::check_email_address(const QString &str) {
return re_email.match(str).hasMatch();
}
-void KeyGenDialog::slotKeyGenResult(bool success) {
- if(success)
- QMessageBox::information(nullptr, tr("Success"), tr("The new key pair has been generated."));
- else
- QMessageBox::critical(nullptr, tr("Failure"), tr("An error occurred during key generation."));
-}
-
QGroupBox *KeyGenDialog::create_basic_info_group_box() {
errorLabel = new QLabel(tr(""));
diff --git a/src/ui/keygen/SubkeyGenerateDialog.cpp b/src/ui/keygen/SubkeyGenerateDialog.cpp
index c545381f..3d709d81 100644
--- a/src/ui/keygen/SubkeyGenerateDialog.cpp
+++ b/src/ui/keygen/SubkeyGenerateDialog.cpp
@@ -23,6 +23,7 @@
*/
#include "ui/keygen/SubkeyGenerateDialog.h"
+#include "ui/WaitingDialog.h"
SubkeyGenerateDialog::SubkeyGenerateDialog(GpgME::GpgContext *ctx, const GpgKey &key, QWidget *parent)
: genKeyInfo(true), mCtx(ctx), mKey(key), QDialog(parent) {
@@ -224,34 +225,27 @@ void SubkeyGenerateDialog::slotKeyGenAccept() {
genKeyInfo.setExpired(dateEdit->dateTime());
}
- kg = new SubkeyGenerateThread(mKey ,&genKeyInfo, mCtx);
- connect(kg, SIGNAL(signalKeyGenerated(bool)), this, SLOT(slotKeyGenResult(bool)));
- kg->start();
-
- this->accept();
-
- auto *dialog = new QDialog(this, Qt::CustomizeWindowHint | Qt::WindowTitleHint);
- dialog->setModal(true);
- dialog->setWindowTitle(tr("Generating Subkey..."));
-
- auto *waitMessage = new QLabel(
- tr("Collecting random data for subkey generation.\n This may take a while.\n To speed up the process use your computer\n (e.g. browse the net, listen to music,...)"));
- auto *pb = new QProgressBar();
- pb->setRange(0, 0);
-
- auto *layout = new QVBoxLayout(dialog);
- layout->addWidget(waitMessage);
- layout->addWidget(pb);
- dialog->setLayout(layout);
+ gpgme_error_t error = false;
+ auto thread = QThread::create([&]() {
+ error = mCtx->generateSubkey(mKey, &genKeyInfo);
+ });
+ thread->start();
+ auto *dialog = new WaitingDialog("Generating", this);
dialog->show();
- while (!kg->isFinished() && kg->isRunning()) {
+ while (thread->isRunning()) {
QCoreApplication::processEvents();
}
dialog->close();
+ if (gpgme_err_code(error) == GPG_ERR_NO_ERROR) {
+ QMessageBox::information(nullptr, tr("Success"), tr("The new subkey has been generated."));
+ this->close();
+ } else
+ QMessageBox::critical(this, tr("Failure"), tr(gpgme_strerror(error)));
+
} else {
/**
* create error message
@@ -303,10 +297,3 @@ void SubkeyGenerateDialog::slotActivatedKeyType(int index) {
genKeyInfo.setAlgo(this->keyTypeComboBox->itemText(index));
refresh_widgets_state();
}
-
-void SubkeyGenerateDialog::slotKeyGenResult(bool success) {
- if(success)
- QMessageBox::information(nullptr, tr("Success"), tr("The new subkey has been generated."));
- else
- QMessageBox::critical(nullptr, tr("Failure"), tr("An error occurred during subkey generation."));
-}
diff --git a/src/ui/keygen/SubkeyGenerateThread.cpp b/src/ui/keygen/SubkeyGenerateThread.cpp
deleted file mode 100644
index 125f35f8..00000000
--- a/src/ui/keygen/SubkeyGenerateThread.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
- * 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.
- *
- * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
- *
- * The initial version of the source code is inherited from gpg4usb-team.
- * Their source code version also complies with GNU General Public License.
- *
- * The source code version of this software was modified and released
- * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
- *
- */
-
-#include "ui/keygen/SubkeyGenerateThread.h"
-
-SubkeyGenerateThread::SubkeyGenerateThread(GpgKey key, GenKeyInfo *keyGenParams, GpgME::GpgContext *ctx)
- : mKey(std::move(key)), keyGenParams(keyGenParams) , mCtx(ctx) {
- connect(this, &SubkeyGenerateThread::finished, this, &SubkeyGenerateThread::deleteLater);
-}
-
-void SubkeyGenerateThread::run() {
- bool success = mCtx->generateSubkey(mKey, keyGenParams);
- emit signalKeyGenerated(success);
- emit finished({});
-}
diff --git a/src/ui/keypair_details/EditSubKeyDialog.cpp b/src/ui/keypair_details/EditSubKeyDialog.cpp
index 5e26a098..e44c987f 100644
--- a/src/ui/keypair_details/EditSubKeyDialog.cpp
+++ b/src/ui/keypair_details/EditSubKeyDialog.cpp
@@ -1,5 +1,25 @@
-//
-// Created by eric on 2021/6/2.
-//
+/**
+ * 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.
+ *
+ * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
#include "ui/keypair_details/EditSubKeyDialog.h"
diff --git a/src/ui/keypair_details/KeyPairDetailTab.cpp b/src/ui/keypair_details/KeyPairDetailTab.cpp
index 9ca4e37e..c0a2df99 100644
--- a/src/ui/keypair_details/KeyPairDetailTab.cpp
+++ b/src/ui/keypair_details/KeyPairDetailTab.cpp
@@ -147,7 +147,6 @@ KeyPairDetailTab::KeyPairDetailTab(GpgME::GpgContext *ctx, const GpgKey &mKey, Q
keyServerOperaButton->setStyleSheet("text-align:center;");
auto *revokeCertGenButton = new QPushButton(tr("Generate Revoke Certificate"));
- revokeCertGenButton->setDisabled(true);
connect(revokeCertGenButton, SIGNAL(clicked()), this, SLOT(slotGenRevokeCert()));
hBoxLayout->addWidget(keyServerOperaButton);
@@ -215,7 +214,11 @@ void KeyPairDetailTab::slotExportPrivateKey() {
return;
}
- auto &key = mCtx->getKeyById(*keyid);
+ auto key = mCtx->getKeyById(*keyid);
+ if (!key.good) {
+ QMessageBox::critical(nullptr, tr("Error"), tr("Key Not Found."));
+ return;
+ }
QString fileString = key.name + " " + key.email + "(" +
key.id + ")_secret.asc";
QString fileName = QFileDialog::getSaveFileName(this, tr("Export Key To File"), fileString,
@@ -342,15 +345,8 @@ void KeyPairDetailTab::slotGenRevokeCert() {
QStringLiteral("%1 (*.rev)").arg(
tr("Revocation Certificates")));
- auto process = mCtx->generateRevokeCert(mKey, mOutputFileName);
-
- auto *dialog = new WaitingDialog("Generating", this);
-
- while (process->state() == QProcess::Running) {
- QApplication::processEvents();
- }
-
- dialog->close();
+ if (!mOutputFileName.isEmpty())
+ mCtx->generateRevokeCert(mKey, mOutputFileName);
}
diff --git a/src/ui/keypair_details/KeyPairSubkeyTab.cpp b/src/ui/keypair_details/KeyPairSubkeyTab.cpp
index 74b52284..6a924394 100644
--- a/src/ui/keypair_details/KeyPairSubkeyTab.cpp
+++ b/src/ui/keypair_details/KeyPairSubkeyTab.cpp
@@ -132,9 +132,8 @@ void KeyPairSubkeyTab::slotRefreshSubkeyList() {
this->buffered_subkeys.clear();
for(const auto &subkeys : mKey.subKeys) {
- if(subkeys.disabled || subkeys.revoked) {
+ if(subkeys.disabled || subkeys.revoked)
continue;
- }
this->buffered_subkeys.push_back(&subkeys);
}
diff --git a/src/ui/keypair_details/KeyUIDSignDialog.cpp b/src/ui/keypair_details/KeyUIDSignDialog.cpp
index f112ea25..9232cfce 100644
--- a/src/ui/keypair_details/KeyUIDSignDialog.cpp
+++ b/src/ui/keypair_details/KeyUIDSignDialog.cpp
@@ -89,13 +89,12 @@ void KeyUIDSignDialog::slotSignKey(bool clicked) {
// Set Signers
QVector<GpgKey> keys;
mKeyList->getCheckedKeys(keys);
- mCtx->setSigners(keys);
const auto expires = expiresEdit->dateTime();
for(const auto &uid : mUids) {
// Sign For mKey
- if (!mCtx->signKey(mKey, uid.uid, &expires)) {
+ if (!mCtx->signKey(mKey, keys, uid.uid, &expires)) {
QMessageBox::critical(nullptr,
tr("Unsuccessful Operation"),
QString(tr("Signature operation failed for UID ") + "%1")
diff --git a/src/ui/main_window/MainWindowFileSlotFunction.cpp b/src/ui/main_window/MainWindowFileSlotFunction.cpp
new file mode 100644
index 00000000..e391c666
--- /dev/null
+++ b/src/ui/main_window/MainWindowFileSlotFunction.cpp
@@ -0,0 +1,610 @@
+/**
+ * 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.
+ *
+ * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "MainWindow.h"
+
+void MainWindow::slotFileEncrypt() {
+
+ auto fileTreeView = edit->slotCurPageFileTreeView();
+ auto path = fileTreeView->getSelected();
+
+ QFileInfo fileInfo(path);
+ QFileInfo pathInfo(fileInfo.absolutePath());
+
+ if (!fileInfo.isFile()) {
+ QMessageBox::critical(this, tr("Error"), tr("Select a file before doing it."));
+ return;
+ }
+ if (!fileInfo.isReadable()) {
+ QMessageBox::critical(this, tr("Error"), tr("No permission to read this file."));
+ return;
+ }
+ if (!pathInfo.isWritable()) {
+ QMessageBox::critical(this, tr("Error"), tr("No permission to create file."));
+ return;
+ }
+ if (QFile::exists(path + ".asc")) {
+ auto ret = QMessageBox::warning(this,
+ tr("Warning"),
+ tr("The target file already exists, do you need to overwrite it?"),
+ QMessageBox::Ok | QMessageBox::Cancel);
+
+ if (ret == QMessageBox::Cancel)
+ return;
+ }
+
+ QVector<GpgKey> keys;
+
+ mKeyList->getCheckedKeys(keys);
+
+ if (keys.empty()) {
+ QMessageBox::critical(this, tr("No Key Selected"), tr("No Key Selected"));
+ return;
+ }
+
+ for (const auto &key : keys) {
+ if (!GpgME::GpgContext::checkIfKeyCanEncr(key)) {
+ QMessageBox::information(this,
+ tr("Invalid Operation"),
+ tr("The selected key contains a key that does not actually have a encrypt usage.<br/>")
+ + tr("<br/>For example the Following Key: <br/>") + key.uids.first().uid);
+ return;
+
+ }
+ }
+
+ gpgme_encrypt_result_t result;
+
+ gpgme_error_t error;
+ bool if_error = false;
+ auto thread = QThread::create([&]() {
+ try {
+ error = GpgFileOpera::encryptFile(mCtx, keys, path, &result);
+ } catch (const std::runtime_error &e) {
+ if_error = true;
+ }
+ });
+ connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
+ thread->start();
+
+ auto *dialog = new WaitingDialog(tr("Encrypting"), this);
+ while (thread->isRunning()) {
+ QApplication::processEvents();
+ }
+
+ dialog->close();
+ if (!if_error) {
+ auto resultAnalyse = new EncryptResultAnalyse(error, result);
+ auto &reportText = resultAnalyse->getResultReport();
+ infoBoard->associateTabWidget(edit->tabWidget);
+ infoBoard->associateFileTreeView(edit->curFilePage());
+
+ if (resultAnalyse->getStatus() < 0)
+ infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL);
+ else if (resultAnalyse->getStatus() > 0)
+ infoBoard->slotRefresh(reportText, INFO_ERROR_OK);
+ else
+ infoBoard->slotRefresh(reportText, INFO_ERROR_WARN);
+
+ delete resultAnalyse;
+
+ fileTreeView->update();
+ } else {
+ QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation."));
+ return;
+ }
+}
+
+void MainWindow::slotFileDecrypt() {
+
+ auto fileTreeView = edit->slotCurPageFileTreeView();
+ auto path = fileTreeView->getSelected();
+
+ QFileInfo fileInfo(path);
+ QFileInfo pathInfo(fileInfo.absolutePath());
+ if (!fileInfo.isFile()) {
+ QMessageBox::critical(this, tr("Error"), tr("Select a file before doing it."));
+ return;
+ }
+ if (!fileInfo.isReadable()) {
+ QMessageBox::critical(this, tr("Error"), tr("No permission to read this file."));
+ return;
+ }
+ if (!pathInfo.isWritable()) {
+ QMessageBox::critical(this, tr("Error"), tr("No permission to create file."));
+ return;
+ }
+
+ QString outFileName, fileExtension = fileInfo.suffix();
+
+ if (fileExtension == "asc" || fileExtension == "gpg") {
+ int pos = path.lastIndexOf(QChar('.'));
+ outFileName = path.left(pos);
+ } else {
+ outFileName = path + ".out";
+ }
+
+ if (QFile::exists(outFileName)) {
+ auto ret = QMessageBox::warning(this,
+ tr("Warning"),
+ tr("The target file already exists, do you need to overwrite it?"),
+ QMessageBox::Ok | QMessageBox::Cancel);
+
+ if (ret == QMessageBox::Cancel)
+ return;
+ }
+
+ gpgme_decrypt_result_t result;
+ gpgme_error_t error;
+ bool if_error = false;
+
+ auto thread = QThread::create([&]() {
+ try {
+ error = GpgFileOpera::decryptFile(mCtx, path, &result);
+ } catch (const std::runtime_error &e) {
+ if_error = true;
+ }
+ });
+ connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
+ thread->start();
+
+ auto *dialog = new WaitingDialog("Decrypting", this);
+ while (thread->isRunning()) {
+ QApplication::processEvents();
+ }
+
+ dialog->close();
+
+ if (!if_error) {
+ auto resultAnalyse = new DecryptResultAnalyse(mCtx, error, result);
+ auto &reportText = resultAnalyse->getResultReport();
+ infoBoard->associateTabWidget(edit->tabWidget);
+ infoBoard->associateFileTreeView(edit->curFilePage());
+
+ if (resultAnalyse->getStatus() < 0)
+ infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL);
+ else if (resultAnalyse->getStatus() > 0)
+ infoBoard->slotRefresh(reportText, INFO_ERROR_OK);
+ else
+ infoBoard->slotRefresh(reportText, INFO_ERROR_WARN);
+
+ delete resultAnalyse;
+
+ fileTreeView->update();
+ } else {
+ QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation."));
+ return;
+ }
+
+
+}
+
+void MainWindow::slotFileSign() {
+
+ auto fileTreeView = edit->slotCurPageFileTreeView();
+ auto path = fileTreeView->getSelected();
+
+ QFileInfo fileInfo(path);
+ QFileInfo pathInfo(fileInfo.absolutePath());
+
+ if (!fileInfo.isFile()) {
+ QMessageBox::critical(this, tr("Error"), tr("Select a file before doing it."));
+ return;
+ }
+ if (!fileInfo.isReadable()) {
+ QMessageBox::critical(this, tr("Error"), tr("No permission to read this file."));
+ return;
+ }
+ if (!pathInfo.isWritable()) {
+ QMessageBox::critical(this, tr("Error"), tr("No permission to create file."));
+ return;
+ }
+
+ if (QFile::exists(path + ".sig")) {
+ auto ret = QMessageBox::warning(this,
+ tr("Warning"),
+ tr("The target file already exists, do you need to overwrite it?"),
+ QMessageBox::Ok | QMessageBox::Cancel);
+
+ if (ret == QMessageBox::Cancel)
+ return;
+ }
+
+ QVector<GpgKey> keys;
+
+ mKeyList->getCheckedKeys(keys);
+
+ if (keys.empty()) {
+ QMessageBox::critical(this, tr("No Key Selected"), tr("No Key Selected"));
+ return;
+ }
+
+ for (const auto &key : keys) {
+ if (!GpgME::GpgContext::checkIfKeyCanEncr(key)) {
+ QMessageBox::information(this,
+ tr("Invalid Operation"),
+ tr("The selected key contains a key that does not actually have a encrypt usage.<br/>")
+ + tr("<br/>For example the Following Key: <br/>") + key.uids.first().uid);
+ return;
+
+ }
+ }
+
+ gpgme_sign_result_t result;
+ gpgme_error_t error;
+ bool if_error = false;
+
+ auto thread = QThread::create([&]() {
+ try {
+ error = GpgFileOpera::signFile(mCtx, keys, path, &result);
+ } catch (const std::runtime_error &e) {
+ if_error = true;
+ }
+ });
+ connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
+ thread->start();
+
+ auto *dialog = new WaitingDialog(tr("Signing"), this);
+ while (thread->isRunning()) {
+ QApplication::processEvents();
+ }
+
+ dialog->close();
+
+ if (!if_error) {
+
+ auto resultAnalyse = new SignResultAnalyse(mCtx, error, result);
+ auto &reportText = resultAnalyse->getResultReport();
+ infoBoard->associateTabWidget(edit->tabWidget);
+ infoBoard->associateFileTreeView(edit->curFilePage());
+
+ if (resultAnalyse->getStatus() < 0)
+ infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL);
+ else if (resultAnalyse->getStatus() > 0)
+ infoBoard->slotRefresh(reportText, INFO_ERROR_OK);
+ else
+ infoBoard->slotRefresh(reportText, INFO_ERROR_WARN);
+
+ delete resultAnalyse;
+
+ fileTreeView->update();
+
+ } else {
+ QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation."));
+ return;
+ }
+
+ fileTreeView->update();
+
+}
+
+void MainWindow::slotFileVerify() {
+
+ auto fileTreeView = edit->slotCurPageFileTreeView();
+ auto path = fileTreeView->getSelected();
+
+ QFileInfo fileInfo(path);
+
+ QString signFilePath, dataFilePath;
+
+ if (fileInfo.suffix() == "gpg") {
+ dataFilePath = path;
+ signFilePath = path;
+ } else if (fileInfo.suffix() == "sig") {
+ int pos = path.lastIndexOf(QChar('.'));
+ dataFilePath = path.left(pos);
+ signFilePath = path;
+ } else {
+ dataFilePath = path;
+ signFilePath = path + ".sig";
+ }
+
+ QFileInfo dataFileInfo(dataFilePath), signFileInfo(signFilePath);
+
+ if (!dataFileInfo.isFile() || !signFileInfo.isFile()) {
+ QMessageBox::critical(this, tr("Error"),
+ tr("Please select the appropriate target file or signature file. Ensure that both are in this directory."));
+ return;
+ }
+ if (!dataFileInfo.isReadable()) {
+ QMessageBox::critical(this, tr("Error"), tr("No permission to read target file."));
+ return;
+ }
+ if (!fileInfo.isReadable()) {
+ QMessageBox::critical(this, tr("Error"), tr("No permission to read signature file."));
+ return;
+ }
+
+ gpgme_verify_result_t result;
+
+ gpgme_error_t error;
+ bool if_error = false;
+ auto thread = QThread::create([&]() {
+ try {
+ error = GpgFileOpera::verifyFile(mCtx, dataFilePath, &result);
+ } catch (const std::runtime_error &e) {
+ if_error = true;
+ }
+ });
+ connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
+ thread->start();
+
+ auto *dialog = new WaitingDialog(tr("Verifying"), this);
+ while (thread->isRunning()) {
+ QApplication::processEvents();
+ }
+ dialog->close();
+
+ if (!if_error) {
+ auto resultAnalyse = new VerifyResultAnalyse(mCtx, error, result);
+ auto &reportText = resultAnalyse->getResultReport();
+ infoBoard->associateTabWidget(edit->tabWidget);
+ infoBoard->associateFileTreeView(edit->curFilePage());
+
+ if (resultAnalyse->getStatus() < 0)
+ infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL);
+ else if (resultAnalyse->getStatus() > 0)
+ infoBoard->slotRefresh(reportText, INFO_ERROR_OK);
+ else
+ infoBoard->slotRefresh(reportText, INFO_ERROR_WARN);
+
+ if (resultAnalyse->getStatus() >= 0) {
+ infoBoard->resetOptionActionsMenu();
+ infoBoard->addOptionalAction("Show Verify Details", [this, error, result]() {
+ VerifyDetailsDialog(this, mCtx, mKeyList, error, result);
+ });
+ }
+
+ delete resultAnalyse;
+
+ fileTreeView->update();
+ } else {
+ QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation."));
+ return;
+ }
+}
+
+void MainWindow::slotFileEncryptSign() {
+ auto fileTreeView = edit->slotCurPageFileTreeView();
+ auto path = fileTreeView->getSelected();
+
+ QFileInfo fileInfo(path);
+ QFileInfo pathInfo(fileInfo.absolutePath());
+
+ if (!fileInfo.isFile()) {
+ QMessageBox::critical(this, tr("Error"), tr("Select a file before doing it."));
+ return;
+ }
+ if (!fileInfo.isReadable()) {
+ QMessageBox::critical(this, tr("Error"), tr("No permission to read this file."));
+ return;
+ }
+ if (!pathInfo.isWritable()) {
+ QMessageBox::critical(this, tr("Error"), tr("No permission to create file."));
+ return;
+ }
+ if (QFile::exists(path + ".gpg")) {
+ auto ret = QMessageBox::warning(this,
+ tr("Warning"),
+ tr("The target file already exists, do you need to overwrite it?"),
+ QMessageBox::Ok | QMessageBox::Cancel);
+
+ if (ret == QMessageBox::Cancel)
+ return;
+ }
+
+ QVector<GpgKey> keys;
+
+ mKeyList->getCheckedKeys(keys);
+
+ if (keys.empty()) {
+ QMessageBox::critical(this, tr("No Key Selected"), tr("No Key Selected"));
+ return;
+ }
+
+ bool can_sign = false, can_encr = false;
+
+ for (const auto &key : keys) {
+ bool key_can_sign = GpgME::GpgContext::checkIfKeyCanSign(key);
+ bool key_can_encr = GpgME::GpgContext::checkIfKeyCanEncr(key);
+
+ if (!key_can_sign && !key_can_encr) {
+ QMessageBox::critical(nullptr,
+ tr("Invalid KeyPair"),
+ tr("The selected keypair cannot be used for signing and encryption at the same time.<br/>")
+ + tr("<br/>For example the Following Key: <br/>") + key.uids.first().uid);
+ return;
+ }
+
+ if (key_can_sign) can_sign = true;
+ if (key_can_encr) can_encr = true;
+ }
+
+ if (!can_encr) {
+ QMessageBox::critical(nullptr,
+ tr("Incomplete Operation"),
+ tr("None of the selected key pairs can provide the encryption function."));
+ return;
+ }
+
+ if (!can_sign) {
+ QMessageBox::warning(nullptr,
+ tr("Incomplete Operation"),
+ tr("None of the selected key pairs can provide the signature function."));
+ }
+
+ gpgme_encrypt_result_t encr_result = nullptr;
+ gpgme_sign_result_t sign_result = nullptr;
+
+ gpgme_error_t error;
+ bool if_error = false;
+
+ auto thread = QThread::create([&]() {
+ try {
+ error = GpgFileOpera::encryptSignFile(mCtx, keys, path, &encr_result, &sign_result);
+ } catch (const std::runtime_error &e) {
+ if_error = true;
+ }
+ });
+ connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
+ thread->start();
+
+ auto *dialog = new WaitingDialog(tr("Encrypting and Signing"), this);
+ while (thread->isRunning()) {
+ QApplication::processEvents();
+ }
+ dialog->close();
+
+ if (!if_error) {
+
+ auto resultAnalyseEncr = new EncryptResultAnalyse(error, encr_result);
+ auto resultAnalyseSign = new SignResultAnalyse(mCtx, error, sign_result);
+ int status = std::min(resultAnalyseEncr->getStatus(), resultAnalyseSign->getStatus());
+ auto reportText = resultAnalyseEncr->getResultReport() + resultAnalyseSign->getResultReport();
+
+ infoBoard->associateFileTreeView(edit->curFilePage());
+
+ if (status < 0)
+ infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL);
+ else if (status > 0)
+ infoBoard->slotRefresh(reportText, INFO_ERROR_OK);
+ else
+ infoBoard->slotRefresh(reportText, INFO_ERROR_WARN);
+
+ delete resultAnalyseEncr;
+ delete resultAnalyseSign;
+
+ fileTreeView->update();
+
+ } else {
+ QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation."));
+ return;
+ }
+}
+
+void MainWindow::slotFileDecryptVerify() {
+ auto fileTreeView = edit->slotCurPageFileTreeView();
+ auto path = fileTreeView->getSelected();
+
+ QFileInfo fileInfo(path);
+ QFileInfo pathInfo(fileInfo.absolutePath());
+ if (!fileInfo.isFile()) {
+ QMessageBox::critical(this, tr("Error"), tr("Select a file(.gpg/.asc) before doing it."));
+ return;
+ }
+ if (!fileInfo.isReadable()) {
+ QMessageBox::critical(this, tr("Error"), tr("No permission to read this file."));
+ return;
+ }
+ if (!pathInfo.isWritable()) {
+ QMessageBox::critical(this, tr("Error"), tr("No permission to create file."));
+ return;
+ }
+
+ QString outFileName, fileExtension = fileInfo.suffix();
+
+ if (fileExtension == "asc" || fileExtension == "gpg") {
+ int pos = path.lastIndexOf(QChar('.'));
+ outFileName = path.left(pos);
+ } else {
+ outFileName = path + ".out";
+ }
+
+ gpgme_decrypt_result_t d_result = nullptr;
+ gpgme_verify_result_t v_result = nullptr;
+
+ gpgme_error_t error;
+ bool if_error = false;
+
+ auto thread = QThread::create([&]() {
+ try {
+ error = GpgFileOpera::decryptVerifyFile(mCtx, path, &d_result, &v_result);
+ } catch (const std::runtime_error &e) {
+ if_error = true;
+ }
+ });
+ connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
+ thread->start();
+
+
+ auto *dialog = new WaitingDialog(tr("Decrypting and Verifying"), this);
+ while (thread->isRunning()) {
+ QApplication::processEvents();
+ }
+ dialog->close();
+
+ if (!if_error) {
+ infoBoard->associateFileTreeView(edit->curFilePage());
+
+ auto resultAnalyseDecrypt = new DecryptResultAnalyse(mCtx, error, d_result);
+ auto resultAnalyseVerify = new VerifyResultAnalyse(mCtx, error, v_result);
+
+ int status = std::min(resultAnalyseDecrypt->getStatus(), resultAnalyseVerify->getStatus());
+ auto &reportText = resultAnalyseDecrypt->getResultReport() + resultAnalyseVerify->getResultReport();
+ if (status < 0)
+ infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL);
+ else if (status > 0)
+ infoBoard->slotRefresh(reportText, INFO_ERROR_OK);
+ else
+ infoBoard->slotRefresh(reportText, INFO_ERROR_WARN);
+
+ if (resultAnalyseVerify->getStatus() >= 0) {
+ infoBoard->resetOptionActionsMenu();
+ infoBoard->addOptionalAction("Show Verify Details", [this, error, v_result]() {
+ VerifyDetailsDialog(this, mCtx, mKeyList, error, v_result);
+ });
+ }
+ delete resultAnalyseDecrypt;
+ delete resultAnalyseVerify;
+
+ fileTreeView->update();
+ } else {
+ QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation."));
+ return;
+ }
+}
+
+void MainWindow::slotFileEncryptCustom() {
+ QStringList *keyList;
+ keyList = mKeyList->getChecked();
+ new FileEncryptionDialog(mCtx, *keyList, FileEncryptionDialog::Encrypt, this);
+}
+
+void MainWindow::slotFileDecryptCustom() {
+ QStringList *keyList;
+ keyList = mKeyList->getChecked();
+ new FileEncryptionDialog(mCtx, *keyList, FileEncryptionDialog::Decrypt, this);
+}
+
+void MainWindow::slotFileSignCustom() {
+ QStringList *keyList;
+ keyList = mKeyList->getChecked();
+ new FileEncryptionDialog(mCtx, *keyList, FileEncryptionDialog::Sign, this);
+}
+
+void MainWindow::slotFileVerifyCustom() {
+ QStringList *keyList;
+ keyList = mKeyList->getChecked();
+ new FileEncryptionDialog(mCtx, *keyList, FileEncryptionDialog::Verify, this);
+}
diff --git a/src/ui/main_window/MainWindowServerSlotFunction.cpp b/src/ui/main_window/MainWindowServerSlotFunction.cpp
new file mode 100644
index 00000000..3a7e9f71
--- /dev/null
+++ b/src/ui/main_window/MainWindowServerSlotFunction.cpp
@@ -0,0 +1,238 @@
+/**
+ * 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.
+ *
+ * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "MainWindow.h"
+#include "server/ComUtils.h"
+#include "ui/ShowCopyDialog.h"
+
+#include "rapidjson/document.h"
+#include "rapidjson/prettywriter.h"
+
+/**
+ * get full size crypt text from server using short crypto text
+ * @param shortenCryptoText short crypto text([GpgFrontend_ShortCrypto]://)
+ * @return
+ */
+QString MainWindow::getCryptText(const QString &shortenCryptoText) {
+
+ QString ownKeyId = settings.value("general/ownKeyId").toString();
+
+ GpgKey key = mCtx->getKeyById(ownKeyId);
+ if (!key.good) {
+ QMessageBox::critical(this, tr("Invalid Own Key"),
+ tr("Own Key can not be use to do any operation. "
+ "Please go to the setting interface to select an OwnKey and get a ServiceToken."));
+ return {};
+ }
+
+ auto utils = new ComUtils(this);
+
+ QString serviceToken = settings.value("general/serviceToken").toString();
+ if (serviceToken.isEmpty() || !utils->checkServiceTokenFormat(serviceToken)) {
+ QMessageBox::critical(this, tr("Error"),
+ tr("Please obtain a Service Token from the server in the settings."));
+ return {};
+ }
+
+ QUrl reqUrl(utils->getUrl(ComUtils::GetFullCryptText));
+ QNetworkRequest request(reqUrl);
+ request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
+
+ // Sign Shorten Text
+ auto outSignTextBase64 = ComUtils::getSignStringBase64(mCtx, shortenCryptoText, key);
+
+ rapidjson::Document doc;
+ doc.SetObject();
+
+ rapidjson::Value s, t;
+
+ // Signature
+ s.SetString(outSignTextBase64.constData(), outSignTextBase64.count());
+ // Service Token
+ const auto t_byte_array = serviceToken.toUtf8();
+ t.SetString(t_byte_array.constData(), t_byte_array.count());
+
+ rapidjson::Document::AllocatorType &allocator = doc.GetAllocator();
+
+ doc.AddMember("signature", s, allocator);
+ doc.AddMember("serviceToken", t, allocator);
+
+ rapidjson::StringBuffer sb;
+ rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(sb);
+ doc.Accept(writer);
+
+ QByteArray postData(sb.GetString());
+ qDebug() << "postData" << QString::fromUtf8(postData);
+
+ QNetworkReply *reply = utils->getNetworkManager().post(request, postData);
+
+ auto dialog = new WaitingDialog(tr("Getting Cpt From Server"), this);
+ dialog->show();
+
+ while (reply->isRunning()) QApplication::processEvents();
+
+ dialog->close();
+
+ QByteArray replyData = reply->readAll().constData();
+ if (utils->checkServerReply(replyData)) {
+ /**
+ * {
+ * "cryptoText" : ...
+ * "sha": ...
+ * "serviceToken": ...
+ * "date": ...
+ * }
+ */
+
+ if (!utils->checkDataValueStr("cryptoText")
+ || !utils->checkDataValueStr("sha")
+ || !utils->checkDataValueStr("serviceToken")) {
+ QMessageBox::critical(this, tr("Error"),
+ tr("The communication content with the server does not meet the requirements"));
+ return {};
+ }
+
+ auto cryptoText = utils->getDataValueStr("cryptoText");
+ auto sha = utils->getDataValueStr("sha");
+ auto serviceTokenFromServer = utils->getDataValueStr("serviceToken");
+
+ QCryptographicHash sha_generator(QCryptographicHash::Sha256);
+ sha_generator.addData(cryptoText.toUtf8());
+
+ if (sha_generator.result().toHex() == sha && serviceToken == serviceTokenFromServer) {
+ return cryptoText;
+ } else QMessageBox::critical(this, tr("Error"), tr("Invalid short ciphertext"));
+
+ return {};
+ }
+
+ return {};
+}
+
+void MainWindow::shortenCryptText() {
+
+ // gather information
+ QString serviceToken = settings.value("general/serviceToken").toString();
+ QString ownKeyId = settings.value("general/ownKeyId").toString();
+ QByteArray cryptoText = edit->curTextPage()->toPlainText().toUtf8();
+
+ auto utils = new ComUtils(this);
+
+ if (serviceToken.isEmpty() || !utils->checkServiceTokenFormat(serviceToken)) {
+ QMessageBox::critical(this, tr("Invalid Service Token"),
+ tr("Please go to the setting interface to get a ServiceToken."));
+ return;
+ }
+
+ QUrl reqUrl(utils->getUrl(ComUtils::ShortenCryptText));
+ QNetworkRequest request(reqUrl);
+ request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
+
+ GpgKey key = mCtx->getKeyById(ownKeyId);
+ if (!key.good) {
+ QMessageBox::critical(this, tr("Invalid Own Key"), tr("Own Key can not be use to do any operation."));
+ return;
+ }
+
+ QCryptographicHash ch(QCryptographicHash::Md5);
+ ch.addData(cryptoText);
+ QString md5 = ch.result().toHex();
+
+ qDebug() << "md5" << md5;
+
+ QByteArray signText = QString("[%1][%2]").arg(serviceToken, md5).toUtf8();
+
+ QCryptographicHash sha(QCryptographicHash::Sha256);
+ sha.addData(signText);
+ QString shaText = sha.result().toHex();
+
+ qDebug() << "shaText" << shaText;
+
+ QByteArray outSignTextBase64 = ComUtils::getSignStringBase64(mCtx, signText, key);
+
+ rapidjson::Value c, s, m, t;
+
+ rapidjson::Document doc;
+ doc.SetObject();
+
+ c.SetString(cryptoText.constData(), cryptoText.count());
+ auto m_byte_array = shaText.toUtf8();
+ m.SetString(m_byte_array.constData(), m_byte_array.count());
+ s.SetString(outSignTextBase64.constData(), outSignTextBase64.count());
+ auto t_byte_array = serviceToken.toUtf8();
+ t.SetString(t_byte_array.constData(), t_byte_array.count());
+
+ rapidjson::Document::AllocatorType &allocator = doc.GetAllocator();
+
+ doc.AddMember("cryptoText", c, allocator);
+ doc.AddMember("sha", m, allocator);
+ doc.AddMember("sign", s, allocator);
+ doc.AddMember("serviceToken", t, allocator);
+
+ rapidjson::StringBuffer sb;
+ rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(sb);
+ doc.Accept(writer);
+
+ QByteArray postData(sb.GetString());
+ qDebug() << "postData" << QString::fromUtf8(postData);
+
+ QNetworkReply *reply = networkAccessManager->post(request, postData);
+
+ auto *dialog = new WaitingDialog(tr("Getting Scpt From Server"), this);
+ dialog->show();
+ while (reply->isRunning()) QApplication::processEvents();
+ dialog->close();
+
+ if (utils->checkServerReply(reply->readAll().constData())) {
+
+ /**
+ * {
+ * "shortenText" : ...
+ * "md5": ...
+ * }
+ */
+
+ if (!utils->checkDataValueStr("shortenText") || !utils->checkDataValueStr("md5")) {
+ QMessageBox::critical(this, tr("Error"),
+ tr("The communication content with the server does not meet the requirements"));
+ return;
+ }
+
+ QString shortenText = utils->getDataValueStr("shortenText");
+
+ QCryptographicHash md5_generator(QCryptographicHash::Md5);
+ md5_generator.addData(shortenText.toUtf8());
+ if (md5_generator.result().toHex() == utils->getDataValueStr("md5")) {
+ auto *dialog = new ShowCopyDialog(shortenText,
+ tr("Notice: Use Decrypt & Verify operation to decrypt this short crypto text."),
+ this);
+ dialog->show();
+ } else {
+ QMessageBox::critical(this, tr("Error"), tr("There is a problem with the communication with the server"));
+ return;
+ }
+ }
+
+}
+
diff --git a/src/ui/main_window/MainWindowSlotFunction.cpp b/src/ui/main_window/MainWindowSlotFunction.cpp
index 4bcee080..501418d6 100644
--- a/src/ui/main_window/MainWindowSlotFunction.cpp
+++ b/src/ui/main_window/MainWindowSlotFunction.cpp
@@ -24,7 +24,14 @@
#include "MainWindow.h"
#include "ui/SendMailDialog.h"
+#include "ui/widgets/SignersPicker.h"
+#include "server/api/PubkeyUploader.h"
+#include "advance/UnknownSignersChecker.h"
+
+/**
+ * Encrypt Entry(Text & File)
+ */
void MainWindow::slotEncrypt() {
if (edit->tabCount() == 0) return;
@@ -50,33 +57,33 @@ void MainWindow::slotEncrypt() {
}
}
- auto *tmp = new QByteArray();
+ auto tmp = QByteArray();
gpgme_encrypt_result_t result = nullptr;
gpgme_error_t error;
auto thread = QThread::create([&]() {
- error = mCtx->encrypt(keys, edit->curTextPage()->toPlainText().toUtf8(), tmp, &result);
+ error = mCtx->encrypt(keys, edit->curTextPage()->toPlainText().toUtf8(), &tmp, &result);
});
- connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater()));
+ connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
auto *dialog = new WaitingDialog(tr("Encrypting"), this);
- while (thread->isRunning()) {
+ while (thread->isRunning())
QApplication::processEvents();
- }
dialog->close();
auto resultAnalyse = new EncryptResultAnalyse(error, result);
auto &reportText = resultAnalyse->getResultReport();
- auto *tmp2 = new QString(*tmp);
- edit->slotFillTextEditWithText(*tmp2);
+ auto tmp2 = QString(tmp);
+ edit->slotFillTextEditWithText(tmp2);
infoBoard->associateTextEdit(edit->curTextPage());
+ // check result analyse status
if (resultAnalyse->getStatus() < 0)
infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL);
else if (resultAnalyse->getStatus() > 0)
@@ -84,10 +91,11 @@ void MainWindow::slotEncrypt() {
else
infoBoard->slotRefresh(reportText, INFO_ERROR_WARN);
+ // set optional actions
if (resultAnalyse->getStatus() >= 0) {
infoBoard->resetOptionActionsMenu();
infoBoard->addOptionalAction("Send Mail", [this]() {
- if(settings.value("sendMail/enable", false).toBool())
+ if (settings.value("sendMail/enable", false).toBool())
new SendMailDialog(edit->curTextPage()->toPlainText(), this);
else {
QMessageBox::warning(nullptr,
@@ -128,15 +136,15 @@ void MainWindow::slotSign() {
}
}
- auto *tmp = new QByteArray();
+ auto tmp = QByteArray();
gpgme_sign_result_t result = nullptr;
gpgme_error_t error;
auto thread = QThread::create([&]() {
- error = mCtx->sign(keys, edit->curTextPage()->toPlainText().toUtf8(), tmp, false, &result);
+ error = mCtx->sign(keys, edit->curTextPage()->toPlainText().toUtf8(), &tmp, GPGME_SIG_MODE_CLEAR, &result);
});
- connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater()));
+ connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
auto *dialog = new WaitingDialog(tr("Signing"), this);
@@ -146,9 +154,9 @@ void MainWindow::slotSign() {
dialog->close();
infoBoard->associateTextEdit(edit->curTextPage());
- edit->slotFillTextEditWithText(QString::fromUtf8(*tmp));
+ edit->slotFillTextEditWithText(QString::fromUtf8(tmp));
- auto resultAnalyse = new SignResultAnalyse(error, result);
+ auto resultAnalyse = new SignResultAnalyse(mCtx, error, result);
auto &reportText = resultAnalyse->getResultReport();
if (resultAnalyse->getStatus() < 0)
@@ -169,18 +177,23 @@ void MainWindow::slotDecrypt() {
if (edit->slotCurPageTextEdit() != nullptr) {
- auto *decrypted = new QByteArray();
+ auto decrypted = QByteArray();
QByteArray text = edit->curTextPage()->toPlainText().toUtf8();
GpgME::GpgContext::preventNoDataErr(&text);
+ if (text.trimmed().startsWith(GpgConstants::GPG_FRONTEND_SHORT_CRYPTO_HEAD)) {
+ QMessageBox::critical(this, tr("Notice"), tr("Short Crypto Text only supports Decrypt & Verify."));
+ return;
+ }
+
gpgme_decrypt_result_t result = nullptr;
gpgme_error_t error;
auto thread = QThread::create([&]() {
// try decrypt, if fail do nothing, especially don't replace text
- error = mCtx->decrypt(text, decrypted, &result);
+ error = mCtx->decrypt(text, &decrypted, &result);
});
- connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater()));
+ connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
auto *dialog = new WaitingDialog(tr("Decrypting"), this);
@@ -193,7 +206,7 @@ void MainWindow::slotDecrypt() {
infoBoard->associateTextEdit(edit->curTextPage());
if (gpgme_err_code(error) == GPG_ERR_NO_ERROR)
- edit->slotFillTextEditWithText(QString::fromUtf8(*decrypted));
+ edit->slotFillTextEditWithText(QString::fromUtf8(decrypted));
auto resultAnalyse = new DecryptResultAnalyse(mCtx, error, result);
@@ -233,20 +246,18 @@ void MainWindow::slotVerify() {
QByteArray text = edit->curTextPage()->toPlainText().toUtf8();
GpgME::GpgContext::preventNoDataErr(&text);
-
gpgme_verify_result_t result;
gpgme_error_t error;
auto thread = QThread::create([&]() {
error = mCtx->verify(&text, nullptr, &result);
});
- connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater()));
+ connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
auto *dialog = new WaitingDialog(tr("Verifying"), this);
- while (thread->isRunning()) {
+ while (thread->isRunning())
QApplication::processEvents();
- }
dialog->close();
auto resultAnalyse = new VerifyResultAnalyse(mCtx, error, result);
@@ -274,7 +285,6 @@ void MainWindow::slotVerify() {
void MainWindow::slotEncryptSign() {
-
if (edit->tabCount() == 0) return;
if (edit->slotCurPageTextEdit() != nullptr) {
@@ -287,49 +297,49 @@ void MainWindow::slotEncryptSign() {
return;
}
- bool can_sign = false, can_encr = false;
-
for (const auto &key : keys) {
- bool key_can_sign = GpgME::GpgContext::checkIfKeyCanSign(key);
bool key_can_encr = GpgME::GpgContext::checkIfKeyCanEncr(key);
- if (!key_can_sign && !key_can_encr) {
+ if (!key_can_encr) {
QMessageBox::critical(nullptr,
tr("Invalid KeyPair"),
- tr("The selected keypair cannot be used for signing and encryption at the same time.<br/>")
+ tr("The selected keypair cannot be used for encryption.<br/>")
+ tr("<br/>For example the Following Key: <br/>") + key.uids.first().uid);
return;
}
- if (key_can_sign) can_sign = true;
- if (key_can_encr) can_encr = true;
}
- if (!can_encr) {
- QMessageBox::critical(nullptr,
- tr("Incomplete Operation"),
- tr("None of the selected key pairs can provide the encryption function."));
- return;
+ QVector<GpgKey> signerKeys;
+
+ auto signersPicker = new SignersPicker(mCtx, this);
+
+ QEventLoop loop;
+ connect(signersPicker, SIGNAL(finished(int)), &loop, SLOT(quit()));
+ loop.exec();
+
+ signersPicker->getCheckedSigners(signerKeys);
+
+ for (const auto &key : keys) {
+ qDebug() << "Keys " << key.email;
}
- if (!can_sign) {
- QMessageBox::warning(nullptr,
- tr("Incomplete Operation"),
- tr("None of the selected key pairs can provide the signature function."));
+ for (const auto &signer : signerKeys) {
+ qDebug() << "Signers " << signer.email;
}
- auto *tmp = new QByteArray();
+
+ auto tmp = QByteArray();
gpgme_encrypt_result_t encr_result = nullptr;
gpgme_sign_result_t sign_result = nullptr;
- gpgme_decrypt_result_t result = nullptr;
-
gpgme_error_t error;
auto thread = QThread::create([&]() {
- error = mCtx->encryptSign(keys, edit->curTextPage()->toPlainText().toUtf8(), tmp, &encr_result,
+ error = mCtx->encryptSign(keys, signerKeys, edit->curTextPage()->toPlainText().toUtf8(), &tmp,
+ &encr_result,
&sign_result);
});
- connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater()));
+ connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
auto *dialog = new WaitingDialog(tr("Encrypting and Signing"), this);
@@ -337,15 +347,29 @@ void MainWindow::slotEncryptSign() {
QApplication::processEvents();
}
+ if (settings.value("advanced/autoPubkeyExchange").toBool()) {
+ PubkeyUploader pubkeyUploader(mCtx, signerKeys);
+ pubkeyUploader.start();
+ if (!pubkeyUploader.result()) {
+ QMessageBox::warning(nullptr,
+ tr("Automatic Key Exchange Warning"),
+ tr("Part of the automatic key exchange failed, which may be related to your key.")
+ +
+ tr("If possible, try to use the RSA algorithm compatible with the server for signing."));
+ }
+ }
+
dialog->close();
if (gpgme_err_code(error) == GPG_ERR_NO_ERROR) {
- auto *tmp2 = new QString(*tmp);
- edit->slotFillTextEditWithText(*tmp2);
+ auto tmp2 = QString(tmp);
+ edit->slotFillTextEditWithText(tmp2);
}
+ qDebug() << "Start Analyse Result";
+
auto resultAnalyseEncr = new EncryptResultAnalyse(error, encr_result);
- auto resultAnalyseSign = new SignResultAnalyse(error, sign_result);
+ auto resultAnalyseSign = new SignResultAnalyse(mCtx, error, sign_result);
int status = std::min(resultAnalyseEncr->getStatus(), resultAnalyseSign->getStatus());
auto reportText = resultAnalyseEncr->getResultReport() + resultAnalyseSign->getResultReport();
@@ -358,10 +382,12 @@ void MainWindow::slotEncryptSign() {
else
infoBoard->slotRefresh(reportText, INFO_ERROR_WARN);
+ qDebug() << "End Analyse Result";
+
if (status >= 0) {
infoBoard->resetOptionActionsMenu();
infoBoard->addOptionalAction("Send Mail", [this]() {
- if(settings.value("sendMail/enable", false).toBool())
+ if (settings.value("sendMail/enable", false).toBool())
new SendMailDialog(edit->curTextPage()->toPlainText(), this);
else {
QMessageBox::warning(nullptr,
@@ -369,6 +395,15 @@ void MainWindow::slotEncryptSign() {
tr("Please go to the settings interface to enable and configure this function."));
}
});
+ infoBoard->addOptionalAction("Shorten Ciphertext", [this]() {
+ if (settings.value("general/serviceToken").toString().isEmpty())
+ QMessageBox::warning(nullptr,
+ tr("Service Token Empty"),
+ tr("Please go to the settings interface to set Own Key and get Service Token."));
+ else {
+ shortenCryptText();
+ }
+ });
}
delete resultAnalyseEncr;
@@ -384,31 +419,56 @@ void MainWindow::slotDecryptVerify() {
if (edit->slotCurPageTextEdit() != nullptr) {
- auto *decrypted = new QByteArray();
- QByteArray text = edit->curTextPage()->toPlainText().toUtf8();
+ auto decrypted = QByteArray();
+ QString plainText = edit->curTextPage()->toPlainText();
+
+
+ if (plainText.trimmed().startsWith(GpgConstants::GPG_FRONTEND_SHORT_CRYPTO_HEAD)) {
+ auto cryptoText = getCryptText(plainText);
+ if (!cryptoText.isEmpty()) {
+ plainText = cryptoText;
+ }
+ }
+
+ QByteArray text = plainText.toUtf8();
+
GpgME::GpgContext::preventNoDataErr(&text);
gpgme_decrypt_result_t d_result = nullptr;
gpgme_verify_result_t v_result = nullptr;
+ auto *dialog = new WaitingDialog(tr("Decrypting and Verifying"), this);
+
+ // Automatically import public keys that are not stored locally
+ if (settings.value("advanced/autoPubkeyExchange").toBool()) {
+ gpgme_verify_result_t tmp_v_result = nullptr;
+ auto thread = QThread::create([&]() {
+ mCtx->verify(&text, nullptr, &tmp_v_result);
+ });
+ thread->start();
+ while (thread->isRunning()) QApplication::processEvents();
+ auto *checker = new UnknownSignersChecker(mCtx, tmp_v_result);
+ checker->start();
+ checker->deleteLater();
+ }
+
gpgme_error_t error;
auto thread = QThread::create([&]() {
- error = mCtx->decryptVerify(text, decrypted, &d_result, &v_result);
+ error = mCtx->decryptVerify(text, &decrypted, &d_result, &v_result);
});
- connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater()));
+ connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
- auto *dialog = new WaitingDialog(tr("Decrypting and Verifying"), this);
- while (thread->isRunning()) {
- QApplication::processEvents();
- }
+ while (thread->isRunning()) QApplication::processEvents();
dialog->close();
+ qDebug() << "Start Analyse Result";
+
infoBoard->associateTextEdit(edit->curTextPage());
if (gpgme_err_code(error) == GPG_ERR_NO_ERROR)
- edit->slotFillTextEditWithText(QString::fromUtf8(*decrypted));
+ edit->slotFillTextEditWithText(QString::fromUtf8(decrypted));
auto resultAnalyseDecrypt = new DecryptResultAnalyse(mCtx, error, d_result);
auto resultAnalyseVerify = new VerifyResultAnalyse(mCtx, error, v_result);
@@ -430,11 +490,15 @@ void MainWindow::slotDecryptVerify() {
}
delete resultAnalyseDecrypt;
delete resultAnalyseVerify;
+
+ qDebug() << "End Analyse Result";
+
} else if (edit->slotCurPageFileTreeView() != nullptr) {
this->slotFileDecryptVerify();
}
}
+
/*
* Append the selected (not checked!) Key(s) To Textedit
*/
@@ -452,7 +516,11 @@ void MainWindow::slotCopyMailAddressToClipboard() {
if (mKeyList->getSelected()->isEmpty()) {
return;
}
- auto &key = mCtx->getKeyById(mKeyList->getSelected()->first());
+ auto key = mCtx->getKeyById(mKeyList->getSelected()->first());
+ if (!key.good) {
+ QMessageBox::critical(nullptr, tr("Error"), tr("Key Not Found."));
+ return;
+ }
QClipboard *cb = QApplication::clipboard();
QString mail = key.email;
cb->setText(mail);
@@ -462,9 +530,11 @@ void MainWindow::slotShowKeyDetails() {
if (mKeyList->getSelected()->isEmpty()) {
return;
}
- auto &key = mCtx->getKeyById(mKeyList->getSelected()->first());
+ auto key = mCtx->getKeyById(mKeyList->getSelected()->first());
if (key.good) {
new KeyDetailsDialog(mCtx, key, this);
+ } else {
+ QMessageBox::critical(nullptr, tr("Error"), tr("Key Not Found."));
}
}
@@ -487,604 +557,20 @@ void MainWindow::uploadKeyToServer() {
dialog->slotUpload();
}
-void MainWindow::slotFileEncrypt() {
-
- auto fileTreeView = edit->slotCurPageFileTreeView();
- auto path = fileTreeView->getSelected();
-
- QFileInfo fileInfo(path);
- QFileInfo pathInfo(fileInfo.absolutePath());
-
- if (!fileInfo.isFile()) {
- QMessageBox::critical(this, tr("Error"), tr("Select a file before doing it."));
- return;
- }
- if (!fileInfo.isReadable()) {
- QMessageBox::critical(this, tr("Error"), tr("No permission to read this file."));
- return;
- }
- if (!pathInfo.isWritable()) {
- QMessageBox::critical(this, tr("Error"), tr("No permission to create file."));
- return;
- }
- if (QFile::exists(path + ".asc")) {
- auto ret = QMessageBox::warning(this,
- tr("Warning"),
- tr("The target file already exists, do you need to overwrite it?"),
- QMessageBox::Ok | QMessageBox::Cancel);
-
- if (ret == QMessageBox::Cancel)
- return;
- }
-
- QVector<GpgKey> keys;
-
- mKeyList->getCheckedKeys(keys);
-
- if (keys.empty()) {
- QMessageBox::critical(this, tr("No Key Selected"), tr("No Key Selected"));
- return;
- }
-
- for (const auto &key : keys) {
- if (!GpgME::GpgContext::checkIfKeyCanEncr(key)) {
- QMessageBox::information(this,
- tr("Invalid Operation"),
- tr("The selected key contains a key that does not actually have a encrypt usage.<br/>")
- + tr("<br/>For example the Following Key: <br/>") + key.uids.first().uid);
- return;
-
- }
- }
-
- gpgme_encrypt_result_t result;
-
- gpgme_error_t error;
- bool if_error = false;
- auto thread = QThread::create([&]() {
- try {
- error = GpgFileOpera::encryptFile(mCtx, keys, path, &result);
- } catch (const std::runtime_error &e) {
- if_error = true;
- }
- });
- connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater()));
- thread->start();
-
- auto *dialog = new WaitingDialog(tr("Encrypting"), this);
- while (thread->isRunning()) {
- QApplication::processEvents();
- }
-
- dialog->close();
- if (!if_error) {
- auto resultAnalyse = new EncryptResultAnalyse(error, result);
- auto &reportText = resultAnalyse->getResultReport();
- infoBoard->associateTabWidget(edit->tabWidget);
- infoBoard->associateFileTreeView(edit->curFilePage());
-
- if (resultAnalyse->getStatus() < 0)
- infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL);
- else if (resultAnalyse->getStatus() > 0)
- infoBoard->slotRefresh(reportText, INFO_ERROR_OK);
- else
- infoBoard->slotRefresh(reportText, INFO_ERROR_WARN);
-
- delete resultAnalyse;
-
- fileTreeView->update();
- } else {
- QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation."));
- return;
- }
-}
-
-void MainWindow::slotFileDecrypt() {
-
- auto fileTreeView = edit->slotCurPageFileTreeView();
- auto path = fileTreeView->getSelected();
-
- QFileInfo fileInfo(path);
- QFileInfo pathInfo(fileInfo.absolutePath());
- if (!fileInfo.isFile()) {
- QMessageBox::critical(this, tr("Error"), tr("Select a file before doing it."));
- return;
- }
- if (!fileInfo.isReadable()) {
- QMessageBox::critical(this, tr("Error"), tr("No permission to read this file."));
- return;
- }
- if (!pathInfo.isWritable()) {
- QMessageBox::critical(this, tr("Error"), tr("No permission to create file."));
- return;
- }
-
- QString outFileName, fileExtension = fileInfo.suffix();
-
- if (fileExtension == "asc" || fileExtension == "gpg") {
- int pos = path.lastIndexOf(QChar('.'));
- outFileName = path.left(pos);
- } else {
- outFileName = path + ".out";
- }
-
- if (QFile::exists(outFileName)) {
- auto ret = QMessageBox::warning(this,
- tr("Warning"),
- tr("The target file already exists, do you need to overwrite it?"),
- QMessageBox::Ok | QMessageBox::Cancel);
-
- if (ret == QMessageBox::Cancel)
- return;
- }
-
- gpgme_decrypt_result_t result;
- gpgme_error_t error;
- bool if_error = false;
-
- auto thread = QThread::create([&]() {
- try {
- error = GpgFileOpera::decryptFile(mCtx, path, &result);
- } catch (const std::runtime_error &e) {
- if_error = true;
- }
- });
- connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater()));
- thread->start();
-
- auto *dialog = new WaitingDialog("Decrypting", this);
- while (thread->isRunning()) {
- QApplication::processEvents();
- }
-
- dialog->close();
-
- if (!if_error) {
- auto resultAnalyse = new DecryptResultAnalyse(mCtx, error, result);
- auto &reportText = resultAnalyse->getResultReport();
- infoBoard->associateTabWidget(edit->tabWidget);
- infoBoard->associateFileTreeView(edit->curFilePage());
-
- if (resultAnalyse->getStatus() < 0)
- infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL);
- else if (resultAnalyse->getStatus() > 0)
- infoBoard->slotRefresh(reportText, INFO_ERROR_OK);
- else
- infoBoard->slotRefresh(reportText, INFO_ERROR_WARN);
-
- delete resultAnalyse;
-
- fileTreeView->update();
- } else {
- QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation."));
- return;
- }
-
-
-}
-
-void MainWindow::slotFileSign() {
-
- auto fileTreeView = edit->slotCurPageFileTreeView();
- auto path = fileTreeView->getSelected();
-
- QFileInfo fileInfo(path);
- QFileInfo pathInfo(fileInfo.absolutePath());
-
- if (!fileInfo.isFile()) {
- QMessageBox::critical(this, tr("Error"), tr("Select a file before doing it."));
- return;
- }
- if (!fileInfo.isReadable()) {
- QMessageBox::critical(this, tr("Error"), tr("No permission to read this file."));
- return;
- }
- if (!pathInfo.isWritable()) {
- QMessageBox::critical(this, tr("Error"), tr("No permission to create file."));
- return;
- }
-
- if (QFile::exists(path + ".sig")) {
- auto ret = QMessageBox::warning(this,
- tr("Warning"),
- tr("The target file already exists, do you need to overwrite it?"),
- QMessageBox::Ok | QMessageBox::Cancel);
-
- if (ret == QMessageBox::Cancel)
- return;
- }
-
- QVector<GpgKey> keys;
-
- mKeyList->getCheckedKeys(keys);
-
- if (keys.empty()) {
- QMessageBox::critical(this, tr("No Key Selected"), tr("No Key Selected"));
- return;
- }
-
- for (const auto &key : keys) {
- if (!GpgME::GpgContext::checkIfKeyCanEncr(key)) {
- QMessageBox::information(this,
- tr("Invalid Operation"),
- tr("The selected key contains a key that does not actually have a encrypt usage.<br/>")
- + tr("<br/>For example the Following Key: <br/>") + key.uids.first().uid);
- return;
-
- }
- }
-
- gpgme_sign_result_t result;
- gpgme_error_t error;
- bool if_error = false;
-
- auto thread = QThread::create([&]() {
- try {
- error = GpgFileOpera::signFile(mCtx, keys, path, &result);
- } catch (const std::runtime_error &e) {
- if_error = true;
- }
- });
- connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater()));
- thread->start();
-
- auto *dialog = new WaitingDialog(tr("Signing"), this);
- while (thread->isRunning()) {
- QApplication::processEvents();
- }
-
- dialog->close();
-
- if (!if_error) {
-
- auto resultAnalyse = new SignResultAnalyse(error, result);
- auto &reportText = resultAnalyse->getResultReport();
- infoBoard->associateTabWidget(edit->tabWidget);
- infoBoard->associateFileTreeView(edit->curFilePage());
-
- if (resultAnalyse->getStatus() < 0)
- infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL);
- else if (resultAnalyse->getStatus() > 0)
- infoBoard->slotRefresh(reportText, INFO_ERROR_OK);
- else
- infoBoard->slotRefresh(reportText, INFO_ERROR_WARN);
-
- delete resultAnalyse;
-
- fileTreeView->update();
-
- } else {
- QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation."));
- return;
- }
-
- fileTreeView->update();
-
-}
-
-void MainWindow::slotFileVerify() {
-
- auto fileTreeView = edit->slotCurPageFileTreeView();
- auto path = fileTreeView->getSelected();
-
- QFileInfo fileInfo(path);
-
- QString signFilePath, dataFilePath;
-
- if (fileInfo.suffix() == "gpg") {
- dataFilePath = path;
- signFilePath = path;
- } else if (fileInfo.suffix() == "sig") {
- int pos = path.lastIndexOf(QChar('.'));
- dataFilePath = path.left(pos);
- signFilePath = path;
- } else {
- dataFilePath = path;
- signFilePath = path + ".sig";
- }
-
- QFileInfo dataFileInfo(dataFilePath), signFileInfo(signFilePath);
-
- if (!dataFileInfo.isFile() || !signFileInfo.isFile()) {
- QMessageBox::critical(this, tr("Error"),
- tr("Please select the appropriate target file or signature file. Ensure that both are in this directory."));
- return;
- }
- if (!dataFileInfo.isReadable()) {
- QMessageBox::critical(this, tr("Error"), tr("No permission to read target file."));
- return;
- }
- if (!fileInfo.isReadable()) {
- QMessageBox::critical(this, tr("Error"), tr("No permission to read signature file."));
- return;
- }
-
- gpgme_verify_result_t result;
-
- gpgme_error_t error;
- bool if_error = false;
- auto thread = QThread::create([&]() {
- try {
- error = GpgFileOpera::verifyFile(mCtx, dataFilePath, &result);
- } catch (const std::runtime_error &e) {
- if_error = true;
- }
- });
- connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater()));
- thread->start();
-
- auto *dialog = new WaitingDialog(tr("Verifying"), this);
- while (thread->isRunning()) {
- QApplication::processEvents();
- }
- dialog->close();
-
- if (!if_error) {
- auto resultAnalyse = new VerifyResultAnalyse(mCtx, error, result);
- auto &reportText = resultAnalyse->getResultReport();
- infoBoard->associateTabWidget(edit->tabWidget);
- infoBoard->associateFileTreeView(edit->curFilePage());
-
- if (resultAnalyse->getStatus() < 0)
- infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL);
- else if (resultAnalyse->getStatus() > 0)
- infoBoard->slotRefresh(reportText, INFO_ERROR_OK);
- else
- infoBoard->slotRefresh(reportText, INFO_ERROR_WARN);
-
- if (resultAnalyse->getStatus() >= 0) {
- infoBoard->resetOptionActionsMenu();
- infoBoard->addOptionalAction("Show Verify Details", [this, error, result]() {
- VerifyDetailsDialog(this, mCtx, mKeyList, error, result);
- });
- }
-
- delete resultAnalyse;
-
- fileTreeView->update();
- } else {
- QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation."));
- return;
- }
-}
-
-void MainWindow::slotFileEncryptSign() {
- auto fileTreeView = edit->slotCurPageFileTreeView();
- auto path = fileTreeView->getSelected();
-
- QFileInfo fileInfo(path);
- QFileInfo pathInfo(fileInfo.absolutePath());
-
- if (!fileInfo.isFile()) {
- QMessageBox::critical(this, tr("Error"), tr("Select a file before doing it."));
- return;
- }
- if (!fileInfo.isReadable()) {
- QMessageBox::critical(this, tr("Error"), tr("No permission to read this file."));
- return;
- }
- if (!pathInfo.isWritable()) {
- QMessageBox::critical(this, tr("Error"), tr("No permission to create file."));
- return;
- }
- if (QFile::exists(path + ".gpg")) {
- auto ret = QMessageBox::warning(this,
- tr("Warning"),
- tr("The target file already exists, do you need to overwrite it?"),
- QMessageBox::Ok | QMessageBox::Cancel);
-
- if (ret == QMessageBox::Cancel)
- return;
- }
-
- QVector<GpgKey> keys;
-
- mKeyList->getCheckedKeys(keys);
-
- if (keys.empty()) {
- QMessageBox::critical(this, tr("No Key Selected"), tr("No Key Selected"));
- return;
- }
-
- bool can_sign = false, can_encr = false;
-
- for (const auto &key : keys) {
- bool key_can_sign = GpgME::GpgContext::checkIfKeyCanSign(key);
- bool key_can_encr = GpgME::GpgContext::checkIfKeyCanEncr(key);
-
- if (!key_can_sign && !key_can_encr) {
- QMessageBox::critical(nullptr,
- tr("Invalid KeyPair"),
- tr("The selected keypair cannot be used for signing and encryption at the same time.<br/>")
- + tr("<br/>For example the Following Key: <br/>") + key.uids.first().uid);
- return;
- }
-
- if (key_can_sign) can_sign = true;
- if (key_can_encr) can_encr = true;
- }
-
- if (!can_encr) {
- QMessageBox::critical(nullptr,
- tr("Incomplete Operation"),
- tr("None of the selected key pairs can provide the encryption function."));
- return;
- }
-
- if (!can_sign) {
- QMessageBox::warning(nullptr,
- tr("Incomplete Operation"),
- tr("None of the selected key pairs can provide the signature function."));
- }
-
- gpgme_encrypt_result_t encr_result = nullptr;
- gpgme_sign_result_t sign_result = nullptr;
-
- gpgme_error_t error;
- bool if_error = false;
-
- auto thread = QThread::create([&]() {
- try {
- error = GpgFileOpera::encryptSignFile(mCtx, keys, path, &encr_result, &sign_result);
- } catch (const std::runtime_error &e) {
- if_error = true;
- }
- });
- connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater()));
- thread->start();
-
- WaitingDialog *dialog = new WaitingDialog(tr("Encrypting and Signing"), this);
- while (thread->isRunning()) {
- QApplication::processEvents();
- }
- dialog->close();
-
- if (!if_error) {
-
- auto resultAnalyseEncr = new EncryptResultAnalyse(error, encr_result);
- auto resultAnalyseSign = new SignResultAnalyse(error, sign_result);
- int status = std::min(resultAnalyseEncr->getStatus(), resultAnalyseSign->getStatus());
- auto reportText = resultAnalyseEncr->getResultReport() + resultAnalyseSign->getResultReport();
-
- infoBoard->associateFileTreeView(edit->curFilePage());
-
- if (status < 0)
- infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL);
- else if (status > 0)
- infoBoard->slotRefresh(reportText, INFO_ERROR_OK);
- else
- infoBoard->slotRefresh(reportText, INFO_ERROR_WARN);
-
- delete resultAnalyseEncr;
- delete resultAnalyseSign;
-
- fileTreeView->update();
-
- } else {
- QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation."));
- return;
- }
-}
-
-void MainWindow::slotFileDecryptVerify() {
- auto fileTreeView = edit->slotCurPageFileTreeView();
- auto path = fileTreeView->getSelected();
-
- QFileInfo fileInfo(path);
- QFileInfo pathInfo(fileInfo.absolutePath());
- if (!fileInfo.isFile()) {
- QMessageBox::critical(this, tr("Error"), tr("Select a file(.gpg/.asc) before doing it."));
- return;
- }
- if (!fileInfo.isReadable()) {
- QMessageBox::critical(this, tr("Error"), tr("No permission to read this file."));
- return;
- }
- if (!pathInfo.isWritable()) {
- QMessageBox::critical(this, tr("Error"), tr("No permission to create file."));
- return;
- }
-
- QString outFileName, fileExtension = fileInfo.suffix();
-
- if (fileExtension == "asc" || fileExtension == "gpg") {
- int pos = path.lastIndexOf(QChar('.'));
- outFileName = path.left(pos);
- } else {
- outFileName = path + ".out";
- }
-
- gpgme_decrypt_result_t d_result = nullptr;
- gpgme_verify_result_t v_result = nullptr;
-
- gpgme_error_t error;
- bool if_error = false;
-
- auto thread = QThread::create([&]() {
- try {
- error = GpgFileOpera::decryptVerifyFile(mCtx, path, &d_result, &v_result);
- } catch (const std::runtime_error &e) {
- if_error = true;
- }
- });
- connect(thread, SIGNAL(finished(QPrivateSignal)), thread, SLOT(deleteLater()));
- thread->start();
-
-
- auto *dialog = new WaitingDialog(tr("Decrypting and Verifying"), this);
- while (thread->isRunning()) {
- QApplication::processEvents();
- }
- dialog->close();
-
- if (!if_error) {
- infoBoard->associateFileTreeView(edit->curFilePage());
-
- auto resultAnalyseDecrypt = new DecryptResultAnalyse(mCtx, error, d_result);
- auto resultAnalyseVerify = new VerifyResultAnalyse(mCtx, error, v_result);
-
- int status = std::min(resultAnalyseDecrypt->getStatus(), resultAnalyseVerify->getStatus());
- auto &reportText = resultAnalyseDecrypt->getResultReport() + resultAnalyseVerify->getResultReport();
- if (status < 0)
- infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL);
- else if (status > 0)
- infoBoard->slotRefresh(reportText, INFO_ERROR_OK);
- else
- infoBoard->slotRefresh(reportText, INFO_ERROR_WARN);
-
- if (resultAnalyseVerify->getStatus() >= 0) {
- infoBoard->resetOptionActionsMenu();
- infoBoard->addOptionalAction("Show Verify Details", [this, error, v_result]() {
- VerifyDetailsDialog(this, mCtx, mKeyList, error, v_result);
- });
- }
- delete resultAnalyseDecrypt;
- delete resultAnalyseVerify;
-
- fileTreeView->update();
- } else {
- QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation."));
- return;
- }
-}
-
-void MainWindow::slotFileEncryptCustom() {
- QStringList *keyList;
- keyList = mKeyList->getChecked();
- new FileEncryptionDialog(mCtx, *keyList, FileEncryptionDialog::Encrypt, this);
-}
-
-void MainWindow::slotFileDecryptCustom() {
- QStringList *keyList;
- keyList = mKeyList->getChecked();
- new FileEncryptionDialog(mCtx, *keyList, FileEncryptionDialog::Decrypt, this);
-}
-
-void MainWindow::slotFileSignCustom() {
- QStringList *keyList;
- keyList = mKeyList->getChecked();
- new FileEncryptionDialog(mCtx, *keyList, FileEncryptionDialog::Sign, this);
-}
-
-void MainWindow::slotFileVerifyCustom() {
- QStringList *keyList;
- keyList = mKeyList->getChecked();
- new FileEncryptionDialog(mCtx, *keyList, FileEncryptionDialog::Verify, this);
-}
void MainWindow::slotOpenFile(QString &path) {
edit->slotOpenFile(path);
}
void MainWindow::slotVersionUpgrade(const QString &currentVersion, const QString &latestVersion) {
- if(currentVersion < latestVersion) {
+ if (currentVersion < latestVersion) {
QMessageBox::warning(this,
tr("Outdated Version"),
tr("This version(%1) is out of date, please update the latest version in time. ").arg(
currentVersion)
+ tr("You can download the latest version(%1) on Github Releases Page.<br/>").arg(
latestVersion));
- } else if(currentVersion > latestVersion) {
+ } else if (currentVersion > latestVersion) {
QMessageBox::warning(this,
tr("Unreleased Version"),
tr("This version(%1) has not been officially released and is not recommended for use in a production environment. <br/>").arg(
diff --git a/src/ui/settings/SettingsAdvanced.cpp b/src/ui/settings/SettingsAdvanced.cpp
new file mode 100644
index 00000000..30414250
--- /dev/null
+++ b/src/ui/settings/SettingsAdvanced.cpp
@@ -0,0 +1,67 @@
+/**
+ * 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.
+ *
+ * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "ui/SettingsDialog.h"
+
+AdvancedTab::AdvancedTab(QWidget *parent)
+: QWidget(parent), appPath(qApp->applicationDirPath()),
+settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
+ QSettings::IniFormat) {
+ /*****************************************
+ * Steganography Box
+ *****************************************/
+ auto *steganoBox = new QGroupBox(tr("Show Steganography Options"));
+ auto *steganoBoxLayout = new QHBoxLayout();
+ steganoCheckBox = new QCheckBox(tr("Show Steganographic Options."), this);
+ steganoBoxLayout->addWidget(steganoCheckBox);
+ steganoBox->setLayout(steganoBoxLayout);
+
+ auto *pubkeyExchangeBox = new QGroupBox(tr("Pubkey Exchange"));
+ auto *pubkeyExchangeBoxLayout = new QHBoxLayout();
+ autoPubkeyExchangeCheckBox = new QCheckBox(tr("Auto Pubkey Exchange"), this);
+ pubkeyExchangeBoxLayout->addWidget(autoPubkeyExchangeCheckBox);
+ pubkeyExchangeBox->setLayout(pubkeyExchangeBoxLayout);
+
+ auto *mainLayout = new QVBoxLayout;
+ mainLayout->addWidget(steganoBox);
+ mainLayout->addWidget(pubkeyExchangeBox);
+ setSettings();
+ mainLayout->addStretch(1);
+ setLayout(mainLayout);
+}
+
+void AdvancedTab::setSettings() {
+ if (settings.value("advanced/steganography").toBool()) {
+ steganoCheckBox->setCheckState(Qt::Checked);
+ }
+ if (settings.value("advanced/autoPubkeyExchange").toBool()) {
+ autoPubkeyExchangeCheckBox->setCheckState(Qt::Checked);
+ }
+}
+
+void AdvancedTab::applySettings() {
+ settings.setValue("advanced/steganography", steganoCheckBox->isChecked());
+ settings.setValue("advanced/autoPubkeyExchange", autoPubkeyExchangeCheckBox->isChecked());
+}
+
diff --git a/src/ui/settings/SettingsAppearance.cpp b/src/ui/settings/SettingsAppearance.cpp
new file mode 100644
index 00000000..aeb7ed70
--- /dev/null
+++ b/src/ui/settings/SettingsAppearance.cpp
@@ -0,0 +1,187 @@
+/**
+ * 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.
+ *
+ * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "ui/SettingsDialog.h"
+
+AppearanceTab::AppearanceTab(QWidget *parent)
+: QWidget(parent), appPath(qApp->applicationDirPath()),
+settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
+ QSettings::IniFormat) {
+ /*****************************************
+ * Icon-Size-Box
+ *****************************************/
+ auto *iconSizeBox = new QGroupBox(tr("Iconsize"));
+ iconSizeGroup = new QButtonGroup();
+ iconSizeSmall = new QRadioButton(tr("small"));
+ iconSizeMedium = new QRadioButton(tr("medium"));
+ iconSizeLarge = new QRadioButton(tr("large"));
+
+ iconSizeGroup->addButton(iconSizeSmall, 1);
+ iconSizeGroup->addButton(iconSizeMedium, 2);
+ iconSizeGroup->addButton(iconSizeLarge, 3);
+
+ auto *iconSizeBoxLayout = new QHBoxLayout();
+ iconSizeBoxLayout->addWidget(iconSizeSmall);
+ iconSizeBoxLayout->addWidget(iconSizeMedium);
+ iconSizeBoxLayout->addWidget(iconSizeLarge);
+
+ iconSizeBox->setLayout(iconSizeBoxLayout);
+
+ /*****************************************
+ * Icon-Style-Box
+ *****************************************/
+ auto *iconStyleBox = new QGroupBox(tr("Iconstyle"));
+ iconStyleGroup = new QButtonGroup();
+ iconTextButton = new QRadioButton(tr("just text"));
+ iconIconsButton = new QRadioButton(tr("just icons"));
+ iconAllButton = new QRadioButton(tr("text and icons"));
+
+ iconStyleGroup->addButton(iconTextButton, 1);
+ iconStyleGroup->addButton(iconIconsButton, 2);
+ iconStyleGroup->addButton(iconAllButton, 3);
+
+ auto *iconStyleBoxLayout = new QHBoxLayout();
+ iconStyleBoxLayout->addWidget(iconTextButton);
+ iconStyleBoxLayout->addWidget(iconIconsButton);
+ iconStyleBoxLayout->addWidget(iconAllButton);
+
+ iconStyleBox->setLayout(iconStyleBoxLayout);
+
+ /*****************************************
+ * Window-Size-Box
+ *****************************************/
+ auto *windowSizeBox = new QGroupBox(tr("Windowstate"));
+ auto *windowSizeBoxLayout = new QHBoxLayout();
+ windowSizeCheckBox =
+ new QCheckBox(tr("Save window size and position on exit."), this);
+ windowSizeBoxLayout->addWidget(windowSizeCheckBox);
+ windowSizeBox->setLayout(windowSizeBoxLayout);
+
+ /*****************************************
+ * Info-Board-Font-Size-Box
+ *****************************************/
+
+ auto *infoBoardBox = new QGroupBox(tr("Information Board"));
+ auto *infoBoardLayout = new QHBoxLayout();
+ infoBoardFontSizeSpin = new QSpinBox();
+ infoBoardFontSizeSpin->setRange(9, 18);
+ infoBoardFontSizeSpin->setValue(10);
+ infoBoardFontSizeSpin->setSingleStep(1);
+ infoBoardLayout->addWidget(new QLabel(tr(" Front Size")));
+ infoBoardLayout->addWidget(infoBoardFontSizeSpin);
+ 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() {
+
+ // Iconsize
+ QSize iconSize = settings.value("toolbar/iconsize", QSize(24, 24)).toSize();
+ switch (iconSize.height()) {
+ case 12:
+ iconSizeSmall->setChecked(true);
+ break;
+ case 24:
+ iconSizeMedium->setChecked(true);
+ break;
+ case 32:
+ iconSizeLarge->setChecked(true);
+ break;
+ }
+ // Iconstyle
+ Qt::ToolButtonStyle iconStyle = static_cast<Qt::ToolButtonStyle>(
+ settings.value("toolbar/iconstyle", Qt::ToolButtonTextUnderIcon)
+ .toUInt());
+ switch (iconStyle) {
+ case Qt::ToolButtonTextOnly:
+ iconTextButton->setChecked(true);
+ break;
+ case Qt::ToolButtonIconOnly:
+ iconIconsButton->setChecked(true);
+ break;
+ case Qt::ToolButtonTextUnderIcon:
+ iconAllButton->setChecked(true);
+ break;
+ default:
+ break;
+ }
+
+ // Window Save and Position
+ if (settings.value("window/windowSave").toBool())
+ windowSizeCheckBox->setCheckState(Qt::Checked);
+
+ // infoBoardFontSize
+ auto infoBoardFontSize = settings.value("informationBoard/fontSize", 10).toInt();
+ if (infoBoardFontSize < 9 || infoBoardFontSize > 18)
+ infoBoardFontSize = 10;
+ infoBoardFontSizeSpin->setValue(infoBoardFontSize);
+}
+
+/***********************************
+ * get the values of the buttons and
+ * write them to settings-file
+ *************************************/
+void AppearanceTab::applySettings() {
+ switch (iconSizeGroup->checkedId()) {
+ case 1:
+ settings.setValue("toolbar/iconsize", QSize(12, 12));
+ break;
+ case 2:
+ settings.setValue("toolbar/iconsize", QSize(24, 24));
+ break;
+ case 3:
+ settings.setValue("toolbar/iconsize", QSize(32, 32));
+ break;
+ }
+
+ switch (iconStyleGroup->checkedId()) {
+ case 1:
+ settings.setValue("toolbar/iconstyle", Qt::ToolButtonTextOnly);
+ break;
+ case 2:
+ settings.setValue("toolbar/iconstyle", Qt::ToolButtonIconOnly);
+ break;
+ case 3:
+ settings.setValue("toolbar/iconstyle", Qt::ToolButtonTextUnderIcon);
+ break;
+ }
+
+ settings.setValue("window/windowSave", windowSizeCheckBox->isChecked());
+
+ settings.setValue("informationBoard/fontSize", infoBoardFontSizeSpin->value());
+}
+
diff --git a/src/ui/settings/SettingsDialog.cpp b/src/ui/settings/SettingsDialog.cpp
new file mode 100644
index 00000000..0ca188f7
--- /dev/null
+++ b/src/ui/settings/SettingsDialog.cpp
@@ -0,0 +1,205 @@
+/**
+ * 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.
+ *
+ * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "ui/SettingsDialog.h"
+#include "ui/WaitingDialog.h"
+
+SettingsDialog::SettingsDialog(GpgME::GpgContext *ctx, QWidget *parent)
+ : QDialog(parent) {
+ mCtx = ctx;
+ tabWidget = new QTabWidget;
+ generalTab = new GeneralTab(mCtx);
+ appearanceTab = new AppearanceTab;
+ sendMailTab = new SendMailTab;
+ keyserverTab = new KeyserverTab;
+ advancedTab = new AdvancedTab;
+ gpgPathsTab = new GpgPathsTab;
+
+ tabWidget->addTab(generalTab, tr("General"));
+ tabWidget->addTab(appearanceTab, tr("Appearance"));
+ tabWidget->addTab(sendMailTab, tr("Send Mail"));
+ tabWidget->addTab(keyserverTab, tr("Key Server"));
+ // tabWidget->addTab(gpgPathsTab, tr("Gpg paths"));
+ tabWidget->addTab(advancedTab, tr("Advanced"));
+
+ buttonBox =
+ new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+
+ connect(buttonBox, SIGNAL(accepted()), this, SLOT(slotAccept()));
+ connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+
+ auto *mainLayout = new QVBoxLayout;
+ mainLayout->addWidget(tabWidget);
+ mainLayout->stretch(0);
+ mainLayout->addWidget(buttonBox);
+ mainLayout->stretch(0);
+ setLayout(mainLayout);
+
+ setWindowTitle(tr("Settings"));
+
+ // slots for handling the restartneeded member
+ this->slotSetRestartNeeded(false);
+ connect(generalTab, SIGNAL(signalRestartNeeded(bool)), this,
+ SLOT(slotSetRestartNeeded(bool)));
+ connect(appearanceTab, SIGNAL(signalRestartNeeded(bool)), this,
+ SLOT(slotSetRestartNeeded(bool)));
+ connect(sendMailTab, SIGNAL(signalRestartNeeded(bool)), this,
+ SLOT(slotSetRestartNeeded(bool)));
+ connect(keyserverTab, SIGNAL(signalRestartNeeded(bool)), this,
+ SLOT(slotSetRestartNeeded(bool)));
+ connect(advancedTab, SIGNAL(signalRestartNeeded(bool)), this,
+ SLOT(slotSetRestartNeeded(bool)));
+
+ connect(this, SIGNAL(signalRestartNeeded(bool)), parent,
+ SLOT(slotSetRestartNeeded(bool)));
+
+ this->resize(480, 640);
+ this->show();
+}
+
+bool SettingsDialog::getRestartNeeded() const { return this->restartNeeded; }
+
+void SettingsDialog::slotSetRestartNeeded(bool needed) {
+ this->restartNeeded = needed;
+}
+
+void SettingsDialog::slotAccept() {
+ generalTab->applySettings();
+ sendMailTab->applySettings();
+ appearanceTab->applySettings();
+ keyserverTab->applySettings();
+ advancedTab->applySettings();
+ gpgPathsTab->applySettings();
+ if (getRestartNeeded()) {
+ emit signalRestartNeeded(true);
+ }
+ close();
+}
+
+// http://www.informit.com/articles/article.aspx?p=1405555&seqNum=3
+// http://developer.qt.nokia.com/wiki/How_to_create_a_multi_language_application
+QHash<QString, QString> SettingsDialog::listLanguages() {
+ QHash<QString, QString> languages;
+
+ languages.insert("", tr("System Default"));
+
+ QString appPath = qApp->applicationDirPath();
+ QDir qmDir = QDir(RESOURCE_DIR(appPath) + "/ts/");
+ QStringList fileNames = qmDir.entryList(QStringList("gpgfrontend_*.qm"));
+
+ for (int i = 0; i < fileNames.size(); ++i) {
+ QString locale = fileNames[i];
+ locale.truncate(locale.lastIndexOf('.'));
+ locale.remove(0, locale.indexOf('_') + 1);
+
+ // this works in qt 4.8
+ QLocale qloc(locale);
+#if QT_VERSION < 0x040800
+ QString language =
+ QLocale::languageToString(qloc.language()) + " (" + locale +
+ ")"; //+ " (" + QLocale::languageToString(qloc.language()) + ")";
+#else
+ QString language = qloc.nativeLanguageName() + " (" + locale + ")";
+#endif
+ languages.insert(locale, language);
+ }
+ return languages;
+}
+
+GpgPathsTab::GpgPathsTab(QWidget *parent)
+ : QWidget(parent), appPath(qApp->applicationDirPath()),
+ settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
+ QSettings::IniFormat) {
+ setSettings();
+
+ /*****************************************
+ * Keydb Box
+ *****************************************/
+ auto *keydbBox = new QGroupBox(tr("Relative path to keydb"));
+ auto *keydbBoxLayout = new QGridLayout();
+
+ // Label containing the current keydbpath relative to default keydb path
+ keydbLabel = new QLabel(accKeydbPath, this);
+
+ auto *keydbButton = new QPushButton("Change keydb path", this);
+ connect(keydbButton, SIGNAL(clicked()), this, SLOT(chooseKeydbDir()));
+ auto *keydbDefaultButton = new QPushButton("Set keydb to default path", this);
+ connect(keydbDefaultButton, SIGNAL(clicked()), this,
+ SLOT(setKeydbPathToDefault()));
+
+ keydbBox->setLayout(keydbBoxLayout);
+ keydbBoxLayout->addWidget(new QLabel(tr("Current keydb path: ")), 1, 1);
+ keydbBoxLayout->addWidget(keydbLabel, 1, 2);
+ keydbBoxLayout->addWidget(keydbButton, 1, 3);
+ keydbBoxLayout->addWidget(keydbDefaultButton, 2, 3);
+ keydbBoxLayout->addWidget(
+ new QLabel(tr("<b>NOTE: </b> Gpg4usb will restart automatically if you "
+ "change the keydb path!")),
+ 3, 1, 1, 3);
+
+ auto *mainLayout = new QVBoxLayout;
+ mainLayout->addWidget(keydbBox);
+ mainLayout->addStretch(1);
+ setLayout(mainLayout);
+}
+
+QString GpgPathsTab::getRelativePath(const QString &dir1, const QString &dir2) {
+ QDir dir(dir1);
+ QString s;
+
+ s = dir.relativeFilePath(dir2);
+ qDebug() << "relative path: " << s;
+ if (s.isEmpty()) {
+ s = ".";
+ }
+ return s;
+}
+
+void GpgPathsTab::setKeydbPathToDefault() {
+ accKeydbPath = ".";
+ keydbLabel->setText(".");
+}
+
+QString GpgPathsTab::chooseKeydbDir() {
+ QString dir = QFileDialog::getExistingDirectory(
+ this, tr("Choose keydb directory"), accKeydbPath,
+ QFileDialog::ShowDirsOnly);
+
+ accKeydbPath = getRelativePath(defKeydbPath, dir);
+ keydbLabel->setText(accKeydbPath);
+ return "";
+}
+
+void GpgPathsTab::setSettings() {
+ defKeydbPath = qApp->applicationDirPath() + "/keydb";
+
+ accKeydbPath = settings.value("gpgpaths/keydbpath").toString();
+ if (accKeydbPath.isEmpty()) {
+ accKeydbPath = ".";
+ }
+}
+
+void GpgPathsTab::applySettings() {
+ settings.setValue("gpgpaths/keydbpath", accKeydbPath);
+}
diff --git a/src/ui/settings/SettingsGeneral.cpp b/src/ui/settings/SettingsGeneral.cpp
new file mode 100644
index 00000000..bec66154
--- /dev/null
+++ b/src/ui/settings/SettingsGeneral.cpp
@@ -0,0 +1,358 @@
+/**
+ * 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.
+ *
+ * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "ui/SettingsDialog.h"
+#include "ui/WaitingDialog.h"
+#include "server/ComUtils.h"
+
+#include "rapidjson/prettywriter.h"
+
+GeneralTab::GeneralTab(GpgME::GpgContext *ctx, QWidget *parent)
+ : QWidget(parent), appPath(qApp->applicationDirPath()),
+ settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
+ QSettings::IniFormat) {
+ mCtx = ctx;
+
+ /*****************************************
+ * GpgFrontend Server
+ *****************************************/
+ auto *serverBox = new QGroupBox(tr("GpgFrontend Server"));
+ auto *serverBoxLayout = new QVBoxLayout();
+ serverSelectBox = new QComboBox();
+ serverBoxLayout->addWidget(serverSelectBox);
+ serverBoxLayout->addWidget(new QLabel(
+ tr("Server that provides short key and key exchange services")));
+
+ serverBox->setLayout(serverBoxLayout);
+
+ /*****************************************
+ * Save-Checked-Keys-Box
+ *****************************************/
+ auto *saveCheckedKeysBox = new QGroupBox(tr("Save Checked Keys"));
+ auto *saveCheckedKeysBoxLayout = new QHBoxLayout();
+ saveCheckedKeysCheckBox = new QCheckBox(
+ tr("Save checked private keys on exit and restore them on next start."),
+ this);
+ saveCheckedKeysBoxLayout->addWidget(saveCheckedKeysCheckBox);
+ saveCheckedKeysBox->setLayout(saveCheckedKeysBoxLayout);
+
+ /*****************************************
+ * Key-Impport-Confirmation Box
+ *****************************************/
+ auto *importConfirmationBox =
+ new QGroupBox(tr("Confirm drag'n'drop key import"));
+ auto *importConfirmationBoxLayout = new QHBoxLayout();
+ importConfirmationCheckBox = new QCheckBox(
+ tr("Import files dropped on the keylist without confirmation."), this);
+ importConfirmationBoxLayout->addWidget(importConfirmationCheckBox);
+ importConfirmationBox->setLayout(importConfirmationBoxLayout);
+
+ /*****************************************
+ * Language Select Box
+ *****************************************/
+ auto *langBox = new QGroupBox(tr("Language"));
+ auto *langBoxLayout = new QVBoxLayout();
+ langSelectBox = new QComboBox;
+ lang = SettingsDialog::listLanguages();
+
+ for (const auto &l: lang) { langSelectBox->addItem(l); }
+
+ langBoxLayout->addWidget(langSelectBox);
+ langBoxLayout->addWidget(
+ new QLabel(tr("<b>NOTE: </b> GpgFrontend will restart automatically if "
+ "you change the language!")));
+ langBox->setLayout(langBoxLayout);
+ connect(langSelectBox, SIGNAL(currentIndexChanged(int)), this,
+ SLOT(slotLanguageChanged()));
+
+ /*****************************************
+ * Own Key Select Box
+ *****************************************/
+ auto *ownKeyBox = new QGroupBox(tr("Own key"));
+ auto *ownKeyBoxLayout = new QVBoxLayout();
+ auto *ownKeyServiceTokenLayout = new QHBoxLayout();
+ ownKeySelectBox = new QComboBox;
+ getServiceTokenButton = new QPushButton(tr("Get Service Token"));
+ serviceTokenLabel = new QLabel(tr("No Service Token Found"));
+ serviceTokenLabel->setAlignment(Qt::AlignCenter);
+
+ ownKeyBox->setLayout(ownKeyBoxLayout);
+ mKeyList = new KeyList(mCtx);
+
+ // Fill the keyid hashmap
+ keyIds.insert("", tr("<none>"));
+
+ for (const auto &keyid : *mKeyList->getAllPrivateKeys()) {
+ auto key = mCtx->getKeyById(keyid);
+ if (!key.good) continue;
+ keyIds.insert(key.id, key.uids.first().uid);
+ }
+ for (const auto &k : keyIds.keys()) {
+ ownKeySelectBox->addItem(keyIds.find(k).value());
+ keyIdsList.append(k);
+ }
+ connect(ownKeySelectBox, SIGNAL(currentIndexChanged(int)), this,
+ SLOT(slotOwnKeyIdChanged()));
+ connect(getServiceTokenButton, SIGNAL(clicked(bool)), this,
+ SLOT(slotGetServiceToken()));
+
+ ownKeyBoxLayout->addWidget(new QLabel(
+ tr("Key pair for synchronization and identity authentication")));
+ ownKeyBoxLayout->addWidget(ownKeySelectBox);
+ ownKeyBoxLayout->addLayout(ownKeyServiceTokenLayout);
+ ownKeyServiceTokenLayout->addWidget(getServiceTokenButton);
+ ownKeyServiceTokenLayout->addWidget(serviceTokenLabel);
+ ownKeyServiceTokenLayout->stretch(0);
+
+ /*****************************************
+ * Mainlayout
+ *****************************************/
+ auto *mainLayout = new QVBoxLayout;
+ mainLayout->addWidget(serverBox);
+ mainLayout->addWidget(saveCheckedKeysBox);
+ mainLayout->addWidget(importConfirmationBox);
+ mainLayout->addWidget(langBox);
+ mainLayout->addWidget(ownKeyBox);
+
+ setSettings();
+ mainLayout->addStretch(1);
+ setLayout(mainLayout);
+}
+
+/**********************************
+ * Read the settings from config
+ * and set the buttons and checkboxes
+ * appropriately
+ **********************************/
+void GeneralTab::setSettings() {
+ // Keysaving
+ if (settings.value("keys/saveKeyChecked").toBool()) {
+ saveCheckedKeysCheckBox->setCheckState(Qt::Checked);
+ }
+
+ auto serverList = settings.value("general/gpgfrontendServerList").toStringList();
+ if (serverList.empty()) {
+ serverList.append("service.gpgfrontend.pub");
+ serverList.append("localhost");
+ }
+ for (const auto &s : serverList)
+ serverSelectBox->addItem(s);
+
+ qDebug() << "Current Gpgfrontend Server" << settings.value("general/currentGpgfrontendServer").toString();
+ serverSelectBox->setCurrentText(settings.value("general/currentGpgfrontendServer",
+ "service.gpgfrontend.pub").toString());
+
+ connect(serverSelectBox, QOverload<const QString &>::of(&QComboBox::currentTextChanged),
+ this, [&](const QString &current) -> void {
+ settings.setValue("general/currentGpgfrontendServer", current);
+ });
+
+ // Language setting
+ QString langKey = settings.value("int/lang").toString();
+ QString langValue = lang.value(langKey);
+ if (langKey != "") {
+ langSelectBox->setCurrentIndex(langSelectBox->findText(langValue));
+ }
+
+ QString own_key_id = settings.value("general/ownKeyId").toString();
+ qDebug() << "OwnKeyId" << own_key_id;
+ if (own_key_id.isEmpty()) {
+ ownKeySelectBox->setCurrentText("<none>");
+ } else {
+ const auto text = keyIds.find(own_key_id).value();
+ qDebug() << "OwnKey" << own_key_id << text;
+ ownKeySelectBox->setCurrentText(text);
+ }
+
+ serviceToken = settings.value("general/serviceToken").toString();
+ qDebug() << "Load Service Token" << serviceToken;
+ if (!serviceToken.isEmpty()) {
+ serviceTokenLabel->setText(serviceToken);
+ }
+
+ // Get own key information from keydb/gpg.conf (if contained)
+ if (settings.value("general/confirmImportKeys", Qt::Checked).toBool()) {
+ importConfirmationCheckBox->setCheckState(Qt::Checked);
+ }
+}
+
+/***********************************
+ * get the values of the buttons and
+ * write them to settings-file
+ *************************************/
+void GeneralTab::applySettings() {
+ settings.setValue("keys/saveKeyChecked",
+ saveCheckedKeysCheckBox->isChecked());
+
+ qDebug() << "serverSelectBox currentText" << serverSelectBox->currentText();
+ settings.setValue("general/currentGpgfrontendServer",
+ serverSelectBox->currentText());
+
+ auto *serverList = new QStringList();
+ for (int i = 0; i < serverSelectBox->count(); i++)
+ serverList->append(serverSelectBox->itemText(i));
+ settings.setValue("general/gpgfrontendServerList",
+ *serverList);
+ delete serverList;
+
+ settings.setValue("int/lang", lang.key(langSelectBox->currentText()));
+
+ settings.setValue("general/ownKeyId",
+ keyIdsList[ownKeySelectBox->currentIndex()]);
+
+ settings.setValue("general/serviceToken",
+ serviceToken);
+
+ settings.setValue("general/confirmImportKeys",
+ importConfirmationCheckBox->isChecked());
+}
+
+void GeneralTab::slotLanguageChanged() { emit signalRestartNeeded(true); }
+
+void GeneralTab::slotOwnKeyIdChanged() {
+ // Set ownKeyId to currently selected
+ this->serviceTokenLabel->setText(tr("No Service Token Found"));
+ serviceToken.clear();
+}
+
+void GeneralTab::slotGetServiceToken() {
+
+ auto utils = new ComUtils(this);
+
+ QUrl reqUrl(utils->getUrl(ComUtils::GetServiceToken));
+ QNetworkRequest request(reqUrl);
+ request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
+
+
+ const auto keyId = keyIdsList[ownKeySelectBox->currentIndex()];
+
+ qDebug() << "KeyId" << keyIdsList[ownKeySelectBox->currentIndex()];
+
+ if (keyId.isEmpty()) {
+ QMessageBox::critical(this, tr("Invalid Operation"),
+ tr("Own Key can not be None while getting service token."));
+ return;
+ }
+
+ QStringList selectedKeyIds(keyIdsList[ownKeySelectBox->currentIndex()]);
+
+ QByteArray keyDataBuf;
+ mCtx->exportKeys(&selectedKeyIds, &keyDataBuf);
+
+ GpgKey key = mCtx->getKeyById(keyId);
+
+ if (!key.good) {
+ QMessageBox::critical(this, tr("Error"),
+ tr("Key Not Exists"));
+ return;
+ }
+
+ qDebug() << "keyDataBuf" << keyDataBuf;
+
+ /**
+ * {
+ * "publicKey" : ...
+ * "sha": ...
+ * "signedFpr": ...
+ * "version": ...
+ * }
+ */
+
+ QCryptographicHash shaGen(QCryptographicHash::Sha256);
+ shaGen.addData(keyDataBuf);
+
+ auto shaStr = shaGen.result().toHex();
+
+ auto signFprStr = ComUtils::getSignStringBase64(mCtx, key.fpr, key);
+
+ rapidjson::Value pubkey, ver, sha, signFpr;
+
+ rapidjson::Document doc;
+ doc.SetObject();
+
+ pubkey.SetString(keyDataBuf.constData(), keyDataBuf.count());
+
+ auto version = qApp->applicationVersion();
+ ver.SetString(version.toUtf8().constData(), qApp->applicationVersion().count());
+
+ sha.SetString(shaStr.constData(), shaStr.count());
+ signFpr.SetString(signFprStr.constData(), signFprStr.count());
+
+ rapidjson::Document::AllocatorType &allocator = doc.GetAllocator();
+
+ doc.AddMember("publicKey", pubkey, allocator);
+ doc.AddMember("sha", sha, allocator);
+ doc.AddMember("signedFpr", signFpr, allocator);
+ doc.AddMember("version", ver, allocator);
+
+ rapidjson::StringBuffer sb;
+ rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(sb);
+ doc.Accept(writer);
+
+ QByteArray postData(sb.GetString());
+
+ QNetworkReply *reply = utils->getNetworkManager().post(request, postData);
+
+ // Show Waiting Dailog
+ auto dialog = new WaitingDialog("Getting Token From Server", this);
+ dialog->show();
+
+ while (reply->isRunning()) {
+ QApplication::processEvents();
+ }
+
+ dialog->close();
+
+ if (utils->checkServerReply(reply->readAll().constData())) {
+
+ /**
+ * {
+ * "serviceToken" : ...
+ * "fpr": ...
+ * }
+ */
+
+ if (!utils->checkDataValueStr("serviceToken") || !utils->checkDataValueStr("fpr")) {
+ QMessageBox::critical(this, tr("Error"),
+ tr("The communication content with the server does not meet the requirements"));
+ return;
+ }
+
+ QString serviceTokenTemp = utils->getDataValueStr("serviceToken");
+ QString fpr = utils->getDataValueStr("fpr");
+ auto key = mCtx->getKeyByFpr(fpr);
+ if (utils->checkServiceTokenFormat(serviceTokenTemp) && key.good) {
+ serviceToken = serviceTokenTemp;
+ qDebug() << "Get Service Token" << serviceToken;
+ // Auto update settings
+ settings.setValue("general/serviceToken", serviceToken);
+ serviceTokenLabel->setText(serviceToken);
+ QMessageBox::information(this, tr("Notice"),
+ tr("Succeed in getting service token"));
+ } else {
+ QMessageBox::critical(this, tr("Error"), tr("There is a problem with the communication with the server"));
+ }
+ }
+
+}
diff --git a/src/ui/settings/SettingsKeyServer.cpp b/src/ui/settings/SettingsKeyServer.cpp
new file mode 100644
index 00000000..b49eb9e0
--- /dev/null
+++ b/src/ui/settings/SettingsKeyServer.cpp
@@ -0,0 +1,148 @@
+/**
+ * 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.
+ *
+ * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "ui/SettingsDialog.h"
+
+KeyserverTab::KeyserverTab(QWidget *parent)
+ : QWidget(parent), appPath(qApp->applicationDirPath()),
+ settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
+ QSettings::IniFormat) {
+
+ auto generalGroupBox = new QGroupBox(tr("General"));
+ auto generalLayout = new QVBoxLayout();
+
+ keyServerTable = new QTableWidget();
+ keyServerTable->setColumnCount(3);
+ keyServerTable->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
+ keyServerTable->horizontalHeader()->setStretchLastSection(false);
+ keyServerTable->verticalHeader()->hide();
+ keyServerTable->setShowGrid(false);
+ keyServerTable->sortByColumn(0, Qt::AscendingOrder);
+ keyServerTable->setSelectionBehavior(QAbstractItemView::SelectRows);
+ keyServerTable->setSelectionMode(QAbstractItemView::SingleSelection);
+
+ // tableitems not editable
+ keyServerTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ // no focus (rectangle around tableitems)
+ // may be it should focus on whole row
+ keyServerTable->setFocusPolicy(Qt::NoFocus);
+ keyServerTable->setAlternatingRowColors(true);
+
+ QStringList labels;
+ labels << tr("No.") << tr("Address") << tr("Available");
+ keyServerTable->setHorizontalHeaderLabels(labels);
+
+ auto *mainLayout = new QVBoxLayout(this);
+ auto *label = new QLabel(tr("Default Key Server for Import:"));
+
+ comboBox = new QComboBox;
+ comboBox->setEditable(false);
+ comboBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+
+ auto *addKeyServerBox = new QWidget(this);
+ auto *addKeyServerLayout = new QHBoxLayout(addKeyServerBox);
+ auto *http = new QLabel("URL: ");
+ newKeyServerEdit = new QLineEdit(this);
+ auto *newKeyServerButton = new QPushButton(tr("Add"), this);
+ connect(newKeyServerButton, SIGNAL(clicked()), this, SLOT(addKeyServer()));
+ addKeyServerLayout->addWidget(http);
+ addKeyServerLayout->addWidget(newKeyServerEdit);
+ addKeyServerLayout->addWidget(newKeyServerButton);
+
+ generalLayout->addWidget(label);
+ generalLayout->addWidget(comboBox);
+ generalLayout->addWidget(keyServerTable);
+ generalLayout->addWidget(addKeyServerBox);
+ generalLayout->addStretch(0);
+
+ generalGroupBox->setLayout(generalLayout);
+ mainLayout->addWidget(generalGroupBox);
+ mainLayout->addStretch(0);
+
+ setLayout(mainLayout);
+ // Read keylist from ini-file and fill it into combobox
+ setSettings();
+ refreshTable();
+}
+
+/**********************************
+ * Read the settings from config
+ * and set the buttons and checkboxes
+ * appropriately
+ **********************************/
+void KeyserverTab::setSettings() {
+
+ keyServerStrList = settings.value("keyserver/keyServerList").toStringList();
+
+ for (const auto &keyServer : keyServerStrList) {
+ comboBox->addItem(keyServer);
+ qDebug() << "KeyserverTab Get ListItemText" << keyServer;
+ }
+
+ comboBox->setCurrentText(
+ settings.value("keyserver/defaultKeyServer").toString());
+
+}
+
+void KeyserverTab::addKeyServer() {
+ QString targetUrl;
+ if (newKeyServerEdit->text().startsWith("http://") ||
+ newKeyServerEdit->text().startsWith("https://"))
+ targetUrl = newKeyServerEdit->text();
+ else
+ targetUrl = "http://" + newKeyServerEdit->text();
+ keyServerStrList.append(targetUrl);
+ comboBox->addItem(targetUrl);
+ refreshTable();
+}
+
+/***********************************
+ * get the values of the buttons and
+ * write them to settings-file
+ *************************************/
+void KeyserverTab::applySettings() {
+ settings.setValue("keyserver/keyServerList", keyServerStrList);
+ settings.setValue("keyserver/defaultKeyServer", comboBox->currentText());
+}
+
+void KeyserverTab::refreshTable() {
+
+ qDebug() << "Start Refreshing Key Server Table";
+
+ keyServerTable->setRowCount(keyServerStrList.size());
+
+ int index = 0;
+ for (const auto &server : keyServerStrList) {
+ auto *tmp1 = new QTableWidgetItem(QString::number(index));
+ tmp1->setTextAlignment(Qt::AlignCenter);
+ keyServerTable->setItem(index, 0, tmp1);
+ auto *tmp2 = new QTableWidgetItem(server);
+ tmp2->setTextAlignment(Qt::AlignCenter);
+ keyServerTable->setItem(index, 1, tmp2);
+ auto *tmp3 = new QTableWidgetItem("");
+ tmp3->setTextAlignment(Qt::AlignCenter);
+ keyServerTable->setItem(index, 2, tmp3);
+ index++;
+ }
+}
diff --git a/src/ui/settings/SettingsSendMail.cpp b/src/ui/settings/SettingsSendMail.cpp
new file mode 100644
index 00000000..a5e3274f
--- /dev/null
+++ b/src/ui/settings/SettingsSendMail.cpp
@@ -0,0 +1,193 @@
+/**
+ * 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.
+ *
+ * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "ui/SettingsDialog.h"
+#include "smtp/SmtpMime"
+
+SendMailTab::SendMailTab(QWidget *parent)
+ : QWidget(parent), appPath(qApp->applicationDirPath()),
+ settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
+ QSettings::IniFormat) {
+
+ enableCheckBox = new QCheckBox(tr("Enable"));
+ enableCheckBox->setTristate(false);
+
+ smtpAddress = new QLineEdit();
+ username = new QLineEdit();
+ password = new QLineEdit();
+ password->setEchoMode(QLineEdit::Password);
+
+ portSpin = new QSpinBox();
+ portSpin->setMinimum(1);
+ portSpin->setMaximum(65535);
+ connectionTypeComboBox = new QComboBox();
+ connectionTypeComboBox->addItem("None");
+ connectionTypeComboBox->addItem("SSL");
+ connectionTypeComboBox->addItem("TLS");
+ connectionTypeComboBox->addItem("STARTTLS");
+
+ defaultSender = new QLineEdit();;
+ checkConnectionButton = new QPushButton(tr("Check Connection"));
+
+ auto generalGroupBox = new QGroupBox(tr("General"));
+ auto connectGroupBox = new QGroupBox(tr("Connection"));
+ auto preferenceGroupBox = new QGroupBox(tr("Preference"));
+
+ auto generalLayout = new QGridLayout();
+ generalLayout->addWidget(enableCheckBox);
+
+ auto connectLayout = new QGridLayout();
+ connectLayout->addWidget(new QLabel(tr("SMTP Address")), 1, 0);
+ connectLayout->addWidget(smtpAddress, 1, 1, 1, 4);
+ connectLayout->addWidget(new QLabel(tr("Username")), 2, 0);
+ connectLayout->addWidget(username, 2, 1, 1, 4);
+ connectLayout->addWidget(new QLabel(tr("Password")), 3, 0);
+ connectLayout->addWidget(password, 3, 1, 1, 4);
+ connectLayout->addWidget(new QLabel(tr("Port")), 4, 0);
+ connectLayout->addWidget(portSpin, 4, 1, 1, 1);
+ connectLayout->addWidget(new QLabel(tr("Connection Security")), 5, 0);
+ connectLayout->addWidget(connectionTypeComboBox, 5, 1, 1, 1);
+ connectLayout->addWidget(checkConnectionButton, 6, 0);
+
+ auto preferenceLayout = new QGridLayout();
+
+ preferenceLayout->addWidget(new QLabel(tr("Default Sender")), 0, 0);
+ preferenceLayout->addWidget(defaultSender, 0, 1, 1, 4);
+
+ generalGroupBox->setLayout(generalLayout);
+ connectGroupBox->setLayout(connectLayout);
+ preferenceGroupBox->setLayout(preferenceLayout);
+
+ auto vBox = new QVBoxLayout();
+ vBox->addWidget(generalGroupBox);
+ vBox->addWidget(connectGroupBox);
+ vBox->addWidget(preferenceGroupBox);
+ vBox->addStretch(0);
+
+ connect(enableCheckBox, SIGNAL(stateChanged(int)), this, SLOT(slotCheckBoxSetEnableDisable(int)));
+ connect(checkConnectionButton, SIGNAL(clicked(bool)), this, SLOT(slotCheckConnection()));
+
+
+ this->setLayout(vBox);
+ setSettings();
+}
+
+/**********************************
+ * Read the settings from config
+ * and set the buttons and checkboxes
+ * appropriately
+ **********************************/
+void SendMailTab::setSettings() {
+
+ if (settings.value("sendMail/enable", false).toBool())
+ enableCheckBox->setCheckState(Qt::Checked);
+ else {
+ enableCheckBox->setCheckState(Qt::Unchecked);
+ smtpAddress->setDisabled(true);
+ username->setDisabled(true);
+ password->setDisabled(true);
+ portSpin->setDisabled(true);
+ connectionTypeComboBox->setDisabled(true);
+ defaultSender->setDisabled(true);
+ checkConnectionButton->setDisabled(true);
+ }
+
+ smtpAddress->setText(settings.value("sendMail/smtpAddress", QString()).toString());
+ username->setText(settings.value("sendMail/username", QString()).toString());
+ password->setText(settings.value("sendMail/password", QString()).toString());
+ portSpin->setValue(settings.value("sendMail/port", 25).toInt());
+ connectionTypeComboBox->setCurrentText(settings.value("sendMail/connectionType", "None").toString());
+ defaultSender->setText(settings.value("sendMail/defaultSender", QString()).toString());
+
+}
+
+/***********************************
+ * get the values of the buttons and
+ * write them to settings-file
+ *************************************/
+void SendMailTab::applySettings() {
+
+ settings.setValue("sendMail/smtpAddress", smtpAddress->text());
+ settings.setValue("sendMail/username", username->text());
+ settings.setValue("sendMail/password", password->text());
+ settings.setValue("sendMail/port", portSpin->value());
+ settings.setValue("sendMail/connectionType", connectionTypeComboBox->currentText());
+ settings.setValue("sendMail/defaultSender", defaultSender->text());
+
+ settings.setValue("sendMail/enable", enableCheckBox->isChecked());
+}
+
+void SendMailTab::slotCheckConnection() {
+
+ SmtpClient::ConnectionType connectionType;
+ const auto selectedConnType = connectionTypeComboBox->currentText();
+ if (selectedConnType == "SSL") {
+ connectionType = SmtpClient::ConnectionType::SslConnection;
+ } else if (selectedConnType == "TLS" || selectedConnType == "STARTTLS") {
+ connectionType = SmtpClient::ConnectionType::TlsConnection;
+ } else {
+ connectionType = SmtpClient::ConnectionType::TcpConnection;
+ }
+
+ SmtpClient smtp(smtpAddress->text(), portSpin->value(), connectionType);
+
+ smtp.setUser(username->text());
+ smtp.setPassword(password->text());
+
+ bool if_success = true;
+
+ if (!smtp.connectToHost()) {
+ QMessageBox::critical(this, tr("Fail"), tr("Fail to Connect SMTP Server"));
+ if_success = false;
+ }
+ if (if_success && !smtp.login()) {
+ QMessageBox::critical(this, tr("Fail"), tr("Fail to Login"));
+ if_success = false;
+ }
+
+ if (if_success)
+ QMessageBox::information(this, tr("Success"), tr("Succeed in connecting and login"));
+
+}
+
+void SendMailTab::slotCheckBoxSetEnableDisable(int state) {
+ if (state == Qt::Checked) {
+ smtpAddress->setEnabled(true);
+ username->setEnabled(true);
+ password->setEnabled(true);
+ portSpin->setEnabled(true);
+ connectionTypeComboBox->setEnabled(true);
+ defaultSender->setEnabled(true);
+ checkConnectionButton->setEnabled(true);
+ } else {
+ smtpAddress->setDisabled(true);
+ username->setDisabled(true);
+ password->setDisabled(true);
+ portSpin->setDisabled(true);
+ connectionTypeComboBox->setDisabled(true);
+ defaultSender->setDisabled(true);
+ checkConnectionButton->setDisabled(true);
+ }
+}
+
diff --git a/src/ui/widgets/EditorPage.cpp b/src/ui/widgets/EditorPage.cpp
index 05d5cbea..beb37b96 100644
--- a/src/ui/widgets/EditorPage.cpp
+++ b/src/ui/widgets/EditorPage.cpp
@@ -44,8 +44,6 @@ EditorPage::EditorPage(QString filePath, QWidget *parent) : QWidget(parent),
// Front in same width
this->setFont({"Courier"});
-
- connect(textPage, SIGNAL(textChanged()), this, SLOT(formatGpgHeader()));
}
const QString &EditorPage::getFilePath() const {
diff --git a/src/ui/widgets/InfoBoardWidget.cpp b/src/ui/widgets/InfoBoardWidget.cpp
index f26917a4..b9372c59 100644
--- a/src/ui/widgets/InfoBoardWidget.cpp
+++ b/src/ui/widgets/InfoBoardWidget.cpp
@@ -50,11 +50,11 @@ InfoBoardWidget::InfoBoardWidget(QWidget *parent, GpgME::GpgContext *ctx, KeyLis
actionButtonMenu->setFixedHeight(36);
actionButtonLayout = new QHBoxLayout();
- actionButtonLayout->setContentsMargins(0, 0, 0, 0);
+ actionButtonLayout->setContentsMargins(5, 5, 5, 5);
actionButtonLayout->setSpacing(0);
actionButtonMenu->setLayout(actionButtonLayout);
- auto label = new QLabel(tr("Optional Actions Menu"));
+ auto label = new QLabel(tr("Optional Actions"));
label->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
label->setContentsMargins(0, 0, 0, 0);
@@ -150,25 +150,44 @@ void InfoBoardWidget::associateTabWidget(QTabWidget *tab) {
connect(tab, SIGNAL(tabCloseRequested(int)), this, SLOT(slotReset()));
}
+
void InfoBoardWidget::addOptionalAction(const QString &name, const std::function<void()> &action) {
auto actionButton = new QPushButton(name);
+ auto layout = new QHBoxLayout();
+ layout->setContentsMargins(5, 0, 5, 0);
infoBoard->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
- actionButtonLayout->addWidget(actionButton);
+ // set margin from surroundings
+ layout->addWidget(actionButton);
+ actionButtonLayout->addLayout(layout);
connect(actionButton, &QPushButton::clicked, this, [=]() {
action();
});
}
+/**
+ * Delete All item in actionButtonLayout
+ */
void InfoBoardWidget::resetOptionActionsMenu() {
- QLayoutItem *item;
- while ((item = actionButtonLayout->layout()->takeAt(2)) != nullptr) {
- actionButtonLayout->removeItem(item);
- delete item->widget();
- delete item;
- }
+ deleteWidgetsInLayout(actionButtonLayout, 2);
}
void InfoBoardWidget::slotReset() {
this->infoBoard->clear();
resetOptionActionsMenu();
}
+
+/**
+ * Try Delete all widget from target layout
+ * @param layout target layout
+ */
+void InfoBoardWidget::deleteWidgetsInLayout(QLayout *layout, int start_index) {
+ QLayoutItem *item;
+ while ((item = layout->layout()->takeAt(start_index)) != nullptr) {
+ layout->removeItem(item);
+ if (item->layout() != nullptr)
+ deleteWidgetsInLayout(item->layout());
+ else if (item->widget() != nullptr)
+ delete item->widget();
+ delete item;
+ }
+}
diff --git a/src/ui/widgets/KeyList.cpp b/src/ui/widgets/KeyList.cpp
index 3929868e..9c9c6763 100644
--- a/src/ui/widgets/KeyList.cpp
+++ b/src/ui/widgets/KeyList.cpp
@@ -31,8 +31,7 @@ KeyList::KeyList(GpgME::GpgContext *ctx,
KeyListColumn::InfoType infoType,
QWidget *parent)
: QWidget(parent), mSelectType(selectType), mInfoType(infoType), appPath(qApp->applicationDirPath()),
- settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", QSettings::IniFormat)
-{
+ settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", QSettings::IniFormat) {
mCtx = ctx;
@@ -43,7 +42,7 @@ KeyList::KeyList(GpgME::GpgContext *ctx,
mKeyList->setShowGrid(false);
mKeyList->sortByColumn(2, Qt::AscendingOrder);
mKeyList->setSelectionBehavior(QAbstractItemView::SelectRows);
- mKeyList->setSelectionMode( QAbstractItemView::SingleSelection );
+ mKeyList->setSelectionMode(QAbstractItemView::SingleSelection);
// tableitems not editable
mKeyList->setEditTriggers(QAbstractItemView::NoEditTriggers);
@@ -54,22 +53,22 @@ KeyList::KeyList(GpgME::GpgContext *ctx,
mKeyList->setAlternatingRowColors(true);
// Hidden Column For Purpose
- if(!(mInfoType & KeyListColumn::TYPE)) {
+ if (!(mInfoType & KeyListColumn::TYPE)) {
mKeyList->setColumnHidden(1, true);
}
- if(!(mInfoType & KeyListColumn::NAME)) {
+ if (!(mInfoType & KeyListColumn::NAME)) {
mKeyList->setColumnHidden(2, true);
}
- if(!(mInfoType & KeyListColumn::EmailAddress)) {
+ if (!(mInfoType & KeyListColumn::EmailAddress)) {
mKeyList->setColumnHidden(3, true);
}
- if(!(mInfoType & KeyListColumn::Usage)) {
+ if (!(mInfoType & KeyListColumn::Usage)) {
mKeyList->setColumnHidden(4, true);
}
- if(!(mInfoType & KeyListColumn::Validity)) {
+ if (!(mInfoType & KeyListColumn::Validity)) {
mKeyList->setColumnHidden(5, true);
}
- if(!(mInfoType & KeyListColumn::FingerPrint)) {
+ if (!(mInfoType & KeyListColumn::FingerPrint)) {
mKeyList->setColumnHidden(6, true);
}
@@ -95,8 +94,7 @@ KeyList::KeyList(GpgME::GpgContext *ctx,
slotRefresh();
}
-void KeyList::slotRefresh()
-{
+void KeyList::slotRefresh() {
QStringList *keyList;
keyList = getChecked();
// while filling the table, sort enabled causes errors
@@ -110,21 +108,21 @@ void KeyList::slotRefresh()
int row_count = 0;
while (it != keys.end()) {
- if(mFilter != nullptr) {
- if(!mFilter(*it)) {
+ if (mFilter != nullptr) {
+ if (!mFilter(*it)) {
it = keys.erase(it);
continue;
}
}
- if(!excluded_key_ids.isEmpty()){
+ if (!excluded_key_ids.isEmpty()) {
auto iterator = std::find_if(excluded_key_ids.begin(), excluded_key_ids.end(),
- [it] (const auto &key_id) -> bool {
- if(it->id == key_id) return true;
- else return false;
- });
+ [it](const auto &key_id) -> bool {
+ if (it->id == key_id) return true;
+ else return false;
+ });
- if(iterator != excluded_key_ids.end()) {
+ if (iterator != excluded_key_ids.end()) {
it = keys.erase(it);
continue;
}
@@ -161,10 +159,10 @@ void KeyList::slotRefresh()
type_steam << "pub";
}
- if(it->is_private_key && !it->has_master_key) {
+ if (it->is_private_key && !it->has_master_key) {
type_steam << "#";
}
- auto* tmp1 = new QTableWidgetItem(type_str);
+ auto *tmp1 = new QTableWidgetItem(type_str);
mKeyList->setItem(row_index, 1, tmp1);
auto *tmp2 = new QTableWidgetItem(it->name);
@@ -177,13 +175,13 @@ void KeyList::slotRefresh()
QString usage;
QTextStream usage_steam(&usage);
- if(GpgME::GpgContext::checkIfKeyCanCert(*it))
+ if (GpgME::GpgContext::checkIfKeyCanCert(*it))
usage_steam << "C";
- if(GpgME::GpgContext::checkIfKeyCanEncr(*it))
+ if (GpgME::GpgContext::checkIfKeyCanEncr(*it))
usage_steam << "E";
- if(GpgME::GpgContext::checkIfKeyCanSign(*it))
+ if (GpgME::GpgContext::checkIfKeyCanSign(*it))
usage_steam << "S";
- if(GpgME::GpgContext::checkIfKeyCanAuth(*it))
+ if (GpgME::GpgContext::checkIfKeyCanAuth(*it))
usage_steam << "A";
auto *temp_usage = new QTableWidgetItem(usage);
@@ -199,7 +197,7 @@ void KeyList::slotRefresh()
mKeyList->setItem(row_index, 6, temp_fpr);
// strike out expired keys
- if(it->expired || it->revoked) {
+ if (it->expired || it->revoked) {
QFont strike = tmp2->font();
strike.setStrikeOut(true);
tmp0->setFont(strike);
@@ -218,8 +216,7 @@ void KeyList::slotRefresh()
setChecked(keyList);
}
-QStringList *KeyList::getChecked()
-{
+QStringList *KeyList::getChecked() {
auto *ret = new QStringList();
for (int i = 0; i < mKeyList->rowCount(); i++) {
if (mKeyList->item(i, 0)->checkState() == Qt::Checked) {
@@ -229,19 +226,17 @@ QStringList *KeyList::getChecked()
return ret;
}
-QStringList *KeyList::getAllPrivateKeys()
-{
+QStringList *KeyList::getAllPrivateKeys() {
auto *ret = new QStringList();
for (int i = 0; i < mKeyList->rowCount(); i++) {
- if (mKeyList->item(i, 1)) {
+ if (mKeyList->item(i, 1) && buffered_keys[i].is_private_key) {
*ret << buffered_keys[i].id;
}
}
return ret;
}
-QStringList *KeyList::getPrivateChecked()
-{
+QStringList *KeyList::getPrivateChecked() {
auto *ret = new QStringList();
for (int i = 0; i < mKeyList->rowCount(); i++) {
if ((mKeyList->item(i, 0)->checkState() == Qt::Checked) && (mKeyList->item(i, 1))) {
@@ -251,19 +246,17 @@ QStringList *KeyList::getPrivateChecked()
return ret;
}
-void KeyList::setChecked(QStringList *keyIds)
-{
+void KeyList::setChecked(QStringList *keyIds) {
if (!keyIds->isEmpty()) {
for (int i = 0; i < mKeyList->rowCount(); i++) {
- if (keyIds->contains(buffered_keys[i].id)) {
+ if (keyIds->contains(buffered_keys[i].id)) {
mKeyList->item(i, 0)->setCheckState(Qt::Checked);
}
}
}
}
-QStringList *KeyList::getSelected()
-{
+QStringList *KeyList::getSelected() {
auto *ret = new QStringList();
for (int i = 0; i < mKeyList->rowCount(); i++) {
@@ -274,47 +267,42 @@ QStringList *KeyList::getSelected()
return ret;
}
-[[maybe_unused]] bool KeyList::containsPrivateKeys()
-{
+[[maybe_unused]] bool KeyList::containsPrivateKeys() {
for (int i = 0; i < mKeyList->rowCount(); i++) {
if (mKeyList->item(i, 1)) {
- return true;
+ return true;
}
}
return false;
}
-void KeyList::setColumnWidth(int row, int size)
-{
+void KeyList::setColumnWidth(int row, int size) {
mKeyList->setColumnWidth(row, size);
}
-void KeyList::contextMenuEvent(QContextMenuEvent *event)
-{
+void KeyList::contextMenuEvent(QContextMenuEvent *event) {
if (mKeyList->selectedItems().length() > 0) {
popupMenu->exec(event->globalPos());
}
}
-void KeyList::addSeparator()
-{
+void KeyList::addSeparator() {
popupMenu->addSeparator();
}
-void KeyList::addMenuAction(QAction *act)
-{
+void KeyList::addMenuAction(QAction *act) {
popupMenu->addAction(act);
}
-void KeyList::dropEvent(QDropEvent* event)
-{
+void KeyList::dropEvent(QDropEvent *event) {
auto *dialog = new QDialog();
dialog->setWindowTitle(tr("Import Keys"));
QLabel *label;
- label = new QLabel(tr("You've dropped something on the table.\n GpgFrontend will now try to import key(s).")+"\n");
+ label = new QLabel(
+ tr("You've dropped something on the table.\n GpgFrontend will now try to import key(s).") + "\n");
// "always import keys"-CheckBox
auto *checkBox = new QCheckBox(tr("Always import without bothering."));
@@ -332,56 +320,50 @@ void KeyList::dropEvent(QDropEvent* event)
dialog->setLayout(vbox);
- if (settings.value("general/confirmImportKeys",Qt::Checked).toBool())
- {
+ if (settings.value("general/confirmImportKeys", Qt::Checked).toBool()) {
dialog->exec();
if (dialog->result() == QDialog::Rejected) {
return;
}
- if (checkBox->isChecked()){
- settings.setValue("general/confirmImportKeys", false);
+ if (checkBox->isChecked()) {
+ settings.setValue("general/confirmImportKeys", false);
} else {
settings.setValue("general/confirmImportKeys", true);
}
}
- if (event->mimeData()->hasUrls())
- {
- for (const QUrl& tmp : event->mimeData()->urls())
- {
- QFile file;
- file.setFileName(tmp.toLocalFile());
- if (!file.open(QIODevice::ReadOnly)) {
- qDebug() << tr("Couldn't Open File: ") + tmp.toString();
- }
- QByteArray inBuffer = file.readAll();
- this->importKeys(inBuffer);
- file.close();
- }
- } else {
- QByteArray inBuffer(event->mimeData()->text().toUtf8());
+ if (event->mimeData()->hasUrls()) {
+ for (const QUrl &tmp : event->mimeData()->urls()) {
+ QFile file;
+ file.setFileName(tmp.toLocalFile());
+ if (!file.open(QIODevice::ReadOnly)) {
+ qDebug() << tr("Couldn't Open File: ") + tmp.toString();
+ }
+ QByteArray inBuffer = file.readAll();
this->importKeys(inBuffer);
- }
+ file.close();
+ }
+ } else {
+ QByteArray inBuffer(event->mimeData()->text().toUtf8());
+ this->importKeys(inBuffer);
+ }
}
-void KeyList::dragEnterEvent(QDragEnterEvent *event)
-{
+void KeyList::dragEnterEvent(QDragEnterEvent *event) {
event->acceptProposedAction();
}
/** set background color for Keys and put them to top
*
*/
-[[maybe_unused]] void KeyList::markKeys(QStringList *keyIds)
-{
- foreach(QString id, *keyIds) {
- qDebug() << "marked: " << id;
- }
+[[maybe_unused]] void KeyList::markKeys(QStringList *keyIds) {
+ foreach(QString id, *keyIds) {
+ qDebug() << "marked: " << id;
+ }
}
-void KeyList::importKeys(QByteArray inBuffer)
-{
+void KeyList::importKeys(QByteArray inBuffer) {
GpgImportInformation result = mCtx->importKey(std::move(inBuffer));
new KeyImportDetailDialog(mCtx, result, false, this);
}
@@ -397,7 +379,7 @@ void KeyList::getCheckedKeys(QVector<GpgKey> &keys) {
void KeyList::setExcludeKeys(std::initializer_list<QString> key_ids) {
excluded_key_ids.clear();
- for(auto &key_id : key_ids) {
+ for (auto &key_id : key_ids) {
excluded_key_ids.push_back(key_id);
}
}
@@ -407,8 +389,8 @@ void KeyList::setFilter(std::function<bool(const GpgKey &)> filter) {
}
void KeyList::slotDoubleClicked(const QModelIndex &index) {
- if(mAction != nullptr) {
- const auto &key = mCtx->getKeyById(buffered_keys[index.row()].id);
+ if (mAction != nullptr) {
+ const auto key = mCtx->getKeyById(buffered_keys[index.row()].id);
mAction(key, this);
}
diff --git a/src/ui/widgets/SignersPicker.cpp b/src/ui/widgets/SignersPicker.cpp
new file mode 100644
index 00000000..00df5fdd
--- /dev/null
+++ b/src/ui/widgets/SignersPicker.cpp
@@ -0,0 +1,59 @@
+/**
+ * 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.
+ *
+ * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "ui/widgets/SignersPicker.h"
+
+SignersPicker::SignersPicker(GpgME::GpgContext *ctx, QWidget *parent) : mCtx(ctx), QDialog(parent) {
+ auto confirmButton = new QPushButton(tr("Confirm"));
+ connect(confirmButton, SIGNAL(clicked(bool)), this, SLOT(accept()));
+
+ /*Setup KeyList*/
+ mKeyList = new KeyList(mCtx, KeyListRow::ONLY_SECRET_KEY,
+ KeyListColumn::NAME | KeyListColumn::EmailAddress | KeyListColumn::Usage);
+
+ mKeyList->setFilter([](const GpgKey &key) -> bool {
+ if (!GpgME::GpgContext::checkIfKeyCanSign(key)) return false;
+ else return true;
+ });
+
+ mKeyList->slotRefresh();
+
+ auto *vbox2 = new QVBoxLayout();
+ vbox2->addWidget(new QLabel("Select Signer(s): "));
+ vbox2->addWidget(mKeyList);
+ vbox2->addWidget(confirmButton);
+ vbox2->addStretch(0);
+ setLayout(vbox2);
+
+ this->setModal(true);
+ this->setWindowTitle("Signers Picker");
+ this->setMinimumWidth(480);
+ this->show();
+
+
+}
+
+void SignersPicker::getCheckedSigners(QVector<GpgKey> &keys) {
+ mKeyList->getPrivateCheckedKeys(keys);
+}