diff options
-rw-r--r-- | .github/workflows/debug.yml | 10 | ||||
-rw-r--r-- | .github/workflows/release.yml | 59 | ||||
-rw-r--r-- | CMakeLists.txt | 5 | ||||
-rw-r--r-- | README.md | 4 | ||||
-rw-r--r-- | manual/_coverpage.md | 29 | ||||
-rw-r--r-- | manual/_navbar.md | 5 | ||||
-rw-r--r-- | manual/_sidebar.md | 3 | ||||
-rw-r--r-- | manual/downloads.md | 17 | ||||
-rw-r--r-- | manual/index.html | 11 | ||||
-rw-r--r-- | manual/manual/symmetric-encrypt-decrypt-text.md | 5 | ||||
-rw-r--r-- | resource/plist/ExportOptions.plist.in | 21 | ||||
-rw-r--r-- | src/CMakeLists.txt | 5 | ||||
-rw-r--r-- | src/core/CMakeLists.txt | 4 | ||||
-rw-r--r-- | src/core/thread/Task.cpp | 91 | ||||
-rw-r--r-- | src/core/thread/Task.h | 169 | ||||
-rw-r--r-- | src/core/thread/TaskRunner.cpp | 28 | ||||
-rw-r--r-- | src/core/thread/ThreadingModel.h | 36 | ||||
-rw-r--r-- | src/ui/GpgFrontendUI.h | 2 | ||||
-rw-r--r-- | src/ui/UserInterfaceUtils.cpp | 28 | ||||
-rw-r--r-- | src/ui/UserInterfaceUtils.h | 7 | ||||
-rw-r--r-- | src/ui/main_window/MainWindowFileSlotFunction.cpp | 183 | ||||
-rw-r--r-- | src/ui/main_window/MainWindowSlotFunction.cpp | 334 |
22 files changed, 766 insertions, 290 deletions
diff --git a/.github/workflows/debug.yml b/.github/workflows/debug.yml index 9ee690be..0615b530 100644 --- a/.github/workflows/debug.yml +++ b/.github/workflows/debug.yml @@ -49,16 +49,6 @@ jobs: - name: Git Sumbodule Update run: | git submodule update --init --recursive - - name: Codesign Configuration (macOS) - run: | - echo ${{secrets.MACOS_CERTIFICATE}} | base64 --decode > certificate.p12 - security create-keychain -p gpgfrontend build.keychain - security default-keychain -s build.keychain - security unlock-keychain -p gpgfrontend build.keychain - security import certificate.p12 -k build.keychain -P ${{secrets.MAOS_CERTIFICATE_PWD}} -T /usr/bin/codesign - security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k gpgfrontend build.keychain - security set-keychain-settings -lut 3600 - if: matrix.os == 'macos-10.15' - name: Install Dependence (macOS) run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5696c692..3ec10770 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -58,13 +58,22 @@ jobs: - name: Codesign Configuration (macOS) run: | - echo ${{secrets.MACOS_CERTIFICATE}} | base64 --decode > certificate.p12 + CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12 + PP_PATH=$RUNNER_TEMP/${{secrets.GPGFRONTEND_XOCDE_PROVISIONING_PROFILE_UUID}}.provisionprofile + KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db + + echo -n "${{secrets.MACOS_CERTIFICATE}}" | base64 --decode --output $CERTIFICATE_PATH + echo -n "${{secrets.GPGFRONTEND_XOCDE_PROVISIONING_PROFILE_DATA}}" | base64 --decode --output $PP_PATH + security create-keychain -p gpgfrontend build.keychain security default-keychain -s build.keychain security unlock-keychain -p gpgfrontend build.keychain - security import certificate.p12 -k build.keychain -P ${{secrets.MAOS_CERTIFICATE_PWD}} -T /usr/bin/codesign + security import $CERTIFICATE_PATH -k build.keychain -P ${{secrets.MAOS_CERTIFICATE_PWD}} -T /usr/bin/codesign security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k gpgfrontend build.keychain security set-keychain-settings -lut 3600 + + mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles + cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles if: matrix.os == 'macos-10.15' - name: Install Dependence (macOS) @@ -141,34 +150,48 @@ jobs: cmake --build ${{github.workspace}}/build --config {{$env.BUILD_TYPE}} -- -v if: matrix.os == 'ubuntu-18.04' - - name: Build GpgFrontend (macOS) + - name: Build & Export GpgFrontend (macOS) # Build your GpgFrontend with the given configuration run: | - cmake -B ${{github.workspace}}/build -G Ninja -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} - cmake --build ${{github.workspace}}/build --config {{$env.BUILD_TYPE}} -- -v - if: matrix.os == 'macos-10.15' - - - name: Build & Sign App Bundle (macOS) - run: | - security -v unlock-keychain -p gpgfrontend - macdeployqt ${{github.workspace}}/build/release/GpgFrontend.app - codesign --deep --force --options=runtime -s "Developer ID Application: Yu Hu (4279AWUL3X)" ${{github.workspace}}/build/release/GpgFrontend.app -v - mkdir ${{github.workspace}}/build/tmp/ + cmake -B ${{github.workspace}}/build -G Xcode \ + -DGPGFRONTEND_CONFIGURE_FOR_XCODE_BUILD=On \ + -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \ + -DGPGFRONTEND_XOCDE_CODE_SIGN_IDENTITY="${{secrets.GPGFRONTEND_XOCDE_CODE_SIGN_IDENTITY}}" \ + -DGPGFRONTEND_XCODE_TEAM_ID="${{secrets.GPGFRONTEND_XCODE_TEAM_ID}}" \ + -DGPGFRONTEND_XOCDE_APPID="${{secrets.GPGFRONTEND_XOCDE_APPID}}" \ + -DGPGFRONTEND_XOCDE_PROVISIONING_PROFILE_UUID="${{secrets.GPGFRONTEND_XOCDE_PROVISIONING_PROFILE_UUID}}" + xcodebuild -list -project ${{github.workspace}}/build/GpgFrontend.xcodeproj + cd ${{github.workspace}}/build/ + xcodebuild -scheme GpgFrontend -configuration "${{env.BUILD_TYPE}}"\ + -archivePath ${{github.workspace}}/build/GpgFrontend.xcarchive archive + mkdir ${{github.workspace}}/build/package + xcodebuild -exportArchive -archivePath ${{github.workspace}}/build/GpgFrontend.xcarchive \ + -exportOptionsPlist ${{github.workspace}}/build/ExportOptions.plist \ + -exportPath ${{github.workspace}}/build/package/ if: matrix.os == 'macos-10.15' - name: Package & Sign App Bundle (macOS) run: | security -v unlock-keychain -p gpgfrontend - hdiutil create ${{github.workspace}}/build/tmp/tmp.dmg -ov -volname "GpgFrontend" -fs HFS+ -srcfolder ${{github.workspace}}/build/release/ + ditto -c -k --keepParent ${{github.workspace}}/build/package/GpgFrontend.app ${{github.workspace}}/build/GpgFrontend.app.zip + hdiutil create ${{github.workspace}}/build/tmp.dmg -ov \ + -volname "GpgFrontend" -fs HFS+ -srcfolder ${{github.workspace}}/build/package/ mkdir ${{github.workspace}}/build/artifactOut - hdiutil convert ${{github.workspace}}/build/tmp/tmp.dmg -format UDZO -o ${{github.workspace}}/build/artifactOut/GpgFrontend.dmg - codesign -s "Developer ID Application: Yu Hu (4279AWUL3X)" ${{github.workspace}}/build/artifactOut/GpgFrontend.dmg - mv ${{github.workspace}}/build/artifactOut/GpgFrontend.dmg ${{github.workspace}}/build/artifactOut/GpgFrontend-${{steps.vars.outputs.sha_short}}-x86_64.dmg + hdiutil convert ${{github.workspace}}/build/tmp.dmg -format UDZO -o ${{github.workspace}}/build/artifactOut/GpgFrontend.dmg + codesign -s "${{secrets.GPGFRONTEND_XOCDE_CODE_SIGN_IDENTITY}}" ${{github.workspace}}/build/artifactOut/GpgFrontend.dmg + mv ${{github.workspace}}/build/artifactOut/GpgFrontend.dmg \ + ${{github.workspace}}/build/artifactOut/GpgFrontend-${{steps.vars.outputs.sha_short}}-x86_64.dmg + mv ${{github.workspace}}/build/GpgFrontend.app.zip \ + ${{github.workspace}}/build/GpgFrontend-${{steps.vars.outputs.sha_short}}-x86_64.zip if: matrix.os == 'macos-10.15' - name: Notarize Release Build (macOS) run: | - xcrun altool --notarize-app -f ${{github.workspace}}/build/artifactOut/GpgFrontend-${{steps.vars.outputs.sha_short}}-x86_64.dmg --primary-bundle-id pub.gpgfrontend.gpgfrontend -u ${{secrets.APPLE_DEVELOPER_ID}} -p ${{secrets.APPLE_DEVELOPER_ID_SECRET}} + xcrun altool --notarize-app \ + -f ${{github.workspace}}/build/GpgFrontend-${{steps.vars.outputs.sha_short}}-x86_64.zip \ + --primary-bundle-id ${{secrets.GPGFRONTEND_XOCDE_APPID}} \ + -u ${{secrets.APPLE_DEVELOPER_ID}} \ + -p ${{secrets.APPLE_DEVELOPER_ID_SECRET}} if: matrix.os == 'macos-10.15' - name: Package App Image (Linux) diff --git a/CMakeLists.txt b/CMakeLists.txt index e93de668..eecb01b0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,7 +57,10 @@ option(GPGFRONTEND_BUILD_TYPE_STABLE option(GPGFRONTEND_GENERATE_LINUX_INSTALL_SOFTWARE "Generate an installable version" OFF) option(GPGFRONTEND_GENERATE_APP_PACKAGE_DEB "Generate DEB package" OFF) option(GPGFRONTEND_CONFIGURE_FOR_XCODE_BUILD "Generate a version that can be successfully compiled and packaged in Xcode" OFF) -option(GPGFRONTEND_XOCDE_CODE_SIGN_IDENTITY "GpgFrontend Signing Certificate" "") +option(GPGFRONTEND_XCODE_TEAM_ID "GpgFrontend Apple Team ID" "NONE") +option(GPGFRONTEND_XOCDE_CODE_SIGN_IDENTITY "GpgFrontend Signing Certificate" "NONE") +option(GPGFRONTEND_XOCDE_APPID "GpgFrontend Apple AppID" "NONE") +option(GPGFRONTEND_XOCDE_PROVISIONING_PROFILE_UUID "GpgFrontend ProvisioningProfile UUID" "NONE") # analyse options if (GPGFRONTEND_BUILD_TYPE_TEST_CORE) @@ -276,12 +276,8 @@ AppImage: https://appimage.org JSON for Modern C++: https://github.com/nlohmann/json -SMTP Client for Qt (C++): https://github.com/bluetiger9/SmtpClient-for-Qt - Qt-AES: https://github.com/saturneric/Qt-AES -vmime: https://www.vmime.org/ - MacOS Application Bundles: [Link](https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFBundles/BundleTypes/BundleTypes.html#//apple_ref/doc/uid/10000123i-CH101-SW1) diff --git a/manual/_coverpage.md b/manual/_coverpage.md index 53544d54..0526b916 100644 --- a/manual/_coverpage.md +++ b/manual/_coverpage.md @@ -1,33 +1,30 @@  # GpgFrontend - - - - +--- + + + [](https://www.codacy.com/gh/saturneric/GpgFrontend/dashboard?utm_source=github.com&utm_medium=referral&utm_content=saturneric/GpgFrontend&utm_campaign=Badge_Grade) -**A Free, Powerful, Easy-to-Use, Compact, Cross-Platform, and Installation-Free [OpenPGP(pgp)](https://www.openpgp.org/) -Crypto Tool.** - -**Also, it's one of the excellent GUI Frontends for Modern GnuPG(gpg).** +- **A Free, Easy-to-Use, Cross-Platform [OpenPGP](https://www.openpgp.org/) Crypto Tool.** +- **One of the excellent GUI Frontends for Modern [GnuPG](https://gnupg.org/).** ## Brief Introduction -You can quickly make encrypted documents or email. - -You can digitally sign your text or documents. - -You can easily and intuitively manage all your keys on your computer. +- You can quickly make encrypted documents or text. +- You can digitally sign your text or documents. +- You can easily manage all your gpg keys on your computer. ## Features - Cross-Platform, can run on **Windows, Linux and macOS**. -- Open source, installation-free and free forever. -- Supports multiple languages. Languages spoken by most people in the world. +- Open source, Installation-free and Free forever. +- Supports multiple languages. -[Download](https://github.com/saturneric/GpgFrontend/releases/latest) +[Downloads](downloads.md) [Manual](overview.md) +[Document](https://doxygen.gpgfrontend.pub) <!-- 背景色 -->  diff --git a/manual/_navbar.md b/manual/_navbar.md index 050f600c..b93a35df 100644 --- a/manual/_navbar.md +++ b/manual/_navbar.md @@ -1,9 +1,8 @@ <!-- _navbar.md --> * [Source Code(Global CDN)](https://global.git.codesdream.com/GpgFrontend.git) -* [GitHub Repository](https://github.com/saturneric/GpgFrontend) -* [Developer Document](https://doxygen.gpgfrontend.pub) +* [Document](https://doxygen.gpgfrontend.pub) * [Manual](overview.md) -* [Download](https://github.com/saturneric/GpgFrontend/releases/latest) +* [Download](download.md) * [Contract](contract.md) diff --git a/manual/_sidebar.md b/manual/_sidebar.md index 26a39c9f..f07fb50a 100644 --- a/manual/_sidebar.md +++ b/manual/_sidebar.md @@ -1,11 +1,12 @@ - Getting Start - [Overview](overview.md) - [Quick Start](quick-start.md) + - [Downloads](downloads.md) - [Basic concepts](basic-concepts.md) - Manual - [Understand Interface](manual/understand-interface.md) - [Encrypt & Decrypt Text](manual/encrypt-decrypt-text.md) - - Symmetric Encrypt & Decrypt Text + - [Symmetric Encrypt & Decrypt Text](manual/symmetric-encrypt-decrypt-text.md) - [Sign & Verify Text](manual/sign-verify-text.md) - [Encrypt & Decrypt File](manual/encrypt-decrypt-file.md) - [Sign & Verify File](manual/sign-verify-file.md) diff --git a/manual/downloads.md b/manual/downloads.md new file mode 100644 index 00000000..bedf505d --- /dev/null +++ b/manual/downloads.md @@ -0,0 +1,17 @@ +# Downloads + +Currently you can download GpgFrontend through various channels. + +--- + +## GitHub Releases + +[](https://github.com/saturneric/GpgFrontend/releases/latest) + +## SourgeForge + +[](https://sourceforge.net/projects/gogfrontend/files/latest/download) + +## Microsoft Store + +<ms-store-badge productid="9NH716MQK2B5" size="small"></ms-store-badge>
\ No newline at end of file diff --git a/manual/index.html b/manual/index.html index 2e07158b..57ca67e3 100644 --- a/manual/index.html +++ b/manual/index.html @@ -6,20 +6,23 @@ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /> <meta name="description" content="Description"> <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0"> - <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify@4/lib/themes/vue.css"> + <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/docsify-themeable@0/dist/css/theme-defaults.css"> <link rel="shortcut icon" href="/_media/icon.svg" type="image/x-icon"> </head> <body> <div id="app"></div> <script> window.$docsify = { - logo: '/_media/trademark.png', - name: 'GpgFrontend', + search: 'auto', + logo: '/_media/trademark.png', + name: 'GpgFrontend', loadNavbar: true, loadSidebar: true, coverpage: true, onlyCover: true, subMaxLevel: 3, + repo: 'https://github.com/saturneric/GpgFrontend', + mergeNavbar: true, alias: { '/.*/_sidebar.md': '/_sidebar.md' } @@ -29,5 +32,7 @@ <script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/emoji.min.js"></script> <script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-bash.min.js"></script> <script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-php.min.js"></script> + <script src="//cdn.jsdelivr.net/npm/docsify-edit-on-github"></script> + <script type="module" src="https://getbadgecdn.azureedge.net/ms-store-badge.bundled.js"></script> </body> </html> diff --git a/manual/manual/symmetric-encrypt-decrypt-text.md b/manual/manual/symmetric-encrypt-decrypt-text.md new file mode 100644 index 00000000..fb469277 --- /dev/null +++ b/manual/manual/symmetric-encrypt-decrypt-text.md @@ -0,0 +1,5 @@ +# Symmetric Encrypt & Decrypt Text + +Symmetric encryption will be triggered when you click the Encrypt button and do not check any key in the Key Toolbox. +For symmetric encryption, you need to set a password for your encryption process. When decrypting, you need to enter +the same password as the encryption process.
\ No newline at end of file diff --git a/resource/plist/ExportOptions.plist.in b/resource/plist/ExportOptions.plist.in new file mode 100644 index 00000000..48a6567d --- /dev/null +++ b/resource/plist/ExportOptions.plist.in @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>method</key> + <string>developer-id</string> + <key>teamID</key> + <string>@GPGFRONTEND_XCODE_TEAM_ID@</string> + <key>compileBitcode</key> + <true/> + <key>signingStyle</key> + <string>automatic</string> + <key>signingCertificate</key> + <string>@GPGFRONTEND_XOCDE_CODE_SIGN_IDENTITY@</string> + <key>provisioningProfiles</key> + <dict> + <key>@GPGFRONTEND_XOCDE_APPID@</key> + <string>@GPGFRONTEND_XOCDE_PROVISIONING_PROFILE_UUID@</string> + </dict> +</dict> +</plist>
\ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5d61564d..fb38cb9a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -129,6 +129,9 @@ if (BASIC_ENV_CONFIG) configure_file(${CMAKE_SOURCE_DIR}/src/GpgFrontend.h.in ${CMAKE_SOURCE_DIR}/src/GpgFrontend.h @ONLY) configure_file(${CMAKE_SOURCE_DIR}/src/GpgFrontendBuildInfo.h.in ${CMAKE_SOURCE_DIR}/src/GpgFrontendBuildInfo.h @ONLY) configure_file(${CMAKE_SOURCE_DIR}/src/GpgFrontendBuildInstallInfo.h.in ${CMAKE_SOURCE_DIR}/src/GpgFrontendBuildInstallInfo.h @ONLY) + if(APPLE) + configure_file(${CMAKE_SOURCE_DIR}/resource/plist/ExportOptions.plist.in ${CMAKE_BINARY_DIR}/ExportOptions.plist @ONLY) + endif () endif () if (APPLICATION_BUILD) @@ -320,7 +323,7 @@ if (LINUX AND LINUX_INSTALL_SOFTWARE) set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "amd64") set(CPACK_PACKAGE_CONTACT "[email protected]") SET(CPACK_DEBIAN_PACKAGE_MAINTAINER "Saturneric") - set(CPACK_DEBIAN_PACKAGE_DEPENDS "gpg (>= 2.2), libqt5core5a (>= 5.9), libqt5gui5 (>= 5.9), libqt5widgets5 (>= 5.9), libqt5network5 (>= 5.9), libqt5printsupport5 (>= 5.9), libconfig++9v5 (>=1.5), libarchive13(>= 3.4), openssl(>= 1.1.1)") + set(CPACK_DEBIAN_PACKAGE_DEPENDS "gpg (>= 2.2), libqt5core5a (>= 5.9), libqt5gui5 (>= 5.9), libqt5widgets5 (>= 5.9), libqt5network5 (>= 5.9), libqt5printsupport5 (>= 5.9), libconfig++9v5 (>=1.5), libarchive13(>= 3.4), openssl(>= 1.1.1), libicu66") set(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}") set(CPACK_PACKAGE_VERSION_MINOR "${PROJECT_VERSION_MINOR}") set(CPACK_PACKAGE_VERSION_PATCH "${PROJECT_VERSION_PATCH}") diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index ee0e39a1..c69c325d 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -80,6 +80,10 @@ target_link_libraries(gpgfrontend_core PUBLIC gpgme assuan gpg-error) target_link_libraries(gpgfrontend_core PUBLIC OpenSSL::SSL OpenSSL::Crypto) # link boost libraries target_link_libraries(gpgfrontend_core PUBLIC ${Boost_LIBRARIES}) +if(MINGW) + # for uuid ability in mingw + target_link_libraries(gpgfrontend_core PUBLIC bcrypt) +endif() # link libarchive target_link_libraries(gpgfrontend_core PRIVATE archive) diff --git a/src/core/thread/Task.cpp b/src/core/thread/Task.cpp index 9626ba69..7b8423b2 100644 --- a/src/core/thread/Task.cpp +++ b/src/core/thread/Task.cpp @@ -26,24 +26,48 @@ #include "core/thread/Task.h" +#include <boost/uuid/uuid.hpp> +#include <boost/uuid/uuid_generators.hpp> +#include <boost/uuid/uuid_io.hpp> #include <functional> +#include <string> +#include <utility> #include "core/thread/TaskRunner.h" +#include "easylogging++.h" -GpgFrontend::Thread::Task::Task() { init(); } +GpgFrontend::Thread::Task::Task() : uuid_(generate_uuid()) { + LOG(INFO) << "Task" << uuid_ << "created"; + init(); +} -GpgFrontend::Thread::Task::Task(TaskCallback callback) - : callback_(std::move(callback)) { +GpgFrontend::Thread::Task::Task(TaskCallback callback, + DataObjectPtr data_object) + : uuid_(generate_uuid()), + callback_(std::move(callback)), + callback_thread_(QThread::currentThread()), + data_object_(data_object) { + LOG(INFO) << "Task" << uuid_ << "created with callback" + << "callback_thread_: " << callback_thread_; init(); } -GpgFrontend::Thread::Task::Task(TaskRunnable runnable, TaskCallback callback) - : runnable_(runnable), callback_(std::move(callback)) { +GpgFrontend::Thread::Task::Task(TaskRunnable runnable, TaskCallback callback, + DataObjectPtr data_object) + : uuid_(generate_uuid()), + runnable_(std::move(runnable)), + callback_(std::move(callback)), + callback_thread_(QThread::currentThread()), + data_object_(data_object) { init(); + LOG(INFO) << "Task" << uuid_ << "created with runnable and callback" + << "callback_thread_: " << callback_thread_; } GpgFrontend::Thread::Task::~Task() = default; +std::string GpgFrontend::Thread::Task::GetUUID() const { return uuid_; } + void GpgFrontend::Thread::Task::SetFinishAfterRun(bool finish_after_run) { this->finish_after_run_ = finish_after_run; } @@ -51,24 +75,71 @@ void GpgFrontend::Thread::Task::SetFinishAfterRun(bool finish_after_run) { void GpgFrontend::Thread::Task::SetRTN(int rtn) { this->rtn_ = rtn; } void GpgFrontend::Thread::Task::init() { - LOG(INFO) << "called"; connect(this, &Task::SignalTaskFinished, this, &Task::before_finish_task); connect(this, &Task::SignalTaskFinished, this, &Task::deleteLater); } void GpgFrontend::Thread::Task::before_finish_task() { - LOG(INFO) << "called"; - if (callback_) callback_(rtn_); + LOG(INFO) << "Task" << uuid_ << "finished"; + if (callback_) { + bool if_invoke = QMetaObject::invokeMethod( + callback_thread_, + [callback = callback_, rtn = rtn_, data_object = data_object_]() { + callback(rtn, data_object); + }); + if (!if_invoke) { + LOG(ERROR) << "failed to invoke callback"; + } + } } void GpgFrontend::Thread::Task::run() { - LOG(INFO) << "called"; + LOG(INFO) << "Task" << uuid_ << "started"; Run(); if (finish_after_run_) emit SignalTaskFinished(); } void GpgFrontend::Thread::Task::Run() { if (runnable_) { - rtn_ = runnable_(); + bool if_invoke = QMetaObject::invokeMethod( + this, [=]() { return runnable_(data_object_); }, &rtn_); + if (!if_invoke) { + LOG(ERROR) << "invokeMethod failed"; + } + } +} + +GpgFrontend::Thread::Task::DataObject::Destructor * +GpgFrontend::Thread::Task::DataObject::get_heap_ptr(size_t bytes_size) { + Destructor *dstr_ptr = new Destructor(); + dstr_ptr->p_obj = malloc(bytes_size); + return dstr_ptr; +} + +GpgFrontend::Thread::Task::DataObject::~DataObject() { + if (!data_objects_.empty()) + LOG(WARNING) << "data_objects_ is not empty" + << "address:" << this; + while (!data_objects_.empty()) { + free_heap_ptr(data_objects_.top()); + data_objects_.pop(); + } +} + +size_t GpgFrontend::Thread::Task::DataObject::GetObjectSize() { + return data_objects_.size(); +} + +void GpgFrontend::Thread::Task::DataObject::free_heap_ptr(Destructor *ptr) { + LOG(INFO) << "p_obj: " << ptr->p_obj << "destructor: " << ptr->destroy + << "DataObject:" << this; + if (ptr->destroy != nullptr) { + ptr->destroy(ptr->p_obj); } + free((void *)ptr->p_obj); + delete ptr; +} + +std::string GpgFrontend::Thread::Task::generate_uuid() { + return boost::uuids::to_string(boost::uuids::random_generator()()); } diff --git a/src/core/thread/Task.h b/src/core/thread/Task.h index 4b536176..468a04b8 100644 --- a/src/core/thread/Task.h +++ b/src/core/thread/Task.h @@ -19,8 +19,10 @@ * The initial version of the source code is inherited from * the gpg4usb project, which is under GPL-3.0-or-later. * - * The source code version of this software was modified and released - * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later * */ @@ -28,6 +30,11 @@ #define GPGFRONTEND_TASK_H #include <functional> +#include <memory> +#include <stack> +#include <string> +#include <type_traits> +#include <utility> #include "core/GpgFrontendCore.h" @@ -38,11 +45,119 @@ class TaskRunner; class GPGFRONTEND_CORE_EXPORT Task : public QObject, public QRunnable { Q_OBJECT public: - using TaskRunnable = std::function<int()>; ///< - using TaskCallback = std::function<void(int)>; ///< + class DataObject; + using DataObjectPtr = std::shared_ptr<DataObject>; ///< + using TaskRunnable = std::function<int(DataObjectPtr)>; ///< + using TaskCallback = std::function<void(int, DataObjectPtr)>; ///< + friend class TaskRunner; /** + * @brief DataObject to be passed to the callback function. + * + */ + class GPGFRONTEND_CORE_EXPORT DataObject { + public: + struct Destructor { + const void *p_obj; + void (*destroy)(const void *); + }; + + /** + * @brief Get the Objects Size + * + * @return size_t + */ + size_t GetObjectSize(); + + /** + * @brief + * + * @tparam T + * @param ptr + */ + template <typename T> + void AppendObject(T &&obj) { + LOG(INFO) << "called:" << this; + auto *obj_dstr = this->get_heap_ptr(sizeof(T)); + auto *ptr_heap = new ((void *)obj_dstr->p_obj) T(std::move(obj)); + if (std::is_class_v<T>) { + auto destructor = [](const void *x) { + static_cast<const T *>(x)->~T(); + }; + obj_dstr->destroy = destructor; + } else { + obj_dstr->destroy = nullptr; + } + data_objects_.push(std::move(obj_dstr)); + } + + /** + * @brief + * + * @tparam T + * @param ptr + */ + template <typename T> + void AppendObject(T *obj) { + LOG(INFO) << "called:" << this; + auto *obj_dstr = this->get_heap_ptr(sizeof(T)); + auto *ptr_heap = new ((void *)obj_dstr->p_obj) T(std::move(*obj)); + if (std::is_class_v<T>) { + auto destructor = [](const void *x) { + static_cast<const T *>(x)->~T(); + }; + obj_dstr->destroy = destructor; + } else { + obj_dstr->destroy = nullptr; + } + data_objects_.push(std::move(obj_dstr)); + } + + /** + * @brief + * + * @tparam T + * @return std::shared_ptr<T> + */ + template <typename T> + T PopObject() { + LOG(INFO) << "called:" << this; + if (data_objects_.empty()) throw std::runtime_error("No object to pop"); + auto *obj_dstr = data_objects_.top(); + auto *heap_ptr = (T *)obj_dstr->p_obj; + auto obj = std::move(*(T *)(heap_ptr)); + this->free_heap_ptr(obj_dstr); + data_objects_.pop(); + return obj; + } + + /** + * @brief Destroy the Data Object object + * + */ + ~DataObject(); + + private: + std::stack<Destructor *> data_objects_; ///< + + /** + * @brief Get the heap ptr object + * + * @param bytes_size + * @return void* + */ + Destructor *get_heap_ptr(size_t bytes_size); + + /** + * @brief + * + * @param heap_ptr + */ + void free_heap_ptr(Destructor *); + }; + + /** * @brief Construct a new Task object * */ @@ -52,9 +167,8 @@ class GPGFRONTEND_CORE_EXPORT Task : public QObject, public QRunnable { * @brief Construct a new Task object * * @param callback The callback function to be executed. - * callback must not be nullptr, and not tp opreate UI object. */ - Task(TaskCallback callback); + Task(TaskCallback callback, DataObjectPtr data_object = nullptr); /** * @brief Construct a new Task object @@ -62,7 +176,9 @@ class GPGFRONTEND_CORE_EXPORT Task : public QObject, public QRunnable { * @param runnable */ Task( - TaskRunnable runnable, TaskCallback callback = [](int) {}); + TaskRunnable runnable, + TaskCallback callback = [](int, std::shared_ptr<DataObject>) {}, + DataObjectPtr data = nullptr); /** * @brief Destroy the Task object @@ -76,19 +192,43 @@ class GPGFRONTEND_CORE_EXPORT Task : public QObject, public QRunnable { */ virtual void Run(); + /** + * @brief + * + * @return std::string + */ + std::string GetUUID() const; + signals: + /** + * @brief + * + */ void SignalTaskFinished(); protected: + /** + * @brief Set the Finish After Run object + * + * @param finish_after_run + */ void SetFinishAfterRun(bool finish_after_run); + /** + * @brief + * + * @param rtn + */ void SetRTN(int rtn); private: - TaskCallback callback_; ///< - TaskRunnable runnable_; ///< - bool finish_after_run_ = true; ///< - int rtn_ = 0; ///< + const std::string uuid_; + TaskCallback callback_; ///< + TaskRunnable runnable_; ///< + bool finish_after_run_ = true; ///< + int rtn_ = 0; ///< + QThread *callback_thread_ = nullptr; ///< + DataObjectPtr data_object_ = nullptr; ///< /** * @brief @@ -107,6 +247,13 @@ class GPGFRONTEND_CORE_EXPORT Task : public QObject, public QRunnable { * */ virtual void run() override; + + /** + * @brief + * + * @return std::string + */ + static std::string generate_uuid(); }; } // namespace GpgFrontend::Thread diff --git a/src/core/thread/TaskRunner.cpp b/src/core/thread/TaskRunner.cpp index 2223bdda..3b565abb 100644 --- a/src/core/thread/TaskRunner.cpp +++ b/src/core/thread/TaskRunner.cpp @@ -26,6 +26,8 @@ #include "core/thread/TaskRunner.h" +#include <exception> + #include "core/thread/Task.h" #include "easylogging++.h" @@ -34,7 +36,9 @@ GpgFrontend::Thread::TaskRunner::TaskRunner() = default; GpgFrontend::Thread::TaskRunner::~TaskRunner() = default; void GpgFrontend::Thread::TaskRunner::PostTask(Task* task) { - LOG(INFO) << "called"; + LOG(INFO) << "called" + << "Post Task" << task->GetUUID(); + if (task == nullptr) return; task->setParent(nullptr); task->moveToThread(this); @@ -46,13 +50,14 @@ void GpgFrontend::Thread::TaskRunner::PostTask(Task* task) { } void GpgFrontend::Thread::TaskRunner::run() { - LOG(INFO) << "called"; + LOG(INFO) << "called" + << "thread id:" << QThread::currentThreadId(); while (true) { if (tasks.empty()) { - LOG(INFO) << "TaskRunner: No tasks to run"; + LOG(INFO) << "TaskRunner: No tasks to run."; exec(); } else { - LOG(INFO) << "TaskRunner: Running task, queue size:" << tasks.size(); + LOG(INFO) << "TaskRunner: Queue size:" << tasks.size(); Task* task = nullptr; { @@ -60,7 +65,20 @@ void GpgFrontend::Thread::TaskRunner::run() { task = std::move(tasks.front()); tasks.pop(); } - if (task != nullptr) task->run(); + + if (task != nullptr) { + // Run the task + LOG(INFO) << "TaskRunner: Running Task" << task->GetUUID(); + try { + task->run(); + } catch (const std::exception& e) { + LOG(ERROR) << "TaskRunner: Exception in Task" << task->GetUUID() + << "Exception: " << e.what(); + } catch (...) { + LOG(ERROR) << "TaskRunner: Unknwon Exception in Task" + << task->GetUUID(); + } + } } } } diff --git a/src/core/thread/ThreadingModel.h b/src/core/thread/ThreadingModel.h new file mode 100644 index 00000000..eb6c9039 --- /dev/null +++ b/src/core/thread/ThreadingModel.h @@ -0,0 +1,36 @@ +/** + * Copyright (C) 2021 Saturneric + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef GPGFRONTEND_THREADINGMODEL_H +#define GPGFRONTEND_THREADINGMODEL_H + +#include "core/thread/Task.h" +#include "core/thread/TaskRunner.h" +#include "core/thread/TaskRunnerGetter.h" + +#endif // GPGFRONTEND_THREADINGMODEL_H
\ No newline at end of file diff --git a/src/ui/GpgFrontendUI.h b/src/ui/GpgFrontendUI.h index b355ec85..4389aa41 100644 --- a/src/ui/GpgFrontendUI.h +++ b/src/ui/GpgFrontendUI.h @@ -44,7 +44,7 @@ #include "GpgFrontend.h" #include "core/GpgFrontendCore.h" #include "core/GpgModel.h" - +#include "core/thread/ThreadingModel.h" #include "ui/GpgFrontendUIExport.h" /** diff --git a/src/ui/UserInterfaceUtils.cpp b/src/ui/UserInterfaceUtils.cpp index 65c55c8f..adcbd6ff 100644 --- a/src/ui/UserInterfaceUtils.cpp +++ b/src/ui/UserInterfaceUtils.cpp @@ -114,21 +114,29 @@ void process_result_analyse(TextEdit *edit, InfoBoardWidget *info_board, } void process_operation(QWidget *parent, const std::string &waiting_title, - const std::function<void()> &func) { + const Thread::Task::TaskRunnable func, + const Thread::Task::TaskCallback callback, + Thread::Task::DataObjectPtr data_object) { auto *dialog = new WaitingDialog(QString::fromStdString(waiting_title), parent); - auto thread = QThread::create(func); - QApplication::connect(thread, &QThread::finished, thread, - &QThread::deleteLater); - QApplication::connect(thread, &QThread::finished, dialog, &QDialog::close); - QApplication::connect(thread, &QThread::finished, dialog, - &QDialog::deleteLater); + auto *process_task = + new Thread::Task(std::move(func), std::move(callback), data_object); + + QApplication::connect(process_task, &Thread::Task::SignalTaskFinished, dialog, + &QDialog::close); QEventLoop looper; - QApplication::connect(dialog, &QDialog::finished, &looper, &QEventLoop::quit); + QApplication::connect(process_task, &Thread::Task::SignalTaskFinished, + &looper, &QEventLoop::quit); - thread->start(); + // post process task to task runner + Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_GPG) + ->PostTask(process_task); + + // block until task finished + // this is to keep reference vaild until task finished looper.exec(); } @@ -350,7 +358,7 @@ void CommonUtils::SlotImportKeyFromKeyServer( void CommonUtils::slot_update_key_status() { LOG(INFO) << "called"; - auto refresh_task = new Thread::Task([]() -> int { + auto refresh_task = new Thread::Task([](Thread::Task::DataObjectPtr) -> int { // flush key cache for all GpgKeyGetter Intances. for (const auto &channel_id : GpgKeyGetter::GetAllChannelId()) { GpgKeyGetter::GetInstance(channel_id).FlushKeyCache(); diff --git a/src/ui/UserInterfaceUtils.h b/src/ui/UserInterfaceUtils.h index 85ef012b..bfd8a3ae 100644 --- a/src/ui/UserInterfaceUtils.h +++ b/src/ui/UserInterfaceUtils.h @@ -101,8 +101,11 @@ void process_result_analyse(TextEdit* edit, InfoBoardWidget* info_board, * @param waiting_title * @param func */ -void process_operation(QWidget* parent, const std::string& waiting_title, - const std::function<void()>& func); +void process_operation( + QWidget* parent, const std::string& waiting_title, + GpgFrontend::Thread::Task::TaskRunnable func, + GpgFrontend::Thread::Task::TaskCallback callback = nullptr, + Thread::Task::DataObjectPtr data_object = nullptr); /** * @brief diff --git a/src/ui/main_window/MainWindowFileSlotFunction.cpp b/src/ui/main_window/MainWindowFileSlotFunction.cpp index d1288a1b..4ab23a22 100644 --- a/src/ui/main_window/MainWindowFileSlotFunction.cpp +++ b/src/ui/main_window/MainWindowFileSlotFunction.cpp @@ -31,6 +31,7 @@ #include "core/function/GlobalSettingStation.h" #include "core/function/gpg/GpgFileOpera.h" #include "core/function/gpg/GpgKeyGetter.h" +#include "core/thread/Task.h" #include "ui/UserInterfaceUtils.h" #include "ui/widgets/SignersPicker.h" @@ -66,7 +67,6 @@ bool path_pre_check(QWidget* parent, const QString& path) { */ bool process_tarball_into_directory(QWidget* parent, std::filesystem::path& path) { - LOG(INFO) << "Converting directory into tarball" << path; auto selected_dir_path = std::filesystem::path(path); @@ -85,14 +85,16 @@ bool process_tarball_into_directory(QWidget* parent, << target_path.u8string(); bool if_error = false; - process_operation(parent, _("Extracting Tarball"), [&]() { - try { - GpgFrontend::ArchiveFileOperator::ExtractArchive(target_path, - base_path); - } catch (const std::runtime_error& e) { - if_error = true; - } - }); + process_operation(parent, _("Extracting Tarball"), + [&](Thread::Task::DataObjectPtr) -> int { + try { + GpgFrontend::ArchiveFileOperator::ExtractArchive( + target_path, base_path); + } catch (const std::runtime_error& e) { + if_error = true; + } + return 0; + }); if (if_error || !exists(target_path)) { throw std::runtime_error("Decompress Failed"); @@ -112,7 +114,6 @@ bool process_tarball_into_directory(QWidget* parent, * @param path the tarball to be converted */ bool process_directory_into_tarball(QWidget* parent, QString& path) { - #ifdef WINDOWS std::filesystem::path selected_dir_path = path.toStdU16String(); #else @@ -128,14 +129,16 @@ bool process_directory_into_tarball(QWidget* parent, QString& path) { << target_path << "selected_dir_path" << selected_dir_path; bool if_error = false; - process_operation(parent, _("Making Tarball"), [&]() { - try { - GpgFrontend::ArchiveFileOperator::CreateArchive(base_path, target_path, - 0, {selected_dir_path}); - } catch (const std::runtime_error& e) { - if_error = true; - } - }); + process_operation(parent, _("Making Tarball"), + [&](Thread::Task::DataObjectPtr) -> int { + try { + GpgFrontend::ArchiveFileOperator::CreateArchive( + base_path, target_path, 0, {selected_dir_path}); + } catch (const std::runtime_error& e) { + if_error = true; + } + return 0; + }); if (if_error || !exists(target_path)) { throw std::runtime_error("Compress Failed"); @@ -223,14 +226,17 @@ void MainWindow::SlotFileEncrypt() { if (ret == QMessageBox::Cancel) return; - process_operation(this, _("Symmetrically Encrypting"), [&]() { - try { - error = GpgFrontend::GpgFileOpera::EncryptFileSymmetric( - path.toStdString(), out_path.toStdString(), result, _channel); - } catch (const std::runtime_error& e) { - if_error = true; - } - }); + process_operation( + this, _("Symmetrically Encrypting"), + [&](Thread::Task::DataObjectPtr) -> int { + try { + error = GpgFrontend::GpgFileOpera::EncryptFileSymmetric( + path.toStdString(), out_path.toStdString(), result, _channel); + } catch (const std::runtime_error& e) { + if_error = true; + } + return 0; + }); } else { auto p_keys = GpgKeyGetter::GetInstance().GetKeys(key_ids); @@ -248,15 +254,17 @@ void MainWindow::SlotFileEncrypt() { } } - process_operation(this, _("Encrypting"), [&]() { - try { - error = - GpgFileOpera::EncryptFile(std::move(p_keys), path.toStdString(), - out_path.toStdString(), result, _channel); - } catch (const std::runtime_error& e) { - if_error = true; - } - }); + process_operation(this, _("Encrypting"), + [&](Thread::Task::DataObjectPtr) -> int { + try { + error = GpgFileOpera::EncryptFile( + std::move(p_keys), path.toStdString(), + out_path.toStdString(), result, _channel); + } catch (const std::runtime_error& e) { + if_error = true; + } + return 0; + }); } // remove xxx.tar and only left xxx.tar.gpg @@ -310,14 +318,16 @@ void MainWindow::SlotFileDecrypt() { GpgDecrResult result = nullptr; gpgme_error_t error; bool if_error = false; - process_operation(this, _("Decrypting"), [&]() { - try { - error = GpgFileOpera::DecryptFile(path.toStdString(), out_path.u8string(), - result); - } catch (const std::runtime_error& e) { - if_error = true; - } - }); + process_operation(this, _("Decrypting"), + [&](Thread::Task::DataObjectPtr) -> int { + try { + error = GpgFileOpera::DecryptFile( + path.toStdString(), out_path.u8string(), result); + } catch (const std::runtime_error& e) { + if_error = true; + } + return 0; + }); if (!if_error) { auto resultAnalyse = GpgDecryptResultAnalyse(error, std::move(result)); @@ -349,7 +359,6 @@ void MainWindow::SlotFileDecrypt() { } } } - } void MainWindow::SlotFileSign() { @@ -419,14 +428,17 @@ void MainWindow::SlotFileSign() { gpgme_error_t error; bool if_error = false; - process_operation(this, _("Signing"), [&]() { - try { - error = GpgFileOpera::SignFile(std::move(keys), in_path.u8string(), - sig_file_path.u8string(), result, _channel); - } catch (const std::runtime_error& e) { - if_error = true; - } - }); + process_operation( + this, _("Signing"), [&](Thread::Task::DataObjectPtr) -> int { + try { + error = GpgFileOpera::SignFile(std::move(keys), in_path.u8string(), + sig_file_path.u8string(), result, + _channel); + } catch (const std::runtime_error& e) { + if_error = true; + } + return 0; + }); if (!if_error) { auto resultAnalyse = GpgSignResultAnalyse(error, std::move(result)); @@ -480,9 +492,9 @@ void MainWindow::SlotFileVerify() { if (in_path.extension() != ".gpg") { bool ok; - QString text = QInputDialog::getText(this, _("Origin file to verify"), - _("Filepath"), QLineEdit::Normal, - data_file_path.u8string().c_str(), &ok); + QString text = QInputDialog::getText( + this, _("Origin file to verify"), _("Filepath"), QLineEdit::Normal, + data_file_path.u8string().c_str(), &ok); if (ok && !text.isEmpty()) { data_file_path = text.toStdString(); } else { @@ -505,14 +517,17 @@ void MainWindow::SlotFileVerify() { GpgVerifyResult result = nullptr; gpgme_error_t error; bool if_error = false; - process_operation(this, _("Verifying"), [&]() { - try { - error = GpgFileOpera::VerifyFile( - data_file_path.u8string(), sign_file_path.u8string(), result, _channel); - } catch (const std::runtime_error& e) { - if_error = true; - } - }); + process_operation( + this, _("Verifying"), [&](Thread::Task::DataObjectPtr) -> int { + try { + error = GpgFileOpera::VerifyFile(data_file_path.u8string(), + sign_file_path.u8string(), result, + _channel); + } catch (const std::runtime_error& e) { + if_error = true; + } + return 0; + }); if (!if_error) { auto result_analyse = GpgVerifyResultAnalyse(error, result); @@ -622,15 +637,18 @@ void MainWindow::SlotFileEncryptSign() { gpgme_error_t error; bool if_error = false; - process_operation(this, _("Encrypting and Signing"), [&]() { - try { - error = GpgFileOpera::EncryptSignFile( - std::move(p_keys), std::move(p_signer_keys), path.toStdString(), - out_path.toStdString(), encr_result, sign_result, _channel); - } catch (const std::runtime_error& e) { - if_error = true; - } - }); + process_operation(this, _("Encrypting and Signing"), + [&](Thread::Task::DataObjectPtr) -> int { + try { + error = GpgFileOpera::EncryptSignFile( + std::move(p_keys), std::move(p_signer_keys), + path.toStdString(), out_path.toStdString(), + encr_result, sign_result, _channel); + } catch (const std::runtime_error& e) { + if_error = true; + } + return 0; + }); if (!if_error) { auto encrypt_result = @@ -656,7 +674,6 @@ void MainWindow::SlotFileEncryptSign() { std::filesystem::remove(target_path); } } - } void MainWindow::SlotFileDecryptVerify() { @@ -694,14 +711,17 @@ void MainWindow::SlotFileDecryptVerify() { GpgVerifyResult v_result = nullptr; gpgme_error_t error; bool if_error = false; - process_operation(this, _("Decrypting and Verifying"), [&]() { - try { - error = GpgFileOpera::DecryptVerifyFile( - path.toStdString(), out_path.u8string(), d_result, v_result); - } catch (const std::runtime_error& e) { - if_error = true; - } - }); + process_operation(this, _("Decrypting and Verifying"), + [&](Thread::Task::DataObjectPtr) -> int { + try { + error = GpgFileOpera::DecryptVerifyFile( + path.toStdString(), out_path.u8string(), d_result, + v_result); + } catch (const std::runtime_error& e) { + if_error = true; + } + return 0; + }); if (!if_error) { auto decrypt_res = GpgDecryptResultAnalyse(error, std::move(d_result)); @@ -741,7 +761,6 @@ void MainWindow::SlotFileDecryptVerify() { } } } - } } // namespace GpgFrontend::UI diff --git a/src/ui/main_window/MainWindowSlotFunction.cpp b/src/ui/main_window/MainWindowSlotFunction.cpp index a1db4d61..910a7bf2 100644 --- a/src/ui/main_window/MainWindowSlotFunction.cpp +++ b/src/ui/main_window/MainWindowSlotFunction.cpp @@ -26,11 +26,20 @@ * */ +#include <cstddef> +#include <memory> +#include <string> +#include <utility> + #include "MainWindow.h" +#include "core/GpgConstants.h" +#include "core/GpgModel.h" #include "core/function/GlobalSettingStation.h" #include "core/function/gpg/GpgBasicOperator.h" #include "core/function/gpg/GpgKeyGetter.h" #include "core/function/gpg/GpgKeyImportExporter.h" +#include "core/model/GpgKey.h" +#include "core/thread/TaskRunner.h" #include "ui/UserInterfaceUtils.h" #include "ui/help/AboutDialog.h" #include "ui/widgets/SignersPicker.h" @@ -47,10 +56,41 @@ void MainWindow::slot_encrypt() { auto key_ids = m_key_list_->GetChecked(); - GpgEncrResult result = nullptr; - GpgError error; - bool if_error = false; - auto tmp = std::make_unique<ByteArray>(); + // data to transfer into task + auto data_object = std::make_shared<Thread::Task::DataObject>(); + + // set input buffer + auto buffer = + edit_->CurTextPage()->GetTextPage()->toPlainText().toStdString(); + data_object->AppendObject(std::move(buffer)); + + // the callback function + auto result_callback = [this](int rtn, + Thread::Task::DataObjectPtr data_object) { + if (!rtn) { + if (data_object->GetObjectSize() != 3) + throw std::runtime_error("Invalid data object size"); + auto error = data_object->PopObject<GpgError>(); + auto result = data_object->PopObject<GpgEncrResult>(); + auto tmp = data_object->PopObject<std::unique_ptr<ByteArray>>(); + + auto resultAnalyse = GpgEncryptResultAnalyse(error, std::move(result)); + resultAnalyse.Analyse(); + process_result_analyse(edit_, info_board_, resultAnalyse); + + if (check_gpg_error_2_err_code(error) == GPG_ERR_NO_ERROR) + edit_->SlotFillTextEditWithText(QString::fromStdString(*tmp)); + info_board_->ResetOptionActionsMenu(); + } else { + QMessageBox::critical(this, _("Error"), + _("An error occurred during operation.")); + return; + } + }; + + Thread::Task::TaskRunnable encrypt_runner = nullptr; + + std::string encrypt_type = ""; if (key_ids->empty()) { // Symmetric Encrypt @@ -62,16 +102,26 @@ void MainWindow::slot_encrypt() { if (ret == QMessageBox::Cancel) return; - process_operation(this, _("Symmetrically Encrypting"), [&]() { + encrypt_type = _("Symmetrically Encrypting"); + encrypt_runner = [](Thread::Task::DataObjectPtr data_object) -> int { + if (data_object == nullptr || data_object->GetObjectSize() != 1) + throw std::runtime_error("Invalid data object size"); + auto buffer = data_object->PopObject<std::string>(); try { - auto buffer = - edit_->CurTextPage()->GetTextPage()->toPlainText().toStdString(); - error = GpgFrontend::GpgBasicOperator::GetInstance().EncryptSymmetric( - buffer, tmp, result); + GpgEncrResult result = nullptr; + auto tmp = std::make_unique<ByteArray>(); + GpgError error = + GpgFrontend::GpgBasicOperator::GetInstance().EncryptSymmetric( + buffer, tmp, result); + data_object->AppendObject(std::move(tmp)); + data_object->AppendObject(std::move(result)); + data_object->AppendObject(std::move(error)); } catch (const std::runtime_error& e) { - if_error = true; + return -1; } - }); + return 0; + }; + } else { auto& key_getter = GpgFrontend::GpgKeyGetter::GetInstance(); auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids); @@ -88,32 +138,36 @@ void MainWindow::slot_encrypt() { } } - process_operation(this, _("Encrypting"), [&]() { + // push the keys into data object + data_object->AppendObject(std::move(keys)); + + // Asymmetric Encrypt + encrypt_type = _("Encrypting"); + encrypt_runner = [](Thread::Task::DataObjectPtr data_object) -> int { + // check the size of the data object + if (data_object == nullptr || data_object->GetObjectSize() != 2) + throw std::runtime_error("Invalid data object size"); + + auto keys = data_object->PopObject<KeyListPtr>(); + auto buffer = data_object->PopObject<std::string>(); try { - auto buffer = - edit_->CurTextPage()->GetTextPage()->toPlainText().toStdString(); - error = GpgFrontend::GpgBasicOperator::GetInstance().Encrypt( + GpgEncrResult result = nullptr; + auto tmp = std::make_unique<ByteArray>(); + GpgError error = GpgFrontend::GpgBasicOperator::GetInstance().Encrypt( std::move(keys), buffer, tmp, result); + + data_object->AppendObject(std::move(tmp)); + data_object->AppendObject(std::move(result)); + data_object->AppendObject(std::move(error)); } catch (const std::runtime_error& e) { - if_error = true; + return -1; } - }); - } - - if (!if_error) { - LOG(INFO) << "result" << result.get(); - auto resultAnalyse = GpgEncryptResultAnalyse(error, std::move(result)); - resultAnalyse.Analyse(); - process_result_analyse(edit_, info_board_, resultAnalyse); - - if (check_gpg_error_2_err_code(error) == GPG_ERR_NO_ERROR) - edit_->SlotFillTextEditWithText(QString::fromStdString(*tmp)); - info_board_->ResetOptionActionsMenu(); - } else { - QMessageBox::critical(this, _("Error"), - _("An error occurred during operation.")); - return; + return 0; + }; } + // Do the task + process_operation(this, _("Encrypting"), std::move(encrypt_runner), + std::move(result_callback), data_object); } void MainWindow::slot_sign() { @@ -145,38 +199,61 @@ void MainWindow::slot_sign() { } } - auto tmp = std::make_unique<ByteArray>(); + // data to transfer into task + auto data_object = std::make_shared<Thread::Task::DataObject>(); - GpgSignResult result = nullptr; - gpgme_error_t error; - bool if_error = false; + // set input buffer + auto buffer = + edit_->CurTextPage()->GetTextPage()->toPlainText().toStdString(); + data_object->AppendObject(std::move(buffer)); + + // push the keys into data object + data_object->AppendObject(std::move(keys)); + + auto sign_ruunner = [](Thread::Task::DataObjectPtr data_object) -> int { + // check the size of the data object + if (data_object == nullptr || data_object->GetObjectSize() != 2) + throw std::runtime_error("Invalid data object size"); - process_operation(this, _("Signing"), [&]() { + auto keys = data_object->PopObject<KeyListPtr>(); + auto buffer = data_object->PopObject<std::string>(); try { - auto buffer = edit_->CurTextPage() - ->GetTextPage() - ->toPlainText() - .toUtf8() - .toStdString(); - error = GpgFrontend::GpgBasicOperator::GetInstance().Sign( + GpgSignResult result = nullptr; + auto tmp = std::make_unique<ByteArray>(); + GpgError error = GpgFrontend::GpgBasicOperator::GetInstance().Sign( std::move(keys), buffer, tmp, GPGME_SIG_MODE_CLEAR, result); + data_object->AppendObject(std::move(tmp)); + data_object->AppendObject(std::move(result)); + data_object->AppendObject(std::move(error)); } catch (const std::runtime_error& e) { - if_error = true; + return -1; } - }); - - if (!if_error) { - auto resultAnalyse = GpgSignResultAnalyse(error, std::move(result)); - resultAnalyse.Analyse(); - process_result_analyse(edit_, info_board_, resultAnalyse); + return 0; + }; + + auto result_callback = [this](int rtn, + Thread::Task::DataObjectPtr data_object) { + if (!rtn) { + if (data_object == nullptr || data_object->GetObjectSize() != 3) + throw std::runtime_error("Invalid data object size"); + auto error = data_object->PopObject<GpgError>(); + auto result = data_object->PopObject<GpgSignResult>(); + auto tmp = data_object->PopObject<std::unique_ptr<ByteArray>>(); + auto resultAnalyse = GpgSignResultAnalyse(error, std::move(result)); + resultAnalyse.Analyse(); + process_result_analyse(edit_, info_board_, resultAnalyse); + + if (check_gpg_error_2_err_code(error) == GPG_ERR_NO_ERROR) + edit_->SlotFillTextEditWithText(QString::fromStdString(*tmp)); + } else { + QMessageBox::critical(this, _("Error"), + _("An error occurred during operation.")); + return; + } + }; - if (check_gpg_error_2_err_code(error) == GPG_ERR_NO_ERROR) - edit_->SlotFillTextEditWithText(QString::fromStdString(*tmp)); - } else { - QMessageBox::critical(this, _("Error"), - _("An error occurred during operation.")); - return; - } + process_operation(this, _("Signing"), std::move(sign_ruunner), + std::move(result_callback), data_object); } void MainWindow::slot_decrypt() { @@ -185,7 +262,6 @@ void MainWindow::slot_decrypt() { return; } - auto decrypted = std::make_unique<ByteArray>(); QByteArray text = edit_->CurTextPage()->GetTextPage()->toPlainText().toUtf8(); if (text.trimmed().startsWith(GpgConstants::GPG_FRONTEND_SHORT_CRYPTO_HEAD)) { @@ -195,31 +271,57 @@ void MainWindow::slot_decrypt() { return; } - GpgDecrResult result = nullptr; - gpgme_error_t error; - bool if_error = false; - process_operation(this, _("Decrypting"), [&]() { + // data to transfer into task + auto data_object = std::make_shared<Thread::Task::DataObject>(); + + // set input buffer + auto buffer = + edit_->CurTextPage()->GetTextPage()->toPlainText().toStdString(); + data_object->AppendObject(std::move(buffer)); + + auto decrypt_runner = [](Thread::Task::DataObjectPtr data_object) -> int { + // check the size of the data object + if (data_object == nullptr || data_object->GetObjectSize() != 1) + throw std::runtime_error("Invalid data object size"); + + auto buffer = data_object->PopObject<std::string>(); try { - auto buffer = text.toStdString(); - error = GpgFrontend::GpgBasicOperator::GetInstance().Decrypt( + GpgDecrResult result = nullptr; + auto decrypted = std::make_unique<ByteArray>(); + GpgError error = GpgFrontend::GpgBasicOperator::GetInstance().Decrypt( buffer, decrypted, result); + data_object->AppendObject(std::move(decrypted)); + data_object->AppendObject(std::move(result)); + data_object->AppendObject(std::move(error)); } catch (const std::runtime_error& e) { - if_error = true; + return -1; } - }); - - if (!if_error) { - auto resultAnalyse = GpgDecryptResultAnalyse(error, std::move(result)); - resultAnalyse.Analyse(); - process_result_analyse(edit_, info_board_, resultAnalyse); + return 0; + }; + + auto result_callback = [this](int rtn, + Thread::Task::DataObjectPtr data_object) { + if (!rtn) { + if (data_object == nullptr || data_object->GetObjectSize() != 3) + throw std::runtime_error("Invalid data object size"); + auto error = data_object->PopObject<GpgError>(); + auto result = data_object->PopObject<GpgDecrResult>(); + auto decrypted = data_object->PopObject<std::unique_ptr<ByteArray>>(); + auto resultAnalyse = GpgDecryptResultAnalyse(error, std::move(result)); + resultAnalyse.Analyse(); + process_result_analyse(edit_, info_board_, resultAnalyse); + + if (check_gpg_error_2_err_code(error) == GPG_ERR_NO_ERROR) + edit_->SlotFillTextEditWithText(QString::fromStdString(*decrypted)); + } else { + QMessageBox::critical(this, _("Error"), + _("An error occurred during operation.")); + return; + } + }; - if (check_gpg_error_2_err_code(error) == GPG_ERR_NO_ERROR) - edit_->SlotFillTextEditWithText(QString::fromStdString(*decrypted)); - } else { - QMessageBox::critical(this, _("Error"), - _("An error occurred during operation.")); - return; - } + process_operation(this, _("Decrypting"), std::move(decrypt_runner), + std::move(result_callback), data_object); } void MainWindow::slot_find() { @@ -249,15 +351,17 @@ void MainWindow::slot_verify() { GpgVerifyResult result = nullptr; GpgError error; bool if_error = false; - process_operation(this, _("Verifying"), [&]() { - try { - auto buffer = text.toStdString(); - error = GpgFrontend::GpgBasicOperator::GetInstance().Verify( - buffer, sig_buffer, result); - } catch (const std::runtime_error& e) { - if_error = true; - } - }); + process_operation( + this, _("Verifying"), [&](Thread::Task::DataObjectPtr) -> int { + try { + auto buffer = text.toStdString(); + error = GpgFrontend::GpgBasicOperator::GetInstance().Verify( + buffer, sig_buffer, result); + } catch (const std::runtime_error& e) { + if_error = true; + } + return 0; + }); if (!if_error) { auto result_analyse = GpgVerifyResultAnalyse(error, result); @@ -325,20 +429,23 @@ void MainWindow::slot_encrypt_sign() { bool if_error = false; auto tmp = std::make_unique<ByteArray>(); - process_operation(this, _("Encrypting and Signing"), [&]() { - try { - auto buffer = edit_->CurTextPage() - ->GetTextPage() - ->toPlainText() - .toUtf8() - .toStdString(); - error = GpgFrontend::GpgBasicOperator::GetInstance().EncryptSign( - std::move(keys), std::move(signer_keys), buffer, tmp, encr_result, - sign_result); - } catch (const std::runtime_error& e) { - if_error = true; - } - }); + process_operation( + this, _("Encrypting and Signing"), + [&](Thread::Task::DataObjectPtr) -> int { + try { + auto buffer = edit_->CurTextPage() + ->GetTextPage() + ->toPlainText() + .toUtf8() + .toStdString(); + error = GpgFrontend::GpgBasicOperator::GetInstance().EncryptSign( + std::move(keys), std::move(signer_keys), buffer, tmp, encr_result, + sign_result); + } catch (const std::runtime_error& e) { + if_error = true; + } + return 0; + }); if (!if_error) { #ifdef ADVANCE_SUPPORT @@ -401,8 +508,9 @@ void MainWindow::slot_decrypt_verify() { // Automatically import public keys that are not stored locally if (settings.value("advanced/autoPubkeyExchange").toBool()) { gpgme_verify_result_t tmp_v_result = nullptr; - auto thread = - QThread::create([&]() { mCtx->verify(&text, nullptr, &tmp_v_result); }); + auto thread = QThread::create([&](Thread::Task::DataObjectPtr) -> int { + mCtx->verify(&text, nullptr, &tmp_v_result); + }); thread->start(); while (thread->isRunning()) QApplication::processEvents(); auto* checker = new UnknownSignersChecker(mCtx, tmp_v_result); @@ -411,15 +519,17 @@ void MainWindow::slot_decrypt_verify() { } #endif auto decrypted = std::make_unique<ByteArray>(); - process_operation(this, _("Decrypting and Verifying"), [&]() { - try { - auto buffer = text.toStdString(); - error = GpgBasicOperator::GetInstance().DecryptVerify(buffer, decrypted, - d_result, v_result); - } catch (const std::runtime_error& e) { - if_error = true; - } - }); + process_operation(this, _("Decrypting and Verifying"), + [&](Thread::Task::DataObjectPtr) -> int { + try { + auto buffer = text.toStdString(); + error = GpgBasicOperator::GetInstance().DecryptVerify( + buffer, decrypted, d_result, v_result); + } catch (const std::runtime_error& e) { + if_error = true; + } + return 0; + }); if (!if_error) { auto decrypt_res = GpgDecryptResultAnalyse(error, std::move(d_result)); |