diff options
Diffstat (limited to '')
| -rw-r--r-- | ChangeLog | 4 | ||||
| -rw-r--r-- | configure.ac | 8 | ||||
| -rw-r--r-- | src/ChangeLog | 22 | ||||
| -rw-r--r-- | src/Makefile.am | 4 | ||||
| -rw-r--r-- | src/assuan-support.c | 27 | ||||
| -rw-r--r-- | src/conversion.c | 1 | ||||
| -rw-r--r-- | src/debug.h | 180 | ||||
| -rw-r--r-- | src/engine-assuan.c | 6 | ||||
| -rw-r--r-- | src/engine-g13.c | 4 | ||||
| -rw-r--r-- | src/g13.c | 19 | ||||
| -rw-r--r-- | src/gpgme-tool.c | 2012 | ||||
| -rw-r--r-- | src/gpgme.c | 18 | ||||
| -rw-r--r-- | src/ops.h | 5 | ||||
| -rw-r--r-- | src/signers.c | 13 | ||||
| -rw-r--r-- | src/version.c | 11 | 
15 files changed, 2214 insertions, 120 deletions
| @@ -1,3 +1,7 @@ +2009-10-30  Marcus Brinkmann  <[email protected]> + +	* configure.ac: Check for argp.h and error_t. +  2009-10-26  Marcus Brinkmann  <[email protected]>  	* configure.ac (NEED_GPG_VERSION_DEFAULT): Bump to 1.4.0 as 1.3.0 diff --git a/configure.ac b/configure.ac index 1d0be30a..3cd7c0b7 100644 --- a/configure.ac +++ b/configure.ac @@ -850,6 +850,14 @@ LTLIBOBJS=`echo "$LIB@&t@OBJS" |             sed 's,\.[[^.]]* ,.lo ,g;s,\.[[^.]]*$,.lo,'`  AC_SUBST(LTLIBOBJS) +# Some checks for gpgme-tool +AC_CHECK_HEADER([argp.h]) +AC_CHECK_TYPES([error_t], [], +   [AC_DEFINE([error_t], [int], +   [Define to a type to use for `error_t' if it is not otherwise available.])], +   [#include <errno.h>]) + +  # Last check.  die=no  if test "$require_libassuan" = "no"; then diff --git a/src/ChangeLog b/src/ChangeLog index 196be97c..40159107 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,25 @@ +2009-10-30  Marcus Brinkmann  <[email protected]> + +	* Makefile.am (noinst_PROGRAMS): New target gpgme-tool. +	(gpgme_tool_LDADD): New variable. +	* gpgme-tool.c: New file. +	* ops.h (_gpgme_sig_notation_clearm _gpgme_signers_clear): New +	prototypes. +	* gpgme.c (gpgme_set_protocol): Allow GPGME_PROTOCOL_GPGCONF (when +	had that gone missing?). +	(_gpgme_sig_notation_clear): New function without debug output. +	(gpgme_release): Call it and _gpgme_signers_clear. +	* signers.c (_gpgme_signers_clear): New function without debug output. +	* g13.c (gpgme_op_vfs_mount): Add debug output. +	* assuan-support.c (my_spawn): Allow fd_child_list to be NULL. +	* conversion.c (_gpgme_encode_percent_string): Fix infinite loop. +	* debug.h: Put tag in front of debug lines, should make for nicer +	output. +	* engine-assuan.c (llass_new): Use our new system hooks for libassuan. +	* engine-g13.c (g13_new): Remove redundant assuan context allocation. +	* version.c (gpgme_check_version_internal): Delay debug output +	until after gpgme_check_version was called. +  2009-10-28  Marcus Brinkmann  <[email protected]>  	* signers.c, encrypt-sign.c, encrypt.c, delete.c, keylist.c, diff --git a/src/Makefile.am b/src/Makefile.am index cf88ab1e..677a8969 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -153,7 +153,6 @@ if HAVE_W32_SYSTEM  # wrapper process.  libexec_PROGRAMS = gpgme-w32spawn -  LTRCCOMPILE = $(LIBTOOL) --mode=compile $(RC) \       `echo $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) | \       sed -e 's/-I/--include-dir /g;s/-D/--define /g'` @@ -226,6 +225,9 @@ libgpgme_qt_la_LIBADD = @LIBASSUAN_LIBS@ @LTLIBOBJS@ \  	@GPG_ERROR_LIBS@ @QT4_CORE_LIBS@  endif +noinst_PROGRAMS = gpgme-tool +gpgme_tool_LDADD = libgpgme.la +  status-table.h : gpgme.h  	$(srcdir)/mkstatus < $(builddir)/gpgme.h > status-table.h diff --git a/src/assuan-support.c b/src/assuan-support.c index cd9cbc41..b5d2548a 100644 --- a/src/assuan-support.c +++ b/src/assuan-support.c @@ -117,19 +117,25 @@ my_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name,      return gpg_error (GPG_ERR_NOT_IMPLEMENTED);    i = 0; -  while (fd_child_list[i] != ASSUAN_INVALID_FD) -    i++; +  if (fd_child_list) +    { +      while (fd_child_list[i] != ASSUAN_INVALID_FD) +	i++; +    }    /* fd_in, fd_out, terminator */    i += 3;    fd_items = malloc (sizeof (struct spawn_fd_item_s) * i);    if (! fd_items)      return gpg_error_from_syserror ();    i = 0; -  while (fd_child_list[i] != ASSUAN_INVALID_FD) +  if (fd_child_list)      { -      fd_items[i].fd = fd_child_list[i]; -      fd_items[i].dup_to = -1; -      i++; +      while (fd_child_list[i] != ASSUAN_INVALID_FD) +	{ +	  fd_items[i].fd = fd_child_list[i]; +	  fd_items[i].dup_to = -1; +	  i++; +	}      }    if (fd_in != ASSUAN_INVALID_FD)      { @@ -151,10 +157,13 @@ my_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name,      {        i = 0; -      while (fd_child_list[i] != ASSUAN_INVALID_FD) +      if (fd_child_list)  	{ -	  fd_child_list[i] = fd_items[i].peer_name; -	  i++; +	  while (fd_child_list[i] != ASSUAN_INVALID_FD) +	    { +	      fd_child_list[i] = fd_items[i].peer_name; +	      i++; +	    }  	}      }    free (fd_items); diff --git a/src/conversion.c b/src/conversion.c index 45513f67..538a5f82 100644 --- a/src/conversion.c +++ b/src/conversion.c @@ -272,6 +272,7 @@ _gpgme_encode_percent_string (const char *src, char **destp, size_t len)          destlen += 3;        else          destlen++; +      str++;      }    /* Terminating nul byte.  */    destlen++; diff --git a/src/debug.h b/src/debug.h index c4455b2e..ed93531f 100644 --- a/src/debug.h +++ b/src/debug.h @@ -89,155 +89,155 @@ void _gpgme_debug_buffer (int lvl, const char *const fmt,  #define TRACE_BEG(lvl, name, tag)			   \    _TRACE (lvl, name, tag);				   \ -  _gpgme_debug (_gpgme_trace_level, "%s (%s=%p): enter\n", \ -		_gpgme_trace_func, _gpgme_trace_tagname,   \ -		_gpgme_trace_tag), 0 +  _gpgme_debug (_gpgme_trace_level, "[%s=%p] %s: enter\n", \ +		_gpgme_trace_tagname, _gpgme_trace_tag,   \ +		_gpgme_trace_func), 0  #define TRACE_BEG0(lvl, name, tag, fmt)					\    _TRACE (lvl, name, tag);						\ -  _gpgme_debug (_gpgme_trace_level, "%s (%s=%p): enter: " fmt "\n",	\ -		_gpgme_trace_func, _gpgme_trace_tagname,		\ -		_gpgme_trace_tag), 0 +  _gpgme_debug (_gpgme_trace_level, "[%s=%p] %s: enter: " fmt "\n",	\ +		_gpgme_trace_tagname, _gpgme_trace_tag,		\ +		_gpgme_trace_func), 0  #define TRACE_BEG1(lvl, name, tag, fmt, arg1)				\    _TRACE (lvl, name, tag);						\ -  _gpgme_debug (_gpgme_trace_level, "%s (%s=%p): enter: " fmt "\n",	\ -		_gpgme_trace_func, _gpgme_trace_tagname,		\ -		_gpgme_trace_tag, arg1), 0 +  _gpgme_debug (_gpgme_trace_level, "[%s=%p] %s: enter: " fmt "\n",	\ +		_gpgme_trace_tagname, _gpgme_trace_tag,		\ +		_gpgme_trace_func, arg1), 0  #define TRACE_BEG2(lvl, name, tag, fmt, arg1, arg2)		    \    _TRACE (lvl, name, tag);					    \ -  _gpgme_debug (_gpgme_trace_level, "%s (%s=%p): enter: " fmt "\n", \ -		_gpgme_trace_func, _gpgme_trace_tagname,	    \ -		_gpgme_trace_tag, arg1, arg2), 0 +  _gpgme_debug (_gpgme_trace_level, "[%s=%p] %s: enter: " fmt "\n", \ +		_gpgme_trace_tagname, _gpgme_trace_tag,	    \ +		_gpgme_trace_func, arg1, arg2), 0  #define TRACE_BEG3(lvl, name, tag, fmt, arg1, arg2, arg3)	    \    _TRACE (lvl, name, tag);					    \ -  _gpgme_debug (_gpgme_trace_level, "%s (%s=%p): enter: " fmt "\n", \ -		_gpgme_trace_func, _gpgme_trace_tagname,	    \ -		_gpgme_trace_tag, arg1, arg2, arg3), 0 +  _gpgme_debug (_gpgme_trace_level, "[%s=%p] %s: enter: " fmt "\n", \ +		_gpgme_trace_tagname, _gpgme_trace_tag,	    \ +		_gpgme_trace_func, arg1, arg2, arg3), 0  #define TRACE_BEG4(lvl, name, tag, fmt, arg1, arg2, arg3, arg4)	    \    _TRACE (lvl, name, tag);					    \ -  _gpgme_debug (_gpgme_trace_level, "%s (%s=%p): enter: " fmt "\n", \ -		_gpgme_trace_func, _gpgme_trace_tagname,	    \ -		_gpgme_trace_tag, arg1, arg2, arg3, arg4), 0 +  _gpgme_debug (_gpgme_trace_level, "[%s=%p] %s: enter: " fmt "\n", \ +		_gpgme_trace_tagname, _gpgme_trace_tag,	    \ +		_gpgme_trace_func, arg1, arg2, arg3, arg4), 0  #define TRACE_BEG5(lvl, name, tag, fmt, arg1, arg2, arg3, arg4, arg5) \    _TRACE (lvl, name, tag);					    \ -  _gpgme_debug (_gpgme_trace_level, "%s (%s=%p): enter: " fmt "\n", \ -		_gpgme_trace_func, _gpgme_trace_tagname,	    \ -		_gpgme_trace_tag, arg1, arg2, arg3, arg4, arg5), 0 +  _gpgme_debug (_gpgme_trace_level, "[%s=%p] %s: enter: " fmt "\n", \ +		_gpgme_trace_tagname, _gpgme_trace_tag,	    \ +		_gpgme_trace_func, arg1, arg2, arg3, arg4, arg5), 0  #define TRACE_BEG7(lvl, name, tag, fmt, arg1, arg2, arg3, arg4,	    \  		   arg5, arg6, arg7)				    \    _TRACE (lvl, name, tag);					    \ -  _gpgme_debug (_gpgme_trace_level, "%s (%s=%p): enter: " fmt "\n", \ -		_gpgme_trace_func, _gpgme_trace_tagname,	    \ -		_gpgme_trace_tag, arg1, arg2, arg3, arg4, arg5,	    \ +  _gpgme_debug (_gpgme_trace_level, "[%s=%p] %s: enter: " fmt "\n", \ +		_gpgme_trace_tagname, _gpgme_trace_tag,	    \ +		_gpgme_trace_func, arg1, arg2, arg3, arg4, arg5,	    \  		arg6, arg7), 0  #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 (%s=%p): enter: " fmt "\n", \ -		_gpgme_trace_func, _gpgme_trace_tagname,	    \ -		_gpgme_trace_tag, arg1, arg2, arg3, arg4, arg5,	    \ +  _gpgme_debug (_gpgme_trace_level, "[%s=%p] %s: enter: " fmt "\n", \ +		_gpgme_trace_tagname, _gpgme_trace_tag,	    \ +		_gpgme_trace_func, arg1, arg2, arg3, arg4, arg5,	    \  		arg6, arg7, arg8), 0  #define TRACE(lvl, name, tag)						\ -  _gpgme_debug (lvl, "%s (%s=%p): call\n",				\ -		name, STRINGIFY (tag), (void *) (uintptr_t) tag), 0 +  _gpgme_debug (lvl, "[%s=%p] %s: call\n",				\ +		STRINGIFY (tag), (void *) (uintptr_t) tag, name), 0  #define TRACE0(lvl, name, tag, fmt)					\ -  _gpgme_debug (lvl, "%s (%s=%p): call: " fmt "\n",			\ -		name, STRINGIFY (tag), (void *) (uintptr_t) tag), 0 +  _gpgme_debug (lvl, "[%s=%p] %s: call: " fmt "\n",			\ +		STRINGIFY (tag), (void *) (uintptr_t) tag, name), 0  #define TRACE1(lvl, name, tag, fmt, arg1)			       \ -  _gpgme_debug (lvl, "%s (%s=%p): call: " fmt "\n",		       \ -		name, STRINGIFY (tag), (void *) (uintptr_t) tag, arg1), 0 +  _gpgme_debug (lvl, "[%s=%p] %s: call: " fmt "\n",		       \ +		STRINGIFY (tag), (void *) (uintptr_t) tag, name, arg1), 0  #define TRACE2(lvl, name, tag, fmt, arg1, arg2)			       \ -  _gpgme_debug (lvl, "%s (%s=%p): call: " fmt "\n",		       \ -		name, STRINGIFY (tag), (void *) (uintptr_t) tag, arg1, \ +  _gpgme_debug (lvl, "[%s=%p] %s: call: " fmt "\n",		       \ +		STRINGIFY (tag), (void *) (uintptr_t) tag, name, arg1, \  		arg2), 0  #define TRACE3(lvl, name, tag, fmt, arg1, arg2, arg3)		       \ -  _gpgme_debug (lvl, "%s (%s=%p): call: " fmt "\n",		       \ -		name, STRINGIFY (tag), (void *) (uintptr_t) tag, arg1, \ +  _gpgme_debug (lvl, "[%s=%p] %s: call: " fmt "\n",		       \ +		STRINGIFY (tag), (void *) (uintptr_t) tag, name, arg1, \  		arg2, arg3), 0  #define TRACE6(lvl, name, tag, fmt, arg1, arg2, arg3, arg4, arg5, arg6)	\ -  _gpgme_debug (lvl, "%s (%s=%p): call: " fmt "\n",			\ -		name, STRINGIFY (tag), (void *) (uintptr_t) tag, arg1,  \ +  _gpgme_debug (lvl, "[%s=%p] %s: call: " fmt "\n",			\ +		STRINGIFY (tag), (void *) (uintptr_t) tag, name, arg1,  \  		arg2, arg3, arg4, arg5, arg6), 0  #define TRACE_ERR(err)							\    err == 0 ? (TRACE_SUC ()) :						\ -    (_gpgme_debug (_gpgme_trace_level, "%s (%s=%p): error: %s <%s>\n",	\ -		   _gpgme_trace_func, _gpgme_trace_tagname,		\ -		   _gpgme_trace_tag, gpgme_strerror (err),		\ +    (_gpgme_debug (_gpgme_trace_level, "[%s=%p] %s: error: %s <%s>\n",	\ +		   _gpgme_trace_tagname, _gpgme_trace_tag,		\ +		   _gpgme_trace_func, gpgme_strerror (err),		\  		   gpgme_strsource (err)), (err))  /* The cast to void suppresses GCC warnings.  */  #define TRACE_SYSRES(res)						\    res >= 0 ? ((void) (TRACE_SUC1 ("result=%i", res)), (res)) :		\ -    (_gpgme_debug (_gpgme_trace_level, "%s (%s=%p): error: %s\n",	\ -		   _gpgme_trace_func, _gpgme_trace_tagname,		\ -		   _gpgme_trace_tag, strerror (errno)), (res)) +    (_gpgme_debug (_gpgme_trace_level, "[%s=%p] %s: error: %s\n",	\ +		   _gpgme_trace_tagname, _gpgme_trace_tag,		\ +		   _gpgme_trace_func, strerror (errno)), (res))  #define TRACE_SYSERR(res)						\    res == 0 ? ((void) (TRACE_SUC1 ("result=%i", res)), (res)) :		\ -    (_gpgme_debug (_gpgme_trace_level, "%s (%s=%p): error: %s\n",	\ -		   _gpgme_trace_func, _gpgme_trace_tagname,		\ -		   _gpgme_trace_tag, strerror (res)), (res)) +    (_gpgme_debug (_gpgme_trace_level, "[%s=%p] %s: error: %s\n",	\ +		   _gpgme_trace_tagname, _gpgme_trace_tag,		\ +		   _gpgme_trace_func, strerror (res)), (res))  #define TRACE_SUC()						 \ -  _gpgme_debug (_gpgme_trace_level, "%s (%s=%p): leave\n",       \ -		_gpgme_trace_func, _gpgme_trace_tagname,	 \ -		_gpgme_trace_tag), 0 +  _gpgme_debug (_gpgme_trace_level, "[%s=%p] %s: leave\n",       \ +		_gpgme_trace_tagname, _gpgme_trace_tag,	 \ +		_gpgme_trace_func), 0  #define TRACE_SUC0(fmt)							\ -  _gpgme_debug (_gpgme_trace_level, "%s (%s=%p): leave: " fmt "\n",	\ -		_gpgme_trace_func, _gpgme_trace_tagname,		\ -		_gpgme_trace_tag), 0 +  _gpgme_debug (_gpgme_trace_level, "[%s=%p] %s: leave: " fmt "\n",	\ +		_gpgme_trace_tagname, _gpgme_trace_tag,		\ +		_gpgme_trace_func), 0  #define TRACE_SUC1(fmt, arg1)						\ -  _gpgme_debug (_gpgme_trace_level, "%s (%s=%p): leave: " fmt "\n",	\ -		_gpgme_trace_func, _gpgme_trace_tagname,		\ -		_gpgme_trace_tag, arg1), 0 +  _gpgme_debug (_gpgme_trace_level, "[%s=%p] %s: leave: " fmt "\n",	\ +		_gpgme_trace_tagname, _gpgme_trace_tag,		\ +		_gpgme_trace_func, arg1), 0  #define TRACE_SUC2(fmt, arg1, arg2)					\ -  _gpgme_debug (_gpgme_trace_level, "%s (%s=%p): leave: " fmt "\n",	\ -		_gpgme_trace_func, _gpgme_trace_tagname,		\ -		_gpgme_trace_tag, arg1, arg2), 0 +  _gpgme_debug (_gpgme_trace_level, "[%s=%p] %s: leave: " fmt "\n",	\ +		_gpgme_trace_tagname, _gpgme_trace_tag,		\ +		_gpgme_trace_func, arg1, arg2), 0  #define TRACE_SUC5(fmt, arg1, arg2, arg3, arg4, arg5)			\ -  _gpgme_debug (_gpgme_trace_level, "%s (%s=%p): leave: " fmt "\n",	\ -		_gpgme_trace_func, _gpgme_trace_tagname,		\ -		_gpgme_trace_tag, arg1, arg2, arg3, arg4, arg5), 0 +  _gpgme_debug (_gpgme_trace_level, "[%s=%p] %s: leave: " fmt "\n",	\ +		_gpgme_trace_tagname, _gpgme_trace_tag,		\ +		_gpgme_trace_func, arg1, arg2, arg3, arg4, arg5), 0  #define TRACE_LOG(fmt)							\ -  _gpgme_debug (_gpgme_trace_level, "%s (%s=%p): check: " fmt "\n",	\ -		_gpgme_trace_func, _gpgme_trace_tagname,		\ -		_gpgme_trace_tag), 0 +  _gpgme_debug (_gpgme_trace_level, "[%s=%p] %s: check: " fmt "\n",	\ +		_gpgme_trace_tagname, _gpgme_trace_tag,		\ +		_gpgme_trace_func), 0  #define TRACE_LOG1(fmt, arg1)						\ -  _gpgme_debug (_gpgme_trace_level, "%s (%s=%p): check: " fmt "\n",	\ -		_gpgme_trace_func, _gpgme_trace_tagname,		\ -		_gpgme_trace_tag, arg1), 0 +  _gpgme_debug (_gpgme_trace_level, "[%s=%p] %s: check: " fmt "\n",	\ +		_gpgme_trace_tagname, _gpgme_trace_tag,		\ +		_gpgme_trace_func, arg1), 0  #define TRACE_LOG2(fmt, arg1, arg2)				    \ -  _gpgme_debug (_gpgme_trace_level, "%s (%s=%p): check: " fmt "\n", \ -		_gpgme_trace_func, _gpgme_trace_tagname,	    \ -		_gpgme_trace_tag, arg1, arg2), 0 +  _gpgme_debug (_gpgme_trace_level, "[%s=%p] %s: check: " fmt "\n", \ +		_gpgme_trace_tagname, _gpgme_trace_tag,	    \ +		_gpgme_trace_func, arg1, arg2), 0  #define TRACE_LOG3(fmt, arg1, arg2, arg3)			    \ -  _gpgme_debug (_gpgme_trace_level, "%s (%s=%p): check: " fmt "\n", \ -		_gpgme_trace_func, _gpgme_trace_tagname,	    \ -		_gpgme_trace_tag, arg1, arg2, arg3), 0 +  _gpgme_debug (_gpgme_trace_level, "[%s=%p] %s: check: " fmt "\n", \ +		_gpgme_trace_tagname, _gpgme_trace_tag,	    \ +		_gpgme_trace_func, arg1, arg2, arg3), 0  #define TRACE_LOG4(fmt, arg1, arg2, arg3, arg4)			    \ -  _gpgme_debug (_gpgme_trace_level, "%s (%s=%p): check: " fmt "\n", \ -		_gpgme_trace_func, _gpgme_trace_tagname,	    \ -		_gpgme_trace_tag, arg1, arg2, arg3, arg4), 0 +  _gpgme_debug (_gpgme_trace_level, "[%s=%p] %s: check: " fmt "\n", \ +		_gpgme_trace_tagname, _gpgme_trace_tag,	    \ +		_gpgme_trace_func, arg1, arg2, arg3, arg4), 0  #define TRACE_LOG5(fmt, arg1, arg2, arg3, arg4, arg5)		    \ -  _gpgme_debug (_gpgme_trace_level, "%s (%s=%p): check: " fmt "\n", \ -		_gpgme_trace_func, _gpgme_trace_tagname,	    \ -		_gpgme_trace_tag, arg1, arg2, arg3, arg4, arg5), 0 +  _gpgme_debug (_gpgme_trace_level, "[%s=%p] %s: check: " fmt "\n", \ +		_gpgme_trace_tagname, _gpgme_trace_tag,	    \ +		_gpgme_trace_func, arg1, arg2, arg3, arg4, arg5), 0  #define TRACE_LOG6(fmt, arg1, arg2, arg3, arg4, arg5, arg6)	    \ -  _gpgme_debug (_gpgme_trace_level, "%s (%s=%p): check: " fmt "\n", \ -		_gpgme_trace_func, _gpgme_trace_tagname,	    \ -		_gpgme_trace_tag, arg1, arg2, arg3, arg4, arg5,	    \ +  _gpgme_debug (_gpgme_trace_level, "[%s=%p] %s: check: " fmt "\n", \ +		_gpgme_trace_tagname, _gpgme_trace_tag,	    \ +		_gpgme_trace_func, arg1, arg2, arg3, arg4, arg5,	    \  		arg6), 0  #define TRACE_LOGBUF(buf, len)						\ -  _gpgme_debug_buffer (_gpgme_trace_level, "%s (%s=%p): check: %s",	\ -		       _gpgme_trace_func, _gpgme_trace_tagname,		\ -		       _gpgme_trace_tag, buf, len) +  _gpgme_debug_buffer (_gpgme_trace_level, "[%s=%p] %s: check: %s",	\ +		       _gpgme_trace_tagname, _gpgme_trace_tag,		\ +		       _gpgme_trace_func, buf, len)  #define TRACE_SEQ(hlp,fmt)						\    _gpgme_debug_begin (&(hlp), _gpgme_trace_level,			\ -		      "%s (%s=%p): check: " fmt,			\ -		      _gpgme_trace_func, _gpgme_trace_tagname,		\ -		      _gpgme_trace_tag) +		      "[%s=%p] %s: check: " fmt,			\ +		      _gpgme_trace_tagname, _gpgme_trace_tag,		\ +		      _gpgme_trace_func)  #define TRACE_ADD0(hlp,fmt) \    _gpgme_debug_add (&(hlp), fmt)  #define TRACE_ADD1(hlp,fmt,a) \ diff --git a/src/engine-assuan.c b/src/engine-assuan.c index 92e1e05d..38fb1adb 100644 --- a/src/engine-assuan.c +++ b/src/engine-assuan.c @@ -233,9 +233,13 @@ llass_new (void **engine, const char *file_name, const char *home_dir)          llass->opt.gpg_agent = 1;      } -  err = assuan_new (&llass->assuan_ctx); +  err = assuan_new_ext (&llass->assuan_ctx, GPG_ERR_SOURCE_GPGME, +			&_gpgme_assuan_malloc_hooks, _gpgme_assuan_log_cb, +			NULL);    if (err)      goto leave; +  assuan_ctx_set_system_hooks (llass->assuan_ctx, &_gpgme_assuan_system_hooks); +    err = assuan_socket_connect (llass->assuan_ctx, file_name, 0);    if (err)      goto leave; diff --git a/src/engine-g13.c b/src/engine-g13.c index 358efc17..34c6ac16 100644 --- a/src/engine-g13.c +++ b/src/engine-g13.c @@ -230,10 +230,6 @@ g13_new (void **engine, const char *file_name, const char *home_dir)    g13->status_cb.tag = 0;    g13->status_cb.data = g13; -  err = assuan_new (&g13->assuan_ctx); -  if (err) -    goto leave; -    argc = 0;    argv[argc++] = "g13";    if (home_dir) @@ -25,6 +25,7 @@  #include <stdlib.h>  #include "gpgme.h" +#include "debug.h"  #include "context.h"  #include "ops.h"  #include "util.h" @@ -135,9 +136,9 @@ gpgme_op_vfs_transact (gpgme_ctx_t ctx,     or destroyed.  This is a synchronous convenience interface, which     automatically returns an operation error if there is no     transmission error.  */ -gpgme_error_t -gpgme_op_vfs_mount (gpgme_ctx_t ctx, const char *container_file, -		    const char *mount_dir, int flags, gpgme_error_t *op_err) +static gpgme_error_t +_gpgme_op_vfs_mount (gpgme_ctx_t ctx, const char *container_file, +		     const char *mount_dir, int flags, gpgme_error_t *op_err)  {    gpg_error_t err;    char *cmd; @@ -194,3 +195,15 @@ gpgme_op_vfs_mount (gpgme_ctx_t ctx, const char *container_file,    return err;  } + +gpgme_error_t +gpgme_op_vfs_mount (gpgme_ctx_t ctx, const char *container_file, +		     const char *mount_dir, int flags, gpgme_error_t *op_err) +{ +  TRACE_BEG4 (DEBUG_CTX, "gpgme_op_vfs_mount", ctx, +	      "container=%s, mount_dir=%s, flags=0x%x, op_err=%p", +	      container_file, mount_dir, flags, op_err); +  return TRACE_ERR (_gpgme_op_vfs_mount (ctx, container_file, mount_dir, +					 flags, op_err)); +} + diff --git a/src/gpgme-tool.c b/src/gpgme-tool.c new file mode 100644 index 00000000..08cd82a9 --- /dev/null +++ b/src/gpgme-tool.c @@ -0,0 +1,2012 @@ +/* gpgme-tool.c - GnuPG Made Easy. +   Copyright (C) 2000 Werner Koch (dd9jn) +   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007 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, write to the Free Software +   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +   02111-1307, USA.  */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <getopt.h> +#include <ctype.h> +#include <stdarg.h> +#include <locale.h> +#ifdef HAVE_ARGP_H +#include <argp.h> +#endif + +#include "gpgme.h" + + +#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; +}; + +#define ARGP_ERR_UNKNOWN E2BIG +#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) + + +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", state.argv[idx]); +	      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 + + +/* SUPPORT.  */ +FILE *log_stream; +char *program_name = "gpgme-tool"; + +void +log_init (void) +{ +  log_stream = stderr; +} + + +void +log_error (int status, gpg_error_t errnum, const char *fmt, ...) +{ +  va_list ap; + +  fprintf (log_stream, "%s: ", program_name); +  va_start (ap, fmt); +  vfprintf (log_stream, fmt, ap); +  va_end (ap); +  if (errnum) +    fprintf (log_stream, ": %s <%s>", gpg_strerror (errnum), +	     gpg_strsource (errnum)); +  fprintf (log_stream, "\n"); +  if (status) +    exit (status); +} + + + +typedef enum status +  { +    STATUS_PROTOCOL, +    STATUS_PROGRESS, +    STATUS_ENGINE, +    STATUS_ARMOR, +    STATUS_TEXTMODE, +    STATUS_INCLUDE_CERTS, +    STATUS_KEYLIST_MODE, +    STATUS_ENCRYPT_RESULT +  } status_t; + +const char *status_string[] = +  { +    "PROTOCOL", +    "PROGRESS", +    "ENGINE", +    "ARMOR", +    "TEXTMODE", +    "INCLUDE_CERTS", +    "KEYLIST_MODE", +    "ENCRYPT_RESULT" +  }; + +struct gpgme_tool +{ +  gpgme_ctx_t ctx; +#define MAX_RECIPIENTS 10 +  gpgme_key_t recipients[MAX_RECIPIENTS + 1]; +  int recipients_nr; + +  gpg_error_t (*write_status) (void *hook, const char *status, const char *msg); +  void *write_status_hook; +}; +typedef struct gpgme_tool *gpgme_tool_t; + + +/* Forward declaration.  */ +void gt_write_status (gpgme_tool_t gt, status_t status, ...); + +void +_gt_progress_cb (void *opaque, const char *what, +		 int type, int current, int total) +{ +  gpgme_tool_t gt = opaque; +  char buf[100]; + +  snprintf (buf, sizeof (buf), "0x%02x %i %i", type, current, total); +  gt_write_status (gt, STATUS_PROGRESS, what, buf); +} + + +gpg_error_t +_gt_gpgme_new (gpgme_tool_t gt, gpgme_ctx_t *ctx) +{ +  gpg_error_t err; + +  err = gpgme_new (ctx); +  if (err) +    return err; +   gpgme_set_progress_cb (*ctx, _gt_progress_cb, gt); +   return 0; +} + + +void +gt_init (gpgme_tool_t gt) +{ +  memset (gt, '\0', sizeof (*gt)); +  gpg_error_t err; + +  err = _gt_gpgme_new (gt, >->ctx); +  if (err) +    log_error (1, err, "can't create gpgme context"); +} + + +gpg_error_t +gt_signers_add (gpgme_tool_t gt, const char *fpr) +{ +  gpg_error_t err; +  gpgme_key_t key; + +  err = gpgme_get_key (gt->ctx, fpr, &key, 0); +  if (err) +    return err; + +  return gpgme_signers_add (gt->ctx, key); +} + + +gpg_error_t +gt_signers_clear (gpgme_tool_t gt) +{ +  gpgme_signers_clear (gt->ctx); +  return 0; +} + + +gpg_error_t +gt_recipients_add (gpgme_tool_t gt, const char *fpr) +{ +  gpg_error_t err; +  gpgme_key_t key; + +  if (gt->recipients_nr >= MAX_RECIPIENTS) +    return gpg_error_from_errno (ENOMEM); + +  err = gpgme_get_key (gt->ctx, fpr, &key, 0); +  if (err) +    return err; + +  gt->recipients[gt->recipients_nr++] = key; +  return 0; +} + + +void +gt_recipients_clear (gpgme_tool_t gt) +{ +  int idx; + +  for (idx = 0; idx < gt->recipients_nr; idx++) +    gpgme_key_unref (gt->recipients[idx]); +  memset (gt->recipients, '\0', gt->recipients_nr * sizeof (gpgme_key_t)); +  gt->recipients_nr = 0; +} + + +gpg_error_t +gt_reset (gpgme_tool_t gt) +{ +  gpg_error_t err; +  gpgme_ctx_t ctx; +   +  err = _gt_gpgme_new (gt, &ctx); +  if (err) +    return err; + +  gpgme_release (gt->ctx); +  gt->ctx = ctx; +  gt_recipients_clear (gt); +  return 0; +} + + +void +gt_write_status (gpgme_tool_t gt, status_t status, ...) +{ +  va_list ap; +  const char *text; +  char buf[950]; +  char *p; +  size_t n; +  gpg_error_t err; + +  va_start (ap, status); +  p = buf; +  n = 0; +  while ((text = va_arg (ap, const char *))) +    { +      if (n) +	{ +	  *p++ = ' '; +	  n++; +	} +      while (*text && n < sizeof (buf) - 2) +	{ +	  *p++ = *text++; +	  n++; +	} +    } +  *p = 0; +  va_end (ap); + +  err = gt->write_status (gt->write_status_hook, status_string[status], buf); +  if (err) +    log_error (1, err, "can't write status line"); +} + + +gpg_error_t +gt_get_engine_info (gpgme_tool_t gt, gpgme_protocol_t proto) +{ +  gpgme_engine_info_t info; +  info = gpgme_ctx_get_engine_info (gt->ctx); +  while (info) +    { +      if (proto == GPGME_PROTOCOL_UNKNOWN || proto == info->protocol) +	gt_write_status (gt, STATUS_ENGINE, +			 gpgme_get_protocol_name (info->protocol), +			 info->file_name, info->version, +			 info->req_version, info->home_dir); +      info = info->next; +    } +  return 0; +} + + +gpgme_protocol_t +gt_protocol_from_name (const char *name) +{ +  if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_OpenPGP))) +    return GPGME_PROTOCOL_OpenPGP; +  if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_CMS))) +    return GPGME_PROTOCOL_CMS; +  if (! strcasecmp (name,gpgme_get_protocol_name (GPGME_PROTOCOL_GPGCONF))) +    return GPGME_PROTOCOL_GPGCONF; +  if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_ASSUAN))) +    return GPGME_PROTOCOL_ASSUAN; +  if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_G13))) +    return GPGME_PROTOCOL_G13; +  return GPGME_PROTOCOL_UNKNOWN; +} + +   +gpg_error_t +gt_set_protocol (gpgme_tool_t gt, gpgme_protocol_t proto) +{ +  return gpgme_set_protocol (gt->ctx, proto); +} + + +gpg_error_t +gt_get_protocol (gpgme_tool_t gt) +{ +  gpgme_protocol_t proto = gpgme_get_protocol (gt->ctx); + +  gt_write_status (gt, STATUS_PROTOCOL, gpgme_get_protocol_name (proto), +		   NULL); + +  return 0; +} + + +gpg_error_t +gt_set_armor (gpgme_tool_t gt, int armor) +{ +  gpgme_set_armor (gt->ctx, armor); +  return 0; +} + + +gpg_error_t +gt_get_armor (gpgme_tool_t gt) +{ +  gt_write_status (gt, STATUS_ARMOR, +		   gpgme_get_armor (gt->ctx) ? "true" : "false", NULL); + +  return 0; +} + + +gpg_error_t +gt_set_textmode (gpgme_tool_t gt, int textmode) +{ +  gpgme_set_textmode (gt->ctx, textmode); +  return 0; +} + + +gpg_error_t +gt_get_textmode (gpgme_tool_t gt) +{ +  gt_write_status (gt, STATUS_TEXTMODE, +		   gpgme_get_textmode (gt->ctx) ? "true" : "false", NULL); + +  return 0; +} + + +gpg_error_t +gt_set_keylist_mode (gpgme_tool_t gt, gpgme_keylist_mode_t keylist_mode) +{ +  gpgme_set_keylist_mode (gt->ctx, keylist_mode); +  return 0; +} + + +gpg_error_t +gt_get_keylist_mode (gpgme_tool_t gt) +{ +#define NR_KEYLIST_MODES 6 +  const char *modes[NR_KEYLIST_MODES + 1]; +  int idx = 0; +  gpgme_keylist_mode_t mode = gpgme_get_keylist_mode (gt->ctx); +   +  if (mode & GPGME_KEYLIST_MODE_LOCAL) +    modes[idx++] = "local"; +  if (mode & GPGME_KEYLIST_MODE_EXTERN) +    modes[idx++] = "extern"; +  if (mode & GPGME_KEYLIST_MODE_SIGS) +    modes[idx++] = "sigs"; +  if (mode & GPGME_KEYLIST_MODE_SIG_NOTATIONS) +    modes[idx++] = "sig_notations"; +  if (mode & GPGME_KEYLIST_MODE_EPHEMERAL) +    modes[idx++] = "ephemeral"; +  if (mode & GPGME_KEYLIST_MODE_VALIDATE) +    modes[idx++] = "validate"; +  modes[idx++] = NULL; + +  gt_write_status (gt, STATUS_KEYLIST_MODE, modes[0], modes[1], modes[2], +		   modes[3], modes[4], modes[5], modes[6]); + +  return 0; +} + + +gpg_error_t +gt_set_include_certs (gpgme_tool_t gt, int include_certs) +{ +  gpgme_set_include_certs (gt->ctx, include_certs); +  return 0; +} + + +gpg_error_t +gt_get_include_certs (gpgme_tool_t gt) +{ +  int include_certs = gpgme_get_include_certs (gt->ctx); +  char buf[100]; + +  if (include_certs == GPGME_INCLUDE_CERTS_DEFAULT) +    strcpy (buf, "default"); +  else +    snprintf (buf, sizeof (buf), "%i", include_certs); + +  gt_write_status (gt, STATUS_INCLUDE_CERTS, buf, NULL); + +  return 0; +} + + +gpg_error_t +gt_decrypt_verify (gpgme_tool_t gt, gpgme_data_t cipher, gpgme_data_t plain, +		   int verify) +{ +  if (verify) +    return gpgme_op_decrypt_verify (gt->ctx, cipher, plain); +  else +    return gpgme_op_decrypt (gt->ctx, cipher, plain); +} + + +gpg_error_t +gt_sign_encrypt (gpgme_tool_t gt, gpgme_encrypt_flags_t flags, +		 gpgme_data_t plain, gpgme_data_t cipher, int sign) +{ +  gpg_error_t err; + +  if (sign) +    err = gpgme_op_encrypt (gt->ctx, gt->recipients, flags, plain, cipher); +  else +    err = gpgme_op_encrypt_sign (gt->ctx, gt->recipients, flags, plain, cipher); + +  gt_recipients_clear (gt); + +  return err; +} + + +gpg_error_t +gt_sign (gpgme_tool_t gt, gpgme_data_t plain, gpgme_data_t sig, +	 gpgme_sig_mode_t mode) +{ +  return gpgme_op_sign (gt->ctx, plain, sig, mode); +} + + +gpg_error_t +gt_verify (gpgme_tool_t gt, gpgme_data_t sig, gpgme_data_t sig_text, +	   gpgme_data_t plain) +{ +  return gpgme_op_verify (gt->ctx, sig, sig_text, plain); +} + + +gpg_error_t +gt_import (gpgme_tool_t gt, gpgme_data_t data) +{ +  return gpgme_op_import (gt->ctx, data); +} + + +gpg_error_t +gt_export (gpgme_tool_t gt, const char *pattern[], gpgme_export_mode_t mode, +	   gpgme_data_t data) +{ +  return gpgme_op_export_ext (gt->ctx, pattern, mode, data); +} + + +gpg_error_t +gt_genkey (gpgme_tool_t gt, const char *parms, gpgme_data_t public, +	   gpgme_data_t secret) +{ +  return gpgme_op_genkey (gt->ctx, parms, public, secret); +} + + +gpg_error_t +gt_import_keys (gpgme_tool_t gt, char *fpr[]) +{ +  gpg_error_t err; +  int cnt; +  int idx; +  gpgme_key_t *keys; +   +  cnt = 0; +  while (fpr[cnt]) +    cnt++; +   +  if (! cnt) +    return gpg_error (GPG_ERR_INV_VALUE); + +  keys = malloc ((cnt + 1) * sizeof (gpgme_key_t)); +  if (! keys) +    return gpg_error_from_syserror (); +   +  for (idx = 0; idx < cnt; idx++) +    { +      err = gpgme_get_key (gt->ctx, fpr[idx], &keys[idx], 0); +      if (err) +	break; +    } +  if (! err) +    { +      keys[cnt] = NULL; +      err = gpgme_op_import_keys (gt->ctx, keys); +    } +   +  /* Rollback.  */ +  while (--idx >= 0) +    gpgme_key_unref (keys[idx]); +  free (keys); + +  return err; +} + + +gpg_error_t +gt_delete (gpgme_tool_t gt, char *fpr, int allow_secret) +{ +  gpg_error_t err; +  gpgme_key_t key; + +  err = gpgme_get_key (gt->ctx, fpr, &key, 0); +  if (err) +    return err; + +  err = gpgme_op_delete (gt->ctx, key, allow_secret); +  gpgme_key_unref (key); +  return err; +} + + +gpg_error_t +gt_keylist_start (gpgme_tool_t gt, const char *pattern[], int secret_only) +{ +  return gpgme_op_keylist_ext_start (gt->ctx, pattern, secret_only, 0); +} + + +gpg_error_t +gt_keylist_next (gpgme_tool_t gt, gpgme_key_t *key) +{ +  return gpgme_op_keylist_next (gt->ctx, key); +} + + +gpg_error_t +gt_getauditlog (gpgme_tool_t gt, gpgme_data_t output, unsigned int flags) +{ +  return gpgme_op_getauditlog (gt->ctx, output, flags); +} + + +gpg_error_t +gt_vfs_mount (gpgme_tool_t gt, const char *container_file, +	      const char *mount_dir, int flags) +{ +  gpg_error_t err; +  gpg_error_t op_err; +  err = gpgme_op_vfs_mount (gt->ctx, container_file, mount_dir, flags, &op_err); +  return err || op_err; +} + + +// TODO +#define GT_RESULT_ENCRYPT 0x1 +#define GT_RESULT_DECRYPT 0x2 +#define GT_RESULT_SIGN 0x4 +#define GT_RESULT_VERIFY 0x8 +#define GT_RESULT_IMPORT 0x10 +#define GT_RESULT_GENKEY 0x20 +#define GT_RESULT_KEYLIST 0x40 +#define GT_RESULT_VFS_MOUNT 0x80 +#define GT_RESULT_ALL (~0U) + +gpg_error_t +gt_result (gpgme_tool_t gt, unsigned int flags) +{ +  if (flags & GT_RESULT_ENCRYPT) +    { +      gpgme_encrypt_result_t res = gpgme_op_encrypt_result (gt->ctx); +      if (res) +	{ +	  gpgme_invalid_key_t invrec = res->invalid_recipients; +	  while (invrec) +	    { +	      gt_write_status (gt, STATUS_ENCRYPT_RESULT, "invalid_recipient", +			       invrec->fpr, invrec->reason); +	      invrec = invrec->next; +	    } +	} +    } +  return 0; +} + + +/* GPGME SERVER.  */ + +#include <assuan.h> + +struct server +{ +  gpgme_tool_t gt; +  assuan_context_t assuan_ctx; + +  gpgme_data_encoding_t input_enc; +  gpgme_data_encoding_t output_enc; +  assuan_fd_t message_fd; +  gpgme_data_encoding_t message_enc; +}; + + +gpg_error_t +server_write_status (void *hook, const char *status, const char *msg) +{ +  struct server *server = hook; +  return assuan_write_status (server->assuan_ctx, status, msg); +} + + +static gpgme_data_encoding_t +server_data_encoding (const char *line) +{ +  if (strstr (line, "--binary")) +    return GPGME_DATA_ENCODING_BINARY; +  if (strstr (line, "--base64")) +    return GPGME_DATA_ENCODING_BASE64; +  if (strstr (line, "--armor")) +    return GPGME_DATA_ENCODING_ARMOR; +  if (strstr (line, "--url")) +    return GPGME_DATA_ENCODING_URL; +  if (strstr (line, "--urlesc")) +    return GPGME_DATA_ENCODING_URLESC; +  if (strstr (line, "--url0")) +    return GPGME_DATA_ENCODING_URL0; +  return GPGME_DATA_ENCODING_NONE; +} + + +static gpgme_error_t +server_data_obj (assuan_fd_t fd, gpgme_data_encoding_t encoding, +		 gpgme_data_t *data) +{ +  gpgme_error_t err; + +  err = gpgme_data_new_from_fd (data, fd); +  if (err) +    return err; +  return gpgme_data_set_encoding (*data, encoding); +} + + +void +server_reset_fds (struct server *server) +{ +  /* assuan closes the input and output FDs for us when doing a RESET, +     but we use this same function after commands, so repeat it +     here.  */ +  assuan_close_input_fd (server->assuan_ctx); +  assuan_close_output_fd (server->assuan_ctx); +  if (server->message_fd != -1) +    { +      /* FIXME: Assuan should provide a close function.  */ +      close (server->message_fd); +      server->message_fd = -1; +    } +  server->input_enc = GPGME_DATA_ENCODING_NONE; +  server->output_enc = GPGME_DATA_ENCODING_NONE; +  server->message_enc = GPGME_DATA_ENCODING_NONE; +} + + +static gpg_error_t +reset_notify (assuan_context_t ctx, char *line) +{ +  struct server *server = assuan_get_pointer (ctx); +  server_reset_fds (server); +  gt_reset (server->gt); +  return 0; +} + + +static gpg_error_t +cmd_version (assuan_context_t ctx, char *line) +{ +  if (line && *line) +    { +      const char *version = gpgme_check_version (line); +      return version ? 0 : gpg_error (GPG_ERR_SELFTEST_FAILED); +    } +  else +    { +      const char *version = gpgme_check_version (NULL); +      return assuan_send_data (ctx, version, strlen (version)); +    } +} + + +static gpg_error_t +cmd_engine (assuan_context_t ctx, char *line) +{ +  struct server *server = assuan_get_pointer (ctx); +  return gt_get_engine_info (server->gt, gt_protocol_from_name (line)); +} + + +static gpg_error_t +cmd_protocol (assuan_context_t ctx, char *line) +{ +  struct server *server = assuan_get_pointer (ctx); +  if (line && *line) +    return gt_set_protocol (server->gt, gt_protocol_from_name (line)); +  else +    return gt_get_protocol (server->gt); +} + + +static gpg_error_t +cmd_armor (assuan_context_t ctx, char *line) +{ +  struct server *server = assuan_get_pointer (ctx); +  if (line && *line) +    { +      int flag = 0; +       +      if (! strcasecmp (line, "true") || ! strcasecmp (line, "yes") +	  || line[0] == '1') +	flag = 1; +       +      return gt_set_armor (server->gt, flag); +    } +  else +    return gt_get_armor (server->gt); +} + + +static gpg_error_t +cmd_textmode (assuan_context_t ctx, char *line) +{ +  struct server *server = assuan_get_pointer (ctx); +  if (line && *line) +    { +      int flag = 0; + +      if (! strcasecmp (line, "true") || ! strcasecmp (line, "yes") +	  || line[0] == '1') +	flag = 1; +       +      return gt_set_textmode (server->gt, flag); +    } +  else +    return gt_get_textmode (server->gt); +} + + +static gpg_error_t +cmd_include_certs (assuan_context_t ctx, char *line) +{ +  struct server *server = assuan_get_pointer (ctx); + +  if (line && *line) +    { +      int include_certs = 0; +       +      if (! strcasecmp (line, "default")) +	include_certs = GPGME_INCLUDE_CERTS_DEFAULT; +      else +	include_certs = atoi (line); +       +      return gt_set_include_certs (server->gt, include_certs); +    } +  else +    return gt_get_include_certs (server->gt); +} + + +static gpg_error_t +cmd_keylist_mode (assuan_context_t ctx, char *line) +{ +  struct server *server = assuan_get_pointer (ctx); + +  if (line && *line) +    { +      gpgme_keylist_mode_t mode = 0; +       +      if (strstr (line, "local")) +	mode |= GPGME_KEYLIST_MODE_LOCAL; +      if (strstr (line, "extern")) +	mode |= GPGME_KEYLIST_MODE_EXTERN; +      if (strstr (line, "sigs")) +	mode |= GPGME_KEYLIST_MODE_SIGS; +      if (strstr (line, "sig_notations")) +	mode |= GPGME_KEYLIST_MODE_SIG_NOTATIONS; +      if (strstr (line, "ephemeral")) +	mode |= GPGME_KEYLIST_MODE_EPHEMERAL; +      if (strstr (line, "validate")) +	mode |= GPGME_KEYLIST_MODE_VALIDATE; +       +      return gt_set_keylist_mode (server->gt, mode); +    } +  else +    return gt_get_keylist_mode (server->gt); +} + + +static void +input_notify (assuan_context_t ctx, const char *line) +{ +  struct server *server = assuan_get_pointer (ctx); +  server->input_enc = server_data_encoding (line); +} + + +static void +output_notify (assuan_context_t ctx, const char *line) +{ +  struct server *server = assuan_get_pointer (ctx); +  server->output_enc = server_data_encoding (line); +} + + +static gpg_error_t +cmd_message (assuan_context_t ctx, char *line) +{ +  struct server *server = assuan_get_pointer (ctx); +  gpg_error_t err; +  assuan_fd_t sysfd; + +  err = assuan_command_parse_fd (ctx, line, &sysfd); +  if (err) +    return err; +  server->message_fd = sysfd; +  server->message_enc = server_data_encoding (line); +  return 0; +} + + +static gpg_error_t +cmd_recipient (assuan_context_t ctx, char *line) +{ +  struct server *server = assuan_get_pointer (ctx); + +  return gt_recipients_add (server->gt, line); +} + + +static gpg_error_t +cmd_signer (assuan_context_t ctx, char *line) +{ +  struct server *server = assuan_get_pointer (ctx); + +  return gt_signers_add (server->gt, line); +} + + +static gpg_error_t +cmd_signers_clear (assuan_context_t ctx, char *line) +{ +  struct server *server = assuan_get_pointer (ctx); + +  return gt_signers_clear (server->gt); +} + + +static gpg_error_t +_cmd_decrypt_verify (assuan_context_t ctx, char *line, int verify) +{ +  struct server *server = assuan_get_pointer (ctx); +  gpg_error_t err; +  assuan_fd_t inp_fd; +  assuan_fd_t out_fd; +  gpgme_data_t inp_data; +  gpgme_data_t out_data; + +  inp_fd = assuan_get_input_fd (ctx); +  if (inp_fd == ASSUAN_INVALID_FD) +    return GPG_ERR_ASS_NO_INPUT; +  out_fd = assuan_get_output_fd (ctx); +  if (out_fd == ASSUAN_INVALID_FD) +    return GPG_ERR_ASS_NO_OUTPUT; +   +  err = server_data_obj (inp_fd, server->input_enc, &inp_data); +  if (err) +    return err; +  err = server_data_obj (out_fd, server->output_enc, &out_data); +  if (err) +    { +      gpgme_data_release (inp_data); +      return err; +    } + +  err = gt_decrypt_verify (server->gt, inp_data, out_data, verify);  + +  gpgme_data_release (inp_data); +  gpgme_data_release (out_data); + +  server_reset_fds (server); + +  return err; +} + + +static gpg_error_t +cmd_decrypt (assuan_context_t ctx, char *line) +{ +  return _cmd_decrypt_verify (ctx, line, 0); +} + + +static gpg_error_t +cmd_decrypt_verify (assuan_context_t ctx, char *line) +{ +  return _cmd_decrypt_verify (ctx, line, 1); +} + + +static gpg_error_t +_cmd_sign_encrypt (assuan_context_t ctx, char *line, int sign) +{ +  struct server *server = assuan_get_pointer (ctx); +  gpg_error_t err; +  assuan_fd_t inp_fd; +  assuan_fd_t out_fd; +  gpgme_data_t inp_data; +  gpgme_data_t out_data; +  gpgme_encrypt_flags_t flags = 0; + +  if (strstr (line, "--always-trust")) +    flags |= GPGME_ENCRYPT_ALWAYS_TRUST; +  if (strstr (line, "--no-encrypt-to")) +    flags |= GPGME_ENCRYPT_NO_ENCRYPT_TO; +   +  inp_fd = assuan_get_input_fd (ctx); +  if (inp_fd == ASSUAN_INVALID_FD) +    return GPG_ERR_ASS_NO_INPUT; +  out_fd = assuan_get_output_fd (ctx); +  if (out_fd == ASSUAN_INVALID_FD) +    return GPG_ERR_ASS_NO_OUTPUT; +   +  err = server_data_obj (inp_fd, server->input_enc, &inp_data); +  if (err) +    return err; +  err = server_data_obj (out_fd, server->output_enc, &out_data); +  if (err) +    { +      gpgme_data_release (inp_data); +      return err; +    } + +  err = gt_sign_encrypt (server->gt, flags, inp_data, out_data, sign);  + +  gpgme_data_release (inp_data); +  gpgme_data_release (out_data); + +  server_reset_fds (server); + +  return err; +} + + +static gpg_error_t +cmd_encrypt (assuan_context_t ctx, char *line) +{ +  return _cmd_sign_encrypt (ctx, line, 0); +} + + +static gpg_error_t +cmd_sign_encrypt (assuan_context_t ctx, char *line) +{ +  return _cmd_sign_encrypt (ctx, line, 1); +} + + +static gpg_error_t +cmd_sign (assuan_context_t ctx, char *line) +{ +  struct server *server = assuan_get_pointer (ctx); +  gpg_error_t err; +  assuan_fd_t inp_fd; +  assuan_fd_t out_fd; +  gpgme_data_t inp_data; +  gpgme_data_t out_data; +  gpgme_sig_mode_t mode = GPGME_SIG_MODE_NORMAL; + +  if (strstr (line, "--clear")) +    mode = GPGME_SIG_MODE_CLEAR; +  if (strstr (line, "--detach")) +    mode = GPGME_SIG_MODE_DETACH; + +  inp_fd = assuan_get_input_fd (ctx); +  if (inp_fd == ASSUAN_INVALID_FD) +    return GPG_ERR_ASS_NO_INPUT; +  out_fd = assuan_get_output_fd (ctx); +  if (out_fd == ASSUAN_INVALID_FD) +    return GPG_ERR_ASS_NO_OUTPUT; +   +  err = server_data_obj (inp_fd, server->input_enc, &inp_data); +  if (err) +    return err; +  err = server_data_obj (out_fd, server->output_enc, &out_data); +  if (err) +    { +      gpgme_data_release (inp_data); +      return err; +    } + +  err = gt_sign (server->gt, inp_data, out_data, mode); + +  gpgme_data_release (inp_data); +  gpgme_data_release (out_data); +  server_reset_fds (server); + +  return err; +} + + +static gpg_error_t +cmd_verify (assuan_context_t ctx, char *line) +{ +  struct server *server = assuan_get_pointer (ctx); +  gpg_error_t err; +  assuan_fd_t inp_fd; +  assuan_fd_t msg_fd; +  assuan_fd_t out_fd; +  gpgme_data_t inp_data; +  gpgme_data_t msg_data = NULL; +  gpgme_data_t out_data = NULL; + +  inp_fd = assuan_get_input_fd (ctx); +  if (inp_fd == ASSUAN_INVALID_FD) +    return GPG_ERR_ASS_NO_INPUT; +  msg_fd = server->message_fd; +  out_fd = assuan_get_output_fd (ctx); +   +  err = server_data_obj (inp_fd, server->input_enc, &inp_data); +  if (err) +    return err; +  if (msg_fd != ASSUAN_INVALID_FD) +    { +      err = server_data_obj (msg_fd, server->message_enc, &msg_data); +      if (err) +	{ +	  gpgme_data_release (inp_data); +	  return err; +	} +    } +  if (out_fd != ASSUAN_INVALID_FD) +    { +      err = server_data_obj (out_fd, server->output_enc, &out_data); +      if (err) +	{ +	  gpgme_data_release (inp_data); +	  gpgme_data_release (msg_data); +	  return err; +	} +    } + +  err = gt_verify (server->gt, inp_data, msg_data, out_data); + +  gpgme_data_release (inp_data); +  if (msg_data) +    gpgme_data_release (msg_data); +  if (out_data) +    gpgme_data_release (out_data); + +  server_reset_fds (server); + +  return err; +} + + +static gpg_error_t +cmd_import (assuan_context_t ctx, char *line) +{ +  struct server *server = assuan_get_pointer (ctx); +   +  if (line && *line) +    { +      char *fprs[2] = { line, NULL }; + +      return gt_import_keys (server->gt, fprs); +    } +  else +    { +      gpg_error_t err; +      assuan_fd_t inp_fd; +      gpgme_data_t inp_data; +       +      inp_fd = assuan_get_input_fd (ctx); +      if (inp_fd == ASSUAN_INVALID_FD) +	return GPG_ERR_ASS_NO_INPUT; + +      err = server_data_obj (inp_fd, server->input_enc, &inp_data); +      if (err) +	return err; +       +      err = gt_import (server->gt, inp_data);  +       +      gpgme_data_release (inp_data); +      server_reset_fds (server); + +      return err; +    } +} + + +static gpg_error_t +cmd_export (assuan_context_t ctx, char *line) +{ +  struct server *server = assuan_get_pointer (ctx); +  gpg_error_t err; +  assuan_fd_t out_fd; +  gpgme_data_t out_data; +  gpgme_export_mode_t mode = 0; +  const char *pattern[2]; +  const char optstr[] = "--extern "; + +  out_fd = assuan_get_output_fd (ctx); +  if (out_fd == ASSUAN_INVALID_FD) +    return GPG_ERR_ASS_NO_OUTPUT; +  err = server_data_obj (out_fd, server->output_enc, &out_data); +  if (err) +    return err; + +  if (strncasecmp (line, optstr, strlen (optstr))) +    { +      mode |= GPGME_EXPORT_MODE_EXTERN; +      line += strlen (optstr); +    } +  pattern[0] = line; +  pattern[1] = NULL; + +  err = gt_export (server->gt, pattern, mode, out_data); + +  gpgme_data_release (out_data); +  server_reset_fds (server); + +  return err; +} + + +static gpg_error_t +_cmd_genkey_write (gpgme_data_t data, const void *buf, size_t size) +{ +  while (size > 0) +    { +      ssize_t writen = gpgme_data_write (data, buf, size); +      if (writen < 0 && errno != EAGAIN) +	return gpg_error_from_syserror (); +      else if (writen > 0) +	{ +	  buf = (void *) (((char *) buf) + writen); +	  size -= writen; +	} +    } +  return 0; +} + + +static gpg_error_t +cmd_genkey (assuan_context_t ctx, char *line) +{ +  struct server *server = assuan_get_pointer (ctx); +  gpg_error_t err; +  assuan_fd_t inp_fd; +  assuan_fd_t out_fd; +  gpgme_data_t inp_data; +  gpgme_data_t out_data = NULL; +  gpgme_data_t parms_data = NULL; +  const char *parms; + +  inp_fd = assuan_get_input_fd (ctx); +  if (inp_fd == ASSUAN_INVALID_FD) +    return GPG_ERR_ASS_NO_INPUT; +  out_fd = assuan_get_output_fd (ctx); +   +  err = server_data_obj (inp_fd, server->input_enc, &inp_data); +  if (err) +    return err; +  if (out_fd != ASSUAN_INVALID_FD) +    { +      err = server_data_obj (out_fd, server->output_enc, &out_data); +      if (err) +	{ +	  gpgme_data_release (inp_data); +	  return err; +	} +    } + +  /* Convert input data.  */ +  err = gpgme_data_new (&parms_data); +  if (err) +    goto out; +  do +    { +      char buf[512]; +      ssize_t readn = gpgme_data_read (inp_data, buf, sizeof (buf)); +      if (readn < 0) +	{ +	  err = gpg_error_from_syserror (); +	  goto out; +	} +      else if (readn == 0) +	break; + +      err = _cmd_genkey_write (parms_data, buf, readn); +      if (err) +	goto out; +    } +  while (1); +  err = _cmd_genkey_write (parms_data, "", 1); +  if (err) +    goto out; +  parms = gpgme_data_release_and_get_mem (parms_data, NULL); +  parms_data = NULL; +  if (! parms) +    { +      err = gpg_error (GPG_ERR_GENERAL); +      goto out; +    } + +  err = gt_genkey (server->gt, parms, out_data, NULL); + +  server_reset_fds (server); + + out: +  gpgme_data_release (inp_data); +  if (out_data) +    gpgme_data_release (out_data); +  if (parms_data) +    gpgme_data_release (parms_data); + +  return err;  +} + + +static gpg_error_t +cmd_delete (assuan_context_t ctx, char *line) +{ +  struct server *server = assuan_get_pointer (ctx); +  int allow_secret = 0; +  const char optstr[] = "--allow-secret "; + +  if (strncasecmp (line, optstr, strlen (optstr))) +    { +      allow_secret = 1; +      line += strlen (optstr); +    } +  return gt_delete (server->gt, line, allow_secret); +} + + +static gpg_error_t +cmd_keylist (assuan_context_t ctx, char *line) +{ +  struct server *server = assuan_get_pointer (ctx); +  gpg_error_t err; +  int secret_only = 0; +  const char *pattern[2]; +  const char optstr[] = "--secret-only "; + +  if (strncasecmp (line, optstr, strlen (optstr))) +    { +      secret_only = 1; +      line += strlen (optstr); +    } +  pattern[0] = line; +  pattern[1] = NULL; + +  err = gt_keylist_start (server->gt, pattern, secret_only); +  while (! err) +    { +      gpgme_key_t key; + +      err = gt_keylist_next (server->gt, &key); +      if (gpg_err_code (err) == GPG_ERR_EOF) +	{ +	  err = 0; +	  break; +	} +      else if (! err) +	{ +	  char buf[100]; +	  /* FIXME: More data.  */ +	  snprintf (buf, sizeof (buf), "key:%s\n", key->subkeys->fpr); +	  assuan_send_data (ctx, buf, strlen (buf)); +	  gpgme_key_unref (key); +	} +    } +   +  server_reset_fds (server); + +  return err; +} + + +static gpg_error_t +cmd_getauditlog (assuan_context_t ctx, char *line) +{ +  struct server *server = assuan_get_pointer (ctx); +  gpg_error_t err; +  assuan_fd_t out_fd; +  gpgme_data_t out_data; + +  out_fd = assuan_get_output_fd (ctx); +  if (out_fd == ASSUAN_INVALID_FD) +    return GPG_ERR_ASS_NO_OUTPUT; +  err = server_data_obj (out_fd, server->output_enc, &out_data); +  if (err) +    return err; + +  err = gt_getauditlog (server->gt, out_data, 0); + +  gpgme_data_release (out_data); +  server_reset_fds (server); + +  return err; +} + + +static gpg_error_t +cmd_vfs_mount (assuan_context_t ctx, char *line) +{ +  struct server *server = assuan_get_pointer (ctx); +  char *mount_dir; +  gpg_error_t err; + +  mount_dir = strchr (line, ' '); +  if (mount_dir) +    { +      *(mount_dir++) = '\0'; +      while (*mount_dir == ' ') +	mount_dir++; +    } + +  err = gt_vfs_mount (server->gt, line, mount_dir, 0); + +  return err; +} + + +static gpg_error_t +cmd_result (assuan_context_t ctx, char *line) +{ +  struct server *server = assuan_get_pointer (ctx); +  return gt_result (server->gt, GT_RESULT_ALL); +} + + +/* STRERROR <err>  */ +static gpg_error_t +cmd_strerror (assuan_context_t ctx, char *line) +{ +  gpg_error_t err; +  char buf[100]; + +  err = atoi (line); +  snprintf (buf, sizeof (buf), "%s <%s>", gpgme_strerror (err), +	    gpgme_strsource (err)); +  return assuan_send_data (ctx, buf, strlen (buf)); +} + + +static gpg_error_t +cmd_pubkey_algo_name (assuan_context_t ctx, char *line) +{ +  gpgme_pubkey_algo_t algo; +  char buf[100]; + +  algo = atoi (line); +  snprintf (buf, sizeof (buf), "%s", gpgme_pubkey_algo_name (algo)); +  return assuan_send_data (ctx, buf, strlen (buf)); +} + + +static gpg_error_t +cmd_hash_algo_name (assuan_context_t ctx, char *line) +{ +  gpgme_hash_algo_t algo; +  char buf[100]; + +  algo = atoi (line); +  snprintf (buf, sizeof (buf), "%s", gpgme_hash_algo_name (algo)); +  return assuan_send_data (ctx, buf, strlen (buf)); +} + + +/* Tell the assuan library about our commands.  */ +static gpg_error_t +register_commands (assuan_context_t ctx) +{ +  gpg_error_t err; +  static struct { +    const char *name; +    gpg_error_t (*handler)(assuan_context_t, char *line); +  } table[] = { +    // RESET, BYE are implicit. +    { "VERSION", cmd_version }, +    // TODO: Set engine info. +    { "ENGINE", cmd_engine }, +    { "PROTOCOL", cmd_protocol }, +    { "ARMOR", cmd_armor }, +    { "TEXTMODE", cmd_textmode }, +    { "INCLUDE_CERTS", cmd_include_certs }, +    { "KEYLIST_MODE", cmd_keylist_mode }, +    { "INPUT", NULL },  +    { "OUTPUT", NULL },  +    { "MESSAGE", cmd_message }, +    { "RECIPIENT", cmd_recipient }, +    { "SIGNER", cmd_signer }, +    { "SIGNERS_CLEAR", cmd_signers_clear }, +    // TODO: SIGNOTATION missing. +    // TODO: Could add wait interface if we allow more than one context +    // and add _START variants. +    // TODO: Could add data interfaces if we allow multiple data objects. +    { "DECRYPT", cmd_decrypt }, +    { "DECRYPT_VERIFY", cmd_decrypt_verify }, +    { "ENCRYPT", cmd_encrypt }, +    { "ENCRYPT_SIGN", cmd_sign_encrypt }, +    { "SIGN_ENCRYPT", cmd_sign_encrypt }, +    { "SIGN", cmd_sign }, +    { "VERIFY", cmd_verify }, +    { "IMPORT", cmd_import }, +    { "EXPORT", cmd_export }, +    { "GENKEY", cmd_genkey }, +    { "DELETE", cmd_delete }, +    // TODO: EDIT, CARD_EDIT (with INQUIRE) +    { "KEYLIST", cmd_keylist }, +    { "LISTKEYS", cmd_keylist }, +    // TODO: TRUSTLIST, TRUSTLIST_EXT +    { "GETAUDITLOG", cmd_getauditlog }, +    // TODO: ASSUAN +    { "VFS_MOUNT", cmd_vfs_mount }, +    { "MOUNT", cmd_vfs_mount }, +    // TODO: GPGCONF +    { "RESULT", cmd_result }, +    { "STRERROR", cmd_strerror }, +    { "PUBKEY_ALGO_NAME", cmd_pubkey_algo_name }, +    { "HASH_ALGO_NAME", cmd_hash_algo_name }, +    { NULL } +  }; +  int idx; + +  for (idx = 0; table[idx].name; idx++) +    { +      err = assuan_register_command (ctx, table[idx].name, table[idx].handler); +      if (err) +        return err; +    }  +  return 0; +} + + +/* TODO: password callback can do INQUIRE.  */ +void +gpgme_server (gpgme_tool_t gt) +{ +  gpg_error_t err; +  int filedes[2]; +  struct server server; +  static const char hello[] = ("GPGME-Tool " VERSION " ready"); + +  memset (&server, 0, sizeof (server)); +  server.message_fd = -1; +  server.input_enc = GPGME_DATA_ENCODING_NONE; +  server.output_enc = GPGME_DATA_ENCODING_NONE; +  server.message_enc = GPGME_DATA_ENCODING_NONE; + +  server.gt = gt; +  gt->write_status = server_write_status; +  gt->write_status_hook = &server; + +  /* We use a pipe based server so that we can work from scripts. +     assuan_init_pipe_server will automagically detect when we are +     called with a socketpair and ignore FIELDES in this case. */ +  filedes[0] = 0; +  filedes[1] = 1; +  err = assuan_new (&server.assuan_ctx); +  if (err) +    log_error (1, err, "can't create assuan context"); + +  assuan_set_pointer (server.assuan_ctx, &server); + +  err = assuan_init_pipe_server (server.assuan_ctx, filedes); +  if (err) +    log_error (1, err, "can't initialize assuan server"); +  err = register_commands (server.assuan_ctx); +  if (err) +    log_error (1, err, "can't register assuan commands"); +  assuan_set_hello_line (server.assuan_ctx, hello); + +  assuan_register_reset_notify (server.assuan_ctx, reset_notify); +  assuan_register_input_notify (server.assuan_ctx, input_notify); +  assuan_register_output_notify (server.assuan_ctx, output_notify); + +#define DBG_ASSUAN 0 +  if (DBG_ASSUAN) +    assuan_set_log_stream (server.assuan_ctx, log_stream); + +  for (;;) +    { +      err = assuan_accept (server.assuan_ctx); +      if (err == -1) +	break; +      else if (err) +	{ +	  log_error (0, err, "assuan accept problem"); +	  break; +        } +       +      err = assuan_process (server.assuan_ctx); +      if (err) +	log_error (0, err, "assuan processing failed"); +    } + +  assuan_release (server.assuan_ctx); +} + + + +/* MAIN PROGRAM STARTS HERE.  */ + +const char *argp_program_version = VERSION; +const char *argp_program_bug_address = "[email protected]"; +error_t argp_err_exit_status = 1; + +static char doc[] = "GPGME Tool -- invoke GPGME operations"; +static char args_doc[] = "COMMAND [OPTIONS...]"; + +static struct argp_option options[] = { +  { "server", 's', 0, 0, "Server mode" }, +  { 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; +}; + +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) +{ +  struct args *args = state->input; + +  switch (key) +    { +    case 's': +      args->cmd = CMD_SERVER; +      break; +#if 0 +    case ARGP_KEY_ARG: +      if (state->arg_num >= 2) +	argp_usage (state); +      printf ("Arg[%i] = %s\n", state->arg_num, arg); +      break; +    case ARGP_KEY_END: +      if (state->arg_num < 2) +	argp_usage (state); +      break; +#endif + +    default: +      return ARGP_ERR_UNKNOWN; +    } +  return 0; +} + + +int +main (int argc, char *argv[]) +{ +  struct args args; +  struct gpgme_tool gt; + +  setlocale (LC_ALL, ""); +  gpgme_check_version (NULL); +  gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL)); +#ifdef LC_MESSAGES +  gpgme_set_locale (NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL)); +#endif +  args_init (&args); + +  argp_parse (&argp, argc, argv, 0, 0, &args); +  log_init (); + +  gt_init (>); + +  switch (args.cmd) +    { +    case CMD_DEFAULT: +    case CMD_SERVER: +      gpgme_server (>); +      break; +    } + +  gpgme_release (gt.ctx); + +  return 0; +} + diff --git a/src/gpgme.c b/src/gpgme.c index 52e14d7c..70f93f1a 100644 --- a/src/gpgme.c +++ b/src/gpgme.c @@ -186,8 +186,8 @@ gpgme_release (gpgme_ctx_t ctx)    _gpgme_engine_release (ctx->engine);    _gpgme_fd_table_deinit (&ctx->fdt);    _gpgme_release_result (ctx); -  gpgme_signers_clear (ctx); -  gpgme_sig_notation_clear (ctx); +  _gpgme_signers_clear (ctx); +  _gpgme_sig_notation_clear (ctx);    if (ctx->signers)      free (ctx->signers);    if (ctx->lc_ctype) @@ -269,6 +269,7 @@ gpgme_set_protocol (gpgme_ctx_t ctx, gpgme_protocol_t protocol)    if (protocol != GPGME_PROTOCOL_OpenPGP        && protocol != GPGME_PROTOCOL_CMS +      && protocol != GPGME_PROTOCOL_GPGCONF        && protocol != GPGME_PROTOCOL_ASSUAN        && protocol != GPGME_PROTOCOL_G13)      return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); @@ -311,6 +312,9 @@ gpgme_get_protocol_name (gpgme_protocol_t protocol)      case GPGME_PROTOCOL_CMS:        return "CMS"; +    case GPGME_PROTOCOL_GPGCONF: +      return "GPGCONF"; +      case GPGME_PROTOCOL_ASSUAN:        return "Assuan"; @@ -654,10 +658,9 @@ gpgme_ctx_set_engine_info (gpgme_ctx_t ctx, gpgme_protocol_t proto,  /* Clear all notation data from the context.  */  void -gpgme_sig_notation_clear (gpgme_ctx_t ctx) +_gpgme_sig_notation_clear (gpgme_ctx_t ctx)  {    gpgme_sig_notation_t notation; -  TRACE (DEBUG_CTX, "gpgme_sig_notation_clear", ctx);    if (!ctx)      return; @@ -672,6 +675,13 @@ gpgme_sig_notation_clear (gpgme_ctx_t ctx)    ctx->sig_notations = NULL;  } +void +gpgme_sig_notation_clear (gpgme_ctx_t ctx) +{ +  TRACE (DEBUG_CTX, "gpgme_sig_notation_clear", ctx); +  _gpgme_sig_notation_clear (ctx); +} +  /* Add the human-readable notation data with name NAME and value VALUE     to the context CTX, using the flags FLAGS.  If NAME is NULL, then @@ -29,6 +29,8 @@  /* From gpgme.c.  */  gpgme_error_t _gpgme_cancel_with_err (gpgme_ctx_t ctx, gpg_error_t ctx_err,  				      gpg_error_t op_err); +/* Clear all notation data from the context.  */ +void _gpgme_sig_notation_clear (gpgme_ctx_t ctx);  void _gpgme_release_result (gpgme_ctx_t ctx); @@ -79,6 +81,9 @@ gpgme_error_t _gpgme_decrypt_status_handler (void *priv,  					     char *args); +/* From signers.c.  */ +void _gpgme_signers_clear (gpgme_ctx_t ctx); +  /* From sign.c.  */  /* Create an initial op data object for signing.  Needs to be called diff --git a/src/signers.c b/src/signers.c index 9eb4e4e7..021a878d 100644 --- a/src/signers.c +++ b/src/signers.c @@ -36,12 +36,10 @@  /* Delete all signers from CTX.  */  void -gpgme_signers_clear (gpgme_ctx_t ctx) +_gpgme_signers_clear (gpgme_ctx_t ctx)  {    unsigned int i; -  TRACE (DEBUG_CTX, "gpgme_signers_clear", ctx); -    if (!ctx || !ctx->signers)      return; @@ -54,6 +52,15 @@ gpgme_signers_clear (gpgme_ctx_t ctx)    ctx->signers_len = 0;  } + +void +gpgme_signers_clear (gpgme_ctx_t ctx) +{ +  TRACE (DEBUG_CTX, "gpgme_signers_clear", ctx); +  return _gpgme_signers_clear (ctx); +} + +  /* Add KEY to list of signers in CTX.  */  gpgme_error_t  gpgme_signers_add (gpgme_ctx_t ctx, const gpgme_key_t key) diff --git a/src/version.c b/src/version.c index b2d795ab..e5d7c3fc 100644 --- a/src/version.c +++ b/src/version.c @@ -193,7 +193,7 @@ gpgme_check_version (const char *req_version)    do_subsystem_inits ();    /* Catch-22: We need to get at least the debug subsystem ready -     before using the tarce facility.  If we won't the tarce would +     before using the trace facility.  If we won't the trace would       automagically initialize the debug system with out the locks       being initialized and missing the assuan log level setting. */    TRACE2 (DEBUG_INIT, "gpgme_check_version: ", 0, @@ -216,14 +216,15 @@ gpgme_check_version_internal (const char *req_version,  {    const char *result; -  TRACE2 (DEBUG_INIT, "gpgme_check_version_internal: ", 0, -	  "req_version=%s, offset_sig_validity=%i", -	  req_version ? req_version : "(null)", offset_sig_validity); -    result = gpgme_check_version (req_version);    if (result == NULL)      return result; +  /* Catch-22, see above.  */ +  TRACE2 (DEBUG_INIT, "gpgme_check_version_internal: ", 0, +	  "req_version=%s, offset_sig_validity=%i", +	  req_version ? req_version : "(null)", offset_sig_validity); +    if (offset_sig_validity != offsetof (struct _gpgme_signature, validity))      {        TRACE1 (DEBUG_INIT, "gpgme_check_version_internal: ", 0, | 
