/* path to the gpg binary */
#undef GPG_PATH
+/* min. needed GPG version */
+#undef NEED_GPG_VERSION
/* stuff needed by lnlib/ */
#undef HAVE_BYTE_TYPEDEF
if test "$*" = ""; then
conf_options="--enable-maintainer-mode"
else
- conf_options=$*
+ conf_options=$*
fi
echo "Running ./configure $conf_options"
./configure $conf_options
LIBGPGME_LT_CURRENT=2
LIBGPGME_LT_AGE=2
LIBGPGME_LT_REVISION=0
+NEED_GPG_VERSION=1.0.4d
##############################################
AC_SUBST(LIBGPGME_LT_CURRENT)
AC_SUBST(LIBGPGME_LT_AGE)
AC_SUBST(LIBGPGME_LT_REVISION)
+AC_DEFINE_UNQUOTED(NEED_GPG_VERSION, "$NEED_GPG_VERSION")
dnl
echo "
GPGME v${VERSION} has been configured as follows:
- GPG path: $GPG
- Component: $component_system
+ GPG version: min. $NEED_GPG_VERSION
+ GPG path: $GPG
+ Component: $component_system
"
+2001-01-22 Werner Koch <wk@gnupg.org>
+
+ * delete.c: New.
+
+ * signers.c: New.
+ * key.c (gpgme_key_ref, gpgme_key_unref): New.
+ * sign.c (gpgme_op_sign_start): Allow the use of other keys.
+
+ * version.c (gpgme_get_engine_info,gpgme_check_engine): New.
+ * rungpg.c (_gpgme_gpg_set_simple_line_handler): New.
+
2001-01-05 Werner Koch <wk@gnupg.org>
* data.c (gpgme_data_rewind): Allow to rewind data_type_none.
libgpgme_la_SOURCES = \
gpgme.h types.h util.h util.c \
context.h ops.h \
- data.c recipient.c \
+ data.c recipient.c signers.c \
wait.c wait.h \
encrypt.c \
decrypt.c \
import.c \
export.c \
genkey.c \
+ delete.c \
rungpg.c rungpg.h status-table.h \
syshdr.h io.h posix-io.c w32-io.c \
gpgme.c version.c errors.c
int use_textmode;
int keylist_mode;
+ int signers_size; /* size of the following array */
+ GpgmeKey *signers;
+
ResultType result_type;
union {
VerifyResult verify;
--- /dev/null
+/* delete.c - delete a key
+ * Copyright (C) 2001 Werner Koch (dd9jn)
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <assert.h>
+
+#include "util.h"
+#include "context.h"
+#include "ops.h"
+#include "key.h"
+
+static void
+delete_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args )
+{
+ if ( ctx->out_of_core )
+ return;
+
+ switch (code) {
+ case STATUS_EOF:
+ break;
+
+ default:
+ /* ignore all other codes */
+ break;
+ }
+}
+
+
+GpgmeError
+gpgme_op_delete_start ( GpgmeCtx c, const GpgmeKey key, int allow_secret )
+{
+ GpgmeError rc = 0;
+ int i;
+ const char *s;
+
+ fail_on_pending_request( c );
+ c->pending = 1;
+
+ if (!key) {
+ rc = mk_error (Invalid_Value);
+ goto leave;
+ }
+
+ if ( c->gpg ) {
+ _gpgme_gpg_release ( c->gpg );
+ c->gpg = NULL;
+ }
+
+ rc = _gpgme_gpg_new ( &c->gpg );
+ if (rc)
+ goto leave;
+
+ _gpgme_gpg_set_status_handler ( c->gpg, delete_status_handler, c );
+
+ /* build the commandline */
+ for ( i=0; i < c->verbosity; i++ )
+ _gpgme_gpg_add_arg ( c->gpg, "--verbose" );
+ _gpgme_gpg_add_arg ( c->gpg, allow_secret?
+ "--delete-secret-and-public-key":"--delete-key" );
+
+ _gpgme_gpg_add_arg ( c->gpg, "--" );
+ s = gpgme_key_get_string_attr ( key, GPGME_ATTR_FPR, NULL, 0 );
+ if (!s) {
+ rc = mk_error (Invalid_Key);
+ goto leave;
+ }
+ _gpgme_gpg_add_arg ( c->gpg, s );
+
+ /* do it */
+ rc = _gpgme_gpg_spawn ( c->gpg, c );
+
+ leave:
+ if (rc) {
+ c->pending = 0;
+ _gpgme_gpg_release ( c->gpg ); c->gpg = NULL;
+ }
+ return rc;
+}
+
+
+GpgmeError
+gpgme_op_delete ( GpgmeCtx c, const GpgmeKey key, int allow_secret )
+{
+ int rc = gpgme_op_delete_start ( c, key, allow_secret );
+ if ( !rc ) {
+ gpgme_wait (c, 1);
+ c->pending = 0;
+ /* FIXME: check for success */
+ }
+ return rc;
+}
+
+
+
+
case GPGME_Decryption_Failed: s="Decryption Failed"; break;
case GPGME_No_Passphrase: s="No Passphrase"; break;
case GPGME_Canceled: s="Canceled"; break;
+ case GPGME_Invalid_Key: s="Invalid Key"; break;
+ case GPGME_Invalid_Engine: s="Invalid Engine"; break;
default: sprintf (buf, "ec=%d", err ); s=buf; break;
}
gpgme_key_release ( c->tmp_key );
gpgme_data_release ( c->help_data_1 );
gpgme_data_release ( c->notation );
+ gpgme_signers_clear (c);
+ if (c->signers)
+ xfree (c->signers);
/* fixme: release the key_queue */
xfree (c);
}
return _gpgme_data_get_as_string ( c->notation );
}
-
/**
* gpgme_set_armor:
* @c: the contect
}
+
+
+
+
+
+
+
GPGME_Decryption_Failed = 18,
GPGME_No_Passphrase = 19,
GPGME_Canceled = 20,
+ GPGME_Invalid_Key = 21,
+ GPGME_Invalid_Engine = 22,
} GpgmeError;
typedef enum {
GpgmePassphraseCb cb, void *cb_value);
void gpgme_set_progress_cb (GpgmeCtx c, GpgmeProgressCb cb, void *cb_value);
+void gpgme_signers_clear (GpgmeCtx c);
+GpgmeError gpgme_signers_add (GpgmeCtx c, const GpgmeKey key);
+GpgmeKey gpgme_signers_enum (const GpgmeCtx c, int seq);
/* Functions to handle recipients */
/* Key and trust functions */
+void gpgme_key_ref (GpgmeKey key);
+void gpgme_key_unref (GpgmeKey key);
void gpgme_key_release ( GpgmeKey key );
char *gpgme_key_get_as_xml ( GpgmeKey key );
const char *gpgme_key_get_string_attr ( GpgmeKey key, GpgmeAttr what,
GpgmeData keydata );
GpgmeError gpgme_op_genkey_start ( GpgmeCtx c, const char *parms,
GpgmeData pubkey, GpgmeData seckey );
+GpgmeError gpgme_op_delete_start ( GpgmeCtx c, const GpgmeKey key,
+ int allow_secret );
GpgmeData keydata );
GpgmeError gpgme_op_genkey ( GpgmeCtx c, const char *parms,
GpgmeData pubkey, GpgmeData seckey );
+GpgmeError gpgme_op_delete ( GpgmeCtx c, const GpgmeKey key, int allow_secret);
/* miscellaneous functions */
-const char *gpgme_check_version ( const char *req_version );
+const char *gpgme_check_version (const char *req_version);
+GpgmeError gpgme_check_engine (void);
+const char *gpgme_get_engine_info (void);
const char *gpgme_strerror (GpgmeError err);
-void gpgme_register_idle ( void (*fnc)(void) );
+void gpgme_register_idle (void (*fnc)(void));
#ifdef __cplusplus
key = xtrycalloc ( 1, sizeof *key );
if (!key)
return mk_error (Out_Of_Core);
-
+ key->ref_count = 1;
*r_key = key;
return 0;
}
+void
+gpgme_key_ref ( GpgmeKey key )
+{
+ return_if_fail (key);
+ key->ref_count++;
+}
+
struct subkey_s *
_gpgme_key_add_subkey (GpgmeKey key)
if (!key)
return;
+ assert (key->ref_count);
+ if ( --key->ref_count )
+ return;
+
xfree (key->keys.fingerprint);
for (k = key->keys.next; k; k = k2 ) {
k2 = k->next;
xfree (key);
}
+void
+gpgme_key_unref (GpgmeKey key)
+{
+ gpgme_key_release (key);
+}
+
+
static char *
set_user_id_part ( char *tail, const char *buf, size_t len )
{
unsigned int expired:1 ;
unsigned int disabled:1 ;
} gloflags;
+ unsigned int ref_count;
struct subkey_s keys;
struct user_id_s *uids;
};
int eof;
GpgColonLineHandler fnc; /* this indicate use of this structrue */
void *fnc_value;
+ int simple;
} colon;
char **argv;
gpg->colon.eof = 0;
gpg->colon.fnc = fnc;
gpg->colon.fnc_value = fnc_value;
+ gpg->colon.simple = 0;
return 0;
}
+GpgmeError
+_gpgme_gpg_set_simple_line_handler ( GpgObject gpg,
+ GpgColonLineHandler fnc,
+ void *fnc_value )
+{
+ GpgmeError err;
+
+ err = _gpgme_gpg_set_colon_line_handler (gpg, fnc, fnc_value);
+ if (!err)
+ gpg->colon.simple = 1;
+ return err;
+}
+
+
/*
* The Fnc will be called to get a value for one of the commands with
* a key KEY. If the Code pssed to FNC is 0, the function may release
* some other printed information.
*/
*p = 0;
- if ( *buffer && strchr (buffer, ':') ) {
+ if ( gpg->colon.simple
+ || (*buffer && strchr (buffer, ':')) ) {
assert (gpg->colon.fnc);
gpg->colon.fnc ( gpg->colon.fnc_value, buffer );
}
GpgmeError _gpgme_gpg_set_colon_line_handler ( GpgObject gpg,
GpgColonLineHandler fnc,
void *fnc_value );
+GpgmeError _gpgme_gpg_set_simple_line_handler ( GpgObject gpg,
+ GpgColonLineHandler fnc,
+ void *fnc_value );
GpgmeError _gpgme_gpg_set_command_handler ( GpgObject gpg,
GpgCommandHandler fnc,
void *fnc_value );
{
int rc = 0;
int i;
+ GpgmeKey key;
fail_on_pending_request( c );
c->pending = 1;
if ( c->use_textmode )
_gpgme_gpg_add_arg ( c->gpg, "--textmode" );
}
- for ( i=0; i < c->verbosity; i++ )
+ for (i=0; i < c->verbosity; i++)
_gpgme_gpg_add_arg ( c->gpg, "--verbose" );
+ for (i=0; (key = gpgme_signers_enum (c, i)); i++ ) {
+ const char *s = gpgme_key_get_string_attr (key, GPGME_ATTR_KEYID,
+ NULL, 0);
+ if (s) {
+ _gpgme_gpg_add_arg (c->gpg, "-u");
+ _gpgme_gpg_add_arg (c->gpg, s);
+ }
+ gpgme_key_unref (key);
+ }
+
/* Check the supplied data */
if ( gpgme_data_get_type (in) == GPGME_DATA_TYPE_NONE ) {
--- /dev/null
+/* signers.c - maintain signer sets
+ * Copyright (C) 2001 Werner Koch (dd9jn)
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "util.h"
+#include "context.h"
+#include "rungpg.h"
+
+/* The signers are directly stored in the context.
+ * So this is quite different to a recipient set.
+ */
+
+
+void
+gpgme_signers_clear (GpgmeCtx c)
+{
+ int i;
+
+ return_if_fail (c);
+
+ if (!c->signers)
+ return;
+ for (i=0; i < c->signers_size; i++ ) {
+ if (!c->signers[i])
+ break;
+ gpgme_key_unref (c->signers[i]);
+ c->signers[i] = NULL;
+ }
+}
+
+
+GpgmeError
+gpgme_signers_add (GpgmeCtx c, const GpgmeKey key)
+{
+ int i = 0;
+
+ if (!c || !key)
+ return mk_error (Invalid_Value);
+
+ if (!c->signers)
+ c->signers_size = 0;
+
+ for (i=0; i < c->signers_size && c->signers[i]; i++ )
+ ;
+ if ( !(i < c->signers_size) ) {
+ GpgmeKey *newarr;
+ int j;
+ int n = c->signers_size + 5;
+
+ newarr = xtrycalloc ( n, sizeof *newarr );
+ if ( !newarr )
+ return mk_error (Out_Of_Core);
+ for (j=0; j < c->signers_size; j++ )
+ newarr[j] = c->signers[j];
+ c->signers_size = n;
+ }
+ gpgme_key_ref (key);
+ c->signers[i] = key;
+ return 0;
+}
+
+
+GpgmeKey
+gpgme_signers_enum (const GpgmeCtx c, int seq )
+{
+ int i;
+
+ return_null_if_fail (c);
+ return_null_if_fail (seq<0);
+
+ if (!c->signers)
+ c->signers_size = 0;
+ for (i=0; i < c->signers_size && c->signers[i]; i++ ) {
+ if (i==seq) {
+ gpgme_key_ref (c->signers[i]);
+ return c->signers[i];
+ }
+ }
+ return NULL;
+}
+
+
+
+
char *stpcpy (char *a, const char *b);
#endif
+#define return_if_fail(expr) do { \
+ if (!(expr)) { \
+ fprintf (stderr, "%s:%d: assertion `%s' failed", \
+ __FILE__, __LINE__, #expr ); \
+ return; \
+ } } while (0)
+#define return_null_if_fail(expr) do { \
+ if (!(expr)) { \
+ fprintf (stderr, "%s:%d: assertion `%s' failed", \
+ __FILE__, __LINE__, #expr ); \
+ return NULL; \
+ } } while (0)
+#define return_val_if_fail(expr,val) do { \
+ if (!(expr)) { \
+ fprintf (stderr, "%s:%d: assertion `%s' failed", \
+ __FILE__, __LINE__, #expr ); \
+ return (val); \
+ } } while (0)
+
#endif /* UTIL_H */
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <ctype.h>
#include "gpgme.h"
+#include "context.h"
+#include "rungpg.h"
+#include "util.h"
+
+
+static int lineno;
+static char *tmp_engine_version;
+
+static const char *get_engine_info (void);
+
static const char*
parse_version_number ( const char *s, int *number )
return s; /* patchlevel */
}
-/**
- * gpgme_check_version:
- * @req_version: A string with a version
- *
- * Check that the the version of the library is at minimum the requested one
- * and return the version string; return NULL if the condition is not
- * met. If a NULL is passed to this function, no check is done and
- * the version string is simply returned.
- *
- * Return value: The version string or NULL
- **/
-const char *
-gpgme_check_version ( const char *req_version )
+static const char *
+compare_versions ( const char *my_version, const char *req_version )
{
- const char *ver = VERSION;
int my_major, my_minor, my_micro;
int rq_major, rq_minor, rq_micro;
const char *my_plvl, *rq_plvl;
if ( !req_version )
- return ver;
+ return my_version;
- my_plvl = parse_version_string ( ver, &my_major, &my_minor, &my_micro );
+ my_plvl = parse_version_string ( my_version,
+ &my_major, &my_minor, &my_micro );
if ( !my_plvl )
return NULL; /* very strange: our own version is bogus */
- rq_plvl = parse_version_string( req_version, &rq_major, &rq_minor,
- &rq_micro );
+ rq_plvl = parse_version_string( req_version,
+ &rq_major, &rq_minor, &rq_micro );
if ( !rq_plvl )
return NULL; /* req version string is invalid */
|| (my_major == rq_major && my_minor == rq_minor
&& my_micro == rq_micro
&& strcmp( my_plvl, rq_plvl ) >= 0) ) {
- return ver;
+ return my_version;
}
return NULL;
}
+/**
+ * gpgme_check_version:
+ * @req_version: A string with a version
+ *
+ * Check that the the version of the library is at minimum the requested one
+ * and return the version string; return NULL if the condition is not
+ * met. If a NULL is passed to this function, no check is done and
+ * the version string is simply returned.
+ *
+ * Return value: The version string or NULL
+ **/
+const char *
+gpgme_check_version ( const char *req_version )
+{
+ return compare_versions ( VERSION, req_version );
+}
+
+
+/**
+ * gpgme_get_engine_info:
+ *
+ * Return information about the underlying crypto engine. This is an
+ * XML string with various information. To get the version of the
+ * crypto engine it should be sufficient to grep for the first
+ * <literal>version</literal> tag and use it's content. A string is
+ * always returned even if the crypto engine is not installed; in this
+ * case a XML string with some error information is returned.
+ *
+ * Return value: A XML string with information about the crypto engine.
+ **/
+const char *
+gpgme_get_engine_info ()
+{
+ return get_engine_info ();
+}
+
+/**
+ * gpgme_check_engine:
+ *
+ * Check whether the installed crypto engine matches the requirement of
+ * GPGME.
+ *
+ * Return value: 0 or an error code.
+ **/
+GpgmeError
+gpgme_check_engine ()
+{
+ const char *info = gpgme_get_engine_info ();
+ const char *s, *s2;
+
+ s = strstr (info, "<version>");
+ if (s) {
+ s += 9;
+ s2 = strchr (s, '>');
+ if (s2) {
+ char *ver = xtrymalloc (s2 - s + 1);
+ if (!ver)
+ return mk_error (Out_Of_Core);
+ memcpy (ver, s, s2-s);
+ ver[s2-s] = 0;
+ s = compare_versions ( ver, NEED_GPG_VERSION );
+ xfree (ver);
+ if (s)
+ return 0;
+ }
+ }
+ return mk_error (Invalid_Engine);
+}
+
+
+\f
+static void
+version_line_handler ( GpgmeCtx c, char *line )
+{
+ char *p;
+ size_t len;
+
+ lineno++;
+ if ( c->out_of_core )
+ return;
+ if (!line)
+ return; /* EOF */
+ if (lineno==1) {
+ if ( memcmp (line, "gpg ", 4) )
+ return;
+ if ( !(p = strpbrk (line, "0123456789")) )
+ return;
+ len = strcspn (p, " \t\r\n()<>" );
+ p[len] = 0;
+ tmp_engine_version = xtrystrdup (p);
+ }
+}
+
+
+static const char *
+get_engine_info (void)
+{
+ const char *engine_info =NULL;
+ GpgmeCtx c = NULL;
+ GpgmeError err = 0;
+
+ /* FIXME: make sure that only one instance does run */
+ if (engine_info)
+ goto leave;
+
+ err = gpgme_new (&c);
+ if (err)
+ goto leave;
+ err = _gpgme_gpg_new ( &c->gpg );
+ if (err)
+ goto leave;
+
+ err = _gpgme_gpg_set_simple_line_handler ( c->gpg,
+ version_line_handler, c );
+ if (err)
+ goto leave;
+
+ _gpgme_gpg_add_arg ( c->gpg, "--version" );
+ lineno = 0;
+ xfree (tmp_engine_version); tmp_engine_version = NULL;
+ err = _gpgme_gpg_spawn ( c->gpg, c );
+ if (err)
+ goto leave;
+ gpgme_wait (c, 1);
+ if (tmp_engine_version) {
+ const char *fmt;
+ char *p;
+
+ fmt = "<GnupgInfo>\n"
+ " <engine>\n"
+ " <version>%s</version>\n"
+ " </engine>\n"
+ "</GnupgInfo>\n";
+ /*(yes, I know that we allocating 2 extra bytes)*/
+ p = xtrymalloc ( strlen(fmt) + strlen (tmp_engine_version) + 1);
+ if (!p) {
+ err = mk_error (Out_Of_Core);
+ goto leave;
+ }
+ sprintf (p, fmt, tmp_engine_version);
+ engine_info = p;
+ xfree (tmp_engine_version); tmp_engine_version = NULL;
+ }
+ else {
+ err = mk_error (General_Error);
+ }
+
+ leave:
+ if (err)
+ engine_info = "<GnupgInfo>\n<error>No engine</error>\n</GnupgInfo>\n";
+ gpgme_release ( c );
+ return engine_info;
+}
+
if (q->exited) {
/* this is the second time we reached this and we got no
- * more data from the pipe (which may happen to to buffering).
+ * more data from the pipe (which may happen due to buffering).
* Set all FDs inactive.
*/
clear_active_fds (q->pid);
if (idle_function)
idle_function ();
}
+
GpgmeData in, out;
GpgmeRecipients rset;
+ err = gpgme_check_engine ();
+ fail_if_err (err);
+ puts ( gpgme_get_engine_info() );
+
do {
err = gpgme_new (&ctx);
fail_if_err (err);