aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsaturneric <[email protected]>2023-12-02 14:01:16 +0000
committersaturneric <[email protected]>2023-12-02 14:01:16 +0000
commit0ec3358e4cfce7ad242e851c450292a25619221e (patch)
tree28a50308678ccbe0e0820d367f363df7df4e0be2
parentfix: add set owner struct action in keymanager menu (diff)
downloadGpgFrontend-0ec3358e4cfce7ad242e851c450292a25619221e.tar.gz
GpgFrontend-0ec3358e4cfce7ad242e851c450292a25619221e.zip
feat: add buddled qt pinentry and make it works
-rw-r--r--cmake/FlagsOverrides.cmake2
-rw-r--r--resource/lfs/icons/data-error.svg9
-rw-r--r--resource/lfs/icons/document-encrypt.pngbin0 -> 1835 bytes
-rw-r--r--resource/lfs/icons/hint.svg13
-rw-r--r--resource/lfs/icons/password-generate.svg13
-rw-r--r--resource/lfs/icons/visibility.svg21
-rw-r--r--resource/lfs/locale/template/GpgFrontend.pot4195
-rw-r--r--src/CMakeLists.txt6
-rw-r--r--src/core/CMakeLists.txt5
-rw-r--r--src/core/function/CoreSignalStation.h4
-rw-r--r--src/core/function/gpg/GpgContext.cpp80
-rw-r--r--src/core/function/gpg/GpgContext.h5
-rw-r--r--src/core/function/gpg/GpgKeyOpera.cpp31
-rw-r--r--src/core/function/gpg/GpgKeyOpera.h4
-rw-r--r--src/core/thread/Task.cpp24
-rw-r--r--src/pinentry/CMakeLists.txt69
-rw-r--r--src/pinentry/accessibility.cpp44
-rw-r--r--src/pinentry/accessibility.h40
-rw-r--r--src/pinentry/argparse.cpp1360
-rw-r--r--src/pinentry/argparse.h204
-rw-r--r--src/pinentry/capslock/capslock.cpp45
-rw-r--r--src/pinentry/capslock/capslock.h77
-rw-r--r--src/pinentry/capslock/capslock_unix.cpp137
-rw-r--r--src/pinentry/capslock/capslock_win.cpp26
-rw-r--r--src/pinentry/focusframe.cpp72
-rw-r--r--src/pinentry/focusframe.h36
-rw-r--r--src/pinentry/keyboardfocusindication.cpp43
-rw-r--r--src/pinentry/keyboardfocusindication.h42
-rw-r--r--src/pinentry/password_cache.cpp153
-rw-r--r--src/pinentry/password_cache.h30
-rw-r--r--src/pinentry/pinentry.cpp1696
-rw-r--r--src/pinentry/pinentry.h370
-rw-r--r--src/pinentry/pinentry_debug.cpp31
-rw-r--r--src/pinentry/pinentry_debug.h28
-rw-r--r--src/pinentry/pinentry_main.cpp413
-rw-r--r--src/pinentry/pinentryconfirm.cpp123
-rw-r--r--src/pinentry/pinentryconfirm.h63
-rw-r--r--src/pinentry/pinentrydialog.cpp718
-rw-r--r--src/pinentry/pinentrydialog.h180
-rw-r--r--src/pinentry/pinlineedit.cpp204
-rw-r--r--src/pinentry/pinlineedit.h63
-rw-r--r--src/pinentry/qti18n.cpp93
-rw-r--r--src/pinentry/secmem++.h91
-rw-r--r--src/pinentry/secmem.cpp375
-rw-r--r--src/pinentry/secmem.h55
-rw-r--r--src/pinentry/secmem_util.h65
-rw-r--r--src/pinentry/util.cpp116
-rw-r--r--src/pinentry/util.h40
-rw-r--r--src/ui/GpgFrontendApplication.cpp4
-rw-r--r--src/ui/UISignalStation.cpp8
-rw-r--r--src/ui/UISignalStation.h7
-rw-r--r--src/ui/UserInterfaceUtils.cpp9
-rw-r--r--src/ui/UserInterfaceUtils.h12
-rw-r--r--src/ui/dialog/keypair_details/KeyPairOperaTab.cpp12
-rw-r--r--src/ui/main_window/MainWindow.cpp5
-rw-r--r--src/ui/main_window/MainWindow.h5
-rw-r--r--src/ui/main_window/MainWindowSlotUI.cpp54
57 files changed, 9485 insertions, 2145 deletions
diff --git a/cmake/FlagsOverrides.cmake b/cmake/FlagsOverrides.cmake
index 58dd76f2..989fe9fa 100644
--- a/cmake/FlagsOverrides.cmake
+++ b/cmake/FlagsOverrides.cmake
@@ -1,3 +1,5 @@
+SET (CMAKE_GENERATOR "Ninja")
+
SET (CMAKE_C_FLAGS_INIT "-Wall -std=c11")
SET (CMAKE_C_FLAGS_DEBUG_INIT "-g")
SET (CMAKE_C_FLAGS_MINSIZEREL_INIT "-Os -DNDEBUG")
diff --git a/resource/lfs/icons/data-error.svg b/resource/lfs/icons/data-error.svg
new file mode 100644
index 00000000..6fc3137e
--- /dev/null
+++ b/resource/lfs/icons/data-error.svg
@@ -0,0 +1,9 @@
+<svg version="1.1" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
+ <style type="text/css" id="current-color-scheme">
+ .ColorScheme-NegativeText {
+ color:#da4453;
+ }
+ </style>
+ <rect class="ColorScheme-NegativeText" x="3" y="3" width="16" height="16" rx="2" fill="currentColor"/>
+ <path d="M 6.414,5 5,6.414 9.586,11 5,15.586 6.414,17 11,12.414 15.586,17 17,15.586 12.414,11 17,6.414 15.586,5 11,9.586 Z" fill="#fff"/>
+</svg>
diff --git a/resource/lfs/icons/document-encrypt.png b/resource/lfs/icons/document-encrypt.png
new file mode 100644
index 00000000..b80c2a6f
--- /dev/null
+++ b/resource/lfs/icons/document-encrypt.png
Binary files differ
diff --git a/resource/lfs/icons/hint.svg b/resource/lfs/icons/hint.svg
new file mode 100644
index 00000000..f6b818fc
--- /dev/null
+++ b/resource/lfs/icons/hint.svg
@@ -0,0 +1,13 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
+ <defs id="defs3051">
+ <style type="text/css" id="current-color-scheme">
+ .ColorScheme-Text {
+ color:#232629;
+ }
+ </style>
+ </defs>
+ <path style="fill:currentColor;fill-opacity:1;stroke:none"
+ d="M 13.314453 2 L 2 13.294922 L 2.7148438 14 L 14 2.6972656 L 13.314453 2 z M 8 3 A 8.9999916 9.000003 0 0 0 0.12304688 7.6679688 C 0.25199187 8.0317035 0.48048562 8.3445563 0.77929688 8.5761719 A 7.9999926 8.0000028 0 0 1 8 4 A 3.9999993 4.0000007 0 0 0 4 8 A 3.9999993 4.0000007 0 0 0 4.1054688 8.8945312 L 5 8 A 2.9999993 3.0000005 0 0 1 8 5 L 8.8925781 4.1074219 A 3.9999993 4.0000007 0 0 0 8.3496094 4.0175781 A 7.9999926 8.0000028 0 0 1 8.9277344 4.0722656 L 9.8066406 3.1933594 A 8.9999916 9.000003 0 0 0 8 3 z M 13.835938 5.1640625 L 13.121094 5.8789062 A 7.9999926 8.0000028 0 0 1 15.220703 8.5761719 C 15.522218 8.3424607 15.752612 8.0261216 15.880859 7.6582031 A 8.9999916 9.000003 0 0 0 13.835938 5.1640625 z M 11.894531 7.1054688 L 11 8 A 2.9999993 3.0000005 0 0 1 8 11 L 7.1074219 11.892578 A 3.9999993 4.0000007 0 0 0 8 12 A 3.9999993 4.0000007 0 0 0 12 8 A 3.9999993 4.0000007 0 0 0 11.894531 7.1054688 z "
+ class="ColorScheme-Text"
+ />
+</svg>
diff --git a/resource/lfs/icons/password-generate.svg b/resource/lfs/icons/password-generate.svg
new file mode 100644
index 00000000..12d703c4
--- /dev/null
+++ b/resource/lfs/icons/password-generate.svg
@@ -0,0 +1,13 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
+ <defs id="defs3051">
+ <style type="text/css" id="current-color-scheme">
+ .ColorScheme-Text {
+ color:#232629;
+ }
+ </style>
+ </defs>
+ <path style="fill:currentColor;fill-opacity:1;stroke:none"
+ d="m3.5 2l-.531.969-.969.531.969.531.531.969.531-.969.969-.531-.969-.531zm7.631 0l-9.125 9.125 2.875 2.875 9.125-9.125zm0 1.438l1.438 1.439-2.781 2.779-1.438-1.438z"
+ class="ColorScheme-Text"
+ />
+</svg>
diff --git a/resource/lfs/icons/visibility.svg b/resource/lfs/icons/visibility.svg
new file mode 100644
index 00000000..df91c9d3
--- /dev/null
+++ b/resource/lfs/icons/visibility.svg
@@ -0,0 +1,21 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
+ <defs id="defs3051">
+ <style type="text/css" id="current-color-scheme">
+ .ColorScheme-Text {
+ color:#232629;
+ }
+ </style>
+ </defs>
+ <g
+ transform="translate(-421.71429,-531.79074)">
+ <g
+ transform="matrix(0.75,0,0,0.74999813,421.46429,-241.22897)">
+ <path
+ style="fill:currentColor;fill-opacity:1;stroke:none"
+ d="M 8 3 A 8.9999925 9.0000023 0 0 0 0.12304688 7.6679688 C 0.2519919 8.0317178 0.48048563 8.3445725 0.77929688 8.5761719 A 7.9999935 8.0000021 0 0 1 8 4 A 3.9999996 4.0000004 0 0 0 4 8 A 3.9999996 4.0000004 0 0 0 8 12 A 3.9999996 4.0000004 0 0 0 12 8 A 3.9999996 4.0000004 0 0 0 8.3496094 4.0175781 A 7.9999935 8.0000021 0 0 1 15.220703 8.5761719 C 15.522218 8.3424725 15.752612 8.0260772 15.880859 7.6582031 A 8.9999925 9.0000023 0 0 0 8 3 z M 8 5 A 2.9999996 3.0000002 0 0 1 11 8 A 2.9999996 3.0000002 0 0 1 8 11 A 2.9999996 3.0000002 0 0 1 5 8 A 2.9999996 3.0000002 0 0 1 8 5 z M 8 6 A 1.9999999 2.0000003 0 0 0 6 8 A 1.9999999 2.0000003 0 0 0 8 10 A 1.9999999 2.0000003 0 0 0 10 8 A 1.9999999 2.0000003 0 0 0 9.9101562 7.4121094 A 0.9999999 1 0 0 1 9 8 A 0.9999999 1 0 0 1 8 7 A 0.9999999 1 0 0 1 8.5898438 6.0898438 A 1.9999999 2.0000003 0 0 0 8 6 z "
+ transform="matrix(1.3333333,0,0,1.3333367,0.33333333,1030.6955)"
+ class="ColorScheme-Text"
+ id="rect4170" />
+ </g>
+ </g>
+</svg>
diff --git a/resource/lfs/locale/template/GpgFrontend.pot b/resource/lfs/locale/template/GpgFrontend.pot
index 7591e844..203cf6cb 100644
--- a/resource/lfs/locale/template/GpgFrontend.pot
+++ b/resource/lfs/locale/template/GpgFrontend.pot
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: GpgFrontend 2.1.1\n"
"Report-Msgid-Bugs-To: [email protected]\n"
-"POT-Creation-Date: 2023-10-29 19:06+0800\n"
+"POT-Creation-Date: 2023-12-02 05:58-0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email protected]>\n"
@@ -17,3421 +17,3475 @@ msgstr ""
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:70
-msgid "Proxy"
+#: /home/eric/Documents/GpgFrontend/src/cmd.cpp:48
+msgid "This is free software; see the source for copying conditions."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:71
-msgid "Network Ability"
+#: /home/eric/Documents/GpgFrontend/src/cmd.cpp:52
+msgid "Build Timestamp: "
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:72
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:54
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyDetailsDialog.cpp:46
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:556
-msgid "Operations"
+#: /home/eric/Documents/GpgFrontend/src/cmd.cpp:53
+msgid "Build Version: "
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:74
-msgid "Enable Proxy"
+#: /home/eric/Documents/GpgFrontend/src/cmd.cpp:54
+msgid "Source Code Version: "
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:75
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:78
-msgid "Port"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/TOFUInfoPage.cpp:36
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:82
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:163
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:68
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp:95
+msgid "Key ID"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:77
-msgid "Host Address"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/TOFUInfoPage.cpp:37
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:83
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:69
+msgid "Algorithm"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:79
-msgid "Proxy Type"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/TOFUInfoPage.cpp:38
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:84
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:71
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:162
+msgid "Key Size"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:80
-msgid "Username"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/TOFUInfoPage.cpp:39
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:85
+msgid "Nominal Usage"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:81
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:411
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:162
-msgid "Password"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/TOFUInfoPage.cpp:40
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:86
+msgid "Actual Usage"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:84
-msgid "Apply Proxy Settings and Check Proxy Connection"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/TOFUInfoPage.cpp:41
+msgid "Expires on"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:87
-msgid "Forbid all GnuPG network connection."
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/TOFUInfoPage.cpp:42
+msgid "Last Update"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:89
-msgid "Prohibit checking for version updates when the program starts."
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/TOFUInfoPage.cpp:43
+msgid "Secret Key Existence"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:91
-msgid "Automatically import a missing key for signature verification."
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:51
+msgid "Import from keyserver"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:93
-msgid ""
-"Tips: These Option Changes take effect only after the application restart."
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:56
+msgid "Key not present with id 0x"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:279
-msgid "Test Server Url Accessibility"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:60
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:86
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:102
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:118
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:120
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:136
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:151
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:140
+msgid "Status"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:289
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeySetExpireDateDialog.cpp:85
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:422
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:174
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:324
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:113
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/UserInterfaceUtils.cpp:322
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp:41
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgSignResultAnalyse.cpp:43
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgEncryptResultAnalyse.cpp:41
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:47
-msgid "Success"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:60
+msgid ":"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:290
-msgid "Successfully connect to the target server through the proxy server."
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:62
+msgid "Key not present in key list"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:294
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:419
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:796
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp:43
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgSignResultAnalyse.cpp:45
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgEncryptResultAnalyse.cpp:43
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:49
-msgid "Failed"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:70
+msgid "A Signature"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:295
-msgid ""
-"Unable to connect to the target server through the proxy server. Proxy "
-"settings may be invalid."
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:75
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:91
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:107
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:125
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:141
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:156
+msgid "Key Information is NOT Available"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:305
-msgid "Test Proxy Server Connection..."
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:77
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:93
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:109
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:127
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:143
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:158
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:140
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:47
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:82
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgSignResultAnalyse.cpp:108
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgEncryptResultAnalyse.cpp:54
+msgid "Fingerprint"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:306
-msgid ""
-"Is using your proxy settings to access the url. Note that this test "
-"operation will apply your proxy settings to the entire software."
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:86
+msgid "Cert Revoked"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsAdvanced.cpp:36
-msgid "Show Steganography Options"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:102
+msgid "Signature Expired"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsAdvanced.cpp:38
-msgid "Show Steganography Options."
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:118
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:120
+msgid "Key Expired"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsAdvanced.cpp:42
-msgid "Pubkey Exchange"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:136
+msgid "General Error"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsAdvanced.cpp:45
-msgid "Auto Pubkey Exchange"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:151
+msgid "Unknown Error "
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsDialog.cpp:54
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:44
-msgid "General"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:181
+msgid "Signer Name"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsDialog.cpp:55
-msgid "Appearance"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:182
+msgid "Signer Email"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsDialog.cpp:56
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:81
-msgid "Key Server"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:183
+msgid "Key's Fingerprint"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsDialog.cpp:57
-msgid "Network"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:184
+msgid "Valid"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsDialog.cpp:68
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:170
-msgid "Settings"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:185
+msgid "Flags"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsDialog.cpp:72
-msgid "Preference"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:192
+msgid "Fully Valid"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsDialog.cpp:131
-msgid "System Default"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:194
+msgid "NOT Fully Valid"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:53
-msgid "Keyserver List"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:200
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:84
+msgid "Good"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:56
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:623
-msgid "Default"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:203
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:87
+msgid "Bad"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:58
-msgid "Keyserver Address"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:206
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:91
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:90
+msgid "Expired"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:59
-msgid "Security"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:209
+msgid "Missing Key"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:60
-msgid "Available"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:212
+msgid "Revoked Key"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:62
-msgid "Add"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:215
+msgid "Expired Key"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:63
-msgid "Test Listed Keyserver"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:218
+msgid "Missing CRL"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:66
-msgid "Tips: Please Double-click table item to edit it."
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/KeyList.cpp:100
+msgid "Refresh"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:67
-msgid "Delete Selected"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/KeyList.cpp:102
+msgid "Refresh the key list to synchronize changes."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:69
-msgid "Delete Selected Key Server"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/KeyList.cpp:103
+msgid "Sync Public Key"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:70
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:71
-msgid "Set As Default"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/KeyList.cpp:105
+msgid "Sync public key with your default keyserver."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:154
-msgid "Insecure keyserver address"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/KeyList.cpp:106
+msgid "Uncheck ALL"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:155
-msgid ""
-"For security reasons, using HTTP as the communication protocol with the key "
-"server is not recommended. It is recommended to use HTTPS."
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/KeyList.cpp:108
+msgid "Cancel all checked items in the current tab at once."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:163
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:410
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:205
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:310
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:411
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:593
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:687
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:787
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/TextEdit.cpp:139
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/TextEdit.cpp:221
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/TextEdit.cpp:448
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/FilePage.cpp:405
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/UserInterfaceUtils.cpp:325
-msgid "Warning"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/KeyList.cpp:109
+msgid "Check ALL"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:164
-msgid ""
-"You may not use HTTPS or HTTP as the protocol for communicating with the key "
-"server, which may not be wrong. But please check the address you entered "
-"again to make sure it is correct. Are you sure that want to add it into the "
-"keyserver list?"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/KeyList.cpp:111
+msgid "Check all items in the current tab at once"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:211
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp:60
-msgid "true"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/KeyList.cpp:112
+msgid "Search for keys..."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:212
-msgid "false"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/KeyList.cpp:168
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:140
+msgid "Select"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:217
-msgid "unknown"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/KeyList.cpp:168
+msgid "Type"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:231
-msgid "Set TCP Timeout"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/KeyList.cpp:168
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:140
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyNewUIDDialog.cpp:50
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:75
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:140
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:163
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:406
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/GnupgTab.cpp:48
+msgid "Name"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:256
-msgid "Reachable"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/KeyList.cpp:168
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:76
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:407
+msgid "Email Address"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:259
-msgid "Not Reachable"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/KeyList.cpp:169
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:73
+msgid "Usage"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:271
-msgid "Test Key Server Connection..."
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/KeyList.cpp:169
+msgid "Trust"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:272
-msgid ""
-"This test only tests the network connectivity of the key server. Passing the "
-"test does not mean that the key server is functionally available."
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/KeyList.cpp:169
+msgid "Finger Print"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsGeneral.cpp:48
-msgid "Cache"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/KeyList.cpp:184
+msgid "Refreshing Key List..."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsGeneral.cpp:50
-msgid "Save checked private keys on exit and restore them on next start."
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/KeyList.cpp:352
+msgid "Import Keys"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsGeneral.cpp:52
-msgid "Clear gpg password cache when closing GpgFrontend."
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/KeyList.cpp:355
+msgid "You've dropped something on the table."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsGeneral.cpp:54
-msgid ""
-"Automatically restore unsaved Text Editor pages after an application crash."
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/KeyList.cpp:356
+msgid "GpgFrontend will now try to import key(s)."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsGeneral.cpp:57
-msgid "Operation"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/KeyList.cpp:361
+msgid "Always import without bothering."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsGeneral.cpp:59
-msgid "Enable to use longer key expiration date."
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/KeyList.cpp:475
+msgid "Key List Refreshed."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsGeneral.cpp:61
-msgid "Import files dropped on the Key List without confirmation."
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/KeyList.cpp:495
+msgid "Syncing Key List..."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsGeneral.cpp:63
-msgid "Language"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/KeyList.cpp:503
+msgid "Sync [%1%/%2%] %3% %4%"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsGeneral.cpp:65
-msgid "NOTE"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/KeyList.cpp:511
+msgid "Key List Sync Done."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsGeneral.cpp:65
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:179
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:77
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:81
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/FileOperator.cpp:85
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/FileOperator.cpp:92
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/FileOperator.cpp:101
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/FileOperator.cpp:109
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/FileOperator.cpp:117
-msgid ": "
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/PlainTextEditorPage.cpp:64
+msgid "0 character"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsGeneral.cpp:66
-msgid "GpgFrontend will restart automatically if you change the language!"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/PlainTextEditorPage.cpp:65
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/PlainTextEditorPage.cpp:109
+msgid "lf"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsGeneral.cpp:68
-msgid "Data"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/PlainTextEditorPage.cpp:66
+msgid "utf-8"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsGeneral.cpp:70
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsGeneral.cpp:90
-#, c-format
-msgid "Clear All Log (Total Size: %s)"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/PlainTextEditorPage.cpp:73
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/PlainTextEditorPage.cpp:259
+msgid "%1% character(s)"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsGeneral.cpp:74
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsGeneral.cpp:106
-#, c-format
-msgid "Clear All Data Objects (Total Size: %s)"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/PlainTextEditorPage.cpp:82
+msgid "Loading..."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsGeneral.cpp:98
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/SignersPicker.cpp:37
-msgid "Confirm"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/PlainTextEditorPage.cpp:110
+msgid "UTF-8"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsGeneral.cpp:99
-msgid ""
-"Are you sure you want to clear all data objects?\n"
-"This will result in loss of all cached form positions, statuses, key "
-"servers, etc."
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/PlainTextEditorPage.cpp:239
+msgid "%1% byte(s)"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsAppearance.cpp:41
-msgid "Icon Size"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/PlainTextEditorPage.cpp:283
+msgid "binary"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsAppearance.cpp:42
-msgid "small"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/TextEdit.cpp:63
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/TextEdit.cpp:78
+msgid "untitled"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsAppearance.cpp:43
-msgid "medium"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/TextEdit.cpp:140
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/TextEdit.cpp:222
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/TextEdit.cpp:449
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/TextEdit.cpp:489
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/FilePage.cpp:407
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:205
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:310
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:411
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:593
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:687
+#: /home/eric/Documents/GpgFrontend/src/ui/function/SetOwnerTrustLevel.cpp:73
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:163
+#: /home/eric/Documents/GpgFrontend/src/ui/UserInterfaceUtils.cpp:319
+msgid "Warning"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsAppearance.cpp:44
-msgid "large"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/TextEdit.cpp:141
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/TextEdit.cpp:223
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/TextEdit.cpp:450
+msgid ""
+"Cannot read file %1%:\n"
+"%2%."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsAppearance.cpp:46
-msgid "Icon Style"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/TextEdit.cpp:152
+msgid "Open file"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsAppearance.cpp:47
-msgid "just text"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/TextEdit.cpp:186
+msgid "Save"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsAppearance.cpp:48
-msgid "just icons"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/TextEdit.cpp:188
+msgid ""
+"After saving, the encoding of the current file will be converted to UTF-8 "
+"and the line endings will be changed to LF. "
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsAppearance.cpp:49
-msgid "text and icons"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/TextEdit.cpp:192
+msgid "If this is not the result you expect, please use \"save as\"."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsAppearance.cpp:51
-msgid "Window State"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/TextEdit.cpp:244
+msgid "Save file"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsAppearance.cpp:53
-msgid "Save window size and position on exit."
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/TextEdit.cpp:306
+msgid "Unsaved document"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsAppearance.cpp:55
-msgid "Text Editor"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/TextEdit.cpp:307
+msgid ""
+"The document \"%1\" has been modified. Do you want to save your changes?"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsAppearance.cpp:56
-msgid "Font Size in Text Editor"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/TextEdit.cpp:310
+msgid "Note:"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsAppearance.cpp:58
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:661
-msgid "Information Board"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/TextEdit.cpp:311
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/QuitDialog.cpp:103
+msgid "If you don't save these files, all changes are lost."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/settings/SettingsAppearance.cpp:60
-msgid "Font Size in Information Board"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/TextEdit.cpp:489
+msgid "No document to print"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeySetExpireDateDialog.cpp:86
-msgid "The expire date of the key pair has been updated."
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/FindWidget.cpp:44
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:156
+msgid "Find"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeySetExpireDateDialog.cpp:95
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:184
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:332
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/UserInterfaceUtils.cpp:314
-msgid "Failure"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/FilePage.cpp:218
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/FilePage.cpp:346
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/FilePage.cpp:357
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/FilePage.cpp:397
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/FilePage.cpp:416
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/FilePage.cpp:460
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/InfoBoardWidget.cpp:175
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:88
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:248
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:304
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:370
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:484
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:556
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:595
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:616
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:642
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:660
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:677
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:690
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:703
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:718
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:342
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:394
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:423
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:429
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:437
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:478
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:50
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:55
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:60
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:80
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:214
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:284
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:337
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:443
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:496
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:534
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:615
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:650
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:728
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:76
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:128
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:175
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:227
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:276
+msgid "Error"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeySetExpireDateDialog.cpp:96
-msgid "Failed to update the expire date of the key pair."
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/FilePage.cpp:219
+msgid "The path is not exists, unprivileged or unreachable."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeySetExpireDateDialog.cpp:143
-msgid "Modified Expiration Date (Local Time)"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/FilePage.cpp:227
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:135
+msgid "Open"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeySetExpireDateDialog.cpp:145
-msgid ""
-"Tips: For the sake of security, the key is valid for up to two years. If you "
-"are an expert user, please unlock it for a longer time in the settings."
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/FilePage.cpp:230
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/FilePage.cpp:382
+msgid "Rename"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeySetExpireDateDialog.cpp:148
-msgid "No Expiration"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/FilePage.cpp:233
+msgid "Delete"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeySetExpireDateDialog.cpp:149
-msgid "Modified Expiration Date"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/FilePage.cpp:237
+msgid "Calculate Hash"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:43
-msgid "Owner"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/FilePage.cpp:241
+msgid "Directory"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:44
-msgid "Primary Key"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/FilePage.cpp:245
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:161
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:248
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:245
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:474
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:548
+msgid "File"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:45
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:80
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:139
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:75
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:91
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:107
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:125
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:141
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:156
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgSignResultAnalyse.cpp:105
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgEncryptResultAnalyse.cpp:54
-msgid "Fingerprint"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/FilePage.cpp:249
+msgid "Compress..."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:46
-msgid "Additional UIDs"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/FilePage.cpp:255
+msgid "Open with Default System Application"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:73
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:139
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:162
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyNewUIDDialog.cpp:49
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:403
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/GnupgTab.cpp:46
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:139
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/KeyList.cpp:167
-msgid "Name"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/FilePage.cpp:260
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:44
+msgid "New"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:74
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:404
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/KeyList.cpp:167
-msgid "Email Address"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/FilePage.cpp:278
+msgid "Show Hidden File"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:75
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:139
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyNewUIDDialog.cpp:51
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:405
-msgid "Comment"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/FilePage.cpp:290
+msgid "Show System File"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:80
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:162
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:66
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/TOFUInfoPage.cpp:36
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp:94
-msgid "Key ID"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/FilePage.cpp:347
+msgid "The directory is unprivileged or unreachable."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:81
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:67
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/TOFUInfoPage.cpp:37
-msgid "Algorithm"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/FilePage.cpp:358
+msgid "The file is unprivileged or unreachable."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:82
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:69
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:160
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/TOFUInfoPage.cpp:38
-msgid "Key Size"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/FilePage.cpp:382
+msgid "New Filename"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:83
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/TOFUInfoPage.cpp:39
-msgid "Nominal Usage"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/FilePage.cpp:398
+msgid "Unable to rename the file or folder."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:84
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/TOFUInfoPage.cpp:40
-msgid "Actual Usage"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/FilePage.cpp:408
+msgid "Are you sure you want to delete it?"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:85
-msgid "Owner Trust Level"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/FilePage.cpp:417
+msgid "Unable to delete the file or folder."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:86
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:75
-msgid "Create Date (Local Time)"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/FilePage.cpp:432
+msgid "Make New Directory"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:88
-msgid "Expires on (Local Time)"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/FilePage.cpp:432
+msgid "Directory Name"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:90
-msgid "Last Update (Local Time)"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/FilePage.cpp:449
+msgid "Create Empty File"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:92
-msgid "Primary Key Existence"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/FilePage.cpp:450
+msgid "Filename (you can given extension)"
+msgstr ""
+
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/FilePage.cpp:460
+msgid "Unable to create the file."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:107
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:132
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:103
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:136
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/InfoBoardWidget.cpp:43
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/InfoBoardWidget.cpp:44
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:136
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:109
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:134
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:105
msgid "Copy"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:134
-msgid "copy fingerprint to clipboard"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/InfoBoardWidget.cpp:45
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:73
+msgid "Save File"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:180
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:286
-msgid "Exists"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/InfoBoardWidget.cpp:46
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgSignResultAnalyse.cpp:67
+msgid "Clear"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:180
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:287
-msgid "Not Exists"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/InfoBoardWidget.cpp:166
+msgid "Save Information Board's Content"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:212
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:222
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:278
-msgid "Certificate"
+#: /home/eric/Documents/GpgFrontend/src/ui/widgets/InfoBoardWidget.cpp:176
+msgid "The file path is not exists, unprivileged or unreachable."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:213
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:224
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:279
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:179
-msgid "Encrypt"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:89
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:249
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:305
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:371
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:485
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:557
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:285
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:338
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:444
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:535
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:651
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:729
+msgid "An error occurred during operation."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:214
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:226
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:280
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:222
-msgid "Sign"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:101
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:223
+msgid "Symmetric Encryption"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:215
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:228
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:281
-msgid "Auth"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:102
+msgid ""
+"No Key Checked. Do you want to encrypt with a symmetric cipher using a "
+"passphrase?"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:240
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:206
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:407
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:160
-msgid "Never Expire"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:108
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:231
+msgid "Symmetrically Encrypting"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:262
-msgid "No Data"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:132
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:192
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:388
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:398
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:381
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:322
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:381
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:503
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:517
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:560
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:569
+msgid "Invalid Operation"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:284
-msgid "Warning: The primary key has expired."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:134
+msgid ""
+"The selected key contains a key that does not actually have a encrypt usage."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:289
-msgid "Warning: The primary key has been revoked."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:136
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:196
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:405
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:251
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:565
+msgid "For example the Following Key:"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyDetailsDialog.cpp:41
-msgid "KeyPair"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:146
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:169
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:257
+msgid "Encrypting"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyDetailsDialog.cpp:42
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:69
-msgid "UIDs"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:183
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:391
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:373
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:552
+msgid "No Key Checked"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyDetailsDialog.cpp:44
-msgid "Subkeys"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:184
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:374
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:553
+msgid "Please check the key in the key toolbox on the right."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyDetailsDialog.cpp:56
-msgid "Key Details"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:194
+msgid ""
+"The selected key contains a key that does not actually have a signature "
+"usage."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:49
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:188
-msgid "New UID"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:254
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:424
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:221
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:104
+msgid "Signing"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:50
-msgid "UID Management"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:310
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:320
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:345
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:350
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:355
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:737
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:742
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:747
+msgid "Decrypting"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:74
-msgid "TOFU"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:376
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:508
+msgid "Verifying"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:86
-msgid "Signature of Selected UID"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:392
+msgid "Please check some key in the key toolbox on the right."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:139
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/KeyList.cpp:167
-msgid "Select"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:403
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:249
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:563
+msgid "Invalid KeyPair"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:139
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:162
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyNewUIDDialog.cpp:50
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:139
-msgid "Email"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:404
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:250
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:564
+msgid "The selected keypair cannot be used for encryption."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:162
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:161
-msgid "Create Date (UTC)"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:490
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:628
+msgid "Encrypting and Signing"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:163
-msgid "Expired Date (UTC)"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:562
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:701
+msgid "Decrypting and Verifying"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:239
-msgid "TOFU %1"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:595
+msgid "Key Export Operation Failed."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:295
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:302
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:246
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:251
-msgid "Never Expires"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:616
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:642
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:660
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:677
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:690
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:703
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:718
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:342
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:394
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:437
+msgid "Key Not Found."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:321
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:378
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:499
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:513
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:555
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:564
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:370
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:380
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:381
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:129
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:189
-msgid "Invalid Operation"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:808
+msgid "GpgFrontend Upgradeable (New Version: %1)."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:322
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:379
-msgid "Please select one or more UIDs before doing this operation."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:819
+msgid "Withdrawn Version"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:343
-msgid "Sign Selected UID(s)"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:821
+msgid ""
+"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."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:345
-msgid "Delete Selected UID(s)"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:826
+msgid ""
+"You can download the latest stable version(%1) on Github Releases Page.<br/>"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:365
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:291
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:305
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:325
-msgid "Successful Operation"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:832
+msgid "This maybe a BETA Version (Latest Stable Version: %1)."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:366
-msgid "Successfully added a new UID."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:53
+msgid "All"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:368
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:403
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:438
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:534
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:586
-msgid "Operation Failed"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:56
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:639
+msgid "Only Public Key"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:369
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:439
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:535
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:587
-msgid "An error occurred during the operation."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:65
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:648
+msgid "Has Private Key"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:390
-msgid "Deleting UIDs"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:74
+msgid "No Primary Key"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:393
-msgid "Are you sure that you want to delete the following UIDs?"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:83
+msgid "Revoked"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:395
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:432
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:529
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:581
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:308
-msgid "The action can not be undone."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:115
+msgid "KeyPair Management"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:404
-msgid "An error occurred during the delete %1 operation."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:136
+msgid "Ctrl+O"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:428
-msgid "Set Primary UID"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:137
+msgid "Open Key File"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:430
-msgid "Are you sure that you want to set the Primary UID to?"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:141
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:144
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:91
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:66
+msgid "Close"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:470
-msgid "Set As Primary"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:142
+msgid "Ctrl+Q"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:473
-msgid "Sign UID"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:147
+msgid "New Keypair"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:476
-msgid "Delete UID"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:148
+msgid "Ctrl+N"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:500
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:514
-msgid "Please select one UID before doing this operation."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:150
+msgid "Generate KeyPair"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:524
-msgid "Deleting UID"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:154
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:181
+msgid "New Subkey"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:527
-msgid "Are you sure that you want to delete the following uid?"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:155
+msgid "Ctrl+Shift+N"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:545
-msgid "Delete(Revoke) Key Signature"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:157
+msgid "Generate Subkey For Selected KeyPair"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:556
-msgid "Please select one Key Signature before doing this operation."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:163
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:247
+msgid "Import New Key From File"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:565
-msgid ""
-"To delete the signature, you need to have its corresponding public key in "
-"the local database."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:167
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:251
+msgid "Clipboard"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:576
-msgid "Deleting Key Signature"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:171
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:255
+msgid "Import New Key From Clipboard"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:578
-msgid "Are you sure that you want to delete the following signature?"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:180
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:264
+msgid "Keyserver"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:48
-msgid "General Operations"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:184
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:268
+msgid "Import New Key From Keyserver"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:54
-msgid "Export Public Key"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:190
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:458
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:56
+msgid "Key Package"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:60
-msgid "Export Private Key"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:193
+msgid "Import Key(s) From a Key Package"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:67
-msgid "Modify Expiration Datetime (Primary Key)"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:197
+msgid "Export To Clipboard"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:70
-msgid "Modify Password"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:200
+msgid "Export Selected Key(s) To Clipboard"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:93
-msgid "Key Server Operation (Pubkey)"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:204
+msgid "Export To Key Package"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:101
-msgid "Generate Revoke Certificate"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:207
+msgid "Export Checked Key(s) To a Key Package"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:107
-msgid "Modify TOFU Policy"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:211
+msgid "Export As OpenSSH"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:112
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:444
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:445
-msgid "Set Owner Trust Level"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:214
+msgid "Export Selected Key(s) As OpenSSH Format to File"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:135
-msgid "Upload Key Pair to Key Server"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:218
+msgid "Delete Selected Key(s)"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:141
-msgid "Sync Key Pair From Key Server"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:219
+msgid "Delete the Selected keys"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:155
-msgid "Export Full Secret Key"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:223
+msgid "Delete Checked Key(s)"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:161
-msgid "Export Shortest Secret Key"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:224
+msgid "Delete the Checked keys"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:173
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:225
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:274
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:75
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:127
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:324
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:376
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:405
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:411
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:419
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:460
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:50
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:55
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:60
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:80
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:214
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:284
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:337
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:443
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:496
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:534
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:615
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:650
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:728
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:85
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:245
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:308
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:374
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:488
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:560
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:599
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:620
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:646
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:664
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:681
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:694
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:707
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:722
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/InfoBoardWidget.cpp:173
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/FilePage.cpp:216
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/FilePage.cpp:344
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/FilePage.cpp:355
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/FilePage.cpp:395
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/FilePage.cpp:414
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/FilePage.cpp:458
-msgid "Error"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:229
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:424
+msgid "Show Key Details"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:174
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:226
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:275
-msgid "An error occurred during the export operation."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:230
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:425
+msgid "Show Details for this Key"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:190
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:242
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:291
-msgid "Export Key To File"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:234
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:235
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:444
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:445
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:114
+msgid "Set Owner Trust Level"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:191
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:243
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:292
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/UserInterfaceUtils.cpp:235
-msgid "Key Files"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:252
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:271
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:566
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/GnupgTab.cpp:62
+msgid "Key"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:198
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:250
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:299
-msgid "Export Error"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:253
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:61
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/Wizard.cpp:131
+msgid "Generate Key"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:199
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:251
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:300
-msgid "Couldn't open %1 for writing"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:257
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:283
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:516
+msgid "Import Key"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:207
-msgid "Exporting short private Key"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:282
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:592
+msgid "Import key"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:208
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:261
-msgid "You are about to export your"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:321
+msgid "Deleting Keys"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:209
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:262
-msgid " PRIVATE KEY "
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:324
+msgid "Are you sure that you want to delete the following keys?"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:210
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:263
-msgid "This is NOT your Public Key, so DON'T give it away."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:326
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:398
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:436
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:533
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:586
+msgid "The action can not be undone."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:211
-msgid "Do you REALLY want to export your PRIVATE KEY in a Minimum Size?"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:353
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:366
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:414
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:86
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:93
+msgid "Forbidden"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:214
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:354
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:367
+msgid "Please check some keys before doing this operation."
+msgstr ""
+
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:359
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:449
+msgid "key(s) exported"
+msgstr ""
+
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:389
+msgid "Please select one KeyPair before doing this operation."
+msgstr ""
+
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:399
msgid ""
-"For OpenPGP keys it removes all signatures except for the latest self-"
-"signatures."
+"If a key pair does not have a private key then it will not be able to "
+"generate sub-keys."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:260
-msgid "Exporting private Key"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:415
+msgid ""
+"Please select a key before performing this operation. If you select multiple "
+"keys, only the first key will be exported."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:264
-msgid "Do you REALLY want to export your PRIVATE KEY?"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:423
+msgid "An error occur in exporting."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:328
-msgid "Revocation Certificates"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:430
+msgid ""
+"This key may not be able to export as OpenSSH format. Please check the key-"
+"size of the subkey(s) used to sign."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:347
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:377
-msgid "Not Successful"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:444
+msgid "Export OpenSSH Key To File"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:348
-msgid "Modify password not successfully."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:445
+msgid "OpenSSH Public Key Files"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:354
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:364
-msgid "Policy Auto"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:457
+msgid "Import Key Package"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:354
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:366
-msgid "Policy Good"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:461
+msgid "Import Key Package Passphrase File"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:354
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:368
-msgid "Policy Bad"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:462
+msgid "Key Package Passphrase File"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:355
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:370
-msgid "Policy Ask"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:472
+msgid "key(s) imported"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:355
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:372
-msgid "Policy Unknown"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:479
+msgid "An error occur in importing key package."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:359
-msgid "Modify TOFU Policy(Default is Auto)"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:53
+msgid "Open a new file"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:360
-msgid "Policy for the Key Pair:"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:56
+msgid "Open..."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:378
-msgid "Modify TOFU policy not successfully."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:59
+msgid "Open an existing file"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:386
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:763
-#: /home/eric/develop/cpp/GpgFrontend/src/core/model/GpgKey.cpp:81
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp:88
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:183
-msgid "Unknown"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:62
+msgid "File Browser"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:386
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:404
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:763
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:781
-#: /home/eric/develop/cpp/GpgFrontend/src/core/model/GpgKey.cpp:83
-msgid "Undefined"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:69
+msgid "Open a file browser"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:386
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:402
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:763
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:779
-#: /home/eric/develop/cpp/GpgFrontend/src/core/model/GpgKey.cpp:85
-msgid "Never"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:76
+msgid "Save the current File"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:386
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:400
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:763
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:777
-#: /home/eric/develop/cpp/GpgFrontend/src/core/model/GpgKey.cpp:87
-msgid "Marginal"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:79
+msgid "Save As"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:387
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:398
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:764
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:775
-#: /home/eric/develop/cpp/GpgFrontend/src/core/model/GpgKey.cpp:89
-msgid "Full"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:82
+msgid "Save the current File as..."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:387
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:396
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:764
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:773
-#: /home/eric/develop/cpp/GpgFrontend/src/core/model/GpgKey.cpp:91
-msgid "Ultimate"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:85
+msgid "Print"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:389
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:766
-msgid "Modify Owner Trust Level"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:88
+msgid "Print Document"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:390
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:767
-msgid "Trust for the Key Pair:"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:93
+msgid "Close file"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:411
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:788
-msgid ""
-"Owner Trust Level cannot set to Unknown level, automately changing it into "
-"Undefined level."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:96
+msgid "Quit"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:420
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:797
-msgid "Modify Owner Trust Level failed."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:99
+msgid "Quit Program"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:423
-msgid "Set Owner Trust Level successful."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:104
+msgid "Undo"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:44
-msgid "Subkey List"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:106
+msgid "Undo Last Edit Action"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:45
-msgid "Detail of Selected Subkey"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:109
+msgid "Redo"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:49
-msgid "Generate A New Subkey"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:111
+msgid "Redo Last Edit Action"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:71
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/KeyList.cpp:168
-msgid "Usage"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:114
+msgid "Zoom In"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:73
-msgid "Expires On (Local Time)"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:118
+msgid "Zoom Out"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:76
-msgid "Existence"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:122
+msgid "Paste"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:79
-msgid "Key in Smart Card"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:125
+msgid "Paste Text From Clipboard"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:160
-msgid "Subkey ID"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:128
+msgid "Cut"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:160
-msgid "Algo"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:132
+msgid "Cut the current selection's contents to the clipboard"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:161
-msgid "Expire Date (UTC)"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:140
+msgid "Copy the current selection's contents to the clipboard"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:290
-msgid "Yes"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:144
+msgid "Quote"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:290
-msgid "No"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:146
+msgid "Quote whole text"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:320
-msgid "Edit Expire Date"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:149
+msgid "Select All"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyNewUIDDialog.cpp:59
-msgid "Notice: The New UID Created will be set as Primary."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:152
+msgid "Select the whole text"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyNewUIDDialog.cpp:67
-msgid "Create New UID"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:158
+msgid "Find a word"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyNewUIDDialog.cpp:83
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:98
-msgid "Name must contain at least five characters."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:161
+msgid "Remove spacing"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyNewUIDDialog.cpp:87
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:103
-msgid "Please give a email address."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:166
+msgid "Remove double linebreaks, e.g. in pasted text from Web Mailer"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyUIDSignDialog.cpp:45
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/SignersPicker.cpp:48
-msgid "Signers"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:170
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsDialog.cpp:69
+msgid "Settings"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyUIDSignDialog.cpp:88
-msgid "Expire Date"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:171
+msgid "Open settings dialog"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyUIDSignDialog.cpp:98
-msgid "Sign For Key's UID(s)"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:179
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:215
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:226
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:281
+msgid "Encrypt"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyUIDSignDialog.cpp:129
-msgid "Unsuccessful Operation"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:185
+msgid "Encrypt Message"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyUIDSignDialog.cpp:130
-msgid "Signature operation failed for UID %1"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:188
+msgid "Encrypt Sign"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyUIDSignDialog.cpp:134
-msgid "Operation Complete"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:196
+msgid "Encrypt and Sign Message"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/keypair_details/KeyUIDSignDialog.cpp:135
-msgid "The signature operation of the UID is complete"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:200
+msgid "Decrypt"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/details/VerifyDetailsDialog.cpp:38
-msgid "Signatures Details"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:207
+msgid "Decrypt Message"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/details/VerifyDetailsDialog.cpp:61
-msgid "No valid input found"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:210
+msgid "Decrypt Verify"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/details/VerifyDetailsDialog.cpp:76
-msgid "Error Validating signature"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:218
+msgid "Decrypt and Verify Message"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/details/VerifyDetailsDialog.cpp:78
-msgid "File was signed on %1%"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:222
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:216
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:228
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:282
+msgid "Sign"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/details/VerifyDetailsDialog.cpp:81
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/details/VerifyDetailsDialog.cpp:87
-msgid "It Contains"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:229
+msgid "Sign Message"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/details/VerifyDetailsDialog.cpp:84
-msgid "Signed on %1%"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:232
+msgid "Verify"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/SignersPicker.cpp:38
-msgid "Cancel"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:239
+msgid "Verify Message"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/SignersPicker.cpp:56
-msgid "Select Signer(s)"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:274
+msgid "Editor"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/SignersPicker.cpp:60
-msgid "Please select one or more private keys you use for signing."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:276
+msgid "Import New Key From Editor"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/SignersPicker.cpp:62
-msgid "If no key is selected, the default key will be used for signing."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:280
+msgid "Manage Keys"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/QuitDialog.cpp:37
-msgid "Unsaved Files"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:282
+msgid "Open Key Management"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/QuitDialog.cpp:86
-msgid ""
-"%1% files contain unsaved information.<br/>Save the changes before closing?"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:286
+msgid "Clear Password Cache"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/QuitDialog.cpp:100
-msgid "Check the files you want to save:"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:288
+msgid "Clear Password Cache of GnuPG"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/QuitDialog.cpp:102
-msgid "Note"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:291
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:305
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:325
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:368
+msgid "Successful Operation"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/QuitDialog.cpp:103
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/TextEdit.cpp:310
-msgid "If you don't save these files, all changes are lost."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:292
+msgid "Clear password cache successfully"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:60
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/Wizard.cpp:130
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:235
-msgid "Generate Key"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:294
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:309
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:329
+msgid "Failed Operation"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:111
-msgid "Expiration time too long."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:295
+msgid "Failed to clear password cache of GnuPG"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:116
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:275
-msgid "Password is empty."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:299
+msgid "Reload All Components"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:155
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:308
-msgid "Generating"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:301
+msgid "Reload All GnuPG's Components"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:175
-msgid "The new key pair has been generated."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:306
+msgid "Reload all the GnuPG's components successfully"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:184
-msgid "Key generation failed."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:310
+msgid "Failed to reload all or one of the GnuPG's component(s)"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:213
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:98
-msgid "Key Usage"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:314
+msgid "Restart All Components"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:215
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:100
-msgid "Encryption"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:316
+msgid "Restart All GnuPG's Components"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:218
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:103
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:424
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:251
-msgid "Signing"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:326
+msgid "Restart all the GnuPG's components successfully"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:221
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:106
-msgid "Certification"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:330
+msgid "Failed to restart all or one of the GnuPG's component(s)"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:224
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:109
-msgid "Authentication"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:335
+msgid "Open GnuPG Controller"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:406
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:159
-msgid "Expiration Date"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:337
+msgid "Open GnuPG Controller Dialog"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:408
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:158
-msgid "KeySize (in Bit)"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:344
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:46
+msgid "About"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:409
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:157
-msgid "Key Type"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:346
+msgid "Show the application's About box"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:412
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:163
-msgid "Non Pass Phrase"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:351
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:524
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:55
+msgid "GnuPG"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:426
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:174
-msgid "Basic Information"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:353
+msgid "Information about Gnupg"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:70
-msgid ""
-"Tipps: if the key pair has a passphrase, the subkey's passphrase must be "
-"equal to it."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:357
+msgid "Translate"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:82
-msgid "Generate New Subkey"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:359
+msgid "Information about translation"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:270
-msgid "Expiration time no more than 2 years."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:366
+msgid "Check for Updates"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:325
-msgid "The new subkey has been generated."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:368
+msgid "Check for updates"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:332
-msgid "Failed to generate key."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:372
+msgid "Open Wizard"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/GnupgTab.cpp:46
-msgid "Description"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:373
+msgid "Open the wizard"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/GnupgTab.cpp:46
-msgid "Version"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:378
+msgid "Append Public Key to Editor"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/GnupgTab.cpp:47
-msgid "Checksum"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:380
+msgid "Append selected Keypair's Public Key to Editor"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/GnupgTab.cpp:47
-msgid "Binary Path"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:385
+msgid "Append Create DateTime to Editor"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/GnupgTab.cpp:49
-msgid "Components"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:387
+msgid "Append selected Key's creation date and time to Editor"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/GnupgTab.cpp:50
-msgid "Configurations"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:392
+msgid "Append Expire DateTime to Editor"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/GnupgTab.cpp:60
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:234
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:253
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:566
-msgid "Key"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:394
+msgid "Append selected Key's expiration date and time to Editor"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/GnupgTab.cpp:60
-msgid "Value"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:399
+msgid "Append Fingerprint to Editor"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:47
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:344
-msgid "About"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:401
+msgid "Append selected Key's Fingerprint to Editor"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:55
-msgid "About GpgFrontend"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:405
+msgid "Copy Email"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:56
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:351
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:524
-msgid "GnuPG"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:407
+msgid "Copy selected Keypair's to clipboard"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:57
-msgid "Translators"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:412
+msgid "Copy Default UID"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:58
-msgid "Update"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:414
+msgid "Copy selected Keypair's default UID to clipboard"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:92
-msgid ""
-"GpgFrontend is an easy-to-use, compact, cross-platform, and installation-"
-"free GnuPG Frontend.It visualizes most of the common operations of GnuPG."
-"GpgFrontend is licensed under the GPLv3"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:418
+msgid "Copy Key ID"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:98
-msgid "Developer:"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:420
+msgid "Copy selected Keypair's ID to clipboard"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:99
-msgid "If you have any questions or suggestions, raise an issue at"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:429
+msgid "Add To Favourite"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:102
-msgid "or send a mail to my mailing list at"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:430
+msgid "Add this key to Favourite Table"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:104
-msgid "Built with Qt"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:436
+msgid "Remove From Favourite"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:105
-msgid "and"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:438
+msgid "Remove this key from Favourite Table"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:106
-msgid "Built at"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:464
+msgid "Remove PGP Header"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:145
-msgid ""
-"If you think there are any problems with the translation, why not "
-"participate in the translation work? If you want to participate, please read "
-"the document or contact me via email."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:468
+msgid "Add PGP Header"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:169
-msgid ""
-"It is recommended that you always check the version of GpgFrontend and "
-"upgrade to the latest version."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:487
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:571
+msgid "Edit"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:172
-msgid ""
-"New versions not only represent new features, but also often represent "
-"functional and security fixes."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:505
+msgid "Crypt"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:178
-msgid "Current Version"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:515
+msgid "Keys"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:269
-msgid "Latest Version From Github"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:532
+msgid "Steganography"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:275
-msgid "The current version is less than the latest version on github."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:536
+msgid "View"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:277
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:288
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:300
-msgid "Please click"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:538
+msgid "Help"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:280
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:291
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:303
-msgid "Here"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:556
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:54
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:72
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyDetailsDialog.cpp:47
+msgid "Operations"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:280
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:291
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:303
-msgid "to download the latest stable version."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:579
+msgid "Special Edit"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:286
-msgid ""
-"This version has serious problems and has been withdrawn. Please stop using "
-"it immediately."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:591
+msgid "Import key from..."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:297
-msgid ""
-"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."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:608
+msgid "Ready"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:45
-msgid "Key Database"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:615
+msgid "Key ToolBox"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:46
-msgid "Advanced"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:623
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:56
+msgid "Default"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:48
-msgid "No ASCII Mode"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:631
+msgid "Favourite"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:50
-msgid "Use Pinentry as Password Input Dialog"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:661
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsAppearance.cpp:58
+msgid "Information Board"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:51
-msgid "Use Custom GnuPG"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:51
+msgid "The path %1 does not exist."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:52
-msgid "Select GnuPG Path"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:56
+msgid "No permission to read this file."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:54
-msgid "Use Custom GnuPG Key Database Path"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:61
+msgid "No permission to create file."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:56
-msgid "Select Key Database Path"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:80
+msgid "The file is not a tarball."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:60
-msgid "Tips: please select a directroy where \"gpgconf\" is located in."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:94
+msgid "Extracting Tarball"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:62
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:139
+msgid "Making Tarball"
+msgstr ""
+
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:201
+msgid "The target file %1% already exists, do you need to overwrite it?"
+msgstr ""
+
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:215
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:616
+msgid "Unable to convert the folder into tarball."
+msgstr ""
+
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:224
msgid ""
-"Tips: notice that modify any of these settings will cause an Application "
-"restart."
+"No Key Selected. Do you want to encrypt with a symmetric cipher using a "
+"passphrase?"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:94
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:130
-msgid "Open Directory"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:311
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:594
+msgid "The target file already exists, do you need to overwrite it?"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:184
-msgid "GnuPG Controller"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:346
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:738
+msgid "Do you want to extract and delete the decrypted tarball?"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:388
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:396
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:403
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:415
-msgid "Illegal GnuPG Path"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:351
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:743
+msgid "Extracting tarball succeeded."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:389
-msgid "Target GnuPG Path is empty."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:356
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:748
+msgid "Extracting tarball failed."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:397
-msgid "Target GnuPG Path is not an exists readable directory."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:382
+msgid ""
+"The selected key contains a key that does not actually have a sign usage."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:404
-msgid "Target GnuPG Path is not an absolute path."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:384
+msgid "for example the Following Key:"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:416
-msgid "Target GnuPG Path contains no \"gpgconf\" executable."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:412
+msgid "The signature file \"%1\" exists, do you need to overwrite it?"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:428
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:435
-msgid "Illegal GnuPG Key Database Path"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:484
+msgid "Origin file to verify"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:429
-msgid "Target GnuPG Key Database Path is empty."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:484
+msgid "Filepath"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:436
-msgid "Target GnuPG Key Database Path is not an exists readable directory."
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:497
+msgid ""
+"Please select the appropriate origin file or signature file. Ensure that "
+"both are in this directory."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:41
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:61
-msgid "Key Update Details"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:688
+msgid "The output file %1 already exists, do you need to overwrite it?"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:42
-msgid "No keys found"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindow.cpp:181
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindow.cpp:183
+msgid "Critical error occur while loading GpgFrontend."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:44
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:63
-msgid "Key Import Details"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindow.cpp:182
+msgid "Loading Failed"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:45
-msgid "No keys found to import"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotUI.cpp:235
+msgid "Show passphrase"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:79
-msgid "General key info"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotUI.cpp:236
+msgid "Hide passphrase"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:82
-msgid "Considered"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotUI.cpp:241
+msgid "PIN:"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:89
-msgid "Public unchanged"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotUI.cpp:244
+msgid "Passphrases do not match"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:95
-msgid "Imported"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotUI.cpp:247
+msgid "Caps Lock is on"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:103
-msgid "Not Imported"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotUI.cpp:251
+msgid "Pinentry"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:110
-msgid "Private Read"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotUI.cpp:256
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsGeneral.cpp:99
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/SignersPicker.cpp:38
+msgid "Confirm"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:117
-msgid "Private Imported"
+#: /home/eric/Documents/GpgFrontend/src/ui/main_window/MainWindowSlotUI.cpp:257
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/SignersPicker.cpp:39
+msgid "Cancel"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:124
-msgid "Private Unchanged"
+#: /home/eric/Documents/GpgFrontend/src/ui/function/SetOwnerTrustLevel.cpp:49
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp:89
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:185
+#: /home/eric/Documents/GpgFrontend/src/core/model/GpgKey.cpp:75
+msgid "Unknown"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:139
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:58
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:84
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:100
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:116
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:118
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:134
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:149
-msgid "Status"
+#: /home/eric/Documents/GpgFrontend/src/ui/function/SetOwnerTrustLevel.cpp:49
+#: /home/eric/Documents/GpgFrontend/src/ui/function/SetOwnerTrustLevel.cpp:67
+#: /home/eric/Documents/GpgFrontend/src/core/model/GpgKey.cpp:77
+msgid "Undefined"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:168
-msgid "Private"
+#: /home/eric/Documents/GpgFrontend/src/ui/function/SetOwnerTrustLevel.cpp:49
+#: /home/eric/Documents/GpgFrontend/src/ui/function/SetOwnerTrustLevel.cpp:65
+#: /home/eric/Documents/GpgFrontend/src/core/model/GpgKey.cpp:79
+msgid "Never"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:171
-msgid "Public"
+#: /home/eric/Documents/GpgFrontend/src/ui/function/SetOwnerTrustLevel.cpp:49
+#: /home/eric/Documents/GpgFrontend/src/ui/function/SetOwnerTrustLevel.cpp:63
+#: /home/eric/Documents/GpgFrontend/src/core/model/GpgKey.cpp:81
+msgid "Marginal"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:174
-msgid "Unchanged"
+#: /home/eric/Documents/GpgFrontend/src/ui/function/SetOwnerTrustLevel.cpp:50
+#: /home/eric/Documents/GpgFrontend/src/ui/function/SetOwnerTrustLevel.cpp:61
+#: /home/eric/Documents/GpgFrontend/src/core/model/GpgKey.cpp:83
+msgid "Full"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:177
-msgid "New Key"
+#: /home/eric/Documents/GpgFrontend/src/ui/function/SetOwnerTrustLevel.cpp:50
+#: /home/eric/Documents/GpgFrontend/src/ui/function/SetOwnerTrustLevel.cpp:59
+#: /home/eric/Documents/GpgFrontend/src/core/model/GpgKey.cpp:85
+msgid "Ultimate"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:180
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:148
-msgid "New Subkey"
+#: /home/eric/Documents/GpgFrontend/src/ui/function/SetOwnerTrustLevel.cpp:52
+msgid "Modify Owner Trust Level"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:184
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgSignResultAnalyse.cpp:57
-msgid "New Signature"
+#: /home/eric/Documents/GpgFrontend/src/ui/function/SetOwnerTrustLevel.cpp:53
+msgid "Trust for the Key Pair:"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyUploadDialog.cpp:57
-msgid "Uploading Public Key"
+#: /home/eric/Documents/GpgFrontend/src/ui/function/SetOwnerTrustLevel.cpp:74
+msgid ""
+"Owner Trust Level cannot set to Unknown level, automately changing it into "
+"Undefined level."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyUploadDialog.cpp:95
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/UserInterfaceUtils.cpp:367
-msgid "Cannot read default_keyserver From Settings"
+#: /home/eric/Documents/GpgFrontend/src/ui/function/SetOwnerTrustLevel.cpp:82
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:294
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp:44
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgSignResultAnalyse.cpp:47
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:51
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgEncryptResultAnalyse.cpp:43
+msgid "Failed"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyUploadDialog.cpp:96
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:466
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/UserInterfaceUtils.cpp:368
-msgid "Default Keyserver Not Found"
+#: /home/eric/Documents/GpgFrontend/src/ui/function/SetOwnerTrustLevel.cpp:83
+msgid "Modify Owner Trust Level failed."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyUploadDialog.cpp:97
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:467
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/UserInterfaceUtils.cpp:369
+#: /home/eric/Documents/GpgFrontend/src/ui/GpgFrontendApplication.cpp:83
+msgid "Standard Exception Thrown"
+msgstr ""
+
+#: /home/eric/Documents/GpgFrontend/src/ui/GpgFrontendApplication.cpp:84
msgid ""
-"Cannot read default keyserver from your settings, please set a default "
-"keyserver first"
+"Oops, an standard exception was thrown during the running of the program. "
+"This is not a serious problem, it may be the negligence of the programmer, "
+"please report this problem if you can."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyUploadDialog.cpp:150
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:498
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:512
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/UserInterfaceUtils.cpp:405
-msgid "Key Not Found"
+#: /home/eric/Documents/GpgFrontend/src/ui/GpgFrontendApplication.cpp:94
+msgid "Unhandled Exception Thrown"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyUploadDialog.cpp:153
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:286
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:501
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:516
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/UserInterfaceUtils.cpp:408
-msgid "Timeout"
+#: /home/eric/Documents/GpgFrontend/src/ui/GpgFrontendApplication.cpp:95
+msgid ""
+"Oops, an unhandled exception was thrown during the running of the program. "
+"This is not a serious problem, it may be the negligence of the programmer, "
+"please report this problem if you can."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyUploadDialog.cpp:156
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:289
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:504
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/UserInterfaceUtils.cpp:411
-msgid "Key Server Not Found"
+#: /home/eric/Documents/GpgFrontend/src/ui/GpgFrontendUIInit.cpp:143
+msgid "Loading Gnupg Info..."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyUploadDialog.cpp:159
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:292
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:507
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:523
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/UserInterfaceUtils.cpp:414
-msgid "Connection Error"
+#: /home/eric/Documents/GpgFrontend/src/ui/GpgFrontendUIInit.cpp:144
+msgid ""
+"If this process is too slow, please set the key server address appropriately "
+"in the gnupg configuration file (depending on the network situation in your "
+"country or region)."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyUploadDialog.cpp:164
-msgid "Upload Success"
+#: /home/eric/Documents/GpgFrontend/src/ui/GpgFrontendUIInit.cpp:270
+msgid "could not read properly from configure file"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyUploadDialog.cpp:165
-msgid "Upload Public Key Successfully"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:45
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsDialog.cpp:55
+msgid "General"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:54
-msgid "Export Key Package"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:46
+msgid "Key Database"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:55
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:184
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:440
-msgid "Key Package"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:47
+msgid "Advanced"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:65
-msgid "Export Key Package Passphrase"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:49
+msgid "No ASCII Mode"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:67
-msgid "Key File"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:51
+msgid "Use Pinentry as Password Input Dialog"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:76
-msgid "An error occurred while generating the passphrase file."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:52
+msgid "Use Custom GnuPG"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:85
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:92
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:335
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:348
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:396
-msgid "Forbidden"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:53
+msgid "Select GnuPG Path"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:86
-msgid "Please select an output path before exporting."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:55
+msgid "Use Custom GnuPG Key Database Path"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:93
-msgid ""
-"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."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:57
+msgid "Select Key Database Path"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:115
-msgid ""
-"The Key Package has been successfully generated and has been protected by "
-"encryption algorithms(AES-256-ECB). You can safely transfer your Key Package."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:61
+msgid "Tips: please select a directroy where \"gpgconf\" is located in."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:119
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:63
msgid ""
-"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."
+"Tips: notice that modify any of these settings will cause an Application "
+"restart."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:128
-msgid "An error occurred while exporting the key package."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:95
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:131
+msgid "Open Directory"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:135
-msgid "Key Package Name"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:185
+msgid "GnuPG Controller"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:136
-msgid "Output Path"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:388
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:396
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:403
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:415
+msgid "Illegal GnuPG Path"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:137
-msgid "Passphrase"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:389
+msgid "Target GnuPG Path is empty."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:139
-msgid ""
-"Tips: You can use Key Package to safely and conveniently transfer your "
-"public and private keys between devices."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:397
+msgid "Target GnuPG Path is not an exists readable directory."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:141
-msgid "Generate and Save Passphrase"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:404
+msgid "Target GnuPG Path is not an absolute path."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:142
-msgid "Generate Key Package Name"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:416
+msgid "Target GnuPG Path contains no \"gpgconf\" executable."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:143
-msgid "Select Output Path"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:428
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:435
+msgid "Illegal GnuPG Key Database Path"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:146
-msgid "Include secret key (Think twice before acting)"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:429
+msgid "Target GnuPG Key Database Path is empty."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:148
-msgid "Exclude keys that do not have a private key"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/gnupg/GnuPGControllerDialog.cpp:436
+msgid "Target GnuPG Key Database Path is not an exists readable directory."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:151
-msgid "Export As Key Package"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:42
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:62
+msgid "Key Update Details"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:65
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:135
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:138
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:91
-msgid "Close"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:43
+msgid "No keys found"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:68
-msgid "Import ALL"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:45
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:64
+msgid "Key Import Details"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:72
-msgid "Search"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:46
+msgid "No keys found to import"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:77
-msgid "Search String"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:80
+msgid "General key info"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:127
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:162
-msgid "Update Keys from Keyserver"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:83
+msgid "Considered"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:129
-msgid "Import Keys from Keyserver"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:90
+msgid "Public unchanged"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:210
-msgid "UID"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:96
+msgid "Imported"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:210
-msgid "Creation date"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:104
+msgid "Not Imported"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:210
-msgid "KeyID"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:111
+msgid "Private Read"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:210
-msgid "Tag"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:118
+msgid "Private Imported"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:235
-msgid "Text is empty."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:125
+msgid "Private Unchanged"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:283
-msgid "Not Key Found"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:140
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyNewUIDDialog.cpp:51
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:140
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:163
+msgid "Email"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:302
-msgid "Too many responses from keyserver!"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:169
+msgid "Private"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:312
-msgid "No keys found, input may be kexId, retrying search with 0x."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:172
+msgid "Public"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:321
-msgid "No keys found containing the search string!"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:175
+msgid "Unchanged"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:328
-msgid "Insufficiently specific search string!"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:178
+msgid "New Key"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:364
-msgid "revoked"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:185
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgSignResultAnalyse.cpp:59
+msgid "New Signature"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:368
-msgid "disabled"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyImportDetailDialog.cpp:189
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:50
+msgid "New UID"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:418
-msgid "%1 keys found. Double click a key to import it."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:55
+msgid "Export Key Package"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:513
-msgid "key not found in the Keyserver"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:66
+msgid "Export Key Package Passphrase"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:519
-msgid "Host Not Found"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:68
+msgid "Key File"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:524
-msgid "General Connection Error"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:77
+msgid "An error occurred while generating the passphrase file."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:538
-msgid "Key Imported"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:87
+msgid "Please select an output path before exporting."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/Wizard.cpp:43
-msgid "First Start Wizard"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:94
+msgid ""
+"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."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/Wizard.cpp:80
-msgid "Getting Started..."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:114
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:289
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeySetExpireDateDialog.cpp:86
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:176
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:325
+#: /home/eric/Documents/GpgFrontend/src/ui/UserInterfaceUtils.cpp:316
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp:42
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgSignResultAnalyse.cpp:45
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:49
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgEncryptResultAnalyse.cpp:41
+msgid "Success"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/Wizard.cpp:81
-msgid "... with GpgFrontend"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:116
+msgid ""
+"The Key Package has been successfully generated and has been protected by "
+"encryption algorithms(AES-256-ECB). You can safely transfer your Key Package."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/Wizard.cpp:84
-msgid "Welcome to use GpgFrontend for decrypting and signing text or file!"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:120
+msgid ""
+"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."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/Wizard.cpp:87
-msgid ""
-"is a Powerful, Easy-to-Use, Compact, Cross-Platform, and Installation-Free "
-"OpenPGP Crypto Tool."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:129
+msgid "An error occurred while exporting the key package."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/Wizard.cpp:89
-msgid "For brief information have a look at the"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:136
+msgid "Key Package Name"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/Wizard.cpp:91
-msgid "Overview"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:137
+msgid "Output Path"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/Wizard.cpp:92
-msgid "by clicking the link, the page will open in the web browser"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:138
+msgid "Passphrase"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/Wizard.cpp:101
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:140
msgid ""
-"If it supports the language currently being used in your system, GpgFrontend "
-"will automatically set it."
+"Tips: You can use Key Package to safely and conveniently transfer your "
+"public and private keys between devices."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/Wizard.cpp:119
-msgid "Choose your action..."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:142
+msgid "Generate and Save Passphrase"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/Wizard.cpp:120
-msgid "...by clicking on the appropriate link."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:143
+msgid "Generate Key Package Name"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/Wizard.cpp:124
-msgid ""
-"If you have never used GpgFrontend before and also don't own a gpg key yet "
-"you may possibly want to read how to"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:144
+msgid "Select Output Path"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/Wizard.cpp:138
-msgid ""
-"If you want to learn how to encrypt, decrypt, sign and verify text, you can "
-"read "
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:147
+msgid "Include secret key (Think twice before acting)"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/Wizard.cpp:143
-msgid "Encrypt & Decrypt Text"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:149
+msgid "Exclude keys that do not have a private key"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/Wizard.cpp:143
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/Wizard.cpp:159
-msgid "or"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/ExportKeyPackageDialog.cpp:152
+msgid "Export As Key Package"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/Wizard.cpp:147
-msgid "Sign & Verify Text"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:69
+msgid "Import ALL"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/Wizard.cpp:155
-msgid "If you want to operate file, you can read "
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:73
+msgid "Search"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/Wizard.cpp:159
-msgid "Encrypt & Sign File"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:78
+msgid "Search String"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/Wizard.cpp:163
-msgid "Sign & Verify File"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:78
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:82
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsGeneral.cpp:66
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:178
+#: /home/eric/Documents/GpgFrontend/src/core/utils/IOUtils.cpp:86
+#: /home/eric/Documents/GpgFrontend/src/core/utils/IOUtils.cpp:93
+#: /home/eric/Documents/GpgFrontend/src/core/utils/IOUtils.cpp:102
+#: /home/eric/Documents/GpgFrontend/src/core/utils/IOUtils.cpp:110
+#: /home/eric/Documents/GpgFrontend/src/core/utils/IOUtils.cpp:118
+msgid ": "
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/Wizard.cpp:189
-msgid "Create a keypair..."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:82
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsDialog.cpp:57
+msgid "Key Server"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/Wizard.cpp:190
-msgid "...for decrypting and signing messages"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:128
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:164
+msgid "Update Keys from Keyserver"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/Wizard.cpp:192
-msgid ""
-"You should create a new keypair.The pair consists of a public and a private "
-"key.<br>Other users can use the public key to encrypt messages for you and "
-"verify messages signed by you.You can use the private key to decrypt and "
-"sign messages.<br>For more information have a look at the offline tutorial "
-"(which then is shown in the main window):"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:130
+msgid "Import Keys from Keyserver"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/Wizard.cpp:204
-msgid "Offline tutorial"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:212
+msgid "UID"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/Wizard.cpp:208
-msgid "Create New Key"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:212
+msgid "Creation date"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/Wizard.cpp:229
-msgid "Ready."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:212
+msgid "KeyID"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/Wizard.cpp:230
-msgid "Have fun with GpgFrontend!"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:212
+msgid "Tag"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/Wizard.cpp:233
-msgid "You are ready to use GpgFrontend now.<br><br>"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:237
+msgid "Text is empty."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/Wizard.cpp:237
-msgid "The Online Document"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:285
+msgid "Not Key Found"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/Wizard.cpp:238
-msgid ""
-" will get you started with GpgFrontend. Anytime you encounter problems, "
-"please try to find help from the documentation"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:288
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:504
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:519
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyUploadDialog.cpp:154
+#: /home/eric/Documents/GpgFrontend/src/ui/UserInterfaceUtils.cpp:402
+msgid "Timeout"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/Wizard.cpp:247
-msgid "Open offline help."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:291
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:507
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyUploadDialog.cpp:157
+#: /home/eric/Documents/GpgFrontend/src/ui/UserInterfaceUtils.cpp:405
+msgid "Key Server Not Found"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/dialog/Wizard.cpp:250
-msgid "Dont show the wizard again."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:294
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:510
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:526
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyUploadDialog.cpp:160
+#: /home/eric/Documents/GpgFrontend/src/ui/UserInterfaceUtils.cpp:408
+msgid "Connection Error"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:51
-msgid "All"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:304
+msgid "Too many responses from keyserver!"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:54
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:639
-msgid "Only Public Key"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:314
+msgid "No keys found, input may be kexId, retrying search with 0x."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:63
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:648
-msgid "Has Private Key"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:323
+msgid "No keys found containing the search string!"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:72
-msgid "No Primary Key"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:330
+msgid "Insufficiently specific search string!"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:81
-msgid "Revoked"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:366
+msgid "revoked"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:89
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:204
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:88
-msgid "Expired"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:370
+msgid "disabled"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:113
-msgid "KeyPair Management"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:420
+msgid "%1 keys found. Double click a key to import it."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:129
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/FilePage.cpp:225
-msgid "Open"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:468
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyUploadDialog.cpp:97
+#: /home/eric/Documents/GpgFrontend/src/ui/UserInterfaceUtils.cpp:362
+msgid "Default Keyserver Not Found"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:130
-msgid "Ctrl+O"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:469
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyUploadDialog.cpp:98
+#: /home/eric/Documents/GpgFrontend/src/ui/UserInterfaceUtils.cpp:363
+msgid ""
+"Cannot read default keyserver from your settings, please set a default "
+"keyserver first"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:131
-msgid "Open Key File"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:501
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:515
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyUploadDialog.cpp:151
+#: /home/eric/Documents/GpgFrontend/src/ui/UserInterfaceUtils.cpp:399
+msgid "Key Not Found"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:136
-msgid "Ctrl+Q"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:516
+msgid "key not found in the Keyserver"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:141
-msgid "New Keypair"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:522
+msgid "Host Not Found"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:142
-msgid "Ctrl+N"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:527
+msgid "General Connection Error"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:144
-msgid "Generate KeyPair"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyServerImportDialog.cpp:541
+msgid "Key Imported"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:149
-msgid "Ctrl+Shift+N"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyUploadDialog.cpp:58
+msgid "Uploading Public Key"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:151
-msgid "Generate Subkey For Selected KeyPair"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyUploadDialog.cpp:96
+#: /home/eric/Documents/GpgFrontend/src/ui/UserInterfaceUtils.cpp:361
+msgid "Cannot read default_keyserver From Settings"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:155
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:230
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:245
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:474
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:548
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/FilePage.cpp:243
-msgid "File"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyUploadDialog.cpp:165
+msgid "Upload Success"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:157
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:247
-msgid "Import New Key From File"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/import_export/KeyUploadDialog.cpp:166
+msgid "Upload Public Key Successfully"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:161
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:251
-msgid "Clipboard"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:53
+msgid "Keyserver List"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:165
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:255
-msgid "Import New Key From Clipboard"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:58
+msgid "Keyserver Address"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:174
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:264
-msgid "Keyserver"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:59
+msgid "Security"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:178
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:268
-msgid "Import New Key From Keyserver"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:60
+msgid "Available"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:187
-msgid "Import Key(s) From a Key Package"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:62
+msgid "Add"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:191
-msgid "Export To Clipboard"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:63
+msgid "Test Listed Keyserver"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:194
-msgid "Export Selected Key(s) To Clipboard"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:66
+msgid "Tips: Please Double-click table item to edit it."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:198
-msgid "Export To Key Package"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:67
+msgid "Delete Selected"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:201
-msgid "Export Checked Key(s) To a Key Package"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:69
+msgid "Delete Selected Key Server"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:205
-msgid "Export As OpenSSH"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:70
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:71
+msgid "Set As Default"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:208
-msgid "Export Selected Key(s) As OpenSSH Format to File"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:154
+msgid "Insecure keyserver address"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:212
-msgid "Delete Selected Key(s)"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:155
+msgid ""
+"For security reasons, using HTTP as the communication protocol with the key "
+"server is not recommended. It is recommended to use HTTPS."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:213
-msgid "Delete the Selected keys"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:164
+msgid ""
+"You may not use HTTPS or HTTP as the protocol for communicating with the key "
+"server, which may not be wrong. But please check the address you entered "
+"again to make sure it is correct. Are you sure that want to add it into the "
+"keyserver list?"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:217
-msgid "Delete Checked Key(s)"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:211
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp:61
+msgid "true"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:218
-msgid "Delete the Checked keys"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:212
+msgid "false"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:223
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:424
-msgid "Show Key Details"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:217
+msgid "unknown"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:224
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:425
-msgid "Show Details for this Key"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:231
+msgid "Set TCP Timeout"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:239
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:265
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:516
-msgid "Import Key"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:256
+msgid "Reachable"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:264
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:592
-msgid "Import key"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:259
+msgid "Not Reachable"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:303
-msgid "Deleting Keys"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:271
+msgid "Test Key Server Connection..."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:306
-msgid "Are you sure that you want to delete the following keys?"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsKeyServer.cpp:272
+msgid ""
+"This test only tests the network connectivity of the key server. Passing the "
+"test does not mean that the key server is functionally available."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:324
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:376
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:419
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:620
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:646
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:664
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:681
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:694
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:707
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:722
-msgid "Key Not Found."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:70
+msgid "Proxy"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:336
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:349
-msgid "Please check some keys before doing this operation."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:71
+msgid "Network Ability"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:341
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:431
-msgid "key(s) exported"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:74
+msgid "Enable Proxy"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:371
-msgid "Please select one KeyPair before doing this operation."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:75
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:78
+msgid "Port"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:381
-msgid ""
-"If a key pair does not have a private key then it will not be able to "
-"generate sub-keys."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:77
+msgid "Host Address"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:397
-msgid ""
-"Please select a key before performing this operation. If you select multiple "
-"keys, only the first key will be exported."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:79
+msgid "Proxy Type"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:405
-msgid "An error occur in exporting."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:80
+msgid "Username"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:412
-msgid ""
-"This key may not be able to export as OpenSSH format. Please check the key-"
-"size of the subkey(s) used to sign."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:81
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:414
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:163
+msgid "Password"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:426
-msgid "Export OpenSSH Key To File"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:84
+msgid "Apply Proxy Settings and Check Proxy Connection"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:427
-msgid "OpenSSH Public Key Files"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:87
+msgid "Forbid all GnuPG network connection."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:439
-msgid "Import Key Package"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:89
+msgid "Prohibit checking for version updates when the program starts."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:443
-msgid "Import Key Package Passphrase File"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:91
+msgid "Automatically import a missing key for signature verification."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:444
-msgid "Key Package Passphrase File"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:93
+msgid ""
+"Tips: These Option Changes take effect only after the application restart."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:454
-msgid "key(s) imported"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:279
+msgid "Test Server Url Accessibility"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/KeyMgmt.cpp:461
-msgid "An error occur in importing key package."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:290
+msgid "Successfully connect to the target server through the proxy server."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:51
-msgid "The path %1 does not exist."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:295
+msgid ""
+"Unable to connect to the target server through the proxy server. Proxy "
+"settings may be invalid."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:56
-msgid "No permission to read this file."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:305
+msgid "Test Proxy Server Connection..."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:61
-msgid "No permission to create file."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsNetwork.cpp:306
+msgid ""
+"Is using your proxy settings to access the url. Note that this test "
+"operation will apply your proxy settings to the entire software."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:80
-msgid "The file is not a tarball."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsAdvanced.cpp:36
+msgid "Show Steganography Options"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:94
-msgid "Extracting Tarball"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsAdvanced.cpp:38
+msgid "Show Steganography Options."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:139
-msgid "Making Tarball"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsAdvanced.cpp:42
+msgid "Pubkey Exchange"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:201
-msgid "The target file %1% already exists, do you need to overwrite it?"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsAdvanced.cpp:45
+msgid "Auto Pubkey Exchange"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:215
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:616
-msgid "Unable to convert the folder into tarball."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsGeneral.cpp:49
+msgid "Cache"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:223
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:98
-msgid "Symmetric Encryption"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsGeneral.cpp:51
+msgid "Save checked private keys on exit and restore them on next start."
+msgstr ""
+
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsGeneral.cpp:53
+msgid "Clear gpg password cache when closing GpgFrontend."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:224
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsGeneral.cpp:55
msgid ""
-"No Key Selected. Do you want to encrypt with a symmetric cipher using a "
-"passphrase?"
+"Automatically restore unsaved Text Editor pages after an application crash."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:231
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:105
-msgid "Symmetrically Encrypting"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsGeneral.cpp:58
+msgid "Operation"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:249
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:563
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:407
-msgid "Invalid KeyPair"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsGeneral.cpp:60
+msgid "Enable to use longer key expiration date."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:250
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:564
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:408
-msgid "The selected keypair cannot be used for encryption."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsGeneral.cpp:62
+msgid "Import files dropped on the Key List without confirmation."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:251
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:565
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:133
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:193
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:409
-msgid "For example the Following Key:"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsGeneral.cpp:64
+msgid "Language"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:257
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:143
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:166
-msgid "Encrypting"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsGeneral.cpp:66
+msgid "NOTE"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:285
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:338
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:444
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:535
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:651
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:729
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:86
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:246
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:309
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:375
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:489
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:561
-msgid "An error occurred during operation."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsGeneral.cpp:67
+msgid "GpgFrontend will restart automatically if you change the language!"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:311
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:594
-msgid "The target file already exists, do you need to overwrite it?"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsGeneral.cpp:69
+msgid "Data"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:320
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:345
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:350
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:355
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:737
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:742
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:747
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:314
-msgid "Decrypting"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsGeneral.cpp:71
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsGeneral.cpp:91
+#, c-format
+msgid "Clear All Log (Total Size: %s)"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:346
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:738
-msgid "Do you want to extract and delete the decrypted tarball?"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsGeneral.cpp:75
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsGeneral.cpp:107
+#, c-format
+msgid "Clear All Data Objects (Total Size: %s)"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:351
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:743
-msgid "Extracting tarball succeeded."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsGeneral.cpp:100
+msgid ""
+"Are you sure you want to clear all data objects?\n"
+"This will result in loss of all cached form positions, statuses, key "
+"servers, etc."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:356
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:748
-msgid "Extracting tarball failed."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsDialog.cpp:56
+msgid "Appearance"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:373
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:552
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:180
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:395
-msgid "No Key Checked"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsDialog.cpp:58
+msgid "Network"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:374
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:553
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:181
-msgid "Please check the key in the key toolbox on the right."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsDialog.cpp:73
+msgid "Preference"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:382
-msgid ""
-"The selected key contains a key that does not actually have a sign usage."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsDialog.cpp:132
+msgid "System Default"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:384
-msgid "for example the Following Key:"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsAppearance.cpp:41
+msgid "Icon Size"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:412
-msgid "The signature file \"%1\" exists, do you need to overwrite it?"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsAppearance.cpp:42
+msgid "small"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:484
-msgid "Origin file to verify"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsAppearance.cpp:43
+msgid "medium"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:484
-msgid "Filepath"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsAppearance.cpp:44
+msgid "large"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:497
-msgid ""
-"Please select the appropriate origin file or signature file. Ensure that "
-"both are in this directory."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsAppearance.cpp:46
+msgid "Icon Style"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:508
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:380
-msgid "Verifying"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsAppearance.cpp:47
+msgid "just text"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:628
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:494
-msgid "Encrypting and Signing"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsAppearance.cpp:48
+msgid "just icons"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:688
-msgid "The output file %1 already exists, do you need to overwrite it?"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsAppearance.cpp:49
+msgid "text and icons"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowFileSlotFunction.cpp:701
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:566
-msgid "Decrypting and Verifying"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsAppearance.cpp:51
+msgid "Window State"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:44
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/FilePage.cpp:258
-msgid "New"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsAppearance.cpp:53
+msgid "Save window size and position on exit."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:53
-msgid "Open a new file"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsAppearance.cpp:55
+msgid "Text Editor"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:56
-msgid "Open..."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsAppearance.cpp:56
+msgid "Font Size in Text Editor"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:59
-msgid "Open an existing file"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/settings/SettingsAppearance.cpp:60
+msgid "Font Size in Information Board"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:62
-msgid "File Browser"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyUIDSignDialog.cpp:46
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/SignersPicker.cpp:49
+msgid "Signers"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:69
-msgid "Open a file browser"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyUIDSignDialog.cpp:86
+msgid "Expire Date"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:73
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/InfoBoardWidget.cpp:44
-msgid "Save File"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyUIDSignDialog.cpp:96
+msgid "Sign For Key's UID(s)"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:76
-msgid "Save the current File"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyUIDSignDialog.cpp:127
+msgid "Unsuccessful Operation"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:79
-msgid "Save As"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyUIDSignDialog.cpp:128
+msgid "Signature operation failed for UID %1"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:82
-msgid "Save the current File as..."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyUIDSignDialog.cpp:132
+msgid "Operation Complete"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:85
-msgid "Print"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyUIDSignDialog.cpp:133
+msgid "The signature operation of the UID is complete"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:88
-msgid "Print Document"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyNewUIDDialog.cpp:52
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:77
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:140
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:408
+msgid "Comment"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:93
-msgid "Close file"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyNewUIDDialog.cpp:60
+msgid "Notice: The New UID Created will be set as Primary."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:96
-msgid "Quit"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyNewUIDDialog.cpp:68
+msgid "Create New UID"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:99
-msgid "Quit Program"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyNewUIDDialog.cpp:84
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:100
+msgid "Name must contain at least five characters."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:104
-msgid "Undo"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyNewUIDDialog.cpp:88
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:105
+msgid "Please give a email address."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:106
-msgid "Undo Last Edit Action"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeySetExpireDateDialog.cpp:87
+msgid "The expire date of the key pair has been updated."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:109
-msgid "Redo"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeySetExpireDateDialog.cpp:96
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:185
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:333
+#: /home/eric/Documents/GpgFrontend/src/ui/UserInterfaceUtils.cpp:308
+msgid "Failure"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:111
-msgid "Redo Last Edit Action"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeySetExpireDateDialog.cpp:97
+msgid "Failed to update the expire date of the key pair."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:114
-msgid "Zoom In"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeySetExpireDateDialog.cpp:144
+msgid "Modified Expiration Date (Local Time)"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:118
-msgid "Zoom Out"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeySetExpireDateDialog.cpp:146
+msgid ""
+"Tips: For the sake of security, the key is valid for up to two years. If you "
+"are an expert user, please unlock it for a longer time in the settings."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:122
-msgid "Paste"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeySetExpireDateDialog.cpp:149
+msgid "No Expiration"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:125
-msgid "Paste Text From Clipboard"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeySetExpireDateDialog.cpp:150
+msgid "Modified Expiration Date"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:128
-msgid "Cut"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:45
+msgid "Owner"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:132
-msgid "Cut the current selection's contents to the clipboard"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:46
+msgid "Primary Key"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:140
-msgid "Copy the current selection's contents to the clipboard"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:48
+msgid "Additional UIDs"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:144
-msgid "Quote"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:87
+msgid "Owner Trust Level"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:146
-msgid "Quote whole text"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:88
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:77
+msgid "Create Date (Local Time)"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:149
-msgid "Select All"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:90
+msgid "Expires on (Local Time)"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:152
-msgid "Select the whole text"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:92
+msgid "Last Update (Local Time)"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:156
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/FindWidget.cpp:44
-msgid "Find"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:94
+msgid "Primary Key Existence"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:158
-msgid "Find a word"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:136
+msgid "copy fingerprint to clipboard"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:161
-msgid "Remove spacing"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:182
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:288
+msgid "Exists"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:166
-msgid "Remove double linebreaks, e.g. in pasted text from Web Mailer"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:182
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:289
+msgid "Not Exists"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:171
-msgid "Open settings dialog"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:214
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:224
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:280
+msgid "Certificate"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:185
-msgid "Encrypt Message"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:217
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:230
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:283
+msgid "Auth"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:188
-msgid "Encrypt Sign"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:242
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:208
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:410
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:161
+msgid "Never Expire"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:196
-msgid "Encrypt and Sign Message"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:264
+msgid "No Data"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:200
-msgid "Decrypt"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:286
+msgid "Warning: The primary key has expired."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:207
-msgid "Decrypt Message"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairDetailTab.cpp:291
+msgid "Warning: The primary key has been revoked."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:210
-msgid "Decrypt Verify"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:51
+msgid "UID Management"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:218
-msgid "Decrypt and Verify Message"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:70
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyDetailsDialog.cpp:43
+msgid "UIDs"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:229
-msgid "Sign Message"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:75
+msgid "TOFU"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:232
-msgid "Verify"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:87
+msgid "Signature of Selected UID"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:239
-msgid "Verify Message"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:163
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:163
+msgid "Create Date (UTC)"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:274
-msgid "Editor"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:164
+msgid "Expired Date (UTC)"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:276
-msgid "Import New Key From Editor"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:240
+msgid "TOFU %1"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:280
-msgid "Manage Keys"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:296
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:303
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:248
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:253
+msgid "Never Expires"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:282
-msgid "Open Key Management"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:323
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:382
+msgid "Please select one or more UIDs before doing this operation."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:286
-msgid "Clear Password Cache"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:345
+msgid "Sign Selected UID(s)"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:288
-msgid "Clear Password Cache of GnuPG"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:348
+msgid "Delete Selected UID(s)"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:292
-msgid "Clear password cache successfully"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:369
+msgid "Successfully added a new UID."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:294
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:309
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:329
-msgid "Failed Operation"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:371
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:406
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:442
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:538
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:591
+msgid "Operation Failed"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:295
-msgid "Failed to clear password cache of GnuPG"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:372
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:443
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:539
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:592
+msgid "An error occurred during the operation."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:299
-msgid "Reload All Components"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:393
+msgid "Deleting UIDs"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:301
-msgid "Reload All GnuPG's Components"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:396
+msgid "Are you sure that you want to delete the following UIDs?"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:306
-msgid "Reload all the GnuPG's components successfully"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:407
+msgid "An error occurred during the delete %1 operation."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:310
-msgid "Failed to reload all or one of the GnuPG's component(s)"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:432
+msgid "Set Primary UID"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:314
-msgid "Restart All Components"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:434
+msgid "Are you sure that you want to set the Primary UID to?"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:316
-msgid "Restart All GnuPG's Components"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:474
+msgid "Set As Primary"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:326
-msgid "Restart all the GnuPG's components successfully"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:477
+msgid "Sign UID"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:330
-msgid "Failed to restart all or one of the GnuPG's component(s)"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:480
+msgid "Delete UID"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:335
-msgid "Open GnuPG Controller"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:504
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:518
+msgid "Please select one UID before doing this operation."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:337
-msgid "Open GnuPG Controller Dialog"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:528
+msgid "Deleting UID"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:346
-msgid "Show the application's About box"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:531
+msgid "Are you sure that you want to delete the following uid?"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:353
-msgid "Information about Gnupg"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:549
+msgid "Delete(Revoke) Key Signature"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:357
-msgid "Translate"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:561
+msgid "Please select one Key Signature before doing this operation."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:359
-msgid "Information about translation"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:570
+msgid ""
+"To delete the signature, you need to have its corresponding public key in "
+"the local database."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:366
-msgid "Check for Updates"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:581
+msgid "Deleting Key Signature"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:368
-msgid "Check for updates"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairUIDTab.cpp:583
+msgid "Are you sure that you want to delete the following signature?"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:372
-msgid "Open Wizard"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:46
+msgid "Subkey List"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:373
-msgid "Open the wizard"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:47
+msgid "Detail of Selected Subkey"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:378
-msgid "Append Public Key to Editor"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:51
+msgid "Generate A New Subkey"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:380
-msgid "Append selected Keypair's Public Key to Editor"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:75
+msgid "Expires On (Local Time)"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:385
-msgid "Append Create DateTime to Editor"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:78
+msgid "Existence"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:387
-msgid "Append selected Key's creation date and time to Editor"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:81
+msgid "Key in Smart Card"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:392
-msgid "Append Expire DateTime to Editor"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:162
+msgid "Subkey ID"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:394
-msgid "Append selected Key's expiration date and time to Editor"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:162
+msgid "Algo"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:399
-msgid "Append Fingerprint to Editor"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:163
+msgid "Expire Date (UTC)"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:401
-msgid "Append selected Key's Fingerprint to Editor"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:292
+msgid "Yes"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:405
-msgid "Copy Email"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:292
+msgid "No"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:407
-msgid "Copy selected Keypair's to clipboard"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairSubkeyTab.cpp:322
+msgid "Edit Expire Date"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:412
-msgid "Copy Default UID"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:50
+msgid "General Operations"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:414
-msgid "Copy selected Keypair's default UID to clipboard"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:56
+msgid "Export Public Key"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:418
-msgid "Copy Key ID"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:62
+msgid "Export Private Key"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:420
-msgid "Copy selected Keypair's ID to clipboard"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:69
+msgid "Modify Expiration Datetime (Primary Key)"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:429
-msgid "Add To Favourite"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:72
+msgid "Modify Password"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:430
-msgid "Add this key to Favourite Table"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:95
+msgid "Key Server Operation (Pubkey)"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:436
-msgid "Remove From Favourite"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:103
+msgid "Generate Revoke Certificate"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:438
-msgid "Remove this key from Favourite Table"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:109
+msgid "Modify TOFU Policy"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:464
-msgid "Remove PGP Header"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:137
+msgid "Upload Key Pair to Key Server"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:468
-msgid "Add PGP Header"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:143
+msgid "Sync Key Pair From Key Server"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:487
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:571
-msgid "Edit"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:157
+msgid "Export Full Secret Key"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:505
-msgid "Crypt"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:163
+msgid "Export Shortest Secret Key"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:515
-msgid "Keys"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:176
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:228
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:277
+msgid "An error occurred during the export operation."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:532
-msgid "Steganography"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:192
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:244
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:293
+msgid "Export Key To File"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:536
-msgid "View"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:193
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:245
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:294
+#: /home/eric/Documents/GpgFrontend/src/ui/UserInterfaceUtils.cpp:229
+msgid "Key Files"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:538
-msgid "Help"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:200
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:252
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:301
+msgid "Export Error"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:579
-msgid "Special Edit"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:201
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:253
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:302
+msgid "Couldn't open %1 for writing"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:591
-msgid "Import key from..."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:209
+msgid "Exporting short private Key"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:608
-msgid "Ready"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:210
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:263
+msgid "You are about to export your"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:615
-msgid "Key ToolBox"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:211
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:264
+msgid " PRIVATE KEY "
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowUI.cpp:631
-msgid "Favourite"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:212
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:265
+msgid "This is NOT your Public Key, so DON'T give it away."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:99
-msgid ""
-"No Key Checked. Do you want to encrypt with a symmetric cipher using a "
-"passphrase?"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:213
+msgid "Do you REALLY want to export your PRIVATE KEY in a Minimum Size?"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:131
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:216
msgid ""
-"The selected key contains a key that does not actually have a encrypt usage."
+"For OpenPGP keys it removes all signatures except for the latest self-"
+"signatures."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:191
-msgid ""
-"The selected key contains a key that does not actually have a signature "
-"usage."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:262
+msgid "Exporting private Key"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:265
-msgid "Notice"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:266
+msgid "Do you REALLY want to export your PRIVATE KEY?"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:266
-msgid "Short Crypto Text only supports Decrypt & Verify."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:330
+msgid "Revocation Certificates"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:396
-msgid "Please check some key in the key toolbox on the right."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:349
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:380
+msgid "Not Successful"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:599
-msgid "Key Export Operation Failed."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:350
+msgid "Modify password not successfully."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:858
-msgid "GpgFrontend Upgradeable (New Version: %1)."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:357
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:367
+msgid "Policy Auto"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:869
-msgid "Withdrawn Version"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:357
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:369
+msgid "Policy Good"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:871
-msgid ""
-"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."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:357
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:371
+msgid "Policy Bad"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:876
-msgid ""
-"You can download the latest stable version(%1) on Github Releases Page.<br/>"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:358
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:373
+msgid "Policy Ask"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindowSlotFunction.cpp:882
-msgid "This maybe a BETA Version (Latest Stable Version: %1)."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:358
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:375
+msgid "Policy Unknown"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindow.cpp:178
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindow.cpp:180
-msgid "Critical error occur while loading GpgFrontend."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:362
+msgid "Modify TOFU Policy(Default is Auto)"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/main_window/MainWindow.cpp:179
-msgid "Loading Failed"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:363
+msgid "Policy for the Key Pair:"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/GpgFrontendUIInit.cpp:144
-msgid "Loading Gnupg Info..."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp:381
+msgid "Modify TOFU policy not successfully."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/GpgFrontendUIInit.cpp:145
-msgid ""
-"If this process is too slow, please set the key server address appropriately "
-"in the gnupg configuration file (depending on the network situation in your "
-"country or region)."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyDetailsDialog.cpp:42
+msgid "KeyPair"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/GpgFrontendUIInit.cpp:274
-msgid "could not read properly from configure file"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyDetailsDialog.cpp:45
+msgid "Subkeys"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:49
-msgid "Import from keyserver"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/keypair_details/KeyDetailsDialog.cpp:57
+msgid "Key Details"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:54
-msgid "Key not present with id 0x"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/details/VerifyDetailsDialog.cpp:40
+msgid "Signatures Details"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:58
-msgid ":"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/details/VerifyDetailsDialog.cpp:63
+msgid "No valid input found"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:60
-msgid "Key not present in key list"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/details/VerifyDetailsDialog.cpp:78
+msgid "Error Validating signature"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:68
-msgid "A Signature"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/details/VerifyDetailsDialog.cpp:80
+msgid "File was signed on %1%"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:73
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:89
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:105
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:123
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:139
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:154
-msgid "Key Information is NOT Available"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/details/VerifyDetailsDialog.cpp:83
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/details/VerifyDetailsDialog.cpp:89
+msgid "It Contains"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:84
-msgid "Cert Revoked"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/details/VerifyDetailsDialog.cpp:86
+msgid "Signed on %1%"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:100
-msgid "Signature Expired"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:113
+msgid "Expiration time too long."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:116
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:118
-msgid "Key Expired"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:118
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:276
+msgid "Password is empty."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:134
-msgid "General Error"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:157
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:309
+msgid "Generating"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:149
-msgid "Unknown Error "
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:177
+msgid "The new key pair has been generated."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:179
-msgid "Signer Name"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:185
+msgid "Key generation failed."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:180
-msgid "Signer Email"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:216
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:99
+msgid "Key Usage"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:181
-msgid "Key's Fingerprint"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:218
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:101
+msgid "Encryption"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:182
-msgid "Valid"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:224
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:107
+msgid "Certification"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:183
-msgid "Flags"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:227
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:110
+msgid "Authentication"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:190
-msgid "Fully Valid"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:409
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:160
+msgid "Expiration Date"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:192
-msgid "NOT Fully Valid"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:411
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:159
+msgid "KeySize (in Bit)"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:198
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:82
-msgid "Good"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:412
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:158
+msgid "Key Type"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:201
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:85
-msgid "Bad"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:415
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:164
+msgid "Non Pass Phrase"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:207
-msgid "Missing Key"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/KeygenDialog.cpp:429
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:175
+msgid "Basic Information"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:210
-msgid "Revoked Key"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:71
+msgid ""
+"Tipps: if the key pair has a passphrase, the subkey's passphrase must be "
+"equal to it."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:213
-msgid "Expired Key"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:83
+msgid "Generate New Subkey"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/VerifyKeyDetailBox.cpp:216
-msgid "Missing CRL"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:271
+msgid "Expiration time no more than 2 years."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/InfoBoardWidget.cpp:45
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgSignResultAnalyse.cpp:65
-msgid "Clear"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:326
+msgid "The new subkey has been generated."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/InfoBoardWidget.cpp:164
-msgid "Save Information Board's Content"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/key_generate/SubkeyGenerateDialog.cpp:333
+msgid "Failed to generate key."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/InfoBoardWidget.cpp:174
-msgid "The file path is not exists, unprivileged or unreachable."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/QuitDialog.cpp:37
+msgid "Unsaved Files"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/TOFUInfoPage.cpp:41
-msgid "Expires on"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/QuitDialog.cpp:86
+msgid ""
+"%1% files contain unsaved information.<br/>Save the changes before closing?"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/TOFUInfoPage.cpp:42
-msgid "Last Update"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/QuitDialog.cpp:100
+msgid "Check the files you want to save:"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/TOFUInfoPage.cpp:43
-msgid "Secret Key Existence"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/QuitDialog.cpp:102
+msgid "Note"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/KeyList.cpp:99
-msgid "Refresh"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/Wizard.cpp:44
+msgid "First Start Wizard"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/KeyList.cpp:101
-msgid "Refresh the key list to synchronize changes."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/Wizard.cpp:81
+msgid "Getting Started..."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/KeyList.cpp:102
-msgid "Sync Public Key"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/Wizard.cpp:82
+msgid "... with GpgFrontend"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/KeyList.cpp:104
-msgid "Sync public key with your default keyserver."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/Wizard.cpp:85
+msgid "Welcome to use GpgFrontend for decrypting and signing text or file!"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/KeyList.cpp:105
-msgid "Uncheck ALL"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/Wizard.cpp:88
+msgid ""
+"is a Powerful, Easy-to-Use, Compact, Cross-Platform, and Installation-Free "
+"OpenPGP Crypto Tool."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/KeyList.cpp:107
-msgid "Cancel all checked items in the current tab at once."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/Wizard.cpp:90
+msgid "For brief information have a look at the"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/KeyList.cpp:108
-msgid "Check ALL"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/Wizard.cpp:92
+msgid "Overview"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/KeyList.cpp:110
-msgid "Check all items in the current tab at once"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/Wizard.cpp:93
+msgid "by clicking the link, the page will open in the web browser"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/KeyList.cpp:111
-msgid "Search for keys..."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/Wizard.cpp:102
+msgid ""
+"If it supports the language currently being used in your system, GpgFrontend "
+"will automatically set it."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/KeyList.cpp:167
-msgid "Type"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/Wizard.cpp:120
+msgid "Choose your action..."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/KeyList.cpp:168
-msgid "Trust"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/Wizard.cpp:121
+msgid "...by clicking on the appropriate link."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/KeyList.cpp:168
-msgid "Finger Print"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/Wizard.cpp:125
+msgid ""
+"If you have never used GpgFrontend before and also don't own a gpg key yet "
+"you may possibly want to read how to"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/KeyList.cpp:183
-msgid "Refreshing Key List..."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/Wizard.cpp:139
+msgid ""
+"If you want to learn how to encrypt, decrypt, sign and verify text, you can "
+"read "
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/KeyList.cpp:351
-msgid "Import Keys"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/Wizard.cpp:144
+msgid "Encrypt & Decrypt Text"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/KeyList.cpp:354
-msgid "You've dropped something on the table."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/Wizard.cpp:144
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/Wizard.cpp:160
+msgid "or"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/KeyList.cpp:355
-msgid "GpgFrontend will now try to import key(s)."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/Wizard.cpp:148
+msgid "Sign & Verify Text"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/KeyList.cpp:360
-msgid "Always import without bothering."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/Wizard.cpp:156
+msgid "If you want to operate file, you can read "
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/KeyList.cpp:474
-msgid "Key List Refreshed."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/Wizard.cpp:160
+msgid "Encrypt & Sign File"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/KeyList.cpp:494
-msgid "Syncing Key List..."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/Wizard.cpp:164
+msgid "Sign & Verify File"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/KeyList.cpp:502
-msgid "Sync [%1%/%2%] %3% %4%"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/Wizard.cpp:190
+msgid "Create a keypair..."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/KeyList.cpp:510
-msgid "Key List Sync Done."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/Wizard.cpp:191
+msgid "...for decrypting and signing messages"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/PlainTextEditorPage.cpp:63
-msgid "0 character"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/Wizard.cpp:193
+msgid ""
+"You should create a new keypair.The pair consists of a public and a private "
+"key.<br>Other users can use the public key to encrypt messages for you and "
+"verify messages signed by you.You can use the private key to decrypt and "
+"sign messages.<br>For more information have a look at the offline tutorial "
+"(which then is shown in the main window):"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/PlainTextEditorPage.cpp:64
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/PlainTextEditorPage.cpp:108
-msgid "lf"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/Wizard.cpp:205
+msgid "Offline tutorial"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/PlainTextEditorPage.cpp:65
-msgid "utf-8"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/Wizard.cpp:209
+msgid "Create New Key"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/PlainTextEditorPage.cpp:72
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/PlainTextEditorPage.cpp:259
-msgid "%1% character(s)"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/Wizard.cpp:230
+msgid "Ready."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/PlainTextEditorPage.cpp:81
-msgid "Loading..."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/Wizard.cpp:231
+msgid "Have fun with GpgFrontend!"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/PlainTextEditorPage.cpp:109
-msgid "UTF-8"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/Wizard.cpp:234
+msgid "You are ready to use GpgFrontend now.<br><br>"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/PlainTextEditorPage.cpp:239
-msgid "%1% byte(s)"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/Wizard.cpp:238
+msgid "The Online Document"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/PlainTextEditorPage.cpp:283
-msgid "binary"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/Wizard.cpp:239
+msgid ""
+" will get you started with GpgFrontend. Anytime you encounter problems, "
+"please try to find help from the documentation"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/TextEdit.cpp:62
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/TextEdit.cpp:77
-msgid "untitled"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/Wizard.cpp:248
+msgid "Open offline help."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/TextEdit.cpp:140
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/TextEdit.cpp:222
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/TextEdit.cpp:449
-msgid ""
-"Cannot read file %1%:\n"
-"%2%."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/Wizard.cpp:251
+msgid "Dont show the wizard again."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/TextEdit.cpp:151
-msgid "Open file"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/SignersPicker.cpp:57
+msgid "Select Signer(s)"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/TextEdit.cpp:185
-msgid "Save"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/SignersPicker.cpp:61
+msgid "Please select one or more private keys you use for signing."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/TextEdit.cpp:187
-msgid ""
-"After saving, the encoding of the current file will be converted to UTF-8 "
-"and the line endings will be changed to LF. "
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/SignersPicker.cpp:63
+msgid "If no key is selected, the default key will be used for signing."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/TextEdit.cpp:191
-msgid "If this is not the result you expect, please use \"save as\"."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/GnupgTab.cpp:48
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/GnupgTab.cpp:63
+msgid "Description"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/TextEdit.cpp:243
-msgid "Save file"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/GnupgTab.cpp:48
+msgid "Version"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/TextEdit.cpp:305
-msgid "Unsaved document"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/GnupgTab.cpp:49
+msgid "Checksum"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/TextEdit.cpp:306
-msgid ""
-"The document \"%1\" has been modified. Do you want to save your changes?"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/GnupgTab.cpp:49
+msgid "Binary Path"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/TextEdit.cpp:309
-msgid "Note:"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/GnupgTab.cpp:51
+msgid "Components"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/FilePage.cpp:217
-msgid "The path is not exists, unprivileged or unreachable."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/GnupgTab.cpp:52
+msgid "Configurations"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/FilePage.cpp:228
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/FilePage.cpp:380
-msgid "Rename"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/GnupgTab.cpp:62
+msgid "Component"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/FilePage.cpp:231
-msgid "Delete"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/GnupgTab.cpp:62
+msgid "Group"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/FilePage.cpp:235
-msgid "Calculate Hash"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/GnupgTab.cpp:63
+msgid "Default Value"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/FilePage.cpp:239
-msgid "Directory"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/GnupgTab.cpp:64
+msgid "Value"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/FilePage.cpp:247
-msgid "Compress..."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:54
+msgid "About GpgFrontend"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/FilePage.cpp:253
-msgid "Open with Default System Application"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:56
+msgid "Translators"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/FilePage.cpp:276
-msgid "Show Hidden File"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:57
+msgid "Update"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/FilePage.cpp:288
-msgid "Show System File"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:91
+msgid ""
+"GpgFrontend is an easy-to-use, compact, cross-platform, and installation-"
+"free GnuPG Frontend.It visualizes most of the common operations of GnuPG."
+"GpgFrontend is licensed under the GPLv3"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/FilePage.cpp:345
-msgid "The directory is unprivileged or unreachable."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:97
+msgid "Developer:"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/FilePage.cpp:356
-msgid "The file is unprivileged or unreachable."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:98
+msgid "If you have any questions or suggestions, raise an issue at"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/FilePage.cpp:380
-msgid "New Filename"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:101
+msgid "or send a mail to my mailing list at"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/FilePage.cpp:396
-msgid "Unable to rename the file or folder."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:103
+msgid "Built with Qt"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/FilePage.cpp:406
-msgid "Are you sure you want to delete it?"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:104
+msgid "and"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/FilePage.cpp:415
-msgid "Unable to delete the file or folder."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:105
+msgid "Built at"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/FilePage.cpp:430
-msgid "Make New Directory"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:144
+msgid ""
+"If you think there are any problems with the translation, why not "
+"participate in the translation work? If you want to participate, please read "
+"the document or contact me via email."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/FilePage.cpp:430
-msgid "Directory Name"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:168
+msgid ""
+"It is recommended that you always check the version of GpgFrontend and "
+"upgrade to the latest version."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/FilePage.cpp:447
-msgid "Create Empty File"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:171
+msgid ""
+"New versions not only represent new features, but also often represent "
+"functional and security fixes."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/FilePage.cpp:448
-msgid "Filename (you can given extension)"
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:177
+msgid "Current Version"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/widgets/FilePage.cpp:458
-msgid "Unable to create the file."
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:260
+msgid "Latest Version From Github"
+msgstr ""
+
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:266
+msgid "The current version is less than the latest version on github."
+msgstr ""
+
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:268
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:279
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:291
+msgid "Please click"
+msgstr ""
+
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:271
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:282
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:294
+msgid "Here"
+msgstr ""
+
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:271
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:282
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:294
+msgid "to download the latest stable version."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/UserInterfaceUtils.cpp:62
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:277
+msgid ""
+"This version has serious problems and has been withdrawn. Please stop using "
+"it immediately."
+msgstr ""
+
+#: /home/eric/Documents/GpgFrontend/src/ui/dialog/help/AboutDialog.cpp:288
+msgid ""
+"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."
+msgstr ""
+
+#: /home/eric/Documents/GpgFrontend/src/ui/UserInterfaceUtils.cpp:62
msgid "Show Verify Details"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/UserInterfaceUtils.cpp:71
+#: /home/eric/Documents/GpgFrontend/src/ui/UserInterfaceUtils.cpp:71
msgid "Public key not found locally"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/UserInterfaceUtils.cpp:72
+#: /home/eric/Documents/GpgFrontend/src/ui/UserInterfaceUtils.cpp:72
msgid ""
"There is no target public key content in local for GpgFrontend to gather "
"enough information about this Signature. Do you want to import the public "
"key from Keyserver now?"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/UserInterfaceUtils.cpp:191
+#: /home/eric/Documents/GpgFrontend/src/ui/UserInterfaceUtils.cpp:185
msgid "GnuPG Context Loading Failed"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/UserInterfaceUtils.cpp:193
+#: /home/eric/Documents/GpgFrontend/src/ui/UserInterfaceUtils.cpp:187
msgid ""
"Gnupg(gpg) is not installed correctly, please follow <a href='https://www."
"gpgfrontend.bktus.com/#/faq?id=how-to-deal-with-39env-loading-failed39'>this "
@@ -3440,282 +3494,335 @@ msgid ""
"Then, GpgFrontend will restart."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/UserInterfaceUtils.cpp:234
+#: /home/eric/Documents/GpgFrontend/src/ui/UserInterfaceUtils.cpp:228
msgid "Open Key"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/UserInterfaceUtils.cpp:235
+#: /home/eric/Documents/GpgFrontend/src/ui/UserInterfaceUtils.cpp:229
msgid "Keyring files"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/UserInterfaceUtils.cpp:240
+#: /home/eric/Documents/GpgFrontend/src/ui/UserInterfaceUtils.cpp:234
msgid "File Open Failed"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/UserInterfaceUtils.cpp:241
+#: /home/eric/Documents/GpgFrontend/src/ui/UserInterfaceUtils.cpp:235
msgid "Failed to open file: "
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/UserInterfaceUtils.cpp:295
+#: /home/eric/Documents/GpgFrontend/src/ui/UserInterfaceUtils.cpp:289
msgid "Processing"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/UserInterfaceUtils.cpp:315
+#: /home/eric/Documents/GpgFrontend/src/ui/UserInterfaceUtils.cpp:309
msgid "Failed to execute command."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/UserInterfaceUtils.cpp:323
+#: /home/eric/Documents/GpgFrontend/src/ui/UserInterfaceUtils.cpp:317
msgid "Succeed in executing command."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/UserInterfaceUtils.cpp:326
+#: /home/eric/Documents/GpgFrontend/src/ui/UserInterfaceUtils.cpp:320
msgid "Finished executing command."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/UserInterfaceUtils.cpp:426
+#: /home/eric/Documents/GpgFrontend/src/ui/UserInterfaceUtils.cpp:420
msgid "The key has been updated"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/UserInterfaceUtils.cpp:428
+#: /home/eric/Documents/GpgFrontend/src/ui/UserInterfaceUtils.cpp:422
msgid "No need to update the key"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/UserInterfaceUtils.cpp:460
+#: /home/eric/Documents/GpgFrontend/src/ui/UserInterfaceUtils.cpp:453
msgid "Password Input Dialog"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/UserInterfaceUtils.cpp:463
+#: /home/eric/Documents/GpgFrontend/src/ui/UserInterfaceUtils.cpp:456
msgid "Please Input The Password"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/GpgFrontendApplication.cpp:82
-msgid "Standard Exception Thrown"
+#: /home/eric/Documents/GpgFrontend/src/pinentry/argparse.cpp:324
+msgid "argument not expected"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/GpgFrontendApplication.cpp:83
-msgid ""
-"Oops, an standard exception was thrown during the running of the program. "
-"This is not a serious problem, it may be the negligence of the programmer, "
-"please report this problem if you can."
+#: /home/eric/Documents/GpgFrontend/src/pinentry/argparse.cpp:326
+msgid "read error"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/GpgFrontendApplication.cpp:93
-msgid "Unhandled Exception Thrown"
+#: /home/eric/Documents/GpgFrontend/src/pinentry/argparse.cpp:328
+msgid "keyword too long"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/ui/GpgFrontendApplication.cpp:94
-msgid ""
-"Oops, an unhandled exception was thrown during the running of the program. "
-"This is not a serious problem, it may be the negligence of the programmer, "
-"please report this problem if you can."
+#: /home/eric/Documents/GpgFrontend/src/pinentry/argparse.cpp:330
+msgid "missing argument"
+msgstr ""
+
+#: /home/eric/Documents/GpgFrontend/src/pinentry/argparse.cpp:332
+msgid "invalid argument"
+msgstr ""
+
+#: /home/eric/Documents/GpgFrontend/src/pinentry/argparse.cpp:334
+msgid "invalid command"
+msgstr ""
+
+#: /home/eric/Documents/GpgFrontend/src/pinentry/argparse.cpp:336
+msgid "invalid alias definition"
+msgstr ""
+
+#: /home/eric/Documents/GpgFrontend/src/pinentry/argparse.cpp:338
+msgid "out of core"
+msgstr ""
+
+#: /home/eric/Documents/GpgFrontend/src/pinentry/argparse.cpp:340
+msgid "invalid option"
+msgstr ""
+
+#: /home/eric/Documents/GpgFrontend/src/pinentry/argparse.cpp:346
+#, c-format
+msgid "missing argument for option \"%.50s\"\n"
+msgstr ""
+
+#: /home/eric/Documents/GpgFrontend/src/pinentry/argparse.cpp:348
+#, c-format
+msgid "invalid argument for option \"%.50s\"\n"
+msgstr ""
+
+#: /home/eric/Documents/GpgFrontend/src/pinentry/argparse.cpp:350
+#, c-format
+msgid "option \"%.50s\" does not expect an argument\n"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/module/integrated/gnupg_info_gathering_module/GnuPGInfoGatheringModule.cpp:131
+#: /home/eric/Documents/GpgFrontend/src/pinentry/argparse.cpp:354
+#, c-format
+msgid "invalid command \"%.50s\"\n"
+msgstr ""
+
+#: /home/eric/Documents/GpgFrontend/src/pinentry/argparse.cpp:356
+#, c-format
+msgid "option \"%.50s\" is ambiguous\n"
+msgstr ""
+
+#: /home/eric/Documents/GpgFrontend/src/pinentry/argparse.cpp:358
+#, c-format
+msgid "command \"%.50s\" is ambiguous\n"
+msgstr ""
+
+#: /home/eric/Documents/GpgFrontend/src/pinentry/argparse.cpp:360
+msgid "out of core\n"
+msgstr ""
+
+#: /home/eric/Documents/GpgFrontend/src/pinentry/argparse.cpp:362
+#, c-format
+msgid "invalid option \"%.50s\"\n"
+msgstr ""
+
+#: /home/eric/Documents/GpgFrontend/src/module/integrated/gnupg_info_gathering_module/GnuPGInfoGatheringModule.cpp:132
msgid "Embedded In"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp:38
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp:39
msgid "Decrypt Operation"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp:48
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp:49
msgid "Unsupported Algo"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp:56
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp:57
msgid "File Name"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp:60
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp:61
msgid "MIME"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp:64
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp:65
msgid "Recipient(s)"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp:80
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp:81
msgid "Recipient"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp:95
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgSignResultAnalyse.cpp:80
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:191
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgDecryptResultAnalyse.cpp:96
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgSignResultAnalyse.cpp:82
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:193
msgid "Public Key Algo"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgSignResultAnalyse.cpp:40
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgSignResultAnalyse.cpp:42
msgid "Sign Operation"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgSignResultAnalyse.cpp:61
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgSignResultAnalyse.cpp:63
msgid "Sign Mode"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgSignResultAnalyse.cpp:63
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgSignResultAnalyse.cpp:65
msgid "Normal"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgSignResultAnalyse.cpp:67
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgSignResultAnalyse.cpp:69
msgid "Detach"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgSignResultAnalyse.cpp:74
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgSignResultAnalyse.cpp:77
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgSignResultAnalyse.cpp:104
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgSignResultAnalyse.cpp:76
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgSignResultAnalyse.cpp:79
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgSignResultAnalyse.cpp:107
msgid "Signer"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgSignResultAnalyse.cpp:82
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:194
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgSignResultAnalyse.cpp:84
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:197
msgid "Hash Algo"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgSignResultAnalyse.cpp:84
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:197
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgSignResultAnalyse.cpp:86
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:201
msgid "Date"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgSignResultAnalyse.cpp:84
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:58
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:197
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgSignResultAnalyse.cpp:86
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:60
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:201
msgid "UTC"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgSignResultAnalyse.cpp:100
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgSignResultAnalyse.cpp:102
msgid "Invalid Signers"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgSignResultAnalyse.cpp:107
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgEncryptResultAnalyse.cpp:55
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgSignResultAnalyse.cpp:110
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgEncryptResultAnalyse.cpp:55
msgid "Reason"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgEncryptResultAnalyse.cpp:38
-msgid "Encrypt Operation"
-msgstr ""
-
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgEncryptResultAnalyse.cpp:51
-msgid "Invalid Recipients"
-msgstr ""
-
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:44
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:46
msgid "Verify Operation"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:58
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:60
msgid "Signed On"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:64
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:66
msgid "Signatures List"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:70
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:72
msgid "Signature [%1%]:"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:73
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:75
msgid "A Bad Signature."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:75
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:77
msgid "This Signature is invalid."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:80
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:82
msgid "A"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:91
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:93
msgid "Missing Key's"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:94
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:96
msgid "Revoked Key's"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:97
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:99
msgid "Expired Key's"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:100
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:102
msgid "Missing CRL's"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:104
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:106
msgid "Signature Fully Valid."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:106
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:108
msgid "Signature Not Fully Valid."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:107
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:109
msgid "(May used a subkey to sign)"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:113
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:115
msgid "Key is NOT present with ID 0x"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:121
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:123
msgid "A signature could NOT be verified due to a Missing Key"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:126
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:128
msgid ""
"A signature is valid but the key used to verify the signature has been "
"revoked"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:135
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:137
msgid "A signature is valid but expired"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:142
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:144
msgid ""
"A signature is valid but the key used to verify the signature has expired."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:150
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:152
msgid "There was some other error which prevented the signature verification."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:158
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:160
msgid "Error for key with fingerprint"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:169
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:171
msgid "Could not find information that can be used for verification."
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:182
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:187
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:184
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgVerifyResultAnalyse.cpp:189
msgid "Signed By"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/FileOperator.cpp:84
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgEncryptResultAnalyse.cpp:38
+msgid "Encrypt Operation"
+msgstr ""
+
+#: /home/eric/Documents/GpgFrontend/src/core/function/result_analyse/GpgEncryptResultAnalyse.cpp:51
+msgid "Invalid Recipients"
+msgstr ""
+
+#: /home/eric/Documents/GpgFrontend/src/core/utils/IOUtils.cpp:85
msgid "File Hash Information"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/FileOperator.cpp:85
+#: /home/eric/Documents/GpgFrontend/src/core/utils/IOUtils.cpp:86
msgid "filename"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/FileOperator.cpp:92
+#: /home/eric/Documents/GpgFrontend/src/core/utils/IOUtils.cpp:93
msgid "file size(bytes)"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/core/function/FileOperator.cpp:122
+#: /home/eric/Documents/GpgFrontend/src/core/utils/IOUtils.cpp:123
msgid "Error in Calculating File Hash "
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/main.cpp:153
+#: /home/eric/Documents/GpgFrontend/src/app.cpp:110
msgid "A serious error has occurred"
msgstr ""
-#: /home/eric/develop/cpp/GpgFrontend/src/main.cpp:154
+#: /home/eric/Documents/GpgFrontend/src/app.cpp:111
msgid ""
"Oh no! GpgFrontend caught a serious error in the software, so it needs to be "
"restarted. If the problem recurs, please manually terminate the program and "
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 88ec8148..31b865d6 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -44,7 +44,7 @@ find_package(Gpgme REQUIRED)
find_package(Config++ REQUIRED)
# Introduce OpenSSL
-if(APPLE)
+if (APPLE)
set(OPENSSL_ROOT_DIR /usr/local/opt/openssl@3)
endif()
find_package(OpenSSL REQUIRED)
@@ -86,6 +86,10 @@ if (BUILD_APPLICATION)
endif ()
if (BUILD_CORE)
+ # core depends pinentry
+ message("[+] Build Pinentry")
+ add_subdirectory(pinentry)
+
message("[+] Build Core")
add_subdirectory(core)
endif ()
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index bb8cdf77..137acc7b 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -24,8 +24,8 @@
# SPDX-License-Identifier: GPL-3.0-or-later
-aux_source_directory(./function/basic CORE_SOURCE)
aux_source_directory(./function/result_analyse CORE_SOURCE)
+aux_source_directory(./function/basic CORE_SOURCE)
aux_source_directory(./function/gpg CORE_SOURCE)
aux_source_directory(./function CORE_SOURCE)
aux_source_directory(./thread CORE_SOURCE)
@@ -43,6 +43,9 @@ add_library(gpgfrontend_core SHARED ${CORE_SOURCE})
set(_export_file "${CMAKE_CURRENT_SOURCE_DIR}/GpgFrontendCoreExport.h")
generate_export_header(gpgfrontend_core EXPORT_FILE_NAME "${_export_file}")
+# link buddled pinentry
+target_link_libraries(gpgfrontend_core PRIVATE gpgfrontend_pinentry)
+
# link third-party libraries
target_link_libraries(gpgfrontend_core PUBLIC config++)
if (NOT LINUX)
diff --git a/src/core/function/CoreSignalStation.h b/src/core/function/CoreSignalStation.h
index 35177a7f..a53f2eb4 100644
--- a/src/core/function/CoreSignalStation.h
+++ b/src/core/function/CoreSignalStation.h
@@ -54,13 +54,13 @@ class GPGFRONTEND_CORE_EXPORT CoreSignalStation : public QObject {
* @brief
*
*/
- void SignalUserInputPassphraseDone();
+ void SignalNeedUserInputPassphrase();
/**
* @brief
*
*/
- void SignalNeedUserInputPassphrase();
+ void SignalUserInputPassphraseCallback(QByteArray);
/**
* @brief
diff --git a/src/core/function/gpg/GpgContext.cpp b/src/core/function/gpg/GpgContext.cpp
index e6975ea4..9ee81bad 100644
--- a/src/core/function/gpg/GpgContext.cpp
+++ b/src/core/function/gpg/GpgContext.cpp
@@ -30,10 +30,19 @@
#include <gpg-error.h>
#include <gpgme.h>
+#include <qapplication.h>
+#include <qcoreapplication.h>
+#include <qeasingcurve.h>
#include <qeventloop.h>
+#include <qlabel.h>
#include <qobject.h>
+#include <qtmetamacros.h>
+#include <qwindowdefs.h>
+#include <sys/types.h>
#include <unistd.h>
+#include <cstring>
+
#include "core/function/CoreSignalStation.h"
#include "core/function/basic/GpgFunctionObject.h"
#include "core/function/gpg/GpgCommandExecutor.h"
@@ -44,6 +53,7 @@
#include "core/utils/CacheUtils.h"
#include "core/utils/CommonUtils.h"
#include "core/utils/GpgUtils.h"
+#include "function/CacheManager.h"
#include "spdlog/spdlog.h"
#ifdef _WIN32
@@ -247,36 +257,28 @@ class GpgContext::Impl : public SingletonFunctionObject<GpgContext::Impl> {
const char *passphrase_info, int last_was_bad,
int fd) -> gpgme_error_t {
auto *p_ctx = static_cast<GpgContext *>(hook);
- SPDLOG_DEBUG("custom passphrase cb called, bad times: {}", last_was_bad);
-
- if (last_was_bad > 3) {
- SPDLOG_WARN("failure_counts is over three times");
- return gpgme_error_from_errno(GPG_ERR_CANCELED);
- }
+ std::string passphrase;
- std::string passphrase = GetTempCacheValue("__key_passphrase");
- // no pawword is an error situation
- if (passphrase.empty()) {
- // user input passphrase
- SPDLOG_DEBUG("might need user to input passparase");
+ SPDLOG_DEBUG(
+ "custom passphrase cb called, uid: {}, info: {}, last_was_bad: {}",
+ uid_hint == nullptr ? "<empty>" : std::string{uid_hint},
+ passphrase_info == nullptr ? "<empty>" : std::string{passphrase_info},
+ last_was_bad);
- p_ctx->ShowPasswordInputDialog();
- passphrase = GetTempCacheValue("__key_passphrase");
+ emit CoreSignalStation::GetInstance()->SignalNeedUserInputPassphrase();
- SPDLOG_DEBUG("use may has inputed the passphrase");
-
- if (passphrase.empty()) {
- SPDLOG_ERROR("cannot get passphrase from use or passphrase is empty");
-
- gpgme_io_write(fd, "\n", 1);
- return gpgme_error_from_errno(GPG_ERR_CANCELED);
- }
- }
+ QEventLoop looper;
+ QObject::connect(
+ CoreSignalStation::GetInstance(),
+ &CoreSignalStation::SignalUserInputPassphraseCallback, &looper,
+ [&](const QByteArray &buffer) { passphrase = buffer.toStdString(); });
+ QObject::connect(CoreSignalStation::GetInstance(),
+ &CoreSignalStation::SignalUserInputPassphraseCallback,
+ &looper, &QEventLoop::quit);
+ looper.exec();
- // the user must at least write a newline character before returning from
- // the callback.
- passphrase = passphrase.append("\n");
auto passpahrase_size = passphrase.size();
+ SPDLOG_DEBUG("get passphrase from pinentry size: {}", passpahrase_size);
size_t off = 0;
size_t res = 0;
@@ -285,8 +287,12 @@ class GpgContext::Impl : public SingletonFunctionObject<GpgContext::Impl> {
if (res > 0) off += res;
} while (res > 0 && off != passpahrase_size);
- return off == passpahrase_size ? 0
- : gpgme_error_from_errno(GPG_ERR_CANCELED);
+ res += gpgme_io_write(fd, "\n", 1);
+
+ SPDLOG_DEBUG("custom passphrase cd is about to return, res: {}", res);
+ return res == passpahrase_size + 1
+ ? 0
+ : gpgme_error_from_errno(GPG_ERR_CANCELED);
}
static auto TestStatusCb(void *hook, const char *keyword, const char *args)
@@ -295,18 +301,6 @@ class GpgContext::Impl : public SingletonFunctionObject<GpgContext::Impl> {
return GPG_ERR_NO_ERROR;
}
- void ShowPasswordInputDialog() {
- emit parent_->SignalNeedUserInputPassphrase();
-
- QEventLoop looper;
- QObject::connect(CoreSignalStation::GetInstance(),
- &CoreSignalStation::SignalUserInputPassphraseDone, &looper,
- &QEventLoop::quit);
- looper.exec();
-
- SPDLOG_DEBUG("show password input dialog done");
- }
-
private:
struct CtxRefDeleter {
void operator()(gpgme_ctx_t _ctx) {
@@ -364,10 +358,6 @@ class GpgContext::Impl : public SingletonFunctionObject<GpgContext::Impl> {
SPDLOG_DEBUG("ctx set custom key db path: {}", database_path);
assert(CheckGpgError(err) == GPG_ERR_NO_ERROR);
}
-
- QObject::connect(parent_, &GpgContext::SignalNeedUserInputPassphrase,
- CoreSignalStation::GetInstance(),
- &CoreSignalStation::SignalNeedUserInputPassphrase);
}
};
@@ -389,10 +379,6 @@ GpgContext::operator gpgme_ctx_t() const {
return static_cast<gpgme_ctx_t>(*p_);
}
-void GpgContext::ShowPasswordInputDialog() {
- return p_->ShowPasswordInputDialog();
-}
-
GpgContext::~GpgContext() = default;
} // namespace GpgFrontend \ No newline at end of file
diff --git a/src/core/function/gpg/GpgContext.h b/src/core/function/gpg/GpgContext.h
index b9042128..527099fc 100644
--- a/src/core/function/gpg/GpgContext.h
+++ b/src/core/function/gpg/GpgContext.h
@@ -71,11 +71,6 @@ class GPGFRONTEND_CORE_EXPORT GpgContext
void SetPassphraseCb(gpgme_passphrase_cb_t passphrase_cb) const;
- void ShowPasswordInputDialog();
-
- signals:
- void SignalNeedUserInputPassphrase();
-
private:
class Impl;
std::unique_ptr<Impl> p_;
diff --git a/src/core/function/gpg/GpgKeyOpera.cpp b/src/core/function/gpg/GpgKeyOpera.cpp
index e48a84d8..64f33373 100644
--- a/src/core/function/gpg/GpgKeyOpera.cpp
+++ b/src/core/function/gpg/GpgKeyOpera.cpp
@@ -28,6 +28,9 @@
#include "GpgKeyOpera.h"
+#include <gpg-error.h>
+#include <qeventloop.h>
+
#include <boost/algorithm/string.hpp>
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/conversion.hpp>
@@ -41,8 +44,12 @@
#include "core/function/result_analyse/GpgResultAnalyse.h"
#include "core/model/GpgGenKeyInfo.h"
#include "core/module/ModuleManager.h"
+#include "core/thread/Task.h"
+#include "core/thread/TaskRunnerGetter.h"
#include "core/utils/CommonUtils.h"
#include "core/utils/GpgUtils.h"
+#include "model/DataObject.h"
+#include "spdlog/spdlog.h"
namespace GpgFrontend {
@@ -271,17 +278,33 @@ auto GpgKeyOpera::GenerateSubkey(const GpgKey& key,
return CheckGpgError(err);
}
-auto GpgKeyOpera::ModifyPassword(const GpgKey& key) -> GpgError {
+void GpgKeyOpera::ModifyPassword(const GpgKey& key,
+ std::function<void(gpgme_error_t)> callback) {
const auto gnupg_version = Module::RetrieveRTValueTypedOrDefault<>(
"core", "gpgme.ctx.gnupg_version", std::string{"2.0.0"});
SPDLOG_DEBUG("got gnupg version from rt: {}", gnupg_version);
if (CompareSoftwareVersion(gnupg_version, "2.0.15") < 0) {
SPDLOG_ERROR("operator not support");
- return GPG_ERR_NOT_SUPPORTED;
+ callback(GPG_ERR_NOT_SUPPORTED);
+ return;
}
- auto err = gpgme_op_passwd(ctx_, static_cast<gpgme_key_t>(key), 0);
- return CheckGpgError(err);
+
+ auto *task = new Thread::Task(
+ [&](const DataObjectPtr& data_object) -> int {
+ auto err = gpgme_op_passwd(ctx_, static_cast<gpgme_key_t>(key), 0);
+ data_object->Swap({err});
+ return 0;
+ },
+ "gpgme_op_passwd", TransferParams(),
+ [=](int, const DataObjectPtr& data_object) {
+ SPDLOG_DEBUG("callback called");
+ callback(ExtractParams<gpgme_error_t>(data_object, 0));
+ });
+
+ Thread::TaskRunnerGetter::GetInstance()
+ .GetTaskRunner(Thread::TaskRunnerGetter::kTaskRunnerType_GPG)
+ ->PostTask(task);
}
auto GpgKeyOpera::ModifyTOFUPolicy(const GpgKey& key,
diff --git a/src/core/function/gpg/GpgKeyOpera.h b/src/core/function/gpg/GpgKeyOpera.h
index 0186cdbb..dd2ee60d 100644
--- a/src/core/function/gpg/GpgKeyOpera.h
+++ b/src/core/function/gpg/GpgKeyOpera.h
@@ -28,6 +28,8 @@
#pragma once
+#include <functional>
+
#include "core/function/gpg/GpgContext.h"
#include "core/function/result_analyse/GpgResultAnalyse.h"
#include "core/typedef/GpgTypedef.h"
@@ -98,7 +100,7 @@ class GPGFRONTEND_CORE_EXPORT GpgKeyOpera
* @param key
* @return GpgFrontend::GpgError
*/
- auto ModifyPassword(const GpgKey& key) -> GpgFrontend::GpgError;
+ void ModifyPassword(const GpgKey& key, std::function<void(gpgme_error_t)>);
/**
* @brief
diff --git a/src/core/thread/Task.cpp b/src/core/thread/Task.cpp
index d7f1dab9..92592bf4 100644
--- a/src/core/thread/Task.cpp
+++ b/src/core/thread/Task.cpp
@@ -89,7 +89,7 @@ class Task::Impl : public QObject {
std::string GetUUID() const { return uuid_; }
void Run() {
- SPDLOG_DEBUG("task {} is using default runnable and callback mode",
+ SPDLOG_TRACE("task {} is using default runnable and callback mode",
GetFullID());
if (runnable_) {
SetRTN(runnable_(data_object_));
@@ -184,27 +184,27 @@ class Task::Impl : public QObject {
try {
if (callback_) {
- SPDLOG_DEBUG("task {} has a callback function", GetFullID());
+ SPDLOG_TRACE("task {} has a callback function", GetFullID());
if (callback_thread_ == QThread::currentThread()) {
- SPDLOG_DEBUG("for task {}, the callback thread is the same thread",
+ SPDLOG_TRACE("for task {}, the callback thread is the same thread",
GetFullID(), callback_thread_->currentThreadId());
callback_(rtn, data_object_);
// raise signal, announcing this task comes to an end
- SPDLOG_DEBUG(
+ SPDLOG_TRACE(
"for task {}, its life comes to an end in the same thread after "
"its callback executed.",
parent_->GetFullID());
emit parent_->SignalTaskEnd();
} else {
- SPDLOG_DEBUG("for task {}, callback thread is a different thread: {}",
+ SPDLOG_TRACE("for task {}, callback thread is a different thread: {}",
GetFullID(), callback_thread_->currentThreadId());
if (!QMetaObject::invokeMethod(
callback_thread_,
[callback = callback_, rtn = rtn_, data_object = data_object_,
parent_ = this->parent_]() {
- SPDLOG_DEBUG("calling callback of task {}",
+ SPDLOG_TRACE("calling callback of task {}",
parent_->GetFullID());
try {
callback(rtn, data_object);
@@ -215,7 +215,7 @@ class Task::Impl : public QObject {
parent_->GetFullID());
}
// raise signal, announcing this task comes to an end
- SPDLOG_DEBUG(
+ SPDLOG_TRACE(
"for task {}, its life comes to an end whether its "
"callback function fails or not.",
parent_->GetFullID());
@@ -225,7 +225,7 @@ class Task::Impl : public QObject {
"task {} had failed to invoke the callback function to target "
"thread",
GetFullID());
- SPDLOG_DEBUG(
+ SPDLOG_TRACE(
"for task {}, its life must come to an end now, although it "
"has something not done yet.",
GetFullID());
@@ -234,7 +234,7 @@ class Task::Impl : public QObject {
}
} else {
// raise signal, announcing this task comes to an end
- SPDLOG_DEBUG(
+ SPDLOG_TRACE(
"for task {}, its life comes to an end without callback "
"peacefully.",
GetFullID());
@@ -246,7 +246,7 @@ class Task::Impl : public QObject {
"stacktrace of the exception: {}",
boost::stacktrace::to_string(boost::stacktrace::stacktrace()));
// raise signal, announcing this task comes to an end
- SPDLOG_DEBUG("for task {}, its life comes to an end at chaos.",
+ SPDLOG_TRACE("for task {}, its life comes to an end at chaos.",
GetFullID());
emit parent_->SignalTaskEnd();
} catch (...) {
@@ -255,7 +255,7 @@ class Task::Impl : public QObject {
"stacktrace of the exception: {}",
boost::stacktrace::to_string(boost::stacktrace::stacktrace()));
// raise signal, announcing this task comes to an end
- SPDLOG_DEBUG("for task {}, its life comes to an end at unknown chaos.",
+ SPDLOG_TRACE("for task {}, its life comes to an end at unknown chaos.",
GetFullID());
emit parent_->SignalTaskEnd();
}
@@ -291,7 +291,7 @@ void Task::SafelyRun() { emit SignalRun(); }
void Task::Run() { p_->Run(); }
void Task::run() {
- SPDLOG_DEBUG("interface run() of task {} was called by thread: {}",
+ SPDLOG_TRACE("interface run() of task {} was called by thread: {}",
GetFullID(), QThread::currentThread()->currentThreadId());
this->SafelyRun();
}
diff --git a/src/pinentry/CMakeLists.txt b/src/pinentry/CMakeLists.txt
new file mode 100644
index 00000000..e6d53feb
--- /dev/null
+++ b/src/pinentry/CMakeLists.txt
@@ -0,0 +1,69 @@
+# Copyright (C) 2021 Saturneric <[email protected]>
+#
+# This file is part of GpgFrontend.
+#
+# GpgFrontend is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# GpgFrontend is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>.
+#
+# The initial version of the source code is inherited from
+# the gpg4usb project, which is under GPL-3.0-or-later.
+#
+# All the source code of GpgFrontend was modified and released by
+# Saturneric <[email protected]> starting on May 12, 2021.
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+aux_source_directory(. PINENTRY_SOURCE)
+
+# capslock
+list(APPEND PINENTRY_SOURCE "capslock/capslock.cpp")
+if (MINGW)
+ list(APPEND PINENTRY_SOURCE "capslock/capslock_win.cpp")
+else()
+ list(APPEND PINENTRY_SOURCE "capslock/capslock_unix.cpp")
+endif()
+
+message(STATUS "PINENTRY_SOURCE: ${PINENTRY_SOURCE}")
+add_library(gpgfrontend_pinentry SHARED ${PINENTRY_SOURCE})
+
+# link Qt core
+if(Qt6_DIR)
+ target_link_libraries(gpgfrontend_pinentry PUBLIC Qt6::Core Qt6::Widgets)
+else()
+ target_link_libraries(gpgfrontend_pinentry PUBLIC Qt5::Core Qt5::Widgets)
+endif()
+
+# using std c++ 17
+target_compile_features(gpgfrontend_pinentry PUBLIC cxx_std_17)
+
+# link for different platforms
+if (MINGW)
+ message(STATUS "Link GPG Static Library For MINGW")
+ target_link_libraries(gpgfrontend_pinentry PUBLIC wsock32)
+elseif (APPLE)
+ message(STATUS "Link GPG Static Library For macOS")
+ target_link_libraries(gpgfrontend_pinentry PUBLIC dl)
+ if (XCODE_BUILD)
+ set_target_properties(gpgfrontend_pinentry
+ 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}
+ XCODE_ATTRIBUTE_SKIP_INSTALL "Yes"
+ XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "${GPGFRONTEND_XOCDE_CODE_SIGN_IDENTITY}")
+ endif ()
+else ()
+ # linux
+ message(STATUS "Link GPG Static Library For Unix")
+ target_link_libraries(gpgfrontend_pinentry PUBLIC pthread dl)
+endif ()
diff --git a/src/pinentry/accessibility.cpp b/src/pinentry/accessibility.cpp
new file mode 100644
index 00000000..f139832a
--- /dev/null
+++ b/src/pinentry/accessibility.cpp
@@ -0,0 +1,44 @@
+/* accessibility.cpp - Helpers for making pinentry accessible
+ * Copyright (C) 2021 g10 Code GmbH
+ *
+ * Software engineering by Ingo Klöcker <[email protected]>
+ *
+ * This program 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 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include "accessibility.h"
+
+#include <QString>
+#include <QWidget>
+
+namespace Accessibility {
+
+void setDescription(QWidget *w, const QString &text) {
+ if (w) {
+#ifndef QT_NO_ACCESSIBILITY
+ w->setAccessibleDescription(text);
+#endif
+ }
+}
+
+void setName(QWidget *w, const QString &text) {
+ if (w) {
+#ifndef QT_NO_ACCESSIBILITY
+ w->setAccessibleName(text);
+#endif
+ }
+}
+
+} // namespace Accessibility
diff --git a/src/pinentry/accessibility.h b/src/pinentry/accessibility.h
new file mode 100644
index 00000000..9ef912d6
--- /dev/null
+++ b/src/pinentry/accessibility.h
@@ -0,0 +1,40 @@
+/* accessibility.h - Helpers for making pinentry accessible
+ * Copyright (C) 2021 g10 Code GmbH
+ *
+ * Software engineering by Ingo Klöcker <[email protected]>
+ *
+ * This program 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 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __PINENTRY_QT_ACCESSIBILITY_H__
+#define __PINENTRY_QT_ACCESSIBILITY_H__
+
+class QString;
+class QWidget;
+
+namespace Accessibility
+{
+
+/* Wrapper for QWidget::setAccessibleDescription which does nothing if
+ QT_NO_ACCESSIBILITY is defined. */
+void setDescription(QWidget *w, const QString &text);
+
+/* Wrapper for QWidget::setAccessibleName which does nothing if
+ QT_NO_ACCESSIBILITY is defined. */
+void setName(QWidget *w, const QString &text);
+
+} // namespace Accessibility
+
+#endif // __PINENTRY_QT_ACCESSIBILITY_H__
diff --git a/src/pinentry/argparse.cpp b/src/pinentry/argparse.cpp
new file mode 100644
index 00000000..d3568c64
--- /dev/null
+++ b/src/pinentry/argparse.cpp
@@ -0,0 +1,1360 @@
+/* [argparse.c wk 17.06.97] Argument Parser for option handling
+ * Copyright (C) 1998-2001, 2006-2008, 2012 Free Software Foundation, Inc.
+ * Copyright (C) 1997-2001, 2006-2008, 2013-2015 Werner Koch
+ *
+ * This file is part of JNLIB, which is a subsystem of GnuPG.
+ *
+ * JNLIB is free software; you can redistribute it and/or modify it
+ * under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * or both in parallel, as here.
+ *
+ * JNLIB 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 copies of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: (GPL-2.0+ OR LGPL-3.0+)
+ */
+
+/* This file may be used as part of GnuPG or standalone. A GnuPG
+ build is detected by the presence of the macro GNUPG_MAJOR_VERSION.
+ Some feature are only availalbe in the GnuPG build mode.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef GNUPG_MAJOR_VERSION
+#include "libjnlib-config.h"
+#include "logging.h"
+#include "mischelp.h"
+#include "stringhelp.h"
+#ifdef JNLIB_NEED_UTF8CONV
+#include "utf8conv.h"
+#endif
+#endif /*GNUPG_MAJOR_VERSION*/
+
+#include "argparse.h"
+
+/* GnuPG uses GPLv3+ but a standalone version of this defaults to
+ GPLv2+ because that is the license of this file. Change this if
+ you include it in a program which uses GPLv3. If you don't want to
+ set a a copyright string for your usage() you may also hardcode it
+ here. */
+#ifndef GNUPG_MAJOR_VERSION
+
+#define ARGPARSE_GPL_VERSION 2
+#define ARGPARSE_CRIGHT_STR "Copyright (C) YEAR NAME"
+
+#else /* Used by GnuPG */
+
+#define ARGPARSE_GPL_VERSION 3
+#define ARGPARSE_CRIGHT_STR "Copyright (C) 2015 Free Software Foundation, Inc."
+
+#endif /*GNUPG_MAJOR_VERSION*/
+
+/* Replacements for standalone builds. */
+#ifndef GNUPG_MAJOR_VERSION
+#ifndef _
+#define _(a) (a)
+#endif
+#ifndef DIM
+#define DIM(v) (sizeof(v) / sizeof((v)[0]))
+#endif
+#define jnlib_malloc(a) malloc((a))
+#define jnlib_realloc(a, b) realloc((a), (b))
+#define jnlib_strdup(a) strdup((a))
+#define jnlib_free(a) free((a))
+#define jnlib_log_error my_log_error
+#define jnlib_log_bug my_log_bug
+#define trim_spaces(a) my_trim_spaces((a))
+#define map_static_macro_string(a) (a)
+#endif /*!GNUPG_MAJOR_VERSION*/
+
+#define ARGPARSE_STR(v) #v
+#define ARGPARSE_STR2(v) ARGPARSE_STR(v)
+
+/* Replacements for standalone builds. */
+#ifndef GNUPG_MAJOR_VERSION
+static void my_log_error(const char *fmt, ...) {
+ va_list arg_ptr;
+
+ va_start(arg_ptr, fmt);
+ fprintf(stderr, "%s: ", strusage(11));
+ vfprintf(stderr, fmt, arg_ptr);
+ va_end(arg_ptr);
+}
+
+static void my_log_bug(const char *fmt, ...) {
+ va_list arg_ptr;
+
+ va_start(arg_ptr, fmt);
+ fprintf(stderr, "%s: Ohhhh jeeee: ", strusage(11));
+ vfprintf(stderr, fmt, arg_ptr);
+ va_end(arg_ptr);
+ abort();
+}
+
+static char *my_trim_spaces(char *str) {
+ char *string, *p, *mark;
+
+ string = str;
+ /* Find first non space character. */
+ for (p = string; *p && isspace(*(unsigned char *)p); p++)
+ ;
+ /* Move characters. */
+ for ((mark = NULL); (*string = *p); string++, p++)
+ if (isspace(*(unsigned char *)p)) {
+ if (!mark) mark = string;
+ } else
+ mark = NULL;
+ if (mark) *mark = '\0'; /* Remove trailing spaces. */
+
+ return str;
+}
+
+#endif /*!GNUPG_MAJOR_VERSION*/
+
+/*********************************
+ * @Summary arg_parse
+ * #include "argparse.h"
+ *
+ * typedef struct {
+ * char *argc; pointer to argc (value subject to change)
+ * char ***argv; pointer to argv (value subject to change)
+ * unsigned flags; Global flags (DO NOT CHANGE)
+ * int err; print error about last option
+ * 1 = warning, 2 = abort
+ * int r_opt; return option
+ * int r_type; type of return value (0 = no argument found)
+ * union {
+ * int ret_int;
+ * long ret_long
+ * ulong ret_ulong;
+ * char *ret_str;
+ * } r; Return values
+ * struct {
+ * int idx;
+ * const char *last;
+ * void *aliases;
+ * } internal; DO NOT CHANGE
+ * } ARGPARSE_ARGS;
+ *
+ * typedef struct {
+ * int short_opt;
+ * const char *long_opt;
+ * unsigned flags;
+ * } ARGPARSE_OPTS;
+ *
+ * int arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts );
+ *
+ * @Description
+ * This is my replacement for getopt(). See the example for a typical usage.
+ * Global flags are:
+ * Bit 0 : Do not remove options form argv
+ * Bit 1 : Do not stop at last option but return other args
+ * with r_opt set to -1.
+ * Bit 2 : Assume options and real args are mixed.
+ * Bit 3 : Do not use -- to stop option processing.
+ * Bit 4 : Do not skip the first arg.
+ * Bit 5 : allow usage of long option with only one dash
+ * Bit 6 : ignore --version
+ * all other bits must be set to zero, this value is modified by the
+ * function, so assume this is write only.
+ * Local flags (for each option):
+ * Bit 2-0 : 0 = does not take an argument
+ * 1 = takes int argument
+ * 2 = takes string argument
+ * 3 = takes long argument
+ * 4 = takes ulong argument
+ * Bit 3 : argument is optional (r_type will the be set to 0)
+ * Bit 4 : allow 0x etc. prefixed values.
+ * Bit 6 : Ignore this option
+ * Bit 7 : This is a command and not an option
+ * You stop the option processing by setting opts to NULL, the function will
+ * then return 0.
+ * @Return Value
+ * Returns the args.r_opt or 0 if ready
+ * r_opt may be -2/-7 to indicate an unknown option/command.
+ * @See Also
+ * ArgExpand
+ * @Notes
+ * You do not need to process the options 'h', '--help' or '--version'
+ * because this function includes standard help processing; but if you
+ * specify '-h', '--help' or '--version' you have to do it yourself.
+ * The option '--' stops argument processing; if bit 1 is set the function
+ * continues to return normal arguments.
+ * To process float args or unsigned args you must use a string args and do
+ * the conversion yourself.
+ * @Example
+ *
+ * ARGPARSE_OPTS opts[] = {
+ * { 'v', "verbose", 0 },
+ * { 'd', "debug", 0 },
+ * { 'o', "output", 2 },
+ * { 'c', "cross-ref", 2|8 },
+ * { 'm', "my-option", 1|8 },
+ * { 300, "ignored-long-option, ARGPARSE_OP_IGNORE},
+ * { 500, "have-no-short-option-for-this-long-option", 0 },
+ * {0} };
+ * ARGPARSE_ARGS pargs = { &argc, &argv, 0 }
+ *
+ * while( ArgParse( &pargs, &opts) ) {
+ * switch( pargs.r_opt ) {
+ * case 'v': opt.verbose++; break;
+ * case 'd': opt.debug++; break;
+ * case 'o': opt.outfile = pargs.r.ret_str; break;
+ * case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break;
+ * case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break;
+ * case 500: opt.a_long_one++; break
+ * default : pargs.err = 1; break; -- force warning output --
+ * }
+ * }
+ * if( argc > 1 )
+ * log_fatal( "Too many args");
+ *
+ */
+
+typedef struct alias_def_s *ALIAS_DEF;
+struct alias_def_s {
+ ALIAS_DEF next;
+ char *name; /* malloced buffer with name, \0, value */
+ const char *value; /* ptr into name */
+};
+
+/* Object to store the names for the --ignore-invalid-option option.
+ This is a simple linked list. */
+typedef struct iio_item_def_s *IIO_ITEM_DEF;
+struct iio_item_def_s {
+ IIO_ITEM_DEF next;
+ char name[1]; /* String with the long option name. */
+};
+
+static const char *(*strusage_handler)(int) = NULL;
+static int (*custom_outfnc)(int, const char *);
+
+static int set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s);
+static void show_help(ARGPARSE_OPTS *opts, unsigned flags);
+static void show_version(void);
+static int writestrings(int is_error, const char *string, ...)
+#if __GNUC__ >= 4
+ __attribute__((sentinel(0)))
+#endif
+ ;
+
+void argparse_register_outfnc(int (*fnc)(int, const char *)) {
+ custom_outfnc = fnc;
+}
+
+/* Write STRING and all following const char * arguments either to
+ stdout or, if IS_ERROR is set, to stderr. The list of strings must
+ be terminated by a NULL. */
+static int writestrings(int is_error, const char *string, ...) {
+ va_list arg_ptr;
+ const char *s;
+ int count = 0;
+
+ if (string) {
+ s = string;
+ va_start(arg_ptr, string);
+ do {
+ if (custom_outfnc)
+ custom_outfnc(is_error ? 2 : 1, s);
+ else
+ fputs(s, is_error ? stderr : stdout);
+ count += strlen(s);
+ } while ((s = va_arg(arg_ptr, const char *)));
+ va_end(arg_ptr);
+ }
+ return count;
+}
+
+static void flushstrings(int is_error) {
+ if (custom_outfnc)
+ custom_outfnc(is_error ? 2 : 1, NULL);
+ else
+ fflush(is_error ? stderr : stdout);
+}
+
+static void initialize(ARGPARSE_ARGS *arg, const char *filename,
+ unsigned *lineno) {
+ if (!(arg->flags & (1 << 15))) {
+ /* Initialize this instance. */
+ arg->internal.idx = 0;
+ arg->internal.last = NULL;
+ arg->internal.inarg = 0;
+ arg->internal.stopped = 0;
+ arg->internal.aliases = NULL;
+ arg->internal.cur_alias = NULL;
+ arg->internal.iio_list = NULL;
+ arg->err = 0;
+ arg->flags |= 1 << 15; /* Mark as initialized. */
+ if (*arg->argc < 0) jnlib_log_bug("invalid argument for arg_parse\n");
+ }
+
+ if (arg->err) {
+ /* Last option was erroneous. */
+ const char *s;
+
+ if (filename) {
+ if (arg->r_opt == ARGPARSE_UNEXPECTED_ARG)
+ s = _("argument not expected");
+ else if (arg->r_opt == ARGPARSE_READ_ERROR)
+ s = _("read error");
+ else if (arg->r_opt == ARGPARSE_KEYWORD_TOO_LONG)
+ s = _("keyword too long");
+ else if (arg->r_opt == ARGPARSE_MISSING_ARG)
+ s = _("missing argument");
+ else if (arg->r_opt == ARGPARSE_INVALID_ARG)
+ s = _("invalid argument");
+ else if (arg->r_opt == ARGPARSE_INVALID_COMMAND)
+ s = _("invalid command");
+ else if (arg->r_opt == ARGPARSE_INVALID_ALIAS)
+ s = _("invalid alias definition");
+ else if (arg->r_opt == ARGPARSE_OUT_OF_CORE)
+ s = _("out of core");
+ else
+ s = _("invalid option");
+ jnlib_log_error("%s:%u: %s\n", filename, *lineno, s);
+ } else {
+ s = arg->internal.last ? arg->internal.last : "[??]";
+
+ if (arg->r_opt == ARGPARSE_MISSING_ARG)
+ jnlib_log_error(_("missing argument for option \"%.50s\"\n"), s);
+ else if (arg->r_opt == ARGPARSE_INVALID_ARG)
+ jnlib_log_error(_("invalid argument for option \"%.50s\"\n"), s);
+ else if (arg->r_opt == ARGPARSE_UNEXPECTED_ARG)
+ jnlib_log_error(_("option \"%.50s\" does not expect an "
+ "argument\n"),
+ s);
+ else if (arg->r_opt == ARGPARSE_INVALID_COMMAND)
+ jnlib_log_error(_("invalid command \"%.50s\"\n"), s);
+ else if (arg->r_opt == ARGPARSE_AMBIGUOUS_OPTION)
+ jnlib_log_error(_("option \"%.50s\" is ambiguous\n"), s);
+ else if (arg->r_opt == ARGPARSE_AMBIGUOUS_COMMAND)
+ jnlib_log_error(_("command \"%.50s\" is ambiguous\n"), s);
+ else if (arg->r_opt == ARGPARSE_OUT_OF_CORE)
+ jnlib_log_error("%s\n", _("out of core\n"));
+ else
+ jnlib_log_error(_("invalid option \"%.50s\"\n"), s);
+ }
+ if (arg->err != ARGPARSE_PRINT_WARNING) exit(2);
+ arg->err = 0;
+ }
+
+ /* Zero out the return value union. */
+ arg->r.ret_str = NULL;
+ arg->r.ret_long = 0;
+}
+
+static void store_alias(ARGPARSE_ARGS *arg, char *name, char *value) {
+ /* TODO: replace this dummy function with a rea one
+ * and fix the probelms IRIX has with (ALIAS_DEV)arg..
+ * used as lvalue
+ */
+ (void)arg;
+ (void)name;
+ (void)value;
+#if 0
+ ALIAS_DEF a = jnlib_xmalloc( sizeof *a );
+ a->name = name;
+ a->value = value;
+ a->next = (ALIAS_DEF)arg->internal.aliases;
+ (ALIAS_DEF)arg->internal.aliases = a;
+#endif
+}
+
+/* Return true if KEYWORD is in the ignore-invalid-option list. */
+static int ignore_invalid_option_p(ARGPARSE_ARGS *arg, const char *keyword) {
+ IIO_ITEM_DEF item = (IIO_ITEM_DEF)arg->internal.iio_list;
+
+ for (; item; item = item->next)
+ if (!strcmp(item->name, keyword)) return 1;
+ return 0;
+}
+
+/* Add the keywords up to the next LF to the list of to be ignored
+ options. After returning FP will either be at EOF or the next
+ character read wll be the first of a new line. The function
+ returns 0 on success or true on malloc failure. */
+static int ignore_invalid_option_add(ARGPARSE_ARGS *arg, FILE *fp) {
+ IIO_ITEM_DEF item;
+ int c;
+ char name[100];
+ int namelen = 0;
+ int ready = 0;
+ enum { skipWS, collectNAME, skipNAME, addNAME } state = skipWS;
+
+ while (!ready) {
+ c = getc(fp);
+ if (c == '\n')
+ ready = 1;
+ else if (c == EOF) {
+ c = '\n';
+ ready = 1;
+ }
+ again:
+ switch (state) {
+ case skipWS:
+ if (!isascii(c) || !isspace(c)) {
+ namelen = 0;
+ state = collectNAME;
+ goto again;
+ }
+ break;
+
+ case collectNAME:
+ if (isspace(c)) {
+ state = addNAME;
+ goto again;
+ } else if (namelen < DIM(name) - 1)
+ name[namelen++] = c;
+ else /* Too long. */
+ state = skipNAME;
+ break;
+
+ case skipNAME:
+ if (isspace(c)) {
+ state = skipWS;
+ goto again;
+ }
+ break;
+
+ case addNAME:
+ name[namelen] = 0;
+ if (!ignore_invalid_option_p(arg, name)) {
+ item = (IIO_ITEM_DEF)jnlib_malloc(sizeof *item + namelen);
+ if (!item) return 1;
+ strcpy(item->name, name);
+ item->next = (IIO_ITEM_DEF)arg->internal.iio_list;
+ arg->internal.iio_list = item;
+ }
+ state = skipWS;
+ goto again;
+ }
+ }
+ return 0;
+}
+
+/* Clear the entire ignore-invalid-option list. */
+static void ignore_invalid_option_clear(ARGPARSE_ARGS *arg) {
+ IIO_ITEM_DEF item, tmpitem;
+
+ for (item = (IIO_ITEM_DEF)arg->internal.iio_list; item; item = tmpitem) {
+ tmpitem = item->next;
+ jnlib_free(item);
+ }
+ arg->internal.iio_list = NULL;
+}
+
+/****************
+ * Get options from a file.
+ * Lines starting with '#' are comment lines.
+ * Syntax is simply a keyword and the argument.
+ * Valid keywords are all keywords from the long_opt list without
+ * the leading dashes. The special keywords "help", "warranty" and "version"
+ * are not valid here.
+ * The special keyword "alias" may be used to store alias definitions,
+ * which are later expanded like long options.
+ * The option
+ * ignore-invalid-option OPTIONNAMEs
+ * is recognized and updates a list of option which should be ignored if they
+ * are not defined.
+ * Caller must free returned strings.
+ * If called with FP set to NULL command line args are parse instead.
+ *
+ * Q: Should we allow the syntax
+ * keyword = value
+ * and accept for boolean options a value of 1/0, yes/no or true/false?
+ * Note: Abbreviation of options is here not allowed.
+ */
+int optfile_parse(FILE *fp, const char *filename, unsigned *lineno,
+ ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts) {
+ int state, i, c;
+ int idx = 0;
+ char keyword[100];
+ char *buffer = NULL;
+ size_t buflen = 0;
+ int in_alias = 0;
+
+ if (!fp) /* Divert to to arg_parse() in this case. */
+ return arg_parse(arg, opts);
+
+ initialize(arg, filename, lineno);
+
+ /* Find the next keyword. */
+ state = i = 0;
+ for (;;) {
+ c = getc(fp);
+ if (c == '\n' || c == EOF) {
+ if (c != EOF) ++*lineno;
+ if (state == -1)
+ break;
+ else if (state == 2) {
+ keyword[i] = 0;
+ for (i = 0; opts[i].short_opt; i++) {
+ if (opts[i].long_opt && !strcmp(opts[i].long_opt, keyword)) break;
+ }
+ idx = i;
+ arg->r_opt = opts[idx].short_opt;
+ if ((opts[idx].flags & ARGPARSE_OPT_IGNORE)) {
+ state = i = 0;
+ continue;
+ } else if (!opts[idx].short_opt) {
+ if (!strcmp(keyword, "ignore-invalid-option")) {
+ /* No argument - ignore this meta option. */
+ state = i = 0;
+ continue;
+ } else if (ignore_invalid_option_p(arg, keyword)) {
+ /* This invalid option is in the iio list. */
+ state = i = 0;
+ continue;
+ }
+ arg->r_opt = ((opts[idx].flags & ARGPARSE_OPT_COMMAND)
+ ? ARGPARSE_INVALID_COMMAND
+ : ARGPARSE_INVALID_OPTION);
+ } else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK))
+ arg->r_type = 0; /* Does not take an arg. */
+ else if ((opts[idx].flags & ARGPARSE_OPT_OPTIONAL))
+ arg->r_type = 0; /* Arg is optional. */
+ else
+ arg->r_opt = ARGPARSE_MISSING_ARG;
+
+ break;
+ } else if (state == 3) {
+ /* No argument found. */
+ if (in_alias)
+ arg->r_opt = ARGPARSE_MISSING_ARG;
+ else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK))
+ arg->r_type = 0; /* Does not take an arg. */
+ else if ((opts[idx].flags & ARGPARSE_OPT_OPTIONAL))
+ arg->r_type = 0; /* No optional argument. */
+ else
+ arg->r_opt = ARGPARSE_MISSING_ARG;
+
+ break;
+ } else if (state == 4) {
+ /* Has an argument. */
+ if (in_alias) {
+ if (!buffer)
+ arg->r_opt = ARGPARSE_UNEXPECTED_ARG;
+ else {
+ char *p;
+
+ buffer[i] = 0;
+ p = strpbrk(buffer, " \t");
+ if (p) {
+ *p++ = 0;
+ trim_spaces(p);
+ }
+ if (!p || !*p) {
+ jnlib_free(buffer);
+ arg->r_opt = ARGPARSE_INVALID_ALIAS;
+ } else {
+ store_alias(arg, buffer, p);
+ }
+ }
+ } else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK))
+ arg->r_opt = ARGPARSE_UNEXPECTED_ARG;
+ else {
+ char *p;
+
+ if (!buffer) {
+ keyword[i] = 0;
+ buffer = jnlib_strdup(keyword);
+ if (!buffer) arg->r_opt = ARGPARSE_OUT_OF_CORE;
+ } else
+ buffer[i] = 0;
+
+ if (buffer) {
+ trim_spaces(buffer);
+ p = buffer;
+ if (*p == '"') {
+ /* Remove quotes. */
+ p++;
+ if (*p && p[strlen(p) - 1] == '\"') p[strlen(p) - 1] = 0;
+ }
+ if (!set_opt_arg(arg, opts[idx].flags, p)) jnlib_free(buffer);
+ }
+ }
+ break;
+ } else if (c == EOF) {
+ ignore_invalid_option_clear(arg);
+ if (ferror(fp))
+ arg->r_opt = ARGPARSE_READ_ERROR;
+ else
+ arg->r_opt = 0; /* EOF. */
+ break;
+ }
+ state = 0;
+ i = 0;
+ } else if (state == -1)
+ ; /* Skip. */
+ else if (state == 0 && isascii(c) && isspace(c))
+ ; /* Skip leading white space. */
+ else if (state == 0 && c == '#')
+ state = 1; /* Start of a comment. */
+ else if (state == 1)
+ ; /* Skip comments. */
+ else if (state == 2 && isascii(c) && isspace(c)) {
+ /* Check keyword. */
+ keyword[i] = 0;
+ for (i = 0; opts[i].short_opt; i++)
+ if (opts[i].long_opt && !strcmp(opts[i].long_opt, keyword)) break;
+ idx = i;
+ arg->r_opt = opts[idx].short_opt;
+ if ((opts[idx].flags & ARGPARSE_OPT_IGNORE)) {
+ state = 1; /* Process like a comment. */
+ } else if (!opts[idx].short_opt) {
+ if (!strcmp(keyword, "alias")) {
+ in_alias = 1;
+ state = 3;
+ } else if (!strcmp(keyword, "ignore-invalid-option")) {
+ if (ignore_invalid_option_add(arg, fp)) {
+ arg->r_opt = ARGPARSE_OUT_OF_CORE;
+ break;
+ }
+ state = i = 0;
+ ++*lineno;
+ } else if (ignore_invalid_option_p(arg, keyword))
+ state = 1; /* Process like a comment. */
+ else {
+ arg->r_opt = ((opts[idx].flags & ARGPARSE_OPT_COMMAND)
+ ? ARGPARSE_INVALID_COMMAND
+ : ARGPARSE_INVALID_OPTION);
+ state = -1; /* Skip rest of line and leave. */
+ }
+ } else
+ state = 3;
+ } else if (state == 3) {
+ /* Skip leading spaces of the argument. */
+ if (!isascii(c) || !isspace(c)) {
+ i = 0;
+ keyword[i++] = c;
+ state = 4;
+ }
+ } else if (state == 4) {
+ /* Collect the argument. */
+ if (buffer) {
+ if (i < buflen - 1)
+ buffer[i++] = c;
+ else {
+ char *tmp;
+ size_t tmplen = buflen + 50;
+
+ tmp = (char *)jnlib_realloc(buffer, tmplen);
+ if (tmp) {
+ buflen = tmplen;
+ buffer = tmp;
+ buffer[i++] = c;
+ } else {
+ jnlib_free(buffer);
+ arg->r_opt = ARGPARSE_OUT_OF_CORE;
+ break;
+ }
+ }
+ } else if (i < DIM(keyword) - 1)
+ keyword[i++] = c;
+ else {
+ size_t tmplen = DIM(keyword) + 50;
+ buffer = (char *)jnlib_malloc(tmplen);
+ if (buffer) {
+ buflen = tmplen;
+ memcpy(buffer, keyword, i);
+ buffer[i++] = c;
+ } else {
+ arg->r_opt = ARGPARSE_OUT_OF_CORE;
+ break;
+ }
+ }
+ } else if (i >= DIM(keyword) - 1) {
+ arg->r_opt = ARGPARSE_KEYWORD_TOO_LONG;
+ state = -1; /* Skip rest of line and leave. */
+ } else {
+ keyword[i++] = c;
+ state = 2;
+ }
+ }
+
+ return arg->r_opt;
+}
+
+static int find_long_option(ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts,
+ const char *keyword) {
+ int i;
+ size_t n;
+
+ (void)arg;
+
+ /* Would be better if we can do a binary search, but it is not
+ possible to reorder our option table because we would mess
+ up our help strings - What we can do is: Build a nice option
+ lookup table when this function is first invoked */
+ if (!*keyword) return -1;
+ for (i = 0; opts[i].short_opt; i++)
+ if (opts[i].long_opt && !strcmp(opts[i].long_opt, keyword)) return i;
+#if 0
+ {
+ ALIAS_DEF a;
+ /* see whether it is an alias */
+ for( a = args->internal.aliases; a; a = a->next ) {
+ if( !strcmp( a->name, keyword) ) {
+ /* todo: must parse the alias here */
+ args->internal.cur_alias = a;
+ return -3; /* alias available */
+ }
+ }
+ }
+#endif
+ /* not found, see whether it is an abbreviation */
+ /* aliases may not be abbreviated */
+ n = strlen(keyword);
+ for (i = 0; opts[i].short_opt; i++) {
+ if (opts[i].long_opt && !strncmp(opts[i].long_opt, keyword, n)) {
+ int j;
+ for (j = i + 1; opts[j].short_opt; j++) {
+ if (opts[j].long_opt && !strncmp(opts[j].long_opt, keyword, n))
+ return -2; /* abbreviation is ambiguous */
+ }
+ return i;
+ }
+ }
+ return -1; /* Not found. */
+}
+
+int arg_parse(ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts) {
+ int idx;
+ int argc;
+ char **argv;
+ char *s, *s2;
+ int i;
+
+ initialize(arg, NULL, NULL);
+ argc = *arg->argc;
+ argv = *arg->argv;
+ idx = arg->internal.idx;
+
+ if (!idx && argc && !(arg->flags & ARGPARSE_FLAG_ARG0)) {
+ /* Skip the first argument. */
+ argc--;
+ argv++;
+ idx++;
+ }
+
+next_one:
+ if (!argc) {
+ /* No more args. */
+ arg->r_opt = 0;
+ goto leave; /* Ready. */
+ }
+
+ s = *argv;
+ arg->internal.last = s;
+
+ if (arg->internal.stopped && (arg->flags & ARGPARSE_FLAG_ALL)) {
+ arg->r_opt = ARGPARSE_IS_ARG; /* Not an option but an argument. */
+ arg->r_type = 2;
+ arg->r.ret_str = s;
+ argc--;
+ argv++;
+ idx++; /* set to next one */
+ } else if (arg->internal.stopped) {
+ arg->r_opt = 0;
+ goto leave; /* Ready. */
+ } else if (*s == '-' && s[1] == '-') {
+ /* Long option. */
+ char *argpos;
+
+ arg->internal.inarg = 0;
+ if (!s[2] && !(arg->flags & ARGPARSE_FLAG_NOSTOP)) {
+ /* Stop option processing. */
+ arg->internal.stopped = 1;
+ arg->flags |= ARGPARSE_FLAG_STOP_SEEN;
+ argc--;
+ argv++;
+ idx++;
+ goto next_one;
+ }
+
+ argpos = strchr(s + 2, '=');
+ if (argpos) *argpos = 0;
+ i = find_long_option(arg, opts, s + 2);
+ if (argpos) *argpos = '=';
+
+ if (i < 0 && !strcmp("help", s + 2))
+ show_help(opts, arg->flags);
+ else if (i < 0 && !strcmp("version", s + 2)) {
+ if (!(arg->flags & ARGPARSE_FLAG_NOVERSION)) {
+ show_version();
+ exit(0);
+ }
+ } else if (i < 0 && !strcmp("warranty", s + 2)) {
+ writestrings(0, strusage(16), "\n", NULL);
+ exit(0);
+ } else if (i < 0 && !strcmp("dump-options", s + 2)) {
+ for (i = 0; opts[i].short_opt; i++) {
+ if (opts[i].long_opt && !(opts[i].flags & ARGPARSE_OPT_IGNORE))
+ writestrings(0, "--", opts[i].long_opt, "\n", NULL);
+ }
+ writestrings(0, "--dump-options\n--help\n--version\n--warranty\n", NULL);
+ exit(0);
+ }
+
+ if (i == -2)
+ arg->r_opt = ARGPARSE_AMBIGUOUS_OPTION;
+ else if (i == -1) {
+ arg->r_opt = ARGPARSE_INVALID_OPTION;
+ arg->r.ret_str = s + 2;
+ } else
+ arg->r_opt = opts[i].short_opt;
+ if (i < 0)
+ ;
+ else if ((opts[i].flags & ARGPARSE_TYPE_MASK)) {
+ if (argpos) {
+ s2 = argpos + 1;
+ if (!*s2) s2 = NULL;
+ } else
+ s2 = argv[1];
+ if (!s2 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL)) {
+ arg->r_type = ARGPARSE_TYPE_NONE; /* Argument is optional. */
+ } else if (!s2) {
+ arg->r_opt = ARGPARSE_MISSING_ARG;
+ } else if (!argpos && *s2 == '-' &&
+ (opts[i].flags & ARGPARSE_OPT_OPTIONAL)) {
+ /* The argument is optional and the next seems to be an
+ option. We do not check this possible option but
+ assume no argument */
+ arg->r_type = ARGPARSE_TYPE_NONE;
+ } else {
+ set_opt_arg(arg, opts[i].flags, s2);
+ if (!argpos) {
+ argc--;
+ argv++;
+ idx++; /* Skip one. */
+ }
+ }
+ } else {
+ /* Does not take an argument. */
+ if (argpos)
+ arg->r_type = ARGPARSE_UNEXPECTED_ARG;
+ else
+ arg->r_type = 0;
+ }
+ argc--;
+ argv++;
+ idx++; /* Set to next one. */
+ } else if ((*s == '-' && s[1]) || arg->internal.inarg) {
+ /* Short option. */
+ int dash_kludge = 0;
+
+ i = 0;
+ if (!arg->internal.inarg) {
+ arg->internal.inarg++;
+ if ((arg->flags & ARGPARSE_FLAG_ONEDASH)) {
+ for (i = 0; opts[i].short_opt; i++)
+ if (opts[i].long_opt && !strcmp(opts[i].long_opt, s + 1)) {
+ dash_kludge = 1;
+ break;
+ }
+ }
+ }
+ s += arg->internal.inarg;
+
+ if (!dash_kludge) {
+ for (i = 0; opts[i].short_opt; i++)
+ if (opts[i].short_opt == *s) break;
+ }
+
+ if (!opts[i].short_opt && (*s == 'h' || *s == '?'))
+ show_help(opts, arg->flags);
+
+ arg->r_opt = opts[i].short_opt;
+ if (!opts[i].short_opt) {
+ arg->r_opt = (opts[i].flags & ARGPARSE_OPT_COMMAND)
+ ? ARGPARSE_INVALID_COMMAND
+ : ARGPARSE_INVALID_OPTION;
+ arg->internal.inarg++; /* Point to the next arg. */
+ arg->r.ret_str = s;
+ } else if ((opts[i].flags & ARGPARSE_TYPE_MASK)) {
+ if (s[1] && !dash_kludge) {
+ s2 = s + 1;
+ set_opt_arg(arg, opts[i].flags, s2);
+ } else {
+ s2 = argv[1];
+ if (!s2 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL)) {
+ arg->r_type = ARGPARSE_TYPE_NONE;
+ } else if (!s2) {
+ arg->r_opt = ARGPARSE_MISSING_ARG;
+ } else if (*s2 == '-' && s2[1] &&
+ (opts[i].flags & ARGPARSE_OPT_OPTIONAL)) {
+ /* The argument is optional and the next seems to
+ be an option. We do not check this possible
+ option but assume no argument. */
+ arg->r_type = ARGPARSE_TYPE_NONE;
+ } else {
+ set_opt_arg(arg, opts[i].flags, s2);
+ argc--;
+ argv++;
+ idx++; /* Skip one. */
+ }
+ }
+ s = "x"; /* This is so that !s[1] yields false. */
+ } else {
+ /* Does not take an argument. */
+ arg->r_type = ARGPARSE_TYPE_NONE;
+ arg->internal.inarg++; /* Point to the next arg. */
+ }
+ if (!s[1] || dash_kludge) {
+ /* No more concatenated short options. */
+ arg->internal.inarg = 0;
+ argc--;
+ argv++;
+ idx++;
+ }
+ } else if (arg->flags & ARGPARSE_FLAG_MIXED) {
+ arg->r_opt = ARGPARSE_IS_ARG;
+ arg->r_type = 2;
+ arg->r.ret_str = s;
+ argc--;
+ argv++;
+ idx++; /* Set to next one. */
+ } else {
+ arg->internal.stopped = 1; /* Stop option processing. */
+ goto next_one;
+ }
+
+leave:
+ *arg->argc = argc;
+ *arg->argv = argv;
+ arg->internal.idx = idx;
+ return arg->r_opt;
+}
+
+/* Returns: -1 on error, 0 for an integer type and 1 for a non integer
+ type argument. */
+static int set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s) {
+ int base = (flags & ARGPARSE_OPT_PREFIX) ? 0 : 10;
+ long l;
+
+ switch ((arg->r_type = (flags & ARGPARSE_TYPE_MASK))) {
+ case ARGPARSE_TYPE_LONG:
+ case ARGPARSE_TYPE_INT:
+ errno = 0;
+ l = strtol(s, NULL, base);
+ if ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE) {
+ arg->r_opt = ARGPARSE_INVALID_ARG;
+ return -1;
+ }
+ if (arg->r_type == ARGPARSE_TYPE_LONG)
+ arg->r.ret_long = l;
+ else if ((l < 0 && l < INT_MIN) || l > INT_MAX) {
+ arg->r_opt = ARGPARSE_INVALID_ARG;
+ return -1;
+ } else
+ arg->r.ret_int = (int)l;
+ return 0;
+
+ case ARGPARSE_TYPE_ULONG:
+ while (isascii(*s) && isspace(*s)) s++;
+ if (*s == '-') {
+ arg->r.ret_ulong = 0;
+ arg->r_opt = ARGPARSE_INVALID_ARG;
+ return -1;
+ }
+ errno = 0;
+ arg->r.ret_ulong = strtoul(s, NULL, base);
+ if (arg->r.ret_ulong == ULONG_MAX && errno == ERANGE) {
+ arg->r_opt = ARGPARSE_INVALID_ARG;
+ return -1;
+ }
+ return 0;
+
+ case ARGPARSE_TYPE_STRING:
+ default:
+ arg->r.ret_str = s;
+ return 1;
+ }
+}
+
+static size_t long_opt_strlen(ARGPARSE_OPTS *o) {
+ size_t n = strlen(o->long_opt);
+
+ if (o->description && *o->description == '|') {
+ const char *s;
+#ifdef JNLIB_NEED_UTF8CONV
+ int is_utf8 = is_native_utf8();
+#endif
+
+ s = o->description + 1;
+ if (*s != '=') n++;
+ /* For a (mostly) correct length calculation we exclude
+ continuation bytes (10xxxxxx) if we are on a native utf8
+ terminal. */
+ for (; *s && *s != '|'; s++)
+#ifdef JNLIB_NEED_UTF8CONV
+ if (is_utf8 && (*s & 0xc0) != 0x80)
+#endif
+ n++;
+ }
+ return n;
+}
+
+/****************
+ * Print formatted help. The description string has some special
+ * meanings:
+ * - A description string which is "@" suppresses help output for
+ * this option
+ * - a description,ine which starts with a '@' and is followed by
+ * any other characters is printed as is; this may be used for examples
+ * ans such.
+ * - A description which starts with a '|' outputs the string between this
+ * bar and the next one as arguments of the long option.
+ */
+static void show_help(ARGPARSE_OPTS *opts, unsigned int flags) {
+ const char *s;
+ char tmp[2];
+
+ show_version();
+ writestrings(0, "\n", NULL);
+ s = strusage(42);
+ if (s && *s == '1') {
+ s = strusage(40);
+ writestrings(1, s, NULL);
+ if (*s && s[strlen(s)] != '\n') writestrings(1, "\n", NULL);
+ }
+ s = strusage(41);
+ writestrings(0, s, "\n", NULL);
+ if (opts[0].description) {
+ /* Auto format the option description. */
+ int i, j, indent;
+
+ /* Get max. length of long options. */
+ for (i = indent = 0; opts[i].short_opt; i++) {
+ if (opts[i].long_opt)
+ if (!opts[i].description || *opts[i].description != '@')
+ if ((j = long_opt_strlen(opts + i)) > indent && j < 35) indent = j;
+ }
+
+ /* Example: " -v, --verbose Viele Sachen ausgeben" */
+ indent += 10;
+ if (*opts[0].description != '@') writestrings(0, "Options:", "\n", NULL);
+ for (i = 0; opts[i].short_opt; i++) {
+ s = map_static_macro_string(_(opts[i].description));
+ if (s && *s == '@' && !s[1]) /* Hide this line. */
+ continue;
+ if (s && *s == '@') /* Unindented comment only line. */
+ {
+ for (s++; *s; s++) {
+ if (*s == '\n') {
+ if (s[1]) writestrings(0, "\n", NULL);
+ } else {
+ tmp[0] = *s;
+ tmp[1] = 0;
+ writestrings(0, tmp, NULL);
+ }
+ }
+ writestrings(0, "\n", NULL);
+ continue;
+ }
+
+ j = 3;
+ if (opts[i].short_opt < 256) {
+ tmp[0] = opts[i].short_opt;
+ tmp[1] = 0;
+ writestrings(0, " -", tmp, NULL);
+ if (!opts[i].long_opt) {
+ if (s && *s == '|') {
+ writestrings(0, " ", NULL);
+ j++;
+ for (s++; *s && *s != '|'; s++, j++) {
+ tmp[0] = *s;
+ tmp[1] = 0;
+ writestrings(0, tmp, NULL);
+ }
+ if (*s) s++;
+ }
+ }
+ } else
+ writestrings(0, " ", NULL);
+ if (opts[i].long_opt) {
+ tmp[0] = opts[i].short_opt < 256 ? ',' : ' ';
+ tmp[1] = 0;
+ j += writestrings(0, tmp, " --", opts[i].long_opt, NULL);
+ if (s && *s == '|') {
+ if (*++s != '=') {
+ writestrings(0, " ", NULL);
+ j++;
+ }
+ for (; *s && *s != '|'; s++, j++) {
+ tmp[0] = *s;
+ tmp[1] = 0;
+ writestrings(0, tmp, NULL);
+ }
+ if (*s) s++;
+ }
+ writestrings(0, " ", NULL);
+ j += 3;
+ }
+ for (; j < indent; j++) writestrings(0, " ", NULL);
+ if (s) {
+ if (*s && j > indent) {
+ writestrings(0, "\n", NULL);
+ for (j = 0; j < indent; j++) writestrings(0, " ", NULL);
+ }
+ for (; *s; s++) {
+ if (*s == '\n') {
+ if (s[1]) {
+ writestrings(0, "\n", NULL);
+ for (j = 0; j < indent; j++) writestrings(0, " ", NULL);
+ }
+ } else {
+ tmp[0] = *s;
+ tmp[1] = 0;
+ writestrings(0, tmp, NULL);
+ }
+ }
+ }
+ writestrings(0, "\n", NULL);
+ }
+ if ((flags & ARGPARSE_FLAG_ONEDASH))
+ writestrings(0,
+ "\n(A single dash may be used "
+ "instead of the double ones)\n",
+ NULL);
+ }
+ if ((s = strusage(19))) {
+ writestrings(0, "\n", NULL);
+ writestrings(0, s, NULL);
+ }
+ flushstrings(0);
+ exit(0);
+}
+
+static void show_version(void) {
+ const char *s;
+ int i;
+
+ /* Version line. */
+ writestrings(0, strusage(11), NULL);
+ if ((s = strusage(12))) writestrings(0, " (", s, ")", NULL);
+ writestrings(0, " ", strusage(13), "\n", NULL);
+ /* Additional version lines. */
+ for (i = 20; i < 30; i++)
+ if ((s = strusage(i))) writestrings(0, s, "\n", NULL);
+ /* Copyright string. */
+ if ((s = strusage(14))) writestrings(0, s, "\n", NULL);
+ /* Licence string. */
+ if ((s = strusage(10))) writestrings(0, s, "\n", NULL);
+ /* Copying conditions. */
+ if ((s = strusage(15))) writestrings(0, s, NULL);
+ /* Thanks. */
+ if ((s = strusage(18))) writestrings(0, s, NULL);
+ /* Additional program info. */
+ for (i = 30; i < 40; i++)
+ if ((s = strusage(i))) writestrings(0, s, NULL);
+ flushstrings(0);
+}
+
+void usage(int level) {
+ const char *p;
+
+ if (!level) {
+ writestrings(1, strusage(11), " ", strusage(13), "; ", strusage(14), "\n",
+ NULL);
+ flushstrings(1);
+ } else if (level == 1) {
+ p = strusage(40);
+ writestrings(1, p, NULL);
+ if (*p && p[strlen(p)] != '\n') writestrings(1, "\n", NULL);
+ exit(2);
+ } else if (level == 2) {
+ p = strusage(42);
+ if (p && *p == '1') {
+ p = strusage(40);
+ writestrings(1, p, NULL);
+ if (*p && p[strlen(p)] != '\n') writestrings(1, "\n", NULL);
+ }
+ writestrings(0, strusage(41), "\n", NULL);
+ exit(0);
+ }
+}
+
+/* Level
+ * 0: Print copyright string to stderr
+ * 1: Print a short usage hint to stderr and terminate
+ * 2: Print a long usage hint to stdout and terminate
+ * 10: Return license info string
+ * 11: Return the name of the program
+ * 12: Return optional name of package which includes this program.
+ * 13: version string
+ * 14: copyright string
+ * 15: Short copying conditions (with LFs)
+ * 16: Long copying conditions (with LFs)
+ * 17: Optional printable OS name
+ * 18: Optional thanks list (with LFs)
+ * 19: Bug report info
+ *20..29: Additional lib version strings.
+ *30..39: Additional program info (with LFs)
+ * 40: short usage note (with LF)
+ * 41: long usage note (with LF)
+ * 42: Flag string:
+ * First char is '1':
+ * The short usage notes needs to be printed
+ * before the long usage note.
+ */
+const char *strusage(int level) {
+ const char *p = strusage_handler ? strusage_handler(level) : NULL;
+
+ if (p) return map_static_macro_string(p);
+
+ switch (level) {
+ case 10:
+#if ARGPARSE_GPL_VERSION == 3
+ p =
+ ("License GPLv3+: GNU GPL version 3 or later "
+ "<https://www.gnu.org/licenses/gpl.html>");
+#else
+ p =
+ ("License GPLv2+: GNU GPL version 2 or later "
+ "<https://www.gnu.org/licenses/>");
+#endif
+ break;
+ case 11:
+ p = "foo";
+ break;
+ case 13:
+ p = "0.0";
+ break;
+ case 14:
+ p = ARGPARSE_CRIGHT_STR;
+ break;
+ case 15:
+ p = "This is free software: you are free to change and redistribute it.\n"
+ "There is NO WARRANTY, to the extent permitted by law.\n";
+ break;
+ case 16:
+ p =
+"This is free software; you can redistribute it and/or modify\n"
+"it under the terms of the GNU General Public License as published by\n"
+"the Free Software Foundation; either version "
+ARGPARSE_STR2(ARGPARSE_GPL_VERSION)
+" of the License, or\n"
+"(at your option) any later version.\n\n"
+"It is distributed in the hope that it will be useful,\n"
+"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+"GNU General Public License for more details.\n\n"
+"You should have received a copy of the GNU General Public License\n"
+"along with this software. If not, see <https://www.gnu.org/licenses/>.\n";
+ break;
+ case 40: /* short and long usage */
+ case 41:
+ p = "";
+ break;
+ }
+
+ return p;
+}
+
+/* Set the usage handler. This function is basically a constructor. */
+void set_strusage(const char *(*f)(int)) { strusage_handler = f; }
+
+#ifdef TEST
+static struct {
+ int verbose;
+ int debug;
+ char *outfile;
+ char *crf;
+ int myopt;
+ int echo;
+ int a_long_one;
+} opt;
+
+int main(int argc, char **argv) {
+ ARGPARSE_OPTS opts[] = {
+ ARGPARSE_x('v', "verbose", NONE, 0, "Laut sein"),
+ ARGPARSE_s_n('e', "echo",
+ ("Zeile ausgeben, damit wir sehen, "
+ "was wir eingegeben haben")),
+ ARGPARSE_s_n('d', "debug", "Debug\nfalls mal etwas\nschief geht"),
+ ARGPARSE_s_s('o', "output", 0),
+ ARGPARSE_o_s('c', "cross-ref", "cross-reference erzeugen\n"),
+ /* Note that on a non-utf8 terminal the ß might garble the output. */
+ ARGPARSE_s_n('s', "street",
+ "|Straße|set the name of the street to Straße"),
+ ARGPARSE_o_i('m', "my-option", 0), ARGPARSE_s_n(500, "a-long-option", 0),
+ ARGPARSE_end()};
+ ARGPARSE_ARGS pargs = {
+ &argc, &argv,
+ (ARGPARSE_FLAG_ALL | ARGPARSE_FLAG_MIXED | ARGPARSE_FLAG_ONEDASH)};
+ int i;
+
+ while (arg_parse(&pargs, opts)) {
+ switch (pargs.r_opt) {
+ case ARGPARSE_IS_ARG:
+ printf("arg='%s'\n", pargs.r.ret_str);
+ break;
+ case 'v':
+ opt.verbose++;
+ break;
+ case 'e':
+ opt.echo++;
+ break;
+ case 'd':
+ opt.debug++;
+ break;
+ case 'o':
+ opt.outfile = pargs.r.ret_str;
+ break;
+ case 'c':
+ opt.crf = pargs.r_type ? pargs.r.ret_str : "a.crf";
+ break;
+ case 'm':
+ opt.myopt = pargs.r_type ? pargs.r.ret_int : 1;
+ break;
+ case 500:
+ opt.a_long_one++;
+ break;
+ default:
+ pargs.err = ARGPARSE_PRINT_WARNING;
+ break;
+ }
+ }
+ for (i = 0; i < argc; i++) printf("%3d -> (%s)\n", i, argv[i]);
+ puts("Options:");
+ if (opt.verbose) printf(" verbose=%d\n", opt.verbose);
+ if (opt.debug) printf(" debug=%d\n", opt.debug);
+ if (opt.outfile) printf(" outfile='%s'\n", opt.outfile);
+ if (opt.crf) printf(" crffile='%s'\n", opt.crf);
+ if (opt.myopt) printf(" myopt=%d\n", opt.myopt);
+ if (opt.a_long_one) printf(" a-long-one=%d\n", opt.a_long_one);
+ if (opt.echo) printf(" echo=%d\n", opt.echo);
+
+ return 0;
+}
+#endif /*TEST*/
+
+/**** bottom of file ****/
diff --git a/src/pinentry/argparse.h b/src/pinentry/argparse.h
new file mode 100644
index 00000000..5b652eba
--- /dev/null
+++ b/src/pinentry/argparse.h
@@ -0,0 +1,204 @@
+/* argparse.h - Argument parser for option handling.
+ * Copyright (C) 1998,1999,2000,2001,2006 Free Software Foundation, Inc.
+ *
+ * This file is part of JNLIB, which is a subsystem of GnuPG.
+ *
+ * JNLIB is free software; you can redistribute it and/or modify it
+ * under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * or both in parallel, as here.
+ *
+ * JNLIB 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 copies of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: (GPL-2.0+ OR LGPL-3.0+)
+ */
+
+#ifndef LIBJNLIB_ARGPARSE_H
+#define LIBJNLIB_ARGPARSE_H
+
+#include <stdio.h>
+
+typedef struct
+{
+ int *argc; /* Pointer to ARGC (value subject to change). */
+ char ***argv; /* Pointer to ARGV (value subject to change). */
+ unsigned int flags; /* Global flags. May be set prior to calling the
+ parser. The parser may change the value. */
+ int err; /* Print error description for last option.
+ Either 0, ARGPARSE_PRINT_WARNING or
+ ARGPARSE_PRINT_ERROR. */
+
+ int r_opt; /* Returns option code. */
+ int r_type; /* Returns type of option value. */
+ union {
+ int ret_int;
+ long ret_long;
+ unsigned long ret_ulong;
+ char *ret_str;
+ } r; /* Return values */
+
+ struct {
+ int idx;
+ int inarg;
+ int stopped;
+ const char *last;
+ void *aliases;
+ const void *cur_alias;
+ void *iio_list;
+ } internal; /* Private - do not change. */
+} ARGPARSE_ARGS;
+
+typedef struct
+{
+ int short_opt;
+ const char *long_opt;
+ unsigned int flags;
+ const char *description; /* Optional option description. */
+} ARGPARSE_OPTS;
+
+
+/* Global flags (ARGPARSE_ARGS). */
+#define ARGPARSE_FLAG_KEEP 1 /* Do not remove options form argv. */
+#define ARGPARSE_FLAG_ALL 2 /* Do not stop at last option but return
+ remaining args with R_OPT set to -1. */
+#define ARGPARSE_FLAG_MIXED 4 /* Assume options and args are mixed. */
+#define ARGPARSE_FLAG_NOSTOP 8 /* Do not stop processing at "--". */
+#define ARGPARSE_FLAG_ARG0 16 /* Do not skip the first arg. */
+#define ARGPARSE_FLAG_ONEDASH 32 /* Allow long options with one dash. */
+#define ARGPARSE_FLAG_NOVERSION 64 /* No output for "--version". */
+
+#define ARGPARSE_FLAG_STOP_SEEN 256 /* Set to true if a "--" has been seen. */
+
+/* Flags for each option (ARGPARSE_OPTS). The type code may be
+ ORed with the OPT flags. */
+#define ARGPARSE_TYPE_NONE 0 /* Does not take an argument. */
+#define ARGPARSE_TYPE_INT 1 /* Takes an int argument. */
+#define ARGPARSE_TYPE_STRING 2 /* Takes a string argument. */
+#define ARGPARSE_TYPE_LONG 3 /* Takes a long argument. */
+#define ARGPARSE_TYPE_ULONG 4 /* Takes an unsigned long argument. */
+#define ARGPARSE_OPT_OPTIONAL (1<<3) /* Argument is optional. */
+#define ARGPARSE_OPT_PREFIX (1<<4) /* Allow 0x etc. prefixed values. */
+#define ARGPARSE_OPT_IGNORE (1<<6) /* Ignore command or option. */
+#define ARGPARSE_OPT_COMMAND (1<<7) /* The argument is a command. */
+
+#define ARGPARSE_TYPE_MASK 7 /* Mask for the type values (internal). */
+
+/* A set of macros to make option definitions easier to read. */
+#define ARGPARSE_x(s,l,t,f,d) \
+ { (s), (l), ARGPARSE_TYPE_ ## t | (f), (d) }
+
+#define ARGPARSE_s(s,l,t,d) \
+ { (s), (l), ARGPARSE_TYPE_ ## t, (d) }
+#define ARGPARSE_s_n(s,l,d) \
+ { (s), (l), ARGPARSE_TYPE_NONE, (d) }
+#define ARGPARSE_s_i(s,l,d) \
+ { (s), (l), ARGPARSE_TYPE_INT, (d) }
+#define ARGPARSE_s_s(s,l,d) \
+ { (s), (l), ARGPARSE_TYPE_STRING, (d) }
+#define ARGPARSE_s_l(s,l,d) \
+ { (s), (l), ARGPARSE_TYPE_LONG, (d) }
+#define ARGPARSE_s_u(s,l,d) \
+ { (s), (l), ARGPARSE_TYPE_ULONG, (d) }
+
+#define ARGPARSE_o(s,l,t,d) \
+ { (s), (l), (ARGPARSE_TYPE_ ## t | ARGPARSE_OPT_OPTIONAL), (d) }
+#define ARGPARSE_o_n(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_NONE | ARGPARSE_OPT_OPTIONAL), (d) }
+#define ARGPARSE_o_i(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_INT | ARGPARSE_OPT_OPTIONAL), (d) }
+#define ARGPARSE_o_s(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_STRING | ARGPARSE_OPT_OPTIONAL), (d) }
+#define ARGPARSE_o_l(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_LONG | ARGPARSE_OPT_OPTIONAL), (d) }
+#define ARGPARSE_o_u(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_ULONG | ARGPARSE_OPT_OPTIONAL), (d) }
+
+#define ARGPARSE_p(s,l,t,d) \
+ { (s), (l), (ARGPARSE_TYPE_ ## t | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_p_n(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_NONE | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_p_i(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_INT | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_p_s(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_STRING | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_p_l(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_LONG | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_p_u(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_ULONG | ARGPARSE_OPT_PREFIX), (d) }
+
+#define ARGPARSE_op(s,l,t,d) \
+ { (s), (l), (ARGPARSE_TYPE_ ## t \
+ | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_op_n(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_NONE \
+ | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_op_i(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_INT \
+ | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_op_s(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_STRING \
+ | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_op_l(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_LONG \
+ | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_op_u(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_ULONG \
+ | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
+
+#define ARGPARSE_c(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_NONE | ARGPARSE_OPT_COMMAND), (d) }
+
+#define ARGPARSE_ignore(s,l) \
+ { (s), (l), (ARGPARSE_OPT_IGNORE), "@" }
+
+#define ARGPARSE_group(s,d) \
+ { (s), NULL, 0, (d) }
+
+#define ARGPARSE_end() { 0, NULL, 0, NULL }
+
+
+/* Other constants. */
+#define ARGPARSE_PRINT_WARNING 1
+#define ARGPARSE_PRINT_ERROR 2
+
+
+/* Error values. */
+#define ARGPARSE_IS_ARG (-1)
+#define ARGPARSE_INVALID_OPTION (-2)
+#define ARGPARSE_MISSING_ARG (-3)
+#define ARGPARSE_KEYWORD_TOO_LONG (-4)
+#define ARGPARSE_READ_ERROR (-5)
+#define ARGPARSE_UNEXPECTED_ARG (-6)
+#define ARGPARSE_INVALID_COMMAND (-7)
+#define ARGPARSE_AMBIGUOUS_OPTION (-8)
+#define ARGPARSE_AMBIGUOUS_COMMAND (-9)
+#define ARGPARSE_INVALID_ALIAS (-10)
+#define ARGPARSE_OUT_OF_CORE (-11)
+#define ARGPARSE_INVALID_ARG (-12)
+
+
+int arg_parse (ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts);
+int optfile_parse (FILE *fp, const char *filename, unsigned *lineno,
+ ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts);
+void usage (int level);
+const char *strusage (int level);
+void set_strusage (const char *(*f)( int ));
+void argparse_register_outfnc (int (*fnc)(int, const char *));
+
+#endif /*LIBJNLIB_ARGPARSE_H*/
diff --git a/src/pinentry/capslock/capslock.cpp b/src/pinentry/capslock/capslock.cpp
new file mode 100644
index 00000000..3ff0b779
--- /dev/null
+++ b/src/pinentry/capslock/capslock.cpp
@@ -0,0 +1,45 @@
+/* capslock.cpp - Helper to check whether Caps Lock is on
+ * Copyright (C) 2021 g10 Code GmbH
+ *
+ * Software engineering by Ingo Klöcker <[email protected]>
+ *
+ * This program 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 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <QDebug>
+#include <QGuiApplication>
+
+#include "capslock.h"
+
+CapsLockWatcher::Private::Private(CapsLockWatcher *q) : q{q} {
+#ifdef PINENTRY_QT_WAYLAND
+ if (qApp->platformName() == QLatin1String("wayland")) {
+ watchWayland();
+ }
+#endif
+}
+
+CapsLockWatcher::CapsLockWatcher(QObject *parent)
+ : QObject{parent}, d{new Private{this}} {
+ if (qApp->platformName() == QLatin1String("wayland")) {
+#ifndef PINENTRY_QT_WAYLAND
+ qWarning() << "CapsLockWatcher was compiled without support for Wayland";
+#endif
+ }
+}
diff --git a/src/pinentry/capslock/capslock.h b/src/pinentry/capslock/capslock.h
new file mode 100644
index 00000000..138f88cc
--- /dev/null
+++ b/src/pinentry/capslock/capslock.h
@@ -0,0 +1,77 @@
+/* capslock.h - Helper to check whether Caps Lock is on
+ * Copyright (C) 2021 g10 Code GmbH
+ *
+ * Software engineering by Ingo Klöcker <[email protected]>
+ *
+ * This program 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 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __PINENTRY_QT_CAPSLOCK_H__
+#define __PINENTRY_QT_CAPSLOCK_H__
+
+#include <QObject>
+#include <memory>
+
+enum class LockState { Unknown = -1, Off, On };
+
+LockState capsLockState();
+
+#ifdef PINENTRY_QT_WAYLAND
+namespace KWayland {
+namespace Client {
+class Registry;
+class Seat;
+} // namespace Client
+} // namespace KWayland
+#endif
+
+class CapsLockWatcher : public QObject {
+ Q_OBJECT
+
+ public:
+ explicit CapsLockWatcher(QObject *parent = nullptr);
+
+ Q_SIGNALS:
+ void stateChanged(bool locked);
+
+ private:
+ class Private;
+ std::unique_ptr<Private> d;
+};
+
+class CapsLockWatcher::Private {
+ public:
+ explicit Private(CapsLockWatcher *);
+#ifdef PINENTRY_QT_WAYLAND
+ void watchWayland();
+#endif
+
+ private:
+#ifdef PINENTRY_QT_WAYLAND
+ void registry_seatAnnounced(quint32, quint32);
+ void seat_hasKeyboardChanged(bool);
+ void keyboard_modifiersChanged(quint32);
+#endif
+
+ private:
+ CapsLockWatcher *const q;
+
+#ifdef PINENTRY_QT_WAYLAND
+ KWayland::Client::Registry *registry = nullptr;
+ KWayland::Client::Seat *seat = nullptr;
+#endif
+};
+
+#endif // __PINENTRY_QT_CAPSLOCK_H__
diff --git a/src/pinentry/capslock/capslock_unix.cpp b/src/pinentry/capslock/capslock_unix.cpp
new file mode 100644
index 00000000..e4f4cd17
--- /dev/null
+++ b/src/pinentry/capslock/capslock_unix.cpp
@@ -0,0 +1,137 @@
+/* capslock_unix.cpp - Helper to check whether Caps Lock is on
+ * Copyright (C) 2021 g10 Code GmbH
+ *
+ * Software engineering by Ingo Klöcker <[email protected]>
+ *
+ * This program 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 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "capslock.h"
+
+#ifdef PINENTRY_QT_WAYLAND
+#include <KWayland/Client/connection_thread.h>
+#include <KWayland/Client/keyboard.h>
+#include <KWayland/Client/registry.h>
+#include <KWayland/Client/seat.h>
+#endif
+
+#include <QGuiApplication>
+
+#ifdef PINENTRY_QT_X11
+#include <X11/XKBlib.h>
+
+#include <QX11Info>
+#undef Status
+#endif
+
+#include <QDebug>
+
+#ifdef PINENTRY_QT_WAYLAND
+using namespace KWayland::Client;
+#endif
+
+#ifdef PINENTRY_QT_WAYLAND
+static bool watchingWayland = false;
+#endif
+
+LockState capsLockState() {
+ static bool reportUnsupportedPlatform = true;
+#ifdef PINENTRY_QT_X11
+ if (qApp->platformName() == QLatin1String("xcb")) {
+ unsigned int state;
+ XkbGetIndicatorState(QX11Info::display(), XkbUseCoreKbd, &state);
+ return (state & 0x01) == 1 ? LockState::On : LockState::Off;
+ }
+#endif
+#ifdef PINENTRY_QT_WAYLAND
+ if (qApp->platformName() == QLatin1String("wayland")) {
+ if (!watchingWayland && reportUnsupportedPlatform) {
+ qDebug() << "Use CapsLockWatcher for checking for Caps Lock on Wayland";
+ }
+ } else
+#endif
+ if (reportUnsupportedPlatform) {
+ qWarning() << "Checking for Caps Lock not possible on unsupported platform:"
+ << qApp->platformName();
+ }
+ reportUnsupportedPlatform = false;
+ return LockState::Unknown;
+}
+
+#ifdef PINENTRY_QT_WAYLAND
+void CapsLockWatcher::Private::watchWayland() {
+ watchingWayland = true;
+ auto connection = ConnectionThread::fromApplication(q);
+ if (!connection) {
+ qWarning() << "Failed to get connection to Wayland server from QPA";
+ return;
+ }
+ registry = new Registry{q};
+ registry->create(connection);
+ if (!registry->isValid()) {
+ qWarning() << "Failed to create valid KWayland registry";
+ return;
+ }
+ registry->setup();
+
+ connect(registry, &Registry::seatAnnounced, q,
+ [this](quint32 name, quint32 version) {
+ registry_seatAnnounced(name, version);
+ });
+}
+
+void CapsLockWatcher::Private::registry_seatAnnounced(quint32 name,
+ quint32 version) {
+ Q_ASSERT(registry);
+ seat = registry->createSeat(name, version, q);
+ if (!seat->isValid()) {
+ qWarning() << "Failed to create valid KWayland seat";
+ return;
+ }
+
+ connect(seat, &Seat::hasKeyboardChanged, q,
+ [this](bool hasKeyboard) { seat_hasKeyboardChanged(hasKeyboard); });
+}
+
+void CapsLockWatcher::Private::seat_hasKeyboardChanged(bool hasKeyboard) {
+ Q_ASSERT(seat);
+
+ if (!hasKeyboard) {
+ qDebug() << "Seat has no keyboard";
+ return;
+ }
+
+ auto keyboard = seat->createKeyboard(q);
+ if (!keyboard->isValid()) {
+ qWarning() << "Failed to create valid KWayland keyboard";
+ return;
+ }
+
+ connect(keyboard, &Keyboard::modifiersChanged, q,
+ [this](quint32, quint32, quint32 locked, quint32) {
+ keyboard_modifiersChanged(locked);
+ });
+}
+
+void CapsLockWatcher::Private::keyboard_modifiersChanged(quint32 locked) {
+ const bool capsLockIsLocked = (locked & 2u) != 0;
+ qDebug() << "Caps Lock is locked:" << capsLockIsLocked;
+ Q_EMIT q->stateChanged(capsLockIsLocked);
+}
+#endif
diff --git a/src/pinentry/capslock/capslock_win.cpp b/src/pinentry/capslock/capslock_win.cpp
new file mode 100644
index 00000000..46bc7043
--- /dev/null
+++ b/src/pinentry/capslock/capslock_win.cpp
@@ -0,0 +1,26 @@
+/* capslock_win.cpp - Helper to check whether Caps Lock is on
+ * Copyright (C) 2021 g10 Code GmbH
+ *
+ * Software engineering by Ingo Klöcker <[email protected]>
+ *
+ * This program 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 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <windows.h>
+
+#include "capslock.h"
+
+LockState capsLockState() {
+ return (GetKeyState(VK_CAPITAL) & 1) ? LockState::On : LockState::Off;
+}
diff --git a/src/pinentry/focusframe.cpp b/src/pinentry/focusframe.cpp
new file mode 100644
index 00000000..492bd4ea
--- /dev/null
+++ b/src/pinentry/focusframe.cpp
@@ -0,0 +1,72 @@
+/* focusframe.cpp - A focus indicator for labels.
+ * Copyright (C) 2022 g10 Code GmbH
+ *
+ * Software engineering by Ingo Klöcker <[email protected]>
+ *
+ * This program 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 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include "focusframe.h"
+
+#if QT_CONFIG(graphicseffect)
+#include <QGraphicsEffect>
+#endif
+#include <QStyleOptionFocusRect>
+#include <QStylePainter>
+
+static QRect effectiveWidgetRect(const QWidget *w)
+{
+ // based on QWidgetPrivate::effectiveRectFor
+#if QT_CONFIG(graphicseffect)
+ const auto* const graphicsEffect = w->graphicsEffect();
+ if (graphicsEffect && graphicsEffect->isEnabled())
+ return graphicsEffect->boundingRectFor(w->rect()).toAlignedRect();
+#endif // QT_CONFIG(graphicseffect)
+ return w->rect();
+}
+
+static QRect clipRect(const QWidget *w)
+{
+ // based on QWidgetPrivate::clipRect
+ if (!w->isVisible()) {
+ return QRect();
+ }
+ QRect r = effectiveWidgetRect(w);
+ int ox = 0;
+ int oy = 0;
+ while (w && w->isVisible() && !w->isWindow() && w->parentWidget()) {
+ ox -= w->x();
+ oy -= w->y();
+ w = w->parentWidget();
+ r &= QRect(ox, oy, w->width(), w->height());
+ }
+ return r;
+}
+
+void FocusFrame::paintEvent(QPaintEvent *)
+{
+ if (!widget()) {
+ return;
+ }
+
+ QStylePainter p{this};
+ QStyleOptionFocusRect option;
+ initStyleOption(&option);
+ const int vmargin = style()->pixelMetric(QStyle::PM_FocusFrameVMargin, &option);
+ const int hmargin = style()->pixelMetric(QStyle::PM_FocusFrameHMargin, &option);
+ const QRect rect = clipRect(widget()).adjusted(0, 0, hmargin*2, vmargin*2);
+ p.setClipRect(rect);
+ p.drawPrimitive(QStyle::PE_FrameFocusRect, option);
+}
diff --git a/src/pinentry/focusframe.h b/src/pinentry/focusframe.h
new file mode 100644
index 00000000..3d2231ea
--- /dev/null
+++ b/src/pinentry/focusframe.h
@@ -0,0 +1,36 @@
+/* focusframe.h - A focus indicator for labels.
+ * Copyright (C) 2022 g10 Code GmbH
+ *
+ * Software engineering by Ingo Klöcker <[email protected]>
+ *
+ * This program 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 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __FOCUSFRAME_H__
+#define __FOCUSFRAME_H__
+
+#include <QFocusFrame>
+
+class FocusFrame : public QFocusFrame
+{
+ Q_OBJECT
+public:
+ using QFocusFrame::QFocusFrame;
+
+protected:
+ void paintEvent(QPaintEvent *event) override;
+};
+
+#endif // __FOCUSFRAME_H__
diff --git a/src/pinentry/keyboardfocusindication.cpp b/src/pinentry/keyboardfocusindication.cpp
new file mode 100644
index 00000000..d783d981
--- /dev/null
+++ b/src/pinentry/keyboardfocusindication.cpp
@@ -0,0 +1,43 @@
+/* keyboardfocusindication.cpp - Helper for extended keyboard focus indication.
+ * Copyright (C) 2022 g10 Code GmbH
+ *
+ * Software engineering by Ingo Klöcker <[email protected]>
+ *
+ * This program 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 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include "keyboardfocusindication.h"
+
+#include "focusframe.h"
+
+#include <QApplication>
+
+KeyboardFocusIndication::KeyboardFocusIndication(QObject *parent)
+ : QObject{parent}
+{
+ connect(qApp, &QApplication::focusChanged, this, &KeyboardFocusIndication::updateFocusFrame);
+}
+
+void KeyboardFocusIndication::updateFocusFrame(QWidget *, QWidget *focusWidget)
+{
+ if (focusWidget && focusWidget->inherits("QLabel") && focusWidget->window()->testAttribute(Qt::WA_KeyboardFocusChange)) {
+ if (!focusFrame) {
+ focusFrame = new FocusFrame{focusWidget};
+ }
+ focusFrame->setWidget(focusWidget);
+ } else if (focusFrame) {
+ focusFrame->setWidget(nullptr);
+ }
+}
diff --git a/src/pinentry/keyboardfocusindication.h b/src/pinentry/keyboardfocusindication.h
new file mode 100644
index 00000000..e86a317e
--- /dev/null
+++ b/src/pinentry/keyboardfocusindication.h
@@ -0,0 +1,42 @@
+/* keyboardfocusindication.h - Helper for extended keyboard focus indication.
+ * Copyright (C) 2022 g10 Code GmbH
+ *
+ * Software engineering by Ingo Klöcker <[email protected]>
+ *
+ * This program 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 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __KEYBOARDFOCUSINDICATION_H__
+#define __KEYBOARDFOCUSINDICATION_H__
+
+#include <QObject>
+#include <QPointer>
+#include <QWidget>
+
+class FocusFrame;
+
+class KeyboardFocusIndication : public QObject
+{
+ Q_OBJECT
+public:
+ KeyboardFocusIndication(QObject *parent);
+
+private:
+ void updateFocusFrame(QWidget *, QWidget *);
+
+ QPointer<FocusFrame> focusFrame;
+};
+
+#endif // __KEYBOARDFOCUSINDICATION_H__
diff --git a/src/pinentry/password_cache.cpp b/src/pinentry/password_cache.cpp
new file mode 100644
index 00000000..b52602d7
--- /dev/null
+++ b/src/pinentry/password_cache.cpp
@@ -0,0 +1,153 @@
+/* password-cache.c - Password cache support.
+ Copyright (C) 2015 g10 Code GmbH
+
+ This file is part of PINENTRY.
+
+ PINENTRY 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 2 of the License, or
+ (at your option) any later version.
+
+ PINENTRY 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 this program; if not, see <https://www.gnu.org/licenses/>.
+ SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_LIBSECRET
+#include <libsecret/secret.h>
+#endif
+
+#include "password_cache.h"
+#include "secmem.h"
+
+#ifdef HAVE_LIBSECRET
+static const SecretSchema *gpg_schema(void) {
+ static const SecretSchema the_schema = {
+ "org.gnupg.Passphrase",
+ SECRET_SCHEMA_NONE,
+ {
+ {"stored-by", SECRET_SCHEMA_ATTRIBUTE_STRING},
+ {"keygrip", SECRET_SCHEMA_ATTRIBUTE_STRING},
+ {"NULL", 0},
+ }};
+ return &the_schema;
+}
+
+static char *keygrip_to_label(const char *keygrip) {
+ char const prefix[] = "GnuPG: ";
+ char *label;
+
+ label = malloc(sizeof(prefix) + strlen(keygrip));
+ if (label) {
+ memcpy(label, prefix, sizeof(prefix) - 1);
+ strcpy(&label[sizeof(prefix) - 1], keygrip);
+ }
+ return label;
+}
+#endif
+
+void password_cache_save(const char *keygrip, const char *password) {
+#ifdef HAVE_LIBSECRET
+ char *label;
+ GError *error = NULL;
+
+ if (!*keygrip) return;
+
+ label = keygrip_to_label(keygrip);
+ if (!label) return;
+
+ if (!secret_password_store_sync(gpg_schema(), SECRET_COLLECTION_DEFAULT,
+ label, password, NULL, &error, "stored-by",
+ "GnuPG Pinentry", "keygrip", keygrip, NULL)) {
+ fprintf(stderr,
+ "Failed to cache password for key %s with secret service: %s\n",
+ keygrip, error->message);
+
+ g_error_free(error);
+ }
+
+ free(label);
+#else
+ (void)keygrip;
+ (void)password;
+ return;
+#endif
+}
+
+char *password_cache_lookup(const char *keygrip, int *fatal_error) {
+#ifdef HAVE_LIBSECRET
+ GError *error = NULL;
+ char *password;
+ char *password2;
+
+ if (!*keygrip) return NULL;
+
+ password = secret_password_lookup_nonpageable_sync(gpg_schema(), NULL, &error,
+ "keygrip", keygrip, NULL);
+
+ if (error != NULL) {
+ if (fatal_error) *fatal_error = 1;
+
+ fprintf(stderr,
+ "Failed to lookup password for key %s with secret service: %s\n",
+ keygrip, error->message);
+ g_error_free(error);
+ return NULL;
+ }
+ if (!password)
+ /* The password for this key is not cached. Just return NULL. */
+ return NULL;
+
+ /* The password needs to be returned in secmem allocated memory. */
+ password2 = secmem_malloc(strlen(password) + 1);
+ if (password2)
+ strcpy(password2, password);
+ else
+ fprintf(stderr, "secmem_malloc failed: can't copy password!\n");
+
+ secret_password_free(password);
+
+ return password2;
+#else
+ (void)keygrip;
+ (void)fatal_error;
+ return NULL;
+#endif
+}
+
+/* Try and remove the cached password for key grip. Returns -1 on
+ error, 0 if the key is not found and 1 if the password was
+ removed. */
+int password_cache_clear(const char *keygrip) {
+#ifdef HAVE_LIBSECRET
+ GError *error = NULL;
+ int removed = secret_password_clear_sync(gpg_schema(), NULL, &error,
+ "keygrip", keygrip, NULL);
+ if (error != NULL) {
+ fprintf(stderr,
+ "Failed to clear password for key %s with secret service: %s\n",
+ keygrip, error->message);
+ g_debug("%s", error->message);
+ g_error_free(error);
+ return -1;
+ }
+ if (removed) return 1;
+ return 0;
+#else
+ (void)keygrip;
+ return -1;
+#endif
+}
diff --git a/src/pinentry/password_cache.h b/src/pinentry/password_cache.h
new file mode 100644
index 00000000..cdba356d
--- /dev/null
+++ b/src/pinentry/password_cache.h
@@ -0,0 +1,30 @@
+/* password_cache.h - Password cache support interfaces.
+ Copyright (C) 2015 g10 Code GmbH
+
+ This file is part of PINENTRY.
+
+ PINENTRY 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 2 of the License, or
+ (at your option) any later version.
+
+ PINENTRY 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 this program; if not, see <https://www.gnu.org/licenses/>.
+ SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef PASSWORD_CACHE_H
+#define PASSWORD_CACHE_H
+
+void password_cache_save(const char *key_grip, const char *password);
+
+char *password_cache_lookup(const char *key_grip, int *fatal_error);
+
+int password_cache_clear(const char *keygrip);
+
+#endif
diff --git a/src/pinentry/pinentry.cpp b/src/pinentry/pinentry.cpp
new file mode 100644
index 00000000..918944b9
--- /dev/null
+++ b/src/pinentry/pinentry.cpp
@@ -0,0 +1,1696 @@
+/* pinentry.c - The PIN entry support library
+ * Copyright (C) 2002, 2003, 2007, 2008, 2010, 2015, 2016, 2021 g10 Code GmbH
+ *
+ * This file is part of PINENTRY.
+ *
+ * PINENTRY 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * PINENTRY 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 this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef WINDOWS
+#include <errno.h>
+#endif
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#ifndef WINDOWS
+#include <sys/utsname.h>
+#endif
+#ifndef WINDOWS
+#include <locale.h>
+#endif
+#include <limits.h>
+#ifdef WINDOWS
+#include <windows.h>
+#endif
+
+#include <assuan.h>
+
+#include "argparse.h"
+#include "password_cache.h"
+#include "pinentry.h"
+#include "secmem_util.h"
+
+#ifdef WINDOWS
+#define getpid() GetCurrentProcessId()
+#endif
+
+/* Keep the name of our program here. */
+static char this_pgmname[50];
+
+struct pinentry pinentry;
+
+static const char *flavor_flag;
+
+/* Because gtk_init removes the --display arg from the command lines
+ * and our command line parser is called after gtk_init (so that it
+ * does not see gtk specific options) we don't have a way to get hold
+ * of the --display option. Our solution is to remember --display in
+ * the call to pinentry_have_display and set it then in our
+ * parser. */
+static char *remember_display;
+
+static void pinentry_reset(int use_defaults) {
+ /* GPG Agent sets these options once when it starts the pinentry.
+ Don't reset them. */
+ int grab = pinentry.grab;
+ char *ttyname = pinentry.ttyname;
+ char *ttytype = pinentry.ttytype_l;
+ char *ttyalert = pinentry.ttyalert;
+ char *lc_ctype = pinentry.lc_ctype;
+ char *lc_messages = pinentry.lc_messages;
+ int allow_external_password_cache = pinentry.allow_external_password_cache;
+ char *default_ok = pinentry.default_ok;
+ char *default_cancel = pinentry.default_cancel;
+ char *default_prompt = pinentry.default_prompt;
+ char *default_pwmngr = pinentry.default_pwmngr;
+ char *default_cf_visi = pinentry.default_cf_visi;
+ char *default_tt_visi = pinentry.default_tt_visi;
+ char *default_tt_hide = pinentry.default_tt_hide;
+ char *default_capshint = pinentry.default_capshint;
+ char *touch_file = pinentry.touch_file;
+ unsigned long owner_pid = pinentry.owner_pid;
+ int owner_uid = pinentry.owner_uid;
+ char *owner_host = pinentry.owner_host;
+ int constraints_enforce = pinentry.constraints_enforce;
+ char *constraints_hint_short = pinentry.constraints_hint_short;
+ char *constraints_hint_long = pinentry.constraints_hint_long;
+ char *constraints_error_title = pinentry.constraints_error_title;
+
+ /* These options are set from the command line. Don't reset
+ them. */
+ int debug = pinentry.debug;
+ char *display = pinentry.display;
+ int parent_wid = pinentry.parent_wid;
+
+ pinentry_color_t color_fg = pinentry.color_fg;
+ int color_fg_bright = pinentry.color_fg_bright;
+ pinentry_color_t color_bg = pinentry.color_bg;
+ pinentry_color_t color_so = pinentry.color_so;
+ int color_so_bright = pinentry.color_so_bright;
+ pinentry_color_t color_ok = pinentry.color_ok;
+ int color_ok_bright = pinentry.color_ok_bright;
+ pinentry_color_t color_qualitybar = pinentry.color_qualitybar;
+ int color_qualitybar_bright = pinentry.color_qualitybar_bright;
+
+ int timeout = pinentry.timeout;
+
+ char *invisible_char = pinentry.invisible_char;
+
+ /* Free any allocated memory. */
+ if (use_defaults) {
+ free(pinentry.ttyname);
+ free(pinentry.ttytype_l);
+ free(pinentry.ttyalert);
+ free(pinentry.lc_ctype);
+ free(pinentry.lc_messages);
+ free(pinentry.default_ok);
+ free(pinentry.default_cancel);
+ free(pinentry.default_prompt);
+ free(pinentry.default_pwmngr);
+ free(pinentry.default_cf_visi);
+ free(pinentry.default_tt_visi);
+ free(pinentry.default_tt_hide);
+ free(pinentry.default_capshint);
+ free(pinentry.touch_file);
+ free(pinentry.owner_host);
+ free(pinentry.display);
+ free(pinentry.constraints_hint_short);
+ free(pinentry.constraints_hint_long);
+ free(pinentry.constraints_error_title);
+ }
+
+ free(pinentry.title);
+ free(pinentry.description);
+ free(pinentry.error);
+ free(pinentry.prompt);
+ free(pinentry.ok);
+ free(pinentry.notok);
+ free(pinentry.cancel);
+ secmem_free(pinentry.pin);
+ free(pinentry.repeat_passphrase);
+ free(pinentry.repeat_error_string);
+ free(pinentry.quality_bar);
+ free(pinentry.quality_bar_tt);
+ free(pinentry.formatted_passphrase_hint);
+ free(pinentry.keyinfo);
+ free(pinentry.specific_err_info);
+
+ /* Reset the pinentry structure. */
+ memset(&pinentry, 0, sizeof(pinentry));
+
+ /* Restore options without a default we want to preserve. */
+ pinentry.invisible_char = invisible_char;
+
+ /* Restore other options or set defaults. */
+
+ if (use_defaults) {
+ /* Pinentry timeout in seconds. */
+ pinentry.timeout = 60;
+
+ /* Global grab. */
+ pinentry.grab = 1;
+
+ pinentry.color_fg = PINENTRY_COLOR_DEFAULT;
+ pinentry.color_fg_bright = 0;
+ pinentry.color_bg = PINENTRY_COLOR_DEFAULT;
+ pinentry.color_so = PINENTRY_COLOR_DEFAULT;
+ pinentry.color_so_bright = 0;
+ pinentry.color_ok = PINENTRY_COLOR_DEFAULT;
+ pinentry.color_ok_bright = 0;
+ pinentry.color_qualitybar = PINENTRY_COLOR_DEFAULT;
+ pinentry.color_qualitybar_bright = 0;
+
+ pinentry.owner_uid = -1;
+ } else /* Restore the options. */
+ {
+ pinentry.grab = grab;
+ pinentry.ttyname = ttyname;
+ pinentry.ttytype_l = ttytype;
+ pinentry.ttyalert = ttyalert;
+ pinentry.lc_ctype = lc_ctype;
+ pinentry.lc_messages = lc_messages;
+ pinentry.allow_external_password_cache = allow_external_password_cache;
+ pinentry.default_ok = default_ok;
+ pinentry.default_cancel = default_cancel;
+ pinentry.default_prompt = default_prompt;
+ pinentry.default_pwmngr = default_pwmngr;
+ pinentry.default_cf_visi = default_cf_visi;
+ pinentry.default_tt_visi = default_tt_visi;
+ pinentry.default_tt_hide = default_tt_hide;
+ pinentry.default_capshint = default_capshint;
+ pinentry.touch_file = touch_file;
+ pinentry.owner_pid = owner_pid;
+ pinentry.owner_uid = owner_uid;
+ pinentry.owner_host = owner_host;
+ pinentry.constraints_enforce = constraints_enforce;
+ pinentry.constraints_hint_short = constraints_hint_short;
+ pinentry.constraints_hint_long = constraints_hint_long;
+ pinentry.constraints_error_title = constraints_error_title;
+
+ pinentry.debug = debug;
+ pinentry.display = display;
+ pinentry.parent_wid = parent_wid;
+
+ pinentry.color_fg = color_fg;
+ pinentry.color_fg_bright = color_fg_bright;
+ pinentry.color_bg = color_bg;
+ pinentry.color_so = color_so;
+ pinentry.color_so_bright = color_so_bright;
+ pinentry.color_ok = color_ok;
+ pinentry.color_ok_bright = color_ok_bright;
+ pinentry.color_qualitybar = color_qualitybar;
+ pinentry.color_qualitybar_bright = color_qualitybar_bright;
+
+ pinentry.timeout = timeout;
+ }
+}
+
+static gpg_error_t pinentry_assuan_reset_handler(assuan_context_t ctx,
+ char *line) {
+ (void)ctx;
+ (void)line;
+
+ pinentry_reset(0);
+
+ return 0;
+}
+
+/* Copy TEXT or TEXTLEN to BUFFER and escape as required. Return a
+ pointer to the end of the new buffer. Note that BUFFER must be
+ large enough to keep the entire text; allocataing it 3 times of
+ TEXTLEN is sufficient. */
+static char *copy_and_escape(char *buffer, const void *text, size_t textlen) {
+ int i;
+ const unsigned char *s = (unsigned char *)text;
+ char *p = buffer;
+
+ for (i = 0; i < textlen; i++) {
+ if (s[i] < ' ' || s[i] == '+') {
+ snprintf(p, 4, "%%%02X", s[i]);
+ p += 3;
+ } else if (s[i] == ' ')
+ *p++ = '+';
+ else
+ *p++ = s[i];
+ }
+ return p;
+}
+
+/* Perform percent unescaping in STRING and return the new valid length
+ of the string. A terminating Nul character is inserted at the end of
+ the unescaped string.
+ */
+static size_t do_unescape_inplace(char *s) {
+ unsigned char *p, *p0;
+
+ p = p0 = (unsigned char *)s;
+ while (*s) {
+ if (*s == '%' && s[1] && s[2]) {
+ s++;
+ *p++ = xtoi_2(s);
+ s += 2;
+ } else
+ *p++ = *s++;
+ }
+ *p = 0;
+
+ return (p - p0);
+}
+
+/* Return a malloced copy of the commandline for PID. If this is not
+ * possible NULL is returned. */
+#ifndef WINDOWS
+static char *get_cmdline(unsigned long pid) {
+ char buffer[200];
+ FILE *fp;
+ size_t i, n;
+
+ snprintf(buffer, sizeof buffer, "/proc/%lu/cmdline", pid);
+
+ fp = fopen(buffer, "rb");
+ if (!fp) return NULL;
+ n = fread(buffer, 1, sizeof buffer - 1, fp);
+ if (n < sizeof buffer - 1 && ferror(fp)) {
+ /* Some error occurred. */
+ fclose(fp);
+ return NULL;
+ }
+ fclose(fp);
+ if (n == 0) return NULL;
+ /* Arguments are delimited by Nuls. We should do proper quoting but
+ * that can be a bit complicated, thus we simply replace the Nuls by
+ * spaces. */
+ for (i = 0; i < n; i++)
+ if (!buffer[i] && i < n - 1) buffer[i] = ' ';
+ buffer[i] = 0; /* Make sure the last byte is the string terminator. */
+
+ return strdup(buffer);
+}
+#endif /*!WINDOWS*/
+
+/* Atomically ask the kernel for information about process PID.
+ * Return a malloc'ed copy of the process name as long as the process
+ * uid matches UID. If it cannot determine that the process has uid
+ * UID, it returns NULL.
+ *
+ * This is not as informative as get_cmdline, but it verifies that the
+ * process does belong to the user in question.
+ */
+#ifndef WINDOWS
+static char *get_pid_name_for_uid(unsigned long pid, int uid) {
+ char buffer[400];
+ FILE *fp;
+ size_t end, n;
+ char *uidstr;
+
+ snprintf(buffer, sizeof buffer, "/proc/%lu/status", pid);
+
+ fp = fopen(buffer, "rb");
+ if (!fp) return NULL;
+ n = fread(buffer, 1, sizeof buffer - 1, fp);
+ if (n < sizeof buffer - 1 && ferror(fp)) {
+ /* Some error occurred. */
+ fclose(fp);
+ return NULL;
+ }
+ fclose(fp);
+ if (n == 0) return NULL;
+ buffer[n] = 0;
+ /* Fixme: Is it specified that "Name" is always the first line? For
+ * robustness I would prefer to have a real parser here. -wk */
+ if (strncmp(buffer, "Name:\t", 6)) return NULL;
+ end = strcspn(buffer + 6, "\n") + 6;
+ buffer[end] = 0;
+
+ /* check that uid matches what we expect */
+ uidstr = strstr(buffer + end + 1, "\nUid:\t");
+ if (!uidstr) return NULL;
+ if (atoi(uidstr + 6) != uid) return NULL;
+
+ return strdup(buffer + 6);
+}
+#endif /*!WINDOWS*/
+
+const char *pinentry_get_pgmname(void) { return this_pgmname; }
+
+/* Return a malloced string with the title. The caller mus free the
+ * string. If no title is available or the title string has an error
+ * NULL is returned. */
+char *pinentry_get_title(pinentry_t pe) {
+ char *title;
+
+ if (pe->title) title = strdup(pe->title);
+#ifndef WINDOWS
+ else if (pe->owner_pid) {
+ char buf[200];
+ struct utsname utsbuf;
+ char *pidname = NULL;
+ char *cmdline = NULL;
+
+ if (pe->owner_host && !uname(&utsbuf) &&
+ !strcmp(utsbuf.nodename, pe->owner_host)) {
+ pidname = get_pid_name_for_uid(pe->owner_pid, pe->owner_uid);
+ if (pidname) cmdline = get_cmdline(pe->owner_pid);
+ }
+
+ if (pe->owner_host && (cmdline || pidname))
+ snprintf(buf, sizeof buf, "[%lu]@%s (%s)", pe->owner_pid, pe->owner_host,
+ cmdline ? cmdline : pidname);
+ else if (pe->owner_host)
+ snprintf(buf, sizeof buf, "[%lu]@%s", pe->owner_pid, pe->owner_host);
+ else
+ snprintf(buf, sizeof buf, "[%lu] <unknown host>", pe->owner_pid);
+ free(pidname);
+ free(cmdline);
+ title = strdup(buf);
+ }
+#endif /*!WINDOWS*/
+ else
+ title = strdup(this_pgmname);
+
+ return title;
+}
+
+/* Run a quality inquiry for PASSPHRASE of LENGTH. (We need LENGTH
+ because not all backends might be able to return a proper
+ C-string.). Returns: A value between -100 and 100 to give an
+ estimate of the passphrase's quality. Negative values are use if
+ the caller won't even accept that passphrase. Note that we expect
+ just one data line which should not be escaped in any represent a
+ numeric signed decimal value. Extra data is currently ignored but
+ should not be send at all. */
+int pinentry_inq_quality(pinentry_t pin, const char *passphrase,
+ size_t length) {
+ assuan_context_t ctx = (assuan_context_t)pin->ctx_assuan;
+ const char prefix[] = "INQUIRE QUALITY ";
+ char *command;
+ char *line;
+ size_t linelen;
+ int gotvalue = 0;
+ int value = 0;
+ int rc;
+
+ if (!ctx) return 0; /* Can't run the callback. */
+
+ if (length > 300)
+ length = 300; /* Limit so that it definitely fits into an Assuan
+ line. */
+
+ command = (char *)secmem_malloc(strlen(prefix) + 3 * length + 1);
+ if (!command) return 0;
+ strcpy(command, prefix);
+ copy_and_escape(command + strlen(command), passphrase, length);
+ rc = assuan_write_line(ctx, command);
+ secmem_free(command);
+ if (rc) {
+ fprintf(stderr, "ASSUAN WRITE LINE failed: rc=%d\n", rc);
+ return 0;
+ }
+
+ for (;;) {
+ do {
+ rc = assuan_read_line(ctx, &line, &linelen);
+ if (rc) {
+ fprintf(stderr, "ASSUAN READ LINE failed: rc=%d\n", rc);
+ return 0;
+ }
+ } while (*line == '#' || !linelen);
+ if (line[0] == 'E' && line[1] == 'N' && line[2] == 'D' &&
+ (!line[3] || line[3] == ' '))
+ break; /* END command received*/
+ if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N' &&
+ (!line[3] || line[3] == ' '))
+ break; /* CAN command received*/
+ if (line[0] == 'E' && line[1] == 'R' && line[2] == 'R' &&
+ (!line[3] || line[3] == ' '))
+ break; /* ERR command received*/
+ if (line[0] != 'D' || line[1] != ' ' || linelen < 3 || gotvalue) continue;
+ gotvalue = 1;
+ value = atoi(line + 2);
+ }
+ if (value < -100)
+ value = -100;
+ else if (value > 100)
+ value = 100;
+
+ return value;
+}
+
+/* Run a checkpin inquiry */
+char *pinentry_inq_checkpin(pinentry_t pin, const char *passphrase,
+ size_t length) {
+ assuan_context_t ctx = (assuan_context_t)pin->ctx_assuan;
+ const char prefix[] = "INQUIRE CHECKPIN ";
+ char *command;
+ char *line;
+ size_t linelen;
+ int gotvalue = 0;
+ char *value = NULL;
+ int rc;
+
+ if (!ctx) return 0; /* Can't run the callback. */
+
+ if (length > 300)
+ length = 300; /* Limit so that it definitely fits into an Assuan
+ line. */
+
+ command = (char *)secmem_malloc(strlen(prefix) + 3 * length + 1);
+ if (!command) return 0;
+ strcpy(command, prefix);
+ copy_and_escape(command + strlen(command), passphrase, length);
+ rc = assuan_write_line(ctx, command);
+ secmem_free(command);
+ if (rc) {
+ fprintf(stderr, "ASSUAN WRITE LINE failed: rc=%d\n", rc);
+ return 0;
+ }
+
+ for (;;) {
+ do {
+ rc = assuan_read_line(ctx, &line, &linelen);
+ if (rc) {
+ fprintf(stderr, "ASSUAN READ LINE failed: rc=%d\n", rc);
+ return 0;
+ }
+ } while (*line == '#' || !linelen);
+ if (line[0] == 'E' && line[1] == 'N' && line[2] == 'D' &&
+ (!line[3] || line[3] == ' '))
+ break; /* END command received*/
+ if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N' &&
+ (!line[3] || line[3] == ' '))
+ break; /* CAN command received*/
+ if (line[0] == 'E' && line[1] == 'R' && line[2] == 'R' &&
+ (!line[3] || line[3] == ' '))
+ break; /* ERR command received*/
+ if (line[0] != 'D' || line[1] != ' ' || linelen < 3 || gotvalue) continue;
+ gotvalue = 1;
+ value = strdup(line + 2);
+ }
+
+ return value;
+}
+
+/* Run a genpin inquiry */
+char *pinentry_inq_genpin(pinentry_t pin) {
+ assuan_context_t ctx = (assuan_context_t)pin->ctx_assuan;
+ const char prefix[] = "INQUIRE GENPIN";
+ char *line;
+ size_t linelen;
+ int gotvalue = 0;
+ char *value = NULL;
+ int rc;
+
+ if (!ctx) return 0; /* Can't run the callback. */
+
+ rc = assuan_write_line(ctx, prefix);
+ if (rc) {
+ fprintf(stderr, "ASSUAN WRITE LINE failed: rc=%d\n", rc);
+ return 0;
+ }
+
+ for (;;) {
+ do {
+ rc = assuan_read_line(ctx, &line, &linelen);
+ if (rc) {
+ fprintf(stderr, "ASSUAN READ LINE failed: rc=%d\n", rc);
+ free(value);
+ return 0;
+ }
+ } while (*line == '#' || !linelen);
+ if (line[0] == 'E' && line[1] == 'N' && line[2] == 'D' &&
+ (!line[3] || line[3] == ' '))
+ break; /* END command received*/
+ if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N' &&
+ (!line[3] || line[3] == ' '))
+ break; /* CAN command received*/
+ if (line[0] == 'E' && line[1] == 'R' && line[2] == 'R' &&
+ (!line[3] || line[3] == ' '))
+ break; /* ERR command received*/
+ if (line[0] != 'D' || line[1] != ' ' || linelen < 3 || gotvalue) continue;
+ gotvalue = 1;
+ value = strdup(line + 2);
+ }
+
+ return value;
+}
+
+/* Try to make room for at least LEN bytes in the pinentry. Returns
+ new buffer on success and 0 on failure or when the old buffer is
+ sufficient. */
+char *pinentry_setbufferlen(pinentry_t pin, int len) {
+ char *newp;
+
+ if (pin->pin_len)
+ assert(pin->pin);
+ else
+ assert(!pin->pin);
+
+ if (len < 2048) len = 2048;
+
+ if (len <= pin->pin_len) return pin->pin;
+
+ newp = (char *)secmem_realloc(pin->pin, len);
+ if (newp) {
+ pin->pin = newp;
+ pin->pin_len = len;
+ } else {
+ secmem_free(pin->pin);
+ pin->pin = 0;
+ pin->pin_len = 0;
+ }
+ return newp;
+}
+
+static void pinentry_setbuffer_clear(pinentry_t pin) {
+ if (!pin->pin) {
+ assert(pin->pin_len == 0);
+ return;
+ }
+
+ assert(pin->pin_len > 0);
+
+ secmem_free(pin->pin);
+ pin->pin = NULL;
+ pin->pin_len = 0;
+}
+
+static void pinentry_setbuffer_init(pinentry_t pin) {
+ pinentry_setbuffer_clear(pin);
+ pinentry_setbufferlen(pin, 0);
+}
+
+/* passphrase better be alloced with secmem_alloc. */
+void pinentry_setbuffer_use(pinentry_t pin, char *passphrase, int len) {
+ if (!passphrase) {
+ assert(len == 0);
+ pinentry_setbuffer_clear(pin);
+
+ return;
+ }
+
+ if (passphrase && len == 0) len = strlen(passphrase) + 1;
+
+ if (pin->pin) secmem_free(pin->pin);
+
+ pin->pin = passphrase;
+ pin->pin_len = len;
+}
+
+static struct assuan_malloc_hooks assuan_malloc_hooks = {
+ secmem_malloc, secmem_realloc, secmem_free};
+
+/* Initialize the secure memory subsystem, drop privileges and return.
+ Must be called early. */
+void pinentry_init(const char *pgmname) {
+ /* Store away our name. */
+ if (strlen(pgmname) > sizeof this_pgmname - 2) abort();
+ strcpy(this_pgmname, pgmname);
+
+ gpgrt_check_version(NULL);
+
+ /* Initialize secure memory. 1 is too small, so the default size
+ will be used. */
+ secmem_init(1);
+ secmem_set_flags(SECMEM_WARN);
+ drop_privs();
+
+ if (atexit(secmem_term)) {
+ /* FIXME: Could not register at-exit function, bail out. */
+ }
+
+ assuan_set_malloc_hooks(&assuan_malloc_hooks);
+}
+
+/* Simple test to check whether DISPLAY is set or the option --display
+ was given. Used to decide whether the GUI or curses should be
+ initialized. */
+int pinentry_have_display(int argc, char **argv) {
+ int found = 0;
+
+ for (; argc; argc--, argv++) {
+ if (!strcmp(*argv, "--display")) {
+ if (argv[1] && !remember_display) {
+ remember_display = strdup(argv[1]);
+ if (!remember_display) {
+#ifndef WINDOWS
+ fprintf(stderr, "%s: %s\n", this_pgmname, strerror(errno));
+#endif
+ exit(EXIT_FAILURE);
+ }
+ }
+ found = 1;
+ break;
+ } else if (!strncmp(*argv, "--display=", 10)) {
+ if (!remember_display) {
+ remember_display = strdup(*argv + 10);
+ if (!remember_display) {
+#ifndef WINDOWS
+ fprintf(stderr, "%s: %s\n", this_pgmname, strerror(errno));
+#endif
+ exit(EXIT_FAILURE);
+ }
+ }
+ found = 1;
+ break;
+ }
+ }
+
+#ifndef WINDOWS
+ {
+ const char *s;
+ s = getenv("DISPLAY");
+ if (s && *s) found = 1;
+ }
+#endif
+
+ return found;
+}
+
+/* Print usage information and and provide strings for help. */
+static const char *my_strusage(int level) {
+ const char *p;
+
+ switch (level) {
+ case 11:
+ p = this_pgmname;
+ break;
+ case 12:
+ p = "pinentry";
+ break;
+ case 13:
+ p = 0;
+ break;
+ case 14:
+ p = "Copyright (C) 2023 Saturneric";
+ break;
+ case 19:
+ p = "Please report bugs to <[email protected]>.\n";
+ break;
+ case 1:
+ case 40: {
+ static char *str;
+
+ if (!str) {
+ size_t n = 50 + strlen(this_pgmname);
+ str = static_cast<char *>(malloc(n));
+ if (str) {
+ snprintf(str, n, "Usage: %s [options] (-h for help)", this_pgmname);
+ }
+ }
+ p = str;
+ } break;
+ case 41:
+ p = "Ask securely for a secret and print it to stdout.";
+ break;
+
+ case 42:
+ p = "1"; /* Flag print 40 as part of 41. */
+ break;
+
+ default:
+ p = NULL;
+ break;
+ }
+ return p;
+}
+
+char *parse_color(char *arg, pinentry_color_t *color_p, int *bright_p) {
+ static struct {
+ const char *name;
+ pinentry_color_t color;
+ } colors[] = {
+ {"none", PINENTRY_COLOR_NONE}, {"default", PINENTRY_COLOR_DEFAULT},
+ {"black", PINENTRY_COLOR_BLACK}, {"red", PINENTRY_COLOR_RED},
+ {"green", PINENTRY_COLOR_GREEN}, {"yellow", PINENTRY_COLOR_YELLOW},
+ {"blue", PINENTRY_COLOR_BLUE}, {"magenta", PINENTRY_COLOR_MAGENTA},
+ {"cyan", PINENTRY_COLOR_CYAN}, {"white", PINENTRY_COLOR_WHITE}};
+
+ int i;
+ char *new_arg;
+ pinentry_color_t color = PINENTRY_COLOR_DEFAULT;
+
+ if (!arg) return NULL;
+
+ new_arg = strchr(arg, ',');
+ if (new_arg) new_arg++;
+
+ if (bright_p) {
+ const char *bname[] = {"bright-", "bright", "bold-", "bold"};
+
+ *bright_p = 0;
+ for (i = 0; i < sizeof(bname) / sizeof(bname[0]); i++)
+ if (!strncasecmp(arg, bname[i], strlen(bname[i]))) {
+ *bright_p = 1;
+ arg += strlen(bname[i]);
+ }
+ }
+
+ for (i = 0; i < sizeof(colors) / sizeof(colors[0]); i++)
+ if (!strncasecmp(arg, colors[i].name, strlen(colors[i].name)))
+ color = colors[i].color;
+
+ *color_p = color;
+ return new_arg;
+}
+
+/* Parse the command line options. May exit the program if only help
+ or version output is requested. */
+void pinentry_parse_opts(int argc, char *argv[]) {
+ static ARGPARSE_OPTS opts[] = {
+ ARGPARSE_s_n('d', "debug", "Turn on debugging output"),
+ ARGPARSE_s_s('D', "display", "|DISPLAY|Set the X display"),
+ ARGPARSE_s_s('T', "ttyname", "|FILE|Set the tty terminal node name"),
+ ARGPARSE_s_s('N', "ttytype", "|NAME|Set the tty terminal type"),
+ ARGPARSE_s_s('C', "lc-ctype", "|STRING|Set the tty LC_CTYPE value"),
+ ARGPARSE_s_s('M', "lc-messages", "|STRING|Set the tty LC_MESSAGES value"),
+ ARGPARSE_s_i('o', "timeout",
+ "|SECS|Timeout waiting for input after this many seconds"),
+ ARGPARSE_s_n('g', "no-global-grab",
+ "Grab keyboard only while window is focused"),
+ ARGPARSE_s_u('W', "parent-wid", "Parent window ID (for positioning)"),
+ ARGPARSE_s_s('c', "colors", "|STRING|Set custom colors for ncurses"),
+ ARGPARSE_s_s('a', "ttyalert",
+ "|STRING|Set the alert mode (none, beep or flash)"),
+ ARGPARSE_end()};
+ ARGPARSE_ARGS pargs = {&argc, &argv, 0};
+
+ set_strusage(my_strusage);
+
+ pinentry_reset(1);
+
+ while (arg_parse(&pargs, opts)) {
+ switch (pargs.r_opt) {
+ case 'd':
+ pinentry.debug = 1;
+ break;
+ case 'g':
+ pinentry.grab = 0;
+ break;
+
+ case 'D':
+ /* Note, this is currently not used because the GUI engine
+ has already been initialized when parsing these options. */
+ pinentry.display = strdup(pargs.r.ret_str);
+ if (!pinentry.display) {
+#ifndef WINDOWS
+ fprintf(stderr, "%s: %s\n", this_pgmname, strerror(errno));
+#endif
+ exit(EXIT_FAILURE);
+ }
+ break;
+ case 'T':
+ pinentry.ttyname = strdup(pargs.r.ret_str);
+ if (!pinentry.ttyname) {
+#ifndef WINDOWS
+ fprintf(stderr, "%s: %s\n", this_pgmname, strerror(errno));
+#endif
+ exit(EXIT_FAILURE);
+ }
+ break;
+ case 'N':
+ pinentry.ttytype_l = strdup(pargs.r.ret_str);
+ if (!pinentry.ttytype_l) {
+#ifndef WINDOWS
+ fprintf(stderr, "%s: %s\n", this_pgmname, strerror(errno));
+#endif
+ exit(EXIT_FAILURE);
+ }
+ break;
+ case 'C':
+ pinentry.lc_ctype = strdup(pargs.r.ret_str);
+ if (!pinentry.lc_ctype) {
+#ifndef WINDOWS
+ fprintf(stderr, "%s: %s\n", this_pgmname, strerror(errno));
+#endif
+ exit(EXIT_FAILURE);
+ }
+ break;
+ case 'M':
+ pinentry.lc_messages = strdup(pargs.r.ret_str);
+ if (!pinentry.lc_messages) {
+#ifndef WINDOWS
+ fprintf(stderr, "%s: %s\n", this_pgmname, strerror(errno));
+#endif
+ exit(EXIT_FAILURE);
+ }
+ break;
+ case 'W':
+ pinentry.parent_wid = pargs.r.ret_ulong;
+ break;
+
+ case 'c': {
+ char *tmpstr = pargs.r.ret_str;
+
+ tmpstr =
+ parse_color(tmpstr, &pinentry.color_fg, &pinentry.color_fg_bright);
+ tmpstr = parse_color(tmpstr, &pinentry.color_bg, NULL);
+ tmpstr =
+ parse_color(tmpstr, &pinentry.color_so, &pinentry.color_so_bright);
+ tmpstr =
+ parse_color(tmpstr, &pinentry.color_ok, &pinentry.color_ok_bright);
+ tmpstr = parse_color(tmpstr, &pinentry.color_qualitybar,
+ &pinentry.color_qualitybar_bright);
+ } break;
+
+ case 'o':
+ pinentry.timeout = pargs.r.ret_int;
+ break;
+
+ case 'a':
+ pinentry.ttyalert = strdup(pargs.r.ret_str);
+ if (!pinentry.ttyalert) {
+#ifndef WINDOWS
+ fprintf(stderr, "%s: %s\n", this_pgmname, strerror(errno));
+#endif
+ exit(EXIT_FAILURE);
+ }
+ break;
+
+ default:
+ pargs.err = ARGPARSE_PRINT_WARNING;
+ break;
+ }
+ }
+
+ if (!pinentry.display && remember_display) {
+ pinentry.display = remember_display;
+ remember_display = NULL;
+ }
+}
+
+/* Set the optional flag used with getinfo. */
+void pinentry_set_flavor_flag(const char *string) { flavor_flag = string; }
+
+static gpg_error_t option_handler(assuan_context_t ctx, const char *key,
+ const char *value) {
+ (void)ctx;
+
+ if (!strcmp(key, "no-grab") && !*value)
+ pinentry.grab = 0;
+ else if (!strcmp(key, "grab") && !*value)
+ pinentry.grab = 1;
+ else if (!strcmp(key, "debug-wait")) {
+#ifndef WINDOWS
+ fprintf(stderr, "%s: waiting for debugger - my pid is %u ...\n",
+ this_pgmname, (unsigned int)getpid());
+ sleep(*value ? atoi(value) : 5);
+ fprintf(stderr, "%s: ... okay\n", this_pgmname);
+#endif
+ } else if (!strcmp(key, "display")) {
+ if (pinentry.display) free(pinentry.display);
+ pinentry.display = strdup(value);
+ if (!pinentry.display) return gpg_error_from_syserror();
+ } else if (!strcmp(key, "ttyname")) {
+ if (pinentry.ttyname) free(pinentry.ttyname);
+ pinentry.ttyname = strdup(value);
+ if (!pinentry.ttyname) return gpg_error_from_syserror();
+ } else if (!strcmp(key, "ttytype")) {
+ if (pinentry.ttytype_l) free(pinentry.ttytype_l);
+ pinentry.ttytype_l = strdup(value);
+ if (!pinentry.ttytype_l) return gpg_error_from_syserror();
+ } else if (!strcmp(key, "ttyalert")) {
+ if (pinentry.ttyalert) free(pinentry.ttyalert);
+ pinentry.ttyalert = strdup(value);
+ if (!pinentry.ttyalert) return gpg_error_from_syserror();
+ } else if (!strcmp(key, "lc-ctype")) {
+ if (pinentry.lc_ctype) free(pinentry.lc_ctype);
+ pinentry.lc_ctype = strdup(value);
+ if (!pinentry.lc_ctype) return gpg_error_from_syserror();
+ } else if (!strcmp(key, "lc-messages")) {
+ if (pinentry.lc_messages) free(pinentry.lc_messages);
+ pinentry.lc_messages = strdup(value);
+ if (!pinentry.lc_messages) return gpg_error_from_syserror();
+ } else if (!strcmp(key, "owner")) {
+ long along;
+ char *endp;
+
+ free(pinentry.owner_host);
+ pinentry.owner_host = NULL;
+ pinentry.owner_uid = -1;
+ pinentry.owner_pid = 0;
+
+ errno = 0;
+ along = strtol(value, &endp, 10);
+ if (along && !errno) {
+ pinentry.owner_pid = (unsigned long)along;
+ if (*endp) {
+ errno = 0;
+ if (*endp == '/') { /* we have a uid */
+ endp++;
+ along = strtol(endp, &endp, 10);
+ if (along >= 0 && !errno) pinentry.owner_uid = (int)along;
+ }
+ if (endp) {
+ while (*endp == ' ') endp++;
+ if (*endp) {
+ pinentry.owner_host = strdup(endp);
+ for (endp = pinentry.owner_host; *endp && *endp != ' '; endp++)
+ ;
+ *endp = 0;
+ }
+ }
+ }
+ }
+ } else if (!strcmp(key, "parent-wid")) {
+ pinentry.parent_wid = atoi(value);
+ /* FIXME: Use strtol and add some error handling. */
+ } else if (!strcmp(key, "touch-file")) {
+ if (pinentry.touch_file) free(pinentry.touch_file);
+ pinentry.touch_file = strdup(value);
+ if (!pinentry.touch_file) return gpg_error_from_syserror();
+ } else if (!strcmp(key, "default-ok")) {
+ pinentry.default_ok = strdup(value);
+ if (!pinentry.default_ok) return gpg_error_from_syserror();
+ } else if (!strcmp(key, "default-cancel")) {
+ pinentry.default_cancel = strdup(value);
+ if (!pinentry.default_cancel) return gpg_error_from_syserror();
+ } else if (!strcmp(key, "default-prompt")) {
+ pinentry.default_prompt = strdup(value);
+ if (!pinentry.default_prompt) return gpg_error_from_syserror();
+ } else if (!strcmp(key, "default-pwmngr")) {
+ pinentry.default_pwmngr = strdup(value);
+ if (!pinentry.default_pwmngr) return gpg_error_from_syserror();
+ } else if (!strcmp(key, "default-cf-visi")) {
+ pinentry.default_cf_visi = strdup(value);
+ if (!pinentry.default_cf_visi) return gpg_error_from_syserror();
+ } else if (!strcmp(key, "default-tt-visi")) {
+ pinentry.default_tt_visi = strdup(value);
+ if (!pinentry.default_tt_visi) return gpg_error_from_syserror();
+ } else if (!strcmp(key, "default-tt-hide")) {
+ pinentry.default_tt_hide = strdup(value);
+ if (!pinentry.default_tt_hide) return gpg_error_from_syserror();
+ } else if (!strcmp(key, "default-capshint")) {
+ pinentry.default_capshint = strdup(value);
+ if (!pinentry.default_capshint) return gpg_error_from_syserror();
+ } else if (!strcmp(key, "allow-external-password-cache") && !*value) {
+ pinentry.allow_external_password_cache = 1;
+ pinentry.tried_password_cache = 0;
+ } else if (!strcmp(key, "allow-emacs-prompt") && !*value) {
+#ifdef INSIDE_EMACS
+ pinentry_enable_emacs_cmd_handler();
+#endif
+ } else if (!strcmp(key, "invisible-char")) {
+ if (pinentry.invisible_char) free(pinentry.invisible_char);
+ pinentry.invisible_char = strdup(value);
+ if (!pinentry.invisible_char) return gpg_error_from_syserror();
+ } else if (!strcmp(key, "formatted-passphrase") && !*value) {
+ pinentry.formatted_passphrase = 1;
+ } else if (!strcmp(key, "formatted-passphrase-hint")) {
+ if (pinentry.formatted_passphrase_hint)
+ free(pinentry.formatted_passphrase_hint);
+ pinentry.formatted_passphrase_hint = strdup(value);
+ if (!pinentry.formatted_passphrase_hint) return gpg_error_from_syserror();
+ do_unescape_inplace(pinentry.formatted_passphrase_hint);
+ } else if (!strcmp(key, "constraints-enforce") && !*value)
+ pinentry.constraints_enforce = 1;
+ else if (!strcmp(key, "constraints-hint-short")) {
+ if (pinentry.constraints_hint_short) free(pinentry.constraints_hint_short);
+ pinentry.constraints_hint_short = strdup(value);
+ if (!pinentry.constraints_hint_short) return gpg_error_from_syserror();
+ do_unescape_inplace(pinentry.constraints_hint_short);
+ } else if (!strcmp(key, "constraints-hint-long")) {
+ if (pinentry.constraints_hint_long) free(pinentry.constraints_hint_long);
+ pinentry.constraints_hint_long = strdup(value);
+ if (!pinentry.constraints_hint_long) return gpg_error_from_syserror();
+ do_unescape_inplace(pinentry.constraints_hint_long);
+ } else if (!strcmp(key, "constraints-error-title")) {
+ if (pinentry.constraints_error_title)
+ free(pinentry.constraints_error_title);
+ pinentry.constraints_error_title = strdup(value);
+ if (!pinentry.constraints_error_title) return gpg_error_from_syserror();
+ do_unescape_inplace(pinentry.constraints_error_title);
+ } else
+ return gpg_error(GPG_ERR_UNKNOWN_OPTION);
+ return 0;
+}
+
+/* Note, that it is sufficient to allocate the target string D as
+ long as the source string S, i.e.: strlen(s)+1; */
+static void strcpy_escaped(char *d, const char *s) {
+ while (*s) {
+ if (*s == '%' && s[1] && s[2]) {
+ s++;
+ *d++ = xtoi_2(s);
+ s += 2;
+ } else
+ *d++ = *s++;
+ }
+ *d = 0;
+}
+
+static void write_status_error(assuan_context_t ctx, pinentry_t pe) {
+ char buf[500];
+ const char *pgm;
+
+ pgm = strchr(this_pgmname, '-');
+ if (pgm && pgm[1])
+ pgm++;
+ else
+ pgm = this_pgmname;
+
+ snprintf(buf, sizeof buf, "%s.%s %d %s", pgm,
+ pe->specific_err_loc ? pe->specific_err_loc : "?", pe->specific_err,
+ pe->specific_err_info ? pe->specific_err_info : "");
+ assuan_write_status(ctx, "ERROR", buf);
+}
+
+static gpg_error_t cmd_setdesc(assuan_context_t ctx, char *line) {
+ char *newd;
+
+ (void)ctx;
+
+ newd = (char *)malloc(strlen(line) + 1);
+ if (!newd) return gpg_error_from_syserror();
+
+ strcpy_escaped(newd, line);
+ if (pinentry.description) free(pinentry.description);
+ pinentry.description = newd;
+ return 0;
+}
+
+static gpg_error_t cmd_setprompt(assuan_context_t ctx, char *line) {
+ char *newp;
+
+ (void)ctx;
+
+ newp = (char *)malloc(strlen(line) + 1);
+ if (!newp) return gpg_error_from_syserror();
+
+ strcpy_escaped(newp, line);
+ if (pinentry.prompt) free(pinentry.prompt);
+ pinentry.prompt = newp;
+ return 0;
+}
+
+/* The data provided at LINE may be used by pinentry implementations
+ to identify a key for caching strategies of its own. The empty
+ string and --clear mean that the key does not have a stable
+ identifier. */
+static gpg_error_t cmd_setkeyinfo(assuan_context_t ctx, char *line) {
+ (void)ctx;
+
+ if (pinentry.keyinfo) free(pinentry.keyinfo);
+
+ if (*line && strcmp(line, "--clear") != 0)
+ pinentry.keyinfo = strdup(line);
+ else
+ pinentry.keyinfo = NULL;
+
+ return 0;
+}
+
+static gpg_error_t cmd_setrepeat(assuan_context_t ctx, char *line) {
+ char *p;
+
+ (void)ctx;
+
+ p = (char *)malloc(strlen(line) + 1);
+ if (!p) return gpg_error_from_syserror();
+
+ strcpy_escaped(p, line);
+ free(pinentry.repeat_passphrase);
+ pinentry.repeat_passphrase = p;
+ return 0;
+}
+
+static gpg_error_t cmd_setrepeatok(assuan_context_t ctx, char *line) {
+ char *p;
+
+ (void)ctx;
+
+ p = (char *)malloc(strlen(line) + 1);
+ if (!p) return gpg_error_from_syserror();
+
+ strcpy_escaped(p, line);
+ free(pinentry.repeat_ok_string);
+ pinentry.repeat_ok_string = p;
+ return 0;
+}
+
+static gpg_error_t cmd_setrepeaterror(assuan_context_t ctx, char *line) {
+ char *p;
+
+ (void)ctx;
+
+ p = (char *)malloc(strlen(line) + 1);
+ if (!p) return gpg_error_from_syserror();
+
+ strcpy_escaped(p, line);
+ free(pinentry.repeat_error_string);
+ pinentry.repeat_error_string = p;
+ return 0;
+}
+
+static gpg_error_t cmd_seterror(assuan_context_t ctx, char *line) {
+ char *newe;
+
+ (void)ctx;
+
+ newe = (char *)malloc(strlen(line) + 1);
+ if (!newe) return gpg_error_from_syserror();
+
+ strcpy_escaped(newe, line);
+ if (pinentry.error) free(pinentry.error);
+ pinentry.error = newe;
+ return 0;
+}
+
+static gpg_error_t cmd_setok(assuan_context_t ctx, char *line) {
+ char *newo;
+
+ (void)ctx;
+
+ newo = (char *)malloc(strlen(line) + 1);
+ if (!newo) return gpg_error_from_syserror();
+
+ strcpy_escaped(newo, line);
+ if (pinentry.ok) free(pinentry.ok);
+ pinentry.ok = newo;
+ return 0;
+}
+
+static gpg_error_t cmd_setnotok(assuan_context_t ctx, char *line) {
+ char *newo;
+
+ (void)ctx;
+
+ newo = (char *)malloc(strlen(line) + 1);
+ if (!newo) return gpg_error_from_syserror();
+
+ strcpy_escaped(newo, line);
+ if (pinentry.notok) free(pinentry.notok);
+ pinentry.notok = newo;
+ return 0;
+}
+
+static gpg_error_t cmd_setcancel(assuan_context_t ctx, char *line) {
+ char *newc;
+
+ (void)ctx;
+
+ newc = (char *)malloc(strlen(line) + 1);
+ if (!newc) return gpg_error_from_syserror();
+
+ strcpy_escaped(newc, line);
+ if (pinentry.cancel) free(pinentry.cancel);
+ pinentry.cancel = newc;
+ return 0;
+}
+
+static gpg_error_t cmd_settimeout(assuan_context_t ctx, char *line) {
+ (void)ctx;
+
+ if (line && *line) pinentry.timeout = atoi(line);
+
+ return 0;
+}
+
+static gpg_error_t cmd_settitle(assuan_context_t ctx, char *line) {
+ char *newt;
+
+ (void)ctx;
+
+ newt = (char *)malloc(strlen(line) + 1);
+ if (!newt) return gpg_error_from_syserror();
+
+ strcpy_escaped(newt, line);
+ if (pinentry.title) free(pinentry.title);
+ pinentry.title = newt;
+ return 0;
+}
+
+static gpg_error_t cmd_setqualitybar(assuan_context_t ctx, char *line) {
+ char *newval;
+
+ (void)ctx;
+
+ if (!*line) line = "Quality:";
+
+ newval = (char *)malloc(strlen(line) + 1);
+ if (!newval) return gpg_error_from_syserror();
+
+ strcpy_escaped(newval, line);
+ if (pinentry.quality_bar) free(pinentry.quality_bar);
+ pinentry.quality_bar = newval;
+ return 0;
+}
+
+/* Set the tooltip to be used for a quality bar. */
+static gpg_error_t cmd_setqualitybar_tt(assuan_context_t ctx, char *line) {
+ char *newval;
+
+ (void)ctx;
+
+ if (*line) {
+ newval = (char *)malloc(strlen(line) + 1);
+ if (!newval) return gpg_error_from_syserror();
+
+ strcpy_escaped(newval, line);
+ } else
+ newval = NULL;
+ if (pinentry.quality_bar_tt) free(pinentry.quality_bar_tt);
+ pinentry.quality_bar_tt = newval;
+ return 0;
+}
+
+/* Set the tooltip to be used for a generate action. */
+static gpg_error_t cmd_setgenpin_tt(assuan_context_t ctx, char *line) {
+ char *newval;
+
+ (void)ctx;
+
+ if (*line) {
+ newval = (char *)malloc(strlen(line) + 1);
+ if (!newval) return gpg_error_from_syserror();
+
+ strcpy_escaped(newval, line);
+ } else
+ newval = NULL;
+ if (pinentry.genpin_tt) free(pinentry.genpin_tt);
+ pinentry.genpin_tt = newval;
+ return 0;
+}
+
+/* Set the label to be used for a generate action. */
+static gpg_error_t cmd_setgenpin_label(assuan_context_t ctx, char *line) {
+ char *newval;
+
+ (void)ctx;
+
+ if (*line) {
+ newval = (char *)malloc(strlen(line) + 1);
+ if (!newval) return gpg_error_from_syserror();
+
+ strcpy_escaped(newval, line);
+ } else
+ newval = NULL;
+ if (pinentry.genpin_label) free(pinentry.genpin_label);
+ pinentry.genpin_label = newval;
+ return 0;
+}
+
+static gpg_error_t cmd_getpin(assuan_context_t ctx, char *line) {
+ int result;
+ int set_prompt = 0;
+ int just_read_password_from_cache = 0;
+
+ (void)line;
+
+ pinentry_setbuffer_init(&pinentry);
+ if (!pinentry.pin) return gpg_error(GPG_ERR_ENOMEM);
+
+ pinentry.confirm = 0;
+
+ /* Try reading from the password cache. */
+ if (/* If repeat passphrase is set, then we don't want to read from
+ the cache. */
+ !pinentry.repeat_passphrase
+ /* Are we allowed to read from the cache? */
+ && pinentry.allow_external_password_cache &&
+ pinentry.keyinfo
+ /* Only read from the cache if we haven't already tried it. */
+ && !pinentry.tried_password_cache
+ /* If the last read resulted in an error, then don't read from
+ the cache. */
+ && !pinentry.error) {
+ char *password;
+ int give_up_on_password_store = 0;
+
+ pinentry.tried_password_cache = 1;
+
+ password =
+ password_cache_lookup(pinentry.keyinfo, &give_up_on_password_store);
+ if (give_up_on_password_store) pinentry.allow_external_password_cache = 0;
+
+ if (password)
+ /* There is a cached password. Try it. */
+ {
+ int len = strlen(password) + 1;
+ if (len > pinentry.pin_len) len = pinentry.pin_len;
+
+ memcpy(pinentry.pin, password, len);
+ pinentry.pin[len] = '\0';
+
+ secmem_free(password);
+
+ pinentry.pin_from_cache = 1;
+
+ assuan_write_status(ctx, "PASSWORD_FROM_CACHE", "");
+
+ /* Result is the length of the password not including the
+ NUL terminator. */
+ result = len - 1;
+
+ just_read_password_from_cache = 1;
+
+ goto out;
+ }
+ }
+
+ /* The password was not cached (or we are not allowed to / cannot
+ use the cache). Prompt the user. */
+ pinentry.pin_from_cache = 0;
+
+ if (!pinentry.prompt) {
+ pinentry.prompt = const_cast<char *>(
+ pinentry.default_prompt ? pinentry.default_prompt : "PIN:");
+ set_prompt = 1;
+ }
+ pinentry.locale_err = 0;
+ pinentry.specific_err = 0;
+ pinentry.specific_err_loc = NULL;
+ free(pinentry.specific_err_info);
+ pinentry.specific_err_info = NULL;
+ pinentry.close_button = 0;
+ pinentry.repeat_okay = 0;
+ pinentry.one_button = 0;
+ pinentry.ctx_assuan = ctx;
+ result = (*pinentry_cmd_handler)(&pinentry);
+ pinentry.ctx_assuan = NULL;
+ if (pinentry.error) {
+ free(pinentry.error);
+ pinentry.error = NULL;
+ }
+ if (pinentry.repeat_passphrase) {
+ free(pinentry.repeat_passphrase);
+ pinentry.repeat_passphrase = NULL;
+ }
+ if (set_prompt) pinentry.prompt = NULL;
+
+ pinentry.quality_bar = 0; /* Reset it after the command. */
+
+ if (pinentry.close_button) assuan_write_status(ctx, "BUTTON_INFO", "close");
+
+ if (result < 0) {
+ pinentry_setbuffer_clear(&pinentry);
+ if (pinentry.specific_err) {
+ write_status_error(ctx, &pinentry);
+
+ if (gpg_err_code(pinentry.specific_err) == GPG_ERR_FULLY_CANCELED)
+ assuan_set_flag(ctx, ASSUAN_FORCE_CLOSE, 1);
+
+ return pinentry.specific_err;
+ }
+ return (pinentry.locale_err ? gpg_error(GPG_ERR_LOCALE_PROBLEM)
+ : gpg_error(GPG_ERR_CANCELED));
+ }
+
+out:
+ if (result) {
+ if (pinentry.repeat_okay) assuan_write_status(ctx, "PIN_REPEATED", "");
+ assuan_begin_confidential(ctx);
+ result = assuan_send_data(ctx, pinentry.pin, strlen(pinentry.pin));
+ if (!result) result = assuan_send_data(ctx, NULL, 0);
+ assuan_end_confidential(ctx);
+
+ if (/* GPG Agent says it's okay. */
+ pinentry.allow_external_password_cache &&
+ pinentry.keyinfo
+ /* We didn't just read it from the cache. */
+ && !just_read_password_from_cache
+ /* And the user said it's okay. */
+ && pinentry.may_cache_password)
+ /* Cache the password. */
+ password_cache_save(pinentry.keyinfo, pinentry.pin);
+ }
+
+ pinentry_setbuffer_clear(&pinentry);
+
+ return result;
+}
+
+/* Note that the option --one-button is a hack to allow the use of old
+ pinentries while the caller is ignoring the result. Given that
+ options have never been used or flagged as an error the new option
+ is an easy way to enable the messsage mode while not requiring to
+ update pinentry or to have the caller test for the message
+ command. New applications which are free to require an updated
+ pinentry should use MESSAGE instead. */
+static gpg_error_t cmd_confirm(assuan_context_t ctx, char *line) {
+ int result;
+
+ pinentry.one_button = !!strstr(line, "--one-button");
+ pinentry.quality_bar = 0;
+ pinentry.close_button = 0;
+ pinentry.locale_err = 0;
+ pinentry.specific_err = 0;
+ pinentry.specific_err_loc = NULL;
+ free(pinentry.specific_err_info);
+ pinentry.specific_err_info = NULL;
+ pinentry.canceled = 0;
+ pinentry.confirm = 1;
+ pinentry_setbuffer_clear(&pinentry);
+ result = (*pinentry_cmd_handler)(&pinentry);
+ if (pinentry.error) {
+ free(pinentry.error);
+ pinentry.error = NULL;
+ }
+
+ if (pinentry.close_button) assuan_write_status(ctx, "BUTTON_INFO", "close");
+
+ if (result > 0) return 0; /* OK */
+
+ if (pinentry.specific_err) {
+ write_status_error(ctx, &pinentry);
+
+ if (gpg_err_code(pinentry.specific_err) == GPG_ERR_FULLY_CANCELED)
+ assuan_set_flag(ctx, ASSUAN_FORCE_CLOSE, 1);
+
+ return pinentry.specific_err;
+ }
+
+ if (pinentry.locale_err) return gpg_error(GPG_ERR_LOCALE_PROBLEM);
+
+ if (pinentry.one_button) return 0; /* OK */
+
+ if (pinentry.canceled) return gpg_error(GPG_ERR_CANCELED);
+ return gpg_error(GPG_ERR_NOT_CONFIRMED);
+}
+
+static gpg_error_t cmd_message(assuan_context_t ctx, char *line) {
+ (void)line;
+
+ return cmd_confirm(ctx, "--one-button");
+}
+
+/* Return a staically allocated string with information on the mode,
+ * uid, and gid of DEVICE. On error "?" is returned if DEVICE is
+ * NULL, "-" is returned. */
+static const char *device_stat_string(const char *device) {
+#ifdef HAVE_STAT
+ static char buf[40];
+ struct stat st;
+
+ if (!device || !*device) return "-";
+
+ if (stat(device, &st)) return "?"; /* Error */
+ snprintf(buf, sizeof buf, "%lo/%lu/%lu", (unsigned long)st.st_mode,
+ (unsigned long)st.st_uid, (unsigned long)st.st_gid);
+ return buf;
+#else
+ return "-";
+#endif
+}
+
+/* GETINFO <what>
+
+ Multipurpose function to return a variety of information.
+ Supported values for WHAT are:
+
+ version - Return the version of the program.
+ pid - Return the process id of the server.
+ flavor - Return information about the used pinentry flavor
+ ttyinfo - Return DISPLAY, ttyinfo and an emacs pinentry status
+ */
+static gpg_error_t cmd_getinfo(assuan_context_t ctx, char *line) {
+ int rc;
+ const char *s;
+ char buffer[150];
+
+ if (!strcmp(line, "version")) {
+ s = 0;
+ rc = assuan_send_data(ctx, s, strlen(s));
+ } else if (!strcmp(line, "pid")) {
+ snprintf(buffer, sizeof buffer, "%lu", (unsigned long)getpid());
+ rc = assuan_send_data(ctx, buffer, strlen(buffer));
+ } else if (!strcmp(line, "flavor")) {
+ if (!strncmp(this_pgmname, "pinentry-", 9) && this_pgmname[9])
+ s = this_pgmname + 9;
+ else
+ s = this_pgmname;
+
+ snprintf(buffer, sizeof buffer, "%s%s%s", s, flavor_flag ? ":" : "",
+ flavor_flag ? flavor_flag : "");
+ rc = assuan_send_data(ctx, buffer, strlen(buffer));
+ /* if (!rc) */
+ /* rc = assuan_write_status (ctx, "FEATURES", "tabbing foo bar"); */
+ } else if (!strcmp(line, "ttyinfo")) {
+ char emacs_status[10];
+#ifdef INSIDE_EMACS
+ snprintf(emacs_status, sizeof emacs_status, "%d", pinentry_emacs_status());
+#else
+ strcpy(emacs_status, "-");
+#endif
+ snprintf(buffer, sizeof buffer, "%s %s %s %s %lu/%lu %s",
+ pinentry.ttyname ? pinentry.ttyname : "-",
+ pinentry.ttytype_l ? pinentry.ttytype_l : "-",
+ pinentry.display ? pinentry.display : "-",
+ device_stat_string(pinentry.ttyname),
+#ifdef HAVE_DOSISH_SYSTEM
+ 0l, 0l,
+#else
+ (unsigned long)geteuid(), (unsigned long)getegid(),
+#endif
+ emacs_status);
+ rc = assuan_send_data(ctx, buffer, strlen(buffer));
+ } else
+ rc = gpg_error(GPG_ERR_ASS_PARAMETER);
+ return rc;
+}
+
+/* CLEARPASSPHRASE <cacheid>
+
+ Clear the cache passphrase associated with the key identified by
+ cacheid.
+ */
+static gpg_error_t cmd_clear_passphrase(assuan_context_t ctx, char *line) {
+ (void)ctx;
+
+ if (!line) return gpg_error(GPG_ERR_ASS_INV_VALUE);
+
+ /* Remove leading and trailing white space. */
+ while (*line == ' ') line++;
+ while (line[strlen(line) - 1] == ' ') line[strlen(line) - 1] = 0;
+
+ switch (password_cache_clear(line)) {
+ case 1:
+ return 0;
+ case 0:
+ return gpg_error(GPG_ERR_ASS_INV_VALUE);
+ default:
+ return gpg_error(GPG_ERR_ASS_GENERAL);
+ }
+}
+
+/* Tell the assuan library about our commands. */
+static gpg_error_t register_commands(assuan_context_t ctx) {
+ static struct {
+ const char *name;
+ gpg_error_t (*handler)(assuan_context_t, char *line);
+ } table[] = {{"SETDESC", cmd_setdesc},
+ {"SETPROMPT", cmd_setprompt},
+ {"SETKEYINFO", cmd_setkeyinfo},
+ {"SETREPEAT", cmd_setrepeat},
+ {"SETREPEATERROR", cmd_setrepeaterror},
+ {"SETREPEATOK", cmd_setrepeatok},
+ {"SETERROR", cmd_seterror},
+ {"SETOK", cmd_setok},
+ {"SETNOTOK", cmd_setnotok},
+ {"SETCANCEL", cmd_setcancel},
+ {"GETPIN", cmd_getpin},
+ {"CONFIRM", cmd_confirm},
+ {"MESSAGE", cmd_message},
+ {"SETQUALITYBAR", cmd_setqualitybar},
+ {"SETQUALITYBAR_TT", cmd_setqualitybar_tt},
+ {"SETGENPIN", cmd_setgenpin_label},
+ {"SETGENPIN_TT", cmd_setgenpin_tt},
+ {"GETINFO", cmd_getinfo},
+ {"SETTITLE", cmd_settitle},
+ {"SETTIMEOUT", cmd_settimeout},
+ {"CLEARPASSPHRASE", cmd_clear_passphrase},
+ {NULL}};
+ int i, j;
+ gpg_error_t rc;
+
+ for (i = j = 0; table[i].name; i++) {
+ rc = assuan_register_command(ctx, table[i].name, table[i].handler, NULL);
+ if (rc) return rc;
+ }
+ return 0;
+}
+
+int pinentry_loop2(int infd, int outfd) {
+ gpg_error_t rc;
+ assuan_fd_t filedes[2];
+ assuan_context_t ctx;
+
+ /* Extra check to make sure we have dropped privs. */
+#ifndef HAVE_DOSISH_SYSTEM
+ if (getuid() != geteuid()) abort();
+#endif
+
+ rc = assuan_new(&ctx);
+ if (rc) {
+ fprintf(stderr, "server context creation failed: %s\n", gpg_strerror(rc));
+ return -1;
+ }
+
+ /* For now we use a simple pipe based server so that we can work
+ from scripts. We will later add options to run as a daemon and
+ wait for requests on a Unix domain socket. */
+ filedes[0] = assuan_fdopen(infd);
+ filedes[1] = assuan_fdopen(outfd);
+ rc = assuan_init_pipe_server(ctx, filedes);
+ if (rc) {
+ fprintf(stderr, "%s: failed to initialize the server: %s\n", this_pgmname,
+ gpg_strerror(rc));
+ return -1;
+ }
+ rc = register_commands(ctx);
+ if (rc) {
+ fprintf(stderr, "%s: failed to the register commands with Assuan: %s\n",
+ this_pgmname, gpg_strerror(rc));
+ return -1;
+ }
+
+ assuan_register_option_handler(ctx, option_handler);
+#if 0
+ assuan_set_log_stream (ctx, stderr);
+#endif
+ assuan_register_reset_notify(ctx, pinentry_assuan_reset_handler);
+
+ for (;;) {
+ rc = assuan_accept(ctx);
+ if (rc == -1)
+ break;
+ else if (rc) {
+ fprintf(stderr, "%s: Assuan accept problem: %s\n", this_pgmname,
+ gpg_strerror(rc));
+ break;
+ }
+
+ rc = assuan_process(ctx);
+ if (rc) {
+ fprintf(stderr, "%s: Assuan processing failed: %s\n", this_pgmname,
+ gpg_strerror(rc));
+ continue;
+ }
+ }
+
+ assuan_release(ctx);
+ return 0;
+}
+
+/* Start the pinentry event loop. The program will start to process
+ Assuan commands until it is finished or an error occurs. If an
+ error occurs, -1 is returned. Otherwise, 0 is returned. */
+int pinentry_loop(void) { return pinentry_loop2(STDIN_FILENO, STDOUT_FILENO); }
diff --git a/src/pinentry/pinentry.h b/src/pinentry/pinentry.h
new file mode 100644
index 00000000..aec01946
--- /dev/null
+++ b/src/pinentry/pinentry.h
@@ -0,0 +1,370 @@
+/* pinentry.h - The interface for the PIN entry support library.
+ * Copyright (C) 2002, 2003, 2010, 2015, 2021 g10 Code GmbH
+ *
+ * This file is part of PINENTRY.
+ *
+ * PINENTRY 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * PINENTRY 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 this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef PINENTRY_H
+#define PINENTRY_H
+
+#include "secmem.h"
+
+#ifdef __cplusplus
+extern "C" {
+#if 0
+}
+#endif
+#endif
+
+typedef enum {
+ PINENTRY_COLOR_NONE,
+ PINENTRY_COLOR_DEFAULT,
+ PINENTRY_COLOR_BLACK,
+ PINENTRY_COLOR_RED,
+ PINENTRY_COLOR_GREEN,
+ PINENTRY_COLOR_YELLOW,
+ PINENTRY_COLOR_BLUE,
+ PINENTRY_COLOR_MAGENTA,
+ PINENTRY_COLOR_CYAN,
+ PINENTRY_COLOR_WHITE
+} pinentry_color_t;
+
+struct pinentry {
+ /* The window title, or NULL. (Assuan: "SETTITLE TITLE".) */
+ char *title;
+ /* The description to display, or NULL. (Assuan: "SETDESC
+ DESC".) */
+ char *description;
+ /* The error message to display, or NULL. (Assuan: "SETERROR
+ MESSAGE".) */
+ char *error;
+ /* The prompt to display, or NULL. (Assuan: "SETPROMPT
+ prompt".) */
+ char *prompt;
+ /* The OK button text to display, or NULL. (Assuan: "SETOK
+ OK".) */
+ char *ok;
+ /* The Not-OK button text to display, or NULL. This is the text for
+ the alternative option shown by the third button. (Assuan:
+ "SETNOTOK NOTOK".) */
+ char *notok;
+ /* The Cancel button text to display, or NULL. (Assuan: "SETCANCEL
+ CANCEL".) */
+ char *cancel;
+
+ /* The buffer to store the secret into. */
+ char *pin;
+ /* The length of the buffer. */
+ int pin_len;
+ /* Whether the pin was read from an external cache (1) or entered by
+ the user (0). */
+ int pin_from_cache;
+
+ /* The name of the X display to use if X is available and supported.
+ (Assuan: "OPTION display DISPLAY".) */
+ char *display;
+ /* The name of the terminal node to open if X not available or
+ supported. (Assuan: "OPTION ttyname TTYNAME".) */
+ char *ttyname;
+ /* The type of the terminal. (Assuan: "OPTION ttytype TTYTYPE".) */
+ char *ttytype_l;
+ /* Set the alert mode (none, beep or flash). */
+ char *ttyalert;
+ /* The LC_CTYPE value for the terminal. (Assuan: "OPTION lc-ctype
+ LC_CTYPE".) */
+ char *lc_ctype;
+ /* The LC_MESSAGES value for the terminal. (Assuan: "OPTION
+ lc-messages LC_MESSAGES".) */
+ char *lc_messages;
+
+ /* True if debug mode is requested. */
+ int debug;
+
+ /* The number of seconds before giving up while waiting for user input. */
+ int timeout;
+
+ /* True if caller should grab the keyboard. (Assuan: "OPTION grab"
+ or "OPTION no-grab".) */
+ int grab;
+
+ /* The PID of the owner or 0 if not known. The owner is the process
+ * which actually triggered the the pinentry. For example gpg. */
+ unsigned long owner_pid;
+
+ /* The numeric uid (user ID) of the owner process or -1 if not
+ * known. */
+ int owner_uid;
+
+ /* The malloced hostname of the owner or NULL. */
+ char *owner_host;
+
+ /* The window ID of the parent window over which the pinentry window
+ should be displayed. (Assuan: "OPTION parent-wid WID".) */
+ int parent_wid;
+
+ /* The name of an optional file which will be touched after a curses
+ entry has been displayed. (Assuan: "OPTION touch-file
+ FILENAME".) */
+ char *touch_file;
+
+ /* The frontend should set this to -1 if the user canceled the
+ request, and to the length of the PIN stored in pin
+ otherwise. */
+ int result;
+
+ /* The frontend should set this if the NOTOK button was pressed. */
+ int canceled;
+
+ /* The frontend should set this to true if an error with the local
+ conversion occurred. */
+ int locale_err;
+
+ /* The frontend should set this to a gpg-error so that commands are
+ able to return specific error codes. This is an ugly hack due to
+ the fact that pinentry_cmd_handler_t returns the length of the
+ passphrase or a negative error code. */
+ int specific_err;
+
+ /* The frontend may store a string with the error location here. */
+ const char *specific_err_loc;
+
+ /* The frontend may store a malloced string here to emit an ERROR
+ * status code with this extra info along with SPECIFIC_ERR. */
+ char *specific_err_info;
+
+ /* The frontend should set this to true if the window close button
+ has been used. This flag is used in addition to a regular return
+ value. */
+ int close_button;
+
+ /* The caller should set this to true if only one button is
+ required. This is useful for notification dialogs where only a
+ dismiss button is required. */
+ int one_button;
+
+ /* Whether this is a CONFIRM pinentry. */
+ int confirm;
+
+ /* If true a second prompt for the passphrase is shown and the user
+ is expected to enter the same passphrase again. Pinentry checks
+ that both match. (Assuan: "SETREPEAT".) */
+ char *repeat_passphrase;
+
+ /* The string to show if a repeated passphrase does not match.
+ (Assuan: "SETREPEATERROR ERROR".) */
+ char *repeat_error_string;
+
+ /* The string to show if a repeated passphrase does match.
+ (Assuan: "SETREPEATOK STRING".) */
+ char *repeat_ok_string;
+
+ /* Set to true if the passphrase has been entered a second time and
+ matches the first passphrase. */
+ int repeat_okay;
+
+ /* If this is not NULL, a passphrase quality indicator is shown.
+ There will also be an inquiry back to the caller to get an
+ indication of the quality for the passphrase entered so far. The
+ string is used as a label for the quality bar. (Assuan:
+ "SETQUALITYBAR LABEL".) */
+ char *quality_bar;
+
+ /* The tooltip to be shown for the qualitybar. Malloced or NULL.
+ (Assuan: "SETQUALITYBAR_TT TOOLTIP".) */
+ char *quality_bar_tt;
+
+ /* If this is not NULL, a generate action should be shown.
+ There will be an inquiry back to the caller to get such a
+ PIN. generate action. Malloced or NULL.
+ (Assuan: "SETGENPIN LABEL" .) */
+ char *genpin_label;
+
+ /* The tooltip to be shown for the generate action. Malloced or NULL.
+ (Assuan: "SETGENPIN_TT TOOLTIP".) */
+ char *genpin_tt;
+
+ /* Specifies whether passphrase formatting should be enabled.
+ (Assuan: "OPTION formatted-passphrase") */
+ int formatted_passphrase;
+
+ /* A hint to be shown near the passphrase input field if passphrase
+ formatting is enabled. Malloced or NULL.
+ (Assuan: "OPTION formatted-passphrase-hint=HINT".) */
+ char *formatted_passphrase_hint;
+
+ /* For the curses pinentry, the color of error messages. */
+ pinentry_color_t color_fg;
+ int color_fg_bright;
+ pinentry_color_t color_bg;
+ pinentry_color_t color_so;
+ int color_so_bright;
+ pinentry_color_t color_ok;
+ int color_ok_bright;
+ pinentry_color_t color_qualitybar;
+ int color_qualitybar_bright;
+
+ /* Malloced and i18ned default strings or NULL. These strings may
+ include an underscore character to indicate an accelerator key.
+ A double underscore represents a plain one. */
+ /* (Assuan: "OPTION default-ok OK"). */
+ char *default_ok;
+ /* (Assuan: "OPTION default-cancel CANCEL"). */
+ char *default_cancel;
+ /* (Assuan: "OPTION default-prompt PROMPT"). */
+ char *default_prompt;
+ /* (Assuan: "OPTION default-pwmngr
+ SAVE_PASSWORD_WITH_PASSWORD_MANAGER?"). */
+ char *default_pwmngr;
+ /* (Assuan: "OPTION default-cf-visi
+ Do you really want to make your passphrase visible?"). */
+ char *default_cf_visi;
+ /* (Assuan: "OPTION default-tt-visi
+ Make passphrase visible?"). */
+ char *default_tt_visi;
+ /* (Assuan: "OPTION default-tt-hide
+ Hide passphrase"). */
+ char *default_tt_hide;
+ /* (Assuan: "OPTION default-capshint
+ Caps Lock is on"). */
+ char *default_capshint;
+
+ /* Whether we are allowed to read the password from an external
+ cache. (Assuan: "OPTION allow-external-password-cache") */
+ int allow_external_password_cache;
+
+ /* We only try the cache once. */
+ int tried_password_cache;
+
+ /* A stable identifier for the key. (Assuan: "SETKEYINFO
+ KEYINFO".) */
+ char *keyinfo;
+
+ /* Whether we may cache the password (according to the user). */
+ int may_cache_password;
+
+ /* NOTE: If you add any additional fields to this structure, be sure
+ to update the initializer in pinentry/pinentry.c!!! */
+
+ /* For the quality indicator and genpin we need to do an inquiry.
+ Thus we need to save the assuan ctx. */
+ void *ctx_assuan;
+
+ /* An UTF-8 string with an invisible character used to override the
+ default in some pinentries. Only the first character is
+ used. */
+ char *invisible_char;
+
+ /* Whether the passphrase constraints are enforced by gpg-agent.
+ (Assuan: "OPTION constraints-enforce") */
+ int constraints_enforce;
+
+ /* A short translated hint for the user with the constraints for new
+ passphrases to be displayed near the passphrase input field.
+ Malloced or NULL.
+ (Assuan: "OPTION constraints-hint-short=At least 8 characters".) */
+ char *constraints_hint_short;
+
+ /* A longer translated hint for the user with the constraints for new
+ passphrases to be displayed for example as tooltip. Malloced or NULL.
+ (Assuan: "OPTION constraints-hint-long=The passphrase must ...".) */
+ char *constraints_hint_long;
+
+ /* A short translated title for an error dialog informing the user about
+ unsatisfied passphrase constraints. Malloced or NULL.
+ (Assuan: "OPTION constraints-error-title=Passphrase Not Allowed".) */
+ char *constraints_error_title;
+};
+typedef struct pinentry *pinentry_t;
+
+/* The pinentry command handler type processes the pinentry request
+ PIN. If PIN->pin is zero, request a confirmation, otherwise a PIN
+ entry. On confirmation, the function should return TRUE if
+ confirmed, and FALSE otherwise. On PIN entry, the function should
+ return -1 if an error occurred or the user cancelled the operation
+ and 1 otherwise. */
+typedef int (*pinentry_cmd_handler_t)(pinentry_t pin);
+
+/* Start the pinentry event loop. The program will start to process
+ Assuan commands until it is finished or an error occurs. If an
+ error occurs, -1 is returned and errno indicates the type of an
+ error. Otherwise, 0 is returned. */
+int pinentry_loop(void);
+
+/* The same as above but allows to specify the i/o descriptors.
+ * infd and outfd will be duplicated in this function so the caller
+ * still has to close them if necessary.
+ */
+int pinentry_loop2(int infd, int outfd);
+
+const char *pinentry_get_pgmname(void);
+
+char *pinentry_get_title(pinentry_t pe);
+
+/* Run a quality inquiry for PASSPHRASE of LENGTH. */
+int pinentry_inq_quality(pinentry_t pin, const char *passphrase, size_t length);
+
+/* Run a checkpin inquiry for PASSPHRASE of LENGTH. Returns NULL, if the
+ passphrase satisfies the constraints. Otherwise, returns a malloced error
+ string. */
+char *pinentry_inq_checkpin(pinentry_t pin, const char *passphrase,
+ size_t length);
+
+/* Run a genpin iquriry. Returns a malloced string or NULL */
+char *pinentry_inq_genpin(pinentry_t pin);
+
+/* Try to make room for at least LEN bytes for the pin in the pinentry
+ PIN. Returns new buffer on success and 0 on failure. */
+char *pinentry_setbufferlen(pinentry_t pin, int len);
+
+/* Use the buffer at BUFFER for PIN->PIN. BUFFER must be NULL or
+ allocated using secmem_alloc. LEN is the size of the buffer. If
+ it is unknown, but BUFFER is a NUL terminated string, you pass 0 to
+ just use strlen(buffer)+1. */
+void pinentry_setbuffer_use(pinentry_t pin, char *buffer, int len);
+
+/* Initialize the secure memory subsystem, drop privileges and
+ return. Must be called early. */
+void pinentry_init(const char *pgmname);
+
+/* Return true if either DISPLAY is set or ARGV contains the string
+ "--display". */
+int pinentry_have_display(int argc, char **argv);
+
+/* Parse the command line options. May exit the program if only help
+ or version output is requested. */
+void pinentry_parse_opts(int argc, char *argv[]);
+
+/* Set the optional flag used with getinfo. */
+void pinentry_set_flavor_flag(const char *string);
+
+/* The caller must define this variable to process assuan commands. */
+extern pinentry_cmd_handler_t pinentry_cmd_handler;
+
+#ifdef WINDOWS
+/* Windows declares sleep as obsolete, but provides a definition for
+ _sleep but non for the still existing sleep. */
+#define sleep(a) _sleep((a))
+#endif /*WINDOWS*/
+
+#if 0
+{
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PINENTRY_H */
diff --git a/src/pinentry/pinentry_debug.cpp b/src/pinentry/pinentry_debug.cpp
new file mode 100644
index 00000000..9afbcdb3
--- /dev/null
+++ b/src/pinentry/pinentry_debug.cpp
@@ -0,0 +1,31 @@
+/* pinentry_debug.h - Logging category for pinentry
+ * Copyright (C) 2021 g10 Code GmbH
+ *
+ * Software engineering by Ingo Klöcker <[email protected]>
+ *
+ * This program 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 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "pinentry_debug.h"
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
+Q_LOGGING_CATEGORY(PINENTRY_LOG, "gpg.pinentry", QtWarningMsg)
+#else
+Q_LOGGING_CATEGORY(PINENTRY_LOG, "gpg.pinentry")
+#endif
diff --git a/src/pinentry/pinentry_debug.h b/src/pinentry/pinentry_debug.h
new file mode 100644
index 00000000..fc8c808a
--- /dev/null
+++ b/src/pinentry/pinentry_debug.h
@@ -0,0 +1,28 @@
+/* pinentry_debug.h - Logging category for pinentry
+ * Copyright (C) 2021 g10 Code GmbH
+ *
+ * Software engineering by Ingo Klöcker <[email protected]>
+ *
+ * This program 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 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __PINENTRY_QT_DEBUG_H__
+#define __PINENTRY_QT_DEBUG_H__
+
+#include <QLoggingCategory>
+
+Q_DECLARE_LOGGING_CATEGORY(PINENTRY_LOG)
+
+#endif // __PINENTRY_QT_DEBUG_H__
diff --git a/src/pinentry/pinentry_main.cpp b/src/pinentry/pinentry_main.cpp
new file mode 100644
index 00000000..fcea7c31
--- /dev/null
+++ b/src/pinentry/pinentry_main.cpp
@@ -0,0 +1,413 @@
+/* main.cpp - A Qt dialog for PIN entry.
+ * Copyright (C) 2002, 2008 Klarälvdalens Datakonsult AB (KDAB)
+ * Copyright (C) 2003, 2021 g10 Code GmbH
+ * Copyright 2007 Ingo Klöcker
+ *
+ * Written by Steffen Hansen <[email protected]>.
+ * Modified by Marcus Brinkmann <[email protected]>.
+ * Modified by Marc Mutz <[email protected]>
+ * Software engineering by Ingo Klöcker <[email protected]>
+ *
+ * This program 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 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <QApplication>
+#include <QDebug>
+#include <QIcon>
+#include <QMessageBox>
+#include <QPushButton>
+#include <QString>
+#include <QWidget>
+
+#include "accessibility.h"
+#include "keyboardfocusindication.h"
+#include "pinentry.h"
+#include "pinentryconfirm.h"
+#include "pinentrydialog.h"
+#include "util.h"
+#if QT_VERSION >= 0x050000
+#include <QWindow>
+#endif
+
+#include <errno.h>
+#include <gpg-error.h>
+#include <stdio.h>
+
+#include <stdexcept>
+
+#ifdef FALLBACK_CURSES
+#include <pinentry-curses.h>
+#endif
+
+#if QT_VERSION >= 0x050000 && defined(QT_STATIC)
+#include <QtPlugin>
+#ifdef Q_OS_WIN
+#include <shlobj.h>
+#include <windows.h>
+Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin)
+#elif defined(Q_OS_MAC)
+Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin)
+#else
+Q_IMPORT_PLUGIN(QXcbIntegrationPlugin)
+#endif
+#endif
+
+#ifdef Q_OS_WIN
+#include <windows.h>
+#endif
+
+#include "pinentry_debug.h"
+
+static QString escape_accel(const QString &s) {
+ QString result;
+ result.reserve(s.size());
+
+ bool afterUnderscore = false;
+
+ for (unsigned int i = 0, end = s.size(); i != end; ++i) {
+ const QChar ch = s[i];
+ if (ch == QLatin1Char('_')) {
+ if (afterUnderscore) { // escaped _
+ result += QLatin1Char('_');
+ afterUnderscore = false;
+ } else { // accel
+ afterUnderscore = true;
+ }
+ } else {
+ if (afterUnderscore || // accel
+ ch == QLatin1Char('&')) { // escape & from being interpreted by Qt
+ result += QLatin1Char('&');
+ }
+ result += ch;
+ afterUnderscore = false;
+ }
+ }
+
+ if (afterUnderscore)
+ // trailing single underscore: shouldn't happen, but deal with it robustly:
+ {
+ result += QLatin1Char('_');
+ }
+
+ return result;
+}
+
+namespace {
+class InvalidUtf8 : public std::invalid_argument {
+ public:
+ InvalidUtf8() : std::invalid_argument("invalid utf8") {}
+ ~InvalidUtf8() throw() {}
+};
+} // namespace
+
+static const bool GPG_AGENT_IS_PORTED_TO_ONLY_SEND_UTF8 = false;
+
+static QString from_utf8(const char *s) {
+ const QString result = QString::fromUtf8(s);
+ if (result.contains(QChar::ReplacementCharacter)) {
+ if (GPG_AGENT_IS_PORTED_TO_ONLY_SEND_UTF8) {
+ throw InvalidUtf8();
+ } else {
+ return QString::fromLocal8Bit(s);
+ }
+ }
+
+ return result;
+}
+
+static void setup_foreground_window(QWidget *widget, WId parentWid) {
+#if QT_VERSION >= 0x050000
+ /* For windows set the desktop window as the transient parent */
+ QWindow *parentWindow = nullptr;
+ if (parentWid) {
+ parentWindow = QWindow::fromWinId(parentWid);
+ }
+#ifdef Q_OS_WIN
+ if (!parentWindow) {
+ HWND desktop = GetDesktopWindow();
+ if (desktop) {
+ parentWindow = QWindow::fromWinId((WId)desktop);
+ }
+ }
+#endif
+ if (parentWindow) {
+ // Ensure that we have a native wid
+ widget->winId();
+ QWindow *wndHandle = widget->windowHandle();
+
+ if (wndHandle) {
+ wndHandle->setTransientParent(parentWindow);
+ }
+ }
+#endif
+ widget->setWindowFlags(Qt::Window | Qt::CustomizeWindowHint |
+ Qt::WindowTitleHint | Qt::WindowCloseButtonHint |
+ Qt::WindowStaysOnTopHint |
+ Qt::WindowMinimizeButtonHint);
+}
+
+static int qt_cmd_handler(pinentry_t pe) {
+ int want_pass = !!pe->pin;
+
+ const QString ok = pe->ok ? escape_accel(from_utf8(pe->ok))
+ : pe->default_ok ? escape_accel(from_utf8(pe->default_ok))
+ :
+ /* else */ QLatin1String("&OK");
+ const QString cancel = pe->cancel ? escape_accel(from_utf8(pe->cancel))
+ : pe->default_cancel
+ ? escape_accel(from_utf8(pe->default_cancel))
+ :
+ /* else */ QLatin1String("&Cancel");
+
+ unique_malloced_ptr<char> str{pinentry_get_title(pe)};
+ const QString title = str ? from_utf8(str.get()) :
+ /* else */ QLatin1String("pinentry-qt");
+
+ const QString repeatError = pe->repeat_error_string
+ ? from_utf8(pe->repeat_error_string)
+ : QLatin1String("Passphrases do not match");
+ const QString repeatString =
+ pe->repeat_passphrase ? from_utf8(pe->repeat_passphrase) : QString();
+ const QString visibilityTT = pe->default_tt_visi
+ ? from_utf8(pe->default_tt_visi)
+ : QLatin1String("Show passphrase");
+ const QString hideTT = pe->default_tt_hide ? from_utf8(pe->default_tt_hide)
+ : QLatin1String("Hide passphrase");
+
+ const QString capsLockHint = pe->default_capshint
+ ? from_utf8(pe->default_capshint)
+ : QLatin1String("Caps Lock is on");
+
+ const QString generateLbl =
+ pe->genpin_label ? from_utf8(pe->genpin_label) : QString();
+ const QString generateTT =
+ pe->genpin_tt ? from_utf8(pe->genpin_tt) : QString();
+
+ if (want_pass) {
+ PinEntryDialog pinentry(nullptr, 0, pe->timeout, true, !!pe->quality_bar,
+ repeatString, visibilityTT, hideTT);
+ setup_foreground_window(&pinentry, pe->parent_wid);
+ pinentry.setPinentryInfo(pe);
+ pinentry.setPrompt(escape_accel(from_utf8(pe->prompt)));
+ pinentry.setDescription(from_utf8(pe->description));
+ pinentry.setRepeatErrorText(repeatError);
+ pinentry.setGenpinLabel(generateLbl);
+ pinentry.setGenpinTT(generateTT);
+ pinentry.setCapsLockHint(capsLockHint);
+ pinentry.setFormattedPassphrase({bool(pe->formatted_passphrase),
+ from_utf8(pe->formatted_passphrase_hint)});
+ pinentry.setConstraintsOptions({bool(pe->constraints_enforce),
+ from_utf8(pe->constraints_hint_short),
+ from_utf8(pe->constraints_hint_long),
+ from_utf8(pe->constraints_error_title)});
+
+ if (!title.isEmpty()) {
+ pinentry.setWindowTitle(title);
+ }
+
+ /* If we reuse the same dialog window. */
+ pinentry.setPin(QString());
+
+ pinentry.setOkText(ok);
+ pinentry.setCancelText(cancel);
+ if (pe->error) {
+ pinentry.setError(from_utf8(pe->error));
+ }
+ if (pe->quality_bar) {
+ pinentry.setQualityBar(from_utf8(pe->quality_bar));
+ }
+ if (pe->quality_bar_tt) {
+ pinentry.setQualityBarTT(from_utf8(pe->quality_bar_tt));
+ }
+ bool ret = pinentry.exec();
+ if (!ret) {
+ if (pinentry.timedOut()) pe->specific_err = gpg_error(GPG_ERR_TIMEOUT);
+ return -1;
+ }
+
+ const QString pinStr = pinentry.pin();
+ QByteArray pin = pinStr.toUtf8();
+
+ if (!!pe->repeat_passphrase) {
+ /* Should not have been possible to accept
+ the dialog in that case but we do a safety
+ check here */
+ pe->repeat_okay = (pinStr == pinentry.repeatedPin());
+ }
+
+ int len = strlen(pin.constData());
+ if (len >= 0) {
+ pinentry_setbufferlen(pe, len + 1);
+ if (pe->pin) {
+ strcpy(pe->pin, pin.constData());
+ return len;
+ }
+ }
+ return -1;
+ } else {
+ const QString desc =
+ pe->description ? from_utf8(pe->description) : QString();
+ const QString notok =
+ pe->notok ? escape_accel(from_utf8(pe->notok)) : QString();
+
+ const QMessageBox::StandardButtons buttons =
+ pe->one_button ? QMessageBox::Ok
+ : pe->notok ? QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel
+ :
+ /* else */ QMessageBox::Ok | QMessageBox::Cancel;
+
+ PinentryConfirm box{QMessageBox::Information, title, desc, buttons};
+ box.setTextFormat(Qt::PlainText);
+ box.setTextInteractionFlags(Qt::TextSelectableByMouse);
+ box.setTimeout(std::chrono::seconds{pe->timeout});
+ setup_foreground_window(&box, pe->parent_wid);
+
+ const struct {
+ QMessageBox::StandardButton button;
+ QString label;
+ } buttonLabels[] = {
+ {QMessageBox::Ok, ok},
+ {QMessageBox::Yes, ok},
+ {QMessageBox::No, notok},
+ {QMessageBox::Cancel, cancel},
+ };
+
+ for (size_t i = 0; i < sizeof buttonLabels / sizeof *buttonLabels; ++i)
+ if ((buttons & buttonLabels[i].button) &&
+ !buttonLabels[i].label.isEmpty()) {
+ box.button(buttonLabels[i].button)->setText(buttonLabels[i].label);
+ Accessibility::setDescription(box.button(buttonLabels[i].button),
+ buttonLabels[i].label);
+ }
+
+ box.setIconPixmap(applicationIconPixmap());
+
+ if (!pe->one_button) {
+ box.setDefaultButton(QMessageBox::Cancel);
+ }
+
+ box.show();
+ raiseWindow(&box);
+
+ const int rc = box.exec();
+
+ if (rc == QMessageBox::Cancel) {
+ pe->canceled = true;
+ }
+ if (box.timedOut()) {
+ pe->specific_err = gpg_error(GPG_ERR_TIMEOUT);
+ }
+
+ return rc == QMessageBox::Ok || rc == QMessageBox::Yes;
+ }
+}
+
+static int qt_cmd_handler_ex(pinentry_t pe) {
+ try {
+ return qt_cmd_handler(pe);
+ } catch (const InvalidUtf8 &) {
+ pe->locale_err = true;
+ return pe->pin ? -1 : false;
+ } catch (...) {
+ pe->canceled = true;
+ return pe->pin ? -1 : false;
+ }
+}
+
+pinentry_cmd_handler_t pinentry_cmd_handler = qt_cmd_handler_ex;
+
+int pinentry_main(int argc, char *argv[]) {
+ pinentry_init("pinentry-qt");
+
+ QApplication *app = NULL;
+ int new_argc = 0;
+
+#ifdef FALLBACK_CURSES
+#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
+ // check a few environment variables that are usually set on X11 or Wayland
+ // sessions
+ const bool hasWaylandDisplay = qEnvironmentVariableIsSet("WAYLAND_DISPLAY");
+ const bool isWaylandSessionType = qgetenv("XDG_SESSION_TYPE") == "wayland";
+ const bool hasX11Display = pinentry_have_display(argc, argv);
+ const bool isX11SessionType = qgetenv("XDG_SESSION_TYPE") == "x11";
+ const bool isGUISession = hasWaylandDisplay || isWaylandSessionType ||
+ hasX11Display || isX11SessionType;
+ qCDebug(PINENTRY_LOG) << "hasWaylandDisplay:" << hasWaylandDisplay;
+ qCDebug(PINENTRY_LOG) << "isWaylandSessionType:" << isWaylandSessionType;
+ qCDebug(PINENTRY_LOG) << "hasX11Display:" << hasX11Display;
+ qCDebug(PINENTRY_LOG) << "isX11SessionType:" << isX11SessionType;
+ qCDebug(PINENTRY_LOG) << "isGUISession:" << isGUISession;
+#else
+ const bool isGUISession = pinentry_have_display(argc, argv);
+#endif
+ if (!isGUISession) {
+ pinentry_cmd_handler = curses_cmd_handler;
+ pinentry_set_flavor_flag("curses");
+ } else
+#endif
+ {
+ /* Qt does only understand -display but not --display; thus we
+ are fixing that here. The code is pretty simply and may get
+ confused if an argument is called "--display". */
+ char **new_argv, *p;
+ size_t n;
+ int i, done;
+
+ for (n = 0, i = 0; i < argc; i++) {
+ n += strlen(argv[i]) + 1;
+ }
+ n++;
+ new_argv = (char **)calloc(argc + 1, sizeof *new_argv);
+ if (new_argv) {
+ *new_argv = (char *)malloc(n);
+ }
+ if (!new_argv || !*new_argv) {
+ fprintf(stderr, "pinentry-qt: can't fixup argument list: %s\n",
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ for (done = 0, p = *new_argv, i = 0; i < argc; i++)
+ if (!done && !strcmp(argv[i], "--display")) {
+ new_argv[i] = strcpy(p, argv[i] + 1);
+ p += strlen(argv[i] + 1) + 1;
+ done = 1;
+ } else {
+ new_argv[i] = strcpy(p, argv[i]);
+ p += strlen(argv[i]) + 1;
+ }
+
+ /* Note: QApplication uses int &argc so argc has to be valid
+ * for the full lifetime of the application.
+ *
+ * As Qt might modify argc / argv we use copies here so that
+ * we do not loose options that are handled in both. e.g. display.
+ */
+ new_argc = argc;
+ Q_ASSERT(new_argc);
+ app = new QApplication(new_argc, new_argv);
+ app->setWindowIcon(QIcon(QLatin1String(":/document-encrypt.png")));
+ (void)new KeyboardFocusIndication{app};
+ }
+
+ pinentry_parse_opts(argc, argv);
+
+ int rc = pinentry_loop();
+ delete app;
+ return rc ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/src/pinentry/pinentryconfirm.cpp b/src/pinentry/pinentryconfirm.cpp
new file mode 100644
index 00000000..31d55b5c
--- /dev/null
+++ b/src/pinentry/pinentryconfirm.cpp
@@ -0,0 +1,123 @@
+/* pinentryconfirm.cpp - A QMessageBox with a timeout
+ *
+ * Copyright (C) 2011 Ben Kibbey <[email protected]>
+ * Copyright (C) 2022 g10 Code GmbH
+ *
+ * Software engineering by Ingo Klöcker <[email protected]>
+ *
+ * This program 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 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include "pinentryconfirm.h"
+
+#include <QAbstractButton>
+#include <QApplication>
+#include <QFontMetrics>
+#include <QGridLayout>
+#include <QLabel>
+#include <QSpacerItem>
+
+#include "accessibility.h"
+#include "pinentrydialog.h"
+
+namespace {
+QLabel *messageBoxLabel(QMessageBox *messageBox) {
+ return messageBox->findChild<QLabel *>(QStringLiteral("qt_msgbox_label"));
+}
+} // namespace
+
+PinentryConfirm::PinentryConfirm(Icon icon, const QString &title,
+ const QString &text, StandardButtons buttons,
+ QWidget *parent, Qt::WindowFlags flags)
+ : QMessageBox{icon, title, text, buttons, parent, flags} {
+ _timer.callOnTimeout(this, &PinentryConfirm::slotTimeout);
+
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::installActivationObserver(this);
+ accessibilityActiveChanged(QAccessible::isActive());
+#endif
+
+#if QT_VERSION >= 0x050000
+ /* This is in line with PinentryDialog ctor to have a maximizing
+ * animation when opening. */
+ if (qApp->platformName() != QLatin1String("wayland")) {
+ setWindowState(Qt::WindowMinimized);
+ QTimer::singleShot(0, this, [this]() { raiseWindow(this); });
+ }
+#else
+ activateWindow();
+ raise();
+#endif
+}
+
+PinentryConfirm::~PinentryConfirm() {
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::removeActivationObserver(this);
+#endif
+}
+
+void PinentryConfirm::setTimeout(std::chrono::seconds timeout) {
+ _timer.setInterval(timeout);
+}
+
+std::chrono::seconds PinentryConfirm::timeout() const {
+ return std::chrono::duration_cast<std::chrono::seconds>(
+ _timer.intervalAsDuration());
+}
+
+bool PinentryConfirm::timedOut() const { return _timed_out; }
+
+void PinentryConfirm::showEvent(QShowEvent *event) {
+ static bool resized;
+ if (!resized) {
+ QGridLayout *lay = dynamic_cast<QGridLayout *>(layout());
+ if (lay) {
+ QSize textSize = fontMetrics().size(Qt::TextExpandTabs, text(),
+ fontMetrics().maxWidth());
+ QSpacerItem *horizontalSpacer =
+ new QSpacerItem(textSize.width() + iconPixmap().width(), 0,
+ QSizePolicy::Minimum, QSizePolicy::Expanding);
+ lay->addItem(horizontalSpacer, lay->rowCount(), 1, 1,
+ lay->columnCount() - 1);
+ }
+ resized = true;
+ }
+
+ QMessageBox::showEvent(event);
+
+ if (timeout() > std::chrono::milliseconds::zero()) {
+ _timer.setSingleShot(true);
+ _timer.start();
+ }
+}
+
+void PinentryConfirm::slotTimeout() {
+ QAbstractButton *b = button(QMessageBox::Cancel);
+ _timed_out = true;
+
+ if (b) {
+ b->animateClick();
+ }
+}
+
+#ifndef QT_NO_ACCESSIBILITY
+void PinentryConfirm::accessibilityActiveChanged(bool active) {
+ // Allow text label to get focus if accessibility is active
+ const auto focusPolicy = active ? Qt::StrongFocus : Qt::ClickFocus;
+ if (auto label = messageBoxLabel(this)) {
+ label->setFocusPolicy(focusPolicy);
+ }
+}
+#endif
diff --git a/src/pinentry/pinentryconfirm.h b/src/pinentry/pinentryconfirm.h
new file mode 100644
index 00000000..7be7c268
--- /dev/null
+++ b/src/pinentry/pinentryconfirm.h
@@ -0,0 +1,63 @@
+/* pinentryconfirm.h - A QMessageBox with a timeout
+ *
+ * Copyright (C) 2011 Ben Kibbey <[email protected]>
+ * Copyright (C) 2022 g10 Code GmbH
+ *
+ * Software engineering by Ingo Klöcker <[email protected]>
+ *
+ * This program 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 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef PINENTRYCONFIRM_H
+#define PINENTRYCONFIRM_H
+
+#include <QAccessible>
+#include <QMessageBox>
+#include <QTimer>
+
+class PinentryConfirm : public QMessageBox
+#ifndef QT_NO_ACCESSIBILITY
+ , public QAccessible::ActivationObserver
+#endif
+{
+ Q_OBJECT
+public:
+ PinentryConfirm(Icon icon, const QString &title, const QString &text,
+ StandardButtons buttons = NoButton, QWidget *parent = nullptr,
+ Qt::WindowFlags flags = Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint);
+ ~PinentryConfirm() override;
+
+ void setTimeout(std::chrono::seconds timeout);
+ std::chrono::seconds timeout() const;
+
+ bool timedOut() const;
+
+protected:
+ void showEvent(QShowEvent *event) override;
+
+private Q_SLOTS:
+ void slotTimeout();
+
+private:
+#ifndef QT_NO_ACCESSIBILITY
+ void accessibilityActiveChanged(bool active) override;
+#endif
+
+private:
+ QTimer _timer;
+ bool _timed_out = false;
+};
+
+#endif
diff --git a/src/pinentry/pinentrydialog.cpp b/src/pinentry/pinentrydialog.cpp
new file mode 100644
index 00000000..f0fba73c
--- /dev/null
+++ b/src/pinentry/pinentrydialog.cpp
@@ -0,0 +1,718 @@
+/* pinentrydialog.cpp - A (not yet) secure Qt 4 dialog for PIN entry.
+ * Copyright (C) 2002, 2008 Klarälvdalens Datakonsult AB (KDAB)
+ * Copyright 2007 Ingo Klöcker
+ * Copyright 2016 Intevation GmbH
+ * Copyright (C) 2021, 2022 g10 Code GmbH
+ *
+ * Written by Steffen Hansen <[email protected]>.
+ * Modified by Andre Heinecke <[email protected]>
+ * Software engineering by Ingo Klöcker <[email protected]>
+ *
+ * This program 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 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <qnamespace.h>
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <QAccessible>
+#include <QAction>
+#include <QApplication>
+#include <QCheckBox>
+#include <QDebug>
+#include <QDialogButtonBox>
+#include <QFontMetrics>
+#include <QGridLayout>
+#include <QHBoxLayout>
+#include <QKeyEvent>
+#include <QLabel>
+#include <QLineEdit>
+#include <QMessageBox>
+#include <QPainter>
+#include <QPalette>
+#include <QProgressBar>
+#include <QPushButton>
+#include <QRegularExpression>
+#include <QStyle>
+#include <QVBoxLayout>
+
+#include "accessibility.h"
+#include "capslock/capslock.h"
+#include "pinentrydialog.h"
+#include "pinlineedit.h"
+#include "util.h"
+
+#ifdef Q_OS_WIN
+#include <windows.h>
+#if QT_VERSION >= 0x050700
+#include <QtPlatformHeaders/QWindowsWindowFunctions>
+#endif
+#endif
+
+void raiseWindow(QWidget *w) {
+#ifdef Q_OS_WIN
+#if QT_VERSION >= 0x050700
+ QWindowsWindowFunctions::setWindowActivationBehavior(
+ QWindowsWindowFunctions::AlwaysActivateWindow);
+#endif
+#endif
+ w->setWindowState((w->windowState() & ~Qt::WindowMinimized) |
+ Qt::WindowActive);
+ w->activateWindow();
+ w->raise();
+}
+
+QPixmap applicationIconPixmap(const QIcon &overlayIcon) {
+ QPixmap pm = qApp->windowIcon().pixmap(48, 48);
+
+ if (!overlayIcon.isNull()) {
+ QPainter painter(&pm);
+ const int emblemSize = 22;
+ painter.drawPixmap(pm.width() - emblemSize, 0,
+ overlayIcon.pixmap(emblemSize, emblemSize));
+ }
+
+ return pm;
+}
+
+void PinEntryDialog::slotTimeout() {
+ _timed_out = true;
+ reject();
+}
+
+PinEntryDialog::PinEntryDialog(QWidget *parent, const char *name, int timeout,
+ bool modal, bool enable_quality_bar,
+ const QString &repeatString,
+ const QString &visibilityTT,
+ const QString &hideTT)
+ : QDialog{parent},
+ _have_quality_bar{enable_quality_bar},
+ mVisibilityTT{visibilityTT},
+ mHideTT{hideTT} {
+ Q_UNUSED(name)
+
+ if (modal) {
+ setModal(true);
+ }
+
+ QPalette redTextPalette;
+ redTextPalette.setColor(QPalette::WindowText, Qt::red);
+
+ auto *const mainLayout = new QVBoxLayout{this};
+
+ auto *const hbox = new QHBoxLayout;
+
+ _icon = new QLabel(this);
+ _icon->setPixmap(applicationIconPixmap());
+ hbox->addWidget(_icon, 0, Qt::AlignVCenter | Qt::AlignLeft);
+
+ auto *const grid = new QGridLayout;
+ int row = 1;
+
+ _error = new QLabel{this};
+ _error->setTextFormat(Qt::PlainText);
+ _error->setTextInteractionFlags(Qt::TextSelectableByMouse);
+ _error->setPalette(redTextPalette);
+ _error->hide();
+ grid->addWidget(_error, row, 1, 1, 2);
+
+ row++;
+ _desc = new QLabel{this};
+ _desc->setTextFormat(Qt::PlainText);
+ _desc->setTextInteractionFlags(Qt::TextSelectableByMouse);
+ _desc->hide();
+ grid->addWidget(_desc, row, 1, 1, 2);
+
+ row++;
+ mCapsLockHint = new QLabel{this};
+ mCapsLockHint->setTextFormat(Qt::PlainText);
+ mCapsLockHint->setTextInteractionFlags(Qt::TextSelectableByMouse);
+ mCapsLockHint->setPalette(redTextPalette);
+ mCapsLockHint->setAlignment(Qt::AlignCenter);
+ mCapsLockHint->setVisible(false);
+ grid->addWidget(mCapsLockHint, row, 1, 1, 2);
+
+ row++;
+ {
+ _prompt = new QLabel(this);
+ _prompt->setTextFormat(Qt::PlainText);
+ _prompt->setTextInteractionFlags(Qt::TextSelectableByMouse);
+ _prompt->hide();
+ grid->addWidget(_prompt, row, 1);
+
+ const auto l = new QHBoxLayout;
+ _edit = new PinLineEdit(this);
+ _edit->setMaxLength(256);
+ _edit->setMinimumWidth(_edit->fontMetrics().averageCharWidth() * 20 + 48);
+ _edit->setEchoMode(QLineEdit::Password);
+ _prompt->setBuddy(_edit);
+ l->addWidget(_edit, 1);
+
+ if (!repeatString.isNull()) {
+ mGenerateButton = new QPushButton{this};
+ mGenerateButton->setIcon(QIcon(QLatin1String(":/password-generate.svg")));
+ mGenerateButton->setVisible(false);
+ l->addWidget(mGenerateButton);
+ }
+ grid->addLayout(l, row, 2);
+ }
+
+ /* Set up the show password action */
+ const QIcon visibilityIcon = QIcon(QLatin1String(":/visibility.svg"));
+ const QIcon hideIcon = QIcon(QLatin1String(":/hint.svg"));
+#if QT_VERSION >= 0x050200
+ if (!visibilityIcon.isNull() && !hideIcon.isNull()) {
+ mVisiActionEdit =
+ _edit->addAction(visibilityIcon, QLineEdit::TrailingPosition);
+ mVisiActionEdit->setVisible(false);
+ mVisiActionEdit->setToolTip(mVisibilityTT);
+ } else
+#endif
+ {
+ if (!mVisibilityTT.isNull()) {
+ row++;
+ mVisiCB = new QCheckBox{mVisibilityTT, this};
+ grid->addWidget(mVisiCB, row, 1, 1, 2, Qt::AlignLeft);
+ }
+ }
+
+ row++;
+ mConstraintsHint = new QLabel{this};
+ mConstraintsHint->setTextFormat(Qt::PlainText);
+ mConstraintsHint->setTextInteractionFlags(Qt::TextSelectableByMouse);
+ mConstraintsHint->setVisible(false);
+ grid->addWidget(mConstraintsHint, row, 2);
+
+ row++;
+ mFormattedPassphraseHintSpacer = new QLabel{this};
+ mFormattedPassphraseHintSpacer->setVisible(false);
+ mFormattedPassphraseHint = new QLabel{this};
+ mFormattedPassphraseHint->setTextFormat(Qt::PlainText);
+ mFormattedPassphraseHint->setTextInteractionFlags(Qt::TextSelectableByMouse);
+ mFormattedPassphraseHint->setVisible(false);
+ grid->addWidget(mFormattedPassphraseHintSpacer, row, 1);
+ grid->addWidget(mFormattedPassphraseHint, row, 2);
+
+ if (!repeatString.isNull()) {
+ row++;
+ auto repeatLabel = new QLabel{this};
+ repeatLabel->setTextFormat(Qt::PlainText);
+ repeatLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
+ repeatLabel->setText(repeatString);
+ grid->addWidget(repeatLabel, row, 1);
+
+ mRepeat = new PinLineEdit(this);
+ mRepeat->setMaxLength(256);
+ mRepeat->setEchoMode(QLineEdit::Password);
+ repeatLabel->setBuddy(mRepeat);
+ grid->addWidget(mRepeat, row, 2);
+
+ row++;
+ mRepeatError = new QLabel{this};
+ mRepeatError->setTextFormat(Qt::PlainText);
+ mRepeatError->setTextInteractionFlags(Qt::TextSelectableByMouse);
+ mRepeatError->setPalette(redTextPalette);
+ mRepeatError->hide();
+ grid->addWidget(mRepeatError, row, 2);
+ }
+
+ if (enable_quality_bar) {
+ row++;
+ _quality_bar_label = new QLabel(this);
+ _quality_bar_label->setTextFormat(Qt::PlainText);
+ _quality_bar_label->setTextInteractionFlags(Qt::TextSelectableByMouse);
+ _quality_bar_label->setAlignment(Qt::AlignVCenter);
+ grid->addWidget(_quality_bar_label, row, 1);
+
+ _quality_bar = new QProgressBar(this);
+ _quality_bar->setAlignment(Qt::AlignCenter);
+ _quality_bar_label->setBuddy(_quality_bar);
+ grid->addWidget(_quality_bar, row, 2);
+ }
+
+ hbox->addLayout(grid, 1);
+ mainLayout->addLayout(hbox);
+
+ QDialogButtonBox *const buttons = new QDialogButtonBox(this);
+ buttons->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+ _ok = buttons->button(QDialogButtonBox::Ok);
+ _cancel = buttons->button(QDialogButtonBox::Cancel);
+
+ if (style()->styleHint(QStyle::SH_DialogButtonBox_ButtonsHaveIcons)) {
+ _ok->setIcon(style()->standardIcon(QStyle::SP_DialogOkButton));
+ _cancel->setIcon(style()->standardIcon(QStyle::SP_DialogCancelButton));
+ }
+
+ mainLayout->addStretch(1);
+ mainLayout->addWidget(buttons);
+ mainLayout->setSizeConstraint(QLayout::SetFixedSize);
+
+ if (timeout > 0) {
+ _timer = new QTimer(this);
+ connect(_timer, &QTimer::timeout, this, &PinEntryDialog::slotTimeout);
+ _timer->start(timeout * 1000);
+ }
+
+ connect(buttons, &QDialogButtonBox::accepted, this,
+ &PinEntryDialog::onAccept);
+ connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
+ connect(_edit, &QLineEdit::textChanged, this, &PinEntryDialog::updateQuality);
+ connect(_edit, &QLineEdit::textChanged, this, &PinEntryDialog::textChanged);
+ connect(_edit, &PinLineEdit::backspacePressed, this,
+ &PinEntryDialog::onBackspace);
+ if (mGenerateButton) {
+ connect(mGenerateButton, &QPushButton::clicked, this,
+ &PinEntryDialog::generatePin);
+ }
+ if (mVisiActionEdit) {
+ connect(mVisiActionEdit, &QAction::triggered, this,
+ &PinEntryDialog::toggleVisibility);
+ }
+ if (mVisiCB) {
+ connect(mVisiCB, &QCheckBox::toggled, this,
+ &PinEntryDialog::toggleVisibility);
+ }
+ if (mRepeat) {
+ connect(mRepeat, &QLineEdit::textChanged, this,
+ &PinEntryDialog::textChanged);
+ }
+
+ auto capsLockWatcher = new CapsLockWatcher{this};
+ connect(capsLockWatcher, &CapsLockWatcher::stateChanged, this,
+ [this](bool locked) { mCapsLockHint->setVisible(locked); });
+
+ connect(qApp, &QApplication::focusChanged, this,
+ &PinEntryDialog::focusChanged);
+ connect(qApp, &QApplication::applicationStateChanged, this,
+ &PinEntryDialog::checkCapsLock);
+ checkCapsLock();
+
+ setAttribute(Qt::WA_DeleteOnClose);
+
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::installActivationObserver(this);
+ accessibilityActiveChanged(QAccessible::isActive());
+#endif
+
+#if QT_VERSION >= 0x050000
+ /* This is mostly an issue on Windows where this results
+ in the pinentry popping up nicely with an animation and
+ comes to front. It is not ifdefed for Windows only since
+ window managers on Linux like KWin can also have this
+ result in an animation when the pinentry is shown and
+ not just popping it up.
+ */
+ if (qApp->platformName() != QLatin1String("wayland")) {
+ setWindowState(Qt::WindowMinimized);
+ QTimer::singleShot(0, this, [this]() { raiseWindow(this); });
+ }
+#else
+ activateWindow();
+ raise();
+#endif
+}
+
+PinEntryDialog::~PinEntryDialog() {
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::removeActivationObserver(this);
+#endif
+}
+
+void PinEntryDialog::keyPressEvent(QKeyEvent *e) {
+ const auto returnPressed =
+ (!e->modifiers() &&
+ (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return)) ||
+ (e->modifiers() & Qt::KeypadModifier && e->key() == Qt::Key_Enter);
+ if (returnPressed && _edit->hasFocus() && mRepeat) {
+ // if the user pressed Return in the first input field, then move the
+ // focus to the repeat input field and prevent further event processing
+ // by QDialog (which would trigger the default button)
+ mRepeat->setFocus();
+ e->ignore();
+ return;
+ }
+
+ QDialog::keyPressEvent(e);
+}
+
+void PinEntryDialog::keyReleaseEvent(QKeyEvent *event) {
+ QDialog::keyReleaseEvent(event);
+ checkCapsLock();
+}
+
+void PinEntryDialog::showEvent(QShowEvent *event) {
+ QDialog::showEvent(event);
+ _edit->setFocus();
+}
+
+void PinEntryDialog::setDescription(const QString &txt) {
+ _desc->setVisible(!txt.isEmpty());
+ _desc->setText(txt);
+ _icon->setPixmap(applicationIconPixmap());
+ setError(QString());
+}
+
+QString PinEntryDialog::description() const { return _desc->text(); }
+
+void PinEntryDialog::setError(const QString &txt) {
+ if (!txt.isNull()) {
+ _icon->setPixmap(
+ applicationIconPixmap(QIcon{QStringLiteral(":/data-error.svg")}));
+ }
+ _error->setText(txt);
+ _error->setVisible(!txt.isEmpty());
+}
+
+QString PinEntryDialog::error() const { return _error->text(); }
+
+void PinEntryDialog::setPin(const QString &txt) { _edit->setPin(txt); }
+
+QString PinEntryDialog::pin() const { return _edit->pin(); }
+
+void PinEntryDialog::setPrompt(const QString &txt) {
+ _prompt->setText(txt);
+ _prompt->setVisible(!txt.isEmpty());
+ if (txt.contains("PIN")) _disable_echo_allowed = false;
+}
+
+QString PinEntryDialog::prompt() const { return _prompt->text(); }
+
+void PinEntryDialog::setOkText(const QString &txt) {
+ _ok->setText(txt);
+ _ok->setVisible(!txt.isEmpty());
+}
+
+void PinEntryDialog::setCancelText(const QString &txt) {
+ _cancel->setText(txt);
+ _cancel->setVisible(!txt.isEmpty());
+}
+
+void PinEntryDialog::setQualityBar(const QString &txt) {
+ if (_have_quality_bar) {
+ _quality_bar_label->setText(txt);
+ }
+}
+
+void PinEntryDialog::setQualityBarTT(const QString &txt) {
+ if (_have_quality_bar) {
+ _quality_bar->setToolTip(txt);
+ }
+}
+
+void PinEntryDialog::setGenpinLabel(const QString &txt) {
+ if (!mGenerateButton) {
+ return;
+ }
+ mGenerateButton->setVisible(!txt.isEmpty());
+ if (!txt.isEmpty()) {
+ Accessibility::setName(mGenerateButton, txt);
+ }
+}
+
+void PinEntryDialog::setGenpinTT(const QString &txt) {
+ if (mGenerateButton) {
+ mGenerateButton->setToolTip(txt);
+ }
+}
+
+void PinEntryDialog::setCapsLockHint(const QString &txt) {
+ mCapsLockHint->setText(txt);
+}
+
+void PinEntryDialog::setFormattedPassphrase(
+ const PinEntryDialog::FormattedPassphraseOptions &options) {
+ mFormatPassphrase = options.formatPassphrase;
+ mFormattedPassphraseHint->setTextFormat(Qt::RichText);
+ mFormattedPassphraseHint->setText(QLatin1String("<html>") +
+ options.hint.toHtmlEscaped() +
+ QLatin1String("</html>"));
+ Accessibility::setName(mFormattedPassphraseHint, options.hint);
+ // toggleFormattedPassphrase();
+}
+
+void PinEntryDialog::setConstraintsOptions(const ConstraintsOptions &options) {
+ mEnforceConstraints = options.enforce;
+ mConstraintsHint->setText(options.shortHint);
+ if (!options.longHint.isEmpty()) {
+ mConstraintsHint->setToolTip(
+ QLatin1String("<html>") +
+ options.longHint.toHtmlEscaped().replace(QLatin1String("\n\n"),
+ QLatin1String("<br>")) +
+ QLatin1String("</html>"));
+ Accessibility::setDescription(mConstraintsHint, options.longHint);
+ }
+ mConstraintsErrorTitle = options.errorTitle;
+
+ mConstraintsHint->setVisible(mEnforceConstraints &&
+ !options.shortHint.isEmpty());
+}
+
+void PinEntryDialog::toggleFormattedPassphrase() {
+ const bool enableFormatting =
+ mFormatPassphrase && _edit->echoMode() == QLineEdit::Normal;
+ _edit->setFormattedPassphrase(enableFormatting);
+ if (mRepeat) {
+ mRepeat->setFormattedPassphrase(enableFormatting);
+ const bool hintAboutToBeHidden =
+ mFormattedPassphraseHint->isVisible() && !enableFormatting;
+ if (hintAboutToBeHidden) {
+ // set hint spacer to current height of hint label before hiding the hint
+ mFormattedPassphraseHintSpacer->setMinimumHeight(
+ mFormattedPassphraseHint->height());
+ mFormattedPassphraseHintSpacer->setVisible(true);
+ } else if (enableFormatting) {
+ mFormattedPassphraseHintSpacer->setVisible(false);
+ }
+ mFormattedPassphraseHint->setVisible(enableFormatting);
+ }
+}
+
+void PinEntryDialog::onBackspace() {
+ cancelTimeout();
+
+ if (_disable_echo_allowed) {
+ _edit->setEchoMode(QLineEdit::NoEcho);
+ if (mRepeat) {
+ mRepeat->setEchoMode(QLineEdit::NoEcho);
+ }
+ }
+}
+
+void PinEntryDialog::updateQuality(const QString &txt) {
+ int length;
+ int percent;
+ QPalette pal;
+
+ _disable_echo_allowed = false;
+
+ if (!_have_quality_bar || !_pinentry_info) {
+ return;
+ }
+ const QByteArray utf8_pin = txt.toUtf8();
+ const char *pin = utf8_pin.constData();
+ length = strlen(pin);
+ percent = length ? pinentry_inq_quality(_pinentry_info, pin, length) : 0;
+ if (!length) {
+ _quality_bar->reset();
+ } else {
+ pal = _quality_bar->palette();
+ if (percent < 0) {
+ pal.setColor(QPalette::Highlight, QColor("red"));
+ percent = -percent;
+ } else {
+ pal.setColor(QPalette::Highlight, QColor("green"));
+ }
+ _quality_bar->setPalette(pal);
+ _quality_bar->setValue(percent);
+ }
+}
+
+void PinEntryDialog::setPinentryInfo(pinentry_t peinfo) {
+ _pinentry_info = peinfo;
+}
+
+void PinEntryDialog::focusChanged(QWidget *old, QWidget *now) {
+ // Grab keyboard. It might be a little weird to do it here, but it works!
+ // Previously this code was in showEvent, but that did not work in Qt4.
+ if (!_pinentry_info || _pinentry_info->grab) {
+ if (_grabbed && old && (old == _edit || old == mRepeat)) {
+ old->releaseKeyboard();
+ _grabbed = false;
+ }
+ if (!_grabbed && now && (now == _edit || now == mRepeat)) {
+ now->grabKeyboard();
+ _grabbed = true;
+ }
+ }
+}
+
+void PinEntryDialog::textChanged(const QString &text) {
+ Q_UNUSED(text);
+
+ cancelTimeout();
+
+ if (mVisiActionEdit && sender() == _edit) {
+ mVisiActionEdit->setVisible(!_edit->pin().isEmpty());
+ }
+ if (mGenerateButton) {
+ mGenerateButton->setVisible(_edit->pin().isEmpty()
+#ifndef QT_NO_ACCESSIBILITY
+ && !mGenerateButton->accessibleName().isEmpty()
+#endif
+ );
+ }
+}
+
+void PinEntryDialog::generatePin() {
+ unique_malloced_ptr<char> pin{pinentry_inq_genpin(_pinentry_info)};
+ if (pin) {
+ if (_edit->echoMode() == QLineEdit::Password) {
+ if (mVisiActionEdit) {
+ mVisiActionEdit->trigger();
+ }
+ if (mVisiCB) {
+ mVisiCB->setChecked(true);
+ }
+ }
+ const auto pinStr = QString::fromUtf8(pin.get());
+ _edit->setPin(pinStr);
+ mRepeat->setPin(pinStr);
+ // explicitly focus the first input field and select the generated password
+ _edit->setFocus();
+ _edit->selectAll();
+ }
+}
+
+void PinEntryDialog::toggleVisibility() {
+ if (sender() != mVisiCB) {
+ if (_edit->echoMode() == QLineEdit::Password) {
+ if (mVisiActionEdit) {
+ mVisiActionEdit->setIcon(QIcon(QLatin1String(":/hint.svg")));
+ mVisiActionEdit->setToolTip(mHideTT);
+ }
+ _edit->setEchoMode(QLineEdit::Normal);
+ if (mRepeat) {
+ mRepeat->setEchoMode(QLineEdit::Normal);
+ }
+ } else {
+ if (mVisiActionEdit) {
+ mVisiActionEdit->setIcon(QIcon(QLatin1String(":/visibility.svg")));
+ mVisiActionEdit->setToolTip(mVisibilityTT);
+ }
+ _edit->setEchoMode(QLineEdit::Password);
+ if (mRepeat) {
+ mRepeat->setEchoMode(QLineEdit::Password);
+ }
+ }
+ } else {
+ if (mVisiCB->isChecked()) {
+ if (mRepeat) {
+ mRepeat->setEchoMode(QLineEdit::Normal);
+ }
+ _edit->setEchoMode(QLineEdit::Normal);
+ } else {
+ if (mRepeat) {
+ mRepeat->setEchoMode(QLineEdit::Password);
+ }
+ _edit->setEchoMode(QLineEdit::Password);
+ }
+ }
+ toggleFormattedPassphrase();
+}
+
+QString PinEntryDialog::repeatedPin() const {
+ if (mRepeat) {
+ return mRepeat->pin();
+ }
+ return QString();
+}
+
+bool PinEntryDialog::timedOut() const { return _timed_out; }
+
+void PinEntryDialog::setRepeatErrorText(const QString &err) {
+ if (mRepeatError) {
+ mRepeatError->setText(err);
+ }
+}
+
+void PinEntryDialog::cancelTimeout() {
+ if (_timer) {
+ _timer->stop();
+ }
+}
+
+void PinEntryDialog::checkCapsLock() {
+ const auto state = capsLockState();
+ if (state != LockState::Unknown) {
+ mCapsLockHint->setVisible(state == LockState::On);
+ }
+}
+
+void PinEntryDialog::onAccept() {
+ cancelTimeout();
+
+ if (mRepeat && mRepeat->pin() != _edit->pin()) {
+#ifndef QT_NO_ACCESSIBILITY
+ if (QAccessible::isActive()) {
+ QMessageBox::information(this, mRepeatError->text(),
+ mRepeatError->text());
+ } else
+#endif
+ {
+ mRepeatError->setVisible(true);
+ }
+ return;
+ }
+
+ const auto result = checkConstraints();
+ if (result != PassphraseNotOk) {
+ accept();
+ }
+}
+
+#ifndef QT_NO_ACCESSIBILITY
+void PinEntryDialog::accessibilityActiveChanged(bool active) {
+ // Allow text labels to get focus if accessibility is active
+ const auto focusPolicy = active ? Qt::StrongFocus : Qt::ClickFocus;
+ _error->setFocusPolicy(focusPolicy);
+ _desc->setFocusPolicy(focusPolicy);
+ mCapsLockHint->setFocusPolicy(focusPolicy);
+ mConstraintsHint->setFocusPolicy(focusPolicy);
+ mFormattedPassphraseHint->setFocusPolicy(focusPolicy);
+ if (mRepeatError) {
+ mRepeatError->setFocusPolicy(focusPolicy);
+ }
+}
+#endif
+
+PinEntryDialog::PassphraseCheckResult PinEntryDialog::checkConstraints() {
+ if (!mEnforceConstraints) {
+ return PassphraseNotChecked;
+ }
+
+ const auto passphrase = _edit->pin().toUtf8();
+ unique_malloced_ptr<char> error{pinentry_inq_checkpin(
+ _pinentry_info, passphrase.constData(), passphrase.size())};
+
+ if (!error) {
+ return PassphraseOk;
+ }
+
+ const auto messageLines =
+ QString::fromUtf8(QByteArray::fromPercentEncoding(error.get()))
+ .split(QChar{'\n'});
+ if (messageLines.isEmpty()) {
+ // shouldn't happen because pinentry_inq_checkpin() either returns NULL or a
+ // non-empty string
+ return PassphraseOk;
+ }
+ const auto firstLine = messageLines.first();
+ const auto indexOfFirstNonEmptyAdditionalLine =
+ messageLines.indexOf(QRegularExpression{QStringLiteral(".*\\S.*")}, 1);
+ const auto additionalLines =
+ indexOfFirstNonEmptyAdditionalLine > 0
+ ? messageLines.mid(indexOfFirstNonEmptyAdditionalLine)
+ .join(QChar{'\n'})
+ : QString{};
+ QMessageBox messageBox{this};
+ messageBox.setIcon(QMessageBox::Information);
+ messageBox.setWindowTitle(mConstraintsErrorTitle);
+ messageBox.setText(firstLine);
+ messageBox.setInformativeText(additionalLines);
+ messageBox.setStandardButtons(QMessageBox::Ok);
+ messageBox.exec();
+ return PassphraseNotOk;
+}
diff --git a/src/pinentry/pinentrydialog.h b/src/pinentry/pinentrydialog.h
new file mode 100644
index 00000000..97a90478
--- /dev/null
+++ b/src/pinentry/pinentrydialog.h
@@ -0,0 +1,180 @@
+/* pinentrydialog.h - A (not yet) secure Qt 4 dialog for PIN entry.
+ * Copyright (C) 2002, 2008 Klarälvdalens Datakonsult AB (KDAB)
+ * Copyright 2007 Ingo Klöcker
+ * Copyright 2016 Intevation GmbH
+ * Copyright (C) 2021, 2022 g10 Code GmbH
+ *
+ * Written by Steffen Hansen <[email protected]>.
+ * Modified by Andre Heinecke <[email protected]>
+ * Software engineering by Ingo Klöcker <[email protected]>
+ *
+ * This program 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 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __PINENTRYDIALOG_H__
+#define __PINENTRYDIALOG_H__
+
+#include <QAccessible>
+#include <QDialog>
+#include <QStyle>
+#include <QTimer>
+
+#include "pinentry.h"
+
+class QIcon;
+class QLabel;
+class QPushButton;
+class QLineEdit;
+class PinLineEdit;
+class QString;
+class QProgressBar;
+class QCheckBox;
+class QAction;
+
+QPixmap applicationIconPixmap(const QIcon &overlayIcon = {});
+
+void raiseWindow(QWidget *w);
+
+class PinEntryDialog : public QDialog
+#ifndef QT_NO_ACCESSIBILITY
+ ,
+ public QAccessible::ActivationObserver
+#endif
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString description READ description WRITE setDescription)
+ Q_PROPERTY(QString error READ error WRITE setError)
+ Q_PROPERTY(QString pin READ pin WRITE setPin)
+ Q_PROPERTY(QString prompt READ prompt WRITE setPrompt)
+ public:
+ struct FormattedPassphraseOptions {
+ bool formatPassphrase;
+ QString hint;
+ };
+ struct ConstraintsOptions {
+ bool enforce;
+ QString shortHint;
+ QString longHint;
+ QString errorTitle;
+ };
+
+ explicit PinEntryDialog(QWidget *parent = 0, const char *name = 0,
+ int timeout = 0, bool modal = false,
+ bool enable_quality_bar = false,
+ const QString &repeatString = QString(),
+ const QString &visibiltyTT = QString(),
+ const QString &hideTT = QString());
+ ~PinEntryDialog() override;
+
+ void setDescription(const QString &);
+ QString description() const;
+
+ void setError(const QString &);
+ QString error() const;
+
+ void setPin(const QString &);
+ QString pin() const;
+
+ QString repeatedPin() const;
+ void setRepeatErrorText(const QString &);
+
+ void setPrompt(const QString &);
+ QString prompt() const;
+
+ void setOkText(const QString &);
+ void setCancelText(const QString &);
+
+ void setQualityBar(const QString &);
+ void setQualityBarTT(const QString &);
+
+ void setGenpinLabel(const QString &);
+ void setGenpinTT(const QString &);
+
+ void setCapsLockHint(const QString &);
+
+ void setFormattedPassphrase(const FormattedPassphraseOptions &options);
+
+ void setConstraintsOptions(const ConstraintsOptions &options);
+
+ void setPinentryInfo(pinentry_t);
+
+ bool timedOut() const;
+
+ protected Q_SLOTS:
+ void updateQuality(const QString &);
+ void slotTimeout();
+ void textChanged(const QString &);
+ void focusChanged(QWidget *old, QWidget *now);
+ void toggleVisibility();
+ void onBackspace();
+ void generatePin();
+ void toggleFormattedPassphrase();
+
+ protected:
+ void keyPressEvent(QKeyEvent *event) override;
+ void keyReleaseEvent(QKeyEvent *event) override;
+ void showEvent(QShowEvent *event) override;
+
+ private Q_SLOTS:
+ void cancelTimeout();
+ void checkCapsLock();
+ void onAccept();
+
+ private:
+#ifndef QT_NO_ACCESSIBILITY
+ void accessibilityActiveChanged(bool active) override;
+#endif
+
+ enum PassphraseCheckResult {
+ PassphraseNotChecked = -1,
+ PassphraseNotOk = 0,
+ PassphraseOk
+ };
+ PassphraseCheckResult checkConstraints();
+
+ private:
+ QLabel *_icon = nullptr;
+ QLabel *_desc = nullptr;
+ QLabel *_error = nullptr;
+ QLabel *_prompt = nullptr;
+ QLabel *_quality_bar_label = nullptr;
+ QProgressBar *_quality_bar = nullptr;
+ PinLineEdit *_edit = nullptr;
+ PinLineEdit *mRepeat = nullptr;
+ QLabel *mRepeatError = nullptr;
+ QPushButton *_ok = nullptr;
+ QPushButton *_cancel = nullptr;
+ bool _grabbed = false;
+ bool _have_quality_bar = false;
+ bool _timed_out = false;
+ bool _disable_echo_allowed = true;
+ bool mEnforceConstraints = false;
+ bool mFormatPassphrase = false;
+ pinentry_t _pinentry_info = nullptr;
+ QTimer *_timer = nullptr;
+ QString mVisibilityTT;
+ QString mHideTT;
+ QAction *mVisiActionEdit = nullptr;
+ QPushButton *mGenerateButton = nullptr;
+ QCheckBox *mVisiCB = nullptr;
+ QLabel *mFormattedPassphraseHint = nullptr;
+ QLabel *mFormattedPassphraseHintSpacer = nullptr;
+ QLabel *mCapsLockHint = nullptr;
+ QLabel *mConstraintsHint = nullptr;
+ QString mConstraintsErrorTitle;
+};
+
+#endif // __PINENTRYDIALOG_H__
diff --git a/src/pinentry/pinlineedit.cpp b/src/pinentry/pinlineedit.cpp
new file mode 100644
index 00000000..9d172b56
--- /dev/null
+++ b/src/pinentry/pinlineedit.cpp
@@ -0,0 +1,204 @@
+/* pinlineedit.cpp - Modified QLineEdit widget.
+ * Copyright (C) 2018 Damien Goutte-Gattat
+ * Copyright (C) 2021 g10 Code GmbH
+ *
+ * Software engineering by Ingo Klöcker <[email protected]>
+ *
+ * This program 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 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include "pinlineedit.h"
+
+#include <QClipboard>
+#include <QGuiApplication>
+#include <QKeyEvent>
+
+static const int FormattedPassphraseGroupSize = 5;
+static const QChar FormattedPassphraseSeparator = QChar::Nbsp;
+
+namespace {
+struct Selection {
+ bool empty() const { return start < 0 || start >= end; }
+ int length() const { return empty() ? 0 : end - start; }
+
+ int start;
+ int end;
+};
+} // namespace
+
+class PinLineEdit::Private {
+ PinLineEdit *const q;
+
+ public:
+ Private(PinLineEdit *q) : q{q} {}
+
+ QString formatted(QString text) const {
+ const int dashCount = text.size() / FormattedPassphraseGroupSize;
+ text.reserve(text.size() + dashCount);
+ for (int i = FormattedPassphraseGroupSize; i < text.size();
+ i += FormattedPassphraseGroupSize + 1) {
+ text.insert(i, FormattedPassphraseSeparator);
+ }
+ return text;
+ }
+
+ Selection formattedSelection(Selection selection) const {
+ if (selection.empty()) {
+ return selection;
+ }
+ return {selection.start + selection.start / FormattedPassphraseGroupSize,
+ selection.end + (selection.end - 1) / FormattedPassphraseGroupSize};
+ }
+
+ QString unformatted(QString text) const {
+ for (int i = FormattedPassphraseGroupSize; i < text.size();
+ i += FormattedPassphraseGroupSize) {
+ text.remove(i, 1);
+ }
+ return text;
+ }
+
+ Selection unformattedSelection(Selection selection) const {
+ if (selection.empty()) {
+ return selection;
+ }
+ return {
+ selection.start - selection.start / (FormattedPassphraseGroupSize + 1),
+ selection.end - selection.end / (FormattedPassphraseGroupSize + 1)};
+ }
+
+ void copyToClipboard() {
+ if (q->echoMode() != QLineEdit::Normal) {
+ return;
+ }
+
+ QString text = q->selectedText();
+ if (mFormattedPassphrase) {
+ text.remove(FormattedPassphraseSeparator);
+ }
+ if (!text.isEmpty()) {
+ QGuiApplication::clipboard()->setText(text);
+ }
+ }
+
+ int selectionEnd() {
+#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
+ return q->selectionEnd();
+#else
+ return q->selectionStart() + q->selectedText().size();
+#endif
+ }
+
+ public:
+ bool mFormattedPassphrase = false;
+};
+
+PinLineEdit::PinLineEdit(QWidget *parent)
+ : QLineEdit(parent), d{new Private{this}} {
+ connect(this, SIGNAL(textEdited(QString)), this, SLOT(textEdited()));
+}
+
+PinLineEdit::~PinLineEdit() = default;
+
+void PinLineEdit::setFormattedPassphrase(bool on) {
+ if (on == d->mFormattedPassphrase) {
+ return;
+ }
+ d->mFormattedPassphrase = on;
+ Selection selection{selectionStart(), d->selectionEnd()};
+ if (d->mFormattedPassphrase) {
+ setText(d->formatted(text()));
+ selection = d->formattedSelection(selection);
+ } else {
+ setText(d->unformatted(text()));
+ selection = d->unformattedSelection(selection);
+ }
+ if (!selection.empty()) {
+ setSelection(selection.start, selection.length());
+ }
+}
+
+void PinLineEdit::copy() const { d->copyToClipboard(); }
+
+void PinLineEdit::cut() {
+ if (hasSelectedText()) {
+ copy();
+ del();
+ }
+}
+
+void PinLineEdit::setPin(const QString &pin) {
+ setText(d->mFormattedPassphrase ? d->formatted(pin) : pin);
+}
+
+QString PinLineEdit::pin() const {
+ if (d->mFormattedPassphrase) {
+ return d->unformatted(text());
+ } else {
+ return text();
+ }
+}
+
+void PinLineEdit::keyPressEvent(QKeyEvent *e) {
+ if (e == QKeySequence::Copy) {
+ copy();
+ return;
+ } else if (e == QKeySequence::Cut) {
+ if (!isReadOnly() && hasSelectedText()) {
+ copy();
+ del();
+ }
+ return;
+ } else if (e == QKeySequence::DeleteEndOfLine) {
+ if (!isReadOnly()) {
+ setSelection(cursorPosition(), text().size());
+ copy();
+ del();
+ }
+ return;
+ } else if (e == QKeySequence::DeleteCompleteLine) {
+ if (!isReadOnly()) {
+ setSelection(0, text().size());
+ copy();
+ del();
+ }
+ return;
+ }
+
+ QLineEdit::keyPressEvent(e);
+
+ if (e->key() == Qt::Key::Key_Backspace) {
+ emit backspacePressed();
+ }
+}
+
+void PinLineEdit::textEdited() {
+ if (!d->mFormattedPassphrase) {
+ return;
+ }
+ auto currentText = text();
+ // first calculate the cursor position in the reformatted text; the cursor
+ // is put left of the separators, so that backspace works as expected
+ auto cursorPos = cursorPosition();
+ cursorPos -= QStringView{currentText}.left(cursorPos).count(
+ FormattedPassphraseSeparator);
+ cursorPos += std::max(cursorPos - 1, 0) / FormattedPassphraseGroupSize;
+ // then reformat the text
+ currentText.remove(FormattedPassphraseSeparator);
+ currentText = d->formatted(currentText);
+ // finally, set reformatted text and updated cursor position
+ setText(currentText);
+ setCursorPosition(cursorPos);
+}
diff --git a/src/pinentry/pinlineedit.h b/src/pinentry/pinlineedit.h
new file mode 100644
index 00000000..e67ced83
--- /dev/null
+++ b/src/pinentry/pinlineedit.h
@@ -0,0 +1,63 @@
+/* pinlineedit.h - Modified QLineEdit widget.
+ * Copyright (C) 2018 Damien Goutte-Gattat
+ * Copyright (C) 2021 g10 Code GmbH
+ *
+ * Software engineering by Ingo Klöcker <[email protected]>
+ *
+ * This program 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 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _PINLINEEDIT_H_
+#define _PINLINEEDIT_H_
+
+#include <QLineEdit>
+
+#include <memory>
+
+class PinLineEdit : public QLineEdit
+{
+ Q_OBJECT
+
+public:
+ explicit PinLineEdit(QWidget *parent = nullptr);
+ ~PinLineEdit() override;
+
+ void setPin(const QString &pin);
+ QString pin() const;
+
+public Q_SLOTS:
+ void setFormattedPassphrase(bool on);
+ void copy() const;
+ void cut();
+
+Q_SIGNALS:
+ void backspacePressed();
+
+protected:
+ void keyPressEvent(QKeyEvent *) override;
+
+private:
+ using QLineEdit::setText;
+ using QLineEdit::text;
+
+private Q_SLOTS:
+ void textEdited();
+
+private:
+ class Private;
+ std::unique_ptr<Private> d;
+};
+
+#endif // _PINLINEEDIT_H_
diff --git a/src/pinentry/qti18n.cpp b/src/pinentry/qti18n.cpp
new file mode 100644
index 00000000..8e6bb591
--- /dev/null
+++ b/src/pinentry/qti18n.cpp
@@ -0,0 +1,93 @@
+/* qti18n.cpp - Load qt translations for pinentry.
+ * Copyright 2021 g10 Code GmbH
+ * SPDX-FileCopyrightText: 2015 Lukáš Tinkl <[email protected]>
+ * SPDX-FileCopyrightText: 2021 Ingo Klöcker <[email protected]>
+ *
+ * Copied from k18n under the terms of LGPLv2 or later.
+ *
+ * This program 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 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <QDebug>
+#include <QCoreApplication>
+#include <QLibraryInfo>
+#include <QLocale>
+#include <QTranslator>
+
+#include <memory>
+
+static bool loadCatalog(const QString &catalog, const QLocale &locale)
+{
+ auto translator = new QTranslator(QCoreApplication::instance());
+
+ if (!translator->load(locale, catalog, QString(), QLibraryInfo::location(QLibraryInfo::TranslationsPath))) {
+ qDebug() << "Loading the" << catalog << "catalog failed for locale" << locale;
+ delete translator;
+ return false;
+ }
+ QCoreApplication::instance()->installTranslator(translator);
+ return true;
+}
+
+static bool loadCatalog(const QString &catalog, const QLocale &locale, const QLocale &fallbackLocale)
+{
+ // try to load the catalog for locale
+ if (loadCatalog(catalog, locale)) {
+ return true;
+ }
+ // if this fails, then try the fallback locale (if it's different from locale)
+ if (fallbackLocale != locale) {
+ return loadCatalog(catalog, fallbackLocale);
+ }
+ return false;
+}
+
+// load global Qt translation, needed in KDE e.g. by lots of builtin dialogs (QColorDialog, QFontDialog) that we use
+static void loadTranslation(const QString &localeName, const QString &fallbackLocaleName)
+{
+ const QLocale locale{localeName};
+ const QLocale fallbackLocale{fallbackLocaleName};
+ // first, try to load the qt_ meta catalog
+ if (loadCatalog(QStringLiteral("qt_"), locale, fallbackLocale)) {
+ return;
+ }
+ // if loading the meta catalog failed, then try loading the four catalogs
+ // it depends on, i.e. qtbase, qtscript, qtmultimedia, qtxmlpatterns, separately
+ const auto catalogs = {
+ QStringLiteral("qtbase_"),
+ /* QStringLiteral("qtscript_"),
+ QStringLiteral("qtmultimedia_"),
+ QStringLiteral("qtxmlpatterns_"), */
+ };
+ for (const auto &catalog : catalogs) {
+ loadCatalog(catalog, locale, fallbackLocale);
+ }
+}
+
+static void load()
+{
+ // The way Qt translation system handles plural forms makes it necessary to
+ // have a translation file which contains only plural forms for `en`. That's
+ // why we load the `en` translation unconditionally, then load the
+ // translation for the current locale to overload it.
+ loadCatalog(QStringLiteral("qt_"), QLocale{QStringLiteral("en")});
+
+ const QLocale locale = QLocale::system();
+ if (locale.name() != QStringLiteral("en")) {
+ loadTranslation(locale.name(), locale.bcp47Name());
+ }
+}
+
+Q_COREAPP_STARTUP_FUNCTION(load)
diff --git a/src/pinentry/secmem++.h b/src/pinentry/secmem++.h
new file mode 100644
index 00000000..116da880
--- /dev/null
+++ b/src/pinentry/secmem++.h
@@ -0,0 +1,91 @@
+/* STL allocator for secmem
+ * Copyright (C) 2008 Marc Mutz <[email protected]>
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __SECMEM_SECMEMPP_H__
+#define __SECMEM_SECMEMPP_H__
+
+#include "../secmem/secmem.h"
+#include <cstddef>
+
+namespace secmem {
+
+ template <typename T>
+ class alloc {
+ public:
+ // type definitions:
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef T value_type;
+
+ // rebind
+ template <typename U>
+ struct rebind {
+ typedef alloc<U> other;
+ };
+
+ // address
+ pointer address( reference value ) const {
+ return &value;
+ }
+ const_pointer address( const_reference value ) const {
+ return &value;
+ }
+
+ // (trivial) ctors and dtors
+ alloc() {}
+ alloc( const alloc & ) {}
+ template <typename U> alloc( const alloc<U> & ) {}
+ // copy ctor is ok
+ ~alloc() {}
+
+ // de/allocation
+ size_type max_size() const {
+ return secmem_get_max_size();
+ }
+
+ pointer allocate( size_type n, void * =0 ) {
+ return static_cast<pointer>( secmem_malloc( n * sizeof(T) ) );
+ }
+
+ void deallocate( pointer p, size_type ) {
+ secmem_free( p );
+ }
+
+ // de/construct
+ void construct( pointer p, const T & value ) {
+ void * loc = p;
+ new (loc)T(value);
+ }
+ void destruct( pointer p ) {
+ p->~T();
+ }
+ };
+
+ // equality comparison
+ template <typename T1,typename T2>
+ bool operator==( const alloc<T1> &, const alloc<T2> & ) { return true; }
+ template <typename T1, typename T2>
+ bool operator!=( const alloc<T1> &, const alloc<T2> & ) { return false; }
+
+}
+
+#endif /* __SECMEM_SECMEMPP_H__ */
diff --git a/src/pinentry/secmem.cpp b/src/pinentry/secmem.cpp
new file mode 100644
index 00000000..cb4eeb4f
--- /dev/null
+++ b/src/pinentry/secmem.cpp
@@ -0,0 +1,375 @@
+/* secmem.c - memory allocation from a secure heap
+ * Copyright (C) 1998, 1999, 2003 Free Software Foundation, Inc.
+ * Copyright (C) 2015 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG 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 this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef WINDOWS
+#include <errno.h>
+#endif
+#include <stdarg.h>
+#include <unistd.h>
+#if defined(HAVE_MLOCK) || defined(HAVE_MMAP)
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#endif
+#include <string.h>
+
+#include "secmem.h"
+
+#ifdef ORIGINAL_GPG_VERSION
+#include "types.h"
+#include "util.h"
+#else /* ORIGINAL_GPG_VERSION */
+
+#include "secmem_util.h"
+
+typedef union {
+ int a;
+ short b;
+ char c[1];
+ long d;
+#ifdef HAVE_U64_TYPE
+ u64 e;
+#endif
+ float f;
+ double g;
+} PROPERLY_ALIGNED_TYPE;
+
+#define log_error log_info
+#define log_bug log_fatal
+
+void log_info(char *template_, ...) {
+ va_list args;
+
+ va_start(args, template_);
+ vfprintf(stderr, template_, args);
+ va_end(args);
+}
+
+void log_fatal(char *template_, ...) {
+ va_list args;
+
+ va_start(args, template_);
+ vfprintf(stderr, template_, args);
+ va_end(args);
+ exit(EXIT_FAILURE);
+}
+
+#endif /* ORIGINAL_GPG_VERSION */
+
+#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+#define DEFAULT_POOLSIZE 16384
+
+typedef struct memblock_struct MEMBLOCK;
+struct memblock_struct {
+ unsigned size;
+ union {
+ MEMBLOCK *next;
+ PROPERLY_ALIGNED_TYPE aligned;
+ } u;
+};
+
+static void *pool;
+static volatile int pool_okay; /* may be checked in an atexit function */
+#if HAVE_MMAP
+static int pool_is_mmapped;
+#endif
+static size_t poolsize; /* allocated length */
+static size_t poollen; /* used length */
+static MEMBLOCK *unused_blocks;
+static unsigned max_alloced;
+static unsigned cur_alloced;
+static unsigned max_blocks;
+static unsigned cur_blocks;
+static int disable_secmem;
+static int show_warning;
+static int no_warning;
+static int suspend_warning;
+
+static void print_warn(void) {
+ if (!no_warning) log_info("Warning: using insecure memory!\n");
+}
+
+static void lock_pool(void *p, size_t n) {
+#if defined(HAVE_MLOCK)
+ uid_t uid;
+ int err;
+
+ uid = getuid();
+
+#ifdef HAVE_BROKEN_MLOCK
+ if (uid) {
+ errno = EPERM;
+ err = -1;
+ } else {
+ err = mlock(p, n);
+ }
+#else
+ err = mlock(p, n);
+#endif
+
+ if (uid && !geteuid()) {
+ if (setuid(uid) || getuid() != geteuid())
+ log_fatal("failed to reset uid: %s\n", strerror(errno));
+ }
+
+ if (err) {
+ if (errno != EPERM
+#ifdef EAGAIN /* OpenBSD returns this */
+ && errno != EAGAIN
+#endif
+ )
+ log_error("can't lock memory: %s\n", strerror(errno));
+ show_warning = 1;
+ }
+
+#else
+ (void)p;
+ (void)n;
+ log_info("Please note that you don't have secure memory on this system\n");
+#endif
+}
+
+static void init_pool(size_t n) {
+#if HAVE_MMAP
+ size_t pgsize;
+#endif
+
+ poolsize = n;
+
+ if (disable_secmem) log_bug("secure memory is disabled");
+
+#if HAVE_MMAP
+#ifdef HAVE_GETPAGESIZE
+ pgsize = getpagesize();
+#else
+ pgsize = 4096;
+#endif
+
+ poolsize = (poolsize + pgsize - 1) & ~(pgsize - 1);
+#ifdef MAP_ANONYMOUS
+ pool = mmap(0, poolsize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS,
+ -1, 0);
+#else /* map /dev/zero instead */
+ {
+ int fd;
+
+ fd = open("/dev/zero", O_RDWR);
+ if (fd == -1) {
+ log_error("can't open /dev/zero: %s\n", strerror(errno));
+ pool = (void *)-1;
+ } else {
+ pool = mmap(0, poolsize, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+ close(fd);
+ }
+ }
+#endif
+ if (pool == (void *)-1)
+ log_info("can't mmap pool of %u bytes: %s - using malloc\n",
+ (unsigned)poolsize, strerror(errno));
+ else {
+ pool_is_mmapped = 1;
+ pool_okay = 1;
+ }
+
+#endif
+ if (!pool_okay) {
+ pool = malloc(poolsize);
+ if (!pool)
+ log_fatal("can't allocate memory pool of %u bytes\n", (unsigned)poolsize);
+ else
+ pool_okay = 1;
+ }
+ lock_pool(pool, poolsize);
+ poollen = 0;
+}
+
+/* concatenate unused blocks */
+static void compress_pool(void) { /* fixme: we really should do this */
+}
+
+void secmem_set_flags(unsigned flags) {
+ int was_susp = suspend_warning;
+
+ no_warning = flags & 1;
+ suspend_warning = flags & 2;
+
+ /* and now issue the warning if it is not longer suspended */
+ if (was_susp && !suspend_warning && show_warning) {
+ show_warning = 0;
+ print_warn();
+ }
+}
+
+unsigned secmem_get_flags(void) {
+ unsigned flags;
+
+ flags = no_warning ? 1 : 0;
+ flags |= suspend_warning ? 2 : 0;
+ return flags;
+}
+
+void secmem_init(size_t n) {
+ if (!n) {
+#if !defined(HAVE_DOSISH_SYSTEM)
+ uid_t uid;
+
+ disable_secmem = 1;
+ uid = getuid();
+ if (uid != geteuid()) {
+ if (setuid(uid) || getuid() != geteuid())
+ log_fatal("failed to drop setuid\n");
+ }
+#endif
+ } else {
+ if (n < DEFAULT_POOLSIZE) n = DEFAULT_POOLSIZE;
+ if (!pool_okay)
+ init_pool(n);
+ else
+ log_error("Oops, secure memory pool already initialized\n");
+ }
+}
+
+void *secmem_malloc(size_t size) {
+ MEMBLOCK *mb, *mb2;
+ int compressed = 0;
+
+ if (!pool_okay) {
+ log_info("operation is not possible without initialized secure memory\n");
+ log_info("(you may have used the wrong program for this task)\n");
+ exit(2);
+ }
+ if (show_warning && !suspend_warning) {
+ show_warning = 0;
+ print_warn();
+ }
+
+ /* blocks are always a multiple of 32 */
+ size += sizeof(MEMBLOCK);
+ size = ((size + 31) / 32) * 32;
+
+retry:
+ /* try to get it from the used blocks */
+ for (mb = unused_blocks, mb2 = NULL; mb; mb2 = mb, mb = mb->u.next)
+ if (mb->size >= size) {
+ if (mb2)
+ mb2->u.next = mb->u.next;
+ else
+ unused_blocks = mb->u.next;
+ goto leave;
+ }
+ /* allocate a new block */
+ if ((poollen + size <= poolsize)) {
+ mb = (MEMBLOCK *)((char *)pool + poollen);
+ poollen += size;
+ mb->size = size;
+ } else if (!compressed) {
+ compressed = 1;
+ compress_pool();
+ goto retry;
+ } else
+ return NULL;
+
+leave:
+ cur_alloced += mb->size;
+ cur_blocks++;
+ if (cur_alloced > max_alloced) max_alloced = cur_alloced;
+ if (cur_blocks > max_blocks) max_blocks = cur_blocks;
+
+ memset(&mb->u.aligned.c, 0,
+ size - (size_t) & ((struct memblock_struct *)0)->u.aligned.c);
+
+ return &mb->u.aligned.c;
+}
+
+void *secmem_realloc(void *p, size_t newsize) {
+ MEMBLOCK *mb;
+ size_t size;
+ void *a;
+
+ if (!p) return secmem_malloc(newsize);
+
+ mb = (MEMBLOCK *)(void *)((char *)p - offsetof(MEMBLOCK, u.aligned.c));
+
+ size = mb->size;
+ if (newsize < size) return p; /* it is easier not to shrink the memory */
+ a = secmem_malloc(newsize);
+ memcpy(a, p, size);
+ memset((char *)a + size, 0, newsize - size);
+ secmem_free(p);
+ return a;
+}
+
+void secmem_free(void *a) {
+ MEMBLOCK *mb;
+ size_t size;
+
+ if (!a) return;
+
+ mb = (MEMBLOCK *)(void *)((char *)a - offsetof(MEMBLOCK, u.aligned.c));
+ size = mb->size;
+ /* This does not make much sense: probably this memory is held in the
+ * cache. We do it anyway: */
+ wipememory2(mb, 0xff, size);
+ wipememory2(mb, 0xaa, size);
+ wipememory2(mb, 0x55, size);
+ wipememory2(mb, 0x00, size);
+ mb->size = size;
+ mb->u.next = unused_blocks;
+ unused_blocks = mb;
+ cur_blocks--;
+ cur_alloced -= size;
+}
+
+int m_is_secure(const void *p) {
+ return p >= pool && p < (void *)((char *)pool + poolsize);
+}
+
+void secmem_term(void) {
+ if (!pool_okay) return;
+
+ wipememory2(pool, 0xff, poolsize);
+ wipememory2(pool, 0xaa, poolsize);
+ wipememory2(pool, 0x55, poolsize);
+ wipememory2(pool, 0x00, poolsize);
+#if HAVE_MMAP
+ if (pool_is_mmapped) munmap(pool, poolsize);
+#endif
+ pool = NULL;
+ pool_okay = 0;
+ poolsize = 0;
+ poollen = 0;
+ unused_blocks = NULL;
+}
+
+void secmem_dump_stats(void) {
+ if (disable_secmem) return;
+ fprintf(stderr, "secmem usage: %u/%u bytes in %u/%u blocks of pool %lu/%lu\n",
+ cur_alloced, max_alloced, cur_blocks, max_blocks, (ulong)poollen,
+ (ulong)poolsize);
+}
+
+size_t secmem_get_max_size(void) { return poolsize; }
diff --git a/src/pinentry/secmem.h b/src/pinentry/secmem.h
new file mode 100644
index 00000000..75fe708b
--- /dev/null
+++ b/src/pinentry/secmem.h
@@ -0,0 +1,55 @@
+/* Quintuple Agent secure memory allocation
+ * Copyright (C) 1998,1999 Free Software Foundation, Inc.
+ * Copyright (C) 1999,2000 Robert Bihlmeyer <[email protected]>
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _MEMORY_H
+#define _MEMORY_H
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#if 0
+}
+#endif
+#endif
+
+
+/* values for flags, hardcoded in secmem.c */
+#define SECMEM_WARN 0
+#define SECMEM_DONT_WARN 1
+#define SECMEM_SUSPEND_WARN 2
+
+void secmem_init( size_t npool );
+void secmem_term( void );
+void *secmem_malloc( size_t size );
+void *secmem_realloc( void *a, size_t newsize );
+void secmem_free( void *a );
+int m_is_secure( const void *p );
+void secmem_dump_stats(void);
+void secmem_set_flags( unsigned flags );
+unsigned secmem_get_flags(void);
+size_t secmem_get_max_size (void);
+
+#if 0
+{
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif /* _MEMORY_H */
diff --git a/src/pinentry/secmem_util.h b/src/pinentry/secmem_util.h
new file mode 100644
index 00000000..3c8ffb8a
--- /dev/null
+++ b/src/pinentry/secmem_util.h
@@ -0,0 +1,65 @@
+/* Quintuple Agent utilities
+ * Copyright (C) 1999 Robert Bihlmeyer <[email protected]>
+ * Copyright (C) 2003 g10 Code GmbH
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef _UTIL_H
+#define _UTIL_H
+
+#include <sys/types.h>
+
+#ifndef HAVE_TYPE_BYTE
+# undef byte
+# if !(defined(_WIN32) && defined(cbNDRContext))
+ /* Windows typedefs byte in the rpc headers. Avoid warning about
+ double definition. */
+ typedef unsigned char byte;
+# endif
+# define HAVE_TYPE_BYTE
+#endif
+
+#ifndef HAVE_TYPE_ULONG
+# undef ulong
+ typedef unsigned long ulong;
+# define HAVE_TYPE_ULONG
+#endif
+
+
+ssize_t xwrite(int, const void *, size_t); /* write until finished */
+int debugmsg(const char *, ...); /* output a debug message if debugging==on */
+void drop_privs(void); /* finally drop privileges */
+
+
+/* To avoid that a compiler optimizes certain memset calls away, these
+ macros may be used instead. */
+#define wipememory2(_ptr,_set,_len) do { \
+ volatile char *_vptr=(volatile char *)(_ptr); \
+ size_t _vlen=(_len); \
+ while(_vlen) { *_vptr=(_set); _vptr++; _vlen--; } \
+ } while(0)
+#define wipememory(_ptr,_len) wipememory2(_ptr,0,_len)
+#define wipe(_ptr,_len) wipememory2(_ptr,0,_len)
+
+
+
+
+#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
+ *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
+#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
+
+
+#endif
diff --git a/src/pinentry/util.cpp b/src/pinentry/util.cpp
new file mode 100644
index 00000000..f1bac4ba
--- /dev/null
+++ b/src/pinentry/util.cpp
@@ -0,0 +1,116 @@
+/* Quintuple Agent
+ * Copyright (C) 1999 Robert Bihlmeyer <[email protected]>
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE 1
+
+#include <unistd.h>
+#ifndef WINDOWS
+# include <errno.h>
+#endif
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "util.h"
+
+#ifndef HAVE_DOSISH_SYSTEM
+static int uid_set = 0;
+static uid_t real_uid, file_uid;
+#endif /*!HAVE_DOSISH_SYSTEM*/
+
+/* Write DATA of size BYTES to FD, until all is written or an error
+ occurs. */
+ssize_t
+xwrite(int fd, const void *data, size_t bytes)
+{
+ char *ptr;
+ size_t todo;
+ ssize_t written = 0;
+
+ for (ptr = (char *)data, todo = bytes; todo; ptr += written, todo -= written)
+ {
+ do
+ written = write (fd, ptr, todo);
+ while (
+#ifdef WINDOWS
+ 0
+#else
+ written == -1 && errno == EINTR
+#endif
+ );
+ if (written < 0)
+ break;
+ }
+ return written;
+}
+
+#if 0
+extern int debug;
+
+int
+debugmsg(const char *fmt, ...)
+{
+ va_list va;
+ int ret;
+
+ if (debug) {
+ va_start(va, fmt);
+ fprintf(stderr, "\e[4m");
+ ret = vfprintf(stderr, fmt, va);
+ fprintf(stderr, "\e[24m");
+ va_end(va);
+ return ret;
+ } else
+ return 0;
+}
+#endif
+
+/* initialize uid variables */
+#ifndef HAVE_DOSISH_SYSTEM
+static void
+init_uids(void)
+{
+ real_uid = getuid();
+ file_uid = geteuid();
+ uid_set = 1;
+}
+#endif
+
+
+/* drop all additional privileges */
+void
+drop_privs(void)
+{
+#ifndef HAVE_DOSISH_SYSTEM
+ if (!uid_set)
+ init_uids();
+ if (real_uid != file_uid) {
+ if (setuid(real_uid) < 0) {
+ perror("dropping privileges failed");
+ exit(EXIT_FAILURE);
+ }
+ file_uid = real_uid;
+ }
+#endif
+}
diff --git a/src/pinentry/util.h b/src/pinentry/util.h
new file mode 100644
index 00000000..04f35957
--- /dev/null
+++ b/src/pinentry/util.h
@@ -0,0 +1,40 @@
+/* util.h - Helper for managing malloced pointers
+ * Copyright (C) 2021 g10 Code GmbH
+ *
+ * Software engineering by Ingo Klöcker <[email protected]>
+ *
+ * This program 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 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __PINENTRY_QT_UTIL_H__
+#define __PINENTRY_QT_UTIL_H__
+
+#include <memory>
+
+#include <stdlib.h>
+
+namespace _detail
+{
+struct FreeDeleter {
+ void operator()(void *ptr) const {
+ free(ptr);
+ }
+};
+}
+
+template<class T>
+using unique_malloced_ptr = std::unique_ptr<T, _detail::FreeDeleter>;
+
+#endif // __PINENTRY_QT_UTIL_H__
diff --git a/src/ui/GpgFrontendApplication.cpp b/src/ui/GpgFrontendApplication.cpp
index 83866c0d..7b079de1 100644
--- a/src/ui/GpgFrontendApplication.cpp
+++ b/src/ui/GpgFrontendApplication.cpp
@@ -73,6 +73,7 @@ GpgFrontendApplication *GpgFrontendApplication::GetInstance(int argc,
}
bool GpgFrontendApplication::notify(QObject *receiver, QEvent *event) {
+#ifdef RELEASE
try {
return QApplication::notify(receiver, event);
} catch (const std::exception &ex) {
@@ -97,6 +98,9 @@ bool GpgFrontendApplication::notify(QObject *receiver, QEvent *event) {
"please report this problem if you can."));
}
return -1;
+#else
+ return QApplication::notify(receiver, event);
+#endif
}
} // namespace GpgFrontend::UI
diff --git a/src/ui/UISignalStation.cpp b/src/ui/UISignalStation.cpp
index cae1de85..9370bcf4 100644
--- a/src/ui/UISignalStation.cpp
+++ b/src/ui/UISignalStation.cpp
@@ -28,15 +28,21 @@
#include "UISignalStation.h"
+#include <memory>
+
+#include "core/function/CoreSignalStation.h"
+
namespace GpgFrontend::UI {
std::unique_ptr<UISignalStation> UISignalStation::instance = nullptr;
auto UISignalStation::GetInstance() -> UISignalStation* {
if (instance == nullptr) {
- instance = std::make_unique<UISignalStation>();
+ instance = std::unique_ptr<UISignalStation>(new UISignalStation());
}
return instance.get();
}
+UISignalStation::UISignalStation() = default;
+
} // namespace GpgFrontend::UI
diff --git a/src/ui/UISignalStation.h b/src/ui/UISignalStation.h
index 16c78239..83e7a02c 100644
--- a/src/ui/UISignalStation.h
+++ b/src/ui/UISignalStation.h
@@ -88,19 +88,22 @@ class UISignalStation : public QObject {
* @brief
*
*/
- void SignalUserInputPassphraseDone(QString passparase);
+ void SignalNeedUserInputPassphrase();
/**
* @brief
*
*/
- void SignalNeedUserInputPassphrase();
+ void SignalUserInputPassphraseCallback(QByteArray);
/**
* @brief
*
*/
void SignalRestartApplication(int);
+
+ private:
+ UISignalStation();
};
} // namespace GpgFrontend::UI
diff --git a/src/ui/UserInterfaceUtils.cpp b/src/ui/UserInterfaceUtils.cpp
index 97520a25..2e3596f8 100644
--- a/src/ui/UserInterfaceUtils.cpp
+++ b/src/ui/UserInterfaceUtils.cpp
@@ -164,9 +164,6 @@ CommonUtils::CommonUtils() : QWidget(nullptr) {
connect(this, &CommonUtils::SignalKeyDatabaseRefreshDone,
UISignalStation::GetInstance(),
&UISignalStation::SignalKeyDatabaseRefreshDone);
- connect(this, &CommonUtils::SignalUserInputPassphraseDone,
- CoreSignalStation::GetInstance(),
- &CoreSignalStation::SignalUserInputPassphraseDone);
// directly connect to SignalKeyStatusUpdated
// to avoid the delay of signal emitting
@@ -175,10 +172,6 @@ CommonUtils::CommonUtils() : QWidget(nullptr) {
&UISignalStation::SignalKeyDatabaseRefresh, this,
&CommonUtils::slot_update_key_status);
- connect(CoreSignalStation::GetInstance(),
- &CoreSignalStation::SignalNeedUserInputPassphrase, this,
- &CommonUtils::slot_popup_passphrase_input_dialog);
-
connect(this, &CommonUtils::SignalRestartApplication,
UISignalStation::GetInstance(),
&UISignalStation::SignalRestartApplication);
@@ -467,7 +460,7 @@ void CommonUtils::slot_popup_passphrase_input_dialog() {
SetTempCacheValue("__key_passphrase", dialog->textValue().toStdString());
// send signal
- emit SignalUserInputPassphraseDone();
+ // emit SignalUserInputPassphraseDone();
}
void CommonUtils::SlotRestartApplication(int code) {
diff --git a/src/ui/UserInterfaceUtils.h b/src/ui/UserInterfaceUtils.h
index 9f9ef5bb..3746526a 100644
--- a/src/ui/UserInterfaceUtils.h
+++ b/src/ui/UserInterfaceUtils.h
@@ -192,18 +192,6 @@ class CommonUtils : public QWidget {
* @brief
*
*/
- void SignalNeedUserInputPassphrase();
-
- /**
- * @brief
- *
- */
- void SignalUserInputPassphraseDone();
-
- /**
- * @brief
- *
- */
void SignalRestartApplication(int);
public slots:
diff --git a/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp b/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp
index e5b5ab18..6f1bde9c 100644
--- a/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp
+++ b/src/ui/dialog/keypair_details/KeyPairOperaTab.cpp
@@ -32,6 +32,7 @@
#include "core/function/GlobalSettingStation.h"
#include "core/function/gpg/GpgKeyImportExporter.h"
#include "core/function/gpg/GpgKeyOpera.h"
+#include "core/typedef/GpgTypedef.h"
#include "core/utils/GpgUtils.h"
#include "core/utils/IOUtils.h"
#include "ui/UISignalStation.h"
@@ -343,11 +344,12 @@ void KeyPairOperaTab::slot_gen_revoke_cert() {
}
void KeyPairOperaTab::slot_modify_password() {
- auto err = GpgKeyOpera::GetInstance().ModifyPassword(m_key_);
- if (CheckGpgError(err) != GPG_ERR_NO_ERROR) {
- QMessageBox::critical(this, _("Not Successful"),
- QString(_("Modify password not successfully.")));
- }
+ GpgKeyOpera::GetInstance().ModifyPassword(m_key_, [this](GpgError err) {
+ if (CheckGpgError(err) != GPG_ERR_NO_ERROR) {
+ QMessageBox::critical(this, _("Not Successful"),
+ QString(_("Modify password not successfully.")));
+ }
+ });
}
void KeyPairOperaTab::slot_modify_tofu_policy() {
diff --git a/src/ui/main_window/MainWindow.cpp b/src/ui/main_window/MainWindow.cpp
index ce62b376..8cc76d65 100644
--- a/src/ui/main_window/MainWindow.cpp
+++ b/src/ui/main_window/MainWindow.cpp
@@ -30,6 +30,7 @@
#include "core/GpgModel.h"
#include "core/function/CacheManager.h"
+#include "core/function/CoreSignalStation.h"
#include "core/function/GlobalSettingStation.h"
#include "core/function/gpg/GpgAdvancedOperator.h"
#include "core/module/ModuleManager.h"
@@ -43,6 +44,10 @@ namespace GpgFrontend::UI {
MainWindow::MainWindow() : GeneralMainWindow("main_window") {
this->setMinimumSize(1200, 700);
this->setWindowTitle(qApp->applicationName());
+
+ connect(CoreSignalStation::GetInstance(),
+ &CoreSignalStation::SignalNeedUserInputPassphrase, this,
+ &MainWindow::SlotRaisePinentry);
}
void MainWindow::Init() noexcept {
diff --git a/src/ui/main_window/MainWindow.h b/src/ui/main_window/MainWindow.h
index f26a0a36..81975579 100644
--- a/src/ui/main_window/MainWindow.h
+++ b/src/ui/main_window/MainWindow.h
@@ -152,6 +152,11 @@ class MainWindow : public GeneralMainWindow {
*/
void SlotSetRestartNeeded(int);
+ /**
+ * @details Open a new tab for path
+ */
+ void SlotRaisePinentry();
+
private slots:
/**
diff --git a/src/ui/main_window/MainWindowSlotUI.cpp b/src/ui/main_window/MainWindowSlotUI.cpp
index 6c9705ac..d640d337 100644
--- a/src/ui/main_window/MainWindowSlotUI.cpp
+++ b/src/ui/main_window/MainWindowSlotUI.cpp
@@ -26,9 +26,15 @@
*
*/
+#include <qnamespace.h>
+
#include "MainWindow.h"
+#include "UISignalStation.h"
#include "core/GpgConstants.h"
+#include "core/function/CoreSignalStation.h"
#include "core/function/GlobalSettingStation.h"
+#include "pinentry/pinentrydialog.h"
+#include "spdlog/spdlog.h"
#include "ui/UserInterfaceUtils.h"
#include "ui/dialog/Wizard.h"
#include "ui/main_window/KeyMgmt.h"
@@ -223,4 +229,52 @@ void MainWindow::SetCryptoMenuStatus(
}
}
+void MainWindow::SlotRaisePinentry() {
+ auto* pinentry =
+ new PinEntryDialog(this, 0, 0, true, false, QString(),
+ QString::fromStdString(_("Show passphrase")),
+ QString::fromStdString(_("Hide passphrase")));
+
+ SPDLOG_DEBUG("setting pinetry's arguments");
+
+ pinentry->setPinentryInfo(new struct pinentry());
+ pinentry->setPrompt(QString::fromStdString(_("PIN:")));
+ pinentry->setDescription(QString());
+ pinentry->setRepeatErrorText(
+ QString::fromStdString(_("Passphrases do not match")));
+ pinentry->setGenpinLabel(QString());
+ pinentry->setGenpinTT(QString());
+ pinentry->setCapsLockHint(QString::fromStdString(_("Caps Lock is on")));
+ pinentry->setFormattedPassphrase({false, QString()});
+ pinentry->setConstraintsOptions({false, QString(), QString(), QString()});
+
+ pinentry->setWindowTitle(_("Pinentry"));
+
+ /* If we reuse the same dialog window. */
+ pinentry->setPin(QString());
+
+ pinentry->setOkText(_("Confirm"));
+ pinentry->setCancelText(_("Cancel"));
+
+ SPDLOG_DEBUG("pinentry is ready to start");
+
+ connect(pinentry, &PinEntryDialog::finished, this, [pinentry](int result) {
+ bool ret = result != 0;
+ SPDLOG_DEBUG("PinEntryDialog finished, ret: {}", ret);
+
+ if (!ret) {
+ emit CoreSignalStation::GetInstance()->SignalUserInputPassphraseCallback(
+ {});
+ return -1;
+ }
+
+ auto pin = pinentry->pin().toUtf8();
+ emit CoreSignalStation::GetInstance()->SignalUserInputPassphraseCallback(
+ pin);
+ return 0;
+ });
+
+ pinentry->open();
+}
+
} // namespace GpgFrontend::UI