diff options
| author | Werner Koch <[email protected]> | 2000-11-10 17:50:24 +0000 | 
|---|---|---|
| committer | Werner Koch <[email protected]> | 2000-11-10 17:50:24 +0000 | 
| commit | cbb513962a8440292746be6bcf451fb207f6b7b4 (patch) | |
| tree | 373f97d07bdddc116ba2c127ca139060ac795634 | |
| parent | Add verify function (diff) | |
| download | gpgme-cbb513962a8440292746be6bcf451fb207f6b7b4.tar.gz gpgme-cbb513962a8440292746be6bcf451fb207f6b7b4.zip | |
Started with --list-key
Diffstat (limited to '')
| -rw-r--r-- | gpgme/Makefile.am | 2 | ||||
| -rw-r--r-- | gpgme/context.h | 2 | ||||
| -rw-r--r-- | gpgme/gpgme.c | 2 | ||||
| -rw-r--r-- | gpgme/gpgme.h | 2 | ||||
| -rw-r--r-- | gpgme/key.c | 135 | ||||
| -rw-r--r-- | gpgme/key.h | 59 | ||||
| -rw-r--r-- | gpgme/keylist.c | 334 | ||||
| -rw-r--r-- | gpgme/ops.h | 5 | ||||
| -rw-r--r-- | gpgme/rungpg.c | 171 | ||||
| -rw-r--r-- | gpgme/rungpg.h | 5 | ||||
| -rw-r--r-- | gpgme/types.h | 3 | ||||
| -rw-r--r-- | tests/Makefile.am | 2 | ||||
| -rw-r--r-- | tests/t-keylist.c | 74 | 
13 files changed, 793 insertions, 3 deletions
| diff --git a/gpgme/Makefile.am b/gpgme/Makefile.am index b47169cb..547dcd44 100644 --- a/gpgme/Makefile.am +++ b/gpgme/Makefile.am @@ -19,6 +19,8 @@ libgpgme_la_SOURCES = \          wait.c wait.h \  	encrypt.c \  	verify.c \ +        key.c key.h \ +	keylist.c \          rungpg.c rungpg.h status-table.h \  	gpgme.c errors.c diff --git a/gpgme/context.h b/gpgme/context.h index c45d1bf6..ab5a2d3d 100644 --- a/gpgme/context.h +++ b/gpgme/context.h @@ -53,6 +53,8 @@ struct gpgme_context_s {      union {          VerifyResult verify;      } result; + +    GpgmeKey tmp_key;  /* used by keylist.c */  }; diff --git a/gpgme/gpgme.c b/gpgme/gpgme.c index 10df5080..8a8cbb27 100644 --- a/gpgme/gpgme.c +++ b/gpgme/gpgme.c @@ -61,6 +61,7 @@ gpgme_release_context ( GpgmeCtx c )      _gpgme_gpg_release_object ( c->gpg );       _gpgme_release_result ( c ); +    _gpgme_key_release ( c->tmp_key );      xfree ( c );  } @@ -75,6 +76,7 @@ _gpgme_release_result ( GpgmeCtx c )          _gpgme_release_verify_result ( c->result.verify );          break;      } +      c->result.verify = NULL;      c->result_type = RESULT_TYPE_NONE;  } diff --git a/gpgme/gpgme.h b/gpgme/gpgme.h index 88a84348..32a925fc 100644 --- a/gpgme/gpgme.h +++ b/gpgme/gpgme.h @@ -95,6 +95,8 @@ GpgmeError gpgme_start_verify ( GpgmeCtx c,  GpgmeData sig, GpgmeData text );  /* Key management functions */ +GpgmeError gpgme_keylist_start ( GpgmeCtx c, +                                 const char *pattern, int secret_only ); diff --git a/gpgme/key.c b/gpgme/key.c new file mode 100644 index 00000000..92bb5972 --- /dev/null +++ b/gpgme/key.c @@ -0,0 +1,135 @@ +/* key.c - Key and keyList objects + *	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 <assert.h> + +#include "util.h" +#include "ops.h" +#include "key.h" + +#define ALLOC_CHUNK 1024 +#define my_isdigit(a) ( (a) >='0' && (a) <= '9' ) + + +GpgmeError +_gpgme_key_new( GpgmeKey *r_key ) +{ +    GpgmeKey key; + +    *r_key = NULL; +    key = xtrycalloc ( 1, sizeof *key ); +    if (!key) +        return mk_error (Out_Of_Core); + +    *r_key = key; +    return 0; +} + +void +_gpgme_key_release ( GpgmeKey key ) +{ +    struct user_id_s *u, *u2; + +    if (!key) +        return; + +    xfree (key->fingerprint); +    for ( u = key->uids; u; u = u2 ) { +        u2 = u->next; +        xfree (u); +    } +    xfree (key); +} + +/*  + * Take a name from the --with-colon listing, remove certain escape sequences + * sequences and put it into the list of UIDs + */ +GpgmeError +_gpgme_key_append_name ( GpgmeKey key, const char *s ) +{ +    struct user_id_s *uid; +    char *d; + +    assert (key); +    /* we can malloc a buffer of the same length, because the converted +     * string will never be larger */ +    uid = xtrymalloc ( sizeof *uid + strlen (s) ); +    if ( !uid ) +        return mk_error (Out_Of_Core); +    uid->validity = 0; +    d = uid->name; + +    while ( *s ) { +        if ( *s != '\\' ) +            *d++ = *s++; +        else if ( s[1] == '\\' ) { +            s++; +            *d++ = *s++;  +        } +        else if ( s[1] == 'n' ) { +            s += 2; +            *d++ = '\n';  +        } +        else if ( s[1] == 'r' ) { +            s += 2; +            *d++ = '\r';  +        } +        else if ( s[1] == 'v' ) { +            s += 2; +            *d++ = '\v';  +        } +        else if ( s[1] == 'b' ) { +            s += 2; +            *d++ = '\b';  +        } +        else if ( s[1] == '0' ) { +            /* Hmmm: no way to express this */ +            s += 2; +            *d++ = '\\'; +            *d++ = '\0';  +        } +        else if ( s[1] == 'x' && my_isdigit (s[2]) && my_isdigit (s[3]) ) { +            unsigned int val = (s[2]-'0')*16 + (s[3]-'0'); +            if ( !val ) { +                *d++ = '\\'; +                *d++ = '\0';  +            } +            else  +                *(byte*)d++ = val; +            s += 3; +        } +        else { /* should not happen */ +            s++; +            *d++ = '\\';  +            *d++ = *s++; +        }  +    } + +    uid->next = key->uids; +    key->uids = uid; +    return 0; +} + + + diff --git a/gpgme/key.h b/gpgme/key.h new file mode 100644 index 00000000..bd32c4b7 --- /dev/null +++ b/gpgme/key.h @@ -0,0 +1,59 @@ +/* key.h  + *	Copyright (C) 2000 Werner Koch (dd9jn) + * + * This file is part of GPGME. + * + * GPGME is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GPGME is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef KEY_H +#define KEY_H + +#include <time.h> +#include "types.h" + +struct user_id_s { +    struct user_id_s *next; +    int validity; /* 0 = undefined, 1 = not, 2 = marginal, +                     3 = full, 4 = ultimate */ +    char name[1]; +}; + +struct gpgme_key_s { +    struct { +        unsigned int revoked:1 ; +        unsigned int expired:1 ; +        unsigned int disabled:1 ; +    } flags; +    unsigned int key_algo; +    unsigned int key_len; +    char keyid[16+1];  +    char *fingerprint; /* malloced hex digits */ +    time_t timestamp; /* -1 for invalid, 0 for not available */ +    struct user_id_s *uids; +     +}; + + +GpgmeError _gpgme_key_append_name ( GpgmeKey key, const char *s ); + + + +#endif /* KEY_H */ + + + + + diff --git a/gpgme/keylist.c b/gpgme/keylist.c new file mode 100644 index 00000000..1e7d5b12 --- /dev/null +++ b/gpgme/keylist.c @@ -0,0 +1,334 @@ +/* keylist.c -  key listing + *	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 <time.h> +#include <assert.h> + +#include "util.h" +#include "context.h" +#include "ops.h" +#include "key.h" + +#define my_isdigit(a) ( (a) >='0' && (a) <= '9' ) + +static void finish_key ( GpgmeCtx ctx ); + + +static void +keylist_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args ) +{ +    if ( ctx->out_of_core ) +        return; + +    switch (code) { +      case STATUS_EOF: +        if (ctx->tmp_key) +            finish_key (ctx); +        break; + +      default: +        /* ignore all other codes */ +        fprintf (stderr, "keylist_status: code=%d not handled\n", code ); +        break; +    } +} + + +static time_t +parse_timestamp ( char *p ) +{ +    struct tm tm; +    int i; +     +    if (!*p ) +        return 0; + +    if (strlen(p) < 10 || p[4] != '-' || p[7] != '-' ) +        return (time_t)-1; +    p[4] = 0; +    p[7] = 0; +    p[10] = 0; /* just in case the time part follows */ +    memset (&tm, 0, sizeof tm); + +    i = atoi (p); +    if ( i < 1900 ) +        return (time_t)-1; +    tm.tm_year = i - 1900; + +    i = atoi (p+5); +    if ( i < 1 || i > 12 ) +        return (time_t)-1; +    tm.tm_mon = i-1; + +    i = atoi (p+8); +    if ( i < 1 || i > 31 ) +        return (time_t)-1; +    tm.tm_mday = i; + +    return mktime (&tm); +} + + +static void +set_trust_info ( GpgmeKey key, const char *s ) +{ +    /* look at letters and stop at the first digit */ +    for (; *s && !my_isdigit (*s); s++ ) { +        switch (*s) { +          case 'e': key->flags.expired = 1; break; +          case 'r': key->flags.revoked = 1; break; +          case 'd': key->flags.disabled = 1; break; +          case 'n': key->uids->validity = 1; break; +          case 'm': key->uids->validity = 2; break; +          case 'f': key->uids->validity = 3; break; +          case 'u': key->uids->validity = 4; break; +        } +    } +} + + +/* Note: we are allowed to modify line */ +static void +keylist_colon_handler ( GpgmeCtx ctx, char *line ) +{ +    char *p, *pend; +    int field = 0; +    enum { +        RT_NONE, RT_SIG, RT_UID, RT_SUB, RT_PUB, RT_FPR, RT_SSB, RT_SEC +    } rectype = RT_NONE; +    GpgmeKey key = ctx->tmp_key; +    int i; +    const char *trust_info = NULL; +     + +    if ( ctx->out_of_core ) +        return; +    if (!line) +        return; /* EOF */ + +    fprintf (stderr, "line=`%s'\n", line ); + +    for (p = line; p; p = pend) { +        field++; +        pend = strchr (p, ':'); +        if (pend)  +            *pend++ = 0; + +        if ( field == 1 ) { +            if ( !strcmp ( p, "sig" ) ) +                rectype = RT_SIG; +            else if ( !strcmp ( p, "uid" ) && key ) { +                rectype = RT_UID; +                key = ctx->tmp_key; +            } +            else if ( !strcmp ( p, "sub" ) ) +                rectype = RT_SUB; +            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 */ +                    return; +                } +                rectype = RT_PUB; +                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 /*|| rectype == RT_SUB*/ ) { +            switch (field) { +              case 2: /* trust info */ +                if ( rectype == RT_PUB )  +                    trust_info = p;  /*save for later */ +                break; +              case 3: /* key length */ +                i = atoi (p);  +                if ( i > 1 ) /* ignore invalid values */ +                    key->key_len = i;  +                break; +              case 4: /* pubkey algo */ +                i = atoi (p); +                if ( i > 1 && i < 128 ) +                    key->key_algo = i; +                break; +              case 5: /* long keyid */ +                if ( strlen (p) == DIM(key->keyid)-1 ) +                    strcpy (key->keyid, p); +                break; +              case 6: /* timestamp (1998-02-28) */ +                key->timestamp = parse_timestamp (p); +                break; +              case 7: /* valid for n days */ +                break; +              case 8: /* reserved (LID) */ +                break; +              case 9: /* ownertrust */ +                break; +              case 10: /* This is the first name listed */ +                if ( rectype == RT_PUB ) { +                    if ( _gpgme_key_append_name ( key, p) ) +                        ctx->out_of_core = 1; +                    else { +                        if (trust_info) +                            set_trust_info (key, trust_info); +                    } +                } +                break; +              case 11:  /* signature class  */ +                break; +              case 12: +                pend = NULL;  /* we can stop here */ +                break; +            } +        } +        else if ( rectype == RT_UID ) { +            switch (field) { +              case 2: /* trust info */ +                trust_info = p;  /*save for later */ +                break; +              case 10: /* the 2nd, 3rd,... user ID */ +                if ( _gpgme_key_append_name ( key, p) ) +                    ctx->out_of_core = 1; +                else { +                    if (trust_info) +                        set_trust_info (key, trust_info); +                } +                pend = NULL;  /* we can stop here */ +                break; +            } +        } +        else if ( rectype == RT_FPR ) { +            switch (field) { +              case 10: /* fingerprint (take only the first one)*/ +                if ( !key->fingerprint && *p ) { +                    key->fingerprint = xtrystrdup (p); +                    if ( !key->fingerprint ) +                        ctx->out_of_core = 1; +                } +                pend = NULL; /* that is all we want */ +                break; +            } +        } +    } +     +} + + +/* + * We have read an entire key into ctx->tmp_key and should now finish + * it.  It is assumed that this releases ctx->tmp_key. + */ +static void +finish_key ( GpgmeCtx ctx ) +{ +    GpgmeKey key = ctx->tmp_key; +    struct user_id_s *u; +     +    assert (key); +    ctx->tmp_key = NULL; +     +    fprintf (stderr, "finish_key: keyid=`%s'\n", key->keyid ); +    if ( key->fingerprint ) +        fprintf (stderr, "finish_key:  fpr=`%s'\n", key->fingerprint ); +    for (u=key->uids; u; u = u->next )  +        fprintf (stderr, "finish_key:  uid=`%s'\n", u->name ); +         + +    /* fixme: call the callback or do something else with the key */ +     +    _gpgme_key_release (key); +} + + + + +GpgmeError +gpgme_keylist_start ( GpgmeCtx c,  const char *pattern, int secret_only ) +{ +    GpgmeError rc = 0; +    int i; + +    fail_on_pending_request( c ); +    c->pending = 1; + +    _gpgme_release_result (c); +    c->out_of_core = 0; + +    if ( c->gpg ) { +        _gpgme_gpg_release_object ( c->gpg );  +        c->gpg = NULL; +    } +    _gpgme_key_release (c->tmp_key); +    c->tmp_key = NULL; +     +    rc = _gpgme_gpg_new_object ( &c->gpg ); +    if (rc) +        goto leave; + +    _gpgme_gpg_set_status_handler ( c->gpg, keylist_status_handler, c ); + +    rc = _gpgme_gpg_set_colon_line_handler ( c->gpg, +                                             keylist_colon_handler, c ); +    if (rc) +        goto leave; + +    /* build the commandline */ +    for ( i=0; i < c->verbosity; i++ ) +        _gpgme_gpg_add_arg ( c->gpg, "--verbose" ); +    _gpgme_gpg_add_arg ( c->gpg, "--with-colons" ); +    _gpgme_gpg_add_arg ( c->gpg, "--with-fingerprint" ); +    _gpgme_gpg_add_arg ( c->gpg, secret_only? +                         "--list-secret-keys":"--list-keys" ); +     +    /* Tell the gpg object about the data */ +    _gpgme_gpg_add_arg ( c->gpg, "--" ); +    if (pattern && *pattern) +        _gpgme_gpg_add_arg ( c->gpg, pattern ); + +    /* 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; +} + + + + + + diff --git a/gpgme/ops.h b/gpgme/ops.h index 59efeffc..020f0fae 100644 --- a/gpgme/ops.h +++ b/gpgme/ops.h @@ -39,6 +39,11 @@ void          _gpgme_set_data_mode ( GpgmeData dh, GpgmeDataMode mode );  GpgmeError    _gpgme_append_data ( GpgmeData dh,                                     const char *buffer, size_t length ); +/*-- key.c --*/ +GpgmeError _gpgme_key_new( GpgmeKey *r_key ); +void       _gpgme_key_release ( GpgmeKey key ); + +  /*-- verify.c --*/  void _gpgme_release_verify_result ( VerifyResult res ); diff --git a/gpgme/rungpg.c b/gpgme/rungpg.c index ac6ba114..29263293 100644 --- a/gpgme/rungpg.c +++ b/gpgme/rungpg.c @@ -73,6 +73,17 @@ struct gpg_object_s {          void *fnc_value;      } status; +    /* This is a kludge - see the comment at gpg_colon_line_handler */ +    struct { +        int fd[2];   +        size_t bufsize; +        char *buffer; +        size_t readpos; +        int eof; +        GpgColonLineHandler fnc;  /* this indicate use of this structrue */ +        void *fnc_value; +    } colon; +      char **argv;        struct fd_data_map_s *fd_data_map; @@ -86,12 +97,16 @@ 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 ); +static int gpg_status_handler ( void *opaque, pid_t pid, int fd );  static GpgmeError read_status ( GpgObject gpg ); +static int gpg_colon_line_handler ( void *opaque, pid_t pid, int fd ); +static GpgmeError read_colon_line ( GpgObject gpg ); +  GpgmeError @@ -109,6 +124,8 @@ _gpgme_gpg_new_object ( GpgObject *r_gpg )      gpg->status.fd[0] = -1;      gpg->status.fd[1] = -1; +    gpg->colon.fd[0] = -1; +    gpg->colon.fd[1] = -1;      /* allocate the read buffer for the status pipe */      gpg->status.bufsize = 1024; @@ -150,12 +167,17 @@ _gpgme_gpg_release_object ( GpgObject gpg )      if ( !gpg )          return;      xfree (gpg->status.buffer); +    xfree (gpg->colon.buffer);      if ( gpg->argv )          free_argv (gpg->argv);      if (gpg->status.fd[0] != -1 )          close (gpg->status.fd[0]);      if (gpg->status.fd[1] != -1 )          close (gpg->status.fd[1]); +    if (gpg->colon.fd[0] != -1 ) +        close (gpg->colon.fd[0]); +    if (gpg->colon.fd[1] != -1 ) +        close (gpg->colon.fd[1]);      free_fd_data_map (gpg->fd_data_map);      kill_gpg (gpg); /* fixme: should be done asyncronously */      xfree (gpg); @@ -232,6 +254,30 @@ _gpgme_gpg_set_status_handler ( GpgObject gpg,      gpg->status.fnc_value = fnc_value;  } +/* Kludge to process --with-colon output */ +GpgmeError +_gpgme_gpg_set_colon_line_handler ( GpgObject gpg, +                                    GpgColonLineHandler fnc, void *fnc_value )  +{ +    assert (gpg); + +    gpg->colon.bufsize = 1024; +    gpg->colon.readpos = 0; +    gpg->colon.buffer = xtrymalloc (gpg->colon.bufsize); +    if (!gpg->colon.buffer) { +        return mk_error (Out_Of_Core); +    } +    if (pipe (gpg->colon.fd) == -1) { +        xfree (gpg->colon.buffer); gpg->colon.buffer = NULL; +        return mk_error (Pipe_Error); +    } +    gpg->colon.eof = 0; +    gpg->colon.fnc = fnc; +    gpg->colon.fnc_value = fnc_value; +    return 0; +} + +  static void  free_argv ( char **argv )  { @@ -431,6 +477,17 @@ _gpgme_gpg_spawn( GpgObject gpg, void *opaque )          int duped_stderr = 0;          close (gpg->status.fd[0]); + +        if (gpg->colon.fnc) { +            /* dup it to stdout */ +            if ( dup2 ( gpg->colon.fd[1], 1 ) == -1 ) { +                fprintf (stderr,"dup2(colon, 1) failed: %s\n", +                         strerror (errno) ); +                _exit (8); +            } +            close (gpg->colon.fd[0]); +            close (gpg->colon.fd[1]); +        }          for (i=0; gpg->fd_data_map[i].data; i++ ) {              close (gpg->fd_data_map[i].fd); @@ -485,14 +542,29 @@ _gpgme_gpg_spawn( GpgObject gpg, void *opaque )      /*_gpgme_register_term_handler ( closure, closure_value, pid );*/ -    if ( gpg->status.fd[1] != -1 ) +    if ( gpg->status.fd[1] != -1 ) {          close (gpg->status.fd[1]); +        gpg->status.fd[1] = -1; +    }      if ( _gpgme_register_pipe_handler ( opaque, gpg_status_handler,                                          gpg, pid, gpg->status.fd[0], 1 ) ) {          /* FIXME: kill the child */          return mk_error (General_Error);      } + +    if ( gpg->colon.fd[1] != -1 ) { +        close (gpg->colon.fd[1]); +        gpg->colon.fd[1] = -1; +        assert ( gpg->colon.fd[0] != -1 ); +        if ( _gpgme_register_pipe_handler ( opaque, gpg_colon_line_handler, +                                            gpg, pid, gpg->colon.fd[0], 1 ) ) { +            /* FIXME: kill the child */ +            return mk_error (General_Error); +             +        } +    } +      for (i=0; gpg->fd_data_map[i].data; i++ ) {          close (gpg->fd_data_map[i].peer_fd);          gpg->fd_data_map[i].peer_fd = -1; @@ -724,3 +796,98 @@ read_status ( GpgObject gpg )  } +/* + * This colonline handler thing is not the clean way to do it. + * It might be better to enhance the GpgmeData object to act as + * a wrapper for a callback.  Same goes for the status thing. + * For now we use this thing here becuase it is easier to implement. + */ +static int +gpg_colon_line_handler ( void *opaque, pid_t pid, int fd ) +{ +    GpgObject gpg = opaque; +    GpgmeError rc = 0; + +    assert ( fd == gpg->colon.fd[0] ); +    rc = read_colon_line ( gpg ); +    if ( rc ) { +        fprintf (stderr, "gpg_colon_line_handler: " +                 "read problem %d\n - stop", rc); +        return 1; +    } + +    return gpg->status.eof; +} + +static GpgmeError +read_colon_line ( GpgObject gpg ) +{ +    char *p; +    int nread; +    size_t bufsize = gpg->colon.bufsize;  +    char *buffer = gpg->colon.buffer; +    size_t readpos = gpg->colon.readpos;  + +    assert (buffer); +    if (bufsize - readpos < 256) {  +        /* need more room for the read */ +        bufsize += 1024; +        buffer = xtryrealloc (buffer, bufsize); +        if ( !buffer )  +            return mk_error (Out_Of_Core); +    } +     + +    do {  +        nread = read ( gpg->colon.fd[0], buffer+readpos, bufsize-readpos ); +    } while (nread == -1 && errno == EINTR); + +    if (nread == -1) +        return mk_error(Read_Error); + +    if (!nread) { +        gpg->colon.eof = 1; +        assert (gpg->colon.fnc); +        gpg->colon.fnc ( gpg->colon.fnc_value, NULL ); +        return 0; +    } + +    while (nread > 0) { +        for (p = buffer + readpos; nread; nread--, p++) { +            if ( *p == '\n' ) { +                /* (we require that the last line is terminated by a +                 * LF) and we skip empty lines.  Note: we use UTF8 +                 * encoding and escaping of special characters +                 * We require at least one colon to cope with +                 * some other printed information. +                 */ +                *p = 0; +                if ( *buffer && strchr (buffer, ':') ) { +                    assert (gpg->colon.fnc); +                    gpg->colon.fnc ( gpg->colon.fnc_value, buffer ); +                } +             +                /* To reuse the buffer for the next line we have to +                 * shift the remaining data to the buffer start and +                 * restart the loop Hmmm: We can optimize this +                 * function by looking forward in the buffer to see +                 * whether a second complete line is available and in +                 * this case avoid the memmove for this line.  */ +                nread--; p++; +                if (nread) +                    memmove (buffer, p, nread); +                readpos = 0; +                break; /* the for loop */ +            } +            else +                readpos++; +        } +    }  +     +    /* Update the gpg object.  */ +    gpg->colon.bufsize = bufsize; +    gpg->colon.buffer  = buffer; +    gpg->colon.readpos = readpos; +    return 0; +} + diff --git a/gpgme/rungpg.h b/gpgme/rungpg.h index 5a27ce96..fd29ca41 100644 --- a/gpgme/rungpg.h +++ b/gpgme/rungpg.h @@ -82,6 +82,7 @@ typedef enum  {  } GpgStatusCode;  typedef void (*GpgStatusHandler)( GpgmeCtx, GpgStatusCode code, char *args );  +typedef void (*GpgColonLineHandler)( GpgmeCtx, char *line );   GpgmeError _gpgme_gpg_new_object ( GpgObject *r_gpg );  void       _gpgme_gpg_release_object ( GpgObject gpg ); @@ -90,6 +91,10 @@ GpgmeError _gpgme_gpg_add_data ( GpgObject gpg, GpgmeData data, int dup_to );  void       _gpgme_gpg_set_status_handler ( GpgObject gpg,                                             GpgStatusHandler fnc,                                             void *fnc_value ); +GpgmeError _gpgme_gpg_set_colon_line_handler ( GpgObject gpg, +                                               GpgColonLineHandler fnc, +                                               void *fnc_value ); +  GpgmeError _gpgme_gpg_spawn ( GpgObject gpg, void *opaque ); diff --git a/gpgme/types.h b/gpgme/types.h index 82f6b79d..045fd7e4 100644 --- a/gpgme/types.h +++ b/gpgme/types.h @@ -47,6 +47,9 @@ typedef struct gpg_object_s *GpgObject;  struct verify_result_s;  typedef struct verify_result_s *VerifyResult; +/*-- key.c --*/ +struct gpgme_key_s; +typedef struct gpgme_key_s *GpgmeKey;  #endif /* TYPES_H */ diff --git a/tests/Makefile.am b/tests/Makefile.am index aced4007..74709b11 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,6 +1,6 @@  ## Process this file with automake to create Makefile.in -TESTS = t-encrypt t-verify +TESTS = t-encrypt t-verify t-keylist  INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/intl diff --git a/tests/t-keylist.c b/tests/t-keylist.c new file mode 100644 index 00000000..43ad3237 --- /dev/null +++ b/tests/t-keylist.c @@ -0,0 +1,74 @@ +/* t-keylist.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" + +#define fail_if_err(a) do { if(a) {                                       \ +                               fprintf (stderr, "%s:%d: GpgmeError %s\n", \ +                                __FILE__, __LINE__, gpgme_strerror(a));   \ +                                exit (1); }                               \ +                             } while(0) + +static void +doit ( GpgmeCtx ctx, const char *pattern ) +{ +    GpgmeError err; + +    err = gpgme_keylist_start (ctx, pattern, 0 ); +    fail_if_err (err); +    gpgme_wait (ctx, 1); +} + + +int  +main (int argc, char **argv ) +{ +    GpgmeCtx ctx; +    GpgmeError err; +    int loop = 0; +    const char *pattern; +     +    if( argc ) { +        argc--; argv++; +    } +     +    if (argc && !strcmp( *argv, "--loop" ) ) { +        loop = 1; +        argc--; argv++; +    } +    pattern = argc? *argv : NULL; + +    err = gpgme_new_context (&ctx); +    fail_if_err (err); +    do { +        doit ( ctx, pattern ); +    } while ( loop ); +    gpgme_release_context (ctx); +     +    return 0; +} + + + | 
