From 0d28a696163677d6b34a802b6beddecd805d0fc7 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 5 Jun 2015 14:25:59 +0200 Subject: Fix segv for userids with a backslash. * src/engine-gpg.c (gpg_keylist_preprocess): Increment SRC for a backslash. -- This bug is not exploitable because this bug fills up .data with backslashes and thus causes the segv. Signed-off-by: Werner Koch --- src/engine-gpg.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine-gpg.c b/src/engine-gpg.c index 57aea8b0..e14fd8dd 100644 --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -2194,6 +2194,7 @@ gpg_keylist_preprocess (char *line, char **r_line) { *dst++ = '\\'; *dst++ = '\\'; + src++; } else *(dst++) = *(src++); -- cgit v1.2.3 From 87d713ff41454bd08a345c63605f6fc7ac854dd4 Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Wed, 18 Mar 2015 17:20:55 -0400 Subject: Set GPGME_SIGSUM_KEY_REVOKED also for gpg. * src/verify.c (calc_sig_summary): Handle GPG_ERR_CERT_REVOKED. -- parse_new_sig() handles a revoked key by setting sig->status to GPG_ERR_CERT_REVOKED, but then later calc_sig_summary() expects that code in sig->validity_reason. Additional comments added by wk. --- src/verify.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/verify.c b/src/verify.c index 37b2bd46..84487ee4 100644 --- a/src/verify.c +++ b/src/verify.c @@ -195,6 +195,10 @@ calc_sig_summary (gpgme_signature_t sig) sum |= GPGME_SIGSUM_KEY_MISSING; break; + case GPG_ERR_CERT_REVOKED: + sum |= GPGME_SIGSUM_KEY_REVOKED; + break; + case GPG_ERR_BAD_SIGNATURE: case GPG_ERR_NO_ERROR: break; @@ -213,6 +217,9 @@ calc_sig_summary (gpgme_signature_t sig) break; case GPG_ERR_CERT_REVOKED: + /* Note that this is a second way to set this flag. It may also + have been set due to a sig->status of STATUS_REVKEYSIG from + parse_new_sig. */ sum |= GPGME_SIGSUM_KEY_REVOKED; break; -- cgit v1.2.3 From a5b040cc57c65b3d105666b90c7eb59ee6ff3882 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 8 Jun 2015 10:43:29 +0200 Subject: Fix test suite for GnuPG 2.1 which uses pubring.kbx. * tests/gpgsm/final.test: New. * tests/gpgsm/initial.test: New. * tests/gpg/start-stop-agent: Move to ../. * tests/gpgsm/Makefile.am (TESTS_ENVIRONMENT): Export top_srcdir. (TESTS): Add intial.test and final.test. (AM_LDFLAGS): Add -no-install. (clean-local): Use start-stop-agent (initial.test): Add dependency. * tests/gpg/Makefile.am (top_srcdir): Export top_srcdir. (AM_LDFLAGS): Add -no-install. (check-local): Depend on pubring-stamp instead of pubring.gpg. (initial.test): Depend on check-local. (./pubring-gpg): Replace by rule for ./pubring-stamp. -- There are also a couple of other changes which should make the tests a bit more robust and the gpg and gpgsm tests more similar. The -no-install avoids creating wrappers for test programs, which make debugging easier. The dependency on check-local guarantees that its rules are run before the first test. This is important because conf files are setup by this rule. Earlier automake versions seem to have run check-local always before the tests but today the order of execution is not defined. Signed-off-by: Werner Koch --- tests/Makefile.am | 2 +- tests/gpg/Makefile.am | 23 +++++++++++++++-------- tests/gpg/final.test | 2 +- tests/gpg/initial.test | 2 +- tests/gpg/start-stop-agent | 45 --------------------------------------------- tests/gpgsm/Makefile.am | 20 +++++++++++++++----- tests/gpgsm/final.test | 5 +++++ tests/gpgsm/initial.test | 4 ++++ tests/start-stop-agent | 45 +++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 87 insertions(+), 61 deletions(-) delete mode 100755 tests/gpg/start-stop-agent create mode 100755 tests/gpgsm/final.test create mode 100755 tests/gpgsm/initial.test create mode 100755 tests/start-stop-agent diff --git a/tests/Makefile.am b/tests/Makefile.am index 4b465d8e..94eddac5 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -23,7 +23,7 @@ TESTS_ENVIRONMENT = GNUPGHOME=$(abs_builddir) TESTS = t-version t-data t-engine-info -EXTRA_DIST = t-data-1.txt t-data-2.txt ChangeLog-2011 +EXTRA_DIST = start-stop-agent t-data-1.txt t-data-2.txt ChangeLog-2011 AM_CPPFLAGS = -I$(top_builddir)/src @GPG_ERROR_CFLAGS@ LDADD = ../src/libgpgme.la @GPG_ERROR_LIBS@ diff --git a/tests/gpg/Makefile.am b/tests/gpg/Makefile.am index 5f40dfe2..107397b4 100644 --- a/tests/gpg/Makefile.am +++ b/tests/gpg/Makefile.am @@ -22,7 +22,8 @@ GPG = gpg GPG_AGENT = gpg-agent -TESTS_ENVIRONMENT = GNUPGHOME=$(abs_builddir) LC_ALL=C GPG_AGENT_INFO= +TESTS_ENVIRONMENT = GNUPGHOME=$(abs_builddir) LC_ALL=C GPG_AGENT_INFO= \ + top_srcdir=$(top_srcdir) # The keylist tests must come after the import and the edit test. noinst_HEADERS = t-support.h @@ -43,7 +44,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 + random_seed S.gpg-agent .gpg-v21-migrated pubring-stamp private_keys = \ 13CD0F3BDF24BE53FE192D62F18737256FF6E4FD \ @@ -53,11 +54,12 @@ private_keys = \ 7A030357C0F253A5BBCD282FFC4E521B37558F5C -EXTRA_DIST = start-stop-agent initial.test final.test \ +EXTRA_DIST = initial.test final.test \ pubdemo.asc secdemo.asc cipher-1.asc cipher-2.asc \ geheim.txt pubkey-1.asc seckey-1.asc pinentry $(private_keys) AM_CPPFLAGS = -I$(top_builddir)/src @GPG_ERROR_CFLAGS@ +AM_LDFLAGS = -no-install LDADD = ../../src/libgpgme.la t_thread1_LDADD = ../../src/libgpgme-pthread.la -lpthread @@ -65,12 +67,16 @@ t_thread1_LDADD = ../../src/libgpgme-pthread.la -lpthread noinst_PROGRAMS = $(c_tests) t-genkey clean-local: - -$(srcdir)/start-stop-agent --stop + -$(top_srcdir)/tests/start-stop-agent --stop -rm -fR private-keys-v1.d -check-local: ./gpg.conf ./gpg-agent.conf ./pubring.gpg \ +check-local: ./gpg.conf ./gpg-agent.conf ./pubring-stamp \ ./private-keys-v1.d/gpg-sample.stamp +# To guarantee that check-local is run before any tests we +# add this dependency: +initial.test : check-local + export GNUPGHOME := $(abs_builddir) export GPG_AGENT_INFO := @@ -82,11 +88,12 @@ export GPG_AGENT_INFO := done echo x > ./private-keys-v1.d/gpg-sample.stamp -./pubring.gpg: $(srcdir)/pubdemo.asc - -$(GPG) --no-permission-warning \ - --import $(srcdir)/pubdemo.asc +./pubring-stamp: $(srcdir)/pubdemo.asc + $(GPG) --no-permission-warning \ + --import $(srcdir)/pubdemo.asc -$(GPG) --no-permission-warning \ --import $(srcdir)/secdemo.asc + touch ./pubring-stamp ./gpg.conf: # This is required for t-sig-notations. diff --git a/tests/gpg/final.test b/tests/gpg/final.test index 5148a34b..5289396f 100755 --- a/tests/gpg/final.test +++ b/tests/gpg/final.test @@ -1,4 +1,4 @@ #!/bin/sh -${srcdir}/start-stop-agent --stop +${top_srcdir}/tests/start-stop-agent --stop exit 0 diff --git a/tests/gpg/initial.test b/tests/gpg/initial.test index 1981c99d..93c8621a 100755 --- a/tests/gpg/initial.test +++ b/tests/gpg/initial.test @@ -1,4 +1,4 @@ #!/bin/sh -${srcdir}/start-stop-agent --start +${top_srcdir}/tests/start-stop-agent --start exit 0 diff --git a/tests/gpg/start-stop-agent b/tests/gpg/start-stop-agent deleted file mode 100755 index ab47d8d9..00000000 --- a/tests/gpg/start-stop-agent +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/sh -# Copyright (C) 2013 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 -# 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. - -if [ -z "$(command -v gpg-connect-agent)" ]; then - echo "gpg-agent not installed and thus not started" >&2 - exit 0; -fi - -GPG_AGENT_INFO= -export GPG_AGENT_INFO - -token=$(echo "gpgme-$(pwd)" | tr ' ' '_') - -if [ "$1" = "--stop" ]; then - if [ "$(gpg-connect-agent getval\ $token /bye 2>/dev/null | head -1)" \ - != "D set" ]; then - echo "gpg-agent not running" >&2 - exit 0 - fi - echo "stopping gpg-agent " >&2 - gpg-connect-agent KILLAGENT /bye >/dev/null 2>&1 - exit 0 -fi - -if [ "$(gpg-connect-agent getval\ $token /bye 2>/dev/null | head -1)" \ - = "D set" ]; then - echo "gpg-agent already running" >&2 - exit 0 -fi - -echo "starting gpg-agent " >&2 -gpg-connect-agent putval\ $token\ set /bye >/dev/null 2>&1 -if [ "$(gpg-connect-agent getval\ $token /bye 2>/dev/null | head -1)" \ - != "D set" ]; then - echo "error starting gpg-agent" >&2 - exit 1 -fi -exit 0 diff --git a/tests/gpgsm/Makefile.am b/tests/gpgsm/Makefile.am index bf616d32..41645b6c 100644 --- a/tests/gpgsm/Makefile.am +++ b/tests/gpgsm/Makefile.am @@ -21,20 +21,26 @@ GPGSM = gpgsm -TESTS_ENVIRONMENT = GNUPGHOME=$(abs_builddir) GPG_AGENT_INFO= +TESTS_ENVIRONMENT = GNUPGHOME=$(abs_builddir) LC_ALL=C GPG_AGENT_INFO= \ + top_srcdir=$(top_srcdir) noinst_HEADERS = t-support.h -TESTS = t-import t-keylist t-encrypt t-verify t-decrypt t-sign t-export + +c_tests = t-import t-keylist t-encrypt t-verify t-decrypt t-sign t-export + + +TESTS = initial.test $(c_tests) final.test EXTRA_DIST = cert_dfn_pca01.der cert_dfn_pca15.der cert_g10code_test1.der \ - $(key_id) + $(key_id) initial.test final.test AM_CPPFLAGS = -I$(top_builddir)/src @GPG_ERROR_CFLAGS@ +AM_LDFLAGS = -no-install LDADD = ../../src/libgpgme.la # We don't run t-genkey in the test suite, because it takes too long # and needs a working pinentry. -noinst_PROGRAMS = $(TESTS) t-genkey cms-keylist cms-decrypt +noinst_PROGRAMS = $(c_tests) t-genkey cms-keylist cms-decrypt key_id = 32100C27173EF6E9C4E9A25D3D69F86D37A4F939 @@ -42,12 +48,16 @@ CLEANFILES = pubring.kbx pubring.kbx~ gpgsm.conf trustlist.txt \ random_seed S.gpg-agent clean-local: - -gpg-connect-agent KILLAGENT /bye + -$(top_srcdir)/tests/start-stop-agent --stop -rm -fR private-keys-v1.d check-local: ./pubring.kbx ./gpgsm.conf \ ./private-keys-v1.d/$(key_id).key ./trustlist.txt +# To guarantee that check-local is run before any tests we add this +# dependency: +initial.test : check-local + export GNUPGHOME := $(abs_builddir) export GPG_AGENT_INFO := diff --git a/tests/gpgsm/final.test b/tests/gpgsm/final.test new file mode 100755 index 00000000..d0567e3f --- /dev/null +++ b/tests/gpgsm/final.test @@ -0,0 +1,5 @@ +#!/bin/sh + +${top_srcdir}/tests/start-stop-agent --stop + +exit 0 diff --git a/tests/gpgsm/initial.test b/tests/gpgsm/initial.test new file mode 100755 index 00000000..93c8621a --- /dev/null +++ b/tests/gpgsm/initial.test @@ -0,0 +1,4 @@ +#!/bin/sh + +${top_srcdir}/tests/start-stop-agent --start +exit 0 diff --git a/tests/start-stop-agent b/tests/start-stop-agent new file mode 100755 index 00000000..ab47d8d9 --- /dev/null +++ b/tests/start-stop-agent @@ -0,0 +1,45 @@ +#!/bin/sh +# Copyright (C) 2013 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 +# 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. + +if [ -z "$(command -v gpg-connect-agent)" ]; then + echo "gpg-agent not installed and thus not started" >&2 + exit 0; +fi + +GPG_AGENT_INFO= +export GPG_AGENT_INFO + +token=$(echo "gpgme-$(pwd)" | tr ' ' '_') + +if [ "$1" = "--stop" ]; then + if [ "$(gpg-connect-agent getval\ $token /bye 2>/dev/null | head -1)" \ + != "D set" ]; then + echo "gpg-agent not running" >&2 + exit 0 + fi + echo "stopping gpg-agent " >&2 + gpg-connect-agent KILLAGENT /bye >/dev/null 2>&1 + exit 0 +fi + +if [ "$(gpg-connect-agent getval\ $token /bye 2>/dev/null | head -1)" \ + = "D set" ]; then + echo "gpg-agent already running" >&2 + exit 0 +fi + +echo "starting gpg-agent " >&2 +gpg-connect-agent putval\ $token\ set /bye >/dev/null 2>&1 +if [ "$(gpg-connect-agent getval\ $token /bye 2>/dev/null | head -1)" \ + != "D set" ]; then + echo "error starting gpg-agent" >&2 + exit 1 +fi +exit 0 -- cgit v1.2.3 From 8b9f84828cd04a7dab37e219123edc1905da8e6b Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 8 Jun 2015 11:08:08 +0200 Subject: Fix compiler warnings about unused value in TRACE macros. * src/debug.h: Change macros to not have a literal 0 as last expression of the comma operator. * src/debug.c (_gpgme_debug_frame_end): Return 0. (_gpgme_debug): Return 0. -- Instead of using foo(), 0 for the trace macros we let foo() return 0 instead. Signed-off-by: Werner Koch --- src/debug.c | 19 +++++++++++++++---- src/debug.h | 63 +++++++++++++++++++++++++++++-------------------------------- 2 files changed, 45 insertions(+), 37 deletions(-) diff --git a/src/debug.c b/src/debug.c index ca0bb21a..292db555 100644 --- a/src/debug.c +++ b/src/debug.c @@ -80,11 +80,12 @@ _gpgme_debug_frame_begin (void) #endif } -void _gpgme_debug_frame_end (void) +int _gpgme_debug_frame_end (void) { #ifdef FRAME_NR frame_nr--; #endif + return 0; } @@ -223,8 +224,17 @@ _gpgme_debug_subsystem_init (void) -/* Log the formatted string FORMAT at debug level LEVEL or higher. */ -void +/* Log the formatted string FORMAT at debug level LEVEL or higher. + * + * Returns: 0 + * + * Note that we always return 0 because the old TRACE macro evaluated + * to 0 which issues a warning with newer gcc version about an unused + * values. By using a return value of this function this can be + * avoided. Fixme: It might be useful to check whether the return + * value from the TRACE macros are actually used somewhere. + */ +int _gpgme_debug (int level, const char *format, ...) { va_list arg_ptr; @@ -232,7 +242,7 @@ _gpgme_debug (int level, const char *format, ...) saved_errno = errno; if (debug_level < level) - return; + return 0; va_start (arg_ptr, format); LOCK (debug_lock); @@ -273,6 +283,7 @@ _gpgme_debug (int level, const char *format, ...) fflush (errfp); gpg_err_set_errno (saved_errno); + return 0; } diff --git a/src/debug.h b/src/debug.h index d0db5736..6bde998f 100644 --- a/src/debug.h +++ b/src/debug.h @@ -64,7 +64,7 @@ int _gpgme_debug_set_debug_envvar (const char *value); void _gpgme_debug_subsystem_init (void); /* Log the formatted string FORMAT at debug level LEVEL or higher. */ -void _gpgme_debug (int level, const char *format, ...); +int _gpgme_debug (int level, const char *format, ...); /* Start a new debug line in *LINE, logged at level LEVEL or higher, and starting with the formatted string FORMAT. */ @@ -82,7 +82,7 @@ void _gpgme_debug_buffer (int lvl, const char *const fmt, size_t len); void _gpgme_debug_frame_begin (void); -void _gpgme_debug_frame_end (void); +int _gpgme_debug_frame_end (void); static inline gpgme_error_t _gpgme_trace_gpgme_error (gpgme_error_t err, const char *file, int line) @@ -108,82 +108,80 @@ _gpgme_trace_gpgme_error (gpgme_error_t err, const char *file, int line) #define TRACE_BEG(lvl, name, tag) \ _TRACE (lvl, name, tag); \ _gpgme_debug (_gpgme_trace_level, "%s: enter: %s=%p\n", \ - _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag), 0 + _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag) #define TRACE_BEG0(lvl, name, tag, fmt) \ _TRACE (lvl, name, tag); \ _gpgme_debug (_gpgme_trace_level, "%s: enter: %s=%p, " fmt "\n", \ - _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag), 0 + _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag) #define TRACE_BEG1(lvl, name, tag, fmt, arg1) \ _TRACE (lvl, name, tag); \ _gpgme_debug (_gpgme_trace_level, "%s: enter: %s=%p, " fmt "\n", \ _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ - arg1), 0 + arg1) #define TRACE_BEG2(lvl, name, tag, fmt, arg1, arg2) \ _TRACE (lvl, name, tag); \ _gpgme_debug (_gpgme_trace_level, "%s: enter: %s=%p, " fmt "\n", \ _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ - arg1, arg2), 0 + arg1, arg2) #define TRACE_BEG3(lvl, name, tag, fmt, arg1, arg2, arg3) \ _TRACE (lvl, name, tag); \ _gpgme_debug (_gpgme_trace_level, "%s: enter: %s=%p, " fmt "\n", \ _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ - arg1, arg2, arg3), 0 + arg1, arg2, arg3) #define TRACE_BEG4(lvl, name, tag, fmt, arg1, arg2, arg3, arg4) \ _TRACE (lvl, name, tag); \ _gpgme_debug (_gpgme_trace_level, "%s: enter: %s=%p, " fmt "\n", \ _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ - arg1, arg2, arg3, arg4), 0 + arg1, arg2, arg3, arg4) #define TRACE_BEG5(lvl, name, tag, fmt, arg1, arg2, arg3, arg4, arg5) \ _TRACE (lvl, name, tag); \ _gpgme_debug (_gpgme_trace_level, "%s: enter: %s=%p, " fmt "\n", \ _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ - arg1, arg2, arg3, arg4, arg5), 0 + arg1, arg2, arg3, arg4, arg5) #define TRACE_BEG7(lvl, name, tag, fmt, arg1, arg2, arg3, arg4, \ arg5, arg6, arg7) \ _TRACE (lvl, name, tag); \ _gpgme_debug (_gpgme_trace_level, "%s: enter: %s=%p, " fmt "\n", \ _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ - arg1, arg2, arg3, arg4, arg5, \ - arg6, arg7), 0 + arg1, arg2, arg3, arg4, arg5, arg6, arg7) #define TRACE_BEG8(lvl, name, tag, fmt, arg1, arg2, arg3, arg4, \ arg5, arg6, arg7, arg8) \ _TRACE (lvl, name, tag); \ _gpgme_debug (_gpgme_trace_level, "%s: enter: %s=%p, " fmt "\n", \ _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ - arg1, arg2, arg3, arg4, arg5, \ - arg6, arg7, arg8), 0 + arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) #define TRACE(lvl, name, tag) \ _gpgme_debug_frame_begin (), \ _gpgme_debug (lvl, "%s: call: %s=%p\n", \ name, STRINGIFY (tag), (void *) (uintptr_t) tag), \ - _gpgme_debug_frame_end (), 0 + _gpgme_debug_frame_end () #define TRACE0(lvl, name, tag, fmt) \ _gpgme_debug_frame_begin (), \ _gpgme_debug (lvl, "%s: call: %s=%p, " fmt "\n", \ name, STRINGIFY (tag), (void *) (uintptr_t) tag), \ - _gpgme_debug_frame_end (), 0 + _gpgme_debug_frame_end () #define TRACE1(lvl, name, tag, fmt, arg1) \ _gpgme_debug_frame_begin (), \ _gpgme_debug (lvl, "%s: call: %s=%p, " fmt "\n", \ name, STRINGIFY (tag), (void *) (uintptr_t) tag, arg1), \ - _gpgme_debug_frame_end (), 0 + _gpgme_debug_frame_end () #define TRACE2(lvl, name, tag, fmt, arg1, arg2) \ _gpgme_debug_frame_begin (), \ _gpgme_debug (lvl, "%s: call: %s=%p, " fmt "\n", \ name, STRINGIFY (tag), (void *) (uintptr_t) tag, arg1, \ - arg2), _gpgme_debug_frame_end (), 0 + arg2), _gpgme_debug_frame_end () #define TRACE3(lvl, name, tag, fmt, arg1, arg2, arg3) \ _gpgme_debug_frame_begin (), \ _gpgme_debug (lvl, "%s: call: %s=%p, " fmt "\n", \ name, STRINGIFY (tag), (void *) (uintptr_t) tag, arg1, \ - arg2, arg3), _gpgme_debug_frame_end (), 0 + arg2, arg3), _gpgme_debug_frame_end () #define TRACE6(lvl, name, tag, fmt, arg1, arg2, arg3, arg4, arg5, arg6) \ _gpgme_debug_frame_begin (), \ _gpgme_debug (lvl, "%s: call: %s=%p, " fmt "\n", \ name, STRINGIFY (tag), (void *) (uintptr_t) tag, arg1, \ arg2, arg3, arg4, arg5, arg6), \ - _gpgme_debug_frame_end (), 0 + _gpgme_debug_frame_end () #define TRACE_ERR(err) \ err == 0 ? (TRACE_SUC ()) : \ @@ -203,53 +201,52 @@ _gpgme_trace_gpgme_error (gpgme_error_t err, const char *file, int line) #define TRACE_SUC() \ _gpgme_debug (_gpgme_trace_level, "%s: leave\n", \ - _gpgme_trace_func), _gpgme_debug_frame_end (), 0 + _gpgme_trace_func), _gpgme_debug_frame_end () #define TRACE_SUC0(fmt) \ _gpgme_debug (_gpgme_trace_level, "%s: leave: " fmt "\n", \ - _gpgme_trace_func), _gpgme_debug_frame_end (), 0 + _gpgme_trace_func), _gpgme_debug_frame_end () #define TRACE_SUC1(fmt, arg1) \ _gpgme_debug (_gpgme_trace_level, "%s: leave: " fmt "\n", \ - _gpgme_trace_func, arg1), _gpgme_debug_frame_end (), 0 + _gpgme_trace_func, arg1), _gpgme_debug_frame_end () #define TRACE_SUC2(fmt, arg1, arg2) \ _gpgme_debug (_gpgme_trace_level, "%s: leave: " fmt "\n", \ - _gpgme_trace_func, arg1, arg2), _gpgme_debug_frame_end (), 0 + _gpgme_trace_func, arg1, arg2), _gpgme_debug_frame_end () #define TRACE_SUC5(fmt, arg1, arg2, arg3, arg4, arg5) \ _gpgme_debug (_gpgme_trace_level, "%s: leave: " fmt "\n", \ _gpgme_trace_func, arg1, arg2, arg3, arg4, arg5), \ - _gpgme_debug_frame_end (), 0 + _gpgme_debug_frame_end () #define TRACE_SUC6(fmt, arg1, arg2, arg3, arg4, arg5, arg6) \ _gpgme_debug (_gpgme_trace_level, "%s: leave: " fmt "\n", \ _gpgme_trace_func, arg1, arg2, arg3, arg4, arg5, arg6), \ - _gpgme_debug_frame_end (), 0 + _gpgme_debug_frame_end () #define TRACE_LOG(fmt) \ _gpgme_debug (_gpgme_trace_level, "%s: check: %s=%p, " fmt "\n", \ - _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag), 0 + _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag) #define TRACE_LOG1(fmt, arg1) \ _gpgme_debug (_gpgme_trace_level, "%s: check: %s=%p, " fmt "\n", \ _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ - arg1), 0 + arg1) #define TRACE_LOG2(fmt, arg1, arg2) \ _gpgme_debug (_gpgme_trace_level, "%s: check: %s=%p, " fmt "\n", \ _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ - arg1, arg2), 0 + arg1, arg2) #define TRACE_LOG3(fmt, arg1, arg2, arg3) \ _gpgme_debug (_gpgme_trace_level, "%s: check: %s=%p, " fmt "\n", \ _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ - arg1, arg2, arg3), 0 + arg1, arg2, arg3) #define TRACE_LOG4(fmt, arg1, arg2, arg3, arg4) \ _gpgme_debug (_gpgme_trace_level, "%s: check: %s=%p, " fmt "\n", \ _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ - arg1, arg2, arg3, arg4), 0 + arg1, arg2, arg3, arg4) #define TRACE_LOG5(fmt, arg1, arg2, arg3, arg4, arg5) \ _gpgme_debug (_gpgme_trace_level, "%s: check: %s=%p, " fmt "\n", \ _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ - arg1, arg2, arg3, arg4, arg5), 0 + arg1, arg2, arg3, arg4, arg5) #define TRACE_LOG6(fmt, arg1, arg2, arg3, arg4, arg5, arg6) \ _gpgme_debug (_gpgme_trace_level, "%s: check: %s=%p, " fmt "\n", \ _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ - arg1, arg2, arg3, arg4, arg5, \ - arg6), 0 + arg1, arg2, arg3, arg4, arg5, arg6) #define TRACE_LOGBUF(buf, len) \ _gpgme_debug_buffer (_gpgme_trace_level, "%s: check: %s", \ -- cgit v1.2.3 From 7addffc0826e7f36afcc7f66268e9ee2a37e2042 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 8 Jun 2015 12:30:11 +0200 Subject: tests: Add option --secret to run-keylist. Signed-off-by: Werner Koch --- tests/run-keylist.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/run-keylist.c b/tests/run-keylist.c index c0c72022..07c6fa18 100644 --- a/tests/run-keylist.c +++ b/tests/run-keylist.c @@ -45,6 +45,7 @@ show_usage (int ex) " --verbose run in verbose mode\n" " --openpgp use the OpenPGP protocol (default)\n" " --cms use the CMS protocol\n" + " --secret list only secret keys\n" " --local use GPGME_KEYLIST_MODE_LOCAL\n" " --extern use GPGME_KEYLIST_MODE_EXTERN\n" " --sigs use GPGME_KEYLIST_MODE_SIGS\n" @@ -70,6 +71,7 @@ main (int argc, char **argv) gpgme_key_t keyarray[100]; int keyidx = 0; gpgme_protocol_t protocol = GPGME_PROTOCOL_OpenPGP; + int only_secret = 0; if (argc) { argc--; argv++; } @@ -99,6 +101,11 @@ main (int argc, char **argv) protocol = GPGME_PROTOCOL_CMS; argc--; argv++; } + else if (!strcmp (*argv, "--secret")) + { + only_secret = 1; + argc--; argv++; + } else if (!strcmp (*argv, "--local")) { mode |= GPGME_KEYLIST_MODE_LOCAL; @@ -150,7 +157,7 @@ main (int argc, char **argv) gpgme_set_keylist_mode (ctx, mode); - err = gpgme_op_keylist_start (ctx, argc? argv[0]:NULL, 0); + err = gpgme_op_keylist_start (ctx, argc? argv[0]:NULL, only_secret); fail_if_err (err); while (!(err = gpgme_op_keylist_next (ctx, &key))) -- cgit v1.2.3 From ddbd54ef881bd2c3481d62b89bef7241667b64ee Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 8 Jun 2015 12:34:49 +0200 Subject: Fix regression with gpgsm 2.0 due to "OPTION with-secret". * src/engine-gpgsm.c (gpgsm_assuan_simple_command): Do not terminate on a status lines. -- This bug has been with us since the support for gpgsm: If there is no status line handler but a status line is received anyway the command handling loop terminates and thus the command/answer order gets out of sync. In the case of the bug report this is triggered by sending an option which starts the agent and that starting emits a "PROGRESS" status line. The solution is not to stop reading after a status line but record a possible error code and return that only after OK or ERR. GnuPG-bug-id: 1795 Signed-off-by: Werner Koch --- src/engine-gpgsm.c | 46 ++++++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/src/engine-gpgsm.c b/src/engine-gpgsm.c index 3a837577..ac6c5fc6 100644 --- a/src/engine-gpgsm.c +++ b/src/engine-gpgsm.c @@ -564,7 +564,7 @@ gpgsm_assuan_simple_command (assuan_context_t ctx, char *cmd, engine_status_handler_t status_fnc, void *status_fnc_value) { - gpg_error_t err; + gpg_error_t err, cb_err; char *line; size_t linelen; @@ -572,6 +572,7 @@ gpgsm_assuan_simple_command (assuan_context_t ctx, char *cmd, if (err) return err; + cb_err = 0; do { err = assuan_read_line (ctx, &line, &linelen); @@ -584,32 +585,45 @@ gpgsm_assuan_simple_command (assuan_context_t ctx, char *cmd, if (linelen >= 2 && line[0] == 'O' && line[1] == 'K' && (line[2] == '\0' || line[2] == ' ')) - return 0; + return cb_err; else if (linelen >= 4 && line[0] == 'E' && line[1] == 'R' && line[2] == 'R' && line[3] == ' ') - err = atoi (&line[4]); + { + /* We prefer a callback generated error because that one is + more related to gpgme and thus probably more important + than the error returned by the engine. */ + err = cb_err? cb_err : atoi (&line[4]); + } else if (linelen >= 2 && line[0] == 'S' && line[1] == ' ') { - char *rest; - gpgme_status_code_t r; + /* After an error from a status callback we skip all further + status lines. */ + if (!cb_err) + { + char *rest; + gpgme_status_code_t r; - rest = strchr (line + 2, ' '); - if (!rest) - rest = line + linelen; /* set to an empty string */ - else - *(rest++) = 0; + rest = strchr (line + 2, ' '); + if (!rest) + rest = line + linelen; /* set to an empty string */ + else + *(rest++) = 0; - r = _gpgme_parse_status (line + 2); + r = _gpgme_parse_status (line + 2); - if (r >= 0 && status_fnc) - err = status_fnc (status_fnc_value, r, rest); - else - err = gpg_error (GPG_ERR_GENERAL); + if (r >= 0 && status_fnc) + cb_err = status_fnc (status_fnc_value, r, rest); + } } else - err = gpg_error (GPG_ERR_GENERAL); + { + /* Invalid line or INQUIRY. We can't do anything else than + to stop. As with ERR we prefer a status callback + generated error code, though. */ + err = cb_err ? cb_err : gpg_error (GPG_ERR_GENERAL); + } } while (!err); -- cgit v1.2.3 From 052a9e3c5671d1ab69551f7b0abd0bbf859d4aba Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 8 Jun 2015 14:58:44 +0200 Subject: Release 1.5.5 --- AUTHORS | 2 +- NEWS | 8 +++++++- configure.ac | 6 +++--- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/AUTHORS b/AUTHORS index 61974167..dd4b4928 100644 --- a/AUTHORS +++ b/AUTHORS @@ -3,7 +3,7 @@ Homepage: http://www.gnupg.org/related_software/gpgme/ Download: ftp://ftp.gnupg.org/gcrypt/gpgme/ Repository: git://git.gnupg.org/gpgme.git Maintainer: Werner Koch -Bug reports: http://bugs.gnupg.org (use category "gpgme") +Bug reports: https://bugs.gnupg.org (use category "gpgme") Security related bug reports: security@gnupg.org License (software): LGPLv2.1+ License (manual+tools): GPLv3+ diff --git a/NEWS b/NEWS index 09cc930d..8e9472a3 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,12 @@ -Noteworthy changes in version 1.6.0 (unreleased) [C__/A__/R_] +Noteworthy changes in version 1.5.5 (2015-06-08) [C24/A13/R4] ------------------------------------------------ + * Fixed crash in key listings for user ids with a backslash. + + * Fixed regression for GPGSM use with GnuPG < 2.1. + + * Properly set signature summary for revoked OpenPGP keys. + Noteworthy changes in version 1.5.4 (2015-04-13) [C24/A13/R3] ------------------------------------------------ diff --git a/configure.ac b/configure.ac index 2f477195..7f03170e 100644 --- a/configure.ac +++ b/configure.ac @@ -28,8 +28,8 @@ 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, [6]) -m4_define(mym4_version_micro, [0]) +m4_define(mym4_version_minor, [5]) +m4_define(mym4_version_micro, [5]) # Below is m4 magic to extract and compute the revision number, the # decimalized short revision number, a beta version string, and a flag @@ -59,7 +59,7 @@ LIBGPGME_LT_CURRENT=24 # Subtract 2 from this value if you want to make the LFS transition an # ABI break. [Note to self: Remove this comment with the next regular break.] LIBGPGME_LT_AGE=13 -LIBGPGME_LT_REVISION=3 +LIBGPGME_LT_REVISION=4 # If the API is changed in an incompatible way: increment the next counter. GPGME_CONFIG_API_VERSION=1 -- cgit v1.2.3 From a5d9e018b8826e97c9fcc548c8e9e797bbc8d6db Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 8 Jun 2015 15:18:56 +0200 Subject: Post release updates -- --- NEWS | 4 ++++ configure.ac | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 8e9472a3..0e1e5009 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,7 @@ +Noteworthy changes in version 1.6.0 (unreleased) [C24/A13/R_] +------------------------------------------------ + + Noteworthy changes in version 1.5.5 (2015-06-08) [C24/A13/R4] ------------------------------------------------ diff --git a/configure.ac b/configure.ac index 7f03170e..be36a420 100644 --- a/configure.ac +++ b/configure.ac @@ -28,8 +28,8 @@ 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, [5]) -m4_define(mym4_version_micro, [5]) +m4_define(mym4_version_minor, [6]) +m4_define(mym4_version_micro, [0]) # Below is m4 magic to extract and compute the revision number, the # decimalized short revision number, a beta version string, and a flag -- cgit v1.2.3 From c23f8897105ce2bb6e62d9c44ca0779fcc08a919 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 23 Jul 2015 11:40:09 +0200 Subject: Add option --lib-version to gpgme-tool. * src/gpgme-tool.c (options, parse_options): Add --lib-version (CMD_LIBVERSION): New. (main): Implement. --- src/gpgme-tool.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/gpgme-tool.c b/src/gpgme-tool.c index d42179bd..94d11248 100644 --- a/src/gpgme-tool.c +++ b/src/gpgme-tool.c @@ -3728,6 +3728,7 @@ static char args_doc[] = "COMMAND [OPTIONS...]"; static struct argp_option options[] = { { "server", 's', 0, 0, "Server mode" }, { "gpg-binary", 501, "FILE", 0, "Use FILE for the GPG backend" }, + { "lib-version", 502, 0, 0, "Show library version" }, { 0 } }; @@ -3736,7 +3737,7 @@ static struct argp argp = { options, parse_options, args_doc, doc }; struct args { - enum { CMD_DEFAULT, CMD_SERVER } cmd; + enum { CMD_DEFAULT, CMD_SERVER, CMD_LIBVERSION } cmd; const char *gpg_binary; }; @@ -3762,6 +3763,11 @@ parse_options (int key, char *arg, struct argp_state *state) case 501: args->gpg_binary = arg; break; + + case 502: + args->cmd = CMD_LIBVERSION; + break; + #if 0 case ARGP_KEY_ARG: if (state->arg_num >= 2) @@ -3787,6 +3793,7 @@ main (int argc, char *argv[]) struct args args; struct gpgme_tool gt; gpg_error_t err; + int needgt = 1; #ifdef HAVE_SETLOCALE setlocale (LC_ALL, ""); @@ -3804,7 +3811,10 @@ main (int argc, char *argv[]) argp_parse (&argp, argc, argv, 0, 0, &args); log_init (); - if (args.gpg_binary) + if (args.cmd == CMD_LIBVERSION) + needgt = 0; + + if (needgt && args.gpg_binary) { if (access (args.gpg_binary, X_OK)) err = gpg_error_from_syserror (); @@ -3816,7 +3826,8 @@ main (int argc, char *argv[]) args.gpg_binary); } - gt_init (>); + if (needgt) + gt_init (>); switch (args.cmd) { @@ -3824,9 +3835,17 @@ main (int argc, char *argv[]) case CMD_SERVER: gpgme_server (>); 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; } - gpgme_release (gt.ctx); + if (needgt) + gpgme_release (gt.ctx); #ifdef HAVE_W32CE_SYSTEM /* Give the buggy ssh server time to flush the output buffers. */ -- cgit v1.2.3 From 157c8be183153ff588f98874a3205aa483d0fd23 Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Thu, 9 Jul 2015 17:11:33 +0200 Subject: build: ignore scissor line for the commit-msg hook * build-aux/git-hooks/commit-msg: Stop processing more lines when the scissor line is encountered. -- This allows the command `git commit -v` to work even if the code is longer than 72 characters. Note that comments are already ignored by the previous line. Signed-off-by: Peter Wu --- build-aux/git-hooks/commit-msg | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/build-aux/git-hooks/commit-msg b/build-aux/git-hooks/commit-msg index 5a697c7a..3ca918b2 100755 --- a/build-aux/git-hooks/commit-msg +++ b/build-aux/git-hooks/commit-msg @@ -86,11 +86,17 @@ sub check_msg($$) 2 <= @line && length $line[1] and return 'second line must be empty'; + # See git-commit(1), this is the --cleanup=scissors option. Everything + # after and including this line gets ignored. + my $marker = '# ------------------------ >8 ------------------------'; + # Limit line length to allow for the ChangeLog's leading TAB. foreach my $line (@line) { 72 < length $line && $line =~ /^[^#]/ and return 'line longer than 72 characters'; + + last if $line eq $marker; } return ''; -- cgit v1.2.3 From 08086dd6901740e155e4361212b4e9cff8a47296 Mon Sep 17 00:00:00 2001 From: Andre Heinecke Date: Thu, 2 Jul 2015 10:19:04 +0200 Subject: Add offline mode support for CMS keylisting * doc/gpgme.texi: Document offline mode. * src/context.h (gpgme_context): Add offline. * src/engine-backend.h (keylist, keylist_ext): Add engine_flags. * src/engine.c, src/engine.h (_gpgme_engine_op_keylist): Ditto. (_gpgme_engine_op_keylist_ext): Ditto. * src/engine.h (GPGME_ENGINE_FLAG_OFFLINE): New. * src/engine-gpg.c (gpg_keylist, gpg_keylist_ext): Ditto. * src/engine-gpgsm.c (gpgsm_keylist): Handle engine_flags. (gpgsm_keylist_ext): Ditto. * src/gpgme.c (gpgme_set_offline, gpgme_get_offline): New. * src/gpgme.def (gpgme_set_offline, gpgme_get_offline): New. * src/gpgme.h.in (gpgme_set_offline, gpgme_get_offline): New. * src/libgpgme.vers (gpgme_set_offline, gpgme_get_offline): New. * src/keylist.c (gpgme_op_keylist_start): Set offline flag. (gpgme_op_keylist_ext_start): Ditto. * tests/run-keylist.c (show_usage, main): Add offline argument. -- The offline engine option was introduced with gpgsm 2.1.6 it is mainly useful for a full keylisting that includes the certificate validation but does not depend on external information that could take an indefinite amount of time to collect. Signed-off-by: Andre Heinecke --- doc/gpgme.texi | 33 +++++++++++++++++++++++++++++++++ src/context.h | 3 +++ src/engine-backend.h | 6 ++++-- src/engine-gpg.c | 4 ++-- src/engine-gpgsm.c | 15 ++++++++++++--- src/engine.c | 10 ++++++---- src/engine.h | 9 +++++++-- src/gpgme.c | 24 ++++++++++++++++++++++++ src/gpgme.def | 3 +++ src/gpgme.h.in | 6 ++++++ src/keylist.c | 13 +++++++++++-- src/libgpgme.vers | 3 +++ tests/run-keylist.c | 9 +++++++++ 13 files changed, 123 insertions(+), 15 deletions(-) diff --git a/doc/gpgme.texi b/doc/gpgme.texi index 45c359d0..ef4936dd 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -189,6 +189,7 @@ Context Attributes * Crypto Engine:: Configuring the crypto engine. * ASCII Armor:: Requesting @acronym{ASCII} armored output. * Text Mode:: Choosing canonical text mode. +* Offline Mode:: Choosing offline mode. * Included Certificates:: Including a number of certificates. * Key Listing Mode:: Selecting key listing mode. * Passphrase Callback:: Getting the passphrase from the user. @@ -2285,6 +2286,7 @@ started. In fact, these references are accessed through the * Crypto Engine:: Configuring the crypto engine. * ASCII Armor:: Requesting @acronym{ASCII} armored output. * Text Mode:: Choosing canonical text mode. +* Offline Mode:: Choosing offline mode. * Included Certificates:: Including a number of certificates. * Key Listing Mode:: Selecting key listing mode. * Passphrase Callback:: Getting the passphrase from the user. @@ -2413,6 +2415,37 @@ valid pointer. @end deftypefun +@node Offline Mode +@subsection Offline Mode +@cindex context, offline mode +@cindex offline mode + +@deftypefun void gpgme_set_offline (@w{gpgme_ctx_t @var{ctx}}, @w{int @var{yes}}) +The function @code{gpgme_set_offline} specifies if offline mode +should be used. By default, offline mode is not used. + +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). + +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. + +This option may be extended in the future to completely disable +the use of dirmngr for any engine. + +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}}) +The function @code{gpgme_get_offline} returns 1 if offline +mode is enabled, and @code{0} if it is not, or if @var{ctx} is not a +valid pointer. +@end deftypefun + + @node Included Certificates @subsection Included Certificates @cindex certificates, included diff --git a/src/context.h b/src/context.h index 745ffa89..8cd86e9c 100644 --- a/src/context.h +++ b/src/context.h @@ -98,6 +98,9 @@ struct gpgme_context /* True if text mode should be used. */ unsigned int use_textmode : 1; + /* True if offline mode should be used. */ + unsigned int offline : 1; + /* Flags for keylist mode. */ gpgme_keylist_mode_t keylist_mode; diff --git a/src/engine-backend.h b/src/engine-backend.h index b3cc412a..4f4519c0 100644 --- a/src/engine-backend.h +++ b/src/engine-backend.h @@ -85,10 +85,12 @@ struct engine_ops gpgme_error_t (*import) (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray); gpgme_error_t (*keylist) (void *engine, const char *pattern, - int secret_only, gpgme_keylist_mode_t mode); + int secret_only, gpgme_keylist_mode_t mode, + int engine_flags); gpgme_error_t (*keylist_ext) (void *engine, const char *pattern[], int secret_only, int reserved, - gpgme_keylist_mode_t mode); + gpgme_keylist_mode_t mode, + int engine_flags); gpgme_error_t (*sign) (void *engine, gpgme_data_t in, gpgme_data_t out, gpgme_sig_mode_t mode, int use_armor, int use_textmode, int include_certs, diff --git a/src/engine-gpg.c b/src/engine-gpg.c index e14fd8dd..510dfd9d 100644 --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -2279,7 +2279,7 @@ gpg_keylist_build_options (engine_gpg_t gpg, int secret_only, static gpgme_error_t gpg_keylist (void *engine, const char *pattern, int secret_only, - gpgme_keylist_mode_t mode) + gpgme_keylist_mode_t mode, int engine_flags) { engine_gpg_t gpg = engine; gpgme_error_t err; @@ -2298,7 +2298,7 @@ gpg_keylist (void *engine, const char *pattern, int secret_only, static gpgme_error_t gpg_keylist_ext (void *engine, const char *pattern[], int secret_only, - int reserved, gpgme_keylist_mode_t mode) + int reserved, gpgme_keylist_mode_t mode, int engine_flags) { engine_gpg_t gpg = engine; gpgme_error_t err; diff --git a/src/engine-gpgsm.c b/src/engine-gpgsm.c index ac6c5fc6..37711574 100644 --- a/src/engine-gpgsm.c +++ b/src/engine-gpgsm.c @@ -1542,7 +1542,7 @@ gpgsm_import (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray) static gpgme_error_t gpgsm_keylist (void *engine, const char *pattern, int secret_only, - gpgme_keylist_mode_t mode) + gpgme_keylist_mode_t mode, int engine_flags) { engine_gpgsm_t gpgsm = engine; char *line; @@ -1599,6 +1599,11 @@ gpgsm_keylist (void *engine, const char *pattern, int secret_only, "OPTION with-secret=1": "OPTION with-secret=0" , NULL, NULL); + gpgsm_assuan_simple_command (gpgsm->assuan_ctx, + (engine_flags & GPGME_ENGINE_FLAG_OFFLINE)? + "OPTION offline=1": + "OPTION offline=0" , + NULL, NULL); /* Length is "LISTSECRETKEYS " + p + '\0'. */ @@ -1629,7 +1634,7 @@ gpgsm_keylist (void *engine, const char *pattern, int secret_only, static gpgme_error_t gpgsm_keylist_ext (void *engine, const char *pattern[], int secret_only, - int reserved, gpgme_keylist_mode_t mode) + int reserved, gpgme_keylist_mode_t mode, int engine_flags) { engine_gpgsm_t gpgsm = engine; char *line; @@ -1669,7 +1674,11 @@ gpgsm_keylist_ext (void *engine, const char *pattern[], int secret_only, "OPTION with-secret=1": "OPTION with-secret=0" , NULL, NULL); - + gpgsm_assuan_simple_command (gpgsm->assuan_ctx, + (engine_flags & GPGME_ENGINE_FLAG_OFFLINE)? + "OPTION offline=1": + "OPTION offline=0" , + NULL, NULL); if (pattern && *pattern) { diff --git a/src/engine.c b/src/engine.c index ff015c00..8e84da95 100644 --- a/src/engine.c +++ b/src/engine.c @@ -726,7 +726,8 @@ _gpgme_engine_op_import (engine_t engine, gpgme_data_t keydata, gpgme_error_t _gpgme_engine_op_keylist (engine_t engine, const char *pattern, - int secret_only, gpgme_keylist_mode_t mode) + int secret_only, gpgme_keylist_mode_t mode, + int engine_flags) { if (!engine) return gpg_error (GPG_ERR_INV_VALUE); @@ -734,14 +735,15 @@ _gpgme_engine_op_keylist (engine_t engine, const char *pattern, if (!engine->ops->keylist) return gpg_error (GPG_ERR_NOT_IMPLEMENTED); - return (*engine->ops->keylist) (engine->engine, pattern, secret_only, mode); + return (*engine->ops->keylist) (engine->engine, pattern, secret_only, mode, + engine_flags); } gpgme_error_t _gpgme_engine_op_keylist_ext (engine_t engine, const char *pattern[], int secret_only, int reserved, - gpgme_keylist_mode_t mode) + gpgme_keylist_mode_t mode, int engine_flags) { if (!engine) return gpg_error (GPG_ERR_INV_VALUE); @@ -750,7 +752,7 @@ _gpgme_engine_op_keylist_ext (engine_t engine, const char *pattern[], return gpg_error (GPG_ERR_NOT_IMPLEMENTED); return (*engine->ops->keylist_ext) (engine->engine, pattern, secret_only, - reserved, mode); + reserved, mode, engine_flags); } diff --git a/src/engine.h b/src/engine.h index bbf009d6..56fcc420 100644 --- a/src/engine.h +++ b/src/engine.h @@ -113,12 +113,14 @@ gpgme_error_t _gpgme_engine_op_import (engine_t engine, gpgme_error_t _gpgme_engine_op_keylist (engine_t engine, const char *pattern, int secret_only, - gpgme_keylist_mode_t mode); + gpgme_keylist_mode_t mode, + int engine_flags); gpgme_error_t _gpgme_engine_op_keylist_ext (engine_t engine, const char *pattern[], int secret_only, int reserved, - gpgme_keylist_mode_t mode); + gpgme_keylist_mode_t mode, + int engine_flags); gpgme_error_t _gpgme_engine_op_sign (engine_t engine, gpgme_data_t in, gpgme_data_t out, gpgme_sig_mode_t mode, int use_armor, int use_textmode, @@ -170,5 +172,8 @@ gpgme_error_t _gpgme_engine_op_spawn (engine_t engine, gpgme_data_t dataerr, unsigned int flags); +/* The available engine option flags. */ +#define GPGME_ENGINE_FLAG_OFFLINE 1 + #endif /* ENGINE_H */ diff --git a/src/gpgme.c b/src/gpgme.c index 628cdaee..c24b6200 100644 --- a/src/gpgme.c +++ b/src/gpgme.c @@ -472,6 +472,30 @@ gpgme_get_textmode (gpgme_ctx_t ctx) } +/* Enable offline mode for this context. In offline mode dirmngr + will be disabled. */ +void +gpgme_set_offline (gpgme_ctx_t ctx, int offline) +{ + TRACE2 (DEBUG_CTX, "gpgme_set_offline", ctx, "offline=%i (%s)", + offline, offline ? "yes" : "no"); + + if (!ctx) + return; + + ctx->offline = offline; +} + +/* Return the state of the offline flag. */ +int +gpgme_get_offline (gpgme_ctx_t ctx) +{ + TRACE2 (DEBUG_CTX, "gpgme_get_offline", ctx, "ctx->offline=%i (%s)", + ctx->offline, ctx->offline ? "yes" : "no"); + return ctx->offline; +} + + /* Set the number of certifications to include in an S/MIME message. The default is GPGME_INCLUDE_CERTS_DEFAULT. -1 means all certs, and -2 means all certs except the root cert. */ diff --git a/src/gpgme.def b/src/gpgme.def index dc189484..cf167b4f 100644 --- a/src/gpgme.def +++ b/src/gpgme.def @@ -217,5 +217,8 @@ EXPORTS gpgme_op_spawn_start @163 gpgme_op_spawn @164 + + gpgme_set_offline @165 + gpgme_get_offline @166 ; END diff --git a/src/gpgme.h.in b/src/gpgme.h.in index 15ed8037..099cc8a5 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -887,6 +887,12 @@ void gpgme_set_textmode (gpgme_ctx_t ctx, int yes); /* Return non-zero if text mode is set in CTX. */ int gpgme_get_textmode (gpgme_ctx_t ctx); +/* If YES is non-zero, enable offline mode in CTX, disable it otherwise. */ +void gpgme_set_offline (gpgme_ctx_t ctx, int yes); + +/* Return non-zero if offline mode is set in CTX. */ +int gpgme_get_offline (gpgme_ctx_t ctx); + /* Use whatever the default of the backend crypto engine is. */ #define GPGME_INCLUDE_CERTS_DEFAULT -256 diff --git a/src/keylist.c b/src/keylist.c index 36ee3eaa..fcf574fc 100644 --- a/src/keylist.c +++ b/src/keylist.c @@ -889,6 +889,7 @@ gpgme_op_keylist_start (gpgme_ctx_t ctx, const char *pattern, int secret_only) gpgme_error_t err; void *hook; op_data_t opd; + int flags = 0; TRACE_BEG2 (DEBUG_CTX, "gpgme_op_keylist_start", ctx, "pattern=%s, secret_only=%i", pattern, secret_only); @@ -913,8 +914,11 @@ gpgme_op_keylist_start (gpgme_ctx_t ctx, const char *pattern, int secret_only) if (err) return TRACE_ERR (err); + if (ctx->offline) + flags |= GPGME_ENGINE_FLAG_OFFLINE; + err = _gpgme_engine_op_keylist (ctx->engine, pattern, secret_only, - ctx->keylist_mode); + ctx->keylist_mode, flags); return TRACE_ERR (err); } @@ -929,6 +933,7 @@ gpgme_op_keylist_ext_start (gpgme_ctx_t ctx, const char *pattern[], gpgme_error_t err; void *hook; op_data_t opd; + int flags = 0; TRACE_BEG2 (DEBUG_CTX, "gpgme_op_keylist_ext_start", ctx, "secret_only=%i, reserved=0x%x", secret_only, reserved); @@ -952,8 +957,12 @@ gpgme_op_keylist_ext_start (gpgme_ctx_t ctx, const char *pattern[], if (err) return TRACE_ERR (err); + if (ctx->offline) + flags |= GPGME_ENGINE_FLAG_OFFLINE; + err = _gpgme_engine_op_keylist_ext (ctx->engine, pattern, secret_only, - reserved, ctx->keylist_mode); + reserved, ctx->keylist_mode, + flags); return TRACE_ERR (err); } diff --git a/src/libgpgme.vers b/src/libgpgme.vers index 39663c1c..fc2920f8 100644 --- a/src/libgpgme.vers +++ b/src/libgpgme.vers @@ -92,6 +92,9 @@ GPGME_1.1 { gpgme_op_spawn_start; gpgme_op_spawn; + + gpgme_set_offline; + gpgme_get_offline; }; diff --git a/tests/run-keylist.c b/tests/run-keylist.c index 07c6fa18..8abdf43d 100644 --- a/tests/run-keylist.c +++ b/tests/run-keylist.c @@ -53,6 +53,7 @@ show_usage (int ex) " --ephemeral use GPGME_KEYLIST_MODE_EPHEMERAL\n" " --validate use GPGME_KEYLIST_MODE_VALIDATE\n" " --import import all keys\n" + " --offline use offline mode\n" , stderr); exit (ex); } @@ -72,6 +73,7 @@ main (int argc, char **argv) int keyidx = 0; gpgme_protocol_t protocol = GPGME_PROTOCOL_OpenPGP; int only_secret = 0; + int offline = 0; if (argc) { argc--; argv++; } @@ -141,6 +143,11 @@ main (int argc, char **argv) import = 1; argc--; argv++; } + else if (!strcmp (*argv, "--offline")) + { + offline = 1; + argc--; argv++; + } else if (!strncmp (*argv, "--", 2)) show_usage (1); @@ -157,6 +164,8 @@ main (int argc, char **argv) gpgme_set_keylist_mode (ctx, mode); + gpgme_set_offline (ctx, offline); + err = gpgme_op_keylist_start (ctx, argc? argv[0]:NULL, only_secret); fail_if_err (err); -- cgit v1.2.3 From 8f28e3caf95d7bc99e9271bfc2b44080166af31f Mon Sep 17 00:00:00 2001 From: Ben Kibbey Date: Mon, 10 Aug 2015 21:23:02 -0400 Subject: Check the return value when starting gpg. * src/engine-gpg.c (gpg_decrypt, gpg_delete, gpg_passwd): Check return value of start(). --- src/engine-gpg.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/engine-gpg.c b/src/engine-gpg.c index 510dfd9d..c3e36aeb 100644 --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -1456,7 +1456,7 @@ gpg_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain) err = add_data (gpg, ciph, -1, 0); if (!err) - start (gpg); + err = start (gpg); return err; } @@ -1479,7 +1479,7 @@ gpg_delete (void *engine, gpgme_key_t key, int allow_secret) } if (!err) - start (gpg); + err = start (gpg); return err; } @@ -1497,7 +1497,7 @@ gpg_passwd (void *engine, gpgme_key_t key, unsigned int flags) if (!err) err = add_arg (gpg, key->subkeys->fpr); if (!err) - start (gpg); + err = start (gpg); return err; } -- cgit v1.2.3 From e07d38f5f9f3b94e403f1265ff7fd3d7009dd557 Mon Sep 17 00:00:00 2001 From: Ben Kibbey Date: Wed, 12 Aug 2015 06:46:43 -0400 Subject: Also check the return code in gpg_sign(). * src/engine-gpg.c (gpg_sign): Check return value from start(). --- src/engine-gpg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine-gpg.c b/src/engine-gpg.c index c3e36aeb..d1385926 100644 --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -2364,7 +2364,7 @@ gpg_sign (void *engine, gpgme_data_t in, gpgme_data_t out, err = add_data (gpg, out, 1, 1); if (!err) - start (gpg); + err = start (gpg); return err; } -- cgit v1.2.3 From 2b6ae3dadf4432f7a72fd119144b835f7b1adcc4 Mon Sep 17 00:00:00 2001 From: Ben Kibbey Date: Tue, 14 Apr 2015 18:39:26 -0400 Subject: Make use of user passphrase handler during genkey. * src/genkey.c (genkey_start): set engine passphrase command handler. -- This allows for inquiring a new passphrase during key generation rather than requiring a pinentry. Needs a patch to gnupg to make use of --command-fd with --gen-key. --- src/genkey.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/genkey.c b/src/genkey.c index fd6685ef..17009bde 100644 --- a/src/genkey.c +++ b/src/genkey.c @@ -186,6 +186,14 @@ genkey_start (gpgme_ctx_t ctx, int synchronous, const char *parms, _gpgme_engine_set_status_handler (ctx->engine, genkey_status_handler, ctx); + if (ctx->passphrase_cb) + { + err = _gpgme_engine_set_command_handler + (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL); + if (err) + return err; + } + return _gpgme_engine_op_genkey (ctx->engine, opd->key_parameter, ctx->use_armor, pubkey, seckey); } -- cgit v1.2.3 From 4fadcf06ec8b0ebfb05c7622dbc3b73fd3c1bad9 Mon Sep 17 00:00:00 2001 From: Ben Kibbey Date: Thu, 16 Apr 2015 20:23:38 -0400 Subject: Add gpgme_set/get_status_cb(). * src/gpgme.h.in (gpgme_set_status_cb): New. (gpgme_get_status_cb): New. (gpgme_status_cb_t): New. * src/gpgme.c (gpgme_set_status_cb): New. (gpgme_get_status_cb): New. * src/context.h (status_cb): New. (status_cb_value): New. * src/gpgme.def: Export new symbols. * src/libgpgme.vers: Ditto. * doc/gpgme.texi: Document these new functions. -- This callback function is used to forward status messages from gpg back to the client. --- doc/gpgme.texi | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/context.h | 4 ++++ src/gpgme.c | 31 +++++++++++++++++++++++++++++++ src/gpgme.def | 3 +++ src/gpgme.h.in | 15 +++++++++++++++ src/libgpgme.vers | 3 +++ 6 files changed, 100 insertions(+) diff --git a/doc/gpgme.texi b/doc/gpgme.texi index ef4936dd..bce6aefd 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -194,6 +194,7 @@ Context Attributes * Key Listing Mode:: Selecting key listing mode. * Passphrase Callback:: Getting the passphrase from the user. * Progress Meter Callback:: Being informed about the progress. +* Status Message Callback:: Status messages received from gpg. * Locale:: Setting the locale of a context. Key Management @@ -2291,6 +2292,7 @@ started. In fact, these references are accessed through the * Key Listing Mode:: Selecting key listing mode. * Passphrase Callback:: Getting the passphrase from the user. * Progress Meter Callback:: Being informed about the progress. +* Status Message Callback:: Status messages received from gpg. * Locale:: Setting the locale of a context. @end menu @@ -2675,6 +2677,48 @@ the corresponding value will not be returned. @end deftypefun +@node Status Message Callback +@subsection Status Message Callback +@cindex callback, status message +@cindex status message callback + +@deftp {Data type} {gpgme_error_t (*gpgme_status_cb_t)(void *@var{hook}, const char *@var{keyword}, const char *@var{args})} +@tindex gpgme_status_cb_t +The @code{gpgme_status_cb_t} type is the type of function usable as +a status message callback function. + +The argument @var{keyword} is the name of the status message while the +@var{args} argument contains any arguments for the status message. + +The status message may have come from gpg or libgpgme. + +If an error occurs, return the corresponding @code{gpgme_error_t} +value. Otherwise, return @code{0}. +@end deftp + +@deftypefun void gpgme_set_status_cb (@w{gpgme_ctx_t @var{ctx}}, @w{gpgme_status_cb_t @var{statusfunc}}, @w{void *@var{hook_value}}) +The function @code{gpgme_set_status_cb} sets the function that is used when a +status message is received from gpg to @var{statusfunc}. The function +@var{statusfunc} needs to implemented by the user, and whenever it is called, +it is called with its first argument being @var{hook_value}. By default, no +status message callback function is set. + +The user can disable the use of a status message callback function by calling +@code{gpgme_set_status_cb} with @var{statusfunc} being @code{NULL}. +@end deftypefun + +@deftypefun void gpgme_get_status_cb (@w{gpgme_ctx_t @var{ctx}}, @w{gpgme_status_cb_t *@var{statusfunc}}, @w{void **@var{hook_value}}) +The function @code{gpgme_get_status_cb} returns the function that is used to +process status messages from gpg in @var{*statusfunc}, and the first argument +for this function in @var{*hook_value}. If no status message callback is set, +or @var{ctx} is not a valid pointer, @code{NULL} is returned in both +variables. + +@var{statusfunc} or @var{hook_value} can be @code{NULL}. In this case, +the corresponding value will not be returned. +@end deftypefun + + @node Locale @subsection Locale @cindex locale, default diff --git a/src/context.h b/src/context.h index 8cd86e9c..757d9b42 100644 --- a/src/context.h +++ b/src/context.h @@ -135,6 +135,10 @@ struct gpgme_context gpgme_progress_cb_t progress_cb; void *progress_cb_value; + /* The user provided status callback and its hook value. */ + gpgme_status_cb_t status_cb; + void *status_cb_value; + /* A list of file descriptors in active use by the current operation. */ struct fd_table fdt; diff --git a/src/gpgme.c b/src/gpgme.c index c24b6200..9c09827e 100644 --- a/src/gpgme.c +++ b/src/gpgme.c @@ -656,6 +656,37 @@ gpgme_get_progress_cb (gpgme_ctx_t ctx, gpgme_progress_cb_t *r_cb, } +/* This function sets a callback function to be used as a status + message forwarder. */ +void +gpgme_set_status_cb (gpgme_ctx_t ctx, gpgme_status_cb_t cb, void *cb_value) +{ + TRACE2 (DEBUG_CTX, "gpgme_set_status_cb", ctx, "status_cb=%p/%p", + cb, cb_value); + + if (!ctx) + return; + + ctx->status_cb = cb; + ctx->status_cb_value = cb_value; +} + + +/* This function returns the callback function to be used as a + status message forwarder. */ +void +gpgme_get_status_cb (gpgme_ctx_t ctx, gpgme_status_cb_t *r_cb, + void **r_cb_value) +{ + TRACE2 (DEBUG_CTX, "gpgme_get_status_cb", ctx, "ctx->status_cb=%p/%p", + ctx->status_cb, ctx->status_cb_value); + if (r_cb) + *r_cb = ctx->status_cb; + if (r_cb_value) + *r_cb_value = ctx->status_cb_value; +} + + /* Set the I/O callback functions for CTX to IO_CBS. */ void gpgme_set_io_cbs (gpgme_ctx_t ctx, gpgme_io_cbs_t io_cbs) diff --git a/src/gpgme.def b/src/gpgme.def index cf167b4f..a3f5fb4a 100644 --- a/src/gpgme.def +++ b/src/gpgme.def @@ -220,5 +220,8 @@ EXPORTS gpgme_set_offline @165 gpgme_get_offline @166 + + gpgme_set_status_cb @167 + gpgme_get_status_cb @168 ; END diff --git a/src/gpgme.h.in b/src/gpgme.h.in index 099cc8a5..ffcc7bac 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -839,6 +839,11 @@ typedef gpgme_error_t (*gpgme_passphrase_cb_t) (void *hook, typedef void (*gpgme_progress_cb_t) (void *opaque, const char *what, int type, int current, int total); +/* Status messages from gpg. */ +typedef gpgme_error_t (*gpgme_status_cb_t) (void *opaque, const char *keyword, + const char *args); + + /* Interact with the user about an edit operation. */ typedef gpgme_error_t (*gpgme_edit_cb_t) (void *opaque, gpgme_status_code_t status, @@ -936,6 +941,16 @@ void gpgme_set_progress_cb (gpgme_ctx_t c, gpgme_progress_cb_t cb, 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 thes 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. */ +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. */ gpgme_error_t gpgme_set_locale (gpgme_ctx_t ctx, int category, diff --git a/src/libgpgme.vers b/src/libgpgme.vers index fc2920f8..6687571f 100644 --- a/src/libgpgme.vers +++ b/src/libgpgme.vers @@ -95,6 +95,9 @@ GPGME_1.1 { gpgme_set_offline; gpgme_get_offline; + + gpgme_set_status_cb; + gpgme_get_status_cb; }; -- cgit v1.2.3 From 6dd24c3c6133ec54f75abd056191a8027fe01de0 Mon Sep 17 00:00:00 2001 From: Ben Kibbey Date: Thu, 16 Apr 2015 21:05:01 -0400 Subject: Parse the INQUIRE_MAXLEN status message. * src/gpgme.h.in: (gpgme_status_code_t): Add INQUIRE_MAXLEN. * src/status-table.c (status_table_s): Ditto. * src/genkey.c (genkey_status_handler): Parse INQUIRE_MAXLEN. * src/decrypt.c (_gpgme_decrypt_status_handler): Ditto. * src/sign.c (_gpgme_sign_status_handler): Ditto. This status message informs the client of the maximum length of an inquired line. It is sent from gpg and forwarded to the client via gpgme_status_cb_t. --- src/decrypt.c | 10 ++++++++++ src/genkey.c | 9 +++++++++ src/gpgme.h.in | 3 ++- src/sign.c | 5 +++++ src/status-table.c | 1 + 5 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/decrypt.c b/src/decrypt.c index 47420601..4fd92c61 100644 --- a/src/decrypt.c +++ b/src/decrypt.c @@ -291,6 +291,16 @@ _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code, err = _gpgme_parse_plaintext (args, &opd->result.file_name); if (err) return err; + break; + + case GPGME_STATUS_INQUIRE_MAXLEN: + if (ctx->status_cb) + { + err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN", args); + if (err) + return err; + } + break; default: break; diff --git a/src/genkey.c b/src/genkey.c index 17009bde..18765dde 100644 --- a/src/genkey.c +++ b/src/genkey.c @@ -124,6 +124,15 @@ genkey_status_handler (void *priv, gpgme_status_code_t code, char *args) return gpg_error (GPG_ERR_GENERAL); break; + case GPGME_STATUS_INQUIRE_MAXLEN: + if (ctx->status_cb) + { + err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN", args); + if (err) + return err; + } + break; + default: break; } diff --git a/src/gpgme.h.in b/src/gpgme.h.in index ffcc7bac..8255e637 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -544,7 +544,8 @@ typedef enum GPGME_STATUS_PINENTRY_LAUNCHED = 88, GPGME_STATUS_ATTRIBUTE = 89, GPGME_STATUS_BEGIN_SIGNING = 90, - GPGME_STATUS_KEY_NOT_CREATED = 91 + GPGME_STATUS_KEY_NOT_CREATED = 91, + GPGME_STATUS_INQUIRE_MAXLEN = 92 } gpgme_status_code_t; diff --git a/src/sign.c b/src/sign.c index ffbde569..9e22fdb8 100644 --- a/src/sign.c +++ b/src/sign.c @@ -338,6 +338,11 @@ _gpgme_sign_status_handler (void *priv, gpgme_status_code_t code, char *args) err = gpg_error (GPG_ERR_GENERAL); break; + case GPGME_STATUS_INQUIRE_MAXLEN: + if (ctx->status_cb) + err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN", args); + break; + default: break; } diff --git a/src/status-table.c b/src/status-table.c index b9369977..c85fa951 100644 --- a/src/status-table.c +++ b/src/status-table.c @@ -80,6 +80,7 @@ static struct status_table_s status_table[] = { "IMPORT_PROBLEM", GPGME_STATUS_IMPORT_PROBLEM }, { "IMPORT_RES", GPGME_STATUS_IMPORT_RES }, { "IMPORTED", GPGME_STATUS_IMPORTED }, + { "INQUIRE_MAXLEN", GPGME_STATUS_INQUIRE_MAXLEN }, { "INV_RECP", GPGME_STATUS_INV_RECP }, { "INV_SGNR", GPGME_STATUS_INV_SGNR }, { "KEY_CREATED", GPGME_STATUS_KEY_CREATED }, -- cgit v1.2.3 From 70b3e5964ea0592bd09d1877d720b2c63f501970 Mon Sep 17 00:00:00 2001 From: Ben Kibbey Date: Sat, 15 Aug 2015 16:58:04 -0400 Subject: Fix gpgme_{get,set}_status_cb to match documentation. * doc/gpgme.texi: Minor fixes. * src/gpgme.c (gpgme_get_status_cb): Set return variables to NULL and check for a valid ctx pointer. --- doc/gpgme.texi | 11 +++-------- src/gpgme.c | 12 +++++++++++- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/doc/gpgme.texi b/doc/gpgme.texi index bce6aefd..010b914d 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -2690,8 +2690,6 @@ a status message callback function. The argument @var{keyword} is the name of the status message while the @var{args} argument contains any arguments for the status message. -The status message may have come from gpg or libgpgme. - If an error occurs, return the corresponding @code{gpgme_error_t} value. Otherwise, return @code{0}. @end deftp @@ -2699,9 +2697,9 @@ value. Otherwise, return @code{0}. @deftypefun void gpgme_set_status_cb (@w{gpgme_ctx_t @var{ctx}}, @w{gpgme_status_cb_t @var{statusfunc}}, @w{void *@var{hook_value}}) The function @code{gpgme_set_status_cb} sets the function that is used when a status message is received from gpg to @var{statusfunc}. The function -@var{statusfunc} needs to implemented by the user, and whenever it is called, -it is called with its first argument being @var{hook_value}. By default, no -status message callback function is set. +@var{statusfunc} needs to be implemented by the user, and whenever it is +called, it is called with its first argument being @var{hook_value}. By +default, no status message callback function is set. The user can disable the use of a status message callback function by calling @code{gpgme_set_status_cb} with @var{statusfunc} being @code{NULL}. @@ -2713,9 +2711,6 @@ process status messages from gpg in @var{*statusfunc}, and the first argument for this function in @var{*hook_value}. If no status message callback is set, or @var{ctx} is not a valid pointer, @code{NULL} is returned in both variables. - -@var{statusfunc} or @var{hook_value} can be @code{NULL}. In this case, -the corresponding value will not be returned. @end deftypefun diff --git a/src/gpgme.c b/src/gpgme.c index 9c09827e..0cf999a7 100644 --- a/src/gpgme.c +++ b/src/gpgme.c @@ -679,7 +679,17 @@ gpgme_get_status_cb (gpgme_ctx_t ctx, gpgme_status_cb_t *r_cb, void **r_cb_value) { TRACE2 (DEBUG_CTX, "gpgme_get_status_cb", ctx, "ctx->status_cb=%p/%p", - ctx->status_cb, ctx->status_cb_value); + ctx ? ctx->status_cb : NULL, ctx ? ctx->status_cb_value : NULL); + + if (r_cb) + *r_cb = NULL; + + if (r_cb_value) + *r_cb_value = NULL; + + if (!ctx || !ctx->status_cb) + return; + if (r_cb) *r_cb = ctx->status_cb; if (r_cb_value) -- cgit v1.2.3 From ccbaccbf2e0ba582d181b9ee4d8543d7c1248b2c Mon Sep 17 00:00:00 2001 From: Ben Kibbey Date: Sun, 16 Aug 2015 12:29:41 -0400 Subject: Parse INQUIRE_MAXLEN in the passphrase callback. * src/passphrase.c (_gpgme_passphrase_status_handler): Parse GPGME_STATUS_INQUIRE_MAXLEN. * src/passphrase.c (_gpgme_passphrase_command_handler): Send the INQUIRE_MAXLEN status message. -- Fixes passing this status message along when decrypting symmetric data from gpg. --- src/passphrase.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/passphrase.c b/src/passphrase.c index 00e9d999..63ab31e6 100644 --- a/src/passphrase.c +++ b/src/passphrase.c @@ -41,6 +41,7 @@ typedef struct char *uid_hint; char *passphrase_info; int bad_passphrase; + char *maxlen; } *op_data_t; @@ -53,6 +54,7 @@ release_op_data (void *hook) free (opd->passphrase_info); if (opd->uid_hint) free (opd->uid_hint); + free (opd->maxlen); } @@ -73,6 +75,11 @@ _gpgme_passphrase_status_handler (void *priv, gpgme_status_code_t code, switch (code) { + case GPGME_STATUS_INQUIRE_MAXLEN: + free (opd->maxlen); + if (!(opd->maxlen = strdup (args))) + return gpg_error_from_syserror (); + break; case GPGME_STATUS_USERID_HINT: if (opd->uid_hint) free (opd->uid_hint); @@ -141,9 +148,14 @@ _gpgme_passphrase_command_handler (void *priv, gpgme_status_code_t code, if (processed) *processed = 1; - err = ctx->passphrase_cb (ctx->passphrase_cb_value, - opd->uid_hint, opd->passphrase_info, - opd->bad_passphrase, fd); + if (ctx->status_cb && opd->maxlen) + err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN", + opd->maxlen); + + if (!err) + err = ctx->passphrase_cb (ctx->passphrase_cb_value, + opd->uid_hint, opd->passphrase_info, + opd->bad_passphrase, fd); /* Reset bad passphrase flag, in case it is correct now. */ opd->bad_passphrase = 0; -- cgit v1.2.3 From 2b632bbb78eee2b94c122f66d171a7c80e9c4fb0 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 24 Aug 2015 12:41:24 +0200 Subject: Add an export secret key feature. * src/gpgme.h.in (GPGME_EXPORT_MODE_SECRET): New. (GPGME_EXPORT_MODE_RAW): New. (GPGME_EXPORT_MODE_PKCS12): New. * src/export.c (export_start, export_ext_start): Allow new flags. * src/engine-gpg.c (export_common): Support secret key export. * src/engine-gpgsm.c (gpgsm_export, gpgsm_export_ext): Ditto. * src/gpgme-tool.c (cmd_export): Add options --secret, --raw, and --pkcs12. * tests/run-export.c (main): Likewise. -- Note that exporting secret X.509 keys requires GnuPG 2.1.8. Signed-off-by: Werner Koch --- doc/gpgme.texi | 15 +++++++++++++++ src/engine-gpg.c | 8 ++++++-- src/engine-gpgsm.c | 33 ++++++++++++++++++++++----------- src/export.c | 35 +++++++++++++++++++++++++++++++++-- src/gpgme-tool.c | 8 +++++++- src/gpgme.h.in | 3 +++ tests/run-export.c | 41 +++++++++++++++++++++++++++++++++++++---- 7 files changed, 123 insertions(+), 20 deletions(-) diff --git a/doc/gpgme.texi b/doc/gpgme.texi index 010b914d..20e1912b 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -3700,6 +3700,21 @@ keys it removes all signatures except for the latest self-signatures. For X.509 keys it has no effect. +@item GPGME_EXPORT_MODE_SECRET +Instead of exporting the public key, the secret key is exported. This +may not be combined with @code{GPGME_EXPORT_MODE_EXTERN}. For X.509 +the export format is PKCS#8. + +@item GPGME_EXPORT_MODE_RAW +If this flag is used with @code{GPGME_EXPORT_MODE_SECRET} for an X.509 +key the export format will be changed to PKCS#1. This flag may not be +used with OpenPGP. + +@item GPGME_EXPORT_MODE_PKCS12 +If this flag is used with @code{GPGME_EXPORT_MODE_SECRET} for an X.509 +key the export format will be changed to PKCS#12 which also includes +the certificate. This flag may not be used with OpenPGP. + @end table diff --git a/src/engine-gpg.c b/src/engine-gpg.c index d1385926..ffae2fe4 100644 --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -1793,7 +1793,8 @@ export_common (engine_gpg_t gpg, gpgme_export_mode_t mode, gpgme_error_t err = 0; if ((mode & ~(GPGME_EXPORT_MODE_EXTERN - |GPGME_EXPORT_MODE_MINIMAL))) + |GPGME_EXPORT_MODE_MINIMAL + |GPGME_EXPORT_MODE_SECRET))) return gpg_error (GPG_ERR_NOT_SUPPORTED); if ((mode & GPGME_EXPORT_MODE_MINIMAL)) @@ -1807,7 +1808,10 @@ export_common (engine_gpg_t gpg, gpgme_export_mode_t mode, } else { - err = add_arg (gpg, "--export"); + if ((mode & GPGME_EXPORT_MODE_SECRET)) + err = add_arg (gpg, "--export-secret-keys"); + else + err = add_arg (gpg, "--export"); if (!err && use_armor) err = add_arg (gpg, "--armor"); if (!err) diff --git a/src/engine-gpgsm.c b/src/engine-gpgsm.c index 37711574..24d3b2a8 100644 --- a/src/engine-gpgsm.c +++ b/src/engine-gpgsm.c @@ -1289,17 +1289,23 @@ gpgsm_export (void *engine, const char *pattern, gpgme_export_mode_t mode, if (!gpgsm) return gpg_error (GPG_ERR_INV_VALUE); - if (mode) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - if (!pattern) pattern = ""; - cmd = malloc (7 + strlen (pattern) + 1); + cmd = malloc (7 + 9 + 9 + strlen (pattern) + 1); if (!cmd) return gpg_error_from_syserror (); + strcpy (cmd, "EXPORT "); - strcpy (&cmd[7], pattern); + if ((mode & GPGME_EXPORT_MODE_SECRET)) + { + strcat (cmd, "--secret "); + if ((mode & GPGME_EXPORT_MODE_RAW)) + strcat (cmd, "--raw "); + else if ((mode & GPGME_EXPORT_MODE_PKCS12)) + strcat (cmd, "--pkcs12 "); + } + strcat (cmd, pattern); gpgsm->output_cb.data = keydata; err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor" @@ -1323,16 +1329,13 @@ gpgsm_export_ext (void *engine, const char *pattern[], gpgme_export_mode_t mode, engine_gpgsm_t gpgsm = engine; gpgme_error_t err = 0; char *line; - /* Length is "EXPORT " + p + '\0'. */ - int length = 7 + 1; + /* Length is "EXPORT " + "--secret " + "--pkcs12 " + p + '\0'. */ + int length = 7 + 9 + 9 + 1; char *linep; if (!gpgsm) return gpg_error (GPG_ERR_INV_VALUE); - if (mode) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - if (pattern && *pattern) { const char **pat = pattern; @@ -1357,7 +1360,15 @@ gpgsm_export_ext (void *engine, const char *pattern[], gpgme_export_mode_t mode, return gpg_error_from_syserror (); strcpy (line, "EXPORT "); - linep = &line[7]; + if ((mode & GPGME_EXPORT_MODE_SECRET)) + { + strcat (line, "--secret "); + if ((mode & GPGME_EXPORT_MODE_RAW)) + strcat (line, "--raw "); + else if ((mode & GPGME_EXPORT_MODE_PKCS12)) + strcat (line, "--pkcs12 "); + } + linep = &line[strlen (line)]; if (pattern && *pattern) { diff --git a/src/export.c b/src/export.c index 8930aa68..a29fbde8 100644 --- a/src/export.c +++ b/src/export.c @@ -120,9 +120,24 @@ export_start (gpgme_ctx_t ctx, int synchronous, const char *pattern, op_data_t opd; if ((mode & ~(GPGME_EXPORT_MODE_EXTERN - |GPGME_EXPORT_MODE_MINIMAL))) + |GPGME_EXPORT_MODE_MINIMAL + |GPGME_EXPORT_MODE_SECRET + |GPGME_EXPORT_MODE_RAW + |GPGME_EXPORT_MODE_PKCS12))) return gpg_error (GPG_ERR_INV_VALUE); /* Invalid flags in MODE. */ + if ((mode & GPGME_EXPORT_MODE_SECRET)) + { + if ((mode & GPGME_EXPORT_MODE_EXTERN)) + return gpg_error (GPG_ERR_INV_FLAG); /* Combination not allowed. */ + if ((mode & GPGME_EXPORT_MODE_RAW) + && (mode & GPGME_EXPORT_MODE_PKCS12)) + return gpg_error (GPG_ERR_INV_FLAG); /* Combination not allowed. */ + + if (ctx->protocol != GPGME_PROTOCOL_CMS + && (mode & (GPGME_EXPORT_MODE_RAW|GPGME_EXPORT_MODE_PKCS12))) + return gpg_error (GPG_ERR_INV_FLAG); /* Only supported for X.509. */ + } if ((mode & GPGME_EXPORT_MODE_EXTERN)) { @@ -199,9 +214,25 @@ export_ext_start (gpgme_ctx_t ctx, int synchronous, const char *pattern[], op_data_t opd; if ((mode & ~(GPGME_EXPORT_MODE_EXTERN - |GPGME_EXPORT_MODE_MINIMAL))) + |GPGME_EXPORT_MODE_MINIMAL + |GPGME_EXPORT_MODE_SECRET + |GPGME_EXPORT_MODE_RAW + |GPGME_EXPORT_MODE_PKCS12))) return gpg_error (GPG_ERR_INV_VALUE); /* Invalid flags in MODE. */ + if ((mode & GPGME_EXPORT_MODE_SECRET)) + { + if ((mode & GPGME_EXPORT_MODE_EXTERN)) + return gpg_error (GPG_ERR_INV_FLAG); /* Combination not allowed. */ + if ((mode & GPGME_EXPORT_MODE_RAW) + && (mode & GPGME_EXPORT_MODE_PKCS12)) + return gpg_error (GPG_ERR_INV_FLAG); /* Combination not allowed. */ + + if (ctx->protocol != GPGME_PROTOCOL_CMS + && (mode & (GPGME_EXPORT_MODE_RAW|GPGME_EXPORT_MODE_PKCS12))) + return gpg_error (GPG_ERR_INV_FLAG); /* Only supported for X.509. */ + } + if ((mode & GPGME_EXPORT_MODE_EXTERN)) { if (keydata) diff --git a/src/gpgme-tool.c b/src/gpgme-tool.c index 94d11248..e5e57073 100644 --- a/src/gpgme-tool.c +++ b/src/gpgme-tool.c @@ -3054,7 +3054,7 @@ cmd_import (assuan_context_t ctx, char *line) static const char hlp_export[] = - "EXPORT [--extern] [--minimal] []\n" + "EXPORT [--extern] [--minimal] [--secret [--pkcs12] [--raw]] []\n" "\n" "Export the keys described by PATTERN. Write the\n" "the output to the object set by the last OUTPUT command."; @@ -3082,6 +3082,12 @@ cmd_export (assuan_context_t ctx, char *line) mode |= GPGME_EXPORT_MODE_EXTERN; if (has_option (line, "--minimal")) mode |= GPGME_EXPORT_MODE_MINIMAL; + if (has_option (line, "--secret")) + mode |= GPGME_EXPORT_MODE_SECRET; + if (has_option (line, "--raw")) + mode |= GPGME_EXPORT_MODE_RAW; + if (has_option (line, "--pkcs12")) + mode |= GPGME_EXPORT_MODE_PKCS12; line = skip_options (line); diff --git a/src/gpgme.h.in b/src/gpgme.h.in index 8255e637..76055708 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -392,6 +392,9 @@ gpgme_pinentry_mode_t; /* The available export mode flags. */ #define GPGME_EXPORT_MODE_EXTERN 2 #define GPGME_EXPORT_MODE_MINIMAL 4 +#define GPGME_EXPORT_MODE_SECRET 16 +#define GPGME_EXPORT_MODE_RAW 32 +#define GPGME_EXPORT_MODE_PKCS12 64 typedef unsigned int gpgme_export_mode_t; diff --git a/tests/run-export.c b/tests/run-export.c index 43332087..b133f130 100644 --- a/tests/run-export.c +++ b/tests/run-export.c @@ -43,7 +43,12 @@ show_usage (int ex) fputs ("usage: " PGM " [options] USERIDS\n\n" "Options:\n" " --verbose run in verbose mode\n" + " --openpgp use OpenPGP protocol (default)\n" + " --cms use X.509 protocol\n" " --extern send keys to the keyserver (TAKE CARE!)\n" + " --secret export secret keys instead of public keys\n" + " --raw use PKCS#1 as secret key format\n" + " --pkcs12 use PKCS#12 as secret key format\n" , stderr); exit (ex); } @@ -59,6 +64,7 @@ main (int argc, char **argv) gpgme_key_t keyarray[100]; int keyidx = 0; gpgme_data_t out; + gpgme_protocol_t protocol = GPGME_PROTOCOL_OpenPGP; gpgme_export_mode_t mode = 0; if (argc) @@ -79,9 +85,34 @@ main (int argc, char **argv) verbose = 1; argc--; argv++; } + else if (!strcmp (*argv, "--openpgp")) + { + protocol = GPGME_PROTOCOL_OpenPGP; + argc--; argv++; + } + else if (!strcmp (*argv, "--cms")) + { + protocol = GPGME_PROTOCOL_CMS; + argc--; argv++; + } else if (!strcmp (*argv, "--extern")) { - mode |= GPGME_KEYLIST_MODE_EXTERN; + mode |= GPGME_EXPORT_MODE_EXTERN; + argc--; argv++; + } + else if (!strcmp (*argv, "--secret")) + { + mode |= GPGME_EXPORT_MODE_SECRET; + argc--; argv++; + } + else if (!strcmp (*argv, "--raw")) + { + mode |= GPGME_EXPORT_MODE_RAW; + argc--; argv++; + } + else if (!strcmp (*argv, "--pkcs12")) + { + mode |= GPGME_EXPORT_MODE_PKCS12; argc--; argv++; } else if (!strncmp (*argv, "--", 2)) @@ -92,11 +123,11 @@ main (int argc, char **argv) if (!argc) show_usage (1); - init_gpgme (GPGME_PROTOCOL_OpenPGP); + init_gpgme (protocol); err = gpgme_new (&ctx); fail_if_err (err); - gpgme_set_protocol (ctx, GPGME_PROTOCOL_OpenPGP); + gpgme_set_protocol (ctx, protocol); /* Lookup the keys. */ err = gpgme_op_keylist_ext_start (ctx, (const char**)argv, 0, 0); @@ -131,8 +162,10 @@ main (int argc, char **argv) } /* Now for the actual export. */ - if ((mode & GPGME_KEYLIST_MODE_EXTERN)) + if ((mode & GPGME_EXPORT_MODE_EXTERN)) printf ("sending keys to keyserver\n"); + if ((mode & GPGME_EXPORT_MODE_SECRET)) + printf ("exporting secret keys!\n"); err = gpgme_data_new (&out); fail_if_err (err); -- cgit v1.2.3 From df098d6a437109c57516db75addf3764a6dfda81 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 24 Aug 2015 15:03:20 +0200 Subject: w32: Print the installation directory in debug mode. * src/debug.c (debug_init) [W32]: Show libgpgme installation dir. -- I expect that gpgme will be distributed by applications and thus it will be helpful to see in the debug log which gpgme is actually used. Signed-off-by: Werner Koch --- src/debug.c | 12 +++++++++++- src/sys-util.h | 4 ++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/debug.c b/src/debug.c index 292db555..1dd37234 100644 --- a/src/debug.c +++ b/src/debug.c @@ -46,6 +46,7 @@ #include "util.h" #include "ath.h" #include "sema.h" +#include "sys-util.h" #include "debug.h" @@ -207,7 +208,16 @@ debug_init (void) UNLOCK (debug_lock); if (debug_level > 0) - _gpgme_debug (DEBUG_INIT, "gpgme_debug: level=%d\n", debug_level); + { + _gpgme_debug (DEBUG_INIT, "gpgme_debug: level=%d\n", debug_level); +#ifdef HAVE_W32_SYSTEM + { + const char *name = _gpgme_get_inst_dir (); + _gpgme_debug (DEBUG_INIT, "gpgme_debug: gpgme='%s'\n", + name? name: "?"); + } +#endif + } } diff --git a/src/sys-util.h b/src/sys-util.h index 7180fca3..589634b2 100644 --- a/src/sys-util.h +++ b/src/sys-util.h @@ -27,4 +27,8 @@ int _gpgme_set_default_gpgconf_name (const char *name); char *_gpgme_get_gpg_path (void); char *_gpgme_get_gpgconf_path (void); +#ifdef HAVE_W32_SYSTEM +const char *_gpgme_get_inst_dir (void); +#endif + #endif /* SYS_UTIL_H */ -- cgit v1.2.3 From 06d6fd8ca01354c8f7cfc847c4ac1b868268cbaa Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 24 Aug 2015 16:34:29 +0200 Subject: w32: Expect gpgme-w32spawn.exe only in the gpgme installation dir. * src/w32-util.c (find_program_at_standard_place): Remove. (_gpgme_get_gpg_path): Make the search order more explicit. (_gpgme_get_gpgconf_path): Ditto. (_gpgme_get_w32spawn_path): Search only in the inst_dir. -- This tries to avoid possible unclear bug reports by removing the fallback to the current gpg4win installation directory for the gpgme helper. It is expected that users of gpgme installing their own gpgme version also install the matching helper. Signed-off-by: Werner Koch --- src/w32-util.c | 123 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 65 insertions(+), 58 deletions(-) diff --git a/src/w32-util.c b/src/w32-util.c index daf3bd2d..fa6dcddc 100644 --- a/src/w32-util.c +++ b/src/w32-util.c @@ -397,40 +397,6 @@ find_program_in_dir (const char *dir, const char *name) } -static char * -find_program_in_inst_dir (const char *inst_dir, const char *name) -{ - char *result; - char *dir; - - /* If an installation directory has been passed, this overrides a - location given by the registry. The idea here is that we prefer - a program installed alongside with gpgme. We don't want the - registry to override this to have a better isolation of an gpgme - aware applications for other effects. Note that the "Install - Directory" registry item has been used for ages in Gpg4win and - earlier GnuPG windows installers. It is technically not anymore - required. */ - if (inst_dir) - { - result = find_program_in_dir (inst_dir, name); - if (result) - return result; - } - - dir = read_w32_registry_string ("HKEY_LOCAL_MACHINE", - "Software\\GNU\\GnuPG", - "Install Directory"); - if (dir) - { - result = find_program_in_dir (dir, name); - free (dir); - return result; - } - return NULL; -} - - static char * find_program_at_standard_place (const char *name) { @@ -491,29 +457,50 @@ _gpgme_set_default_gpgconf_name (const char *name) /* Return the full file name of the GPG binary. This function is used - if gpgconf was not found and thus it can be assumed that gpg2 is + iff gpgconf was not found and thus it can be assumed that gpg2 is not installed. This function is only called by get_gpgconf_item and may not be called concurrently. */ char * _gpgme_get_gpg_path (void) { - char *gpg; - const char *inst_dir, *name; + char *gpg = NULL; + const char *name, *inst_dir; + name = default_gpg_name? get_basename (default_gpg_name) : "gpg.exe"; + + /* 1. Try to find gpg.exe in the installation directory of gpgme. */ inst_dir = _gpgme_get_inst_dir (); - gpg = find_program_in_inst_dir - (inst_dir, - default_gpg_name? get_basename (default_gpg_name) : "gpg.exe"); + if (inst_dir) + { + gpg = find_program_in_dir (inst_dir, name); + } + + /* 2. Try to find gpg.exe using that ancient registry key. */ if (!gpg) { - name = (default_gpg_name? default_gpg_name - /* */ : "GNU\\GnuPG\\gpg.exe"); + char *dir; + + dir = read_w32_registry_string ("HKEY_LOCAL_MACHINE", + "Software\\GNU\\GnuPG", + "Install Directory"); + if (dir) + { + gpg = find_program_in_dir (dir, name); + free (dir); + } + } + + /* 3. Try to find gpg.exe below CSIDL_PROGRAM_FILES. */ + if (!gpg) + { + name = default_gpg_name? default_gpg_name : "GNU\\GnuPG\\gpg.exe"; gpg = find_program_at_standard_place (name); - if (!gpg) - _gpgme_debug (DEBUG_ENGINE, "_gpgme_get_gpg_path: '%s' not found", - name); } + /* 4. Print a debug message if not found. */ + if (!gpg) + _gpgme_debug (DEBUG_ENGINE, "_gpgme_get_gpg_path: '%s' not found", name); + return gpg; } @@ -523,22 +510,45 @@ _gpgme_get_gpg_path (void) char * _gpgme_get_gpgconf_path (void) { - char *gpgconf; + char *gpgconf = NULL; const char *inst_dir, *name; + name = default_gpgconf_name? get_basename(default_gpgconf_name):"gpgconf.exe"; + + /* 1. Try to find gpgconf.exe in the installation directory of gpgme. */ inst_dir = _gpgme_get_inst_dir (); - gpgconf = find_program_in_inst_dir - (inst_dir, - default_gpgconf_name? get_basename (default_gpgconf_name) : "gpgconf.exe"); + if (inst_dir) + { + gpgconf = find_program_in_dir (inst_dir, name); + } + + /* 2. Try to find gpgconf.exe using that ancient registry key. */ if (!gpgconf) { - name = (default_gpgconf_name? default_gpgconf_name - /* */ : "GNU\\GnuPG\\gpgconf.exe"); + char *dir; + + dir = read_w32_registry_string ("HKEY_LOCAL_MACHINE", + "Software\\GNU\\GnuPG", + "Install Directory"); + if (dir) + { + gpgconf = find_program_in_dir (dir, name); + free (dir); + } + } + + /* 3. Try to find gpgconf.exe below CSIDL_PROGRAM_FILES. */ + if (!gpgconf) + { + name = (default_gpgconf_name ? default_gpgconf_name + /**/ : "GNU\\GnuPG\\gpgconf.exe"); gpgconf = find_program_at_standard_place (name); - if (!gpgconf) - _gpgme_debug (DEBUG_ENGINE, "_gpgme_get_gpgconf_path: '%s' not found", - name); } + + /* 4. Print a debug message if not found. */ + if (!gpgconf) + _gpgme_debug (DEBUG_ENGINE, "_gpgme_get_gpgconf_path: '%s' not found",name); + return gpgconf; } @@ -552,10 +562,7 @@ _gpgme_get_w32spawn_path (void) inst_dir = _gpgme_get_inst_dir (); LOCK (get_path_lock); if (!w32spawn_program) - w32spawn_program = find_program_in_inst_dir (inst_dir,"gpgme-w32spawn.exe"); - if (!w32spawn_program) - w32spawn_program - = find_program_at_standard_place ("GNU\\GnuPG\\gpgme-w32spawn.exe"); + w32spawn_program = find_program_in_dir (inst_dir, "gpgme-w32spawn.exe"); UNLOCK (get_path_lock); return w32spawn_program; } -- cgit v1.2.3 From a7dbab23ea4976d106d649aa515ffb2968a085ed Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 24 Aug 2015 19:59:43 +0200 Subject: w32: Look for gpgconf in the new GnuPG 2.1 install dir. * src/w32-util.c (_gpgme_get_gpgconf_path): Try another location of gpgconf.exe. Signed-off-by: Werner Koch --- src/w32-util.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/w32-util.c b/src/w32-util.c index fa6dcddc..9aba26f5 100644 --- a/src/w32-util.c +++ b/src/w32-util.c @@ -522,7 +522,16 @@ _gpgme_get_gpgconf_path (void) gpgconf = find_program_in_dir (inst_dir, name); } - /* 2. Try to find gpgconf.exe using that ancient registry key. */ + /* 2. Try to find gpgconf.exe from GnuPG >= 2.1 below CSIDL_PROGRAM_FILES. */ + if (!gpgconf) + { + const char *name2 = (default_gpgconf_name ? default_gpgconf_name + /**/ : "GnuPG\\bin\\gpgconf.exe"); + gpgconf = find_program_at_standard_place (name2); + } + + /* 3. Try to find gpgconf.exe using that ancient registry key. This + should eventually be removed. */ if (!gpgconf) { char *dir; @@ -537,15 +546,13 @@ _gpgme_get_gpgconf_path (void) } } - /* 3. Try to find gpgconf.exe below CSIDL_PROGRAM_FILES. */ + /* 4. Try to find gpgconf.exe from Gpg4win below CSIDL_PROGRAM_FILES. */ if (!gpgconf) { - name = (default_gpgconf_name ? default_gpgconf_name - /**/ : "GNU\\GnuPG\\gpgconf.exe"); - gpgconf = find_program_at_standard_place (name); + gpgconf = find_program_at_standard_place ("GNU\\GnuPG\\gpgconf.exe"); } - /* 4. Print a debug message if not found. */ + /* 5. Print a debug message if not found. */ if (!gpgconf) _gpgme_debug (DEBUG_ENGINE, "_gpgme_get_gpgconf_path: '%s' not found",name); -- cgit v1.2.3 From ad46f4f655e653580343c15f1b0b365b7d307d1b Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 24 Aug 2015 21:17:21 +0200 Subject: Call status_cb for an ERROR status seen in the passphrase handler. * src/passphrase.c (_gpgme_passphrase_status_handler): Call status_cb. -- Frankly, we should have a more generic way of feeding the status_cb handler than our current ad-hoc method. Signed-off-by: Werner Koch --- src/passphrase.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/passphrase.c b/src/passphrase.c index 63ab31e6..5d656b17 100644 --- a/src/passphrase.c +++ b/src/passphrase.c @@ -116,6 +116,18 @@ _gpgme_passphrase_status_handler (void *priv, gpgme_status_code_t code, return gpg_error (GPG_ERR_BAD_PASSPHRASE); break; + case GPGME_STATUS_ERROR: + /* We abuse this status handler to forward ERROR status codes to + the caller. This should better be done in a generic handler, + but for now this is sufficient. */ + if (ctx->status_cb) + { + err = ctx->status_cb (ctx->status_cb_value, "ERROR", args); + if (err) + return err; + } + break; + default: /* Ignore all other codes. */ break; -- cgit v1.2.3 From 491fcd91b84564232d5d061942baa50b99e166c0 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 25 Aug 2015 09:05:27 +0200 Subject: tests: Allow using run-sign to test loopback pinentry problems. * tests/run-sign.c: Add options --status and --loopback. --- tests/run-sign.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/run-sign.c b/tests/run-sign.c index e1498ea8..c59c3563 100644 --- a/tests/run-sign.c +++ b/tests/run-sign.c @@ -36,6 +36,14 @@ static int verbose; +static gpg_error_t +status_cb (void *opaque, const char *keyword, const char *value) +{ + (void)opaque; + printf ("status_cb: %s %s\n", keyword, value); + return 0; +} + static void print_result (gpgme_sign_result_t result, gpgme_sig_mode_t type) @@ -67,9 +75,11 @@ 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" " --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 use key NAME for signing\n" , stderr); exit (ex); @@ -87,6 +97,8 @@ main (int argc, char **argv) gpgme_sig_mode_t sigmode = GPGME_SIG_MODE_NORMAL; gpgme_data_t in, out; gpgme_sign_result_t result; + int print_status = 0; + int use_loopback = 0; if (argc) { argc--; argv++; } @@ -106,6 +118,11 @@ main (int argc, char **argv) verbose = 1; argc--; argv++; } + else if (!strcmp (*argv, "--status")) + { + print_status = 1; + argc--; argv++; + } else if (!strcmp (*argv, "--openpgp")) { protocol = GPGME_PROTOCOL_OpenPGP; @@ -129,6 +146,11 @@ main (int argc, char **argv) key_string = *argv; argc--; argv++; } + else if (!strcmp (*argv, "--loopback")) + { + use_loopback = 1; + argc--; argv++; + } else if (!strncmp (*argv, "--", 2)) show_usage (1); @@ -149,6 +171,10 @@ main (int argc, char **argv) fail_if_err (err); gpgme_set_protocol (ctx, protocol); gpgme_set_armor (ctx, 1); + if (print_status) + gpgme_set_status_cb (ctx, status_cb, NULL); + if (use_loopback) + gpgme_set_pinentry_mode (ctx, GPGME_PINENTRY_MODE_LOOPBACK); if (key_string) { -- cgit v1.2.3 From 208f0297466ce68abfc432f4944f81eb8bf47cf8 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 25 Aug 2015 10:37:02 +0200 Subject: tests: Build test programs in tests/ without wrappers. -- --- tests/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Makefile.am b/tests/Makefile.am index 94eddac5..89e52e8d 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -26,6 +26,7 @@ TESTS = t-version t-data t-engine-info EXTRA_DIST = start-stop-agent t-data-1.txt t-data-2.txt ChangeLog-2011 AM_CPPFLAGS = -I$(top_builddir)/src @GPG_ERROR_CFLAGS@ +AM_LDFLAGS = -no-install LDADD = ../src/libgpgme.la @GPG_ERROR_LIBS@ noinst_HEADERS = run-support.h -- cgit v1.2.3 From 8ddc5801ade02297924447df5745c8877a96e5e3 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 25 Aug 2015 13:22:43 +0200 Subject: Improve error return by checking the FAILURE status. * src/gpgme.h.in (GPGME_STATUS_FAILURE): New. * src/status-table.c (FAILURE): New. * src/op-support.c (_gpgme_parse_failure): New. * src/passphrase.c (_gpgme_passphrase_status_handler): Forward FAILURE status line to the status callback. * src/decrypt.c (op_data_t): Add field failure_code. (_gpgme_decrypt_status_handler): Parse that code and act upon it on EOF. * src/encrypt.c (op_data_t): Add field failure_code. (_gpgme_encrypt_status_handler): Parse that code and act upon it on EOF. * src/genkey.c (op_data_t): Add field failure_code. (genkey_status_handler): Parse that code and act upon it on EOF. * src/passwd.c (op_data_t): Add field failure_code. (passwd_status_handler): Parse that code and act upon it on EOF. * src/sign.c (op_data_t): Add field failure_code. (_gpgme_sign_status_handler): Parse that code and act upon it on EOF. * src/verify.c (op_data_t): Add field failure_code. (_gpgme_verify_status_handler): Parse that code and act upon it on EOF. -- This requires GnuPG 2.1.8 to actually make a difference. Signed-off-by: Werner Koch --- src/decrypt.c | 9 +++++++++ src/encrypt.c | 9 +++++++++ src/genkey.c | 9 +++++++++ src/gpgme.h.in | 3 ++- src/op-support.c | 24 ++++++++++++++++++++++++ src/ops.h | 4 ++++ src/passphrase.c | 13 +++++++++++++ src/passwd.c | 9 +++++++++ src/sign.c | 10 +++++++++- src/status-table.c | 1 + src/verify.c | 9 +++++++++ 11 files changed, 98 insertions(+), 2 deletions(-) diff --git a/src/decrypt.c b/src/decrypt.c index 4fd92c61..4db68a10 100644 --- a/src/decrypt.c +++ b/src/decrypt.c @@ -38,6 +38,9 @@ typedef struct { struct _gpgme_op_decrypt_result result; + /* The error code from a FAILURE status line or 0. */ + gpg_error_t failure_code; + int okay; int failed; @@ -192,6 +195,10 @@ _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code, switch (code) { + case GPGME_STATUS_FAILURE: + opd->failure_code = _gpgme_parse_failure (args); + break; + case GPGME_STATUS_EOF: /* FIXME: These error values should probably be attributed to the underlying crypto engine (as error source). */ @@ -199,6 +206,8 @@ _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code, return gpg_error (GPG_ERR_DECRYPT_FAILED); else if (!opd->okay) return gpg_error (GPG_ERR_NO_DATA); + else if (opd->failure_code) + return opd->failure_code; break; case GPGME_STATUS_DECRYPTION_INFO: diff --git a/src/encrypt.c b/src/encrypt.c index 792c25c5..9f5134de 100644 --- a/src/encrypt.c +++ b/src/encrypt.c @@ -36,6 +36,9 @@ typedef struct { struct _gpgme_op_encrypt_result result; + /* The error code from a FAILURE status line or 0. */ + gpg_error_t failure_code; + /* A pointer to the next pointer of the last invalid recipient in the list. This makes appending new invalid recipients painless while preserving the order. */ @@ -114,9 +117,15 @@ _gpgme_encrypt_status_handler (void *priv, gpgme_status_code_t code, switch (code) { + case GPGME_STATUS_FAILURE: + opd->failure_code = _gpgme_parse_failure (args); + break; + case GPGME_STATUS_EOF: if (opd->result.invalid_recipients) return gpg_error (GPG_ERR_UNUSABLE_PUBKEY); + if (opd->failure_code) + return opd->failure_code; break; case GPGME_STATUS_INV_RECP: diff --git a/src/genkey.c b/src/genkey.c index 18765dde..3afd3b41 100644 --- a/src/genkey.c +++ b/src/genkey.c @@ -37,6 +37,9 @@ typedef struct { struct _gpgme_op_genkey_result result; + /* The error code from a FAILURE status line or 0. */ + gpg_error_t failure_code; + /* The key parameters passed to the crypto engine. */ gpgme_data_t key_parameter; } *op_data_t; @@ -118,10 +121,16 @@ genkey_status_handler (void *priv, gpgme_status_code_t code, char *args) } break; + case GPGME_STATUS_FAILURE: + opd->failure_code = _gpgme_parse_failure (args); + break; + case GPGME_STATUS_EOF: /* FIXME: Should return some more useful error value. */ if (!opd->result.primary && !opd->result.sub) return gpg_error (GPG_ERR_GENERAL); + else if (opd->failure_code) + return opd->failure_code; break; case GPGME_STATUS_INQUIRE_MAXLEN: diff --git a/src/gpgme.h.in b/src/gpgme.h.in index 76055708..432d18a1 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -548,7 +548,8 @@ typedef enum GPGME_STATUS_ATTRIBUTE = 89, GPGME_STATUS_BEGIN_SIGNING = 90, GPGME_STATUS_KEY_NOT_CREATED = 91, - GPGME_STATUS_INQUIRE_MAXLEN = 92 + GPGME_STATUS_INQUIRE_MAXLEN = 92, + GPGME_STATUS_FAILURE = 93 } gpgme_status_code_t; diff --git a/src/op-support.c b/src/op-support.c index 2bcb3a35..02940efd 100644 --- a/src/op-support.c +++ b/src/op-support.c @@ -337,3 +337,27 @@ _gpgme_parse_plaintext (char *args, char **filenamep) } return 0; } + + +/* Parse a FAILURE status line and return the error code. ARGS is + modified to contain the location part. */ +gpgme_error_t +_gpgme_parse_failure (char *args) +{ + char *where, *which; + + where = strchr (args, ' '); + if (!where) + return trace_gpg_error (GPG_ERR_INV_ENGINE); + + *where = '\0'; + which = where + 1; + + where = strchr (which, ' '); + if (where) + *where = '\0'; + + where = args; + + return atoi (which); +} diff --git a/src/ops.h b/src/ops.h index 782265e4..3662d571 100644 --- a/src/ops.h +++ b/src/ops.h @@ -65,6 +65,10 @@ gpgme_error_t _gpgme_parse_inv_recp (char *args, gpgme_invalid_key_t *key); FILENAMEP. */ gpgme_error_t _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. */ +gpgme_error_t _gpgme_parse_failure (char *args); + /* From verify.c. */ diff --git a/src/passphrase.c b/src/passphrase.c index 5d656b17..c88e57d2 100644 --- a/src/passphrase.c +++ b/src/passphrase.c @@ -128,6 +128,19 @@ _gpgme_passphrase_status_handler (void *priv, gpgme_status_code_t code, } break; + case GPGME_STATUS_FAILURE: + /* We abuse this status handler to forward FAILURE status codes + to the caller. This should better be done in a generic + handler, but for now this is sufficient. */ + if (ctx->status_cb) + { + err = ctx->status_cb (ctx->status_cb_value, "FAILURE", args); + if (err) + return err; + } + break; + + default: /* Ignore all other codes. */ break; diff --git a/src/passwd.c b/src/passwd.c index e832026d..ff30df01 100644 --- a/src/passwd.c +++ b/src/passwd.c @@ -30,6 +30,9 @@ typedef struct { + /* The error code from a FAILURE status line or 0. */ + gpg_error_t failure_code; + int success_seen; int error_seen; } *op_data_t; @@ -92,6 +95,10 @@ passwd_status_handler (void *priv, gpgme_status_code_t code, char *args) opd->success_seen = 1; break; + case GPGME_STATUS_FAILURE: + opd->failure_code = _gpgme_parse_failure (args); + break; + case GPGME_STATUS_EOF: /* In case the OpenPGP engine does not properly implement the passwd command we won't get a success status back and thus we @@ -102,6 +109,8 @@ passwd_status_handler (void *priv, gpgme_status_code_t code, char *args) if (ctx->protocol == GPGME_PROTOCOL_OpenPGP && !opd->error_seen && !opd->success_seen) err = gpg_error (GPG_ERR_NOT_SUPPORTED); + else if (opd->failure_code) + err = opd->failure_code; break; default: diff --git a/src/sign.c b/src/sign.c index 9e22fdb8..6c9fc03a 100644 --- a/src/sign.c +++ b/src/sign.c @@ -39,6 +39,9 @@ typedef struct { struct _gpgme_op_sign_result result; + /* The error code from a FAILURE status line or 0. */ + gpg_error_t failure_code; + /* A pointer to the next pointer of the last invalid signer in the list. This makes appending new invalid signers painless while preserving the order. */ @@ -327,6 +330,10 @@ _gpgme_sign_status_handler (void *priv, gpgme_status_code_t code, char *args) opd->last_signer_p = &(*opd->last_signer_p)->next; break; + case GPGME_STATUS_FAILURE: + opd->failure_code = _gpgme_parse_failure (args); + break; + case GPGME_STATUS_EOF: /* The UI server does not send information about the created signature. This is irrelevant for this protocol and thus we @@ -335,7 +342,7 @@ _gpgme_sign_status_handler (void *priv, gpgme_status_code_t code, char *args) err = gpg_error (GPG_ERR_UNUSABLE_SECKEY); else if (!opd->sig_created_seen && ctx->protocol != GPGME_PROTOCOL_UISERVER) - err = gpg_error (GPG_ERR_GENERAL); + err = opd->failure_code? opd->failure_code:gpg_error (GPG_ERR_GENERAL); break; case GPGME_STATUS_INQUIRE_MAXLEN: @@ -374,6 +381,7 @@ sign_init_result (gpgme_ctx_t ctx, int ignore_inv_recp) opd = hook; if (err) return err; + opd->failure_code = 0; opd->last_signer_p = &opd->result.invalid_signers; opd->last_sig_p = &opd->result.signatures; opd->ignore_inv_recp = !!ignore_inv_recp; diff --git a/src/status-table.c b/src/status-table.c index c85fa951..6d428d71 100644 --- a/src/status-table.c +++ b/src/status-table.c @@ -66,6 +66,7 @@ static struct status_table_s status_table[] = { "ERRSIG", GPGME_STATUS_ERRSIG }, { "EXPKEYSIG", GPGME_STATUS_EXPKEYSIG }, { "EXPSIG", GPGME_STATUS_EXPSIG }, + { "FAILURE", GPGME_STATUS_FAILURE }, { "FILE_DONE", GPGME_STATUS_FILE_DONE }, { "FILE_ERROR", GPGME_STATUS_FILE_ERROR }, { "FILE_START", GPGME_STATUS_FILE_START }, diff --git a/src/verify.c b/src/verify.c index 84487ee4..75914e22 100644 --- a/src/verify.c +++ b/src/verify.c @@ -38,6 +38,9 @@ typedef struct { struct _gpgme_op_verify_result result; + /* The error code from a FAILURE status line or 0. */ + gpg_error_t failure_code; + gpgme_signature_t current_sig; int did_prepare_new_sig; int only_newsig_seen; @@ -769,6 +772,10 @@ _gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args) error code if we are not ready to process this status. */ return parse_error (sig, args, !!sig ); + case GPGME_STATUS_FAILURE: + opd->failure_code = _gpgme_parse_failure (args); + break; + case GPGME_STATUS_EOF: if (sig && !opd->did_prepare_new_sig) calc_sig_summary (sig); @@ -795,6 +802,8 @@ _gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args) opd->current_sig = NULL; } opd->only_newsig_seen = 0; + if (opd->failure_code) + return opd->failure_code; break; case GPGME_STATUS_PLAINTEXT: -- cgit v1.2.3 From 97f1f3e883808743da5ee144abab25de062f34ac Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 25 Aug 2015 18:06:24 +0200 Subject: Cleanup layout of gpgme.h * src/gpgme.h.in: Reorder prototypes. Chnage some comments. Signed-off-by: Werner Koch --- src/gpgme.h.in | 390 +++++++++++++++++++++++++++++--------------------- src/versioninfo.rc.in | 2 +- 2 files changed, 225 insertions(+), 167 deletions(-) diff --git a/src/gpgme.h.in b/src/gpgme.h.in index 432d18a1..88766465 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -1,24 +1,24 @@ /* gpgme.h - Public interface to GnuPG Made Easy. -*- c -*- - Copyright (C) 2000 Werner Koch (dd9jn) - Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2009 - 2010, 2011, 2012, 2013, 2014 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 . - - Generated from gpgme.h.in for @GPGME_CONFIG_HOST@. */ + * Copyright (C) 2000 Werner Koch (dd9jn) + * Copyright (C) 2001-2015 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 . + * + * Generated from gpgme.h.in for @GPGME_CONFIG_HOST@. + */ #ifndef GPGME_H #define GPGME_H @@ -46,7 +46,10 @@ extern "C" { @INSERT__TYPEDEFS_FOR_GPGME_H@ -/* Check for compiler features. */ +/* + * Check for compiler features. + */ + #if __GNUC__ #define _GPGME_GCC_VERSION (__GNUC__ * 10000 \ + __GNUC_MINOR__ * 100 \ @@ -69,7 +72,7 @@ extern "C" { #define _GPGME_DEPRECATED_OUTSIDE_GPGME _GPGME_DEPRECATED #endif - + /* 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 @@ -94,7 +97,9 @@ extern "C" { -/* Some opaque data types used by GPGME. */ +/* + * Some opaque data types used by GPGME. + */ /* The context holds some global state and configuration options, as well as the results of a crypto operation. */ @@ -105,8 +110,11 @@ typedef struct gpgme_context *gpgme_ctx_t; struct gpgme_data; typedef struct gpgme_data *gpgme_data_t; + -/* Wrappers for the libgpg-error library. */ +/* + * Wrappers for the libgpg-error library. + */ typedef gpg_error_t gpgme_error_t; typedef gpg_err_code_t gpgme_err_code_t; @@ -196,7 +204,12 @@ gpgme_error_from_syserror (void) return gpgme_error (gpgme_err_code_from_syserror ()); } + +/* + * Various constants and types + */ + /* The possible encoding mode of gpgme_data_t objects. */ typedef enum { @@ -210,6 +223,7 @@ typedef enum } gpgme_data_encoding_t; + /* Known data types. */ typedef enum { @@ -226,7 +240,7 @@ typedef enum } gpgme_data_type_t; - + /* Public key algorithms. */ typedef enum { @@ -264,7 +278,7 @@ typedef enum } gpgme_hash_algo_t; - + /* The possible signature stati. Deprecated, use error value in sig status. */ typedef enum @@ -292,7 +306,7 @@ typedef enum } gpgme_sig_mode_t; - + /* The available key and signature attributes. Deprecated, use the individual result structures instead. */ typedef enum @@ -333,7 +347,7 @@ typedef enum _gpgme_attr_t; typedef _gpgme_attr_t gpgme_attr_t _GPGME_DEPRECATED; - + /* The available validities for a trust item or key. */ typedef enum { @@ -346,7 +360,7 @@ typedef enum } gpgme_validity_t; - + /* The available protocols. */ typedef enum { @@ -364,7 +378,7 @@ gpgme_protocol_t; /* Convenience macro for the surprisingly mixed spelling. */ #define GPGME_PROTOCOL_OPENPGP GPGME_PROTOCOL_OpenPGP - + /* The available keylist mode flags. */ #define GPGME_KEYLIST_MODE_LOCAL 1 #define GPGME_KEYLIST_MODE_EXTERN 2 @@ -376,7 +390,7 @@ gpgme_protocol_t; typedef unsigned int gpgme_keylist_mode_t; - + /* The pinentry modes. */ typedef enum { @@ -388,7 +402,7 @@ typedef enum } gpgme_pinentry_mode_t; - + /* The available export mode flags. */ #define GPGME_EXPORT_MODE_EXTERN 2 #define GPGME_EXPORT_MODE_MINIMAL 4 @@ -398,52 +412,11 @@ gpgme_pinentry_mode_t; typedef unsigned int gpgme_export_mode_t; - + /* Flags for the audit log functions. */ #define GPGME_AUDITLOG_HTML 1 #define GPGME_AUDITLOG_WITH_HELP 128 - -/* Signature notations. */ - -/* The available signature notation flags. */ -#define GPGME_SIG_NOTATION_HUMAN_READABLE 1 -#define GPGME_SIG_NOTATION_CRITICAL 2 - -typedef unsigned int gpgme_sig_notation_flags_t; - -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. */ - char *name; - - /* The value of the notation data. */ - char *value; - - /* The length of the name of the notation data. */ - int name_len; - - /* The length of the value of the notation data. */ - int value_len; - - /* The accumulated flags. */ - gpgme_sig_notation_flags_t flags; - - /* Notation data is human-readable. */ - unsigned int human_readable : 1; - - /* Notation data is critical. */ - unsigned int critical : 1; - - /* Internal to GPGME, do not use. */ - int _unused : 30; -}; -typedef struct _gpgme_sig_notation *gpgme_sig_notation_t; - - /* The possible stati for the edit operation. */ typedef enum { @@ -553,7 +526,50 @@ typedef enum } gpgme_status_code_t; + +/* The available signature notation flags. */ +#define GPGME_SIG_NOTATION_HUMAN_READABLE 1 +#define GPGME_SIG_NOTATION_CRITICAL 2 + +typedef unsigned int gpgme_sig_notation_flags_t; + +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. */ + char *name; + + /* The value of the notation data. */ + char *value; + + /* The length of the name of the notation data. */ + int name_len; + + /* The length of the value of the notation data. */ + int value_len; + + /* The accumulated flags. */ + gpgme_sig_notation_flags_t flags; + + /* Notation data is human-readable. */ + unsigned int human_readable : 1; + + /* Notation data is critical. */ + unsigned int critical : 1; + + /* Internal to GPGME, do not use. */ + int _unused : 30; +}; +typedef struct _gpgme_sig_notation *gpgme_sig_notation_t; + + +/* + * Public structures. + */ + /* The engine information structure. */ struct _gpgme_engine_info { @@ -576,7 +592,7 @@ struct _gpgme_engine_info }; typedef struct _gpgme_engine_info *gpgme_engine_info_t; - + /* A subkey from a key. */ struct _gpgme_subkey { @@ -831,8 +847,20 @@ struct _gpgme_key typedef struct _gpgme_key *gpgme_key_t; +/* An invalid key object. */ +struct _gpgme_invalid_key +{ + struct _gpgme_invalid_key *next; + char *fpr; + gpgme_error_t reason; +}; +typedef struct _gpgme_invalid_key *gpgme_invalid_key_t; + + -/* Types for callback functions. */ +/* + * Types for callback functions. + */ /* Request a passphrase from the user. */ typedef gpgme_error_t (*gpgme_passphrase_cb_t) (void *hook, @@ -857,7 +885,9 @@ typedef gpgme_error_t (*gpgme_edit_cb_t) (void *opaque, -/* Context management functions. */ +/* + * Context management functions. + */ /* Create a new context and return it in CTX. */ gpgme_error_t gpgme_new (gpgme_ctx_t *ctx); @@ -973,16 +1003,6 @@ gpgme_error_t gpgme_ctx_set_engine_info (gpgme_ctx_t ctx, const char *file_name, const char *home_dir); - -/* Return a statically allocated string with the name of the public - 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. */ -const char *gpgme_hash_algo_name (gpgme_hash_algo_t algo); - - /* Delete all signers from CTX. */ void gpgme_signers_clear (gpgme_ctx_t ctx); @@ -1021,7 +1041,7 @@ const char *gpgme_get_sig_string_attr (gpgme_ctx_t c, int idx, gpgme_error_t gpgme_get_sig_key (gpgme_ctx_t ctx, int idx, gpgme_key_t *r_key) _GPGME_DEPRECATED; - + /* Clear all notation data from the context. */ void gpgme_sig_notation_clear (gpgme_ctx_t ctx); @@ -1037,8 +1057,11 @@ gpgme_error_t gpgme_sig_notation_add (gpgme_ctx_t ctx, const char *name, /* Get the sig notations for this context. */ gpgme_sig_notation_t gpgme_sig_notation_get (gpgme_ctx_t ctx); + -/* Run control. */ +/* + * Run control. + */ /* The type of an I/O callback function. */ typedef gpgme_error_t (*gpgme_io_cb_t) (void *data, int fd); @@ -1111,8 +1134,17 @@ 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, gpgme_error_t *op_err, int hang); +/* Cancel a pending asynchronous operation. */ +gpgme_error_t gpgme_cancel (gpgme_ctx_t ctx); + +/* Cancel a pending operation asynchronously. */ +gpgme_error_t gpgme_cancel_async (gpgme_ctx_t ctx); + + -/* Functions to handle data objects. */ +/* + * Functions to handle data objects. + */ /* 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 @@ -1235,14 +1267,20 @@ gpgme_error_t gpgme_data_new_from_filepart (gpgme_data_t *r_dh, gpgme_data_seek instead. */ gpgme_error_t gpgme_data_rewind (gpgme_data_t dh) _GPGME_DEPRECATED; + -/* Key and trust functions. */ +/* + * Key and trust functions. + */ /* Get the key with the fingerprint FPR from the crypto backend. If 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); +/* Create a dummy key to specify an email address. */ +gpgme_error_t gpgme_key_from_uid (gpgme_key_t *key, const char *name); + /* Acquire a reference to KEY. */ void gpgme_key_ref (gpgme_key_t key); @@ -1285,26 +1323,12 @@ unsigned long gpgme_key_sig_get_ulong_attr (gpgme_key_t key, int uid_idx, const void *reserved, int idx) _GPGME_DEPRECATED; - -/* Crypto Operations. */ - -/* Cancel a pending asynchronous operation. */ -gpgme_error_t gpgme_cancel (gpgme_ctx_t ctx); - -/* Cancel a pending operation asynchronously. */ -gpgme_error_t gpgme_cancel_async (gpgme_ctx_t ctx); -struct _gpgme_invalid_key -{ - struct _gpgme_invalid_key *next; - char *fpr; - gpgme_error_t reason; -}; -typedef struct _gpgme_invalid_key *gpgme_invalid_key_t; +/* + * Encryption. + */ - -/* Encryption. */ struct _gpgme_op_encrypt_result { /* The list of invalid recipients. */ @@ -1348,7 +1372,9 @@ gpgme_error_t gpgme_op_encrypt_sign (gpgme_ctx_t ctx, gpgme_key_t recp[], gpgme_data_t plain, gpgme_data_t cipher); -/* Decryption. */ +/* + * Decryption. + */ struct _gpgme_recipient { @@ -1405,7 +1431,10 @@ gpgme_error_t gpgme_op_decrypt_verify (gpgme_ctx_t ctx, gpgme_data_t cipher, gpgme_data_t plain); -/* Signing. */ +/* + * Signing. + */ + struct _gpgme_new_signature { struct _gpgme_new_signature *next; @@ -1461,7 +1490,9 @@ gpgme_error_t gpgme_op_sign (gpgme_ctx_t ctx, gpgme_sig_mode_t mode); -/* Verify. */ +/* + * Verify. + */ /* Flags used for the SUMMARY field in a gpgme_signature_t. */ typedef enum @@ -1550,22 +1581,15 @@ gpgme_error_t gpgme_op_verify (gpgme_ctx_t ctx, gpgme_data_t sig, gpgme_data_t plaintext); -/* Import. */ - -/* The key was new. */ -#define GPGME_IMPORT_NEW 1 - -/* The key contained new user IDs. */ -#define GPGME_IMPORT_UID 2 - -/* The key contained new signatures. */ -#define GPGME_IMPORT_SIG 4 - -/* The key contained new sub keys. */ -#define GPGME_IMPORT_SUBKEY 8 +/* + * Import/Export + */ -/* The key contained a secret key. */ -#define GPGME_IMPORT_SECRET 16 +#define GPGME_IMPORT_NEW 1 /* The key was new. */ +#define GPGME_IMPORT_UID 2 /* The key contained new user IDs. */ +#define GPGME_IMPORT_SIG 4 /* The key contained new signatures. */ +#define GPGME_IMPORT_SUBKEY 8 /* The key contained new sub keys. */ +#define GPGME_IMPORT_SECRET 16 /* The key contained a secret key. */ struct _gpgme_import_status @@ -1586,7 +1610,7 @@ struct _gpgme_import_status }; typedef struct _gpgme_import_status *gpgme_import_status_t; -/* Import. */ +/* Import result object. */ struct _gpgme_op_import_result { /* Number of considered keys. */ @@ -1650,7 +1674,6 @@ gpgme_error_t gpgme_op_import_keys_start (gpgme_ctx_t ctx, gpgme_key_t keys[]); gpgme_error_t gpgme_op_import_keys (gpgme_ctx_t ctx, gpgme_key_t keys[]); - /* Export the keys found by PATTERN into KEYDATA. */ gpgme_error_t gpgme_op_export_start (gpgme_ctx_t ctx, const char *pattern, gpgme_export_mode_t mode, @@ -1679,7 +1702,10 @@ gpgme_error_t gpgme_op_export_keys (gpgme_ctx_t ctx, -/* Key generation. */ +/* + * Key generation. + */ + struct _gpgme_op_genkey_result { /* A primary key was generated. */ @@ -1707,7 +1733,7 @@ gpgme_error_t gpgme_op_genkey (gpgme_ctx_t ctx, const char *parms, /* Retrieve a pointer to the result of the genkey operation. */ 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. */ gpgme_error_t gpgme_op_delete_start (gpgme_ctx_t ctx, const gpgme_key_t key, @@ -1715,7 +1741,12 @@ gpgme_error_t gpgme_op_delete_start (gpgme_ctx_t ctx, const gpgme_key_t key, gpgme_error_t gpgme_op_delete (gpgme_ctx_t ctx, const gpgme_key_t key, int allow_secret); + +/* + * Key Edit interface + */ + /* Edit the key KEY. Send status and command requests to FNC and output of edit commands to OUT. */ gpgme_error_t gpgme_op_edit_start (gpgme_ctx_t ctx, gpgme_key_t key, @@ -1735,27 +1766,11 @@ gpgme_error_t gpgme_op_card_edit (gpgme_ctx_t ctx, gpgme_key_t key, gpgme_data_t out); -/* Flags for the spawn operations. */ -#define GPGME_SPAWN_DETACHED 1 -#define GPGME_SPAWN_ALLOW_SET_FG 2 - - -/* 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. */ -gpgme_error_t gpgme_op_spawn_start (gpgme_ctx_t ctx, - const char *file, const char *argv[], - gpgme_data_t datain, - gpgme_data_t dataout, gpgme_data_t dataerr, - unsigned int flags); -gpgme_error_t gpgme_op_spawn (gpgme_ctx_t ctx, - const char *file, const char *argv[], - gpgme_data_t datain, - gpgme_data_t dataout, gpgme_data_t dataerr, - unsigned int flags); - -/* Key management functions. */ +/* + * Key listing + */ + struct _gpgme_op_keylist_result { unsigned int truncated : 1; @@ -1792,7 +1807,9 @@ gpgme_error_t gpgme_op_passwd (gpgme_ctx_t ctx, gpgme_key_t key, -/* Trust items and operations. */ +/* + * Trust items and operations. + */ struct _gpgme_trust_item { @@ -1867,7 +1884,12 @@ int gpgme_trust_item_get_int_attr (gpgme_trust_item_t item, _gpgme_attr_t what, const void *reserved, int idx) _GPGME_DEPRECATED; + +/* + * Audit log + */ + /* Return the auditlog for the current session. This may be called after a successful or failed operation. If no audit log is available GPG_ERR_NO_DATA is returned. */ @@ -1878,7 +1900,33 @@ gpgme_error_t gpgme_op_getauditlog (gpgme_ctx_t ctx, gpgme_data_t output, -/* Low-level Assuan protocol access. */ +/* + * Spawn interface + */ + +/* Flags for the spawn operations. */ +#define GPGME_SPAWN_DETACHED 1 +#define GPGME_SPAWN_ALLOW_SET_FG 2 + + +/* 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. */ +gpgme_error_t gpgme_op_spawn_start (gpgme_ctx_t ctx, + const char *file, const char *argv[], + gpgme_data_t datain, + gpgme_data_t dataout, gpgme_data_t dataerr, + unsigned int flags); +gpgme_error_t gpgme_op_spawn (gpgme_ctx_t ctx, + const char *file, const char *argv[], + gpgme_data_t datain, + gpgme_data_t dataout, gpgme_data_t dataerr, + unsigned int flags); + + +/* + * Low-level Assuan protocol access. + */ typedef gpgme_error_t (*gpgme_assuan_data_cb_t) (void *opaque, const void *data, size_t datalen); @@ -1937,7 +1985,10 @@ gpgme_op_assuan_transact (gpgme_ctx_t ctx, void *status_cb_value) _GPGME_DEPRECATED; -/* Crypto container support. */ +/* + * Crypto container support. + */ + struct _gpgme_op_vfs_mount_result { char *mount_dir; @@ -1958,7 +2009,9 @@ gpgme_error_t gpgme_op_vfs_create (gpgme_ctx_t ctx, gpgme_key_t recp[], unsigned int flags, gpgme_error_t *op_err); -/* Interface to gpgconf(1). */ +/* + * Interface to gpgconf(1). + */ /* The expert level at which a configuration option or group of options should be displayed. See the gpgconf(1) documentation for @@ -2122,15 +2175,11 @@ gpgme_error_t gpgme_op_conf_load (gpgme_ctx_t ctx, gpgme_conf_comp_t *conf_p); follow chained components! */ gpgme_error_t gpgme_op_conf_save (gpgme_ctx_t ctx, gpgme_conf_comp_t comp); - -/* UIServer support. */ - -/* Create a dummy key to specify an email address. */ -gpgme_error_t gpgme_key_from_uid (gpgme_key_t *key, const char *name); - -/* Various functions. */ +/* + * Various functions. + */ /* Set special global flags; consult the manual before use. */ int gpgme_set_global_flag (const char *name, const char *value); @@ -2165,19 +2214,28 @@ gpgme_error_t gpgme_set_engine_info (gpgme_protocol_t proto, const char *file_name, const char *home_dir); - -/* Engine support functions. */ - /* Verify that the engine implementing PROTO is installed and available. */ gpgme_error_t gpgme_engine_check_version (gpgme_protocol_t proto); - + +/* Reference counting for result objects. */ void gpgme_result_ref (void *result); void gpgme_result_unref (void *result); +/* Return a statically allocated string with the name of the public + 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. */ +const char *gpgme_hash_algo_name (gpgme_hash_algo_t algo); + + -/* Deprecated types. */ +/* + * Deprecated types. + */ typedef gpgme_ctx_t GpgmeCtx _GPGME_DEPRECATED; typedef gpgme_data_t GpgmeData _GPGME_DEPRECATED; typedef gpgme_error_t GpgmeError _GPGME_DEPRECATED; diff --git a/src/versioninfo.rc.in b/src/versioninfo.rc.in index a4ab0af4..7f19b307 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-2013 g10 Code GmbH\0" + VALUE "LegalCopyright", "Copyright © 2001-2015 g10 Code GmbH\0" VALUE "LegalTrademarks", "\0" VALUE "OriginalFilename", "gpgme.dll\0" VALUE "PrivateBuild", "\0" -- cgit v1.2.3 From 028a0ef3336c5180797fb247448683195376c007 Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Mon, 27 Jul 2015 16:19:52 +0900 Subject: Relax ttyname_r error checks * src/engine-assuan.c (llass_new): Don't treat ttyname_r error as fatal. * src/engine-g13.c (g13_new): Likewise. * src/engine-gpg.c (gpg_new): Likewise. * src/engine-gpgsm.c (gpgsm_new): Likewise. * src/engine-uiserver.c (uiserver_new): Likewise. -- Even though isatty() returns 1, ttyname_r() may fail in many ways, e.g., when /dev/pts is not accessible under chroot. Since all our uses of ttyname_r() require that the function works, we can treat the failure as if isatty() fails. Signed-off-by: Daiki Ueno --- src/engine-assuan.c | 10 ++++------ src/engine-g13.c | 10 ++++------ src/engine-gpg.c | 13 ++++++++----- src/engine-gpgsm.c | 10 ++++------ src/engine-uiserver.c | 10 ++++------ 5 files changed, 24 insertions(+), 29 deletions(-) diff --git a/src/engine-assuan.c b/src/engine-assuan.c index 663b2eab..99024675 100644 --- a/src/engine-assuan.c +++ b/src/engine-assuan.c @@ -282,12 +282,10 @@ llass_new (void **engine, const char *file_name, const char *home_dir) char *dft_ttytype = NULL; rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname)); - if (rc) - { - err = gpg_error_from_errno (rc); - goto leave; - } - else + + /* Even though isatty() returns 1, ttyname_r() may fail in many + ways, e.g., when /dev/pts is not accessible under chroot. */ + if (!rc) { if (asprintf (&optstr, "OPTION ttyname=%s", dft_ttyname) < 0) { diff --git a/src/engine-g13.c b/src/engine-g13.c index a9717eec..4a7b75c5 100644 --- a/src/engine-g13.c +++ b/src/engine-g13.c @@ -286,12 +286,10 @@ g13_new (void **engine, const char *file_name, const char *home_dir) int rc; rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname)); - if (rc) - { - err = gpg_error_from_errno (rc); - goto leave; - } - else + + /* Even though isatty() returns 1, ttyname_r() may fail in many + ways, e.g., when /dev/pts is not accessible under chroot. */ + if (!rc) { if (asprintf (&optstr, "OPTION ttyname=%s", dft_ttyname) < 0) { diff --git a/src/engine-gpg.c b/src/engine-gpg.c index ffae2fe4..9efced25 100644 --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -513,6 +513,8 @@ gpg_new (void **engine, const char *file_name, const char *home_dir) rc = add_arg (gpg, dft_display); free (dft_display); + if (rc) + goto leave; } if (isatty (1)) @@ -520,9 +522,10 @@ gpg_new (void **engine, const char *file_name, const char *home_dir) int err; err = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname)); - if (err) - rc = gpg_error_from_errno (err); - else + + /* Even though isatty() returns 1, ttyname_r() may fail in many + ways, e.g., when /dev/pts is not accessible under chroot. */ + if (!err) { if (*dft_ttyname) { @@ -547,9 +550,9 @@ gpg_new (void **engine, const char *file_name, const char *home_dir) free (dft_ttytype); } + if (rc) + goto leave; } - if (rc) - goto leave; } leave: diff --git a/src/engine-gpgsm.c b/src/engine-gpgsm.c index 24d3b2a8..476e9ef3 100644 --- a/src/engine-gpgsm.c +++ b/src/engine-gpgsm.c @@ -408,12 +408,10 @@ gpgsm_new (void **engine, const char *file_name, const char *home_dir) int rc; rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname)); - if (rc) - { - err = gpg_error_from_errno (rc); - goto leave; - } - else + + /* Even though isatty() returns 1, ttyname_r() may fail in many + ways, e.g., when /dev/pts is not accessible under chroot. */ + if (!rc) { if (asprintf (&optstr, "OPTION ttyname=%s", dft_ttyname) < 0) { diff --git a/src/engine-uiserver.c b/src/engine-uiserver.c index a7184b7a..e4fd47c3 100644 --- a/src/engine-uiserver.c +++ b/src/engine-uiserver.c @@ -326,12 +326,10 @@ uiserver_new (void **engine, const char *file_name, const char *home_dir) int rc; rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname)); - if (rc) - { - err = gpg_error_from_errno (rc); - goto leave; - } - else + + /* Even though isatty() returns 1, ttyname_r() may fail in many + ways, e.g., when /dev/pts is not accessible under chroot. */ + if (!rc) { if (asprintf (&optstr, "OPTION ttyname=%s", dft_ttyname) < 0) { -- cgit v1.2.3 From ff91e699f7c14ea6cbc27b487cb40e9f6bd58901 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 25 Aug 2015 20:40:06 +0200 Subject: Add configure option --enable-build-timestamp. * configure.ac (BUILD_TIMESTAMP): Set to "" by default. -- This is based on libgpg-error commit d620005fd1a655d591fccb44639e22ea445e4554 but changed to be disbaled by default. Check there for some background. Signed-off-by: Werner Koch --- configure.ac | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index be36a420..a1973e76 100644 --- a/configure.ac +++ b/configure.ac @@ -260,11 +260,21 @@ changequote([,])dnl BUILD_FILEVERSION="${BUILD_FILEVERSION}mym4_revision_dec" AC_SUBST(BUILD_FILEVERSION) -BUILD_TIMESTAMP=`date -u +%Y-%m-%dT%H:%M+0000 2>/dev/null || date` +AC_ARG_ENABLE([build-timestamp], + AC_HELP_STRING([--enable-build-timestamp], + [set an explicit build timestamp for reproducibility. + (default is the current time in ISO-8601 format)]), + [if test "$enableval" = "yes"; then + BUILD_TIMESTAMP=`date -u +%Y-%m-%dT%H:%M+0000 2>/dev/null || date` + else + BUILD_TIMESTAMP="$enableval" + fi], + [BUILD_TIMESTAMP=""]) AC_SUBST(BUILD_TIMESTAMP) AC_DEFINE_UNQUOTED(BUILD_TIMESTAMP, "$BUILD_TIMESTAMP", [The time this package was configured for a build]) + # # Options to disable some regression tests # -- cgit v1.2.3 From 3f53d3d5d9e73a053b1e89073ef8f7cf01bfc8e6 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 25 Aug 2015 21:04:15 +0200 Subject: Avoid -Wundef warnings if gpgme.h is used by g++. * src/gpgme.h.in (_GPGME_INLINE): Move definition into the extern-C-scope. Signed-off-by: Werner Koch --- src/gpgme.h.in | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/src/gpgme.h.in b/src/gpgme.h.in index 88766465..a0d9d31b 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -23,14 +23,6 @@ #ifndef GPGME_H #define GPGME_H -#ifdef __GNUC__ -#define _GPGME_INLINE __inline__ -#elif __STDC_VERSION__ >= 199901L -#define _GPGME_INLINE inline -#else -#define _GPGME_INLINE -#endif - /* Include stdio.h for the FILE type definition. */ #include #include @@ -38,17 +30,40 @@ #ifdef __cplusplus extern "C" { -#if 0 /* just to make Emacs auto-indent happy */ +#if 0 /*(Make Emacsen's auto-indent happy.)*/ } #endif #endif /* __cplusplus */ + +/* 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. */ +#define GPGME_VERSION "@PACKAGE_VERSION@" + +/* The version number of this header. It may be used to handle minor + API incompatibilities. */ +#define GPGME_VERSION_NUMBER @VERSION_NUMBER@ + + +/* System specific typedefs. */ @INSERT__TYPEDEFS_FOR_GPGME_H@ + /* * Check for compiler features. */ +#ifdef __GNUC__ +# define _GPGME_INLINE __inline__ +#elif __STDC_VERSION__ >= 199901L +# define _GPGME_INLINE inline +#else +# define _GPGME_INLINE +#endif + #if __GNUC__ #define _GPGME_GCC_VERSION (__GNUC__ * 10000 \ @@ -73,17 +88,6 @@ extern "C" { #endif -/* 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. */ -#define GPGME_VERSION "@PACKAGE_VERSION@" - -/* The version number of this header. It may be used to handle minor - API incompatibilities. */ -#define GPGME_VERSION_NUMBER @VERSION_NUMBER@ - /* Check for a matching _FILE_OFFSET_BITS definition. */ #if @NEED__FILE_OFFSET_BITS@ #ifndef _FILE_OFFSET_BITS -- cgit v1.2.3 From c4f4b5c0a6fc172f7ceedc1a0021169e7f31b941 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 26 Aug 2015 09:16:36 +0200 Subject: Make use of GPGRT macros is available. * src/gpgme.h.in (_GPGME_INLINE): Define using GPGRT_INLINE if possible. Fix problem with -Wundef by adding an extra "defined()". (_GPGME_GCC_VERSION): Define using GPGRT_ macro if possible. --- src/gpgme.h.in | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/gpgme.h.in b/src/gpgme.h.in index a0d9d31b..6cea2c77 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -56,28 +56,33 @@ extern "C" { /* * Check for compiler features. */ -#ifdef __GNUC__ +#ifdef GPGRT_INLINE +# define _GPGME_INLINE GPGRT_INLINE +#elif defined(__GNUC__) # define _GPGME_INLINE __inline__ -#elif __STDC_VERSION__ >= 199901L +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L # define _GPGME_INLINE inline #else # define _GPGME_INLINE #endif -#if __GNUC__ -#define _GPGME_GCC_VERSION (__GNUC__ * 10000 \ - + __GNUC_MINOR__ * 100 \ - + __GNUC_PATCHLEVEL__) +#ifdef GPGRT_ATTR_DEPRECATED +# define _GPGME_DEPRECATED GPGRT_ATTR_DEPRECATED +#elif defined(__GNUC__) +# define _GPGME_GCC_VERSION (__GNUC__ * 10000 \ + + __GNUC_MINOR__ * 100 \ + + __GNUC_PATCHLEVEL__) -#if _GPGME_GCC_VERSION > 30100 -#define _GPGME_DEPRECATED __attribute__ ((__deprecated__)) -#endif +# if _GPGME_GCC_VERSION > 30100 +# define _GPGME_DEPRECATED __attribute__ ((__deprecated__)) +# else +# define _GPGME_DEPRECATED +# endif +#else +# define _GPGME_DEPRECATED #endif -#ifndef _GPGME_DEPRECATED -#define _GPGME_DEPRECATED -#endif /* The macro _GPGME_DEPRECATED_OUTSIDE_GPGME suppresses warnings for fields we must access in GPGME for ABI compatibility. */ -- cgit v1.2.3 From 107bff70edb611309f627058dd4777a5da084b1a Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 26 Aug 2015 09:28:32 +0200 Subject: Release 1.6.0 * configure.ac: Set LT version to C25/A14/R0. Signed-off-by: Werner Koch --- NEWS | 31 ++++++++++++++++++++++++++++++- configure.ac | 8 ++++---- doc/HACKING | 48 +++++++++++++++++++++++++++++++++++++++++++++++- doc/gpgme.texi | 10 +++++----- doc/lesser.texi | 13 ++++--------- 5 files changed, 90 insertions(+), 20 deletions(-) diff --git a/NEWS b/NEWS index 0e1e5009..8518dae2 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,35 @@ -Noteworthy changes in version 1.6.0 (unreleased) [C24/A13/R_] +Noteworthy changes in version 1.6.0 (2015-08-26) [C25/A14/R0] ------------------------------------------------ + * Added gpgme_set_offline to do a key listinging w/o requiring CRL. + + * Added gpgme_set_status_cb to allow a user to see some status + messages. + + * Added an export mode for secret keys. + + * More precise error codes are returned if GnuPG >= 2.1.8 is used. + + * The passphrase handler for the loopback mode has been improved and may + also be used with genkey. + + * [w32] The standard GnuPG 2.1 install directory is now seached for + gpgconf.exe before a registry specified directory and the Gpg4win + install directory. + + * [w32] gpgme-w32spawn.exe will now only be searched in the gpgme DLL + directory. + + * Interface changes relative to the 1.5.1 release: + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + gpgme_set_offline NEW. + gpgme_get_offline NEW. + gpgme_set_status_cb NEW. + gpgme_get_status_cb NEW. + GPGME_EXPORT_MODE_SECRET NEW + GPGME_EXPORT_MODE_RAW NEW. + GPGME_EXPORT_MODE_PKCS12 NEW. + Noteworthy changes in version 1.5.5 (2015-06-08) [C24/A13/R4] ------------------------------------------------ diff --git a/configure.ac b/configure.ac index a1973e76..015ed464 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ # configure.ac for GPGME # Copyright (C) 2000 Werner Koch (dd9jn) # Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, -# 2009, 2010, 2011, 2012, 2013 g10 Code GmbH +# 2009, 2010, 2011, 2012, 2013, 2014, 2015 g10 Code GmbH # # This file is part of GPGME. # @@ -55,11 +55,11 @@ AC_INIT([gpgme],[mym4_full_version],[http://bugs.gnupg.org]) # (Interfaces added: AGE++) # (Interfaces removed/changed: AGE=0) # -LIBGPGME_LT_CURRENT=24 +LIBGPGME_LT_CURRENT=25 # Subtract 2 from this value if you want to make the LFS transition an # ABI break. [Note to self: Remove this comment with the next regular break.] -LIBGPGME_LT_AGE=13 -LIBGPGME_LT_REVISION=4 +LIBGPGME_LT_AGE=14 +LIBGPGME_LT_REVISION=0 # If the API is changed in an incompatible way: increment the next counter. GPGME_CONFIG_API_VERSION=1 diff --git a/doc/HACKING b/doc/HACKING index aedcf094..83c0f517 100644 --- a/doc/HACKING +++ b/doc/HACKING @@ -23,11 +23,34 @@ the big picture. Omit the leading TABs that you're used to seeing in a "real" ChangeLog file, but keep the maximum line length at 72 or smaller, so that the generated ChangeLog lines, each with its - leading TAB, will not exceed 80 columns. + leading TAB, will not exceed 80 columns. If you want to add text + which shall not be copied to the ChangeLog, separate it by a line + consisting of two dashes at the begin of a line. Note that ./autogen.sh installs a git hook to do some basic syntax checking on the commit log message. + Typo fixes and documentation updates don't need a ChangeLog entry; + thus you would use a commit message like + + #+begin_example + Fix typo in a comment + + -- + #+end_example + + The marker line here is important; without it the first line would + appear in the ChangeLog. + + If you exceptionally need to have longer lines in a commit log you may + do this after this scissor line: + #+begin_example + # ------------------------ >8 ------------------------ + #+end_example + (hash, blank, 24 dashes, blank, scissor, blank, 24 dashes). + Note that such a comment will be removed if the git commit option + =--cleanup-scissor= is used. + ** License policy GPGME is currently licensed under the LGPLv2.1+ with tools and the @@ -73,6 +96,29 @@ need. If you really need to do it, use a separate commit for such a change. + - C99 syntax should not be used; stick to C90. + - Please do not use C++ =//= style comments. + - Try to fit lines into 80 columns. + - Ignore signed/unsigned pointer mismatches + - No arithmetic on void pointers; cast to char* first. + +** Commit log keywords + + - GnuPG-bug-id :: Values are comma or space delimited bug numbers + from bug.gnupg.org pertaining to this commit. + - Debian-bug-id :: Same as above but from the Debian bug tracker. + - CVE-id :: CVE id number pertaining to this commit. + - Regression-due-to :: Commit id of the regression fixed by this commit. + - Fixes-commit :: Commit id this commit fixes. + - Reported-by :: Value is a name or mail address of a bug reporte. + - Suggested-by :: Value is a name or mail address of someone how + suggested this change. + - Co-authored-by :: Name or mail address of a co-author + - Some-comments-by :: Name or mail address of the author of + additional comments (commit log or code). + - Proofread-by :: Sometimes used by translation commits. + - Signed-off-by :: Name or mail address of the developer + * Debug hints - Use gpgme-tool for manual tests. diff --git a/doc/gpgme.texi b/doc/gpgme.texi index 20e1912b..c02a30f3 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -6203,15 +6203,15 @@ you run your tests only with play data. @include gpl.texi -@node Function and Data Index -@unnumbered Function and Data Index - -@printindex fn - @node Concept Index @unnumbered Concept Index @printindex cp +@node Function and Data Index +@unnumbered Function and Data Index + +@printindex fn + @bye diff --git a/doc/lesser.texi b/doc/lesser.texi index f23f0fd0..bbd18a00 100644 --- a/doc/lesser.texi +++ b/doc/lesser.texi @@ -1,7 +1,7 @@ @node Library Copying @unnumbered GNU Lesser General Public License -@cindex LGPL, Lesser General Public License +@cindex LGPL, GNU Lesser General Public License @center Version 2.1, February 1999 @display @@ -16,7 +16,7 @@ as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] @end display -@section Preamble +@heading Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public @@ -119,7 +119,7 @@ former contains code derived from the library, whereas the latter must be combined with the library in order to run. @iftex -@section TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION +@heading TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION @end iftex @ifinfo @center GNU LESSER GENERAL PUBLIC LICENSE @@ -476,12 +476,7 @@ decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. -@iftex -@heading NO WARRANTY -@end iftex -@ifinfo @center NO WARRANTY -@end ifinfo @item BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO @@ -515,7 +510,7 @@ DAMAGES. @end ifinfo @page -@section How to Apply These Terms to Your New Libraries +@heading How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that -- cgit v1.2.3 From c8e7870281950ae3b943c819147d4329198c0520 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 26 Aug 2015 10:16:39 +0200 Subject: Post release updates -- --- NEWS | 4 ++++ configure.ac | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 8518dae2..7bf140b6 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,7 @@ +Noteworthy changes in version 1.6.1 (unreleased) [C25/A14/R_] +------------------------------------------------ + + Noteworthy changes in version 1.6.0 (2015-08-26) [C25/A14/R0] ------------------------------------------------ diff --git a/configure.ac b/configure.ac index 015ed464..55c388eb 100644 --- a/configure.ac +++ b/configure.ac @@ -29,7 +29,7 @@ min_automake_version="1.14" # for the LT versions. m4_define(mym4_version_major, [1]) m4_define(mym4_version_minor, [6]) -m4_define(mym4_version_micro, [0]) +m4_define(mym4_version_micro, [1]) # Below is m4 magic to extract and compute the revision number, the # decimalized short revision number, a beta version string, and a flag -- cgit v1.2.3 From c4b6b35bfa98e478f1d13f4ce3e664771f2604c2 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Sun, 30 Aug 2015 19:04:44 +0200 Subject: Add gpgme_pubkey_algo_string * src/gpgme.h.in (GPGME_PK_EDDSA): New. (gpgme_pubkey_algo_string): New. * src/conversion.c (_gpgme_map_pk_algo): Add new algo. * src/gpgme.c (gpgme_pubkey_algo_string): New. (gpgme_pubkey_algo_name): Reformat. Signed-off-by: Werner Koch --- NEWS | 7 +++++ doc/gpgme.texi | 21 ++++++++++++--- src/conversion.c | 1 + src/data-mem.c | 3 ++- src/gpgme.c | 81 +++++++++++++++++++++++++++++++++++++------------------ src/gpgme.def | 2 ++ src/gpgme.h.in | 10 +++++-- src/libgpgme.vers | 2 ++ 8 files changed, 94 insertions(+), 33 deletions(-) diff --git a/NEWS b/NEWS index 7bf140b6..85c084ff 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,13 @@ Noteworthy changes in version 1.6.1 (unreleased) [C25/A14/R_] ------------------------------------------------ + * New function to format a GnuPG style public key algorithm string. + + * Interface changes relative to the 1.6.0 release: + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + gpgme_pubkey_algo_string NEW. + GPGME_PK_EDDSA NEW. + Noteworthy changes in version 1.6.0 (2015-08-26) [C25/A14/R0] ------------------------------------------------ diff --git a/doc/gpgme.texi b/doc/gpgme.texi index c02a30f3..a764ce42 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -1161,6 +1161,9 @@ Algorithm as defined by FIPS 186-2 and RFC-6637. This value indicates ECDH, the Eliptic Curve Diffie-Hellmann encryption algorithm as defined by RFC-6637. +@item GPGME_PK_EDDSA +This value indicates the EdDSA algorithm. + @end table @end deftp @@ -1174,6 +1177,14 @@ If @var{algo} is not a valid public key algorithm, @code{NULL} is returned. @end deftypefun +@deftypefun {char *} gpgme_pubkey_algo_string (@w{gpgme_subkey_t @var{key}}) +The function @code{gpgme_pubkey_algo_string} is a convenience function +to build and return an algorithm string in the same way GnuPG does +(e.g. ``rsa2048'' or ``ed25519''). The caller must free the result +using @code{gpgme_free}. On error (e.g. invalid argument or memory +exhausted), the function returns NULL and sets @code{ERRNO}. +@end deftypefun + @node Hash Algorithms @section Hash Algorithms @@ -1954,9 +1965,11 @@ case, the data object @var{dh} is destroyed. @deftypefun void gpgme_free (@w{void *@var{buffer}}) The function @code{gpgme_free} releases the memory returned by -@code{gpgme_data_release_and_get_mem}. It should be used instead of -the system libraries @code{free} function in case different allocators -are used in a single program. +@code{gpgme_data_release_and_get_mem} and +@code{gpgme_pubkey_algo_string}. It should be used instead of the +system libraries @code{free} function in case different allocators are +used by a program. This is often the case if gpgme is used under +Windows as a DLL. @end deftypefun @@ -2838,7 +2851,7 @@ True if the secret key is stored on a smart card. The serial number of a smart card holding this key or @code{NULL}. @item char *curve -For ECC algoritms the name of the curve. +For ECC algorithms the name of the curve. @end table @end deftp diff --git a/src/conversion.c b/src/conversion.c index d04a6bef..0992225b 100644 --- a/src/conversion.c +++ b/src/conversion.c @@ -427,6 +427,7 @@ _gpgme_map_pk_algo (int algo, gpgme_protocol_t protocol) case 18: algo = GPGME_PK_ECDH; break; case 19: algo = GPGME_PK_ECDSA; break; case 20: break; + case 22: algo = GPGME_PK_EDDSA; break; default: algo = 0; break; /* Unknown. */ } } diff --git a/src/data-mem.c b/src/data-mem.c index e06a920c..a498b826 100644 --- a/src/data-mem.c +++ b/src/data-mem.c @@ -271,7 +271,8 @@ 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(). */ +/* Release the memory returned by gpgme_data_release_and_get_mem() and + some other functions. */ void gpgme_free (void *buffer) { diff --git a/src/gpgme.c b/src/gpgme.c index 0cf999a7..343e7752 100644 --- a/src/gpgme.c +++ b/src/gpgme.c @@ -1,7 +1,7 @@ /* gpgme.c - GnuPG Made Easy. Copyright (C) 2000 Werner Koch (dd9jn) Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2012, - 2014 g10 Code GmbH + 2014, 2015 g10 Code GmbH This file is part of GPGME. @@ -994,41 +994,70 @@ gpgme_sig_notation_get (gpgme_ctx_t ctx) return ctx->sig_notations; } + -const char * -gpgme_pubkey_algo_name (gpgme_pubkey_algo_t algo) +/* Return a public key algorithm string made of the algorithm and size + or the curve name. May return NULL on error. Caller must free the + result using gpgme_free. */ +char * +gpgme_pubkey_algo_string (gpgme_subkey_t subkey) { - switch (algo) + const char *prefix = NULL; + char *result; + + if (!subkey) { - case GPGME_PK_RSA: - return "RSA"; + gpg_err_set_errno (EINVAL); + return NULL; + } + switch (subkey->pubkey_algo) + { + case GPGME_PK_RSA: case GPGME_PK_RSA_E: - return "RSA-E"; - - case GPGME_PK_RSA_S: - return "RSA-S"; - - case GPGME_PK_ELG_E: - return "ELG-E"; - - case GPGME_PK_DSA: - return "DSA"; - + case GPGME_PK_RSA_S: prefix = "rsa"; break; + case GPGME_PK_ELG_E: prefix = "elg"; break; + case GPGME_PK_DSA: prefix = "dsa"; break; + case GPGME_PK_ELG: prefix = "xxx"; break; case GPGME_PK_ECC: - return "ECC"; + case GPGME_PK_ECDH: + case GPGME_PK_ECDSA: + case GPGME_PK_EDDSA: prefix = ""; break; + } - case GPGME_PK_ELG: - return "ELG"; + if (prefix && *prefix) + { + char buffer[40]; + snprintf (buffer, sizeof buffer, "%s%u", prefix, subkey->length); + result = strdup (buffer); + } + else if (prefix && subkey->curve && *subkey->curve) + result = strdup (subkey->curve); + else if (prefix) + result = strdup ("E_error"); + else + result = strdup ("unknown"); - case GPGME_PK_ECDSA: - return "ECDSA"; + return result; +} - case GPGME_PK_ECDH: - return "ECDH"; - default: - return NULL; +const char * +gpgme_pubkey_algo_name (gpgme_pubkey_algo_t algo) +{ + switch (algo) + { + case GPGME_PK_RSA: return "RSA"; + case GPGME_PK_RSA_E: return "RSA-E"; + case GPGME_PK_RSA_S: return "RSA-S"; + case GPGME_PK_ELG_E: return "ELG-E"; + case GPGME_PK_DSA: return "DSA"; + case GPGME_PK_ECC: return "ECC"; + case GPGME_PK_ELG: return "ELG"; + case GPGME_PK_ECDSA: return "ECDSA"; + case GPGME_PK_ECDH: return "ECDH"; + case GPGME_PK_EDDSA: return "EdDSA"; + default: return NULL; } } diff --git a/src/gpgme.def b/src/gpgme.def index a3f5fb4a..3b56aaad 100644 --- a/src/gpgme.def +++ b/src/gpgme.def @@ -223,5 +223,7 @@ EXPORTS gpgme_set_status_cb @167 gpgme_get_status_cb @168 + + gpgme_pubkey_algo_string @169 ; END diff --git a/src/gpgme.h.in b/src/gpgme.h.in index 6cea2c77..e7216cbe 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -261,7 +261,8 @@ typedef enum GPGME_PK_ECC = 18, GPGME_PK_ELG = 20, GPGME_PK_ECDSA = 301, - GPGME_PK_ECDH = 302 + GPGME_PK_ECDH = 302, + GPGME_PK_EDDSA = 303 } gpgme_pubkey_algo_t; @@ -1218,7 +1219,8 @@ gpgme_error_t gpgme_data_new_from_mem (gpgme_data_t *r_dh, 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(). */ +/* Release the memory returned by gpgme_data_release_and_get_mem() and + some other functions. */ void gpgme_free (void *buffer); gpgme_error_t gpgme_data_new_from_cbs (gpgme_data_t *dh, @@ -2232,6 +2234,10 @@ gpgme_error_t gpgme_engine_check_version (gpgme_protocol_t proto); 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. */ +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. */ const char *gpgme_pubkey_algo_name (gpgme_pubkey_algo_t algo); diff --git a/src/libgpgme.vers b/src/libgpgme.vers index 6687571f..c677190f 100644 --- a/src/libgpgme.vers +++ b/src/libgpgme.vers @@ -98,6 +98,8 @@ GPGME_1.1 { gpgme_set_status_cb; gpgme_get_status_cb; + + gpgme_pubkey_algo_string; }; -- cgit v1.2.3 From f0ccce855bd99fca7cfbbcafe3544e3113fedc67 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 31 Aug 2015 20:33:44 +0200 Subject: gpgme-tool: Switch to argparse.c for option parsing. * src/argparse.c, src/argparse.h: New. Taken from current gnupg. * src/Makefile.am (gpgme_tool_SOURCES): New. * src/gpgme-tool.c: Remove all argp.h stuff. (my_strusage): New. (main): Change to use argparse. -- As a GnuPG related tool the user should get the same experience in option parsing as with gpg et al. Thus we use the same parser. Signed-off-by: Werner Koch --- src/Makefile.am | 1 + src/argparse.c | 1609 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/argparse.h | 203 +++++++ src/gpgme-tool.c | 540 ++---------------- 4 files changed, 1862 insertions(+), 491 deletions(-) create mode 100644 src/argparse.c create mode 100644 src/argparse.h diff --git a/src/Makefile.am b/src/Makefile.am index 58922f90..698c6322 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -128,6 +128,7 @@ endif AM_CPPFLAGS = @GPG_ERROR_CFLAGS@ @QT4_CORE_CFLAGS@ AM_CFLAGS = @LIBASSUAN_CFLAGS@ @GLIB_CFLAGS@ @QT4_CORE_CFLAGS@ +gpgme_tool_SOURCES = gpgme-tool.c argparse.c argparse.h gpgme_tool_LDADD = libgpgme.la @LIBASSUAN_LIBS@ diff --git a/src/argparse.c b/src/argparse.c new file mode 100644 index 00000000..53c20fca --- /dev/null +++ b/src/argparse.c @@ -0,0 +1,1609 @@ +/* [argparse.c wk 17.06.97] Argument Parser for option handling + * Copyright (C) 1998-2001, 2006-2008, 2012 Free Software Foundation, Inc. + * Copyright (C) 1997-2001, 2006-2008, 2013-2015 Werner Koch + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify it + * under the terms of either + * + * - the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at + * your option) any later version. + * + * or + * + * - the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * or both in parallel, as here. + * + * GnuPG is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copies of the GNU General Public License + * and the GNU Lesser General Public License along with this program; + * if not, see . + */ + +/* This file may be used as part of GnuPG or standalone. A GnuPG + build is detected by the presence of the macro GNUPG_MAJOR_VERSION. + Some feature are only availalbe in the GnuPG build mode. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#ifdef GNUPG_MAJOR_VERSION +# include "util.h" +# include "common-defs.h" +# include "i18n.h" +# include "mischelp.h" +# include "stringhelp.h" +# include "logging.h" +# include "utf8conv.h" +#endif /*GNUPG_MAJOR_VERSION*/ + +#include "argparse.h" + +/* GnuPG uses GPLv3+ but a standalone version of this defaults to + GPLv2+ because that is the license of this file. Change this if + you include it in a program which uses GPLv3. If you don't want to + set a a copyright string for your usage() you may also hardcode it + here. */ +#ifndef GNUPG_MAJOR_VERSION + +# define ARGPARSE_GPL_VERSION 2 +# define ARGPARSE_CRIGHT_STR "Copyright (C) YEAR NAME" + +#else /* Used by GnuPG */ + +# define ARGPARSE_GPL_VERSION 3 +# define ARGPARSE_CRIGHT_STR "Copyright (C) 2015 Free Software Foundation, Inc." + +#endif /*GNUPG_MAJOR_VERSION*/ + +/* Replacements for standalone builds. */ +#ifndef GNUPG_MAJOR_VERSION +# ifndef _ +# define _(a) (a) +# endif +# ifndef DIM +# define DIM(v) (sizeof(v)/sizeof((v)[0])) +# endif +# define xtrymalloc(a) malloc ((a)) +# define xtryrealloc(a,b) realloc ((a), (b)) +# define xtrystrdup(a) strdup ((a)) +# define xfree(a) free ((a)) +# define log_error my_log_error +# define log_bug my_log_bug +# define trim_spaces(a) my_trim_spaces ((a)) +# define map_static_macro_string(a) (a) +#endif /*!GNUPG_MAJOR_VERSION*/ + + +#define ARGPARSE_STR(v) #v +#define ARGPARSE_STR2(v) ARGPARSE_STR(v) + + +/* Replacements for standalone builds. */ +#ifndef GNUPG_MAJOR_VERSION +static void +my_log_error (const char *fmt, ...) +{ + va_list arg_ptr ; + + va_start (arg_ptr, fmt); + fprintf (stderr, "%s: ", strusage (11)); + vfprintf (stderr, fmt, arg_ptr); + va_end (arg_ptr); +} + +static void +my_log_bug (const char *fmt, ...) +{ + va_list arg_ptr ; + + va_start (arg_ptr, fmt); + fprintf (stderr, "%s: Ohhhh jeeee: ", strusage (11)); + vfprintf (stderr, fmt, arg_ptr); + va_end (arg_ptr); + abort (); +} + +/* Return true if the native charset is utf-8. */ +static int +is_native_utf8 (void) +{ + return 1; +} + +static char * +my_trim_spaces (char *str) +{ + char *string, *p, *mark; + + string = str; + /* Find first non space character. */ + for (p=string; *p && isspace (*(unsigned char*)p) ; p++) + ; + /* Move characters. */ + for ((mark = NULL); (*string = *p); string++, p++) + if (isspace (*(unsigned char*)p)) + { + if (!mark) + mark = string; + } + else + mark = NULL; + if (mark) + *mark = '\0' ; /* Remove trailing spaces. */ + + return str ; +} + +#endif /*!GNUPG_MAJOR_VERSION*/ + + + +/********************************* + * @Summary arg_parse + * #include "argparse.h" + * + * typedef struct { + * char *argc; pointer to argc (value subject to change) + * char ***argv; pointer to argv (value subject to change) + * unsigned flags; Global flags (DO NOT CHANGE) + * int err; print error about last option + * 1 = warning, 2 = abort + * int r_opt; return option + * int r_type; type of return value (0 = no argument found) + * union { + * int ret_int; + * long ret_long + * ulong ret_ulong; + * char *ret_str; + * } r; Return values + * struct { + * int idx; + * const char *last; + * void *aliases; + * } internal; DO NOT CHANGE + * } ARGPARSE_ARGS; + * + * typedef struct { + * int short_opt; + * const char *long_opt; + * unsigned flags; + * } ARGPARSE_OPTS; + * + * int arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts ); + * + * @Description + * This is my replacement for getopt(). See the example for a typical usage. + * Global flags are: + * Bit 0 : Do not remove options form argv + * Bit 1 : Do not stop at last option but return other args + * with r_opt set to -1. + * Bit 2 : Assume options and real args are mixed. + * Bit 3 : Do not use -- to stop option processing. + * Bit 4 : Do not skip the first arg. + * Bit 5 : allow usage of long option with only one dash + * Bit 6 : ignore --version + * all other bits must be set to zero, this value is modified by the + * function, so assume this is write only. + * Local flags (for each option): + * Bit 2-0 : 0 = does not take an argument + * 1 = takes int argument + * 2 = takes string argument + * 3 = takes long argument + * 4 = takes ulong argument + * Bit 3 : argument is optional (r_type will the be set to 0) + * Bit 4 : allow 0x etc. prefixed values. + * Bit 6 : Ignore this option + * Bit 7 : This is a command and not an option + * You stop the option processing by setting opts to NULL, the function will + * then return 0. + * @Return Value + * Returns the args.r_opt or 0 if ready + * r_opt may be -2/-7 to indicate an unknown option/command. + * @See Also + * ArgExpand + * @Notes + * You do not need to process the options 'h', '--help' or '--version' + * because this function includes standard help processing; but if you + * specify '-h', '--help' or '--version' you have to do it yourself. + * The option '--' stops argument processing; if bit 1 is set the function + * continues to return normal arguments. + * To process float args or unsigned args you must use a string args and do + * the conversion yourself. + * @Example + * + * ARGPARSE_OPTS opts[] = { + * { 'v', "verbose", 0 }, + * { 'd', "debug", 0 }, + * { 'o', "output", 2 }, + * { 'c', "cross-ref", 2|8 }, + * { 'm', "my-option", 1|8 }, + * { 300, "ignored-long-option, ARGPARSE_OP_IGNORE}, + * { 500, "have-no-short-option-for-this-long-option", 0 }, + * {0} }; + * ARGPARSE_ARGS pargs = { &argc, &argv, 0 } + * + * while( ArgParse( &pargs, &opts) ) { + * switch( pargs.r_opt ) { + * case 'v': opt.verbose++; break; + * case 'd': opt.debug++; break; + * case 'o': opt.outfile = pargs.r.ret_str; break; + * case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break; + * case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break; + * case 500: opt.a_long_one++; break + * default : pargs.err = 1; break; -- force warning output -- + * } + * } + * if( argc > 1 ) + * log_fatal( "Too many args"); + * + */ + +typedef struct alias_def_s *ALIAS_DEF; +struct alias_def_s { + ALIAS_DEF next; + char *name; /* malloced buffer with name, \0, value */ + const char *value; /* ptr into name */ +}; + + +/* Object to store the names for the --ignore-invalid-option option. + This is a simple linked list. */ +typedef struct iio_item_def_s *IIO_ITEM_DEF; +struct iio_item_def_s +{ + IIO_ITEM_DEF next; + char name[1]; /* String with the long option name. */ +}; + +static const char *(*strusage_handler)( int ) = NULL; +static int (*custom_outfnc) (int, const char *); + +static int set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s); +static void show_help(ARGPARSE_OPTS *opts, unsigned flags); +static void show_version(void); +static int writestrings (int is_error, const char *string, ...) +#if __GNUC__ >= 4 + __attribute__ ((sentinel(0))) +#endif + ; + + +void +argparse_register_outfnc (int (*fnc)(int, const char *)) +{ + custom_outfnc = fnc; +} + + +/* Write STRING and all following const char * arguments either to + stdout or, if IS_ERROR is set, to stderr. The list of strings must + be terminated by a NULL. */ +static int +writestrings (int is_error, const char *string, ...) +{ + va_list arg_ptr; + const char *s; + int count = 0; + + if (string) + { + s = string; + va_start (arg_ptr, string); + do + { + if (custom_outfnc) + custom_outfnc (is_error? 2:1, s); + else + fputs (s, is_error? stderr : stdout); + count += strlen (s); + } + while ((s = va_arg (arg_ptr, const char *))); + va_end (arg_ptr); + } + return count; +} + + +static void +flushstrings (int is_error) +{ + if (custom_outfnc) + custom_outfnc (is_error? 2:1, NULL); + else + fflush (is_error? stderr : stdout); +} + + +static void +initialize( ARGPARSE_ARGS *arg, const char *filename, unsigned *lineno ) +{ + if( !(arg->flags & (1<<15)) ) + { + /* Initialize this instance. */ + arg->internal.idx = 0; + arg->internal.last = NULL; + arg->internal.inarg = 0; + arg->internal.stopped = 0; + arg->internal.aliases = NULL; + arg->internal.cur_alias = NULL; + arg->internal.iio_list = NULL; + arg->err = 0; + arg->flags |= 1<<15; /* Mark as initialized. */ + if ( *arg->argc < 0 ) + log_bug ("invalid argument for arg_parse\n"); + } + + + if (arg->err) + { + /* Last option was erroneous. */ + const char *s; + + if (filename) + { + if ( arg->r_opt == ARGPARSE_UNEXPECTED_ARG ) + s = _("argument not expected"); + else if ( arg->r_opt == ARGPARSE_READ_ERROR ) + s = _("read error"); + else if ( arg->r_opt == ARGPARSE_KEYWORD_TOO_LONG ) + s = _("keyword too long"); + else if ( arg->r_opt == ARGPARSE_MISSING_ARG ) + s = _("missing argument"); + else if ( arg->r_opt == ARGPARSE_INVALID_ARG ) + s = _("invalid argument"); + else if ( arg->r_opt == ARGPARSE_INVALID_COMMAND ) + s = _("invalid command"); + else if ( arg->r_opt == ARGPARSE_INVALID_ALIAS ) + s = _("invalid alias definition"); + else if ( arg->r_opt == ARGPARSE_OUT_OF_CORE ) + s = _("out of core"); + else + s = _("invalid option"); + log_error ("%s:%u: %s\n", filename, *lineno, s); + } + else + { + s = arg->internal.last? arg->internal.last:"[??]"; + + if ( arg->r_opt == ARGPARSE_MISSING_ARG ) + log_error (_("missing argument for option \"%.50s\"\n"), s); + else if ( arg->r_opt == ARGPARSE_INVALID_ARG ) + log_error (_("invalid argument for option \"%.50s\"\n"), s); + else if ( arg->r_opt == ARGPARSE_UNEXPECTED_ARG ) + log_error (_("option \"%.50s\" does not expect an argument\n"), s); + else if ( arg->r_opt == ARGPARSE_INVALID_COMMAND ) + log_error (_("invalid command \"%.50s\"\n"), s); + else if ( arg->r_opt == ARGPARSE_AMBIGUOUS_OPTION ) + log_error (_("option \"%.50s\" is ambiguous\n"), s); + else if ( arg->r_opt == ARGPARSE_AMBIGUOUS_COMMAND ) + log_error (_("command \"%.50s\" is ambiguous\n"),s ); + else if ( arg->r_opt == ARGPARSE_OUT_OF_CORE ) + log_error ("%s\n", _("out of core\n")); + else + log_error (_("invalid option \"%.50s\"\n"), s); + } + if (arg->err != ARGPARSE_PRINT_WARNING) + exit (2); + arg->err = 0; + } + + /* Zero out the return value union. */ + arg->r.ret_str = NULL; + arg->r.ret_long = 0; +} + + +static void +store_alias( ARGPARSE_ARGS *arg, char *name, char *value ) +{ + /* TODO: replace this dummy function with a rea one + * and fix the probelms IRIX has with (ALIAS_DEV)arg.. + * used as lvalue + */ + (void)arg; + (void)name; + (void)value; +#if 0 + ALIAS_DEF a = xmalloc( sizeof *a ); + a->name = name; + a->value = value; + a->next = (ALIAS_DEF)arg->internal.aliases; + (ALIAS_DEF)arg->internal.aliases = a; +#endif +} + + +/* Return true if KEYWORD is in the ignore-invalid-option list. */ +static int +ignore_invalid_option_p (ARGPARSE_ARGS *arg, const char *keyword) +{ + IIO_ITEM_DEF item = arg->internal.iio_list; + + for (; item; item = item->next) + if (!strcmp (item->name, keyword)) + return 1; + return 0; +} + + +/* Add the keywords up to the next LF to the list of to be ignored + options. After returning FP will either be at EOF or the next + character read wll be the first of a new line. The function + returns 0 on success or true on malloc failure. */ +static int +ignore_invalid_option_add (ARGPARSE_ARGS *arg, FILE *fp) +{ + IIO_ITEM_DEF item; + int c; + char name[100]; + int namelen = 0; + int ready = 0; + enum { skipWS, collectNAME, skipNAME, addNAME} state = skipWS; + + while (!ready) + { + c = getc (fp); + if (c == '\n') + ready = 1; + else if (c == EOF) + { + c = '\n'; + ready = 1; + } + again: + switch (state) + { + case skipWS: + if (!isascii (c) || !isspace(c)) + { + namelen = 0; + state = collectNAME; + goto again; + } + break; + + case collectNAME: + if (isspace (c)) + { + state = addNAME; + goto again; + } + else if (namelen < DIM(name)-1) + name[namelen++] = c; + else /* Too long. */ + state = skipNAME; + break; + + case skipNAME: + if (isspace (c)) + { + state = skipWS; + goto again; + } + break; + + case addNAME: + name[namelen] = 0; + if (!ignore_invalid_option_p (arg, name)) + { + item = xtrymalloc (sizeof *item + namelen); + if (!item) + return 1; + strcpy (item->name, name); + item->next = (IIO_ITEM_DEF)arg->internal.iio_list; + arg->internal.iio_list = item; + } + state = skipWS; + goto again; + } + } + return 0; +} + + +/* Clear the entire ignore-invalid-option list. */ +static void +ignore_invalid_option_clear (ARGPARSE_ARGS *arg) +{ + IIO_ITEM_DEF item, tmpitem; + + for (item = arg->internal.iio_list; item; item = tmpitem) + { + tmpitem = item->next; + xfree (item); + } + arg->internal.iio_list = NULL; +} + + + +/**************** + * Get options from a file. + * Lines starting with '#' are comment lines. + * Syntax is simply a keyword and the argument. + * Valid keywords are all keywords from the long_opt list without + * the leading dashes. The special keywords "help", "warranty" and "version" + * are not valid here. + * The special keyword "alias" may be used to store alias definitions, + * which are later expanded like long options. + * The option + * ignore-invalid-option OPTIONNAMEs + * is recognized and updates a list of option which should be ignored if they + * are not defined. + * Caller must free returned strings. + * If called with FP set to NULL command line args are parse instead. + * + * Q: Should we allow the syntax + * keyword = value + * and accept for boolean options a value of 1/0, yes/no or true/false? + * Note: Abbreviation of options is here not allowed. + */ +int +optfile_parse (FILE *fp, const char *filename, unsigned *lineno, + ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts) +{ + int state, i, c; + int idx=0; + char keyword[100]; + char *buffer = NULL; + size_t buflen = 0; + int in_alias=0; + + if (!fp) /* Divert to to arg_parse() in this case. */ + return arg_parse (arg, opts); + + initialize (arg, filename, lineno); + + /* Find the next keyword. */ + state = i = 0; + for (;;) + { + c = getc (fp); + if (c == '\n' || c== EOF ) + { + if ( c != EOF ) + ++*lineno; + if (state == -1) + break; + else if (state == 2) + { + keyword[i] = 0; + for (i=0; opts[i].short_opt; i++ ) + { + if (opts[i].long_opt && !strcmp (opts[i].long_opt, keyword)) + break; + } + idx = i; + arg->r_opt = opts[idx].short_opt; + if ((opts[idx].flags & ARGPARSE_OPT_IGNORE)) + { + state = i = 0; + continue; + } + else if (!opts[idx].short_opt ) + { + if (!strcmp (keyword, "ignore-invalid-option")) + { + /* No argument - ignore this meta option. */ + state = i = 0; + continue; + } + else if (ignore_invalid_option_p (arg, keyword)) + { + /* This invalid option is in the iio list. */ + state = i = 0; + continue; + } + arg->r_opt = ((opts[idx].flags & ARGPARSE_OPT_COMMAND) + ? ARGPARSE_INVALID_COMMAND + : ARGPARSE_INVALID_OPTION); + } + else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK)) + arg->r_type = 0; /* Does not take an arg. */ + else if ((opts[idx].flags & ARGPARSE_OPT_OPTIONAL) ) + arg->r_type = 0; /* Arg is optional. */ + else + arg->r_opt = ARGPARSE_MISSING_ARG; + + break; + } + else if (state == 3) + { + /* No argument found. */ + if (in_alias) + arg->r_opt = ARGPARSE_MISSING_ARG; + else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK)) + arg->r_type = 0; /* Does not take an arg. */ + else if ((opts[idx].flags & ARGPARSE_OPT_OPTIONAL)) + arg->r_type = 0; /* No optional argument. */ + else + arg->r_opt = ARGPARSE_MISSING_ARG; + + break; + } + else if (state == 4) + { + /* Has an argument. */ + if (in_alias) + { + if (!buffer) + arg->r_opt = ARGPARSE_UNEXPECTED_ARG; + else + { + char *p; + + buffer[i] = 0; + p = strpbrk (buffer, " \t"); + if (p) + { + *p++ = 0; + trim_spaces (p); + } + if (!p || !*p) + { + xfree (buffer); + arg->r_opt = ARGPARSE_INVALID_ALIAS; + } + else + { + store_alias (arg, buffer, p); + } + } + } + else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK)) + arg->r_opt = ARGPARSE_UNEXPECTED_ARG; + else + { + char *p; + + if (!buffer) + { + keyword[i] = 0; + buffer = xtrystrdup (keyword); + if (!buffer) + arg->r_opt = ARGPARSE_OUT_OF_CORE; + } + else + buffer[i] = 0; + + if (buffer) + { + trim_spaces (buffer); + p = buffer; + if (*p == '"') + { + /* Remove quotes. */ + p++; + if (*p && p[strlen(p)-1] == '\"' ) + p[strlen(p)-1] = 0; + } + if (!set_opt_arg (arg, opts[idx].flags, p)) + xfree (buffer); + } + } + break; + } + else if (c == EOF) + { + ignore_invalid_option_clear (arg); + if (ferror (fp)) + arg->r_opt = ARGPARSE_READ_ERROR; + else + arg->r_opt = 0; /* EOF. */ + break; + } + state = 0; + i = 0; + } + else if (state == -1) + ; /* Skip. */ + else if (state == 0 && isascii (c) && isspace(c)) + ; /* Skip leading white space. */ + else if (state == 0 && c == '#' ) + state = 1; /* Start of a comment. */ + else if (state == 1) + ; /* Skip comments. */ + else if (state == 2 && isascii (c) && isspace(c)) + { + /* Check keyword. */ + keyword[i] = 0; + for (i=0; opts[i].short_opt; i++ ) + if (opts[i].long_opt && !strcmp (opts[i].long_opt, keyword)) + break; + idx = i; + arg->r_opt = opts[idx].short_opt; + if ((opts[idx].flags & ARGPARSE_OPT_IGNORE)) + { + state = 1; /* Process like a comment. */ + } + else if (!opts[idx].short_opt) + { + if (!strcmp (keyword, "alias")) + { + in_alias = 1; + state = 3; + } + else if (!strcmp (keyword, "ignore-invalid-option")) + { + if (ignore_invalid_option_add (arg, fp)) + { + arg->r_opt = ARGPARSE_OUT_OF_CORE; + break; + } + state = i = 0; + ++*lineno; + } + else if (ignore_invalid_option_p (arg, keyword)) + state = 1; /* Process like a comment. */ + else + { + arg->r_opt = ((opts[idx].flags & ARGPARSE_OPT_COMMAND) + ? ARGPARSE_INVALID_COMMAND + : ARGPARSE_INVALID_OPTION); + state = -1; /* Skip rest of line and leave. */ + } + } + else + state = 3; + } + else if (state == 3) + { + /* Skip leading spaces of the argument. */ + if (!isascii (c) || !isspace(c)) + { + i = 0; + keyword[i++] = c; + state = 4; + } + } + else if (state == 4) + { + /* Collect the argument. */ + if (buffer) + { + if (i < buflen-1) + buffer[i++] = c; + else + { + char *tmp; + size_t tmplen = buflen + 50; + + tmp = xtryrealloc (buffer, tmplen); + if (tmp) + { + buflen = tmplen; + buffer = tmp; + buffer[i++] = c; + } + else + { + xfree (buffer); + arg->r_opt = ARGPARSE_OUT_OF_CORE; + break; + } + } + } + else if (i < DIM(keyword)-1) + keyword[i++] = c; + else + { + size_t tmplen = DIM(keyword) + 50; + buffer = xtrymalloc (tmplen); + if (buffer) + { + buflen = tmplen; + memcpy(buffer, keyword, i); + buffer[i++] = c; + } + else + { + arg->r_opt = ARGPARSE_OUT_OF_CORE; + break; + } + } + } + else if (i >= DIM(keyword)-1) + { + arg->r_opt = ARGPARSE_KEYWORD_TOO_LONG; + state = -1; /* Skip rest of line and leave. */ + } + else + { + keyword[i++] = c; + state = 2; + } + } + + return arg->r_opt; +} + + + +static int +find_long_option( ARGPARSE_ARGS *arg, + ARGPARSE_OPTS *opts, const char *keyword ) +{ + int i; + size_t n; + + (void)arg; + + /* Would be better if we can do a binary search, but it is not + possible to reorder our option table because we would mess + up our help strings - What we can do is: Build a nice option + lookup table wehn this function is first invoked */ + if( !*keyword ) + return -1; + for(i=0; opts[i].short_opt; i++ ) + if( opts[i].long_opt && !strcmp( opts[i].long_opt, keyword) ) + return i; +#if 0 + { + ALIAS_DEF a; + /* see whether it is an alias */ + for( a = args->internal.aliases; a; a = a->next ) { + if( !strcmp( a->name, keyword) ) { + /* todo: must parse the alias here */ + args->internal.cur_alias = a; + return -3; /* alias available */ + } + } + } +#endif + /* not found, see whether it is an abbreviation */ + /* aliases may not be abbreviated */ + n = strlen( keyword ); + for(i=0; opts[i].short_opt; i++ ) { + if( opts[i].long_opt && !strncmp( opts[i].long_opt, keyword, n ) ) { + int j; + for(j=i+1; opts[j].short_opt; j++ ) { + if( opts[j].long_opt + && !strncmp( opts[j].long_opt, keyword, n ) ) + return -2; /* abbreviation is ambiguous */ + } + return i; + } + } + return -1; /* Not found. */ +} + +int +arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts) +{ + int idx; + int argc; + char **argv; + char *s, *s2; + int i; + + initialize( arg, NULL, NULL ); + argc = *arg->argc; + argv = *arg->argv; + idx = arg->internal.idx; + + if (!idx && argc && !(arg->flags & ARGPARSE_FLAG_ARG0)) + { + /* Skip the first argument. */ + argc--; argv++; idx++; + } + + next_one: + if (!argc) + { + /* No more args. */ + arg->r_opt = 0; + goto leave; /* Ready. */ + } + + s = *argv; + arg->internal.last = s; + + if (arg->internal.stopped && (arg->flags & ARGPARSE_FLAG_ALL)) + { + arg->r_opt = ARGPARSE_IS_ARG; /* Not an option but an argument. */ + arg->r_type = 2; + arg->r.ret_str = s; + argc--; argv++; idx++; /* set to next one */ + } + else if( arg->internal.stopped ) + { + arg->r_opt = 0; + goto leave; /* Ready. */ + } + else if ( *s == '-' && s[1] == '-' ) + { + /* Long option. */ + char *argpos; + + arg->internal.inarg = 0; + if (!s[2] && !(arg->flags & ARGPARSE_FLAG_NOSTOP)) + { + /* Stop option processing. */ + arg->internal.stopped = 1; + arg->flags |= ARGPARSE_FLAG_STOP_SEEN; + argc--; argv++; idx++; + goto next_one; + } + + argpos = strchr( s+2, '=' ); + if ( argpos ) + *argpos = 0; + i = find_long_option ( arg, opts, s+2 ); + if ( argpos ) + *argpos = '='; + + if ( i < 0 && !strcmp ( "help", s+2) ) + show_help (opts, arg->flags); + else if ( i < 0 && !strcmp ( "version", s+2) ) + { + if (!(arg->flags & ARGPARSE_FLAG_NOVERSION)) + { + show_version (); + exit(0); + } + } + else if ( i < 0 && !strcmp( "warranty", s+2)) + { + writestrings (0, strusage (16), "\n", NULL); + exit (0); + } + else if ( i < 0 && !strcmp( "dump-options", s+2) ) + { + for (i=0; opts[i].short_opt; i++ ) + { + if (opts[i].long_opt && !(opts[i].flags & ARGPARSE_OPT_IGNORE)) + writestrings (0, "--", opts[i].long_opt, "\n", NULL); + } + writestrings (0, "--dump-options\n--help\n--version\n--warranty\n", + NULL); + exit (0); + } + + if ( i == -2 ) + arg->r_opt = ARGPARSE_AMBIGUOUS_OPTION; + else if ( i == -1 ) + { + arg->r_opt = ARGPARSE_INVALID_OPTION; + arg->r.ret_str = s+2; + } + else + arg->r_opt = opts[i].short_opt; + if ( i < 0 ) + ; + else if ( (opts[i].flags & ARGPARSE_TYPE_MASK) ) + { + if ( argpos ) + { + s2 = argpos+1; + if ( !*s2 ) + s2 = NULL; + } + else + s2 = argv[1]; + if ( !s2 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) ) + { + arg->r_type = ARGPARSE_TYPE_NONE; /* Argument is optional. */ + } + else if ( !s2 ) + { + arg->r_opt = ARGPARSE_MISSING_ARG; + } + else if ( !argpos && *s2 == '-' + && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) ) + { + /* The argument is optional and the next seems to be an + option. We do not check this possible option but + assume no argument */ + arg->r_type = ARGPARSE_TYPE_NONE; + } + else + { + set_opt_arg (arg, opts[i].flags, s2); + if ( !argpos ) + { + argc--; argv++; idx++; /* Skip one. */ + } + } + } + else + { + /* Does not take an argument. */ + if ( argpos ) + arg->r_type = ARGPARSE_UNEXPECTED_ARG; + else + arg->r_type = 0; + } + argc--; argv++; idx++; /* Set to next one. */ + } + else if ( (*s == '-' && s[1]) || arg->internal.inarg ) + { + /* Short option. */ + int dash_kludge = 0; + + i = 0; + if ( !arg->internal.inarg ) + { + arg->internal.inarg++; + if ( (arg->flags & ARGPARSE_FLAG_ONEDASH) ) + { + for (i=0; opts[i].short_opt; i++ ) + if ( opts[i].long_opt && !strcmp (opts[i].long_opt, s+1)) + { + dash_kludge = 1; + break; + } + } + } + s += arg->internal.inarg; + + if (!dash_kludge ) + { + for (i=0; opts[i].short_opt; i++ ) + if ( opts[i].short_opt == *s ) + break; + } + + if ( !opts[i].short_opt && ( *s == 'h' || *s == '?' ) ) + show_help (opts, arg->flags); + + arg->r_opt = opts[i].short_opt; + if (!opts[i].short_opt ) + { + arg->r_opt = (opts[i].flags & ARGPARSE_OPT_COMMAND)? + ARGPARSE_INVALID_COMMAND:ARGPARSE_INVALID_OPTION; + arg->internal.inarg++; /* Point to the next arg. */ + arg->r.ret_str = s; + } + else if ( (opts[i].flags & ARGPARSE_TYPE_MASK) ) + { + if ( s[1] && !dash_kludge ) + { + s2 = s+1; + set_opt_arg (arg, opts[i].flags, s2); + } + else + { + s2 = argv[1]; + if ( !s2 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) ) + { + arg->r_type = ARGPARSE_TYPE_NONE; + } + else if ( !s2 ) + { + arg->r_opt = ARGPARSE_MISSING_ARG; + } + else if ( *s2 == '-' && s2[1] + && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) ) + { + /* The argument is optional and the next seems to + be an option. We do not check this possible + option but assume no argument. */ + arg->r_type = ARGPARSE_TYPE_NONE; + } + else + { + set_opt_arg (arg, opts[i].flags, s2); + argc--; argv++; idx++; /* Skip one. */ + } + } + s = "x"; /* This is so that !s[1] yields false. */ + } + else + { + /* Does not take an argument. */ + arg->r_type = ARGPARSE_TYPE_NONE; + arg->internal.inarg++; /* Point to the next arg. */ + } + if ( !s[1] || dash_kludge ) + { + /* No more concatenated short options. */ + arg->internal.inarg = 0; + argc--; argv++; idx++; + } + } + else if ( arg->flags & ARGPARSE_FLAG_MIXED ) + { + arg->r_opt = ARGPARSE_IS_ARG; + arg->r_type = 2; + arg->r.ret_str = s; + argc--; argv++; idx++; /* Set to next one. */ + } + else + { + arg->internal.stopped = 1; /* Stop option processing. */ + goto next_one; + } + + leave: + *arg->argc = argc; + *arg->argv = argv; + arg->internal.idx = idx; + return arg->r_opt; +} + + +/* Returns: -1 on error, 0 for an integer type and 1 for a non integer + type argument. */ +static int +set_opt_arg (ARGPARSE_ARGS *arg, unsigned flags, char *s) +{ + int base = (flags & ARGPARSE_OPT_PREFIX)? 0 : 10; + long l; + + switch ( (arg->r_type = (flags & ARGPARSE_TYPE_MASK)) ) + { + case ARGPARSE_TYPE_LONG: + case ARGPARSE_TYPE_INT: + errno = 0; + l = strtol (s, NULL, base); + if ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE) + { + arg->r_opt = ARGPARSE_INVALID_ARG; + return -1; + } + if (arg->r_type == ARGPARSE_TYPE_LONG) + arg->r.ret_long = l; + else if ( (l < 0 && l < INT_MIN) || l > INT_MAX ) + { + arg->r_opt = ARGPARSE_INVALID_ARG; + return -1; + } + else + arg->r.ret_int = (int)l; + return 0; + + case ARGPARSE_TYPE_ULONG: + while (isascii (*s) && isspace(*s)) + s++; + if (*s == '-') + { + arg->r.ret_ulong = 0; + arg->r_opt = ARGPARSE_INVALID_ARG; + return -1; + } + errno = 0; + arg->r.ret_ulong = strtoul (s, NULL, base); + if (arg->r.ret_ulong == ULONG_MAX && errno == ERANGE) + { + arg->r_opt = ARGPARSE_INVALID_ARG; + return -1; + } + return 0; + + case ARGPARSE_TYPE_STRING: + default: + arg->r.ret_str = s; + return 1; + } +} + + +static size_t +long_opt_strlen( ARGPARSE_OPTS *o ) +{ + size_t n = strlen (o->long_opt); + + if ( o->description && *o->description == '|' ) + { + const char *s; + int is_utf8 = is_native_utf8 (); + + s=o->description+1; + if ( *s != '=' ) + n++; + /* For a (mostly) correct length calculation we exclude + continuation bytes (10xxxxxx) if we are on a native utf8 + terminal. */ + for (; *s && *s != '|'; s++ ) + if ( is_utf8 && (*s&0xc0) != 0x80 ) + n++; + } + return n; +} + + +/**************** + * Print formatted help. The description string has some special + * meanings: + * - A description string which is "@" suppresses help output for + * this option + * - a description,ine which starts with a '@' and is followed by + * any other characters is printed as is; this may be used for examples + * ans such. + * - A description which starts with a '|' outputs the string between this + * bar and the next one as arguments of the long option. + */ +static void +show_help (ARGPARSE_OPTS *opts, unsigned int flags) +{ + const char *s; + char tmp[2]; + + show_version (); + writestrings (0, "\n", NULL); + s = strusage (42); + if (s && *s == '1') + { + s = strusage (40); + writestrings (1, s, NULL); + if (*s && s[strlen(s)] != '\n') + writestrings (1, "\n", NULL); + } + s = strusage(41); + writestrings (0, s, "\n", NULL); + if ( opts[0].description ) + { + /* Auto format the option description. */ + int i,j, indent; + + /* Get max. length of long options. */ + for (i=indent=0; opts[i].short_opt; i++ ) + { + if ( opts[i].long_opt ) + if ( !opts[i].description || *opts[i].description != '@' ) + if ( (j=long_opt_strlen(opts+i)) > indent && j < 35 ) + indent = j; + } + + /* Example: " -v, --verbose Viele Sachen ausgeben" */ + indent += 10; + if ( *opts[0].description != '@' ) + writestrings (0, "Options:", "\n", NULL); + for (i=0; opts[i].short_opt; i++ ) + { + s = map_static_macro_string (_( opts[i].description )); + if ( s && *s== '@' && !s[1] ) /* Hide this line. */ + continue; + if ( s && *s == '@' ) /* Unindented comment only line. */ + { + for (s++; *s; s++ ) + { + if ( *s == '\n' ) + { + if( s[1] ) + writestrings (0, "\n", NULL); + } + else + { + tmp[0] = *s; + tmp[1] = 0; + writestrings (0, tmp, NULL); + } + } + writestrings (0, "\n", NULL); + continue; + } + + j = 3; + if ( opts[i].short_opt < 256 ) + { + tmp[0] = opts[i].short_opt; + tmp[1] = 0; + writestrings (0, " -", tmp, NULL ); + if ( !opts[i].long_opt ) + { + if (s && *s == '|' ) + { + writestrings (0, " ", NULL); j++; + for (s++ ; *s && *s != '|'; s++, j++ ) + { + tmp[0] = *s; + tmp[1] = 0; + writestrings (0, tmp, NULL); + } + if ( *s ) + s++; + } + } + } + else + writestrings (0, " ", NULL); + if ( opts[i].long_opt ) + { + tmp[0] = opts[i].short_opt < 256?',':' '; + tmp[1] = 0; + j += writestrings (0, tmp, " --", opts[i].long_opt, NULL); + if (s && *s == '|' ) + { + if ( *++s != '=' ) + { + writestrings (0, " ", NULL); + j++; + } + for ( ; *s && *s != '|'; s++, j++ ) + { + tmp[0] = *s; + tmp[1] = 0; + writestrings (0, tmp, NULL); + } + if ( *s ) + s++; + } + writestrings (0, " ", NULL); + j += 3; + } + for (;j < indent; j++ ) + writestrings (0, " ", NULL); + if ( s ) + { + if ( *s && j > indent ) + { + writestrings (0, "\n", NULL); + for (j=0;j < indent; j++ ) + writestrings (0, " ", NULL); + } + for (; *s; s++ ) + { + if ( *s == '\n' ) + { + if ( s[1] ) + { + writestrings (0, "\n", NULL); + for (j=0; j < indent; j++ ) + writestrings (0, " ", NULL); + } + } + else + { + tmp[0] = *s; + tmp[1] = 0; + writestrings (0, tmp, NULL); + } + } + } + writestrings (0, "\n", NULL); + } + if ( (flags & ARGPARSE_FLAG_ONEDASH) ) + writestrings (0, "\n(A single dash may be used " + "instead of the double ones)\n", NULL); + } + if ( (s=strusage(19)) ) + { + writestrings (0, "\n", NULL); + writestrings (0, s, NULL); + } + flushstrings (0); + exit(0); +} + +static void +show_version () +{ + const char *s; + int i; + + /* Version line. */ + writestrings (0, strusage (11), NULL); + if ((s=strusage (12))) + writestrings (0, " (", s, ")", NULL); + writestrings (0, " ", strusage (13), "\n", NULL); + /* Additional version lines. */ + for (i=20; i < 30; i++) + if ((s=strusage (i))) + writestrings (0, s, "\n", NULL); + /* Copyright string. */ + if ((s=strusage (14))) + writestrings (0, s, "\n", NULL); + /* Licence string. */ + if( (s=strusage (10)) ) + writestrings (0, s, "\n", NULL); + /* Copying conditions. */ + if ( (s=strusage(15)) ) + writestrings (0, s, NULL); + /* Thanks. */ + if ((s=strusage(18))) + writestrings (0, s, NULL); + /* Additional program info. */ + for (i=30; i < 40; i++ ) + if ( (s=strusage (i)) ) + writestrings (0, s, NULL); + flushstrings (0); +} + + +void +usage (int level) +{ + const char *p; + + if (!level) + { + writestrings (1, strusage(11), " ", strusage(13), "; ", + strusage (14), "\n", NULL); + flushstrings (1); + } + else if (level == 1) + { + p = strusage (40); + writestrings (1, p, NULL); + if (*p && p[strlen(p)] != '\n') + writestrings (1, "\n", NULL); + exit (2); + } + else if (level == 2) + { + p = strusage (42); + if (p && *p == '1') + { + p = strusage (40); + writestrings (1, p, NULL); + if (*p && p[strlen(p)] != '\n') + writestrings (1, "\n", NULL); + } + writestrings (0, strusage(41), "\n", NULL); + exit (0); + } +} + +/* Level + * 0: Print copyright string to stderr + * 1: Print a short usage hint to stderr and terminate + * 2: Print a long usage hint to stdout and terminate + * 10: Return license info string + * 11: Return the name of the program + * 12: Return optional name of package which includes this program. + * 13: version string + * 14: copyright string + * 15: Short copying conditions (with LFs) + * 16: Long copying conditions (with LFs) + * 17: Optional printable OS name + * 18: Optional thanks list (with LFs) + * 19: Bug report info + *20..29: Additional lib version strings. + *30..39: Additional program info (with LFs) + * 40: short usage note (with LF) + * 41: long usage note (with LF) + * 42: Flag string: + * First char is '1': + * The short usage notes needs to be printed + * before the long usage note. + */ +const char * +strusage( int level ) +{ + const char *p = strusage_handler? strusage_handler(level) : NULL; + + if ( p ) + return map_static_macro_string (p); + + switch ( level ) + { + + case 10: +#if ARGPARSE_GPL_VERSION == 3 + p = ("License GPLv3+: GNU GPL version 3 or later " + ""); +#else + p = ("License GPLv2+: GNU GPL version 2 or later " + ""); +#endif + break; + case 11: p = "foo"; break; + case 13: p = "0.0"; break; + case 14: p = ARGPARSE_CRIGHT_STR; break; + case 15: p = +"This is free software: you are free to change and redistribute it.\n" +"There is NO WARRANTY, to the extent permitted by law.\n"; + break; + case 16: p = +"This is free software; you can redistribute it and/or modify\n" +"it under the terms of the GNU General Public License as published by\n" +"the Free Software Foundation; either version " +ARGPARSE_STR2(ARGPARSE_GPL_VERSION) +" of the License, or\n" +"(at your option) any later version.\n\n" +"It is distributed in the hope that it will be useful,\n" +"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" +"GNU General Public License for more details.\n\n" +"You should have received a copy of the GNU General Public License\n" +"along with this software. If not, see .\n"; + break; + case 40: /* short and long usage */ + case 41: p = ""; break; + } + + return p; +} + + +/* Set the usage handler. This function is basically a constructor. */ +void +set_strusage ( const char *(*f)( int ) ) +{ + strusage_handler = f; +} + + +#ifdef TEST +static struct { + int verbose; + int debug; + char *outfile; + char *crf; + int myopt; + int echo; + int a_long_one; +} opt; + +int +main(int argc, char **argv) +{ + ARGPARSE_OPTS opts[] = { + ARGPARSE_x('v', "verbose", NONE, 0, "Laut sein"), + ARGPARSE_s_n('e', "echo" , ("Zeile ausgeben, damit wir sehen, " + "was wir eingegeben haben")), + ARGPARSE_s_n('d', "debug", "Debug\nfalls mal etwas\nschief geht"), + ARGPARSE_s_s('o', "output", 0 ), + ARGPARSE_o_s('c', "cross-ref", "cross-reference erzeugen\n" ), + /* Note that on a non-utf8 terminal the ß might garble the output. */ + ARGPARSE_s_n('s', "street","|Straße|set the name of the street to Straße"), + ARGPARSE_o_i('m', "my-option", 0), + ARGPARSE_s_n(500, "a-long-option", 0 ), + ARGPARSE_end() + }; + ARGPARSE_ARGS pargs = { &argc, &argv, (ARGPARSE_FLAG_ALL + | ARGPARSE_FLAG_MIXED + | ARGPARSE_FLAG_ONEDASH) }; + int i; + + while (arg_parse (&pargs, opts)) + { + switch (pargs.r_opt) + { + case ARGPARSE_IS_ARG : + printf ("arg='%s'\n", pargs.r.ret_str); + break; + case 'v': opt.verbose++; break; + case 'e': opt.echo++; break; + case 'd': opt.debug++; break; + case 'o': opt.outfile = pargs.r.ret_str; break; + case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break; + case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break; + case 500: opt.a_long_one++; break; + default : pargs.err = ARGPARSE_PRINT_WARNING; break; + } + } + for (i=0; i < argc; i++ ) + printf ("%3d -> (%s)\n", i, argv[i] ); + puts ("Options:"); + if (opt.verbose) + printf (" verbose=%d\n", opt.verbose ); + if (opt.debug) + printf (" debug=%d\n", opt.debug ); + if (opt.outfile) + printf (" outfile='%s'\n", opt.outfile ); + if (opt.crf) + printf (" crffile='%s'\n", opt.crf ); + if (opt.myopt) + printf (" myopt=%d\n", opt.myopt ); + if (opt.a_long_one) + printf (" a-long-one=%d\n", opt.a_long_one ); + if (opt.echo) + printf (" echo=%d\n", opt.echo ); + + return 0; +} +#endif /*TEST*/ + +/**** bottom of file ****/ diff --git a/src/argparse.h b/src/argparse.h new file mode 100644 index 00000000..10b838fe --- /dev/null +++ b/src/argparse.h @@ -0,0 +1,203 @@ +/* argparse.h - Argument parser for option handling. + * Copyright (C) 1998,1999,2000,2001,2006 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify it + * under the terms of either + * + * - the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at + * your option) any later version. + * + * or + * + * - the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * or both in parallel, as here. + * + * GnuPG is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copies of the GNU General Public License + * and the GNU Lesser General Public License along with this program; + * if not, see . + */ + +#ifndef GNUPG_COMMON_ARGPARSE_H +#define GNUPG_COMMON_ARGPARSE_H + +#include + +typedef struct +{ + int *argc; /* Pointer to ARGC (value subject to change). */ + char ***argv; /* Pointer to ARGV (value subject to change). */ + unsigned int flags; /* Global flags. May be set prior to calling the + parser. The parser may change the value. */ + int err; /* Print error description for last option. + Either 0, ARGPARSE_PRINT_WARNING or + ARGPARSE_PRINT_ERROR. */ + + int r_opt; /* Returns option code. */ + int r_type; /* Returns type of option value. */ + union { + int ret_int; + long ret_long; + unsigned long ret_ulong; + char *ret_str; + } r; /* Return values */ + + struct { + int idx; + int inarg; + int stopped; + const char *last; + void *aliases; + const void *cur_alias; + void *iio_list; + } internal; /* Private - do not change. */ +} ARGPARSE_ARGS; + +typedef struct +{ + int short_opt; + const char *long_opt; + unsigned int flags; + const char *description; /* Optional option description. */ +} ARGPARSE_OPTS; + + +/* Global flags (ARGPARSE_ARGS). */ +#define ARGPARSE_FLAG_KEEP 1 /* Do not remove options form argv. */ +#define ARGPARSE_FLAG_ALL 2 /* Do not stop at last option but return + remaining args with R_OPT set to -1. */ +#define ARGPARSE_FLAG_MIXED 4 /* Assume options and args are mixed. */ +#define ARGPARSE_FLAG_NOSTOP 8 /* Do not stop processing at "--". */ +#define ARGPARSE_FLAG_ARG0 16 /* Do not skip the first arg. */ +#define ARGPARSE_FLAG_ONEDASH 32 /* Allow long options with one dash. */ +#define ARGPARSE_FLAG_NOVERSION 64 /* No output for "--version". */ + +#define ARGPARSE_FLAG_STOP_SEEN 256 /* Set to true if a "--" has been seen. */ + +/* Flags for each option (ARGPARSE_OPTS). The type code may be + ORed with the OPT flags. */ +#define ARGPARSE_TYPE_NONE 0 /* Does not take an argument. */ +#define ARGPARSE_TYPE_INT 1 /* Takes an int argument. */ +#define ARGPARSE_TYPE_STRING 2 /* Takes a string argument. */ +#define ARGPARSE_TYPE_LONG 3 /* Takes a long argument. */ +#define ARGPARSE_TYPE_ULONG 4 /* Takes an unsigned long argument. */ +#define ARGPARSE_OPT_OPTIONAL (1<<3) /* Argument is optional. */ +#define ARGPARSE_OPT_PREFIX (1<<4) /* Allow 0x etc. prefixed values. */ +#define ARGPARSE_OPT_IGNORE (1<<6) /* Ignore command or option. */ +#define ARGPARSE_OPT_COMMAND (1<<7) /* The argument is a command. */ + +#define ARGPARSE_TYPE_MASK 7 /* Mask for the type values (internal). */ + +/* A set of macros to make option definitions easier to read. */ +#define ARGPARSE_x(s,l,t,f,d) \ + { (s), (l), ARGPARSE_TYPE_ ## t | (f), (d) } + +#define ARGPARSE_s(s,l,t,d) \ + { (s), (l), ARGPARSE_TYPE_ ## t, (d) } +#define ARGPARSE_s_n(s,l,d) \ + { (s), (l), ARGPARSE_TYPE_NONE, (d) } +#define ARGPARSE_s_i(s,l,d) \ + { (s), (l), ARGPARSE_TYPE_INT, (d) } +#define ARGPARSE_s_s(s,l,d) \ + { (s), (l), ARGPARSE_TYPE_STRING, (d) } +#define ARGPARSE_s_l(s,l,d) \ + { (s), (l), ARGPARSE_TYPE_LONG, (d) } +#define ARGPARSE_s_u(s,l,d) \ + { (s), (l), ARGPARSE_TYPE_ULONG, (d) } + +#define ARGPARSE_o(s,l,t,d) \ + { (s), (l), (ARGPARSE_TYPE_ ## t | ARGPARSE_OPT_OPTIONAL), (d) } +#define ARGPARSE_o_n(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_NONE | ARGPARSE_OPT_OPTIONAL), (d) } +#define ARGPARSE_o_i(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_INT | ARGPARSE_OPT_OPTIONAL), (d) } +#define ARGPARSE_o_s(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_STRING | ARGPARSE_OPT_OPTIONAL), (d) } +#define ARGPARSE_o_l(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_LONG | ARGPARSE_OPT_OPTIONAL), (d) } +#define ARGPARSE_o_u(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_ULONG | ARGPARSE_OPT_OPTIONAL), (d) } + +#define ARGPARSE_p(s,l,t,d) \ + { (s), (l), (ARGPARSE_TYPE_ ## t | ARGPARSE_OPT_PREFIX), (d) } +#define ARGPARSE_p_n(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_NONE | ARGPARSE_OPT_PREFIX), (d) } +#define ARGPARSE_p_i(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_INT | ARGPARSE_OPT_PREFIX), (d) } +#define ARGPARSE_p_s(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_STRING | ARGPARSE_OPT_PREFIX), (d) } +#define ARGPARSE_p_l(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_LONG | ARGPARSE_OPT_PREFIX), (d) } +#define ARGPARSE_p_u(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_ULONG | ARGPARSE_OPT_PREFIX), (d) } + +#define ARGPARSE_op(s,l,t,d) \ + { (s), (l), (ARGPARSE_TYPE_ ## t \ + | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) } +#define ARGPARSE_op_n(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_NONE \ + | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) } +#define ARGPARSE_op_i(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_INT \ + | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) } +#define ARGPARSE_op_s(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_STRING \ + | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) } +#define ARGPARSE_op_l(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_LONG \ + | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) } +#define ARGPARSE_op_u(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_ULONG \ + | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) } + +#define ARGPARSE_c(s,l,d) \ + { (s), (l), (ARGPARSE_TYPE_NONE | ARGPARSE_OPT_COMMAND), (d) } + +#define ARGPARSE_ignore(s,l) \ + { (s), (l), (ARGPARSE_OPT_IGNORE), "@" } + +#define ARGPARSE_group(s,d) \ + { (s), NULL, 0, (d) } + +#define ARGPARSE_end() { 0, NULL, 0, NULL } + + +/* Other constants. */ +#define ARGPARSE_PRINT_WARNING 1 +#define ARGPARSE_PRINT_ERROR 2 + + +/* Error values. */ +#define ARGPARSE_IS_ARG (-1) +#define ARGPARSE_INVALID_OPTION (-2) +#define ARGPARSE_MISSING_ARG (-3) +#define ARGPARSE_KEYWORD_TOO_LONG (-4) +#define ARGPARSE_READ_ERROR (-5) +#define ARGPARSE_UNEXPECTED_ARG (-6) +#define ARGPARSE_INVALID_COMMAND (-7) +#define ARGPARSE_AMBIGUOUS_OPTION (-8) +#define ARGPARSE_AMBIGUOUS_COMMAND (-9) +#define ARGPARSE_INVALID_ALIAS (-10) +#define ARGPARSE_OUT_OF_CORE (-11) +#define ARGPARSE_INVALID_ARG (-12) + + +int arg_parse (ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts); +int optfile_parse (FILE *fp, const char *filename, unsigned *lineno, + ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts); +void usage (int level); +const char *strusage (int level); +void set_strusage (const char *(*f)( int )); +void argparse_register_outfnc (int (*fnc)(int, const char *)); + +#endif /*GNUPG_COMMON_ARGPARSE_H*/ diff --git a/src/gpgme-tool.c b/src/gpgme-tool.c index e5e57073..557ed644 100644 --- a/src/gpgme-tool.c +++ b/src/gpgme-tool.c @@ -32,12 +32,10 @@ #ifdef HAVE_LOCALE_H #include #endif -#ifdef HAVE_ARGP_H -#include -#endif #include +#include "argparse.h" #include "gpgme.h" /* GCC attributes. */ @@ -59,421 +57,6 @@ #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1)) - -#ifndef HAVE_ARGP_H -/* Minimal argp implementation. */ - -/* Differences to ARGP: - argp_program_version: Required. - argp_program_bug_address: Required. - argp_program_version_hook: Not supported. - argp_err_exit_status: Required. - struct argp: Children and help_filter not supported. - argp_domain: Not supported. - struct argp_option: Group not supported. Options are printed in - order given. Flags OPTION_ALIAS, OPTION_DOC and OPTION_NO_USAGE - are not supported. - argp_parse: No flags are supported (ARGP_PARSE_ARGV0, ARGP_NO_ERRS, - ARGP_NO_ARGS, ARGP_IN_ORDER, ARGP_NO_HELP, ARGP_NO_EXIT, - ARGP_LONG_ONLY, ARGP_SILENT). ARGP must not be NULL. - argp_help: Flag ARGP_HELP_LONG_ONLY not supported. - argp_state: argc, argv, next may not be modified and should not be used. */ - -extern const char *argp_program_version; -extern const char *argp_program_bug_address; -extern error_t argp_err_exit_status; - -struct argp_option -{ - const char *name; - int key; - const char *arg; -#define OPTION_ARG_OPTIONAL 0x1 -#define OPTION_HIDDEN 0x2 - int flags; - const char *doc; - int group; -}; - -struct argp; -struct argp_state -{ - const struct argp *const root_argp; - int argc; - char **argv; - int next; - unsigned flags; - unsigned arg_num; - int quoted; - void *input; - void **child_inputs; - void *hook; - char *name; - FILE *err_stream; - FILE *out_stream; - void *pstate; -}; - -#ifdef EDEADLK -# define ARGP_ERR_UNKNOWN EDEADLK /* POSIX */ -#else -# define ARGP_ERR_UNKNOWN EDEADLOCK /* *GNU/kFreebsd does not define this) */ -#endif -#define ARGP_KEY_ARG 0 -#define ARGP_KEY_ARGS 0x1000006 -#define ARGP_KEY_END 0x1000001 -#define ARGP_KEY_NO_ARGS 0x1000002 -#define ARGP_KEY_INIT 0x1000003 -#define ARGP_KEY_FINI 0x1000007 -#define ARGP_KEY_SUCCESS 0x1000004 -#define ARGP_KEY_ERROR 0x1000005 -typedef error_t (*argp_parser_t) (int key, char *arg, struct argp_state *state); - -struct argp -{ - const struct argp_option *options; - argp_parser_t parser; - const char *args_doc; - const char *doc; - - const struct argp_child *children; - char *(*help_filter) (int key, const char *text, void *input); - const char *argp_domain; -}; - -#define ARGP_HELP_USAGE ARGP_HELP_SHORT_USAGE -#define ARGP_HELP_SHORT_USAGE 0x02 -#define ARGP_HELP_SEE 0x04 -#define ARGP_HELP_LONG 0x08 -#define ARGP_HELP_PRE_DOC 0x10 -#define ARGP_HELP_POST_DOC 0x20 -#define ARGP_HELP_DOC (ARGP_HELP_PRE_DOC | ARGP_HELP_POST_DOC) -#define ARGP_HELP_BUG_ADDR 0x40 -#define ARGP_HELP_EXIT_ERR 0x100 -#define ARGP_HELP_EXIT_OK 0x200 -#define ARGP_HELP_STD_ERR (ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR) -#define ARGP_HELP_STD_USAGE \ - (ARGP_HELP_SHORT_USAGE | ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR) -#define ARGP_HELP_STD_HELP \ - (ARGP_HELP_SHORT_USAGE | ARGP_HELP_LONG | ARGP_HELP_EXIT_OK \ - | ARGP_HELP_DOC | ARGP_HELP_BUG_ADDR) - - -void argp_error (const struct argp_state *state, - const char *fmt, ...) GT_GCC_A_PRINTF(2, 3); - - - -char * -_argp_pname (char *name) -{ - char *pname = name; - char *bname = strrchr (pname, '/'); - if (! bname) - bname = strrchr (pname, '\\'); - if (bname) - pname = bname + 1; - return pname; -} - - -void -_argp_state_help (const struct argp *argp, const struct argp_state *state, - FILE *stream, unsigned flags, char *name) -{ - if (state) - name = state->name; - - if (flags & ARGP_HELP_SHORT_USAGE) - fprintf (stream, "Usage: %s [OPTIONS...] %s\n", name, argp->args_doc); - if (flags & ARGP_HELP_SEE) - fprintf (stream, "Try `%s --help' or `%s --usage' for more information.\n", - name, name); - if (flags & ARGP_HELP_PRE_DOC) - { - char buf[1024]; - char *end; - strncpy (buf, argp->doc, sizeof (buf)); - buf[sizeof (buf) - 1] = '\0'; - end = strchr (buf, '\v'); - if (end) - *end = '\0'; - fprintf (stream, "%s\n%s", buf, buf[0] ? "\n" : ""); - } - if (flags & ARGP_HELP_LONG) - { - const struct argp_option *opt = argp->options; - while (opt->key) - { - #define NSPACES 29 - char spaces[NSPACES + 1] = " "; - int len = 0; - fprintf (stream, " "); - len += 2; - if (isascii (opt->key)) - { - fprintf (stream, "-%c", opt->key); - len += 2; - if (opt->name) - { - fprintf (stream, ", "); - len += 2; - } - } - if (opt->name) - { - fprintf (stream, "--%s", opt->name); - len += 2 + strlen (opt->name); - } - if (opt->arg && (opt->flags & OPTION_ARG_OPTIONAL)) - { - fprintf (stream, "[=%s]", opt->arg); - len += 3 + strlen (opt->arg); - } - else if (opt->arg) - { - fprintf (stream, "=%s", opt->arg); - len += 1 + strlen (opt->arg); - } - if (len >= NSPACES) - len = NSPACES - 1; - spaces[NSPACES - len] = '\0'; - fprintf (stream, "%s%s\n", spaces, opt->doc); - opt++; - } - fprintf (stream, " -?, --help Give this help list\n"); - fprintf (stream, " --usage Give a short usage " - "message\n"); - } - if (flags & ARGP_HELP_POST_DOC) - { - char buf[1024]; - char *end; - strncpy (buf, argp->doc, sizeof (buf)); - buf[sizeof (buf) - 1] = '\0'; - end = strchr (buf, '\v'); - if (end) - { - end++; - if (*end) - fprintf (stream, "\n%s\n", end); - } - fprintf (stream, "\nMandatory or optional arguments to long options are also mandatory or optional\n"); - fprintf (stream, "for any corresponding short options.\n"); - } - if (flags & ARGP_HELP_BUG_ADDR) - fprintf (stream, "\nReport bugs to %s.\n", argp_program_bug_address); - - if (flags & ARGP_HELP_EXIT_ERR) - exit (argp_err_exit_status); - if (flags & ARGP_HELP_EXIT_OK) - exit (0); -} - - -void -argp_usage (const struct argp_state *state) -{ - _argp_state_help (state->root_argp, state, state->err_stream, - ARGP_HELP_STD_USAGE, state->name); -} - - -void -argp_state_help (const struct argp_state *state, FILE *stream, unsigned flags) -{ - _argp_state_help (state->root_argp, state, stream, flags, state->name); -} - - -void -argp_error (const struct argp_state *state, const char *fmt, ...) -{ - va_list ap; - - fprintf (state->err_stream, "%s: ", state->name); - va_start (ap, fmt); - vfprintf (state->err_stream, fmt, ap); - va_end (ap); - fprintf (state->err_stream, "\n"); - argp_state_help (state, state->err_stream, ARGP_HELP_STD_ERR); - exit (argp_err_exit_status); -} - - -void -argp_help (const struct argp *argp, FILE *stream, unsigned flags, char *name) -{ - _argp_state_help (argp, NULL, stream, flags, name); -} - - -error_t -argp_parse (const struct argp *argp, int argc, - char **argv, unsigned flags, int *arg_index, void *input) -{ - int rc = 0; - struct argp_state state = { argp, argc, argv, 1, flags, 0, 0, input, - NULL, NULL, _argp_pname (argv[0]), - stderr, stdout, NULL }; - /* All non-option arguments are collected at the beginning of - &argv[1] during processing. This is a counter for their number. */ - int non_opt_args = 0; - - rc = argp->parser (ARGP_KEY_INIT, NULL, &state); - if (rc && rc != ARGP_ERR_UNKNOWN) - goto argperror; - - while (state.next < state.argc - non_opt_args) - { - int idx = state.next; - state.next++; - - if (! strcasecmp (state.argv[idx], "--")) - { - state.quoted = idx; - continue; - } - - if (state.quoted || state.argv[idx][0] != '-') - { - char *arg_saved = state.argv[idx]; - non_opt_args++; - memmove (&state.argv[idx], &state.argv[idx + 1], - (state.argc - 1 - idx) * sizeof (char *)); - state.argv[argc - 1] = arg_saved; - state.next--; - } - else if (! strcasecmp (state.argv[idx], "--help") - || !strcmp (state.argv[idx], "-?")) - { - argp_state_help (&state, state.out_stream, ARGP_HELP_STD_HELP); - } - else if (! strcasecmp (state.argv[idx], "--usage")) - { - argp_state_help (&state, state.out_stream, - ARGP_HELP_USAGE | ARGP_HELP_EXIT_OK); - } - else if (! strcasecmp (state.argv[idx], "--version") - || !strcmp (state.argv[idx], "-V")) - { - fprintf (state.out_stream, "%s\n", argp_program_version); - exit (0); - } - else - { - /* Search for option and call parser with its KEY. */ - int key = ARGP_KEY_ARG; /* Just some dummy value. */ - const struct argp_option *opt = argp->options; - char *arg = NULL; - int found = 0; - - /* Check for --opt=value syntax. */ - arg = strchr (state.argv[idx], '='); - if (arg) - { - *arg = '\0'; - arg++; - } - - if (state.argv[idx][1] != '-') - key = state.argv[idx][1]; - - while (! found && opt->key) - { - if (key == opt->key - || (key == ARGP_KEY_ARG - && ! strcasecmp (&state.argv[idx][2], opt->name))) - { - if (arg && !opt->arg) - argp_error (&state, "Option %s does not take an argument", - state.argv[idx]); - if (opt->arg && state.next < state.argc - && state.argv[idx + 1][0] != '-') - { - arg = state.argv[idx + 1]; - state.next++; - } - if (opt->arg && !(opt->flags & OPTION_ARG_OPTIONAL)) - argp_error (&state, "Option %s requires an argument", - state.argv[idx]); - - rc = argp->parser (opt->key, arg, &state); - if (rc == ARGP_ERR_UNKNOWN) - break; - else if (rc) - goto argperror; - found = 1; - } - opt++; - } - if (! found) - argp_error (&state, "Unknown option %s", state.argv[idx]); - } - } - - while (state.next < state.argc) - { - /* Call parser for all non-option args. */ - int idx = state.next; - state.next++; - rc = argp->parser (ARGP_KEY_ARG, state.argv[idx], &state); - if (rc && rc != ARGP_ERR_UNKNOWN) - goto argperror; - if (rc == ARGP_ERR_UNKNOWN) - { - int old_next = state.next; - rc = argp->parser (ARGP_KEY_ARGS, NULL, &state); - if (rc == ARGP_ERR_UNKNOWN) - { - argp_error (&state, "Too many arguments"); - goto argperror; - } - if (! rc && state.next == old_next) - { - state.arg_num += state.argc - state.next; - state.next = state.argc; - } - } - else - state.arg_num++; - } - - if (state.arg_num == 0) - { - rc = argp->parser (ARGP_KEY_NO_ARGS, NULL, &state); - if (rc && rc != ARGP_ERR_UNKNOWN) - goto argperror; - } - if (state.next == state.argc) - { - rc = argp->parser (ARGP_KEY_END, NULL, &state); - if (rc && rc != ARGP_ERR_UNKNOWN) - goto argperror; - } - rc = argp->parser (ARGP_KEY_FINI, NULL, &state); - if (rc && rc != ARGP_ERR_UNKNOWN) - goto argperror; - - rc = 0; - argp->parser (ARGP_KEY_SUCCESS, NULL, &state); - - argperror: - if (rc) - { - argp_error (&state, "unexpected error: %s", strerror (rc)); - argp->parser (ARGP_KEY_ERROR, NULL, &state); - } - - argp->parser (ARGP_KEY_FINI, NULL, &state); - - if (arg_index) - *arg_index = state.next - 1; - - return 0; -} -#endif - /* MEMBUF */ @@ -3722,85 +3305,51 @@ gpgme_server (gpgme_tool_t gt) -/* MAIN PROGRAM STARTS HERE. */ - -const char *argp_program_version = VERSION; -const char *argp_program_bug_address = "bug-gpgme@gnupg.org"; -error_t argp_err_exit_status = 1; - -static char doc[] = "GPGME Tool -- Assuan server exposing GPGME operations"; -static char args_doc[] = "COMMAND [OPTIONS...]"; - -static struct argp_option options[] = { - { "server", 's', 0, 0, "Server mode" }, - { "gpg-binary", 501, "FILE", 0, "Use FILE for the GPG backend" }, - { "lib-version", 502, 0, 0, "Show library version" }, - { 0 } -}; - -static error_t parse_options (int key, char *arg, struct argp_state *state); -static struct argp argp = { options, parse_options, args_doc, doc }; - -struct args -{ - enum { CMD_DEFAULT, CMD_SERVER, CMD_LIBVERSION } cmd; - const char *gpg_binary; -}; - -void -args_init (struct args *args) -{ - memset (args, '\0', sizeof (*args)); - args->cmd = CMD_DEFAULT; -} - - -static error_t -parse_options (int key, char *arg, struct argp_state *state) +static const char * +my_strusage( int level ) { - struct args *args = state->input; + const char *p; - switch (key) + switch (level) { - case 's': - args->cmd = CMD_SERVER; - break; - - case 501: - args->gpg_binary = arg; - break; - - case 502: - args->cmd = CMD_LIBVERSION; + case 11: p = "gpgme-tool"; break; + case 13: p = PACKAGE_VERSION; break; + case 14: p = "Copyright (C) 2015 g10 Code GmbH"; break; + case 19: p = "Please report bugs to <" PACKAGE_BUGREPORT ">.\n"; break; + case 1: + case 40: + p = "Usage: gpgme-tool [OPTIONS] [COMMANDS]"; break; - -#if 0 - case ARGP_KEY_ARG: - if (state->arg_num >= 2) - argp_usage (state); - printf ("Arg[%i] = %s\n", state->arg_num, arg); + case 41: + p = "GPGME Tool -- Assuan server exposing GPGME operations\n"; break; - case ARGP_KEY_END: - if (state->arg_num < 2) - argp_usage (state); + case 42: + p = "1"; /* Flag print 40 as part of 41. */ break; -#endif - - default: - return ARGP_ERR_UNKNOWN; + default: p = NULL; break; } - return 0; + return p; } - + int main (int argc, char *argv[]) { - struct args args; + static ARGPARSE_OPTS opts[] = { + ARGPARSE_c ('s', "server", "Server mode"), + ARGPARSE_s_s(501, "gpg-binary", "|FILE|Use FILE for the GPG backend"), + ARGPARSE_c (502, "lib-version", "Show library version"), + ARGPARSE_end() + }; + ARGPARSE_ARGS pargs = { &argc, &argv, 0 }; + enum { CMD_DEFAULT, CMD_SERVER, CMD_LIBVERSION } cmd = CMD_DEFAULT; + const char *gpg_binary = NULL; struct gpgme_tool gt; gpg_error_t err; int needgt = 1; + set_strusage (my_strusage); + #ifdef HAVE_SETLOCALE setlocale (LC_ALL, ""); #endif @@ -3812,30 +3361,40 @@ main (int argc, char *argv[]) gpgme_set_locale (NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL)); #endif - args_init (&args); - - argp_parse (&argp, argc, argv, 0, 0, &args); log_init (); - if (args.cmd == CMD_LIBVERSION) + while (arg_parse (&pargs, opts)) + { + switch (pargs.r_opt) + { + case 's': cmd = CMD_SERVER; break; + case 501: gpg_binary = pargs.r.ret_str; break; + case 502: cmd = CMD_LIBVERSION; break; + default: + pargs.err = ARGPARSE_PRINT_WARNING; + break; + } + } + + if (cmd == CMD_LIBVERSION) needgt = 0; - if (needgt && args.gpg_binary) + if (needgt && gpg_binary) { - if (access (args.gpg_binary, X_OK)) + if (access (gpg_binary, X_OK)) err = gpg_error_from_syserror (); else err = gpgme_set_engine_info (GPGME_PROTOCOL_OpenPGP, - args.gpg_binary, NULL); + gpg_binary, NULL); if (err) log_error (1, err, "error witching OpenPGP engine to '%s'", - args.gpg_binary); + gpg_binary); } if (needgt) gt_init (>); - switch (args.cmd) + switch (cmd) { case CMD_DEFAULT: case CMD_SERVER: @@ -3860,4 +3419,3 @@ main (int argc, char *argv[]) return 0; } - -- cgit v1.2.3 From 0d9d0a6b5b0c6f474a079bbaef11078c5df5f3b5 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Fri, 16 Oct 2015 09:51:42 +0900 Subject: cleanup: Fix type mismatch around gpgme_error_t. * src/data-compat.c (gpgme_error_to_errno): Use gpg_err_code to get error code from gpgme_error_t. * src/gpgme.c (gpgme_new): Don't use gpgme_error. --- src/data-compat.c | 2 +- src/gpgme.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/data-compat.c b/src/data-compat.c index 99827f16..abb78637 100644 --- a/src/data-compat.c +++ b/src/data-compat.c @@ -146,7 +146,7 @@ gpgme_data_new_from_file (gpgme_data_t *r_dh, const char *fname, int copy) static int gpgme_error_to_errno (gpgme_error_t err) { - int res = gpg_err_code_to_errno (err); + int res = gpg_err_code_to_errno (gpg_err_code (err)); if (!err) { diff --git a/src/gpgme.c b/src/gpgme.c index 343e7752..3c4e8e92 100644 --- a/src/gpgme.c +++ b/src/gpgme.c @@ -91,7 +91,7 @@ gpgme_new (gpgme_ctx_t *r_ctx) TRACE_BEG (DEBUG_CTX, "gpgme_new", r_ctx); if (_gpgme_selftest) - return TRACE_ERR (gpgme_error (_gpgme_selftest)); + return TRACE_ERR (_gpgme_selftest); if (!r_ctx) return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); -- cgit v1.2.3 From bb600aa8fd2f9575ee7afc64c978e3e7523b1173 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 28 Oct 2015 16:24:30 +0100 Subject: w32: Add new global flag "w32-inst-dir". * src/gpgme.c (gpgme_set_global_flag): Add flag "w32-inst-dir"; * src/posix-util.c (_gpgme_set_override_inst_dir): New stub. * src/w32-util.c (override_inst_dir): New var. (_gpgme_get_inst_dir): Return this var is set. (_gpgme_set_override_inst_dir): New. -- See https://lists.gnupg.org/pipermail/gnupg-devel/2015-September/030267.html for background. Signed-off-by: Werner Koch --- doc/gpgme.texi | 10 ++++++++++ src/gpgme.c | 2 ++ src/posix-util.c | 9 +++++++++ src/sys-util.h | 1 + src/w32-util.c | 30 +++++++++++++++++++++++++++++- 5 files changed, 51 insertions(+), 1 deletion(-) diff --git a/doc/gpgme.texi b/doc/gpgme.texi index a764ce42..1c680b51 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -701,6 +701,16 @@ directory part is used as the default installation directory; the @code{.exe} suffix is added by GPGME. Use forward slashed even under Windows. +@item "w32-inst-dir" +On Windows GPGME needs to know its installation directory to find its +spawn helper. This is in general no problem because a DLL has this +information. Some applications however link statically to GPGME and +thus GPGME can only figure out the installation directory of this +application which may be wrong in certain cases. By supplying an +installation directory as value to this flag, GPGME will assume that +that directory is the installation directory. This flag has no effect +on non-Windows platforms. + @end table This function returns @code{0} on success. In contrast to other diff --git a/src/gpgme.c b/src/gpgme.c index 3c4e8e92..0b42ea19 100644 --- a/src/gpgme.c +++ b/src/gpgme.c @@ -75,6 +75,8 @@ gpgme_set_global_flag (const char *name, const char *value) return _gpgme_set_default_gpgconf_name (value); else if (!strcmp (name, "gpg-name")) return _gpgme_set_default_gpg_name (value); + else if (!strcmp (name, "w32-inst-dir")) + return _gpgme_set_override_inst_dir (value); else return -1; } diff --git a/src/posix-util.c b/src/posix-util.c index f7e0a171..0fce5c29 100644 --- a/src/posix-util.c +++ b/src/posix-util.c @@ -71,6 +71,15 @@ _gpgme_set_default_gpgconf_name (const char *name) } +/* Dummy function - see w32-util.c for the actual code. */ +int +_gpgme_set_override_inst_dir (const char *dir) +{ + (void)dir; + return 0; +} + + /* Find an executable program PGM along the envvar PATH. */ static char * walk_path (const char *pgm) diff --git a/src/sys-util.h b/src/sys-util.h index 589634b2..541c5575 100644 --- a/src/sys-util.h +++ b/src/sys-util.h @@ -23,6 +23,7 @@ /*-- {posix,w32}-util.c --*/ int _gpgme_set_default_gpg_name (const char *name); int _gpgme_set_default_gpgconf_name (const char *name); +int _gpgme_set_override_inst_dir (const char *dir); char *_gpgme_get_gpg_path (void); char *_gpgme_get_gpgconf_path (void); diff --git a/src/w32-util.c b/src/w32-util.c index 9aba26f5..f611b6c0 100644 --- a/src/w32-util.c +++ b/src/w32-util.c @@ -85,7 +85,10 @@ static HMODULE my_hmodule; binaries. The are set only once by gpgme_set_global_flag. */ static char *default_gpg_name; static char *default_gpgconf_name; - +/* If this variable is not NULL the value is assumed to be the + installation directory. The variable may only be set once by + gpgme_set_global_flag and accessed by _gpgme_get_inst_dir. */ +static char *override_inst_dir; #ifdef HAVE_ALLOW_SET_FOREGROUND_WINDOW @@ -347,6 +350,9 @@ _gpgme_get_inst_dir (void) { static char *inst_dir; + if (override_inst_dir) + return override_inst_dir; + LOCK (get_path_lock); if (!inst_dir) { @@ -456,6 +462,28 @@ _gpgme_set_default_gpgconf_name (const char *name) } +/* Set the override installation directory. This function may only be + called by gpgme_set_global_flag. Returns 0 on success. */ +int +_gpgme_set_override_inst_dir (const char *dir) +{ + if (!override_inst_dir) + { + override_inst_dir = malloc (strlen (dir) + 1); + if (override_inst_dir) + { + strcpy (override_inst_dir, dir); + replace_slashes (override_inst_dir); + /* Remove a trailing slash. */ + if (*override_inst_dir + && override_inst_dir[strlen (override_inst_dir)-1] == '\\') + override_inst_dir[strlen (override_inst_dir)-1] = 0; + } + } + return !override_inst_dir; +} + + /* Return the full file name of the GPG binary. This function is used iff gpgconf was not found and thus it can be assumed that gpg2 is not installed. This function is only called by get_gpgconf_item -- cgit v1.2.3 From a82e9b182f62966207cad0972be6fa284329a5a1 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 28 Oct 2015 16:26:03 +0100 Subject: w32: Improve locating gpgconf on 64 bit systems. * src/w32-util.c (find_program_at_standard_place): Fallback to CSIDL_PROGRAM_FILESX86. Signed-off-by: Werner Koch --- src/w32-util.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/w32-util.c b/src/w32-util.c index f611b6c0..3600b28a 100644 --- a/src/w32-util.c +++ b/src/w32-util.c @@ -409,8 +409,13 @@ find_program_at_standard_place (const char *name) char path[MAX_PATH]; char *result = NULL; - /* See http://wiki.tcl.tk/17492 for details on compatibility. */ - if (SHGetSpecialFolderPathA (NULL, path, CSIDL_PROGRAM_FILES, 0)) + /* See http://wiki.tcl.tk/17492 for details on compatibility. + + We First try the generic place and then fallback to the x86 + (i.e. 32 bit) place. This will prefer a 64 bit of the program + over a 32 bit version on 64 bit Windows if installed. */ + if (SHGetSpecialFolderPathA (NULL, path, CSIDL_PROGRAM_FILES, 0) + || SHGetSpecialFolderPathA (NULL, path, CSIDL_PROGRAM_FILESX86, 0)) { result = malloc (strlen (path) + 1 + strlen (name) + 1); if (result) -- cgit v1.2.3 From bb2d11c1eebd4bcfb0f2cfce728026a7420dca47 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 28 Oct 2015 16:27:49 +0100 Subject: w32: Add extra diagnostic about possible missing gpgme-w32spawn.exe. * src/w32-io.c (_gpgme_io_spawn): Add a new diagnostic. Signed-off-by: Werner Koch --- src/w32-io.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/w32-io.c b/src/w32-io.c index 42961e31..a6d52388 100644 --- a/src/w32-io.c +++ b/src/w32-io.c @@ -1550,6 +1550,7 @@ _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags, int debug_me = 0; int tmp_fd; char *tmp_name; + const char *spawnhelper; TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path, "path=%s", path); @@ -1603,7 +1604,8 @@ _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags, if ((flags & IOSPAWN_FLAG_DETACHED)) cr_flags |= DETACHED_PROCESS; cr_flags |= GetPriorityClass (GetCurrentProcess ()); - if (!CreateProcessA (_gpgme_get_w32spawn_path (), + spawnhelper = _gpgme_get_w32spawn_path (); + if (!CreateProcessA (spawnhelper, arg_string, &sec_attr, /* process security attributes */ &sec_attr, /* thread security attributes */ @@ -1614,7 +1616,10 @@ _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags, &si, /* startup information */ &pi)) /* returns process information */ { - TRACE_LOG1 ("CreateProcess failed: ec=%d", (int) GetLastError ()); + int lasterr = (int)GetLastError (); + TRACE_LOG1 ("CreateProcess failed: ec=%d", lasterr); + if (lasterr == ERROR_INVALID_PARAMETER) + TRACE_LOG1 ("(is '%s' correctly installed?)", spawnhelper); free (arg_string); close (tmp_fd); DeleteFileA (tmp_name); -- cgit v1.2.3 From dfa79f9300b837b0f7f2ea44afa589bfcda1dbd9 Mon Sep 17 00:00:00 2001 From: Ben Kibbey Date: Wed, 28 Oct 2015 18:16:27 -0400 Subject: Make use of user passphrase handler during passwd. * src/passwd.c (passwd_start): set engine passphrase command handler. -- This allows for inquiring a passphrase when changing a passphrase rather than requiring a pinentry. --- src/passwd.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/passwd.c b/src/passwd.c index ff30df01..c34f3577 100644 --- a/src/passwd.c +++ b/src/passwd.c @@ -148,6 +148,14 @@ passwd_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t key, _gpgme_engine_set_status_handler (ctx->engine, passwd_status_handler, ctx); + if (ctx->passphrase_cb) + { + err = _gpgme_engine_set_command_handler + (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL); + if (err) + return err; + } + return _gpgme_engine_op_passwd (ctx->engine, key, flags); } -- cgit v1.2.3 From 8c61cbfb8ff2e1056840ecf8511810ed2482eb1f Mon Sep 17 00:00:00 2001 From: Justus Winter Date: Wed, 2 Dec 2015 11:28:07 +0100 Subject: Fix typos found by codespell. -- Signed-off-by: Justus Winter --- src/argparse.c | 2 +- src/funopen.c | 2 +- src/gpgme.h.in | 4 ++-- src/w32-glib-io.c | 2 +- src/w32-io.c | 4 ++-- src/wait-global.c | 4 ++-- src/wait-private.c | 6 +++--- tests/t-data.c | 2 +- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/argparse.c b/src/argparse.c index 53c20fca..b6abf86b 100644 --- a/src/argparse.c +++ b/src/argparse.c @@ -851,7 +851,7 @@ find_long_option( ARGPARSE_ARGS *arg, /* Would be better if we can do a binary search, but it is not possible to reorder our option table because we would mess up our help strings - What we can do is: Build a nice option - lookup table wehn this function is first invoked */ + lookup table when this function is first invoked */ if( !*keyword ) return -1; for(i=0; opts[i].short_opt; i++ ) diff --git a/src/funopen.c b/src/funopen.c index b71d3aed..b7220202 100644 --- a/src/funopen.c +++ b/src/funopen.c @@ -35,7 +35,7 @@ The functions to provide my either be NULL if not required or similar to the unistd function with the exception of using the - cookie instead of the fiel descripor. + cookie instead of the file descriptor. */ diff --git a/src/gpgme.h.in b/src/gpgme.h.in index e7216cbe..8264bab9 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -1518,7 +1518,7 @@ typedef enum GPGME_SIGSUM_CRL_MISSING = 0x0100, /* CRL not available. */ GPGME_SIGSUM_CRL_TOO_OLD = 0x0200, /* Available CRL is too old. */ GPGME_SIGSUM_BAD_POLICY = 0x0400, /* A policy was not met. */ - GPGME_SIGSUM_SYS_ERROR = 0x0800 /* A system error occured. */ + GPGME_SIGSUM_SYS_ERROR = 0x0800 /* A system error occurred. */ } gpgme_sigsum_t; @@ -1610,7 +1610,7 @@ struct _gpgme_import_status /* Fingerprint. */ char *fpr; - /* If a problem occured, the reason why the key could not be + /* If a problem occurred, the reason why the key could not be imported. Otherwise GPGME_No_Error. */ gpgme_error_t result; diff --git a/src/w32-glib-io.c b/src/w32-glib-io.c index a5af4e68..66dc9bf7 100644 --- a/src/w32-glib-io.c +++ b/src/w32-glib-io.c @@ -98,7 +98,7 @@ static struct FD is closed. This, together with the fact that dup'ed file descriptors are closed before the file descriptors from which they are dup'ed are closed, ensures that CHAN is always valid, - and shared among all file descriptors refering to the same + and shared among all file descriptors referring to the same underlying object. The logic behind this is that there is only one reason for us to diff --git a/src/w32-io.c b/src/w32-io.c index a6d52388..8e7abd32 100644 --- a/src/w32-io.c +++ b/src/w32-io.c @@ -74,7 +74,7 @@ static struct that dup'ed file descriptors are closed before the file descriptors from which they are dup'ed are closed, ensures that the handle or socket is always valid, and shared among all file - descriptors refering to the same underlying object. + descriptors referring to the same underlying object. The logic behind this is that there is only one reason for us to dup file descriptors anyway: to allow simpler book-keeping of @@ -978,7 +978,7 @@ _gpgme_io_write (int fd, const void *buffer, size_t count) return TRACE_SYSRES (-1); } - /* If no error occured, the number of bytes in the buffer must be + /* If no error occurred, the number of bytes in the buffer must be zero. */ assert (!ctx->nbytes); diff --git a/src/wait-global.c b/src/wait-global.c index f03775e2..28f3921f 100644 --- a/src/wait-global.c +++ b/src/wait-global.c @@ -206,7 +206,7 @@ _gpgme_wait_global_event_cb (void *data, gpgme_event_io_t type, gpgme_error_t err = ctx_active (ctx); if (err) - /* An error occured. Close all fds in this context, and + /* An error occurred. Close all fds in this context, and send the error in a done event. */ _gpgme_cancel_with_err (ctx, err, 0); } @@ -325,7 +325,7 @@ gpgme_wait_ext (gpgme_ctx_t ctx, gpgme_error_t *status, err = _gpgme_run_io_cb (&fdt.fds[i], 0, &local_op_err); if (err || local_op_err) { - /* An error occured. Close all fds in this context, + /* An error occurred. Close all fds in this context, and signal it. */ _gpgme_cancel_with_err (ictx, err, local_op_err); diff --git a/src/wait-private.c b/src/wait-private.c index 9a43110e..12d31805 100644 --- a/src/wait-private.c +++ b/src/wait-private.c @@ -89,7 +89,7 @@ _gpgme_wait_on_condition (gpgme_ctx_t ctx, volatile int *cond, if (nr < 0) { - /* An error occured. Close all fds in this context, and + /* An error occurred. Close all fds in this context, and signal it. */ err = gpg_error_from_syserror (); _gpgme_cancel_with_err (ctx, err, 0); @@ -116,7 +116,7 @@ _gpgme_wait_on_condition (gpgme_ctx_t ctx, volatile int *cond, err = _gpgme_run_io_cb (&ctx->fdt.fds[i], 0, &op_err); if (err) { - /* An error occured. Close all fds in this context, + /* An error occurred. Close all fds in this context, and signal it. */ _gpgme_cancel_with_err (ctx, err, 0); @@ -124,7 +124,7 @@ _gpgme_wait_on_condition (gpgme_ctx_t ctx, volatile int *cond, } else if (op_err) { - /* An operational error occured. Cancel the current + /* An operational error occurred. Cancel the current operation but not the session, and signal it. */ _gpgme_cancel_with_err (ctx, 0, op_err); diff --git a/tests/t-data.c b/tests/t-data.c index 888475fd..465f29ee 100644 --- a/tests/t-data.c +++ b/tests/t-data.c @@ -143,7 +143,7 @@ read_test (round_t round, gpgme_data_t data) read = gpgme_data_read (data, buffer, sizeof (buffer)); if (read > 0) { - fprintf (stderr, "%s:%d: (%i) gpgme_data_read succeded unexpectedly\n", + fprintf (stderr, "%s:%d: (%i) gpgme_data_read succeeded unexpectedly\n", __FILE__, __LINE__, round); exit (1); } -- cgit v1.2.3 From 3b6e9a3d0afcdd3c2f1de19f15924c3404c7140a Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Fri, 4 Dec 2015 17:55:09 +0900 Subject: doc: Fix minor errors * doc/gpgme.texi: Fix errors and typos in the cancellation and gpgme_import_result_t documentation. Signed-off-by: Daiki Ueno --- doc/gpgme.texi | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/doc/gpgme.texi b/doc/gpgme.texi index 1c680b51..db94617b 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -3810,7 +3810,7 @@ for the context @var{ctx}, or, if that is not set, by the encoding specified for @var{keydata}. The keys to export are taken form the @code{NULL} terminated array -@var{keys}. Only keys of the the currently selected protocol of +@var{keys}. Only keys of the currently selected protocol of @var{ctx} which do have a fingerprint set are considered for export. Other keys specified by the @var{keys} are ignored. In particular OpenPGP keys retrieved via an external key listing are not included. @@ -3883,7 +3883,7 @@ permanent which have been retrieved from an external source (i.e. using for the usual workaround of exporting and then importing a key to make an X.509 key permanent.} -Only keys of the the currently selected protocol of @var{ctx} are +Only keys of the currently selected protocol of @var{ctx} are considered for import. Other keys specified by the @var{keys} are ignored. As of now all considered keys must have been retrieved using the same method, that is the used key listing mode must be identical. @@ -3970,34 +3970,34 @@ The number of keys without user ID. @item int imported The total number of imported keys. -@item imported_rsa +@item int imported_rsa The number of imported RSA keys. -@item unchanged +@item int unchanged The number of unchanged keys. -@item new_user_ids +@item int new_user_ids The number of new user IDs. -@item new_sub_keys +@item int new_sub_keys The number of new sub keys. -@item new_signatures +@item int new_signatures The number of new signatures. -@item new_revocations +@item int new_revocations The number of new revocations. -@item secret_read +@item int secret_read The total number of secret keys read. -@item secret_imported +@item int secret_imported The number of imported secret keys. -@item secret_unchanged +@item int secret_unchanged The number of unchanged secret keys. -@item not_imported +@item int not_imported The number of keys not imported. @item gpgme_import_status_t imports @@ -6147,16 +6147,16 @@ operation in the context @var{ctx}. This only works if you use the global event loop or your own event loop. If you use the global event loop, you must not call @code{gpgme_wait} -or @code{gpgme_wait} during cancellation. After successful +during cancellation. After successful cancellation, you can call @code{gpgme_wait} (optionally waiting on @var{ctx}), and the context @var{ctx} will appear as if it had finished with the error code @code{GPG_ERR_CANCEL}. -If you use your an external event loop, you must ensure that no I/O +If you use an external event loop, you must ensure that no I/O callbacks are invoked for this context (for example by halting the event loop). On successful cancellation, all registered I/O callbacks for this context will be unregistered, and a @code{GPGME_EVENT_DONE} -event with the error code @code{GPG_ERR_CANCEL} will be signaled. +event with the error code @code{GPG_ERR_CANCEL} will be signalled. The function returns an error code if the cancellation failed (in this case the state of @var{ctx} is not modified). -- cgit v1.2.3 From 67d7f7a9383763b01daf877c846bf3e32f647fa5 Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Mon, 9 Nov 2015 13:13:50 +0900 Subject: Return on user cancellation of delete operation * src/delete.c (delete_status_handler): Return on ERROR status, if the error location is set to "delete_key.secret" and the code is either CANCELED or FULLY_CANCELED, which indicates a situation that the user selected "No" on the confirmation dialog. --- src/delete.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/delete.c b/src/delete.c index 37e54f89..d20a5bf6 100644 --- a/src/delete.c +++ b/src/delete.c @@ -68,6 +68,38 @@ delete_status_handler (void *priv, gpgme_status_code_t code, char *args) return gpg_error (GPG_ERR_GENERAL); } } + else if (code == GPGME_STATUS_ERROR) + { + /* Some error stati are informational, so we don't return an + error code if we are not ready to process this status. */ + gpgme_error_t err; + char *where = strchr (args, ' '); + char *which; + + if (where) + { + *where = '\0'; + which = where + 1; + + where = strchr (which, ' '); + if (where) + *where = '\0'; + + where = args; + } + else + return trace_gpg_error (GPG_ERR_INV_ENGINE); + + err = atoi (which); + + if (!strcmp (where, "delete_key.secret") + && (gpg_err_code (err) == GPG_ERR_CANCELED + || gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)) + { + /* This indicates a user cancellation on the confirmation dialog. */ + return gpg_error (gpg_err_code (err)); + } + } return 0; } -- cgit v1.2.3 From 83415dffaea53611dbce77b50d8ddfb2a50aed2e Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 9 Dec 2015 11:39:26 +0100 Subject: w32: Avoid conflict with Mingw-w64 version 4.0.4-1 * src/w32-util.c (mkstemp): Rename to my_mkstemp. Change caller. -- For some reason the linker seems to use the mkstemp now provided by mingw instead of our static symbol. Strange. Reported-by: Andrej Kacian Signed-off-by: Werner Koch --- src/w32-util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/w32-util.c b/src/w32-util.c index 3600b28a..a27955b5 100644 --- a/src/w32-util.c +++ b/src/w32-util.c @@ -647,7 +647,7 @@ static const char letters[] = does not exist at the time of the call to mkstemp. TMPL is overwritten with the result. */ static int -mkstemp (char *tmpl) +my_mkstemp (char *tmpl) { int len; char *XXXXXX; @@ -755,7 +755,7 @@ _gpgme_mkstemp (int *fd, char **name) if (!tmpname) return -1; strcpy (stpcpy (tmpname, tmp), "\\gpgme-XXXXXX"); - *fd = mkstemp (tmpname); + *fd = my_mkstemp (tmpname); if (fd < 0) { free (tmpname); -- cgit v1.2.3 From e79199468ac54ce4fe919603ff7bada97267174f Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 15 Jan 2016 16:16:38 +0100 Subject: Fix possible _SC_OPEN_MAX max problem on AIX. * src/posix-io.c [HAVE_STDINT_H]: Include stdint.h. (get_max_fds): Limit returned value for too high values. -- Signed-off-by: Werner Koch --- src/posix-io.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/posix-io.c b/src/posix-io.c index ac823fc8..e49c71ec 100644 --- a/src/posix-io.c +++ b/src/posix-io.c @@ -23,6 +23,9 @@ #endif #include #include +#ifdef HAVE_STDINT_H +# include +#endif #include #include #include @@ -331,6 +334,16 @@ get_max_fds (void) fds = 1024; } + /* AIX returns INT32_MAX instead of a proper value. We assume that + * this is always an error and use a more reasonable limit. */ +#ifdef INT32_MAX + if (fds == INT32_MAX) + { + source = "aix-fix"; + fds = 1024; + } +#endif + TRACE2 (DEBUG_SYSIO, "gpgme:max_fds", 0, "max fds=%i (%s)", fds, source); return fds; } -- cgit v1.2.3 From fc38c15136c87ce971a8381fa87399088dd5a3cc Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 10 May 2016 10:27:54 +0200 Subject: Allow cc to detect missing cases in a switch. * src/delete.c (delete_status_handler): Remove default case from a switch so that cc can check the use of all enum values. Signed-off-by: Werner Koch --- src/delete.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/delete.c b/src/delete.c index d20a5bf6..d7fdf50f 100644 --- a/src/delete.c +++ b/src/delete.c @@ -64,9 +64,9 @@ delete_status_handler (void *priv, gpgme_status_code_t code, char *args) case DELETE_Ambiguous_Specification: return gpg_error (GPG_ERR_AMBIGUOUS_NAME); - default: - return gpg_error (GPG_ERR_GENERAL); } + + return gpg_error (GPG_ERR_GENERAL); } else if (code == GPGME_STATUS_ERROR) { -- cgit v1.2.3