diff options
Diffstat (limited to 'gpgme/keylist.c')
| -rw-r--r-- | gpgme/keylist.c | 334 | 
1 files changed, 334 insertions, 0 deletions
| 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; +} + + + + + + | 
