diff options
author | saturneric <[email protected]> | 2023-12-02 14:01:16 +0000 |
---|---|---|
committer | saturneric <[email protected]> | 2023-12-02 14:01:16 +0000 |
commit | 0ec3358e4cfce7ad242e851c450292a25619221e (patch) | |
tree | 28a50308678ccbe0e0820d367f363df7df4e0be2 | |
parent | fix: add set owner struct action in keymanager menu (diff) | |
download | GpgFrontend-0ec3358e4cfce7ad242e851c450292a25619221e.tar.gz GpgFrontend-0ec3358e4cfce7ad242e851c450292a25619221e.zip |
feat: add buddled qt pinentry and make it works
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 Binary files differnew file mode 100644 index 00000000..b80c2a6f --- /dev/null +++ b/resource/lfs/icons/document-encrypt.png 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 |