data.c recipient.c \
wait.c wait.h \
encrypt.c \
+ verify.c \
rungpg.c rungpg.h status-table.h \
gpgme.c errors.c
#include "types.h"
#include "rungpg.h" /* for GpgObject */
+typedef enum {
+ RESULT_TYPE_NONE = 0,
+ RESULT_TYPE_VERIFY,
+} ResultType;
+
+
/* Currently we need it at several places, so we put the definition
* into this header file */
struct gpgme_context_s {
int initialized;
int pending; /* a gpg request is still pending */
-
+
+ /* at some points we need to allocate memory but we are not
+ * able to handle a malloc problem at that point, so we set this
+ * flag to indicate this condition */
+ int out_of_core;
+
GpgObject gpg; /* the running gpg process */
int verbosity; /* level of verbosity to use */
int use_armor; /* use armoring */
+
+
+
+ ResultType result_type;
+ union {
+ VerifyResult verify;
+ } result;
};
GpgmeDataType type;
GpgmeDataMode mode;
size_t readpos;
+ size_t writepos;
+ size_t private_len;
char *private_buffer;
};
#include "context.h"
+#define ALLOC_CHUNK 1024
+
+
/**
* gpgme_new_data:
* @r_dh: Returns a new data object.
xfree (dh);
return mk_error (Out_Of_Core);
}
+ dh->private_len = size;
memcpy (dh->private_buffer, buffer, size );
dh->data = dh->private_buffer;
+ dh->writepos = size;
}
else {
dh->data = buffer;
return dh->mode;
}
+GpgmeError
+gpgme_rewind_data ( GpgmeData dh )
+{
+ if ( !dh )
+ return mk_error (Invalid_Value);
+ /* Fixme: We should check whether rewinding does make sense for the
+ * data type */
+ dh->readpos = 0;
+ return 0;
+}
+
+GpgmeError
+gpgme_read_data ( GpgmeData dh, char *buffer, size_t length, size_t *nread )
+{
+ size_t nbytes;
+
+ if ( !dh )
+ return mk_error (Invalid_Value);
+ nbytes = dh->len - dh->readpos;
+ if ( !nbytes ) {
+ *nread = 0;
+ return mk_error(EOF);
+ }
+ if (nbytes > length)
+ nbytes = length;
+ memcpy ( buffer, dh->data + dh->readpos, nbytes );
+ *nread = nbytes;
+ dh->readpos += nbytes;
+ return 0;
+}
GpgmeError
-_gpgme_append_data ( GpgmeData dh, const char *buf, size_t length )
+_gpgme_append_data ( GpgmeData dh, const char *buffer, size_t length )
{
assert (dh);
if ( dh->type == GPGME_DATA_TYPE_NONE ) {
/* convert it to a mem data type */
+ assert (!dh->private_buffer);
+ dh->type = GPGME_DATA_TYPE_MEM;
+ dh->private_len = length < ALLOC_CHUNK? ALLOC_CHUNK : length;
+ dh->private_buffer = xtrymalloc ( dh->private_len );
+ if (!dh->private_buffer) {
+ dh->private_len = 0;
+ return mk_error (Out_Of_Core);
+ }
+ dh->writepos = 0;
+ dh->data = dh->private_buffer;
}
- else if ( dh->type != GPGME_DATA_TYPE_MEM ) {
+ else if ( dh->type != GPGME_DATA_TYPE_MEM )
return mk_error (Invalid_Type);
- }
-
+
if ( dh->mode != GPGME_DATA_MODE_INOUT
&& dh->mode != GPGME_DATA_MODE_IN )
return mk_error (Invalid_Mode);
+ if ( !dh->private_buffer ) {
+ /* we have to copy it now */
+ assert (dh->data);
+ dh->private_len = dh->len+length;
+ if (dh->private_len < ALLOC_CHUNK)
+ dh->private_len = ALLOC_CHUNK;
+ dh->private_buffer = xtrymalloc ( dh->private_len );
+ if (!dh->private_buffer) {
+ dh->private_len = 0;
+ return mk_error (Out_Of_Core);
+ }
+ dh->writepos = 0;
+ dh->data = dh->private_buffer;
+ }
+
+ /* allocate more memory if needed */
+ if ( dh->writepos + length > dh->private_len ) {
+ char *p;
+ size_t newlen = dh->private_len
+ + (dh->len < ALLOC_CHUNK? ALLOC_CHUNK : length);
+ p = xtryrealloc ( dh->private_buffer, newlen );
+ if ( !p )
+ return mk_error (Out_Of_Core);
+ dh->private_buffer = p;
+ dh->private_len = newlen;
+ dh->data = dh->private_buffer;
+ assert ( !(dh->writepos + length > dh->private_len) );
+ }
+
+ memcpy ( dh->private_buffer + dh->writepos, buffer, length );
+ dh->writepos += length;
+ dh->len += length;
return 0;
}
GpgmeError
-gpgme_req_encrypt ( GpgmeCtx c, GpgmeRecipientSet recp,
+gpgme_start_encrypt ( GpgmeCtx c, GpgmeRecipientSet recp,
GpgmeData plain, GpgmeData ciph )
{
int rc = 0;
_gpgme_gpg_add_arg ( c->gpg, "--output" );
_gpgme_gpg_add_arg ( c->gpg, "-" );
_gpgme_gpg_add_data ( c->gpg, ciph, 1 );
-
+ _gpgme_gpg_add_arg ( c->gpg, "--" );
_gpgme_gpg_add_data ( c->gpg, plain, 0 );
/* and kick off the process */
}
-GpgmeError
-gpgme_wait_encrypt ( GpgmeCtx c, GpgmeData *r_out )
-{
- wait_on_request_or_fail (c);
-
- fprintf (stderr,"gpgme_wait_encrypt: main\n");
-
-
- return 0;
-}
-
-
/**
* gpgme_encrypt:
* @c: The context
gpgme_encrypt ( GpgmeCtx c, GpgmeRecipientSet recp,
GpgmeData in, GpgmeData out )
{
- int rc = gpgme_req_encrypt ( c, recp, in, out );
- if ( !rc )
- rc = gpgme_wait_encrypt ( c, NULL );
+ int rc = gpgme_start_encrypt ( c, recp, in, out );
+ if ( !rc ) {
+ gpgme_wait (c, 1);
+ c->pending = 0;
+ }
return rc;
}
#include "util.h"
#include "context.h"
-
+#include "ops.h"
/**
* gpgme_new_context:
void
gpgme_release_context ( GpgmeCtx c )
{
+
+ _gpgme_gpg_release_object ( c->gpg );
+ _gpgme_release_result ( c );
xfree ( c );
}
-
-
-
-
+void
+_gpgme_release_result ( GpgmeCtx c )
+{
+ switch (c->result_type) {
+ case RESULT_TYPE_NONE:
+ break;
+ case RESULT_TYPE_VERIFY:
+ _gpgme_release_verify_result ( c->result.verify );
+ break;
+ }
+ c->result.verify = NULL;
+ c->result_type = RESULT_TYPE_NONE;
+}
typedef enum {
+ GPGME_EOF = -1,
GPGME_No_Error = 0,
GPGME_General_Error = 1,
GPGME_Out_Of_Core = 2,
const char *buffer, size_t size, int copy );
void gpgme_release_data ( GpgmeData dh );
GpgmeDataType gpgme_query_data_type ( GpgmeData dh );
+GpgmeError gpgme_rewind_data ( GpgmeData dh );
+GpgmeError gpgme_read_data ( GpgmeData dh,
+ char *buffer, size_t length, size_t *nread );
+
/* Basic GnuPG functions */
-GpgmeError gpgme_req_encrypt ( GpgmeCtx c, GpgmeRecipientSet recp,
- GpgmeData in, GpgmeData out );
-GpgmeError gpgme_wait_encrypt ( GpgmeCtx c, GpgmeData *r_out );
+GpgmeError gpgme_start_encrypt ( GpgmeCtx c, GpgmeRecipientSet recp,
+ GpgmeData in, GpgmeData out );
+GpgmeError gpgme_start_verify ( GpgmeCtx c, GpgmeData sig, GpgmeData text );
/* Key management functions */
/* Convenience functions for syncronous usage */
GpgmeError gpgme_encrypt ( GpgmeCtx c, GpgmeRecipientSet recp,
GpgmeData in, GpgmeData out );
+GpgmeError gpgme_verify ( GpgmeCtx c, GpgmeData sig, GpgmeData text );
/* miscellaneous functions */
#include "types.h"
+/*-- gpgme.c --*/
+void _gpgme_release_result ( GpgmeCtx c );
+
/*-- recipient.c --*/
void _gpgme_append_gpg_args_from_recipients (
/*-- data.c --*/
GpgmeDataMode _gpgme_query_data_mode ( GpgmeData dh );
void _gpgme_set_data_mode ( GpgmeData dh, GpgmeDataMode mode );
+GpgmeError _gpgme_append_data ( GpgmeData dh,
+ const char *buffer, size_t length );
-
+/*-- verify.c --*/
+void _gpgme_release_verify_result ( VerifyResult res );
#endif /* OPS_H */
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
+#include <fcntl.h>
#include "gpgme.h"
#include "util.h"
static void kill_gpg ( GpgObject gpg );
static void free_argv ( char **argv );
+static void free_fd_data_map ( struct fd_data_map_s *fd_data_map );
static int gpg_status_handler ( void *opaque, pid_t pid, int fd );
static int gpg_inbound_handler ( void *opaque, pid_t pid, int fd );
static int gpg_outbound_handler ( void *opaque, pid_t pid, int fd );
_gpgme_gpg_new_object ( GpgObject *r_gpg )
{
GpgObject gpg;
- char buf[20];
int rc = 0;
gpg = xtrycalloc ( 1, sizeof *gpg );
gpg->status.fd[0] = -1;
gpg->status.fd[1] = -1;
- /* The name of the beast will be gpg - so put it into argv[0] */
- _gpgme_gpg_add_arg ( gpg, "gpg" );
-
/* allocate the read buffer for the status pipe */
gpg->status.bufsize = 1024;
gpg->status.readpos = 0;
}
gpg->status.eof = 0;
_gpgme_gpg_add_arg ( gpg, "--status-fd" );
- sprintf ( buf, "%d", gpg->status.fd[1]);
- _gpgme_gpg_add_arg ( gpg, buf );
+ {
+ char buf[25];
+ sprintf ( buf, "%d", gpg->status.fd[1]);
+ _gpgme_gpg_add_arg ( gpg, buf );
+ }
+ _gpgme_gpg_add_arg ( gpg, "--batch" );
+ _gpgme_gpg_add_arg ( gpg, "--no-tty" );
leave:
if (rc) {
close (gpg->status.fd[0]);
if (gpg->status.fd[1] != -1 )
close (gpg->status.fd[1]);
- /* fixme: walk over the data map and close all fds */
- xfree (gpg->fd_data_map);
+ free_fd_data_map (gpg->fd_data_map);
kill_gpg (gpg); /* fixme: should be done asyncronously */
xfree (gpg);
}
static void
kill_gpg ( GpgObject gpg )
{
+ #if 0
if ( gpg->running ) {
/* still running? Must send a killer */
kill ( gpg->pid, SIGTERM);
}
gpg->running = 0;
}
+ #endif
}
xfree (argv);
}
+static void
+free_fd_data_map ( struct fd_data_map_s *fd_data_map )
+{
+ int i;
+
+ for (i=0; fd_data_map[i].data; i++ ) {
+ if ( fd_data_map[i].fd != -1 )
+ close (fd_data_map[i].fd);
+ if ( fd_data_map[i].peer_fd != -1 )
+ close (fd_data_map[i].peer_fd);
+ /* don't realease data because this is only a reference */
+ }
+ xfree (fd_data_map);
+}
+
static GpgmeError
build_argv ( GpgObject gpg )
struct fd_data_map_s *fd_data_map;
size_t datac=0, argc=0;
char **argv;
+ int need_special = 0;
if ( gpg->argv ) {
free_argv ( gpg->argv );
gpg->argv = NULL;
}
- /* fixme: release fd_data_map */
+ if (gpg->fd_data_map) {
+ free_fd_data_map (gpg->fd_data_map);
+ gpg->fd_data_map = NULL;
+ }
+ argc++; /* for argv[0] */
for ( a=gpg->arglist; a; a = a->next ) {
argc++;
if (a->data) {
- fprintf (stderr, "build_argv: data\n" );
+ /*fprintf (stderr, "build_argv: data\n" );*/
datac++;
+ if ( a->dup_to == -1 )
+ need_special = 1;
+ }
+ else {
+ /* fprintf (stderr, "build_argv: arg=`%s'\n", a->arg );*/
}
- else
- fprintf (stderr, "build_argv: arg=`%s'\n", a->arg );
}
+ if ( need_special )
+ argc++;
argv = xtrycalloc ( argc+1, sizeof *argv );
if (!argv)
}
argc = datac = 0;
+ argv[argc] = xtrystrdup ( "gpg" ); /* argv[0] */
+ if (!argv[argc]) {
+ xfree (fd_data_map);
+ free_argv (argv);
+ return mk_error (Out_Of_Core);
+ }
+ argc++;
+ if ( need_special ) {
+ argv[argc] = xtrystrdup ( "--enable-special-filenames" );
+ if (!argv[argc]) {
+ xfree (fd_data_map);
+ free_argv (argv);
+ return mk_error (Out_Of_Core);
+ }
+ argc++;
+ }
for ( a=gpg->arglist; a; a = a->next ) {
if ( a->data ) {
switch ( _gpgme_query_data_mode (a->data) ) {
}
fd_data_map[datac].data = a->data;
fd_data_map[datac].dup_to = a->dup_to;
+ if ( a->dup_to == -1 ) {
+ argv[argc] = xtrymalloc ( 25 );
+ if (!argv[argc]) {
+ xfree (fd_data_map);
+ free_argv (argv);
+ return mk_error (Out_Of_Core);
+ }
+ sprintf ( argv[argc], "-&%d", fd_data_map[datac].peer_fd );
+ argc++;
+ }
datac++;
}
else {
free_argv (argv);
return mk_error (Out_Of_Core);
}
+ argc++;
}
- argc++;
}
gpg->argv = argv;
}
if ( !pid ) { /* child */
+ int duped_stdin = 0;
+ int duped_stderr = 0;
+
+ close (gpg->status.fd[0]);
+
for (i=0; gpg->fd_data_map[i].data; i++ ) {
close (gpg->fd_data_map[i].fd);
gpg->fd_data_map[i].fd = -1;
strerror (errno));
_exit (8);
}
+ if ( gpg->fd_data_map[i].dup_to == 0 )
+ duped_stdin=1;
+ if ( gpg->fd_data_map[i].dup_to == 2 )
+ duped_stderr=1;
close ( gpg->fd_data_map[i].peer_fd );
}
}
-
- if ( gpg->status.fd[0] != -1 )
- close (gpg->status.fd[0]);
- /* FIXME: dup /dev/null to stdin if nothing is connected to stdin */
- execv ("/usr/local/bin/gpg", gpg->argv );
- fprintf (stderr,"exec of gpg failed\n"); fflush (stderr);
+ if( !duped_stdin || !duped_stderr ) {
+ int fd = open ( "/dev/null", O_RDONLY );
+ if ( fd == -1 ) {
+ fprintf (stderr,"can't open `/dev/null': %s\n",
+ strerror (errno) );
+ _exit (8);
+ }
+ /* Make sure that gpg has a connected stdin */
+ if ( !duped_stdin ) {
+ if ( dup2 ( fd, 0 ) == -1 ) {
+ fprintf (stderr,"dup2(/dev/null, 0) failed: %s\n",
+ strerror (errno) );
+ _exit (8);
+ }
+ }
+ /* We normally don't want all the normal output */
+ if ( !duped_stderr ) {
+ if ( dup2 ( fd, 2 ) == -1 ) {
+ fprintf (stderr,"dup2(dev/null, 2) failed: %s\n",
+ strerror (errno) );
+ _exit (8);
+ }
+ }
+ close (fd);
+ }
+
+ execv ("./gpg", gpg->argv );
+ fprintf (stderr,"exec of gpg failed\n");
_exit (8);
}
+ /* parent */
gpg->pid = pid;
+ /*_gpgme_register_term_handler ( closure, closure_value, pid );*/
+
if ( gpg->status.fd[1] != -1 )
close (gpg->status.fd[1]);
if ( _gpgme_register_pipe_handler ( opaque, gpg_status_handler,
gpg->running = 1;
return 0;
-
}
gpg_inbound_handler ( void *opaque, pid_t pid, int fd )
{
GpgmeData dh = opaque;
+ GpgmeError err;
int nread;
char buf[200];
}
else if (!nread)
return 1; /* eof */
+
+ /* We could improve this with a GpgmeData function which takes
+ * the read function or provides a memory area for writing to it.
+ */
+ err = _gpgme_append_data ( dh, buf, nread );
+ if ( err ) {
+ fprintf (stderr, "_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 */
+ return 1;
+ }
return 0;
}
static int
-status_cmp (const struct status_table_s *a, const struct status_table_s *b)
+status_cmp (const void *ap, const void *bp)
{
+ const struct status_table_s *a = ap;
+ const struct status_table_s *b = bp;
+
return strcmp (a->name, b->name);
}
typedef struct gpg_object_s *GpgObject;
+/*-- verify.c --*/
+struct verify_result_s;
+typedef struct verify_result_s *VerifyResult;
+
+
#endif /* TYPES_H */
--- /dev/null
+/* verify.c - signature verification
+ * Copyright (C) 2000 Werner Koch (dd9jn)
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GPGME is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "util.h"
+#include "context.h"
+#include "ops.h"
+
+typedef enum {
+ VERIFY_STATUS_NONE = 0,
+ VERIFY_STATUS_NOSIG,
+ VERIFY_STATUS_NOKEY,
+ VERIFY_STATUS_ERROR,
+ VERIFY_STATUS_BAD,
+ VERIFY_STATUS_GOOD
+} VerifyStatus;
+
+struct verify_result_s {
+ VerifyStatus status;
+
+};
+
+
+void
+_gpgme_release_verify_result ( VerifyResult res )
+{
+ xfree (res);
+}
+
+
+static void
+verify_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args )
+{
+ if ( ctx->out_of_core )
+ return;
+ if ( ctx->result_type == RESULT_TYPE_NONE ) {
+ assert ( !ctx->result.verify );
+ ctx->result.verify = xtrycalloc ( 1, sizeof *ctx->result.verify );
+ if ( !ctx->result.verify ) {
+ ctx->out_of_core = 1;
+ return;
+ }
+ ctx->result_type = RESULT_TYPE_VERIFY;
+ }
+ assert ( ctx->result_type == RESULT_TYPE_VERIFY );
+
+ /* FIXME: For now we handle only one signature */
+ /* FIXME: Collect useful information */
+ switch (code) {
+ case STATUS_GOODSIG:
+ ctx->result.verify->status = VERIFY_STATUS_GOOD;
+ break;
+ case STATUS_BADSIG:
+ ctx->result.verify->status = VERIFY_STATUS_BAD;
+ break;
+ case STATUS_ERRSIG:
+ ctx->result.verify->status = VERIFY_STATUS_ERROR;
+ /* FIXME: distinguish between a regular error and a missing key.
+ * this is encoded in the args. */
+ break;
+ default:
+ /* ignore all other codes */
+ fprintf (stderr, "verify_status: code=%d not handled\n", code );
+ break;
+ }
+}
+
+
+
+GpgmeError
+gpgme_start_verify ( GpgmeCtx c, GpgmeData sig, GpgmeData text )
+{
+ int rc = 0;
+ int i;
+
+ fail_on_pending_request( c );
+ c->pending = 1;
+
+ _gpgme_release_result (c);
+ c->out_of_core = 0;
+
+ /* create a process object.
+ * To optimize this, we should reuse an existing one and
+ * run gpg in the new --pipemode (I started with this but it is
+ * not yet finished) */
+ if ( c->gpg ) {
+ _gpgme_gpg_release_object ( c->gpg );
+ c->gpg = NULL;
+ }
+ rc = _gpgme_gpg_new_object ( &c->gpg );
+ if (rc)
+ goto leave;
+
+ _gpgme_gpg_set_status_handler ( c->gpg, verify_status_handler, c );
+
+ /* build the commandline */
+ _gpgme_gpg_add_arg ( c->gpg, "--verify" );
+ for ( i=0; i < c->verbosity; i++ )
+ _gpgme_gpg_add_arg ( c->gpg, "--verbose" );
+
+
+ /* Check the supplied data */
+ if ( gpgme_query_data_type (sig) == GPGME_DATA_TYPE_NONE ) {
+ rc = mk_error (No_Data);
+ goto leave;
+ }
+ if ( text && gpgme_query_data_type (text) == GPGME_DATA_TYPE_NONE ) {
+ rc = mk_error (No_Data);
+ goto leave;
+ }
+ _gpgme_set_data_mode (sig, GPGME_DATA_MODE_OUT );
+ if (text) /* detached signature */
+ _gpgme_set_data_mode (text, GPGME_DATA_MODE_OUT );
+ /* Tell the gpg object about the data */
+ _gpgme_gpg_add_arg ( c->gpg, "--" );
+ _gpgme_gpg_add_data ( c->gpg, sig, -1 );
+ if (text)
+ _gpgme_gpg_add_data ( c->gpg, text, 0 );
+
+ /* and kick off the process */
+ rc = _gpgme_gpg_spawn ( c->gpg, c );
+
+ leave:
+ if (rc) {
+ c->pending = 0;
+ _gpgme_gpg_release_object ( c->gpg ); c->gpg = NULL;
+ }
+ return rc;
+}
+
+
+
+GpgmeError
+gpgme_verify ( GpgmeCtx c, GpgmeData sig, GpgmeData text )
+{
+ int rc = gpgme_start_verify ( c, sig, text );
+ if ( !rc ) {
+ gpgme_wait (c, 1);
+ if ( c->result_type != RESULT_TYPE_VERIFY )
+ rc = mk_error (General_Error);
+ else if ( c->out_of_core )
+ rc = mk_error (Out_Of_Core);
+ else {
+ assert ( c->result.verify );
+ switch ( c->result.verify->status ) {
+ case VERIFY_STATUS_NONE:
+ fputs ("Verification Status: None\n", stdout);
+ break;
+ case VERIFY_STATUS_NOSIG:
+ fputs ("Verification Status: No Signature\n", stdout);
+ break;
+ case VERIFY_STATUS_GOOD:
+ fputs ("Verification Status: Good\n", stdout);
+ break;
+ case VERIFY_STATUS_BAD:
+ fputs ("Verification Status: Bad\n", stdout);
+ break;
+ case VERIFY_STATUS_NOKEY:
+ fputs ("Verification Status: No Key\n", stdout);
+ break;
+ case VERIFY_STATUS_ERROR:
+ fputs ("Verification Status: Error\n", stdout);
+ break;
+ }
+ }
+ c->pending = 0;
+ }
+ return rc;
+}
+
+
+
+
+
+
+
}
+static void
+propagate_term_results ( const struct wait_queue_item_s *first_q )
+{
+ struct wait_queue_item_s *q;
+
+ for (q=wait_queue; q; q = q->next) {
+ if ( q->used && q != first_q && !q->exited
+ && q->pid == first_q->pid ) {
+ q->exited = first_q->exited;
+ q->exit_status = first_q->exit_status;
+ q->exit_signal = first_q->exit_signal;
+ }
+ }
+}
+
+static int
+count_active_fds ( pid_t pid )
+{
+ struct wait_queue_item_s *q;
+ int count = 0;
+
+ for (q=wait_queue; q; q = q->next) {
+ if ( q->used && q->active && q->pid == pid )
+ count++;
+ }
+ return count;
+}
+
+
+/* remove the given process from the queue */
+static void
+remove_process ( pid_t pid )
+{
+ struct wait_queue_item_s *q;
+
+ for (q=wait_queue; q; q = q->next) {
+ if ( q->used ) {
+ close (q->fd);
+ q->handler = NULL;
+ q->ctx = NULL;
+ q->used = 0;
+ }
+ }
+}
+
+
+
/**
* gpgme_wait:
* @c:
q = queue_item_from_context ( c );
assert (q);
- if ( waitpid ( q->pid, &status, WNOHANG ) == q->pid ) {
+ if (q->exited)
+ ;
+ else if ( waitpid ( q->pid, &status, WNOHANG ) == q->pid ) {
q->exited = 1;
if ( WIFSIGNALED (status) ) {
q->exit_status = 4; /* Need some value here */
q->exited++;
q->exit_status = 4;
}
- /* okay, the process has terminated - we are ready */
- hang = 0;
+ propagate_term_results (q);
+ }
+
+ if ( q->exited ) {
+ if ( !count_active_fds (q->pid) ) {
+ /* Hmmm, as long as we don't have a callback for
+ * the exit status, we have no use for these
+ * values and therefore we can remove this from
+ * the queue */
+ remove_process (q->pid);
+ hang = 0;
+ }
}
}
} while (hang);
## Process this file with automake to create Makefile.in
-TESTS = t-encrypt
+TESTS = t-encrypt t-verify
INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/intl
exit (1); } \
} while(0)
+static void
+print_data ( GpgmeData dh )
+{
+ char buf[100];
+ size_t nread;
+ GpgmeError err;
+
+ err = gpgme_rewind_data ( dh );
+ fail_if_err (err);
+ while ( !(err = gpgme_read_data ( dh, buf, 100, &nread )) ) {
+ fwrite ( buf, nread, 1, stdout );
+ }
+ if (err != GPGME_EOF)
+ fail_if_err (err);
+}
+
+
int
main (int argc, char **argv )
GpgmeData in, out;
GpgmeRecipientSet rset;
+ do {
err = gpgme_new_context (&ctx);
fail_if_err (err);
- err = gpgme_new_data ( &in, "Hallo Leute", 11, 0 );
+ err = gpgme_new_data ( &in, "Hallo Leute\n", 12, 0 );
fail_if_err (err);
err = gpgme_new_data ( &out, NULL, 0,0 );
fail_if_err (err);
err = gpgme_add_recipient (rset, "Bob");
fail_if_err (err);
+ err = gpgme_add_recipient (rset, "Alpha");
+ fail_if_err (err);
err = gpgme_encrypt (ctx, rset, in, out );
fail_if_err (err);
+ fflush (NULL);
+ fputs ("Begin Result:\n", stdout );
+ print_data (out);
+ fputs ("End Result.\n", stdout );
gpgme_release_recipient_set (rset);
gpgme_release_data (in);
gpgme_release_data (out);
gpgme_release_context (ctx);
+ } while ( argc > 1 && !strcmp( argv[1], "--loop" ) );
+
return 0;
}
--- /dev/null
+/* t-verify.c - regression test
+ * Copyright (C) 2000 Werner Koch (dd9jn)
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GPGME is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "../gpgme/gpgme.h"
+
+static const char test_text1[] = "Just GNU it!\n";
+static const char test_text1f[]= "Just GNU it?\n";
+static const char test_sig1[] =
+"-----BEGIN PGP SIGNATURE-----\n"
+"\n"
+"iEYEABECAAYFAjoKgjIACgkQLXJ8x2hpdzQMSwCeO/xUrhysZ7zJKPf/FyXA//u1\n"
+"ZgIAn0204PBR7yxSdQx6CFxugstNqmRv\n"
+"=yku6\n"
+"-----END PGP SIGNATURE-----\n"
+;
+
+
+#define fail_if_err(a) do { if(a) { \
+ fprintf (stderr, "%s:%d: GpgmeError %s\n", \
+ __FILE__, __LINE__, gpgme_strerror(a)); \
+ exit (1); } \
+ } while(0)
+
+
+int
+main (int argc, char **argv )
+{
+ GpgmeCtx ctx;
+ GpgmeError err;
+ GpgmeData sig, text;
+
+ err = gpgme_new_context (&ctx);
+ fail_if_err (err);
+
+ do {
+ err = gpgme_new_data ( &text, test_text1, strlen (test_text1), 0 );
+ fail_if_err (err);
+ err = gpgme_new_data ( &sig, test_sig1, strlen (test_sig1), 0 );
+ fail_if_err (err);
+
+ puts ("checking a valid message:\n");
+ err = gpgme_verify (ctx, sig, text );
+ fail_if_err (err);
+
+ puts ("checking a manipulated message:\n");
+ gpgme_release_data (text);
+ err = gpgme_new_data ( &text, test_text1f, strlen (test_text1f), 0 );
+ fail_if_err (err);
+ gpgme_rewind_data ( sig );
+ err = gpgme_verify (ctx, sig, text );
+ fail_if_err (err);
+
+ gpgme_release_data (sig);
+ gpgme_release_data (text);
+
+} while ( argc > 1 && !strcmp( argv[1], "--loop" ) );
+ gpgme_release_context (ctx);
+
+ return 0;
+}
+
+
+