diff options
author | saturneric <[email protected]> | 2024-07-31 06:13:26 +0000 |
---|---|---|
committer | saturneric <[email protected]> | 2024-07-31 06:13:26 +0000 |
commit | 081147d65fcb0a20818bbfb43f6ec4f5ddf59581 (patch) | |
tree | f6ec05666acb98da46b4cb0dfc0871225f4ad388 /src | |
parent | fix: dealing with unknown compiler (diff) | |
download | GpgFrontend-081147d65fcb0a20818bbfb43f6ec4f5ddf59581.tar.gz GpgFrontend-081147d65fcb0a20818bbfb43f6ec4f5ddf59581.zip |
fix: addressing some of the significant deficiencies identified
Diffstat (limited to 'src')
30 files changed, 659 insertions, 232 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ddbc0fae..08b6e3a1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -569,6 +569,12 @@ endif() # if only build sdk if(STABLE_BUILD_ONLY_SDK) include(GNUInstallDirs) + + if(INSTALL_TO_MODULES_REPO) + set(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/modules/sdk/${CMAKE_PROJECT_VERSION}") + message(STATUS "Set CMake Install Prefix for Cooperation: ${CMAKE_INSTALL_PREFIX}") + endif() + set(GPGFRONTEND_SDK_INSTALL_LIBRARIES gpgfrontend_module_sdk) @@ -584,6 +590,11 @@ endif() if(STABLE_BUILD_FULL_SDK) include(GNUInstallDirs) + if(INSTALL_TO_MODULES_REPO) + set(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/modules/sdk/${CMAKE_PROJECT_VERSION}") + message(STATUS "Set CMake Install Prefix for Cooperation: ${CMAKE_INSTALL_PREFIX}") + endif() + set(GPGFRONTEND_SDK_INSTALL_LIBRARIES gpgfrontend_core gpgfrontend_ui diff --git a/src/app.cpp b/src/app.cpp index aac9e2cc..0ba65117 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -73,13 +73,17 @@ auto StartApplication(const GFCxtWPtr& p_ctx) -> int { // after that load ui totally GpgFrontend::UI::InitGpgFrontendUI(app); + // check and waiting for condition + GpgFrontend::UI::WaitingAllInitializationFinished(); + + // load module's translations + GpgFrontend::UI::InitModulesTranslations(); + // finally create main window return_from_event_loop_code = GpgFrontend::UI::RunGpgFrontendUI(app); - restart_count++; - } while (return_from_event_loop_code == GpgFrontend::kRestartCode && - restart_count < 99); + restart_count++ < 99); // first should shutdown the module system GpgFrontend::Module::ShutdownGpgFrontendModules(); diff --git a/src/core/GpgCoreInit.cpp b/src/core/GpgCoreInit.cpp index 1a00049c..3f738835 100644 --- a/src/core/GpgCoreInit.cpp +++ b/src/core/GpgCoreInit.cpp @@ -289,36 +289,36 @@ void InitGpgFrontendCore(CoreInitArgs args) { return; } - auto* task = new Thread::Task( - [args, gnupg_install_fs_path](const DataObjectPtr&) -> int { - auto settings = GlobalSettingStation::GetInstance().GetSettings(); - // read settings from config file - auto forbid_all_gnupg_connection = - settings.value("network/forbid_all_gnupg_connection", false) - .toBool(); - - auto auto_import_missing_key = - settings.value("network/auto_import_missing_key", false).toBool(); - - auto use_custom_key_database_path = - settings.value("gnupg/use_custom_key_database_path", false) - .toBool(); - - auto custom_key_database_path = - settings.value("gnupg/custom_key_database_path", QString{}) - .toString(); - - auto custom_gnupg_install_path = - settings.value("gnupg/custom_gnupg_install_path", QString{}) - .toString(); - - auto use_pinentry_as_password_input_dialog = - settings - .value( - "gnupg/use_pinentry_as_password_input_dialog", - QString::fromLocal8Bit(qgetenv("container")) != "flatpak") - .toBool(); + auto settings = GlobalSettingStation::GetInstance().GetSettings(); + + // read settings from config file + auto forbid_all_gnupg_connection = + settings.value("network/forbid_all_gnupg_connection", false).toBool(); + + auto auto_import_missing_key = + settings.value("network/auto_import_missing_key", false).toBool(); + + auto use_custom_key_database_path = + settings.value("gnupg/use_custom_key_database_path", false).toBool(); + + auto custom_key_database_path = + settings.value("gnupg/custom_key_database_path", QString{}).toString(); + + auto custom_gnupg_install_path = + settings.value("gnupg/custom_gnupg_install_path", QString{}).toString(); + auto use_pinentry_as_password_input_dialog = + settings + .value("gnupg/use_pinentry_as_password_input_dialog", + QString::fromLocal8Bit(qgetenv("container")) != "flatpak") + .toBool(); + + // try to restart all components + auto restart_all_gnupg_components_on_start = + settings.value("gnupg/restart_gpg_agent_on_start", false).toBool(); + + auto* task = new Thread::Task( + [=](const DataObjectPtr&) -> int { // key database path QString key_database_fs_path; @@ -390,15 +390,10 @@ void InitGpgFrontendCore(CoreInitArgs args) { Module::UpsertRTValue("core", "env.state.basic", 1); CoreSignalStation::GetInstance()->SignalGoodGnupgEnv(); - // try to restart all components - auto restart_all_gnupg_components_on_start = - settings.value("gnupg/restart_gpg_agent_on_start", false).toBool(); - if (restart_all_gnupg_components_on_start) { GpgAdvancedOperator::RestartGpgComponents(); } - Module::UpsertRTValue("core", "env.state.all", 1); return 0; }, "core_init_task"); @@ -414,4 +409,47 @@ void InitGpgFrontendCore(CoreInitArgs args) { ->PostTask(task); } +void StartMonitorCoreInitializationStatus() { + auto* task = new Thread::Task( + [=](const DataObjectPtr&) -> int { + for (;;) { + if (Module::RetrieveRTValueTypedOrDefault<>("core", "env.state.basic", + 0)) { + break; + } + + LOG_D() << "monitor: core env is still initializing, waiting..."; + QThread::msleep(15); + } + + // waiting for module first + for (;;) { + if (Module::ModuleManager::GetInstance().IsAllModulesRegistered()) + break; + + LOG_D() << "monitor: some modules are still going to be registered, " + "waiting..."; + QThread::msleep(15); + } + LOG_D() << "monitor: good, all module are registered."; + + LOG_D() + << "monitor: core is fully initialized, sending signal to ui..."; + Module::UpsertRTValue("core", "env.state.all", 1); + CoreSignalStation::GetInstance()->SignalCoreFullyLoaded(); + return 0; + }, + "waiting_core_init_task"); + + QObject::connect(task, &Thread::Task::SignalTaskEnd, [=]() { + LOG_D() << "monitor task ended, call back to main thead."; + }); + + // start the thread to check ctx and gnupg state + // it may take a few seconds or minutes + GpgFrontend::Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_External_Process) + ->PostTask(task); +} + } // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/GpgCoreInit.h b/src/core/GpgCoreInit.h index 203fd4dc..dd60578a 100644 --- a/src/core/GpgCoreInit.h +++ b/src/core/GpgCoreInit.h @@ -49,4 +49,9 @@ void GPGFRONTEND_CORE_EXPORT DestroyGpgFrontendCore(); */ void GPGFRONTEND_CORE_EXPORT InitGpgFrontendCore(CoreInitArgs); +/** + * @brief + * + */ +void GPGFRONTEND_CORE_EXPORT StartMonitorCoreInitializationStatus(); } // namespace GpgFrontend diff --git a/src/core/GpgFrontendCore.h b/src/core/GpgFrontendCore.h index 1d5ae29f..a632966e 100644 --- a/src/core/GpgFrontendCore.h +++ b/src/core/GpgFrontendCore.h @@ -46,10 +46,21 @@ Q_DECLARE_LOGGING_CATEGORY(core) #define LOG_E() qCCritical(core) #define LOG_F() qCFatal(core) +#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) +#define LOG_F(...) qCFatal(core) +#else +#define LOG_F(...) qFatal() +#endif + #define FLOG_D(...) qCDebug(core, __VA_ARGS__) #define FLOG_I(...) qCInfo(core, __VA_ARGS__) #define FLOG_W(...) qCWarning(core, __VA_ARGS__) #define FLOG_E(...) qCCritical(core, __VA_ARGS__) + +#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) #define FLOG_F(...) qCFatal(core, __VA_ARGS__) +#else +#define FLOG_F(...) qFatal(__VA_ARGS__) +#endif #endif
\ No newline at end of file diff --git a/src/core/function/CoreSignalStation.h b/src/core/function/CoreSignalStation.h index 1b7c3fa2..a5bea44a 100644 --- a/src/core/function/CoreSignalStation.h +++ b/src/core/function/CoreSignalStation.h @@ -69,6 +69,12 @@ class GPGFRONTEND_CORE_EXPORT CoreSignalStation : public QObject { * */ void SignalGoodGnupgEnv(); + + /** + * @brief + * + */ + void SignalCoreFullyLoaded(); }; } // namespace GpgFrontend diff --git a/src/core/function/SecureMemoryAllocator.cpp b/src/core/function/SecureMemoryAllocator.cpp index cb2249c9..c24e13f2 100644 --- a/src/core/function/SecureMemoryAllocator.cpp +++ b/src/core/function/SecureMemoryAllocator.cpp @@ -34,11 +34,13 @@ namespace GpgFrontend { auto SecureMemoryAllocator::Allocate(std::size_t size) -> void* { auto* addr = malloc(size); + if (addr == nullptr) FLOG_F("malloc failed!"); return addr; } auto SecureMemoryAllocator::Reallocate(void* ptr, std::size_t size) -> void* { auto* addr = realloc(ptr, size); + if (addr == nullptr) FLOG_F("realloc failed!"); return addr; } @@ -50,11 +52,13 @@ void SecureMemoryAllocator::Deallocate(void* p) { free(p); } auto SecureMemoryAllocator::Allocate(std::size_t size) -> void* { auto* addr = mi_malloc(size); + if (addr == nullptr) FLOG_F("malloc failed!"); return addr; } auto SecureMemoryAllocator::Reallocate(void* ptr, std::size_t size) -> void* { auto* addr = mi_realloc(ptr, size); + if (addr == nullptr) FLOG_F("realloc memory failed!"); return addr; } diff --git a/src/core/function/gpg/GpgContext.cpp b/src/core/function/gpg/GpgContext.cpp index a4757d7f..2d9c5992 100644 --- a/src/core/function/gpg/GpgContext.cpp +++ b/src/core/function/gpg/GpgContext.cpp @@ -110,7 +110,7 @@ class GpgContext::Impl { } res += gpgme_io_write(fd, "\n", 1); - return res == pass_size + 1 ? 0 : gpgme_error_from_errno(GPG_ERR_CANCELED); + return res == pass_size + 1 ? 0 : GPG_ERR_CANCELED; } static auto CustomPassphraseCb(void *hook, const char *uid_hint, @@ -143,13 +143,18 @@ class GpgContext::Impl { [&passphrase, &looper](Module::EventIdentifier i, Module::Event::ListenerIdentifier ei, Module::Event::Params p) { - passphrase = p["passphrase"]; + if (p["ret"] == "0") passphrase = p["passphrase"]; looper.quit(); }); looper.exec(); ResetCacheValue("PinentryContext"); + LOG_D() << "passphrase size:" << passphrase.size(); + + // empty passphrase is not allowed + if (passphrase.isEmpty()) return GPG_ERR_CANCELED; + auto pass_bytes = passphrase.toLatin1(); auto pass_size = pass_bytes.size(); const auto *p_pass_bytes = pass_bytes.constData(); @@ -166,7 +171,7 @@ class GpgContext::Impl { } res += gpgme_io_write(fd, "\n", 1); - return res == pass_size + 1 ? 0 : gpgme_error_from_errno(GPG_ERR_CANCELED); + return res == pass_size + 1 ? 0 : GPG_ERR_CANCELED; } static auto TestStatusCb(void *hook, const char *keyword, diff --git a/src/core/function/gpg/GpgKeyOpera.cpp b/src/core/function/gpg/GpgKeyOpera.cpp index d501acbc..332ed1b3 100644 --- a/src/core/function/gpg/GpgKeyOpera.cpp +++ b/src/core/function/gpg/GpgKeyOpera.cpp @@ -258,7 +258,7 @@ void GpgKeyOpera::GenerateSubkey(const GpgKey& key, auto err = gpgme_op_createsubkey(ctx.DefaultContext(), static_cast<gpgme_key_t>(key), - algo.toUtf8(), 0, expires, flags); + algo.toLatin1(), 0, expires, flags); if (CheckGpgError(err) != GPG_ERR_NO_ERROR) { data_object->Swap({GpgGenerateKeyResult{}}); return err; @@ -297,7 +297,7 @@ auto GpgKeyOpera::GenerateSubkeySync(const GpgKey& key, auto err = gpgme_op_createsubkey(ctx.DefaultContext(), static_cast<gpgme_key_t>(key), - algo.toUtf8(), 0, expires, flags); + algo.toLatin1(), 0, expires, flags); if (CheckGpgError(err) != GPG_ERR_NO_ERROR) { data_object->Swap({GpgGenerateKeyResult{}}); diff --git a/src/core/model/GpgGenKeyInfo.cpp b/src/core/model/GpgGenKeyInfo.cpp index 0d0ab239..3955a7cd 100644 --- a/src/core/model/GpgGenKeyInfo.cpp +++ b/src/core/model/GpgGenKeyInfo.cpp @@ -30,6 +30,9 @@ #include <cassert> +#include "module/ModuleManager.h" +#include "utils/CommonUtils.h" + namespace GpgFrontend { void GenKeyInfo::SetAlgo(const QString &t_algo_args) { @@ -40,6 +43,7 @@ void GenKeyInfo::SetAlgo(const QString &t_algo_args) { if (!this->subkey_) { this->SetAllowCertification(true); + } else { this->SetAllowCertification(false); } @@ -64,6 +68,7 @@ void GenKeyInfo::SetAlgo(const QString &t_algo_args) { * Recently, NIST has declared 512-bit keys obsolete: * now, DSA is available in 1024, 2048 and 3072-bit lengths. */ + SetAllowEncryption(false); allow_change_encryption_ = false; @@ -73,11 +78,10 @@ void GenKeyInfo::SetAlgo(const QString &t_algo_args) { SetKeyLength(2048); } else if (algo_args == "elg") { /** - * Algorithm (DSA) as a government standard for digital signatures. - * Originally, it supported key lengths between 512 and 1024 bits. - * Recently, NIST has declared 512-bit keys obsolete: - * now, DSA is available in 1024, 2048 and 3072-bit lengths. + * GnuPG supports the Elgamal asymmetric encryption algorithm in key lengths + * ranging from 1024 to 4096 bits. */ + SetAllowEncryption(true); SetAllowAuthentication(false); @@ -86,19 +90,12 @@ void GenKeyInfo::SetAlgo(const QString &t_algo_args) { SetAllowSigning(false); allow_change_signing_ = false; - SetAllowCertification(false); - allow_change_certification_ = false; - suggest_min_key_size_ = 1024; suggest_max_key_size_ = 4096; suggest_size_addition_step_ = 1024; SetKeyLength(3072); } else if (algo_args == "ed25519") { - /** - * GnuPG supports the Elgamal asymmetric encryption algorithm in key lengths - * ranging from 1024 to 4096 bits. - */ SetAllowEncryption(false); allow_change_encryption_ = false; @@ -106,18 +103,45 @@ void GenKeyInfo::SetAlgo(const QString &t_algo_args) { suggest_max_key_size_ = -1; suggest_size_addition_step_ = -1; SetKeyLength(-1); - } else if (algo_args == "cv25519" || algo_args == "nistp256" || - algo_args == "nistp384" || algo_args == "nistp521" || - algo_args == "brainpoolp256r1" || algo_args == "brainpoolp384r1" || - algo_args == "brainpoolp512r1") { + } else if (algo_args == "cv25519" || algo_args == "x448") { SetAllowAuthentication(false); allow_change_authentication_ = false; SetAllowSigning(false); allow_change_signing_ = false; - SetAllowCertification(false); - allow_change_certification_ = false; + suggest_min_key_size_ = -1; + suggest_max_key_size_ = -1; + suggest_size_addition_step_ = -1; + SetKeyLength(-1); + } else if (algo_args == "ed448") { + SetAllowEncryption(false); + allow_change_encryption_ = false; + + // why not support signing? test later... + SetAllowSigning(false); + allow_change_signing_ = false; + + suggest_min_key_size_ = -1; + suggest_max_key_size_ = -1; + suggest_size_addition_step_ = -1; + SetKeyLength(-1); + } else if (algo_args == "nistp256" || algo_args == "nistp384" || + algo_args == "nistp521" || algo_args == "brainpoolp256r1" || + algo_args == "brainpoolp384r1" || algo_args == "brainpoolp512r1") { + if (!subkey_) { // for primary key is always ecdsa + + SetAllowEncryption(false); + allow_change_encryption_ = false; + + } else { // for subkey key is always ecdh + + SetAllowAuthentication(false); + allow_change_authentication_ = false; + + SetAllowSigning(false); + allow_change_signing_ = false; + } suggest_min_key_size_ = -1; suggest_max_key_size_ = -1; @@ -192,33 +216,93 @@ GenKeyInfo::GenKeyInfo(bool m_is_sub_key) : subkey_(m_is_sub_key) { auto GenKeyInfo::GetSupportedKeyAlgo() -> const std::vector<GenKeyInfo::KeyGenAlgo> & { - static const std::vector<GenKeyInfo::KeyGenAlgo> kSupportKeyAlgo = { + static std::vector<GenKeyInfo::KeyGenAlgo> k_support_key_algo = { {"RSA", "RSA", ""}, {"DSA", "DSA", ""}, - {"ECDSA", "ED25519", ""}, - {"ECDSA + ECDH", "ED25519", "CV25519"}, - {"ECDSA + ECDH NIST P-256", "ED25519", "NISTP256"}, - {"ECDSA + ECDH BrainPooL P-256", "ED25519", "BRAINPOOLP256R1"}, }; - return kSupportKeyAlgo; + static bool initialized = false; + + if (!initialized) { + const auto gnupg_version = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.gnupg_version", QString{"2.0.0"}); + if (GFCompareSoftwareVersion(gnupg_version, "2.0.0") < 0) { + // do nothing + } else if (GFCompareSoftwareVersion(gnupg_version, "2.3.0") < 0) { + k_support_key_algo = { + {"RSA", "RSA", ""}, + {"DSA", "DSA", ""}, + {"ECDSA (ED25519)", "ED25519", ""}, + {"ECDSA (NIST P-256)", "NISTP256", ""}, + {"ECDSA (NIST P-384)", "NISTP384", ""}, + {"ECDSA (NIST P-521)", "NISTP521", ""}, + }; + } else { + k_support_key_algo = { + {"RSA", "RSA", ""}, + {"DSA", "DSA", ""}, + {"ECDSA (ED25519)", "ED25519", ""}, + {"ECDSA (NIST P-256)", "NISTP256", ""}, + {"ECDSA (NIST P-384)", "NISTP384", ""}, + {"ECDSA (NIST P-521)", "NISTP521", ""}, + {"ECDSA (BrainPooL P-256)", "BRAINPOOLP256R1", ""}, + {"ECDSA (BrainPooL P-384)", "BRAINPOOLP384R1", ""}, + {"ECDSA (BrainPooL P-512)", "BRAINPOOLP512R1", ""}, + }; + } + + initialized = true; + } + + return k_support_key_algo; } auto GenKeyInfo::GetSupportedSubkeyAlgo() -> const std::vector<GenKeyInfo::KeyGenAlgo> & { - static const std::vector<GenKeyInfo::KeyGenAlgo> kSupportSubkeyAlgo = { + static std::vector<GenKeyInfo::KeyGenAlgo> k_support_subkey_algo = { {"RSA", "", "RSA"}, {"DSA", "", "DSA"}, {"ELG-E", "", "ELG"}, - {"ECDSA", "", "ED25519"}, - {"ECDH", "", "CV25519"}, - {"ECDH NIST P-256", "", "NISTP256"}, - {"ECDH NIST P-384", "", "NISTP384"}, - {"ECDH NIST P-521", "", "NISTP521"}, - {"ECDH BrainPooL P-256", "", "BRAINPOOLP256R1"}, - {"ECDH BrainPooL P-384", "", "BRAINPOOLP384R1"}, - {"ECDH BrainPooL P-512", "", "BRAINPOOLP512R1"}}; - - return kSupportSubkeyAlgo; + }; + static bool initialized = false; + + if (!initialized) { + const auto gnupg_version = Module::RetrieveRTValueTypedOrDefault<>( + "core", "gpgme.ctx.gnupg_version", QString{"2.0.0"}); + if (GFCompareSoftwareVersion(gnupg_version, "2.0.0") < 0) { + // do nothing + } else if (GFCompareSoftwareVersion(gnupg_version, "2.3.0") < 0) { + k_support_subkey_algo = { + {"RSA", "", "RSA"}, + {"DSA", "", "DSA"}, + {"ELG-E", "", "ELG"}, + {"ECDSA (ED25519)", "", "ED25519"}, + {"ECDH (CV25519)", "", "CV25519"}, + {"ECDH (NIST P-256)", "", "NISTP256"}, + {"ECDH (NIST P-384)", "", "NISTP384"}, + {"ECDH (NIST P-521)", "", "NISTP521"}, + }; + } else { + k_support_subkey_algo = { + {"RSA", "", "RSA"}, + {"DSA", "", "DSA"}, + {"ELG-E", "", "ELG"}, + {"ECDSA (ED25519)", "", "ED25519"}, + {"ECDSA (ED448)", "", "ED448"}, + {"ECDH (CV25519)", "", "CV25519"}, + {"ECDH (X448)", "", "X448"}, + {"ECDH (NIST P-256)", "", "NISTP256"}, + {"ECDH (NIST P-384)", "", "NISTP384"}, + {"ECDH (NIST P-521)", "", "NISTP521"}, + {"ECDH (BrainPooL P-256)", "", "BRAINPOOLP256R1"}, + {"ECDH (BrainPooL P-384)", "", "BRAINPOOLP384R1"}, + {"ECDH (BrainPooL P-512)", "", "BRAINPOOLP512R1"}, + }; + } + + initialized = true; + } + + return k_support_subkey_algo; } /** diff --git a/src/core/module/Event.cpp b/src/core/module/Event.cpp index 873e728d..56f45261 100644 --- a/src/core/module/Event.cpp +++ b/src/core/module/Event.cpp @@ -38,7 +38,7 @@ class Event::Impl { : event_identifier_(std::move(event_id)), callback_(std::move(callback)), callback_thread_(QThread::currentThread()) { - data_.insert(params); + if (!params.empty()) data_.insert(params); } auto operator[](const QString& key) const -> std::optional<ParameterValue> { @@ -98,17 +98,16 @@ class Event::Impl { event->id = GFStrDup(event_identifier_); event->trigger_id = GFStrDup(trigger_uuid_); + event->params = nullptr; GFModuleEventParam* l_param = nullptr; GFModuleEventParam* p_param; - int index = 0; - #if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) for (const auto& data : data_.asKeyValueRange()) { p_param = static_cast<GFModuleEventParam*>( SecureMalloc(sizeof(GFModuleEventParam))); - if (index++ == 0) event->params = p_param; + if (event->params == nullptr) event->params = p_param; p_param->name = GFStrDup(data.first); p_param->value = GFStrDup(data.second); @@ -121,7 +120,7 @@ class Event::Impl { for (auto it = data_.keyValueBegin(); it != data_.keyValueEnd(); ++it) { p_param = static_cast<GFModuleEventParam*>( SecureMalloc(sizeof(GFModuleEventParam))); - if (index++ == 0) event->params = p_param; + if (event->params == nullptr) event->params = p_param; p_param->name = GFStrDup(it->first); p_param->value = GFStrDup(it->second); diff --git a/src/core/module/GlobalModuleContext.cpp b/src/core/module/GlobalModuleContext.cpp index 08090d33..25ddce65 100644 --- a/src/core/module/GlobalModuleContext.cpp +++ b/src/core/module/GlobalModuleContext.cpp @@ -102,14 +102,12 @@ class GlobalModuleContext::Impl { module_register_table_.find(module->GetModuleIdentifier()) != module_register_table_.end()) { FLOG_W("module is null or have already registered this module"); + registered_modules_++; return false; } - if (module->Register() != 0) { - LOG_W() << "register module " << module->GetModuleIdentifier() - << " failed"; - return false; - } + LOG_D() << "(+) module: " << module->GetModuleIdentifier() + << "registering..."; auto register_info = GpgFrontend::SecureCreateSharedObject<ModuleRegisterInfo>(); @@ -124,13 +122,28 @@ class GlobalModuleContext::Impl { .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Module) ->GetThread()); - // Register the module with its identifier. + // register the module with its identifier. module_register_table_[module->GetModuleIdentifier()] = register_info; + if (module->Register() != 0) { + LOG_W() << "module: " << module->GetModuleIdentifier() + << " register failed."; + register_info->registered = false; + registered_modules_++; + return false; + } + + register_info->registered = true; + registered_modules_++; + + LOG_D() << "(+) module: " << module->GetModuleIdentifier() << "registered."; + return true; } auto ActiveModule(ModuleIdentifier module_id) -> bool { + LOG_D() << "(*) module: " << module_id << "activating..."; + // Search for the module in the register table. auto module_info_opt = search_module_register_table(module_id); if (!module_info_opt.has_value()) { @@ -140,6 +153,12 @@ class GlobalModuleContext::Impl { auto module_info = module_info_opt.value(); + if (!module_info->registered) { + LOG_W() << "module id:" << module_id + << " is not properly register, activation abort..."; + return false; + } + // try to get module from module info auto module = module_info->module; if (module == nullptr) { @@ -152,6 +171,8 @@ class GlobalModuleContext::Impl { if (!module_info->activate) { module->Active(); module_info->activate = true; + + LOG_D() << "(*) module: " << module_id << "activated."; } return module_info->activate; @@ -293,6 +314,12 @@ class GlobalModuleContext::Impl { return m.has_value() && m->get()->activate; } + [[nodiscard]] auto IsModuleRegistered(const ModuleIdentifier& m_id) const + -> bool { + auto m = search_module_register_table(m_id); + return m.has_value() && m->get()->activate; + } + auto IsIntegratedModule(ModuleIdentifier m_id) -> bool { auto m = search_module_register_table(m_id); return m.has_value() && m->get()->integrated; @@ -314,10 +341,13 @@ class GlobalModuleContext::Impl { return module_info->get()->listening_event_ids; } + auto GetRegisteredModuleNum() const -> int { return registered_modules_; } + private: struct ModuleRegisterInfo { int channel; ModulePtr module; + bool registered; bool activate; bool integrated; QList<QString> listening_event_ids; @@ -334,6 +364,7 @@ class GlobalModuleContext::Impl { std::set<int> acquired_channel_; TaskRunnerPtr default_task_runner_; + int registered_modules_ = 0; auto acquire_new_unique_channel() -> int { int random_channel = QRandomGenerator::global()->bounded(65535); @@ -440,4 +471,9 @@ auto GlobalModuleContext::GetModuleListening(ModuleIdentifier module_id) -> QList<EventIdentifier> { return p_->GetModuleListening(module_id); } + +auto GlobalModuleContext::GetRegisteredModuleNum() const -> int { + return p_->GetRegisteredModuleNum(); +} + } // namespace GpgFrontend::Module diff --git a/src/core/module/GlobalModuleContext.h b/src/core/module/GlobalModuleContext.h index e3dabe0e..f122f36f 100644 --- a/src/core/module/GlobalModuleContext.h +++ b/src/core/module/GlobalModuleContext.h @@ -90,6 +90,8 @@ class GPGFRONTEND_CORE_EXPORT GlobalModuleContext : public QObject { auto ListAllRegisteredModuleID() -> QList<ModuleIdentifier>; + [[nodiscard]] auto GetRegisteredModuleNum() const -> int; + private: class Impl; SecureUniquePtr<Impl> p_; diff --git a/src/core/module/Module.cpp b/src/core/module/Module.cpp index becda4b6..1be4a4bd 100644 --- a/src/core/module/Module.cpp +++ b/src/core/module/Module.cpp @@ -110,10 +110,10 @@ class Module::Impl { if (qt_env_ver_major != QString::number(QT_VERSION_MAJOR) + "." || qt_env_ver_minor != QString::number(QT_VERSION_MINOR) + ".") { - LOG_W() << "uncompatible module: " << identifier_ - << ", reason sdk version: " << qt_env_ver_ - << "current sdk version: " << QString::fromUtf8(QT_VERSION_STR) - << ", abort..."; + LOG_W() << "module: " << identifier_ + << "is not compatible, reason module qt version: " << qt_env_ver_ + << ", but application qt version: " + << QString::fromUtf8(QT_VERSION_STR) << ", abort..."; return; } @@ -274,7 +274,8 @@ auto Module::Register() -> int { return p_->Register(); } auto Module::Active() -> int { return p_->Active(); } auto Module::Exec(EventReference event) -> int { - return p_->Exec(std::move(event)); + LOG_D() << "module" << GetModuleIdentifier() << "executing..."; + return p_->Exec(event); } auto Module::Deactivate() -> int { return p_->Deactivate(); } diff --git a/src/core/module/ModuleInit.cpp b/src/core/module/ModuleInit.cpp index 3c71a45b..972e7025 100644 --- a/src/core/module/ModuleInit.cpp +++ b/src/core/module/ModuleInit.cpp @@ -38,15 +38,17 @@ namespace GpgFrontend::Module { -void LoadModuleFromPath(const QString& mods_path, bool integrated) { +auto SearchModuleFromPath(const QString& mods_path, + bool integrated) -> QMap<QString, bool> { + QMap<QString, bool> m; for (const auto& module_library_name : QDir(mods_path).entryList( QStringList() << "*.so" << "*.dll" << "*.dylib", QDir::Files)) { - ModuleManager::GetInstance().LoadModule( - mods_path + "/" + module_library_name, integrated); + m[mods_path + "/" + module_library_name] = integrated; } + return m; } -auto LoadIntegratedMods() -> bool { +auto LoadIntegratedMods() -> QMap<QString, bool> { const auto exec_binary_path = QCoreApplication::applicationDirPath(); QString mods_path = exec_binary_path + "/modules"; @@ -71,37 +73,63 @@ auto LoadIntegratedMods() -> bool { if (!QDir(mods_path).exists()) { LOG_W() << "integrated module directory at path: " << mods_path << " not found, abort..."; - return false; + return {}; } - LoadModuleFromPath(mods_path, true); - - return true; + return SearchModuleFromPath(mods_path, true); } -auto LoadExternalMods() -> bool { +auto LoadExternalMods() -> QMap<QString, bool> { auto mods_path = GpgFrontend::GlobalSettingStation::GetInstance().GetModulesDir(); if (!QDir(mods_path).exists()) { LOG_W() << "external module directory at path " << mods_path << " not found, abort..."; - return false; + return {}; } - LoadModuleFromPath(mods_path, false); - - return true; + return SearchModuleFromPath(mods_path, false); } void LoadGpgFrontendModules(ModuleInitArgs) { + // give user ability to give up all modules + auto disable_loading_all_modules = + GlobalSettingStation::GetInstance() + .GetSettings() + .value("basic/disable_loading_all_modules", false) + .toBool(); + if (disable_loading_all_modules) return; + // must init at default thread before core - Thread::TaskRunnerGetter::GetInstance().GetTaskRunner()->PostTask( - new Thread::Task( + Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Module) + ->PostTask(new Thread::Task( [](const DataObjectPtr&) -> int { - return LoadIntegratedMods() && LoadExternalMods() ? 0 : -1; + QMap<QString, bool> modules = LoadIntegratedMods(); + modules.insert(LoadExternalMods()); + + auto& manager = ModuleManager::GetInstance(); + manager.SetNeedRegisterModulesNum(static_cast<int>(modules.size())); + +#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) + for (const auto& m : modules.asKeyValueRange()) { + manager.LoadModule(m.first, m.second); + } +#else + for (auto it = modules.keyValueBegin(); it != modules.keyValueEnd(); + ++it) { + manager.LoadModule(it->first, it->second); + } +#endif + + LOG_D() << "all modules are loaded into memory."; + return 0; }, "modules_system_init_task")); + + LOG_D() << "dear module manager, is all module registered? answer: " + << ModuleManager::GetInstance().IsAllModulesRegistered(); } void ShutdownGpgFrontendModules() {} diff --git a/src/core/module/ModuleManager.cpp b/src/core/module/ModuleManager.cpp index 5f8895be..8f97adc3 100644 --- a/src/core/module/ModuleManager.cpp +++ b/src/core/module/ModuleManager.cpp @@ -54,66 +54,79 @@ class ModuleManager::Impl { ~Impl() = default; auto LoadAndRegisterModule(const QString& module_library_path, - bool integrated_module) -> void { - // give user ability to give up all modules - auto disable_loading_all_modules = - GlobalSettingStation::GetInstance() - .GetSettings() - .value("basic/disable_loading_all_modules", false) - .toBool(); - if (disable_loading_all_modules) return; - - Thread::TaskRunnerGetter::GetInstance() - .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Default) - ->PostTask(new Thread::Task( - [=](GpgFrontend::DataObjectPtr) -> int { - QLibrary module_library(module_library_path); - if (!module_library.load()) { - LOG_W() << "module manager failed to load module: " - << module_library.fileName() - << ", reason: " << module_library.errorString(); - return -1; - } - - auto module = SecureCreateSharedObject<Module>(module_library); - if (!module->IsGood()) { - LOG_W() << "module manager failed to load module, " - "reason: illegal module: " - << module_library.fileName(); - return -1; - } - - module->SetGPC(gmc_.get()); - if (!gmc_->RegisterModule(module, integrated_module)) return -1; - - const auto module_id = module->GetModuleIdentifier(); - const auto module_hash = module->GetModuleHash(); - - SettingsObject so(QString("module.%1.so").arg(module_id)); - ModuleSO module_so(so); - - // reset module settings if necessary - if (module_so.module_id != module_id || - module_so.module_hash != module_hash) { - module_so.module_id = module_id; - module_so.module_hash = module_hash; - // auto active integrated module by default - module_so.auto_activate = integrated_module; - module_so.set_by_user = false; - - so.Store(module_so.ToJson()); - } - - // if this module need auto active - if (module_so.auto_activate) { - if (!gmc_->ActiveModule(module_id)) { - return -1; - } - } + bool integrated_module) -> bool { + QLibrary module_library(module_library_path); + if (!module_library.load()) { + LOG_W() << "module manager failed to load module: " + << module_library.fileName() + << ", reason: " << module_library.errorString(); + need_register_modules_--; + return false; + } + + auto module = SecureCreateSharedObject<Module>(module_library); + if (!module->IsGood()) { + LOG_W() << "module manager failed to load module, " + "reason: illegal module: " + << module_library.fileName(); + need_register_modules_--; + return false; + } + + module->SetGPC(gmc_.get()); + + LOG_D() << "a new need register module: " + << QFileInfo(module_library_path).fileName(); + + auto runner = Thread::TaskRunnerGetter::GetInstance().GetTaskRunner( + Thread::TaskRunnerGetter::kTaskRunnerType_Module); + + runner->PostTask(new Thread::Task( + [=](GpgFrontend::DataObjectPtr) -> int { + // register module + if (!gmc_->RegisterModule(module, integrated_module)) return -1; + + return 0; + }, + __func__, nullptr)); + + runner->PostTask(new Thread::Task( + [=](GpgFrontend::DataObjectPtr) -> int { + const auto module_id = module->GetModuleIdentifier(); + const auto module_hash = module->GetModuleHash(); + + SettingsObject so(QString("module.%1.so").arg(module_id)); + ModuleSO module_so(so); + + // reset module settings if necessary + if (module_so.module_id != module_id || + module_so.module_hash != module_hash) { + module_so.module_id = module_id; + module_so.module_hash = module_hash; + // auto active integrated module by default + module_so.auto_activate = integrated_module; + module_so.set_by_user = false; + + so.Store(module_so.ToJson()); + } + + // if this module need auto active + if (module_so.auto_activate) { + if (!gmc_->ActiveModule(module_id)) { + return -1; + } + } + + return 0; + }, + __func__, nullptr)); + + return true; + } - return 0; - }, - __func__, nullptr)); + void SetNeedRegisterModulesNum(int n) { + if (need_register_modules_ != -1 || n < 0) return; + need_register_modules_ = n; } auto SearchModule(ModuleIdentifier module_id) -> ModulePtr { @@ -126,7 +139,7 @@ class ModuleManager::Impl { void RegisterModule(const ModulePtr& module) { Thread::TaskRunnerGetter::GetInstance() - .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Default) + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Module) ->PostTask(new Thread::Task( [=](GpgFrontend::DataObjectPtr) -> int { module->SetGPC(gmc_.get()); @@ -138,7 +151,7 @@ class ModuleManager::Impl { void ListenEvent(const ModuleIdentifier& module_id, const EventIdentifier& event_id) { Thread::TaskRunnerGetter::GetInstance() - .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Default) + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Module) ->PostTask(new Thread::Task( [=](const GpgFrontend::DataObjectPtr&) -> int { gmc_->ListenEvent(module_id, event_id); @@ -149,7 +162,7 @@ class ModuleManager::Impl { void TriggerEvent(const EventReference& event) { Thread::TaskRunnerGetter::GetInstance() - .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Default) + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Module) ->PostTask(new Thread::Task( [=](const GpgFrontend::DataObjectPtr&) -> int { gmc_->TriggerEvent(event); @@ -170,7 +183,7 @@ class ModuleManager::Impl { void ActiveModule(const ModuleIdentifier& identifier) { Thread::TaskRunnerGetter::GetInstance() - .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Default) + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Module) ->PostTask(new Thread::Task( [=](const GpgFrontend::DataObjectPtr&) -> int { gmc_->ActiveModule(identifier); @@ -181,7 +194,7 @@ class ModuleManager::Impl { void DeactivateModule(const ModuleIdentifier& identifier) { Thread::TaskRunnerGetter::GetInstance() - .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Default) + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_Module) ->PostTask(new Thread::Task( [=](const GpgFrontend::DataObjectPtr&) -> int { gmc_->DeactivateModule(identifier); @@ -219,6 +232,14 @@ class ModuleManager::Impl { return gmc_->IsIntegratedModule(id); } + auto IsAllModulesRegistered() { + if (need_register_modules_ == -1) return false; + LOG_D() << "module manager report, need register: " + << need_register_modules_ << "registered" + << gmc_->GetRegisteredModuleNum(); + return need_register_modules_ == gmc_->GetRegisteredModuleNum(); + } + auto GRT() -> GlobalRegisterTable* { return grt_.get(); } private: @@ -226,12 +247,18 @@ class ModuleManager::Impl { SecureUniquePtr<GlobalModuleContext> gmc_; SecureUniquePtr<GlobalRegisterTable> grt_; QList<QLibrary> module_libraries_; + int need_register_modules_ = -1; }; auto IsModuleActivate(ModuleIdentifier id) -> bool { return ModuleManager::GetInstance().IsModuleActivated(id); } +auto GPGFRONTEND_CORE_EXPORT IsModuleExists(ModuleIdentifier id) -> bool { + auto module = ModuleManager::GetInstance().SearchModule(id); + return module != nullptr && module->IsGood(); +} + auto UpsertRTValue(const QString& namespace_, const QString& key, const std::any& value) -> bool { return ModuleManager::GetInstance().UpsertRTValue(namespace_, key, @@ -254,8 +281,8 @@ ModuleManager::ModuleManager(int channel) ModuleManager::~ModuleManager() = default; -void ModuleManager::LoadModule(QString module_library_path, - bool integrated_module) { +auto ModuleManager::LoadModule(QString module_library_path, + bool integrated_module) -> bool { return p_->LoadAndRegisterModule(module_library_path, integrated_module); } @@ -332,4 +359,11 @@ auto ModuleManager::ListAllRegisteredModuleID() -> QList<ModuleIdentifier> { auto ModuleManager::GRT() -> GlobalRegisterTable* { return p_->GRT(); } +auto ModuleManager::IsAllModulesRegistered() -> bool { + return p_->IsAllModulesRegistered(); +} + +void ModuleManager::SetNeedRegisterModulesNum(int n) { + p_->SetNeedRegisterModulesNum(n); +} } // namespace GpgFrontend::Module
\ No newline at end of file diff --git a/src/core/module/ModuleManager.h b/src/core/module/ModuleManager.h index 365dd8fd..5c703bf3 100644 --- a/src/core/module/ModuleManager.h +++ b/src/core/module/ModuleManager.h @@ -65,14 +65,18 @@ class GPGFRONTEND_CORE_EXPORT ModuleManager virtual ~ModuleManager() override; - auto LoadModule(QString, bool) -> void; + auto LoadModule(QString, bool) -> bool; auto SearchModule(ModuleIdentifier) -> ModulePtr; + void SetNeedRegisterModulesNum(int); + auto ListAllRegisteredModuleID() -> QList<ModuleIdentifier>; void RegisterModule(ModulePtr); + auto IsAllModulesRegistered() -> bool; + auto IsModuleActivated(ModuleIdentifier) -> bool; auto IsIntegratedModule(ModuleIdentifier) -> bool; @@ -139,6 +143,14 @@ auto GPGFRONTEND_CORE_EXPORT IsModuleActivate(ModuleIdentifier) -> bool; /** * @brief * + * @return true + * @return false + */ +auto GPGFRONTEND_CORE_EXPORT IsModuleExists(ModuleIdentifier) -> bool; + +/** + * @brief + * * @param namespace_ * @param key * @param value diff --git a/src/core/utils/CommonUtils.cpp b/src/core/utils/CommonUtils.cpp index f8468c46..60ce4642 100644 --- a/src/core/utils/CommonUtils.cpp +++ b/src/core/utils/CommonUtils.cpp @@ -72,24 +72,25 @@ auto GFCompareSoftwareVersion(const QString& a, const QString& b) -> int { return 0; } -auto GFStrDup(const QString& str) -> char* { - auto utf8_str = str.toUtf8(); - auto* c_str = - static_cast<char*>(SecureMalloc((utf8_str.size() + 1) * sizeof(char))); - - memcpy(c_str, utf8_str.constData(), utf8_str.size()); - c_str[utf8_str.size()] = '\0'; - return c_str; +auto GFStrDup(const QString& s) -> char* { + if (s.isEmpty()) return nullptr; + + auto u_s = s.toUtf8(); + auto* c_s = static_cast<char*>(SecureMalloc((u_s.size() + 1) * sizeof(char))); + + memcpy(c_s, u_s.constData(), u_s.size()); + c_s[u_s.size()] = '\0'; + return c_s; } -auto GFUnStrDup(char* str) -> QString { - auto qt_str = QString::fromUtf8(str); - SecureFree(static_cast<void*>(const_cast<char*>(str))); - return qt_str; +auto GFUnStrDup(char* s) -> QString { + auto q_s = QString::fromUtf8(s == nullptr ? "" : s); + if (s != nullptr) SecureFree(static_cast<void*>(const_cast<char*>(s))); + return q_s; } -auto GFUnStrDup(const char* str) -> QString { - return GFUnStrDup(const_cast<char*>(str)); +auto GFUnStrDup(const char* s) -> QString { + return GFUnStrDup(const_cast<char*>(s)); } } // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/utils/CommonUtils.h b/src/core/utils/CommonUtils.h index c2f4157a..83490cc4 100644 --- a/src/core/utils/CommonUtils.h +++ b/src/core/utils/CommonUtils.h @@ -56,13 +56,13 @@ auto GPGFRONTEND_CORE_EXPORT GFCompareSoftwareVersion(const QString &a, * * @return char* */ -auto GFStrDup(const QString &) -> char *; +auto GPGFRONTEND_CORE_EXPORT GFStrDup(const QString &) -> char *; /** * @brief * * @return QString */ -auto GFUnStrDup(const char *) -> QString; +auto GPGFRONTEND_CORE_EXPORT GFUnStrDup(const char *) -> QString; } // namespace GpgFrontend
\ No newline at end of file diff --git a/src/init.cpp b/src/init.cpp index 6d8fe8e4..f5476783 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -108,6 +108,9 @@ void InitGlobalBasicEnv(const GFCxtWPtr &p_ctx, bool gui_mode) { // then load core InitGpgFrontendCore(core_init_args); + + // monitor + StartMonitorCoreInitializationStatus(); } /** diff --git a/src/sdk/GFSDKBasic.cpp b/src/sdk/GFSDKBasic.cpp index 906f9baf..32076cd0 100644 --- a/src/sdk/GFSDKBasic.cpp +++ b/src/sdk/GFSDKBasic.cpp @@ -32,7 +32,7 @@ #include "core/function/gpg/GpgCommandExecutor.h" #include "core/utils/BuildInfoUtils.h" #include "sdk/private/CommonUtils.h" -#include "ui/GpgFrontendUIInit.h" +#include "ui/UIModuleManager.h" auto GFAllocateMemory(uint32_t size) -> void* { return GpgFrontend::SecureMemoryAllocator::Allocate(size); @@ -110,11 +110,10 @@ auto GFModuleStrDup(const char* src) -> char* { auto GFAppActiveLocale() -> char* { return GFStrDup(QLocale().name()); } -auto GFAppRegisterTranslator(char* data, int size) -> int { - auto b = QByteArray(data, size); - QMetaObject::invokeMethod(QApplication::instance()->thread(), [b]() { - GpgFrontend::UI::InstallTranslatorFromQMData(b); - }); - GFFreeMemory(data); - return 0; +auto GFAppRegisterTranslatorReader(const char* id, + GFTranslatorDataReader reader) -> int { + return GpgFrontend::UI::UIModuleManager::GetInstance() + .RegisterTranslatorDataReader(GFUnStrDup(id), reader) + ? 0 + : -1; } diff --git a/src/sdk/GFSDKBasic.h b/src/sdk/GFSDKBasic.h index aba4d2e0..f6c80287 100644 --- a/src/sdk/GFSDKBasic.h +++ b/src/sdk/GFSDKBasic.h @@ -48,6 +48,8 @@ using GFCommandExecuteContext = struct { void* data; }; +using GFTranslatorDataReader = int (*)(const char* locale, char** data); + /** * @brief * @@ -129,6 +131,6 @@ auto GPGFRONTEND_MODULE_SDK_EXPORT GFAppActiveLocale() -> char*; * @param size * @return auto */ -auto GPGFRONTEND_MODULE_SDK_EXPORT GFAppRegisterTranslator(char* data, - int size) -> int; +auto GPGFRONTEND_MODULE_SDK_EXPORT +GFAppRegisterTranslatorReader(const char* id, GFTranslatorDataReader reader) -> int; }
\ No newline at end of file diff --git a/src/test/GpgFrontendTest.h b/src/test/GpgFrontendTest.h index d78f6636..c5b7a375 100644 --- a/src/test/GpgFrontendTest.h +++ b/src/test/GpgFrontendTest.h @@ -44,13 +44,23 @@ Q_DECLARE_LOGGING_CATEGORY(test) #define LOG_I() qCInfo(test) #define LOG_W() qCWarning(test) #define LOG_E() qCCritical(test) -#define LOG_F() qCFatal(test) + +#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) +#define LOG_F(...) qCFatal(test) +#else +#define LOG_F(...) qFatal() +#endif #define FLOG_D(...) qCDebug(test, __VA_ARGS__) #define FLOG_I(...) qCInfo(test, __VA_ARGS__) #define FLOG_W(...) qCWarning(test, __VA_ARGS__) #define FLOG_E(...) qCCritical(test, __VA_ARGS__) + +#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) #define FLOG_F(...) qCFatal(test, __VA_ARGS__) +#else +#define FLOG_F(...) qFatal(__VA_ARGS__) +#endif #endif diff --git a/src/ui/GpgFrontendUI.h b/src/ui/GpgFrontendUI.h index c3816469..39c39686 100644 --- a/src/ui/GpgFrontendUI.h +++ b/src/ui/GpgFrontendUI.h @@ -47,12 +47,23 @@ Q_DECLARE_LOGGING_CATEGORY(ui) #define LOG_I() qCInfo(ui) #define LOG_W() qCWarning(ui) #define LOG_E() qCCritical(ui) -#define LOG_F() qCFatal(core) +#define LOG_F() qCFatal(ui) + +#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) +#define LOG_F(...) qCFatal(ui) +#else +#define LOG_F(...) qFatal() +#endif #define FLOG_D(...) qCDebug(ui, __VA_ARGS__) #define FLOG_I(...) qCInfo(ui, __VA_ARGS__) #define FLOG_W(...) qCWarning(ui, __VA_ARGS__) #define FLOG_E(...) qCCritical(ui, __VA_ARGS__) + +#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) #define FLOG_F(...) qCFatal(ui, __VA_ARGS__) +#else +#define FLOG_F(...) qFatal(__VA_ARGS__) +#endif #endif diff --git a/src/ui/GpgFrontendUIInit.cpp b/src/ui/GpgFrontendUIInit.cpp index 0309ca1f..965ce471 100644 --- a/src/ui/GpgFrontendUIInit.cpp +++ b/src/ui/GpgFrontendUIInit.cpp @@ -30,12 +30,12 @@ #include <QtNetwork> -#include "UIModuleManager.h" #include "core/GpgConstants.h" #include "core/function/CoreSignalStation.h" #include "core/function/GlobalSettingStation.h" #include "core/model/GpgPassphraseContext.h" #include "core/module/ModuleManager.h" +#include "ui/UIModuleManager.h" #include "ui/UISignalStation.h" #include "ui/UserInterfaceUtils.h" #include "ui/main_window/MainWindow.h" @@ -65,8 +65,9 @@ void WaitEnvCheckingProcess() { waiting_dialog->setLabel(waiting_dialog_label); waiting_dialog->resize(420, 120); QApplication::connect(CoreSignalStation::GetInstance(), - &CoreSignalStation::SignalGoodGnupgEnv, waiting_dialog, - [=]() { + &CoreSignalStation::SignalCoreFullyLoaded, + waiting_dialog, [=]() { + LOG_D() << "ui caught signal: core fully loaded"; waiting_dialog->finished(0); waiting_dialog->deleteLater(); }); @@ -74,7 +75,7 @@ void WaitEnvCheckingProcess() { // new local event looper QEventLoop looper; QApplication::connect(CoreSignalStation::GetInstance(), - &CoreSignalStation::SignalGoodGnupgEnv, &looper, + &CoreSignalStation::SignalCoreFullyLoaded, &looper, &QEventLoop::quit); QApplication::connect(waiting_dialog, &QProgressDialog::canceled, [=]() { @@ -84,9 +85,9 @@ void WaitEnvCheckingProcess() { }); auto env_state = - Module::RetrieveRTValueTypedOrDefault<>("core", "env.state.basic", 0); + Module::RetrieveRTValueTypedOrDefault<>("core", "env.state.all", 0); FLOG_D("ui is ready to waiting for env initialized, env_state: %d", - env_state); + env_state); // check twice to avoid some unlucky sitations if (env_state == 1) { @@ -194,16 +195,20 @@ void InitGpgFrontendUI(QApplication* /*app*/) { // no proxy by default QNetworkProxy::setApplicationProxy(QNetworkProxy::NoProxy); } +} - if (Module::RetrieveRTValueTypedOrDefault<>("core", "env.state.basic", 0) == +void WaitingAllInitializationFinished() { + if (Module::RetrieveRTValueTypedOrDefault<>("core", "env.state.all", 0) == 0) { + LOG_D() << "ui init is done, but cor doesn't, going to waiting for core..."; WaitEnvCheckingProcess(); } + LOG_D() << "application fully initialized..."; } auto RunGpgFrontendUI(QApplication* app) -> int { // create main window and show it - auto main_window = std::make_unique<GpgFrontend::UI::MainWindow>(); + auto main_window = SecureCreateUniqueObject<GpgFrontend::UI::MainWindow>(); // pre-check, if application need to restart if (CommonUtils::GetInstance()->isApplicationNeedRestart()) { @@ -211,6 +216,8 @@ auto RunGpgFrontendUI(QApplication* app) -> int { return kDeepRestartCode; } + LOG_D() << "main window start to initialize..."; + // init main window main_window->Init(); @@ -257,19 +264,11 @@ void InitUITranslations() { } } -auto InstallTranslatorFromQMData(const QByteArray& data) -> bool { - auto* translator = new QTranslator(QCoreApplication::instance()); - - if (translator->load(reinterpret_cast<uchar*>(const_cast<char*>(data.data())), - data.size())) { - QCoreApplication::installTranslator(translator); - registered_translators.append(translator); - loaded_qm_datum.append(data); - - return true; - } - - return false; +void InitModulesTranslations() { + // register module's translations + UIModuleManager::GetInstance().RegisterAllModuleTranslators(); + // translate all params + UIModuleManager::GetInstance().TranslateAllModulesParams(); } } // namespace GpgFrontend::UI diff --git a/src/ui/GpgFrontendUIInit.h b/src/ui/GpgFrontendUIInit.h index 5e44c5bf..afdbc2ab 100644 --- a/src/ui/GpgFrontendUIInit.h +++ b/src/ui/GpgFrontendUIInit.h @@ -45,6 +45,12 @@ void GPGFRONTEND_UI_EXPORT PreInitGpgFrontendUI(); void GPGFRONTEND_UI_EXPORT InitGpgFrontendUI(QApplication *); /** + * @brief + * + */ +void GPGFRONTEND_UI_EXPORT WaitingAllInitializationFinished(); + +/** * @brief init the UI library * */ @@ -59,7 +65,6 @@ auto GPGFRONTEND_UI_EXPORT RunGpgFrontendUI(QApplication *) -> int; * @brief * */ -auto GPGFRONTEND_UI_EXPORT InstallTranslatorFromQMData(const QByteArray &data) - -> bool; +void GPGFRONTEND_UI_EXPORT InitModulesTranslations(); }; // namespace GpgFrontend::UI diff --git a/src/ui/UIModuleManager.cpp b/src/ui/UIModuleManager.cpp index 4b2ce648..353e9053 100644 --- a/src/ui/UIModuleManager.cpp +++ b/src/ui/UIModuleManager.cpp @@ -31,6 +31,7 @@ #include <utility> #include "core/module/ModuleManager.h" +#include "core/utils/CommonUtils.h" namespace GpgFrontend::UI { @@ -101,4 +102,84 @@ auto MountedUIEntry::GetMetaDataByDefault( if (!meta_data_.contains(key)) return default_value; return meta_data_[key]; } + +auto UIModuleManager::RegisterTranslatorDataReader( + Module::ModuleIdentifier id, GFTranslatorDataReader reader) -> bool { + if (reader != nullptr && !id.isEmpty() && Module::IsModuleExists(id)) { + LOG_D() << "module " << id << "registering translator reader..."; + translator_data_readers_[id] = ModuleTranslatorInfo{reader}; + return true; + } + return false; +} + +void UIModuleManager::RegisterAllModuleTranslators() { + registered_translators_.clear(); + read_translator_data_list_.clear(); + + const auto locale_name = QLocale().name(); + +#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) + for (const auto& reader : translator_data_readers_.asKeyValueRange()) { + char* data = nullptr; + + auto data_size = reader.second.reader_(GFStrDup(locale_name), &data); + LOG_D() << "module " << reader.first << "reader, read locale " + << locale_name << ", data size: " << data_size; +#else + for (auto it = translator_data_readers_.keyValueBegin(); + it != translator_data_readers_.keyValueEnd(); ++it) { + char* data = nullptr; + + auto data_size = it->second.reader_(GFStrDup(locale_name), &data); + LOG_D() << "module " << it->first << "reader, read locale " << locale_name + << ", data size: " << data_size; +#endif + + if (data == nullptr) continue; + + if (data_size <= 0) { + SecureFree(data); + continue; + } + + QByteArray b(data, data_size); + SecureFree(data); + + auto* translator = new QTranslator(QCoreApplication::instance()); + auto load = translator->load( + reinterpret_cast<uchar*>(const_cast<char*>(b.data())), b.size()); + if (load && QCoreApplication::installTranslator(translator)) { + registered_translators_.append(translator); + read_translator_data_list_.append(b); + } else { + translator->deleteLater(); + } + } +} + +void UIModuleManager::TranslateAllModulesParams() { +#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) + for (auto entry : mounted_entries_.asKeyValueRange()) { + for (auto& m_entry : entry.second) { + for (auto param : m_entry.meta_data_.asKeyValueRange()) { + m_entry.meta_data_[param.first] = + QApplication::translate("GTrC", param.second.toUtf8()); + } + } + } +#else + for (auto it = mounted_entries_.keyValueBegin(); + it != mounted_entries_.keyValueEnd(); ++it) { + for (auto& m_entry : it->second) { + for (auto it_p = m_entry.meta_data_.keyValueBegin(); + it_p != m_entry.meta_data_.keyValueEnd(); ++it_p) { + m_entry.meta_data_[it_p->first] = + QApplication::translate("GTrC", it_p->second.toUtf8()); + } + } + } +#endif +} + } // namespace GpgFrontend::UI
\ No newline at end of file diff --git a/src/ui/UIModuleManager.h b/src/ui/UIModuleManager.h index bef3768d..392222d6 100644 --- a/src/ui/UIModuleManager.h +++ b/src/ui/UIModuleManager.h @@ -30,6 +30,8 @@ #include "GpgFrontendUIExport.h" #include "core/function/basic/GpgFunctionObject.h" +#include "core/module/Module.h" +#include "sdk/GFSDKBasic.h" #include "sdk/GFSDKUI.h" #include "ui/struct/UIMountPoint.h" @@ -48,6 +50,10 @@ struct MountedUIEntry { const QString& key, QString default_value) const -> QString; }; +struct ModuleTranslatorInfo { + GFTranslatorDataReader reader_; +}; + class GPGFRONTEND_UI_EXPORT UIModuleManager : public SingletonFunctionObject<UIModuleManager> { public: @@ -95,9 +101,32 @@ class GPGFRONTEND_UI_EXPORT UIModuleManager */ auto QueryMountedEntries(QString id) -> QList<MountedUIEntry>; + /** + * @brief + * + * @return auto + */ + auto RegisterTranslatorDataReader(Module::ModuleIdentifier id, + GFTranslatorDataReader reader) -> bool; + + /** + * @brief + * + */ + void RegisterAllModuleTranslators(); + + /** + * @brief + * + */ + void TranslateAllModulesParams(); + private: QMap<QString, UIMountPoint> mount_points_; QMap<QString, QList<MountedUIEntry>> mounted_entries_; + QMap<QString, ModuleTranslatorInfo> translator_data_readers_; + QList<QTranslator*> registered_translators_; + QList<QByteArray> read_translator_data_list_; }; } // namespace GpgFrontend::UI
\ No newline at end of file diff --git a/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp b/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp index 2e9e4150..711e6784 100644 --- a/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp +++ b/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp @@ -120,6 +120,7 @@ KeyPairDetailTab::KeyPairDetailTab(const QString& key_id, QWidget* parent) fingerprint_var_label_->setTextInteractionFlags(Qt::TextSelectableByMouse); fingerprint_var_label_->setStyleSheet("margin-left: 0; margin-right: 5;"); fingerprint_var_label_->setAlignment(Qt::AlignCenter); + fingerprint_var_label_->setMinimumWidth(400); auto* hbox_fp = new QHBoxLayout(); hbox_fp->addStretch(); @@ -264,6 +265,7 @@ void KeyPairDetailTab::slot_refresh_key_info() { algorithm_var_label_->setText(key_algo_val); algorithm_detail_var_label_->setText(key_algo_detail_val); fingerprint_var_label_->setText(BeautifyFingerprint(key_.GetFingerprint())); + fingerprint_var_label_->setWordWrap(true); // for x448 and ed448 icon_label_->hide(); exp_label_->hide(); diff --git a/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp b/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp index bb7972ae..c008206f 100644 --- a/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp +++ b/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp @@ -156,8 +156,8 @@ void KeyPairSubkeyTab::create_subkey_list() { subkey_list_->setAlternatingRowColors(true); QStringList labels; - labels << tr("Subkey ID") << tr("Key Size") << tr("Algo") << tr("Create Date") - << tr("Expire Date"); + labels << tr("Subkey ID") << tr("Key Size") << tr("Algorithm") + << tr("Algorithm Detail") << tr("Create Date") << tr("Expire Date"); subkey_list_->setHorizontalHeaderLabels(labels); subkey_list_->horizontalHeader()->setStretchLastSection(false); @@ -190,17 +190,21 @@ void KeyPairSubkeyTab::slot_refresh_subkey_list() { tmp2->setTextAlignment(Qt::AlignCenter); subkey_list_->setItem(row, 2, tmp2); - auto* tmp3 = - new QTableWidgetItem(QLocale().toString(subkeys.GetCreateTime())); + auto* tmp3 = new QTableWidgetItem(subkeys.GetKeyAlgo()); tmp3->setTextAlignment(Qt::AlignCenter); subkey_list_->setItem(row, 3, tmp3); auto* tmp4 = + new QTableWidgetItem(QLocale().toString(subkeys.GetCreateTime())); + tmp4->setTextAlignment(Qt::AlignCenter); + subkey_list_->setItem(row, 4, tmp4); + + auto* tmp5 = new QTableWidgetItem(subkeys.GetExpireTime().toSecsSinceEpoch() == 0 ? tr("Never Expire") : QLocale().toString(subkeys.GetExpireTime())); - tmp4->setTextAlignment(Qt::AlignCenter); - subkey_list_->setItem(row, 4, tmp4); + tmp5->setTextAlignment(Qt::AlignCenter); + subkey_list_->setItem(row, 5, tmp5); if (!row) { for (auto i = 0; i < subkey_list_->columnCount(); i++) { @@ -292,6 +296,7 @@ void KeyPairSubkeyTab::slot_refresh_subkey_detail() { } fingerprint_var_label_->setText(BeautifyFingerprint(subkey.GetFingerprint())); + fingerprint_var_label_->setWordWrap(true); // for x448 and ed448 } void KeyPairSubkeyTab::create_subkey_opera_menu() { |