2009-10-22 Marcus Brinkmann <marcus@g10code.de>

* configure.ac: Add support for G13.

src/
2009-10-22  Marcus Brinkmann  <marcus@g10code.de>

	* Makefile.am: Remove @NETLIBS@ from LIBADDs.
	(g13_components): New variable.
	(main_sources): Add $(g13_components).
	* g13.c, engine-g13.c: New files.
	* engine.c (engine_ops): Check for assuan for assuan engine, add
	g13 engine.
	* util.h (_gpgme_get_g13_path, _gpgme_encode_percent_string): New
	prototypes.
	* conversion.c (_gpgme_encode_percent_string): New function.
	* gpgme.h.in (gpgme_protocol_t): Add GPGME_PROTOCOL_G13.
	(struct _gpgme_op_g13_result, gpgme_g13_result_t): New types.
	(gpgme_op_g13_mount): New function.
	* gpgme.def, libgpgme.vers: Add gpgme_op_g13_mount.
	* gpgme.c (gpgme_set_protocol): Allow GPGME_PROTOCOL_G13.
	(gpgme_get_protocol_name): Add GPGME_PROTOCOL_G13.
	* posix-util.c (_gpgme_get_g13_path): New function.
	* w32-util.c (_gpgme_get_g13_path): New function.
	* engine-backend.h (_gpgme_engine_ops_g13): New declaration.
This commit is contained in:
Marcus Brinkmann 2009-10-22 16:44:07 +00:00
parent 9e2397571d
commit a6f3857128
18 changed files with 1346 additions and 20 deletions

View File

@ -1,3 +1,7 @@
2009-10-22 Marcus Brinkmann <marcus@g10code.de>
* configure.ac: Add support for G13.
2009-10-20 Marcus Brinkmann <marcus@g10code.de>
* configure.ac (AC_CONFIG_FILES): Remove assuan/Makefile.

13
NEWS
View File

@ -6,11 +6,16 @@ Noteworthy changes in version 1.2.1 (unreleased)
application programmers on systems that can resolve inter-library
dependencies at runtime, this is a transparent change.
* New engine GPGME_PROTOCOL_G13 to support the new g13 tool.
* Interface changes relative to the 1.2.0 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GPGME_STATUS_INV_SGNR NEW.
GPGME_STATUS_NO_SGNR NEW.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GPGME_STATUS_INV_SGNR NEW
GPGME_STATUS_NO_SGNR NEW
GPGME_PROTOCOL_G13 NEW
gpgme_op_g13_mount NEW
gpgme_g13_result_t NEW
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Noteworthy changes in version 1.2.0 (2009-06-18)
------------------------------------------------

View File

@ -120,6 +120,7 @@ AM_CONDITIONAL(HAVE_LD_VERSION_SCRIPT, test "$have_ld_version_script" = "yes")
GPG_DEFAULT=no
GPGSM_DEFAULT=no
GPGCONF_DEFAULT=no
G13_DEFAULT=no
component_system=None
have_dosish_system=no
have_w32_system=no
@ -133,6 +134,7 @@ case "${host}" in
GPG_DEFAULT='c:\\gnupg\\gpg.exe'
GPGSM_DEFAULT='c:\\gnupg\\gpgsm.exe'
GPGCONF_DEFAULT='c:\\gnupg\\gpgconf.exe'
G13_DEFAULT='c:\\gnupg\\g13.exe'
#component_system='COM+'
AM_PATH_GLIB_2_0
@ -166,6 +168,7 @@ case "${host}" in
# GPG_DEFAULT='/usr/bin/gpg'
# GPGSM_DEFAULT='/usr/bin/gpgsm'
# GPGCONF_DEFAULT='/usr/bin/gpgconf'
# G13_DEFAULT='/usr/bin/g13'
;;
esac
@ -286,9 +289,11 @@ fi
NEED_GPG_VERSION_DEFAULT=1.3.0
NEED_GPGSM_VERSION_DEFAULT=1.9.6
NEED_GPGCONF_VERSION_DEFAULT=2.0.4
NEED_G13_VERSION_DEFAULT=2.1.0
NEED_GPG_VERSION="$NEED_GPG_VERSION_DEFAULT"
NEED_GPGSM_VERSION="$NEED_GPGSM_VERSION_DEFAULT"
NEED_GPGCONF_VERSION="$NEED_GPGCONF_VERSION_DEFAULT"
NEED_G13_VERSION="$NEED_G13_VERSION_DEFAULT"
AC_ARG_WITH(gpg-version,
AC_HELP_STRING([--with-gpg-version=VER], [require GnuPG version VER]),
NEED_GPG_VERSION=$withval)
@ -316,6 +321,15 @@ fi
if test "$NEED_GPGCONF_VERSION" = "no"; then
NEED_GPGCONF_VERSION=0.0.0
fi
AC_ARG_WITH(g13-version,
AC_HELP_STRING([--with-g13-version=VER], [require G13 version VER]),
NEED_G13_VERSION=$withval)
if test "$NEED_G13_VERSION" = "yes"; then
NEED_G13_VERSION="$NEED_G13_VERSION_DEFAULT"
fi
if test "$NEED_G13_VERSION" = "no"; then
NEED_G13_VERSION=0.0.0
fi
AC_DEFINE_UNQUOTED(NEED_GPG_VERSION, "$NEED_GPG_VERSION",
[Min. needed GnuPG version.])
@ -323,6 +337,8 @@ AC_DEFINE_UNQUOTED(NEED_GPGSM_VERSION, "$NEED_GPGSM_VERSION",
[Min. needed GPGSM version.])
AC_DEFINE_UNQUOTED(NEED_GPGCONF_VERSION, "$NEED_GPGCONF_VERSION",
[Min. needed GPGCONF version.])
AC_DEFINE_UNQUOTED(NEED_G13_VERSION, "$NEED_G13_VERSION",
[Min. needed G13 version.])
NO_OVERRIDE=no
@ -518,6 +534,9 @@ require_libassuan=no
if test "$GPGSM" != "no"; then
require_libassuan=yes
fi
if test "$G13" != "no"; then
require_libassuan=yes
fi
NO_OVERRIDE=no
@ -623,6 +642,109 @@ if test "$GPGCONF" != "no"; then
fi
NO_OVERRIDE=no
AC_ARG_WITH(g13,
AC_HELP_STRING([--with-g13=PATH],
[use g13 binary at PATH]),
G13=$withval, NO_OVERRIDE=yes)
if test "$NO_OVERRIDE" = "yes" || test "$G13" = "yes"; then
G13=
NO_OVERRIDE=yes
if test "$cross_compiling" != "yes"; then
AC_PATH_PROG(G13, g13)
fi
if test -z "$G13"; then
G13="$G13_DEFAULT"
fi
fi
if test "$G13" = no; then
if test "$NO_OVERRIDE" = "yes"; then
if test "$cross_compiling" != "yes"; then
AC_MSG_WARN([
***
*** Could not find g13, install g13 or use --with-g13=PATH to enable it
***])
else
AC_MSG_ERROR([
***
*** Can not determine path to g13 when cross-compiling, use --with-g13=PATH
***])
fi
fi
else
AC_DEFINE_UNQUOTED(G13_PATH, "$G13", [Path to the G13 binary.])
AC_DEFINE(ENABLE_G13,1,[Whether G13 support is enabled])
fi
AM_CONDITIONAL(HAVE_G13, test "$G13" != "no")
dnl Check for G13 version requirement.
G13_VERSION=unknown
ok=maybe
if test -z "$G13" -o "x$G13" = "xno"; then
ok=no
else
if test "$cross_compiling" = "yes"; then
AC_MSG_WARN([G13 version can not be checked when cross compiling])
ok=no
else
if test ! -x "$G13"; then
AC_MSG_WARN([G13 not executable, version check disabled])
ok=no
fi
fi
fi
if test "$ok" = "maybe"; then
AC_MSG_CHECKING(for G13 >= $NEED_G13_VERSION)
req_major=`echo $NEED_G13_VERSION | \
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/'`
req_minor=`echo $NEED_G13_VERSION | \
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/'`
req_micro=`echo $NEED_G13_VERSION | \
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'`
G13_VERSION=`$G13 --version | sed -n '1 s/.*\ \([[0-9]].*\)/\1/p'`
major=`echo $G13_VERSION | \
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\1/'`
minor=`echo $G13_VERSION | \
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\2/'`
micro=`echo $G13_VERSION | \
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\3/'`
if test "$major" -gt "$req_major"; then
ok=yes
else
if test "$major" -eq "$req_major"; then
if test "$minor" -gt "$req_minor"; then
ok=yes
else
if test "$minor" -eq "$req_minor"; then
if test "$micro" -ge "$req_micro"; then
ok=yes
fi
fi
fi
fi
fi
if test "$ok" = "yes"; then
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
AC_MSG_WARN([G13 must be at least version $NEED_G13_VERSION])
fi
fi
run_g13_test="$ok"
AC_ARG_ENABLE(g13-test,
AC_HELP_STRING([--disable-g13-test], [disable G13 run test]),
run_g13_test=$enableval)
AM_CONDITIONAL(RUN_G13_TESTS, test "$run_g13_test" = "yes")
# Only build if supported.
AM_CONDITIONAL(BUILD_G13, test "$G13" != "no")
if test "$G13" != "no"; then
AC_DEFINE(HAVE_G13, 1,
[Defined if we are building with g13 support.])
fi
# Check for funopen
AC_CHECK_FUNCS(funopen)
if test $ac_cv_func_funopen != yes; then
@ -777,6 +899,9 @@ echo "
GpgConf path: $GPGCONF
GpgConf version: $GPGCONF_VERSION, min. $NEED_GPGCONF_VERSION
G13 path: $G13
G13 version: $G13_VERSION, min. $NEED_G13_VERSION
Assuan version: $LIBASSUAN_VERSION
GPGME Pthread: $have_pthread

View File

@ -1,3 +1,24 @@
2009-10-22 Marcus Brinkmann <marcus@g10code.de>
* Makefile.am: Remove @NETLIBS@ from LIBADDs.
(g13_components): New variable.
(main_sources): Add $(g13_components).
* g13.c, engine-g13.c: New files.
* engine.c (engine_ops): Check for assuan for assuan engine, add
g13 engine.
* util.h (_gpgme_get_g13_path, _gpgme_encode_percent_string): New
prototypes.
* conversion.c (_gpgme_encode_percent_string): New function.
* gpgme.h.in (gpgme_protocol_t): Add GPGME_PROTOCOL_G13.
(struct _gpgme_op_g13_result, gpgme_g13_result_t): New types.
(gpgme_op_g13_mount): New function.
* gpgme.def, libgpgme.vers: Add gpgme_op_g13_mount.
* gpgme.c (gpgme_set_protocol): Allow GPGME_PROTOCOL_G13.
(gpgme_get_protocol_name): Add GPGME_PROTOCOL_G13.
* posix-util.c (_gpgme_get_g13_path): New function.
* w32-util.c (_gpgme_get_g13_path): New function.
* engine-backend.h (_gpgme_engine_ops_g13): New declaration.
2009-10-20 Marcus Brinkmann <marcus@g10code.de>
* gpgme-config.in (netlibs): Remove.

View File

@ -86,6 +86,12 @@ else
gpgconf_components =
endif
if HAVE_G13
g13_components = engine-g13.c
else
g13_components =
endif
# These are the source files common to all library versions. We used
# to build a non-installed library for that, but that does not work
# correctly on all platforms (in particular, one can not specify the
@ -105,6 +111,7 @@ main_sources = \
opassuan.c \
engine.h engine-backend.h engine.c engine-gpg.c status-table.h \
$(gpgsm_components) $(assuan_components) $(gpgconf_components) \
$(g13_components) g13.c \
gpgconf.c \
sema.h priv-io.h $(system_components) dirinfo.c \
debug.c debug.h gpgme.c version.c error.c
@ -185,21 +192,20 @@ libgpgme_la_LDFLAGS = $(gpgme_res_ldflag) $(no_undefined) $(export_symbols) \
$(libgpgme_version_script_cmd) -version-info \
@LIBGPGME_LT_CURRENT@:@LIBGPGME_LT_REVISION@:@LIBGPGME_LT_AGE@
libgpgme_la_DEPENDENCIES = @LTLIBOBJS@ $(srcdir)/libgpgme.vers $(gpgme_deps)
libgpgme_la_LIBADD = @LIBASSUAN_LIBS@ @LTLIBOBJS@ \
@GPG_ERROR_LIBS@ @NETLIBS@
libgpgme_la_LIBADD = @LIBASSUAN_LIBS@ @LTLIBOBJS@ @GPG_ERROR_LIBS@
libgpgme_pthread_la_LDFLAGS = $(libgpgme_version_script_cmd) -version-info \
@LIBGPGME_LT_CURRENT@:@LIBGPGME_LT_REVISION@:@LIBGPGME_LT_AGE@
libgpgme_pthread_la_DEPENDENCIES = @LTLIBOBJS@ $(srcdir)/libgpgme.vers
libgpgme_pthread_la_LIBADD = @LIBASSUAN_LIBS@ @LTLIBOBJS@ \
-lpthread @GPG_ERROR_LIBS@ @NETLIBS@
-lpthread @GPG_ERROR_LIBS@
libgpgme_pth_la_LDFLAGS = @PTH_LDFLAGS@ \
$(libgpgme_version_script_cmd) -version-info \
@LIBGPGME_LT_CURRENT@:@LIBGPGME_LT_REVISION@:@LIBGPGME_LT_AGE@
libgpgme_pth_la_DEPENDENCIES = @LTLIBOBJS@ $(srcdir)/libgpgme.vers
libgpgme_pth_la_LIBADD = @LIBASSUAN_LIBS@ @LTLIBOBJS@ \
@PTH_LIBS@ @GPG_ERROR_LIBS@ @NETLIBS@
@PTH_LIBS@ @GPG_ERROR_LIBS@
if BUILD_W32_GLIB
libgpgme_glib_la_LDFLAGS = $(gpgme_res_ldflag) $(no_undefined) \
@ -208,7 +214,7 @@ libgpgme_glib_la_LDFLAGS = $(gpgme_res_ldflag) $(no_undefined) \
libgpgme_glib_la_DEPENDENCIES = @LTLIBOBJS@ \
$(srcdir)/libgpgme.vers $(gpgme_deps)
libgpgme_glib_la_LIBADD = @LIBASSUAN_LIBS@ @LTLIBOBJS@ \
@GPG_ERROR_LIBS@ @GLIB_LIBS@ @NETLIBS@
@GPG_ERROR_LIBS@ @GLIB_LIBS@
endif
if BUILD_W32_QT
@ -217,7 +223,7 @@ libgpgme_qt_la_LDFLAGS = $(gpgme_res_ldflag) $(no_undefined) \
@LIBGPGME_LT_CURRENT@:@LIBGPGME_LT_REVISION@:@LIBGPGME_LT_AGE@
libgpgme_qt_la_DEPENDENCIES = @LTLIBOBJS@ $(srcdir)/libgpgme.vers $(gpgme_deps)
libgpgme_qt_la_LIBADD = @LIBASSUAN_LIBS@ @LTLIBOBJS@ \
@GPG_ERROR_LIBS@ @QT4_CORE_LIBS@ @NETLIBS@
@GPG_ERROR_LIBS@ @QT4_CORE_LIBS@
endif
status-table.h : gpgme.h

View File

@ -245,6 +245,75 @@ _gpgme_decode_percent_string (const char *src, char **destp, size_t len,
}
/* Encode the string SRC with percent escaping and store the result in
the buffer *DESTP which is LEN bytes long. If LEN is zero, then a
large enough buffer is allocated with malloc and *DESTP is set to
the result. Currently, LEN is only used to specify if allocation
is desired or not, the caller is expected to make sure that *DESTP
is large enough if LEN is not zero. If BINARY is 1, then '\0'
characters are allowed in the output. */
gpgme_error_t
_gpgme_encode_percent_string (const char *src, char **destp, size_t len)
{
size_t destlen;
char *dest;
const char *str;
destlen = 0;
str = src;
/* We percent-escape the + character because the user might need a
"percent plus" escaped string (special gpg format). But we
percent-escape the space character, which works with and without
the special plus format. */
while (*str)
{
if (*str == '+' || *str == '\"' || *str == '%'
|| *(const unsigned char *)str <= 0x20)
destlen += 3;
else
destlen++;
}
/* Terminating nul byte. */
destlen++;
/* Set up the destination buffer. */
if (len)
{
if (len < destlen);
return gpg_error (GPG_ERR_INTERNAL);
dest = *destp;
}
else
{
/* The converted string will never be larger than the original
string. */
dest = malloc (destlen);
if (!dest)
return gpg_error_from_errno (errno);
*destp = dest;
}
/* Convert the string. */
while (*src)
{
if (*src == '+' || *src == '\"' || *src == '%'
|| *(const unsigned char *)src <= 0x20)
{
snprintf (dest, 4, "%%%02X", *(unsigned char *)src);
dest += 3;
}
else
*(dest++) = *src;
src++;
}
*(dest++) = 0;
return 0;
}
/* Parse the string TIMESTAMP into a time_t. The string may either be
seconds since Epoch or in the ISO 8601 format like
"20390815T143012". Returns 0 for an empty string or seconds since

View File

@ -554,6 +554,8 @@ llass_status_handler (void *opaque, int fd)
TRACE2 (DEBUG_CTX, "gpgme:llass_status_handler", llass,
"fd 0x%x: ERR line: %s",
fd, err ? gpg_strerror (err) : "ok");
/* Command execution errors are not fatal, as we use
a session based protocol. */
if (llass->result_cb)
err = llass->result_cb (llass->result_cb_value, err);
else

View File

@ -22,11 +22,6 @@
#include "engine.h"
/* FIXME: Correct check? */
#ifdef GPGSM_PATH
#define ENABLE_GPGSM 1
#endif
struct engine_ops
{
/* Static functions. */
@ -132,5 +127,8 @@ extern struct engine_ops _gpgme_engine_ops_gpgconf; /* gpg-conf. */
#ifdef ENABLE_ASSUAN
extern struct engine_ops _gpgme_engine_ops_assuan; /* Low-level Assuan. */
#endif
#ifdef ENABLE_G13
extern struct engine_ops _gpgme_engine_ops_g13; /* Crypto VFS. */
#endif
#endif /* ENGINE_BACKEND_H */

796
src/engine-g13.c Normal file
View File

@ -0,0 +1,796 @@
/* engine-g13.c - G13 engine.
Copyright (C) 2000 Werner Koch (dd9jn)
Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2009 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 <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <assert.h>
#include <unistd.h>
#include <locale.h>
#include <fcntl.h> /* FIXME */
#include <errno.h>
#include "gpgme.h"
#include "util.h"
#include "ops.h"
#include "wait.h"
#include "priv-io.h"
#include "sema.h"
#include "assuan.h"
#include "debug.h"
#include "engine-backend.h"
typedef struct
{
int fd; /* FD we talk about. */
int server_fd;/* Server FD for this connection. */
int dir; /* Inbound/Outbound, maybe given implicit? */
void *data; /* Handler-specific data. */
void *tag; /* ID from the user for gpgme_remove_io_callback. */
char server_fd_str[15]; /* Same as SERVER_FD but as a string. We
need this because _gpgme_io_fd2str can't
be used on a closed descriptor. */
} iocb_data_t;
struct engine_g13
{
assuan_context_t assuan_ctx;
int lc_ctype_set;
int lc_messages_set;
iocb_data_t status_cb;
struct gpgme_io_cbs io_cbs;
/* Internal callbacks. */
engine_assuan_result_cb_t result_cb;
void *result_cb_value;
/* User provided callbacks. */
struct {
gpgme_assuan_data_cb_t data_cb;
void *data_cb_value;
gpgme_assuan_inquire_cb_t inq_cb;
void *inq_cb_value;
gpgme_assuan_status_cb_t status_cb;
void *status_cb_value;
} user;
};
typedef struct engine_g13 *engine_g13_t;
static void g13_io_event (void *engine,
gpgme_event_io_t type, void *type_data);
static char *
g13_get_version (const char *file_name)
{
return _gpgme_get_program_version (file_name ? file_name
: _gpgme_get_g13_path ());
}
static const char *
g13_get_req_version (void)
{
return NEED_G13_VERSION;
}
static void
close_notify_handler (int fd, void *opaque)
{
engine_g13_t g13 = opaque;
assert (fd != -1);
if (g13->status_cb.fd == fd)
{
if (g13->status_cb.tag)
(*g13->io_cbs.remove) (g13->status_cb.tag);
g13->status_cb.fd = -1;
g13->status_cb.tag = NULL;
}
}
/* This is the default inquiry callback. We use it to handle the
Pinentry notifications. */
static gpgme_error_t
default_inq_cb (engine_g13_t g13, const char *keyword, const char *args)
{
gpg_error_t err;
if (!strcmp (keyword, "PINENTRY_LAUNCHED"))
{
_gpgme_allow_set_foreground_window ((pid_t)strtoul (args, NULL, 10));
}
if (g13->user.inq_cb)
{
gpgme_data_t data = NULL;
err = g13->user.inq_cb (g13->user.inq_cb_value,
keyword, args, &data);
if (!err && data)
{
/* FIXME: Returning data is not yet implemented. However we
need to allow the caller to cleanup his data object.
Thus we run the callback in finish mode immediately. */
err = g13->user.inq_cb (g13->user.inq_cb_value,
NULL, NULL, &data);
}
}
else
err = 0;
return err;
}
static gpgme_error_t
g13_cancel (void *engine)
{
engine_g13_t g13 = engine;
if (!g13)
return gpg_error (GPG_ERR_INV_VALUE);
if (g13->status_cb.fd != -1)
_gpgme_io_close (g13->status_cb.fd);
if (g13->assuan_ctx)
{
assuan_release (g13->assuan_ctx);
g13->assuan_ctx = NULL;
}
return 0;
}
static void
g13_release (void *engine)
{
engine_g13_t g13 = engine;
if (!g13)
return;
g13_cancel (engine);
free (g13);
}
static gpgme_error_t
g13_new (void **engine, const char *file_name, const char *home_dir)
{
gpgme_error_t err = 0;
engine_g13_t g13;
int argc;
char *argv[5];
char *dft_display = NULL;
char dft_ttyname[64];
char *dft_ttytype = NULL;
char *optstr;
g13 = calloc (1, sizeof *g13);
if (!g13)
return gpg_error_from_errno (errno);
g13->status_cb.fd = -1;
g13->status_cb.dir = 1;
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)
{
argv[argc++] = "--homedir";
argv[argc++] = home_dir;
}
argv[argc++] = "--server";
argv[argc++] = NULL;
err = assuan_new_ext (&g13->assuan_ctx, GPG_ERR_SOURCE_GPGME,
&_gpgme_assuan_malloc_hooks, _gpgme_assuan_log_cb,
NULL);
if (err)
goto leave;
assuan_ctx_set_system_hooks (g13->assuan_ctx, &_gpgme_assuan_system_hooks);
#if USE_DESCRIPTOR_PASSING
err = assuan_pipe_connect_ext
(g13->assuan_ctx, file_name ? file_name : _gpgme_get_g13_path (),
argv, NULL, NULL, NULL, 1);
#else
err = assuan_pipe_connect
(g13->assuan_ctx, file_name ? file_name : _gpgme_get_g13_path (),
argv, NULL);
#endif
if (err)
goto leave;
err = _gpgme_getenv ("DISPLAY", &dft_display);
if (err)
goto leave;
if (dft_display)
{
if (asprintf (&optstr, "OPTION display=%s", dft_display) < 0)
{
free (dft_display);
err = gpg_error_from_errno (errno);
goto leave;
}
free (dft_display);
err = assuan_transact (g13->assuan_ctx, optstr, NULL, NULL, NULL,
NULL, NULL, NULL);
free (optstr);
if (err)
goto leave;
}
if (isatty (1))
{
int rc;
rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
if (rc)
{
err = gpg_error_from_errno (rc);
goto leave;
}
else
{
if (asprintf (&optstr, "OPTION ttyname=%s", dft_ttyname) < 0)
{
err = gpg_error_from_errno (errno);
goto leave;
}
err = assuan_transact (g13->assuan_ctx, optstr, NULL, NULL, NULL,
NULL, NULL, NULL);
free (optstr);
if (err)
goto leave;
err = _gpgme_getenv ("TERM", &dft_ttytype);
if (err)
goto leave;
if (dft_ttytype)
{
if (asprintf (&optstr, "OPTION ttytype=%s", dft_ttytype) < 0)
{
free (dft_ttytype);
err = gpg_error_from_errno (errno);
goto leave;
}
free (dft_ttytype);
err = assuan_transact (g13->assuan_ctx, optstr, NULL, NULL,
NULL, NULL, NULL, NULL);
free (optstr);
if (err)
goto leave;
}
}
}
#ifdef HAVE_W32_SYSTEM
/* Under Windows we need to use AllowSetForegroundWindow. Tell
g13 to tell us when it needs it. */
if (!err)
{
err = assuan_transact (g13->assuan_ctx, "OPTION allow-pinentry-notify",
NULL, NULL, NULL, NULL, NULL, NULL);
if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
err = 0; /* This is a new feature of g13. */
}
#endif /*HAVE_W32_SYSTEM*/
leave:
if (err)
g13_release (g13);
else
*engine = g13;
return err;
}
static gpgme_error_t
g13_set_locale (void *engine, int category, const char *value)
{
engine_g13_t g13 = engine;
gpgme_error_t err;
char *optstr;
char *catstr;
/* FIXME: If value is NULL, we need to reset the option to default.
But we can't do this. So we error out here. G13 needs support
for this. */
if (category == LC_CTYPE)
{
catstr = "lc-ctype";
if (!value && g13->lc_ctype_set)
return gpg_error (GPG_ERR_INV_VALUE);
if (value)
g13->lc_ctype_set = 1;
}
#ifdef LC_MESSAGES
else if (category == LC_MESSAGES)
{
catstr = "lc-messages";
if (!value && g13->lc_messages_set)
return gpg_error (GPG_ERR_INV_VALUE);
if (value)
g13->lc_messages_set = 1;
}
#endif /* LC_MESSAGES */
else
return gpg_error (GPG_ERR_INV_VALUE);
/* FIXME: Reset value to default. */
if (!value)
return 0;
if (asprintf (&optstr, "OPTION %s=%s", catstr, value) < 0)
err = gpg_error_from_errno (errno);
else
{
err = assuan_transact (g13->assuan_ctx, optstr, NULL, NULL,
NULL, NULL, NULL, NULL);
free (optstr);
}
return err;
}
/* Forward declaration. */
static gpgme_status_code_t parse_status (const char *name);
static gpgme_error_t
g13_assuan_simple_command (assuan_context_t ctx, char *cmd,
engine_status_handler_t status_fnc,
void *status_fnc_value)
{
gpg_error_t err;
char *line;
size_t linelen;
err = assuan_write_line (ctx, cmd);
if (err)
return err;
do
{
err = assuan_read_line (ctx, &line, &linelen);
if (err)
return err;
if (*line == '#' || !linelen)
continue;
if (linelen >= 2
&& line[0] == 'O' && line[1] == 'K'
&& (line[2] == '\0' || line[2] == ' '))
return 0;
else if (linelen >= 4
&& line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
&& line[3] == ' ')
err = atoi (&line[4]);
else if (linelen >= 2
&& line[0] == 'S' && line[1] == ' ')
{
char *rest;
gpgme_status_code_t r;
rest = strchr (line + 2, ' ');
if (!rest)
rest = line + linelen; /* set to an empty string */
else
*(rest++) = 0;
r = parse_status (line + 2);
if (r >= 0 && status_fnc)
err = status_fnc (status_fnc_value, r, rest);
else
err = gpg_error (GPG_ERR_GENERAL);
}
else
err = gpg_error (GPG_ERR_GENERAL);
}
while (!err);
return err;
}
static gpgme_error_t
status_handler (void *opaque, int fd)
{
gpgme_error_t err = 0;
engine_g13_t g13 = opaque;
char *line;
size_t linelen;
do
{
err = assuan_read_line (g13->assuan_ctx, &line, &linelen);
if (err)
{
/* Try our best to terminate the connection friendly. */
/* assuan_write_line (g13->assuan_ctx, "BYE"); */
TRACE2 (DEBUG_CTX, "gpgme:status_handler", g13,
"fd 0x%x: error reading assuan line: %s",
fd, gpg_strerror (err));
}
else if (linelen >= 3
&& line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
&& (line[3] == '\0' || line[3] == ' '))
{
if (line[3] == ' ')
err = atoi (&line[4]);
if (! err)
err = gpg_error (GPG_ERR_GENERAL);
TRACE2 (DEBUG_CTX, "gpgme:status_handler", g13,
"fd 0x%x: ERR line: %s",
fd, err ? gpg_strerror (err) : "ok");
/* In g13, command execution errors are not fatal, as we use
a session based protocol. */
if (g13->result_cb)
err = g13->result_cb (g13->result_cb_value, err);
else
err = 0;
if (!err)
{
_gpgme_io_close (g13->status_cb.fd);
return 0;
}
}
else if (linelen >= 2
&& line[0] == 'O' && line[1] == 'K'
&& (line[2] == '\0' || line[2] == ' '))
{
TRACE1 (DEBUG_CTX, "gpgme:status_handler", g13,
"fd 0x%x: OK line", fd);
if (g13->result_cb)
err = g13->result_cb (g13->result_cb_value, 0);
else
err = 0;
if (!err)
{
_gpgme_io_close (g13->status_cb.fd);
return 0;
}
}
else if (linelen > 2
&& line[0] == 'D' && line[1] == ' ')
{
/* We are using the colon handler even for plain inline data
- strange name for that function but for historic reasons
we keep it. */
/* FIXME We can't use this for binary data because we
assume this is a string. For the current usage of colon
output it is correct. */
char *src = line + 2;
char *end = line + linelen;
char *dst = src;
linelen = 0;
while (src < end)
{
if (*src == '%' && src + 2 < end)
{
/* Handle escaped characters. */
++src;
*dst++ = _gpgme_hextobyte (src);
src += 2;
}
else
*dst++ = *src++;
linelen++;
}
src = line + 2;
if (linelen && g13->user.data_cb)
err = g13->user.data_cb (g13->user.data_cb_value,
src, linelen);
else
err = 0;
TRACE2 (DEBUG_CTX, "gpgme:g13_status_handler", g13,
"fd 0x%x: D inlinedata; status from cb: %s",
fd, (g13->user.data_cb ?
(err? gpg_strerror (err):"ok"):"no callback"));
}
else if (linelen > 2
&& line[0] == 'S' && line[1] == ' ')
{
char *src;
char *args;
src = line + 2;
while (*src == ' ')
src++;
args = strchr (line + 2, ' ');
if (!args)
args = line + linelen; /* set to an empty string */
else
*(args++) = 0;
while (*args == ' ')
args++;
if (g13->user.status_cb)
err = g13->user.status_cb (g13->user.status_cb_value,
src, args);
else
err = 0;
TRACE3 (DEBUG_CTX, "gpgme:g13_status_handler", g13,
"fd 0x%x: S line (%s) - status from cb: %s",
fd, line+2, (g13->user.status_cb ?
(err? gpg_strerror (err):"ok"):"no callback"));
}
else if (linelen >= 7
&& line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
&& line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
&& line[6] == 'E'
&& (line[7] == '\0' || line[7] == ' '))
{
char *src;
char *args;
for (src=line+7; *src == ' '; src++)
;
args = strchr (src, ' ');
if (!args)
args = line + linelen; /* Let it point to an empty string. */
else
*(args++) = 0;
while (*args == ' ')
args++;
err = default_inq_cb (g13, src, args);
if (!err)
{
/* Flush and send END. */
err = assuan_send_data (g13->assuan_ctx, NULL, 0);
}
else if (gpg_err_code (err) == GPG_ERR_ASS_CANCELED)
{
/* Flush and send CANcel. */
err = assuan_send_data (g13->assuan_ctx, NULL, 1);
}
assuan_write_line (g13->assuan_ctx, "END");
}
}
while (!err && assuan_pending_line (g13->assuan_ctx));
return err;
}
static gpgme_error_t
add_io_cb (engine_g13_t g13, iocb_data_t *iocbd, gpgme_io_cb_t handler)
{
gpgme_error_t err;
TRACE_BEG2 (DEBUG_ENGINE, "engine-g13:add_io_cb", g13,
"fd %d, dir %d", iocbd->fd, iocbd->dir);
err = (*g13->io_cbs.add) (g13->io_cbs.add_priv,
iocbd->fd, iocbd->dir,
handler, iocbd->data, &iocbd->tag);
if (err)
return TRACE_ERR (err);
if (!iocbd->dir)
/* FIXME Kludge around poll() problem. */
err = _gpgme_io_set_nonblocking (iocbd->fd);
return TRACE_ERR (err);
}
static gpgme_error_t
start (engine_g13_t g13, const char *command)
{
gpgme_error_t err;
int fdlist[5];
int nfds;
/* We need to know the fd used by assuan for reads. We do this by
using the assumption that the first returned fd from
assuan_get_active_fds() is always this one. */
nfds = assuan_get_active_fds (g13->assuan_ctx, 0 /* read fds */,
fdlist, DIM (fdlist));
if (nfds < 1)
return gpg_error (GPG_ERR_GENERAL); /* FIXME */
/* We "duplicate" the file descriptor, so we can close it here (we
can't close fdlist[0], as that is closed by libassuan, and
closing it here might cause libassuan to close some unrelated FD
later). Alternatively, we could special case status_fd and
register/unregister it manually as needed, but this increases
code duplication and is more complicated as we can not use the
close notifications etc. A third alternative would be to let
Assuan know that we closed the FD, but that complicates the
Assuan interface. */
g13->status_cb.fd = _gpgme_io_dup (fdlist[0]);
if (g13->status_cb.fd < 0)
return gpg_error_from_syserror ();
if (_gpgme_io_set_close_notify (g13->status_cb.fd,
close_notify_handler, g13))
{
_gpgme_io_close (g13->status_cb.fd);
g13->status_cb.fd = -1;
return gpg_error (GPG_ERR_GENERAL);
}
err = add_io_cb (g13, &g13->status_cb, status_handler);
if (!err)
err = assuan_write_line (g13->assuan_ctx, command);
if (!err)
g13_io_event (g13, GPGME_EVENT_START, NULL);
return err;
}
#if USE_DESCRIPTOR_PASSING
static gpgme_error_t
g13_reset (void *engine)
{
engine_g13_t g13 = engine;
/* We must send a reset because we need to reset the list of
signers. Note that RESET does not reset OPTION commands. */
return g13_assuan_simple_command (g13->assuan_ctx, "RESET", NULL, NULL);
}
#endif
static gpgme_error_t
g13_transact (void *engine,
const char *command,
engine_assuan_result_cb_t result_cb,
void *result_cb_value,
gpgme_assuan_data_cb_t data_cb,
void *data_cb_value,
gpgme_assuan_inquire_cb_t inq_cb,
void *inq_cb_value,
gpgme_assuan_status_cb_t status_cb,
void *status_cb_value)
{
engine_g13_t g13 = engine;
gpgme_error_t err;
if (!g13 || !command || !*command)
return gpg_error (GPG_ERR_INV_VALUE);
g13->result_cb = result_cb;
g13->result_cb_value = result_cb_value;
g13->user.data_cb = data_cb;
g13->user.data_cb_value = data_cb_value;
g13->user.inq_cb = inq_cb;
g13->user.inq_cb_value = inq_cb_value;
g13->user.status_cb = status_cb;
g13->user.status_cb_value = status_cb_value;
err = start (g13, command);
return err;
}
static void
g13_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
{
engine_g13_t g13 = engine;
g13->io_cbs = *io_cbs;
}
static void
g13_io_event (void *engine, gpgme_event_io_t type, void *type_data)
{
engine_g13_t g13 = engine;
TRACE3 (DEBUG_ENGINE, "gpgme:g13_io_event", g13,
"event %p, type %d, type_data %p",
g13->io_cbs.event, type, type_data);
if (g13->io_cbs.event)
(*g13->io_cbs.event) (g13->io_cbs.event_priv, type, type_data);
}
struct engine_ops _gpgme_engine_ops_g13 =
{
/* Static functions. */
_gpgme_get_g13_path,
NULL,
g13_get_version,
g13_get_req_version,
g13_new,
/* Member functions. */
g13_release,
#if USE_DESCRIPTOR_PASSING
g13_reset,
#else
NULL, /* reset */
#endif
NULL, /* set_status_handler */
NULL, /* set_command_handler */
NULL, /* set_colon_line_handler */
g13_set_locale,
NULL, /* decrypt */
NULL, /* delete */
NULL, /* edit */
NULL, /* encrypt */
NULL, /* encrypt_sign */
NULL, /* export */
NULL, /* export_ext */
NULL, /* genkey */
NULL, /* import */
NULL, /* keylist */
NULL, /* keylist_ext */
NULL, /* sign */
NULL, /* trustlist */
NULL, /* verify */
NULL, /* getauditlog */
g13_transact,
NULL, /* conf_load */
NULL, /* conf_save */
g13_set_io_cbs,
g13_io_event,
g13_cancel
};

View File

@ -55,8 +55,13 @@ static struct engine_ops *engine_ops[] =
#else
NULL,
#endif
#ifdef ENABLE_GPGSM /* This indicates that we have assuan support. */
&_gpgme_engine_ops_assuan /* Low-Level Assuan. */
#ifdef ENABLE_ASSUAN
&_gpgme_engine_ops_assuan, /* Low-Level Assuan. */
#else
NULL
#endif
#ifdef ENABLE_G13
&_gpgme_engine_ops_g13 /* Crypto VFS. */
#else
NULL
#endif
@ -194,7 +199,8 @@ gpgme_get_engine_info (gpgme_engine_info_t *info)
gpgme_protocol_t proto_list[] = { GPGME_PROTOCOL_OpenPGP,
GPGME_PROTOCOL_CMS,
GPGME_PROTOCOL_GPGCONF,
GPGME_PROTOCOL_ASSUAN };
GPGME_PROTOCOL_ASSUAN,
GPGME_PROTOCOL_G13 };
unsigned int proto;
for (proto = 0; proto < DIM (proto_list); proto++)

229
src/g13.c Normal file
View File

@ -0,0 +1,229 @@
/* g13.c - g13 support in GPGME
Copyright (C) 2009 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 <stdlib.h>
#include "gpgme.h"
#include "context.h"
#include "ops.h"
#include "util.h"
typedef struct
{
struct _gpgme_op_g13_result result;
} *op_data_t;
/* This callback is used to return the status of the assuan command
back rather than transmission errors. */
static gpgme_error_t
result_cb (void *priv, gpgme_error_t result)
{
gpgme_ctx_t ctx = (gpgme_ctx_t)priv;
gpgme_error_t err;
void *hook;
op_data_t opd;
err = _gpgme_op_data_lookup (ctx, OPDATA_ASSUAN, &hook, -1, NULL);
opd = hook;
if (err)
return err;
if (!opd)
return gpg_error (GPG_ERR_INTERNAL);
opd->result.err = result;
return 0;
}
gpgme_g13_result_t
gpgme_op_g13_result (gpgme_ctx_t ctx)
{
gpgme_error_t err;
void *hook;
op_data_t opd;
err = _gpgme_op_data_lookup (ctx, OPDATA_ASSUAN, &hook, -1, NULL);
opd = hook;
/* Check in case this function is used without having run a command
before. */
if (err || !opd)
return NULL;
return &opd->result;
}
static gpgme_error_t
opg13_start (gpgme_ctx_t ctx, int synchronous,
const char *command,
gpgme_assuan_data_cb_t data_cb,
void *data_cb_value,
gpgme_assuan_inquire_cb_t inq_cb,
void *inq_cb_value,
gpgme_assuan_status_cb_t status_cb,
void *status_cb_value)
{
gpgme_error_t err;
void *hook;
op_data_t opd;
if (!command || !*command)
return gpg_error (GPG_ERR_INV_VALUE);
/* The flag value 256 is used to suppress an engine reset. This is
required to keep the connection running. */
err = _gpgme_op_reset (ctx, ((synchronous & 255) | 256));
if (err)
return err;
err = _gpgme_op_data_lookup (ctx, OPDATA_ASSUAN, &hook, sizeof (*opd), NULL);
opd = hook;
if (err)
return err;
opd->result.err = gpg_error (GPG_ERR_UNFINISHED);
return _gpgme_engine_op_assuan_transact (ctx->engine, command,
result_cb, ctx,
data_cb, data_cb_value,
inq_cb, inq_cb_value,
status_cb, status_cb_value);
}
/* XXXX. This is the asynchronous variant. */
static gpgme_error_t
gpgme_op_g13_transact_start (gpgme_ctx_t ctx,
const char *command,
gpgme_assuan_data_cb_t data_cb,
void *data_cb_value,
gpgme_assuan_inquire_cb_t inq_cb,
void *inq_cb_value,
gpgme_assuan_status_cb_t status_cb,
void *status_cb_value)
{
return opg13_start (ctx, 0, command, data_cb, data_cb_value,
inq_cb, inq_cb_value, status_cb, status_cb_value);
}
/* XXXX. This is the synchronous variant. */
static gpgme_error_t
gpgme_op_g13_transact (gpgme_ctx_t ctx,
const char *command,
gpgme_assuan_data_cb_t data_cb,
void *data_cb_value,
gpgme_assuan_inquire_cb_t inq_cb,
void *inq_cb_value,
gpgme_assuan_status_cb_t status_cb,
void *status_cb_value)
{
gpgme_error_t err;
err = opg13_start (ctx, 1, command, data_cb, data_cb_value,
inq_cb, inq_cb_value, status_cb, status_cb_value);
if (!err)
err = _gpgme_wait_one (ctx);
return err;
}
/* The actual exported interface follows. */
static gpg_error_t
get_err (gpgme_ctx_t ctx)
{
gpgme_g13_result_t res;
res = gpgme_op_g13_result (ctx);
if (! res)
return gpg_error (GPG_ERR_GENERAL);
return res->err;
}
/* The container is automatically unmounted when the context is reset
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_g13_mount (gpgme_ctx_t ctx, const char *container_file,
const char *mount_dir, int flags)
{
gpg_error_t err;
char *cmd;
char *container_file_esc = NULL;
err = _gpgme_encode_percent_string (container_file, &container_file_esc, 0);
if (err)
return err;
if (asprintf (&cmd, "OPEN -- %s", container_file_esc) < 0)
{
err = gpg_error_from_syserror ();
free (container_file_esc);
return err;
}
free (container_file_esc);
err = gpgme_op_g13_transact (ctx, cmd, NULL, NULL, NULL, NULL,
NULL, NULL);
free (cmd);
err = err || get_err (ctx);
if (err)
return err;
if (mount_dir)
{
char *mount_dir_esc = NULL;
err = _gpgme_encode_percent_string (mount_dir, &mount_dir_esc, 0);
if (err)
return err;
if (asprintf (&cmd, "MOUNT -- %s", mount_dir_esc) < 0)
{
err = gpg_error_from_syserror ();
free (mount_dir_esc);
return err;
}
free (mount_dir_esc);
}
else
{
if (asprintf (&cmd, "MOUNT") < 0)
return gpg_error_from_syserror ();
}
err = gpgme_op_g13_transact (ctx, cmd, NULL, NULL, NULL, NULL,
NULL, NULL);
free (cmd);
/* Note: in symmetry with the asynchronous variant, we don't return
the error in the result structure here, if any. */
return err;
}

View File

@ -248,7 +248,8 @@ gpgme_set_protocol (gpgme_ctx_t ctx, gpgme_protocol_t protocol)
if (protocol != GPGME_PROTOCOL_OpenPGP
&& protocol != GPGME_PROTOCOL_CMS
&& protocol != GPGME_PROTOCOL_ASSUAN)
&& protocol != GPGME_PROTOCOL_ASSUAN
&& protocol != GPGME_PROTOCOL_G13)
return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
if (ctx->protocol != protocol)
@ -292,6 +293,9 @@ gpgme_get_protocol_name (gpgme_protocol_t protocol)
case GPGME_PROTOCOL_ASSUAN:
return "Assuan";
case GPGME_PROTOCOL_G13:
return "G13";
case GPGME_PROTOCOL_UNKNOWN:
return "unknown";

View File

@ -185,5 +185,7 @@ EXPORTS
gpgme_op_export_keys @142
gpgme_op_export_keys_start @143
gpgme_op_g13_mount @144
; END

View File

@ -324,6 +324,7 @@ typedef enum
GPGME_PROTOCOL_CMS = 1,
GPGME_PROTOCOL_GPGCONF = 2, /* Special code for gpgconf. */
GPGME_PROTOCOL_ASSUAN = 3, /* Low-level access to an Assuan server. */
GPGME_PROTOCOL_G13 = 4,
GPGME_PROTOCOL_UNKNOWN = 255
}
gpgme_protocol_t;
@ -1735,7 +1736,10 @@ typedef gpgme_error_t (*gpgme_assuan_status_cb_t)
struct _gpgme_op_assuan_result
{
/* The result of the actual assuan command. An OK is indicated by a
value of 0 and an ERR by the respective error error value. */
value of 0 and an ERR by the respective error error value. This
is required because assuan operations use a session-based
interface. The error code of the GPGME function calls just
reflects transmission errors. */
gpgme_error_t err;
};
typedef struct _gpgme_op_assuan_result *gpgme_assuan_result_t;
@ -1767,6 +1771,26 @@ gpgme_error_t gpgme_op_assuan_transact (gpgme_ctx_t ctx,
void *stat_cb_value);
/* Crypto container support. */
struct _gpgme_op_g13_result
{
/* The result of the actual assuan command. An OK is indicated by a
value of 0 and an ERR by the respective error error value. This
is required because assuan operations use a session-based
interface. The error code of the GPGME function calls just
reflects transmission errors. */
gpgme_error_t err;
};
typedef struct _gpgme_op_g13_result *gpgme_g13_result_t;
/* The container is automatically unmounted when the context is reset
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_g13_mount (gpgme_ctx_t ctx, const char *container_file,
const char *mount_dir, int flags);
/* Interface to gpgconf(1). */

View File

@ -64,6 +64,8 @@ GPGME_1.1 {
gpgme_op_import_keys_start;
gpgme_op_export_keys;
gpgme_op_export_keys_start;
gpgme_op_g13_mount;
};

View File

@ -59,6 +59,16 @@ _gpgme_get_gpgconf_path (void)
#endif
}
const char *
_gpgme_get_g13_path (void)
{
#ifdef G13_PATH
return G13_PATH;
#else
return NULL;
#endif
}
/* See w32-util.c */
int
_gpgme_get_conf_int (const char *key, int *value)

View File

@ -32,6 +32,7 @@
const char *_gpgme_get_gpg_path (void);
const char *_gpgme_get_gpgsm_path (void);
const char *_gpgme_get_gpgconf_path (void);
const char *_gpgme_get_g13_path (void);
int _gpgme_get_conf_int (const char *key, int *value);
void _gpgme_allow_set_foreground_window (pid_t pid);
@ -93,6 +94,9 @@ gpgme_error_t _gpgme_decode_c_string (const char *src, char **destp,
gpgme_error_t _gpgme_decode_percent_string (const char *src, char **destp,
size_t len, int binary);
gpgme_error_t _gpgme_encode_percent_string (const char *src, char **destp,
size_t len);
/* Parse the string TIMESTAMP into a time_t. The string may either be
seconds since Epoch or in the ISO 8601 format like

View File

@ -361,6 +361,25 @@ _gpgme_get_gpgconf_path (void)
}
const char *
_gpgme_get_g13_path (void)
{
static char *g13_program;
LOCK (get_path_lock);
#if 0
if (!g13_program)
g13_program = find_program_in_registry ("g13Program");
#endif
if (!g13_program)
g13_program = find_program_in_inst_dir ("g13.exe");
if (!g13_program)
g13_program = find_program_at_standard_place ("GNU\\GnuPG\\g13.exe");
UNLOCK (get_path_lock);
return g13_program;
}
const char *
_gpgme_get_w32spawn_path (void)
{