* configure.ac: Support gpgconf.
gpgme/
2008-01-04 Marcus Brinkmann <marcus@g10code.de>
* Makefile.am (gpgconf_components): New variable.
(main_sources): Add gpgconf.c.
* gpgme.h (gpgme_protocol_t): New protocol GPGME_PROTOCOL_GPGCONF.
(gpgme_conf_level_t, gpgme_conf_type_t, gpgme_conf_arg_t)
(gpgme_conf_opt_t, gpgme_conf_comp_t, gpgme_conf_arg_new)
(gpgme_conf_arg_release, gpgme_conf_opt_change)
(gpgme_conf_release, gpgme_op_conf_load, gpgme_op_conf_save): New
types.
* gpgconf.c, engine-gpgconf.c: New files.
* engine.h: (_gpgme_engine_op_conf_load,
(_gpgme_engine_op_conf_save): New prototypes.
* op-support.c (_gpgme_op_reset): Ignore not implemented locale
function.
* posix-util.c (_gpgme_get_gpgconf_path): New function.
* w32-util.c (_gpgme_get_gpgconf_path): New function.
* engine-gpgsm.c:
(_gpgme_engine_ops_gpgsm): Add stubs for conf_load and conf_save.
* rungpg.c:
(_gpgme_engine_ops_gpg): Add stubs for conf_load and conf_save.
* gpgme.def: Add new gpgconf related interfaces.
* libgpgme.vers: Likewise.
* util.h (_gpgme_get_gpgconf_path): New prototype.
* gpgme.h (gpgme_protocol_t): Add GPGME_PROTOCOL_GPGCONF.
* engine-backend.h (_gpgme_engine_ops_gpgconf): New prototype.
(struct engine_ops): Add members for conf_load and conf_save.
* engine.c (engine_ops): Add _gpgme_engine_ops_gpgconf.
(_gpgme_engine_op_conf_load,
(_gpgme_engine_op_conf_save): New functions.
(gpgme_get_engine_info): Allow protocol GPGME_PROTOCOL_GPGCONF.
tests/
2008-01-04 Marcus Brinkmann <marcus@g10code.de>
* Makefile.am (TESTS_ENVIRONMENT): Use absolute path for
GNUPGHOME.
* gpg/Makefile.am (TESTS_ENVIRONMENT): Use absolute path for
GNUPGHOME.
* gpgsm/Makefile.am (TESTS_ENVIRONMENT): Use absolute path for
GNUPGHOME.
* gpg/Makefile.am (TESTS): Add t-gpgconf.
t-gpgconf.c: New file.
+2008-01-04 Marcus Brinkmann <marcus@g10code.de>
+
+ * configure.ac: Support gpgconf.
+
2007-09-27 Marcus Brinkmann <marcus@g10code.de>
* assuan-pipe-connect.c (pipe_connect_gpgme): Do not close process
GPG_DEFAULT=no
GPGSM_DEFAULT=no
+GPGCONF_DEFAULT=no
component_system=None
have_dosish_system=no
have_w32_system=no
have_w32_system=yes
GPG_DEFAULT='c:\\gnupg\\gpg.exe'
GPGSM_DEFAULT='c:\\gnupg\\gpgsm.exe'
+ GPGCONF_DEFAULT='c:\\gnupg\\gpgconf.exe'
#component_system='COM+'
AM_PATH_GLIB_2_0
# XXX: Probably use exec-prefix here?
# GPG_DEFAULT='/usr/bin/gpg'
# GPGSM_DEFAULT='/usr/bin/gpgsm'
+# GPGCONF_DEFAULT='/usr/bin/gpgconf'
;;
esac
# Checks for system services
NEED_GPG_VERSION_DEFAULT=1.3.0
NEED_GPGSM_VERSION_DEFAULT=1.9.6
+NEED_GPGCONF_VERSION_DEFAULT=2.0.4
NEED_GPG_VERSION="$NEED_GPG_VERSION_DEFAULT"
NEED_GPGSM_VERSION="$NEED_GPGSM_VERSION_DEFAULT"
+NEED_GPGCONF_VERSION="$NEED_GPGCONF_VERSION_DEFAULT"
AC_ARG_WITH(gpg-version,
AC_HELP_STRING([--with-gpg-version=VER], [require GnuPG version VER]),
NEED_GPG_VERSION=$withval)
if test "$NEED_GPGSM_VERSION" = "no"; then
NEED_GPGSM_VERSION=0.0.0
fi
+AC_ARG_WITH(gpgconf-version,
+ AC_HELP_STRING([--with-gpgconf-version=VER], [require GPGCONF version VER]),
+ NEED_GPGCONF_VERSION=$withval)
+if test "$NEED_GPGCONF_VERSION" = "yes"; then
+ NEED_GPGCONF_VERSION="$NEED_GPGCONF_VERSION_DEFAULT"
+fi
+if test "$NEED_GPGCONF_VERSION" = "no"; then
+ NEED_GPGCONF_VERSION=0.0.0
+fi
AC_DEFINE_UNQUOTED(NEED_GPG_VERSION, "$NEED_GPG_VERSION",
[Min. needed GnuPG version.])
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.])
NO_OVERRIDE=no
AM_CONDITIONAL(RUN_GPGSM_TESTS, test "$run_gpgsm_test" = "yes")
+NO_OVERRIDE=no
+AC_ARG_WITH(gpgconf,
+ AC_HELP_STRING([--with-gpgconf=PATH],
+ [use gpgconf binary at PATH]),
+ GPGCONF=$withval, NO_OVERRIDE=yes)
+if test "$NO_OVERRIDE" = "yes" || test "$GPGCONF" = "yes"; then
+ GPGCONF=
+ NO_OVERRIDE=yes
+ if test "$cross_compiling" != "yes"; then
+ AC_PATH_PROG(GPGCONF, gpgconf)
+ fi
+ if test -z "$GPGCONF"; then
+ GPGCONF="$GPGCONF_DEFAULT"
+ fi
+fi
+if test "$GPGCONF" = no; then
+ if test "$NO_OVERRIDE" = "yes"; then
+ if test "$cross_compiling" != "yes"; then
+ AC_MSG_WARN([
+***
+*** Could not find gpgconf, install gpgconf or use --with-gpgconf=PATH to enable it
+***])
+ else
+ AC_MSG_ERROR([
+***
+*** Can not determine path to gpgconf when cross-compiling, use --with-gpgconf=PATH
+***])
+ fi
+ fi
+else
+ AC_DEFINE_UNQUOTED(GPGCONF_PATH, "$GPGCONF", [Path to the GPGCONF binary.])
+ AC_DEFINE(ENABLE_GPGCONF,1,[Whether GPGCONF support is enabled])
+fi
+AM_CONDITIONAL(HAVE_GPGCONF, test "$GPGCONF" != "no")
+
+dnl Check for GPGCONF version requirement.
+GPGCONF_VERSION=unknown
+ok=maybe
+if test -z "$GPGCONF" -o "x$GPGCONF" = "xno"; then
+ ok=no
+else
+ if test "$cross_compiling" = "yes"; then
+ AC_MSG_WARN([GPGCONF version can not be checked when cross compiling])
+ ok=no
+ else
+ if test ! -x "$GPGCONF"; then
+ AC_MSG_WARN([GPGCONF not executable, version check disabled])
+ ok=no
+ fi
+ fi
+fi
+if test "$ok" = "maybe"; then
+ AC_MSG_CHECKING(for GPGCONF >= $NEED_GPGCONF_VERSION)
+ req_major=`echo $NEED_GPGCONF_VERSION | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/'`
+ req_minor=`echo $NEED_GPGCONF_VERSION | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/'`
+ req_micro=`echo $NEED_GPGCONF_VERSION | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'`
+ GPGCONF_VERSION=`$GPGCONF --version | sed -n '1 s/[[^0-9]]*\(.*\)/\1/p'`
+ major=`echo $GPGCONF_VERSION | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\1/'`
+ minor=`echo $GPGCONF_VERSION | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\2/'`
+ micro=`echo $GPGCONF_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([GPGCONF must be at least version $NEED_GPGCONF_VERSION])
+ fi
+fi
+run_gpgconf_test="$ok"
+AC_ARG_ENABLE(gpgconf-test,
+ AC_HELP_STRING([--disable-gpgconf-test], [disable GPGCONF run test]),
+ run_gpgconf_test=$enableval)
+AM_CONDITIONAL(RUN_GPGCONF_TESTS, test "$run_gpgconf_test" = "yes")
+
+# Only build if supported.
+AM_CONDITIONAL(BUILD_GPGCONF, test "$GPGCONF" != "no")
+if test "$GPGCONF" != "no"; then
+ AC_DEFINE(HAVE_GPGCONF, 1,
+ [Defined if we are building with gpgconf support.])
+fi
+
+
# FIXME: Only build if supported.
AM_CONDITIONAL(BUILD_ASSUAN, test "$GPGSM" != "no")
if test "$GPGSM" != "no"; then
echo "
GPGME v${VERSION} has been configured as follows:
- GnuPG path: $GPG
- GnuPG version: $GPG_VERSION, min. $NEED_GPG_VERSION
+ GnuPG path: $GPG
+ GnuPG version: $GPG_VERSION, min. $NEED_GPG_VERSION
+
+ GpgSM path: $GPGSM
+ GpgSM version: $GPGSM_VERSION, min. $NEED_GPGSM_VERSION
- GpgSM path: $GPGSM
- GpgSM version: $GPGSM_VERSION, min. $NEED_GPGSM_VERSION
+ GpgConf path: $GPGCONF
+ GpgConf version: $GPGCONF_VERSION, min. $NEED_GPGCONF_VERSION
- GPGME Pthread: $have_pthread
- GPGME Pth: $have_pth
+ GPGME Pthread: $have_pthread
+ GPGME Pth: $have_pth
"
+2008-01-04 Marcus Brinkmann <marcus@g10code.de>
+
+ * Makefile.am (gpgconf_components): New variable.
+ (main_sources): Add gpgconf.c.
+ * gpgme.h (gpgme_protocol_t): New protocol GPGME_PROTOCOL_GPGCONF.
+ (gpgme_conf_level_t, gpgme_conf_type_t, gpgme_conf_arg_t)
+ (gpgme_conf_opt_t, gpgme_conf_comp_t, gpgme_conf_arg_new)
+ (gpgme_conf_arg_release, gpgme_conf_opt_change)
+ (gpgme_conf_release, gpgme_op_conf_load, gpgme_op_conf_save): New
+ types.
+ * gpgconf.c, engine-gpgconf.c: New files.
+ * engine.h: (_gpgme_engine_op_conf_load,
+ (_gpgme_engine_op_conf_save): New prototypes.
+ * op-support.c (_gpgme_op_reset): Ignore not implemented locale
+ function.
+ * posix-util.c (_gpgme_get_gpgconf_path): New function.
+ * w32-util.c (_gpgme_get_gpgconf_path): New function.
+ * engine-gpgsm.c:
+ (_gpgme_engine_ops_gpgsm): Add stubs for conf_load and conf_save.
+ * rungpg.c:
+ (_gpgme_engine_ops_gpg): Add stubs for conf_load and conf_save.
+ * gpgme.def: Add new gpgconf related interfaces.
+ * libgpgme.vers: Likewise.
+ * util.h (_gpgme_get_gpgconf_path): New prototype.
+ * gpgme.h (gpgme_protocol_t): Add GPGME_PROTOCOL_GPGCONF.
+ * engine-backend.h (_gpgme_engine_ops_gpgconf): New prototype.
+ (struct engine_ops): Add members for conf_load and conf_save.
+ * engine.c (engine_ops): Add _gpgme_engine_ops_gpgconf.
+ (_gpgme_engine_op_conf_load,
+ (_gpgme_engine_op_conf_save): New functions.
+ (gpgme_get_engine_info): Allow protocol GPGME_PROTOCOL_GPGCONF.
+
2007-11-28 Marcus Brinkmann <marcus@g10code.de>
* w32-util.c (_gpgme_get_gpg_path, _gpgme_get_gpgsm_path): Search
gpgsm_components =
endif
+if HAVE_GPGCONF
+gpgconf_components = engine-gpgconf.c
+else
+gpgconf_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
key.c keylist.c trust-item.c trustlist.c \
import.c export.c genkey.c delete.c edit.c getauditlog.c \
engine.h engine-backend.h engine.c rungpg.c status-table.h \
- $(gpgsm_components) sema.h priv-io.h $(system_components) \
+ $(gpgsm_components) $(gpgconf_components) gpgconf.c \
+ sema.h priv-io.h $(system_components) \
debug.c debug.h gpgme.c version.c error.c
libgpgme_la_SOURCES = $(main_sources) \
gpgme_error_t (*getauditlog) (void *engine, gpgme_data_t output,
unsigned int flags);
+ gpgme_error_t (*conf_load) (void *engine, gpgme_conf_comp_t *conf_p);
+ gpgme_error_t (*conf_save) (void *engine, gpgme_conf_comp_t conf);
+
void (*set_io_cbs) (void *engine, gpgme_io_cbs_t io_cbs);
void (*io_event) (void *engine, gpgme_event_io_t type, void *type_data);
#ifdef ENABLE_GPGSM
extern struct engine_ops _gpgme_engine_ops_gpgsm; /* CMS. */
#endif
+#ifdef ENABLE_GPGCONF
+extern struct engine_ops _gpgme_engine_ops_gpgconf; /* gpg-conf. */
+#endif
#endif /* ENGINE_BACKEND_H */
--- /dev/null
+// Check protocol.
+// IMPLEMENT NO_ARG_DESC!!!!
+
+/* engine-gpgconf.c - gpg-conf engine.
+ 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 <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"
+
+\f
+struct engine_gpgconf
+{
+ char *file_name;
+ char *home_dir;
+};
+
+typedef struct engine_gpgconf *engine_gpgconf_t;
+
+\f
+static char *
+gpgconf_get_version (const char *file_name)
+{
+ return _gpgme_get_program_version (file_name ? file_name
+ : _gpgme_get_gpgconf_path ());
+}
+
+
+static const char *
+gpgconf_get_req_version (void)
+{
+ return NEED_GPGCONF_VERSION;
+}
+
+\f
+static void
+gpgconf_release (void *engine)
+{
+ engine_gpgconf_t gpgconf = engine;
+
+ if (!gpgconf)
+ return;
+
+ if (gpgconf->file_name)
+ free (gpgconf->file_name);
+ if (gpgconf->home_dir)
+ free (gpgconf->home_dir);
+
+ free (gpgconf);
+}
+
+
+static gpgme_error_t
+gpgconf_new (void **engine, const char *file_name, const char *home_dir)
+{
+ gpgme_error_t err = 0;
+ engine_gpgconf_t gpgconf;
+
+ gpgconf = calloc (1, sizeof *gpgconf);
+ if (!gpgconf)
+ return gpg_error_from_errno (errno);
+
+ gpgconf->file_name = strdup (file_name ? file_name
+ : _gpgme_get_gpgconf_path ());
+ if (!gpgconf->file_name)
+ err = gpg_error_from_syserror ();
+
+ if (!err && home_dir)
+ {
+ gpgconf->home_dir = strdup (home_dir);
+ if (!gpgconf->home_dir)
+ err = gpg_error_from_syserror ();
+ }
+
+ if (err)
+ gpgconf_release (gpgconf);
+ else
+ *engine = gpgconf;
+
+ return err;
+}
+
+\f
+static void
+release_arg (gpgme_conf_arg_t arg, gpgme_conf_type_t alt_type)
+{
+ while (arg)
+ {
+ gpgme_conf_arg_t next = arg->next;
+
+ if (alt_type == GPGME_CONF_STRING)
+ free (arg->value.string);
+ free (arg);
+ arg = next;
+ }
+}
+
+
+static void
+release_opt (gpgme_conf_opt_t opt)
+{
+ if (opt->name)
+ free (opt->name);
+ if (opt->description)
+ free (opt->description);
+ if (opt->argname)
+ free (opt->argname);
+
+ release_arg (opt->default_value, opt->alt_type);
+ if (opt->default_description)
+ free (opt->default_description);
+
+ release_arg (opt->no_arg_value, opt->alt_type);
+ release_arg (opt->value, opt->alt_type);
+ release_arg (opt->new_value, opt->alt_type);
+
+ free (opt);
+}
+
+
+static void
+release_comp (gpgme_conf_comp_t comp)
+{
+ gpgme_conf_opt_t opt;
+
+ if (comp->name)
+ free (comp->name);
+ if (comp->description)
+ free (comp->description);
+ if (comp->program_name)
+ free (comp->program_name);
+
+ opt = comp->options;
+ while (opt)
+ {
+ gpgme_conf_opt_t next = opt->next;
+ release_opt (opt);
+ opt = next;
+ }
+
+ free (comp);
+}
+
+
+static void
+gpgconf_config_release (gpgme_conf_comp_t conf)
+{
+ while (conf)
+ {
+ gpgme_conf_comp_t next = conf->next;
+ release_comp (conf);
+ conf = next;
+ }
+}
+
+
+static gpgme_error_t
+gpgconf_read (void *engine, char *arg1, char *arg2,
+ gpgme_error_t (*cb) (void *hook, char *line),
+ void *hook)
+{
+ struct engine_gpgconf *gpgconf = engine;
+ gpgme_error_t err = 0;
+#define LINELENGTH 1024
+ char line[LINELENGTH] = "";
+ int linelen = 0;
+ char *argv[] = { NULL /* file_name */, arg1, arg2, 0 };
+ int rp[2];
+ struct spawn_fd_item_s pfd[] = { {0, -1}, {-1, -1} };
+ struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */}, {-1, -1} };
+ int status;
+ int nread;
+ char *mark = NULL;
+
+ /* FIXME: Deal with engine->home_dir. */
+
+ /* _gpgme_engine_new guarantees that this is not NULL. */
+ argv[0] = gpgconf->file_name;
+
+ if (_gpgme_io_pipe (rp, 1) < 0)
+ return gpg_error_from_syserror ();
+
+ pfd[0].fd = rp[1];
+ cfd[0].fd = rp[1];
+
+ status = _gpgme_io_spawn (gpgconf->file_name, argv, cfd, pfd);
+ if (status < 0)
+ {
+ _gpgme_io_close (rp[0]);
+ _gpgme_io_close (rp[1]);
+ return gpg_error_from_syserror ();
+ }
+
+ do
+ {
+ nread = _gpgme_io_read (rp[0], &line[linelen], LINELENGTH - linelen - 1);
+ if (nread > 0)
+ {
+ line[linelen + nread] = '\0';
+ linelen += nread;
+
+ while ((mark = strchr (line, '\n')))
+ {
+ char *eol = mark;
+
+ if (eol > &line[0] && *eol == '\r')
+ eol--;
+ *eol = '\0';
+
+ /* Got a full line. */
+ err = (*cb) (hook, line);
+ if (err)
+ break;
+
+ linelen -= mark - line;
+ memmove (line, eol + 1, linelen);
+ }
+ }
+ }
+ while (nread > 0 && linelen < LINELENGTH - 1);
+
+ if (!err && nread < 0)
+ err = gpg_error_from_syserror ();
+ if (!err && nread > 0)
+ err = gpg_error (GPG_ERR_LINE_TOO_LONG);
+
+ _gpgme_io_close (rp[0]);
+
+ return err;
+}
+
+
+static gpgme_error_t
+gpgconf_config_load_cb (void *hook, char *line)
+{
+ gpgme_conf_comp_t *comp_p = hook;
+ gpgme_conf_comp_t comp = *comp_p;
+#define NR_FIELDS 16
+ char *field[NR_FIELDS];
+ int fields = 0;
+
+ while (line && fields < NR_FIELDS)
+ {
+ field[fields++] = line;
+ line = strchr (line, ':');
+ if (line)
+ *(line++) = '\0';
+ }
+
+ /* We require at least the first 3 fields. */
+ if (fields < 2)
+ return gpg_error (GPG_ERR_INV_ENGINE);
+
+ /* Find the pointer to the new component in the list. */
+ while (comp && comp->next)
+ comp = comp->next;
+ if (comp)
+ comp_p = &comp->next;
+
+ comp = calloc (1, sizeof (*comp));
+ if (!comp)
+ return gpg_error_from_syserror ();
+ /* Prepare return value. */
+ comp->_last_opt_p = &comp->options;
+ *comp_p = comp;
+
+ comp->name = strdup (field[0]);
+ if (!comp->name)
+ return gpg_error_from_syserror ();
+
+ comp->description = strdup (field[1]);
+ if (!comp->description)
+ return gpg_error_from_syserror ();
+
+ if (fields >= 3)
+ {
+ comp->description = strdup (field[2]);
+ if (!comp->description)
+ return gpg_error_from_syserror ();
+ }
+
+ return 0;
+}
+
+
+static gpgme_error_t
+gpgconf_parse_option (gpgme_conf_opt_t opt,
+ gpgme_conf_arg_t *arg_p, char *line)
+{
+ gpgme_error_t err;
+ char *mark;
+
+ if (!line[0])
+ return 0;
+
+ mark = strchr (line, ',');
+ if (mark)
+ *mark = '\0';
+
+ while (line)
+ {
+ gpgme_conf_arg_t arg = calloc (1, sizeof (*arg));
+ if (!arg)
+ return gpg_error_from_syserror ();
+ *arg_p = arg;
+ arg_p = &arg->next;
+
+ if (*line == '\0')
+ arg->no_arg = 1;
+ else
+ {
+ switch (opt->alt_type)
+ {
+ /* arg->value.count is an alias for arg->value.uint32. */
+ case GPGME_CONF_NONE:
+ case GPGME_CONF_UINT32:
+ arg->value.uint32 = strtoul (line, NULL, 0);
+ break;
+
+ case GPGME_CONF_INT32:
+ arg->value.uint32 = strtol (line, NULL, 0);
+ break;
+
+ case GPGME_CONF_STRING:
+ case GPGME_CONF_PATHNAME:
+ case GPGME_CONF_LDAP_SERVER:
+ /* Skip quote character. */
+ line++;
+
+ err = _gpgme_decode_percent_string (line, &arg->value.string,
+ 0, 0);
+ if (err)
+ return err;
+ break;
+ }
+ }
+
+ /* Find beginning of next value. */
+ if (mark++ && *mark)
+ line = mark;
+ else
+ line = NULL;
+ }
+
+ return 0;
+}
+
+
+static gpgme_error_t
+gpgconf_config_load_cb2 (void *hook, char *line)
+{
+ gpgme_error_t err;
+ gpgme_conf_comp_t comp = hook;
+ gpgme_conf_opt_t *opt_p = comp->_last_opt_p;
+ gpgme_conf_opt_t opt;
+#define NR_FIELDS 16
+ char *field[NR_FIELDS];
+ int fields = 0;
+
+ while (line && fields < NR_FIELDS)
+ {
+ field[fields++] = line;
+ line = strchr (line, ':');
+ if (line)
+ *(line++) = '\0';
+ }
+
+ /* We require at least the first 10 fields. */
+ if (fields < 10)
+ return gpg_error (GPG_ERR_INV_ENGINE);
+
+ opt = calloc (1, sizeof (*opt));
+ if (!opt)
+ return gpg_error_from_syserror ();
+
+ comp->_last_opt_p = &opt->next;
+ *opt_p = opt;
+
+ if (field[0][0])
+ {
+ opt->name = strdup (field[0]);
+ if (!opt->name)
+ return gpg_error_from_syserror ();
+ }
+
+ opt->flags = strtoul (field[1], NULL, 0);
+
+ opt->level = strtoul (field[2], NULL, 0);
+
+ if (field[3][0])
+ {
+ opt->description = strdup (field[3]);
+ if (!opt->description)
+ return gpg_error_from_syserror ();
+ }
+
+ opt->type = strtoul (field[4], NULL, 0);
+
+ opt->alt_type = strtoul (field[5], NULL, 0);
+
+ if (field[6][0])
+ {
+ opt->argname = strdup (field[6]);
+ if (!opt->argname)
+ return gpg_error_from_syserror ();
+ }
+
+ if (opt->flags & GPGME_CONF_DEFAULT)
+ {
+ err = gpgconf_parse_option (opt, &opt->default_value, field[7]);
+ if (err)
+ return err;
+ }
+ else if ((opt->flags & GPGME_CONF_DEFAULT_DESC) && field[7][0])
+ {
+ opt->default_description = strdup (field[7]);
+ if (!opt->default_description)
+ return gpg_error_from_syserror ();
+ }
+
+ err = gpgconf_parse_option (opt, &opt->no_arg_value, field[8]);
+ if (err)
+ return err;
+
+ err = gpgconf_parse_option (opt, &opt->value, field[9]);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+
+static gpgme_error_t
+gpgconf_conf_load (void *engine, gpgme_conf_comp_t *comp_p)
+{
+ gpgme_error_t err;
+ gpgme_conf_comp_t comp = NULL;
+ gpgme_conf_comp_t cur_comp;
+
+ *comp_p = NULL;
+
+ err = gpgconf_read (engine, "--list-components", NULL,
+ gpgconf_config_load_cb, &comp);
+ if (err)
+ {
+ gpgconf_release (comp);
+ return err;
+ }
+
+ cur_comp = comp;
+ while (!err && cur_comp)
+ {
+ err = gpgconf_read (engine, "--list-options", cur_comp->name,
+ gpgconf_config_load_cb2, cur_comp);
+ cur_comp = cur_comp->next;
+ }
+
+ if (err)
+ {
+ gpgconf_release (comp);
+ return err;
+ }
+
+ *comp_p = comp;
+ return 0;
+}
+
+
+\f
+gpgme_error_t
+_gpgme_conf_arg_new (gpgme_conf_arg_t *arg_p,
+ gpgme_conf_type_t type, void *value)
+{
+ gpgme_conf_arg_t arg;
+
+ arg = calloc (1, sizeof (*arg));
+ if (!arg)
+ return gpg_error_from_syserror ();
+
+ if (!value)
+ arg->no_arg = 1;
+ else
+ {
+ switch (type)
+ {
+ case GPGME_CONF_NONE:
+ case GPGME_CONF_UINT32:
+ arg->value.uint32 = *((unsigned int *) value);
+ break;
+
+ case GPGME_CONF_INT32:
+ arg->value.int32 = *((int *) value);
+ break;
+
+ case GPGME_CONF_STRING:
+ case GPGME_CONF_PATHNAME:
+ case GPGME_CONF_LDAP_SERVER:
+ arg->value.string = strdup (value);
+ if (!arg->value.string)
+ {
+ free (arg);
+ return gpg_error_from_syserror ();
+ }
+ break;
+
+ default:
+ free (arg);
+ return gpg_error (GPG_ERR_INV_VALUE);
+ }
+ }
+
+ *arg_p = arg;
+ return 0;
+}
+
+
+void
+_gpgme_conf_arg_release (gpgme_conf_arg_t arg, gpgme_conf_type_t type)
+{
+ switch (type)
+ {
+ case GPGME_CONF_NONE:
+ case GPGME_CONF_UINT32:
+ case GPGME_CONF_INT32:
+ case GPGME_CONF_STRING:
+ default:
+ break;
+
+ case GPGME_CONF_PATHNAME:
+ case GPGME_CONF_LDAP_SERVER:
+ type = GPGME_CONF_STRING;
+ break;
+ }
+
+ release_arg (arg, type);
+}
+
+
+gpgme_error_t
+_gpgme_conf_opt_change (gpgme_conf_opt_t opt, int reset, gpgme_conf_arg_t arg)
+{
+ if (opt->new_value)
+ release_arg (opt->new_value, opt->alt_type);
+
+ if (reset)
+ {
+ opt->new_value = NULL;
+ opt->change_value = 0;
+ }
+ else
+ {
+ opt->new_value = arg;
+ opt->change_value = 1;
+ }
+ return 0;
+}
+
+\f
+/* FIXME: Major problem: We don't get errors from gpgconf. */
+
+static gpgme_error_t
+gpgconf_write (void *engine, char *arg1, char *arg2, gpgme_data_t conf)
+{
+ struct engine_gpgconf *gpgconf = engine;
+ gpgme_error_t err = 0;
+#define BUFLEN 1024
+ char buf[BUFLEN];
+ int buflen = 0;
+ char *argv[] = { NULL /* file_name */, arg1, arg2, 0 };
+ int rp[2];
+ struct spawn_fd_item_s pfd[] = { {1, -1}, {-1, -1} };
+ struct spawn_fd_item_s cfd[] = { {-1, 0 /* STDIN_FILENO */}, {-1, -1} };
+ int status;
+ int nwrite;
+
+ /* FIXME: Deal with engine->home_dir. */
+
+ /* _gpgme_engine_new guarantees that this is not NULL. */
+ argv[0] = gpgconf->file_name;
+ argv[0] = "/home/marcus/g10/install/bin/gpgconf";
+
+ if (_gpgme_io_pipe (rp, 0) < 0)
+ return gpg_error_from_syserror ();
+
+ pfd[0].fd = rp[0];
+ cfd[0].fd = rp[0];
+
+ status = _gpgme_io_spawn (gpgconf->file_name, argv, cfd, pfd);
+ if (status < 0)
+ {
+ _gpgme_io_close (rp[0]);
+ _gpgme_io_close (rp[1]);
+ return gpg_error_from_syserror ();
+ }
+
+ for (;;)
+ {
+ if (buflen == 0)
+ {
+ do
+ {
+ buflen = gpgme_data_read (conf, buf, BUFLEN);
+ }
+ while (buflen < 0 && errno == EAGAIN);
+
+ if (buflen < 0)
+ {
+ err = gpg_error_from_syserror ();
+ _gpgme_io_close (rp[1]);
+ return err;
+ }
+ else if (buflen == 0)
+ {
+ /* All is written. */
+ _gpgme_io_close (rp[1]);
+ return 0;
+ }
+ }
+
+ do
+ {
+ nwrite = _gpgme_io_write (rp[1], buf, buflen);
+ }
+ while (nwrite < 0 && errno == EAGAIN);
+
+ if (nwrite > 0)
+ {
+ buflen -= nwrite;
+ if (buflen > 0)
+ memmove (&buf[0], &buf[nwrite], buflen);
+ }
+ else if (nwrite < 0)
+ {
+ _gpgme_io_close (rp[1]);
+ return gpg_error_from_syserror ();
+ }
+ }
+
+ return 0;
+}
+
+
+static gpgme_error_t
+arg_to_data (gpgme_data_t conf, gpgme_conf_opt_t option, gpgme_conf_arg_t arg)
+{
+ gpgme_error_t err = 0;
+ int amt = 0;
+ char buf[16];
+
+ while (amt >= 0 && arg)
+ {
+ switch (option->alt_type)
+ {
+ case GPGME_CONF_NONE:
+ case GPGME_CONF_UINT32:
+ default:
+ snprintf (buf, sizeof (buf), "%u", arg->value.uint32);
+ buf[sizeof (buf) - 1] = '\0';
+ amt = gpgme_data_write (conf, buf, strlen (buf));
+ break;
+
+ case GPGME_CONF_INT32:
+ snprintf (buf, sizeof (buf), "%i", arg->value.uint32);
+ buf[sizeof (buf) - 1] = '\0';
+ amt = gpgme_data_write (conf, buf, strlen (buf));
+ break;
+
+ case GPGME_CONF_STRING:
+ case GPGME_CONF_PATHNAME:
+ case GPGME_CONF_LDAP_SERVER:
+ /* One quote character, and three times to allow
+ for percent escaping. */
+ {
+ char *ptr = arg->value.string;
+ amt = gpgme_data_write (conf, "\"", 1);
+ if (amt < 0)
+ break;
+
+ while (!err && *ptr)
+ {
+ switch (*ptr)
+ {
+ case '%':
+ amt = gpgme_data_write (conf, "%25", 3);
+ break;
+
+ case ':':
+ amt = gpgme_data_write (conf, "%3a", 3);
+ break;
+
+ case ',':
+ amt = gpgme_data_write (conf, "%2c", 3);
+ break;
+
+ default:
+ amt = gpgme_data_write (conf, ptr, 1);
+ }
+ ptr++;
+ }
+ }
+ break;
+ }
+
+ if (amt < 0)
+ break;
+
+ arg = arg->next;
+ /* Comma separator. */
+ if (arg)
+ amt = gpgme_data_write (conf, ",", 1);
+ }
+
+ if (amt < 0)
+ return gpg_error_from_syserror ();
+
+ return 0;
+}
+
+
+static gpgme_error_t
+gpgconf_conf_save (void *engine, gpgme_conf_comp_t comp)
+{
+ gpgme_error_t err;
+ int amt = 0;
+ /* We use a data object to store the new configuration. */
+ gpgme_data_t conf;
+ gpgme_conf_opt_t option;
+ int something_changed = 0;
+
+ err = gpgme_data_new (&conf);
+ if (err)
+ return err;
+
+ option = comp->options;
+ while (!err && amt >= 0 && option)
+ {
+ if (option->change_value)
+ {
+ unsigned int flags = 0;
+ char buf[16];
+
+ something_changed = 1;
+
+ amt = gpgme_data_write (conf, option->name, strlen (option->name));
+ if (amt >= 0)
+ amt = gpgme_data_write (conf, ":", 1);
+ if (amt < 0)
+ break;
+
+ if (!option->new_value)
+ flags |= GPGME_CONF_DEFAULT;
+ snprintf (buf, sizeof (buf), "%u", flags);
+ buf[sizeof (buf) - 1] = '\0';
+
+ amt = gpgme_data_write (conf, buf, strlen (buf));
+ if (amt >= 0)
+ amt = gpgme_data_write (conf, ":", 1);
+ if (amt < 0)
+ break;
+
+ if (option->new_value)
+ {
+ err = arg_to_data (conf, option, option->new_value);
+ if (err)
+ break;
+ }
+ amt = gpgme_data_write (conf, "\n", 1);
+ }
+ option = option->next;
+ }
+ if (!err && amt < 0)
+ err = gpg_error_from_syserror ();
+ if (err || !something_changed)
+ goto bail;
+
+ err = gpgme_data_seek (conf, 0, SEEK_SET);
+ if (err)
+ goto bail;
+
+ err = gpgconf_write (engine, "--change-options", comp->name, conf);
+ bail:
+ gpgme_data_release (conf);
+ return err;
+}
+
+
+static void
+gpgconf_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
+{
+ /* Nothing to do. */
+}
+
+\f
+/* Currently, we do not use the engine interface for the various
+ operations. */
+void
+_gpgme_conf_release (gpgme_conf_comp_t conf)
+{
+ gpgconf_config_release (conf);
+}
+
+\f
+struct engine_ops _gpgme_engine_ops_gpgconf =
+ {
+ /* Static functions. */
+ _gpgme_get_gpgconf_path,
+ gpgconf_get_version,
+ gpgconf_get_req_version,
+ gpgconf_new,
+
+ /* Member functions. */
+ gpgconf_release,
+ NULL, /* reset */
+ NULL, /* set_status_handler */
+ NULL, /* set_command_handler */
+ NULL, /* set_colon_line_handler */
+ NULL, /* 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 */
+ gpgconf_conf_load,
+ gpgconf_conf_save,
+ gpgconf_set_io_cbs,
+ NULL, /* io_event */
+ NULL /* cancel */
+ };
NULL, /* trustlist */
gpgsm_verify,
gpgsm_getauditlog,
+ NULL, /* conf_load */
+ NULL, /* conf_save */
gpgsm_set_io_cbs,
gpgsm_io_event,
gpgsm_cancel
{
&_gpgme_engine_ops_gpg, /* OpenPGP. */
#ifdef ENABLE_GPGSM
- &_gpgme_engine_ops_gpgsm /* CMS. */
+ &_gpgme_engine_ops_gpgsm, /* CMS. */
+#else
+ NULL,
+#endif
+#ifdef ENABLE_GPGCONF
+ &_gpgme_engine_ops_gpgconf /* gpg-conf. */
#else
NULL
#endif
{
gpgme_engine_info_t *lastp = &engine_info;
gpgme_protocol_t proto_list[] = { GPGME_PROTOCOL_OpenPGP,
- GPGME_PROTOCOL_CMS };
+ GPGME_PROTOCOL_CMS,
+ GPGME_PROTOCOL_GPGCONF };
unsigned int proto;
for (proto = 0; proto < DIM (proto_list); proto++)
}
+gpgme_error_t
+_gpgme_engine_op_conf_load (engine_t engine, gpgme_conf_comp_t *conf_p)
+{
+ if (!engine)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (!engine->ops->conf_load)
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
+ return (*engine->ops->conf_load) (engine->engine, conf_p);
+}
+
+
+gpgme_error_t
+_gpgme_engine_op_conf_save (engine_t engine, gpgme_conf_comp_t conf)
+{
+ if (!engine)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (!engine->ops->conf_save)
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
+ return (*engine->ops->conf_save) (engine->engine, conf);
+}
+
+
void
_gpgme_engine_set_io_cbs (engine_t engine, gpgme_io_cbs_t io_cbs)
{
gpgme_data_t output,
unsigned int flags);
+gpgme_error_t _gpgme_engine_op_conf_load (engine_t engine,
+ gpgme_conf_comp_t *conf_p);
+gpgme_error_t _gpgme_engine_op_conf_save (engine_t engine,
+ gpgme_conf_comp_t conf);
+
void _gpgme_engine_set_io_cbs (engine_t engine,
gpgme_io_cbs_t io_cbs);
void _gpgme_engine_io_event (engine_t engine,
--- /dev/null
+/* gpgconf.c - GnuPG Made Easy.
+ Copyright (C) 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 "gpgme.h"
+
+#include "ops.h"
+#include "engine.h"
+
+#ifdef ENABLE_GPGCONF
+/* engine-gpgconf.c. */
+gpgme_error_t _gpgme_conf_arg_new (gpgme_conf_arg_t *arg_p,
+ gpgme_conf_type_t type, void *value);
+void _gpgme_conf_arg_release (gpgme_conf_arg_t arg, gpgme_conf_type_t type);
+gpgme_error_t _gpgme_conf_opt_change (gpgme_conf_opt_t opt, int reset,
+ gpgme_conf_arg_t arg);
+void _gpgme_conf_release (gpgme_conf_comp_t conf);
+gpgme_error_t _gpgme_conf_load (void *engine, gpgme_conf_comp_t *conf_p);
+gpgme_error_t gpgme_op_conf_save (gpgme_ctx_t ctx, gpgme_conf_comp_t comp);
+
+#endif
+
+\f
+/* Allocate a new gpgme_conf_arg_t. */
+gpgme_error_t
+gpgme_conf_arg_new (gpgme_conf_arg_t *arg_p,
+ gpgme_conf_type_t type, void *value)
+{
+#ifdef ENABLE_GPGCONF
+ return _gpgme_conf_arg_new (arg_p, type, value);
+#else
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+#endif
+}
+
+
+/* This also releases all chained argument structures! */
+void
+gpgme_conf_arg_release (gpgme_conf_arg_t arg, gpgme_conf_type_t type)
+{
+#ifdef ENABLE_GPGCONF
+ return _gpgme_conf_arg_release (arg, type);
+#endif
+}
+
+
+/* Register a change for the value of OPT to ARG. */
+gpgme_error_t
+gpgme_conf_opt_change (gpgme_conf_opt_t opt, int reset, gpgme_conf_arg_t arg)
+{
+#ifdef ENABLE_GPGCONF
+ return _gpgme_conf_opt_change (opt, reset, arg);
+#else
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+#endif
+}
+
+
+
+/* Public function to release a gpgme_conf_comp list. */
+void
+gpgme_conf_release (gpgme_conf_comp_t conf)
+{
+#ifdef ENABLE_GPGCONF
+ _gpgme_conf_release (conf);
+#endif
+}
+
+
+/* Public function to release load a configuration list. No
+ asynchronous interface for now. */
+gpgme_error_t
+gpgme_op_conf_load (gpgme_ctx_t ctx, gpgme_conf_comp_t *conf_p)
+{
+#ifdef ENABLE_GPGCONF
+ gpgme_error_t err;
+ gpgme_protocol_t proto = ctx->protocol;
+
+ ctx->protocol = GPGME_PROTOCOL_GPGCONF;
+ err = _gpgme_op_reset (ctx, 1);
+ if (err)
+ return err;
+
+ err = _gpgme_engine_op_conf_load (ctx->engine, conf_p);
+ ctx->protocol = proto;
+ return err;
+#else
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+#endif
+}
+
+
+/* This function does not follow chained components! */
+gpgme_error_t
+gpgme_op_conf_save (gpgme_ctx_t ctx, gpgme_conf_comp_t comp)
+{
+#ifdef ENABLE_GPGCONF
+ gpgme_error_t err;
+ gpgme_protocol_t proto = ctx->protocol;
+
+ ctx->protocol = GPGME_PROTOCOL_GPGCONF;
+ err = _gpgme_op_reset (ctx, 1);
+ if (err)
+ return err;
+
+ err = _gpgme_engine_op_conf_save (ctx->engine, comp);
+ ctx->protocol = proto;
+ return err;
+#else
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+#endif
+}
+
+
gpgme_op_getauditlog_start @123
gpgme_op_getauditlog @124
+ gpgme_conf_release @125
+ gpgme_conf_arg_new @126
+ gpgme_conf_arg_release @127
+ gpgme_conf_opt_change @128
+ gpgme_op_conf_load @129
+ gpgme_op_conf_save @130
+
; END
AM_PATH_GPGME macro) check that this header matches the installed
library. Warning: Do not edit the next line. configure will do
that for you! */
-#define GPGME_VERSION "1.1.6-svn1258"
+#define GPGME_VERSION "1.1.6-svn1282"
\f
{
GPGME_PROTOCOL_OpenPGP = 0, /* The default mode. */
GPGME_PROTOCOL_CMS = 1,
+ GPGME_PROTOCOL_GPGCONF = 2, /* Special code for gpgconf. */
GPGME_PROTOCOL_UNKNOWN = 255
}
gpgme_protocol_t;
gpgme_error_t gpgme_op_getauditlog (gpgme_ctx_t ctx, gpgme_data_t output,
unsigned int flags);
+\f
+/* Interface to gpg-conf. */
+
+/* The expert level at which a configuration option or group of
+ options should be displayed. See the gpg-conf documentation for
+ more details. */
+typedef enum
+ {
+ GPGME_CONF_BASIC = 0,
+ GPGME_CONF_ADVANCED = 1,
+ GPGME_CONF_EXPERT = 2,
+ GPGME_CONF_INVISIBLE = 3,
+ GPGME_CONF_INTERNAL = 4
+ }
+gpgme_conf_level_t;
+
+
+/* The data type of a configuration option argument. See the gpg-conf
+ documentation for more details. */
+typedef enum
+ {
+ /* Basic types. */
+ GPGME_CONF_NONE = 0,
+ GPGME_CONF_STRING = 1,
+ GPGME_CONF_INT32 = 2,
+ GPGME_CONF_UINT32 = 3,
+
+ /* Complex types. */
+ GPGME_CONF_PATHNAME = 32,
+ GPGME_CONF_LDAP_SERVER = 33
+ }
+gpgme_conf_type_t;
+
+
+/* This represents a single argument for a configuration option.
+ Which of the members of value is used depends on the ALT_TYPE. */
+typedef struct gpgme_conf_arg
+{
+ struct gpgme_conf_arg *next;
+ /* True if the option appears without an (optional) argument. */
+ unsigned int no_arg;
+ union
+ {
+ unsigned int count;
+ unsigned int uint32;
+ int int32;
+ char *string;
+ } value;
+} *gpgme_conf_arg_t;
+
+
+/* The flags of a configuration option. See the gpg-conf
+ documentation for details. */
+#define GPGME_CONF_GROUP (1 << 0)
+#define GPGME_CONF_OPTIONAL (1 << 1)
+#define GPGME_CONF_LIST (1 << 2)
+#define GPGME_CONF_RUNTIME (1 << 3)
+#define GPGME_CONF_DEFAULT (1 << 4)
+#define GPGME_CONF_DEFAULT_DESC (1 << 5)
+#define GPGME_CONF_NO_ARG_DESC (1 << 6)
+#define GPGME_CONF_NO_CHANGE (1 << 7)
+
+
+/* The representation of a single configuration option. See the
+ gpg-conf documentation for details. */
+typedef struct gpgme_conf_opt
+{
+ struct gpgme_conf_opt *next;
+
+ /* The option name. */
+ char *name;
+
+ /* The flags for this option. */
+ unsigned int flags;
+
+ /* The level of this option. */
+ gpgme_conf_level_t level;
+
+ /* The localized description of this option. */
+ char *description;
+
+ /* The type and alternate type of this option. */
+ gpgme_conf_type_t type;
+ gpgme_conf_type_t alt_type;
+
+ /* The localized (short) name of the argument, if any. */
+ char *argname;
+
+ /* The default value. */
+ gpgme_conf_arg_t default_value;
+ char *default_description;
+
+ /* The default value if the option is not set. */
+ gpgme_conf_arg_t no_arg_value;
+ char *no_arg_description;
+
+ /* The current value if the option is set. */
+ gpgme_conf_arg_t value;
+
+ /* The new value, if any. NULL means reset to default. */
+ int change_value;
+ gpgme_conf_arg_t new_value;
+
+ /* Free for application use. */
+ void *user_data;
+} *gpgme_conf_opt_t;
+
+
+/* The representation of a component that can be configured. See the
+ gpg-conf documentation for details. */
+typedef struct gpgme_conf_comp
+{
+ struct gpgme_conf_comp *next;
+
+ /* Internal to GPGME, do not use! */
+ gpgme_conf_opt_t *_last_opt_p;
+
+ /* The component name. */
+ char *name;
+
+ /* A human-readable description for the component. */
+ char *description;
+
+ /* The program name (an absolute path to the program). */
+ char *program_name;
+
+ /* A linked list of options for this component. */
+ struct gpgme_conf_opt *options;
+} *gpgme_conf_comp_t;
+
+
+/* Allocate a new gpgme_conf_arg_t. If VALUE is NULL, a "no arg
+ default" is prepared. If type is a string type, VALUE should point
+ to the string. Else, it should point to an unsigned or signed
+ integer respectively. */
+gpgme_error_t gpgme_conf_arg_new (gpgme_conf_arg_t *arg_p,
+ gpgme_conf_type_t type, void *value);
+
+/* This also releases all chained argument structures! */
+void gpgme_conf_arg_release (gpgme_conf_arg_t arg, gpgme_conf_type_t type);
+
+/* Register a change for the value of OPT to ARG. If RESET is 1 (do
+ not use any values but 0 or 1), ARG is ignored and the option is
+ not changed (reverting a previous change). Otherwise, if ARG is
+ NULL, the option is cleared or reset to its default. */
+gpgme_error_t gpgme_conf_opt_change (gpgme_conf_opt_t opt, int reset,
+ gpgme_conf_arg_t arg);
+
+/* Release a set of configurations. */
+void gpgme_conf_release (gpgme_conf_comp_t conf);
+
+/* Retrieve the current configurations. */
+gpgme_error_t gpgme_op_conf_load (gpgme_ctx_t ctx, gpgme_conf_comp_t *conf_p);
+
+/* Save the configuration of component comp. This function does not
+ follow chained components! */
+gpgme_error_t gpgme_op_conf_save (gpgme_ctx_t ctx, gpgme_conf_comp_t comp);
\f
/* Various functions. */
gpgme_op_getauditlog_start;
gpgme_op_getauditlog;
+
+ gpgme_conf_release;
+ gpgme_conf_arg_new;
+ gpgme_conf_arg_release;
+ gpgme_conf_opt_change;
+ gpgme_op_conf_load;
+ gpgme_op_conf_save;
};
err = _gpgme_engine_set_locale (ctx->engine,
LC_MESSAGES, ctx->lc_messages);
#endif
+ if (gpg_err_code (err) == GPG_ERR_NOT_IMPLEMENTED)
+ err = 0;
if (err)
{
_gpgme_engine_release (ctx->engine);
#endif
}
+const char *
+_gpgme_get_gpgconf_path (void)
+{
+#ifdef GPGCONF_PATH
+ return GPGCONF_PATH;
+#else
+ return NULL;
+#endif
+}
+
/* See w32-util.c */
int
_gpgme_get_conf_int (const char *key, int *value)
gpg_sign,
gpg_trustlist,
gpg_verify,
- NULL,
+ NULL, /* getauditlog */
+ NULL, /* conf_load */
+ NULL, /* conf_save */
gpg_set_io_cbs,
gpg_io_event,
gpg_cancel
/*-- {posix,w32}-util.c --*/
const char *_gpgme_get_gpg_path (void);
const char *_gpgme_get_gpgsm_path (void);
+const char *_gpgme_get_gpgconf_path (void);
int _gpgme_get_conf_int (const char *key, int *value);
\f
return result;
}
+
static char *
find_program_at_standard_place (const char *name)
{
return gpg_program;
}
+
const char *
_gpgme_get_gpgsm_path (void)
{
}
+const char *
+_gpgme_get_gpgconf_path (void)
+{
+ static char *gpgconf_program;
+
+ LOCK (get_path_lock);
+ if (!gpgconf_program)
+ gpgconf_program = find_program_in_registry ("gpgconfProgram");
+ if (!gpgconf_program)
+ gpgconf_program = find_program_in_inst_dir ("gpgconf.exe");
+ if (!gpgconf_program)
+ gpgconf_program
+ = find_program_at_standard_place ("GNU\\GnuPG\\gpgconf.exe");
+ UNLOCK (get_path_lock);
+ return gpgconf_program;
+}
+
+
/* Return an integer value from gpgme specific configuration
entries. VALUE receives that value; function returns true if a value
has been configured and false if not. */
+2008-01-04 Marcus Brinkmann <marcus@g10code.de>
+
+ * Makefile.am (TESTS_ENVIRONMENT): Use absolute path for
+ GNUPGHOME.
+ * gpg/Makefile.am (TESTS_ENVIRONMENT): Use absolute path for
+ GNUPGHOME.
+ * gpgsm/Makefile.am (TESTS_ENVIRONMENT): Use absolute path for
+ GNUPGHOME.
+ * gpg/Makefile.am (TESTS): Add t-gpgconf.
+ t-gpgconf.c: New file.
+
2007-11-23 Marcus Brinkmann <marcus@g10code.de>
* gpgsm/t-verify.c (show_auditlog): Check for GPG_ERR_ASS_UNKNOWN_CMD.
## Process this file with automake to produce Makefile.in
-TESTS_ENVIRONMENT = GNUPGHOME=.
+TESTS_ENVIRONMENT = GNUPGHOME=$(abs_builddir)
TESTS = t-version t-data t-engine-info
GPG = @GPG@
-TESTS_ENVIRONMENT = GNUPGHOME=. GPG_AGENT_INFO=
+TESTS_ENVIRONMENT = GNUPGHOME=$(abs_builddir) GPG_AGENT_INFO=
# The keylist tests must come after the import and the edit test.
noinst_HEADERS = t-support.h
TESTS = t-encrypt t-encrypt-sym t-encrypt-sign t-sign t-signers \
t-decrypt t-verify t-decrypt-verify t-sig-notation t-export \
t-import t-trustlist t-edit t-keylist t-keylist-sig t-wait \
- t-encrypt-large t-file-name $(tests_unix)
+ t-encrypt-large t-file-name t-gpgconf $(tests_unix)
-CLEANFILES = secring.gpg pubring.gpg trustdb.gpg
+CLEANFILES = secring.gpg pubring.gpg trustdb.gpg dirmngr.conf
DISTCLEANFILES = pubring.gpg~ random_seed gpg.conf
EXTRA_DIST = mkdemodirs pubdemo.asc secdemo.asc cipher-1.asc cipher-2.asc \
--- /dev/null
+/* t-gpgconf.c - Regression test.
+ Copyright (C) 2001, 2004, 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. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <string.h>
+
+#ifdef HAVE_W32_SYSTEM
+#include <windows.h>
+#endif
+
+#include <gpgme.h>
+
+
+#define fail_if_err(err) \
+ do \
+ { \
+ if (err) \
+ { \
+ fprintf (stderr, "%s:%d: %s: %s\n", \
+ __FILE__, __LINE__, gpgme_strsource (err), \
+ gpgme_strerror (err)); \
+ exit (1); \
+ } \
+ } \
+ while (0)
+
+
+void
+init_gpgme (gpgme_protocol_t proto)
+{
+ gpgme_error_t err;
+
+ gpgme_check_version (NULL);
+ setlocale (LC_ALL, "");
+ gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
+#ifndef HAVE_W32_SYSTEM
+ gpgme_set_locale (NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL));
+#endif
+
+ err = gpgme_engine_check_version (proto);
+ fail_if_err (err);
+}
+
+\f
+static char *
+spaces (char *str, int extra)
+{
+ static char buf[80];
+ int len = str ? strlen (str) : 0;
+ int n;
+
+#define TABSTOP 30
+ n = TABSTOP - len - extra;
+
+ memset (buf, ' ', sizeof (buf));
+ if (n < 1 || n > (sizeof (buf) - 1))
+ {
+ buf[0] = '\n';
+ n = TABSTOP + 1;
+ }
+
+ buf[n] = '\0';
+ return buf;
+}
+
+
+void
+dump_arg (int type, gpgme_conf_arg_t arg)
+{
+ if (!arg)
+ {
+ printf ("(none)");
+ return;
+ }
+
+ while (arg)
+ {
+ switch (type)
+ {
+ case GPGME_CONF_STRING:
+ case GPGME_CONF_PATHNAME:
+ case GPGME_CONF_LDAP_SERVER:
+ printf ("%s", arg->value.string);
+ break;
+
+ case GPGME_CONF_UINT32:
+ printf ("%u", arg->value.uint32);
+ break;
+
+ case GPGME_CONF_INT32:
+ printf ("%i", arg->value.int32);
+ break;
+
+ case GPGME_CONF_NONE:
+ printf ("%i (times)", arg->value.count);
+ break;
+
+ default:
+ printf ("(unknown type)");
+ }
+
+ arg = arg->next;
+ if (arg)
+ printf (" ");
+ }
+}
+
+
+void
+dump_opt (gpgme_conf_opt_t opt)
+{
+ char level;
+ char runtime = (opt->flags & GPGME_CONF_RUNTIME) ? 'r' : ' ';
+
+ switch (opt->level)
+ {
+ case GPGME_CONF_BASIC:
+ level = 'b';
+ break;
+ case GPGME_CONF_ADVANCED:
+ level = 'a';
+ break;
+ case GPGME_CONF_EXPERT:
+ level = 'e';
+ break;
+ case GPGME_CONF_INVISIBLE:
+ level = 'i';
+ break;
+ case GPGME_CONF_INTERNAL:
+ level = '#';
+ break;
+ default:
+ level = '?';
+ }
+
+ if (opt->flags & GPGME_CONF_GROUP)
+ {
+ printf ("\n");
+ printf ("%c%c [%s]%s%s\n", level, runtime, opt->name, spaces (opt->name, 5),
+ opt->description
+ ? opt->description : "");
+ }
+ else
+ {
+ if (opt->argname)
+ {
+ char *more = (opt->flags & GPGME_CONF_LIST) ? "..." : "";
+
+ if (opt->flags & GPGME_CONF_OPTIONAL)
+ {
+ printf ("%c%c --%s [%s%s] %s", level, runtime, opt->name, opt->argname, more,
+ spaces (opt->name, 9 + strlen (opt->argname) + strlen (more)));
+ }
+ else
+ {
+ printf ("%c%c --%s %s%s %s", level, runtime, opt->name, opt->argname, more,
+ spaces (opt->name, 7 + strlen (opt->argname) + strlen (more)));
+ }
+ }
+ else
+ printf ("%c%c --%s%s", level, runtime, opt->name, spaces (opt->name, 5));
+
+ if (opt->description)
+ printf ("%s", opt->description);
+ printf ("\n");
+
+ if (opt->flags & GPGME_CONF_DEFAULT)
+ {
+ printf ("%s%s = ", spaces (NULL, 0), opt->argname ? opt->argname : "(default)");
+ dump_arg (opt->type, opt->default_value);
+ printf ("\n");
+ }
+ else if (opt->flags & GPGME_CONF_DEFAULT_DESC)
+ printf ("%s%s = %s\n", spaces (NULL, 0), opt->argname ? opt->argname : "(default)",
+ opt->default_description);
+
+ if (opt->no_arg_value)
+ {
+ printf ("%sNo Arg Def = ", spaces (NULL, 0));
+ dump_arg (opt->type, opt->no_arg_value);
+ printf ("\n");
+ }
+ if (opt->value)
+ {
+ printf ("%sCurrent = ", spaces (NULL, 0));
+ dump_arg (opt->type, opt->value);
+ printf ("\n");
+ }
+ }
+
+#if 0
+ arg = comp->options;
+ while (opt)
+ {
+ dump_opt (opt);
+ opt = opt->next;
+ }
+#endif
+}
+
+
+void
+dump_comp (gpgme_conf_comp_t comp)
+{
+ gpgme_conf_opt_t opt;
+
+ printf ("COMPONENT\n");
+ printf ("=========\n");
+ printf (" Name: %s\n", comp->name);
+ if (comp->description)
+ printf (" Desc: %s\n", comp->description);
+ if (comp->program_name)
+ printf (" Path: %s\n", comp->program_name);
+ printf ("\n");
+
+ opt = comp->options;
+ while (opt)
+ {
+ dump_opt (opt);
+ opt = opt->next;
+ }
+}
+
+
+int
+main (int argc, char **argv)
+{
+ gpgme_ctx_t ctx;
+ gpgme_error_t err;
+ gpgme_conf_comp_t conf;
+ gpgme_conf_comp_t comp;
+ int first;
+ init_gpgme (GPGME_PROTOCOL_GPGCONF);
+
+ err = gpgme_new (&ctx);
+ fail_if_err (err);
+
+ err = gpgme_op_conf_load (ctx, &conf);
+ fail_if_err (err);
+
+ comp = conf;
+ first = 1;
+ while (comp)
+ {
+ if (!first)
+ printf ("\n");
+ else
+ first = 0;
+ dump_comp (comp);
+ comp = comp->next;
+ }
+
+#if 1
+ /* Now change something. */
+ {
+ unsigned int count = 1;
+ gpgme_conf_arg_t arg;
+ gpgme_conf_opt_t opt;
+
+ err = gpgme_conf_arg_new (&arg, GPGME_CONF_NONE, &count);
+ fail_if_err (err);
+
+ comp = conf;
+ while (comp && strcmp (comp->name, "dirmngr"))
+ comp = comp->next;
+ opt = comp->options;
+ while (opt && strcmp (opt->name, "verbose"))
+ opt = opt->next;
+
+ err = gpgme_conf_opt_change (opt, 0, arg);
+ fail_if_err (err);
+
+ err = gpgme_op_conf_save (ctx, comp);
+ fail_if_err (err);
+ }
+#endif
+
+ gpgme_conf_release (conf);
+
+ return 0;
+}
GPGSM = @GPGSM@
-TESTS_ENVIRONMENT = GNUPGHOME=. GPG_AGENT_INFO=
+TESTS_ENVIRONMENT = GNUPGHOME=$(abs_builddir) GPG_AGENT_INFO=
noinst_HEADERS = t-support.h
TESTS = t-import t-keylist t-encrypt t-verify t-decrypt t-sign t-export