Add better debug printing. Use reader threads for W32
authorWerner Koch <wk@gnupg.org>
Tue, 30 Jan 2001 11:01:41 +0000 (11:01 +0000)
committerWerner Koch <wk@gnupg.org>
Tue, 30 Jan 2001 11:01:41 +0000 (11:01 +0000)
29 files changed:
TODO [new file with mode: 0644]
autogen.sh
gpgme/ChangeLog
gpgme/Makefile.am
gpgme/data.c
gpgme/debug.c [new file with mode: 0644]
gpgme/decrypt.c
gpgme/encrypt.c
gpgme/export.c
gpgme/genkey.c
gpgme/gpgme.c
gpgme/gpgme.h
gpgme/import.c
gpgme/key.c
gpgme/key.h
gpgme/keylist.c
gpgme/ops.h
gpgme/posix-io.c
gpgme/posix-sema.c [new file with mode: 0644]
gpgme/rungpg.c
gpgme/sema.h [new file with mode: 0644]
gpgme/sign.c
gpgme/signers.c
gpgme/util.h
gpgme/verify.c
gpgme/version.c
gpgme/w32-io.c
gpgme/w32-sema.c [new file with mode: 0644]
tests/t-keylist.c

diff --git a/TODO b/TODO
new file mode 100644 (file)
index 0000000..59a6d8c
--- /dev/null
+++ b/TODO
@@ -0,0 +1,10 @@
+* Implement posix-sema.c
+
+* Add gpgme_mime_xxx to make handling of MIME/PGP easier
+
+* Allow to use GTK's main loop instead of the select stuff in
+  wait.c
+
+* Remove all that funny exit code handling - we donn't need it.
+
+
index 13e4b368d5157c9d237b9302f99192d17be7b098..378fe59412dfd30384a5161eece34e1501b7ec0b 100755 (executable)
@@ -62,7 +62,7 @@ if test "$1" = "--build-w32"; then
 
     ./configure --host=${host} --target=${target}  ${disable_foo_tests} \
                 --bindir=${crossbindir} --libdir=${crosslibdir} \
-                --includedir=${crossincdir}  $*
+                --includedir=${crossincdir}  --enable-maintainer-mode $*
     exit $?
 fi
 
index fe88ebba34e5e5a1073858930269fc6543018ca5..63e16155749621d19cbb4c295c61ae0677577f5a 100644 (file)
@@ -1,3 +1,18 @@
+2001-01-30  Werner Koch  <wk@gnupg.org>
+
+       * w32-io.c: Does now use reader threads, so that we can use
+       WaitForMultipleObjects. 
+       * sema.h, posix-sema.c, w32-sema.c: Support for Critcial sections.
+       Does currently only work for W32.
+
+       * debug.c, util.h : New. Changed all fprintfs to use this new
+       set of debugging functions.
+
+2001-01-23  Werner Koch  <wk@gnupg.org>
+
+       * data.c (_gpgme_data_release_and_return_string): Fixed string
+       termination.
+
 2001-01-22  Werner Koch  <wk@gnupg.org>
 
        * delete.c: New.
index 74d5955d6715e3c38e11f719254a24656572a634..20944ac821b8d6debc01107821ee4014c4cd7e47 100644 (file)
@@ -13,7 +13,7 @@ libgpgme_la_LDFLAGS = -version-info \
 libgpgme_la_INCLUDES = -I$(top_srcdir)/lib 
 
 libgpgme_la_SOURCES = \
-       gpgme.h types.h util.h util.c \
+       gpgme.h types.h util.h util.c debug.c \
        context.h ops.h \
        data.c recipient.c signers.c \
         wait.c wait.h \
@@ -29,6 +29,7 @@ libgpgme_la_SOURCES = \
        genkey.c \
        delete.c \
         rungpg.c rungpg.h status-table.h \
+       sema.h posix-sema.c w32-sema.c \
        syshdr.h io.h posix-io.c w32-io.c \
        gpgme.c version.c errors.c
 
index 48a2eaeb48d37213acfbe1b04a70e63432896bf5..9d8b58eea582ff1c9de2df5a7d4814db4f328c44 100644 (file)
@@ -311,7 +311,7 @@ _gpgme_data_release_and_return_string ( GpgmeData dh )
     char *val = NULL;
 
     if (dh) {
-        if ( _gpgme_data_append ( dh, "", 0 ) ) /* append EOS */
+        if ( _gpgme_data_append ( dh, "", 1 ) ) /* append EOS */
             xfree (dh->private_buffer );
         else {
             val = dh->private_buffer;
@@ -331,10 +331,11 @@ _gpgme_data_release_and_return_string ( GpgmeData dh )
  * @dh: the data object
  * @r_len: returns the length of the memory
  * 
- * Release the data object @dh and return its content and the length of
- * that content.  The caller has to free this data.  @dh maybe NULL in
- * which case NULL is returned.  I there is not enough memory for allocating
- * the return value, NULL is returned and the object is released.
+ * Release the data object @dh and return its content and the length
+ * of that content.  The caller has to free this data.  @dh maybe NULL
+ * in which case NULL is returned.  If there is not enough memory for
+ * allocating the return value, NULL is returned and the object is
+ * released.
  * 
  * Return value: a pointer to an allocated buffer of length @r_len.
  **/
diff --git a/gpgme/debug.c b/gpgme/debug.c
new file mode 100644 (file)
index 0000000..f41929b
--- /dev/null
@@ -0,0 +1,156 @@
+/* debug.c
+ *     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 <stdarg.h>
+#include <assert.h>
+
+#include "util.h"
+#include "sema.h"
+
+DEFINE_STATIC_LOCK (debug_lock);
+
+struct debug_control_s {
+    FILE *fp;
+    char fname[100];
+};
+
+static int debug_level = 0;
+
+static void
+debug_init (void)
+{
+    static volatile int initialized = 0;
+       
+    if (initialized) 
+        return;
+    LOCK (debug_lock);
+    if (!initialized) {
+        const char *e = getenv ("GPGME_DEBUG");
+        
+        debug_level =  e? atoi (e): 0;
+        initialized = 1;
+        if (debug_level > 0)
+            fprintf (stderr,"gpgme_debug: level=%d\n", debug_level);
+    }
+    UNLOCK (debug_lock);
+}
+
+
+void
+_gpgme_debug (int level, const char *format, ...)
+{
+    va_list arg_ptr ;
+
+    debug_init ();
+    if ( debug_level < level )
+        return;
+    
+    va_start ( arg_ptr, format ) ;
+    LOCK (debug_lock);
+    vfprintf (stderr, format, arg_ptr) ;
+    va_end ( arg_ptr ) ;
+    if( format && *format && format[strlen(format)-1] != '\n' )
+        putc ('\n', stderr);
+    UNLOCK (debug_lock);
+    fflush (stderr);
+}
+
+
+
+void
+_gpgme_debug_begin ( void **helper, int level, const char *text)
+{
+    struct debug_control_s *ctl;
+
+    debug_init ();
+
+    *helper = NULL;
+    if ( debug_level < level )
+        return;
+    ctl = xtrycalloc (1, sizeof *ctl );
+    if (!ctl) {
+        _gpgme_debug (255, __FILE__ ":" STR2(__LINE__)": out of core");
+        return;
+    }
+
+    /* Oh what a pitty sthat we don't have a asprintf or snprintf under
+     * Windoze.  We definitely should write our own clib for W32! */
+    sprintf ( ctl->fname, "/tmp/gpgme_debug.%d.%p", getpid (), ctl );
+    ctl->fp = fopen (ctl->fname, "w+");
+    if (!ctl->fp) {
+        _gpgme_debug (255,__FILE__ ":" STR2(__LINE__)": failed to create `%s'",
+                      ctl->fname );
+        xfree (ctl);
+        return;
+    }
+    *helper = ctl;
+    _gpgme_debug_add (helper, "%s", text );
+}
+
+int
+_gpgme_debug_enabled (void **helper)
+{
+    return helper && *helper;
+}
+
+
+void
+_gpgme_debug_add (void **helper, const char *format, ...)
+{
+    struct debug_control_s *ctl = *helper;
+    va_list arg_ptr ;
+
+    if ( !*helper )
+        return;
+    
+    va_start ( arg_ptr, format ) ;
+    vfprintf (ctl->fp, format, arg_ptr) ;
+    va_end ( arg_ptr ) ;
+}
+
+void
+_gpgme_debug_end (void **helper, const char *text)
+{
+    struct debug_control_s *ctl = *helper;
+    int c, last_c=EOF;
+
+    if ( !*helper )
+        return;
+    
+    _gpgme_debug_add (helper, "%s", text );
+    rewind (ctl->fp);
+    LOCK (debug_lock);
+    while ( (c=getc (ctl->fp)) != EOF ) {
+        putc (c, stderr);
+        last_c = c;
+    }
+    if (last_c != '\n')
+        putc ('\n', stderr);
+    UNLOCK (debug_lock);
+    
+    remove (ctl->fname);
+    xfree (ctl);
+    *helper = NULL;
+}
+
index 083e5e82cdb40a1f3bf0571f050089e8c791f521..75d4ac8b24f302da62d3850d8fa78c095e4c3881 100644 (file)
@@ -102,7 +102,7 @@ decrypt_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args )
         break;
 
       case STATUS_MISSING_PASSPHRASE:
-        fprintf (stderr, "Missing passphrase - stop\n");;
+        DEBUG0 ("missing passphrase - stop\n");;
         ctx->result.decrypt->no_passphrase = 1;
         break;
 
@@ -174,7 +174,7 @@ command_handler ( void *opaque, GpgStatusCode code, const char *key )
                               buf, &c->result.decrypt->last_pw_handle );
         xfree (buf);
         return s;
-   }
+    }
     
     return NULL;
 }
index 91520a89791e7375af05537deb7af52a421bcaea..e4bb38e2812d1ee7f1482c492b254dbfdc71cd9c 100644 (file)
@@ -31,8 +31,7 @@
 static void
 encrypt_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args )
 {
-    fprintf (stderr, "encrypt_status: code=%d args=`%s'\n",
-             code, args );
+    DEBUG2 ("encrypt_status: code=%d args=`%s'\n", code, args );
 
 }
 
index 0265b46a169497978e8107ae65242b078c3b3f04..c46c3a97e20764de7fe30cd5f20a5bb17430e6f5 100644 (file)
@@ -31,8 +31,7 @@
 static void
 export_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args )
 {
-    fprintf (stderr, "export_status: code=%d args=`%s'\n",
-             code, args );
+    DEBUG2 ("export_status: code=%d args=`%s'\n", code, args );
     /* FIXME: Need to do more */
 }
 
index b002372c9b59475f6c2319de678059cbe9bfd789..c2bab3d628d17c989514a0c03a8254416be2288c 100644 (file)
@@ -59,8 +59,7 @@ genkey_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args )
         return;
     }
 
-    fprintf (stderr, "genkey_status: code=%d args=`%s'\n",
-             code, args );
+    DEBUG2 ("genkey_status: code=%d args=`%s'\n", code, args );
     /* FIXME: Need to do more */
 }
 
index 54ec97fba47a987ab502c008e4d3bba04f837626..935e8e8064af34d6f2cbac1f943cbf68981333ae 100644 (file)
@@ -50,7 +50,6 @@ gpgme_new (GpgmeCtx *r_ctx)
     if (!c)
         return mk_error (Out_Of_Core);
     c->verbosity = 1;
-    c->use_armor = 1; /* fixme: reset this to 0 */
     *r_ctx = c;
 
     return 0;
index 971101b90e1614eaf9a64d3ec0781841a5261c9d..73744922af28b39c8decfea203971183b46ec9fb 100644 (file)
@@ -22,7 +22,7 @@
 #define GPGME_H
 
 #ifdef _MSC_VER
-  typedef long off_t 
+  typedef long off_t;
 #else
 # include <sys/types.h>
 #endif
@@ -126,7 +126,8 @@ typedef enum {
     GPGME_ATTR_COMMENT = 11,
     GPGME_ATTR_VALIDITY= 12,
     GPGME_ATTR_LEVEL   = 13,
-    GPGME_ATTR_TYPE    = 14
+    GPGME_ATTR_TYPE    = 14,
+    GPGME_ATTR_IS_SECRET= 15
 } GpgmeAttr;
 
 typedef enum {
index 368063ac8849404fa72a41936dba30bc6c5b05a7..a05f60b356ebe9d756bdde20451c1c089df9d8ea 100644 (file)
@@ -31,8 +31,7 @@
 static void
 import_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args )
 {
-    fprintf (stderr, "import_status: code=%d args=`%s'\n",
-             code, args );
+    DEBUG2 ("import_status: code=%d args=`%s'\n", code, args );
     /* FIXME: We have to check here whether the import actually worked 
      * and maybe it is a good idea to save some statistics and provide
      * a progress callback */
index 87a5602ade1be383d804d9daee27cfc7e6db2dba..3ee49f7b6f137e76d3d4eef36daf312af92b2dd4 100644 (file)
@@ -48,8 +48,8 @@ pkalgo_to_string ( int algo )
 
 
 
-GpgmeError
-_gpgme_key_new( GpgmeKey *r_key )
+static GpgmeError
+key_new ( GpgmeKey *r_key, int secret )
 {
     GpgmeKey key;
 
@@ -59,9 +59,23 @@ _gpgme_key_new( GpgmeKey *r_key )
         return mk_error (Out_Of_Core);
     key->ref_count = 1;
     *r_key = key;
+    if (secret)
+        key->secret = 1;
     return 0;
 }
 
+GpgmeError
+_gpgme_key_new ( GpgmeKey *r_key )
+{
+    return key_new ( r_key, 0 );
+}
+
+GpgmeError
+_gpgme_key_new_secret ( GpgmeKey *r_key )
+{
+    return key_new ( r_key, 1 );
+}
+
 void
 gpgme_key_ref ( GpgmeKey key )
 {
@@ -70,8 +84,8 @@ gpgme_key_ref ( GpgmeKey key )
 }
 
 
-struct subkey_s *
-_gpgme_key_add_subkey (GpgmeKey key)
+static struct subkey_s *
+add_subkey (GpgmeKey key, int secret)
 {
     struct subkey_s *k, *kk;
 
@@ -86,9 +100,22 @@ _gpgme_key_add_subkey (GpgmeKey key)
             kk = kk->next;
         kk->next = k;
     }
+    if (secret)
+        k->secret = 1;
     return k;
 }
 
+struct subkey_s *
+_gpgme_key_add_subkey (GpgmeKey key)
+{
+    return add_subkey (key, 0);
+}
+
+struct subkey_s *
+_gpgme_key_add_secret_subkey (GpgmeKey key)
+{
+    return add_subkey (key, 1);
+}
 
 void
 gpgme_key_release ( GpgmeKey key )
@@ -350,6 +377,8 @@ gpgme_key_get_as_xml ( GpgmeKey key )
     
     _gpgme_data_append_string ( d, "<GnupgKeyblock>\n"
                                    "  <mainkey>\n" );
+    if ( key->secret )
+        _gpgme_data_append_string ( d, "    <secret/>\n");
     add_tag_and_string (d, "keyid", key->keys.keyid );   
     if (key->keys.fingerprint)
         add_tag_and_string (d, "fpr", key->keys.fingerprint );
@@ -374,6 +403,8 @@ gpgme_key_get_as_xml ( GpgmeKey key )
     
     for (k=key->keys.next; k; k = k->next ) {
         _gpgme_data_append_string (d, "  <subkey>\n");
+        if ( k->secret )
+            _gpgme_data_append_string ( d, "    <secret/>\n");
         add_tag_and_string (d, "keyid", k->keyid );   
         if (k->fingerprint)
             add_tag_and_string (d, "fpr", k->fingerprint );
@@ -456,6 +487,10 @@ gpgme_key_get_string_attr ( GpgmeKey key, GpgmeAttr what,
       case GPGME_ATTR_LEVEL:  /* not used here */
       case GPGME_ATTR_TYPE:
         break;
+      case GPGME_ATTR_IS_SECRET:
+        if (key->secret)
+            val = "1";
+        break;
     }
     return val;
 }
@@ -491,6 +526,9 @@ gpgme_key_get_ulong_attr ( GpgmeKey key, GpgmeAttr what,
         if (u)
             val = u->validity;
         break;
+      case GPGME_ATTR_IS_SECRET:
+        val = !!key->secret;
+        break;
       default:
         break;
     }
index c9be9b0a19aa843c8f3265971fea4f437c593c2f..91a4c846dd6315c33cef5d8ad77ba60cb21048ca 100644 (file)
@@ -27,6 +27,7 @@
 
 struct subkey_s {
     struct subkey_s *next;
+    unsigned int secret:1;
     struct {
         unsigned int revoked:1 ;
         unsigned int expired:1 ;
@@ -46,11 +47,13 @@ struct gpgme_key_s {
         unsigned int disabled:1 ;
     } gloflags; 
     unsigned int ref_count;
+    unsigned int secret:1;
     struct subkey_s   keys; 
     struct user_id_s *uids;
 };
 
 struct subkey_s *_gpgme_key_add_subkey (GpgmeKey key);
+struct subkey_s *_gpgme_key_add_secret_subkey (GpgmeKey key);
 GpgmeError _gpgme_key_append_name ( GpgmeKey key, const char *s );
 
 
index a1c356fc97027cfde3855e8226358d980a937fe1..9fea42575c0de93bec54673d7dc995d5554568de 100644 (file)
@@ -49,7 +49,6 @@ keylist_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args )
 
       default:
         /* ignore all other codes */
-        fprintf (stderr, "keylist_status: code=%d not handled\n", code );
         break;
     }
 }
@@ -153,7 +152,7 @@ keylist_colon_handler ( GpgmeCtx ctx, char *line )
                 rectype = RT_UID;
                 key = ctx->tmp_key;
             }
-            else if ( !strcmp ( p, "sub" ) && key ) {
+            else if ( !strcmp (p, "sub") && key ) {
                 /* start a new subkey */
                 rectype = RT_SUB;
                 if ( !(sk = _gpgme_key_add_subkey (key)) ) {
@@ -161,10 +160,18 @@ keylist_colon_handler ( GpgmeCtx ctx, char *line )
                     return;
                 }
             }
-            else if ( !strcmp ( p, "pub" ) ) {
+            else if ( !strcmp (p, "ssb") && key ) {
+                /* start a new secret subkey */
+                rectype = RT_SSB;
+                if ( !(sk = _gpgme_key_add_secret_subkey (key)) ) {
+                    ctx->out_of_core=1;
+                    return;
+                }
+            }
+            else if ( !strcmp (p, "pub") ) {
                 /* start a new keyblock */
                 if ( _gpgme_key_new ( &key ) ) {
-                    ctx->out_of_core=1; /* the only kind of error we can get */
+                    ctx->out_of_core=1; /* the only kind of error we can get*/
                     return;
                 }
                 rectype = RT_PUB;
@@ -173,17 +180,25 @@ keylist_colon_handler ( GpgmeCtx ctx, char *line )
                 assert ( !ctx->tmp_key );
                 ctx->tmp_key = key;
             }
+            else if ( !strcmp (p, "sec") ) {
+                /* start a new keyblock */
+                if ( _gpgme_key_new_secret ( &key ) ) {
+                    ctx->out_of_core=1; /*the only kind of error we can get*/
+                    return;
+                }
+                rectype = RT_SEC;
+                if ( ctx->tmp_key )
+                    finish_key ( ctx );
+                assert ( !ctx->tmp_key );
+                ctx->tmp_key = key;
+            }
             else if ( !strcmp ( p, "fpr" ) && key ) 
                 rectype = RT_FPR;
-            else if ( !strcmp ( p, "ssb" ) )
-                rectype = RT_SSB;
-            else if ( !strcmp ( p, "sec" ) )
-                rectype = RT_SEC;
             else 
                 rectype = RT_NONE;
             
         }
-        else if ( rectype == RT_PUB ) {
+        else if ( rectype == RT_PUB || rectype == RT_SEC ) {
             switch (field) {
               case 2: /* trust info */
                 trust_info = p;  /*save for later */
@@ -226,7 +241,7 @@ keylist_colon_handler ( GpgmeCtx ctx, char *line )
                 break;
             }
         }
-        else if ( rectype == RT_SUB && sk ) {
+        else if ( (rectype == RT_SUB || rectype== RT_SSB) && sk ) {
             switch (field) {
               case 2: /* trust info */
                 set_subkey_trust_info ( sk, p);
@@ -344,6 +359,7 @@ gpgme_op_keylist_start ( GpgmeCtx c,  const char *pattern, int secret_only )
     _gpgme_release_result (c);
     c->out_of_core = 0;
 
+#warning This context still keeps a gpg Zombie in some cases.
     if ( c->gpg ) {
         _gpgme_gpg_release ( c->gpg ); 
         c->gpg = NULL;
index 43001f2c829b4c1d3f974d160a76da4a57315a4d..cbf35299d60e8f09862a20a6c0cca8749fdc0c72 100644 (file)
@@ -61,7 +61,8 @@ GpgmeError    _gpgme_data_unread (GpgmeData dh,
 
 
 /*-- key.c --*/
-GpgmeError _gpgme_key_new( GpgmeKey *r_key );
+GpgmeError _gpgme_key_new ( GpgmeKey *r_key );
+GpgmeError _gpgme_key_new_secret ( GpgmeKey *r_key );
 
 
 /*-- verify.c --*/
index ec242d3173e558c334d23434fd59637d79a46b33..e46c70b73a1b7076c2bc554edf192a44cd6af1ef 100644 (file)
 #include <fcntl.h>
 #include "syshdr.h"
 
+#include "util.h"
 #include "io.h"
 
-#define DEBUG_SELECT_ENABLED 0
-
-#if DEBUG_SELECT_ENABLED
-# define DEBUG_SELECT(a) fprintf a
-#else
-# define DEBUG_SELECT(a) do { } while(0)
-#endif
-
-
 int
 _gpgme_io_read ( int fd, void *buffer, size_t count )
 {
@@ -137,8 +129,7 @@ _gpgme_io_spawn ( const char *path, char **argv,
             if (fd_child_list[i].dup_to != -1 ) {
                 if ( dup2 (fd_child_list[i].fd,
                            fd_child_list[i].dup_to ) == -1 ) {
-                    fprintf (stderr, "dup2 failed in child: %s\n",
-                             strerror (errno));
+                    DEBUG1 ("dup2 failed in child: %s\n", strerror (errno));
                     _exit (8);
                 }
                 if ( fd_child_list[i].dup_to == 0 )
@@ -152,26 +143,21 @@ _gpgme_io_spawn ( const char *path, char **argv,
         if( !duped_stdin || !duped_stderr ) {
             int fd = open ( "/dev/null", O_RDWR );
             if ( fd == -1 ) {
-                fprintf (stderr,"can't open `/dev/null': %s\n",
-                         strerror (errno) );
+                DEBUG1 ("can't open `/dev/null': %s\n", strerror (errno) );
                 _exit (8);
             }
             /* Make sure that the process has a connected stdin */
             if ( !duped_stdin ) {
                 if ( dup2 ( fd, 0 ) == -1 ) {
-                    fprintf (stderr,"dup2(/dev/null, 0) failed: %s\n",
+                    DEBUG1("dup2(/dev/null, 0) failed: %s\n",
                              strerror (errno) );
                     _exit (8);
                 }
             }
-            /* We normally don't want all the normal output */
             if ( !duped_stderr ) {
-                if (!getenv ("GPGME_DEBUG") ) {
-                    if ( dup2 ( fd, 2 ) == -1 ) {
-                        fprintf (stderr,"dup2(dev/null, 2) failed: %s\n",
-                                 strerror (errno) );
-                        _exit (8);
-                    }
+                if ( dup2 ( fd, 2 ) == -1 ) {
+                    DEBUG1 ("dup2(dev/null, 2) failed: %s\n", strerror (errno));
+                    _exit (8);
                 }
             }
             close (fd);
@@ -180,7 +166,7 @@ _gpgme_io_spawn ( const char *path, char **argv,
         execv ( path, argv );
         /* Hmm: in that case we could write a special status code to the
          * status-pipe */
-        fprintf (stderr,"exec of `%s' failed\n", path );
+        DEBUG1 ("exec of `%s' failed\n", path );
         _exit (8);
     } /* end child */
     
@@ -230,12 +216,13 @@ _gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds )
     static fd_set writefds;
     int any, i, max_fd, n, count;
     struct timeval timeout = { 0, 50 }; /* Use a 50ms timeout */
+    void *dbg_help;
     
     FD_ZERO ( &readfds );
     FD_ZERO ( &writefds );
     max_fd = 0;
 
-    DEBUG_SELECT ((stderr, "gpgme:select on [ "));
+    DEBUG_BEGIN (dbg_help, "gpgme:select on [ ");
     any = 0;
     for ( i=0; i < nfds; i++ ) {
         if ( fds[i].fd == -1 ) 
@@ -245,7 +232,7 @@ _gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds )
             FD_SET ( fds[i].fd, &readfds );
             if ( fds[i].fd > max_fd )
                 max_fd = fds[i].fd;
-            DEBUG_SELECT ((stderr, "r%d ", fds[i].fd ));
+            DEBUG_ADD1 (dbg_help, "r%d ", fds[i].fd );
             any = 1;
         }
         else if ( fds[i].for_write ) {
@@ -253,12 +240,12 @@ _gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds )
             FD_SET ( fds[i].fd, &writefds );
             if ( fds[i].fd > max_fd )
                 max_fd = fds[i].fd;
-            DEBUG_SELECT ((stderr, "w%d ", fds[i].fd ));
+            DEBUG_ADD1 (dbg_help, "w%d ", fds[i].fd );
             any = 1;
         }
         fds[i].signaled = 0;
     }
-    DEBUG_SELECT ((stderr, "]\n" ));
+    DEBUG_END (dbg_help, "]" );
     if ( !any )
         return 0;
 
@@ -266,20 +253,20 @@ _gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds )
         count = select ( max_fd+1, &readfds, &writefds, NULL, &timeout );
     } while ( count < 0 && errno == EINTR);
     if ( count < 0 ) {
-        fprintf (stderr, "_gpgme_io_select failed: %s\n", strerror (errno) );
+        DEBUG1 ("_gpgme_io_select failed: %s\n", strerror (errno) );
         return -1; /* error */
     }
 
-#if DEBUG_SELECT_ENABLED
-    fprintf (stderr, "gpgme:select OK [ " );
-    for (i=0; i <= max_fd; i++ ) {
-        if (FD_ISSET (i, &readfds) )
-            fprintf (stderr, "r%d ", i );
-        if (FD_ISSET (i, &writefds) )
-            fprintf (stderr, "w%d ", i );
+    DEBUG_BEGIN (dbg_help, "select OK [ " );
+    if (DEBUG_ENABLED(dbg_help)) {
+        for (i=0; i <= max_fd; i++ ) {
+            if (FD_ISSET (i, &readfds) )
+                DEBUG_ADD1 (dbg_help, "r%d ", i );
+            if (FD_ISSET (i, &writefds) )
+                DEBUG_ADD1 (dbg_help, "w%d ", i );
+        }
+        DEBUG_END (dbg_help, "]" );
     }
-    fprintf (stderr, "]\n" );
-#endif
     
     /* n is used to optimize it a little bit */
     for ( n=count, i=0; i < nfds && n ; i++ ) {
diff --git a/gpgme/posix-sema.c b/gpgme/posix-sema.c
new file mode 100644 (file)
index 0000000..82f9b8c
--- /dev/null
@@ -0,0 +1,70 @@
+/* posix-sema.c 
+ *     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>
+#ifndef HAVE_DOSISH_SYSTEM
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <fcntl.h>
+#include "syshdr.h"
+
+#include "util.h"
+#include "sema.h"
+
+
+
+void
+_gpgme_sema_subsystem_init ()
+{
+#warning Posix semaphore support has not yet been implemented 
+}
+
+
+void
+_gpgme_sema_cs_enter ( struct critsect_s *s )
+{
+}
+
+void
+_gpgme_sema_cs_leave (struct critsect_s *s)
+{
+}
+
+void
+_gpgme_sema_cs_destroy ( struct critsect_s *s )
+{
+}
+
+
+
+#endif /*!HAVE_DOSISH_SYSTEM*/
+
+
+
+
+
index 76313584901a3900a956e37d633da3048cb230ff..101d9a9fa8a55a5364c1aec87a4053fe3ddb64f5 100644 (file)
@@ -789,7 +789,7 @@ gpg_inbound_handler ( void *opaque, int pid, int fd )
 
     nread = _gpgme_io_read (fd, buf, 200 );
     if ( nread < 0 ) {
-        fprintf (stderr, "read_mem_data: read failed on fd %d (n=%d): %s\n",
+        DEBUG3 ("read_mem_data: read failed on fd %d (n=%d): %s",
                  fd, nread, strerror (errno) );
         return 1;
     }
@@ -802,7 +802,7 @@ gpg_inbound_handler ( void *opaque, int pid, int fd )
     
     err = _gpgme_data_append ( dh, buf, nread );
     if ( err ) {
-        fprintf (stderr, "_gpgme_append_data failed: %s\n",
+        DEBUG1 ("_gpgme_append_data failed: %s\n",
                  gpgme_strerror(err));
         /* Fixme: we should close the pipe or read it to /dev/null in
          * this case. Returnin EOF is not sufficient */
@@ -836,8 +836,8 @@ write_mem_data ( GpgmeData dh, int fd )
     if (nwritten == -1 && errno == EAGAIN )
         return 0;
     if ( nwritten < 1 ) {
-        fprintf (stderr, "write_mem_data(%d): write failed (n=%d): %s\n",
-                 fd, nwritten, strerror (errno) );
+        DEBUG3 ("write_mem_data(%d): write failed (n=%d): %s",
+                fd, nwritten, strerror (errno) );
         _gpgme_io_close (fd);
         return 1;
     }
@@ -863,8 +863,8 @@ write_cb_data ( GpgmeData dh, int fd )
     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) );
+        DEBUG3 ("write_cb_data(%d): write failed (n=%d): %s",
+                fd, nwritten, strerror (errno) );
         _gpgme_io_close (fd);
         return 1;
     }
@@ -872,7 +872,7 @@ write_cb_data ( GpgmeData dh, int fd )
     if ( nwritten < nbytes ) {
         /* ugly, ugly: It does currently only for for MEM type data */
         if ( _gpgme_data_unread (dh, buffer + nwritten, nbytes - nwritten ) )
-            fprintf (stderr, "wite_cb_data: unread of %d bytes failed\n",
+            DEBUG1 ("wite_cb_data: unread of %d bytes failed\n",
                      nbytes - nwritten );
         _gpgme_io_close (fd);
         return 1;
@@ -915,7 +915,7 @@ gpg_status_handler ( void *opaque, int pid, int fd )
     assert ( fd == gpg->status.fd[0] );
     rc = read_status ( gpg );
     if ( rc ) {
-        fprintf (stderr, "gpg_handler: read_status problem %d\n - stop", rc);
+        DEBUG1 ("gpg_handler: read_status problem %d\n - stop", rc);
         return 1;
     }
 
@@ -1006,10 +1006,9 @@ read_status ( GpgObject gpg )
                                 return mk_error (Out_Of_Core);
                             /* this should be the last thing we have received
                              * and the next thing will be that the command
-                             * handler does it action */
+                             * handler does its action */
                             if ( nread > 1 )
-                                fprintf (stderr, "** ERROR, unxpected data in"
-                                         " read_status\n" );
+                                DEBUG0 ("ERROR, unexpected data in read_status");
                             _gpgme_thaw_fd (gpg->cmd.fd);
                         }
                         else if ( gpg->status.fnc ) {
@@ -1061,7 +1060,7 @@ gpg_colon_line_handler ( void *opaque, int pid, int fd )
     assert ( fd == gpg->colon.fd[0] );
     rc = read_colon_line ( gpg );
     if ( rc ) {
-        fprintf (stderr, "gpg_colon_line_handler: "
+        DEBUG1 ("gpg_colon_line_handler: "
                  "read problem %d\n - stop", rc);
         return 1;
     }
@@ -1191,7 +1190,7 @@ pipemode_cb ( void *opaque, char *buffer, size_t length, size_t *nread )
             *nread = 2;
         }
         else if (err) {
-            fprintf (stderr, "** pipemode_cb: copy sig failed: %s\n",
+            DEBUG1 ("pipemode_cb: copy sig failed: %s\n",
                      gpgme_strerror (err) );
             return -1;
         }
@@ -1205,7 +1204,7 @@ pipemode_cb ( void *opaque, char *buffer, size_t length, size_t *nread )
             *nread = 4;
         }
         else if (err) {
-            fprintf (stderr, "** pipemode_cb: copy data failed: %s\n",
+            DEBUG1 ("pipemode_cb: copy data failed: %s\n",
                      gpgme_strerror (err) );
             return -1;
         }
@@ -1230,32 +1229,32 @@ command_cb ( void *opaque, char *buffer, size_t length, size_t *nread )
     const char *value;
     int value_len;
 
-    fprintf (stderr, "** command_cb: enter\n");
+    DEBUG0 ("command_cb: enter\n");
     assert (gpg->cmd.used);
     if ( !buffer || !length || !nread )
         return 0; /* those values are reserved for extensions */
     *nread =0;
     if ( !gpg->cmd.code ) {
-        fprintf (stderr, "** command_cb: no code\n");
+        DEBUG0 ("command_cb: no code\n");
         return -1;
     }
     
     if ( !gpg->cmd.fnc ) {
-        fprintf (stderr, "** command_cb: no user cb\n");
+        DEBUG0 ("command_cb: no user cb\n");
         return -1;
     }
 
     value = gpg->cmd.fnc ( gpg->cmd.fnc_value, 
                            gpg->cmd.code, gpg->cmd.keyword );
     if ( !value ) {
-        fprintf (stderr, "** command_cb: no data from user cb\n");
+        DEBUG0 ("command_cb: no data from user cb\n");
         gpg->cmd.fnc ( gpg->cmd.fnc_value, 0, value);
         return -1;
     }
 
     value_len = strlen (value);
     if ( value_len+1 > length ) {
-        fprintf (stderr, "** command_cb: too much data from user cb\n");
+        DEBUG0 ("command_cb: too much data from user cb\n");
         gpg->cmd.fnc ( gpg->cmd.fnc_value, 0, value);
         return -1;
     }
@@ -1265,8 +1264,6 @@ command_cb ( void *opaque, char *buffer, size_t length, size_t *nread )
         buffer[value_len++] = '\n';
     *nread = value_len;
     
-    fprintf (stderr, "** command_cb: leave (wrote `%.*s')\n",
-             (int)*nread-1, buffer);
     gpg->cmd.fnc ( gpg->cmd.fnc_value, 0, value);
     gpg->cmd.code = 0;
     /* and sleep again until read_status will wake us up again */
diff --git a/gpgme/sema.h b/gpgme/sema.h
new file mode 100644 (file)
index 0000000..db28a71
--- /dev/null
@@ -0,0 +1,62 @@
+/* sema.h -  definitions for semaphores
+ *     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
+ */
+
+#ifndef SEMA_H
+#define SEMA_H
+
+struct critsect_s {
+    const char *name;
+    void *private;
+};
+
+#define DEFINE_GLOBAL_LOCK(name) \
+        struct critsect_s name = { #name, NULL }
+#define DEFINE_STATIC_LOCK(name) \
+        static struct critsect_s name  = { #name, NULL }
+
+#define DECLARE_LOCK(name)  struct critsect_s name
+#define INIT_LOCK(a)  do { \
+                      (a).name = #a; \
+                      (a).private = NULL; \
+                    } while (0)
+#define DESTROY_LOCK(name) _gpgme_sema_cs_destroy (&(name))
+                       
+
+#define LOCK(name)  do { \
+                         _gpgme_sema_cs_enter ( &(name) );\
+                    } while (0)
+
+#define UNLOCK(name)  do { \
+                         _gpgme_sema_cs_leave ( &(name) );\
+                    } while (0)
+
+
+void _gpgme_sema_subsystem_init (void);
+void _gpgme_sema_cs_enter ( struct critsect_s *s );
+void _gpgme_sema_cs_leave ( struct critsect_s *s );
+void _gpgme_sema_cs_destroy ( struct critsect_s *s );
+
+
+#endif /* SEMA_H */
+
+
+
+
+
index cef099bb64e89394be1b8a8e34e2e9dcbcd78e4c..5b6c61e80b95dca1782ec59005f97d9566329fda 100644 (file)
@@ -33,12 +33,17 @@ struct  sign_result_s {
     int no_passphrase;
     int okay;
     void *last_pw_handle;
+    char *userid_hint;
+    char *passphrase_info;
+    int bad_passphrase;
 };
 
 
 void
 _gpgme_release_sign_result ( SignResult res )
 {
+    xfree (res->userid_hint);
+    xfree (res->passphrase_info);
     xfree (res);
 }
 
@@ -64,23 +69,41 @@ sign_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args )
       case STATUS_EOF:
         break;
 
+      case STATUS_USERID_HINT:
+        xfree (ctx->result.sign->userid_hint);
+        if (!(ctx->result.sign->userid_hint = xtrystrdup (args)) )
+            ctx->out_of_core = 1;
+        break;
+
+      case STATUS_BAD_PASSPHRASE:
+        ctx->result.sign->bad_passphrase++;
+        break;
+
+      case STATUS_GOOD_PASSPHRASE:
+        ctx->result.sign->bad_passphrase = 0;
+        break;
+
       case STATUS_NEED_PASSPHRASE:
       case STATUS_NEED_PASSPHRASE_SYM:
-        fprintf (stderr, "Ooops: Need a passphrase -  use the agent\n");
+        xfree (ctx->result.sign->passphrase_info);
+        if (!(ctx->result.sign->passphrase_info = xtrystrdup (args)) )
+            ctx->out_of_core = 1;
         break;
 
       case STATUS_MISSING_PASSPHRASE:
-        fprintf (stderr, "Missing passphrase - stop\n");;
+        DEBUG0 ("missing passphrase - stop\n");
         ctx->result.sign->no_passphrase = 1;
         break;
 
-      case STATUS_SIG_CREATED:
-        /* fixme: we have no error return for multible signatures */
+      case STATUS_SIG_CREATED: 
+        /* fixme: we have no error return for multiple signatures */
         ctx->result.sign->okay =1;
+        /* parse the line and save the information 
+         * <type> <pubkey algo> <hash algo> <class> <timestamp> <key fpr>
+         */
         break;
 
       default:
-        fprintf (stderr, "sign_status: code=%d not handled\n", code );
         break;
     }
 }
@@ -115,10 +138,32 @@ command_handler ( void *opaque, GpgStatusCode code, const char *key )
         return NULL;
     
     if ( code == STATUS_GET_HIDDEN && !strcmp (key, "passphrase.enter") ) {
-        return c->passphrase_cb (c->passphrase_cb_value,
-                                 "Please enter your Friedrich Willem!",
-                                 &c->result.sign->last_pw_handle );
-   }
+        const char *userid_hint = c->result.sign->userid_hint;
+        const char *passphrase_info = c->result.sign->passphrase_info;
+        int bad_passphrase = c->result.sign->bad_passphrase;
+        char *buf;
+        const char *s;
+
+        c->result.sign->bad_passphrase = 0;
+        if (!userid_hint)
+            userid_hint = "[User ID hint missing]";
+        if (!passphrase_info)
+            passphrase_info = "[passphrase info missing]";
+        buf = xtrymalloc ( 20 + strlen (userid_hint)
+                           + strlen (passphrase_info) + 3);
+        if (!buf) {
+            c->out_of_core = 1;
+            return NULL;
+        }
+        sprintf (buf, "%s\n%s\n%s",
+                 bad_passphrase? "TRY_AGAIN":"ENTER",
+                 userid_hint, passphrase_info );
+
+        s = c->passphrase_cb (c->passphrase_cb_value,
+                              buf, &c->result.sign->last_pw_handle );
+        xfree (buf);
+        return s;
+    }
     
     return NULL;
 }
index a9da7da68af1ef8cbe5eca931362c35a03548181..70c3a004b01ca51fc95f551d060e3cdbd2a57b6f 100644 (file)
@@ -87,7 +87,7 @@ gpgme_signers_enum (const GpgmeCtx c, int seq )
     int i;
 
     return_null_if_fail (c);
-    return_null_if_fail (seq<0);
+    return_null_if_fail (seq>=0);
 
     if (!c->signers)
         c->signers_size = 0;
index 39e18e83f7502d117a78ffd3b99a2e662b1f6ddc..65bfa2b4190aca4958013d4f6edec7dc6fbffaef 100644 (file)
@@ -40,6 +40,57 @@ void  _gpgme_free ( void *a );
 
 #define DIM(v) (sizeof(v)/sizeof((v)[0]))
 #define DIMof(type,member)   DIM(((type *)0)->member)
+#ifndef STR
+  #define STR(v) #v
+#endif
+#define STR2(v) STR(v)
+
+
+void _gpgme_debug (int level, const char *format, ...);
+void _gpgme_debug_begin ( void **helper, int level, const char *text);
+int  _gpgme_debug_enabled ( void **helper );
+void _gpgme_debug_add (void **helper, const char *format, ...);
+void _gpgme_debug_end (void **helper, const char *text);
+
+#define DEBUG0(x)                     _gpgme_debug (1,  __FILE__ ":" \
+     STR2 (__LINE__) ": " x )
+#define DEBUG1(x,a)                   _gpgme_debug (1,  __FILE__ ":" \
+     STR2 (__LINE__)": " x, (a) )
+#define DEBUG2(x,a,b)                 _gpgme_debug (1,  __FILE__ ":" \
+     STR2 (__LINE__) ": " x, (a), (b) )
+#define DEBUG3(x,a,b,c)               _gpgme_debug (1,  __FILE__ ":" \
+     STR2 (__LINE__) ": " x, (a), (b), (c) )
+#define DEBUG4(x,a,b,c,d)             _gpgme_debug (1,  __FILE__ ":" \
+     STR2 (__LINE__) ": " x, (a), (b), (c), (d) )
+#define DEBUG5(x,a,b,c,d,e)           _gpgme_debug (1,  __FILE__ ":" \
+     STR2 (__LINE__) ": " x, (a), (b), (c), (d), (e) )
+#define DEBUG6(x,a,b,c,d,e,f)         _gpgme_debug (1,  __FILE__ ":" \
+     STR2 (__LINE__) ": " x, (a), (b), (c), (d), (e), (f) )
+#define DEBUG7(x,a,b,c,d,e,f,g)       _gpgme_debug (1,  __FILE__ ":" \
+     STR2 (__LINE__) ": " x, (a), (b), (c), (d), (e), (f), (g) )
+#define DEBUG8(x,a,b,c,d,e,f,g,h)      _gpgme_debug (1,  __FILE__ ":" \
+     STR2 (__LINE__) ": " x, (a), (b), (c), (d), (e), (f), (g), (h) )
+#define DEBUG9(x,a,b,c,d,e,f,g,h,i)    _gpgme_debug (1,  __FILE__ ":" \
+     STR2 (__LINE__) ": " x, (a), (b), (c), (d), (e), (f), (g), (h), (i) )
+#define DEBUG10(x,a,b,c,d,e,f,g,h,i,j) _gpgme_debug (1,  __FILE__ ":" \
+     STR2 (__LINE__) ": " x, (a), (b), (c), (d), (e), (f), (g), (h), (i), (j) )
+
+#define DEBUG_BEGIN(y,x)  _gpgme_debug_begin (&(y), 1,  __FILE__ ":" \
+     STR2 (__LINE__) ": " x )
+#define DEBUG_ENABLED(y)  _gpgme_debug_enabled(&(y))
+#define DEBUG_ADD0(y,x)                 _gpgme_debug_add (&(y), (x), \
+                       )
+#define DEBUG_ADD1(y,x,a)               _gpgme_debug_add (&(y), (x), \
+                      (a) )
+#define DEBUG_ADD2(y,x,a,b)             _gpgme_debug_add (&(y), (x), \
+                      (a), (b) )
+#define DEBUG_ADD3(y,x,a,b,c)           _gpgme_debug_add (&(y), (x), \
+                      (a), (b), (c) )
+#define DEBUG_ADD4(y,x,a,b,c,d)         _gpgme_debug_add (&(y), (x), \
+                      (a), (b), (c), (d) )
+#define DEBUG_ADD5(y,x,a,b,c,d,e)       _gpgme_debug_add (&(y), (x), \
+                      (a), (b), (c), (d), (e) )
+#define DEBUG_END(y,x)  _gpgme_debug_end (&(y), (x) )
 
 
 
index fad5cd9b7900da38755c847ca7821132e7d1ad56..cc2039593a4a97352b79bead9c77002d5fe964c0 100644 (file)
@@ -129,7 +129,6 @@ verify_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args )
 
       default:
         /* ignore all other codes */
-        fprintf (stderr, "verify_status: code=%d not handled\n", code );
         break;
     }
 }
index 0dfe4a360737ee1d091805d5431b792c04991cc2..f1c839703a55b2c809c0009ff051df3c3afacb11 100644 (file)
@@ -27,6 +27,7 @@
 #include "gpgme.h"
 #include "context.h"
 #include "rungpg.h"
+#include "sema.h"
 #include "util.h"
 
 
@@ -36,6 +37,18 @@ static char *tmp_engine_version;
 static const char *get_engine_info (void);
 
 
+static void
+do_subsystem_inits (void)
+{
+    static int done = 0;
+
+    if (done)
+        return;
+    _gpgme_sema_subsystem_init ();
+}
+
+
+
 static const char*
 parse_version_number ( const char *s, int *number )
 {
@@ -108,13 +121,17 @@ compare_versions ( const char *my_version, const char *req_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.
+ * the version string is simply returned.  It is a pretty good idea to
+ * run this function as soon as poossible, becuase it also intializes 
+ * some subsystems.  In a multithreaded environment if should be called
+ * before the first thread is created.
  * 
  * Return value: The version string or NULL
  **/
 const char *
 gpgme_check_version ( const char *req_version )
 {
+    do_subsystem_inits ();
     return compare_versions ( VERSION, req_version );
 }
 
@@ -134,6 +151,7 @@ gpgme_check_version ( const char *req_version )
 const char *
 gpgme_get_engine_info ()
 {
+    do_subsystem_inits ();
     return get_engine_info ();
 }
 
index 9df6c981da878a7c7210f6604237e733599e067d..c16e4415a873876a3521665e36406d892cade83f 100644 (file)
 #include "syshdr.h"
 
 #include "util.h"
+#include "sema.h"
 #include "io.h"
 
-#define DEBUG_SELECT_ENABLED 1
-
-#if DEBUG_SELECT_ENABLED
-# define DEBUG_SELECT(a) fprintf a
-#else
-# define DEBUG_SELECT(a) do { } while(0)
-#endif
-
-
 
 /* 
  * We assume that a HANDLE can be represented by an int which should be true   
 #define pid_to_handle(a) ((HANDLE)(a))
 #define handle_to_pid(a) ((int)(a))
 
+#define READBUF_SIZE 4096
+
+struct reader_context_s {
+    HANDLE file_hd;
+    HANDLE thread_hd;  
+    DECLARE_LOCK (mutex);
+    
+    int eof;
+    int error;
+    int error_code;
+
+    HANDLE have_data_ev;  /* manually reset */
+    int    have_data_flag;  /* FIXME: is there another way to check whether
+                               it has been signaled? */
+    HANDLE have_space_ev; /* auto reset */
+    size_t readpos, writepos;
+    char buffer[READBUF_SIZE];
+};
+
+
+#define MAX_READERS 20
+static struct {
+    volatile int used;
+    int fd;
+    struct reader_context_s *context;
+} reader_table[MAX_READERS];
+static int reader_table_size= MAX_READERS;
+DEFINE_STATIC_LOCK (reader_table_lock);
+
+static HANDLE
+set_synchronize (HANDLE h)
+{
+    HANDLE tmp;
+    
+    /* For NT we have to set the sync flag.  It seems that the only
+     * way to do it is by duplicating the handle.  Tsss.. */
+    if (!DuplicateHandle( GetCurrentProcess(), h,
+                          GetCurrentProcess(), &tmp,
+                          SYNCHRONIZE, FALSE, 0 ) ) {
+        DEBUG1 ("** Set SYNCRONIZE failed: ec=%d\n", (int)GetLastError());
+    }
+    else {
+        CloseHandle (h);
+        h = tmp;
+    }
+    return h;
+}
+
+
+
+static DWORD CALLBACK 
+reader (void *arg)
+{
+    struct reader_context_s *c = arg;
+    int nbytes;
+    DWORD nread;
+
+    DEBUG2 ("reader thread %p for file %p started", c->thread_hd, c->file_hd );
+    for (;;) {
+        LOCK (c->mutex);
+        /* leave a one byte gap so that we can see wheter it is empty or full*/
+        if ((c->writepos + 1) % READBUF_SIZE == c->readpos) { 
+            /* wait for space */
+            ResetEvent (c->have_space_ev);
+            UNLOCK (c->mutex);
+            DEBUG1 ("reader thread %p: waiting for space ...", c->thread_hd );
+            WaitForSingleObject (c->have_space_ev, INFINITE);
+            DEBUG1 ("reader thread %p: got space", c->thread_hd );
+            LOCK (c->mutex);
+               }
+        nbytes = (c->readpos + READBUF_SIZE - c->writepos-1) % READBUF_SIZE;
+        if ( nbytes > READBUF_SIZE - c->writepos )
+            nbytes = READBUF_SIZE - c->writepos;
+        UNLOCK (c->mutex);
+
+        DEBUG2 ("reader thread %p: reading %d bytes", c->thread_hd, nbytes );
+        if ( !ReadFile ( c->file_hd,
+                         c->buffer+c->writepos, nbytes, &nread, NULL) ) {
+            c->error = 1;
+            c->error_code = (int)GetLastError ();
+            DEBUG2 ("reader thread %p: read error: ec=%d",
+                    c->thread_hd, c->error_code );
+            break;
+        }
+        if ( !nread ) {
+            c->eof = 1;
+            DEBUG1 ("reader thread %p: got eof", c->thread_hd );
+            break;
+        }
+        DEBUG2 ("reader thread %p: got %d bytes", c->thread_hd, (int)nread );
+      
+        LOCK (c->mutex);
+        c->writepos = (c->writepos + nread) % READBUF_SIZE;
+        c->have_data_flag = 1;
+        SetEvent (c->have_data_ev);
+        UNLOCK (c->mutex);
+    }
+    DEBUG1 ("reader thread %p ended", c->thread_hd );
+
+    return 0;
+}
+
+
+static struct reader_context_s *
+create_reader (HANDLE fd)
+{
+    struct reader_context_s *c;
+    SECURITY_ATTRIBUTES sec_attr;
+    DWORD tid;
+
+    DEBUG1 ("creating new read thread for file handle %p", fd );
+    memset (&sec_attr, 0, sizeof sec_attr );
+    sec_attr.nLength = sizeof sec_attr;
+    sec_attr.bInheritHandle = FALSE;
+
+    c = xtrycalloc (1, sizeof *c );
+    if (!c)
+        return NULL;
+
+    c->file_hd = fd;
+    c->have_data_ev = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
+    c->have_space_ev = CreateEvent (&sec_attr, FALSE, TRUE, NULL);
+    if (!c->have_data_ev || !c->have_space_ev) {
+        DEBUG1 ("** CreateEvent failed: ec=%d\n", (int)GetLastError ());
+        if (c->have_data_ev)
+            CloseHandle (c->have_data_ev);
+        if (c->have_space_ev)
+            CloseHandle (c->have_space_ev);
+        xfree (c);
+        return NULL;
+    }
+
+    c->have_data_ev = set_synchronize (c->have_data_ev);
+    INIT_LOCK (c->mutex);
+
+    c->thread_hd = CreateThread (&sec_attr, 0, reader, c, 0, &tid );
+    if (!c->thread_hd) {
+        DEBUG1 ("** failed to create reader thread: ec=%d\n",
+                 (int)GetLastError ());
+        DESTROY_LOCK (c->mutex);
+        if (c->have_data_ev)
+            CloseHandle (c->have_data_ev);
+        if (c->have_space_ev)
+            CloseHandle (c->have_space_ev);
+        xfree (c);
+        return NULL;
+    }    
+
+    return c;
+}
+
+
+/* 
+ * Find a reader context or create a new one 
+ * Note that the reader context will last until a io_close.
+ */
+static struct reader_context_s *
+find_reader (int fd, int start_it)
+{
+    int i;
+
+    for (i=0; i < reader_table_size ; i++ ) {
+        if ( reader_table[i].used && reader_table[i].fd == fd )
+            return reader_table[i].context;
+    }
+    if (!start_it)
+        return NULL;
+
+    LOCK (reader_table_lock);
+    for (i=0; i < reader_table_size; i++ ) {
+        if (!reader_table[i].used) {
+            reader_table[i].fd = fd;
+            reader_table[i].context = create_reader (fd_to_handle (fd));
+            reader_table[i].used = 1;
+            UNLOCK (reader_table_lock);
+            return reader_table[i].context;
+        }
+    }
+    UNLOCK (reader_table_lock);
+    return NULL;
+}
+
+
 
 int
 _gpgme_io_read ( int fd, void *buffer, size_t count )
 {
-    int nread = 0;
-    HANDLE h = fd_to_handle (fd);
+    int nread;
+    struct reader_context_s *c = find_reader (fd,1);
 
-    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 ());
+    DEBUG2 ("fd %d: about to read %d bytes\n", fd, (int)count );
+    if ( !c ) {
+        DEBUG0 ( "no reader thread\n");
         return -1;
     }
-    DEBUG_SELECT ((stderr,"** fd %d:           got %d bytes\n", fd, nread ));
+
+    LOCK (c->mutex);
+    if (c->readpos == c->writepos) { /* no data avail */
+        UNLOCK (c->mutex);
+        DEBUG2 ("fd %d: waiting for data from thread %p", fd, c->thread_hd);
+        WaitForSingleObject (c->have_data_ev, INFINITE);
+        DEBUG2 ("fd %d: data from thread %p available", fd, c->thread_hd);
+        LOCK (c->mutex);
+        if (c->readpos == c->writepos && !c->eof && !c->error) {
+            UNLOCK (c->mutex);
+            if (c->eof) 
+                return 0;
+            return -1;
+       }
+    }
+  
+    nread = c->readpos < c->writepos? c->writepos - c->readpos
+                                    : READBUF_SIZE - c->readpos;
+    if (nread > count)
+        nread = count;
+    memcpy (buffer, c->buffer+c->readpos, nread);
+    c->readpos = (c->readpos + nread) % READBUF_SIZE;
+    if (c->readpos == c->writepos) {
+        c->have_data_flag = 0;
+        ResetEvent (c->have_data_ev);
+    }
+    if (nread)
+        SetEvent (c->have_space_ev);
+    UNLOCK (c->mutex);
+
+    DEBUG2 ("fd %d: got %d bytes\n", fd, nread );
 
     return nread;
 }
@@ -79,17 +284,18 @@ _gpgme_io_read ( int fd, void *buffer, size_t count )
 int
 _gpgme_io_write ( int fd, const void *buffer, size_t count )
 {
-    int nwritten;
+    DWORD nwritten;
     HANDLE h = fd_to_handle (fd);
 
-    DEBUG_SELECT ((stderr,"** fd %d: about to write %d bytes\n", fd, (int)count ));
+    DEBUG2 ("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 ());
+        DEBUG1 ("WriteFile failed: ec=%d\n", (int)GetLastError ());
         return -1;
     }
-    DEBUG_SELECT ((stderr,"** fd %d:          wrote %d bytes\n", fd, nwritten ));
+    DEBUG2 ("fd %d:          wrote %d bytes\n",
+                   fd, (int)nwritten );
 
-    return nwritten;
+    return (int)nwritten;
 }
 
 int
@@ -110,8 +316,7 @@ _gpgme_io_pipe ( int filedes[2], int inherit_idx )
         if (!DuplicateHandle( GetCurrentProcess(), r,
                               GetCurrentProcess(), &h, 0,
                               TRUE, DUPLICATE_SAME_ACCESS ) ) {
-            fprintf (stderr, "** DuplicateHandle failed: ec=%d\n",
-                     (int)GetLastError());
+            DEBUG1 ("DuplicateHandle failed: ec=%d\n", (int)GetLastError());
             CloseHandle (r);
             CloseHandle (w);
             return -1;
@@ -124,8 +329,7 @@ _gpgme_io_pipe ( int filedes[2], int inherit_idx )
         if (!DuplicateHandle( GetCurrentProcess(), w,
                               GetCurrentProcess(), &h, 0,
                               TRUE, DUPLICATE_SAME_ACCESS ) ) {
-            fprintf (stderr, "** DuplicateHandle failed: ec=%d\n",
-                     (int)GetLastError());
+            DEBUG1 ("DuplicateHandle failed: ec=%d\n", (int)GetLastError());
             CloseHandle (r);
             CloseHandle (w);
             return -1;
@@ -136,8 +340,8 @@ _gpgme_io_pipe ( int filedes[2], int inherit_idx )
 
     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 ));
+    DEBUG5 ("CreatePipe %p %p %d %d inherit=%d\n", r, w,
+                   filedes[0], filedes[1], inherit_idx );
     return 0;
 }
 
@@ -147,9 +351,11 @@ _gpgme_io_close ( int fd )
     if ( fd == -1 )
         return -1;
 
-    DEBUG_SELECT ((stderr,"** closing handle for fd %d\n", fd));
+    DEBUG1 ("** closing handle for fd %d\n", fd);
+    /* fixme: destroy thread */
+
     if ( !CloseHandle (fd_to_handle (fd)) ) { 
-        fprintf (stderr, "** CloseHandle for fd %d failed: ec=%d\n",
+        DEBUG2 ("CloseHandle for fd %d failed: ec=%d\n",
                  fd, (int)GetLastError ());
         return -1;
     }
@@ -230,16 +436,16 @@ _gpgme_io_spawn ( const char *path, char **argv,
     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 ));
+            DEBUG1 ("using %d for stdin", 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 ));
+            DEBUG1 ("using %d for stdout", 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 ));
+            DEBUG1 ("using %d for stderr", fd_child_list[i].fd );
             duped_stderr = 1;
         }
     }
@@ -250,7 +456,7 @@ _gpgme_io_spawn ( const char *path, char **argv,
         memset (&sa, 0, sizeof sa );
         sa.nLength = sizeof sa;
         sa.bInheritHandle = TRUE;
-        hnul = CreateFile ( "/dev/nul",
+        hnul = CreateFile ( "nul",
                             GENERIC_READ|GENERIC_WRITE,
                             FILE_SHARE_READ|FILE_SHARE_WRITE,
                             &sa,
@@ -258,27 +464,23 @@ _gpgme_io_spawn ( const char *path, char **argv,
                             FILE_ATTRIBUTE_NORMAL,
                             NULL );
         if ( hnul == INVALID_HANDLE_VALUE ) {
-            fprintf (stderr,"can't open `/dev/nul': ec=%d\n",
-                     (int)GetLastError () );
+            DEBUG1 ("can't open `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 ));
+            DEBUG1 ("using %d for dummy stdin", (int)hnul );
         }
         /* We normally don't want all the normal output */
         if ( !duped_stderr ) {
-            if (!debug_me) {
-                si.hStdError = hnul;
-                DEBUG_SELECT ((stderr,"** using %d for stderr\n", (int)hnul ));
-            }
+            si.hStdError = hnul;
+            DEBUG1 ("using %d for dummy stderr", (int)hnul );
         }
     }
 
-    DEBUG_SELECT ((stderr,"** CreateProcess ...\n"));
-    DEBUG_SELECT ((stderr,"** args=`%s'\n", arg_string));
+    DEBUG1 ("CreateProcess, args=`%s'", arg_string);
     cr_flags |= CREATE_SUSPENDED; 
     if ( !CreateProcessA (GPG_PATH,
                           arg_string,
@@ -291,8 +493,7 @@ _gpgme_io_spawn ( const char *path, char **argv,
                           &si,           /* startup information */
                           &pi            /* returns process information */
         ) ) {
-        fprintf (stderr, "** CreateProcess failed: ec=%d\n",
-                 (int) GetLastError ());
+        DEBUG1 ("CreateProcess failed: ec=%d\n", (int) GetLastError ());
         xfree (arg_string);
         return -1;
     }
@@ -300,31 +501,28 @@ _gpgme_io_spawn ( const char *path, char **argv,
     /* 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());
+            DEBUG1 ("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++ ) {
-        DEBUG_SELECT ((stderr,"** Closing fd %d\n", fd_parent_list[i].fd ));
+        DEBUG1 ("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());
+            DEBUG1 ("CloseHandle failed: ec=%d", (int)GetLastError());
     }
 
-    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));
+    DEBUG4 ("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 ());
+        DEBUG1 ("ResumeThread failed: ec=%d\n", (int)GetLastError ());
     }
 
     if ( !CloseHandle (pi.hThread) ) { 
-        fprintf (stderr, "** CloseHandle of thread failed: ec=%d\n",
+        DEBUG1 ("CloseHandle of thread failed: ec=%d\n",
                  (int)GetLastError ());
     }
 
@@ -345,30 +543,29 @@ _gpgme_io_waitpid ( int pid, int hang, int *r_status, int *r_signal )
     code = WaitForSingleObject ( proc, hang? INFINITE : 0 );
     switch (code) {
       case WAIT_FAILED:
-        fprintf (stderr, "** WFSO pid=%d failed: %d\n",
-                 (int)pid, (int)GetLastError () );
+        DEBUG2 ("WFSO pid=%d failed: %d\n", (int)pid, (int)GetLastError () );
         break;
 
       case WAIT_OBJECT_0:
         if (!GetExitCodeProcess (proc, &exc)) {
-            fprintf (stderr, "** GECP pid=%d failed: ec=%d\n",
-                     (int)pid, (int)GetLastError () );
+            DEBUG2 ("** GECP pid=%d failed: ec=%d\n",
+                    (int)pid, (int)GetLastError () );
             *r_status = 4; 
         }
         else {
-            DEBUG_SELECT ((stderr,"** GECP pid=%d exit code=%d\n",
-                           (int)pid,  exc));
+            DEBUG2 ("GECP pid=%d exit code=%d\n", (int)pid,  exc);
             *r_status = exc;
         }
         ret = 1;
         break;
 
       case WAIT_TIMEOUT:
-        DEBUG_SELECT ((stderr,"** WFSO pid=%d timed out\n", (int)pid));
+        if (hang)
+            DEBUG1 ("WFSO pid=%d timed out\n", (int)pid);
         break;
 
       default:
-        fprintf (stderr, "** WFSO pid=%d returned %d\n", (int)pid, code );
+        DEBUG2 ("WFSO pid=%d returned %d\n", (int)pid, code );
         break;
     }
     return ret;
@@ -384,40 +581,50 @@ _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 */
+#if 1
     HANDLE waitbuf[MAXIMUM_WAIT_OBJECTS];
     int code, nwait;
     int i, any, any_write;
     int count;
+    void *dbg_help;
 
  restart:
-    DEBUG_SELECT ((stderr, "gpgme:select on [ "));
+    DEBUG_BEGIN (dbg_help, "select on [ ");
     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 ( fds[i].for_read ) {
             if ( nwait >= DIM (waitbuf) ) {
-                DEBUG_SELECT ((stderr,stderr, "oops ]\n" ));
-                fprintf (stderr, "** Too many objects for WFMO!\n" );
+                DEBUG_END (dbg_help, "oops ]");
+                DEBUG0 ("Too many objects for WFMO!" );
                 return -1;
             }
             else {
-                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 ));
+                if ( fds[i].for_read ) {
+                    struct reader_context_s *c = find_reader (fds[i].fd,1);
+                    
+                    if (!c) { 
+                        DEBUG1 ("no reader thread for fd %d", fds[i].fd);
+                    }
+                    else {
+                        waitbuf[nwait++] = c->have_data_ev;
+                    }
+                }
+                DEBUG_ADD2 (dbg_help, "%c%d ",
+                               fds[i].for_read? 'r':'w',fds[i].fd );
                 any = 1;
             }
         }
         fds[i].signaled = 0;
     }
-    DEBUG_SELECT ((stderr, "]\n" ));
+    DEBUG_END (dbg_help, "]");
     if (!any) 
         return 0;
 
     count = 0;
+    /* no way to see whether a handle is ready for writing, signal all */
     for ( i=0; i < nfds; i++ ) {
         if ( fds[i].fd == -1 ) 
             continue;
@@ -428,64 +635,7 @@ _gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds )
         }
     }
     code = WaitForMultipleObjects ( nwait, waitbuf, 0, any_write? 0:1000);
-    if (code == WAIT_FAILED ) {
-        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" );
-    }  
-    else if ( code >= WAIT_OBJECT_0 && code < WAIT_OBJECT_0 + nwait ) {
+    if ( code >= WAIT_OBJECT_0 && code < WAIT_OBJECT_0 + nwait ) {
         /* This WFMO is a really silly function:  It does return either
          * the index of the signaled object or if 2 objects have been
          * signalled at the same time, the index of the object with the
@@ -503,13 +653,32 @@ _gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds )
             }
         }
         if (!any) {
-            fprintf (stderr,
-                     "** Oops: No signaled objects found after WFMO\n");
+            DEBUG0 ("Oops: No signaled objects found after WFMO");
             count = -1;
         }
     }
+    else if ( code == WAIT_TIMEOUT ) {
+        DEBUG0 ("WFMO timed out\n" );
+    }  
+    else if (code == WAIT_FAILED ) {
+        int le = (int)GetLastError ();
+        if ( le == ERROR_INVALID_HANDLE ) {
+            int k, j = handle_to_fd (waitbuf[i]);
+                    
+            DEBUG1 ("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;
+                }
+            }
+            DEBUG0 (" oops, or not???\n");
+        }
+        DEBUG1 ("WFMO failed: %d\n", le );
+        count = -1;
+    }
     else {
-        fprintf (stderr, "** WFMO returned %d\n", code );
+        DEBUG1 ("WFMO returned %d\n", code );
         count = -1;
     }
 
@@ -552,15 +721,14 @@ _gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds )
             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 ());
+                DEBUG1 ("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 );*/
+                DEBUG2 ("fd %d has %d bytes to read\n",  fds[i].fd, navail );
                 fds[i].signaled = 1;
                 count++;
             }
diff --git a/gpgme/w32-sema.c b/gpgme/w32-sema.c
new file mode 100644 (file)
index 0000000..3b905c9
--- /dev/null
@@ -0,0 +1,123 @@
+/* w32-sema.c 
+ *     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>
+#ifdef HAVE_DOSISH_SYSTEM
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <windows.h>
+#include "syshdr.h"
+
+#include "util.h"
+#include "sema.h"
+
+static void
+sema_fatal (const char *text)
+{
+    fprintf (stderr, "sema.c: %s\n", text);
+    abort ();
+}
+
+
+static void
+critsect_init (struct critsect_s *s)
+{
+    CRITICAL_SECTION *mp;
+    static CRITICAL_SECTION init_lock;
+    static int initialized;
+    
+    if (!initialized) {
+        /* the very first time we call this function, we assume that only
+         * one thread is running, so that we can bootstrap the semaphore code 
+         */
+        InitializeCriticalSection (&init_lock);
+        initialized = 1;
+    }
+    if (!s)
+        return; /* we just want to initialize ourself */
+
+    /* first test whether it is really not initialized */
+    EnterCriticalSection (&init_lock);
+    if ( s->private ) {
+        LeaveCriticalSection (&init_lock);
+        return;
+    }
+    /* now init it */
+    mp = xtrymalloc ( sizeof *mp );
+    if (!mp) {
+        LeaveCriticalSection (&init_lock);
+        sema_fatal ("out of core while creating critical section lock");
+    }
+    InitializeCriticalSection (mp);
+    s->private = mp;
+    LeaveCriticalSection (&init_lock);
+}
+
+void
+_gpgme_sema_subsystem_init ()
+{
+    /* fixme: we should check that there is only one thread running */
+    critsect_init (NULL);
+}
+
+
+void
+_gpgme_sema_cs_enter ( struct critsect_s *s )
+{
+    if (!s->private)
+        critsect_init (s);
+    EnterCriticalSection ( (CRITICAL_SECTION*)s->private );
+}
+
+void
+_gpgme_sema_cs_leave (struct critsect_s *s)
+{
+    if (!s->private)
+        critsect_init (s);
+    LeaveCriticalSection ( (CRITICAL_SECTION*)s->private );
+}
+
+void
+_gpgme_sema_cs_destroy ( struct critsect_s *s )
+{
+    if (s && s->private) {
+        DeleteCriticalSection ((CRITICAL_SECTION*)s->private);
+        xfree (s->private);
+        s->private = NULL;
+    }
+}
+
+
+
+#endif /*HAVE_DOSISH_SYSTEM*/
+
+
+
+
+
index 978174f328c9c78ec48c55833f31fe17d5e297fb..fb7b79d530599872c17003ecbe3cf308809f9d97 100644 (file)
@@ -68,6 +68,7 @@ doit ( GpgmeCtx ctx, const char *pattern )
             s = gpgme_key_get_string_attr (key, GPGME_ATTR_COMMENT, NULL, i );
             printf ("<!-- comment.%d=%s -->\n", i, s );
         }
+
         printf ("<!-- End key object (%p) -->\n", key );
         gpgme_key_release (key);
     }