diff --git a/README b/README index 080d6bcd..b244fc55 100644 --- a/README +++ b/README @@ -12,6 +12,7 @@ ftp.gnupg.org/pub/gcrypt/alpha/gnupg/gnupg-1.1.2.tar.gz) and install the agent from the agent subdirectory or use the new gpgme_set_passphrase_cb() + Please subscribe to the gnupg-devel@gnupg.org mailing list if you want to do serious work. diff --git a/configure.in b/configure.in index 41a8b18c..710b0434 100644 --- a/configure.in +++ b/configure.in @@ -13,10 +13,10 @@ AM_MAINTAINER_MODE # AGE, set REVISION to 0. # 3. Interfaces removed (BAD, breaks upward compatibility): Increment # CURRENT, set AGE and REVISION to 0. -AM_INIT_AUTOMAKE(gpgme,0.1.2) -LIBGPGME_LT_CURRENT=0 -LIBGPGME_LT_AGE=0 -LIBGPGME_LT_REVISION=3 +AM_INIT_AUTOMAKE(gpgme,0.1.3) +LIBGPGME_LT_CURRENT=1 +LIBGPGME_LT_AGE=1 +LIBGPGME_LT_REVISION=0 ############################################## AC_SUBST(LIBGPGME_LT_CURRENT) diff --git a/gpgme/context.h b/gpgme/context.h index 6bba5372..86554e04 100644 --- a/gpgme/context.h +++ b/gpgme/context.h @@ -72,6 +72,9 @@ struct gpgme_context_s { GpgmePassphraseCb passphrase_cb; void *passphrase_cb_value; + GpgmeProgressCb progress_cb; + void *progress_cb_value; + GpgmeData help_data_1; }; diff --git a/gpgme/genkey.c b/gpgme/genkey.c index d0abae99..b002372c 100644 --- a/gpgme/genkey.c +++ b/gpgme/genkey.c @@ -31,8 +31,33 @@ static void genkey_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args ) { - if ( code == STATUS_PROGRESS ) + if ( code == STATUS_PROGRESS && *args ) { + if (ctx->progress_cb) { + char *p; + int type=0, current=0, total=0; + + if ( (p = strchr (args, ' ')) ) { + *p++ = 0; + if (*p) { + type = *(byte*)p; + if ( (p = strchr (p+1, ' ')) ) { + *p++ = 0; + if (*p) { + current = atoi (p); + if ( (p = strchr (p+1, ' ')) ) { + *p++ = 0; + total = atoi (p); + } + } + } + } + } + if ( type != 'X' ) + ctx->progress_cb ( ctx->progress_cb_value, args, type, + current, total ); + } return; + } fprintf (stderr, "genkey_status: code=%d args=`%s'\n", code, args ); diff --git a/gpgme/gpgme.c b/gpgme/gpgme.c index 23eef199..97c82504 100644 --- a/gpgme/gpgme.c +++ b/gpgme/gpgme.c @@ -183,7 +183,28 @@ gpgme_set_passphrase_cb ( GpgmeCtx c, GpgmePassphraseCb cb, void *cb_value ) c->passphrase_cb_value = cb_value; } - - +/** + * gpgme_set_pprogress_cb: + * @c: the context + * @cb: A callback function + * @cb_value: The value passed to the callback function + * + * This function sets a callback function to be used as a progress indicator. + * + * The callback function is defined as: + * + * typedef void (*GpgmeProgressCb) (void*cb_value, + * const char *what, int type, + * int curretn, int total); + * + * For details on the progress events, see the entry for the PROGRESS + * status in the file doc/DETAILS of the GnuPG distribution. + **/ +void +gpgme_set_progress_cb ( GpgmeCtx c, GpgmeProgressCb cb, void *cb_value ) +{ + c->progress_cb = cb; + c->progress_cb_value = cb_value; +} diff --git a/gpgme/gpgme.h b/gpgme/gpgme.h index e4f1e95a..7c0e4c47 100644 --- a/gpgme/gpgme.h +++ b/gpgme/gpgme.h @@ -34,7 +34,7 @@ extern "C" { * let autoconf (using the AM_PATH_GPGME macro) check that this * header matches the installed library. * Warning: Do not edit the next line. configure will do that for you! */ -#define GPGME_VERSION "0.1.2" +#define GPGME_VERSION "0.1.3" @@ -99,19 +99,24 @@ typedef enum { } GpgmeSigMode; -typedef const char *(*GpgmePassphraseCb)(void*, const char *desc, void *r_hd); +typedef const char *(*GpgmePassphraseCb)(void*, + const char *desc, void *r_hd); +typedef void (*GpgmeProgressCb)(void *opaque, + const char *what, + int type, int current, int total ); /* Context management */ GpgmeError gpgme_new (GpgmeCtx *r_ctx); -void gpgme_release ( GpgmeCtx c ); -GpgmeCtx gpgme_wait ( GpgmeCtx c, int hang ); +void gpgme_release (GpgmeCtx c); +GpgmeCtx gpgme_wait (GpgmeCtx c, int hang); -char *gpgme_get_notation ( GpgmeCtx c ); -void gpgme_set_armor ( GpgmeCtx c, int yes ); -void gpgme_set_textmode ( GpgmeCtx c, int yes ); -void gpgme_set_passphrase_cb ( GpgmeCtx c, - GpgmePassphraseCb cb, void *cb_value ); +char *gpgme_get_notation (GpgmeCtx c); +void gpgme_set_armor (GpgmeCtx c, int yes); +void gpgme_set_textmode (GpgmeCtx c, int yes); +void gpgme_set_passphrase_cb (GpgmeCtx c, + GpgmePassphraseCb cb, void *cb_value); +void gpgme_set_progress_cb (GpgmeCtx c, GpgmeProgressCb cb, void *cb_value); diff --git a/gpgme/key.c b/gpgme/key.c index c58e859d..909b5cff 100644 --- a/gpgme/key.c +++ b/gpgme/key.c @@ -45,16 +45,43 @@ _gpgme_key_new( GpgmeKey *r_key ) return 0; } + +struct subkey_s * +_gpgme_key_add_subkey (GpgmeKey key) +{ + struct subkey_s *k, *kk; + + k = xtrycalloc (1, sizeof *k); + if (!k) + return NULL; + + if( !(kk=key->keys.next) ) + key->keys.next = k; + else { + while ( kk->next ) + kk = kk->next; + kk->next = k; + } + return k; +} + + void _gpgme_key_release ( GpgmeKey key ) { struct user_id_s *u, *u2; + struct subkey_s *k, *k2; if (!key) return; - xfree (key->fingerprint); - for ( u = key->uids; u; u = u2 ) { + xfree (key->keys.fingerprint); + for (k = key->keys.next; k; k = k2 ) { + k2 = k->next; + xfree (k->fingerprint); + xfree (k); + } + for (u = key->uids; u; u = u2 ) { u2 = u->next; xfree (u); } @@ -250,6 +277,7 @@ gpgme_key_get_as_xml ( GpgmeKey key ) { GpgmeData d; struct user_id_s *u; + struct subkey_s *k; if ( !key ) return NULL; @@ -259,25 +287,33 @@ gpgme_key_get_as_xml ( GpgmeKey key ) _gpgme_data_append_string ( d, "\n" " \n" ); - add_tag_and_string (d, "keyid", key->keyid ); - if (key) - add_tag_and_string (d, "fpr", key->fingerprint ); - add_tag_and_uint (d, "algo", key->key_algo ); - add_tag_and_uint (d, "len", key->key_len ); - add_tag_and_time (d, "created", key->timestamp ); + add_tag_and_string (d, "keyid", key->keys.keyid ); + if (key->keys.fingerprint) + add_tag_and_string (d, "fpr", key->keys.fingerprint ); + add_tag_and_uint (d, "algo", key->keys.key_algo ); + add_tag_and_uint (d, "len", key->keys.key_len ); + add_tag_and_time (d, "created", key->keys.timestamp ); /*add_tag_and_time (d, "expires", key->expires );*/ _gpgme_data_append_string (d, " \n"); - /* No the user IDs */ + /* Now the user IDs */ for ( u = key->uids; u; u = u->next ) { _gpgme_data_append_string (d, " \n"); add_tag_and_string ( d, "raw", u->name ); add_user_id ( d, u->name ); _gpgme_data_append_string (d, " \n"); } - _gpgme_data_append_string (d, " \n"); - _gpgme_data_append_string (d, " \n"); + for (k=key->keys.next; k; k = k->next ) { + _gpgme_data_append_string (d, " \n"); + add_tag_and_string (d, "keyid", k->keyid ); + if (k->fingerprint) + add_tag_and_string (d, "fpr", k->fingerprint ); + add_tag_and_uint (d, "algo", k->key_algo ); + add_tag_and_uint (d, "len", k->key_len ); + add_tag_and_time (d, "created", k->timestamp ); + _gpgme_data_append_string (d, " \n"); + } _gpgme_data_append_string ( d, "\n" ); return _gpgme_data_release_and_return_string (d); @@ -285,3 +321,5 @@ gpgme_key_get_as_xml ( GpgmeKey key ) + + diff --git a/gpgme/key.h b/gpgme/key.h index f95c9092..8c68779f 100644 --- a/gpgme/key.h +++ b/gpgme/key.h @@ -25,8 +25,8 @@ #include "types.h" #include "context.h" - -struct gpgme_key_s { +struct subkey_s { + struct subkey_s *next; struct { unsigned int revoked:1 ; unsigned int expired:1 ; @@ -37,11 +37,19 @@ struct gpgme_key_s { char keyid[16+1]; char *fingerprint; /* malloced hex digits */ time_t timestamp; /* -1 for invalid, 0 for not available */ - struct user_id_s *uids; - }; +struct gpgme_key_s { + struct { + unsigned int revoked:1 ; + unsigned int expired:1 ; + unsigned int disabled:1 ; + } gloflags; + struct subkey_s keys; + struct user_id_s *uids; +}; +struct subkey_s *_gpgme_key_add_subkey (GpgmeKey key); GpgmeError _gpgme_key_append_name ( GpgmeKey key, const char *s ); diff --git a/gpgme/keylist.c b/gpgme/keylist.c index cbd7cb48..5cb124e4 100644 --- a/gpgme/keylist.c +++ b/gpgme/keylist.c @@ -91,14 +91,14 @@ parse_timestamp ( char *p ) static void -set_trust_info ( GpgmeKey key, const char *s ) +set_mainkey_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 'e': key->keys.flags.expired = 1; break; + case 'r': key->keys.flags.revoked = 1; break; + case 'd': key->keys.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; @@ -107,6 +107,19 @@ set_trust_info ( GpgmeKey key, const char *s ) } } +static void +set_subkey_trust_info ( struct subkey_s *k, const char *s ) +{ + /* look at letters and stop at the first digit */ + for (; *s && !my_isdigit (*s); s++ ) { + switch (*s) { + case 'e': k->flags.expired = 1; break; + case 'r': k->flags.revoked = 1; break; + case 'd': k->flags.disabled = 1; break; + } + } +} + /* Note: we are allowed to modify line */ static void @@ -120,15 +133,13 @@ keylist_colon_handler ( GpgmeCtx ctx, char *line ) GpgmeKey key = ctx->tmp_key; int i; const char *trust_info = NULL; - + struct subkey_s *sk = 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, ':'); @@ -142,8 +153,14 @@ keylist_colon_handler ( GpgmeCtx ctx, char *line ) rectype = RT_UID; key = ctx->tmp_key; } - else if ( !strcmp ( p, "sub" ) ) + else if ( !strcmp ( p, "sub" ) && key ) { + /* start a new subkey */ rectype = RT_SUB; + if ( !(sk = _gpgme_key_add_subkey (key)) ) { + ctx->out_of_core=1; + return; + } + } else if ( !strcmp ( p, "pub" ) ) { /* start a new keyblock */ if ( _gpgme_key_new ( &key ) ) { @@ -166,28 +183,27 @@ keylist_colon_handler ( GpgmeCtx ctx, char *line ) rectype = RT_NONE; } - else if ( rectype == RT_PUB /*|| rectype == RT_SUB*/ ) { + else if ( rectype == RT_PUB ) { switch (field) { case 2: /* trust info */ - if ( rectype == RT_PUB ) - trust_info = p; /*save for later */ + trust_info = p; /*save for later */ break; case 3: /* key length */ i = atoi (p); if ( i > 1 ) /* ignore invalid values */ - key->key_len = i; + key->keys.key_len = i; break; case 4: /* pubkey algo */ i = atoi (p); if ( i > 1 && i < 128 ) - key->key_algo = i; + key->keys.key_algo = i; break; case 5: /* long keyid */ - if ( strlen (p) == DIM(key->keyid)-1 ) - strcpy (key->keyid, p); + if ( strlen (p) == DIM(key->keys.keyid)-1 ) + strcpy (key->keys.keyid, p); break; case 6: /* timestamp (1998-02-28) */ - key->timestamp = parse_timestamp (p); + key->keys.timestamp = parse_timestamp (p); break; case 7: /* valid for n days */ break; @@ -196,13 +212,11 @@ keylist_colon_handler ( GpgmeCtx ctx, char *line ) 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); - } + if ( _gpgme_key_append_name ( key, p) ) + ctx->out_of_core = 1; + else { + if (trust_info) + set_mainkey_trust_info (key, trust_info); } break; case 11: /* signature class */ @@ -212,6 +226,43 @@ keylist_colon_handler ( GpgmeCtx ctx, char *line ) break; } } + else if ( rectype == RT_SUB && sk ) { + switch (field) { + case 2: /* trust info */ + set_subkey_trust_info ( sk, p); + break; + case 3: /* key length */ + i = atoi (p); + if ( i > 1 ) /* ignore invalid values */ + sk->key_len = i; + break; + case 4: /* pubkey algo */ + i = atoi (p); + if ( i > 1 && i < 128 ) + sk->key_algo = i; + break; + case 5: /* long keyid */ + if ( strlen (p) == DIM(sk->keyid)-1 ) + strcpy (sk->keyid, p); + break; + case 6: /* timestamp (1998-02-28) */ + sk->timestamp = parse_timestamp (p); + break; + case 7: /* valid for n days */ + break; + case 8: /* reserved (LID) */ + break; + case 9: /* ownertrust */ + break; + case 10:/* user ID n/a for a subkey */ + 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 */ @@ -222,7 +273,7 @@ keylist_colon_handler ( GpgmeCtx ctx, char *line ) ctx->out_of_core = 1; else { if (trust_info) - set_trust_info (key, trust_info); + set_mainkey_trust_info (key, trust_info); } pend = NULL; /* we can stop here */ break; @@ -231,9 +282,9 @@ keylist_colon_handler ( GpgmeCtx ctx, char *line ) 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 ) + if ( !key->keys.fingerprint && *p ) { + key->keys.fingerprint = xtrystrdup (p); + if ( !key->keys.fingerprint ) ctx->out_of_core = 1; } pend = NULL; /* that is all we want */ @@ -266,7 +317,7 @@ finish_key ( GpgmeCtx ctx ) } q->key = key; q->next = NULL; - /* fixme: lock queue */ + /* fixme: lock queue. Use a tail pointer? */ if ( !(q2 = ctx->key_queue) ) ctx->key_queue = q; else { @@ -373,12 +424,3 @@ gpgme_op_keylist_next ( GpgmeCtx c, GpgmeKey *r_key ) - - - - - - - - - diff --git a/gpgme/w32-io.c b/gpgme/w32-io.c index 47736224..237c0386 100644 --- a/gpgme/w32-io.c +++ b/gpgme/w32-io.c @@ -559,8 +559,8 @@ _gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds ) (int)GetLastError ()); } else if ( navail ) { - fprintf (stderr, "** fd %d has %d bytes to read\n", - fds[i].fd, navail ); + /*fprintf (stderr, "** fd %d has %d bytes to read\n", + fds[i].fd, navail );*/ fds[i].signaled = 1; count++; } diff --git a/gpgme/wait.c b/gpgme/wait.c index b024b092..edd492ee 100644 --- a/gpgme/wait.c +++ b/gpgme/wait.c @@ -234,7 +234,7 @@ do_select ( void ) if ( n <= 0 ) return 0; /* error or timeout */ - for (i=0; i < fd_table_size /*&& n*/; i++ ) { + for (i=0; i < fd_table_size && n; i++ ) { if ( fd_table[i].fd != -1 && fd_table[i].signaled && !fd_table[i].frozen ) { q = fd_table[i].opaque; @@ -328,7 +328,7 @@ _gpgme_freeze_fd ( int fd ) for (i=0; i < fd_table_size; i++ ) { if ( fd_table[i].fd == fd ) { fd_table[i].frozen = 1; - fprintf (stderr, "** FD %d frozen\n", fd ); + /*fprintf (stderr, "** FD %d frozen\n", fd );*/ break; } } @@ -344,7 +344,7 @@ _gpgme_thaw_fd ( int fd ) for (i=0; i < fd_table_size; i++ ) { if ( fd_table[i].fd == fd ) { fd_table[i].frozen = 0; - fprintf (stderr, "** FD %d thawed\n", fd ); + /*fprintf (stderr, "** FD %d thawed\n", fd );*/ break; } } diff --git a/tests/Makefile.am b/tests/Makefile.am index 3f5f2349..de7a0456 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -2,8 +2,8 @@ TESTS_ENVIRONMENT = GNUPGHOME=. -TESTS = t-encrypt t-sign t-decrypt t-verify t-keylist t-export t-import \ - t-genkey +TESTS = t-encrypt t-sign t-decrypt t-verify t-keylist t-export t-import + EXTRA_DIST = mkdemodirs pubdemo.asc secdemo.asc cipher-1.asc geheim.txt \ pubkey-1.asc seckey-1.asc @@ -13,7 +13,8 @@ INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/intl INCLUDES = LDADD = ../gpgme/libgpgme.la -noinst_PROGRAMS = $(TESTS) +# We don't run t-genkey in the test suite, because it taes too long +noinst_PROGRAMS = $(TESTS) t-genkey distclean-local: $(srcdir)/mkdemodirs --clean diff --git a/tests/t-genkey.c b/tests/t-genkey.c index 710dfa0b..d22b95ea 100644 --- a/tests/t-genkey.c +++ b/tests/t-genkey.c @@ -32,6 +32,13 @@ } while(0) +static void +progress ( void *self, const char *what, int type, int current, int total) +{ + fprintf (stderr, "progress `%s' %d %d %d\n", what, type, current, total); +} + + int main (int argc, char **argv ) { @@ -45,6 +52,8 @@ main (int argc, char **argv ) err = gpgme_new (&ctx); fail_if_err (err); + gpgme_set_progress_cb (ctx, progress, NULL); + format = "\n" "Key-Type: DSA\n" "Key-Length: 1024\n"