Add verify function
authorWerner Koch <wk@gnupg.org>
Thu, 9 Nov 2000 16:35:35 +0000 (16:35 +0000)
committerWerner Koch <wk@gnupg.org>
Thu, 9 Nov 2000 16:35:35 +0000 (16:35 +0000)
14 files changed:
gpgme/Makefile.am
gpgme/context.h
gpgme/data.c
gpgme/encrypt.c
gpgme/gpgme.c
gpgme/gpgme.h
gpgme/ops.h
gpgme/rungpg.c
gpgme/types.h
gpgme/verify.c [new file with mode: 0644]
gpgme/wait.c
tests/Makefile.am
tests/t-encrypt.c
tests/t-verify.c [new file with mode: 0644]

index 87de1de1461a92a532236caa1b42d99be541e4a8..b47169cb3bc9034ade44b134e7e01c99719f0a33 100644 (file)
@@ -18,6 +18,7 @@ libgpgme_la_SOURCES = \
        data.c recipient.c \
         wait.c wait.h \
        encrypt.c \
+       verify.c \
         rungpg.c rungpg.h status-table.h \
        gpgme.c errors.c
 
index 504ec89cf7e666b66fdccc4ccdb48bb6516c7f4f..c45d1bf601072dc8a7420d06f81b3c9e8f3dcf78 100644 (file)
 #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;
 };
 
 
@@ -44,6 +62,8 @@ struct gpgme_data_s {
     GpgmeDataType type;
     GpgmeDataMode mode;
     size_t readpos;
+    size_t writepos;
+    size_t private_len;
     char *private_buffer;
 };
 
index 253e1011a2f43fc815cff0e19a8d8b993468c229..8499069b7762fcd004e779b54baace8483e26b2e 100644 (file)
@@ -27,6 +27,9 @@
 #include "context.h"
 
 
+#define ALLOC_CHUNK 1024
+
+
 /**
  * gpgme_new_data:
  * @r_dh:   Returns a new data object.
@@ -59,8 +62,10 @@ gpgme_new_data ( GpgmeData *r_dh, const char *buffer, size_t size, int copy )
                 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;
@@ -113,24 +118,95 @@ _gpgme_query_data_mode ( GpgmeData dh )
     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;
 }
index eaf57429b5cb0f8d3909ebb5099c82abec085296..501e65fdfb818083740722f48613e137d8299a28 100644 (file)
@@ -39,7 +39,7 @@ encrypt_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args )
 
 
 GpgmeError
-gpgme_req_encrypt ( GpgmeCtx c, GpgmeRecipientSet recp,
+gpgme_start_encrypt ( GpgmeCtx c, GpgmeRecipientSet recp,
                     GpgmeData plain, GpgmeData ciph )
 {
     int rc = 0;
@@ -87,7 +87,7 @@ gpgme_req_encrypt ( GpgmeCtx c, GpgmeRecipientSet recp,
     _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 */
@@ -102,18 +102,6 @@ gpgme_req_encrypt ( GpgmeCtx c, GpgmeRecipientSet recp,
 }
 
 
-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
@@ -131,9 +119,11 @@ GpgmeError
 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;
 }
 
index fd55c4b617f5b1ffc4f54ccffd444899f08ca7d4..10df50802b749f7241052ea61301bb695da1fb59 100644 (file)
@@ -24,7 +24,7 @@
 
 #include "util.h"
 #include "context.h"
-
+#include "ops.h"
 
 /**
  * gpgme_new_context:
@@ -58,14 +58,26 @@ gpgme_new_context (GpgmeCtx *r_ctx)
 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;
+}
 
 
 
index f5ede58bf55bfc6c6275394f5815677d0a6ed9c5..88a84348db728599ea47beb7db24cc2759c59304 100644 (file)
@@ -38,6 +38,7 @@ typedef struct gpgme_recipient_set_s *GpgmeRecipientSet;
 
 
 typedef enum {
+    GPGME_EOF = -1,
     GPGME_No_Error = 0,
     GPGME_General_Error = 1,
     GPGME_Out_Of_Core = 2,
@@ -81,12 +82,16 @@ GpgmeError gpgme_new_data ( GpgmeData *r_dh,
                                 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 */
@@ -99,6 +104,7 @@ GpgmeError gpgme_wait_encrypt ( GpgmeCtx c, GpgmeData *r_out );
 /* 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 */
index ca361ca5eb774de340e79d89ee005f84a102510d..59efeffc02eaa515d3ea4e1403f7c1d83314eed3 100644 (file)
@@ -23,6 +23,9 @@
 
 #include "types.h"
 
+/*-- gpgme.c --*/
+void _gpgme_release_result ( GpgmeCtx c );
+
 
 /*-- recipient.c --*/
 void _gpgme_append_gpg_args_from_recipients (
@@ -33,8 +36,11 @@ 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 */
index 6353ad27e9399b1956d1cb90cd7d7177e0d12e98..ac6ba1140cdc863bd01f4dd25f181784e21c2680 100644 (file)
@@ -29,6 +29,7 @@
 #include <unistd.h>
 #include <sys/wait.h>
 #include <signal.h>
+#include <fcntl.h>
 
 #include "gpgme.h"
 #include "util.h"
@@ -84,6 +85,7 @@ struct gpg_object_s {
 
 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 );
@@ -96,7 +98,6 @@ GpgmeError
 _gpgme_gpg_new_object ( GpgObject *r_gpg )
 {
     GpgObject gpg;
-    char buf[20];
     int rc = 0;
 
     gpg = xtrycalloc ( 1, sizeof *gpg );
@@ -109,9 +110,6 @@ _gpgme_gpg_new_object ( GpgObject *r_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;
@@ -128,8 +126,13 @@ _gpgme_gpg_new_object ( GpgObject *r_gpg )
     }
     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) {
@@ -153,8 +156,7 @@ _gpgme_gpg_release_object ( GpgObject gpg )
         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);
 }
@@ -162,6 +164,7 @@ _gpgme_gpg_release_object ( GpgObject gpg )
 static void
 kill_gpg ( GpgObject gpg )
 {
+  #if 0
     if ( gpg->running ) {
         /* still running? Must send a killer */
         kill ( gpg->pid, SIGTERM);
@@ -172,6 +175,7 @@ kill_gpg ( GpgObject gpg )
         }
         gpg->running = 0;
     }
+  #endif
 }
 
 
@@ -238,6 +242,21 @@ free_argv ( char **argv )
     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 )
@@ -246,22 +265,32 @@ 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)
@@ -273,6 +302,22 @@ build_argv ( GpgObject gpg )
     }
 
     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) ) {
@@ -328,6 +373,16 @@ build_argv ( GpgObject gpg )
             }
             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 {
@@ -337,8 +392,8 @@ build_argv ( GpgObject gpg )
                 free_argv (argv);
                 return mk_error (Out_Of_Core);
             }
+            argc++;
         }
-        argc++;
     }
 
     gpg->argv = argv;
@@ -372,6 +427,11 @@ _gpgme_gpg_spawn( GpgObject gpg, void *opaque )
     }
         
     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;
@@ -382,20 +442,49 @@ _gpgme_gpg_spawn( GpgObject gpg, void *opaque )
                              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,
@@ -424,7 +513,6 @@ _gpgme_gpg_spawn( GpgObject gpg, void *opaque )
 
     gpg->running = 1;
     return 0;
-
 }
 
 
@@ -432,6 +520,7 @@ static int
 gpg_inbound_handler ( void *opaque, pid_t pid, int fd )
 {
     GpgmeData dh = opaque;
+    GpgmeError err;
     int nread;
     char buf[200];
 
@@ -448,7 +537,19 @@ gpg_inbound_handler ( void *opaque, pid_t pid, int fd )
     }
     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;
 }
@@ -520,8 +621,11 @@ gpg_status_handler ( void *opaque, pid_t pid, int fd )
 
 
 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);
 }
 
index c8b23023ccb48b7080f92d3f57f9ce2b4ac1b818..82f6b79d1768985aa1cc8b5f9f925fb9d15a4307 100644 (file)
@@ -43,6 +43,11 @@ struct gpg_object_s;
 typedef struct gpg_object_s *GpgObject;
 
 
+/*-- verify.c --*/
+struct verify_result_s;
+typedef struct verify_result_s *VerifyResult;
+
+
 
 #endif /* TYPES_H */
 
diff --git a/gpgme/verify.c b/gpgme/verify.c
new file mode 100644 (file)
index 0000000..e984478
--- /dev/null
@@ -0,0 +1,198 @@
+/* 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;
+}
+
+
+
+
+
+
+
index f8cadc003b306c18417372100bd3071c5941f903..a84c746506cb8054fa40f364387aaf1a1d244a61 100644 (file)
@@ -98,6 +98,53 @@ queue_item_from_context ( GpgmeCtx ctx )
 }
 
 
+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: 
@@ -127,7 +174,9 @@ gpgme_wait ( GpgmeCtx c, int hang )
             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 */
@@ -140,8 +189,18 @@ gpgme_wait ( GpgmeCtx c, int hang )
                     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);
index eab4df3c50a9b776c525045dc9cf4cc4070a5243..aced40071ea0b138e0f7c4cd4a9246a4a547e279 100644 (file)
@@ -1,6 +1,6 @@
 ## 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
 
index 8f6e5c5db7c15311c90bc4ac3ae5785f8a76fb9a..d99beff03d9ea2ede15e92bb7bf9ee35a0da6e3c 100644 (file)
                                 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 )
@@ -40,10 +57,11 @@ 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 );
@@ -53,16 +71,24 @@ main (int argc, char **argv )
     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;
 }
 
diff --git a/tests/t-verify.c b/tests/t-verify.c
new file mode 100644 (file)
index 0000000..3a948af
--- /dev/null
@@ -0,0 +1,85 @@
+/* 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;
+}
+
+
+