diff options
author | Saturn&Eric <[email protected]> | 2023-02-25 11:49:54 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2023-02-25 11:49:54 +0000 |
commit | af1cd680f2496629026ba27707cef2afd860f5f9 (patch) | |
tree | 78e78450893e98b8828cc41010e377c1561e5f34 | |
parent | fix: improve manual (diff) | |
parent | feat: use aqt to install qt in ci build (diff) | |
download | GpgFrontend-af1cd680f2496629026ba27707cef2afd860f5f9.tar.gz GpgFrontend-af1cd680f2496629026ba27707cef2afd860f5f9.zip |
Merge pull request #91 from saturneric/dev/2.0.10/main
Develop 2.1.0.1
148 files changed, 3525 insertions, 1193 deletions
diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..44c37b71 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +resource/lfs/** filter=lfs diff=lfs merge=lfs -text diff --git a/.github/workflows/debug.yml b/.github/workflows/debug.yml index 26bbcad2..055347f0 100644 --- a/.github/workflows/debug.yml +++ b/.github/workflows/debug.yml @@ -23,7 +23,7 @@ jobs: build: strategy: matrix: - os: [ 'ubuntu-latest', 'macos-10.15', 'macos-11', 'macos-12', 'windows-latest' ] + os: [ 'ubuntu-latest', 'macos-11', 'macos-12', 'windows-latest' ] runs-on: ${{ matrix.os }} continue-on-error: true steps: @@ -32,7 +32,7 @@ jobs: run: | git config --global core.autocrlf false git config --global core.eol lf - if: matrix.os == 'windows-latest' || matrix.os == 'macos-10.15' || matrix.os == 'macos-11' || matrix.os == 'macos-12' + if: matrix.os == 'windows-latest' || matrix.os == 'macos-11' || matrix.os == 'macos-12' - uses: actions/checkout@v2 with: @@ -53,12 +53,11 @@ jobs: - name: Install Dependence (macOS) run: | - brew install cmake autoconf automake qt@5 texinfo gettext [email protected] + brew install cmake autoconf automake texinfo gettext [email protected] brew install boost ninja libarchive libconfig gpgme brew unlink gettext && brew link --force gettext - brew link qt@5 brew link [email protected] --force - if: matrix.os == 'macos-10.15' || matrix.os == 'macos-11' || matrix.os == 'macos-12' + if: matrix.os == 'macos-11' || matrix.os == 'macos-12' - name: Build gpg-error (Linux) run: | @@ -92,14 +91,16 @@ jobs: uses: actions/cache@v1 with: path: ../Qt - key: ${{ runner.os }}-QtCache - if: matrix.os == 'ubuntu-latest' + key: ${{ runner.os }}-qt-cache-6 + if: matrix.os == 'ubuntu-latest' || matrix.os == 'macos-11' || matrix.os == 'macos-12' - name: Install Qt - uses: jurplel/install-qt-action@v2 + uses: jurplel/install-qt-action@v3 with: + version: '6.4.2' + modules: 'qt5compat' cached: ${{ steps.cache-qt.outputs.cache-hit }} - if: matrix.os == 'ubuntu-latest' + if: matrix.os == 'ubuntu-latest' || matrix.os == 'macos-11' || matrix.os == 'macos-12' - name: Set up MinGW (Windows) uses: msys2/setup-msys2@v2 @@ -113,7 +114,7 @@ jobs: run: | pacman --noconfirm -S --needed mingw-w64-x86_64-gcc mingw-w64-x86_64-make mingw-w64-x86_64-cmake autoconf pacman --noconfirm -S --needed make texinfo mingw-w64-x86_64-libconfig mingw-w64-x86_64-boost automake - pacman --noconfirm -S --needed mingw-w64-x86_64-qt5 libintl msys2-runtime-devel gettext-devel + pacman --noconfirm -S --needed mingw-w64-x86_64-qt6 libintl msys2-runtime-devel gettext-devel pacman --noconfirm -S --needed mingw-w64-x86_64-ninja mingw-w64-x86_64-gnupg mingw-w64-x86_64-gpgme pacman --noconfirm -S --needed mingw-w64-x86_64-libarchive mingw-w64-x86_64-icu mingw-w64-x86_64-icu-debug-libs if: matrix.os == 'windows-latest' @@ -130,7 +131,7 @@ jobs: run: | cmake -G Ninja -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DGPGFRONTEND_BUILD_TYPE_TEST_UI=ON cmake --build ${{github.workspace}}/build --config {{$env.BUILD_TYPE}} -- -v - if: matrix.os == 'macos-10.15' || matrix.os == 'macos-11' || matrix.os == 'macos-12' + if: matrix.os == 'macos-11' || matrix.os == 'macos-12' - name: Configure CMake & Build Binary(Windows) shell: msys2 {0} @@ -158,7 +159,7 @@ jobs: with: name: gpgfrontend-${{matrix.os}}-${{env.BUILD_TYPE}}-${{steps.vars.outputs.sha_short}} path: ${{github.workspace}}/build/release/* - if: matrix.os == 'macos-10.15' || matrix.os == 'macos-11' || matrix.os == 'macos-12' + if: matrix.os == 'macos-11' || matrix.os == 'macos-12' - name: Upload Artifact(Windows) uses: actions/upload-artifact@master diff --git a/.github/workflows/release-deb-package.yml b/.github/workflows/release-deb-package.yml index f5aff6a0..63cacb6f 100644 --- a/.github/workflows/release-deb-package.yml +++ b/.github/workflows/release-deb-package.yml @@ -36,22 +36,6 @@ jobs: id: vars run: echo "::set-output name=sha_short::$(git rev-parse --short HEAD)" - - name: Install Dependence (Ubuntu 18.04) - run: | - sudo apt-get update - sudo apt-get -y install build-essential binutils git autoconf automake gettext texinfo qt5-default - sudo apt-get -y install gcc-8 g++-8 ninja-build - sudo apt-get -y install libconfig++-dev libboost-all-dev libarchive-dev libssl-dev - sudo apt-get -y install gpgsm libxcb-xinerama0 libxcb-icccm4-dev libcups2-dev libdrm-dev libegl1-mesa-dev - sudo apt-get -y install libgcrypt11-dev libnss3-dev libpci-dev libpulse-dev libudev-dev libxtst-dev gyp - sudo apt-get -y install libglu1-mesa-dev libfontconfig1-dev libx11-xcb-dev libicu-dev libxcb-image0 - sudo apt-get -y install libglu1-mesa-dev libfontconfig1-dev libx11-xcb-dev libicu-dev libxcb-* - sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-8 8 - sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-8 8 - sudo update-alternatives --set gcc "/usr/bin/gcc-8" - sudo update-alternatives --set g++ "/usr/bin/g++-8" - if: matrix.os == 'ubuntu-18.04' - - name: Install Dependence (Ubuntu 20.04) run: | sudo apt-get update @@ -103,6 +87,7 @@ jobs: cd ${{github.workspace}}/build-deb-${{matrix.os}} ninja package cd ${{github.workspace}} + - name: Upload Artifact(Linux DEB) uses: actions/upload-artifact@master with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9b9e8f82..d10dde2a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -23,7 +23,7 @@ jobs: build: strategy: matrix: - os: [ 'ubuntu-18.04', 'macos-10.15', 'macos-11', 'macos-12', 'windows-2019' ] + os: [ 'ubuntu-18.04', 'macos-11', 'macos-12', 'windows-2019' ] runs-on: ${{ matrix.os }} continue-on-error: true steps: @@ -31,7 +31,7 @@ jobs: run: | git config --global core.autocrlf false git config --global core.eol lf - if: matrix.os == 'windows-2019' || matrix.os == 'macos-10.15' || matrix.os == 'macos-11' || matrix.os == 'macos-12' + if: matrix.os == 'windows-2019' || matrix.os == 'macos-11' || matrix.os == 'macos-12' - uses: actions/checkout@v2 with: @@ -92,16 +92,31 @@ jobs: mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles - if: matrix.os == 'macos-10.15' || matrix.os == 'macos-11' || matrix.os == 'macos-12' + if: matrix.os == 'macos-11' || matrix.os == 'macos-12' + + - name: Cache Qt (macOS) + id: cache-qt-6 + uses: actions/cache@v1 + with: + path: ../Qt + key: ${{ runner.os }}-qt-cache-6 + if: matrix.os == 'macos-11' || matrix.os == 'macos-12' + + - name: Install Qt6 (macOS) + uses: jurplel/install-qt-action@v3 + with: + version: '6.4.2' + modules: 'qt5compat' + cached: ${{ steps.cache-qt.outputs.cache-hit }} + if: matrix.os == 'macos-11' || matrix.os == 'macos-12' - name: Install Dependence (macOS) run: | - brew install cmake autoconf automake qt@5 texinfo gettext [email protected] + brew install cmake autoconf automake texinfo gettext [email protected] brew install boost ninja libarchive libconfig gpgme brew unlink gettext && brew link --force gettext - brew link qt@5 brew link [email protected] --force - if: matrix.os == 'macos-10.15' || matrix.os == 'macos-11' || matrix.os == 'macos-12' + if: matrix.os == 'macos-11' || matrix.os == 'macos-12' - name: Build gpg-error (Linux) run: | @@ -156,7 +171,7 @@ jobs: run: | pacman --noconfirm -S --needed mingw-w64-x86_64-gcc mingw-w64-x86_64-make mingw-w64-x86_64-cmake autoconf pacman --noconfirm -S --needed make texinfo mingw-w64-x86_64-libconfig mingw-w64-x86_64-boost automake - pacman --noconfirm -S --needed mingw-w64-x86_64-qt5 libintl msys2-runtime-devel gettext-devel mingw-w64-x86_64-gpgme + pacman --noconfirm -S --needed mingw-w64-x86_64-qt6 libintl msys2-runtime-devel gettext-devel mingw-w64-x86_64-gpgme pacman --noconfirm -S --needed mingw-w64-x86_64-ninja mingw-w64-x86_64-gnupg mingw-w64-x86_64-libarchive pacman --noconfirm -S --needed mingw-w64-x86_64-icu mingw-w64-x86_64-icu-debug-libs if: matrix.os == 'windows-2019' @@ -186,7 +201,7 @@ jobs: 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' || matrix.os == 'macos-11' || matrix.os == 'macos-12' + if: matrix.os == 'macos-11' || matrix.os == 'macos-12' - name: Package & Sign App Bundle (macOS) run: | @@ -201,7 +216,7 @@ jobs: ${{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' || matrix.os == 'macos-11' || matrix.os == 'macos-12' + if: matrix.os == 'macos-11' || matrix.os == 'macos-12' - name: Notarize Release Build (macOS) run: | @@ -210,7 +225,7 @@ jobs: --primary-bundle-id ${{secrets.GPGFRONTEND_XOCDE_APPID}} \ -u ${{secrets.APPLE_DEVELOPER_ID}} \ -p ${{secrets.APPLE_DEVELOPER_ID_SECRET}} - if: matrix.os == 'macos-10.15' || matrix.os == 'macos-11' || matrix.os == 'macos-12' + if: matrix.os == 'macos-11' || matrix.os == 'macos-12' - name: Package App Image (Linux) run: | @@ -243,7 +258,7 @@ jobs: with: name: gpgfrontend-${{matrix.os}}-${{env.BUILD_TYPE}}-${{steps.vars.outputs.sha_short}} path: ${{github.workspace}}/build/artifactOut/* - if: matrix.os == 'macos-10.15' || matrix.os == 'macos-11' || matrix.os == 'macos-12' + if: matrix.os == 'macos-11' || matrix.os == 'macos-12' - name: Upload Artifact(Windows) uses: actions/upload-artifact@master diff --git a/.gitmodules b/.gitmodules index f8ddc595..9243d165 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,9 +10,6 @@ [submodule "third_party/json"] path = third_party/json url = https://git.bktus.com/GpgFrontend/json.git -[submodule "third_party/easyloggingpp"] - path = third_party/easyloggingpp - url = https://git.bktus.com/GpgFrontend/easyloggingpp.git [submodule "third_party/qt-aes"] path = third_party/qt-aes url = https://git.bktus.com/GpgFrontend/Qt-AES.git @@ -22,3 +19,6 @@ [submodule "third_party/libconfig"] path = third_party/libconfig url = https://git.bktus.com/GpgFrontend/libconfig.git +[submodule "third_party/spdlog"] + path = third_party/spdlog + url = https://git.bktus.com/GpgFrontend/spdlog.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f08f440..e2c107ca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,7 +27,7 @@ cmake_minimum_required(VERSION 3.16) # define project -project(GpgFrontend VERSION 2.0.10 LANGUAGES CXX) +project(GpgFrontend VERSION 2.1.0 LANGUAGES CXX) # show cmake version message(STATUS "GpgFrontend Build Configuration Started CMAKE Version ${CMAKE_VERSION}") @@ -63,6 +63,7 @@ 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") +option(GPGFRONTEND_XOCDE_ENABLE_SANDBOX "Enable SandBox For Xcode Build" OFF) # analyse options if (GPGFRONTEND_BUILD_TYPE_TEST_CORE) @@ -443,40 +444,6 @@ endif () SET(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL) SET(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC) -# disable myeasylog.log -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DELPP_NO_DEFAULT_LOG_FILE") - -# Introduce boost -if(NOT BOOST_ROOT) - find_package(Boost COMPONENTS date_time system REQUIRED) -else() - find_package(Boost - COMPONENTS date_time system REQUIRED - PATHS ${BOOST_ROOT} NO_DEFAULT_PATH) -endif() - -# Introduce OpenSSL -if(APPLE) - set(OPENSSL_ROOT_DIR /usr/local/opt/[email protected]) -endif() -find_package(OpenSSL REQUIRED) - -# Introduce Qt -if (QT5_ENV_SUPPORT) - # Support Qt version Both 5.12.x and 5.15.x - find_package(Qt5 5.9 COMPONENTS Core Test Widgets PrintSupport Network REQUIRED) - - # Qt configuration - set(CMAKE_AUTOMOC ON) - set(CMAKE_AUTORCC ON) - set(CMAKE_AUTOUIC ON) - - set(CMAKE_AUTORCC_OPTIONS "--compress;9") - set(CMAKE_AUTOUIC_SEARCH_PATHS ${CMAKE_AUTOUIC_SEARCH_PATHS} ${CMAKE_SOURCE_DIR}/ui) - -endif () - - if (SMTP_SUPPORT) add_compile_definitions(SMTP_SUPPORT) endif () diff --git a/GpgFrontend.entitlements b/GpgFrontend.entitlements new file mode 100644 index 00000000..637aa6f1 --- /dev/null +++ b/GpgFrontend.entitlements @@ -0,0 +1,14 @@ +<?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>com.apple.security.app-sandbox</key> + <true/> + <key>com.apple.security.files.user-selected.read-write</key> + <true/> + <key>com.apple.security.network.client</key> + <true/> + <key>com.apple.security.print</key> + <true/> +</dict> +</plist> @@ -217,9 +217,15 @@ $ ./linuxdeployqt-continuous-x86_64.AppImage ../release/gpgfrontend/usr/share/ap ## Languages Support +<<<<<<< HEAD +The supported languages are listed here. Some languages use machine translation and have not been verified. If you want +to join translation and verification work, please refer to [HERE](https://gpgfrontend.pub/#/translate-interface). +======= The supported languages are listed here. Some translations use machine translation and have not been verified. If you want to join translation or verification work, please refer to [HERE](https://gpgfrontend.pub/#/translate-interface). +> > > > > > > main + ### Supported Languages 'zh_CN', 'zh_TW', 'zh_HK', 'es_ES', 'fr_FR', 'de_DE', 'pl_PL', 'ru_RU', 'ja_JP', 'it_IT', @@ -227,7 +233,7 @@ to join translation or verification work, please refer to [HERE](https://gpgfron 'hr_HR', 'cs_CZ', 'da_DK', 'nl_NL', 'et_EE', 'fa_IR', 'fi_FI', 'fr_CA', 'he_IL', 'id_ID', 'lt_LT', 'de_AT', 'de_CH', 'el_GR', 'es_MX', 'iw_IL', 'uk_UA', 'en_US', 'en_GB', 'en_AU', -Notice: Most translations are generated by Google's automatic translation machine.If you find that a certain translation +Notice: Most translations are generated by Google's automatic translation machine. If you find that a certain translation is wrong, you are welcome to join the translation work to provide a more suitable human translation. ## Contract diff --git a/resource/lfs/macOS/GnuPG/agent/gpg-agent b/resource/lfs/macOS/GnuPG/agent/gpg-agent new file mode 100755 index 00000000..190c40e2 --- /dev/null +++ b/resource/lfs/macOS/GnuPG/agent/gpg-agent @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:09ad99b28e3b2db960965f7debf20d5d64867cebc6852d52a853f827dad7c7b5 +size 436544 diff --git a/resource/lfs/macOS/GnuPG/bin/gpgconf b/resource/lfs/macOS/GnuPG/bin/gpgconf new file mode 100755 index 00000000..f30709d1 --- /dev/null +++ b/resource/lfs/macOS/GnuPG/bin/gpgconf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1d433cb8cd39b2e727467452063047005205b4e742e24ffb2b8d2e2c3389c798 +size 88 diff --git a/resource/lfs/macOS/GnuPG/bin/gpgconf-original b/resource/lfs/macOS/GnuPG/bin/gpgconf-original new file mode 100755 index 00000000..e305b949 --- /dev/null +++ b/resource/lfs/macOS/GnuPG/bin/gpgconf-original @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:453e1ff371d08aee36b84899582ba68bc275ba8883340ea183f0c82a51bf480c +size 201552 diff --git a/resource/lfs/macOS/GnuPG/dirmngr/dirmngr b/resource/lfs/macOS/GnuPG/dirmngr/dirmngr new file mode 100755 index 00000000..944a545a --- /dev/null +++ b/resource/lfs/macOS/GnuPG/dirmngr/dirmngr @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:80903d1d7107d87f350790a01fb19a6206cc36d62d50d82865e1ef9c081d443b +size 581472 diff --git a/resource/lfs/macOS/GnuPG/g10/gpg b/resource/lfs/macOS/GnuPG/g10/gpg new file mode 100755 index 00000000..92f49d92 --- /dev/null +++ b/resource/lfs/macOS/GnuPG/g10/gpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d8973db4e183b7b26aed45fc663ff34e2d0ba52b0d3d08bc249294d89a955cf1 +size 1033696 diff --git a/resource/lfs/macOS/GnuPG/kbx/keyboxd b/resource/lfs/macOS/GnuPG/kbx/keyboxd new file mode 100755 index 00000000..e3675190 --- /dev/null +++ b/resource/lfs/macOS/GnuPG/kbx/keyboxd @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c66166e8e8efef62e18c67cd2bac0db5d0ba50e6c0eb117fc07369f1bb55d207 +size 305488 diff --git a/resource/lfs/macOS/GnuPG/libs/libassuan.0.dylib b/resource/lfs/macOS/GnuPG/libs/libassuan.0.dylib new file mode 100644 index 00000000..b1775f54 --- /dev/null +++ b/resource/lfs/macOS/GnuPG/libs/libassuan.0.dylib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:243914cefac155f1843f91331d2eb3326154ba5f68a1143b3882b8fc94f13bc4 +size 116640 diff --git a/resource/lfs/macOS/GnuPG/libs/libgcrypt.20.dylib b/resource/lfs/macOS/GnuPG/libs/libgcrypt.20.dylib new file mode 100644 index 00000000..e1a31ac4 --- /dev/null +++ b/resource/lfs/macOS/GnuPG/libs/libgcrypt.20.dylib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cc444590a050499a5f516284b43cedeba243822729b3c593ac458ca5a509a710 +size 842032 diff --git a/resource/lfs/macOS/GnuPG/libs/libgmp.10.dylib b/resource/lfs/macOS/GnuPG/libs/libgmp.10.dylib new file mode 100644 index 00000000..829aea2b --- /dev/null +++ b/resource/lfs/macOS/GnuPG/libs/libgmp.10.dylib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ed2249f92c4386a97513991642ee9eb6af041c646e3c9fdab2ac4c6f468fefec +size 486352 diff --git a/resource/lfs/macOS/GnuPG/libs/libgnutls.30.dylib b/resource/lfs/macOS/GnuPG/libs/libgnutls.30.dylib new file mode 100644 index 00000000..55330b13 --- /dev/null +++ b/resource/lfs/macOS/GnuPG/libs/libgnutls.30.dylib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ddc00b098c8a5c43fcba2524d9c9a0cb323fd1f77e6b64a809927ebcf14f542c +size 1948912 diff --git a/resource/lfs/macOS/GnuPG/libs/libgpg-error.0.dylib b/resource/lfs/macOS/GnuPG/libs/libgpg-error.0.dylib new file mode 100644 index 00000000..16479414 --- /dev/null +++ b/resource/lfs/macOS/GnuPG/libs/libgpg-error.0.dylib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ac9396f90299bd5952399c5428ed41b285e1b35d97ff90ee7917f17b314df746 +size 178496 diff --git a/resource/lfs/macOS/GnuPG/libs/libhogweed.6.6.dylib b/resource/lfs/macOS/GnuPG/libs/libhogweed.6.6.dylib new file mode 100644 index 00000000..e76bc3ae --- /dev/null +++ b/resource/lfs/macOS/GnuPG/libs/libhogweed.6.6.dylib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e6581f0ae342f40ac50f205bbfb3cb3b639eeebad4aa10f0892aab4e2c42f1db +size 300160 diff --git a/resource/lfs/macOS/GnuPG/libs/libidn2.0.dylib b/resource/lfs/macOS/GnuPG/libs/libidn2.0.dylib new file mode 100644 index 00000000..1e6338ba --- /dev/null +++ b/resource/lfs/macOS/GnuPG/libs/libidn2.0.dylib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:308f59ceaa30199b39fdcb63080f86c0135beb744a0f73d89155bc94ed44ac1f +size 259536 diff --git a/resource/lfs/macOS/GnuPG/libs/libintl.8.dylib b/resource/lfs/macOS/GnuPG/libs/libintl.8.dylib new file mode 100644 index 00000000..ed4dfc46 --- /dev/null +++ b/resource/lfs/macOS/GnuPG/libs/libintl.8.dylib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c55333e6fa8832b6f8a0276bfce9a50cecee95af2515e9d2fbde04074cfdbc5e +size 111216 diff --git a/resource/lfs/macOS/GnuPG/libs/libksba.8.dylib b/resource/lfs/macOS/GnuPG/libs/libksba.8.dylib new file mode 100644 index 00000000..20a0ceb5 --- /dev/null +++ b/resource/lfs/macOS/GnuPG/libs/libksba.8.dylib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e1604bb672c6a414b5c2dc2e3a5fc1a26554c74ec0790cf66c622d594466f04a +size 267344 diff --git a/resource/lfs/macOS/GnuPG/libs/libnettle.8.6.dylib b/resource/lfs/macOS/GnuPG/libs/libnettle.8.6.dylib new file mode 100644 index 00000000..5da22375 --- /dev/null +++ b/resource/lfs/macOS/GnuPG/libs/libnettle.8.6.dylib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:952c262111a35af64debcdcac6d38e9bf794b4602e6661625345b8f74813382d +size 315664 diff --git a/resource/lfs/macOS/GnuPG/libs/libnpth.0.dylib b/resource/lfs/macOS/GnuPG/libs/libnpth.0.dylib new file mode 100644 index 00000000..8b17220c --- /dev/null +++ b/resource/lfs/macOS/GnuPG/libs/libnpth.0.dylib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e01272a5843b3abf78ecd0862a09d6648c7217c31fc1eccac23f380e4f84d1ee +size 56464 diff --git a/resource/lfs/macOS/GnuPG/libs/libp11-kit.0.dylib b/resource/lfs/macOS/GnuPG/libs/libp11-kit.0.dylib new file mode 100644 index 00000000..6a974b2f --- /dev/null +++ b/resource/lfs/macOS/GnuPG/libs/libp11-kit.0.dylib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1df14b9fd115d317087f606a312f3095082e3286da21801f4f5ac41449f1babd +size 1022832 diff --git a/resource/lfs/macOS/GnuPG/libs/libreadline.8.2.dylib b/resource/lfs/macOS/GnuPG/libs/libreadline.8.2.dylib new file mode 100644 index 00000000..232ff1a9 --- /dev/null +++ b/resource/lfs/macOS/GnuPG/libs/libreadline.8.2.dylib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b1c19c68716d6098eff03f3d2bb62d312b9ebcca44c7b51ccc67d6cd3329b1ed +size 295968 diff --git a/resource/lfs/macOS/GnuPG/libs/libtasn1.6.dylib b/resource/lfs/macOS/GnuPG/libs/libtasn1.6.dylib new file mode 100644 index 00000000..22bc919e --- /dev/null +++ b/resource/lfs/macOS/GnuPG/libs/libtasn1.6.dylib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:57c57b889d791ffca6f3c128dc6396de707086c11d1067a7c92b9e55cff49950 +size 125328 diff --git a/resource/lfs/macOS/GnuPG/libs/libunistring.5.dylib b/resource/lfs/macOS/GnuPG/libs/libunistring.5.dylib new file mode 100644 index 00000000..7fc15150 --- /dev/null +++ b/resource/lfs/macOS/GnuPG/libs/libunistring.5.dylib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c9f775e184335cc6bbb7e2b702f14054ac38672c4cd1648e12cedf4f2a4cd0e3 +size 1849472 diff --git a/resource/lfs/macOS/GnuPG/libs/libusb-1.0.0.dylib b/resource/lfs/macOS/GnuPG/libs/libusb-1.0.0.dylib new file mode 100644 index 00000000..569c5bdd --- /dev/null +++ b/resource/lfs/macOS/GnuPG/libs/libusb-1.0.0.dylib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1e35b0eb52d44b464970aa671113f87089c4b540933437d2bf0dac8fcfc38fba +size 161040 diff --git a/resource/lfs/macOS/GnuPG/scd/scdaemon b/resource/lfs/macOS/GnuPG/scd/scdaemon new file mode 100755 index 00000000..ba7d6de6 --- /dev/null +++ b/resource/lfs/macOS/GnuPG/scd/scdaemon @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1dd2a6bdf916e99dfbf6d662941661805de38f78bcf3522a9813fc430bede78e +size 555632 diff --git a/resource/lfs/macOS/GnuPG/sm/gpgsm b/resource/lfs/macOS/GnuPG/sm/gpgsm new file mode 100755 index 00000000..784b56ba --- /dev/null +++ b/resource/lfs/macOS/GnuPG/sm/gpgsm @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9e660da5cdf99a0ff9be44326332a7d901b41a05136f279beb26dd81b4155555 +size 550544 diff --git a/resource/lfs/macOS/GnuPG/tools/gpg-connect-agent b/resource/lfs/macOS/GnuPG/tools/gpg-connect-agent new file mode 100755 index 00000000..882568b5 --- /dev/null +++ b/resource/lfs/macOS/GnuPG/tools/gpg-connect-agent @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b696f753532e0ff1c149c6e0e4b602982aa3715f31456d448b1ee3dfacbb06b +size 202832 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e00f9b60..4ec07d66 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -24,6 +24,40 @@ # # SPDX-License-Identifier: GPL-3.0-or-later +# Introduce boost +if(NOT BOOST_ROOT) + find_package(Boost COMPONENTS date_time system REQUIRED) +else() + find_package(Boost + COMPONENTS date_time system REQUIRED + PATHS ${BOOST_ROOT} NO_DEFAULT_PATH) +endif() + +# Introduce OpenSSL +if(APPLE) + set(OPENSSL_ROOT_DIR /usr/local/opt/[email protected]) +endif() +find_package(OpenSSL REQUIRED) + +# Introduce Qt +if (QT5_ENV_SUPPORT) + # Support Qt version: 6.x, 5.12.x and 5.15.x + find_package(Qt6 6.3 COMPONENTS Core Test Widgets PrintSupport Network Core5Compat) + if(NOT Qt6_DIR) + find_package(Qt5 5.9 COMPONENTS Core Test Widgets PrintSupport Network REQUIRED) + else() + add_definitions(-DGPGFRONTEND_GUI_QT6) + endif() + + # Qt configuration + set(CMAKE_AUTOMOC ON) + set(CMAKE_AUTORCC ON) + set(CMAKE_AUTOUIC ON) + + set(CMAKE_AUTORCC_OPTIONS "--compress;9") + set(CMAKE_AUTOUIC_SEARCH_PATHS ${CMAKE_AUTOUIC_SEARCH_PATHS} ${CMAKE_SOURCE_DIR}/ui) +endif () + # configure for output path and resources if (APPLICATION_BUILD) aux_source_directory(. BASE_SOURCE) @@ -160,14 +194,148 @@ if (APPLICATION_BUILD) # Copy Utils Files if (MINGW) message(STATUS "Copying Dependent DLL For Windows Runtime Env") - file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/lib/ DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) - file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/gpgme/ DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) - file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/bearer DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) - file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/iconengines DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) - file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/imageformats DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) - file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/printsupport DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) - file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/platforms DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) - file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/openssl/ DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) + + set(ALL_RUNTIME_DEP_PATH_LIST "") + + # get mingw bin path + find_file(_libGccDllPath NAMES libgcc_s_seh-1.dll NO_CACHE REQUIRED) + cmake_path(GET _libGccDllPath PARENT_PATH _libDllBinPath) + + # find libicu*.dll + unset(_libDllPath) + file(GLOB _libDllPath "${_libDllBinPath}/libicu[a-z]*[0-9][0-9].dll") + list(APPEND ALL_RUNTIME_DEP_PATH_LIST ${_libDllPath}) + + unset(_libDllPath) + file(GLOB _libDllPath "${_libDllBinPath}/libconfig++-*.dll") + list(APPEND ALL_RUNTIME_DEP_PATH_LIST ${_libDllPath}) + + unset(_libDllPath) + file(GLOB _libDllPath "${_libDllBinPath}/libarchive-*.dll") + list(APPEND ALL_RUNTIME_DEP_PATH_LIST ${_libDllPath}) + + unset(_libDllPath) + file(GLOB _libDllPath "${_libDllBinPath}/libassuan-*.dll") + list(APPEND ALL_RUNTIME_DEP_PATH_LIST ${_libDllPath}) + + unset(_libDllPath) + file(GLOB _libDllPath "${_libDllBinPath}/libbz*.dll") + list(APPEND ALL_RUNTIME_DEP_PATH_LIST ${_libDllPath}) + + unset(_libDllPath) + file(GLOB _libDllPath "${_libDllBinPath}/libcrypto-*.dll") + list(APPEND ALL_RUNTIME_DEP_PATH_LIST ${_libDllPath}) + + unset(_libDllPath) + file(GLOB _libDllPath "${_libDllBinPath}/libexpat-*.dll") + list(APPEND ALL_RUNTIME_DEP_PATH_LIST ${_libDllPath}) + + unset(_libDllPath) + file(GLOB _libDllPath "${_libDllBinPath}/libfreetype-*.dll") + list(APPEND ALL_RUNTIME_DEP_PATH_LIST ${_libDllPath}) + + unset(_libDllPath) + file(GLOB _libDllPath "${_libDllBinPath}/libgcc_s_seh-*.dll") + list(APPEND ALL_RUNTIME_DEP_PATH_LIST ${_libDllPath}) + + unset(_libDllPath) + file(GLOB _libDllPath "${_libDllBinPath}/libglib-*.dll") + list(APPEND ALL_RUNTIME_DEP_PATH_LIST ${_libDllPath}) + + unset(_libDllPath) + file(GLOB _libDllPath "${_libDllBinPath}/libgpg-error-*.dll") + list(APPEND ALL_RUNTIME_DEP_PATH_LIST ${_libDllPath}) + + unset(_libDllPath) + file(GLOB _libDllPath "${_libDllBinPath}/libgpgme-*.dll") + list(APPEND ALL_RUNTIME_DEP_PATH_LIST ${_libDllPath}) + + unset(_libDllPath) + file(GLOB _libDllPath "${_libDllBinPath}/libgraphite2.dll") + list(APPEND ALL_RUNTIME_DEP_PATH_LIST ${_libDllPath}) + + unset(_libDllPath) + file(GLOB _libDllPath "${_libDllBinPath}/libharfbuzz-*.dll") + list(APPEND ALL_RUNTIME_DEP_PATH_LIST ${_libDllPath}) + + unset(_libDllPath) + file(GLOB _libDllPath "${_libDllBinPath}/libiconv-*.dll") + list(APPEND ALL_RUNTIME_DEP_PATH_LIST ${_libDllPath}) + + unset(_libDllPath) + file(GLOB _libDllPath "${_libDllBinPath}/libintl-*.dll") + list(APPEND ALL_RUNTIME_DEP_PATH_LIST ${_libDllPath}) + + unset(_libDllPath) + file(GLOB _libDllPath "${_libDllBinPath}/liblz4.dll") + list(APPEND ALL_RUNTIME_DEP_PATH_LIST ${_libDllPath}) + + unset(_libDllPath) + file(GLOB _libDllPath "${_libDllBinPath}/liblzma-*.dll") + list(APPEND ALL_RUNTIME_DEP_PATH_LIST ${_libDllPath}) + + unset(_libDllPath) + file(GLOB _libDllPath "${_libDllBinPath}/libpcre-*.dll") + list(APPEND ALL_RUNTIME_DEP_PATH_LIST ${_libDllPath}) + + unset(_libDllPath) + file(GLOB _libDllPath "${_libDllBinPath}/libpcre2-*.dll") + list(APPEND ALL_RUNTIME_DEP_PATH_LIST ${_libDllPath}) + + unset(_libDllPath) + file(GLOB _libDllPath "${_libDllBinPath}/libpng*-*.dll") + list(APPEND ALL_RUNTIME_DEP_PATH_LIST ${_libDllPath}) + + unset(_libDllPath) + file(GLOB _libDllPath "${_libDllBinPath}/libstdc++-*.dll") + list(APPEND ALL_RUNTIME_DEP_PATH_LIST ${_libDllPath}) + + unset(_libDllPath) + file(GLOB _libDllPath "${_libDllBinPath}/libwinpthread-*.dll") + list(APPEND ALL_RUNTIME_DEP_PATH_LIST ${_libDllPath}) + + unset(_libDllPath) + file(GLOB _libDllPath "${_libDllBinPath}/zlib*.dll") + list(APPEND ALL_RUNTIME_DEP_PATH_LIST ${_libDllPath}) + + unset(_libDllPath) + file(GLOB _libDllPath "${_libDllBinPath}/libb2-*.dll") + list(APPEND ALL_RUNTIME_DEP_PATH_LIST ${_libDllPath}) + + # openssl + unset(_libDllPath) + file(GLOB _libDllPath "${_libDllBinPath}/libssl-*.dll") + list(APPEND ALL_RUNTIME_DEP_PATH_LIST ${_libDllPath}) + + unset(_libDllPath) + file(GLOB _libDllPath "${_libDllBinPath}/libcrypto-*.dll") + list(APPEND ALL_RUNTIME_DEP_PATH_LIST ${_libDllPath}) + + # gpgme-w32spawn.exe + unset(_libExEPath) + file(GLOB _libExEPath "${_libDllBinPath}/gpgme-w32spawn.exe") + list(APPEND ALL_RUNTIME_DEP_PATH_LIST ${_libExEPath}) + + set(ALL_RUNTIME_DLL_FILES "") + list(APPEND ALL_RUNTIME_DLL_FILES "Qt6Core.dll;Qt6Core5Compat.dll;Qt6Gui.dll;Qt6Network.dll;Qt6PrintSupport.dll;Qt6Svg.dll;Qt6Widgets.dll;libbrotlicommon.dll;libbrotlidec.dll;libdouble-conversion.dll;libzstd.dll;libmd4c.dll;") + # find the other dlls + foreach (_dllFileName ${ALL_RUNTIME_DLL_FILES}) + message(STATUS "DLL FILE ${_dllFileName}") + list(APPEND ALL_DLL_NAME ${_dllFileName}) + unset(_runtimeDllLocalPath) + + find_file(_runtimeDllLocalPath NAMES ${_dllFileName} NO_CACHE REQUIRED) + list(APPEND ALL_RUNTIME_DEP_PATH_LIST ${_runtimeDllLocalPath}) + message(STATUS "DLL ${_dllFileName} Path is ${_runtimeDllLocalPath}") + endforeach() + + message(STATUS "All Runtime Dependencies Path ${ALL_RUNTIME_DEP_PATH_LIST}") + + # copy dependencies to release path + foreach (_dllRuntimeFilePath ${ALL_RUNTIME_DEP_PATH_LIST}) + file(COPY ${_dllRuntimeFilePath} DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN) + endforeach() + endif () endif () @@ -183,8 +351,16 @@ if (APPLICATION_BUILD) if (${CMAKE_BUILD_TYPE} STREQUAL "Release") if (MINGW) add_executable(${AppName} WIN32 ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS}) - # custom app bundle packing + # include qt dependencies + if(NOT Qt6_DIR) + add_custom_command(TARGET ${AppName} POST_BUILD + COMMAND windeployqt --force ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${AppName}.exe) + else() + add_custom_command(TARGET ${AppName} POST_BUILD + COMMAND windeployqt-qt6.exe --force ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${AppName}.exe) + endif() elseif (APPLE AND NOT XCODE_BUILD) + # custom app bundle packing add_executable(${AppName} MACOSX_BUNDLE ${ICON_RESOURCE} ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS}) set_target_properties(${AppName} PROPERTIES BUNDLE True @@ -214,6 +390,7 @@ if (APPLICATION_BUILD) COMMENT "Complement to build the required architecture") # app bundle packing using xcode elseif (APPLE AND XCODE_BUILD) + # standard app bundle packing add_executable(${AppName} MACOSX_BUNDLE ${ICON_RESOURCE} ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS}) set_target_properties(${AppName} PROPERTIES BUNDLE True @@ -239,19 +416,43 @@ if (APPLICATION_BUILD) COMMAND macdeployqt ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_BUILD_TYPE}/${AppName}.app WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} COMMENT "Resolving Qt Dependency") + + # option for sandbox mode, still under test + if(GPGFRONTEND_XOCDE_ENABLE_SANDBOX) + set(CUSTOM_ATTRIBUTE_ENABLE_APP_SANDBOX "Yes") + add_custom_command(TARGET ${AppName} POST_BUILD + COMMAND /bin/cp -rf ${CMAKE_SOURCE_DIR}/resource/lfs/macOS/GnuPG ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_BUILD_TYPE}/${AppName}.app/Contents/ + WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} + COMMENT "Copying Buddled GnuPG into App Bundle Resource") + else() + set(CUSTOM_ATTRIBUTE_ENABLE_APP_SANDBOX "No") + endif() + set_target_properties(${AppName} PROPERTIES XCODE_ATTRIBUTE_INSTALL_PATH "$(LOCAL_APPS_DIR)" XCODE_ATTRIBUTE_SKIP_INSTALL "No" XCODE_ATTRIBUTE_OTHER_CODE_SIGN_FLAGS "--deep --entitlements ${CMAKE_SOURCE_DIR}/resource/plist/entitlement.plist" - XCODE_ATTRIBUTE_ENABLE_APP_SANDBOX "No" + XCODE_ATTRIBUTE_ENABLE_APP_SANDBOX "${CUSTOM_ATTRIBUTE_ENABLE_APP_SANDBOX}" XCODE_ATTRIBUTE_ENABLE_HARDENED_RUNTIME "Yes" + XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${CMAKE_SOURCE_DIR}/GpgFrontend.entitlements" XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "${GPGFRONTEND_XOCDE_CODE_SIGN_IDENTITY}" ) else () add_executable(${AppName} ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS}) endif () else () + # if the status is debug add_executable(${AppName} ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS}) + if(MINGW) + # include qt dependencies + if(NOT Qt6_DIR) + add_custom_command(TARGET ${AppName} POST_BUILD + COMMAND windeployqt --force ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${AppName}.exe) + else() + add_custom_command(TARGET ${AppName} POST_BUILD + COMMAND windeployqt-qt6.exe --force ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${AppName}.exe) + endif() + endif() endif () # Make app build with resources diff --git a/src/GpgFrontend.h.in b/src/GpgFrontend.h.in index 78ab6e6a..f441fb8f 100644 --- a/src/GpgFrontend.h.in +++ b/src/GpgFrontend.h.in @@ -57,9 +57,8 @@ // logging system -#define ELPP_DEFAULT_LOGGING_FLAGS 8192 -#include <easylogging++.h> - +#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE +#include <spdlog/spdlog.h> // build info #define PROJECT_NAME "@CMAKE_PROJECT_NAME@" diff --git a/src/before_exit.cpp b/src/before_exit.cpp index f13649db..31c56354 100644 --- a/src/before_exit.cpp +++ b/src/before_exit.cpp @@ -32,4 +32,6 @@ * @brief Actions performed before exiting the application * */ -void before_exit() { LOG(INFO) << "called"; } +void before_exit() { + +} diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 0282b58c..22a0b88a 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -46,11 +46,6 @@ if (NOT LINUX) target_link_libraries(gpgfrontend_core PUBLIC config++ intl) endif () -# easyloggingpp -target_include_directories(gpgfrontend_core PUBLIC - ${CMAKE_SOURCE_DIR}/third_party/easyloggingpp/src) -target_sources(gpgfrontend_core PUBLIC - ${CMAKE_SOURCE_DIR}/third_party/easyloggingpp/src/easylogging++.cc) # qt-aes target_sources(gpgfrontend_core PRIVATE ${CMAKE_SOURCE_DIR}/third_party/qt-aes/qaesencryption.cpp) @@ -82,6 +77,9 @@ if (MINGW) target_link_libraries(gpgfrontend_core PUBLIC bcrypt) endif () +# spdlog +target_link_libraries(gpgfrontend_core PRIVATE spdlog) + # link libarchive target_link_libraries(gpgfrontend_core PRIVATE archive) @@ -89,7 +87,11 @@ target_link_libraries(gpgfrontend_core PRIVATE archive) target_link_libraries(gpgfrontend_core PUBLIC nlohmann_json::nlohmann_json) # link Qt core -target_link_libraries(gpgfrontend_core PUBLIC Qt5::Core) +if(Qt6_DIR) + target_link_libraries(gpgfrontend_core PUBLIC Qt6::Core) +else() + target_link_libraries(gpgfrontend_core PUBLIC Qt5::Core) +endif() # set up pch target_precompile_headers(gpgfrontend_core diff --git a/src/core/GpgConstants.cpp b/src/core/GpgConstants.cpp index ff783872..35e485d4 100644 --- a/src/core/GpgConstants.cpp +++ b/src/core/GpgConstants.cpp @@ -53,9 +53,8 @@ const char* GpgFrontend::GpgConstants::GPG_FRONTEND_SHORT_CRYPTO_HEAD = gpgme_error_t GpgFrontend::check_gpg_error(gpgme_error_t err) { if (gpg_err_code(err) != GPG_ERR_NO_ERROR) { - LOG(ERROR) << "[" << _("Error") << gpg_err_code(err) << "]" << _("Source: ") - << gpgme_strsource(err) << _("Description: ") - << gpgme_strerror(err); + SPDLOG_ERROR("[error: {}] source: {} description: {}", gpg_err_code(err), + gpgme_strsource(err), gpgme_strerror(err)); } return err; } @@ -65,14 +64,13 @@ gpg_err_code_t GpgFrontend::check_gpg_error_2_err_code(gpgme_error_t err, auto err_code = gpg_err_code(err); if (err_code != gpg_err_code(predict)) { if (err_code == GPG_ERR_NO_ERROR) - LOG(WARNING) << "[" << _("Warning") << gpg_err_code(err) << "]" - << _("Source: ") << gpgme_strsource(err) - << _("Description: ") << gpgme_strerror(err) << _("Predict") - << gpgme_strerror(err); + SPDLOG_WARN("[Warning {}] Source: {} description: {} predict: {}", + gpg_err_code(err), gpgme_strsource(err), gpgme_strerror(err), + gpgme_strerror(err)); else - LOG(ERROR) << "[" << _("Error") << gpg_err_code(err) << "]" - << _("Source: ") << gpgme_strsource(err) << _("Description: ") - << gpgme_strerror(err) << _("Predict") << gpgme_strerror(err); + SPDLOG_ERROR("[Error {}] Source: {} description: {} predict: {}", + gpg_err_code(err), gpgme_strsource(err), gpgme_strerror(err), + gpgme_strerror(err)); } return err_code; } @@ -80,9 +78,9 @@ gpg_err_code_t GpgFrontend::check_gpg_error_2_err_code(gpgme_error_t err, gpgme_error_t GpgFrontend::check_gpg_error(gpgme_error_t err, const std::string& comment) { if (gpg_err_code(err) != GPG_ERR_NO_ERROR) { - LOG(ERROR) << "[" << _("Error") << gpg_err_code(err) << "]" << _("Source: ") - << gpgme_strsource(err) << _("Description: ") - << gpgme_strerror(err); + SPDLOG_WARN("[Error {}] Source: {} description: {} predict: {}", + gpg_err_code(err), gpgme_strsource(err), gpgme_strerror(err), + gpgme_strerror(err)); } return err; } @@ -201,6 +199,6 @@ GpgFrontend::GpgGenKeyResult GpgFrontend::_new_result( } void GpgFrontend::_result_ref_deletor::operator()(void* _result) { - DLOG(INFO) << _("Called") << _result; + SPDLOG_TRACE("gpgme unref {}", _result); if (_result != nullptr) gpgme_result_unref(_result); } diff --git a/src/core/GpgContext.cpp b/src/core/GpgContext.cpp index 7ebd9fa9..a5213134 100644 --- a/src/core/GpgContext.cpp +++ b/src/core/GpgContext.cpp @@ -30,12 +30,19 @@ #include <gpg-error.h> #include <gpgme.h> +#include <unistd.h> -#include <functional> +#include <mutex> +#include <shared_mutex> #include <string> -#include <utility> -#include "GpgConstants.h" +#include "core/GpgConstants.h" +#include "core/GpgModel.h" +#include "core/common/CoreCommonUtil.h" +#include "core/function/CoreSignalStation.h" +#include "core/function/gpg/GpgCommandExecutor.h" +#include "core/thread/TaskRunnerGetter.h" +#include "thread/Task.h" #ifdef _WIN32 #include <windows.h> @@ -55,7 +62,7 @@ GpgContext::GpgContext(const GpgContextInitArgs &args) : args_(args) { if (_first) { /* Initialize the locale environment. */ - LOG(INFO) << "locale" << setlocale(LC_CTYPE, nullptr); + SPDLOG_DEBUG("locale: {}", setlocale(LC_CTYPE, nullptr)); info_.GpgMEVersion = gpgme_check_version(nullptr); gpgme_set_locale(nullptr, LC_CTYPE, setlocale(LC_CTYPE, nullptr)); #ifdef LC_MESSAGES @@ -87,15 +94,14 @@ GpgContext::GpgContext(const GpgContextInitArgs &args) : args_(args) { continue; } - LOG(INFO) << gpgme_get_protocol_name(engine_info->protocol) - << std::string(engine_info->file_name == nullptr - ? "null" - : engine_info->file_name) - << std::string(engine_info->home_dir == nullptr - ? "null" - : engine_info->home_dir) - << std::string(engine_info->version ? "null" - : engine_info->version); + SPDLOG_DEBUG( + "gpg context engine info: {} {} {} {}", + gpgme_get_protocol_name(engine_info->protocol), + std::string(engine_info->file_name == nullptr ? "null" + : engine_info->file_name), + std::string(engine_info->home_dir == nullptr ? "null" + : engine_info->home_dir), + std::string(engine_info->version ? "null" : engine_info->version)); switch (engine_info->protocol) { case GPGME_PROTOCOL_OpenPGP: @@ -137,7 +143,7 @@ GpgContext::GpgContext(const GpgContextInitArgs &args) : args_(args) { auto err = gpgme_ctx_set_engine_info(_ctx_ref.get(), GPGME_PROTOCOL_OpenPGP, info_.AppPath.c_str(), info_.DatabasePath.c_str()); - LOG(INFO) << "ctx set custom key db path:" << info_.DatabasePath; + SPDLOG_DEBUG("ctx set custom key db path: {}", info_.DatabasePath); assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR); } @@ -149,20 +155,28 @@ GpgContext::GpgContext(const GpgContextInitArgs &args) : args_(args) { if (!check_passed) { this->good_ = false; - LOG(ERROR) << "Env check failed"; + SPDLOG_ERROR("env check failed"); return; } else { - LOG(INFO) << "gnupg version" << info_.GnupgVersion; - init_ctx(); + // async, init context + Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_GPG) + ->PostTask(new Thread::Task( + [=](Thread::Task::DataObjectPtr) -> int { + post_init_ctx(); + return 0; + }, + "post_init_ctx")); + good_ = true; } } -void GpgContext::init_ctx() { +void GpgContext::post_init_ctx() { // Set Independent Database if (info_.GnupgVersion <= "2.0.0" && args_.independent_database) { info_.DatabasePath = args_.db_path; - LOG(INFO) << "custom key db path" << info_.DatabasePath; + SPDLOG_DEBUG("custom key db path {}", info_.DatabasePath); auto err = gpgme_ctx_set_engine_info(_ctx_ref.get(), GPGME_PROTOCOL_OpenPGP, info_.AppPath.c_str(), info_.DatabasePath.c_str()); @@ -198,10 +212,18 @@ void GpgContext::init_ctx() { // for unit test if (args_.test_mode) { - LOG(INFO) << "test mode"; if (info_.GnupgVersion >= "2.1.0") SetPassphraseCb(test_passphrase_cb); gpgme_set_status_cb(*this, test_status_cb, nullptr); } + + // preload info + auto &info = GetInfo(); + + // listen passphrase input event + SetPassphraseCb(custom_passphrase_cb); + connect(this, &GpgContext::SignalNeedUserInputPassphrase, + CoreSignalStation::GetInstance(), + &CoreSignalStation::SignalNeedUserInputPassphrase); } bool GpgContext::good() const { return good_; } @@ -213,7 +235,7 @@ void GpgContext::SetPassphraseCb(gpgme_passphrase_cb_t cb) const { } gpgme_set_passphrase_cb(*this, cb, nullptr); } else { - LOG(ERROR) << "Not supported for gnupg version" << info_.GnupgVersion; + SPDLOG_ERROR("not supported for gnupg version: {}", info_.GnupgVersion); } } @@ -234,12 +256,327 @@ gpgme_error_t GpgContext::test_passphrase_cb(void *opaque, const char *uid_hint, return off == pass_len ? 0 : gpgme_error_from_errno(errno); } +gpgme_error_t GpgContext::custom_passphrase_cb(void *opaque, + const char *uid_hint, + const char *passphrase_info, + int last_was_bad, int fd) { + SPDLOG_DEBUG("custom passphrase cb called, bad times: {}", last_was_bad); + + if (last_was_bad > 3) { + SPDLOG_WARN("failure_counts is over three times"); + return gpgme_error_from_errno(GPG_ERR_CANCELED); + } + + std::string passphrase = + CoreCommonUtil::GetInstance()->GetTempCacheValue("__key_passphrase"); + // no pawword is an error situation + if (passphrase.empty()) { + // user input passphrase + SPDLOG_DEBUG("might need user to input passparase"); + passphrase = GpgContext::GetInstance().need_user_input_passphrase(); + if (passphrase.empty()) { + gpgme_io_write(fd, "\n", 1); + return gpgme_error_from_errno(GPG_ERR_CANCELED); + } + } + + // the user must at least write a newline character before returning from the + // callback. + passphrase = passphrase.append("\n"); + auto passpahrase_size = passphrase.size(); + + size_t off = 0, res = 0; + do { + res = gpgme_io_write(fd, &passphrase[off], passpahrase_size - off); + if (res > 0) off += res; + } while (res > 0 && off != passpahrase_size); + + return off == passpahrase_size ? 0 : gpgme_error_from_errno(GPG_ERR_CANCELED); +} + gpgme_error_t GpgContext::test_status_cb(void *hook, const char *keyword, const char *args) { - LOG(INFO) << "keyword" << keyword; + SPDLOG_DEBUG("keyword {}", keyword); return GPG_ERR_NO_ERROR; } +std::string GpgContext::need_user_input_passphrase() { + emit SignalNeedUserInputPassphrase(); + + std::string final_passphrase; + bool input_done = false; + SPDLOG_DEBUG("loop start to wait from user"); + auto connection = + connect(CoreSignalStation::GetInstance(), + &CoreSignalStation::SignalUserInputPassphraseDone, this, + [&](QString passphrase) { + SPDLOG_DEBUG("SignalUserInputPassphraseDone emitted"); + final_passphrase = passphrase.toStdString(); + input_done = true; + }); + while (!input_done) { + QCoreApplication::processEvents(QEventLoop::AllEvents, 800); + } + disconnect(connection); + + SPDLOG_DEBUG("lopper end"); + return final_passphrase; +} + +const GpgInfo &GpgContext::GetInfo(bool refresh) { + if (!extend_info_loaded_ || refresh) { + // try lock + std::unique_lock lock(preload_lock_); + + // check twice + if (extend_info_loaded_ && !refresh) return info_; + + SPDLOG_DEBUG("start to load extra info"); + + // get all components + GpgCommandExecutor::GetInstance().Execute( + info_.GpgConfPath, {"--list-components"}, + [=](int exit_code, const std::string &p_out, const std::string &p_err) { + SPDLOG_DEBUG( + "gpgconf components exit_code: {} process stdout size: {}", + exit_code, p_out.size()); + + if (exit_code != 0) { + SPDLOG_ERROR( + "gpgconf execute error, process stderr: {} ,process stdout: " + "{}", + p_err, p_out); + return; + } + + auto &components_info = info_.ComponentsInfo; + components_info["gpgme"] = {"GPG Made Easy", info_.GpgMEVersion, + _("Embedded In"), "/"}; + + auto gpgconf_binary_checksum = + check_binary_chacksum(info_.GpgConfPath); + components_info["gpgconf"] = {"GPG Configure", "/", info_.GpgConfPath, + gpgconf_binary_checksum.has_value() + ? gpgconf_binary_checksum.value() + : "/"}; + + std::vector<std::string> line_split_list; + boost::split(line_split_list, p_out, boost::is_any_of("\n")); + + for (const auto &line : line_split_list) { + std::vector<std::string> info_split_list; + boost::split(info_split_list, line, boost::is_any_of(":")); + + if (info_split_list.size() != 3) continue; + + auto component_name = info_split_list[0]; + auto component_desc = info_split_list[1]; + auto component_path = info_split_list[2]; + auto binary_checksum = check_binary_chacksum(component_path); + + SPDLOG_DEBUG( + "gnupg component name: {} desc: {} checksum: {} path: {} ", + component_name, component_desc, + binary_checksum.has_value() ? binary_checksum.value() : "/", + component_path); + + std::string version = "/"; + + if (component_name == "gpg") { + version = info_.GnupgVersion; + } + if (component_name == "gpg-agent") { + info_.GpgAgentPath = info_split_list[2]; + } + if (component_name == "dirmngr") { + info_.DirmngrPath = info_split_list[2]; + } + if (component_name == "keyboxd") { + info_.KeyboxdPath = info_split_list[2]; + } + + { + // try lock + std::unique_lock lock(info_.Lock); + // add component info to list + components_info[component_name] = { + component_desc, version, component_path, + binary_checksum.has_value() ? binary_checksum.value() : "/"}; + } + } + }); + + SPDLOG_DEBUG("start to get dirs info"); + + GpgCommandExecutor::GetInstance().ExecuteConcurrently( + info_.GpgConfPath, {"--list-dirs"}, + [=](int exit_code, const std::string &p_out, const std::string &p_err) { + SPDLOG_DEBUG( + "gpgconf configurations exit_code: {} process stdout size: {}", + exit_code, p_out.size()); + + if (exit_code != 0) { + SPDLOG_ERROR( + "gpgconf execute error, process stderr: {} process stdout: " + "{}", + p_err, p_out); + return; + } + + auto &configurations_info = info_.ConfigurationsInfo; + + std::vector<std::string> line_split_list; + boost::split(line_split_list, p_out, boost::is_any_of("\n")); + + for (const auto &line : line_split_list) { + std::vector<std::string> info_split_list; + boost::split(info_split_list, line, boost::is_any_of(":")); + SPDLOG_DEBUG("gpgconf info line: {} info size: {}", line, + info_split_list.size()); + + if (info_split_list.size() != 2) continue; + + // record gnupg home path + if (info_split_list[0] == "homedir") { + info_.GnuPGHomePath = info_split_list[1]; + } + + auto configuration_name = info_split_list[0]; + { + // try lock + std::unique_lock lock(info_.Lock); + configurations_info[configuration_name] = {info_split_list[1]}; + } + } + }); + + SPDLOG_DEBUG("start to get components info"); + + for (const auto &component : info_.ComponentsInfo) { + SPDLOG_DEBUG("gpgconf check options ready", "component", component.first); + + if (component.first == "gpgme" || component.first == "gpgconf") continue; + + GpgCommandExecutor::GetInstance().ExecuteConcurrently( + info_.GpgConfPath, {"--check-options", component.first}, + [=](int exit_code, const std::string &p_out, + const std::string &p_err) { + SPDLOG_DEBUG( + "gpgconf {} options exit_code: {} process stdout " + "size: {} ", + component.first, exit_code, p_out.size()); + + if (exit_code != 0) { + SPDLOG_ERROR( + "gpgconf {} options execute error, process " + "stderr: {} , process stdout:", + component.first, p_err, p_out); + return; + } + + auto &options_info = info_.OptionsInfo; + + std::vector<std::string> line_split_list; + boost::split(line_split_list, p_out, boost::is_any_of("\n")); + + for (const auto &line : line_split_list) { + std::vector<std::string> info_split_list; + boost::split(info_split_list, line, boost::is_any_of(":")); + + SPDLOG_DEBUG("component {} options line: {} info size: {}", + component.first, line, info_split_list.size()); + + if (info_split_list.size() != 6) continue; + + auto configuration_name = info_split_list[0]; + { + // try lock + std::unique_lock lock(info_.Lock); + options_info[configuration_name] = { + info_split_list[1], info_split_list[2], info_split_list[3], + info_split_list[4], info_split_list[5]}; + } + } + }); + } + + SPDLOG_DEBUG("start to get avaliable component options info"); + + for (const auto &component : info_.ComponentsInfo) { + SPDLOG_DEBUG("gpgconf list options ready", "component", component.first); + + if (component.first == "gpgme" || component.first == "gpgconf") continue; + + GpgCommandExecutor::GetInstance().ExecuteConcurrently( + info_.GpgConfPath, {"--list-options", component.first}, + [=](int exit_code, const std::string &p_out, + const std::string &p_err) { + SPDLOG_DEBUG( + "gpgconf {} avaliable options exit_code: {} process stdout " + "size: {} ", + component.first, exit_code, p_out.size()); + + if (exit_code != 0) { + SPDLOG_ERROR( + "gpgconf {} avaliable options execute error, process stderr: " + "{} , process stdout:", + component.first, p_err, p_out); + return; + } + + auto &available_options_info = info_.AvailableOptionsInfo; + + std::vector<std::string> line_split_list; + boost::split(line_split_list, p_out, boost::is_any_of("\n")); + + for (const auto &line : line_split_list) { + std::vector<std::string> info_split_list; + boost::split(info_split_list, line, boost::is_any_of(":")); + + SPDLOG_DEBUG( + "component {} avaliable options line: {} info size: {}", + component.first, line, info_split_list.size()); + + if (info_split_list.size() != 10) continue; + + auto configuration_name = info_split_list[0]; + { + // try lock + std::unique_lock lock(info_.Lock); + available_options_info[configuration_name] = { + info_split_list[1], info_split_list[2], info_split_list[3], + info_split_list[4], info_split_list[5], info_split_list[6], + info_split_list[7], info_split_list[8], info_split_list[9]}; + } + } + }); + } + extend_info_loaded_ = true; + } + + // ensure nothing is changing now + std::shared_lock lock(preload_lock_); + return info_; +} + +std::optional<std::string> GpgContext::check_binary_chacksum( + std::filesystem::path path) { + QFile f(QString::fromStdString(path.u8string())); + if (!f.open(QFile::ReadOnly)) return {}; + + // read all data from file + auto buffer = f.readAll(); + f.close(); + + auto hash_md5 = QCryptographicHash(QCryptographicHash::Md5); + // md5 + hash_md5.addData(buffer); + auto md5 = hash_md5.result().toHex().toStdString(); + SPDLOG_DEBUG("md5 {}", md5); + + return md5.substr(0, 6); +} + void GpgContext::_ctx_ref_deleter::operator()(gpgme_ctx_t _ctx) { if (_ctx != nullptr) gpgme_release(_ctx); } diff --git a/src/core/GpgContext.h b/src/core/GpgContext.h index e1f1bda4..384271a6 100644 --- a/src/core/GpgContext.h +++ b/src/core/GpgContext.h @@ -29,6 +29,9 @@ #ifndef __SGPGMEPP_CONTEXT_H__ #define __SGPGMEPP_CONTEXT_H__ +#include <optional> +#include <string> + #include "GpgConstants.h" #include "GpgFunctionObject.h" #include "GpgInfo.h" @@ -57,7 +60,9 @@ struct GpgContextInitArgs { * */ class GPGFRONTEND_CORE_EXPORT GpgContext - : public SingletonFunctionObject<GpgContext> { + : public QObject, + public SingletonFunctionObject<GpgContext> { + Q_OBJECT public: /** * @brief Construct a new Gpg Context object @@ -92,7 +97,7 @@ class GPGFRONTEND_CORE_EXPORT GpgContext * * @return const GpgInfo& */ - [[nodiscard]] const GpgInfo& GetInfo() const { return info_; } + [[nodiscard]] const GpgInfo& GetInfo(bool refresh = false); /** * @brief @@ -102,14 +107,29 @@ class GPGFRONTEND_CORE_EXPORT GpgContext operator gpgme_ctx_t() const { return _ctx_ref.get(); } private: - GpgInfo info_; ///< - GpgContextInitArgs args_; ///< + GpgInfo info_{}; ///< + GpgContextInitArgs args_{}; ///< + bool extend_info_loaded_ = false; + std::shared_mutex preload_lock_{}; /** * @brief * */ - void init_ctx(); + void post_init_ctx(); + + /** + * @brief + * + * @return std::string + */ + std::string need_user_input_passphrase(); + + /** + * @brief Construct a new std::check component existence object + * + */ + std::optional<std::string> check_binary_chacksum(std::filesystem::path); /** * @brief @@ -124,6 +144,13 @@ class GPGFRONTEND_CORE_EXPORT GpgContext CtxRefHandler _ctx_ref = nullptr; ///< bool good_ = true; ///< + signals: + /** + * @brief + * + */ + void SignalNeedUserInputPassphrase(); + public: /** * @brief @@ -142,6 +169,20 @@ class GPGFRONTEND_CORE_EXPORT GpgContext /** * @brief * + * @param opaque + * @param uid_hint + * @param passphrase_info + * @param last_was_bad + * @param fd + * @return gpgme_error_t + */ + static gpgme_error_t custom_passphrase_cb(void* opaque, const char* uid_hint, + const char* passphrase_info, + int last_was_bad, int fd); + + /** + * @brief + * * @param hook * @param keyword * @param args diff --git a/src/core/GpgCoreInit.cpp b/src/core/GpgCoreInit.cpp index 9ccc693d..840b2b87 100644 --- a/src/core/GpgCoreInit.cpp +++ b/src/core/GpgCoreInit.cpp @@ -25,15 +25,17 @@ * SPDX-License-Identifier: GPL-3.0-or-later * */ - #include "GpgCoreInit.h" +#include <spdlog/async.h> +#include <spdlog/common.h> +#include <spdlog/sinks/rotating_file_sink.h> +#include <spdlog/sinks/stdout_color_sinks.h> + #include "GpgFunctionObject.h" #include "core/GpgContext.h" #include "core/function/GlobalSettingStation.h" - -// init easyloggingpp library -INITIALIZE_EASYLOGGINGPP +#include "function/gpg/GpgAdvancedOperator.h" namespace GpgFrontend { @@ -41,40 +43,51 @@ namespace GpgFrontend { * @brief setup logging system and do proper initialization * */ -void InitLoggingSystem() { +void InitCoreLoggingSystem() { using namespace boost::posix_time; using namespace boost::gregorian; - el::Loggers::addFlag(el::LoggingFlag::AutoSpacing); - el::Loggers::addFlag(el::LoggingFlag::ColoredTerminalOutput); - el::Loggers::addFlag(el::LoggingFlag::StrictLogFileSizeCheck); - el::Configurations defaultConf; - defaultConf.setToDefault(); - - // apply settings - defaultConf.setGlobally(el::ConfigurationType::Format, - "%datetime %level [core] {%func} -> %msg"); - - // apply settings no written to file - defaultConf.setGlobally(el::ConfigurationType::ToFile, "false"); - - // set the logger - el::Loggers::reconfigureLogger("default", defaultConf); - // get the log directory - auto logfile_path = (GlobalSettingStation::GetInstance().GetLogDir() / - to_iso_string(second_clock::local_time())); + auto logfile_path = + (GlobalSettingStation::GetInstance().GetLogDir() / "core"); logfile_path.replace_extension(".log"); - defaultConf.setGlobally(el::ConfigurationType::Filename, - logfile_path.u8string()); - - // apply settings written to file - defaultConf.setGlobally(el::ConfigurationType::ToFile, "true"); - // set the logger - el::Loggers::reconfigureLogger("default", defaultConf); + // sinks + std::vector<spdlog::sink_ptr> sinks; + sinks.push_back(std::make_shared<spdlog::sinks::stderr_color_sink_mt>()); + sinks.push_back(std::make_shared<spdlog::sinks::rotating_file_sink_mt>( + logfile_path.u8string(), 1048576 * 32, 8)); + + // thread pool + spdlog::init_thread_pool(1024, 2); + + // logger + auto core_logger = std::make_shared<spdlog::async_logger>( + "core", begin(sinks), end(sinks), spdlog::thread_pool()); + core_logger->set_pattern( + "[%H:%M:%S.%e] [T:%t] [%=4n] %^[%=8l]%$ [%s:%#] [%!] -> %v (+%ius)"); + +#ifdef DEBUG + core_logger->set_level(spdlog::level::trace); +#else + core_logger->set_level(spdlog::level::info); +#endif + + // flush policy + core_logger->flush_on(spdlog::level::err); + spdlog::flush_every(std::chrono::seconds(5)); + + // register it as default logger + spdlog::set_default_logger(core_logger); +} - LOG(INFO) << _("log file path") << logfile_path; +void ShutdownCoreLoggingSystem() { +#ifdef WINDOWS + // Under VisualStudio, this must be called before main finishes to workaround + // a known VS issue + spdlog::drop_all(); + spdlog::shutdown(); +#endif } void ResetGpgFrontendCore() { reset_gpgfrontend_core(); } @@ -89,12 +102,11 @@ void init_gpgfrontend_core() { use_custom_key_database_path = settings.lookup("general.use_custom_key_database_path"); } catch (...) { - LOG(ERROR) << _("Setting Operation Error") - << _("use_custom_key_database_path"); + SPDLOG_ERROR("setting operation error: use_custom_key_database_path"); } - LOG(INFO) << "core loaded if use custom key databse path: " - << use_custom_key_database_path; + SPDLOG_DEBUG("core loaded if use custom key databse path: {}", + use_custom_key_database_path); std::string custom_key_database_path; try { @@ -104,11 +116,11 @@ void init_gpgfrontend_core() { settings.lookup("general.custom_key_database_path")); } catch (...) { - LOG(ERROR) << _("Setting Operation Error") << _("custom_key_database_path"); + SPDLOG_ERROR("setting operation error: custom_key_database_path"); } - LOG(INFO) << "core loaded custom key databse path: " - << custom_key_database_path; + SPDLOG_DEBUG("core loaded custom key databse path: {}", + custom_key_database_path); // init default channel GpgFrontend::GpgContext::CreateInstance( @@ -136,6 +148,9 @@ void init_gpgfrontend_core() { return std::unique_ptr<ChannelObject>(new GpgContext(args)); }); + + // try to restart all components + GpgFrontend::GpgAdvancedOperator::GetInstance().RestartGpgComponents(); } void reset_gpgfrontend_core() { SingletonStorageCollection::GetInstance(true); } diff --git a/src/core/GpgCoreInit.h b/src/core/GpgCoreInit.h index 77942b56..41e04d60 100644 --- a/src/core/GpgCoreInit.h +++ b/src/core/GpgCoreInit.h @@ -37,7 +37,13 @@ namespace GpgFrontend { * @brief * */ -void GPGFRONTEND_CORE_EXPORT InitLoggingSystem(); +void GPGFRONTEND_CORE_EXPORT InitCoreLoggingSystem(); + +/** + * @brief + * + */ +void GPGFRONTEND_CORE_EXPORT ShutdownCoreLoggingSystem(); /** * @brief diff --git a/src/core/GpgFunctionObject.cpp b/src/core/GpgFunctionObject.cpp index 6ff83d72..0ddc290c 100644 --- a/src/core/GpgFunctionObject.cpp +++ b/src/core/GpgFunctionObject.cpp @@ -34,8 +34,6 @@ #include <mutex> #include <shared_mutex> -#include "easylogging++.h" - void GpgFrontend::ChannelObject::SetChannel(int channel) { this->channel_ = channel; } @@ -79,8 +77,8 @@ std::vector<int> GpgFrontend::SingletonStorage::GetAllChannelId() { GpgFrontend::ChannelObject* GpgFrontend::SingletonStorage::SetObjectInChannel( int channel, std::unique_ptr<ChannelObject> p_obj) { { - LOG(TRACE) << "set channel:" << channel - << "instance address:" << &instances_map_; + SPDLOG_TRACE("set channel: {} instance address: {}", channel, + static_cast<void*>(&instances_map_)); assert(p_obj != nullptr); if (p_obj == nullptr) return nullptr; @@ -111,9 +109,8 @@ GpgFrontend::SingletonStorageCollection::GetSingletonStorage( std::unique_lock<std::shared_mutex> lock(storages_mutex_); storages_map_.insert({hash, std::make_unique<SingletonStorage>()}); } - LOG(TRACE) << "hash:" << hash << "created" - << "storage address:" << &storages_map_ - << "type_name : " << type_id.name(); + SPDLOG_TRACE("hash: {} created, storage address: {} type_name: {}", hash, + static_cast<void*>(&storages_map_), type_id.name()); continue; } else { return _it->second.get(); @@ -128,7 +125,8 @@ GpgFrontend::SingletonStorageCollection::GetInstance( if (force_refresh || instance == nullptr) { instance = new SingletonStorageCollection(); - LOG(INFO) << "new single storage collection created: " << instance; + SPDLOG_DEBUG("new single storage collection created: {}", + static_cast<void*>(instance)); } return instance; diff --git a/src/core/GpgFunctionObject.h b/src/core/GpgFunctionObject.h index 56d0ab22..9b8c2aa3 100644 --- a/src/core/GpgFunctionObject.h +++ b/src/core/GpgFunctionObject.h @@ -29,6 +29,8 @@ #ifndef GPGFRONTEND_ZH_CN_TS_FUNCTIONOBJECT_H #define GPGFRONTEND_ZH_CN_TS_FUNCTIONOBJECT_H +#include <mutex> + #include "GpgConstants.h" namespace GpgFrontend { @@ -169,16 +171,33 @@ class SingletonFunctionObject : public ChannelObject { */ static T& GetInstance( int channel = GpgFrontend::GPGFRONTEND_DEFAULT_CHANNEL) { + static std::mutex g_channel_mutex_map_lock; + static std::map<int, std::mutex> g_channel_mutex_map; + + { + std::lock_guard<std::mutex> guard(g_channel_mutex_map_lock); + if (g_channel_mutex_map.find(channel) == g_channel_mutex_map.end()) { + g_channel_mutex_map[channel]; + } + } + static_assert(std::is_base_of<SingletonFunctionObject<T>, T>::value, "T not derived from SingletonFunctionObject<T>"); - auto p_storage = + auto* p_storage = SingletonStorageCollection::GetInstance(false)->GetSingletonStorage( typeid(T)); - auto* _p_pbj = (T*)(p_storage->FindObjectInChannel(channel)); if (_p_pbj == nullptr) { + // lock this channel + std::lock_guard<std::mutex> guard(g_channel_mutex_map[channel]); + + // double check + if ((_p_pbj = (T*)(p_storage->FindObjectInChannel(channel))) != nullptr) + return *_p_pbj; + + // do create object of this channel auto new_obj = std::unique_ptr<ChannelObject>(new T(channel)); return *(T*)(p_storage->SetObjectInChannel(channel, std::move(new_obj))); } else { diff --git a/src/core/GpgGenKeyInfo.cpp b/src/core/GpgGenKeyInfo.cpp index f9065529..290c93c2 100644 --- a/src/core/GpgGenKeyInfo.cpp +++ b/src/core/GpgGenKeyInfo.cpp @@ -38,7 +38,7 @@ void GpgFrontend::GenKeyInfo::SetAlgo( const GpgFrontend::GenKeyInfo::KeyGenAlgo &m_algo) { - LOG(INFO) << "set algo name" << m_algo.first; + SPDLOG_DEBUG("set algo name: {}", m_algo.first); // Check algo if supported std::string algo_args = m_algo.second; if (standalone_) { diff --git a/src/core/GpgInfo.h b/src/core/GpgInfo.h index d0453b9f..f4415af1 100644 --- a/src/core/GpgInfo.h +++ b/src/core/GpgInfo.h @@ -29,6 +29,7 @@ #ifndef GPGFRONTEND_ZH_CN_TS_GPGINFO_H #define GPGFRONTEND_ZH_CN_TS_GPGINFO_H +#include <mutex> #include <string> namespace GpgFrontend { @@ -38,13 +39,26 @@ namespace GpgFrontend { */ class GpgInfo { public: - std::string AppPath; ///< executable binary path of gnupg - std::string DatabasePath; ///< - std::string GnupgVersion; ///< - std::string GpgConfPath; ///< - std::string AssuanPath; ///< - std::string CMSPath; ///< + std::string GnupgVersion; ///< version of gnupg std::string GpgMEVersion; ///< + + std::string AppPath; ///< executable binary path of gnupg + std::string DatabasePath; ///< key database path + std::string GpgConfPath; ///< executable binary path of gpgconf + std::string AssuanPath; ///< executable binary path of assuan + std::string CMSPath; ///< executable binary path of cms + std::string GpgAgentPath; ///< executable binary path of gpg-agent + std::string DirmngrPath; ///< executable binary path of dirmgr + std::string KeyboxdPath; ///< executable binary path of keyboxd + + std::string GnuPGHomePath; ///< value of ---homedir + + std::map<std::string, std::vector<std::string>> ComponentsInfo; ///< + std::map<std::string, std::vector<std::string>> ConfigurationsInfo; ///< + std::map<std::string, std::vector<std::string>> OptionsInfo; ///< + std::map<std::string, std::vector<std::string>> AvailableOptionsInfo; ///< + + std::shared_mutex Lock; }; } // namespace GpgFrontend diff --git a/src/core/common/CoreCommonUtil.cpp b/src/core/common/CoreCommonUtil.cpp index 3b2b4007..93cad60a 100644 --- a/src/core/common/CoreCommonUtil.cpp +++ b/src/core/common/CoreCommonUtil.cpp @@ -26,15 +26,33 @@ #include "CoreCommonUtil.h"
+#include <string>
+
namespace GpgFrontend {
std::unique_ptr<CoreCommonUtil> CoreCommonUtil::instance_ = nullptr; ///<
-CoreCommonUtil *CoreCommonUtil::GetInstance() {
- LOG(INFO) << "called";
+CoreCommonUtil* CoreCommonUtil::GetInstance() {
if (instance_ == nullptr) {
instance_ = std::make_unique<CoreCommonUtil>();
}
return instance_.get();
}
+
+void CoreCommonUtil::SetTempCacheValue(const std::string& key,
+ const std::string& value) {
+ temp_cache_[key] = value;
+}
+
+std::string CoreCommonUtil::GetTempCacheValue(const std::string& key) {
+ std::string temp_cache_value;
+ std::swap(temp_cache_value, temp_cache_[key]);
+ return temp_cache_value;
+}
+
+void CoreCommonUtil::ResetTempCacheValue(const std::string& key) {
+ std::string temp_cache_value;
+ std::swap(temp_cache_value, temp_cache_[key]);
+}
+
} // namespace GpgFrontend
diff --git a/src/core/common/CoreCommonUtil.h b/src/core/common/CoreCommonUtil.h index 3762c4f0..58bb4d40 100644 --- a/src/core/common/CoreCommonUtil.h +++ b/src/core/common/CoreCommonUtil.h @@ -27,6 +27,8 @@ #ifndef GPGFRONTEND_CORECOMMONUTIL_H
#define GPGFRONTEND_CORECOMMONUTIL_H
+#include <string>
+
#include "core/GpgFrontendCore.h"
namespace GpgFrontend {
@@ -46,6 +48,27 @@ class GPGFRONTEND_CORE_EXPORT CoreCommonUtil : public QObject { */
CoreCommonUtil() = default;
+ /**
+ * @brief set a temp cache under a certain key
+ *
+ */
+ void SetTempCacheValue(const std::string &, const std::string &);
+
+ /**
+ * @brief after get the temp cache, its value will be imediately ease in
+ * storage
+ *
+ * @return std::string
+ */
+ std::string GetTempCacheValue(const std::string &);
+
+ /**
+ * @brief imediately ease temp cache in storage
+ *
+ * @return std::string
+ */
+ void ResetTempCacheValue(const std::string &);
+
signals:
/**
@@ -56,6 +79,7 @@ class GPGFRONTEND_CORE_EXPORT CoreCommonUtil : public QObject { private:
static std::unique_ptr<CoreCommonUtil> instance_; ///<
+ std::map<std::string, std::string> temp_cache_; //<
};
} // namespace GpgFrontend
diff --git a/src/core/function/ArchiveFileOperator.cpp b/src/core/function/ArchiveFileOperator.cpp index 64c7389e..04c9326f 100644 --- a/src/core/function/ArchiveFileOperator.cpp +++ b/src/core/function/ArchiveFileOperator.cpp @@ -38,14 +38,14 @@ int copy_data(struct archive *ar, struct archive *aw) { r = archive_read_data_block(ar, &buff, &size, &offset); if (r == ARCHIVE_EOF) return (ARCHIVE_OK); if (r != ARCHIVE_OK) { - LOG(ERROR) << "archive_read_data_block() failed: " - << archive_error_string(ar); + SPDLOG_ERROR("archive_read_data_block() failed: {}", + archive_error_string(ar)); return (r); } r = archive_write_data_block(aw, buff, size, offset); if (r != ARCHIVE_OK) { - LOG(ERROR) << "archive_write_data_block() failed: " - << archive_error_string(aw); + SPDLOG_ERROR("archive_write_data_block() failed: {}", + archive_error_string(aw)); return (r); } } @@ -55,7 +55,7 @@ void GpgFrontend::ArchiveFileOperator::CreateArchive( const std::filesystem::path &base_path, const std::filesystem::path &archive_path, int compress, const std::vector<std::filesystem::path> &files) { - LOG(INFO) << "CreateArchive: " << archive_path.u8string(); + SPDLOG_DEBUG("CreateArchive: {}", archive_path.u8string()); auto current_base_path_backup = QDir::currentPath(); QDir::setCurrent(base_path.u8string().c_str()); @@ -74,7 +74,7 @@ void GpgFrontend::ArchiveFileOperator::CreateArchive( ssize_t len; int fd; - LOG(INFO) << "compress: " << compress; + SPDLOG_DEBUG("compress: {}", compress); a = archive_write_new(); switch (compress) { @@ -119,7 +119,7 @@ void GpgFrontend::ArchiveFileOperator::CreateArchive( #endif int r; - LOG(INFO) << "reading file: " << file.u8string(); + SPDLOG_DEBUG("reading file: {}", file.u8string()); #ifdef WINDOWS r = archive_read_disk_open_w(disk, file.wstring().c_str()); @@ -127,11 +127,11 @@ void GpgFrontend::ArchiveFileOperator::CreateArchive( r = archive_read_disk_open(disk, file.u8string().c_str()); #endif - LOG(INFO) << "read file done: " << file.u8string(); + SPDLOG_DEBUG("read file done: {}", file.u8string()); if (r != ARCHIVE_OK) { - LOG(ERROR) << "archive_read_disk_open() failed: " - << archive_error_string(disk); + SPDLOG_ERROR("{archive_read_disk_open() failed: {}", + archive_error_string(disk)); throw std::runtime_error("archive_read_disk_open() failed"); } @@ -143,8 +143,8 @@ void GpgFrontend::ArchiveFileOperator::CreateArchive( if (r == ARCHIVE_EOF) break; if (r != ARCHIVE_OK) { - LOG(ERROR) << "archive_read_next_header2() failed: " - << archive_error_string(disk); + SPDLOG_ERROR("archive_read_next_header2() failed: {}", + archive_error_string(disk)); throw std::runtime_error("archive_read_next_header2() failed"); } archive_read_disk_descend(disk); @@ -158,14 +158,14 @@ void GpgFrontend::ArchiveFileOperator::CreateArchive( auto entry_path = std::string(archive_entry_pathname_utf8(entry)); #endif - LOG(INFO) << "Adding: " << archive_entry_pathname_utf8(entry) << "size" - << archive_entry_size(entry) << " bytes" - << "file type" << archive_entry_filetype(entry); + SPDLOG_DEBUG("Adding: {} size: {} bytes: {} file type: {}", + archive_entry_pathname_utf8(entry), + archive_entry_size(entry), archive_entry_filetype(entry)); r = archive_write_header(a, entry); if (r < ARCHIVE_OK) { - LOG(ERROR) << "archive_write_header() failed: " - << archive_error_string(a); + SPDLOG_ERROR("archive_write_header() failed: {}", + archive_error_string(a)); throw std::runtime_error("archive_write_header() failed"); } if (r == ARCHIVE_FATAL) throw std::runtime_error("archive fatal"); @@ -193,7 +193,7 @@ void GpgFrontend::ArchiveFileOperator::CreateArchive( void GpgFrontend::ArchiveFileOperator::ExtractArchive( const std::filesystem::path &archive_path, const std::filesystem::path &base_path) { - LOG(INFO) << "ExtractArchive: " << archive_path.u8string(); + SPDLOG_DEBUG("ExtractArchive: {}", archive_path.u8string()); auto current_base_path_backup = QDir::currentPath(); QDir::setCurrent(base_path.u8string().c_str()); @@ -228,7 +228,7 @@ void GpgFrontend::ArchiveFileOperator::ExtractArchive( auto filename = archive_path.u8string(); if (!filename.empty() && filename == u8"-") { - LOG(ERROR) << "cannot read from stdin"; + SPDLOG_ERROR("cannot read from stdin"); } #ifdef WINDOWS if (archive_read_open_filename_w(a, archive_path.wstring().c_str(), 10240) != @@ -237,29 +237,29 @@ void GpgFrontend::ArchiveFileOperator::ExtractArchive( if (archive_read_open_filename(a, archive_path.u8string().c_str(), 10240) != ARCHIVE_OK) { #endif - LOG(ERROR) << "archive_read_open_filename() failed: " - << archive_error_string(a); + SPDLOG_ERROR("archive_read_open_filename() failed: {}", + archive_error_string(a)); throw std::runtime_error("archive_read_open_filename() failed"); } for (;;) { r = archive_read_next_header(a, &entry); if (r == ARCHIVE_EOF) break; if (r != ARCHIVE_OK) { - LOG(ERROR) << "archive_read_next_header() failed: " - << archive_error_string(a); + SPDLOG_ERROR("archive_read_next_header() failed: {}", + archive_error_string(a)); throw std::runtime_error("archive_read_next_header() failed"); } - LOG(INFO) << "Extracting: " << archive_entry_pathname(entry) << "size" - << archive_entry_size(entry) << " bytes" - << "file type" << archive_entry_filetype(entry); + SPDLOG_DEBUG("Adding: {} size: {} bytes: {} file type: {}", + archive_entry_pathname_utf8(entry), archive_entry_size(entry), + archive_entry_filetype(entry)); r = archive_write_header(ext, entry); if (r != ARCHIVE_OK) { - LOG(ERROR) << "archive_write_header() failed: " - << archive_error_string(ext); + SPDLOG_ERROR("archive_write_header() failed: {}", + archive_error_string(ext)); } else { r = copy_data(a, ext); if (r != ARCHIVE_OK) { - LOG(ERROR) << "copy_data() failed: " << archive_error_string(ext); + SPDLOG_ERROR("copy_data() failed: {}", archive_error_string(ext)); } } } @@ -285,8 +285,8 @@ void GpgFrontend::ArchiveFileOperator::ListArchive( 10240); // Note 1 if (r != ARCHIVE_OK) return; while (archive_read_next_header(a, &entry) == ARCHIVE_OK) { - LOG(INFO) << "File: " << archive_entry_pathname(entry); - LOG(INFO) << "File Path: " << archive_entry_pathname(entry); + SPDLOG_DEBUG("File: {}", archive_entry_pathname(entry)); + SPDLOG_DEBUG("File Path: {}", archive_entry_pathname(entry)); archive_read_data_skip(a); // Note 2 } r = archive_read_free(a); // Note 3 diff --git a/src/core/function/CacheManager.cpp b/src/core/function/CacheManager.cpp new file mode 100644 index 00000000..a20b8003 --- /dev/null +++ b/src/core/function/CacheManager.cpp @@ -0,0 +1,66 @@ +/** + * Copyright (C) 2021 Saturneric + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "CacheManager.h" + +#include <algorithm> + +#include "function/DataObjectOperator.h" +#include "nlohmann/json_fwd.hpp" +#include "spdlog/spdlog.h" + +void GpgFrontend::CacheManager::SaveCache(std::string key, + const nlohmann::json &value) { + auto stored_data = + GpgFrontend::DataObjectOperator::GetInstance().GetDataObject( + "__cache_data_list"); + + // get cache data list from file system + nlohmann::json cache_data_list; + if (stored_data.has_value()) { + cache_data_list = std::move(stored_data.value()); + } + + if (!cache_data_list.is_array()) { + cache_data_list.clear(); + } + + if (GpgFrontend::DataObjectOperator::GetInstance() + .SaveDataObj(key, value) + .empty()) { + return; + } + + if (std::find(cache_data_list.begin(), cache_data_list.end(), key) == + cache_data_list.end()) { + cache_data_list.push_back(key); + } + + GpgFrontend::DataObjectOperator::GetInstance().SaveDataObj( + "__cache_data_list", cache_data_list); +} diff --git a/src/core/function/CacheManager.h b/src/core/function/CacheManager.h new file mode 100644 index 00000000..e489182f --- /dev/null +++ b/src/core/function/CacheManager.h @@ -0,0 +1,45 @@ +/** + * 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_CACHEMANAGER_H +#define GPGFRONTEND_CACHEMANAGER_H + +namespace GpgFrontend { + +class CacheManager { + public: + static void SaveCache(std::string key, const nlohmann::json &value); + + static nlohmann::json LoadCache(std::string name); + + static void ClearAllCache(); +}; + +} // namespace GpgFrontend + +#endif diff --git a/src/core/function/CharsetOperator.cpp b/src/core/function/CharsetOperator.cpp index 81c23388..0e40e317 100644 --- a/src/core/function/CharsetOperator.cpp +++ b/src/core/function/CharsetOperator.cpp @@ -28,6 +28,7 @@ #include "core/function/CharsetOperator.h" +#include <spdlog/spdlog.h> #include <unicode/ucnv.h> #include <unicode/ucsdet.h> #include <unicode/ustring.h> @@ -37,8 +38,6 @@ #include <memory> #include <string> -#include "easylogging++.h" - GpgFrontend::CharsetOperator::CharsetInfo GpgFrontend::CharsetOperator::Detect( const std::string &buffer) { const UCharsetMatch *ucm; @@ -47,17 +46,17 @@ GpgFrontend::CharsetOperator::CharsetInfo GpgFrontend::CharsetOperator::Detect( status = U_ZERO_ERROR; if (U_FAILURE(status)) { - LOG(ERROR) << "Failed to open charset detector: " << u_errorName(status); + SPDLOG_ERROR("failed to open charset detector: {}", u_errorName(status)); return {"unknown", "unknown", 0}; } - LOG(INFO) << "Detecting charset buffer:" << buffer.size() << "bytes"; + SPDLOG_DEBUG("detecting charset buffer: {} bytes", buffer.size()); status = U_ZERO_ERROR; ucsdet_setText(csd, buffer.data(), buffer.size(), &status); if (U_FAILURE(status)) { - LOG(ERROR) << "Failed to set text to charset detector: " - << u_errorName(status); + SPDLOG_ERROR("failed to set text to charset detector: {}", + u_errorName(status)); return {"unknown", "unknown", 0}; } @@ -78,7 +77,7 @@ GpgFrontend::CharsetOperator::CharsetInfo GpgFrontend::CharsetOperator::Detect( const char *language = ucsdet_getLanguage(ucm, &status); if (U_FAILURE(status)) return {name, "unknown", confidence}; - LOG(INFO) << "Detected charset: " << name << language << confidence; + SPDLOG_DEBUG("Detected charset: {} {} {}", name, language, confidence); return {name, language, confidence}; } @@ -89,14 +88,14 @@ bool GpgFrontend::CharsetOperator::Convert2Utf8(const std::string &buffer, const auto from_encode = std::string("utf-8"); const auto to_encode = from_charset_name; - LOG(INFO) << "Converting buffer:" << buffer.size(); + SPDLOG_DEBUG("Converting buffer: {}", buffer.size()); // test if the charset is supported UConverter *conv = ucnv_open(from_encode.c_str(), &status); ucnv_close(conv); if (U_FAILURE(status)) { - LOG(ERROR) << "Failed to open converter: " << u_errorName(status) << ":" - << from_encode; + SPDLOG_ERROR("failed to open converter: {}, from encode: {}", + u_errorName(status), from_encode); return false; } @@ -104,8 +103,8 @@ bool GpgFrontend::CharsetOperator::Convert2Utf8(const std::string &buffer, conv = ucnv_open(to_encode.c_str(), &status); ucnv_close(conv); if (U_FAILURE(status)) { - LOG(ERROR) << "Failed to open converter: " << u_errorName(status) << ":" - << to_encode; + SPDLOG_ERROR("failed to open converter: {}, to encode: {}", + u_errorName(status), to_encode); return false; } @@ -127,10 +126,10 @@ bool GpgFrontend::CharsetOperator::Convert2Utf8(const std::string &buffer, } if (U_FAILURE(status)) { - LOG(ERROR) << "Failed to convert to utf-8: " << u_errorName(status); + SPDLOG_ERROR("failed to convert to utf-8: {}", u_errorName(status)); return false; } - LOG(INFO) << "Converted buffer:" << out_buffer.size() << "bytes"; + SPDLOG_DEBUG("converted buffer: {} bytes", out_buffer.size()); return true; }
\ No newline at end of file diff --git a/src/core/function/CoreSignalStation.cpp b/src/core/function/CoreSignalStation.cpp new file mode 100644 index 00000000..f78d417b --- /dev/null +++ b/src/core/function/CoreSignalStation.cpp @@ -0,0 +1,39 @@ +/** + * Copyright (C) 2021 Saturneric + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "core/function/CoreSignalStation.h" + +std::unique_ptr<GpgFrontend::CoreSignalStation> + GpgFrontend::CoreSignalStation::_instance = nullptr; + +GpgFrontend::CoreSignalStation* GpgFrontend::CoreSignalStation::GetInstance() { + if (_instance == nullptr) { + _instance = std::make_unique<CoreSignalStation>(); + } + return _instance.get(); +} diff --git a/src/core/function/CoreSignalStation.h b/src/core/function/CoreSignalStation.h new file mode 100644 index 00000000..7497cab7 --- /dev/null +++ b/src/core/function/CoreSignalStation.h @@ -0,0 +1,69 @@ +/** + * 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_CORESIGNALSTATION_H +#define GPGFRONTEND_CORESIGNALSTATION_H + +#include "core/GpgFrontendCore.h" + +namespace GpgFrontend { + +/** + * @brief + * + */ +class GPGFRONTEND_CORE_EXPORT CoreSignalStation : public QObject { + Q_OBJECT + static std::unique_ptr<CoreSignalStation> _instance; + + public: + /** + * @brief Get the Instance object + * + * @return SignalStation* + */ + static CoreSignalStation* GetInstance(); + + signals: + + /** + * @brief + * + */ + void SignalUserInputPassphraseDone(QString passparase); + + /** + * @brief + * + */ + void SignalNeedUserInputPassphrase(); +}; + +} // namespace GpgFrontend + +#endif // GPGFRONTEND_CORESIGNALSTATION_H diff --git a/src/core/function/DataObjectOperator.cpp b/src/core/function/DataObjectOperator.cpp index 2744c448..180cef30 100644 --- a/src/core/function/DataObjectOperator.cpp +++ b/src/core/function/DataObjectOperator.cpp @@ -36,7 +36,7 @@ #include "core/function/PassphraseGenerator.h" void GpgFrontend::DataObjectOperator::init_app_secure_key() { - LOG(INFO) << "Initializing application secure key"; + SPDLOG_DEBUG("initializing application secure key"); FileOperator::WriteFileStd(app_secure_key_path_, PassphraseGenerator::GetInstance().Generate(256)); std::filesystem::permissions( @@ -54,13 +54,13 @@ GpgFrontend::DataObjectOperator::DataObjectOperator(int channel) std::string key; if (!FileOperator::ReadFileStd(app_secure_key_path_.u8string(), key)) { - LOG(FATAL) << _("Failed to read app secure key file") - << app_secure_key_path_; - throw std::runtime_error(_("Failed to read app secure key file")); + SPDLOG_ERROR("failed to read app secure key file: {}", + app_secure_key_path_.u8string()); + throw std::runtime_error("failed to read app secure key file"); } hash_key_ = QCryptographicHash::hash(QByteArray::fromStdString(key), QCryptographicHash::Sha256); - LOG(INFO) << "App secure key loaded" << hash_key_.size() << "bytes"; + SPDLOG_DEBUG("app secure key loaded {} bytes", hash_key_.size()); if (!exists(app_data_objs_path_)) create_directory(app_data_objs_path_); } @@ -93,8 +93,8 @@ std::string GpgFrontend::DataObjectOperator::SaveDataObj( auto encoded = encryption.encode(QByteArray::fromStdString(to_string(value)), hash_key_); - LOG(INFO) << _("Saving data object") << _hash_obj_key << "to" << obj_path - << encoded.size() << "bytes"; + SPDLOG_DEBUG("saving data object {} to {} , size: {} bytes", _hash_obj_key, + obj_path.u8string(), encoded.size()); FileOperator::WriteFileStd(obj_path.u8string(), encoded.toStdString()); @@ -104,7 +104,7 @@ std::string GpgFrontend::DataObjectOperator::SaveDataObj( std::optional<nlohmann::json> GpgFrontend::DataObjectOperator::GetDataObject( const std::string& _key) { try { - LOG(INFO) << _("Get data object") << _key; + SPDLOG_DEBUG("get data object {}", _key); auto _hash_obj_key = QCryptographicHash::hash(hash_key_ + QByteArray::fromStdString(_key), QCryptographicHash::Sha256) @@ -114,33 +114,33 @@ std::optional<nlohmann::json> GpgFrontend::DataObjectOperator::GetDataObject( const auto obj_path = app_data_objs_path_ / _hash_obj_key; if (!std::filesystem::exists(obj_path)) { - LOG(ERROR) << _("Data object not found") << _key; + SPDLOG_ERROR("data object not found :{}", _key); return {}; } std::string buffer; if (!FileOperator::ReadFileStd(obj_path.u8string(), buffer)) { - LOG(ERROR) << _("Failed to read data object") << _key; + SPDLOG_ERROR("failed to read data object: {}", _key); return {}; } - LOG(INFO) << _("Data object found") << _key; + SPDLOG_DEBUG("data object found {}", _key); auto encoded = QByteArray::fromStdString(buffer); QAESEncryption encryption(QAESEncryption::AES_256, QAESEncryption::ECB, QAESEncryption::Padding::ISO); - LOG(INFO) << _("Decrypting data object") << encoded.size() - << hash_key_.size(); + SPDLOG_DEBUG("decrypting data object {} , hash key size: {}", + encoded.size(), hash_key_.size()); auto decoded = encryption.removePadding(encryption.decode(encoded, hash_key_)); - LOG(INFO) << _("Data object decoded") << _key; + SPDLOG_DEBUG("data object decoded: {}", _key); return nlohmann::json::parse(decoded.toStdString()); } catch (...) { - LOG(ERROR) << _("Failed to get data object") << _key; + SPDLOG_ERROR("failed to get data object: {}", _key); return {}; } } diff --git a/src/core/function/FileOperator.cpp b/src/core/function/FileOperator.cpp index fcbdb91c..41552246 100644 --- a/src/core/function/FileOperator.cpp +++ b/src/core/function/FileOperator.cpp @@ -32,7 +32,7 @@ bool GpgFrontend::FileOperator::ReadFile(const QString& file_name, QByteArray& data) { QFile file(file_name); if (!file.open(QIODevice::ReadOnly)) { - LOG(ERROR) << "failed to open file" << file_name.toStdString(); + SPDLOG_ERROR("failed to open file: {}", file_name.toStdString()); return false; } data = file.readAll(); @@ -44,7 +44,7 @@ bool GpgFrontend::FileOperator::WriteFile(const QString& file_name, const QByteArray& data) { QFile file(file_name); if (!file.open(QIODevice::WriteOnly)) { - LOG(ERROR) << "failed to open file" << file_name.toStdString(); + SPDLOG_ERROR("failed to open file: {}", file_name.toStdString()); return false; } file.write(data); @@ -84,33 +84,33 @@ std::string GpgFrontend::FileOperator::CalculateHash( << file_path.filename().u8string().c_str() << std::endl; QFile f(info.filePath()); - f.open(QFile::ReadOnly); - auto buffer = f.readAll(); - ss << " " << _("file size(bytes)") << _(": ") << buffer.size() - << std::endl; - f.close(); if (f.open(QFile::ReadOnly)) { - auto hash_md5 = QCryptographicHash(QCryptographicHash::Md5); + // read all data + auto buffer = f.readAll(); + ss << " " << _("file size(bytes)") << _(": ") << buffer.size() + << std::endl; + // md5 + auto hash_md5 = QCryptographicHash(QCryptographicHash::Md5); hash_md5.addData(buffer); auto md5 = hash_md5.result().toHex().toStdString(); - LOG(INFO) << "md5" << md5; + SPDLOG_DEBUG("md5 {}", md5); ss << " " << "md5" << _(": ") << md5 << std::endl; - auto hash_sha1 = QCryptographicHash(QCryptographicHash::Sha1); // sha1 + auto hash_sha1 = QCryptographicHash(QCryptographicHash::Sha1); hash_sha1.addData(buffer); auto sha1 = hash_sha1.result().toHex().toStdString(); - LOG(INFO) << "sha1" << sha1; + SPDLOG_DEBUG("sha1 {}", sha1); ss << " " << "sha1" << _(": ") << sha1 << std::endl; - auto hash_sha256 = QCryptographicHash(QCryptographicHash::Sha256); // sha1 + auto hash_sha256 = QCryptographicHash(QCryptographicHash::Sha256); hash_sha256.addData(buffer); auto sha256 = hash_sha256.result().toHex().toStdString(); - LOG(INFO) << "sha256" << sha256; + SPDLOG_DEBUG("sha256 {}", sha256); ss << " " << "sha256" << _(": ") << sha256 << std::endl; diff --git a/src/core/function/GlobalSettingStation.cpp b/src/core/function/GlobalSettingStation.cpp index 7231ac9e..79c47408 100644 --- a/src/core/function/GlobalSettingStation.cpp +++ b/src/core/function/GlobalSettingStation.cpp @@ -34,12 +34,12 @@ void GpgFrontend::GlobalSettingStation::SyncSettings() noexcept { using namespace libconfig; try { ui_cfg_.writeFile(ui_config_path_.u8string().c_str()); - LOG(INFO) << _("Updated ui configuration successfully written to") - << ui_config_path_; + SPDLOG_DEBUG("updated ui configuration successfully written to {}", + ui_config_path_.u8string()); } catch (const FileIOException &fioex) { - LOG(ERROR) << _("I/O error while writing ui configuration file") - << ui_config_path_; + SPDLOG_ERROR("i/o error while writing ui configuration file: {}", + ui_config_path_.u8string()); } } @@ -48,14 +48,12 @@ GpgFrontend::GlobalSettingStation::GlobalSettingStation(int channel) noexcept using namespace std::filesystem; using namespace libconfig; - el::Loggers::addFlag(el::LoggingFlag::AutoSpacing); - - LOG(INFO) << _("App Path") << app_path_; - LOG(INFO) << _("App Configure Path") << app_configure_path_; - LOG(INFO) << _("App Data Path") << app_data_path_; - LOG(INFO) << _("App Log Path") << app_log_path_; - LOG(INFO) << _("App Locale Path") << app_locale_path_; - LOG(INFO) << _("App Conf Path") << ui_config_path_; + SPDLOG_INFO("app path: {}", app_path_.u8string()); + SPDLOG_INFO("app configure path: {}", app_configure_path_.u8string()); + SPDLOG_INFO("app data path: {}", app_data_path_.u8string()); + SPDLOG_INFO("app log path: {}", app_log_path_.u8string()); + SPDLOG_INFO("app locale path: {}", app_locale_path_.u8string()); + SPDLOG_INFO("app conf path: {}", ui_config_path_.u8string()); if (!is_directory(app_configure_path_)) create_directory(app_configure_path_); @@ -68,24 +66,24 @@ GpgFrontend::GlobalSettingStation::GlobalSettingStation(int channel) noexcept if (!exists(ui_config_path_)) { try { this->ui_cfg_.writeFile(ui_config_path_.u8string().c_str()); - LOG(INFO) << _("UserInterface configuration successfully written to") - << ui_config_path_; + SPDLOG_DEBUG("user interface configuration successfully written to {}", + ui_config_path_.u8string()); } catch (const FileIOException &fioex) { - LOG(ERROR) - << _("I/O error while writing UserInterface configuration file") - << ui_config_path_; + SPDLOG_DEBUG( + "i/o error while writing UserInterface configuration file {}", + ui_config_path_.u8string()); } } else { try { this->ui_cfg_.readFile(ui_config_path_.u8string().c_str()); - LOG(INFO) << _("UserInterface configuration successfully read from") - << ui_config_path_; + SPDLOG_DEBUG("user interface configuration successfully read from {}", + ui_config_path_.u8string()); } catch (const FileIOException &fioex) { - LOG(ERROR) << _("I/O error while reading UserInterface configure file"); + SPDLOG_ERROR("i/o error while reading UserInterface configure file"); } catch (const ParseException &pex) { - LOG(ERROR) << _("Parse error at ") << pex.getFile() << ":" - << pex.getLine() << " - " << pex.getError(); + SPDLOG_ERROR("parse error at {} : {} - {}", pex.getFile(), pex.getLine(), + pex.getError()); } } } diff --git a/src/core/function/KeyPackageOperator.cpp b/src/core/function/KeyPackageOperator.cpp index 3779c64b..5c917ab8 100644 --- a/src/core/function/KeyPackageOperator.cpp +++ b/src/core/function/KeyPackageOperator.cpp @@ -39,7 +39,7 @@ namespace GpgFrontend { bool KeyPackageOperator::GeneratePassphrase( const std::filesystem::path& phrase_path, std::string& phrase) { phrase = PassphraseGenerator::GetInstance().Generate(256); - LOG(INFO) << "Generated passphrase: " << phrase.size() << " bytes"; + SPDLOG_DEBUG("generated passphrase: {} bytes", phrase.size()); return FileOperator::WriteFileStd(phrase_path, phrase); } @@ -47,12 +47,12 @@ bool KeyPackageOperator::GenerateKeyPackage( const std::filesystem::path& key_package_path, const std::string& key_package_name, KeyIdArgsListPtr& key_ids, std::string& phrase, bool secret) { - LOG(INFO) << "Generating key package: " << key_package_name; + SPDLOG_DEBUG("generating key package: {}", key_package_name); ByteArrayPtr key_export_data = nullptr; - if (!GpgKeyImportExporter::GetInstance().ExportKeys(key_ids, key_export_data, - secret)) { - LOG(ERROR) << "Failed to export keys"; + if (!GpgKeyImportExporter::GetInstance().ExportAllKeys( + key_ids, key_export_data, secret)) { + SPDLOG_ERROR("failed to export keys"); return false; } @@ -64,7 +64,7 @@ bool KeyPackageOperator::GenerateKeyPackage( QAESEncryption::Padding::ISO); auto encoded = encryption.encode(data, hash_key); - LOG(INFO) << "Writing key package: " << key_package_name; + SPDLOG_DEBUG("writing key package: {}", key_package_name); return FileOperator::WriteFileStd(key_package_path, encoded.toStdString()); } @@ -72,21 +72,21 @@ bool KeyPackageOperator::ImportKeyPackage( const std::filesystem::path& key_package_path, const std::filesystem::path& phrase_path, GpgFrontend::GpgImportInformation& import_info) { - LOG(INFO) << "Importing key package: " << key_package_path.u8string(); + SPDLOG_DEBUG("importing key package: {]", key_package_path.u8string()); std::string encrypted_data; FileOperator::ReadFileStd(key_package_path, encrypted_data); if (encrypted_data.empty()) { - LOG(ERROR) << "Failed to read key package: " << key_package_path.u8string(); + SPDLOG_ERROR("failed to read key package: {}", key_package_path.u8string()); return false; }; std::string passphrase; FileOperator::ReadFileStd(phrase_path, passphrase); - LOG(INFO) << "Passphrase: " << passphrase.size() << " bytes"; + SPDLOG_DEBUG("passphrase: {} bytes", passphrase.size()); if (passphrase.size() != 256) { - LOG(ERROR) << "Failed to read passphrase: " << phrase_path.u8string(); + SPDLOG_ERROR("failed to read passphrase: {}", phrase_path.u8string()); return false; } @@ -100,7 +100,7 @@ bool KeyPackageOperator::ImportKeyPackage( auto decoded = encryption.removePadding(encryption.decode(encoded, hash_key)); auto key_data = QByteArray::fromBase64(decoded); - LOG(INFO) << "key data" << key_data.size(); + SPDLOG_DEBUG("key data size: {}", key_data.size()); if (!key_data.startsWith(GpgConstants::PGP_PUBLIC_KEY_BEGIN) && !key_data.startsWith(GpgConstants::PGP_PRIVATE_KEY_BEGIN)) { return false; diff --git a/src/core/function/gpg/GpgAdvancedOperator.cpp b/src/core/function/gpg/GpgAdvancedOperator.cpp new file mode 100644 index 00000000..2a3bba42 --- /dev/null +++ b/src/core/function/gpg/GpgAdvancedOperator.cpp @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2023. Saturneric + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +// +// Created by eric on 07.01.2023. +// + +#include "GpgAdvancedOperator.h" + +#include "core/function/gpg/GpgCommandExecutor.h" +#include "spdlog/spdlog.h" + +GpgFrontend::GpgAdvancedOperator::GpgAdvancedOperator(int channel) + : SingletonFunctionObject(channel) {} + +bool GpgFrontend::GpgAdvancedOperator::ClearGpgPasswordCache() { + bool success = false; + GpgFrontend::GpgCommandExecutor::GetInstance().Execute( + ctx_.GetInfo().GpgConfPath, {"--reload", "gpg-agent"}, + [&](int exit_code, const std::string &p_out, const std::string &p_err) { + if (exit_code == 0) { + SPDLOG_DEBUG("gpgconf reload exit code: {}", exit_code); + success = true; + } + }); + return success; +} + +bool GpgFrontend::GpgAdvancedOperator::ReloadGpgComponents() { + bool success = false; + GpgFrontend::GpgCommandExecutor::GetInstance().Execute( + ctx_.GetInfo().GpgConfPath, {"--reload"}, + [&](int exit_code, const std::string &p_out, const std::string &p_err) { + if (exit_code == 0) { + success = true; + } else { + SPDLOG_ERROR( + "gpgconf execute error, process stderr: {}, process stdout: {}", + p_err, p_out); + return; + } + }); + return success; +} + +bool GpgFrontend::GpgAdvancedOperator::RestartGpgComponents() { + bool success = false; + + GpgFrontend::GpgCommandExecutor::GetInstance().Execute( + ctx_.GetInfo().GpgConfPath, {"--verbose", "--kill", "all"}, + [&](int exit_code, const std::string &p_out, const std::string &p_err) { + if (exit_code == 0) { + success = true; + return; + } else { + SPDLOG_ERROR( + "gpgconf execute error, process stderr: {}, process stdout: {}", + p_err, p_out); + return; + } + }); + + if (!success) return false; + + success &= StartGpgAgent(); + + success &= StartDirmngr(); + + success &= StartKeyBoxd(); + + return success; +} + +bool GpgFrontend::GpgAdvancedOperator::ResetConfigures() { + bool success = false; + GpgFrontend::GpgCommandExecutor::GetInstance().Execute( + ctx_.GetInfo().GpgConfPath, {"--apply-defaults"}, + [&](int exit_code, const std::string &p_out, const std::string &p_err) { + if (exit_code == 0) { + success = true; + } else { + SPDLOG_ERROR( + "gpgconf execute error, process stderr: {}, process stdout: {}", + p_err, p_out); + return; + } + }); + + return success; +} + +bool GpgFrontend::GpgAdvancedOperator::StartGpgAgent() { + bool success = false; + GpgFrontend::GpgCommandExecutor::GetInstance().Execute( + ctx_.GetInfo().GpgAgentPath, + {"--homedir", ctx_.GetInfo().GnuPGHomePath, "--daemon"}, + [&](int exit_code, const std::string &p_out, const std::string &p_err) { + if (exit_code == 0) { + success = true; + SPDLOG_INFO("start gpg-agent successfully"); + } else if (exit_code == 2) { + success = true; + SPDLOG_INFO("gpg-agent already started"); + } else { + SPDLOG_ERROR( + "gpg-agent execute error, process stderr: {}, process stdout: {}", + p_err, p_out); + return; + } + }); + + return success; +} + +bool GpgFrontend::GpgAdvancedOperator::StartDirmngr() { + bool success = false; + GpgFrontend::GpgCommandExecutor::GetInstance().Execute( + ctx_.GetInfo().DirmngrPath, + {"--homedir", ctx_.GetInfo().GnuPGHomePath, "--daemon"}, + [&](int exit_code, const std::string &p_out, const std::string &p_err) { + if (exit_code == 0) { + success = true; + SPDLOG_INFO("start dirmngr successfully"); + } else if (exit_code == 2) { + success = true; + SPDLOG_INFO("dirmngr already started"); + } else { + SPDLOG_ERROR( + "dirmngr execute error, process stderr: {}, process stdout: {}", + p_err, p_out); + return; + } + }); + + return success; +} + +bool GpgFrontend::GpgAdvancedOperator::StartKeyBoxd() { + bool success = false; + GpgFrontend::GpgCommandExecutor::GetInstance().Execute( + ctx_.GetInfo().KeyboxdPath, + {"--homedir", ctx_.GetInfo().GnuPGHomePath, "--daemon"}, + [&](int exit_code, const std::string &p_out, const std::string &p_err) { + if (exit_code == 0) { + success = true; + SPDLOG_INFO("start keyboxd successfully"); + } else if (exit_code == 2) { + success = true; + SPDLOG_INFO("keyboxd already started"); + } else { + SPDLOG_ERROR( + "keyboxd execute error, process stderr: {}, process stdout: {}", + p_err, p_out); + return; + } + }); + + return success; +} diff --git a/src/core/function/gpg/GpgAdvancedOperator.h b/src/core/function/gpg/GpgAdvancedOperator.h new file mode 100644 index 00000000..5325020a --- /dev/null +++ b/src/core/function/gpg/GpgAdvancedOperator.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2023. Saturneric + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric<[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +// +// Created by eric on 07.01.2023. +// + +#ifndef GPGFRONTEND_GPGADVANCEDOPERATOR_H +#define GPGFRONTEND_GPGADVANCEDOPERATOR_H + +#include "core/GpgConstants.h" +#include "core/GpgContext.h" +#include "core/GpgFunctionObject.h" + +namespace GpgFrontend { + +class GPGFRONTEND_CORE_EXPORT GpgAdvancedOperator + : public SingletonFunctionObject<GpgAdvancedOperator> { + public: + /** + * @brief Construct a new Basic Operator object + * + * @param channel Channel corresponding to the context + */ + explicit GpgAdvancedOperator( + int channel = SingletonFunctionObject::GetDefaultChannel()); + + /** + * @brief + * + * @return true + * @return false + */ + bool ClearGpgPasswordCache(); + + /** + * @brief + * + * @return true + * @return false + */ + bool ReloadGpgComponents(); + + /** + * @brief + * + * @return true + * @return false + */ + bool RestartGpgComponents(); + + /** + * @brief + * + * @return true + * @return false + */ + bool ResetConfigures(); + + /** + * @brief + * + * @return true + * @return false + */ + bool StartGpgAgent(); + + /** + * @brief + * + * @return true + * @return false + */ + bool StartDirmngr(); + + /** + * @brief + * + * @return true + * @return false + */ + bool StartKeyBoxd(); + + private: + GpgContext& ctx_ = GpgContext::GetInstance( + SingletonFunctionObject::GetChannel()); ///< Corresponding context +}; + +} // namespace GpgFrontend + +#endif // GPGFRONTEND_GPGADVANCEDOPERATOR_H diff --git a/src/core/function/gpg/GpgBasicOperator.cpp b/src/core/function/gpg/GpgBasicOperator.cpp index 93075c7c..71f84907 100644 --- a/src/core/function/gpg/GpgBasicOperator.cpp +++ b/src/core/function/gpg/GpgBasicOperator.cpp @@ -178,15 +178,15 @@ gpgme_error_t GpgFrontend::GpgBasicOperator::EncryptSign( void GpgFrontend::GpgBasicOperator::SetSigners(KeyArgsList& signers) { gpgme_signers_clear(ctx_); for (const GpgKey& key : signers) { - DLOG(INFO) << "key" << key.GetFingerprint(); + SPDLOG_DEBUG("key fpr: {}", key.GetFingerprint()); if (key.IsHasActualSigningCapability()) { - DLOG(INFO) << "signer"; + SPDLOG_DEBUG("signer"); auto error = gpgme_signers_add(ctx_, gpgme_key_t(key)); check_gpg_error(error); } } if (signers.size() != gpgme_signers_count(ctx_)) - DLOG(INFO) << "No All Signers Added"; + SPDLOG_DEBUG("not all signers added"); } std::unique_ptr<GpgFrontend::KeyArgsList> diff --git a/src/core/function/gpg/GpgCommandExecutor.cpp b/src/core/function/gpg/GpgCommandExecutor.cpp index 2292ed0e..86c47c60 100644 --- a/src/core/function/gpg/GpgCommandExecutor.cpp +++ b/src/core/function/gpg/GpgCommandExecutor.cpp @@ -27,41 +27,245 @@ */ #include "GpgCommandExecutor.h" +#include "GpgFunctionObject.h" +#include "core/thread/TaskRunnerGetter.h" + GpgFrontend::GpgCommandExecutor::GpgCommandExecutor(int channel) : SingletonFunctionObject<GpgCommandExecutor>(channel) {} -#ifndef WINDOWS -#include <boost/asio.hpp> -#endif +void GpgFrontend::GpgCommandExecutor::Execute( + std::string cmd, std::vector<std::string> arguments, + std::function<void(int, std::string, std::string)> callback, + std::function<void(QProcess *)> interact_func) { + SPDLOG_DEBUG("called cmd {} arguments size: {}", cmd, arguments.size()); -#ifndef WINDOWS + Thread::Task::TaskCallback result_callback = + [](int rtn, Thread::Task::DataObjectPtr data_object) { + SPDLOG_DEBUG("data object use count: {}", data_object.use_count()); + if (data_object->GetObjectSize() != 4) + throw std::runtime_error("invalid data object size"); -using boost::process::async_pipe; + auto exit_code = data_object->PopObject<int>(); + auto process_stdout = data_object->PopObject<std::string>(); + auto process_stderr = data_object->PopObject<std::string>(); + auto callback = data_object->PopObject< + std::function<void(int, std::string, std::string)>>(); -void GpgFrontend::GpgCommandExecutor::Execute( - StringArgsRef arguments, - const std::function<void(async_pipe& in, async_pipe& out)>& interact_func) { - using namespace boost::process; + // call callback + callback(exit_code, process_stdout, process_stderr); + }; + + Thread::Task::TaskRunnable runner = + [](GpgFrontend::Thread::Task::DataObjectPtr data_object) -> int { + SPDLOG_DEBUG("process runner called, data object size: {}", + data_object->GetObjectSize()); + + if (data_object->GetObjectSize() != 4) + throw std::runtime_error("invalid data object size"); + + // get arguments + auto cmd = data_object->PopObject<std::string>(); + SPDLOG_DEBUG("get cmd: {}", cmd); + auto arguments = data_object->PopObject<std::vector<std::string>>(); + auto interact_func = + data_object->PopObject<std::function<void(QProcess *)>>(); + + auto *cmd_process = new QProcess(); + cmd_process->setProcessChannelMode(QProcess::MergedChannels); + + QObject::connect(cmd_process, &QProcess::started, + []() -> void { SPDLOG_DEBUG("process started"); }); + QObject::connect( + cmd_process, &QProcess::readyReadStandardOutput, + [interact_func, cmd_process]() { interact_func(cmd_process); }); + QObject::connect(cmd_process, &QProcess::errorOccurred, + [=](QProcess::ProcessError error) { + SPDLOG_ERROR("error in executing command: {} error: {}", + cmd, error); + }); + QObject::connect( + cmd_process, qOverload<int, QProcess::ExitStatus>(&QProcess::finished), + [=](int, QProcess::ExitStatus status) { + if (status == QProcess::NormalExit) + SPDLOG_DEBUG( + "proceess finished, succeed in executing command: {}, exit " + "status: {}", + cmd, status); + else + SPDLOG_ERROR( + "proceess finished, error in executing command: {}, exit " + "status: {}", + cmd, status); + }); + + cmd_process->setProgram(QString::fromStdString(cmd)); - boost::asio::io_service ios; + QStringList q_arguments; + for (const auto &argument : arguments) + q_arguments.append(QString::fromStdString(argument)); + cmd_process->setArguments(q_arguments); - std::vector<char> buf; + SPDLOG_DEBUG("process execute ready, cmd: {} {}", cmd, + q_arguments.join(" ").toStdString()); - async_pipe in_pipe_stream(ios); - async_pipe out_pipe_stream(ios); + cmd_process->start(); + cmd_process->waitForFinished(); - child child_process(ctx_.GetInfo().AppPath.c_str(), arguments, - std_out > in_pipe_stream, std_in < out_pipe_stream); + std::string process_stdout = + cmd_process->readAllStandardOutput().toStdString(), + process_stderr = + cmd_process->readAllStandardError().toStdString(); + int exit_code = cmd_process->exitCode(); - boost::asio::async_read( - in_pipe_stream, boost::asio::buffer(buf), - [&](const boost::system::error_code& ec, std::size_t size) { - interact_func(in_pipe_stream, out_pipe_stream); - }); + cmd_process->close(); + cmd_process->deleteLater(); - ios.run(); - child_process.wait(); - child_process.exit_code(); + // transfer result + SPDLOG_DEBUG("runner append object"); + data_object->AppendObject(std::move(process_stderr)); + data_object->AppendObject(std::move(process_stdout)); + data_object->AppendObject(std::move(exit_code)); + SPDLOG_DEBUG("runner append object done"); + + return 0; + }; + + // data transfer into task + auto data_object = std::make_shared<Thread::Task::DataObject>(); + SPDLOG_DEBUG("executor append object"); + data_object->AppendObject(std::move(callback)); + data_object->AppendObject(std::move(interact_func)); + data_object->AppendObject(std::move(arguments)); + data_object->AppendObject(std::move(std::string{cmd})); + SPDLOG_DEBUG("executor append object done"); + + auto *process_task = new GpgFrontend::Thread::Task( + std::move(runner), fmt::format("Execute/{}", cmd), data_object, + std::move(result_callback)); + + QEventLoop looper; + QObject::connect(process_task, &Thread::Task::SignalTaskEnd, &looper, + &QEventLoop::quit); + + GpgFrontend::Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_External_Process) + ->PostTask(process_task); + + // block until task finished + // this is to keep reference vaild until task finished + looper.exec(); } -#endif +void GpgFrontend::GpgCommandExecutor::ExecuteConcurrently( + std::string cmd, std::vector<std::string> arguments, + std::function<void(int, std::string, std::string)> callback, + std::function<void(QProcess *)> interact_func) { + SPDLOG_DEBUG("called cmd {} arguments size: {}", cmd, arguments.size()); + + Thread::Task::TaskCallback result_callback = + [](int rtn, Thread::Task::DataObjectPtr data_object) { + if (data_object->GetObjectSize() != 4) + throw std::runtime_error("invalid data object size"); + + auto exit_code = data_object->PopObject<int>(); + auto process_stdout = data_object->PopObject<std::string>(); + auto process_stderr = data_object->PopObject<std::string>(); + auto callback = data_object->PopObject< + std::function<void(int, std::string, std::string)>>(); + + // call callback + callback(exit_code, process_stdout, process_stderr); + }; + + Thread::Task::TaskRunnable runner = + [](GpgFrontend::Thread::Task::DataObjectPtr data_object) -> int { + SPDLOG_DEBUG("process runner called, data object size: {}", + data_object->GetObjectSize()); + + if (data_object->GetObjectSize() != 4) + throw std::runtime_error("invalid data object size"); + + SPDLOG_DEBUG("runner pop object"); + // get arguments + auto cmd = data_object->PopObject<std::string>(); + auto arguments = data_object->PopObject<std::vector<std::string>>(); + auto interact_func = + data_object->PopObject<std::function<void(QProcess *)>>(); + SPDLOG_DEBUG("runner pop object done"); + + auto *cmd_process = new QProcess(); + cmd_process->setProcessChannelMode(QProcess::MergedChannels); + + QObject::connect(cmd_process, &QProcess::started, + []() -> void { SPDLOG_DEBUG("process started"); }); + QObject::connect( + cmd_process, &QProcess::readyReadStandardOutput, + [interact_func, cmd_process]() { interact_func(cmd_process); }); + QObject::connect(cmd_process, &QProcess::errorOccurred, + [=](QProcess::ProcessError error) { + SPDLOG_ERROR("error in executing command: {} error: {}", + cmd, error); + }); + QObject::connect( + cmd_process, qOverload<int, QProcess::ExitStatus>(&QProcess::finished), + [=](int, QProcess::ExitStatus status) { + if (status == QProcess::NormalExit) + SPDLOG_DEBUG( + "proceess finished, succeed in executing command: {}, exit " + "status: {}", + cmd, status); + else + SPDLOG_ERROR( + "proceess finished, error in executing command: {}, exit " + "status: {}", + cmd, status); + }); + + cmd_process->setProgram(QString::fromStdString(cmd)); + cmd_process->setProcessChannelMode(QProcess::SeparateChannels); + + QStringList q_arguments; + for (const auto &argument : arguments) + q_arguments.append(QString::fromStdString(argument)); + cmd_process->setArguments(q_arguments); + + SPDLOG_DEBUG("process start ready, cmd: {} {}", cmd, + q_arguments.join(" ").toStdString()); + + cmd_process->start(); + cmd_process->waitForFinished(); + + std::string process_stdout = + cmd_process->readAllStandardOutput().toStdString(), + process_stderr = + cmd_process->readAllStandardError().toStdString(); + int exit_code = cmd_process->exitCode(); + + cmd_process->close(); + cmd_process->deleteLater(); + + // transfer result + SPDLOG_DEBUG("runner append object"); + data_object->AppendObject(std::move(process_stderr)); + data_object->AppendObject(std::move(process_stdout)); + data_object->AppendObject(std::move(exit_code)); + SPDLOG_DEBUG("runner append object done"); + + return 0; + }; + + // data transfer into task + auto data_object = std::make_shared<Thread::Task::DataObject>(); + data_object->AppendObject(std::move(callback)); + data_object->AppendObject(std::move(interact_func)); + data_object->AppendObject(std::move(arguments)); + data_object->AppendObject(std::move(std::string{cmd})); + + auto *process_task = new GpgFrontend::Thread::Task( + std::move(runner), fmt::format("ExecuteConcurrently/{}", cmd), + data_object, std::move(result_callback), false); + + GpgFrontend::Thread::TaskRunnerGetter::GetInstance() + .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_External_Process) + ->PostTask(process_task); +} diff --git a/src/core/function/gpg/GpgCommandExecutor.h b/src/core/function/gpg/GpgCommandExecutor.h index 40ee22df..da0e7a8b 100644 --- a/src/core/function/gpg/GpgCommandExecutor.h +++ b/src/core/function/gpg/GpgCommandExecutor.h @@ -35,6 +35,7 @@ #include "core/GpgContext.h" #include "core/GpgFunctionObject.h" +#include "core/thread/Task.h" namespace GpgFrontend { @@ -53,19 +54,22 @@ class GPGFRONTEND_CORE_EXPORT GpgCommandExecutor explicit GpgCommandExecutor( int channel = SingletonFunctionObject::GetDefaultChannel()); -#ifndef WINDOWS - /** - * @brief Excuting an order + * @brief Excuting a command * * @param arguments Command parameters * @param interact_func Command answering function */ - void Execute(StringArgsRef arguments, - const std::function<void(boost::process::async_pipe &in, - boost::process::async_pipe &out)> - &interact_func); -#endif + void Execute( + std::string cmd, std::vector<std::string> arguments, + std::function<void(int, std::string, std::string)> callback = + [](int, std::string, std::string) {}, + std::function<void(QProcess *)> interact_func = [](QProcess *) {}); + + void ExecuteConcurrently( + std::string cmd, std::vector<std::string> arguments, + std::function<void(int, std::string, std::string)> callback, + std::function<void(QProcess *)> interact_func = [](QProcess *) {}); private: GpgContext &ctx_ = GpgContext::GetInstance( diff --git a/src/core/function/gpg/GpgKeyGetter.cpp b/src/core/function/gpg/GpgKeyGetter.cpp index 571e8797..a8e685e0 100644 --- a/src/core/function/gpg/GpgKeyGetter.cpp +++ b/src/core/function/gpg/GpgKeyGetter.cpp @@ -35,19 +35,15 @@ #include <utility> #include "GpgConstants.h" -#include "easylogging++.h" #include "model/GpgKey.h" GpgFrontend::GpgKeyGetter::GpgKeyGetter(int channel) : SingletonFunctionObject<GpgKeyGetter>(channel) { - LOG(INFO) << "called" - << "channel:" << channel; + SPDLOG_DEBUG("called channel: {}", channel); } GpgFrontend::GpgKey GpgFrontend::GpgKeyGetter::GetKey(const std::string& fpr, bool use_cache) { - LOG(INFO) << "called"; - // find in cache first if (use_cache) { auto key = get_key_in_cache(fpr); @@ -57,7 +53,7 @@ GpgFrontend::GpgKey GpgFrontend::GpgKeyGetter::GetKey(const std::string& fpr, gpgme_key_t _p_key = nullptr; gpgme_get_key(ctx_, fpr.c_str(), &_p_key, 1); if (_p_key == nullptr) { - DLOG(WARNING) << "GpgKeyGetter GetKey Private _p_key Null fpr" << fpr; + SPDLOG_WARN("GpgKeyGetter GetKey Private _p_key Null fpr", fpr); return GetPubkey(fpr); } else { return GpgKey(std::move(_p_key)); @@ -74,8 +70,7 @@ GpgFrontend::GpgKey GpgFrontend::GpgKeyGetter::GetPubkey(const std::string& fpr, gpgme_key_t _p_key = nullptr; gpgme_get_key(ctx_, fpr.c_str(), &_p_key, 0); - if (_p_key == nullptr) - DLOG(WARNING) << "GpgKeyGetter GetKey _p_key Null" << fpr; + if (_p_key == nullptr) SPDLOG_WARN("GpgKeyGetter GetKey _p_key Null", fpr); return GpgKey(std::move(_p_key)); } @@ -83,21 +78,19 @@ GpgFrontend::KeyLinkListPtr GpgFrontend::GpgKeyGetter::FetchKey() { // get the lock std::lock_guard<std::mutex> lock(keys_cache_mutex_); - LOG(INFO) << "GpgKeyGetter FetchKey" - << "channel id:" << GetChannel(); + SPDLOG_DEBUG("channel id: {}", GetChannel()); auto keys_list = std::make_unique<GpgKeyLinkList>(); for (const auto& [key, value] : keys_cache_) { - LOG(INFO) << "FetchKey Id:" << value.GetId(); + SPDLOG_DEBUG("fetch key id: {}", value.GetId()); keys_list->push_back(value.Copy()); } return keys_list; } void GpgFrontend::GpgKeyGetter::FlushKeyCache() { - LOG(INFO) << "called" - << "channel id: " << GetChannel(); + SPDLOG_DEBUG("called channel id: {}", GetChannel()); // clear the keys cache keys_cache_.clear(); @@ -125,13 +118,14 @@ void GpgFrontend::GpgKeyGetter::FlushKeyCache() { gpg_key = GetKey(gpg_key.GetId(), false); } - LOG(INFO) << "LoadKey Fpr:" << gpg_key.GetFingerprint() - << "Id:" << gpg_key.GetId(); + SPDLOG_DEBUG("load key fpr: {} id: {}", gpg_key.GetFingerprint(), + gpg_key.GetId()); keys_cache_.insert({gpg_key.GetId(), std::move(gpg_key)}); } } - LOG(INFO) << "cache address:" << &keys_cache_ << "object address" << this; + SPDLOG_DEBUG("cache address: {} object address: {}", + static_cast<void*>(&keys_cache_), static_cast<void*>(this)); // for debug assert(check_gpg_error_2_err_code(err, GPG_ERR_EOF) == GPG_ERR_EOF); diff --git a/src/core/function/gpg/GpgKeyImportExporter.cpp b/src/core/function/gpg/GpgKeyImportExporter.cpp index 206282ae..01349c94 100644 --- a/src/core/function/gpg/GpgKeyImportExporter.cpp +++ b/src/core/function/gpg/GpgKeyImportExporter.cpp @@ -28,6 +28,8 @@ #include "GpgKeyImportExporter.h" +#include <memory> + #include "GpgConstants.h" #include "GpgKeyGetter.h" @@ -91,8 +93,8 @@ bool GpgFrontend::GpgKeyImportExporter::ExportKeys(KeyIdArgsListPtr& uid_list, delete[] keys_array; - DLOG(INFO) << "exportKeys read_bytes" - << gpgme_data_seek(data_out, 0, SEEK_END); + SPDLOG_DEBUG("export keys read_bytes: {}", + gpgme_data_seek(data_out, 0, SEEK_END)); auto temp_out_buffer = data_out.Read2Buffer(); @@ -116,6 +118,25 @@ bool GpgFrontend::GpgKeyImportExporter::ExportKeys(const KeyArgsList& keys, } /** + * Export all the keys both private and public keys + * @param uid_list key ids + * @param out_buffer output byte array + * @return if success + */ +bool GpgFrontend::GpgKeyImportExporter::ExportAllKeys( + KeyIdArgsListPtr& uid_list, ByteArrayPtr& out_buffer, bool secret) const { + bool result = true; + result = ExportKeys(uid_list, out_buffer, false) & result; + + ByteArrayPtr temp_buffer; + if (secret) { + result = ExportKeys(uid_list, temp_buffer, true) & result; + } + out_buffer->append(*temp_buffer); + return result; +} + +/** * Export the secret key of a key pair(including subkeys) * @param key target key pair * @param outBuffer output byte array @@ -123,7 +144,7 @@ bool GpgFrontend::GpgKeyImportExporter::ExportKeys(const KeyArgsList& keys, */ bool GpgFrontend::GpgKeyImportExporter::ExportSecretKey( const GpgKey& key, ByteArrayPtr& out_buffer) const { - DLOG(INFO) << "Export Secret Key" << key.GetId().c_str(); + SPDLOG_DEBUG("export secret key: {}", key.GetId().c_str()); gpgme_key_t target_key[2] = {gpgme_key_t(key), nullptr}; @@ -144,8 +165,8 @@ bool GpgFrontend::GpgKeyImportExporter::ExportKey( GpgData data_out; auto err = gpgme_op_export(ctx_, key.GetId().c_str(), 0, data_out); - DLOG(INFO) << "exportKeys read_bytes" - << gpgme_data_seek(data_out, 0, SEEK_END); + SPDLOG_DEBUG("export keys read_bytes: {}", + gpgme_data_seek(data_out, 0, SEEK_END)); auto temp_out_buffer = data_out.Read2Buffer(); std::swap(out_buffer, temp_out_buffer); @@ -159,7 +180,7 @@ bool GpgFrontend::GpgKeyImportExporter::ExportKeyOpenSSH( auto err = gpgme_op_export(ctx_, key.GetId().c_str(), GPGME_EXPORT_MODE_SSH, data_out); - DLOG(INFO) << "read_bytes" << gpgme_data_seek(data_out, 0, SEEK_END); + SPDLOG_DEBUG("read_bytes: {}", gpgme_data_seek(data_out, 0, SEEK_END)); auto temp_out_buffer = data_out.Read2Buffer(); std::swap(out_buffer, temp_out_buffer); @@ -173,7 +194,7 @@ bool GpgFrontend::GpgKeyImportExporter::ExportSecretKeyShortest( auto err = gpgme_op_export(ctx_, key.GetId().c_str(), GPGME_EXPORT_MODE_MINIMAL, data_out); - DLOG(INFO) << "read_bytes" << gpgme_data_seek(data_out, 0, SEEK_END); + SPDLOG_DEBUG("read_bytes: {}", gpgme_data_seek(data_out, 0, SEEK_END)); auto temp_out_buffer = data_out.Read2Buffer(); std::swap(out_buffer, temp_out_buffer); diff --git a/src/core/function/gpg/GpgKeyImportExporter.h b/src/core/function/gpg/GpgKeyImportExporter.h index 7603c17d..6e90f436 100644 --- a/src/core/function/gpg/GpgKeyImportExporter.h +++ b/src/core/function/gpg/GpgKeyImportExporter.h @@ -132,6 +132,18 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyImportExporter /** * @brief * + * @param keys + * @param outBuffer + * @param secret + * @return true + * @return false + */ + bool ExportAllKeys(KeyIdArgsListPtr& uid_list, ByteArrayPtr& out_buffer, + bool secret) const; + + /** + * @brief + * * @param key * @param out_buffer * @return true diff --git a/src/core/function/gpg/GpgKeyOpera.cpp b/src/core/function/gpg/GpgKeyOpera.cpp index 0839c132..0d715ba7 100644 --- a/src/core/function/gpg/GpgKeyOpera.cpp +++ b/src/core/function/gpg/GpgKeyOpera.cpp @@ -59,7 +59,7 @@ void GpgFrontend::GpgKeyOpera::DeleteKeys( GPGME_DELETE_ALLOW_SECRET | GPGME_DELETE_FORCE)); assert(gpg_err_code(err) == GPG_ERR_NO_ERROR); } else { - LOG(WARNING) << "GpgKeyOpera DeleteKeys get key failed" << tmp; + SPDLOG_WARN("GpgKeyOpera DeleteKeys get key failed", tmp); } } } @@ -84,7 +84,7 @@ GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::SetExpire( to_time_t(*expires) - system_clock::to_time_t(system_clock::now()); } - LOG(INFO) << key.GetId() << subkey_fpr << expires_time; + SPDLOG_DEBUG(key.GetId(), subkey_fpr, expires_time); GpgError err; if (key.GetFingerprint() == subkey_fpr || subkey_fpr.empty()) @@ -103,59 +103,7 @@ GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::SetExpire( * @return the process doing this job */ void GpgFrontend::GpgKeyOpera::GenerateRevokeCert( - const GpgKey& key, const std::string& output_file_name) { - auto args = std::vector<std::string>{"--no-tty", - "--command-fd", - "0", - "--status-fd", - "1", - "-o", - output_file_name, - "--gen-revoke", - key.GetFingerprint()}; - - using boost::asio::async_write; - using boost::process::async_pipe; -#ifndef WINDOWS - GpgCommandExecutor::GetInstance().Execute( - args, [](async_pipe& in, async_pipe& out) -> void { - // boost::asio::streambuf buff; - // boost::asio::read_until(in, buff, '\n'); - // - // std::istream is(&buff); - // - // while (!is.eof()) { - // std::string line; - // is >> line; - // LOG(INFO) << "line" << line; - // boost::algorithm::trim(line); - // if (line == std::string("[GNUPG:] GET_BOOL - // gen_revoke.okay")) { - // - // } else if (line == - // std::string( - // "[GNUPG:] GET_LINE - // ask_revocation_reason.code")) { - // - // } else if (line == - // std::string( - // "[GNUPG:] GET_LINE - // ask_revocation_reason.text")) { - // - // } else if (line == - // std::string("[GNUPG:] GET_BOOL - // openfile.overwrite.okay")) { - // - // } else if (line == - // std::string( - // "[GNUPG:] GET_BOOL - // ask_revocation_reason.okay")) { - // - // } - // } - }); -#endif -} + const GpgKey& key, const std::string& output_file_name) {} /** * Generate a new key pair @@ -168,7 +116,7 @@ GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::GenerateKey( const char* userid = userid_utf8.c_str(); auto algo_utf8 = params->GetAlgo() + params->GetKeySizeStr(); - LOG(INFO) << "params" << params->GetAlgo() << params->GetKeySizeStr(); + SPDLOG_DEBUG("params: {} {}", params->GetAlgo(), params->GetKeySizeStr()); const char* algo = algo_utf8.c_str(); unsigned long expires = 0; @@ -181,9 +129,9 @@ GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::GenerateKey( GpgError err; - LOG(INFO) << "ctx version" << ctx_.GetInfo().GnupgVersion; + SPDLOG_DEBUG("ctx version, {}", ctx_.GetInfo(false).GnupgVersion); - if (ctx_.GetInfo().GnupgVersion >= "2.1.0") { + if (ctx_.GetInfo(false).GnupgVersion >= "2.1.0") { unsigned int flags = 0; if (!params->IsSubKey()) flags |= GPGME_CREATE_CERT; @@ -193,7 +141,7 @@ GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::GenerateKey( if (params->IsNonExpired()) flags |= GPGME_CREATE_NOEXPIRE; if (params->IsNoPassPhrase()) flags |= GPGME_CREATE_NOPASSWD; - LOG(INFO) << "args: " << userid << algo << expires << flags; + SPDLOG_DEBUG("args: {}", userid, algo, expires, flags); err = gpgme_op_createkey(ctx_, userid, algo, 0, expires, nullptr, flags); @@ -222,7 +170,7 @@ GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::GenerateKey( ss << "</GnupgKeyParms>"; - DLOG(INFO) << "params" << std::endl << ss.str(); + SPDLOG_DEBUG("params: {}", ss.str()); err = gpgme_op_genkey(ctx_, ss.str().c_str(), nullptr, nullptr); } @@ -245,9 +193,8 @@ GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::GenerateSubkey( const GpgKey& key, const std::unique_ptr<GenKeyInfo>& params) { if (!params->IsSubKey()) return GPG_ERR_CANCELED; - LOG(INFO) << "generate subkey" - << "algo" << params->GetAlgo() << "key size" - << params->GetKeySizeStr(); + SPDLOG_DEBUG("generate subkey algo {} key size {}", params->GetAlgo(), + params->GetKeySizeStr()); auto algo_utf8 = (params->GetAlgo() + params->GetKeySizeStr()); const char* algo = algo_utf8.c_str(); @@ -265,11 +212,9 @@ GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::GenerateSubkey( if (params->IsAllowSigning()) flags |= GPGME_CREATE_SIGN; if (params->IsAllowAuthentication()) flags |= GPGME_CREATE_AUTH; if (params->IsNonExpired()) flags |= GPGME_CREATE_NOEXPIRE; + if (params->IsNoPassPhrase()) flags |= GPGME_CREATE_NOPASSWD; - flags |= GPGME_CREATE_NOPASSWD; - - LOG(INFO) << "GpgFrontend::GpgKeyOpera::GenerateSubkey Args: " << key.GetId() - << algo << expires << flags; + SPDLOG_DEBUG("args: {} {} {} {}", key.GetId(), algo, expires, flags); auto err = gpgme_op_createsubkey(ctx_, gpgme_key_t(key), algo, 0, expires, flags); @@ -278,8 +223,8 @@ GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::GenerateSubkey( GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::ModifyPassword( const GpgFrontend::GpgKey& key) { - if (ctx_.GetInfo().GnupgVersion < "2.0.15") { - LOG(ERROR) << _("operator not support"); + if (ctx_.GetInfo(false).GnupgVersion < "2.0.15") { + SPDLOG_ERROR("operator not support"); return GPG_ERR_NOT_SUPPORTED; } auto err = gpgme_op_passwd(ctx_, gpgme_key_t(key), 0); @@ -287,8 +232,8 @@ GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::ModifyPassword( } GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::ModifyTOFUPolicy( const GpgFrontend::GpgKey& key, gpgme_tofu_policy_t tofu_policy) { - if (ctx_.GetInfo().GnupgVersion < "2.1.10") { - LOG(ERROR) << _("operator not support"); + if (ctx_.GetInfo(false).GnupgVersion < "2.1.10") { + SPDLOG_ERROR("operator not support"); return GPG_ERR_NOT_SUPPORTED; } auto err = gpgme_op_tofu_policy(ctx_, gpgme_key_t(key), tofu_policy); diff --git a/src/core/function/gpg/GpgUIDOperator.cpp b/src/core/function/gpg/GpgUIDOperator.cpp index 33c29fa4..7e7a711e 100644 --- a/src/core/function/gpg/GpgUIDOperator.cpp +++ b/src/core/function/gpg/GpgUIDOperator.cpp @@ -65,7 +65,7 @@ bool GpgFrontend::GpgUIDOperator::AddUID(const GpgFrontend::GpgKey& key, const std::string& name, const std::string& comment, const std::string& email) { - LOG(INFO) << "GpgFrontend::UidOperator::AddUID" << name << comment << email; + SPDLOG_DEBUG("new uuid: {} {} {}", name, comment, email); auto uid = boost::format("%1%(%2%)<%3%>") % name % comment % email; return AddUID(key, uid.str()); } diff --git a/src/core/function/result_analyse/GpgEncryptResultAnalyse.cpp b/src/core/function/result_analyse/GpgEncryptResultAnalyse.cpp index 9b3b9700..21d37eab 100644 --- a/src/core/function/result_analyse/GpgEncryptResultAnalyse.cpp +++ b/src/core/function/result_analyse/GpgEncryptResultAnalyse.cpp @@ -33,7 +33,7 @@ GpgFrontend::GpgEncryptResultAnalyse::GpgEncryptResultAnalyse( : error_(error), result_(std::move(result)) {} void GpgFrontend::GpgEncryptResultAnalyse::do_analyse() { - LOG(INFO) << _("Start Encrypt Result Analyse"); + SPDLOG_DEBUG("start encrypt result analyse"); stream_ << "[#] " << _("Encrypt Operation") << " "; diff --git a/src/core/function/result_analyse/GpgSignResultAnalyse.cpp b/src/core/function/result_analyse/GpgSignResultAnalyse.cpp index a47b8e3e..e4d1354f 100644 --- a/src/core/function/result_analyse/GpgSignResultAnalyse.cpp +++ b/src/core/function/result_analyse/GpgSignResultAnalyse.cpp @@ -35,7 +35,7 @@ GpgFrontend::GpgSignResultAnalyse::GpgSignResultAnalyse(GpgError error, : error_(error), result_(std::move(result)) {} void GpgFrontend::GpgSignResultAnalyse::do_analyse() { - LOG(INFO) << _("Start Sign Result Analyse"); + SPDLOG_DEBUG("start sign result analyse"); stream_ << "[#] " << _("Sign Operation") << " "; @@ -49,14 +49,14 @@ void GpgFrontend::GpgSignResultAnalyse::do_analyse() { if (result_ != nullptr && (result_->signatures != nullptr || result_->invalid_signers != nullptr)) { - LOG(INFO) << _("Sign Result Analyse Getting Result"); + SPDLOG_DEBUG("sign result analyse getting result"); stream_ << "------------>" << std::endl; auto new_sign = result_->signatures; while (new_sign != nullptr) { stream_ << "[>]" << _("New Signature") << ": " << std::endl; - LOG(INFO) << _("Signers Fingerprint") << ": " << new_sign->fpr; + SPDLOG_DEBUG("signers fingerprint: ", new_sign->fpr); stream_ << " " << _("Sign Mode") << ": "; if (new_sign->type == GPGME_SIG_MODE_NORMAL) @@ -92,7 +92,7 @@ void GpgFrontend::GpgSignResultAnalyse::do_analyse() { new_sign = new_sign->next; } - LOG(INFO) << _("Sign Result Analyse Getting Invalid Signer"); + SPDLOG_DEBUG("sign result analyse getting invalid signer"); auto invalid_signer = result_->invalid_signers; diff --git a/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp b/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp index 79eb5282..b19db5b2 100644 --- a/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp +++ b/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp @@ -39,7 +39,7 @@ GpgFrontend::GpgVerifyResultAnalyse::GpgVerifyResultAnalyse( : error_(error), result_(std::move(result)) {} void GpgFrontend::GpgVerifyResultAnalyse::do_analyse() { - LOG(INFO) << _("started"); + SPDLOG_DEBUG("started"); stream_ << "[#] " << _("Verify Operation") << " "; diff --git a/src/core/thread/CtxCheckTask.cpp b/src/core/thread/CtxCheckTask.cpp index 997dd341..9735fcaa 100644 --- a/src/core/thread/CtxCheckTask.cpp +++ b/src/core/thread/CtxCheckTask.cpp @@ -30,8 +30,9 @@ #include "core/GpgCoreInit.h" #include "core/common/CoreCommonUtil.h" #include "core/function/gpg/GpgKeyGetter.h" +#include "thread/Task.h" -GpgFrontend::Thread::CtxCheckTask::CtxCheckTask() { +GpgFrontend::Thread::CtxCheckTask::CtxCheckTask() : Task("ctx_check_task") { connect(this, &CtxCheckTask::SignalGnupgNotInstall, CoreCommonUtil::GetInstance(), &CoreCommonUtil::SignalGnupgNotInstall); @@ -48,4 +49,6 @@ void GpgFrontend::Thread::CtxCheckTask::Run() { // Try flushing key cache else GpgFrontend::GpgKeyGetter::GetInstance().FlushKeyCache(); + + SPDLOG_DEBUG("ctx check task runnable done"); } diff --git a/src/core/thread/FileReadTask.cpp b/src/core/thread/FileReadTask.cpp index 3a235390..73954d28 100644 --- a/src/core/thread/FileReadTask.cpp +++ b/src/core/thread/FileReadTask.cpp @@ -26,11 +26,9 @@ #include "core/thread/FileReadTask.h" -#include <utility> - namespace GpgFrontend::UI { -FileReadTask::FileReadTask(std::string path) { +FileReadTask::FileReadTask(std::string path) : Task("file_read_task") { connect(this, &FileReadTask::SignalFileBytesReadNext, this, &FileReadTask::read_bytes); @@ -48,18 +46,18 @@ void FileReadTask::Run() { SetFinishAfterRun(false); if (is_regular_file(read_file_path_)) { - LOG(INFO) << "read open file" << read_file_path_; + SPDLOG_DEBUG("read open file: {}", read_file_path_.u8string()); target_file_.setFileName( QString::fromStdString(read_file_path_.u8string())); target_file_.open(QIODevice::ReadOnly); if (!(target_file_.isOpen() && target_file_.isReadable())) { - LOG(ERROR) << "file not open or not readable"; + SPDLOG_ERROR("file not open or not readable"); if (target_file_.isOpen()) target_file_.close(); return; } - LOG(INFO) << "started reading" << read_file_path_; + SPDLOG_DEBUG("started reading: {}", read_file_path_.u8string()); read_bytes(); } else { emit SignalFileBytesReadEnd(); @@ -70,18 +68,18 @@ void FileReadTask::read_bytes() { QByteArray read_buffer; if (!target_file_.atEnd() && (read_buffer = target_file_.read(buffer_size_)).size() > 0) { - LOG(INFO) << "read bytes" << read_buffer.size(); + SPDLOG_DEBUG("read bytes: {}", read_buffer.size()); emit SignalFileBytesRead(std::move(read_buffer)); } else { - LOG(INFO) << "read bytes end"; + SPDLOG_DEBUG("read bytes end"); emit SignalFileBytesReadEnd(); - // finish task - emit SignalTaskFinished(); + // announce finish task + emit SignalTaskRunnableEnd(0); } } FileReadTask::~FileReadTask() { - LOG(INFO) << "close file" << read_file_path_; + SPDLOG_DEBUG("close file: {}", read_file_path_.u8string()); if (target_file_.isOpen()) target_file_.close(); } diff --git a/src/core/thread/Task.cpp b/src/core/thread/Task.cpp index 6b1a27a1..f3c6ae86 100644 --- a/src/core/thread/Task.cpp +++ b/src/core/thread/Task.cpp @@ -34,86 +34,159 @@ #include <utility> #include "core/thread/TaskRunner.h" -#include "easylogging++.h" -GpgFrontend::Thread::Task::Task() : uuid_(generate_uuid()) { - LOG(TRACE) << "Task" << uuid_ << "created"; +const std::string GpgFrontend::Thread::Task::DEFAULT_TASK_NAME = "default-task"; + +GpgFrontend::Thread::Task::Task(std::string name) + : uuid_(generate_uuid()), name_(name) { + SPDLOG_TRACE("task {}/ created", GetFullID()); init(); } -GpgFrontend::Thread::Task::Task(TaskCallback callback, - DataObjectPtr data_object) +GpgFrontend::Thread::Task::Task(TaskRunnable runnable, std::string name, + DataObjectPtr data_object, bool sequency) : uuid_(generate_uuid()), - callback_(std::move(callback)), + name_(name), + runnable_(std::move(runnable)), + callback_(std::move([](int, const std::shared_ptr<DataObject> &) {})), callback_thread_(QThread::currentThread()), - data_object_(data_object) { - LOG(TRACE) << "Task" << uuid_ << "created with callback" - << "callback_thread_: " << callback_thread_; + data_object_(data_object), + sequency_(sequency) { + SPDLOG_TRACE("task {} created with runnable, callback_thread_: {}", + GetFullID(), static_cast<void *>(callback_thread_)); init(); } -GpgFrontend::Thread::Task::Task(TaskRunnable runnable, TaskCallback callback, - DataObjectPtr data_object) +GpgFrontend::Thread::Task::Task(TaskRunnable runnable, std::string name, + DataObjectPtr data_object, + TaskCallback callback, bool sequency) : uuid_(generate_uuid()), + name_(name), runnable_(std::move(runnable)), callback_(std::move(callback)), callback_thread_(QThread::currentThread()), - data_object_(data_object) { + data_object_(data_object), + sequency_(sequency) { init(); - LOG(TRACE) << "Task" << uuid_ << "created with runnable and callback" - << "callback_thread_: " << callback_thread_; + SPDLOG_TRACE( + "task {} created with runnable and callback, callback_thread_: {}", + GetFullID(), static_cast<void *>(callback_thread_)); } GpgFrontend::Thread::Task::~Task() { - LOG(TRACE) << "Task" << uuid_ << "destroyed"; + SPDLOG_TRACE("task {} destroyed", GetFullID()); +} + +/** + * @brief + * + * @return std::string + */ +std::string GpgFrontend::Thread::Task::GetFullID() const { + return uuid_ + "/" + name_; } 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; +bool GpgFrontend::Thread::Task::GetSequency() const { return sequency_; } + +void GpgFrontend::Thread::Task::SetFinishAfterRun( + bool run_callback_after_runnable_finished) { + this->run_callback_after_runnable_finished_ = + run_callback_after_runnable_finished; } void GpgFrontend::Thread::Task::SetRTN(int rtn) { this->rtn_ = rtn; } void GpgFrontend::Thread::Task::init() { - connect(this, &Task::SignalTaskFinished, this, &Task::before_finish_task); + // after runnable finished, running callback + connect(this, &Task::SignalTaskRunnableEnd, this, + &Task::slot_task_run_callback); } -void GpgFrontend::Thread::Task::before_finish_task() { - LOG(TRACE) << "Task" << uuid_ << "finished"; +void GpgFrontend::Thread::Task::slot_task_run_callback(int rtn) { + SPDLOG_TRACE("task runnable {} finished, rtn: {}", GetFullID(), rtn); + // set return value + this->SetRTN(rtn); + try { 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"; + if (callback_thread_ == QThread::currentThread()) { + SPDLOG_DEBUG("callback thread is the same thread"); + if (!QMetaObject::invokeMethod(callback_thread_, + [callback = callback_, rtn = rtn_, + data_object = data_object_, this]() { + callback(rtn, data_object); + // do cleaning work + emit SignalTaskEnd(); + })) { + SPDLOG_ERROR("failed to invoke callback"); + } + // just finished, let callack thread to raise SignalTaskEnd + return; + } else { + // waiting for callback to finish + if (!QMetaObject::invokeMethod( + callback_thread_, + [callback = callback_, rtn = rtn_, + data_object = data_object_]() { callback(rtn, data_object); }, + Qt::BlockingQueuedConnection)) { + SPDLOG_ERROR("failed to invoke callback"); + } } } } catch (std::exception &e) { - LOG(ERROR) << "exception caught: " << e.what(); + SPDLOG_ERROR("exception caught: {}", e.what()); } catch (...) { - LOG(ERROR) << "unknown exception caught"; + SPDLOG_ERROR("unknown exception caught"); } - emit SignalTaskPostFinishedDone(); + + // raise signal, announcing this task come to an end + SPDLOG_DEBUG("task {}, starting calling signal SignalTaskEnd", GetFullID()); + emit SignalTaskEnd(); } void GpgFrontend::Thread::Task::run() { - LOG(TRACE) << "Task" << uuid_ << "started"; - Run(); - if (finish_after_run_) emit SignalTaskFinished(); + SPDLOG_TRACE("task {} starting", GetFullID()); + + // build runnable package for running + auto runnable_package = [=, id = GetFullID()]() { + SPDLOG_DEBUG("task {} runnable start runing", id); + // Run() will set rtn by itself + Run(); + // raise signal to anounce after runnable returned + if (run_callback_after_runnable_finished_) emit SignalTaskRunnableEnd(rtn_); + }; + + if (thread() != QThread::currentThread()) { + SPDLOG_DEBUG("task running thread is not object living thread"); + // if running sequently + if (sequency_) { + // running in another thread, blocking until returned + if (!QMetaObject::invokeMethod(thread(), runnable_package, + Qt::BlockingQueuedConnection)) { + SPDLOG_ERROR("qt invoke method failed"); + } + } else { + // running in another thread, non-blocking + if (!QMetaObject::invokeMethod(thread(), runnable_package)) { + SPDLOG_ERROR("qt invoke method failed"); + } + } + } else { + if (!QMetaObject::invokeMethod(this, runnable_package)) { + SPDLOG_ERROR("qt invoke method failed"); + } + } } +void GpgFrontend::Thread::Task::SlotRun() { run(); } + void GpgFrontend::Thread::Task::Run() { if (runnable_) { - bool if_invoke = QMetaObject::invokeMethod( - this, [=]() { return runnable_(data_object_); }, &rtn_); - if (!if_invoke) { - LOG(ERROR) << "Qt invokeMethod failed"; - } + SetRTN(runnable_(data_object_)); + } else { + SPDLOG_WARN("no runnable in task, do callback operation"); } } @@ -126,8 +199,8 @@ GpgFrontend::Thread::Task::DataObject::get_heap_ptr(size_t bytes_size) { GpgFrontend::Thread::Task::DataObject::~DataObject() { if (!data_objects_.empty()) - LOG(WARNING) << "data_objects_ is not empty" - << "address:" << this; + SPDLOG_WARN("data_objects_ is not empty", + "address:", static_cast<void *>(this)); while (!data_objects_.empty()) { free_heap_ptr(data_objects_.top()); data_objects_.pop(); @@ -139,8 +212,9 @@ size_t GpgFrontend::Thread::Task::DataObject::GetObjectSize() { } void GpgFrontend::Thread::Task::DataObject::free_heap_ptr(Destructor *ptr) { - DLOG(TRACE) << "p_obj: " << ptr->p_obj << "destructor: " << ptr->destroy - << "DataObject:" << this; + SPDLOG_TRACE("p_obj: {} data object: {}", + static_cast<const void *>(ptr->p_obj), + static_cast<void *>(this)); if (ptr->destroy != nullptr) { ptr->destroy(ptr->p_obj); } diff --git a/src/core/thread/Task.h b/src/core/thread/Task.h index c94baea6..ce354697 100644 --- a/src/core/thread/Task.h +++ b/src/core/thread/Task.h @@ -50,6 +50,8 @@ class GPGFRONTEND_CORE_EXPORT Task : public QObject, public QRunnable { using TaskRunnable = std::function<int(DataObjectPtr)>; ///< using TaskCallback = std::function<void(int, DataObjectPtr)>; ///< + static const std::string DEFAULT_TASK_NAME; + friend class TaskRunner; /** @@ -78,9 +80,10 @@ class GPGFRONTEND_CORE_EXPORT Task : public QObject, public QRunnable { */ template <typename T> void AppendObject(T &&obj) { - DLOG(TRACE) << "called:" << this; + SPDLOG_TRACE("append object: {}", static_cast<void *>(this)); auto *obj_dstr = this->get_heap_ptr(sizeof(T)); - auto *ptr_heap = new ((void *)obj_dstr->p_obj) T(std::move(obj)); + new ((void *)obj_dstr->p_obj) T(std::forward<T>(obj)); + if (std::is_class_v<T>) { auto destructor = [](const void *x) { static_cast<const T *>(x)->~T(); @@ -89,7 +92,8 @@ class GPGFRONTEND_CORE_EXPORT Task : public QObject, public QRunnable { } else { obj_dstr->destroy = nullptr; } - data_objects_.push(std::move(obj_dstr)); + + data_objects_.push(obj_dstr); } /** @@ -100,11 +104,11 @@ class GPGFRONTEND_CORE_EXPORT Task : public QObject, public QRunnable { */ template <typename T> void AppendObject(T *obj) { - DLOG(TRACE) << "called:" << this; + SPDLOG_TRACE("called: {}", static_cast<void *>(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>) { - LOG(TRACE) << "is class"; + SPDLOG_TRACE("is class"); auto destructor = [](const void *x) { static_cast<const T *>(x)->~T(); }; @@ -123,7 +127,7 @@ class GPGFRONTEND_CORE_EXPORT Task : public QObject, public QRunnable { */ template <typename T> T PopObject() { - DLOG(TRACE) << "called:" << this; + SPDLOG_TRACE("pop object: {}", static_cast<void *>(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; @@ -162,24 +166,25 @@ class GPGFRONTEND_CORE_EXPORT Task : public QObject, public QRunnable { * @brief Construct a new Task object * */ - Task(); + Task(std::string name = DEFAULT_TASK_NAME); /** * @brief Construct a new Task object * * @param callback The callback function to be executed. */ - Task(TaskCallback callback, DataObjectPtr data_object = nullptr); + explicit Task(TaskRunnable runnable, std::string name = DEFAULT_TASK_NAME, + DataObjectPtr data_object = nullptr, bool sequency = true); /** * @brief Construct a new Task object * * @param runnable */ - Task( - TaskRunnable runnable, - TaskCallback callback = [](int, std::shared_ptr<DataObject>) {}, - DataObjectPtr data = nullptr); + explicit Task( + TaskRunnable runnable, std::string name, DataObjectPtr data, + TaskCallback callback = [](int, const std::shared_ptr<DataObject> &) {}, + bool sequency = true); /** * @brief Destroy the Task object @@ -200,18 +205,40 @@ class GPGFRONTEND_CORE_EXPORT Task : public QObject, public QRunnable { */ std::string GetUUID() const; - signals: /** * @brief * + * @return std::string */ - void SignalTaskFinished(); + std::string GetFullID() const; /** * @brief * + * @return std::string + */ + bool GetSequency() const; + + public slots: + + /** + * @brief + * + */ + void SlotRun(); + + signals: + /** + * @brief announce runnable finished + * + */ + void SignalTaskRunnableEnd(int rtn); + + /** + * @brief runnable and callabck all finished + * */ - void SignalTaskPostFinishedDone(); + void SignalTaskEnd(); protected: /** @@ -230,37 +257,40 @@ class GPGFRONTEND_CORE_EXPORT Task : public QObject, public QRunnable { private: const std::string uuid_; - TaskCallback callback_; ///< - TaskRunnable runnable_; ///< - bool finish_after_run_ = true; ///< - int rtn_ = 0; ///< - QThread *callback_thread_ = nullptr; ///< - DataObjectPtr data_object_ = nullptr; ///< + const std::string name_; + const bool sequency_ = true; ///< must run in the same thread + TaskCallback callback_; ///< + TaskRunnable runnable_; ///< + bool run_callback_after_runnable_finished_ = true; ///< + int rtn_ = 0; ///< + QThread *callback_thread_ = nullptr; ///< + DataObjectPtr data_object_ = nullptr; ///< /** * @brief * */ - void before_finish_task(); + void init(); /** * @brief * */ - void init(); + virtual void run() override; /** * @brief * + * @return std::string */ - virtual void run() override; + static std::string generate_uuid(); + private slots: /** * @brief * - * @return std::string */ - static std::string generate_uuid(); + void slot_task_run_callback(int rtn); }; } // namespace GpgFrontend::Thread diff --git a/src/core/thread/TaskRunner.cpp b/src/core/thread/TaskRunner.cpp index f70b2d4c..461d5fb5 100644 --- a/src/core/thread/TaskRunner.cpp +++ b/src/core/thread/TaskRunner.cpp @@ -26,32 +26,24 @@ #include "core/thread/TaskRunner.h" -#include <exception> - #include "core/thread/Task.h" -#include "easylogging++.h" +#include "spdlog/spdlog.h" GpgFrontend::Thread::TaskRunner::TaskRunner() = default; GpgFrontend::Thread::TaskRunner::~TaskRunner() = default; void GpgFrontend::Thread::TaskRunner::PostTask(Task* task) { - std::string uuid = task->GetUUID(); - LOG(TRACE) << "Post Task" << uuid; + if (task == nullptr) { + SPDLOG_ERROR("task posted is null"); + return; + } + + SPDLOG_TRACE("post task: {}", task->GetFullID()); - if (task == nullptr) return; task->setParent(nullptr); task->moveToThread(this); - connect(task, &Task::SignalTaskPostFinishedDone, this, [&, uuid]() { - auto it = pending_tasks_.find(uuid); - if (it == pending_tasks_.end()) { - return; - } else { - it->second->deleteLater(); - pending_tasks_.erase(it); - } - }); { std::lock_guard<std::mutex> lock(tasks_mutex_); tasks.push(task); @@ -59,16 +51,20 @@ void GpgFrontend::Thread::TaskRunner::PostTask(Task* task) { quit(); } -void GpgFrontend::Thread::TaskRunner::run() { - LOG(TRACE) << "called" - << "thread id:" << QThread::currentThreadId(); +void GpgFrontend::Thread::TaskRunner::PostScheduleTask(Task* task, + size_t seconds) { + if (task == nullptr) return; + // TODO +} + +[[noreturn]] void GpgFrontend::Thread::TaskRunner::run() { + SPDLOG_TRACE("task runner runing, thread id: {}", QThread::currentThreadId()); while (true) { - LOG(TRACE) << "TaskRunner: A new cycle start"; if (tasks.empty()) { - LOG(TRACE) << "TaskRunner: No tasks to run, trapping into event loop..."; + SPDLOG_TRACE("no tasks to run, trapping into event loop..."); exec(); } else { - LOG(TRACE) << "TaskRunner: Task queue size:" << tasks.size(); + SPDLOG_TRACE("start to run task(s), queue size: {}", tasks.size()); Task* task = nullptr; { @@ -79,26 +75,72 @@ void GpgFrontend::Thread::TaskRunner::run() { } if (task != nullptr) { - // Run the task - LOG(TRACE) << "TaskRunner: Running Task" << task->GetUUID(); try { + // triger + SPDLOG_TRACE("running task {}, sequency: {}", task->GetFullID(), + task->GetSequency()); + + // when a signal SignalTaskEnd raise, do unregister work + connect(task, &Task::SignalTaskEnd, this, [this, task]() { + unregister_finished_task(task->GetUUID()); + }); + + if (!task->GetSequency()) { + // if it need to run concurrently, we should create a new thread to + // run it. + auto* concurrent_thread = new QThread(nullptr); + task->setParent(nullptr); + task->moveToThread(concurrent_thread); + // start thread + concurrent_thread->start(); + + connect(task, &Task::SignalTaskEnd, concurrent_thread, + &QThread::quit); + // concurrent thread is responsible for deleting the task + connect(concurrent_thread, &QThread::finished, task, + &Task::deleteLater); + } + + // run the task task->run(); } catch (const std::exception& e) { - LOG(ERROR) << "TaskRunner: Exception in Task" << task->GetUUID() - << "Exception: " << e.what(); - - // destroy the task, remove the task from the pending tasks - task->deleteLater(); - pending_tasks_.erase(task->GetUUID()); + SPDLOG_ERROR("task runner: exception in task {}, exception: {}", + task->GetFullID(), e.what()); + // if any exception caught, destroy the task, remove the task from the + // pending tasks + unregister_finished_task(task->GetUUID()); } catch (...) { - LOG(ERROR) << "TaskRunner: Unknwon Exception in Task" - << task->GetUUID(); - - // destroy the task, remove the task from the pending tasks - task->deleteLater(); - pending_tasks_.erase(task->GetUUID()); + SPDLOG_ERROR("task runner: unknown exception in task: {}", + task->GetFullID()); + // if any exception caught, destroy the task, remove the task from the + // pending tasks + unregister_finished_task(task->GetUUID()); } } } } } + +/** + * @brief + * + */ +void GpgFrontend::Thread::TaskRunner::unregister_finished_task( + std::string task_uuid) { + SPDLOG_DEBUG("cleaning task {}", task_uuid); + // search in map + auto pending_task = pending_tasks_.find(task_uuid); + if (pending_task == pending_tasks_.end()) { + SPDLOG_ERROR("cannot find task in pending list: {}", task_uuid); + return; + } else { + std::lock_guard<std::mutex> lock(tasks_mutex_); + // if thread runs sequenctly, that means the thread is living in this + // thread, so we can delete it. Or, its living thread need to delete it. + if (pending_task->second->GetSequency()) + pending_task->second->deleteLater(); + pending_tasks_.erase(pending_task); + } + + SPDLOG_DEBUG("clean task {} done", task_uuid); +} diff --git a/src/core/thread/TaskRunner.h b/src/core/thread/TaskRunner.h index f18efca6..35cd1a30 100644 --- a/src/core/thread/TaskRunner.h +++ b/src/core/thread/TaskRunner.h @@ -27,6 +27,7 @@ #ifndef GPGFRONTEND_TASKRUNNER_H #define GPGFRONTEND_TASKRUNNER_H +#include <cstddef> #include <mutex> #include <queue> @@ -55,7 +56,7 @@ class GPGFRONTEND_CORE_EXPORT TaskRunner : public QThread { * @brief * */ - void run() override; + [[noreturn]] void run() override; public slots: @@ -66,10 +67,25 @@ class GPGFRONTEND_CORE_EXPORT TaskRunner : public QThread { */ void PostTask(Task* task); + /** + * @brief + * + * @param task + * @param seconds + */ + void PostScheduleTask(Task* task, size_t seconds); + private: std::queue<Task*> tasks; ///< The task queue std::map<std::string, Task*> pending_tasks_; ///< The pending tasks std::mutex tasks_mutex_; ///< The task queue mutex + QThreadPool thread_pool_{this}; ///< run non-sequency task + + /** + * @brief + * + */ + void unregister_finished_task(std::string); }; } // namespace GpgFrontend::Thread diff --git a/src/core/thread/TaskRunnerGetter.h b/src/core/thread/TaskRunnerGetter.h index afbf63af..80b25c3e 100644 --- a/src/core/thread/TaskRunnerGetter.h +++ b/src/core/thread/TaskRunnerGetter.h @@ -41,6 +41,7 @@ class GPGFRONTEND_CORE_EXPORT TaskRunnerGetter kTaskRunnerType_GPG, kTaskRunnerType_IO, kTaskRunnerType_Network, + kTaskRunnerType_External_Process, }; TaskRunnerGetter(int channel = SingletonFunctionObject::GetDefaultChannel()); diff --git a/src/init.cpp b/src/init.cpp index c872170e..80c34800 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -26,21 +26,103 @@ * */ +#include <spdlog/async.h> +#include <spdlog/common.h> +#include <spdlog/sinks/rotating_file_sink.h> +#include <spdlog/sinks/stdout_color_sinks.h> + +#include <filesystem> + #include "GpgFrontend.h" #include "GpgFrontendBuildInfo.h" #include "core/function/GlobalSettingStation.h" +#ifdef WINDOWS +int setenv(const char *name, const char *value, int overwrite) +{ + if(!overwrite) { + int errcode = 0; + size_t envsize = 0; + errcode = getenv_s(&envsize, NULL, 0, name); + if(errcode || envsize) return errcode; + } + return _putenv_s(name, value); +} +#endif + void init_logging_system() { - el::Loggers::addFlag(el::LoggingFlag::AutoSpacing); - el::Configurations defaultConf; - defaultConf.setToDefault(); - - // apply settings - defaultConf.setGlobally(el::ConfigurationType::Format, - "%datetime %level [main] %func %msg"); - // apply settings no written to file - defaultConf.setGlobally(el::ConfigurationType::ToFile, "false"); - - // set the logger - el::Loggers::reconfigureLogger("default", defaultConf); + using namespace boost::posix_time; + using namespace boost::gregorian; + + // sinks + std::vector<spdlog::sink_ptr> sinks; + sinks.push_back(std::make_shared<spdlog::sinks::stderr_color_sink_mt>()); + + // thread pool + spdlog::init_thread_pool(1024, 2); + + // logger + auto main_logger = std::make_shared<spdlog::async_logger>( + "main", begin(sinks), end(sinks), spdlog::thread_pool()); + main_logger->set_pattern( + "[%H:%M:%S.%e] [T:%t] [%=4n] %^[%=8l]%$ [%s:%#] [%!] -> %v (+%ius)"); + +#ifdef DEBUG + main_logger->set_level(spdlog::level::trace); +#else + main_logger->set_level(spdlog::level::info); +#endif + + // flush policy + main_logger->flush_on(spdlog::level::err); + spdlog::flush_every(std::chrono::seconds(5)); + + // register it as default logger + spdlog::set_default_logger(main_logger); +} + +void shutdown_logging_system() { +#ifdef WINDOWS + // Under VisualStudio, this must be called before main finishes to workaround + // a known VS issue + spdlog::drop_all(); + spdlog::shutdown(); +#endif +} + +void init_global_path_env() { + auto& settings = + GpgFrontend::GlobalSettingStation::GetInstance().GetUISettings(); + + bool use_custom_gnupg_install_path = false; + try { + use_custom_gnupg_install_path = + settings.lookup("general.use_custom_gnupg_install_path"); + } catch (...) { + SPDLOG_ERROR("setting operation error: use_custom_gnupg_install_path"); + } + + // read from settings file + std::string custom_gnupg_install_path; + try { + custom_gnupg_install_path = static_cast<std::string>( + settings.lookup("general.custom_gnupg_install_path")); + + } catch (...) { + SPDLOG_ERROR("setting operation error: custom_gnupg_install_path"); + } + + // add custom gnupg install path into env $PATH + if (use_custom_gnupg_install_path && !custom_gnupg_install_path.empty()) { + std::string path_value = getenv("PATH"); + SPDLOG_DEBUG("PATH: {}", path_value); + setenv( + "PATH", + ((std::filesystem::path{custom_gnupg_install_path} / "bin").u8string() + + ":" + path_value) + .c_str(), + 1); + std::string modified_path_value = getenv("PATH"); + SPDLOG_DEBUG("Modified PATH: {}", modified_path_value); + } } diff --git a/src/main.cpp b/src/main.cpp index 5f2ba02e..98c02a0e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -33,18 +33,17 @@ #include <csetjmp> #include <csignal> #include <cstddef> +#include <cstdlib> +#include <string> #include "core/GpgConstants.h" #include "core/GpgCoreInit.h" +#include "core/function/GlobalSettingStation.h" +#include "spdlog/spdlog.h" #include "ui/GpgFrontendApplication.h" #include "ui/GpgFrontendUIInit.h" /** - * \brief initialize the easylogging++ library. - */ -INITIALIZE_EASYLOGGINGPP - -/** * \brief Store the jump buff and make it possible to recover from a crash. */ #ifdef FREEBSD @@ -75,6 +74,18 @@ extern void before_exit(); extern void init_logging_system(); /** + * @brief initialize the logging system. + * + */ +extern void shutdown_logging_system(); + +/** + * @brief init global PATH env + * + */ +extern void init_global_path_env(); + +/** * * @param argc * @param argv @@ -98,11 +109,17 @@ int main(int argc, char* argv[]) { auto* app = GpgFrontend::UI::GpgFrontendApplication::GetInstance(argc, argv, true); - // init the logging system + // init the logging system for main init_logging_system(); // init the logging system for core - GpgFrontend::InitLoggingSystem(); + GpgFrontend::InitCoreLoggingSystem(); + + // init the logging system for ui + GpgFrontend::UI::InitUILoggingSystem(); + + // change path to search for related + init_global_path_env(); /** * internationalisation. loop to restart main window @@ -124,7 +141,7 @@ int main(int argc, char* argv[]) { // create main window return_from_event_loop_code = GpgFrontend::UI::RunGpgFrontendUI(app); } else { - LOG(ERROR) << "recover from a crash"; + SPDLOG_ERROR("recover from a crash"); // when signal is caught, restart the main window auto* message_box = new QMessageBox( QMessageBox::Critical, _("A serious error has occurred"), @@ -137,16 +154,38 @@ int main(int argc, char* argv[]) { return_from_event_loop_code = CRASH_CODE; } - LOG(INFO) << "loop refresh"; + SPDLOG_DEBUG("restart loop refresh, event loop code: {}", + return_from_event_loop_code); } while (return_from_event_loop_code == RESTART_CODE); - // reset core - GpgFrontend::ResetGpgFrontendCore(); + if (return_from_event_loop_code == DEEP_RESTART_CODE || + return_from_event_loop_code == CRASH_CODE) { + // reset core + GpgFrontend::ResetGpgFrontendCore(); + // log for debug + SPDLOG_DEBUG("deep restart or cash loop refresh"); + } else { + // log for debug + SPDLOG_DEBUG("need to close application, event loop code: {}", + return_from_event_loop_code); + } // deep restart mode } while (return_from_event_loop_code == DEEP_RESTART_CODE || return_from_event_loop_code == CRASH_CODE); + + // shutdown the logging system for ui + GpgFrontend::UI::ShutdownUILoggingSystem(); + + // shutdown the logging system for core + GpgFrontend::ShutdownCoreLoggingSystem(); + + + + // log for debug + SPDLOG_INFO("GpgFrontend about to exit."); + // exit the program return return_from_event_loop_code; } diff --git a/src/signal.cpp b/src/signal.cpp index bd4cfdb1..da4dfb39 100644 --- a/src/signal.cpp +++ b/src/signal.cpp @@ -43,7 +43,8 @@ extern jmp_buf recover_env; */ void handle_signal(int sig) { static int _repeat_handle_num = 1, last_sig = sig; - LOG(INFO) << "signal caught" << sig; + // SPDLOG_DEBUG("signal caught {}", sig); + std::cout << "signal caught" << sig; if (last_sig == sig) _repeat_handle_num++; @@ -51,8 +52,8 @@ void handle_signal(int sig) { _repeat_handle_num = 1, last_sig = sig; if (_repeat_handle_num > 3) { - LOG(INFO) << "The same signal appears three times, execute the termination " - "operation. "; + std::cout << "The same signal appears three times," + << "execute the termination operation." << sig; exit(-1); } diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index 24158e27..176a406e 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -46,8 +46,13 @@ set(_export_file "${CMAKE_CURRENT_SOURCE_DIR}/GpgFrontendUIExport.h") generate_export_header(gpgfrontend_ui EXPORT_FILE_NAME "${_export_file}") # link Qt -target_link_libraries(gpgfrontend_ui - Qt5::Network Qt5::PrintSupport Qt5::Widgets Qt5::Test Qt5::Core) +if(Qt6_DIR) + target_link_libraries(gpgfrontend_ui + Qt6::Network Qt6::PrintSupport Qt6::Widgets Qt6::Test Qt6::Core5Compat Qt6::Core) +else() + target_link_libraries(gpgfrontend_ui + Qt5::Network Qt5::PrintSupport Qt5::Widgets Qt5::Test Qt5::Core) +endif() # link gpgfrontend_core target_link_libraries(gpgfrontend_ui @@ -58,7 +63,8 @@ target_precompile_headers(gpgfrontend_ui PUBLIC GpgFrontendUI.h) # add ui generator include path target_include_directories(gpgfrontend_ui PUBLIC - ${CMAKE_CURRENT_BINARY_DIR}/gpgfrontend_ui_autogen/include) + ${CMAKE_CURRENT_BINARY_DIR}/gpgfrontend_ui_autogen/include + ${CMAKE_SOURCE_DIR}/third_party/spdlog/include) # using std c++ 17 target_compile_features(gpgfrontend_ui PUBLIC cxx_std_17) diff --git a/src/ui/GpgFrontendApplication.cpp b/src/ui/GpgFrontendApplication.cpp index b1c5beed..1b2bb9ad 100644 --- a/src/ui/GpgFrontendApplication.cpp +++ b/src/ui/GpgFrontendApplication.cpp @@ -26,6 +26,8 @@ #include "ui/GpgFrontendApplication.h" +#include <QTextCodec> + #include "GpgFrontendBuildInfo.h" namespace GpgFrontend::UI { @@ -36,11 +38,6 @@ GpgFrontendApplication::GpgFrontendApplication(int &argc, char *argv[]) this->setWindowIcon(QIcon(":gpgfrontend.png")); #endif -#ifdef MACOS - // support retina screen - this->setAttribute(Qt::AA_UseHighDpiPixmaps); -#endif - // set the extra information of the build this->setApplicationVersion(BUILD_VERSION); this->setApplicationName(PROJECT_NAME); @@ -75,7 +72,7 @@ bool GpgFrontendApplication::notify(QObject *receiver, QEvent *event) { try { app_done = QApplication::notify(receiver, event); } catch (const std::exception &ex) { - LOG(INFO) << "Exception caught in notify: " << ex.what(); + SPDLOG_ERROR("exception caught in notify: {}", ex.what()); QMessageBox::information(nullptr, _("Standard Exception Thrown"), _("Oops, an standard exception was thrown " "during the running of the " @@ -83,7 +80,7 @@ bool GpgFrontendApplication::notify(QObject *receiver, QEvent *event) { "be the negligence of the programmer, " "please report this problem if you can.")); } catch (...) { - LOG(INFO) << "Unknown exception caught in notify"; + SPDLOG_ERROR("unknown exception caught in notify"); QMessageBox::information( nullptr, _("Unhandled Exception Thrown"), _("Oops, an unhandled exception was thrown " diff --git a/src/ui/GpgFrontendUIInit.cpp b/src/ui/GpgFrontendUIInit.cpp index 5cbca31b..6e41f81f 100644 --- a/src/ui/GpgFrontendUIInit.cpp +++ b/src/ui/GpgFrontendUIInit.cpp @@ -28,6 +28,11 @@ #include "GpgFrontendUIInit.h" +#include <spdlog/async.h> +#include <spdlog/common.h> +#include <spdlog/sinks/rotating_file_sink.h> +#include <spdlog/sinks/stdout_color_sinks.h> + #include "core/function/GlobalSettingStation.h" #include "core/thread/CtxCheckTask.h" #include "core/thread/TaskRunnerGetter.h" @@ -39,18 +44,12 @@ #include "core/function/GlobalSettingStation.h" #endif -// init easyloggingpp library -INITIALIZE_EASYLOGGINGPP - namespace GpgFrontend::UI { extern void init_logging_system(); extern void init_locale(); void InitGpgFrontendUI(QApplication* app) { - // init logging system - init_logging_system(); - // init locale init_locale(); @@ -88,15 +87,15 @@ void InitGpgFrontendUI(QApplication* app) { waiting_dialog_label->setWordWrap(true); waiting_dialog->setLabel(waiting_dialog_label); waiting_dialog->resize(420, 120); - app->connect(init_ctx_task, &Thread::CtxCheckTask::SignalTaskFinished, + app->connect(init_ctx_task, &Thread::CtxCheckTask::SignalTaskEnd, waiting_dialog, [=]() { - LOG(INFO) << "Gpg context loaded"; + SPDLOG_DEBUG("gpg context loaded"); waiting_dialog->finished(0); waiting_dialog->deleteLater(); }); app->connect(waiting_dialog, &QProgressDialog::canceled, [=]() { - LOG(INFO) << "cancel clicked"; + SPDLOG_DEBUG("cancel clicked"); app->quit(); exit(0); }); @@ -108,8 +107,8 @@ void InitGpgFrontendUI(QApplication* app) { // new local event looper QEventLoop looper; - app->connect(init_ctx_task, &Thread::CtxCheckTask::SignalTaskFinished, - &looper, &QEventLoop::quit); + app->connect(init_ctx_task, &Thread::CtxCheckTask::SignalTaskEnd, &looper, + &QEventLoop::quit); // start the thread to load the gpg context Thread::TaskRunnerGetter::GetInstance().GetTaskRunner()->PostTask( @@ -123,46 +122,56 @@ int RunGpgFrontendUI(QApplication* app) { // create main window and show it auto main_window = std::make_unique<GpgFrontend::UI::MainWindow>(); main_window->Init(); - LOG(INFO) << "Main window inited"; + SPDLOG_DEBUG("main window inited"); main_window->show(); // start the main event loop return app->exec(); } -void init_logging_system() { +void InitUILoggingSystem() { using namespace boost::posix_time; using namespace boost::gregorian; - el::Loggers::addFlag(el::LoggingFlag::AutoSpacing); - el::Loggers::addFlag(el::LoggingFlag::ColoredTerminalOutput); - el::Loggers::addFlag(el::LoggingFlag::StrictLogFileSizeCheck); - - el::Configurations defaultConf; - defaultConf.setToDefault(); + // get the log directory + auto logfile_path = (GlobalSettingStation::GetInstance().GetLogDir() / "ui"); + logfile_path.replace_extension(".log"); - // apply settings - defaultConf.setGlobally(el::ConfigurationType::Format, - "%datetime %level [ui] {%func} -> %msg"); + // sinks + std::vector<spdlog::sink_ptr> sinks; + sinks.push_back(std::make_shared<spdlog::sinks::stderr_color_sink_mt>()); + sinks.push_back(std::make_shared<spdlog::sinks::rotating_file_sink_mt>( + logfile_path.u8string(), 1048576 * 32, 32)); - // apply settings no written to file - defaultConf.setGlobally(el::ConfigurationType::ToFile, "false"); + // thread pool + spdlog::init_thread_pool(1024, 2); - // apply settings - el::Loggers::reconfigureLogger("default", defaultConf)->reconfigure(); + // logger + auto ui_logger = std::make_shared<spdlog::async_logger>( + "ui", begin(sinks), end(sinks), spdlog::thread_pool()); + ui_logger->set_pattern( + "[%H:%M:%S.%e] [T:%t] [%=4n] %^[%=8l]%$ [%s:%#] [%!] -> %v (+%ius)"); - // get the log directory - auto logfile_path = (GlobalSettingStation::GetInstance().GetLogDir() / - to_iso_string(second_clock::local_time())); - logfile_path.replace_extension(".log"); - defaultConf.setGlobally(el::ConfigurationType::Filename, - logfile_path.u8string()); +#ifdef DEBUG + ui_logger->set_level(spdlog::level::trace); +#else + ui_logger->set_level(spdlog::level::info); +#endif - // apply settings written to file - defaultConf.setGlobally(el::ConfigurationType::ToFile, "false"); + // flush policy + ui_logger->flush_on(spdlog::level::err); + spdlog::flush_every(std::chrono::seconds(5)); - el::Loggers::reconfigureLogger("default", defaultConf); + // register it as default logger + spdlog::set_default_logger(ui_logger); +} - LOG(INFO) << _("log file path") << logfile_path; +void ShutdownUILoggingSystem() { +#ifdef WINDOWS + // Under VisualStudio, this must be called before main finishes to workaround + // a known VS issue + spdlog::drop_all(); + spdlog::shutdown(); +#endif } /** @@ -187,20 +196,20 @@ void init_locale() { // sync the settings to the file GpgFrontend::GlobalSettingStation::GetInstance().SyncSettings(); - LOG(INFO) << "current system locale" << setlocale(LC_ALL, nullptr); + SPDLOG_DEBUG("current system locale: {}", setlocale(LC_ALL, nullptr)); // read from settings file std::string lang; if (!general.lookupValue("lang", lang)) { - LOG(ERROR) << _("could not read properly from configure file"); + SPDLOG_ERROR(_("could not read properly from configure file")); }; - LOG(INFO) << "lang from settings" << lang; - LOG(INFO) << "project name" << PROJECT_NAME; - LOG(INFO) << "locales path" - << GpgFrontend::GlobalSettingStation::GetInstance() + SPDLOG_DEBUG("lang from settings: {}", lang); + SPDLOG_DEBUG("project name: {}", PROJECT_NAME); + SPDLOG_DEBUG("locales path: {}", + GpgFrontend::GlobalSettingStation::GetInstance() .GetLocaleDir() - .c_str(); + .u8string()); #ifndef WINDOWS if (!lang.empty()) { @@ -208,14 +217,14 @@ void init_locale() { // set LC_ALL auto* locale_name = setlocale(LC_ALL, lc.c_str()); - if (locale_name == nullptr) LOG(WARNING) << "set LC_ALL failed" << lc; + if (locale_name == nullptr) SPDLOG_WARN("set LC_ALL failed, lc: {}", lc); auto language = getenv("LANGUAGE"); // set LANGUAGE std::string language_env = language == nullptr ? "en" : language; language_env.insert(0, lang + ":"); - LOG(INFO) << "language env" << language_env; + SPDLOG_DEBUG("language env: {}", language_env); if (setenv("LANGUAGE", language_env.c_str(), 1)) { - LOG(WARNING) << "set LANGUAGE failed" << language_env; + SPDLOG_WARN("set LANGUAGE {} failed", language_env); }; } #else @@ -224,16 +233,16 @@ void init_locale() { // set LC_ALL auto* locale_name = setlocale(LC_ALL, lc.c_str()); - if (locale_name == nullptr) LOG(WARNING) << "set LC_ALL failed" << lc; + if (locale_name == nullptr) SPDLOG_WARN("set LC_ALL failed, lc: {}", lc); auto language = getenv("LANGUAGE"); // set LANGUAGE std::string language_env = language == nullptr ? "en" : language; language_env.insert(0, lang + ":"); language_env.insert(0, "LANGUAGE="); - LOG(INFO) << "language env" << language_env; + SPDLOG_DEBUG("language env: {}", language_env); if (putenv(language_env.c_str())) { - LOG(WARNING) << "set LANGUAGE failed" << language_env; + SPDLOG_WARN("set LANGUAGE {} failed", language_env); }; } #endif @@ -246,4 +255,4 @@ void init_locale() { textdomain(PROJECT_NAME); } -} // namespace GpgFrontend::UI
\ No newline at end of file +} // namespace GpgFrontend::UI diff --git a/src/ui/GpgFrontendUIInit.h b/src/ui/GpgFrontendUIInit.h index 9b490c0f..0e68aa57 100644 --- a/src/ui/GpgFrontendUIInit.h +++ b/src/ui/GpgFrontendUIInit.h @@ -40,6 +40,18 @@ namespace GpgFrontend::UI { void GPGFRONTEND_UI_EXPORT InitGpgFrontendUI(QApplication *); /** + * @brief + * + */ +void GPGFRONTEND_UI_EXPORT InitUILoggingSystem(); + +/** + * @brief + * + */ +void GPGFRONTEND_UI_EXPORT ShutdownUILoggingSystem(); + +/** * @brief run main window */ int GPGFRONTEND_UI_EXPORT RunGpgFrontendUI(QApplication *); diff --git a/src/ui/SignalStation.h b/src/ui/SignalStation.h index eb7b3f74..48651f1b 100644 --- a/src/ui/SignalStation.h +++ b/src/ui/SignalStation.h @@ -79,6 +79,18 @@ class SignalStation : public QObject { * @param timeout */ void SignalRefreshStatusBar(const QString& message, int timeout); + + /** + * @brief + * + */ + void SignalUserInputPassphraseDone(QString passparase); + + /** + * @brief + * + */ + void SignalNeedUserInputPassphrase(); }; } // namespace GpgFrontend::UI diff --git a/src/ui/UserInterfaceUtils.cpp b/src/ui/UserInterfaceUtils.cpp index f2659e9d..f944e037 100644 --- a/src/ui/UserInterfaceUtils.cpp +++ b/src/ui/UserInterfaceUtils.cpp @@ -28,17 +28,19 @@ #include "UserInterfaceUtils.h" +#include <string> #include <utility> #include <vector> #include "core/common/CoreCommonUtil.h" +#include "core/function/CoreSignalStation.h" #include "core/function/FileOperator.h" #include "core/function/GlobalSettingStation.h" #include "core/function/gpg/GpgKeyGetter.h" #include "core/thread/Task.h" #include "core/thread/TaskRunner.h" #include "core/thread/TaskRunnerGetter.h" -#include "easylogging++.h" +#include "spdlog/spdlog.h" #include "ui/SignalStation.h" #include "ui/dialog/WaitingDialog.h" #include "ui/struct/SettingsObject.h" @@ -72,7 +74,7 @@ void import_unknown_key_from_keyserver( auto key_ids = std::make_unique<KeyIdArgsList>(); auto *signature = verify_res.GetSignatures(); while (signature != nullptr) { - LOG(INFO) << "signature fpr" << signature->fpr; + SPDLOG_DEBUG("signature fpr: {}", signature->fpr); key_ids->push_back(signature->fpr); signature = signature->next; } @@ -103,8 +105,6 @@ void process_result_analyse(TextEdit *edit, InfoBoardWidget *info_board, void process_result_analyse(TextEdit *edit, InfoBoardWidget *info_board, const GpgResultAnalyse &result_analyse_a, const GpgResultAnalyse &result_analyse_b) { - LOG(INFO) << "process_result_analyse Started"; - info_board->AssociateTabWidget(edit->tab_widget_); refresh_info_board( @@ -120,15 +120,15 @@ void process_operation(QWidget *parent, const std::string &waiting_title, auto *dialog = new WaitingDialog(QString::fromStdString(waiting_title), parent); - auto *process_task = - new Thread::Task(std::move(func), std::move(callback), data_object); + auto *process_task = new Thread::Task(std::move(func), waiting_title, + data_object, std::move(callback)); - QApplication::connect(process_task, &Thread::Task::SignalTaskFinished, dialog, + QApplication::connect(process_task, &Thread::Task::SignalTaskEnd, dialog, &QDialog::close); QEventLoop looper; - QApplication::connect(process_task, &Thread::Task::SignalTaskFinished, - &looper, &QEventLoop::quit); + QApplication::connect(process_task, &Thread::Task::SignalTaskEnd, &looper, + &QEventLoop::quit); // post process task to task runner Thread::TaskRunnerGetter::GetInstance() @@ -148,8 +148,6 @@ CommonUtils *CommonUtils::GetInstance() { } CommonUtils::CommonUtils() : QWidget(nullptr) { - LOG(INFO) << "common utils created"; - connect(CoreCommonUtil::GetInstance(), &CoreCommonUtil::SignalGnupgNotInstall, this, &CommonUtils::SignalGnupgNotInstall); connect(this, &CommonUtils::SignalKeyStatusUpdated, @@ -158,6 +156,9 @@ CommonUtils::CommonUtils() : QWidget(nullptr) { connect(this, &CommonUtils::SignalKeyDatabaseRefreshDone, SignalStation::GetInstance(), &SignalStation::SignalKeyDatabaseRefreshDone); + connect(this, &CommonUtils::SignalUserInputPassphraseDone, + CoreSignalStation::GetInstance(), + &CoreSignalStation::SignalUserInputPassphraseDone); // directly connect to SignalKeyStatusUpdated // to avoid the delay of signal emitting @@ -166,6 +167,10 @@ CommonUtils::CommonUtils() : QWidget(nullptr) { &SignalStation::SignalKeyDatabaseRefresh, this, &CommonUtils::slot_update_key_status); + connect(CoreSignalStation::GetInstance(), + &CoreSignalStation::SignalNeedUserInputPassphrase, this, + &CommonUtils::slot_popup_passphrase_input_dialog); + connect(this, &CommonUtils::SignalGnupgNotInstall, this, []() { QMessageBox::critical( nullptr, _("ENV Loading Failed"), @@ -213,6 +218,38 @@ void CommonUtils::SlotImportKeyFromClipboard(QWidget *parent) { cb->text(QClipboard::Clipboard).toUtf8().toStdString()); } +void CommonUtils::SlotExecuteCommand( + const std::string &cmd, const QStringList &arguments, + const std::function<void(QProcess *)> &interact_func) { + QEventLoop looper; + auto *cmd_process = new QProcess(&looper); + cmd_process->setProcessChannelMode(QProcess::MergedChannels); + + connect(cmd_process, + qOverload<int, QProcess::ExitStatus>(&QProcess::finished), &looper, + &QEventLoop::quit); + connect(cmd_process, &QProcess::errorOccurred, &looper, &QEventLoop::quit); + connect(cmd_process, &QProcess::started, + []() -> void { SPDLOG_DEBUG("process started"); }); + connect(cmd_process, &QProcess::readyReadStandardOutput, + [interact_func, cmd_process]() { interact_func(cmd_process); }); + connect(cmd_process, &QProcess::errorOccurred, this, + [=]() -> void { SPDLOG_ERROR("error in process"); }); + connect(cmd_process, + qOverload<int, QProcess::ExitStatus>(&QProcess::finished), this, + [=](int, QProcess::ExitStatus status) { + if (status == QProcess::NormalExit) + SPDLOG_DEBUG("succeed in executing command: {}", cmd); + else + SPDLOG_WARN("error in executing command: {}", cmd); + }); + + cmd_process->setProgram(QString::fromStdString(cmd)); + cmd_process->setArguments(arguments); + cmd_process->start(); + looper.exec(); +} + void CommonUtils::SlotExecuteGpgCommand( const QStringList &arguments, const std::function<void(QProcess *)> &interact_func) { @@ -230,11 +267,11 @@ void CommonUtils::SlotExecuteGpgCommand( &WaitingDialog::deleteLater); connect(gpg_process, &QProcess::errorOccurred, &looper, &QEventLoop::quit); connect(gpg_process, &QProcess::started, - []() -> void { LOG(ERROR) << "Gpg Process Started Success"; }); + []() -> void { SPDLOG_DEBUG("gpg process started"); }); connect(gpg_process, &QProcess::readyReadStandardOutput, [interact_func, gpg_process]() { interact_func(gpg_process); }); connect(gpg_process, &QProcess::errorOccurred, this, [=]() -> void { - LOG(ERROR) << "Error in Process"; + SPDLOG_ERROR("Error in Process"); dialog->close(); QMessageBox::critical(nullptr, _("Failure"), _("Failed to execute command.")); @@ -251,7 +288,8 @@ void CommonUtils::SlotExecuteGpgCommand( _("Finished executing command.")); }); - gpg_process->setProgram(GpgContext::GetInstance().GetInfo().AppPath.c_str()); + gpg_process->setProgram( + GpgContext::GetInstance().GetInfo(false).AppPath.c_str()); gpg_process->setArguments(arguments); gpg_process->start(); looper.exec(); @@ -283,10 +321,10 @@ void CommonUtils::SlotImportKeyFromKeyServer( target_keyserver = key_server_list[target_key_server_index].get<std::string>(); - LOG(INFO) << _("Set target Key Server to default Key Server") - << target_keyserver; + SPDLOG_DEBUG("set target key server to default Key Server: {}", + target_keyserver); } catch (...) { - LOG(ERROR) << _("Cannot read default_keyserver From Settings"); + SPDLOG_ERROR(_("Cannot read default_keyserver From Settings")); QMessageBox::critical( nullptr, _("Default Keyserver Not Found"), _("Cannot read default keyserver from your settings, " @@ -307,7 +345,7 @@ void CommonUtils::SlotImportKeyFromKeyServer( target_keyserver_url.scheme() + "://" + target_keyserver_url.host() + "/pks/lookup?op=get&search=0x" + key_id.c_str() + "&options=mr"); - LOG(INFO) << "request url" << req_url.toString().toStdString(); + SPDLOG_DEBUG("request url: {}", req_url.toString().toStdString()); // Waiting for reply QNetworkReply *reply = network_manager->get(QNetworkRequest(req_url)); @@ -360,21 +398,39 @@ void CommonUtils::SlotImportKeyFromKeyServer( } void CommonUtils::slot_update_key_status() { - LOG(INFO) << "called"; - - 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(); - } - return 0; - }); - connect(refresh_task, &Thread::Task::SignalTaskFinished, this, - &CommonUtils::SignalKeyDatabaseRefreshDone); + 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(); + } + return 0; + }, + "update_key_database_task"); + connect(refresh_task, &Thread::Task::SignalTaskEnd, this, + &CommonUtils::SignalKeyDatabaseRefreshDone, + Qt::BlockingQueuedConnection); // post the task to the default task runner Thread::TaskRunnerGetter::GetInstance().GetTaskRunner()->PostTask( refresh_task); } +void CommonUtils::slot_popup_passphrase_input_dialog() { + auto *dialog = new QInputDialog(QApplication::activeWindow(), Qt::Dialog); + dialog->setModal(true); + dialog->setWindowTitle(_("Password Input Dialog")); + dialog->setInputMode(QInputDialog::TextInput); + dialog->setTextEchoMode(QLineEdit::Password); + dialog->setLabelText(_("Please Input The Password")); + dialog->resize(500, 80); + dialog->exec(); + + QString password = dialog->textValue(); + dialog->deleteLater(); + + // send signal + emit SignalUserInputPassphraseDone(password); +} + } // namespace GpgFrontend::UI
\ No newline at end of file diff --git a/src/ui/UserInterfaceUtils.h b/src/ui/UserInterfaceUtils.h index bcfa28d2..7761de7b 100644 --- a/src/ui/UserInterfaceUtils.h +++ b/src/ui/UserInterfaceUtils.h @@ -163,6 +163,18 @@ class CommonUtils : public QWidget { */ void SignalKeyDatabaseRefreshDone(); + /** + * @brief + * + */ + void SignalNeedUserInputPassphrase(); + + /** + * @brief + * + */ + void SignalUserInputPassphraseDone(QString passphrase); + public slots: /** * @brief @@ -214,6 +226,15 @@ class CommonUtils : public QWidget { const QStringList& arguments, const std::function<void(QProcess*)>& interact_func); + /** + * @brief + * + * @param arguments + * @param interact_func + */ + void SlotExecuteCommand(const std::string& cmd, const QStringList& arguments, + const std::function<void(QProcess*)>& interact_func); + private slots: /** @@ -222,6 +243,12 @@ class CommonUtils : public QWidget { */ void slot_update_key_status(); + /** + * @brief + * + */ + void slot_popup_passphrase_input_dialog(); + private: static std::unique_ptr<CommonUtils> instance_; ///< }; diff --git a/src/ui/dialog/GeneralDialog.cpp b/src/ui/dialog/GeneralDialog.cpp index 6fd2f32c..9367aa44 100644 --- a/src/ui/dialog/GeneralDialog.cpp +++ b/src/ui/dialog/GeneralDialog.cpp @@ -39,8 +39,6 @@ GpgFrontend::UI::GeneralDialog::~GeneralDialog() = default; void GpgFrontend::UI::GeneralDialog::slot_restore_settings() noexcept { try { - LOG(INFO) << name_ << _("Called"); - SettingsObject general_windows_state(name_ + "_dialog_state"); bool window_save = general_windows_state.Check("window_save", true); @@ -60,8 +58,6 @@ void GpgFrontend::UI::GeneralDialog::slot_restore_settings() noexcept { size_ = {width, height}; if (this->parent() != nullptr) { - LOG(INFO) << "parent address" << this->parent(); - QPoint parent_pos = {0, 0}; QSize parent_size = {0, 0}; @@ -83,14 +79,13 @@ void GpgFrontend::UI::GeneralDialog::slot_restore_settings() noexcept { parent_size = parent_window->size(); } - LOG(INFO) << "parent pos x:" << parent_pos.x() - << "y:" << parent_pos.y(); + SPDLOG_DEBUG("parent pos x: {} y: {}", parent_pos.x(), parent_pos.y()); - LOG(INFO) << "parent size width:" << parent_size.width() - << "height:" << parent_size.height(); + SPDLOG_DEBUG("parent size width: {} height: {}", parent_size.width(), + parent_size.height()); - LOG(INFO) << "this dialog size width:" << size_.width() - << "height:" << size_.height(); + SPDLOG_DEBUG("this dialog size width: {} height: {}", size_.width(), + size_.height()); if (parent_pos != QPoint{0, 0}) { QPoint parent_center{parent_pos.x() + parent_size.width() / 2, @@ -110,14 +105,12 @@ void GpgFrontend::UI::GeneralDialog::slot_restore_settings() noexcept { } } catch (...) { - LOG(ERROR) << name_ << "error"; + SPDLOG_ERROR(name_, "error"); } } void GpgFrontend::UI::GeneralDialog::slot_save_settings() noexcept { try { - LOG(INFO) << name_ << _("Called"); - SettingsObject general_windows_state(name_ + "_dialog_state"); // window position and size @@ -132,7 +125,7 @@ void GpgFrontend::UI::GeneralDialog::slot_save_settings() noexcept { general_windows_state["window_save"] = true; } catch (...) { - LOG(ERROR) << name_ << "error"; + SPDLOG_ERROR(name_, "error"); } } @@ -142,8 +135,8 @@ void GpgFrontend::UI::GeneralDialog::setPosCenterOfScreen() { int screen_width = geo.width(); int screen_height = geo.height(); - LOG(INFO) << "primary screen available geometry" << screen_width - << screen_height; + SPDLOG_DEBUG("primary screen available geometry", screen_width, + screen_height); pos_ = QPoint((screen_width - QWidget::width()) / 2, (screen_height - QWidget::height()) / 2); @@ -155,13 +148,13 @@ void GpgFrontend::UI::GeneralDialog::setPosCenterOfScreen() { * */ void GpgFrontend::UI::GeneralDialog::movePosition2CenterOfParent() { - LOG(INFO) << "parent pos x:" << parent_pos_.x() << "y:" << parent_pos_.y(); + SPDLOG_DEBUG("parent pos x: {} y: {}", parent_pos_.x(), parent_pos_.y()); - LOG(INFO) << "parent size width:" << parent_size_.width() - << "height:" << parent_size_.height(); + SPDLOG_DEBUG("parent size width: {}", parent_size_.width(), + "height:", parent_size_.height()); if (parent_pos_ != QPoint{0, 0} && parent_size_ != QSize{0, 0}) { - LOG(INFO) << "update current dialog position now"; + SPDLOG_DEBUG("update current dialog position now"); QPoint parent_center{parent_pos_.x() + parent_size_.width() / 2, parent_pos_.y() + parent_size_.height() / 2}; diff --git a/src/ui/dialog/WaitingDialog.cpp b/src/ui/dialog/WaitingDialog.cpp index a4412e57..afdd55b8 100644 --- a/src/ui/dialog/WaitingDialog.cpp +++ b/src/ui/dialog/WaitingDialog.cpp @@ -57,8 +57,8 @@ WaitingDialog::WaitingDialog(const QString& title, QWidget* parent) int screen_width = geo.width(); int screen_height = geo.height(); - LOG(INFO) << "primary screen available geometry" << screen_width - << screen_height; + SPDLOG_DEBUG("primary screen available geometry: {} {}", screen_width, + screen_height); auto pos = QPoint((screen_width - QWidget::width()) / 2, (screen_height - QWidget::height()) / 2); @@ -67,7 +67,7 @@ WaitingDialog::WaitingDialog(const QString& title, QWidget* parent) } else { auto pos = QPoint(parent->x() + (parent->width() - QWidget::width()) / 2, parent->y() + (parent->height() - QWidget::height()) / 2); - LOG(INFO) << "pos" << pos.x() << pos.y(); + SPDLOG_DEBUG("pos: {} {}", pos.x(), pos.y()); this->move(pos); } diff --git a/src/ui/dialog/Wizard.cpp b/src/ui/dialog/Wizard.cpp index 0f051874..57aefcfb 100644 --- a/src/ui/dialog/Wizard.cpp +++ b/src/ui/dialog/Wizard.cpp @@ -52,7 +52,7 @@ Wizard::Wizard(QWidget* parent) : QWizard(parent) { try { next_page_id = settings.lookup("wizard.next_page"); } catch (...) { - LOG(ERROR) << _("Setting Operation Error"); + SPDLOG_ERROR("setting operation error"); } setStartId(next_page_id); @@ -60,7 +60,6 @@ Wizard::Wizard(QWidget* parent) : QWizard(parent) { } void Wizard::slot_wizard_accepted() { - LOG(INFO) << _("Called"); // Don't show is mapped to show -> negation try { auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); @@ -75,7 +74,7 @@ void Wizard::slot_wizard_accepted() { } GlobalSettingStation::GetInstance().SyncSettings(); } catch (...) { - LOG(ERROR) << _("Setting Operation Error"); + SPDLOG_ERROR("setting operation error"); } if (field("openHelp").toBool()) { emit SignalOpenHelp("docu.html#content"); @@ -223,7 +222,6 @@ KeyGenPage::KeyGenPage(QWidget* parent) : QWizardPage(parent) { int KeyGenPage::nextId() const { return Wizard::Page_Conclusion; } void KeyGenPage::slot_generate_key_dialog() { - LOG(INFO) << "Try Opening KeyGenDialog"; (new KeyGenDialog(this))->show(); wizard()->next(); } diff --git a/src/ui/dialog/details/VerifyDetailsDialog.cpp b/src/ui/dialog/details/VerifyDetailsDialog.cpp index d2af4ee1..307d404a 100644 --- a/src/ui/dialog/details/VerifyDetailsDialog.cpp +++ b/src/ui/dialog/details/VerifyDetailsDialog.cpp @@ -65,7 +65,11 @@ void VerifyDetailsDialog::slot_refresh() { // Get timestamp of signature of current text QDateTime timestamp; +#ifdef GPGFRONTEND_GUI_QT6 + timestamp.setSecsSinceEpoch(sign->timestamp); +#else timestamp.setTime_t(sign->timestamp); +#endif // Set the title widget depending on sign status if (gpg_err_code(sign->status) == GPG_ERR_BAD_SIGNATURE) { diff --git a/src/ui/dialog/help/AboutDialog.cpp b/src/ui/dialog/help/AboutDialog.cpp index 6b6e4356..3cf6c2a2 100644 --- a/src/ui/dialog/help/AboutDialog.cpp +++ b/src/ui/dialog/help/AboutDialog.cpp @@ -52,7 +52,7 @@ AboutDialog::AboutDialog(int defaultIndex, QWidget* parent) tab_widget->addTab(update_tab_, _("Update")); connect(tab_widget, &QTabWidget::currentChanged, this, - [&](int index) { LOG(INFO) << "Current Index" << index; }); + [&](int index) { SPDLOG_DEBUG("current index: {}", index); }); if (defaultIndex < tab_widget->count() && defaultIndex >= 0) { tab_widget->setCurrentIndex(defaultIndex); @@ -66,7 +66,7 @@ AboutDialog::AboutDialog(int defaultIndex, QWidget* parent) mainLayout->addWidget(buttonBox); setLayout(mainLayout); - this->resize(450, 580); + this->resize(550, 650); this->setMinimumWidth(450); this->show(); } @@ -95,7 +95,9 @@ InfoTab::InfoTab(QWidget* parent) : QWidget(parent) { _("or send a mail to my mailing list at") + " <a " + "href=\"mailto:[email protected]\">[email protected]</a>." + "<br><br> " + _("Built with Qt") + " " + qVersion() + " " + _("and GPGME") + " " + - GpgFrontend::GpgContext::GetInstance().GetInfo().GpgMEVersion.c_str() + + GpgFrontend::GpgContext::GetInstance() + .GetInfo(false) + .GpgMEVersion.c_str() + "<br>" + _("Built at") + " " + BUILD_TIMESTAMP + "</center>"); auto* layout = new QGridLayout(); @@ -201,7 +203,7 @@ UpdateTab::UpdateTab(QWidget* parent) : QWidget(parent) { void UpdateTab::getLatestVersion() { this->pb_->setHidden(false); - LOG(INFO) << _("try to get latest version"); + SPDLOG_DEBUG("try to get latest version"); auto* version_task = new VersionCheckTask(); diff --git a/src/ui/dialog/help/GnupgTab.cpp b/src/ui/dialog/help/GnupgTab.cpp index 9d783367..2758cbe1 100644 --- a/src/ui/dialog/help/GnupgTab.cpp +++ b/src/ui/dialog/help/GnupgTab.cpp @@ -31,103 +31,104 @@ #include "GnupgTab.h" -#include "easylogging++.h" +#include <shared_mutex> + +#include "ui/UserInterfaceUtils.h" #include "ui_GnuPGInfo.h" GpgFrontend::UI::GnupgTab::GnupgTab(QWidget* parent) - : QWidget(parent), - ui_(std::make_shared<Ui_GnuPGInfo>()), - gpgconf_process_(new QProcess(this)) { - GpgContext& ctx = GpgContext::GetInstance(); - auto info = ctx.GetInfo(); - + : QWidget(parent), ui_(std::make_shared<Ui_GnuPGInfo>()) { ui_->setupUi(this); - QStringList column_titles; - column_titles << _("Name") << _("Description") << _("Version") << _("Path"); + QStringList components_column_titles; + components_column_titles << _("Name") << _("Description") << _("Version") + << _("Checksum") << _("Path"); + + ui_->componentDetailsTable->setColumnCount(components_column_titles.length()); + ui_->componentDetailsTable->setHorizontalHeaderLabels( + components_column_titles); + ui_->componentDetailsTable->horizontalHeader()->setStretchLastSection(false); + ui_->componentDetailsTable->setSelectionBehavior( + QAbstractItemView::SelectRows); + + QStringList configurations_column_titles; + configurations_column_titles << _("Name") << _("Path"); - ui_->conponentDetailsTable->setColumnCount(column_titles.length()); - ui_->conponentDetailsTable->setHorizontalHeaderLabels(column_titles); - ui_->conponentDetailsTable->horizontalHeader()->setStretchLastSection(false); - ui_->conponentDetailsTable->setSelectionBehavior( + ui_->configurationDetailsTable->setColumnCount( + configurations_column_titles.length()); + ui_->configurationDetailsTable->setHorizontalHeaderLabels( + configurations_column_titles); + ui_->configurationDetailsTable->horizontalHeader()->setStretchLastSection( + false); + ui_->configurationDetailsTable->setSelectionBehavior( QAbstractItemView::SelectRows); // tableitems not editable - ui_->conponentDetailsTable->setEditTriggers( + ui_->componentDetailsTable->setEditTriggers( QAbstractItemView::NoEditTriggers); // no focus (rectangle around tableitems) // may be it should focus on whole row - ui_->conponentDetailsTable->setFocusPolicy(Qt::NoFocus); - ui_->conponentDetailsTable->setAlternatingRowColors(true); + ui_->componentDetailsTable->setFocusPolicy(Qt::NoFocus); + ui_->componentDetailsTable->setAlternatingRowColors(true); - gpgconf_process_->start(QString::fromStdString(info.GpgConfPath), - QStringList() << "--list-components"); - - connect(gpgconf_process_, - qOverload<int, QProcess::ExitStatus>(&QProcess::finished), this, - &GnupgTab::process_components_info); + process_software_info(); } -void GpgFrontend::UI::GnupgTab::process_components_info( - int exit_code, QProcess::ExitStatus exit_status) { - LOG(INFO) << "called"; +void GpgFrontend::UI::GnupgTab::process_software_info() { + auto& ctx_info = GpgContext::GetInstance().GetInfo(); + + ui_->gnupgVersionLabel->setText(QString::fromStdString( + fmt::format("Version: {}", ctx_info.GnupgVersion))); - GpgContext& ctx = GpgContext::GetInstance(); - auto info = ctx.GetInfo(); + ui_->componentDetailsTable->setRowCount(ctx_info.ComponentsInfo.size()); - std::vector<std::vector<std::string>> components_info = { - {"gpgme", "GPG Made Easy", info.GpgMEVersion, "/"}, - {"gpgconf", "GPG Configure", "/", info.GpgConfPath}, + int row = 0; + for (const auto& info : ctx_info.ComponentsInfo) { + if (info.second.size() != 4) continue; - }; + auto* tmp0 = new QTableWidgetItem(QString::fromStdString(info.first)); + tmp0->setTextAlignment(Qt::AlignCenter); + ui_->componentDetailsTable->setItem(row, 0, tmp0); - if (gpgconf_process_ != nullptr) { - QString data = gpgconf_process_->readAllStandardOutput(); + auto* tmp1 = new QTableWidgetItem(QString::fromStdString(info.second[0])); + tmp1->setTextAlignment(Qt::AlignCenter); + ui_->componentDetailsTable->setItem(row, 1, tmp1); - std::vector<std::string> line_split_list; - boost::split(line_split_list, data.toStdString(), boost::is_any_of("\n")); + auto* tmp2 = new QTableWidgetItem(QString::fromStdString(info.second[1])); + tmp2->setTextAlignment(Qt::AlignCenter); + ui_->componentDetailsTable->setItem(row, 2, tmp2); - for (const auto& line : line_split_list) { - std::vector<std::string> info_split_list; - boost::split(info_split_list, line, boost::is_any_of(":")); - LOG(INFO) << "gpgconf info line" << line << "info size" - << info_split_list.size(); + auto* tmp3 = new QTableWidgetItem(QString::fromStdString(info.second[3])); + tmp3->setTextAlignment(Qt::AlignCenter); + ui_->componentDetailsTable->setItem(row, 3, tmp3); - if (info_split_list.size() != 3) continue; + auto* tmp4 = new QTableWidgetItem(QString::fromStdString(info.second[2])); + tmp4->setTextAlignment(Qt::AlignLeft); + ui_->componentDetailsTable->setItem(row, 4, tmp4); - if (info_split_list[0] == "gpg") { - components_info.push_back({info_split_list[0], info_split_list[1], - info.GnupgVersion, info_split_list[2]}); - } else { - components_info.push_back( - {info_split_list[0], info_split_list[1], "/", info_split_list[2]}); - } - } + row++; } - ui_->conponentDetailsTable->setRowCount(components_info.size()); + ui_->componentDetailsTable->resizeColumnsToContents(); - int row = 0; - for (const auto& info : components_info) { - if (info.size() != 4) continue; + ui_->configurationDetailsTable->setRowCount( + ctx_info.ConfigurationsInfo.size()); + + row = 0; + for (const auto& info : ctx_info.ConfigurationsInfo) { + if (info.second.size() != 1) continue; - auto* tmp0 = new QTableWidgetItem(QString::fromStdString(info[0])); + auto* tmp0 = new QTableWidgetItem(QString::fromStdString(info.first)); tmp0->setTextAlignment(Qt::AlignCenter); - ui_->conponentDetailsTable->setItem(row, 0, tmp0); + ui_->configurationDetailsTable->setItem(row, 0, tmp0); - auto* tmp1 = new QTableWidgetItem(QString::fromStdString(info[1])); + auto* tmp1 = new QTableWidgetItem(QString::fromStdString(info.second[0])); tmp1->setTextAlignment(Qt::AlignCenter); - ui_->conponentDetailsTable->setItem(row, 1, tmp1); - - auto* tmp2 = new QTableWidgetItem(QString::fromStdString(info[2])); - tmp2->setTextAlignment(Qt::AlignCenter); - ui_->conponentDetailsTable->setItem(row, 2, tmp2); - - auto* tmp3 = new QTableWidgetItem(QString::fromStdString(info[3])); - tmp3->setTextAlignment(Qt::AlignLeft); - ui_->conponentDetailsTable->setItem(row, 3, tmp3); + ui_->configurationDetailsTable->setItem(row, 1, tmp1); row++; } + + ui_->configurationDetailsTable->resizeColumnsToContents(); } diff --git a/src/ui/dialog/help/GnupgTab.h b/src/ui/dialog/help/GnupgTab.h index c143bae3..9195dee0 100644 --- a/src/ui/dialog/help/GnupgTab.h +++ b/src/ui/dialog/help/GnupgTab.h @@ -48,11 +48,9 @@ class GnupgTab : public QWidget { explicit GnupgTab(QWidget* parent = nullptr); private: - std::shared_ptr<Ui_GnuPGInfo> ui_; - QProcess* gpgconf_process_; + std::shared_ptr<Ui_GnuPGInfo> ui_; ///< - private slots: - void process_components_info(int, QProcess::ExitStatus); + void process_software_info(); }; } // namespace GpgFrontend::UI diff --git a/src/ui/dialog/import_export/KeyImportDetailDialog.cpp b/src/ui/dialog/import_export/KeyImportDetailDialog.cpp index 31183a34..e9b1af93 100644 --- a/src/ui/dialog/import_export/KeyImportDetailDialog.cpp +++ b/src/ui/dialog/import_export/KeyImportDetailDialog.cpp @@ -129,8 +129,6 @@ void KeyImportDetailDialog::create_general_info_box() { } void KeyImportDetailDialog::create_keys_table() { - LOG(INFO) << "KeyImportDetailDialog::create_keys_table() Called"; - keys_table_ = new QTableWidget(this); keys_table_->setRowCount(0); keys_table_->setColumnCount(4); diff --git a/src/ui/dialog/import_export/KeyServerImportDialog.cpp b/src/ui/dialog/import_export/KeyServerImportDialog.cpp index 6430a22e..713c5a58 100644 --- a/src/ui/dialog/import_export/KeyServerImportDialog.cpp +++ b/src/ui/dialog/import_export/KeyServerImportDialog.cpp @@ -28,6 +28,7 @@ #include "KeyServerImportDialog.h" +#include <QRegExp> #include <string> #include <utility> @@ -177,8 +178,7 @@ QComboBox* KeyServerImportDialog::create_comboBox() { comboBox->setCurrentText(default_key_server.c_str()); } catch (...) { - LOG(ERROR) << _("Setting Operation Error") << "server_list" - << "default_server"; + SPDLOG_ERROR("setting operation error", "server_list", "default_server"); } return comboBox; @@ -253,8 +253,7 @@ void KeyServerImportDialog::slot_search() { void KeyServerImportDialog::slot_search_finished( QNetworkReply::NetworkError error, QByteArray buffer) { - LOG(INFO) << "Called" << error << buffer.size(); - LOG(INFO) << buffer.toStdString(); + SPDLOG_DEBUG("search result {} {}", error, buffer.size()); keys_table_->clearContents(); keys_table_->setRowCount(0); @@ -262,7 +261,7 @@ void KeyServerImportDialog::slot_search_finished( auto stream = QTextStream(buffer); if (error != QNetworkReply::NoError) { - LOG(INFO) << "Error From Reply" << error; + SPDLOG_DEBUG("error from reply: {}", error); switch (error) { case QNetworkReply::ContentNotFoundError: @@ -364,8 +363,14 @@ void KeyServerImportDialog::slot_search_finished( uid->setText(line2[1]); keys_table_->setItem(row, 0, uid); } +#ifdef GPGFRONTEND_GUI_QT6 + auto* creation_date = + new QTableWidgetItem(QDateTime::fromSecsSinceEpoch(line[4].toInt()) + .toString("dd. MMM. yyyy")); +#else auto* creation_date = new QTableWidgetItem( QDateTime::fromTime_t(line[4].toInt()).toString("dd. MMM. yyyy")); +#endif keys_table_->setItem(row, 1, creation_date); auto* keyid = new QTableWidgetItem(line[1]); keys_table_->setItem(row, 2, keyid); @@ -440,8 +445,7 @@ void KeyServerImportDialog::SlotImport(const KeyIdArgsListPtr& keys) { target_keyserver = default_key_server; } catch (...) { - LOG(ERROR) << _("Setting Operation Error") << "server_list" - << "default_server"; + SPDLOG_ERROR("setting operation error", "server_list", "default_server"); QMessageBox::critical( nullptr, _("Default Keyserver Not Found"), _("Cannot read default keyserver from your settings, " @@ -470,10 +474,8 @@ void KeyServerImportDialog::SlotImport(std::vector<std::string> key_ids, void KeyServerImportDialog::slot_import_finished( QNetworkReply::NetworkError error, QByteArray buffer) { - LOG(INFO) << _("Called"); - if (error != QNetworkReply::NoError) { - LOG(ERROR) << "Error From Reply" << buffer.toStdString(); + SPDLOG_ERROR("Error From Reply", buffer.toStdString()); if (!m_automatic_) { switch (error) { case QNetworkReply::ContentNotFoundError: diff --git a/src/ui/dialog/import_export/KeyUploadDialog.cpp b/src/ui/dialog/import_export/KeyUploadDialog.cpp index ad4be0cb..5e05da2d 100644 --- a/src/ui/dialog/import_export/KeyUploadDialog.cpp +++ b/src/ui/dialog/import_export/KeyUploadDialog.cpp @@ -41,7 +41,6 @@ KeyUploadDialog::KeyUploadDialog(const KeyIdArgsListPtr& keys_ids, QWidget* parent) : GeneralDialog(typeid(KeyUploadDialog).name(), parent), m_keys_(GpgKeyGetter::GetInstance().GetKeys(keys_ids)) { - auto* pb = new QProgressBar(); pb->setRange(0, 0); pb->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); @@ -71,7 +70,6 @@ void KeyUploadDialog::SlotUpload() { void KeyUploadDialog::slot_upload_key_to_server( const GpgFrontend::ByteArray& keys_data) { - std::string target_keyserver; try { @@ -88,11 +86,11 @@ void KeyUploadDialog::slot_upload_key_to_server( target_keyserver = key_server_list[default_key_server_index].get<std::string>(); - LOG(INFO) << _("Set target Key Server to default Key Server") - << target_keyserver; + SPDLOG_DEBUG("set target key server to default key server: {}", + target_keyserver); } catch (...) { - LOG(ERROR) << _("Cannot read default_keyserver From Settings"); + SPDLOG_ERROR(_("Cannot read default_keyserver From Settings")); QMessageBox::critical(nullptr, _("Default Keyserver Not Found"), _("Cannot read default keyserver from your settings, " "please set a default keyserver first")); @@ -139,11 +137,11 @@ void KeyUploadDialog::slot_upload_finished() { auto* reply = qobject_cast<QNetworkReply*>(sender()); QByteArray response = reply->readAll(); - LOG(INFO) << "Response: " << response.toStdString(); + SPDLOG_DEBUG("response: {}", response.toStdString()); auto error = reply->error(); if (error != QNetworkReply::NoError) { - LOG(INFO) << "Error From Reply" << reply->errorString().toStdString(); + SPDLOG_DEBUG("error from reply: {}", reply->errorString().toStdString()); QString message; switch (error) { case QNetworkReply::ContentNotFoundError: @@ -163,7 +161,7 @@ void KeyUploadDialog::slot_upload_finished() { } else { QMessageBox::information(this, _("Upload Success"), _("Upload Public Key Successfully")); - LOG(INFO) << "Success while contacting keyserver!"; + SPDLOG_DEBUG("success while contacting keyserver!"); } reply->deleteLater(); } diff --git a/src/ui/dialog/key_generate/KeygenDialog.cpp b/src/ui/dialog/key_generate/KeygenDialog.cpp index b7ba6369..d6f61215 100644 --- a/src/ui/dialog/key_generate/KeygenDialog.cpp +++ b/src/ui/dialog/key_generate/KeygenDialog.cpp @@ -28,6 +28,7 @@ #include "KeygenDialog.h" +#include "core/common/CoreCommonUtil.h" #include "core/function/GlobalSettingStation.h" #include "core/function/gpg/GpgKeyOpera.h" #include "dialog/WaitingDialog.h" @@ -46,10 +47,10 @@ KeyGenDialog::KeyGenDialog(QWidget* parent) bool longer_expiration_date = false; try { longer_expiration_date = settings.lookup("general.longer_expiration_date"); - LOG(INFO) << "longer_expiration_date" << longer_expiration_date; + SPDLOG_DEBUG("longer_expiration_date: {}", longer_expiration_date); } catch (...) { - LOG(ERROR) << _("Setting Operation Error") << _("longer_expiration_date"); + SPDLOG_ERROR("setting operation error: longer_expiration_date"); } max_date_time_ = longer_expiration_date @@ -110,6 +111,10 @@ void KeyGenDialog::slot_key_gen_accept() { error_stream << " " << _("Expiration time too long.") << std::endl; } + if (passphrase_edit_->isEnabled() && passphrase_edit_->text().size() == 0) { + error_stream << " " << _("Password is empty.") << std::endl; + } + auto err_string = error_stream.str(); if (err_string.empty()) { @@ -125,8 +130,18 @@ void KeyGenDialog::slot_key_gen_accept() { if (expire_check_box_->checkState()) { gen_key_info_->SetNonExpired(true); } else { +#ifdef GPGFRONTEND_GUI_QT6 + gen_key_info_->SetExpireTime(boost::posix_time::from_time_t( + date_edit_->dateTime().toSecsSinceEpoch())); +#else gen_key_info_->SetExpireTime( boost::posix_time::from_time_t(date_edit_->dateTime().toTime_t())); +#endif + } + + if (!gen_key_info_->IsNoPassPhrase()) { + CoreCommonUtil::GetInstance()->SetTempCacheValue( + "__key_passphrase", this->passphrase_edit_->text().toStdString()); } GpgGenKeyResult result; @@ -145,7 +160,11 @@ void KeyGenDialog::slot_key_gen_accept() { dialog->close(); - LOG(INFO) << "generate done"; + if (!gen_key_info_->IsNoPassPhrase()) { + CoreCommonUtil::GetInstance()->ResetTempCacheValue("__key_passphrase"); + } + + SPDLOG_DEBUG("generate done"); if (gpgme_err_code(error) == GPG_ERR_NO_ERROR) { auto* msg_box = new QMessageBox((QWidget*)this->parent()); @@ -156,7 +175,7 @@ void KeyGenDialog::slot_key_gen_accept() { msg_box->setModal(true); msg_box->open(); - LOG(INFO) << "generate success"; + SPDLOG_DEBUG("generate success"); emit SignalKeyGenerated(); this->close(); @@ -252,7 +271,7 @@ void KeyGenDialog::slot_authentication_box_changed(int state) { } void KeyGenDialog::slot_activated_key_type(int index) { - qDebug() << "key type index changed " << index; + SPDLOG_DEBUG("key type index changed: {}", index); // check assert(gen_key_info_->GetSupportedKeyAlgo().size() > index); @@ -261,8 +280,6 @@ void KeyGenDialog::slot_activated_key_type(int index) { } void KeyGenDialog::refresh_widgets_state() { - qDebug() << "refresh_widgets_state called"; - if (gen_key_info_->IsAllowEncryption()) key_usage_check_boxes_[0]->setCheckState(Qt::CheckState::Checked); else @@ -337,11 +354,8 @@ void KeyGenDialog::set_signal_slot() { connect(no_pass_phrase_check_box_, &QCheckBox::stateChanged, this, [this](int state) -> void { - if (state == 0) { - gen_key_info_->SetNonPassPhrase(false); - } else { - gen_key_info_->SetNonPassPhrase(true); - } + gen_key_info_->SetNonPassPhrase(state != 0); + passphrase_edit_->setDisabled(state != 0); }); } @@ -356,6 +370,7 @@ QGroupBox* KeyGenDialog::create_basic_info_group_box() { comment_edit_ = new QLineEdit(this); key_size_spin_box_ = new QSpinBox(this); key_type_combo_box_ = new QComboBox(this); + passphrase_edit_ = new QLineEdit(this); for (auto& algo : GenKeyInfo::GetSupportedKeyAlgo()) { key_type_combo_box_->addItem(QString::fromStdString(algo.first)); @@ -375,6 +390,8 @@ QGroupBox* KeyGenDialog::create_basic_info_group_box() { expire_check_box_ = new QCheckBox(this); expire_check_box_->setCheckState(Qt::Unchecked); + passphrase_edit_->setEchoMode(QLineEdit::Password); + no_pass_phrase_check_box_ = new QCheckBox(this); no_pass_phrase_check_box_->setCheckState(Qt::Unchecked); @@ -387,7 +404,8 @@ QGroupBox* KeyGenDialog::create_basic_info_group_box() { vbox1->addWidget(new QLabel(QString(_("Never Expire")) + ": "), 3, 3); vbox1->addWidget(new QLabel(QString(_("KeySize (in Bit)")) + ": "), 4, 0); vbox1->addWidget(new QLabel(QString(_("Key Type")) + ": "), 5, 0); - vbox1->addWidget(new QLabel(QString(_("Non Pass Phrase")) + ": "), 6, 0); + vbox1->addWidget(new QLabel(QString(_("Password")) + ": "), 6, 0); + vbox1->addWidget(new QLabel(QString(_("Non Pass Phrase")) + ": "), 6, 3); vbox1->addWidget(name_edit_, 0, 1, 1, 3); vbox1->addWidget(email_edit_, 1, 1, 1, 3); @@ -396,7 +414,8 @@ QGroupBox* KeyGenDialog::create_basic_info_group_box() { vbox1->addWidget(expire_check_box_, 3, 2); vbox1->addWidget(key_size_spin_box_, 4, 1); vbox1->addWidget(key_type_combo_box_, 5, 1); - vbox1->addWidget(no_pass_phrase_check_box_, 6, 1); + vbox1->addWidget(passphrase_edit_, 6, 1); + vbox1->addWidget(no_pass_phrase_check_box_, 6, 2); auto basicInfoGroupBox = new QGroupBox(); basicInfoGroupBox->setLayout(vbox1); diff --git a/src/ui/dialog/key_generate/KeygenDialog.h b/src/ui/dialog/key_generate/KeygenDialog.h index baf10dbf..a1d7f39a 100644 --- a/src/ui/dialog/key_generate/KeygenDialog.h +++ b/src/ui/dialog/key_generate/KeygenDialog.h @@ -93,6 +93,7 @@ class KeyGenDialog : public GeneralDialog { QLineEdit* name_edit_{}; ///< Line edit for the keys name QLineEdit* email_edit_{}; ///< Line edit for the keys email QLineEdit* comment_edit_{}; ///< Line edit for the keys comment + QLineEdit* passphrase_edit_{}; ///< QSpinBox* key_size_spin_box_{}; ///< Spinbox for the keys size (in bit) QComboBox* key_type_combo_box_{}; ///< Combobox for Key type QDateTimeEdit* date_edit_{}; ///< Date edit for expiration date diff --git a/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp b/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp index afa768f0..50f38413 100644 --- a/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp +++ b/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp @@ -28,11 +28,12 @@ #include <cassert> +#include "core/common/CoreCommonUtil.h" #include "core/function/GlobalSettingStation.h" #include "core/function/gpg/GpgKeyGetter.h" #include "core/function/gpg/GpgKeyOpera.h" -#include "dialog/WaitingDialog.h" #include "ui/SignalStation.h" +#include "ui/dialog/WaitingDialog.h" namespace GpgFrontend::UI { @@ -45,10 +46,10 @@ SubkeyGenerateDialog::SubkeyGenerateDialog(const KeyId& key_id, QWidget* parent) bool longer_expiration_date = false; try { longer_expiration_date = settings.lookup("general.longer_expiration_date"); - LOG(INFO) << "longer_expiration_date" << longer_expiration_date; + SPDLOG_DEBUG("longer expiration date: {}", longer_expiration_date); } catch (...) { - LOG(ERROR) << _("Setting Operation Error") << _("longer_expiration_date"); + SPDLOG_ERROR("setting operation error: longer_expiration_date"); } max_date_time_ = longer_expiration_date @@ -60,15 +61,20 @@ SubkeyGenerateDialog::SubkeyGenerateDialog(const KeyId& key_id, QWidget* parent) key_usage_group_box_ = create_key_usage_group_box(); - auto* groupGrid = new QGridLayout(this); - groupGrid->addWidget(create_basic_info_group_box(), 0, 0); - groupGrid->addWidget(key_usage_group_box_, 1, 0); + auto* group_grid = new QGridLayout(this); + group_grid->addWidget(create_basic_info_group_box(), 0, 0); + group_grid->addWidget(key_usage_group_box_, 1, 0); - auto* nameList = new QWidget(this); - nameList->setLayout(groupGrid); + auto* tipps_label = new QLabel( + QString(_("Tipps: if the key pair has a passphrase, the subkey's " + "passphrase must be equal to it."))); + group_grid->addWidget(tipps_label); + + auto* name_list = new QWidget(this); + name_list->setLayout(group_grid); auto* vbox2 = new QVBoxLayout(); - vbox2->addWidget(nameList); + vbox2->addWidget(name_list); vbox2->addWidget(error_label_); vbox2->addWidget(button_box_); @@ -121,6 +127,8 @@ QGroupBox* SubkeyGenerateDialog::create_basic_info_group_box() { error_label_ = new QLabel(); key_size_spin_box_ = new QSpinBox(this); key_type_combo_box_ = new QComboBox(this); + no_pass_phrase_check_box_ = new QCheckBox(this); + passphrase_edit_ = new QLineEdit(this); for (auto& algo : GenKeyInfo::GetSupportedSubkeyAlgo()) { key_type_combo_box_->addItem(QString::fromStdString(algo.first)); @@ -142,15 +150,19 @@ QGroupBox* SubkeyGenerateDialog::create_basic_info_group_box() { auto* vbox1 = new QGridLayout; - vbox1->addWidget(new QLabel(QString(_("Expiration Date")) + ": "), 2, 0); - vbox1->addWidget(new QLabel(QString(_("Never Expire")) + ": "), 2, 3); - vbox1->addWidget(new QLabel(QString(_("KeySize (in Bit)")) + ": "), 1, 0); vbox1->addWidget(new QLabel(QString(_("Key Type")) + ": "), 0, 0); + vbox1->addWidget(new QLabel(QString(_("KeySize (in Bit)")) + ": "), 1, 0); + vbox1->addWidget(new QLabel(QString(_("Expiration Date")) + ": "), 2, 0); + vbox1->addWidget(new QLabel(QString(_("Never Expire"))), 2, 3); + vbox1->addWidget(new QLabel(QString(_("Password")) + ": "), 3, 0); + vbox1->addWidget(new QLabel(QString(_("Non Pass Phrase"))), 3, 3); + vbox1->addWidget(key_type_combo_box_, 0, 1); + vbox1->addWidget(key_size_spin_box_, 1, 1); vbox1->addWidget(date_edit_, 2, 1); vbox1->addWidget(expire_check_box_, 2, 2); - vbox1->addWidget(key_size_spin_box_, 1, 1); - vbox1->addWidget(key_type_combo_box_, 0, 1); + vbox1->addWidget(passphrase_edit_, 3, 1); + vbox1->addWidget(no_pass_phrase_check_box_, 3, 2); auto basicInfoGroupBox = new QGroupBox(); basicInfoGroupBox->setLayout(vbox1); @@ -179,6 +191,12 @@ void SubkeyGenerateDialog::set_signal_slot() { connect(key_type_combo_box_, qOverload<int>(&QComboBox::currentIndexChanged), this, &SubkeyGenerateDialog::slot_activated_key_type); + + connect(no_pass_phrase_check_box_, &QCheckBox::stateChanged, this, + [this](int state) -> void { + gen_key_info_->SetNonPassPhrase(state != 0); + passphrase_edit_->setDisabled(state != 0); + }); } void SubkeyGenerateDialog::slot_expire_box_changed() { @@ -190,8 +208,6 @@ void SubkeyGenerateDialog::slot_expire_box_changed() { } void SubkeyGenerateDialog::refresh_widgets_state() { - LOG(INFO) << "refresh_widgets_state called"; - if (gen_key_info_->IsAllowEncryption()) key_usage_check_boxes_[0]->setCheckState(Qt::CheckState::Checked); else @@ -249,6 +265,10 @@ void SubkeyGenerateDialog::slot_key_gen_accept() { err_stream << " " << _("Expiration time no more than 2 years.") << " "; } + if (passphrase_edit_->isEnabled() && passphrase_edit_->text().size() == 0) { + err_stream << " " << _("Password is empty.") << std::endl; + } + auto err_string = err_stream.str(); if (err_string.empty()) { @@ -257,13 +277,24 @@ void SubkeyGenerateDialog::slot_key_gen_accept() { if (expire_check_box_->checkState()) { gen_key_info_->SetNonExpired(true); } else { +#ifdef GPGFRONTEND_GUI_QT6 + gen_key_info_->SetExpireTime(boost::posix_time::from_time_t( + date_edit_->dateTime().toSecsSinceEpoch())); +#else gen_key_info_->SetExpireTime( boost::posix_time::from_time_t(date_edit_->dateTime().toTime_t())); +#endif + } + + if (!gen_key_info_->IsNoPassPhrase()) { + CoreCommonUtil::GetInstance()->SetTempCacheValue( + "__key_passphrase", this->passphrase_edit_->text().toStdString()); } GpgError error; + // TODO: remove plain qt thread usage auto thread = QThread::create([&]() { - LOG(INFO) << "Thread Started"; + SPDLOG_DEBUG("thread started"); error = GpgKeyOpera::GetInstance().GenerateSubkey(key_, gen_key_info_); }); thread->start(); @@ -276,6 +307,10 @@ void SubkeyGenerateDialog::slot_key_gen_accept() { } waiting_dialog->close(); + if (!gen_key_info_->IsNoPassPhrase()) { + CoreCommonUtil::GetInstance()->ResetTempCacheValue("__key_passphrase"); + } + if (check_gpg_error_2_err_code(error) == GPG_ERR_NO_ERROR) { auto* msg_box = new QMessageBox((QWidget*)this->parent()); msg_box->setAttribute(Qt::WA_DeleteOnClose); @@ -338,7 +373,7 @@ void SubkeyGenerateDialog::slot_authentication_box_changed(int state) { } void SubkeyGenerateDialog::slot_activated_key_type(int index) { - qDebug() << "key type index changed " << index; + SPDLOG_DEBUG("key type index changed: {}", index); // check assert(gen_key_info_->GetSupportedSubkeyAlgo().size() > index); diff --git a/src/ui/dialog/key_generate/SubkeyGenerateDialog.h b/src/ui/dialog/key_generate/SubkeyGenerateDialog.h index 1e6608b2..731bb951 100644 --- a/src/ui/dialog/key_generate/SubkeyGenerateDialog.h +++ b/src/ui/dialog/key_generate/SubkeyGenerateDialog.h @@ -69,6 +69,8 @@ class SubkeyGenerateDialog : public GeneralDialog { QComboBox* key_type_combo_box_{}; ///< Combobox for Key tpe QDateTimeEdit* date_edit_{}; ///< Date edit for expiration date QCheckBox* expire_check_box_{}; ///< Checkbox, if key should expire + QCheckBox* no_pass_phrase_check_box_{}; ///< Checkbox, if key should expire + QLineEdit* passphrase_edit_{}; std::vector<QCheckBox*> key_usage_check_boxes_; ///< ENCR, SIGN, CERT, AUTH QDateTime max_date_time_; ///< diff --git a/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp b/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp index b4d2d688..2785603b 100644 --- a/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp +++ b/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp @@ -35,8 +35,8 @@ namespace GpgFrontend::UI { KeyPairDetailTab::KeyPairDetailTab(const std::string& key_id, QWidget* parent) : QWidget(parent), key_(GpgKeyGetter::GetInstance().GetKey(key_id)) { - LOG(INFO) << key_.GetEmail() << key_.IsPrivateKey() << key_.IsHasMasterKey() - << key_.GetSubKeys()->front().IsPrivateKey(); + SPDLOG_DEBUG(key_.GetEmail(), key_.IsPrivateKey(), key_.IsHasMasterKey(), + key_.GetSubKeys()->front().IsPrivateKey()); owner_box_ = new QGroupBox(_("Owner")); key_box_ = new QGroupBox(_("Primary Key")); @@ -232,20 +232,35 @@ void KeyPairDetailTab::slot_refresh_key_info() { if (to_time_t(boost::posix_time::ptime(key_.GetExpireTime())) == 0) { expire_var_label_->setText(_("Never Expire")); } else { +#ifdef GPGFRONTEND_GUI_QT6 + expire_var_label_->setText(QLocale::system().toString( + QDateTime::fromSecsSinceEpoch(to_time_t(key_.GetExpireTime())))); +#else expire_var_label_->setText(QLocale::system().toString( QDateTime::fromTime_t(to_time_t(key_.GetExpireTime())))); +#endif } key_algo_val = key_.GetPublicKeyAlgo(); +#ifdef GPGFRONTEND_GUI_QT6 + created_var_label_->setText(QLocale::system().toString( + QDateTime::fromSecsSinceEpoch(to_time_t(key_.GetCreateTime())))); +#else created_var_label_->setText(QLocale::system().toString( QDateTime::fromTime_t(to_time_t(key_.GetCreateTime())))); +#endif if (to_time_t(boost::posix_time::ptime(key_.GetLastUpdateTime())) == 0) { last_update_var_label_->setText(_("No Data")); } else { +#ifdef GPGFRONTEND_GUI_QT6 + last_update_var_label_->setText(QLocale::system().toString( + QDateTime::fromSecsSinceEpoch(to_time_t(key_.GetLastUpdateTime())))); +#else last_update_var_label_->setText(QLocale::system().toString( QDateTime::fromTime_t(to_time_t(key_.GetLastUpdateTime())))); +#endif } key_size_var_label_->setText(key_size_val.c_str()); @@ -269,8 +284,6 @@ void KeyPairDetailTab::slot_refresh_key_info() { } void KeyPairDetailTab::slot_refresh_key() { - LOG(INFO) << _("called"); - // refresh the key GpgKey refreshed_key = GpgKeyGetter::GetInstance().GetKey(key_.GetId()); std::swap(this->key_, refreshed_key); diff --git a/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp b/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp index 77eba0bc..a1452033 100644 --- a/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp +++ b/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp @@ -296,7 +296,7 @@ void KeyPairOperaTab::slot_gen_revoke_cert() { // Code From Gpg4Win while (proc->canReadLine()) { const QString line = QString::fromUtf8(proc->readLine()).trimmed(); - LOG(INFO) << "line" << line.toStdString(); + SPDLOG_DEBUG("line: {}", line.toStdString()); if (line == QLatin1String("[GNUPG:] GET_BOOL gen_revoke.okay")) { proc->write("y\n"); } else if (line == QLatin1String("[GNUPG:] GET_LINE " @@ -336,7 +336,7 @@ void KeyPairOperaTab::slot_modify_tofu_policy() { this, _("Modify TOFU Policy(Default is Auto)"), _("Policy for the Key Pair:"), items, 0, false, &ok); if (ok && !item.isEmpty()) { - LOG(INFO) << "selected policy" << item.toStdString(); + SPDLOG_DEBUG("selected policy: {}", item.toStdString()); gpgme_tofu_policy_t tofu_policy = GPGME_TOFU_POLICY_AUTO; if (item == _("Policy Auto")) { tofu_policy = GPGME_TOFU_POLICY_AUTO; diff --git a/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp b/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp index be67e5ca..d1367541 100644 --- a/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp +++ b/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp @@ -35,8 +35,8 @@ namespace GpgFrontend::UI { KeyPairSubkeyTab::KeyPairSubkeyTab(const std::string& key_id, QWidget* parent) : QWidget(parent), key_(GpgKeyGetter::GetInstance().GetKey(key_id)) { - LOG(INFO) << key_.GetEmail() << key_.IsPrivateKey() << key_.IsHasMasterKey() - << key_.GetSubKeys()->front().IsPrivateKey(); + SPDLOG_DEBUG(key_.GetEmail(), key_.IsPrivateKey(), key_.IsHasMasterKey(), + key_.GetSubKeys()->front().IsPrivateKey()); create_subkey_list(); create_subkey_opera_menu(); @@ -165,7 +165,6 @@ void KeyPairSubkeyTab::create_subkey_list() { } void KeyPairSubkeyTab::slot_refresh_subkey_list() { - LOG(INFO) << "called"; int row = 0; subkey_list_->setSelectionMode(QAbstractItemView::SingleSelection); @@ -177,9 +176,8 @@ void KeyPairSubkeyTab::slot_refresh_subkey_list() { this->buffered_subkeys_.push_back(std::move(sub_key)); } - LOG(INFO) << "buffered_subkeys_" - << "refreshed" - << "size" << this->buffered_subkeys_.size(); + SPDLOG_DEBUG("buffered_subkeys_ refreshed size", + this->buffered_subkeys_.size()); subkey_list_->setRowCount(buffered_subkeys_.size()); @@ -216,20 +214,16 @@ void KeyPairSubkeyTab::slot_refresh_subkey_list() { } } - LOG(INFO) << "subkey_list_ item" << row << "refreshed"; + SPDLOG_DEBUG("subkey_list_ item {} refreshed", row); row++; } - LOG(INFO) << "subkey_list_" - << "refreshed"; + SPDLOG_DEBUG("subkey_list_ refreshed"); if (subkey_list_->rowCount() > 0) { subkey_list_->selectRow(0); } - - LOG(INFO) << "slot_refresh_subkey_list" - << "ended"; } void KeyPairSubkeyTab::slot_add_subkey() { @@ -246,10 +240,18 @@ void KeyPairSubkeyTab::slot_refresh_subkey_detail() { time_t subkey_time_t = boost::posix_time::to_time_t( boost::posix_time::ptime(subkey.GetExpireTime())); +#ifdef GPGFRONTEND_GUI_QT6 + expire_var_label_->setText( + subkey_time_t == 0 + ? _("Never Expires") + : QLocale::system().toString(QDateTime::fromSecsSinceEpoch( + to_time_t(subkey.GetExpireTime())))); +#else expire_var_label_->setText( subkey_time_t == 0 ? _("Never Expires") : QLocale::system().toString(QDateTime::fromTime_t( to_time_t(subkey.GetExpireTime())))); +#endif if (subkey_time_t != 0 && subkey.GetExpireTime() < boost::posix_time::second_clock::local_time()) { auto paletteExpired = expire_var_label_->palette(); @@ -262,8 +264,13 @@ void KeyPairSubkeyTab::slot_refresh_subkey_detail() { } algorithm_var_label_->setText(QString::fromStdString(subkey.GetPubkeyAlgo())); +#ifdef GPGFRONTEND_GUI_QT6 + created_var_label_->setText(QLocale::system().toString( + QDateTime::fromSecsSinceEpoch(to_time_t(subkey.GetCreateTime())))); +#else created_var_label_->setText(QLocale::system().toString( QDateTime::fromTime_t(to_time_t(subkey.GetCreateTime())))); +#endif std::stringstream usage_steam; @@ -318,7 +325,7 @@ void KeyPairSubkeyTab::create_subkey_opera_menu() { } void KeyPairSubkeyTab::slot_edit_subkey() { - LOG(INFO) << "Fpr" << get_selected_subkey().GetFingerprint(); + SPDLOG_DEBUG("fpr {}", get_selected_subkey().GetFingerprint()); auto dialog = new KeySetExpireDateDialog( key_.GetId(), get_selected_subkey().GetFingerprint(), this); @@ -344,7 +351,6 @@ const GpgSubKey& KeyPairSubkeyTab::get_selected_subkey() { return buffered_subkeys_[row]; } void KeyPairSubkeyTab::slot_refresh_key_info() { - LOG(INFO) << "called"; key_ = GpgKeyGetter::GetInstance().GetKey(key_.GetId()); } diff --git a/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp b/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp index caa4e3be..d55e44d8 100644 --- a/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp +++ b/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp @@ -225,7 +225,7 @@ void KeyPairUIDTab::slot_refresh_tofu_info() { continue; } auto tofu_infos = uid.GetTofuInfos(); - LOG(INFO) << "tofu info size" << tofu_infos->size(); + SPDLOG_DEBUG("tofu info size: {}", tofu_infos->size()); if (tofu_infos->empty()) { tofu_tabs_->hide(); } else { @@ -277,17 +277,30 @@ void KeyPairUIDTab::slot_refresh_sig_list() { new QTableWidgetItem(QString::fromStdString(sig.GetEmail())); sig_list_->setItem(sigRow, 2, tmp3); } - +#ifdef GPGFRONTEND_GUI_QT6 + auto* tmp4 = new QTableWidgetItem(QLocale::system().toString( + QDateTime::fromSecsSinceEpoch(to_time_t(sig.GetCreateTime())))); +#else auto* tmp4 = new QTableWidgetItem(QLocale::system().toString( QDateTime::fromTime_t(to_time_t(sig.GetCreateTime())))); +#endif sig_list_->setItem(sigRow, 3, tmp4); +#ifdef GPGFRONTEND_GUI_QT6 + auto* tmp5 = new QTableWidgetItem( + boost::posix_time::to_time_t( + boost::posix_time::ptime(sig.GetExpireTime())) == 0 + ? _("Never Expires") + : QLocale::system().toString(QDateTime::fromSecsSinceEpoch( + to_time_t(sig.GetExpireTime())))); +#else auto* tmp5 = new QTableWidgetItem( boost::posix_time::to_time_t( boost::posix_time::ptime(sig.GetExpireTime())) == 0 ? _("Never Expires") : QLocale::system().toString( QDateTime::fromTime_t(to_time_t(sig.GetExpireTime())))); +#endif tmp5->setTextAlignment(Qt::AlignCenter); sig_list_->setItem(sigRow, 4, tmp5); @@ -382,7 +395,7 @@ void KeyPairUIDTab::slot_del_uid() { if (ret == QMessageBox::Yes) { for (const auto& uid : *selected_uids) { - LOG(INFO) << "KeyPairUIDTab::slot_del_uid UID" << uid; + SPDLOG_DEBUG("uid: {}", uid); if (!GpgUIDOperator::GetInstance().RevUID(m_key_, uid)) { QMessageBox::critical( nullptr, _("Operation Failed"), @@ -574,8 +587,6 @@ void KeyPairUIDTab::slot_del_sign() { } } void KeyPairUIDTab::slot_refresh_key() { - LOG(INFO) << "called"; - // refresh the key GpgKey refreshed_key = GpgKeyGetter::GetInstance().GetKey(m_key_.GetId()); std::swap(this->m_key_, refreshed_key); diff --git a/src/ui/dialog/keypair_details/KeySetExpireDateDialog.cpp b/src/ui/dialog/keypair_details/KeySetExpireDateDialog.cpp index 2c10b895..d09662e1 100644 --- a/src/ui/dialog/keypair_details/KeySetExpireDateDialog.cpp +++ b/src/ui/dialog/keypair_details/KeySetExpireDateDialog.cpp @@ -57,16 +57,23 @@ KeySetExpireDateDialog::KeySetExpireDateDialog(const KeyId& key_id, } void KeySetExpireDateDialog::slot_confirm() { - LOG(INFO) << "Called" << ui_->dateEdit->date().toString().toStdString() - << ui_->timeEdit->time().toString().toStdString(); + SPDLOG_DEBUG("called: {} {}", ui_->dateEdit->date().toString().toStdString(), + ui_->timeEdit->time().toString().toStdString()); auto datetime = QDateTime(ui_->dateEdit->date(), ui_->timeEdit->time()); std::unique_ptr<boost::posix_time::ptime> expires = nullptr; if (ui_->noExpirationCheckBox->checkState() == Qt::Unchecked) { +#ifdef GPGFRONTEND_GUI_QT6 + expires = std::make_unique<boost::posix_time::ptime>( + boost::posix_time::from_time_t( + datetime.toLocalTime().toSecsSinceEpoch())); +#else expires = std::make_unique<boost::posix_time::ptime>( boost::posix_time::from_time_t(datetime.toLocalTime().toTime_t())); - LOG(INFO) << "keyid" << m_key_.GetId() << m_subkey_ << *expires; +#endif + SPDLOG_DEBUG("keyid: {}", m_key_.GetId(), m_subkey_, + to_iso_string(*expires)); } else { - LOG(INFO) << "keyid" << m_key_.GetId() << m_subkey_ << "Non Expired"; + SPDLOG_DEBUG("keyid: {}", m_key_.GetId(), m_subkey_, "Non Expired"); } auto err = GpgKeyOpera::GetInstance().SetExpire(m_key_, m_subkey_, expires); @@ -98,10 +105,10 @@ void KeySetExpireDateDialog::init() { bool longer_expiration_date = false; try { longer_expiration_date = settings.lookup("general.longer_expiration_date"); - LOG(INFO) << "longer_expiration_date" << longer_expiration_date; + SPDLOG_DEBUG("longer_expiration_date: {}", longer_expiration_date); } catch (...) { - LOG(ERROR) << _("Setting Operation Error") << _("longer_expiration_date"); + SPDLOG_ERROR("setting operation error: longer_expiration_date"); } auto max_date_time = @@ -115,8 +122,13 @@ void KeySetExpireDateDialog::init() { ui_->dateEdit->setMinimumDateTime(min_date_time); // set default date time to expire date time +#ifdef GPGFRONTEND_GUI_QT6 + auto current_expire_time = + QDateTime::fromSecsSinceEpoch(to_time_t(m_key_.GetExpireTime())); +#else auto current_expire_time = QDateTime::fromTime_t(to_time_t(m_key_.GetExpireTime())); +#endif ui_->dateEdit->setDateTime(current_expire_time); ui_->timeEdit->setDateTime(current_expire_time); diff --git a/src/ui/dialog/keypair_details/KeyUIDSignDialog.cpp b/src/ui/dialog/keypair_details/KeyUIDSignDialog.cpp index 0f7de587..ca83dbfd 100644 --- a/src/ui/dialog/keypair_details/KeyUIDSignDialog.cpp +++ b/src/ui/dialog/keypair_details/KeyUIDSignDialog.cpp @@ -104,19 +104,23 @@ KeyUIDSignDialog::KeyUIDSignDialog(const GpgKey& key, UIDArgsListPtr uid, } void KeyUIDSignDialog::slot_sign_key(bool clicked) { - LOG(INFO) << "Called"; - // Set Signers auto key_ids = m_key_list_->GetChecked(); auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids); - LOG(INFO) << "Key Info Got"; + SPDLOG_DEBUG("key info got"); +#ifdef GPGFRONTEND_GUI_QT6 + auto expires = + std::make_unique<boost::posix_time::ptime>(boost::posix_time::from_time_t( + expires_edit_->dateTime().toSecsSinceEpoch())); +#else auto expires = std::make_unique<boost::posix_time::ptime>( boost::posix_time::from_time_t(expires_edit_->dateTime().toTime_t())); +#endif - LOG(INFO) << "Sign Start"; + SPDLOG_DEBUG("sign start"); for (const auto& uid : *m_uids_) { - LOG(INFO) << "Sign UID" << uid; + SPDLOG_DEBUG("sign uid: {}", uid); // Sign For mKey if (!GpgKeyManager::GetInstance().SignKey(m_key_, *keys, uid, expires)) { QMessageBox::critical( diff --git a/src/ui/dialog/settings/SettingsAdvanced.cpp b/src/ui/dialog/settings/SettingsAdvanced.cpp index 516d4d02..e10b5dd1 100644 --- a/src/ui/dialog/settings/SettingsAdvanced.cpp +++ b/src/ui/dialog/settings/SettingsAdvanced.cpp @@ -60,7 +60,7 @@ void AdvancedTab::SetSettings() { bool stegano_checked = settings.lookup("advanced.stegano_checked"); if (stegano_checked) stegano_check_box_->setCheckState(Qt::Checked); } catch (...) { - LOG(ERROR) << _("Setting Operation Error") << _("stegano_checked"); + SPDLOG_ERROR("setting operation error: stegano_checked"); } try { @@ -69,8 +69,7 @@ void AdvancedTab::SetSettings() { if (auto_pubkey_exchange_checked) auto_pubkey_exchange_check_box_->setCheckState(Qt::Checked); } catch (...) { - LOG(ERROR) << _("Setting Operation Error") - << _("auto_pubkey_exchange_checked"); + SPDLOG_ERROR("setting operation error: auto_pubkey_exchange_checked"); } } diff --git a/src/ui/dialog/settings/SettingsDialog.cpp b/src/ui/dialog/settings/SettingsDialog.cpp index 6737a512..d484207a 100644 --- a/src/ui/dialog/settings/SettingsDialog.cpp +++ b/src/ui/dialog/settings/SettingsDialog.cpp @@ -108,19 +108,17 @@ void SettingsDialog::slot_set_restart_needed(int mode) { } void SettingsDialog::SlotAccept() { - LOG(INFO) << "Called"; - general_tab_->ApplySettings(); appearance_tab_->ApplySettings(); key_server_tab_->ApplySettings(); network_tab_->ApplySettings(); - LOG(INFO) << "apply done"; + SPDLOG_DEBUG("apply done"); // write settings to filesystem GlobalSettingStation::GetInstance().SyncSettings(); - LOG(INFO) << "restart needed" << get_restart_needed(); + SPDLOG_DEBUG("restart needed: {}", get_restart_needed()); if (get_restart_needed()) { emit SignalRestartNeeded(get_restart_needed()); } @@ -139,7 +137,7 @@ QHash<QString, QString> SettingsDialog::ListLanguages() { for (int i = 0; i < file_names.size(); ++i) { QString locale = file_names[i]; - LOG(INFO) << "locale" << locale.toStdString(); + SPDLOG_DEBUG("locale: {}", locale.toStdString()); if (locale == "." || locale == "..") continue; // this works in qt 4.8 diff --git a/src/ui/dialog/settings/SettingsGeneral.cpp b/src/ui/dialog/settings/SettingsGeneral.cpp index 680ed014..7e48b4e1 100644 --- a/src/ui/dialog/settings/SettingsGeneral.cpp +++ b/src/ui/dialog/settings/SettingsGeneral.cpp @@ -43,20 +43,26 @@ GeneralTab::GeneralTab(QWidget* parent) : QWidget(parent), ui_(std::make_shared<Ui_GeneralSettings>()) { ui_->setupUi(this); - ui_->saveCheckedKeysBox->setTitle(_("Save Checked Keys")); + ui_->cacheBox->setTitle(_("Cache")); ui_->saveCheckedKeysCheckBox->setText( _("Save checked private keys on exit and restore them on next start.")); - ui_->longerKeyExpirationDateBox->setTitle(_("Longer Key Expiration Date")); + ui_->clearGpgPasswordCacheCheckBox->setText( + "Clear gpg password cache when closing GpgFrontend."); + + ui_->importConfirmationBox->setTitle(_("Operation")); ui_->longerKeyExpirationDateCheckBox->setText( - _("Unlock key expiration date setting up to 30 years.")); - ui_->importConfirmationBox->setTitle(_("Confirm drag'n'drop key import")); + _("Enable to use longer key expiration date.")); ui_->importConfirmationCheckBox->setText( _("Import files dropped on the Key List without confirmation.")); - ui_->asciiModeBox->setTitle(_("ASCII Mode")); - ui_->asciiModeCheckBox->setText( - _("ASCII encoding is not used when file encrypting and " - "signing.")); + ui_->gnupgDatabaseBox->setTitle(_("GnuPG")); + ui_->asciiModeCheckBox->setText(_("No ASCII Mode")); + ui_->useCustomGnuPGInstallPathCheckBox->setText(_("Use Custom GnuPG")); + ui_->useCustomGnuPGInstallPathButton->setText(_("Select GnuPG Path")); + ui_->keyDatabseUseCustomCheckBox->setText( + _("Use Custom GnuPG Key Database Path")); + ui_->customKeyDatabasePathSelectButton->setText( + _("Select Key Database Path")); ui_->langBox->setTitle(_("Language")); ui_->langNoteLabel->setText( @@ -77,12 +83,23 @@ GeneralTab::GeneralTab(QWidget* parent) ui_->customKeyDatabasePathSelectButton->setDisabled( state != Qt::CheckState::Checked); // announce the restart - this->slot_key_databse_path_changed(); + this->slot_gnupg_stettings_changed(); + }); + + connect(ui_->useCustomGnuPGInstallPathCheckBox, &QCheckBox::stateChanged, + this, [=](int state) { + ui_->useCustomGnuPGInstallPathButton->setDisabled( + state != Qt::CheckState::Checked); + // announce the restart + this->slot_gnupg_stettings_changed(); }); connect(ui_->keyDatabseUseCustomCheckBox, &QCheckBox::stateChanged, this, &GeneralTab::slot_update_custom_key_database_path_label); + connect(ui_->useCustomGnuPGInstallPathCheckBox, &QCheckBox::stateChanged, + this, &GeneralTab::slot_update_custom_gnupg_install_path_label); + connect( ui_->customKeyDatabasePathSelectButton, &QPushButton::clicked, this, [=]() { @@ -91,8 +108,8 @@ GeneralTab::GeneralTab(QWidget* parent) this, _("Open Directory"), {}, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); - LOG(INFO) << "key databse path selected" - << selected_custom_key_database_path.toStdString(); + SPDLOG_DEBUG("key databse path selected: {}", + selected_custom_key_database_path.toStdString()); if (!selected_custom_key_database_path.isEmpty()) { auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); @@ -109,7 +126,7 @@ GeneralTab::GeneralTab(QWidget* parent) } // announce the restart - this->slot_key_databse_path_changed(); + this->slot_gnupg_stettings_changed(); // update ui this->slot_update_custom_key_database_path_label( @@ -117,6 +134,39 @@ GeneralTab::GeneralTab(QWidget* parent) } }); + connect( + ui_->useCustomGnuPGInstallPathButton, &QPushButton::clicked, this, [=]() { + QString selected_custom_gnupg_install_path = + QFileDialog::getExistingDirectory( + this, _("Open Directory"), {}, + QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + + SPDLOG_DEBUG("gnupg install path selected: {}", + selected_custom_gnupg_install_path.toStdString()); + + if (!selected_custom_gnupg_install_path.isEmpty()) { + auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); + auto& general = settings["general"]; + + // update settings + if (!general.exists("custom_gnupg_install_path")) + general.add("custom_gnupg_install_path", + libconfig::Setting::TypeString) = + selected_custom_gnupg_install_path.toStdString(); + else { + general["custom_gnupg_install_path"] = + selected_custom_gnupg_install_path.toStdString(); + } + + // announce the restart + this->slot_gnupg_stettings_changed(); + + // update ui + this->slot_update_custom_gnupg_install_path_label( + this->ui_->useCustomGnuPGInstallPathCheckBox->checkState()); + } + }); + SetSettings(); } @@ -132,24 +182,33 @@ void GeneralTab::SetSettings() { if (save_key_checked) ui_->saveCheckedKeysCheckBox->setCheckState(Qt::Checked); } catch (...) { - LOG(ERROR) << _("Setting Operation Error") << _("save_key_checked"); + SPDLOG_ERROR("setting operation error: save_key_checked"); + } + + try { + bool clear_gpg_password_cache = + settings.lookup("general.clear_gpg_password_cache"); + if (clear_gpg_password_cache) + ui_->clearGpgPasswordCacheCheckBox->setCheckState(Qt::Checked); + } catch (...) { + SPDLOG_ERROR("setting operation error: clear_gpg_password_cache"); } try { bool longer_expiration_date = settings.lookup("general.longer_expiration_date"); - LOG(INFO) << "longer_expiration_date" << longer_expiration_date; + SPDLOG_DEBUG("longer_expiration_date: {}", longer_expiration_date); if (longer_expiration_date) ui_->longerKeyExpirationDateCheckBox->setCheckState(Qt::Checked); } catch (...) { - LOG(ERROR) << _("Setting Operation Error") << _("longer_expiration_date"); + SPDLOG_ERROR("setting operation error: longer_expiration_date"); } #ifdef MULTI_LANG_SUPPORT try { std::string lang_key = settings.lookup("general.lang"); QString lang_value = lang_.value(lang_key.c_str()); - LOG(INFO) << "lang settings current" << lang_value.toStdString(); + SPDLOG_DEBUG("lang settings current: {}", lang_value.toStdString()); if (!lang_.empty()) { ui_->langSelectBox->setCurrentIndex( ui_->langSelectBox->findText(lang_value)); @@ -157,27 +216,27 @@ void GeneralTab::SetSettings() { ui_->langSelectBox->setCurrentIndex(0); } } catch (...) { - LOG(ERROR) << _("Setting Operation Error") << _("lang"); + SPDLOG_ERROR("setting operation error: lang"); } #endif try { bool confirm_import_keys = settings.lookup("general.confirm_import_keys"); - LOG(INFO) << "confirm_import_keys" << confirm_import_keys; + SPDLOG_DEBUG("confirm_import_keys: {}", confirm_import_keys); if (confirm_import_keys) ui_->importConfirmationCheckBox->setCheckState(Qt::Checked); } catch (...) { - LOG(ERROR) << _("Setting Operation Error") << _("confirm_import_keys"); + SPDLOG_ERROR("setting operation error: confirm_import_keys"); } try { bool non_ascii_when_export = settings.lookup("general.non_ascii_when_export"); - LOG(INFO) << "non_ascii_when_export" << non_ascii_when_export; + SPDLOG_DEBUG("non_ascii_when_export: {}", non_ascii_when_export); if (non_ascii_when_export) ui_->asciiModeCheckBox->setCheckState(Qt::Checked); } catch (...) { - LOG(ERROR) << _("Setting Operation Error") << _("non_ascii_when_export"); + SPDLOG_ERROR("setting operation error: non_ascii_when_export"); } try { @@ -186,12 +245,23 @@ void GeneralTab::SetSettings() { if (use_custom_key_database_path) ui_->keyDatabseUseCustomCheckBox->setCheckState(Qt::Checked); } catch (...) { - LOG(ERROR) << _("Setting Operation Error") - << _("use_custom_key_database_path"); + SPDLOG_ERROR("setting operation error: use_custom_key_database_path"); } this->slot_update_custom_key_database_path_label( ui_->keyDatabseUseCustomCheckBox->checkState()); + + try { + bool use_custom_gnupg_install_path = + settings.lookup("general.use_custom_gnupg_install_path"); + if (use_custom_gnupg_install_path) + ui_->useCustomGnuPGInstallPathCheckBox->setCheckState(Qt::Checked); + } catch (...) { + SPDLOG_ERROR("setting operation error: use_custom_gnupg_install_path"); + } + + this->slot_update_custom_gnupg_install_path_label( + ui_->useCustomGnuPGInstallPathCheckBox->checkState()); } /*********************************** @@ -223,6 +293,14 @@ void GeneralTab::ApplySettings() { general["save_key_checked"] = ui_->saveCheckedKeysCheckBox->isChecked(); } + if (!general.exists("clear_gpg_password_cache")) + general.add("clear_gpg_password_cache", libconfig::Setting::TypeBoolean) = + ui_->clearGpgPasswordCacheCheckBox->isChecked(); + else { + general["clear_gpg_password_cache"] = + ui_->saveCheckedKeysCheckBox->isChecked(); + } + if (!general.exists("non_ascii_when_export")) general.add("non_ascii_when_export", libconfig::Setting::TypeBoolean) = ui_->asciiModeCheckBox->isChecked(); @@ -256,6 +334,15 @@ void GeneralTab::ApplySettings() { general["use_custom_key_database_path"] = ui_->keyDatabseUseCustomCheckBox->isChecked(); } + + if (!general.exists("use_custom_gnupg_install_path")) + general.add("use_custom_gnupg_install_path", + libconfig::Setting::TypeBoolean) = + ui_->useCustomGnuPGInstallPathCheckBox->isChecked(); + else { + general["use_custom_gnupg_install_path"] = + ui_->useCustomGnuPGInstallPathCheckBox->isChecked(); + } } #ifdef MULTI_LANG_SUPPORT @@ -265,7 +352,7 @@ void GeneralTab::slot_language_changed() { emit SignalRestartNeeded(true); } void GeneralTab::slot_update_custom_key_database_path_label(int state) { if (state != Qt::CheckState::Checked) { ui_->currentKeyDatabasePathLabel->setText(QString::fromStdString( - GpgContext::GetInstance().GetInfo().DatabasePath)); + GpgContext::GetInstance().GetInfo(false).DatabasePath)); // hide label (not necessary to show the default path) this->ui_->currentKeyDatabasePathLabel->setHidden(true); @@ -279,27 +366,58 @@ void GeneralTab::slot_update_custom_key_database_path_label(int state) { settings.lookup("general.custom_key_database_path")); } catch (...) { - LOG(ERROR) << _("Setting Operation Error") - << _("custom_key_database_path"); + SPDLOG_ERROR("setting operation error: custom_key_database_path"); } - LOG(INFO) << "selected_custom_key_database_path from settings" - << custom_key_database_path; + SPDLOG_DEBUG("selected_custom_key_database_path from settings: {}", + custom_key_database_path); // set label value if (!custom_key_database_path.empty()) { ui_->currentKeyDatabasePathLabel->setText( QString::fromStdString(custom_key_database_path)); + this->ui_->currentKeyDatabasePathLabel->setHidden(false); } else { - ui_->currentKeyDatabasePathLabel->setText( - _("None custom key database path.")); + this->ui_->currentKeyDatabasePathLabel->setHidden(true); } + } +} - this->ui_->currentKeyDatabasePathLabel->setHidden(false); +void GeneralTab::slot_update_custom_gnupg_install_path_label(int state) { + if (state != Qt::CheckState::Checked) { + ui_->currentCustomGnuPGInstallPathLabel->setText(QString::fromStdString( + GpgContext::GetInstance().GetInfo(false).GnuPGHomePath)); + + // hide label (not necessary to show the default path) + this->ui_->currentCustomGnuPGInstallPathLabel->setHidden(true); + } else { + // read from settings file + std::string custom_gnupg_install_path; + try { + auto& settings = + GpgFrontend::GlobalSettingStation::GetInstance().GetUISettings(); + custom_gnupg_install_path = static_cast<std::string>( + settings.lookup("general.custom_gnupg_install_path")); + + } catch (...) { + SPDLOG_ERROR("setting operation error: custom_gnupg_install_path"); + } + + SPDLOG_DEBUG("custom_gnupg_install_path from settings: {}", + custom_gnupg_install_path); + + // set label value + if (!custom_gnupg_install_path.empty()) { + ui_->currentCustomGnuPGInstallPathLabel->setText( + QString::fromStdString(custom_gnupg_install_path)); + this->ui_->currentCustomGnuPGInstallPathLabel->setHidden(false); + } else { + this->ui_->currentCustomGnuPGInstallPathLabel->setHidden(true); + } } } -void GeneralTab::slot_key_databse_path_changed() { +void GeneralTab::slot_gnupg_stettings_changed() { emit SignalDeepRestartNeeded(true); } diff --git a/src/ui/dialog/settings/SettingsGeneral.h b/src/ui/dialog/settings/SettingsGeneral.h index 4543df7d..ecd2809e 100644 --- a/src/ui/dialog/settings/SettingsGeneral.h +++ b/src/ui/dialog/settings/SettingsGeneral.h @@ -109,7 +109,13 @@ class GeneralTab : public QWidget { * @brief * */ - void slot_key_databse_path_changed(); + void slot_update_custom_gnupg_install_path_label(int state); + + /** + * @brief + * + */ + void slot_gnupg_stettings_changed(); #endif }; diff --git a/src/ui/dialog/settings/SettingsKeyServer.cpp b/src/ui/dialog/settings/SettingsKeyServer.cpp index 365e19d4..8719ab9a 100644 --- a/src/ui/dialog/settings/SettingsKeyServer.cpp +++ b/src/ui/dialog/settings/SettingsKeyServer.cpp @@ -74,7 +74,7 @@ KeyserverTab::KeyserverTab(QWidget* parent) connect(ui_->keyServerListTable, &QTableWidget::itemChanged, [=](QTableWidgetItem* item) { - LOG(INFO) << "item edited" << item->column(); + SPDLOG_DEBUG("item edited: {}", item->column()); if (item->column() != 1) return; const auto row_size = ui_->keyServerListTable->rowCount(); // Update Actions @@ -137,7 +137,7 @@ void KeyserverTab::SetSettings() { key_server_str_list_.append(default_key_server.c_str()); default_key_server_ = QString::fromStdString(default_key_server); } catch (const std::exception& e) { - LOG(ERROR) << "Error reading key-server settings: " << e.what(); + SPDLOG_ERROR("Error reading key-server settings: ", e.what()); } } @@ -188,7 +188,7 @@ void KeyserverTab::ApplySettings() { } void KeyserverTab::slot_refresh_table() { - LOG(INFO) << "Start Refreshing Key Server Table"; + SPDLOG_INFO("start refreshing key server table"); ui_->keyServerListTable->blockSignals(true); ui_->keyServerListTable->setRowCount(key_server_str_list_.size()); @@ -273,7 +273,7 @@ void KeyserverTab::slot_test_listed_key_server() { waiting_dialog->setLabel(waiting_dialog_label); waiting_dialog->resize(420, 120); waiting_dialog->setModal(true); - connect(task, &Thread::Task::SignalTaskFinished, [=]() { + connect(task, &Thread::Task::SignalTaskEnd, [=]() { waiting_dialog->close(); waiting_dialog->deleteLater(); }); diff --git a/src/ui/dialog/settings/SettingsNetwork.cpp b/src/ui/dialog/settings/SettingsNetwork.cpp index d4edae42..fe3d450e 100644 --- a/src/ui/dialog/settings/SettingsNetwork.cpp +++ b/src/ui/dialog/settings/SettingsNetwork.cpp @@ -76,28 +76,28 @@ void GpgFrontend::UI::NetworkTab::SetSettings() { std::string proxy_host = settings.lookup("proxy.proxy_host"); ui_->proxyServerAddressEdit->setText(proxy_host.c_str()); } catch (...) { - LOG(ERROR) << _("Setting Operation Error") << _("proxy_host"); + SPDLOG_ERROR("setting operation error: proxy_host"); } try { std::string std_username = settings.lookup("proxy.username"); ui_->usernameEdit->setText(std_username.c_str()); } catch (...) { - LOG(ERROR) << _("Setting Operation Error") << _("username"); + SPDLOG_ERROR("setting operation error: username"); } try { std::string std_password = settings.lookup("proxy.password"); ui_->passwordEdit->setText(std_password.c_str()); } catch (...) { - LOG(ERROR) << _("Setting Operation Error") << _("password"); + SPDLOG_ERROR("setting operation error: password"); } try { int port = settings.lookup("proxy.port"); ui_->portSpin->setValue(port); } catch (...) { - LOG(ERROR) << _("Setting Operation Error") << _("port"); + SPDLOG_ERROR("setting operation error: port"); } ui_->proxyTypeComboBox->setCurrentText("HTTP"); @@ -105,7 +105,7 @@ void GpgFrontend::UI::NetworkTab::SetSettings() { std::string proxy_type = settings.lookup("proxy.proxy_type"); ui_->proxyTypeComboBox->setCurrentText(proxy_type.c_str()); } catch (...) { - LOG(ERROR) << _("Setting Operation Error") << _("proxy_type"); + SPDLOG_ERROR("setting operation error: proxy_type"); } switch_ui_proxy_type(ui_->proxyTypeComboBox->currentText()); @@ -117,7 +117,7 @@ void GpgFrontend::UI::NetworkTab::SetSettings() { else ui_->enableProxyCheckBox->setCheckState(Qt::Unchecked); } catch (...) { - LOG(ERROR) << _("Setting Operation Error") << _("proxy_enable"); + SPDLOG_ERROR("setting operation error: proxy_enable"); } { @@ -134,7 +134,7 @@ void GpgFrontend::UI::NetworkTab::SetSettings() { else ui_->forbidALLCheckBox->setCheckState(Qt::Unchecked); } catch (...) { - LOG(ERROR) << _("Setting Operation Error") << _("forbid_all_connection"); + SPDLOG_ERROR("setting operation error: forbid_all_connection"); } ui_->prohibitUpdateCheck->setCheckState(Qt::Unchecked); @@ -146,13 +146,11 @@ void GpgFrontend::UI::NetworkTab::SetSettings() { else ui_->prohibitUpdateCheck->setCheckState(Qt::Unchecked); } catch (...) { - LOG(ERROR) << _("Setting Operation Error") << _("prohibit_update_checking"); + SPDLOG_ERROR("setting operation error: prohibit_update_checking"); } } void GpgFrontend::UI::NetworkTab::ApplySettings() { - LOG(INFO) << "called"; - auto &settings = GpgFrontend::GlobalSettingStation::GetInstance().GetUISettings(); @@ -224,8 +222,6 @@ void GpgFrontend::UI::NetworkTab::ApplySettings() { } apply_proxy_settings(); - - LOG(INFO) << "done"; } void GpgFrontend::UI::NetworkTab::slot_test_proxy_connection_result() { @@ -270,7 +266,7 @@ void GpgFrontend::UI::NetworkTab::slot_test_proxy_connection_result() { waiting_dialog->deleteLater(); }); connect(waiting_dialog, &QProgressDialog::canceled, [=]() { - LOG(INFO) << "cancel clicked"; + SPDLOG_DEBUG("cancel clicked"); if (thread->isRunning()) thread->terminate(); }); diff --git a/src/ui/main_window/GeneralMainWindow.cpp b/src/ui/main_window/GeneralMainWindow.cpp index fb42d71a..66255a08 100644 --- a/src/ui/main_window/GeneralMainWindow.cpp +++ b/src/ui/main_window/GeneralMainWindow.cpp @@ -47,8 +47,6 @@ void GpgFrontend::UI::GeneralMainWindow::closeEvent(QCloseEvent *event) { void GpgFrontend::UI::GeneralMainWindow::slot_restore_settings() noexcept { try { - LOG(INFO) << name_ << _("Called"); - SettingsObject general_windows_state(name_ + "_state"); std::string window_state = general_windows_state.Check( @@ -75,7 +73,7 @@ void GpgFrontend::UI::GeneralMainWindow::slot_restore_settings() noexcept { size_ = {width, height}; if (this->parent() != nullptr) { - LOG(INFO) << "parent address" << this->parent(); + SPDLOG_DEBUG("parent address: {}", static_cast<void *>(this->parent())); QPoint parent_pos = {0, 0}; QSize parent_size = {0, 0}; @@ -92,11 +90,10 @@ void GpgFrontend::UI::GeneralMainWindow::slot_restore_settings() noexcept { parent_size = parent_window->size(); } - LOG(INFO) << "parent pos x:" << parent_pos.x() - << "y:" << parent_pos.y(); + SPDLOG_DEBUG("parent pos x: {} y: {}", parent_pos.x(), parent_pos.y()); - LOG(INFO) << "parent size width:" << parent_size.width() - << "height:" << parent_size.height(); + SPDLOG_DEBUG("parent size width: {} height: {}", parent_size.width(), + parent_size.height()); if (parent_pos != QPoint{0, 0}) { QPoint parent_center{parent_pos.x() + parent_size.width() / 2, @@ -116,7 +113,7 @@ void GpgFrontend::UI::GeneralMainWindow::slot_restore_settings() noexcept { int width = general_settings_state.Check("icon_size").Check("width", 24), height = general_settings_state.Check("icon_size").Check("height", 24); - LOG(INFO) << "icon_size" << width << height; + SPDLOG_DEBUG("icon size: {} {}", width, height); icon_size_ = {width, height}; font_size_ = general_settings_state.Check("font_size", 10); @@ -130,14 +127,12 @@ void GpgFrontend::UI::GeneralMainWindow::slot_restore_settings() noexcept { icon_style_ = toolButtonStyle(); } catch (...) { - LOG(ERROR) << name_ << "error"; + SPDLOG_ERROR(name_, "error"); } } void GpgFrontend::UI::GeneralMainWindow::slot_save_settings() noexcept { try { - LOG(INFO) << name_ << _("Called"); - SettingsObject general_windows_state(name_ + "_state"); // window position and size @@ -166,6 +161,6 @@ void GpgFrontend::UI::GeneralMainWindow::slot_save_settings() noexcept { general_settings_state["icon_style"] = this->toolButtonStyle(); } catch (...) { - LOG(ERROR) << name_ << "error"; + SPDLOG_ERROR(name_, "error"); } } diff --git a/src/ui/main_window/KeyMgmt.cpp b/src/ui/main_window/KeyMgmt.cpp index 9df2b918..9183d9d7 100644 --- a/src/ui/main_window/KeyMgmt.cpp +++ b/src/ui/main_window/KeyMgmt.cpp @@ -431,7 +431,7 @@ void KeyMgmt::SlotExportAsOpenSSHFormat() { } void KeyMgmt::SlotImportKeyPackage() { - LOG(INFO) << "Importing key package..."; + SPDLOG_INFO("Importing key package..."); auto key_package_file_name = QFileDialog::getOpenFileName( this, _("Import Key Package"), {}, @@ -445,7 +445,7 @@ void KeyMgmt::SlotImportKeyPackage() { GpgImportInformation info; - LOG(INFO) << "Importing key package: " << key_package_file_name.toStdString(); + SPDLOG_INFO("importing key package: {}", key_package_file_name.toStdString()); if (KeyPackageOperator::ImportKeyPackage(key_package_file_name.toStdString(), key_file_name.toStdString(), info)) { diff --git a/src/ui/main_window/MainWindow.cpp b/src/ui/main_window/MainWindow.cpp index b0273d86..fff3ab63 100644 --- a/src/ui/main_window/MainWindow.cpp +++ b/src/ui/main_window/MainWindow.cpp @@ -29,6 +29,7 @@ #include "MainWindow.h" #include "core/function/GlobalSettingStation.h" +#include "core/function/gpg/GpgAdvancedOperator.h" #include "ui/SignalStation.h" #include "ui/UserInterfaceUtils.h" #include "ui/struct/SettingsObject.h" @@ -108,7 +109,7 @@ void MainWindow::Init() noexcept { bool show_wizard = true; wizard.lookupValue("show_wizard", show_wizard); - LOG(INFO) << "wizard show_wizard" << show_wizard; + SPDLOG_DEBUG("wizard show_wizard: {}", show_wizard); if (show_wizard) { slot_start_wizard(); @@ -128,8 +129,31 @@ void MainWindow::Init() noexcept { ->PostTask(version_task); } + // before application exit + connect(qApp, &QCoreApplication::aboutToQuit, this, []() { + SPDLOG_DEBUG("about to quit process started"); + + auto &settings = GlobalSettingStation::GetInstance().GetUISettings(); + try { + bool clear_gpg_password_cache = + settings.lookup("general.clear_gpg_password_cache"); + + if (clear_gpg_password_cache) { + if (GpgFrontend::GpgAdvancedOperator::GetInstance() + .ClearGpgPasswordCache()) { + SPDLOG_DEBUG("clear gpg password cache done"); + } else { + SPDLOG_ERROR("clear gpg password cache error"); + } + } + + } catch (...) { + SPDLOG_ERROR("setting operation error: clear_gpg_password_cache"); + } + }); + } catch (...) { - LOG(FATAL) << _("Critical error occur while loading GpgFrontend."); + SPDLOG_ERROR(_("Critical error occur while loading GpgFrontend.")); QMessageBox::critical(nullptr, _("Loading Failed"), _("Critical error occur while loading GpgFrontend.")); QCoreApplication::quit(); @@ -138,10 +162,8 @@ void MainWindow::Init() noexcept { } void MainWindow::restore_settings() { - LOG(INFO) << _("Called"); - try { - LOG(INFO) << "restore settings key_server"; + SPDLOG_DEBUG("restore settings key_server"); SettingsObject key_server_json("key_server"); if (!key_server_json.contains("server_list") || @@ -177,7 +199,7 @@ void MainWindow::restore_settings() { import_button_->setToolButtonStyle(icon_style_); try { - LOG(INFO) << "restore settings default_key_checked"; + SPDLOG_DEBUG("restore settings default_key_checked"); // Checked Keys SettingsObject default_key_checked("default_key_checked"); @@ -185,13 +207,13 @@ void MainWindow::restore_settings() { auto key_ids_ptr = std::make_unique<KeyIdArgsList>(); for (auto &it : default_key_checked) { std::string key_id = it; - LOG(INFO) << "get checked key id" << key_id; + SPDLOG_DEBUG("get checked key id: {}", key_id); key_ids_ptr->push_back(key_id); } m_key_list_->SetChecked(std::move(key_ids_ptr)); } } catch (...) { - LOG(ERROR) << "restore default_key_checked failed"; + SPDLOG_ERROR("restore default_key_checked failed"); } prohibit_update_checking_ = false; @@ -199,16 +221,15 @@ void MainWindow::restore_settings() { prohibit_update_checking_ = settings.lookup("network.prohibit_update_checking"); } catch (...) { - LOG(ERROR) << _("Setting Operation Error") - << _("prohibit_update_checking"); + SPDLOG_ERROR("setting operation error: prohibit_update_checking"); } } catch (...) { - LOG(ERROR) << "cannot resolve settings"; + SPDLOG_ERROR("cannot resolve settings"); } GlobalSettingStation::GetInstance().SyncSettings(); - LOG(INFO) << _("settings restored"); + SPDLOG_DEBUG("settings restored"); } void MainWindow::save_settings() { @@ -230,7 +251,7 @@ void MainWindow::save_settings() { settings["general"].remove("save_key_checked"); } } catch (...) { - LOG(ERROR) << "cannot save settings"; + SPDLOG_ERROR("cannot save settings"); }; GlobalSettingStation::GetInstance().SyncSettings(); diff --git a/src/ui/main_window/MainWindow.h b/src/ui/main_window/MainWindow.h index 2e24cecd..e32a02ff 100644 --- a/src/ui/main_window/MainWindow.h +++ b/src/ui/main_window/MainWindow.h @@ -328,6 +328,7 @@ class MainWindow : public GeneralMainWindow { QMenu* file_menu_{}; ///< Submenu for file-operations QMenu* edit_menu_{}; ///< Submenu for text-operations QMenu* crypt_menu_{}; ///< Submenu for crypt-operations + QMenu* gpg_menu_{}; ///< Submenu for help-operations QMenu* help_menu_{}; ///< Submenu for help-operations QMenu* key_menu_{}; ///< Submenu for key-operations QMenu* view_menu_{}; ///< Submenu for view operations @@ -369,6 +370,10 @@ class MainWindow : public GeneralMainWindow { QAction* clean_double_line_breaks_act_{}; ///< Action to remove double line ///< breaks + QAction* clean_gpg_password_cache_act_{}; ///< + QAction* reload_components_act_{}; ///< + QAction* restart_components_act_{}; ///< + QAction* append_selected_keys_act_{}; ///< Action to append selected keys to edit QAction* copy_mail_address_to_clipboard_act_{}; ///< Action to copy mail to diff --git a/src/ui/main_window/MainWindowFileSlotFunction.cpp b/src/ui/main_window/MainWindowFileSlotFunction.cpp index 526c27c0..598ba33c 100644 --- a/src/ui/main_window/MainWindowFileSlotFunction.cpp +++ b/src/ui/main_window/MainWindowFileSlotFunction.cpp @@ -67,7 +67,7 @@ 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; + SPDLOG_DEBUG("converting directory into tarball: {}", path.u8string()); auto selected_dir_path = std::filesystem::path(path); if (selected_dir_path.extension() != ".tar") { @@ -81,8 +81,8 @@ bool process_tarball_into_directory(QWidget* parent, auto target_path = selected_dir_path; target_path.replace_extension(".tar"); - LOG(INFO) << "base path" << base_path.u8string() << "target archive path" - << target_path.u8string(); + SPDLOG_DEBUG("base path: {} target archive path: {]", base_path.u8string(), + target_path.u8string()); bool if_error = false; process_operation(parent, _("Extracting Tarball"), @@ -101,7 +101,7 @@ bool process_tarball_into_directory(QWidget* parent, } path = target_path.u8string().c_str(); } catch (...) { - LOG(ERROR) << "decompress error"; + SPDLOG_ERROR("decompress error"); return false; } return true; @@ -125,8 +125,9 @@ bool process_directory_into_tarball(QWidget* parent, QString& path) { auto target_path = selected_dir_path; selected_dir_path.replace_extension(""); - LOG(INFO) << "base path" << base_path << "target archive path" - << target_path << "selected_dir_path" << selected_dir_path; + SPDLOG_DEBUG("base path: {} target archive path: {} selected_dir_path: {}", + base_path.u8string(), target_path.u8string(), + selected_dir_path.u8string()); bool if_error = false; process_operation(parent, _("Making Tarball"), @@ -145,7 +146,7 @@ bool process_directory_into_tarball(QWidget* parent, QString& path) { } path = target_path.u8string().c_str(); } catch (...) { - LOG(ERROR) << "compress error"; + SPDLOG_ERROR("compress error"); return false; } return true; @@ -156,7 +157,7 @@ void MainWindow::SlotFileEncrypt() { auto path = fileTreeView->GetSelected(); if (!path_pre_check(this, path)) { - LOG(ERROR) << "path pre check failed"; + SPDLOG_ERROR("path pre check failed"); return; } @@ -172,7 +173,7 @@ void MainWindow::SlotFileEncrypt() { try { non_ascii_when_export = settings.lookup("general.non_ascii_when_export"); } catch (...) { - LOG(ERROR) << _("Setting Operation Error") << _("non_ascii_when_export"); + SPDLOG_ERROR("setting operation error: non_ascii_when_export"); } // get file info @@ -395,7 +396,7 @@ void MainWindow::SlotFileSign() { try { non_ascii_when_export = settings.lookup("general.non_ascii_when_export"); } catch (...) { - LOG(ERROR) << _("Setting Operation Error") << _("non_ascii_when_export"); + SPDLOG_ERROR("setting operation error: non_ascii_when_export"); } auto _channel = GPGFRONTEND_DEFAULT_CHANNEL; @@ -474,7 +475,7 @@ void MainWindow::SlotFileVerify() { try { non_ascii_when_export = settings.lookup("general.non_ascii_when_export"); } catch (...) { - LOG(ERROR) << _("Setting Operation Error") << _("non_ascii_when_export"); + SPDLOG_ERROR("setting operation error: non_ascii_when_export"); } auto _channel = GPGFRONTEND_DEFAULT_CHANNEL; @@ -488,7 +489,8 @@ void MainWindow::SlotFileVerify() { data_file_path = sign_file_path.parent_path() / sign_file_path.stem(); } - LOG(INFO) << "sign_file_path" << sign_file_path << sign_file_path.extension(); + SPDLOG_DEBUG("sign_file_path: {} {}", sign_file_path.u8string(), + sign_file_path.extension().u8string()); if (in_path.extension() != ".gpg") { bool ok; @@ -511,8 +513,8 @@ void MainWindow::SlotFileVerify() { return; } - DLOG(INFO) << "data path" << data_file_path; - DLOG(INFO) << "sign path" << sign_file_path; + SPDLOG_DEBUG("data path: {}", data_file_path.u8string()); + SPDLOG_DEBUG("sign path: {}", sign_file_path.u8string()); GpgVerifyResult result = nullptr; gpgme_error_t error; @@ -585,7 +587,7 @@ void MainWindow::SlotFileEncryptSign() { try { non_ascii_when_export = settings.lookup("general.non_ascii_when_export"); } catch (...) { - LOG(ERROR) << _("Setting Operation Error") << _("non_ascii_when_export"); + SPDLOG_ERROR("setting operation error: non_ascii_when_export"); } // get file info @@ -697,7 +699,7 @@ void MainWindow::SlotFileDecryptVerify() { } else { out_path += ".out"; } - LOG(INFO) << "out path" << out_path; + SPDLOG_DEBUG("out path: {}", out_path.u8string()); if (QFile::exists(out_path.u8string().c_str())) { auto ret = diff --git a/src/ui/main_window/MainWindowSlotFunction.cpp b/src/ui/main_window/MainWindowSlotFunction.cpp index f715046c..6f702e34 100644 --- a/src/ui/main_window/MainWindowSlotFunction.cpp +++ b/src/ui/main_window/MainWindowSlotFunction.cpp @@ -36,9 +36,10 @@ #include "core/function/gpg/GpgBasicOperator.h" #include "core/function/gpg/GpgKeyGetter.h" #include "core/function/gpg/GpgKeyImportExporter.h" +#include "dialog/SignersPicker.h" +#include "spdlog/spdlog.h" #include "ui/UserInterfaceUtils.h" #include "ui/dialog/help/AboutDialog.h" -#include "dialog/SignersPicker.h" namespace GpgFrontend::UI { /** @@ -341,7 +342,7 @@ void MainWindow::slot_verify() { auto buffer = data_object->PopObject<std::string>(); - LOG(INFO) << "Verify buffer: " << buffer.size(); + SPDLOG_DEBUG("verify buffer size: {}", buffer.size()); try { GpgVerifyResult verify_result = nullptr; @@ -430,11 +431,11 @@ void MainWindow::slot_encrypt_sign() { auto signer_keys = GpgKeyGetter::GetInstance().GetKeys(signer_key_ids); for (const auto& key : *keys) { - LOG(INFO) << "Keys " << key.GetEmail(); + SPDLOG_DEBUG("keys {}", key.GetEmail()); } for (const auto& signer : *signer_keys) { - LOG(INFO) << "Signers " << signer.GetEmail(); + SPDLOG_DEBUG("signers {}", signer.GetEmail()); } // data to transfer into task @@ -486,7 +487,6 @@ void MainWindow::slot_encrypt_sign() { auto sign_result = data_object->PopObject<GpgSignResult>(); auto tmp = data_object->PopObject<std::unique_ptr<ByteArray>>(); - LOG(INFO) << "GpgResultAnalyse Started"; auto encrypt_result_analyse = GpgEncryptResultAnalyse(error, std::move(encrypt_result)); auto sign_result_analyse = @@ -544,7 +544,7 @@ void MainWindow::slot_decrypt_verify() { data_object->AppendObject(std::move(decrypt_result)); data_object->AppendObject(std::move(error)); } catch (const std::runtime_error& e) { - LOG(ERROR) << e.what(); + SPDLOG_ERROR(e.what()); return -1; } return 0; @@ -660,13 +660,17 @@ void MainWindow::upload_key_to_server() { void MainWindow::SlotOpenFile(QString& path) { edit_->SlotOpenFile(path); } void MainWindow::slot_version_upgrade(const SoftwareVersion& version) { - LOG(INFO) << _("Called"); - - if (!version.InfoVaild()) { - LOG(INFO) << "Invalid version info"; + if (!version.InfoValid()) { + SPDLOG_ERROR("invalid version info"); return; } + SPDLOG_DEBUG( + "version info, need upgrade: {}, with drawn: {}, current version " + "released: {}", + version.NeedUpgrade(), version.VersionWithDrawn(), + version.CurrentVersionReleased()); + if (version.NeedUpgrade()) { statusBar()->showMessage( QString(_("GpgFrontend Upgradeable (New Version: %1).")) diff --git a/src/ui/main_window/MainWindowSlotUI.cpp b/src/ui/main_window/MainWindowSlotUI.cpp index 8961a33f..8839df4b 100644 --- a/src/ui/main_window/MainWindowSlotUI.cpp +++ b/src/ui/main_window/MainWindowSlotUI.cpp @@ -104,13 +104,11 @@ void MainWindow::slot_open_settings_dialog() { auto dialog = new SettingsDialog(this); connect(dialog, &SettingsDialog::finished, this, [&]() -> void { - LOG(INFO) << "Setting Dialog Finished"; - SettingsObject general_settings_state("general_settings_state"); int width = general_settings_state.Check("icon_size").Check("width", 24), height = general_settings_state.Check("icon_size").Check("height", 24); - LOG(INFO) << "icon_size" << width << height; + SPDLOG_DEBUG("icon_size: {} {}", width, height); general_settings_state.Check("info_font_size", 10); @@ -184,7 +182,7 @@ void MainWindow::slot_cut_pgp_header() { } void MainWindow::SlotSetRestartNeeded(int mode) { - LOG(INFO) << "restart mode" << mode; + SPDLOG_DEBUG("restart mode: {}", mode); this->restart_needed_ = mode; } @@ -192,7 +190,7 @@ int MainWindow::get_restart_needed() const { return this->restart_needed_; } void MainWindow::SetCryptoMenuStatus( MainWindow::CryptoMenu::OperationType type) { - LOG(INFO) << "SetCryptoMenuStatus" << type; + SPDLOG_DEBUG("type: {}", type); // refresh status to disable all verify_act_->setDisabled(true); diff --git a/src/ui/main_window/MainWindowUI.cpp b/src/ui/main_window/MainWindowUI.cpp index 1470b731..b9a01c15 100644 --- a/src/ui/main_window/MainWindowUI.cpp +++ b/src/ui/main_window/MainWindowUI.cpp @@ -27,6 +27,7 @@ */ #include "MainWindow.h" +#include "core/function/gpg/GpgAdvancedOperator.h" #include "ui/UserInterfaceUtils.h" namespace GpgFrontend::UI { @@ -37,8 +38,11 @@ void MainWindow::create_actions() { new_tab_act_ = new QAction(_("New"), this); new_tab_act_->setIcon(QIcon(":misc_doc.png")); QList<QKeySequence> newTabActShortcutList; - newTabActShortcutList.append(QKeySequence(Qt::CTRL + Qt::Key_N)); - newTabActShortcutList.append(QKeySequence(Qt::CTRL + Qt::Key_T)); +#ifdef GPGFRONTEND_GUI_QT6 + newTabActShortcutList.append(QKeySequence(Qt::CTRL | Qt::Key_N)); + newTabActShortcutList.append(QKeySequence(Qt::CTRL | Qt::Key_T)); +#else +#endif new_tab_act_->setShortcuts(newTabActShortcutList); new_tab_act_->setToolTip(_("Open a new file")); connect(new_tab_act_, &QAction::triggered, edit_, &TextEdit::SlotNewTab); @@ -51,7 +55,11 @@ void MainWindow::create_actions() { browser_act_ = new QAction(_("File Browser"), this); browser_act_->setIcon(QIcon(":file-browser.png")); +#ifdef GPGFRONTEND_GUI_QT6 + browser_act_->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_B)); +#else browser_act_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_B)); +#endif browser_act_->setToolTip(_("Open a file browser")); connect(browser_act_, &QAction::triggered, this, &MainWindow::slot_open_file_tab); @@ -164,41 +172,64 @@ void MainWindow::create_actions() { */ encrypt_act_ = new QAction(_("Encrypt"), this); encrypt_act_->setIcon(QIcon(":encrypted.png")); - encrypt_act_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_E)); +#ifdef GPGFRONTEND_GUI_QT6 + encrypt_act_->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_E)); +#else +#endif encrypt_act_->setToolTip(_("Encrypt Message")); connect(encrypt_act_, &QAction::triggered, this, &MainWindow::slot_encrypt); encrypt_sign_act_ = new QAction(_("Encrypt Sign"), this); encrypt_sign_act_->setIcon(QIcon(":encrypted_signed.png")); +#ifdef GPGFRONTEND_GUI_QT6 encrypt_sign_act_->setShortcut( - QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_E)); + QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_E)); +#else + encrypt_act_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_E)); +#endif encrypt_sign_act_->setToolTip(_("Encrypt and Sign Message")); connect(encrypt_sign_act_, &QAction::triggered, this, &MainWindow::slot_encrypt_sign); decrypt_act_ = new QAction(_("Decrypt"), this); decrypt_act_->setIcon(QIcon(":decrypted.png")); - decrypt_act_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_D)); +#ifdef GPGFRONTEND_GUI_QT6 + decrypt_act_->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_D)); +#else + encrypt_act_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_E)); +#endif decrypt_act_->setToolTip(_("Decrypt Message")); connect(decrypt_act_, &QAction::triggered, this, &MainWindow::slot_decrypt); decrypt_verify_act_ = new QAction(_("Decrypt Verify"), this); decrypt_verify_act_->setIcon(QIcon(":decrypted_verified.png")); +#ifdef GPGFRONTEND_GUI_QT6 decrypt_verify_act_->setShortcut( - QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_D)); + QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_D)); +#else + encrypt_act_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_E)); +#endif decrypt_verify_act_->setToolTip(_("Decrypt and Verify Message")); connect(decrypt_verify_act_, &QAction::triggered, this, &MainWindow::slot_decrypt_verify); sign_act_ = new QAction(_("Sign"), this); sign_act_->setIcon(QIcon(":signature.png")); - sign_act_->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_I)); +#ifdef GPGFRONTEND_GUI_QT6 + sign_act_->setShortcut(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_I)); +#else + encrypt_act_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_E)); +#endif sign_act_->setToolTip(_("Sign Message")); connect(sign_act_, &QAction::triggered, this, &MainWindow::slot_sign); verify_act_ = new QAction(_("Verify"), this); verify_act_->setIcon(QIcon(":verify.png")); - verify_act_->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_V)); +#ifdef GPGFRONTEND_GUI_QT6 + verify_act_->setShortcut(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_V)); +#else + encrypt_act_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_E)); +#endif verify_act_->setToolTip(_("Verify Message")); connect(verify_act_, &QAction::triggered, this, &MainWindow::slot_verify); @@ -241,6 +272,51 @@ void MainWindow::create_actions() { connect(open_key_management_act_, &QAction::triggered, this, &MainWindow::slot_open_key_management); + clean_gpg_password_cache_act_ = new QAction(_("Clear Password Cache"), this); + clean_gpg_password_cache_act_->setIcon(QIcon(":configure.png")); + clean_gpg_password_cache_act_->setToolTip(_("Clear Password Cache of GnuPG")); + connect(clean_gpg_password_cache_act_, &QAction::triggered, this, [=]() { + if (GpgFrontend::GpgAdvancedOperator::GetInstance() + .ClearGpgPasswordCache()) { + QMessageBox::information(this, _("Successful Operation"), + _("Clear password cache successfully")); + } else { + QMessageBox::critical(this, _("Failed Operation"), + _("Failed to clear password cache of GnuPG")); + } + }); + + reload_components_act_ = new QAction(_("Reload All Components"), this); + reload_components_act_->setIcon(QIcon(":configure.png")); + reload_components_act_->setToolTip(_("Reload All GnuPG's Components")); + connect(reload_components_act_, &QAction::triggered, this, [=]() { + if (GpgFrontend::GpgAdvancedOperator::GetInstance().ReloadGpgComponents()) { + QMessageBox::information( + this, _("Successful Operation"), + _("Reload all the GnuPG's components successfully")); + } else { + QMessageBox::critical( + this, _("Failed Operation"), + _("Failed to reload all or one of the GnuPG's component(s)")); + } + }); + + restart_components_act_ = new QAction(_("Restart All Components"), this); + restart_components_act_->setIcon(QIcon(":configure.png")); + restart_components_act_->setToolTip(_("Restart All GnuPG's Components")); + connect(restart_components_act_, &QAction::triggered, this, [=]() { + if (GpgFrontend::GpgAdvancedOperator::GetInstance() + .RestartGpgComponents()) { + QMessageBox::information( + this, _("Successful Operation"), + _("Restart all the GnuPG's components successfully")); + } else { + QMessageBox::critical( + this, _("Failed Operation"), + _("Failed to restart all or one of the GnuPG's component(s)")); + } + }); + /* * About Menu */ @@ -270,7 +346,7 @@ void MainWindow::create_actions() { check_update_act_->setIcon(QIcon(":help.png")); check_update_act_->setToolTip(_("Check for updates")); connect(check_update_act_, &QAction::triggered, this, - [=]() { new AboutDialog(2, this); }); + [=]() { new AboutDialog(3, this); }); start_wizard_act_ = new QAction(_("Open Wizard"), this); start_wizard_act_->setToolTip(_("Open the wizard")); @@ -372,6 +448,12 @@ void MainWindow::create_menus() { import_key_menu_->addAction(import_key_from_key_server_act_); key_menu_->addAction(open_key_management_act_); + gpg_menu_ = menuBar()->addMenu(_("GnuPG")); + gpg_menu_->addAction(clean_gpg_password_cache_act_); + gpg_menu_->addSeparator(); + gpg_menu_->addAction(reload_components_act_); + gpg_menu_->addAction(restart_components_act_); + steganography_menu_ = menuBar()->addMenu(_("Steganography")); steganography_menu_->addAction(cut_pgp_header_act_); steganography_menu_->addAction(add_pgp_header_act_); diff --git a/src/ui/struct/SettingsObject.cpp b/src/ui/struct/SettingsObject.cpp index 4a9aa7d6..d5230089 100644 --- a/src/ui/struct/SettingsObject.cpp +++ b/src/ui/struct/SettingsObject.cpp @@ -32,7 +32,7 @@ nlohmann::json& GpgFrontend::UI::SettingsObject::Check( const std::string& key, const nlohmann::json& default_value) { // check if the self null if (this->nlohmann::json::is_null()) { - LOG(INFO) << "SettingsObject is null, creating new one"; + SPDLOG_DEBUG("settings object is null, creating new one"); this->nlohmann::json::operator=(nlohmann::json::object()); } @@ -41,9 +41,9 @@ nlohmann::json& GpgFrontend::UI::SettingsObject::Check( this->nlohmann::json::at(key).is_null() || this->nlohmann::json::at(key).type_name() != default_value.type_name()) { - LOG(INFO) << "Added missing key: " << key; + SPDLOG_DEBUG("added missing key: {}", key); if (default_value.is_null()) { - LOG(WARNING) << "Default value is null, using empty object"; + SPDLOG_WARN("default value is null, using empty object"); this->nlohmann::json::operator[](key) = nlohmann::json::object(); } else { this->nlohmann::json::operator[](key) = default_value; @@ -51,7 +51,7 @@ nlohmann::json& GpgFrontend::UI::SettingsObject::Check( } return this->nlohmann::json::at(key); } catch (nlohmann::json::exception& e) { - LOG(ERROR) << e.what(); + SPDLOG_ERROR(e.what()); throw e; } } @@ -60,14 +60,14 @@ GpgFrontend::UI::SettingsObject GpgFrontend::UI::SettingsObject::Check( const std::string& key) { // check if the self null if (this->nlohmann::json::is_null()) { - LOG(INFO) << "SettingsObject is null, creating new one"; + SPDLOG_DEBUG("settings object is null, creating new one"); this->nlohmann::json::operator=(nlohmann::json::object()); } if (!nlohmann::json::contains(key) || this->nlohmann::json::at(key).is_null() || this->nlohmann::json::at(key).type() != nlohmann::json::value_t::object) { - LOG(INFO) << "Added missing key: " << key; + SPDLOG_DEBUG("added missing key: {}", key); this->nlohmann::json::operator[](key) = nlohmann::json::object(); } return SettingsObject{nlohmann::json::operator[](key), false}; @@ -76,21 +76,21 @@ GpgFrontend::UI::SettingsObject GpgFrontend::UI::SettingsObject::Check( GpgFrontend::UI::SettingsObject::SettingsObject(std::string settings_name) : settings_name_(std::move(settings_name)) { try { - LOG(INFO) << "Loading settings from: " << this->settings_name_; + SPDLOG_DEBUG("loading settings from: {}", this->settings_name_); auto _json_optional = GpgFrontend::DataObjectOperator::GetInstance().GetDataObject( settings_name_); if (_json_optional.has_value()) { - LOG(INFO) << "SettingsObject: " << settings_name_ << " loaded."; + SPDLOG_DEBUG("settings object: {} loaded.", settings_name_); nlohmann::json::operator=(_json_optional.value()); } else { - LOG(INFO) << "SettingsObject: " << settings_name_ << " not found."; + SPDLOG_DEBUG("settings object: {} not found.", settings_name_); nlohmann::json::operator=({}); } } catch (std::exception& e) { - LOG(ERROR) << e.what(); + SPDLOG_ERROR(e.what()); } } @@ -101,4 +101,4 @@ GpgFrontend::UI::SettingsObject::~SettingsObject() { if (!settings_name_.empty()) GpgFrontend::DataObjectOperator::GetInstance().SaveDataObj(settings_name_, *this); -} +}
\ No newline at end of file diff --git a/src/ui/struct/SoftwareVersion.cpp b/src/ui/struct/SoftwareVersion.cpp index ecccf7c0..6a60cb02 100644 --- a/src/ui/struct/SoftwareVersion.cpp +++ b/src/ui/struct/SoftwareVersion.cpp @@ -27,3 +27,75 @@ */ #include "SoftwareVersion.h" + +int GpgFrontend::UI::SoftwareVersion::version_compare(const std::string& a, + const std::string& b) { + auto temp_a = a, temp_b = b; + + if (!temp_a.empty() && temp_a.front() == 'v') { + temp_a = temp_a.erase(0, 1); + SPDLOG_DEBUG("real version a: {}", temp_a); + } + + if (!temp_b.empty() && temp_b.front() == 'v') { + temp_b.erase(0, 1); + SPDLOG_DEBUG("real version b: {}", temp_b); + } + + // First, split the string. + std::vector<std::string> va, vb; + boost::split(va, temp_a, boost::is_any_of(".")); + boost::split(vb, temp_b, boost::is_any_of(".")); + + // Compare the numbers step by step, but only as deep as the version + // with the least elements allows. + const int depth = + std::min(static_cast<int>(va.size()), static_cast<int>(vb.size())); + int ia = 0, ib = 0; + for (int i = 0; i < depth; ++i) { + try { + ia = boost::lexical_cast<int>(va[i]); + ib = boost::lexical_cast<int>(vb[i]); + } catch (boost::bad_lexical_cast& ignored) { + break; + } + if (ia != ib) break; + } + + // Return the required number. + if (ia > ib) + return 1; + else if (ia < ib) + return -1; + else { + // In case of equal versions, assumes that the version + // with the most elements is the highest version. + if (va.size() > vb.size()) + return 1; + else if (va.size() < vb.size()) + return -1; + } + + // Everything is equal, return 0. + return 0; +} + +bool GpgFrontend::UI::SoftwareVersion::NeedUpgrade() const { + SPDLOG_DEBUG("compair version current {} latest {}, result {}", + current_version, latest_version, + version_compare(current_version, latest_version)); + + SPDLOG_DEBUG("load done: {}, pre-release: {}, draft: {}", load_info_done, + latest_prerelease, latest_draft); + return load_info_done && !latest_prerelease && !latest_draft && + version_compare(current_version, latest_version) < 0; +} + +bool GpgFrontend::UI::SoftwareVersion::VersionWithDrawn() const { + return load_info_done && !current_version_found && current_prerelease && + !current_draft; +} + +bool GpgFrontend::UI::SoftwareVersion::CurrentVersionReleased() const { + return load_info_done && current_version_found; +}
\ No newline at end of file diff --git a/src/ui/struct/SoftwareVersion.h b/src/ui/struct/SoftwareVersion.h index da93f8c6..9d861ef1 100644 --- a/src/ui/struct/SoftwareVersion.h +++ b/src/ui/struct/SoftwareVersion.h @@ -54,7 +54,7 @@ struct SoftwareVersion { * @return true * @return false */ - [[nodiscard]] bool InfoVaild() const { return load_info_done; } + [[nodiscard]] bool InfoValid() const { return load_info_done; } /** * @brief @@ -62,10 +62,7 @@ struct SoftwareVersion { * @return true * @return false */ - [[nodiscard]] bool NeedUpgrade() const { - return load_info_done && !latest_prerelease && !latest_draft && - current_version < latest_version; - } + [[nodiscard]] bool NeedUpgrade() const; /** * @brief @@ -73,10 +70,7 @@ struct SoftwareVersion { * @return true * @return false */ - [[nodiscard]] bool VersionWithDrawn() const { - return load_info_done && !current_version_found && current_prerelease && - !current_draft; - } + [[nodiscard]] bool VersionWithDrawn() const; /** * @brief @@ -84,9 +78,10 @@ struct SoftwareVersion { * @return true * @return false */ - [[nodiscard]] bool CurrentVersionReleased() const { - return load_info_done && current_version_found; - } + [[nodiscard]] bool CurrentVersionReleased() const; + + private: + static int version_compare(const std::string& a, const std::string& b); }; } // namespace GpgFrontend::UI diff --git a/src/ui/thread/KeyServerImportTask.cpp b/src/ui/thread/KeyServerImportTask.cpp index bf3e1822..fc6a868c 100644 --- a/src/ui/thread/KeyServerImportTask.cpp +++ b/src/ui/thread/KeyServerImportTask.cpp @@ -30,7 +30,8 @@ GpgFrontend::UI::KeyServerImportTask::KeyServerImportTask( std::string keyserver_url, std::vector<std::string> keyids) - : keyserver_url_(std::move(keyserver_url)), + : Task("key_server_import_task"), + keyserver_url_(std::move(keyserver_url)), keyids_(std::move(keyids)), manager_(new QNetworkAccessManager(this)) {} @@ -59,6 +60,6 @@ void GpgFrontend::UI::KeyServerImportTask::dealing_reply_from_server() { emit SignalKeyServerImportResult(network_reply, buffer); if (result_count_++ == keyids_.size() - 1) { - emit SignalTaskFinished(); + emit SignalTaskRunnableEnd(0); } }
\ No newline at end of file diff --git a/src/ui/thread/KeyServerSearchTask.cpp b/src/ui/thread/KeyServerSearchTask.cpp index 0090e79d..863a4ca3 100644 --- a/src/ui/thread/KeyServerSearchTask.cpp +++ b/src/ui/thread/KeyServerSearchTask.cpp @@ -30,7 +30,8 @@ GpgFrontend::UI::KeyServerSearchTask::KeyServerSearchTask( std::string keyserver_url, std::string search_string) - : keyserver_url_(std::move(keyserver_url)), + : Task("key_server_search_task"), + keyserver_url_(std::move(keyserver_url)), search_string_(std::move(search_string)), manager_(new QNetworkAccessManager(this)) {} @@ -55,5 +56,5 @@ void GpgFrontend::UI::KeyServerSearchTask::dealing_reply_from_server() { buffer = reply_->readAll(); } emit SignalKeyServerSearchResult(network_reply, buffer); - emit SignalTaskFinished(); + emit SignalTaskRunnableEnd(0); } diff --git a/src/ui/thread/ListedKeyServerTestTask.cpp b/src/ui/thread/ListedKeyServerTestTask.cpp index 9d4ca74d..914cd3d6 100644 --- a/src/ui/thread/ListedKeyServerTestTask.cpp +++ b/src/ui/thread/ListedKeyServerTestTask.cpp @@ -30,7 +30,8 @@ GpgFrontend::UI::ListedKeyServerTestTask::ListedKeyServerTestTask( const QStringList& urls, int timeout, QWidget* parent) - : urls_(urls), + : Task("listed_key_server_test_task"), + urls_(urls), timeout_(timeout), network_manager_(new QNetworkAccessManager(this)), result_(urls_.size(), kTestResultType_Error) { @@ -44,20 +45,20 @@ void GpgFrontend::UI::ListedKeyServerTestTask::run() { size_t index = 0; for (const auto& url : urls_) { auto key_url = QUrl{url}; - LOG(INFO) << "key server request: " << key_url.host().toStdString(); + SPDLOG_DEBUG("key server request: {}", key_url.host().toStdString()); auto* network_reply = network_manager_->get(QNetworkRequest{key_url}); auto* timer = new QTimer(this); connect(network_reply, &QNetworkReply::finished, this, [this, index, network_reply]() { - LOG(INFO) << "key server domain reply" - << urls_[index].toStdString(); + SPDLOG_DEBUG("key server domain reply: {}", + urls_[index].toStdString()); this->slot_process_network_reply(index, network_reply); }); connect(timer, &QTimer::timeout, this, [this, index, network_reply]() { - LOG(INFO) << "timeout for key server" << urls_[index].toStdString(); + SPDLOG_DEBUG("timeout for key server: {}", urls_[index].toStdString()); if (network_reply->isRunning()) { network_reply->abort(); this->slot_process_network_reply(index, network_reply); @@ -83,6 +84,6 @@ void GpgFrontend::UI::ListedKeyServerTestTask::slot_process_network_reply( if (++result_count_ == urls_.size()) { emit SignalKeyServerListTestResult(result_); - emit SignalTaskFinished(); + emit SignalTaskRunnableEnd(0); } } diff --git a/src/ui/thread/ProxyConnectionTestThread.cpp b/src/ui/thread/ProxyConnectionTestThread.cpp index 062f4774..8b113453 100644 --- a/src/ui/thread/ProxyConnectionTestThread.cpp +++ b/src/ui/thread/ProxyConnectionTestThread.cpp @@ -31,13 +31,13 @@ void GpgFrontend::UI::ProxyConnectionTestThread::run() { auto proxies_list = QNetworkProxyFactory::systemProxyForQuery(npq); if (proxies_list.isEmpty()) { - LOG(INFO) << "no proxy applied"; + SPDLOG_DEBUG("no proxy applied"); } else { - LOG(INFO) << "proxies list hostname" - << proxies_list.front().hostName().toStdString(); + SPDLOG_DEBUG("proxies list hostname: {}", + proxies_list.front().hostName().toStdString()); } - LOG(INFO) << "proxies list size" << proxies_list.size(); + SPDLOG_DEBUG("proxies list size: {}", proxies_list.size()); auto manager = std::make_unique<QNetworkAccessManager>(nullptr); QNetworkRequest url_request; diff --git a/src/ui/thread/VersionCheckTask.cpp b/src/ui/thread/VersionCheckTask.cpp index 7de3b511..e9490e1c 100644 --- a/src/ui/thread/VersionCheckTask.cpp +++ b/src/ui/thread/VersionCheckTask.cpp @@ -36,7 +36,8 @@ namespace GpgFrontend::UI { VersionCheckTask::VersionCheckTask() - : network_manager_(new QNetworkAccessManager(this)), + : Task("version_check_task"), + network_manager_(new QNetworkAccessManager(this)), current_version_(std::string("v") + std::to_string(VERSION_MAJOR) + "." + std::to_string(VERSION_MINOR) + "." + std::to_string(VERSION_PATCH)) { @@ -49,7 +50,7 @@ void VersionCheckTask::Run() { try { using namespace nlohmann; - LOG(INFO) << "current version" << current_version_; + SPDLOG_DEBUG("current version: {}", current_version_); std::string latest_version_url = "https://api.github.com/repos/saturneric/gpgfrontend/releases/latest"; @@ -63,7 +64,8 @@ void VersionCheckTask::Run() { version_.load_info_done = true; } catch (...) { - emit SignalTaskFinished(); + SPDLOG_ERROR("unknown error occurred"); + emit SignalTaskRunnableEnd(-1); } } @@ -73,7 +75,7 @@ void VersionCheckTask::slot_parse_latest_version_info() { try { if (latest_reply_ == nullptr || latest_reply_->error() != QNetworkReply::NoError) { - LOG(ERROR) << "latest version request error"; + SPDLOG_ERROR("latest version request error"); version_.latest_version = current_version_; } else { latest_reply_bytes_ = latest_reply_->readAll(); @@ -83,16 +85,16 @@ void VersionCheckTask::slot_parse_latest_version_info() { std::string latest_version = latest_reply_json["tag_name"]; - LOG(INFO) << "latest version from Github" << latest_version; + SPDLOG_INFO("latest version from Github: {}", latest_version); QRegularExpression re(R"(^[vV](\d+\.)?(\d+\.)?(\*|\d+))"); auto version_match = re.match(latest_version.c_str()); if (version_match.hasMatch()) { latest_version = version_match.captured(0).toStdString(); - LOG(INFO) << "latest version matched" << latest_version; + SPDLOG_DEBUG("latest version matched: {}", latest_version); } else { latest_version = current_version_; - LOG(WARNING) << "latest version unknown"; + SPDLOG_WARN("latest version unknown"); } bool prerelease = latest_reply_json["prerelease"], @@ -106,7 +108,7 @@ void VersionCheckTask::slot_parse_latest_version_info() { version_.release_note = release_note; } } catch (...) { - LOG(INFO) << "error occurred"; + SPDLOG_ERROR("unknown error occurred"); version_.load_info_done = false; } @@ -126,8 +128,8 @@ void VersionCheckTask::slot_parse_latest_version_info() { connect(current_reply_, &QNetworkReply::finished, this, &VersionCheckTask::slot_parse_current_version_info); } catch (...) { - LOG(ERROR) << "current version request create error"; - emit SignalTaskFinished(); + SPDLOG_ERROR("current version request create error"); + emit SignalTaskRunnableEnd(-1); } } @@ -135,12 +137,20 @@ void VersionCheckTask::slot_parse_current_version_info() { try { if (current_reply_ == nullptr || current_reply_->error() != QNetworkReply::NoError) { - LOG(ERROR) << "current version request network error"; + if (current_reply_ != nullptr) { + SPDLOG_ERROR("current version request network error: {}", + current_reply_->errorString().toStdString()); + } else { + SPDLOG_ERROR( + "current version request network error, null reply object"); + } + version_.current_version_found = false; + version_.load_info_done = false; } else { version_.current_version_found = true; current_reply_bytes_ = current_reply_->readAll(); - LOG(INFO) << "current version" << current_reply_bytes_.size(); + SPDLOG_DEBUG("current version: {}", current_reply_bytes_.size()); auto current_reply_json = nlohmann::json::parse(current_reply_bytes_.toStdString()); bool current_prerelease = current_reply_json["prerelease"], @@ -150,18 +160,19 @@ void VersionCheckTask::slot_parse_current_version_info() { version_.load_info_done = true; } } catch (...) { - LOG(INFO) << "error occurred"; + SPDLOG_ERROR("unknown error occurred"); version_.load_info_done = false; } - LOG(INFO) << "current version parse done" << version_.current_version_found; + SPDLOG_DEBUG("current version parse done: {}", + version_.current_version_found); if (current_reply_ != nullptr) { current_reply_->deleteLater(); } emit SignalUpgradeVersion(version_); - emit SignalTaskFinished(); + emit SignalTaskRunnableEnd(0); } } // namespace GpgFrontend::UI diff --git a/src/ui/widgets/FilePage.cpp b/src/ui/widgets/FilePage.cpp index fe188e93..144de3d8 100644 --- a/src/ui/widgets/FilePage.cpp +++ b/src/ui/widgets/FilePage.cpp @@ -108,7 +108,7 @@ void FilePage::slot_file_tree_view_item_clicked(const QModelIndex& index) { #endif m_path_ = selected_path_; - LOG(INFO) << "selected path" << selected_path_.u8string(); + SPDLOG_DEBUG("selected path: {}", selected_path_.u8string()); selected_path_ = std::filesystem::path(selected_path_); MainWindow::CryptoMenu::OperationType operation_type = @@ -164,10 +164,10 @@ void FilePage::slot_up_level() { std::filesystem::path path_obj(str_path); m_path_ = path_obj; - LOG(INFO) << "get path" << m_path_; + SPDLOG_DEBUG("get path: {}", m_path_.u8string()); if (m_path_.has_parent_path() && !m_path_.parent_path().empty()) { m_path_ = m_path_.parent_path(); - LOG(INFO) << "parent path" << m_path_; + SPDLOG_DEBUG("parent path: {}", m_path_.u8string()); ui_->pathEdit->setText(m_path_.u8string().c_str()); this->SlotGoPath(); } @@ -204,7 +204,7 @@ void FilePage::SlotGoPath() { m_path_ = std::filesystem::path(fileInfo.filePath().toStdString()); #endif - LOG(INFO) << "set path" << m_path_.u8string(); + SPDLOG_DEBUG("set path: {}", m_path_.u8string()); ui_->fileTreeView->setRootIndex(dir_model_->index(fileInfo.filePath())); dir_model_->setRootPath(fileInfo.filePath()); for (int i = 1; i < dir_model_->columnCount(); ++i) { @@ -267,7 +267,7 @@ void FilePage::create_popup_menu() { auto showHiddenAct = new QAction(_("Show Hidden File"), this); showHiddenAct->setCheckable(true); connect(showHiddenAct, &QAction::triggered, this, [&](bool checked) { - LOG(INFO) << "Set Hidden" << checked; + SPDLOG_DEBUG("set hidden: {}", checked); if (checked) dir_model_->setFilter(dir_model_->filter() | QDir::Hidden); else @@ -279,7 +279,7 @@ void FilePage::create_popup_menu() { auto showSystemAct = new QAction(_("Show System File"), this); showSystemAct->setCheckable(true); connect(showSystemAct, &QAction::triggered, this, [&](bool checked) { - LOG(INFO) << "Set Hidden" << checked; + SPDLOG_DEBUG("set hidden: {}", checked); if (checked) dir_model_->setFilter(dir_model_->filter() | QDir::System); else @@ -291,7 +291,7 @@ void FilePage::create_popup_menu() { void FilePage::onCustomContextMenu(const QPoint& point) { QModelIndex index = ui_->fileTreeView->indexAt(point); - LOG(INFO) << "right click" << selected_path_.u8string(); + SPDLOG_DEBUG("right click: {}", selected_path_.u8string()); #ifdef WINDOWS auto index_dir_str = @@ -328,7 +328,7 @@ void FilePage::slot_open_item() { if (info.isDir()) { if (info.isReadable() && info.isExecutable()) { const auto file_path = info.filePath().toUtf8().toStdString(); - LOG(INFO) << "set path" << file_path; + SPDLOG_DEBUG("set path: {}", file_path); ui_->pathEdit->setText(info.filePath().toUtf8()); SlotGoPath(); } else { @@ -340,7 +340,7 @@ void FilePage::slot_open_item() { // handle normal text or binary file auto main_window = qobject_cast<MainWindow*>(first_parent_); auto qt_open_path = QString::fromStdString(selected_path_.u8string()); - LOG(INFO) << "open item" << qt_open_path.toStdString(); + SPDLOG_DEBUG("open item: {}", qt_open_path.toStdString()); if (main_window != nullptr) main_window->SlotOpenFile(qt_open_path); } else { QMessageBox::critical(this, _("Error"), @@ -365,12 +365,12 @@ void FilePage::slot_rename_item() { #else new_name_path /= text.toStdString(); #endif - LOG(INFO) << "new name path" << new_name_path; + SPDLOG_DEBUG("new name path: {}", new_name_path.u8string()); std::filesystem::rename(old_name_path, new_name_path); // refresh this->SlotGoPath(); } catch (...) { - LOG(ERROR) << "rename error" << new_name_path; + SPDLOG_ERROR("rename error: {}", new_name_path.u8string()); QMessageBox::critical(this, _("Error"), _("Unable to rename the file or folder.")); } @@ -387,7 +387,7 @@ void FilePage::slot_delete_item() { if (ret == QMessageBox::Cancel) return; - LOG(INFO) << "Delete Item" << data.toString().toStdString(); + SPDLOG_DEBUG("delete item: {}", data.toString().toStdString()); if (!dir_model_->remove(index)) { QMessageBox::critical(this, _("Error"), @@ -441,7 +441,7 @@ void FilePage::slot_create_empty_file() { } void FilePage::keyPressEvent(QKeyEvent* event) { - LOG(INFO) << "Key Press" << event->key(); + SPDLOG_DEBUG("key press: {}", event->key()); if (ui_->pathEdit->hasFocus() && (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)) { SlotGoPath(); diff --git a/src/ui/widgets/InfoBoardWidget.cpp b/src/ui/widgets/InfoBoardWidget.cpp index 74ead2ce..98b07089 100644 --- a/src/ui/widgets/InfoBoardWidget.cpp +++ b/src/ui/widgets/InfoBoardWidget.cpp @@ -85,7 +85,6 @@ void InfoBoardWidget::SetInfoBoard(const QString& text, auto info_font_size = general_settings_state.Check("text_editor").Check("font_size", 10); ui_->infoBoard->setFont(QFont("Times", info_font_size)); - } void InfoBoardWidget::SlotRefresh(const QString& text, InfoBoardStatus status) { @@ -114,7 +113,7 @@ void InfoBoardWidget::AssociateTabWidget(QTabWidget* tab) { void InfoBoardWidget::AddOptionalAction(const QString& name, const std::function<void()>& action) { - LOG(INFO) << "add option" << name.toStdString(); + SPDLOG_DEBUG("add option: {}", name.toStdString()); auto actionButton = new QPushButton(name); auto layout = new QHBoxLayout(); layout->setContentsMargins(5, 0, 5, 0); @@ -144,8 +143,6 @@ void InfoBoardWidget::SlotReset() { */ void InfoBoardWidget::delete_widgets_in_layout(QLayout* layout, int start_index) { - LOG(INFO) << "Called"; - QLayoutItem* item; while ((item = layout->layout()->takeAt(start_index)) != nullptr) { layout->removeItem(item); @@ -165,7 +162,7 @@ void InfoBoardWidget::slot_copy() { void InfoBoardWidget::slot_save() { auto file_path = QFileDialog::getSaveFileName( this, _("Save Information Board's Content"), {}, tr("Text (*.txt)")); - LOG(INFO) << "file path" << file_path.toStdString(); + SPDLOG_DEBUG("file path: {}", file_path.toStdString()); if (file_path.isEmpty()) return; QFile file(file_path); diff --git a/src/ui/widgets/KeyList.cpp b/src/ui/widgets/KeyList.cpp index 9150d580..e426ed48 100644 --- a/src/ui/widgets/KeyList.cpp +++ b/src/ui/widgets/KeyList.cpp @@ -100,7 +100,7 @@ void KeyList::AddListGroupTab( const QString& name, KeyListRow::KeyType selectType, KeyListColumn::InfoType infoType, const std::function<bool(const GpgKey&)>& filter) { - LOG(INFO) << _("Called") << name.toStdString(); + SPDLOG_DEBUG("add tab: {}", name.toStdString()); auto key_list = new QTableWidget(this); if (m_key_list_ == nullptr) { @@ -158,7 +158,7 @@ void KeyList::AddListGroupTab( } void KeyList::SlotRefresh() { - LOG(INFO) << _("called") << "address" << this; + SPDLOG_DEBUG("refresh, address: {}", static_cast<void*>(this)); ui_->refreshKeyListButton->setDisabled(true); ui_->syncButton->setDisabled(true); @@ -317,10 +317,10 @@ void KeyList::dropEvent(QDropEvent* event) { bool confirm_import_keys = true; try { confirm_import_keys = settings.lookup("general.confirm_import_keys"); - LOG(INFO) << "confirm_import_keys" << confirm_import_keys; + SPDLOG_DEBUG("confirm_import_keys: {}", confirm_import_keys); if (confirm_import_keys) checkBox->setCheckState(Qt::Checked); } catch (...) { - LOG(ERROR) << _("Setting Operation Error") << _("confirm_import_keys"); + SPDLOG_ERROR("setting operation error: confirm_import_keys"); } // Buttons for ok and cancel @@ -358,8 +358,7 @@ void KeyList::dropEvent(QDropEvent* event) { QFile file; file.setFileName(tmp.toLocalFile()); if (!file.open(QIODevice::ReadOnly)) { - LOG(INFO) << _("Couldn't Open File") << ":" - << tmp.toString().toStdString(); + SPDLOG_ERROR("couldn't open file: {}", tmp.toString().toStdString()); } QByteArray inBuffer = file.readAll(); this->import_keys(inBuffer); @@ -379,7 +378,7 @@ void KeyList::dragEnterEvent(QDragEnterEvent* event) { * */ [[maybe_unused]] void KeyList::MarkKeys(QStringList* keyIds) { - foreach (QString id, *keyIds) { qDebug() << "marked: " << id; } + foreach (QString id, *keyIds) { spdlog::debug("marked: ", id.toStdString()); } } void KeyList::import_keys(const QByteArray& inBuffer) { @@ -419,7 +418,7 @@ std::string KeyList::GetSelectedKey() { } void KeyList::slot_refresh_ui() { - LOG(INFO) << _("Called") << buffered_keys_list_.get(); + SPDLOG_DEBUG("refresh: {}", static_cast<void*>(buffered_keys_list_.get())); if (buffered_keys_list_ != nullptr) { std::lock_guard<std::mutex> guard(buffered_key_list_mutex_); for (auto& key_table : m_key_tables_) { @@ -451,8 +450,8 @@ void KeyList::slot_sync_with_key_server() { CommonUtils::SlotImportKeyFromKeyServer( key_ids, [=](const std::string& key_id, const std::string& status, size_t current_index, size_t all_index) { - LOG(INFO) << _("Called") << key_id << status << current_index - << all_index; + SPDLOG_DEBUG("import key: {} {} {} {}", key_id, status, current_index, + all_index); auto key = GpgKeyGetter::GetInstance().GetKey(key_id); boost::format status_str = boost::format(_("Sync [%1%/%2%] %3% %4%")) % @@ -503,7 +502,7 @@ KeyIdArgsListPtr& KeyTable::GetChecked() { auto& ret = checked_key_ids_; for (int i = 0; i < buffered_keys_.size(); i++) { auto key_id = buffered_keys_[i].GetId(); - LOG(INFO) << "i: " << i << " key_id: " << key_id; + SPDLOG_DEBUG("i: {} key_id: {}", i, key_id); if (key_list_->item(i, 0)->checkState() == Qt::Checked && std::find(ret->begin(), ret->end(), key_id) == ret->end()) { ret->push_back(key_id); @@ -513,7 +512,6 @@ KeyIdArgsListPtr& KeyTable::GetChecked() { } void KeyTable::SetChecked(KeyIdArgsListPtr key_ids) { - LOG(INFO) << "called"; checked_key_ids_ = std::move(key_ids); } @@ -535,14 +533,14 @@ void KeyTable::Refresh(KeyLinkListPtr m_keys) { int row_count = 0; while (it != keys->end()) { - LOG(INFO) << "filtering key id: " << it->GetId(); + SPDLOG_DEBUG("filtering key id: {}", it->GetId()); if (filter_ != nullptr) { if (!filter_(*it)) { it = keys->erase(it); continue; } } - LOG(INFO) << "adding key id: " << it->GetId(); + SPDLOG_DEBUG("adding key id: {}", it->GetId()); if (select_type_ == KeyListRow::ONLY_SECRET_KEY && !it->IsPrivateKey()) { it = keys->erase(it); continue; @@ -625,7 +623,8 @@ void KeyTable::Refresh(KeyLinkListPtr m_keys) { tmp3->setFont(strike); } - LOG(INFO) << "key id: " << it->GetId() << "added into key_list_:" << this; + SPDLOG_DEBUG("key id: {} added into key_list_: {}", it->GetId(), + static_cast<void*>(this)); // move to buffered keys buffered_keys_.emplace_back(std::move(*it)); diff --git a/src/ui/widgets/PlainTextEditorPage.cpp b/src/ui/widgets/PlainTextEditorPage.cpp index 10e19b8b..c9a65a4c 100644 --- a/src/ui/widgets/PlainTextEditorPage.cpp +++ b/src/ui/widgets/PlainTextEditorPage.cpp @@ -160,8 +160,6 @@ void PlainTextEditorPage::slot_format_gpg_header() { } void PlainTextEditorPage::ReadFile() { - LOG(INFO) << "called"; - read_done_ = false; read_bytes_ = 0; ui_->textPage->setEnabled(false); @@ -184,10 +182,10 @@ void PlainTextEditorPage::ReadFile() { connect(this, &PlainTextEditorPage::SignalUIBytesDisplayed, read_task, &FileReadTask::SignalFileBytesReadNext, Qt::QueuedConnection); - connect(read_task, &FileReadTask::SignalTaskFinished, this, - []() { LOG(INFO) << "read thread closed"; }); + connect(read_task, &FileReadTask::SignalTaskRunnableEnd, this, + []() { SPDLOG_DEBUG("read thread closed"); }); connect(this, &PlainTextEditorPage::close, read_task, - &FileReadTask::SignalTaskFinished); + [=]() { read_task->SignalTaskRunnableEnd(0); }); connect(read_task, &FileReadTask::SignalFileBytesReadEnd, this, [=]() { // set the UI if (!binary_mode_) text_page->setReadOnly(false); @@ -212,7 +210,7 @@ std::string binary_to_string(const std::string &source) { void PlainTextEditorPage::slot_insert_text(QByteArray bytes_data) { std::string data = bytes_data.toStdString(); - LOG(INFO) << "data size" << data.size(); + SPDLOG_DEBUG("data size: {}", data.size()); read_bytes_ += data.size(); // If binary format is detected, the entire file is converted to binary // format for display. @@ -260,7 +258,6 @@ void PlainTextEditorPage::slot_insert_text(QByteArray bytes_data) { this->ui_->characterLabel->setText(str.str().c_str()); } QTimer::singleShot(25, this, &PlainTextEditorPage::SignalUIBytesDisplayed); - LOG(INFO) << "end"; } void PlainTextEditorPage::detect_encoding(const std::string &data) { diff --git a/src/ui/widgets/TextEdit.cpp b/src/ui/widgets/TextEdit.cpp index 713dbb80..4947e179 100644 --- a/src/ui/widgets/TextEdit.cpp +++ b/src/ui/widgets/TextEdit.cpp @@ -29,6 +29,11 @@ #include "ui/widgets/TextEdit.h" #include <boost/format.hpp> +#include <string> +#include <tuple> +#include <vector> + +#include "spdlog/spdlog.h" namespace GpgFrontend::UI { @@ -61,6 +66,8 @@ void TextEdit::SlotNewTab() { page->GetTextPage()->setFocus(); connect(page->GetTextPage()->document(), &QTextDocument::modificationChanged, this, &TextEdit::SlotShowModified); + connect(page->GetTextPage()->document(), &QTextDocument::contentsChanged, + this, &TextEdit::slot_save_status_to_cache_for_revovery); } void TextEdit::slotNewHelpTab(const QString& title, const QString& path) const { @@ -79,15 +86,18 @@ void TextEdit::SlotNewFileTab() const { page->SlotGoPath(); } -void TextEdit::SlotOpenFile(QString& path) { +void TextEdit::SlotOpenFile(const QString& path) { QFile file(path); - LOG(INFO) << "path" << path.toStdString(); + SPDLOG_DEBUG("path: {}", path.toStdString()); auto result = file.open(QIODevice::ReadOnly | QIODevice::Text); if (result) { auto* page = new PlainTextEditorPage(path); connect(page->GetTextPage()->document(), &QTextDocument::modificationChanged, this, &TextEdit::SlotShowModified); + // connect to cache recovery fucntion + connect(page->GetTextPage()->document(), &QTextDocument::contentsChanged, + this, &TextEdit::slot_save_status_to_cache_for_revovery); QApplication::setOverrideCursor(Qt::WaitCursor); auto index = tab_widget_->addTab(page, stripped_name(path)); @@ -112,35 +122,7 @@ void TextEdit::SlotOpen() { QFileDialog::getOpenFileNames(this, _("Open file"), QDir::currentPath()); for (const auto& file_name : file_names) { if (!file_name.isEmpty()) { - QFile file(file_name); - - if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { - auto* page = new PlainTextEditorPage(file_name); - - QTextStream in(&file); - QApplication::setOverrideCursor(Qt::WaitCursor); - page->GetTextPage()->setPlainText(in.readAll()); - page->SetFilePath(file_name); - QTextDocument* document = page->GetTextPage()->document(); - document->setModified(false); - - tab_widget_->addTab(page, stripped_name(file_name)); - tab_widget_->setCurrentIndex(tab_widget_->count() - 1); - QApplication::restoreOverrideCursor(); - page->GetTextPage()->setFocus(); - connect(page->GetTextPage()->document(), - &QTextDocument::modificationChanged, this, - &TextEdit::SlotShowModified); - // enableAction(true) - file.close(); - } else { - QMessageBox::warning( - this, _("Warning"), - (boost::format(_("Cannot read file %1%:\n%2%.")) % - file_name.toStdString() % file.errorString().toStdString()) - .str() - .c_str()); - } + SlotOpenFile(file_name); } } } @@ -477,9 +459,17 @@ void TextEdit::SlotPrint() { #endif } -void TextEdit::SlotShowModified() const { +void TextEdit::SlotShowModified(bool changed) const { + // get current tab int index = tab_widget_->currentIndex(); QString title = tab_widget_->tabText(index); + + // if changed + if (!changed) { + tab_widget_->setTabText(index, title.remove(0, 2)); + return; + } + // if doc is modified now, add leading * to title, // otherwise remove the leading * from the title if (CurTextPage()->GetTextPage()->document()->isModified()) { @@ -516,7 +506,7 @@ QHash<int, QString> TextEdit::UnsavedDocuments() const { if (ep != nullptr && ep->ReadDone() && ep->GetTextPage()->document()->isModified()) { QString doc_name = tab_widget_->tabText(i); - LOG(INFO) << "unsaved" << doc_name.toStdString(); + SPDLOG_DEBUG("unsaved: {}", doc_name.toStdString()); // remove * before name of modified doc doc_name.remove(0, 2); @@ -608,4 +598,43 @@ void TextEdit::slot_file_page_path_changed(const QString& path) const { tab_widget_->setTabText(index, mPath); } +void TextEdit::slot_save_status_to_cache_for_revovery() { + SPDLOG_DEBUG("catch text page modified event, count: {}", + text_page_data_modified_count_); + if (this->text_page_data_modified_count_++ % 3 != 0) return; + + int tab_count = tab_widget_->count(); + SPDLOG_DEBUG("current tabs count {}", tab_count); + + std::vector<std::pair<int, std::string>> saved_pages; + std::vector<std::tuple<int, std::string, std::string>> unsaved_pages; + + for (int i = 0; i < tab_count; i++) { + auto* target_page = + qobject_cast<PlainTextEditorPage*>(tab_widget_->widget(i)); + + // if this page is no textedit, there should be nothing to save + if (target_page == nullptr) { + continue; + } + + auto* document = target_page->GetTextPage()->document(); + auto tab_title = tab_widget_->tabText(i).toStdString(); + if (!target_page->ReadDone() || !target_page->isEnabled() || + !document->isModified()) { + auto file_path = target_page->GetFilePath().toStdString(); + SPDLOG_DEBUG("saved page index: {}, tab title: {} tab file path: {}", i, + tab_title, file_path); + + saved_pages.push_back({i, file_path}); + continue; + } + + auto raw_text = document->toRawText().toStdString(); + SPDLOG_DEBUG("unsaved page index: {}, tab title: {} tab content: {}", i, + tab_title, raw_text.size()); + unsaved_pages.push_back({i, tab_title, raw_text}); + } +} + } // namespace GpgFrontend::UI diff --git a/src/ui/widgets/TextEdit.h b/src/ui/widgets/TextEdit.h index cb32bfb2..2e2f949d 100644 --- a/src/ui/widgets/TextEdit.h +++ b/src/ui/widgets/TextEdit.h @@ -153,7 +153,7 @@ class TextEdit : public QWidget { /** * @details Adds a new tab with opening file by path */ - void SlotOpenFile(QString& path); + void SlotOpenFile(const QString& path); /** * @details Adds a new tab with the given title and opens given html file. @@ -172,7 +172,7 @@ class TextEdit : public QWidget { * @details put a * in front of current tabs title, if current textedit is * modified */ - void SlotShowModified() const; + void SlotShowModified(bool) const; /** * @details close the current tab and decrease TabWidget->count by \a 1 @@ -193,6 +193,8 @@ class TextEdit : public QWidget { void SlotSwitchTabDown() const; private: + uint text_page_data_modified_count_ = 0; ///< + /** * @details return just a filename stripped of a whole path * @@ -221,6 +223,13 @@ class TextEdit : public QWidget { */ void slot_remove_tab(int index); + /** + * @brief + * + * @param index + */ + void slot_save_status_to_cache_for_revovery(); + public slots: /** diff --git a/third_party/CMakeLists.txt b/third_party/CMakeLists.txt index 04068ca1..c7912e31 100644 --- a/third_party/CMakeLists.txt +++ b/third_party/CMakeLists.txt @@ -26,4 +26,6 @@ # json set(JSON_BuildTests OFF CACHE INTERNAL "") -add_subdirectory(json EXCLUDE_FROM_ALL)
\ No newline at end of file +add_subdirectory(json EXCLUDE_FROM_ALL) + +add_subdirectory(spdlog EXCLUDE_FROM_ALL)
\ No newline at end of file diff --git a/third_party/easyloggingpp b/third_party/easyloggingpp deleted file mode 160000 -Subproject 8489989bb26c6371df103f6cbced3fbee1bc3c2 diff --git a/third_party/gpgme b/third_party/gpgme -Subproject cc37447b625b45efb5c94c40461084460f03f24 +Subproject 64da77620a451653e9b8c41bb0c9e58e2296712 diff --git a/third_party/json b/third_party/json -Subproject c6740d7d58a209da8960c961ee07bfb0e841e44 +Subproject da6b908c4fe63d8c6192c78f00d43ddb40cc563 diff --git a/third_party/libarchive b/third_party/libarchive -Subproject b1b501161013296d19dfe9acb84a341c8a1755b +Subproject 90799596b2ef2f847d669b610919e8d51a38250 diff --git a/third_party/libassuan b/third_party/libassuan -Subproject 335030e3d204afe33873df83c29302ff1caa021 +Subproject e4e54fb4ba1b82f1cd08ea44ad4c48db4c23631 diff --git a/third_party/libconfig b/third_party/libconfig -Subproject 020a9ce12d1be7ab79ca0674fc957e732ab67f4 +Subproject 4f13b7f5152427b5e511a09617ca2d9ff63f780 diff --git a/third_party/libgpg-error b/third_party/libgpg-error -Subproject 220a427b4f997ef6af1b2d4e82ef1dc96e0cd6f +Subproject 885a287a57cf060b4c5b441822c09d23b8dee2b diff --git a/third_party/qt-aes b/third_party/qt-aes -Subproject 845e3b4d3d3873843ca26dc365232aa1aa8ea2a +Subproject 27410ebf00328951cd81a6242a3e8c2d508f64a diff --git a/third_party/spdlog b/third_party/spdlog new file mode 160000 +Subproject 927cc29444a294d76e83dfb898e797dc431ce09 diff --git a/ui/GeneralSettings.ui b/ui/GeneralSettings.ui index 4121e762..75aef6b2 100644 --- a/ui/GeneralSettings.ui +++ b/ui/GeneralSettings.ui @@ -7,7 +7,7 @@ <x>0</x> <y>0</y> <width>643</width> - <height>656</height> + <height>721</height> </rect> </property> <property name="windowTitle"> @@ -17,37 +17,24 @@ <item row="0" column="0"> <layout class="QVBoxLayout" name="verticalLayout"> <item> - <widget class="QGroupBox" name="longerKeyExpirationDateBox"> + <widget class="QGroupBox" name="cacheBox"> <property name="title"> - <string>Longer Key Expiration Date</string> + <string>Cache</string> </property> - <layout class="QGridLayout" name="gridLayout_2"> + <layout class="QGridLayout" name="gridLayout_3"> <item row="0" column="0"> - <layout class="QVBoxLayout" name="verticalLayout_2"> + <layout class="QVBoxLayout" name="verticalLayout_3"> <item> - <widget class="QCheckBox" name="longerKeyExpirationDateCheckBox"> + <widget class="QCheckBox" name="saveCheckedKeysCheckBox"> <property name="text"> - <string>Unlock key expiration date setting up to 30 years.</string> + <string>Save checked keys in Key ToolBox on exit and restore them on next start.</string> </property> </widget> </item> - </layout> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QGroupBox" name="saveCheckedKeysBox"> - <property name="title"> - <string>Save Checked Keys</string> - </property> - <layout class="QGridLayout" name="gridLayout_3"> - <item row="0" column="0"> - <layout class="QVBoxLayout" name="verticalLayout_3"> <item> - <widget class="QCheckBox" name="saveCheckedKeysCheckBox"> + <widget class="QCheckBox" name="clearGpgPasswordCacheCheckBox"> <property name="text"> - <string>Save checked private keys on exit and restore them on next start.</string> + <string>Clear gpg password cache when closing GpgFrontend.</string> </property> </widget> </item> @@ -59,7 +46,7 @@ <item> <widget class="QGroupBox" name="importConfirmationBox"> <property name="title"> - <string>Confirm drag'n'drop key import</string> + <string>Operation</string> </property> <layout class="QGridLayout" name="gridLayout_4"> <item row="0" column="0"> @@ -71,70 +58,75 @@ </property> </widget> </item> + <item> + <widget class="QCheckBox" name="longerKeyExpirationDateCheckBox"> + <property name="text"> + <string>Enable to use longer key expiration date.</string> + </property> + </widget> + </item> </layout> </item> </layout> </widget> </item> <item> - <widget class="QGroupBox" name="asciiModeBox"> + <widget class="QGroupBox" name="gnupgDatabaseBox"> <property name="title"> - <string>ASCII Mode</string> + <string>GnuPG</string> </property> - <layout class="QGridLayout" name="gridLayout_6"> + <layout class="QGridLayout" name="gridLayout_7"> <item row="0" column="0"> - <layout class="QVBoxLayout" name="verticalLayout_6"> + <layout class="QVBoxLayout" name="verticalLayout_7"> <item> <widget class="QCheckBox" name="asciiModeCheckBox"> <property name="text"> - <string>ASCII encoding is not used when file encrypting and signing.</string> + <string>No ASCII Mode</string> </property> </widget> </item> - </layout> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QGroupBox" name="langBox"> - <property name="title"> - <string>Language</string> - </property> - <layout class="QGridLayout" name="gridLayout_5"> - <item row="0" column="0"> - <layout class="QVBoxLayout" name="verticalLayout_5"> <item> - <widget class="QComboBox" name="langSelectBox"> - <property name="sizeAdjustPolicy"> - <enum>QComboBox::AdjustToContents</enum> + <widget class="Line" name="line_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> </property> </widget> </item> <item> - <widget class="QLabel" name="langNoteLabel"> + <widget class="QCheckBox" name="useCustomGnuPGInstallPathCheckBox"> <property name="text"> - <string>NOTE: GpgFrontend will restart automatically if you change the language!</string> + <string>Use Custom GnuPG</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="currentCustomGnuPGInstallPathLabel"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="useCustomGnuPGInstallPathButton"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Select GnuPG Path</string> + </property> + </widget> + </item> + <item> + <widget class="Line" name="line"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> </property> </widget> </item> - </layout> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QGroupBox" name="gnupgDatabaseBox"> - <property name="title"> - <string>GnuPG Key Database Path</string> - </property> - <layout class="QGridLayout" name="gridLayout_7"> - <item row="0" column="0"> - <layout class="QVBoxLayout" name="verticalLayout_7"> <item> <widget class="QCheckBox" name="keyDatabseUseCustomCheckBox"> <property name="text"> - <string>Use Custom Path</string> + <string>Use Custom GnuPG Key Database Path</string> </property> </widget> </item> @@ -154,7 +146,34 @@ <bool>false</bool> </property> <property name="text"> - <string>Select Custom Path</string> + <string>Select Key Database Path</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="langBox"> + <property name="title"> + <string>Language</string> + </property> + <layout class="QGridLayout" name="gridLayout_5"> + <item row="0" column="0"> + <layout class="QVBoxLayout" name="verticalLayout_5"> + <item> + <widget class="QComboBox" name="langSelectBox"> + <property name="sizeAdjustPolicy"> + <enum>QComboBox::AdjustToContents</enum> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="langNoteLabel"> + <property name="text"> + <string>NOTE: GpgFrontend will restart automatically if you change the language!</string> </property> </widget> </item> diff --git a/ui/GnuPGInfo.ui b/ui/GnuPGInfo.ui index f907874f..efb895af 100644 --- a/ui/GnuPGInfo.ui +++ b/ui/GnuPGInfo.ui @@ -16,17 +16,20 @@ <layout class="QGridLayout" name="gridLayout"> <item row="0" column="0"> <layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,0,0"> + <property name="spacing"> + <number>0</number> + </property> <property name="leftMargin"> - <number>5</number> + <number>0</number> </property> <property name="topMargin"> - <number>5</number> + <number>0</number> </property> <property name="rightMargin"> - <number>5</number> + <number>0</number> </property> <property name="bottomMargin"> - <number>5</number> + <number>0</number> </property> <item> <widget class="QLabel" name="label"> @@ -51,6 +54,19 @@ </widget> </item> <item> + <widget class="QLabel" name="gnupgVersionLabel"> + <property name="text"> + <string>Version</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <property name="margin"> + <number>5</number> + </property> + </widget> + </item> + <item> <widget class="Line" name="line"> <property name="sizePolicy"> <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> @@ -64,27 +80,52 @@ </widget> </item> <item> - <widget class="QLabel" name="componentDetailsTableTitle"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Components Information</string> - </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> + <widget class="QTabWidget" name="tabWidget"> + <property name="tabShape"> + <enum>QTabWidget::Rounded</enum> </property> - <property name="margin"> - <number>5</number> + <property name="currentIndex"> + <number>0</number> </property> + <widget class="QWidget" name="tab"> + <attribute name="title"> + <string>Components</string> + </attribute> + <layout class="QGridLayout" name="gridLayout_3"> + <item row="0" column="0"> + <widget class="QTableWidget" name="componentDetailsTable"> + <property name="sizeAdjustPolicy"> + <enum>QAbstractScrollArea::AdjustToContents</enum> + </property> + <property name="autoScrollMargin"> + <number>16</number> + </property> + <property name="editTriggers"> + <set>QAbstractItemView::NoEditTriggers</set> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="tab_2"> + <attribute name="title"> + <string>Configurations</string> + </attribute> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="0" column="0"> + <widget class="QTableWidget" name="configurationDetailsTable"> + <property name="sizeAdjustPolicy"> + <enum>QAbstractScrollArea::AdjustToContents</enum> + </property> + <property name="editTriggers"> + <set>QAbstractItemView::NoEditTriggers</set> + </property> + </widget> + </item> + </layout> + </widget> </widget> </item> - <item> - <widget class="QTableWidget" name="conponentDetailsTable"/> - </item> </layout> </item> </layout> |