aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSaturn&Eric <[email protected]>2022-01-05 20:02:19 +0000
committerGitHub <[email protected]>2022-01-05 20:02:19 +0000
commita3ca1bf1d4404327d68d3d49127085638c272152 (patch)
treedeb10c33977e5002fa6e9b434f2b07d2719a4e31
parentMerge pull request #37 from saturneric/document (diff)
parent<doc>(navbar): take repository and GitHub apart. (diff)
downloadGpgFrontend-a3ca1bf1d4404327d68d3d49127085638c272152.tar.gz
GpgFrontend-a3ca1bf1d4404327d68d3d49127085638c272152.zip
Merge pull request #36 from saturneric/developv2.0.4
v2.0.4
-rw-r--r--.gitignore1
-rw-r--r--CMakeLists.txt38
-rw-r--r--gpgfrontend.qrc1
-rw-r--r--resource/icons/key_package.pngbin0 -> 8815 bytes
-rw-r--r--resource/plist/MacOSXBundleInfo.plist.in36
-rw-r--r--resource/plist/entitlement.plist7
-rw-r--r--src/CMakeLists.txt50
-rw-r--r--src/GpgFrontend.h.in2
-rw-r--r--src/gpg/CMakeLists.txt11
-rw-r--r--src/gpg/GpgConstants.cpp10
-rw-r--r--src/gpg/GpgConstants.h9
-rw-r--r--src/gpg/GpgContext.cpp177
-rw-r--r--src/gpg/GpgContext.h55
-rw-r--r--src/gpg/GpgCoreInit.cpp52
-rw-r--r--src/gpg/GpgCoreInit.h40
-rw-r--r--src/gpg/GpgFunctionObject.h115
-rw-r--r--src/gpg/GpgGenKeyInfo.cpp132
-rw-r--r--src/gpg/GpgGenKeyInfo.h93
-rw-r--r--src/gpg/GpgInfo.h6
-rw-r--r--src/gpg/function/BasicOperator.cpp9
-rw-r--r--src/gpg/function/BasicOperator.h6
-rw-r--r--src/gpg/function/GpgCommandExecutor.h6
-rw-r--r--src/gpg/function/GpgFileOpera.cpp106
-rw-r--r--src/gpg/function/GpgFileOpera.h37
-rw-r--r--src/gpg/function/GpgKeyGetter.cpp4
-rw-r--r--src/gpg/function/GpgKeyGetter.h6
-rw-r--r--src/gpg/function/GpgKeyImportExporter.cpp (renamed from src/gpg/function/GpgKeyImportExportor.cpp)62
-rw-r--r--src/gpg/function/GpgKeyImportExporter.h (renamed from src/gpg/function/GpgKeyImportExportor.h)16
-rw-r--r--src/gpg/function/GpgKeyManager.h7
-rw-r--r--src/gpg/function/GpgKeyOpera.cpp85
-rw-r--r--src/gpg/function/GpgKeyOpera.h12
-rw-r--r--src/gpg/function/UidOperator.h7
-rw-r--r--src/gpg/model/GpgKey.h7
-rw-r--r--src/gpg/result_analyse/DecryptResultAnalyse.cpp38
-rw-r--r--src/gpg/result_analyse/DecryptResultAnalyse.h4
-rw-r--r--src/gpg/result_analyse/VerifyResultAnalyse.cpp16
-rw-r--r--src/main.cpp54
-rw-r--r--src/smtp/CMakeLists.txt8
-rw-r--r--src/ui/CMakeLists.txt9
-rwxr-xr-xsrc/ui/FileEncryptionDialog.cpp285
-rwxr-xr-xsrc/ui/FileEncryptionDialog.h114
-rw-r--r--src/ui/GpgFrontendUI.h6
-rw-r--r--src/ui/KeyImportDetailDialog.h2
-rwxr-xr-xsrc/ui/KeyMgmt.cpp182
-rwxr-xr-xsrc/ui/KeyMgmt.h7
-rw-r--r--src/ui/KeyServerImportDialog.cpp6
-rw-r--r--src/ui/KeyServerImportDialog.h2
-rw-r--r--src/ui/KeyUploadDialog.cpp8
-rw-r--r--src/ui/MainWindow.cpp51
-rw-r--r--src/ui/MainWindow.h8
-rw-r--r--src/ui/UserInterfaceUtils.cpp17
-rw-r--r--src/ui/UserInterfaceUtils.h4
-rw-r--r--src/ui/aes/qaesencryption.cpp626
-rw-r--r--src/ui/aes/qaesencryption.h165
-rw-r--r--src/ui/data_struct/SoftwareVersion.cpp25
-rw-r--r--src/ui/data_struct/SoftwareVersion.h59
-rw-r--r--src/ui/function/CtxCheckThread.cpp48
-rw-r--r--src/ui/function/CtxCheckThread.h42
-rw-r--r--src/ui/function/FileReadThread.h3
-rw-r--r--src/ui/function/ProxyConnectionTestThread.cpp56
-rw-r--r--src/ui/function/ProxyConnectionTestThread.h57
-rw-r--r--src/ui/function/SMTPSendMailThread.cpp261
-rw-r--r--src/ui/function/SMTPSendMailThread.h106
-rw-r--r--src/ui/function/SMTPTestThread.cpp46
-rw-r--r--src/ui/function/SMTPTestThread.h70
-rw-r--r--src/ui/function/TestListedKeyServerThread.cpp47
-rw-r--r--src/ui/function/TestListedKeyServerThread.h55
-rw-r--r--src/ui/function/VersionCheckThread.cpp118
-rw-r--r--src/ui/function/VersionCheckThread.h8
-rw-r--r--src/ui/help/AboutDialog.cpp60
-rw-r--r--src/ui/help/AboutDialog.h4
-rw-r--r--src/ui/keygen/KeygenDialog.cpp148
-rw-r--r--src/ui/keygen/KeygenDialog.h7
-rw-r--r--src/ui/keygen/SubkeyGenerateDialog.cpp126
-rw-r--r--src/ui/keygen/SubkeyGenerateDialog.h10
-rw-r--r--src/ui/keypair_details/KeyDetailsDialog.cpp8
-rw-r--r--src/ui/keypair_details/KeyDetailsDialog.h3
-rw-r--r--src/ui/keypair_details/KeyPairDetailTab.cpp391
-rw-r--r--src/ui/keypair_details/KeyPairDetailTab.h25
-rw-r--r--src/ui/keypair_details/KeyPairOperaTab.cpp349
-rw-r--r--src/ui/keypair_details/KeyPairOperaTab.h69
-rw-r--r--src/ui/keypair_details/KeyPairSubkeyTab.cpp69
-rw-r--r--src/ui/keypair_details/KeyPairSubkeyTab.h3
-rw-r--r--src/ui/keypair_details/KeyUIDSignDialog.cpp2
-rw-r--r--src/ui/main_window/MainWindowFileSlotFunction.cpp285
-rw-r--r--src/ui/main_window/MainWindowSlotFunction.cpp56
-rw-r--r--src/ui/main_window/MainWindowUI.cpp9
-rw-r--r--src/ui/settings/GlobalSettingStation.h12
-rw-r--r--src/ui/settings/SettingsDialog.cpp13
-rwxr-xr-xsrc/ui/settings/SettingsDialog.h2
-rw-r--r--src/ui/settings/SettingsGeneral.cpp396
-rw-r--r--src/ui/settings/SettingsGeneral.h23
-rw-r--r--src/ui/settings/SettingsKeyServer.cpp80
-rw-r--r--src/ui/settings/SettingsNetwork.cpp334
-rw-r--r--src/ui/settings/SettingsNetwork.h57
-rw-r--r--src/ui/settings/SettingsSendMail.cpp270
-rw-r--r--src/ui/settings/SettingsSendMail.h35
-rw-r--r--src/ui/smtp/EmailListEditor.cpp102
-rw-r--r--src/ui/smtp/EmailListEditor.h54
-rw-r--r--src/ui/smtp/RecipientsPicker.cpp76
-rw-r--r--src/ui/smtp/RecipientsPicker.h49
-rw-r--r--src/ui/smtp/SendMailDialog.cpp302
-rw-r--r--src/ui/smtp/SendMailDialog.h31
-rw-r--r--src/ui/smtp/SenderPicker.cpp76
-rw-r--r--src/ui/smtp/SenderPicker.h47
-rw-r--r--src/ui/widgets/EditorPage.cpp30
-rw-r--r--src/ui/widgets/EditorPage.h8
-rw-r--r--src/ui/widgets/ExportKeyPackageDialog.cpp170
-rw-r--r--src/ui/widgets/ExportKeyPackageDialog.h55
-rw-r--r--src/ui/widgets/FilePage.cpp131
-rw-r--r--src/ui/widgets/FilePage.h11
-rw-r--r--src/ui/widgets/InfoBoardWidget.cpp3
-rw-r--r--src/ui/widgets/KeyList.cpp135
-rw-r--r--src/ui/widgets/KeyList.h29
-rw-r--r--src/ui/widgets/SignersPicker.cpp30
-rw-r--r--src/ui/widgets/SignersPicker.h8
-rw-r--r--src/ui/widgets/TextEdit.cpp30
-rw-r--r--src/ui/widgets/TextEdit.h2
-rw-r--r--test/CMakeLists.txt13
-rw-r--r--test/GpgCoreTest.cpp28
-rw-r--r--test/GpgCoreTestBasicOpera.cpp86
-rw-r--r--test/GpgCoreTestImportExport.cpp2
-rw-r--r--test/GpgCoreTestKeyModel.cpp21
-rw-r--r--test/GpgCoreTestKeyModelAlone.cpp158
-rw-r--r--test/GpgCoreTestKeygen.cpp128
-rw-r--r--test/GpgCoreTestKeygenAlone.cpp156
-rw-r--r--test/GpgFrontendTest.h99
-rw-r--r--test/conf/core.cfg7
m---------third_party/AppImageUpdate0
-rw-r--r--third_party/CMakeLists.txt2
-rw-r--r--third_party/easyloggingpp/CMakeLists.txt9
-rw-r--r--ui/EmailListEditor.ui70
-rw-r--r--ui/ExportKeyPackageDialog.ui207
-rw-r--r--ui/FilePage.ui55
-rw-r--r--ui/GeneralSettings.ui145
-rw-r--r--ui/InfoBoard.ui15
-rw-r--r--ui/KeyList.ui79
-rw-r--r--ui/NetworkSettings.ui325
-rw-r--r--ui/ReceiveMailDialog.ui41
-rw-r--r--ui/SendMailDialog.ui201
-rw-r--r--ui/SendMailSettings.ui34
141 files changed, 7485 insertions, 2439 deletions
diff --git a/.gitignore b/.gitignore
index 243ab625..8d75fe32 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
src/GpgFrontend.h
src/GpgFrontendBuildInfo.h
src/GpgFrontendBuildInstallInfo.h
+third_party/AppImageUpdate
# gettext
*.mo
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8a524da7..4a96a11d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.16)
-project(GpgFrontend VERSION 2.0.3 LANGUAGES CXX)
+project(GpgFrontend VERSION 2.0.4 LANGUAGES CXX)
message(STATUS "GpgFrontend Build Configuration Started CMAKE Version ${CMAKE_VERSION}")
@@ -42,16 +42,16 @@ else ()
endif ()
# Specify different compilation modes
-if (BUILD_CONFIG)
+if (GPGFRONTEND_BUILD_CONFIG)
# Test Build
- if (${BUILD_CONFIG} STREQUAL "test")
- message(STATUS "Switch TEST_BUILD")
- set(TEST_BUILD 1)
- set(AppName GpgFrontendTest)
+ if (${GPGFRONTEND_BUILD_CONFIG} STREQUAL "test_core")
+ message(STATUS "Switch TEST_CORE_BUILD")
+ set(TEST_CORE_BUILD 1)
+ set(AppName GpgFrontendCoreTest)
# Test Build With Coverage Test
- elseif (${BUILD_CONFIG} STREQUAL "test_coverage")
+ elseif (${GPGFRONTEND_BUILD_CONFIG} STREQUAL "test_core_coverage")
message(STATUS "Switch TEST_COVERAGE_BUILD")
- set(TEST_BUILD 1)
+ set(TEST_CORE_BUILD 1)
if (USING_COMPILER_CLANG OR USING_COMPILER_GCC)
set(TEST_COVERAGE_BUILD 1)
set(CMAKE_CXX_OUTPUT_EXTENSION_REPLACE 1)
@@ -61,11 +61,11 @@ if (BUILD_CONFIG)
endif ()
set(AppName GpgFrontendTest)
# Test Build with minimum UI
- elseif (${BUILD_CONFIG} STREQUAL "test_ui")
+ elseif (${GPGFRONTEND_BUILD_CONFIG} STREQUAL "test_ui")
message(STATUS "Switch TEST_MINIMUM_UI_BUILD")
set(MINIMUM_APPLICATION_BUILD 1)
set(AppName GpgFrontend)
- elseif (${BUILD_CONFIG} STREQUAL "test_all")
+ elseif (${GPGFRONTEND_BUILD_CONFIG} STREQUAL "test_all")
message(STATUS "Switch FULL_APPLICATION_BUILD")
set(FULL_APPLICATION_BUILD 1)
set(AppName GpgFrontend)
@@ -171,6 +171,14 @@ if (APPLE)
set(ENV{Qt5_DIR} /usr/local/opt/qt5/lib/cmake)
+ if (XCODE_BUILD)
+ set(XCODE_CODE_SIGN_IDENTITY "\"${XCODE_CODE_SIGN_IDENTITY}\"")
+ message(STATUS "XCODE_CODE_SIGN_IDENTITY ${XCODE_CODE_SIGN_IDENTITY}")
+ if (APPLE_SANDBOX)
+ add_compile_definitions(APPLE_SANDBOX)
+ endif ()
+ endif ()
+
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/src
${CMAKE_CURRENT_SOURCE_DIR}/third_party
@@ -216,10 +224,14 @@ endif ()
message(STATUS "OS_PLATFORM ${OS_PLATFORM}")
+if (GPG_STANDALONE_MODE)
+ add_compile_definitions(GPG_STANDALONE_MODE)
+endif ()
+
# Basic Envirnoment Configure
set(BASIC_ENV_CONFIG 1)
set(QT_MOC_CONFIG 1)
-set(ESAY_LOGGING_PP 1)
+set(EASY_LOGGING_PP 1)
if (LINUX_INSTALL_SOFTWARE)
include(GNUInstallDirs)
@@ -262,7 +274,7 @@ elseif (STABLE_APPLICATION_BUILD)
set(BASIC_ENV_CONFIG 1)
set(SMTP_SUPPORT 1)
set(MULTI_LANG_SUPPORT 1)
-elseif (TEST_BUILD)
+elseif (TEST_CORE_BUILD)
message(STATUS "Build Test Cases")
if (MODULES)
@@ -317,7 +329,7 @@ endif ()
add_subdirectory(third_party)
add_subdirectory(src)
-if (TEST_BUILD)
+if (TEST_CORE_BUILD)
include(CTest)
enable_testing()
add_subdirectory(test)
diff --git a/gpgfrontend.qrc b/gpgfrontend.qrc
index c7ecc963..461c488d 100644
--- a/gpgfrontend.qrc
+++ b/gpgfrontend.qrc
@@ -45,6 +45,7 @@
<file alias="key_generate.png">resource/icons/key_generate.png</file>
<file alias="key_import.png">resource/icons/key_import.png</file>
<file alias="kgpg_key2.png">resource/icons/kgpg_key2.png</file>
+ <file alias="key_package.png">resource/icons/key_package.png</file>
<file alias="misc_doc.png">resource/icons/misc_doc.png</file>
<file alias="quote.png">resource/icons/quote.png</file>
<file alias="signature.png">resource/icons/signature.png</file>
diff --git a/resource/icons/key_package.png b/resource/icons/key_package.png
new file mode 100644
index 00000000..6464cb9d
--- /dev/null
+++ b/resource/icons/key_package.png
Binary files differ
diff --git a/resource/plist/MacOSXBundleInfo.plist.in b/resource/plist/MacOSXBundleInfo.plist.in
new file mode 100644
index 00000000..55c42e1a
--- /dev/null
+++ b/resource/plist/MacOSXBundleInfo.plist.in
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
+ <key>CFBundleGetInfoString</key>
+ <string>${MACOSX_BUNDLE_INFO_STRING}</string>
+ <key>CFBundleIconFile</key>
+ <string>${MACOSX_BUNDLE_ICON_FILE}</string>
+ <key>CFBundleIdentifier</key>
+ <string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleLongVersionString</key>
+ <string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
+ <key>CFBundleName</key>
+ <string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
+ <key>CSResourcesFileMapped</key>
+ <true/>
+ <key>NSHumanReadableCopyright</key>
+ <string>${MACOSX_BUNDLE_COPYRIGHT}</string>
+ <key>LSApplicationCategoryType</key>
+ <string>public.app-category.utilities</string>
+</dict>
+</plist> \ No newline at end of file
diff --git a/resource/plist/entitlement.plist b/resource/plist/entitlement.plist
new file mode 100644
index 00000000..625c18bd
--- /dev/null
+++ b/resource/plist/entitlement.plist
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<plist version="1.0">
+ <dict>
+ <key>com.apple.security.app-sandbox</key>
+ <true/>
+ </dict>
+</plist> \ No newline at end of file
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 346b1524..a6c70923 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -31,8 +31,13 @@ if (APPLICATION_BUILD)
set(APP_ICON_RESOURCE_WINDOWS "${CMAKE_SOURCE_DIR}/gpgfrontend.rc")
set_property(SOURCE gpgfrontend.rc APPEND PROPERTY OBJECT_DEPENDS ${CMAKE_SOURCE_DIR}/gpgfrontend.ico)
- # Set Binary Output Path
- set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release)
+ if (NOT XCODE_BUILD)
+ # Set Binary Output Path
+ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release)
+ else ()
+ # Set Binary Output Path
+ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE})
+ endif ()
message(STATUS "CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
endif ()
@@ -114,6 +119,9 @@ if (APPLICATION_BUILD)
file(COPY ${CMAKE_SOURCE_DIR}/resource/css DESTINATION ${RESOURCE_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN)
file(COPY ${CMAKE_SOURCE_DIR}/resource/icons DESTINATION ${RESOURCE_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN)
file(COPY ${CMAKE_SOURCE_DIR}/TRANSLATORS DESTINATION ${RESOURCE_OUTPUT_DIRECTORY} FOLLOW_SYMLINK_CHAIN)
+ if (GPG_STANDALONE_MODE)
+ file(COPY ${CMAKE_SOURCE_DIR}/resource/gpg1.4 DESTINATION ${RESOURCE_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN)
+ endif ()
endif ()
if (APPLICATION_BUILD)
@@ -155,7 +163,7 @@ if (APPLICATION_BUILD)
if (${CMAKE_BUILD_TYPE} STREQUAL "Release")
if (MINGW)
add_executable(${AppName} WIN32 ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS})
- elseif (APPLE)
+ elseif (APPLE AND NOT XCODE_BUILD)
add_executable(${AppName} MACOSX_BUNDLE ${ICON_RESOURCE} ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS})
set_target_properties(${AppName} PROPERTIES
BUNDLE True
@@ -183,6 +191,38 @@ if (APPLICATION_BUILD)
COMMAND /bin/mkdir -p ./gpgfrontend/usr/lib
WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
COMMENT "Complement to build the required architecture")
+ elseif (APPLE AND XCODE_BUILD)
+ add_executable(${AppName} MACOSX_BUNDLE ${ICON_RESOURCE} ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS})
+ set_target_properties(${AppName} PROPERTIES
+ BUNDLE True
+ MACOSX_BUNDLE_GUI_IDENTIFIER pub.gpgfrontend.gpgfrontend
+ MACOSX_BUNDLE_BUNDLE_NAME ${AppName}
+ MACOSX_BUNDLE_LONG_VERSION_STRING ${BUILD_VERSION}
+ MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION}
+ MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
+ MACOSX_BUNDLE_COPYRIGHT "GPL-3.0"
+ MACOSX_BUNDLE_INFO_STRING "An OpenPGP Crypto Tool"
+ MACOSX_BUNDLE_ICON_FILE "gpgfrontend.icns"
+ MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/resource/plist/MacOSXBundleInfo.plist.in
+ )
+ add_custom_command(TARGET ${AppName} POST_BUILD
+ COMMAND /bin/rm -rf ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${AppName}.app/Contents/Resources
+ WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
+ COMMENT "Deleting Resources in App Bundle")
+ add_custom_command(TARGET ${AppName} POST_BUILD
+ COMMAND /bin/cp -rf ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Resources ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_BUILD_TYPE}/${AppName}.app/Contents/
+ WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
+ COMMENT "Copying Resources into App Bundle Resource")
+ add_custom_command(TARGET ${AppName} POST_BUILD
+ COMMAND macdeployqt ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_BUILD_TYPE}/${AppName}.app
+ WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
+ COMMENT "Resolving Qt Dependency")
+ 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 "Yes"
+ )
else ()
add_executable(${AppName} ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS})
endif ()
@@ -252,6 +292,8 @@ if (LINUX_INSTALL_SOFTWARE)
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
+ install(FILES ${CMAKE_SOURCE_DIR}/TRANSLATORS
+ DESTINATION /usr/local/share/${AppName}/)
install(FILES ${CMAKE_SOURCE_DIR}/resource/meta/pub.gpgfrontend.gpgfrontend.appdata.xml
DESTINATION /usr/share/metainfo/)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/resource/desktop/
@@ -274,7 +316,7 @@ if (LINUX_INSTALL_SOFTWARE)
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "amd64")
set(CPACK_PACKAGE_CONTACT "[email protected]")
SET(CPACK_DEBIAN_PACKAGE_MAINTAINER "Saturneric")
- set(CPACK_DEBIAN_PACKAGE_DEPENDS "gpg (>= 2.2), libqt5core5a (>= 5.9), libqt5gui5 (>= 5.9), libqt5widgets5 (>= 5.9), libqt5network5 (>= 5.9), libqt5printsupport5 (>= 5.9)")
+ set(CPACK_DEBIAN_PACKAGE_DEPENDS "gpg (>= 2.2), libqt5core5a (>= 5.9), libqt5gui5 (>= 5.9), libqt5widgets5 (>= 5.9), libqt5network5 (>= 5.9), libqt5printsupport5 (>= 5.9), libconfig++-dev (>=1.5)")
set(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}")
set(CPACK_PACKAGE_VERSION_MINOR "${PROJECT_VERSION_MINOR}")
set(CPACK_PACKAGE_VERSION_PATCH "${PROJECT_VERSION_PATCH}")
diff --git a/src/GpgFrontend.h.in b/src/GpgFrontend.h.in
index 622c2b07..11934550 100644
--- a/src/GpgFrontend.h.in
+++ b/src/GpgFrontend.h.in
@@ -39,6 +39,8 @@
#ifdef WINDOWS
#include <clocale>
#undef vsnprintf
+#undef sprintf
+#undef snprintf
#endif
// logging
diff --git a/src/gpg/CMakeLists.txt b/src/gpg/CMakeLists.txt
index 19b9f00f..0ccc8171 100644
--- a/src/gpg/CMakeLists.txt
+++ b/src/gpg/CMakeLists.txt
@@ -9,8 +9,8 @@ set(UTILS_DIR ${CMAKE_SOURCE_DIR}/utils)
set(GPGME_LIB_DIR ${UTILS_DIR}/gpgme/lib)
-if (ESAY_LOGGING_PP)
- message(STATUS "Link ESAY_LOGGING_PP")
+if (EASY_LOGGING_PP)
+ message(STATUS "Link EASY_LOGGING_PP")
set(THIRD_PARTY_LIBS easy_logging_pp config++)
endif ()
@@ -33,6 +33,13 @@ elseif (APPLE)
${BOOST_LIBS}
${libgpgme} ${libgpg-error} ${libassuan}
dl)
+ if (XCODE_BUILD)
+ set_target_properties(gpg_core
+ PROPERTIES
+ ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}
+ LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}
+ LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE})
+ endif ()
else ()
find_library(libgpgme NAMES libgpgme.a)
find_library(libgpg-error NAMES libgpg-error.a)
diff --git a/src/gpg/GpgConstants.cpp b/src/gpg/GpgConstants.cpp
index fd3c56b4..100bf8f8 100644
--- a/src/gpg/GpgConstants.cpp
+++ b/src/gpg/GpgConstants.cpp
@@ -42,6 +42,10 @@ const char* GpgFrontend::GpgConstants::PGP_SIGNATURE_BEGIN =
"-----BEGIN PGP SIGNATURE-----";
const char* GpgFrontend::GpgConstants::PGP_SIGNATURE_END =
"-----END PGP SIGNATURE-----";
+const char* GpgFrontend::GpgConstants::PGP_PUBLIC_KEY_BEGIN =
+ "------BEGIN PGP PUBLIC KEY BLOCK-----";
+const char* GpgFrontend::GpgConstants::PGP_PRIVATE_KEY_BEGIN =
+ "-----BEGIN PGP PRIVATE KEY BLOCK-----";
const char* GpgFrontend::GpgConstants::GPG_FRONTEND_SHORT_CRYPTO_HEAD =
"GpgF_Scpt://";
@@ -215,6 +219,12 @@ GpgFrontend::GpgVerifyResult GpgFrontend::_new_result(
return {result, _result_ref_deletor()};
}
+GpgFrontend::GpgGenKeyResult GpgFrontend::_new_result(
+ gpgme_genkey_result_t&& result) {
+ gpgme_result_ref(result);
+ return {result, _result_ref_deletor()};
+}
+
void GpgFrontend::_result_ref_deletor::operator()(void* _result) {
DLOG(INFO) << _("Called") << _result;
if (_result != nullptr) gpgme_result_unref(_result);
diff --git a/src/gpg/GpgConstants.h b/src/gpg/GpgConstants.h
index 14895df7..d2f9b0b6 100644
--- a/src/gpg/GpgConstants.h
+++ b/src/gpg/GpgConstants.h
@@ -58,12 +58,14 @@ using GpgEncrResult = std::shared_ptr<struct _gpgme_op_encrypt_result>;
using GpgDecrResult = std::shared_ptr<struct _gpgme_op_decrypt_result>;
using GpgSignResult = std::shared_ptr<struct _gpgme_op_sign_result>;
using GpgVerifyResult = std::shared_ptr<struct _gpgme_op_verify_result>;
+using GpgGenKeyResult = std::shared_ptr<struct _gpgme_op_genkey_result>;
// Convert from gpgme_xxx_result to GpgXXXResult
GpgEncrResult _new_result(gpgme_encrypt_result_t&& result);
GpgDecrResult _new_result(gpgme_decrypt_result_t&& result);
GpgSignResult _new_result(gpgme_sign_result_t&& result);
GpgVerifyResult _new_result(gpgme_verify_result_t&& result);
+GpgGenKeyResult _new_result(gpgme_genkey_result_t&& result);
// Error Info Printer
GpgError check_gpg_error(GpgError err);
@@ -85,6 +87,10 @@ std::string get_only_file_name_with_path(const std::string& path);
// Check
int text_is_signed(BypeArrayRef text);
+// Channels
+const int GPGFRONTEND_DEFAULT_CHANNEL = 0;
+const int GPGFRONTEND_NON_ASCII_CHANNEL = 2;
+
class GpgConstants {
public:
static const char* PGP_CRYPT_BEGIN;
@@ -93,8 +99,11 @@ class GpgConstants {
static const char* PGP_SIGNED_END;
static const char* PGP_SIGNATURE_BEGIN;
static const char* PGP_SIGNATURE_END;
+ static const char* PGP_PUBLIC_KEY_BEGIN;
+ static const char* PGP_PRIVATE_KEY_BEGIN;
static const char* GPG_FRONTEND_SHORT_CRYPTO_HEAD;
};
+
} // namespace GpgFrontend
#endif // GPG_CONSTANTS_H
diff --git a/src/gpg/GpgContext.cpp b/src/gpg/GpgContext.cpp
index a8b86619..e3f10056 100644
--- a/src/gpg/GpgContext.cpp
+++ b/src/gpg/GpgContext.cpp
@@ -29,6 +29,7 @@
#include <functional>
#include <string>
+#include <utility>
#include "GpgConstants.h"
@@ -36,23 +37,19 @@
#include <windows.h>
#endif
-#define INT2VOIDP(i) (void*)(uintptr_t)(i)
-
namespace GpgFrontend {
/**
* Constructor
* Set up gpgme-context, set paths to app-run path
*/
-GpgContext::GpgContext(bool independent_database, std::string db_path,
- int channel)
- : SingletonFunctionObject<GpgContext>(channel) {
+GpgContext::GpgContext(const GpgContextInitArgs &args) : args_(args) {
static bool _first = true;
if (_first) {
/* Initialize the locale environment. */
LOG(INFO) << "locale" << setlocale(LC_CTYPE, nullptr);
- gpgme_check_version(nullptr);
+ info_.GpgMEVersion = gpgme_check_version(nullptr);
gpgme_set_locale(nullptr, LC_CTYPE, setlocale(LC_CTYPE, nullptr));
#ifdef LC_MESSAGES
gpgme_set_locale(nullptr, LC_MESSAGES, setlocale(LC_MESSAGES, nullptr));
@@ -64,66 +61,160 @@ GpgContext::GpgContext(bool independent_database, std::string db_path,
check_gpg_error(gpgme_new(&_p_ctx));
_ctx_ref = CtxRefHandler(_p_ctx);
- auto engineInfo = gpgme_ctx_get_engine_info(*this);
+ if (args.gpg_alone) {
+ info_.AppPath = args.gpg_path;
+ auto err = gpgme_ctx_set_engine_info(_ctx_ref.get(), GPGME_PROTOCOL_OpenPGP,
+ info_.AppPath.c_str(),
+ info_.DatabasePath.c_str());
+ assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR);
+ }
+ auto engine_info = gpgme_ctx_get_engine_info(*this);
// Check ENV before running
- bool check_pass = false, find_openpgp = false, find_gpgconf = false,
- find_assuan = false, find_cms = false;
- while (engineInfo != nullptr) {
- if (engineInfo->protocol == GPGME_PROTOCOL_GPGCONF &&
- strcmp(engineInfo->version, "1.0.0") != 0)
- find_gpgconf = true;
- if (engineInfo->protocol == GPGME_PROTOCOL_OpenPGP &&
- strcmp(engineInfo->version, "1.0.0") != 0)
- find_openpgp = true, info.AppPath = engineInfo->file_name,
- info.DatabasePath = "default", info.GnupgVersion = engineInfo->version;
- if (engineInfo->protocol == GPGME_PROTOCOL_CMS &&
- strcmp(engineInfo->version, "1.0.0") != 0)
- find_cms = true;
- if (engineInfo->protocol == GPGME_PROTOCOL_ASSUAN) find_assuan = true;
- engineInfo = engineInfo->next;
+ bool check_passed = false, find_openpgp = false, find_gpgconf = false,
+ find_cms = false;
+
+ while (engine_info != nullptr) {
+ if (!strcmp(engine_info->version, "1.0.0")) {
+ engine_info = engine_info->next;
+ continue;
+ }
+
+ DLOG(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);
+
+ switch (engine_info->protocol) {
+ case GPGME_PROTOCOL_OpenPGP:
+ find_openpgp = true;
+ info_.AppPath = engine_info->file_name;
+ info_.GnupgVersion = engine_info->version;
+ break;
+ case GPGME_PROTOCOL_CMS:
+ find_cms = true;
+ info_.CMSPath = engine_info->file_name;
+ break;
+ case GPGME_PROTOCOL_GPGCONF:
+ find_gpgconf = true;
+ info_.GpgConfPath = engine_info->file_name;
+ break;
+ case GPGME_PROTOCOL_ASSUAN:
+ break;
+ case GPGME_PROTOCOL_G13:
+ break;
+ case GPGME_PROTOCOL_UISERVER:
+ break;
+ case GPGME_PROTOCOL_SPAWN:
+ break;
+ case GPGME_PROTOCOL_DEFAULT:
+ break;
+ case GPGME_PROTOCOL_UNKNOWN:
+ break;
+ }
+ engine_info = engine_info->next;
}
- if (find_gpgconf && find_openpgp && find_cms && find_assuan)
- check_pass = true;
+ // conditional check
+ if ((info_.GnupgVersion >= "2.0.0" && find_gpgconf && find_openpgp &&
+ find_cms) ||
+ (info_.GnupgVersion > "1.0.0" && find_gpgconf))
+ check_passed = true;
- if (!check_pass) {
- good_ = false;
+ if (!check_passed) {
+ this->good_ = false;
+ LOG(ERROR) << "Env check failed";
return;
} else {
- LOG(INFO) << "Gnupg Version" << info.GnupgVersion;
-
- // Set Independent Database
- if (independent_database) {
- info.DatabasePath = db_path;
- auto err = gpgme_ctx_set_engine_info(
- _ctx_ref.get(), GPGME_PROTOCOL_OpenPGP, info.AppPath.c_str(),
- info.DatabasePath.c_str());
- assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR);
- }
+ DLOG(INFO) << "gnupg version" << info_.GnupgVersion;
+ init_ctx();
+ good_ = true;
+ }
+}
+
+void GpgContext::init_ctx() {
+ // Set Independent Database
+ if (info_.GnupgVersion <= "2.0.0" && args_.independent_database) {
+ info_.DatabasePath = args_.db_path;
+ DLOG(INFO) << "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());
+ assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR);
+ } else {
+ info_.DatabasePath = "default";
+ }
+ if (args_.ascii) {
/** Setting the output type must be done at the beginning */
/** think this means ascii-armor --> ? */
gpgme_set_armor(*this, 1);
- // Speed up loading process
- gpgme_set_offline(*this, 1);
+ } else {
+ /** Setting the output type must be done at the beginning */
+ /** think this means ascii-armor --> ? */
+ gpgme_set_armor(*this, 0);
+ }
+
+ // Speed up loading process
+ gpgme_set_offline(*this, 1);
+ if (info_.GnupgVersion >= "2.0.0") {
check_gpg_error(gpgme_set_keylist_mode(
*this, GPGME_KEYLIST_MODE_LOCAL | GPGME_KEYLIST_MODE_WITH_SECRET |
GPGME_KEYLIST_MODE_SIGS | GPGME_KEYLIST_MODE_SIG_NOTATIONS |
GPGME_KEYLIST_MODE_WITH_TOFU));
- good_ = true;
+ } else {
+ check_gpg_error(gpgme_set_keylist_mode(
+ *this, GPGME_KEYLIST_MODE_LOCAL | GPGME_KEYLIST_MODE_SIGS |
+ GPGME_KEYLIST_MODE_SIG_NOTATIONS |
+ GPGME_KEYLIST_MODE_WITH_TOFU));
+ }
+
+ // 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);
}
}
bool GpgContext::good() const { return good_; }
-void GpgContext::SetPassphraseCb(decltype(test_passphrase_cb) cb) const {
- gpgme_set_passphrase_cb(*this, cb, nullptr);
+void GpgContext::SetPassphraseCb(gpgme_passphrase_cb_t cb) const {
+ if (info_.GnupgVersion >= "2.1.0") {
+ if (gpgme_get_pinentry_mode(*this) != GPGME_PINENTRY_MODE_LOOPBACK) {
+ gpgme_set_pinentry_mode(*this, GPGME_PINENTRY_MODE_LOOPBACK);
+ }
+ gpgme_set_passphrase_cb(*this, cb, nullptr);
+ } else {
+ LOG(ERROR) << "Not supported for gnupg version" << info_.GnupgVersion;
+ }
+}
+
+gpgme_error_t GpgContext::test_passphrase_cb(void *opaque, const char *uid_hint,
+ const char *passphrase_info,
+ int last_was_bad, int fd) {
+ size_t res;
+ std::string pass = "abcdefg\n";
+ auto pass_len = pass.size();
+
+ size_t off = 0;
+
+ do {
+ res = gpgme_io_write(fd, &pass[off], pass_len - off);
+ if (res > 0) off += res;
+ } while (res > 0 && off != pass_len);
+
+ return off == pass_len ? 0 : gpgme_error_from_errno(errno);
}
-std::string GpgContext::getGpgmeVersion() {
- return {gpgme_check_version(nullptr)};
+gpgme_error_t GpgContext::test_status_cb(void *hook, const char *keyword,
+ const char *args) {
+ LOG(INFO) << "keyword" << keyword;
+ return GPG_ERR_NO_ERROR;
}
} // namespace GpgFrontend \ No newline at end of file
diff --git a/src/gpg/GpgContext.h b/src/gpg/GpgContext.h
index 5812f49f..146f0794 100644
--- a/src/gpg/GpgContext.h
+++ b/src/gpg/GpgContext.h
@@ -32,34 +32,49 @@
namespace GpgFrontend {
+struct GpgContextInitArgs {
+ // make no sense for gpg2
+ bool independent_database = false;
+ std::string db_path = {};
+ bool gpg_alone = false;
+ std::string gpg_path = {};
+ bool test_mode = false;
+ bool ascii = true;
+
+ GpgContextInitArgs() = default;
+};
+
/**
* Custom Encapsulation of GpgME APIs
*/
class GpgContext : public SingletonFunctionObject<GpgContext> {
public:
- explicit GpgContext(bool independent_database = false,
- std::string path = std::string(), int channel = 0);
+ explicit GpgContext(const GpgContextInitArgs& args = {});
+
+ explicit GpgContext(int channel)
+ : SingletonFunctionObject<GpgContext>(channel) {}
~GpgContext() override = default;
[[nodiscard]] bool good() const;
- [[nodiscard]] const GpgInfo& GetInfo() const { return info; }
-
- static std::string getGpgmeVersion();
+ [[nodiscard]] const GpgInfo& GetInfo() const { return info_; }
operator gpgme_ctx_t() const { return _ctx_ref.get(); }
private:
- GpgInfo info;
+ GpgInfo info_;
+ GpgContextInitArgs args_;
- struct _ctx_ref_deletor {
+ void init_ctx();
+
+ struct _ctx_ref_deleter {
void operator()(gpgme_ctx_t _ctx) {
if (_ctx != nullptr) gpgme_release(_ctx);
}
};
- using CtxRefHandler = std::unique_ptr<struct gpgme_context, _ctx_ref_deletor>;
+ using CtxRefHandler = std::unique_ptr<struct gpgme_context, _ctx_ref_deleter>;
CtxRefHandler _ctx_ref = nullptr;
bool good_ = true;
@@ -67,28 +82,12 @@ class GpgContext : public SingletonFunctionObject<GpgContext> {
public:
static gpgme_error_t test_passphrase_cb(void* opaque, const char* uid_hint,
const char* passphrase_info,
- int last_was_bad, int fd) {
- LOG(INFO) << "test_passphrase_cb Called";
- size_t res;
- std::string pass = "abcdefg\n";
- auto pass_len = pass.size();
-
- size_t off = 0;
-
- (void)opaque;
- (void)uid_hint;
- (void)passphrase_info;
- (void)last_was_bad;
-
- do {
- res = gpgme_io_write(fd, &pass[off], pass_len - off);
- if (res > 0) off += res;
- } while (res > 0 && off != pass_len);
+ int last_was_bad, int fd);
- return off == pass_len ? 0 : gpgme_error_from_errno(errno);
- }
+ static gpgme_error_t test_status_cb(void* hook, const char* keyword,
+ const char* args);
- void SetPassphraseCb(decltype(test_passphrase_cb) func) const;
+ void SetPassphraseCb(gpgme_passphrase_cb_t func) const;
};
} // namespace GpgFrontend
diff --git a/src/gpg/GpgCoreInit.cpp b/src/gpg/GpgCoreInit.cpp
new file mode 100644
index 00000000..3f07d2b1
--- /dev/null
+++ b/src/gpg/GpgCoreInit.cpp
@@ -0,0 +1,52 @@
+/**
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "GpgCoreInit.h"
+
+#include "GpgContext.h"
+
+void GpgFrontend::init_gpgfrontend_core() {
+ GpgFrontend::GpgContext::CreateInstance(
+ GPGFRONTEND_DEFAULT_CHANNEL,
+ [&]() -> std::unique_ptr<GpgFrontend::GpgContext> {
+ GpgFrontend::GpgContextInitArgs args;
+ return std::make_unique<GpgFrontend::GpgContext>(args);
+ });
+
+ GpgFrontend::GpgContext::CreateInstance(
+ GPGFRONTEND_NON_ASCII_CHANNEL,
+ [&]() -> std::unique_ptr<GpgFrontend::GpgContext> {
+ GpgFrontend::GpgContextInitArgs args;
+ args.ascii = false;
+ return std::make_unique<GpgFrontend::GpgContext>(args);
+ });
+}
+
+void GpgFrontend::new_default_settings_channel(int channel) {
+ GpgFrontend::GpgContext::CreateInstance(
+ channel, [&]() -> std::unique_ptr<GpgFrontend::GpgContext> {
+ GpgFrontend::GpgContextInitArgs args;
+ return std::make_unique<GpgFrontend::GpgContext>(args);
+ });
+} \ No newline at end of file
diff --git a/src/gpg/GpgCoreInit.h b/src/gpg/GpgCoreInit.h
new file mode 100644
index 00000000..577f46a3
--- /dev/null
+++ b/src/gpg/GpgCoreInit.h
@@ -0,0 +1,40 @@
+/**
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef GPGFRONTEND_GPGCOREINIT_H
+#define GPGFRONTEND_GPGCOREINIT_H
+
+#include "GpgConstants.h"
+
+namespace GpgFrontend {
+
+// Init
+void init_gpgfrontend_core();
+
+void new_default_settings_channel(
+ int channel = GpgFrontend::GPGFRONTEND_DEFAULT_CHANNEL);
+
+} // namespace GpgFrontend
+
+#endif // GPGFRONTEND_GPGCOREINIT_H
diff --git a/src/gpg/GpgFunctionObject.h b/src/gpg/GpgFunctionObject.h
index 6f1d60af..404b2f84 100644
--- a/src/gpg/GpgFunctionObject.h
+++ b/src/gpg/GpgFunctionObject.h
@@ -34,63 +34,61 @@
#include <stdexcept>
#include <string>
+#include "GpgConstants.h"
+
namespace GpgFrontend {
template <typename T>
class SingletonFunctionObject {
public:
- static T& GetInstance(int channel = 0) {
- if (!channel) {
- std::lock_guard<std::mutex> guard(_instance_mutex);
- if (_instance == nullptr) _instance = std::make_unique<T>();
- return *_instance;
- } else {
- // read _instances_map
- decltype(_instances_map.end()) _it;
- {
- std::shared_lock lock(_instances_mutex);
- _it = _instances_map.find(channel);
- }
- if (_it != _instances_map.end())
- return *_it->second;
- else
- return CreateInstance(channel);
- }
+ static T& GetInstance(
+ int channel = GpgFrontend::GPGFRONTEND_DEFAULT_CHANNEL) {
+ static_assert(std::is_base_of<SingletonFunctionObject<T>, T>::value,
+ "T not derived from SingletonFunctionObject<T>");
+
+ auto _p_pbj = find_object_in_channel(channel);
+ if (_p_pbj == nullptr)
+ return *set_object_in_channel(channel, std::make_unique<T>(channel));
+ else
+ return *_p_pbj;
+ }
+
+ static T& CreateInstance(int channel,
+ std::function<std::unique_ptr<T>(void)> factory) {
+ static_assert(std::is_base_of<SingletonFunctionObject<T>, T>::value,
+ "T not derived from SingletonFunctionObject<T>");
+
+ auto _p_pbj = find_object_in_channel(channel);
+ if (_p_pbj == nullptr)
+ return *set_object_in_channel(channel, std::move(factory()));
+ else
+ return *_p_pbj;
}
static T& CreateInstance(int channel, std::unique_ptr<T> p_obj = nullptr) {
- if (!channel) return *_instance;
+ static_assert(std::is_base_of<SingletonFunctionObject<T>, T>::value,
+ "T not derived from SingletonFunctionObject<T>");
+
+ auto _p_pbj = find_object_in_channel(channel);
+ if (_p_pbj == nullptr)
+ return *set_object_in_channel(channel, std::move(p_obj));
+ else
+ return *_p_pbj;
+ }
- // read _instances_map
+ static T& ReleaseChannel(int channel) {
decltype(_instances_map.end()) _it;
{
std::shared_lock lock(_instances_mutex);
_it = _instances_map.find(channel);
}
- if (_it == _instances_map.end()) {
- {
- std::lock_guard<std::mutex> guard(_default_channel_mutex);
- int tmp = channel;
- std::swap(_default_channel, tmp);
- if (p_obj == nullptr) p_obj = std::make_unique<T>();
- std::swap(_default_channel, tmp);
- }
- T* obj = p_obj.get();
-
- // change _instances_map
- {
- std::unique_lock lock(_instances_mutex);
- _instances_map.insert({channel, std::move(p_obj)});
- }
- return *obj;
- } else {
- return *_it->second;
- }
+ if (_it != _instances_map.end()) _instances_map.erase(_it);
+ DLOG(INFO) << "channel" << channel << "released";
}
static int GetDefaultChannel() { return _default_channel; }
- int GetChannel() const { return channel_; }
+ [[nodiscard]] int GetChannel() const { return channel_; }
SingletonFunctionObject(T&&) = delete;
@@ -99,27 +97,52 @@ class SingletonFunctionObject {
void operator=(const T&) = delete;
protected:
- SingletonFunctionObject() {}
+ SingletonFunctionObject() = default;
- SingletonFunctionObject(int channel) : channel_(channel) {}
+ explicit SingletonFunctionObject(int channel) : channel_(channel) {}
virtual ~SingletonFunctionObject() = default;
+ void SetChannel(int channel) { this->channel_ = channel; }
+
private:
int channel_ = _default_channel;
static int _default_channel;
- static std::mutex _default_channel_mutex;
static std::mutex _instance_mutex;
static std::shared_mutex _instances_mutex;
static std::unique_ptr<T> _instance;
static std::map<int, std::unique_ptr<T>> _instances_map;
-};
-template <typename T>
-int SingletonFunctionObject<T>::_default_channel = 0;
+ static T* find_object_in_channel(int channel) {
+ // read _instances_map
+ decltype(_instances_map.end()) _it;
+ {
+ std::shared_lock lock(_instances_mutex);
+ _it = _instances_map.find(channel);
+ if (_it == _instances_map.end())
+ return nullptr;
+ else
+ return _it->second.get();
+ }
+ }
+
+ static T* set_object_in_channel(int channel, std::unique_ptr<T> p_obj) {
+ {
+ if (p_obj == nullptr) p_obj = std::make_unique<T>();
+ T* obj = p_obj.get();
+ obj->SetChannel(channel);
+ {
+ std::unique_lock lock(_instances_mutex);
+ _instances_map.insert({channel, std::move(p_obj)});
+ }
+ return obj;
+ }
+ }
+};
template <typename T>
-std::mutex SingletonFunctionObject<T>::_default_channel_mutex;
+int SingletonFunctionObject<T>::_default_channel =
+ GpgFrontend::GPGFRONTEND_DEFAULT_CHANNEL;
template <typename T>
std::mutex SingletonFunctionObject<T>::_instance_mutex;
diff --git a/src/gpg/GpgGenKeyInfo.cpp b/src/gpg/GpgGenKeyInfo.cpp
index 4a0a99fc..f67aaa1f 100644
--- a/src/gpg/GpgGenKeyInfo.cpp
+++ b/src/gpg/GpgGenKeyInfo.cpp
@@ -32,18 +32,41 @@
#include <string>
#include <vector>
-const std::vector<std::string> GpgFrontend::GenKeyInfo::SupportedKeyAlgo = {
- "RSA", "DSA", "ED25519"};
-
-const std::vector<std::string> GpgFrontend::GenKeyInfo::SupportedSubkeyAlgo = {
- "RSA", "DSA", "ED25519", "ELG"};
-
void GpgFrontend::GenKeyInfo::setAlgo(const std::string &m_algo) {
- LOG(INFO) << "GpgFrontend::GenKeyInfo::setAlgo m_algo" << m_algo;
+ LOG(INFO) << "set algo" << m_algo;
+ // Check algo if supported
+ std::string algo_args = std::string(m_algo);
+ boost::algorithm::to_upper(algo_args);
+ if (standalone_) {
+ if (!subkey_) {
+ auto support_algo = getSupportedKeyAlgoStandalone();
+ auto it = std::find(support_algo.begin(), support_algo.end(), algo_args);
+ // Algo Not Supported
+ if (it == support_algo.end()) return;
+ } else {
+ auto support_algo = getSupportedSubkeyAlgoStandalone();
+ auto it = std::find(support_algo.begin(), support_algo.end(), algo_args);
+ // Algo Not Supported
+ if (it == support_algo.end()) return;
+ }
+ } else {
+ if (!subkey_) {
+ auto support_algo = getSupportedKeyAlgo();
+ auto it = std::find(support_algo.begin(), support_algo.end(), algo_args);
+ // Algo Not Supported
+ if (it == support_algo.end()) return;
+ } else {
+ auto support_algo = getSupportedSubkeyAlgo();
+ auto it = std::find(support_algo.begin(), support_algo.end(), algo_args);
+ // Algo Not Supported
+ if (it == support_algo.end()) return;
+ }
+ }
+ // reset all options
reset_options();
- if (!this->subKey) {
+ if (!this->subkey_) {
this->setAllowCertification(true);
} else {
this->setAllowCertification(false);
@@ -51,23 +74,20 @@ void GpgFrontend::GenKeyInfo::setAlgo(const std::string &m_algo) {
this->allowChangeCertification = false;
- std::string lower_algo = std::string(m_algo);
- boost::algorithm::to_lower(lower_algo);
-
- LOG(INFO) << "GpgFrontend::GenKeyInfo::setAlgo lower_algo" << lower_algo;
+ if (!standalone_) boost::algorithm::to_lower(algo_args);
- if (lower_algo == "rsa") {
+ if (algo_args == "rsa") {
/**
* RSA is the world’s premier asymmetric cryptographic algorithm,
* and is built on the difficulty of factoring extremely large composites.
* GnuPG supports RSA with key sizes of between 1024 and 4096 bits.
*/
- suggestMinKeySize = 1024;
- suggestMaxKeySize = 4096;
- suggestSizeAdditionStep = 1024;
+ suggest_min_key_size_ = 1024;
+ suggest_max_key_size_ = 4096;
+ suggest_size_addition_step_ = 1024;
setKeySize(2048);
- } else if (lower_algo == "dsa") {
+ } else if (algo_args == "dsa") {
/**
* Algorithm (DSA) as a government standard for digital signatures.
* Originally, it supported key lengths between 512 and 1024 bits.
@@ -77,42 +97,40 @@ void GpgFrontend::GenKeyInfo::setAlgo(const std::string &m_algo) {
setAllowEncryption(false);
allowChangeEncryption = false;
- suggestMinKeySize = 1024;
- suggestMaxKeySize = 3072;
- suggestSizeAdditionStep = 1024;
+ suggest_min_key_size_ = 1024;
+ suggest_max_key_size_ = 3072;
+ suggest_size_addition_step_ = 1024;
setKeySize(2048);
- } else if (lower_algo == "ed25519") {
+ } else if (algo_args == "ed25519") {
/**
* GnuPG supports the Elgamal asymmetric encryption algorithm in key lengths
* ranging from 1024 to 4096 bits.
*/
-
setAllowEncryption(false);
allowChangeEncryption = false;
- suggestMinKeySize = -1;
- suggestMaxKeySize = -1;
- suggestSizeAdditionStep = -1;
+ suggest_min_key_size_ = -1;
+ suggest_max_key_size_ = -1;
+ suggest_size_addition_step_ = -1;
setKeySize(-1);
- } else if (lower_algo == "elg") {
+ } else if (algo_args == "elg") {
/**
* GnuPG supports the Elgamal asymmetric encryption algorithm in key lengths
* ranging from 1024 to 4096 bits.
*/
-
setAllowAuthentication(false);
allowChangeAuthentication = false;
setAllowSigning(false);
allowChangeSigning = false;
- suggestMinKeySize = 1024;
- suggestMaxKeySize = 4096;
- suggestSizeAdditionStep = 1024;
+ suggest_min_key_size_ = 1024;
+ suggest_max_key_size_ = 4096;
+ suggest_size_addition_step_ = 1024;
setKeySize(2048);
}
- this->algo = lower_algo;
+ this->algo_ = algo_args;
}
void GpgFrontend::GenKeyInfo::reset_options() {
@@ -128,37 +146,37 @@ void GpgFrontend::GenKeyInfo::reset_options() {
allowChangeAuthentication = true;
setAllowAuthentication(true);
- passPhrase.clear();
+ passphrase_.clear();
}
std::string GpgFrontend::GenKeyInfo::getKeySizeStr() const {
- if (keySize > 0) {
- return std::to_string(keySize);
+ if (key_size_ > 0) {
+ return std::to_string(key_size_);
} else {
return {};
}
}
void GpgFrontend::GenKeyInfo::setKeySize(int m_key_size) {
- if (m_key_size < suggestMinKeySize || m_key_size > suggestMaxKeySize) {
+ if (m_key_size < suggest_min_key_size_ ||
+ m_key_size > suggest_max_key_size_) {
return;
}
- GenKeyInfo::keySize = m_key_size;
+ GenKeyInfo::key_size_ = m_key_size;
}
void GpgFrontend::GenKeyInfo::setExpired(
const boost::posix_time::ptime &m_expired) {
using namespace boost::gregorian;
- auto current = boost::posix_time::second_clock::local_time();
- if (isNonExpired() && m_expired < current + years(2)) {
- GenKeyInfo::expired = m_expired;
+ if (!isNonExpired()) {
+ GenKeyInfo::expired_ = m_expired;
}
}
void GpgFrontend::GenKeyInfo::setNonExpired(bool m_non_expired) {
using namespace boost::posix_time;
- if (!m_non_expired) this->expired = from_time_t(0);
- GenKeyInfo::nonExpired = m_non_expired;
+ if (!m_non_expired) this->expired_ = from_time_t(0);
+ GenKeyInfo::non_expired_ = m_non_expired;
}
void GpgFrontend::GenKeyInfo::setAllowEncryption(bool m_allow_encryption) {
@@ -170,3 +188,35 @@ void GpgFrontend::GenKeyInfo::setAllowCertification(
if (allowChangeCertification)
GenKeyInfo::allowCertification = m_allow_certification;
}
+
+GpgFrontend::GenKeyInfo::GenKeyInfo(bool m_is_sub_key, bool m_standalone)
+ : standalone_(m_standalone), subkey_(m_is_sub_key) {
+ setAlgo("rsa");
+}
+
+const std::vector<std::string> &GpgFrontend::GenKeyInfo::getSupportedKeyAlgo() {
+ static const std::vector<std::string> support_key_algo = {"RSA", "DSA",
+ "ED25519"};
+ return support_key_algo;
+}
+
+const std::vector<std::string>
+ &GpgFrontend::GenKeyInfo::getSupportedSubkeyAlgo() {
+ static const std::vector<std::string> support_subkey_algo = {"RSA", "DSA",
+ "ED25519"};
+ return support_subkey_algo;
+}
+
+const std::vector<std::string>
+ &GpgFrontend::GenKeyInfo::getSupportedKeyAlgoStandalone() {
+ static const std::vector<std::string> support_subkey_algo_standalone = {
+ "RSA", "DSA"};
+ return support_subkey_algo_standalone;
+}
+
+const std::vector<std::string>
+ &GpgFrontend::GenKeyInfo::getSupportedSubkeyAlgoStandalone() {
+ static const std::vector<std::string> support_subkey_algo_standalone = {
+ "RSA", "DSA", "ELG-E"};
+ return support_subkey_algo_standalone;
+}
diff --git a/src/gpg/GpgGenKeyInfo.h b/src/gpg/GpgGenKeyInfo.h
index 14290e17..8f7d19ea 100644
--- a/src/gpg/GpgGenKeyInfo.h
+++ b/src/gpg/GpgGenKeyInfo.h
@@ -27,72 +27,97 @@
#include <boost/date_time.hpp>
#include <boost/date_time/gregorian/greg_duration_types.hpp>
+#include <boost/format.hpp>
#include <string>
#include <vector>
namespace GpgFrontend {
class GenKeyInfo {
- bool subKey = true;
- std::string userid;
- std::string algo;
- int keySize = 2048;
- boost::posix_time::ptime expired =
+ bool standalone_ = false;
+ bool subkey_ = false;
+ std::string name_;
+ std::string email_;
+ std::string comment_;
+
+ std::string algo_;
+ int key_size_ = 2048;
+ boost::posix_time::ptime expired_ =
boost::posix_time::second_clock::local_time() +
boost::gregorian::years(2);
- bool nonExpired = false;
+ bool non_expired_ = false;
- bool noPassPhrase = false;
- bool allowNoPassPhrase = true;
+ bool no_passphrase_ = false;
+ bool allow_no_pass_phrase_ = true;
- int suggestMaxKeySize = 4096;
- int suggestSizeAdditionStep = 1024;
- int suggestMinKeySize = 1024;
+ int suggest_max_key_size_ = 4096;
+ int suggest_size_addition_step_ = 1024;
+ int suggest_min_key_size_ = 1024;
- std::string passPhrase;
+ std::string passphrase_;
public:
- static const std::vector<std::string> SupportedKeyAlgo;
+ static const std::vector<std::string> &getSupportedKeyAlgo();
- static const std::vector<std::string> SupportedSubkeyAlgo;
+ static const std::vector<std::string> &getSupportedSubkeyAlgo();
- [[nodiscard]] bool isSubKey() const { return subKey; }
+ static const std::vector<std::string> &getSupportedKeyAlgoStandalone();
- void setIsSubKey(bool m_sub_key) { GenKeyInfo::subKey = m_sub_key; }
+ static const std::vector<std::string> &getSupportedSubkeyAlgoStandalone();
- [[nodiscard]] const std::string &getUserid() const { return userid; }
+ [[nodiscard]] bool isSubKey() const { return subkey_; }
- void setUserid(const std::string &m_userid) { GenKeyInfo::userid = m_userid; }
+ void setIsSubKey(bool m_sub_key) { GenKeyInfo::subkey_ = m_sub_key; }
- [[nodiscard]] const std::string &getAlgo() const { return algo; }
+ [[nodiscard]] std::string getUserid() const {
+ auto uid_format = boost::format("%1%(%2%)<%3%>") % this->name_ %
+ this->comment_ % this->email_;
+ return uid_format.str();
+ }
+
+ void setName(const std::string &m_name) { this->name_ = m_name; }
+
+ void setEmail(const std::string &m_email) { this->email_ = m_email; }
+
+ void setComment(const std::string &m_comment) { this->comment_ = m_comment; }
+
+ [[nodiscard]] std::string getName() const { return name_; }
+
+ [[nodiscard]] std::string getEmail() const { return email_; }
+
+ [[nodiscard]] std::string getComment() const { return comment_; }
+
+ [[nodiscard]] const std::string &getAlgo() const { return algo_; }
void setAlgo(const std::string &m_algo);
[[nodiscard]] std::string getKeySizeStr() const;
- [[nodiscard]] int getKeySize() const { return keySize; }
+ [[nodiscard]] int getKeySize() const { return key_size_; }
void setKeySize(int m_key_size);
[[nodiscard]] const boost::posix_time::ptime &getExpired() const {
- return expired;
+ return expired_;
}
void setExpired(const boost::posix_time::ptime &m_expired);
- [[nodiscard]] bool isNonExpired() const { return nonExpired; }
+ [[nodiscard]] bool isNonExpired() const { return non_expired_; }
void setNonExpired(bool m_non_expired);
- [[nodiscard]] bool isNoPassPhrase() const { return this->noPassPhrase; }
+ [[nodiscard]] bool isNoPassPhrase() const { return this->no_passphrase_; }
void setNonPassPhrase(bool m_non_pass_phrase) {
- GenKeyInfo::noPassPhrase = m_non_pass_phrase;
+ GenKeyInfo::no_passphrase_ = m_non_pass_phrase;
}
[[nodiscard]] bool isAllowSigning() const { return allowSigning; }
- [[nodiscard]] bool isAllowNoPassPhrase() const { return allowNoPassPhrase; }
+ [[nodiscard]] bool isAllowNoPassPhrase() const {
+ return allow_no_pass_phrase_;
+ }
void setAllowSigning(bool m_allow_signing) {
if (allowChangeSigning) GenKeyInfo::allowSigning = m_allow_signing;
@@ -115,10 +140,10 @@ class GenKeyInfo {
GenKeyInfo::allowAuthentication = m_allow_authentication;
}
- [[nodiscard]] const std::string &getPassPhrase() const { return passPhrase; }
+ [[nodiscard]] const std::string &getPassPhrase() const { return passphrase_; }
void setPassPhrase(const std::string &m_pass_phrase) {
- GenKeyInfo::passPhrase = m_pass_phrase;
+ GenKeyInfo::passphrase_ = m_pass_phrase;
}
[[nodiscard]] bool isAllowChangeSigning() const { return allowChangeSigning; }
@@ -134,12 +159,16 @@ class GenKeyInfo {
return allowChangeAuthentication;
}
- [[nodiscard]] int getSuggestMaxKeySize() const { return suggestMaxKeySize; }
+ [[nodiscard]] int getSuggestMaxKeySize() const {
+ return suggest_max_key_size_;
+ }
- [[nodiscard]] int getSuggestMinKeySize() const { return suggestMinKeySize; }
+ [[nodiscard]] int getSuggestMinKeySize() const {
+ return suggest_min_key_size_;
+ }
[[nodiscard]] int getSizeChangeStep() const {
- return suggestSizeAdditionStep;
+ return suggest_size_addition_step_;
}
private:
@@ -158,9 +187,7 @@ class GenKeyInfo {
void reset_options();
public:
- explicit GenKeyInfo(bool m_is_sub_key = false) : subKey(m_is_sub_key) {
- setAlgo("rsa");
- }
+ explicit GenKeyInfo(bool m_is_sub_key = false, bool m_standalone = false);
};
} // namespace GpgFrontend
diff --git a/src/gpg/GpgInfo.h b/src/gpg/GpgInfo.h
index 6ecb9b92..67ac55d6 100644
--- a/src/gpg/GpgInfo.h
+++ b/src/gpg/GpgInfo.h
@@ -40,6 +40,12 @@ class GpgInfo {
std::string DatabasePath;
std::string GnupgVersion;
+
+ std::string GpgConfPath;
+
+ std::string CMSPath;
+
+ std::string GpgMEVersion;
};
#endif // GPGFRONTEND_ZH_CN_TS_GPGINFO_H
diff --git a/src/gpg/function/BasicOperator.cpp b/src/gpg/function/BasicOperator.cpp
index 56b7ca54..0383f8ab 100644
--- a/src/gpg/function/BasicOperator.cpp
+++ b/src/gpg/function/BasicOperator.cpp
@@ -75,8 +75,7 @@ GpgFrontend::GpgError GpgFrontend::BasicOperator::Verify(
BypeArrayRef& in_buffer, ByteArrayPtr& sig_buffer,
GpgVerifyResult& result) const {
gpgme_error_t err;
-
- LOG(INFO) << "in buffer size" << in_buffer.size();
+
GpgData data_in(in_buffer.data(), in_buffer.size());
GpgData data_out;
@@ -187,9 +186,11 @@ gpgme_error_t GpgFrontend::BasicOperator::EncryptSign(
void GpgFrontend::BasicOperator::SetSigners(KeyArgsList& keys) {
gpgme_signers_clear(ctx);
for (const GpgKey& key : keys) {
+ DLOG(INFO) << "key" << key.fpr();
if (key.CanSignActual()) {
- auto gpgmeError = gpgme_signers_add(ctx, gpgme_key_t(key));
- check_gpg_error(gpgmeError);
+ DLOG(INFO) << "signer";
+ auto error = gpgme_signers_add(ctx, gpgme_key_t(key));
+ check_gpg_error(error);
}
}
if (keys.size() != gpgme_signers_count(ctx))
diff --git a/src/gpg/function/BasicOperator.h b/src/gpg/function/BasicOperator.h
index 4ea70eea..41bd9b7f 100644
--- a/src/gpg/function/BasicOperator.h
+++ b/src/gpg/function/BasicOperator.h
@@ -34,6 +34,10 @@ namespace GpgFrontend {
class BasicOperator : public SingletonFunctionObject<BasicOperator> {
public:
+ explicit BasicOperator(
+ int channel = SingletonFunctionObject::GetDefaultChannel())
+ : SingletonFunctionObject<BasicOperator>(channel) {}
+
gpg_error_t Encrypt(KeyListPtr keys, BypeArrayRef in_buffer,
ByteArrayPtr& out_buffer, GpgEncrResult& result);
@@ -65,7 +69,7 @@ class BasicOperator : public SingletonFunctionObject<BasicOperator> {
private:
GpgContext& ctx =
- GpgContext::GetInstance(SingletonFunctionObject::GetDefaultChannel());
+ GpgContext::GetInstance(SingletonFunctionObject::GetChannel());
};
} // namespace GpgFrontend
diff --git a/src/gpg/function/GpgCommandExecutor.h b/src/gpg/function/GpgCommandExecutor.h
index f28caca8..dcdd318d 100644
--- a/src/gpg/function/GpgCommandExecutor.h
+++ b/src/gpg/function/GpgCommandExecutor.h
@@ -35,6 +35,9 @@
namespace GpgFrontend {
class GpgCommandExecutor : public SingletonFunctionObject<GpgCommandExecutor> {
public:
+ explicit GpgCommandExecutor(
+ int channel = SingletonFunctionObject::GetDefaultChannel())
+ : SingletonFunctionObject<GpgCommandExecutor>(channel) {}
#ifndef WINDOWS
void Execute(StringArgsRef arguments,
@@ -44,7 +47,8 @@ class GpgCommandExecutor : public SingletonFunctionObject<GpgCommandExecutor> {
#endif
private:
- GpgContext &ctx = GpgContext::GetInstance();
+ GpgContext &ctx =
+ GpgContext::GetInstance(SingletonFunctionObject::GetChannel());
};
} // namespace GpgFrontend
diff --git a/src/gpg/function/GpgFileOpera.cpp b/src/gpg/function/GpgFileOpera.cpp
index 42b37c71..8babfa6d 100644
--- a/src/gpg/function/GpgFileOpera.cpp
+++ b/src/gpg/function/GpgFileOpera.cpp
@@ -30,15 +30,16 @@
#include "gpg/function/BasicOperator.h"
GpgFrontend::GpgError GpgFrontend::GpgFileOpera::EncryptFile(
- KeyListPtr keys, const std::string& path, GpgEncrResult& result) {
- std::string in_buffer = read_all_data_in_file(path);
+ KeyListPtr keys, const std::string& in_path, const std::string& out_path,
+ GpgEncrResult& result, int _channel) {
+ std::string in_buffer = read_all_data_in_file(in_path);
std::unique_ptr<std::string> out_buffer;
- auto err = BasicOperator::GetInstance().Encrypt(std::move(keys), in_buffer,
- out_buffer, result);
+ auto err = BasicOperator::GetInstance(_channel).Encrypt(
+ std::move(keys), in_buffer, out_buffer, result);
if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR)
- if (!write_buffer_to_file(path + ".asc", *out_buffer)) {
+ if (!write_buffer_to_file(out_path, *out_buffer)) {
throw std::runtime_error("write_buffer_to_file error");
};
@@ -46,8 +47,9 @@ GpgFrontend::GpgError GpgFrontend::GpgFileOpera::EncryptFile(
}
GpgFrontend::GpgError GpgFrontend::GpgFileOpera::DecryptFile(
- const std::string& path, GpgDecrResult& result) {
- std::string in_buffer = read_all_data_in_file(path);
+ const std::string& in_path, const std::string& out_path,
+ GpgDecrResult& result) {
+ std::string in_buffer = read_all_data_in_file(in_path);
std::unique_ptr<std::string> out_buffer;
auto err =
@@ -55,14 +57,8 @@ GpgFrontend::GpgError GpgFrontend::GpgFileOpera::DecryptFile(
assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR);
- std::string out_file_name = get_only_file_name_with_path(path),
- file_extension = get_file_extension(path);
-
- if (!(file_extension == ".asc" || file_extension == ".gpg"))
- out_file_name += ".out";
-
if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR)
- if (!write_buffer_to_file(out_file_name, *out_buffer)) {
+ if (!write_buffer_to_file(out_path, *out_buffer)) {
throw std::runtime_error("write_buffer_to_file error");
};
@@ -70,58 +66,49 @@ GpgFrontend::GpgError GpgFrontend::GpgFileOpera::DecryptFile(
}
gpgme_error_t GpgFrontend::GpgFileOpera::SignFile(KeyListPtr keys,
- const std::string& path,
- GpgSignResult& result) {
- auto in_buffer = read_all_data_in_file(path);
+ const std::string& in_path,
+ const std::string& out_path,
+ GpgSignResult& result,
+ int _channel) {
+ auto in_buffer = read_all_data_in_file(in_path);
std::unique_ptr<std::string> out_buffer;
- auto err = BasicOperator::GetInstance().Sign(
+ auto err = BasicOperator::GetInstance(_channel).Sign(
std::move(keys), in_buffer, out_buffer, GPGME_SIG_MODE_DETACH, result);
if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR)
- if (!write_buffer_to_file(path + ".sig", *out_buffer)) {
+ if (!write_buffer_to_file(out_path, *out_buffer)) {
throw std::runtime_error("write_buffer_to_file error");
};
return err;
}
-gpgme_error_t GpgFrontend::GpgFileOpera::VerifyFile(const std::string& path,
- GpgVerifyResult& result) {
- auto in_buffer = read_all_data_in_file(path);
+gpgme_error_t GpgFrontend::GpgFileOpera::VerifyFile(
+ const std::string& data_path, const std::string& sign_path,
+ GpgVerifyResult& result, int _channel) {
+ auto in_buffer = read_all_data_in_file(data_path);
std::unique_ptr<std::string> sign_buffer = nullptr;
-
- if (get_file_extension(path) == ".gpg") {
- auto err =
- BasicOperator::GetInstance().Verify(in_buffer, sign_buffer, result);
- return err;
- } else {
+ if (!sign_path.empty()) {
sign_buffer =
- std::make_unique<std::string>(read_all_data_in_file(path + ".sig"));
-
- auto err =
- BasicOperator::GetInstance().Verify(in_buffer, sign_buffer, result);
- return err;
+ std::make_unique<std::string>(read_all_data_in_file(sign_path));
}
+ auto err = BasicOperator::GetInstance(_channel).Verify(in_buffer, sign_buffer,
+ result);
+ return err;
}
-// TODO
-
gpg_error_t GpgFrontend::GpgFileOpera::EncryptSignFile(
- KeyListPtr keys, KeyListPtr signer_keys, const std::string& path,
- GpgEncrResult& encr_res, GpgSignResult& sign_res) {
- auto in_buffer = read_all_data_in_file(path);
+ KeyListPtr keys, KeyListPtr signer_keys, const std::string& in_path,
+ const std::string& out_path, GpgEncrResult& encr_res,
+ GpgSignResult& sign_res, int _channel) {
+ auto in_buffer = read_all_data_in_file(in_path);
std::unique_ptr<std::string> out_buffer = nullptr;
- // TODO dealing with signer keys
- auto err = BasicOperator::GetInstance().EncryptSign(
+ auto err = BasicOperator::GetInstance(_channel).EncryptSign(
std::move(keys), std::move(signer_keys), in_buffer, out_buffer, encr_res,
sign_res);
- auto out_path = path + ".gpg";
- LOG(INFO) << "EncryptSignFile out_path" << out_path;
- LOG(INFO) << "EncryptSignFile out_buffer size" << out_buffer->size();
-
if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR)
if (!write_buffer_to_file(out_path, *out_buffer)) {
throw std::runtime_error("write_buffer_to_file error");
@@ -131,28 +118,33 @@ gpg_error_t GpgFrontend::GpgFileOpera::EncryptSignFile(
}
gpg_error_t GpgFrontend::GpgFileOpera::DecryptVerifyFile(
- const std::string& path, GpgDecrResult& decr_res,
- GpgVerifyResult& verify_res) {
- LOG(INFO) << "GpgFrontend::GpgFileOpera::DecryptVerifyFile Called";
+ const std::string& in_path, const std::string& out_path,
+ GpgDecrResult& decr_res, GpgVerifyResult& verify_res) {
+ auto in_buffer = read_all_data_in_file(in_path);
- auto in_buffer = read_all_data_in_file(path);
-
- LOG(INFO) << "GpgFrontend::GpgFileOpera::DecryptVerifyFile in_buffer"
- << in_buffer.size();
std::unique_ptr<std::string> out_buffer = nullptr;
auto err = BasicOperator::GetInstance().DecryptVerify(in_buffer, out_buffer,
decr_res, verify_res);
- std::string out_file_name = get_only_file_name_with_path(path),
- file_extension = get_file_extension(path);
+ if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR)
+ if (!write_buffer_to_file(out_path, *out_buffer)) {
+ throw std::runtime_error("write_buffer_to_file error");
+ };
+
+ return err;
+}
+unsigned int GpgFrontend::GpgFileOpera::EncryptFileSymmetric(
+ const std::string& in_path, const std::string& out_path,
+ GpgFrontend::GpgEncrResult& result, int _channel) {
+ std::string in_buffer = read_all_data_in_file(in_path);
+ std::unique_ptr<std::string> out_buffer;
- if (!(file_extension == ".asc" || file_extension == ".gpg"))
- out_file_name = path + ".out";
- LOG(INFO) << "out_file_name" << out_file_name;
+ auto err = BasicOperator::GetInstance(_channel).EncryptSymmetric(
+ in_buffer, out_buffer, result);
if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR)
- if (!write_buffer_to_file(out_file_name, *out_buffer)) {
+ if (!write_buffer_to_file(out_path, *out_buffer)) {
throw std::runtime_error("write_buffer_to_file error");
};
diff --git a/src/gpg/function/GpgFileOpera.h b/src/gpg/function/GpgFileOpera.h
index 4aaf09f1..f4508f42 100644
--- a/src/gpg/function/GpgFileOpera.h
+++ b/src/gpg/function/GpgFileOpera.h
@@ -33,22 +33,41 @@ namespace GpgFrontend {
class GpgFileOpera : public SingletonFunctionObject<GpgFileOpera> {
public:
- static GpgError EncryptFile(KeyListPtr keys, const std::string& path,
- GpgEncrResult& result);
+ explicit GpgFileOpera(
+ int channel = SingletonFunctionObject::GetDefaultChannel())
+ : SingletonFunctionObject<GpgFileOpera>(channel) {}
- static GpgError DecryptFile(const std::string& path, GpgDecrResult& result);
+ static unsigned int EncryptFile(KeyListPtr keys, const std::string& in_path,
+ const std::string& out_path,
+ GpgEncrResult& result,
+ int _channel = GPGFRONTEND_DEFAULT_CHANNEL);
- static GpgError SignFile(KeyListPtr keys, const std::string& path,
- GpgSignResult& result);
+ static unsigned int EncryptFileSymmetric(
+ const std::string& in_path, const std::string& out_path,
+ GpgEncrResult& result, int _channel = GPGFRONTEND_DEFAULT_CHANNEL);
- static GpgError VerifyFile(const std::string& path, GpgVerifyResult& result);
+ static GpgError DecryptFile(const std::string& in_path,
+ const std::string& out_path,
+ GpgDecrResult& result);
+
+ static GpgError SignFile(KeyListPtr keys, const std::string& in_path,
+ const std::string& out_path, GpgSignResult& result,
+ int _channel = GPGFRONTEND_DEFAULT_CHANNEL);
+
+ static GpgError VerifyFile(const std::string& data_path,
+ const std::string& sign_path,
+ GpgVerifyResult& result,
+ int _channel = GPGFRONTEND_DEFAULT_CHANNEL);
static GpgError EncryptSignFile(KeyListPtr keys, KeyListPtr signer_keys,
- const std::string& path,
+ const std::string& in_path,
+ const std::string& out_path,
GpgEncrResult& encr_res,
- GpgSignResult& sign_res);
+ GpgSignResult& sign_res,
+ int _channel = GPGFRONTEND_DEFAULT_CHANNEL);
- static GpgError DecryptVerifyFile(const std::string& path,
+ static GpgError DecryptVerifyFile(const std::string& in_path,
+ const std::string& out_path,
GpgDecrResult& decr_res,
GpgVerifyResult& verify_res);
};
diff --git a/src/gpg/function/GpgKeyGetter.cpp b/src/gpg/function/GpgKeyGetter.cpp
index 664aff56..8a26dcd9 100644
--- a/src/gpg/function/GpgKeyGetter.cpp
+++ b/src/gpg/function/GpgKeyGetter.cpp
@@ -58,13 +58,15 @@ GpgFrontend::KeyLinkListPtr GpgFrontend::GpgKeyGetter::FetchKey() {
gpgme_key_t key;
while ((err = gpgme_op_keylist_next(ctx, &key)) == GPG_ERR_NO_ERROR) {
- keys_list->push_back(GpgKey(std::move(key)));
+ keys_list->push_back(GetKey(key->fpr));
}
assert(check_gpg_error_2_err_code(err, GPG_ERR_EOF) == GPG_ERR_EOF);
err = gpgme_op_keylist_end(ctx);
+ assert(check_gpg_error_2_err_code(err, GPG_ERR_EOF) == GPG_ERR_NO_ERROR);
+
return keys_list;
}
diff --git a/src/gpg/function/GpgKeyGetter.h b/src/gpg/function/GpgKeyGetter.h
index 3af51815..fcd518d3 100644
--- a/src/gpg/function/GpgKeyGetter.h
+++ b/src/gpg/function/GpgKeyGetter.h
@@ -33,7 +33,9 @@ namespace GpgFrontend {
class GpgKeyGetter : public SingletonFunctionObject<GpgKeyGetter> {
public:
- GpgKeyGetter() = default;
+ explicit GpgKeyGetter(
+ int channel = SingletonFunctionObject::GetDefaultChannel())
+ : SingletonFunctionObject<GpgKeyGetter>(channel) {}
GpgKey GetKey(const std::string& fpr);
@@ -49,7 +51,7 @@ class GpgKeyGetter : public SingletonFunctionObject<GpgKeyGetter> {
private:
GpgContext& ctx =
- GpgContext::GetInstance(SingletonFunctionObject::GetDefaultChannel());
+ GpgContext::GetInstance(SingletonFunctionObject::GetChannel());
};
} // namespace GpgFrontend
diff --git a/src/gpg/function/GpgKeyImportExportor.cpp b/src/gpg/function/GpgKeyImportExporter.cpp
index 89d3b002..dd027eab 100644
--- a/src/gpg/function/GpgKeyImportExportor.cpp
+++ b/src/gpg/function/GpgKeyImportExporter.cpp
@@ -22,16 +22,17 @@
*
*/
-#include "gpg/function/GpgKeyImportExportor.h"
+#include "gpg/function/GpgKeyImportExporter.h"
#include "GpgConstants.h"
+#include "gpg/function/GpgKeyGetter.h"
/**
* Import key pair
* @param inBuffer input byte array
* @return Import information
*/
-GpgFrontend::GpgImportInformation GpgFrontend::GpgKeyImportExportor::ImportKey(
+GpgFrontend::GpgImportInformation GpgFrontend::GpgKeyImportExporter::ImportKey(
StdBypeArrayPtr in_buffer) {
if (in_buffer->empty()) return {};
@@ -60,25 +61,37 @@ GpgFrontend::GpgImportInformation GpgFrontend::GpgKeyImportExportor::ImportKey(
* @param out_buffer output byte array
* @return if success
*/
-bool GpgFrontend::GpgKeyImportExportor::ExportKeys(
- KeyIdArgsListPtr& uid_list, ByteArrayPtr& out_buffer) const {
+bool GpgFrontend::GpgKeyImportExporter::ExportKeys(KeyIdArgsListPtr& uid_list,
+ ByteArrayPtr& out_buffer,
+ bool secret) const {
if (uid_list->empty()) return false;
- // Alleviate another crash problem caused by an unknown array out-of-bounds
- // access
- auto all_success = true;
- for (size_t i = 0; i < uid_list->size(); i++) {
- GpgData data_out;
- auto err = gpgme_op_export(ctx, (*uid_list)[i].c_str(), 0, data_out);
- if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) all_success = false;
- DLOG(INFO) << "exportKeys read_bytes"
- << gpgme_data_seek(data_out, 0, SEEK_END);
-
- auto temp_out_buffer = data_out.Read2Buffer();
- std::swap(out_buffer, temp_out_buffer);
+ int _mode = 0;
+ if (secret) _mode |= GPGME_EXPORT_MODE_SECRET;
+
+ auto keys = GpgKeyGetter::GetInstance().GetKeys(uid_list);
+ auto keys_array = new gpgme_key_t[keys->size() + 1];
+
+ int index = 0;
+ for (const auto& key : *keys) {
+ keys_array[index++] = gpgme_key_t(key);
}
+ keys_array[index] = nullptr;
+
+ GpgData data_out;
+ auto err = gpgme_op_export_keys(ctx, keys_array, _mode, data_out);
+ if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) return false;
+
+ delete[] keys_array;
+
+ DLOG(INFO) << "exportKeys read_bytes"
+ << gpgme_data_seek(data_out, 0, SEEK_END);
+
+ auto temp_out_buffer = data_out.Read2Buffer();
+
+ swap(temp_out_buffer, out_buffer);
- return all_success;
+ return true;
}
/**
@@ -87,11 +100,12 @@ bool GpgFrontend::GpgKeyImportExportor::ExportKeys(
* @param outBuffer output byte array
* @return if success
*/
-bool GpgFrontend::GpgKeyImportExportor::ExportKeys(
- const KeyArgsList& keys, ByteArrayPtr& out_buffer) const {
+bool GpgFrontend::GpgKeyImportExporter::ExportKeys(const KeyArgsList& keys,
+ ByteArrayPtr& out_buffer,
+ bool secret) const {
KeyIdArgsListPtr key_ids = std::make_unique<std::vector<std::string>>();
for (const auto& key : keys) key_ids->push_back(key.id());
- return ExportKeys(key_ids, out_buffer);
+ return ExportKeys(key_ids, out_buffer, secret);
}
/**
@@ -100,7 +114,7 @@ bool GpgFrontend::GpgKeyImportExportor::ExportKeys(
* @param outBuffer output byte array
* @return if successful
*/
-bool GpgFrontend::GpgKeyImportExportor::ExportSecretKey(
+bool GpgFrontend::GpgKeyImportExporter::ExportSecretKey(
const GpgKey& key, ByteArrayPtr& out_buffer) const {
DLOG(INFO) << "Export Secret Key" << key.id().c_str();
@@ -117,7 +131,7 @@ bool GpgFrontend::GpgKeyImportExportor::ExportSecretKey(
return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR;
}
-bool GpgFrontend::GpgKeyImportExportor::ExportKey(
+bool GpgFrontend::GpgKeyImportExporter::ExportKey(
const GpgFrontend::GpgKey& key,
GpgFrontend::ByteArrayPtr& out_buffer) const {
GpgData data_out;
@@ -131,7 +145,7 @@ bool GpgFrontend::GpgKeyImportExportor::ExportKey(
return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR;
}
-bool GpgFrontend::GpgKeyImportExportor::ExportKeyOpenSSH(
+bool GpgFrontend::GpgKeyImportExporter::ExportKeyOpenSSH(
const GpgFrontend::GpgKey& key,
GpgFrontend::ByteArrayPtr& out_buffer) const {
GpgData data_out;
@@ -145,7 +159,7 @@ bool GpgFrontend::GpgKeyImportExportor::ExportKeyOpenSSH(
return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR;
}
-bool GpgFrontend::GpgKeyImportExportor::ExportSecretKeyShortest(
+bool GpgFrontend::GpgKeyImportExporter::ExportSecretKeyShortest(
const GpgFrontend::GpgKey& key,
GpgFrontend::ByteArrayPtr& out_buffer) const {
GpgData data_out;
diff --git a/src/gpg/function/GpgKeyImportExportor.h b/src/gpg/function/GpgKeyImportExporter.h
index ad43d539..64b3b8a9 100644
--- a/src/gpg/function/GpgKeyImportExportor.h
+++ b/src/gpg/function/GpgKeyImportExporter.h
@@ -79,14 +79,20 @@ class GpgImportInformation {
GpgImportedKeyList importedKeys;
};
-class GpgKeyImportExportor
- : public SingletonFunctionObject<GpgKeyImportExportor> {
+class GpgKeyImportExporter
+ : public SingletonFunctionObject<GpgKeyImportExporter> {
public:
+ explicit GpgKeyImportExporter(
+ int channel = SingletonFunctionObject::GetDefaultChannel())
+ : SingletonFunctionObject<GpgKeyImportExporter>(channel) {}
+
GpgImportInformation ImportKey(StdBypeArrayPtr inBuffer);
- bool ExportKeys(KeyIdArgsListPtr& uid_list, ByteArrayPtr& out_buffer) const;
+ bool ExportKeys(KeyIdArgsListPtr& uid_list, ByteArrayPtr& out_buffer,
+ bool secret = false) const;
- bool ExportKeys(const KeyArgsList& keys, ByteArrayPtr& outBuffer) const;
+ bool ExportKeys(const KeyArgsList& keys, ByteArrayPtr& outBuffer,
+ bool secret = false) const;
bool ExportKey(const GpgKey& key, ByteArrayPtr& out_buffer) const;
@@ -99,7 +105,7 @@ class GpgKeyImportExportor
private:
GpgContext& ctx =
- GpgContext::GetInstance(SingletonFunctionObject::GetDefaultChannel());
+ GpgContext::GetInstance(SingletonFunctionObject::GetChannel());
};
} // namespace GpgFrontend
diff --git a/src/gpg/function/GpgKeyManager.h b/src/gpg/function/GpgKeyManager.h
index 01254962..b2444e8d 100644
--- a/src/gpg/function/GpgKeyManager.h
+++ b/src/gpg/function/GpgKeyManager.h
@@ -33,6 +33,10 @@ namespace GpgFrontend {
class GpgKeyManager : public SingletonFunctionObject<GpgKeyManager> {
public:
+ explicit GpgKeyManager(
+ int channel = SingletonFunctionObject::GetDefaultChannel())
+ : SingletonFunctionObject<GpgKeyManager>(channel) {}
+
/**
* Sign a key pair(actually a certain uid)
* @param target target key pair
@@ -50,7 +54,8 @@ class GpgKeyManager : public SingletonFunctionObject<GpgKeyManager> {
std::unique_ptr<boost::posix_time::ptime>& expires);
private:
- GpgContext& ctx = GpgContext::GetInstance();
+ GpgContext& ctx =
+ GpgContext::GetInstance(SingletonFunctionObject::GetChannel());
};
} // namespace GpgFrontend
diff --git a/src/gpg/function/GpgKeyOpera.cpp b/src/gpg/function/GpgKeyOpera.cpp
index 4bad303d..e9fcbc1d 100644
--- a/src/gpg/function/GpgKeyOpera.cpp
+++ b/src/gpg/function/GpgKeyOpera.cpp
@@ -26,6 +26,7 @@
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/conversion.hpp>
+#include <boost/format.hpp>
#include <boost/process/async_pipe.hpp>
#include <memory>
#include <string>
@@ -46,18 +47,21 @@ void GpgFrontend::GpgKeyOpera::DeleteKeys(
for (const auto& tmp : *key_ids) {
auto key = GpgKeyGetter::GetInstance().GetKey(tmp);
if (key.good()) {
- LOG(INFO) << "GpgKeyOpera DeleteKeys Get Key Good";
- err = check_gpg_error(gpgme_op_delete(ctx, gpgme_key_t(key), 1));
+ err = check_gpg_error(
+ gpgme_op_delete_ext(ctx, gpgme_key_t(key),
+ GPGME_DELETE_ALLOW_SECRET | GPGME_DELETE_FORCE));
assert(gpg_err_code(err) == GPG_ERR_NO_ERROR);
- } else
- LOG(WARNING) << "GpgKeyOpera DeleteKeys Get Key Bad";
+ } else {
+ LOG(WARNING) << "GpgKeyOpera DeleteKeys get key failed" << tmp;
+ }
}
}
/**
- * Set the expire date and time of a key pair(actually the master key) or subkey
+ * Set the expire date and time of a key pair(actually the primary key) or
+ * subkey
* @param key target key pair
- * @param subkey null if master key
+ * @param subkey null if primary key
* @param expires date and time
* @return if successful
*/
@@ -146,13 +150,12 @@ void GpgFrontend::GpgKeyOpera::GenerateRevokeCert(
* @return error information
*/
GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::GenerateKey(
- const std::unique_ptr<GenKeyInfo>& params) {
+ const std::unique_ptr<GenKeyInfo>& params, GpgGenKeyResult& result) {
auto userid_utf8 = params->getUserid();
const char* userid = userid_utf8.c_str();
auto algo_utf8 = params->getAlgo() + params->getKeySizeStr();
- LOG(INFO) << "GpgFrontend::GpgKeyOpera::GenerateKey Params"
- << params->getAlgo() << params->getKeySizeStr();
+ LOG(INFO) << "params" << params->getAlgo() << params->getKeySizeStr();
const char* algo = algo_utf8.c_str();
unsigned long expires = 0;
@@ -163,19 +166,57 @@ GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::GenerateKey(
system_clock::to_time_t(system_clock::now());
}
- unsigned int flags = 0;
+ GpgError err;
- if (!params->isSubKey()) flags |= GPGME_CREATE_CERT;
- if (params->isAllowEncryption()) flags |= GPGME_CREATE_ENCR;
- if (params->isAllowSigning()) flags |= GPGME_CREATE_SIGN;
- if (params->isAllowAuthentication()) flags |= GPGME_CREATE_AUTH;
- if (params->isNonExpired()) flags |= GPGME_CREATE_NOEXPIRE;
- if (params->isNoPassPhrase()) flags |= GPGME_CREATE_NOPASSWD;
+ if (ctx.GetInfo().GnupgVersion >= "2.1.0") {
+ unsigned int flags = 0;
+
+ if (!params->isSubKey()) flags |= GPGME_CREATE_CERT;
+ if (params->isAllowEncryption()) flags |= GPGME_CREATE_ENCR;
+ if (params->isAllowSigning()) flags |= GPGME_CREATE_SIGN;
+ if (params->isAllowAuthentication()) flags |= GPGME_CREATE_AUTH;
+ if (params->isNonExpired()) flags |= GPGME_CREATE_NOEXPIRE;
+ if (params->isNoPassPhrase()) flags |= GPGME_CREATE_NOPASSWD;
+
+ LOG(INFO) << "args: " << userid << algo << expires << flags;
+
+ err = gpgme_op_createkey(ctx, userid, algo, 0, expires, nullptr, flags);
- LOG(INFO) << "GpgFrontend::GpgKeyOpera::GenerateKey Args: " << userid << algo
- << expires << flags;
+ } else {
+ std::stringstream ss;
+ auto param_format =
+ boost::format{
+ "<GnupgKeyParms format=\"internal\">\n"
+ "Key-Type: %1%\n"
+ "Key-Usage: sign\n"
+ "Key-Length: %2%\n"
+ "Name-Real: %3%\n"
+ "Name-Comment: %4%\n"
+ "Name-Email: %5%\n"} %
+ params->getAlgo() % params->getKeySize() % params->getName() %
+ params->getComment() % params->getEmail();
+ ss << param_format;
+
+ if (!params->isNonExpired()) {
+ auto date = params->getExpired().date();
+ ss << boost::format{"Expire-Date: %1%\n"} % to_iso_string(date);
+ } else
+ ss << boost::format{"Expire-Date: 0\n"};
+ if (!params->isNoPassPhrase())
+ ss << boost::format{"Passphrase: %1%\n"} % params->getPassPhrase();
+
+ ss << "</GnupgKeyParms>";
+
+ DLOG(INFO) << "params" << std::endl << ss.str();
+
+ err = gpgme_op_genkey(ctx, ss.str().c_str(), nullptr, nullptr);
+ }
+
+ if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) {
+ auto temp_result = _new_result(gpgme_op_genkey_result(ctx));
+ std::swap(temp_result, result);
+ }
- auto err = gpgme_op_createkey(ctx, userid, algo, 0, expires, nullptr, flags);
return check_gpg_error(err);
}
@@ -234,3 +275,9 @@ GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::ModifyTOFUPolicy(
auto err = gpgme_op_tofu_policy(ctx, gpgme_key_t(key), tofu_policy);
return check_gpg_error(err);
}
+
+void GpgFrontend::GpgKeyOpera::DeleteKey(const GpgFrontend::KeyId& key_id) {
+ auto keys = std::make_unique<KeyIdArgsList>();
+ keys->push_back(key_id);
+ DeleteKeys(std::move(keys));
+}
diff --git a/src/gpg/function/GpgKeyOpera.h b/src/gpg/function/GpgKeyOpera.h
index 7decfd79..73b8bdb5 100644
--- a/src/gpg/function/GpgKeyOpera.h
+++ b/src/gpg/function/GpgKeyOpera.h
@@ -33,8 +33,14 @@ namespace GpgFrontend {
class GenKeyInfo;
class GpgKeyOpera : public SingletonFunctionObject<GpgKeyOpera> {
public:
+ explicit GpgKeyOpera(
+ int channel = SingletonFunctionObject::GetDefaultChannel())
+ : SingletonFunctionObject<GpgKeyOpera>(channel) {}
+
void DeleteKeys(KeyIdArgsListPtr key_ids);
+ void DeleteKey(const KeyId& key_id);
+
GpgError SetExpire(const GpgKey& key, const SubkeyId& subkey_fpr,
std::unique_ptr<boost::posix_time::ptime>& expires);
@@ -46,13 +52,15 @@ class GpgKeyOpera : public SingletonFunctionObject<GpgKeyOpera> {
GpgFrontend::GpgError ModifyTOFUPolicy(const GpgKey& key,
gpgme_tofu_policy_t tofu_policy);
- GpgFrontend::GpgError GenerateKey(const std::unique_ptr<GenKeyInfo>& params);
+ GpgFrontend::GpgError GenerateKey(const std::unique_ptr<GenKeyInfo>& params,
+ GpgGenKeyResult& result);
GpgFrontend::GpgError GenerateSubkey(
const GpgKey& key, const std::unique_ptr<GenKeyInfo>& params);
private:
- GpgContext& ctx = GpgContext::GetInstance();
+ GpgContext& ctx =
+ GpgContext::GetInstance(SingletonFunctionObject::GetChannel());
};
} // namespace GpgFrontend
diff --git a/src/gpg/function/UidOperator.h b/src/gpg/function/UidOperator.h
index 7d5df254..d1a92b38 100644
--- a/src/gpg/function/UidOperator.h
+++ b/src/gpg/function/UidOperator.h
@@ -32,6 +32,10 @@ namespace GpgFrontend {
class UidOperator : public SingletonFunctionObject<UidOperator> {
public:
+ explicit UidOperator(
+ int channel = SingletonFunctionObject::GetDefaultChannel())
+ : SingletonFunctionObject<UidOperator>(channel) {}
+
/**
* create a new uid in certain key pair
* @param key target key pair
@@ -68,7 +72,8 @@ class UidOperator : public SingletonFunctionObject<UidOperator> {
bool setPrimaryUID(const GpgKey& key, const std::string& uid);
private:
- GpgContext& ctx = GpgContext::GetInstance();
+ GpgContext& ctx =
+ GpgContext::GetInstance(SingletonFunctionObject::GetChannel());
};
} // namespace GpgFrontend
diff --git a/src/gpg/model/GpgKey.h b/src/gpg/model/GpgKey.h
index fb7d5735..0ce83372 100644
--- a/src/gpg/model/GpgKey.h
+++ b/src/gpg/model/GpgKey.h
@@ -108,6 +108,13 @@ class GpgKey {
[[nodiscard]] bool CanAuthActual() const;
+ [[nodiscard]] bool HasCardKey() const {
+ auto subkeys = subKeys();
+ return std::any_of(
+ subkeys->begin(), subkeys->end(),
+ [](const GpgSubKey& subkey) -> bool { return subkey.is_cardkey(); });
+ }
+
[[nodiscard]] bool is_private_key() const { return _key_ref->secret; }
[[nodiscard]] bool expired() const { return _key_ref->expired; }
diff --git a/src/gpg/result_analyse/DecryptResultAnalyse.cpp b/src/gpg/result_analyse/DecryptResultAnalyse.cpp
index 9c3e7dd0..f2e9f947 100644
--- a/src/gpg/result_analyse/DecryptResultAnalyse.cpp
+++ b/src/gpg/result_analyse/DecryptResultAnalyse.cpp
@@ -26,12 +26,12 @@
#include "gpg/function/GpgKeyGetter.h"
-GpgFrontend::DecryptResultAnalyse::DecryptResultAnalyse(GpgError error,
- GpgDecrResult result)
- : error(error), result(std::move(result)) {}
+GpgFrontend::DecryptResultAnalyse::DecryptResultAnalyse(GpgError m_error,
+ GpgDecrResult m_result)
+ : error(m_error), result(std::move(m_result)) {}
void GpgFrontend::DecryptResultAnalyse::do_analyse() {
- stream << "[#]" << _("Decrypt Operation");
+ stream << "[#] " << _("Decrypt Operation");
if (gpgme_err_code(error) == GPG_ERR_NO_ERROR) {
stream << "[" << _("Success") << "]" << std::endl;
@@ -55,11 +55,11 @@ void GpgFrontend::DecryptResultAnalyse::do_analyse() {
stream << _("MIME") << ": " << _("true") << std::endl;
}
- auto reci = result->recipients;
- if (reci != nullptr) stream << _("Recipient(s)") << ": " << std::endl;
- while (reci != nullptr) {
- print_reci(stream, reci);
- reci = reci->next;
+ auto recipient = result->recipients;
+ if (recipient != nullptr) stream << _("Recipient(s)") << ": " << std::endl;
+ while (recipient != nullptr) {
+ print_recipient(stream, recipient);
+ recipient = recipient->next;
}
stream << "<------------" << std::endl;
}
@@ -67,12 +67,13 @@ void GpgFrontend::DecryptResultAnalyse::do_analyse() {
stream << std::endl;
}
-bool GpgFrontend::DecryptResultAnalyse::print_reci(std::stringstream &stream,
- gpgme_recipient_t reci) {
- bool keyFound = true;
- stream << " {>} " << _("Recipient") << ": ";
+void GpgFrontend::DecryptResultAnalyse::print_recipient(
+ std::stringstream &stream, gpgme_recipient_t recipient) {
+ // check
+ if (recipient->keyid == nullptr) return;
- auto key = GpgFrontend::GpgKeyGetter::GetInstance().GetKey(reci->keyid);
+ stream << " {>} " << _("Recipient") << ": ";
+ auto key = GpgFrontend::GpgKeyGetter::GetInstance().GetKey(recipient->keyid);
if (key.good()) {
stream << key.name().c_str();
if (!key.email().empty()) {
@@ -81,14 +82,11 @@ bool GpgFrontend::DecryptResultAnalyse::print_reci(std::stringstream &stream,
} else {
stream << "<" << _("Unknown") << ">";
setStatus(0);
- keyFound = false;
}
stream << std::endl;
- stream << " " << _("Keu ID") << ": " << reci->keyid << std::endl;
- stream << " " << _("Public Algo") << ": "
- << gpgme_pubkey_algo_name(reci->pubkey_algo) << std::endl;
-
- return keyFound;
+ stream << " " << _("Key ID") << ": " << recipient->keyid << std::endl;
+ stream << " " << _("Public Key Algo") << ": "
+ << gpgme_pubkey_algo_name(recipient->pubkey_algo) << std::endl;
}
diff --git a/src/gpg/result_analyse/DecryptResultAnalyse.h b/src/gpg/result_analyse/DecryptResultAnalyse.h
index 0864c23b..729d8853 100644
--- a/src/gpg/result_analyse/DecryptResultAnalyse.h
+++ b/src/gpg/result_analyse/DecryptResultAnalyse.h
@@ -32,13 +32,13 @@ namespace GpgFrontend {
class DecryptResultAnalyse : public ResultAnalyse {
public:
- explicit DecryptResultAnalyse(GpgError error, GpgDecrResult result);
+ explicit DecryptResultAnalyse(GpgError m_error, GpgDecrResult m_result);
protected:
void do_analyse() final;
private:
- bool print_reci(std::stringstream &stream, gpgme_recipient_t reci);
+ void print_recipient(std::stringstream &stream, gpgme_recipient_t recipient);
GpgError error;
GpgDecrResult result;
diff --git a/src/gpg/result_analyse/VerifyResultAnalyse.cpp b/src/gpg/result_analyse/VerifyResultAnalyse.cpp
index 8f565b8e..99cbd528 100644
--- a/src/gpg/result_analyse/VerifyResultAnalyse.cpp
+++ b/src/gpg/result_analyse/VerifyResultAnalyse.cpp
@@ -35,7 +35,7 @@ GpgFrontend::VerifyResultAnalyse::VerifyResultAnalyse(GpgError error,
: error(error), result(std::move(result)) {}
void GpgFrontend::VerifyResultAnalyse::do_analyse() {
- LOG(INFO) << _("Verify Result Analyse Started");
+ LOG(INFO) << _("started");
stream << "[#] " << _("Verify Operation") << " ";
@@ -46,16 +46,10 @@ void GpgFrontend::VerifyResultAnalyse::do_analyse() {
setStatus(-1);
}
- if (result != nullptr && result->signatures) {
+ if (result != nullptr && result->signatures != nullptr) {
stream << "------------>" << std::endl;
auto sign = result->signatures;
- if (sign == nullptr) {
- stream << "[>] " << _("Not Signature Found") << std::endl;
- setStatus(0);
- return;
- }
-
stream << "[>] " << _("Signed On") << "(" << _("UTC") << ")"
<< " "
<< boost::posix_time::to_iso_extended_string(
@@ -163,6 +157,12 @@ void GpgFrontend::VerifyResultAnalyse::do_analyse() {
sign = sign->next;
}
stream << "<------------" << std::endl;
+ } else {
+ stream << "[>] "
+ << _("Could not find information that can be used for verification.")
+ << std::endl;
+ setStatus(0);
+ return;
}
}
diff --git a/src/main.cpp b/src/main.cpp
index 10d54958..fa4195ce 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -28,8 +28,9 @@
#include "GpgFrontendBuildInfo.h"
#include "gpg/GpgContext.h"
-#include "gpg/function/GpgKeyGetter.h"
+#include "gpg/GpgFunctionObject.h"
#include "ui/MainWindow.h"
+#include "ui/function/CtxCheckThread.h"
#include "ui/settings/GlobalSettingStation.h"
// Easy Logging Cpp
@@ -78,7 +79,9 @@ int main(int argc, char* argv[]) {
#if !defined(RELEASE) && defined(WINDOWS)
// css
- boost::filesystem::path css_path = GpgFrontend::UI::GlobalSettingStation::GetInstance().GetResourceDir() / "css" / "default.qss";
+ boost::filesystem::path css_path =
+ GpgFrontend::UI::GlobalSettingStation::GetInstance().GetResourceDir() /
+ "css" / "default.qss";
QFile file(css_path.string().c_str());
file.open(QFile::ReadOnly);
QString styleSheet = QLatin1String(file.readAll());
@@ -86,21 +89,20 @@ int main(int argc, char* argv[]) {
file.close();
#endif
- auto* init_ctx_thread = QThread::create([]() {
- // Create & Check Gnupg Context Status
- if (!GpgFrontend::GpgContext::GetInstance().good()) {
- QMessageBox::critical(
- nullptr, _("ENV Loading Failed"),
- _("Gnupg(gpg) is not installed correctly, please follow the "
- "ReadME "
- "instructions in Github to install Gnupg and then open "
- "GpgFrontend."));
- QCoreApplication::quit();
- exit(0);
- }
- // Try fetching key
- GpgFrontend::GpgKeyGetter::GetInstance().FetchKey();
- });
+#ifdef GPG_STANDALONE_MODE
+ LOG(INFO) << "GPG_STANDALONE_MODE Enabled";
+ auto gpg_path = GpgFrontend::UI::GlobalSettingStation::GetInstance()
+ .GetStandaloneGpgBinDir();
+ auto db_path = GpgFrontend::UI::GlobalSettingStation::GetInstance()
+ .GetStandaloneDatabaseDir();
+ GpgFrontend::GpgContext::CreateInstance(
+ GpgFrontend::SingletonFunctionObject<
+ GpgFrontend::GpgContext>::GetDefaultChannel(),
+ std::make_unique<GpgFrontend::GpgContext>(true, db_path.string(), true,
+ gpg_path.string()));
+#endif
+
+ auto* init_ctx_thread = new GpgFrontend::UI::CtxCheckThread();
QApplication::connect(init_ctx_thread, &QThread::finished, init_ctx_thread,
&QThread::deleteLater);
@@ -118,9 +120,13 @@ int main(int argc, char* argv[]) {
waiting_dialog_label->setWordWrap(true);
waiting_dialog->setLabel(waiting_dialog_label);
waiting_dialog->resize(420, 120);
+ QApplication::connect(init_ctx_thread, &QThread::finished, [=]() {
+ waiting_dialog->finished(0);
+ waiting_dialog->deleteLater();
+ });
QApplication::connect(waiting_dialog, &QProgressDialog::canceled, [=]() {
LOG(INFO) << "cancel clicked";
- init_ctx_thread->terminate();
+ if (init_ctx_thread->isRunning()) init_ctx_thread->terminate();
QCoreApplication::quit();
exit(0);
});
@@ -130,11 +136,10 @@ int main(int argc, char* argv[]) {
waiting_dialog->setFocus();
init_ctx_thread->start();
- while (init_ctx_thread->isRunning()) {
- QApplication::processEvents();
- }
- waiting_dialog->finished(0);
- waiting_dialog->deleteLater();
+ QEventLoop loop;
+ QApplication::connect(init_ctx_thread, &QThread::finished, &loop,
+ &QEventLoop::quit);
+ loop.exec();
/**
* internationalisation. loop to restart main window
@@ -149,7 +154,6 @@ int main(int argc, char* argv[]) {
int r = setjmp(recover_env);
#endif
if (!r) {
-
try {
// i18n
init_locale();
@@ -169,10 +173,12 @@ int main(int argc, char* argv[]) {
"program, and now it needs to be restarted. This is not a "
"serious problem, it may be the negligence of the programmer, "
"please report this problem if you can."));
+ return_from_event_loop_code = RESTART_CODE;
continue;
}
} else {
+ QApplication::exit(RESTART_CODE);
QMessageBox::information(
nullptr, _("A serious error has occurred"),
_("Oh no! GpgFrontend caught a serious error in the software, so it "
diff --git a/src/smtp/CMakeLists.txt b/src/smtp/CMakeLists.txt
index 8e341f98..afae322e 100644
--- a/src/smtp/CMakeLists.txt
+++ b/src/smtp/CMakeLists.txt
@@ -4,3 +4,11 @@ add_library(smtp STATIC ${SMTP_MIME_SOURCE})
target_link_libraries(smtp
Qt5::Network Qt5::Core)
+
+if(XCODE_BUILD)
+set_target_properties(smtp
+ PROPERTIES
+ ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}
+ LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}
+ LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE})
+endif() \ No newline at end of file
diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt
index 529921e0..3e44a0d6 100644
--- a/src/ui/CMakeLists.txt
+++ b/src/ui/CMakeLists.txt
@@ -1,4 +1,5 @@
aux_source_directory(. UI_SOURCE)
+aux_source_directory(./aes UI_SOURCE)
aux_source_directory(./keypair_details UI_SOURCE)
aux_source_directory(./widgets UI_SOURCE)
aux_source_directory(./keygen UI_SOURCE)
@@ -7,6 +8,7 @@ aux_source_directory(./help UI_SOURCE)
aux_source_directory(./settings UI_SOURCE)
aux_source_directory(./function UI_SOURCE)
aux_source_directory(./details UI_SOURCE)
+aux_source_directory(./data_struct UI_SOURCE)
if (SMTP_SUPPORT)
aux_source_directory(./smtp UI_SOURCE)
@@ -19,4 +21,11 @@ target_link_libraries(${GPGFRONTEND_UI_LIB_NAME}
target_include_directories(gpgfrontend-ui PUBLIC
${CMAKE_CURRENT_BINARY_DIR}/${GPGFRONTEND_UI_LIB_NAME}_autogen/include)
+if (XCODE_BUILD)
+ set_target_properties(gpgfrontend-ui
+ PROPERTIES
+ ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}
+ LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}
+ LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE})
+endif ()
target_compile_features(gpgfrontend-ui PUBLIC cxx_std_17) \ No newline at end of file
diff --git a/src/ui/FileEncryptionDialog.cpp b/src/ui/FileEncryptionDialog.cpp
deleted file mode 100755
index 6930c3c9..00000000
--- a/src/ui/FileEncryptionDialog.cpp
+++ /dev/null
@@ -1,285 +0,0 @@
-/**
- * This file is part of GpgFrontend.
- *
- * GpgFrontend is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Foobar is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
- *
- * The initial version of the source code is inherited from gpg4usb-team.
- * Their source code version also complies with GNU General Public License.
- *
- * The source code version of this software was modified and released
- * by Saturneric<[email protected]> starting on May 12, 2021.
- *
- */
-
-#include "ui/FileEncryptionDialog.h"
-
-#include "gpg/function/BasicOperator.h"
-#include "gpg/function/GpgKeyGetter.h"
-
-namespace GpgFrontend::UI {
-FileEncryptionDialog::FileEncryptionDialog(KeyIdArgsListPtr keyList,
- DialogAction action, QWidget* parent)
- : QDialog(parent), mAction(action) {
- if (mAction == Decrypt) {
- setWindowTitle(_("Decrypt File"));
- } else if (mAction == Encrypt) {
- setWindowTitle(_("Encrypt File"));
- } else if (mAction == Sign) {
- setWindowTitle(_("Sign File"));
- } else if (mAction == Verify) {
- setWindowTitle(_("Verify File"));
- }
-
- setModal(true);
-
- auto* buttonBox =
- new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
- connect(buttonBox, SIGNAL(accepted()), this, SLOT(slotExecuteAction()));
- connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
-
- auto* groupBox1 = new QGroupBox(_("Input Parameters"));
-
- /* Setup input & Outputfileselection*/
- inputFileEdit = new QLineEdit();
- auto* fb1 = new QPushButton("Select");
- connect(fb1, SIGNAL(clicked()), this, SLOT(slotSelectInputFile()));
- auto* fl1 = new QLabel(_("Target File"));
- fl1->setBuddy(inputFileEdit);
-
- outputFileEdit = new QLineEdit();
- auto* fb2 = new QPushButton("Select");
- connect(fb2, SIGNAL(clicked()), this, SLOT(slotSelectOutputFile()));
- auto* fl2 = new QLabel(_("Output File"));
- fl2->setBuddy(outputFileEdit);
-
- auto* gLayout = new QGridLayout();
- gLayout->addWidget(fl1, 0, 0);
- gLayout->addWidget(inputFileEdit, 0, 1);
- gLayout->addWidget(fb1, 0, 2);
- signFileEdit = new QLineEdit();
- // verify does not need outfile, but signature file
- if (mAction != Verify) {
- gLayout->addWidget(fl2, 1, 0);
- gLayout->addWidget(outputFileEdit, 1, 1);
- gLayout->addWidget(fb2, 1, 2);
- } else {
- auto* sfb1 = new QPushButton("Select");
- connect(sfb1, SIGNAL(clicked()), this, SLOT(slotSelectSignFile()));
- auto* sfl1 = new QLabel(_("Signature File(.sig) Path"));
- sfl1->setBuddy(signFileEdit);
-
- gLayout->addWidget(sfl1, 1, 0);
- gLayout->addWidget(signFileEdit, 1, 1);
- gLayout->addWidget(sfb1, 1, 2);
- }
- groupBox1->setLayout(gLayout);
-
- /*Setup KeyList*/
- mKeyList = new KeyList(false, this);
- if (mAction == Verify) {
- mKeyList->addListGroupTab(
- _("Default"), KeyListRow::ONLY_SECRET_KEY,
- KeyListColumn::NAME | KeyListColumn::EmailAddress |
- KeyListColumn::Usage,
- [](const GpgKey& key) -> bool {
- if (key.disabled() || key.expired() || key.revoked())
- return false;
- else
- return true;
- });
- }
-
- if (mAction == Encrypt) {
- mKeyList->addListGroupTab(_("Default"), KeyListRow::ONLY_SECRET_KEY,
- KeyListColumn::NAME |
- KeyListColumn::EmailAddress |
- KeyListColumn::Usage,
- [](const GpgKey& key) -> bool {
- if (!key.CanEncrActual())
- return false;
- else
- return true;
- });
- }
-
- if (mAction == Encrypt) {
- mKeyList->addListGroupTab(_("Default"), KeyListRow::ONLY_SECRET_KEY,
- KeyListColumn::NAME |
- KeyListColumn::EmailAddress |
- KeyListColumn::Usage,
- [](const GpgKey& key) -> bool {
- if (!key.CanSignActual())
- return false;
- else
- return true;
- });
- }
-
- if (mAction == Decrypt) mKeyList->setDisabled(true);
-
- mKeyList->slotRefresh();
- mKeyList->setChecked(keyList);
-
- statusLabel = new QLabel();
- statusLabel->setStyleSheet("QLabel {color: red;}");
-
- auto* vbox2 = new QVBoxLayout();
- vbox2->addWidget(groupBox1);
- vbox2->addWidget(mKeyList);
- vbox2->addWidget(statusLabel);
- vbox2->addWidget(buttonBox);
- vbox2->addStretch(0);
- setLayout(vbox2);
-
- this->setMinimumWidth(480);
- this->show();
-}
-
-void FileEncryptionDialog::slotSelectInputFile() {
- QString path;
- if (inputFileEdit->text().size() > 0) {
- path = QFileInfo(inputFileEdit->text()).absolutePath();
- }
-
- // QString infileName = QFileDialog::getOpenFileName(this, _("Open File"),
- // path, _("Files") + _("All Files (*)"));
- QString infileName = QFileDialog::getOpenFileName(this, _("Open File"), path);
- inputFileEdit->setText(infileName);
-
- // try to find a matching output-filename, if not yet done
- if (!infileName.isEmpty() && outputFileEdit->text().size() == 0 &&
- signFileEdit->text().size() == 0) {
- if (mAction == Encrypt) {
- outputFileEdit->setText(infileName + ".asc");
- } else if (mAction == Sign) {
- outputFileEdit->setText(infileName + ".sig");
- } else if (mAction == Verify) {
- signFileEdit->setText(infileName + ".sig");
- } else {
- if (infileName.endsWith(".asc", Qt::CaseInsensitive)) {
- QString ofn = infileName;
- ofn.chop(4);
- outputFileEdit->setText(ofn);
- } else {
- outputFileEdit->setText(infileName + ".out");
- }
- }
- }
-}
-
-void FileEncryptionDialog::slotSelectOutputFile() {
- QString path;
- if (outputFileEdit->text().size() > 0) {
- path = QFileInfo(outputFileEdit->text()).absolutePath();
- }
-
- QString outfileName =
- QFileDialog::getSaveFileName(this, _("Save File"), path, nullptr, nullptr,
- QFileDialog::DontConfirmOverwrite);
- outputFileEdit->setText(outfileName);
-}
-
-void FileEncryptionDialog::slotSelectSignFile() {
- QString path;
- if (signFileEdit->text().size() > 0) {
- path = QFileInfo(signFileEdit->text()).absolutePath();
- }
-
- QString signfileName =
- QFileDialog::getSaveFileName(this, _("Open File"), path, nullptr, nullptr,
- QFileDialog::DontConfirmOverwrite);
- signFileEdit->setText(signfileName);
-
- if (inputFileEdit->text().size() == 0 &&
- signfileName.endsWith(".sig", Qt::CaseInsensitive)) {
- QString sfn = signfileName;
- sfn.chop(4);
- inputFileEdit->setText(sfn);
- }
-}
-
-void FileEncryptionDialog::slotExecuteAction() {
- QFile infile;
- infile.setFileName(inputFileEdit->text());
- if (!infile.open(QIODevice::ReadOnly)) {
- statusLabel->setText(_("Couldn't open file"));
- inputFileEdit->setStyleSheet("QLineEdit { background: yellow }");
- return;
- }
- auto in_data = read_all_data_in_file(inputFileEdit->text().toStdString());
- auto out_data = std::make_unique<ByteArray>();
-
- auto key_ids = mKeyList->getChecked();
- auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids);
-
- if (mAction == Encrypt) {
- qDebug() << "Action Encrypt";
- GpgEncrResult result = nullptr;
- gpgme_error_t err = BasicOperator::GetInstance().Encrypt(
- std::move(keys), in_data, out_data, result);
- if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) {
- qDebug() << "Error" << gpgme_strerror(err);
-
- QMessageBox::warning(this, _("Error"),
- _("Error Occurred During Encryption"));
- return;
- }
- }
-
- else if (mAction == Decrypt) {
- qDebug() << "Action Decrypt";
- GpgDecrResult result = nullptr;
- gpgme_error_t err =
- BasicOperator::GetInstance().Decrypt(in_data, out_data, result);
- if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) {
- qDebug() << "Error" << gpgme_strerror(err);
- QMessageBox::warning(this, _("Error"),
- _("Error Occurred During Decryption"));
- return;
- }
- }
-
- else if (mAction == Sign) {
- qDebug() << "Action Sign";
- GpgSignResult result = nullptr;
- gpgme_error_t err = BasicOperator::GetInstance().Sign(
- std::move(keys), in_data, out_data, GPGME_SIG_MODE_DETACH, result);
- if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) {
- qDebug() << "Error" << gpgme_strerror(err);
- QMessageBox::warning(this, _("Error"),
- _("Error Occurred During Signature"));
- return;
- }
- }
-
- if (mAction == Verify) {
- auto sign_data = std::make_unique<ByteArray>(
- read_all_data_in_file(signFileEdit->text().toStdString()));
- GpgVerifyResult result = nullptr;
- auto error =
- BasicOperator::GetInstance().Verify(in_data, sign_data, result);
- new VerifyDetailsDialog(this, error, std::move(result));
- return;
- }
-
- write_buffer_to_file(outputFileEdit->text().toStdString(), *out_data);
-
- accept();
-}
-
-void FileEncryptionDialog::slotShowKeyList() { mKeyList->show(); }
-
-void FileEncryptionDialog::slotHideKeyList() { mKeyList->hide(); }
-
-} // namespace GpgFrontend::UI
diff --git a/src/ui/FileEncryptionDialog.h b/src/ui/FileEncryptionDialog.h
deleted file mode 100755
index b09bb8db..00000000
--- a/src/ui/FileEncryptionDialog.h
+++ /dev/null
@@ -1,114 +0,0 @@
-/**
- * This file is part of GpgFrontend.
- *
- * GpgFrontend is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Foobar is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
- *
- * The initial version of the source code is inherited from gpg4usb-team.
- * Their source code version also complies with GNU General Public License.
- *
- * The source code version of this software was modified and released
- * by Saturneric<[email protected]> starting on May 12, 2021.
- *
- */
-
-#ifndef __FILEENCRYPTIONDIALOG_H__
-#define __FILEENCRYPTIONDIALOG_H__
-
-#include "gpg/GpgContext.h"
-#include "ui/GpgFrontendUI.h"
-#include "ui/details/VerifyDetailsDialog.h"
-#include "ui/widgets/KeyList.h"
-
-namespace GpgFrontend::UI {
-
-/**
- * @brief
- *
- * @class FileEncryptionDialog fileencryptiondialog.h "fileencryptiondialog.h"
- */
-class FileEncryptionDialog : public QDialog {
- Q_OBJECT
-
- public:
- enum DialogAction { Encrypt, Decrypt, Sign, Verify };
-
- /**
- * @brief
- *
- * @fn FileEncryptionDialog
- * @param ctx
- * @param keyList
- * @param parent
- */
- FileEncryptionDialog(KeyIdArgsListPtr keyList, DialogAction action,
- QWidget* parent = nullptr);
-
- public slots:
-
- /**
- * @details
- *
- * @fn selectInputFile
- */
- void slotSelectInputFile();
-
- /**
- * @brief
- *
- * @fn selectOutputFile
- */
- void slotSelectOutputFile();
-
- /**
- * @brief
- *
- * @fn selectSignFile
- */
- void slotSelectSignFile();
-
- /**
- * @brief
- *
- * @fn executeAction
- */
- void slotExecuteAction();
-
- /**
- * @brief
- *
- * @fn hideKeyList
- */
- void slotHideKeyList();
-
- /**
- * @brief
- *
- * @fn showKeyList
- */
- void slotShowKeyList();
-
- private:
- QLineEdit* outputFileEdit;
- QLineEdit* inputFileEdit;
- QLineEdit* signFileEdit;
- DialogAction mAction;
- QLabel* statusLabel;
-
- protected:
- KeyList* mKeyList;
-};
-
-} // namespace GpgFrontend::UI
-
-#endif // __FILEENCRYPTIONDIALOG_H__
diff --git a/src/ui/GpgFrontendUI.h b/src/ui/GpgFrontendUI.h
index 01f82822..90e15324 100644
--- a/src/ui/GpgFrontendUI.h
+++ b/src/ui/GpgFrontendUI.h
@@ -25,13 +25,15 @@
#ifndef GPGFRONTEND_GPGFRONTENDUI_H
#define GPGFRONTEND_GPGFRONTENDUI_H
-#include "GpgFrontend.h"
-
#include <QtCore>
#include <QtNetwork>
#include <QtPrintSupport>
#include <QtWidgets>
+#include "GpgFrontend.h"
+#include "gpg/GpgConstants.h"
+#include "gpg/GpgModel.h"
+
#undef LIBCONFIGXX_STATIC
#define LIBCONFIGXX_STATIC
#include <libconfig.h++>
diff --git a/src/ui/KeyImportDetailDialog.h b/src/ui/KeyImportDetailDialog.h
index fe63baaa..a75d466d 100644
--- a/src/ui/KeyImportDetailDialog.h
+++ b/src/ui/KeyImportDetailDialog.h
@@ -25,7 +25,7 @@
#ifndef __KEYIMPORTDETAILSDIALOG_H__
#define __KEYIMPORTDETAILSDIALOG_H__
-#include <gpg/function/GpgKeyImportExportor.h>
+#include <gpg/function/GpgKeyImportExporter.h>
#include "gpg/GpgContext.h"
#include "ui/GpgFrontendUI.h"
diff --git a/src/ui/KeyMgmt.cpp b/src/ui/KeyMgmt.cpp
index c03b8e6b..3715b01a 100755
--- a/src/ui/KeyMgmt.cpp
+++ b/src/ui/KeyMgmt.cpp
@@ -27,20 +27,23 @@
#include <utility>
#include "gpg/function/GpgKeyGetter.h"
-#include "gpg/function/GpgKeyImportExportor.h"
+#include "gpg/function/GpgKeyImportExporter.h"
#include "gpg/function/GpgKeyOpera.h"
#include "ui/SignalStation.h"
#include "ui/UserInterfaceUtils.h"
+#include "ui/aes/qaesencryption.h"
+#include "ui/keygen/SubkeyGenerateDialog.h"
#include "ui/settings/GlobalSettingStation.h"
+#include "ui/widgets/ExportKeyPackageDialog.h"
namespace GpgFrontend::UI {
KeyMgmt::KeyMgmt(QWidget* parent) : QMainWindow(parent) {
/* the list of Keys available*/
- mKeyList = new KeyList(true, this);
+ key_list_ = new KeyList(KeyMenuAbility::ALL, this);
- mKeyList->addListGroupTab(_("All"), KeyListRow::SECRET_OR_PUBLIC_KEY);
+ key_list_->addListGroupTab(_("All"), KeyListRow::SECRET_OR_PUBLIC_KEY);
- mKeyList->addListGroupTab(
+ key_list_->addListGroupTab(
_("Only Public Key"), KeyListRow::SECRET_OR_PUBLIC_KEY,
KeyListColumn::TYPE | KeyListColumn::NAME | KeyListColumn::EmailAddress |
KeyListColumn::Usage | KeyListColumn::Validity,
@@ -49,7 +52,7 @@ KeyMgmt::KeyMgmt(QWidget* parent) : QMainWindow(parent) {
!(key.revoked() || key.disabled() || key.expired());
});
- mKeyList->addListGroupTab(
+ key_list_->addListGroupTab(
_("Has Private Key"), KeyListRow::SECRET_OR_PUBLIC_KEY,
KeyListColumn::TYPE | KeyListColumn::NAME | KeyListColumn::EmailAddress |
KeyListColumn::Usage | KeyListColumn::Validity,
@@ -58,8 +61,8 @@ KeyMgmt::KeyMgmt(QWidget* parent) : QMainWindow(parent) {
!(key.revoked() || key.disabled() || key.expired());
});
- mKeyList->addListGroupTab(
- _("No Master Key"), KeyListRow::SECRET_OR_PUBLIC_KEY,
+ key_list_->addListGroupTab(
+ _("No Primary Key"), KeyListRow::SECRET_OR_PUBLIC_KEY,
KeyListColumn::TYPE | KeyListColumn::NAME | KeyListColumn::EmailAddress |
KeyListColumn::Usage | KeyListColumn::Validity,
[](const GpgKey& key) -> bool {
@@ -67,24 +70,24 @@ KeyMgmt::KeyMgmt(QWidget* parent) : QMainWindow(parent) {
!(key.revoked() || key.disabled() || key.expired());
});
- mKeyList->addListGroupTab(
+ key_list_->addListGroupTab(
_("Revoked"), KeyListRow::SECRET_OR_PUBLIC_KEY,
KeyListColumn::TYPE | KeyListColumn::NAME | KeyListColumn::EmailAddress |
KeyListColumn::Usage | KeyListColumn::Validity,
[](const GpgKey& key) -> bool { return key.revoked(); });
- mKeyList->addListGroupTab(
+ key_list_->addListGroupTab(
_("Expired"), KeyListRow::SECRET_OR_PUBLIC_KEY,
KeyListColumn::TYPE | KeyListColumn::NAME | KeyListColumn::EmailAddress |
KeyListColumn::Usage | KeyListColumn::Validity,
[](const GpgKey& key) -> bool { return key.expired(); });
- setCentralWidget(mKeyList);
- mKeyList->setDoubleClickedAction([this](const GpgKey& key, QWidget* parent) {
+ setCentralWidget(key_list_);
+ key_list_->setDoubleClickedAction([this](const GpgKey& key, QWidget* parent) {
new KeyDetailsDialog(key, parent);
});
- mKeyList->slotRefresh();
+ key_list_->slotRefresh();
createActions();
createMenus();
@@ -141,18 +144,16 @@ KeyMgmt::KeyMgmt(QWidget* parent) : QMainWindow(parent) {
this->resize(size);
this->move(pos);
- this->setWindowModality(Qt::ApplicationModal);
this->statusBar()->show();
setWindowTitle(_("KeyPair Management"));
- mKeyList->addMenuAction(deleteSelectedKeysAct);
- mKeyList->addMenuAction(showKeyDetailsAct);
+ key_list_->addMenuAction(deleteSelectedKeysAct);
+ key_list_->addMenuAction(showKeyDetailsAct);
connect(this, SIGNAL(signalKeyStatusUpdated()), SignalStation::GetInstance(),
SIGNAL(KeyDatabaseRefresh()));
- connect(SignalStation::GetInstance(),
- &SignalStation::signalRefreshStatusBar, this,
- [=](const QString& message, int timeout) {
+ connect(SignalStation::GetInstance(), &SignalStation::signalRefreshStatusBar,
+ this, [=](const QString& message, int timeout) {
statusBar()->showMessage(message, timeout);
});
}
@@ -204,17 +205,24 @@ void KeyMgmt::createActions() {
CommonUtils::GetInstance()->slotImportKeyFromKeyServer(this);
});
+ importKeysFromKeyPackageAct = new QAction(_("Key Package"), this);
+ importKeysFromKeyPackageAct->setIcon(QIcon(":key_package.png"));
+ importKeysFromKeyPackageAct->setToolTip(
+ _("Import Key(s) From a Key Package"));
+ connect(importKeysFromKeyPackageAct, &QAction::triggered, this,
+ &KeyMgmt::slotImportKeyPackage);
+
exportKeyToClipboardAct = new QAction(_("Export To Clipboard"), this);
exportKeyToClipboardAct->setIcon(QIcon(":export_key_to_clipboard.png"));
exportKeyToClipboardAct->setToolTip(_("Export Selected Key(s) To Clipboard"));
connect(exportKeyToClipboardAct, SIGNAL(triggered()), this,
SLOT(slotExportKeyToClipboard()));
- exportKeyToFileAct = new QAction(_("Export To File"), this);
- exportKeyToFileAct->setIcon(QIcon(":export_key_to_file.png"));
- exportKeyToFileAct->setToolTip(_("Export Selected Key(s) To File"));
+ exportKeyToFileAct = new QAction(_("Export To Key Package"), this);
+ exportKeyToFileAct->setIcon(QIcon(":key_package.png"));
+ exportKeyToFileAct->setToolTip(_("Export Checked Key(s) To a Key Package"));
connect(exportKeyToFileAct, SIGNAL(triggered()), this,
- SLOT(slotExportKeyToFile()));
+ SLOT(slotExportKeyToKeyPackage()));
exportKeyAsOpenSSHFormat = new QAction(_("Export As OpenSSH"), this);
exportKeyAsOpenSSHFormat->setIcon(QIcon(":ssh-key.png"));
@@ -254,6 +262,7 @@ void KeyMgmt::createMenus() {
importKeyMenu->addAction(importKeyFromFileAct);
importKeyMenu->addAction(importKeyFromClipboardAct);
importKeyMenu->addAction(importKeyFromKeyServerAct);
+ importKeyMenu->addAction(importKeysFromKeyPackageAct);
keyMenu->addAction(exportKeyToFileAct);
keyMenu->addAction(exportKeyToClipboardAct);
@@ -295,11 +304,11 @@ void KeyMgmt::createToolBars() {
}
void KeyMgmt::slotDeleteSelectedKeys() {
- deleteKeysWithWarning(mKeyList->getSelected());
+ deleteKeysWithWarning(key_list_->getSelected());
}
void KeyMgmt::slotDeleteCheckedKeys() {
- deleteKeysWithWarning(mKeyList->getChecked());
+ deleteKeysWithWarning(key_list_->getChecked());
}
void KeyMgmt::deleteKeysWithWarning(KeyIdArgsListPtr key_ids) {
@@ -308,8 +317,6 @@ void KeyMgmt::deleteKeysWithWarning(KeyIdArgsListPtr key_ids) {
* more than one selected... compare to seahorse "delete-dialog"
*/
- LOG(INFO) << "KeyMgmt::deleteKeysWithWarning Called";
-
if (key_ids->empty()) return;
QString keynames;
for (const auto& key_id : *key_ids) {
@@ -337,48 +344,44 @@ void KeyMgmt::deleteKeysWithWarning(KeyIdArgsListPtr key_ids) {
}
void KeyMgmt::slotShowKeyDetails() {
- auto keys_selected = mKeyList->getSelected();
+ auto keys_selected = key_list_->getSelected();
if (keys_selected->empty()) return;
auto key = GpgKeyGetter::GetInstance().GetKey(keys_selected->front());
if (!key.good()) {
- QMessageBox::critical(nullptr, _("Error"), _("Key Not Found."));
+ QMessageBox::critical(this, _("Error"), _("Key Not Found."));
return;
}
new KeyDetailsDialog(key);
}
-void KeyMgmt::slotExportKeyToFile() {
- ByteArrayPtr key_export_data = nullptr;
- auto keys_checked = mKeyList->getChecked();
- if (!GpgKeyImportExportor::GetInstance().ExportKeys(keys_checked,
- key_export_data)) {
- return;
- }
- auto key =
- GpgKeyGetter::GetInstance().GetKey(mKeyList->getSelected()->front());
- if (!key.good()) {
- QMessageBox::critical(nullptr, _("Error"), _("Key Not Found."));
+void KeyMgmt::slotExportKeyToKeyPackage() {
+ auto keys_checked = key_list_->getChecked();
+ if (keys_checked->empty()) {
+ QMessageBox::critical(
+ this, _("Forbidden"),
+ _("Please check some keys before doing this operation."));
return;
}
- QString fileString = QString::fromStdString(key.name() + " " + key.email() +
- "(" + key.id() + ")_pub.asc");
-
- QString file_name = QFileDialog::getSaveFileName(
- this, _("Export Key To File"), fileString,
- QString(_("Key Files")) + " (*.asc *.txt);;All Files (*)");
-
- write_buffer_to_file(file_name.toStdString(), *key_export_data);
-
+ auto dialog = new ExportKeyPackageDialog(std::move(keys_checked), this);
+ dialog->exec();
emit signalStatusBarChanged(QString(_("key(s) exported")));
}
void KeyMgmt::slotExportKeyToClipboard() {
+
+ auto keys_checked = key_list_->getChecked();
+ if (keys_checked->empty()) {
+ QMessageBox::critical(
+ this, _("Forbidden"),
+ _("Please check some keys before doing this operation."));
+ return;
+ }
+
ByteArrayPtr key_export_data = nullptr;
- auto keys_checked = mKeyList->getChecked();
- if (!GpgKeyImportExportor::GetInstance().ExportKeys(keys_checked,
+ if (!GpgKeyImportExporter::GetInstance().ExportKeys(keys_checked,
key_export_data)) {
return;
}
@@ -396,20 +399,20 @@ void KeyMgmt::closeEvent(QCloseEvent* event) {
}
void KeyMgmt::slotGenerateSubKey() {
- auto keys_selected = mKeyList->getSelected();
+ auto keys_selected = key_list_->getSelected();
if (keys_selected->empty()) {
QMessageBox::information(
- nullptr, _("Invalid Operation"),
+ this, _("Invalid Operation"),
_("Please select one KeyPair before doing this operation."));
return;
}
const auto key = GpgKeyGetter::GetInstance().GetKey(keys_selected->front());
if (!key.good()) {
- QMessageBox::critical(nullptr, _("Error"), _("Key Not Found."));
+ QMessageBox::critical(this, _("Error"), _("Key Not Found."));
return;
}
if (!key.is_private_key()) {
- QMessageBox::critical(nullptr, _("Invalid Operation"),
+ QMessageBox::critical(this, _("Invalid Operation"),
_("If a key pair does not have a private key then "
"it will not be able to generate sub-keys."));
return;
@@ -467,24 +470,26 @@ void KeyMgmt::slotSaveWindowState() {
void KeyMgmt::slotExportAsOpenSSHFormat() {
ByteArrayPtr key_export_data = nullptr;
- auto keys_checked = mKeyList->getChecked();
+ auto keys_checked = key_list_->getChecked();
if (keys_checked->empty()) {
- QMessageBox::critical(nullptr, _("Error"), _("No Key Checked."));
+ QMessageBox::critical(
+ this, _("Forbidden"),
+ _("Please select a key before performing this operation. If you select "
+ "multiple keys, only the first key will be exported."));
return;
}
auto key = GpgKeyGetter::GetInstance().GetKey(keys_checked->front());
- if (!GpgKeyImportExportor::GetInstance().ExportKeyOpenSSH(key,
+ if (!GpgKeyImportExporter::GetInstance().ExportKeyOpenSSH(key,
key_export_data)) {
- QMessageBox::critical(nullptr, _("Error"),
- _("An error occur in exporting."));
+ QMessageBox::critical(this, _("Error"), _("An error occur in exporting."));
return;
}
if (key_export_data->empty()) {
QMessageBox::critical(
- nullptr, _("Error"),
+ this, _("Error"),
_("This key may not be able to export as OpenSSH format. Please check "
"the key-size of the subkey(s) used to sign."));
return;
@@ -492,7 +497,7 @@ void KeyMgmt::slotExportAsOpenSSHFormat() {
key = GpgKeyGetter::GetInstance().GetKey(keys_checked->front());
if (!key.good()) {
- QMessageBox::critical(nullptr, _("Error"), _("Key Not Found."));
+ QMessageBox::critical(this, _("Error"), _("Key Not Found."));
return;
}
QString fileString = QString::fromStdString(key.name() + " " + key.email() +
@@ -508,4 +513,59 @@ void KeyMgmt::slotExportAsOpenSSHFormat() {
}
}
+void KeyMgmt::slotImportKeyPackage() {
+ auto key_package_file_name = QFileDialog::getOpenFileName(
+ this, _("Import Key Package"), {},
+ QString(_("Key Package")) + " (*.gfepack);;All Files (*)");
+
+ if (key_package_file_name.isEmpty()) return;
+
+ auto encrypted_data =
+ read_all_data_in_file(key_package_file_name.toStdString());
+
+ if (encrypted_data.empty()) {
+ QMessageBox::critical(this, _("Error"),
+ _("No data was read from the key package."));
+ return;
+ };
+
+ auto key_file_name = QFileDialog::getOpenFileName(
+ this, _("Import Key Package Passphrase File"), {},
+ QString(_("Key Package Passphrase File")) + " (*.key);;All Files (*)");
+
+ auto passphrase = read_all_data_in_file(key_file_name.toStdString());
+
+ LOG(INFO) << "passphrase size" << passphrase.size();
+ if (passphrase.size() != 256) {
+ QMessageBox::critical(
+ this, _("Wrong Passphrase"),
+ _("Please double check the passphrase you entered is correct."));
+ return;
+ }
+ auto hash_key = QCryptographicHash::hash(
+ QByteArray::fromStdString(passphrase), QCryptographicHash::Sha256);
+ auto encoded = QByteArray::fromStdString(encrypted_data);
+
+ QAESEncryption encryption(QAESEncryption::AES_256, QAESEncryption::ECB,
+ QAESEncryption::Padding::ISO);
+
+ auto decoded = encryption.removePadding(encryption.decode(encoded, hash_key));
+ auto key_data = QByteArray::fromBase64(decoded);
+
+ if (!key_data.startsWith(GpgConstants::PGP_PUBLIC_KEY_BEGIN) &&
+ !key_data.startsWith(GpgConstants::PGP_PRIVATE_KEY_BEGIN)) {
+ QMessageBox::critical(
+ this, _("Wrong Passphrase"),
+ _("Please double check the passphrase you entered is correct."));
+ return;
+ }
+
+ auto key_data_ptr = std::make_unique<ByteArray>(key_data.toStdString());
+ auto info =
+ GpgKeyImportExporter::GetInstance().ImportKey(std::move(key_data_ptr));
+
+ auto dialog = new KeyImportDetailDialog(info, false, this);
+ dialog->exec();
+}
+
} // namespace GpgFrontend::UI
diff --git a/src/ui/KeyMgmt.h b/src/ui/KeyMgmt.h
index 7edb1b5c..e3f250eb 100755
--- a/src/ui/KeyMgmt.h
+++ b/src/ui/KeyMgmt.h
@@ -44,7 +44,7 @@ class KeyMgmt : public QMainWindow {
void slotGenerateSubKey();
- void slotExportKeyToFile();
+ void slotExportKeyToKeyPackage();
void slotExportKeyToClipboard();
@@ -60,6 +60,8 @@ class KeyMgmt : public QMainWindow {
void slotSaveWindowState();
+ void slotImportKeyPackage();
+
signals:
void signalStatusBarChanged(QString);
@@ -75,7 +77,7 @@ class KeyMgmt : public QMainWindow {
void deleteKeysWithWarning(GpgFrontend::KeyIdArgsListPtr uidList);
- KeyList* mKeyList;
+ KeyList* key_list_;
QMenu* fileMenu{};
QMenu* keyMenu{};
QMenu* generateKeyMenu{};
@@ -92,6 +94,7 @@ class KeyMgmt : public QMainWindow {
QAction* importKeyFromClipboardAct{};
QAction* importKeyFromFileAct{};
QAction* importKeyFromKeyServerAct{};
+ QAction* importKeysFromKeyPackageAct{};
QAction* closeAct{};
QAction* showKeyDetailsAct{};
KeyServerImportDialog* importDialog{};
diff --git a/src/ui/KeyServerImportDialog.cpp b/src/ui/KeyServerImportDialog.cpp
index 844f2ae5..9a118b93 100644
--- a/src/ui/KeyServerImportDialog.cpp
+++ b/src/ui/KeyServerImportDialog.cpp
@@ -26,7 +26,7 @@
#include <utility>
-#include "gpg/function/GpgKeyImportExportor.h"
+#include "gpg/function/GpgKeyImportExporter.h"
#include "ui/SignalStation.h"
#include "ui/settings/GlobalSettingStation.h"
@@ -441,7 +441,7 @@ void KeyServerImportDialog::slotImport(const QStringList& keyIds,
}
}
-void KeyServerImportDialog::slotImportFinished(QString keyid) {
+void KeyServerImportDialog::slotImportFinished(const QString& keyid) {
LOG(INFO) << _("Called");
auto* reply = qobject_cast<QNetworkReply*>(sender());
@@ -503,7 +503,7 @@ void KeyServerImportDialog::slotImportFinished(QString keyid) {
void KeyServerImportDialog::importKeys(ByteArrayPtr in_data) {
GpgImportInformation result =
- GpgKeyImportExportor::GetInstance().ImportKey(std::move(in_data));
+ GpgKeyImportExporter::GetInstance().ImportKey(std::move(in_data));
emit signalKeyImported();
QWidget* _parent = qobject_cast<QWidget*>(parent());
if (mAutomatic) {
diff --git a/src/ui/KeyServerImportDialog.h b/src/ui/KeyServerImportDialog.h
index 508fb42d..e3761f5c 100644
--- a/src/ui/KeyServerImportDialog.h
+++ b/src/ui/KeyServerImportDialog.h
@@ -53,7 +53,7 @@ class KeyServerImportDialog : public QDialog {
void slotSearchFinished();
- void slotImportFinished(QString keyid);
+ void slotImportFinished(const QString& keyid);
void slotSearch();
diff --git a/src/ui/KeyUploadDialog.cpp b/src/ui/KeyUploadDialog.cpp
index 52aa2bd3..d2b8c0bf 100644
--- a/src/ui/KeyUploadDialog.cpp
+++ b/src/ui/KeyUploadDialog.cpp
@@ -27,15 +27,14 @@
#include <algorithm>
#include "gpg/function/GpgKeyGetter.h"
-#include "gpg/function/GpgKeyImportExportor.h"
+#include "gpg/function/GpgKeyImportExporter.h"
#include "ui/settings/GlobalSettingStation.h"
namespace GpgFrontend::UI {
KeyUploadDialog::KeyUploadDialog(const KeyIdArgsListPtr& keys_ids,
QWidget* parent)
- : QDialog(parent),
- mKeys(GpgKeyGetter::GetInstance().GetKeys(keys_ids)) {
+ : QDialog(parent), mKeys(GpgKeyGetter::GetInstance().GetKeys(keys_ids)) {
auto* pb = new QProgressBar();
pb->setRange(0, 0);
pb->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
@@ -54,13 +53,12 @@ KeyUploadDialog::KeyUploadDialog(const KeyIdArgsListPtr& keys_ids,
void KeyUploadDialog::slotUpload() {
auto out_data = std::make_unique<ByteArray>();
- GpgKeyImportExportor::GetInstance().ExportKeys(*mKeys, out_data);
+ GpgKeyImportExporter::GetInstance().ExportKeys(*mKeys, out_data);
uploadKeyToServer(*out_data);
}
void KeyUploadDialog::uploadKeyToServer(
const GpgFrontend::ByteArray& keys_data) {
-
std::string target_keyserver;
if (target_keyserver.empty()) {
try {
diff --git a/src/ui/MainWindow.cpp b/src/ui/MainWindow.cpp
index 8e6b6f81..2af6da78 100644
--- a/src/ui/MainWindow.cpp
+++ b/src/ui/MainWindow.cpp
@@ -50,7 +50,8 @@ void MainWindow::init() noexcept {
setCentralWidget(edit);
/* the list of Keys available*/
- mKeyList = new KeyList(true, this);
+ mKeyList = new KeyList(
+ KeyMenuAbility::REFRESH | KeyMenuAbility::UNCHECK_ALL, this);
infoBoard = new InfoBoardWidget(this);
@@ -115,21 +116,20 @@ void MainWindow::init() noexcept {
emit loaded();
+ // if not prohibit update checking
+ if (!prohibit_update_checking_) {
#ifdef RELEASE
- QString baseUrl =
- "https://api.github.com/repos/saturneric/gpgfrontend/releases/latest";
- QNetworkRequest request;
- request.setUrl(QUrl(baseUrl));
- auto* replay = networkAccessManager->get(request);
- auto version_thread = new VersionCheckThread(replay);
-
- connect(version_thread, SIGNAL(finished()), version_thread,
- SLOT(deleteLater()));
- connect(version_thread, &VersionCheckThread::upgradeVersion, this,
- &MainWindow::slotVersionUpgrade);
-
- version_thread->start();
+ auto version_thread = new VersionCheckThread();
+
+ connect(version_thread, SIGNAL(finished()), version_thread,
+ SLOT(deleteLater()));
+ connect(version_thread, &VersionCheckThread::upgradeVersion, this,
+ &MainWindow::slotVersionUpgrade);
+
+ version_thread->start();
#endif
+ }
+
} catch (...) {
LOG(FATAL) << _("Critical error occur while loading GpgFrontend.");
QMessageBox::critical(nullptr, _("Loading Failed"),
@@ -274,6 +274,11 @@ void MainWindow::restoreSettings() {
general.add("save_key_checked", libconfig::Setting::TypeBoolean) = true;
}
+ if (!general.exists("non_ascii_when_export")) {
+ general.add("non_ascii_when_export", libconfig::Setting::TypeBoolean) =
+ true;
+ }
+
bool save_key_checked = true;
general.lookupValue("save_key_checked", save_key_checked);
@@ -291,8 +296,24 @@ void MainWindow::restoreSettings() {
LOG(INFO) << "get checked key id" << key_id;
key_ids_ptr->push_back(key_id);
}
- mKeyList->setChecked(key_ids_ptr);
+ mKeyList->setChecked(std::move(key_ids_ptr));
}
+
+ auto& smtp = settings["smtp"];
+
+ if (!smtp.exists("enable")) {
+ smtp.add("enable", libconfig::Setting::TypeBoolean) = true;
+ }
+
+ prohibit_update_checking_ = false;
+ try {
+ prohibit_update_checking_ =
+ settings.lookup("network.prohibit_update_checking");
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error")
+ << _("prohibit_update_checking");
+ }
+
} catch (...) {
LOG(ERROR) << "cannot resolve settings";
}
diff --git a/src/ui/MainWindow.h b/src/ui/MainWindow.h
index 68b062ce..5f9d9b50 100644
--- a/src/ui/MainWindow.h
+++ b/src/ui/MainWindow.h
@@ -29,7 +29,6 @@
#include "gpg/result_analyse/DecryptResultAnalyse.h"
#include "gpg/result_analyse/EncryptResultAnalyse.h"
#include "gpg/result_analyse/SignResultAnalyse.h"
-#include "ui/FileEncryptionDialog.h"
#include "ui/FindWidget.h"
#include "ui/GpgFrontendUI.h"
#include "ui/KeyMgmt.h"
@@ -245,8 +244,7 @@ class MainWindow : public QMainWindow {
/**
* @details called when need to upgrade.
*/
- void slotVersionUpgrade(const QString& currentVersion,
- const QString& latestVersion);
+ void slotVersionUpgrade(const SoftwareVersion& version);
private:
/**
@@ -323,7 +321,7 @@ class MainWindow : public QMainWindow {
QMenu* viewMenu{}; /** Submenu for view operations */
QMenu* importKeyMenu{}; /** Sumenu for import operations */
#ifdef SMTP_SUPPORT
- QMenu* emailMenu{}; /** Sumenu for email operations */
+ QMenu* emailMenu{}; /** Sumenu for email operations */
#endif
QMenu* steganoMenu{}; /** Submenu for steganographic operations*/
@@ -332,6 +330,7 @@ class MainWindow : public QMainWindow {
QToolBar* editToolBar{}; /** Toolbar holding edit actions */
QToolBar* specialEditToolBar{}; /** Toolbar holding special edit actions */
QToolBar* keyToolBar{}; /** Toolbar holding key operations */
+ QToolBar* emailToolBar{}; /** Toolbar holding key operations */
QToolButton*
importButton{}; /** Toolbutton for import dropdown menu in toolbar */
QDockWidget* keyListDock{}; /** Encrypt Dock*/
@@ -399,6 +398,7 @@ class MainWindow : public QMainWindow {
bool attachmentDockCreated{};
bool restartNeeded{};
+ bool prohibit_update_checking_ = false;
};
} // namespace GpgFrontend::UI
diff --git a/src/ui/UserInterfaceUtils.cpp b/src/ui/UserInterfaceUtils.cpp
index 0931a179..967dcc32 100644
--- a/src/ui/UserInterfaceUtils.cpp
+++ b/src/ui/UserInterfaceUtils.cpp
@@ -41,7 +41,7 @@ std::unique_ptr<GpgFrontend::UI::CommonUtils>
#ifdef SMTP_SUPPORT
void send_an_email(QWidget* parent, InfoBoardWidget* info_board,
- const QString& text) {
+ const QString& text, bool attach_signature) {
info_board->addOptionalAction(_("Send Encrypted Mail"), [=]() {
bool smtp_enabled = false;
try {
@@ -52,6 +52,8 @@ void send_an_email(QWidget* parent, InfoBoardWidget* info_board,
}
if (smtp_enabled) {
auto dialog = new SendMailDialog(text, parent);
+ dialog->setContentEncryption(false);
+ dialog->setAttachSignature(attach_signature);
dialog->show();
} else {
QMessageBox::warning(nullptr, _("Function Disabled"),
@@ -151,11 +153,20 @@ CommonUtils* CommonUtils::GetInstance() {
CommonUtils::CommonUtils() : QWidget(nullptr) {
connect(this, SIGNAL(signalKeyStatusUpdated()), SignalStation::GetInstance(),
SIGNAL(KeyDatabaseRefresh()));
+ connect(this, &CommonUtils::signalGnupgNotInstall, this, []() {
+ QMessageBox::critical(
+ nullptr, _("ENV Loading Failed"),
+ _("Gnupg(gpg) is not installed correctly, please follow the "
+ "ReadME "
+ "instructions in Github to install Gnupg and then open "
+ "GpgFrontend."));
+ QCoreApplication::quit();
+ });
}
void CommonUtils::slotImportKeys(QWidget* parent,
const std::string& in_buffer) {
- GpgImportInformation result = GpgKeyImportExportor::GetInstance().ImportKey(
+ GpgImportInformation result = GpgKeyImportExporter::GetInstance().ImportKey(
std::make_unique<ByteArray>(in_buffer));
emit signalKeyStatusUpdated();
new KeyImportDetailDialog(result, false, parent);
@@ -300,7 +311,7 @@ void CommonUtils::slotImportKeyFromKeyServer(
// Try importing
GpgImportInformation result =
- GpgKeyImportExportor::GetInstance(ctx_channel)
+ GpgKeyImportExporter::GetInstance(ctx_channel)
.ImportKey(std::move(key_data_ptr));
if (result.imported == 1) {
diff --git a/src/ui/UserInterfaceUtils.h b/src/ui/UserInterfaceUtils.h
index be114b0a..d64b06b0 100644
--- a/src/ui/UserInterfaceUtils.h
+++ b/src/ui/UserInterfaceUtils.h
@@ -40,7 +40,7 @@ class TextEdit;
#ifdef SMTP_SUPPORT
void send_an_email(QWidget* parent, InfoBoardWidget* info_board,
- const QString& text);
+ const QString& text, bool attach_signature = true);
#endif
void show_verify_details(QWidget* parent, InfoBoardWidget* info_board,
@@ -75,6 +75,8 @@ class CommonUtils : public QWidget {
signals:
void signalKeyStatusUpdated();
+ void signalGnupgNotInstall();
+
public slots:
void slotImportKeys(QWidget* parent, const std::string& in_buffer);
diff --git a/src/ui/aes/qaesencryption.cpp b/src/ui/aes/qaesencryption.cpp
new file mode 100644
index 00000000..9103fb8e
--- /dev/null
+++ b/src/ui/aes/qaesencryption.cpp
@@ -0,0 +1,626 @@
+#include "qaesencryption.h"
+#include <QDebug>
+#include <QVector>
+
+#ifdef USE_INTEL_AES_IF_AVAILABLE
+#include "aesni/aesni-key-exp.h"
+#include "aesni/aesni-enc-ecb.h"
+#include "aesni/aesni-enc-cbc.h"
+#endif
+
+/*
+ * Static Functions
+ * */
+QByteArray QAESEncryption::Crypt(QAESEncryption::Aes level, QAESEncryption::Mode mode, const QByteArray &rawText,
+ const QByteArray &key, const QByteArray &iv, QAESEncryption::Padding padding)
+{
+ return QAESEncryption(level, mode, padding).encode(rawText, key, iv);
+}
+
+QByteArray QAESEncryption::Decrypt(QAESEncryption::Aes level, QAESEncryption::Mode mode, const QByteArray &rawText,
+ const QByteArray &key, const QByteArray &iv, QAESEncryption::Padding padding)
+{
+ return QAESEncryption(level, mode, padding).decode(rawText, key, iv);
+}
+
+QByteArray QAESEncryption::ExpandKey(QAESEncryption::Aes level, QAESEncryption::Mode mode, const QByteArray &key)
+{
+ return QAESEncryption(level, mode).expandKey(key);
+}
+
+QByteArray QAESEncryption::RemovePadding(const QByteArray &rawText, QAESEncryption::Padding padding)
+{
+ if (rawText.isEmpty())
+ return rawText;
+
+ QByteArray ret(rawText);
+ switch (padding)
+ {
+ case Padding::ZERO:
+ //Works only if the last byte of the decoded array is not zero
+ while (ret.at(ret.length()-1) == 0x00)
+ ret.remove(ret.length()-1, 1);
+ break;
+ case Padding::PKCS7:
+#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
+ ret.remove(ret.length() - ret.back(), ret.back());
+#else
+ ret.remove(ret.length() - ret.at(ret.length() - 1), ret.at(ret.length() - 1));
+#endif
+ break;
+ case Padding::ISO:
+ {
+ // Find the last byte which is not zero
+ int marker_index = ret.length() - 1;
+ for (; marker_index >= 0; --marker_index)
+ {
+ if (ret.at(marker_index) != 0x00)
+ {
+ break;
+ }
+ }
+
+ // And check if it's the byte for marking padding
+ if (ret.at(marker_index) == '\x80')
+ {
+ ret.truncate(marker_index);
+ }
+ break;
+ }
+ default:
+ //do nothing
+ break;
+ }
+ return ret;
+}
+/*
+ * End Static function declarations
+ * */
+
+/*
+ * Local Functions
+ * */
+
+namespace {
+
+quint8 xTime(quint8 x)
+{
+ return ((x<<1) ^ (((x>>7) & 1) * 0x1b));
+}
+
+quint8 multiply(quint8 x, quint8 y)
+{
+ return (((y & 1) * x) ^ ((y>>1 & 1) * xTime(x)) ^ ((y>>2 & 1) * xTime(xTime(x))) ^ ((y>>3 & 1)
+ * xTime(xTime(xTime(x)))) ^ ((y>>4 & 1) * xTime(xTime(xTime(xTime(x))))));
+}
+
+}
+
+/*
+ * End Local functions
+ * */
+
+QAESEncryption::QAESEncryption(Aes level, Mode mode,
+ Padding padding)
+ : m_nb(4), m_blocklen(16), m_level(level), m_mode(mode), m_padding(padding)
+ , m_aesNIAvailable(false), m_state(nullptr)
+{
+#ifdef USE_INTEL_AES_IF_AVAILABLE
+ m_aesNIAvailable = check_aesni_support();
+#endif
+
+ switch (level)
+ {
+ case AES_128: {
+ AES128 aes;
+ m_nk = aes.nk;
+ m_keyLen = aes.keylen;
+ m_nr = aes.nr;
+ m_expandedKey = aes.expandedKey;
+ }
+ break;
+ case AES_192: {
+ AES192 aes;
+ m_nk = aes.nk;
+ m_keyLen = aes.keylen;
+ m_nr = aes.nr;
+ m_expandedKey = aes.expandedKey;
+ }
+ break;
+ case AES_256: {
+ AES256 aes;
+ m_nk = aes.nk;
+ m_keyLen = aes.keylen;
+ m_nr = aes.nr;
+ m_expandedKey = aes.expandedKey;
+ }
+ break;
+ default: {
+ AES128 aes;
+ m_nk = aes.nk;
+ m_keyLen = aes.keylen;
+ m_nr = aes.nr;
+ m_expandedKey = aes.expandedKey;
+ }
+ break;
+ }
+
+}
+QByteArray QAESEncryption::getPadding(int currSize, int alignment)
+{
+ int size = (alignment - currSize % alignment) % alignment;
+ switch(m_padding)
+ {
+ case Padding::ZERO:
+ return QByteArray(size, 0x00);
+ break;
+ case Padding::PKCS7:
+ if (size == 0)
+ size = alignment;
+ return QByteArray(size, size);
+ break;
+ case Padding::ISO:
+ if (size > 0)
+ return QByteArray (size - 1, 0x00).prepend('\x80');
+ break;
+ default:
+ return QByteArray(size, 0x00);
+ break;
+ }
+ return QByteArray();
+}
+
+QByteArray QAESEncryption::expandKey(const QByteArray &key)
+{
+
+#ifdef USE_INTEL_AES_IF_AVAILABLE
+ if (true){
+ switch(m_level) {
+ case AES_128: {
+ AES128 aes128;
+ quint8 ret[aes128.expandedKey];
+ memset(ret, 0x00, sizeof(ret));
+ quint8 uchar_key[key.size()];
+ memcpy(uchar_key, key.data(), key.size());
+ AES_128_Key_Expansion(uchar_key, ret);
+ return QByteArray((char*) ret, aes128.expandedKey);
+ }
+ break;
+ case AES_192: {
+ AES192 aes192;
+ quint8 ret[aes192.expandedKey];
+ memset(ret, 0x00, sizeof(ret));
+ quint8 uchar_key[key.size()];
+ memcpy(uchar_key, key.data(), key.size());
+
+ AES_192_Key_Expansion(uchar_key, ret);
+ return QByteArray((char*) ret, aes192.expandedKey);
+ }
+ break;
+ case AES_256: {
+ AES256 aes256;
+ quint8 ret[aes256.expandedKey];
+ memset(ret, 0x00, sizeof(ret));
+ quint8 uchar_key[key.size()];
+ memcpy(uchar_key, key.data(), key.size());
+
+ AES_256_Key_Expansion(uchar_key, ret);
+ return QByteArray((char*) ret, aes256.expandedKey);
+ }
+ break;
+ default:
+ return QByteArray();
+ break;
+ }
+ } else
+#endif
+ {
+
+ int i, k;
+ quint8 tempa[4]; // Used for the column/row operations
+ QByteArray roundKey(key); // The first round key is the key itself.
+
+ // All other round keys are found from the previous round keys.
+ //i == Nk
+ for(i = m_nk; i < m_nb * (m_nr + 1); i++)
+ {
+ tempa[0] = (quint8) roundKey.at((i-1) * 4 + 0);
+ tempa[1] = (quint8) roundKey.at((i-1) * 4 + 1);
+ tempa[2] = (quint8) roundKey.at((i-1) * 4 + 2);
+ tempa[3] = (quint8) roundKey.at((i-1) * 4 + 3);
+
+ if (i % m_nk == 0)
+ {
+ // This function shifts the 4 bytes in a word to the left once.
+ // [a0,a1,a2,a3] becomes [a1,a2,a3,a0]
+
+ // Function RotWord()
+ k = tempa[0];
+ tempa[0] = tempa[1];
+ tempa[1] = tempa[2];
+ tempa[2] = tempa[3];
+ tempa[3] = k;
+
+ // Function Subword()
+ tempa[0] = getSBoxValue(tempa[0]);
+ tempa[1] = getSBoxValue(tempa[1]);
+ tempa[2] = getSBoxValue(tempa[2]);
+ tempa[3] = getSBoxValue(tempa[3]);
+
+ tempa[0] = tempa[0] ^ Rcon[i/m_nk];
+ }
+
+ if (m_level == AES_256 && i % m_nk == 4)
+ {
+ // Function Subword()
+ tempa[0] = getSBoxValue(tempa[0]);
+ tempa[1] = getSBoxValue(tempa[1]);
+ tempa[2] = getSBoxValue(tempa[2]);
+ tempa[3] = getSBoxValue(tempa[3]);
+ }
+ roundKey.insert(i * 4 + 0, (quint8) roundKey.at((i - m_nk) * 4 + 0) ^ tempa[0]);
+ roundKey.insert(i * 4 + 1, (quint8) roundKey.at((i - m_nk) * 4 + 1) ^ tempa[1]);
+ roundKey.insert(i * 4 + 2, (quint8) roundKey.at((i - m_nk) * 4 + 2) ^ tempa[2]);
+ roundKey.insert(i * 4 + 3, (quint8) roundKey.at((i - m_nk) * 4 + 3) ^ tempa[3]);
+ }
+ return roundKey;
+ }
+}
+
+// This function adds the round key to state.
+// The round key is added to the state by an XOR function.
+void QAESEncryption::addRoundKey(const quint8 round, const QByteArray &expKey)
+{
+ QByteArray::iterator it = m_state->begin();
+ for(int i=0; i < 16; ++i)
+ it[i] = (quint8) it[i] ^ (quint8) expKey.at(round * m_nb * 4 + (i/4) * m_nb + (i%4));
+}
+
+// The SubBytes Function Substitutes the values in the
+// state matrix with values in an S-box.
+void QAESEncryption::subBytes()
+{
+ QByteArray::iterator it = m_state->begin();
+ for(int i = 0; i < 16; i++)
+ it[i] = getSBoxValue((quint8) it[i]);
+}
+
+// The ShiftRows() function shifts the rows in the state to the left.
+// Each row is shifted with different offset.
+// Offset = Row number. So the first row is not shifted.
+void QAESEncryption::shiftRows()
+{
+ QByteArray::iterator it = m_state->begin();
+ quint8 temp;
+ //Keep in mind that QByteArray is column-driven!!
+
+ //Shift 1 to left
+ temp = (quint8)it[1];
+ it[1] = (quint8)it[5];
+ it[5] = (quint8)it[9];
+ it[9] = (quint8)it[13];
+ it[13] = (quint8)temp;
+
+ //Shift 2 to left
+ temp = (quint8)it[2];
+ it[2] = (quint8)it[10];
+ it[10] = (quint8)temp;
+ temp = (quint8)it[6];
+ it[6] = (quint8)it[14];
+ it[14] = (quint8)temp;
+
+ //Shift 3 to left
+ temp = (quint8)it[3];
+ it[3] = (quint8)it[15];
+ it[15] = (quint8)it[11];
+ it[11] = (quint8)it[7];
+ it[7] = (quint8)temp;
+}
+
+// MixColumns function mixes the columns of the state matrix
+//optimized!!
+void QAESEncryption::mixColumns()
+{
+ QByteArray::iterator it = m_state->begin();
+ quint8 tmp, tm, t;
+
+ for(int i = 0; i < 16; i += 4){
+ t = (quint8)it[i];
+ tmp = (quint8)it[i] ^ (quint8)it[i+1] ^ (quint8)it[i+2] ^ (quint8)it[i+3] ;
+
+ tm = xTime( (quint8)it[i] ^ (quint8)it[i+1] );
+ it[i] = (quint8)it[i] ^ (quint8)tm ^ (quint8)tmp;
+
+ tm = xTime( (quint8)it[i+1] ^ (quint8)it[i+2]);
+ it[i+1] = (quint8)it[i+1] ^ (quint8)tm ^ (quint8)tmp;
+
+ tm = xTime( (quint8)it[i+2] ^ (quint8)it[i+3]);
+ it[i+2] =(quint8)it[i+2] ^ (quint8)tm ^ (quint8)tmp;
+
+ tm = xTime((quint8)it[i+3] ^ (quint8)t);
+ it[i+3] =(quint8)it[i+3] ^ (quint8)tm ^ (quint8)tmp;
+ }
+}
+
+// MixColumns function mixes the columns of the state matrix.
+// The method used to multiply may be difficult to understand for the inexperienced.
+// Please use the references to gain more information.
+void QAESEncryption::invMixColumns()
+{
+ QByteArray::iterator it = m_state->begin();
+ quint8 a,b,c,d;
+ for(int i = 0; i < 16; i+=4){
+ a = (quint8) it[i];
+ b = (quint8) it[i+1];
+ c = (quint8) it[i+2];
+ d = (quint8) it[i+3];
+
+ it[i] = (quint8) (multiply(a, 0x0e) ^ multiply(b, 0x0b) ^ multiply(c, 0x0d) ^ multiply(d, 0x09));
+ it[i+1] = (quint8) (multiply(a, 0x09) ^ multiply(b, 0x0e) ^ multiply(c, 0x0b) ^ multiply(d, 0x0d));
+ it[i+2] = (quint8) (multiply(a, 0x0d) ^ multiply(b, 0x09) ^ multiply(c, 0x0e) ^ multiply(d, 0x0b));
+ it[i+3] = (quint8) (multiply(a, 0x0b) ^ multiply(b, 0x0d) ^ multiply(c, 0x09) ^ multiply(d, 0x0e));
+ }
+}
+
+// The SubBytes Function Substitutes the values in the
+// state matrix with values in an S-box.
+void QAESEncryption::invSubBytes()
+{
+ QByteArray::iterator it = m_state->begin();
+ for(int i = 0; i < 16; ++i)
+ it[i] = getSBoxInvert((quint8) it[i]);
+}
+
+void QAESEncryption::invShiftRows()
+{
+ QByteArray::iterator it = m_state->begin();
+ uint8_t temp;
+
+ //Keep in mind that QByteArray is column-driven!!
+
+ //Shift 1 to right
+ temp = (quint8)it[13];
+ it[13] = (quint8)it[9];
+ it[9] = (quint8)it[5];
+ it[5] = (quint8)it[1];
+ it[1] = (quint8)temp;
+
+ //Shift 2
+ temp = (quint8)it[10];
+ it[10] = (quint8)it[2];
+ it[2] = (quint8)temp;
+ temp = (quint8)it[14];
+ it[14] = (quint8)it[6];
+ it[6] = (quint8)temp;
+
+ //Shift 3
+ temp = (quint8)it[7];
+ it[7] = (quint8)it[11];
+ it[11] = (quint8)it[15];
+ it[15] = (quint8)it[3];
+ it[3] = (quint8)temp;
+}
+
+QByteArray QAESEncryption::byteXor(const QByteArray &a, const QByteArray &b)
+{
+ QByteArray::const_iterator it_a = a.begin();
+ QByteArray::const_iterator it_b = b.begin();
+ QByteArray ret;
+
+ //for(int i = 0; i < m_blocklen; i++)
+ for(int i = 0; i < std::min(a.size(), b.size()); i++)
+ ret.insert(i,it_a[i] ^ it_b[i]);
+
+ return ret;
+}
+
+// Cipher is the main function that encrypts the PlainText.
+QByteArray QAESEncryption::cipher(const QByteArray &expKey, const QByteArray &in)
+{
+
+ //m_state is the input buffer...
+ QByteArray output(in);
+ m_state = &output;
+
+ // Add the First round key to the state before starting the rounds.
+ addRoundKey(0, expKey);
+
+ // There will be Nr rounds.
+ // The first Nr-1 rounds are identical.
+ // These Nr-1 rounds are executed in the loop below.
+ for(quint8 round = 1; round < m_nr; ++round){
+ subBytes();
+ shiftRows();
+ mixColumns();
+ addRoundKey(round, expKey);
+ }
+
+ // The last round is given below.
+ // The MixColumns function is not here in the last round.
+ subBytes();
+ shiftRows();
+ addRoundKey(m_nr, expKey);
+
+ return output;
+}
+
+QByteArray QAESEncryption::invCipher(const QByteArray &expKey, const QByteArray &in)
+{
+ //m_state is the input buffer.... handle it!
+ QByteArray output(in);
+ m_state = &output;
+
+ // Add the First round key to the state before starting the rounds.
+ addRoundKey(m_nr, expKey);
+
+ // There will be Nr rounds.
+ // The first Nr-1 rounds are identical.
+ // These Nr-1 rounds are executed in the loop below.
+ for(quint8 round=m_nr-1; round>0 ; round--){
+ invShiftRows();
+ invSubBytes();
+ addRoundKey(round, expKey);
+ invMixColumns();
+ }
+
+ // The last round is given below.
+ // The MixColumns function is not here in the last round.
+ invShiftRows();
+ invSubBytes();
+ addRoundKey(0, expKey);
+
+ return output;
+}
+
+QByteArray QAESEncryption::printArray(uchar* arr, int size)
+{
+ QByteArray print("");
+ for(int i=0; i<size; i++)
+ print.append(arr[i]);
+
+ return print.toHex();
+}
+
+QByteArray QAESEncryption::encode(const QByteArray &rawText, const QByteArray &key, const QByteArray &iv)
+{
+ if (m_mode >= CBC && (iv.isEmpty() || iv.size() != m_blocklen))
+ return QByteArray();
+
+ QByteArray expandedKey = expandKey(key);
+ QByteArray alignedText(rawText);
+
+ //Fill array with padding
+ alignedText.append(getPadding(rawText.size(), m_blocklen));
+
+ switch(m_mode)
+ {
+ case ECB: {
+#ifdef USE_INTEL_AES_IF_AVAILABLE
+ if (m_aesNIAvailable){
+ unsigned char in[alignedText.size()];
+ memcpy(in, alignedText.data(), alignedText.size());
+ unsigned char out[alignedText.size()];
+ memcpy(out, alignedText.data(), alignedText.size());
+ char expKey[expandedKey.size()];
+ memcpy(expKey, expandedKey.data(), expandedKey.size());
+ AES_ECB_encrypt(in, out, alignedText.size(),
+ expKey, m_nr);
+ return QByteArray((char*)out, alignedText.size());
+ }
+#endif
+ QByteArray ret;
+ for(int i=0; i < alignedText.size(); i+= m_blocklen)
+ ret.append(cipher(expandedKey, alignedText.mid(i, m_blocklen)));
+ return ret;
+ }
+ break;
+ case CBC: {
+#ifdef USE_INTEL_AES_IF_AVAILABLE
+ if (m_aesNIAvailable){
+ quint8 in[alignedText.size()];
+ memcpy(in, alignedText.constData(), alignedText.size());
+ quint8 ivec[iv.size()];
+ memcpy(ivec, iv.data(), iv.size());
+ char out[alignedText.size()];
+ memset(out, 0x00, alignedText.size());
+ char expKey[expandedKey.size()];
+ memcpy(expKey, expandedKey.data(), expandedKey.size());
+ AES_CBC_encrypt(in,
+ (unsigned char*) out,
+ ivec,
+ alignedText.size(),
+ expKey,
+ m_nr);
+ return QByteArray(out, alignedText.size());
+ }
+#endif
+ QByteArray ret;
+ QByteArray ivTemp(iv);
+ for(int i=0; i < alignedText.size(); i+= m_blocklen) {
+ alignedText.replace(i, m_blocklen, byteXor(alignedText.mid(i, m_blocklen),ivTemp));
+ ret.append(cipher(expandedKey, alignedText.mid(i, m_blocklen)));
+ ivTemp = ret.mid(i, m_blocklen);
+ }
+ return ret;
+ }
+ break;
+ case CFB: {
+ QByteArray ret;
+ ret.append(byteXor(alignedText.left(m_blocklen), cipher(expandedKey, iv)));
+ for(int i=0; i < alignedText.size(); i+= m_blocklen) {
+ if (i+m_blocklen < alignedText.size())
+ ret.append(byteXor(alignedText.mid(i+m_blocklen, m_blocklen),
+ cipher(expandedKey, ret.mid(i, m_blocklen))));
+ }
+ return ret;
+ }
+ break;
+ case OFB: {
+ QByteArray ret;
+ QByteArray ofbTemp;
+ ofbTemp.append(cipher(expandedKey, iv));
+ for (int i=m_blocklen; i < alignedText.size(); i += m_blocklen){
+ ofbTemp.append(cipher(expandedKey, ofbTemp.right(m_blocklen)));
+ }
+ ret.append(byteXor(alignedText, ofbTemp));
+ return ret;
+ }
+ break;
+ default: break;
+ }
+ return QByteArray();
+}
+
+QByteArray QAESEncryption::decode(const QByteArray &rawText, const QByteArray &key, const QByteArray &iv)
+{
+ if (m_mode >= CBC && (iv.isEmpty() || iv.size() != m_blocklen))
+ return QByteArray();
+
+ QByteArray ret;
+ QByteArray expandedKey = expandKey(key);
+
+ switch(m_mode)
+ {
+ case ECB:
+ for(int i=0; i < rawText.size(); i+= m_blocklen)
+ ret.append(invCipher(expandedKey, rawText.mid(i, m_blocklen)));
+ break;
+ case CBC: {
+ QByteArray ivTemp(iv);
+ for(int i=0; i < rawText.size(); i+= m_blocklen){
+ ret.append(invCipher(expandedKey, rawText.mid(i, m_blocklen)));
+ ret.replace(i, m_blocklen, byteXor(ret.mid(i, m_blocklen),ivTemp));
+ ivTemp = rawText.mid(i, m_blocklen);
+ }
+ }
+ break;
+ case CFB: {
+ ret.append(byteXor(rawText.mid(0, m_blocklen), cipher(expandedKey, iv)));
+ for(int i=0; i < rawText.size(); i+= m_blocklen){
+ if (i+m_blocklen < rawText.size()) {
+ ret.append(byteXor(rawText.mid(i+m_blocklen, m_blocklen),
+ cipher(expandedKey, rawText.mid(i, m_blocklen))));
+ }
+ }
+ }
+ break;
+ case OFB: {
+ QByteArray ofbTemp;
+ ofbTemp.append(cipher(expandedKey, iv));
+ for (int i=m_blocklen; i < rawText.size(); i += m_blocklen){
+ ofbTemp.append(cipher(expandedKey, ofbTemp.right(m_blocklen)));
+ }
+ ret.append(byteXor(rawText, ofbTemp));
+ }
+ break;
+ default:
+ //do nothing
+ break;
+ }
+ return ret;
+}
+
+QByteArray QAESEncryption::removePadding(const QByteArray &rawText)
+{
+ return RemovePadding(rawText, (Padding) m_padding);
+}
diff --git a/src/ui/aes/qaesencryption.h b/src/ui/aes/qaesencryption.h
new file mode 100644
index 00000000..ec8023b3
--- /dev/null
+++ b/src/ui/aes/qaesencryption.h
@@ -0,0 +1,165 @@
+#ifndef QAESENCRYPTION_H
+#define QAESENCRYPTION_H
+
+#ifdef QtAES_EXPORTS
+#include "qtaes_export.h"
+#else
+#define QTAESSHARED_EXPORT
+#endif
+
+#include <QByteArray>
+#include <QObject>
+
+#ifdef __linux__
+#ifndef __LP64__
+#define do_rdtsc _do_rdtsc
+#endif
+#endif
+
+class QTAESSHARED_EXPORT QAESEncryption : public QObject {
+ Q_OBJECT
+ public:
+ enum Aes { AES_128, AES_192, AES_256 };
+
+ enum Mode { ECB, CBC, CFB, OFB };
+
+ enum Padding { ZERO, PKCS7, ISO };
+
+ static QByteArray Crypt(
+ QAESEncryption::Aes level, QAESEncryption::Mode mode,
+ const QByteArray &rawText, const QByteArray &key,
+ const QByteArray &iv = QByteArray(),
+ QAESEncryption::Padding padding = QAESEncryption::ISO);
+ static QByteArray Decrypt(
+ QAESEncryption::Aes level, QAESEncryption::Mode mode,
+ const QByteArray &rawText, const QByteArray &key,
+ const QByteArray &iv = QByteArray(),
+ QAESEncryption::Padding padding = QAESEncryption::ISO);
+ static QByteArray ExpandKey(QAESEncryption::Aes level,
+ QAESEncryption::Mode mode, const QByteArray &key);
+ static QByteArray RemovePadding(
+ const QByteArray &rawText,
+ QAESEncryption::Padding padding = QAESEncryption::ISO);
+
+ QAESEncryption(QAESEncryption::Aes level, QAESEncryption::Mode mode,
+ QAESEncryption::Padding padding = QAESEncryption::ISO);
+
+ QByteArray encode(const QByteArray &rawText, const QByteArray &key,
+ const QByteArray &iv = QByteArray());
+ QByteArray decode(const QByteArray &rawText, const QByteArray &key,
+ const QByteArray &iv = QByteArray());
+ QByteArray removePadding(const QByteArray &rawText);
+ QByteArray expandKey(const QByteArray &key);
+
+ QByteArray printArray(uchar *arr, int size);
+ Q_SIGNALS:
+
+ public Q_SLOTS:
+
+ private:
+ int m_nb;
+ int m_blocklen;
+ int m_level;
+ int m_mode;
+ int m_nk;
+ int m_keyLen;
+ quint8 m_nr;
+ int m_expandedKey;
+ int m_padding;
+ bool m_aesNIAvailable;
+ QByteArray *m_state;
+
+ struct AES256 {
+ int nk = 8;
+ int keylen = 32;
+ int nr = 14;
+ int expandedKey = 240;
+ };
+
+ struct AES192 {
+ int nk = 6;
+ int keylen = 24;
+ int nr = 12;
+ int expandedKey = 209;
+ };
+
+ struct AES128 {
+ int nk = 4;
+ int keylen = 16;
+ int nr = 10;
+ int expandedKey = 176;
+ };
+
+ quint8 getSBoxValue(quint8 num) { return sbox[num]; }
+ quint8 getSBoxInvert(quint8 num) { return rsbox[num]; }
+
+ void addRoundKey(const quint8 round, const QByteArray &expKey);
+ void subBytes();
+ void shiftRows();
+ void mixColumns();
+ void invMixColumns();
+ void invSubBytes();
+ void invShiftRows();
+ QByteArray getPadding(int currSize, int alignment);
+ QByteArray cipher(const QByteArray &expKey, const QByteArray &in);
+ QByteArray invCipher(const QByteArray &expKey, const QByteArray &in);
+ QByteArray byteXor(const QByteArray &a, const QByteArray &b);
+
+ const quint8 sbox[256] = {
+ // 0 1 2 3 4 5 6 7 8 9 A B C
+ // D E F
+ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b,
+ 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
+ 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26,
+ 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
+ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2,
+ 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
+ 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed,
+ 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
+ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f,
+ 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
+ 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec,
+ 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
+ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14,
+ 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
+ 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d,
+ 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
+ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f,
+ 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
+ 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11,
+ 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
+ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f,
+ 0xb0, 0x54, 0xbb, 0x16};
+
+ const quint8 rsbox[256] = {
+ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e,
+ 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
+ 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32,
+ 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
+ 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49,
+ 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,
+ 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50,
+ 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
+ 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05,
+ 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,
+ 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41,
+ 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
+ 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8,
+ 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,
+ 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b,
+ 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
+ 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59,
+ 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,
+ 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d,
+ 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
+ 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63,
+ 0x55, 0x21, 0x0c, 0x7d};
+
+ // The round constant word array, Rcon[i], contains the values given by
+ // x to th e power (i-1) being powers of x (x is denoted as {02}) in the field
+ // GF(2^8) Only the first 14 elements are needed
+ const quint8 Rcon[14] = {0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,
+ 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab};
+};
+
+#endif // QAESENCRYPTION_H
diff --git a/src/ui/data_struct/SoftwareVersion.cpp b/src/ui/data_struct/SoftwareVersion.cpp
new file mode 100644
index 00000000..2e814cb9
--- /dev/null
+++ b/src/ui/data_struct/SoftwareVersion.cpp
@@ -0,0 +1,25 @@
+/**
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "SoftwareVersion.h"
diff --git a/src/ui/data_struct/SoftwareVersion.h b/src/ui/data_struct/SoftwareVersion.h
new file mode 100644
index 00000000..be646b71
--- /dev/null
+++ b/src/ui/data_struct/SoftwareVersion.h
@@ -0,0 +1,59 @@
+/**
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef GPGFRONTEND_SOFTWAREVERSION_H
+#define GPGFRONTEND_SOFTWAREVERSION_H
+
+#include <boost/date_time.hpp>
+
+namespace GpgFrontend::UI {
+struct SoftwareVersion {
+ std::string latest_version;
+ std::string current_version;
+ bool latest_prerelease = false;
+ bool latest_draft = false;
+ bool current_prerelease = false;
+ bool current_draft = false;
+ bool load_info_done = false;
+ bool current_version_found = false;
+ std::string publish_date;
+ std::string release_note;
+
+ [[nodiscard]] bool NeedUpgrade() const {
+ return load_info_done && !latest_prerelease && !latest_draft &&
+ current_version < latest_version;
+ }
+
+ [[nodiscard]] bool VersionWithDrawn() const {
+ return load_info_done && !current_version_found && current_prerelease &&
+ !current_draft;
+ }
+
+ [[nodiscard]] bool CurrentVersionReleased() const {
+ return load_info_done && current_version_found;
+ }
+};
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_SOFTWAREVERSION_H
diff --git a/src/ui/function/CtxCheckThread.cpp b/src/ui/function/CtxCheckThread.cpp
new file mode 100644
index 00000000..b51954e1
--- /dev/null
+++ b/src/ui/function/CtxCheckThread.cpp
@@ -0,0 +1,48 @@
+/**
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "CtxCheckThread.h"
+
+#include "gpg/GpgContext.h"
+#include "gpg/GpgCoreInit.h"
+#include "gpg/function/GpgKeyGetter.h"
+#include "ui/UserInterfaceUtils.h"
+
+GpgFrontend::UI::CtxCheckThread::CtxCheckThread() : QThread(nullptr) {
+ connect(this, &CtxCheckThread::signalGnupgNotInstall,
+ CommonUtils::GetInstance(), &CommonUtils::signalGnupgNotInstall);
+}
+
+void GpgFrontend::UI::CtxCheckThread::run() {
+ // Init GpgFrontend Core
+ init_gpgfrontend_core();
+
+ // Create & Check Gnupg Context Status
+ if (!GpgContext::GetInstance().good()) {
+ emit signalGnupgNotInstall();
+ }
+ // Try fetching key
+ else
+ GpgFrontend::GpgKeyGetter::GetInstance().FetchKey();
+}
diff --git a/src/ui/function/CtxCheckThread.h b/src/ui/function/CtxCheckThread.h
new file mode 100644
index 00000000..74bdb491
--- /dev/null
+++ b/src/ui/function/CtxCheckThread.h
@@ -0,0 +1,42 @@
+/**
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef GPGFRONTEND_CTXCHECKTRHEAD_H
+#define GPGFRONTEND_CTXCHECKTRHEAD_H
+#include "ui/GpgFrontendUI.h"
+namespace GpgFrontend::UI {
+class CtxCheckThread : public QThread {
+ Q_OBJECT
+ public:
+ CtxCheckThread();
+
+ signals:
+ void signalGnupgNotInstall();
+
+ protected:
+ void run() override;
+};
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_CTXCHECKTRHEAD_H
diff --git a/src/ui/function/FileReadThread.h b/src/ui/function/FileReadThread.h
index ebfcfb3c..46ed6cbc 100644
--- a/src/ui/function/FileReadThread.h
+++ b/src/ui/function/FileReadThread.h
@@ -26,6 +26,7 @@
#define GPGFRONTEND_FILEREADTHREAD_H
#include "ui/GpgFrontendUI.h"
+
namespace GpgFrontend::UI {
class FileReadThread : public QThread {
@@ -35,7 +36,7 @@ class FileReadThread : public QThread {
explicit FileReadThread(std::string path);
signals:
-
+
void sendReadBlock(const QString& block);
void readDone();
diff --git a/src/ui/function/ProxyConnectionTestThread.cpp b/src/ui/function/ProxyConnectionTestThread.cpp
new file mode 100644
index 00000000..76cf525e
--- /dev/null
+++ b/src/ui/function/ProxyConnectionTestThread.cpp
@@ -0,0 +1,56 @@
+/**
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "ProxyConnectionTestThread.h"
+
+void GpgFrontend::UI::ProxyConnectionTestThread::run() {
+ QNetworkProxyQuery npq({QUrl(url_)});
+ auto proxies_list = QNetworkProxyFactory::systemProxyForQuery(npq);
+
+ if (proxies_list.isEmpty()) {
+ LOG(INFO) << "no proxy applied";
+ } else {
+ LOG(INFO) << "proxies list hostname"
+ << proxies_list.front().hostName().toStdString();
+ }
+
+ LOG(INFO) << "proxies list size" << proxies_list.size();
+
+ auto manager = std::make_unique<QNetworkAccessManager>(nullptr);
+ QNetworkRequest url_request;
+ url_request.setUrl(QUrl(url_));
+ auto _reply = manager->get(url_request);
+
+ while (_reply->isRunning()) QApplication::processEvents();
+ auto _buffer = _reply->readAll();
+ if (_reply->error() == QNetworkReply::NoError && !_buffer.isEmpty()) {
+ result_ = "Reachable";
+ } else {
+ result_ = "Not Reachable";
+ }
+
+ _reply->deleteLater();
+
+ emit signalProxyConnectionTestResult(result_);
+}
diff --git a/src/ui/function/ProxyConnectionTestThread.h b/src/ui/function/ProxyConnectionTestThread.h
new file mode 100644
index 00000000..4ef75050
--- /dev/null
+++ b/src/ui/function/ProxyConnectionTestThread.h
@@ -0,0 +1,57 @@
+/**
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef GPGFRONTEND_PROXYCONNECTIONTESTTHREAD_H
+#define GPGFRONTEND_PROXYCONNECTIONTESTTHREAD_H
+
+class ProxyConnectionTestThread {};
+
+#include <utility>
+
+#include "GpgFrontendUI.h"
+
+namespace GpgFrontend::UI {
+
+class ProxyConnectionTestThread : public QThread {
+ Q_OBJECT
+ public:
+ explicit ProxyConnectionTestThread(QString url, int timeout,
+ QWidget* parent = nullptr)
+ : QThread(parent), url_(std::move(url)), timeout_(timeout) {}
+
+ signals:
+ void signalProxyConnectionTestResult(const QString& result);
+
+ protected:
+ void run() override;
+
+ private:
+ QString url_;
+ QString result_;
+ int timeout_ = 500;
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_PROXYCONNECTIONTESTTHREAD_H
diff --git a/src/ui/function/SMTPSendMailThread.cpp b/src/ui/function/SMTPSendMailThread.cpp
new file mode 100644
index 00000000..edfd3156
--- /dev/null
+++ b/src/ui/function/SMTPSendMailThread.cpp
@@ -0,0 +1,261 @@
+/**
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "SMTPSendMailThread.h"
+
+#include <boost/format.hpp>
+
+#include "gpg/function/BasicOperator.h"
+#include "gpg/function/GpgKeyGetter.h"
+#include "gpg/function/GpgKeyImportExporter.h"
+
+namespace GpgFrontend::UI {
+
+void SMTPSendMailThread::run() {
+ SmtpClient smtp(host_.c_str(), port_, connection_type_);
+
+ if (identify_) {
+ smtp.setUser(username_.c_str());
+ smtp.setPassword(password_.c_str());
+ }
+
+ if (encrypt_content_ && public_key_ids_ != nullptr &&
+ !public_key_ids_->empty() && !attach_signature_file_) {
+ message.getContent().setContentType(
+ "multipart/encrypted; "
+ "protocol=\"application/pgp-encrypted\"");
+ }
+
+ if (attach_signature_file_ && !private_key_id_.empty()) {
+ message.getContent().setContentType(
+ "multipart/signed; "
+ "protocol=\"application/pgp-signature\"");
+ }
+
+ int index = 0;
+ for (auto& text : texts_) {
+ const auto plain_text = text->getText().toStdString();
+
+ // encrypt
+ if (encrypt_content_ && public_key_ids_ != nullptr &&
+ !public_key_ids_->empty()) {
+ ByteArrayPtr out_buffer = nullptr;
+ GpgEncrResult result;
+ auto in_buffer = std::make_unique<ByteArray>(plain_text);
+ auto keys = GpgKeyGetter::GetInstance().GetKeys(public_key_ids_);
+ auto err = BasicOperator::GetInstance().Encrypt(
+ std::move(keys), *in_buffer, out_buffer, result);
+
+ if (check_gpg_error_2_err_code(err) != GPG_ERR_NO_ERROR) {
+ emit signalSMTPResult("Fail to encrypt with gpg keys");
+ return;
+ }
+ text->setText(out_buffer->c_str());
+
+ // The multipart/encrypted MIME body MUST consist of exactly two body
+ // parts, the first with content type "application/pgp-encrypted". This
+ // body contains the control information. A message complying with this
+ // standard MUST contain a "Version: 1" field in this body. Since the
+ // OpenPGP packet format contains all other information necessary for
+ // decrypting, no other information is required here.
+ auto control_text = std::make_unique<MimeText>("Version: 1\r\n");
+ control_text->setContentType("application/pgp-encrypted");
+ send_texts_.push_back(std::move(control_text));
+ // The second MIME body part MUST contain the actual encrypted data. It
+ // MUST be labeled with a content type of "application/octet-stream".
+ text->setContentType("application/octet-stream");
+ }
+
+ send_texts_.push_back(std::move(text));
+
+ // sign
+ if (attach_signature_file_ && !private_key_id_.empty()) {
+ ByteArrayPtr out_buffer = nullptr;
+ GpgSignResult result;
+
+ auto& plain_mime_text = send_texts_.back();
+ // In particular, line endings in the encoded data
+ // MUST use the canonical <CR><LF> sequence where appropriate
+ auto encoded_text = plain_mime_text->getText();
+ // As described in section 3 of this document, any trailing
+ // whitespace MUST then be removed from the signed material.
+ encoded_text = encoded_text.trimmed();
+ encoded_text = encoded_text.replace('\n', "\r\n");
+ // An implementation which elects to adhere to the OpenPGP convention
+ // has to make sure it inserts a <CR><LF> pair on the last line of the
+ // data to be signed and transmitted.
+ encoded_text.append("\r\n");
+ plain_mime_text->setText(encoded_text);
+
+ // This presents serious problems
+ // for multipart/signed, in particular, where the signature is
+ // invalidated when such an operation occurs. For this reason all data
+ // signed according to this protocol MUST be constrained to 7 bits (8-
+ // bit data MUST be encoded using either Quoted-Printable or Base64).
+ plain_mime_text->setEncoding(MimePart::_7Bit);
+
+ // As described in [2], the digital signature MUST be calculated
+ // over both the data to be signed and its set of content headers.
+ auto text_calculated = plain_mime_text->toString().toStdString();
+
+ auto in_buffer = std::make_unique<ByteArray>(text_calculated);
+ auto key = GpgKeyGetter::GetInstance().GetKey(private_key_id_);
+ auto keys = std::make_unique<KeyArgsList>();
+ keys->push_back(std::move(key));
+
+ // The signature MUST be generated detached from the signed data
+ // so that the process does not alter the signed data in any way.
+ auto err = BasicOperator::GetInstance().Sign(
+ std::move(keys), *in_buffer, out_buffer, GPGME_SIG_MODE_DETACH,
+ result);
+
+ if (check_gpg_error_2_err_code(err) != GPG_ERR_NO_ERROR) {
+ emit signalSMTPResult("Fail to sign with gpg keys");
+ return;
+ }
+
+ auto sign_content_name =
+ boost::format("%1%_sign_%2%.asc") % private_key_id_ % index++;
+
+ // Set MIME Options
+ send_texts_.push_back(std::make_unique<MimeText>(out_buffer->c_str()));
+ auto& sig_text = send_texts_.back();
+ sig_text->setContentType("application/pgp-signature");
+ sig_text->setEncoding(MimePart::_7Bit);
+ sig_text->setContentName(sign_content_name.str().c_str());
+
+ // set Message Integrity Check (MIC) algorithm
+ if (result->signatures != nullptr) {
+ // The "micalg" parameter for the "application/pgp-signature"
+ // protocol
+ // MUST contain exactly one hash-symbol of the format "pgp-<hash-
+ // identifier>", where <hash-identifier> identifies the Message
+ // Integrity Check (MIC) algorithm used to generate the signature.
+ // Hash-symbols are constructed from the text names registered in [1]
+ // or according to the mechanism defined in that document by
+ // converting the text name to lower case and prefixing it with the
+ // four characters "pgp-".
+ auto hash_algo_name =
+ std::string(gpgme_hash_algo_name(result->signatures->hash_algo));
+ boost::algorithm::to_lower(hash_algo_name);
+ std::stringstream ss;
+ ss << message.getContent().getContentType().toStdString();
+ ss << "; micalg=pgp-" << hash_algo_name;
+ message.getContent().setContentType(ss.str().c_str());
+ }
+ }
+ }
+
+ if (attach_public_key_file_ && !attached_public_key_ids_.empty()) {
+ auto key = GpgKeyGetter::GetInstance().GetKey(attached_public_key_ids_);
+ ByteArrayPtr out_buffer = nullptr;
+ GpgKeyImportExporter::GetInstance().ExportKey(key, out_buffer);
+
+ auto public_key_file_name =
+ boost::format("%1%_pubkey.asc") % attached_public_key_ids_;
+ addFileContent(public_key_file_name.str().c_str(), out_buffer->c_str());
+ auto& key_file = files_.back();
+ key_file->setEncoding(MimePart::_7Bit);
+ key_file->setContentType("application/pgp-keys");
+ }
+
+ for (const auto& text : send_texts_) {
+ message.addPart(text.get());
+ }
+
+ for (const auto& file : files_) {
+ message.addPart(file.get());
+ }
+
+ // Now we can send the mail
+ if (!smtp.connectToHost()) {
+ emit signalSMTPResult("Fail to connect SMTP server");
+ return;
+ }
+ if (!smtp.login()) {
+ emit signalSMTPResult("Fail to login");
+ return;
+ }
+ if (!smtp.sendMail(message)) {
+ emit signalSMTPResult("Fail to send mail");
+ return;
+ }
+ smtp.quit();
+ emit signalSMTPResult("Succeed in sending a test email");
+}
+
+void SMTPSendMailThread::setBCC(const QString& bccs) {
+ QStringList bcc_string_list = bccs.split(';');
+ for (const auto& bcc : bcc_string_list) {
+ if (!bcc.isEmpty()) message.addBcc(new EmailAddress(bcc.trimmed()));
+ }
+}
+
+void SMTPSendMailThread::setCC(const QString& ccs) {
+ QStringList cc_string_list = ccs.split(';');
+ for (const auto& cc : cc_string_list) {
+ if (!cc.isEmpty()) message.addCc(new EmailAddress(cc.trimmed()));
+ }
+}
+
+void SMTPSendMailThread::setRecipient(const QString& recipients) {
+ QStringList rcpt_string_list = recipients.split(';');
+ for (const auto& rcpt : rcpt_string_list) {
+ if (!rcpt.isEmpty()) message.addRecipient(new EmailAddress(rcpt.trimmed()));
+ }
+}
+
+void SMTPSendMailThread::setSender(const QString& sender) {
+ message.setSender(new EmailAddress(sender));
+}
+
+void SMTPSendMailThread::addTextContent(const QString& content) {
+ auto text = std::make_unique<MimeText>(content.trimmed());
+ texts_.push_back(std::move(text));
+}
+
+void SMTPSendMailThread::addFileContent(const QString& file_name,
+ const QByteArray& content) {
+ auto file = std::make_unique<MimeFile>(content, file_name);
+ files_.push_back(std::move(file));
+}
+
+void SMTPSendMailThread::setEncryptContent(
+ bool encrypt_content, GpgFrontend::KeyIdArgsListPtr public_key_ids) {
+ this->encrypt_content_ = encrypt_content;
+ this->public_key_ids_ = std::move(public_key_ids);
+}
+
+void SMTPSendMailThread::setAttachSignatureFile(
+ bool attach_signature_file, GpgFrontend::KeyId private_key_id) {
+ this->attach_signature_file_ = attach_signature_file;
+ this->private_key_id_ = std::move(private_key_id);
+}
+
+void SMTPSendMailThread::setAttachPublicKey(
+ bool attach_public_key_file, GpgFrontend::KeyId attached_public_key_ids) {
+ this->attach_public_key_file_ = attach_public_key_file;
+ this->attached_public_key_ids_ = std::move(attached_public_key_ids);
+}
+} // namespace GpgFrontend::UI
diff --git a/src/ui/function/SMTPSendMailThread.h b/src/ui/function/SMTPSendMailThread.h
new file mode 100644
index 00000000..e5c9e27f
--- /dev/null
+++ b/src/ui/function/SMTPSendMailThread.h
@@ -0,0 +1,106 @@
+/**
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef GPGFRONTEND_SMTPSENDMAILTHREAD_H
+#define GPGFRONTEND_SMTPSENDMAILTHREAD_H
+
+#include <utility>
+
+#ifdef SMTP_SUPPORT
+#include "smtp/SmtpMime"
+#endif
+
+#include "ui/GpgFrontendUI.h"
+
+namespace GpgFrontend::UI {
+class SMTPSendMailThread : public QThread {
+ Q_OBJECT
+ public:
+ explicit SMTPSendMailThread(std::string host, int port,
+ SmtpClient::ConnectionType connection_type,
+ bool identify, std::string username,
+ std::string password, QWidget* parent = nullptr)
+ : QThread(parent),
+ host_(std::move(host)),
+ port_(port),
+ connection_type_(connection_type),
+ identify_(identify),
+ username_(std::move(username)),
+ password_(std::move(password)) {}
+
+ void setSender(const QString& sender);
+
+ void setRecipient(const QString& recipients);
+
+ void setCC(const QString& ccs);
+
+ void setBCC(const QString& bccs);
+
+ void setSubject(const QString& subject) { message.setSubject(subject); }
+
+ void addTextContent(const QString& content);
+
+ void addFileContent(const QString& file_name, const QByteArray& content);
+
+ void setEncryptContent(bool encrypt_content,
+ GpgFrontend::KeyIdArgsListPtr public_key_ids);
+
+ void setAttachSignatureFile(bool attach_signature_file,
+ GpgFrontend::KeyId private_key_id);
+
+ void setAttachPublicKey(bool attach_public_key_file,
+ GpgFrontend::KeyId attached_public_key_ids);
+
+ signals:
+ void signalSMTPResult(const QString& result);
+
+ protected:
+ void run() override;
+
+ private:
+ // SMTP Options
+ std::string host_;
+ int port_;
+ SmtpClient::ConnectionType connection_type_;
+
+ bool identify_;
+ std::string username_;
+ std::string password_;
+
+ MimeMessage message;
+ std::vector<std::unique_ptr<MimeText>> texts_;
+ std::vector<std::unique_ptr<MimeText>> send_texts_;
+ std::vector<std::unique_ptr<MimeFile>> files_;
+
+ // GPG Options
+ bool encrypt_content_ = false;
+ GpgFrontend::KeyIdArgsListPtr public_key_ids_;
+ bool attach_signature_file_ = false;
+ GpgFrontend::KeyId private_key_id_;
+ bool attach_public_key_file_ = false;
+ GpgFrontend::KeyId attached_public_key_ids_;
+};
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_SMTPSENDMAILTHREAD_H
diff --git a/src/ui/function/SMTPTestThread.cpp b/src/ui/function/SMTPTestThread.cpp
new file mode 100644
index 00000000..0eb267f2
--- /dev/null
+++ b/src/ui/function/SMTPTestThread.cpp
@@ -0,0 +1,46 @@
+/**
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "SMTPTestThread.h"
+namespace GpgFrontend::UI {
+
+void SMTPTestThread::run() {
+ SmtpClient smtp(host_.c_str(), port_, connection_type_);
+ if (identify_) {
+ smtp.setUser(username_.c_str());
+ smtp.setPassword(password_.c_str());
+ }
+ if (!smtp.connectToHost()) {
+ emit signalSMTPTestResult("Fail to connect SMTP server");
+ return;
+ }
+ if (!smtp.login()) {
+ emit signalSMTPTestResult("Fail to login");
+ return;
+ }
+ smtp.quit();
+ emit signalSMTPTestResult("Succeed in testing connection");
+}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/function/SMTPTestThread.h b/src/ui/function/SMTPTestThread.h
new file mode 100644
index 00000000..db61d97d
--- /dev/null
+++ b/src/ui/function/SMTPTestThread.h
@@ -0,0 +1,70 @@
+/**
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef GPGFRONTEND_SMTPTESTTHREAD_H
+#define GPGFRONTEND_SMTPTESTTHREAD_H
+
+#include <utility>
+
+#ifdef SMTP_SUPPORT
+#include "smtp/SmtpMime"
+#endif
+
+#include "ui/GpgFrontendUI.h"
+namespace GpgFrontend::UI {
+
+class SMTPTestThread : public QThread {
+ Q_OBJECT
+ public:
+ explicit SMTPTestThread(std::string host, int port,
+ SmtpClient::ConnectionType connection_type,
+ bool identify, std::string username,
+ std::string password, QWidget* parent = nullptr)
+ : QThread(parent),
+ host_(std::move(host)),
+ port_(port),
+ connection_type_(connection_type),
+ identify_(identify),
+ username_(std::move(username)),
+ password_(std::move(password)) {}
+
+ signals:
+ void signalSMTPTestResult(const QString& result);
+
+ protected:
+ void run() override;
+
+ private:
+ std::string host_;
+ int port_;
+ SmtpClient::ConnectionType connection_type_;
+
+ bool identify_;
+ std::string username_;
+ std::string password_;
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_SMTPTESTTHREAD_H
diff --git a/src/ui/function/TestListedKeyServerThread.cpp b/src/ui/function/TestListedKeyServerThread.cpp
new file mode 100644
index 00000000..4f816860
--- /dev/null
+++ b/src/ui/function/TestListedKeyServerThread.cpp
@@ -0,0 +1,47 @@
+/**
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "TestListedKeyServerThread.h"
+
+void GpgFrontend::UI::TestListedKeyServerThread::run() {
+ for (const auto& url : urls_) {
+ const auto keyserver_url = url;
+
+ auto key_url = QUrl{keyserver_url};
+
+ LOG(INFO) << "key server domain" << key_url.host().toStdString();
+
+ QTcpSocket socket(nullptr);
+ socket.abort();
+ socket.connectToHost(key_url.host(), 80);
+ if (socket.waitForConnected(timeout_)) {
+ result_.push_back("Reachable");
+ } else {
+ result_.push_back("Not Reachable");
+ }
+ socket.close();
+ }
+
+ emit signalKeyServerListTestResult(result_);
+}
diff --git a/src/ui/function/TestListedKeyServerThread.h b/src/ui/function/TestListedKeyServerThread.h
new file mode 100644
index 00000000..99fd6c6d
--- /dev/null
+++ b/src/ui/function/TestListedKeyServerThread.h
@@ -0,0 +1,55 @@
+/**
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef GPGFRONTEND_TESTLISTEDKEYSERVERTHREAD_H
+#define GPGFRONTEND_TESTLISTEDKEYSERVERTHREAD_H
+
+#include "GpgFrontendUI.h"
+
+namespace GpgFrontend::UI {
+
+class TestListedKeyServerThread : public QThread {
+ Q_OBJECT
+ public:
+ explicit TestListedKeyServerThread(const QStringList& urls, int timeout,
+ QWidget* parent = nullptr)
+ : QThread(parent), urls_(urls), timeout_(timeout) {}
+
+ signals:
+ void signalKeyServerListTestResult(const QStringList& result);
+
+ protected:
+ void run() override;
+
+ private:
+ QStringList urls_;
+ QStringList result_;
+ int timeout_ = 500;
+};
+
+} // namespace GpgFrontend::UI
+
+class TestListedKeyServerThread {};
+
+#endif // GPGFRONTEND_TESTLISTEDKEYSERVERTHREAD_H
diff --git a/src/ui/function/VersionCheckThread.cpp b/src/ui/function/VersionCheckThread.cpp
index bad60ef4..2a1cf9af 100644
--- a/src/ui/function/VersionCheckThread.cpp
+++ b/src/ui/function/VersionCheckThread.cpp
@@ -24,8 +24,7 @@
#include "VersionCheckThread.h"
-#include <iterator>
-#include <regex>
+#include <QMetaType>
#include "GpgFrontendBuildInfo.h"
#include "json/json.hpp"
@@ -33,45 +32,94 @@
namespace GpgFrontend::UI {
void VersionCheckThread::run() {
- using namespace nlohmann;
-
- LOG(INFO) << "get latest version from Github";
-
auto current_version = std::string("v") + std::to_string(VERSION_MAJOR) +
"." + std::to_string(VERSION_MINOR) + "." +
std::to_string(VERSION_PATCH);
- while (mNetworkReply->isRunning()) {
- QApplication::processEvents();
- }
-
- if (mNetworkReply->error() != QNetworkReply::NoError) {
- LOG(ERROR) << "network error";
- return;
+ SoftwareVersion version;
+ version.current_version = current_version;
+
+ auto manager = std::make_unique<QNetworkAccessManager>(nullptr);
+
+ try {
+ using namespace nlohmann;
+ LOG(INFO) << "current version" << current_version;
+
+ std::string latest_version_url =
+ "https://api.github.com/repos/saturneric/gpgfrontend/releases/latest";
+ std::string current_version_url =
+ "https://api.github.com/repos/saturneric/gpgfrontend/releases/tags/" +
+ current_version;
+
+ QNetworkRequest latest_request, current_request;
+ latest_request.setUrl(QUrl(latest_version_url.c_str()));
+ current_request.setUrl(QUrl(current_version_url.c_str()));
+ auto _reply = manager->get(latest_request);
+ while (_reply->isRunning()) QApplication::processEvents();
+ if (_reply->error() != QNetworkReply::NoError) {
+ LOG(ERROR) << "current version request error";
+ version.latest_version = current_version;
+ } else {
+ latest_reply_bytes_ = _reply->readAll();
+ auto latest_reply_json =
+ nlohmann::json::parse(latest_reply_bytes_.toStdString());
+
+ std::string latest_version = latest_reply_json["tag_name"];
+
+ LOG(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;
+ } else {
+ latest_version = current_version;
+ LOG(WARNING) << "latest version unknown";
+ }
+
+ bool prerelease = latest_reply_json["prerelease"],
+ draft = latest_reply_json["draft"];
+ std::string publish_date = latest_reply_json["published_at"];
+ std::string release_note = latest_reply_json["body"];
+ version.latest_version = latest_version;
+ version.latest_prerelease = prerelease;
+ version.latest_draft = draft;
+ version.publish_date = publish_date;
+ version.release_note = release_note;
+ }
+
+ _reply->deleteLater();
+
+ _reply = manager->get(current_request);
+ while (_reply->isRunning()) QApplication::processEvents();
+ current_reply_bytes_ = _reply->readAll();
+ if (_reply->error() != QNetworkReply::NoError) {
+ LOG(ERROR) << "current version request network error";
+ version.current_version_found = false;
+ } else {
+ version.current_version_found = true;
+ auto current_reply_json =
+ nlohmann::json::parse(current_reply_bytes_.toStdString());
+ bool current_prerelease = current_reply_json["prerelease"],
+ current_draft = current_reply_json["draft"];
+ version.latest_prerelease = current_prerelease;
+ version.latest_draft = current_draft;
+ }
+ _reply->deleteLater();
+
+ // loading done
+ version.load_info_done = true;
+
+ } catch (...) {
+ LOG(INFO) << "error occurred";
+ version.load_info_done = false;
}
-
- auto bytes = mNetworkReply->readAll();
-
- auto reply_json = nlohmann::json::parse(bytes.toStdString());
-
- std::string latest_version = reply_json["tag_name"];
-
- LOG(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;
- } else {
- latest_version = current_version;
- LOG(WARNING) << "latest version unknown";
- }
-
- emit upgradeVersion(current_version.c_str(), latest_version.c_str());
+ emit upgradeVersion(version);
}
-VersionCheckThread::VersionCheckThread(QNetworkReply* networkReply)
- : mNetworkReply(networkReply) {}
+VersionCheckThread::VersionCheckThread() : QThread(nullptr) {
+ qRegisterMetaType<SoftwareVersion>("SoftwareVersion");
+};
} // namespace GpgFrontend::UI
diff --git a/src/ui/function/VersionCheckThread.h b/src/ui/function/VersionCheckThread.h
index 181ee947..0db9770c 100644
--- a/src/ui/function/VersionCheckThread.h
+++ b/src/ui/function/VersionCheckThread.h
@@ -26,6 +26,7 @@
#define GPGFRONTEND_VERSIONCHECKTHREAD_H
#include "ui/GpgFrontendUI.h"
+#include "ui/data_struct/SoftwareVersion.h"
namespace GpgFrontend::UI {
@@ -33,18 +34,17 @@ class VersionCheckThread : public QThread {
Q_OBJECT
public:
- explicit VersionCheckThread(QNetworkReply* networkReply);
+ explicit VersionCheckThread();
signals:
- void upgradeVersion(const QString& currentVersion,
- const QString& latestVersion);
+ void upgradeVersion(SoftwareVersion version);
protected:
void run() override;
private:
- QNetworkReply* mNetworkReply;
+ QByteArray latest_reply_bytes_, current_reply_bytes_;
};
} // namespace GpgFrontend::UI
diff --git a/src/ui/help/AboutDialog.cpp b/src/ui/help/AboutDialog.cpp
index 93e7ccb3..78ff5557 100644
--- a/src/ui/help/AboutDialog.cpp
+++ b/src/ui/help/AboutDialog.cpp
@@ -86,8 +86,8 @@ 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::getGpgmeVersion().c_str() + "<br>" +
- _("Built at") + " " + BUILD_TIMESTAMP + "</center>");
+ GpgFrontend::GpgContext::GetInstance().GetInfo().GpgMEVersion.c_str() +
+ "<br>" + _("Built at") + " " + BUILD_TIMESTAMP + "</center>");
auto* layout = new QGridLayout();
auto* pixmapLabel = new QLabel();
@@ -163,14 +163,6 @@ UpdateTab::UpdateTab(QWidget* parent) : QWidget(parent) {
latestVersionLabel->setWordWrap(true);
upgradeLabel = new QLabel();
- upgradeLabel->setText(
- "<center>" +
- QString(_("The current version is less than the latest version on "
- "github.")) +
- "</center><center>" + _("Please click") +
- " <a "
- "href=\"https://github.com/saturneric/GpgFrontend/releases\">" +
- _("Here") + "</a> " + _("to download the latest version.") + "</center>");
upgradeLabel->setWordWrap(true);
upgradeLabel->setOpenExternalLinks(true);
upgradeLabel->setHidden(true);
@@ -196,11 +188,7 @@ void UpdateTab::getLatestVersion() {
LOG(INFO) << _("try to get latest version");
- QString base_url =
- "https://api.github.com/repos/saturneric/gpgfrontend/releases/latest";
- QNetworkRequest request;
- request.setUrl(QUrl(base_url));
- auto version_thread = new VersionCheckThread(manager->get(request));
+ auto version_thread = new VersionCheckThread();
connect(version_thread, SIGNAL(finished()), version_thread,
SLOT(deleteLater()));
@@ -210,15 +198,45 @@ void UpdateTab::getLatestVersion() {
version_thread->start();
}
-void UpdateTab::slotShowVersionStatus(const QString& current,
- const QString& server) {
+void UpdateTab::slotShowVersionStatus(const SoftwareVersion& version) {
this->pb->setHidden(true);
-
latestVersionLabel->setText("<center><b>" +
QString(_("Latest Version From Github")) + ": " +
- server + "</b></center>");
-
- if (current < server) {
+ version.latest_version.c_str() + "</b></center>");
+
+ if (version.NeedUpgrade()) {
+ upgradeLabel->setText(
+ "<center>" +
+ QString(_("The current version is less than the latest version on "
+ "github.")) +
+ "</center><center>" + _("Please click") +
+ " <a "
+ "href=\"https://github.com/saturneric/GpgFrontend/releases\">" +
+ _("Here") + "</a> " + _("to download the latest stable version.") +
+ "</center>");
+ upgradeLabel->show();
+ } else if (version.VersionWithDrawn()) {
+ upgradeLabel->setText(
+ "<center>" +
+ QString(_("This version has serious problems and has been withdrawn. "
+ "Please stop using it immediately.")) +
+ "</center><center>" + _("Please click") +
+ " <a "
+ "href=\"https://github.com/saturneric/GpgFrontend/releases\">" +
+ _("Here") + "</a> " + _("to download the latest stable version.") +
+ "</center>");
+ upgradeLabel->show();
+ } else if (!version.CurrentVersionReleased()) {
+ upgradeLabel->setText(
+ "<center>" +
+ QString(_("This version has not been released yet, it may be a beta "
+ "version. If you are not a tester and care about version "
+ "stability, please do not use this version.")) +
+ "</center><center>" + _("Please click") +
+ " <a "
+ "href=\"https://github.com/saturneric/GpgFrontend/releases\">" +
+ _("Here") + "</a> " + _("to download the latest stable version.") +
+ "</center>");
upgradeLabel->show();
}
}
diff --git a/src/ui/help/AboutDialog.h b/src/ui/help/AboutDialog.h
index 78c98149..44ab0e3c 100644
--- a/src/ui/help/AboutDialog.h
+++ b/src/ui/help/AboutDialog.h
@@ -27,6 +27,8 @@
#include "gpg/GpgContext.h"
#include "ui/GpgFrontendUI.h"
+#include "ui/data_struct/SoftwareVersion.h"
+
namespace GpgFrontend::UI {
/**
@@ -73,7 +75,7 @@ class UpdateTab : public QWidget {
void getLatestVersion();
private slots:
- void slotShowVersionStatus(const QString& current, const QString& server);
+ void slotShowVersionStatus(const SoftwareVersion& version);
signals:
void replyFromUpdateServer(QByteArray data);
diff --git a/src/ui/keygen/KeygenDialog.cpp b/src/ui/keygen/KeygenDialog.cpp
index 98ea1d5c..2baa22f4 100644
--- a/src/ui/keygen/KeygenDialog.cpp
+++ b/src/ui/keygen/KeygenDialog.cpp
@@ -27,6 +27,7 @@
#include "gpg/function/GpgKeyOpera.h"
#include "ui/SignalStation.h"
#include "ui/WaitingDialog.h"
+#include "ui/settings/GlobalSettingStation.h"
namespace GpgFrontend::UI {
@@ -34,6 +35,22 @@ KeyGenDialog::KeyGenDialog(QWidget* parent) : QDialog(parent) {
buttonBox =
new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+ auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
+
+ // max expire date time
+ bool longer_expiration_date = false;
+ try {
+ longer_expiration_date = settings.lookup("general.longer_expiration_date");
+ LOG(INFO) << "longer_expiration_date" << longer_expiration_date;
+
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("longer_expiration_date");
+ }
+
+ max_date_time_ = longer_expiration_date
+ ? QDateTime::currentDateTime().toLocalTime().addYears(30)
+ : QDateTime::currentDateTime().toLocalTime().addYears(2);
+
this->setWindowTitle(_("Generate Key"));
this->setModal(true);
@@ -83,9 +100,8 @@ void KeyGenDialog::slotKeyGenAccept() {
* primary keys should have a reasonable expiration date (no more than 2 years
* in the future)
*/
- if (dateEdit->dateTime() > QDateTime::currentDateTime().addYears(2)) {
- error_stream << " " << _("Expiration time no more than 2 years.")
- << std::endl;
+ if (dateEdit->dateTime() > max_date_time_) {
+ error_stream << " " << _("Expiration time too long.") << std::endl;
}
auto err_string = error_stream.str();
@@ -94,24 +110,24 @@ void KeyGenDialog::slotKeyGenAccept() {
/**
* create the string for key generation
*/
+ gen_key_info_->setName(nameEdit->text().toStdString());
+ gen_key_info_->setEmail(emailEdit->text().toStdString());
+ gen_key_info_->setComment(commentEdit->text().toStdString());
- genKeyInfo->setUserid(
- QString("%1(%3)<%2>")
- .arg(nameEdit->text(), emailEdit->text(), commentEdit->text())
- .toStdString());
-
- genKeyInfo->setKeySize(keySizeSpinBox->value());
+ gen_key_info_->setKeySize(keySizeSpinBox->value());
if (expireCheckBox->checkState()) {
- genKeyInfo->setNonExpired(true);
+ gen_key_info_->setNonExpired(true);
} else {
- genKeyInfo->setExpired(
+ gen_key_info_->setExpired(
boost::posix_time::from_time_t(dateEdit->dateTime().toTime_t()));
}
+ GpgGenKeyResult result;
gpgme_error_t error = false;
- auto thread = QThread::create(
- [&]() { error = GpgKeyOpera::GetInstance().GenerateKey(genKeyInfo); });
+ auto thread = QThread::create([&]() {
+ error = GpgKeyOpera::GetInstance().GenerateKey(gen_key_info_, result);
+ });
thread->start();
auto* dialog = new WaitingDialog(_("Generating"), this);
@@ -178,10 +194,10 @@ QGroupBox* KeyGenDialog::create_key_usage_group_box() {
auto* auth = new QCheckBox(_("Authentication"), groupBox);
auth->setTristate(false);
- keyUsageCheckBoxes.push_back(encrypt);
- keyUsageCheckBoxes.push_back(sign);
- keyUsageCheckBoxes.push_back(cert);
- keyUsageCheckBoxes.push_back(auth);
+ key_usage_check_boxes_.push_back(encrypt);
+ key_usage_check_boxes_.push_back(sign);
+ key_usage_check_boxes_.push_back(cert);
+ key_usage_check_boxes_.push_back(auth);
grid->addWidget(encrypt, 0, 0);
grid->addWidget(sign, 0, 1);
@@ -195,95 +211,95 @@ QGroupBox* KeyGenDialog::create_key_usage_group_box() {
void KeyGenDialog::slotEncryptionBoxChanged(int state) {
if (state == 0) {
- genKeyInfo->setAllowEncryption(false);
+ gen_key_info_->setAllowEncryption(false);
} else {
- genKeyInfo->setAllowEncryption(true);
+ gen_key_info_->setAllowEncryption(true);
}
}
void KeyGenDialog::slotSigningBoxChanged(int state) {
if (state == 0) {
- genKeyInfo->setAllowSigning(false);
+ gen_key_info_->setAllowSigning(false);
} else {
- genKeyInfo->setAllowSigning(true);
+ gen_key_info_->setAllowSigning(true);
}
}
void KeyGenDialog::slotCertificationBoxChanged(int state) {
if (state == 0) {
- genKeyInfo->setAllowCertification(false);
+ gen_key_info_->setAllowCertification(false);
} else {
- genKeyInfo->setAllowCertification(true);
+ gen_key_info_->setAllowCertification(true);
}
}
void KeyGenDialog::slotAuthenticationBoxChanged(int state) {
if (state == 0) {
- genKeyInfo->setAllowAuthentication(false);
+ gen_key_info_->setAllowAuthentication(false);
} else {
- genKeyInfo->setAllowAuthentication(true);
+ gen_key_info_->setAllowAuthentication(true);
}
}
void KeyGenDialog::slotActivatedKeyType(int index) {
qDebug() << "key type index changed " << index;
- genKeyInfo->setAlgo(this->keyTypeComboBox->itemText(index).toStdString());
+ gen_key_info_->setAlgo(this->keyTypeComboBox->itemText(index).toStdString());
refresh_widgets_state();
}
void KeyGenDialog::refresh_widgets_state() {
qDebug() << "refresh_widgets_state called";
- if (genKeyInfo->isAllowEncryption())
- keyUsageCheckBoxes[0]->setCheckState(Qt::CheckState::Checked);
+ if (gen_key_info_->isAllowEncryption())
+ key_usage_check_boxes_[0]->setCheckState(Qt::CheckState::Checked);
else
- keyUsageCheckBoxes[0]->setCheckState(Qt::CheckState::Unchecked);
+ key_usage_check_boxes_[0]->setCheckState(Qt::CheckState::Unchecked);
- if (genKeyInfo->isAllowChangeEncryption())
- keyUsageCheckBoxes[0]->setDisabled(false);
+ if (gen_key_info_->isAllowChangeEncryption())
+ key_usage_check_boxes_[0]->setDisabled(false);
else
- keyUsageCheckBoxes[0]->setDisabled(true);
+ key_usage_check_boxes_[0]->setDisabled(true);
- if (genKeyInfo->isAllowSigning())
- keyUsageCheckBoxes[1]->setCheckState(Qt::CheckState::Checked);
+ if (gen_key_info_->isAllowSigning())
+ key_usage_check_boxes_[1]->setCheckState(Qt::CheckState::Checked);
else
- keyUsageCheckBoxes[1]->setCheckState(Qt::CheckState::Unchecked);
+ key_usage_check_boxes_[1]->setCheckState(Qt::CheckState::Unchecked);
- if (genKeyInfo->isAllowChangeSigning())
- keyUsageCheckBoxes[1]->setDisabled(false);
+ if (gen_key_info_->isAllowChangeSigning())
+ key_usage_check_boxes_[1]->setDisabled(false);
else
- keyUsageCheckBoxes[1]->setDisabled(true);
+ key_usage_check_boxes_[1]->setDisabled(true);
- if (genKeyInfo->isAllowCertification())
- keyUsageCheckBoxes[2]->setCheckState(Qt::CheckState::Checked);
+ if (gen_key_info_->isAllowCertification())
+ key_usage_check_boxes_[2]->setCheckState(Qt::CheckState::Checked);
else
- keyUsageCheckBoxes[2]->setCheckState(Qt::CheckState::Unchecked);
+ key_usage_check_boxes_[2]->setCheckState(Qt::CheckState::Unchecked);
- if (genKeyInfo->isAllowChangeCertification())
- keyUsageCheckBoxes[2]->setDisabled(false);
+ if (gen_key_info_->isAllowChangeCertification())
+ key_usage_check_boxes_[2]->setDisabled(false);
else
- keyUsageCheckBoxes[2]->setDisabled(true);
+ key_usage_check_boxes_[2]->setDisabled(true);
- if (genKeyInfo->isAllowAuthentication())
- keyUsageCheckBoxes[3]->setCheckState(Qt::CheckState::Checked);
+ if (gen_key_info_->isAllowAuthentication())
+ key_usage_check_boxes_[3]->setCheckState(Qt::CheckState::Checked);
else
- keyUsageCheckBoxes[3]->setCheckState(Qt::CheckState::Unchecked);
+ key_usage_check_boxes_[3]->setCheckState(Qt::CheckState::Unchecked);
- if (genKeyInfo->isAllowChangeAuthentication())
- keyUsageCheckBoxes[3]->setDisabled(false);
+ if (gen_key_info_->isAllowChangeAuthentication())
+ key_usage_check_boxes_[3]->setDisabled(false);
else
- keyUsageCheckBoxes[3]->setDisabled(true);
+ key_usage_check_boxes_[3]->setDisabled(true);
- if (genKeyInfo->isAllowNoPassPhrase())
+ if (gen_key_info_->isAllowNoPassPhrase())
noPassPhraseCheckBox->setDisabled(false);
else
noPassPhraseCheckBox->setDisabled(true);
- keySizeSpinBox->setRange(genKeyInfo->getSuggestMinKeySize(),
- genKeyInfo->getSuggestMaxKeySize());
- keySizeSpinBox->setValue(genKeyInfo->getKeySize());
- keySizeSpinBox->setSingleStep(genKeyInfo->getSizeChangeStep());
+ keySizeSpinBox->setRange(gen_key_info_->getSuggestMinKeySize(),
+ gen_key_info_->getSuggestMaxKeySize());
+ keySizeSpinBox->setValue(gen_key_info_->getKeySize());
+ keySizeSpinBox->setSingleStep(gen_key_info_->getSizeChangeStep());
}
void KeyGenDialog::set_signal_slot() {
@@ -293,13 +309,13 @@ void KeyGenDialog::set_signal_slot() {
connect(expireCheckBox, SIGNAL(stateChanged(int)), this,
SLOT(slotExpireBoxChanged()));
- connect(keyUsageCheckBoxes[0], SIGNAL(stateChanged(int)), this,
+ connect(key_usage_check_boxes_[0], SIGNAL(stateChanged(int)), this,
SLOT(slotEncryptionBoxChanged(int)));
- connect(keyUsageCheckBoxes[1], SIGNAL(stateChanged(int)), this,
+ connect(key_usage_check_boxes_[1], SIGNAL(stateChanged(int)), this,
SLOT(slotSigningBoxChanged(int)));
- connect(keyUsageCheckBoxes[2], SIGNAL(stateChanged(int)), this,
+ connect(key_usage_check_boxes_[2], SIGNAL(stateChanged(int)), this,
SLOT(slotCertificationBoxChanged(int)));
- connect(keyUsageCheckBoxes[3], SIGNAL(stateChanged(int)), this,
+ connect(key_usage_check_boxes_[3], SIGNAL(stateChanged(int)), this,
SLOT(slotAuthenticationBoxChanged(int)));
connect(keyTypeComboBox, SIGNAL(currentIndexChanged(int)), this,
@@ -308,9 +324,9 @@ void KeyGenDialog::set_signal_slot() {
connect(noPassPhraseCheckBox, &QCheckBox::stateChanged, this,
[this](int state) -> void {
if (state == 0) {
- genKeyInfo->setNonPassPhrase(false);
+ gen_key_info_->setNonPassPhrase(false);
} else {
- genKeyInfo->setNonPassPhrase(true);
+ gen_key_info_->setNonPassPhrase(true);
}
});
}
@@ -327,18 +343,16 @@ QGroupBox* KeyGenDialog::create_basic_info_group_box() {
keySizeSpinBox = new QSpinBox(this);
keyTypeComboBox = new QComboBox(this);
- for (auto& algo : GenKeyInfo::SupportedKeyAlgo) {
+ for (auto& algo : GenKeyInfo::getSupportedKeyAlgo()) {
keyTypeComboBox->addItem(QString::fromStdString(algo));
}
- if (!GenKeyInfo::SupportedKeyAlgo.empty()) {
+ if (!GenKeyInfo::getSupportedKeyAlgo().empty()) {
keyTypeComboBox->setCurrentIndex(0);
}
- QDateTime maxDateTime = QDateTime::currentDateTime().addYears(2);
-
- dateEdit = new QDateTimeEdit(maxDateTime, this);
+ dateEdit = new QDateTimeEdit(QDateTime::currentDateTime().addYears(2), this);
dateEdit->setMinimumDateTime(QDateTime::currentDateTime());
- dateEdit->setMaximumDateTime(maxDateTime);
+ dateEdit->setMaximumDateTime(max_date_time_);
dateEdit->setDisplayFormat("dd/MM/yyyy hh:mm:ss");
dateEdit->setCalendarPopup(true);
dateEdit->setEnabled(true);
diff --git a/src/ui/keygen/KeygenDialog.h b/src/ui/keygen/KeygenDialog.h
index c16a2e76..1b9fdb2a 100644
--- a/src/ui/keygen/KeygenDialog.h
+++ b/src/ui/keygen/KeygenDialog.h
@@ -55,9 +55,9 @@ class KeyGenDialog : public QDialog {
QRegularExpression re_email{
R"((?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\]))"};
- QStringList errorMessages; /** List of errors occuring when checking entries
+ QStringList error_messages_; /** List of errors occuring when checking entries
of lineedits */
- std::unique_ptr<GenKeyInfo> genKeyInfo = std::make_unique<GenKeyInfo>();
+ std::unique_ptr<GenKeyInfo> gen_key_info_ = std::make_unique<GenKeyInfo>();
QDialogButtonBox* buttonBox; /** Box for standard buttons */
QLabel* errorLabel{}; /** Label containing error message */
@@ -72,9 +72,10 @@ class KeyGenDialog : public QDialog {
QGroupBox* keyUsageGroupBox{}; /** Group of Widgets detecting the usage of the
Key **/
+ QDateTime max_date_time_;
// ENCR, SIGN, CERT, AUTH
- std::vector<QCheckBox*> keyUsageCheckBoxes;
+ std::vector<QCheckBox*> key_usage_check_boxes_;
void generateKeyDialog();
diff --git a/src/ui/keygen/SubkeyGenerateDialog.cpp b/src/ui/keygen/SubkeyGenerateDialog.cpp
index 9bac076e..70d3ee3c 100644
--- a/src/ui/keygen/SubkeyGenerateDialog.cpp
+++ b/src/ui/keygen/SubkeyGenerateDialog.cpp
@@ -28,11 +28,28 @@
#include "gpg/function/GpgKeyOpera.h"
#include "ui/SignalStation.h"
#include "ui/WaitingDialog.h"
+#include "ui/settings/GlobalSettingStation.h"
namespace GpgFrontend::UI {
SubkeyGenerateDialog::SubkeyGenerateDialog(const KeyId& key_id, QWidget* parent)
- : QDialog(parent), mKey(GpgKeyGetter::GetInstance().GetKey(key_id)) {
+ : QDialog(parent), key_(GpgKeyGetter::GetInstance().GetKey(key_id)) {
+ auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
+
+ // max expire date time
+ bool longer_expiration_date = false;
+ try {
+ longer_expiration_date = settings.lookup("general.longer_expiration_date");
+ LOG(INFO) << "longer_expiration_date" << longer_expiration_date;
+
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("longer_expiration_date");
+ }
+
+ max_date_time_ = longer_expiration_date
+ ? QDateTime::currentDateTime().toLocalTime().addYears(30)
+ : QDateTime::currentDateTime().toLocalTime().addYears(2);
+
buttonBox =
new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
@@ -79,10 +96,10 @@ QGroupBox* SubkeyGenerateDialog::create_key_usage_group_box() {
auto* auth = new QCheckBox(_("Authentication"), groupBox);
auth->setTristate(false);
- keyUsageCheckBoxes.push_back(encrypt);
- keyUsageCheckBoxes.push_back(sign);
- keyUsageCheckBoxes.push_back(cert);
- keyUsageCheckBoxes.push_back(auth);
+ key_usage_check_boxes_.push_back(encrypt);
+ key_usage_check_boxes_.push_back(sign);
+ key_usage_check_boxes_.push_back(cert);
+ key_usage_check_boxes_.push_back(auth);
grid->addWidget(encrypt, 0, 0);
grid->addWidget(sign, 0, 1);
@@ -99,18 +116,17 @@ QGroupBox* SubkeyGenerateDialog::create_basic_info_group_box() {
keySizeSpinBox = new QSpinBox(this);
keyTypeComboBox = new QComboBox(this);
- for (auto& algo : GenKeyInfo::SupportedSubkeyAlgo) {
+ for (auto& algo : GenKeyInfo::getSupportedKeyAlgo()) {
keyTypeComboBox->addItem(QString::fromStdString(algo));
}
- if (!GenKeyInfo::SupportedKeyAlgo.empty()) {
+ if (!GenKeyInfo::getSupportedKeyAlgo().empty()) {
keyTypeComboBox->setCurrentIndex(0);
}
- QDateTime maxDateTime = QDateTime::currentDateTime().addYears(2);
- dateEdit = new QDateTimeEdit(maxDateTime, this);
+ dateEdit = new QDateTimeEdit(QDateTime::currentDateTime().addYears(2), this);
dateEdit->setMinimumDateTime(QDateTime::currentDateTime());
- dateEdit->setMaximumDateTime(maxDateTime);
+ dateEdit->setMaximumDateTime(max_date_time_);
dateEdit->setDisplayFormat("dd/MM/yyyy hh:mm:ss");
dateEdit->setCalendarPopup(true);
dateEdit->setEnabled(true);
@@ -144,13 +160,13 @@ void SubkeyGenerateDialog::set_signal_slot() {
connect(expireCheckBox, SIGNAL(stateChanged(int)), this,
SLOT(slotExpireBoxChanged()));
- connect(keyUsageCheckBoxes[0], SIGNAL(stateChanged(int)), this,
+ connect(key_usage_check_boxes_[0], SIGNAL(stateChanged(int)), this,
SLOT(slotEncryptionBoxChanged(int)));
- connect(keyUsageCheckBoxes[1], SIGNAL(stateChanged(int)), this,
+ connect(key_usage_check_boxes_[1], SIGNAL(stateChanged(int)), this,
SLOT(slotSigningBoxChanged(int)));
- connect(keyUsageCheckBoxes[2], SIGNAL(stateChanged(int)), this,
+ connect(key_usage_check_boxes_[2], SIGNAL(stateChanged(int)), this,
SLOT(slotCertificationBoxChanged(int)));
- connect(keyUsageCheckBoxes[3], SIGNAL(stateChanged(int)), this,
+ connect(key_usage_check_boxes_[3], SIGNAL(stateChanged(int)), this,
SLOT(slotAuthenticationBoxChanged(int)));
connect(keyTypeComboBox, SIGNAL(currentIndexChanged(int)), this,
@@ -168,50 +184,50 @@ void SubkeyGenerateDialog::slotExpireBoxChanged() {
void SubkeyGenerateDialog::refresh_widgets_state() {
qDebug() << "refresh_widgets_state called";
- if (genKeyInfo->isAllowEncryption())
- keyUsageCheckBoxes[0]->setCheckState(Qt::CheckState::Checked);
+ if (gen_key_info_->isAllowEncryption())
+ key_usage_check_boxes_[0]->setCheckState(Qt::CheckState::Checked);
else
- keyUsageCheckBoxes[0]->setCheckState(Qt::CheckState::Unchecked);
+ key_usage_check_boxes_[0]->setCheckState(Qt::CheckState::Unchecked);
- if (genKeyInfo->isAllowChangeEncryption())
- keyUsageCheckBoxes[0]->setDisabled(false);
+ if (gen_key_info_->isAllowChangeEncryption())
+ key_usage_check_boxes_[0]->setDisabled(false);
else
- keyUsageCheckBoxes[0]->setDisabled(true);
+ key_usage_check_boxes_[0]->setDisabled(true);
- if (genKeyInfo->isAllowSigning())
- keyUsageCheckBoxes[1]->setCheckState(Qt::CheckState::Checked);
+ if (gen_key_info_->isAllowSigning())
+ key_usage_check_boxes_[1]->setCheckState(Qt::CheckState::Checked);
else
- keyUsageCheckBoxes[1]->setCheckState(Qt::CheckState::Unchecked);
+ key_usage_check_boxes_[1]->setCheckState(Qt::CheckState::Unchecked);
- if (genKeyInfo->isAllowChangeSigning())
- keyUsageCheckBoxes[1]->setDisabled(false);
+ if (gen_key_info_->isAllowChangeSigning())
+ key_usage_check_boxes_[1]->setDisabled(false);
else
- keyUsageCheckBoxes[1]->setDisabled(true);
+ key_usage_check_boxes_[1]->setDisabled(true);
- if (genKeyInfo->isAllowCertification())
- keyUsageCheckBoxes[2]->setCheckState(Qt::CheckState::Checked);
+ if (gen_key_info_->isAllowCertification())
+ key_usage_check_boxes_[2]->setCheckState(Qt::CheckState::Checked);
else
- keyUsageCheckBoxes[2]->setCheckState(Qt::CheckState::Unchecked);
+ key_usage_check_boxes_[2]->setCheckState(Qt::CheckState::Unchecked);
- if (genKeyInfo->isAllowChangeCertification())
- keyUsageCheckBoxes[2]->setDisabled(false);
+ if (gen_key_info_->isAllowChangeCertification())
+ key_usage_check_boxes_[2]->setDisabled(false);
else
- keyUsageCheckBoxes[2]->setDisabled(true);
+ key_usage_check_boxes_[2]->setDisabled(true);
- if (genKeyInfo->isAllowAuthentication())
- keyUsageCheckBoxes[3]->setCheckState(Qt::CheckState::Checked);
+ if (gen_key_info_->isAllowAuthentication())
+ key_usage_check_boxes_[3]->setCheckState(Qt::CheckState::Checked);
else
- keyUsageCheckBoxes[3]->setCheckState(Qt::CheckState::Unchecked);
+ key_usage_check_boxes_[3]->setCheckState(Qt::CheckState::Unchecked);
- if (genKeyInfo->isAllowChangeAuthentication())
- keyUsageCheckBoxes[3]->setDisabled(false);
+ if (gen_key_info_->isAllowChangeAuthentication())
+ key_usage_check_boxes_[3]->setDisabled(false);
else
- keyUsageCheckBoxes[3]->setDisabled(true);
+ key_usage_check_boxes_[3]->setDisabled(true);
- keySizeSpinBox->setRange(genKeyInfo->getSuggestMinKeySize(),
- genKeyInfo->getSuggestMaxKeySize());
- keySizeSpinBox->setValue(genKeyInfo->getKeySize());
- keySizeSpinBox->setSingleStep(genKeyInfo->getSizeChangeStep());
+ keySizeSpinBox->setRange(gen_key_info_->getSuggestMinKeySize(),
+ gen_key_info_->getSuggestMaxKeySize());
+ keySizeSpinBox->setValue(gen_key_info_->getKeySize());
+ keySizeSpinBox->setSingleStep(gen_key_info_->getSizeChangeStep());
}
void SubkeyGenerateDialog::slotKeyGenAccept() {
@@ -228,19 +244,19 @@ void SubkeyGenerateDialog::slotKeyGenAccept() {
auto err_string = err_stream.str();
if (err_string.empty()) {
- genKeyInfo->setKeySize(keySizeSpinBox->value());
+ gen_key_info_->setKeySize(keySizeSpinBox->value());
if (expireCheckBox->checkState()) {
- genKeyInfo->setNonExpired(true);
+ gen_key_info_->setNonExpired(true);
} else {
- genKeyInfo->setExpired(
+ gen_key_info_->setExpired(
boost::posix_time::from_time_t(dateEdit->dateTime().toTime_t()));
}
GpgError error;
auto thread = QThread::create([&]() {
LOG(INFO) << "Thread Started";
- error = GpgKeyOpera::GetInstance().GenerateSubkey(mKey, genKeyInfo);
+ error = GpgKeyOpera::GetInstance().GenerateSubkey(key_, gen_key_info_);
});
thread->start();
@@ -282,39 +298,39 @@ void SubkeyGenerateDialog::slotKeyGenAccept() {
void SubkeyGenerateDialog::slotEncryptionBoxChanged(int state) {
if (state == 0) {
- genKeyInfo->setAllowEncryption(false);
+ gen_key_info_->setAllowEncryption(false);
} else {
- genKeyInfo->setAllowEncryption(true);
+ gen_key_info_->setAllowEncryption(true);
}
}
void SubkeyGenerateDialog::slotSigningBoxChanged(int state) {
if (state == 0) {
- genKeyInfo->setAllowSigning(false);
+ gen_key_info_->setAllowSigning(false);
} else {
- genKeyInfo->setAllowSigning(true);
+ gen_key_info_->setAllowSigning(true);
}
}
void SubkeyGenerateDialog::slotCertificationBoxChanged(int state) {
if (state == 0) {
- genKeyInfo->setAllowCertification(false);
+ gen_key_info_->setAllowCertification(false);
} else {
- genKeyInfo->setAllowCertification(true);
+ gen_key_info_->setAllowCertification(true);
}
}
void SubkeyGenerateDialog::slotAuthenticationBoxChanged(int state) {
if (state == 0) {
- genKeyInfo->setAllowAuthentication(false);
+ gen_key_info_->setAllowAuthentication(false);
} else {
- genKeyInfo->setAllowAuthentication(true);
+ gen_key_info_->setAllowAuthentication(true);
}
}
void SubkeyGenerateDialog::slotActivatedKeyType(int index) {
qDebug() << "key type index changed " << index;
- genKeyInfo->setAlgo(this->keyTypeComboBox->itemText(index).toStdString());
+ gen_key_info_->setAlgo(this->keyTypeComboBox->itemText(index).toStdString());
refresh_widgets_state();
}
diff --git a/src/ui/keygen/SubkeyGenerateDialog.h b/src/ui/keygen/SubkeyGenerateDialog.h
index ec7c9fb1..78f3ac92 100644
--- a/src/ui/keygen/SubkeyGenerateDialog.h
+++ b/src/ui/keygen/SubkeyGenerateDialog.h
@@ -41,9 +41,10 @@ class SubkeyGenerateDialog : public QDialog {
void SubKeyGenerated();
private:
- GpgKey mKey;
+ GpgKey key_;
- std::unique_ptr<GenKeyInfo> genKeyInfo = std::make_unique<GenKeyInfo>(true);
+ std::unique_ptr<GenKeyInfo> gen_key_info_ =
+ std::make_unique<GenKeyInfo>(true);
QGroupBox* keyUsageGroupBox{};
QDialogButtonBox* buttonBox; /** Box for standardbuttons */
@@ -54,12 +55,11 @@ class SubkeyGenerateDialog : public QDialog {
QCheckBox* expireCheckBox{}; /** Checkbox, if key should expire */
// ENCR, SIGN, CERT, AUTH
- std::vector<QCheckBox*> keyUsageCheckBoxes;
+ std::vector<QCheckBox*> key_usage_check_boxes_;
+ QDateTime max_date_time_;
QGroupBox* create_key_usage_group_box();
-
QGroupBox* create_basic_info_group_box();
-
void set_signal_slot();
/**
diff --git a/src/ui/keypair_details/KeyDetailsDialog.cpp b/src/ui/keypair_details/KeyDetailsDialog.cpp
index 3864820f..83be8af0 100644
--- a/src/ui/keypair_details/KeyDetailsDialog.cpp
+++ b/src/ui/keypair_details/KeyDetailsDialog.cpp
@@ -24,6 +24,11 @@
#include "ui/keypair_details/KeyDetailsDialog.h"
+#include "ui/keypair_details/KeyPairDetailTab.h"
+#include "ui/keypair_details/KeyPairOperaTab.h"
+#include "ui/keypair_details/KeyPairSubkeyTab.h"
+#include "ui/keypair_details/KeyPairUIDTab.h"
+
namespace GpgFrontend::UI {
KeyDetailsDialog::KeyDetailsDialog(const GpgKey& key, QWidget* parent)
: QDialog(parent) {
@@ -31,6 +36,7 @@ KeyDetailsDialog::KeyDetailsDialog(const GpgKey& key, QWidget* parent)
tabWidget->addTab(new KeyPairDetailTab(key.id(), tabWidget), _("KeyPair"));
tabWidget->addTab(new KeyPairUIDTab(key.id(), tabWidget), _("UIDs"));
tabWidget->addTab(new KeyPairSubkeyTab(key.id(), tabWidget), _("Subkeys"));
+ tabWidget->addTab(new KeyPairOperaTab(key.id(), tabWidget), _("Operations"));
auto* mainLayout = new QVBoxLayout;
mainLayout->addWidget(tabWidget);
@@ -42,7 +48,7 @@ KeyDetailsDialog::KeyDetailsDialog(const GpgKey& key, QWidget* parent)
this->setLayout(mainLayout);
this->setWindowTitle(_("Key Details"));
this->setModal(true);
- this->setMinimumSize({520, 800});
+ this->setMinimumSize({520, 600});
this->resize(this->minimumSize());
this->show();
}
diff --git a/src/ui/keypair_details/KeyDetailsDialog.h b/src/ui/keypair_details/KeyDetailsDialog.h
index 51fc01cf..72ae3f57 100644
--- a/src/ui/keypair_details/KeyDetailsDialog.h
+++ b/src/ui/keypair_details/KeyDetailsDialog.h
@@ -25,9 +25,6 @@
#ifndef __KEYDETAILSDIALOG_H__
#define __KEYDETAILSDIALOG_H__
-#include "KeyPairDetailTab.h"
-#include "KeyPairSubkeyTab.h"
-#include "KeyPairUIDTab.h"
#include "gpg/GpgContext.h"
#include "ui/GpgFrontendUI.h"
diff --git a/src/ui/keypair_details/KeyPairDetailTab.cpp b/src/ui/keypair_details/KeyPairDetailTab.cpp
index e4b9206a..49593d01 100644
--- a/src/ui/keypair_details/KeyPairDetailTab.cpp
+++ b/src/ui/keypair_details/KeyPairDetailTab.cpp
@@ -25,17 +25,18 @@
#include "ui/keypair_details/KeyPairDetailTab.h"
#include "gpg/function/GpgKeyGetter.h"
-#include "gpg/function/GpgKeyImportExportor.h"
-#include "gpg/function/GpgKeyOpera.h"
+#include "gpg/function/GpgKeyImportExporter.h"
#include "ui/SignalStation.h"
-#include "ui/UserInterfaceUtils.h"
#include "ui/WaitingDialog.h"
namespace GpgFrontend::UI {
KeyPairDetailTab::KeyPairDetailTab(const std::string& key_id, QWidget* parent)
- : QWidget(parent), mKey(GpgKeyGetter::GetInstance().GetKey(key_id)) {
+ : QWidget(parent), key_(GpgKeyGetter::GetInstance().GetKey(key_id)) {
+
+ LOG(INFO) << key_.email() <<key_.is_private_key() << key_.has_master_key() << key_.subKeys()->front().is_private_key();
+
ownerBox = new QGroupBox(_("Owner"));
- keyBox = new QGroupBox(_("Master Key"));
+ keyBox = new QGroupBox(_("Primary Key"));
fingerprintBox = new QGroupBox(_("Fingerprint"));
additionalUidBox = new QGroupBox(_("Additional UIDs"));
@@ -81,7 +82,7 @@ KeyPairDetailTab::KeyPairDetailTab(const std::string& key_id, QWidget* parent)
0);
vboxKD->addWidget(new QLabel(QString(_("Last Update (Local Time)")) + ": "),
7, 0);
- vboxKD->addWidget(new QLabel(QString(_("Master Key Existence")) + ": "), 8,
+ vboxKD->addWidget(new QLabel(QString(_("Primary Key Existence")) + ": "), 8,
0);
keyidVarLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
@@ -133,66 +134,6 @@ KeyPairDetailTab::KeyPairDetailTab(const std::string& key_id, QWidget* parent)
mvbox->addWidget(fingerprintBox);
mvbox->addStretch();
- // Set Menu
- createOperaMenu();
-
- auto* opera_key_box = new QGroupBox(_("Operations"));
- auto* vbox_p_k = new QVBoxLayout();
-
- auto export_h_box_layout = new QHBoxLayout();
- vbox_p_k->addLayout(export_h_box_layout);
-
- auto* export_public_button = new QPushButton(_("Export Public Key"));
- export_h_box_layout->addWidget(export_public_button);
- connect(export_public_button, SIGNAL(clicked()), this,
- SLOT(slotExportPublicKey()));
-
- if (mKey.is_private_key()) {
- auto* export_private_button = new QPushButton(_("Export Private Key"));
- export_private_button->setStyleSheet("text-align:center;");
- export_private_button->setMenu(secretKeyExportOperaMenu);
- export_h_box_layout->addWidget(export_private_button);
-
- if (mKey.has_master_key()) {
- auto* edit_expires_button =
- new QPushButton(_("Modify Expiration Datetime (Master Key)"));
- connect(edit_expires_button, SIGNAL(clicked()), this,
- SLOT(slotModifyEditDatetime()));
- auto* edit_password_button = new QPushButton(_("Modify Password"));
- connect(edit_password_button, SIGNAL(clicked()), this,
- SLOT(slotModifyPassword()));
-
- auto edit_h_box_layout = new QHBoxLayout();
- edit_h_box_layout->addWidget(edit_expires_button);
- edit_h_box_layout->addWidget(edit_password_button);
- vbox_p_k->addLayout(edit_h_box_layout);
- }
- }
-
- auto advance_h_box_layout = new QHBoxLayout();
- auto* key_server_opera_button =
- new QPushButton(_("Key Server Operation (Pubkey)"));
- key_server_opera_button->setStyleSheet("text-align:center;");
- key_server_opera_button->setMenu(keyServerOperaMenu);
- advance_h_box_layout->addWidget(key_server_opera_button);
-
- if (mKey.is_private_key() && mKey.has_master_key()) {
- auto* revoke_cert_gen_button =
- new QPushButton(_("Generate Revoke Certificate"));
- connect(revoke_cert_gen_button, SIGNAL(clicked()), this,
- SLOT(slotGenRevokeCert()));
- advance_h_box_layout->addWidget(revoke_cert_gen_button);
- }
-
- auto* modify_tofu_button = new QPushButton(_("Modify TOFU Policy"));
- connect(modify_tofu_button, SIGNAL(clicked()), this,
- SLOT(slotModifyTOFUPolicy()));
-
- vbox_p_k->addLayout(advance_h_box_layout);
- opera_key_box->setLayout(vbox_p_k);
- mvbox->addWidget(opera_key_box);
- vbox_p_k->addWidget(modify_tofu_button);
-
auto* expBox = new QHBoxLayout();
QPixmap pixmap(":warning.png");
@@ -217,142 +158,28 @@ KeyPairDetailTab::KeyPairDetailTab(const std::string& key_id, QWidget* parent)
setLayout(mvbox);
}
-void KeyPairDetailTab::slotExportPublicKey() {
- ByteArrayPtr keyArray = nullptr;
-
- if (!GpgKeyImportExportor::GetInstance().ExportKey(mKey, keyArray)) {
- QMessageBox::critical(this, _("Error"),
- _("An error occurred during the export operation."));
- return;
- }
- auto file_string =
- mKey.name() + " " + mKey.email() + "(" + mKey.id() + ")_pub.asc";
- auto file_name =
- QFileDialog::getSaveFileName(
- this, _("Export Key To File"), QString::fromStdString(file_string),
- QString(_("Key Files")) + " (*.asc *.txt);;All Files (*)")
- .toStdString();
-
- if (file_name.empty()) return;
-
- if (!write_buffer_to_file(file_name, *keyArray)) {
- QMessageBox::critical(
- this, _("Export Error"),
- QString(_("Couldn't open %1 for writing")).arg(file_name.c_str()));
- return;
- }
-}
-
-void KeyPairDetailTab::slotExportShortPrivateKey() {
- // Show a information box with explanation about private key
- int ret = QMessageBox::information(
- this, _("Exporting short private Key"),
- "<h3>" + QString(_("You are about to export your")) +
- "<font color=\"red\">" + _(" PRIVATE KEY ") + "</font>!</h3>\n" +
- _("This is NOT your Public Key, so DON'T give it away.") + "<br />" +
- _("Do you REALLY want to export your PRIVATE KEY in a Minimum "
- "Size?") +
- "<br />" +
- _("For OpenPGP keys it removes all signatures except for the latest "
- "self-signatures."),
- QMessageBox::Cancel | QMessageBox::Ok);
-
- // export key, if ok was clicked
- if (ret == QMessageBox::Ok) {
- ByteArrayPtr keyArray = nullptr;
-
- if (!GpgKeyImportExportor::GetInstance().ExportSecretKeyShortest(
- mKey, keyArray)) {
- QMessageBox::critical(
- this, _("Error"),
- _("An error occurred during the export operation."));
- return;
- }
- auto file_string = mKey.name() + " " + mKey.email() + "(" + mKey.id() +
- ")_short_secret.asc";
- auto file_name =
- QFileDialog::getSaveFileName(
- this, _("Export Key To File"), QString::fromStdString(file_string),
- QString(_("Key Files")) + " (*.asc *.txt);;All Files (*)")
- .toStdString();
-
- if (file_name.empty()) return;
-
- if (!write_buffer_to_file(file_name, *keyArray)) {
- QMessageBox::critical(
- this, _("Export Error"),
- QString(_("Couldn't open %1 for writing")).arg(file_name.c_str()));
- return;
- }
- }
-}
-
-void KeyPairDetailTab::slotExportPrivateKey() {
- // Show a information box with explanation about private key
- int ret = QMessageBox::information(
- this, _("Exporting private Key"),
- "<h3>" + QString(_("You are about to export your")) +
- "<font color=\"red\">" + _(" PRIVATE KEY ") + "</font>!</h3>\n" +
- _("This is NOT your Public Key, so DON'T give it away.") + "<br />" +
- _("Do you REALLY want to export your PRIVATE KEY?"),
- QMessageBox::Cancel | QMessageBox::Ok);
-
- // export key, if ok was clicked
- if (ret == QMessageBox::Ok) {
- ByteArrayPtr keyArray = nullptr;
-
- if (!GpgKeyImportExportor::GetInstance().ExportSecretKey(mKey, keyArray)) {
- QMessageBox::critical(
- this, _("Error"),
- _("An error occurred during the export operation."));
- return;
- }
- auto file_string = mKey.name() + " " + mKey.email() + "(" + mKey.id() +
- ")_full_secret.asc";
- auto file_name =
- QFileDialog::getSaveFileName(
- this, _("Export Key To File"), QString::fromStdString(file_string),
- QString(_("Key Files")) + " (*.asc *.txt);;All Files (*)")
- .toStdString();
-
- if (file_name.empty()) return;
-
- if (!write_buffer_to_file(file_name, *keyArray)) {
- QMessageBox::critical(
- this, _("Export Error"),
- QString(_("Couldn't open %1 for writing")).arg(file_name.c_str()));
- return;
- }
- }
-}
-
void KeyPairDetailTab::slotCopyFingerprint() {
QString fpr = fingerPrintVarLabel->text().trimmed().replace(" ", QString());
QClipboard* cb = QApplication::clipboard();
cb->setText(fpr);
}
-void KeyPairDetailTab::slotModifyEditDatetime() {
- auto dialog = new KeySetExpireDateDialog(mKey.id(), this);
- dialog->show();
-}
-
void KeyPairDetailTab::slotRefreshKeyInfo() {
- // Show the situation that master key not exists.
- masterKeyExistVarLabel->setText(mKey.has_master_key() ? _("Exists")
+ // Show the situation that primary key not exists.
+ masterKeyExistVarLabel->setText(key_.has_master_key() ? _("Exists")
: _("Not Exists"));
- if (!mKey.has_master_key()) {
- auto paletteExpired = masterKeyExistVarLabel->palette();
- paletteExpired.setColor(masterKeyExistVarLabel->foregroundRole(), Qt::red);
- masterKeyExistVarLabel->setPalette(paletteExpired);
+ if (!key_.has_master_key()) {
+ auto palette_expired = masterKeyExistVarLabel->palette();
+ palette_expired.setColor(masterKeyExistVarLabel->foregroundRole(), Qt::red);
+ masterKeyExistVarLabel->setPalette(palette_expired);
} else {
- auto paletteValid = masterKeyExistVarLabel->palette();
- paletteValid.setColor(masterKeyExistVarLabel->foregroundRole(),
- Qt::darkGreen);
- masterKeyExistVarLabel->setPalette(paletteValid);
+ auto palette_valid = masterKeyExistVarLabel->palette();
+ palette_valid.setColor(masterKeyExistVarLabel->foregroundRole(),
+ Qt::darkGreen);
+ masterKeyExistVarLabel->setPalette(palette_valid);
}
- if (mKey.expired()) {
+ if (key_.expired()) {
auto paletteExpired = expireVarLabel->palette();
paletteExpired.setColor(expireVarLabel->foregroundRole(), Qt::red);
expireVarLabel->setPalette(paletteExpired);
@@ -362,209 +189,77 @@ void KeyPairDetailTab::slotRefreshKeyInfo() {
expireVarLabel->setPalette(paletteValid);
}
- nameVarLabel->setText(QString::fromStdString(mKey.name()));
- emailVarLabel->setText(QString::fromStdString(mKey.email()));
+ nameVarLabel->setText(QString::fromStdString(key_.name()));
+ emailVarLabel->setText(QString::fromStdString(key_.email()));
- commentVarLabel->setText(QString::fromStdString(mKey.comment()));
- keyidVarLabel->setText(QString::fromStdString(mKey.id()));
+ commentVarLabel->setText(QString::fromStdString(key_.comment()));
+ keyidVarLabel->setText(QString::fromStdString(key_.id()));
std::stringstream usage_steam;
- if (mKey.can_certify()) usage_steam << _("Certificate") << " ";
- if (mKey.can_encrypt()) usage_steam << _("Encrypt") << " ";
- if (mKey.can_sign()) usage_steam << _("Sign") << " ";
- if (mKey.can_authenticate()) usage_steam << _("Auth") << " ";
+ if (key_.can_certify()) usage_steam << _("Certificate") << " ";
+ if (key_.can_encrypt()) usage_steam << _("Encrypt") << " ";
+ if (key_.can_sign()) usage_steam << _("Sign") << " ";
+ if (key_.can_authenticate()) usage_steam << _("Auth") << " ";
usageVarLabel->setText(usage_steam.str().c_str());
std::stringstream actual_usage_steam;
- if (mKey.CanCertActual()) actual_usage_steam << _("Certificate") << " ";
- if (mKey.CanEncrActual()) actual_usage_steam << _("Encrypt") << " ";
- if (mKey.CanSignActual()) actual_usage_steam << _("Sign") << " ";
- if (mKey.CanAuthActual()) actual_usage_steam << _("Auth") << " ";
+ if (key_.CanCertActual()) actual_usage_steam << _("Certificate") << " ";
+ if (key_.CanEncrActual()) actual_usage_steam << _("Encrypt") << " ";
+ if (key_.CanSignActual()) actual_usage_steam << _("Sign") << " ";
+ if (key_.CanAuthActual()) actual_usage_steam << _("Auth") << " ";
actualUsageVarLabel->setText(actual_usage_steam.str().c_str());
std::string key_size_val, key_expire_val, key_create_time_val, key_algo_val,
key_last_update_val;
- key_size_val = std::to_string(mKey.length());
+ key_size_val = std::to_string(key_.length());
- if (to_time_t(boost::posix_time::ptime(mKey.expires())) == 0) {
+ if (to_time_t(boost::posix_time::ptime(key_.expires())) == 0) {
expireVarLabel->setText(_("Never Expire"));
} else {
expireVarLabel->setText(QLocale::system().toString(
- QDateTime::fromTime_t(to_time_t(mKey.expires()))));
+ QDateTime::fromTime_t(to_time_t(key_.expires()))));
}
- key_algo_val = mKey.pubkey_algo();
+ key_algo_val = key_.pubkey_algo();
createdVarLabel->setText(QLocale::system().toString(
- QDateTime::fromTime_t(to_time_t(mKey.create_time()))));
+ QDateTime::fromTime_t(to_time_t(key_.create_time()))));
- if (to_time_t(boost::posix_time::ptime(mKey.last_update())) == 0) {
+ if (to_time_t(boost::posix_time::ptime(key_.last_update())) == 0) {
lastUpdateVarLabel->setText(_("No Data"));
} else {
lastUpdateVarLabel->setText(QLocale::system().toString(
- QDateTime::fromTime_t(to_time_t(mKey.last_update()))));
+ QDateTime::fromTime_t(to_time_t(key_.last_update()))));
}
keySizeVarLabel->setText(key_size_val.c_str());
algorithmVarLabel->setText(key_algo_val.c_str());
- fingerPrintVarLabel->setText(beautify_fingerprint(mKey.fpr()).c_str());
+ fingerPrintVarLabel->setText(beautify_fingerprint(key_.fpr()).c_str());
iconLabel->hide();
expLabel->hide();
- if (mKey.expired()) {
+ if (key_.expired()) {
iconLabel->show();
expLabel->show();
- expLabel->setText(_("Warning: The Master Key has expired."));
+ expLabel->setText(_("Warning: The primary key has expired."));
}
- if (mKey.revoked()) {
+ if (key_.revoked()) {
iconLabel->show();
expLabel->show();
- expLabel->setText(_("Warning: The Master Key has been revoked."));
+ expLabel->setText(_("Warning: The primary key has been revoked."));
}
}
-void KeyPairDetailTab::createOperaMenu() {
- keyServerOperaMenu = new QMenu(this);
-
- auto* uploadKeyPair = new QAction(_("Upload Key Pair to Key Server"), this);
- connect(uploadKeyPair, SIGNAL(triggered()), this,
- SLOT(slotUploadKeyToServer()));
- if (!(mKey.is_private_key() && mKey.has_master_key()))
- uploadKeyPair->setDisabled(true);
-
- auto* updateKeyPair = new QAction(_("Sync Key Pair From Key Server"), this);
- connect(updateKeyPair, SIGNAL(triggered()), this,
- SLOT(slotUpdateKeyFromServer()));
-
- // when a key has master key, it should always upload to keyserver.
- if (mKey.has_master_key()) {
- updateKeyPair->setDisabled(true);
- }
-
- keyServerOperaMenu->addAction(uploadKeyPair);
- keyServerOperaMenu->addAction(updateKeyPair);
-
- secretKeyExportOperaMenu = new QMenu(this);
-
- auto* exportFullSecretKey = new QAction(_("Export Full Secret Key"), this);
- connect(exportFullSecretKey, SIGNAL(triggered()), this,
- SLOT(slotExportPrivateKey()));
- if (!mKey.is_private_key()) exportFullSecretKey->setDisabled(true);
-
- auto* exportShortestSecretKey =
- new QAction(_("Export Shortest Secret Key"), this);
- connect(exportShortestSecretKey, SIGNAL(triggered()), this,
- SLOT(slotExportShortPrivateKey()));
-
- secretKeyExportOperaMenu->addAction(exportFullSecretKey);
- secretKeyExportOperaMenu->addAction(exportShortestSecretKey);
-}
-
-void KeyPairDetailTab::slotUploadKeyToServer() {
- auto keys = std::make_unique<KeyIdArgsList>();
- keys->push_back(mKey.id());
- auto* dialog = new KeyUploadDialog(keys, this);
- dialog->show();
- dialog->slotUpload();
-}
-
-void KeyPairDetailTab::slotUpdateKeyFromServer() {
- auto keys = std::make_unique<KeyIdArgsList>();
- keys->push_back(mKey.id());
- auto* dialog = new KeyServerImportDialog(this);
- dialog->show();
- dialog->slotImport(keys);
-}
-
-void KeyPairDetailTab::slotGenRevokeCert() {
- auto literal = QString("%1 (*.rev)").arg(_("Revocation Certificates"));
- QString m_output_file_name;
-
- QFileDialog dialog(this, "Generate revocation certificate", QString(),
- literal);
- dialog.setDefaultSuffix(".rev");
- dialog.setAcceptMode(QFileDialog::AcceptSave);
-
- if (dialog.exec()) m_output_file_name = dialog.selectedFiles().front();
-
- if (!m_output_file_name.isEmpty())
- CommonUtils::GetInstance()->slotExecuteGpgCommand(
- {"--command-fd", "0", "--status-fd", "1", "--no-tty", "-o",
- m_output_file_name, "--gen-revoke", mKey.fpr().c_str()},
- [](QProcess* proc) -> void {
- // Code From Gpg4Win
- while (proc->canReadLine()) {
- const QString line = QString::fromUtf8(proc->readLine()).trimmed();
- LOG(INFO) << "line" << line.toStdString();
- if (line == QLatin1String("[GNUPG:] GET_BOOL gen_revoke.okay")) {
- proc->write("y\n");
- } else if (line == QLatin1String("[GNUPG:] GET_LINE "
- "ask_revocation_reason.code")) {
- proc->write("0\n");
- } else if (line == QLatin1String("[GNUPG:] GET_LINE "
- "ask_revocation_reason.text")) {
- proc->write("\n");
- } else if (line ==
- QLatin1String(
- "[GNUPG:] GET_BOOL openfile.overwrite.okay")) {
- // We asked before
- proc->write("y\n");
- } else if (line == QLatin1String("[GNUPG:] GET_BOOL "
- "ask_revocation_reason.okay")) {
- proc->write("y\n");
- }
- }
- });
-}
void KeyPairDetailTab::slotRefreshKey() {
LOG(INFO) << _("Called");
- this->mKey = GpgKeyGetter::GetInstance().GetKey(mKey.id());
+ this->key_ = GpgKeyGetter::GetInstance().GetKey(key_.id());
this->slotRefreshKeyInfo();
}
-void KeyPairDetailTab::slotModifyPassword() {
- auto err = GpgKeyOpera::GetInstance().ModifyPassword(mKey);
- if (check_gpg_error_2_err_code(err) != GPG_ERR_NO_ERROR) {
- QMessageBox::critical(this, _("Not Successful"),
- QString(_("Modify password not successfully.")));
- }
-}
-
-void KeyPairDetailTab::slotModifyTOFUPolicy() {
- QStringList items;
- items << _("Policy Auto") << _("Policy Good") << _("Policy Bad")
- << _("Policy Ask") << _("Policy Unknown");
-
- bool ok;
- QString item = QInputDialog::getItem(
- 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();
- gpgme_tofu_policy_t tofu_policy = GPGME_TOFU_POLICY_AUTO;
- if (item == _("Policy Auto")) {
- tofu_policy = GPGME_TOFU_POLICY_AUTO;
- } else if (item == _("Policy Good")) {
- tofu_policy = GPGME_TOFU_POLICY_GOOD;
- } else if (item == _("Policy Bad")) {
- tofu_policy = GPGME_TOFU_POLICY_BAD;
- } else if (item == _("Policy Ask")) {
- tofu_policy = GPGME_TOFU_POLICY_ASK;
- } else if (item == _("Policy Unknown")) {
- tofu_policy = GPGME_TOFU_POLICY_UNKNOWN;
- }
- auto err = GpgKeyOpera::GetInstance().ModifyTOFUPolicy(mKey, tofu_policy);
- if (check_gpg_error_2_err_code(err) != GPG_ERR_NO_ERROR) {
- QMessageBox::critical(this, _("Not Successful"),
- QString(_("Modify TOFU policy not successfully.")));
- }
- }
-}
-
} // namespace GpgFrontend::UI
diff --git a/src/ui/keypair_details/KeyPairDetailTab.h b/src/ui/keypair_details/KeyPairDetailTab.h
index 3e2f2298..151d8fc7 100644
--- a/src/ui/keypair_details/KeyPairDetailTab.h
+++ b/src/ui/keypair_details/KeyPairDetailTab.h
@@ -36,42 +36,19 @@ namespace GpgFrontend::UI {
class KeyPairDetailTab : public QWidget {
Q_OBJECT
- void createOperaMenu();
-
private slots:
/**
- * @details Export the key to a file, which is chosen in a file dialog
- */
- void slotExportPrivateKey();
-
- void slotExportShortPrivateKey();
-
- void slotExportPublicKey();
-
- /**
* @details Copy the fingerprint to clipboard
*/
void slotCopyFingerprint();
- void slotModifyEditDatetime();
-
- void slotModifyPassword();
-
void slotRefreshKeyInfo();
- void slotUploadKeyToServer();
-
- void slotUpdateKeyFromServer();
-
- void slotGenRevokeCert();
-
void slotRefreshKey();
- void slotModifyTOFUPolicy();
-
private:
- GpgKey mKey;
+ GpgKey key_;
QGroupBox* ownerBox; /** Groupbox containing owner information */
QGroupBox* keyBox; /** Groupbox containing key information */
diff --git a/src/ui/keypair_details/KeyPairOperaTab.cpp b/src/ui/keypair_details/KeyPairOperaTab.cpp
new file mode 100644
index 00000000..57eb8164
--- /dev/null
+++ b/src/ui/keypair_details/KeyPairOperaTab.cpp
@@ -0,0 +1,349 @@
+/**
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "KeyPairOperaTab.h"
+
+#include "gpg/function/GpgKeyImportExporter.h"
+#include "gpg/function/GpgKeyOpera.h"
+#include "ui/KeyUploadDialog.h"
+#include "ui/SignalStation.h"
+#include "ui/UserInterfaceUtils.h"
+#include "ui/keypair_details/KeySetExpireDateDialog.h"
+
+namespace GpgFrontend::UI {
+
+KeyPairOperaTab::KeyPairOperaTab(const std::string& key_id, QWidget* parent)
+ : QWidget(parent), m_key_(GpgKeyGetter::GetInstance().GetKey(key_id)) {
+ // Set Menu
+ createOperaMenu();
+ auto m_vbox = new QVBoxLayout(this);
+
+ auto* opera_key_box = new QGroupBox(_("General Operations"));
+ auto* vbox_p_k = new QVBoxLayout();
+
+ auto export_h_box_layout = new QHBoxLayout();
+ vbox_p_k->addLayout(export_h_box_layout);
+
+ auto* export_public_button = new QPushButton(_("Export Public Key"));
+ export_h_box_layout->addWidget(export_public_button);
+ connect(export_public_button, SIGNAL(clicked()), this,
+ SLOT(slotExportPublicKey()));
+
+ if (m_key_.is_private_key()) {
+ auto* export_private_button = new QPushButton(_("Export Private Key"));
+ export_private_button->setStyleSheet("text-align:center;");
+ export_private_button->setMenu(secretKeyExportOperaMenu);
+ export_h_box_layout->addWidget(export_private_button);
+
+ if (m_key_.has_master_key()) {
+ auto* edit_expires_button =
+ new QPushButton(_("Modify Expiration Datetime (Primary Key)"));
+ connect(edit_expires_button, SIGNAL(clicked()), this,
+ SLOT(slotModifyEditDatetime()));
+ auto* edit_password_button = new QPushButton(_("Modify Password"));
+ connect(edit_password_button, SIGNAL(clicked()), this,
+ SLOT(slotModifyPassword()));
+
+ vbox_p_k->addWidget(edit_expires_button);
+ vbox_p_k->addWidget(edit_password_button);
+ }
+ }
+
+ auto advance_h_box_layout = new QHBoxLayout();
+ auto* key_server_opera_button =
+ new QPushButton(_("Key Server Operation (Pubkey)"));
+ key_server_opera_button->setStyleSheet("text-align:center;");
+ key_server_opera_button->setMenu(keyServerOperaMenu);
+ advance_h_box_layout->addWidget(key_server_opera_button);
+
+ if (m_key_.is_private_key() && m_key_.has_master_key()) {
+ auto* revoke_cert_gen_button =
+ new QPushButton(_("Generate Revoke Certificate"));
+ connect(revoke_cert_gen_button, SIGNAL(clicked()), this,
+ SLOT(slotGenRevokeCert()));
+ advance_h_box_layout->addWidget(revoke_cert_gen_button);
+ }
+
+ auto* modify_tofu_button = new QPushButton(_("Modify TOFU Policy"));
+ connect(modify_tofu_button, SIGNAL(clicked()), this,
+ SLOT(slotModifyTOFUPolicy()));
+
+ vbox_p_k->addLayout(advance_h_box_layout);
+ opera_key_box->setLayout(vbox_p_k);
+ m_vbox->addWidget(opera_key_box);
+ vbox_p_k->addWidget(modify_tofu_button);
+ m_vbox->addStretch(0);
+
+ setLayout(m_vbox);
+}
+
+void KeyPairOperaTab::createOperaMenu() {
+ keyServerOperaMenu = new QMenu(this);
+
+ auto* uploadKeyPair = new QAction(_("Upload Key Pair to Key Server"), this);
+ connect(uploadKeyPair, SIGNAL(triggered()), this,
+ SLOT(slotUploadKeyToServer()));
+ if (!(m_key_.is_private_key() && m_key_.has_master_key()))
+ uploadKeyPair->setDisabled(true);
+
+ auto* updateKeyPair = new QAction(_("Sync Key Pair From Key Server"), this);
+ connect(updateKeyPair, SIGNAL(triggered()), this,
+ SLOT(slotUpdateKeyFromServer()));
+
+ // when a key has primary key, it should always upload to keyserver.
+ if (m_key_.has_master_key()) {
+ updateKeyPair->setDisabled(true);
+ }
+
+ keyServerOperaMenu->addAction(uploadKeyPair);
+ keyServerOperaMenu->addAction(updateKeyPair);
+
+ secretKeyExportOperaMenu = new QMenu(this);
+
+ auto* exportFullSecretKey = new QAction(_("Export Full Secret Key"), this);
+ connect(exportFullSecretKey, SIGNAL(triggered()), this,
+ SLOT(slotExportPrivateKey()));
+ if (!m_key_.is_private_key()) exportFullSecretKey->setDisabled(true);
+
+ auto* exportShortestSecretKey =
+ new QAction(_("Export Shortest Secret Key"), this);
+ connect(exportShortestSecretKey, SIGNAL(triggered()), this,
+ SLOT(slotExportShortPrivateKey()));
+
+ secretKeyExportOperaMenu->addAction(exportFullSecretKey);
+ secretKeyExportOperaMenu->addAction(exportShortestSecretKey);
+}
+
+void KeyPairOperaTab::slotExportPublicKey() {
+ ByteArrayPtr keyArray = nullptr;
+
+ if (!GpgKeyImportExporter::GetInstance().ExportKey(m_key_, keyArray)) {
+ QMessageBox::critical(this, _("Error"),
+ _("An error occurred during the export operation."));
+ return;
+ }
+ auto file_string =
+ m_key_.name() + " " + m_key_.email() + "(" + m_key_.id() + ")_pub.asc";
+ auto file_name =
+ QFileDialog::getSaveFileName(
+ this, _("Export Key To File"), QString::fromStdString(file_string),
+ QString(_("Key Files")) + " (*.asc *.txt);;All Files (*)")
+ .toStdString();
+
+ if (file_name.empty()) return;
+
+ if (!write_buffer_to_file(file_name, *keyArray)) {
+ QMessageBox::critical(
+ this, _("Export Error"),
+ QString(_("Couldn't open %1 for writing")).arg(file_name.c_str()));
+ return;
+ }
+}
+
+void KeyPairOperaTab::slotExportShortPrivateKey() {
+ // Show a information box with explanation about private key
+ int ret = QMessageBox::information(
+ this, _("Exporting short private Key"),
+ "<h3>" + QString(_("You are about to export your")) +
+ "<font color=\"red\">" + _(" PRIVATE KEY ") + "</font>!</h3>\n" +
+ _("This is NOT your Public Key, so DON'T give it away.") + "<br />" +
+ _("Do you REALLY want to export your PRIVATE KEY in a Minimum "
+ "Size?") +
+ "<br />" +
+ _("For OpenPGP keys it removes all signatures except for the latest "
+ "self-signatures."),
+ QMessageBox::Cancel | QMessageBox::Ok);
+
+ // export key, if ok was clicked
+ if (ret == QMessageBox::Ok) {
+ ByteArrayPtr keyArray = nullptr;
+
+ if (!GpgKeyImportExporter::GetInstance().ExportSecretKeyShortest(
+ m_key_, keyArray)) {
+ QMessageBox::critical(
+ this, _("Error"),
+ _("An error occurred during the export operation."));
+ return;
+ }
+ auto file_string = m_key_.name() + " " + m_key_.email() + "(" +
+ m_key_.id() + ")_short_secret.asc";
+ auto file_name =
+ QFileDialog::getSaveFileName(
+ this, _("Export Key To File"), QString::fromStdString(file_string),
+ QString(_("Key Files")) + " (*.asc *.txt);;All Files (*)")
+ .toStdString();
+
+ if (file_name.empty()) return;
+
+ if (!write_buffer_to_file(file_name, *keyArray)) {
+ QMessageBox::critical(
+ this, _("Export Error"),
+ QString(_("Couldn't open %1 for writing")).arg(file_name.c_str()));
+ return;
+ }
+ }
+}
+
+void KeyPairOperaTab::slotExportPrivateKey() {
+ // Show a information box with explanation about private key
+ int ret = QMessageBox::information(
+ this, _("Exporting private Key"),
+ "<h3>" + QString(_("You are about to export your")) +
+ "<font color=\"red\">" + _(" PRIVATE KEY ") + "</font>!</h3>\n" +
+ _("This is NOT your Public Key, so DON'T give it away.") + "<br />" +
+ _("Do you REALLY want to export your PRIVATE KEY?"),
+ QMessageBox::Cancel | QMessageBox::Ok);
+
+ // export key, if ok was clicked
+ if (ret == QMessageBox::Ok) {
+ ByteArrayPtr keyArray = nullptr;
+
+ if (!GpgKeyImportExporter::GetInstance().ExportSecretKey(m_key_,
+ keyArray)) {
+ QMessageBox::critical(
+ this, _("Error"),
+ _("An error occurred during the export operation."));
+ return;
+ }
+ auto file_string = m_key_.name() + " " + m_key_.email() + "(" +
+ m_key_.id() + ")_full_secret.asc";
+ auto file_name =
+ QFileDialog::getSaveFileName(
+ this, _("Export Key To File"), QString::fromStdString(file_string),
+ QString(_("Key Files")) + " (*.asc *.txt);;All Files (*)")
+ .toStdString();
+
+ if (file_name.empty()) return;
+
+ if (!write_buffer_to_file(file_name, *keyArray)) {
+ QMessageBox::critical(
+ this, _("Export Error"),
+ QString(_("Couldn't open %1 for writing")).arg(file_name.c_str()));
+ return;
+ }
+ }
+}
+
+void KeyPairOperaTab::slotModifyEditDatetime() {
+ auto dialog = new KeySetExpireDateDialog(m_key_.id(), this);
+ dialog->show();
+}
+
+void KeyPairOperaTab::slotUploadKeyToServer() {
+ auto keys = std::make_unique<KeyIdArgsList>();
+ keys->push_back(m_key_.id());
+ auto* dialog = new KeyUploadDialog(keys, this);
+ dialog->show();
+ dialog->slotUpload();
+}
+
+void KeyPairOperaTab::slotUpdateKeyFromServer() {
+ auto keys = std::make_unique<KeyIdArgsList>();
+ keys->push_back(m_key_.id());
+ auto* dialog = new KeyServerImportDialog(this);
+ dialog->show();
+ dialog->slotImport(keys);
+}
+
+void KeyPairOperaTab::slotGenRevokeCert() {
+ auto literal = QString("%1 (*.rev)").arg(_("Revocation Certificates"));
+ QString m_output_file_name;
+
+ QFileDialog dialog(this, "Generate revocation certificate", QString(),
+ literal);
+ dialog.setDefaultSuffix(".rev");
+ dialog.setAcceptMode(QFileDialog::AcceptSave);
+
+ if (dialog.exec()) m_output_file_name = dialog.selectedFiles().front();
+
+ if (!m_output_file_name.isEmpty())
+ CommonUtils::GetInstance()->slotExecuteGpgCommand(
+ {"--command-fd", "0", "--status-fd", "1", "--no-tty", "-o",
+ m_output_file_name, "--gen-revoke", m_key_.fpr().c_str()},
+ [](QProcess* proc) -> void {
+ // Code From Gpg4Win
+ while (proc->canReadLine()) {
+ const QString line = QString::fromUtf8(proc->readLine()).trimmed();
+ LOG(INFO) << "line" << line.toStdString();
+ if (line == QLatin1String("[GNUPG:] GET_BOOL gen_revoke.okay")) {
+ proc->write("y\n");
+ } else if (line == QLatin1String("[GNUPG:] GET_LINE "
+ "ask_revocation_reason.code")) {
+ proc->write("0\n");
+ } else if (line == QLatin1String("[GNUPG:] GET_LINE "
+ "ask_revocation_reason.text")) {
+ proc->write("\n");
+ } else if (line ==
+ QLatin1String(
+ "[GNUPG:] GET_BOOL openfile.overwrite.okay")) {
+ // We asked before
+ proc->write("y\n");
+ } else if (line == QLatin1String("[GNUPG:] GET_BOOL "
+ "ask_revocation_reason.okay")) {
+ proc->write("y\n");
+ }
+ }
+ });
+}
+
+void KeyPairOperaTab::slotModifyPassword() {
+ auto err = GpgKeyOpera::GetInstance().ModifyPassword(m_key_);
+ if (check_gpg_error_2_err_code(err) != GPG_ERR_NO_ERROR) {
+ QMessageBox::critical(this, _("Not Successful"),
+ QString(_("Modify password not successfully.")));
+ }
+}
+
+void KeyPairOperaTab::slotModifyTOFUPolicy() {
+ QStringList items;
+ items << _("Policy Auto") << _("Policy Good") << _("Policy Bad")
+ << _("Policy Ask") << _("Policy Unknown");
+
+ bool ok;
+ QString item = QInputDialog::getItem(
+ 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();
+ gpgme_tofu_policy_t tofu_policy = GPGME_TOFU_POLICY_AUTO;
+ if (item == _("Policy Auto")) {
+ tofu_policy = GPGME_TOFU_POLICY_AUTO;
+ } else if (item == _("Policy Good")) {
+ tofu_policy = GPGME_TOFU_POLICY_GOOD;
+ } else if (item == _("Policy Bad")) {
+ tofu_policy = GPGME_TOFU_POLICY_BAD;
+ } else if (item == _("Policy Ask")) {
+ tofu_policy = GPGME_TOFU_POLICY_ASK;
+ } else if (item == _("Policy Unknown")) {
+ tofu_policy = GPGME_TOFU_POLICY_UNKNOWN;
+ }
+ auto err = GpgKeyOpera::GetInstance().ModifyTOFUPolicy(m_key_, tofu_policy);
+ if (check_gpg_error_2_err_code(err) != GPG_ERR_NO_ERROR) {
+ QMessageBox::critical(this, _("Not Successful"),
+ QString(_("Modify TOFU policy not successfully.")));
+ }
+ }
+}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/keypair_details/KeyPairOperaTab.h b/src/ui/keypair_details/KeyPairOperaTab.h
new file mode 100644
index 00000000..f8a5ded9
--- /dev/null
+++ b/src/ui/keypair_details/KeyPairOperaTab.h
@@ -0,0 +1,69 @@
+/**
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef GPGFRONTEND_KEYPAIROPERATAB_H
+#define GPGFRONTEND_KEYPAIROPERATAB_H
+
+#include "gpg/function/GpgKeyGetter.h"
+#include "ui/GpgFrontendUI.h"
+
+namespace GpgFrontend::UI {
+class KeyPairOperaTab : public QWidget {
+ Q_OBJECT
+ public:
+ KeyPairOperaTab(const std::string& key_id, QWidget* parent);
+
+ void createOperaMenu();
+
+ private slots:
+
+ /**
+ * @details Export the key to a file, which is chosen in a file dialog
+ */
+ void slotExportPrivateKey();
+
+ void slotExportShortPrivateKey();
+
+ void slotExportPublicKey();
+
+ void slotModifyEditDatetime();
+
+ void slotModifyPassword();
+
+ void slotUploadKeyToServer();
+
+ void slotUpdateKeyFromServer();
+
+ void slotGenRevokeCert();
+
+ void slotModifyTOFUPolicy();
+
+ private:
+ GpgKey m_key_;
+ QMenu* keyServerOperaMenu{};
+ QMenu* secretKeyExportOperaMenu{};
+};
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_KEYPAIROPERATAB_H
diff --git a/src/ui/keypair_details/KeyPairSubkeyTab.cpp b/src/ui/keypair_details/KeyPairSubkeyTab.cpp
index 8068d9a8..a80eb5e4 100644
--- a/src/ui/keypair_details/KeyPairSubkeyTab.cpp
+++ b/src/ui/keypair_details/KeyPairSubkeyTab.cpp
@@ -30,7 +30,10 @@
namespace GpgFrontend::UI {
KeyPairSubkeyTab::KeyPairSubkeyTab(const std::string& key_id, QWidget* parent)
- : QWidget(parent), mKey(GpgKeyGetter::GetInstance().GetKey(key_id)) {
+ : QWidget(parent), key_(GpgKeyGetter::GetInstance().GetKey(key_id)) {
+
+ LOG(INFO) << key_.email() <<key_.is_private_key() << key_.has_master_key() << key_.subKeys()->front().is_private_key();
+
createSubkeyList();
createSubkeyOperaMenu();
@@ -40,7 +43,7 @@ KeyPairSubkeyTab::KeyPairSubkeyTab(const std::string& key_id, QWidget* parent)
auto uidButtonsLayout = new QGridLayout();
auto addSubkeyButton = new QPushButton(_("Generate A New Subkey"));
- if (!mKey.is_private_key() || !mKey.has_master_key()) {
+ if (!key_.is_private_key() || !key_.has_master_key()) {
addSubkeyButton->setDisabled(true);
setHidden(addSubkeyButton);
}
@@ -68,17 +71,20 @@ KeyPairSubkeyTab::KeyPairSubkeyTab(const std::string& key_id, QWidget* parent)
new QLabel(QString(_("Create Date (Local Time)")) + ": "), 5, 0);
subkeyDetailLayout->addWidget(new QLabel(QString(_("Existence")) + ": "), 6,
0);
- subkeyDetailLayout->addWidget(new QLabel(QString(_("Fingerprint")) + ": "), 7,
+ subkeyDetailLayout->addWidget(
+ new QLabel(QString(_("Key in Smart Card")) + ": "), 7, 0);
+ subkeyDetailLayout->addWidget(new QLabel(QString(_("Fingerprint")) + ": "), 8,
0);
- keyidVarLabel = new QLabel();
- keySizeVarLabel = new QLabel();
- expireVarLabel = new QLabel();
- algorithmVarLabel = new QLabel();
- createdVarLabel = new QLabel();
- usageVarLabel = new QLabel();
- masterKeyExistVarLabel = new QLabel();
- fingerPrintVarLabel = new QLabel();
+ keyidVarLabel = new QLabel(this);
+ keySizeVarLabel = new QLabel(this);
+ expireVarLabel = new QLabel(this);
+ algorithmVarLabel = new QLabel(this);
+ createdVarLabel = new QLabel(this);
+ usageVarLabel = new QLabel(this);
+ masterKeyExistVarLabel = new QLabel(this);
+ fingerPrintVarLabel = new QLabel(this);
+ cardKeyLabel = new QLabel(this);
subkeyDetailLayout->addWidget(keyidVarLabel, 0, 1, 1, 1);
subkeyDetailLayout->addWidget(keySizeVarLabel, 2, 1, 1, 2);
@@ -87,7 +93,8 @@ KeyPairSubkeyTab::KeyPairSubkeyTab(const std::string& key_id, QWidget* parent)
subkeyDetailLayout->addWidget(createdVarLabel, 5, 1, 1, 2);
subkeyDetailLayout->addWidget(usageVarLabel, 3, 1, 1, 2);
subkeyDetailLayout->addWidget(masterKeyExistVarLabel, 6, 1, 1, 2);
- subkeyDetailLayout->addWidget(fingerPrintVarLabel, 7, 1, 1, 2);
+ subkeyDetailLayout->addWidget(cardKeyLabel, 7, 1, 1, 2);
+ subkeyDetailLayout->addWidget(fingerPrintVarLabel, 8, 1, 1, 2);
auto* copyKeyIdButton = new QPushButton(_("Copy"));
copyKeyIdButton->setFlat(true);
@@ -157,7 +164,7 @@ void KeyPairSubkeyTab::slotRefreshSubkeyList() {
subkeyList->setSelectionMode(QAbstractItemView::SingleSelection);
this->buffered_subkeys.clear();
- auto sub_keys = mKey.subKeys();
+ auto sub_keys = key_.subKeys();
for (auto& sub_key : *sub_keys) {
if (sub_key.disabled() || sub_key.revoked()) continue;
this->buffered_subkeys.push_back(std::move(sub_key));
@@ -207,7 +214,7 @@ void KeyPairSubkeyTab::slotRefreshSubkeyList() {
}
void KeyPairSubkeyTab::slotAddSubkey() {
- auto dialog = new SubkeyGenerateDialog(mKey.id(), this);
+ auto dialog = new SubkeyGenerateDialog(key_.id(), this);
dialog->show();
}
@@ -248,18 +255,32 @@ void KeyPairSubkeyTab::slotRefreshSubkeyDetail() {
usageVarLabel->setText(usage_steam.str().c_str());
- // Show the situation that master key not exists.
+ // Show the situation that secret key not exists.
masterKeyExistVarLabel->setText(subkey.secret() ? _("Exists")
: _("Not Exists"));
+
+ // Show the situation if key in a smart card.
+ cardKeyLabel->setText(subkey.is_cardkey() ? _("Yes") : _("No"));
+
if (!subkey.secret()) {
- auto paletteExpired = masterKeyExistVarLabel->palette();
- paletteExpired.setColor(masterKeyExistVarLabel->foregroundRole(), Qt::red);
- masterKeyExistVarLabel->setPalette(paletteExpired);
+ auto palette_expired = masterKeyExistVarLabel->palette();
+ palette_expired.setColor(masterKeyExistVarLabel->foregroundRole(), Qt::red);
+ masterKeyExistVarLabel->setPalette(palette_expired);
+ } else {
+ auto palette_valid = masterKeyExistVarLabel->palette();
+ palette_valid.setColor(masterKeyExistVarLabel->foregroundRole(),
+ Qt::darkGreen);
+ masterKeyExistVarLabel->setPalette(palette_valid);
+ }
+
+ if (!subkey.is_cardkey()) {
+ auto palette_expired = cardKeyLabel->palette();
+ palette_expired.setColor(cardKeyLabel->foregroundRole(), Qt::red);
+ cardKeyLabel->setPalette(palette_expired);
} else {
- auto paletteValid = masterKeyExistVarLabel->palette();
- paletteValid.setColor(masterKeyExistVarLabel->foregroundRole(),
- Qt::darkGreen);
- masterKeyExistVarLabel->setPalette(paletteValid);
+ auto palette_valid = cardKeyLabel->palette();
+ palette_valid.setColor(cardKeyLabel->foregroundRole(), Qt::darkGreen);
+ cardKeyLabel->setPalette(palette_valid);
}
fingerPrintVarLabel->setText(QString::fromStdString(subkey.fpr()));
@@ -279,7 +300,7 @@ void KeyPairSubkeyTab::slotEditSubkey() {
LOG(INFO) << "Fpr" << getSelectedSubkey().fpr();
auto dialog =
- new KeySetExpireDateDialog(mKey.id(), getSelectedSubkey().fpr(), this);
+ new KeySetExpireDateDialog(key_.id(), getSelectedSubkey().fpr(), this);
dialog->show();
}
@@ -302,7 +323,7 @@ const GpgSubKey& KeyPairSubkeyTab::getSelectedSubkey() {
return buffered_subkeys[row];
}
void KeyPairSubkeyTab::slotRefreshKeyInfo() {
- mKey = GpgKeyGetter::GetInstance().GetKey(mKey.id());
+ key_ = GpgKeyGetter::GetInstance().GetKey(key_.id());
}
} // namespace GpgFrontend::UI
diff --git a/src/ui/keypair_details/KeyPairSubkeyTab.h b/src/ui/keypair_details/KeyPairSubkeyTab.h
index 8922e723..f254fed0 100644
--- a/src/ui/keypair_details/KeyPairSubkeyTab.h
+++ b/src/ui/keypair_details/KeyPairSubkeyTab.h
@@ -45,7 +45,7 @@ class KeyPairSubkeyTab : public QWidget {
const GpgSubKey& getSelectedSubkey();
- GpgKey mKey;
+ GpgKey key_;
QTableWidget* subkeyList{};
std::vector<GpgSubKey> buffered_subkeys;
@@ -62,6 +62,7 @@ class KeyPairSubkeyTab : public QWidget {
QLabel* fingerPrintVarLabel; /** Label containing the keys fingerprint */
QLabel* usageVarLabel;
QLabel* masterKeyExistVarLabel;
+ QLabel* cardKeyLabel;
private slots:
diff --git a/src/ui/keypair_details/KeyUIDSignDialog.cpp b/src/ui/keypair_details/KeyUIDSignDialog.cpp
index eb459701..b43a119e 100644
--- a/src/ui/keypair_details/KeyUIDSignDialog.cpp
+++ b/src/ui/keypair_details/KeyUIDSignDialog.cpp
@@ -34,7 +34,7 @@ KeyUIDSignDialog::KeyUIDSignDialog(const GpgKey& key, UIDArgsListPtr uid,
QWidget* parent)
: QDialog(parent), mUids(std::move(uid)), mKey(key) {
const auto key_id = mKey.id();
- mKeyList = new KeyList(false, this);
+ mKeyList = new KeyList(KeyMenuAbility::NONE, this);
mKeyList->addListGroupTab(_("Signers"), KeyListRow::ONLY_SECRET_KEY,
KeyListColumn::NAME | KeyListColumn::EmailAddress,
[key_id](const GpgKey& key) -> bool {
diff --git a/src/ui/main_window/MainWindowFileSlotFunction.cpp b/src/ui/main_window/MainWindowFileSlotFunction.cpp
index 2a2c9be9..286cef3a 100644
--- a/src/ui/main_window/MainWindowFileSlotFunction.cpp
+++ b/src/ui/main_window/MainWindowFileSlotFunction.cpp
@@ -26,6 +26,7 @@
#include "gpg/function/GpgFileOpera.h"
#include "gpg/function/GpgKeyGetter.h"
#include "ui/UserInterfaceUtils.h"
+#include "ui/settings/GlobalSettingStation.h"
#include "ui/widgets/SignersPicker.h"
namespace GpgFrontend::UI {
@@ -57,46 +58,87 @@ void MainWindow::slotFileEncrypt() {
if (!file_pre_check(this, path)) return;
- if (QFile::exists(path + ".asc")) {
- auto ret = QMessageBox::warning(
- this, _("Warning"),
- _("The target file already exists, do you need to overwrite it?"),
- QMessageBox::Ok | QMessageBox::Cancel);
+ // check selected keys
+ auto key_ids = mKeyList->getChecked();
+ GpgEncrResult result = nullptr;
+ GpgError error;
+ bool if_error = false;
- if (ret == QMessageBox::Cancel) return;
+ // Detect ascii mode
+ auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
+ bool non_ascii_when_export = true;
+ try {
+ non_ascii_when_export = settings.lookup("general.non_ascii_when_export");
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("non_ascii_when_export");
}
- auto key_ids = mKeyList->getChecked();
- auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids);
- if (keys->empty()) {
- QMessageBox::critical(this, _("No Key Selected"), _("No Key Selected"));
- return;
+ auto _channel = GPGFRONTEND_DEFAULT_CHANNEL;
+ auto _extension = ".asc";
+ if (non_ascii_when_export) {
+ _channel = GPGFRONTEND_NON_ASCII_CHANNEL;
+ _extension = ".gpg";
}
- for (const auto& key : *keys) {
- if (!key.CanEncrActual()) {
- QMessageBox::information(
- this, _("Invalid Operation"),
- QString(
- _("The selected key contains a key that does not actually have a "
- "encrypt usage.")) +
- "<br/><br/>" + _("For example the Following Key:") + " <br/>" +
- QString::fromStdString(key.uids()->front().uid()));
- return;
- }
+ auto out_path = path + _extension;
+
+ if (QFile::exists(out_path)) {
+ boost::filesystem::path _out_path = out_path.toStdString();
+ auto out_file_name = boost::format(_("The target file %1% already exists, "
+ "do you need to overwrite it?")) %
+ _out_path.filename();
+ auto ret =
+ QMessageBox::warning(this, _("Warning"), out_file_name.str().c_str(),
+ QMessageBox::Ok | QMessageBox::Cancel);
+
+ if (ret == QMessageBox::Cancel) return;
}
- GpgEncrResult result = nullptr;
- GpgError error;
- bool if_error = false;
- process_operation(this, _("Encrypting"), [&]() {
- try {
- error = GpgFileOpera::EncryptFile(std::move(keys), path.toStdString(),
- result);
- } catch (const std::runtime_error& e) {
- if_error = true;
+ if (key_ids->empty()) {
+ // Symmetric Encrypt
+ auto ret = QMessageBox::information(
+ this, _("Symmetric Encryption"),
+ _("No Key Selected. Do you want to encrypt with a "
+ "symmetric cipher using a passphrase?"),
+ QMessageBox::Ok | QMessageBox::Cancel);
+
+ if (ret == QMessageBox::Cancel) return;
+
+ process_operation(this, _("Symmetrically Encrypting"), [&]() {
+ try {
+ error = GpgFrontend::GpgFileOpera::EncryptFileSymmetric(
+ path.toStdString(), out_path.toStdString(), result, _channel);
+ } catch (const std::runtime_error& e) {
+ if_error = true;
+ }
+ });
+ } else {
+ auto p_keys = GpgKeyGetter::GetInstance().GetKeys(key_ids);
+
+ // check key abilities
+ for (const auto& key : *p_keys) {
+ bool key_can_encrypt = key.CanEncrActual();
+
+ if (!key_can_encrypt) {
+ QMessageBox::critical(
+ nullptr, _("Invalid KeyPair"),
+ QString(_("The selected keypair cannot be used for encryption.")) +
+ "<br/><br/>" + _("For example the Following Key:") + " <br/>" +
+ QString::fromStdString(key.uids()->front().uid()));
+ return;
+ }
}
- });
+
+ process_operation(this, _("Encrypting"), [&]() {
+ try {
+ error =
+ GpgFileOpera::EncryptFile(std::move(p_keys), path.toStdString(),
+ out_path.toStdString(), result, _channel);
+ } catch (const std::runtime_error& e) {
+ if_error = true;
+ }
+ });
+ }
if (!if_error) {
auto resultAnalyse = EncryptResultAnalyse(error, std::move(result));
@@ -116,16 +158,15 @@ void MainWindow::slotFileDecrypt() {
if (!file_pre_check(this, path)) return;
- QString outFileName, fileExtension = QFileInfo(path).suffix();
+ boost::filesystem::path out_path = path.toStdString();
- if (fileExtension == "asc" || fileExtension == "gpg") {
- int pos = path.lastIndexOf(QChar('.'));
- outFileName = path.left(pos);
+ if (out_path.extension() == ".asc" || out_path.extension() == ".gpg") {
+ out_path = out_path.parent_path() / out_path.stem();
} else {
- outFileName = path + ".out";
+ out_path += ".out";
}
- if (QFile::exists(outFileName)) {
+ if (exists(out_path)) {
auto ret = QMessageBox::warning(
this, _("Warning"),
_("The target file already exists, do you need to overwrite it?"),
@@ -139,7 +180,8 @@ void MainWindow::slotFileDecrypt() {
bool if_error = false;
process_operation(this, _("Decrypting"), [&]() {
try {
- error = GpgFileOpera::DecryptFile(path.toStdString(), result);
+ error = GpgFileOpera::DecryptFile(path.toStdString(), out_path.string(),
+ result);
} catch (const std::runtime_error& e) {
if_error = true;
}
@@ -168,7 +210,9 @@ void MainWindow::slotFileSign() {
auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids);
if (keys->empty()) {
- QMessageBox::critical(this, _("No Key Selected"), _("No Key Selected"));
+ QMessageBox::critical(
+ this, _("No Key Selected"),
+ _("Please select the key in the key toolbox on the right."));
return;
}
@@ -184,8 +228,26 @@ void MainWindow::slotFileSign() {
}
}
- auto sig_file_path = boost::filesystem::path(path.toStdString() + ".sig");
- if (QFile::exists(sig_file_path.string().c_str())) {
+ // Detect ascii mode
+ auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
+ bool non_ascii_when_export = true;
+ try {
+ non_ascii_when_export = settings.lookup("general.non_ascii_when_export");
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("non_ascii_when_export");
+ }
+
+ auto _channel = GPGFRONTEND_DEFAULT_CHANNEL;
+ auto _extension = ".asc";
+ if (non_ascii_when_export) {
+ _channel = GPGFRONTEND_NON_ASCII_CHANNEL;
+ _extension = ".sig";
+ }
+
+ boost::filesystem::path in_path = path.toStdString();
+ auto sig_file_path = in_path;
+ sig_file_path += _extension;
+ if (exists(sig_file_path)) {
auto ret = QMessageBox::warning(
this, _("Warning"),
QString(_("The signature file \"%1\" exists, "
@@ -202,8 +264,8 @@ void MainWindow::slotFileSign() {
process_operation(this, _("Signing"), [&]() {
try {
- error =
- GpgFileOpera::SignFile(std::move(keys), path.toStdString(), result);
+ error = GpgFileOpera::SignFile(std::move(keys), in_path.string(),
+ sig_file_path.string(), result, _channel);
} catch (const std::runtime_error& e) {
if_error = true;
}
@@ -229,60 +291,62 @@ void MainWindow::slotFileVerify() {
auto fileTreeView = edit->slotCurPageFileTreeView();
auto path = fileTreeView->getSelected();
- QFileInfo fileInfo(path);
+ boost::filesystem::path in_path = path.toStdString();
+ boost::filesystem::path sign_file_path = in_path, data_file_path;
- QString signFilePath, dataFilePath;
+ // Detect ascii mode
+ auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
+ bool non_ascii_when_export = true;
+ try {
+ non_ascii_when_export = settings.lookup("general.non_ascii_when_export");
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("non_ascii_when_export");
+ }
- if (fileInfo.suffix() == "gpg") {
- dataFilePath = path;
- signFilePath = path;
- } else if (fileInfo.suffix() == "sig") {
- int pos = path.lastIndexOf(QChar('.'));
- dataFilePath = path.left(pos);
- signFilePath = path;
- } else {
- dataFilePath = path;
- signFilePath = path + ".sig";
+ auto _channel = GPGFRONTEND_DEFAULT_CHANNEL;
+ if (non_ascii_when_export) {
+ _channel = GPGFRONTEND_NON_ASCII_CHANNEL;
}
- if (fileInfo.suffix() != "gpg") {
+ if (in_path.extension() == ".gpg") {
+ swap(data_file_path, sign_file_path);
+ } else if (in_path.extension() == ".sig" || in_path.extension() == ".asc") {
+ data_file_path = sign_file_path.parent_path() / sign_file_path.stem();
+ }
+
+ LOG(INFO) << "sign_file_path" << sign_file_path << sign_file_path.extension();
+
+ if (in_path.extension() != ".gpg") {
bool ok;
- QString text =
- QInputDialog::getText(this, _("Origin file to verify"), _("Filepath"),
- QLineEdit::Normal, dataFilePath, &ok);
+ QString text = QInputDialog::getText(this, _("Origin file to verify"),
+ _("Filepath"), QLineEdit::Normal,
+ data_file_path.string().c_str(), &ok);
if (ok && !text.isEmpty()) {
- dataFilePath = text;
+ data_file_path = text.toStdString();
} else {
return;
}
}
- QFileInfo dataFileInfo(dataFilePath), signFileInfo(signFilePath);
-
- if (!dataFileInfo.isFile() || !signFileInfo.isFile()) {
+ if (!is_regular_file(data_file_path) ||
+ (!sign_file_path.empty() && !is_regular_file(sign_file_path))) {
QMessageBox::critical(
this, _("Error"),
_("Please select the appropriate origin file or signature file. "
"Ensure that both are in this directory."));
return;
}
- if (!dataFileInfo.isReadable()) {
- QMessageBox::critical(this, _("Error"),
- _("No permission to read target file."));
- return;
- }
- if (!fileInfo.isReadable()) {
- QMessageBox::critical(this, _("Error"),
- _("No permission to read signature file."));
- return;
- }
+
+ DLOG(INFO) << "data path" << data_file_path;
+ DLOG(INFO) << "sign path" << sign_file_path;
GpgVerifyResult result = nullptr;
gpgme_error_t error;
bool if_error = false;
process_operation(this, _("Verifying"), [&]() {
try {
- error = GpgFileOpera::VerifyFile(dataFilePath.toStdString(), result);
+ error = GpgFileOpera::VerifyFile(
+ data_file_path.string(), sign_file_path.string(), result, _channel);
} catch (const std::runtime_error& e) {
if_error = true;
}
@@ -313,23 +377,18 @@ void MainWindow::slotFileEncryptSign() {
if (!file_pre_check(this, path)) return;
- if (QFile::exists(path + ".gpg")) {
- auto ret = QMessageBox::warning(
- this, _("Warning"),
- _("The target file already exists, do you need to overwrite it?"),
- QMessageBox::Ok | QMessageBox::Cancel);
-
- if (ret == QMessageBox::Cancel) return;
- }
-
+ // check selected keys
auto key_ids = mKeyList->getChecked();
auto p_keys = GpgKeyGetter::GetInstance().GetKeys(key_ids);
if (p_keys->empty()) {
- QMessageBox::critical(this, _("No Key Selected"), _("No Key Selected"));
+ QMessageBox::critical(
+ this, _("No Key Selected"),
+ _("Please select the key in the key toolbox on the right."));
return;
}
+ // check key abilities
for (const auto& key : *p_keys) {
bool key_can_encrypt = key.CanEncrActual();
@@ -343,6 +402,33 @@ void MainWindow::slotFileEncryptSign() {
}
}
+ // Detect ascii mode
+ auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
+ bool non_ascii_when_export = true;
+ try {
+ non_ascii_when_export = settings.lookup("general.non_ascii_when_export");
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("non_ascii_when_export");
+ }
+
+ auto _channel = GPGFRONTEND_DEFAULT_CHANNEL;
+ auto _extension = ".asc";
+ if (non_ascii_when_export) {
+ _channel = GPGFRONTEND_NON_ASCII_CHANNEL;
+ _extension = ".gpg";
+ }
+
+ boost::filesystem::path out_path = path.toStdString() + _extension;
+
+ if (exists(out_path)) {
+ auto ret = QMessageBox::warning(
+ this, _("Warning"),
+ _("The target file already exists, do you need to overwrite it?"),
+ QMessageBox::Ok | QMessageBox::Cancel);
+
+ if (ret == QMessageBox::Cancel) return;
+ }
+
auto signersPicker = new SignersPicker(this);
QEventLoop loop;
connect(signersPicker, SIGNAL(finished(int)), &loop, SLOT(quit()));
@@ -351,14 +437,6 @@ void MainWindow::slotFileEncryptSign() {
auto signer_key_ids = signersPicker->getCheckedSigners();
auto p_signer_keys = GpgKeyGetter::GetInstance().GetKeys(signer_key_ids);
- for (const auto& key : *p_keys) {
- LOG(INFO) << "Keys " << key.email();
- }
-
- for (const auto& signer : *p_signer_keys) {
- LOG(INFO) << "Signers " << signer.email();
- }
-
GpgEncrResult encr_result = nullptr;
GpgSignResult sign_result = nullptr;
@@ -369,18 +447,18 @@ void MainWindow::slotFileEncryptSign() {
try {
error = GpgFileOpera::EncryptSignFile(
std::move(p_keys), std::move(p_signer_keys), path.toStdString(),
- encr_result, sign_result);
+ out_path.string(), encr_result, sign_result, _channel);
} catch (const std::runtime_error& e) {
if_error = true;
}
});
if (!if_error) {
- auto encrypt_res = EncryptResultAnalyse(error, std::move(encr_result));
+ auto encrypt_result = EncryptResultAnalyse(error, std::move(encr_result));
auto sign_res = SignResultAnalyse(error, std::move(sign_result));
- encrypt_res.analyse();
+ encrypt_result.analyse();
sign_res.analyse();
- process_result_analyse(edit, infoBoard, encrypt_res, sign_res);
+ process_result_analyse(edit, infoBoard, encrypt_result, sign_res);
fileTreeView->update();
@@ -397,11 +475,12 @@ void MainWindow::slotFileDecryptVerify() {
if (!file_pre_check(this, path)) return;
- boost::filesystem::path out_path(path.toStdString());
- if (out_path.extension() == ".asc" || out_path.extension() == ".gpg") {
- out_path = out_path.parent_path() / out_path.filename();
+ boost::filesystem::path in_path(path.toStdString());
+ boost::filesystem::path out_path = in_path;
+ if (in_path.extension() == ".asc" || in_path.extension() == ".gpg") {
+ out_path = in_path.parent_path() / out_path.stem();
} else {
- out_path = out_path.replace_extension(".out").string();
+ out_path += ".out";
}
LOG(INFO) << "out path" << out_path;
@@ -422,8 +501,8 @@ void MainWindow::slotFileDecryptVerify() {
bool if_error = false;
process_operation(this, _("Decrypting and Verifying"), [&]() {
try {
- error = GpgFileOpera::DecryptVerifyFile(path.toStdString(), d_result,
- v_result);
+ error = GpgFileOpera::DecryptVerifyFile(
+ path.toStdString(), out_path.string(), d_result, v_result);
} catch (const std::runtime_error& e) {
if_error = true;
}
diff --git a/src/ui/main_window/MainWindowSlotFunction.cpp b/src/ui/main_window/MainWindowSlotFunction.cpp
index 2dd3f842..57fb5bae 100644
--- a/src/ui/main_window/MainWindowSlotFunction.cpp
+++ b/src/ui/main_window/MainWindowSlotFunction.cpp
@@ -37,7 +37,7 @@
#include "gpg/function/BasicOperator.h"
#include "gpg/function/GpgKeyGetter.h"
-#include "gpg/function/GpgKeyImportExportor.h"
+#include "gpg/function/GpgKeyImportExporter.h"
#include "ui/UserInterfaceUtils.h"
#include "ui/help/AboutDialog.h"
#include "ui/settings/GlobalSettingStation.h"
@@ -59,11 +59,11 @@ void MainWindow::slotEncrypt() {
if (key_ids->empty()) {
// Symmetric Encrypt
- auto ret =
- QMessageBox::warning(this, _("Warning"),
- _("No Key Selected. Do you want to encrypt with a "
- "symmetric cipher using a passphrase?"),
- QMessageBox::Ok | QMessageBox::Cancel);
+ auto ret = QMessageBox::information(
+ this, _("Symmetric Encryption"),
+ _("No Key Selected. Do you want to encrypt with a "
+ "symmetric cipher using a passphrase?"),
+ QMessageBox::Ok | QMessageBox::Cancel);
if (ret == QMessageBox::Cancel) return;
@@ -129,7 +129,9 @@ void MainWindow::slotSign() {
auto key_ids = mKeyList->getPrivateChecked();
if (key_ids->empty()) {
- QMessageBox::critical(this, _("No Key Selected"), _("No Key Selected"));
+ QMessageBox::critical(
+ this, _("No Key Selected"),
+ _("Please select the key in the key toolbox on the right."));
return;
}
@@ -270,7 +272,9 @@ void MainWindow::slotEncryptSign() {
auto key_ids = mKeyList->getChecked();
if (key_ids->empty()) {
- QMessageBox::critical(nullptr, _("No Key Selected"), _("No Key Selected"));
+ QMessageBox::critical(
+ nullptr, _("No Key Selected"),
+ _("Please select the key in the key toolbox on the right."));
return;
}
@@ -348,7 +352,7 @@ void MainWindow::slotEncryptSign() {
infoBoard->resetOptionActionsMenu();
#ifdef SMTP_SUPPORT
if (check_gpg_error_2_err_code(error) == GPG_ERR_NO_ERROR)
- send_an_email(this, infoBoard, edit->curTextPage()->toPlainText());
+ send_an_email(this, infoBoard, edit->curTextPage()->toPlainText(), false);
#endif
#ifdef ADVANCE_SUPPORT
@@ -448,7 +452,7 @@ void MainWindow::slotAppendSelectedKeys() {
auto exported = std::make_unique<ByteArray>();
auto key_ids = mKeyList->getSelected();
- GpgKeyImportExportor::GetInstance().ExportKeys(key_ids, exported);
+ GpgKeyImportExporter::GetInstance().ExportKeys(key_ids, exported);
edit->curTextPage()->append(QString::fromStdString(*exported));
}
@@ -495,13 +499,12 @@ void MainWindow::uploadKeyToServer() {
void MainWindow::slotOpenFile(QString& path) { edit->slotOpenFile(path); }
-void MainWindow::slotVersionUpgrade(const QString& currentVersion,
- const QString& latestVersion) {
+void MainWindow::slotVersionUpgrade(const SoftwareVersion& version) {
LOG(INFO) << _("called");
- if (currentVersion < latestVersion) {
+ if (version.NeedUpgrade()) {
statusBar()->showMessage(
QString(_("GpgFrontend Upgradeable (New Version: %1)."))
- .arg(latestVersion),
+ .arg(version.latest_version.c_str()),
30000);
auto update_button = new QPushButton("Update GpgFrontend", this);
connect(update_button, &QPushButton::clicked, [=]() {
@@ -509,17 +512,24 @@ void MainWindow::slotVersionUpgrade(const QString& currentVersion,
about_dialog->show();
});
statusBar()->addPermanentWidget(update_button, 0);
- } else if (currentVersion > latestVersion) {
+ } else if (version.VersionWithDrawn()) {
QMessageBox::warning(
- this, _("Unreleased Version"),
+ this, _("Withdrawn Version"),
QString(
- _("This version(%1) has not been officially released and is not "
- "recommended for use in a production environment. <br/>"))
- .arg(currentVersion) +
- QString(
- _("You can download the latest version(%1) on Github Releases "
- "Page.<br/>"))
- .arg(latestVersion));
+ _("This version(%1) may have been withdrawn by the developer due "
+ "to serious problems. Please stop using this version "
+ "immediately and use the latest stable version."))
+ .arg(version.current_version.c_str()) +
+ "<br/>" +
+ QString(_("You can download the latest stable version(%1) on "
+ "Github Releases "
+ "Page.<br/>"))
+ .arg(version.latest_version.c_str()));
+ } else if (!version.CurrentVersionReleased()) {
+ statusBar()->showMessage(
+ QString(_("This maybe a BETA Version (Latest Stable Version: %1)."))
+ .arg(version.latest_version.c_str()),
+ 30000);
}
}
diff --git a/src/ui/main_window/MainWindowUI.cpp b/src/ui/main_window/MainWindowUI.cpp
index 0c557d16..cb7962f7 100644
--- a/src/ui/main_window/MainWindowUI.cpp
+++ b/src/ui/main_window/MainWindowUI.cpp
@@ -258,7 +258,7 @@ void MainWindow::createActions() {
/* Popup-Menu-Action for KeyList
*/
appendSelectedKeysAct =
- new QAction(_("Append Selected Key(s) To Text"), this);
+ new QAction(_("Append Public Key To Text Editor"), this);
appendSelectedKeysAct->setToolTip(
_("Append The Selected Keys To Text in Editor"));
connect(appendSelectedKeysAct, SIGNAL(triggered()), this,
@@ -297,7 +297,7 @@ void MainWindow::createActions() {
connect(addPgpHeaderAct, SIGNAL(triggered()), this, SLOT(slotAddPgpHeader()));
#ifdef SMTP_SUPPORT
- sendMailAct = new QAction(_("Send An Email"), this);
+ sendMailAct = new QAction(_("New Message"), this);
sendMailAct->setIcon(QIcon(":email.png"));
connect(sendMailAct, &QAction::triggered, this, [=]() {
auto* dialog = new SendMailDialog({}, this);
@@ -421,6 +421,11 @@ void MainWindow::createToolBars() {
specialEditToolBar->hide();
viewMenu->addAction(specialEditToolBar->toggleViewAction());
+ emailToolBar = addToolBar(_("Email"));
+ emailToolBar->setObjectName("emailToolBar");
+ emailToolBar->addAction(sendMailAct);
+ viewMenu->addAction(emailToolBar->toggleViewAction());
+
// Add dropdown menu for key import to keytoolbar
importButton = new QToolButton();
importButton->setMenu(importKeyMenu);
diff --git a/src/ui/settings/GlobalSettingStation.h b/src/ui/settings/GlobalSettingStation.h
index a7cbe569..a89bf32d 100644
--- a/src/ui/settings/GlobalSettingStation.h
+++ b/src/ui/settings/GlobalSettingStation.h
@@ -48,6 +48,18 @@ class GlobalSettingStation : public QObject {
return app_log_path;
}
+ [[nodiscard]] boost::filesystem::path GetStandaloneDatabaseDir() const {
+ auto db_path = app_configure_path / "db";
+ if (!boost::filesystem::exists(db_path)) {
+ boost::filesystem::create_directory(db_path);
+ }
+ return db_path;
+ }
+
+ [[nodiscard]] boost::filesystem::path GetStandaloneGpgBinDir() const {
+ return app_resource_path / "gpg1.4" / "gpg";
+ }
+
[[nodiscard]] boost::filesystem::path GetLocaleDir() const {
return app_locale_path;
}
diff --git a/src/ui/settings/SettingsDialog.cpp b/src/ui/settings/SettingsDialog.cpp
index 7b8a8624..01e4094f 100644
--- a/src/ui/settings/SettingsDialog.cpp
+++ b/src/ui/settings/SettingsDialog.cpp
@@ -29,6 +29,7 @@
#include "SettingsAppearance.h"
#include "SettingsGeneral.h"
#include "SettingsKeyServer.h"
+#include "SettingsNetwork.h"
#ifdef SMTP_SUPPORT
#include "SettingsSendMail.h"
@@ -37,13 +38,15 @@
namespace GpgFrontend::UI {
SettingsDialog::SettingsDialog(QWidget* parent) : QDialog(parent) {
- tabWidget = new QTabWidget;
+
+ tabWidget = new QTabWidget();
generalTab = new GeneralTab();
- appearanceTab = new AppearanceTab;
+ appearanceTab = new AppearanceTab();
#ifdef SMTP_SUPPORT
- sendMailTab = new SendMailTab;
+ sendMailTab = new SendMailTab();
#endif
- keyserverTab = new KeyserverTab;
+ keyserverTab = new KeyserverTab();
+ networkTab = new NetworkTab();
#ifdef ADVANCED_SUPPORT
advancedTab = new AdvancedTab;
#endif
@@ -55,6 +58,7 @@ SettingsDialog::SettingsDialog(QWidget* parent) : QDialog(parent) {
#endif
tabWidget->addTab(keyserverTab, _("Key Server"));
// tabWidget->addTab(gpgPathsTab, _("Gpg paths"));
+ tabWidget->addTab(networkTab, _("Network"));
#ifdef ADVANCED_SUPPORT
tabWidget->addTab(advancedTab, _("Advanced"));
#endif
@@ -114,6 +118,7 @@ void SettingsDialog::slotAccept() {
#endif
appearanceTab->applySettings();
keyserverTab->applySettings();
+ networkTab->applySettings();
#ifdef ADVANCED_SUPPORT
advancedTab->applySettings();
#endif
diff --git a/src/ui/settings/SettingsDialog.h b/src/ui/settings/SettingsDialog.h
index b8277906..da3bdba3 100755
--- a/src/ui/settings/SettingsDialog.h
+++ b/src/ui/settings/SettingsDialog.h
@@ -38,6 +38,7 @@ class SendMailTab;
class AppearanceTab;
class KeyserverTab;
+class NetworkTab;
#ifdef ADVANCED_SUPPORT
class AdvancedTab;
@@ -55,6 +56,7 @@ class SettingsDialog : public QDialog {
#endif
AppearanceTab* appearanceTab;
KeyserverTab* keyserverTab;
+ NetworkTab* networkTab;
#ifdef ADVANCED_SUPPORT
AdvancedTab* advancedTab;
#endif
diff --git a/src/ui/settings/SettingsGeneral.cpp b/src/ui/settings/SettingsGeneral.cpp
index 6b6568a4..4f8ef544 100644
--- a/src/ui/settings/SettingsGeneral.cpp
+++ b/src/ui/settings/SettingsGeneral.cpp
@@ -24,157 +24,49 @@
#include "SettingsGeneral.h"
-#ifdef SERVER_SUPPORT
-#include "server/ComUtils.h"
-#endif
-
#ifdef MULTI_LANG_SUPPORT
#include "SettingsDialog.h"
#endif
#include "GlobalSettingStation.h"
-#include "gpg/function/GpgKeyGetter.h"
-#include "ui/widgets/KeyList.h"
+#include "ui_GeneralSettings.h"
namespace GpgFrontend::UI {
-GeneralTab::GeneralTab(QWidget* parent) : QWidget(parent) {
-#ifdef SERVER_SUPPORT
- /*****************************************
- * GpgFrontend Server
- *****************************************/
- auto* serverBox = new QGroupBox(_("GpgFrontend Server"));
- auto* serverBoxLayout = new QVBoxLayout();
- serverSelectBox = new QComboBox();
- serverBoxLayout->addWidget(serverSelectBox);
- serverBoxLayout->addWidget(new QLabel(
- _("Server that provides short key and key exchange services")));
-
- serverBox->setLayout(serverBoxLayout);
-#endif
-
- /*****************************************
- * Save-Checked-Keys-Box
- *****************************************/
- auto* saveCheckedKeysBox = new QGroupBox(_("Save Checked Keys"));
- auto* saveCheckedKeysBoxLayout = new QHBoxLayout();
- saveCheckedKeysCheckBox = new QCheckBox(
- _("Save checked private keys on exit and restore them on next start."),
- this);
- saveCheckedKeysBoxLayout->addWidget(saveCheckedKeysCheckBox);
- saveCheckedKeysBox->setLayout(saveCheckedKeysBoxLayout);
-
- /*****************************************
- * Longer-Expire-Date-Box
- *****************************************/
- auto* longerKeyExpirationDateBox =
- new QGroupBox(_("Longer Key Expiration Date"));
- auto* longerKeyExpirationDateBoxLayout = new QHBoxLayout();
- longerKeyExpirationDateCheckBox = new QCheckBox(
- _("Unlock key expiration date setting up to 30 years."), this);
- longerKeyExpirationDateBoxLayout->addWidget(longerKeyExpirationDateCheckBox);
- longerKeyExpirationDateBox->setLayout(longerKeyExpirationDateBoxLayout);
-
- /*****************************************
- * Key-Impport-Confirmation Box
- *****************************************/
- auto* importConfirmationBox =
- new QGroupBox(_("Confirm drag'n'drop key import"));
- auto* importConfirmationBoxLayout = new QHBoxLayout();
- importConfirmationCheckBox = new QCheckBox(
- _("Import files dropped on the Key List without confirmation."), this);
- importConfirmationBoxLayout->addWidget(importConfirmationCheckBox);
- importConfirmationBox->setLayout(importConfirmationBoxLayout);
+GeneralTab::GeneralTab(QWidget* parent)
+ : QWidget(parent), ui(std::make_shared<Ui_GeneralSettings>()) {
+ ui->setupUi(this);
+
+ ui->saveCheckedKeysBox->setTitle(_("Save Checked Keys"));
+ ui->saveCheckedKeysCheckBox->setText(
+ _("Save checked private keys on exit and restore them on next start."));
+ ui->longerKeyExpirationDateBox->setTitle(_("Longer Key Expiration Date"));
+ ui->longerKeyExpirationDateCheckBox->setText(
+ _("Unlock key expiration date setting up to 30 years."));
+ ui->importConfirmationBox->setTitle(_("Confirm drag'n'drop key import"));
+ 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->langBox->setTitle(_("Language"));
+ ui->langNoteLabel->setText(
+ "<b>" + QString(_("NOTE")) + _(": ") + "</b>" +
+ _("GpgFrontend will restart automatically if you change the language!"));
#ifdef MULTI_LANG_SUPPORT
- /*****************************************
- * Language Select Box
- *****************************************/
- auto* langBox = new QGroupBox(_("Language"));
- auto* langBoxLayout = new QVBoxLayout();
- langSelectBox = new QComboBox();
- langSelectBox->setMaxVisibleItems(8);
- langSelectBox->view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
lang = SettingsDialog::listLanguages();
-
for (const auto& l : lang) {
- langSelectBox->addItem(l);
+ ui->langSelectBox->addItem(l);
}
- langSelectBox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
-
- langBoxLayout->addWidget(langSelectBox);
- langBoxLayout->addWidget(new QLabel(
- "<b>" + QString(_("NOTE")) + _(": ") + "</b>" +
- _("GpgFrontend will restart automatically if you change the language!")));
- langBox->setLayout(langBoxLayout);
- connect(langSelectBox, SIGNAL(currentIndexChanged(int)), this,
+ connect(ui->langSelectBox, SIGNAL(currentIndexChanged(int)), this,
SLOT(slotLanguageChanged()));
#endif
-#ifdef SERVER_SUPPORT
- /*****************************************
- * Own Key Select Box
- *****************************************/
- auto* ownKeyBox = new QGroupBox(_("Own key"));
- auto* ownKeyBoxLayout = new QVBoxLayout();
- auto* ownKeyServiceTokenLayout = new QHBoxLayout();
- ownKeySelectBox = new QComboBox;
- getServiceTokenButton = new QPushButton(_("Get Service Token"));
- serviceTokenLabel = new QLabel(_("No Service Token Found"));
- serviceTokenLabel->setAlignment(Qt::AlignCenter);
-
- ownKeyBox->setLayout(ownKeyBoxLayout);
-
- mKeyList = new KeyList();
-
- // Fill the keyid hashmap
- keyIds.insert({QString(), "<none>"});
-
- auto private_keys = mKeyList->getAllPrivateKeys();
-
- for (const auto& keyid : *private_keys) {
- auto key = GpgKeyGetter::GetInstance().GetKey(keyid);
- if (!key.good()) continue;
- keyIds.insert({key.id(), key.uids()->front().uid()});
- }
- for (const auto& k : keyIds) {
- ownKeySelectBox->addItem(QString::fromStdString(k.second));
- keyIdsList.push_back(k.first);
- }
- connect(ownKeySelectBox, SIGNAL(currentIndexChanged(int)), this,
- SLOT(slotOwnKeyIdChanged()));
- connect(getServiceTokenButton, SIGNAL(clicked(bool)), this,
- SLOT(slotGetServiceToken()));
-
- ownKeyBoxLayout->addWidget(new QLabel(
- _("Key pair for synchronization and identity authentication")));
- ownKeyBoxLayout->addWidget(ownKeySelectBox);
- ownKeyBoxLayout->addLayout(ownKeyServiceTokenLayout);
- ownKeyServiceTokenLayout->addWidget(getServiceTokenButton);
- ownKeyServiceTokenLayout->addWidget(serviceTokenLabel);
- ownKeyServiceTokenLayout->stretch(0);
-#endif
-
- /*****************************************
- * Mainlayout
- *****************************************/
- auto* mainLayout = new QVBoxLayout;
-#ifdef SERVER_SUPPORT
- mainLayout->addWidget(serverBox);
-#endif
- mainLayout->addWidget(longerKeyExpirationDateBox);
- mainLayout->addWidget(saveCheckedKeysBox);
- mainLayout->addWidget(importConfirmationBox);
-#ifdef MULTI_LANG_SUPPORT
- mainLayout->addWidget(langBox);
-#endif
-#ifdef SERVER_SUPPORT
- mainLayout->addWidget(ownKeyBox);
-#endif
-
setSettings();
- mainLayout->addStretch(1);
- setLayout(mainLayout);
}
/**********************************
@@ -186,7 +78,8 @@ void GeneralTab::setSettings() {
auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
try {
bool save_key_checked = settings.lookup("general.save_key_checked");
- if (save_key_checked) saveCheckedKeysCheckBox->setCheckState(Qt::Checked);
+ if (save_key_checked)
+ ui->saveCheckedKeysCheckBox->setCheckState(Qt::Checked);
} catch (...) {
LOG(ERROR) << _("Setting Operation Error") << _("save_key_checked");
}
@@ -196,73 +89,45 @@ void GeneralTab::setSettings() {
settings.lookup("general.longer_expiration_date");
LOG(INFO) << "longer_expiration_date" << longer_expiration_date;
if (longer_expiration_date)
- longerKeyExpirationDateCheckBox->setCheckState(Qt::Checked);
+ ui->longerKeyExpirationDateCheckBox->setCheckState(Qt::Checked);
} catch (...) {
LOG(ERROR) << _("Setting Operation Error") << _("longer_expiration_date");
}
-#ifdef SERVER_SUPPORT
- auto serverList =
- settings.value("general/gpgfrontendServerList").toStringList();
- if (serverList.empty()) {
- serverList.append("service.gpgfrontend.pub");
- serverList.append("localhost");
- }
- for (const auto& s : serverList) serverSelectBox->addItem(s);
-
- qDebug() << "Current Gpgfrontend Server"
- << settings.value("general/currentGpgfrontendServer").toString();
- serverSelectBox->setCurrentText(
- settings
- .value("general/currentGpgfrontendServer", "service.gpgfrontend.pub")
- .toString());
-
- connect(serverSelectBox,
- QOverload<const QString&>::of(&QComboBox::currentTextChanged), this,
- [&](const QString& current) -> void {
- settings.setValue("general/currentGpgfrontendServer", current);
- });
-#endif
-
#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();
if (!lang.empty()) {
- langSelectBox->setCurrentIndex(langSelectBox->findText(lang_value));
+ ui->langSelectBox->setCurrentIndex(
+ ui->langSelectBox->findText(lang_value));
} else {
- langSelectBox->setCurrentIndex(0);
+ ui->langSelectBox->setCurrentIndex(0);
}
} catch (...) {
LOG(ERROR) << _("Setting Operation Error") << _("lang");
}
#endif
-#ifdef SERVER_SUPPORT
- auto own_key_id = settings.value("general/ownKeyId").toString().toStdString();
- if (own_key_id.empty()) {
- ownKeySelectBox->setCurrentText("<none>");
- } else {
- const auto uid = keyIds.find(own_key_id)->second;
- ownKeySelectBox->setCurrentText(QString::fromStdString(uid));
- }
-
- serviceToken =
- settings.value("general/serviceToken").toString().toStdString();
- if (!serviceToken.empty()) {
- serviceTokenLabel->setText(QString::fromStdString(serviceToken));
- }
-#endif
-
try {
bool confirm_import_keys = settings.lookup("general.confirm_import_keys");
LOG(INFO) << "confirm_import_keys" << confirm_import_keys;
if (confirm_import_keys)
- importConfirmationCheckBox->setCheckState(Qt::Checked);
+ ui->importConfirmationCheckBox->setCheckState(Qt::Checked);
} catch (...) {
LOG(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;
+ if (non_ascii_when_export)
+ ui->asciiModeCheckBox->setCheckState(Qt::Checked);
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("non_ascii_when_export");
+ }
}
/***********************************
@@ -281,54 +146,41 @@ void GeneralTab::applySettings() {
if (!general.exists("longer_expiration_date"))
general.add("longer_expiration_date", libconfig::Setting::TypeBoolean) =
- longerKeyExpirationDateCheckBox->isChecked();
+ ui->longerKeyExpirationDateCheckBox->isChecked();
else {
general["longer_expiration_date"] =
- longerKeyExpirationDateCheckBox->isChecked();
+ ui->longerKeyExpirationDateCheckBox->isChecked();
}
if (!general.exists("save_key_checked"))
general.add("save_key_checked", libconfig::Setting::TypeBoolean) =
- saveCheckedKeysCheckBox->isChecked();
+ ui->saveCheckedKeysCheckBox->isChecked();
else {
- general["save_key_checked"] = saveCheckedKeysCheckBox->isChecked();
+ general["save_key_checked"] = ui->saveCheckedKeysCheckBox->isChecked();
}
-#ifdef SERVER_SUPPORT
- qDebug() << "serverSelectBox currentText" << serverSelectBox->currentText();
- settings.setValue("general/currentGpgfrontendServer",
- serverSelectBox->currentText());
-
- auto* serverList = new QStringList();
- for (int i = 0; i < serverSelectBox->count(); i++)
- serverList->append(serverSelectBox->itemText(i));
- settings.setValue("general/gpgfrontendServerList", *serverList);
- delete serverList;
-#endif
+ if (!general.exists("non_ascii_when_export"))
+ general.add("non_ascii_when_export", libconfig::Setting::TypeBoolean) =
+ ui->asciiModeCheckBox->isChecked();
+ else {
+ general["non_ascii_when_export"] = ui->asciiModeCheckBox->isChecked();
+ }
#ifdef MULTI_LANG_SUPPORT
if (!general.exists("lang"))
general.add("lang", libconfig::Setting::TypeBoolean) =
- lang.key(langSelectBox->currentText()).toStdString();
+ lang.key(ui->langSelectBox->currentText()).toStdString();
else {
- general["lang"] = lang.key(langSelectBox->currentText()).toStdString();
+ general["lang"] = lang.key(ui->langSelectBox->currentText()).toStdString();
}
#endif
-#ifdef SERVER_SUPPORT
- settings.setValue(
- "general/ownKeyId",
- QString::fromStdString(keyIdsList[ownKeySelectBox->currentIndex()]));
-
- settings.setValue("general/serviceToken",
- QString::fromStdString(serviceToken));
-#endif
-
if (!general.exists("confirm_import_keys"))
general.add("confirm_import_keys", libconfig::Setting::TypeBoolean) =
- importConfirmationCheckBox->isChecked();
+ ui->importConfirmationCheckBox->isChecked();
else {
- general["confirm_import_keys"] = importConfirmationCheckBox->isChecked();
+ general["confirm_import_keys"] =
+ ui->importConfirmationCheckBox->isChecked();
}
}
@@ -336,136 +188,4 @@ void GeneralTab::applySettings() {
void GeneralTab::slotLanguageChanged() { emit signalRestartNeeded(true); }
#endif
-#ifdef SERVER_SUPPORT
-void GeneralTab::slotOwnKeyIdChanged() {
- // Set ownKeyId to currently selected
- this->serviceTokenLabel->setText(_("No Service Token Found"));
- serviceToken.clear();
-}
-#endif
-
-#ifdef SERVER_SUPPORT
-void GeneralTab::slotGetServiceToken() {
- auto utils = new ComUtils(this);
-
- QUrl reqUrl(utils->getUrl(ComUtils::GetServiceToken));
- QNetworkRequest request(reqUrl);
- request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
-
- const auto keyId = keyIdsList[ownKeySelectBox->currentIndex()];
-
- qDebug() << "KeyId" << keyIdsList[ownKeySelectBox->currentIndex()];
-
- if (keyId.isEmpty()) {
- QMessageBox::critical(
- this, _("Invalid Operation"),
- _("Own Key can not be None while getting service token."));
- return;
- }
-
- QStringList selectedKeyIds(keyIdsList[ownKeySelectBox->currentIndex()]);
-
- QByteArray keyDataBuf;
- mCtx->exportKeys(&selectedKeyIds, &keyDataBuf);
-
- GpgKey key = mCtx->getKeyRefById(keyId);
-
- if (!key.good) {
- QMessageBox::critical(this, _("Error"), _("Key Not Exists"));
- return;
- }
-
- qDebug() << "keyDataBuf" << keyDataBuf;
-
- /**
- * {
- * "publicKey" : ...
- * "sha": ...
- * "signedFpr": ...
- * "version": ...
- * }
- */
-
- QCryptographicHash shaGen(QCryptographicHash::Sha256);
- shaGen.addData(keyDataBuf);
-
- auto shaStr = shaGen.result().toHex();
-
- auto signFprStr = ComUtils::getSignStringBase64(mCtx, key.fpr, key);
-
- rapidjson::Value pubkey, ver, sha, signFpr;
-
- rapidjson::Document doc;
- doc.SetObject();
-
- pubkey.SetString(keyDataBuf.constData(), keyDataBuf.count());
-
- auto version = qApp->applicationVersion();
- ver.SetString(version.toUtf8().constData(),
- qApp->applicationVersion().count());
-
- sha.SetString(shaStr.constData(), shaStr.count());
- signFpr.SetString(signFprStr.constData(), signFprStr.count());
-
- rapidjson::Document::AllocatorType& allocator = doc.GetAllocator();
-
- doc.AddMember("publicKey", pubkey, allocator);
- doc.AddMember("sha", sha, allocator);
- doc.AddMember("signedFpr", signFpr, allocator);
- doc.AddMember("version", ver, allocator);
-
- rapidjson::StringBuffer sb;
- rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(sb);
- doc.Accept(writer);
-
- QByteArray postData(sb.GetString());
-
- QNetworkReply* reply = utils->getNetworkManager().post(request, postData);
-
- // Show Waiting Dailog
- auto dialog = new WaitingDialog("Getting Token From Server", this);
- dialog->show();
-
- while (reply->isRunning()) {
- QApplication::processEvents();
- }
-
- dialog->close();
-
- if (utils->checkServerReply(reply->readAll().constData())) {
- /**
- * {
- * "serviceToken" : ...
- * "fpr": ...
- * }
- */
-
- if (!utils->checkDataValueStr("serviceToken") ||
- !utils->checkDataValueStr("fpr")) {
- QMessageBox::critical(this, _("Error"),
- _("The communication content with the server does "
- "not meet the requirements"));
- return;
- }
-
- QString serviceTokenTemp = utils->getDataValueStr("serviceToken");
- QString fpr = utils->getDataValueStr("fpr");
- auto key = mCtx->getKeyRefByFpr(fpr);
- if (utils->checkServiceTokenFormat(serviceTokenTemp) && key.good) {
- serviceToken = serviceTokenTemp;
- qDebug() << "Get Service Token" << serviceToken;
- // Auto update settings
- settings.setValue("general/serviceToken", serviceToken);
- serviceTokenLabel->setText(serviceToken);
- QMessageBox::information(this, _("Notice"),
- _("Succeed in getting service token"));
- } else {
- QMessageBox::critical(
- this, _("Error"),
- _("There is a problem with the communication with the server"));
- }
- }
-}
-#endif
-
} // namespace GpgFrontend::UI
diff --git a/src/ui/settings/SettingsGeneral.h b/src/ui/settings/SettingsGeneral.h
index bebe7609..a5e2b8d0 100644
--- a/src/ui/settings/SettingsGeneral.h
+++ b/src/ui/settings/SettingsGeneral.h
@@ -27,6 +27,8 @@
#include "ui/GpgFrontendUI.h"
+class Ui_GeneralSettings;
+
namespace GpgFrontend::UI {
class KeyList;
@@ -41,24 +43,12 @@ class GeneralTab : public QWidget {
void applySettings();
private:
- QCheckBox* saveCheckedKeysCheckBox;
- QCheckBox* importConfirmationCheckBox;
- QCheckBox* longerKeyExpirationDateCheckBox;
+ std::shared_ptr<Ui_GeneralSettings> ui;
#ifdef MULTI_LANG_SUPPORT
- QComboBox* langSelectBox;
QHash<QString, QString> lang;
#endif
-#ifdef SERVER_SUPPORT
- QComboBox* serverSelectBox;
- QComboBox* ownKeySelectBox;
- QPushButton* getServiceTokenButton;
- QLabel* serviceTokenLabel;
- std::string serviceToken;
- std::unordered_map<std::string, std::string> keyIds;
-#endif
-
std::vector<std::string> keyIdsList;
KeyList* mKeyList{};
@@ -70,13 +60,6 @@ class GeneralTab : public QWidget {
void slotLanguageChanged();
#endif
-
-#ifdef SERVER_SUPPORT
-
- void slotOwnKeyIdChanged();
-
-#endif
-
signals:
void signalRestartNeeded(bool needed);
diff --git a/src/ui/settings/SettingsKeyServer.cpp b/src/ui/settings/SettingsKeyServer.cpp
index 1d520e35..0cba7b51 100644
--- a/src/ui/settings/SettingsKeyServer.cpp
+++ b/src/ui/settings/SettingsKeyServer.cpp
@@ -25,6 +25,7 @@
#include "SettingsKeyServer.h"
#include "GlobalSettingStation.h"
+#include "ui/function/TestListedKeyServerThread.h"
#include "ui_KeyServerSettings.h"
namespace GpgFrontend::UI {
@@ -95,6 +96,7 @@ KeyserverTab::KeyserverTab(QWidget* parent)
const auto item = ui->keyServerListTable->item(i, 1);
if (!item->isSelected()) continue;
this->keyServerStrList.removeAt(i);
+ break;
}
this->refreshTable();
});
@@ -231,35 +233,71 @@ void KeyserverTab::refreshTable() {
}
void KeyserverTab::slotTestListedKeyServer() {
- ui->keyServerListTable->blockSignals(true);
auto timeout =
QInputDialog::getInt(this, _("Set TCP Timeout"), tr("timeout(ms): "),
QLineEdit::Normal, 500, 2000);
+ QStringList urls;
const auto row_size = ui->keyServerListTable->rowCount();
for (int i = 0; i < row_size; i++) {
- const auto keyserver = ui->keyServerListTable->item(i, 1)->text();
- const auto status = ui->keyServerListTable->item(i, 3);
- if (keyserver == nullptr || status == nullptr) continue;
-
- auto key_url = QUrl{keyserver};
-
- LOG(INFO) << "key domain" << key_url.host().toStdString();
-
- QTcpSocket socket(this);
- socket.abort();
- socket.connectToHost(key_url.host(), 80);
- if (socket.waitForConnected(timeout)) {
- status->setText(_("Reachable"));
- status->setForeground(QBrush(QColor::fromRgb(0, 255, 0)));
- } else {
- status->setText(_("Not Reachable"));
- status->setForeground(QBrush(QColor::fromRgb(255, 0, 0)));
- }
- socket.close();
+ const auto keyserver_url = ui->keyServerListTable->item(i, 1)->text();
+ urls.push_back(keyserver_url);
}
- ui->keyServerListTable->blockSignals(false);
+
+ auto thread = new TestListedKeyServerThread(urls, timeout, this);
+ connect(thread,
+ &GpgFrontend::UI::TestListedKeyServerThread::
+ signalKeyServerListTestResult,
+ this, [=](const QStringList& result) {
+ const auto row_size = ui->keyServerListTable->rowCount();
+ if (result.size() != row_size) return;
+ ui->keyServerListTable->blockSignals(true);
+ for (int i = 0; i < row_size; i++) {
+ const auto status = result[i];
+ auto status_iem = ui->keyServerListTable->item(i, 3);
+ if (status == "Reachable") {
+ status_iem->setText(_("Reachable"));
+ status_iem->setForeground(QBrush(QColor::fromRgb(0, 255, 0)));
+ } else {
+ status_iem->setText(_("Not Reachable"));
+ status_iem->setForeground(QBrush(QColor::fromRgb(255, 0, 0)));
+ }
+ }
+ ui->keyServerListTable->blockSignals(false);
+ });
+ connect(thread, &QThread::finished, thread, &QThread::deleteLater);
+
+ // Waiting Dialog
+ auto* waiting_dialog = new QProgressDialog(this);
+ waiting_dialog->setMaximum(0);
+ waiting_dialog->setMinimum(0);
+ auto waiting_dialog_label =
+ new QLabel(QString(_("Test Key Server Connection...")) + "<br /><br />" +
+ _("This test only tests the network connectivity of the key "
+ "server. Passing the test does not mean that the key server "
+ "is functionally available."));
+ waiting_dialog_label->setWordWrap(true);
+ waiting_dialog->setLabel(waiting_dialog_label);
+ waiting_dialog->resize(420, 120);
+ connect(thread, &QThread::finished, [=]() {
+ waiting_dialog->finished(0);
+ waiting_dialog->deleteLater();
+ });
+ connect(waiting_dialog, &QProgressDialog::canceled, [=]() {
+ LOG(INFO) << "cancel clicked";
+ if (thread->isRunning()) thread->terminate();
+ });
+
+ // Show Waiting Dialog
+ waiting_dialog->show();
+ waiting_dialog->setFocus();
+
+ thread->start();
+ QEventLoop loop;
+ connect(thread, &QThread::finished, &loop, &QEventLoop::quit);
+ loop.exec();
}
+
void KeyserverTab::contextMenuEvent(QContextMenuEvent* event) {
QWidget::contextMenuEvent(event);
if (ui->keyServerListTable->selectedItems().length() > 0) {
diff --git a/src/ui/settings/SettingsNetwork.cpp b/src/ui/settings/SettingsNetwork.cpp
new file mode 100644
index 00000000..c457c1a0
--- /dev/null
+++ b/src/ui/settings/SettingsNetwork.cpp
@@ -0,0 +1,334 @@
+/**
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "SettingsNetwork.h"
+
+#include "ui/function/ProxyConnectionTestThread.h"
+#include "ui/settings//GlobalSettingStation.h"
+#include "ui_NetworkSettings.h"
+
+GpgFrontend::UI::NetworkTab::NetworkTab(QWidget *parent)
+ : QWidget(parent), ui(std::make_shared<Ui_NetworkSettings>()) {
+ ui->setupUi(this);
+
+ connect(ui->enableProxyCheckBox, &QCheckBox::stateChanged, this,
+ [=](int state) { switch_ui_enabled(state == Qt::Checked); });
+
+ connect(
+ ui->proxyTypeComboBox, &QComboBox::currentTextChanged, this,
+ [=](const QString &current_text) { switch_ui_proxy_type(current_text); });
+
+ connect(ui->checkProxyConnectionButton, &QPushButton::clicked, this,
+ &NetworkTab::slotTestProxyConnectionResult);
+
+ ui->proxyGroupBox->setTitle(_("Proxy"));
+ ui->capabilityGroupBox->setTitle(_("Network Capability"));
+ ui->operationsGroupBox->setTitle(_("Operations"));
+
+ ui->enableProxyCheckBox->setText(_("Enable Proxy"));
+ ui->proxyServerPortLabel->setText(_("Port"));
+
+ ui->proxyServerAddressLabel->setText(_("Host Address"));
+ ui->proxyServerPortLabel->setText(_("Port"));
+ ui->proxyTypeLabel->setText(_("Proxy Type"));
+ ui->usernameLabel->setText(_("Username"));
+ ui->passwordLabel->setText(_("Password"));
+
+ ui->forbidALLCheckBox->setText(_("Forbid all network connection."));
+ ui->forbidALLCheckBox->setDisabled(true);
+
+ ui->prohibitUpdateCheck->setText(
+ _("Prohibit checking for version updates when the program starts."));
+ ui->checkProxyConnectionButton->setText(_("Check Proxy Connection"));
+
+ setSettings();
+}
+
+void GpgFrontend::UI::NetworkTab::setSettings() {
+ auto &settings = GlobalSettingStation::GetInstance().GetUISettings();
+
+ try {
+ std::string proxy_host = settings.lookup("proxy.proxy_host");
+ ui->proxyServerAddressEdit->setText(proxy_host.c_str());
+ } catch (...) {
+ LOG(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");
+ }
+
+ try {
+ std::string std_password = settings.lookup("proxy.password");
+ ui->passwordEdit->setText(std_password.c_str());
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("password");
+ }
+
+ try {
+ int port = settings.lookup("proxy.port");
+ ui->portSpin->setValue(port);
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("port");
+ }
+
+ ui->proxyTypeComboBox->setCurrentText("HTTP");
+ try {
+ std::string proxy_type = settings.lookup("proxy.proxy_type");
+ ui->proxyTypeComboBox->setCurrentText(proxy_type.c_str());
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("proxy_type");
+ }
+ switch_ui_proxy_type(ui->proxyTypeComboBox->currentText());
+
+ ui->enableProxyCheckBox->setCheckState(Qt::Unchecked);
+ try {
+ bool proxy_enable = settings.lookup("proxy.enable");
+ if (proxy_enable)
+ ui->enableProxyCheckBox->setCheckState(Qt::Checked);
+ else
+ ui->enableProxyCheckBox->setCheckState(Qt::Unchecked);
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("proxy_enable");
+ }
+
+ {
+ auto state = ui->enableProxyCheckBox->checkState();
+ switch_ui_enabled(state == Qt::Checked);
+ }
+
+ ui->forbidALLCheckBox->setCheckState(Qt::Unchecked);
+ try {
+ bool forbid_all_connection =
+ settings.lookup("network.forbid_all_connection");
+ if (forbid_all_connection)
+ ui->forbidALLCheckBox->setCheckState(Qt::Checked);
+ else
+ ui->forbidALLCheckBox->setCheckState(Qt::Unchecked);
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("forbid_all_connection");
+ }
+
+ ui->prohibitUpdateCheck->setCheckState(Qt::Unchecked);
+ try {
+ bool prohibit_update_checking =
+ settings.lookup("network.prohibit_update_checking");
+ if (prohibit_update_checking)
+ ui->prohibitUpdateCheck->setCheckState(Qt::Checked);
+ else
+ ui->prohibitUpdateCheck->setCheckState(Qt::Unchecked);
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("prohibit_update_checking");
+ }
+}
+
+void GpgFrontend::UI::NetworkTab::applySettings() {
+ LOG(INFO) << "called";
+
+ auto &settings =
+ GpgFrontend::UI::GlobalSettingStation::GetInstance().GetUISettings();
+
+ if (!settings.exists("proxy") ||
+ settings.lookup("proxy").getType() != libconfig::Setting::TypeGroup)
+ settings.add("proxy", libconfig::Setting::TypeGroup);
+
+ auto &proxy = settings["proxy"];
+
+ if (!proxy.exists("proxy_host"))
+ proxy.add("proxy_host", libconfig::Setting::TypeString) =
+ ui->proxyServerAddressEdit->text().toStdString();
+ else {
+ proxy["proxy_host"] = ui->proxyServerAddressEdit->text().toStdString();
+ }
+
+ if (!proxy.exists("username"))
+ proxy.add("username", libconfig::Setting::TypeString) =
+ ui->usernameEdit->text().toStdString();
+ else {
+ proxy["username"] = ui->usernameEdit->text().toStdString();
+ }
+
+ if (!proxy.exists("password"))
+ proxy.add("password", libconfig::Setting::TypeString) =
+ ui->passwordEdit->text().toStdString();
+ else {
+ proxy["password"] = ui->passwordEdit->text().toStdString();
+ }
+
+ if (!proxy.exists("port"))
+ proxy.add("port", libconfig::Setting::TypeInt) = ui->portSpin->value();
+ else {
+ proxy["port"] = ui->portSpin->value();
+ }
+
+ if (!proxy.exists("proxy_type"))
+ proxy.add("proxy_type", libconfig::Setting::TypeString) =
+ ui->proxyTypeComboBox->currentText().toStdString();
+ else {
+ proxy["proxy_type"] = ui->proxyTypeComboBox->currentText().toStdString();
+ }
+
+ if (!proxy.exists("enable"))
+ proxy.add("enable", libconfig::Setting::TypeBoolean) =
+ ui->enableProxyCheckBox->isChecked();
+ else {
+ proxy["enable"] = ui->enableProxyCheckBox->isChecked();
+ }
+
+ if (!settings.exists("network") ||
+ settings.lookup("network").getType() != libconfig::Setting::TypeGroup)
+ settings.add("network", libconfig::Setting::TypeGroup);
+
+ auto &network = settings["network"];
+
+ if (!network.exists("forbid_all_connection"))
+ network.add("forbid_all_connection", libconfig::Setting::TypeBoolean) =
+ ui->forbidALLCheckBox->isChecked();
+ else {
+ network["forbid_all_connection"] = ui->forbidALLCheckBox->isChecked();
+ }
+
+ if (!network.exists("prohibit_update_checking"))
+ network.add("prohibit_update_checking", libconfig::Setting::TypeBoolean) =
+ ui->prohibitUpdateCheck->isChecked();
+ else {
+ network["prohibit_update_checking"] = ui->prohibitUpdateCheck->isChecked();
+ }
+
+ apply_proxy_settings();
+
+ LOG(INFO) << "done";
+}
+
+void GpgFrontend::UI::NetworkTab::slotTestProxyConnectionResult() {
+ apply_proxy_settings();
+
+ bool ok;
+ auto url = QInputDialog::getText(this, _("Test Server Url Accessibility"),
+ tr("Server Url"), QLineEdit::Normal,
+ "https://", &ok);
+ if (ok && !url.isEmpty()) {
+ auto thread = new ProxyConnectionTestThread(url, 800, this);
+ connect(thread,
+ &GpgFrontend::UI::ProxyConnectionTestThread::
+ signalProxyConnectionTestResult,
+ this, [=](const QString &result) {
+ if (result == "Reachable") {
+ QMessageBox::information(this, _("Success"),
+ _("Successfully connect to the target "
+ "server through the proxy server."));
+ } else {
+ QMessageBox::critical(
+ this, _("Failed"),
+ _("Unable to connect to the target server through the "
+ "proxy server. Proxy settings may be invalid."));
+ }
+ });
+ connect(thread, &QThread::finished, thread, &QThread::deleteLater);
+
+ // Waiting Dialog
+ auto *waiting_dialog = new QProgressDialog(this);
+ waiting_dialog->setMaximum(0);
+ waiting_dialog->setMinimum(0);
+ auto waiting_dialog_label = new QLabel(
+ QString(_("Test Proxy Server Connection...")) + "<br /><br />" +
+ _("Is using your proxy settings to access the url. Note that this test "
+ "operation will apply your proxy settings to the entire software."));
+ waiting_dialog_label->setWordWrap(true);
+ waiting_dialog->setLabel(waiting_dialog_label);
+ waiting_dialog->resize(420, 120);
+ connect(thread, &QThread::finished, [=]() {
+ waiting_dialog->finished(0);
+ waiting_dialog->deleteLater();
+ });
+ connect(waiting_dialog, &QProgressDialog::canceled, [=]() {
+ LOG(INFO) << "cancel clicked";
+ if (thread->isRunning()) thread->terminate();
+ });
+
+ // Show Waiting Dialog
+ waiting_dialog->show();
+ waiting_dialog->setFocus();
+
+ thread->start();
+ QEventLoop loop;
+ connect(thread, &QThread::finished, &loop, &QEventLoop::quit);
+ loop.exec();
+ }
+}
+
+void GpgFrontend::UI::NetworkTab::apply_proxy_settings() {
+ // apply settings
+ QNetworkProxy _proxy;
+ if (ui->enableProxyCheckBox->isChecked() &&
+ proxy_type_ != QNetworkProxy::DefaultProxy) {
+ _proxy.setType(proxy_type_);
+ _proxy.setHostName(ui->proxyServerAddressEdit->text());
+ _proxy.setPort(ui->portSpin->value());
+ if (!ui->usernameEdit->text().isEmpty()) {
+ _proxy.setUser(ui->usernameEdit->text());
+ _proxy.setPassword(ui->passwordEdit->text());
+ }
+ } else {
+ _proxy.setType(proxy_type_);
+ }
+
+ QNetworkProxy::setApplicationProxy(_proxy);
+}
+
+void GpgFrontend::UI::NetworkTab::switch_ui_enabled(bool enabled) {
+ ui->proxyServerAddressEdit->setDisabled(!enabled);
+ ui->portSpin->setDisabled(!enabled);
+ ui->proxyTypeComboBox->setDisabled(!enabled);
+ ui->usernameEdit->setDisabled(!enabled);
+ ui->passwordEdit->setDisabled(!enabled);
+ ui->checkProxyConnectionButton->setDisabled(!enabled);
+ if (!enabled) proxy_type_ = QNetworkProxy::NoProxy;
+}
+
+void GpgFrontend::UI::NetworkTab::switch_ui_proxy_type(
+ const QString &type_text) {
+ if (type_text == "HTTP") {
+ ui->proxyServerAddressEdit->setDisabled(false);
+ ui->portSpin->setDisabled(false);
+ ui->usernameEdit->setDisabled(false);
+ ui->passwordEdit->setDisabled(false);
+ proxy_type_ = QNetworkProxy::HttpProxy;
+ } else if (type_text == "Socks5") {
+ ui->proxyServerAddressEdit->setDisabled(false);
+ ui->portSpin->setDisabled(false);
+ ui->usernameEdit->setDisabled(false);
+ ui->passwordEdit->setDisabled(false);
+ proxy_type_ = QNetworkProxy::Socks5Proxy;
+ } else {
+ ui->proxyServerAddressEdit->setDisabled(true);
+ ui->portSpin->setDisabled(true);
+ ui->usernameEdit->setDisabled(true);
+ ui->passwordEdit->setDisabled(true);
+ proxy_type_ = QNetworkProxy::DefaultProxy;
+ }
+}
diff --git a/src/ui/settings/SettingsNetwork.h b/src/ui/settings/SettingsNetwork.h
new file mode 100644
index 00000000..cf136604
--- /dev/null
+++ b/src/ui/settings/SettingsNetwork.h
@@ -0,0 +1,57 @@
+/**
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef GPGFRONTEND_SETTINGSNETWORK_H
+#define GPGFRONTEND_SETTINGSNETWORK_H
+
+#include "ui/GpgFrontendUI.h"
+
+class Ui_NetworkSettings;
+
+namespace GpgFrontend::UI {
+class NetworkTab : public QWidget {
+ Q_OBJECT
+
+ public:
+ explicit NetworkTab(QWidget* parent = nullptr);
+
+ void setSettings();
+
+ void applySettings();
+
+ private slots:
+
+ void slotTestProxyConnectionResult();
+
+ private:
+ std::shared_ptr<Ui_NetworkSettings> ui;
+ QNetworkProxy::ProxyType proxy_type_ = QNetworkProxy::HttpProxy;
+
+ void apply_proxy_settings();
+ void switch_ui_enabled(bool enabled);
+ void switch_ui_proxy_type(const QString& type_text);
+};
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_SETTINGSNETWORK_H
diff --git a/src/ui/settings/SettingsSendMail.cpp b/src/ui/settings/SettingsSendMail.cpp
index 733ed82f..f0acb10d 100644
--- a/src/ui/settings/SettingsSendMail.cpp
+++ b/src/ui/settings/SettingsSendMail.cpp
@@ -28,6 +28,8 @@
#include "smtp/SmtpMime"
#endif
+#include "ui/function/SMTPSendMailThread.h"
+#include "ui/function/SMTPTestThread.h"
#include "ui/settings/GlobalSettingStation.h"
#include "ui_SendMailSettings.h"
@@ -37,18 +39,8 @@ SendMailTab::SendMailTab(QWidget* parent)
: QWidget(parent), ui(std::make_shared<Ui_SendMailSettings>()) {
ui->setupUi(this);
- connect(ui->enableCheckBox, &QCheckBox::stateChanged, this, [=](int state) {
- ui->smtpServerAddressEdit->setDisabled(state != Qt::Checked);
- ui->portSpin->setDisabled(state != Qt::Checked);
- ui->connextionSecurityComboBox->setDisabled(state != Qt::Checked);
-
- ui->identityCheckBox->setDisabled(state != Qt::Checked);
- ui->usernameEdit->setDisabled(state != Qt::Checked);
- ui->passwordEdit->setDisabled(state != Qt::Checked);
-
- ui->defaultSenderEmailEdit->setDisabled(state != Qt::Checked);
- ui->checkConnectionButton->setDisabled(state != Qt::Checked);
- });
+ connect(ui->enableCheckBox, &QCheckBox::stateChanged, this,
+ [=](int state) { switch_ui_enabled(state == Qt::Checked); });
#ifdef SMTP_SUPPORT
connect(ui->checkConnectionButton, &QPushButton::clicked, this,
@@ -57,10 +49,19 @@ SendMailTab::SendMailTab(QWidget* parent)
&SendMailTab::slotSendTestMail);
#endif
- connect(ui->identityCheckBox, &QCheckBox::stateChanged, this, [=](int state) {
- ui->usernameEdit->setDisabled(state != Qt::Checked);
- ui->passwordEdit->setDisabled(state != Qt::Checked);
- });
+ connect(ui->identityCheckBox, &QCheckBox::stateChanged, this,
+ [=](int state) { switch_ui_identity_enabled(state == Qt::Checked); });
+
+ connect(ui->connextionSecurityComboBox, &QComboBox::currentTextChanged, this,
+ [=](const QString& current_text) {
+ if (current_text == "SSL") {
+ connection_type_ = SmtpClient::ConnectionType::SslConnection;
+ } else if (current_text == "TLS" || current_text == "STARTTLS") {
+ connection_type_ = SmtpClient::ConnectionType::TlsConnection;
+ } else {
+ connection_type_ = SmtpClient::ConnectionType::TcpConnection;
+ }
+ });
ui->generalGroupBox->setTitle(_("General"));
ui->identityGroupBox->setTitle(_("Identity Information"));
@@ -79,6 +80,8 @@ SendMailTab::SendMailTab(QWidget* parent)
ui->senderLabel->setText(_("Default Sender Email"));
ui->checkConnectionButton->setText(_("Check Connection"));
ui->senTestMailButton->setText(_("Send Test Email"));
+ ui->gpgkeyIdLabel->setText(_("Default Sender GPG Key ID"));
+
ui->tipsLabel->setText(
_("Tips: It is recommended that you build your own mail server or use "
"a trusted mail server. If you don't know the detailed configuration "
@@ -138,7 +141,16 @@ void SendMailTab::setSettings() {
} catch (...) {
LOG(ERROR) << _("Setting Operation Error") << _("default_sender");
}
-
+
+ try {
+ std::string default_sender_gpg_key_id =
+ settings.lookup("smtp.default_sender_gpg_key_id");
+ ui->gpgKeyIDEdit->setText(default_sender_gpg_key_id.c_str());
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error")
+ << _("default_sender_gpg_key_id");
+ }
+
ui->identityCheckBox->setCheckState(Qt::Unchecked);
try {
bool identity_enable = settings.lookup("smtp.identity_enable");
@@ -149,6 +161,11 @@ void SendMailTab::setSettings() {
} catch (...) {
LOG(ERROR) << _("Setting Operation Error") << _("identity_enable");
}
+
+ {
+ auto state = ui->identityCheckBox->checkState();
+ switch_ui_identity_enabled(state == Qt::Checked);
+ }
ui->enableCheckBox->setCheckState(Qt::Unchecked);
try {
@@ -160,6 +177,11 @@ void SendMailTab::setSettings() {
} catch (...) {
LOG(ERROR) << _("Setting Operation Error") << _("save_key_checked");
}
+
+ {
+ auto state = ui->enableCheckBox->checkState();
+ switch_ui_enabled(state == Qt::Checked);
+ }
}
void SendMailTab::applySettings() {
@@ -214,6 +236,13 @@ void SendMailTab::applySettings() {
smtp["default_sender"] = ui->defaultSenderEmailEdit->text().toStdString();
}
+ if (!smtp.exists("default_sender_gpg_key_id"))
+ smtp.add("default_sender_gpg_key_id", libconfig::Setting::TypeString) =
+ ui->gpgKeyIDEdit->text().toStdString();
+ else {
+ smtp["default_sender_gpg_key_id"] = ui->gpgKeyIDEdit->text().toStdString();
+ }
+
if (!smtp.exists("identity_enable"))
smtp.add("identity_enable", libconfig::Setting::TypeBoolean) =
ui->identityCheckBox->isChecked();
@@ -231,105 +260,144 @@ void SendMailTab::applySettings() {
#ifdef SMTP_SUPPORT
void SendMailTab::slotCheckConnection() {
- SmtpClient::ConnectionType connectionType;
- const auto selectedConnType = ui->connextionSecurityComboBox->currentText();
- if (selectedConnType == "SSL") {
- connectionType = SmtpClient::ConnectionType::SslConnection;
- } else if (selectedConnType == "TLS" || selectedConnType == "STARTTLS") {
- connectionType = SmtpClient::ConnectionType::TlsConnection;
- } else {
- connectionType = SmtpClient::ConnectionType::TcpConnection;
- }
-
- SmtpClient smtp(ui->smtpServerAddressEdit->text(), ui->portSpin->value(),
- connectionType);
-
- if (ui->identityCheckBox->isChecked()) {
- smtp.setUser(ui->usernameEdit->text());
- smtp.setPassword(ui->passwordEdit->text());
- }
+ auto host = ui->smtpServerAddressEdit->text().toStdString();
+ auto port = ui->portSpin->value();
+ auto connection_type = connection_type_;
+ bool identity_needed = ui->identityCheckBox->isChecked();
+ auto username = ui->usernameEdit->text().toStdString();
+ auto password = ui->passwordEdit->text().toStdString();
+
+ auto thread = new SMTPTestThread(host, port, connection_type, identity_needed,
+ username, password);
+
+ // Waiting Dialog
+ auto* waiting_dialog = new QProgressDialog(this);
+ waiting_dialog->setMaximum(0);
+ waiting_dialog->setMinimum(0);
+ auto waiting_dialog_label =
+ new QLabel(QString(_("Test SMTP Connection...")) + "<br /><br />" +
+ _("If the process does not end for a long time, please check "
+ "again whether your SMTP server configuration is correct."));
+ waiting_dialog_label->setWordWrap(true);
+ waiting_dialog->setLabel(waiting_dialog_label);
+ waiting_dialog->resize(420, 120);
+ connect(thread, &SMTPTestThread::signalSMTPTestResult, this,
+ &SendMailTab::slotTestSMTPConnectionResult);
+ connect(thread, &QThread::finished, [=]() {
+ waiting_dialog->finished(0);
+ waiting_dialog->deleteLater();
+ });
+ connect(waiting_dialog, &QProgressDialog::canceled, [=]() {
+ LOG(INFO) << "cancel clicked";
+ if (thread->isRunning()) thread->terminate();
+ });
- if (!smtp.connectToHost()) {
- QMessageBox::critical(this, _("Fail"), _("Fail to Connect SMTP Server"));
- ui->senTestMailButton->setDisabled(true);
- return;
- }
- if (!smtp.login()) {
- QMessageBox::critical(this, _("Fail"), _("Fail to Login"));
- ui->senTestMailButton->setDisabled(true);
- return;
- }
+ // Show Waiting Dialog
+ waiting_dialog->show();
+ waiting_dialog->setFocus();
- QMessageBox::information(this, _("Success"),
- _("Succeed in connecting and login"));
- ui->senTestMailButton->setDisabled(false);
+ thread->start();
+ QEventLoop loop;
+ connect(thread, &QThread::finished, &loop, &QEventLoop::quit);
+ loop.exec();
}
#endif
#ifdef SMTP_SUPPORT
void SendMailTab::slotSendTestMail() {
- if (ui->defaultSenderEmailEdit->text().isEmpty()) {
- QMessageBox::critical(this, _("Fail"), _("Given a default sender first"));
- return;
- }
-
- SmtpClient::ConnectionType connectionType;
- const auto selectedConnType = ui->connextionSecurityComboBox->currentText();
- if (selectedConnType == "SSL") {
- connectionType = SmtpClient::ConnectionType::SslConnection;
- } else if (selectedConnType == "TLS" || selectedConnType == "STARTTLS") {
- connectionType = SmtpClient::ConnectionType::TlsConnection;
- } else {
- connectionType = SmtpClient::ConnectionType::TcpConnection;
- }
-
- SmtpClient smtp(ui->smtpServerAddressEdit->text(), ui->portSpin->value(),
- connectionType);
+ auto host = ui->smtpServerAddressEdit->text().toStdString();
+ auto port = ui->portSpin->value();
+ auto connection_type = connection_type_;
+ bool identity_needed = ui->identityCheckBox->isChecked();
+ auto username = ui->usernameEdit->text().toStdString();
+ auto password = ui->passwordEdit->text().toStdString();
+ auto sender_address = ui->defaultSenderEmailEdit->text();
- if (ui->identityCheckBox->isChecked()) {
- smtp.setUser(ui->usernameEdit->text());
- smtp.setPassword(ui->passwordEdit->text());
- }
+ auto thread = new SMTPSendMailThread(host, port, connection_type,
+ identity_needed, username, password);
+
+ // Waiting Dialog
+ auto* waiting_dialog = new QProgressDialog(this);
+ waiting_dialog->setMaximum(0);
+ waiting_dialog->setMinimum(0);
+ auto waiting_dialog_label =
+ new QLabel(QString(_("Test SMTP Send Mail Ability...")) + "<br /><br />" +
+ _("If the process does not end for a long time, please check "
+ "again whether your SMTP server configuration is correct."));
+ waiting_dialog_label->setWordWrap(true);
+ waiting_dialog->setLabel(waiting_dialog_label);
+ waiting_dialog->resize(420, 120);
+ connect(thread, &SMTPSendMailThread::signalSMTPResult, this,
+ &SendMailTab::slotTestSMTPConnectionResult);
+ connect(thread, &QThread::finished, [=]() {
+ waiting_dialog->finished(0);
+ waiting_dialog->deleteLater();
+ });
+ connect(waiting_dialog, &QProgressDialog::canceled, [=]() {
+ LOG(INFO) << "cancel clicked";
+ if (thread->isRunning()) thread->terminate();
+ });
- MimeMessage message;
+ thread->setSender(sender_address);
+ thread->setRecipient(sender_address);
+ thread->setSubject(_("Test Email from GpgFrontend"));
+ thread->addTextContent(
+ _("Hello, this is a test email from GpgFrontend. If you receive this "
+ "email, it means that you have configured the correct SMTP server "
+ "parameters."));
+
+ // Show Waiting Dialog
+ waiting_dialog->show();
+ waiting_dialog->setFocus();
+
+ thread->start();
+ QEventLoop loop;
+ connect(thread, &QThread::finished, &loop, &QEventLoop::quit);
+ loop.exec();
+}
- auto sender_address = ui->defaultSenderEmailEdit->text();
- message.setSender(new EmailAddress(sender_address));
- message.addRecipient(new EmailAddress(sender_address));
- message.setSubject(_("Test Email from GpgFrontend"));
-
- MimeText text;
- text.setText(_("Hello, this is a test email from GpgFrontend."));
- // Now add it to the mail
- message.addPart(&text);
- // Now we can send the mail
- if (!smtp.connectToHost()) {
- LOG(INFO) << "Connect to SMTP Server Failed";
- QMessageBox::critical(this, _("Fail"), _("Fail to Connect SMTP Server"));
+void SendMailTab::slotTestSMTPConnectionResult(const QString& result) {
+ if (result == "Fail to connect SMTP server") {
+ QMessageBox::critical(this, _("Fail"), _("Fail to Connect SMTP Server."));
ui->senTestMailButton->setDisabled(true);
- return;
- }
- if (!smtp.login()) {
- LOG(INFO) << "Login to SMTP Server Failed";
- QMessageBox::critical(this, _("Fail"), _("Fail to Login into SMTP Server"));
+ } else if (result == "Fail to login") {
+ QMessageBox::critical(this, _("Fail"), _("Fail to Login."));
ui->senTestMailButton->setDisabled(true);
- return;
- }
- if (!smtp.sendMail(message)) {
- LOG(INFO) << "Send Mail to SMTP Server Failed";
- QMessageBox::critical(
- this, _("Fail"),
- _("Fail to send a test email to the SMTP Server, please "
- "recheck your configuration."));
+ } else if (result == "Fail to send mail") {
+ QMessageBox::critical(this, _("Fail"), _("Fail to Login."));
+ ui->senTestMailButton->setDisabled(true);
+ } else if (result == "Succeed in testing connection") {
+ QMessageBox::information(this, _("Success"),
+ _("Succeed in connecting and login"));
+ ui->senTestMailButton->setDisabled(false);
+ } else if (result == "Succeed in sending a test email") {
+ QMessageBox::information(
+ this, _("Success"),
+ _("Succeed in sending a test email to the SMTP Server"));
+ ui->senTestMailButton->setDisabled(false);
+ } else {
+ QMessageBox::critical(this, _("Fail"), _("Unknown error."));
ui->senTestMailButton->setDisabled(true);
- return;
}
- smtp.quit();
+}
+
+void SendMailTab::switch_ui_enabled(bool enabled) {
+ ui->smtpServerAddressEdit->setDisabled(!enabled);
+ ui->portSpin->setDisabled(!enabled);
+ ui->connextionSecurityComboBox->setDisabled(!enabled);
+
+ ui->identityCheckBox->setDisabled(!enabled);
+ ui->usernameEdit->setDisabled(!enabled);
+ ui->passwordEdit->setDisabled(!enabled);
+
+ ui->defaultSenderEmailEdit->setDisabled(!enabled);
+ ui->gpgKeyIDEdit->setDisabled(!enabled);
+ ui->checkConnectionButton->setDisabled(!enabled);
+}
- // Close after sending email
- QMessageBox::information(
- this, _("Success"),
- _("Succeed in sending a test email to the SMTP Server"));
+void SendMailTab::switch_ui_identity_enabled(bool enabled) {
+ ui->usernameEdit->setDisabled(!enabled);
+ ui->passwordEdit->setDisabled(!enabled);
}
#endif
diff --git a/src/ui/settings/SettingsSendMail.h b/src/ui/settings/SettingsSendMail.h
index cc733f28..c866fa5f 100644
--- a/src/ui/settings/SettingsSendMail.h
+++ b/src/ui/settings/SettingsSendMail.h
@@ -1,10 +1,31 @@
-//
-// Created by saturneric on 2021/11/28.
-//
+/**
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
#ifndef GPGFRONTEND_SETTINGSSENDMAIL_H
#define GPGFRONTEND_SETTINGSSENDMAIL_H
+#include "smtp/SmtpMime"
#include "ui/GpgFrontendUI.h"
class Ui_SendMailSettings;
@@ -22,6 +43,8 @@ class SendMailTab : public QWidget {
private slots:
+ void slotTestSMTPConnectionResult(const QString& result);
+
#ifdef SMTP_SUPPORT
void slotCheckConnection();
@@ -32,6 +55,12 @@ class SendMailTab : public QWidget {
std::shared_ptr<Ui_SendMailSettings> ui;
QRegularExpression re_email{
R"((?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\]))"};
+ SmtpClient::ConnectionType connection_type_ =
+ SmtpClient::ConnectionType::TcpConnection;
+
+ void switch_ui_enabled(bool enabled);
+
+ void switch_ui_identity_enabled(bool enabled);
signals:
diff --git a/src/ui/smtp/EmailListEditor.cpp b/src/ui/smtp/EmailListEditor.cpp
new file mode 100644
index 00000000..49399f11
--- /dev/null
+++ b/src/ui/smtp/EmailListEditor.cpp
@@ -0,0 +1,102 @@
+/**
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "EmailListEditor.h"
+
+#include "ui_EmailListEditor.h"
+
+GpgFrontend::UI::EmailListEditor::EmailListEditor(const QString& email_list,
+ QWidget* parent)
+ : QDialog(parent), ui(std::make_shared<Ui_EmailListEditorDialog>()) {
+ ui->setupUi(this);
+
+ QStringList email_string_list = email_list.split(';');
+
+ if (!email_string_list.isEmpty()) {
+ for (const auto& recipient : email_string_list) {
+ auto _recipient = recipient.trimmed();
+ if (check_email_address(_recipient)) {
+ auto item = new QListWidgetItem(_recipient);
+ ui->emaillistWidget->addItem(item);
+ item->setFlags(item->flags() | Qt::ItemIsEditable);
+ }
+ }
+ }
+
+ connect(ui->addEmailAddressButton, &QPushButton::clicked, this, [=]() {
+ auto item = new QListWidgetItem("new email address");
+ ui->emaillistWidget->addItem(item);
+ item->setFlags(item->flags() | Qt::ItemIsEditable);
+ });
+
+ connect(
+ ui->actionDelete_Selected_Email_Address, &QAction::triggered, this,
+ [=]() {
+ const auto row_size = ui->emaillistWidget->count();
+ for (int i = 0; i < row_size; i++) {
+ auto item = ui->emaillistWidget->item(i);
+ if (!item->isSelected()) continue;
+ delete ui->emaillistWidget->takeItem(ui->emaillistWidget->row(item));
+ break;
+ }
+ });
+
+ ui->titleLabel->setText(_("Email List:"));
+ ui->tipsLabel->setText(
+ _("Tips: You can double-click the email address in the edit list, or "
+ "click the email to pop up the option menu."));
+ ui->addEmailAddressButton->setText(_("Add An Email Address"));
+ this->setWindowTitle(_("Email List Editor"));
+ ui->actionDelete_Selected_Email_Address->setText(_("Delete"));
+
+ popupMenu = new QMenu(this);
+ popupMenu->addAction(ui->actionDelete_Selected_Email_Address);
+
+ this->exec();
+}
+
+bool GpgFrontend::UI::EmailListEditor::check_email_address(
+ const QString& email_address) {
+ return re_email.match(email_address).hasMatch();
+}
+
+QString GpgFrontend::UI::EmailListEditor::getEmailList() {
+ QString email_list;
+ for (int i = 0; i < ui->emaillistWidget->count(); ++i) {
+ QListWidgetItem* item = ui->emaillistWidget->item(i);
+ if (check_email_address(item->text())) {
+ email_list.append(item->text());
+ email_list.append("; ");
+ }
+ }
+ return email_list;
+}
+
+void GpgFrontend::UI::EmailListEditor::contextMenuEvent(
+ QContextMenuEvent* event) {
+ QWidget::contextMenuEvent(event);
+ if (ui->emaillistWidget->selectedItems().length() > 0) {
+ popupMenu->exec(event->globalPos());
+ }
+}
diff --git a/src/ui/smtp/EmailListEditor.h b/src/ui/smtp/EmailListEditor.h
new file mode 100644
index 00000000..d4e476a4
--- /dev/null
+++ b/src/ui/smtp/EmailListEditor.h
@@ -0,0 +1,54 @@
+/**
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef GPGFRONTEND_EMAILLISTEDITOR_H
+#define GPGFRONTEND_EMAILLISTEDITOR_H
+
+#include "GpgFrontendUI.h"
+
+class Ui_EmailListEditorDialog;
+
+namespace GpgFrontend::UI {
+class EmailListEditor : public QDialog {
+ Q_OBJECT
+
+ public:
+ explicit EmailListEditor(const QString& email_list, QWidget* parent);
+ QString getEmailList();
+
+ private:
+ std::shared_ptr<Ui_EmailListEditorDialog> ui;
+ QMenu* popupMenu{};
+
+ QRegularExpression re_email{
+ R"((?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\]))"};
+
+ bool check_email_address(const QString& email_address);
+
+ protected:
+ void contextMenuEvent(QContextMenuEvent* event) override;
+};
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_EMAILLISTEDITOR_H
diff --git a/src/ui/smtp/RecipientsPicker.cpp b/src/ui/smtp/RecipientsPicker.cpp
new file mode 100644
index 00000000..eaaa683a
--- /dev/null
+++ b/src/ui/smtp/RecipientsPicker.cpp
@@ -0,0 +1,76 @@
+/**
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "RecipientsPicker.h"
+
+#include "ui/widgets/KeyList.h"
+
+GpgFrontend::UI::RecipientsPicker::RecipientsPicker(
+ const GpgFrontend::KeyIdArgsListPtr& current_key_ids, QWidget* parent)
+ : QDialog(parent) {
+ auto confirm_button = new QPushButton(_("Confirm"));
+ connect(confirm_button, SIGNAL(clicked(bool)), this, SLOT(accept()));
+
+ // Setup KeyList
+ key_list_ = new KeyList(KeyMenuAbility::NONE, this);
+ key_list_->addListGroupTab(
+ _("Recipient(s)"), KeyListRow::SECRET_OR_PUBLIC_KEY,
+ KeyListColumn::NAME | KeyListColumn::EmailAddress,
+ [](const GpgKey& key) -> bool {
+ return !key.is_private_key() && key.CanEncrActual();
+ });
+ key_list_->slotRefresh();
+
+ auto key_ids = std::make_unique<GpgFrontend::KeyIdArgsList>();
+ for (const auto& key_id : *current_key_ids) {
+ key_ids->push_back(key_id);
+ }
+ key_list_->setChecked(std::move(key_ids));
+
+ auto* vbox2 = new QVBoxLayout();
+ vbox2->addWidget(new QLabel(QString(_("Select Recipient(s)")) + ": "));
+ vbox2->addWidget(key_list_);
+ vbox2->addWidget(new QLabel(
+ QString(_("We use the public key provided by the recipient to encrypt "
+ "the text.")) +
+ "\n" +
+ _("If you want to send to multiple recipients at the same time, you can "
+ "select multiple keys.")));
+ vbox2->addWidget(confirm_button);
+ vbox2->addStretch(0);
+ setLayout(vbox2);
+
+ this->setWindowFlags(Qt::Window | Qt::WindowTitleHint |
+ Qt::CustomizeWindowHint);
+
+ this->setModal(true);
+ this->setWindowTitle("Recipient(s) Picker");
+ this->setMinimumWidth(480);
+ this->exec();
+}
+
+GpgFrontend::KeyIdArgsListPtr
+GpgFrontend::UI::RecipientsPicker::getCheckedRecipients() {
+ return key_list_->getChecked();
+}
diff --git a/src/ui/smtp/RecipientsPicker.h b/src/ui/smtp/RecipientsPicker.h
new file mode 100644
index 00000000..bf128149
--- /dev/null
+++ b/src/ui/smtp/RecipientsPicker.h
@@ -0,0 +1,49 @@
+/**
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef GPGFRONTEND_RECIPENTSPICKER_H
+#define GPGFRONTEND_RECIPENTSPICKER_H
+
+#include "GpgFrontendUI.h"
+
+namespace GpgFrontend::UI {
+
+class KeyList;
+
+class RecipientsPicker : public QDialog {
+ Q_OBJECT
+
+ public:
+ explicit RecipientsPicker(
+ const GpgFrontend::KeyIdArgsListPtr& current_key_ids,
+ QWidget* parent = nullptr);
+
+ GpgFrontend::KeyIdArgsListPtr getCheckedRecipients();
+
+ private:
+ KeyList* key_list_;
+};
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_RECIPENTSPICKER_H
diff --git a/src/ui/smtp/SendMailDialog.cpp b/src/ui/smtp/SendMailDialog.cpp
index 374b3875..3f0b87cd 100644
--- a/src/ui/smtp/SendMailDialog.cpp
+++ b/src/ui/smtp/SendMailDialog.cpp
@@ -24,12 +24,15 @@
#include "SendMailDialog.h"
-#include <utility>
-
+#include "gpg/function/GpgKeyGetter.h"
+#include "ui/smtp/EmailListEditor.h"
+#include "ui/smtp/RecipientsPicker.h"
+#include "ui/smtp/SenderPicker.h"
#include "ui_SendMailDialog.h"
#ifdef SMTP_SUPPORT
#include "smtp/SmtpMime"
+#include "ui/function/SMTPSendMailThread.h"
#include "ui/settings/GlobalSettingStation.h"
#endif
@@ -40,9 +43,9 @@ SendMailDialog::SendMailDialog(const QString& text, QWidget* parent)
// read from settings
initSettings();
- if (smtpAddress.isEmpty()) {
+ if (smtp_address_.isEmpty()) {
QMessageBox::critical(
- this, _("Incomplete configuration"),
+ this->parentWidget(), _("Incomplete configuration"),
_("The SMTP address is empty, please go to the setting interface to "
"complete the configuration."));
@@ -57,7 +60,17 @@ SendMailDialog::SendMailDialog(const QString& text, QWidget* parent)
ui->textEdit->setText(text);
ui->errorLabel->setHidden(true);
- ui->senderEdit->setText(defaultSender);
+ ui->senderEdit->setText(default_sender_);
+
+ if (!default_sender_gpg_key_id.isEmpty()) {
+ auto key = GpgKeyGetter::GetInstance().GetKey(
+ default_sender_gpg_key_id.toStdString());
+ if (key.good() && key.is_private_key() && key.CanSignActual()) {
+ sender_key_id_ = key.id();
+ set_sender_value_label();
+ }
+ }
+
connect(ui->ccButton, &QPushButton::clicked, [=]() {
ui->ccInputWidget->setHidden(!ui->ccInputWidget->isHidden());
ui->ccEdit->clear();
@@ -72,6 +85,33 @@ SendMailDialog::SendMailDialog(const QString& text, QWidget* parent)
&SendMailDialog::slotConfirm);
#endif
+ connect(ui->senderKeySelectButton, &QPushButton::clicked, this, [=]() {
+ auto picker = new SenderPicker(sender_key_id_, this);
+ sender_key_id_ = picker->getCheckedSender();
+ set_sender_value_label();
+ });
+
+ connect(ui->recipientKeySelectButton, &QPushButton::clicked, this, [=]() {
+ auto picker = new RecipientsPicker(recipients_key_ids_, this);
+ recipients_key_ids_ = picker->getCheckedRecipients();
+ set_recipients_value_label();
+ });
+
+ connect(ui->recipientsEditButton, &QPushButton::clicked, this, [=]() {
+ auto editor = new EmailListEditor(ui->recipientEdit->text(), this);
+ ui->recipientEdit->setText(editor->getEmailList());
+ });
+
+ connect(ui->ccEditButton, &QPushButton::clicked, this, [=]() {
+ auto editor = new EmailListEditor(ui->ccEdit->text(), this);
+ ui->ccEdit->setText(editor->getEmailList());
+ });
+
+ connect(ui->bccEditButton, &QPushButton::clicked, this, [=]() {
+ auto editor = new EmailListEditor(ui->bccEdit->text(), this);
+ ui->bccEdit->setText(editor->getEmailList());
+ });
+
ui->ccButton->setText(_("CC"));
ui->bccButton->setText(_("BCC"));
ui->senderLabel->setText(_("Sender"));
@@ -82,9 +122,27 @@ SendMailDialog::SendMailDialog(const QString& text, QWidget* parent)
ui->tipsLabel->setText(
_("Tips: You can fill in multiple email addresses, please separate them "
"with \";\"."));
- ui->sendMailButton->setText(_("Send Mail"));
-
- this->setWindowTitle(_("Send Mail"));
+ ui->sendMailButton->setText(_("Send Message"));
+ ui->senderKeySelectButton->setText(_("Select Sender GPG Key"));
+ ui->recipientKeySelectButton->setText(_("Select Recipient(s) GPG Key"));
+ ui->gpgOperaLabel->setText(_("GPG Operations"));
+ ui->attacSignatureCheckBox->setText(_("Attach signature"));
+ ui->attachSenderPublickeyCheckBox->setText(_("Attach sender's public key"));
+ ui->contentEncryptCheckBox->setText(_("Encrypt content"));
+ ui->recipientsEditButton->setText(_("Edit Recipients(s)"));
+ ui->ccEditButton->setText(_("Edit CC(s)"));
+ ui->bccEditButton->setText(_("Edit BCC(s)"));
+ ui->senderKeyLabel->setText(_("Sender GPG Key: "));
+ ui->recipientKeysLabel->setText(_("Recipient(s) GPG Key: "));
+
+ auto pos = QPoint(100, 100);
+ LOG(INFO) << "parent" << parent;
+ if (parent) pos += parent->pos();
+ LOG(INFO) << "pos default" << pos.x() << pos.y();
+
+ move(pos);
+
+ this->setWindowTitle(_("New Message"));
this->setAttribute(Qt::WA_DeleteOnClose);
}
@@ -155,129 +213,223 @@ void SendMailDialog::slotConfirm() {
return;
}
- SmtpClient::ConnectionType connectionType =
+ SmtpClient::ConnectionType connection_type_ =
SmtpClient::ConnectionType::TcpConnection;
- if (connectionTypeSettings == "SSL") {
- connectionType = SmtpClient::ConnectionType::SslConnection;
- } else if (connectionTypeSettings == "TLS") {
- connectionType = SmtpClient::ConnectionType::TlsConnection;
- } else if (connectionTypeSettings == "STARTTLS") {
- connectionType = SmtpClient::ConnectionType::TlsConnection;
+ if (connection_type_settings_ == "SSL") {
+ connection_type_ = SmtpClient::ConnectionType::SslConnection;
+ } else if (connection_type_settings_ == "TLS") {
+ connection_type_ = SmtpClient::ConnectionType::TlsConnection;
+ } else if (connection_type_settings_ == "STARTTLS") {
+ connection_type_ = SmtpClient::ConnectionType::TlsConnection;
} else {
- connectionType = SmtpClient::ConnectionType::TcpConnection;
+ connection_type_ = SmtpClient::ConnectionType::TcpConnection;
}
- SmtpClient smtp(smtpAddress, port, connectionType);
-
- // We need to set the username (your email address) and the password
- // for smtp authentification.
-
- smtp.setUser(username);
- smtp.setPassword(password);
-
- // Now we create a MimeMessage object. This will be the email.
-
- MimeMessage message;
-
- message.setSender(new EmailAddress(ui->senderEdit->text()));
- for (const auto& reci : rcpt_string_list) {
- if (!reci.isEmpty()) message.addRecipient(new EmailAddress(reci.trimmed()));
- }
- for (const auto& cc : cc_string_list) {
- if (!cc.isEmpty()) message.addCc(new EmailAddress(cc.trimmed()));
- }
- for (const auto& bcc : cc_string_list) {
- if (!bcc.isEmpty()) message.addBcc(new EmailAddress(bcc.trimmed()));
+ auto host = smtp_address_.toStdString();
+ auto port = port_;
+ auto connection_type = connection_type_;
+ bool identity_needed = identity_enable_;
+ auto username = username_.toStdString();
+ auto password = password_.toStdString();
+ auto sender_address = ui->senderEdit->text().toStdString();
+
+ auto thread = new SMTPSendMailThread(
+ host, port, connection_type, identity_needed, username, password, this);
+
+ thread->setSender(ui->senderEdit->text());
+ thread->setRecipient(ui->recipientEdit->text());
+ thread->setCC(ui->ccEdit->text());
+ thread->setBCC(ui->bccEdit->text());
+ thread->setSubject(ui->subjectEdit->text());
+ thread->addTextContent(ui->textEdit->toPlainText());
+
+ if (ui->contentEncryptCheckBox->checkState() == Qt::Checked) {
+ if (recipients_key_ids_ == nullptr || recipients_key_ids_->empty()) {
+ QMessageBox::critical(
+ this, _("Forbidden"),
+ _("You have checked the encrypted email content, but you have not "
+ "selected the recipient's GPG key. This is dangerous and the mail "
+ "will not be encrypted. So the send operation is forbidden"));
+ return;
+ } else {
+ auto key_ids = std::make_unique<KeyIdArgsList>();
+ for (const auto& key_id : *recipients_key_ids_)
+ key_ids->push_back(key_id);
+ thread->setEncryptContent(true, std::move(key_ids));
+ }
}
- message.setSubject(ui->subjectEdit->text());
- // Now add some text to the email.
- // First we create a MimeText object.
+ if (ui->attacSignatureCheckBox->checkState() == Qt::Checked) {
+ if (sender_key_id_.empty()) {
+ QMessageBox::critical(
+ this, _("Forbidden"),
+ _("You checked the option to attach signature to the email, but did "
+ "not specify the sender's GPG Key. This will cause the content of "
+ "the email to be inconsistent with your expectations, so the "
+ "operation is prohibited."));
+ return;
+ } else {
+ thread->setAttachSignatureFile(true, sender_key_id_);
+ }
+ }
- MimeText text;
- text.setText(ui->textEdit->toPlainText());
+ if (ui->attachSenderPublickeyCheckBox->checkState() == Qt::Checked) {
+ if (sender_key_id_.empty()) {
+ QMessageBox::critical(
+ this, _("Forbidden"),
+ _("You checked the option to attach your public key to the email, "
+ "but did not specify the sender's GPG Key. This will cause the "
+ "content of "
+ "the email to be inconsistent "
+ "with your expectations, so the operation is prohibited."));
+ return;
+ } else {
+ thread->setAttachPublicKey(true, sender_key_id_);
+ }
+ }
- // Now add it to the mail
- message.addPart(&text);
+ // Waiting Dialog
+ auto* waiting_dialog = new QProgressDialog(this);
+ waiting_dialog->setMaximum(0);
+ waiting_dialog->setMinimum(0);
+ auto waiting_dialog_label =
+ new QLabel(QString(_("Sending Email...")) + "<br /><br />" +
+ _("If the process does not end for a long time, please check "
+ "again whether your SMTP server configuration is correct."));
+ waiting_dialog_label->setWordWrap(true);
+ waiting_dialog->setLabel(waiting_dialog_label);
+ waiting_dialog->resize(420, 120);
+ connect(thread, &SMTPSendMailThread::signalSMTPResult, this,
+ &SendMailDialog::slotTestSMTPConnectionResult);
+ connect(thread, &QThread::finished, [=]() {
+ waiting_dialog->finished(0);
+ waiting_dialog->deleteLater();
+ });
+ connect(waiting_dialog, &QProgressDialog::canceled, [=]() {
+ LOG(INFO) << "cancel clicked";
+ if (thread->isRunning()) thread->terminate();
+ });
- // Now we can send the mail
- if (!smtp.connectToHost()) {
- qDebug() << "Connect to SMTP Server Failed";
- QMessageBox::critical(this, _("Fail"), _("Fail to Connect SMTP Server"));
- return;
- }
- if (!smtp.login()) {
- qDebug() << "Login to SMTP Server Failed";
- QMessageBox::critical(this, _("Fail"), _("Fail to Login into SMTP Server"));
- return;
- }
- if (!smtp.sendMail(message)) {
- qDebug() << "Send Mail to SMTP Server Failed";
- QMessageBox::critical(this, _("Fail"),
- _("Fail to Send Mail to SMTP Server"));
- return;
- }
- smtp.quit();
+ // Show Waiting Dialog
+ waiting_dialog->show();
+ waiting_dialog->setFocus();
- // Close after sending email
- QMessageBox::information(this, _("Success"),
- _("Succeed in Sending Mail to SMTP Server"));
- deleteLater();
+ thread->start();
+ QEventLoop loop;
+ connect(thread, &QThread::finished, &loop, &QEventLoop::quit);
+ loop.exec();
}
void SendMailDialog::initSettings() {
auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
try {
- ability_enable = settings.lookup("smtp.enable");
+ ability_enable_ = settings.lookup("smtp.enable");
} catch (...) {
LOG(ERROR) << _("Setting Operation Error") << _("save_key_checked");
}
try {
- identity_enable = settings.lookup("smtp.identity_enable");
+ identity_enable_ = settings.lookup("smtp.identity_enable");
} catch (...) {
LOG(ERROR) << _("Setting Operation Error") << _("identity_enable");
}
try {
- smtpAddress = settings.lookup("smtp.mail_address").c_str();
+ smtp_address_ = settings.lookup("smtp.mail_address").c_str();
} catch (...) {
LOG(ERROR) << _("Setting Operation Error") << _("mail_address");
}
try {
- username = settings.lookup("smtp.username").c_str();
+ username_ = settings.lookup("smtp.username").c_str();
} catch (...) {
LOG(ERROR) << _("Setting Operation Error") << _("username");
}
try {
- password = settings.lookup("smtp.password").c_str();
+ password_ = settings.lookup("smtp.password").c_str();
} catch (...) {
LOG(ERROR) << _("Setting Operation Error") << _("password");
}
try {
- port = settings.lookup("smtp.port");
+ port_ = settings.lookup("smtp.port");
} catch (...) {
LOG(ERROR) << _("Setting Operation Error") << _("port");
}
try {
- connectionTypeSettings = settings.lookup("smtp.connection_type").c_str();
+ connection_type_settings_ = settings.lookup("smtp.connection_type").c_str();
} catch (...) {
LOG(ERROR) << _("Setting Operation Error") << _("connection_type");
}
try {
- defaultSender = settings.lookup("smtp.default_sender").c_str();
+ default_sender_ = settings.lookup("smtp.default_sender").c_str();
} catch (...) {
LOG(ERROR) << _("Setting Operation Error") << _("default_sender");
}
-}
+ try {
+ default_sender_gpg_key_id =
+ settings.lookup("smtp.default_sender_gpg_key_id").c_str();
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error")
+ << _("default_sender_gpg_key_id");
+ }
+}
#endif
+void SendMailDialog::set_sender_value_label() {
+ auto key = GpgKeyGetter::GetInstance().GetKey(sender_key_id_);
+ if (key.good()) {
+ ui->senderKeyValueLabel->setText(key.uids()->front().uid().c_str());
+ }
+}
+
+void SendMailDialog::set_recipients_value_label() {
+ auto keys = GpgKeyGetter::GetInstance().GetKeys(recipients_key_ids_);
+ std::stringstream ss;
+ for (const auto& key : *keys) {
+ if (key.good()) {
+ ss << key.uids()->front().uid().c_str() << ";";
+ }
+ }
+ ui->recipientsKeyValueLabel->setText(ss.str().c_str());
+}
+
+void SendMailDialog::slotTestSMTPConnectionResult(const QString& result) {
+ if (result == "Fail to connect SMTP server") {
+ QMessageBox::critical(this, _("Fail"), _("Fail to Connect SMTP Server."));
+ } else if (result == "Fail to login") {
+ QMessageBox::critical(this, _("Fail"), _("Fail to Login."));
+ } else if (result == "Fail to send mail") {
+ QMessageBox::critical(this, _("Fail"), _("Fail to Login."));
+ } else if (result == "Succeed in testing connection") {
+ QMessageBox::information(this, _("Success"),
+ _("Succeed in connecting and login"));
+ } else if (result == "Succeed in sending a test email") {
+ QMessageBox::information(
+ this, _("Success"),
+ _("Succeed in sending the message to the SMTP Server"));
+ } else if (result == "Fail to encrypt with gpg keys") {
+ QMessageBox::critical(
+ this, _("Encryption Error"),
+ _("An error occurred while encrypting the content of the email. This "
+ "may be because you did not complete some operations during Gnupg "
+ "encryption."));
+ } else {
+ QMessageBox::critical(this, _("Fail"), _("Unknown error."));
+ }
+}
+void SendMailDialog::setContentEncryption(bool on) {
+ ui->contentEncryptCheckBox->setCheckState(on ? Qt::Checked : Qt::Unchecked);
+}
+
+void SendMailDialog::setAttachSignature(bool on) {
+ ui->attacSignatureCheckBox->setCheckState(on ? Qt::Checked : Qt::Unchecked);
+}
+
} // namespace GpgFrontend::UI
diff --git a/src/ui/smtp/SendMailDialog.h b/src/ui/smtp/SendMailDialog.h
index 979d4f88..04224f18 100644
--- a/src/ui/smtp/SendMailDialog.h
+++ b/src/ui/smtp/SendMailDialog.h
@@ -36,28 +36,43 @@ class SendMailDialog : public QDialog {
public:
explicit SendMailDialog(const QString& text, QWidget* parent = nullptr);
+ void setContentEncryption(bool on);
+
+ void setAttachSignature(bool on);
+
private slots:
void slotConfirm();
+ void slotTestSMTPConnectionResult(const QString& result);
+
private:
void initSettings();
std::shared_ptr<Ui_SendMailDialog> ui;
- bool ability_enable = false;
- bool identity_enable = false;
- QString smtpAddress;
- QString username;
- QString password;
- QString defaultSender;
- QString connectionTypeSettings = "None";
- int port = 25;
+ bool ability_enable_ = false;
+ bool identity_enable_ = false;
+ QString smtp_address_;
+ QString username_;
+ QString password_;
+ QString default_sender_;
+ QString connection_type_settings_ = "None";
+ QString default_sender_gpg_key_id = {};
+ int port_ = 25;
+
+ GpgFrontend::KeyId sender_key_id_;
+ GpgFrontend::KeyIdArgsListPtr recipients_key_ids_ =
+ std::make_unique<GpgFrontend::KeyIdArgsList>();
QRegularExpression re_email{
R"((?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\]))"};
bool check_email_address(const QString& str);
+
+ void set_sender_value_label();
+
+ void set_recipients_value_label();
};
} // namespace GpgFrontend::UI
diff --git a/src/ui/smtp/SenderPicker.cpp b/src/ui/smtp/SenderPicker.cpp
new file mode 100644
index 00000000..fcd3ba61
--- /dev/null
+++ b/src/ui/smtp/SenderPicker.cpp
@@ -0,0 +1,76 @@
+/**
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "SenderPicker.h"
+
+#include "ui/widgets/KeyList.h"
+
+GpgFrontend::UI::SenderPicker::SenderPicker(const KeyId& current_key_id,
+ QWidget* parent)
+ : QDialog(parent) {
+ auto confirm_button = new QPushButton(_("Confirm"));
+ connect(confirm_button, SIGNAL(clicked(bool)), this, SLOT(accept()));
+
+ // Setup KeyList
+ key_list_ = new KeyList(KeyMenuAbility::NONE, this);
+ key_list_->addListGroupTab(
+ _("Sender"), KeyListRow::ONLY_SECRET_KEY,
+ KeyListColumn::NAME | KeyListColumn::EmailAddress,
+ [](const GpgKey& key) -> bool { return key.CanSignActual(); });
+ key_list_->slotRefresh();
+
+ auto key_ids = std::make_unique<GpgFrontend::KeyIdArgsList>();
+ key_ids->push_back(current_key_id);
+ key_list_->setChecked(std::move(key_ids));
+
+ auto* vbox2 = new QVBoxLayout();
+ vbox2->addWidget(new QLabel(QString(_("Select Sender")) + ": "));
+ vbox2->addWidget(key_list_);
+ vbox2->addWidget(new QLabel(
+ QString(
+ _("As the sender of the mail, the private key is generally used.")) +
+ "\n" +
+ _(" The private key is generally used as a signature for the content of "
+ "the mail.")));
+ vbox2->addWidget(confirm_button);
+ vbox2->addStretch(0);
+ setLayout(vbox2);
+
+ this->setWindowFlags(Qt::Window | Qt::WindowTitleHint |
+ Qt::CustomizeWindowHint);
+
+ this->setModal(true);
+ this->setWindowTitle("Sender Picker");
+ this->setMinimumWidth(480);
+ this->exec();
+}
+
+GpgFrontend::KeyId GpgFrontend::UI::SenderPicker::getCheckedSender() {
+ auto checked_keys = key_list_->getChecked();
+ if (!checked_keys->empty()) {
+ return key_list_->getChecked()->front();
+ } else {
+ return {};
+ }
+}
diff --git a/src/ui/smtp/SenderPicker.h b/src/ui/smtp/SenderPicker.h
new file mode 100644
index 00000000..3745bb34
--- /dev/null
+++ b/src/ui/smtp/SenderPicker.h
@@ -0,0 +1,47 @@
+/**
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef GPGFRONTEND_SENDERPICKER_H
+#define GPGFRONTEND_SENDERPICKER_H
+
+#include "GpgFrontendUI.h"
+
+namespace GpgFrontend::UI {
+
+class KeyList;
+
+class SenderPicker : public QDialog {
+ Q_OBJECT
+
+ public:
+ explicit SenderPicker(const KeyId& current_key_id, QWidget* parent = nullptr);
+
+ GpgFrontend::KeyId getCheckedSender();
+
+ private:
+ KeyList* key_list_;
+};
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_SENDERPICKER_H
diff --git a/src/ui/widgets/EditorPage.cpp b/src/ui/widgets/EditorPage.cpp
index 94c98036..b73974a7 100644
--- a/src/ui/widgets/EditorPage.cpp
+++ b/src/ui/widgets/EditorPage.cpp
@@ -32,7 +32,7 @@
namespace GpgFrontend::UI {
EditorPage::EditorPage(QString filePath, QWidget* parent)
- : QWidget(parent), fullFilePath(std::move(filePath)) {
+ : QWidget(parent), full_file_path_(std::move(filePath)) {
// Set the Textedit properties
textPage = new QTextEdit();
textPage->setAcceptRichText(false);
@@ -51,12 +51,12 @@ EditorPage::EditorPage(QString filePath, QWidget* parent)
this->setAttribute(Qt::WA_DeleteOnClose);
}
-const QString& EditorPage::getFilePath() const { return fullFilePath; }
+const QString& EditorPage::getFilePath() const { return full_file_path_; }
QTextEdit* EditorPage::getTextPage() { return textPage; }
void EditorPage::setFilePath(const QString& filePath) {
- fullFilePath = filePath;
+ full_file_path_ = filePath;
}
void EditorPage::showNotificationWidget(QWidget* widget,
@@ -110,34 +110,34 @@ void EditorPage::slotFormatGpgHeader() {
void EditorPage::ReadFile() {
LOG(INFO) << "Called";
- readDone = false;
+ read_done_ = false;
auto text_page = this->getTextPage();
text_page->setReadOnly(true);
- auto thread = new FileReadThread(this->fullFilePath.toStdString());
+ auto thread = new FileReadThread(this->full_file_path_.toStdString());
connect(thread, &FileReadThread::sendReadBlock, this,
&EditorPage::slotInsertText);
connect(thread, &FileReadThread::readDone, this, [=]() {
- LOG(INFO) << "Thread read done";
+ LOG(INFO) << "thread read done";
text_page->document()->setModified(false);
text_page->setReadOnly(false);
});
connect(thread, &FileReadThread::finished, this, [=]() {
- LOG(INFO) << "Thread finished";
+ LOG(INFO) << "thread finished";
thread->deleteLater();
- readDone = true;
- readThread = nullptr;
+ read_done_ = true;
+ read_hread_ = nullptr;
});
connect(this, &EditorPage::destroyed, [=]() {
- LOG(INFO) << "RequestInterruption for readThread";
+ LOG(INFO) << "request interruption for read thread";
thread->requestInterruption();
- readThread = nullptr;
+ read_hread_ = nullptr;
});
- this->readThread = thread;
+ this->read_hread_ = thread;
thread->start();
}
@@ -145,9 +145,9 @@ void EditorPage::slotInsertText(const QString& text) {
this->getTextPage()->insertPlainText(text);
}
void EditorPage::PrepareToDestroy() {
- if (readThread) {
- readThread->requestInterruption();
- readThread = nullptr;
+ if (read_hread_) {
+ read_hread_->requestInterruption();
+ read_hread_ = nullptr;
}
}
diff --git a/src/ui/widgets/EditorPage.h b/src/ui/widgets/EditorPage.h
index a0a05dab..d1bc1ac2 100644
--- a/src/ui/widgets/EditorPage.h
+++ b/src/ui/widgets/EditorPage.h
@@ -86,17 +86,17 @@ class EditorPage : public QWidget {
void ReadFile();
- [[nodiscard]] bool ReadDone() const { return this->readDone; }
+ [[nodiscard]] bool ReadDone() const { return this->read_done_; }
void PrepareToDestroy();
private:
QTextEdit* textPage; /** The textedit of the tab */
QVBoxLayout* mainLayout; /** The layout for the tab */
- QString fullFilePath; /** The path to the file handled in the tab */
+ QString full_file_path_; /** The path to the file handled in the tab */
bool signMarked{}; /** true, if the signed header is marked, false if not */
- bool readDone = false;
- QThread* readThread = nullptr;
+ bool read_done_ = false;
+ QThread* read_hread_ = nullptr;
private slots:
diff --git a/src/ui/widgets/ExportKeyPackageDialog.cpp b/src/ui/widgets/ExportKeyPackageDialog.cpp
new file mode 100644
index 00000000..d99e966a
--- /dev/null
+++ b/src/ui/widgets/ExportKeyPackageDialog.cpp
@@ -0,0 +1,170 @@
+/**
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "ExportKeyPackageDialog.h"
+
+#include <boost/format.hpp>
+
+#include "gpg/function/GpgKeyGetter.h"
+#include "gpg/function/GpgKeyImportExporter.h"
+#include "ui/aes/qaesencryption.h"
+#include "ui_ExportKeyPackageDialog.h"
+
+GpgFrontend::UI::ExportKeyPackageDialog::ExportKeyPackageDialog(
+ KeyIdArgsListPtr key_ids, QWidget* parent)
+ : QDialog(parent),
+ ui(std::make_shared<Ui_exportKeyPackageDialog>()),
+ key_ids_(std::move(key_ids)),
+ mt(rd()) {
+ ui->setupUi(this);
+
+ generate_key_package_name();
+
+ connect(ui->gnerateNameButton, &QPushButton::clicked, this,
+ [=]() { generate_key_package_name(); });
+
+ connect(ui->setOutputPathButton, &QPushButton::clicked, this, [=]() {
+ auto file_name = QFileDialog::getSaveFileName(
+ this, _("Export Key Package"), ui->nameValueLabel->text() + ".gfepack",
+ QString(_("Key Package")) + " (*.gfepack);;All Files (*)");
+ ui->outputPathLabel->setText(file_name);
+ });
+
+ connect(ui->generatePassphraseButton, &QPushButton::clicked, this, [=]() {
+ passphrase_ = generate_passphrase(256);
+ auto file_name = QFileDialog::getSaveFileName(
+ this, _("Export Key Package Passphrase"),
+ ui->nameValueLabel->text() + ".key",
+ QString(_("Key File")) + " (*.key);;All Files (*)");
+ ui->passphraseValueLabel->setText(file_name);
+ write_buffer_to_file(file_name.toStdString(), passphrase_);
+ });
+
+ connect(ui->buttonBox, &QDialogButtonBox::accepted, this, [=]() {
+ if (ui->outputPathLabel->text().isEmpty()) {
+ QMessageBox::critical(
+ this, _("Forbidden"),
+ _("Please select an output path before exporting."));
+ return;
+ }
+
+ if (ui->passphraseValueLabel->text().isEmpty()) {
+ QMessageBox::critical(
+ this, _("Forbidden"),
+ _("Please generate a password to protect your key before exporting, "
+ "it is very important. Don't forget to back up your password in a "
+ "safe place."));
+ return;
+ }
+
+ auto key_id_exported = std::make_unique<KeyIdArgsList>();
+ auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids_);
+ for (const auto& key : *keys) {
+ if (ui->noPublicKeyCheckBox->isChecked() && !key.is_private_key()) {
+ continue;
+ }
+ key_id_exported->push_back(key.id());
+ }
+
+ ByteArrayPtr key_export_data = nullptr;
+ if (!GpgKeyImportExporter::GetInstance().ExportKeys(
+ key_ids_, key_export_data,
+ ui->includeSecretKeyCheckBox->isChecked())) {
+ QMessageBox::critical(this, _("Error"), _("Export Key(s) Failed."));
+ this->close();
+ return;
+ }
+
+ auto key = QByteArray::fromStdString(passphrase_),
+ data =
+ QString::fromStdString(*key_export_data).toLocal8Bit().toBase64();
+
+ auto hash_key = QCryptographicHash::hash(key, QCryptographicHash::Sha256);
+ QAESEncryption encryption(QAESEncryption::AES_256, QAESEncryption::ECB,
+ QAESEncryption::Padding::ISO);
+ auto encoded = encryption.encode(data, hash_key);
+
+ write_buffer_to_file(ui->outputPathLabel->text().toStdString(),
+ encoded.toStdString());
+
+ QMessageBox::information(
+ this, _("Success"),
+ QString(_(
+ "The Key Package has been successfully generated and has been "
+ "protected by encryption algorithms. You can safely transfer your "
+ "Key Package.")) +
+ "<br />" + "<b>" +
+ _("But the key file cannot be leaked under any "
+ "circumstances. Please delete the Key Package and key file as "
+ "soon "
+ "as possible after completing the transfer operation.") +
+ "</b>");
+ });
+
+ connect(ui->buttonBox, &QDialogButtonBox::rejected, this,
+ [=]() { this->close(); });
+
+ ui->nameLabel->setText(_("Key Package Name"));
+ ui->selectOutputPathLabel->setText(_("Output Path"));
+ ui->passphraseLabel->setText(_("Passphrase"));
+ ui->tipsLabel->setText(
+ _("Tips: You can use Key Package to safely and conveniently transfer "
+ "your public and private keys between devices."));
+ ui->generatePassphraseButton->setText(_("Generate and Save Passphrase"));
+ ui->gnerateNameButton->setText(_("Generate Key Package Name"));
+ ui->setOutputPathButton->setText(_("Select Output Path"));
+
+ ui->includeSecretKeyCheckBox->setText(
+ _("Include secret key (Think twice before acting)"));
+ ui->noPublicKeyCheckBox->setText(
+ _("Exclude keys that do not have a private key"));
+
+ setAttribute(Qt::WA_DeleteOnClose);
+ setWindowTitle(_("exportKeyPackageDialog"));
+}
+
+std::string GpgFrontend::UI::ExportKeyPackageDialog::generate_passphrase(
+ const int len) {
+ std::uniform_int_distribution<int> dist(999, 99999);
+ static const char alphanum[] =
+ "0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz";
+ std::string tmp_str;
+ tmp_str.reserve(len);
+
+ for (int i = 0; i < len; ++i) {
+ tmp_str += alphanum[dist(mt) % (sizeof(alphanum) - 1)];
+ }
+
+ return tmp_str;
+}
+
+void GpgFrontend::UI::ExportKeyPackageDialog::generate_key_package_name() {
+ std::uniform_int_distribution<int> dist(999, 99999);
+ auto file_string = boost::format("KeyPackage_%1%") % dist(mt);
+ ui->nameValueLabel->setText(file_string.str().c_str());
+ ui->outputPathLabel->clear();
+ ui->passphraseValueLabel->clear();
+}
diff --git a/src/ui/widgets/ExportKeyPackageDialog.h b/src/ui/widgets/ExportKeyPackageDialog.h
new file mode 100644
index 00000000..a254b453
--- /dev/null
+++ b/src/ui/widgets/ExportKeyPackageDialog.h
@@ -0,0 +1,55 @@
+/**
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef GPGFRONTEND_EXPORTKEYPACKAGEDIALOG_H
+#define GPGFRONTEND_EXPORTKEYPACKAGEDIALOG_H
+
+#include "GpgFrontendUI.h"
+
+class Ui_exportKeyPackageDialog;
+
+namespace GpgFrontend::UI {
+
+class ExportKeyPackageDialog : public QDialog {
+ Q_OBJECT
+
+ public:
+ explicit ExportKeyPackageDialog(KeyIdArgsListPtr key_ids, QWidget* parent);
+
+ std::string generate_passphrase(const int len);
+
+ private:
+ std::shared_ptr<Ui_exportKeyPackageDialog> ui;
+ KeyIdArgsListPtr key_ids_;
+
+ std::random_device rd;
+ std::mt19937 mt;
+
+ std::string passphrase_;
+
+ void generate_key_package_name();
+};
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_EXPORTKEYPACKAGEDIALOG_H
diff --git a/src/ui/widgets/FilePage.cpp b/src/ui/widgets/FilePage.cpp
index ca6dedc1..3e140bd4 100644
--- a/src/ui/widgets/FilePage.cpp
+++ b/src/ui/widgets/FilePage.cpp
@@ -156,48 +156,57 @@ void FilePage::slotGoPath() {
void FilePage::createPopupMenu() {
popUpMenu = new QMenu();
- openItemAct = new QAction(_("Open"), this);
- connect(openItemAct, &QAction::triggered, this, &FilePage::slotOpenItem);
- renameItemAct = new QAction(_("Rename"), this);
- connect(renameItemAct, &QAction::triggered, this, &FilePage::slotRenameItem);
- deleteItemAct = new QAction(_("Delete"), this);
- connect(deleteItemAct, &QAction::triggered, this, &FilePage::slotDeleteItem);
- encryptItemAct = new QAction(_("Encrypt Sign"), this);
- connect(encryptItemAct, &QAction::triggered, this,
+ ui->actionOpenFile->setText(_("Open"));
+ connect(ui->actionOpenFile, &QAction::triggered, this,
+ &FilePage::slotOpenItem);
+ ui->actionRenameFile->setText(_("Rename"));
+ connect(ui->actionRenameFile, &QAction::triggered, this,
+ &FilePage::slotRenameItem);
+ ui->actionDeleteFile->setText(_("Delete"));
+ connect(ui->actionDeleteFile, &QAction::triggered, this,
+ &FilePage::slotDeleteItem);
+
+ ui->actionEncrypt->setText(_("Encrypt"));
+ connect(ui->actionEncrypt, &QAction::triggered, this,
&FilePage::slotEncryptItem);
- decryptItemAct =
- new QAction(QString(_("Decrypt Verify")) + " " + _("(.gpg .asc)"), this);
- connect(decryptItemAct, &QAction::triggered, this,
+ ui->actionEncryptSign->setText(_("Encrypt Sign"));
+ connect(ui->actionEncryptSign, &QAction::triggered, this,
+ &FilePage::slotEncryptSignItem);
+ ui->actionDecrypt->setText(QString(_("Decrypt Verify")) + " " +
+ _("(.gpg .asc)"));
+ connect(ui->actionDecrypt, &QAction::triggered, this,
&FilePage::slotDecryptItem);
- signItemAct = new QAction(_("Sign"), this);
- connect(signItemAct, &QAction::triggered, this, &FilePage::slotSignItem);
- verifyItemAct =
- new QAction(QString(_("Verify")) + " " + _("(.sig .gpg .asc)"), this);
- connect(verifyItemAct, &QAction::triggered, this, &FilePage::slotVerifyItem);
-
- hashCalculateAct = new QAction(_("Calculate Hash"), this);
- connect(hashCalculateAct, &QAction::triggered, this,
+ ui->actionSign->setText(_("Sign"));
+ connect(ui->actionSign, &QAction::triggered, this, &FilePage::slotSignItem);
+ ui->actionVerify->setText(QString(_("Verify")) + " " + _("(.sig .gpg .asc)"));
+ connect(ui->actionVerify, &QAction::triggered, this,
+ &FilePage::slotVerifyItem);
+
+ ui->actionCalculateHash->setText(_("Calculate Hash"));
+ connect(ui->actionCalculateHash, &QAction::triggered, this,
&FilePage::slotCalculateHash);
- mkdirAct = new QAction(_("Make New Directory"), this);
- connect(mkdirAct, &QAction::triggered, this, &FilePage::slotMkdir);
+ ui->actionMakeDirectory->setText(_("Make New Directory"));
+ connect(ui->actionMakeDirectory, &QAction::triggered, this,
+ &FilePage::slotMkdir);
- createEmptyFileAct = new QAction(_("Create Empty File"), this);
- connect(createEmptyFileAct, &QAction::triggered, this,
+ ui->actionCreateEmptyFile->setText(_("Create Empty File"));
+ connect(ui->actionCreateEmptyFile, &QAction::triggered, this,
&FilePage::slotCreateEmptyFile);
- popUpMenu->addAction(openItemAct);
- popUpMenu->addAction(renameItemAct);
- popUpMenu->addAction(deleteItemAct);
+ popUpMenu->addAction(ui->actionOpenFile);
+ popUpMenu->addAction(ui->actionRenameFile);
+ popUpMenu->addAction(ui->actionDeleteFile);
popUpMenu->addSeparator();
- popUpMenu->addAction(encryptItemAct);
- popUpMenu->addAction(decryptItemAct);
- popUpMenu->addAction(signItemAct);
- popUpMenu->addAction(verifyItemAct);
+ popUpMenu->addAction(ui->actionEncrypt);
+ popUpMenu->addAction(ui->actionEncryptSign);
+ popUpMenu->addAction(ui->actionDecrypt);
+ popUpMenu->addAction(ui->actionSign);
+ popUpMenu->addAction(ui->actionVerify);
popUpMenu->addSeparator();
- popUpMenu->addAction(mkdirAct);
- popUpMenu->addAction(createEmptyFileAct);
- popUpMenu->addAction(hashCalculateAct);
+ popUpMenu->addAction(ui->actionMakeDirectory);
+ popUpMenu->addAction(ui->actionCreateEmptyFile);
+ popUpMenu->addAction(ui->actionCalculateHash);
optionPopUpMenu = new QMenu();
@@ -232,32 +241,37 @@ void FilePage::onCustomContextMenu(const QPoint& point) {
dirModel->fileInfo(index).absoluteFilePath().toStdString());
LOG(INFO) << "right click" << selectedPath;
if (index.isValid()) {
- openItemAct->setEnabled(true);
- renameItemAct->setEnabled(true);
- deleteItemAct->setEnabled(true);
+ ui->actionOpenFile->setEnabled(true);
+ ui->actionRenameFile->setEnabled(true);
+ ui->actionDeleteFile->setEnabled(true);
QFileInfo info(QString::fromStdString(selectedPath.string()));
- encryptItemAct->setEnabled(
- info.isFile() && (info.suffix() != "gpg" && info.suffix() != "sig"));
- encryptItemAct->setEnabled(
- info.isFile() && (info.suffix() != "gpg" && info.suffix() != "sig"));
- decryptItemAct->setEnabled(info.isFile() && info.suffix() == "gpg");
- signItemAct->setEnabled(info.isFile() &&
- (info.suffix() != "gpg" && info.suffix() != "sig"));
- verifyItemAct->setEnabled(
- info.isFile() && (info.suffix() == "sig" || info.suffix() == "gpg"));
- hashCalculateAct->setEnabled(info.isFile() && info.isReadable());
+ ui->actionEncrypt->setEnabled(info.isFile() && (info.suffix() != "gpg" &&
+ info.suffix() != "sig" &&
+ info.suffix() != "asc"));
+ ui->actionEncryptSign->setEnabled(
+ info.isFile() && (info.suffix() != "gpg" && info.suffix() != "sig" &&
+ info.suffix() != "asc"));
+ ui->actionDecrypt->setEnabled(
+ info.isFile() && (info.suffix() == "gpg" || info.suffix() == "asc"));
+ ui->actionSign->setEnabled(info.isFile() && (info.suffix() != "gpg" &&
+ info.suffix() != "sig" &&
+ info.suffix() != "asc"));
+ ui->actionVerify->setEnabled(info.isFile() && (info.suffix() == "sig" ||
+ info.suffix() == "gpg" ||
+ info.suffix() == "asc"));
+ ui->actionCalculateHash->setEnabled(info.isFile() && info.isReadable());
} else {
- openItemAct->setEnabled(false);
- renameItemAct->setEnabled(false);
- deleteItemAct->setEnabled(false);
-
- encryptItemAct->setEnabled(false);
- encryptItemAct->setEnabled(false);
- decryptItemAct->setEnabled(false);
- signItemAct->setEnabled(false);
- verifyItemAct->setEnabled(false);
- hashCalculateAct->setEnabled(false);
+ ui->actionOpenFile->setEnabled(false);
+ ui->actionRenameFile->setEnabled(false);
+ ui->actionDeleteFile->setEnabled(false);
+
+ ui->actionEncrypt->setEnabled(false);
+ ui->actionEncryptSign->setEnabled(false);
+ ui->actionDecrypt->setEnabled(false);
+ ui->actionSign->setEnabled(false);
+ ui->actionVerify->setEnabled(false);
+ ui->actionCalculateHash->setEnabled(false);
}
popUpMenu->exec(ui->fileTreeView->viewport()->mapToGlobal(point));
}
@@ -331,6 +345,11 @@ void FilePage::slotDeleteItem() {
void FilePage::slotEncryptItem() {
auto mainWindow = qobject_cast<MainWindow*>(firstParent);
+ if (mainWindow != nullptr) mainWindow->slotFileEncrypt();
+}
+
+void FilePage::slotEncryptSignItem() {
+ auto mainWindow = qobject_cast<MainWindow*>(firstParent);
if (mainWindow != nullptr) mainWindow->slotFileEncryptSign();
}
diff --git a/src/ui/widgets/FilePage.h b/src/ui/widgets/FilePage.h
index 03caf36b..1f2b51f8 100644
--- a/src/ui/widgets/FilePage.h
+++ b/src/ui/widgets/FilePage.h
@@ -61,6 +61,7 @@ class FilePage : public QWidget {
void slotRenameItem();
void slotDeleteItem();
void slotEncryptItem();
+ void slotEncryptSignItem();
void slotDecryptItem();
void slotSignItem();
void slotVerifyItem();
@@ -88,16 +89,6 @@ class FilePage : public QWidget {
QMenu* popUpMenu{};
QMenu* optionPopUpMenu{};
- QAction* encryptItemAct{};
- QAction* decryptItemAct{};
- QAction* signItemAct{};
- QAction* verifyItemAct{};
- QAction* hashCalculateAct{};
- QAction* mkdirAct{};
- QAction* openItemAct{};
- QAction* renameItemAct{};
- QAction* deleteItemAct{};
- QAction* createEmptyFileAct{};
QWidget* firstParent;
};
diff --git a/src/ui/widgets/InfoBoardWidget.cpp b/src/ui/widgets/InfoBoardWidget.cpp
index d46d5f92..7718cba3 100644
--- a/src/ui/widgets/InfoBoardWidget.cpp
+++ b/src/ui/widgets/InfoBoardWidget.cpp
@@ -35,7 +35,6 @@ InfoBoardWidget::InfoBoardWidget(QWidget* parent)
ui->setupUi(this);
ui->actionButtonLayout->addStretch();
- ui->actionLabel->setText(_("InfoBoard's Actions Menu"));
ui->copyButton->setText(_("Copy"));
ui->saveButton->setText(_("Save File"));
ui->clearButton->setText(_("Clear"));
@@ -163,7 +162,7 @@ void InfoBoardWidget::slotSave() {
auto file_path = QFileDialog::getSaveFileName(
this, _("Save Information Board's Content"), {}, tr("Text (*.txt)"));
LOG(INFO) << "file path" << file_path.toStdString();
- if(file_path.isEmpty()) return;
+ if (file_path.isEmpty()) return;
QFile file(file_path);
if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
diff --git a/src/ui/widgets/KeyList.cpp b/src/ui/widgets/KeyList.cpp
index 0e4c5bba..89634f95 100644
--- a/src/ui/widgets/KeyList.cpp
+++ b/src/ui/widgets/KeyList.cpp
@@ -27,6 +27,7 @@
#include <boost/format.hpp>
#include <utility>
+#include "gpg/GpgCoreInit.h"
#include "gpg/function/GpgKeyGetter.h"
#include "ui/SignalStation.h"
#include "ui/UserInterfaceUtils.h"
@@ -37,18 +38,35 @@ namespace GpgFrontend::UI {
int KeyList::key_list_id = 2048;
-KeyList::KeyList(bool menu, QWidget* parent)
+KeyList::KeyList(KeyMenuAbility::AbilityType menu_ability, QWidget* parent)
: QWidget(parent),
_m_key_list_id(key_list_id++),
ui(std::make_shared<Ui_KeyList>()),
- menu_status(menu) {
+ menu_ability_(menu_ability) {
init();
}
void KeyList::init() {
+#ifdef GPG_STANDALONE_MODE
+ LOG(INFO) << "GPG_STANDALONE_MODE Enabled";
+ auto gpg_path = GpgFrontend::UI::GlobalSettingStation::GetInstance()
+ .GetStandaloneGpgBinDir();
+ auto db_path = GpgFrontend::UI::GlobalSettingStation::GetInstance()
+ .GetStandaloneDatabaseDir();
+ GpgContext::CreateInstance(
+ _m_key_list_id, std::make_unique<GpgContext>(true, db_path.string(), true,
+ gpg_path.string()));
+#else
+ new_default_settings_channel(_m_key_list_id);
+#endif
+
ui->setupUi(this);
- ui->menuWidget->setHidden(!menu_status);
+ ui->menuWidget->setHidden(!menu_ability_);
+ ui->refreshKeyListButton->setHidden(~menu_ability_ & KeyMenuAbility::REFRESH);
+ ui->syncButton->setHidden(~menu_ability_ & KeyMenuAbility::SYNC_PUBLIC_KEY);
+ ui->uncheckButton->setHidden(~menu_ability_ & KeyMenuAbility::UNCHECK_ALL);
+
ui->keyGroupTab->clear();
popupMenu = new QMenu(this);
@@ -59,6 +77,10 @@ void KeyList::init() {
SLOT(slotRefresh()));
connect(ui->refreshKeyListButton, &QPushButton::clicked, this,
&KeyList::slotRefresh);
+ connect(ui->uncheckButton, &QPushButton::clicked, this,
+ &KeyList::slotUncheckALL);
+ connect(ui->checkALLButton, &QPushButton::clicked, this,
+ &KeyList::slotCheckALL);
connect(ui->syncButton, &QPushButton::clicked, this,
&KeyList::slotSyncWithKeyServer);
connect(this, &KeyList::signalRefreshStatusBar, SignalStation::GetInstance(),
@@ -66,10 +88,17 @@ void KeyList::init() {
setAcceptDrops(true);
- ui->keyListOperationsLabel->setText(_("Key List Menu: "));
ui->refreshKeyListButton->setText(_("Refresh"));
+ ui->refreshKeyListButton->setToolTip(
+ _("Refresh the key list to synchronize changes."));
ui->syncButton->setText(_("Sync Public Key"));
- ui->syncButton->setToolTip(_("Sync public key with your default keyserver"));
+ ui->syncButton->setToolTip(_("Sync public key with your default keyserver."));
+ ui->uncheckButton->setText(_("Uncheck ALL"));
+ ui->uncheckButton->setToolTip(
+ _("Cancel all checked items in the current tab at once."));
+ ui->checkALLButton->setText(_("Check ALL"));
+ ui->checkALLButton->setToolTip(
+ _("Check all items in the current tab at once"));
}
void KeyList::addListGroupTab(
@@ -214,17 +243,14 @@ void KeyList::setChecked(const KeyIdArgsListPtr& keyIds,
}
}
-void KeyList::setChecked(const KeyIdArgsListPtr& keyIds) {
- if (ui->keyGroupTab->size().isEmpty()) return;
+void KeyList::setChecked(KeyIdArgsListPtr key_ids) {
auto key_list = qobject_cast<QTableWidget*>(ui->keyGroupTab->currentWidget());
- const auto& buffered_keys =
- mKeyTables[ui->keyGroupTab->currentIndex()].buffered_keys;
-
- if (!keyIds->empty()) {
- for (int i = 0; i < key_list->rowCount(); i++) {
- if (std::find(keyIds->begin(), keyIds->end(), buffered_keys[i].id()) !=
- keyIds->end()) {
- key_list->item(i, 0)->setCheckState(Qt::Checked);
+ if (key_list == nullptr) return;
+ if (!mKeyTables.empty()) {
+ for (auto& key_table : mKeyTables) {
+ if (key_table.key_list == key_list) {
+ key_table.SetChecked(std::move(key_ids));
+ break;
}
}
}
@@ -364,7 +390,7 @@ void KeyList::dragEnterEvent(QDragEnterEvent* event) {
void KeyList::importKeys(const QByteArray& inBuffer) {
auto std_buffer = std::make_unique<ByteArray>(inBuffer.toStdString());
GpgImportInformation result =
- GpgKeyImportExportor::GetInstance(_m_key_list_id)
+ GpgKeyImportExporter::GetInstance(_m_key_list_id)
.ImportKey(std::move(std_buffer));
new KeyImportDetailDialog(result, false, this);
}
@@ -447,31 +473,56 @@ void KeyList::slotSyncWithKeyServer() {
});
}
-KeyIdArgsListPtr KeyTable::GetChecked() {
- auto ret = std::make_unique<KeyIdArgsList>();
- for (int i = 0; i < key_list->rowCount(); i++) {
- if (key_list->item(i, 0)->checkState() == Qt::Checked) {
- ret->push_back(buffered_keys[i].id());
+void KeyList::slotUncheckALL() {
+ auto key_list = qobject_cast<QTableWidget*>(ui->keyGroupTab->currentWidget());
+ if (key_list == nullptr) return;
+ if (!mKeyTables.empty()) {
+ for (auto& key_table : mKeyTables) {
+ if (key_table.key_list == key_list) {
+ key_table.UncheckALL();
+ break;
+ }
}
}
- return ret;
}
-void KeyTable::SetChecked(const KeyIdArgsListPtr& key_ids) {
- if (!key_ids->empty()) {
- for (int i = 0; i < key_list->rowCount(); i++) {
- if (std::find(key_ids->begin(), key_ids->end(), buffered_keys[i].id()) !=
- key_ids->end()) {
- key_list->item(i, 0)->setCheckState(Qt::Checked);
+void KeyList::slotCheckALL() {
+ auto key_list = qobject_cast<QTableWidget*>(ui->keyGroupTab->currentWidget());
+ if (key_list == nullptr) return;
+ if (!mKeyTables.empty()) {
+ for (auto& key_table : mKeyTables) {
+ if (key_table.key_list == key_list) {
+ key_table.CheckALL();
+ break;
}
}
}
}
+KeyIdArgsListPtr& KeyTable::GetChecked() {
+ LOG(INFO) << "called";
+ if (checked_key_ids_ == nullptr)
+ checked_key_ids_ = std::make_unique<KeyIdArgsList>();
+ auto& ret = checked_key_ids_;
+ for (int i = 0; i < key_list->rowCount(); i++) {
+ auto key_id = buffered_keys[i].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);
+ }
+ }
+ return ret;
+}
+
+void KeyTable::SetChecked(KeyIdArgsListPtr key_ids) {
+ LOG(INFO) << "called";
+ checked_key_ids_ = std::move(key_ids);
+}
+
void KeyTable::Refresh(KeyLinkListPtr m_keys) {
LOG(INFO) << "Called";
- auto checked_key_list = GetChecked();
+ auto& checked_key_list = GetChecked();
// while filling the table, sort enabled causes errors
key_list->setSortingEnabled(false);
@@ -532,6 +583,11 @@ void KeyTable::Refresh(KeyLinkListPtr m_keys) {
if (it->is_private_key() && !it->has_master_key()) {
type_steam << "#";
}
+
+ if(it->HasCardKey()) {
+ type_steam << "^";
+ }
+
auto* tmp1 = new QTableWidgetItem(type_str);
key_list->setItem(row_index, 1, tmp1);
@@ -577,8 +633,27 @@ void KeyTable::Refresh(KeyLinkListPtr m_keys) {
++row_index;
}
- SetChecked(checked_key_list);
+ if (!checked_key_list->empty()) {
+ for (int i = 0; i < key_list->rowCount(); i++) {
+ if (std::find(checked_key_list->begin(), checked_key_list->end(),
+ buffered_keys[i].id()) != checked_key_list->end()) {
+ key_list->item(i, 0)->setCheckState(Qt::Checked);
+ }
+ }
+ }
LOG(INFO) << "End";
}
+
+void KeyTable::UncheckALL() const {
+ for (int i = 0; i < key_list->rowCount(); i++) {
+ key_list->item(i, 0)->setCheckState(Qt::Unchecked);
+ }
+}
+
+void KeyTable::CheckALL() const {
+ for (int i = 0; i < key_list->rowCount(); i++) {
+ key_list->item(i, 0)->setCheckState(Qt::Checked);
+ }
+}
} // namespace GpgFrontend::UI
diff --git a/src/ui/widgets/KeyList.h b/src/ui/widgets/KeyList.h
index 617bb274..4b41decd 100644
--- a/src/ui/widgets/KeyList.h
+++ b/src/ui/widgets/KeyList.h
@@ -53,12 +53,24 @@ struct KeyListColumn {
static constexpr InfoType FingerPrint = 1 << 5;
};
+struct KeyMenuAbility {
+ using AbilityType = unsigned int;
+
+ static constexpr AbilityType ALL = ~0;
+ static constexpr AbilityType NONE = 0;
+ static constexpr AbilityType REFRESH = 1 << 0;
+ static constexpr AbilityType SYNC_PUBLIC_KEY = 1 << 1;
+ static constexpr AbilityType UNCHECK_ALL = 1 << 3;
+ static constexpr AbilityType CHECK_ALL = 1 << 5;
+};
+
struct KeyTable {
QTableWidget* key_list;
KeyListRow::KeyType select_type;
KeyListColumn::InfoType info_type;
std::vector<GpgKey> buffered_keys;
std::function<bool(const GpgKey&)> filter;
+ KeyIdArgsListPtr checked_key_ids_;
KeyTable(
QTableWidget* _key_list, KeyListRow::KeyType _select_type,
@@ -73,16 +85,21 @@ struct KeyTable {
void Refresh(KeyLinkListPtr m_keys = nullptr);
- KeyIdArgsListPtr GetChecked();
+ KeyIdArgsListPtr& GetChecked();
+
+ void UncheckALL() const;
+
+ void CheckALL() const;
- void SetChecked(const KeyIdArgsListPtr& key_ids);
+ void SetChecked(KeyIdArgsListPtr key_ids);
};
class KeyList : public QWidget {
Q_OBJECT
public:
- explicit KeyList(bool menu, QWidget* parent = nullptr);
+ explicit KeyList(KeyMenuAbility::AbilityType menu_ability,
+ QWidget* parent = nullptr);
void addListGroupTab(
const QString& name,
@@ -102,7 +119,7 @@ class KeyList : public QWidget {
static KeyIdArgsListPtr getChecked(const KeyTable& key_table);
KeyIdArgsListPtr getPrivateChecked();
KeyIdArgsListPtr getAllPrivateKeys();
- void setChecked(const KeyIdArgsListPtr& keyIds);
+ void setChecked(KeyIdArgsListPtr key_ids);
static void setChecked(const KeyIdArgsListPtr& keyIds,
const KeyTable& key_table);
KeyIdArgsListPtr getSelected();
@@ -123,6 +140,8 @@ class KeyList : public QWidget {
private:
void init();
void importKeys(const QByteArray& inBuffer);
+ void slotUncheckALL();
+ void slotCheckALL();
static int key_list_id;
int _m_key_list_id;
@@ -134,7 +153,7 @@ class KeyList : public QWidget {
QMenu* popupMenu{};
GpgFrontend::KeyLinkListPtr _buffered_keys_list;
std::function<void(const GpgKey&, QWidget*)> mAction = nullptr;
- bool menu_status = false;
+ KeyMenuAbility::AbilityType menu_ability_ = KeyMenuAbility::ALL;
private slots:
diff --git a/src/ui/widgets/SignersPicker.cpp b/src/ui/widgets/SignersPicker.cpp
index e769d05c..b035bf19 100644
--- a/src/ui/widgets/SignersPicker.cpp
+++ b/src/ui/widgets/SignersPicker.cpp
@@ -24,31 +24,31 @@
#include "ui/widgets/SignersPicker.h"
+#include "ui/widgets/KeyList.h"
+
namespace GpgFrontend::UI {
SignersPicker::SignersPicker(QWidget* parent) : QDialog(parent) {
- auto confirmButton = new QPushButton(_("Confirm"));
- connect(confirmButton, SIGNAL(clicked(bool)), this, SLOT(accept()));
+ auto confirm_button = new QPushButton(_("Confirm"));
+ connect(confirm_button, SIGNAL(clicked(bool)), this, SLOT(accept()));
/*Setup KeyList*/
- mKeyList = new KeyList(false, this);
- mKeyList->addListGroupTab(
+ key_list_ = new KeyList(false, this);
+ key_list_->addListGroupTab(
_("Signers"), KeyListRow::ONLY_SECRET_KEY,
KeyListColumn::NAME | KeyListColumn::EmailAddress | KeyListColumn::Usage,
- [](const GpgKey& key) -> bool {
- if (!key.CanSignActual())
- return false;
- else
- return true;
- });
- mKeyList->slotRefresh();
+ [](const GpgKey& key) -> bool { return key.CanSignActual(); });
+ key_list_->slotRefresh();
auto* vbox2 = new QVBoxLayout();
vbox2->addWidget(new QLabel(QString(_("Select Signer(s)")) + ": "));
- vbox2->addWidget(mKeyList);
+ vbox2->addWidget(key_list_);
vbox2->addWidget(new QLabel(
- _("If any key is selected, the default key will be used for signing.")));
- vbox2->addWidget(confirmButton);
+ QString(
+ _("Please select one or more private keys you use for signing.")) +
+ "\n" +
+ _("If no key is selected, the default key will be used for signing.")));
+ vbox2->addWidget(confirm_button);
vbox2->addStretch(0);
setLayout(vbox2);
@@ -62,7 +62,7 @@ SignersPicker::SignersPicker(QWidget* parent) : QDialog(parent) {
}
GpgFrontend::KeyIdArgsListPtr SignersPicker::getCheckedSigners() {
- return mKeyList->getPrivateChecked();
+ return key_list_->getPrivateChecked();
}
} // namespace GpgFrontend::UI
diff --git a/src/ui/widgets/SignersPicker.h b/src/ui/widgets/SignersPicker.h
index 055b6ef6..08972a76 100644
--- a/src/ui/widgets/SignersPicker.h
+++ b/src/ui/widgets/SignersPicker.h
@@ -25,12 +25,12 @@
#ifndef GPGFRONTEND_ZH_CN_TS_SIGNERSPIRCKER_H
#define GPGFRONTEND_ZH_CN_TS_SIGNERSPIRCKER_H
-#include "GpgFrontend.h"
-#include "gpg/GpgContext.h"
-#include "ui/widgets/KeyList.h"
+#include "GpgFrontendUI.h"
namespace GpgFrontend::UI {
+class KeyList;
+
class SignersPicker : public QDialog {
Q_OBJECT
@@ -40,7 +40,7 @@ class SignersPicker : public QDialog {
GpgFrontend::KeyIdArgsListPtr getCheckedSigners();
private:
- KeyList* mKeyList;
+ KeyList* key_list_;
};
} // namespace GpgFrontend::UI
diff --git a/src/ui/widgets/TextEdit.cpp b/src/ui/widgets/TextEdit.cpp
index 036c69d4..be6ec181 100644
--- a/src/ui/widgets/TextEdit.cpp
+++ b/src/ui/widgets/TextEdit.cpp
@@ -55,8 +55,8 @@ void TextEdit::slotNewTab() {
tabWidget->setTabIcon(index, QIcon(":file.png"));
tabWidget->setCurrentIndex(tabWidget->count() - 1);
page->getTextPage()->setFocus();
- connect(page->getTextPage()->document(), SIGNAL(modificationChanged(bool)),
- this, SLOT(slotShowModified()));
+ connect(page->getTextPage()->document(), &QTextDocument::modificationChanged,
+ this, &TextEdit::slotShowModified);
}
void TextEdit::slotNewHelpTab(const QString& title, const QString& path) const {
@@ -81,6 +81,10 @@ void TextEdit::slotOpenFile(QString& path) {
auto result = file.open(QIODevice::ReadOnly | QIODevice::Text);
if (result) {
auto* page = new EditorPage(path);
+ connect(page->getTextPage()->document(),
+ &QTextDocument::modificationChanged, this,
+ &TextEdit::slotShowModified);
+
QApplication::setOverrideCursor(Qt::WaitCursor);
auto index = tabWidget->addTab(page, strippedName(path));
tabWidget->setTabIcon(index, QIcon(":file.png"));
@@ -295,20 +299,20 @@ bool TextEdit::maybeSaveCurrentTab(bool askToSave) {
bool TextEdit::maybeSaveAnyTab() {
// get a list of all unsaved documents and their tabids
- QHash<int, QString> unsavedDocs = this->unsavedDocuments();
+ QHash<int, QString> unsaved_docs = this->unsavedDocuments();
/*
* no unsaved documents, so app can be closed
*/
- if (unsavedDocs.empty()) {
+ if (unsaved_docs.empty()) {
return true;
}
/*
* only 1 unsaved document -> set modified tab as current
* and show normal unsaved doc dialog
*/
- if (unsavedDocs.size() == 1) {
- int modifiedTab = unsavedDocs.keys().at(0);
+ if (unsaved_docs.size() == 1) {
+ int modifiedTab = unsaved_docs.keys().at(0);
tabWidget->setCurrentIndex(modifiedTab);
return maybeSaveCurrentTab(true);
}
@@ -316,11 +320,11 @@ bool TextEdit::maybeSaveAnyTab() {
/*
* more than one unsaved documents
*/
- if (unsavedDocs.size() > 1) {
- QHashIterator<int, QString> i(unsavedDocs);
+ if (unsaved_docs.size() > 1) {
+ QHashIterator<int, QString> i(unsaved_docs);
QuitDialog* dialog;
- dialog = new QuitDialog(this, unsavedDocs);
+ dialog = new QuitDialog(this, unsaved_docs);
int result = dialog->exec();
// if result is QDialog::Rejected, discard or cancel was clicked
@@ -429,8 +433,8 @@ void TextEdit::loadFile(const QString& fileName) {
// statusBar()->showMessage(_("File loaded"), 2000);
}
-QString TextEdit::strippedName(const QString& fullFileName) {
- return QFileInfo(fullFileName).fileName();
+QString TextEdit::strippedName(const QString& full_file_name) {
+ return QFileInfo(full_file_name).fileName();
}
void TextEdit::slotPrint() {
@@ -469,8 +473,8 @@ void TextEdit::slotShowModified() const {
void TextEdit::slotSwitchTabUp() const {
if (tabWidget->count() > 1) {
- int newindex = (tabWidget->currentIndex() + 1) % (tabWidget->count());
- tabWidget->setCurrentIndex(newindex);
+ int new_index = (tabWidget->currentIndex() + 1) % (tabWidget->count());
+ tabWidget->setCurrentIndex(new_index);
}
}
diff --git a/src/ui/widgets/TextEdit.h b/src/ui/widgets/TextEdit.h
index 3cff74e7..e877ccc1 100644
--- a/src/ui/widgets/TextEdit.h
+++ b/src/ui/widgets/TextEdit.h
@@ -185,7 +185,7 @@ class TextEdit : public QWidget {
* @param a filename path
* @return QString containing the filename
*/
- static QString strippedName(const QString& fullFileName);
+ static QString strippedName(const QString& full_file_name);
/**
* @brief
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 8a5859f4..cee1720b 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -11,10 +11,17 @@ add_executable(
${TEST_SOURCE}
)
-if(GPG_CORE)
+if (GPG_CORE)
target_link_libraries(${AppName} gpg_core)
-endif()
+endif ()
-target_link_libraries(${AppName} gtest gtest_main)
+if (GPG_STANDALONE_MODE)
+ file(COPY ${CMAKE_SOURCE_DIR}/test/gpg DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/ FOLLOW_SYMLINK_CHAIN)
+endif ()
+
+target_link_libraries(${AppName} ${Boost_LIBRARIES} gtest gtest_main)
+if (APPLE)
+ target_link_libraries(${AppName} intl)
+endif ()
add_test(AllTestsInGpgFrontend ${AppName})
diff --git a/test/GpgCoreTest.cpp b/test/GpgCoreTest.cpp
new file mode 100644
index 00000000..ab9dbf28
--- /dev/null
+++ b/test/GpgCoreTest.cpp
@@ -0,0 +1,28 @@
+/**
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "GpgFrontendTest.h"
+
+// Should be used once and once-only
+INITIALIZE_EASYLOGGINGPP
diff --git a/test/GpgCoreTestBasicOpera.cpp b/test/GpgCoreTestBasicOpera.cpp
index 40972982..283ceb82 100644
--- a/test/GpgCoreTestBasicOpera.cpp
+++ b/test/GpgCoreTestBasicOpera.cpp
@@ -31,18 +31,18 @@
#include "gpg/GpgConstants.h"
#include "gpg/function/BasicOperator.h"
#include "gpg/function/GpgKeyGetter.h"
-#include "gpg/model/GpgKey.h"
+#include "gpg/result_analyse/DecryptResultAnalyse.h"
using namespace GpgFrontend;
TEST_F(GpgCoreTest, CoreEncryptDecrTest) {
- auto encrpyt_key = GpgKeyGetter::GetInstance(default_channel)
+ auto encrypt_key = GpgKeyGetter::GetInstance(default_channel)
.GetPubkey("467F14220CE8DCF780CF4BAD8465C55B25C9B7D1");
ByteArray encrypt_text = "Hello GpgFrontend!";
ByteArrayPtr encr_out_data;
GpgEncrResult e_result;
- std::vector<GpgKey> keys;
- keys.push_back(std::move(encrpyt_key));
+ KeyListPtr keys = std::make_unique<KeyArgsList>();
+ keys->push_back(std::move(encrypt_key));
auto err =
BasicOperator::GetInstance(default_channel)
.Encrypt(std::move(keys), encrypt_text, encr_out_data, e_result);
@@ -59,14 +59,65 @@ TEST_F(GpgCoreTest, CoreEncryptDecrTest) {
ASSERT_EQ(*decr_out_data, encrypt_text);
}
+TEST_F(GpgCoreTest, CoreEncryptDecrTest_KeyNotFound_1) {
+ ByteArrayPtr encr_out_data = std::make_unique<ByteArray>(
+ "-----BEGIN PGP MESSAGE-----\n"
+ "\n"
+ "hQEMA6UM/S9sZ32MAQf9Fb6gp6nvgKTQBv2mmjXia6ODXYq6kNeLsPVzLCbHyWOs\n"
+ "0GDED11R1NksA3EQxFf4fzLkDpbo68r5bWy7c28c99Fr68IRET19Tw6Gu65MQezD\n"
+ "Rdzo1oVqmK9sfKqOT3+0S2H+suFYw5kfBztMZLVGGl9R9fOXdKcj0fqGs2br3e9D\n"
+ "ArBFqq07Bae2DD1J8mckWB2x9Uem4vjRiY+vEJcEdAS1N5xu1n7qzzyDgcRcS34X\n"
+ "PNBQeTrFMc2RS7mnip2DbyZVEjORobhguK6xZyqXXbvFacStGWDLptV3dcCn4JRO\n"
+ "dIORyt5wugqAtgE4qEGTvr/pJ/oXPw4Wve/trece/9I/AR38vW8ntVmDa/hV75iZ\n"
+ "4QGAhQ8grD4kq31GHXHUOmBX51XXW9SINmplC8elEx3R460EUZJjjb0OvTih+eZH\n"
+ "=8n2H\n"
+ "-----END PGP MESSAGE-----");
+
+ GpgDecrResult d_result;
+ ByteArrayPtr decr_out_data;
+ auto err = BasicOperator::GetInstance(default_channel)
+ .Decrypt(*encr_out_data, decr_out_data, d_result);
+ ASSERT_EQ(check_gpg_error_2_err_code(err), GPG_ERR_NO_SECKEY);
+ ASSERT_NE(d_result->recipients, nullptr);
+ ASSERT_EQ(std::string(d_result->recipients->keyid), "A50CFD2F6C677D8C");
+}
+
+TEST_F(GpgCoreTest, CoreEncryptDecrTest_KeyNotFound_ResultAnalyse) {
+ ByteArrayPtr encr_out_data = std::make_unique<ByteArray>(
+ "-----BEGIN PGP MESSAGE-----\n"
+ "\n"
+ "hQEMA6UM/S9sZ32MAQf9Fb6gp6nvgKTQBv2mmjXia6ODXYq6kNeLsPVzLCbHyWOs\n"
+ "0GDED11R1NksA3EQxFf4fzLkDpbo68r5bWy7c28c99Fr68IRET19Tw6Gu65MQezD\n"
+ "Rdzo1oVqmK9sfKqOT3+0S2H+suFYw5kfBztMZLVGGl9R9fOXdKcj0fqGs2br3e9D\n"
+ "ArBFqq07Bae2DD1J8mckWB2x9Uem4vjRiY+vEJcEdAS1N5xu1n7qzzyDgcRcS34X\n"
+ "PNBQeTrFMc2RS7mnip2DbyZVEjORobhguK6xZyqXXbvFacStGWDLptV3dcCn4JRO\n"
+ "dIORyt5wugqAtgE4qEGTvr/pJ/oXPw4Wve/trece/9I/AR38vW8ntVmDa/hV75iZ\n"
+ "4QGAhQ8grD4kq31GHXHUOmBX51XXW9SINmplC8elEx3R460EUZJjjb0OvTih+eZH\n"
+ "=8n2H\n"
+ "-----END PGP MESSAGE-----");
+
+ GpgDecrResult d_result;
+ ByteArrayPtr decr_out_data;
+ auto err = BasicOperator::GetInstance(default_channel)
+ .Decrypt(*encr_out_data, decr_out_data, d_result);
+ ASSERT_EQ(check_gpg_error_2_err_code(err), GPG_ERR_NO_SECKEY);
+ ASSERT_NE(d_result->recipients, nullptr);
+ ASSERT_EQ(std::string(d_result->recipients->keyid), "A50CFD2F6C677D8C");
+
+ DecryptResultAnalyse analyse{err, d_result};
+ analyse.analyse();
+ ASSERT_EQ(analyse.getStatus(), -1);
+ ASSERT_FALSE(analyse.getResultReport().empty());
+}
+
TEST_F(GpgCoreTest, CoreSignVerifyNormalTest) {
- auto encrpyt_key = GpgKeyGetter::GetInstance(default_channel)
+ auto encrypt_key = GpgKeyGetter::GetInstance(default_channel)
.GetPubkey("467F14220CE8DCF780CF4BAD8465C55B25C9B7D1");
ByteArray sign_text = "Hello GpgFrontend!";
ByteArrayPtr sign_out_data;
GpgSignResult s_result;
- std::vector<GpgKey> keys;
- keys.push_back(std::move(encrpyt_key));
+ KeyListPtr keys = std::make_unique<KeyArgsList>();
+ keys->push_back(std::move(encrypt_key));
auto err = BasicOperator::GetInstance(default_channel)
.Sign(std::move(keys), sign_text, sign_out_data,
GPGME_SIG_MODE_NORMAL, s_result);
@@ -85,13 +136,13 @@ TEST_F(GpgCoreTest, CoreSignVerifyNormalTest) {
}
TEST_F(GpgCoreTest, CoreSignVerifyDetachTest) {
- auto encrpyt_key = GpgKeyGetter::GetInstance(default_channel)
+ auto encrypt_key = GpgKeyGetter::GetInstance(default_channel)
.GetPubkey("467F14220CE8DCF780CF4BAD8465C55B25C9B7D1");
ByteArray sign_text = "Hello GpgFrontend!";
ByteArrayPtr sign_out_data;
GpgSignResult s_result;
- std::vector<GpgKey> keys;
- keys.push_back(std::move(encrpyt_key));
+ KeyListPtr keys = std::make_unique<KeyArgsList>();
+ keys->push_back(std::move(encrypt_key));
auto err = BasicOperator::GetInstance(default_channel)
.Sign(std::move(keys), sign_text, sign_out_data,
GPGME_SIG_MODE_DETACH, s_result);
@@ -114,8 +165,8 @@ TEST_F(GpgCoreTest, CoreSignVerifyClearTest) {
ByteArray sign_text = "Hello GpgFrontend!";
ByteArrayPtr sign_out_data;
GpgSignResult s_result;
- std::vector<GpgKey> keys;
- keys.push_back(std::move(sign_key));
+ KeyListPtr keys = std::make_unique<KeyArgsList>();
+ keys->push_back(std::move(sign_key));
auto err = BasicOperator::GetInstance(default_channel)
.Sign(std::move(keys), sign_text, sign_out_data,
GPGME_SIG_MODE_CLEAR, s_result);
@@ -134,12 +185,12 @@ TEST_F(GpgCoreTest, CoreSignVerifyClearTest) {
}
TEST_F(GpgCoreTest, CoreEncryptSignDecrVerifyTest) {
- auto encrpyt_key = GpgKeyGetter::GetInstance(default_channel)
+ auto encrypt_key = GpgKeyGetter::GetInstance(default_channel)
.GetPubkey("467F14220CE8DCF780CF4BAD8465C55B25C9B7D1");
auto sign_key = GpgKeyGetter::GetInstance(default_channel)
.GetKey("8933EB283A18995F45D61DAC021D89771B680FFB");
// Question?
- // ASSERT_FALSE(encrpyt_key.is_private_key());
+ // ASSERT_FALSE(encrypt_key.is_private_key());
ASSERT_TRUE(sign_key.is_private_key());
ASSERT_TRUE(sign_key.CanSignActual());
ByteArray encrypt_text = "Hello GpgFrontend!";
@@ -147,9 +198,10 @@ TEST_F(GpgCoreTest, CoreEncryptSignDecrVerifyTest) {
GpgEncrResult e_result;
GpgSignResult s_result;
- std::vector<GpgKey> keys, sign_keys;
- keys.push_back(std::move(encrpyt_key));
- sign_keys.push_back(std::move(sign_key));
+ KeyListPtr keys = std::make_unique<KeyArgsList>(),
+ sign_keys = std::make_unique<KeyArgsList>();
+ keys->push_back(std::move(encrypt_key));
+ sign_keys->push_back(std::move(sign_key));
auto err = BasicOperator::GetInstance(default_channel)
.EncryptSign(std::move(keys), std::move(sign_keys),
diff --git a/test/GpgCoreTestImportExport.cpp b/test/GpgCoreTestImportExport.cpp
index 9d01cc3e..1e226247 100644
--- a/test/GpgCoreTestImportExport.cpp
+++ b/test/GpgCoreTestImportExport.cpp
@@ -28,7 +28,7 @@
#include "GpgFrontendTest.h"
#include "gpg/GpgConstants.h"
#include "gpg/function/GpgKeyGetter.h"
-#include "gpg/function/GpgKeyImportExportor.h"
+#include "gpg/function/GpgKeyImportExporter.h"
#include "gpg/model/GpgKey.h"
TEST_F(GpgCoreTest, CoreExportSecretTest) {} \ No newline at end of file
diff --git a/test/GpgCoreTestKeyModel.cpp b/test/GpgCoreTestKeyModel.cpp
index 4e85a8cf..79cd7dcd 100644
--- a/test/GpgCoreTestKeyModel.cpp
+++ b/test/GpgCoreTestKeyModel.cpp
@@ -25,15 +25,11 @@
#include "GpgFrontendTest.h"
#include "gpg/function/GpgKeyGetter.h"
-// Should be used once and once-only
-INITIALIZE_EASYLOGGINGPP
-
TEST_F(GpgCoreTest, CoreInitTest) {
auto& ctx = GpgFrontend::GpgContext::GetInstance(default_channel);
auto& ctx_default = GpgFrontend::GpgContext::GetInstance();
ASSERT_TRUE(ctx.good());
ASSERT_TRUE(ctx_default.good());
- ASSERT_EQ(ctx_default.GetInfo().DatabasePath, "default");
}
TEST_F(GpgCoreTest, GpgDataTest) {
@@ -75,18 +71,19 @@ TEST_F(GpgCoreTest, GpgKeyTest) {
ASSERT_EQ(key.email(), "[email protected]");
ASSERT_EQ(key.id(), "81704859182661FB");
ASSERT_EQ(key.fpr(), "9490795B78F8AFE9F93BD09281704859182661FB");
- ASSERT_EQ(key.expires(), boost::gregorian::from_simple_string("2023-09-05"));
+ ASSERT_EQ(key.expires(),
+ boost::posix_time::from_iso_string("20230905T040000"));
ASSERT_EQ(key.pubkey_algo(), "RSA");
ASSERT_EQ(key.length(), 3072);
ASSERT_EQ(key.last_update(),
- boost::gregorian::from_simple_string("1970-01-01"));
+ boost::posix_time::from_iso_string("19700101T000000"));
ASSERT_EQ(key.create_time(),
- boost::gregorian::from_simple_string("2021-09-05"));
+ boost::posix_time::from_iso_string("20210905T060153"));
ASSERT_EQ(key.owner_trust(), "Unknown");
using namespace boost::posix_time;
- ASSERT_EQ(key.expired(), key.expires() < second_clock::local_time().date());
+ ASSERT_EQ(key.expired(), key.expires() < second_clock::local_time());
}
TEST_F(GpgCoreTest, GpgSubKeyTest) {
@@ -100,7 +97,7 @@ TEST_F(GpgCoreTest, GpgSubKeyTest) {
ASSERT_FALSE(sub_key.revoked());
ASSERT_FALSE(sub_key.disabled());
ASSERT_EQ(sub_key.timestamp(),
- boost::gregorian::from_simple_string("2021-09-05"));
+ boost::posix_time::from_iso_string("20210905T060153"));
ASSERT_FALSE(sub_key.is_cardkey());
ASSERT_TRUE(sub_key.is_private_key());
@@ -112,11 +109,11 @@ TEST_F(GpgCoreTest, GpgSubKeyTest) {
ASSERT_FALSE(sub_key.can_authenticate());
ASSERT_FALSE(sub_key.can_sign());
ASSERT_TRUE(sub_key.can_encrypt());
- ASSERT_EQ(key.expires(), boost::gregorian::from_simple_string("2023-09-05"));
+ ASSERT_EQ(key.expires(),
+ boost::posix_time::from_iso_string("20230905T040000"));
using namespace boost::posix_time;
- ASSERT_EQ(sub_key.expired(),
- sub_key.expires() < second_clock::local_time().date());
+ ASSERT_EQ(sub_key.expired(), sub_key.expires() < second_clock::local_time());
}
TEST_F(GpgCoreTest, GpgUIDTest) {
diff --git a/test/GpgCoreTestKeyModelAlone.cpp b/test/GpgCoreTestKeyModelAlone.cpp
new file mode 100644
index 00000000..3d5bd175
--- /dev/null
+++ b/test/GpgCoreTestKeyModelAlone.cpp
@@ -0,0 +1,158 @@
+/**
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "GpgFrontendTest.h"
+#include "gpg/function/GpgKeyGetter.h"
+
+TEST_F(GpgCoreTest, CoreInitTestAlone) {
+ auto& ctx = GpgFrontend::GpgContext::GetInstance(gpg_alone_channel);
+ ASSERT_TRUE(ctx.good());
+}
+
+TEST_F(GpgCoreTest, GpgDataTestAlone) {
+ auto data_buff = std::string(
+ "cqEh8fyKWtmiXrW2zzlszJVGJrpXDDpzgP7ZELGxhfZYFi8rMrSVKDwrpFZBSWMG");
+
+ GpgFrontend::GpgData data(data_buff.data(), data_buff.size());
+
+ auto out_buffer = data.Read2Buffer();
+ ASSERT_EQ(out_buffer->size(), 64);
+}
+
+TEST_F(GpgCoreTest, GpgKeyFetchTestAlone) {
+ auto keys =
+ GpgFrontend::GpgKeyGetter::GetInstance(gpg_alone_channel).FetchKey();
+ ASSERT_EQ(keys->size(), 4);
+}
+
+TEST_F(GpgCoreTest, GpgKeyTestAlone) {
+ auto key = GpgFrontend::GpgKeyGetter::GetInstance(gpg_alone_channel)
+ .GetKey("9490795B78F8AFE9F93BD09281704859182661FB");
+ ASSERT_TRUE(key.good());
+ ASSERT_TRUE(key.is_private_key());
+ ASSERT_TRUE(key.has_master_key());
+
+ ASSERT_FALSE(key.disabled());
+ ASSERT_FALSE(key.revoked());
+
+ ASSERT_EQ(key.protocol(), "OpenPGP");
+
+ ASSERT_EQ(key.subKeys()->size(), 2);
+ ASSERT_EQ(key.uids()->size(), 1);
+
+ ASSERT_TRUE(key.can_certify());
+ ASSERT_TRUE(key.can_encrypt());
+ ASSERT_TRUE(key.can_sign());
+ ASSERT_FALSE(key.can_authenticate());
+ ASSERT_TRUE(key.CanEncrActual());
+ ASSERT_TRUE(key.CanEncrActual());
+ ASSERT_TRUE(key.CanSignActual());
+ ASSERT_FALSE(key.CanAuthActual());
+
+ ASSERT_EQ(key.name(), "GpgFrontendTest");
+ ASSERT_TRUE(key.comment().empty());
+ ASSERT_EQ(key.email(), "[email protected]");
+ ASSERT_EQ(key.id(), "81704859182661FB");
+ ASSERT_EQ(key.fpr(), "9490795B78F8AFE9F93BD09281704859182661FB");
+ ASSERT_EQ(key.expires(),
+ boost::posix_time::from_iso_string("20230905T040000"));
+ ASSERT_EQ(key.pubkey_algo(), "RSA");
+ ASSERT_EQ(key.length(), 3072);
+ ASSERT_EQ(key.last_update(),
+ boost::posix_time::from_iso_string("19700101T000000"));
+ ASSERT_EQ(key.create_time(),
+ boost::posix_time::from_iso_string("20210905T060153"));
+
+ ASSERT_EQ(key.owner_trust(), "Unknown");
+
+ using namespace boost::posix_time;
+ ASSERT_EQ(key.expired(), key.expires() < second_clock::local_time());
+}
+
+TEST_F(GpgCoreTest, GpgSubKeyTestAlone) {
+ auto key = GpgFrontend::GpgKeyGetter::GetInstance(gpg_alone_channel)
+ .GetKey("9490795B78F8AFE9F93BD09281704859182661FB");
+ auto sub_keys = key.subKeys();
+ ASSERT_EQ(sub_keys->size(), 2);
+
+ auto& sub_key = sub_keys->back();
+
+ ASSERT_FALSE(sub_key.revoked());
+ ASSERT_FALSE(sub_key.disabled());
+ ASSERT_EQ(sub_key.timestamp(),
+ boost::posix_time::from_iso_string("20210905T060153"));
+
+ ASSERT_FALSE(sub_key.is_cardkey());
+ ASSERT_TRUE(sub_key.is_private_key());
+ ASSERT_EQ(sub_key.id(), "2B36803235B5E25B");
+ ASSERT_EQ(sub_key.fpr(), "50D37E8F8EE7340A6794E0592B36803235B5E25B");
+ ASSERT_EQ(sub_key.length(), 3072);
+ ASSERT_EQ(sub_key.pubkey_algo(), "RSA");
+ ASSERT_FALSE(sub_key.can_certify());
+ ASSERT_FALSE(sub_key.can_authenticate());
+ ASSERT_FALSE(sub_key.can_sign());
+ ASSERT_TRUE(sub_key.can_encrypt());
+ ASSERT_EQ(key.expires(),
+ boost::posix_time::from_iso_string("20230905T040000"));
+
+ using namespace boost::posix_time;
+ ASSERT_EQ(sub_key.expired(), sub_key.expires() < second_clock::local_time());
+}
+
+TEST_F(GpgCoreTest, GpgUIDTestAlone) {
+ auto key = GpgFrontend::GpgKeyGetter::GetInstance(gpg_alone_channel)
+ .GetKey("9490795B78F8AFE9F93BD09281704859182661FB");
+ auto uids = key.uids();
+ ASSERT_EQ(uids->size(), 1);
+ auto& uid = uids->front();
+
+ ASSERT_EQ(uid.name(), "GpgFrontendTest");
+ ASSERT_TRUE(uid.comment().empty());
+ ASSERT_EQ(uid.email(), "[email protected]");
+ ASSERT_EQ(uid.uid(), "GpgFrontendTest <[email protected]>");
+ ASSERT_FALSE(uid.invalid());
+ ASSERT_FALSE(uid.revoked());
+}
+
+TEST_F(GpgCoreTest, GpgKeySignatureTestAlone) {
+ auto key = GpgFrontend::GpgKeyGetter::GetInstance(gpg_alone_channel)
+ .GetKey("9490795B78F8AFE9F93BD09281704859182661FB");
+ auto uids = key.uids();
+ ASSERT_EQ(uids->size(), 1);
+ auto& uid = uids->front();
+
+ // No key signature support
+ auto signatures = uid.signatures();
+ ASSERT_EQ(signatures->size(), 0);
+}
+
+TEST_F(GpgCoreTest, GpgKeyGetterTestAlone) {
+ auto key = GpgFrontend::GpgKeyGetter::GetInstance(gpg_alone_channel)
+ .GetKey("9490795B78F8AFE9F93BD09281704859182661FB");
+ ASSERT_TRUE(key.good());
+ auto keys =
+ GpgFrontend::GpgKeyGetter::GetInstance(gpg_alone_channel).FetchKey();
+ ASSERT_GE(keys->size(), secret_keys_.size());
+ ASSERT_TRUE(find(keys->begin(), keys->end(), key) != keys->end());
+}
diff --git a/test/GpgCoreTestKeygen.cpp b/test/GpgCoreTestKeygen.cpp
new file mode 100644
index 00000000..b703ee40
--- /dev/null
+++ b/test/GpgCoreTestKeygen.cpp
@@ -0,0 +1,128 @@
+/**
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "GpgFrontendTest.h"
+#include "gpg/GpgGenKeyInfo.h"
+#include "gpg/function/GpgKeyGetter.h"
+#include "gpg/function/GpgKeyOpera.h"
+
+TEST_F(GpgCoreTest, GenerateKeyTest) {
+ auto& key_opera = GpgFrontend::GpgKeyOpera::GetInstance(default_channel);
+ auto keygen_info = std::make_unique<GpgFrontend::GenKeyInfo>();
+ keygen_info->setName("foo");
+ keygen_info->setEmail("[email protected]");
+ keygen_info->setComment("");
+ keygen_info->setKeySize(1024);
+ keygen_info->setAlgo("rsa");
+ keygen_info->setNonExpired(true);
+ keygen_info->setNonPassPhrase(true);
+
+ GpgFrontend::GpgGenKeyResult result = nullptr;
+ auto err = GpgFrontend::check_gpg_error_2_err_code(
+ key_opera.GenerateKey(keygen_info, result));
+ ASSERT_EQ(err, GPG_ERR_NO_ERROR);
+
+ auto fpr = result->fpr;
+ ASSERT_FALSE(fpr == nullptr);
+
+ auto key =
+ GpgFrontend::GpgKeyGetter::GetInstance(default_channel).GetKey(fpr);
+ ASSERT_TRUE(key.good());
+ key_opera.DeleteKey(fpr);
+}
+
+TEST_F(GpgCoreTest, GenerateKeyTest_1) {
+ auto& key_opera = GpgFrontend::GpgKeyOpera::GetInstance(default_channel);
+ auto keygen_info = std::make_unique<GpgFrontend::GenKeyInfo>();
+ keygen_info->setName("foo");
+ keygen_info->setEmail("[email protected]");
+ keygen_info->setComment("hello gpgfrontend");
+ keygen_info->setAlgo("rsa");
+ keygen_info->setKeySize(4096);
+ keygen_info->setNonExpired(false);
+ keygen_info->setExpired(boost::posix_time::second_clock::local_time() +
+ boost::posix_time::hours(24));
+ keygen_info->setNonPassPhrase(false);
+
+ GpgFrontend::GpgGenKeyResult result = nullptr;
+ auto err = GpgFrontend::check_gpg_error_2_err_code(
+ key_opera.GenerateKey(keygen_info, result));
+ ASSERT_EQ(err, GPG_ERR_NO_ERROR);
+
+ auto fpr = result->fpr;
+ ASSERT_FALSE(fpr == nullptr);
+
+ auto key =
+ GpgFrontend::GpgKeyGetter::GetInstance(default_channel).GetKey(fpr);
+ ASSERT_TRUE(key.good());
+ key_opera.DeleteKey(fpr);
+}
+
+TEST_F(GpgCoreTest, GenerateKeyTest_4) {
+ auto& key_opera = GpgFrontend::GpgKeyOpera::GetInstance(default_channel);
+ auto keygen_info = std::make_unique<GpgFrontend::GenKeyInfo>();
+ keygen_info->setName("foo");
+ keygen_info->setEmail("[email protected]");
+ keygen_info->setComment("");
+ keygen_info->setAlgo("dsa");
+ keygen_info->setNonExpired(true);
+ keygen_info->setNonPassPhrase(false);
+
+ GpgFrontend::GpgGenKeyResult result = nullptr;
+ auto err = GpgFrontend::check_gpg_error_2_err_code(
+ key_opera.GenerateKey(keygen_info, result));
+ ASSERT_EQ(err, GPG_ERR_NO_ERROR);
+
+ auto fpr = result->fpr;
+ ASSERT_FALSE(fpr == nullptr);
+
+ auto key =
+ GpgFrontend::GpgKeyGetter::GetInstance(default_channel).GetKey(fpr);
+ ASSERT_TRUE(key.good());
+ key_opera.DeleteKey(fpr);
+}
+
+TEST_F(GpgCoreTest, GenerateKeyTest_5) {
+ auto& key_opera = GpgFrontend::GpgKeyOpera::GetInstance(default_channel);
+ auto keygen_info = std::make_unique<GpgFrontend::GenKeyInfo>();
+ keygen_info->setName("foo");
+ keygen_info->setEmail("[email protected]");
+ keygen_info->setComment("");
+ keygen_info->setAlgo("ed25519");
+ keygen_info->setNonExpired(true);
+ keygen_info->setNonPassPhrase(false);
+
+ GpgFrontend::GpgGenKeyResult result = nullptr;
+ auto err = GpgFrontend::check_gpg_error_2_err_code(
+ key_opera.GenerateKey(keygen_info, result));
+ ASSERT_EQ(err, GPG_ERR_NO_ERROR);
+
+ auto fpr = result->fpr;
+ ASSERT_FALSE(fpr == nullptr);
+
+ auto key =
+ GpgFrontend::GpgKeyGetter::GetInstance(default_channel).GetKey(fpr);
+ ASSERT_TRUE(key.good());
+ key_opera.DeleteKey(fpr);
+}
diff --git a/test/GpgCoreTestKeygenAlone.cpp b/test/GpgCoreTestKeygenAlone.cpp
new file mode 100644
index 00000000..4a725ba7
--- /dev/null
+++ b/test/GpgCoreTestKeygenAlone.cpp
@@ -0,0 +1,156 @@
+/**
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "GpgFrontendTest.h"
+#include "gpg/GpgGenKeyInfo.h"
+#include "gpg/function/GpgKeyGetter.h"
+#include "gpg/function/GpgKeyOpera.h"
+
+TEST_F(GpgCoreTest, GenerateKeyTestAlone) {
+ auto& key_opera = GpgFrontend::GpgKeyOpera::GetInstance(gpg_alone_channel);
+ auto keygen_info = std::make_unique<GpgFrontend::GenKeyInfo>(false, true);
+ keygen_info->setName("foobar");
+ keygen_info->setEmail("[email protected]");
+ keygen_info->setComment("hello");
+ keygen_info->setAlgo("rsa");
+ keygen_info->setNonExpired(true);
+ keygen_info->setNonPassPhrase(true);
+
+ GpgFrontend::GpgGenKeyResult result = nullptr;
+ auto err = GpgFrontend::check_gpg_error_2_err_code(
+ key_opera.GenerateKey(keygen_info, result));
+ ASSERT_EQ(err, GPG_ERR_NO_ERROR);
+
+ auto fpr = result->fpr;
+ ASSERT_FALSE(fpr == nullptr);
+
+ auto key =
+ GpgFrontend::GpgKeyGetter::GetInstance(gpg_alone_channel).GetKey(fpr);
+ ASSERT_TRUE(key.good());
+ key_opera.DeleteKey(fpr);
+}
+
+TEST_F(GpgCoreTest, GenerateKeyTestAlone_1) {
+ auto& key_opera = GpgFrontend::GpgKeyOpera::GetInstance(gpg_alone_channel);
+ auto keygen_info = std::make_unique<GpgFrontend::GenKeyInfo>(false, true);
+ keygen_info->setName("foobar");
+ keygen_info->setEmail("[email protected]");
+ keygen_info->setComment("hello gpgfrontend");
+ keygen_info->setAlgo("rsa");
+ keygen_info->setNonExpired(false);
+ keygen_info->setPassPhrase("abcdefg");
+ keygen_info->setExpired(boost::posix_time::second_clock::local_time() +
+ boost::posix_time::hours(24));
+ keygen_info->setNonPassPhrase(false);
+
+ GpgFrontend::GpgGenKeyResult result = nullptr;
+ auto err = GpgFrontend::check_gpg_error_2_err_code(
+ key_opera.GenerateKey(keygen_info, result));
+ ASSERT_EQ(err, GPG_ERR_NO_ERROR);
+
+ auto fpr = result->fpr;
+ ASSERT_FALSE(fpr == nullptr);
+
+ auto key =
+ GpgFrontend::GpgKeyGetter::GetInstance(gpg_alone_channel).GetKey(fpr);
+ ASSERT_TRUE(key.good());
+ key_opera.DeleteKey(fpr);
+}
+
+TEST_F(GpgCoreTest, GenerateKeyTestAlone_2) {
+ auto& key_opera = GpgFrontend::GpgKeyOpera::GetInstance(gpg_alone_channel);
+ auto keygen_info = std::make_unique<GpgFrontend::GenKeyInfo>(false, true);
+ keygen_info->setName("foobar");
+ keygen_info->setEmail("[email protected]");
+ keygen_info->setComment("hi");
+ keygen_info->setAlgo("rsa");
+ keygen_info->setKeySize(3072);
+ keygen_info->setNonExpired(true);
+ keygen_info->setNonPassPhrase(false);
+ keygen_info->setPassPhrase("abcdefg");
+
+ GpgFrontend::GpgGenKeyResult result = nullptr;
+ auto err = GpgFrontend::check_gpg_error_2_err_code(
+ key_opera.GenerateKey(keygen_info, result));
+ ASSERT_EQ(err, GPG_ERR_NO_ERROR);
+
+ auto fpr = result->fpr;
+ ASSERT_FALSE(fpr == nullptr);
+
+ auto key =
+ GpgFrontend::GpgKeyGetter::GetInstance(gpg_alone_channel).GetKey(fpr);
+ ASSERT_TRUE(key.good());
+ key_opera.DeleteKey(fpr);
+}
+
+TEST_F(GpgCoreTest, GenerateKeyTestAlone_3) {
+ auto& key_opera = GpgFrontend::GpgKeyOpera::GetInstance(gpg_alone_channel);
+ auto keygen_info = std::make_unique<GpgFrontend::GenKeyInfo>(false, true);
+ keygen_info->setName("foo");
+ keygen_info->setEmail("[email protected]");
+ keygen_info->setComment("hello");
+ keygen_info->setAlgo("rsa");
+ keygen_info->setKeySize(4096);
+ keygen_info->setNonExpired(true);
+ keygen_info->setNonPassPhrase(false);
+ keygen_info->setPassPhrase("abcdefg");
+
+ GpgFrontend::GpgGenKeyResult result = nullptr;
+ auto err = GpgFrontend::check_gpg_error_2_err_code(
+ key_opera.GenerateKey(keygen_info, result));
+ ASSERT_EQ(err, GPG_ERR_NO_ERROR);
+
+ auto fpr = result->fpr;
+ ASSERT_FALSE(fpr == nullptr);
+
+ auto key =
+ GpgFrontend::GpgKeyGetter::GetInstance(gpg_alone_channel).GetKey(fpr);
+ ASSERT_TRUE(key.good());
+ key_opera.DeleteKey(fpr);
+}
+
+TEST_F(GpgCoreTest, GenerateKeyTestAlone_4) {
+ auto& key_opera = GpgFrontend::GpgKeyOpera::GetInstance(gpg_alone_channel);
+ auto keygen_info = std::make_unique<GpgFrontend::GenKeyInfo>(false, true);
+ keygen_info->setName("foobar");
+ keygen_info->setEmail("[email protected]");
+ keygen_info->setComment("hello");
+ keygen_info->setAlgo("dsa");
+ keygen_info->setNonExpired(true);
+ keygen_info->setNonPassPhrase(false);
+ keygen_info->setPassPhrase("abcdefg");
+
+ GpgFrontend::GpgGenKeyResult result = nullptr;
+ auto err = GpgFrontend::check_gpg_error_2_err_code(
+ key_opera.GenerateKey(keygen_info, result));
+ ASSERT_EQ(err, GPG_ERR_NO_ERROR);
+
+ auto fpr = result->fpr;
+ ASSERT_FALSE(fpr == nullptr);
+
+ auto key =
+ GpgFrontend::GpgKeyGetter::GetInstance(gpg_alone_channel).GetKey(fpr);
+ ASSERT_TRUE(key.good());
+ key_opera.DeleteKey(fpr);
+} \ No newline at end of file
diff --git a/test/GpgFrontendTest.h b/test/GpgFrontendTest.h
index 181c513e..84476106 100644
--- a/test/GpgFrontendTest.h
+++ b/test/GpgFrontendTest.h
@@ -29,16 +29,18 @@
#include <gpg-error.h>
#include <gtest/gtest.h>
-#include <boost/date_time/gregorian/parsers.hpp>
+#include <boost/date_time.hpp>
#include <boost/dll.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>
+#include <libconfig.h++>
#include <memory>
#include <string>
#include <vector>
#include "gpg/GpgConstants.h"
-#include "gpg/function/GpgKeyImportExportor.h"
+#include "gpg/function/GpgKeyImportExporter.h"
+#include "gpg/function/GpgKeyOpera.h"
class GpgCoreTest : public ::testing::Test {
protected:
@@ -55,13 +57,24 @@ class GpgCoreTest : public ::testing::Test {
// Data File Directory Location
boost::filesystem::path data_path;
- int default_channel = 0;
+ const int default_channel = 0;
+
+ const int gpg_alone_channel = 512;
GpgCoreTest() = default;
- virtual ~GpgCoreTest() = default;
+ ~GpgCoreTest() override = default;
+
+ void SetUp() override {
+ el::Loggers::addFlag(el::LoggingFlag::AutoSpacing);
+ el::Configurations defaultConf;
+ defaultConf.setToDefault();
+ el::Loggers::reconfigureLogger("default", defaultConf);
+
+ defaultConf.setGlobally(el::ConfigurationType::Format,
+ "%datetime %level %func %msg");
+ el::Loggers::reconfigureLogger("default", defaultConf);
- virtual void SetUp() {
using namespace libconfig;
Config cfg;
ASSERT_NO_THROW(cfg.readFile(config_path.c_str()));
@@ -75,21 +88,42 @@ class GpgCoreTest : public ::testing::Test {
configure_independent_database(root);
+ configure_alone_gpg(root);
+
dealing_private_keys(root);
import_data();
+ import_data_alone();
}
- virtual void TearDown() {}
+ void TearDown() override {
+ auto key_ids = std::make_unique<GpgFrontend::KeyIdArgsList>();
+ key_ids->push_back("81704859182661FB");
+ key_ids->push_back("06F1C7E7240C94E8");
+ key_ids->push_back("8465C55B25C9B7D1");
+ key_ids->push_back("021D89771B680FFB");
+ GpgFrontend::GpgKeyOpera::GetInstance(default_channel)
+ .DeleteKeys(std::move(key_ids));
+ }
private:
void import_data() {
- GpgFrontend::GpgContext::GetInstance(default_channel)
- .SetPassphraseCb(GpgFrontend::GpgContext::test_passphrase_cb);
+ for (const auto& secret_key : secret_keys_) {
+ auto secret_key_copy =
+ std::make_unique<GpgFrontend::ByteArray>(*secret_key);
+ GpgFrontend::GpgKeyImportExporter::GetInstance(default_channel)
+ .ImportKey(std::move(secret_key_copy));
+ }
+ }
+
+ void import_data_alone() {
for (auto& secret_key : secret_keys_) {
- GpgFrontend::GpgKeyImportExportor::GetInstance(default_channel)
- .ImportKey(std::move(secret_key));
+ auto secret_key_copy =
+ std::make_unique<GpgFrontend::ByteArray>(*secret_key);
+ GpgFrontend::GpgKeyImportExporter::GetInstance(gpg_alone_channel)
+ .ImportKey(std::move(secret_key_copy));
}
}
+
void dealing_private_keys(const libconfig::Setting& root) {
if (root.exists("load_keys.private_keys")) {
auto& private_keys = root.lookup("load_keys.private_keys");
@@ -106,21 +140,60 @@ class GpgCoreTest : public ::testing::Test {
}
}
+ void configure_alone_gpg(const libconfig::Setting& root) {
+ bool alone_gpg = false;
+ if (root.exists("alone_gpg")) {
+ root.lookupValue("alone_gpg", alone_gpg);
+ if (alone_gpg && root.exists("alone_gpg")) {
+ std::string alone_gpg_path;
+ root.lookupValue("alone_gpg_path", alone_gpg_path);
+ auto gpg_path = parent_path / alone_gpg_path;
+
+ std::string relative_db_path;
+ root.lookupValue("alone_gpg_db_path", relative_db_path);
+ auto db_path = parent_path / relative_db_path;
+ if (!boost::filesystem::exists(db_path)) {
+ boost::filesystem::create_directory(db_path);
+ } else {
+ boost::filesystem::remove_all(db_path);
+ boost::filesystem::create_directory(db_path);
+ }
+ GpgFrontend::GpgContext::CreateInstance(
+ gpg_alone_channel,
+ [&]() -> std::unique_ptr<GpgFrontend::GpgContext> {
+ GpgFrontend::GpgContextInitArgs args;
+ args.gpg_alone = true;
+ args.independent_database = true;
+ args.db_path = db_path.string();
+ args.gpg_path = gpg_path.string();
+ args.test_mode = true;
+ return std::make_unique<GpgFrontend::GpgContext>(args);
+ });
+ }
+ }
+ }
+
void configure_independent_database(const libconfig::Setting& root) {
bool independent_database = false;
if (root.exists("independent_database")) {
root.lookupValue("independent_database", independent_database);
if (independent_database && root.exists("independent_db_path")) {
- default_channel = 1;
std::string relative_db_path;
root.lookupValue("independent_db_path", relative_db_path);
auto db_path = parent_path / relative_db_path;
if (!boost::filesystem::exists(db_path)) {
boost::filesystem::create_directory(db_path);
+ } else {
+ boost::filesystem::remove_all(db_path);
+ boost::filesystem::create_directory(db_path);
}
+
GpgFrontend::GpgContext::CreateInstance(
- 1,
- std::make_unique<GpgFrontend::GpgContext>(true, db_path.c_str()));
+ default_channel, [&]() -> std::unique_ptr<GpgFrontend::GpgContext> {
+ GpgFrontend::GpgContextInitArgs args;
+ args.test_mode = true;
+ return std::make_unique<GpgFrontend::GpgContext>(args);
+ });
}
}
}
diff --git a/test/conf/core.cfg b/test/conf/core.cfg
index 69395963..7a9b76d6 100644
--- a/test/conf/core.cfg
+++ b/test/conf/core.cfg
@@ -1,8 +1,11 @@
# core test configuration file
version = "1.0";
independent_database = true;
-independent_db_path = "db"
-data_path = "data"
+independent_db_path = "db";
+alone_gpg = true;
+alone_gpg_path = "gpg/gpg1";
+alone_gpg_db_path = "alone_db";
+data_path = "data";
load_keys =
{
private_keys = (
diff --git a/third_party/AppImageUpdate b/third_party/AppImageUpdate
deleted file mode 160000
-Subproject 1b97acc55c89f742d51c3849eb62eb58464d866
diff --git a/third_party/CMakeLists.txt b/third_party/CMakeLists.txt
index f7c031b7..01e8c2ca 100644
--- a/third_party/CMakeLists.txt
+++ b/third_party/CMakeLists.txt
@@ -1,4 +1,4 @@
-if (ESAY_LOGGING_PP)
+if (EASY_LOGGING_PP)
message(STATUS "Build easyloggingpp")
add_subdirectory(easyloggingpp)
endif ()
diff --git a/third_party/easyloggingpp/CMakeLists.txt b/third_party/easyloggingpp/CMakeLists.txt
index 9b96f9c4..40b4bd14 100644
--- a/third_party/easyloggingpp/CMakeLists.txt
+++ b/third_party/easyloggingpp/CMakeLists.txt
@@ -1,4 +1,11 @@
aux_source_directory(. EASY_LOGGING_CPP_SOURCE)
add_library(easy_logging_pp STATIC ${EASY_LOGGING_CPP_SOURCE})
-target_link_libraries(easy_logging_pp stdc++) \ No newline at end of file
+target_link_libraries(easy_logging_pp stdc++)
+if(XCODE_BUILD)
+set_target_properties(easy_logging_pp
+ PROPERTIES
+ ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}
+ LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}
+ LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE})
+endif() \ No newline at end of file
diff --git a/ui/EmailListEditor.ui b/ui/EmailListEditor.ui
new file mode 100644
index 00000000..5cc0ddef
--- /dev/null
+++ b/ui/EmailListEditor.ui
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>EmailListEditorDialog</class>
+ <widget class="QDialog" name="EmailListEditorDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>618</width>
+ <height>498</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Email List Editor</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QLabel" name="titleLabel">
+ <property name="text">
+ <string>Email List:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QListWidget" name="emaillistWidget">
+ <property name="editTriggers">
+ <set>QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed</set>
+ </property>
+ <property name="dragEnabled">
+ <bool>true</bool>
+ </property>
+ <property name="isWrapping" stdset="0">
+ <bool>false</bool>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="addEmailAddressButton">
+ <property name="text">
+ <string>Add An Email Address</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="tipsLabel">
+ <property name="text">
+ <string>Tips: You can double-click the email address in the edit list, or click the email to pop up the option menu.</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ <action name="actionDelete_Selected_Email_Address">
+ <property name="text">
+ <string>Delete Selected Email Address</string>
+ </property>
+ </action>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/ui/ExportKeyPackageDialog.ui b/ui/ExportKeyPackageDialog.ui
new file mode 100644
index 00000000..a40d0154
--- /dev/null
+++ b/ui/ExportKeyPackageDialog.ui
@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>exportKeyPackageDialog</class>
+ <widget class="QDialog" name="exportKeyPackageDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>527</width>
+ <height>385</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Export As Key Package</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="1" column="0">
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QLabel" name="nameLabel">
+ <property name="text">
+ <string>Key Package Name</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="gnerateNameButton">
+ <property name="text">
+ <string>Generate Key Package Name</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QLabel" name="nameValueLabel">
+ <property name="text">
+ <string>KeyPackage_0000</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Line" name="line_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QLabel" name="selectOutputPathLabel">
+ <property name="text">
+ <string>Output Path</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="setOutputPathButton">
+ <property name="text">
+ <string>Select Output Path</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QLabel" name="outputPathLabel">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Line" name="line">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QLabel" name="passphraseLabel">
+ <property name="text">
+ <string>Passphrase</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="generatePassphraseButton">
+ <property name="text">
+ <string>Generate and Save Passphrase</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QLabel" name="passphraseValueLabel">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Line" name="line_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="includeSecretKeyCheckBox">
+ <property name="text">
+ <string>Include secret key (Think twice before acting)</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="noPublicKeyCheckBox">
+ <property name="text">
+ <string>Exclude keys that do not have a private key</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="tipsLabel">
+ <property name="text">
+ <string>Tips: You can use Key Package to safely and conveniently transfer your public and private keys between devices.</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>exportKeyPackageDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>exportKeyPackageDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/ui/FilePage.ui b/ui/FilePage.ui
index 6d7f7d7a..cb4517b1 100644
--- a/ui/FilePage.ui
+++ b/ui/FilePage.ui
@@ -143,6 +143,61 @@
</layout>
</item>
</layout>
+ <action name="actionEncrypt">
+ <property name="text">
+ <string>Encrypt</string>
+ </property>
+ </action>
+ <action name="actionEncryptSign">
+ <property name="text">
+ <string>EncryptSign</string>
+ </property>
+ </action>
+ <action name="actionDecrypt">
+ <property name="text">
+ <string>Decrypt</string>
+ </property>
+ </action>
+ <action name="actionSign">
+ <property name="text">
+ <string>Sign</string>
+ </property>
+ </action>
+ <action name="actionVerify">
+ <property name="text">
+ <string>Verify</string>
+ </property>
+ </action>
+ <action name="actionOpenFile">
+ <property name="text">
+ <string>OpenFile</string>
+ </property>
+ </action>
+ <action name="actionRenameFile">
+ <property name="text">
+ <string>RenameFile</string>
+ </property>
+ </action>
+ <action name="actionDeleteFile">
+ <property name="text">
+ <string>DeleteFile</string>
+ </property>
+ </action>
+ <action name="actionCalculateHash">
+ <property name="text">
+ <string>CalculateHash</string>
+ </property>
+ </action>
+ <action name="actionMakeDirectory">
+ <property name="text">
+ <string>MakeDirectory</string>
+ </property>
+ </action>
+ <action name="actionCreateEmptyFile">
+ <property name="text">
+ <string>CreateEmptyFile</string>
+ </property>
+ </action>
</widget>
<resources>
<include location="../gpgfrontend.qrc"/>
diff --git a/ui/GeneralSettings.ui b/ui/GeneralSettings.ui
new file mode 100644
index 00000000..4bfb5f43
--- /dev/null
+++ b/ui/GeneralSettings.ui
@@ -0,0 +1,145 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>GeneralSettings</class>
+ <widget class="QWidget" name="GeneralSettings">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>643</width>
+ <height>656</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QGroupBox" name="longerKeyExpirationDateBox">
+ <property name="title">
+ <string>Longer Key Expiration Date</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="0" column="0">
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QCheckBox" name="longerKeyExpirationDateCheckBox">
+ <property name="text">
+ <string>Unlock key expiration date setting up to 30 years.</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">
+ <property name="text">
+ <string>Save checked private keys on exit and restore them on next start.</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="importConfirmationBox">
+ <property name="title">
+ <string>Confirm drag'n'drop key import</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_4">
+ <item row="0" column="0">
+ <layout class="QVBoxLayout" name="verticalLayout_4">
+ <item>
+ <widget class="QCheckBox" name="importConfirmationCheckBox">
+ <property name="text">
+ <string>Import files dropped on the Key List without confirmation.</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="asciiModeBox">
+ <property name="title">
+ <string>ASCII Mode</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_6">
+ <item row="0" column="0">
+ <layout class="QVBoxLayout" name="verticalLayout_6">
+ <item>
+ <widget class="QCheckBox" name="asciiModeCheckBox">
+ <property name="text">
+ <string>ASCII encoding is not used when file encrypting and signing.</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>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/ui/InfoBoard.ui b/ui/InfoBoard.ui
index 1aac29aa..1c87974b 100644
--- a/ui/InfoBoard.ui
+++ b/ui/InfoBoard.ui
@@ -32,6 +32,9 @@
<property name="sizeConstraint">
<enum>QLayout::SetNoConstraint</enum>
</property>
+ <property name="leftMargin">
+ <number>6</number>
+ </property>
<item alignment="Qt::AlignLeft">
<widget class="QWidget" name="horizontalWidget" native="true">
<property name="sizePolicy">
@@ -59,16 +62,6 @@
<property name="bottomMargin">
<number>0</number>
</property>
- <item alignment="Qt::AlignLeft">
- <widget class="QLabel" name="actionLabel">
- <property name="text">
- <string>Actions</string>
- </property>
- <property name="scaledContents">
- <bool>false</bool>
- </property>
- </widget>
- </item>
<item alignment="Qt::AlignRight">
<widget class="QPushButton" name="copyButton">
<property name="text">
@@ -83,7 +76,7 @@
</property>
</widget>
</item>
- <item alignment="Qt::AlignRight|Qt::AlignBottom">
+ <item>
<widget class="QPushButton" name="clearButton">
<property name="text">
<string>Clear</string>
diff --git a/ui/KeyList.ui b/ui/KeyList.ui
index 99932453..d24a2825 100644
--- a/ui/KeyList.ui
+++ b/ui/KeyList.ui
@@ -18,9 +18,9 @@
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QWidget" name="menuWidget" native="true">
- <layout class="QHBoxLayout" name="menu">
+ <layout class="QVBoxLayout" name="verticalLayout_3">
<property name="spacing">
- <number>0</number>
+ <number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
@@ -35,38 +35,49 @@
<number>0</number>
</property>
<item>
- <widget class="QLabel" name="keyListOperationsLabel">
- <property name="text">
- <string>Key List Menu: </string>
- </property>
- </widget>
- </item>
- <item alignment="Qt::AlignLeft">
- <widget class="QPushButton" name="refreshKeyListButton">
- <property name="text">
- <string>Refresh</string>
- </property>
- </widget>
- </item>
- <item alignment="Qt::AlignLeft">
- <widget class="QPushButton" name="syncButton">
- <property name="text">
- <string>Sync With Key Server</string>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>40</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QPushButton" name="refreshKeyListButton">
+ <property name="text">
+ <string>Refresh</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="syncButton">
+ <property name="text">
+ <string>Sync Public Key</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="uncheckButton">
+ <property name="text">
+ <string>Uncheck ALL</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="checkALLButton">
+ <property name="text">
+ <string>Check ALL</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
</item>
</layout>
</widget>
diff --git a/ui/NetworkSettings.ui b/ui/NetworkSettings.ui
new file mode 100644
index 00000000..9e27d11b
--- /dev/null
+++ b/ui/NetworkSettings.ui
@@ -0,0 +1,325 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>NetworkSettings</class>
+ <widget class="QWidget" name="NetworkSettings">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>549</width>
+ <height>727</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QGroupBox" name="proxyGroupBox">
+ <property name="title">
+ <string>Proxy</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="0" column="0">
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QCheckBox" name="enableProxyCheckBox">
+ <property name="text">
+ <string>Enable Proxy</string>
+ </property>
+ <property name="tristate">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="horizontalWidget_3" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_8">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="proxyTypeLabel">
+ <property name="text">
+ <string>Proxy Type</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="proxyTypeComboBox">
+ <property name="currentText">
+ <string>System Default</string>
+ </property>
+ <item>
+ <property name="text">
+ <string>System Default</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>HTTP</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Socks5</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="horizontalWidget" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="proxyServerAddressLabel">
+ <property name="text">
+ <string>Host Address</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="proxyServerAddressEdit">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="horizontalWidget_2" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="proxyServerPortLabel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Port</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="portSpin">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimum">
+ <number>1</number>
+ </property>
+ <property name="maximum">
+ <number>65535</number>
+ </property>
+ <property name="value">
+ <number>1080</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="horizontalWidget_4" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="usernameLabel">
+ <property name="text">
+ <string>Username</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="usernameEdit">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="horizontalWidget_5" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_5">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="passwordLabel">
+ <property name="text">
+ <string>Password</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="passwordEdit">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="capabilityGroupBox">
+ <property name="title">
+ <string>Network Capability</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_3">
+ <item row="2" column="0">
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <widget class="QCheckBox" name="forbidALLCheckBox">
+ <property name="text">
+ <string>Forbid all network connection.</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="prohibitUpdateCheck">
+ <property name="text">
+ <string>Prohibit checking for version updates when the program starts.</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="operationsGroupBox">
+ <property name="title">
+ <string>Operations</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_5">
+ <item row="0" column="0">
+ <layout class="QVBoxLayout" name="verticalLayout_5">
+ <item>
+ <widget class="QPushButton" name="checkProxyConnectionButton">
+ <property name="text">
+ <string>Check Proxy Connection</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/ui/ReceiveMailDialog.ui b/ui/ReceiveMailDialog.ui
new file mode 100644
index 00000000..61c23738
--- /dev/null
+++ b/ui/ReceiveMailDialog.ui
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ReceiveMailDialog</class>
+ <widget class="QDialog" name="ReceiveMailDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>643</width>
+ <height>657</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Receive Mail</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QTreeWidget" name="treeWidget">
+ <column>
+ <property name="text">
+ <string notr="true">1</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ <item>
+ <widget class="QListView" name="listView"/>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/ui/SendMailDialog.ui b/ui/SendMailDialog.ui
index 8eb004f7..d29a5f63 100644
--- a/ui/SendMailDialog.ui
+++ b/ui/SendMailDialog.ui
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>958</width>
- <height>607</height>
+ <width>995</width>
+ <height>760</height>
</rect>
</property>
<property name="cursor">
@@ -17,7 +17,7 @@
<enum>Qt::NoContextMenu</enum>
</property>
<property name="windowTitle">
- <string>Send Mail</string>
+ <string>New Message</string>
</property>
<property name="sizeGripEnabled">
<bool>false</bool>
@@ -80,6 +80,9 @@
<property name="text">
<string>CC</string>
</property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
</widget>
</item>
<item>
@@ -87,6 +90,9 @@
<property name="text">
<string>BCC</string>
</property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
</widget>
</item>
</layout>
@@ -96,7 +102,7 @@
<widget class="QWidget" name="horizontalWidget_4" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="spacing">
- <number>0</number>
+ <number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
@@ -113,7 +119,7 @@
<item>
<widget class="QLabel" name="recipientLabel">
<property name="text">
- <string>Recipient</string>
+ <string>Recipient(s)</string>
</property>
<property name="margin">
<number>5</number>
@@ -123,6 +129,13 @@
<item>
<widget class="QLineEdit" name="recipientEdit"/>
</item>
+ <item>
+ <widget class="QPushButton" name="recipientsEditButton">
+ <property name="text">
+ <string>Edit Recipients(s)</string>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
</item>
@@ -154,7 +167,7 @@
<item>
<widget class="QLabel" name="subjectLabel">
<property name="text">
- <string>Subject</string>
+ <string>Mail Subject</string>
</property>
<property name="margin">
<number>5</number>
@@ -168,6 +181,64 @@
</widget>
</item>
<item>
+ <widget class="QWidget" name="horizontalWidget_6" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_9">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="gpgOperaLabel">
+ <property name="text">
+ <string>GPG Operations</string>
+ </property>
+ <property name="margin">
+ <number>5</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="senderKeySelectButton">
+ <property name="text">
+ <string>Select Sender GPG Key</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="recipientKeySelectButton">
+ <property name="text">
+ <string>Select Recipient(s) GPG Key</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
<widget class="Line" name="line_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
@@ -178,7 +249,7 @@
<widget class="QWidget" name="ccInputWidget" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing">
- <number>0</number>
+ <number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
@@ -205,6 +276,13 @@
<item>
<widget class="QLineEdit" name="ccEdit"/>
</item>
+ <item>
+ <widget class="QPushButton" name="ccEditButton">
+ <property name="text">
+ <string>Edit CC(s)</string>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
</item>
@@ -212,7 +290,7 @@
<widget class="QWidget" name="bccInputWidget" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="spacing">
- <number>0</number>
+ <number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
@@ -239,6 +317,13 @@
<item>
<widget class="QLineEdit" name="bccEdit"/>
</item>
+ <item>
+ <widget class="QPushButton" name="bccEditButton">
+ <property name="text">
+ <string>Edit BCC(s)</string>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
</item>
@@ -260,6 +345,57 @@
<widget class="QTextEdit" name="textEdit"/>
</item>
<item>
+ <layout class="QHBoxLayout" name="horizontalLayout_5">
+ <item alignment="Qt::AlignLeft|Qt::AlignVCenter">
+ <widget class="QLabel" name="senderKeyLabel">
+ <property name="text">
+ <string>Sender GPG Key: </string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="senderKeyValueLabel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_10">
+ <item alignment="Qt::AlignLeft|Qt::AlignVCenter">
+ <widget class="QLabel" name="recipientKeysLabel">
+ <property name="text">
+ <string>Recipient(s) GPG Key: </string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="recipientsKeyValueLabel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
<widget class="QLabel" name="errorLabel">
<property name="text">
<string/>
@@ -267,11 +403,58 @@
</widget>
</item>
<item>
+ <widget class="Line" name="line_5">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
<layout class="QHBoxLayout" name="horizontalLayout_7">
+ <item>
+ <widget class="QCheckBox" name="contentEncryptCheckBox">
+ <property name="text">
+ <string>Encrypt content</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="attacSignatureCheckBox">
+ <property name="text">
+ <string>Attach signature</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="attachSenderPublickeyCheckBox">
+ <property name="text">
+ <string>Attach sender's public key</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
<item alignment="Qt::AlignRight">
<widget class="QPushButton" name="sendMailButton">
<property name="text">
- <string>Send</string>
+ <string>Send Mail</string>
</property>
</widget>
</item>
diff --git a/ui/SendMailSettings.ui b/ui/SendMailSettings.ui
index 96703f7f..6d409946 100644
--- a/ui/SendMailSettings.ui
+++ b/ui/SendMailSettings.ui
@@ -328,6 +328,40 @@
</item>
</layout>
</item>
+ <item row="1" column="0">
+ <widget class="QWidget" name="horizontalWidget_6" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_7">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="gpgkeyIdLabel">
+ <property name="text">
+ <string>Default Sender GPG Key ID</string>
+ </property>
+ <property name="margin">
+ <number>5</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="gpgKeyIDEdit"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
</layout>
</widget>
</item>