Some new but untested functions
authorWerner Koch <wk@gnupg.org>
Mon, 22 Jan 2001 20:22:41 +0000 (20:22 +0000)
committerWerner Koch <wk@gnupg.org>
Mon, 22 Jan 2001 20:22:41 +0000 (20:22 +0000)
20 files changed:
acconfig.h
autogen.sh
configure.in
gpgme/ChangeLog
gpgme/Makefile.am
gpgme/context.h
gpgme/delete.c [new file with mode: 0644]
gpgme/errors.c
gpgme/gpgme.c
gpgme/gpgme.h
gpgme/key.c
gpgme/key.h
gpgme/rungpg.c
gpgme/rungpg.h
gpgme/sign.c
gpgme/signers.c [new file with mode: 0644]
gpgme/util.h
gpgme/version.c
gpgme/wait.c
tests/t-encrypt.c

index e8cd758..1a7f63c 100644 (file)
@@ -41,6 +41,8 @@
 
 /* path to the gpg binary */
 #undef GPG_PATH
+/* min. needed GPG version */
+#undef NEED_GPG_VERSION
 
 /* stuff needed by lnlib/ */
 #undef HAVE_BYTE_TYPEDEF
index 10b498c..13e4b36 100755 (executable)
@@ -148,7 +148,7 @@ autoconf
 if test "$*" = ""; then
     conf_options="--enable-maintainer-mode"
 else
-   conf_options=$*
+    conf_options=$*
 fi
 echo "Running ./configure $conf_options"
 ./configure $conf_options
index 9eb81d1..264deda 100644 (file)
@@ -17,11 +17,13 @@ AM_INIT_AUTOMAKE(gpgme,0.1.4a)
 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
@@ -156,8 +158,9 @@ complus/Makefile
 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
 "
 
 
index 79fed0f..fe88ebb 100644 (file)
@@ -1,3 +1,14 @@
+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.
index 8365678..74d5955 100644 (file)
@@ -15,7 +15,7 @@ libgpgme_la_INCLUDES = -I$(top_srcdir)/lib
 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 \
@@ -27,6 +27,7 @@ libgpgme_la_SOURCES = \
        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
index 982eb1d..57d9d1f 100644 (file)
@@ -63,6 +63,9 @@ struct gpgme_context_s {
     int use_textmode;
     int keylist_mode;
 
+    int signers_size;  /* size of the following array */
+    GpgmeKey *signers;
+
     ResultType result_type;
     union {
         VerifyResult verify;
diff --git a/gpgme/delete.c b/gpgme/delete.c
new file mode 100644 (file)
index 0000000..4e3c9b4
--- /dev/null
@@ -0,0 +1,116 @@
+/* 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;
+}
+
+
+
+
index e25db3e..f07d086 100644 (file)
@@ -42,6 +42,8 @@ gpgme_strerror (GpgmeError err)
   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;
 }
 
index aea18fa..54ec97f 100644 (file)
@@ -72,6 +72,9 @@ gpgme_release ( GpgmeCtx c )
     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);
 }
@@ -132,7 +135,6 @@ gpgme_get_notation ( GpgmeCtx c )
     return _gpgme_data_get_as_string ( c->notation );
 }
 
-
 /**
  * gpgme_set_armor:
  * @c: the contect 
@@ -241,3 +243,10 @@ gpgme_set_progress_cb ( GpgmeCtx c, GpgmeProgressCb cb, void *cb_value )
 }
 
 
+
+
+
+
+
+
+
index 0fe59f7..971101b 100644 (file)
@@ -85,6 +85,8 @@ typedef enum {
     GPGME_Decryption_Failed = 18,
     GPGME_No_Passphrase = 19,
     GPGME_Canceled = 20,
+    GPGME_Invalid_Key = 21,
+    GPGME_Invalid_Engine = 22,
 } GpgmeError;
 
 typedef enum {
@@ -158,6 +160,9 @@ void gpgme_set_passphrase_cb (GpgmeCtx c,
                               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 */
@@ -200,6 +205,8 @@ GpgmeError    gpgme_data_write ( GpgmeData dh,
 
 
 /* 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,
@@ -233,6 +240,8 @@ GpgmeError gpgme_op_export_start ( GpgmeCtx c, GpgmeRecipients recp,
                                    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 );
 
 
 
@@ -261,12 +270,15 @@ GpgmeError gpgme_op_export ( GpgmeCtx c, GpgmeRecipients recp,
                              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
index 89e545b..87a5602 100644 (file)
@@ -57,11 +57,18 @@ _gpgme_key_new( GpgmeKey *r_key )
     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)
@@ -92,6 +99,10 @@ gpgme_key_release ( 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;
@@ -105,6 +116,13 @@ gpgme_key_release ( GpgmeKey key )
     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 )
 {
index 8c68779..c9be9b0 100644 (file)
@@ -45,6 +45,7 @@ struct gpgme_key_s {
         unsigned int expired:1 ;
         unsigned int disabled:1 ;
     } gloflags; 
+    unsigned int ref_count;
     struct subkey_s   keys; 
     struct user_id_s *uids;
 };
index 0723171..7631358 100644 (file)
@@ -84,6 +84,7 @@ struct gpg_object_s {
         int eof;
         GpgColonLineHandler fnc;  /* this indicate use of this structrue */
         void *fnc_value;
+        int simple;
     } colon;
 
     char **argv;  
@@ -376,10 +377,25 @@ _gpgme_gpg_set_colon_line_handler ( GpgObject gpg,
     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
@@ -1094,7 +1110,8 @@ read_colon_line ( GpgObject gpg )
                  * 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 );
                 }
index 27ccf3e..bdd4a7a 100644 (file)
@@ -105,6 +105,9 @@ void       _gpgme_gpg_set_status_handler ( GpgObject gpg,
 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 );
index 11480e0..cef099b 100644 (file)
@@ -130,6 +130,7 @@ gpgme_op_sign_start ( GpgmeCtx c, GpgmeData in, GpgmeData out,
 {
     int rc = 0;
     int i;
+    GpgmeKey key;
 
     fail_on_pending_request( c );
     c->pending = 1;
@@ -170,8 +171,18 @@ gpgme_op_sign_start ( GpgmeCtx c, GpgmeData in, GpgmeData out,
         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 ) {
diff --git a/gpgme/signers.c b/gpgme/signers.c
new file mode 100644 (file)
index 0000000..a9da7da
--- /dev/null
@@ -0,0 +1,105 @@
+/* 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;
+}
+
+
+
+
index 72e3eae..39e18e8 100644 (file)
@@ -47,6 +47,25 @@ void  _gpgme_free ( void *a );
 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 */
index 0319b06..0dfe4a3 100644 (file)
 #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 )
@@ -58,33 +69,22 @@ parse_version_string( const char *s, int *major, int *minor, int *micro )
     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 */
 
@@ -95,10 +95,164 @@ gpgme_check_version ( const char *req_version )
          || (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;
+}
+
 
index 1cd2418..ba7a22f 100644 (file)
@@ -189,7 +189,7 @@ _gpgme_wait_on_condition ( GpgmeCtx c, int hang, volatile int *cond )
             
             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);
@@ -377,3 +377,4 @@ run_idle ()
     if (idle_function)
         idle_function ();
 }
+
index ba7097e..15d2197 100644 (file)
@@ -57,6 +57,10 @@ main (int argc, char **argv )
     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);