summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS4
-rw-r--r--ChangeLog1259
-rw-r--r--NEWS62
-rw-r--r--README2
-rw-r--r--TODO518
-rw-r--r--VERSION2
-rw-r--r--config.h.in2
-rwxr-xr-xconfigure42
-rw-r--r--configure.ac16
-rw-r--r--doc/gpgme.info246
-rw-r--r--doc/gpgme.info-1294
-rw-r--r--doc/gpgme.info-2157
-rw-r--r--doc/gpgme.texi178
-rw-r--r--gpgme.spec2
-rw-r--r--lang/README1
-rw-r--r--lang/cl/gpgme.asd2
-rw-r--r--lang/cpp/src/context.h3
-rw-r--r--lang/cpp/src/data.cpp14
-rw-r--r--lang/cpp/src/data.h3
-rw-r--r--lang/cpp/src/importresult.cpp5
-rw-r--r--lang/cpp/src/importresult.h1
-rw-r--r--lang/cpp/src/key.cpp21
-rw-r--r--lang/cpp/src/key.h14
-rw-r--r--lang/python/README94
-rw-r--r--lang/python/examples/howto/README.org58
-rwxr-xr-xlang/python/examples/howto/add-userid.py62
-rwxr-xr-xlang/python/examples/howto/clear-sign-file.py56
-rwxr-xr-xlang/python/examples/howto/create-key.py95
-rwxr-xr-xlang/python/examples/howto/decrypt-file.py44
-rwxr-xr-xlang/python/examples/howto/detach-sign-file.py64
-rwxr-xr-xlang/python/examples/howto/encrypt-file.py71
-rwxr-xr-xlang/python/examples/howto/encrypt-sign-file.py70
-rw-r--r--lang/python/examples/howto/groups.py50
-rwxr-xr-xlang/python/examples/howto/keycount.py42
-rwxr-xr-xlang/python/examples/howto/revoke-userid.py62
-rwxr-xr-xlang/python/examples/howto/sign-file.py64
-rwxr-xr-xlang/python/examples/howto/sign-key.py63
-rwxr-xr-xlang/python/examples/howto/temp-homedir-config.py126
-rwxr-xr-xlang/python/examples/howto/verify-signatures.py64
-rwxr-xr-xlang/python/examples/howto/verify-signed-file.py61
-rwxr-xr-xlang/python/examples/low_level-encrypt_to_all.py (renamed from lang/python/examples/encrypt-to-all.py)0
-rwxr-xr-xlang/python/setup.py.in19
-rw-r--r--lang/python/tests/Makefile.am21
-rw-r--r--lang/python/tests/Makefile.in21
-rw-r--r--lang/qt/tests/Makefile.am10
-rw-r--r--lang/qt/tests/Makefile.in10
-rw-r--r--lang/qt/tests/t-config.cpp34
-rw-r--r--src/Makefile.am9
-rw-r--r--src/Makefile.in29
-rw-r--r--src/cJSON.c1404
-rw-r--r--src/cJSON.h187
-rw-r--r--src/context.h6
-rw-r--r--src/conversion.c46
-rw-r--r--src/decrypt.c81
-rw-r--r--src/encrypt-sign.c111
-rw-r--r--src/encrypt.c106
-rw-r--r--src/engine-assuan.c35
-rw-r--r--src/engine-backend.h3
-rw-r--r--src/engine-g13.c1
-rw-r--r--src/engine-gpg.c237
-rw-r--r--src/engine-gpgconf.c1
-rw-r--r--src/engine-gpgsm.c93
-rw-r--r--src/engine-spawn.c4
-rw-r--r--src/engine-uiserver.c60
-rw-r--r--src/engine.c30
-rw-r--r--src/engine.h3
-rw-r--r--src/get-env.c76
-rw-r--r--src/gpgme-json.c1772
-rw-r--r--src/gpgme-tool.c2
-rw-r--r--src/gpgme-w32spawn.c4
-rw-r--r--src/gpgme.c29
-rw-r--r--src/gpgme.def5
-rw-r--r--src/gpgme.h.in388
-rw-r--r--src/import.c9
-rw-r--r--src/keylist.c14
-rw-r--r--src/libgpgme.vers9
-rw-r--r--src/op-support.c18
-rw-r--r--src/ops.h4
-rw-r--r--src/priv-io.h2
-rw-r--r--src/util.h5
-rw-r--r--src/verify.c33
-rw-r--r--src/versioninfo.rc.in2
-rw-r--r--src/w32-io.c4
-rw-r--r--tests/gpg/Makefile.am22
-rw-r--r--tests/gpg/Makefile.in22
-rwxr-xr-xtests/gpg/pinentry2
-rw-r--r--tests/gpg/t-support.h6
-rw-r--r--tests/gpg/t-verify.c138
-rw-r--r--tests/gpgsm/Makefile.am20
-rw-r--r--tests/gpgsm/Makefile.in20
-rw-r--r--tests/run-decrypt.c65
-rw-r--r--tests/run-encrypt.c79
-rw-r--r--tests/run-support.h6
-rw-r--r--tests/run-verify.c32
94 files changed, 8424 insertions, 919 deletions
diff --git a/AUTHORS b/AUTHORS
index 6d2ce67..c989eff 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,5 +1,5 @@
Package: gpgme
-Homepage: https://gnupg.org/related_software/gpgme/
+Homepage: https://gnupg.org/software/gpgme/
Download: https://gnupg.org/ftp/gcrypt/gpgme/
Repository: git://git.gnupg.org/gpgme.git
Maintainer: Werner Koch <wk@gnupg.org>
@@ -19,7 +19,7 @@ List of Copyright holders
Copyright (C) 1991-2013 Free Software Foundation, Inc.
Copyright (C) 2000-2001 Werner Koch
- Copyright (C) 2001-2017 g10 Code GmbH
+ Copyright (C) 2001-2018 g10 Code GmbH
Copyright (C) 2002 Klarälvdalens Datakonsult AB
Copyright (C) 2004-2008 Igor Belyi
Copyright (C) 2002 John Goerzen
diff --git a/ChangeLog b/ChangeLog
index 3691aee..10dfc61 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,1262 @@
+2018-04-18 Werner Koch <wk@gnupg.org>
+
+ Release 1.11.0.
+ + commit 3f55c52b9adc3680c7a9fb0e598598e6ed3a2a5d
+ * configure.ac: Bump LT version to C31/A20/R0. For cpp to C12/A6/R0.
+ For qt to: C10/A3/R1.
+
+ json: Add stpcpy replacement.
+ + commit 8e34a14fe694a8c765973aaa3a8b2a2d2c3ba8b9
+ * src/gpgme-json.c [!HAVE_STPCPY](_my_stpcpy): New.
+
+ core: New convenience constant GPGME_KEYLIST_MODE_LOCATE.
+ + commit 55e9a94680370e584fbe5d21161a2cee3fe95744
+ * src/gpgme.h.in (GPGME_KEYLIST_MODE_LOCATE): New.
+
+ json: Add command "decrypt" to gpgme-json.
+ + commit e5273fc4431dfb597a2d9cf4af5172572476a2de
+ * src/gpgme-json.c (make_data_object): Enable auto-detection of
+ base-64.
+ (op_encrypt): Support a 'mime' flag.
+ (op_decrypt): New.
+ (process_request): Add command "encrypt".
+
+ core: Add 'is_mime' flags to the verify and decrypt results.
+ + commit 65479fe7b871ad6237d5a8959b73afcc7db784da
+ * src/op-support.c (_gpgme_parse_plaintext): Add arg r_mime.
+ * src/decrypt.c (_gpgme_decrypt_status_handler): Ser mime flag.
+ * src/verify.c (_gpgme_verify_status_handler): Ditto.
+ * src/gpgme.h.in (gpgme_op_verify_result_t): Append fields 'is_mime'
+ and '_unused'.
+ (gpgme_op_decrypt_result_t): New field 'is_mime'. Shrink '_unused'.
+
+ * tests/run-decrypt.c (print_result): Print MIME flag.
+ * tests/run-verify.c (print_result): Ditto.
+
+ core: Fix possible compliance mode detection error.
+ + commit 23177e4410d05d590c0f2e1675dc645bbb4ad62c
+ * src/verify.c (_gpgme_verify_status_handler): Insert missing break.
+
+ json: Improve help meta command in gpgme-json.
+ + commit 49a617f8bbff116884ca5c7238c2e0ea4e26ce59
+ * src/gpgme-json.c (process_meta_commands): Add ",help CMD".
+
+ json: Add command "getmore" to gpgme-json.
+ + commit ed1052842df633bc149b14c4cb17859e3c66afe4
+ * src/gpgme-json.c (MIN_REPLY_CHUNK_SIZE): New const.
+ (DEF_REPLY_CHUNK_SIZE): New const.
+ (MAX_REPLY_CHUNK_SIZE): New const.
+ (pending_data): New var.
+ (add_base64_to_object): Chnage to take a plain data pointer.
+ (get_chunksize): New.
+ (make_data_object): New.
+ (op_encrypt): Get chunksize and use make_data_object.
+ (op_getmore): New.
+ (process_request): Release pending data for all commands but "getmore"
+ and "help".
+
+ json: Add meta command ,read to gpgme-json.
+ + commit e69b175e8ed5430b56e2e8f3d68c16a45f0fed17
+ * src/gpgme-json.c: Include stat.h.
+ (get_file): New.
+ (process_meta_commands): Implement ",read".
+
+2018-04-17 Werner Koch <wk@gnupg.org>
+
+ core: Extend decryption result with symkey_algo.
+ + commit 01435da498af9f7538d7ee810392d7eaa407957e
+ * src/gpgme.h.in (gpgme_op_decrypt_result_t): Add field 'symkey_algo'.
+ * src/decrypt.c (release_op_data): Free SYMKEY_ALGO.
+ (gpgme_op_decrypt_result): Make sure SYMKEY_ALGO is not NULL.
+ (parse_decryption_info): New.
+ (_gpgme_decrypt_status_handler): Parse DECRYPTION_INFO status.
+ * src/conversion.c (_gpgme_cipher_algo_name): New.
+ (_gpgme_cipher_mode_name): New.
+
+ * tests/run-decrypt.c (print_result): Print SYMKEY_ALGO
+
+ * src/util.h (_gpgme_map_gnupg_error): Remove obsolete prototype.
+
+ core: New keyword --file for OpenPGP recpstring.
+ + commit 3589da0500f1c80717e658d103a0cb2751d27b49
+ * src/engine-gpg.c (append_args_from_recipients_string): Add new
+ flags.
+
+ core: For OpenPGP let offline mode disable dirmngr.
+ + commit c143ab692c7fc7cf2ec0aebe40b9479ee15eaba9
+ * src/engine-gpg.c (struct engine_gpg): New flag.offline.
+ (gpg_set_engine_flags): Set it. Also fix setting of no_symkey_cache.
+ (build_argv): Pass --disable-dirmngr in offline mode.
+
+2018-04-17 Tobias Mueller <muelli@cryptobitch.de>
+
+ python: Fix crash by leaving struct members intact.
+ + commit bbfa7c42337bb619e6af20bf051fe0755ed5a9fd
+ * lang/python/setup.py.in: Copy gpgme.h instead of parsing it.
+
+2018-04-17 Werner Koch <wk@gnupg.org>
+
+ core: Allow for --hidden keyword in OpenPGP recpstrings.
+ + commit 4bba3b8e2c350b8ff0d562ec63cc03a096448d84
+ * src/engine-gpg.c (append_args_from_recipients_string): Add special
+ keywords.
+
+ core: New encryption flag GPGME_ENCRYPT_WANT_ADDRESS.
+ + commit 86efba2be270d2cdd0bc66c9d3fe190495b7af2f
+ * src/gpgme.h.in (GPGME_ENCRYPT_WANT_ADDRESS): New flag.
+ * src/engine-gpg.c (add_arg_recipient): New.
+ (add_arg_recipient_string): New.
+ (append_args_from_recipients): Call new helper function.
+ (append_args_from_recipients_string): Ditto.
+ * src/gpgme-json.c (op_encrypt): Add flag "want-address".
+
+ core: Add extended versions of the encrypt functions.
+ + commit a1f76b3b54b75a150fe272b804d85ffd40a507a6
+ * src/gpgme.h.in (gpgme_op_encrypt_ext_start) New.
+ (gpgme_op_encrypt_ext): New.
+ (gpgme_op_encrypt_sign_ext_start): New.
+ (gpgme_op_encrypt_sign_ext): New.
+ * src/libgpgme.vers, tests/run-encrypt.c: Add them.
+
+ * src/encrypt.c (encrypt_start): Add arg recpstring.
+ (gpgme_op_encrypt): Factor code out to ...
+ (gpgme_op_encrypt_ext): new function with new arg recpstring.
+ (gpgme_op_encrypt_start): Factor code out to ...
+ (gpgme_op_encrypt_ext_start): new function with new arg recpstring.
+ * src/encrypt-sign.c (encrypt_sign_start): Add arg recpstring.
+ (gpgme_op_encrypt_sign): Factor code out to ...
+ (gpgme_op_encrypt_sign_ext): new function with new arg recpstring.
+ (gpgme_op_encrypt_sign_start): Factor code out to ...
+ (gpgme_op_encrypt_sign_ext_start): new function with new arg
+ recpstring.
+
+ * src/engine-backend.h (struct engine_ops): Change fields encrypt and
+ encrypt_sign.
+ * src/engine.c (_gpgme_engine_op_encrypt): Add arg recpstring and pass
+ to engine.
+ (_gpgme_engine_op_encrypt_sign): Ditto.
+ * src/engine-gpg.c (append_args_from_recipients_string): New.
+ (gpg_encrypt): Add arg recpstring and call new function as needed.
+ (gpg_encrypt_sign): Ditto.
+ * src/engine-gpgsm.c (set_recipients_from_string): New.
+ (gpgsm_encrypt): Add arg recpstring and call new function as needed.
+ * src/engine-uiserver.c (set_recipients_from_string): New.
+ (uiserver_encrypt): Add arg recpstring and call new function as
+ needed.
+
+ * tests/run-encrypt.c (xstrdup): New.
+ (main): Add option --keystring.
+
+ * src/gpgme-json.c (get_keys): Simplify.
+ (op_encrypt): Modify to make use of the extended encrypt function.
+
+2018-04-12 Werner Koch <wk@gnupg.org>
+
+ core: Tweak STATUS_FAILURE handling.
+ + commit b99502274ae5efdf6df0d967900ec3d1e64373d7
+ * src/op-support.c (_gpgme_parse_failure): Ignore failures with
+ location "gpg-exit".
+ * tests/gpg/t-verify.c (main): Adjust for the now working checking of
+ the second key.
+
+ core: For a failed verification return the sig's fingerprint.
+ + commit 478d1650bbef84958ccce439fac982ef57b16cd0
+ * src/verify.c (parse_new_sig): Parse the new ERRSIG fpr.
+
+ tests: Avoid segv in run-verify due to Policy URLs.
+ + commit ee8fad3ea0cbc82f31c86b3483abd8549df62b69
+ * tests/run-verify.c (print_result): Take care of Policy URLs.
+
+ tests: Add another check to gpg/t-verify.
+ + commit bdf7cd2e28432cf0fa7e0758acdfee03d7bfd45f
+ * tests/gpg/t-verify.c (PGM): New. Use it instead of __FILE__.
+ (test_sig1_plus_unknown_key): New test signature.
+ (check_result): Allow checking of several signatures.
+ (main): Check a signature with a know and an unknown key.
+
+ core: Add new context flag "no-symkey-cache".
+ + commit f7700a016926f0d8e9cb3c0337837deb7fe01079
+ * src/gpgme.c (gpgme_set_ctx_flag): Set flag.
+ (gpgme_get_ctx_flag): Get flag.
+ * src/context.h (struct gpgme_context): Add field no_symkey_cache.
+ * src/engine-gpg.c (struct engine_gpg): Ditto.
+ (gpg_set_engine_flags): Set flag.
+ (build_argv): Pass option --no-symkey-cache to gpg.
+
+ * tests/run-decrypt.c (print_result): Fix segv for symmetric messages.
+ (main): New option --no-symkey-cache.
+ * tests/run-encrypt.c (main): New option --no-symkey-cache.
+
+2018-04-04 Andre Heinecke <aheinecke@intevation.de>
+
+ qt: Add test for resetting config value.
+ + commit 5eb261d6028ab2c0ddd9af8e3e1f82e479c6109c
+ * lang/qt/tests/t-config.cpp (CryptoConfigTest::testDefault): New.
+
+2018-03-29 Werner Koch <wk@gnupg.org>
+
+ json: Build only a dummy if libgpg-error is < 1.28.
+ + commit 60d7a1e8f625ea0db455bff989534dd52f0650c7
+
+
+2018-03-29 Ben McGinnes <ben@adversary.org>
+
+ example: revoke UID.
+ + commit 3b91f6af378ccc37dcf8924cbc157894c35b5192
+ * Script to revoke a UID on an existing key.
+
+ docs: python bindings howto.
+ + commit d65864989c0560b5f51cb8d05d9ea9f1957b453e
+ * Added section on revoking UIDs.
+
+ example: key signing.
+ + commit 56bbfd39acea90eb87a28b11a515b0314cdda54c
+ * Added script for signing or certifying keys.
+
+ doc: python bindings howto.
+ + commit 5a553f5a317e5ad5ab0274d58854df1ecf390e0d
+ * Fixed a typo.
+
+2018-03-28 Ben McGinnes <ben@adversary.org>
+
+ docs python bindings howto.
+ + commit 2f507b045909d32bf29d23da04db02b078e5fb9d
+ * PEP8 compliance: a collection of minor edits across multiple example
+ code snippets.
+
+ example: add user ID.
+ + commit 5cd419341807d8ae23fec7bd9bb7025a8a2dcb3c
+ * Added script to add a UID to an existing key.
+
+2018-03-28 Werner Koch <wk@gnupg.org>
+
+ json: Remove the "message" object thingy again.
+ + commit 3345a17dda2222e3c1592235e8a1cd9493192777
+ * src/gpgme-json.c (process_request): Remove 'nm_mode'.
+
+ json: Make native messaging work.
+ + commit 4b2fa657d195382d14ac99be40b66327e0fc855c
+ * src/gpgme-json.c (opt_debug): New.
+ (process_request): Add optional arg nm_mode. In this mode take the
+ request from a "message" object.
+ (native_messaging_repl): Add debug output and call process_request
+ in NM_MODE.
+ (main): Add option --debug. Parse envvar GPGME_JSON_DEBUG as an
+ alternative way to enable this. Use a default log file.
+
+2018-03-27 Andre Heinecke <aheinecke@intevation.de>
+
+ core: Initialize key return value in gpgme_get_key.
+ + commit 7c220e387d511b0cf66f99370759c36b729cc444
+ * src/keylist.c (gpgme_get_key): Set r_key to NULL.
+
+2018-03-27 Ben McGinnes <ben@adversary.org>
+
+ doc: python bindings howto.
+ + commit a2eedef630891397f8eccb5bb426a0728588bf41
+ * Fixed some minor PEP8 compliance issues in the key creation examples.
+
+ example: key creation.
+ + commit f9159b1d75d3209b1c22bbb0ed4472800b60a522
+ * Script to generate a new key with encryption subkey taking input
+ from interactive prompts.
+ * Will also take a passphrase via pinentry and uses passphrase caching
+ of five minutes when used in conjunction with the temp homedir
+ script.
+
+ script: temp homedir config.
+ + commit 1b5da37a47ceef41545e0b2474738613f36be949
+ * added passphrase caching of 5 minutes.
+
+2018-03-25 Ben McGinnes <ben@adversary.org>
+
+ doc: python bindings howto.
+ + commit 5b32efbaf37920b2e99d4bb87cb383b2809b1688
+ * Testing the addition of a HTML header set in org-mode in order to
+ had RSS update links for files.
+ * This should work with any [X]HTML export from current versions of
+ Org-Mode, but if it also works on website generated pages then it'll
+ tick off one of the wishlist itmes.
+
+ script: temp homedir.
+ + commit 40a9dea5d56506400b67b0c11f6e55a1629dc6fe
+ * Fixed whitespace.
+
+ doc: python bindings howto.
+ + commit 3b724aae423f2de01812165d54df2a7b524c82f6
+ * Added a reference to new script which will setup a temporary homedir
+ for a user.
+
+ script: temporary homedir creation.
+ + commit dde1aae312958776fab475d6c0cdfa19cc255863
+ * Script to create a temporary gnupg homedir in the user's directory
+ for testing or scripting purposes.
+ * Creates a hidden directory on POSIX systems with the correct
+ permissions (700).
+ * Creates a gpg.conf in that directory containing the same
+ configuration options as used in the "Danger Mouse" example in the
+ HOWTO with the correct permissions (600).
+
+ doc: python bindings howto.
+ + commit 22247f658ce2f8e527c26746358cfc2643c4832f
+ * Fixed the plaintext, result and verify_result references in the
+ decryption section.
+
+2018-03-23 Ben McGinnes <ben@adversary.org>
+
+ doc: python bindings howto.
+ + commit e6180f2b36cc8a6c6154e5f3d702324af573132a
+ * Fixed a minor spelling error and a minor grammatical error.
+
+2018-03-23 Werner Koch <wk@gnupg.org>
+
+ core: Need to increase an array in the gpg engine.
+ + commit 4763974ef6932c503e35c3d14fe47a66a5323f48
+ * src/engine-gpg.c (build_argv): Allcate one slot more for ARGV.
+
+ json: Use a request origin of "browser".
+ + commit e5abf4827aead50437bbdff8cfdd5e9fdc6ed72d
+ * src/gpgme-json.c (_create_new_context): Set flag.
+
+ core: New gpgme_set_ctx_flag "request-origin".
+ + commit b9000bc293164ff62efa7e91e5cf6d5fc19d482f
+ * src/context.h (gpgme_context): Add 'request_origin'.
+ * src/gpgme.c (gpgme_release): Free that field.
+ (gpgme_set_ctx_flag, gpgme_get_ctx_flag): Add "request-origin".
+ * src/engine-backend.h (engine_ops): Add 'set_engine_ops' func ptr and
+ adjust all users.
+ * src/engine.c (_gpgme_engine_set_engine_flags): New.
+ * src/op-support.c (_gpgme_op_reset): Call that func.
+ * src/engine-gpg.c (struct engine_gpg): Add 'request_origin'.
+ (gpg_set_engine_flags): New.
+ (_gpgme_engine_ops_gpg): Hook it.
+ (build_argv): Use command line option --request-origin.
+ * src/engine-gpgsm.c (struct engine_gpgsm): Add 'request_origin'.
+ (gpgsm_set_engine_flags): New.
+ (_gpgme_engine_ops_gpgsm): Hook it.
+ (start): Send OPTION "request-origin".
+ * src/engine-assuan.c (struct engine_llass): Add 'request_origin'.
+ (gpgsm_set_engine_flags): New.
+ (_gpgme_engine_ops_assuan): Hook it.
+ (start): Send OPTION "pretend-request-origin".
+
+ build: Allow building with released libgpg-error.
+ + commit eee68c1b13fbe21c123f469712817e0c81f16383
+ * src/gpgme-json.c (add_base64_to_object): Return an error if building
+ with an older libgpg-error.
+
+ json: Finish op:encrypt.
+ + commit d83482a1d768fc5afd3aa4836f2fefe5c549d02e
+ * src/gpgme-json.c (add_base64_to_object): New.
+ (data_from_base64_string): New.
+ (op_encrypt): Employ them.
+ (process_request): Print unformated json.
+
+ json: Add a new function to cJSON.
+ + commit 6525d78d0a1d303c449762082942e71d3002b9ca
+ * src/cJSON.c (cJSON_CreateStringConvey): New.
+
+2018-03-22 Ben McGinnes <ben@adversary.org>
+
+ doc: python bindings howto.
+ + commit 65ed4ac82598734551b87fc89deab3cee010bd37
+ * Fixed table.
+
+2018-03-21 Ben McGinnes <ben@adversary.org>
+
+ doc and examples: python bindings HOWTO.
+ + commit 5722148bacab5862b40a027861d64683a0f214ea
+ * Added GPGME Python bindings HOWTO in Australian/British English.
+ ** en-US "translation" still to be done.
+ * Added several example scripts comprised of the "Basic Functions"
+ section of the HOWTO (plus the work-around at the end).
+ ** As these scripts are very basic examples they are released under
+ both the GPLv2+ and the LGPLv2.1+ (just like GPGME itself).
+
+ examples: multi-key selection operations.
+ + commit 05e59933056ee8ef8ba7579351a58ed25dd7f754
+ * Temporarily removing multi-key selection based examples.
+ * There are a few issues with getting the key selections to play
+ nicely with gpg.Context().keylist object types.
+ * Will troubleshoot them separately and restore them when that's
+ worked out, but I don't want these more complicated examples to
+ delay merging the HOWTO with master.
+
+ example: group encryption.
+ + commit 61a988036bd3f0d43f7d55bfa43f5f05bec978c4
+ * Troubleshooting.
+
+ examples: encryption.
+ + commit 7ddff71908a85111c8e0da41312197b3b1a77da6
+ * Fixed two incorrect Context() objects.
+
+ example: key selection.
+ + commit c6a0395f0a3a57071f0c943f7815f58a02f9d2f3
+ * Removed extraneous blank line.
+
+ example: key selection.
+ + commit 0a0d57fd41380cd797d29e11cec8a77c7404e960
+ * Similar to group-key-selection.py, but does not use an existing
+ group from gpg.conf; instead takes multiple key IDs, fingerprints or
+ patterns on the command line and adds them to a keylist object.
+
+ example: sign and encrypt to group.
+ + commit 0ccc57c9512246d82d46e7732bfb0f95c18ca9d3
+ * Begins to string together some of the simpler examples to do more
+ useful things.
+ * Signs and encrypts a file while encrypting to every key in a group
+ specified in the gpg.conf file.
+
+2018-03-21 Werner Koch <wk@gnupg.org>
+
+ json: Use gpgrt_argparse instead of argsparse.c.
+ + commit e14f1f687ff618716ed17e309a0475df95e1c0aa
+ * src/gpgme-json.c: Remove header argparse.h. Define
+ GPGRT_ENABLE_ARGPARSE_MACROS.
+ (interactive_repl): Replace strusage by gpgrt_strusage.
+ (my_strusage): Add SPDX level.
+ (main): Switch to gpgrt_argparse stuff but keep very limited
+ functionality when building with an older libgpg-error.
+
+2018-03-21 Ben McGinnes <ben@adversary.org>
+
+ example: group key selection.
+ + commit 8b401bfc76eac762553f76faab53c2f4cd117a8d
+ * Example of preparing a keylist object using an existing group line
+ from the gpg.conf file.
+
+ example groups work around.
+ + commit 6c6af9a7b0ae4e7182d669bec282c6edaaa7eaa1
+ * Updated usage so it only references importing the final list of
+ lists produced. Trying to use some of the mid-points can have
+ unpredictable results (this is part of the problem with work
+ arounds).
+
+ example: groups.
+ + commit a4e3f827652c59d850b4e5506a92c1ecd190c1bb
+ * Added a docstring.
+
+ example: verify signatures.
+ + commit ad6cb4f9b8b97a2bc501c17fc542a84b725dedea
+ * Added example for verifying detached signatures against the files
+ they're the signatures for.
+
+ example: verify signed file.
+ + commit ae2767eb27b6a76284ee4403e575869afe2e80a8
+ * Added example to verify normal and clearsigned files.
+
+ doc: python bindings howto.
+ + commit e57388a69f61d14e3df3c842d227fb450c96c807
+ * Fixed minor error in one of the verification examples.
+
+ example: detach sign file.
+ + commit ac6a552c37147a000de74f49d1bff34dad52252e
+ * Added example to make detached signatures of a file with key selection.
+
+ example: encrypt-sign-file.py.
+ + commit af6cbba18ba5e2bbecce5f8268c146282cd12367
+ * Adjusted the doc string.
+
+ examples: doc strings.
+ + commit 6fa2a344282e369e6aca8155bc77dd2c12a29414
+ * Fixed minor errors in two doc strings.
+
+ example: clear signing.
+ + commit 1fdd1f306d45f6aeee91c7f016f7c37286ee3b3b
+ * Added example to clear sign a file with signing key selection.
+
+ doc: python bindings howto.
+ + commit 1d2746433c9632fc0c7bc10b59280fca15895545
+ * deconstructed and fixed all three signing methods.
+
+ example: sign file.
+ + commit 0390ede18696520be9cc1a42f628e23159b7c2eb
+ * Similar to encrypt file except for signing a file in normal mode.
+ * Noticed additional changes to be made to the howto to match this,
+ but they will have to wait due to a power outage (currently running
+ on battery and a mobile connection, but that won't last).
+
+2018-03-20 Werner Koch <wk@gnupg.org>
+
+ json: Implement op:encrypt.
+ + commit 6073789a6d3514263404c93fa795a398bfd93d91
+
+
+ core: Do not clobber R_KEY in gpgme_get_key on error.
+ + commit 343d3e2232a22d0999e1693f0f95e5e290005829
+ * src/keylist.c (gpgme_get_key): Assign a value to the return
+ parameter only on success.
+
+ core: Fix ABI regression in recent commit.
+ + commit 9e1e6554834d0e803dd0889deaef4f11047c7e47
+ * src/gpgme.h.in (_gpgme_op_import_result): Move new field
+ 'skipped_v3_keys' to the end.
+
+2018-03-20 Ben McGinnes <ben@adversary.org>
+
+ doc: python bindings howto.
+ + commit 52e262991f1fdf7da93882c3b22c05537376cf49
+ * Fixed typos in examples.
+
+ example: keycount.
+ + commit 96d0395bccbbff91f73c06cb7bd6c131f04b8a9a
+ * Fixed missing parenthesis.
+
+ example: decrypt file.
+ + commit 51258975d763c9471859d635e6080c2ec02e8647
+ * Decrypts a file taking file names as command line parameters.
+
+ example: groups work-around.
+ + commit 29e918171f352c71a90a16c04d4a3dcafa5db682
+ * Added groups selection work around code.
+ * Intended for use as a module to be imported by other scripts,
+ usually with "from groups import group_lists" or "from groups import
+ group_lines" or similar.
+
+2018-03-19 Ben McGinnes <ben@adversary.org>
+
+ example: encrypt file.
+ + commit 7221bb67642eb01a07957d66d0cbcd4ef8aadbf8
+ * Nested encryption in try/except statement in case recipient key is
+ untrusted or invalid.
+
+ example: sign and encrypt file.
+ + commit f3fe47e8fd2e7bc748016befcae494421223368c
+ * Example to sign and encrypt a file.
+ * Similar to encrypt-file.py except all keys are considered trusted
+ and signs with the default key.
+ * Also encrypts to the default key.
+
+ example: encrypt file.
+ + commit f0790f224d7af9521efe96e69a8f719fb89a5af2
+ * Fixed typo in second encryption call.
+
+ example: encrypt file.
+ + commit 7ab42e79ade89f28507ea42d51148a40b4bfc736
+ * Example to encrypt a file to a single key.
+ * Takes key ID and/or fpr as a CLI parameter.
+ * Takes path and filename as a CLI parameter.
+ * Encrypts to specified key only, no signing and writes the output in
+ both ASCII armoured and GPG binary formats with output filenames
+ based on input filename.
+
+ example: python bindings key count.
+ + commit cfbdcb7fb3fa438cafba82e4fb8f327df596f98e
+ * Added script wo count the number of keys in both the public and
+ secret key stores.
+
+ doc: python bindings examples.
+ + commit b30ebf89725641018b3b08f77876530f9b983fa2
+ * Explicitly stated that all this code is released under the GPLv2+
+ and the LGPLv2.1+.
+
+ doc: python bindings example README.
+ + commit 8f7672ad1b267f122f647bb5f984734d0ff66a5c
+ * Added the same license as used with the HOWTO.
+ * Since these examples are so basic, they'll be dual licensed the same
+ as GPGME itself (otherwise it would slip too dangerously against the
+ need for permissive licensing of crypto libraries).
+
+ docs: python bindings examples.
+ + commit 6950a63e63d60685ddb6f4cbff7b826b8acb5b13
+ * Added reference to location where all the examples included in the
+ HOWTO will be available as executable scripts.
+ * Included a short README file in that location.
+
+ example: python bindings encryption.
+ + commit 3e0f68fdff1998dae9cb6f8510a3e945a268d1f6
+ * Since we don't want to encourage accessing the low level functions
+ (e.g. op_encrypt), but since this example can still be useful to
+ understand, renaming it and will add new encryption examples to
+ match the instructions in the HOWTO.
+
+ doc: python bindings howto.
+ + commit d5f6dec048d3d4d94f1fcdb3f4249cf6e71c4b92
+ * Slight python-gnupg clarification. See also this thread:
+ https://lists.gnupg.org/pipermail/gnupg-devel/2018-March/033528.html
+
+ doc: python bindings howto.
+ + commit 0fb8a5d45c1c77a5928d6e356271da055aa55994
+ * Adjusted the python-gnupg so the comments regarding insecure
+ invocation of commands via subprocess (shell=True) were a major
+ historical issue and not a a current issue.
+ * Not including Vinay Sajip's requested change to say it is now secure
+ since no audit of the current code base has been performed and my
+ last major inspection of that code was around the time I first
+ ported PyME to Python 3 in 2015.
+
+ doc: python bindings todo list.
+ + commit bf67cf433fe82924ed40e79785e95403c07cc068
+ * Checked off several points of howto coverage as completed.
+ * Reorganised to move S/MIME coverage to its own separate group of tasks.
+ * Noted only revocation remains for howto completion.
+
+ doc: python bindings howto.
+ + commit 1779d7b9d6769b2e47f1e90260290e25c8c3aa02
+ * deconstructing multi-recipient encryption.
+
+ doc: python bindings howto.
+ + commit 64c5886132aceefc9d9600a3a6dbbbf404b95b81
+ * Replaced the single encryption methods with one main way (i.e. cut
+ the low level stuff involving SEEK_SET instructions).
+
+2018-03-18 Ben McGinnes <ben@adversary.org>
+
+ doc: python bindings howto.
+ + commit 4811ff7b6c8ef97c7d4858ce235e9bf8227f4917
+ * moved single encrytion examples up to the first ones, pending merge
+ and major cut.
+ * This is basically just to make future checks of revisions a little easier.
+
+ doc: python bindings howto.
+ + commit 82c5af225f2bdf3acc6fc652a96ee61c9b057395
+ * Stripped decryption example to the bare bones as suggested by Justus.
+
+2018-03-16 Ben McGinnes <ben@adversary.org>
+
+ doc: python bindings howto.
+ + commit b549f69d0520bb74957b95cec9ea918dba2374f6
+ * Made the changes suggested by Jakub Wilk on gnupg-devel.
+ * Still need to make the far more comprehensive changes suggested by Justus.
+
+2018-03-16 Werner Koch <wk@gnupg.org>
+
+ json: Add framework for the gpgme-json tool.
+ + commit d2b31d8c106423bd0eaa5fffaa39b0983c9ae525
+ * src/gpgme-json.c: New.
+ * src/Makefile.am (bin_PROGRAMS): Add gpgme-json.
+ (gpgme_json_SOURCES, gpgme_json_LDADD): New.
+
+ core: Adjust cJSON code for use in GPGME.
+ + commit 81c90d0cd0f959fd5e01baed9b4af0ec35ecb85c
+ * src/cJSON.c: Remove util.h. Use gpgrt alloc functions.
+ (cJSON_Delete): Do not clobber ERRNO.
+ (cJSON_AddItemToObject): Return OBJECT or NULL.
+ (cJSON_AddNullToObject): New.
+ (cJSON_AddTrueToObject): New.
+ (cJSON_AddFalseToObject): New.
+ (cJSON_AddBoolToObject): New.
+ (cJSON_AddNumberToObject): New.
+ (cJSON_AddStringToObject): New.
+ * src/cJSON.h (cJSON__h): Replace macro by cJSON_h for C compliance.
+ (cJSON_AddNullToObject): Remove macro.
+ (cJSON_AddTrueToObject): Remove macro.
+ (cJSON_AddFalseToObject): Remove macro.
+ (cJSON_AddBoolToObject): Remove macro.
+ (cJSON_AddNumberToObject): Remove macro.
+ (cJSON_AddStringToObject): Remove macro.
+
+2018-03-15 Ben McGinnes <ben@adversary.org>
+
+ doc: python bindings howto.
+ + commit 431897a4c48fe1bc9d37f655097aabaf5b685d11
+ * Added clarification on why it's not on PyPI.
+
+2018-03-15 Andre Heinecke <aheinecke@intevation.de>
+
+ cpp: Expose skipped_v3_keys.
+ + commit ad95288d3b3efc38998841add4fe658c84701f98
+ * lang/cpp/src/importresult.cpp,
+ lang/cpp/src/importresult.h (ImportResult::numV3KeysSkipped): New.
+
+ core: Parse skipped_v3_keys.
+ + commit a630a1e3e74c926163864b013cb164b4cd1866fc
+ * src/gpgme.h.in (gpgme_import_result_t): Extend with skipped_v3_keys.
+ * src/import.c (gpgme_op_import_result): Extend debug with new field.
+ (parse_import_res): Parse skipped_v3_keys.
+ * tests/gpg/t-support.h, tests/run-support.h (print_import_result):
+ Print skipped_v3_keys.
+
+2018-03-15 Ben McGinnes <ben@adversary.org>
+
+ doc: python bindings howto.
+ + commit 22e2445beee46ed1e527a98e635153c7cf03786f
+ * fixed custom_id for decryption so the XHTML validates.
+
+ doc: python bindings howto.
+ + commit 94a95ac12364989db7f4be333107f3c023551857
+ * Promoted final encryption example so that it will appear as heading
+ 6.1.3 when exported to HTML or PDF.
+
+ doc: python bindings howto.
+ + commit 3d0c7a2202c8e9bd4f284fd00069d34b8d3d3d4c
+ * Fixed a minor typographic error.
+ * Bumped version number in preparation for merge with master.
+ * While there are probably a few more things worthy of being added
+ (mainly how to revoke things), this document is essentially ready
+ for publication now.
+
+ doc: python bindings howto.
+ + commit 961aea212ef48914ecbfa169addf951b0854b0b4
+ * Added key signing.
+
+ doc: python bindings howto.
+ + commit 7ac65b10837740caf68cdade791b8c5ce4eb1b03
+ * Added a new user ID for Danger Mouse.
+ * Removed the empty entry for key preferences since that is handled
+ through gpg.conf and/or editing the key directly.
+
+ doc: python bindings howto.
+ + commit 9e3e4a835c64f5d06de821b1fd648af37827ff26
+ * Spell checking and fixing the few errors.
+
+ doc: python bindings howto.
+ + commit b02d9d0a7b96b186eb3063d94bde369339181461
+ * Added an encryption subkey to Danger Mouse's primary key.
+
+ doc: python bindings howto.
+ + commit 5432e5f9d1dfc02812d0b181f8d88cdf4a2bfbfb
+ * generated a new primary key for Danger Mouse in an alternative homedir.
+
+ doc: python bindings howto.
+ + commit 5d1dd2abe5cf787875d12afe46c78c75385d7b31
+ * Added sections for key generation and key editing.
+
+ doc: python bindings howto.
+ + commit 1d05e6aa4ea467c8c5926b827cfcfba357d03312
+ * Added c.get_key instructions and examples.
+
+ doc: python bindings howto.
+ + commit b35aaef7a3b793b8f6f5b42596c0a6a51e87f78c
+ * Added text for verifying signatures.
+
+2018-03-14 Ben McGinnes <ben@adversary.org>
+
+ doc: python bindings howto.
+ + commit 6bc12a0eeb20409770cb8b923d08c18c2b730cb8
+ * Added 4 signature verification methods and partial text for them.
+
+ doc: python bindings howto.
+ + commit e5c85fba25de1187949697e2dae0e89345b71e89
+ * Added description for detached signatures.
+
+ doc: python bindings howto.
+ + commit ada059b07178147821b1598c935aa70ae45e3e6c
+ * Fixed multiple sample code examples of writing output to a file.
+ * Added the description of detached signatures.
+
+2018-03-14 Werner Koch <wk@gnupg.org>
+
+ core: Import cJSON code from the payproc project.
+ + commit 8eb08b318913644d918002f3195f7ec0e75ae239
+ * src/cJSON.c: New.
+ * src/cJSON.h: New.
+ * src/cJSON.readme: New.
+
+2018-03-14 Ben McGinnes <ben@adversary.org>
+
+ doc: python bindings todo.
+ + commit ef27f3781a37e264d0eb7d1745eb2c804ec062c4
+ * minor phrasing fix.
+
+ doc: python bindings howto.
+ + commit 423fdcd4653cb01f07f2b0e72cfcf49554930f70
+ * Added recommended method of single encryption with description.
+
+2018-03-13 Ben McGinnes <ben@adversary.org>
+
+ doc: python binding howto.
+ + commit a71205dc3b58970adf591b4e4553824a33f353db
+ * Clarified which English dialects this is written in.
+ * Translating to American can happen *after* it's done.
+ ** The Yank version would probably want to change some of the examples
+ anyway.
+ * Began the description for normal/default signing.
+
+ doc: python bindings howto.
+ + commit a10dcb4f138eb5a21881cdbc4806c25129d4ae4e
+ * Added a section on key selection.
+ * Included recommendation for using fingerprint when selecting one
+ specific key.
+ * Also included the most ironically amusing example of multiple key
+ selection in a GPG guide. Hey, it's public data ... (heh).
+
+ doc: python bindings howto.
+ + commit 952b6042f78017c476452088261af8d352cfa729
+ * Added explanation of the ascendance of Python 3 over Python 2 in the
+ guide to the intro.
+ * Expanded key selection description so people know what not to
+ include regarding key IDs with this key selection method.
+
+ doc: python bindings howto.
+ + commit c92da2c7eb148ce9fb06495a8470dd9caf662f9a
+ * Added key selection for specifying signing key or keys.
+
+ doc: python bindings howto.
+ + commit e489ddd08af29fdad8db8aa0aec0c314daa3678c
+ * During the course of working out the updated signature methods,
+ determined that key selection (including counting) will beed to be
+ presented before the basic functions.
+ * Moved "working with keys" up.
+
+ doc: python bindings howto.
+ + commit f29bda8d7146b4bc0bf73d6e613131545ff86b73
+ * Signatures have changed as a result of the recent update from Justus.
+ * Sample code updated.
+ * Text to follow later.
+
+ doc: python bindings howto.
+ + commit c27a7a3f994dad0eccee890185582f4350fbf233
+ * Added text description for the decryption example.
+
+2018-03-12 Ben McGinnes <ben@adversary.org>
+
+ doc: python bindings howto.
+ + commit f81adeba992a9fd3b5a199e9a2e242a0f53cf639
+ * Added a miscellaneous work-arounds section at the end.
+ * Included code in said miscellaneous section for accessing the groups
+ specified in a gpg.conf file.
+ * It's a bit ugly since it does require subprocess (but not call,
+ Popen or shell access and only accesses one command).
+
+ doc: python bindings howto.
+ + commit 36dfbdffea60c529a6d1e1ff3e507be016b6a0f6
+ * Fixed a spelling error in the key counting text.
+
+ doc: python bindings howto.
+ + commit 484e9a6229ac9c80c6be4df638bce711f08a74c6
+ * updated multi-encryption final example to be complete.
+ * second example shows most likely method of reading plaintext.
+ * updated example filenames to stick with running gag
+ (i.e. secret_plans.txt).
+
+ doc: python bindings howto.
+ + commit a8f48b6f577d562c25fd0191c0cc2cc8e96078c1
+ * error corrections.
+ * multiple typesetting fixes only required due to certain archaic
+ eccentricities of LaTeX.
+ * a couple of minor python PEP8 compliance corrections.
+
+ doc: python bindings howto.
+ + commit 83b1336ceebb86e13a55bbf220df2d750f6b3ec6
+ * Fixed an error in the encryption try/except statement.
+
+ doc: python bindings howto.
+ + commit 0e1300ce777dd0c87f31ac8bc49846b9df242df9
+ * Added a more complicated encryption example with a few variations on
+ the encryption method to account for untrusted recipient keys,
+ signing or not signing, including or excluding default keys and so
+ on.
+
+ doc: python bindings howto.
+ + commit 7ebc5a357057d01b7ef965521ab68b7cb7e20a8f
+ * Switched from links to some external docs to using footnotes where
+ necessary.
+ * Ideally the howto should be as stand alone as possible.
+ * Also it makes it difficult to convert to another format for
+ proof-reading if there are links that the conversion can't find.
+
+2018-03-09 Ben McGinnes <ben@adversary.org>
+
+ doc: python bindings HOWTO.
+ + commit 172baaf4d3e4ed03a4d3437be9efa3dfe6a847bc
+ * Added instructions and code to count the number of public and secret
+ keys available since it was quick and easy.
+
+ doc: python TODO list.
+ + commit f2c1e8d8d54068a7f072efa178fc30460821eff3
+ * Slightly tweaked one heading to make it clear it wasn't a duplicate.
+
+ doc: python bindings howto.
+ + commit 01686463948ac6096dd8579a110c478d3a1f9a83
+ * Wrote the text description explaining each step in the most basic
+ encryption operation.
+ * Will need to include additional examples for encrypting to multiple
+ recipients using Context().encrypt instead of Context().op_encrypt.
+
+ doc: python bindings TODO list.
+ + commit 93252df9dc4c9932467814745655350a8cab900e
+ * Updated to reflect the most recent work on the HOWTO for the Python
+ bindings.
+
+ doc: python bindings howto.
+ + commit ab81c2d868bba79fdb8f8d7f576b6bd88c6bdf3c
+ * Added example for verifying both detached and "in-line" signatures.
+
+2018-03-08 Ben McGinnes <ben@adversary.org>
+
+ docs: TODO.
+ + commit e846c3daeeb4e7092169cdb7bf4f55e0b105aac3
+ * Removed WS.
+
+ doc: TODO list update.
+ + commit 6849924ffbd48ba3f9d32b4a59a02e1d2083fc19
+ * Closed off a few ancient items and added recommendation to others to
+ use the dev.gnupg.org site for real bugs/features updates.
+ * See also this statement on the gnupg-devel list regarding this file:
+ https://lists.gnupg.org/pipermail/gnupg-devel/2018-March/033499.html
+
+ docs: python bindings howto update.
+ + commit fa4927146b68dd045903285f1c45fb64deb2e361
+ * Added all four signing code examples that are most likely to be
+ used: armoured, clearsigned, detached armoured and detached binary.
+ * May remove some examples and just discuss the differences, but it
+ depends on the way the text is filled out.
+
+ doc: python bindings howto update.
+ + commit c767a4a3590bd8a224d0268746df443942cb28c2
+ * Added example of decryption.
+ * included some quick notes for myself regarding aspects to explain
+ when I flesh out the explanatory text.
+
+ doc: Basic operation of the python bindings.
+ + commit 75463d589522cba427f9e5a3a408192ffad8bb21
+ * Added sample code for encrypting some text to a single key.
+ * Basically I'm just lifting existing production code and changing the
+ key IDs from mine to "0x12345678DEADBEEF" for these first few
+ examples.
+ * I'll fill in the text description after.
+ * Note: due to my regional location, I might split some tasks into
+ more commits in order to be sure no work gets lost in case of
+ emergency (or to put it another way: I know Telstra too well to
+ trust them).
+
+ doc-howto: fundamental aspects of GPGME vs Python.
+ + commit a98f2c556fe6e33a9cd38279e64e4b09f05cc675
+ * Added a section for those pythonistas who are too used to web
+ programming. Stressed that it's not simply not RESTful, it's not
+ even REST-like.
+ * Letting me move on to drawing a very loose parallel between a
+ session and a context. The differences should become obvious in the
+ subsequent sections.
+
+ doc: Added multiple TODOs for inclusion in the HOWTO.
+ + commit e8adab68f8c0cd865ff220f06dfaff7fe183e8a1
+ * Some instructions to include are fairly obvious; as with encryption,
+ decryption and signature verification.
+ * Some are a little less obvious.
+ * This includes the requests received to specifically include subkey
+ management (adding and revoking subkeys on a primary key that's
+ being retained.
+ * Added the UID equivalents to the list, as well as key selection
+ matters (and may or may not include something for handling group
+ lines since that involves wrapping a CLI binary).
+ * Key control documentation and examples requested by Mike Ingle of
+ confidantmail.org.
+
+2018-03-07 Ben McGinnes <ben@adversary.org>
+
+ GPL compatible license for documentation.
+ + commit 47d401d159852ea08e90af21d91bb4b93be9000d
+ * Added the same, slightly modified GPL based license that is used in
+ other parts of GnuPG.
+
+ HOWTO update.
+ + commit 8a76deb11efd7dadfde6e8e7e69fbcd92577982f
+ * removed one bit of whitespace.
+ * Marked up references to gpgme.h.
+ * Fixed one spelling error.
+ * Removed py2.6 from python search order since even if it is
+ supported, it shouldn't be encouraged.
+
+ GPGME Python bindings HOWTO.
+ + commit 5215d58ae2521d81c3db0b45dfbdce01a679acab
+ * Started work on the GPGME Python bindings HOWTO.
+ * 1,050 words to begin with at approx. 7.5KB.
+ * Got as far as installation.
+ * Includes instruction not to use PyPI for this.
+
+ TODO - HOWTO.
+ + commit 8f2c0f4534ea2a07f071f360a63e877f60dc52f2
+ * Added suv-entry for the new HOWTO being started and, since it has
+ been started, checked it off.
+
+ TODO.
+ + commit d4778bb23d0817ee6fbcbe4f0ff0ff0429bf3669
+ * Slightly expanded the list.
+
+ copyright fix.
+ + commit 3a746d5d46ffd7d332dc24fd6a4d24efc5fc1230
+ * Made the copyright line a new top level org heading in order to
+ prevent it getting folded into other tasks which will eventually get
+ closed (so it doesn't go missing if those items are subsequently
+ archived).
+
+ Nuxed doubles.
+ + commit 13d2164cd9f313b409b2210d9e63465681cccc99
+ * Just because there's a lot of documentation which needs to be added,
+ doesn't mean it needs to be listed twice. Merged the two lists.
+
+ Removed double.
+ + commit 1516c56ee4da28eb720bbacb026892393d10b24a
+ * default.profraw didn't need to be listed twice.
+
+2018-03-04 Ben McGinnes <ben@adversary.org>
+
+ IDENTIFY.
+ + commit f61d4f585f27c13fabf7a23ad295bdc8bea7c838
+ * Fixed sp error in docstring.
+
+2018-03-03 Ben McGinnes <ben@adversary.org>
+
+ Missed a couple.
+ + commit 75f5e6e6672a1bbd16b7680313c0f96796c219bd
+ * WS indicated 2 custom-ids were missed, now they're set.
+
+ TODO DONE.
+ + commit b438e5e44c2eaf22549db94141a3ec8731556674
+ * Marked off a TODO for this clean-up.
+
+ TODO.
+ + commit 1d910672539686e2e17fd8fa1a894cee92863417
+ * WS removal
+
+ TODO updates.
+ + commit 12a87af1df906744a14079ff7ff88e7d60679695
+ * Updated TODO with tags to make everything appear properly when
+ exported to HTML or PDF.
+ * Added a couple more items, mainly to do with docs or future bindings.
+ * Marked some, but not all as actual TODO items.
+ * Some items should probably be removed, but haven't been yet.
+ * Some have probably been completed already.
+
+2018-02-27 Ben McGinnes <ben@adversary.org>
+
+ New stuff.
+ + commit 85bdca3b2b095afb672f19abbffccd2bcb8bbd0a
+ * Added the idea for alternative Emacs bindings (to extend the
+ existing ones, not replace them outright).
+ * Added a reference to the API Squared part of the project.
+
+ TODO the TODO.
+ + commit 8047e1374fe6e69e8c4502e58e6522ea86e4bef4
+ * Added an actual TODO to fix the TODOs.
+ * Pretty sure I know who will be completing this one ... ;)
+
+ TODO ... the TODO.
+ + commit 73c51bc9858de2aab25844e7e283a6334038ccc8
+ * If we're going to use Org, let's actually use Org.
+ * Added the properties tags for each point.
+ * Some of thems still need custom ID tags assigned properly.
+ * Probably ought to make them actual TODOs at some point, but that can
+ wait until they can be marked as DONE anyway.
+ * Will add a TODO for some of this stuff ... oh, the irony.
+
+2018-02-27 NIIBE Yutaka <gniibe@fsij.org>
+
+ core: Support non-thread-safe getenv.
+ + commit 59fe3f26c1ca0fba16f76738cd05aaf80fb735ef
+ * src/get-env.c (_gpgme_getenv): Use gpgrt_lock_lock
+ and gpgrt_lock_unlock to protect call of getnev.
+
+2018-02-26 Ben McGinnes <ben@adversary.org>
+
+ WS removal.
+ + commit c58f61e92226c4a03f216f5d07bdc5479ce8a2d9
+ * Whitespace removal.
+
+ LaTeX headers.
+ + commit 6f2e2e0f150d5c6d53de5bc48af137f7864d5fd9
+ * Set LaTeX headers to enable ligatures and a 12pt font by default.
+ * Paper size left for regional defaults.
+ * Using XeLaTeX for easier font control.
+ * Using default LaTeX font of Latin Main, but that's easy enough to change.
+
+2018-02-19 Ben McGinnes <ben@adversary.org>
+
+ Renaming ad infinitum ...
+ + commit 272a8e778a959cb24298f488e77fce9bffd23b7a
+ * Dropped the .txt from the end of the file ...
+
+ Text conversion.
+ + commit c82b17c6ce490738efb07186532e752e6f70ea07
+ * Exported from Org Mode to UTF-8 text.
+ * Removed my name from just under the title.
+
+ Title fix.
+ + commit ea481d4bb9e6197fbc195187d1362b844e2cba2e
+ * Fixed title.
+
+ Conflict with Phabricator files.
+ + commit 1ae3ead2cd854258954e784bf51f03822321aefe
+ * The developers of Phabricator, the web front-end on dev.gnupg.org
+ have not implemented renderers for Markdown, Org-Mode or any other
+ common markdown like language.
+ * They also refuse to do so.
+ * Instead they re-invented the wheel and implemented their own version
+ of Markdown-like thing which is incompatible with everything else.
+ It is called Remarkup.
+ * The developers of Phabricator and Remarkup have refused to provide
+ conversion tools to move files to/from any format to/from Remarkup.
+ * They expect everyone to learn their new favourite pet project.
+ * Remarkup may or may not display Org Mode files, but if so then it is
+ likely to only want to do so as plain text.
+ * There is an unaffiliated and unofficial project to convert Github
+ Markdown to Remarkup via Pandoc. This might be adapted for our use,
+ but requires testing.
+ * Until then exporting from Org Mode to UTF-8 text is likely the least
+ worst plan.
+ * Which means renaming this file to README.org first.
+
+ Schizophrenic file types.
+ + commit fe4f3edd70949329cb992dd963de2de3c86dcd81
+ * Removed Markdown style heading underlining.
+ * Removed in-line file type declaration (which is not correctly parsed
+ by the web interface on dev.gnupg.org).
+
+2018-02-16 Andre Heinecke <aheinecke@intevation.de>
+
+ cpp: Add shorthand for key locate.
+ + commit 7f9d5c6cd204bfd84ea477b284df795b1dadb1af
+ * lang/cpp/src/key.cpp (Key::locate): New static helper.
+ * lang/cpp/src/key.h: Update accordingly.
+
+2018-02-16 Ben McGinnes <ben@adversary.org>
+
+ History path.
+ + commit fb16eaa685fe488f12f4df9b59d1f3689c813034
+ * Fixed a typo in a filepath reference.
+ * Moved conjecture regarding the first version of Python used to a
+ footnote.
+
+2018-02-15 Ben McGinnes <ben@adversary.org>
+
+ LaTeX margins.
+ + commit 6f15d821404742ac2683f54ca4102ee4aaedacf2
+ * Added LaTeX header for 1 inch margins in the quite likely event that
+ all PDF output ultimately uses LaTeX.
+
+ TODO Documentation.
+ + commit 235d899a5fc24cdf9c856adbc021a69c43985c99
+ * Checked off the decision to stick with Org Mode.
+
+ TODO.
+ + commit 40da5022922172ed898172956a8ccf5622e5638d
+ * Beginning to turn the first part of this into something kind of like
+ an actual TODO list as Org Mode uses it (maybe).
+
+2018-02-15 NIIBE Yutaka <gniibe@fsij.org>
+
+ tests: Fix previous commit.
+ + commit 3224d7f0ea83a3c2baaa9f97846c4a5b392d2c59
+
+
+ tests: More Makefile portability.
+ + commit ba6e610baa138ba9b43be303df2c5981dd04de5a
+ * tests/gpg/Makefile.am: Invoke GPG with TESTS_ENVIRONMENT.
+
+ tests: Makefile portability.
+ + commit b5ec21b9baf017b4cee88c9ef3cc1a638547cd20
+ * tests/gpg/Makefile.am: Don't use "export" directive.
+ * tests/gpgsm/Makefile.am: Ditto.
+ * lang/qt/tests/Makefile.am: Ditto.
+ * lang/python/tests/Makefile.am: Ditto.
+
+ build: More Makefile fix.
+ + commit c9a351f5af289c8f6919854c40f235c781b76ec7
+ * lang/python/tests/Makefile.am: Avoid target with '/'.
+
+2018-02-14 Ben McGinnes <ben@adversary.org>
+
+ Short History.
+ + commit 3c3b149996036e7ff4cc4c77ef2d97062d880409
+ * Fixed or updated the most fundamental errors.
+ * Also included some details on which modules are available on PyPI,
+ as well as what happened to the PyME commit log.
+
+ Subsectioned history.
+ + commit 7c662d22a8f7d2e6ad6532014f2ecc1769de16fb
+ * Split the main parts down into subsections.
+ * Still need to cull the incorrect stuff towards the end and add more
+ recent changes.
+
+ History.
+ + commit a1bc710c5fb7a7d2253434c1443e33e019020a55
+ * Reshaping the history file to fit Org Mode's structuring for docs.
+ * Also said history needs to be a bit more clear (it was kind of
+ unfinished).
+
+ TODO.
+ + commit fccd2ea3871f5d63fb038db0733a34f9c5d550c3
+ * Updated TODO.
+ * The entirety of the old TODO has been replaced with either more
+ relevant tasks or goals for the examples and a more measured
+ approach to the docs and why, in this project, Org Mode trumps reST,
+ even though it's Python through and through.
+
+ TODO.
+ + commit 487ed9337e8e07d1c63e53b785cc39e3bd35ff6e
+ * Removed reST version of file.
+
+ TODO.
+ + commit c4fa4216199b16c1f169725c0a1e0a40764b1ebb
+ * Converted document from reST to org-mode.
+
+ Short History.
+ + commit 1d48b04cfb3d1de654f3995578e9434a6b7b2fed
+ * Removed reST version.
+
+ Short History.
+ + commit d86fd7c54c462ef23c70370624e07fcc1bc15121
+ * Converted document from reST to org-mode.
+
+ House keeping.
+ + commit 1b5719cd57d80dcd9577141491a0860912e74cd4
+ * Added a bunch of things to .gitignore that might otherwise creep in
+ during Python development.
+ * This really should be merged ASAP. You'll thank me later ...
+
+2018-02-14 NIIBE Yutaka <gniibe@fsij.org>
+
+ build: Fix Makefiles for portability.
+ + commit f1d8a7975b0a166f55aef06eb25d50230781b96f
+ * tests/gpg/Makefile.am: Don't allow target with '/'.
+ * tests/gpgsm/Makefile.am: Ditto.
+
+2018-02-13 Andre Heinecke <aheinecke@intevation.de>
+
+ configure: Fix mingw check for getenv.
+ + commit 5ec890b9c76db0f23cc396108ff6f1fe658855a8
+ * configure.ac: have_thread_safe_getenv=yes with have_w32_system.
+
+2018-02-13 NIIBE Yutaka <gniibe@fsij.org>
+
+ configure: MinGW has thread-safe getenv.
+ + commit 77ca9cc2db2c6da303b9224a931679a325ebda1e
+ * configure.ac: have_thread_safe_getenv=yes with have_w64_system.
+
+2018-02-09 Andre Heinecke <aheinecke@intevation.de>
+
+ cpp: Add SpawnShowWindow flag.
+ + commit 7e27a0ff64626026521dc5877b278794cea72e61
+ * lang/cpp/src/context.h (SpawnShowWindow): New.
+
+ core, w32: Enable spawning GUI applications.
+ + commit 201db83a7f1b7759173b6e9f0a844caef4da6cce
+ * src/engine-spawn.c (engspawn_start): Translate spawn flag
+ to IOSPAWN flag.
+ * src/gpgme-w32spawn.c (my_spawn): Handle the new flag.
+ * src/gpgme.h.in (GPGME_SPAWN_SHOW_WINDOW): New.
+ * src/priv-io.h (IOSPAWN_FLAG_SHOW_WINDOW): New.
+
+ core, w32: Fix flags passing to gpgme-w32-spawn.
+ + commit f10605ffb5cc9d457c3e432918fdfbfaf3d04185
+ * src/w32-io.c (_gpgme_io_spawn): Don't hardcode flags value.
+
+ cpp: Add conveniance Data::toString.
+ + commit 5a5b0d4996c17bfbc69b90f89fec23732f92813a
+ * lang/cpp/src/data.h, lang/cpp/src/data.cpp: Add Data::toString.
+
+2018-01-30 NIIBE Yutaka <gniibe@fsij.org>
+
+ Fix for BSD Make.
+ + commit 59fcabbdf537b2745ef0c3cae908b21970a5b39b
+ * tests/gpg/Makefile.am, tests/gpgsm/Makefile.am: Remove ./.
+
+2018-01-29 NIIBE Yutaka <gniibe@fsij.org>
+
+ Fix compile error message.
+ + commit bbb5e70e7e8598978b6c61b13ba77705ff86e469
+ * src/get-env.c (_gpgme_getenv): Fix error message.
+
+ tests: Fix for NetBSD.
+ + commit 58130b97f6582455fd355ac58ae3182a28812cfc
+ * tests/gpg/pinentry: Use /bin/sh instead of Bash.
+
+ core: Implement _gpgme_getenv for NetBSD.
+ + commit 37d62e9d0f685c257fdb5f303e60ff01f8a36a2f
+ * src/get-env.c [HAVE_GETENV_R] (_gpgme_getenv): New.
+
2017-12-12 Werner Koch <wk@gnupg.org>
Release 1.10.0.
diff --git a/NEWS b/NEWS
index 879d1af..b7c091c 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,65 @@
+Noteworthy changes in version 1.11.0 (2018-04-18)
+-------------------------------------------------
+
+ * New encryption API to support direct key specification including
+ hidden recipients option and taking keys from a file. This also
+ allows to enforce the use of a subkey.
+
+ * New encryption flag for the new API to enforce the use of plain
+ mail addresses (addr-spec).
+
+ * The import API can now tell whether v3 keys are skipped. These old
+ and basically broken keys are not anymore supported by GnuPG 2.1.
+
+ * The decrypt and verify API will now return the MIME flag as
+ specified by RFC-4880bis.
+
+ * The offline mode now has an effect on gpg by disabling all network
+ access. [#3831]
+
+ * A failed OpenPGP verification how returns the fingerprint of the
+ intended key if a recent gpg version was used for signature
+ creation.
+
+ * New tool gpgme-json as native messaging server for web browsers.
+ As of now public key encryption and decryption is supported.
+ Requires Libgpg-error 1.29.
+
+ * New context flag "request-origin" which has an effect when used
+ with GnuPG 2.2.6 or later.
+
+ * New context flag "no-symkey-cache" which has an effect when used
+ with GnuPG 2.2.7 or later.
+
+ * New convenience constant GPGME_KEYLIST_MODE_LOCATE.
+
+ * Improved the Python documentation.
+
+ * Fixed a potential regression with GnuPG 2.2.6 or later.
+
+ * Fixed a crash in the Python bindings on 32 bit platforms. [#3892]
+
+ * Various minor fixes.
+
+ * Interface changes relative to the 1.10.0 release:
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ gpgme_op_encrypt_ext NEW.
+ gpgme_op_encrypt_ext_start NEW.
+ gpgme_op_encrypt_sign_ext NEW.
+ gpgme_op_encrypt_sign_ext_start NEW.
+ GPGME_ENCRYPT_WANT_ADDRESS NEW.
+ GPGME_KEYLIST_MODE_LOCATE NEW.
+ gpgme_import_result_t EXTENDED: New field 'skipped_v3_keys'.
+ gpgme_decrypt_result_t EXTENDED: New field 'symkey_algo'.
+ gpgme_decrypt_result_t EXTENDED: New field 'is_mime'.
+ gpgme_verify_result_t EXTENDED: New field 'is_mime'.
+ cpp: Key::locate NEW.
+ cpp: Data::toString NEW.
+ cpp: ImportResult::numV3KeysSkipped NEW.
+
+ [c=C31/A20/R0 cpp=C12/A6/R0 qt=C10/A3/R1]
+
+
Noteworthy changes in version 1.10.0 (2017-12-12)
-------------------------------------------------
diff --git a/README b/README
index f7b006f..8e031ae 100644
--- a/README
+++ b/README
@@ -1,7 +1,7 @@
GPGME - GnuPG Made Easy
---------------------------
-Copyright 2001-2017 g10 Code GmbH
+Copyright 2001-2018 g10 Code GmbH
This file is free software; as a special exception the author gives
unlimited permission to copy and/or distribute it, with or without
diff --git a/TODO b/TODO
index 0458cb5..a915ed7 100644
--- a/TODO
+++ b/TODO
@@ -1,58 +1,254 @@
+#+TITLE: TODO List
Hey Emacs, this is -*- org -*- mode!
-* Document all the new stuff.
+* IMPORTANT!
+ :PROPERTIES:
+ :CUSTOM_ID: dev-gnupg-org
+ :END:
+
+ There was a nine year gap (2009 to 2018) between edits of this file,
+ so it is likely that much of the old information in it is wrong or
+ no longer applicable.
+
+ Bugs, feature requests and other development related work will be
+ tracked through the [[https://dev.gnupg.org/][dev.gnupg.org]] site.
+
+
+* Documentation
+ :PROPERTIES:
+ :CUSTOM_ID: documentation
+ :END:
+
+** Document all the new stuff.
+ :PROPERTIES:
+ :CUSTOM_ID: more-docs-is-better
+ :END:
+
+*** TODO Fix this TODO list.
+ :PROPERTIES:
+ :CUSTOM_ID: fix-todo
+ :END:
+
+ Clean up the current TODO list. Include properties as relevant (so
+ if someone does make a PDF or HTML version the TOC will work).
+
+ Also check ans see if some of these ancient things can be removed
+ (e.g. do we really need to fix things that were broken in GPG
+ 1.3.x? I'm thinking not so much).
+
+**** DONE fix TODO items
+ CLOSED: [2018-03-04 Sun 08:55]
+ :PROPERTIES:
+ :CUSTOM_ID: fix-todo-items
+ :END:
+
+ Adjust todo items so each can now be referenced by custom-id and
+ checked off as necessary.
+
+** TODO Document validity and trust issues.
+ :PROPERTIES:
+ :CUSTOM_ID: valid-trust-issues
+ :END:
+
+** In gpgme.texi: Register callbacks under the right letter in the index.
+ :PROPERTIES:
+ :CUSTOM_ID: gpgme-texi
+ :END:
+
+
* Fix the remaining UI Server problems:
+ :PROPERTIES:
+ :CUSTOM_ID: ui-server-fix
+ :END:
** VERIFY --silent support.
+ :PROPERTIES:
+ :CUSTOM_ID: verify-silent
+ :END:
** ENCRYPT/DECRYPT/VERIFY/SIGN reset the engine, shouldn't be done with UISERVER?
+ :PROPERTIES:
+ :CUSTOM_ID: reset-engine-not-ui
+ :END:
+
* IMPORTANT
+ :PROPERTIES:
+ :CUSTOM_ID: important-stuff-really
+ :END:
** When using descriptor passing, we need to set the fd to blocking before
+ :PROPERTIES:
+ :CUSTOM_ID: set-fd-blocking
+ :END:
issueing simple commands, because we are mixing synchronous
commands into potentially asynchronous operations.
-** Might want to implement nonblock for w32 native backend! Right now,
- we block reading the next line with assuan.
+** Might want to implement nonblock for w32 native backend!
+ :PROPERTIES:
+ :CUSTOM_ID: nonblock-win32
+ :END:
+ Right now we block reading the next line with assuan.
+
* Before release:
-** Some gpg tests fail with gpg 1.3.4-cvs (gpg/t-keylist-sig)
+ :PROPERTIES:
+ :CUSTOM_ID: pre-release
+ :END:
+
+** CANCELLED Some gpg tests fail with gpg 1.3.4-cvs (gpg/t-keylist-sig)
+ CLOSED: [2018-03-09 Fri 08:16]
+ :PROPERTIES:
+ :CUSTOM_ID: gpg-1-3-4-really
+ :END:
+ - State "CANCELLED" from "TODO" [2018-03-09 Fri 08:16] \\
+ WON'T FIX — too old or no longer applies.
The test is currently disabled there and in gpg/t-import.
+
** When gpg supports it, write binary subpackets directly,
+ :PROPERTIES:
+ :CUSTOM_ID: binary-subpackets
+ :END:
and parse SUBPACKET status lines.
+
* ABI's to break:
+ :PROPERTIES:
+ :CUSTOM_ID: abi-breakage-apparently-on-purpose
+ :END:
+
** Old opassuan interface.
+ :PROPERTIES:
+ :CUSTOM_ID: old-opassuan
+ :END:
+
** Implementation: Remove support for old style error codes in
+ :PROPERTIES:
+ :CUSTOM_ID: remove-old-error-codes
+ :END:
conversion.c::_gpgme_map_gnupg_error.
+
** gpgme_edit_cb_t: Add "processed" return argument
+ :PROPERTIES:
+ :CUSTOM_ID: add-processed-return
+ :END:
(see edit.c::command_handler).
+
** I/O and User Data could be made extensible. But this can be done
+ :PROPERTIES:
+ :CUSTOM_ID: add-io-user-data
+ :END:
without breaking the ABI hopefully.
+
** All enums should be replaced by ints and simple macros for
+ :PROPERTIES:
+ :CUSTOM_ID: enums-should-be-ints
+ :END:
maximum compatibility.
+
** Compatibility interfaces that can be removed in future versions:
+ :PROPERTIES:
+ :CUSTOM_ID: compat-interfaces-to-go
+ :END:
+
*** gpgme_data_new_from_filepart
+ :PROPERTIES:
+ :CUSTOM_ID: gpgme-data-new-from-filepart
+ :END:
+
*** gpgme_data_new_from_file
+ :PROPERTIES:
+ :CUSTOM_ID: gpgme-data-new-from-file
+ :END:
+
*** gpgme_data_new_with_read_cb
+ :PROPERTIES:
+ :CUSTOM_ID: gpgme-data-new-with-read-cb
+ :END:
+
*** gpgme_data_rewind
+ :PROPERTIES:
+ :CUSTOM_ID: gpgme-data-rewind
+ :END:
+
*** gpgme_op_import_ext
+ :PROPERTIES:
+ :CUSTOM_ID: gpgme-op-import-ext
+ :END:
+
*** gpgme_get_sig_key
+ :PROPERTIES:
+ :CUSTOM_ID: gpgme-get-sig-key
+ :END:
+
*** gpgme_get_sig_ulong_attr
+ :PROPERTIES:
+ :CUSTOM_ID: gpgme-get-sig-ulong-attr
+ :END:
+
*** gpgme_get_sig_string_attr
+ :PROPERTIES:
+ :CUSTOM_ID: gpgme-get-sig-string-attr
+ :END:
+
*** GPGME_SIG_STAT_*
+ :PROPERTIES:
+ :CUSTOM_ID: gpgme-sig-stat
+ :END:
+
*** gpgme_get_sig_status
+ :PROPERTIES:
+ :CUSTOM_ID: gpgme-get-sig-status
+ :END:
+
*** gpgme_trust_item_release
+ :PROPERTIES:
+ :CUSTOM_ID: gpgme-trust-item-release
+ :END:
+
*** gpgme_trust_item_get_string_attr
+ :PROPERTIES:
+ :CUSTOM_ID: gpgme-trust-item-get-string-attr
+ :END:
+
*** gpgme_trust_item_get_ulong_attr
+ :PROPERTIES:
+ :CUSTOM_ID: gpgme-trust-item-get-ulong-attr
+ :END:
+
*** gpgme_attr_t
+ :PROPERTIES:
+ :CUSTOM_ID: gpgme-attr-t
+ :END:
+
*** All Gpgme* typedefs.
+ :PROPERTIES:
+ :CUSTOM_ID: all-gpgme-typedefs
+ :END:
* Thread support:
+ :PROPERTIES:
+ :CUSTOM_ID: threads
+ :END:
+
** When GNU Pth supports sendmsg/recvmsg, wrap them properly.
+ :PROPERTIES:
+ :CUSTOM_ID: wrap-oth
+ :END:
+
** Without timegm (3) support our ISO time parser is not thread safe.
+ :PROPERTIES:
+ :CUSTOM_ID: time-threads
+ :END:
There is a configure time warning, though.
+
* New features:
+ :PROPERTIES:
+ :CUSTOM_ID: new-features
+ :END:
+
** Flow control for data objects.
+ :PROPERTIES:
+ :CUSTOM_ID: flow-control-is-not-a-euphemism-for-an-s-bend
+ :END:
Currently, gpgme_data_t objects are assumed to be blocking. To
break this assumption, we need either (A) a way for an user I/O
callback to store the current operation in a continuation that can
@@ -61,9 +257,17 @@ Hey Emacs, this is -*- org -*- mode!
respective event loop. or (B) a way for gpgme data objects to be
associated with a waitable object, that can be registered with the
user event loop. Neither is particularly simple.
+
** Extended notation support. When gpg supports arbitrary binary
+ :PROPERTIES:
+ :CUSTOM_ID: extended-notation
+ :END:
notation data, provide a user interface for that.
+
** notification system
+ :PROPERTIES:
+ :CUSTOM_ID: notification-system
+ :END:
We need a simple notification system, probably a simple callback
with a string and some optional arguments. This is for example
required to notify an application of a changed smartcard, The
@@ -75,35 +279,77 @@ Hey Emacs, this is -*- org -*- mode!
sufficient for this.
** --learn-code support
+ :PROPERTIES:
+ :CUSTOM_ID: learn-code
+ :END:
This might be integrated with import. we still need to work out how
to learn a card when gpg and gpgsm have support for smartcards. In
GPA we currently invoke gpg directly.
** Might need a stat() for data objects and use it for length param to gpg.
+ :PROPERTIES:
+ :CUSTOM_ID: stat-data
+ :END:
+
** Implement support for photo ids.
+ :PROPERTIES:
+ :CUSTOM_ID: photo-id
+ :END:
+
** Allow selection of subkeys
+ :PROPERTIES:
+ :CUSTOM_ID: subkey-selection
+ :END:
+
** Allow to return time stamps in ISO format
- This allows us to handle years later than 2037 properly. With the
- time_t interface they are all mapped to 2037-12-31
+ :PROPERTIES:
+ :CUSTOM_ID: iso-format-datetime
+ :END:
+ This allows us to handle years later than 2037 properly. With the
+ time_t interface they are all mapped to 2037-12-31
+
** New features requested by our dear users, but rejected or left for
+ :PROPERTIES:
+ :CUSTOM_ID: feature-requests
+ :END:
later consideration:
+
*** Allow to export secret keys.
+ :PROPERTIES:
+ :CUSTOM_ID: export-secret-keys
+ :END:
Rejected because this is conceptually flawed. Secret keys on a
smart card can not be exported, for example.
May eventually e supproted with a keywrapping system.
+
*** Selecting the key ring, setting the version or comment in output.
+ :PROPERTIES:
+ :CUSTOM_ID: select-keyring-version
+ :END:
Rejected because the naive implementation is engine specific, the
configuration is part of the engine's configuration or readily
worked around in a different way
+
*** Selecting the symmetric cipher.
+ :PROPERTIES:
+ :CUSTOM_ID: symmetric-cipher-selection
+ :END:
+
*** Exchanging keys with key servers.
+ :PROPERTIES:
+ :CUSTOM_ID: key-server-exchange
+ :END:
-* Documentation
-** Document validity and trust issues.
-** In gpgme.texi: Register callbacks under the right letter in the index.
* Engines
+ :PROPERTIES:
+ :CUSTOM_ID: engines
+ :END:
+
** Do not create/destroy engines, but create engine and then reset it.
+ :PROPERTIES:
+ :CUSTOM_ID: reset-engine-is-not-quite-just-ignition
+ :END:
Internally the reset operation still spawns a new engine process,
but this can be replaced with a reset later. Also, be very sure to
release everything properly at a reset and at an error. Think hard
@@ -112,85 +358,255 @@ Hey Emacs, this is -*- org -*- mode!
Note that we need support in gpgsm to set include-certs to default
as RESET does not reset it, also for no_encrypt_to and probably
other options.
+
** Optimize the case where a data object has an underlying fd we can pass
+ :PROPERTIES:
+ :CUSTOM_ID: optimus-data-cousin-of-optimus-prime
+ :END:
directly to the engine. This will be automatic with socket I/O and
descriptor passing.
+
** Move code common to all engines up from gpg to engine.
+ :PROPERTIES:
+ :CUSTOM_ID: move-code-common-to-engines-out-of-gpg
+ :END:
+
** engine operations can return General Error on unknown protocol
+ :PROPERTIES:
+ :CUSTOM_ID: general-error-looking-to-be-court-martialled
+ :END:
(it's an internal error, as select_protocol checks already).
+
** When server mode is implemented properly, more care has to be taken to
+ :PROPERTIES:
+ :CUSTOM_ID: server-mode
+ :END:
release all resources on error (for example to free assuan_cmd).
-** op_import_keys and op_export_keys have a limit ion the number of keys.
+
+** op_import_keys and op_export_keys have a limit in the number of keys.
+ :PROPERTIES:
+ :CUSTOM_ID: import-export-problems
+ :END:
This is because we pass them in gpg via the command line and gpgsm
via an assuan control line. We should pipe them instead and maybe
change gpg/gpgsm to not put them in memory.
+
* GPG breakage:
-** gpg 1.4.2 lacks error reporting if sign/encrypt with revoked key.
-** gpg 1.4.2 does crappy error reporting (namely none at all) when
+ :PROPERTIES:
+ :CUSTOM_ID: gpg-breakage
+ :END:
+
+** CANCELLED gpg 1.4.2 lacks error reporting if sign/encrypt with revoked key.
+ CLOSED: [2018-03-09 Fri 08:19]
+ :PROPERTIES:
+ :CUSTOM_ID: gpg-classic-lacks-stuff
+ :END:
+ - State "CANCELLED" from "TODO" [2018-03-09 Fri 08:19] \\
+ WON'T FIX.
+
+** CANCELLED gpg 1.4.2 does crappy error reporting (namely none at all) when
+ CLOSED: [2018-03-09 Fri 08:20]
+ :PROPERTIES:
+ :CUSTOM_ID: gpg-classic-problems-but-do-we-care
+ :END:
+ - State "CANCELLED" from "TODO" [2018-03-09 Fri 08:20] \\
+ WON'T FIX.
smart card is missing for sign operation:
[GNUPG:] CARDCTRL 4
gpg: selecting openpgp failed: ec=6.110
gpg: signing failed: general error
[GNUPG:] BEGIN_ENCRYPTION 2 10
gpg: test: sign+encrypt failed: general error
-** Without agent and with wrong passphrase, gpg 1.4.2 enters into an
+
+** DONE Without agent and with wrong passphrase, gpg 1.4.2 enters into an
+ CLOSED: [2018-03-09 Fri 08:20]
+ :PROPERTIES:
+ :CUSTOM_ID: recursive-gpg-classic
+ :END:
+ - State "DONE" from "TODO" [2018-03-09 Fri 08:20] \\
+ Must have been fixed in a subsequent release.
infinite loop.
-** Use correct argv[0]
+
+** CANCELLED Use correct argv[0]
+ CLOSED: [2018-03-09 Fri 08:24]
+ :PROPERTIES:
+ :CUSTOM_ID: correct-argv
+ :END:
+ - State "CANCELLED" from "TODO" [2018-03-09 Fri 08:24] \\
+ WON'T FIX.
+
+ Also, there is no rungpg.c file in GPGME (or in GPG or most, if not
+ all of the rest of the libs and packages; I suspect there hasn't been
+ for a very long time).
In rungpg.c:build_argv we use
argv[argc] = strdup ("gpg"); /* argv[0] */
This should be changed to take the real file name used in account.
* Operations
+ :PROPERTIES:
+ :CUSTOM_ID: operations-are-not-surgical
+ :END:
+
** Include cert values -2, -1, 0 and 1 should be defined as macros.
+ :PROPERTIES:
+ :CUSTOM_ID: certified-macros
+ :END:
+
** If an operation failed, make sure that the result functions don't return
+ :PROPERTIES:
+ :CUSTOM_ID: operation-failure
+ :END:
corrupt partial information. !!!
NOTE: The EOF status handler is not called in this case !!!
+
** Verify must not fail on NODATA premature if auto-key-retrieval failed.
+ :PROPERTIES:
+ :CUSTOM_ID: autobot-key-retrieval
+ :END:
It should not fail silently if it knows there is an error. !!!
+
** All operations: Better error reporting. !!
+ :PROPERTIES:
+ :CUSTOM_ID: better-reporting-not-like-fox-news
+ :END:
+
** Export status handler need much more work. !!!
+ :PROPERTIES:
+ :CUSTOM_ID: export-status-handler
+ :END:
+
** Import should return a useful error when one happened.
+ :PROPERTIES:
+ :CUSTOM_ID: import-useful-stuff-even-wrong-stuff
+ :END:
+
*** Import does not take notice of NODATA status report.
+ :PROPERTIES:
+ :CUSTOM_ID: import-no-data
+ :END:
+
*** When GPGSM does issue IMPORT_OK status reports, make sure to check for
+ :PROPERTIES:
+ :CUSTOM_ID: gpgsm-import-ok
+ :END:
them in tests/gpgs m/t-import.c.
+
** Verify can include info about version/algo/class, but currently
+ :PROPERTIES:
+ :CUSTOM_ID: verify-class
+ :END:
this is only available for gpg, not gpgsm.
+
** Return ENC_TO output in verify result. Again, this is not available
+ :PROPERTIES:
+ :CUSTOM_ID: return-to-enc
+ :END:
for gpgsm.
+
** Genkey should return something more useful than General_Error.
+ :PROPERTIES:
+ :CUSTOM_ID: general-key-assumed-command-from-general-error
+ :END:
+
** If possible, use --file-setsize to set the file size for proper progress
+ :PROPERTIES:
+ :CUSTOM_ID: file-setsize
+ :END:
callback handling. Write data interface for file size.
+
** Optimize the file descriptor list, so the number of open fds is
+ :PROPERTIES:
+ :CUSTOM_ID: optimus-descriptus-younger-brother-of-optimus-prime
+ :END:
always known easily.
+
** Encryption: It should be verified that the behaviour for partially untrusted
+ :PROPERTIES:
+ :CUSTOM_ID: only-mostly-dead-means-partially-alive
+ :END:
recipients is correct.
+
** When GPG issues INV_something for invalid signers, catch them.
+ :PROPERTIES:
+ :CUSTOM_ID: invalid-sig
+ :END:
+
* Error Values
+ :PROPERTIES:
+ :CUSTOM_ID: error-value
+ :END:
+
** Map ASSUAN/GpgSM ERR error values in a better way than is done now. !!
+ :PROPERTIES:
+ :CUSTOM_ID: map-ass-error
+ :END:
+
** Some error values should identify the source more correctly (mostly error
+ :PROPERTIES:
+ :CUSTOM_ID: source-errors
+ :END:
values derived from status messages).
+
** In rungpg.c we need to check the version of the engine
+ :PROPERTIES:
+ :CUSTOM_ID: rungpg-c-engine-ver
+ :END:
This requires a way to get the cached version number from the
engine layer.
* Tests
-** Write a fake gpg-agent so that we can supply known passphrases to
+ :PROPERTIES:
+ :CUSTOM_ID: tests
+ :END:
+
+** TODO Write a fake gpg-agent so that we can supply known passphrases to
+ :PROPERTIES:
+ :CUSTOM_ID: test-fake-gpg-agent
+ :END:
gpgsm and setup the configuration files to use the agent. Without
this we are testing a currently running gpg-agent which is not a
clever idea. !
+
** t-data
+ :PROPERTIES:
+ :CUSTOM_ID: test-data
+ :END:
+
*** Test gpgme_data_release_and_get_mem.
+ :PROPERTIES:
+ :CUSTOM_ID: test-gpgme-data-release-mem
+ :END:
+
*** Test gpgme_data_seek for invalid types.
+ :PROPERTIES:
+ :CUSTOM_ID: test-gpgme-data-seek
+ :END:
+
** t-keylist
+ :PROPERTIES:
+ :CUSTOM_ID: test-keylist
+ :END:
Write a test for ext_keylist.
+
** Test reading key signatures.
+ :PROPERTIES:
+ :CUSTOM_ID: test-key-sig
+ :END:
+
* Debug
+ :PROPERTIES:
+ :CUSTOM_ID: debug
+ :END:
+
** Tracepoints should be added at: Every public interface enter/leave,
+ :PROPERTIES:
+ :CUSTOM_ID: tracepoint-pub-int
+ :END:
before and in every callback, at major decision points, at every
internal data point which might easily be observed by the outside
(system handles). We also trace handles and I/O support threads in
@@ -202,21 +618,83 @@ Hey Emacs, this is -*- org -*- mode!
decrypt-verify.c delete.c edit.c encrypt.c encrypt-sign.c export.c
genkey.c import.c key.c keylist.c passphrase.c progress.c signers.c
sig-notation.c trust-item.c trustlist.c verify.c
-** Handle malloc and vasprintf errors. But decide first if they should be
+
+** TODO Handle malloc and vasprintf errors. But decide first if they should be
+ :PROPERTIES:
+ :CUSTOM_ID: malloc-vasprintf
+ :END:
+
ignored (and logged with 255?!), or really be assertions. !
+
* Build suite
-** Make sure everything is cleaned correctly (esp. test area).
-** Enable AC_CONFIG_MACRO_DIR and bump up autoconf version requirement.
+ :PROPERTIES:
+ :CUSTOM_ID: build-suite
+ :END:
+
+** TODO Make sure everything is cleaned correctly (esp. test area).
+ :PROPERTIES:
+ :CUSTOM_ID: clean-tests
+ :END:
+
+** TODO Enable AC_CONFIG_MACRO_DIR and bump up autoconf version requirement.
+ :PROPERTIES:
+ :CUSTOM_ID: autoconf-macros
+ :END:
(To fix "./autogen.sh; ./configure --enable-maintainer-mode; touch
configure.ac; make"). Currently worked around with ACLOCAL_AMFLAGS???
+
* Error checking
-** engine-gpgsm, with-validation
+ :PROPERTIES:
+ :CUSTOM_ID: error-checking
+ :END:
+
+** TODO engine-gpgsm, with-validation
+ :PROPERTIES:
+ :CUSTOM_ID: gpgsm-validation
+ :END:
Add error checking some time after releasing a new gpgsm.
-Copyright 2004, 2005 g10 Code GmbH
+* Language bindings and related components
+ :PROPERTIES:
+ :CUSTOM_ID: language-bindings-and-related-stuff
+ :END:
+
+** TODO Emacs and elisp binding
+ :PROPERTIES:
+ :CUSTOM_ID: emacs-and-elisp
+ :END:
+
+ Currently GNU Emacs uses EPA and EPG to provide GnuPG support. EPG
+ does this by calling the GPG executable and wrapping the commands
+ with elisp functions. A more preferable solution would be to
+ implement an epgme.el which integrated with GPGME, then if it could
+ not to attempt calling the gpgme-tool and only if those failed to
+ fall back to the current epg.el and calling the command line
+ binaries.
+
+** TODO API of an API
+ :PROPERTIES:
+ :CUSTOM_ID: api-squared
+ :END:
+
+ See the more detailed notes on this in the [[lang/python/docs/TODO.org][python TODO]].
+
+** TODO GPGME installation and package management guide
+ :PROPERTIES:
+ :CUSTOM_ID: package-management
+ :END:
+
+ Write a guide/best practices for maintainers of GPGME packages with
+ third party package management systems.
+
+
+* Copyright 2004, 2005, 2018 g10 Code GmbH
+ :PROPERTIES:
+ :CUSTOM_ID: copyright-and-license
+ :END:
This file is free software; as a special exception the author gives
unlimited permission to copy and/or distribute it, with or without
diff --git a/VERSION b/VERSION
index 81c871d..1cac385 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.10.0
+1.11.0
diff --git a/config.h.in b/config.h.in
index 276dbef..d388ae5 100644
--- a/config.h.in
+++ b/config.h.in
@@ -281,5 +281,5 @@
#define GPG_ERR_ENABLE_ERRNO_MACROS 1
#define CRIGHTBLURB "Copyright (C) 2000 Werner Koch\n" \
- "Copyright (C) 2001--2017 g10 Code GmbH\n"
+ "Copyright (C) 2001--2018 g10 Code GmbH\n"
diff --git a/configure b/configure
index 3584980..035a97f 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for gpgme 1.10.0.
+# Generated by GNU Autoconf 2.69 for gpgme 1.11.0.
#
# Report bugs to <http://bugs.gnupg.org>.
#
@@ -590,8 +590,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='gpgme'
PACKAGE_TARNAME='gpgme'
-PACKAGE_VERSION='1.10.0'
-PACKAGE_STRING='gpgme 1.10.0'
+PACKAGE_VERSION='1.11.0'
+PACKAGE_STRING='gpgme 1.11.0'
PACKAGE_BUGREPORT='http://bugs.gnupg.org'
PACKAGE_URL=''
@@ -1457,7 +1457,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures gpgme 1.10.0 to adapt to many kinds of systems.
+\`configure' configures gpgme 1.11.0 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1527,7 +1527,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of gpgme 1.10.0:";;
+ short | recursive ) echo "Configuration of gpgme 1.11.0:";;
esac
cat <<\_ACEOF
@@ -1677,7 +1677,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-gpgme configure 1.10.0
+gpgme configure 1.11.0
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2507,7 +2507,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by gpgme $as_me 1.10.0, which was
+It was created by gpgme $as_me 1.11.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -2870,20 +2870,20 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
# (Interfaces added: AGE++)
# (Interfaces removed/changed: AGE=0)
#
-LIBGPGME_LT_CURRENT=30
-LIBGPGME_LT_AGE=19
+LIBGPGME_LT_CURRENT=31
+LIBGPGME_LT_AGE=20
LIBGPGME_LT_REVISION=0
# If there is an ABI break in gpgmepp or qgpgme also bump the
# version in IMPORTED_LOCATION in the GpgmeppConfig-w32.cmake.in.in
-LIBGPGMEPP_LT_CURRENT=11
-LIBGPGMEPP_LT_AGE=5
+LIBGPGMEPP_LT_CURRENT=12
+LIBGPGMEPP_LT_AGE=6
LIBGPGMEPP_LT_REVISION=0
LIBQGPGME_LT_CURRENT=10
LIBQGPGME_LT_AGE=3
-LIBQGPGME_LT_REVISION=0
+LIBQGPGME_LT_REVISION=1
# If the API is changed in an incompatible way: increment the next counter.
GPGME_CONFIG_API_VERSION=1
@@ -2898,7 +2898,7 @@ PACKAGE=$PACKAGE_NAME
VERSION=$PACKAGE_VERSION
VERSION_MAJOR=1
-VERSION_MINOR=10
+VERSION_MINOR=11
VERSION_MICRO=0
ac_aux_dir=
@@ -3420,7 +3420,7 @@ fi
# Define the identity of the package.
PACKAGE='gpgme'
- VERSION='1.10.0'
+ VERSION='1.11.0'
cat >>confdefs.h <<_ACEOF
@@ -6470,7 +6470,7 @@ cat >>confdefs.h <<_ACEOF
#define VERSION "$VERSION"
_ACEOF
-VERSION_NUMBER=0x010a00
+VERSION_NUMBER=0x010b00
# We need to compile and run a program on the build machine. A
@@ -20754,7 +20754,7 @@ ENABLED_LANGUAGES=$enabled_languages
#
# Provide information about the build.
#
-BUILD_REVISION="6a42eb5"
+BUILD_REVISION="3f55c52"
cat >>confdefs.h <<_ACEOF
@@ -20763,7 +20763,7 @@ _ACEOF
BUILD_FILEVERSION=`echo "$PACKAGE_VERSION"|sed 's/\([0-9.]*\).*/\1./;s/\./,/g'`
-BUILD_FILEVERSION="${BUILD_FILEVERSION}27202"
+BUILD_FILEVERSION="${BUILD_FILEVERSION}16213"
# Check whether --enable-build-timestamp was given.
@@ -21662,7 +21662,7 @@ $as_echo "$ac_cv_gnu_library_2_1" >&6; }
GLIBC21="$ac_cv_gnu_library_2_1"
-if test $GLIBC21 = yes; then
+if test $GLIBC21 = yes -o $have_w32_system = yes; then
have_thread_safe_getenv=yes
fi
if test $have_thread_safe_getenv = yes; then
@@ -23006,7 +23006,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by gpgme $as_me 1.10.0, which was
+This file was extended by gpgme $as_me 1.11.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -23072,7 +23072,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-gpgme config.status 1.10.0
+gpgme config.status 1.11.0
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
@@ -25384,7 +25384,7 @@ fi
echo "
GPGME v${VERSION} has been configured as follows:
- Revision: 6a42eb5 (27202)
+ Revision: 3f55c52 (16213)
Platform: $host
UI Server: $uiserver
diff --git a/configure.ac b/configure.ac
index 6ea4bcd..a04b059 100644
--- a/configure.ac
+++ b/configure.ac
@@ -28,7 +28,7 @@ min_automake_version="1.14"
# commit and push so that the git magic is able to work. See below
# for the LT versions.
m4_define(mym4_version_major, [1])
-m4_define(mym4_version_minor, [10])
+m4_define(mym4_version_minor, [11])
m4_define(mym4_version_micro, [0])
# Below is m4 magic to extract and compute the revision number, the
@@ -55,20 +55,20 @@ AC_INIT([gpgme],[mym4_full_version],[http://bugs.gnupg.org])
# (Interfaces added: AGE++)
# (Interfaces removed/changed: AGE=0)
#
-LIBGPGME_LT_CURRENT=30
-LIBGPGME_LT_AGE=19
+LIBGPGME_LT_CURRENT=31
+LIBGPGME_LT_AGE=20
LIBGPGME_LT_REVISION=0
# If there is an ABI break in gpgmepp or qgpgme also bump the
# version in IMPORTED_LOCATION in the GpgmeppConfig-w32.cmake.in.in
-LIBGPGMEPP_LT_CURRENT=11
-LIBGPGMEPP_LT_AGE=5
+LIBGPGMEPP_LT_CURRENT=12
+LIBGPGMEPP_LT_AGE=6
LIBGPGMEPP_LT_REVISION=0
LIBQGPGME_LT_CURRENT=10
LIBQGPGME_LT_AGE=3
-LIBQGPGME_LT_REVISION=0
+LIBQGPGME_LT_REVISION=1
# If the API is changed in an incompatible way: increment the next counter.
GPGME_CONFIG_API_VERSION=1
@@ -656,7 +656,7 @@ fi
# Try to find a thread-safe version of getenv().
have_thread_safe_getenv=no
jm_GLIBC21
-if test $GLIBC21 = yes; then
+if test $GLIBC21 = yes -o $have_w32_system = yes; then
have_thread_safe_getenv=yes
fi
if test $have_thread_safe_getenv = yes; then
@@ -810,7 +810,7 @@ AH_BOTTOM([
#define GPG_ERR_ENABLE_ERRNO_MACROS 1
#define CRIGHTBLURB "Copyright (C) 2000 Werner Koch\n" \
- "Copyright (C) 2001--2017 g10 Code GmbH\n"
+ "Copyright (C) 2001--2018 g10 Code GmbH\n"
])
diff --git a/doc/gpgme.info b/doc/gpgme.info
index 82aeb5b..dfdad87 100644
--- a/doc/gpgme.info
+++ b/doc/gpgme.info
@@ -19,8 +19,8 @@ END-INFO-DIR-ENTRY
This file documents the GPGME library.
- This is Edition 1.10.0, last updated 8 December 2017, of â€The â€GnuPG
-Made Easy’ Reference Manual’, for Version 1.10.0.
+ This is Edition 1.10.1-beta188, last updated 8 December 2017, of â€The
+â€GnuPG Made Easy’ Reference Manual’, for Version 1.10.1-beta188.
Copyright © 2002–2008, 2010, 2012–2017 g10 Code GmbH.
@@ -37,130 +37,130 @@ Public License for more details.

Indirect:
-gpgme.info-1: 1673
-gpgme.info-2: 302282
+gpgme.info-1: 1689
+gpgme.info-2: 302743

Tag Table:
(Indirect)
-Node: Top1673
-Node: Introduction9267
-Node: Getting Started10057
-Node: Features11518
-Node: Overview12830
-Node: Preparation13939
-Node: Header14936
-Node: Building the Source15683
-Node: Largefile Support (LFS)17827
-Node: Using Automake23243
-Node: Using Libtool25796
-Node: Library Version Check26158
-Node: Signal Handling32218
-Node: Multi-Threading33488
-Ref: Multi-Threading-Footnote-134904
-Node: Protocols and Engines35327
-Node: Engine Version Check38078
-Node: Engine Information40601
-Node: Engine Configuration44461
-Node: OpenPGP45765
-Node: Cryptographic Message Syntax46105
-Node: Assuan46418
-Node: Algorithms46792
-Ref: Algorithms-Footnote-147271
-Node: Public Key Algorithms47399
-Node: Hash Algorithms50001
-Node: Error Handling51215
-Node: Error Values53089
-Node: Error Sources58292
-Node: Error Codes60732
-Node: Error Strings65525
-Node: Exchanging Data67332
-Node: Creating Data Buffers69217
-Node: Memory Based Data Buffers69733
-Node: File Based Data Buffers73166
-Node: Callback Based Data Buffers75368
-Node: Destroying Data Buffers79559
-Node: Manipulating Data Buffers81066
-Node: Data Buffer I/O Operations81558
-Node: Data Buffer Meta-Data83931
-Node: Data Buffer Convenience88450
-Node: Contexts90670
-Node: Creating Contexts91856
-Node: Destroying Contexts92703
-Node: Result Management93042
-Node: Context Attributes94623
-Node: Protocol Selection95660
-Node: Crypto Engine96692
-Node: Setting the Sender98581
-Node: ASCII Armor100094
-Node: Text Mode100723
-Node: Offline Mode101657
-Node: Pinentry Mode102767
-Node: Included Certificates104661
-Node: Key Listing Mode106107
-Node: Passphrase Callback110319
-Node: Progress Meter Callback113881
-Node: Status Message Callback115866
-Node: Locale121218
-Node: Key Management122796
-Node: Key objects124024
-Node: Listing Keys138248
-Node: Information About Keys146901
-Node: Manipulating Keys148209
-Node: Generating Keys148779
-Node: Signing Keys167101
-Node: Exporting Keys170734
-Node: Importing Keys177541
-Ref: Importing Keys-Footnote-1184685
-Node: Deleting Keys184813
-Node: Changing Passphrases187093
-Node: Changing TOFU Data188420
-Node: Advanced Key Editing190528
-Node: Trust Item Management193261
-Node: Listing Trust Items194297
-Node: Manipulating Trust Items196658
-Node: Crypto Operations197301
-Node: Decrypt198565
-Node: Verify205072
-Node: Decrypt and Verify217536
-Node: Sign220391
-Node: Selecting Signers220955
-Node: Creating a Signature222361
-Node: Signature Notation Data227131
-Node: Encrypt229416
-Node: Encrypting a Plaintext229772
-Node: Miscellaneous237495
-Node: Running other Programs237907
-Node: Using the Assuan protocol240070
-Node: Checking for updates242868
-Node: Run Control247685
-Node: Waiting For Completion248429
-Node: Using External Event Loops250547
-Node: I/O Callback Interface252519
-Node: Registering I/O Callbacks257759
-Node: I/O Callback Example259798
-Node: I/O Callback Example GTK+266423
-Node: I/O Callback Example GDK268212
-Node: I/O Callback Example Qt269854
-Node: Cancellation272142
-Node: UI Server Protocol274450
-Ref: UI Server Protocol-Footnote-1275885
-Node: UI Server Encrypt276004
-Node: UI Server Sign281362
-Node: UI Server Decrypt283715
-Node: UI Server Verify285370
-Node: UI Server Set Input Files288942
-Node: UI Server Sign/Encrypt Files290012
-Node: UI Server Verify/Decrypt Files291820
-Node: UI Server Import/Export Keys293696
-Node: UI Server Checksum Files294758
-Node: Miscellaneous UI Server Commands296976
-Ref: command SENDER298907
-Node: Debugging302282
-Node: Deprecated Functions304031
-Node: Library Copying329248
-Node: Copying357468
-Node: Concept Index395218
-Node: Function and Data Index409997
+Node: Top1689
+Node: Introduction9299
+Node: Getting Started10089
+Node: Features11550
+Node: Overview12862
+Node: Preparation13971
+Node: Header14968
+Node: Building the Source15715
+Node: Largefile Support (LFS)17859
+Node: Using Automake23275
+Node: Using Libtool25828
+Node: Library Version Check26190
+Node: Signal Handling32250
+Node: Multi-Threading33520
+Ref: Multi-Threading-Footnote-134936
+Node: Protocols and Engines35359
+Node: Engine Version Check38110
+Node: Engine Information40633
+Node: Engine Configuration44493
+Node: OpenPGP45797
+Node: Cryptographic Message Syntax46137
+Node: Assuan46450
+Node: Algorithms46824
+Ref: Algorithms-Footnote-147303
+Node: Public Key Algorithms47431
+Node: Hash Algorithms50033
+Node: Error Handling51247
+Node: Error Values53121
+Node: Error Sources58324
+Node: Error Codes60764
+Node: Error Strings65557
+Node: Exchanging Data67364
+Node: Creating Data Buffers69249
+Node: Memory Based Data Buffers69765
+Node: File Based Data Buffers73198
+Node: Callback Based Data Buffers75400
+Node: Destroying Data Buffers79591
+Node: Manipulating Data Buffers81098
+Node: Data Buffer I/O Operations81590
+Node: Data Buffer Meta-Data83963
+Node: Data Buffer Convenience88482
+Node: Contexts90702
+Node: Creating Contexts91888
+Node: Destroying Contexts92735
+Node: Result Management93074
+Node: Context Attributes94655
+Node: Protocol Selection95692
+Node: Crypto Engine96724
+Node: Setting the Sender98613
+Node: ASCII Armor100126
+Node: Text Mode100755
+Node: Offline Mode101689
+Node: Pinentry Mode103187
+Node: Included Certificates105081
+Node: Key Listing Mode106527
+Node: Passphrase Callback110985
+Node: Progress Meter Callback114547
+Node: Status Message Callback116532
+Node: Locale122500
+Node: Key Management124078
+Node: Key objects125306
+Node: Listing Keys139530
+Node: Information About Keys148183
+Node: Manipulating Keys149491
+Node: Generating Keys150061
+Node: Signing Keys168383
+Node: Exporting Keys172016
+Node: Importing Keys178823
+Ref: Importing Keys-Footnote-1186226
+Node: Deleting Keys186354
+Node: Changing Passphrases188634
+Node: Changing TOFU Data189961
+Node: Advanced Key Editing192069
+Node: Trust Item Management194802
+Node: Listing Trust Items195838
+Node: Manipulating Trust Items198199
+Node: Crypto Operations198842
+Node: Decrypt200106
+Node: Verify206858
+Node: Decrypt and Verify219322
+Node: Sign222177
+Node: Selecting Signers222741
+Node: Creating a Signature224147
+Node: Signature Notation Data228917
+Node: Encrypt231202
+Node: Encrypting a Plaintext231558
+Node: Miscellaneous243791
+Node: Running other Programs244203
+Node: Using the Assuan protocol246366
+Node: Checking for updates249164
+Node: Run Control253981
+Node: Waiting For Completion254725
+Node: Using External Event Loops256843
+Node: I/O Callback Interface258815
+Node: Registering I/O Callbacks264055
+Node: I/O Callback Example266094
+Node: I/O Callback Example GTK+272719
+Node: I/O Callback Example GDK274508
+Node: I/O Callback Example Qt276150
+Node: Cancellation278438
+Node: UI Server Protocol280746
+Ref: UI Server Protocol-Footnote-1282181
+Node: UI Server Encrypt282300
+Node: UI Server Sign287658
+Node: UI Server Decrypt290011
+Node: UI Server Verify291666
+Node: UI Server Set Input Files295238
+Node: UI Server Sign/Encrypt Files296308
+Node: UI Server Verify/Decrypt Files298116
+Node: UI Server Import/Export Keys299992
+Node: UI Server Checksum Files302743
+Node: Miscellaneous UI Server Commands304961
+Ref: command SENDER306892
+Node: Debugging308594
+Node: Deprecated Functions310343
+Node: Library Copying335560
+Node: Copying363780
+Node: Concept Index401530
+Node: Function and Data Index416309

End Tag Table
diff --git a/doc/gpgme.info-1 b/doc/gpgme.info-1
index 4dc3349..888e180 100644
--- a/doc/gpgme.info-1
+++ b/doc/gpgme.info-1
@@ -19,8 +19,8 @@ END-INFO-DIR-ENTRY
This file documents the GPGME library.
- This is Edition 1.10.0, last updated 8 December 2017, of â€The â€GnuPG
-Made Easy’ Reference Manual’, for Version 1.10.0.
+ This is Edition 1.10.1-beta188, last updated 8 December 2017, of â€The
+â€GnuPG Made Easy’ Reference Manual’, for Version 1.10.1-beta188.
Copyright © 2002–2008, 2010, 2012–2017 g10 Code GmbH.
@@ -41,8 +41,9 @@ File: gpgme.info, Node: Top, Next: Introduction, Up: (dir)
Main Menu
*********
-This is Edition 1.10.0, last updated 8 December 2017, of â€The â€GnuPG
-Made Easy’ Reference Manual’, for Version 1.10.0 of the GPGME library.
+This is Edition 1.10.1-beta188, last updated 8 December 2017, of â€The
+â€GnuPG Made Easy’ Reference Manual’, for Version 1.10.1-beta188 of the
+GPGME library.
* Menu:
@@ -2421,20 +2422,26 @@ File: gpgme.info, Node: Offline Mode, Next: Pinentry Mode, Prev: Text Mode,
SINCE: 1.6.0
The function â€gpgme_set_offline’ specifies if offline mode should
- be used. By default, offline mode is not used.
+ be used. Offline mode is disabled if YES is zero, and enabled
+ otherwise. By default, offline mode is disabled.
- The offline mode specifies if dirmngr should be used to do
- additional validation that might require connections to external
- services. (e.g. CRL / OCSP checks).
+ The details of the offline mode depend on the used protocol and its
+ backend engine. It may eventually be extended to be more stricter
+ and for example completely disable the use of Dirmngr for any
+ engine.
- Offline mode only affects the keylist mode
- â€GPGME_KEYLIST_MODE_VALIDATE’ and is only relevant to the CMS
- crypto engine. Offline mode is ignored otherwise.
+ For the CMS protocol the offline mode specifies whether Dirmngr
+ shall be used to do additional validation that might require
+ connecting external services (e.g. CRL / OCSP checks). Here the
+ offline mode only affects the keylist mode
+ â€GPGME_KEYLIST_MODE_VALIDATE’.
- This option may be extended in the future to completely disable the
- use of dirmngr for any engine.
+ For the OpenPGP protocol offline mode entirely disables the use of
+ the Dirmngr and will thus guarantee that no network connections are
+ done as part of an operation on this context. It has only an
+ effect with GnuPG versions 2.1.23 or later.
- Offline mode is disabled if YES is zero, and enabled otherwise.
+ For all other protocols the offline mode is currently ignored.
-- Function: int gpgme_get_offline (gpgme_ctx_t CTX)
SINCE: 1.6.0
@@ -2570,6 +2577,11 @@ File: gpgme.info, Node: Key Listing Mode, Next: Passphrase Callback, Prev: In
â€GPGME_KEYLIST_MODE_LOCAL’. For example, it can be a remote
keyserver or LDAP certificate server.
+ â€GPGME_KEYLIST_MODE_LOCATE’
+ This is a shortcut for the combination of
+ â€GPGME_KEYLIST_MODE_LOCAL’ and â€GPGME_KEYLIST_MODE_EXTERN’ and
+ convenient when the –locate-key feature of OpenPGP is desired.
+
â€GPGME_KEYLIST_MODE_SIGS’
The â€GPGME_KEYLIST_MODE_SIGS’ symbol specifies that the key
signatures should be included in the listed keys.
@@ -2860,6 +2872,19 @@ File: gpgme.info, Node: Status Message Callback, Next: Locale, Prev: Progress
the operator can tell both your IP address and the time when
you verified the signature.
+ â€"request-origin"’
+ The string given in VALUE is passed to the GnuPG engines to
+ request restrictions based on the origin of the request.
+ Valid values are documented in the GnuPG manual and the gpg
+ man page under the option “–request-origin”. Requires at
+ least GnuPG 2.2.6 to have an effect.
+
+ â€"no-symkey-cache"’
+ For OpenPGP disable the passphrase cache used for symmetrical
+ en- and decryption. This cache is based on the message
+ specific salt value. Requires at least GnuPG 2.2.7 to have an
+ effect.
+
This function returns â€0’ on success.
-- Function: const char * gpgme_get_ctx_flag (gpgme_ctx_t CTX,
@@ -4423,6 +4448,12 @@ Importing keys means the same as running â€gpg’ with the command
A list of gpgme_import_status_t objects which contain more
information about the keys for which an import was attempted.
+ â€int skipped_v3_keys’
+ For security reasons modern versions of GnuPG do not anymore
+ support v3 keys (created with PGP 2.x) and ignores them on
+ import. This counter provides the number of such skipped v3
+ keys.
+
-- Function: gpgme_import_result_t gpgme_op_import_result
(gpgme_ctx_t CTX)
The function â€gpgme_op_import_result’ returns a
@@ -4827,8 +4858,8 @@ File: gpgme.info, Node: Decrypt, Next: Verify, Up: Crypto Operations
SINCE: 1.8.0
The function â€gpgme_op_decrypt_ext’ is the same as
- â€gpgme_op_decrypt_ext’ but has an additional argument FLAGS. If
- FLAGS is 0 both function behave identically.
+ â€gpgme_op_decrypt’ but has an additional argument FLAGS. If FLAGS
+ is 0 both function behave identically.
The value in FLAGS is a bitwise-or combination of one or multiple
of the following bit values:
@@ -4933,6 +4964,13 @@ File: gpgme.info, Node: Decrypt, Next: Verify, Up: Crypto Operations
success or â€gpgme_get_ctx_flag (ctx, "export-session-key")’
returns true (non-empty string).
+ â€char *symkey_algo’
+ SINCE: 1.11.0
+
+ A string with the symmetric encryption algorithm and mode
+ using the format "<algo>.<mode>". Note that old non-MDC
+ encryption mode of OpenPGP is given as "PGPCFB".
+
-- Function: gpgme_decrypt_result_t gpgme_op_decrypt_result
(gpgme_ctx_t CTX)
The function â€gpgme_op_decrypt_result’ returns a
@@ -5592,7 +5630,7 @@ File: gpgme.info, Node: Encrypting a Plaintext, Up: Encrypt
The â€GPGME_ENCRYPT_SYMMETRIC’ symbol specifies that the output
should be additionally encrypted symmetrically even if
recipients are provided. This feature is only supported for
- for the OpenPGP crypto engine.
+ the OpenPGP crypto engine.
â€GPGME_ENCRYPT_THROW_KEYIDS’
SINCE: 1.8.0
@@ -5611,6 +5649,19 @@ File: gpgme.info, Node: Encrypting a Plaintext, Up: Encrypt
OpenPGP message and not a plain data. This is the counterpart
to â€GPGME_DECRYPT_UNWRAP’.
+ â€GPGME_ENCRYPT_WANT_ADDRESS’
+ SINCE: 1.11.0
+
+ The â€GPGME_ENCRYPT_WANT_ADDRESS’ symbol requests that all
+ supplied keys or key specifications include a syntactically
+ valid mail address. If this is not the case the operation is
+ not even tried and the error code â€GPG_ERR_INV_USER_ID’ is
+ returned. Only the address part of the key specification is
+ conveyed to the backend. As of now the key must be specified
+ using the RECPSTRING argument of the extended encrypt
+ functions. This feature is currently only supported for the
+ OpenPGP crypto engine.
+
If â€GPG_ERR_UNUSABLE_PUBKEY’ is returned, some recipients in RECP
are invalid, but not all. In this case the plaintext might be
encrypted for all valid recipients and returned in CIPHER (if this
@@ -5648,6 +5699,60 @@ File: gpgme.info, Node: Encrypting a Plaintext, Up: Encrypt
â€GPG_ERR_UNUSABLE_PUBKEY’ if RSET does not contain any valid
recipients.
+ -- Function: gpgme_error_t gpgme_op_encrypt_ext (gpgme_ctx_t CTX,
+ gpgme_key_t RECP[], const char *RECPSTRING,
+ gpgme_encrypt_flags_t FLAGS, gpgme_data_t PLAIN,
+ gpgme_data_t CIPHER)
+
+ SINCE: 1.11.0
+
+ This is an extended version of â€gpgme_op_encrypt’ with RECPSTRING
+ as additional parameter. If RECP is NULL and RECPSTRING is not
+ NULL, the latter is expected to be a linefeed delimited string with
+ the set of key specifications. In contrast to RECP the keys are
+ given directly as strings and there is no need to first create key
+ objects. Leading and trailing white space is remove from each line
+ in RECPSTRING. The keys are then passed verbatim to the backend
+ engine.
+
+ For the OpenPGP backend several special keywords are supported to
+ modify the operation. These keywords are given instead of a key
+ specification. The currently supported keywords are:
+
+ â€--hidden’
+ â€--no-hidden’
+ These keywords toggle between normal and hidden recipients for
+ all following key specifications. When a hidden recipient is
+ requested the gpg option â€-R’ (or â€-F’ in file mode) is used
+ instead of â€-r’ (â€-f’ in file mode).
+
+ â€--file’
+ â€--no-file’
+ These keywords toggle between regular and file mode for all
+ following key specification. In file mode the option â€-f’ or
+ â€-F’ is passed to gpg. At least GnuPG version 2.1.14 is
+ required to handle these options. The
+ â€GPGME_ENCRYPT_WANT_ADDRESS’ flag is ignored in file mode.
+
+ â€--’
+ This keyword disables all keyword detection up to the end of
+ the string. All keywords are treated as verbatim arguments.
+
+ -- Function: gpgme_error_t gpgme_op_encrypt_ext_start (gpgme_ctx_t CTX,
+ gpgme_key_t RECP[], const char *RECPSTRING,
+ gpgme_encrypt_flags_t FLAGS, gpgme_data_t PLAIN,
+ gpgme_data_t CIPHER)
+
+ SINCE: 1.11.0
+
+ This is an extended version of â€gpgme_op_encrypt_start’ with
+ RECPSTRING as additional parameter. If RECP is NULL and RECPSTRING
+ is not NULL, the latter is expected to be a linefeed delimited
+ string with the set of key specifications. In contrast to RECP the
+ keys are given directly as strings and there is no need to first
+ create key objects. The keys are passed verbatim to the backend
+ engine.
+
-- Data type: gpgme_encrypt_result_t
This is a pointer to a structure used to store the result of a
â€gpgme_op_encrypt’ operation. After successfully encrypting data,
@@ -5692,6 +5797,36 @@ File: gpgme.info, Node: Encrypting a Plaintext, Up: Encrypt
operation could be started successfully, and â€GPG_ERR_INV_VALUE’ if
CTX, RSET, PLAIN or CIPHER is not a valid pointer.
+ -- Function: gpgme_error_t gpgme_op_encrypt_sign_ext (gpgme_ctx_t CTX,
+ gpgme_key_t RECP[], const char *RECPSTRING,
+ gpgme_encrypt_flags_t FLAGS, gpgme_data_t PLAIN,
+ gpgme_data_t CIPHER)
+
+ SINCE: 1.11.0
+
+ This is an extended version of â€gpgme_op_encrypt_sign’ with
+ RECPSTRING as additional parameter. If RECP is NULL and RECPSTRING
+ is not NULL, the latter is expected to be a linefeed delimited
+ string with the set of key specifications. In contrast to RECP the
+ keys are given directly as strings and there is no need to first
+ create the key objects. The keys are passed verbatim to the
+ backend engine.
+
+ -- Function: gpgme_error_t gpgme_op_encrypt_sign_ext_start
+ (gpgme_ctx_t CTX, gpgme_key_t RECP[], const char *RECPSTRING,
+ gpgme_encrypt_flags_t FLAGS, gpgme_data_t PLAIN,
+ gpgme_data_t CIPHER)
+
+ SINCE: 1.11.0
+
+ This is an extended version of â€gpgme_op_encrypt_sign_start’ with
+ RECPSTRING as additional parameter. If RECP is NULL and RECPSTRING
+ is not NULL, the latter is expected to be a linefeed delimited
+ string with the set of key specifications. In contrast to RECP the
+ keys are given directly as strings and there is no need to first
+ create the key objects. The keys are passed verbatim to the
+ backend engine.
+

File: gpgme.info, Node: Miscellaneous, Next: Run Control, Prev: Crypto Operations, Up: Contexts
@@ -7132,128 +7267,3 @@ commands. Afterwards, the actual operation is requested:
FIXME: It may be nice to support an â€EXPORT’ command as well, which
is enabled by the context menu of the background of a directory.
-
-File: gpgme.info, Node: UI Server Checksum Files, Next: Miscellaneous UI Server Commands, Prev: UI Server Import/Export Keys, Up: UI Server Protocol
-
-A.9 UI Server: Create and verify checksums for files.
-=====================================================
-
-First, the input files need to be specified by one or more â€FILE’
-commands. Afterwards, the actual operation is requested:
-
- -- Command: CHECKSUM_CREATE_FILES --nohup
- Request that checksums are created for the files specified by
- â€FILE’. The choice of checksum algorithm and the destination
- storage and format for the created checksums depend on the
- preferences of the user and the functionality provided by the UI
- server. For directories, the server may offer multiple options to
- the user (for example ignore or process recursively).
-
- The option â€--nohup’ is mandatory. It is currently unspecified
- what should happen if â€--nohup’ is not present. Because â€--nohup’
- is present, the server always returns â€OK’ promptly, and completes
- the operation asynchronously.
-
- -- Command: CHECKSUM_VERIFY_FILES --nohup
- Request that checksums are created for the files specified by
- â€FILE’ and verified against previously created and stored
- checksums. The choice of checksum algorithm and the source storage
- and format for previously created checksums depend on the
- preferences of the user and the functionality provided by the UI
- server. For directories, the server may offer multiple options to
- the user (for example ignore or process recursively).
-
- If the source storage of previously created checksums is available
- to the user through the Windows shell, this command may also accept
- such checksum files as â€FILE’ arguments. In this case, the UI
- server should instead verify the checksum of the referenced files
- as if they were given as INPUT files.
-
- The option â€--nohup’ is mandatory. It is currently unspecified
- what should happen if â€--nohup’ is not present. Because â€--nohup’
- is present, the server always returns â€OK’ promptly, and completes
- the operation asynchronously.
-
-
-File: gpgme.info, Node: Miscellaneous UI Server Commands, Prev: UI Server Checksum Files, Up: UI Server Protocol
-
-A.10 Miscellaneous UI Server Commands
-=====================================
-
-The server needs to implement the following commands which are not
-related to a specific command:
-
- -- Command: GETINFO WHAT
- This is a multi purpose command, commonly used to return a variety
- of information. The required subcommands as described by the WHAT
- parameter are:
-
- â€pid’
- Return the process id of the server in decimal notation using
- an Assuan data line.
-
-To allow the server to pop up the windows in the correct relation to the
-client, the client is advised to tell the server by sending the option:
-
- -- Command option: window-id NUMBER
- The NUMBER represents the native window ID of the clients current
- window. On Windows systems this is a windows handle (â€HWND’) and
- on X11 systems it is the â€X Window ID’. The number needs to be
- given as a hexadecimal value so that it is easier to convey pointer
- values (e.g. â€HWND’).
-
-A client may want to fire up the certificate manager of the server. To
-do this it uses the Assuan command:
-
- -- Command: START_KEYMANAGER
- The server shall pop up the main window of the key manager (aka
- certificate manager). The client expects that the key manager is
- brought into the foregound and that this command immediatley
- returns (does not wait until the key manager has been fully brought
- up).
-
-A client may want to fire up the configuration dialog of the server. To
-do this it uses the Assuan command:
-
- -- Command: START_CONFDIALOG
- The server shall pop up its configuration dialog. The client
- expects that this dialog is brought into the foregound and that
- this command immediatley returns (i.e. it does not wait until the
- dialog has been fully brought up).
-
-When doing an operation on a mail, it is useful to let the server know
-the address of the sender:
-
- -- Command: SENDER [--info] [--protocol=NAME] EMAIL
- EMAIL is the plain ASCII encoded address ("addr-spec" as per
- RFC-2822) enclosed in angle brackets. The address set with this
- command is valid until a successful completion of the operation or
- until a â€RESET’ command. A second command overrides the effect of
- the first one; if EMAIL is not given and â€--info’ is not used, the
- server shall use the default signing key.
-
- If option â€--info’ is not given, the server shall also suggest a
- protocol to use for signing. The client may use this suggested
- protocol on its own discretion. The same status line as with
- PREP_ENCRYPT is used for this.
-
- The option â€--protocol’ may be used to give the server a hint on
- which signing protocol should be preferred.
-
-To allow the UI-server to visually identify a running operation or to
-associate operations the server MAY support the command:
-
- -- Command: SESSION NUMBER [STRING]
- The NUMBER is an arbitrary value, a server may use to associate
- simultaneous running sessions. It is a 32 bit unsigned integer
- with â€0’ as a special value indicating that no session association
- shall be done.
-
- If STRING is given, the server may use this as the title of a
- window or, in the case of an email operation, to extract the
- sender’s address. The string may contain spaces; thus no
- plus-escaping is used.
-
- This command may be used at any time and overrides the effect of
- the last command. A â€RESET’ undoes the effect of this command.
-
diff --git a/doc/gpgme.info-2 b/doc/gpgme.info-2
index 2a805d3..4888966 100644
--- a/doc/gpgme.info-2
+++ b/doc/gpgme.info-2
@@ -19,8 +19,8 @@ END-INFO-DIR-ENTRY
This file documents the GPGME library.
- This is Edition 1.10.0, last updated 8 December 2017, of â€The â€GnuPG
-Made Easy’ Reference Manual’, for Version 1.10.0.
+ This is Edition 1.10.1-beta188, last updated 8 December 2017, of â€The
+â€GnuPG Made Easy’ Reference Manual’, for Version 1.10.1-beta188.
Copyright © 2002–2008, 2010, 2012–2017 g10 Code GmbH.
@@ -36,6 +36,131 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
Public License for more details.

+File: gpgme.info, Node: UI Server Checksum Files, Next: Miscellaneous UI Server Commands, Prev: UI Server Import/Export Keys, Up: UI Server Protocol
+
+A.9 UI Server: Create and verify checksums for files.
+=====================================================
+
+First, the input files need to be specified by one or more â€FILE’
+commands. Afterwards, the actual operation is requested:
+
+ -- Command: CHECKSUM_CREATE_FILES --nohup
+ Request that checksums are created for the files specified by
+ â€FILE’. The choice of checksum algorithm and the destination
+ storage and format for the created checksums depend on the
+ preferences of the user and the functionality provided by the UI
+ server. For directories, the server may offer multiple options to
+ the user (for example ignore or process recursively).
+
+ The option â€--nohup’ is mandatory. It is currently unspecified
+ what should happen if â€--nohup’ is not present. Because â€--nohup’
+ is present, the server always returns â€OK’ promptly, and completes
+ the operation asynchronously.
+
+ -- Command: CHECKSUM_VERIFY_FILES --nohup
+ Request that checksums are created for the files specified by
+ â€FILE’ and verified against previously created and stored
+ checksums. The choice of checksum algorithm and the source storage
+ and format for previously created checksums depend on the
+ preferences of the user and the functionality provided by the UI
+ server. For directories, the server may offer multiple options to
+ the user (for example ignore or process recursively).
+
+ If the source storage of previously created checksums is available
+ to the user through the Windows shell, this command may also accept
+ such checksum files as â€FILE’ arguments. In this case, the UI
+ server should instead verify the checksum of the referenced files
+ as if they were given as INPUT files.
+
+ The option â€--nohup’ is mandatory. It is currently unspecified
+ what should happen if â€--nohup’ is not present. Because â€--nohup’
+ is present, the server always returns â€OK’ promptly, and completes
+ the operation asynchronously.
+
+
+File: gpgme.info, Node: Miscellaneous UI Server Commands, Prev: UI Server Checksum Files, Up: UI Server Protocol
+
+A.10 Miscellaneous UI Server Commands
+=====================================
+
+The server needs to implement the following commands which are not
+related to a specific command:
+
+ -- Command: GETINFO WHAT
+ This is a multi purpose command, commonly used to return a variety
+ of information. The required subcommands as described by the WHAT
+ parameter are:
+
+ â€pid’
+ Return the process id of the server in decimal notation using
+ an Assuan data line.
+
+To allow the server to pop up the windows in the correct relation to the
+client, the client is advised to tell the server by sending the option:
+
+ -- Command option: window-id NUMBER
+ The NUMBER represents the native window ID of the clients current
+ window. On Windows systems this is a windows handle (â€HWND’) and
+ on X11 systems it is the â€X Window ID’. The number needs to be
+ given as a hexadecimal value so that it is easier to convey pointer
+ values (e.g. â€HWND’).
+
+A client may want to fire up the certificate manager of the server. To
+do this it uses the Assuan command:
+
+ -- Command: START_KEYMANAGER
+ The server shall pop up the main window of the key manager (aka
+ certificate manager). The client expects that the key manager is
+ brought into the foregound and that this command immediatley
+ returns (does not wait until the key manager has been fully brought
+ up).
+
+A client may want to fire up the configuration dialog of the server. To
+do this it uses the Assuan command:
+
+ -- Command: START_CONFDIALOG
+ The server shall pop up its configuration dialog. The client
+ expects that this dialog is brought into the foregound and that
+ this command immediatley returns (i.e. it does not wait until the
+ dialog has been fully brought up).
+
+When doing an operation on a mail, it is useful to let the server know
+the address of the sender:
+
+ -- Command: SENDER [--info] [--protocol=NAME] EMAIL
+ EMAIL is the plain ASCII encoded address ("addr-spec" as per
+ RFC-2822) enclosed in angle brackets. The address set with this
+ command is valid until a successful completion of the operation or
+ until a â€RESET’ command. A second command overrides the effect of
+ the first one; if EMAIL is not given and â€--info’ is not used, the
+ server shall use the default signing key.
+
+ If option â€--info’ is not given, the server shall also suggest a
+ protocol to use for signing. The client may use this suggested
+ protocol on its own discretion. The same status line as with
+ PREP_ENCRYPT is used for this.
+
+ The option â€--protocol’ may be used to give the server a hint on
+ which signing protocol should be preferred.
+
+To allow the UI-server to visually identify a running operation or to
+associate operations the server MAY support the command:
+
+ -- Command: SESSION NUMBER [STRING]
+ The NUMBER is an arbitrary value, a server may use to associate
+ simultaneous running sessions. It is a 32 bit unsigned integer
+ with â€0’ as a special value indicating that no session association
+ shall be done.
+
+ If STRING is given, the server may use this as the title of a
+ window or, in the case of an email operation, to extract the
+ sender’s address. The string may contain spaces; thus no
+ plus-escaping is used.
+
+ This command may be used at any time and overrides the effect of
+ the last command. A â€RESET’ undoes the effect of this command.
+
+
File: gpgme.info, Node: Debugging, Next: Deprecated Functions, Prev: UI Server Protocol, Up: Top
Appendix B How to solve problems
@@ -2290,7 +2415,7 @@ Function and Data Index
* gpgme_edit_cb_t: Deprecated Functions.
(line 37)
* gpgme_encrypt_result_t: Encrypting a Plaintext.
- (line 118)
+ (line 188)
* gpgme_engine_check_version: Engine Version Check.
(line 67)
* gpgme_engine_info_t: Engine Information. (line 6)
@@ -2332,7 +2457,7 @@ Function and Data Index
* gpgme_genkey_result_t: Generating Keys. (line 381)
* gpgme_get_armor: ASCII Armor. (line 13)
* gpgme_get_ctx_flag: Status Message Callback.
- (line 109)
+ (line 122)
* gpgme_get_dirinfo: Engine Version Check.
(line 6)
* gpgme_get_engine_info: Engine Information. (line 46)
@@ -2341,8 +2466,8 @@ Function and Data Index
* gpgme_get_io_cbs: Registering I/O Callbacks.
(line 44)
* gpgme_get_key: Listing Keys. (line 178)
-* gpgme_get_keylist_mode: Key Listing Mode. (line 83)
-* gpgme_get_offline: Offline Mode. (line 25)
+* gpgme_get_keylist_mode: Key Listing Mode. (line 88)
+* gpgme_get_offline: Offline Mode. (line 31)
* gpgme_get_passphrase_cb: Passphrase Callback. (line 63)
* gpgme_get_pinentry_mode: Pinentry Mode. (line 18)
* gpgme_get_progress_cb: Progress Meter Callback.
@@ -2407,7 +2532,7 @@ Function and Data Index
* gpgme_op_decrypt: Decrypt. (line 6)
* gpgme_op_decrypt_ext: Decrypt. (line 30)
* gpgme_op_decrypt_ext_start: Decrypt. (line 60)
-* gpgme_op_decrypt_result: Decrypt. (line 144)
+* gpgme_op_decrypt_result: Decrypt. (line 151)
* gpgme_op_decrypt_start: Decrypt. (line 20)
* gpgme_op_decrypt_verify: Decrypt and Verify. (line 6)
* gpgme_op_decrypt_verify_start: Decrypt and Verify. (line 30)
@@ -2421,14 +2546,22 @@ Function and Data Index
(line 72)
* gpgme_op_encrypt: Encrypting a Plaintext.
(line 6)
+* gpgme_op_encrypt_ext: Encrypting a Plaintext.
+ (line 131)
+* gpgme_op_encrypt_ext_start: Encrypting a Plaintext.
+ (line 171)
* gpgme_op_encrypt_result: Encrypting a Plaintext.
- (line 129)
+ (line 199)
* gpgme_op_encrypt_sign: Encrypting a Plaintext.
- (line 140)
+ (line 210)
+* gpgme_op_encrypt_sign_ext: Encrypting a Plaintext.
+ (line 235)
+* gpgme_op_encrypt_sign_ext_start: Encrypting a Plaintext.
+ (line 251)
* gpgme_op_encrypt_sign_start: Encrypting a Plaintext.
- (line 151)
+ (line 221)
* gpgme_op_encrypt_start: Encrypting a Plaintext.
- (line 100)
+ (line 113)
* gpgme_op_export: Exporting Keys. (line 46)
* gpgme_op_export_ext: Exporting Keys. (line 79)
* gpgme_op_export_ext_start: Exporting Keys. (line 101)
@@ -2443,7 +2576,7 @@ Function and Data Index
(line 22)
* gpgme_op_import_keys: Importing Keys. (line 35)
* gpgme_op_import_keys_start: Importing Keys. (line 65)
-* gpgme_op_import_result: Importing Keys. (line 168)
+* gpgme_op_import_result: Importing Keys. (line 174)
* gpgme_op_import_start: Importing Keys. (line 24)
* gpgme_op_interact: Advanced Key Editing.
(line 23)
diff --git a/doc/gpgme.texi b/doc/gpgme.texi
index cd7bb4b..20bfa23 100644
--- a/doc/gpgme.texi
+++ b/doc/gpgme.texi
@@ -2606,22 +2606,26 @@ valid pointer.
@deftypefun void gpgme_set_offline (@w{gpgme_ctx_t @var{ctx}}, @w{int @var{yes}})
@since{1.6.0}
-The function @code{gpgme_set_offline} specifies if offline mode
-should be used. By default, offline mode is not used.
+The function @code{gpgme_set_offline} specifies if offline mode should
+be used. Offline mode is disabled if @var{yes} is zero, and enabled
+otherwise. By default, offline mode is disabled.
-The offline mode specifies if dirmngr should be used to do additional
-validation that might require connections to external services.
-(e.g. CRL / OCSP checks).
+The details of the offline mode depend on the used protocol and its
+backend engine. It may eventually be extended to be more stricter and
+for example completely disable the use of Dirmngr for any engine.
-Offline mode only affects the keylist mode @code{GPGME_KEYLIST_MODE_VALIDATE}
-and is only relevant to the CMS crypto engine. Offline mode
-is ignored otherwise.
+For the CMS protocol the offline mode specifies whether Dirmngr shall
+be used to do additional validation that might require connecting
+external services (e.g. CRL / OCSP checks). Here the offline mode
+only affects the keylist mode @code{GPGME_KEYLIST_MODE_VALIDATE}.
-This option may be extended in the future to completely disable
-the use of dirmngr for any engine.
+For the OpenPGP protocol offline mode entirely disables the use of the
+Dirmngr and will thus guarantee that no network connections are done
+as part of an operation on this context. It has only an effect with
+GnuPG versions 2.1.23 or later.
+
+For all other protocols the offline mode is currently ignored.
-Offline mode is disabled if @var{yes} is zero, and enabled
-otherwise.
@end deftypefun
@deftypefun int gpgme_get_offline (@w{gpgme_ctx_t @var{ctx}})
@@ -2765,6 +2769,11 @@ type of external source is dependent on the crypto engine used and
whether it is combined with @code{GPGME_KEYLIST_MODE_LOCAL}. For
example, it can be a remote keyserver or LDAP certificate server.
+@item GPGME_KEYLIST_MODE_LOCATE
+This is a shortcut for the combination of
+@code{GPGME_KEYLIST_MODE_LOCAL} and @code{GPGME_KEYLIST_MODE_EXTERN}
+and convenient when the --locate-key feature of OpenPGP is desired.
+
@item GPGME_KEYLIST_MODE_SIGS
The @code{GPGME_KEYLIST_MODE_SIGS} symbol specifies that the key
signatures should be included in the listed keys.
@@ -3065,6 +3074,17 @@ a message signed by a brand new key (which you naturally will not have
on your local keyring), the operator can tell both your IP address and
the time when you verified the signature.
+@item "request-origin"
+The string given in @var{value} is passed to the GnuPG engines to
+request restrictions based on the origin of the request. Valid values
+are documented in the GnuPG manual and the gpg man page under the
+option ``--request-origin''. Requires at least GnuPG 2.2.6 to have an
+effect.
+
+@item "no-symkey-cache"
+For OpenPGP disable the passphrase cache used for symmetrical en- and
+decryption. This cache is based on the message specific salt value.
+Requires at least GnuPG 2.2.7 to have an effect.
@end table
@@ -4811,6 +4831,12 @@ The number of keys not imported.
@item gpgme_import_status_t imports
A list of gpgme_import_status_t objects which contain more information
about the keys for which an import was attempted.
+
+@item int skipped_v3_keys
+For security reasons modern versions of GnuPG do not anymore support
+v3 keys (created with PGP 2.x) and ignores them on import. This
+counter provides the number of such skipped v3 keys.
+
@end table
@end deftp
@@ -5263,7 +5289,7 @@ if @var{cipher} or @var{plain} is not a valid pointer.
@since{1.8.0}
The function @code{gpgme_op_decrypt_ext} is the same as
-@code{gpgme_op_decrypt_ext} but has an additional argument
+@code{gpgme_op_decrypt} but has an additional argument
@var{flags}. If @var{flags} is 0 both function behave identically.
The value in @var{flags} is a bitwise-or combination of one or
@@ -5378,6 +5404,13 @@ You must not try to access this member of the struct unless
or @code{gpgme_get_ctx_flag (ctx, "export-session-key")} returns true
(non-empty string).
+@item char *symkey_algo
+@since{1.11.0}
+
+A string with the symmetric encryption algorithm and mode using the
+format "<algo>.<mode>". Note that old non-MDC encryption mode of
+OpenPGP is given as "PGPCFB".
+
@end table
@end deftp
@@ -6077,7 +6110,7 @@ also expect a sign command.
The @code{GPGME_ENCRYPT_SYMMETRIC} symbol specifies that the
output should be additionally encrypted symmetrically even
-if recipients are provided. This feature is only supported for
+if recipients are provided. This feature is only supported
for the OpenPGP crypto engine.
@item GPGME_ENCRYPT_THROW_KEYIDS
@@ -6096,6 +6129,18 @@ The @code{GPGME_ENCRYPT_WRAP} symbol specifies that the input is an
OpenPGP message and not a plain data. This is the counterpart to
@code{GPGME_DECRYPT_UNWRAP}.
+@item GPGME_ENCRYPT_WANT_ADDRESS
+@since{1.11.0}
+
+The @code{GPGME_ENCRYPT_WANT_ADDRESS} symbol requests that all
+supplied keys or key specifications include a syntactically valid mail
+address. If this is not the case the operation is not even tried and
+the error code @code{GPG_ERR_INV_USER_ID} is returned. Only the
+address part of the key specification is conveyed to the backend. As
+of now the key must be specified using the @var{recpstring} argument
+of the extended encrypt functions. This feature is currently only
+supported for the OpenPGP crypto engine.
+
@end table
If @code{GPG_ERR_UNUSABLE_PUBKEY} is returned, some recipients in
@@ -6137,6 +6182,73 @@ pointer, and @code{GPG_ERR_UNUSABLE_PUBKEY} if @var{rset} does not
contain any valid recipients.
@end deftypefun
+@deftypefun gpgme_error_t gpgme_op_encrypt_ext @
+ (@w{gpgme_ctx_t @var{ctx}}, @
+ @w{gpgme_key_t @var{recp}[]}, @
+ @w{const char *@var{recpstring}}, @
+ @w{gpgme_encrypt_flags_t @var{flags}}, @
+ @w{gpgme_data_t @var{plain}}, @w{gpgme_data_t @var{cipher}})
+
+@since{1.11.0}
+
+This is an extended version of @code{gpgme_op_encrypt} with
+@var{recpstring} as additional parameter. If @var{recp} is NULL and
+@var{recpstring} is not NULL, the latter is expected to be a linefeed
+delimited string with the set of key specifications. In contrast to
+@var{recp} the keys are given directly as strings and there is no need
+to first create key objects. Leading and trailing white space is
+remove from each line in @var{recpstring}. The keys are then passed
+verbatim to the backend engine.
+
+For the OpenPGP backend several special keywords are supported to
+modify the operation. These keywords are given instead of a key
+specification. The currently supported keywords are:
+
+@table @code
+@item --hidden
+@itemx --no-hidden
+These keywords toggle between normal and hidden recipients for all
+following key specifications. When a hidden recipient is requested
+the gpg option @option{-R} (or @option{-F} in file mode) is used
+instead of @option{-r} (@option{-f} in file mode).
+
+@item --file
+@itemx --no-file
+These keywords toggle between regular and file mode for all following
+key specification. In file mode the option @option{-f} or @option{-F}
+is passed to gpg. At least GnuPG version 2.1.14 is required to handle
+these options. The @code{GPGME_ENCRYPT_WANT_ADDRESS} flag is ignored
+in file mode.
+
+@item --
+This keyword disables all keyword detection up to the end of the
+string. All keywords are treated as verbatim arguments.
+
+@end table
+
+
+@end deftypefun
+
+
+@deftypefun gpgme_error_t gpgme_op_encrypt_ext_start @
+ (@w{gpgme_ctx_t @var{ctx}}, @
+ @w{gpgme_key_t @var{recp}[]}, @
+ @w{const char *@var{recpstring}}, @
+ @w{gpgme_encrypt_flags_t @var{flags}}, @
+ @w{gpgme_data_t @var{plain}}, @w{gpgme_data_t @var{cipher}})
+
+@since{1.11.0}
+
+This is an extended version of @code{gpgme_op_encrypt_start} with
+@var{recpstring} as additional parameter. If @var{recp} is NULL and
+@var{recpstring} is not NULL, the latter is expected to be a linefeed
+delimited string with the set of key specifications. In contrast to
+@var{recp} the keys are given directly as strings and there is no need
+to first create key objects. The keys are passed verbatim to the
+backend engine.
+
+@end deftypefun
+
@deftp {Data type} {gpgme_encrypt_result_t}
This is a pointer to a structure used to store the result of a
@code{gpgme_op_encrypt} operation. After successfully encrypting
@@ -6186,6 +6298,44 @@ if @var{ctx}, @var{rset}, @var{plain} or @var{cipher} is not a valid
pointer.
@end deftypefun
+@deftypefun gpgme_error_t gpgme_op_encrypt_sign_ext @
+ (@w{gpgme_ctx_t @var{ctx}}, @
+ @w{gpgme_key_t @var{recp}[]}, @
+ @w{const char *@var{recpstring}}, @
+ @w{gpgme_encrypt_flags_t @var{flags}}, @
+ @w{gpgme_data_t @var{plain}}, @w{gpgme_data_t @var{cipher}})
+
+@since{1.11.0}
+
+This is an extended version of @code{gpgme_op_encrypt_sign} with
+@var{recpstring} as additional parameter. If @var{recp} is NULL and
+@var{recpstring} is not NULL, the latter is expected to be a linefeed
+delimited string with the set of key specifications. In contrast to
+@var{recp} the keys are given directly as strings and there is no need
+to first create the key objects. The keys are passed verbatim to the
+backend engine.
+
+@end deftypefun
+
+@deftypefun gpgme_error_t gpgme_op_encrypt_sign_ext_start @
+ (@w{gpgme_ctx_t @var{ctx}}, @
+ @w{gpgme_key_t @var{recp}[]}, @
+ @w{const char *@var{recpstring}}, @
+ @w{gpgme_encrypt_flags_t @var{flags}}, @
+ @w{gpgme_data_t @var{plain}}, @w{gpgme_data_t @var{cipher}})
+
+@since{1.11.0}
+
+This is an extended version of @code{gpgme_op_encrypt_sign_start} with
+@var{recpstring} as additional parameter. If @var{recp} is NULL and
+@var{recpstring} is not NULL, the latter is expected to be a linefeed
+delimited string with the set of key specifications. In contrast to
+@var{recp} the keys are given directly as strings and there is no need
+to first create the key objects. The keys are passed verbatim to the
+backend engine.
+
+@end deftypefun
+
@node Miscellaneous
@section Miscellaneous operations
diff --git a/gpgme.spec b/gpgme.spec
index 1a79ae6..760477e 100644
--- a/gpgme.spec
+++ b/gpgme.spec
@@ -1,7 +1,7 @@
# This is a template. The dist target uses it to create the real file.
Summary: GPGME - GnuPG Made Easy
Name: gpgme
-Version: 1.10.0
+Version: 1.11.0
Release: 1
URL: https://gnupg.org/gpgme.html
Source: ftp://ftp.gnupg.org/gcrypt/alpha/gpgme/%{name}-%{version}.tar.gz
diff --git a/lang/README b/lang/README
index 0c5bbd9..ee99f0f 100644
--- a/lang/README
+++ b/lang/README
@@ -13,3 +13,4 @@ cl Common Lisp
cpp C++
qt Qt-Framework API
python Python 2 and 3 (module name: gpg)
+javascript Native messaging client for the gpgme-json server.
diff --git a/lang/cl/gpgme.asd b/lang/cl/gpgme.asd
index 4db4d63..a39b61a 100644
--- a/lang/cl/gpgme.asd
+++ b/lang/cl/gpgme.asd
@@ -27,7 +27,7 @@
(defsystem gpgme
:description "GnuPG Made Easy."
:author "g10 Code GmbH"
- :version "1.10.0"
+ :version "1.11.0"
:licence "GPL"
:depends-on ("cffi" "gpg-error")
:components ((:file "gpgme-package")
diff --git a/lang/cpp/src/context.h b/lang/cpp/src/context.h
index 4cd5b30..aff8e49 100644
--- a/lang/cpp/src/context.h
+++ b/lang/cpp/src/context.h
@@ -408,7 +408,8 @@ public:
enum SpawnFlags {
SpawnNone = 0,
SpawnDetached = 1,
- SpawnAllowSetFg = 2
+ SpawnAllowSetFg = 2,
+ SpawnShowWindow = 4
};
/** Spwan the process \a file with arguments \a argv.
*
diff --git a/lang/cpp/src/data.cpp b/lang/cpp/src/data.cpp
index 32ca561..52b8da2 100644
--- a/lang/cpp/src/data.cpp
+++ b/lang/cpp/src/data.cpp
@@ -254,3 +254,17 @@ std::vector<GpgME::Key> GpgME::Data::toKeys(Protocol proto) const
delete ctx;
return ret;
}
+
+std::string GpgME::Data::toString()
+{
+ std::string ret;
+ char buf[4096];
+ size_t nread;
+ seek (0, SEEK_SET);
+ while ((nread = read (buf, 4096)) > 0)
+ {
+ ret += std::string (buf, nread);
+ }
+ seek (0, SEEK_SET);
+ return ret;
+}
diff --git a/lang/cpp/src/data.h b/lang/cpp/src/data.h
index cc7906f..446f6fa 100644
--- a/lang/cpp/src/data.h
+++ b/lang/cpp/src/data.h
@@ -114,6 +114,9 @@ public:
* Protocol proto. Returns an empty list on error.*/
std::vector<Key> toKeys(const Protocol proto = Protocol::OpenPGP) const;
+ /** Return a copy of the data as std::string. Sets seek pos to 0 */
+ std::string toString();
+
class Private;
Private *impl()
{
diff --git a/lang/cpp/src/importresult.cpp b/lang/cpp/src/importresult.cpp
index 8c35f9c..dbb31d0 100644
--- a/lang/cpp/src/importresult.cpp
+++ b/lang/cpp/src/importresult.cpp
@@ -154,6 +154,11 @@ int GpgME::ImportResult::notImported() const
return d ? d->res.not_imported : 0 ;
}
+int GpgME::ImportResult::numV3KeysSkipped() const
+{
+ return d ? d->res.skipped_v3_keys : 0 ;
+}
+
GpgME::Import GpgME::ImportResult::import(unsigned int idx) const
{
return Import(d, idx);
diff --git a/lang/cpp/src/importresult.h b/lang/cpp/src/importresult.h
index 2f0e7f2..0547679 100644
--- a/lang/cpp/src/importresult.h
+++ b/lang/cpp/src/importresult.h
@@ -78,6 +78,7 @@ public:
int numSecretKeysUnchanged() const;
int notImported() const;
+ int numV3KeysSkipped() const;
Import import(unsigned int idx) const;
std::vector<Import> imports() const;
diff --git a/lang/cpp/src/key.cpp b/lang/cpp/src/key.cpp
index 66fdea9..0e86a19 100644
--- a/lang/cpp/src/key.cpp
+++ b/lang/cpp/src/key.cpp
@@ -371,6 +371,27 @@ void Key::update()
return;
}
+// static
+Key Key::locate(const char *mbox)
+{
+ if (!mbox) {
+ return Key();
+ }
+
+ auto ctx = Context::createForProtocol(OpenPGP);
+ if (!ctx) {
+ return Key();
+ }
+
+ ctx->setKeyListMode (Extern | Local);
+
+ Error e = ctx->startKeyListing (mbox);
+ auto ret = ctx->nextKey (e);
+ delete ctx;
+
+ return ret;
+}
+
//
//
// class Subkey
diff --git a/lang/cpp/src/key.h b/lang/cpp/src/key.h
index 829bd26..c3c711c 100644
--- a/lang/cpp/src/key.h
+++ b/lang/cpp/src/key.h
@@ -164,6 +164,20 @@ public:
* @returns a possible error.
**/
Error addUid(const char *uid);
+
+ /**
+ * @brief try to locate the best pgp key for a given mailbox.
+ *
+ * Boils down to gpg --locate-key <mbox>
+ * This may take some time if remote sources are also
+ * used.
+ *
+ * @param mbox should be a mail address does not need to be normalized.
+ *
+ * @returns The best key for a mailbox or a null key.
+ */
+ static Key locate(const char *mbox);
+
private:
gpgme_key_t impl() const
{
diff --git a/lang/python/README b/lang/python/README
index 6a2e8b8..99da4dd 100644
--- a/lang/python/README
+++ b/lang/python/README
@@ -1,61 +1,77 @@
-gpg - GPGME bindings for Python -*- org -*-
-=======================
+ â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”
+ GPG - GPGME BINDINGS FOR PYTHON
+ â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”
+
+
+Table of Contents
+─────────────────
+
+1 Mailing List
+2 Bugs
+3 Authors
+4 History
+
The "gpg" module is a python interface to the GPGME library:
-https://www.gnupg.org/related_software/gpgme/
+[https://www.gnupg.org/software/gpgme/]
-"gpg" offers two interfaces, one is a high-level, curated, and
-idiomatic interface that is implemented as a shim on top of the
-low-level interface automatically created using SWIG.
+"gpg" offers two interfaces, one is a high-level, curated, and idiomatic
+interface that is implemented as a shim on top of the low-level
+interface automatically created using SWIG.
This way we make simple things easy, while still providing the entire
functionality of the underlying library.
-* Mailing List
-For general discussion and help see the gnupg-users mailing list:
-https://lists.gnupg.org/mailman/listinfo/gnupg-users
+1 Mailing List
+â•â•â•â•â•â•â•â•â•â•â•â•â•â•
+
+ For general discussion and help see the gnupg-users mailing list:
+ [https://lists.gnupg.org/mailman/listinfo/gnupg-users]
+
+ For development see the gnupg-devel mailing list:
+ [https://lists.gnupg.org/mailman/listinfo/gnupg-devel]
+
+
+2 Bugs
+â•â•â•â•â•â•
-For development see the gnupg-devel mailing list:
-https://lists.gnupg.org/mailman/listinfo/gnupg-devel
+ Please report bugs using our bug tracker [https://bugs.gnupg.org] with
+ tag (aka project) 'gpgme'.
-* Bugs
-Please report bugs using our bug tracker using the category 'gpgme',
-and topic 'python':
-https://bugs.gnupg.org/gnupg/
+3 Authors
+â•â•â•â•â•â•â•â•â•
-* Authors
+ PyME was created by John Goerzen, and maintained, developed, and
+ cherished by Igor Belyi, Martin Albrecht, Ben McGinnes, and everyone
+ who contributed to it in any way.
-PyME was created by John Goerzen, and maintained, developed, and
-cherished by Igor Belyi, Martin Albrecht, Ben McGinnes, and everyone
-who contributed to it in any way.
+ In 2016 we merged a port of PyME to into the GPGME repository, and
+ development will continue there. Please see the VCS history for the
+ list of contributors, and if you do find bugs, or want to contribute,
+ please get in touch and help maintain the python gpg bindings.
-In 2016 we merged a port of PyME to into the GPGME repository, and
-development will continue there. Please see the VCS history for the
-list of contributors, and if you do find bugs, or want to contribute,
-please get in touch and help maintain the python gpg bindings.
+ Please see the section 'History' further down this document for
+ references to previous versions.
-Please see the section 'History' further down this document for
-references to previous versions.
-* History
+4 History
+â•â•â•â•â•â•â•â•â•
- - The python bindings were renamed from PyME to "gpg" in 2016.
+ • The python bindings were renamed from PyME to "gpg" in 2016.
- - The bindings have been merged into the GPGME repository in 2016.
+ • The bindings have been merged into the GPGME repository in 2016.
- - The latest version of PyME for Python 3.2 and above (as of
- May, 2015) is v0.9.1.
- https://git.gnupg.org/gpgme.git/lang/py3-pyme
+ • The latest version of PyME for Python 3.2 and above (as of May,
+ 2015) is v0.9.1. [https://git.gnupg.org/gpgme.git/lang/py3-pyme]
- - The latest version of PyME for Python 2.6 and 2.7 (as of this
- writing) is v0.9.0. https://bitbucket.org/malb/pyme
+ • The latest version of PyME for Python 2.6 and 2.7 (as of this
+ writing) is v0.9.0. [https://bitbucket.org/malb/pyme]
- - A previous version of PyME v0.8.0 can be found on sourceforge:
- http://pyme.sourceforge.net/
+ • A previous version of PyME v0.8.0 can be found on sourceforge:
+ [http://pyme.sourceforge.net/]
- - A previous version of PyME v0.5.1 which works with GPGME v0.3.15
- can be found on John Goerzen's PyME page:
- http://quux.org/devel/pyme/
- http://www.complete.org/JohnGoerzen
+ • A previous version of PyME v0.5.1 which works with GPGME v0.3.15 can
+ be found on John Goerzen's PyME page: [http://quux.org/devel/pyme/]
+ [http://www.complete.org/JohnGoerzen]
diff --git a/lang/python/examples/howto/README.org b/lang/python/examples/howto/README.org
new file mode 100644
index 0000000..b74ae7e
--- /dev/null
+++ b/lang/python/examples/howto/README.org
@@ -0,0 +1,58 @@
+#+TITLE: GPGME Python Bindings HOWTO Examples
+#+LATEX_COMPILER: xelatex
+#+LATEX_CLASS: article
+#+LATEX_CLASS_OPTIONS: [12pt]
+#+LATEX_HEADER: \usepackage{xltxtra}
+#+LATEX_HEADER: \usepackage[margin=1in]{geometry}
+#+LATEX_HEADER: \setmainfont[Ligatures={Common}]{Times New Roman}
+#+LATEX_HEADER: \author{Ben McGinnes <ben@gnupg.org>}
+
+
+* Examples
+ :PROPERTIES:
+ :CUSTOM_ID: gpgme-python3-examples
+ :END:
+
+ The contents of this directory are the examples included in the /GNU
+ Privacy Guard (GnuPG) Made Easy Python Bindings HOWTO/ file. Each
+ script is explicitly for Python 3 and specifically for Python 3.4 or
+ later.
+
+ Some of these scripts may work with Python 2.7, but there are no
+ guarantees. They will include the relevant imports from the
+ =__future__= module to facilitate that if possible.
+
+
+* Copyright and Licensing
+ :PROPERTIES:
+ :CUSTOM_ID: copyright-and-license
+ :END:
+
+ Unless otherwise stated, all the examples in this directory are
+ released under the same terms as GPGME itself; that is they are dual
+ licensed under the terms of both the GNU General Public License
+ version 2.0 (or any later version) *and* the GNU Lesser General
+ Public License version 2.1 (or any later version).
+
+
+** Copyright (C) The GnuPG Project, 2018
+ :PROPERTIES:
+ :CUSTOM_ID: copyright
+ :END:
+
+ Copyright © The GnuPG Project, 2018.
+
+
+** License GPL compatible
+ :PROPERTIES:
+ :CUSTOM_ID: license
+ :END:
+
+ This file is free software; as a special exception the author gives
+ unlimited permission to copy and/or distribute it, with or without
+ modifications, as long as this notice is preserved.
+
+ This file is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY, to the extent permitted by law; without even
+ the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE.
diff --git a/lang/python/examples/howto/add-userid.py b/lang/python/examples/howto/add-userid.py
new file mode 100755
index 0000000..b868979
--- /dev/null
+++ b/lang/python/examples/howto/add-userid.py
@@ -0,0 +1,62 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+from __future__ import absolute_import, division, unicode_literals
+
+# Copyright (C) 2018 Ben McGinnes <ben@gnupg.org>
+#
+# 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 free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; either version 2.1 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 and the GNU
+# Lesser General Public Licensefor more details.
+#
+# You should have received a copy of the GNU General Public License and the GNU
+# Lesser General Public along with this program; if not, see
+# <http://www.gnu.org/licenses/>.
+
+import gpg
+import os.path
+
+print("""
+This script adds a new user ID to an existing key.
+
+The gpg-agent and pinentry are invoked to enter the passphrase.
+""")
+
+c = gpg.Context()
+
+homedir = input("Enter the GPG configuration directory path (optional): ")
+fpr0 = input("Enter the fingerprint of the key to modify: ")
+uid_name = input("Enter the name of the user ID: ")
+uid_email = input("Enter the email address of the user ID: ")
+uid_cmnt = input("Enter a comment to include (optional): ")
+
+if homedir.startswith("~"):
+ if os.path.exists(os.path.expanduser(homedir)) is True:
+ c.home_dir = os.path.expanduser(homedir)
+ else:
+ pass
+elif os.path.exists(homedir) is True:
+ c.home_dir = homedir
+else:
+ pass
+
+fpr = "".join(fpr0.split())
+
+if len(uid_cmnt) > 0:
+ userid = "{0} ({1}) <{2}>".format(uid_name, uid_cmnt, uid_email)
+else:
+ userid = "{0} <{2}>".format(uid_name, uid_email)
+
+key = c.get_key(fpr, secret=True)
+c.key_add_uid(key, userid)
diff --git a/lang/python/examples/howto/clear-sign-file.py b/lang/python/examples/howto/clear-sign-file.py
new file mode 100755
index 0000000..597bbc5
--- /dev/null
+++ b/lang/python/examples/howto/clear-sign-file.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+from __future__ import absolute_import, division, unicode_literals
+
+# Copyright (C) 2018 Ben McGinnes <ben@gnupg.org>
+#
+# 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 free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; either version 2.1 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 and the GNU
+# Lesser General Public Licensefor more details.
+#
+# You should have received a copy of the GNU General Public License and the GNU
+# Lesser General Public along with this program; if not, see
+# <http://www.gnu.org/licenses/>.
+
+import gpg
+import sys
+
+"""
+Clear-signs a file with a specified key. If entering both the key and the
+filename on the command line, the key must be entered first.
+"""
+
+if len(sys.argv) > 3:
+ logrus = sys.argv[1]
+ filename = " ".join(sys.argv[2:])
+elif len(sys.argv) == 3:
+ logrus = sys.argv[1]
+ filename = sys.argv[2]
+elif len(sys.argv) == 2:
+ logrus = sys.argv[1]
+ filename = input("Enter the path and filename to sign: ")
+else:
+ logrus = input("Enter the fingerprint or key ID to sign with: ")
+ filename = input("Enter the path and filename to sign: ")
+
+with open(filename, "rb") as f:
+ text = f.read()
+
+key = list(gpg.Context().keylist(pattern=logrus))
+
+with gpg.Context(armor=True, signers=key) as c:
+ signed_data, result = c.sign(text, mode=gpg.constants.sig.mode.CLEAR)
+ with open("{0}.asc".format(filename), "wb") as f:
+ f.write(signed_data)
diff --git a/lang/python/examples/howto/create-key.py b/lang/python/examples/howto/create-key.py
new file mode 100755
index 0000000..429ab1f
--- /dev/null
+++ b/lang/python/examples/howto/create-key.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+from __future__ import absolute_import, division, unicode_literals
+
+# Copyright (C) 2018 Ben McGinnes <ben@gnupg.org>
+#
+# 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 free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; either version 2.1 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 and the GNU
+# Lesser General Public Licensefor more details.
+#
+# You should have received a copy of the GNU General Public License and the GNU
+# Lesser General Public along with this program; if not, see
+# <http://www.gnu.org/licenses/>.
+
+import gpg
+import os.path
+
+print("""
+This script generates a new key which does not expire.
+
+The gpg-agent and pinentry are invoked to set the passphrase.
+""")
+
+c = gpg.Context()
+
+homedir = input("Enter the GPG configuration directory path (optional): ")
+uid_name = input("Enter the name of the user ID: ")
+uid_email = input("Enter the email address of the user ID: ")
+uid_cmnt = input("Enter a comment to include (optional): ")
+key_algo = input("Enter the key algorithm, RSA or DSA (default is RSA): ")
+key_size = input("Enter the key size (2048-4096, default is 2048): ")
+
+if homedir.startswith("~"):
+ if os.path.exists(os.path.expanduser(homedir)) is True:
+ c.home_dir = os.path.expanduser(homedir)
+ else:
+ pass
+elif os.path.exists(homedir) is True:
+ c.home_dir = homedir
+else:
+ pass
+
+if len(uid_cmnt) > 0:
+ userid = "{0} ({1}) <{2}>".format(uid_name, uid_cmnt, uid_email)
+else:
+ userid = "{0} <{2}>".format(uid_name, uid_email)
+
+if key_algo.lower() == "dsa":
+ ka = "dsa"
+else:
+ ka = "rsa"
+
+if len(key_size) == 4:
+ try:
+ ks0 = int(key_size)
+ except ValueError:
+ ks0 = None
+ if ks0 is None:
+ ks = "2048"
+ else:
+ if ks0 < 2048:
+ ks = "2048"
+ elif ka == "dsa" and ks0 > 3072:
+ ks = "3072"
+ elif ka == "rsa" and ks0 > 4096:
+ ks = "4096"
+ else:
+ ks = key_size
+else:
+ ks = "2048"
+
+keyalgo = "{0}{1}".format(ka, ks)
+
+newkey = c.create_key(userid, algorithm=keyalgo, expires=False,
+ passphrase=True, certify=True)
+key = c.get_key(newkey.fpr, secret=True)
+
+if ka == "rsa":
+ newsub = c.create_subkey(key, algorithm=keyalgo, expires=False,
+ passphrase=True, encrypt=True)
+else:
+ newsub = c.create_subkey(key, expires=False, passphrase=True,
+ encrypt=True)
diff --git a/lang/python/examples/howto/decrypt-file.py b/lang/python/examples/howto/decrypt-file.py
new file mode 100755
index 0000000..60a050b
--- /dev/null
+++ b/lang/python/examples/howto/decrypt-file.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+from __future__ import absolute_import, division, unicode_literals
+
+# Copyright (C) 2018 Ben McGinnes <ben@gnupg.org>
+#
+# 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 free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; either version 2.1 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 and the GNU
+# Lesser General Public Licensefor more details.
+#
+# You should have received a copy of the GNU General Public License and the GNU
+# Lesser General Public along with this program; if not, see
+# <http://www.gnu.org/licenses/>.
+
+import gpg
+import sys
+
+if len(sys.argv) == 3:
+ ciphertext = sys.argv[1]
+ newfile = sys.argv[2]
+elif len(sys.argv) == 2:
+ ciphertext = sys.argv[1]
+ newfile = input("Enter path and filename of file to save decrypted data to: ")
+else:
+ ciphertext = input("Enter path and filename of encrypted file: ")
+ newfile = input("Enter path and filename of file to save decrypted data to: ")
+
+with open(ciphertext, "rb") as cfile:
+ plaintext, result, verify_result = gpg.Context().decrypt(cfile)
+
+with open(newfile, "wb") as nfile:
+ nfile.write(plaintext)
diff --git a/lang/python/examples/howto/detach-sign-file.py b/lang/python/examples/howto/detach-sign-file.py
new file mode 100755
index 0000000..99fbe65
--- /dev/null
+++ b/lang/python/examples/howto/detach-sign-file.py
@@ -0,0 +1,64 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+from __future__ import absolute_import, division, unicode_literals
+
+# Copyright (C) 2018 Ben McGinnes <ben@gnupg.org>
+#
+# 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 free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; either version 2.1 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 and the GNU
+# Lesser General Public Licensefor more details.
+#
+# You should have received a copy of the GNU General Public License and the GNU
+# Lesser General Public along with this program; if not, see
+# <http://www.gnu.org/licenses/>.
+
+import gpg
+import sys
+
+"""
+Signs a file with a specified key. If entering both the key and the filename
+on the command line, the key must be entered first.
+
+Will produce both an ASCII armoured and GPG binary format copy of the detached
+signature file.
+"""
+
+if len(sys.argv) > 3:
+ logrus = sys.argv[1]
+ filename = " ".join(sys.argv[2:])
+elif len(sys.argv) == 3:
+ logrus = sys.argv[1]
+ filename = sys.argv[2]
+elif len(sys.argv) == 2:
+ logrus = sys.argv[1]
+ filename = input("Enter the path and filename to sign: ")
+else:
+ logrus = input("Enter the fingerprint or key ID to sign with: ")
+ filename = input("Enter the path and filename to sign: ")
+
+with open(filename, "rb") as f:
+ text = f.read()
+
+key = list(gpg.Context().keylist(pattern=logrus))
+
+with gpg.Context(armor=True, signers=key) as ca:
+ signed_data, result = ca.sign(text, mode=gpg.constants.sig.mode.DETACH)
+ with open("{0}.asc".format(filename), "wb") as fa:
+ fa.write(signed_data)
+
+with gpg.Context(signers=key) as cb:
+ signed_data, result = cb.sign(text, mode=gpg.constants.sig.mode.DETACH)
+ with open("{0}.sig".format(filename), "wb") as fb:
+ fb.write(signed_data)
diff --git a/lang/python/examples/howto/encrypt-file.py b/lang/python/examples/howto/encrypt-file.py
new file mode 100755
index 0000000..ad4e1ce
--- /dev/null
+++ b/lang/python/examples/howto/encrypt-file.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+from __future__ import absolute_import, division, unicode_literals
+
+# Copyright (C) 2018 Ben McGinnes <ben@gnupg.org>
+#
+# 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 free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; either version 2.1 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 and the GNU
+# Lesser General Public Licensefor more details.
+#
+# You should have received a copy of the GNU General Public License and the GNU
+# Lesser General Public along with this program; if not, see
+# <http://www.gnu.org/licenses/>.
+
+import gpg
+import sys
+
+"""
+Encrypts a file to a specified key. If entering both the key and the filename
+on the command line, the key must be entered first.
+
+Will produce both an ASCII armoured and GPG binary format copy of the encrypted
+file.
+"""
+
+if len(sys.argv) > 3:
+ a_key = sys.argv[1]
+ filename = " ".join(sys.argv[2:])
+elif len(sys.argv) == 3:
+ a_key = sys.argv[1]
+ filename = sys.argv[2]
+elif len(sys.argv) == 2:
+ a_key = sys.argv[1]
+ filename = input("Enter the path and filename to encrypt: ")
+else:
+ a_key = input("Enter the fingerprint or key ID to encrypt to: ")
+ filename = input("Enter the path and filename to encrypt: ")
+
+rkey = list(gpg.Context().keylist(pattern=a_key, secret=False))
+with open(filename, "rb") as f:
+ text = f.read()
+
+with gpg.Context(armor=True) as ca:
+ try:
+ ciphertext, result, sign_result = ca.encrypt(text, recipients=rkey,
+ sign=False)
+ with open("{0}.asc".format(filename), "wb") as fa:
+ fa.write(ciphertext)
+ except gpg.errors.InvalidRecipients as e:
+ print(e)
+
+with gpg.Context() as cg:
+ try:
+ ciphertext, result, sign_result = cg.encrypt(text, recipients=rkey,
+ sign=False)
+ with open("{0}.gpg".format(filename), "wb") as fg:
+ fg.write(ciphertext)
+ except gpg.errors.InvalidRecipients as e:
+ print(e)
diff --git a/lang/python/examples/howto/encrypt-sign-file.py b/lang/python/examples/howto/encrypt-sign-file.py
new file mode 100755
index 0000000..41aaac8
--- /dev/null
+++ b/lang/python/examples/howto/encrypt-sign-file.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+from __future__ import absolute_import, division, unicode_literals
+
+# Copyright (C) 2018 Ben McGinnes <ben@gnupg.org>
+#
+# 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 free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; either version 2.1 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 and the GNU
+# Lesser General Public Licensefor more details.
+#
+# You should have received a copy of the GNU General Public License and the GNU
+# Lesser General Public along with this program; if not, see
+# <http://www.gnu.org/licenses/>.
+
+import gpg
+import sys
+
+"""
+Signs and encrypts a file to a specified key. If entering both the key and the
+filename on the command line, the key must be entered first.
+
+Signs with and also encrypts to the default key of the user invoking the
+script. Will treat all recipients as trusted to permit encryption.
+
+Will produce both an ASCII armoured and GPG binary format copy of the signed
+and encrypted file.
+"""
+
+if len(sys.argv) > 3:
+ a_key = sys.argv[1]
+ filename = " ".join(sys.argv[2:])
+elif len(sys.argv) == 3:
+ a_key = sys.argv[1]
+ filename = sys.argv[2]
+elif len(sys.argv) == 2:
+ a_key = sys.argv[1]
+ filename = input("Enter the path and filename to encrypt: ")
+else:
+ a_key = input("Enter the fingerprint or key ID to encrypt to: ")
+ filename = input("Enter the path and filename to encrypt: ")
+
+rkey = list(gpg.Context().keylist(pattern=a_key, secret=False))
+with open(filename, "rb") as f:
+ text = f.read()
+
+with gpg.Context(armor=True) as ca:
+ ciphertext, result, sign_result = ca.encrypt(text, recipients=rkey,
+ always_trust=True,
+ add_encrypt_to=True)
+ with open("{0}.asc".format(filename), "wb") as fa:
+ fa.write(ciphertext)
+
+with gpg.Context() as cg:
+ ciphertext, result, sign_result = cg.encrypt(text, recipients=rkey,
+ always_trust=True,
+ add_encrypt_to=True)
+ with open("{0}.gpg".format(filename), "wb") as fg:
+ fg.write(ciphertext)
diff --git a/lang/python/examples/howto/groups.py b/lang/python/examples/howto/groups.py
new file mode 100644
index 0000000..5e7fdf6
--- /dev/null
+++ b/lang/python/examples/howto/groups.py
@@ -0,0 +1,50 @@
+# -*- coding: utf-8 -*-
+
+from __future__ import absolute_import, division, unicode_literals
+
+# Copyright (C) 2018 Ben McGinnes <ben@gnupg.org>
+#
+# 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 free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; either version 2.1 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 and the GNU
+# Lesser General Public Licensefor more details.
+#
+# You should have received a copy of the GNU General Public License and the GNU
+# Lesser General Public along with this program; if not, see
+# <http://www.gnu.org/licenses/>.
+
+import subprocess
+
+"""
+Intended for use with other scripts.
+
+Usage: from groups import group_lists
+"""
+
+lines = subprocess.getoutput("gpgconf --list-options gpg").splitlines()
+
+for i in range(len(lines)):
+ if lines[i].startswith("group") is True:
+ line = lines[i]
+ else:
+ pass
+
+groups = line.split(":")[-1].replace('"', '').split(',')
+
+group_lines = groups
+for i in range(len(group_lines)):
+ group_lines[i] = group_lines[i].split("=")
+
+group_lists = group_lines
+for i in range(len(group_lists)):
+ group_lists[i][1] = group_lists[i][1].split()
diff --git a/lang/python/examples/howto/keycount.py b/lang/python/examples/howto/keycount.py
new file mode 100755
index 0000000..8e25454
--- /dev/null
+++ b/lang/python/examples/howto/keycount.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+from __future__ import absolute_import, division, unicode_literals
+
+# Copyright (C) 2018 Ben McGinnes <ben@gnupg.org>
+#
+# 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 free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; either version 2.1 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 and the GNU
+# Lesser General Public Licensefor more details.
+#
+# You should have received a copy of the GNU General Public License and the GNU
+# Lesser General Public along with this program; if not, see
+# <http://www.gnu.org/licenses/>.
+
+import gpg
+
+c = gpg.Context()
+seckeys = c.keylist(pattern=None, secret=True)
+pubkeys = c.keylist(pattern=None, secret=False)
+
+seclist = list(seckeys)
+secnum = len(seclist)
+
+publist = list(pubkeys)
+pubnum = len(publist)
+
+print("""
+Number of secret keys: {0}
+Number of public keys: {1}
+""".format(secnum, pubnum))
diff --git a/lang/python/examples/howto/revoke-userid.py b/lang/python/examples/howto/revoke-userid.py
new file mode 100755
index 0000000..7a3d190
--- /dev/null
+++ b/lang/python/examples/howto/revoke-userid.py
@@ -0,0 +1,62 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+from __future__ import absolute_import, division, unicode_literals
+
+# Copyright (C) 2018 Ben McGinnes <ben@gnupg.org>
+#
+# 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 free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; either version 2.1 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 and the GNU
+# Lesser General Public Licensefor more details.
+#
+# You should have received a copy of the GNU General Public License and the GNU
+# Lesser General Public along with this program; if not, see
+# <http://www.gnu.org/licenses/>.
+
+import gpg
+import os.path
+
+print("""
+This script revokes a user ID on an existing key.
+
+The gpg-agent and pinentry are invoked to enter the passphrase.
+""")
+
+c = gpg.Context()
+
+homedir = input("Enter the GPG configuration directory path (optional): ")
+fpr0 = input("Enter the fingerprint of the key to modify: ")
+uid_name = input("Enter the name of the user ID: ")
+uid_email = input("Enter the email address of the user ID: ")
+uid_cmnt = input("Enter a comment to include (optional): ")
+
+if homedir.startswith("~"):
+ if os.path.exists(os.path.expanduser(homedir)) is True:
+ c.home_dir = os.path.expanduser(homedir)
+ else:
+ pass
+elif os.path.exists(homedir) is True:
+ c.home_dir = homedir
+else:
+ pass
+
+fpr = "".join(fpr0.split())
+
+if len(uid_cmnt) > 0:
+ userid = "{0} ({1}) <{2}>".format(uid_name, uid_cmnt, uid_email)
+else:
+ userid = "{0} <{2}>".format(uid_name, uid_email)
+
+key = c.get_key(fpr, secret=True)
+c.key_revoke_uid(key, userid)
diff --git a/lang/python/examples/howto/sign-file.py b/lang/python/examples/howto/sign-file.py
new file mode 100755
index 0000000..01006df
--- /dev/null
+++ b/lang/python/examples/howto/sign-file.py
@@ -0,0 +1,64 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+from __future__ import absolute_import, division, unicode_literals
+
+# Copyright (C) 2018 Ben McGinnes <ben@gnupg.org>
+#
+# 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 free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; either version 2.1 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 and the GNU
+# Lesser General Public Licensefor more details.
+#
+# You should have received a copy of the GNU General Public License and the GNU
+# Lesser General Public along with this program; if not, see
+# <http://www.gnu.org/licenses/>.
+
+import gpg
+import sys
+
+"""
+Signs a file with a specified key. If entering both the key and the filename
+on the command line, the key must be entered first.
+
+Will produce both an ASCII armoured and GPG binary format copy of the signed
+file.
+"""
+
+if len(sys.argv) > 3:
+ logrus = sys.argv[1]
+ filename = " ".join(sys.argv[2:])
+elif len(sys.argv) == 3:
+ logrus = sys.argv[1]
+ filename = sys.argv[2]
+elif len(sys.argv) == 2:
+ logrus = sys.argv[1]
+ filename = input("Enter the path and filename to sign: ")
+else:
+ logrus = input("Enter the fingerprint or key ID to sign with: ")
+ filename = input("Enter the path and filename to sign: ")
+
+with open(filename, "rb") as f:
+ text = f.read()
+
+key = list(gpg.Context().keylist(pattern=logrus))
+
+with gpg.Context(armor=True, signers=key) as ca:
+ signed_data, result = ca.sign(text, mode=gpg.constants.sig.mode.NORMAL)
+ with open("{0}.asc".format(filename), "wb") as fa:
+ fa.write(signed_data)
+
+with gpg.Context(signers=key) as cg:
+ signed_data, result = cg.sign(text, mode=gpg.constants.sig.mode.NORMAL)
+ with open("{0}.gpg".format(filename), "wb") as fg:
+ fg.write(signed_data)
diff --git a/lang/python/examples/howto/sign-key.py b/lang/python/examples/howto/sign-key.py
new file mode 100755
index 0000000..b1afe13
--- /dev/null
+++ b/lang/python/examples/howto/sign-key.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+from __future__ import absolute_import, division, unicode_literals
+
+# Copyright (C) 2018 Ben McGinnes <ben@gnupg.org>
+#
+# 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 free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; either version 2.1 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 and the GNU
+# Lesser General Public Licensefor more details.
+#
+# You should have received a copy of the GNU General Public License and the GNU
+# Lesser General Public along with this program; if not, see
+# <http://www.gnu.org/licenses/>.
+
+import gpg
+import os.path
+
+print("""
+This script signs or certifies a key.
+
+The gpg-agent and pinentry are invoked to enter the passphrase.
+""")
+
+c = gpg.Context()
+
+homedir = input("Enter the GPG configuration directory path (optional): ")
+fpr0 = input("Enter the fingerprint of the key to sign: ")
+userid = input("Enter the UID to sign (case sensitive, optional): ")
+sig_type = input("Enter the certification type (local or normal): ")
+
+if homedir.startswith("~"):
+ if os.path.exists(os.path.expanduser(homedir)) is True:
+ c.home_dir = os.path.expanduser(homedir)
+ else:
+ pass
+elif os.path.exists(homedir) is True:
+ c.home_dir = homedir
+else:
+ pass
+
+fpr = "".join(fpr0.split())
+key = c.get_key(fpr, secret=False)
+
+if len(userid) > 0 and sig_type.lower() == "local":
+ c.key_sign(key, uids=userid, local=True)
+elif len(userid) > 0 and sig_type.lower() != "local":
+ c.key_sign(key, uids=userid)
+elif len(userid) == 0 and sig_type.lower() == "local":
+ c.key_sign(key, local=True)
+else:
+ c.key_sign(key)
diff --git a/lang/python/examples/howto/temp-homedir-config.py b/lang/python/examples/howto/temp-homedir-config.py
new file mode 100755
index 0000000..ddd7932
--- /dev/null
+++ b/lang/python/examples/howto/temp-homedir-config.py
@@ -0,0 +1,126 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+from __future__ import absolute_import, division, unicode_literals
+
+# Copyright (C) 2018 Ben McGinnes <ben@gnupg.org>
+#
+# 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 free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; either version 2.1 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 and the GNU
+# Lesser General Public Licensefor more details.
+#
+# You should have received a copy of the GNU General Public License and the GNU
+# Lesser General Public along with this program; if not, see
+# <http://www.gnu.org/licenses/>.
+
+import os
+import os.path
+import sys
+
+intro = """
+This script creates a temporary directory to use as a homedir for
+testing key generation tasks with the correct permissions, along
+with a gpg.conf file containing the same configuration options
+listed in the HOWTO.
+
+You may wish to change the order of the cipher preferences or
+remove those not relevant to your installation. These
+configuration parameters assume that all ciphers and digests are
+installed and available rather than limiting to the default
+ciphers and digests.
+
+The script prompts for a directory name to be installed as a hidden
+directory in the user's home directory on POSIX systems. So if you
+enter "gnupg-temp" on a Linux, BSD or OS X system, it will create
+"~/.gnupg-temp" (you do not need to enter the leading dot).
+
+This script has not been tested on Windows systems and may have
+unpredictable results. That said, it will not delete or copy over
+existing data.
+
+If the directory already exists, the script will terminate with a
+message telling you to specify a new directory name. There is no
+default directory name.
+"""
+
+gpgconf = """# gpg.conf settings for key generation:
+expert
+allow-freeform-uid
+allow-secret-key-import
+trust-model tofu+pgp
+tofu-default-policy unknown
+enable-large-rsa
+enable-dsa2
+cert-digest-algo SHA512
+default-preference-list TWOFISH CAMELLIA256 AES256 CAMELLIA192 AES192 CAMELLIA128 AES BLOWFISH IDEA CAST5 3DES SHA512 SHA384 SHA256 SHA224 RIPEMD160 SHA1 ZLIB BZIP2 ZIP Uncompressed
+personal-cipher-preferences TWOFISH CAMELLIA256 AES256 CAMELLIA192 AES192 CAMELLIA128 AES BLOWFISH IDEA CAST5 3DES
+personal-digest-preferences SHA512 SHA384 SHA256 SHA224 RIPEMD160 SHA1
+personal-compress-preferences ZLIB BZIP2 ZIP Uncompressed
+"""
+
+agentconf = """# gpg-agent.conf settings for key generation:
+default-cache-ttl 300
+"""
+
+if len(sys.argv) == 1:
+ print(intro)
+ new_homedir = input("Enter the temporary gnupg homedir name: ")
+elif len(sys.argv) == 2:
+ new_homedir = sys.argv[1]
+else:
+ new_homedir = " ".join(sys.argv[1:])
+
+userdir = os.path.expanduser("~")
+
+if new_homedir.startswith("~"):
+ new_homdir.replace("~", "")
+else:
+ pass
+
+if new_homedir.startswith("/"):
+ new_homdir.replace("/", "")
+else:
+ pass
+
+if new_homedir.startswith("."):
+ new_homdir.replace(".", "_")
+else:
+ pass
+
+if new_homedir.count(" ") > 0:
+ new_homedir.replace(" ", "_")
+else:
+ pass
+
+nh = "{0}/.{1}".format(userdir, new_homedir)
+
+if os.path.exists(nh) is True:
+ print("The {0} directory already exists.".format(nh))
+else:
+ print("Creating the {0} directory.".format(nh))
+ os.mkdir(nh)
+ os.chmod(nh, 0o700)
+ with open("{0}/{1}".format(nh, "gpg.conf"), "w") as f1:
+ f1.write(gpgconf)
+ os.chmod("{0}/{1}".format(nh, "gpg.conf"), 0o600)
+ with open("{0}/{1}".format(nh, "gpg-agent.conf"), "w") as f2:
+ f2.write(gpgconf)
+ os.chmod("{0}/{1}".format(nh, "gpg-agent.conf"), 0o600)
+ print("""You may now use the {0} directory as an alternative GPG homedir:
+
+gpg --homedir {0}
+gpg --homedir --full-gen-key
+
+Or with GPGME scripts, including the GPGME Python bindings.
+""")
diff --git a/lang/python/examples/howto/verify-signatures.py b/lang/python/examples/howto/verify-signatures.py
new file mode 100755
index 0000000..8aafc3b
--- /dev/null
+++ b/lang/python/examples/howto/verify-signatures.py
@@ -0,0 +1,64 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+from __future__ import absolute_import, division, unicode_literals
+
+# Copyright (C) 2018 Ben McGinnes <ben@gnupg.org>
+#
+# 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 free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; either version 2.1 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 and the GNU
+# Lesser General Public Licensefor more details.
+#
+# You should have received a copy of the GNU General Public License and the GNU
+# Lesser General Public along with this program; if not, see
+# <http://www.gnu.org/licenses/>.
+
+import gpg
+import sys
+import time
+
+"""
+Verifies a signed file which has been signed with a detached signature.
+"""
+
+if len(sys.argv) > 2:
+ filename = sys.argv[1]
+ sig_file = sys.argv[2]
+elif len(sys.argv) == 2:
+ filename = sys.argv[1]
+ sig_file = input("Enter the path and filename of the detached signature: ")
+else:
+ filename = input("Enter the path and filename to verify: ")
+ sig_file = input("Enter the path and filename of the detached signature: ")
+
+c = gpg.Context()
+
+try:
+ data, result = c.verify(open(filename), open(sig_file))
+ verified = True
+except gpg.errors.BadSignatures as e:
+ verified = False
+ print(e)
+
+if verified is True:
+ for i in range(len(result.signatures)):
+ sign = result.signatures[i]
+ print("""Good signature from:
+{0}
+with key {1}
+made at {2}
+""".format(c.get_key(sign.fpr).uids[0].uid, sign.fpr,
+ time.ctime(sign.timestamp)))
+else:
+ pass
diff --git a/lang/python/examples/howto/verify-signed-file.py b/lang/python/examples/howto/verify-signed-file.py
new file mode 100755
index 0000000..9f8702f
--- /dev/null
+++ b/lang/python/examples/howto/verify-signed-file.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+from __future__ import absolute_import, division, unicode_literals
+
+# Copyright (C) 2018 Ben McGinnes <ben@gnupg.org>
+#
+# 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 free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; either version 2.1 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 and the GNU
+# Lesser General Public Licensefor more details.
+#
+# You should have received a copy of the GNU General Public License and the GNU
+# Lesser General Public along with this program; if not, see
+# <http://www.gnu.org/licenses/>.
+
+import gpg
+import sys
+import time
+
+"""
+Verifies a signed file which has been signed with either NORMAL or CLEAR modes.
+"""
+
+if len(sys.argv) > 2:
+ filename = " ".join(sys.argv[1:])
+elif len(sys.argv) == 2:
+ filename = sys.argv[1]
+else:
+ filename = input("Enter the path and filename to sign: ")
+
+c = gpg.Context()
+
+try:
+ data, result = c.verify(open(filename))
+ verified = True
+except gpg.errors.BadSignatures as e:
+ verified = False
+ print(e)
+
+if verified is True:
+ for i in range(len(result.signatures)):
+ sign = result.signatures[i]
+ print("""Good signature from:
+{0}
+with key {1}
+made at {2}
+""".format(c.get_key(sign.fpr).uids[0].uid, sign.fpr,
+ time.ctime(sign.timestamp)))
+else:
+ pass
diff --git a/lang/python/examples/encrypt-to-all.py b/lang/python/examples/low_level-encrypt_to_all.py
index bad4220..bad4220 100755
--- a/lang/python/examples/encrypt-to-all.py
+++ b/lang/python/examples/low_level-encrypt_to_all.py
diff --git a/lang/python/setup.py.in b/lang/python/setup.py.in
index f9dda20..2595073 100755
--- a/lang/python/setup.py.in
+++ b/lang/python/setup.py.in
@@ -152,25 +152,8 @@ class BuildExtFirstHack(build):
sink.write(content)
def _generate_gpgme_h(self, source_name, sink_name):
- if up_to_date(source_name, sink_name):
- return
-
print("Using gpgme.h from {}".format(source_name))
-
- deprec_func = re.compile(r'^(.*typedef.*|.*\(.*\)|[^#]+\s+.+)'
- + r'\s*_GPGME_DEPRECATED(_OUTSIDE_GPGME)?\(.*\);\s*',
- re.S)
- line_break = re.compile(';|\\$|\\x0c|^\s*#|{')
-
- with open(sink_name, "w") as sink, open(source_name) as source:
- text = ''
- for line in source:
- text += re.sub(' class ', ' _py_obsolete_class ', line)
- if line_break.search(line):
- if not deprec_func.search(text):
- sink.write(text)
- text = ''
- sink.write(text)
+ shutil.copy2(source_name, sink_name)
def _generate_errors_i(self):
diff --git a/lang/python/tests/Makefile.am b/lang/python/tests/Makefile.am
index 25b15f2..3864f8b 100644
--- a/lang/python/tests/Makefile.am
+++ b/lang/python/tests/Makefile.am
@@ -18,8 +18,6 @@
GPG = gpg
GPG_AGENT = gpg-agent
-export GNUPGHOME := $(abs_builddir)
-export GPG_AGENT_INFO :=
test_srcdir = $(top_srcdir)/tests/gpg
@@ -79,7 +77,7 @@ xcheck: all
CLEANFILES = secring.gpg pubring.gpg pubring.kbx trustdb.gpg dirmngr.conf \
gpg-agent.conf pubring.kbx~ gpg.conf pubring.gpg~ \
random_seed .gpg-v21-migrated tofu.db \
- pubring-stamp private-keys-v1.d/gpg-sample.stamp
+ pubring-stamp gpg-sample.stamp
private_keys = \
$(test_srcdir)/13CD0F3BDF24BE53FE192D62F18737256FF6E4FD \
@@ -89,26 +87,25 @@ private_keys = \
$(test_srcdir)/7A030357C0F253A5BBCD282FFC4E521B37558F5C
clean-local:
- -$(top_srcdir)/tests/start-stop-agent --stop
+ -$(TESTS_ENVIRONMENT) $(top_srcdir)/tests/start-stop-agent --stop
-rm -fR -- private-keys-v1.d openpgp-revocs.d S.gpg-agent sshcontrol
BUILT_SOURCES = gpg.conf gpg-agent.conf pubring-stamp \
- private-keys-v1.d/gpg-sample.stamp
+ gpg-sample.stamp
-private-keys-v1.d/gpg-sample.stamp: $(private_keys)
- -gpgconf --kill all
+gpg-sample.stamp: $(private_keys)
+ -$(TESTS_ENVIRONMENT) gpgconf --kill all
$(MKDIR_P) ./private-keys-v1.d
for k in $(private_keys); do \
cp $$k private-keys-v1.d/$${k#$(test_srcdir)/}.key; \
done
- echo x > ./private-keys-v1.d/gpg-sample.stamp
+ echo x > ./gpg-sample.stamp
-pubring-stamp: $(test_srcdir)/pubdemo.asc \
- ./private-keys-v1.d/gpg-sample.stamp
- $(GPG) --batch --no-permission-warning \
+pubring-stamp: $(test_srcdir)/pubdemo.asc gpg-sample.stamp
+ $(TESTS_ENVIRONMENT) $(GPG) --batch --no-permission-warning \
--import $(test_srcdir)/pubdemo.asc
- -$(GPG) --batch --no-permission-warning \
+ -$(TESTS_ENVIRONMENT) $(GPG) --batch --no-permission-warning \
--import $(test_srcdir)/secdemo.asc
echo x > ./pubring-stamp
diff --git a/lang/python/tests/Makefile.in b/lang/python/tests/Makefile.in
index 89fcee2..c7512dd 100644
--- a/lang/python/tests/Makefile.in
+++ b/lang/python/tests/Makefile.in
@@ -375,7 +375,7 @@ EXTRA_DIST = support.py $(XTESTS) encrypt-only.asc sign-only.asc \
CLEANFILES = secring.gpg pubring.gpg pubring.kbx trustdb.gpg dirmngr.conf \
gpg-agent.conf pubring.kbx~ gpg.conf pubring.gpg~ \
random_seed .gpg-v21-migrated tofu.db \
- pubring-stamp private-keys-v1.d/gpg-sample.stamp
+ pubring-stamp gpg-sample.stamp
private_keys = \
$(test_srcdir)/13CD0F3BDF24BE53FE192D62F18737256FF6E4FD \
@@ -385,7 +385,7 @@ private_keys = \
$(test_srcdir)/7A030357C0F253A5BBCD282FFC4E521B37558F5C
BUILT_SOURCES = gpg.conf gpg-agent.conf pubring-stamp \
- private-keys-v1.d/gpg-sample.stamp
+ gpg-sample.stamp
all: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) all-am
@@ -582,8 +582,6 @@ uninstall-am:
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
tags-am uninstall uninstall-am
-export GNUPGHOME := $(abs_builddir)
-export GPG_AGENT_INFO :=
# XXX: Currently, one cannot override automake's 'check' target. As a
# workaround, we avoid defining 'TESTS', thus automake will not emit
@@ -601,22 +599,21 @@ xcheck: all
$(XTESTS)
clean-local:
- -$(top_srcdir)/tests/start-stop-agent --stop
+ -$(TESTS_ENVIRONMENT) $(top_srcdir)/tests/start-stop-agent --stop
-rm -fR -- private-keys-v1.d openpgp-revocs.d S.gpg-agent sshcontrol
-private-keys-v1.d/gpg-sample.stamp: $(private_keys)
- -gpgconf --kill all
+gpg-sample.stamp: $(private_keys)
+ -$(TESTS_ENVIRONMENT) gpgconf --kill all
$(MKDIR_P) ./private-keys-v1.d
for k in $(private_keys); do \
cp $$k private-keys-v1.d/$${k#$(test_srcdir)/}.key; \
done
- echo x > ./private-keys-v1.d/gpg-sample.stamp
+ echo x > ./gpg-sample.stamp
-pubring-stamp: $(test_srcdir)/pubdemo.asc \
- ./private-keys-v1.d/gpg-sample.stamp
- $(GPG) --batch --no-permission-warning \
+pubring-stamp: $(test_srcdir)/pubdemo.asc gpg-sample.stamp
+ $(TESTS_ENVIRONMENT) $(GPG) --batch --no-permission-warning \
--import $(test_srcdir)/pubdemo.asc
- -$(GPG) --batch --no-permission-warning \
+ -$(TESTS_ENVIRONMENT) $(GPG) --batch --no-permission-warning \
--import $(test_srcdir)/secdemo.asc
echo x > ./pubring-stamp
diff --git a/lang/qt/tests/Makefile.am b/lang/qt/tests/Makefile.am
index a662b4c..104672e 100644
--- a/lang/qt/tests/Makefile.am
+++ b/lang/qt/tests/Makefile.am
@@ -70,21 +70,19 @@ CLEANFILES = secring.gpg pubring.gpg pubring.kbx trustdb.gpg dirmngr.conf \
gpg.conf tofu.db
clean-local:
- -$(top_srcdir)/tests/start-stop-agent --stop
+ -$(TESTS_ENVIRONMENT) $(top_srcdir)/tests/start-stop-agent --stop
-rm -fR private-keys-v1.d crls.d
-export GNUPGHOME := $(abs_builddir)
-
pubring-stamp: $(top_srcdir)/tests/gpg/pubdemo.asc \
$(top_srcdir)/tests/gpg/secdemo.asc
- -gpgconf --kill all
+ -$(TESTS_ENVIRONMENT) gpgconf --kill all
echo "ignore-invalid-option allow-loopback-pinentry" > $(abs_builddir)/gpg-agent.conf
echo "allow-loopback-pinentry" >> gpg-agent.conf
echo "ignore-invalid-option pinentry-mode" > gpg.conf
echo "pinentry-mode loopback" >> gpg.conf
- $(GPG) --no-permission-warning \
+ $(TESTS_ENVIRONMENT) $(GPG) --no-permission-warning \
--import $(top_srcdir)/tests/gpg/pubdemo.asc
- $(GPG) --no-permission-warning \
+ $(TESTS_ENVIRONMENT) $(GPG) --no-permission-warning \
--passphrase "abc" \
--import $(top_srcdir)/tests/gpg/secdemo.asc
touch pubring-stamp
diff --git a/lang/qt/tests/Makefile.in b/lang/qt/tests/Makefile.in
index adf9bb1..075747f 100644
--- a/lang/qt/tests/Makefile.in
+++ b/lang/qt/tests/Makefile.in
@@ -958,21 +958,19 @@ uninstall-am:
clean-local:
- -$(top_srcdir)/tests/start-stop-agent --stop
+ -$(TESTS_ENVIRONMENT) $(top_srcdir)/tests/start-stop-agent --stop
-rm -fR private-keys-v1.d crls.d
-export GNUPGHOME := $(abs_builddir)
-
pubring-stamp: $(top_srcdir)/tests/gpg/pubdemo.asc \
$(top_srcdir)/tests/gpg/secdemo.asc
- -gpgconf --kill all
+ -$(TESTS_ENVIRONMENT) gpgconf --kill all
echo "ignore-invalid-option allow-loopback-pinentry" > $(abs_builddir)/gpg-agent.conf
echo "allow-loopback-pinentry" >> gpg-agent.conf
echo "ignore-invalid-option pinentry-mode" > gpg.conf
echo "pinentry-mode loopback" >> gpg.conf
- $(GPG) --no-permission-warning \
+ $(TESTS_ENVIRONMENT) $(GPG) --no-permission-warning \
--import $(top_srcdir)/tests/gpg/pubdemo.asc
- $(GPG) --no-permission-warning \
+ $(TESTS_ENVIRONMENT) $(GPG) --no-permission-warning \
--passphrase "abc" \
--import $(top_srcdir)/tests/gpg/secdemo.asc
touch pubring-stamp
diff --git a/lang/qt/tests/t-config.cpp b/lang/qt/tests/t-config.cpp
index e04a6bb..afbb4d1 100644
--- a/lang/qt/tests/t-config.cpp
+++ b/lang/qt/tests/t-config.cpp
@@ -39,6 +39,8 @@
#include "t-support.h"
#include "protocol.h"
#include "cryptoconfig.h"
+#include "engineinfo.h"
+
#include <unistd.h>
using namespace QGpgME;
@@ -51,7 +53,7 @@ private Q_SLOTS:
void testKeyserver()
{
// Repeatedly set a config value and clear it
- // this war broken at some point so it gets a
+ // this was broken at some point so it gets a
// unit test.
for (int i = 0; i < 10; i++) {
auto conf = cryptoConfig();
@@ -78,6 +80,36 @@ private Q_SLOTS:
}
}
+ void testDefault()
+ {
+ if (GpgME::engineInfo(GpgME::GpgEngine).engineVersion() < "2.2.0") {
+ // We are using compliance here and other options might also
+ // be unsupported in older versions.
+ return;
+ }
+ // First set compliance to de-vs
+ auto conf = cryptoConfig();
+ QVERIFY(conf);
+ auto entry = conf->entry(QStringLiteral("gpg"),
+ QStringLiteral("Configuration"),
+ QStringLiteral("compliance"));
+ QVERIFY(entry);
+ entry->setStringValue("de-vs");
+ conf->sync(true);
+ conf->clear();
+ entry = conf->entry(QStringLiteral("gpg"),
+ QStringLiteral("Configuration"),
+ QStringLiteral("compliance"));
+ QCOMPARE(entry->stringValue(), QStringLiteral("de-vs"));
+ entry->resetToDefault();
+ conf->sync(true);
+ conf->clear();
+ entry = conf->entry(QStringLiteral("gpg"),
+ QStringLiteral("Configuration"),
+ QStringLiteral("compliance"));
+ QCOMPARE(entry->stringValue(), QStringLiteral("gnupg"));
+ }
+
void initTestCase()
{
QGpgMETest::initTestCase();
diff --git a/src/Makefile.am b/src/Makefile.am
index ce6f1d4..c2d4a84 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -26,7 +26,7 @@ m4datadir = $(datadir)/aclocal
m4data_DATA = gpgme.m4
nodist_include_HEADERS = gpgme.h
-bin_PROGRAMS = gpgme-tool
+bin_PROGRAMS = gpgme-tool gpgme-json
if BUILD_W32_GLIB
ltlib_gpgme_glib = libgpgme-glib.la
@@ -95,13 +95,18 @@ if BUILD_W32_GLIB
libgpgme_glib_la_SOURCES = $(main_sources) w32-glib-io.c
endif
-# We use a global CFLAGS setting for all library
+# We use a global CFLAGS setting for all libraries
# versions, because then every object file is only compiled once.
AM_CFLAGS = @LIBASSUAN_CFLAGS@ @GLIB_CFLAGS@
gpgme_tool_SOURCES = gpgme-tool.c argparse.c argparse.h
gpgme_tool_LDADD = libgpgme.la @LIBASSUAN_LIBS@
+gpgme_json_SOURCES = gpgme-json.c cJSON.c cJSON.h
+gpgme_json_LDADD = -lm libgpgme.la $(GPG_ERROR_LIBS)
+# We use -no-install temporary during development.
+gpgme_json_LDFLAGS = -no-install
+
if HAVE_W32_SYSTEM
# Windows provides us with an endless stream of Tough Love. To spawn
diff --git a/src/Makefile.in b/src/Makefile.in
index dfdf550..5eac9e1 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -100,14 +100,14 @@ PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
-bin_PROGRAMS = gpgme-tool$(EXEEXT)
+bin_PROGRAMS = gpgme-tool$(EXEEXT) gpgme-json$(EXEEXT)
@HAVE_W32CE_SYSTEM_TRUE@am__append_1 = w32-ce.h w32-ce.c
@HAVE_W32CE_SYSTEM_FALSE@@HAVE_W32_SYSTEM_TRUE@libexec_PROGRAMS = gpgme-w32spawn$(EXEEXT)
subdir = src
DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
$(top_srcdir)/build-aux/mkinstalldirs \
$(srcdir)/versioninfo.rc.in $(srcdir)/gpgme.h.in \
- $(srcdir)/gpgme-config.in ttyname_r.c setenv.c stpcpy.c \
+ $(srcdir)/gpgme-config.in stpcpy.c setenv.c ttyname_r.c \
$(top_srcdir)/build-aux/depcomp
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
@@ -231,6 +231,13 @@ libgpgme_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(libgpgme_la_LDFLAGS) $(LDFLAGS) -o $@
PROGRAMS = $(bin_PROGRAMS) $(libexec_PROGRAMS)
+am_gpgme_json_OBJECTS = gpgme-json.$(OBJEXT) cJSON.$(OBJEXT)
+gpgme_json_OBJECTS = $(am_gpgme_json_OBJECTS)
+am__DEPENDENCIES_2 =
+gpgme_json_DEPENDENCIES = libgpgme.la $(am__DEPENDENCIES_2)
+gpgme_json_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(gpgme_json_LDFLAGS) $(LDFLAGS) -o $@
am_gpgme_tool_OBJECTS = gpgme-tool.$(OBJEXT) argparse.$(OBJEXT)
gpgme_tool_OBJECTS = $(am_gpgme_tool_OBJECTS)
gpgme_tool_DEPENDENCIES = libgpgme.la
@@ -273,10 +280,10 @@ am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
SOURCES = $(libgpgme_glib_la_SOURCES) $(libgpgme_la_SOURCES) \
- $(gpgme_tool_SOURCES) gpgme-w32spawn.c
+ $(gpgme_json_SOURCES) $(gpgme_tool_SOURCES) gpgme-w32spawn.c
DIST_SOURCES = $(am__libgpgme_glib_la_SOURCES_DIST) \
- $(am__libgpgme_la_SOURCES_DIST) $(gpgme_tool_SOURCES) \
- gpgme-w32spawn.c
+ $(am__libgpgme_la_SOURCES_DIST) $(gpgme_json_SOURCES) \
+ $(gpgme_tool_SOURCES) gpgme-w32spawn.c
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
@@ -551,11 +558,15 @@ main_sources = \
libgpgme_la_SOURCES = $(main_sources) $(system_components_not_extra)
@BUILD_W32_GLIB_TRUE@libgpgme_glib_la_SOURCES = $(main_sources) w32-glib-io.c
-# We use a global CFLAGS setting for all library
+# We use a global CFLAGS setting for all libraries
# versions, because then every object file is only compiled once.
AM_CFLAGS = @LIBASSUAN_CFLAGS@ @GLIB_CFLAGS@
gpgme_tool_SOURCES = gpgme-tool.c argparse.c argparse.h
gpgme_tool_LDADD = libgpgme.la @LIBASSUAN_LIBS@
+gpgme_json_SOURCES = gpgme-json.c cJSON.c cJSON.h
+gpgme_json_LDADD = -lm libgpgme.la $(GPG_ERROR_LIBS)
+# We use -no-install temporary during development.
+gpgme_json_LDFLAGS = -no-install
@HAVE_W32_SYSTEM_TRUE@RCCOMPILE = $(RC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES)
@HAVE_W32_SYSTEM_TRUE@LTRCCOMPILE = $(LIBTOOL) --mode=compile --tag=RC $(RCCOMPILE)
@HAVE_W32_SYSTEM_TRUE@SUFFIXES = .rc .lo
@@ -768,6 +779,10 @@ clean-libexecPROGRAMS:
echo " rm -f" $$list; \
rm -f $$list
+gpgme-json$(EXEEXT): $(gpgme_json_OBJECTS) $(gpgme_json_DEPENDENCIES) $(EXTRA_gpgme_json_DEPENDENCIES)
+ @rm -f gpgme-json$(EXEEXT)
+ $(AM_V_CCLD)$(gpgme_json_LINK) $(gpgme_json_OBJECTS) $(gpgme_json_LDADD) $(LIBS)
+
gpgme-tool$(EXEEXT): $(gpgme_tool_OBJECTS) $(gpgme_tool_DEPENDENCIES) $(EXTRA_gpgme_tool_DEPENDENCIES)
@rm -f gpgme-tool$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(gpgme_tool_OBJECTS) $(gpgme_tool_LDADD) $(LIBS)
@@ -824,6 +839,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/assuan-support.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ath.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/b64dec.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cJSON.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conversion.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/data-compat.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/data-fd.Plo@am__quote@
@@ -854,6 +870,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/get-env.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getauditlog.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpgconf.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpgme-json.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpgme-tool.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpgme-w32spawn.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpgme.Plo@am__quote@
diff --git a/src/cJSON.c b/src/cJSON.c
new file mode 100644
index 0000000..cf0cb13
--- /dev/null
+++ b/src/cJSON.c
@@ -0,0 +1,1404 @@
+/* cJSON.c - JSON parser in C.
+ * Copyright (c) 2009 Dave Gamble
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Note that this code has been modified from the original code taken
+ * from cjson-code-58.zip.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <float.h>
+#include <limits.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "cJSON.h"
+
+/* We use malloc function wrappers from gpgrt (aka libgpg-error). */
+#if 1
+# include <gpgrt.h>
+# define xtrymalloc(a) gpgrt_malloc ((a))
+# define xtrycalloc(a,b) gpgrt_calloc ((a), (b))
+# define xtrystrdup(a) gpgrt_strdup ((a))
+# define xfree(a) gpgrt_free ((a))
+#else
+# define xtrymalloc(a) malloc ((a))
+# define xtrycalloc(a,b) calloc ((a), (b))
+# define xtrystrdup(a) strdup ((a))
+# define xfree(a) free ((a))
+#endif
+
+
+static int
+cJSON_strcasecmp (const char *s1, const char *s2)
+{
+ if (!s1)
+ return (s1 == s2) ? 0 : 1;
+ if (!s2)
+ return 1;
+ for (; tolower (*(const unsigned char *)s1)
+ == tolower (*(const unsigned char *) s2); ++s1, ++s2)
+ if (*s1 == 0)
+ return 0;
+ return tolower (*(const unsigned char *) s1) -
+ tolower (*(const unsigned char *) s2);
+}
+
+/* Internal constructor. */
+static cJSON *
+cJSON_New_Item (void)
+{
+ return xtrycalloc (1, sizeof (cJSON));
+}
+
+/* Delete a cJSON structure. (Does not clobber ERRNO). */
+void
+cJSON_Delete (cJSON * c)
+{
+ cJSON *next;
+ int save_errno;
+
+ if (!c)
+ return;
+
+ save_errno = errno;
+ while (c)
+ {
+ next = c->next;
+ if (!(c->type & cJSON_IsReference) && c->child)
+ cJSON_Delete (c->child);
+ if (!(c->type & cJSON_IsReference) && c->valuestring)
+ xfree (c->valuestring);
+ if (c->string)
+ xfree (c->string);
+ xfree (c);
+ c = next;
+ }
+ errno = save_errno;
+}
+
+/* Parse the input text to generate a number, and populate the result
+ * into item. */
+static const char *
+parse_number (cJSON * item, const char *num)
+{
+ double n = 0, sign = 1, scale = 0;
+ int subscale = 0, signsubscale = 1;
+
+ if (*num == '-')
+ sign = -1, num++; /* Has sign? */
+ if (*num == '0')
+ num++; /* is zero */
+ if (*num >= '1' && *num <= '9')
+ do
+ n = (n * 10.0) + (*num++ - '0');
+ while (*num >= '0' && *num <= '9'); /* Number? */
+ if (*num == '.' && num[1] >= '0' && num[1] <= '9')
+ {
+ num++;
+ do
+ n = (n * 10.0) + (*num++ - '0'), scale--;
+ while (*num >= '0' && *num <= '9');
+ } /* Fractional part? */
+ if (*num == 'e' || *num == 'E') /* Exponent? */
+ {
+ num++;
+ if (*num == '+')
+ num++;
+ else if (*num == '-')
+ signsubscale = -1, num++; /* With sign? */
+ while (*num >= '0' && *num <= '9')
+ subscale = (subscale * 10) + (*num++ - '0'); /* Number? */
+ }
+
+ /* number = +/- number.fraction * 10^+/- exponent */
+ n = sign * n * pow (10.0, (scale + subscale * signsubscale));
+
+ item->valuedouble = n;
+ item->valueint = (int) n;
+ item->type = cJSON_Number;
+ return num;
+}
+
+/* Render the number nicely from the given item into a string. */
+static char *
+print_number (cJSON * item)
+{
+ char *str;
+ double d = item->valuedouble;
+ if (fabs (((double) item->valueint) - d) <= DBL_EPSILON && d <= INT_MAX
+ && d >= INT_MIN)
+ {
+ /* 2^64+1 can be represented in 21 chars. */
+ str = xtrymalloc (21);
+ if (str)
+ sprintf (str, "%d", item->valueint);
+ }
+ else
+ {
+ str = xtrymalloc (64); /* This is a nice tradeoff. */
+ if (str)
+ {
+ if (fabs (floor (d) - d) <= DBL_EPSILON && fabs (d) < 1.0e60)
+ sprintf (str, "%.0f", d);
+ else if (fabs (d) < 1.0e-6 || fabs (d) > 1.0e9)
+ sprintf (str, "%e", d);
+ else
+ sprintf (str, "%f", d);
+ }
+ }
+ return str;
+}
+
+static unsigned
+parse_hex4 (const char *str)
+{
+ unsigned h = 0;
+ if (*str >= '0' && *str <= '9')
+ h += (*str) - '0';
+ else if (*str >= 'A' && *str <= 'F')
+ h += 10 + (*str) - 'A';
+ else if (*str >= 'a' && *str <= 'f')
+ h += 10 + (*str) - 'a';
+ else
+ return 0;
+ h = h << 4;
+ str++;
+ if (*str >= '0' && *str <= '9')
+ h += (*str) - '0';
+ else if (*str >= 'A' && *str <= 'F')
+ h += 10 + (*str) - 'A';
+ else if (*str >= 'a' && *str <= 'f')
+ h += 10 + (*str) - 'a';
+ else
+ return 0;
+ h = h << 4;
+ str++;
+ if (*str >= '0' && *str <= '9')
+ h += (*str) - '0';
+ else if (*str >= 'A' && *str <= 'F')
+ h += 10 + (*str) - 'A';
+ else if (*str >= 'a' && *str <= 'f')
+ h += 10 + (*str) - 'a';
+ else
+ return 0;
+ h = h << 4;
+ str++;
+ if (*str >= '0' && *str <= '9')
+ h += (*str) - '0';
+ else if (*str >= 'A' && *str <= 'F')
+ h += 10 + (*str) - 'A';
+ else if (*str >= 'a' && *str <= 'f')
+ h += 10 + (*str) - 'a';
+ else
+ return 0;
+ return h;
+}
+
+/* Parse the input text into an unescaped cstring, and populate item. */
+static const unsigned char firstByteMark[7] =
+ { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+static const char *
+parse_string (cJSON * item, const char *str, const char **ep)
+{
+ const char *ptr = str + 1;
+ char *ptr2;
+ char *out;
+ int len = 0;
+ unsigned uc, uc2;
+ if (*str != '\"')
+ {
+ *ep = str;
+ return 0;
+ } /* not a string! */
+
+ while (*ptr != '\"' && *ptr && ++len)
+ if (*ptr++ == '\\')
+ ptr++; /* Skip escaped quotes. */
+
+ out = xtrymalloc (len + 1); /* This is how long we need for the
+ string, roughly. */
+ if (!out)
+ return 0;
+
+ ptr = str + 1;
+ ptr2 = out;
+ while (*ptr != '\"' && *ptr)
+ {
+ if (*ptr != '\\')
+ *ptr2++ = *ptr++;
+ else
+ {
+ ptr++;
+ switch (*ptr)
+ {
+ case 'b':
+ *ptr2++ = '\b';
+ break;
+ case 'f':
+ *ptr2++ = '\f';
+ break;
+ case 'n':
+ *ptr2++ = '\n';
+ break;
+ case 'r':
+ *ptr2++ = '\r';
+ break;
+ case 't':
+ *ptr2++ = '\t';
+ break;
+ case 'u': /* transcode utf16 to utf8. */
+ uc = parse_hex4 (ptr + 1);
+ ptr += 4; /* get the unicode char. */
+
+ if ((uc >= 0xDC00 && uc <= 0xDFFF) || uc == 0)
+ break; /* check for invalid. */
+
+ if (uc >= 0xD800 && uc <= 0xDBFF) /* UTF16 surrogate pairs. */
+ {
+ if (ptr[1] != '\\' || ptr[2] != 'u')
+ break; /* missing second-half of surrogate. */
+ uc2 = parse_hex4 (ptr + 3);
+ ptr += 6;
+ if (uc2 < 0xDC00 || uc2 > 0xDFFF)
+ break; /* invalid second-half of surrogate. */
+ uc = 0x10000 + (((uc & 0x3FF) << 10) | (uc2 & 0x3FF));
+ }
+
+ len = 4;
+ if (uc < 0x80)
+ len = 1;
+ else if (uc < 0x800)
+ len = 2;
+ else if (uc < 0x10000)
+ len = 3;
+ ptr2 += len;
+
+ switch (len)
+ {
+ case 4:
+ *--ptr2 = ((uc | 0x80) & 0xBF);
+ uc >>= 6;
+ case 3:
+ *--ptr2 = ((uc | 0x80) & 0xBF);
+ uc >>= 6;
+ case 2:
+ *--ptr2 = ((uc | 0x80) & 0xBF);
+ uc >>= 6;
+ case 1:
+ *--ptr2 = (uc | firstByteMark[len]);
+ }
+ ptr2 += len;
+ break;
+ default:
+ *ptr2++ = *ptr;
+ break;
+ }
+ ptr++;
+ }
+ }
+ *ptr2 = 0;
+ if (*ptr == '\"')
+ ptr++;
+ item->valuestring = out;
+ item->type = cJSON_String;
+ return ptr;
+}
+
+/* Render the cstring provided to an escaped version that can be printed. */
+static char *
+print_string_ptr (const char *str)
+{
+ const char *ptr;
+ char *ptr2, *out;
+ int len = 0;
+ unsigned char token;
+
+ if (!str)
+ return xtrystrdup ("");
+ ptr = str;
+ while ((token = *ptr) && ++len)
+ {
+ if (strchr ("\"\\\b\f\n\r\t", token))
+ len++;
+ else if (token < 32)
+ len += 5;
+ ptr++;
+ }
+
+ out = xtrymalloc (len + 3);
+ if (!out)
+ return 0;
+
+ ptr2 = out;
+ ptr = str;
+ *ptr2++ = '\"';
+ while (*ptr)
+ {
+ if ((unsigned char) *ptr > 31 && *ptr != '\"' && *ptr != '\\')
+ *ptr2++ = *ptr++;
+ else
+ {
+ *ptr2++ = '\\';
+ switch (token = *ptr++)
+ {
+ case '\\':
+ *ptr2++ = '\\';
+ break;
+ case '\"':
+ *ptr2++ = '\"';
+ break;
+ case '\b':
+ *ptr2++ = 'b';
+ break;
+ case '\f':
+ *ptr2++ = 'f';
+ break;
+ case '\n':
+ *ptr2++ = 'n';
+ break;
+ case '\r':
+ *ptr2++ = 'r';
+ break;
+ case '\t':
+ *ptr2++ = 't';
+ break;
+ default:
+ sprintf (ptr2, "u%04x", token);
+ ptr2 += 5;
+ break; /* escape and print */
+ }
+ }
+ }
+ *ptr2++ = '\"';
+ *ptr2++ = 0;
+ return out;
+}
+
+/* Invote print_string_ptr (which is useful) on an item. */
+static char *
+print_string (cJSON * item)
+{
+ return print_string_ptr (item->valuestring);
+}
+
+/* Predeclare these prototypes. */
+static const char *parse_value (cJSON * item, const char *value,
+ const char **ep);
+static char *print_value (cJSON * item, int depth, int fmt);
+static const char *parse_array (cJSON * item, const char *value,
+ const char **ep);
+static char *print_array (cJSON * item, int depth, int fmt);
+static const char *parse_object (cJSON * item, const char *value,
+ const char **ep);
+static char *print_object (cJSON * item, int depth, int fmt);
+
+/* Utility to jump whitespace and cr/lf */
+static const char *
+skip (const char *in)
+{
+ while (in && *in && (unsigned char) *in <= 32)
+ in++;
+ return in;
+}
+
+/* Parse an object - create a new root, and populate. */
+cJSON *
+cJSON_ParseWithOpts (const char *value, const char **return_parse_end,
+ int require_null_terminated, size_t *r_erroff)
+{
+ const char *end = 0;
+ const char *ep = 0;
+ cJSON *c;
+
+ if (r_erroff)
+ *r_erroff = 0;
+
+ c = cJSON_New_Item ();
+ if (!c)
+ return NULL; /* memory fail */
+
+ end = parse_value (c, skip (value), &ep);
+ if (!end)
+ {
+ cJSON_Delete (c);
+ errno = EINVAL;
+ if (r_erroff)
+ *r_erroff = ep - value;
+ return 0;
+ } /* parse failure. ep is set. */
+
+ /* if we require null-terminated JSON without appended garbage, skip
+ and then check for a null terminator */
+ if (require_null_terminated)
+ {
+ end = skip (end);
+ if (*end)
+ {
+ cJSON_Delete (c);
+ ep = end;
+ errno = EINVAL;
+ if (r_erroff)
+ *r_erroff = ep - value;
+ return 0;
+ }
+ }
+ if (return_parse_end)
+ *return_parse_end = end;
+ return c;
+}
+
+/* Default options for cJSON_Parse */
+cJSON *
+cJSON_Parse (const char *value, size_t *r_erroff)
+{
+ return cJSON_ParseWithOpts (value, 0, 0, r_erroff);
+}
+
+/* Render a cJSON item/entity/structure to text. */
+char *
+cJSON_Print (cJSON * item)
+{
+ return print_value (item, 0, 1);
+}
+
+char *
+cJSON_PrintUnformatted (cJSON * item)
+{
+ return print_value (item, 0, 0);
+}
+
+/* Parser core - when encountering text, process appropriately. */
+static const char *
+parse_value (cJSON * item, const char *value, const char **ep)
+{
+ if (!value)
+ return 0; /* Fail on null. */
+ if (!strncmp (value, "null", 4))
+ {
+ item->type = cJSON_NULL;
+ return value + 4;
+ }
+ if (!strncmp (value, "false", 5))
+ {
+ item->type = cJSON_False;
+ return value + 5;
+ }
+ if (!strncmp (value, "true", 4))
+ {
+ item->type = cJSON_True;
+ item->valueint = 1;
+ return value + 4;
+ }
+ if (*value == '\"')
+ {
+ return parse_string (item, value, ep);
+ }
+ if (*value == '-' || (*value >= '0' && *value <= '9'))
+ {
+ return parse_number (item, value);
+ }
+ if (*value == '[')
+ {
+ return parse_array (item, value, ep);
+ }
+ if (*value == '{')
+ {
+ return parse_object (item, value, ep);
+ }
+
+ *ep = value;
+ return 0; /* failure. */
+}
+
+/* Render a value to text. */
+static char *
+print_value (cJSON * item, int depth, int fmt)
+{
+ char *out = 0;
+ if (!item)
+ return 0;
+ switch ((item->type) & 255)
+ {
+ case cJSON_NULL:
+ out = xtrystrdup ("null");
+ break;
+ case cJSON_False:
+ out = xtrystrdup ("false");
+ break;
+ case cJSON_True:
+ out = xtrystrdup ("true");
+ break;
+ case cJSON_Number:
+ out = print_number (item);
+ break;
+ case cJSON_String:
+ out = print_string (item);
+ break;
+ case cJSON_Array:
+ out = print_array (item, depth, fmt);
+ break;
+ case cJSON_Object:
+ out = print_object (item, depth, fmt);
+ break;
+ }
+ return out;
+}
+
+/* Build an array from input text. */
+static const char *
+parse_array (cJSON * item, const char *value, const char **ep)
+{
+ cJSON *child;
+ if (*value != '[')
+ {
+ *ep = value;
+ return 0;
+ } /* not an array! */
+
+ item->type = cJSON_Array;
+ value = skip (value + 1);
+ if (*value == ']')
+ return value + 1; /* empty array. */
+
+ item->child = child = cJSON_New_Item ();
+ if (!item->child)
+ return 0; /* memory fail */
+ /* skip any spacing, get the value. */
+ value = skip (parse_value (child, skip (value), ep));
+ if (!value)
+ return 0;
+
+ while (*value == ',')
+ {
+ cJSON *new_item;
+ if (!(new_item = cJSON_New_Item ()))
+ return 0; /* memory fail */
+ child->next = new_item;
+ new_item->prev = child;
+ child = new_item;
+ value = skip (parse_value (child, skip (value + 1), ep));
+ if (!value)
+ return 0; /* memory fail */
+ }
+
+ if (*value == ']')
+ return value + 1; /* end of array */
+ *ep = value;
+ return 0; /* malformed. */
+}
+
+/* Render an array to text */
+static char *
+print_array (cJSON * item, int depth, int fmt)
+{
+ char **entries;
+ char *out = 0, *ptr, *ret;
+ int len = 5;
+ cJSON *child = item->child;
+ int numentries = 0, i = 0, fail = 0;
+
+ /* How many entries in the array? */
+ while (child)
+ numentries++, child = child->next;
+ /* Explicitly handle numentries==0 */
+ if (!numentries)
+ {
+ out = xtrymalloc (3);
+ if (out)
+ strcpy (out, "[]");
+ return out;
+ }
+ /* Allocate an array to hold the values for each */
+ entries = xtrymalloc (numentries * sizeof (char *));
+ if (!entries)
+ return 0;
+ memset (entries, 0, numentries * sizeof (char *));
+ /* Retrieve all the results: */
+ child = item->child;
+ while (child && !fail)
+ {
+ ret = print_value (child, depth + 1, fmt);
+ entries[i++] = ret;
+ if (ret)
+ len += strlen (ret) + 2 + (fmt ? 1 : 0);
+ else
+ fail = 1;
+ child = child->next;
+ }
+
+ /* If we didn't fail, try to xtrymalloc the output string */
+ if (!fail)
+ out = xtrymalloc (len);
+ /* If that fails, we fail. */
+ if (!out)
+ fail = 1;
+
+ /* Handle failure. */
+ if (fail)
+ {
+ for (i = 0; i < numentries; i++)
+ if (entries[i])
+ xfree (entries[i]);
+ xfree (entries);
+ return 0;
+ }
+
+ /* Compose the output array. */
+ *out = '[';
+ ptr = out + 1;
+ *ptr = 0;
+ for (i = 0; i < numentries; i++)
+ {
+ strcpy (ptr, entries[i]);
+ ptr += strlen (entries[i]);
+ if (i != numentries - 1)
+ {
+ *ptr++ = ',';
+ if (fmt)
+ *ptr++ = ' ';
+ *ptr = 0;
+ }
+ xfree (entries[i]);
+ }
+ xfree (entries);
+ *ptr++ = ']';
+ *ptr++ = 0;
+ return out;
+}
+
+/* Build an object from the text. */
+static const char *
+parse_object (cJSON * item, const char *value, const char **ep)
+{
+ cJSON *child;
+ if (*value != '{')
+ {
+ *ep = value;
+ return 0;
+ } /* not an object! */
+
+ item->type = cJSON_Object;
+ value = skip (value + 1);
+ if (*value == '}')
+ return value + 1; /* empty array. */
+
+ item->child = child = cJSON_New_Item ();
+ if (!item->child)
+ return 0;
+ value = skip (parse_string (child, skip (value), ep));
+ if (!value)
+ return 0;
+ child->string = child->valuestring;
+ child->valuestring = 0;
+ if (*value != ':')
+ {
+ *ep = value;
+ return 0;
+ } /* fail! */
+ /* skip any spacing, get the value. */
+ value = skip (parse_value (child, skip (value + 1), ep));
+ if (!value)
+ return 0;
+
+ while (*value == ',')
+ {
+ cJSON *new_item;
+ if (!(new_item = cJSON_New_Item ()))
+ return 0; /* memory fail */
+ child->next = new_item;
+ new_item->prev = child;
+ child = new_item;
+ value = skip (parse_string (child, skip (value + 1), ep));
+ if (!value)
+ return 0;
+ child->string = child->valuestring;
+ child->valuestring = 0;
+ if (*value != ':')
+ {
+ *ep = value;
+ return 0;
+ } /* fail! */
+ /* skip any spacing, get the value. */
+ value = skip (parse_value (child, skip (value + 1), ep));
+ if (!value)
+ return 0;
+ }
+
+ if (*value == '}')
+ return value + 1; /* end of array */
+ *ep = value;
+ return 0; /* malformed. */
+}
+
+/* Render an object to text. */
+static char *
+print_object (cJSON * item, int depth, int fmt)
+{
+ char **entries = 0, **names = 0;
+ char *out = 0, *ptr, *ret, *str;
+ int len = 7, i = 0, j;
+ cJSON *child = item->child;
+ int numentries = 0, fail = 0;
+ /* Count the number of entries. */
+ while (child)
+ numentries++, child = child->next;
+ /* Explicitly handle empty object case */
+ if (!numentries)
+ {
+ out = xtrymalloc (fmt ? depth + 4 : 3);
+ if (!out)
+ return 0;
+ ptr = out;
+ *ptr++ = '{';
+ if (fmt)
+ {
+ *ptr++ = '\n';
+ for (i = 0; i < depth - 1; i++)
+ *ptr++ = '\t';
+ }
+ *ptr++ = '}';
+ *ptr++ = 0;
+ return out;
+ }
+ /* Allocate space for the names and the objects */
+ entries = xtrymalloc (numentries * sizeof (char *));
+ if (!entries)
+ return 0;
+ names = xtrymalloc (numentries * sizeof (char *));
+ if (!names)
+ {
+ xfree (entries);
+ return 0;
+ }
+ memset (entries, 0, sizeof (char *) * numentries);
+ memset (names, 0, sizeof (char *) * numentries);
+
+ /* Collect all the results into our arrays: */
+ child = item->child;
+ depth++;
+ if (fmt)
+ len += depth;
+ while (child)
+ {
+ names[i] = str = print_string_ptr (child->string);
+ entries[i++] = ret = print_value (child, depth, fmt);
+ if (str && ret)
+ len += strlen (ret) + strlen (str) + 2 + (fmt ? 2 + depth : 0);
+ else
+ fail = 1;
+ child = child->next;
+ }
+
+ /* Try to allocate the output string */
+ if (!fail)
+ out = xtrymalloc (len);
+ if (!out)
+ fail = 1;
+
+ /* Handle failure */
+ if (fail)
+ {
+ for (i = 0; i < numentries; i++)
+ {
+ if (names[i])
+ xfree (names[i]);
+ if (entries[i])
+ xfree (entries[i]);
+ }
+ xfree (names);
+ xfree (entries);
+ return 0;
+ }
+
+ /* Compose the output: */
+ *out = '{';
+ ptr = out + 1;
+ if (fmt)
+ *ptr++ = '\n';
+ *ptr = 0;
+ for (i = 0; i < numentries; i++)
+ {
+ if (fmt)
+ for (j = 0; j < depth; j++)
+ *ptr++ = '\t';
+ strcpy (ptr, names[i]);
+ ptr += strlen (names[i]);
+ *ptr++ = ':';
+ if (fmt)
+ *ptr++ = '\t';
+ strcpy (ptr, entries[i]);
+ ptr += strlen (entries[i]);
+ if (i != numentries - 1)
+ *ptr++ = ',';
+ if (fmt)
+ *ptr++ = '\n';
+ *ptr = 0;
+ xfree (names[i]);
+ xfree (entries[i]);
+ }
+
+ xfree (names);
+ xfree (entries);
+ if (fmt)
+ for (i = 0; i < depth - 1; i++)
+ *ptr++ = '\t';
+ *ptr++ = '}';
+ *ptr++ = 0;
+ return out;
+}
+
+/* Get Array size/item / object item. */
+int
+cJSON_GetArraySize (cJSON * array)
+{
+ cJSON *c = array->child;
+ int i = 0;
+ while (c)
+ i++, c = c->next;
+ return i;
+}
+
+cJSON *
+cJSON_GetArrayItem (cJSON * array, int item)
+{
+ cJSON *c = array->child;
+ while (c && item > 0)
+ item--, c = c->next;
+ return c;
+}
+
+cJSON *
+cJSON_GetObjectItem (cJSON * object, const char *string)
+{
+ cJSON *c = object->child;
+ while (c && cJSON_strcasecmp (c->string, string))
+ c = c->next;
+ return c;
+}
+
+/* Utility for array list handling. */
+static void
+suffix_object (cJSON * prev, cJSON * item)
+{
+ prev->next = item;
+ item->prev = prev;
+}
+
+/* Utility for handling references. */
+static cJSON *
+create_reference (cJSON * item)
+{
+ cJSON *ref = cJSON_New_Item ();
+ if (!ref)
+ return 0;
+ memcpy (ref, item, sizeof (cJSON));
+ ref->string = 0;
+ ref->type |= cJSON_IsReference;
+ ref->next = ref->prev = 0;
+ return ref;
+}
+
+/* Add item to array/object. */
+void
+cJSON_AddItemToArray (cJSON * array, cJSON * item)
+{
+ cJSON *c = array->child;
+ if (!item)
+ return;
+ if (!c)
+ {
+ array->child = item;
+ }
+ else
+ {
+ while (c && c->next)
+ c = c->next;
+ suffix_object (c, item);
+ }
+}
+
+cJSON *
+cJSON_AddItemToObject (cJSON * object, const char *string, cJSON * item)
+{
+ char *tmp;
+
+ if (!item)
+ return 0;
+ tmp = xtrystrdup (string);
+ if (!tmp)
+ return NULL;
+
+ if (item->string)
+ xfree (item->string);
+ item->string = tmp;
+ cJSON_AddItemToArray (object, item);
+ return object;
+}
+
+cJSON *
+cJSON_AddNullToObject (cJSON *object, const char *name)
+{
+ cJSON *obj, *tmp;
+
+ tmp = cJSON_CreateNull ();
+ if (!tmp)
+ return NULL;
+ obj = cJSON_AddItemToObject(object, name, tmp);
+ if (!obj)
+ cJSON_Delete (tmp);
+ return obj;
+}
+
+cJSON *
+cJSON_AddTrueToObject (cJSON *object, const char *name)
+{
+ cJSON *obj, *tmp;
+
+ tmp = cJSON_CreateTrue ();
+ if (!tmp)
+ return NULL;
+ obj = cJSON_AddItemToObject(object, name, tmp);
+ if (!obj)
+ cJSON_Delete (tmp);
+ return obj;
+}
+
+cJSON *
+cJSON_AddFalseToObject (cJSON *object, const char *name)
+{
+ cJSON *obj, *tmp;
+
+ tmp = cJSON_CreateFalse ();
+ if (!tmp)
+ return NULL;
+ obj = cJSON_AddItemToObject(object, name, tmp);
+ if (!obj)
+ cJSON_Delete (tmp);
+ return obj;
+}
+
+cJSON *
+cJSON_AddBoolToObject (cJSON *object, const char *name, int b)
+{
+ cJSON *obj, *tmp;
+
+ tmp = cJSON_CreateBool (b);
+ if (!tmp)
+ return NULL;
+ obj = cJSON_AddItemToObject(object, name, tmp);
+ if (!obj)
+ cJSON_Delete (tmp);
+ return obj;
+}
+
+cJSON *
+cJSON_AddNumberToObject (cJSON *object, const char *name, double num)
+{
+ cJSON *obj, *tmp;
+
+ tmp = cJSON_CreateNumber (num);
+ if (!tmp)
+ return NULL;
+ obj = cJSON_AddItemToObject(object, name, tmp);
+ if (!obj)
+ cJSON_Delete (tmp);
+ return obj;
+}
+
+cJSON *
+cJSON_AddStringToObject (cJSON *object, const char *name, const char *string)
+{
+ cJSON *obj, *tmp;
+
+ tmp = cJSON_CreateString (string);
+ if (!tmp)
+ return NULL;
+ obj = cJSON_AddItemToObject(object, name, tmp);
+ if (!obj)
+ cJSON_Delete (tmp);
+ return obj;
+}
+
+void
+cJSON_AddItemReferenceToArray (cJSON * array, cJSON * item)
+{
+ cJSON_AddItemToArray (array, create_reference (item));
+}
+
+void
+cJSON_AddItemReferenceToObject (cJSON * object, const char *string,
+ cJSON * item)
+{
+ cJSON_AddItemToObject (object, string, create_reference (item));
+}
+
+cJSON *
+cJSON_DetachItemFromArray (cJSON * array, int which)
+{
+ cJSON *c = array->child;
+ while (c && which > 0)
+ c = c->next, which--;
+ if (!c)
+ return 0;
+ if (c->prev)
+ c->prev->next = c->next;
+ if (c->next)
+ c->next->prev = c->prev;
+ if (c == array->child)
+ array->child = c->next;
+ c->prev = c->next = 0;
+ return c;
+}
+
+void
+cJSON_DeleteItemFromArray (cJSON * array, int which)
+{
+ cJSON_Delete (cJSON_DetachItemFromArray (array, which));
+}
+
+cJSON *
+cJSON_DetachItemFromObject (cJSON * object, const char *string)
+{
+ int i = 0;
+ cJSON *c = object->child;
+ while (c && cJSON_strcasecmp (c->string, string))
+ i++, c = c->next;
+ if (c)
+ return cJSON_DetachItemFromArray (object, i);
+ return 0;
+}
+
+void
+cJSON_DeleteItemFromObject (cJSON * object, const char *string)
+{
+ cJSON_Delete (cJSON_DetachItemFromObject (object, string));
+}
+
+/* Replace array/object items with new ones. */
+void
+cJSON_ReplaceItemInArray (cJSON * array, int which, cJSON * newitem)
+{
+ cJSON *c = array->child;
+ while (c && which > 0)
+ c = c->next, which--;
+ if (!c)
+ return;
+ newitem->next = c->next;
+ newitem->prev = c->prev;
+ if (newitem->next)
+ newitem->next->prev = newitem;
+ if (c == array->child)
+ array->child = newitem;
+ else
+ newitem->prev->next = newitem;
+ c->next = c->prev = 0;
+ cJSON_Delete (c);
+}
+
+void
+cJSON_ReplaceItemInObject (cJSON * object, const char *string,
+ cJSON * newitem)
+{
+ int i = 0;
+ cJSON *c = object->child;
+ while (c && cJSON_strcasecmp (c->string, string))
+ i++, c = c->next;
+ if (c)
+ {
+ newitem->string = xtrystrdup (string);
+ cJSON_ReplaceItemInArray (object, i, newitem);
+ }
+}
+
+/* Create basic types: */
+cJSON *
+cJSON_CreateNull (void)
+{
+ cJSON *item = cJSON_New_Item ();
+ if (item)
+ item->type = cJSON_NULL;
+ return item;
+}
+
+cJSON *
+cJSON_CreateTrue (void)
+{
+ cJSON *item = cJSON_New_Item ();
+ if (item)
+ item->type = cJSON_True;
+ return item;
+}
+
+cJSON *
+cJSON_CreateFalse (void)
+{
+ cJSON *item = cJSON_New_Item ();
+ if (item)
+ item->type = cJSON_False;
+ return item;
+}
+
+cJSON *
+cJSON_CreateBool (int b)
+{
+ cJSON *item = cJSON_New_Item ();
+ if (item)
+ item->type = b ? cJSON_True : cJSON_False;
+ return item;
+}
+
+cJSON *
+cJSON_CreateNumber (double num)
+{
+ cJSON *item = cJSON_New_Item ();
+ if (item)
+ {
+ item->type = cJSON_Number;
+ item->valuedouble = num;
+ item->valueint = (int) num;
+ }
+ return item;
+}
+
+cJSON *
+cJSON_CreateString (const char *string)
+{
+ cJSON *item = cJSON_New_Item ();
+ if (item)
+ {
+ item->type = cJSON_String;
+ item->valuestring = xtrystrdup (string);
+ }
+ return item;
+}
+
+cJSON *
+cJSON_CreateStringConvey (char *string)
+{
+ cJSON *item = cJSON_New_Item ();
+ if (item)
+ {
+ item->type = cJSON_String;
+ item->valuestring = string;
+ }
+ return item;
+}
+
+cJSON *
+cJSON_CreateArray (void)
+{
+ cJSON *item = cJSON_New_Item ();
+ if (item)
+ item->type = cJSON_Array;
+ return item;
+}
+
+cJSON *
+cJSON_CreateObject (void)
+{
+ cJSON *item = cJSON_New_Item ();
+ if (item)
+ item->type = cJSON_Object;
+ return item;
+}
+
+/* Create Arrays: */
+cJSON *
+cJSON_CreateIntArray (const int *numbers, int count)
+{
+ int i;
+ cJSON *n = 0, *p = 0, *a = cJSON_CreateArray ();
+ for (i = 0; a && i < count; i++)
+ {
+ n = cJSON_CreateNumber (numbers[i]);
+ if (!i)
+ a->child = n;
+ else
+ suffix_object (p, n);
+ p = n;
+ }
+ return a;
+}
+
+cJSON *
+cJSON_CreateFloatArray (const float *numbers, int count)
+{
+ int i;
+ cJSON *n = 0, *p = 0, *a = cJSON_CreateArray ();
+ for (i = 0; a && i < count; i++)
+ {
+ n = cJSON_CreateNumber (numbers[i]);
+ if (!i)
+ a->child = n;
+ else
+ suffix_object (p, n);
+ p = n;
+ }
+ return a;
+}
+
+cJSON *
+cJSON_CreateDoubleArray (const double *numbers, int count)
+{
+ int i;
+ cJSON *n = 0, *p = 0, *a = cJSON_CreateArray ();
+ for (i = 0; a && i < count; i++)
+ {
+ n = cJSON_CreateNumber (numbers[i]);
+ if (!i)
+ a->child = n;
+ else
+ suffix_object (p, n);
+ p = n;
+ }
+ return a;
+}
+
+cJSON *
+cJSON_CreateStringArray (const char **strings, int count)
+{
+ int i;
+ cJSON *n = 0, *p = 0, *a = cJSON_CreateArray ();
+ for (i = 0; a && i < count; i++)
+ {
+ n = cJSON_CreateString (strings[i]);
+ if (!i)
+ a->child = n;
+ else
+ suffix_object (p, n);
+ p = n;
+ }
+ return a;
+}
+
+/* Duplication */
+cJSON *
+cJSON_Duplicate (cJSON * item, int recurse)
+{
+ cJSON *newitem, *cptr, *nptr = 0, *newchild;
+ /* Bail on bad ptr */
+ if (!item)
+ return 0;
+ /* Create new item */
+ newitem = cJSON_New_Item ();
+ if (!newitem)
+ return 0;
+ /* Copy over all vars */
+ newitem->type = item->type & (~cJSON_IsReference), newitem->valueint =
+ item->valueint, newitem->valuedouble = item->valuedouble;
+ if (item->valuestring)
+ {
+ newitem->valuestring = xtrystrdup (item->valuestring);
+ if (!newitem->valuestring)
+ {
+ cJSON_Delete (newitem);
+ return 0;
+ }
+ }
+ if (item->string)
+ {
+ newitem->string = xtrystrdup (item->string);
+ if (!newitem->string)
+ {
+ cJSON_Delete (newitem);
+ return 0;
+ }
+ }
+ /* If non-recursive, then we're done! */
+ if (!recurse)
+ return newitem;
+ /* Walk the ->next chain for the child. */
+ cptr = item->child;
+ while (cptr)
+ {
+ /* Duplicate (with recurse) each item in the ->next chain */
+ newchild = cJSON_Duplicate (cptr, 1);
+ if (!newchild)
+ {
+ cJSON_Delete (newitem);
+ return 0;
+ }
+ if (nptr)
+ {
+ /* If newitem->child already set,
+ * then crosswire ->prev and ->next and move on. */
+ nptr->next = newchild, newchild->prev = nptr;
+ nptr = newchild;
+ }
+ else
+ {
+ /* Set newitem->child and move to it. */
+ newitem->child = newchild;
+ nptr = newchild;
+ }
+ cptr = cptr->next;
+ }
+ return newitem;
+}
+
+void
+cJSON_Minify (char *json)
+{
+ char *into = json;
+ while (*json)
+ {
+ if (*json == ' ')
+ json++;
+ else if (*json == '\t')
+ json++; /* Whitespace characters. */
+ else if (*json == '\r')
+ json++;
+ else if (*json == '\n')
+ json++;
+ else if (*json == '/' && json[1] == '/')
+ while (*json && *json != '\n')
+ json++; /* Double-slash comments, to end of line. */
+ else if (*json == '/' && json[1] == '*')
+ {
+ while (*json && !(*json == '*' && json[1] == '/'))
+ json++;
+ json += 2;
+ } /* Multiline comments. */
+ else if (*json == '\"')
+ {
+ *into++ = *json++;
+ while (*json && *json != '\"')
+ {
+ if (*json == '\\')
+ *into++ = *json++;
+ *into++ = *json++;
+ }
+ *into++ = *json++;
+ } /* String literals, which are \" sensitive. */
+ else
+ *into++ = *json++; /* All other characters. */
+ }
+ *into = 0; /* and null-terminate. */
+}
diff --git a/src/cJSON.h b/src/cJSON.h
new file mode 100644
index 0000000..a200c31
--- /dev/null
+++ b/src/cJSON.h
@@ -0,0 +1,187 @@
+/* cJSON.h
+ * Copyright (c) 2009 Dave Gamble
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Note that this code has been modified from the original code taken
+ * from cjson-code-58.zip.
+ */
+
+#ifndef cJSON_h
+#define cJSON_h
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0 /*(to make Emacs auto-indent happy)*/
+}
+#endif
+#endif
+
+/* cJSON Types: */
+#define cJSON_False 0
+#define cJSON_True 1
+#define cJSON_NULL 2
+#define cJSON_Number 3
+#define cJSON_String 4
+#define cJSON_Array 5
+#define cJSON_Object 6
+
+#define cJSON_IsReference 256
+
+/* The cJSON structure: */
+typedef struct cJSON
+{
+ /* next/prev allow you to walk array/object chains. Alternatively,
+ use GetArraySize/GetArrayItem/GetObjectItem */
+ struct cJSON *next, *prev;
+
+ /* An array or object item will have a child pointer pointing to a
+ chain of the items in the array/object. */
+ struct cJSON *child;
+
+ int type; /* The type of the item, as above. */
+
+ char *valuestring; /* The item's string, if type==cJSON_String */
+ int valueint; /* The item's number, if type==cJSON_Number */
+ double valuedouble; /* The item's number, if type==cJSON_Number */
+
+ /* The item's name string, if this item is the child of, or is in
+ the list of subitems of an object. */
+ char *string;
+} cJSON;
+
+typedef struct cJSON *cjson_t;
+
+/* Macros to test the type of an object. */
+#define cjson_is_boolean(a) (!((a)->type & ~1))
+#define cjson_is_false(a) ((a)->type == cJSON_False)
+#define cjson_is_true(a) ((a)->type == cJSON_True)
+#define cjson_is_null(a) ((a)->type == cJSON_NULL)
+#define cjson_is_number(a) ((a)->type == cJSON_Number)
+#define cjson_is_string(a) ((a)->type == cJSON_String)
+#define cjson_is_array(a) ((a)->type == cJSON_Array)
+#define cjson_is_object(a) ((a)->type == cJSON_Object)
+
+/* Supply a block of JSON, and this returns a cJSON object you can
+ interrogate. Call cJSON_Delete when finished. */
+extern cJSON *cJSON_Parse(const char *value, size_t *r_erroff);
+
+/* Render a cJSON entity to text for transfer/storage. Free the char*
+ when finished. */
+extern char *cJSON_Print(cJSON *item);
+
+/* Render a cJSON entity to text for transfer/storage without any
+ formatting. Free the char* when finished. */
+extern char *cJSON_PrintUnformatted(cJSON *item);
+
+/* Delete a cJSON entity and all subentities. */
+extern void cJSON_Delete(cJSON *c);
+
+/* Returns the number of items in an array (or object). */
+extern int cJSON_GetArraySize(cJSON *array);
+
+/* Retrieve item number "item" from array "array". Returns NULL if
+ unsuccessful. */
+extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);
+
+/* Get item "string" from object. Case insensitive. */
+extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
+
+/* These calls create a cJSON item of the appropriate type. */
+extern cJSON *cJSON_CreateNull(void);
+extern cJSON *cJSON_CreateTrue(void);
+extern cJSON *cJSON_CreateFalse(void);
+extern cJSON *cJSON_CreateBool(int b);
+extern cJSON *cJSON_CreateNumber(double num);
+extern cJSON *cJSON_CreateString(const char *string);
+extern cJSON *cJSON_CreateStringConvey (char *string);
+extern cJSON *cJSON_CreateArray(void);
+extern cJSON *cJSON_CreateObject(void);
+
+/* These utilities create an Array of count items. */
+extern cJSON *cJSON_CreateIntArray(const int *numbers,int count);
+extern cJSON *cJSON_CreateFloatArray(const float *numbers,int count);
+extern cJSON *cJSON_CreateDoubleArray(const double *numbers,int count);
+extern cJSON *cJSON_CreateStringArray(const char **strings,int count);
+
+/* Append item to the specified array. */
+extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
+
+/* Append item to the specified object. */
+extern cJSON *cJSON_AddItemToObject(cJSON *object, const char *name,
+ cJSON *item);
+extern cJSON *cJSON_AddNullToObject (cJSON *object, const char *name);
+extern cJSON *cJSON_AddTrueToObject (cJSON *object, const char *name);
+extern cJSON *cJSON_AddFalseToObject (cJSON *object, const char *name);
+extern cJSON *cJSON_AddBoolToObject (cJSON *object, const char *name, int b);
+extern cJSON *cJSON_AddNumberToObject (cJSON *object, const char *name,
+ double num);
+extern cJSON *cJSON_AddStringToObject (cJSON *object, const char *name,
+ const char *string);
+
+/* Append reference to item to the specified array/object. Use this
+ when you want to add an existing cJSON to a new cJSON, but don't
+ want to corrupt your existing cJSON. */
+extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
+extern void cJSON_AddItemReferenceToObject(cJSON *object,
+ const char *string,cJSON *item);
+
+/* Remove/Detatch items from Arrays/Objects. */
+extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which);
+extern void cJSON_DeleteItemFromArray(cJSON *array,int which);
+extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string);
+extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string);
+
+/* Update array items. */
+extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem);
+extern void cJSON_ReplaceItemInObject(cJSON *object,
+ const char *string, cJSON *newitem);
+
+/* Duplicate a cJSON item */
+extern cJSON *cJSON_Duplicate(cJSON *item,int recurse);
+
+/* Duplicate will create a new, identical cJSON item to the one you
+ pass, in new memory that will need to be released. With recurse!=0,
+ it will duplicate any children connected to the item. The
+ item->next and ->prev pointers are always zero on return from
+ Duplicate. */
+
+/* ParseWithOpts allows you to require (and check) that the JSON is
+ null terminated, and to retrieve the pointer to the final byte
+ parsed. */
+extern cJSON *cJSON_ParseWithOpts(const char *value,
+ const char **return_parse_end,
+ int require_null_terminated,
+ size_t *r_erroff);
+
+extern void cJSON_Minify(char *json);
+
+/* When assigning an integer value, it needs to be propagated to
+ valuedouble too. */
+#define cJSON_SetIntValue(object,val) \
+ ((object)?(object)->valueint=(object)->valuedouble=(val):(val))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* cJSON_h */
diff --git a/src/context.h b/src/context.h
index 1e763d2..c8e75ba 100644
--- a/src/context.h
+++ b/src/context.h
@@ -121,6 +121,9 @@ struct gpgme_context
/* True if the option --auto-key-retrieve shall be passed to gpg. */
unsigned int auto_key_retrieve : 1;
+ /* Do not use the symmtric encryption passphrase cache. */
+ unsigned int no_symkey_cache : 1;
+
/* Flags for keylist mode. */
gpgme_keylist_mode_t keylist_mode;
@@ -145,6 +148,9 @@ struct gpgme_context
/* The gpg specific override session key or NULL. */
char *override_session_key;
+ /* The optional request origin. */
+ char *request_origin;
+
/* The locale for the pinentry. */
char *lc_ctype;
char *lc_messages;
diff --git a/src/conversion.c b/src/conversion.c
index 5b84f67..4bfd3d3 100644
--- a/src/conversion.c
+++ b/src/conversion.c
@@ -575,3 +575,49 @@ _gpgme_map_pk_algo (int algo, gpgme_protocol_t protocol)
return algo;
}
+
+
+/* Return a string with a cipher algorithm. */
+const char *
+_gpgme_cipher_algo_name (int algo, gpgme_protocol_t protocol)
+{
+ if (protocol == GPGME_PROTOCOL_OPENPGP)
+ {
+ /* The algo is given according to OpenPGP specs. */
+ switch (algo)
+ {
+ case 1: return "IDEA";
+ case 2: return "3DES";
+ case 3: return "CAST5";
+ case 4: return "BLOWFISH";
+ case 7: return "AES";
+ case 8: return "AES192";
+ case 9: return "AES256";
+ case 10: return "TWOFISH";
+ case 11: return "CAMELLIA128";
+ case 12: return "CAMELLIA192";
+ case 13: return "CAMELLIA256";
+ }
+ }
+
+ return "Unknown";
+}
+
+
+/* Return a string with the cipher mode. */
+const char *
+_gpgme_cipher_mode_name (int algo, gpgme_protocol_t protocol)
+{
+ if (protocol == GPGME_PROTOCOL_OPENPGP)
+ {
+ /* The algo is given according to OpenPGP specs. */
+ switch (algo)
+ {
+ case 0: return "CFB";
+ case 1: return "EAX";
+ case 2: return "OCB";
+ }
+ }
+
+ return "Unknown";
+}
diff --git a/src/decrypt.c b/src/decrypt.c
index 8c2cd4d..155e18e 100644
--- a/src/decrypt.c
+++ b/src/decrypt.c
@@ -69,14 +69,10 @@ release_op_data (void *hook)
op_data_t opd = (op_data_t) hook;
gpgme_recipient_t recipient = opd->result.recipients;
- if (opd->result.unsupported_algorithm)
- free (opd->result.unsupported_algorithm);
-
- if (opd->result.file_name)
- free (opd->result.file_name);
-
- if (opd->result.session_key)
- free (opd->result.session_key);
+ free (opd->result.unsupported_algorithm);
+ free (opd->result.file_name);
+ free (opd->result.session_key);
+ free (opd->result.symkey_algo);
while (recipient)
{
@@ -104,6 +100,17 @@ gpgme_op_decrypt_result (gpgme_ctx_t ctx)
return NULL;
}
+ /* Make sure that SYMKEY_ALGO has a value. */
+ if (!opd->result.symkey_algo)
+ {
+ opd->result.symkey_algo = strdup ("?.?");
+ if (!opd->result.symkey_algo)
+ {
+ TRACE_SUC0 ("result=(null)");
+ return NULL;
+ }
+ }
+
if (_gpgme_debug_trace ())
{
gpgme_recipient_t rcp;
@@ -263,6 +270,49 @@ parse_enc_to (char *args, gpgme_recipient_t *recp, gpgme_protocol_t protocol)
}
+/* Parse the ARGS of a
+ * DECRYPTION_INFO <mdc_method> <sym_algo> [<aead_algo>]
+ * status. Returns 0 on success and updates the OPD.
+ */
+static gpgme_error_t
+parse_decryption_info (char *args, op_data_t opd, gpgme_protocol_t protocol)
+{
+ char *field[3];
+ int nfields;
+ char *args2;
+ int mdc, mode;
+ const char *algostr, *modestr;
+
+ if (!args)
+ return trace_gpg_error (GPG_ERR_INV_ENGINE);
+
+ args2 = strdup (args); /* Split modifies the input string. */
+ nfields = _gpgme_split_fields (args2, field, DIM (field));
+ if (nfields < 2)
+ {
+ free (args2);
+ return trace_gpg_error (GPG_ERR_INV_ENGINE); /* Required arg missing. */
+ }
+
+ mdc = atoi (field[0]);
+ algostr = _gpgme_cipher_algo_name (atoi (field[1]), protocol);
+ mode = nfields < 3? 0 : atoi (field[2]);
+ modestr = _gpgme_cipher_mode_name (mode, protocol);
+
+ free (args2);
+
+ free (opd->result.symkey_algo);
+ if (!mode && mdc != 2)
+ opd->result.symkey_algo = _gpgme_strconcat (algostr, ".PGPCFB", NULL);
+ else
+ opd->result.symkey_algo = _gpgme_strconcat (algostr, ".", modestr, NULL);
+ if (!opd->result.symkey_algo)
+ return gpg_error_from_syserror ();
+
+ return 0;
+}
+
+
gpgme_error_t
_gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code,
char *args)
@@ -303,7 +353,9 @@ _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code,
break;
case GPGME_STATUS_DECRYPTION_INFO:
- /* Fixme: Provide a way to return the used symmetric algorithm. */
+ err = parse_decryption_info (args, opd, ctx->protocol);
+ if (err)
+ return err;
break;
case GPGME_STATUS_DECRYPTION_OKAY:
@@ -357,9 +409,14 @@ _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code,
break;
case GPGME_STATUS_PLAINTEXT:
- err = _gpgme_parse_plaintext (args, &opd->result.file_name);
- if (err)
- return err;
+ {
+ int mime = 0;
+ err = _gpgme_parse_plaintext (args, &opd->result.file_name, &mime);
+ if (err)
+ return err;
+ gpgrt_log_debug ("decrypt.c setting mime to %d\n", mime);
+ opd->result.is_mime = !!mime;
+ }
break;
case GPGME_STATUS_INQUIRE_MAXLEN:
diff --git a/src/encrypt-sign.c b/src/encrypt-sign.c
index af6de63..4db46e2 100644
--- a/src/encrypt-sign.c
+++ b/src/encrypt-sign.c
@@ -62,6 +62,7 @@ encrypt_sym_status_handler (void *priv, gpgme_status_code_t code, char *args)
static gpgme_error_t
encrypt_sign_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t recp[],
+ const char *recpstring,
gpgme_encrypt_flags_t flags,
gpgme_data_t plain, gpgme_data_t cipher)
{
@@ -72,7 +73,7 @@ encrypt_sign_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t recp[],
if (err)
return err;
- symmetric = !recp || (flags & GPGME_ENCRYPT_SYMMETRIC);
+ symmetric = (!recp && !recpstring) || (flags & GPGME_ENCRYPT_SYMMETRIC);
if (!plain)
return gpg_error (GPG_ERR_NO_DATA);
@@ -103,43 +104,75 @@ encrypt_sign_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t recp[],
: encrypt_sign_status_handler,
ctx);
- return _gpgme_engine_op_encrypt_sign (ctx->engine, recp, flags, plain,
+ return _gpgme_engine_op_encrypt_sign (ctx->engine, recp, recpstring,
+ flags, plain,
cipher, ctx->use_armor,
ctx /* FIXME */);
}
-/* Encrypt plaintext PLAIN within CTX for the recipients RECP and
- store the resulting ciphertext in CIPHER. Also sign the ciphertext
- with the signers in CTX. */
+/* Old version of gpgme_op_encrypt_sign_ext_start w/o RECPSTRING. */
gpgme_error_t
gpgme_op_encrypt_sign_start (gpgme_ctx_t ctx, gpgme_key_t recp[],
gpgme_encrypt_flags_t flags,
gpgme_data_t plain, gpgme_data_t cipher)
{
+ return gpgme_op_encrypt_sign_ext_start (ctx, recp, NULL,
+ flags, plain, cipher);
+}
+
+
+/* Old version of gpgme_op_encrypt_sign_ext w/o RECPSTRING. */
+gpgme_error_t
+gpgme_op_encrypt_sign (gpgme_ctx_t ctx, gpgme_key_t recp[],
+ gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain, gpgme_data_t cipher)
+{
+ return gpgme_op_encrypt_sign_ext (ctx, recp, NULL, flags, plain, cipher);
+}
+
+
+/* Encrypt plaintext PLAIN within CTX for the recipients RECP and
+ * store the resulting ciphertext in CIPHER. Also sign the ciphertext
+ * with the signers in CTX. */
+gpgme_error_t
+gpgme_op_encrypt_sign_ext (gpgme_ctx_t ctx, gpgme_key_t recp[],
+ const char *recpstring,
+ gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain, gpgme_data_t cipher)
+{
gpgme_error_t err;
- TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt_sign_start", ctx,
+ TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt_sign", ctx,
"flags=0x%x, plain=%p, cipher=%p", flags, plain, cipher);
if (!ctx)
return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
- if (_gpgme_debug_trace () && recp)
+ if (_gpgme_debug_trace () && (recp || recpstring))
{
- int i = 0;
-
- while (recp[i])
- {
- TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i],
- (recp[i]->subkeys && recp[i]->subkeys->fpr) ?
- recp[i]->subkeys->fpr : "invalid");
- i++;
- }
+ if (recp)
+ {
+ int i = 0;
+
+ while (recp[i])
+ {
+ TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i],
+ (recp[i]->subkeys && recp[i]->subkeys->fpr) ?
+ recp[i]->subkeys->fpr : "invalid");
+ i++;
+ }
+ }
+ else
+ {
+ TRACE_LOG1 ("recipients = '%s'", recpstring);
+ }
}
- err = encrypt_sign_start (ctx, 0, recp, flags, plain, cipher);
- return err;
+ err = encrypt_sign_start (ctx, 1, recp, recpstring, flags, plain, cipher);
+ if (!err)
+ err = _gpgme_wait_one (ctx);
+ return TRACE_ERR (err);
}
@@ -147,33 +180,39 @@ gpgme_op_encrypt_sign_start (gpgme_ctx_t ctx, gpgme_key_t recp[],
store the resulting ciphertext in CIPHER. Also sign the ciphertext
with the signers in CTX. */
gpgme_error_t
-gpgme_op_encrypt_sign (gpgme_ctx_t ctx, gpgme_key_t recp[],
- gpgme_encrypt_flags_t flags,
- gpgme_data_t plain, gpgme_data_t cipher)
+gpgme_op_encrypt_sign_ext_start (gpgme_ctx_t ctx, gpgme_key_t recp[],
+ const char *recpstring,
+ gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain, gpgme_data_t cipher)
{
gpgme_error_t err;
- TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt_sign", ctx,
+ TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt_sign_start", ctx,
"flags=0x%x, plain=%p, cipher=%p", flags, plain, cipher);
if (!ctx)
return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
- if (_gpgme_debug_trace () && recp)
+ if (_gpgme_debug_trace () && (recp || recpstring))
{
- int i = 0;
-
- while (recp[i])
- {
- TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i],
- (recp[i]->subkeys && recp[i]->subkeys->fpr) ?
- recp[i]->subkeys->fpr : "invalid");
- i++;
- }
+ if (recp)
+ {
+ int i = 0;
+
+ while (recp[i])
+ {
+ TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i],
+ (recp[i]->subkeys && recp[i]->subkeys->fpr) ?
+ recp[i]->subkeys->fpr : "invalid");
+ i++;
+ }
+ }
+ else
+ {
+ TRACE_LOG1 ("recipients = '%s'", recpstring);
+ }
}
- err = encrypt_sign_start (ctx, 1, recp, flags, plain, cipher);
- if (!err)
- err = _gpgme_wait_one (ctx);
- return TRACE_ERR (err);
+ err = encrypt_sign_start (ctx, 0, recp, recpstring, flags, plain, cipher);
+ return err;
}
diff --git a/src/encrypt.c b/src/encrypt.c
index 4023654..2318497 100644
--- a/src/encrypt.c
+++ b/src/encrypt.c
@@ -214,6 +214,7 @@ _gpgme_op_encrypt_init_result (gpgme_ctx_t ctx)
static gpgme_error_t
encrypt_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t recp[],
+ const char *recpstring,
gpgme_encrypt_flags_t flags,
gpgme_data_t plain, gpgme_data_t cipher)
{
@@ -228,13 +229,13 @@ encrypt_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t recp[],
if (err)
return err;
- symmetric = !recp || (flags & GPGME_ENCRYPT_SYMMETRIC);
+ symmetric = (!recp && !recpstring) || (flags & GPGME_ENCRYPT_SYMMETRIC);
if (!plain)
return gpg_error (GPG_ERR_NO_DATA);
if (!cipher)
return gpg_error (GPG_ERR_INV_VALUE);
- if (recp && ! *recp)
+ if (recp && !*recp)
return gpg_error (GPG_ERR_INV_VALUE);
if (symmetric && ctx->passphrase_cb)
@@ -252,72 +253,111 @@ encrypt_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t recp[],
: encrypt_status_handler,
ctx);
- return _gpgme_engine_op_encrypt (ctx->engine, recp, flags, plain, cipher,
- ctx->use_armor);
+ return _gpgme_engine_op_encrypt (ctx->engine, recp, recpstring,
+ flags, plain, cipher, ctx->use_armor);
}
+/* Old version of gpgme_op_encrypt_ext without RECPSTRING. */
+gpgme_error_t
+gpgme_op_encrypt (gpgme_ctx_t ctx, gpgme_key_t recp[],
+ gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain, gpgme_data_t cipher)
+{
+ return gpgme_op_encrypt_ext (ctx, recp, NULL, flags, plain, cipher);
+}
+
+
+/* Old version of gpgme_op_encrypt_ext_start without RECPSTRING. */
gpgme_error_t
gpgme_op_encrypt_start (gpgme_ctx_t ctx, gpgme_key_t recp[],
gpgme_encrypt_flags_t flags,
gpgme_data_t plain, gpgme_data_t cipher)
{
+ return gpgme_op_encrypt_ext_start (ctx, recp, NULL, flags, plain, cipher);
+}
+
+
+/* Encrypt plaintext PLAIN within CTX for the recipients RECP and
+ * store the resulting ciphertext in CIPHER. RECPSTRING can be used
+ * instead of the RECP array to directly specify recipients as LF
+ * delimited strings; these may be any kind of recipient specification
+ * patterns as supported by the backend. */
+gpgme_error_t
+gpgme_op_encrypt_ext (gpgme_ctx_t ctx, gpgme_key_t recp[],
+ const char *recpstring,
+ gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain, gpgme_data_t cipher)
+{
gpgme_error_t err;
- TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt_start", ctx,
+ TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt", ctx,
"flags=0x%x, plain=%p, cipher=%p", flags, plain, cipher);
if (!ctx)
return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
- if (_gpgme_debug_trace () && recp)
+ if (_gpgme_debug_trace () && (recp || recpstring))
{
- int i = 0;
+ if (recp)
+ {
+ int i = 0;
- while (recp[i])
- {
- TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i],
+ while (recp[i])
+ {
+ TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i],
(recp[i]->subkeys && recp[i]->subkeys->fpr) ?
- recp[i]->subkeys->fpr : "invalid");
- i++;
- }
+ recp[i]->subkeys->fpr : "invalid");
+ i++;
+ }
+ }
+ else
+ {
+ TRACE_LOG1 ("recipients = '%s'", recpstring);
+ }
}
- err = encrypt_start (ctx, 0, recp, flags, plain, cipher);
+ err = encrypt_start (ctx, 1, recp, recpstring, flags, plain, cipher);
+ if (!err)
+ err = _gpgme_wait_one (ctx);
return TRACE_ERR (err);
}
-/* Encrypt plaintext PLAIN within CTX for the recipients RECP and
- store the resulting ciphertext in CIPHER. */
gpgme_error_t
-gpgme_op_encrypt (gpgme_ctx_t ctx, gpgme_key_t recp[],
- gpgme_encrypt_flags_t flags,
- gpgme_data_t plain, gpgme_data_t cipher)
+gpgme_op_encrypt_ext_start (gpgme_ctx_t ctx, gpgme_key_t recp[],
+ const char *recpstring,
+ gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain, gpgme_data_t cipher)
{
gpgme_error_t err;
- TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt", ctx,
+ TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt_start", ctx,
"flags=0x%x, plain=%p, cipher=%p", flags, plain, cipher);
if (!ctx)
return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
- if (_gpgme_debug_trace () && recp)
+ if (_gpgme_debug_trace () && (recp || recpstring))
{
- int i = 0;
-
- while (recp[i])
- {
- TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i],
- (recp[i]->subkeys && recp[i]->subkeys->fpr) ?
- recp[i]->subkeys->fpr : "invalid");
- i++;
- }
+ if (recp)
+ {
+ int i = 0;
+
+ while (recp[i])
+ {
+ TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i],
+ (recp[i]->subkeys && recp[i]->subkeys->fpr) ?
+ recp[i]->subkeys->fpr : "invalid");
+ i++;
+ }
+ }
+ else
+ {
+ TRACE_LOG1 ("recipients = '%s'", recpstring);
+ }
}
- err = encrypt_start (ctx, 1, recp, flags, plain, cipher);
- if (!err)
- err = _gpgme_wait_one (ctx);
+ err = encrypt_start (ctx, 0, recp, recpstring, flags, plain, cipher);
return TRACE_ERR (err);
}
diff --git a/src/engine-assuan.c b/src/engine-assuan.c
index bb2290a..6e603d9 100644
--- a/src/engine-assuan.c
+++ b/src/engine-assuan.c
@@ -96,6 +96,7 @@ struct engine_llass
int gpg_agent:1; /* Assume this is a gpg-agent connection. */
} opt;
+ char request_origin[10]; /* Copy from the CTX. */
};
typedef struct engine_llass *engine_llass_t;
@@ -365,6 +366,24 @@ llass_new (void **engine, const char *file_name, const char *home_dir,
}
+/* Copy flags from CTX into the engine object. */
+static void
+llass_set_engine_flags (void *engine, const gpgme_ctx_t ctx)
+{
+ engine_llass_t llass = engine;
+
+ if (ctx->request_origin)
+ {
+ if (strlen (ctx->request_origin) + 1 > sizeof llass->request_origin)
+ strcpy (llass->request_origin, "xxx"); /* Too long - force error */
+ else
+ strcpy (llass->request_origin, ctx->request_origin);
+ }
+ else
+ *llass->request_origin = 0;
+}
+
+
static gpgme_error_t
llass_set_locale (void *engine, int category, const char *value)
{
@@ -660,6 +679,21 @@ start (engine_llass_t llass, const char *command)
int nfds;
int i;
+ if (*llass->request_origin && llass->opt.gpg_agent)
+ {
+ char *cmd;
+
+ cmd = _gpgme_strconcat ("OPTION pretend-request-origin=",
+ llass->request_origin, NULL);
+ if (!cmd)
+ return gpg_error_from_syserror ();
+ err = assuan_transact (llass->assuan_ctx, cmd, NULL, NULL, NULL,
+ NULL, NULL, NULL);
+ free (cmd);
+ if (err && gpg_err_code (err) != GPG_ERR_UNKNOWN_OPTION)
+ return err;
+ }
+
/* We need to know the fd used by assuan for reads. We do this by
using the assumption that the first returned fd from
assuan_get_active_fds() is always this one. */
@@ -775,6 +809,7 @@ struct engine_ops _gpgme_engine_ops_assuan =
NULL, /* set_colon_line_handler */
llass_set_locale,
NULL, /* set_protocol */
+ llass_set_engine_flags,
NULL, /* decrypt */
NULL, /* delete */
NULL, /* edit */
diff --git a/src/engine-backend.h b/src/engine-backend.h
index 421eb16..f692666 100644
--- a/src/engine-backend.h
+++ b/src/engine-backend.h
@@ -61,6 +61,7 @@ struct engine_ops
void *fnc_value);
gpgme_error_t (*set_locale) (void *engine, int category, const char *value);
gpgme_error_t (*set_protocol) (void *engine, gpgme_protocol_t protocol);
+ void (*set_engine_flags) (void *engine, gpgme_ctx_t ctx);
gpgme_error_t (*decrypt) (void *engine,
gpgme_decrypt_flags_t flags,
gpgme_data_t ciph,
@@ -71,10 +72,12 @@ struct engine_ops
gpgme_error_t (*edit) (void *engine, int type, gpgme_key_t key,
gpgme_data_t out, gpgme_ctx_t ctx /* FIXME */);
gpgme_error_t (*encrypt) (void *engine, gpgme_key_t recp[],
+ const char *recpstring,
gpgme_encrypt_flags_t flags,
gpgme_data_t plain, gpgme_data_t ciph,
int use_armor);
gpgme_error_t (*encrypt_sign) (void *engine, gpgme_key_t recp[],
+ const char *recpstring,
gpgme_encrypt_flags_t flags,
gpgme_data_t plain, gpgme_data_t ciph,
int use_armor, gpgme_ctx_t ctx /* FIXME */);
diff --git a/src/engine-g13.c b/src/engine-g13.c
index f8f3178..ec2f7af 100644
--- a/src/engine-g13.c
+++ b/src/engine-g13.c
@@ -790,6 +790,7 @@ struct engine_ops _gpgme_engine_ops_g13 =
NULL, /* set_colon_line_handler */
g13_set_locale,
NULL, /* set_protocol */
+ NULL, /* set_engine_flags */
NULL, /* decrypt */
NULL, /* delete */
NULL, /* edit */
diff --git a/src/engine-gpg.c b/src/engine-gpg.c
index bfe7d13..173e940 100644
--- a/src/engine-gpg.c
+++ b/src/engine-gpg.c
@@ -43,6 +43,7 @@
#include "sema.h"
#include "debug.h"
#include "data.h"
+#include "mbox-util.h"
#include "engine-backend.h"
@@ -143,6 +144,12 @@ struct engine_gpg
struct gpgme_io_cbs io_cbs;
gpgme_pinentry_mode_t pinentry_mode;
+ char request_origin[10];
+
+ struct {
+ unsigned int no_symkey_cache : 1;
+ unsigned int offline : 1;
+ } flags;
/* NULL or the data object fed to --override_session_key-fd. */
gpgme_data_t override_session_key;
@@ -628,6 +635,30 @@ gpg_new (void **engine, const char *file_name, const char *home_dir,
}
+/* Copy flags from CTX into the engine object. */
+static void
+gpg_set_engine_flags (void *engine, const gpgme_ctx_t ctx)
+{
+ engine_gpg_t gpg = engine;
+
+ if (ctx->request_origin && have_gpg_version (gpg, "2.2.6"))
+ {
+ if (strlen (ctx->request_origin) + 1 > sizeof gpg->request_origin)
+ strcpy (gpg->request_origin, "xxx"); /* Too long - force error */
+ else
+ strcpy (gpg->request_origin, ctx->request_origin);
+ }
+ else
+ *gpg->request_origin = 0;
+
+ gpg->flags.no_symkey_cache = (ctx->no_symkey_cache
+ && have_gpg_version (gpg, "2.2.7"));
+
+ gpg->flags.offline = (ctx->offline && have_gpg_version (gpg, "2.1.23"));
+
+}
+
+
static gpgme_error_t
gpg_set_locale (void *engine, int category, const char *value)
{
@@ -856,7 +887,8 @@ build_argv (engine_gpg_t gpg, const char *pgmname)
argc++;
if (!gpg->cmd.used)
argc++; /* --batch */
- argc += 1; /* --no-sk-comments */
+ argc += 4; /* --no-sk-comments, --request-origin, --no-symkey-cache */
+ /* --disable-dirmngr */
argv = calloc (argc + 1, sizeof *argv);
if (!argv)
@@ -904,6 +936,46 @@ build_argv (engine_gpg_t gpg, const char *pgmname)
argc++;
}
+ if (*gpg->request_origin)
+ {
+ argv[argc] = _gpgme_strconcat ("--request-origin=",
+ gpg->request_origin, NULL);
+ if (!argv[argc])
+ {
+ int saved_err = gpg_error_from_syserror ();
+ free (fd_data_map);
+ free_argv (argv);
+ return saved_err;
+ }
+ argc++;
+ }
+
+ if (gpg->flags.no_symkey_cache)
+ {
+ argv[argc] = strdup ("--no-symkey-cache");
+ if (!argv[argc])
+ {
+ int saved_err = gpg_error_from_syserror ();
+ free (fd_data_map);
+ free_argv (argv);
+ return saved_err;
+ }
+ argc++;
+ }
+
+ if (gpg->flags.offline)
+ {
+ argv[argc] = strdup ("--disable-dirmngr");
+ if (!argv[argc])
+ {
+ int saved_err = gpg_error_from_syserror ();
+ free (fd_data_map);
+ free_argv (argv);
+ return saved_err;
+ }
+ argc++;
+ }
+
if (gpg->pinentry_mode && have_gpg_version (gpg, "2.1.0"))
{
const char *s = NULL;
@@ -1838,8 +1910,70 @@ gpg_edit (void *engine, int type, gpgme_key_t key, gpgme_data_t out,
}
+/* Add a single argument from a key to an -r option. */
+static gpg_error_t
+add_arg_recipient (engine_gpg_t gpg, gpgme_encrypt_flags_t flags,
+ gpgme_key_t key)
+{
+ gpg_error_t err;
+
+ if ((flags & GPGME_ENCRYPT_WANT_ADDRESS))
+ {
+ /* We have no way to figure out which mail address was
+ * requested. FIXME: It would be possible to figure this out by
+ * consulting the SENDER property of the context. */
+ err = gpg_error (GPG_ERR_INV_USER_ID);
+ }
+ else
+ err = add_arg (gpg, key->subkeys->fpr);
+
+ return err;
+}
+
+
+/* Add a single argument from a USERID string to an -r option. */
+static gpg_error_t
+add_arg_recipient_string (engine_gpg_t gpg, gpgme_encrypt_flags_t flags,
+ const char *userid, int useridlen)
+{
+ gpg_error_t err;
+
+ if ((flags & GPGME_ENCRYPT_WANT_ADDRESS))
+ {
+ char *tmpstr, *mbox;
+
+ tmpstr = malloc (useridlen + 1);
+ if (!tmpstr)
+ err = gpg_error_from_syserror ();
+ else
+ {
+ memcpy (tmpstr, userid, useridlen);
+ tmpstr[useridlen] = 0;
+
+ mbox = _gpgme_mailbox_from_userid (tmpstr);
+ if (!mbox)
+ {
+ err = gpg_error_from_syserror ();
+ if (gpg_err_code (err) == GPG_ERR_EINVAL)
+ err = gpg_error (GPG_ERR_INV_USER_ID);
+ }
+ else
+ err = add_arg (gpg, mbox);
+
+ free (mbox);
+ free (tmpstr);
+ }
+ }
+ else
+ err = add_arg_len (gpg, NULL, userid, useridlen);
+
+ return err;
+}
+
+
static gpgme_error_t
-append_args_from_recipients (engine_gpg_t gpg, gpgme_key_t recp[])
+append_args_from_recipients (engine_gpg_t gpg, gpgme_encrypt_flags_t flags,
+ gpgme_key_t recp[])
{
gpgme_error_t err = 0;
int i = 0;
@@ -1851,7 +1985,7 @@ append_args_from_recipients (engine_gpg_t gpg, gpgme_key_t recp[])
if (!err)
err = add_arg (gpg, "-r");
if (!err)
- err = add_arg (gpg, recp[i]->subkeys->fpr);
+ err = add_arg_recipient (gpg, flags, recp[i]);
if (err)
break;
i++;
@@ -1860,17 +1994,86 @@ append_args_from_recipients (engine_gpg_t gpg, gpgme_key_t recp[])
}
+/* Take recipients from the LF delimited STRING and add -r args. */
+static gpg_error_t
+append_args_from_recipients_string (engine_gpg_t gpg,
+ gpgme_encrypt_flags_t flags,
+ const char *string)
+{
+ gpg_error_t err = 0;
+ gpgme_encrypt_flags_t orig_flags = flags;
+ int any = 0;
+ int ignore = 0;
+ int hidden = 0;
+ int file = 0;
+ const char *s;
+ int n;
+
+ do
+ {
+ /* Skip leading white space */
+ while (*string == ' ' || *string == '\t')
+ string++;
+ if (!*string)
+ break;
+
+ /* Look for the LF. */
+ s = strchr (string, '\n');
+ if (s)
+ n = s - string;
+ else
+ n = strlen (string);
+ while (n && (string[n-1] == ' ' || string[n-1] == '\t'))
+ n--;
+
+ if (!ignore && n == 2 && !memcmp (string, "--", 2))
+ ignore = 1;
+ else if (!ignore && n == 8 && !memcmp (string, "--hidden", 8))
+ hidden = 1;
+ else if (!ignore && n == 11 && !memcmp (string, "--no-hidden", 11))
+ hidden = 0;
+ else if (!ignore && n == 6 && !memcmp (string, "--file", 6))
+ {
+ file = 1;
+ /* Because the key is used as is we need to ignore this flag: */
+ flags &= ~GPGME_ENCRYPT_WANT_ADDRESS;
+ }
+ else if (!ignore && n == 9 && !memcmp (string, "--no-file", 9))
+ {
+ file = 0;
+ flags = orig_flags;
+ }
+ else if (n) /* Not empty - use it. */
+ {
+ err = add_arg (gpg, file? (hidden? "-F":"-f") : (hidden? "-R":"-r"));
+ if (!err)
+ err = add_arg_recipient_string (gpg, flags, string, n);
+ if (!err)
+ any = 1;
+ }
+
+ string += n + !!s;
+ }
+ while (!err);
+
+ if (!err && !any)
+ err = gpg_error (GPG_ERR_MISSING_KEY);
+ return err;
+}
+
+
static gpgme_error_t
-gpg_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
+gpg_encrypt (void *engine, gpgme_key_t recp[], const char *recpstring,
+ gpgme_encrypt_flags_t flags,
gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
{
engine_gpg_t gpg = engine;
gpgme_error_t err = 0;
- if (recp)
+ if (recp || recpstring)
err = add_arg (gpg, "--encrypt");
- if (!err && ((flags & GPGME_ENCRYPT_SYMMETRIC) || !recp))
+ if (!err && ((flags & GPGME_ENCRYPT_SYMMETRIC) || (!recp && !recpstring)))
err = add_arg (gpg, "--symmetric");
if (!err && use_armor)
@@ -1897,7 +2100,7 @@ gpg_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
&& have_gpg_version (gpg, "2.1.14"))
err = add_arg (gpg, "--mimemode");
- if (recp)
+ if (recp || recpstring)
{
/* If we know that all recipients are valid (full or ultimate trust)
we can suppress further checks. */
@@ -1907,8 +2110,10 @@ gpg_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
if (!err && (flags & GPGME_ENCRYPT_NO_ENCRYPT_TO))
err = add_arg (gpg, "--no-encrypt-to");
- if (!err)
- err = append_args_from_recipients (gpg, recp);
+ if (!err && !recp && recpstring)
+ err = append_args_from_recipients_string (gpg, flags, recpstring);
+ else if (!err)
+ err = append_args_from_recipients (gpg, flags, recp);
}
/* Tell the gpg object about the data. */
@@ -1941,6 +2146,7 @@ gpg_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
static gpgme_error_t
gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
+ const char *recpstring,
gpgme_encrypt_flags_t flags, gpgme_data_t plain,
gpgme_data_t ciph, int use_armor,
gpgme_ctx_t ctx /* FIXME */)
@@ -1948,10 +2154,10 @@ gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
engine_gpg_t gpg = engine;
gpgme_error_t err = 0;
- if (recp)
+ if (recp || recpstring)
err = add_arg (gpg, "--encrypt");
- if (!err && ((flags & GPGME_ENCRYPT_SYMMETRIC) || !recp))
+ if (!err && ((flags & GPGME_ENCRYPT_SYMMETRIC) || (!recp && !recpstring)))
err = add_arg (gpg, "--symmetric");
if (!err)
@@ -1969,7 +2175,7 @@ gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
&& have_gpg_version (gpg, "2.1.14"))
err = add_arg (gpg, "--mimemode");
- if (recp)
+ if (recp || recpstring)
{
/* If we know that all recipients are valid (full or ultimate trust)
we can suppress further checks. */
@@ -1979,8 +2185,10 @@ gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
if (!err && (flags & GPGME_ENCRYPT_NO_ENCRYPT_TO))
err = add_arg (gpg, "--no-encrypt-to");
- if (!err)
- err = append_args_from_recipients (gpg, recp);
+ if (!err && !recp && recpstring)
+ err = append_args_from_recipients_string (gpg, flags, recpstring);
+ else if (!err)
+ err = append_args_from_recipients (gpg, flags, recp);
}
if (!err)
@@ -3090,6 +3298,7 @@ struct engine_ops _gpgme_engine_ops_gpg =
gpg_set_colon_line_handler,
gpg_set_locale,
NULL, /* set_protocol */
+ gpg_set_engine_flags, /* set_engine_flags */
gpg_decrypt,
gpg_delete,
gpg_edit,
diff --git a/src/engine-gpgconf.c b/src/engine-gpgconf.c
index 94ae67f..24867c7 100644
--- a/src/engine-gpgconf.c
+++ b/src/engine-gpgconf.c
@@ -1287,6 +1287,7 @@ struct engine_ops _gpgme_engine_ops_gpgconf =
NULL, /* set_colon_line_handler */
NULL, /* set_locale */
NULL, /* set_protocol */
+ NULL, /* set_engine_flags */
NULL, /* decrypt */
NULL, /* delete */
NULL, /* edit */
diff --git a/src/engine-gpgsm.c b/src/engine-gpgsm.c
index e337fed..da7e524 100644
--- a/src/engine-gpgsm.c
+++ b/src/engine-gpgsm.c
@@ -107,6 +107,8 @@ struct engine_gpgsm
gpgme_data_t inline_data; /* Used to collect D lines. */
+ char request_origin[10];
+
struct gpgme_io_cbs io_cbs;
};
@@ -521,6 +523,24 @@ gpgsm_new (void **engine, const char *file_name, const char *home_dir,
}
+/* Copy flags from CTX into the engine object. */
+static void
+gpgsm_set_engine_flags (void *engine, const gpgme_ctx_t ctx)
+{
+ engine_gpgsm_t gpgsm = engine;
+
+ if (ctx->request_origin)
+ {
+ if (strlen (ctx->request_origin) + 1 > sizeof gpgsm->request_origin)
+ strcpy (gpgsm->request_origin, "xxx"); /* Too long - force error */
+ else
+ strcpy (gpgsm->request_origin, ctx->request_origin);
+ }
+ else
+ *gpgsm->request_origin = 0;
+}
+
+
static gpgme_error_t
gpgsm_set_locale (void *engine, int category, const char *value)
{
@@ -1058,6 +1078,20 @@ start (engine_gpgsm_t gpgsm, const char *command)
int nfds;
int i;
+ if (*gpgsm->request_origin)
+ {
+ char *cmd;
+
+ cmd = _gpgme_strconcat ("OPTION request-origin=",
+ gpgsm->request_origin, NULL);
+ if (!cmd)
+ return gpg_error_from_syserror ();
+ err = gpgsm_assuan_simple_command (gpgsm, cmd, NULL, NULL);
+ free (cmd);
+ if (err && gpg_err_code (err) != GPG_ERR_UNKNOWN_OPTION)
+ return err;
+ }
+
/* We need to know the fd used by assuan for reads. We do this by
using the assumption that the first returned fd from
assuan_get_active_fds() is always this one. */
@@ -1293,8 +1327,57 @@ set_recipients (engine_gpgsm_t gpgsm, gpgme_key_t recp[])
}
+/* Take recipients from the LF delimited STRING and send RECIPIENT
+ * commands to gpgsm. */
static gpgme_error_t
-gpgsm_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
+set_recipients_from_string (engine_gpgsm_t gpgsm, const char *string)
+{
+ gpg_error_t err = 0;
+ char *line = NULL;
+ int no_pubkey = 0;
+ const char *s;
+ int n;
+
+ for (;;)
+ {
+ while (*string == ' ' || *string == '\t')
+ string++;
+ if (!*string)
+ break;
+
+ s = strchr (string, '\n');
+ if (s)
+ n = s - string;
+ else
+ n = strlen (string);
+ while (n && (string[n-1] == ' ' || string[n-1] == '\t'))
+ n--;
+
+ gpgrt_free (line);
+ if (gpgrt_asprintf (&line, "RECIPIENT %.*s", n, string) < 0)
+ {
+ err = gpg_error_from_syserror ();
+ break;
+ }
+ string += n + !!s;
+
+ err = gpgsm_assuan_simple_command (gpgsm, line, gpgsm->status.fnc,
+ gpgsm->status.fnc_value);
+
+ /* Fixme: Improve error reporting. */
+ if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY)
+ no_pubkey++;
+ else if (err)
+ break;
+ }
+ gpgrt_free (line);
+ return err? err : no_pubkey? gpg_error (GPG_ERR_NO_PUBKEY) : 0;
+}
+
+
+static gpgme_error_t
+gpgsm_encrypt (void *engine, gpgme_key_t recp[], const char *recpstring,
+ gpgme_encrypt_flags_t flags,
gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
{
engine_gpgsm_t gpgsm = engine;
@@ -1305,7 +1388,7 @@ gpgsm_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
if (!recp)
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
- if (flags & GPGME_ENCRYPT_NO_ENCRYPT_TO)
+ if ((flags & GPGME_ENCRYPT_NO_ENCRYPT_TO))
{
err = gpgsm_assuan_simple_command (gpgsm,
"OPTION no-encrypt-to", NULL, NULL);
@@ -1325,7 +1408,10 @@ gpgsm_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
gpgsm_clear_fd (gpgsm, MESSAGE_FD);
gpgsm->inline_data = NULL;
- err = set_recipients (gpgsm, recp);
+ if (!recp && recpstring)
+ err = set_recipients_from_string (gpgsm, recpstring);
+ else
+ err = set_recipients (gpgsm, recp);
if (!err)
err = start (gpgsm, "ENCRYPT");
@@ -2102,6 +2188,7 @@ struct engine_ops _gpgme_engine_ops_gpgsm =
gpgsm_set_colon_line_handler,
gpgsm_set_locale,
NULL, /* set_protocol */
+ gpgsm_set_engine_flags,
gpgsm_decrypt,
gpgsm_delete, /* decrypt_verify */
NULL, /* edit */
diff --git a/src/engine-spawn.c b/src/engine-spawn.c
index 7044781..7b7a9cd 100644
--- a/src/engine-spawn.c
+++ b/src/engine-spawn.c
@@ -241,7 +241,8 @@ engspawn_start (engine_spawn_t esp, const char *file, const char *argv[],
spflags |= IOSPAWN_FLAG_DETACHED;
if ((flags & GPGME_SPAWN_ALLOW_SET_FG))
spflags |= IOSPAWN_FLAG_ALLOW_SET_FG;
-
+ if ((flags & GPGME_SPAWN_SHOW_WINDOW))
+ spflags |= IOSPAWN_FLAG_SHOW_WINDOW;
err = build_fd_data_map (esp);
if (err)
@@ -448,6 +449,7 @@ struct engine_ops _gpgme_engine_ops_spawn =
NULL, /* set_colon_line_handler */
NULL, /* set_locale */
NULL, /* set_protocol */
+ NULL, /* set_engine_flags */
NULL, /* decrypt */
NULL, /* delete */
NULL, /* edit */
diff --git a/src/engine-uiserver.c b/src/engine-uiserver.c
index bc3f3fb..d8f4fce 100644
--- a/src/engine-uiserver.c
+++ b/src/engine-uiserver.c
@@ -1075,8 +1075,58 @@ set_recipients (engine_uiserver_t uiserver, gpgme_key_t recp[])
}
+/* Take recipients from the LF delimited STRING and send RECIPIENT
+ * commands to gpgsm. */
static gpgme_error_t
-uiserver_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
+set_recipients_from_string (engine_uiserver_t uiserver, const char *string)
+{
+ gpg_error_t err = 0;
+ char *line = NULL;
+ int no_pubkey = 0;
+ const char *s;
+ int n;
+
+ for (;;)
+ {
+ while (*string == ' ' || *string == '\t')
+ string++;
+ if (!*string)
+ break;
+
+ s = strchr (string, '\n');
+ if (s)
+ n = s - string;
+ else
+ n = strlen (string);
+ while (n && (string[n-1] == ' ' || string[n-1] == '\t'))
+ n--;
+
+ gpgrt_free (line);
+ if (gpgrt_asprintf (&line, "RECIPIENT %.*s", n, string) < 0)
+ {
+ err = gpg_error_from_syserror ();
+ break;
+ }
+ string += n + !!s;
+
+ err = uiserver_assuan_simple_command (uiserver, line,
+ uiserver->status.fnc,
+ uiserver->status.fnc_value);
+
+ /* Fixme: Improve error reporting. */
+ if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY)
+ no_pubkey++;
+ else if (err)
+ break;
+ }
+ gpgrt_free (line);
+ return err? err : no_pubkey? gpg_error (GPG_ERR_NO_PUBKEY) : 0;
+}
+
+
+static gpgme_error_t
+uiserver_encrypt (void *engine, gpgme_key_t recp[], const char *recpstring,
+ gpgme_encrypt_flags_t flags,
gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
{
engine_uiserver_t uiserver = engine;
@@ -1140,9 +1190,12 @@ uiserver_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
uiserver->inline_data = NULL;
- if (recp)
+ if (recp || recpstring)
{
- err = set_recipients (uiserver, recp);
+ if (recp)
+ err = set_recipients (uiserver, recp);
+ else
+ err = set_recipients_from_string (uiserver, recpstring);
if (err)
{
gpgrt_free (cmd);
@@ -1368,6 +1421,7 @@ struct engine_ops _gpgme_engine_ops_uiserver =
uiserver_set_colon_line_handler,
uiserver_set_locale,
uiserver_set_protocol,
+ NULL, /* set_engine_flags */
uiserver_decrypt,
NULL, /* delete */
NULL, /* edit */
diff --git a/src/engine.c b/src/engine.c
index 28ba9fd..b716ca2 100644
--- a/src/engine.c
+++ b/src/engine.c
@@ -651,6 +651,26 @@ _gpgme_engine_set_protocol (engine_t engine, gpgme_protocol_t protocol)
}
+/* Pass information about the current context to the engine. The
+ * engine may use this context to retrieve context specific flags.
+ * Important: The engine is required to immediately copy the required
+ * flags to its own context!
+ *
+ * This function will eventually be used to reduce the number of
+ * explicit passed flags. */
+void
+_gpgme_engine_set_engine_flags (engine_t engine, gpgme_ctx_t ctx)
+{
+ if (!engine)
+ return;
+
+ if (!engine->ops->set_engine_flags)
+ return;
+
+ (*engine->ops->set_engine_flags) (engine->engine, ctx);
+}
+
+
gpgme_error_t
_gpgme_engine_op_decrypt (engine_t engine,
gpgme_decrypt_flags_t flags,
@@ -701,6 +721,7 @@ _gpgme_engine_op_edit (engine_t engine, int type, gpgme_key_t key,
gpgme_error_t
_gpgme_engine_op_encrypt (engine_t engine, gpgme_key_t recp[],
+ const char *recpstring,
gpgme_encrypt_flags_t flags,
gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
{
@@ -710,13 +731,14 @@ _gpgme_engine_op_encrypt (engine_t engine, gpgme_key_t recp[],
if (!engine->ops->encrypt)
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
- return (*engine->ops->encrypt) (engine->engine, recp, flags, plain, ciph,
- use_armor);
+ return (*engine->ops->encrypt) (engine->engine, recp, recpstring,
+ flags, plain, ciph, use_armor);
}
gpgme_error_t
_gpgme_engine_op_encrypt_sign (engine_t engine, gpgme_key_t recp[],
+ const char *recpstring,
gpgme_encrypt_flags_t flags,
gpgme_data_t plain, gpgme_data_t ciph,
int use_armor, gpgme_ctx_t ctx /* FIXME */)
@@ -727,8 +749,8 @@ _gpgme_engine_op_encrypt_sign (engine_t engine, gpgme_key_t recp[],
if (!engine->ops->encrypt_sign)
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
- return (*engine->ops->encrypt_sign) (engine->engine, recp, flags,
- plain, ciph, use_armor, ctx);
+ return (*engine->ops->encrypt_sign) (engine->engine, recp, recpstring,
+ flags, plain, ciph, use_armor, ctx);
}
diff --git a/src/engine.h b/src/engine.h
index 0bf1bb2..8b692f2 100644
--- a/src/engine.h
+++ b/src/engine.h
@@ -69,6 +69,7 @@ gpgme_error_t _gpgme_engine_set_locale (engine_t engine, int category,
const char *value);
gpgme_error_t _gpgme_engine_set_protocol (engine_t engine,
gpgme_protocol_t protocol);
+void _gpgme_engine_set_engine_flags (engine_t engine, gpgme_ctx_t ctx);
void _gpgme_engine_release (engine_t engine);
void _gpgme_engine_set_status_cb (engine_t engine,
gpgme_status_cb_t cb, void *cb_value);
@@ -97,11 +98,13 @@ gpgme_error_t _gpgme_engine_op_edit (engine_t engine, int type,
gpgme_ctx_t ctx /* FIXME */);
gpgme_error_t _gpgme_engine_op_encrypt (engine_t engine,
gpgme_key_t recp[],
+ const char *recpstring,
gpgme_encrypt_flags_t flags,
gpgme_data_t plain, gpgme_data_t ciph,
int use_armor);
gpgme_error_t _gpgme_engine_op_encrypt_sign (engine_t engine,
gpgme_key_t recp[],
+ const char *recpstring,
gpgme_encrypt_flags_t flags,
gpgme_data_t plain,
gpgme_data_t ciph,
diff --git a/src/get-env.c b/src/get-env.c
index 57fd419..b13706f 100644
--- a/src/get-env.c
+++ b/src/get-env.c
@@ -28,17 +28,71 @@
#include "util.h"
-#if defined(HAVE_THREAD_SAFE_GETENV) || !defined (HAVE_GETENV_R)
-/* We prefer using getenv() if it is thread-safe. */
-
/* Retrieve the environment variable NAME and return a copy of it in a
malloc()'ed buffer in *VALUE. If the environment variable is not
set, return NULL in *VALUE. */
+
+#ifdef HAVE_GETENV_R
+#define INITIAL_GETENV_SIZE 32
+
+gpgme_error_t
+_gpgme_getenv (const char *name, char **value)
+{
+ size_t len = INITIAL_GETENV_SIZE;
+ char *env_value;
+
+ env_value = malloc (len);
+
+ while (1)
+ {
+ *value = env_value;
+ if (!env_value)
+ return gpg_error_from_syserror ();
+
+ if (getenv_r (name, env_value, len) == 0)
+ break;
+
+ if (errno == ERANGE)
+ {
+ len *= 2;
+ env_value = realloc (env_value, len);
+ }
+ else
+ {
+ int saved = errno;
+
+ free (env_value);
+ *value = NULL;
+ if (errno == ENOENT)
+ return 0;
+ else
+ return gpg_error_from_errno (saved);
+ }
+ }
+
+ return 0;
+}
+#else
+#ifndef HAVE_THREAD_SAFE_GETENV
+GPGRT_LOCK_DEFINE (environ_lock);
+#endif
+
gpgme_error_t
_gpgme_getenv (const char *name, char **value)
{
char *env_value;
+ gpgme_error_t err = 0;
+
+#ifndef HAVE_THREAD_SAFE_GETENV
+ gpg_err_code_t rc;
+ rc= gpgrt_lock_lock (&environ_lock);
+ if (rc)
+ {
+ err = gpg_error (rc);
+ goto leave;
+ }
+#endif
env_value = getenv (name);
if (!env_value)
*value = NULL;
@@ -46,14 +100,14 @@ _gpgme_getenv (const char *name, char **value)
{
*value = strdup (env_value);
if (!*value)
- return gpg_error_from_syserror ();
+ err = gpg_error_from_syserror ();
}
- return 0;
+#ifndef HAVE_THREAD_SAFE_GETENV
+ rc = gpgrt_lock_unlock (&environ_lock);
+ if (rc)
+ err = gpg_error (rc);
+ leave:
+#endif
+ return err;
}
-
-#else
-
-/* FIXME: Implement this when we have the specification for it. */
-#error Use of getenv_r not implemented.
-
#endif
diff --git a/src/gpgme-json.c b/src/gpgme-json.c
new file mode 100644
index 0000000..f1e9f25
--- /dev/null
+++ b/src/gpgme-json.c
@@ -0,0 +1,1772 @@
+/* gpgme-json.c - JSON based interface to gpgme (server)
+ * Copyright (C) 2018 g10 Code GmbH
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * GPGME 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+/* This is tool implements the Native Messaging protocol of web
+ * browsers and provides the server part of it. A Javascript based
+ * client can be found in lang/javascript.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif
+#include <stdint.h>
+#include <sys/stat.h>
+
+#define GPGRT_ENABLE_ES_MACROS 1
+#define GPGRT_ENABLE_LOG_MACROS 1
+#define GPGRT_ENABLE_ARGPARSE_MACROS 1
+#include "gpgme.h"
+#include "cJSON.h"
+
+
+#if GPGRT_VERSION_NUMBER < 0x011c00 /* 1.28 */
+int main (void){fputs ("Build with Libgpg-error >= 1.28!\n", stderr);return 1;}
+#else /* libgpg-error >= 1.28 */
+
+/* We don't allow a request with more than 64 MiB. */
+#define MAX_REQUEST_SIZE (64 * 1024 * 1024)
+
+/* Minimal, default and maximum chunk size for returned data. The
+ * first chunk is returned directly. If the "more" flag is also
+ * returned, a "getmore" command needs to be used to get the next
+ * chunk. Right now this value covers just the value of the "data"
+ * element; so to cover for the other returned objects this values
+ * needs to be lower than the maximum allowed size of the browser. */
+#define MIN_REPLY_CHUNK_SIZE 512
+#define DEF_REPLY_CHUNK_SIZE (512 * 1024)
+#define MAX_REPLY_CHUNK_SIZE (10 * 1024 * 1024)
+
+
+static void xoutofcore (const char *type) GPGRT_ATTR_NORETURN;
+static cjson_t error_object_v (cjson_t json, const char *message,
+ va_list arg_ptr) GPGRT_ATTR_PRINTF(2,0);
+static cjson_t error_object (cjson_t json, const char *message,
+ ...) GPGRT_ATTR_PRINTF(2,3);
+static char *error_object_string (const char *message,
+ ...) GPGRT_ATTR_PRINTF(1,2);
+
+
+/* True if interactive mode is active. */
+static int opt_interactive;
+/* True is debug mode is active. */
+static int opt_debug;
+
+/* Pending data to be returned by a getmore command. */
+static struct
+{
+ char *buffer; /* Malloced data or NULL if not used. */
+ size_t length; /* Length of that data. */
+ size_t written; /* # of already written bytes from BUFFER. */
+ const char *type;/* The "type" of the data. */
+ int base64; /* The "base64" flag of the data. */
+} pending_data;
+
+
+/*
+ * Helper functions and macros
+ */
+
+#define xtrymalloc(a) gpgrt_malloc ((a))
+#define xtrystrdup(a) gpgrt_strdup ((a))
+#define xmalloc(a) ({ \
+ void *_r = gpgrt_malloc ((a)); \
+ if (!_r) \
+ xoutofcore ("malloc"); \
+ _r; })
+#define xcalloc(a,b) ({ \
+ void *_r = gpgrt_calloc ((a), (b)); \
+ if (!_r) \
+ xoutofcore ("calloc"); \
+ _r; })
+#define xstrdup(a) ({ \
+ char *_r = gpgrt_strdup ((a)); \
+ if (!_r) \
+ xoutofcore ("strdup"); \
+ _r; })
+#define xstrconcat(a, ...) ({ \
+ char *_r = gpgrt_strconcat ((a), __VA_ARGS__); \
+ if (!_r) \
+ xoutofcore ("strconcat"); \
+ _r; })
+#define xfree(a) gpgrt_free ((a))
+
+#define spacep(p) (*(p) == ' ' || *(p) == '\t')
+
+#ifndef HAVE_STPCPY
+static GPGRT_INLINE char *
+_my_stpcpy (char *a, const char *b)
+{
+ while (*b)
+ *a++ = *b++;
+ *a = 0;
+ return a;
+}
+#define stpcpy(a,b) _my_stpcpy ((a), (b))
+#endif /*!HAVE_STPCPY*/
+
+
+
+static void
+xoutofcore (const char *type)
+{
+ gpg_error_t err = gpg_error_from_syserror ();
+ log_error ("%s failed: %s\n", type, gpg_strerror (err));
+ exit (2);
+}
+
+
+/* Call cJSON_CreateObject but terminate in case of an error. */
+static cjson_t
+xjson_CreateObject (void)
+{
+ cjson_t json = cJSON_CreateObject ();
+ if (!json)
+ xoutofcore ("cJSON_CreateObject");
+ return json;
+}
+
+
+/* Wrapper around cJSON_AddStringToObject which returns an gpg-error
+ * code instead of the NULL or the new object. */
+static gpg_error_t
+cjson_AddStringToObject (cjson_t object, const char *name, const char *string)
+{
+ if (!cJSON_AddStringToObject (object, name, string))
+ return gpg_error_from_syserror ();
+ return 0;
+}
+
+
+/* Same as cjson_AddStringToObject but prints an error message and
+ * terminates the process. */
+static void
+xjson_AddStringToObject (cjson_t object, const char *name, const char *string)
+{
+ if (!cJSON_AddStringToObject (object, name, string))
+ xoutofcore ("cJSON_AddStringToObject");
+}
+
+
+/* Wrapper around cJSON_AddBoolToObject which terminates the process
+ * in case of an error. */
+static void
+xjson_AddBoolToObject (cjson_t object, const char *name, int abool)
+{
+ if (!cJSON_AddBoolToObject (object, name, abool))
+ xoutofcore ("cJSON_AddStringToObject");
+ return ;
+}
+
+/* This is similar to cJSON_AddStringToObject but takes (DATA,
+ * DATALEN) and adds it under NAME as a base 64 encoded string to
+ * OBJECT. */
+static gpg_error_t
+add_base64_to_object (cjson_t object, const char *name,
+ const void *data, size_t datalen)
+{
+#if GPGRT_VERSION_NUMBER < 0x011d00 /* 1.29 */
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+#else
+ gpg_err_code_t err;
+ estream_t fp = NULL;
+ gpgrt_b64state_t state = NULL;
+ cjson_t j_str = NULL;
+ void *buffer = NULL;
+
+ fp = es_fopenmem (0, "rwb");
+ if (!fp)
+ {
+ err = gpg_err_code_from_syserror ();
+ goto leave;
+ }
+ state = gpgrt_b64enc_start (fp, "");
+ if (!state)
+ {
+ err = gpg_err_code_from_syserror ();
+ goto leave;
+ }
+
+ err = gpgrt_b64enc_write (state, data, datalen);
+ if (err)
+ goto leave;
+
+ err = gpgrt_b64enc_finish (state);
+ state = NULL;
+ if (err)
+ return err;
+
+ es_fputc (0, fp);
+ if (es_fclose_snatch (fp, &buffer, NULL))
+ {
+ fp = NULL;
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ fp = NULL;
+
+ j_str = cJSON_CreateStringConvey (buffer);
+ if (!j_str)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ buffer = NULL;
+
+ if (!cJSON_AddItemToObject (object, name, j_str))
+ {
+ err = gpg_error_from_syserror ();
+ cJSON_Delete (j_str);
+ j_str = NULL;
+ goto leave;
+ }
+ j_str = NULL;
+
+ leave:
+ xfree (buffer);
+ cJSON_Delete (j_str);
+ gpgrt_b64enc_finish (state);
+ es_fclose (fp);
+ return err;
+#endif
+}
+
+
+/* Create a JSON error object. If JSON is not NULL the error message
+ * is appended to that object. An existing "type" item will be replaced. */
+static cjson_t
+error_object_v (cjson_t json, const char *message, va_list arg_ptr)
+{
+ cjson_t response, j_tmp;
+ char *msg;
+
+ msg = gpgrt_vbsprintf (message, arg_ptr);
+ if (!msg)
+ xoutofcore ("error_object");
+
+ response = json? json : xjson_CreateObject ();
+
+ if (!(j_tmp = cJSON_GetObjectItem (response, "type")))
+ xjson_AddStringToObject (response, "type", "error");
+ else /* Replace existing "type". */
+ {
+ j_tmp = cJSON_CreateString ("error");
+ if (!j_tmp)
+ xoutofcore ("cJSON_CreateString");
+ cJSON_ReplaceItemInObject (response, "type", j_tmp);
+ }
+ xjson_AddStringToObject (response, "msg", msg);
+
+ xfree (msg);
+ return response;
+}
+
+
+/* Call cJSON_Print but terminate in case of an error. */
+static char *
+xjson_Print (cjson_t object)
+{
+ char *buf;
+ buf = cJSON_Print (object);
+ if (!buf)
+ xoutofcore ("cJSON_Print");
+ return buf;
+}
+
+
+static cjson_t
+error_object (cjson_t json, const char *message, ...)
+{
+ cjson_t response;
+ va_list arg_ptr;
+
+ va_start (arg_ptr, message);
+ response = error_object_v (json, message, arg_ptr);
+ va_end (arg_ptr);
+ return response;
+}
+
+
+static char *
+error_object_string (const char *message, ...)
+{
+ cjson_t response;
+ va_list arg_ptr;
+ char *msg;
+
+ va_start (arg_ptr, message);
+ response = error_object_v (NULL, message, arg_ptr);
+ va_end (arg_ptr);
+
+ msg = xjson_Print (response);
+ cJSON_Delete (response);
+ return msg;
+}
+
+
+/* Get the boolean property NAME from the JSON object and store true
+ * or valse at R_VALUE. If the name is unknown the value of DEF_VALUE
+ * is returned. If the type of the value is not boolean,
+ * GPG_ERR_INV_VALUE is returned and R_VALUE set to DEF_VALUE. */
+static gpg_error_t
+get_boolean_flag (cjson_t json, const char *name, int def_value, int *r_value)
+{
+ cjson_t j_item;
+
+ j_item = cJSON_GetObjectItem (json, name);
+ if (!j_item)
+ *r_value = def_value;
+ else if (cjson_is_true (j_item))
+ *r_value = 1;
+ else if (cjson_is_false (j_item))
+ *r_value = 0;
+ else
+ {
+ *r_value = def_value;
+ return gpg_error (GPG_ERR_INV_VALUE);
+ }
+
+ return 0;
+}
+
+
+/* Get the boolean property PROTOCOL from the JSON object and store
+ * its value at R_PROTOCOL. The default is OpenPGP. */
+static gpg_error_t
+get_protocol (cjson_t json, gpgme_protocol_t *r_protocol)
+{
+ cjson_t j_item;
+
+ *r_protocol = GPGME_PROTOCOL_OpenPGP;
+ j_item = cJSON_GetObjectItem (json, "protocol");
+ if (!j_item)
+ ;
+ else if (!cjson_is_string (j_item))
+ return gpg_error (GPG_ERR_INV_VALUE);
+ else if (!strcmp(j_item->valuestring, "openpgp"))
+ ;
+ else if (!strcmp(j_item->valuestring, "cms"))
+ *r_protocol = GPGME_PROTOCOL_CMS;
+ else
+ return gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
+
+ return 0;
+}
+
+
+/* Get the chunksize from JSON and store it at R_CHUNKSIZE. */
+static gpg_error_t
+get_chunksize (cjson_t json, size_t *r_chunksize)
+{
+ cjson_t j_item;
+
+ *r_chunksize = DEF_REPLY_CHUNK_SIZE;
+ j_item = cJSON_GetObjectItem (json, "chunksize");
+ if (!j_item)
+ ;
+ else if (!cjson_is_number (j_item))
+ return gpg_error (GPG_ERR_INV_VALUE);
+ else if ((size_t)j_item->valueint < MIN_REPLY_CHUNK_SIZE)
+ *r_chunksize = MIN_REPLY_CHUNK_SIZE;
+ else if ((size_t)j_item->valueint > MAX_REPLY_CHUNK_SIZE)
+ *r_chunksize = MAX_REPLY_CHUNK_SIZE;
+ else
+ *r_chunksize = (size_t)j_item->valueint;
+
+ return 0;
+}
+
+
+/* Extract the keys from the "keys" array in the JSON object. On
+ * success a string with the keys identifiers is stored at R_KEYS.
+ * The keys in that string are LF delimited. On failure an error code
+ * is returned. */
+static gpg_error_t
+get_keys (cjson_t json, char **r_keystring)
+{
+ cjson_t j_keys, j_item;
+ int i, nkeys;
+ char *p;
+ size_t length;
+
+ *r_keystring = NULL;
+
+ j_keys = cJSON_GetObjectItem (json, "keys");
+ if (!j_keys)
+ return gpg_error (GPG_ERR_NO_KEY);
+ if (!cjson_is_array (j_keys) && !cjson_is_string (j_keys))
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ /* Fixme: We should better use a membuf like thing. */
+ length = 1; /* For the EOS. */
+ if (cjson_is_string (j_keys))
+ {
+ nkeys = 1;
+ length += strlen (j_keys->valuestring);
+ if (strchr (j_keys->valuestring, '\n'))
+ return gpg_error (GPG_ERR_INV_USER_ID);
+ }
+ else
+ {
+ nkeys = cJSON_GetArraySize (j_keys);
+ if (!nkeys)
+ return gpg_error (GPG_ERR_NO_KEY);
+ for (i=0; i < nkeys; i++)
+ {
+ j_item = cJSON_GetArrayItem (j_keys, i);
+ if (!j_item || !cjson_is_string (j_item))
+ return gpg_error (GPG_ERR_INV_VALUE);
+ if (i)
+ length++; /* Space for delimiter. */
+ length += strlen (j_item->valuestring);
+ if (strchr (j_item->valuestring, '\n'))
+ return gpg_error (GPG_ERR_INV_USER_ID);
+ }
+ }
+
+ p = *r_keystring = xtrymalloc (length);
+ if (!p)
+ return gpg_error_from_syserror ();
+
+ if (cjson_is_string (j_keys))
+ {
+ strcpy (p, j_keys->valuestring);
+ }
+ else
+ {
+ for (i=0; i < nkeys; i++)
+ {
+ j_item = cJSON_GetArrayItem (j_keys, i);
+ if (i)
+ *p++ = '\n'; /* Add delimiter. */
+ p = stpcpy (p, j_item->valuestring);
+ }
+ }
+ return 0;
+}
+
+
+
+
+/*
+ * GPGME support functions.
+ */
+
+/* Helper for get_context. */
+static gpgme_ctx_t
+_create_new_context (gpgme_protocol_t proto)
+{
+ gpg_error_t err;
+ gpgme_ctx_t ctx;
+
+ err = gpgme_new (&ctx);
+ if (err)
+ log_fatal ("error creating GPGME context: %s\n", gpg_strerror (err));
+ gpgme_set_protocol (ctx, proto);
+ gpgme_set_ctx_flag (ctx, "request-origin", "browser");
+ return ctx;
+}
+
+
+/* Return a context object for protocol PROTO. This is currently a
+ * statuically allocated context initialized for PROTO. Termnates
+ * process on failure. */
+static gpgme_ctx_t
+get_context (gpgme_protocol_t proto)
+{
+ static gpgme_ctx_t ctx_openpgp, ctx_cms;
+
+ if (proto == GPGME_PROTOCOL_OpenPGP)
+ {
+ if (!ctx_openpgp)
+ ctx_openpgp = _create_new_context (proto);
+ return ctx_openpgp;
+ }
+ else if (proto == GPGME_PROTOCOL_CMS)
+ {
+ if (!ctx_cms)
+ ctx_cms = _create_new_context (proto);
+ return ctx_cms;
+ }
+ else
+ log_bug ("invalid protocol %d requested\n", proto);
+}
+
+
+
+/* Free context object retrieved by get_context. */
+static void
+release_context (gpgme_ctx_t ctx)
+{
+ /* Nothing to do right now. */
+ (void)ctx;
+}
+
+
+
+/* Given a Base-64 encoded string object in JSON return a gpgme data
+ * object at R_DATA. */
+static gpg_error_t
+data_from_base64_string (gpgme_data_t *r_data, cjson_t json)
+{
+#if GPGRT_VERSION_NUMBER < 0x011d00 /* 1.29 */
+ *r_data = NULL;
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+#else
+ gpg_error_t err;
+ size_t len;
+ char *buf = NULL;
+ gpgrt_b64state_t state = NULL;
+ gpgme_data_t data = NULL;
+
+ *r_data = NULL;
+
+ /* A quick check on the JSON. */
+ if (!cjson_is_string (json))
+ {
+ err = gpg_error (GPG_ERR_INV_VALUE);
+ goto leave;
+ }
+
+ state = gpgrt_b64dec_start (NULL);
+ if (!state)
+ {
+ err = gpg_err_code_from_syserror ();
+ goto leave;
+ }
+
+ /* Fixme: Data duplication - we should see how to snatch the memory
+ * from the json object. */
+ len = strlen (json->valuestring);
+ buf = xtrystrdup (json->valuestring);
+ if (!buf)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+
+ err = gpgrt_b64dec_proc (state, buf, len, &len);
+ if (err)
+ goto leave;
+
+ err = gpgrt_b64dec_finish (state);
+ state = NULL;
+ if (err)
+ goto leave;
+
+ err = gpgme_data_new_from_mem (&data, buf, len, 1);
+ if (err)
+ goto leave;
+ *r_data = data;
+ data = NULL;
+
+ leave:
+ xfree (data);
+ xfree (buf);
+ gpgrt_b64dec_finish (state);
+ return err;
+#endif
+}
+
+
+
+/*
+ * Implementation of the commands.
+ */
+
+
+/* Create a "data" object and the "type", "base64" and "more" flags
+ * from DATA and append them to RESULT. Ownership if DATA is
+ * transferred to this function. TYPE must be a fixed string.
+ * CHUNKSIZE is the chunksize requested from the caller. If BASE64 is
+ * -1 the need for base64 encoding is determined by the content of
+ * DATA, all other values are take as rtue or false. Note that
+ * op_getmore has similar code but works on PENDING_DATA which is set
+ * here. */
+static gpg_error_t
+make_data_object (cjson_t result, gpgme_data_t data, size_t chunksize,
+ const char *type, int base64)
+{
+ gpg_error_t err;
+ char *buffer;
+ size_t buflen;
+ int c;
+
+ if (!base64 || base64 == -1) /* Make sure that we really have a string. */
+ gpgme_data_write (data, "", 1);
+
+ buffer = gpgme_data_release_and_get_mem (data, &buflen);
+ data = NULL;
+ if (!buffer)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+
+ if (base64 == -1)
+ {
+ base64 = 0;
+ if (!buflen)
+ log_fatal ("Appended Nul byte got lost\n");
+ if (memchr (buffer, 0, buflen-1))
+ {
+ buflen--; /* Adjust for the extra nul byte. */
+ base64 = 1;
+ }
+ /* Fixme: We might want to do more advanced heuristics than to
+ * only look for a Nul. */
+ }
+
+ /* Adjust the chunksize if we need to do base64 conversion. */
+ if (base64)
+ chunksize = (chunksize / 4) * 3;
+
+ xjson_AddStringToObject (result, "type", type);
+ xjson_AddBoolToObject (result, "base64", base64);
+
+ if (buflen > chunksize)
+ {
+ xjson_AddBoolToObject (result, "more", 1);
+
+ c = buffer[chunksize];
+ buffer[chunksize] = 0;
+ if (base64)
+ err = add_base64_to_object (result, "data", buffer, chunksize);
+ else
+ err = cjson_AddStringToObject (result, "data", buffer);
+ buffer[chunksize] = c;
+ if (err)
+ goto leave;
+
+ pending_data.buffer = buffer;
+ buffer = NULL;
+ pending_data.length = buflen;
+ pending_data.written = chunksize;
+ pending_data.type = type;
+ pending_data.base64 = base64;
+ }
+ else
+ {
+ if (base64)
+ err = add_base64_to_object (result, "data", buffer, buflen);
+ else
+ err = cjson_AddStringToObject (result, "data", buffer);
+ }
+
+ leave:
+ gpgme_free (buffer);
+ return err;
+}
+
+
+
+static const char hlp_encrypt[] =
+ "op: \"encrypt\"\n"
+ "keys: Array of strings with the fingerprints or user-ids\n"
+ " of the keys to encrypt the data. For a single key\n"
+ " a String may be used instead of an array.\n"
+ "data: Input data. \n"
+ "\n"
+ "Optional parameters:\n"
+ "protocol: Either \"openpgp\" (default) or \"cms\".\n"
+ "chunksize: Max number of bytes in the resulting \"data\".\n"
+ "\n"
+ "Optional boolean flags (default is false):\n"
+ "base64: Input data is base64 encoded.\n"
+ "mime: Indicate that data is a MIME object.\n"
+ "armor: Request output in armored format.\n"
+ "always-trust: Request --always-trust option.\n"
+ "no-encrypt-to: Do not use a default recipient.\n"
+ "no-compress: Do not compress the plaintext first.\n"
+ "throw-keyids: Request the --throw-keyids option.\n"
+ "want-address: Require that the keys include a mail address.\n"
+ "wrap: Assume the input is an OpenPGP message.\n"
+ "\n"
+ "Response on success:\n"
+ "type: \"ciphertext\"\n"
+ "data: Unless armor mode is used a Base64 encoded binary\n"
+ " ciphertext. In armor mode a string with an armored\n"
+ " OpenPGP or a PEM message.\n"
+ "base64: Boolean indicating whether data is base64 encoded.\n"
+ "more: Optional boolean indicating that \"getmore\" is required.";
+static gpg_error_t
+op_encrypt (cjson_t request, cjson_t result)
+{
+ gpg_error_t err;
+ gpgme_ctx_t ctx = NULL;
+ gpgme_protocol_t protocol;
+ size_t chunksize;
+ int opt_base64;
+ int opt_mime;
+ char *keystring = NULL;
+ cjson_t j_input;
+ gpgme_data_t input = NULL;
+ gpgme_data_t output = NULL;
+ int abool;
+ gpgme_encrypt_flags_t encrypt_flags = 0;
+
+ if ((err = get_protocol (request, &protocol)))
+ goto leave;
+ ctx = get_context (protocol);
+ if ((err = get_chunksize (request, &chunksize)))
+ goto leave;
+
+ if ((err = get_boolean_flag (request, "base64", 0, &opt_base64)))
+ goto leave;
+ if ((err = get_boolean_flag (request, "mime", 0, &opt_mime)))
+ goto leave;
+
+ if ((err = get_boolean_flag (request, "armor", 0, &abool)))
+ goto leave;
+ gpgme_set_armor (ctx, abool);
+ if ((err = get_boolean_flag (request, "always-trust", 0, &abool)))
+ goto leave;
+ if (abool)
+ encrypt_flags |= GPGME_ENCRYPT_ALWAYS_TRUST;
+ if ((err = get_boolean_flag (request, "no-encrypt-to", 0,&abool)))
+ goto leave;
+ if (abool)
+ encrypt_flags |= GPGME_ENCRYPT_NO_ENCRYPT_TO;
+ if ((err = get_boolean_flag (request, "no-compress", 0, &abool)))
+ goto leave;
+ if (abool)
+ encrypt_flags |= GPGME_ENCRYPT_NO_COMPRESS;
+ if ((err = get_boolean_flag (request, "throw-keyids", 0, &abool)))
+ goto leave;
+ if (abool)
+ encrypt_flags |= GPGME_ENCRYPT_THROW_KEYIDS;
+ if ((err = get_boolean_flag (request, "wrap", 0, &abool)))
+ goto leave;
+ if (abool)
+ encrypt_flags |= GPGME_ENCRYPT_WRAP;
+ if ((err = get_boolean_flag (request, "want-address", 0, &abool)))
+ goto leave;
+ if (abool)
+ encrypt_flags |= GPGME_ENCRYPT_WANT_ADDRESS;
+
+
+ /* Get the keys. */
+ err = get_keys (request, &keystring);
+ if (err)
+ {
+ /* Provide a custom error response. */
+ error_object (result, "Error getting keys: %s", gpg_strerror (err));
+ goto leave;
+ }
+
+ /* Get the data. Note that INPUT is a shallow data object with the
+ * storage hold in REQUEST. */
+ j_input = cJSON_GetObjectItem (request, "data");
+ if (!j_input)
+ {
+ err = gpg_error (GPG_ERR_NO_DATA);
+ goto leave;
+ }
+ if (!cjson_is_string (j_input))
+ {
+ err = gpg_error (GPG_ERR_INV_VALUE);
+ goto leave;
+ }
+ if (opt_base64)
+ {
+ err = data_from_base64_string (&input, j_input);
+ if (err)
+ {
+ error_object (result, "Error decoding Base-64 encoded 'data': %s",
+ gpg_strerror (err));
+ goto leave;
+ }
+ }
+ else
+ {
+ err = gpgme_data_new_from_mem (&input, j_input->valuestring,
+ strlen (j_input->valuestring), 0);
+ if (err)
+ {
+ error_object (result, "Error getting 'data': %s", gpg_strerror (err));
+ goto leave;
+ }
+ }
+ if (opt_mime)
+ gpgme_data_set_encoding (input, GPGME_DATA_ENCODING_MIME);
+
+
+ /* Create an output data object. */
+ err = gpgme_data_new (&output);
+ if (err)
+ {
+ error_object (result, "Error creating output data object: %s",
+ gpg_strerror (err));
+ goto leave;
+ }
+
+ /* Encrypt. */
+ err = gpgme_op_encrypt_ext (ctx, NULL, keystring, encrypt_flags,
+ input, output);
+ /* encrypt_result = gpgme_op_encrypt_result (ctx); */
+ if (err)
+ {
+ error_object (result, "Encryption failed: %s", gpg_strerror (err));
+ goto leave;
+ }
+ gpgme_data_release (input);
+ input = NULL;
+
+ /* We need to base64 if armoring has not been requested. */
+ err = make_data_object (result, output, chunksize,
+ "ciphertext", !gpgme_get_armor (ctx));
+ output = NULL;
+
+ leave:
+ xfree (keystring);
+ release_context (ctx);
+ gpgme_data_release (input);
+ gpgme_data_release (output);
+ return err;
+}
+
+
+
+static const char hlp_decrypt[] =
+ "op: \"decrypt\"\n"
+ "data: The encrypted data.\n"
+ "\n"
+ "Optional parameters:\n"
+ "protocol: Either \"openpgp\" (default) or \"cms\".\n"
+ "chunksize: Max number of bytes in the resulting \"data\".\n"
+ "\n"
+ "Optional boolean flags (default is false):\n"
+ "base64: Input data is base64 encoded.\n"
+ "\n"
+ "Response on success:\n"
+ "type: \"plaintext\"\n"
+ "data: The decrypted data. This may be base64 encoded.\n"
+ "base64: Boolean indicating whether data is base64 encoded.\n"
+ "mime: A Boolean indicating whether the data is a MIME object.\n"
+ "info: An optional object with extra information.\n"
+ "more: Optional boolean indicating that \"getmore\" is required.";
+static gpg_error_t
+op_decrypt (cjson_t request, cjson_t result)
+{
+ gpg_error_t err;
+ gpgme_ctx_t ctx = NULL;
+ gpgme_protocol_t protocol;
+ size_t chunksize;
+ int opt_base64;
+ cjson_t j_input;
+ gpgme_data_t input = NULL;
+ gpgme_data_t output = NULL;
+ gpgme_decrypt_result_t decrypt_result;
+
+ if ((err = get_protocol (request, &protocol)))
+ goto leave;
+ ctx = get_context (protocol);
+ if ((err = get_chunksize (request, &chunksize)))
+ goto leave;
+
+ if ((err = get_boolean_flag (request, "base64", 0, &opt_base64)))
+ goto leave;
+
+ /* Get the data. Note that INPUT is a shallow data object with the
+ * storage hold in REQUEST. */
+ j_input = cJSON_GetObjectItem (request, "data");
+ if (!j_input)
+ {
+ err = gpg_error (GPG_ERR_NO_DATA);
+ goto leave;
+ }
+ if (!cjson_is_string (j_input))
+ {
+ err = gpg_error (GPG_ERR_INV_VALUE);
+ goto leave;
+ }
+ if (opt_base64)
+ {
+ err = data_from_base64_string (&input, j_input);
+ if (err)
+ {
+ error_object (result, "Error decoding Base-64 encoded 'data': %s",
+ gpg_strerror (err));
+ goto leave;
+ }
+ }
+ else
+ {
+ err = gpgme_data_new_from_mem (&input, j_input->valuestring,
+ strlen (j_input->valuestring), 0);
+ if (err)
+ {
+ error_object (result, "Error getting 'data': %s", gpg_strerror (err));
+ goto leave;
+ }
+ }
+
+ /* Create an output data object. */
+ err = gpgme_data_new (&output);
+ if (err)
+ {
+ error_object (result, "Error creating output data object: %s",
+ gpg_strerror (err));
+ goto leave;
+ }
+
+ /* Decrypt. */
+ err = gpgme_op_decrypt_ext (ctx, GPGME_DECRYPT_VERIFY,
+ input, output);
+ decrypt_result = gpgme_op_decrypt_result (ctx);
+ if (err)
+ {
+ error_object (result, "Decryption failed: %s", gpg_strerror (err));
+ goto leave;
+ }
+ gpgme_data_release (input);
+ input = NULL;
+
+ if (decrypt_result->is_mime)
+ xjson_AddBoolToObject (result, "mime", 1);
+
+ err = make_data_object (result, output, chunksize, "plaintext", -1);
+ output = NULL;
+
+ leave:
+ release_context (ctx);
+ gpgme_data_release (input);
+ gpgme_data_release (output);
+ return err;
+}
+
+
+
+static const char hlp_getmore[] =
+ "op: \"getmore\"\n"
+ "\n"
+ "Optional parameters:\n"
+ "chunksize: Max number of bytes in the \"data\" object.\n"
+ "\n"
+ "Response on success:\n"
+ "type: Type of the pending data\n"
+ "data: The next chunk of data\n"
+ "base64: Boolean indicating whether data is base64 encoded\n"
+ "more: Optional boolean requesting another \"getmore\".";
+static gpg_error_t
+op_getmore (cjson_t request, cjson_t result)
+{
+ gpg_error_t err;
+ int c;
+ size_t n;
+ size_t chunksize;
+
+ if ((err = get_chunksize (request, &chunksize)))
+ goto leave;
+
+ /* Adjust the chunksize if we need to do base64 conversion. */
+ if (pending_data.base64)
+ chunksize = (chunksize / 4) * 3;
+
+ /* Do we have anything pending? */
+ if (!pending_data.buffer)
+ {
+ err = gpg_error (GPG_ERR_NO_DATA);
+ error_object (result, "Operation not possible: %s", gpg_strerror (err));
+ goto leave;
+ }
+
+ xjson_AddStringToObject (result, "type", pending_data.type);
+ xjson_AddBoolToObject (result, "base64", pending_data.base64);
+
+ if (pending_data.written >= pending_data.length)
+ {
+ /* EOF reached. This should not happen but we return an empty
+ * string once in case of client errors. */
+ gpgme_free (pending_data.buffer);
+ pending_data.buffer = NULL;
+ xjson_AddBoolToObject (result, "more", 0);
+ err = cjson_AddStringToObject (result, "data", "");
+ }
+ else
+ {
+ n = pending_data.length - pending_data.written;
+ if (n > chunksize)
+ {
+ n = chunksize;
+ xjson_AddBoolToObject (result, "more", 1);
+ }
+ else
+ xjson_AddBoolToObject (result, "more", 0);
+
+ c = pending_data.buffer[pending_data.written + n];
+ pending_data.buffer[pending_data.written + n] = 0;
+ if (pending_data.base64)
+ err = add_base64_to_object (result, "data",
+ (pending_data.buffer
+ + pending_data.written), n);
+ else
+ err = cjson_AddStringToObject (result, "data",
+ (pending_data.buffer
+ + pending_data.written));
+ pending_data.buffer[pending_data.written + n] = c;
+ if (!err)
+ {
+ pending_data.written += n;
+ if (pending_data.written >= pending_data.length)
+ {
+ gpgme_free (pending_data.buffer);
+ pending_data.buffer = NULL;
+ }
+ }
+ }
+
+ leave:
+ return err;
+}
+
+
+
+static const char hlp_help[] =
+ "The tool expects a JSON object with the request and responds with\n"
+ "another JSON object. Even on error a JSON object is returned. The\n"
+ "property \"op\" is mandatory and its string value selects the\n"
+ "operation; if the property \"help\" with the value \"true\" exists, the\n"
+ "operation is not performned but a string with the documentation\n"
+ "returned. To list all operations it is allowed to leave out \"op\" in\n"
+ "help mode. Supported values for \"op\" are:\n\n"
+ " encrypt Encrypt data.\n"
+ " getmore Retrieve remaining data.\n"
+ " help Help overview.";
+static gpg_error_t
+op_help (cjson_t request, cjson_t result)
+{
+ cjson_t j_tmp;
+ char *buffer = NULL;
+ const char *msg;
+
+ j_tmp = cJSON_GetObjectItem (request, "interactive_help");
+ if (opt_interactive && j_tmp && cjson_is_string (j_tmp))
+ msg = buffer = xstrconcat (hlp_help, "\n", j_tmp->valuestring, NULL);
+ else
+ msg = hlp_help;
+
+ xjson_AddStringToObject (result, "type", "help");
+ xjson_AddStringToObject (result, "msg", msg);
+
+ xfree (buffer);
+ return 0;
+}
+
+
+
+/*
+ * Dispatcher
+ */
+
+/* Process a request and return the response. The response is a newly
+ * allocated string or NULL in case of an error. */
+static char *
+process_request (const char *request)
+{
+ static struct {
+ const char *op;
+ gpg_error_t (*handler)(cjson_t request, cjson_t result);
+ const char * const helpstr;
+ } optbl[] = {
+ { "encrypt", op_encrypt, hlp_encrypt },
+ { "decrypt", op_decrypt, hlp_decrypt },
+ { "getmore", op_getmore, hlp_getmore },
+ { "help", op_help, hlp_help },
+ { NULL }
+ };
+ size_t erroff;
+ cjson_t json;
+ cjson_t j_tmp, j_op;
+ cjson_t response;
+ int helpmode;
+ const char *op;
+ char *res;
+ int idx;
+
+ response = xjson_CreateObject ();
+
+ json = cJSON_Parse (request, &erroff);
+ if (!json)
+ {
+ log_string (GPGRT_LOGLVL_INFO, request);
+ log_info ("invalid JSON object at offset %zu\n", erroff);
+ error_object (response, "invalid JSON object at offset %zu\n", erroff);
+ goto leave;
+ }
+
+ j_tmp = cJSON_GetObjectItem (json, "help");
+ helpmode = (j_tmp && cjson_is_true (j_tmp));
+
+ j_op = cJSON_GetObjectItem (json, "op");
+ if (!j_op || !cjson_is_string (j_op))
+ {
+ if (!helpmode)
+ {
+ error_object (response, "Property \"op\" missing");
+ goto leave;
+ }
+ op = "help"; /* Help summary. */
+ }
+ else
+ op = j_op->valuestring;
+
+ for (idx=0; optbl[idx].op; idx++)
+ if (!strcmp (op, optbl[idx].op))
+ break;
+ if (optbl[idx].op)
+ {
+ if (helpmode && strcmp (op, "help"))
+ {
+ xjson_AddStringToObject (response, "type", "help");
+ xjson_AddStringToObject (response, "op", op);
+ xjson_AddStringToObject (response, "msg", optbl[idx].helpstr);
+ }
+ else
+ {
+ gpg_error_t err;
+
+ /* If this is not the "getmore" command and we have any
+ * pending data release that data. */
+ if (pending_data.buffer && optbl[idx].handler != op_getmore)
+ {
+ gpgme_free (pending_data.buffer);
+ pending_data.buffer = NULL;
+ }
+
+ err = optbl[idx].handler (json, response);
+ if (err)
+ {
+ if (!(j_tmp = cJSON_GetObjectItem (response, "type"))
+ || !cjson_is_string (j_tmp)
+ || strcmp (j_tmp->valuestring, "error"))
+ {
+ /* No error type response - provide a generic one. */
+ error_object (response, "Operation failed: %s",
+ gpg_strerror (err));
+ }
+
+ xjson_AddStringToObject (response, "op", op);
+ }
+ }
+ }
+ else /* Operation not supported. */
+ {
+ error_object (response, "Unknown operation '%s'", op);
+ xjson_AddStringToObject (response, "op", op);
+ }
+
+ leave:
+ cJSON_Delete (json);
+ if (opt_interactive)
+ res = cJSON_Print (response);
+ else
+ res = cJSON_PrintUnformatted (response);
+ if (!res)
+ log_error ("Printing JSON data failed\n");
+ cJSON_Delete (response);
+ return res;
+}
+
+
+
+/*
+ * Driver code
+ */
+
+static char *
+get_file (const char *fname)
+{
+ gpg_error_t err;
+ estream_t fp;
+ struct stat st;
+ char *buf;
+ size_t buflen;
+
+ fp = es_fopen (fname, "r");
+ if (!fp)
+ {
+ err = gpg_error_from_syserror ();
+ log_error ("can't open '%s': %s\n", fname, gpg_strerror (err));
+ return NULL;
+ }
+
+ if (fstat (es_fileno(fp), &st))
+ {
+ err = gpg_error_from_syserror ();
+ log_error ("can't stat '%s': %s\n", fname, gpg_strerror (err));
+ es_fclose (fp);
+ return NULL;
+ }
+
+ buflen = st.st_size;
+ buf = xmalloc (buflen+1);
+ if (es_fread (buf, buflen, 1, fp) != 1)
+ {
+ err = gpg_error_from_syserror ();
+ log_error ("error reading '%s': %s\n", fname, gpg_strerror (err));
+ es_fclose (fp);
+ xfree (buf);
+ return NULL;
+ }
+ buf[buflen] = 0;
+ es_fclose (fp);
+
+ return buf;
+}
+
+
+/* Return a malloced line or NULL on EOF. Terminate on read
+ * error. */
+static char *
+get_line (void)
+{
+ char *line = NULL;
+ size_t linesize = 0;
+ gpg_error_t err;
+ size_t maxlength = 2048;
+ int n;
+ const char *s;
+ char *p;
+
+ again:
+ n = es_read_line (es_stdin, &line, &linesize, &maxlength);
+ if (n < 0)
+ {
+ err = gpg_error_from_syserror ();
+ log_error ("error reading line: %s\n", gpg_strerror (err));
+ exit (1);
+ }
+ if (!n)
+ {
+ xfree (line);
+ line = NULL;
+ return NULL; /* EOF */
+ }
+ if (!maxlength)
+ {
+ log_info ("line too long - skipped\n");
+ goto again;
+ }
+ if (memchr (line, 0, n))
+ log_info ("warning: line shortened due to embedded Nul character\n");
+
+ if (line[n-1] == '\n')
+ line[n-1] = 0;
+
+ /* Trim leading spaces. */
+ for (s=line; spacep (s); s++)
+ ;
+ if (s != line)
+ {
+ for (p=line; *s;)
+ *p++ = *s++;
+ *p = 0;
+ n = p - line;
+ }
+
+ return line;
+}
+
+
+/* Process meta commands used with the standard REPL. */
+static char *
+process_meta_commands (const char *request)
+{
+ char *result = NULL;
+
+ while (spacep (request))
+ request++;
+
+ if (!strncmp (request, "help", 4) && (spacep (request+4) || !request[4]))
+ {
+ if (request[4])
+ {
+ char *buf = xstrconcat ("{ \"help\":true, \"op\":\"", request+5,
+ "\" }", NULL);
+ result = process_request (buf);
+ xfree (buf);
+ }
+ else
+ result = process_request ("{ \"op\": \"help\","
+ " \"interactive_help\": "
+ "\"\\nMeta commands:\\n"
+ " ,read FNAME Process data from FILE\\n"
+ " ,help CMD Print help for a command\\n"
+ " ,quit Terminate process\""
+ "}");
+ }
+ else if (!strncmp (request, "quit", 4) && (spacep (request+4) || !request[4]))
+ exit (0);
+ else if (!strncmp (request, "read", 4) && (spacep (request+4) || !request[4]))
+ {
+ if (!request[4])
+ log_info ("usage: ,read FILENAME\n");
+ else
+ {
+ char *buffer = get_file (request + 5);
+ if (buffer)
+ {
+ result = process_request (buffer);
+ xfree (buffer);
+ }
+ }
+ }
+ else
+ log_info ("invalid meta command\n");
+
+ return result;
+}
+
+
+/* If STRING has a help response, return the MSG property in a human
+ * readable format. */
+static char *
+get_help_msg (const char *string)
+{
+ cjson_t json, j_type, j_msg;
+ const char *msg;
+ char *buffer = NULL;
+ char *p;
+
+ json = cJSON_Parse (string, NULL);
+ if (json)
+ {
+ j_type = cJSON_GetObjectItem (json, "type");
+ if (j_type && cjson_is_string (j_type)
+ && !strcmp (j_type->valuestring, "help"))
+ {
+ j_msg = cJSON_GetObjectItem (json, "msg");
+ if (j_msg || cjson_is_string (j_msg))
+ {
+ msg = j_msg->valuestring;
+ buffer = malloc (strlen (msg)+1);
+ if (buffer)
+ {
+ for (p=buffer; *msg; msg++)
+ {
+ if (*msg == '\\' && msg[1] == '\n')
+ *p++ = '\n';
+ else
+ *p++ = *msg;
+ }
+ *p = 0;
+ }
+ }
+ }
+ cJSON_Delete (json);
+ }
+ return buffer;
+}
+
+
+/* An interactive standard REPL. */
+static void
+interactive_repl (void)
+{
+ char *line = NULL;
+ char *request = NULL;
+ char *response = NULL;
+ char *p;
+ int first;
+
+ es_setvbuf (es_stdin, NULL, _IONBF, 0);
+#if GPGRT_VERSION_NUMBER >= 0x011d00 /* 1.29 */
+ es_fprintf (es_stderr, "%s %s ready (enter \",help\" for help)\n",
+ gpgrt_strusage (11), gpgrt_strusage (13));
+#endif
+ do
+ {
+ es_fputs ("> ", es_stderr);
+ es_fflush (es_stderr);
+ es_fflush (es_stdout);
+ xfree (line);
+ line = get_line ();
+ es_fflush (es_stderr);
+ es_fflush (es_stdout);
+
+ first = !request;
+ if (line && *line)
+ {
+ if (!request)
+ request = xstrdup (line);
+ else
+ request = xstrconcat (request, "\n", line, NULL);
+ }
+
+ if (!line)
+ es_fputs ("\n", es_stderr);
+
+ if (!line || !*line || (first && *request == ','))
+ {
+ /* Process the input. */
+ xfree (response);
+ response = NULL;
+ if (request && *request == ',')
+ {
+ response = process_meta_commands (request+1);
+ }
+ else if (request)
+ {
+ response = process_request (request);
+ }
+ xfree (request);
+ request = NULL;
+
+ if (response)
+ {
+ if (opt_interactive)
+ {
+ char *msg = get_help_msg (response);
+ if (msg)
+ {
+ xfree (response);
+ response = msg;
+ }
+ }
+
+ es_fputs ("===> ", es_stderr);
+ es_fflush (es_stderr);
+ for (p=response; *p; p++)
+ {
+ if (*p == '\n')
+ {
+ es_fflush (es_stdout);
+ es_fputs ("\n===> ", es_stderr);
+ es_fflush (es_stderr);
+ }
+ else
+ es_putc (*p, es_stdout);
+ }
+ es_fflush (es_stdout);
+ es_fputs ("\n", es_stderr);
+ }
+ }
+ }
+ while (line);
+
+ xfree (request);
+ xfree (response);
+ xfree (line);
+}
+
+
+/* Read and process a single request. */
+static void
+read_and_process_single_request (void)
+{
+ char *line = NULL;
+ char *request = NULL;
+ char *response = NULL;
+ size_t n;
+
+ for (;;)
+ {
+ xfree (line);
+ line = get_line ();
+ if (line && *line)
+ request = (request? xstrconcat (request, "\n", line, NULL)
+ /**/ : xstrdup (line));
+ if (!line)
+ {
+ if (request)
+ {
+ xfree (response);
+ response = process_request (request);
+ if (response)
+ {
+ es_fputs (response, es_stdout);
+ if ((n = strlen (response)) && response[n-1] != '\n')
+ es_fputc ('\n', es_stdout);
+ }
+ es_fflush (es_stdout);
+ }
+ break;
+ }
+ }
+
+ xfree (response);
+ xfree (request);
+ xfree (line);
+}
+
+
+/* The Native Messaging processing loop. */
+static void
+native_messaging_repl (void)
+{
+ gpg_error_t err;
+ uint32_t nrequest, nresponse;
+ char *request = NULL;
+ char *response = NULL;
+ size_t n;
+
+ /* Due to the length octets we need to switch the I/O stream into
+ * binary mode. */
+ es_set_binary (es_stdin);
+ es_set_binary (es_stdout);
+ es_setbuf (es_stdin, NULL); /* stdin needs to be unbuffered! */
+
+ for (;;)
+ {
+ /* Read length. Note that the protocol uses native endianess.
+ * Is it allowed to call such a thing a well thought out
+ * protocol? */
+ if (es_read (es_stdin, &nrequest, sizeof nrequest, &n))
+ {
+ err = gpg_error_from_syserror ();
+ log_error ("error reading request header: %s\n", gpg_strerror (err));
+ break;
+ }
+ if (!n)
+ break; /* EOF */
+ if (n != sizeof nrequest)
+ {
+ log_error ("error reading request header: short read\n");
+ break;
+ }
+ if (nrequest > MAX_REQUEST_SIZE)
+ {
+ log_error ("error reading request: request too long (%zu MiB)\n",
+ (size_t)nrequest / (1024*1024));
+ /* Fixme: Shall we read the request to the bit bucket and
+ * return an error reponse or just return an error reponse
+ * and terminate? Needs some testing. */
+ break;
+ }
+
+ /* Read request. */
+ request = xtrymalloc (nrequest);
+ if (!request)
+ {
+ err = gpg_error_from_syserror ();
+ log_error ("error reading request: Not enough memory for %zu MiB)\n",
+ (size_t)nrequest / (1024*1024));
+ /* FIXME: See comment above. */
+ break;
+ }
+ if (es_read (es_stdin, request, nrequest, &n))
+ {
+ err = gpg_error_from_syserror ();
+ log_error ("error reading request: %s\n", gpg_strerror (err));
+ break;
+ }
+ if (n != nrequest)
+ {
+ /* That is a protocol violation. */
+ xfree (response);
+ response = error_object_string ("Invalid request:"
+ " short read (%zu of %zu bytes)\n",
+ n, (size_t)nrequest);
+ }
+ else /* Process request */
+ {
+ if (opt_debug)
+ log_debug ("request='%s'\n", request);
+ xfree (response);
+ response = process_request (request);
+ if (opt_debug)
+ log_debug ("response='%s'\n", response);
+ }
+ nresponse = strlen (response);
+
+ /* Write response */
+ if (es_write (es_stdout, &nresponse, sizeof nresponse, &n))
+ {
+ err = gpg_error_from_syserror ();
+ log_error ("error writing request header: %s\n", gpg_strerror (err));
+ break;
+ }
+ if (n != sizeof nrequest)
+ {
+ log_error ("error writing request header: short write\n");
+ break;
+ }
+ if (es_write (es_stdout, response, nresponse, &n))
+ {
+ err = gpg_error_from_syserror ();
+ log_error ("error writing request: %s\n", gpg_strerror (err));
+ break;
+ }
+ if (n != nresponse)
+ {
+ log_error ("error writing request: short write\n");
+ break;
+ }
+ if (es_fflush (es_stdout) || es_ferror (es_stdout))
+ {
+ err = gpg_error_from_syserror ();
+ log_error ("error writing request: %s\n", gpg_strerror (err));
+ break;
+ }
+ }
+
+ xfree (response);
+ xfree (request);
+}
+
+
+
+static const char *
+my_strusage( int level )
+{
+ const char *p;
+
+ switch (level)
+ {
+ case 9: p = "LGPL-2.1-or-later"; break;
+ case 11: p = "gpgme-json"; break;
+ case 13: p = PACKAGE_VERSION; break;
+ case 14: p = "Copyright (C) 2018 g10 Code GmbH"; break;
+ case 19: p = "Please report bugs to <" PACKAGE_BUGREPORT ">.\n"; break;
+ case 1:
+ case 40:
+ p = "Usage: gpgme-json [OPTIONS]";
+ break;
+ case 41:
+ p = "Native messaging based GPGME operations.\n";
+ break;
+ case 42:
+ p = "1"; /* Flag print 40 as part of 41. */
+ break;
+ default: p = NULL; break;
+ }
+ return p;
+}
+
+int
+main (int argc, char *argv[])
+{
+#if GPGRT_VERSION_NUMBER < 0x011d00 /* 1.29 */
+
+ fprintf (stderr, "WARNING: Old libgpg-error - using limited mode\n");
+ native_messaging_repl ();
+
+#else /* This is a modern libgp-error. */
+
+ enum { CMD_DEFAULT = 0,
+ CMD_INTERACTIVE = 'i',
+ CMD_SINGLE = 's',
+ CMD_LIBVERSION = 501,
+ } cmd = CMD_DEFAULT;
+ enum {
+ OPT_DEBUG = 600
+ };
+
+ static gpgrt_opt_t opts[] = {
+ ARGPARSE_c (CMD_INTERACTIVE, "interactive", "Interactive REPL"),
+ ARGPARSE_c (CMD_SINGLE, "single", "Single request mode"),
+ ARGPARSE_c (CMD_LIBVERSION, "lib-version", "Show library version"),
+ ARGPARSE_s_n(OPT_DEBUG, "debug", "Flyswatter"),
+
+ ARGPARSE_end()
+ };
+ gpgrt_argparse_t pargs = { &argc, &argv};
+
+ gpgrt_set_strusage (my_strusage);
+
+#ifdef HAVE_SETLOCALE
+ setlocale (LC_ALL, "");
+#endif
+ gpgme_check_version (NULL);
+#ifdef LC_CTYPE
+ gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
+#endif
+#ifdef LC_MESSAGES
+ gpgme_set_locale (NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL));
+#endif
+
+ while (gpgrt_argparse (NULL, &pargs, opts))
+ {
+ switch (pargs.r_opt)
+ {
+ case CMD_INTERACTIVE:
+ opt_interactive = 1;
+ /* Fall trough. */
+ case CMD_SINGLE:
+ case CMD_LIBVERSION:
+ cmd = pargs.r_opt;
+ break;
+
+ case OPT_DEBUG: opt_debug = 1; break;
+
+ default:
+ pargs.err = ARGPARSE_PRINT_WARNING;
+ break;
+ }
+ }
+ gpgrt_argparse (NULL, &pargs, NULL);
+
+ if (!opt_debug)
+ {
+ const char *s = getenv ("GPGME_JSON_DEBUG");
+ if (s && atoi (s) > 0)
+ opt_debug = 1;
+ }
+
+ if (opt_debug)
+ {
+ const char *home = getenv ("HOME");
+ char *file = xstrconcat ("socket://",
+ home? home:"/tmp",
+ "/.gnupg/S.gpgme-json.log", NULL);
+ log_set_file (file);
+ xfree (file);
+ }
+
+ if (opt_debug)
+ { int i;
+ for (i=0; argv[i]; i++)
+ log_debug ("argv[%d]='%s'\n", i, argv[i]);
+ }
+
+ switch (cmd)
+ {
+ case CMD_DEFAULT:
+ native_messaging_repl ();
+ break;
+
+ case CMD_SINGLE:
+ read_and_process_single_request ();
+ break;
+
+ case CMD_INTERACTIVE:
+ interactive_repl ();
+ break;
+
+ case CMD_LIBVERSION:
+ printf ("Version from header: %s (0x%06x)\n",
+ GPGME_VERSION, GPGME_VERSION_NUMBER);
+ printf ("Version from binary: %s\n", gpgme_check_version (NULL));
+ printf ("Copyright blurb ...:%s\n", gpgme_check_version ("\x01\x01"));
+ break;
+ }
+
+ if (opt_debug)
+ log_debug ("ready");
+
+#endif /* This is a modern libgp-error. */
+ return 0;
+}
+#endif /* libgpg-error >= 1.28 */
diff --git a/src/gpgme-tool.c b/src/gpgme-tool.c
index 3e2dc78..e7a7a6f 100644
--- a/src/gpgme-tool.c
+++ b/src/gpgme-tool.c
@@ -3101,7 +3101,7 @@ cmd_hash_algo_name (assuan_context_t ctx, char *line)
static const char hlp_identify[] =
- "IDENTIY\n"
+ "IDENTIFY\n"
"\n"
"Identify the type of data set with the INPUT command.";
static gpg_error_t
diff --git a/src/gpgme-w32spawn.c b/src/gpgme-w32spawn.c
index d86c850..868dbd5 100644
--- a/src/gpgme-w32spawn.c
+++ b/src/gpgme-w32spawn.c
@@ -121,8 +121,6 @@ my_spawn (char **argv, struct spawn_fd_item_s *fd_list, unsigned int flags)
int duped_stdout = 0;
int duped_stderr = 0;
HANDLE hnul = INVALID_HANDLE_VALUE;
- /* FIXME. */
- int debug_me = 0;
i = 0;
while (argv[i])
@@ -142,7 +140,7 @@ my_spawn (char **argv, struct spawn_fd_item_s *fd_list, unsigned int flags)
memset (&si, 0, sizeof si);
si.cb = sizeof (si);
si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
- si.wShowWindow = debug_me ? SW_SHOW : SW_HIDE;
+ si.wShowWindow = (flags & IOSPAWN_FLAG_SHOW_WINDOW) ? SW_SHOW : SW_HIDE;
si.hStdInput = GetStdHandle (STD_INPUT_HANDLE);
si.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
si.hStdError = GetStdHandle (STD_ERROR_HANDLE);
diff --git a/src/gpgme.c b/src/gpgme.c
index d0a5afe..82d6747 100644
--- a/src/gpgme.c
+++ b/src/gpgme.c
@@ -248,6 +248,7 @@ gpgme_release (gpgme_ctx_t ctx)
free (ctx->lc_ctype);
free (ctx->lc_messages);
free (ctx->override_session_key);
+ free (ctx->request_origin);
_gpgme_engine_info_release (ctx->engine_info);
ctx->engine_info = NULL;
DESTROY_LOCK (ctx->lock);
@@ -486,13 +487,8 @@ gpgme_get_armor (gpgme_ctx_t ctx)
}
-/* Set the flag NAME for CTX to VALUE. The supported flags are:
- *
- * - full-status :: With a value of "1" the status callback set by
- * gpgme_set_status_cb returns all status lines
- * except for PROGRESS lines. With the default of
- * "0" the status callback is only called in certain
- * situations.
+/* Set the flag NAME for CTX to VALUE. Please consult the manual for
+ * a description of the flags.
*/
gpgme_error_t
gpgme_set_ctx_flag (gpgme_ctx_t ctx, const char *name, const char *value)
@@ -535,6 +531,17 @@ gpgme_set_ctx_flag (gpgme_ctx_t ctx, const char *name, const char *value)
{
ctx->auto_key_retrieve = abool;
}
+ else if (!strcmp (name, "request-origin"))
+ {
+ free (ctx->request_origin);
+ ctx->request_origin = strdup (value);
+ if (!ctx->request_origin)
+ err = gpg_error_from_syserror ();
+ }
+ else if (!strcmp (name, "no-symkey-cache"))
+ {
+ ctx->no_symkey_cache = abool;
+ }
else
err = gpg_error (GPG_ERR_UNKNOWN_NAME);
@@ -576,6 +583,14 @@ gpgme_get_ctx_flag (gpgme_ctx_t ctx, const char *name)
{
return ctx->auto_key_retrieve? "1":"";
}
+ else if (!strcmp (name, "request-origin"))
+ {
+ return ctx->request_origin? ctx->request_origin : "";
+ }
+ else if (!strcmp (name, "no-symkey-cache"))
+ {
+ return ctx->no_symkey_cache? "1":"";
+ }
else
return NULL;
}
diff --git a/src/gpgme.def b/src/gpgme.def
index cad30f6..a01d89a 100644
--- a/src/gpgme.def
+++ b/src/gpgme.def
@@ -267,5 +267,10 @@ EXPORTS
gpgme_op_conf_dir @199
+ gpgme_op_encrypt_ext @200
+ gpgme_op_encrypt_ext_start @201
+ gpgme_op_encrypt_sign_ext @202
+ gpgme_op_encrypt_sign_ext_start @203
+
; END
diff --git a/src/gpgme.h.in b/src/gpgme.h.in
index 31a9060..49fafb9 100644
--- a/src/gpgme.h.in
+++ b/src/gpgme.h.in
@@ -1,6 +1,6 @@
/* gpgme.h - Public interface to GnuPG Made Easy. -*- c -*-
* Copyright (C) 2000 Werner Koch (dd9jn)
- * Copyright (C) 2001-2017 g10 Code GmbH
+ * Copyright (C) 2001-2018 g10 Code GmbH
*
* This file is part of GPGME.
*
@@ -16,6 +16,7 @@
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: LGPL-2.1+
*
* Generated from gpgme.h.in for @GPGME_CONFIG_HOST@.
*/
@@ -37,14 +38,14 @@ extern "C" {
/* The version of this header should match the one of the library. Do
- not use this symbol in your application, use gpgme_check_version
- instead. The purpose of this macro is to let autoconf (using the
- AM_PATH_GPGME macro) check that this header matches the installed
- library. */
+ * not use this symbol in your application, use gpgme_check_version
+ * instead. The purpose of this macro is to let autoconf (using the
+ * AM_PATH_GPGME macro) check that this header matches the installed
+ * library. */
#define GPGME_VERSION "@PACKAGE_VERSION@"
/* The version number of this header. It may be used to handle minor
- API incompatibilities. */
+ * API incompatibilities. */
#define GPGME_VERSION_NUMBER @VERSION_NUMBER@
@@ -87,7 +88,7 @@ extern "C" {
/* The macro _GPGME_DEPRECATED_OUTSIDE_GPGME suppresses warnings for
- fields we must access in GPGME for ABI compatibility. */
+ * fields we must access in GPGME for ABI compatibility. */
#ifdef _GPGME_IN_GPGME
#define _GPGME_DEPRECATED_OUTSIDE_GPGME(a,b)
#else
@@ -113,7 +114,7 @@ extern "C" {
*/
/* The context holds some global state and configuration options, as
- well as the results of a crypto operation. */
+ * well as the results of a crypto operation. */
struct gpgme_context;
typedef struct gpgme_context *gpgme_ctx_t;
@@ -124,7 +125,8 @@ typedef struct gpgme_data *gpgme_data_t;
/*
- * Wrappers for the libgpg-error library.
+ * Wrappers for the libgpg-error library. They are generally not
+ * needed and the gpg-error versions may be used instead.
*/
typedef gpg_error_t gpgme_error_t;
@@ -140,7 +142,7 @@ gpgme_err_make (gpgme_err_source_t source, gpgme_err_code_t code)
/* The user can define GPGME_ERR_SOURCE_DEFAULT before including this
- file to specify a default source for gpgme_error. */
+ * file to specify a default source for gpgme_error. */
#ifndef GPGME_ERR_SOURCE_DEFAULT
#define GPGME_ERR_SOURCE_DEFAULT GPG_ERR_SOURCE_USER_1
#endif
@@ -167,45 +169,46 @@ gpgme_err_source (gpgme_error_t err)
/* Return a pointer to a string containing a description of the error
- code in the error value ERR. This function is not thread safe. */
+ * code in the error value ERR. This function is not thread safe. */
const char *gpgme_strerror (gpgme_error_t err);
/* Return the error string for ERR in the user-supplied buffer BUF of
- size BUFLEN. This function is, in contrast to gpg_strerror,
- thread-safe if a thread-safe strerror_r() function is provided by
- the system. If the function succeeds, 0 is returned and BUF
- contains the string describing the error. If the buffer was not
- large enough, ERANGE is returned and BUF contains as much of the
- beginning of the error string as fits into the buffer. */
+ * size BUFLEN. This function is, in contrast to gpg_strerror,
+ * thread-safe if a thread-safe strerror_r() function is provided by
+ * the system. If the function succeeds, 0 is returned and BUF
+ * contains the string describing the error. If the buffer was not
+ * large enough, ERANGE is returned and BUF contains as much of the
+ * beginning of the error string as fits into the buffer. */
int gpgme_strerror_r (gpg_error_t err, char *buf, size_t buflen);
/* Return a pointer to a string containing a description of the error
- source in the error value ERR. */
+ * source in the error value ERR. */
const char *gpgme_strsource (gpgme_error_t err);
/* Retrieve the error code for the system error ERR. This returns
- GPG_ERR_UNKNOWN_ERRNO if the system error is not mapped (report
- this). */
+ * GPG_ERR_UNKNOWN_ERRNO if the system error is not mapped (report
+ * this). */
gpgme_err_code_t gpgme_err_code_from_errno (int err);
/* Retrieve the system error for the error code CODE. This returns 0
- if CODE is not a system error code. */
+ * if CODE is not a system error code. */
int gpgme_err_code_to_errno (gpgme_err_code_t code);
/* Retrieve the error code directly from the ERRNO variable. This
- returns GPG_ERR_UNKNOWN_ERRNO if the system error is not mapped
- (report this) and GPG_ERR_MISSING_ERRNO if ERRNO has the value 0. */
+ * returns GPG_ERR_UNKNOWN_ERRNO if the system error is not mapped
+ * (report this) and GPG_ERR_MISSING_ERRNO if ERRNO has the value 0. */
gpgme_err_code_t gpgme_err_code_from_syserror (void);
/* Set the ERRNO variable. This function is the preferred way to set
- ERRNO due to peculiarities on WindowsCE. */
+ * ERRNO due to peculiarities on WindowsCE. */
void gpgme_err_set_errno (int err);
/* Return an error value with the error source SOURCE and the system
- error ERR. FIXME: Should be inline. */
+ * error ERR. FIXME: Should be inline. */
gpgme_error_t gpgme_err_make_from_errno (gpgme_err_source_t source, int err);
-/* Return an error value with the system error ERR. FIXME: Should be inline. */
+/* Return an error value with the system error ERR.
+ * inline. */
gpgme_error_t gpgme_error_from_errno (int err);
@@ -373,6 +376,8 @@ gpgme_protocol_t;
#define GPGME_KEYLIST_MODE_EPHEMERAL 128
#define GPGME_KEYLIST_MODE_VALIDATE 256
+#define GPGME_KEYLIST_MODE_LOCATE (1|2)
+
typedef unsigned int gpgme_keylist_mode_t;
@@ -417,7 +422,7 @@ struct _gpgme_sig_notation
struct _gpgme_sig_notation *next;
/* If NAME is a null pointer, then VALUE contains a policy URL
- rather than a notation. */
+ * rather than a notation. */
char *name;
/* The value of the notation data. */
@@ -632,10 +637,10 @@ struct _gpgme_key_sig
/* Same as in gpgme_signature_t. */
gpgme_error_t status;
+ /* Deprecated; use SIG_CLASS instead. */
#ifdef __cplusplus
unsigned int _obsolete_class _GPGME_DEPRECATED(0,4);
#else
- /* Must be set to SIG_CLASS below. */
unsigned int class _GPGME_DEPRECATED_OUTSIDE_GPGME(0,4);
#endif
@@ -874,10 +879,10 @@ gpgme_error_t gpgme_set_protocol (gpgme_ctx_t ctx, gpgme_protocol_t proto);
gpgme_protocol_t gpgme_get_protocol (gpgme_ctx_t ctx);
/* Set the crypto protocol to be used by CTX to PROTO.
- gpgme_set_protocol actually sets the backend engine. This sets the
- crypto protocol used in engines that support more than one crypto
- prococol (for example, an UISERVER can support OpenPGP and CMS).
- This is reset to the default with gpgme_set_protocol. */
+ * gpgme_set_protocol actually sets the backend engine. This sets the
+ * crypto protocol used in engines that support more than one crypto
+ * prococol (for example, an UISERVER can support OpenPGP and CMS).
+ * This is reset to the default with gpgme_set_protocol. */
gpgme_error_t gpgme_set_sub_protocol (gpgme_ctx_t ctx,
gpgme_protocol_t proto);
@@ -929,47 +934,47 @@ gpgme_error_t gpgme_set_pinentry_mode (gpgme_ctx_t ctx,
gpgme_pinentry_mode_t gpgme_get_pinentry_mode (gpgme_ctx_t ctx);
/* Set the passphrase callback function in CTX to CB. HOOK_VALUE is
- passed as first argument to the passphrase callback function. */
+ * passed as first argument to the passphrase callback function. */
void gpgme_set_passphrase_cb (gpgme_ctx_t ctx,
gpgme_passphrase_cb_t cb, void *hook_value);
/* Get the current passphrase callback function in *CB and the current
- hook value in *HOOK_VALUE. */
+ * hook value in *HOOK_VALUE. */
void gpgme_get_passphrase_cb (gpgme_ctx_t ctx, gpgme_passphrase_cb_t *cb,
void **hook_value);
/* Set the progress callback function in CTX to CB. HOOK_VALUE is
- passed as first argument to the progress callback function. */
+ * passed as first argument to the progress callback function. */
void gpgme_set_progress_cb (gpgme_ctx_t c, gpgme_progress_cb_t cb,
void *hook_value);
/* Get the current progress callback function in *CB and the current
- hook value in *HOOK_VALUE. */
+ * hook value in *HOOK_VALUE. */
void gpgme_get_progress_cb (gpgme_ctx_t ctx, gpgme_progress_cb_t *cb,
void **hook_value);
/* Set the status callback function in CTX to CB. HOOK_VALUE is
- passed as first argument to the status callback function. */
+ * passed as first argument to the status callback function. */
void gpgme_set_status_cb (gpgme_ctx_t c, gpgme_status_cb_t cb,
void *hook_value);
/* Get the current status callback function in *CB and the current
- hook value in *HOOK_VALUE. */
+ * hook value in *HOOK_VALUE. */
void gpgme_get_status_cb (gpgme_ctx_t ctx, gpgme_status_cb_t *cb,
void **hook_value);
/* This function sets the locale for the context CTX, or the default
- locale if CTX is a null pointer. */
+ * locale if CTX is a null pointer. */
gpgme_error_t gpgme_set_locale (gpgme_ctx_t ctx, int category,
const char *value);
/* Get the information about the configured engines. A pointer to the
- first engine in the statically allocated linked list is returned.
- The returned data is valid until the next gpgme_ctx_set_engine_info. */
+ * first engine in the statically allocated linked list is returned.
+ * The returned data is valid until the next gpgme_ctx_set_engine_info. */
gpgme_engine_info_t gpgme_ctx_get_engine_info (gpgme_ctx_t ctx);
/* Set the engine info for the context CTX, protocol PROTO, to the
- file name FILE_NAME and the home directory HOME_DIR. */
+ * file name FILE_NAME and the home directory HOME_DIR. */
gpgme_error_t gpgme_ctx_set_engine_info (gpgme_ctx_t ctx,
gpgme_protocol_t proto,
const char *file_name,
@@ -991,10 +996,10 @@ gpgme_key_t gpgme_signers_enum (const gpgme_ctx_t ctx, int seq);
void gpgme_sig_notation_clear (gpgme_ctx_t ctx);
/* Add the human-readable notation data with name NAME and value VALUE
- to the context CTX, using the flags FLAGS. If NAME is NULL, then
- VALUE should be a policy URL. The flag
- GPGME_SIG_NOTATION_HUMAN_READABLE is forced to be true for notation
- data, and false for policy URLs. */
+ * to the context CTX, using the flags FLAGS. If NAME is NULL, then
+ * VALUE should be a policy URL. The flag
+ * GPGME_SIG_NOTATION_HUMAN_READABLE is forced to be true for notation
+ * data, and false for policy URLs. */
gpgme_error_t gpgme_sig_notation_add (gpgme_ctx_t ctx, const char *name,
const char *value,
gpgme_sig_notation_flags_t flags);
@@ -1018,17 +1023,17 @@ const char *gpgme_get_sender (gpgme_ctx_t ctx);
typedef gpgme_error_t (*gpgme_io_cb_t) (void *data, int fd);
/* The type of a function that can register FNC as the I/O callback
- function for the file descriptor FD with direction dir (0: for writing,
- 1: for reading). FNC_DATA should be passed as DATA to FNC. The
- function should return a TAG suitable for the corresponding
- gpgme_remove_io_cb_t, and an error value. */
+ * function for the file descriptor FD with direction dir (0: for writing,
+ * 1: for reading). FNC_DATA should be passed as DATA to FNC. The
+ * function should return a TAG suitable for the corresponding
+ * gpgme_remove_io_cb_t, and an error value. */
typedef gpgme_error_t (*gpgme_register_io_cb_t) (void *data, int fd, int dir,
gpgme_io_cb_t fnc,
void *fnc_data, void **tag);
/* The type of a function that can remove a previously registered I/O
- callback function given TAG as returned by the register
- function. */
+ * callback function given TAG as returned by the register
+ * function. */
typedef void (*gpgme_remove_io_cb_t) (void *tag);
typedef enum
@@ -1043,7 +1048,7 @@ gpgme_event_io_t;
struct gpgme_io_event_done_data
{
/* A fatal IPC error or an operational error in state-less
- protocols. */
+ * protocols. */
gpgme_error_t err;
/* An operational errors in session-based protocols. */
@@ -1052,7 +1057,7 @@ struct gpgme_io_event_done_data
typedef struct gpgme_io_event_done_data *gpgme_io_event_done_data_t;
/* The type of a function that is called when a context finished an
- operation. */
+ * operation. */
typedef void (*gpgme_event_io_cb_t) (void *data, gpgme_event_io_t type,
void *type_data);
@@ -1073,13 +1078,13 @@ void gpgme_set_io_cbs (gpgme_ctx_t ctx, gpgme_io_cbs_t io_cbs);
void gpgme_get_io_cbs (gpgme_ctx_t ctx, gpgme_io_cbs_t io_cbs);
/* Wrappers around the internal I/O functions for use with
- gpgme_passphrase_cb_t and gpgme_interact_cb_t. */
+ * gpgme_passphrase_cb_t and gpgme_interact_cb_t. */
@API__SSIZE_T@ gpgme_io_read (int fd, void *buffer, size_t count);
@API__SSIZE_T@ gpgme_io_write (int fd, const void *buffer, size_t count);
int gpgme_io_writen (int fd, const void *buffer, size_t count);
/* Process the pending operation and, if HANG is non-zero, wait for
- the pending operation to finish. */
+ * the pending operation to finish. */
gpgme_ctx_t gpgme_wait (gpgme_ctx_t ctx, gpgme_error_t *status, int hang);
gpgme_ctx_t gpgme_wait_ext (gpgme_ctx_t ctx, gpgme_error_t *status,
@@ -1098,21 +1103,21 @@ gpgme_error_t gpgme_cancel_async (gpgme_ctx_t ctx);
*/
/* Read up to SIZE bytes into buffer BUFFER from the data object with
- the handle HANDLE. Return the number of characters read, 0 on EOF
- and -1 on error. If an error occurs, errno is set. */
+ * the handle HANDLE. Return the number of characters read, 0 on EOF
+ * and -1 on error. If an error occurs, errno is set. */
typedef @API__SSIZE_T@ (*gpgme_data_read_cb_t) (void *handle, void *buffer,
size_t size);
/* Write up to SIZE bytes from buffer BUFFER to the data object with
- the handle HANDLE. Return the number of characters written, or -1
- on error. If an error occurs, errno is set. */
+ * the handle HANDLE. Return the number of characters written, or -1
+ * on error. If an error occurs, errno is set. */
typedef @API__SSIZE_T@ (*gpgme_data_write_cb_t) (void *handle, const void *buffer,
size_t size);
/* Set the current position from where the next read or write starts
- in the data object with the handle HANDLE to OFFSET, relativ to
- WHENCE. Returns the new offset in bytes from the beginning of the
- data object. */
+ * in the data object with the handle HANDLE to OFFSET, relativ to
+ * WHENCE. Returns the new offset in bytes from the beginning of the
+ * data object. */
typedef @API__OFF_T@ (*gpgme_data_seek_cb_t) (void *handle,
@API__OFF_T@ offset, int whence);
@@ -1129,19 +1134,19 @@ struct gpgme_data_cbs
typedef struct gpgme_data_cbs *gpgme_data_cbs_t;
/* Read up to SIZE bytes into buffer BUFFER from the data object with
- the handle DH. Return the number of characters read, 0 on EOF and
- -1 on error. If an error occurs, errno is set. */
+ * the handle DH. Return the number of characters read, 0 on EOF and
+ * -1 on error. If an error occurs, errno is set. */
@API__SSIZE_T@ gpgme_data_read (gpgme_data_t dh, void *buffer, size_t size);
/* Write up to SIZE bytes from buffer BUFFER to the data object with
- the handle DH. Return the number of characters written, or -1 on
- error. If an error occurs, errno is set. */
+ * the handle DH. Return the number of characters written, or -1 on
+ * error. If an error occurs, errno is set. */
@API__SSIZE_T@ gpgme_data_write (gpgme_data_t dh, const void *buffer, size_t size);
/* Set the current position from where the next read or write starts
- in the data object with the handle DH to OFFSET, relativ to WHENCE.
- Returns the new offset in bytes from the beginning of the data
- object. */
+ * in the data object with the handle DH to OFFSET, relativ to WHENCE.
+ * Returns the new offset in bytes from the beginning of the data
+ * object. */
@API__OFF_T@ gpgme_data_seek (gpgme_data_t dh, @API__OFF_T@ offset, int whence);
/* Create a new data buffer and return it in R_DH. */
@@ -1151,19 +1156,19 @@ gpgme_error_t gpgme_data_new (gpgme_data_t *r_dh);
void gpgme_data_release (gpgme_data_t dh);
/* Create a new data buffer filled with SIZE bytes starting from
- BUFFER. If COPY is zero, copying is delayed until necessary, and
- the data is taken from the original location when needed. */
+ * BUFFER. If COPY is zero, copying is delayed until necessary, and
+ * the data is taken from the original location when needed. */
gpgme_error_t gpgme_data_new_from_mem (gpgme_data_t *r_dh,
const char *buffer, size_t size,
int copy);
/* Destroy the data buffer DH and return a pointer to its content.
- The memory has be to released with gpgme_free() by the user. It's
- size is returned in R_LEN. */
+ * The memory has be to released with gpgme_free() by the user. It's
+ * size is returned in R_LEN. */
char *gpgme_data_release_and_get_mem (gpgme_data_t dh, size_t *r_len);
/* Release the memory returned by gpgme_data_release_and_get_mem() and
- some other functions. */
+ * some other functions. */
void gpgme_free (void *buffer);
gpgme_error_t gpgme_data_new_from_cbs (gpgme_data_t *dh,
@@ -1182,11 +1187,11 @@ gpgme_error_t gpgme_data_set_encoding (gpgme_data_t dh,
gpgme_data_encoding_t enc);
/* Get the file name associated with the data object with handle DH, or
- NULL if there is none. */
+ * NULL if there is none. */
char *gpgme_data_get_file_name (gpgme_data_t dh);
/* Set the file name associated with the data object with handle DH to
- FILE_NAME. */
+ * FILE_NAME. */
gpgme_error_t gpgme_data_set_file_name (gpgme_data_t dh,
const char *file_name);
@@ -1199,15 +1204,15 @@ gpgme_data_type_t gpgme_data_identify (gpgme_data_t dh, int reserved);
/* Create a new data buffer filled with the content of file FNAME.
- COPY must be non-zero. For delayed read, please use
- gpgme_data_new_from_fd or gpgme_data_new_from_stream instead. */
+ * COPY must be non-zero. For delayed read, please use
+ * gpgme_data_new_from_fd or gpgme_data_new_from_stream instead. */
gpgme_error_t gpgme_data_new_from_file (gpgme_data_t *r_dh,
const char *fname,
int copy);
/* Create a new data buffer filled with LENGTH bytes starting from
- OFFSET within the file FNAME or stream FP (exactly one must be
- non-zero). */
+ * OFFSET within the file FNAME or stream FP (exactly one must be
+ * non-zero). */
gpgme_error_t gpgme_data_new_from_filepart (gpgme_data_t *r_dh,
const char *fname, FILE *fp,
@API__OFF_T@ offset, size_t length);
@@ -1222,7 +1227,7 @@ gpgme_error_t gpgme_data_rewind (gpgme_data_t dh);
*/
/* Get the key with the fingerprint FPR from the crypto backend. If
- SECRET is true, get the secret key. */
+ * SECRET is true, get the secret key. */
gpgme_error_t gpgme_get_key (gpgme_ctx_t ctx, const char *fpr,
gpgme_key_t *r_key, int secret);
@@ -1233,7 +1238,7 @@ gpgme_error_t gpgme_key_from_uid (gpgme_key_t *key, const char *name);
void gpgme_key_ref (gpgme_key_t key);
/* Release a reference to KEY. If this was the last one the key is
- destroyed. */
+ * destroyed. */
void gpgme_key_unref (gpgme_key_t key);
void gpgme_key_release (gpgme_key_t key);
@@ -1266,22 +1271,35 @@ typedef enum
GPGME_ENCRYPT_NO_COMPRESS = 16,
GPGME_ENCRYPT_SYMMETRIC = 32,
GPGME_ENCRYPT_THROW_KEYIDS = 64,
- GPGME_ENCRYPT_WRAP = 128
+ GPGME_ENCRYPT_WRAP = 128,
+ GPGME_ENCRYPT_WANT_ADDRESS = 256
}
gpgme_encrypt_flags_t;
/* Encrypt plaintext PLAIN within CTX for the recipients RECP and
- store the resulting ciphertext in CIPHER. */
+ * store the resulting ciphertext in CIPHER. */
gpgme_error_t gpgme_op_encrypt_start (gpgme_ctx_t ctx, gpgme_key_t recp[],
gpgme_encrypt_flags_t flags,
- gpgme_data_t plain, gpgme_data_t cipher);
+ gpgme_data_t plain,
+ gpgme_data_t cipher);
gpgme_error_t gpgme_op_encrypt (gpgme_ctx_t ctx, gpgme_key_t recp[],
gpgme_encrypt_flags_t flags,
- gpgme_data_t plain, gpgme_data_t cipher);
+ gpgme_data_t plain,
+ gpgme_data_t cipher);
+gpgme_error_t gpgme_op_encrypt_ext_start (gpgme_ctx_t ctx, gpgme_key_t recp[],
+ const char *recpstring,
+ gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain,
+ gpgme_data_t cipher);
+gpgme_error_t gpgme_op_encrypt_ext (gpgme_ctx_t ctx, gpgme_key_t recp[],
+ const char *recpstring,
+ gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain,
+ gpgme_data_t cipher);
/* Encrypt plaintext PLAIN within CTX for the recipients RECP and
- store the resulting ciphertext in CIPHER. Also sign the ciphertext
- with the signers in CTX. */
+ * store the resulting ciphertext in CIPHER. Also sign the ciphertext
+ * with the signers in CTX. */
gpgme_error_t gpgme_op_encrypt_sign_start (gpgme_ctx_t ctx,
gpgme_key_t recp[],
gpgme_encrypt_flags_t flags,
@@ -1289,7 +1307,19 @@ gpgme_error_t gpgme_op_encrypt_sign_start (gpgme_ctx_t ctx,
gpgme_data_t cipher);
gpgme_error_t gpgme_op_encrypt_sign (gpgme_ctx_t ctx, gpgme_key_t recp[],
gpgme_encrypt_flags_t flags,
- gpgme_data_t plain, gpgme_data_t cipher);
+ gpgme_data_t plain,
+ gpgme_data_t cipher);
+gpgme_error_t gpgme_op_encrypt_sign_ext_start (gpgme_ctx_t ctx,
+ gpgme_key_t recp[],
+ const char *recpstring,
+ gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain,
+ gpgme_data_t cipher);
+gpgme_error_t gpgme_op_encrypt_sign_ext (gpgme_ctx_t ctx, gpgme_key_t recp[],
+ const char *recpstring,
+ gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain,
+ gpgme_data_t cipher);
/*
@@ -1317,6 +1347,7 @@ struct _gpgme_recipient
};
typedef struct _gpgme_recipient *gpgme_recipient_t;
+
/* An object to return results from a decryption operation.
* This structure shall be considered read-only and an application
* must not allocate such a structure on its own. */
@@ -1331,24 +1362,33 @@ struct _gpgme_op_decrypt_result
* mode. */
unsigned int is_de_vs : 1;
+ /* The message claims that the content is a MIME object. */
+ unsigned int is_mime : 1;
+
/* Internal to GPGME, do not use. */
- int _unused : 30;
+ int _unused : 29;
gpgme_recipient_t recipients;
/* The original file name of the plaintext message, if
- available. */
+ * available. */
char *file_name;
/* A textual representation of the session key used to decrypt the
* message, if available */
char *session_key;
+
+ /* A string with the symmetric encryption algorithm and mode using
+ * the format "<algo>.<mode>". */
+ char *symkey_algo;
};
typedef struct _gpgme_op_decrypt_result *gpgme_decrypt_result_t;
+
/* Retrieve a pointer to the result of the decrypt operation. */
gpgme_decrypt_result_t gpgme_op_decrypt_result (gpgme_ctx_t ctx);
+
/* The valid decryption flags. */
typedef enum
{
@@ -1357,15 +1397,16 @@ typedef enum
}
gpgme_decrypt_flags_t;
+
/* Decrypt ciphertext CIPHER within CTX and store the resulting
- plaintext in PLAIN. */
+ * plaintext in PLAIN. */
gpgme_error_t gpgme_op_decrypt_start (gpgme_ctx_t ctx, gpgme_data_t cipher,
gpgme_data_t plain);
gpgme_error_t gpgme_op_decrypt (gpgme_ctx_t ctx,
gpgme_data_t cipher, gpgme_data_t plain);
/* Decrypt ciphertext CIPHER and make a signature verification within
- CTX and store the resulting plaintext in PLAIN. */
+ * CTX and store the resulting plaintext in PLAIN. */
gpgme_error_t gpgme_op_decrypt_verify_start (gpgme_ctx_t ctx,
gpgme_data_t cipher,
gpgme_data_t plain);
@@ -1407,7 +1448,7 @@ struct _gpgme_new_signature
gpgme_hash_algo_t hash_algo;
/* Internal to GPGME, do not use. Must be set to the same value as
- CLASS below. */
+ * CLASS below. */
unsigned long _obsolete_class;
/* Signature creation time. */
@@ -1416,10 +1457,10 @@ struct _gpgme_new_signature
/* The fingerprint of the signature. */
char *fpr;
+ /* Deprecated; use SIG_CLASS instead. */
#ifdef __cplusplus
unsigned int _obsolete_class_2;
#else
- /* Must be set to SIG_CLASS below. */
unsigned int class _GPGME_DEPRECATED_OUTSIDE_GPGME(0,4);
#endif
@@ -1440,6 +1481,7 @@ struct _gpgme_op_sign_result
};
typedef struct _gpgme_op_sign_result *gpgme_sign_result_t;
+
/* Retrieve a pointer to the result of the signing operation. */
gpgme_sign_result_t gpgme_op_sign_result (gpgme_ctx_t ctx);
@@ -1533,6 +1575,7 @@ struct _gpgme_signature
};
typedef struct _gpgme_signature *gpgme_signature_t;
+
/* An object to return the results of a verify operation.
* This structure shall be considered read-only and an application
* must not allocate such a structure on its own. */
@@ -1543,9 +1586,16 @@ struct _gpgme_op_verify_result
/* The original file name of the plaintext message, if
available. */
char *file_name;
+
+ /* The message claims that the content is a MIME object. */
+ unsigned int is_mime : 1;
+
+ /* Internal to GPGME; do not use. */
+ unsigned int _unused : 31;
};
typedef struct _gpgme_op_verify_result *gpgme_verify_result_t;
+
/* Retrieve a pointer to the result of the verify operation. */
gpgme_verify_result_t gpgme_op_verify_result (gpgme_ctx_t ctx);
@@ -1590,6 +1640,7 @@ struct _gpgme_import_status
};
typedef struct _gpgme_import_status *gpgme_import_status_t;
+
/* Import result object.
* This structure shall be considered read-only and an application
* must not allocate such a structure on its own. */
@@ -1639,9 +1690,13 @@ struct _gpgme_op_import_result
/* List of keys for which an import was attempted. */
gpgme_import_status_t imports;
+
+ /* Number of v3 keys skipped. */
+ int skipped_v3_keys;
};
typedef struct _gpgme_op_import_result *gpgme_import_result_t;
+
/* Retrieve a pointer to the result of the import operation. */
gpgme_import_result_t gpgme_op_import_result (gpgme_ctx_t ctx);
@@ -1699,6 +1754,7 @@ gpgme_error_t gpgme_op_export_keys (gpgme_ctx_t ctx,
#define GPGME_CREATE_FORCE (1 << 12) /* Force creation. */
#define GPGME_CREATE_NOEXPIRE (1 << 13) /* Create w/o expiration. */
+
/* An object to return result from a key generation.
* This structure shall be considered read-only and an application
* must not allocate such a structure on its own. */
@@ -1729,9 +1785,10 @@ struct _gpgme_op_genkey_result
};
typedef struct _gpgme_op_genkey_result *gpgme_genkey_result_t;
+
/* Generate a new keypair and add it to the keyring. PUBKEY and
- SECKEY should be null for now. PARMS specifies what keys should be
- generated. */
+ * SECKEY should be null for now. PARMS specifies what keys should be
+ * generated. */
gpgme_error_t gpgme_op_genkey_start (gpgme_ctx_t ctx, const char *parms,
gpgme_data_t pubkey, gpgme_data_t seckey);
gpgme_error_t gpgme_op_genkey (gpgme_ctx_t ctx, const char *parms,
@@ -1797,7 +1854,7 @@ gpgme_genkey_result_t gpgme_op_genkey_result (gpgme_ctx_t ctx);
/* Delete KEY from the keyring. If ALLOW_SECRET is non-zero, secret
- keys are also deleted. */
+ * keys are also deleted. */
gpgme_error_t gpgme_op_delete_start (gpgme_ctx_t ctx, const gpgme_key_t key,
int allow_secret);
gpgme_error_t gpgme_op_delete (gpgme_ctx_t ctx, const gpgme_key_t key,
@@ -1916,7 +1973,7 @@ gpgme_error_t gpgme_op_keylist_end (gpgme_ctx_t ctx);
*/
/* Change the passphrase for KEY. FLAGS is reserved for future use
- and must be passed as 0. */
+ * and must be passed as 0. */
gpgme_error_t gpgme_op_passwd_start (gpgme_ctx_t ctx, gpgme_key_t key,
unsigned int flags);
gpgme_error_t gpgme_op_passwd (gpgme_ctx_t ctx, gpgme_key_t key,
@@ -1981,7 +2038,7 @@ gpgme_error_t gpgme_op_trustlist_end (gpgme_ctx_t ctx);
void gpgme_trust_item_ref (gpgme_trust_item_t item);
/* Release a reference to ITEM. If this was the last one the trust
- item is destroyed. */
+ * item is destroyed. */
void gpgme_trust_item_unref (gpgme_trust_item_t item);
@@ -2007,11 +2064,12 @@ gpgme_error_t gpgme_op_getauditlog (gpgme_ctx_t ctx, gpgme_data_t output,
/* Flags for the spawn operations. */
#define GPGME_SPAWN_DETACHED 1
#define GPGME_SPAWN_ALLOW_SET_FG 2
+#define GPGME_SPAWN_SHOW_WINDOW 4
/* Run the command FILE with the arguments in ARGV. Connect stdin to
- DATAIN, stdout to DATAOUT, and STDERR to DATAERR. If one the data
- streams is NULL, connect to /dev/null instead. */
+ * DATAIN, stdout to DATAOUT, and STDERR to DATAERR. If one the data
+ * streams is NULL, connect to /dev/null instead. */
gpgme_error_t gpgme_op_spawn_start (gpgme_ctx_t ctx,
const char *file, const char *argv[],
gpgme_data_t datain,
@@ -2027,6 +2085,7 @@ gpgme_error_t gpgme_op_spawn (gpgme_ctx_t ctx,
/*
* Low-level Assuan protocol access.
*/
+
typedef gpgme_error_t (*gpgme_assuan_data_cb_t)
(void *opaque, const void *data, size_t datalen);
@@ -2038,7 +2097,7 @@ typedef gpgme_error_t (*gpgme_assuan_status_cb_t)
(void *opaque, const char *status, const char *args);
/* Send the Assuan COMMAND and return results via the callbacks.
- Asynchronous variant. */
+ * Asynchronous variant. */
gpgme_error_t gpgme_op_assuan_transact_start (gpgme_ctx_t ctx,
const char *command,
gpgme_assuan_data_cb_t data_cb,
@@ -2049,7 +2108,7 @@ gpgme_error_t gpgme_op_assuan_transact_start (gpgme_ctx_t ctx,
void *stat_cb_value);
/* Send the Assuan COMMAND and return results via the callbacks.
- Synchronous variant. */
+ * Synchronous variant. */
gpgme_error_t gpgme_op_assuan_transact_ext (gpgme_ctx_t ctx,
const char *command,
gpgme_assuan_data_cb_t data_cb,
@@ -2077,8 +2136,8 @@ typedef struct _gpgme_op_vfs_mount_result *gpgme_vfs_mount_result_t;
gpgme_vfs_mount_result_t gpgme_op_vfs_mount_result (gpgme_ctx_t ctx);
/* The container is automatically unmounted when the context is reset
- or destroyed. Transmission errors are returned directly,
- operational errors are returned in OP_ERR. */
+ * or destroyed. Transmission errors are returned directly,
+ * operational errors are returned in OP_ERR. */
gpgme_error_t gpgme_op_vfs_mount (gpgme_ctx_t ctx, const char *container_file,
const char *mount_dir, unsigned int flags,
gpgme_error_t *op_err);
@@ -2093,8 +2152,8 @@ gpgme_error_t gpgme_op_vfs_create (gpgme_ctx_t ctx, gpgme_key_t recp[],
*/
/* The expert level at which a configuration option or group of
- options should be displayed. See the gpgconf(1) documentation for
- more details. */
+ * options should be displayed. See the gpgconf(1) documentation for
+ * more details. */
typedef enum
{
GPGME_CONF_BASIC = 0,
@@ -2107,7 +2166,7 @@ gpgme_conf_level_t;
/* The data type of a configuration option argument. See the gpgconf(1)
- documentation for more details. */
+ * documentation for more details. */
typedef enum
{
/* Basic types. */
@@ -2131,7 +2190,7 @@ gpgme_conf_type_t;
/* This represents a single argument for a configuration option.
- Which of the members of value is used depends on the ALT_TYPE. */
+ * Which of the members of value is used depends on the ALT_TYPE. */
typedef struct gpgme_conf_arg
{
struct gpgme_conf_arg *next;
@@ -2148,7 +2207,7 @@ typedef struct gpgme_conf_arg
/* The flags of a configuration option. See the gpgconf
- documentation for details. */
+ * documentation for details. */
#define GPGME_CONF_GROUP (1 << 0)
#define GPGME_CONF_OPTIONAL (1 << 1)
#define GPGME_CONF_LIST (1 << 2)
@@ -2160,7 +2219,7 @@ typedef struct gpgme_conf_arg
/* The representation of a single configuration option. See the
- gpg-conf documentation for details. */
+ * gpg-conf documentation for details. */
typedef struct gpgme_conf_opt
{
struct gpgme_conf_opt *next;
@@ -2205,7 +2264,7 @@ typedef struct gpgme_conf_opt
/* The representation of a component that can be configured. See the
- gpg-conf documentation for details. */
+ * gpg-conf documentation for details. */
typedef struct gpgme_conf_comp
{
struct gpgme_conf_comp *next;
@@ -2228,9 +2287,9 @@ typedef struct gpgme_conf_comp
/* Allocate a new gpgme_conf_arg_t. If VALUE is NULL, a "no arg
- default" is prepared. If type is a string type, VALUE should point
- to the string. Else, it should point to an unsigned or signed
- integer respectively. */
+ * default" is prepared. If type is a string type, VALUE should point
+ * to the string. Else, it should point to an unsigned or signed
+ * integer respectively. */
gpgme_error_t gpgme_conf_arg_new (gpgme_conf_arg_t *arg_p,
gpgme_conf_type_t type, const void *value);
@@ -2238,10 +2297,10 @@ gpgme_error_t gpgme_conf_arg_new (gpgme_conf_arg_t *arg_p,
void gpgme_conf_arg_release (gpgme_conf_arg_t arg, gpgme_conf_type_t type);
/* Register a change for the value of OPT to ARG. If RESET is 1 (do
- not use any values but 0 or 1), ARG is ignored and the option is
- not changed (reverting a previous change). Otherwise, if ARG is
- NULL, the option is cleared or reset to its default. The change
- is done with gpgconf's --runtime option to immediately take effect. */
+ * not use any values but 0 or 1), ARG is ignored and the option is
+ * not changed (reverting a previous change). Otherwise, if ARG is
+ * NULL, the option is cleared or reset to its default. The change
+ * is done with gpgconf's --runtime option to immediately take effect. */
gpgme_error_t gpgme_conf_opt_change (gpgme_conf_opt_t opt, int reset,
gpgme_conf_arg_t arg);
@@ -2332,16 +2391,17 @@ gpgme_query_swdb_result_t gpgme_op_query_swdb_result (gpgme_ctx_t ctx);
int gpgme_set_global_flag (const char *name, const char *value);
/* Check that the library fulfills the version requirement. Note:
- This is here only for the case where a user takes a pointer from
- the old version of this function. The new version and macro for
- run-time checks are below. */
+ * This is here only for the case where a user takes a pointer from
+ * the old version of this function. The new version and macro for
+ * run-time checks are below. */
const char *gpgme_check_version (const char *req_version);
-/* Check that the library fulfills the version requirement and check
- for struct layout mismatch involving bitfields. */
+/* Do not call this directly; use the macro below. */
const char *gpgme_check_version_internal (const char *req_version,
size_t offset_sig_validity);
+/* Check that the library fulfills the version requirement and check
+ * for struct layout mismatch involving bitfields. */
#define gpgme_check_version(req_version) \
gpgme_check_version_internal (req_version, \
offsetof (struct _gpgme_signature, validity))
@@ -2350,19 +2410,19 @@ const char *gpgme_check_version_internal (const char *req_version,
const char *gpgme_get_dirinfo (const char *what);
/* Get the information about the configured and installed engines. A
- pointer to the first engine in the statically allocated linked list
- is returned in *INFO. If an error occurs, it is returned. The
- returned data is valid until the next gpgme_set_engine_info. */
+ * pointer to the first engine in the statically allocated linked list
+ * is returned in *INFO. If an error occurs, it is returned. The
+ * returned data is valid until the next gpgme_set_engine_info. */
gpgme_error_t gpgme_get_engine_info (gpgme_engine_info_t *engine_info);
/* Set the default engine info for the protocol PROTO to the file name
- FILE_NAME and the home directory HOME_DIR. */
+ * FILE_NAME and the home directory HOME_DIR. */
gpgme_error_t gpgme_set_engine_info (gpgme_protocol_t proto,
const char *file_name,
const char *home_dir);
/* Verify that the engine implementing PROTO is installed and
- available. */
+ * available. */
gpgme_error_t gpgme_engine_check_version (gpgme_protocol_t proto);
@@ -2371,15 +2431,15 @@ void gpgme_result_ref (void *result);
void gpgme_result_unref (void *result);
/* Return a public key algorithm string (e.g. "rsa2048"). Caller must
- free using gpgme_free. */
+ * free using gpgme_free. */
char *gpgme_pubkey_algo_string (gpgme_subkey_t subkey);
/* Return a statically allocated string with the name of the public
- key algorithm ALGO, or NULL if that name is not known. */
+ * key algorithm ALGO, or NULL if that name is not known. */
const char *gpgme_pubkey_algo_name (gpgme_pubkey_algo_t algo);
/* Return a statically allocated string with the name of the hash
- algorithm ALGO, or NULL if that name is not known. */
+ * algorithm ALGO, or NULL if that name is not known. */
const char *gpgme_hash_algo_name (gpgme_hash_algo_t algo);
/* Return the addr-spec from a user id. Caller must free the result
@@ -2531,7 +2591,7 @@ gpgme_error_t gpgme_op_card_edit (gpgme_ctx_t ctx, gpgme_key_t key,
_GPGME_DEPRECATED(1,7);
/* The possible signature stati. Deprecated, use error value in sig
- status. */
+ * status. */
typedef enum
{
GPGME_SIG_STAT_NONE = 0,
@@ -2548,7 +2608,7 @@ _gpgme_sig_stat_t;
typedef _gpgme_sig_stat_t gpgme_sig_stat_t _GPGME_DEPRECATED(0,4);
/* The available key and signature attributes. Deprecated, use the
- individual result structures instead. */
+ * individual result structures instead. */
typedef enum
{
GPGME_ATTR_KEYID = 1,
@@ -2588,18 +2648,18 @@ _gpgme_attr_t;
typedef _gpgme_attr_t gpgme_attr_t _GPGME_DEPRECATED(0,4);
/* Retrieve the signature status of signature IDX in CTX after a
- successful verify operation in R_STAT (if non-null). The creation
- time stamp of the signature is returned in R_CREATED (if non-null).
- The function returns a string containing the fingerprint.
- Deprecated, use verify result directly. */
+ * successful verify operation in R_STAT (if non-null). The creation
+ * time stamp of the signature is returned in R_CREATED (if non-null).
+ * The function returns a string containing the fingerprint.
+ * Deprecated, use verify result directly. */
const char *gpgme_get_sig_status (gpgme_ctx_t ctx, int idx,
_gpgme_sig_stat_t *r_stat,
time_t *r_created) _GPGME_DEPRECATED(0,4);
/* Retrieve certain attributes of a signature. IDX is the index
- number of the signature after a successful verify operation. WHAT
- is an attribute where GPGME_ATTR_EXPIRE is probably the most useful
- one. WHATIDX is to be passed as 0 for most attributes . */
+ * number of the signature after a successful verify operation. WHAT
+ * is an attribute where GPGME_ATTR_EXPIRE is probably the most useful
+ * one. WHATIDX is to be passed as 0 for most attributes . */
unsigned long gpgme_get_sig_ulong_attr (gpgme_ctx_t c, int idx,
_gpgme_attr_t what, int whatidx)
_GPGME_DEPRECATED(0,4);
@@ -2609,13 +2669,13 @@ const char *gpgme_get_sig_string_attr (gpgme_ctx_t c, int idx,
/* Get the key used to create signature IDX in CTX and return it in
- R_KEY. */
+ * R_KEY. */
gpgme_error_t gpgme_get_sig_key (gpgme_ctx_t ctx, int idx, gpgme_key_t *r_key)
_GPGME_DEPRECATED(0,4);
/* Create a new data buffer which retrieves the data from the callback
- function READ_CB. Deprecated, please use gpgme_data_new_from_cbs
- instead. */
+ * function READ_CB. Deprecated, please use gpgme_data_new_from_cbs
+ * instead. */
gpgme_error_t gpgme_data_new_with_read_cb (gpgme_data_t *r_dh,
int (*read_cb) (void*,char *,
size_t,size_t*),
@@ -2623,34 +2683,34 @@ gpgme_error_t gpgme_data_new_with_read_cb (gpgme_data_t *r_dh,
_GPGME_DEPRECATED(0,4);
/* Return the value of the attribute WHAT of KEY, which has to be
- representable by a string. IDX specifies the sub key or user ID
- for attributes related to sub keys or user IDs. Deprecated, use
- key structure directly instead. */
+ * representable by a string. IDX specifies the sub key or user ID
+ * for attributes related to sub keys or user IDs. Deprecated, use
+ * key structure directly instead. */
const char *gpgme_key_get_string_attr (gpgme_key_t key, _gpgme_attr_t what,
const void *reserved, int idx)
_GPGME_DEPRECATED(0,4);
/* Return the value of the attribute WHAT of KEY, which has to be
- representable by an unsigned integer. IDX specifies the sub key or
- user ID for attributes related to sub keys or user IDs.
- Deprecated, use key structure directly instead. */
+ * representable by an unsigned integer. IDX specifies the sub key or
+ * user ID for attributes related to sub keys or user IDs.
+ * Deprecated, use key structure directly instead. */
unsigned long gpgme_key_get_ulong_attr (gpgme_key_t key, _gpgme_attr_t what,
const void *reserved, int idx)
_GPGME_DEPRECATED(0,4);
/* Return the value of the attribute WHAT of a signature on user ID
- UID_IDX in KEY, which has to be representable by a string. IDX
- specifies the signature. Deprecated, use key structure directly
- instead. */
+ * UID_IDX in KEY, which has to be representable by a string. IDX
+ * specifies the signature. Deprecated, use key structure directly
+ * instead. */
const char *gpgme_key_sig_get_string_attr (gpgme_key_t key, int uid_idx,
_gpgme_attr_t what,
const void *reserved, int idx)
_GPGME_DEPRECATED(0,4);
/* Return the value of the attribute WHAT of a signature on user ID
- UID_IDX in KEY, which has to be representable by an unsigned
- integer string. IDX specifies the signature. Deprecated, use key
- structure directly instead. */
+ * UID_IDX in KEY, which has to be representable by an unsigned
+ * integer string. IDX specifies the signature. Deprecated, use key
+ * structure directly instead. */
unsigned long gpgme_key_sig_get_ulong_attr (gpgme_key_t key, int uid_idx,
_gpgme_attr_t what,
const void *reserved, int idx)
@@ -2661,21 +2721,21 @@ gpgme_error_t gpgme_op_import_ext (gpgme_ctx_t ctx, gpgme_data_t keydata,
int *nr) _GPGME_DEPRECATED(0,4);
/* Release the trust item ITEM. Deprecated, use
- gpgme_trust_item_unref. */
+ * gpgme_trust_item_unref. */
void gpgme_trust_item_release (gpgme_trust_item_t item) _GPGME_DEPRECATED(0,4);
/* Return the value of the attribute WHAT of ITEM, which has to be
- representable by a string. Deprecated, use trust item structure
- directly. */
+ * representable by a string. Deprecated, use trust item structure
+ * directly. */
const char *gpgme_trust_item_get_string_attr (gpgme_trust_item_t item,
_gpgme_attr_t what,
const void *reserved, int idx)
_GPGME_DEPRECATED(0,4);
/* Return the value of the attribute WHAT of KEY, which has to be
- representable by an integer. IDX specifies a running index if the
- attribute appears more than once in the key. Deprecated, use trust
- item structure directly. */
+ * representable by an integer. IDX specifies a running index if the
+ * attribute appears more than once in the key. Deprecated, use trust
+ * item structure directly. */
int gpgme_trust_item_get_int_attr (gpgme_trust_item_t item, _gpgme_attr_t what,
const void *reserved, int idx)
_GPGME_DEPRECATED(0,4);
diff --git a/src/import.c b/src/import.c
index 386ca72..f0d9d9f 100644
--- a/src/import.c
+++ b/src/import.c
@@ -94,8 +94,9 @@ gpgme_op_import_result (gpgme_ctx_t ctx)
TRACE_LOG3 ("%i secret keys, %i imported, %i unchanged",
opd->result.secret_read, opd->result.secret_imported,
opd->result.secret_unchanged);
- TRACE_LOG2 ("%i skipped new keys, %i not imported",
- opd->result.skipped_new_keys, opd->result.not_imported);
+ TRACE_LOG3 ("%i skipped new keys, %i not imported, %i v3 skipped",
+ opd->result.skipped_new_keys, opd->result.not_imported,
+ opd->result.skipped_v3_keys);
impstat = opd->result.imports;
i = 0;
@@ -212,6 +213,10 @@ parse_import_res (char *args, gpgme_import_result_t result)
PARSE_NEXT (result->secret_unchanged);
PARSE_NEXT (result->skipped_new_keys);
PARSE_NEXT (result->not_imported);
+ if (args && *args)
+ {
+ PARSE_NEXT (result->skipped_v3_keys);
+ }
return 0;
}
diff --git a/src/keylist.c b/src/keylist.c
index 24a9b0b..9c5bd4e 100644
--- a/src/keylist.c
+++ b/src/keylist.c
@@ -1261,7 +1261,7 @@ gpgme_get_key (gpgme_ctx_t ctx, const char *fpr, gpgme_key_t *r_key,
{
gpgme_ctx_t listctx;
gpgme_error_t err;
- gpgme_key_t key;
+ gpgme_key_t result, key;
TRACE_BEG2 (DEBUG_CTX, "gpgme_get_key", ctx,
"fpr=%s, secret=%i", fpr, secret);
@@ -1269,6 +1269,8 @@ gpgme_get_key (gpgme_ctx_t ctx, const char *fpr, gpgme_key_t *r_key,
if (!ctx || !r_key || !fpr)
return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
+ *r_key = NULL;
+
if (strlen (fpr) < 8) /* We have at least a key ID. */
return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
@@ -1295,7 +1297,7 @@ gpgme_get_key (gpgme_ctx_t ctx, const char *fpr, gpgme_key_t *r_key,
err = gpgme_op_keylist_start (listctx, fpr, secret);
if (!err)
- err = gpgme_op_keylist_next (listctx, r_key);
+ err = gpgme_op_keylist_next (listctx, &result);
if (!err)
{
try_next_key:
@@ -1305,9 +1307,9 @@ gpgme_get_key (gpgme_ctx_t ctx, const char *fpr, gpgme_key_t *r_key,
else
{
if (!err
- && *r_key && (*r_key)->subkeys && (*r_key)->subkeys->fpr
+ && result && result->subkeys && result->subkeys->fpr
&& key && key->subkeys && key->subkeys->fpr
- && !strcmp ((*r_key)->subkeys->fpr, key->subkeys->fpr))
+ && !strcmp (result->subkeys->fpr, key->subkeys->fpr))
{
/* The fingerprint is identical. We assume that this is
the same key and don't mark it as an ambiguous. This
@@ -1323,12 +1325,14 @@ gpgme_get_key (gpgme_ctx_t ctx, const char *fpr, gpgme_key_t *r_key,
gpgme_key_unref (key);
err = gpg_error (GPG_ERR_AMBIGUOUS_NAME);
}
- gpgme_key_unref (*r_key);
+ gpgme_key_unref (result);
+ result = NULL;
}
}
gpgme_release (listctx);
if (! err)
{
+ *r_key = result;
TRACE_LOG2 ("key=%p (%s)", *r_key,
((*r_key)->subkeys && (*r_key)->subkeys->fpr) ?
(*r_key)->subkeys->fpr : "invalid");
diff --git a/src/libgpgme.vers b/src/libgpgme.vers
index a95befb..b49c86d 100644
--- a/src/libgpgme.vers
+++ b/src/libgpgme.vers
@@ -215,10 +215,15 @@ GPGME_1.0 {
gpgme_op_edit;
gpgme_op_edit_start;
gpgme_op_encrypt;
- gpgme_op_encrypt_result;
+ gpgme_op_encrypt_start;
+ gpgme_op_encrypt_ext;
+ gpgme_op_encrypt_ext_start;
gpgme_op_encrypt_sign;
+ gpgme_op_encrypt_sign_ext;
gpgme_op_encrypt_sign_start;
- gpgme_op_encrypt_start;
+ gpgme_op_encrypt_sign_ext_start;
+ gpgme_op_encrypt_result;
+
gpgme_op_export;
gpgme_op_export_ext;
gpgme_op_export_ext_start;
diff --git a/src/op-support.c b/src/op-support.c
index 817c569..03f274c 100644
--- a/src/op-support.c
+++ b/src/op-support.c
@@ -141,6 +141,8 @@ _gpgme_op_reset (gpgme_ctx_t ctx, int type)
if (gpg_err_code (err) == GPG_ERR_NOT_IMPLEMENTED)
err = 0;
+ _gpgme_engine_set_engine_flags (ctx->engine, ctx);
+
if (!err)
{
err = _gpgme_engine_set_pinentry_mode (ctx->engine,
@@ -356,7 +358,7 @@ _gpgme_parse_key_considered (const char *args,
/* Parse the PLAINTEXT status line in ARGS and return the result in
FILENAMEP. */
gpgme_error_t
-_gpgme_parse_plaintext (char *args, char **filenamep)
+_gpgme_parse_plaintext (char *args, char **filenamep, int *r_mime)
{
char *tail;
@@ -365,7 +367,9 @@ _gpgme_parse_plaintext (char *args, char **filenamep)
if (*args == '\0')
return 0;
- /* First argument is file type. */
+ /* First argument is file type (a one byte uppercase hex value). */
+ if (args[0] == '6' && args[1] == 'D')
+ *r_mime = 1;
while (*args != ' ' && *args != '\0')
args++;
while (*args == ' ')
@@ -398,7 +402,13 @@ _gpgme_parse_plaintext (char *args, char **filenamep)
/* Parse a FAILURE status line and return the error code. ARGS is
- modified to contain the location part. */
+ * modified to contain the location part. Note that for now we ignore
+ * failure codes with a location of gpg-exit; they are too trouble
+ * some. Instead we should eventually record that error in the
+ * context and provide a function to return a fuller error
+ * description; this could then also show the location of the error
+ * (e.g. "option- parser") to make it easier for the user to detect
+ * the actual error. */
gpgme_error_t
_gpgme_parse_failure (char *args)
{
@@ -416,6 +426,8 @@ _gpgme_parse_failure (char *args)
*where = '\0';
where = args;
+ if (!strcmp (where, "gpg-exit"))
+ return 0;
return atoi (which);
}
diff --git a/src/ops.h b/src/ops.h
index cc61dc4..5955454 100644
--- a/src/ops.h
+++ b/src/ops.h
@@ -68,8 +68,8 @@ gpgme_error_t _gpgme_parse_inv_recp (char *args, int for_signing,
gpgme_invalid_key_t *key);
/* Parse the PLAINTEXT status line in ARGS and return the result in
- FILENAMEP. */
-gpgme_error_t _gpgme_parse_plaintext (char *args, char **filenamep);
+ FILENAMEP and R_MIME. */
+gpgme_error_t _gpgme_parse_plaintext (char *args, char **filenamep,int *r_mime);
/* Parse a FAILURE status line and return the error code. ARGS is
modified to contain the location part. */
diff --git a/src/priv-io.h b/src/priv-io.h
index 2306175..bc9d3d5 100644
--- a/src/priv-io.h
+++ b/src/priv-io.h
@@ -83,6 +83,8 @@ int _gpgme_io_set_nonblocking (int fd);
#define IOSPAWN_FLAG_ALLOW_SET_FG 2
/* Don't close any child FDs. */
#define IOSPAWN_FLAG_NOCLOSE 4
+/* Set show window to true for windows */
+#define IOSPAWN_FLAG_SHOW_WINDOW 8
/* Spawn the executable PATH with ARGV as arguments. After forking
close all fds except for those in FD_LIST in the child, then
diff --git a/src/util.h b/src/util.h
index b4043ed..da929eb 100644
--- a/src/util.h
+++ b/src/util.h
@@ -165,10 +165,11 @@ time_t _gpgme_parse_timestamp (const char *timestamp, char **endp);
* on error or missing timestamp. */
unsigned long _gpgme_parse_timestamp_ul (const char *timestamp);
-gpgme_error_t _gpgme_map_gnupg_error (char *err);
-
int _gpgme_map_pk_algo (int algo, gpgme_protocol_t protocol);
+const char *_gpgme_cipher_algo_name (int algo, gpgme_protocol_t protocol);
+const char *_gpgme_cipher_mode_name (int algo, gpgme_protocol_t protocol);
+
/*-- b64dec.c --*/
diff --git a/src/verify.c b/src/verify.c
index ee730a3..bd437c9 100644
--- a/src/verify.c
+++ b/src/verify.c
@@ -284,6 +284,7 @@ parse_new_sig (op_data_t opd, gpgme_status_code_t code, char *args,
gpgme_signature_t sig;
char *end = strchr (args, ' ');
char *tail;
+ int got_fpr = 0;
if (end)
{
@@ -370,7 +371,23 @@ parse_new_sig (op_data_t opd, gpgme_status_code_t code, char *args,
if (!*end)
goto parse_err_sig_fail;
- sig->status = strtoul (end, NULL, 10);
+ gpg_err_set_errno (0);
+ sig->status = strtoul (end, &tail, 10);
+ if (errno || end == tail || (*tail && *tail != ' '))
+ goto parse_err_sig_fail;
+ if (!*tail)
+ goto parse_err_sig_ok;
+ end = tail;
+ while (*end == ' ')
+ end++;
+
+ /* Parse the new fingerprint (from the ISSUER_FPR subpacket). */
+ if (!*end || (*end == '-' && (end[1] == ' ' || !end[1])))
+ goto parse_err_sig_ok; /* Okay (just trailing spaces). */
+ sig->fpr = strdup (end);
+ if (!sig->fpr)
+ return gpg_error_from_syserror ();
+ got_fpr = 1;
goto parse_err_sig_ok;
parse_err_sig_fail:
@@ -382,7 +399,7 @@ parse_new_sig (op_data_t opd, gpgme_status_code_t code, char *args,
return gpg_error (GPG_ERR_GENERAL);
}
- if (*args)
+ if (*args && !got_fpr)
{
sig->fpr = strdup (args);
if (!sig->fpr)
@@ -1074,9 +1091,15 @@ _gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args)
case GPGME_STATUS_PLAINTEXT:
if (++opd->plaintext_seen > 1)
return gpg_error (GPG_ERR_BAD_DATA);
- err = _gpgme_parse_plaintext (args, &opd->result.file_name);
- if (err)
- return err;
+ {
+ int mime = 0;
+ err = _gpgme_parse_plaintext (args, &opd->result.file_name, &mime);
+ if (err)
+ return err;
+ gpgrt_log_debug ("verify.c: setting mime to %d\n", mime);
+ opd->result.is_mime = !!mime;
+ }
+ break;
case GPGME_STATUS_VERIFICATION_COMPLIANCE_MODE:
PARSE_COMPLIANCE_FLAGS (args, opd->current_sig);
diff --git a/src/versioninfo.rc.in b/src/versioninfo.rc.in
index 2b1cc81..88b662e 100644
--- a/src/versioninfo.rc.in
+++ b/src/versioninfo.rc.in
@@ -39,7 +39,7 @@ BEGIN
VALUE "FileDescription", "GPGME - GnuPG Made Easy\0"
VALUE "FileVersion", "@LIBGPGME_LT_CURRENT@.@LIBGPGME_LT_AGE@.@LIBGPGME_LT_REVISION@.@BUILD_REVISION@\0"
VALUE "InternalName", "gpgme\0"
- VALUE "LegalCopyright", "Copyright © 2001-2017 g10 Code GmbH\0"
+ VALUE "LegalCopyright", "Copyright © 2001-2018 g10 Code GmbH\0"
VALUE "LegalTrademarks", "\0"
VALUE "OriginalFilename", "gpgme.dll\0"
VALUE "PrivateBuild", "\0"
diff --git a/src/w32-io.c b/src/w32-io.c
index eed8a00..05e11ee 100644
--- a/src/w32-io.c
+++ b/src/w32-io.c
@@ -1724,8 +1724,8 @@ _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags,
int written;
size_t len;
- if ((flags & IOSPAWN_FLAG_ALLOW_SET_FG))
- strcpy (line, "~1 \n");
+ if (flags)
+ snprintf (line, BUFFER_MAX, "~%i \n", flags);
else
strcpy (line, "\n");
for (i = 0; fd_list[i].fd != -1; i++)
diff --git a/tests/gpg/Makefile.am b/tests/gpg/Makefile.am
index 642e0a0..b50f4b0 100644
--- a/tests/gpg/Makefile.am
+++ b/tests/gpg/Makefile.am
@@ -46,7 +46,7 @@ TESTS = initial.test $(c_tests) final.test
CLEANFILES = secring.gpg pubring.gpg pubring.kbx trustdb.gpg dirmngr.conf \
gpg-agent.conf pubring.kbx~ S.gpg-agent gpg.conf pubring.gpg~ \
random_seed S.gpg-agent .gpg-v21-migrated pubring-stamp \
- tofu.db *.conf.gpgconf.bak
+ gpg-sample.stamp tofu.db *.conf.gpgconf.bak
private_keys = \
13CD0F3BDF24BE53FE192D62F18737256FF6E4FD \
@@ -61,7 +61,7 @@ EXTRA_DIST = initial.test final.test \
geheim.txt pubkey-1.asc seckey-1.asc pinentry $(private_keys)
BUILT_SOURCES = gpg.conf gpg-agent.conf pubring-stamp \
- private-keys-v1.d/gpg-sample.stamp
+ gpg-sample.stamp
AM_CPPFLAGS = -I$(top_builddir)/src @GPG_ERROR_CFLAGS@
AM_LDFLAGS = -no-install
LDADD = ../../src/libgpgme.la
@@ -81,25 +81,21 @@ noinst_PROGRAMS = $(c_tests) $(tests_skipped)
clean-local:
- -$(top_srcdir)/tests/start-stop-agent --stop
+ -$(TESTS_ENVIRONMENT) $(top_srcdir)/tests/start-stop-agent --stop
-rm -fR private-keys-v1.d
-export GNUPGHOME := $(abs_builddir)
-
-export GPG_AGENT_INFO :=
-
-private-keys-v1.d/gpg-sample.stamp: $(srcdir)/$(private_keys)
- -gpgconf --kill all
+gpg-sample.stamp: $(srcdir)/$(private_keys)
+ -$(TESTS_ENVIRONMENT) gpgconf --kill all
$(MKDIR_P) ./private-keys-v1.d
for k in $(private_keys); do \
cp $(srcdir)/$$k private-keys-v1.d/$$k.key; \
done
- echo x > ./private-keys-v1.d/gpg-sample.stamp
+ echo x > ./gpg-sample.stamp
-pubring-stamp: $(srcdir)/pubdemo.asc ./private-keys-v1.d/gpg-sample.stamp
- $(GPG) --batch --no-permission-warning \
+pubring-stamp: $(srcdir)/pubdemo.asc gpg-sample.stamp
+ $(TESTS_ENVIRONMENT) $(GPG) --batch --no-permission-warning \
--import $(srcdir)/pubdemo.asc
- -$(GPG) --batch --no-permission-warning \
+ -$(TESTS_ENVIRONMENT) $(GPG) --batch --no-permission-warning \
--import $(srcdir)/secdemo.asc
echo x > ./pubring-stamp
diff --git a/tests/gpg/Makefile.in b/tests/gpg/Makefile.in
index d5ab6a7..f09f94a 100644
--- a/tests/gpg/Makefile.in
+++ b/tests/gpg/Makefile.in
@@ -552,7 +552,7 @@ c_tests = \
CLEANFILES = secring.gpg pubring.gpg pubring.kbx trustdb.gpg dirmngr.conf \
gpg-agent.conf pubring.kbx~ S.gpg-agent gpg.conf pubring.gpg~ \
random_seed S.gpg-agent .gpg-v21-migrated pubring-stamp \
- tofu.db *.conf.gpgconf.bak
+ gpg-sample.stamp tofu.db *.conf.gpgconf.bak
private_keys = \
13CD0F3BDF24BE53FE192D62F18737256FF6E4FD \
@@ -566,7 +566,7 @@ EXTRA_DIST = initial.test final.test \
geheim.txt pubkey-1.asc seckey-1.asc pinentry $(private_keys)
BUILT_SOURCES = gpg.conf gpg-agent.conf pubring-stamp \
- private-keys-v1.d/gpg-sample.stamp
+ gpg-sample.stamp
AM_CPPFLAGS = -I$(top_builddir)/src @GPG_ERROR_CFLAGS@
AM_LDFLAGS = -no-install
@@ -1091,25 +1091,21 @@ uninstall-am:
clean-local:
- -$(top_srcdir)/tests/start-stop-agent --stop
+ -$(TESTS_ENVIRONMENT) $(top_srcdir)/tests/start-stop-agent --stop
-rm -fR private-keys-v1.d
-export GNUPGHOME := $(abs_builddir)
-
-export GPG_AGENT_INFO :=
-
-private-keys-v1.d/gpg-sample.stamp: $(srcdir)/$(private_keys)
- -gpgconf --kill all
+gpg-sample.stamp: $(srcdir)/$(private_keys)
+ -$(TESTS_ENVIRONMENT) gpgconf --kill all
$(MKDIR_P) ./private-keys-v1.d
for k in $(private_keys); do \
cp $(srcdir)/$$k private-keys-v1.d/$$k.key; \
done
- echo x > ./private-keys-v1.d/gpg-sample.stamp
+ echo x > ./gpg-sample.stamp
-pubring-stamp: $(srcdir)/pubdemo.asc ./private-keys-v1.d/gpg-sample.stamp
- $(GPG) --batch --no-permission-warning \
+pubring-stamp: $(srcdir)/pubdemo.asc gpg-sample.stamp
+ $(TESTS_ENVIRONMENT) $(GPG) --batch --no-permission-warning \
--import $(srcdir)/pubdemo.asc
- -$(GPG) --batch --no-permission-warning \
+ -$(TESTS_ENVIRONMENT) $(GPG) --batch --no-permission-warning \
--import $(srcdir)/secdemo.asc
echo x > ./pubring-stamp
diff --git a/tests/gpg/pinentry b/tests/gpg/pinentry
index 3b99726..b12caae 100755
--- a/tests/gpg/pinentry
+++ b/tests/gpg/pinentry
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
# Dummy pinentry
#
# Copyright 2008 g10 Code GmbH
diff --git a/tests/gpg/t-support.h b/tests/gpg/t-support.h
index f6dec68..ef5766a 100644
--- a/tests/gpg/t-support.h
+++ b/tests/gpg/t-support.h
@@ -196,7 +196,8 @@ print_import_result (gpgme_import_result_t r)
" secret imported: %d\n"
" secret unchanged: %d\n"
" skipped new keys: %d\n"
- " not imported: %d\n",
+ " not imported: %d\n"
+ " skipped v3 keys: %d\n",
r->considered,
r->no_user_id,
r->imported,
@@ -210,6 +211,7 @@ print_import_result (gpgme_import_result_t r)
r->secret_imported,
r->secret_unchanged,
r->skipped_new_keys,
- r->not_imported);
+ r->not_imported,
+ r->skipped_v3_keys);
}
diff --git a/tests/gpg/t-verify.c b/tests/gpg/t-verify.c
index f955cc9..7c23406 100644
--- a/tests/gpg/t-verify.c
+++ b/tests/gpg/t-verify.c
@@ -31,31 +31,14 @@
#include <gpgme.h>
+#define PGM "t-verify"
#include "t-support.h"
+
static const char test_text1[] = "Just GNU it!\n";
static const char test_text1f[]= "Just GNU it?\n";
static const char test_sig1[] =
-#if 0
-"-----BEGIN PGP SIGNATURE-----\n"
-"\n"
-"iEYEABECAAYFAjoKgjIACgkQLXJ8x2hpdzQMSwCeO/xUrhysZ7zJKPf/FyXA//u1\n"
-"ZgIAn0204PBR7yxSdQx6CFxugstNqmRv\n"
-"=yku6\n"
-"-----END PGP SIGNATURE-----\n"
-#elif 0
-"-----BEGIN PGP SIGNATURE-----\n"
-"Version: GnuPG v1.0.4-2 (GNU/Linux)\n"
-"Comment: For info see http://www.gnupg.org\n"
-"\n"
-"iJcEABECAFcFAjoS8/E1FIAAAAAACAAkZm9vYmFyLjF0aGlzIGlzIGEgbm90YXRp\n"
-"b24gZGF0YSB3aXRoIDIgbGluZXMaGmh0dHA6Ly93d3cuZ3Uub3JnL3BvbGljeS8A\n"
-"CgkQLXJ8x2hpdzQLyQCbBW/fgU8ZeWSlWPM1F8umHX17bAAAoIfSNDSp5zM85XcG\n"
-"iwxMrf+u8v4r\n"
-"=88Zo\n"
-"-----END PGP SIGNATURE-----\n"
-#elif 1
"-----BEGIN PGP SIGNATURE-----\n"
"\n"
"iN0EABECAJ0FAjoS+i9FFIAAAAAAAwA5YmFyw7bDpMO8w58gZGFzIHdhcmVuIFVt\n"
@@ -64,9 +47,24 @@ static const char test_sig1[] =
"Oi8vd3d3Lmd1Lm9yZy9wb2xpY3kvAAoJEC1yfMdoaXc0JBIAoIiLlUsvpMDOyGEc\n"
"dADGKXF/Hcb+AKCJWPphZCphduxSvrzH0hgzHdeQaA==\n"
"=nts1\n"
-"-----END PGP SIGNATURE-----\n"
-#endif
-;
+"-----END PGP SIGNATURE-----\n";
+
+/* The same as test_sig1 but with a second signature for which we do
+ * not have the public key (deleted after signature creation). */
+static const char test_sig1_plus_unknown_key[] =
+"-----BEGIN PGP SIGNATURE-----\n"
+"\n"
+"iN0EABECAJ0FAjoS+i9FFIAAAAAAAwA5YmFyw7bDpMO8w58gZGFzIHdhcmVuIFVt\n"
+"bGF1dGUgdW5kIGpldHp0IGVpbiBwcm96ZW50JS1aZWljaGVuNRSAAAAAAAgAJGZv\n"
+"b2Jhci4xdGhpcyBpcyBhIG5vdGF0aW9uIGRhdGEgd2l0aCAyIGxpbmVzGhpodHRw\n"
+"Oi8vd3d3Lmd1Lm9yZy9wb2xpY3kvAAoJEC1yfMdoaXc0JBIAoIiLlUsvpMDOyGEc\n"
+"dADGKXF/Hcb+AKCJWPphZCphduxSvrzH0hgzHdeQaIh1BAAWCAAdFiEENuwqcMZC\n"
+"brD85btN+RyY8EnUIEwFAlrPR4cACgkQ+RyY8EnUIEyiuAEAm41LJTGUFDzhavRm\n"
+"jNwqUZxGGOySduW+u/X1lEfV+MYA/2lJOo75rHtD1EG+tkFVWt4Ukj0rjhR132vZ\n"
+"IOtrYAcG\n"
+"=yYwZ\n"
+"-----END PGP SIGNATURE-----\n";
+
static const char test_sig2[] =
"-----BEGIN PGP MESSAGE-----\n"
"\n"
@@ -91,37 +89,51 @@ static const char double_plaintext_sig[] =
+/* NO_OF_SIGS is the expected number of signatures. SKIP_SKIPS is
+ * which of these signatures to check (0 based). */
static void
-check_result (gpgme_verify_result_t result, unsigned int summary,
- const char *fpr,
+check_result (gpgme_verify_result_t result, int no_of_sigs, int skip_sigs,
+ unsigned int summary, const char *fpr,
gpgme_error_t status, int notation)
{
gpgme_signature_t sig;
+ int n;
sig = result->signatures;
- if (!sig || sig->next)
+ for (n=0; sig; sig = sig->next)
+ n++;
+ if (n != no_of_sigs)
+ {
+ fprintf (stderr, "%s:%i: Unexpected number of signatures"
+ " (got %d expected %d)\n", PGM, __LINE__, n, no_of_sigs);
+ exit (1);
+ }
+ if (skip_sigs >= n)
{
- fprintf (stderr, "%s:%i: Unexpected number of signatures\n",
- __FILE__, __LINE__);
+ fprintf (stderr, "%s:%i: oops SKIPP_SIGS to high\n", PGM, __LINE__);
exit (1);
}
+
+ for (n=0, sig = result->signatures; n < skip_sigs; sig = sig->next, n++)
+ ;
+
if (sig->summary != summary)
{
- fprintf (stderr, "%s:%i: Unexpected signature summary: "
+ fprintf (stderr, "%s:%i:sig-%d: Unexpected signature summary: "
"want=0x%x have=0x%x\n",
- __FILE__, __LINE__, summary, sig->summary);
+ PGM, __LINE__, skip_sigs, summary, sig->summary);
exit (1);
}
if (strcmp (sig->fpr, fpr))
{
- fprintf (stderr, "%s:%i: Unexpected fingerprint: %s\n",
- __FILE__, __LINE__, sig->fpr);
+ fprintf (stderr, "%s:%i:sig-%d: Unexpected fingerprint: %s\n",
+ PGM, __LINE__, skip_sigs, sig->fpr);
exit (1);
}
if (gpgme_err_code (sig->status) != status)
{
- fprintf (stderr, "%s:%i: Unexpected signature status: %s\n",
- __FILE__, __LINE__, gpgme_strerror (sig->status));
+ fprintf (stderr, "%s:%i:sig-%d: Unexpected signature status: %s\n",
+ PGM, __LINE__, skip_sigs, gpgme_strerror (sig->status));
exit (1);
}
if (notation)
@@ -166,8 +178,8 @@ check_result (gpgme_verify_result_t result, unsigned int summary,
}
if (!any)
{
- fprintf (stderr, "%s:%i: Unexpected notation data\n",
- __FILE__, __LINE__);
+ fprintf (stderr, "%s:%i:sig-%d: Unexpected notation data\n",
+ PGM, __LINE__, skip_sigs);
exit (1);
}
}
@@ -175,28 +187,30 @@ check_result (gpgme_verify_result_t result, unsigned int summary,
{
if (expected_notations[i].seen != 1)
{
- fprintf (stderr, "%s:%i: Missing or duplicate notation data\n",
- __FILE__, __LINE__);
+ fprintf (stderr, "%s:%i:sig-%d: "
+ "Missing or duplicate notation data\n",
+ PGM, __LINE__, skip_sigs);
exit (1);
}
}
}
if (sig->wrong_key_usage)
{
- fprintf (stderr, "%s:%i: Unexpectedly wrong key usage\n",
- __FILE__, __LINE__);
+ fprintf (stderr, "%s:%i:sig-%d: Unexpectedly wrong key usage\n",
+ PGM, __LINE__, skip_sigs);
exit (1);
}
if (sig->validity != GPGME_VALIDITY_UNKNOWN)
{
- fprintf (stderr, "%s:%i: Unexpected validity: %i\n",
- __FILE__, __LINE__, sig->validity);
+ fprintf (stderr, "%s:%i:sig-%d: Unexpected validity: %i\n",
+ PGM, __LINE__, skip_sigs, sig->validity);
exit (1);
}
if (gpgme_err_code (sig->validity_reason) != GPG_ERR_NO_ERROR)
{
- fprintf (stderr, "%s:%i: Unexpected validity reason: %s\n",
- __FILE__, __LINE__, gpgme_strerror (sig->validity_reason));
+ fprintf (stderr, "%s:%i:sig-%d: Unexpected validity reason: %s\n",
+ PGM, __LINE__, skip_sigs,
+ gpgme_strerror (sig->validity_reason));
exit (1);
}
}
@@ -227,7 +241,7 @@ main (int argc, char *argv[])
err = gpgme_op_verify (ctx, sig, text, NULL);
fail_if_err (err);
result = gpgme_op_verify_result (ctx);
- check_result (result, 0, "A0FF4590BB6122EDEF6E3C542D727CC768697734",
+ check_result (result, 1, 0, 0, "A0FF4590BB6122EDEF6E3C542D727CC768697734",
GPG_ERR_NO_ERROR, 1);
/* Checking a manipulated message. */
@@ -238,9 +252,29 @@ main (int argc, char *argv[])
err = gpgme_op_verify (ctx, sig, text, NULL);
fail_if_err (err);
result = gpgme_op_verify_result (ctx);
- check_result (result, GPGME_SIGSUM_RED, "2D727CC768697734",
+ check_result (result, 1, 0, GPGME_SIGSUM_RED, "2D727CC768697734",
GPG_ERR_BAD_SIGNATURE, 0);
+ /* Checking a valid message. Bu that one has a second signature
+ * made by an unknown key. */
+ gpgme_data_release (text);
+ gpgme_data_release (sig);
+ err = gpgme_data_new_from_mem (&text, test_text1, strlen (test_text1), 0);
+ fail_if_err (err);
+ err = gpgme_data_new_from_mem (&sig, test_sig1_plus_unknown_key,
+ strlen (test_sig1_plus_unknown_key), 0);
+ fail_if_err (err);
+ err = gpgme_op_verify (ctx, sig, text, NULL);
+ fail_if_err (err);
+ result = gpgme_op_verify_result (ctx);
+ check_result (result, 2, 0, 0,
+ "A0FF4590BB6122EDEF6E3C542D727CC768697734",
+ GPG_ERR_NO_ERROR, 1);
+ check_result (result, 2, 1, GPGME_SIGSUM_KEY_MISSING,
+ "36EC2A70C6426EB0FCE5BB4DF91C98F049D4204C",
+ GPG_ERR_NO_PUBKEY, 0);
+
+
/* Checking a normal signature. */
gpgme_data_release (sig);
gpgme_data_release (text);
@@ -251,7 +285,7 @@ main (int argc, char *argv[])
err = gpgme_op_verify (ctx, sig, NULL, text);
fail_if_err (err);
result = gpgme_op_verify_result (ctx);
- check_result (result, 0, "A0FF4590BB6122EDEF6E3C542D727CC768697734",
+ check_result (result, 1, 0, 0, "A0FF4590BB6122EDEF6E3C542D727CC768697734",
GPG_ERR_NO_ERROR, 0);
@@ -267,7 +301,7 @@ main (int argc, char *argv[])
if (gpgme_err_code (err) != GPG_ERR_BAD_DATA)
{
fprintf (stderr, "%s:%i: Double plaintext message not detected\n",
- __FILE__, __LINE__);
+ PGM, __LINE__);
exit (1);
}
@@ -278,7 +312,7 @@ main (int argc, char *argv[])
if (!s || strcmp (s, "foo@example.org"))
{
fprintf (stderr, "%s:%i: gpgme_{set,get}_sender mismatch\n",
- __FILE__, __LINE__);
+ PGM, __LINE__);
exit (1);
}
@@ -288,7 +322,7 @@ main (int argc, char *argv[])
if (!s || strcmp (s, "bar@example.org"))
{
fprintf (stderr, "%s:%i: gpgme_{set,get}_sender mismatch\n",
- __FILE__, __LINE__);
+ PGM, __LINE__);
exit (1);
}
@@ -298,7 +332,7 @@ main (int argc, char *argv[])
if (!s || strcmp (s, "foo@example.org"))
{
fprintf (stderr, "%s:%i: gpgme_{set,get}_sender mismatch\n",
- __FILE__, __LINE__);
+ PGM, __LINE__);
exit (1);
}
@@ -306,7 +340,7 @@ main (int argc, char *argv[])
if (gpgme_err_code (err) != GPG_ERR_INV_VALUE)
{
fprintf (stderr, "%s:%i: gpgme_set_sender didn't detect bogus address\n",
- __FILE__, __LINE__);
+ PGM, __LINE__);
exit (1);
}
/* (the former address should still be there.) */
@@ -314,7 +348,7 @@ main (int argc, char *argv[])
if (!s || strcmp (s, "foo@example.org"))
{
fprintf (stderr, "%s:%i: gpgme_{set,get}_sender mismatch\n",
- __FILE__, __LINE__);
+ PGM, __LINE__);
exit (1);
}
diff --git a/tests/gpgsm/Makefile.am b/tests/gpgsm/Makefile.am
index 4ab2283..d2acd05 100644
--- a/tests/gpgsm/Makefile.am
+++ b/tests/gpgsm/Makefile.am
@@ -46,21 +46,17 @@ noinst_PROGRAMS = $(c_tests) t-genkey cms-keylist cms-decrypt
key_id = 32100C27173EF6E9C4E9A25D3D69F86D37A4F939
CLEANFILES = pubring-stamp pubring.kbx pubring.kbx~ gpgsm.conf trustlist.txt \
- random_seed S.gpg-agent
+ random_seed S.gpg-agent gpg-sample.stamp
clean-local:
- -$(top_srcdir)/tests/start-stop-agent --stop
+ -$(TESTS_ENVIRONMENT) $(top_srcdir)/tests/start-stop-agent --stop
-rm -fR private-keys-v1.d
-export GNUPGHOME := $(abs_builddir)
-
-export GPG_AGENT_INFO :=
-
BUILT_SOURCES = gpgsm.conf trustlist.txt pubring-stamp \
- private-keys-v1.d/gpg-sample.stamp
+ gpg-sample.stamp
-pubring-stamp: $(srcdir)/cert_g10code_test1.der ./private-keys-v1.d/gpg-sample.stamp
- $(GPGSM) --import $(srcdir)/cert_g10code_test1.der
+pubring-stamp: $(srcdir)/cert_g10code_test1.der gpg-sample.stamp
+ $(TESTS_ENVIRONMENT) $(GPGSM) --import $(srcdir)/cert_g10code_test1.der
touch pubring-stamp
gpgsm.conf:
@@ -68,11 +64,11 @@ gpgsm.conf:
echo faked-system-time 1008241200 >> ./gpgsm.conf
echo "agent-program `which $(GPG_AGENT)`|--debug-quick-random" >> ./gpgsm.conf
-private-keys-v1.d/gpg-sample.stamp: $(srcdir)/$(key_id)
- -gpgconf --kill all
+gpg-sample.stamp: $(srcdir)/$(key_id)
+ -$(TESTS_ENVIRONMENT) gpgconf --kill all
$(MKDIR_P) ./private-keys-v1.d
cp $(srcdir)/$(key_id) private-keys-v1.d/$(key_id).key
- echo x > ./private-keys-v1.d/gpg-sample.stamp
+ echo x > ./gpg-sample.stamp
trustlist.txt:
echo $(key_id) > ./trustlist.txt
diff --git a/tests/gpgsm/Makefile.in b/tests/gpgsm/Makefile.in
index 42ffb7a..307b3f1 100644
--- a/tests/gpgsm/Makefile.in
+++ b/tests/gpgsm/Makefile.in
@@ -468,10 +468,10 @@ AM_LDFLAGS = -no-install
LDADD = ../../src/libgpgme.la
key_id = 32100C27173EF6E9C4E9A25D3D69F86D37A4F939
CLEANFILES = pubring-stamp pubring.kbx pubring.kbx~ gpgsm.conf trustlist.txt \
- random_seed S.gpg-agent
+ random_seed S.gpg-agent gpg-sample.stamp
BUILT_SOURCES = gpgsm.conf trustlist.txt pubring-stamp \
- private-keys-v1.d/gpg-sample.stamp
+ gpg-sample.stamp
all: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) all-am
@@ -905,15 +905,11 @@ uninstall-am:
clean-local:
- -$(top_srcdir)/tests/start-stop-agent --stop
+ -$(TESTS_ENVIRONMENT) $(top_srcdir)/tests/start-stop-agent --stop
-rm -fR private-keys-v1.d
-export GNUPGHOME := $(abs_builddir)
-
-export GPG_AGENT_INFO :=
-
-pubring-stamp: $(srcdir)/cert_g10code_test1.der ./private-keys-v1.d/gpg-sample.stamp
- $(GPGSM) --import $(srcdir)/cert_g10code_test1.der
+pubring-stamp: $(srcdir)/cert_g10code_test1.der gpg-sample.stamp
+ $(TESTS_ENVIRONMENT) $(GPGSM) --import $(srcdir)/cert_g10code_test1.der
touch pubring-stamp
gpgsm.conf:
@@ -921,11 +917,11 @@ gpgsm.conf:
echo faked-system-time 1008241200 >> ./gpgsm.conf
echo "agent-program `which $(GPG_AGENT)`|--debug-quick-random" >> ./gpgsm.conf
-private-keys-v1.d/gpg-sample.stamp: $(srcdir)/$(key_id)
- -gpgconf --kill all
+gpg-sample.stamp: $(srcdir)/$(key_id)
+ -$(TESTS_ENVIRONMENT) gpgconf --kill all
$(MKDIR_P) ./private-keys-v1.d
cp $(srcdir)/$(key_id) private-keys-v1.d/$(key_id).key
- echo x > ./private-keys-v1.d/gpg-sample.stamp
+ echo x > ./gpg-sample.stamp
trustlist.txt:
echo $(key_id) > ./trustlist.txt
diff --git a/tests/run-decrypt.c b/tests/run-decrypt.c
index e961293..69de139 100644
--- a/tests/run-decrypt.c
+++ b/tests/run-decrypt.c
@@ -53,19 +53,21 @@ print_result (gpgme_decrypt_result_t result)
gpgme_recipient_t recp;
int count = 0;
- printf ("Original file name: %s\n", nonnull(result->file_name));
- printf ("Wrong key usage: %i\n", result->wrong_key_usage);
- printf ("Unsupported algorithm: %s\n",
- nonnull(result->unsupported_algorithm));
- if (result->session_key)
- printf ("Session key: %s\n", result->session_key);
-
- for (recp = result->recipients; recp->next; recp = recp->next)
+ printf ("Original file name .: %s\n", nonnull(result->file_name));
+ printf ("Wrong key usage ....: %s\n", result->wrong_key_usage? "yes":"no");
+ printf ("Compliance de-vs ...: %s\n", result->is_de_vs? "yes":"no");
+ printf ("MIME flag ..........: %s\n", result->is_mime? "yes":"no");
+ printf ("Unsupported algo ...: %s\n", nonnull(result->unsupported_algorithm));
+ printf ("Session key ........: %s\n", nonnull (result->session_key));
+ printf ("Symmetric algorithm : %s\n", result->symkey_algo);
+
+ for (recp = result->recipients; recp && recp->next; recp = recp->next)
{
- printf ("recipient %d\n", count++);
+ printf ("Recipient ...: %d\n", count++);
printf (" status ....: %s\n", gpgme_strerror (recp->status));
- printf (" keyid: %s\n", nonnull (recp->keyid));
- printf (" algo ...: %s\n", gpgme_pubkey_algo_name (recp->pubkey_algo));
+ printf (" keyid .....: %s\n", nonnull (recp->keyid));
+ printf (" algo ......: %s\n",
+ gpgme_pubkey_algo_name (recp->pubkey_algo));
}
}
@@ -81,6 +83,8 @@ show_usage (int ex)
" --cms use the CMS protocol\n"
" --export-session-key show the session key\n"
" --override-session-key STRING use STRING as session key\n"
+ " --request-origin STRING use STRING as request origin\n"
+ " --no-symkey-cache disable the use of that cache\n"
" --unwrap remove only the encryption layer\n"
, stderr);
exit (ex);
@@ -102,6 +106,8 @@ main (int argc, char **argv)
int print_status = 0;
int export_session_key = 0;
const char *override_session_key = NULL;
+ const char *request_origin = NULL;
+ int no_symkey_cache = 0;
int raw_output = 0;
if (argc)
@@ -150,6 +156,19 @@ main (int argc, char **argv)
override_session_key = *argv;
argc--; argv++;
}
+ else if (!strcmp (*argv, "--request-origin"))
+ {
+ argc--; argv++;
+ if (!argc)
+ show_usage (1);
+ request_origin = *argv;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--no-symkey-cache"))
+ {
+ no_symkey_cache = 1;
+ argc--; argv++;
+ }
else if (!strcmp (*argv, "--unwrap"))
{
flags |= GPGME_DECRYPT_UNWRAP;
@@ -199,7 +218,29 @@ main (int argc, char **argv)
override_session_key);
if (err)
{
- fprintf (stderr, PGM ": error overriding session key: %s\n",
+ fprintf (stderr, PGM ": error setting overriding session key: %s\n",
+ gpgme_strerror (err));
+ exit (1);
+ }
+ }
+
+ if (request_origin)
+ {
+ err = gpgme_set_ctx_flag (ctx, "request-origin", request_origin);
+ if (err)
+ {
+ fprintf (stderr, PGM ": error setting request_origin: %s\n",
+ gpgme_strerror (err));
+ exit (1);
+ }
+ }
+
+ if (no_symkey_cache)
+ {
+ err = gpgme_set_ctx_flag (ctx, "no-symkey-cache", "1");
+ if (err)
+ {
+ fprintf (stderr, PGM ": error setting no-symkey-cache: %s\n",
gpgme_strerror (err));
exit (1);
}
diff --git a/tests/run-encrypt.c b/tests/run-encrypt.c
index e949d76..9408469 100644
--- a/tests/run-encrypt.c
+++ b/tests/run-encrypt.c
@@ -37,6 +37,19 @@
static int verbose;
+static char *
+xstrdup (const char *string)
+{
+ char *p = strdup (string);
+ if (!p)
+ {
+ fprintf (stderr, "strdup failed\n");
+ exit (2);
+ }
+ return p;
+}
+
+
static gpg_error_t
status_cb (void *opaque, const char *keyword, const char *value)
{
@@ -80,17 +93,19 @@ show_usage (int ex)
{
fputs ("usage: " PGM " [options] FILE\n\n"
"Options:\n"
- " --verbose run in verbose mode\n"
- " --status print status lines from the backend\n"
- " --progress print progress info\n"
- " --openpgp use the OpenPGP protocol (default)\n"
- " --cms use the CMS protocol\n"
- " --uiserver use the UI server\n"
- " --loopback use a loopback pinentry\n"
- " --key NAME encrypt to key NAME\n"
- " --throw-keyids use this option\n"
- " --wrap assume input is valid OpenPGP message\n"
- " --symmetric encrypt symmetric (OpenPGP only)\n"
+ " --verbose run in verbose mode\n"
+ " --status print status lines from the backend\n"
+ " --progress print progress info\n"
+ " --openpgp use the OpenPGP protocol (default)\n"
+ " --cms use the CMS protocol\n"
+ " --uiserver use the UI server\n"
+ " --loopback use a loopback pinentry\n"
+ " --key NAME encrypt to key NAME\n"
+ " --keystring NAMES encrypt to ';' delimited NAMES\n"
+ " --throw-keyids use this option\n"
+ " --no-symkey-cache disable the use of that cache\n"
+ " --wrap assume input is valid OpenPGP message\n"
+ " --symmetric encrypt symmetric (OpenPGP only)\n"
, stderr);
exit (ex);
}
@@ -102,7 +117,6 @@ main (int argc, char **argv)
int last_argc = -1;
gpgme_error_t err;
gpgme_ctx_t ctx;
- const char *key_string = NULL;
gpgme_protocol_t protocol = GPGME_PROTOCOL_OpenPGP;
gpgme_data_t in, out;
gpgme_encrypt_result_t result;
@@ -112,9 +126,11 @@ main (int argc, char **argv)
char *keyargs[10];
gpgme_key_t keys[10+1];
int keycount = 0;
+ char *keystring = NULL;
int i;
gpgme_encrypt_flags_t flags = GPGME_ENCRYPT_ALWAYS_TRUST;
gpgme_off_t offset;
+ int no_symkey_cache = 0;
if (argc)
{ argc--; argv++; }
@@ -172,6 +188,17 @@ main (int argc, char **argv)
keyargs[keycount++] = *argv;
argc--; argv++;
}
+ else if (!strcmp (*argv, "--keystring"))
+ {
+ argc--; argv++;
+ if (!argc)
+ show_usage (1);
+ keystring = xstrdup (*argv);
+ for (i=0; keystring[i]; i++)
+ if (keystring[i] == ';')
+ keystring[i] = '\n';
+ argc--; argv++;
+ }
else if (!strcmp (*argv, "--throw-keyids"))
{
flags |= GPGME_ENCRYPT_THROW_KEYIDS;
@@ -192,6 +219,11 @@ main (int argc, char **argv)
flags |= GPGME_ENCRYPT_SYMMETRIC;
argc--; argv++;
}
+ else if (!strcmp (*argv, "--no-symkey-cache"))
+ {
+ no_symkey_cache = 1;
+ argc--; argv++;
+ }
else if (!strncmp (*argv, "--", 2))
show_usage (1);
@@ -200,15 +232,6 @@ main (int argc, char **argv)
if (argc != 1)
show_usage (1);
- if (key_string && protocol == GPGME_PROTOCOL_UISERVER)
- {
- fprintf (stderr, PGM ": ignoring --key in UI-server mode\n");
- key_string = NULL;
- }
-
- if (!key_string)
- key_string = "test";
-
init_gpgme (protocol);
err = gpgme_new (&ctx);
@@ -227,6 +250,16 @@ main (int argc, char **argv)
gpgme_set_pinentry_mode (ctx, GPGME_PINENTRY_MODE_LOOPBACK);
gpgme_set_passphrase_cb (ctx, passphrase_cb, NULL);
}
+ if (no_symkey_cache)
+ {
+ err = gpgme_set_ctx_flag (ctx, "no-symkey-cache", "1");
+ if (err)
+ {
+ fprintf (stderr, PGM ": error setting no-symkey-cache: %s\n",
+ gpgme_strerror (err));
+ exit (1);
+ }
+ }
for (i=0; i < keycount; i++)
{
@@ -281,7 +314,8 @@ main (int argc, char **argv)
err = gpgme_data_new (&out);
fail_if_err (err);
- err = gpgme_op_encrypt (ctx, keycount ? keys : NULL, flags, in, out);
+ err = gpgme_op_encrypt_ext (ctx, keycount ? keys : NULL, keystring,
+ flags, in, out);
result = gpgme_op_encrypt_result (ctx);
if (result)
print_result (result);
@@ -301,5 +335,6 @@ main (int argc, char **argv)
for (i=0; i < keycount; i++)
gpgme_key_unref (keys[i]);
gpgme_release (ctx);
+ free (keystring);
return 0;
}
diff --git a/tests/run-support.h b/tests/run-support.h
index 6a2170b..6c713a9 100644
--- a/tests/run-support.h
+++ b/tests/run-support.h
@@ -177,7 +177,8 @@ print_import_result (gpgme_import_result_t r)
" secret imported: %d\n"
" secret unchanged: %d\n"
" skipped new keys: %d\n"
- " not imported: %d\n",
+ " not imported: %d\n"
+ " skipped v3 keys: %d\n",
r->considered,
r->no_user_id,
r->imported,
@@ -191,6 +192,7 @@ print_import_result (gpgme_import_result_t r)
r->secret_imported,
r->secret_unchanged,
r->skipped_new_keys,
- r->not_imported);
+ r->not_imported,
+ r->skipped_v3_keys);
}
diff --git a/tests/run-verify.c b/tests/run-verify.c
index b22e644..4a6c960 100644
--- a/tests/run-verify.c
+++ b/tests/run-verify.c
@@ -136,10 +136,11 @@ print_result (gpgme_verify_result_t result)
gpgme_tofu_info_t ti;
int count = 0;
- printf ("Original file name: %s\n", nonnull(result->file_name));
+ printf ("Original file name .: %s\n", nonnull(result->file_name));
+ printf ("MIME flag ..........: %s\n", result->is_mime? "yes":"no");
for (sig = result->signatures; sig; sig = sig->next)
{
- printf ("Signature %d\n", count++);
+ printf ("Signature ...: %d\n", count++);
printf (" status ....: %s\n", gpgme_strerror (sig->status));
printf (" summary ...:"); print_summary (sig->summary); putchar ('\n');
printf (" fingerprint: %s\n", nonnull (sig->fpr));
@@ -163,17 +164,24 @@ print_result (gpgme_verify_result_t result)
);
for (nt = sig->notations; nt; nt = nt->next)
{
- printf (" notation ..: '%s'\n", nt->name);
- if (strlen (nt->name) != nt->name_len)
- printf (" warning : name larger (%d)\n", nt->name_len);
- printf (" flags ...:%s%s (0x%02x)\n",
- nt->critical? " critical":"",
- nt->human_readable? " human":"",
- nt->flags);
- if (nt->value)
- printf (" value ...: '%s'\n", nt->value);
+ if (nt->name)
+ {
+ printf (" notation ..: '%s'\n", nt->name);
+ if (strlen (nt->name) != nt->name_len)
+ printf (" warning .: name larger (%d)\n", nt->name_len);
+ printf (" flags ...:%s%s (0x%02x)\n",
+ nt->critical? " critical":"",
+ nt->human_readable? " human":"",
+ nt->flags);
+ if (nt->value)
+ printf (" value ...: '%s'\n", nt->value);
+ }
+ else
+ {
+ printf (" policy ....: '%s'\n", nt->value);
+ }
if ((nt->value?strlen (nt->value):0) != nt->value_len)
- printf (" warning : value larger (%d)\n", nt->value_len);
+ printf (" warning .: value larger (%d)\n", nt->value_len);
}
if (sig->key)
{