speedo: Improve speedo Makefile.
[gnupg.git] / g10 / getkey.c
index 96537b7..707a106 100644 (file)
@@ -35,6 +35,7 @@
 #include "trustdb.h"
 #include "i18n.h"
 #include "keyserver-internal.h"
+#include "call-agent.h"
 
 #define MAX_PK_CACHE_ENTRIES   PK_UID_CACHE_SIZE
 #define MAX_UID_CACHE_ENTRIES  PK_UID_CACHE_SIZE
@@ -46,6 +47,7 @@
 struct getkey_ctx_s
 {
   int exact;
+  int want_secret;       /* The caller requested only secret keys.  */
   KBNODE keyblock;
   KBPOS kbpos;
   KBNODE found_key;     /* Pointer into some keyblock. */
@@ -101,8 +103,8 @@ typedef struct user_id_db
 static user_id_db_t user_id_db;
 static int uid_cache_entries;  /* Number of entries in uid cache. */
 
-static void merge_selfsigs (KBNODE keyblock);
-static int lookup (GETKEY_CTX ctx, KBNODE * ret_keyblock, int secmode);
+static void merge_selfsigs (kbnode_t keyblock);
+static int lookup (getkey_ctx_t ctx, kbnode_t *ret_keyblock, int want_secret);
 
 #if 0
 static void
@@ -126,17 +128,21 @@ void
 cache_public_key (PKT_public_key * pk)
 {
 #if MAX_PK_CACHE_ENTRIES
-  pk_cache_entry_t ce;
+  pk_cache_entry_t ce, ce2;
   u32 keyid[2];
 
   if (pk_cache_disabled)
     return;
 
-  if (pk->dont_cache)
+  if (pk->flags.dont_cache)
     return;
 
   if (is_ELGAMAL (pk->pubkey_algo)
-      || pk->pubkey_algo == PUBKEY_ALGO_DSA || is_RSA (pk->pubkey_algo))
+      || pk->pubkey_algo == PUBKEY_ALGO_DSA
+      || pk->pubkey_algo == PUBKEY_ALGO_ECDSA
+      || pk->pubkey_algo == PUBKEY_ALGO_EDDSA
+      || pk->pubkey_algo == PUBKEY_ALGO_ECDH
+      || is_RSA (pk->pubkey_algo))
     {
       keyid_from_pk (pk, keyid);
     }
@@ -153,11 +159,25 @@ cache_public_key (PKT_public_key * pk)
 
   if (pk_cache_entries >= MAX_PK_CACHE_ENTRIES)
     {
-      /* fixme: Use another algorithm to free some cache slots.  */
-      pk_cache_disabled = 1;
-      if (opt.verbose > 1)
-       log_info (_("too many entries in pk cache - disabled\n"));
-      return;
+      int n;
+
+      /* Remove the last 50% of the entries.  */
+      for (ce = pk_cache, n = 0; ce && n < pk_cache_entries/2; n++)
+        ce = ce->next;
+      if (ce != pk_cache && ce->next)
+        {
+          ce2 = ce->next;
+          ce->next = NULL;
+          ce = ce2;
+          for (; ce; ce = ce2)
+            {
+              ce2 = ce->next;
+              free_public_key (ce->pk);
+              xfree (ce);
+              pk_cache_entries--;
+            }
+        }
+      assert (pk_cache_entries < MAX_PK_CACHE_ENTRIES);
     }
   pk_cache_entries++;
   ce = xmalloc (sizeof *ce);
@@ -324,18 +344,6 @@ pk_from_block (GETKEY_CTX ctx, PKT_public_key * pk, KBNODE keyblock)
   copy_public_key (pk, a->pkt->pkt.public_key);
 }
 
-static void
-sk_from_block (GETKEY_CTX ctx, PKT_secret_key * sk, KBNODE keyblock)
-{
-  KBNODE a = ctx->found_key ? ctx->found_key : keyblock;
-
-  assert (a->pkt->pkttype == PKT_SECRET_KEY
-         || a->pkt->pkttype == PKT_SECRET_SUBKEY);
-
-  copy_secret_key (sk, a->pkt->pkt.secret_key);
-}
-
-
 /* Get a public key and store it into the allocated pk can be called
  * with PK set to NULL to just read it into some internal
  * structures.  */
@@ -377,7 +385,7 @@ get_pubkey (PKT_public_key * pk, u32 * keyid)
     memset (&ctx, 0, sizeof ctx);
     ctx.exact = 1; /* Use the key ID exactly as given.  */
     ctx.not_allocated = 1;
-    ctx.kr_handle = keydb_new (0);
+    ctx.kr_handle = keydb_new ();
     ctx.nitems = 1;
     ctx.items[0].mode = KEYDB_SEARCH_MODE_LONG_KID;
     ctx.items[0].u.kid[0] = keyid[0];
@@ -436,9 +444,9 @@ get_pubkey_fast (PKT_public_key * pk, u32 * keyid)
   }
 #endif
 
-  hd = keydb_new (0);
+  hd = keydb_new ();
   rc = keydb_search_kid (hd, keyid);
-  if (rc == -1)
+  if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
     {
       keydb_release (hd);
       return G10ERR_NO_PUBKEY;
@@ -451,8 +459,9 @@ get_pubkey_fast (PKT_public_key * pk, u32 * keyid)
       return G10ERR_NO_PUBKEY;
     }
 
-  assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY
-         || keyblock->pkt->pkttype == PKT_PUBLIC_SUBKEY);
+  assert (keyblock && keyblock->pkt
+          && (keyblock->pkt->pkttype == PKT_PUBLIC_KEY
+              || keyblock->pkt->pkttype == PKT_PUBLIC_SUBKEY));
 
   keyid_from_pk (keyblock->pkt->pkt.public_key, pkid);
   if (keyid[0] == pkid[0] && keyid[1] == pkid[1])
@@ -479,7 +488,7 @@ get_pubkeyblock (u32 * keyid)
   memset (&ctx, 0, sizeof ctx);
   /* No need to set exact here because we want the entire block.  */
   ctx.not_allocated = 1;
-  ctx.kr_handle = keydb_new (0);
+  ctx.kr_handle = keydb_new ();
   ctx.nitems = 1;
   ctx.items[0].mode = KEYDB_SEARCH_MODE_LONG_KID;
   ctx.items[0].u.kid[0] = keyid[0];
@@ -493,67 +502,43 @@ get_pubkeyblock (u32 * keyid)
 
 
 
-/****************
- * Get a secret key and store it into sk
+/*
+ * Get a public key and store it into PK.  This functions check that a
+ * corresponding secret key is available.  With no secret key it does
+ * not succeeed.
  */
-int
-get_seckey (PKT_secret_key * sk, u32 * keyid)
+gpg_error_t
+get_seckey (PKT_public_key *pk, u32 *keyid)
 {
-  int rc;
+  gpg_error_t err;
   struct getkey_ctx_s ctx;
-  KBNODE kb = NULL;
+  kbnode_t keyblock = NULL;
 
   memset (&ctx, 0, sizeof ctx);
   ctx.exact = 1; /* Use the key ID exactly as given.  */
   ctx.not_allocated = 1;
-  ctx.kr_handle = keydb_new (1);
+  ctx.kr_handle = keydb_new ();
   ctx.nitems = 1;
   ctx.items[0].mode = KEYDB_SEARCH_MODE_LONG_KID;
   ctx.items[0].u.kid[0] = keyid[0];
   ctx.items[0].u.kid[1] = keyid[1];
-  ctx.req_algo = sk->req_algo;
-  ctx.req_usage = sk->req_usage;
-  rc = lookup (&ctx, &kb, 1);
-  if (!rc)
+  ctx.req_algo = pk->req_algo;
+  ctx.req_usage = pk->req_usage;
+  err = lookup (&ctx, &keyblock, 1);
+  if (!err)
     {
-      sk_from_block (&ctx, sk, kb);
+      pk_from_block (&ctx, pk, keyblock);
     }
-  get_seckey_end (&ctx);
-  release_kbnode (kb);
+  get_pubkey_end (&ctx);
+  release_kbnode (keyblock);
 
-  if (!rc)
-    {
-      /* Check the secret key (this may prompt for a passprase to
-       * unlock the secret key.  */
-      rc = check_secret_key (sk, 0);
-    }
+  if (!err)
+    err = agent_probe_secret_key (/*ctrl*/NULL, pk);
 
-  return rc;
+  return err;
 }
 
 
-/* Check whether the secret key is available.  This is just a fast
- * check and does not tell us whether the secret key is valid.  It
- * merely tells other whether there is some secret key.
- * Returns:
- *    0                := key is available
- *    G10ERR_NO_SECKEY := key not availabe
- */
-int
-seckey_available (u32 * keyid)
-{
-  int rc;
-  KEYDB_HANDLE hd = keydb_new (1);
-
-  rc = keydb_search_kid (hd, keyid);
-  if (rc == -1)
-    rc = G10ERR_NO_SECKEY;
-  keydb_release (hd);
-  return rc;
-}
-
-
-
 static int
 skip_unusable (void *dummy, u32 * keyid, PKT_user_id * uid)
 {
@@ -598,17 +583,17 @@ leave:
 }
 
 
-/* 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/sk has the pubkey algo set, the function will only return a
- * pubkey with that algo.  If namelist is NULL, the first key is
- * returned.  The caller should provide storage for either the pk or
- * the sk.  If ret_kb is not NULL the function will return the
- * keyblock there.  */
+/* 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 a pubkey
+ * with that algo.  If NAMELIST is NULL, the first key is returned.
+ * The caller should provide storage for the PK or pass NULL if it is
+ * not needed.  If RET_KB is not NULL the function stores the entire
+ * keyblock at that address.  */
 static int
-key_byname (GETKEY_CTX * retctx, strlist_t namelist,
-           PKT_public_key * pk, PKT_secret_key * sk,
-           int secmode, int include_unusable,
+key_byname (GETKEY_CTX *retctx, strlist_t namelist,
+           PKT_public_key *pk,
+           int want_secret, int include_unusable,
            KBNODE * ret_kb, KEYDB_HANDLE * ret_kdbhd)
 {
   int rc = 0;
@@ -648,7 +633,7 @@ key_byname (GETKEY_CTX * retctx, strlist_t namelist,
        {
          gpg_error_t err;
 
-         err = classify_user_id (r->d, &ctx->items[n]);
+         err = classify_user_id (r->d, &ctx->items[n], 1);
 
          if (ctx->items[n].exact)
            ctx->exact = 1;
@@ -667,35 +652,21 @@ key_byname (GETKEY_CTX * retctx, strlist_t namelist,
        }
     }
 
-  ctx->kr_handle = keydb_new (secmode);
+  ctx->want_secret = want_secret;
+  ctx->kr_handle = keydb_new ();
   if (!ret_kb)
     ret_kb = &help_kb;
 
-  if (secmode)
+  if (pk)
     {
-      if (sk)
-       {
-         ctx->req_algo = sk->req_algo;
-         ctx->req_usage = sk->req_usage;
-       }
-      rc = lookup (ctx, ret_kb, 1);
-      if (!rc && sk)
-       {
-         sk_from_block (ctx, sk, *ret_kb);
-       }
+      ctx->req_algo = pk->req_algo;
+      ctx->req_usage = pk->req_usage;
     }
-  else
+
+  rc = lookup (ctx, ret_kb, want_secret);
+  if (!rc && pk)
     {
-      if (pk)
-       {
-         ctx->req_algo = pk->req_algo;
-         ctx->req_usage = pk->req_usage;
-       }
-      rc = lookup (ctx, ret_kb, 0);
-      if (!rc && pk)
-       {
-         pk_from_block (ctx, pk, *ret_kb);
-       }
+      pk_from_block (ctx, pk, *ret_kb);
     }
 
   release_kbnode (help_kb);
@@ -725,7 +696,7 @@ key_byname (GETKEY_CTX * retctx, strlist_t namelist,
    to import the key via the online mechanisms defined by
    --auto-key-locate.  */
 int
-get_pubkey_byname (GETKEY_CTX * retctx, PKT_public_key * pk,
+get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
                   const char *name, KBNODE * ret_keyblock,
                   KEYDB_HANDLE * ret_kdbhd, int include_unusable, int no_akl)
 {
@@ -741,7 +712,7 @@ get_pubkey_byname (GETKEY_CTX * retctx, PKT_public_key * pk,
 
   is_mbox = is_valid_mailbox (name);
 
-  /* Check whether we the default local search has been disabled.
+  /* Check whether the default local search has been disabled.
      This is the case if either the "nodefault" or the "local" keyword
      are in the list of auto key locate mechanisms.
 
@@ -778,7 +749,7 @@ get_pubkey_byname (GETKEY_CTX * retctx, PKT_public_key * pk,
   else
     {
       add_to_strlist (&namelist, name);
-      rc = key_byname (retctx, namelist, pk, NULL, 0,
+      rc = key_byname (retctx, namelist, pk, 0,
                       include_unusable, ret_keyblock, ret_kdbhd);
     }
 
@@ -812,28 +783,28 @@ get_pubkey_byname (GETKEY_CTX * retctx, PKT_public_key * pk,
                }
              add_to_strlist (&namelist, name);
              rc = key_byname (anylocalfirst ? retctx : NULL,
-                              namelist, pk, NULL, 0,
+                              namelist, pk, 0,
                               include_unusable, ret_keyblock, ret_kdbhd);
              break;
 
            case AKL_CERT:
              mechanism = "DNS CERT";
              glo_ctrl.in_auto_key_retrieve++;
-             rc = keyserver_import_cert (name, &fpr, &fpr_len);
+             rc = keyserver_import_cert (ctrl, name, &fpr, &fpr_len);
              glo_ctrl.in_auto_key_retrieve--;
              break;
 
            case AKL_PKA:
              mechanism = "PKA";
              glo_ctrl.in_auto_key_retrieve++;
-             rc = keyserver_import_pka (name, &fpr, &fpr_len);
+             rc = keyserver_import_pka (ctrl, name, &fpr, &fpr_len);
              glo_ctrl.in_auto_key_retrieve--;
              break;
 
            case AKL_LDAP:
              mechanism = "LDAP";
              glo_ctrl.in_auto_key_retrieve++;
-             rc = keyserver_import_ldap (name, &fpr, &fpr_len);
+             rc = keyserver_import_ldap (ctrl, name, &fpr, &fpr_len);
              glo_ctrl.in_auto_key_retrieve--;
              break;
 
@@ -846,9 +817,8 @@ get_pubkey_byname (GETKEY_CTX * retctx, PKT_public_key * pk,
                {
                  mechanism = opt.keyserver->uri;
                  glo_ctrl.in_auto_key_retrieve++;
-                 rc =
-                   keyserver_import_name (name, &fpr, &fpr_len,
-                                          opt.keyserver);
+                 rc = keyserver_import_name (ctrl, name, &fpr, &fpr_len,
+                                              opt.keyserver);
                  glo_ctrl.in_auto_key_retrieve--;
                }
              else
@@ -865,7 +835,8 @@ get_pubkey_byname (GETKEY_CTX * retctx, PKT_public_key * pk,
                mechanism = akl->spec->uri;
                keyserver = keyserver_match (akl->spec);
                glo_ctrl.in_auto_key_retrieve++;
-               rc = keyserver_import_name (name, &fpr, &fpr_len, keyserver);
+               rc = keyserver_import_name (ctrl,
+                                            name, &fpr, &fpr_len, keyserver);
                glo_ctrl.in_auto_key_retrieve--;
              }
              break;
@@ -911,18 +882,18 @@ get_pubkey_byname (GETKEY_CTX * retctx, PKT_public_key * pk,
                  *retctx = NULL;
                }
              rc = key_byname (anylocalfirst ? retctx : NULL,
-                              namelist, pk, NULL, 0,
+                              namelist, pk, 0,
                               include_unusable, ret_keyblock, ret_kdbhd);
            }
          if (!rc)
            {
              /* Key found.  */
-             log_info (_("automatically retrieved `%s' via %s\n"),
+             log_info (_("automatically retrieved '%s' via %s\n"),
                        name, mechanism);
              break;
            }
          if (rc != G10ERR_NO_PUBKEY || opt.verbose || no_fingerprint)
-           log_info (_("error retrieving `%s' via %s: %s\n"),
+           log_info (_("error retrieving '%s' via %s: %s\n"),
                      name, mechanism,
                      no_fingerprint ? _("No fingerprint") : g10_errstr (rc));
        }
@@ -950,7 +921,7 @@ int
 get_pubkey_bynames (GETKEY_CTX * retctx, PKT_public_key * pk,
                    strlist_t names, KBNODE * ret_keyblock)
 {
-  return key_byname (retctx, names, pk, NULL, 0, 1, ret_keyblock, NULL);
+  return key_byname (retctx, names, pk, 0, 1, ret_keyblock, NULL);
 }
 
 int
@@ -998,7 +969,7 @@ get_pubkey_byfprint (PKT_public_key * pk,
       memset (&ctx, 0, sizeof ctx);
       ctx.exact = 1;
       ctx.not_allocated = 1;
-      ctx.kr_handle = keydb_new (0);
+      ctx.kr_handle = keydb_new ();
       ctx.nitems = 1;
       ctx.items[0].mode = fprint_len == 16 ? KEYDB_SEARCH_MODE_FPR16
        : KEYDB_SEARCH_MODE_FPR20;
@@ -1035,9 +1006,9 @@ get_pubkey_byfprint_fast (PKT_public_key * pk,
   while (i < MAX_FINGERPRINT_LEN)
     fprbuf[i++] = 0;
 
-  hd = keydb_new (0);
+  hd = keydb_new ();
   rc = keydb_search_fpr (hd, fprbuf);
-  if (rc == -1)
+  if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
     {
       keydb_release (hd);
       return G10ERR_NO_PUBKEY;
@@ -1077,7 +1048,7 @@ get_keyblock_byfprint (KBNODE * ret_keyblock, const byte * fprint,
 
       memset (&ctx, 0, sizeof ctx);
       ctx.not_allocated = 1;
-      ctx.kr_handle = keydb_new (0);
+      ctx.kr_handle = keydb_new ();
       ctx.nitems = 1;
       ctx.items[0].mode = (fprint_len == 16
                            ? KEYDB_SEARCH_MODE_FPR16
@@ -1093,15 +1064,15 @@ get_keyblock_byfprint (KBNODE * ret_keyblock, const byte * fprint,
 }
 
 
-/* Get a secret key by name and store it into sk.
- * If NAME is NULL use the default key.   */
-static int
-get_seckey_byname2 (GETKEY_CTX * retctx,
-                   PKT_secret_key * sk, const char *name, int unprotect,
-                   KBNODE * retblock)
+/* Get a secret key by NAME and store it into PK.  If NAME is NULL use
+ * the default key.  This functions checks that a corresponding secret
+ * key is available.  With no secret key it does not succeeed. */
+gpg_error_t
+get_seckey_byname (PKT_public_key *pk, const char *name)
 {
+  gpg_error_t err;
   strlist_t namelist = NULL;
-  int rc, include_unusable = 1;
+  int include_unusable = 1;
 
   /* If we have no name, try to use the default secret key.  If we
      have no default, we'll use the first usable one. */
@@ -1113,221 +1084,204 @@ get_seckey_byname2 (GETKEY_CTX * retctx,
   else
     include_unusable = 0;
 
-  rc = key_byname (retctx, namelist, NULL, sk, 1, include_unusable,
-                  retblock, NULL);
+  err = key_byname (NULL, namelist, pk, 1, include_unusable, NULL, NULL);
 
   free_strlist (namelist);
 
-  if (!rc && unprotect)
-    rc = check_secret_key (sk, 0);
-
-  return rc;
-}
-
-int
-get_seckey_byname (PKT_secret_key * sk, const char *name, int unlock)
-{
-  return get_seckey_byname2 (NULL, sk, name, unlock, NULL);
+  return err;
 }
 
 
-int
-get_seckey_bynames (GETKEY_CTX * retctx, PKT_secret_key * sk,
-                   strlist_t names, KBNODE * ret_keyblock)
-{
-  return key_byname (retctx, names, NULL, sk, 1, 1, ret_keyblock, NULL);
-}
-
-
-int
-get_seckey_next (GETKEY_CTX ctx, PKT_secret_key * sk, KBNODE * ret_keyblock)
-{
-  int rc;
-
-  rc = lookup (ctx, ret_keyblock, 1);
-  if (!rc && sk && ret_keyblock)
-    sk_from_block (ctx, sk, *ret_keyblock);
-
-  return rc;
-}
-
-
-void
-get_seckey_end (GETKEY_CTX ctx)
-{
-  get_pubkey_end (ctx);
-}
-
 
 /* Search for a key with the given fingerprint.
  * FIXME:
- * We should replace this with the _byname function.  Thiscsan be done
+ * We should replace this with the _byname function.  This can be done
  * by creating a userID conforming to the unified fingerprint style.   */
-int
-get_seckey_byfprint (PKT_secret_key * sk,
-                    const byte * fprint, size_t fprint_len)
+gpg_error_t
+get_seckey_byfprint (PKT_public_key *pk, const byte * fprint, size_t fprint_len)
 {
-  int rc;
+  gpg_error_t err;
 
   if (fprint_len == 20 || fprint_len == 16)
     {
       struct getkey_ctx_s ctx;
-      KBNODE kb = NULL;
+      kbnode_t kb = NULL;
 
       memset (&ctx, 0, sizeof ctx);
       ctx.exact = 1;
       ctx.not_allocated = 1;
-      ctx.kr_handle = keydb_new (1);
+      ctx.kr_handle = keydb_new ();
       ctx.nitems = 1;
       ctx.items[0].mode = fprint_len == 16 ? KEYDB_SEARCH_MODE_FPR16
        : KEYDB_SEARCH_MODE_FPR20;
       memcpy (ctx.items[0].u.fpr, fprint, fprint_len);
-      rc = lookup (&ctx, &kb, 1);
-      if (!rc && sk)
-       sk_from_block (&ctx, sk, kb);
+      err = lookup (&ctx, &kb, 1);
+      if (!err && pk)
+       pk_from_block (&ctx, pk, kb);
       release_kbnode (kb);
-      get_seckey_end (&ctx);
+      get_pubkey_end (&ctx);
     }
   else
-    rc = G10ERR_GENERAL;       /* Oops */
-  return rc;
+    err = gpg_error (GPG_ERR_BUG);
+  return err;
 }
 
 
 /* Search for a secret key with the given fingerprint and return the
-   complete keyblock which may have more than only this key. */
-int
-get_seckeyblock_byfprint (KBNODE * ret_keyblock, const byte * fprint,
-                         size_t fprint_len)
+   complete keyblock which may have more than only this key.  Return
+   an error if no corresponding secret key is available.  */
+gpg_error_t
+get_seckeyblock_byfprint (kbnode_t *ret_keyblock,
+                          const byte *fprint, size_t fprint_len)
 {
-  int rc;
+  gpg_error_t err;
   struct getkey_ctx_s ctx;
 
   if (fprint_len != 20 && fprint_len == 16)
-    return G10ERR_GENERAL;     /* Oops */
+    return gpg_error (GPG_ERR_BUG);
 
   memset (&ctx, 0, sizeof ctx);
   ctx.not_allocated = 1;
-  ctx.kr_handle = keydb_new (1);
+  ctx.kr_handle = keydb_new ();
   ctx.nitems = 1;
   ctx.items[0].mode = (fprint_len == 16
                       ? KEYDB_SEARCH_MODE_FPR16 : KEYDB_SEARCH_MODE_FPR20);
   memcpy (ctx.items[0].u.fpr, fprint, fprint_len);
-  rc = lookup (&ctx, ret_keyblock, 1);
-  get_seckey_end (&ctx);
+  err = lookup (&ctx, ret_keyblock, 1);
+  get_pubkey_end (&ctx);
+
+  return err;
+}
+
+
+\f
+/* The new function to return a key.
+   FIXME: Document it.  */
+gpg_error_t
+getkey_bynames (getkey_ctx_t *retctx, PKT_public_key *pk,
+                strlist_t names, int want_secret, kbnode_t *ret_keyblock)
+{
+  return key_byname (retctx, names, pk, want_secret, 1,
+                     ret_keyblock, NULL);
+}
+
+
+/* Get a key by name and store it into PK if that is not NULL.  If
+ * RETCTX is not NULL return the search context which needs to be
+ * released by the caller using getkey_end.  If NAME is NULL use the
+ * default key (see below).  On success and if RET_KEYBLOCK is not
+ * NULL the found keyblock is stored at this address.  WANT_SECRET
+ * passed as true requires that a secret key is available for the
+ * selected key.
+ *
+ * If WANT_SECRET is true and NAME is NULL and a default key has been
+ * defined that defined key is used.  In all other cases the first
+ * available key is used.
+ *
+ * FIXME: Explain what is up with unusable keys.
+ *
+ * FIXME: We also have the get_pubkey_byname function which has a
+ * different semantic.  Should be merged with this one.
+ */
+gpg_error_t
+getkey_byname (getkey_ctx_t *retctx, PKT_public_key *pk,
+               const char *name, int want_secret, kbnode_t *ret_keyblock)
+{
+  gpg_error_t err;
+  strlist_t namelist = NULL;
+  int with_unusable = 1;
+
+  if (want_secret && !name && opt.def_secret_key && *opt.def_secret_key)
+    add_to_strlist (&namelist, opt.def_secret_key);
+  else if (name)
+    add_to_strlist (&namelist, name);
+  else
+    with_unusable = 0;
+
+  err = key_byname (retctx, namelist, pk, want_secret, with_unusable,
+                    ret_keyblock, NULL);
+
+  /* FIXME: Check that we really return GPG_ERR_NO_SECKEY if
+     WANT_SECRET has been used.  */
+
+  free_strlist (namelist);
+
+  return err;
+}
+
+
+/* The new function to return the next key.  */
+gpg_error_t
+getkey_next (getkey_ctx_t ctx, PKT_public_key *pk, kbnode_t *ret_keyblock)
+{
+  int rc; /* Fixme:  Make sure this is proper gpg_error */
+
+  rc = lookup (ctx, ret_keyblock, ctx->want_secret);
+  if (!rc && pk && ret_keyblock)
+    pk_from_block (ctx, pk, *ret_keyblock);
 
   return rc;
 }
 
+
+/* The new function to finish a key listing.  */
+void
+getkey_end (getkey_ctx_t ctx)
+{
+  get_pubkey_end (ctx);
+}
+
+
 \f
 /************************************************
  ************* Merging stuff ********************
  ************************************************/
 
-/* Merge all self-signatures with the keys.
-
- * FIXME: replace this at least for the public key parts
- *        by merge_selfsigs.
- *        It is still used in keyedit.c and
- *        at 2 or 3 other places - check whether it is really needed.
- *        It might be needed by the key edit and import stuff because
- *        the keylock is changed.  */
+/* Set the mainkey_id fields for all keys in KEYBLOCK.  This is
+   usually done by merge_selfsigs but at some places we only need the
+   main_kid but the the full merging.  The function also guarantees
+   that all pk->keyids are computed. */
 void
-merge_keys_and_selfsig (KBNODE keyblock)
+setup_main_keyids (kbnode_t keyblock)
 {
-  PKT_public_key *pk = NULL;
-  PKT_secret_key *sk = NULL;
-  PKT_signature *sig;
-  KBNODE k;
-  u32 kid[2] = { 0, 0 };
-  u32 sigdate = 0;
-
-  if (keyblock && keyblock->pkt->pkttype == PKT_PUBLIC_KEY)
-    {
-      /* Divert to our new function.  */
-      merge_selfsigs (keyblock);
-      return;
-    }
+  u32 kid[2], mainkid[2];
+  kbnode_t kbctx, node;
+  PKT_public_key *pk;
 
-  /* Still need the old one because the new one can't handle secret keys.  */
+  if (keyblock->pkt->pkttype != PKT_PUBLIC_KEY)
+    BUG ();
+  pk = keyblock->pkt->pkt.public_key;
 
-  for (k = keyblock; k; k = k->next)
+  keyid_from_pk (pk, mainkid);
+  for (kbctx=NULL; (node = walk_kbnode (keyblock, &kbctx, 0)); )
     {
-      if (k->pkt->pkttype == PKT_PUBLIC_KEY
-         || k->pkt->pkttype == PKT_PUBLIC_SUBKEY)
-       {
-         pk = k->pkt->pkt.public_key;
-         sk = NULL;
-         if (pk->version < 4)
-           pk = NULL; /* Not needed for old keys.  */
-         else if (k->pkt->pkttype == PKT_PUBLIC_KEY)
-           keyid_from_pk (pk, kid);
-         else if (!pk->expiredate)
-           {
-              /* and subkey */
-             /* insert the expiration date here */
-             /*FIXME!!! pk->expiredate = subkeys_expiretime( k, kid ); */
-           }
-         sigdate = 0;
-       }
-      else if (k->pkt->pkttype == PKT_SECRET_KEY
-              || k->pkt->pkttype == PKT_SECRET_SUBKEY)
-       {
-         pk = NULL;
-         sk = k->pkt->pkt.secret_key;
-         if (sk->version < 4)
-           sk = NULL;
-         else if (k->pkt->pkttype == PKT_SECRET_KEY)
-           keyid_from_sk (sk, kid);
-         sigdate = 0;
-       }
-      else if ((pk || sk) && k->pkt->pkttype == PKT_SIGNATURE
-              && (sig = k->pkt->pkt.signature)->sig_class >= 0x10
-              && sig->sig_class <= 0x30 && sig->version > 3
-              && !(sig->sig_class == 0x18 || sig->sig_class == 0x28)
-              && sig->keyid[0] == kid[0] && sig->keyid[1] == kid[1])
-       {
-         /* okay this is a self-signature which can be used.
-          * This is not used for subkey binding signature, becuase this
-          * is done above.
-          * FIXME: We should only use this if the signature is valid
-          *        but this is time consuming - we must provide another
-          *        way to handle this
-          */
-         const byte *p;
-         u32 ed;
-
-         p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL);
-         if (pk)
-           {
-             ed = p ? pk->timestamp + buffer_to_u32 (p) : 0;
-             if (sig->timestamp > sigdate)
-               {
-                 pk->expiredate = ed;
-                 sigdate = sig->timestamp;
-               }
-           }
-         else
-           {
-             ed = p ? sk->timestamp + buffer_to_u32 (p) : 0;
-             if (sig->timestamp > sigdate)
-               {
-                 sk->expiredate = ed;
-                 sigdate = sig->timestamp;
-               }
-           }
-       }
+      if (!(node->pkt->pkttype == PKT_PUBLIC_KEY
+            || node->pkt->pkttype == PKT_PUBLIC_SUBKEY))
+        continue;
+      pk = node->pkt->pkt.public_key;
+      keyid_from_pk (pk, kid); /* Make sure pk->keyid is set.  */
+      if (!pk->main_keyid[0] && !pk->main_keyid[1])
+        {
+          pk->main_keyid[0] = mainkid[0];
+          pk->main_keyid[1] = mainkid[1];
+        }
+    }
+}
 
-      if (pk && (pk->expiredate == 0 ||
-                (pk->max_expiredate && pk->expiredate > pk->max_expiredate)))
-       pk->expiredate = pk->max_expiredate;
 
-      if (sk && (sk->expiredate == 0 ||
-                (sk->max_expiredate && sk->expiredate > sk->max_expiredate)))
-       sk->expiredate = sk->max_expiredate;
-    }
+/* Merge all self-signatures with the keys.  */
+void
+merge_keys_and_selfsig (KBNODE keyblock)
+{
+  if (!keyblock)
+    ;
+  else if (keyblock->pkt->pkttype == PKT_PUBLIC_KEY)
+    merge_selfsigs (keyblock);
+  else
+    log_debug ("FIXME: merging secret key blocks is not anymore available\n");
 }
 
+
 static int
 parse_key_usage (PKT_signature * sig)
 {
@@ -1370,13 +1324,19 @@ parse_key_usage (PKT_signature * sig)
 
       if (flags)
        key_usage |= PUBKEY_USAGE_UNKNOWN;
+
+      if (!key_usage)
+       key_usage |= PUBKEY_USAGE_NONE;
     }
+  else if (p) /* Key flags of length zero.  */
+    key_usage |= PUBKEY_USAGE_NONE;
 
   /* We set PUBKEY_USAGE_UNKNOWN to indicate that this key has a
      capability that we do not handle.  This serves to distinguish
      between a zero key usage which we handle as the default
      capabilities for that algorithm, and a usage that we do not
-     handle. */
+     handle.  Likewise we use PUBKEY_USAGE_NONE to indicate that
+     key_flags have been given but they do not specify any usage.  */
 
   return key_usage;
 }
@@ -1508,6 +1468,8 @@ sig_to_revoke_info (PKT_signature * sig, struct revoke_info *rinfo)
   rinfo->keyid[1] = sig->keyid[1];
 }
 
+
+/* Note that R_REVOKED may be set to 0, 1 or 2.  */
 static void
 merge_selfsigs_main (KBNODE keyblock, int *r_revoked,
                     struct revoke_info *rinfo)
@@ -1668,7 +1630,7 @@ merge_selfsigs_main (KBNODE keyblock, int *r_revoked,
 
       /* Mark that key as valid: One direct key signature should
        * render a key as valid.  */
-      pk->is_valid = 1;
+      pk->flags.valid = 1;
     }
 
   /* Pass 1.5: Look for key revocation signatures that were not made
@@ -1696,7 +1658,7 @@ merge_selfsigs_main (KBNODE keyblock, int *r_revoked,
                    break;
                  }
                else if (rc == G10ERR_NO_PUBKEY)
-                 pk->maybe_revoked = 1;
+                 pk->flags.maybe_revoked = 1;
 
                /* A failure here means the sig did not verify, was
                   not issued by a revocation key, or a revocation
@@ -1720,7 +1682,7 @@ merge_selfsigs_main (KBNODE keyblock, int *r_revoked,
          if (uidnode && signode)
            {
              fixup_uidnode (uidnode, signode, keytimestamp);
-             pk->is_valid = 1;
+             pk->flags.valid = 1;
            }
          uidnode = k;
          signode = NULL;
@@ -1756,22 +1718,22 @@ merge_selfsigs_main (KBNODE keyblock, int *r_revoked,
   if (uidnode && signode)
     {
       fixup_uidnode (uidnode, signode, keytimestamp);
-      pk->is_valid = 1;
+      pk->flags.valid = 1;
     }
 
   /* If the key isn't valid yet, and we have
      --allow-non-selfsigned-uid set, then force it valid. */
-  if (!pk->is_valid && opt.allow_non_selfsigned_uid)
+  if (!pk->flags.valid && opt.allow_non_selfsigned_uid)
     {
       if (opt.verbose)
        log_info (_("Invalid key %s made valid by"
                    " --allow-non-selfsigned-uid\n"), keystr_from_pk (pk));
-      pk->is_valid = 1;
+      pk->flags.valid = 1;
     }
 
   /* The key STILL isn't valid, so try and find an ultimately
      trusted signature. */
-  if (!pk->is_valid)
+  if (!pk->flags.valid)
     {
       uidnode = NULL;
 
@@ -1802,7 +1764,7 @@ merge_selfsigs_main (KBNODE keyblock, int *r_revoked,
                      && get_ownertrust (ultimate_pk) == TRUST_ULTIMATE)
                    {
                      free_public_key (ultimate_pk);
-                     pk->is_valid = 1;
+                     pk->flags.valid = 1;
                      break;
                    }
 
@@ -2039,7 +2001,7 @@ merge_selfsigs_subkey (KBNODE keyblock, KBNODE subnode)
   subpk = subnode->pkt->pkt.public_key;
   keytimestamp = subpk->timestamp;
 
-  subpk->is_valid = 0;
+  subpk->flags.valid = 0;
   subpk->main_keyid[0] = mainpk->main_keyid[0];
   subpk->main_keyid[1] = mainpk->main_keyid[1];
 
@@ -2066,7 +2028,7 @@ merge_selfsigs_subkey (KBNODE keyblock, KBNODE subnode)
                     subkeys rather than re-sign old ones as the
                     problem is in the distribution.  Plus, PGP (7)
                     does this the same way.  */
-                 subpk->is_revoked = 1;
+                 subpk->flags.revoked = 1;
                  sig_to_revoke_info (sig, &subpk->revoked);
                  /* Although we could stop now, we continue to
                   * figure out other information like the old expiration
@@ -2122,10 +2084,10 @@ merge_selfsigs_subkey (KBNODE keyblock, KBNODE subnode)
   if (openpgp_pk_test_algo (subpk->pubkey_algo))
     return;
 
-  subpk->is_valid = 1;
+  subpk->flags.valid = 1;
 
   /* Find the most recent 0x19 embedded signature on our self-sig. */
-  if (subpk->backsig == 0)
+  if (!subpk->flags.backsig)
     {
       int seq = 0;
       size_t n;
@@ -2190,9 +2152,9 @@ merge_selfsigs_subkey (KBNODE keyblock, KBNODE subnode)
 
          /* 2==valid, 1==invalid, 0==didn't check */
          if (check_backsig (mainpk, subpk, backsig) == 0)
-           subpk->backsig = 2;
+           subpk->flags.backsig = 2;
          else
-           subpk->backsig = 1;
+           subpk->flags.backsig = 1;
 
          free_seckey_enc (backsig);
        }
@@ -2220,7 +2182,7 @@ merge_selfsigs (KBNODE keyblock)
   struct revoke_info rinfo;
   PKT_public_key *main_pk;
   prefitem_t *prefs;
-  int mdc_feature;
+  unsigned int mdc_feature;
 
   if (keyblock->pkt->pkttype != PKT_PUBLIC_KEY)
     {
@@ -2248,7 +2210,7 @@ merge_selfsigs (KBNODE keyblock)
     }
 
   main_pk = keyblock->pkt->pkt.public_key;
-  if (revoked || main_pk->has_expired || !main_pk->is_valid)
+  if (revoked || main_pk->has_expired || !main_pk->flags.valid)
     {
       /* If the primary key is revoked, expired, or invalid we
        * better set the appropriate flags on that key and all
@@ -2259,11 +2221,11 @@ merge_selfsigs (KBNODE keyblock)
              || k->pkt->pkttype == PKT_PUBLIC_SUBKEY)
            {
              PKT_public_key *pk = k->pkt->pkt.public_key;
-             if (!main_pk->is_valid)
-               pk->is_valid = 0;
-             if (revoked && !pk->is_revoked)
+             if (!main_pk->flags.valid)
+               pk->flags.valid = 0;
+             if (revoked && !pk->flags.revoked)
                {
-                 pk->is_revoked = revoked;
+                 pk->flags.revoked = revoked;
                  memcpy (&pk->revoked, &rinfo, sizeof (rinfo));
                }
              if (main_pk->has_expired)
@@ -2303,152 +2265,16 @@ merge_selfsigs (KBNODE keyblock)
          if (pk->prefs)
            xfree (pk->prefs);
          pk->prefs = copy_prefs (prefs);
-         pk->mdc_feature = mdc_feature;
-       }
-    }
-}
-
-
-/*
- * Merge the secret keys from secblock into the pubblock thereby
- * replacing the public (sub)keys with their secret counterparts Hmmm:
- * It might be better to get away from the concept of entire secret
- * keys at all and have a way to store just the real secret parts
- * from the key.
- */
-static void
-merge_public_with_secret (KBNODE pubblock, KBNODE secblock)
-{
-  KBNODE pub;
-
-  assert (pubblock->pkt->pkttype == PKT_PUBLIC_KEY);
-  assert (secblock->pkt->pkttype == PKT_SECRET_KEY);
-
-  for (pub = pubblock; pub; pub = pub->next)
-    {
-      if (pub->pkt->pkttype == PKT_PUBLIC_KEY)
-       {
-         PKT_public_key *pk = pub->pkt->pkt.public_key;
-         PKT_secret_key *sk = secblock->pkt->pkt.secret_key;
-         assert (pub == pubblock); /* Only in the first node.  */
-         /* There is nothing to compare in this case, so just replace
-          * some information.  */
-         copy_public_parts_to_secret_key (pk, sk);
-         free_public_key (pk);
-         pub->pkt->pkttype = PKT_SECRET_KEY;
-         pub->pkt->pkt.secret_key = copy_secret_key (NULL, sk);
-       }
-      else if (pub->pkt->pkttype == PKT_PUBLIC_SUBKEY)
-       {
-         KBNODE sec;
-         PKT_public_key *pk = pub->pkt->pkt.public_key;
-
-         /* This is more complicated: It may happen that the sequence
-          * of the subkeys dosn't match, so we have to find the
-          * appropriate secret key.  */
-         for (sec = secblock->next; sec; sec = sec->next)
-           {
-             if (sec->pkt->pkttype == PKT_SECRET_SUBKEY)
-               {
-                 PKT_secret_key *sk = sec->pkt->pkt.secret_key;
-                 if (!cmp_public_secret_key (pk, sk))
-                   {
-                     copy_public_parts_to_secret_key (pk, sk);
-                     free_public_key (pk);
-                     pub->pkt->pkttype = PKT_SECRET_SUBKEY;
-                     pub->pkt->pkt.secret_key = copy_secret_key (NULL, sk);
-                     break;
-                   }
-               }
-           }
-         if (!sec)
-           BUG (); /* Already checked in premerge.  */
-       }
-    }
-}
-
-
-/* This function checks that for every public subkey a corresponding
- * secret subkey is available and deletes the public subkey otherwise.
- * We need this function because we can't delete it later when we
- * actually merge the secret parts into the pubring.
- * The function also plays some games with the node flags.  */
-static void
-premerge_public_with_secret (KBNODE pubblock, KBNODE secblock)
-{
-  KBNODE last, pub;
-
-  assert (pubblock->pkt->pkttype == PKT_PUBLIC_KEY);
-  assert (secblock->pkt->pkttype == PKT_SECRET_KEY);
-
-  for (pub = pubblock, last = NULL; pub; last = pub, pub = pub->next)
-    {
-      pub->flag &= ~3; /* Reset bits 0 and 1.  */
-      if (pub->pkt->pkttype == PKT_PUBLIC_SUBKEY)
-       {
-         KBNODE sec;
-         PKT_public_key *pk = pub->pkt->pkt.public_key;
-
-         for (sec = secblock->next; sec; sec = sec->next)
-           {
-             if (sec->pkt->pkttype == PKT_SECRET_SUBKEY)
-               {
-                 PKT_secret_key *sk = sec->pkt->pkt.secret_key;
-                 if (!cmp_public_secret_key (pk, sk))
-                   {
-                     if (sk->protect.s2k.mode == 1001)
-                       {
-                         /* The secret parts are not available so
-                            we can't use that key for signing etc.
-                            Fix the pubkey usage */
-                         pk->pubkey_usage &= ~(PUBKEY_USAGE_SIG
-                                               | PUBKEY_USAGE_AUTH);
-                       }
-                     /* Transfer flag bits 0 and 1 to the pubblock.  */
-                     pub->flag |= (sec->flag & 3);
-                     break;
-                   }
-               }
-           }
-         if (!sec)
-           {
-             KBNODE next, ll;
-
-             if (opt.verbose)
-               log_info (_("no secret subkey"
-                           " for public subkey %s - ignoring\n"),
-                         keystr_from_pk (pk));
-             /* We have to remove the subkey in this case.  */
-             assert (last);
-             /* Find the next subkey.  */
-             for (next = pub->next, ll = pub;
-                  next && next->pkt->pkttype != PKT_PUBLIC_SUBKEY;
-                  ll = next, next = next->next)
-               ;
-             /* Make new link.  */
-             last->next = next;
-             /* Release this public subkey with all sigs.  */
-             ll->next = NULL;
-             release_kbnode (pub);
-             /* Let the loop continue.  */
-             pub = last;
-           }
+         pk->flags.mdc = mdc_feature;
        }
     }
-  /* We need to copy the found bits (0 and 1) from the secret key to
-     the public key.  This has already been done for the subkeys but
-     got lost on the primary key - fix it here.  */
-  pubblock->flag |= (secblock->flag & 3);
 }
 
 
 \f
-/* See see whether the key fits our requirements and in case we do not
- * request the primary key, we should select a suitable subkey.
+/* See whether the key fits our requirements and in case we do not
+ * request the primary key, select a suitable subkey.
  *
- * FIXME: Check against PGP 7 whether we still need a kludge
- *        to favor type 16 keys over type 20 keys when type 20
- *        has not been explitely requested.
  * Returns: True when a suitable key has been found.
  *
  * We have to distinguish four cases:  FIXME!
@@ -2533,7 +2359,7 @@ finish_lookup (GETKEY_CTX ctx)
   if ((!foundk || foundk->pkt->pkttype == PKT_PUBLIC_SUBKEY) && !req_prim)
     {
       KBNODE nextk;
-      /* ceither start a loop or check just this one subkey.  */
+      /* Either start a loop or check just this one subkey.  */
       for (k = foundk ? foundk : keyblock; k; k = nextk)
        {
          PKT_public_key *pk;
@@ -2546,13 +2372,13 @@ finish_lookup (GETKEY_CTX ctx)
          if (DBG_CACHE)
            log_debug ("\tchecking subkey %08lX\n",
                       (ulong) keyid_from_pk (pk, NULL));
-         if (!pk->is_valid)
+         if (!pk->flags.valid)
            {
              if (DBG_CACHE)
                log_debug ("\tsubkey not valid\n");
              continue;
            }
-         if (pk->is_revoked)
+         if (pk->flags.revoked)
            {
              if (DBG_CACHE)
                log_debug ("\tsubkey has been revoked\n");
@@ -2601,12 +2427,12 @@ finish_lookup (GETKEY_CTX ctx)
       if (DBG_CACHE && !foundk && !req_prim)
        log_debug ("\tno suitable subkeys found - trying primary\n");
       pk = keyblock->pkt->pkt.public_key;
-      if (!pk->is_valid)
+      if (!pk->flags.valid)
        {
          if (DBG_CACHE)
            log_debug ("\tprimary key not valid\n");
        }
-      else if (pk->is_revoked)
+      else if (pk->flags.revoked)
        {
          if (DBG_CACHE)
            log_debug ("\tprimary key has been revoked\n");
@@ -2635,7 +2461,7 @@ finish_lookup (GETKEY_CTX ctx)
     {
       if (DBG_CACHE)
        log_debug ("\tno suitable key found -  giving up\n");
-      return 0;
+      return 0; /* Not found.  */
     }
 
 found:
@@ -2668,15 +2494,17 @@ found:
 }
 
 
+/* The main function to lookup a key.  On success the found keyblock
+   is stored at RET_KEYBLOCK and also in CTX.  If WANT_SECRET is true
+   a corresponding secret key is required.  */
 static int
-lookup (GETKEY_CTX ctx, KBNODE * ret_keyblock, int secmode)
+lookup (getkey_ctx_t ctx, kbnode_t *ret_keyblock, int want_secret)
 {
   int rc;
-  KBNODE secblock = NULL; /* Helper.  */
   int no_suitable_key = 0;
 
   rc = 0;
-  while (!(rc = keydb_search (ctx->kr_handle, ctx->items, ctx->nitems)))
+  while (!(rc = keydb_search (ctx->kr_handle, ctx->items, ctx->nitems, NULL)))
     {
       /* If we are searching for the first key we have to make sure
          that the next iteration does not do an implicit reset.
@@ -2692,30 +2520,8 @@ lookup (GETKEY_CTX ctx, KBNODE * ret_keyblock, int secmode)
          goto skip;
        }
 
-      if (secmode)
-       {
-         /* Find the correspondig public key and use this
-          * this one for the selection process.  */
-         u32 aki[2];
-         KBNODE k = ctx->keyblock;
-
-         if (k->pkt->pkttype != PKT_SECRET_KEY)
-           BUG ();
-
-         keyid_from_sk (k->pkt->pkt.secret_key, aki);
-         k = get_pubkeyblock (aki);
-         if (!k)
-           {
-             if (!opt.quiet)
-               log_info (_("key %s: secret key without public key"
-                           " - skipped\n"), keystr (aki));
-             goto skip;
-           }
-         secblock = ctx->keyblock;
-         ctx->keyblock = k;
-
-         premerge_public_with_secret (ctx->keyblock, secblock);
-       }
+      if (want_secret && agent_probe_any_secret_key (NULL, ctx->keyblock))
+        goto skip; /* No secret key available.  */
 
       /* Warning: node flag bits 0 and 1 should be preserved by
        * merge_selfsigs.  For secret keys, premerge did tranfer the
@@ -2724,12 +2530,6 @@ lookup (GETKEY_CTX ctx, KBNODE * ret_keyblock, int secmode)
       if (finish_lookup (ctx))
        {
          no_suitable_key = 0;
-         if (secmode)
-           {
-             merge_public_with_secret (ctx->keyblock, secblock);
-             release_kbnode (secblock);
-             secblock = NULL;
-           }
          goto found;
        }
       else
@@ -2737,17 +2537,12 @@ lookup (GETKEY_CTX ctx, KBNODE * ret_keyblock, int secmode)
 
     skip:
       /* Release resources and continue search. */
-      if (secmode)
-       {
-         release_kbnode (secblock);
-         secblock = NULL;
-       }
       release_kbnode (ctx->keyblock);
       ctx->keyblock = NULL;
     }
 
 found:
-  if (rc && rc != -1)
+  if (rc && gpg_err_code (rc) != GPG_ERR_NOT_FOUND)
     log_error ("keydb_search failed: %s\n", g10_errstr (rc));
 
   if (!rc)
@@ -2755,16 +2550,11 @@ found:
       *ret_keyblock = ctx->keyblock; /* Return the keyblock.  */
       ctx->keyblock = NULL;
     }
-  else if (rc == -1 && no_suitable_key)
-    rc = secmode ? G10ERR_UNU_SECKEY : G10ERR_UNU_PUBKEY;
-  else if (rc == -1)
-    rc = secmode ? G10ERR_NO_SECKEY : G10ERR_NO_PUBKEY;
+  else if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND && no_suitable_key)
+    rc = want_secret? G10ERR_UNU_SECKEY : G10ERR_UNU_PUBKEY;
+  else if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
+    rc = want_secret? G10ERR_NO_SECKEY : G10ERR_NO_PUBKEY;
 
-  if (secmode)
-    {
-      release_kbnode (secblock);
-      secblock = NULL;
-    }
   release_kbnode (ctx->keyblock);
   ctx->keyblock = NULL;
 
@@ -2775,55 +2565,42 @@ found:
 
 
 
-/****************
- * FIXME: Replace by the generic function
- *        It does not work as it is right now - it is used at
- *        2 places:  a) to get the key for an anonyous recipient
- *                   b) to get the ultimately trusted keys.
- *        The a) usage might have some problems.
- *
- * set with_subkeys true to include subkeys
- * set with_spm true to include secret-parts-missing keys
- *
- * Enumerate all primary secret keys.  Caller must use these procedure:
+/*
+ * Enumerate certain 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
  *     and provide space for the secret key (pass a buffer for sk)
- *  3) call this function as long as it does not return -1
- *     to indicate EOF.
+ *  3) call this function as long as it does not return an error.
+ *     The error code GPG_ERR_EOF indicates the end of the listing.
  *  4) Always call this function a last time with SK set to NULL,
  *     so that can free it's context.
  */
-int
-enum_secret_keys (void **context, PKT_secret_key * sk,
-                 int with_subkeys, int with_spm)
+gpg_error_t
+enum_secret_keys (void **context, PKT_public_key *sk)
 {
-  int rc = 0;
+  gpg_error_t err = 0;
+  const char *name;
   struct
   {
     int eof;
-    int first;
-    KEYDB_HANDLE hd;
-    KBNODE keyblock;
-    KBNODE node;
+    int state;
+    strlist_t sl;
+    kbnode_t keyblock;
+    kbnode_t node;
   } *c = *context;
 
-
   if (!c)
     {
       /* Make a new context.  */
-      c = xmalloc_clear (sizeof *c);
+      c = xtrycalloc (1, sizeof *c);
+      if (!c)
+        return gpg_error_from_syserror ();
       *context = c;
-      c->hd = keydb_new (1);
-      c->first = 1;
-      c->keyblock = NULL;
-      c->node = NULL;
     }
 
   if (!sk)
     {
       /* Free the context.  */
-      keydb_release (c->hd);
       release_kbnode (c->keyblock);
       xfree (c);
       *context = NULL;
@@ -2831,47 +2608,79 @@ enum_secret_keys (void **context, PKT_secret_key * sk,
     }
 
   if (c->eof)
-    return -1;
-
-  do
-    {
-      /* Get the next secret key from the current keyblock.  */
+    return gpg_error (GPG_ERR_EOF);
+
+  for (;;)
+    {
+      /* Loop until we have a keyblock.  */
+      while (!c->keyblock)
+        {
+          /* Loop over the list of secret keys.  */
+          do
+            {
+              name = NULL;
+              switch (c->state)
+                {
+                case 0: /* First try to use the --default-key.  */
+                  if (opt.def_secret_key && *opt.def_secret_key)
+                    name = opt.def_secret_key;
+                  c->state = 1;
+                  break;
+
+                case 1: /* Init list of keys to try.  */
+                  c->sl = opt.secret_keys_to_try;
+                  c->state++;
+                  break;
+
+                case 2: /* Get next item from list.  */
+                  if (c->sl)
+                    {
+                      name = c->sl->d;
+                      c->sl = c->sl->next;
+                    }
+                  else
+                    c->state++;
+                  break;
+
+                default: /* No more names to check - stop.  */
+                  c->eof = 1;
+                  return gpg_error (GPG_ERR_EOF);
+                }
+            }
+          while (!name || !*name);
+
+          err = getkey_byname (NULL, NULL, name, 1, &c->keyblock);
+          if (err)
+            {
+              /* getkey_byname might return a keyblock even in the
+                 error case - I have not checked.  Thus better release
+                 it.  */
+              release_kbnode (c->keyblock);
+              c->keyblock = NULL;
+            }
+          else
+            c->node = c->keyblock;
+        }
+
+      /* Get the next key from the current keyblock.  */
       for (; c->node; c->node = c->node->next)
        {
-         if ((c->node->pkt->pkttype == PKT_SECRET_KEY
-              || (with_subkeys
-                  && c->node->pkt->pkttype == PKT_SECRET_SUBKEY))
-             && !(c->node->pkt->pkt.secret_key->protect.s2k.mode == 1001
-                  && !with_spm))
+         if (c->node->pkt->pkttype == PKT_PUBLIC_KEY
+              || c->node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
            {
-             copy_secret_key (sk, c->node->pkt->pkt.secret_key);
+             copy_public_key (sk, c->node->pkt->pkt.public_key);
              c->node = c->node->next;
              return 0; /* Found.  */
            }
-       }
-      release_kbnode (c->keyblock);
-      c->keyblock = c->node = NULL;
-
-      rc = c->first ? keydb_search_first (c->hd) : keydb_search_next (c->hd);
-      c->first = 0;
-      if (rc)
-       {
-         keydb_release (c->hd);
-         c->hd = NULL;
-         c->eof = 1;
-         return -1; /* eof */
-       }
+        }
 
-      rc = keydb_get_keyblock (c->hd, &c->keyblock);
-      c->node = c->keyblock;
+      /* Dispose the keyblock and continue.  */
+      release_kbnode (c->keyblock);
+      c->keyblock = NULL;
     }
-  while (!rc);
-
-  return rc; /* Error.  */
 }
-\f
-
 
+\f
 /*********************************************
  ***********  User ID printing helpers *******
  *********************************************/
@@ -2966,7 +2775,10 @@ get_user_id (u32 * keyid, size_t * rn)
            {
              if (a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1])
                {
-                 p = xmalloc (r->len);
+                  /* An empty string as user id is possible.  Make
+                     sure that the malloc allocates one byte and does
+                     not bail out.  */
+                 p = xmalloc (r->len? r->len : 1);
                  memcpy (p, r->name, r->len);
                  *rn = r->len;
                  return p;
@@ -3032,7 +2844,14 @@ parse_auto_key_locate (char *options)
 
       akl = xmalloc_clear (sizeof (*akl));
 
-      if (ascii_strcasecmp (tok, "nodefault") == 0)
+      if (ascii_strcasecmp (tok, "clear") == 0)
+       {
+          xfree (akl);
+          free_akl (opt.auto_key_locate);
+          opt.auto_key_locate = NULL;
+          continue;
+        }
+      else if (ascii_strcasecmp (tok, "nodefault") == 0)
        akl->type = AKL_NODEFAULT;
       else if (ascii_strcasecmp (tok, "local") == 0)
        akl->type = AKL_LOCAL;
@@ -3083,3 +2902,214 @@ parse_auto_key_locate (char *options)
 
   return 1;
 }
+
+
+/* Return true if a secret key or secret subkey is available for one
+   of the public keys in KEYBLOCK.  */
+int
+have_any_secret_key (ctrl_t ctrl, kbnode_t keyblock)
+{
+  kbnode_t node;
+
+  for (node = keyblock; node; node = node->next)
+    if ((node->pkt->pkttype == PKT_PUBLIC_KEY
+         || node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+        && !agent_probe_secret_key (ctrl, node->pkt->pkt.public_key))
+      return 1;
+  return 0;
+}
+
+
+/* Return true if a secret key is available for the public key with
+ * the given KEYID.  This is just a fast check and does not tell us
+ * whether the secret key is valid.  It merely tells os whether there
+ * is some secret key.  */
+int
+have_secret_key_with_kid (u32 *keyid)
+{
+  gpg_error_t err;
+  KEYDB_HANDLE kdbhd;
+  KEYDB_SEARCH_DESC desc;
+  kbnode_t keyblock;
+  kbnode_t node;
+  int result = 0;
+
+  kdbhd = keydb_new ();
+  memset (&desc, 0, sizeof desc);
+  desc.mode = KEYDB_SEARCH_MODE_LONG_KID;
+  desc.u.kid[0] = keyid[0];
+  desc.u.kid[1] = keyid[1];
+  while (!result && !(err = keydb_search (kdbhd, &desc, 1, NULL)))
+    {
+      desc.mode = KEYDB_SEARCH_MODE_NEXT;
+      err = keydb_get_keyblock (kdbhd, &keyblock);
+      if (err)
+        {
+          log_error (_("error reading keyblock: %s\n"), g10_errstr (err));
+          break;
+        }
+
+      for (node = keyblock; node; node = node->next)
+       {
+          /* Bit 0 of the flags is set if the search found the key
+             using that key or subkey.  */
+         if ((node->flag & 1))
+            {
+              assert (node->pkt->pkttype == PKT_PUBLIC_KEY
+                      || node->pkt->pkttype == PKT_PUBLIC_SUBKEY);
+
+              if (!agent_probe_secret_key (NULL, node->pkt->pkt.public_key))
+                {
+                  result = 1;
+                  break;
+                }
+           }
+       }
+      release_kbnode (keyblock);
+    }
+  keydb_release (kdbhd);
+  return result;
+}
+
+
+
+#if 0
+/*
+ * Merge the secret keys from secblock into the pubblock thereby
+ * replacing the public (sub)keys with their secret counterparts Hmmm:
+ * It might be better to get away from the concept of entire secret
+ * keys at all and have a way to store just the real secret parts
+ * from the key.
+ *
+ * FIXME: this is not anymore needed but we keep it as example code for the
+ * new code we need to write for the import/export feature.
+ */
+static void
+merge_public_with_secret (KBNODE pubblock, KBNODE secblock)
+{
+  KBNODE pub;
+
+  assert (pubblock->pkt->pkttype == PKT_PUBLIC_KEY);
+  assert (secblock->pkt->pkttype == PKT_SECRET_KEY);
+
+  for (pub = pubblock; pub; pub = pub->next)
+    {
+      if (pub->pkt->pkttype == PKT_PUBLIC_KEY)
+       {
+         PKT_public_key *pk = pub->pkt->pkt.public_key;
+         PKT_secret_key *sk = secblock->pkt->pkt.secret_key;
+         assert (pub == pubblock); /* Only in the first node.  */
+         /* There is nothing to compare in this case, so just replace
+          * some information.  */
+         copy_public_parts_to_secret_key (pk, sk);
+         free_public_key (pk);
+         pub->pkt->pkttype = PKT_SECRET_KEY;
+         pub->pkt->pkt.secret_key = copy_secret_key (NULL, sk);
+       }
+      else if (pub->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+       {
+         KBNODE sec;
+         PKT_public_key *pk = pub->pkt->pkt.public_key;
+
+         /* This is more complicated: It may happen that the sequence
+          * of the subkeys dosn't match, so we have to find the
+          * appropriate secret key.  */
+         for (sec = secblock->next; sec; sec = sec->next)
+           {
+             if (sec->pkt->pkttype == PKT_SECRET_SUBKEY)
+               {
+                 PKT_secret_key *sk = sec->pkt->pkt.secret_key;
+                 if (!cmp_public_secret_key (pk, sk))
+                   {
+                     copy_public_parts_to_secret_key (pk, sk);
+                     free_public_key (pk);
+                     pub->pkt->pkttype = PKT_SECRET_SUBKEY;
+                     pub->pkt->pkt.secret_key = copy_secret_key (NULL, sk);
+                     break;
+                   }
+               }
+           }
+         if (!sec)
+           BUG (); /* Already checked in premerge.  */
+       }
+    }
+}
+
+
+/* This function checks that for every public subkey a corresponding
+ * secret subkey is available and deletes the public subkey otherwise.
+ * We need this function because we can't delete it later when we
+ * actually merge the secret parts into the pubring.
+ * The function also plays some games with the node flags.
+ *
+ * FIXME: this is not anymore needed but we keep it as example code for the
+ * new code we need to write for the import/export feature.
+ */
+static void
+premerge_public_with_secret (KBNODE pubblock, KBNODE secblock)
+{
+  KBNODE last, pub;
+
+  assert (pubblock->pkt->pkttype == PKT_PUBLIC_KEY);
+  assert (secblock->pkt->pkttype == PKT_SECRET_KEY);
+
+  for (pub = pubblock, last = NULL; pub; last = pub, pub = pub->next)
+    {
+      pub->flag &= ~3; /* Reset bits 0 and 1.  */
+      if (pub->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+       {
+         KBNODE sec;
+         PKT_public_key *pk = pub->pkt->pkt.public_key;
+
+         for (sec = secblock->next; sec; sec = sec->next)
+           {
+             if (sec->pkt->pkttype == PKT_SECRET_SUBKEY)
+               {
+                 PKT_secret_key *sk = sec->pkt->pkt.secret_key;
+                 if (!cmp_public_secret_key (pk, sk))
+                   {
+                     if (sk->protect.s2k.mode == 1001)
+                       {
+                         /* The secret parts are not available so
+                            we can't use that key for signing etc.
+                            Fix the pubkey usage */
+                         pk->pubkey_usage &= ~(PUBKEY_USAGE_SIG
+                                               | PUBKEY_USAGE_AUTH);
+                       }
+                     /* Transfer flag bits 0 and 1 to the pubblock.  */
+                     pub->flag |= (sec->flag & 3);
+                     break;
+                   }
+               }
+           }
+         if (!sec)
+           {
+             KBNODE next, ll;
+
+             if (opt.verbose)
+               log_info (_("no secret subkey"
+                           " for public subkey %s - ignoring\n"),
+                         keystr_from_pk (pk));
+             /* We have to remove the subkey in this case.  */
+             assert (last);
+             /* Find the next subkey.  */
+             for (next = pub->next, ll = pub;
+                  next && next->pkt->pkttype != PKT_PUBLIC_SUBKEY;
+                  ll = next, next = next->next)
+               ;
+             /* Make new link.  */
+             last->next = next;
+             /* Release this public subkey with all sigs.  */
+             ll->next = NULL;
+             release_kbnode (pub);
+             /* Let the loop continue.  */
+             pub = last;
+           }
+       }
+    }
+  /* We need to copy the found bits (0 and 1) from the secret key to
+     the public key.  This has already been done for the subkeys but
+     got lost on the primary key - fix it here.  */
+  pubblock->flag |= (secblock->flag & 3);
+}
+#endif /*0*/