See ChangeLog: Sun Jan 24 18:16:26 CET 1999 Werner Koch
authorWerner Koch <wk@gnupg.org>
Sun, 24 Jan 1999 17:16:40 +0000 (17:16 +0000)
committerWerner Koch <wk@gnupg.org>
Sun, 24 Jan 1999 17:16:40 +0000 (17:16 +0000)
13 files changed:
NEWS
PROJECTS
VERSION
acconfig.h
configure.in
doc/gpg.1pod
g10/ChangeLog
g10/g10.c
g10/getkey.c
g10/keydb.h
g10/keylist.c
g10/openfile.c
g10/parse-packet.c

diff --git a/NEWS b/NEWS
index 75fa0aa..8b423f7 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,8 @@
+
+    * changed the internal design of getkey which now allows a
+      efficient lookup of multiple keys and add a word match mode.
+
+
 Noteworthy changes in version 0.9.2
 -----------------------------------
 
index c5c4458..ce0e5be 100644 (file)
--- a/PROJECTS
+++ b/PROJECTS
@@ -47,3 +47,8 @@
 
     * Keep a list of duplicate, faked or unwanted keyids.
 
+    * use regular C strings for the user ids; this can be done because
+      OpenPGP requires them to be UTF-8 and we can replace a Null by
+      an UTF-8 character (which one?)
+
+
diff --git a/VERSION b/VERSION
index 2003b63..112d5be 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.9.2
+0.9.2a
index de2fa3e..d3b6cf0 100644 (file)
 #undef IPC_HAVE_SHM_LOCK
 #undef IPC_RMID_DEFERRED_RELEASE
 
+/* set this to limit filenames to the 8.3 format */
+#undef USE_ONLY_8DOT3
+/* defined if we must run on a stupid file system */
+#undef HAVE_DRIVE_LETTERS
+
 @BOTTOM@
 
 #include "g10defs.h"
index 9606095..a9975bf 100644 (file)
@@ -100,6 +100,8 @@ case "${target}" in
         RANLIB="i386--mingw32-ranlib"
         ac_cv_have_dev_random=no
         AC_DEFINE(USE_RNDW32)
+        AC_DEFINE(USE_ONLY_8DOT3)
+        AC_DEFINE(HAVE_DRIVE_LETTERS)
         ;;
     *-*-hpux*)
         if test -z "$GCC" ; then
index 1e9cdcf..21cc126 100644 (file)
@@ -253,7 +253,7 @@ B<--trusted-key>  I<keyid>
     time GnuPG starts up:  Use for I<keyid> the one of
     your key.
 
-B<-r>  I<name>, B<--remote-user>  I<name>
+B<-r>  I<name>, B<--recipient> I<name>
     Use I<name> as the user-id for encryption.
     This option is silently ignored for the list commands,
     so that it can be used in an options file.
index e3ba21f..8a09ff3 100644 (file)
@@ -1,3 +1,18 @@
+Sun Jan 24 18:16:26 CET 1999  Werner Koch  <wk@isil.d.shuttle.de>
+
+       * getkey.c: Changed the internal design to allow simultaneous
+       lookup of multible user ids
+       (get_pubkey_bynames): New.
+       (get_seckey_bynames): New.
+       (get_seckey_next): New.
+       (get_seckey_end): New.
+       * keylist.c (list_one): Use the new functions.
+
+       * keylist.c (list_keyblock): add a newline for normal listings.
+
+       * g10.c (--recipient): New option name to replace --remote-user
+
+
 Wed Jan 20 18:59:49 CET 1999  Werner Koch  <wk@isil.d.shuttle.de>
 
        * textfilter.c: Mostly rewritten
index c9d6b65..df0cd48 100644 (file)
--- a/g10/g10.c
+++ b/g10/g10.c
@@ -60,7 +60,7 @@ enum cmd_and_opt_values { aNull = 0,
     oDryRun      = 'n',
     oOutput      = 'o',
     oQuiet       = 'q',
-    oRemote      = 'r',
+    oRecipient   = 'r',
     aSign        = 's',
     oTextmodeShort= 't',
     oUser        = 'u',
@@ -215,9 +215,10 @@ static ARGPARSE_OPTS opts[] = {
     { 301, NULL, 0, N_("@\nOptions:\n ") },
 
     { oArmor, "armor",     0, N_("create ascii armored output")},
+    { oRecipient, "recipient", 2, N_("|NAME|encrypt for NAME")},
+    { oRecipient, "remote-user", 2, "@"},  /* old option name */
   #ifdef IS_G10
     { oUser, "local-user",2, N_("use this user-id to sign or decrypt")},
-    { oRemote, "remote-user", 2, N_("use this user-id for encryption")},
     { oCompress, NULL,       1, N_("|N|set compress level N (0 disables)") },
     { oTextmodeShort, NULL,   0, "@"},
     { oTextmode, "textmode",  0, N_("use canonical text mode")},
@@ -552,7 +553,7 @@ main( int argc, char **argv )
     opt.max_cert_depth = 5;
     opt.homedir = getenv("GNUPGHOME");
     if( !opt.homedir || !*opt.homedir ) {
-      #ifdef __MINGW32__
+      #ifdef HAVE_DRIVE_LETTERS
        opt.homedir = "c:/gnupg";
       #else
        opt.homedir = "~/.gnupg";
@@ -758,7 +759,7 @@ main( int argc, char **argv )
          case oS2KCipher: s2k_cipher_string = m_strdup(pargs.r.ret_str); break;
 
        #ifdef IS_G10
-         case oRemote: /* store the remote users */
+         case oRecipient: /* store the recipient */
            sl = m_alloc( sizeof *sl + strlen(pargs.r.ret_str));
            strcpy(sl->d, pargs.r.ret_str);
            sl->next = remusr;
index 0a8e4b2..770aa58 100644 (file)
@@ -1,5 +1,5 @@
 /* getkey.c -  Get a key from the database
- *     Copyright (C) 1998 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 1999 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -18,8 +18,6 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
  */
 
-#define DEFINES_GETKEY_CTX 1
-
 #include <config.h>
 #include <stdio.h>
 #include <stdlib.h>
 #define MAX_PK_CACHE_ENTRIES   50
 #define MAX_UID_CACHE_ENTRIES  50
 
+/* Aa map of the all characters valid used for word_match()
+ * Valid characters are in in this table converted to uppercase.
+ * becuase the upper 128 bytes have special meanin, we assume
+ * that they are all valid.
+ * Note: We must use numerical values here in case that this program
+ * will be converted to those little blue HAL9000s with their strange
+ * EBCDIC character set (user ids are UTF-8). */
+static const byte word_match_chars[256] = {
+  /* 00 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  /* 08 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  /* 10 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  /* 18 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  /* 20 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  /* 28 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  /* 30 */  0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+  /* 38 */  0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  /* 40 */  0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+  /* 48 */  0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+  /* 50 */  0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+  /* 58 */  0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00,
+  /* 60 */  0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+  /* 68 */  0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+  /* 70 */  0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+  /* 78 */  0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00,
+  /* 80 */  0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+  /* 88 */  0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+  /* 90 */  0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+  /* 98 */  0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+  /* a0 */  0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+  /* a8 */  0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+  /* b0 */  0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+  /* b8 */  0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+  /* c0 */  0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+  /* c8 */  0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+  /* d0 */  0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+  /* d8 */  0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+  /* e0 */  0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+  /* e8 */  0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+  /* f0 */  0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+  /* f8 */  0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+};
 
-struct getkey_ctx_s {
+typedef struct {
     int mode;
-    int internal;
     u32 keyid[2];
+    byte fprint[20];
     char *namebuf;
     const char *name;
+} getkey_item_t;
+
+struct getkey_ctx_s {
+    /* make an array or a linked list from dome fields */
     int primary;
     KBNODE keyblock;
     KBPOS kbpos;
     int last_rc;
     ulong count;
+    int nitems;
+    getkey_item_t items[1];
 };
 
 
 
 
 
-
+#if 0
 static struct {
     int any;
     int okay_count;
     int nokey_count;
     int error_count;
 } lkup_stats[21];
-
+#endif
 
 
 
@@ -104,17 +149,12 @@ static int uid_cache_entries;     /* number of entries in uid cache */
 
 
 
-static int lookup( GETKEY_CTX *ctx, PKT_public_key *pk,
-                  int mode,  u32 *keyid, const char *name,
-                  KBNODE *ret_keyblock, int primary  );
-static void lookup_close( GETKEY_CTX ctx );
-static int  lookup_read( GETKEY_CTX ctx,
-                        PKT_public_key *pk, KBNODE *ret_keyblock );
-static int lookup_sk( PKT_secret_key *sk,
-                  int mode,  u32 *keyid, const char *name, int primary );
-
+static char* prepare_word_match( const byte *name );
+static int lookup_pk( GETKEY_CTX ctx, PKT_public_key *pk, KBNODE *ret_kb );
+static int lookup_sk( GETKEY_CTX ctx, PKT_secret_key *sk, KBNODE *ret_kb );
 
 
+#if 0
 static void
 print_stats()
 {
@@ -129,7 +169,7 @@ print_stats()
                    lkup_stats[i].error_count );
     }
 }
-
+#endif
 
 
 static void
@@ -280,7 +320,14 @@ get_pubkey( PKT_public_key *pk, u32 *keyid )
 
 
     /* do a lookup */
-    rc = lookup( NULL, pk, 11, keyid, NULL, NULL, 0 );
+    {  struct getkey_ctx_s ctx;
+       memset( &ctx, 0, sizeof ctx );
+       ctx.nitems = 1;
+       ctx.items[0].mode = 11;
+       ctx.items[0].keyid[0] = keyid[0];
+       ctx.items[0].keyid[1] = keyid[1];
+       rc = lookup_pk( &ctx, pk, NULL );
+    }
     if( !rc )
        goto leave;
 
@@ -314,6 +361,77 @@ get_pubkey( PKT_public_key *pk, u32 *keyid )
 }
 
 
+/****************
+ * Get a secret key and store it into sk
+ */
+int
+get_seckey( PKT_secret_key *sk, u32 *keyid )
+{
+    int rc;
+    struct getkey_ctx_s ctx;
+
+    memset( &ctx, 0, sizeof ctx );
+    ctx.nitems = 1;
+    ctx.items[0].mode = 11;
+    ctx.items[0].keyid[0] = keyid[0];
+    ctx.items[0].keyid[1] = keyid[1];
+    rc = lookup_sk( &ctx, sk, NULL );
+    if( !rc ) {
+       /* check the secret key (this may prompt for a passprase to
+        * unlock the secret key
+        */
+       rc = check_secret_key( sk, 0 );
+    }
+
+    return rc;
+}
+
+
+/****************
+ * Get the primary secret key and store it into sk
+ * Note: This function does not unprotect the key!
+ */
+int
+get_primary_seckey( PKT_secret_key *sk, u32 *keyid )
+{
+    struct getkey_ctx_s ctx;
+
+    memset( &ctx, 0, sizeof ctx );
+    ctx.primary = 1;
+    ctx.nitems = 1;
+    ctx.items[0].mode = 11;
+    ctx.items[0].keyid[0] = keyid[0];
+    ctx.items[0].keyid[1] = keyid[1];
+    return lookup_sk( &ctx, sk, NULL );
+}
+
+
+
+/****************
+ * Check whether the secret key is available
+ * Returns: 0 := key is available
+ *         G10ERR_NO_SECKEY := not availabe
+ */
+int
+seckey_available( u32 *keyid )
+{
+    int rc;
+    struct getkey_ctx_s ctx;
+    PKT_secret_key *sk;
+
+    sk = m_alloc_clear( sizeof *sk );
+    memset( &ctx, 0, sizeof ctx );
+    ctx.nitems = 1;
+    ctx.items[0].mode = 11;
+    ctx.items[0].keyid[0] = keyid[0];
+    ctx.items[0].keyid[1] = keyid[1];
+    rc = lookup_sk( &ctx, sk, NULL );
+    free_secret_key( sk );
+    return rc;
+}
+
+
+
 static int
 hextobyte( const byte *s )
 {
@@ -350,6 +468,7 @@ hextobyte( const byte *s )
  *  3 = match an email address
  *  4 = match a substring of an email address
  *  5 = match an email address, but compare from end
+ *  6 = word match mode
  * 10 = it is a short KEYID (don't care about keyid[0])
  * 11 = it is a long  KEYID
  * 16 = it is a 16 byte fingerprint
@@ -372,6 +491,11 @@ hextobyte( const byte *s )
  * - If the userid start with an '=' an exact compare is done.
  * - If the userid starts with a '*' a case insensitive substring search is
  *   done (This is the default).
+ * - If the userid starts with a '+' we will compare individual words
+ *   and a match requires that all the words are in the userid.
+ *   Words are delimited by white space or "()<>[]{}.@-+_,;/&!"
+ *   (note that you can't search for these characters). Compare
+ *   is not case sensitive.
  */
 
 int
@@ -460,6 +584,10 @@ classify_user_id( const char *name, u32 *keyid, byte *fprint,
        mode = 5;
        s++;
     }
+    else if( *s == '+' ) { /* word match mode */
+       mode = 6;
+       s++;
+    }
     else if( *s == '#' ) { /* use local id */
        return 0;
     }
@@ -481,51 +609,62 @@ classify_user_id( const char *name, u32 *keyid, byte *fprint,
 /****************
  * Try to get the pubkey by the userid. This function looks for the
  * first pubkey certificate which has the given name in a user_id.
- * if pk has the pubkey algo set, the function will only return
+ * if pk/sk has the pubkey algo set, the function will only return
  * a pubkey with that algo.
+ * The caller must provide provide storage for either the pk or the sk.
+ * If ret_kb is not NULL the funtion will return the keyblock there.
  */
 
 static int
-key_byname( int secret, GETKEY_CTX *retctx,
-           PKT_public_key *pk, PKT_secret_key *sk,
-           const char *name, KBNODE *ret_kb )
+key_byname( GETKEY_CTX *retctx, STRLIST namelist,
+           PKT_public_key *pk, PKT_secret_key *sk, KBNODE *ret_kb )
 {
-    int internal = 0;
     int rc = 0;
-    const char *s;
-    u32 keyid[2] = {0}; /* init to avoid compiler warning */
-    byte fprint[20];
-    int mode;
-
-    mode = classify_user_id( name, keyid, fprint, &s, NULL );
-    if( !mode ) {
-       rc = G10ERR_INV_USER_ID;
-       goto leave;
-    }
+    int n;
+    STRLIST r;
+    GETKEY_CTX ctx;
 
-    if( secret ) {
-       if( !sk ) {
-           sk = m_alloc_clear( sizeof *sk );
-           internal++;
+    assert( !pk ^ !sk );
+
+    /* build the search context */
+    /* Performance hint: Use a static buffer if there is only one name */
+    /*                  and we don't have mode 6 */
+    for(n=0, r=namelist; r; r = r->next )
+       n++;
+    ctx = m_alloc_clear( sizeof *ctx + (n-1)*sizeof ctx->items );
+    ctx->nitems = n;
+
+    for(n=0, r=namelist; r; r = r->next, n++ ) {
+       ctx->items[n].mode = classify_user_id( r->d,
+                                             ctx->items[n].keyid,
+                                             ctx->items[n].fprint,
+                                             &ctx->items[n].name,
+                                             NULL );
+       if( !ctx->items[n].mode ) {
+           m_free( ctx );
+           return G10ERR_INV_USER_ID;
        }
-       rc = mode < 16? lookup_sk( sk, mode, keyid, s, 1 )
-                     : lookup_sk( sk, mode, keyid, fprint, 1 );
-    }
-    else {
-       if( !pk ) {
-           pk = m_alloc_clear( sizeof *pk );
-           internal++;
+       if( ctx->items[n].mode == 6 ) {
+           ctx->items[n].namebuf = prepare_word_match(ctx->items[n].name);
+           ctx->items[n].name = ctx->items[n].namebuf;
        }
-       rc = mode < 16? lookup( retctx, pk, mode, keyid, s, ret_kb, 1 )
-                     : lookup( retctx, pk, mode, keyid, fprint, ret_kb, 1 );
     }
 
+    /* and call the lookup function */
+    ctx->primary = 1; /* we want to look for the primary key only */
+    if( sk )
+       rc = lookup_sk( ctx, sk, NULL );
+    else
+       rc = lookup_pk( ctx, pk, NULL );
+
+    if( retctx ) /* caller wants the context */
+       *retctx = ctx;
+    else {
+       for(n=0; n < ctx->nitems; n++ )
+           m_free( ctx->items[n].namebuf );
+       m_free( ctx );
+    }
 
-  leave:
-    if( internal && secret )
-       m_free( sk );
-    else if( internal )
-       m_free( pk );
     return rc;
 }
 
@@ -534,15 +673,38 @@ get_pubkey_byname( GETKEY_CTX *retctx, PKT_public_key *pk,
                   const char *name, KBNODE *ret_keyblock )
 {
     int rc;
+    STRLIST namelist = NULL;
+
+    add_to_strlist( &namelist, name );
 
     if( !pk ) {
-       /* fixme: key_byname should not need a pk in this case */
+       /* Performance Hint: key_byname should not need a pk here */
        pk = m_alloc_clear( sizeof *pk );
-       rc = key_byname( 0, retctx, pk, NULL, name, ret_keyblock );
+       rc = key_byname( retctx, namelist, pk, NULL, ret_keyblock );
        free_public_key( pk );
     }
     else
-       rc = key_byname( 0, retctx, pk, NULL, name, ret_keyblock );
+       rc = key_byname( retctx, namelist, pk, NULL, ret_keyblock );
+
+    free_strlist( namelist );
+    return rc;
+}
+
+int
+get_pubkey_bynames( GETKEY_CTX *retctx, PKT_public_key *pk,
+                   STRLIST names, KBNODE *ret_keyblock )
+{
+    int rc;
+
+    if( !pk ) {
+       /* Performance Hint: key_byname should not need a pk here */
+       pk = m_alloc_clear( sizeof *pk );
+       rc = key_byname( retctx, names, pk, NULL, ret_keyblock );
+       free_public_key( pk );
+    }
+    else
+       rc = key_byname( retctx, names, pk, NULL, ret_keyblock );
+
     return rc;
 }
 
@@ -552,13 +714,13 @@ get_pubkey_next( GETKEY_CTX ctx, PKT_public_key *pk, KBNODE *ret_keyblock )
     int rc;
 
     if( !pk ) {
-       /* fixme: lookup_read should not need a pk in this case */
+       /* Performance Hint: lookup_read should not need a pk in this case */
        pk = m_alloc_clear( sizeof *pk );
-       rc = lookup_read( ctx, pk, ret_keyblock );
+       rc = lookup_pk( ctx, pk, ret_keyblock );
        free_public_key( pk );
     }
     else
-       rc = lookup_read( ctx, pk, ret_keyblock );
+       rc = lookup_pk( ctx, pk, ret_keyblock );
     return rc;
 }
 
@@ -566,7 +728,11 @@ void
 get_pubkey_end( GETKEY_CTX ctx )
 {
     if( ctx ) {
-       lookup_close( ctx );
+       int n;
+
+       enum_keyblocks( 2, &ctx->kbpos, NULL ); /* close */
+       for(n=0; n < ctx->nitems; n++ )
+           m_free( ctx->items[n].namebuf );
        m_free( ctx );
     }
 }
@@ -579,8 +745,14 @@ get_pubkey_byfprint( PKT_public_key *pk, const byte *fprint, size_t fprint_len)
 {
     int rc;
 
-    if( fprint_len == 20 || fprint_len == 16 )
-       rc = lookup( NULL, pk, fprint_len, NULL, fprint, NULL, 0 );
+    if( fprint_len == 20 || fprint_len == 16 ) {
+       struct getkey_ctx_s ctx;
+       memset( &ctx, 0, sizeof ctx );
+       ctx.nitems = 1;
+       ctx.items[0].mode = fprint_len;
+       memcpy( ctx.items[0].fprint, fprint, fprint_len );
+       rc = lookup_pk( &ctx, pk, NULL );
+    }
     else
        rc = G10ERR_GENERAL; /* Oops */
     return rc;
@@ -597,8 +769,14 @@ get_keyblock_byfprint( KBNODE *ret_keyblock, const byte *fprint,
     int rc;
     PKT_public_key *pk = m_alloc_clear( sizeof *pk );
 
-    if( fprint_len == 20 || fprint_len == 16 )
-       rc = lookup( NULL, pk, fprint_len, NULL, fprint, ret_keyblock, 0 );
+    if( fprint_len == 20 || fprint_len == 16 ) {
+       struct getkey_ctx_s ctx;
+       memset( &ctx, 0, sizeof ctx );
+       ctx.nitems = 1;
+       ctx.items[0].mode = fprint_len;
+       memcpy( ctx.items[0].fprint, fprint, fprint_len );
+       rc = lookup_pk( &ctx, pk, ret_keyblock );
+    }
     else
        rc = G10ERR_GENERAL; /* Oops */
 
@@ -606,76 +784,183 @@ get_keyblock_byfprint( KBNODE *ret_keyblock, const byte *fprint,
     return rc;
 }
 
+
+
+
+
 /****************
- * Get a secret key and store it into sk
+ * Get a secret key by name and store it into sk
+ * If NAME is NULL use the default key
  */
 int
-get_seckey( PKT_secret_key *sk, u32 *keyid )
+get_seckey_byname( PKT_secret_key *sk, const char *name, int unprotect )
 {
+    STRLIST namelist = NULL;
     int rc;
 
-    rc = lookup_sk( sk, 11, keyid, NULL, 0 );
-    if( !rc ) {
-       /* check the secret key (this may prompt for a passprase to
-        * unlock the secret key
-        */
-       rc = check_secret_key( sk, 0 );
+    if( !name && opt.def_secret_key && *opt.def_secret_key ) {
+       add_to_strlist( &namelist, opt.def_secret_key );
+       rc = key_byname( NULL, namelist, NULL, sk, NULL );
+    }
+    else if( !name ) { /* use the first one as default key */
+       struct getkey_ctx_s ctx;
+
+       memset( &ctx, 0, sizeof ctx );
+       ctx.primary = 1;
+       ctx.nitems = 1;
+       ctx.items[0].mode = 15;
+       rc = lookup_sk( &ctx, sk, NULL );
     }
+    else {
+       add_to_strlist( &namelist, name );
+       rc = key_byname( NULL, namelist, NULL, sk, NULL );
+    }
+
+    free_strlist( namelist );
+
+    if( !rc && unprotect )
+       rc = check_secret_key( sk, 0 );
 
     return rc;
 }
 
-/****************
- * Get the primary secret key and store it into sk
- * Note: This function does not unprotect the key!
- */
 int
-get_primary_seckey( PKT_secret_key *sk, u32 *keyid )
+get_seckey_bynames( GETKEY_CTX *retctx, PKT_secret_key *sk,
+                   STRLIST names, KBNODE *ret_keyblock )
 {
-    return lookup_sk( sk, 11, keyid, NULL, 1 );
+    int rc;
+
+    if( !sk ) {
+       /* Performance Hint: key_byname should not need a sk here */
+       sk = m_alloc_secure_clear( sizeof *sk );
+       rc = key_byname( retctx, names, NULL, sk, ret_keyblock );
+       free_secret_key( sk );
+    }
+    else
+       rc = key_byname( retctx, names, NULL, sk, ret_keyblock );
+
+    return rc;
 }
 
-/****************
- * Check whether the secret key is available
- * Returns: 0 := key is available
- *         G10ERR_NO_SECKEY := not availabe
- */
+
 int
-seckey_available( u32 *keyid )
+get_seckey_next( GETKEY_CTX ctx, PKT_secret_key *sk, KBNODE *ret_keyblock )
 {
-    PKT_secret_key *sk;
     int rc;
 
-    sk = m_alloc_clear( sizeof *sk );
-    rc = lookup_sk( sk, 11, keyid, NULL, 0 );
-    free_secret_key( sk );
+    if( !sk ) {
+       /* Performance Hint: lookup_read should not need a pk in this case */
+       sk = m_alloc_secure_clear( sizeof *sk );
+       rc = lookup_sk( ctx, sk, ret_keyblock );
+       free_secret_key( sk );
+    }
+    else
+       rc = lookup_sk( ctx, sk, ret_keyblock );
     return rc;
 }
 
+void
+get_seckey_end( GETKEY_CTX ctx )
+{
+    if( ctx ) {
+       int n;
+
+       enum_keyblocks( 2, &ctx->kbpos, NULL ); /* close */
+       for(n=0; n < ctx->nitems; n++ )
+           m_free( ctx->items[n].namebuf );
+       m_free( ctx );
+    }
+}
+
 
 
 /****************
- * Get a secret key by name and store it into sk
- * If NAME is NULL use the default key
+ * Do a word match (original user id starts with a '+').
+ * The pattern is already tokenized to a more suitable format:
+ * There are only the real words in it delimited by one space
+ * and all converted to uppercase.
+ *
+ * Returns: 0 if all words match.
+ *
+ * Note: This algorithm is a straightforward one and not very
+ *      fast.  It works for UTF-8 strings.  The uidlen should
+ *      be removed but due to the fact that old versions of
+ *      pgp don't use UTF-8 we still use the length; this should
+ *      be fixed in parse-packet (and replace \0 by some special
+ *      UTF-8 encoding)
  */
-int
-get_seckey_byname( PKT_secret_key *sk, const char *name, int unprotect )
+static int
+word_match( const byte *uid, size_t uidlen, const byte *pattern )
 {
-    int rc;
+    size_t wlen, n;
+    const byte *p;
+    const byte *s;
+
+    for( s=pattern; *s; ) {
+       do {
+           /* skip leading delimiters */
+           while( uidlen && !word_match_chars[*uid] )
+               uid++, uidlen--;
+           /* get length of the word */
+           n = uidlen; p = uid;
+           while( n && word_match_chars[*p] )
+               p++, n--;
+           wlen = p - uid;
+           /* and compare against the current word from pattern */
+           for(n=0, p=uid; n < wlen && s[n] != ' ' && s[n] ; n++, p++ ) {
+               if( word_match_chars[*p] != s[n] )
+                   break;
+           }
+           if( n == wlen && (s[n] == ' ' || !s[n]) )
+               break; /* found */
+           uid += wlen;
+           uidlen -= wlen;
+       } while( uidlen );
+       if( !uidlen )
+           return -1; /* not found */
+
+       /* advance to next word in pattern */
+       for(; *s != ' ' && *s ; s++ )
+           ;
+       if( *s )
+           s++ ;
+    }
+    return 0; /* found */
+}
 
-    if( !name && opt.def_secret_key && *opt.def_secret_key )
-       rc = key_byname( 1, NULL, NULL, sk, opt.def_secret_key, NULL );
-    else if( !name ) /* use the first one as default key */
-       rc = lookup_sk( sk, 15, NULL, NULL, 1 );
-    else
-       rc = key_byname( 1, NULL, NULL, sk, name, NULL );
-    if( !rc && unprotect )
-       rc = check_secret_key( sk, 0 );
+/****************
+ * prepare word word_match; that is parse the name and
+ * build the pattern.
+ * caller has to free the returned pattern
+ */
+static char*
+prepare_word_match( const byte *name )
+{
+    byte *pattern, *p;
+    int c;
 
-    return rc;
+    /* the original length is always enough for the pattern */
+    p = pattern = m_alloc(strlen(name)+1);
+    do {
+       /* skip leading delimiters */
+       while( *name && !word_match_chars[*name] )
+           name++;
+       /* copy as long as we don't have a delimiter and convert
+        * to uppercase.
+        * fixme: how can we handle utf8 uppercasing */
+       for( ; *name &&  (c=word_match_chars[*name]); name++ )
+           *p++ = c;
+       *p++ = ' '; /* append pattern delimiter */
+    } while( *name );
+    p[-1] = 0; /* replace last pattern delimiter by EOS */
+
+    return pattern;
 }
 
 
+
+
+
 static int
 compare_name( const char *uid, size_t uidlen, const char *name, int mode )
 {
@@ -717,6 +1002,8 @@ compare_name( const char *uid, size_t uidlen, const char *name, int mode )
            }
        }
     }
+    else if( mode == 6 )
+       return word_match( uid, uidlen, name );
     else
        BUG();
 
@@ -897,6 +1184,45 @@ find_by_name( KBNODE keyblock, PKT_public_key *pk, const char *name,
     return NULL;
 }
 
+static KBNODE
+find_by_name_sk( KBNODE keyblock, PKT_secret_key *sk, const char *name,
+                int mode )
+{
+    KBNODE k, kk;
+
+    for(k=keyblock; k; k = k->next ) {
+       if( k->pkt->pkttype == PKT_USER_ID
+           && !compare_name( k->pkt->pkt.user_id->name,
+                             k->pkt->pkt.user_id->len, name, mode)) {
+           /* we found a matching name, look for the key */
+           for(kk=keyblock; kk; kk = kk->next ) {
+               if( (    kk->pkt->pkttype == PKT_SECRET_KEY
+                     || kk->pkt->pkttype == PKT_SECRET_SUBKEY )
+                   && ( !sk->pubkey_algo
+                        || sk->pubkey_algo
+                           == kk->pkt->pkt.secret_key->pubkey_algo)
+                   && ( !sk->pubkey_usage
+                        || !check_pubkey_algo2(
+                              kk->pkt->pkt.secret_key->pubkey_algo,
+                                                  sk->pubkey_usage ))
+                 )
+                   break;
+           }
+           if( kk ) {
+               u32 aki[2];
+               keyid_from_sk( kk->pkt->pkt.secret_key, aki );
+               cache_user_id( k->pkt->pkt.user_id, aki );
+               return kk;
+           }
+           else if( is_RSA(sk->pubkey_algo) )
+               log_error("RSA key cannot be used in this version\n");
+           else
+               log_error("No key for userid\n");
+       }
+    }
+    return NULL;
+}
+
 
 static KBNODE
 find_by_keyid( KBNODE keyblock, PKT_public_key *pk, u32 *keyid, int mode )
@@ -938,6 +1264,46 @@ find_by_keyid( KBNODE keyblock, PKT_public_key *pk, u32 *keyid, int mode )
     return NULL;
 }
 
+static KBNODE
+find_by_keyid_sk( KBNODE keyblock, PKT_secret_key *sk, u32 *keyid, int mode )
+{
+    KBNODE k;
+
+    if( DBG_CACHE )
+       log_debug("lookup_sk keyid=%08lx%08lx req_algo=%d mode=%d\n",
+                  (ulong)keyid[0], (ulong)keyid[1], sk->pubkey_algo, mode );
+
+    for(k=keyblock; k; k = k->next ) {
+       if(    k->pkt->pkttype == PKT_SECRET_KEY
+           || k->pkt->pkttype == PKT_SECRET_SUBKEY ) {
+           u32 aki[2];
+           keyid_from_sk( k->pkt->pkt.secret_key, aki );
+           if( DBG_CACHE )
+               log_debug("         aki=%08lx%08lx algo=%d\n",
+                               (ulong)aki[0], (ulong)aki[1],
+                                k->pkt->pkt.secret_key->pubkey_algo    );
+
+           if( aki[1] == keyid[1]
+               && ( mode == 10 || aki[0] == keyid[0] )
+               && ( !sk->pubkey_algo
+                    || sk->pubkey_algo
+                       == k->pkt->pkt.secret_key->pubkey_algo) ){
+               KBNODE kk;
+               /* cache the userid */
+               for(kk=keyblock; kk; kk = kk->next )
+                   if( kk->pkt->pkttype == PKT_USER_ID )
+                       break;
+               if( kk )
+                   cache_user_id( kk->pkt->pkt.user_id, aki );
+               else
+                   log_error("No userid for key\n");
+               return k; /* found */
+           }
+       }
+    }
+    return NULL;
+}
+
 
 static KBNODE
 find_first( KBNODE keyblock, PKT_public_key *pk )
@@ -956,6 +1322,23 @@ find_first( KBNODE keyblock, PKT_public_key *pk )
     return NULL;
 }
 
+static KBNODE
+find_first_sk( KBNODE keyblock, PKT_secret_key *sk )
+{
+    KBNODE k;
+
+    for(k=keyblock; k; k = k->next ) {
+       if(    k->pkt->pkttype == PKT_SECRET_KEY
+           || k->pkt->pkttype == PKT_SECRET_SUBKEY )
+       {
+           if( !sk->pubkey_algo
+               || sk->pubkey_algo == k->pkt->pkt.secret_key->pubkey_algo )
+               return k;
+       }
+    }
+    return NULL;
+}
+
 
 static KBNODE
 find_by_fpr( KBNODE keyblock, PKT_public_key *pk, const char *name, int mode )
@@ -988,6 +1371,38 @@ find_by_fpr( KBNODE keyblock, PKT_public_key *pk, const char *name, int mode )
     return NULL;
 }
 
+static KBNODE
+find_by_fpr_sk( KBNODE keyblock, PKT_secret_key *sk,
+                                const char *name, int mode )
+{
+    KBNODE k;
+
+    for(k=keyblock; k; k = k->next ) {
+       if(    k->pkt->pkttype == PKT_SECRET_KEY
+           || k->pkt->pkttype == PKT_SECRET_SUBKEY ) {
+           byte afp[MAX_FINGERPRINT_LEN];
+           size_t an;
+
+           fingerprint_from_sk(k->pkt->pkt.secret_key, afp, &an );
+
+           if( DBG_CACHE ) {
+               u32 aki[2];
+               keyid_from_sk( k->pkt->pkt.secret_key, aki );
+               log_debug("         aki=%08lx%08lx algo=%d mode=%d an=%u\n",
+                               (ulong)aki[0], (ulong)aki[1],
+                       k->pkt->pkt.secret_key->pubkey_algo, mode, an );
+           }
+
+           if( an == mode
+               && !memcmp( afp, name, an)
+               && ( !sk->pubkey_algo
+                    || sk->pubkey_algo == k->pkt->pkt.secret_key->pubkey_algo) )
+               return k;
+       }
+    }
+    return NULL;
+}
+
 
 static void
 finish_lookup( KBNODE keyblock, PKT_public_key *pk, KBNODE k, byte *namehash,
@@ -1048,73 +1463,63 @@ finish_lookup( KBNODE keyblock, PKT_public_key *pk, KBNODE k, byte *namehash,
     }
 }
 
-/****************
- * Lookup a key by scanning all keyresources
- *   mode 1 = lookup by NAME (exact)
- *       2 = lookup by NAME (substring)
- *       3 = lookup by NAME (email address)
- *       4 = email address (substring)
- *       5 = email address (compare from end)
- *      10 = lookup by short KEYID (don't care about keyid[0])
- *      11 = lookup by long  KEYID
- *      15 = Get the first key.
- *      16 = lookup by 16 byte fingerprint which is stored in NAME
- *      20 = lookup by 20 byte fingerprint which is stored in NAME
- * Caller must provide an empty PK, if the pubkey_algo is filled in, only
- * a key of this algo will be returned.
- * If ret_keyblock is not NULL, the complete keyblock is returned also
- * and the caller must release it.
- */
-static int
-lookup( GETKEY_CTX *retctx, PKT_public_key *pk, int mode, u32 *keyid,
-       const char *name, KBNODE *ret_keyblock, int primary )
+static void
+finish_lookup_sk( KBNODE keyblock, PKT_secret_key *sk, KBNODE k, int primary )
 {
-    struct getkey_ctx_s help_ctx;
-    GETKEY_CTX ctx;
-    int rc;
-
-    if( !retctx )
-       ctx = &help_ctx;
-    else {
-       ctx = m_alloc( sizeof *ctx );
-       *retctx = ctx;
+    assert(    k->pkt->pkttype == PKT_SECRET_KEY
+           || k->pkt->pkttype == PKT_SECRET_SUBKEY );
+    assert( keyblock->pkt->pkttype == PKT_SECRET_KEY );
+    if( primary && !sk->pubkey_usage ) {
+       copy_secret_key( sk, keyblock->pkt->pkt.secret_key );
     }
+    else {
+       if( primary && sk->pubkey_usage
+           && check_pubkey_algo2( k->pkt->pkt.secret_key->pubkey_algo,
+                      sk->pubkey_usage ) == G10ERR_WR_PUBKEY_ALGO ) {
+           /* if the usage is not correct, try to use a subkey */
+           KBNODE save_k = k;
 
-    memset( ctx, 0, sizeof *ctx );
-    ctx->mode = mode;
-    if( keyid ) {
-       ctx->keyid[0] = keyid[0];
-       ctx->keyid[1] = keyid[1];
-    }
-    if( retctx ) {
-       ctx->namebuf = name? m_strdup(name) : NULL;
-       ctx->name = ctx->namebuf;
-    }
-    else
-       ctx->name = name;
-    ctx->primary = primary;
-    rc = lookup_read( ctx, pk, ret_keyblock );
-    if( !retctx )
-       lookup_close( ctx );
-    return rc;
-}
+           k = NULL;
+           /* kludge for pgp 5: which doesn't accept type 20:
+            * try to use a type 16 subkey instead */
+           if( sk->pubkey_usage == PUBKEY_USAGE_ENC ) {
+               for( k = save_k; k; k = k->next ) {
+                   if( k->pkt->pkttype == PKT_SECRET_SUBKEY
+                       && k->pkt->pkt.secret_key->pubkey_algo
+                           == PUBKEY_ALGO_ELGAMAL_E
+                       && !check_pubkey_algo2(
+                               k->pkt->pkt.secret_key->pubkey_algo,
+                                                sk->pubkey_usage ) )
+                       break;
+               }
+           }
 
-static void
-lookup_close( GETKEY_CTX ctx )
-{
-    enum_keyblocks( 2, &ctx->kbpos, NULL ); /* close */
-    m_free( ctx->namebuf );
+           if( !k ) {
+               for(k = save_k ; k; k = k->next ) {
+                   if( k->pkt->pkttype == PKT_SECRET_SUBKEY
+                       && !check_pubkey_algo2(
+                               k->pkt->pkt.secret_key->pubkey_algo,
+                                                sk->pubkey_usage ) )
+                       break;
+               }
+           }
+           if( !k )
+               k = save_k;
+           else
+               log_info(_("using secondary key %08lX "
+                          "instead of primary key %08lX\n"),
+                     (ulong)keyid_from_sk( k->pkt->pkt.secret_key, NULL),
+                     (ulong)keyid_from_sk( save_k->pkt->pkt.secret_key, NULL)
+                       );
+       }
+
+       copy_secret_key( sk, k->pkt->pkt.secret_key );
+    }
 }
 
-static int
-lookup_read( GETKEY_CTX ctx, PKT_public_key *pk, KBNODE *ret_keyblock )
-{
-    int rc;
-    KBNODE k;
-    int oldmode = set_packet_list_mode(0);
-    byte namehash[20];
-    int use_namehash=0;
 
+/****** old code from lookup_read ******/
+#if 0 /* can't use it anymore - invent a more general approach */
     /* try the quick functions */
     if( !ctx->count ) {
        k = NULL;
@@ -1157,39 +1562,60 @@ lookup_read( GETKEY_CTX ctx, PKT_public_key *pk, KBNODE *ret_keyblock )
      *       works, but the key was not found, we will not find it
      *       in the other resources */
     if( rc == G10ERR_UNSUPPORTED ) {
-       if( !ctx->count )
-           rc = enum_keyblocks( 0, &ctx->kbpos, &ctx->keyblock );
-       else
-           rc = 0;
-       if( !rc ) {
-           while( !(rc = enum_keyblocks( 1, &ctx->kbpos, &ctx->keyblock )) ) {
-               /* fixme: we donĀ“t enum the complete keyblock, but
-                * use the first match and that continue with the next keyblock
-                */
-               if( ctx->mode < 10 )
-                   k = find_by_name( ctx->keyblock, pk, ctx->name, ctx->mode,
-                                                   namehash, &use_namehash);
-               else if( ctx->mode == 10 ||ctx-> mode == 11 )
-                   k = find_by_keyid( ctx->keyblock, pk, ctx->keyid,
-                                                               ctx->mode );
-               else if( ctx->mode == 15 )
+    }
+#endif
+
+
+static int
+lookup_pk( GETKEY_CTX ctx, PKT_public_key *pk, KBNODE *ret_keyblock )
+{
+    int rc;
+    KBNODE k;
+    int oldmode = set_packet_list_mode(0);
+    byte namehash[20];
+    int use_namehash=0;
+
+    if( !ctx->count ) /* first time */
+       rc = enum_keyblocks( 0, &ctx->kbpos, &ctx->keyblock );
+    else
+       rc = 0;
+    if( !rc ) {
+       while( !(rc = enum_keyblocks( 1, &ctx->kbpos, &ctx->keyblock )) ) {
+           int n;
+           getkey_item_t *item;
+           /* fixme: we don't enum the complete keyblock, but
+            * use the first match and then continue with the next keyblock
+            */
+           /* loop over all the user ids we want to look for */
+           item = ctx->items;
+           for(n=0; n < ctx->nitems; n++, item++ ) {
+               if( item->mode < 10 )
+                   k = find_by_name( ctx->keyblock, pk,
+                                     item->name, item->mode,
+                                     namehash, &use_namehash );
+               else if( item->mode == 10 || item->mode == 11 )
+                   k = find_by_keyid( ctx->keyblock, pk,
+                                      item->keyid, item->mode );
+               else if( item->mode == 15 )
                    k = find_first( ctx->keyblock, pk );
-               else if( ctx->mode == 16 || ctx->mode == 20 )
-                   k = find_by_fpr( ctx->keyblock, pk, ctx->name, ctx->mode );
+               else if( item->mode == 16 || item->mode == 20 )
+                   k = find_by_fpr( ctx->keyblock, pk,
+                                    item->name, item->mode );
                else
                    BUG();
                if( k ) {
                    finish_lookup( ctx->keyblock, pk, k, namehash,
                                                 use_namehash, ctx->primary );
-                   break; /* found */
+                   goto found;
                }
-               release_kbnode( ctx->keyblock );
-               ctx->keyblock = NULL;
            }
+           release_kbnode( ctx->keyblock );
+           ctx->keyblock = NULL;
        }
-       if( rc && rc != -1 )
-           log_error("enum_keyblocks failed: %s\n", g10_errstr(rc));
+      found: ;
     }
+    if( rc && rc != -1 )
+       log_error("enum_keyblocks failed: %s\n", g10_errstr(rc));
 
     if( !rc ) {
        if( ret_keyblock ) {
@@ -1203,6 +1629,7 @@ lookup_read( GETKEY_CTX ctx, PKT_public_key *pk, KBNODE *ret_keyblock )
     release_kbnode( ctx->keyblock );
     ctx->keyblock = NULL;
     set_packet_list_mode(oldmode);
+  #if 0
     if( opt.debug & DBG_MEMSTAT_VALUE ) {
        static int initialized;
 
@@ -1220,6 +1647,7 @@ lookup_read( GETKEY_CTX ctx, PKT_public_key *pk, KBNODE *ret_keyblock )
        else
            lkup_stats[ctx->mode].error_count++;
     }
+   #endif
 
     ctx->last_rc = rc;
     ctx->count++;
@@ -1227,144 +1655,214 @@ lookup_read( GETKEY_CTX ctx, PKT_public_key *pk, KBNODE *ret_keyblock )
 }
 
 
-/****************
- * Ditto for secret keys
- */
+
 static int
-lookup_sk( PKT_secret_key *sk, int mode,  u32 *keyid, const char *name,
-          int primary )
+lookup_sk( GETKEY_CTX ctx, PKT_secret_key *sk, KBNODE *ret_keyblock )
 {
     int rc;
-    KBNODE keyblock = NULL;
-    KBPOS kbpos;
+    KBNODE k;
     int oldmode = set_packet_list_mode(0);
 
-    rc = enum_keyblocks( 5 /* open secret */, &kbpos, &keyblock );
-    if( rc ) {
-       if( rc == -1 )
-           rc = G10ERR_NO_SECKEY;
-       else if( rc )
-           log_error("enum_keyblocks(open secret) failed: %s\n", g10_errstr(rc) );
-       goto leave;
-    }
-
-    while( !(rc = enum_keyblocks( 1, &kbpos, &keyblock )) ) {
-       KBNODE k, kk;
-       if( mode < 10 ) { /* name lookup */
-           for(k=keyblock; k; k = k->next ) {
-               if( k->pkt->pkttype == PKT_USER_ID
-                   && !compare_name( k->pkt->pkt.user_id->name,
-                                     k->pkt->pkt.user_id->len, name, mode)) {
-                   /* we found a matching name, look for the key */
-                   for(kk=keyblock; kk; kk = kk->next ) {
-                       if( (    kk->pkt->pkttype == PKT_SECRET_KEY
-                             || kk->pkt->pkttype == PKT_SECRET_SUBKEY )
-                           && ( !sk->pubkey_algo
-                                || sk->pubkey_algo
-                                   == kk->pkt->pkt.secret_key->pubkey_algo)
-                           && ( !sk->pubkey_usage
-                                || !check_pubkey_algo2(
-                                      kk->pkt->pkt.secret_key->pubkey_algo,
-                                                          sk->pubkey_usage ))
-                         )
-                           break;
-                   }
-                   if( kk ) {
-                       u32 aki[2];
-                       keyid_from_sk( kk->pkt->pkt.secret_key, aki );
-                       cache_user_id( k->pkt->pkt.user_id, aki );
-                       k = kk;
-                       break;
-                   }
-                   else
-                       log_error("No key for userid (in sk)\n");
+    if( !ctx->count ) /* first time */
+       rc = enum_keyblocks( 5, &ctx->kbpos, &ctx->keyblock );
+    else
+       rc = 0;
+    if( !rc ) {
+       while( !(rc = enum_keyblocks( 1, &ctx->kbpos, &ctx->keyblock )) ) {
+           int n;
+           getkey_item_t *item;
+           /* fixme: we don't enum the complete keyblock, but
+            * use the first match and then continue with the next keyblock
+            */
+           /* loop over all the user ids we want to look for */
+           item = ctx->items;
+           for(n=0; n < ctx->nitems; n++, item++ ) {
+               if( item->mode < 10 )
+                   k = find_by_name_sk( ctx->keyblock, sk,
+                                        item->name, item->mode );
+               else if( item->mode == 10 || item->mode == 11 )
+                   k = find_by_keyid_sk( ctx->keyblock, sk,
+                                         item->keyid, item->mode );
+               else if( item->mode == 15 )
+                   k = find_first_sk( ctx->keyblock, sk );
+               else if( item->mode == 16 || item->mode == 20 )
+                   k = find_by_fpr_sk( ctx->keyblock, sk,
+                                       item->name, item->mode );
+               else
+                   BUG();
+               if( k ) {
+                   finish_lookup_sk( ctx->keyblock, sk, k, ctx->primary );
+                   goto found;
                }
            }
+           release_kbnode( ctx->keyblock );
+           ctx->keyblock = NULL;
        }
-       else { /* keyid or fingerprint lookup */
-           if( DBG_CACHE && (mode== 10 || mode==11) ) {
-               log_debug("lookup_sk keyid=%08lx%08lx req_algo=%d mode=%d\n",
-                               (ulong)keyid[0], (ulong)keyid[1],
-                                sk->pubkey_algo, mode );
-           }
-           for(k=keyblock; k; k = k->next ) {
-               if(    k->pkt->pkttype == PKT_SECRET_KEY
-                   || k->pkt->pkttype == PKT_SECRET_SUBKEY ) {
-                   if( mode == 10 || mode == 11 ) {
-                       u32 aki[2];
-                       keyid_from_sk( k->pkt->pkt.secret_key, aki );
-                       if( DBG_CACHE ) {
-                           log_debug("             aki=%08lx%08lx algo=%d\n",
-                                           (ulong)aki[0], (ulong)aki[1],
-                                   k->pkt->pkt.secret_key->pubkey_algo    );
-                       }
-                       if( aki[1] == keyid[1]
-                           && ( mode == 10 || aki[0] == keyid[0] )
-                           && ( !sk->pubkey_algo
-                                || sk->pubkey_algo
-                                   == k->pkt->pkt.secret_key->pubkey_algo) ){
-                           /* cache the userid */
-                           for(kk=keyblock; kk; kk = kk->next )
-                               if( kk->pkt->pkttype == PKT_USER_ID )
-                                   break;
-                           if( kk )
-                               cache_user_id( kk->pkt->pkt.user_id, aki );
-                           else
-                               log_error("No userid for key\n");
-                           break; /* found */
-                       }
-                   }
-                   else if( mode == 15 ) { /* get the first key */
-                       if( !sk->pubkey_algo
-                           || sk->pubkey_algo
-                                 == k->pkt->pkt.secret_key->pubkey_algo )
-                           break;
-                   }
-                   else if( mode == 16 || mode == 20 ) {
-                       size_t an;
-                       byte afp[MAX_FINGERPRINT_LEN];
-
-                       fingerprint_from_sk(k->pkt->pkt.secret_key, afp, &an );
-                       if( an == mode && !memcmp( afp, name, an)
-                           && ( !sk->pubkey_algo
-                                || sk->pubkey_algo
-                                   == k->pkt->pkt.secret_key->pubkey_algo) ) {
-                           break;
-                       }
-                   }
-                   else
-                       BUG();
-               } /* end compare secret keys */
-           }
-       }
-       if( k ) { /* found */
-           assert(    k->pkt->pkttype == PKT_SECRET_KEY
-                   || k->pkt->pkttype == PKT_SECRET_SUBKEY );
-           assert( keyblock->pkt->pkttype == PKT_SECRET_KEY );
-           if( primary && !sk->pubkey_usage )
-               copy_secret_key( sk, keyblock->pkt->pkt.secret_key );
-           else
-               copy_secret_key( sk, k->pkt->pkt.secret_key );
-           break; /* enumeration */
+      found: ;
+    }
+    if( rc && rc != -1 )
+       log_error("enum_keyblocks failed: %s\n", g10_errstr(rc));
+
+    if( !rc ) {
+       if( ret_keyblock ) {
+           *ret_keyblock = ctx->keyblock;
+           ctx->keyblock = NULL;
        }
-       release_kbnode( keyblock );
-       keyblock = NULL;
     }
-    if( rc == -1 )
-       rc = G10ERR_NO_SECKEY;
-    else if( rc )
-       log_error("enum_keyblocks(read) failed: %s\n", g10_errstr(rc));
+    else if( rc == -1 )
+       rc = G10ERR_NO_PUBKEY;
 
-  leave:
-    enum_keyblocks( 2, &kbpos, &keyblock ); /* close */
-    release_kbnode( keyblock );
+    release_kbnode( ctx->keyblock );
+    ctx->keyblock = NULL;
     set_packet_list_mode(oldmode);
+
+    ctx->last_rc = rc;
+    ctx->count++;
     return rc;
 }
 
 
+#if 0
+OLD/************
+OLD * Ditto for secret keys WORK!!!!!!
+OLD */
+OLDstatic int
+OLDlookup_sk( PKT_secret_key *sk, int mode,  u32 *keyid, const char *name,
+OLD          int primary )
+OLD{
+OLD    int rc;
+OLD    KBNODE keyblock = NULL;
+OLD    KBPOS kbpos;
+OLD    int oldmode = set_packet_list_mode(0);
+OLD
+OLD    rc = enum_keyblocks( 5 /* open secret */, &kbpos, &keyblock );
+OLD    if( rc ) {
+OLD       if( rc == -1 )
+OLD           rc = G10ERR_NO_SECKEY;
+OLD       else if( rc )
+OLD           log_error("enum_keyblocks(open secret) failed: %s\n", g10_errstr(rc) );
+OLD       goto leave;
+OLD    }
+OLD
+OLD    while( !(rc = enum_keyblocks( 1, &kbpos, &keyblock )) ) {
+OLD       KBNODE k, kk;
+OLD       if( mode < 10 ) { /* name lookup */
+OLD           for(k=keyblock; k; k = k->next ) {
+OLD               if( k->pkt->pkttype == PKT_USER_ID
+OLD                   && !compare_name( k->pkt->pkt.user_id->name,
+OLD                                     k->pkt->pkt.user_id->len, name, mode)) {
+OLD                   /* we found a matching name, look for the key */
+OLD                   for(kk=keyblock; kk; kk = kk->next ) {
+OLD                       if( (    kk->pkt->pkttype == PKT_SECRET_KEY
+OLD                             || kk->pkt->pkttype == PKT_SECRET_SUBKEY )
+OLD                           && ( !sk->pubkey_algo
+OLD                                || sk->pubkey_algo
+OLD                                   == kk->pkt->pkt.secret_key->pubkey_algo)
+OLD                           && ( !sk->pubkey_usage
+OLD                                || !check_pubkey_algo2(
+OLD                                      kk->pkt->pkt.secret_key->pubkey_algo,
+OLD                                                          sk->pubkey_usage ))
+OLD                         )
+OLD                           break;
+OLD                   }
+OLD                   if( kk ) {
+OLD                       u32 aki[2];
+OLD                       keyid_from_sk( kk->pkt->pkt.secret_key, aki );
+OLD                       cache_user_id( k->pkt->pkt.user_id, aki );
+OLD                       k = kk;
+OLD                       break;
+OLD                   }
+OLD                   else
+OLD                       log_error("No key for userid (in sk)\n");
+OLD               }
+OLD           }
+OLD       }
+OLD       else { /* keyid or fingerprint lookup */
+OLD           if( DBG_CACHE && (mode== 10 || mode==11) ) {
+OLD               log_debug("lookup_sk keyid=%08lx%08lx req_algo=%d mode=%d\n",
+OLD                               (ulong)keyid[0], (ulong)keyid[1],
+OLD                                sk->pubkey_algo, mode );
+OLD           }
+OLD           for(k=keyblock; k; k = k->next ) {
+OLD               if(    k->pkt->pkttype == PKT_SECRET_KEY
+OLD                   || k->pkt->pkttype == PKT_SECRET_SUBKEY ) {
+OLD                   if( mode == 10 || mode == 11 ) {
+OLD                       u32 aki[2];
+OLD                       keyid_from_sk( k->pkt->pkt.secret_key, aki );
+OLD                       if( DBG_CACHE ) {
+OLD                           log_debug("             aki=%08lx%08lx algo=%d\n",
+OLD                                           (ulong)aki[0], (ulong)aki[1],
+OLD                                   k->pkt->pkt.secret_key->pubkey_algo    );
+OLD                       }
+OLD                       if( aki[1] == keyid[1]
+OLD                           && ( mode == 10 || aki[0] == keyid[0] )
+OLD                           && ( !sk->pubkey_algo
+OLD                                || sk->pubkey_algo
+OLD                                   == k->pkt->pkt.secret_key->pubkey_algo) ){
+OLD                           /* cache the userid */
+OLD                           for(kk=keyblock; kk; kk = kk->next )
+OLD                               if( kk->pkt->pkttype == PKT_USER_ID )
+OLD                                   break;
+OLD                           if( kk )
+OLD                               cache_user_id( kk->pkt->pkt.user_id, aki );
+OLD                           else
+OLD                               log_error("No userid for key\n");
+OLD                           break; /* found */
+OLD                       }
+OLD                   }
+OLD                   else if( mode == 15 ) { /* get the first key */
+OLD                       if( !sk->pubkey_algo
+OLD                           || sk->pubkey_algo
+OLD                                 == k->pkt->pkt.secret_key->pubkey_algo )
+OLD                           break;
+OLD                   }
+OLD                   else if( mode == 16 || mode == 20 ) {
+OLD                       size_t an;
+OLD                       byte afp[MAX_FINGERPRINT_LEN];
+OLD
+OLD                       fingerprint_from_sk(k->pkt->pkt.secret_key, afp, &an );
+OLD                       if( an == mode && !memcmp( afp, name, an)
+OLD                           && ( !sk->pubkey_algo
+OLD                                || sk->pubkey_algo
+OLD                                   == k->pkt->pkt.secret_key->pubkey_algo) ) {
+OLD                           break;
+OLD                       }
+OLD                   }
+OLD                   else
+OLD                       BUG();
+OLD               } /* end compare secret keys */
+OLD           }
+OLD       }
+OLD       if( k ) { /* found */
+OLD           assert(    k->pkt->pkttype == PKT_SECRET_KEY
+OLD                   || k->pkt->pkttype == PKT_SECRET_SUBKEY );
+OLD           assert( keyblock->pkt->pkttype == PKT_SECRET_KEY );
+OLD           if( primary && !sk->pubkey_usage )
+OLD               copy_secret_key( sk, keyblock->pkt->pkt.secret_key );
+OLD           else
+OLD               copy_secret_key( sk, k->pkt->pkt.secret_key );
+OLD           break; /* enumeration */
+OLD       }
+OLD       release_kbnode( keyblock );
+OLD       keyblock = NULL;
+OLD    }
+OLD    if( rc == -1 )
+OLD       rc = G10ERR_NO_SECKEY;
+OLD    else if( rc )
+OLD       log_error("enum_keyblocks(read) failed: %s\n", g10_errstr(rc));
+OLD
+OLD  leave:
+OLD    enum_keyblocks( 2, &kbpos, &keyblock ); /* close */
+OLD    release_kbnode( keyblock );
+OLD    set_packet_list_mode(oldmode);
+OLD    return rc;
+OLD}
+#endif
+
 
 /****************
+ * fixme: replace by the generic function
+ *
  * Enumerate all primary secret keys.  Caller must use these procedure:
  *  1) create a void pointer and initialize it to NULL
  *  2) pass this void pointer by reference to this function
index 73c2d59..9a7dcc8 100644 (file)
 
 #define MAX_FINGERPRINT_LEN 20
 
+struct getkey_ctx_s;
 typedef struct getkey_ctx_s *GETKEY_CTX;
-#ifndef DEFINES_GETKEY_CTX
-struct getkey_ctx_s { char hidden[1]; };
-#endif
 
 /****************
  * A Keyblock is all packets which form an entire certificate;
@@ -135,6 +133,8 @@ void getkey_disable_caches(void);
 int get_pubkey( PKT_public_key *pk, u32 *keyid );
 int get_pubkey_byname( GETKEY_CTX *rx, PKT_public_key *pk,
                       const char *name, KBNODE *ret_keyblock );
+int get_pubkey_bynames( GETKEY_CTX *rx, PKT_public_key *pk,
+                       STRLIST names, KBNODE *ret_keyblock );
 int get_pubkey_next( GETKEY_CTX ctx, PKT_public_key *pk, KBNODE *ret_keyblock );
 void get_pubkey_end( GETKEY_CTX ctx );
 int get_seckey( PKT_secret_key *sk, u32 *keyid );
@@ -145,6 +145,10 @@ int get_keyblock_byfprint( KBNODE *ret_keyblock, const byte *fprint,
                                                 size_t fprint_len );
 int seckey_available( u32 *keyid );
 int get_seckey_byname( PKT_secret_key *sk, const char *name, int unlock );
+int get_seckey_bynames( GETKEY_CTX *rx, PKT_secret_key *sk,
+                       STRLIST names, KBNODE *ret_keyblock );
+int get_seckey_next( GETKEY_CTX ctx, PKT_secret_key *sk, KBNODE *ret_keyblock );
+void get_seckey_end( GETKEY_CTX ctx );
 int enum_secret_keys( void **context, PKT_secret_key *sk, int with_subkeys );
 void merge_keys_and_selfsig( KBNODE keyblock );
 char*get_user_id_string( u32 *keyid );
index 3c68680..2a471b8 100644 (file)
@@ -36,7 +36,7 @@
 #include "i18n.h"
 
 static void list_all(int);
-static void list_one(const char *name, int secret);
+static void list_one( STRLIST names, int secret);
 static void list_keyblock( KBNODE keyblock, int secret );
 static void fingerprint( PKT_public_key *pk, PKT_secret_key *sk );
 
@@ -51,8 +51,11 @@ public_key_list( int nnames, char **names )
     if( !nnames )
        list_all(0);
     else { /* List by user id */
+       STRLIST list = NULL;
        for( ; nnames ; nnames--, names++ )
-           list_one( *names, 0 );
+           add_to_strlist( &list, *names );
+       list_one( list, 0 );
+       free_strlist( list );
     }
 }
 
@@ -62,8 +65,11 @@ secret_key_list( int nnames, char **names )
     if( !nnames )
        list_all(1);
     else { /* List by user id */
+       STRLIST list = NULL;
        for( ; nnames ; nnames--, names++ )
-           list_one( *names, 1 );
+           add_to_strlist( &list, *names );
+       list_one( list, 0 );
+       free_strlist( list );
     }
 }
 
@@ -111,36 +117,30 @@ list_all( int secret )
 
 
 static void
-list_one( const char *name, int secret )
+list_one( STRLIST names, int secret )
 {
     int rc = 0;
     KBNODE keyblock = NULL;
+    GETKEY_CTX ctx;
 
     if( secret ) {
-       KBPOS kbpos;
-
-       rc = secret? find_secret_keyblock_byname( &kbpos, name )
-                  : find_keyblock_byname( &kbpos, name );
-       if( rc ) {
-           log_error("%s: user not found\n", name );
-           return;
-       }
-
-       rc = read_keyblock( &kbpos, &keyblock );
+       rc = get_seckey_bynames( &ctx, NULL, names, &keyblock );
        if( rc ) {
-           log_error("%s: keyblock read problem: %s\n", name, g10_errstr(rc) );
+           log_error("error reading key: %s\n",  g10_errstr(rc) );
+           get_seckey_end( ctx );
            return;
        }
-       merge_keys_and_selfsig( keyblock );
-       list_keyblock( keyblock, secret );
-       release_kbnode( keyblock );
+       do {
+           merge_keys_and_selfsig( keyblock );
+           list_keyblock( keyblock, 0 );
+           release_kbnode( keyblock );
+       } while( !get_seckey_next( ctx, NULL, &keyblock ) );
+       get_seckey_end( ctx );
     }
     else {
-       GETKEY_CTX ctx;
-
-       rc = get_pubkey_byname( &ctx, NULL, name, &keyblock );
+       rc = get_pubkey_bynames( &ctx, NULL, names, &keyblock );
        if( rc ) {
-           log_error("%s: %s\n", name, g10_errstr(rc) );
+           log_error("error reading key: %s\n", g10_errstr(rc) );
            get_pubkey_end( ctx );
            return;
        }
@@ -380,6 +380,8 @@ list_keyblock( KBNODE keyblock, int secret )
            putchar(':');
        putchar('\n');
     }
+    else if( !opt.with_colons )
+       putchar('\n');  /* separator line */
 }
 
 
index 5b2d468..8e5a51a 100644 (file)
 #include "status.h"
 #include "i18n.h"
 
+#ifdef USE_ONLY_8DOT3
+  #define SKELEXT ".skl"
+#else
+  #define SKELEXT ".skel"
+#endif
 
 /****************
  * Check whether FNAME exists and ask if it's okay to overwrite an
@@ -91,6 +96,9 @@ open_outfile( const char *iname, int mode, IOBUF *a )
        if( opt.outfile )
            name = opt.outfile;
        else {
+         #ifdef USE_ONLY_8DOT3
+           #error please implement this
+         #endif
            buf = m_alloc(strlen(iname)+4+1);
            strcpy(stpcpy(buf,iname), mode==1 ? ".asc" :
                                      mode==2 ? ".sig" : ".gpg");
@@ -122,6 +130,9 @@ open_sigfile( const char *iname )
     IOBUF a = NULL;
     size_t len;
 
+  #ifdef USE_ONLY_8DOT3
+    #error please implement this
+  #endif
     if( iname && !(*iname == '-' && !iname[1]) ) {
        len = strlen(iname);
        if( len > 4 && ( !strcmp(iname + len - 4, ".sig")
@@ -152,7 +163,7 @@ copy_options_file( const char *destdir )
     int c;
 
     fname = m_alloc( strlen(datadir) + strlen(destdir) + 15 );
-    strcpy(stpcpy(fname, datadir), "/options.skel" );
+    strcpy(stpcpy(fname, datadir), "/options" SKELEXT );
     src = fopen( fname, "r" );
     if( !src ) {
        log_error(_("%s: can't open: %s\n"), fname, strerror(errno) );
index 53d8c7b..3c45a45 100644 (file)
@@ -1397,15 +1397,28 @@ parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
 {
     byte *p;
 
-    packet->pkt.user_id = m_alloc(sizeof *packet->pkt.user_id  + pktlen - 1);
+    packet->pkt.user_id = m_alloc(sizeof *packet->pkt.user_id  + pktlen);
     packet->pkt.user_id->len = pktlen;
     p = packet->pkt.user_id->name;
-    for( ; pktlen; pktlen--, p++ )
+    for( ; pktlen; pktlen--, p++ ) {
        *p = iobuf_get_noeof(inp);
+       /* 0xff is not a valid utf-8 encoding so we can use it to replace
+        * Nulls. This has the advantage that we can work with regular
+        * C strings. When exporting it, we change it back to Null
+        * the utf-8 functions know about this special convention.
+        * The advantage of this single character is that we can
+        * simple replace it.  Problem is that we can't handle the 0xff
+        * character which may have been used by pref rfc2440 implementations
+        * I hope we can live with this. */
+       if( !*p )
+           *p = 0xff;
+    }
+    *p = 0;
 
     if( list_mode ) {
        int n = packet->pkt.user_id->len;
        printf(":user id packet: \"");
+       /* fixme: Hey why don't we replace this wioth print_string?? */
        for(p=packet->pkt.user_id->name; n; p++, n-- ) {
            if( *p >= ' ' && *p <= 'z' )
                putchar(*p);