diff options
author | saturneric <[email protected]> | 2025-04-16 18:05:00 +0000 |
---|---|---|
committer | saturneric <[email protected]> | 2025-04-16 18:05:00 +0000 |
commit | 272cf34f21ab1741d24673a7e3b7c95567a74cec (patch) | |
tree | 4497435e41a8bbdd7560cee57b2c8c4171099951 | |
parent | fix: found bugs (diff) | |
download | GpgFrontend-272cf34f21ab1741d24673a7e3b7c95567a74cec.tar.gz GpgFrontend-272cf34f21ab1741d24673a7e3b7c95567a74cec.zip |
fix: testing and solve bugs found
42 files changed, 612 insertions, 501 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 70e4ed4b..b5f0501a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -457,5 +457,5 @@ message(STATUS "Build C Flags: ${CMAKE_C_FLAGS}") message(STATUS "Build C++ Flags: ${CMAKE_CXX_FLAGS}") # third_party -add_subdirectory(third_party)# source code +add_subdirectory(third_party) # source code add_subdirectory(src) diff --git a/src/core/function/gpg/GpgAbstractKeyGetter.cpp b/src/core/function/gpg/GpgAbstractKeyGetter.cpp index 0b544469..193fec0e 100644 --- a/src/core/function/gpg/GpgAbstractKeyGetter.cpp +++ b/src/core/function/gpg/GpgAbstractKeyGetter.cpp @@ -66,7 +66,7 @@ auto GpgAbstractKeyGetter::GetKey(const QString& key_id) -> GpgAbstractKeyPtr { if (IsKeyGroupID(key_id)) { return kg_.KeyGroup(key_id); } - return key_.GetKeyPtr(key_id); + return key_.GetKeyORSubkeyPtr(key_id); } auto GpgAbstractKeyGetter::GetKeys(const QStringList& key_ids) diff --git a/src/core/function/gpg/GpgAssuanHelper.cpp b/src/core/function/gpg/GpgAssuanHelper.cpp index 8fa311dc..2fa836e5 100644 --- a/src/core/function/gpg/GpgAssuanHelper.cpp +++ b/src/core/function/gpg/GpgAssuanHelper.cpp @@ -28,8 +28,6 @@ #include "GpgAssuanHelper.h" -#include <utility> - #include "core/module/ModuleManager.h" #include "core/utils/GpgUtils.h" diff --git a/src/core/function/gpg/GpgAutomatonHandler.cpp b/src/core/function/gpg/GpgAutomatonHandler.cpp index b2d9d562..33c94436 100644 --- a/src/core/function/gpg/GpgAutomatonHandler.cpp +++ b/src/core/function/gpg/GpgAutomatonHandler.cpp @@ -28,8 +28,6 @@ #include "GpgAutomatonHandler.h" -#include <utility> - #include "core/model/GpgData.h" #include "core/model/GpgKey.h" #include "core/utils/GpgUtils.h" diff --git a/src/core/function/gpg/GpgKeyGetter.cpp b/src/core/function/gpg/GpgKeyGetter.cpp index 86218a94..3419c18d 100644 --- a/src/core/function/gpg/GpgKeyGetter.cpp +++ b/src/core/function/gpg/GpgKeyGetter.cpp @@ -32,9 +32,7 @@ #include <mutex> -#include "core/GpgModel.h" #include "core/function/gpg/GpgContext.h" -#include "core/function/gpg/GpgKeyGroupGetter.h" #include "core/utils/GpgUtils.h" namespace GpgFrontend { @@ -44,48 +42,65 @@ class GpgKeyGetter::Impl : public SingletonFunctionObject<GpgKeyGetter::Impl> { explicit Impl(int channel) : SingletonFunctionObject<GpgKeyGetter::Impl>(channel) {} - auto GetKey(const QString& fpr, bool use_cache) -> GpgKey { + auto GetKeyPtr(const QString& key_id, bool cache) -> GpgKeyPtr { // find in cache first - if (use_cache) { - auto key = get_key_in_cache(fpr); - if (key.IsGood()) return key; + if (cache) { + auto key = get_key_in_cache(key_id); + if (key != nullptr) return qSharedPointerDynamicCast<GpgKey>(key); + + LOG_W() << "get gpg key" << key_id + << "from cache failed, channel: " << GetChannel(); } gpgme_key_t p_key = nullptr; - gpgme_get_key(ctx_.DefaultContext(), fpr.toUtf8(), &p_key, 1); + gpgme_get_key(ctx_.DefaultContext(), key_id.toUtf8(), &p_key, 1); if (p_key == nullptr) { - LOG_W() << "GpgKeyGetter GetKey Private _p_key Null, fpr: " << fpr; - return GetPubkey(fpr, true); + LOG_W() << "GpgKeyGetter GetKey p_key is null, fpr: " << key_id; + return GetPubkeyPtr(key_id, true); } - return GpgKey(std::move(p_key)); + + return QSharedPointer<GpgKey>::create(p_key); + } + + auto GetKey(const QString& key_id, bool cache) -> GpgKey { + auto key = GetKeyPtr(key_id, cache); + + if (key != nullptr) return *key; + return {}; + } + + auto GetPubkey(const QString& key_id, bool cache) -> GpgKey { + auto key = GetKeyPtr(key_id, cache); + + if (key != nullptr) return *key; + return {}; } - auto GetPubkey(const QString& fpr, bool use_cache) -> GpgKey { + auto GetPubkeyPtr(const QString& key_id, bool cache) -> GpgKeyPtr { // find in cache first - if (use_cache) { - auto key = get_key_in_cache(fpr); - if (key.IsGood()) return key; + if (cache) { + auto key = get_key_in_cache(key_id); + if (key != nullptr) return qSharedPointerDynamicCast<GpgKey>(key); + + LOG_W() << "get public gpg key" << key_id + << "from cache failed, channel: " << GetChannel(); } gpgme_key_t p_key = nullptr; - gpgme_get_key(ctx_.DefaultContext(), fpr.toUtf8(), &p_key, 0); - if (p_key == nullptr) - LOG_W() << "GpgKeyGetter GetKey _p_key Null, fpr: " << fpr; - return GpgKey(p_key); - } - - auto GetPubkeyPtr(const QString& fpr, bool use_cache) -> GpgKeyPtr { - auto key = GetPubkey(fpr, use_cache); - if (!key.IsGood()) return nullptr; - return QSharedPointer<GpgKey>::create(key); + gpgme_get_key(ctx_.DefaultContext(), key_id.toUtf8(), &p_key, 0); + if (p_key == nullptr) { + LOG_W() << "GpgKeyGetter GetKey p_key is null, key id: " << key_id; + return nullptr; + } + return QSharedPointer<GpgKey>::create(p_key); } - auto FetchKey() -> GpgKeyList { - if (keys_search_cache_.empty()) { + auto FetchKey() -> GpgKeyPtrList { + if (keys_cache_.empty() || keys_search_cache_.empty()) { FlushKeyCache(); } - auto keys_list = GpgKeyList{}; + auto keys_list = GpgKeyPtrList{}; { // get the lock std::lock_guard<std::mutex> lock(keys_cache_mutex_); @@ -106,7 +121,7 @@ class GpgKeyGetter::Impl : public SingletonFunctionObject<GpgKeyGetter::Impl> { // get the lock std::lock_guard<std::mutex> lock(keys_cache_mutex_); for (const auto& key : keys_cache_) { - keys_list.push_back(QSharedPointer<GpgKey>::create(key)); + keys_list.push_back(key); } } @@ -133,18 +148,25 @@ class GpgKeyGetter::Impl : public SingletonFunctionObject<GpgKeyGetter::Impl> { gpgme_key_t key; while ((err = gpgme_op_keylist_next(ctx_.DefaultContext(), &key)) == GPG_ERR_NO_ERROR) { - auto gpg_key = GpgKey(std::move(key)); + auto g_key = QSharedPointer<GpgKey>::create(key); // detect if the key is in a smartcard // if so, try to get full information using gpgme_get_key() // this maybe a bug in gpgme - if (gpg_key.IsHasCardKey()) { - gpg_key = GetKey(gpg_key.ID(), false); + if (g_key->IsHasCardKey()) { + g_key = GetKeyPtr(g_key->ID(), false); } - keys_cache_.push_back(gpg_key); - keys_search_cache_.insert(gpg_key.ID(), gpg_key); - keys_search_cache_.insert(gpg_key.Fingerprint(), gpg_key); + keys_cache_.push_back(g_key); + keys_search_cache_.insert(g_key->ID(), g_key); + keys_search_cache_.insert(g_key->Fingerprint(), g_key); + + for (const auto& s_key : g_key->SubKeys()) { + if (s_key.ID() == g_key->ID()) continue; + auto p_s_key = QSharedPointer<GpgSubKey>::create(s_key); + keys_search_cache_.insert(s_key.ID(), p_s_key); + keys_search_cache_.insert(s_key.Fingerprint(), p_s_key); + } } } @@ -163,29 +185,25 @@ class GpgKeyGetter::Impl : public SingletonFunctionObject<GpgKeyGetter::Impl> { return keys; } - auto GetKeysCopy(const GpgKeyList& keys) -> GpgKeyList { - // get the lock - std::lock_guard<std::mutex> lock(ctx_mutex_); - auto keys_copy = GpgKeyList{}; - for (const auto& key : keys) keys_copy.push_back(key); - return keys_copy; - } - auto Fetch() -> QContainer<QSharedPointer<GpgKey>> { auto keys = FetchKey(); auto ret = QContainer<QSharedPointer<GpgKey>>(); for (const auto& key : keys) { - ret.append(QSharedPointer<GpgKey>::create(key)); + ret.append(key); } return ret; } - auto GetKeyPtr(const QString& key_id, - bool use_cache) -> QSharedPointer<GpgKey> { - auto key = GetKey(key_id, use_cache); - if (!key.IsGood()) return nullptr; - return QSharedPointer<GpgKey>::create(key); + auto GetKeyORSubkeyPtr(const QString& key_id) -> GpgAbstractKeyPtr { + auto key = get_key_in_cache(key_id); + + if (key != nullptr) return key; + + LOG_W() << "get key" << key_id + << "from cache failed, channel: " << GetChannel(); + + return nullptr; } private: @@ -206,13 +224,13 @@ class GpgKeyGetter::Impl : public SingletonFunctionObject<GpgKeyGetter::Impl> { * @brief cache the keys with key id * */ - QMap<QString, GpgKey> keys_search_cache_; + QMap<QString, GpgAbstractKeyPtr> keys_search_cache_; /** * @brief * */ - QContainer<GpgKey> keys_cache_; + QContainer<GpgKeyPtr> keys_cache_; /** * @brief shared mutex for the keys cache @@ -226,8 +244,9 @@ class GpgKeyGetter::Impl : public SingletonFunctionObject<GpgKeyGetter::Impl> { * @param id * @return GpgKey */ - auto get_key_in_cache(const QString& key_id) -> GpgKey { + auto get_key_in_cache(const QString& key_id) -> GpgAbstractKeyPtr { std::lock_guard<std::mutex> lock(keys_cache_mutex_); + if (keys_search_cache_.find(key_id) != keys_search_cache_.end()) { std::lock_guard<std::mutex> lock(ctx_mutex_); // return a copy of the key in cache @@ -269,13 +288,10 @@ auto GpgKeyGetter::GetKeys(const KeyIdArgsList& ids) -> GpgKeyList { return p_->GetKeys(ids); } -auto GpgKeyGetter::GetKeysCopy(const GpgKeyList& keys) -> GpgKeyList { - return p_->GetKeysCopy(keys); -} - -auto GpgKeyGetter::FetchKey() -> GpgKeyList { return p_->FetchKey(); } +auto GpgKeyGetter::Fetch() -> GpgKeyPtrList { return p_->Fetch(); } -auto GpgKeyGetter::Fetch() -> QContainer<QSharedPointer<GpgKey>> { - return p_->Fetch(); +auto GpgKeyGetter::GetKeyORSubkeyPtr(const QString& key_id) + -> GpgAbstractKeyPtr { + return p_->GetKeyORSubkeyPtr(key_id); } } // namespace GpgFrontend diff --git a/src/core/function/gpg/GpgKeyGetter.h b/src/core/function/gpg/GpgKeyGetter.h index b266bf17..1fe4aeb7 100644 --- a/src/core/function/gpg/GpgKeyGetter.h +++ b/src/core/function/gpg/GpgKeyGetter.h @@ -90,11 +90,13 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyGetter auto GetPubkeyPtr(const QString& key_id, bool use_cache = true) -> GpgKeyPtr; /** - * @brief Get all the keys by receiving a linked list + * @brief Get the Pubkey Ptr object * - * @return KeyLinkListPtr + * @param key_id + * @param use_cache + * @return GpgKeyPtr */ - auto FetchKey() -> GpgKeyList; + auto GetKeyORSubkeyPtr(const QString& key_id) -> GpgAbstractKeyPtr; /** * @brief @@ -117,14 +119,6 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyGetter */ auto GetKeys(const KeyIdArgsList& key_ids) -> GpgKeyList; - /** - * @brief Get the Keys Copy object - * - * @param keys - * @return KeyListPtr - */ - auto GetKeysCopy(const GpgKeyList& keys) -> GpgKeyList; - private: class Impl; SecureUniquePtr<Impl> p_; diff --git a/src/core/function/gpg/GpgKeyGroupGetter.cpp b/src/core/function/gpg/GpgKeyGroupGetter.cpp index 47878414..4d4a18cc 100644 --- a/src/core/function/gpg/GpgKeyGroupGetter.cpp +++ b/src/core/function/gpg/GpgKeyGroupGetter.cpp @@ -76,9 +76,10 @@ void GpgKeyGroupGetter::fetch_key_groups() { LOG_D() << "load raw key group:" << key_group.id << "key ids: " << key_group.key_ids; - key_groups_forest_.insert( - key_group.id, - QSharedPointer<GpgKeyGroupTreeNode>::create(GpgKeyGroup{key_group})); + auto node = + QSharedPointer<GpgKeyGroupTreeNode>::create(GpgKeyGroup{key_group}); + node->key_group->SetKeyGroupGetter(this); + key_groups_forest_.insert(key_group.id, node); } build_gpg_key_group_tree(); @@ -108,30 +109,30 @@ auto GpgKeyGroupGetter::KeyGroup(const QString& id) } void GpgKeyGroupGetter::check_key_group( - const QSharedPointer<GpgKeyGroup>& key_group) { - if (key_group == nullptr || key_group->IsDisabled()) return; + const QSharedPointer<GpgKeyGroupTreeNode>& node) { + if (node == nullptr || node->disabled) return; - for (const auto& key_id : key_group->KeyIds()) { - LOG_D() << "check" << key_id << "of" << key_group->UID(); + for (const auto& key_id : node->KeyIds()) { + assert(key_id != node->key_group->ID()); + if (key_id == node->key_group->ID()) continue; - if (IsKeyGroupID(key_id) || key_id == key_group->ID()) { + if (IsKeyGroupID(key_id)) { if (!key_groups_forest_.contains(key_id)) { - key_group->SetDisabled(true); return; } auto s_node = key_groups_forest_.value(key_id, nullptr); - check_key_group(s_node->key_group); + check_key_group(s_node); if (s_node->key_group->IsDisabled()) { - key_group->SetDisabled(true); + node->disabled = true; return; } } else { auto key = GpgKeyGetter::GetInstance(GetChannel()).GetKeyPtr(key_id); if (key == nullptr || !key->IsHasEncrCap()) { - key_group->SetDisabled(true); + node->disabled = true; return; } } @@ -139,20 +140,23 @@ void GpgKeyGroupGetter::check_key_group( } void GpgKeyGroupGetter::check_all_key_groups() { - for (const auto& node : key_groups_forest_) { - node->key_group->SetDisabled(false); - } + for (const auto& node : key_groups_forest_) node->disabled = false; for (const auto& node : key_groups_forest_) { - auto key_group = node->key_group; - check_key_group(key_group); + check_key_group(node); - LOG_D() << "key group" << key_group->ID() << "ids: " << key_group->KeyIds() - << "status: " << key_group->IsDisabled(); + assert(node->key_group != nullptr); + LOG_D() << "key group" << node->key_group->ID() + << "ids: " << node->key_group->KeyIds() + << "status: " << node->disabled; } } auto GpgKeyGroupGetter::FlushCache() -> bool { + for (const auto& node : key_groups_forest_.values()) { + node->Apply(); + } + check_all_key_groups(); persist_key_groups(); return true; @@ -180,6 +184,7 @@ void GpgKeyGroupGetter::build_gpg_key_group_tree() { void GpgKeyGroupGetter::AddKeyGroup(const GpgKeyGroup& key_group) { auto node = QSharedPointer<GpgKeyGroupTreeNode>::create(key_group); + node->key_group->SetKeyGroupGetter(this); key_groups_forest_.insert(node->key_group->ID(), node); LOG_D() << "add new key group" << key_group.ID() @@ -249,18 +254,7 @@ GpgKeyGroupTreeNode::GpgKeyGroupTreeNode(GpgKeyGroup kg) } } -void GpgKeyGroupTreeNode::Apply() { - QStringList key_ids; - for (const auto& child : children) { - key_ids.push_back(child->key_group->ID()); - } - - for (const auto& key_id : non_key_group_ids) { - key_ids.push_back(key_id); - } - - key_group->SetKeyIds(key_ids); -} +void GpgKeyGroupTreeNode::Apply() { key_group->SetKeyIds(KeyIds()); } auto GpgKeyGroupTreeNode::AddNonKeyGroupKey(const GpgAbstractKeyPtr& key) -> bool { @@ -308,4 +302,19 @@ auto GpgKeyGroupTreeNode::RemoveNonKeyGroupKey(const QString& key) -> bool { Apply(); return true; } + +auto GpgKeyGroupGetter::IsKeyGroupDisabled(const QString& id) -> bool { + if (!key_groups_forest_.contains(id)) return false; + auto node = key_groups_forest_.value(id); + return node->disabled; +} + +auto GpgKeyGroupTreeNode::KeyIds() const -> QStringList { + QStringList ret; + for (const auto& child : children) { + ret.push_back(child->key_group->ID()); + } + ret.append(non_key_group_ids); + return ret; +} } // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/gpg/GpgKeyGroupGetter.h b/src/core/function/gpg/GpgKeyGroupGetter.h index 9eabccde..823fe338 100644 --- a/src/core/function/gpg/GpgKeyGroupGetter.h +++ b/src/core/function/gpg/GpgKeyGroupGetter.h @@ -42,6 +42,7 @@ struct GpgKeyGroupTreeNode { // over take QStringList non_key_group_ids; + bool disabled; /** * @brief Construct a new Gpg Key Group Tree Node object @@ -106,6 +107,13 @@ struct GpgKeyGroupTreeNode { * @return false */ auto RemoveNonKeyGroupKey(const QString& key) -> bool; + + /** + * @brief + * + * @return QStringList + */ + [[nodiscard]] auto KeyIds() const -> QStringList; }; class GPGFRONTEND_CORE_EXPORT GpgKeyGroupGetter @@ -173,6 +181,13 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyGroupGetter */ auto KeyGroup(const QString& id) -> QSharedPointer<GpgKeyGroup>; + /** + * @brief + * + * @param id + */ + auto IsKeyGroupDisabled(const QString& id) -> bool; + private: GpgContext& ctx_ = GpgContext::GetInstance(SingletonFunctionObject::GetChannel()); @@ -203,7 +218,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyGroupGetter * @brief * */ - void check_key_group(const QSharedPointer<GpgKeyGroup>&); + void check_key_group(const QSharedPointer<GpgKeyGroupTreeNode>&); /** * @brief diff --git a/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp b/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp index f84e9b85..1fcda489 100644 --- a/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp +++ b/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp @@ -28,8 +28,7 @@ #include "GpgDecryptResultAnalyse.h" -#include "core/GpgModel.h" -#include "core/function/gpg/GpgKeyGetter.h" +#include "core/function/gpg/GpgAbstractKeyGetter.h" GpgFrontend::GpgDecryptResultAnalyse::GpgDecryptResultAnalyse( int channel, GpgError m_error, GpgDecryptResult m_result) @@ -107,12 +106,13 @@ void GpgFrontend::GpgDecryptResultAnalyse::doAnalyse() { void GpgFrontend::GpgDecryptResultAnalyse::print_recipient( QTextStream &stream, gpgme_recipient_t recipient) { - auto key = GpgFrontend::GpgKeyGetter::GetInstance(GetChannel()) - .GetKey(recipient->keyid); - if (key.IsGood()) { - stream << key.Name(); - if (!key.Comment().isEmpty()) stream << "(" << key.Comment() << ")"; - if (!key.Email().isEmpty()) stream << "<" << key.Email() << ">"; + auto key = + GpgAbstractKeyGetter::GetInstance(GetChannel()).GetKey(recipient->keyid); + + if (key != nullptr) { + stream << key->Name(); + if (!key->Comment().isEmpty()) stream << "(" << key->Comment() << ")"; + if (!key->Email().isEmpty()) stream << "<" << key->Email() << ">"; } else { stream << "<" << tr("unknown") << ">"; setStatus(0); @@ -120,7 +120,17 @@ void GpgFrontend::GpgDecryptResultAnalyse::print_recipient( stream << Qt::endl; - stream << "- " << tr("Key ID") << ": " << recipient->keyid << Qt::endl; + stream << "- " << tr("Key ID") << ": " << recipient->keyid; + if (key != nullptr) { + stream << " (" + << (key->KeyType() == GpgAbstractKeyType::kGPG_SUBKEY + ? tr("Subkey") + : tr("Primary Key")) + << ")"; + } + + stream << Qt::endl; + stream << "- " << tr("Public Key Algo") << ": " << gpgme_pubkey_algo_name(recipient->pubkey_algo) << Qt::endl; stream << "- " << tr("Status") << ": " << gpgme_strerror(recipient->status) diff --git a/src/core/function/result_analyse/GpgSignResultAnalyse.cpp b/src/core/function/result_analyse/GpgSignResultAnalyse.cpp index 262d0692..0cecc96b 100644 --- a/src/core/function/result_analyse/GpgSignResultAnalyse.cpp +++ b/src/core/function/result_analyse/GpgSignResultAnalyse.cpp @@ -28,8 +28,7 @@ #include "GpgSignResultAnalyse.h" -#include "core/GpgModel.h" -#include "core/function/gpg/GpgKeyGetter.h" +#include "core/function/gpg/GpgAbstractKeyGetter.h" #include "core/utils/LocalizedUtils.h" namespace GpgFrontend { @@ -54,66 +53,61 @@ void GpgSignResultAnalyse::doAnalyse() { if (result != nullptr && (result->signatures != nullptr || result->invalid_signers != nullptr)) { stream_ << Qt::endl; - auto *new_sign = result->signatures; + auto *sign = result->signatures; auto index = 0; - while (new_sign != nullptr) { + while (sign != nullptr) { stream_ << "## " << tr("New Signature") << " [" << ++index << "]: " << Qt::endl; stream_ << "- " << tr("Sign Mode") << ": "; - if (new_sign->type == GPGME_SIG_MODE_NORMAL) { + if (sign->type == GPGME_SIG_MODE_NORMAL) { stream_ << tr("Normal"); - } else if (new_sign->type == GPGME_SIG_MODE_CLEAR) { + } else if (sign->type == GPGME_SIG_MODE_CLEAR) { stream_ << tr("Clear"); - } else if (new_sign->type == GPGME_SIG_MODE_DETACH) { + } else if (sign->type == GPGME_SIG_MODE_DETACH) { stream_ << tr("Detach"); } stream_ << Qt::endl; - QString fpr = new_sign->fpr == nullptr ? "" : new_sign->fpr; - auto singer_key = GpgKeyGetter::GetInstance(GetChannel()).GetKey(fpr); - if (singer_key.IsGood()) { - stream_ << "- " << tr("Signed By") << ": " - << singer_key.UIDs().front().GetUID() << Qt::endl; - - auto s_keys = singer_key.SubKeys(); - auto it = std::find_if( - s_keys.begin(), s_keys.end(), - [fpr](const GpgSubKey &k) { return k.Fingerprint() == fpr; }); - - if (it != s_keys.end()) { - auto &subkey = *it; - if (subkey.Fingerprint() != singer_key.Fingerprint()) { - stream_ << "- " << tr("Key ID") << ": " << singer_key.ID() << " (" - << tr("Subkey") << ")" << Qt::endl; - } else { - stream_ << "- " << tr("Key ID") << ": " << singer_key.ID() << " (" - << tr("Primary Key") << ")" << Qt::endl; - } - stream_ << "- " << tr("Key Create Date") << ": " - << QLocale().toString(subkey.CreationTime()) << Qt::endl; + QString fpr = sign->fpr == nullptr ? "" : sign->fpr; + auto sign_key = + GpgAbstractKeyGetter::GetInstance(GetChannel()).GetKey(fpr); + if (sign_key != nullptr) { + stream_ << "- " << tr("Signed By") << ": " << sign_key->UID() + << Qt::endl; + + if (sign_key->KeyType() == GpgAbstractKeyType::kGPG_SUBKEY) { + stream_ << "- " << tr("Key ID") << ": " << sign_key->ID() << " (" + << tr("Subkey") << ")" << Qt::endl; + } else { + stream_ << "- " << tr("Key ID") << ": " << sign_key->ID() << " (" + << tr("Primary Key") << ")" << Qt::endl; } + stream_ << "- " << tr("Key Create Date") << ": " + << QLocale().toString(sign_key->CreationTime()) << Qt::endl; + } else { stream_ << "- " << tr("Signed By") << "(" << tr("Fingerprint") << ")" << ": " << (fpr.isEmpty() ? tr("<unknown>") : fpr) << Qt::endl; } + stream_ << "- " << tr("Public Key Algo") << ": " - << gpgme_pubkey_algo_name(new_sign->pubkey_algo) << Qt::endl; + << gpgme_pubkey_algo_name(sign->pubkey_algo) << Qt::endl; stream_ << "- " << tr("Hash Algo") << ": " - << gpgme_hash_algo_name(new_sign->hash_algo) << Qt::endl; + << gpgme_hash_algo_name(sign->hash_algo) << Qt::endl; stream_ << "- " << tr("Sign Date") << "(" << tr("UTC") << ")" << ": " - << GetUTCDateByTimestamp(new_sign->timestamp) << Qt::endl; + << GetUTCDateByTimestamp(sign->timestamp) << Qt::endl; stream_ << "- " << tr("Sign Date") << "(" << tr("Localized") << ")" - << ": " << GetLocalizedDateByTimestamp(new_sign->timestamp) + << ": " << GetLocalizedDateByTimestamp(sign->timestamp) << Qt::endl; stream_ << Qt::endl << "---------------------------------------" << Qt::endl << Qt::endl; - new_sign = new_sign->next; + sign = sign->next; } auto *invalid_signer = result->invalid_signers; diff --git a/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp b/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp index 09b7da7e..66a607b8 100644 --- a/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp +++ b/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp @@ -28,8 +28,7 @@ #include "GpgVerifyResultAnalyse.h" -#include "core/GpgModel.h" -#include "core/function/gpg/GpgKeyGetter.h" +#include "core/function/gpg/GpgAbstractKeyGetter.h" #include "core/utils/CommonUtils.h" #include "core/utils/LocalizedUtils.h" @@ -200,29 +199,19 @@ auto GpgFrontend::GpgVerifyResultAnalyse::print_signer( QTextStream &stream, GpgSignature sign) -> bool { auto fingerprint = sign.GetFingerprint(); auto key = - GpgFrontend::GpgKeyGetter::GetInstance(GetChannel()).GetKey(fingerprint); - if (key.IsGood()) { - stream << "- " << tr("Signed By") << ": " << key.UIDs().front().GetUID() - << Qt::endl; - - auto s_keys = key.SubKeys(); - auto it = std::find_if(s_keys.begin(), s_keys.end(), - [fingerprint](const GpgSubKey &k) { - return k.Fingerprint() == fingerprint; - }); - - if (it != s_keys.end()) { - auto &s_key = *it; - if (s_key.Fingerprint() != key.Fingerprint()) { - stream << "- " << tr("Key ID") << ": " << key.ID() << " (" - << tr("Subkey") << ")" << Qt::endl; - } else { - stream << "- " << tr("Key ID") << ": " << key.ID() << " (" - << tr("Primary Key") << ")" << Qt::endl; - } - stream << "- " << tr("Key Create Date") << ": " - << QLocale().toString(s_key.CreationTime()) << Qt::endl; + GpgAbstractKeyGetter::GetInstance(GetChannel()).GetKey(fingerprint); + if (key != nullptr) { + stream << "- " << tr("Signed By") << ": " << key->UID() << Qt::endl; + + if (key->KeyType() == GpgAbstractKeyType::kGPG_SUBKEY) { + stream << "- " << tr("Key ID") << ": " << key->ID() << " (" + << tr("Subkey") << ")" << Qt::endl; + } else { + stream << "- " << tr("Key ID") << ": " << key->ID() << " (" + << tr("Primary Key") << ")" << Qt::endl; } + stream << "- " << tr("Key Create Date") << ": " + << QLocale().toString(key->CreationTime()) << Qt::endl; } else { stream_ << "- " << tr("Signed By") << "(" << tr("Fingerprint") << ")" @@ -239,7 +228,8 @@ auto GpgFrontend::GpgVerifyResultAnalyse::print_signer( stream << "- " << tr("Sign Date") << "(" << tr("Localized") << ")" << ": " << QLocale().toString(sign.GetCreateTime()) << Qt::endl; stream << Qt::endl; - return key.IsGood(); + + return key != nullptr; } auto GpgFrontend::GpgVerifyResultAnalyse::GetSignatures() const diff --git a/src/core/model/GpgKeyGroup.cpp b/src/core/model/GpgKeyGroup.cpp index b572deac..13c0d542 100644 --- a/src/core/model/GpgKeyGroup.cpp +++ b/src/core/model/GpgKeyGroup.cpp @@ -28,7 +28,7 @@ #include "core/model/GpgKeyGroup.h" -#include <utility> +#include "core/function/gpg/GpgKeyGroupGetter.h" namespace GpgFrontend { @@ -50,13 +50,15 @@ auto GpgKeyGroup::Email() const -> QString { return email_; } auto GpgKeyGroup::Comment() const -> QString { return comment_; } -auto GpgKeyGroup::Fingerprint() const -> QString { return {}; } +auto GpgKeyGroup::Fingerprint() const -> QString { return ID(); } auto GpgKeyGroup::PublicKeyAlgo() const -> QString { return {}; } auto GpgKeyGroup::Algo() const -> QString { return {}; } -auto GpgKeyGroup::ExpirationTime() const -> QDateTime { return {}; }; +auto GpgKeyGroup::ExpirationTime() const -> QDateTime { + return QDateTime::fromSecsSinceEpoch(0); +}; auto GpgKeyGroup::CreationTime() const -> QDateTime { return creation_time_; }; @@ -75,7 +77,7 @@ auto GpgKeyGroup::IsExpired() const -> bool { return false; } auto GpgKeyGroup::IsRevoked() const -> bool { return false; } auto GpgKeyGroup::IsDisabled() const -> bool { - return key_ids_.isEmpty() || disabled_; + return getter_ == nullptr ? true : getter_->IsKeyGroupDisabled(ID()); } auto GpgKeyGroup::KeyType() const -> GpgAbstractKeyType { @@ -116,5 +118,7 @@ void GpgKeyGroup::SetKeyIds(QStringList key_ids) { key_ids_ = std::move(key_ids); } -void GpgKeyGroup::SetDisabled(bool disabled) { disabled_ = disabled; } +void GpgKeyGroup::SetKeyGroupGetter(GpgKeyGroupGetter *getter) { + getter_ = getter; +} } // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/model/GpgKeyGroup.h b/src/core/model/GpgKeyGroup.h index d3ae8e03..887fd13f 100644 --- a/src/core/model/GpgKeyGroup.h +++ b/src/core/model/GpgKeyGroup.h @@ -33,6 +33,8 @@ namespace GpgFrontend { +class GpgKeyGroupGetter; + /** * @brief * @@ -248,7 +250,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyGroup : public GpgAbstractKey { * @brief Set the Disabled object * */ - void SetDisabled(bool); + void SetKeyGroupGetter(GpgKeyGroupGetter*); private: QString id_; @@ -257,7 +259,8 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyGroup : public GpgAbstractKey { QString comment_; QStringList key_ids_; QDateTime creation_time_; - bool disabled_; + + GpgKeyGroupGetter* getter_ = nullptr; }; } // namespace GpgFrontend diff --git a/src/core/model/GpgKeyTreeModel.cpp b/src/core/model/GpgKeyTreeModel.cpp index a62878c9..92a0f77c 100644 --- a/src/core/model/GpgKeyTreeModel.cpp +++ b/src/core/model/GpgKeyTreeModel.cpp @@ -28,14 +28,12 @@ #include "GpgKeyTreeModel.h" -#include <utility> - #include "core/model/GpgKey.h" #include "core/utils/GpgUtils.h" namespace GpgFrontend { -GpgKeyTreeModel::GpgKeyTreeModel(int channel, const GpgKeyList &keys, +GpgKeyTreeModel::GpgKeyTreeModel(int channel, const GpgAbstractKeyPtrList &keys, Detector checkable_detector, QObject *parent) : QAbstractItemModel(parent), gpg_context_channel_(channel), @@ -165,13 +163,13 @@ auto GpgKeyTreeModel::GetGpgContextChannel() const -> int { return gpg_context_channel_; } -void GpgKeyTreeModel::setup_model_data(const GpgKeyList &keys) { +void GpgKeyTreeModel::setup_model_data(const GpgAbstractKeyPtrList &keys) { auto root = QSharedPointer<GpgKeyTreeItem>::create(nullptr, column_headers_); cached_items_.clear(); for (const auto &key : keys) { auto pi_key = create_gpg_key_tree_items(key); - root->AppendChild(pi_key); + if (pi_key != nullptr) root->AppendChild(pi_key); } std::swap(root_, root); @@ -197,36 +195,39 @@ auto GpgKeyTreeModel::GetAllCheckedKeyIds() -> KeyIdArgsList { return ret; } -auto GpgKeyTreeModel::create_gpg_key_tree_items(const GpgKey &key) +auto GpgKeyTreeModel::create_gpg_key_tree_items(const GpgAbstractKeyPtr &key) -> QSharedPointer<GpgKeyTreeItem> { QVariantList columns; columns << "/"; + if (key->KeyType() != GpgAbstractKeyType::kGPG_KEY) return nullptr; + + auto g_key = qSharedPointerDynamicCast<GpgKey>(key); + QString type; - type += key.IsPrivateKey() ? "pub/sec" : "pub"; - if (key.IsPrivateKey() && !key.IsHasMasterKey()) type += "#"; - if (key.IsHasCardKey()) type += "^"; + type += g_key->IsPrivateKey() ? "pub/sec" : "pub"; + if (g_key->IsPrivateKey() && !g_key->IsHasMasterKey()) type += "#"; + if (g_key->IsHasCardKey()) type += "^"; columns << type; - columns << key.UIDs().front().GetUID(); - columns << key.ID(); + columns << g_key->UIDs().front().GetUID(); + columns << g_key->ID(); - columns << GetUsagesByAbstractKey(&key); - columns << key.PublicKeyAlgo(); - columns << key.Algo(); - columns << QLocale().toString(key.CreationTime(), "yyyy-MM-dd"); + columns << GetUsagesByAbstractKey(key.get()); + columns << g_key->PublicKeyAlgo(); + columns << g_key->Algo(); + columns << QLocale().toString(g_key->CreationTime(), "yyyy-MM-dd"); - auto i_key = QSharedPointer<GpgKeyTreeItem>::create( - QSharedPointer<GpgKey>::create(key), columns); + auto i_key = QSharedPointer<GpgKeyTreeItem>::create(key, columns); i_key->SetEnable(true); i_key->SetCheckable(checkable_detector_(i_key->Key())); cached_items_.push_back(i_key); - for (const auto &s_key : key.SubKeys()) { + for (const auto &s_key : g_key->SubKeys()) { QVariantList columns; columns << "/"; columns << (s_key.IsHasCertCap() ? "primary" : "sub"); - columns << key.UIDs().front().GetUID(); + columns << g_key->UIDs().front().GetUID(); columns << s_key.ID(); columns << GetUsagesByAbstractKey(&s_key); columns << s_key.PublicKeyAlgo(); diff --git a/src/core/model/GpgKeyTreeModel.h b/src/core/model/GpgKeyTreeModel.h index 20b63e01..bc27d2bd 100644 --- a/src/core/model/GpgKeyTreeModel.h +++ b/src/core/model/GpgKeyTreeModel.h @@ -32,7 +32,6 @@ * @brief * */ -#include <utility> #include "core/model/GpgAbstractKey.h" #include "core/model/GpgKey.h" @@ -250,7 +249,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyTreeModel : public QAbstractItemModel { * @param keys * @param parent */ - explicit GpgKeyTreeModel(int channel, const GpgKeyList &keys, + explicit GpgKeyTreeModel(int channel, const GpgAbstractKeyPtrList &keys, Detector checkable, QObject *parent = nullptr); /** @@ -372,7 +371,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyTreeModel : public QAbstractItemModel { * @brief * */ - void setup_model_data(const GpgKeyList &keys); + void setup_model_data(const GpgAbstractKeyPtrList &keys); /** * @brief Create a gpg key tree items object @@ -380,7 +379,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyTreeModel : public QAbstractItemModel { * @param key * @return QSharedPointer<GpgKeyTreeItem> */ - auto create_gpg_key_tree_items(const GpgKey &key) + auto create_gpg_key_tree_items(const GpgAbstractKeyPtr &key) -> QSharedPointer<GpgKeyTreeItem>; }; diff --git a/src/test/core/GpgCoreTestKeyModel.cpp b/src/test/core/GpgCoreTestKeyModel.cpp index 878ea953..1fa7454a 100644 --- a/src/test/core/GpgCoreTestKeyModel.cpp +++ b/src/test/core/GpgCoreTestKeyModel.cpp @@ -183,9 +183,9 @@ TEST_F(GpgCoreTest, GpgKeySignatureTest) { TEST_F(GpgCoreTest, GpgKeyGetterTest) { auto key = GpgKeyGetter::GetInstance(kGpgFrontendDefaultChannel) - .GetKey("9490795B78F8AFE9F93BD09281704859182661FB"); - ASSERT_TRUE(key.IsGood()); - auto keys = GpgKeyGetter::GetInstance(kGpgFrontendDefaultChannel).FetchKey(); + .GetKeyPtr("9490795B78F8AFE9F93BD09281704859182661FB"); + ASSERT_TRUE(key != nullptr); + auto keys = GpgKeyGetter::GetInstance(kGpgFrontendDefaultChannel).Fetch(); EXPECT_GT(keys.size(), 0); ASSERT_TRUE(std::find(keys.begin(), keys.end(), key) != keys.end()); diff --git a/src/ui/UserInterfaceUtils.cpp b/src/ui/UserInterfaceUtils.cpp index e66a775c..7cae0648 100644 --- a/src/ui/UserInterfaceUtils.cpp +++ b/src/ui/UserInterfaceUtils.cpp @@ -184,9 +184,17 @@ void CommonUtils::SlotImportKeys(QWidget *parent, int channel, LOG_D() << "try to import key(s) to channel: " << channel; auto info = GpgKeyImportExporter::GetInstance(channel).ImportKey(GFBuffer(in_buffer)); - emit SignalKeyStatusUpdated(); - (new KeyImportDetailDialog(channel, info, parent)); + auto *connection = new QMetaObject::Connection; + *connection = + connect(UISignalStation::GetInstance(), + &UISignalStation::SignalKeyDatabaseRefreshDone, this, [=]() { + (new KeyImportDetailDialog(channel, info, parent)); + QObject::disconnect(*connection); + delete connection; + }); + + emit SignalKeyStatusUpdated(); } void CommonUtils::SlotImportKeyFromFile(QWidget *parent, int channel) { @@ -332,6 +340,9 @@ void CommonUtils::SlotImportKeyFromKeyServer( .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Network) ->PostTask(new Thread::Task( [=](const DataObjectPtr &data_obj) -> int { + // rate limit + QThread::msleep(200); + // call Module::TriggerEvent( "REQUEST_GET_PUBLIC_KEY_BY_KEY_ID", { @@ -374,8 +385,6 @@ void CommonUtils::SlotImportKeyFromKeyServer( }, QString("key_%1_import_task").arg(key_id))); - // not too fast to hit rate limit - QThread::msleep(200); current_index++; } @@ -480,8 +489,14 @@ void CommonUtils::slot_update_key_from_server_finished( // refresh the key database emit UISignalStation::GetInstance() -> SignalKeyDatabaseRefresh(); - // show details - (new KeyImportDetailDialog(channel, std::move(info), this))->exec(); + auto *connection = new QMetaObject::Connection; + *connection = + connect(UISignalStation::GetInstance(), + &UISignalStation::SignalKeyDatabaseRefreshDone, this, [=]() { + (new KeyImportDetailDialog(channel, info, this)); + QObject::disconnect(*connection); + delete connection; + }); } void CommonUtils::SlotRestartApplication(int code) { diff --git a/src/ui/dialog/ADSKsPicker.cpp b/src/ui/dialog/ADSKsPicker.cpp index 9d9fa4c3..09648355 100644 --- a/src/ui/dialog/ADSKsPicker.cpp +++ b/src/ui/dialog/ADSKsPicker.cpp @@ -28,12 +28,14 @@ #include "ADSKsPicker.h" -#include "core/GpgModel.h" +#include "core/function/gpg/GpgKeyOpera.h" +#include "core/utils/GpgUtils.h" +#include "ui/UISignalStation.h" #include "ui/widgets/KeyTreeView.h" namespace GpgFrontend::UI { -ADSKsPicker::ADSKsPicker(int channel, +ADSKsPicker::ADSKsPicker(int channel, GpgKeyPtr key, const GpgKeyTreeProxyModel::KeyFilter& filter, QWidget* parent) : GeneralDialog(typeid(ADSKsPicker).name(), parent), @@ -47,14 +49,22 @@ ADSKsPicker::ADSKsPicker(int channel, (k->KeyType() == GpgAbstractKeyType::kGPG_SUBKEY && k->IsHasEncrCap())) && filter(k); - })) { + })), + channel_(channel), + key_(std::move(key)) { auto* confirm_button = new QPushButton(tr("Confirm")); auto* cancel_button = new QPushButton(tr("Cancel")); connect(confirm_button, &QPushButton::clicked, this, [=]() { - emit SignalSubkeyChecked(tree_view_->GetAllCheckedSubKey()); + if (tree_view_->GetAllCheckedSubKey().isEmpty()) { + QMessageBox::information(this, tr("No Subkeys Selected"), + tr("Please select at least one s_key.")); + + return; + } + slot_add_adsk(tree_view_->GetAllCheckedSubKey()); + accept(); }); - connect(confirm_button, &QPushButton::clicked, this, &QDialog::accept); connect(cancel_button, &QPushButton::clicked, this, &QDialog::reject); tree_view_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); @@ -88,4 +98,39 @@ ADSKsPicker::ADSKsPicker(int channel, this->activateWindow(); } +void ADSKsPicker::slot_add_adsk(const QContainer<GpgSubKey>& s_keys) { + QContainer<QString> err_sub_key_infos; + for (const auto& s_key : s_keys) { + auto [err, data_object] = + GpgKeyOpera::GetInstance(channel_).AddADSKSync(key_, s_key); + if (CheckGpgError(err) == GPG_ERR_NO_ERROR) continue; + + err_sub_key_infos.append(tr("Key ID: %1 Reason: %2") + .arg(s_key.ID()) + .arg(DescribeGpgErrCode(err).second)); + } + + if (!err_sub_key_infos.isEmpty()) { + QStringList failed_info; + for (const auto& info : err_sub_key_infos) { + failed_info.append(info); + } + QString details = failed_info.join("\n\n"); + + auto* msg_box = new QMessageBox(nullptr); + msg_box->setIcon(QMessageBox::Warning); + msg_box->setWindowTitle(err_sub_key_infos.size() == s_keys.size() + ? tr("Failed") + : tr("Partially Failed")); + msg_box->setText(err_sub_key_infos.size() == s_keys.size() + ? tr("Failed to add all selected subkeys.") + : tr("Some subkeys failed to be added as ADSKs.")); + msg_box->setDetailedText(details); + msg_box->show(); + + return; + } + + emit UISignalStation::GetInstance() -> SignalKeyDatabaseRefresh(); +} } // namespace GpgFrontend::UI diff --git a/src/ui/dialog/ADSKsPicker.h b/src/ui/dialog/ADSKsPicker.h index 59c7b06b..577ac06a 100644 --- a/src/ui/dialog/ADSKsPicker.h +++ b/src/ui/dialog/ADSKsPicker.h @@ -50,16 +50,23 @@ class ADSKsPicker : public GeneralDialog { * * @param parent */ - explicit ADSKsPicker(int channel, + explicit ADSKsPicker(int channel, GpgKeyPtr key, const GpgKeyTreeProxyModel::KeyFilter& filter, QWidget* parent = nullptr); - signals: - void SignalSubkeyChecked(QContainer<GpgSubKey>); + private slots: + /** + * @brief + * + * @param s_keys + */ + void slot_add_adsk(const QContainer<GpgSubKey>& s_keys); private: KeyTreeView* tree_view_; ///< bool accepted_ = false; + int channel_; + GpgKeyPtr key_; }; } // namespace GpgFrontend::UI diff --git a/src/ui/dialog/KeyGroupCreationDialog.cpp b/src/ui/dialog/KeyGroupCreationDialog.cpp index 506c173d..16e34536 100644 --- a/src/ui/dialog/KeyGroupCreationDialog.cpp +++ b/src/ui/dialog/KeyGroupCreationDialog.cpp @@ -46,20 +46,29 @@ KeyGroupCreationDialog::KeyGroupCreationDialog(int channel, QStringList key_ids, email_->setMinimumWidth(240); comment_ = new QLineEdit(); comment_->setMinimumWidth(240); - create_button_ = new QPushButton("Create"); + create_button_ = new QPushButton(tr("Create")); error_label_ = new QLabel(); auto* grid_layout = new QGridLayout(); - grid_layout->addWidget(new QLabel(tr("Name")), 0, 0); - grid_layout->addWidget(new QLabel(tr("Email")), 1, 0); - grid_layout->addWidget(new QLabel(tr("Comment")), 2, 0); - grid_layout->addWidget(name_, 0, 1); - grid_layout->addWidget(email_, 1, 1); - grid_layout->addWidget(comment_, 2, 1); + auto* description_label = new QLabel(tr( + "A Key Group is a collection of keys. It allows you to encrypt data for " + "multiple recipients at once by grouping their public keys together.")); + description_label->setWordWrap(true); + description_label->setStyleSheet("color: gray; font-size: 11px;"); - grid_layout->addWidget(create_button_, 3, 0, 1, 2); - grid_layout->addWidget(error_label_, 4, 0, 1, 2); + grid_layout->addWidget(description_label, 0, 0, 2, 2); + + grid_layout->addWidget(new QLabel(tr("Name")), 2, 0); + grid_layout->addWidget(new QLabel(tr("Email")), 3, 0); + grid_layout->addWidget(new QLabel(tr("Comment")), 4, 0); + + grid_layout->addWidget(name_, 2, 1); + grid_layout->addWidget(email_, 3, 1); + grid_layout->addWidget(comment_, 4, 1); + + grid_layout->addWidget(create_button_, 5, 0, 1, 2); + grid_layout->addWidget(error_label_, 6, 0, 1, 2); connect(create_button_, &QPushButton::clicked, this, &KeyGroupCreationDialog::slot_create_new_uid); @@ -68,8 +77,10 @@ KeyGroupCreationDialog::KeyGroupCreationDialog(int channel, QStringList key_ids, UISignalStation::GetInstance(), &UISignalStation::SignalKeyDatabaseRefresh); + setMinimumHeight(250); + this->setLayout(grid_layout); - this->setWindowTitle(tr("Create New Key Group")); + this->setWindowTitle(tr("New Key Group")); this->setAttribute(Qt::WA_DeleteOnClose, true); this->setModal(true); } diff --git a/src/ui/dialog/KeyGroupManageDialog.cpp b/src/ui/dialog/KeyGroupManageDialog.cpp index cbd70b61..88892ada 100644 --- a/src/ui/dialog/KeyGroupManageDialog.cpp +++ b/src/ui/dialog/KeyGroupManageDialog.cpp @@ -54,7 +54,8 @@ KeyGroupManageDialog::KeyGroupManageDialog( ui_->keyGroupKeyList->Init( channel, KeyMenuAbility::kCOLUMN_FILTER | KeyMenuAbility::kSEARCH_BAR, GpgKeyTableColumn::kTYPE | GpgKeyTableColumn::kNAME | - GpgKeyTableColumn::kEMAIL_ADDRESS | GpgKeyTableColumn::kKEY_ID); + GpgKeyTableColumn::kEMAIL_ADDRESS | GpgKeyTableColumn::kKEY_ID | + GpgKeyTableColumn::kUSAGE); ui_->keyGroupKeyList->AddListGroupTab( tr("Key Group"), "key-group", GpgKeyTableDisplayMode::kPRIVATE_KEY | @@ -78,6 +79,14 @@ KeyGroupManageDialog::KeyGroupManageDialog( }); ui_->keyList->SlotRefresh(); + connect(ui_->keyList, &KeyList::SignalKeyChecked, this, + &KeyGroupManageDialog::slot_set_add_button_state); + connect(ui_->keyGroupKeyList, &KeyList::SignalKeyChecked, this, + &KeyGroupManageDialog::slot_set_remove_button_state); + + ui_->addButton->setDisabled(true); + ui_->removeButton->setDisabled(true); + QTimer::singleShot(200, [=]() { slot_notify_invalid_key_ids(); }); this->setModal(true); @@ -104,6 +113,8 @@ void KeyGroupManageDialog::slot_add_to_key_group() { ui_->keyGroupKeyList->RefreshKeyTable(0); ui_->keyList->RefreshKeyTable(0); + slot_set_add_button_state(); + slot_set_remove_button_state(); if (!failed_keys.isEmpty()) { QStringList failed_ids; @@ -127,6 +138,8 @@ void KeyGroupManageDialog::slot_remove_from_key_group() { ui_->keyGroupKeyList->RefreshKeyTable(0); ui_->keyList->RefreshKeyTable(0); + slot_set_add_button_state(); + slot_set_remove_button_state(); } void KeyGroupManageDialog::slot_notify_invalid_key_ids() { @@ -138,9 +151,7 @@ void KeyGroupManageDialog::slot_notify_invalid_key_ids() { if (key == nullptr) invalid_key_ids.push_back(key_id); } - if (invalid_key_ids.isEmpty()) { - return; - } + if (invalid_key_ids.isEmpty()) return; const QString id_list = invalid_key_ids.join(", "); const auto message = @@ -163,4 +174,13 @@ void KeyGroupManageDialog::slot_notify_invalid_key_ids() { emit UISignalStation::GetInstance() -> SignalKeyDatabaseRefresh(); } + +void KeyGroupManageDialog::slot_set_add_button_state() { + ui_->addButton->setDisabled(ui_->keyList->GetCheckedKeys().isEmpty()); +} + +void KeyGroupManageDialog::slot_set_remove_button_state() { + ui_->removeButton->setDisabled( + ui_->keyGroupKeyList->GetCheckedKeys().isEmpty()); +} } // namespace GpgFrontend::UI diff --git a/src/ui/dialog/KeyGroupManageDialog.h b/src/ui/dialog/KeyGroupManageDialog.h index 66211d28..902bbb59 100644 --- a/src/ui/dialog/KeyGroupManageDialog.h +++ b/src/ui/dialog/KeyGroupManageDialog.h @@ -74,6 +74,18 @@ class KeyGroupManageDialog : public GeneralDialog { */ void slot_notify_invalid_key_ids(); + /** + * @brief + * + */ + void slot_set_add_button_state(); + + /** + * @brief + * + */ + void slot_set_remove_button_state(); + private: QSharedPointer<Ui_KeyGroupManageDialog> ui_; ///< int channel_; diff --git a/src/ui/dialog/import_export/KeyImportDetailDialog.cpp b/src/ui/dialog/import_export/KeyImportDetailDialog.cpp index 24062796..92e45eb6 100644 --- a/src/ui/dialog/import_export/KeyImportDetailDialog.cpp +++ b/src/ui/dialog/import_export/KeyImportDetailDialog.cpp @@ -28,7 +28,7 @@ #include "KeyImportDetailDialog.h" -#include "core/function/gpg/GpgKeyGetter.h" +#include "core/function/gpg/GpgAbstractKeyGetter.h" #include "core/model/GpgImportInformation.h" namespace GpgFrontend::UI { @@ -147,11 +147,13 @@ void KeyImportDetailDialog::create_keys_table() { int row = 0; for (const auto& imp_key : m_result_->imported_keys) { keys_table_->setRowCount(row + 1); - auto key = GpgKeyGetter::GetInstance(current_gpg_context_channel_) + + auto key = GpgAbstractKeyGetter::GetInstance(current_gpg_context_channel_) .GetKey(imp_key.fpr); - if (!key.IsGood()) continue; - keys_table_->setItem(row, 0, new QTableWidgetItem(key.Name())); - keys_table_->setItem(row, 1, new QTableWidgetItem(key.Email())); + if (key == nullptr) continue; + + keys_table_->setItem(row, 0, new QTableWidgetItem(key->Name())); + keys_table_->setItem(row, 1, new QTableWidgetItem(key->Email())); keys_table_->setItem( row, 2, new QTableWidgetItem(get_status_string(imp_key.import_status))); keys_table_->setItem(row, 3, new QTableWidgetItem(imp_key.fpr)); diff --git a/src/ui/dialog/import_export/KeyServerImportDialog.cpp b/src/ui/dialog/import_export/KeyServerImportDialog.cpp index 03ee6c4a..8e01bd4b 100644 --- a/src/ui/dialog/import_export/KeyServerImportDialog.cpp +++ b/src/ui/dialog/import_export/KeyServerImportDialog.cpp @@ -422,10 +422,14 @@ void KeyServerImportDialog::slot_import_finished( // refresh the key database emit SignalKeyImported(); - // show details - (new KeyImportDetailDialog(current_gpg_context_channel_, std::move(info), - this)) - ->exec(); + auto* connection = new QMetaObject::Connection; + *connection = connect( + UISignalStation::GetInstance(), + &UISignalStation::SignalKeyDatabaseRefreshDone, this, [=]() { + (new KeyImportDetailDialog(current_gpg_context_channel_, info, this)); + QObject::disconnect(*connection); + delete connection; + }); } void KeyServerImportDialog::set_loading(bool status) { diff --git a/src/ui/dialog/import_export/KeyUploadDialog.cpp b/src/ui/dialog/import_export/KeyUploadDialog.cpp index 346be765..8abcc8de 100644 --- a/src/ui/dialog/import_export/KeyUploadDialog.cpp +++ b/src/ui/dialog/import_export/KeyUploadDialog.cpp @@ -29,7 +29,6 @@ #include "KeyUploadDialog.h" #include <QtNetwork> -#include <utility> #include "core/function/gpg/GpgKeyImportExporter.h" #include "core/model/SettingsObject.h" diff --git a/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp b/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp index 662ac77a..b182e017 100644 --- a/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp +++ b/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp @@ -30,7 +30,6 @@ #include <cassert> #include <cstddef> -#include <utility> #include "core/function/gpg/GpgKeyOpera.h" #include "core/utils/GpgUtils.h" diff --git a/src/ui/dialog/keypair_details/KeyNewUIDDialog.cpp b/src/ui/dialog/keypair_details/KeyNewUIDDialog.cpp index d05154d5..6a6745da 100644 --- a/src/ui/dialog/keypair_details/KeyNewUIDDialog.cpp +++ b/src/ui/dialog/keypair_details/KeyNewUIDDialog.cpp @@ -28,8 +28,6 @@ #include "KeyNewUIDDialog.h" -#include <utility> - #include "core/function/gpg/GpgUIDOperator.h" #include "ui/UISignalStation.h" diff --git a/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp b/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp index fcdc139e..b5a6c1d2 100644 --- a/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp +++ b/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp @@ -28,8 +28,6 @@ #include "KeyPairDetailTab.h" -#include <utility> - #include "core/function/GlobalSettingStation.h" #include "core/function/gpg/GpgKeyGetter.h" #include "core/model/GpgKey.h" diff --git a/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp b/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp index dddbb545..a06ec835 100644 --- a/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp +++ b/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp @@ -34,6 +34,7 @@ #include "core/function/gpg/GpgKeyOpera.h" #include "core/model/GpgKey.h" #include "core/module/ModuleManager.h" +#include "core/thread/TaskRunnerGetter.h" #include "core/typedef/GpgTypedef.h" #include "core/utils/GpgUtils.h" #include "core/utils/IOUtils.h" @@ -131,8 +132,9 @@ KeyPairOperaTab::KeyPairOperaTab(int channel, GpgKeyPtr key, QWidget* parent) opera_key_box->setLayout(vbox_p_k); m_vbox->addWidget(opera_key_box); // modify owner trust of public key - if (!m_key_->IsPrivateKey()) + if (!m_key_->IsPrivateKey()) { vbox_p_k->addWidget(set_owner_trust_level_button); + } vbox_p_k->addWidget(modify_tofu_button); m_vbox->addStretch(0); @@ -212,37 +214,68 @@ void KeyPairOperaTab::CreateOperaMenu() { rev_cert_opera_menu_->addAction(rev_cert_gen_action); } -void KeyPairOperaTab::slot_export_public_key() { - auto [err, gf_buffer] = - GpgKeyImportExporter::GetInstance(current_gpg_context_channel_) - .ExportKey(m_key_, false, true, false); - if (CheckGpgError(err) != GPG_ERR_NO_ERROR) { - CommonUtils::RaiseMessageBox(this, err); - return; - } +void KeyPairOperaTab::slot_export_key(bool secret, bool ascii, bool shortest, + const QString& type) { + auto* task = new Thread::Task( + [=](const DataObjectPtr& data_object) -> int { + auto [err, gf_buffer] = + GpgKeyImportExporter::GetInstance(current_gpg_context_channel_) + .ExportKey(m_key_, secret, ascii, shortest); + data_object->Swap({err, gf_buffer}); + return 0; + }, + "key_export", TransferParams(), + [=](int ret, const DataObjectPtr& data_object) { + if (ret < 0) { + QMessageBox::critical( + this, tr("Unknown Error"), + tr("Caught unknown error while exporting the key.")); + return; + } - // generate a file name + // generate a file name #if defined(_WIN32) || defined(WIN32) - - auto file_string = m_key_->Name() + "[" + m_key_->Email() + "](" + - m_key_->ID() + ")_pub.asc"; + auto file_name = QString("%1[%2](%3)_%4.asc"); #else - auto file_string = m_key_->Name() + "<" + m_key_->Email() + ">(" + - m_key_->ID() + ")_pub.asc"; + auto file_name = QString("%1<%2[(%3)_%4.asc"); #endif - std::replace(file_string.begin(), file_string.end(), ' ', '_'); - auto file_name = QFileDialog::getSaveFileName( - this, tr("Export Key To File"), file_string, - tr("Key Files") + " (*.asc *.txt);;All Files (*)"); + file_name = + file_name.arg(m_key_->Name(), m_key_->Email(), m_key_->ID(), type); - if (file_name.isEmpty()) return; + if (!data_object->Check<GpgError, GFBuffer>()) return; - if (!WriteFileGFBuffer(file_name, gf_buffer)) { - QMessageBox::critical(this, tr("Export Error"), - tr("Couldn't open %1 for writing").arg(file_name)); - return; - } + auto err = ExtractParams<GpgError>(data_object, 0); + auto gf_buffer = ExtractParams<GFBuffer>(data_object, 1); + + if (CheckGpgError(err) != GPG_ERR_NO_ERROR) { + CommonUtils::RaiseMessageBox(this, err); + return; + } + + file_name.replace(' ', '_'); + + auto filepath = QFileDialog::getSaveFileName( + this, tr("Export Key To File"), file_name, + tr("Key Files") + " (*.asc *.txt);;All Files (*)"); + + if (filepath.isEmpty()) return; + + if (!WriteFileGFBuffer(filepath, gf_buffer)) { + QMessageBox::critical( + this, tr("Export Error"), + tr("Couldn't open %1 for writing").arg(file_name)); + return; + } + }); + + Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_GPG) + ->PostTask(task); +} + +void KeyPairOperaTab::slot_export_public_key() { + slot_export_key(false, true, false, "pub"); } void KeyPairOperaTab::slot_export_short_private_key() { @@ -261,38 +294,9 @@ void KeyPairOperaTab::slot_export_short_private_key() { QMessageBox::Cancel | QMessageBox::Ok); // export key, if ok was clicked - if (ret == QMessageBox::Ok) { - auto [err, gf_buffer] = - GpgKeyImportExporter::GetInstance(current_gpg_context_channel_) - .ExportKey(m_key_, true, true, true); - if (CheckGpgError(err) != GPG_ERR_NO_ERROR) { - CommonUtils::RaiseMessageBox(this, err); - return; - } - - // generate a file name -#if defined(_WIN32) || defined(WIN32) - - auto file_string = m_key_->Name() + "[" + m_key_->Email() + "](" + - m_key_->ID() + ")_short_secret.asc"; -#else - auto file_string = m_key_->Name() + "<" + m_key_->Email() + ">(" + - m_key_->ID() + ")_short_secret.asc"; -#endif - std::replace(file_string.begin(), file_string.end(), ' ', '_'); - - auto file_name = QFileDialog::getSaveFileName( - this, tr("Export Key To File"), file_string, - tr("Key Files") + " (*.asc *.txt);;All Files (*)"); - - if (file_name.isEmpty()) return; + if (ret != QMessageBox::Ok) return; - if (!WriteFileGFBuffer(file_name, gf_buffer)) { - QMessageBox::critical(this, tr("Export Error"), - tr("Couldn't open %1 for writing").arg(file_name)); - return; - } - } + slot_export_key(true, true, false, "short_secret"); } void KeyPairOperaTab::slot_export_private_key() { @@ -313,37 +317,9 @@ void KeyPairOperaTab::slot_export_private_key() { QMessageBox::Cancel | QMessageBox::Ok); // export key, if ok was clicked - if (ret == QMessageBox::Ok) { - auto [err, gf_buffer] = - GpgKeyImportExporter::GetInstance(current_gpg_context_channel_) - .ExportKey(m_key_, true, true, false); - if (CheckGpgError(err) != GPG_ERR_NO_ERROR) { - CommonUtils::RaiseMessageBox(this, err); - return; - } - - // generate a file name -#if defined(_WIN32) || defined(WIN32) - auto file_string = m_key_->Name() + "[" + m_key_->Email() + "](" + - m_key_->ID() + ")_full_secret.asc"; -#else - auto file_string = m_key_->Name() + "<" + m_key_->Email() + ">(" + - m_key_->ID() + ")_full_secret.asc"; -#endif - std::replace(file_string.begin(), file_string.end(), ' ', '_'); - - auto file_name = QFileDialog::getSaveFileName( - this, tr("Export Key To File"), file_string, - tr("Key Files") + " (*.asc *.txt);;All Files (*)"); - - if (file_name.isEmpty()) return; + if (ret != QMessageBox::Ok) return; - if (!WriteFileGFBuffer(file_name, gf_buffer)) { - QMessageBox::critical(this, tr("Export Error"), - tr("Couldn't open %1 for writing").arg(file_name)); - return; - } - } + slot_export_key(true, true, false, "full_secret"); } void KeyPairOperaTab::slot_modify_edit_datetime() { diff --git a/src/ui/dialog/keypair_details/KeyPairOperaTab.h b/src/ui/dialog/keypair_details/KeyPairOperaTab.h index 729a7d74..02566b61 100644 --- a/src/ui/dialog/keypair_details/KeyPairOperaTab.h +++ b/src/ui/dialog/keypair_details/KeyPairOperaTab.h @@ -138,6 +138,17 @@ class KeyPairOperaTab : public QWidget { */ void slot_import_paper_key(); + /** + * @brief + * + * @param secret + * @param ascii + * @param shortest + * @param type + */ + void slot_export_key(bool secret, bool ascii, bool shortest, + const QString& type); + private: int current_gpg_context_channel_; GpgKeyPtr m_key_; ///< diff --git a/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp b/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp index fa0c5c34..90bd3537 100644 --- a/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp +++ b/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp @@ -28,8 +28,6 @@ #include "KeyPairSubkeyTab.h" -#include <utility> - #include "core/function/gpg/GpgKeyGetter.h" #include "core/function/gpg/GpgKeyImportExporter.h" #include "core/function/gpg/GpgKeyManager.h" @@ -291,57 +289,12 @@ void KeyPairSubkeyTab::slot_add_adsk() { except_key_ids.append(s_key.ID()); } - auto* dialog = new ADSKsPicker( - current_gpg_context_channel_, + new ADSKsPicker( + current_gpg_context_channel_, key_, [=](const GpgAbstractKey* key) { return !except_key_ids.contains(key->ID()); }, this); - - connect(dialog, &ADSKsPicker::SignalSubkeyChecked, this, - [=](const QContainer<GpgSubKey>& s_keys) { - if (s_keys.isEmpty()) { - QMessageBox::information(this, tr("No Subkeys Selected"), - tr("Please select at least one s_key.")); - - return; - } - - QContainer<GpgSubKey> err_sub_keys; - for (const auto& s_key : s_keys) { - auto [err, data_object] = - GpgKeyOpera::GetInstance(current_gpg_context_channel_) - .AddADSKSync(key_, s_key); - if (CheckGpgError(err) == GPG_ERR_NO_ERROR) continue; - - err_sub_keys.append(s_key); - } - - if (!err_sub_keys.isEmpty()) { - QStringList failed_info; - for (const auto& s_key : err_sub_keys) { - QString key_id = s_key.ID(); - failed_info << tr("Key ID: %1").arg(key_id); - } - - QString details = failed_info.join("\n\n"); - - QMessageBox msg_box(this); - msg_box.setIcon(QMessageBox::Warning); - msg_box.setWindowTitle(err_sub_keys.size() == s_keys.size() - ? tr("Failed") - : tr("Partially Failed")); - msg_box.setText( - err_sub_keys.size() == s_keys.size() - ? tr("Failed to add all selected subkeys.") - : tr("Some subkeys failed to be added as ADSKs.")); - msg_box.setDetailedText(details); - msg_box.exec(); - } - - emit SignalKeyDatabaseRefresh(); - }); - dialog->show(); } void KeyPairSubkeyTab::slot_refresh_subkey_detail() { diff --git a/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp b/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp index e720b9b0..bc9e422c 100644 --- a/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp +++ b/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp @@ -28,8 +28,6 @@ #include "KeyPairUIDTab.h" -#include <utility> - #include "core/function/gpg/GpgKeyGetter.h" #include "core/function/gpg/GpgKeyManager.h" #include "core/function/gpg/GpgUIDOperator.h" diff --git a/src/ui/dialog/keypair_details/KeySetExpireDateDialog.cpp b/src/ui/dialog/keypair_details/KeySetExpireDateDialog.cpp index b2d8d424..b1a33450 100644 --- a/src/ui/dialog/keypair_details/KeySetExpireDateDialog.cpp +++ b/src/ui/dialog/keypair_details/KeySetExpireDateDialog.cpp @@ -28,8 +28,6 @@ #include "KeySetExpireDateDialog.h" -#include <utility> - #include "core/function/GlobalSettingStation.h" #include "core/function/gpg/GpgKeyOpera.h" #include "core/utils/GpgUtils.h" diff --git a/src/ui/main_window/KeyMgmt.cpp b/src/ui/main_window/KeyMgmt.cpp index cd5a9f05..e3128231 100644 --- a/src/ui/main_window/KeyMgmt.cpp +++ b/src/ui/main_window/KeyMgmt.cpp @@ -121,12 +121,17 @@ KeyMgmt::KeyMgmt(QWidget* parent) setWindowTitle(tr("KeyPair Management")); setMinimumSize(QSize(640, 480)); - key_list_->AddMenuAction(generate_subkey_act_); - key_list_->AddMenuAction(delete_selected_keys_act_); - key_list_->AddSeparator(); - key_list_->AddMenuAction(set_owner_trust_of_key_act_); - key_list_->AddSeparator(); - key_list_->AddMenuAction(show_key_details_act_); + popup_menu_ = new QMenu(this); + + popup_menu_->addAction(generate_subkey_act_); + popup_menu_->addAction(delete_selected_keys_act_); + popup_menu_->addSeparator(); + popup_menu_->addAction(set_owner_trust_of_key_act_); + popup_menu_->addSeparator(); + popup_menu_->addAction(show_key_details_act_); + + connect(key_list_, &KeyList::SignalRequestContextMenu, this, + &KeyMgmt::slot_popup_menu_by_key_list); connect(this, &KeyMgmt::SignalKeyStatusUpdated, UISignalStation::GetInstance(), @@ -292,7 +297,7 @@ void KeyMgmt::create_tool_bars() { QToolBar* key_tool_bar = addToolBar(tr("Key")); key_tool_bar->setObjectName("keytoolbar"); - // genrate key pair + // generate key pair key_tool_bar->addAction(generate_key_pair_act_); key_tool_bar->addSeparator(); @@ -587,13 +592,36 @@ void KeyMgmt::SlotImportKeyPackage() { emit SignalStatusBarChanged(tr("key(s) imported")); emit SignalKeyStatusUpdated(); - auto* dialog = new KeyImportDetailDialog( - key_list_->GetCurrentGpgContextChannel(), - SecureCreateSharedObject<GpgImportInformation>(info), this); - dialog->exec(); + auto* connection = new QMetaObject::Connection; + *connection = connect( + UISignalStation::GetInstance(), + &UISignalStation::SignalKeyDatabaseRefreshDone, this, + [=]() { + (new KeyImportDetailDialog( + key_list_->GetCurrentGpgContextChannel(), + SecureCreateSharedObject<GpgImportInformation>(info), + this)); + QObject::disconnect(*connection); + delete connection; + }); } }); }); } +void KeyMgmt::slot_popup_menu_by_key_list(QContextMenuEvent* event, + KeyTable* key_table) { + if (event == nullptr || key_table == nullptr) return; + + auto keys = key_table->GetSelectedKeys(); + if (keys.isEmpty()) return; + + auto key = keys.front(); + generate_subkey_act_->setDisabled(key->KeyType() != + GpgAbstractKeyType::kGPG_KEY); + set_owner_trust_of_key_act_->setDisabled(key->KeyType() != + GpgAbstractKeyType::kGPG_KEY); + + popup_menu_->exec(event->globalPos()); +} } // namespace GpgFrontend::UI diff --git a/src/ui/main_window/KeyMgmt.h b/src/ui/main_window/KeyMgmt.h index b25cfaaa..c0a8502a 100644 --- a/src/ui/main_window/KeyMgmt.h +++ b/src/ui/main_window/KeyMgmt.h @@ -34,6 +34,7 @@ namespace GpgFrontend::UI { class KeyList; +struct KeyTable; /** * @brief @@ -120,6 +121,10 @@ class KeyMgmt : public GeneralMainWindow { */ void SignalKeyStatusUpdated(); + private slots: + + void slot_popup_menu_by_key_list(QContextMenuEvent* event, KeyTable*); + private: KeyList* key_list_; ///< QMenu* file_menu_{}; ///< @@ -128,6 +133,8 @@ class KeyMgmt : public GeneralMainWindow { QMenu* import_key_menu_{}; ///< QMenu* export_key_menu_{}; /// < + QMenu* popup_menu_; + QAction* open_key_file_act_{}; ///< QAction* export_key_to_file_act_{}; ///< QAction* export_key_as_open_ssh_format_{}; ///< @@ -143,7 +150,7 @@ class KeyMgmt : public GeneralMainWindow { QAction* import_keys_from_key_package_act_{}; ///< QAction* close_act_{}; ///< QAction* show_key_details_act_{}; ///< - QAction* set_owner_trust_of_key_act_{}; + QAction* set_owner_trust_of_key_act_{}; ///< /** * @brief Create a menus object diff --git a/src/ui/main_window/MainWindow.cpp b/src/ui/main_window/MainWindow.cpp index 5ebfbb00..e17dacca 100644 --- a/src/ui/main_window/MainWindow.cpp +++ b/src/ui/main_window/MainWindow.cpp @@ -105,27 +105,36 @@ void MainWindow::Init() noexcept { [=](const QString& message, int timeout) { statusBar()->showMessage(message, timeout); }); - connect(UISignalStation::GetInstance(), - &UISignalStation::SignalMainWindowUpdateBasicOperaMenu, this, - &MainWindow::SlotUpdateCryptoMenuStatus); + connect( + UISignalStation::GetInstance(), + &UISignalStation::SignalMainWindowUpdateBasicOperaMenu, this, + [=](unsigned int mask) { + operations_menu_mask_ = mask; + slot_update_operations_menu_by_checked_keys(operations_menu_mask_); + }); connect(UISignalStation::GetInstance(), &UISignalStation::SignalMainWindowOpenFile, this, &MainWindow::SlotOpenFile); - m_key_list_->AddMenuAction(append_selected_keys_act_); - m_key_list_->AddMenuAction(append_key_create_date_to_editor_act_); - m_key_list_->AddMenuAction(append_key_expire_date_to_editor_act_); - m_key_list_->AddMenuAction(append_key_fingerprint_to_editor_act_); - m_key_list_->AddSeparator(); - m_key_list_->AddMenuAction(copy_mail_address_to_clipboard_act_); - m_key_list_->AddMenuAction(copy_key_default_uid_to_clipboard_act_); - m_key_list_->AddMenuAction(copy_key_id_to_clipboard_act_); - m_key_list_->AddMenuAction(set_owner_trust_of_key_act_); - m_key_list_->AddMenuAction(add_key_2_favourite_act_); - m_key_list_->AddMenuAction(remove_key_from_favourtie_act_); - - m_key_list_->AddSeparator(); - m_key_list_->AddMenuAction(show_key_details_act_); + popup_menu_ = new QMenu(this); + + popup_menu_->addAction(append_selected_keys_act_); + popup_menu_->addAction(append_key_create_date_to_editor_act_); + popup_menu_->addAction(append_key_expire_date_to_editor_act_); + popup_menu_->addAction(append_key_fingerprint_to_editor_act_); + popup_menu_->addSeparator(); + popup_menu_->addAction(copy_mail_address_to_clipboard_act_); + popup_menu_->addAction(copy_key_default_uid_to_clipboard_act_); + popup_menu_->addAction(copy_key_id_to_clipboard_act_); + popup_menu_->addAction(set_owner_trust_of_key_act_); + popup_menu_->addAction(add_key_2_favourite_act_); + popup_menu_->addAction(remove_key_from_favourtie_act_); + + popup_menu_->addSeparator(); + popup_menu_->addAction(show_key_details_act_); + + connect(m_key_list_, &KeyList::SignalRequestContextMenu, this, + &MainWindow::slot_popup_menu_by_key_list); restore_settings(); @@ -139,7 +148,7 @@ void MainWindow::Init() noexcept { // recover unsaved page from cache if it exists recover_editor_unsaved_pages_from_cache(); - slot_update_operations_menu_by_checked_keys(); + slot_update_operations_menu_by_checked_keys(~0); // check if need to open wizard window if (GetSettings().value("wizard/show_wizard", true).toBool()) { @@ -307,4 +316,20 @@ void MainWindow::check_update_at_startup() { Module::TriggerEvent("CHECK_APPLICATION_VERSION"); } } + +void MainWindow::slot_popup_menu_by_key_list(QContextMenuEvent* event, + KeyTable* key_table) { + if (event == nullptr || key_table == nullptr) return; + + const auto key_table_name = key_table->objectName(); + if (key_table_name == "favourite") { + remove_key_from_favourtie_act_->setDisabled(true); + add_key_2_favourite_act_->setDisabled(false); + } else { + remove_key_from_favourtie_act_->setDisabled(false); + add_key_2_favourite_act_->setDisabled(true); + } + + popup_menu_->popup(event->globalPos()); +} } // namespace GpgFrontend::UI diff --git a/src/ui/main_window/MainWindow.h b/src/ui/main_window/MainWindow.h index 6eb4da65..d89356aa 100644 --- a/src/ui/main_window/MainWindow.h +++ b/src/ui/main_window/MainWindow.h @@ -46,6 +46,7 @@ class TextEdit; class InfoBoardWidget; struct GpgOperaContext; struct GpgOperaContextBasement; +struct KeyTable; /** * @brief @@ -121,11 +122,6 @@ class MainWindow : public GeneralMainWindow { public slots: /** - * @details refresh and enable specify crypto-menu actions. - */ - void SlotUpdateCryptoMenuStatus(unsigned int type); - - /** * @details Open a new tab for path */ void SlotOpenFile(const QString& path); @@ -523,11 +519,23 @@ class MainWindow : public GeneralMainWindow { const QContainer<GpgOperaResult>& results); /** + * @details refresh and enable specify crypto-menu actions. + */ + void slot_update_crypto_operations_menu(unsigned int mask); + + /** * @brief * * @param results */ - void slot_update_operations_menu_by_checked_keys(); + void slot_update_operations_menu_by_checked_keys(unsigned int type); + + /** + * @brief + * + * @param event + */ + void slot_popup_menu_by_key_list(QContextMenuEvent* event, KeyTable*); private: /** @@ -771,9 +779,12 @@ class MainWindow : public GeneralMainWindow { InfoBoardWidget* info_board_{}; ///< QMap<QString, QPointer<QAction>> buffered_actions_; + QMenu* popup_menu_; + bool attachment_dock_created_{}; ///< int restart_mode_{0}; ///< bool prohibit_update_checking_ = false; ///< + unsigned int operations_menu_mask_ = ~0; }; } // namespace GpgFrontend::UI diff --git a/src/ui/main_window/MainWindowSlotUI.cpp b/src/ui/main_window/MainWindowSlotUI.cpp index 51de7d23..49958c9f 100644 --- a/src/ui/main_window/MainWindowSlotUI.cpp +++ b/src/ui/main_window/MainWindowSlotUI.cpp @@ -167,8 +167,8 @@ void MainWindow::slot_cut_pgp_header() { void MainWindow::SlotSetRestartNeeded(int mode) { this->restart_mode_ = mode; } -void MainWindow::SlotUpdateCryptoMenuStatus(unsigned int type) { - OperationMenu::OperationType opera_type = type; +void MainWindow::slot_update_crypto_operations_menu(unsigned int mask) { + OperationMenu::OperationType opera_type = mask; // refresh status to disable all verify_act_->setDisabled(true); @@ -346,13 +346,14 @@ void MainWindow::slot_restart_gpg_components(bool) { }); } -void MainWindow::slot_update_operations_menu_by_checked_keys() { +void MainWindow::slot_update_operations_menu_by_checked_keys( + unsigned int mask) { auto keys = m_key_list_->GetCheckedKeys(); - OperationMenu::OperationType type = ~0; + unsigned int temp = ~0; if (keys.isEmpty()) { - type &= ~(OperationMenu::kEncrypt | OperationMenu::kEncryptAndSign | + temp &= ~(OperationMenu::kEncrypt | OperationMenu::kEncryptAndSign | OperationMenu::kSign); } else { @@ -360,15 +361,15 @@ void MainWindow::slot_update_operations_menu_by_checked_keys() { if (key == nullptr || key->IsDisabled()) continue; if (!key->IsHasEncrCap()) { - type &= ~(OperationMenu::kEncrypt | OperationMenu::kEncryptAndSign); + temp &= ~(OperationMenu::kEncrypt | OperationMenu::kEncryptAndSign); } if (!key->IsHasSignCap()) { - type &= ~(OperationMenu::kSign); + temp &= ~(OperationMenu::kSign); } } } - SlotUpdateCryptoMenuStatus(type); + slot_update_crypto_operations_menu(operations_menu_mask_ & mask & temp); } } // namespace GpgFrontend::UI diff --git a/src/ui/main_window/MainWindowUI.cpp b/src/ui/main_window/MainWindowUI.cpp index 26c3a8ad..41463b7a 100644 --- a/src/ui/main_window/MainWindowUI.cpp +++ b/src/ui/main_window/MainWindowUI.cpp @@ -611,7 +611,7 @@ void MainWindow::create_dock_windows() { view_menu_->addAction(info_board_dock_->toggleViewAction()); connect(m_key_list_, &KeyList::SignalKeyChecked, this, - &MainWindow::slot_update_operations_menu_by_checked_keys); + [=]() { slot_update_operations_menu_by_checked_keys(~0); }); } } // namespace GpgFrontend::UI diff --git a/src/ui/widgets/KeyList.cpp b/src/ui/widgets/KeyList.cpp index 53adb316..dfabe885 100644 --- a/src/ui/widgets/KeyList.cpp +++ b/src/ui/widgets/KeyList.cpp @@ -222,7 +222,6 @@ void KeyList::init() { ui_->columnTypeButton->setMenu(column_type_menu); ui_->keyGroupTab->clear(); - popup_menu_ = new QMenu(this); auto forbid_all_gnupg_connection = GetSettings() @@ -409,37 +408,11 @@ void KeyList::contextMenuEvent(QContextMenuEvent* event) { return; } - QString current_tab_widget_obj_name = - ui_->keyGroupTab->widget(ui_->keyGroupTab->currentIndex())->objectName(); - if (current_tab_widget_obj_name == "favourite") { - auto actions = popup_menu_->actions(); - for (QAction* action : actions) { - if (action->data().toString() == "remove_key_from_favourtie_action") { - action->setVisible(true); - } else if (action->data().toString() == "add_key_2_favourite_action") { - action->setVisible(false); - } - } - } else { - auto actions = popup_menu_->actions(); - for (QAction* action : actions) { - if (action->data().toString() == "remove_key_from_favourtie_action") { - action->setVisible(false); - } else if (action->data().toString() == "add_key_2_favourite_action") { - action->setVisible(true); - } - } - } - if (key_table->GetRowSelected() >= 0) { - popup_menu_->exec(event->globalPos()); + emit SignalRequestContextMenu(event, key_table); } } -void KeyList::AddSeparator() { popup_menu_->addSeparator(); } - -void KeyList::AddMenuAction(QAction* act) { popup_menu_->addAction(act); } - void KeyList::dropEvent(QDropEvent* event) { auto* dialog = new QDialog(); @@ -501,9 +474,17 @@ void KeyList::import_keys(const QByteArray& in_buffer) { LOG_D() << "importing keys to channel:" << current_gpg_context_channel_; auto result = GpgKeyImportExporter::GetInstance(current_gpg_context_channel_) .ImportKey(GFBuffer(in_buffer)); - emit SignalRefreshDatabase(); - (new KeyImportDetailDialog(current_gpg_context_channel_, result, this)); + auto* connection = new QMetaObject::Connection; + *connection = connect( + UISignalStation::GetInstance(), + &UISignalStation::SignalKeyDatabaseRefreshDone, this, [=]() { + new KeyImportDetailDialog(current_gpg_context_channel_, result, this); + QObject::disconnect(*connection); + delete connection; + }); + + emit SignalRefreshDatabase(); } auto KeyList::GetSelectedKey() -> GpgAbstractKeyPtr { @@ -529,10 +510,8 @@ auto KeyList::GetSelectedGpgKeys() -> GpgKeyPtrList { } void KeyList::slot_sync_with_key_server() { - auto target_keys = GetCheckedPublicKey(); - - KeyIdArgsList key_ids; - if (target_keys.empty()) { + auto keys = GetCheckedPublicKey(); + if (keys.empty()) { QMessageBox::StandardButton const reply = QMessageBox::question( this, QCoreApplication::tr("Sync All Public Key"), QCoreApplication::tr("You have not checked any public keys that you " @@ -542,32 +521,25 @@ void KeyList::slot_sync_with_key_server() { if (reply == QMessageBox::No) return; - target_keys = model_->GetAllKeys(); - } - - for (auto& key : target_keys) { - if (key->KeyType() != GpgAbstractKeyType::kGPG_KEY) continue; - key_ids.push_back(key->ID()); + keys = model_->GetAllKeys(); } + auto key_ids = ConvertKey2GpgKeyIdList(current_gpg_context_channel_, keys); if (key_ids.empty()) return; ui_->refreshKeyListButton->setDisabled(true); ui_->syncButton->setDisabled(true); emit SignalRefreshStatusBar(tr("Syncing Key List..."), 3000); + CommonUtils::SlotImportKeyFromKeyServer( current_gpg_context_channel_, key_ids, [=](const QString& key_id, const QString& status, size_t current_index, size_t all_index) { - auto key = GpgKeyGetter::GetInstance(current_gpg_context_channel_) - .GetKey(key_id); - assert(key.IsGood()); - auto status_str = tr("Sync [%1/%2] %3 %4") .arg(current_index) .arg(all_index) - .arg(key.UIDs().front().GetUID()) + .arg(key_id) .arg(status); emit SignalRefreshStatusBar(status_str, 1500); diff --git a/src/ui/widgets/KeyList.h b/src/ui/widgets/KeyList.h index 0b0b9be6..bb48c63b 100644 --- a/src/ui/widgets/KeyList.h +++ b/src/ui/widgets/KeyList.h @@ -135,19 +135,6 @@ class KeyList : public QWidget { void SetColumnWidth(int row, int size); /** - * @brief - * - * @param act - */ - void AddMenuAction(QAction* act); - - /** - * @brief - * - */ - void AddSeparator(); - - /** * @brief Get the Checked Keys object * * @return QStringList @@ -288,6 +275,12 @@ class KeyList : public QWidget { */ void SignalKeyChecked(); + /** + * @brief + * + */ + void SignalRequestContextMenu(QContextMenuEvent* event, KeyTable*); + protected: /** * @brief @@ -326,7 +319,6 @@ class KeyList : public QWidget { private: std::shared_ptr<Ui_KeyList> ui_; ///< - QMenu* popup_menu_{}; ///< std::function<void(const GpgKey&, QWidget*)> m_action_ = nullptr; ///< int current_gpg_context_channel_; KeyMenuAbility menu_ability_ = KeyMenuAbility::kALL; ///< diff --git a/src/ui/widgets/KeyTreeView.cpp b/src/ui/widgets/KeyTreeView.cpp index 46cfa2db..a6fb23bf 100644 --- a/src/ui/widgets/KeyTreeView.cpp +++ b/src/ui/widgets/KeyTreeView.cpp @@ -28,9 +28,7 @@ #include "ui/widgets/KeyTreeView.h" -#include <utility> - -#include "core/function/gpg/GpgKeyGetter.h" +#include "core/function/gpg/GpgAbstractKeyGetter.h" #include "ui/UISignalStation.h" #include "ui/UserInterfaceUtils.h" #include "ui/model/GpgKeyTreeProxyModel.h" @@ -41,7 +39,7 @@ KeyTreeView::KeyTreeView(QWidget* parent) : QTreeView(parent), channel_(kGpgFrontendDefaultChannel), model_(QSharedPointer<GpgKeyTreeModel>::create( - channel_, GpgKeyGetter::GetInstance(channel_).FetchKey(), + channel_, GpgAbstractKeyGetter::GetInstance(channel_).Fetch(), [](auto) { return false; }, this)), proxy_model_( model_, GpgKeyTreeDisplayMode::kALL, [](auto) { return false; }, @@ -56,7 +54,7 @@ KeyTreeView::KeyTreeView(int channel, : QTreeView(parent), channel_(channel), model_(QSharedPointer<GpgKeyTreeModel>::create( - channel_, GpgKeyGetter::GetInstance(channel_).FetchKey(), + channel_, GpgAbstractKeyGetter::GetInstance(channel_).Fetch(), checkable_detector, this)), proxy_model_(model_, GpgKeyTreeDisplayMode::kALL, std::move(filter), this) { @@ -120,7 +118,7 @@ void KeyTreeView::init() { connect(UISignalStation::GetInstance(), &UISignalStation::SignalKeyDatabaseRefresh, this, [=] { model_ = QSharedPointer<GpgKeyTreeModel>::create( - channel_, GpgKeyGetter::GetInstance(channel_).FetchKey(), + channel_, GpgAbstractKeyGetter::GetInstance(channel_).Fetch(), [](auto) { return false; }, this); proxy_model_.setSourceModel(model_.get()); proxy_model_.invalidate(); @@ -138,7 +136,7 @@ void KeyTreeView::SetChannel(int channel) { channel_ = channel; init_ = false; model_ = QSharedPointer<GpgKeyTreeModel>::create( - channel_, GpgKeyGetter::GetInstance(channel_).FetchKey(), + channel_, GpgAbstractKeyGetter::GetInstance(channel_).Fetch(), [](auto) { return false; }, this); proxy_model_.setSourceModel(model_.get()); proxy_model_.invalidate(); |