2008-01-04 Marcus Brinkmann <marcus@g10code.de>

* 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.
This commit is contained in:
Marcus Brinkmann 2008-01-04 14:31:15 +00:00
parent 6286b436bd
commit 19025d7918
23 changed files with 1760 additions and 16 deletions

View File

@ -1,3 +1,7 @@
2008-01-04 Marcus Brinkmann <marcus@g10code.de>
* configure.ac: Support gpgconf.
2007-09-27 Marcus Brinkmann <marcus@g10code.de> 2007-09-27 Marcus Brinkmann <marcus@g10code.de>
* assuan-pipe-connect.c (pipe_connect_gpgme): Do not close process * assuan-pipe-connect.c (pipe_connect_gpgme): Do not close process

View File

@ -114,6 +114,7 @@ AM_CONDITIONAL(HAVE_LD_VERSION_SCRIPT, test "$have_ld_version_script" = "yes")
GPG_DEFAULT=no GPG_DEFAULT=no
GPGSM_DEFAULT=no GPGSM_DEFAULT=no
GPGCONF_DEFAULT=no
component_system=None component_system=None
have_dosish_system=no have_dosish_system=no
have_w32_system=no have_w32_system=no
@ -126,6 +127,7 @@ case "${host}" in
have_w32_system=yes have_w32_system=yes
GPG_DEFAULT='c:\\gnupg\\gpg.exe' GPG_DEFAULT='c:\\gnupg\\gpg.exe'
GPGSM_DEFAULT='c:\\gnupg\\gpgsm.exe' GPGSM_DEFAULT='c:\\gnupg\\gpgsm.exe'
GPGCONF_DEFAULT='c:\\gnupg\\gpgconf.exe'
#component_system='COM+' #component_system='COM+'
AM_PATH_GLIB_2_0 AM_PATH_GLIB_2_0
@ -158,6 +160,7 @@ case "${host}" in
# XXX: Probably use exec-prefix here? # XXX: Probably use exec-prefix here?
# GPG_DEFAULT='/usr/bin/gpg' # GPG_DEFAULT='/usr/bin/gpg'
# GPGSM_DEFAULT='/usr/bin/gpgsm' # GPGSM_DEFAULT='/usr/bin/gpgsm'
# GPGCONF_DEFAULT='/usr/bin/gpgconf'
;; ;;
esac esac
@ -261,8 +264,10 @@ AC_DEFINE(GPG_ERR_SOURCE_DEFAULT, GPG_ERR_SOURCE_GPGME,
# Checks for system services # Checks for system services
NEED_GPG_VERSION_DEFAULT=1.3.0 NEED_GPG_VERSION_DEFAULT=1.3.0
NEED_GPGSM_VERSION_DEFAULT=1.9.6 NEED_GPGSM_VERSION_DEFAULT=1.9.6
NEED_GPGCONF_VERSION_DEFAULT=2.0.4
NEED_GPG_VERSION="$NEED_GPG_VERSION_DEFAULT" NEED_GPG_VERSION="$NEED_GPG_VERSION_DEFAULT"
NEED_GPGSM_VERSION="$NEED_GPGSM_VERSION_DEFAULT" NEED_GPGSM_VERSION="$NEED_GPGSM_VERSION_DEFAULT"
NEED_GPGCONF_VERSION="$NEED_GPGCONF_VERSION_DEFAULT"
AC_ARG_WITH(gpg-version, AC_ARG_WITH(gpg-version,
AC_HELP_STRING([--with-gpg-version=VER], [require GnuPG version VER]), AC_HELP_STRING([--with-gpg-version=VER], [require GnuPG version VER]),
NEED_GPG_VERSION=$withval) NEED_GPG_VERSION=$withval)
@ -281,11 +286,22 @@ fi
if test "$NEED_GPGSM_VERSION" = "no"; then if test "$NEED_GPGSM_VERSION" = "no"; then
NEED_GPGSM_VERSION=0.0.0 NEED_GPGSM_VERSION=0.0.0
fi 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", AC_DEFINE_UNQUOTED(NEED_GPG_VERSION, "$NEED_GPG_VERSION",
[Min. needed GnuPG version.]) [Min. needed GnuPG version.])
AC_DEFINE_UNQUOTED(NEED_GPGSM_VERSION, "$NEED_GPGSM_VERSION", AC_DEFINE_UNQUOTED(NEED_GPGSM_VERSION, "$NEED_GPGSM_VERSION",
[Min. needed GPGSM version.]) [Min. needed GPGSM version.])
AC_DEFINE_UNQUOTED(NEED_GPGCONF_VERSION, "$NEED_GPGCONF_VERSION",
[Min. needed GPGCONF version.])
NO_OVERRIDE=no NO_OVERRIDE=no
@ -477,6 +493,109 @@ AC_ARG_ENABLE(gpgsm-test,
AM_CONDITIONAL(RUN_GPGSM_TESTS, test "$run_gpgsm_test" = "yes") 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. # FIXME: Only build if supported.
AM_CONDITIONAL(BUILD_ASSUAN, test "$GPGSM" != "no") AM_CONDITIONAL(BUILD_ASSUAN, test "$GPGSM" != "no")
if test "$GPGSM" != "no"; then if test "$GPGSM" != "no"; then
@ -640,6 +759,9 @@ echo "
GpgSM path: $GPGSM GpgSM path: $GPGSM
GpgSM version: $GPGSM_VERSION, min. $NEED_GPGSM_VERSION GpgSM version: $GPGSM_VERSION, min. $NEED_GPGSM_VERSION
GpgConf path: $GPGCONF
GpgConf version: $GPGCONF_VERSION, min. $NEED_GPGCONF_VERSION
GPGME Pthread: $have_pthread GPGME Pthread: $have_pthread
GPGME Pth: $have_pth GPGME Pth: $have_pth
" "

View File

@ -1,3 +1,35 @@
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> 2007-11-28 Marcus Brinkmann <marcus@g10code.de>
* w32-util.c (_gpgme_get_gpg_path, _gpgme_get_gpgsm_path): Search * w32-util.c (_gpgme_get_gpg_path, _gpgme_get_gpgsm_path): Search

View File

@ -83,6 +83,12 @@ else
gpgsm_components = gpgsm_components =
endif 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 # 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 # to build a non-installed library for that, but that does not work
# correctly on all platforms (in particular, one can not specify the # correctly on all platforms (in particular, one can not specify the
@ -100,7 +106,8 @@ main_sources = \
key.c keylist.c trust-item.c trustlist.c \ key.c keylist.c trust-item.c trustlist.c \
import.c export.c genkey.c delete.c edit.c getauditlog.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 \ 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 debug.c debug.h gpgme.c version.c error.c
libgpgme_la_SOURCES = $(main_sources) \ libgpgme_la_SOURCES = $(main_sources) \

View File

@ -97,6 +97,9 @@ struct engine_ops
gpgme_error_t (*getauditlog) (void *engine, gpgme_data_t output, gpgme_error_t (*getauditlog) (void *engine, gpgme_data_t output,
unsigned int flags); 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 (*set_io_cbs) (void *engine, gpgme_io_cbs_t io_cbs);
void (*io_event) (void *engine, gpgme_event_io_t type, void *type_data); void (*io_event) (void *engine, gpgme_event_io_t type, void *type_data);
@ -108,5 +111,8 @@ extern struct engine_ops _gpgme_engine_ops_gpg; /* OpenPGP. */
#ifdef ENABLE_GPGSM #ifdef ENABLE_GPGSM
extern struct engine_ops _gpgme_engine_ops_gpgsm; /* CMS. */ extern struct engine_ops _gpgme_engine_ops_gpgsm; /* CMS. */
#endif #endif
#ifdef ENABLE_GPGCONF
extern struct engine_ops _gpgme_engine_ops_gpgconf; /* gpg-conf. */
#endif
#endif /* ENGINE_BACKEND_H */ #endif /* ENGINE_BACKEND_H */

877
gpgme/engine-gpgconf.c Normal file
View File

@ -0,0 +1,877 @@
// 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"
struct engine_gpgconf
{
char *file_name;
char *home_dir;
};
typedef struct engine_gpgconf *engine_gpgconf_t;
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;
}
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;
}
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;
}
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;
}
/* 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. */
}
/* 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);
}
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 */
};

View File

@ -1885,6 +1885,8 @@ struct engine_ops _gpgme_engine_ops_gpgsm =
NULL, /* trustlist */ NULL, /* trustlist */
gpgsm_verify, gpgsm_verify,
gpgsm_getauditlog, gpgsm_getauditlog,
NULL, /* conf_load */
NULL, /* conf_save */
gpgsm_set_io_cbs, gpgsm_set_io_cbs,
gpgsm_io_event, gpgsm_io_event,
gpgsm_cancel gpgsm_cancel

View File

@ -47,7 +47,12 @@ static struct engine_ops *engine_ops[] =
{ {
&_gpgme_engine_ops_gpg, /* OpenPGP. */ &_gpgme_engine_ops_gpg, /* OpenPGP. */
#ifdef ENABLE_GPGSM #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 #else
NULL NULL
#endif #endif
@ -169,7 +174,8 @@ gpgme_get_engine_info (gpgme_engine_info_t *info)
{ {
gpgme_engine_info_t *lastp = &engine_info; gpgme_engine_info_t *lastp = &engine_info;
gpgme_protocol_t proto_list[] = { GPGME_PROTOCOL_OpenPGP, gpgme_protocol_t proto_list[] = { GPGME_PROTOCOL_OpenPGP,
GPGME_PROTOCOL_CMS }; GPGME_PROTOCOL_CMS,
GPGME_PROTOCOL_GPGCONF };
unsigned int proto; unsigned int proto;
for (proto = 0; proto < DIM (proto_list); proto++) for (proto = 0; proto < DIM (proto_list); proto++)
@ -724,6 +730,32 @@ _gpgme_engine_op_getauditlog (engine_t engine, gpgme_data_t output,
} }
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 void
_gpgme_engine_set_io_cbs (engine_t engine, gpgme_io_cbs_t io_cbs) _gpgme_engine_set_io_cbs (engine_t engine, gpgme_io_cbs_t io_cbs)
{ {

View File

@ -127,6 +127,11 @@ gpgme_error_t _gpgme_engine_op_getauditlog (engine_t engine,
gpgme_data_t output, gpgme_data_t output,
unsigned int flags); 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, void _gpgme_engine_set_io_cbs (engine_t engine,
gpgme_io_cbs_t io_cbs); gpgme_io_cbs_t io_cbs);
void _gpgme_engine_io_event (engine_t engine, void _gpgme_engine_io_event (engine_t engine,

134
gpgme/gpgconf.c Normal file
View File

@ -0,0 +1,134 @@
/* 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
/* 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
}

View File

@ -159,5 +159,12 @@ EXPORTS
gpgme_op_getauditlog_start @123 gpgme_op_getauditlog_start @123
gpgme_op_getauditlog @124 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 ; END

View File

@ -72,7 +72,7 @@ extern "C" {
AM_PATH_GPGME macro) check that this header matches the installed AM_PATH_GPGME macro) check that this header matches the installed
library. Warning: Do not edit the next line. configure will do library. Warning: Do not edit the next line. configure will do
that for you! */ that for you! */
#define GPGME_VERSION "1.1.6-svn1258" #define GPGME_VERSION "1.1.6-svn1282"
@ -300,6 +300,7 @@ typedef enum
{ {
GPGME_PROTOCOL_OpenPGP = 0, /* The default mode. */ GPGME_PROTOCOL_OpenPGP = 0, /* The default mode. */
GPGME_PROTOCOL_CMS = 1, GPGME_PROTOCOL_CMS = 1,
GPGME_PROTOCOL_GPGCONF = 2, /* Special code for gpgconf. */
GPGME_PROTOCOL_UNKNOWN = 255 GPGME_PROTOCOL_UNKNOWN = 255
} }
gpgme_protocol_t; gpgme_protocol_t;
@ -1652,6 +1653,163 @@ gpgme_error_t gpgme_op_getauditlog_start (gpgme_ctx_t ctx, gpgme_data_t output,
gpgme_error_t gpgme_op_getauditlog (gpgme_ctx_t ctx, gpgme_data_t output, gpgme_error_t gpgme_op_getauditlog (gpgme_ctx_t ctx, gpgme_data_t output,
unsigned int flags); unsigned int flags);
/* 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);
/* Various functions. */ /* Various functions. */

View File

@ -39,6 +39,13 @@ GPGME_1.1 {
gpgme_op_getauditlog_start; gpgme_op_getauditlog_start;
gpgme_op_getauditlog; 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;
}; };

View File

@ -115,6 +115,8 @@ _gpgme_op_reset (gpgme_ctx_t ctx, int type)
err = _gpgme_engine_set_locale (ctx->engine, err = _gpgme_engine_set_locale (ctx->engine,
LC_MESSAGES, ctx->lc_messages); LC_MESSAGES, ctx->lc_messages);
#endif #endif
if (gpg_err_code (err) == GPG_ERR_NOT_IMPLEMENTED)
err = 0;
if (err) if (err)
{ {
_gpgme_engine_release (ctx->engine); _gpgme_engine_release (ctx->engine);

View File

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

View File

@ -2120,7 +2120,9 @@ struct engine_ops _gpgme_engine_ops_gpg =
gpg_sign, gpg_sign,
gpg_trustlist, gpg_trustlist,
gpg_verify, gpg_verify,
NULL, NULL, /* getauditlog */
NULL, /* conf_load */
NULL, /* conf_save */
gpg_set_io_cbs, gpg_set_io_cbs,
gpg_io_event, gpg_io_event,
gpg_cancel gpg_cancel

View File

@ -31,6 +31,7 @@
/*-- {posix,w32}-util.c --*/ /*-- {posix,w32}-util.c --*/
const char *_gpgme_get_gpg_path (void); const char *_gpgme_get_gpg_path (void);
const char *_gpgme_get_gpgsm_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); int _gpgme_get_conf_int (const char *key, int *value);

View File

@ -274,6 +274,7 @@ find_program_in_inst_dir (const char *name)
return result; return result;
} }
static char * static char *
find_program_at_standard_place (const char *name) find_program_at_standard_place (const char *name)
{ {
@ -313,6 +314,7 @@ _gpgme_get_gpg_path (void)
return gpg_program; return gpg_program;
} }
const char * const char *
_gpgme_get_gpgsm_path (void) _gpgme_get_gpgsm_path (void)
{ {
@ -330,6 +332,24 @@ _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 /* Return an integer value from gpgme specific configuration
entries. VALUE receives that value; function returns true if a value entries. VALUE receives that value; function returns true if a value
has been configured and false if not. */ has been configured and false if not. */

View File

@ -1,3 +1,14 @@
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> 2007-11-23 Marcus Brinkmann <marcus@g10code.de>
* gpgsm/t-verify.c (show_auditlog): Check for GPG_ERR_ASS_UNKNOWN_CMD. * gpgsm/t-verify.c (show_auditlog): Check for GPG_ERR_ASS_UNKNOWN_CMD.

View File

@ -20,7 +20,7 @@
## Process this file with automake to produce Makefile.in ## 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 TESTS = t-version t-data t-engine-info

View File

@ -21,7 +21,7 @@
GPG = @GPG@ 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. # The keylist tests must come after the import and the edit test.
noinst_HEADERS = t-support.h noinst_HEADERS = t-support.h
@ -35,9 +35,9 @@ endif
TESTS = t-encrypt t-encrypt-sym t-encrypt-sign t-sign t-signers \ 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-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-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 DISTCLEANFILES = pubring.gpg~ random_seed gpg.conf
EXTRA_DIST = mkdemodirs pubdemo.asc secdemo.asc cipher-1.asc cipher-2.asc \ EXTRA_DIST = mkdemodirs pubdemo.asc secdemo.asc cipher-1.asc cipher-2.asc \

305
tests/gpg/t-gpgconf.c Normal file
View File

@ -0,0 +1,305 @@
/* 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);
}
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;
}

View File

@ -21,7 +21,7 @@
GPGSM = @GPGSM@ GPGSM = @GPGSM@
TESTS_ENVIRONMENT = GNUPGHOME=. GPG_AGENT_INFO= TESTS_ENVIRONMENT = GNUPGHOME=$(abs_builddir) GPG_AGENT_INFO=
noinst_HEADERS = t-support.h noinst_HEADERS = t-support.h
TESTS = t-import t-keylist t-encrypt t-verify t-decrypt t-sign t-export TESTS = t-import t-keylist t-encrypt t-verify t-decrypt t-sign t-export