--- /dev/null
+* 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.
+
+
./configure --host=${host} --target=${target} ${disable_foo_tests} \
--bindir=${crossbindir} --libdir=${crosslibdir} \
- --includedir=${crossincdir} $*
+ --includedir=${crossincdir} --enable-maintainer-mode $*
exit $?
fi
+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.
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 \
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
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;
* @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.
**/
--- /dev/null
+/* 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;
+}
+
break;
case STATUS_MISSING_PASSPHRASE:
- fprintf (stderr, "Missing passphrase - stop\n");;
+ DEBUG0 ("missing passphrase - stop\n");;
ctx->result.decrypt->no_passphrase = 1;
break;
buf, &c->result.decrypt->last_pw_handle );
xfree (buf);
return s;
- }
+ }
return NULL;
}
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 );
}
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 */
}
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 */
}
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;
#define GPGME_H
#ifdef _MSC_VER
- typedef long off_t
+ typedef long off_t;
#else
# include <sys/types.h>
#endif
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 {
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 */
-GpgmeError
-_gpgme_key_new( GpgmeKey *r_key )
+static GpgmeError
+key_new ( GpgmeKey *r_key, int secret )
{
GpgmeKey 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 )
{
}
-struct subkey_s *
-_gpgme_key_add_subkey (GpgmeKey key)
+static struct subkey_s *
+add_subkey (GpgmeKey key, int secret)
{
struct subkey_s *k, *kk;
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 )
_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 );
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 );
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;
}
if (u)
val = u->validity;
break;
+ case GPGME_ATTR_IS_SECRET:
+ val = !!key->secret;
+ break;
default:
break;
}
struct subkey_s {
struct subkey_s *next;
+ unsigned int secret:1;
struct {
unsigned int revoked:1 ;
unsigned int expired:1 ;
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 );
default:
/* ignore all other codes */
- fprintf (stderr, "keylist_status: code=%d not handled\n", code );
break;
}
}
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)) ) {
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;
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 */
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);
_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;
/*-- 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 --*/
#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 )
{
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 )
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);
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 */
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 )
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 ) {
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;
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++ ) {
--- /dev/null
+/* 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*/
+
+
+
+
+
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;
}
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 */
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;
}
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;
}
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;
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;
}
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 ) {
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;
}
*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;
}
*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;
}
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;
}
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 */
--- /dev/null
+/* 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 */
+
+
+
+
+
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);
}
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;
}
}
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;
}
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;
#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) )
default:
/* ignore all other codes */
- fprintf (stderr, "verify_status: code=%d not handled\n", code );
break;
}
}
#include "gpgme.h"
#include "context.h"
#include "rungpg.h"
+#include "sema.h"
#include "util.h"
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 )
{
* 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 );
}
const char *
gpgme_get_engine_info ()
{
+ do_subsystem_inits ();
return get_engine_info ();
}
#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;
}
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
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;
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;
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;
}
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;
}
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;
}
}
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,
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,
&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;
}
/* 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 ());
}
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;
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;
}
}
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
}
}
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;
}
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++;
}
--- /dev/null
+/* 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*/
+
+
+
+
+
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);
}