Okay, it runs at least on Windows 95
authorWerner Koch <wk@gnupg.org>
Wed, 6 Dec 2000 12:17:10 +0000 (12:17 +0000)
committerWerner Koch <wk@gnupg.org>
Wed, 6 Dec 2000 12:17:10 +0000 (12:17 +0000)
27 files changed:
Makefile.am
acconfig.h
acinclude.m4
bonobo/Makefile.am [new file with mode: 0644]
bonobo/gpgme.c [new file with mode: 0644]
bonobo/main.c [new file with mode: 0644]
bonobo/main.h [new file with mode: 0644]
complus/Makefile.am [new file with mode: 0644]
complus/main.c [new file with mode: 0644]
complus/main.h [new file with mode: 0644]
configure.in
gpgme/context.h
gpgme/data.c
gpgme/decrypt.c
gpgme/errors.c [new file with mode: 0644]
gpgme/gpgme.c
gpgme/gpgme.h
gpgme/io.h
gpgme/ops.h
gpgme/posix-io.c
gpgme/rungpg.c
gpgme/status-table.h [new file with mode: 0644]
gpgme/verify.c
gpgme/version.c [new file with mode: 0644]
gpgme/w32-io.c
gpgme/wait.c
tests/t-decrypt.c

index 1b9784b..13cb797 100644 (file)
@@ -1,6 +1,18 @@
 
-EXTRA_DIST = README-alpha
+EXTRA_DIST = README-alpha build-w32
 
-SUBDIRS = gpgme tests
+if BUILD_BONOBO
+bonobo = bonobo
+else
+bonobo = 
+endif
+if BUILD_COMPLUS
+complus = complus
+else
+complus = 
+endif
+
+
+SUBDIRS = jnlib gpgme tests ${bonobo} ${complus}
 
 
index 5b1dd4c..e8cd758 100644 (file)
 /* path to the gpg binary */
 #undef GPG_PATH
 
+/* stuff needed by lnlib/ */
+#undef HAVE_BYTE_TYPEDEF
+#undef HAVE_USHORT_TYPEDEF
+#undef HAVE_ULONG_TYPEDEF
+#undef HAVE_U16_TYPEDEF
+#undef HAVE_U32_TYPEDEF
+
+
+
 @BOTTOM@
 
 /* not yet needed #include "gpgme-defs.h"*/
index 4b870ed..0952b2f 100644 (file)
@@ -21,6 +21,23 @@ AC_DEFUN(GNUPG_FIX_HDR_VERSION,
     fi
   ])
 
+dnl GNUPG_CHECK_TYPEDEF(TYPE, HAVE_NAME)
+dnl Check whether a typedef exists and create a #define $2 if it exists
+dnl
+AC_DEFUN(GNUPG_CHECK_TYPEDEF,
+  [ AC_MSG_CHECKING(for $1 typedef)
+    AC_CACHE_VAL(gnupg_cv_typedef_$1,
+    [AC_TRY_COMPILE([#include <stdlib.h>
+    #include <sys/types.h>], [
+    #undef $1
+    int a = sizeof($1);
+    ], gnupg_cv_typedef_$1=yes, gnupg_cv_typedef_$1=no )])
+    AC_MSG_RESULT($gnupg_cv_typedef_$1)
+    if test "$gnupg_cv_typedef_$1" = yes; then
+        AC_DEFINE($2)
+    fi
+  ])
+
 
 
 
diff --git a/bonobo/Makefile.am b/bonobo/Makefile.am
new file mode 100644 (file)
index 0000000..48bc03e
--- /dev/null
@@ -0,0 +1,11 @@
+## Process this file with automake to produce Makefile.in
+
+bin_PROGRAMS = gpgme
+
+INCLUDES = -I$(top_srcdir)/jnlib
+LDADD = -L ../jnlib -ljnlib 
+
+gpgme_SOURCES = main.c main.h
+
+
+
diff --git a/bonobo/gpgme.c b/bonobo/gpgme.c
new file mode 100644 (file)
index 0000000..765de50
--- /dev/null
@@ -0,0 +1,20 @@
+/* gpgme - Bonbobo component to access GnuPG
+ *     Copyright (C) 2000 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
+ */
+
diff --git a/bonobo/main.c b/bonobo/main.c
new file mode 100644 (file)
index 0000000..e42d20a
--- /dev/null
@@ -0,0 +1,20 @@
+/* main.c - Bonbobo component to access GnuPG
+ *     Copyright (C) 2000 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
+ */
+
diff --git a/bonobo/main.h b/bonobo/main.h
new file mode 100644 (file)
index 0000000..41b56df
--- /dev/null
@@ -0,0 +1,42 @@
+/* main.h -  GPGME Bonobo component
+ *     Copyright (C) 2000 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
+ */
+
+#ifndef MAIN_H
+#define MAIN_H
+
+
+struct {
+    int verbose;
+    int quiet;
+    unsigned int debug;
+    char *homedir;
+} opt;
+
+
+
+
+#endif /* MAIN_H */
+
+
+
+
+
+
+
diff --git a/complus/Makefile.am b/complus/Makefile.am
new file mode 100644 (file)
index 0000000..8976cd8
--- /dev/null
@@ -0,0 +1,12 @@
+## Process this file with automake to produce Makefile.in
+
+# No need to install this becuase we are cross-compiling anyway.
+noinst_PROGRAMS = gpgme
+
+INCLUDES = -I$(top_srcdir)/jnlib
+LDADD = -L ../jnlib -ljnlib 
+
+gpgme_SOURCES = main.c main.h
+
+
+
diff --git a/complus/main.c b/complus/main.c
new file mode 100644 (file)
index 0000000..221a66b
--- /dev/null
@@ -0,0 +1,287 @@
+/* main.c - COM+ component to access GnuPG
+ *     Copyright (C) 2000 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 <errno.h>
+#include <assert.h>
+#include <time.h>
+#include <windows.h>
+
+#include "argparse.h"
+
+#include "main.h"
+
+
+static void register_server (void);
+static void unregister_server (void);
+static void enter_complus (void);
+
+
+enum cmd_and_opt_values { aNull = 0,
+    oQuiet       = 'q',
+    oVerbose     = 'v',
+
+    oNoVerbose = 500,
+    oOptions,
+    oDebug,
+    oDebugAll,
+    oNoGreeting,
+    oNoOptions,
+    oHomedir,
+    oGPGBinary,
+    oRegServer,
+    oUnregServer,
+    oEmbedding,
+aTest };
+
+
+static ARGPARSE_OPTS opts[] = {
+
+    { 301, NULL, 0, N_("@Options:\n ") },
+
+    { oVerbose, "verbose",   0, N_("verbose") },
+    { oQuiet,  "quiet",     0, N_("be somewhat more quiet") },
+    { oOptions, "options"  , 2, N_("read options from file")},
+    { oDebug,  "debug"     ,4|16, N_("set debugging flags")},
+    { oDebugAll, "debug-all" ,0, N_("enable full debugging")},
+    { oGPGBinary, "gpg-program", 2 , "@" },
+    { oRegServer, "RegServer" , 0, "@" },
+    { oUnregServer, "UnregServer" , 0, "@" },
+    { oEmbedding, "Embedding" , 0, "@" },
+{0} };
+
+static const char *
+my_strusage( int level )
+{
+    const char *p;
+    switch( level ) {
+      case 11: p = "gpgme";
+       break;
+      case 13: p = VERSION; break;
+      /*case 17: p = PRINTABLE_OS_NAME; break;*/
+      case 19: p =
+           _("Please report bugs to <gpgme-bugs@gnupg.org>.\n");
+       break;
+      case 1:
+      case 40: p =
+           _("Usage: gpgme [options] (-h for help)");
+       break;
+      case 41: p =
+           _("Syntax: gpgme [options]\n"
+             "GnuPG COM+ component\n");
+       break;
+
+      default: p = NULL;
+    }
+    return p;
+}
+
+
+int
+main (int argc, char **argv )
+{
+    ARGPARSE_ARGS pargs;
+    int orig_argc;
+    char **orig_argv;
+    FILE *configfp = NULL;
+    char *configname = NULL;
+    unsigned configlineno;
+    int parse_debug = 0;
+    int default_config =1;
+    int greeting = 0;
+    int nogreeting = 0;
+    int action = 0;
+
+    set_strusage( my_strusage );
+    /*log_set_name ("gpa"); not yet implemented in logging.c */
+
+    opt.homedir = getenv("GNUPGHOME");
+    if( !opt.homedir || !*opt.homedir ) {
+      #ifdef HAVE_DRIVE_LETTERS
+       opt.homedir = "c:/gnupg";
+      #else
+       opt.homedir = "~/.gnupg";
+      #endif
+    }
+
+    /* check whether we have a config file on the commandline */
+    orig_argc = argc;
+    orig_argv = argv;
+    pargs.argc = &argc;
+    pargs.argv = &argv;
+    pargs.flags= 1|(1<<6);  /* do not remove the args, ignore version */
+    while( arg_parse( &pargs, opts) ) {
+       if( pargs.r_opt == oDebug || pargs.r_opt == oDebugAll )
+           parse_debug++;
+       else if( pargs.r_opt == oOptions ) {
+           /* yes there is one, so we do not try the default one, but
+            * read the option file when it is encountered at the commandline
+            */
+           default_config = 0;
+       }
+       else if( pargs.r_opt == oNoOptions )
+           default_config = 0; /* --no-options */
+       else if( pargs.r_opt == oHomedir )
+           opt.homedir = pargs.r.ret_str;
+    }
+
+    if( default_config )
+       configname = make_filename(opt.homedir, "gpgme.conf", NULL );
+
+
+    argc = orig_argc;
+    argv = orig_argv;
+    pargs.argc = &argc;
+    pargs.argv = &argv;
+    pargs.flags=  1 | (1<<5);  /* do not remove the args, allow one dash */
+  next_pass:
+    if( configname ) {
+       configlineno = 0;
+       configfp = fopen( configname, "r" );
+       if( !configfp ) {
+           if( default_config ) {
+               if( parse_debug )
+                   log_info(_("NOTE: no default option file `%s'\n"),
+                                                           configname );
+           }
+           else {
+               log_error(_("option file `%s': %s\n"),
+                                   configname, strerror(errno) );
+               exit(2);
+           }
+           free(configname); configname = NULL;
+       }
+       if( parse_debug && configname )
+           log_info(_("reading options from `%s'\n"), configname );
+       default_config = 0;
+    }
+
+    while( optfile_parse( configfp, configname, &configlineno,
+                                               &pargs, opts) ) {
+       switch( pargs.r_opt ) {
+         case oQuiet: opt.quiet = 1; break;
+         case oVerbose: opt.verbose++; break;
+
+         case oDebug: opt.debug |= pargs.r.ret_ulong; break;
+         case oDebugAll: opt.debug = ~0; break;
+
+         case oOptions:
+           /* config files may not be nested (silently ignore them) */
+           if( !configfp ) {
+               free(configname);
+               configname = xstrdup(pargs.r.ret_str);
+               goto next_pass;
+           }
+           break;
+         case oNoGreeting: nogreeting = 1; break;
+         case oNoVerbose: opt.verbose = 0; break;
+         case oNoOptions: break; /* no-options */
+         case oHomedir: opt.homedir = pargs.r.ret_str; break;
+         case oGPGBinary:  break;
+
+          case oRegServer: action = 1; break;
+          case oUnregServer: action = 2; break;
+          case oEmbedding: action = 3; break;
+
+         default : pargs.err = configfp? 1:2; break;
+       }
+    }
+    if( configfp ) {
+       fclose( configfp );
+       configfp = NULL;
+       free(configname); configname = NULL;
+       goto next_pass;
+    }
+    free( configname ); configname = NULL;
+    if( log_get_errorcount(0) )
+       exit(2);
+    if( nogreeting )
+       greeting = 0;
+
+    if( greeting ) {
+       fprintf(stderr, "%s %s; %s\n",
+                       strusage(11), strusage(13), strusage(14) );
+       fprintf(stderr, "%s\n", strusage(15) );
+    }
+  #ifdef IS_DEVELOPMENT_VERSION
+    log_info("NOTE: this is a development version!\n");
+  #endif
+
+    if ( action == 1 )
+        register_server ();
+    else if (action == 2 )
+        unregister_server ();
+    else if (action == 3 )
+        enter_complus ();
+    else {
+        fprintf (stderr, "This is a COM+ component with no user interface.\n"
+                 "gpgme --help will give you a list of options\n" );
+        exit (1);
+    }
+
+    return 0;
+}
+
+static void
+register_server ()
+{
+}
+
+static void
+unregister_server ()
+{
+}
+
+static void
+enter_complus ()
+{
+    HANDLE running;
+    int reg;
+    void *factory;
+
+    /* CoInitializeEx (NULL, COINIT_MULTITHREADED); */
+    running = CreateEvent (NULL, FALSE, FALSE, NULL );
+
+  #if 0
+    factory = create_class_factory ();
+    CoRegisterClassObject (CLSID_gpgme, factory, 
+                           CLSCTX_LOCAL_SERVER,
+                           REGCLS_SUSPENDED|REGCLASS_MULTIPLEUSE, &reg );
+    CoResumeClassObjects ();
+  #endif
+
+    WaitForSingleObject ( running, INFINITE );
+    CloseHandle (running);
+  #if 0
+    CoRevokeClassObject ( reg );
+    factory->release ();
+    CoUnitialize (); 
+  #endif
+}
+
+
+
+
+
+
diff --git a/complus/main.h b/complus/main.h
new file mode 100644 (file)
index 0000000..9c48c7b
--- /dev/null
@@ -0,0 +1,50 @@
+/* main.h -  GPGME COM+ component
+ *     Copyright (C) 2000 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
+ */
+
+#ifndef COMPLUS_MAIN_H
+#define COMPLUS_MAIN_H
+
+#include "xmalloc.h"
+#include "stringhelp.h"
+#include "logging.h"
+
+
+#define _(a) (a)
+#define N_(a) (a)
+
+
+struct {
+    int verbose;
+    int quiet;
+    unsigned int debug;
+    char *homedir;
+} opt;
+
+
+
+
+#endif /* COMPLUS_MAIN_H */
+
+
+
+
+
+
+
index c1fde71..ec98903 100644 (file)
@@ -13,10 +13,10 @@ AM_MAINTAINER_MODE
 #    AGE, set REVISION to 0.
 # 3. Interfaces removed (BAD, breaks upward compatibility): Increment
 #    CURRENT, set AGE and REVISION to 0.
-AM_INIT_AUTOMAKE(gpgme,0.1.0)
+AM_INIT_AUTOMAKE(gpgme,0.1.1)
 LIBGPGME_LT_CURRENT=0
 LIBGPGME_LT_AGE=0
-LIBGPGME_LT_REVISION=2
+LIBGPGME_LT_REVISION=3
 ##############################################
 
 AC_SUBST(LIBGPGME_LT_CURRENT)
@@ -38,6 +38,7 @@ if test "$GCC" = yes; then
 fi
 
 GPG=
+component_system=None
 case "${target}" in
     *-*-mingw32* | i?86-emx-os2 | i?86-*-os2*emx | i?86-*-msdosdjgpp* )
         # special stuff for Windoze NT
@@ -46,6 +47,7 @@ case "${target}" in
         AC_DEFINE(HAVE_DRIVE_LETTERS)
         AC_DEFINE(HAVE_DOSISH_SYSTEM)
         GPG='c:\\gnupg\\gpg.exe'
+        component_system='COM+'
         ;;
     *)
        ;;
@@ -63,9 +65,27 @@ dnl Checks for header files
 dnl
 
 
+
 dnl
 dnl Checks for typedefs and structures
 dnl
+GNUPG_CHECK_TYPEDEF(byte, HAVE_BYTE_TYPEDEF)
+GNUPG_CHECK_TYPEDEF(ushort, HAVE_USHORT_TYPEDEF)
+GNUPG_CHECK_TYPEDEF(ulong, HAVE_ULONG_TYPEDEF)
+GNUPG_CHECK_TYPEDEF(u16, HAVE_U16_TYPEDEF)
+GNUPG_CHECK_TYPEDEF(u32, HAVE_U32_TYPEDEF)
+# We should not use them in this software;
+# However jnlib/types.h needs them - so we take the easy way.
+AC_CHECK_SIZEOF(unsigned short, 2)
+AC_CHECK_SIZEOF(unsigned int, 4)
+AC_CHECK_SIZEOF(unsigned long, 4)
+if test "$ac_cv_sizeof_unsigned_short" = "0" \
+   || test "$ac_cv_sizeof_unsigned_int" = "0" \
+   || test "$ac_cv_sizeof_unsigned_long" = "0"; then
+    AC_MSG_WARN([Hmmm, something is wrong with the sizes - using defaults]);
+fi
+
+
 
 dnl
 dnl Checks for compiler features
@@ -74,14 +94,15 @@ dnl
 dnl
 dnl Checks for library functions
 dnl
-AC_CHECK_FUNCS(stpcpy)
+dnl These are needed by libjnlib
+AC_CHECK_FUNCS(memicmp stpcpy strlwr strtoul memmove stricmp)
 
 
 dnl
 dnl Checks for system services
 dnl
 
-if test -z "GPG"; then
+if test -z "$GPG"; then
   AC_PATH_PROG(GPG, gpg)
   if test -z "$GPG"; then
        AC_MSG_ERROR([[
@@ -96,10 +117,18 @@ AC_DEFINE_UNQUOTED(GPG_PATH, "$GPG")
 
 
 dnl
+dnl FIXME: check whether Bonobo is installed
+dnl 
+
+
+dnl
 dnl Create config files 
 dnl
 dnl
 
+AM_CONDITIONAL(BUILD_COMPLUS, test "$component_system" = "COM+")
+AM_CONDITIONAL(BUILD_BONOBO,  test "$component_system" = "Bonobo")
+
 dnl Make the version number in gpgme/gpgme.h the same as the one here.
 dnl (this is easier than to have a *.in file just for one substitution)
 GNUPG_FIX_HDR_VERSION(gpgme/gpgme.h, GPGME_VERSION)
@@ -116,11 +145,20 @@ chmod +x gpgme/gpgme-config
 
 AC_OUTPUT([
 Makefile
+jnlib/Makefile
 gpgme/Makefile
 gpgme/gpgme-config
 tests/Makefile
+bonobo/Makefile
+complus/Makefile
 ])
 
+echo "
+       GPGME v${VERSION} has been configured as follows:
+
+       GPG path:   $GPG
+       Component:  $component_system
+"
 
 
 
index e888aa8..324245a 100644 (file)
@@ -56,9 +56,6 @@ struct gpgme_context_s {
     int use_armor;  
     int use_textmode;
 
-    /*   GpgmePassphraseCb passphrase_cb;*/
-    /* void *            passphrase_cb_value;*/
-    
     ResultType result_type;
     union {
         VerifyResult verify;
@@ -71,6 +68,8 @@ struct gpgme_context_s {
     GpgmeKey tmp_key;       /* used by keylist.c */
     volatile int key_cond;  /* something new is available */
     struct key_queue_item_s *key_queue;
+
+    char *prompt_1;
 };
 
 
@@ -79,6 +78,11 @@ struct gpgme_data_s {
     const char *data;
     GpgmeDataType type;
     GpgmeDataMode mode;
+
+    int (*read_cb)( void *, char *, size_t, size_t *);
+    void *read_cb_value;
+    int read_cb_eof;
+
     size_t readpos;
     size_t writepos;
     size_t private_len;
index dc6117f..94438f6 100644 (file)
@@ -113,6 +113,30 @@ gpgme_data_new_from_mem ( GpgmeData *r_dh,
     return 0;
 }
 
+
+GpgmeError
+gpgme_data_new_with_read_cb ( GpgmeData *r_dh,
+                              int (*read_cb)(void*,char *,size_t,size_t*),
+                              void *read_cb_value )
+{
+    GpgmeData dh;
+    GpgmeError err;
+
+    if (!r_dh || !read_cb)
+        return mk_error (Invalid_Value);
+    *r_dh = NULL;
+    err = gpgme_data_new ( &dh );
+    if (err)
+        return err;
+    dh->type = GPGME_DATA_TYPE_CB;
+    dh->mode = GPGME_DATA_MODE_OUT;
+    dh->read_cb = read_cb;
+    dh->read_cb_value = read_cb_value;
+    
+    *r_dh = dh;
+    return 0;
+}
+
 /**
  * gpgme_data_new_from_file:
  * @r_dh: returns the new data object
@@ -279,7 +303,7 @@ gpgme_data_release_and_get_mem ( GpgmeData dh, size_t *r_len )
 GpgmeDataType
 gpgme_data_get_type ( GpgmeData dh )
 {
-    if ( !dh || !dh->data )
+    if ( !dh || (!dh->data && !dh->read_cb))
         return GPGME_DATA_TYPE_NONE;
             
     return dh->type;
@@ -315,9 +339,18 @@ gpgme_data_rewind ( GpgmeData dh )
 {
     if ( !dh )
         return mk_error (Invalid_Value);
-    /* Fixme: We should check whether rewinding does make sense for the
-     * data type */
-    dh->readpos = 0;
+
+    if (dh->type == GPGME_DATA_TYPE_MEM ) {
+        dh->readpos = 0;
+    }
+    else if (dh->type == GPGME_DATA_TYPE_CB) {
+        dh->len = dh->readpos = 0;
+        dh->read_cb_eof = 0;
+        /* FIXME: do a special call to the read function to trigger a rewind
+           there */
+    }
+    else
+        return mk_error (General_Error);
     return 0;
 }
 
@@ -334,7 +367,7 @@ gpgme_data_rewind ( GpgmeData dh )
  * If there are no more bytes available %GPGME_EOF is returned and @nread
  * is set to 0.
  * 
- * Return value: An errocodee or 0 on success, EOF is indcated by the
+ * Return value: An errorcode or 0 on success, EOF is indcated by the
  * error code GPGME_EOF.
  **/
 GpgmeError
@@ -344,19 +377,66 @@ gpgme_data_read ( GpgmeData dh, char *buffer, size_t length, size_t *nread )
 
     if ( !dh )
         return mk_error (Invalid_Value);
-    nbytes = dh->len - dh->readpos;
-    if ( !nbytes ) {
-        *nread = 0;
-        return mk_error(EOF);
+    if (dh->type == GPGME_DATA_TYPE_MEM ) {
+        nbytes = dh->len - dh->readpos;
+        if ( !nbytes ) {
+            *nread = 0;
+            return mk_error(EOF);
+        }
+        if (nbytes > length)
+            nbytes = length;
+        memcpy ( buffer, dh->data + dh->readpos, nbytes );
+        *nread = nbytes;
+        dh->readpos += nbytes;
+    }
+    else if (dh->type == GPGME_DATA_TYPE_CB) {
+        nbytes = dh->len - dh->readpos;
+        if ( nbytes ) {
+            /* we have unread data - return this */
+            if (nbytes > length)
+                nbytes = length;
+            memcpy ( buffer, dh->data + dh->readpos, nbytes );
+            *nread = nbytes;
+            dh->readpos += nbytes;
+        }
+        else { /* get the data from the callback */
+            if (!dh->read_cb || dh->read_cb_eof) { 
+                *nread = 0;
+                return mk_error (EOF);
+            }
+            if (dh->read_cb (dh->read_cb_value, buffer, length, nread )) {
+                *nread = 0;
+                dh->read_cb_eof = 1;
+                return mk_error (EOF);
+            }
+        }
     }
-    if (nbytes > length)
-        nbytes = length;
-    memcpy ( buffer, dh->data + dh->readpos, nbytes );
-    *nread = nbytes;
-    dh->readpos += nbytes;
+    else
+        return mk_error (General_Error);
     return 0;
 } 
 
+GpgmeError
+_gpgme_data_unread (GpgmeData dh, const char *buffer, size_t length )
+{
+   if ( !dh )
+        return mk_error (Invalid_Value);
+
+   if (dh->type == GPGME_DATA_TYPE_MEM ) {
+       /* check that we don't unread more than we have yet read */
+       if ( dh->readpos < length )
+           return mk_error (Invalid_Value);
+       /* No need to use the buffer for this data type */
+       dh->readpos -= length;
+   }
+   else {
+       return mk_error (General_Error);
+   }
+
+   return 0;
+}
+
+
 /* 
  * This function does make sense when we know that it contains no nil chars.
  */
index 017cbf9..0a2545f 100644 (file)
@@ -33,6 +33,7 @@ struct decrypt_result_s {
     int no_passphrase;
     int okay;
     int failed;
+
 };
 
 
@@ -43,6 +44,17 @@ _gpgme_release_decrypt_result ( DecryptResult res )
 }
 
 
+static GpgmeError
+create_result_struct ( GpgmeCtx ctx )
+{
+    assert ( !ctx->result.decrypt );
+    ctx->result.decrypt = xtrycalloc ( 1, sizeof *ctx->result.decrypt );
+    if ( !ctx->result.decrypt ) {
+        return mk_error (Out_Of_Core);
+    }
+    ctx->result_type = RESULT_TYPE_DECRYPT;
+    return 0;    
+}
 
 static void
 decrypt_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args )
@@ -50,13 +62,10 @@ decrypt_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args )
     if ( ctx->out_of_core )
         return;
     if ( ctx->result_type == RESULT_TYPE_NONE ) {
-        assert ( !ctx->result.decrypt );
-        ctx->result.decrypt = xtrycalloc ( 1, sizeof *ctx->result.decrypt );
-        if ( !ctx->result.decrypt ) {
+        if ( create_result_struct ( ctx ) ) {
             ctx->out_of_core = 1;
             return;
         }
-        ctx->result_type = RESULT_TYPE_DECRYPT;
     }
     assert ( ctx->result_type == RESULT_TYPE_DECRYPT );
 
@@ -66,7 +75,9 @@ decrypt_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args )
 
       case STATUS_NEED_PASSPHRASE:
       case STATUS_NEED_PASSPHRASE_SYM:
-        fprintf (stderr, "Ooops: Need a passphrase -  use the agent\n");
+        fprintf (stderr, "need a passphrase ...\n" );
+        _gpgme_set_prompt (ctx, 1, "Hey! We need your passphrase!");
+        /* next thing gpg has to do is to read it from the passphrase-fd */
         break;
 
       case STATUS_MISSING_PASSPHRASE:
@@ -91,9 +102,9 @@ decrypt_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args )
 }
 
 
-
 GpgmeError
-gpgme_op_decrypt_start ( GpgmeCtx c, GpgmeData ciph, GpgmeData plain )
+gpgme_op_decrypt_start ( GpgmeCtx c, GpgmeData passphrase,
+                         GpgmeData ciph, GpgmeData plain   )
 {
     int rc = 0;
     int i;
@@ -118,14 +129,19 @@ gpgme_op_decrypt_start ( GpgmeCtx c, GpgmeData ciph, GpgmeData plain )
     _gpgme_gpg_add_arg ( c->gpg, "--decrypt" );
     for ( i=0; i < c->verbosity; i++ )
         _gpgme_gpg_add_arg ( c->gpg, "--verbose" );
-    
+    if (passphrase) {
+        _gpgme_gpg_add_arg (c->gpg, "--passphrase-fd" );
+        _gpgme_gpg_add_data (c->gpg, passphrase, -2 );
+    }
+
+
     /* Check the supplied data */
     if ( !ciph || gpgme_data_get_type (ciph) == GPGME_DATA_TYPE_NONE ) {
         rc = mk_error (No_Data);
         goto leave;
     }
-
     _gpgme_data_set_mode (ciph, GPGME_DATA_MODE_OUT );
+
     if ( gpgme_data_get_type (plain) != GPGME_DATA_TYPE_NONE ) {
         rc = mk_error (Invalid_Value);
         goto leave;
@@ -153,6 +169,7 @@ gpgme_op_decrypt_start ( GpgmeCtx c, GpgmeData ciph, GpgmeData plain )
 /**
  * gpgme_op_decrypt:
  * @c: The context
+ * @passphrase: A data object with the passphrase or NULL.
  * @in: ciphertext input
  * @out: plaintext output
  * 
@@ -163,9 +180,10 @@ gpgme_op_decrypt_start ( GpgmeCtx c, GpgmeData ciph, GpgmeData plain )
  * Return value:  0 on success or an errorcode. 
  **/
 GpgmeError
-gpgme_op_decrypt ( GpgmeCtx c, GpgmeData in, GpgmeData out )
+gpgme_op_decrypt ( GpgmeCtx c, GpgmeData passphrase,
+                   GpgmeData in, GpgmeData out )
 {
-    GpgmeError err = gpgme_op_decrypt_start ( c, in, out );
+    GpgmeError err = gpgme_op_decrypt_start ( c, passphrase, in, out );
     if ( !err ) {
         gpgme_wait (c, 1);
         if ( c->result_type != RESULT_TYPE_DECRYPT )
diff --git a/gpgme/errors.c b/gpgme/errors.c
new file mode 100644 (file)
index 0000000..4445d17
--- /dev/null
@@ -0,0 +1,49 @@
+/* Generated automatically by mkerrors */
+/* Do not edit! */
+
+#include <stdio.h>
+#include "gpgme.h"
+
+/**
+ * gpgme_strerror:
+ * @err:  Error code 
+ * 
+ * This function returns a textual representaion of the given
+ * errocode. If this is an unknown value, a string with the value
+ * is returned (which is hold in a static buffer).
+ * 
+ * Return value: String with the error description.
+ **/
+const char *
+gpgme_strerror (GpgmeError err)
+{
+    const char *s;
+    static char buf[25];
+
+    switch (err) {
+  case GPGME_No_Error: s="No Error"; break;
+  case GPGME_General_Error: s="General Error"; break;
+  case GPGME_Out_Of_Core: s="Out Of Core"; break;
+  case GPGME_Invalid_Value: s="Invalid Value"; break;
+  case GPGME_Busy: s="Busy"; break;
+  case GPGME_No_Request: s="No Request"; break;
+  case GPGME_Exec_Error: s="Exec Error"; break;
+  case GPGME_Too_Many_Procs: s="Too Many Procs"; break;
+  case GPGME_Pipe_Error: s="Pipe Error"; break;
+  case GPGME_No_Recipients: s="No Recipients"; break;
+  case GPGME_No_Data: s="No Data"; break;
+  case GPGME_Conflict: s="Conflict"; break;
+  case GPGME_Not_Implemented: s="Not Implemented"; break;
+  case GPGME_Read_Error: s="Read Error"; break;
+  case GPGME_Write_Error: s="Write Error"; break;
+  case GPGME_Invalid_Type: s="Invalid Type"; break;
+  case GPGME_Invalid_Mode: s="Invalid Mode"; break;
+  case GPGME_File_Error: s="File Error"; break;
+  case GPGME_Decryption_Failed: s="Decryption Failed"; break;
+  case GPGME_No_Passphrase: s="No Passphrase"; break;
+    default:  sprintf (buf, "ec=%d", err ); s=buf; break;
+}
+
+return s;
+}
+
index 9a6d7b5..d6b189c 100644 (file)
@@ -21,6 +21,7 @@
 #include <config.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <assert.h>
 
 #include "util.h"
 #include "context.h"
@@ -69,7 +70,8 @@ gpgme_release ( GpgmeCtx c )
     _gpgme_key_release ( c->tmp_key );
     gpgme_data_release ( c->notation );
     /* fixme: release the key_queue */
-    xfree ( c );
+    xfree (c->prompt_1);
+    xfree (c);
 }
 
 
@@ -145,16 +147,31 @@ gpgme_set_textmode ( GpgmeCtx c, int yes )
     c->use_textmode = yes;
 }
 
-#if 0
+/* 
+ * The only which currently allowed is 1
+ */
 void
-gpgme_set_passphrase_cb ( GpgmeCtx c, GpgmePassphraseCb fnc, void *fncval )
+_gpgme_set_prompt ( GpgmeCtx c, int which, const char *text )
 {
-    if ( c ) {
-        c->passphrase_cb = fnc;
-        c->passphrase_cb_value = fncval;
+    assert ( which == 1 );
+
+    xfree (c->prompt_1); c->prompt_1 = NULL;
+    if (text) {
+        c->prompt_1 = xtrystrdup (text);
+        if ( !c->prompt_1 )
+            c->out_of_core = 1;
     }
 }
-#endif
+
+const char *
+gpgme_get_prompt ( GpgmeCtx c, int which )
+{
+    if ( which != 1 )
+        return NULL;
+    return c->prompt_1;
+}
+
+
 
 
 
index 692362b..b9509cc 100644 (file)
@@ -34,7 +34,7 @@ extern "C" {
  * let autoconf (using the AM_PATH_GPGME macro) check that this
  * header matches the installed library.
  * Warning: Do not edit the next line.  configure will do that for you! */
-#define GPGME_VERSION "0.1.0"
+#define GPGME_VERSION "0.1.1"
 
 
 
@@ -79,7 +79,8 @@ typedef enum {
     GPGME_DATA_TYPE_NONE = 0,
     GPGME_DATA_TYPE_MEM  = 1,
     GPGME_DATA_TYPE_FD   = 2,
-    GPGME_DATA_TYPE_FILE = 3
+    GPGME_DATA_TYPE_FILE = 3,
+    GPGME_DATA_TYPE_CB   = 4
 } GpgmeDataType;
 
 typedef enum {
@@ -91,8 +92,6 @@ typedef enum {
     GPGME_SIG_STAT_ERROR = 5
 } GpgmeSigStat;
 
-/*typedef GpgmeData (*GpgmePassphraseCb)( void *opaque, const char *desc );*/
-
 
 /* Context management */
 GpgmeError gpgme_new (GpgmeCtx *r_ctx);
@@ -102,8 +101,7 @@ GpgmeCtx   gpgme_wait ( GpgmeCtx c, int hang );
 char *gpgme_get_notation ( GpgmeCtx c );
 void gpgme_set_armor ( GpgmeCtx c, int yes );
 void gpgme_set_textmode ( GpgmeCtx c, int yes );
-/*void gpgme_set_passphrase_cb ( GpgmeCtx c,
-  GpgmePassphraseCb fnc, void *fncval );*/
+
 
 
 /* Functions to handle recipients */
@@ -118,6 +116,10 @@ GpgmeError    gpgme_data_new ( GpgmeData *r_dh );
 GpgmeError    gpgme_data_new_from_mem ( GpgmeData *r_dh,
                                         const char *buffer, size_t size,
                                         int copy );
+GpgmeError    gpgme_data_new_with_read_cb ( GpgmeData *r_dh,
+                              int (*read_cb)(void*,char *,size_t,size_t*),
+                              void *read_cb_value );
+
 GpgmeError    gpgme_data_new_from_file ( GpgmeData *r_dh,
                                          const char *fname,
                                          int copy );
@@ -136,7 +138,7 @@ char *gpgme_key_get_as_xml ( GpgmeKey key );
 GpgmeError gpgme_op_encrypt_start ( GpgmeCtx c,
                                     GpgmeRecipients recp,
                                     GpgmeData in, GpgmeData out );
-GpgmeError gpgme_op_decrypt_start ( GpgmeCtx c,
+GpgmeError gpgme_op_decrypt_start ( GpgmeCtx c, GpgmeData passphrase,
                                     GpgmeData ciph, GpgmeData plain );
 GpgmeError gpgme_op_sign_start ( GpgmeCtx c, GpgmeData in, GpgmeData out );
 GpgmeError gpgme_op_verify_start ( GpgmeCtx c,
@@ -152,7 +154,8 @@ GpgmeError gpgme_op_keylist_next ( GpgmeCtx c, GpgmeKey *r_key );
 /* Convenience functions for normal usage */
 GpgmeError gpgme_op_encrypt ( GpgmeCtx c, GpgmeRecipients recp,
                               GpgmeData in, GpgmeData out );
-GpgmeError gpgme_op_decrypt ( GpgmeCtx c, GpgmeData in, GpgmeData out );
+GpgmeError gpgme_op_decrypt ( GpgmeCtx c, GpgmeData passphrase,
+                              GpgmeData in, GpgmeData out );
 GpgmeError gpgme_op_sign ( GpgmeCtx c, GpgmeData in, GpgmeData out );
 GpgmeError gpgme_op_verify ( GpgmeCtx c, GpgmeData sig, GpgmeData text,
                              GpgmeSigStat *r_status );
@@ -161,6 +164,7 @@ GpgmeError gpgme_op_verify ( GpgmeCtx c, GpgmeData sig, GpgmeData text,
 /* miscellaneous functions */
 const char *gpgme_check_version ( const char *req_version );
 const char *gpgme_strerror (GpgmeError err);
+const char *gpgme_get_prompt ( GpgmeCtx c, int which );
 
 
 #ifdef __cplusplus
index 41ea160..0ae58a2 100644 (file)
@@ -31,6 +31,7 @@ struct spawn_fd_item_s {
 
 struct io_select_fd_s {
     int fd;
+    int is_closed;
     int for_read;
     int for_write;
     int signaled;
@@ -42,7 +43,7 @@ struct io_select_fd_s {
 
 int _gpgme_io_read ( int fd, void *buffer, size_t count );
 int _gpgme_io_write ( int fd, const void *buffer, size_t count );
-int _gpgme_io_pipe ( int filedes[2] );
+int _gpgme_io_pipe ( int filedes[2], int inherit_idx );
 int _gpgme_io_close ( int fd );
 int _gpgme_io_set_nonblocking ( int fd );
 int _gpgme_io_spawn ( const char *path, char **argv,
index 9de6d24..ba382a9 100644 (file)
@@ -25,6 +25,7 @@
 
 /*-- gpgme.c --*/
 void _gpgme_release_result ( GpgmeCtx c );
+void _gpgme_set_prompt ( GpgmeCtx c, int which, const char *text );
 
 /*-- wait.c --*/
 GpgmeCtx _gpgme_wait_on_condition ( GpgmeCtx c,
@@ -53,6 +54,9 @@ GpgmeError    _gpgme_data_append_for_xml ( GpgmeData dh,
 GpgmeError    _gpgme_data_append_percentstring_for_xml ( GpgmeData dh,
                                                          const char *string );
 
+GpgmeError    _gpgme_data_unread (GpgmeData dh,
+                                  const char *buffer, size_t length );
+
 
 /*-- key.c --*/
 GpgmeError _gpgme_key_new( GpgmeKey *r_key );
index 098a83e..dede3f9 100644 (file)
@@ -68,8 +68,9 @@ _gpgme_io_write ( int fd, const void *buffer, size_t count )
 }
 
 int
-_gpgme_io_pipe ( int filedes[2] )
+_gpgme_io_pipe ( int filedes[2], int inherit_idx )
 {
+    /* we don't need inherit_idx in this implementation */
     return pipe ( filedes );
 }
 
index b7a3943..1a8f6ae 100644 (file)
 
 #include "status-table.h"
 
+
 /* This type is used to build a list of gpg arguments and
  * data sources/sinks */
 struct arg_and_data_s {
     struct arg_and_data_s *next;
     GpgmeData data;  /* If this is not NULL .. */
     int dup_to;
+    int print_fd;    /* print the fd number and not the special form of it */
     char arg[1];     /* .. this is used */
 };
 
@@ -137,7 +139,7 @@ _gpgme_gpg_new ( GpgObject *r_gpg )
     }
     /* In any case we need a status pipe - create it right here  and
      * don't handle it with our generic GpgmeData mechanism */
-    if (_gpgme_io_pipe (gpg->status.fd) == -1) {
+    if (_gpgme_io_pipe (gpg->status.fd, 1) == -1) {
         rc = mk_error (Pipe_Error);
         goto leave;
     }
@@ -151,6 +153,7 @@ _gpgme_gpg_new ( GpgObject *r_gpg )
     _gpgme_gpg_add_arg ( gpg, "--batch" );
     _gpgme_gpg_add_arg ( gpg, "--no-tty" );
 
+
  leave:
     if (rc) {
         _gpgme_gpg_release (gpg);
@@ -170,6 +173,11 @@ _gpgme_gpg_release ( GpgObject gpg )
     xfree (gpg->colon.buffer);
     if ( gpg->argv )
         free_argv (gpg->argv);
+  #if 0
+    /* fixme: We need a way to communicate back closed fds, so that we
+     * don't do it a second time.  One way to do it is by using a global
+     * table of open fds associated with gpg objects - but this requires
+     * additional locking. */
     if (gpg->status.fd[0] != -1 )
         _gpgme_io_close (gpg->status.fd[0]);
     if (gpg->status.fd[1] != -1 )
@@ -178,6 +186,7 @@ _gpgme_gpg_release ( GpgObject gpg )
         _gpgme_io_close (gpg->colon.fd[0]);
     if (gpg->colon.fd[1] != -1 )
         _gpgme_io_close (gpg->colon.fd[1]);
+  #endif
     free_fd_data_map (gpg->fd_data_map);
     kill_gpg (gpg); /* fixme: should be done asyncronously */
     xfree (gpg);
@@ -237,7 +246,14 @@ _gpgme_gpg_add_data ( GpgObject gpg, GpgmeData data, int dup_to )
     }
     a->next = NULL;
     a->data = data;
-    a->dup_to = dup_to;
+    if ( dup_to == -2 ) {
+        a->print_fd = 1;
+        a->dup_to = -1;
+    }
+    else {
+        a->print_fd = 0;
+        a->dup_to = dup_to;
+    }
     *gpg->argtail = a;
     gpg->argtail = &a->next;
     return 0;
@@ -268,7 +284,7 @@ _gpgme_gpg_set_colon_line_handler ( GpgObject gpg,
     if (!gpg->colon.buffer) {
         return mk_error (Out_Of_Core);
     }
-    if (_gpgme_io_pipe (gpg->colon.fd) == -1) {
+    if (_gpgme_io_pipe (gpg->colon.fd, 1) == -1) {
         xfree (gpg->colon.buffer); gpg->colon.buffer = NULL;
         return mk_error (Pipe_Error);
     }
@@ -294,11 +310,16 @@ free_fd_data_map ( struct fd_data_map_s *fd_data_map )
 {
     int i;
 
+    if ( !fd_data_map )
+        return;
+
     for (i=0; fd_data_map[i].data; i++ ) {
+#if 0 /* fixme -> see gpg_release */
         if ( fd_data_map[i].fd != -1 )
             _gpgme_io_close (fd_data_map[i].fd);
         if ( fd_data_map[i].peer_fd != -1 )
             _gpgme_io_close (fd_data_map[i].peer_fd);
+#endif
         /* don't realease data because this is only a reference */
     }
     xfree (fd_data_map);
@@ -330,7 +351,7 @@ build_argv ( GpgObject gpg )
         if (a->data) {
             /*fprintf (stderr, "build_argv: data\n" );*/
             datac++;
-            if ( a->dup_to == -1 )
+            if ( a->dup_to == -1 && !a->print_fd )
                 need_special = 1;
         }
         else {
@@ -403,6 +424,7 @@ build_argv ( GpgObject gpg )
                 free_argv (argv);
                 return mk_error (Invalid_Type);
               case GPGME_DATA_TYPE_MEM:
+              case GPGME_DATA_TYPE_CB:
                 break;
               case GPGME_DATA_TYPE_FD:
               case GPGME_DATA_TYPE_FILE:
@@ -415,7 +437,8 @@ build_argv ( GpgObject gpg )
             {   
                 int fds[2];
                 
-                if (_gpgme_io_pipe (fds) == -1) {
+                if (_gpgme_io_pipe (fds, fd_data_map[datac].inbound?1:0 )
+                    == -1) {
                     xfree (fd_data_map);
                     free_argv (argv);
                     return mk_error (Pipe_Error);
@@ -439,7 +462,9 @@ build_argv ( GpgObject gpg )
                     free_argv (argv);
                     return mk_error (Out_Of_Core);
                 }
-                sprintf ( argv[argc], "-&%d", fd_data_map[datac].peer_fd );
+                sprintf ( argv[argc], 
+                          a->print_fd? "%d" : "-&%d",
+                          fd_data_map[datac].peer_fd );
                 argc++;
             }
             datac++;
@@ -490,7 +515,7 @@ _gpgme_gpg_spawn( GpgObject gpg, void *opaque )
 
     /* build the fd list for the child */
     n=0;
-    fd_child_list[n].fd = gpg->status.fd[0];
+    fd_child_list[n].fd = gpg->status.fd[0]; 
     fd_child_list[n].dup_to = -1;
     n++;
     if ( gpg->colon.fnc ) {
@@ -538,7 +563,6 @@ _gpgme_gpg_spawn( GpgObject gpg, void *opaque )
     fd_parent_list[n].dup_to = -1;
 
 
-    fflush (stderr);
     pid = _gpgme_io_spawn (GPG_PATH, gpg->argv, fd_child_list, fd_parent_list);
     xfree (fd_child_list);
     if (pid == -1) {
@@ -604,7 +628,6 @@ gpg_inbound_handler ( void *opaque, int pid, int fd )
     assert ( _gpgme_data_get_mode (dh) == GPGME_DATA_MODE_IN );
 
     nread = _gpgme_io_read (fd, buf, 200 );
-    fprintf(stderr, "inbound on fd %d: nread=%d\n", fd, nread );
     if ( nread < 0 ) {
         fprintf (stderr, "read_mem_data: read failed on fd %d (n=%d): %s\n",
                  fd, nread, strerror (errno) );
@@ -638,7 +661,6 @@ write_mem_data ( GpgmeData dh, int fd )
 
     nbytes = dh->len - dh->readpos;
     if ( !nbytes ) {
-        fprintf (stderr, "write_mem_data(%d): closing\n", fd );
         _gpgme_io_close (fd);
         return 1;
     }
@@ -650,11 +672,7 @@ write_mem_data ( GpgmeData dh, int fd )
      * To avoid that we have set the pipe to nonblocking.
      */
 
-
-    fprintf (stderr, "write_mem_data(%d): about to write %d bytes len=%d rpos=%d\n",
-                 fd, (int)nbytes, (int)dh->len, dh->readpos );
     nwritten = _gpgme_io_write ( fd, dh->data+dh->readpos, nbytes );
-    fprintf (stderr, "write_mem_data(%d): wrote %d bytes\n", fd, nwritten );
     if (nwritten == -1 && errno == EAGAIN )
         return 0;
     if ( nwritten < 1 ) {
@@ -668,6 +686,40 @@ write_mem_data ( GpgmeData dh, int fd )
     return 0;
 }
 
+static int
+write_cb_data ( GpgmeData dh, int fd )
+{
+    size_t nbytes;
+    int  err, nwritten; 
+    char buffer[512];
+
+    err = gpgme_data_read ( dh, buffer, DIM(buffer), &nbytes );
+    if (err == GPGME_EOF) {
+        _gpgme_io_close (fd);
+        return 1;
+    }
+    
+    nwritten = _gpgme_io_write ( fd, dh->data+dh->readpos, nbytes );
+    if (nwritten == -1 && errno == EAGAIN )
+        return 0;
+    if ( nwritten < 1 ) {
+        fprintf (stderr, "write_cb_data(%d): write failed (n=%d): %s\n",
+                 fd, nwritten, strerror (errno) );
+        _gpgme_io_close (fd);
+        return 1;
+    }
+
+    if ( nwritten < nbytes ) {
+        if ( _gpgme_data_unread (dh, buffer + nwritten, nbytes - nwritten ) )
+            fprintf (stderr, "wite_cb_data: unread of %d bytes failed\n",
+                     nbytes - nwritten );
+        _gpgme_io_close (fd);
+        return 1;
+    }
+
+    return 0;
+}
+
 
 static int
 gpg_outbound_handler ( void *opaque, int pid, int fd )
@@ -680,11 +732,14 @@ gpg_outbound_handler ( void *opaque, int pid, int fd )
         if ( write_mem_data ( dh, fd ) )
             return 1; /* ready */
         break;
+      case GPGME_DATA_TYPE_CB:
+        if (write_cb_data (dh, fd))
+            return 1; /* ready */
+        break;
       default:
         assert (0);
     }
 
-
     return 0;
 }
 
diff --git a/gpgme/status-table.h b/gpgme/status-table.h
new file mode 100644 (file)
index 0000000..ce42710
--- /dev/null
@@ -0,0 +1,68 @@
+/* Generated automatically by mkstatus */
+/* Do not edit! */
+
+struct status_table_s {
+    const char *name;
+    GpgStatusCode code;
+};
+
+static struct status_table_s status_table[] = 
+{
+  { "ABORT", STATUS_ABORT },
+  { "BADARMOR", STATUS_BADARMOR },
+  { "BADMDC", STATUS_BADMDC },
+  { "BADSIG", STATUS_BADSIG },
+  { "BAD_PASSPHRASE", STATUS_BAD_PASSPHRASE },
+  { "BEGIN_DECRYPTION", STATUS_BEGIN_DECRYPTION },
+  { "BEGIN_ENCRYPTION", STATUS_BEGIN_ENCRYPTION },
+  { "DECRYPTION_FAILED", STATUS_DECRYPTION_FAILED },
+  { "DECRYPTION_OKAY", STATUS_DECRYPTION_OKAY },
+  { "DELETE_PROBLEM", STATUS_DELETE_PROBLEM },
+  { "ENC_TO", STATUS_ENC_TO },
+  { "END_DECRYPTION", STATUS_END_DECRYPTION },
+  { "END_ENCRYPTION", STATUS_END_ENCRYPTION },
+  { "ENTER", STATUS_ENTER },
+  { "ERRMDC", STATUS_ERRMDC },
+  { "ERRSIG", STATUS_ERRSIG },
+  { "FILE_DONE", STATUS_FILE_DONE },
+  { "FILE_ERROR", STATUS_FILE_ERROR },
+  { "FILE_START", STATUS_FILE_START },
+  { "GET_BOOL", STATUS_GET_BOOL },
+  { "GET_HIDDEN", STATUS_GET_HIDDEN },
+  { "GET_LINE", STATUS_GET_LINE },
+  { "GOODMDC", STATUS_GOODMDC },
+  { "GOODSIG", STATUS_GOODSIG },
+  { "GOOD_PASSPHRASE", STATUS_GOOD_PASSPHRASE },
+  { "GOT_IT", STATUS_GOT_IT },
+  { "IMPORTED", STATUS_IMPORTED },
+  { "IMPORT_RES", STATUS_IMPORT_RES },
+  { "KEYREVOKED", STATUS_KEYREVOKED },
+  { "LEAVE", STATUS_LEAVE },
+  { "MISSING_PASSPHRASE", STATUS_MISSING_PASSPHRASE },
+  { "NEED_PASSPHRASE", STATUS_NEED_PASSPHRASE },
+  { "NEED_PASSPHRASE_SYM,", STATUS_NEED_PASSPHRASE_SYM, },
+  { "NODATA", STATUS_NODATA },
+  { "NOTATION_DATA", STATUS_NOTATION_DATA },
+  { "NOTATION_NAME", STATUS_NOTATION_NAME },
+  { "NO_PUBKEY", STATUS_NO_PUBKEY },
+  { "NO_SECKEY", STATUS_NO_SECKEY },
+  { "POLICY_URL", STATUS_POLICY_URL },
+  { "PROGRESS", STATUS_PROGRESS },
+  { "RSA_OR_IDEA", STATUS_RSA_OR_IDEA },
+  { "SESSION_KEY", STATUS_SESSION_KEY },
+  { "SHM_GET", STATUS_SHM_GET },
+  { "SHM_GET_BOOL", STATUS_SHM_GET_BOOL },
+  { "SHM_GET_HIDDEN", STATUS_SHM_GET_HIDDEN },
+  { "SHM_INFO", STATUS_SHM_INFO },
+  { "SIGEXPIRED", STATUS_SIGEXPIRED },
+  { "SIG_CREATED", STATUS_SIG_CREATED },
+  { "SIG_ID", STATUS_SIG_ID },
+  { "TRUST_FULLY", STATUS_TRUST_FULLY },
+  { "TRUST_MARGINAL", STATUS_TRUST_MARGINAL },
+  { "TRUST_NEVER", STATUS_TRUST_NEVER },
+  { "TRUST_ULTIMATE", STATUS_TRUST_ULTIMATE },
+  { "TRUST_UNDEFINED", STATUS_TRUST_UNDEFINED },
+  { "VALIDSIG", STATUS_VALIDSIG },
+  {NULL, 0}
+};
+
index 3d97fd6..4c3e61b 100644 (file)
@@ -163,7 +163,6 @@ gpgme_op_verify_start ( GpgmeCtx c,  GpgmeData sig, GpgmeData text )
     _gpgme_gpg_add_arg ( c->gpg, "--verify" );
     for ( i=0; i < c->verbosity; i++ )
         _gpgme_gpg_add_arg ( c->gpg, "--verbose" );
-    
 
     /* Check the supplied data */
     if ( gpgme_data_get_type (sig) == GPGME_DATA_TYPE_NONE ) {
@@ -180,8 +179,10 @@ gpgme_op_verify_start ( GpgmeCtx c,  GpgmeData sig, GpgmeData text )
     /* Tell the gpg object about the data */
     _gpgme_gpg_add_arg ( c->gpg, "--" );
     _gpgme_gpg_add_data ( c->gpg, sig, -1 );
-    if (text)
+    if (text) {
+        _gpgme_gpg_add_arg ( c->gpg, "-" );
         _gpgme_gpg_add_data ( c->gpg, text, 0 );
+    }
 
     /* and kick off the process */
     rc = _gpgme_gpg_spawn ( c->gpg, c );
diff --git a/gpgme/version.c b/gpgme/version.c
new file mode 100644 (file)
index 0000000..0319b06
--- /dev/null
@@ -0,0 +1,104 @@
+/* version.c -  version check
+ *     Copyright (C) 2000 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 <ctype.h>
+
+#include "gpgme.h"
+
+static const char*
+parse_version_number ( const char *s, int *number )
+{
+    int val = 0;
+
+    if ( *s == '0' && isdigit(s[1]) )
+       return NULL; /* leading zeros are not allowed */
+    for ( ; isdigit(*s); s++ ) {
+       val *= 10;
+       val += *s - '0';
+    }
+    *number = val;
+    return val < 0? NULL : s;
+}
+
+
+static const char *
+parse_version_string( const char *s, int *major, int *minor, int *micro )
+{
+    s = parse_version_number ( s, major );
+    if ( !s || *s != '.' )
+       return NULL;
+    s++;
+    s = parse_version_number ( s, minor );
+    if ( !s || *s != '.' )
+       return NULL;
+    s++;
+    s = parse_version_number ( s, micro );
+    if ( !s )
+       return NULL;
+    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 )
+{
+    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;
+
+    my_plvl = parse_version_string ( ver, &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 );
+    if ( !rq_plvl )
+       return NULL;  /* req version string is invalid */
+
+    if ( my_major > rq_major
+         || (my_major == rq_major && my_minor > rq_minor)
+         || (my_major == rq_major && my_minor == rq_minor
+             && my_micro > rq_micro)
+         || (my_major == rq_major && my_minor == rq_minor
+             && my_micro == rq_micro
+             && strcmp( my_plvl, rq_plvl ) >= 0) ) {
+       return ver;
+    }
+    return NULL;
+}
+
+
+
index 39e5082..21d4b1f 100644 (file)
@@ -36,7 +36,7 @@
 #include "util.h"
 #include "io.h"
 
-#define DEBUG_SELECT_ENABLED 1
+#define DEBUG_SELECT_ENABLED 0
 
 #if DEBUG_SELECT_ENABLED
 # define DEBUG_SELECT(a) fprintf a
@@ -47,7 +47,7 @@
 
 
 /* 
- * We assume that a HANDLE can be represented by an int which should be true
+ * We assume that a HANDLE can be represented by an int which should be true   
  * for all i386 systems (HANDLE is defined as void *) and these are the only
  * systems for which Windows is available.
  * Further we assume that -1 denotes an invalid handle.
@@ -65,10 +65,12 @@ _gpgme_io_read ( int fd, void *buffer, size_t count )
     int nread = 0;
     HANDLE h = fd_to_handle (fd);
 
+    DEBUG_SELECT ((stderr,"** fd %d: about to read %d bytes\n", fd, (int)count ));
     if ( !ReadFile ( h, buffer, count, &nread, NULL) ) {
         fprintf (stderr, "** ReadFile failed: ec=%d\n", (int)GetLastError ());
         return -1;
     }
+    DEBUG_SELECT ((stderr,"** fd %d:           got %d bytes\n", fd, nread ));
 
     return nread;
 }
@@ -80,23 +82,62 @@ _gpgme_io_write ( int fd, const void *buffer, size_t count )
     int nwritten;
     HANDLE h = fd_to_handle (fd);
 
+    DEBUG_SELECT ((stderr,"** fd %d: about to write %d bytes\n", fd, (int)count ));
     if ( !WriteFile ( h, buffer, count, &nwritten, NULL) ) {
         fprintf (stderr, "** WriteFile failed: ec=%d\n", (int)GetLastError ());
         return -1;
     }
+    DEBUG_SELECT ((stderr,"** fd %d:          wrote %d bytes\n", fd, nwritten ));
 
     return nwritten;
 }
 
 int
-_gpgme_io_pipe ( int filedes[2] )
+_gpgme_io_pipe ( int filedes[2], int inherit_idx )
 {
     HANDLE r, w;
+    SECURITY_ATTRIBUTES sec_attr;
+
+    memset (&sec_attr, 0, sizeof sec_attr );
+    sec_attr.nLength = sizeof sec_attr;
+    sec_attr.bInheritHandle = FALSE;
     
-    if (!CreatePipe ( &r, &w, NULL, 0))
+    if (!CreatePipe ( &r, &w, &sec_attr, 0))
         return -1;
+    /* make one end inheritable */
+    if ( inherit_idx == 0 ) {
+        HANDLE h;
+        if (!DuplicateHandle( GetCurrentProcess(), r,
+                              GetCurrentProcess(), &h, 0,
+                              TRUE, DUPLICATE_SAME_ACCESS ) ) {
+            fprintf (stderr, "** DuplicateHandle failed: ec=%d\n",
+                     (int)GetLastError());
+            CloseHandle (r);
+            CloseHandle (w);
+            return -1;
+        }
+        CloseHandle (r);
+        r = h;
+    }
+    else if ( inherit_idx == 1 ) {
+        HANDLE h;
+        if (!DuplicateHandle( GetCurrentProcess(), w,
+                              GetCurrentProcess(), &h, 0,
+                              TRUE, DUPLICATE_SAME_ACCESS ) ) {
+            fprintf (stderr, "** DuplicateHandle failed: ec=%d\n",
+                     (int)GetLastError());
+            CloseHandle (r);
+            CloseHandle (w);
+            return -1;
+        }
+        CloseHandle (w);
+        w = h;
+    }
+
     filedes[0] = handle_to_fd (r);
     filedes[1] = handle_to_fd (w);
+    DEBUG_SELECT ((stderr,"** create pipe %p %p %d %d inherit=%d\n", r, w,
+                   filedes[0], filedes[1], inherit_idx ));
     return 0;
 }
 
@@ -105,7 +146,15 @@ _gpgme_io_close ( int fd )
 {
     if ( fd == -1 )
         return -1;
-    return CloseHandle (fd_to_handle(fd)) ? 0 : -1;
+
+    DEBUG_SELECT ((stderr,"** closing handle for fd %d\n", fd));
+    if ( !CloseHandle (fd_to_handle (fd)) ) { 
+        fprintf (stderr, "** CloseHandle for fd %d failed: ec=%d\n",
+                 fd, (int)GetLastError ());
+        return -1;
+    }
+
+    return 0;
 }
 
 
@@ -126,12 +175,13 @@ build_commandline ( char **argv )
      * program parses the commandline and does some unquoting */
     for (i=0; argv[i]; i++)
         n += strlen (argv[i]) + 1;
-    n += 5;                     /* "gpg " */
     buf = p = xtrymalloc (n);
     if ( !buf )
         return NULL;
-    p = stpcpy (p, "gpg");
-    for (i = 0; argv[i]; i++)
+    *buf = 0;
+    if ( argv[0] )
+        p = stpcpy (p, argv[0]);
+    for (i = 1; argv[i]; i++)
         p = stpcpy (stpcpy (p, " "), argv[i]);
 
     return buf;
@@ -150,46 +200,84 @@ _gpgme_io_spawn ( const char *path, char **argv,
         0,         /* returns pid */
         0         /* returns tid */
     };
-    STARTUPINFO si = {
-        0, NULL, NULL, NULL,
-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-        NULL, NULL, NULL, NULL
-    };
+    STARTUPINFO si;
     char *envblock = NULL;
     int cr_flags = CREATE_DEFAULT_ERROR_MODE
                  | GetPriorityClass (GetCurrentProcess ());
-    int i, rc;
+    int i;
     char *arg_string;
-    HANDLE save_stdout;
-    HANDLE outputfd[2], statusfd[2], inputfd[2];
+    int duped_stdin = 0;
+    int duped_stderr = 0;
+    HANDLE hnul = INVALID_HANDLE_VALUE;
 
-    sec_attr.nLength = sizeof (sec_attr);
+    memset (&sec_attr, 0, sizeof sec_attr );
+    sec_attr.nLength = sizeof sec_attr;
     sec_attr.bInheritHandle = FALSE;
-    sec_attr.lpSecurityDescriptor = NULL;
-
 
     arg_string = build_commandline ( argv );
     if (!arg_string )
         return -1; 
 
+    memset (&si, 0, sizeof si);
     si.cb = sizeof (si);
     si.dwFlags = STARTF_USESTDHANDLES;
     si.hStdInput = GetStdHandle (STD_INPUT_HANDLE);
     si.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
     si.hStdError = GetStdHandle (STD_ERROR_HANDLE);
-    if (!SetHandleInformation (si.hStdOutput,
-                               HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) {
-        fprintf (stderr, "** SHI 1 failed: ec=%d\n", (int) GetLastError ());
+
+    for (i=0; fd_child_list[i].fd != -1; i++ ) {
+        if (fd_child_list[i].dup_to == 0 ) {
+            si.hStdInput = fd_to_handle (fd_child_list[i].fd);
+            DEBUG_SELECT ((stderr,"** using %d for stdin\n", fd_child_list[i].fd ));
+            duped_stdin=1;
+        }
+        else if (fd_child_list[i].dup_to == 1 ) {
+            si.hStdOutput = fd_to_handle (fd_child_list[i].fd);
+            DEBUG_SELECT ((stderr,"** using %d for stdout\n", fd_child_list[i].fd ));
+        }
+        else if (fd_child_list[i].dup_to == 2 ) {
+            si.hStdError = fd_to_handle (fd_child_list[i].fd);
+            DEBUG_SELECT ((stderr,"** using %d for stderr\n", fd_child_list[i].fd ));
+            duped_stderr = 1;
+        }
     }
-    if (!SetHandleInformation (si.hStdError,
-                               HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) {
-        fprintf (stderr, "** SHI 2 failed: ec=%d\n", (int) GetLastError ());
+
+    if( !duped_stdin || !duped_stderr ) {
+        SECURITY_ATTRIBUTES sa;
+
+        memset (&sa, 0, sizeof sa );
+        sa.nLength = sizeof sa;
+        sa.bInheritHandle = TRUE;
+        hnul = CreateFile ( "/dev/nul",
+                            GENERIC_READ|GENERIC_WRITE,
+                            FILE_SHARE_READ|FILE_SHARE_WRITE,
+                            &sa,
+                            OPEN_EXISTING,
+                            FILE_ATTRIBUTE_NORMAL,
+                            NULL );
+        if ( hnul == INVALID_HANDLE_VALUE ) {
+            fprintf (stderr,"can't open `/dev/nul': ec=%d\n",
+                     (int)GetLastError () );
+            xfree (arg_string);
+            return -1;
+        }
+        /* Make sure that the process has a connected stdin */
+        if ( !duped_stdin ) {
+            si.hStdInput = hnul;
+            DEBUG_SELECT ((stderr,"** using %d for stdin\n", (int)hnul ));
+        }
+        /* We normally don't want all the normal output */
+        if ( !duped_stderr ) {
+            if (!getenv ("GPGME_DEBUG") ) {
+                si.hStdError = hnul;
+                DEBUG_SELECT ((stderr,"** using %d for stderr\n", (int)hnul ));
+            }
+        }
     }
-    
 
-    fputs ("** CreateProcess ...\n", stderr);
-    fprintf (stderr, "** args=`%s'\n", arg_string);
-    fflush (stderr);
+    DEBUG_SELECT ((stderr,"** CreateProcess ...\n"));
+    DEBUG_SELECT ((stderr,"** args=`%s'\n", arg_string));
+    cr_flags |= CREATE_SUSPENDED; 
     if ( !CreateProcessA (GPG_PATH,
                           arg_string,
                           &sec_attr,     /* process security attributes */
@@ -203,27 +291,47 @@ _gpgme_io_spawn ( const char *path, char **argv,
         ) ) {
         fprintf (stderr, "** CreateProcess failed: ec=%d\n",
                  (int) GetLastError ());
-        fflush (stderr);
         xfree (arg_string);
         return -1;
     }
 
-    /* .dup_to is not used in the parent list */
+    /* close the /dev/nul handle if used */
+    if (hnul != INVALID_HANDLE_VALUE ) {
+        if ( !CloseHandle ( hnul ) )
+            fprintf (stderr, "** CloseHandle(hnul) failed: ec=%d\n", 
+                     (int)GetLastError());
+    }
+
+    /* Close the other ends of the pipes */
     for (i=0; fd_parent_list[i].fd != -1; i++ ) {
-        CloseHandle ( fd_to_handle (fd_parent_list[i].fd) );
+        DEBUG_SELECT ((stderr,"** Closing fd %d\n", fd_parent_list[i].fd ));
+        if ( !CloseHandle ( fd_to_handle (fd_parent_list[i].fd) ) )
+            fprintf (stderr, "** CloseHandle failed: ec=%d\n",                 
+                     (int)GetLastError());
     }
 
-    fprintf (stderr, "** CreateProcess ready\n");
-    fprintf (stderr, "**   hProcess=%p  hThread=%p\n",
-             pi.hProcess, pi.hThread);
-    fprintf (stderr, "**   dwProcessID=%d dwThreadId=%d\n",
-             (int) pi.dwProcessId, (int) pi.dwThreadId);
-    fflush (stderr);
+    DEBUG_SELECT ((stderr,"** CreateProcess ready\n"
+                   "**   hProcess=%p  hThread=%p\n"
+                   "**   dwProcessID=%d dwThreadId=%d\n",
+                   pi.hProcess, pi.hThread, 
+                   (int) pi.dwProcessId, (int) pi.dwThreadId));
+
+    if ( ResumeThread ( pi.hThread ) < 0 ) {
+        fprintf (stderr, "** ResumeThread failed: ec=%d\n",
+                 (int)GetLastError ());
+    }
+
+    if ( !CloseHandle (pi.hThread) ) { 
+        fprintf (stderr, "** CloseHandle of thread failed: ec=%d\n",
+                 (int)GetLastError ());
+    }
 
     return handle_to_pid (pi.hProcess);
 }
 
 
+
+
 int
 _gpgme_io_waitpid ( int pid, int hang, int *r_status, int *r_signal )
 {
@@ -246,15 +354,15 @@ _gpgme_io_waitpid ( int pid, int hang, int *r_status, int *r_signal )
             *r_status = 4; 
         }
         else {
-            fprintf (stderr, "** GECP pid=%d exit code=%d\n",
-                        (int)pid,  exc);
+            DEBUG_SELECT ((stderr,"** GECP pid=%d exit code=%d\n",
+                           (int)pid,  exc));
             *r_status = exc;
         }
         ret = 1;
         break;
 
       case WAIT_TIMEOUT:
-        fprintf (stderr, "** WFSO pid=%d timed out\n", (int)pid);
+        DEBUG_SELECT ((stderr,"** WFSO pid=%d timed out\n", (int)pid));
         break;
 
       default:
@@ -274,24 +382,28 @@ _gpgme_io_waitpid ( int pid, int hang, int *r_status, int *r_signal )
 int
 _gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds )
 {
+#if 0 /* We can't use WFMO becaus a pipe handle is not a suitable object */
     HANDLE waitbuf[MAXIMUM_WAIT_OBJECTS];
     int code, nwait;
-    int i, any, ret;
+    int i, any, any_write;
+    int count;
 
+ restart:
     DEBUG_SELECT ((stderr, "gpgme:select on [ "));
-    any = 0;
+    any = any_write = 0;
     nwait = 0;
     for ( i=0; i < nfds; i++ ) {
         if ( fds[i].fd == -1 ) 
             continue;
         if ( fds[i].for_read || fds[i].for_write ) {
             if ( nwait >= DIM (waitbuf) ) {
-                DEBUG_SELECT ((stderr, "oops ]\n" ));
+                DEBUG_SELECT ((stderr,stderr, "oops ]\n" ));
                 fprintf (stderr, "** Too many objects for WFMO!\n" );
                 return -1;
             }
             else {
-                waitbuf[nwait++] = fd_to_handle (fds[i].fd);
+                if ( fds[i].for_read ) 
+                    waitbuf[nwait++] = fd_to_handle (fds[i].fd);
                 DEBUG_SELECT ((stderr, "%c%d ",
                                fds[i].for_read? 'r':'w',fds[i].fd ));
                 any = 1;
@@ -300,14 +412,73 @@ _gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds )
         fds[i].signaled = 0;
     }
     DEBUG_SELECT ((stderr, "]\n" ));
-    if (!any)
+    if (!any) 
         return 0;
 
-    ret = 0;
-    code = WaitForMultipleObjects ( nwait, waitbuf, 0, 1000 );
+    count = 0;
+    for ( i=0; i < nfds; i++ ) {
+        if ( fds[i].fd == -1 ) 
+            continue;
+        if ( fds[i].for_write ) {
+            fds[i].signaled = 1;
+            any_write =1;
+            count++;
+        }
+    }
+    code = WaitForMultipleObjects ( nwait, waitbuf, 0, any_write? 0:1000);
     if (code == WAIT_FAILED ) {
-        fprintf (stderr, "** WFMO failed: %d\n",  (int)GetLastError () );
-        ret = -1;
+        int le = (int)GetLastError ();
+        if ( le == ERROR_INVALID_HANDLE  || le == ERROR_INVALID_EVENT_COUNT ) {
+            any = 0;
+            for ( i=0; i < nfds; i++ ) {
+                if ( fds[i].fd == -1 ) 
+                    continue;
+                if ( fds[i].for_read /*|| fds[i].for_write*/ ) {
+                    int navail;
+                    if (PeekNamedPipe (fd_to_handle (fds[i].fd), 
+                                       NULL, 0, NULL,
+                                      &navail, NULL) && navail ) {
+                        fds[i].signaled = 1;
+                        any = 1;
+                        count++;
+                    }
+                }
+            }
+            if (any)
+                return count;
+            /* find that handle and remove it from the list*/
+            for (i=0; i < nwait; i++ ) {
+                code = WaitForSingleObject ( waitbuf[i], NULL );
+                if (!code) {
+                    int k, j = handle_to_fd (waitbuf[i]);
+
+                    fprintf (stderr, "** handle meanwhile signaled %d\n", j);
+                    for (k=0 ; k < nfds; k++ ) {
+                        if ( fds[k].fd == j ) {
+                            fds[k].signaled = 1;
+                            count++;
+                            return count; 
+                        }
+                    }
+                    fprintf (stderr, "** oops, or not???\n");
+                }
+                if ( GetLastError () == ERROR_INVALID_HANDLE) {
+                    int k, j = handle_to_fd (waitbuf[i]);
+                    
+                    fprintf (stderr, "** WFMO invalid handle %d removed\n", j);
+                    for (k=0 ; k < nfds; i++ ) {
+                        if ( fds[k].fd == j ) {
+                            fds[k].for_read = fds[k].for_write = 0;
+                            goto restart;
+                        }
+                    }
+                    fprintf (stderr, "** oops, or not???\n");
+                }
+            }
+        }
+
+        fprintf (stderr, "** WFMO failed: %d\n", le );
+        count = -1;
     }
     else if ( code == WAIT_TIMEOUT ) {
         fprintf (stderr, "** WFMO timed out\n" );
@@ -326,22 +497,94 @@ _gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds )
             if (WaitForSingleObject ( waitbuf[i], NULL ) == WAIT_OBJECT_0) {
                 fds[i].signaled = 1;
                 any = 1;
+                count++;
             }
         }
-        if (any)
-            ret = 1;
-        else {
+        if (!any) {
             fprintf (stderr,
                      "** Oops: No signaled objects found after WFMO\n");
-            ret = -1;
+            count = -1;
         }
     }
     else {
         fprintf (stderr, "** WFMO returned %d\n", code );
-        ret = -1;
+        count = -1;
     }
 
-    return ret;
+    return count;
+#else  /* This is the code we use */
+    int i, any, count;
+    int once_more = 0;
+
+    DEBUG_SELECT ((stderr, "gpgme:fakedselect on [ "));
+    any = 0;
+    for ( i=0; i < nfds; i++ ) {
+        if ( fds[i].fd == -1 ) 
+            continue;
+        if ( fds[i].for_read || fds[i].for_write ) {
+            DEBUG_SELECT ((stderr, "%c%d ",
+                           fds[i].for_read? 'r':'w',fds[i].fd ));
+            any = 1;
+        }
+        fds[i].signaled = 0;
+    }
+    DEBUG_SELECT ((stderr, "]\n" ));
+    if (!any) 
+        return 0;
+
+ restart:
+    count = 0;
+    /* no way to see whether a handle is ready fro writing, signal all */
+    for ( i=0; i < nfds; i++ ) {
+        if ( fds[i].fd == -1 ) 
+            continue;
+        if ( fds[i].for_write ) {
+            fds[i].signaled = 1;
+            count++;
+        }
+    }
+
+    /* now peek on all read handles */
+    for ( i=0; i < nfds; i++ ) {
+        if ( fds[i].fd == -1 ) 
+            continue;
+        if ( fds[i].for_read ) {
+            int navail;
+
+            if ( !PeekNamedPipe (fd_to_handle (fds[i].fd),
+                                 NULL, 0, NULL, &navail, NULL) ) {
+                fprintf (stderr, "** select: PeekFile failed: ec=%d\n",
+                         (int)GetLastError ());
+            }
+            else if ( navail ) {
+                fprintf (stderr, "** fd %d has %d bytes to read\n",
+                         fds[i].fd, navail );
+                fds[i].signaled = 1;
+                count++;
+            }
+        }
+    }
+    if ( !once_more && !count ) {
+        once_more = 1;
+        Sleep (300);
+        goto restart;
+    }
+
+    if ( count ) {
+        DEBUG_SELECT ((stderr, "gpgme:      signaled [ "));
+        for ( i=0; i < nfds; i++ ) {
+            if ( fds[i].fd == -1 ) 
+                continue;
+            if ( (fds[i].for_read || fds[i].for_write) && fds[i].signaled ) {
+                DEBUG_SELECT ((stderr, "%c%d ",
+                               fds[i].for_read? 'r':'w',fds[i].fd ));
+            }
+        }
+        DEBUG_SELECT ((stderr, "]\n" ));
+    }
+    
+    return count;
+#endif
 }
 
 #endif /*HAVE_DOSISH_SYSTEM*/
index 080858e..a337ad0 100644 (file)
@@ -111,6 +111,19 @@ count_active_fds ( int pid )
     return count;
 }
 
+static void
+clear_active_fds ( int pid )
+{
+    struct wait_item_s *q;
+    int i;
+    
+    for (i=0; i < fd_table_size; i++ ) {
+        if ( fd_table[i].fd != -1 && (q=fd_table[i].opaque)
+             && q->active && q->pid == pid  ) 
+            q->active = 0;
+    }
+}
+
 
 /* remove the given process from the queue */
 static void
@@ -123,7 +136,11 @@ remove_process ( int pid )
         if (fd_table[i].fd != -1 && (q=fd_table[i].opaque) && q->pid == pid ) {
             xfree (q);
             fd_table[i].opaque = NULL;
-            _gpgme_io_close (fd_table[i].fd);
+            
+            if ( !fd_table[i].is_closed ) {
+                _gpgme_io_close (fd_table[i].fd);
+                fd_table[i].is_closed = 1;
+            }
             fd_table[i].fd = -1;
         }
     }
@@ -168,8 +185,13 @@ _gpgme_wait_on_condition ( GpgmeCtx c, int hang, volatile int *cond )
             q = queue_item_from_context ( c );
             assert (q);
             
-            if (q->exited)
-                ;
+            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).
+                 * Set all FDs inactive.
+                 */
+                clear_active_fds (q->pid);
+            }
             else if ( _gpgme_io_waitpid (q->pid, 0,
                                           &q->exit_status, &q->exit_signal)){
                 q->exited = 1;     
@@ -207,26 +229,30 @@ do_select ( void )
 {
     struct wait_item_s *q;
     int i, n;
+    int any=0;
     
     n = _gpgme_io_select ( fd_table, fd_table_size );
     if ( n <= 0 ) 
         return 0; /* error or timeout */
 
-    for (i=0; i < fd_table_size && n; i++ ) {
+    for (i=0; i < fd_table_size /*&& n*/; i++ ) {
         if ( fd_table[i].fd != -1 && fd_table[i].signaled ) {
             q = fd_table[i].opaque;
             assert (n);
             n--;
+            if ( q->active )
+                any = 1;
             if ( q->active && q->handler (q->handler_value,
                                           q->pid, fd_table[i].fd ) ) {
                 q->active = 0;
                 fd_table[i].for_read = 0;
                 fd_table[i].for_write = 0;
+                fd_table[i].is_closed = 1;
             }
         }
     }
     
-    return 1;
+    return any;
 }
 
 
@@ -262,6 +288,7 @@ _gpgme_register_pipe_handler( void *opaque,
     for (i=0; i < fd_table_size; i++ ) {
         if ( fd_table[i].fd == -1 ) {
             fd_table[i].fd = fd;
+            fd_table[i].is_closed = 0;
             fd_table[i].for_read = inbound;    
             fd_table[i].for_write = !inbound;    
             fd_table[i].signaled = 0;
index f98748d..dd64689 100644 (file)
 
 #include "../gpgme/gpgme.h"
 
+struct passphrase_cb_info_s {
+    GpgmeCtx c;
+    int did_it;
+};
+
+
 #define fail_if_err(a) do { if(a) { int my_errno = errno; \
             fprintf (stderr, "%s:%d: GpgmeError %s\n", \
                  __FILE__, __LINE__, gpgme_strerror(a));   \
@@ -50,17 +56,31 @@ print_data ( GpgmeData dh )
         fail_if_err (err);
 }
 
-#if 0
-static GpgmeData
-passphrase_cb ( void *opaque, const char *description )
-{
-    GpgmeData dh;
 
-    assert (NULL);
-    gpgme_data_new_from_mem ( &dh, "abc", 3, 0 );
-    return dh;
+static int
+passphrase_cb ( void *opaque, char *buffer, size_t length, size_t *nread )
+{
+    struct passphrase_cb_info_s *info = opaque;
+    const char *desc;
+
+    assert (info);
+    assert (info->c);
+    if ( !buffer || !length || !nread )
+        return 0; /* those values are reserved for extensions */
+    if ( info->did_it )
+        return -1; /* eof */
+
+    desc = gpgme_get_prompt (info->c, 1);
+    if (desc)
+        fprintf (stderr, "Request passphrase for '%s'\n", desc );
+    if ( length < 3 )
+        return -1; /* FIXME - sending an EOF here is wrong */
+    memcpy (buffer, "abc", 3 );
+    *nread = 3;
+    info->did_it = 1;
+    return 0;
 }
-#endif
+
 
 static char *
 mk_fname ( const char *fname )
@@ -84,17 +104,18 @@ main (int argc, char **argv )
 {
     GpgmeCtx ctx;
     GpgmeError err;
-    GpgmeData in, out;
+    GpgmeData in, out, pwdata = NULL;
+    struct passphrase_cb_info_s info;
     const char *cipher_1_asc = mk_fname ("cipher-1.asc");
 
   do {
     err = gpgme_new (&ctx);
     fail_if_err (err);
-#if 0
-    if ( !getenv("GPG_AGENT_INFO") {
-        gpgme_set_passphrase_cb ( ctx, passphrase_cb, NULL );
+    if ( 0 && !getenv("GPG_AGENT_INFO") ) {
+        memset ( &info, 0, sizeof info );
+        info.c = ctx;
+        gpgme_data_new_with_read_cb ( &pwdata, passphrase_cb, &info );
     } 
-#endif
 
     err = gpgme_data_new_from_file ( &in, cipher_1_asc, 1 );
     fail_if_err (err);
@@ -102,7 +123,7 @@ main (int argc, char **argv )
     err = gpgme_data_new ( &out );
     fail_if_err (err);
 
-    err = gpgme_op_decrypt (ctx, in, out );
+    err = gpgme_op_decrypt (ctx, pwdata, in, out );
     fail_if_err (err);
 
     fflush (NULL);
@@ -112,6 +133,7 @@ main (int argc, char **argv )
    
     gpgme_data_release (in);
     gpgme_data_release (out);
+    gpgme_data_release (pwdata);
     gpgme_release (ctx);
   } while ( argc > 1 && !strcmp( argv[1], "--loop" ) );