diff --git a/g10/keydb.c b/g10/keydb.c
index 263b504e5..401478a1d 100644
--- a/g10/keydb.c
+++ b/g10/keydb.c
@@ -1,1533 +1,1549 @@
 /* keydb.c - key database dispatcher
  * Copyright (C) 2001, 2002, 2003, 2004, 2005,
  *               2008, 2009, 2011, 2013 Free Software Foundation, Inc.
  * Coyrright (C) 2013 Werner Koch
  *
  * This file is part of GnuPG.
  *
  * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
 #include <assert.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 
 #include "gpg.h"
 #include "util.h"
 #include "options.h"
 #include "main.h" /*try_make_homedir ()*/
 #include "packet.h"
 #include "keyring.h"
 #include "../kbx/keybox.h"
 #include "keydb.h"
 #include "i18n.h"
 
 static int active_handles;
 
 typedef enum
   {
     KEYDB_RESOURCE_TYPE_NONE = 0,
     KEYDB_RESOURCE_TYPE_KEYRING,
     KEYDB_RESOURCE_TYPE_KEYBOX
   } KeydbResourceType;
 #define MAX_KEYDB_RESOURCES 40
 
 struct resource_item
 {
   KeydbResourceType type;
   union {
     KEYRING_HANDLE kr;
     KEYBOX_HANDLE kb;
   } u;
   void *token;
 };
 
 static struct resource_item all_resources[MAX_KEYDB_RESOURCES];
 static int used_resources;
 static void *primary_keyring=NULL;
 
 struct keydb_handle
 {
   int locked;
   int found;
   unsigned long skipped_long_blobs;
   int no_caching;
   int current;
   int used;   /* Number of items in ACTIVE. */
   struct resource_item active[MAX_KEYDB_RESOURCES];
 };
 
 
 /* This is a simple cache used to return the last result of a
    successful fingerprint search.  This works only for keybox resources
    because (due to lack of a copy_keyblock function) we need to store
    an image of the keyblock which is fortunately instantly available
    for keyboxes.  */
 enum keyblock_cache_states {
   KEYBLOCK_CACHE_EMPTY,
   KEYBLOCK_CACHE_PREPARED,
   KEYBLOCK_CACHE_FILLED
 };
 
 struct {
   enum keyblock_cache_states state;
   byte fpr[MAX_FINGERPRINT_LEN];
   iobuf_t iobuf; /* Image of the keyblock.  */
   u32 *sigstatus;
   int pk_no;
   int uid_no;
 } keyblock_cache;
 
 
 static int lock_all (KEYDB_HANDLE hd);
 static void unlock_all (KEYDB_HANDLE hd);
 
 
 static void
 keyblock_cache_clear (void)
 {
   keyblock_cache.state = KEYBLOCK_CACHE_EMPTY;
   xfree (keyblock_cache.sigstatus);
   keyblock_cache.sigstatus = NULL;
   iobuf_close (keyblock_cache.iobuf);
   keyblock_cache.iobuf = NULL;
 }
 
 
 /* Handle the creation of a keyring or a keybox if it does not yet
    exist.  Take into account that other processes might have the
    keyring/keybox already locked.  This lock check does not work if
    the directory itself is not yet available.  If is IS_BOX is true
    the filename is expected to be a keybox.  If FORCE_CREATE is true
    the keyring or keybox shall be created.  */
 static int
 maybe_create_keyring_or_box (char *filename, int is_box, int force_create)
 {
   dotlock_t lockhd = NULL;
   IOBUF iobuf;
   int rc;
   mode_t oldmask;
   char *last_slash_in_filename;
   int save_slash;
 
   /* A quick test whether the filename already exists. */
   if (!access (filename, F_OK))
     return 0;
 
   /* If we don't want to create a new file at all, there is no need to
      go any further - bail out right here.  */
   if (!force_create)
     return gpg_error (GPG_ERR_ENOENT);
 
   /* First of all we try to create the home directory.  Note, that we
      don't do any locking here because any sane application of gpg
      would create the home directory by itself and not rely on gpg's
      tricky auto-creation which is anyway only done for certain home
      directory name pattern. */
   last_slash_in_filename = strrchr (filename, DIRSEP_C);
 #if HAVE_W32_SYSTEM
   {
     /* Windows may either have a slash or a backslash.  Take care of it.  */
     char *p = strrchr (filename, '/');
     if (!last_slash_in_filename || p > last_slash_in_filename)
       last_slash_in_filename = p;
   }
 #endif /*HAVE_W32_SYSTEM*/
   if (!last_slash_in_filename)
     return gpg_error (GPG_ERR_ENOENT);  /* No slash at all - should
                                            not happen though.  */
   save_slash = *last_slash_in_filename;
   *last_slash_in_filename = 0;
   if (access(filename, F_OK))
     {
       static int tried;
 
       if (!tried)
         {
           tried = 1;
           try_make_homedir (filename);
         }
       if (access (filename, F_OK))
         {
           rc = gpg_error_from_syserror ();
           *last_slash_in_filename = save_slash;
           goto leave;
         }
     }
   *last_slash_in_filename = save_slash;
 
   /* To avoid races with other instances of gpg trying to create or
      update the keyring (it is removed during an update for a short
      time), we do the next stuff in a locked state. */
   lockhd = dotlock_create (filename, 0);
   if (!lockhd)
     {
       rc = gpg_error_from_syserror ();
       /* A reason for this to fail is that the directory is not
          writable. However, this whole locking stuff does not make
          sense if this is the case. An empty non-writable directory
          with no keyring is not really useful at all. */
       if (opt.verbose)
         log_info ("can't allocate lock for '%s': %s\n",
                   filename, gpg_strerror (rc));
 
       if (!force_create)
         return gpg_error (GPG_ERR_ENOENT);  /* Won't happen.  */
       else
         return rc;
     }
 
   if ( dotlock_take (lockhd, -1) )
     {
       rc = gpg_error_from_syserror ();
       /* This is something bad.  Probably a stale lockfile.  */
       log_info ("can't lock '%s': %s\n", filename, gpg_strerror (rc));
       goto leave;
     }
 
   /* Now the real test while we are locked. */
   if (!access (filename, F_OK))
     {
       rc = 0;  /* Okay, we may access the file now.  */
       goto leave;
     }
 
   /* The file does not yet exist, create it now. */
   oldmask = umask (077);
   if (is_secured_filename (filename))
     {
       iobuf = NULL;
       gpg_err_set_errno (EPERM);
     }
   else
     iobuf = iobuf_create (filename, 0);
   umask (oldmask);
   if (!iobuf)
     {
       rc = gpg_error_from_syserror ();
       if (is_box)
         log_error (_("error creating keybox '%s': %s\n"),
                    filename, gpg_strerror (rc));
       else
         log_error (_("error creating keyring '%s': %s\n"),
                    filename, gpg_strerror (rc));
       goto leave;
     }
 
   iobuf_close (iobuf);
   /* Must invalidate that ugly cache */
   iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, filename);
 
   /* Make sure that at least one record is in a new keybox file, so
      that the detection magic will work the next time it is used.  */
   if (is_box)
     {
       FILE *fp = fopen (filename, "w");
       if (!fp)
         rc = gpg_error_from_syserror ();
       else
         {
           rc = _keybox_write_header_blob (fp, 1);
           fclose (fp);
         }
       if (rc)
         {
           if (is_box)
             log_error (_("error creating keybox '%s': %s\n"),
                        filename, gpg_strerror (rc));
           else
             log_error (_("error creating keyring '%s': %s\n"),
                        filename, gpg_strerror (rc));
           goto leave;
         }
     }
 
   if (!opt.quiet)
     {
       if (is_box)
         log_info (_("keybox '%s' created\n"), filename);
       else
         log_info (_("keyring '%s' created\n"), filename);
     }
 
   rc = 0;
 
  leave:
   if (lockhd)
     {
       dotlock_release (lockhd);
       dotlock_destroy (lockhd);
     }
   return rc;
 }
 
 
 /* Helper for keydb_add_resource.  Opens FILENAME to figures out the
    resource type.  Returns the resource type and a flag at R_NOTFOUND
    indicating whether FILENAME could be opened at all.  If the openpgp
    flag is set in a keybox header, R_OPENPGP will be set to true.  */
 static KeydbResourceType
 rt_from_file (const char *filename, int *r_found, int *r_openpgp)
 {
   u32 magic;
   unsigned char verbuf[4];
   FILE *fp;
   KeydbResourceType rt = KEYDB_RESOURCE_TYPE_NONE;
 
   *r_found = *r_openpgp = 0;
   fp = fopen (filename, "rb");
   if (fp)
     {
       *r_found = 1;
 
       if (fread (&magic, 4, 1, fp) == 1 )
         {
           if (magic == 0x13579ace || magic == 0xce9a5713)
             ; /* GDBM magic - not anymore supported. */
           else if (fread (&verbuf, 4, 1, fp) == 1
                    && verbuf[0] == 1
                    && fread (&magic, 4, 1, fp) == 1
                    && !memcmp (&magic, "KBXf", 4))
             {
               if ((verbuf[3] & 0x02))
                 *r_openpgp = 1;
               rt = KEYDB_RESOURCE_TYPE_KEYBOX;
             }
           else
             rt = KEYDB_RESOURCE_TYPE_KEYRING;
         }
       else /* Maybe empty: assume keyring. */
         rt = KEYDB_RESOURCE_TYPE_KEYRING;
 
       fclose (fp);
     }
 
   return rt;
 }
 
 
 /*
  * Register a resource (keyring or aeybox).  The first keyring or
  * keybox which is added by this function is created if it does not
  * exist.  FLAGS are a combination of the KEYDB_RESOURCE_FLAG_
  * constants as defined in keydb.h.
  */
 gpg_error_t
 keydb_add_resource (const char *url, unsigned int flags)
 {
   static int any_registered;
   const char *resname = url;
   char *filename = NULL;
   int create;
   int read_only = !!(flags&KEYDB_RESOURCE_FLAG_READONLY);
   int is_default = !!(flags&KEYDB_RESOURCE_FLAG_DEFAULT);
   int rc = 0;
   KeydbResourceType rt = KEYDB_RESOURCE_TYPE_NONE;
   void *token;
 
   /* Create the resource if it is the first registered one.  */
   create = (!read_only && !any_registered);
 
   /* Do we have an URL?
    *	gnupg-ring:filename  := this is a plain keyring.
    *	gnupg-kbx:filename   := this is a keybox file.
    *	filename := See what is is, but create as plain keyring.
    */
   if (strlen (resname) > 11 && !strncmp( resname, "gnupg-ring:", 11) )
     {
       rt = KEYDB_RESOURCE_TYPE_KEYRING;
       resname += 11;
     }
   else if (strlen (resname) > 10 && !strncmp (resname, "gnupg-kbx:", 10) )
     {
       rt = KEYDB_RESOURCE_TYPE_KEYBOX;
       resname += 10;
     }
 #if !defined(HAVE_DRIVE_LETTERS) && !defined(__riscos__)
   else if (strchr (resname, ':'))
     {
       log_error ("invalid key resource URL '%s'\n", url );
       rc = gpg_error (GPG_ERR_GENERAL);
       goto leave;
     }
 #endif /* !HAVE_DRIVE_LETTERS && !__riscos__ */
 
   if (*resname != DIRSEP_C )
     {
       /* Do tilde expansion etc. */
       if (strchr(resname, DIRSEP_C) )
         filename = make_filename (resname, NULL);
       else
         filename = make_filename (opt.homedir, resname, NULL);
     }
   else
     filename = xstrdup (resname);
 
   /* See whether we can determine the filetype.  */
   if (rt == KEYDB_RESOURCE_TYPE_NONE)
     {
       int found, openpgp_flag;
       int pass = 0;
       size_t filenamelen;
 
     check_again:
       filenamelen = strlen (filename);
       rt = rt_from_file (filename, &found, &openpgp_flag);
       if (found)
         {
           /* The file exists and we have the resource type in RT.
 
              Now let us check whether in addition to the "pubring.gpg"
              a "pubring.kbx with openpgp keys exists.  This is so that
              GPG 2.1 will use an existing "pubring.kbx" by default iff
              that file has been created or used by 2.1.  This check is
              needed because after creation or use of the kbx file with
              2.1 an older version of gpg may have created a new
              pubring.gpg for its own use.  */
           if (!pass && is_default && rt == KEYDB_RESOURCE_TYPE_KEYRING
               && filenamelen > 4 && !strcmp (filename+filenamelen-4, ".gpg"))
             {
               strcpy (filename+filenamelen-4, ".kbx");
               if ((rt_from_file (filename, &found, &openpgp_flag)
                    == KEYDB_RESOURCE_TYPE_KEYBOX) && found && openpgp_flag)
                 rt = KEYDB_RESOURCE_TYPE_KEYBOX;
               else /* Restore filename */
                 strcpy (filename+filenamelen-4, ".gpg");
             }
 	}
       else if (!pass
                && is_default && create
                && filenamelen > 4 && !strcmp (filename+filenamelen-4, ".gpg"))
         {
           /* The file does not exist, the default resource has been
              requested, the file shall be created, and the file has a
              ".gpg" suffix.  Change the suffix to ".kbx" and try once
              more.  This way we achieve that we open an existing
              ".gpg" keyring, but create a new keybox file with an
              ".kbx" suffix.  */
           strcpy (filename+filenamelen-4, ".kbx");
           pass++;
           goto check_again;
         }
       else /* No file yet: create keybox. */
         rt = KEYDB_RESOURCE_TYPE_KEYBOX;
     }
 
   switch (rt)
     {
     case KEYDB_RESOURCE_TYPE_NONE:
       log_error ("unknown type of key resource '%s'\n", url );
       rc = gpg_error (GPG_ERR_GENERAL);
       goto leave;
 
     case KEYDB_RESOURCE_TYPE_KEYRING:
       rc = maybe_create_keyring_or_box (filename, 0, create);
       if (rc)
         goto leave;
 
       if (keyring_register_filename (filename, read_only, &token))
         {
           if (used_resources >= MAX_KEYDB_RESOURCES)
             rc = gpg_error (GPG_ERR_RESOURCE_LIMIT);
           else
             {
               if ((flags & KEYDB_RESOURCE_FLAG_PRIMARY))
                 primary_keyring = token;
               all_resources[used_resources].type = rt;
               all_resources[used_resources].u.kr = NULL; /* Not used here */
               all_resources[used_resources].token = token;
               used_resources++;
             }
         }
       else
         {
           /* This keyring was already registered, so ignore it.
              However, we can still mark it as primary even if it was
              already registered.  */
           if ((flags & KEYDB_RESOURCE_FLAG_PRIMARY))
             primary_keyring = token;
         }
       break;
 
     case KEYDB_RESOURCE_TYPE_KEYBOX:
       {
         rc = maybe_create_keyring_or_box (filename, 1, create);
         if (rc)
           goto leave;
 
         /* FIXME: How do we register a read-only keybox?  */
         token = keybox_register_file (filename, 0);
         if (token)
           {
             if (used_resources >= MAX_KEYDB_RESOURCES)
               rc = gpg_error (GPG_ERR_RESOURCE_LIMIT);
             else
               {
                 /* if ((flags & KEYDB_RESOURCE_FLAG_PRIMARY)) */
                 /*   primary_keyring = token; */
                 all_resources[used_resources].type = rt;
                 all_resources[used_resources].u.kb = NULL; /* Not used here */
                 all_resources[used_resources].token = token;
 
                 /* FIXME: Do a compress run if needed and no other
                    user is currently using the keybox. */
 
                 used_resources++;
               }
           }
         else
           {
             /* Already registered.  We will mark it as the primary key
                if requested.  */
             /* FIXME: How to do that?  Change the keybox interface?  */
             /* if ((flags & KEYDB_RESOURCE_FLAG_PRIMARY)) */
             /*   primary_keyring = token; */
           }
       }
       break;
 
       default:
 	log_error ("resource type of '%s' not supported\n", url);
 	rc = gpg_error (GPG_ERR_GENERAL);
 	goto leave;
     }
 
   /* fixme: check directory permissions and print a warning */
 
  leave:
   if (rc)
     log_error (_("keyblock resource '%s': %s\n"), filename, gpg_strerror (rc));
   else
     any_registered = 1;
   xfree (filename);
   return rc;
 }
 
 
 
 
 KEYDB_HANDLE
 keydb_new (void)
 {
   KEYDB_HANDLE hd;
   int i, j;
 
   if (DBG_CLOCK)
     log_clock ("keydb_new");
 
   hd = xmalloc_clear (sizeof *hd);
   hd->found = -1;
 
   assert (used_resources <= MAX_KEYDB_RESOURCES);
   for (i=j=0; i < used_resources; i++)
     {
       switch (all_resources[i].type)
         {
         case KEYDB_RESOURCE_TYPE_NONE: /* ignore */
           break;
         case KEYDB_RESOURCE_TYPE_KEYRING:
           hd->active[j].type   = all_resources[i].type;
           hd->active[j].token  = all_resources[i].token;
           hd->active[j].u.kr = keyring_new (all_resources[i].token);
           if (!hd->active[j].u.kr) {
             xfree (hd);
             return NULL; /* fixme: release all previously allocated handles*/
           }
           j++;
           break;
         case KEYDB_RESOURCE_TYPE_KEYBOX:
           hd->active[j].type   = all_resources[i].type;
           hd->active[j].token  = all_resources[i].token;
           hd->active[j].u.kb   = keybox_new_openpgp (all_resources[i].token, 0);
           if (!hd->active[j].u.kb)
             {
               xfree (hd);
               return NULL; /* fixme: release all previously allocated handles*/
             }
           j++;
           break;
         }
     }
   hd->used = j;
 
   active_handles++;
   return hd;
 }
 
 
 void
 keydb_release (KEYDB_HANDLE hd)
 {
   int i;
 
   if (!hd)
     return;
   assert (active_handles > 0);
   active_handles--;
 
   unlock_all (hd);
   for (i=0; i < hd->used; i++)
     {
       switch (hd->active[i].type)
         {
         case KEYDB_RESOURCE_TYPE_NONE:
           break;
         case KEYDB_RESOURCE_TYPE_KEYRING:
           keyring_release (hd->active[i].u.kr);
           break;
         case KEYDB_RESOURCE_TYPE_KEYBOX:
           keybox_release (hd->active[i].u.kb);
           break;
         }
     }
 
   xfree (hd);
 }
 
 
 /* Set a flag on handle to not use cached results.  This is required
    for updating a keyring and for key listins.  Fixme: Using a new
    parameter for keydb_new might be a better solution.  */
 void
 keydb_disable_caching (KEYDB_HANDLE hd)
 {
   if (hd)
     hd->no_caching = 1;
 }
 
 
 /*
  * Return the name of the current resource.  This is function first
  * looks for the last found found, then for the current search
  * position, and last returns the first available resource.  The
  * returned string is only valid as long as the handle exists.  This
  * function does only return NULL if no handle is specified, in all
  * other error cases an empty string is returned.
  */
 const char *
 keydb_get_resource_name (KEYDB_HANDLE hd)
 {
   int idx;
   const char *s = NULL;
 
   if (!hd)
     return NULL;
 
   if ( hd->found >= 0 && hd->found < hd->used)
     idx = hd->found;
   else if ( hd->current >= 0 && hd->current < hd->used)
     idx = hd->current;
   else
     idx = 0;
 
   switch (hd->active[idx].type)
     {
     case KEYDB_RESOURCE_TYPE_NONE:
       s = NULL;
       break;
     case KEYDB_RESOURCE_TYPE_KEYRING:
       s = keyring_get_resource_name (hd->active[idx].u.kr);
       break;
     case KEYDB_RESOURCE_TYPE_KEYBOX:
       s = keybox_get_resource_name (hd->active[idx].u.kb);
       break;
     }
 
   return s? s: "";
 }
 
 
 
 static int
 lock_all (KEYDB_HANDLE hd)
 {
   int i, rc = 0;
 
   /* Fixme: This locking scheme may lead to a deadlock if the resources
      are not added in the same order by all processes.  We are
      currently only allowing one resource so it is not a problem.
      [Oops: Who claimed the latter]
 
      To fix this we need to use a lock file to protect lock_all.  */
 
   for (i=0; !rc && i < hd->used; i++)
     {
       switch (hd->active[i].type)
         {
         case KEYDB_RESOURCE_TYPE_NONE:
           break;
         case KEYDB_RESOURCE_TYPE_KEYRING:
           rc = keyring_lock (hd->active[i].u.kr, 1);
           break;
         case KEYDB_RESOURCE_TYPE_KEYBOX:
           rc = keybox_lock (hd->active[i].u.kb, 1);
           break;
         }
     }
 
   if (rc)
     {
       /* Revert the already taken locks.  */
       for (i--; i >= 0; i--)
         {
           switch (hd->active[i].type)
             {
             case KEYDB_RESOURCE_TYPE_NONE:
               break;
             case KEYDB_RESOURCE_TYPE_KEYRING:
               keyring_lock (hd->active[i].u.kr, 0);
               break;
             case KEYDB_RESOURCE_TYPE_KEYBOX:
               rc = keybox_lock (hd->active[i].u.kb, 0);
               break;
             }
         }
     }
   else
     hd->locked = 1;
 
   return rc;
 }
 
 
 static void
 unlock_all (KEYDB_HANDLE hd)
 {
   int i;
 
   if (!hd->locked)
     return;
 
   for (i=hd->used-1; i >= 0; i--)
     {
       switch (hd->active[i].type)
         {
         case KEYDB_RESOURCE_TYPE_NONE:
           break;
         case KEYDB_RESOURCE_TYPE_KEYRING:
           keyring_lock (hd->active[i].u.kr, 0);
           break;
         case KEYDB_RESOURCE_TYPE_KEYBOX:
           keybox_lock (hd->active[i].u.kb, 0);
           break;
         }
     }
   hd->locked = 0;
 }
 
 
 static gpg_error_t
 parse_keyblock_image (iobuf_t iobuf, int pk_no, int uid_no,
                       const u32 *sigstatus, kbnode_t *r_keyblock)
 {
   gpg_error_t err;
   PACKET *pkt;
   kbnode_t keyblock = NULL;
   kbnode_t node, *tail;
   int in_cert, save_mode;
   u32 n_sigs;
   int pk_count, uid_count;
 
   *r_keyblock = NULL;
 
   pkt = xtrymalloc (sizeof *pkt);
   if (!pkt)
     return gpg_error_from_syserror ();
   init_packet (pkt);
   save_mode = set_packet_list_mode (0);
   in_cert = 0;
   n_sigs = 0;
   tail = NULL;
   pk_count = uid_count = 0;
   while ((err = parse_packet (iobuf, pkt)) != -1)
     {
       if (gpg_err_code (err) == GPG_ERR_UNKNOWN_PACKET)
         {
           free_packet (pkt);
           init_packet (pkt);
           continue;
 	}
       if (err)
         {
           log_error ("parse_keyblock_image: read error: %s\n",
                      gpg_strerror (err));
           err = gpg_error (GPG_ERR_INV_KEYRING);
           break;
         }
       if (pkt->pkttype == PKT_COMPRESSED)
         {
           log_error ("skipped compressed packet in keybox blob\n");
           free_packet(pkt);
           init_packet(pkt);
           continue;
         }
       if (pkt->pkttype == PKT_RING_TRUST)
         {
           log_info ("skipped ring trust packet in keybox blob\n");
           free_packet(pkt);
           init_packet(pkt);
           continue;
         }
 
       if (!in_cert && pkt->pkttype != PKT_PUBLIC_KEY)
         {
           log_error ("parse_keyblock_image: first packet in a keybox blob "
                      "is not a public key packet\n");
           err = gpg_error (GPG_ERR_INV_KEYRING);
           break;
         }
       if (in_cert && (pkt->pkttype == PKT_PUBLIC_KEY
                       || pkt->pkttype == PKT_SECRET_KEY))
         {
           log_error ("parse_keyblock_image: "
                      "multiple keyblocks in a keybox blob\n");
           err = gpg_error (GPG_ERR_INV_KEYRING);
           break;
         }
       in_cert = 1;
 
       if (pkt->pkttype == PKT_SIGNATURE && sigstatus)
         {
           PKT_signature *sig = pkt->pkt.signature;
 
           n_sigs++;
           if (n_sigs > sigstatus[0])
             {
               log_error ("parse_keyblock_image: "
                          "more signatures than found in the meta data\n");
               err = gpg_error (GPG_ERR_INV_KEYRING);
               break;
 
             }
           if (sigstatus[n_sigs])
             {
               sig->flags.checked = 1;
               if (sigstatus[n_sigs] == 1 )
                 ; /* missing key */
               else if (sigstatus[n_sigs] == 2 )
                 ; /* bad signature */
               else if (sigstatus[n_sigs] < 0x10000000)
                 ; /* bad flag */
               else
                 {
                   sig->flags.valid = 1;
                   /* Fixme: Shall we set the expired flag here?  */
                 }
             }
         }
 
       node = new_kbnode (pkt);
 
       switch (pkt->pkttype)
         {
         case PKT_PUBLIC_KEY:
         case PKT_PUBLIC_SUBKEY:
         case PKT_SECRET_KEY:
         case PKT_SECRET_SUBKEY:
           if (++pk_count == pk_no)
             node->flag |= 1;
           break;
 
         case PKT_USER_ID:
           if (++uid_count == uid_no)
             node->flag |= 2;
           break;
 
         default:
           break;
         }
 
       if (!keyblock)
         keyblock = node;
       else
         *tail = node;
       tail = &node->next;
       pkt = xtrymalloc (sizeof *pkt);
       if (!pkt)
         {
           err = gpg_error_from_syserror ();
           break;
         }
       init_packet (pkt);
     }
   set_packet_list_mode (save_mode);
 
   if (err == -1 && keyblock)
     err = 0; /* Got the entire keyblock.  */
 
   if (!err && sigstatus && n_sigs != sigstatus[0])
     {
       log_error ("parse_keyblock_image: signature count does not match\n");
       err = gpg_error (GPG_ERR_INV_KEYRING);
     }
 
   if (err)
     release_kbnode (keyblock);
   else
     *r_keyblock = keyblock;
   free_packet (pkt);
   xfree (pkt);
   return err;
 }
 
 
 /*
  * Return the last found keyring.  Caller must free it.
  * The returned keyblock has the kbode flag bit 0 set for the node with
  * the public key used to locate the keyblock or flag bit 1 set for
  * the user ID node.
  */
 gpg_error_t
 keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb)
 {
   gpg_error_t err = 0;
 
   *ret_kb = NULL;
 
   if (!hd)
     return gpg_error (GPG_ERR_INV_ARG);
 
   if (keyblock_cache.state == KEYBLOCK_CACHE_FILLED)
     {
       iobuf_seek (keyblock_cache.iobuf, 0);
       err = parse_keyblock_image (keyblock_cache.iobuf,
                                   keyblock_cache.pk_no,
                                   keyblock_cache.uid_no,
                                   keyblock_cache.sigstatus,
                                   ret_kb);
       if (err)
         keyblock_cache_clear ();
       return err;
     }
 
   if (hd->found < 0 || hd->found >= hd->used)
     return gpg_error (GPG_ERR_VALUE_NOT_FOUND);
 
   switch (hd->active[hd->found].type)
     {
     case KEYDB_RESOURCE_TYPE_NONE:
       err = gpg_error (GPG_ERR_GENERAL); /* oops */
       break;
     case KEYDB_RESOURCE_TYPE_KEYRING:
       err = keyring_get_keyblock (hd->active[hd->found].u.kr, ret_kb);
       break;
     case KEYDB_RESOURCE_TYPE_KEYBOX:
       {
         iobuf_t iobuf;
         u32 *sigstatus;
         int pk_no, uid_no;
 
         err = keybox_get_keyblock (hd->active[hd->found].u.kb,
                                    &iobuf, &pk_no, &uid_no, &sigstatus);
         if (!err)
           {
             err = parse_keyblock_image (iobuf, pk_no, uid_no, sigstatus,
                                         ret_kb);
             if (!err && keyblock_cache.state == KEYBLOCK_CACHE_PREPARED)
               {
                 keyblock_cache.state     = KEYBLOCK_CACHE_FILLED;
                 keyblock_cache.sigstatus = sigstatus;
                 keyblock_cache.iobuf     = iobuf;
                 keyblock_cache.pk_no     = pk_no;
                 keyblock_cache.uid_no    = uid_no;
               }
             else
               {
                 xfree (sigstatus);
                 iobuf_close (iobuf);
               }
           }
       }
       break;
     }
 
   if (keyblock_cache.state != KEYBLOCK_CACHE_FILLED)
     keyblock_cache_clear ();
 
   return err;
 }
 
 
 /* Build a keyblock image from KEYBLOCK.  Returns 0 on success and
    only then stores a new iobuf object at R_IOBUF and a signature
    status vecotor at R_SIGSTATUS.  */
 static gpg_error_t
 build_keyblock_image (kbnode_t keyblock, iobuf_t *r_iobuf, u32 **r_sigstatus)
 {
   gpg_error_t err;
   iobuf_t iobuf;
   kbnode_t kbctx, node;
   u32 n_sigs;
   u32 *sigstatus;
 
   *r_iobuf = NULL;
   if (r_sigstatus)
     *r_sigstatus = NULL;
 
   /* Allocate a vector for the signature cache.  This is an array of
      u32 values with the first value giving the number of elements to
      follow and each element descriping the cache status of the
      signature.  */
   if (r_sigstatus)
     {
       for (kbctx=NULL, n_sigs=0; (node = walk_kbnode (keyblock, &kbctx, 0));)
         if (node->pkt->pkttype == PKT_SIGNATURE)
           n_sigs++;
       sigstatus = xtrycalloc (1+n_sigs, sizeof *sigstatus);
       if (!sigstatus)
         return gpg_error_from_syserror ();
     }
   else
     sigstatus = NULL;
 
   iobuf = iobuf_temp ();
   for (kbctx = NULL, n_sigs = 0; (node = walk_kbnode (keyblock, &kbctx, 0));)
     {
       /* Make sure to use only packets valid on a keyblock.  */
       switch (node->pkt->pkttype)
         {
         case PKT_PUBLIC_KEY:
         case PKT_PUBLIC_SUBKEY:
         case PKT_SIGNATURE:
         case PKT_USER_ID:
         case PKT_ATTRIBUTE:
           /* Note that we don't want the ring trust packets.  They are
              not useful. */
           break;
         default:
           continue;
         }
 
       err = build_packet (iobuf, node->pkt);
       if (err)
         {
           iobuf_close (iobuf);
           return err;
         }
 
       /* Build signature status vector.  */
       if (node->pkt->pkttype == PKT_SIGNATURE)
         {
           PKT_signature *sig = node->pkt->pkt.signature;
 
           n_sigs++;
           /* Fixme: Detect the "missing key" status.  */
           if (sig->flags.checked && sigstatus)
             {
               if (sig->flags.valid)
                 {
                   if (!sig->expiredate)
                     sigstatus[n_sigs] = 0xffffffff;
                   else if (sig->expiredate < 0x1000000)
                     sigstatus[n_sigs] = 0x10000000;
                   else
                     sigstatus[n_sigs] = sig->expiredate;
                 }
               else
                 sigstatus[n_sigs] = 0x00000002; /* Bad signature.  */
             }
         }
     }
   if (sigstatus)
     sigstatus[0] = n_sigs;
 
   *r_iobuf = iobuf;
   if (r_sigstatus)
     *r_sigstatus = sigstatus;
   return 0;
 }
 
 
 /*
  * Update the current keyblock with the keyblock KB
  */
 gpg_error_t
 keydb_update_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
 {
   gpg_error_t err;
 
   if (!hd)
     return gpg_error (GPG_ERR_INV_ARG);
 
   keyblock_cache_clear ();
 
   if (hd->found < 0 || hd->found >= hd->used)
     return gpg_error (GPG_ERR_VALUE_NOT_FOUND);
 
   if (opt.dry_run)
     return 0;
 
   err = lock_all (hd);
   if (err)
     return err;
 
   switch (hd->active[hd->found].type)
     {
     case KEYDB_RESOURCE_TYPE_NONE:
       err = gpg_error (GPG_ERR_GENERAL); /* oops */
       break;
     case KEYDB_RESOURCE_TYPE_KEYRING:
       err = keyring_update_keyblock (hd->active[hd->found].u.kr, kb);
       break;
     case KEYDB_RESOURCE_TYPE_KEYBOX:
       {
         iobuf_t iobuf;
 
         err = build_keyblock_image (kb, &iobuf, NULL);
         if (!err)
           {
             err = keybox_update_keyblock (hd->active[hd->found].u.kb,
                                           iobuf_get_temp_buffer (iobuf),
                                           iobuf_get_temp_length (iobuf));
             iobuf_close (iobuf);
           }
       }
       break;
     }
 
   unlock_all (hd);
   return err;
 }
 
 
 /*
  * Insert a new KB into one of the resources.
  */
 gpg_error_t
 keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
 {
   gpg_error_t err;
   int idx;
 
   if (!hd)
     return gpg_error (GPG_ERR_INV_ARG);
 
   keyblock_cache_clear ();
 
   if (opt.dry_run)
     return 0;
 
   if (hd->found >= 0 && hd->found < hd->used)
     idx = hd->found;
   else if (hd->current >= 0 && hd->current < hd->used)
     idx = hd->current;
   else
     return gpg_error (GPG_ERR_GENERAL);
 
   err = lock_all (hd);
   if (err)
     return err;
 
   switch (hd->active[idx].type)
     {
     case KEYDB_RESOURCE_TYPE_NONE:
       err = gpg_error (GPG_ERR_GENERAL); /* oops */
       break;
     case KEYDB_RESOURCE_TYPE_KEYRING:
       err = keyring_insert_keyblock (hd->active[idx].u.kr, kb);
       break;
     case KEYDB_RESOURCE_TYPE_KEYBOX:
       { /* We need to turn our kbnode_t list of packets into a proper
            keyblock first.  This is required by the OpenPGP key parser
            included in the keybox code.  Eventually we can change this
            kludge to have the caller pass the image.  */
         iobuf_t iobuf;
         u32 *sigstatus;
 
         err = build_keyblock_image (kb, &iobuf, &sigstatus);
         if (!err)
           {
             err = keybox_insert_keyblock (hd->active[idx].u.kb,
                                           iobuf_get_temp_buffer (iobuf),
                                           iobuf_get_temp_length (iobuf),
                                           sigstatus);
             xfree (sigstatus);
             iobuf_close (iobuf);
           }
       }
       break;
     }
 
   unlock_all (hd);
   return err;
 }
 
 
 /*
  * Delete the current keyblock.
  */
 gpg_error_t
 keydb_delete_keyblock (KEYDB_HANDLE hd)
 {
   gpg_error_t rc;
 
   if (!hd)
     return gpg_error (GPG_ERR_INV_ARG);
 
   keyblock_cache_clear ();
 
   if (hd->found < 0 || hd->found >= hd->used)
     return gpg_error (GPG_ERR_VALUE_NOT_FOUND);
 
   if (opt.dry_run)
     return 0;
 
   rc = lock_all (hd);
   if (rc)
     return rc;
 
   switch (hd->active[hd->found].type)
     {
     case KEYDB_RESOURCE_TYPE_NONE:
       rc = gpg_error (GPG_ERR_GENERAL);
       break;
     case KEYDB_RESOURCE_TYPE_KEYRING:
       rc = keyring_delete_keyblock (hd->active[hd->found].u.kr);
       break;
     case KEYDB_RESOURCE_TYPE_KEYBOX:
       rc = keybox_delete (hd->active[hd->found].u.kb);
       break;
     }
 
   unlock_all (hd);
   return rc;
 }
 
 
 
 /*
  * Locate the default writable key resource, so that the next
  * operation (which is only relevant for inserts) will be done on this
  * resource.
  */
 gpg_error_t
 keydb_locate_writable (KEYDB_HANDLE hd, const char *reserved)
 {
   gpg_error_t rc;
 
   (void)reserved;
 
   if (!hd)
     return GPG_ERR_INV_ARG;
 
   rc = keydb_search_reset (hd); /* this does reset hd->current */
   if (rc)
     return rc;
 
   /* If we have a primary set, try that one first */
   if (primary_keyring)
     {
       for ( ; hd->current >= 0 && hd->current < hd->used; hd->current++)
 	{
 	  if(hd->active[hd->current].token==primary_keyring)
 	    {
 	      if(keyring_is_writable (hd->active[hd->current].token))
 		return 0;
 	      else
 		break;
 	    }
 	}
 
       rc = keydb_search_reset (hd); /* this does reset hd->current */
       if (rc)
 	return rc;
     }
 
   for ( ; hd->current >= 0 && hd->current < hd->used; hd->current++)
     {
       switch (hd->active[hd->current].type)
         {
         case KEYDB_RESOURCE_TYPE_NONE:
           BUG();
           break;
         case KEYDB_RESOURCE_TYPE_KEYRING:
           if (keyring_is_writable (hd->active[hd->current].token))
             return 0; /* found (hd->current is set to it) */
           break;
         case KEYDB_RESOURCE_TYPE_KEYBOX:
           if (keybox_is_writable (hd->active[hd->current].token))
             return 0; /* found (hd->current is set to it) */
           break;
         }
     }
 
   return gpg_error (GPG_ERR_NOT_FOUND);
 }
 
 /*
  * Rebuild the caches of all key resources.
  */
 void
 keydb_rebuild_caches (int noisy)
 {
   int i, rc;
 
   keyblock_cache_clear ();
 
   for (i=0; i < used_resources; i++)
     {
       if (!keyring_is_writable (all_resources[i].token))
         continue;
       switch (all_resources[i].type)
         {
         case KEYDB_RESOURCE_TYPE_NONE: /* ignore */
           break;
         case KEYDB_RESOURCE_TYPE_KEYRING:
           rc = keyring_rebuild_cache (all_resources[i].token,noisy);
           if (rc)
             log_error (_("failed to rebuild keyring cache: %s\n"),
                        gpg_strerror (rc));
           break;
         case KEYDB_RESOURCE_TYPE_KEYBOX:
           /* N/A.  */
           break;
         }
     }
 }
 
 
 /* Return the number of skipped blocks since the last search reset.  */
 unsigned long
 keydb_get_skipped_counter (KEYDB_HANDLE hd)
 {
   return hd ? hd->skipped_long_blobs : 0;
 }
 
 
 /*
  * Start the next search on this handle right at the beginning
  */
 gpg_error_t
 keydb_search_reset (KEYDB_HANDLE hd)
 {
   gpg_error_t rc = 0;
   int i;
 
   if (!hd)
     return gpg_error (GPG_ERR_INV_ARG);
 
   keyblock_cache_clear ();
 
   if (DBG_CLOCK)
     log_clock ("keydb_search_reset");
 
   if (DBG_CACHE)
     log_debug ("keydb_search: reset  (hd=%p)", hd);
 
   hd->skipped_long_blobs = 0;
   hd->current = 0;
   hd->found = -1;
   /* Now reset all resources.  */
   for (i=0; !rc && i < hd->used; i++)
     {
       switch (hd->active[i].type)
         {
         case KEYDB_RESOURCE_TYPE_NONE:
           break;
         case KEYDB_RESOURCE_TYPE_KEYRING:
           rc = keyring_search_reset (hd->active[i].u.kr);
           break;
         case KEYDB_RESOURCE_TYPE_KEYBOX:
           rc = keybox_search_reset (hd->active[i].u.kb);
           break;
         }
     }
   return rc;
 }
 
 
 static void
 dump_search_desc (KEYDB_HANDLE hd, const char *text,
                   KEYDB_SEARCH_DESC *desc, size_t ndesc)
 {
   int n;
   const char *s;
 
   for (n=0; n < ndesc; n++)
     {
       switch (desc[n].mode)
         {
         case KEYDB_SEARCH_MODE_NONE:      s = "none";      break;
         case KEYDB_SEARCH_MODE_EXACT:     s = "exact";     break;
         case KEYDB_SEARCH_MODE_SUBSTR:    s = "substr";    break;
         case KEYDB_SEARCH_MODE_MAIL:      s = "mail";      break;
         case KEYDB_SEARCH_MODE_MAILSUB:   s = "mailsub";   break;
         case KEYDB_SEARCH_MODE_MAILEND:   s = "mailend";   break;
         case KEYDB_SEARCH_MODE_WORDS:     s = "words";     break;
         case KEYDB_SEARCH_MODE_SHORT_KID: s = "short_kid"; break;
         case KEYDB_SEARCH_MODE_LONG_KID:  s = "long_kid";  break;
         case KEYDB_SEARCH_MODE_FPR16:     s = "fpr16";     break;
         case KEYDB_SEARCH_MODE_FPR20:     s = "fpr20";     break;
         case KEYDB_SEARCH_MODE_FPR:       s = "fpr";       break;
         case KEYDB_SEARCH_MODE_ISSUER:    s = "issuer";    break;
         case KEYDB_SEARCH_MODE_ISSUER_SN: s = "issuer_sn"; break;
         case KEYDB_SEARCH_MODE_SN:        s = "sn";        break;
         case KEYDB_SEARCH_MODE_SUBJECT:   s = "subject";   break;
         case KEYDB_SEARCH_MODE_KEYGRIP:   s = "keygrip";   break;
         case KEYDB_SEARCH_MODE_FIRST:     s = "first";     break;
         case KEYDB_SEARCH_MODE_NEXT:      s = "next";      break;
         default:                          s = "?";         break;
         }
       if (!n)
         log_debug ("%s: mode=%s  (hd=%p)", text, s, hd);
       else
         log_debug ("%*s  mode=%s", (int)strlen (text), "", s);
       if (desc[n].mode == KEYDB_SEARCH_MODE_LONG_KID)
         log_printf (" %08lX%08lX", (unsigned long)desc[n].u.kid[0],
                     (unsigned long)desc[n].u.kid[1]);
       else if (desc[n].mode == KEYDB_SEARCH_MODE_SHORT_KID)
         log_printf (" %08lX", (unsigned long)desc[n].u.kid[1]);
       else if (desc[n].mode == KEYDB_SEARCH_MODE_SUBSTR)
         log_printf (" '%s'", desc[n].u.name);
     }
 }
 
 
 /*
  * Search through all keydb resources, starting at the current
  * position, for a keyblock which contains one of the keys described
  * in the DESC array.  Returns GPG_ERR_NOT_FOUND if no matching
  * keyring was found.
  */
 gpg_error_t
 keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
               size_t ndesc, size_t *descindex)
 {
   gpg_error_t rc;
 
   if (descindex)
     *descindex = 0; /* Make sure it is always set on return.  */
 
   if (!hd)
     return gpg_error (GPG_ERR_INV_ARG);
 
   if (DBG_CLOCK)
     log_clock ("keydb_search enter");
 
   if (DBG_CACHE)
     dump_search_desc (hd, "keydb_search", desc, ndesc);
 
   /* NB: If one of the exact search modes below is used in a loop to
      walk over all keys (with the same fingerprint) the caching must
      have been disabled for the handle.  */
   if (!hd->no_caching
       && ndesc == 1
       && (desc[0].mode == KEYDB_SEARCH_MODE_FPR20
           || desc[0].mode == KEYDB_SEARCH_MODE_FPR)
       && keyblock_cache.state  == KEYBLOCK_CACHE_FILLED
       && !memcmp (keyblock_cache.fpr, desc[0].u.fpr, 20))
     {
       /* (DESCINDEX is already set).  */
       if (DBG_CLOCK)
         log_clock ("keydb_search leave (cached)");
       return 0;
     }
 
   rc = -1;
   while ((rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF)
          && hd->current >= 0 && hd->current < hd->used)
     {
       switch (hd->active[hd->current].type)
         {
         case KEYDB_RESOURCE_TYPE_NONE:
           BUG(); /* we should never see it here */
           break;
         case KEYDB_RESOURCE_TYPE_KEYRING:
           rc = keyring_search (hd->active[hd->current].u.kr, desc,
                                ndesc, descindex);
           break;
         case KEYDB_RESOURCE_TYPE_KEYBOX:
           rc = keybox_search (hd->active[hd->current].u.kb, desc,
                               ndesc, KEYBOX_BLOBTYPE_PGP,
                               descindex, &hd->skipped_long_blobs);
           break;
         }
       if (rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF)
         {
           /* EOF -> switch to next resource */
           hd->current++;
         }
       else if (!rc)
         hd->found = hd->current;
     }
 
   rc = ((rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF)
         ? gpg_error (GPG_ERR_NOT_FOUND)
         : rc);
 
   keyblock_cache_clear ();
   if (!hd->no_caching
       && !rc
       && ndesc == 1 && (desc[0].mode == KEYDB_SEARCH_MODE_FPR20
                         || desc[0].mode == KEYDB_SEARCH_MODE_FPR))
     {
       keyblock_cache.state = KEYBLOCK_CACHE_PREPARED;
       memcpy (keyblock_cache.fpr, desc[0].u.fpr, 20);
     }
 
   if (DBG_CLOCK)
     log_clock (rc? "keydb_search leave (not found)"
                  : "keydb_search leave (found)");
   return rc;
 }
 
 
+/* Note that in contrast to using keydb_search in search first mode,
+   this function skips legacy keys.  */
 gpg_error_t
 keydb_search_first (KEYDB_HANDLE hd)
 {
+  gpg_error_t err;
   KEYDB_SEARCH_DESC desc;
 
   memset (&desc, 0, sizeof desc);
   desc.mode = KEYDB_SEARCH_MODE_FIRST;
-  return keydb_search (hd, &desc, 1, NULL);
+  err = keydb_search (hd, &desc, 1, NULL);
+  if (gpg_err_code (err) == GPG_ERR_LEGACY_KEY)
+    err = keydb_search_next (hd);
+  return err;
 }
 
+
+/* Note that in contrast to using keydb_search in search next mode,
+   this fucntion skips legacy keys.  */
 gpg_error_t
 keydb_search_next (KEYDB_HANDLE hd)
 {
+  gpg_error_t err;
   KEYDB_SEARCH_DESC desc;
 
-  memset (&desc, 0, sizeof desc);
-  desc.mode = KEYDB_SEARCH_MODE_NEXT;
-  return keydb_search (hd, &desc, 1, NULL);
+  do
+    {
+      memset (&desc, 0, sizeof desc);
+      desc.mode = KEYDB_SEARCH_MODE_NEXT;
+      err = keydb_search (hd, &desc, 1, NULL);
+    }
+  while (gpg_err_code (err) == GPG_ERR_LEGACY_KEY);
+
+  return err;
 }
 
 gpg_error_t
 keydb_search_kid (KEYDB_HANDLE hd, u32 *kid)
 {
   KEYDB_SEARCH_DESC desc;
 
   memset (&desc, 0, sizeof desc);
   desc.mode = KEYDB_SEARCH_MODE_LONG_KID;
   desc.u.kid[0] = kid[0];
   desc.u.kid[1] = kid[1];
   return keydb_search (hd, &desc, 1, NULL);
 }
 
 gpg_error_t
 keydb_search_fpr (KEYDB_HANDLE hd, const byte *fpr)
 {
   KEYDB_SEARCH_DESC desc;
 
   memset (&desc, 0, sizeof desc);
   desc.mode = KEYDB_SEARCH_MODE_FPR;
   memcpy (desc.u.fpr, fpr, MAX_FINGERPRINT_LEN);
   return keydb_search (hd, &desc, 1, NULL);
 }
diff --git a/g10/keylist.c b/g10/keylist.c
index daabc7dba..5fd9eb87e 100644
--- a/g10/keylist.c
+++ b/g10/keylist.c
@@ -1,1734 +1,1736 @@
 /* keylist.c - Print information about OpenPGP keys
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
  *               2008, 2010, 2012 Free Software Foundation, Inc.
  * Copyright (C) 2013, 2014  Werner Koch
  *
  * This file is part of GnuPG.
  *
  * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
 #include <assert.h>
 #ifdef HAVE_DOSISH_SYSTEM
 #include <fcntl.h>		/* for setmode() */
 #endif
 
 #include "gpg.h"
 #include "options.h"
 #include "packet.h"
 #include "status.h"
 #include "keydb.h"
 #include "photoid.h"
 #include "util.h"
 #include "ttyio.h"
 #include "trustdb.h"
 #include "main.h"
 #include "i18n.h"
 #include "status.h"
 #include "call-agent.h"
 
 static void list_all (int, int);
 static void list_one (strlist_t names, int secret, int mark_secret);
 static void locate_one (ctrl_t ctrl, strlist_t names);
 static void print_card_serialno (const char *serialno);
 
 struct sig_stats
 {
   int inv_sigs;
   int no_key;
   int oth_err;
 };
 
 /* The stream used to write attribute packets to.  */
 static estream_t attrib_fp;
 
 
 /* List the keys.  If list is NULL, all available keys are listed.
    With LOCATE_MODE set the locate algorithm is used to find a
    key.  */
 void
 public_key_list (ctrl_t ctrl, strlist_t list, int locate_mode)
 {
 #ifndef NO_TRUST_MODELS
   if (opt.with_colons)
     {
       byte trust_model, marginals, completes, cert_depth, min_cert_level;
       ulong created, nextcheck;
 
       read_trust_options (&trust_model, &created, &nextcheck,
 			  &marginals, &completes, &cert_depth, &min_cert_level);
 
       es_fprintf (es_stdout, "tru:");
 
       if (nextcheck && nextcheck <= make_timestamp ())
 	es_fprintf (es_stdout, "o");
       if (trust_model != opt.trust_model)
 	es_fprintf (es_stdout, "t");
       if (opt.trust_model == TM_PGP || opt.trust_model == TM_CLASSIC)
 	{
 	  if (marginals != opt.marginals_needed)
 	    es_fprintf (es_stdout, "m");
 	  if (completes != opt.completes_needed)
 	    es_fprintf (es_stdout, "c");
 	  if (cert_depth != opt.max_cert_depth)
 	    es_fprintf (es_stdout, "d");
 	  if (min_cert_level != opt.min_cert_level)
 	    es_fprintf (es_stdout, "l");
 	}
 
       es_fprintf (es_stdout, ":%d:%lu:%lu", trust_model, created, nextcheck);
 
       /* Only show marginals, completes, and cert_depth in the classic
          or PGP trust models since they are not meaningful
          otherwise. */
 
       if (trust_model == TM_PGP || trust_model == TM_CLASSIC)
 	es_fprintf (es_stdout, ":%d:%d:%d", marginals, completes, cert_depth);
       es_fprintf (es_stdout, "\n");
     }
 #endif /*!NO_TRUST_MODELS*/
 
   /* We need to do the stale check right here because it might need to
      update the keyring while we already have the keyring open.  This
      is very bad for W32 because of a sharing violation. For real OSes
      it might lead to false results if we are later listing a keyring
      which is associated with the inode of a deleted file.  */
   check_trustdb_stale ();
 
   if (locate_mode)
     locate_one (ctrl, list);
   else if (!list)
     list_all (0, opt.with_secret);
   else
     list_one (list, 0, opt.with_secret);
 }
 
 
 void
 secret_key_list (ctrl_t ctrl, strlist_t list)
 {
   (void)ctrl;
 
   check_trustdb_stale ();
 
   if (!list)
     list_all (1, 0);
   else				/* List by user id */
     list_one (list, 1, 0);
 }
 
 void
 print_seckey_info (PKT_public_key *pk)
 {
   u32 keyid[2];
   char *p;
   char pkstrbuf[PUBKEY_STRING_SIZE];
 
   keyid_from_pk (pk, keyid);
   p = get_user_id_native (keyid);
 
   tty_printf ("\nsec  %s/%s %s %s\n",
               pubkey_string (pk, pkstrbuf, sizeof pkstrbuf),
 	      keystr (keyid), datestr_from_pk (pk), p);
 
   xfree (p);
 }
 
 /* Print information about the public key.  With FP passed as NULL,
    the tty output interface is used, otherwise output is directted to
    the given stream.  */
 void
 print_pubkey_info (estream_t fp, PKT_public_key * pk)
 {
   u32 keyid[2];
   char *p;
   char pkstrbuf[PUBKEY_STRING_SIZE];
 
   keyid_from_pk (pk, keyid);
 
   /* If the pk was chosen by a particular user ID, that is the one to
      print.  */
   if (pk->user_id)
     p = utf8_to_native (pk->user_id->name, pk->user_id->len, 0);
   else
     p = get_user_id_native (keyid);
 
   if (fp)
     tty_printf ("\n");
   tty_fprintf (fp, "pub  %s/%s %s %s\n",
                pubkey_string (pk, pkstrbuf, sizeof pkstrbuf),
                keystr (keyid), datestr_from_pk (pk), p);
   xfree (p);
 }
 
 
 /* Print basic information of a secret key including the card serial
    number information.  */
 #ifdef ENABLE_CARD_SUPPORT
 void
 print_card_key_info (estream_t fp, kbnode_t keyblock)
 {
   kbnode_t node;
   char *hexgrip;
   char *serialno;
   int s2k_char;
   char pkstrbuf[PUBKEY_STRING_SIZE];
 
   for (node = keyblock; node; node = node->next)
     {
       if (node->pkt->pkttype == PKT_PUBLIC_KEY
           || node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
         {
           int rc;
           PKT_public_key *pk = node->pkt->pkt.public_key;
 
           serialno = NULL;
           rc = hexkeygrip_from_pk (pk, &hexgrip);
           if (rc)
             {
               log_error ("error computing a keygrip: %s\n", gpg_strerror (rc));
               s2k_char = '?';
             }
           else if (!agent_get_keyinfo (NULL, hexgrip, &serialno))
             s2k_char = serialno? '>':' ';
           else
             s2k_char = '#';  /* Key not found.  */
 
           tty_fprintf (fp, "%s%c  %s/%s  ",
                        node->pkt->pkttype == PKT_PUBLIC_KEY ? "sec" : "ssb",
                        s2k_char,
                        pubkey_string (pk, pkstrbuf, sizeof pkstrbuf),
                        keystr_from_pk (pk));
           tty_fprintf (fp, _("created: %s"), datestr_from_pk (pk));
           tty_fprintf (fp, "  ");
           tty_fprintf (fp, _("expires: %s"), expirestr_from_pk (pk));
           if (serialno)
             {
               tty_fprintf (fp, "\n                      ");
               tty_fprintf (fp, _("card-no: "));
               if (strlen (serialno) == 32
                   && !strncmp (serialno, "D27600012401", 12))
                 {
                   /* This is an OpenPGP card.  Print the relevant part.  */
                   /* Example: D2760001240101010001000003470000 */
                   /*                          xxxxyyyyyyyy     */
                   tty_fprintf (fp, "%.*s %.*s", 4, serialno+16, 8, serialno+20);
                 }
               else
                 tty_fprintf (fp, "%s", serialno);
             }
           tty_fprintf (fp, "\n");
           xfree (hexgrip);
           xfree (serialno);
         }
     }
 }
 #endif /*ENABLE_CARD_SUPPORT*/
 
 
 /* Flags = 0x01 hashed 0x02 critical.  */
 static void
 status_one_subpacket (sigsubpkttype_t type, size_t len, int flags,
 		      const byte * buf)
 {
   char status[40];
 
   /* Don't print these. */
   if (len > 256)
     return;
 
   snprintf (status, sizeof status,
             "%d %u %u ", type, flags, (unsigned int) len);
 
   write_status_text_and_buffer (STATUS_SIG_SUBPACKET, status, buf, len, 0);
 }
 
 
 /* Print a policy URL.  Allowed values for MODE are:
  *   0 - print to stdout.
  *   1 - use log_info and emit status messages.
  *   2 - emit only status messages.
  */
 void
 show_policy_url (PKT_signature * sig, int indent, int mode)
 {
   const byte *p;
   size_t len;
   int seq = 0, crit;
   estream_t fp = mode ? log_get_stream () : es_stdout;
 
   while ((p =
 	  enum_sig_subpkt (sig->hashed, SIGSUBPKT_POLICY, &len, &seq, &crit)))
     {
       if (mode != 2)
 	{
 	  int i;
 	  const char *str;
 
 	  for (i = 0; i < indent; i++)
 	    es_putc (' ', fp);
 
 	  if (crit)
 	    str = _("Critical signature policy: ");
 	  else
 	    str = _("Signature policy: ");
 	  if (mode)
 	    log_info ("%s", str);
 	  else
 	    es_fprintf (fp, "%s", str);
 	  print_utf8_buffer (fp, p, len);
 	  es_fprintf (fp, "\n");
 	}
 
       if (mode)
 	write_status_buffer (STATUS_POLICY_URL, p, len, 0);
     }
 }
 
 
 /*
   mode=0 for stdout.
   mode=1 for log_info + status messages
   mode=2 for status messages only
 */
 /* TODO: use this */
 void
 show_keyserver_url (PKT_signature * sig, int indent, int mode)
 {
   const byte *p;
   size_t len;
   int seq = 0, crit;
   estream_t fp = mode ? log_get_stream () : es_stdout;
 
   while ((p =
 	  enum_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_KS, &len, &seq,
 			   &crit)))
     {
       if (mode != 2)
 	{
 	  int i;
 	  const char *str;
 
 	  for (i = 0; i < indent; i++)
 	    es_putc (' ', es_stdout);
 
 	  if (crit)
 	    str = _("Critical preferred keyserver: ");
 	  else
 	    str = _("Preferred keyserver: ");
 	  if (mode)
 	    log_info ("%s", str);
 	  else
 	    es_fprintf (es_stdout, "%s", str);
 	  print_utf8_buffer (fp, p, len);
 	  es_fprintf (fp, "\n");
 	}
 
       if (mode)
 	status_one_subpacket (SIGSUBPKT_PREF_KS, len,
 			      (crit ? 0x02 : 0) | 0x01, p);
     }
 }
 
 /*
   mode=0 for stdout.
   mode=1 for log_info + status messages
   mode=2 for status messages only
 
   Defined bits in WHICH:
     1 == standard notations
     2 == user notations
 */
 void
 show_notation (PKT_signature * sig, int indent, int mode, int which)
 {
   estream_t fp = mode ? log_get_stream () : es_stdout;
   struct notation *nd, *notations;
 
   if (which == 0)
     which = 3;
 
   notations = sig_to_notation (sig);
 
   /* There may be multiple notations in the same sig. */
   for (nd = notations; nd; nd = nd->next)
     {
       if (mode != 2)
 	{
 	  int has_at = !!strchr (nd->name, '@');
 
 	  if ((which & 1 && !has_at) || (which & 2 && has_at))
 	    {
 	      int i;
 	      const char *str;
 
 	      for (i = 0; i < indent; i++)
 		es_putc (' ', es_stdout);
 
 	      if (nd->flags.critical)
 		str = _("Critical signature notation: ");
 	      else
 		str = _("Signature notation: ");
 	      if (mode)
 		log_info ("%s", str);
 	      else
 		es_fprintf (es_stdout, "%s", str);
 	      /* This is all UTF8 */
 	      print_utf8_buffer (fp, nd->name, strlen (nd->name));
 	      es_fprintf (fp, "=");
 	      print_utf8_buffer (fp, nd->value, strlen (nd->value));
               /* (We need to use log_printf so that the next call to a
                   log function does not insert an extra LF.)  */
               if (mode)
                 log_printf ("\n");
               else
                 es_putc ('\n', fp);
 	    }
 	}
 
       if (mode)
 	{
 	  write_status_buffer (STATUS_NOTATION_NAME,
 			       nd->name, strlen (nd->name), 0);
 	  write_status_buffer (STATUS_NOTATION_DATA,
 			       nd->value, strlen (nd->value), 50);
 	}
     }
 
   free_notation (notations);
 }
 
 static void
 print_signature_stats (struct sig_stats *s)
 {
   if (s->inv_sigs == 1)
     tty_printf (_("1 bad signature\n"));
   else if (s->inv_sigs)
     tty_printf (_("%d bad signatures\n"), s->inv_sigs);
   if (s->no_key == 1)
     tty_printf (_("1 signature not checked due to a missing key\n"));
   else if (s->no_key)
     tty_printf (_("%d signatures not checked due to missing keys\n"),
 		s->no_key);
   if (s->oth_err == 1)
     tty_printf (_("1 signature not checked due to an error\n"));
   else if (s->oth_err)
     tty_printf (_("%d signatures not checked due to errors\n"), s->oth_err);
 }
 
 
 /* List all keys.  If SECRET is true only secret keys are listed.  If
    MARK_SECRET is true secret keys are indicated in a public key
    listing.  */
 static void
 list_all (int secret, int mark_secret)
 {
   KEYDB_HANDLE hd;
   KBNODE keyblock = NULL;
   int rc = 0;
   int any_secret;
   const char *lastresname, *resname;
   struct sig_stats stats;
 
   memset (&stats, 0, sizeof (stats));
 
   hd = keydb_new ();
   if (!hd)
     rc = gpg_error (GPG_ERR_GENERAL);
   else
     rc = keydb_search_first (hd);
   if (rc)
     {
       if (gpg_err_code (rc) != GPG_ERR_NOT_FOUND)
 	log_error ("keydb_search_first failed: %s\n", gpg_strerror (rc));
       goto leave;
     }
 
   lastresname = NULL;
   do
     {
       rc = keydb_get_keyblock (hd, &keyblock);
       if (rc)
 	{
+          if (gpg_err_code (rc) == GPG_ERR_LEGACY_KEY)
+            continue;  /* Skip legacy keys.  */
 	  log_error ("keydb_get_keyblock failed: %s\n", gpg_strerror (rc));
 	  goto leave;
 	}
 
       if (secret || mark_secret)
         any_secret = !agent_probe_any_secret_key (NULL, keyblock);
       else
         any_secret = 0;
 
       if (secret && !any_secret)
         ; /* Secret key listing requested but this isn't one.  */
       else
         {
           if (!opt.with_colons)
             {
               resname = keydb_get_resource_name (hd);
               if (lastresname != resname)
                 {
                   int i;
 
                   es_fprintf (es_stdout, "%s\n", resname);
                   for (i = strlen (resname); i; i--)
                     es_putc ('-', es_stdout);
                   es_putc ('\n', es_stdout);
                   lastresname = resname;
                 }
             }
           merge_keys_and_selfsig (keyblock);
           list_keyblock (keyblock, secret, any_secret, opt.fingerprint,
                          opt.check_sigs ? &stats : NULL);
         }
       release_kbnode (keyblock);
       keyblock = NULL;
     }
   while (!(rc = keydb_search_next (hd)));
   es_fflush (es_stdout);
   if (rc && gpg_err_code (rc) != GPG_ERR_NOT_FOUND)
     log_error ("keydb_search_next failed: %s\n", gpg_strerror (rc));
   if (keydb_get_skipped_counter (hd))
     log_info (_("Warning: %lu key(s) skipped due to their large size\n"),
               keydb_get_skipped_counter (hd));
 
   if (opt.check_sigs && !opt.with_colons)
     print_signature_stats (&stats);
 
 leave:
   release_kbnode (keyblock);
   keydb_release (hd);
 }
 
 
 static void
 list_one (strlist_t names, int secret, int mark_secret)
 {
   int rc = 0;
   KBNODE keyblock = NULL;
   GETKEY_CTX ctx;
   const char *resname;
   const char *keyring_str = _("Keyring");
   int i;
   struct sig_stats stats;
 
   memset (&stats, 0, sizeof (stats));
 
   /* fixme: using the bynames function has the disadvantage that we
    * don't know wether one of the names given was not found.  OTOH,
    * this function has the advantage to list the names in the
    * sequence as defined by the keyDB and does not duplicate
    * outputs.  A solution could be do test whether all given have
    * been listed (this needs a way to use the keyDB search
    * functions) or to have the search function return indicators for
    * found names.  Yet another way is to use the keydb search
    * facilities directly. */
   rc = getkey_bynames (&ctx, NULL, names, secret, &keyblock);
   if (rc)
     {
       log_error ("error reading key: %s\n", gpg_strerror (rc));
       get_pubkey_end (ctx);
       return;
     }
 
   do
     {
       if ((opt.list_options & LIST_SHOW_KEYRING) && !opt.with_colons)
         {
           resname = keydb_get_resource_name (get_ctx_handle (ctx));
           es_fprintf (es_stdout, "%s: %s\n", keyring_str, resname);
           for (i = strlen (resname) + strlen (keyring_str) + 2; i; i--)
             es_putc ('-', es_stdout);
           es_putc ('\n', es_stdout);
         }
       list_keyblock (keyblock, secret, mark_secret, opt.fingerprint,
                      (!secret && opt.check_sigs)? &stats : NULL);
       release_kbnode (keyblock);
     }
   while (!getkey_next (ctx, NULL, &keyblock));
   getkey_end (ctx);
 
   if (opt.check_sigs && !opt.with_colons)
     print_signature_stats (&stats);
 }
 
 
 static void
 locate_one (ctrl_t ctrl, strlist_t names)
 {
   int rc = 0;
   strlist_t sl;
   GETKEY_CTX ctx = NULL;
   KBNODE keyblock = NULL;
   struct sig_stats stats;
 
   memset (&stats, 0, sizeof (stats));
 
   for (sl = names; sl; sl = sl->next)
     {
       rc = get_pubkey_byname (ctrl, &ctx, NULL, sl->d, &keyblock, NULL, 1, 0);
       if (rc)
 	{
 	  if (gpg_err_code (rc) != GPG_ERR_NO_PUBKEY)
 	    log_error ("error reading key: %s\n", gpg_strerror (rc));
 	}
       else
 	{
 	  do
 	    {
 	      list_keyblock (keyblock, 0, 0, opt.fingerprint,
 			     opt.check_sigs ? &stats : NULL);
 	      release_kbnode (keyblock);
 	    }
 	  while (ctx && !get_pubkey_next (ctx, NULL, &keyblock));
 	  get_pubkey_end (ctx);
 	  ctx = NULL;
 	}
     }
 
   if (opt.check_sigs && !opt.with_colons)
     print_signature_stats (&stats);
 }
 
 
 static void
 print_key_data (PKT_public_key * pk)
 {
   int n = pk ? pubkey_get_npkey (pk->pubkey_algo) : 0;
   int i;
 
   for (i = 0; i < n; i++)
     {
       es_fprintf (es_stdout, "pkd:%d:%u:", i, mpi_get_nbits (pk->pkey[i]));
       mpi_print (es_stdout, pk->pkey[i], 1);
       es_putc (':', es_stdout);
       es_putc ('\n', es_stdout);
     }
 }
 
 static void
 print_capabilities (PKT_public_key *pk, KBNODE keyblock)
 {
   unsigned int use = pk->pubkey_usage;
   int c_printed = 0;
 
   if (use & PUBKEY_USAGE_ENC)
     es_putc ('e', es_stdout);
 
   if (use & PUBKEY_USAGE_SIG)
     {
       es_putc ('s', es_stdout);
       if (pk->flags.primary)
         {
           es_putc ('c', es_stdout);
           /* The PUBKEY_USAGE_CERT flag was introduced later and we
              used to always print 'c' for a primary key.  To avoid any
              regression here we better track whether we printed 'c'
              already.  */
           c_printed = 1;
         }
     }
 
   if ((use & PUBKEY_USAGE_CERT) && !c_printed)
     es_putc ('c', es_stdout);
 
   if ((use & PUBKEY_USAGE_AUTH))
     es_putc ('a', es_stdout);
 
   if ((use & PUBKEY_USAGE_UNKNOWN))
     es_putc ('?', es_stdout);
 
   if (keyblock)
     {
       /* Figure out the usable capabilities.  */
       KBNODE k;
       int enc = 0, sign = 0, cert = 0, auth = 0, disabled = 0;
 
       for (k = keyblock; k; k = k->next)
 	{
 	  if (k->pkt->pkttype == PKT_PUBLIC_KEY
 	      || k->pkt->pkttype == PKT_PUBLIC_SUBKEY)
 	    {
 	      pk = k->pkt->pkt.public_key;
 
 	      if (pk->flags.primary)
 		disabled = pk_is_disabled (pk);
 
 	      if (pk->flags.valid && !pk->flags.revoked && !pk->has_expired)
 		{
 		  if (pk->pubkey_usage & PUBKEY_USAGE_ENC)
 		    enc = 1;
 		  if (pk->pubkey_usage & PUBKEY_USAGE_SIG)
 		    {
 		      sign = 1;
 		      if (pk->flags.primary)
 			cert = 1;
 		    }
 		  if (pk->pubkey_usage & PUBKEY_USAGE_CERT)
 		    cert = 1;
 		  if ((pk->pubkey_usage & PUBKEY_USAGE_AUTH))
 		    auth = 1;
 		}
 	    }
 	}
       if (enc)
 	es_putc ('E', es_stdout);
       if (sign)
 	es_putc ('S', es_stdout);
       if (cert)
 	es_putc ('C', es_stdout);
       if (auth)
 	es_putc ('A', es_stdout);
       if (disabled)
 	es_putc ('D', es_stdout);
     }
 
   es_putc (':', es_stdout);
 }
 
 
 /* FLAGS: 0x01 hashed
           0x02 critical  */
 static void
 print_one_subpacket (sigsubpkttype_t type, size_t len, int flags,
 		     const byte * buf)
 {
   size_t i;
 
   es_fprintf (es_stdout, "spk:%d:%u:%u:", type, flags, (unsigned int) len);
 
   for (i = 0; i < len; i++)
     {
       /* printable ascii other than : and % */
       if (buf[i] >= 32 && buf[i] <= 126 && buf[i] != ':' && buf[i] != '%')
 	es_fprintf (es_stdout, "%c", buf[i]);
       else
 	es_fprintf (es_stdout, "%%%02X", buf[i]);
     }
 
   es_fprintf (es_stdout, "\n");
 }
 
 
 void
 print_subpackets_colon (PKT_signature * sig)
 {
   byte *i;
 
   assert (opt.show_subpackets);
 
   for (i = opt.show_subpackets; *i; i++)
     {
       const byte *p;
       size_t len;
       int seq, crit;
 
       seq = 0;
 
       while ((p = enum_sig_subpkt (sig->hashed, *i, &len, &seq, &crit)))
 	print_one_subpacket (*i, len, 0x01 | (crit ? 0x02 : 0), p);
 
       seq = 0;
 
       while ((p = enum_sig_subpkt (sig->unhashed, *i, &len, &seq, &crit)))
 	print_one_subpacket (*i, len, 0x00 | (crit ? 0x02 : 0), p);
     }
 }
 
 
 void
 dump_attribs (const PKT_user_id *uid, PKT_public_key *pk)
 {
   int i;
 
   if (!attrib_fp)
     return;
 
   for (i = 0; i < uid->numattribs; i++)
     {
       if (is_status_enabled ())
 	{
 	  byte array[MAX_FINGERPRINT_LEN], *p;
 	  char buf[(MAX_FINGERPRINT_LEN * 2) + 90];
 	  size_t j, n;
 
           if (!pk)
             BUG ();
           fingerprint_from_pk (pk, array, &n);
 
 	  p = array;
 	  for (j = 0; j < n; j++, p++)
 	    sprintf (buf + 2 * j, "%02X", *p);
 
 	  sprintf (buf + strlen (buf), " %lu %u %u %u %lu %lu %u",
 		   (ulong) uid->attribs[i].len, uid->attribs[i].type, i + 1,
 		   uid->numattribs, (ulong) uid->created,
 		   (ulong) uid->expiredate,
 		   ((uid->is_primary ? 0x01 : 0) | (uid->
 						    is_revoked ? 0x02 : 0) |
 		    (uid->is_expired ? 0x04 : 0)));
 	  write_status_text (STATUS_ATTRIBUTE, buf);
 	}
 
       es_fwrite (uid->attribs[i].data, uid->attribs[i].len, 1, attrib_fp);
       es_fflush (attrib_fp);
     }
 }
 
 
 static void
 list_keyblock_print (KBNODE keyblock, int secret, int fpr, void *opaque)
 {
   int rc;
   KBNODE kbctx;
   KBNODE node;
   PKT_public_key *pk;
   struct sig_stats *stats = opaque;
   int skip_sigs = 0;
   int s2k_char;
   char *hexgrip = NULL;
   char *serialno = NULL;
   char pkstrbuf[PUBKEY_STRING_SIZE];
 
   /* Get the keyid from the keyblock.  */
   node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
   if (!node)
     {
       log_error ("Oops; key lost!\n");
       dump_kbnode (keyblock);
       return;
     }
 
   pk = node->pkt->pkt.public_key;
 
   if (secret || opt.with_keygrip)
     {
       rc = hexkeygrip_from_pk (pk, &hexgrip);
       if (rc)
         log_error ("error computing a keygrip: %s\n", gpg_strerror (rc));
     }
 
   if (secret)
     {
       if (!agent_get_keyinfo (NULL, hexgrip, &serialno))
         s2k_char = serialno? '>':' ';
       else
         s2k_char = '#';  /* Key not found.  */
     }
   else
     s2k_char = ' ';
 
   check_trustdb_stale ();
 
 
   es_fprintf (es_stdout, "%s%c  %s/%s %s",
               secret? "sec":"pub",
               s2k_char,
               pubkey_string (pk, pkstrbuf, sizeof pkstrbuf),
               keystr_from_pk (pk), datestr_from_pk (pk));
 
   if ((opt.list_options & LIST_SHOW_USAGE))
     {
       es_fprintf (es_stdout, " [%s]", usagestr_from_pk (pk, 0));
     }
   if (pk->flags.revoked)
     {
       es_fprintf (es_stdout, " [");
       es_fprintf (es_stdout, _("revoked: %s"), revokestr_from_pk (pk));
       es_fprintf (es_stdout, "]");
     }
   else if (pk->has_expired)
     {
       es_fprintf (es_stdout, " [");
       es_fprintf (es_stdout, _("expired: %s"), expirestr_from_pk (pk));
       es_fprintf (es_stdout, "]");
     }
   else if (pk->expiredate)
     {
       es_fprintf (es_stdout, " [");
       es_fprintf (es_stdout, _("expires: %s"), expirestr_from_pk (pk));
       es_fprintf (es_stdout, "]");
     }
 
 #if 0
   /* I need to think about this some more.  It's easy enough to
      include, but it looks sort of confusing in the listing... */
   if (opt.list_options & LIST_SHOW_VALIDITY)
     {
       int validity = get_validity (pk, NULL);
       es_fprintf (es_stdout, " [%s]", trust_value_to_string (validity));
     }
 #endif
 
   if (pk->pubkey_algo >= 100)
     es_fprintf (es_stdout, " [experimental algorithm %d]", pk->pubkey_algo);
 
   es_fprintf (es_stdout, "\n");
 
   if (fpr)
     print_fingerprint (NULL, pk, 0);
 
   if (opt.with_keygrip && hexgrip)
     es_fprintf (es_stdout, "      Keygrip = %s\n", hexgrip);
 
   if (serialno)
     print_card_serialno (serialno);
 
   if (opt.with_key_data)
     print_key_data (pk);
 
   for (kbctx = NULL; (node = walk_kbnode (keyblock, &kbctx, 0));)
     {
       if (node->pkt->pkttype == PKT_USER_ID && !opt.fast_list_mode)
 	{
 	  PKT_user_id *uid = node->pkt->pkt.user_id;
 
 	  if (pk && (uid->is_expired || uid->is_revoked)
 	      && !(opt.list_options & LIST_SHOW_UNUSABLE_UIDS))
 	    {
 	      skip_sigs = 1;
 	      continue;
 	    }
 	  else
 	    skip_sigs = 0;
 
 	  if (attrib_fp && uid->attrib_data != NULL)
 	    dump_attribs (uid, pk);
 
 	  if ((uid->is_revoked || uid->is_expired)
 	      || ((opt.list_options & LIST_SHOW_UID_VALIDITY) && pk))
 	    {
 	      const char *validity;
 	      int indent;
 
 	      validity = uid_trust_string_fixed (pk, uid);
 	      indent =
 		(keystrlen () + 9) -
 		atoi (uid_trust_string_fixed (NULL, NULL));
 
 	      if (indent < 0 || indent > 40)
 		indent = 0;
 
 	      es_fprintf (es_stdout, "uid%*s%s ", indent, "", validity);
 	    }
 	  else
 	    es_fprintf (es_stdout, "uid%*s", (int) keystrlen () + 10, "");
 
 	  print_utf8_buffer (es_stdout, uid->name, uid->len);
 	  es_putc ('\n', es_stdout);
 
 	  if ((opt.list_options & LIST_SHOW_PHOTOS) && uid->attribs != NULL)
 	    show_photos (uid->attribs, uid->numattribs, pk, uid);
 	}
       else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
 	{
 	  PKT_public_key *pk2 = node->pkt->pkt.public_key;
 
 	  if ((pk2->flags.revoked || pk2->has_expired)
 	      && !(opt.list_options & LIST_SHOW_UNUSABLE_SUBKEYS))
 	    {
 	      skip_sigs = 1;
 	      continue;
 	    }
 	  else
 	    skip_sigs = 0;
 
           xfree (serialno); serialno = NULL;
           xfree (hexgrip); hexgrip = NULL;
           if (secret || opt.with_keygrip)
             {
               rc = hexkeygrip_from_pk (pk2, &hexgrip);
               if (rc)
                 log_error ("error computing a keygrip: %s\n",
                            gpg_strerror (rc));
             }
           if (secret)
             {
               if (!agent_get_keyinfo (NULL, hexgrip, &serialno))
                 s2k_char = serialno? '>':' ';
               else
                 s2k_char = '#';  /* Key not found.  */
             }
           else
             s2k_char = ' ';
 
 	  es_fprintf (es_stdout, "%s%c  %s/%s %s",
                   secret? "ssb":"sub",
                   s2k_char,
                   pubkey_string (pk2, pkstrbuf, sizeof pkstrbuf),
 		  keystr_from_pk (pk2), datestr_from_pk (pk2));
 
           if (pk2->pubkey_algo == PUBKEY_ALGO_ECDSA
               || pk2->pubkey_algo == PUBKEY_ALGO_EDDSA
               || pk2->pubkey_algo == PUBKEY_ALGO_ECDH)
             {
               char *curve = openpgp_oid_to_str (pk2->pkey[0]);
               const char *name = openpgp_oid_to_curve (curve);
               if (!*name || *name == '?')
                 name = curve;
               es_fprintf (es_stdout, " %s", name);
               xfree (curve);
             }
 
           if ((opt.list_options & LIST_SHOW_USAGE))
             {
               es_fprintf (es_stdout, " [%s]", usagestr_from_pk (pk2, 0));
             }
 	  if (pk2->flags.revoked)
 	    {
 	      es_fprintf (es_stdout, " [");
 	      es_fprintf (es_stdout, _("revoked: %s"), revokestr_from_pk (pk2));
 	      es_fprintf (es_stdout, "]");
 	    }
 	  else if (pk2->has_expired)
 	    {
 	      es_fprintf (es_stdout, " [");
 	      es_fprintf (es_stdout, _("expired: %s"), expirestr_from_pk (pk2));
 	      es_fprintf (es_stdout, "]");
 	    }
 	  else if (pk2->expiredate)
 	    {
 	      es_fprintf (es_stdout, " [");
 	      es_fprintf (es_stdout, _("expires: %s"), expirestr_from_pk (pk2));
 	      es_fprintf (es_stdout, "]");
 	    }
 	  es_putc ('\n', es_stdout);
 	  if (fpr > 1)
             {
               print_fingerprint (NULL, pk2, 0);
               if (serialno)
                 print_card_serialno (serialno);
             }
           if (opt.with_keygrip && hexgrip)
             es_fprintf (es_stdout, "      Keygrip = %s\n", hexgrip);
 	  if (opt.with_key_data)
 	    print_key_data (pk2);
 	}
       else if (opt.list_sigs
 	       && node->pkt->pkttype == PKT_SIGNATURE && !skip_sigs)
 	{
 	  PKT_signature *sig = node->pkt->pkt.signature;
 	  int sigrc;
 	  char *sigstr;
 
 	  if (stats)
 	    {
 	      rc = check_key_signature (keyblock, node, NULL);
 	      switch (gpg_err_code (rc))
 		{
 		case 0:
 		  sigrc = '!';
 		  break;
 		case GPG_ERR_BAD_SIGNATURE:
 		  stats->inv_sigs++;
 		  sigrc = '-';
 		  break;
 		case GPG_ERR_NO_PUBKEY:
 		case GPG_ERR_UNUSABLE_PUBKEY:
 		  stats->no_key++;
 		  continue;
 		default:
 		  stats->oth_err++;
 		  sigrc = '%';
 		  break;
 		}
 
 	      /* TODO: Make sure a cached sig record here still has
 	         the pk that issued it.  See also
 	         keyedit.c:print_and_check_one_sig */
 	    }
 	  else
 	    {
 	      rc = 0;
 	      sigrc = ' ';
 	    }
 
 	  if (sig->sig_class == 0x20 || sig->sig_class == 0x28
 	      || sig->sig_class == 0x30)
 	    sigstr = "rev";
 	  else if ((sig->sig_class & ~3) == 0x10)
 	    sigstr = "sig";
 	  else if (sig->sig_class == 0x18)
 	    sigstr = "sig";
 	  else if (sig->sig_class == 0x1F)
 	    sigstr = "sig";
 	  else
 	    {
 	      es_fprintf (es_stdout, "sig                             "
 		      "[unexpected signature class 0x%02x]\n",
 		      sig->sig_class);
 	      continue;
 	    }
 
 	  es_fputs (sigstr, es_stdout);
 	  es_fprintf (es_stdout, "%c%c %c%c%c%c%c%c %s %s",
 		  sigrc, (sig->sig_class - 0x10 > 0 &&
 			  sig->sig_class - 0x10 <
 			  4) ? '0' + sig->sig_class - 0x10 : ' ',
 		  sig->flags.exportable ? ' ' : 'L',
 		  sig->flags.revocable ? ' ' : 'R',
 		  sig->flags.policy_url ? 'P' : ' ',
 		  sig->flags.notation ? 'N' : ' ',
 		  sig->flags.expired ? 'X' : ' ',
 		  (sig->trust_depth > 9) ? 'T' : (sig->trust_depth >
 						  0) ? '0' +
 		  sig->trust_depth : ' ', keystr (sig->keyid),
 		  datestr_from_sig (sig));
 	  if (opt.list_options & LIST_SHOW_SIG_EXPIRE)
 	    es_fprintf (es_stdout, " %s", expirestr_from_sig (sig));
 	  es_fprintf (es_stdout, "  ");
 	  if (sigrc == '%')
 	    es_fprintf (es_stdout, "[%s] ", gpg_strerror (rc));
 	  else if (sigrc == '?')
 	    ;
 	  else if (!opt.fast_list_mode)
 	    {
 	      size_t n;
 	      char *p = get_user_id (sig->keyid, &n);
 	      print_utf8_buffer (es_stdout, p, n);
 	      xfree (p);
 	    }
 	  es_putc ('\n', es_stdout);
 
 	  if (sig->flags.policy_url
 	      && (opt.list_options & LIST_SHOW_POLICY_URLS))
 	    show_policy_url (sig, 3, 0);
 
 	  if (sig->flags.notation && (opt.list_options & LIST_SHOW_NOTATIONS))
 	    show_notation (sig, 3, 0,
 			   ((opt.
 			     list_options & LIST_SHOW_STD_NOTATIONS) ? 1 : 0)
 			   +
 			   ((opt.
 			     list_options & LIST_SHOW_USER_NOTATIONS) ? 2 :
 			    0));
 
 	  if (sig->flags.pref_ks
 	      && (opt.list_options & LIST_SHOW_KEYSERVER_URLS))
 	    show_keyserver_url (sig, 3, 0);
 
 	  /* fixme: check or list other sigs here */
 	}
     }
   es_putc ('\n', es_stdout);
   xfree (serialno);
   xfree (hexgrip);
 }
 
 void
 print_revokers (estream_t fp, PKT_public_key * pk)
 {
   /* print the revoker record */
   if (!pk->revkey && pk->numrevkeys)
     BUG ();
   else
     {
       int i, j;
 
       for (i = 0; i < pk->numrevkeys; i++)
 	{
 	  byte *p;
 
 	  es_fprintf (fp, "rvk:::%d::::::", pk->revkey[i].algid);
 	  p = pk->revkey[i].fpr;
 	  for (j = 0; j < 20; j++, p++)
 	    es_fprintf (fp, "%02X", *p);
 	  es_fprintf (fp, ":%02x%s:\n",
                       pk->revkey[i].class,
                       (pk->revkey[i].class & 0x40) ? "s" : "");
 	}
     }
 }
 
 
 /* List a key in colon mode.  If SECRET is true this is a secret key
    record (i.e. requested via --list-secret-key).  If HAS_SECRET a
    secret key is available even if SECRET is not set.  */
 static void
 list_keyblock_colon (KBNODE keyblock, int secret, int has_secret, int fpr)
 {
   int rc;
   KBNODE kbctx;
   KBNODE node;
   PKT_public_key *pk;
   u32 keyid[2];
   int trustletter = 0;
   int ulti_hack = 0;
   int i;
   char *p;
   char *hexgrip = NULL;
   char *serialno = NULL;
   int stubkey;
 
   /* Get the keyid from the keyblock.  */
   node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
   if (!node)
     {
       log_error ("Oops; key lost!\n");
       dump_kbnode (keyblock);
       return;
     }
 
   pk = node->pkt->pkt.public_key;
   if (secret || has_secret || opt.with_keygrip || opt.with_key_data)
     {
       rc = hexkeygrip_from_pk (pk, &hexgrip);
       if (rc)
         log_error ("error computing a keygrip: %s\n", gpg_strerror (rc));
     }
   stubkey = 0;
   if ((secret||has_secret) && agent_get_keyinfo (NULL, hexgrip, &serialno))
     stubkey = 1;  /* Key not found.  */
 
   keyid_from_pk (pk, keyid);
   es_fputs (secret? "sec:":"pub:", es_stdout);
   if (!pk->flags.valid)
     es_putc ('i', es_stdout);
   else if (pk->flags.revoked)
     es_putc ('r', es_stdout);
   else if (pk->has_expired)
     es_putc ('e', es_stdout);
   else if (opt.fast_list_mode || opt.no_expensive_trust_checks)
     ;
   else
     {
       trustletter = get_validity_info (pk, NULL);
       if (trustletter == 'u')
         ulti_hack = 1;
       es_putc (trustletter, es_stdout);
     }
 
   es_fprintf (es_stdout, ":%u:%d:%08lX%08lX:%s:%s::",
           nbits_from_pk (pk),
           pk->pubkey_algo,
           (ulong) keyid[0], (ulong) keyid[1],
           colon_datestr_from_pk (pk), colon_strtime (pk->expiredate));
 
   if (!opt.fast_list_mode && !opt.no_expensive_trust_checks)
     es_putc (get_ownertrust_info (pk), es_stdout);
   es_putc (':', es_stdout);
 
   es_putc (':', es_stdout);
   es_putc (':', es_stdout);
   print_capabilities (pk, keyblock);
   es_putc (':', es_stdout);		/* End of field 13. */
   es_putc (':', es_stdout);		/* End of field 14. */
   if (secret || has_secret)
     {
       if (stubkey)
 	es_putc ('#', es_stdout);
       else if (serialno)
         es_fputs (serialno, es_stdout);
       else if (has_secret)
         es_putc ('+', es_stdout);
     }
   es_putc (':', es_stdout);		/* End of field 15. */
   es_putc (':', es_stdout);		/* End of field 16. */
   if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA
       || pk->pubkey_algo == PUBKEY_ALGO_EDDSA
       || pk->pubkey_algo == PUBKEY_ALGO_ECDH)
     {
       char *curve = openpgp_oid_to_str (pk->pkey[0]);
       const char *name = openpgp_oid_to_curve (curve);
       if (!*name || *name == '?')
         name = curve;
       es_fputs (name, es_stdout);
       xfree (curve);
     }
   es_putc (':', es_stdout);		/* End of field 17. */
   es_putc ('\n', es_stdout);
 
   print_revokers (es_stdout, pk);
   if (fpr)
     print_fingerprint (NULL, pk, 0);
   if (opt.with_key_data || opt.with_keygrip)
     {
       if (hexgrip)
         es_fprintf (es_stdout, "grp:::::::::%s:\n", hexgrip);
       if (opt.with_key_data)
         print_key_data (pk);
     }
 
   for (kbctx = NULL; (node = walk_kbnode (keyblock, &kbctx, 0));)
     {
       if (node->pkt->pkttype == PKT_USER_ID && !opt.fast_list_mode)
 	{
 	  char *str;
 	  PKT_user_id *uid = node->pkt->pkt.user_id;
 
 	  if (attrib_fp && node->pkt->pkt.user_id->attrib_data != NULL)
 	    dump_attribs (node->pkt->pkt.user_id, pk);
 	  /*
 	   * Fixme: We need a valid flag here too
 	   */
 	  str = uid->attrib_data ? "uat" : "uid";
 	  if (uid->is_revoked)
 	    es_fprintf (es_stdout, "%s:r::::", str);
 	  else if (uid->is_expired)
 	    es_fprintf (es_stdout, "%s:e::::", str);
 	  else if (opt.no_expensive_trust_checks)
 	    es_fprintf (es_stdout, "%s:::::", str);
 	  else
 	    {
 	      int uid_validity;
 
 	      if (pk && !ulti_hack)
 		uid_validity = get_validity_info (pk, uid);
 	      else
 		uid_validity = 'u';
 	      es_fprintf (es_stdout, "%s:%c::::", str, uid_validity);
 	    }
 
 	  es_fprintf (es_stdout, "%s:", colon_strtime (uid->created));
 	  es_fprintf (es_stdout, "%s:", colon_strtime (uid->expiredate));
 
 	  namehash_from_uid (uid);
 
 	  for (i = 0; i < 20; i++)
 	    es_fprintf (es_stdout, "%02X", uid->namehash[i]);
 
 	  es_fprintf (es_stdout, "::");
 
 	  if (uid->attrib_data)
 	    es_fprintf (es_stdout, "%u %lu", uid->numattribs, uid->attrib_len);
 	  else
 	    es_write_sanitized (es_stdout, uid->name, uid->len, ":", NULL);
 	  es_putc (':', es_stdout);
 	  es_putc ('\n', es_stdout);
 	}
       else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
 	{
 	  u32 keyid2[2];
 	  PKT_public_key *pk2;
 
           pk2 = node->pkt->pkt.public_key;
           xfree (hexgrip); hexgrip = NULL;
           xfree (serialno); serialno = NULL;
           if (secret || has_secret || opt.with_keygrip || opt.with_key_data)
             {
               rc = hexkeygrip_from_pk (pk2, &hexgrip);
               if (rc)
                 log_error ("error computing a keygrip: %s\n",
                            gpg_strerror (rc));
             }
           stubkey = 0;
           if ((secret||has_secret)
               && agent_get_keyinfo (NULL, hexgrip, &serialno))
             stubkey = 1;  /* Key not found.  */
 
 	  keyid_from_pk (pk2, keyid2);
 	  es_fputs (secret? "ssb:":"sub:", es_stdout);
 	  if (!pk2->flags.valid)
 	    es_putc ('i', es_stdout);
 	  else if (pk2->flags.revoked)
 	    es_putc ('r', es_stdout);
 	  else if (pk2->has_expired)
 	    es_putc ('e', es_stdout);
 	  else if (opt.fast_list_mode || opt.no_expensive_trust_checks)
 	    ;
 	  else
 	    {
 	      /* TRUSTLETTER should always be defined here. */
 	      if (trustletter)
 		es_fprintf (es_stdout, "%c", trustletter);
 	    }
 	  es_fprintf (es_stdout, ":%u:%d:%08lX%08lX:%s:%s:::::",
 		  nbits_from_pk (pk2),
 		  pk2->pubkey_algo,
 		  (ulong) keyid2[0], (ulong) keyid2[1],
 		  colon_datestr_from_pk (pk2), colon_strtime (pk2->expiredate)
 		  /* fixme: add LID and ownertrust here */
 	    );
 	  print_capabilities (pk2, NULL);
           es_putc (':', es_stdout);	/* End of field 13. */
           es_putc (':', es_stdout);	/* End of field 14. */
           if (secret || has_secret)
             {
               if (stubkey)
                 es_putc ('#', es_stdout);
               else if (serialno)
                 es_fputs (serialno, es_stdout);
               else if (has_secret)
                 es_putc ('+', es_stdout);
             }
           es_putc (':', es_stdout);	/* End of field 15. */
           es_putc (':', es_stdout);	/* End of field 16. */
           if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA
               || pk->pubkey_algo == PUBKEY_ALGO_EDDSA
               || pk->pubkey_algo == PUBKEY_ALGO_ECDH)
             {
               char *curve = openpgp_oid_to_str (pk->pkey[0]);
               const char *name = openpgp_oid_to_curve (curve);
               if (!*name || *name == '?')
                 name = curve;
               es_fputs (name, es_stdout);
               xfree (curve);
             }
           es_putc (':', es_stdout);	/* End of field 17. */
 	  es_putc ('\n', es_stdout);
 	  if (fpr > 1)
 	    print_fingerprint (NULL, pk2, 0);
 	  if (opt.with_key_data || opt.with_keygrip)
             {
               if (hexgrip)
                 es_fprintf (es_stdout, "grp:::::::::%s:\n", hexgrip);
               if (opt.with_key_data)
                 print_key_data (pk2);
             }
 	}
       else if (opt.list_sigs && node->pkt->pkttype == PKT_SIGNATURE)
 	{
 	  PKT_signature *sig = node->pkt->pkt.signature;
 	  int sigrc, fprokay = 0;
 	  char *sigstr;
 	  size_t fplen;
 	  byte fparray[MAX_FINGERPRINT_LEN];
 
 	  if (sig->sig_class == 0x20 || sig->sig_class == 0x28
 	      || sig->sig_class == 0x30)
 	    sigstr = "rev";
 	  else if ((sig->sig_class & ~3) == 0x10)
 	    sigstr = "sig";
 	  else if (sig->sig_class == 0x18)
 	    sigstr = "sig";
 	  else if (sig->sig_class == 0x1F)
 	    sigstr = "sig";
 	  else
 	    {
 	      es_fprintf (es_stdout, "sig::::::::::%02x%c:\n",
 		      sig->sig_class, sig->flags.exportable ? 'x' : 'l');
 	      continue;
 	    }
 
 	  if (opt.check_sigs)
 	    {
 	      PKT_public_key *signer_pk = NULL;
 
 	      fflush (stdout);
 	      if (opt.no_sig_cache)
 		signer_pk = xmalloc_clear (sizeof (PKT_public_key));
 
 	      rc = check_key_signature2 (keyblock, node, NULL, signer_pk,
 					 NULL, NULL, NULL);
 	      switch (gpg_err_code (rc))
 		{
 		case 0:
 		  sigrc = '!';
 		  break;
 		case GPG_ERR_BAD_SIGNATURE:
 		  sigrc = '-';
 		  break;
 		case GPG_ERR_NO_PUBKEY:
 		case GPG_ERR_UNUSABLE_PUBKEY:
 		  sigrc = '?';
 		  break;
 		default:
 		  sigrc = '%';
 		  break;
 		}
 
 	      if (opt.no_sig_cache)
 		{
 		  if (!rc)
 		    {
 		      fingerprint_from_pk (signer_pk, fparray, &fplen);
 		      fprokay = 1;
 		    }
 		  free_public_key (signer_pk);
 		}
 	    }
 	  else
 	    {
 	      rc = 0;
 	      sigrc = ' ';
 	    }
 	  es_fputs (sigstr, es_stdout);
 	  es_putc (':', es_stdout);
 	  if (sigrc != ' ')
 	    es_putc (sigrc, es_stdout);
 	  es_fprintf (es_stdout, "::%d:%08lX%08lX:%s:%s:", sig->pubkey_algo,
 		  (ulong) sig->keyid[0], (ulong) sig->keyid[1],
 		  colon_datestr_from_sig (sig),
 		  colon_expirestr_from_sig (sig));
 
 	  if (sig->trust_depth || sig->trust_value)
 	    es_fprintf (es_stdout, "%d %d", sig->trust_depth, sig->trust_value);
 	  es_fprintf (es_stdout, ":");
 
 	  if (sig->trust_regexp)
 	    es_write_sanitized (es_stdout, sig->trust_regexp,
                                 strlen (sig->trust_regexp), ":", NULL);
 	  es_fprintf (es_stdout, ":");
 
 	  if (sigrc == '%')
 	    es_fprintf (es_stdout, "[%s] ", gpg_strerror (rc));
 	  else if (sigrc == '?')
 	    ;
 	  else if (!opt.fast_list_mode)
 	    {
 	      size_t n;
 	      p = get_user_id (sig->keyid, &n);
 	      es_write_sanitized (es_stdout, p, n, ":", NULL);
 	      xfree (p);
 	    }
 	  es_fprintf (es_stdout, ":%02x%c::", sig->sig_class,
 		  sig->flags.exportable ? 'x' : 'l');
 
 	  if (opt.no_sig_cache && opt.check_sigs && fprokay)
 	    {
 	      for (i = 0; i < fplen; i++)
 		es_fprintf (es_stdout, "%02X", fparray[i]);
 	    }
 
 	  es_fprintf (es_stdout, ":::%d:\n", sig->digest_algo);
 
 	  if (opt.show_subpackets)
 	    print_subpackets_colon (sig);
 
 	  /* fixme: check or list other sigs here */
 	}
     }
 
   xfree (hexgrip);
   xfree (serialno);
 }
 
 /*
  * Reorder the keyblock so that the primary user ID (and not attribute
  * packet) comes first.  Fixme: Replace this by a generic sort
  * function.  */
 static void
 do_reorder_keyblock (KBNODE keyblock, int attr)
 {
   KBNODE primary = NULL, primary0 = NULL, primary2 = NULL;
   KBNODE last, node;
 
   for (node = keyblock; node; primary0 = node, node = node->next)
     {
       if (node->pkt->pkttype == PKT_USER_ID &&
 	  ((attr && node->pkt->pkt.user_id->attrib_data) ||
 	   (!attr && !node->pkt->pkt.user_id->attrib_data)) &&
 	  node->pkt->pkt.user_id->is_primary)
 	{
 	  primary = primary2 = node;
 	  for (node = node->next; node; primary2 = node, node = node->next)
 	    {
 	      if (node->pkt->pkttype == PKT_USER_ID
 		  || node->pkt->pkttype == PKT_PUBLIC_SUBKEY
 		  || node->pkt->pkttype == PKT_SECRET_SUBKEY)
 		{
 		  break;
 		}
 	    }
 	  break;
 	}
     }
   if (!primary)
     return; /* No primary key flag found (should not happen).  */
 
   for (last = NULL, node = keyblock; node; last = node, node = node->next)
     {
       if (node->pkt->pkttype == PKT_USER_ID)
 	break;
     }
   assert (node);
   assert (last);	 /* The user ID is never the first packet.  */
   assert (primary0);	 /* Ditto (this is the node before primary).  */
   if (node == primary)
     return; /* Already the first one.  */
 
   last->next = primary;
   primary0->next = primary2->next;
   primary2->next = node;
 }
 
 void
 reorder_keyblock (KBNODE keyblock)
 {
   do_reorder_keyblock (keyblock, 1);
   do_reorder_keyblock (keyblock, 0);
 }
 
 void
 list_keyblock (KBNODE keyblock, int secret, int has_secret, int fpr,
                void *opaque)
 {
   reorder_keyblock (keyblock);
   if (opt.with_colons)
     list_keyblock_colon (keyblock, secret, has_secret, fpr);
   else
     list_keyblock_print (keyblock, secret, fpr, opaque);
   if (secret)
     es_fflush (es_stdout);
 }
 
 /*
  * Function to print the finperprint.
  * mode 0: as used in key listings, opt.with_colons is honored
  *      1: print using log_info ()
  *      2: direct use of tty
  *      3: direct use of tty but only primary key.
  *
  * Modes 1 and 2 will try and print both subkey and primary key
  * fingerprints.  A MODE with bit 7 set is used internally.  If
  * OVERRIDE_FP is not NULL that stream will be used in  0 instead
  * of es_stdout or instead of the TTY in modes 2 and 3.
  */
 void
 print_fingerprint (estream_t override_fp, PKT_public_key *pk, int mode)
 {
   byte array[MAX_FINGERPRINT_LEN], *p;
   size_t i, n;
   estream_t fp;
   const char *text;
   int primary = 0;
 
   if (pk->main_keyid[0] == pk->keyid[0]
       && pk->main_keyid[1] == pk->keyid[1])
     primary = 1;
 
   /* Just to be safe */
   if ((mode & 0x80) && !primary)
     {
       log_error ("primary key is not really primary!\n");
       return;
     }
 
   mode &= ~0x80;
 
   if (!primary && (mode == 1 || mode == 2))
     {
       PKT_public_key *primary_pk = xmalloc_clear (sizeof (*primary_pk));
       get_pubkey (primary_pk, pk->main_keyid);
       print_fingerprint (override_fp, primary_pk, (mode | 0x80));
       free_public_key (primary_pk);
     }
 
   if (mode == 1)
     {
       fp = log_get_stream ();
       if (primary)
 	text = _("Primary key fingerprint:");
       else
 	text = _("     Subkey fingerprint:");
     }
   else if (mode == 2)
     {
       fp = override_fp; /* Use tty or given stream.  */
       if (primary)
 	/* TRANSLATORS: this should fit into 24 bytes to that the
 	 * fingerprint data is properly aligned with the user ID */
 	text = _(" Primary key fingerprint:");
       else
 	text = _("      Subkey fingerprint:");
     }
   else if (mode == 3)
     {
       fp = override_fp; /* Use tty or given stream.  */
       text = _("      Key fingerprint =");
     }
   else
     {
       fp = override_fp? override_fp : es_stdout;
       text = _("      Key fingerprint =");
     }
 
   fingerprint_from_pk (pk, array, &n);
   p = array;
   if (opt.with_colons && !mode)
     {
       es_fprintf (fp, "fpr:::::::::");
       for (i = 0; i < n; i++, p++)
 	es_fprintf (fp, "%02X", *p);
       es_putc (':', fp);
     }
   else
     {
       tty_fprintf (fp, "%s", text);
       if (n == 20)
 	{
 	  for (i = 0; i < n; i++, i++, p += 2)
             tty_fprintf (fp, "%s %02X%02X", i==10? " ":"", *p, p[1]);
 	}
       else
 	{
 	  for (i = 0; i < n; i++, p++)
             tty_fprintf (fp, "%s %02X", (i && !(i % 8))? " ":"", *p);
 	}
     }
   tty_fprintf (fp, "\n");
 }
 
 /* Print the serial number of an OpenPGP card if available.  */
 static void
 print_card_serialno (const char *serialno)
 {
   if (!serialno)
     return;
   if (opt.with_colons)
     return; /* Handled elsewhere. */
 
   es_fputs (_("      Card serial no. ="), es_stdout);
   es_putc (' ', es_stdout);
   if (strlen (serialno) == 32 && !strncmp (serialno, "D27600012401", 12))
     {
       /* This is an OpenPGP card.  Print the relevant part.  */
       /* Example: D2760001240101010001000003470000 */
       /*                          xxxxyyyyyyyy     */
       es_fprintf (es_stdout, "%.*s %.*s", 4, serialno+16, 8, serialno+20);
     }
  else
    es_fputs (serialno, es_stdout);
   es_putc ('\n', es_stdout);
 }
 
 
 
 void
 set_attrib_fd (int fd)
 {
   static int last_fd = -1;
 
   if (fd != -1 && last_fd == fd)
     return;
 
   /* Fixme: Do we need to check for the log stream here?  */
   if (attrib_fp && attrib_fp != log_get_stream ())
     es_fclose (attrib_fp);
   attrib_fp = NULL;
   if (fd == -1)
     return;
 
 #ifdef HAVE_DOSISH_SYSTEM
   setmode (fd, O_BINARY);
 #endif
   if (fd == 1)
     attrib_fp = es_stdout;
   else if (fd == 2)
     attrib_fp = es_stderr;
   else
     attrib_fp = es_fdopen (fd, "wb");
   if (!attrib_fp)
     {
       log_fatal ("can't open fd %d for attribute output: %s\n",
 		 fd, strerror (errno));
     }
 
   last_fd = fd;
 }
diff --git a/g10/keyring.c b/g10/keyring.c
index 34829e711..6060f0894 100644
--- a/g10/keyring.c
+++ b/g10/keyring.c
@@ -1,1646 +1,1665 @@
 /* keyring.c - keyring file handling
  * Copyright (C) 2001, 2004, 2009, 2010 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
  * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
 #include <assert.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 
 #include "gpg.h"
 #include "util.h"
 #include "keyring.h"
 #include "packet.h"
 #include "keydb.h"
 #include "options.h"
 #include "main.h" /*for check_key_signature()*/
 #include "i18n.h"
 
 /* off_item is a funny named for an object used to keep track of known
  * keys.  The idea was to use the offset to seek to the known keyblock, but
  * this is not possible if more than one process is using the keyring.
  */
 struct off_item {
   struct off_item *next;
   u32 kid[2];
   /*off_t off;*/
 };
 
 typedef struct off_item **OffsetHashTable;
 
 
 typedef struct keyring_name *KR_NAME;
 struct keyring_name
 {
   struct keyring_name *next;
   int read_only;
   dotlock_t lockhd;
   int is_locked;
   int did_full_scan;
   char fname[1];
 };
 typedef struct keyring_name const * CONST_KR_NAME;
 
 static KR_NAME kr_names;
 static int active_handles;
 
 static OffsetHashTable kr_offtbl;
 static int kr_offtbl_ready;
 
 
 struct keyring_handle
 {
   CONST_KR_NAME resource;
   struct {
     CONST_KR_NAME kr;
     IOBUF iobuf;
     int eof;
     int error;
   } current;
   struct {
     CONST_KR_NAME kr;
     off_t offset;
     size_t pk_no;
     size_t uid_no;
     unsigned int n_packets; /*used for delete and update*/
   } found;
   struct {
     char *name;
     char *pattern;
   } word_match;
 };
 
 
 
 static int do_copy (int mode, const char *fname, KBNODE root,
                     off_t start_offset, unsigned int n_packets );
 
 
 
 static struct off_item *
 new_offset_item (void)
 {
   struct off_item *k;
 
   k = xmalloc_clear (sizeof *k);
   return k;
 }
 
 #if 0
 static void
 release_offset_items (struct off_item *k)
 {
   struct off_item *k2;
 
   for (; k; k = k2)
     {
       k2 = k->next;
       xfree (k);
     }
 }
 #endif
 
 static OffsetHashTable
 new_offset_hash_table (void)
 {
   struct off_item **tbl;
 
   tbl = xmalloc_clear (2048 * sizeof *tbl);
   return tbl;
 }
 
 #if 0
 static void
 release_offset_hash_table (OffsetHashTable tbl)
 {
   int i;
 
   if (!tbl)
     return;
   for (i=0; i < 2048; i++)
     release_offset_items (tbl[i]);
   xfree (tbl);
 }
 #endif
 
 static struct off_item *
 lookup_offset_hash_table (OffsetHashTable tbl, u32 *kid)
 {
   struct off_item *k;
 
   for (k = tbl[(kid[1] & 0x07ff)]; k; k = k->next)
     if (k->kid[0] == kid[0] && k->kid[1] == kid[1])
       return k;
   return NULL;
 }
 
 static void
 update_offset_hash_table (OffsetHashTable tbl, u32 *kid, off_t off)
 {
   struct off_item *k;
 
   (void)off;
 
   for (k = tbl[(kid[1] & 0x07ff)]; k; k = k->next)
     {
       if (k->kid[0] == kid[0] && k->kid[1] == kid[1])
         {
           /*k->off = off;*/
           return;
         }
     }
 
   k = new_offset_item ();
   k->kid[0] = kid[0];
   k->kid[1] = kid[1];
   /*k->off = off;*/
   k->next = tbl[(kid[1] & 0x07ff)];
   tbl[(kid[1] & 0x07ff)] = k;
 }
 
 static void
 update_offset_hash_table_from_kb (OffsetHashTable tbl, KBNODE node, off_t off)
 {
   for (; node; node = node->next)
     {
       if (node->pkt->pkttype == PKT_PUBLIC_KEY
           || node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
         {
           u32 aki[2];
           keyid_from_pk (node->pkt->pkt.public_key, aki);
           update_offset_hash_table (tbl, aki, off);
         }
     }
 }
 
 /*
  * Register a filename for plain keyring files.  ptr is set to a
  * pointer to be used to create a handles etc, or the already-issued
  * pointer if it has already been registered.  The function returns 1
  * if a new keyring was registered.
 */
 int
 keyring_register_filename (const char *fname, int read_only, void **ptr)
 {
     KR_NAME kr;
 
     if (active_handles)
         BUG (); /* We don't allow that */
 
     for (kr=kr_names; kr; kr = kr->next)
       {
         if (same_file_p (kr->fname, fname))
 	  {
             /* Already registered. */
             if (read_only)
               kr->read_only = 1;
             *ptr=kr;
 	    return 0;
 	  }
       }
 
     kr = xmalloc (sizeof *kr + strlen (fname));
     strcpy (kr->fname, fname);
     kr->read_only = read_only;
     kr->lockhd = NULL;
     kr->is_locked = 0;
     kr->did_full_scan = 0;
     /* keep a list of all issued pointers */
     kr->next = kr_names;
     kr_names = kr;
 
     /* create the offset table the first time a function here is used */
     if (!kr_offtbl)
       kr_offtbl = new_offset_hash_table ();
 
     *ptr=kr;
 
     return 1;
 }
 
 int
 keyring_is_writable (void *token)
 {
   KR_NAME r = token;
 
   return r? (r->read_only || !access (r->fname, W_OK)) : 0;
 }
 
 
 
 /* Create a new handle for the resource associated with TOKEN.
 
    The returned handle must be released using keyring_release (). */
 KEYRING_HANDLE
 keyring_new (void *token)
 {
   KEYRING_HANDLE hd;
   KR_NAME resource = token;
 
   assert (resource);
 
   hd = xmalloc_clear (sizeof *hd);
   hd->resource = resource;
   active_handles++;
   return hd;
 }
 
 void
 keyring_release (KEYRING_HANDLE hd)
 {
     if (!hd)
         return;
     assert (active_handles > 0);
     active_handles--;
     xfree (hd->word_match.name);
     xfree (hd->word_match.pattern);
     iobuf_close (hd->current.iobuf);
     xfree (hd);
 }
 
 
 const char *
 keyring_get_resource_name (KEYRING_HANDLE hd)
 {
     if (!hd || !hd->resource)
       return NULL;
     return hd->resource->fname;
 }
 
 
 /*
  * Lock the keyring with the given handle, or unlock if YES is false.
  * We ignore the handle and lock all registered files.
  */
 int
 keyring_lock (KEYRING_HANDLE hd, int yes)
 {
     KR_NAME kr;
     int rc = 0;
 
     (void)hd;
 
     if (yes) {
         /* first make sure the lock handles are created */
         for (kr=kr_names; kr; kr = kr->next) {
             if (!keyring_is_writable(kr))
                 continue;
             if (!kr->lockhd) {
                 kr->lockhd = dotlock_create (kr->fname, 0);
                 if (!kr->lockhd) {
                     log_info ("can't allocate lock for '%s'\n", kr->fname );
                     rc = GPG_ERR_GENERAL;
                 }
             }
         }
         if (rc)
             return rc;
 
         /* and now set the locks */
         for (kr=kr_names; kr; kr = kr->next) {
             if (!keyring_is_writable(kr))
                 continue;
             if (kr->is_locked)
                 ;
             else if (dotlock_take (kr->lockhd, -1) ) {
                 log_info ("can't lock '%s'\n", kr->fname );
                 rc = GPG_ERR_GENERAL;
             }
             else
                 kr->is_locked = 1;
         }
     }
 
     if (rc || !yes) {
         for (kr=kr_names; kr; kr = kr->next) {
             if (!keyring_is_writable(kr))
                 continue;
             if (!kr->is_locked)
                 ;
             else if (dotlock_release (kr->lockhd))
                 log_info ("can't unlock '%s'\n", kr->fname );
             else
                 kr->is_locked = 0;
         }
     }
 
     return rc;
 }
 
 
 
 /*
  * Return the last found keyblock.  Caller must free it.
  * The returned keyblock has the kbode flag bit 0 set for the node with
  * the public key used to locate the keyblock or flag bit 1 set for
  * the user ID node.
  */
 int
 keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
 {
     PACKET *pkt;
     int rc;
     KBNODE keyblock = NULL, node, lastnode;
     IOBUF a;
     int in_cert = 0;
     int pk_no = 0;
     int uid_no = 0;
     int save_mode;
 
     if (ret_kb)
         *ret_kb = NULL;
 
     if (!hd->found.kr)
         return -1; /* no successful search */
 
     a = iobuf_open (hd->found.kr->fname);
     if (!a)
       {
 	log_error(_("can't open '%s'\n"), hd->found.kr->fname);
 	return GPG_ERR_KEYRING_OPEN;
       }
 
     if (iobuf_seek (a, hd->found.offset) ) {
         log_error ("can't seek '%s'\n", hd->found.kr->fname);
 	iobuf_close(a);
 	return GPG_ERR_KEYRING_OPEN;
     }
 
     pkt = xmalloc (sizeof *pkt);
     init_packet (pkt);
     hd->found.n_packets = 0;;
     lastnode = NULL;
     save_mode = set_packet_list_mode(0);
     while ((rc=parse_packet (a, pkt)) != -1) {
         hd->found.n_packets++;
         if (gpg_err_code (rc) == GPG_ERR_UNKNOWN_PACKET) {
 	    free_packet (pkt);
 	    init_packet (pkt);
 	    continue;
 	}
+        if (gpg_err_code (rc) == GPG_ERR_LEGACY_KEY)
+          break;  /* Upper layer needs to handle this.  */
 	if (rc) {
             log_error ("keyring_get_keyblock: read error: %s\n",
                        gpg_strerror (rc) );
             rc = GPG_ERR_INV_KEYRING;
             break;
         }
 	if (pkt->pkttype == PKT_COMPRESSED) {
 	    log_error ("skipped compressed packet in keyring\n");
 	    free_packet(pkt);
 	    init_packet(pkt);
 	    continue;
         }
 
         if (in_cert && (pkt->pkttype == PKT_PUBLIC_KEY
                         || pkt->pkttype == PKT_SECRET_KEY)) {
             hd->found.n_packets--; /* fix counter */
             break; /* ready */
         }
 
         in_cert = 1;
         if (pkt->pkttype == PKT_RING_TRUST)
           {
             /*(this code is duplicated after the loop)*/
             if ( lastnode
                  && lastnode->pkt->pkttype == PKT_SIGNATURE
                  && (pkt->pkt.ring_trust->sigcache & 1) ) {
                 /* This is a ring trust packet with a checked signature
                  * status cache following directly a signature paket.
                  * Set the cache status into that signature packet.  */
                 PKT_signature *sig = lastnode->pkt->pkt.signature;
 
                 sig->flags.checked = 1;
                 sig->flags.valid = !!(pkt->pkt.ring_trust->sigcache & 2);
             }
             /* Reset LASTNODE, so that we set the cache status only from
              * the ring trust packet immediately following a signature. */
             lastnode = NULL;
 	    free_packet(pkt);
 	    init_packet(pkt);
 	    continue;
           }
 
 
         node = lastnode = new_kbnode (pkt);
         if (!keyblock)
           keyblock = node;
         else
           add_kbnode (keyblock, node);
         switch (pkt->pkttype)
           {
           case PKT_PUBLIC_KEY:
           case PKT_PUBLIC_SUBKEY:
           case PKT_SECRET_KEY:
           case PKT_SECRET_SUBKEY:
             if (++pk_no == hd->found.pk_no)
               node->flag |= 1;
             break;
 
           case PKT_USER_ID:
             if (++uid_no == hd->found.uid_no)
               node->flag |= 2;
             break;
 
           default:
             break;
           }
 
         pkt = xmalloc (sizeof *pkt);
         init_packet(pkt);
     }
     set_packet_list_mode(save_mode);
 
     if (rc == -1 && keyblock)
 	rc = 0; /* got the entire keyblock */
 
     if (rc || !ret_kb)
 	release_kbnode (keyblock);
     else {
         /*(duplicated form the loop body)*/
         if ( pkt && pkt->pkttype == PKT_RING_TRUST
              && lastnode
              && lastnode->pkt->pkttype == PKT_SIGNATURE
              && (pkt->pkt.ring_trust->sigcache & 1) ) {
             PKT_signature *sig = lastnode->pkt->pkt.signature;
             sig->flags.checked = 1;
             sig->flags.valid = !!(pkt->pkt.ring_trust->sigcache & 2);
         }
 	*ret_kb = keyblock;
     }
     free_packet (pkt);
     xfree (pkt);
     iobuf_close(a);
 
     /* Make sure that future search operations fail immediately when
      * we know that we are working on a invalid keyring
      */
     if (gpg_err_code (rc) == GPG_ERR_INV_KEYRING)
         hd->current.error = rc;
 
     return rc;
 }
 
 int
 keyring_update_keyblock (KEYRING_HANDLE hd, KBNODE kb)
 {
     int rc;
 
     if (!hd->found.kr)
         return -1; /* no successful prior search */
 
     if (hd->found.kr->read_only)
       return gpg_error (GPG_ERR_EACCES);
 
     if (!hd->found.n_packets) {
         /* need to know the number of packets - do a dummy get_keyblock*/
         rc = keyring_get_keyblock (hd, NULL);
         if (rc) {
             log_error ("re-reading keyblock failed: %s\n", gpg_strerror (rc));
             return rc;
         }
         if (!hd->found.n_packets)
             BUG ();
     }
 
     /* The open iobuf isn't needed anymore and in fact is a problem when
        it comes to renaming the keyring files on some operating systems,
        so close it here */
     iobuf_close(hd->current.iobuf);
     hd->current.iobuf = NULL;
 
     /* do the update */
     rc = do_copy (3, hd->found.kr->fname, kb,
                   hd->found.offset, hd->found.n_packets );
     if (!rc) {
       if (kr_offtbl)
         {
           update_offset_hash_table_from_kb (kr_offtbl, kb, 0);
         }
       /* better reset the found info */
       hd->found.kr = NULL;
       hd->found.offset = 0;
     }
     return rc;
 }
 
 int
 keyring_insert_keyblock (KEYRING_HANDLE hd, KBNODE kb)
 {
     int rc;
     const char *fname;
 
     if (!hd)
         fname = NULL;
     else if (hd->found.kr)
       {
         fname = hd->found.kr->fname;
         if (hd->found.kr->read_only)
           return gpg_error (GPG_ERR_EACCES);
       }
     else if (hd->current.kr)
       {
         fname = hd->current.kr->fname;
         if (hd->current.kr->read_only)
           return gpg_error (GPG_ERR_EACCES);
       }
     else
         fname = hd->resource? hd->resource->fname:NULL;
 
     if (!fname)
         return GPG_ERR_GENERAL;
 
     /* Close this one otherwise we will lose the position for
      * a next search.  Fixme: it would be better to adjust the position
      * after the write opertions.
      */
     iobuf_close (hd->current.iobuf);
     hd->current.iobuf = NULL;
 
     /* do the insert */
     rc = do_copy (1, fname, kb, 0, 0 );
     if (!rc && kr_offtbl)
       {
         update_offset_hash_table_from_kb (kr_offtbl, kb, 0);
       }
 
     return rc;
 }
 
 
 int
 keyring_delete_keyblock (KEYRING_HANDLE hd)
 {
     int rc;
 
     if (!hd->found.kr)
         return -1; /* no successful prior search */
 
     if (hd->found.kr->read_only)
       return gpg_error (GPG_ERR_EACCES);
 
     if (!hd->found.n_packets) {
         /* need to know the number of packets - do a dummy get_keyblock*/
         rc = keyring_get_keyblock (hd, NULL);
         if (rc) {
             log_error ("re-reading keyblock failed: %s\n", gpg_strerror (rc));
             return rc;
         }
         if (!hd->found.n_packets)
             BUG ();
     }
 
     /* close this one otherwise we will lose the position for
      * a next search.  Fixme: it would be better to adjust the position
      * after the write opertions.
      */
     iobuf_close (hd->current.iobuf);
     hd->current.iobuf = NULL;
 
     /* do the delete */
     rc = do_copy (2, hd->found.kr->fname, NULL,
                   hd->found.offset, hd->found.n_packets );
     if (!rc) {
         /* better reset the found info */
         hd->found.kr = NULL;
         hd->found.offset = 0;
         /* Delete is a rare operations, so we don't remove the keys
          * from the offset table */
     }
     return rc;
 }
 
 
 
 /*
  * Start the next search on this handle right at the beginning
  */
 int
 keyring_search_reset (KEYRING_HANDLE hd)
 {
     assert (hd);
 
     hd->current.kr = NULL;
     iobuf_close (hd->current.iobuf);
     hd->current.iobuf = NULL;
     hd->current.eof = 0;
     hd->current.error = 0;
 
     hd->found.kr = NULL;
     hd->found.offset = 0;
     return 0;
 }
 
 
 static int
 prepare_search (KEYRING_HANDLE hd)
 {
-    if (hd->current.error)
-        return hd->current.error; /* still in error state */
+    if (hd->current.error) {
+        /* If the last key was a legacy key, we simply ignore the error so that
+           we can easily use search_next.  */
+        if (gpg_err_code (hd->current.error) == GPG_ERR_LEGACY_KEY)
+            hd->current.error = 0;
+        else
+            return hd->current.error; /* still in error state */
+    }
 
     if (hd->current.kr && !hd->current.eof) {
         if ( !hd->current.iobuf )
             return GPG_ERR_GENERAL; /* Position invalid after a modify.  */
         return 0; /* okay */
     }
 
     if (!hd->current.kr && hd->current.eof)
         return -1; /* still EOF */
 
     if (!hd->current.kr) { /* start search with first keyring */
         hd->current.kr = hd->resource;
         if (!hd->current.kr) {
             hd->current.eof = 1;
             return -1; /* keyring not available */
         }
         assert (!hd->current.iobuf);
     }
     else { /* EOF */
         iobuf_close (hd->current.iobuf);
         hd->current.iobuf = NULL;
         hd->current.kr = NULL;
         hd->current.eof = 1;
         return -1;
     }
 
     hd->current.eof = 0;
     hd->current.iobuf = iobuf_open (hd->current.kr->fname);
     if (!hd->current.iobuf)
       {
         hd->current.error = gpg_error_from_syserror ();
         log_error(_("can't open '%s'\n"), hd->current.kr->fname );
         return hd->current.error;
       }
 
     return 0;
 }
 
 
 /* A map of the all characters valid used for word_match()
  * Valid characters are in in this table converted to uppercase.
  * because the upper 128 bytes have special meaning, 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).
  * wk 2000-04-13: Hmmm, does this really make sense, given the fact that
  * we can run gpg now on a S/390 running GNU/Linux, where the code
  * translation is done by the device drivers?
  */
 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
 };
 
 /****************
  * 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)
  */
 static int
 word_match( const byte *uid, size_t uidlen, const byte *pattern )
 {
     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 */
 }
 
 /****************
  * 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;
 
     /* the original length is always enough for the pattern */
     p = pattern = xmalloc(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 (int mode, const char *name, const char *uid, size_t uidlen)
 {
     int i;
     const char *s, *se;
 
     if (mode == KEYDB_SEARCH_MODE_EXACT) {
 	for (i=0; name[i] && uidlen; i++, uidlen--)
 	    if (uid[i] != name[i])
 		break;
 	if (!uidlen && !name[i])
 	    return 0; /* found */
     }
     else if (mode == KEYDB_SEARCH_MODE_SUBSTR) {
 	if (ascii_memistr( uid, uidlen, name ))
 	    return 0;
     }
     else if (   mode == KEYDB_SEARCH_MODE_MAIL
              || mode == KEYDB_SEARCH_MODE_MAILSUB
              || mode == KEYDB_SEARCH_MODE_MAILEND) {
 	for (i=0, s= uid; i < uidlen && *s != '<'; s++, i++)
 	    ;
 	if (i < uidlen)  {
 	    /* skip opening delim and one char and look for the closing one*/
 	    s++; i++;
 	    for (se=s+1, i++; i < uidlen && *se != '>'; se++, i++)
 		;
 	    if (i < uidlen) {
 		i = se - s;
 		if (mode == KEYDB_SEARCH_MODE_MAIL) {
 		    if( strlen(name)-2 == i
                         && !ascii_memcasecmp( s, name+1, i) )
 			return 0;
 		}
 		else if (mode == KEYDB_SEARCH_MODE_MAILSUB) {
 		    if( ascii_memistr( s, i, name ) )
 			return 0;
 		}
 		else { /* email from end */
 		    /* nyi */
 		}
 	    }
 	}
     }
     else if (mode == KEYDB_SEARCH_MODE_WORDS)
 	return word_match (uid, uidlen, name);
     else
 	BUG();
 
     return -1; /* not found */
 }
 
 
 /*
  * Search through the keyring(s), starting at the current position,
  * for a keyblock which contains one of the keys described in the DESC array.
  */
 int
 keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
 		size_t ndesc, size_t *descindex)
 {
   int rc;
   PACKET pkt;
   int save_mode;
   off_t offset, main_offset;
   size_t n;
   int need_uid, need_words, need_keyid, need_fpr, any_skip;
   int pk_no, uid_no;
   int initial_skip;
   int use_offtbl;
   PKT_user_id *uid = NULL;
   PKT_public_key *pk = NULL;
   u32 aki[2];
 
   /* figure out what information we need */
   need_uid = need_words = need_keyid = need_fpr = any_skip = 0;
   for (n=0; n < ndesc; n++)
     {
       switch (desc[n].mode)
         {
         case KEYDB_SEARCH_MODE_EXACT:
         case KEYDB_SEARCH_MODE_SUBSTR:
         case KEYDB_SEARCH_MODE_MAIL:
         case KEYDB_SEARCH_MODE_MAILSUB:
         case KEYDB_SEARCH_MODE_MAILEND:
           need_uid = 1;
           break;
         case KEYDB_SEARCH_MODE_WORDS:
           need_uid = 1;
           need_words = 1;
           break;
         case KEYDB_SEARCH_MODE_SHORT_KID:
         case KEYDB_SEARCH_MODE_LONG_KID:
           need_keyid = 1;
           break;
         case KEYDB_SEARCH_MODE_FPR16:
         case KEYDB_SEARCH_MODE_FPR20:
         case KEYDB_SEARCH_MODE_FPR:
           need_fpr = 1;
           break;
         case KEYDB_SEARCH_MODE_FIRST:
           /* always restart the search in this mode */
           keyring_search_reset (hd);
           break;
         default: break;
 	}
       if (desc[n].skipfnc)
         {
           any_skip = 1;
           need_keyid = 1;
         }
     }
 
   rc = prepare_search (hd);
   if (rc)
     return rc;
 
   use_offtbl = !!kr_offtbl;
   if (!use_offtbl)
     ;
   else if (!kr_offtbl_ready)
     need_keyid = 1;
   else if (ndesc == 1 && desc[0].mode == KEYDB_SEARCH_MODE_LONG_KID)
     {
       struct off_item *oi;
 
       oi = lookup_offset_hash_table (kr_offtbl, desc[0].u.kid);
       if (!oi)
         { /* We know that we don't have this key */
           hd->found.kr = NULL;
           hd->current.eof = 1;
           return -1;
         }
       /* We could now create a positive search status and return.
        * However the problem is that another instance of gpg may
        * have changed the keyring so that the offsets are not valid
        * anymore - therefore we don't do it
        */
     }
 
   if (need_words)
     {
       const char *name = NULL;
 
       log_debug ("word search mode does not yet work\n");
       /* FIXME: here is a long standing bug in our function and in addition we
          just use the first search description */
       for (n=0; n < ndesc && !name; n++)
         {
           if (desc[n].mode == KEYDB_SEARCH_MODE_WORDS)
             name = desc[n].u.name;
         }
       assert (name);
       if ( !hd->word_match.name || strcmp (hd->word_match.name, name) )
         {
           /* name changed */
           xfree (hd->word_match.name);
           xfree (hd->word_match.pattern);
           hd->word_match.name = xstrdup (name);
           hd->word_match.pattern = prepare_word_match (name);
         }
       /*  name = hd->word_match.pattern; */
     }
 
   init_packet(&pkt);
   save_mode = set_packet_list_mode(0);
 
   hd->found.kr = NULL;
   main_offset = 0;
   pk_no = uid_no = 0;
   initial_skip = 1; /* skip until we see the start of a keyblock */
   while (!(rc=search_packet (hd->current.iobuf, &pkt, &offset, need_uid)))
     {
       byte afp[MAX_FINGERPRINT_LEN];
       size_t an;
 
       if (pkt.pkttype == PKT_PUBLIC_KEY  || pkt.pkttype == PKT_SECRET_KEY)
         {
           main_offset = offset;
           pk_no = uid_no = 0;
           initial_skip = 0;
         }
       if (initial_skip)
         {
           free_packet (&pkt);
           continue;
         }
 
       pk = NULL;
       uid = NULL;
       if (   pkt.pkttype == PKT_PUBLIC_KEY
              || pkt.pkttype == PKT_PUBLIC_SUBKEY
              || pkt.pkttype == PKT_SECRET_KEY
              || pkt.pkttype == PKT_SECRET_SUBKEY)
         {
           pk = pkt.pkt.public_key;
           ++pk_no;
 
           if (need_fpr) {
             fingerprint_from_pk (pk, afp, &an);
             while (an < 20) /* fill up to 20 bytes */
               afp[an++] = 0;
           }
           if (need_keyid)
             keyid_from_pk (pk, aki);
 
           if (use_offtbl && !kr_offtbl_ready)
             update_offset_hash_table (kr_offtbl, aki, main_offset);
         }
       else if (pkt.pkttype == PKT_USER_ID)
         {
           uid = pkt.pkt.user_id;
           ++uid_no;
         }
 
       for (n=0; n < ndesc; n++)
         {
           switch (desc[n].mode) {
           case KEYDB_SEARCH_MODE_NONE:
             BUG ();
             break;
           case KEYDB_SEARCH_MODE_EXACT:
           case KEYDB_SEARCH_MODE_SUBSTR:
           case KEYDB_SEARCH_MODE_MAIL:
           case KEYDB_SEARCH_MODE_MAILSUB:
           case KEYDB_SEARCH_MODE_MAILEND:
           case KEYDB_SEARCH_MODE_WORDS:
             if ( uid && !compare_name (desc[n].mode,
                                        desc[n].u.name,
                                        uid->name, uid->len))
               goto found;
             break;
 
           case KEYDB_SEARCH_MODE_SHORT_KID:
             if (pk && desc[n].u.kid[1] == aki[1])
               goto found;
             break;
           case KEYDB_SEARCH_MODE_LONG_KID:
             if (pk && desc[n].u.kid[0] == aki[0]
                 && desc[n].u.kid[1] == aki[1])
               goto found;
             break;
           case KEYDB_SEARCH_MODE_FPR16:
             if (pk && !memcmp (desc[n].u.fpr, afp, 16))
               goto found;
             break;
           case KEYDB_SEARCH_MODE_FPR20:
           case KEYDB_SEARCH_MODE_FPR:
             if (pk && !memcmp (desc[n].u.fpr, afp, 20))
               goto found;
             break;
           case KEYDB_SEARCH_MODE_FIRST:
             if (pk)
               goto found;
             break;
           case KEYDB_SEARCH_MODE_NEXT:
             if (pk)
               goto found;
             break;
           default:
             rc = GPG_ERR_INV_ARG;
             goto found;
           }
 	}
       free_packet (&pkt);
       continue;
     found:
       /* Record which desc we matched on.  Note this value is only
 	 meaningful if this function returns with no errors. */
       if(descindex)
 	*descindex=n;
       for (n=any_skip?0:ndesc; n < ndesc; n++)
         {
           if (desc[n].skipfnc
               && desc[n].skipfnc (desc[n].skipfncvalue, aki, uid))
             break;
         }
       if (n == ndesc)
         goto real_found;
       free_packet (&pkt);
     }
  real_found:
   if (!rc)
     {
       hd->found.offset = main_offset;
       hd->found.kr = hd->current.kr;
       hd->found.pk_no = pk? pk_no : 0;
       hd->found.uid_no = uid? uid_no : 0;
     }
   else if (rc == -1)
     {
       hd->current.eof = 1;
       /* if we scanned all keyrings, we are sure that
        * all known key IDs are in our offtbl, mark that. */
       if (use_offtbl && !kr_offtbl_ready)
         {
           KR_NAME kr;
 
           /* First set the did_full_scan flag for this keyring.  */
           for (kr=kr_names; kr; kr = kr->next)
             {
               if (hd->resource == kr)
                 {
                   kr->did_full_scan = 1;
                   break;
                 }
             }
           /* Then check whether all flags are set and if so, mark the
              offtbl ready */
           for (kr=kr_names; kr; kr = kr->next)
             {
               if (!kr->did_full_scan)
                 break;
             }
           if (!kr)
             kr_offtbl_ready = 1;
         }
     }
   else
     hd->current.error = rc;
 
   free_packet(&pkt);
   set_packet_list_mode(save_mode);
   return rc;
 }
 
 
 static int
 create_tmp_file (const char *template,
                  char **r_bakfname, char **r_tmpfname, IOBUF *r_fp)
 {
   char *bakfname, *tmpfname;
   mode_t oldmask;
 
   *r_bakfname = NULL;
   *r_tmpfname = NULL;
 
 # ifdef USE_ONLY_8DOT3
   /* Here is another Windoze bug?:
    * you cant rename("pubring.gpg.tmp", "pubring.gpg");
    * but	rename("pubring.gpg.tmp", "pubring.aaa");
    * works.  So we replace .gpg by .bak or .tmp
    */
   if (strlen (template) > 4
       && !strcmp (template+strlen(template)-4, EXTSEP_S GPGEXT_GPG) )
     {
       bakfname = xmalloc (strlen (template) + 1);
       strcpy (bakfname, template);
       strcpy (bakfname+strlen(template)-4, EXTSEP_S "bak");
 
       tmpfname = xmalloc (strlen( template ) + 1 );
       strcpy (tmpfname,template);
       strcpy (tmpfname+strlen(template)-4, EXTSEP_S "tmp");
     }
     else
       { /* file does not end with gpg; hmmm */
 	bakfname = xmalloc (strlen( template ) + 5);
 	strcpy (stpcpy(bakfname, template), EXTSEP_S "bak");
 
 	tmpfname = xmalloc (strlen( template ) + 5);
 	strcpy (stpcpy(tmpfname, template), EXTSEP_S "tmp");
     }
 # else /* Posix file names */
     bakfname = xmalloc (strlen( template ) + 2);
     strcpy (stpcpy (bakfname,template),"~");
 
     tmpfname = xmalloc (strlen( template ) + 5);
     strcpy (stpcpy(tmpfname,template), EXTSEP_S "tmp");
 # endif /* Posix filename */
 
     /* Create the temp file with limited access.  Note that the umask
        call is not anymore needed because iobuf_create now takes care
        of it.  However, it does not harm and thus we keep it.  */
     oldmask=umask(077);
     if (is_secured_filename (tmpfname))
       {
         *r_fp = NULL;
         gpg_err_set_errno (EPERM);
       }
     else
       *r_fp = iobuf_create (tmpfname, 1);
     umask(oldmask);
     if (!*r_fp)
       {
         int rc = gpg_error_from_syserror ();
 	log_error(_("can't create '%s': %s\n"), tmpfname, strerror(errno) );
         xfree (tmpfname);
         xfree (bakfname);
 	return rc;
       }
 
     *r_bakfname = bakfname;
     *r_tmpfname = tmpfname;
     return 0;
 }
 
 
 static int
 rename_tmp_file (const char *bakfname, const char *tmpfname, const char *fname)
 {
   int rc = 0;
 
   /* Invalidate close caches.  */
   if (iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)tmpfname ))
     {
       rc = gpg_error_from_syserror ();
       goto fail;
     }
   iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)bakfname );
   iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname );
 
   /* First make a backup file. */
 #if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
   gnupg_remove (bakfname);
 #endif
   if (rename (fname, bakfname) )
     {
       rc = gpg_error_from_syserror ();
       log_error ("renaming '%s' to '%s' failed: %s\n",
                  fname, bakfname, strerror(errno) );
       return rc;
     }
 
   /* then rename the file */
 #if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
   gnupg_remove( fname );
 #endif
   if (rename (tmpfname, fname) )
     {
       rc = gpg_error_from_syserror ();
       log_error (_("renaming '%s' to '%s' failed: %s\n"),
                  tmpfname, fname, strerror(errno) );
       register_secured_file (fname);
       goto fail;
     }
 
   /* Now make sure the file has the same permissions as the original */
 
 #ifndef HAVE_DOSISH_SYSTEM
   {
     struct stat statbuf;
 
     statbuf.st_mode=S_IRUSR | S_IWUSR;
 
     if (!stat (bakfname, &statbuf) && !chmod (fname, statbuf.st_mode))
       ;
     else
       log_error ("WARNING: unable to restore permissions to '%s': %s",
                  fname, strerror(errno));
   }
 #endif
 
   return 0;
 
  fail:
   return rc;
 }
 
 
 static int
 write_keyblock (IOBUF fp, KBNODE keyblock)
 {
   KBNODE kbctx = NULL, node;
   int rc;
 
   while ( (node = walk_kbnode (keyblock, &kbctx, 0)) )
     {
       if (node->pkt->pkttype == PKT_RING_TRUST)
         continue; /* we write it later on our own */
 
       if ( (rc = build_packet (fp, node->pkt) ))
         {
           log_error ("build_packet(%d) failed: %s\n",
                      node->pkt->pkttype, gpg_strerror (rc) );
           return rc;
         }
       if (node->pkt->pkttype == PKT_SIGNATURE)
         { /* always write a signature cache packet */
           PKT_signature *sig = node->pkt->pkt.signature;
           unsigned int cacheval = 0;
 
           if (sig->flags.checked)
             {
               cacheval |= 1;
               if (sig->flags.valid)
                 cacheval |= 2;
             }
           iobuf_put (fp, 0xb0); /* old style packet 12, 1 byte len*/
           iobuf_put (fp, 2);    /* 2 bytes */
           iobuf_put (fp, 0);    /* unused */
           if (iobuf_put (fp, cacheval))
             {
               rc = gpg_error_from_syserror ();
               log_error ("writing sigcache packet failed\n");
               return rc;
             }
         }
     }
   return 0;
 }
 
 /*
  * Walk over all public keyrings, check the signatures and replace the
  * keyring with a new one where the signature cache is then updated.
  * This is only done for the public keyrings.
  */
 int
 keyring_rebuild_cache (void *token,int noisy)
 {
   KEYRING_HANDLE hd;
   KEYDB_SEARCH_DESC desc;
   KBNODE keyblock = NULL, node;
   const char *lastresname = NULL, *resname;
   IOBUF tmpfp = NULL;
   char *tmpfilename = NULL;
   char *bakfilename = NULL;
   int rc;
   ulong count = 0, sigcount = 0;
 
   hd = keyring_new (token);
   memset (&desc, 0, sizeof desc);
   desc.mode = KEYDB_SEARCH_MODE_FIRST;
 
   rc=keyring_lock (hd, 1);
   if(rc)
     goto leave;
 
-  while ( !(rc = keyring_search (hd, &desc, 1, NULL)) )
+  for (;;)
     {
+      rc = keyring_search (hd, &desc, 1, NULL);
+      if (rc && gpg_err_code (rc) != GPG_ERR_LEGACY_KEY)
+        break;  /* ready.  */
+
       desc.mode = KEYDB_SEARCH_MODE_NEXT;
       resname = keyring_get_resource_name (hd);
       if (lastresname != resname )
         { /* we have switched to a new keyring - commit changes */
           if (tmpfp)
             {
               if (iobuf_close (tmpfp))
                 {
                   rc = gpg_error_from_syserror ();
                   log_error ("error closing '%s': %s\n",
                              tmpfilename, strerror (errno));
                   goto leave;
                 }
               /* because we have switched resources, we can be sure that
                * the original file is closed */
               tmpfp = NULL;
             }
           rc = lastresname? rename_tmp_file (bakfilename, tmpfilename,
                                              lastresname) : 0;
           xfree (tmpfilename);  tmpfilename = NULL;
           xfree (bakfilename);  bakfilename = NULL;
           if (rc)
             goto leave;
           lastresname = resname;
           if (noisy && !opt.quiet)
             log_info (_("caching keyring '%s'\n"), resname);
           rc = create_tmp_file (resname, &bakfilename, &tmpfilename, &tmpfp);
           if (rc)
             goto leave;
         }
 
+      if (gpg_err_code (rc) == GPG_ERR_LEGACY_KEY)
+        continue;
+
       release_kbnode (keyblock);
       rc = keyring_get_keyblock (hd, &keyblock);
       if (rc)
         {
+          if (gpg_err_code (rc) == GPG_ERR_LEGACY_KEY)
+            continue;  /* Skip legacy keys.  */
           log_error ("keyring_get_keyblock failed: %s\n", gpg_strerror (rc));
           goto leave;
         }
       if ( keyblock->pkt->pkttype != PKT_PUBLIC_KEY)
         {
           /* We had a few reports about corrupted keyrings; if we have
              been called directly from the command line we delete such
              a keyblock instead of bailing out.  */
           log_error ("unexpected keyblock found (pkttype=%d)%s\n",
                      keyblock->pkt->pkttype, noisy? " - deleted":"");
           if (noisy)
             continue;
           log_info ("Hint: backup your keys and try running '%s'\n",
                     "gpg --rebuild-keydb-caches");
           rc = gpg_error (GPG_ERR_INV_KEYRING);
           goto leave;
         }
 
       if (keyblock->pkt->pkt.public_key->version < 4)
         {
           /* We do not copy/cache v3 keys or any other unknown
              packets.  It is better to remove them from the keyring.
              The code required to keep them in the keyring would be
              too complicated.  Given that we do not touch the old
              secring.gpg a suitable backup for decryption of v3 stuff
-             using an older gpg version will always be available.  */
+             using an older gpg version will always be available.
+             Note: This test is actually superfluous because we
+             already acted upon GPG_ERR_LEGACY_KEY.      */
         }
       else
         {
           /* Check all signature to set the signature's cache flags. */
           for (node=keyblock; node; node=node->next)
             {
               /* Note that this doesn't cache the result of a
                  revocation issued by a designated revoker.  This is
                  because the pk in question does not carry the revkeys
                  as we haven't merged the key and selfsigs.  It is
                  questionable whether this matters very much since
                  there are very very few designated revoker revocation
                  packets out there. */
               if (node->pkt->pkttype == PKT_SIGNATURE)
                 {
                   PKT_signature *sig=node->pkt->pkt.signature;
 
                   if(!opt.no_sig_cache && sig->flags.checked && sig->flags.valid
                      && (openpgp_md_test_algo(sig->digest_algo)
                          || openpgp_pk_test_algo(sig->pubkey_algo)))
                     sig->flags.checked=sig->flags.valid=0;
                   else
                     check_key_signature (keyblock, node, NULL);
 
                   sigcount++;
                 }
             }
 
           /* Write the keyblock to the temporary file.  */
           rc = write_keyblock (tmpfp, keyblock);
           if (rc)
             goto leave;
 
           if ( !(++count % 50) && noisy && !opt.quiet)
             log_info(_("%lu keys cached so far (%lu signatures)\n"),
                      count, sigcount );
         }
     } /* end main loop */
   if (rc == -1)
     rc = 0;
   if (rc)
     {
       log_error ("keyring_search failed: %s\n", gpg_strerror (rc));
       goto leave;
     }
   if(noisy || opt.verbose)
     log_info(_("%lu keys cached (%lu signatures)\n"), count, sigcount );
   if (tmpfp)
     {
       if (iobuf_close (tmpfp))
         {
           rc = gpg_error_from_syserror ();
           log_error ("error closing '%s': %s\n",
                      tmpfilename, strerror (errno));
           goto leave;
         }
       /* because we have switched resources, we can be sure that
        * the original file is closed */
       tmpfp = NULL;
     }
   rc = lastresname? rename_tmp_file (bakfilename, tmpfilename,
                                      lastresname) : 0;
   xfree (tmpfilename);  tmpfilename = NULL;
   xfree (bakfilename);  bakfilename = NULL;
 
  leave:
   if (tmpfp)
     iobuf_cancel (tmpfp);
   xfree (tmpfilename);
   xfree (bakfilename);
   release_kbnode (keyblock);
   keyring_lock (hd, 0);
   keyring_release (hd);
   return rc;
 }
 
 
 /****************
  * Perform insert/delete/update operation.
  * mode 1 = insert
  *	2 = delete
  *	3 = update
  */
 static int
 do_copy (int mode, const char *fname, KBNODE root,
          off_t start_offset, unsigned int n_packets )
 {
     IOBUF fp, newfp;
     int rc=0;
     char *bakfname = NULL;
     char *tmpfname = NULL;
 
     /* Open the source file. Because we do a rename, we have to check the
        permissions of the file */
     if (access (fname, W_OK))
       return gpg_error_from_syserror ();
 
     fp = iobuf_open (fname);
     if (mode == 1 && !fp && errno == ENOENT) {
 	/* insert mode but file does not exist: create a new file */
 	KBNODE kbctx, node;
 	mode_t oldmask;
 
 	oldmask=umask(077);
         if (is_secured_filename (fname)) {
             newfp = NULL;
             gpg_err_set_errno (EPERM);
         }
         else
             newfp = iobuf_create (fname, 1);
 	umask(oldmask);
 	if( !newfp )
 	  {
             rc = gpg_error_from_syserror ();
 	    log_error (_("can't create '%s': %s\n"), fname, strerror(errno));
 	    return rc;
 	  }
 	if( !opt.quiet )
 	    log_info(_("%s: keyring created\n"), fname );
 
 	kbctx=NULL;
 	while ( (node = walk_kbnode( root, &kbctx, 0 )) ) {
 	    if( (rc = build_packet( newfp, node->pkt )) ) {
 		log_error("build_packet(%d) failed: %s\n",
 			    node->pkt->pkttype, gpg_strerror (rc) );
 		iobuf_cancel(newfp);
 		return rc;
 	    }
 	}
 	if( iobuf_close(newfp) ) {
             rc = gpg_error_from_syserror ();
 	    log_error ("%s: close failed: %s\n", fname, strerror(errno));
 	    return rc;
 	}
 	return 0; /* ready */
     }
 
     if( !fp )
       {
         rc = gpg_error_from_syserror ();
 	log_error(_("can't open '%s': %s\n"), fname, strerror(errno) );
 	goto leave;
       }
 
     /* Create the new file.  */
     rc = create_tmp_file (fname, &bakfname, &tmpfname, &newfp);
     if (rc) {
 	iobuf_close(fp);
 	goto leave;
     }
 
     if( mode == 1 ) { /* insert */
 	/* copy everything to the new file */
 	rc = copy_all_packets (fp, newfp);
 	if( rc != -1 ) {
 	    log_error("%s: copy to '%s' failed: %s\n",
 		      fname, tmpfname, gpg_strerror (rc) );
 	    iobuf_close(fp);
 	    iobuf_cancel(newfp);
 	    goto leave;
 	}
 	rc = 0;
     }
 
     if( mode == 2 || mode == 3 ) { /* delete or update */
 	/* copy first part to the new file */
 	rc = copy_some_packets( fp, newfp, start_offset );
 	if( rc ) { /* should never get EOF here */
 	    log_error ("%s: copy to '%s' failed: %s\n",
                        fname, tmpfname, gpg_strerror (rc) );
 	    iobuf_close(fp);
 	    iobuf_cancel(newfp);
 	    goto leave;
 	}
 	/* skip this keyblock */
 	assert( n_packets );
 	rc = skip_some_packets( fp, n_packets );
 	if( rc ) {
 	    log_error("%s: skipping %u packets failed: %s\n",
 			    fname, n_packets, gpg_strerror (rc));
 	    iobuf_close(fp);
 	    iobuf_cancel(newfp);
 	    goto leave;
 	}
     }
 
     if( mode == 1 || mode == 3 ) { /* insert or update */
         rc = write_keyblock (newfp, root);
         if (rc) {
           iobuf_close(fp);
           iobuf_cancel(newfp);
           goto leave;
         }
     }
 
     if( mode == 2 || mode == 3 ) { /* delete or update */
 	/* copy the rest */
 	rc = copy_all_packets( fp, newfp );
 	if( rc != -1 ) {
 	    log_error("%s: copy to '%s' failed: %s\n",
 		      fname, tmpfname, gpg_strerror (rc) );
 	    iobuf_close(fp);
 	    iobuf_cancel(newfp);
 	    goto leave;
 	}
 	rc = 0;
     }
 
     /* close both files */
     if( iobuf_close(fp) ) {
         rc = gpg_error_from_syserror ();
 	log_error("%s: close failed: %s\n", fname, strerror(errno) );
 	goto leave;
     }
     if( iobuf_close(newfp) ) {
         rc = gpg_error_from_syserror ();
 	log_error("%s: close failed: %s\n", tmpfname, strerror(errno) );
 	goto leave;
     }
 
     rc = rename_tmp_file (bakfname, tmpfname, fname);
 
   leave:
     xfree(bakfname);
     xfree(tmpfname);
     return rc;
 }
diff --git a/g10/keyserver.c b/g10/keyserver.c
index 0530907a9..035cd031f 100644
--- a/g10/keyserver.c
+++ b/g10/keyserver.c
@@ -1,2080 +1,2089 @@
 /* keyserver.c - generic keyserver code
  * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  *               2009, 2011, 2012 Free Software Foundation, Inc.
  * Copyright (C) 2014 Werner Koch
  *
  * This file is part of GnuPG.
  *
  * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
 #include <ctype.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <assert.h>
 #include <errno.h>
 
 #include "gpg.h"
 #include "iobuf.h"
 #include "filter.h"
 #include "keydb.h"
 #include "status.h"
 #include "exec.h"
 #include "main.h"
 #include "i18n.h"
 #include "ttyio.h"
 #include "options.h"
 #include "packet.h"
 #include "trustdb.h"
 #include "keyserver-internal.h"
 #include "util.h"
 #include "dns-cert.h"
 #include "pka.h"
 #ifdef USE_DNS_SRV
 #include "srv.h"
 #endif
 #include "membuf.h"
 #include "call-dirmngr.h"
 
 #ifdef HAVE_W32_SYSTEM
 /* It seems Vista doesn't grok X_OK and so fails access() tests.
    Previous versions interpreted X_OK as F_OK anyway, so we'll just
    use F_OK directly. */
 #undef X_OK
 #define X_OK F_OK
 #endif /* HAVE_W32_SYSTEM */
 
 struct keyrec
 {
   KEYDB_SEARCH_DESC desc;
   u32 createtime,expiretime;
   int size,flags;
   byte type;
   IOBUF uidbuf;
   unsigned int lines;
 };
 
 /* Parameters for the search line handler.  */
 struct search_line_handler_parm_s
 {
   ctrl_t ctrl;     /* The session control structure.  */
   char *searchstr_disp;  /* Native encoded search string or NULL.  */
   KEYDB_SEARCH_DESC *desc; /* Array with search descriptions.  */
   int count;      /* Number of keys we are currently prepared to
                      handle.  This is the size of the DESC array.  If
                      it is too small, it will grow safely.  */
   int validcount; /* Enable the "Key x-y of z" messages. */
   int nkeys;      /* Number of processed records.  */
   int any_lines;  /* At least one line has been processed.  */
   unsigned int numlines;  /* Counter for displayed lines.  */
   int eof_seen;   /* EOF encountered.  */
   int not_found;  /* Set if no keys have been found.  */
 };
 
 
 enum ks_action {KS_UNKNOWN=0,KS_GET,KS_GETNAME,KS_SEND,KS_SEARCH};
 
 static struct parse_options keyserver_opts[]=
   {
     /* some of these options are not real - just for the help
        message */
     {"max-cert-size",0,NULL,NULL},
     {"include-revoked",0,NULL,N_("include revoked keys in search results")},
     {"include-subkeys",0,NULL,N_("include subkeys when searching by key ID")},
     {"use-temp-files",0,NULL,
      N_("use temporary files to pass data to keyserver helpers")},
     {"keep-temp-files",KEYSERVER_KEEP_TEMP_FILES,NULL,
      N_("do not delete temporary files after using them")},
     {"refresh-add-fake-v3-keyids",KEYSERVER_ADD_FAKE_V3,NULL,
      NULL},
     {"auto-key-retrieve",KEYSERVER_AUTO_KEY_RETRIEVE,NULL,
      N_("automatically retrieve keys when verifying signatures")},
     {"honor-keyserver-url",KEYSERVER_HONOR_KEYSERVER_URL,NULL,
      N_("honor the preferred keyserver URL set on the key")},
     {"honor-pka-record",KEYSERVER_HONOR_PKA_RECORD,NULL,
      N_("honor the PKA record set on a key when retrieving keys")},
     {NULL,0,NULL,NULL}
   };
 
 static gpg_error_t keyserver_get (ctrl_t ctrl,
                                   KEYDB_SEARCH_DESC *desc, int ndesc,
                                   struct keyserver_spec *keyserver,
                                   unsigned char **r_fpr, size_t *r_fprlen);
 static gpg_error_t keyserver_put (ctrl_t ctrl, strlist_t keyspecs,
                                   struct keyserver_spec *keyserver);
 
 
 /* Reasonable guess.  The commonly used test key simon.josefsson.org
    is larger than 32k, thus we need at least this value. */
 #define DEFAULT_MAX_CERT_SIZE 65536
 
 static size_t max_cert_size=DEFAULT_MAX_CERT_SIZE;
 
 static void
 warn_kshelper_option(char *option)
 {
   char *p;
 
   if ((p=strchr (option, '=')))
     *p = 0;
 
   if (!strcmp (option, "ca-cert-file"))
     log_info ("keyserver option '%s' is obsolete; please use "
               "'%s' in dirmngr.conf\n",
               "ca-cert-file", "hkp-cacert");
   else if (!strcmp (option, "check-cert")
            || !strcmp (option, "broken-http-proxy"))
     log_info ("keyserver option '%s' is obsolete\n", option);
 }
 
 
 int
 parse_keyserver_options(char *options)
 {
   int ret=1;
   char *tok;
   char *max_cert=NULL;
 
   keyserver_opts[0].value=&max_cert;
 
   while((tok=optsep(&options)))
     {
       if(tok[0]=='\0')
 	continue;
 
       /* For backwards compatibility.  1.2.x used honor-http-proxy and
 	 there are a good number of documents published that recommend
 	 it. */
       if(ascii_strcasecmp(tok,"honor-http-proxy")==0)
 	tok="http-proxy";
       else if(ascii_strcasecmp(tok,"no-honor-http-proxy")==0)
 	tok="no-http-proxy";
 
       /* We accept quite a few possible options here - some options to
 	 handle specially, the keyserver_options list, and import and
 	 export options that pertain to keyserver operations.  Note
 	 that you must use strncasecmp here as there might be an
 	 =argument attached which will foil the use of strcasecmp. */
 
 #ifdef EXEC_TEMPFILE_ONLY
       if(ascii_strncasecmp(tok,"use-temp-files",14)==0 ||
 	      ascii_strncasecmp(tok,"no-use-temp-files",17)==0)
 	log_info(_("WARNING: keyserver option '%s' is not used"
 		   " on this platform\n"),tok);
 #else
       if(ascii_strncasecmp(tok,"use-temp-files",14)==0)
 	opt.keyserver_options.options|=KEYSERVER_USE_TEMP_FILES;
       else if(ascii_strncasecmp(tok,"no-use-temp-files",17)==0)
 	opt.keyserver_options.options&=~KEYSERVER_USE_TEMP_FILES;
 #endif
       else if(!parse_options(tok,&opt.keyserver_options.options,
 			     keyserver_opts,0)
 	 && !parse_import_options(tok,
 				  &opt.keyserver_options.import_options,0)
 	 && !parse_export_options(tok,
 				  &opt.keyserver_options.export_options,0))
 	{
 	  /* All of the standard options have failed, so the option was
 	     destined for a keyserver plugin as used by GnuPG < 2.1 */
 	  warn_kshelper_option (tok);
 	}
     }
 
   if(max_cert)
     {
       max_cert_size=strtoul(max_cert,(char **)NULL,10);
 
       if(max_cert_size==0)
 	max_cert_size=DEFAULT_MAX_CERT_SIZE;
     }
 
   return ret;
 }
 
 void
 free_keyserver_spec(struct keyserver_spec *keyserver)
 {
   xfree(keyserver->uri);
   xfree(keyserver->scheme);
   xfree(keyserver->auth);
   xfree(keyserver->host);
   xfree(keyserver->port);
   xfree(keyserver->path);
   xfree(keyserver->opaque);
   free_strlist(keyserver->options);
   xfree(keyserver);
 }
 
 /* Return 0 for match */
 static int
 cmp_keyserver_spec(struct keyserver_spec *one,struct keyserver_spec *two)
 {
   if(ascii_strcasecmp(one->scheme,two->scheme)==0)
     {
       if(one->host && two->host && ascii_strcasecmp(one->host,two->host)==0)
 	{
 	  if((one->port && two->port
 	      && ascii_strcasecmp(one->port,two->port)==0)
 	     || (!one->port && !two->port))
 	    return 0;
 	}
       else if(one->opaque && two->opaque
 	      && ascii_strcasecmp(one->opaque,two->opaque)==0)
 	return 0;
     }
 
   return 1;
 }
 
 /* Try and match one of our keyservers.  If we can, return that.  If
    we can't, return our input. */
 struct keyserver_spec *
 keyserver_match(struct keyserver_spec *spec)
 {
   struct keyserver_spec *ks;
 
   for(ks=opt.keyserver;ks;ks=ks->next)
     if(cmp_keyserver_spec(spec,ks)==0)
       return ks;
 
   return spec;
 }
 
 /* TODO: once we cut over to an all-curl world, we don't need this
    parser any longer so it can be removed, or at least moved to
    keyserver/ksutil.c for limited use in gpgkeys_ldap or the like. */
 
 keyserver_spec_t
 parse_keyserver_uri (const char *string,int require_scheme)
 {
   int assume_hkp=0;
   struct keyserver_spec *keyserver;
   const char *idx;
   int count;
   char *uri,*options;
 
   assert(string!=NULL);
 
   keyserver=xmalloc_clear(sizeof(struct keyserver_spec));
 
   uri=xstrdup(string);
 
   options=strchr(uri,' ');
   if(options)
     {
       char *tok;
 
       *options='\0';
       options++;
 
       while((tok=optsep(&options)))
 	warn_kshelper_option (tok);
     }
 
   /* Get the scheme */
 
   for(idx=uri,count=0;*idx && *idx!=':';idx++)
     {
       count++;
 
       /* Do we see the start of an RFC-2732 ipv6 address here?  If so,
 	 there clearly isn't a scheme so get out early. */
       if(*idx=='[')
 	{
 	  /* Was the '[' the first thing in the string?  If not, we
 	     have a mangled scheme with a [ in it so fail. */
 	  if(count==1)
 	    break;
 	  else
 	    goto fail;
 	}
     }
 
   if(count==0)
     goto fail;
 
   if(*idx=='\0' || *idx=='[')
     {
       if(require_scheme)
 	return NULL;
 
       /* Assume HKP if there is no scheme */
       assume_hkp=1;
       keyserver->scheme=xstrdup("hkp");
 
       keyserver->uri=xmalloc(strlen(keyserver->scheme)+3+strlen(uri)+1);
       strcpy(keyserver->uri,keyserver->scheme);
       strcat(keyserver->uri,"://");
       strcat(keyserver->uri,uri);
     }
   else
     {
       int i;
 
       keyserver->uri=xstrdup(uri);
 
       keyserver->scheme=xmalloc(count+1);
 
       /* Force to lowercase */
       for(i=0;i<count;i++)
 	keyserver->scheme[i]=ascii_tolower(uri[i]);
 
       keyserver->scheme[i]='\0';
 
       /* Skip past the scheme and colon */
       uri+=count+1;
     }
 
   if(ascii_strcasecmp(keyserver->scheme,"x-broken-hkp")==0)
     {
       log_info ("keyserver option '%s' is obsolete\n",
                 "x-broken-hkp");
     }
   else if(ascii_strcasecmp(keyserver->scheme,"x-hkp")==0)
     {
       /* Canonicalize this to "hkp" so it works with both the internal
 	 and external keyserver interface. */
       xfree(keyserver->scheme);
       keyserver->scheme=xstrdup("hkp");
     }
 
   if (uri[0]=='/' && uri[1]=='/' && uri[2] == '/')
     {
       /* Three slashes means network path with a default host name.
          This is a hack because it does not crok all possible
          combiantions.  We should better repalce all code bythe parser
          from http.c.  */
       keyserver->path = xstrdup (uri+2);
     }
   else if(assume_hkp || (uri[0]=='/' && uri[1]=='/'))
     {
       /* Two slashes means network path. */
 
       /* Skip over the "//", if any */
       if(!assume_hkp)
 	uri+=2;
 
       /* Do we have userinfo auth data present? */
       for(idx=uri,count=0;*idx && *idx!='@' && *idx!='/';idx++)
 	count++;
 
       /* We found a @ before the slash, so that means everything
 	 before the @ is auth data. */
       if(*idx=='@')
 	{
 	  if(count==0)
 	    goto fail;
 
 	  keyserver->auth=xmalloc(count+1);
 	  strncpy(keyserver->auth,uri,count);
 	  keyserver->auth[count]='\0';
 	  uri+=count+1;
 	}
 
       /* Is it an RFC-2732 ipv6 [literal address] ? */
       if(*uri=='[')
 	{
 	  for(idx=uri+1,count=1;*idx
 		&& ((isascii (*idx) && isxdigit(*idx))
                     || *idx==':' || *idx=='.');idx++)
 	    count++;
 
 	  /* Is the ipv6 literal address terminated? */
 	  if(*idx==']')
 	    count++;
 	  else
 	    goto fail;
 	}
       else
 	for(idx=uri,count=0;*idx && *idx!=':' && *idx!='/';idx++)
 	  count++;
 
       if(count==0)
 	goto fail;
 
       keyserver->host=xmalloc(count+1);
       strncpy(keyserver->host,uri,count);
       keyserver->host[count]='\0';
 
       /* Skip past the host */
       uri+=count;
 
       if(*uri==':')
 	{
 	  /* It would seem to be reasonable to limit the range of the
 	     ports to values between 1-65535, but RFC 1738 and 1808
 	     imply there is no limit.  Of course, the real world has
 	     limits. */
 
 	  for(idx=uri+1,count=0;*idx && *idx!='/';idx++)
 	    {
 	      count++;
 
 	      /* Ports are digits only */
 	      if(!digitp(idx))
 		goto fail;
 	    }
 
 	  keyserver->port=xmalloc(count+1);
 	  strncpy(keyserver->port,uri+1,count);
 	  keyserver->port[count]='\0';
 
 	  /* Skip past the colon and port number */
 	  uri+=1+count;
 	}
 
       /* Everything else is the path */
       if(*uri)
 	keyserver->path=xstrdup(uri);
       else
 	keyserver->path=xstrdup("/");
 
       if(keyserver->path[1])
 	keyserver->flags.direct_uri=1;
     }
   else if(uri[0]!='/')
     {
       /* No slash means opaque.  Just record the opaque blob and get
 	 out. */
       keyserver->opaque=xstrdup(uri);
     }
   else
     {
       /* One slash means absolute path.  We don't need to support that
 	 yet. */
       goto fail;
     }
 
   return keyserver;
 
  fail:
   free_keyserver_spec(keyserver);
 
   return NULL;
 }
 
 struct keyserver_spec *
 parse_preferred_keyserver(PKT_signature *sig)
 {
   struct keyserver_spec *spec=NULL;
   const byte *p;
   size_t plen;
 
   p=parse_sig_subpkt(sig->hashed,SIGSUBPKT_PREF_KS,&plen);
   if(p && plen)
     {
       byte *dupe=xmalloc(plen+1);
 
       memcpy(dupe,p,plen);
       dupe[plen]='\0';
       spec = parse_keyserver_uri (dupe, 1);
       xfree(dupe);
     }
 
   return spec;
 }
 
 static void
 print_keyrec(int number,struct keyrec *keyrec)
 {
   int i;
 
   iobuf_writebyte(keyrec->uidbuf,0);
   iobuf_flush_temp(keyrec->uidbuf);
   es_printf ("(%d)\t%s  ", number, iobuf_get_temp_buffer (keyrec->uidbuf));
 
   if (keyrec->size>0)
     es_printf ("%d bit ", keyrec->size);
 
   if(keyrec->type)
     {
       const char *str;
 
       str = openpgp_pk_algo_name (keyrec->type);
 
       if (str && strcmp (str, "?"))
 	es_printf ("%s ",str);
       else
 	es_printf ("unknown ");
     }
 
   switch(keyrec->desc.mode)
     {
       /* If the keyserver helper gave us a short keyid, we have no
 	 choice but to use it.  Do check --keyid-format to add a 0x if
 	 needed. */
     case KEYDB_SEARCH_MODE_SHORT_KID:
       es_printf ("key %s%08lX",
                  (opt.keyid_format==KF_0xSHORT
                   || opt.keyid_format==KF_0xLONG)?"0x":"",
                  (ulong)keyrec->desc.u.kid[1]);
       break;
 
       /* However, if it gave us a long keyid, we can honor
 	 --keyid-format via keystr(). */
     case KEYDB_SEARCH_MODE_LONG_KID:
       es_printf ("key %s",keystr(keyrec->desc.u.kid));
       break;
 
       /* If it gave us a PGP 2.x fingerprint, not much we can do
 	 beyond displaying it. */
     case KEYDB_SEARCH_MODE_FPR16:
       es_printf ("key ");
       for(i=0;i<16;i++)
 	es_printf ("%02X",keyrec->desc.u.fpr[i]);
       break;
 
       /* If we get a modern fingerprint, we have the most
 	 flexibility. */
     case KEYDB_SEARCH_MODE_FPR20:
       {
 	u32 kid[2];
 	keyid_from_fingerprint(keyrec->desc.u.fpr,20,kid);
 	es_printf("key %s",keystr(kid));
       }
       break;
 
     default:
       BUG();
       break;
     }
 
   if(keyrec->createtime>0)
     {
       es_printf (", ");
       es_printf (_("created: %s"), strtimestamp(keyrec->createtime));
     }
 
   if(keyrec->expiretime>0)
     {
       es_printf (", ");
       es_printf (_("expires: %s"), strtimestamp(keyrec->expiretime));
     }
 
   if (keyrec->flags&1)
     es_printf (" (%s)", _("revoked"));
   if(keyrec->flags&2)
     es_printf (" (%s)", _("disabled"));
   if(keyrec->flags&4)
     es_printf (" (%s)", _("expired"));
 
   es_printf ("\n");
 }
 
 /* Returns a keyrec (which must be freed) once a key is complete, and
    NULL otherwise.  Call with a NULL keystring once key parsing is
    complete to return any unfinished keys. */
 static struct keyrec *
 parse_keyrec(char *keystring)
 {
   /* FIXME: Remove the static and put the data into the parms we use
      for the caller anyway.  */
   static struct keyrec *work=NULL;
   struct keyrec *ret=NULL;
   char *record;
   int i;
 
   if(keystring==NULL)
     {
       if(work==NULL)
 	return NULL;
       else if(work->desc.mode==KEYDB_SEARCH_MODE_NONE)
 	{
 	  xfree(work);
 	  return NULL;
 	}
       else
 	{
 	  ret=work;
 	  work=NULL;
 	  return ret;
 	}
     }
 
   if(work==NULL)
     {
       work=xmalloc_clear(sizeof(struct keyrec));
       work->uidbuf=iobuf_temp();
     }
 
   trim_trailing_ws (keystring, strlen (keystring));
 
   if((record=strsep(&keystring,":"))==NULL)
     return ret;
 
   if(ascii_strcasecmp("pub",record)==0)
     {
       char *tok;
       gpg_error_t err;
 
       if(work->desc.mode)
 	{
 	  ret=work;
 	  work=xmalloc_clear(sizeof(struct keyrec));
 	  work->uidbuf=iobuf_temp();
 	}
 
       if((tok=strsep(&keystring,":"))==NULL)
 	return ret;
 
       err = classify_user_id (tok, &work->desc, 1);
       if (err || (work->desc.mode    != KEYDB_SEARCH_MODE_SHORT_KID
                   && work->desc.mode != KEYDB_SEARCH_MODE_LONG_KID
                   && work->desc.mode != KEYDB_SEARCH_MODE_FPR16
                   && work->desc.mode != KEYDB_SEARCH_MODE_FPR20))
 	{
 	  work->desc.mode=KEYDB_SEARCH_MODE_NONE;
 	  return ret;
 	}
 
       /* Note all items after this are optional.  This allows us to
          have a pub line as simple as pub:keyid and nothing else. */
 
       work->lines++;
 
       if((tok=strsep(&keystring,":"))==NULL)
 	return ret;
 
       work->type=atoi(tok);
 
       if((tok=strsep(&keystring,":"))==NULL)
 	return ret;
 
       work->size=atoi(tok);
 
       if((tok=strsep(&keystring,":"))==NULL)
 	return ret;
 
       if(atoi(tok)<=0)
 	work->createtime=0;
       else
 	work->createtime=atoi(tok);
 
       if((tok=strsep(&keystring,":"))==NULL)
 	return ret;
 
       if(atoi(tok)<=0)
 	work->expiretime=0;
       else
 	{
 	  work->expiretime=atoi(tok);
 	  /* Force the 'e' flag on if this key is expired. */
 	  if(work->expiretime<=make_timestamp())
 	    work->flags|=4;
 	}
 
       if((tok=strsep(&keystring,":"))==NULL)
 	return ret;
 
       while(*tok)
 	switch(*tok++)
 	  {
 	  case 'r':
 	  case 'R':
 	    work->flags|=1;
 	    break;
 
 	  case 'd':
 	  case 'D':
 	    work->flags|=2;
 	    break;
 
 	  case 'e':
 	  case 'E':
 	    work->flags|=4;
 	    break;
 	  }
     }
   else if(ascii_strcasecmp("uid",record)==0 && work->desc.mode)
     {
       char *userid,*tok,*decoded;
 
       if((tok=strsep(&keystring,":"))==NULL)
 	return ret;
 
       if(strlen(tok)==0)
 	return ret;
 
       userid=tok;
 
       /* By definition, de-%-encoding is always smaller than the
          original string so we can decode in place. */
 
       i=0;
 
       while(*tok)
 	if(tok[0]=='%' && tok[1] && tok[2])
 	  {
             int c;
 
 	    userid[i] = (c=hextobyte(&tok[1])) == -1 ? '?' : c;
 	    i++;
 	    tok+=3;
 	  }
 	else
 	  userid[i++]=*tok++;
 
       /* We don't care about the other info provided in the uid: line
          since no keyserver supports marking userids with timestamps
          or revoked/expired/disabled yet. */
 
       /* No need to check for control characters, as utf8_to_native
 	 does this for us. */
 
       decoded=utf8_to_native(userid,i,0);
       if(strlen(decoded)>opt.screen_columns-10)
 	decoded[opt.screen_columns-10]='\0';
       iobuf_writestr(work->uidbuf,decoded);
       xfree(decoded);
       iobuf_writestr(work->uidbuf,"\n\t");
       work->lines++;
     }
 
   /* Ignore any records other than "pri" and "uid" for easy future
      growth. */
 
   return ret;
 }
 
 /* Show a prompt and allow the user to select keys for retrieval.  */
 static gpg_error_t
 show_prompt (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int numdesc,
              int count, const char *search)
 {
   gpg_error_t err;
   char *answer = NULL;
 
   es_fflush (es_stdout);
 
   if (count && opt.command_fd == -1)
     {
       static int from = 1;
       tty_printf ("Keys %d-%d of %d for \"%s\".  ",
                   from, numdesc, count, search);
       from = numdesc + 1;
     }
 
  again:
   err = 0;
   xfree (answer);
   answer = cpr_get_no_help ("keysearch.prompt",
                             _("Enter number(s), N)ext, or Q)uit > "));
   /* control-d */
   if (answer[0]=='\x04')
     {
       tty_printf ("Q\n");
       answer[0] = 'q';
     }
 
   if (answer[0]=='q' || answer[0]=='Q')
     err = gpg_error (GPG_ERR_CANCELED);
   else if (atoi (answer) >= 1 && atoi (answer) <= numdesc)
     {
       char *split = answer;
       char *num;
       int numarray[50];
       int numidx = 0;
       int idx;
 
       while ((num = strsep (&split, " ,")))
 	if (atoi (num) >= 1 && atoi (num) <= numdesc)
           {
             if (numidx >= DIM (numarray))
               {
                 tty_printf ("Too many keys selected\n");
                 goto again;
               }
             numarray[numidx++] = atoi (num);
           }
 
       if (!numidx)
         goto again;
 
       {
         KEYDB_SEARCH_DESC *selarray;
 
         selarray = xtrymalloc (numidx * sizeof *selarray);
         if (!selarray)
           {
             err = gpg_error_from_syserror ();
             goto leave;
           }
         for (idx = 0; idx < numidx; idx++)
           selarray[idx] = desc[numarray[idx]-1];
         err = keyserver_get (ctrl, selarray, numidx, NULL, NULL, NULL);
         xfree (selarray);
       }
     }
 
  leave:
   xfree (answer);
   return err;
 }
 
 
 /* This is a callback used by call-dirmngr.c to process the result of
    KS_SEARCH command.  If SPECIAL is 0, LINE is the actual data line
    received with all escaping removed and guaranteed to be exactly one
    line with stripped LF; an EOF is indicated by LINE passed as NULL.
    If special is 1, the line contains the source of the information
    (usually an URL).  LINE may be modified after return.  */
 static gpg_error_t
 search_line_handler (void *opaque, int special, char *line)
 {
   struct search_line_handler_parm_s *parm = opaque;
   gpg_error_t err = 0;
   struct keyrec *keyrec;
 
   if (special == 1)
     {
       log_info ("data source: %s\n", line);
       return 0;
     }
   else if (special)
     {
       log_debug ("unknown value %d for special search callback", special);
       return 0;
     }
 
   if (parm->eof_seen && line)
     {
       log_debug ("ooops: unexpected data after EOF\n");
       line = NULL;
     }
 
   /* Print the received line.  */
   if (opt.with_colons && line)
     {
       es_printf ("%s\n", line);
     }
 
   /* Look for an info: line.  The only current info: values defined
      are the version and key count. */
   if (line && !parm->any_lines && !ascii_strncasecmp ("info:", line, 5))
     {
       char *str = line + 5;
       char *tok;
 
       if ((tok = strsep (&str, ":")))
         {
           int version;
 
           if (sscanf (tok, "%d", &version) !=1 )
             version = 1;
 
           if (version !=1 )
             {
               log_error (_("invalid keyserver protocol "
                            "(us %d!=handler %d)\n"), 1, version);
               return gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
             }
         }
 
       if ((tok = strsep (&str, ":"))
           && sscanf (tok, "%d", &parm->count) == 1)
         {
           if (!parm->count)
             parm->not_found = 1;/* Server indicated that no items follow.  */
           else if (parm->count < 0)
             parm->count = 10;   /* Bad value - assume something reasonable.  */
           else
             parm->validcount = 1; /* COUNT seems to be okay.  */
         }
 
       parm->any_lines = 1;
       return 0; /* Line processing finished.  */
     }
 
  again:
   if (line)
     keyrec = parse_keyrec (line);
   else
     {
       /* Received EOF - flush data */
       parm->eof_seen = 1;
       keyrec = parse_keyrec (NULL);
       if (!keyrec)
         {
           if (!parm->nkeys)
             parm->not_found = 1;  /* No keys at all.  */
           else
             {
               if (parm->nkeys != parm->count)
                 parm->validcount = 0;
 
               if (!(opt.with_colons && opt.batch))
                 {
                   err = show_prompt (parm->ctrl, parm->desc, parm->nkeys,
                                      parm->validcount? parm->count : 0,
                                      parm->searchstr_disp);
                   return err;
                 }
             }
         }
     }
 
   /* Save the key in the key array.  */
   if (keyrec)
     {
       /* Allocate or enlarge the key array if needed.  */
       if (!parm->desc)
         {
           if (parm->count < 1)
             {
               parm->count = 10;
               parm->validcount = 0;
             }
           parm->desc = xtrymalloc (parm->count * sizeof *parm->desc);
           if (!parm->desc)
             {
               err = gpg_error_from_syserror ();
               iobuf_close (keyrec->uidbuf);
               xfree (keyrec);
               return err;
             }
         }
       else if (parm->nkeys == parm->count)
         {
           /* Keyserver sent more keys than claimed in the info: line. */
           KEYDB_SEARCH_DESC *tmp;
           int newcount = parm->count + 10;
 
           tmp = xtryrealloc (parm->desc, newcount * sizeof *parm->desc);
           if (!tmp)
             {
               err = gpg_error_from_syserror ();
               iobuf_close (keyrec->uidbuf);
               xfree (keyrec);
               return err;
             }
           parm->count = newcount;
           parm->desc = tmp;
           parm->validcount = 0;
         }
 
       parm->desc[parm->nkeys] = keyrec->desc;
 
       if (!opt.with_colons)
         {
           /* SCREEN_LINES - 1 for the prompt. */
           if (parm->numlines + keyrec->lines > opt.screen_lines - 1)
             {
               err = show_prompt (parm->ctrl, parm->desc, parm->nkeys,
                                  parm->validcount ? parm->count:0,
                                  parm->searchstr_disp);
               if (err)
                 return err;
               parm->numlines = 0;
             }
 
           print_keyrec (parm->nkeys+1, keyrec);
         }
 
       parm->numlines += keyrec->lines;
       iobuf_close (keyrec->uidbuf);
       xfree (keyrec);
 
       parm->any_lines = 1;
       parm->nkeys++;
 
       /* If we are here due to a flush after the EOF, run again for
          the last prompt.  Fixme: Make this code better readable. */
       if (parm->eof_seen)
         goto again;
     }
 
   return 0;
 }
 
 
 
 int
 keyserver_export (ctrl_t ctrl, strlist_t users)
 {
   gpg_error_t err;
   strlist_t sl=NULL;
   KEYDB_SEARCH_DESC desc;
   int rc=0;
 
   /* Weed out descriptors that we don't support sending */
   for(;users;users=users->next)
     {
       err = classify_user_id (users->d, &desc, 1);
       if (err || (desc.mode    != KEYDB_SEARCH_MODE_SHORT_KID
                   && desc.mode != KEYDB_SEARCH_MODE_LONG_KID
                   && desc.mode != KEYDB_SEARCH_MODE_FPR16
                   && desc.mode != KEYDB_SEARCH_MODE_FPR20))
 	{
 	  log_error(_("\"%s\" not a key ID: skipping\n"),users->d);
 	  continue;
 	}
       else
 	append_to_strlist(&sl,users->d);
     }
 
   if(sl)
     {
       rc = keyserver_put (ctrl, sl, opt.keyserver);
       free_strlist(sl);
     }
 
   return rc;
 }
 
 
 /* Structure to convey the arg to keyserver_retrieval_screener.  */
 struct ks_retrieval_screener_arg_s
 {
   KEYDB_SEARCH_DESC *desc;
   int ndesc;
 };
 
 
 /* Check whether a key matches the search description.  The function
    returns 0 if the key shall be imported.  */
 static gpg_error_t
 keyserver_retrieval_screener (kbnode_t keyblock, void *opaque)
 {
   struct ks_retrieval_screener_arg_s *arg = opaque;
   KEYDB_SEARCH_DESC *desc = arg->desc;
   int ndesc = arg->ndesc;
   kbnode_t node;
   PKT_public_key *pk;
   int n;
   u32 keyid[2];
   byte fpr[MAX_FINGERPRINT_LEN];
   size_t fpr_len = 0;
 
   /* Secret keys are not expected from a keyserver.  We do not
      care about secret subkeys because the import code takes care
      of skipping them.  Not allowing an import of a public key
      with a secret subkey would make it too easy to inhibit the
      downloading of a public key.  Recall that keyservers do only
      limited checks.  */
   node = find_kbnode (keyblock, PKT_SECRET_KEY);
   if (node)
     return gpg_error (GPG_ERR_GENERAL);   /* Do not import. */
 
   if (!ndesc)
     return 0; /* Okay if no description given.  */
 
   /* Loop over all key packets.  */
   for (node = keyblock; node; node = node->next)
     {
       if (node->pkt->pkttype != PKT_PUBLIC_KEY
           && node->pkt->pkttype != PKT_PUBLIC_SUBKEY)
         continue;
 
       pk = node->pkt->pkt.public_key;
       fingerprint_from_pk (pk, fpr, &fpr_len);
       keyid_from_pk (pk, keyid);
 
       /* Compare requested and returned fingerprints if available. */
       for (n = 0; n < ndesc; n++)
         {
           if (desc[n].mode == KEYDB_SEARCH_MODE_FPR20)
             {
               if (fpr_len == 20 && !memcmp (fpr, desc[n].u.fpr, 20))
                 return 0;
             }
           else if (desc[n].mode == KEYDB_SEARCH_MODE_FPR16)
             {
               if (fpr_len == 16 && !memcmp (fpr, desc[n].u.fpr, 16))
                 return 0;
             }
           else if (desc[n].mode == KEYDB_SEARCH_MODE_LONG_KID)
             {
               if (keyid[0] == desc[n].u.kid[0] && keyid[1] == desc[n].u.kid[1])
                 return 0;
             }
           else if (desc[n].mode == KEYDB_SEARCH_MODE_SHORT_KID)
             {
               if (keyid[1] == desc[n].u.kid[1])
                 return 0;
             }
           else /* No keyid or fingerprint - can't check.  */
             return 0; /* allow import.  */
         }
     }
 
   return gpg_error (GPG_ERR_GENERAL);
 }
 
 
 int
 keyserver_import (ctrl_t ctrl, strlist_t users)
 {
   gpg_error_t err;
   KEYDB_SEARCH_DESC *desc;
   int num=100,count=0;
   int rc=0;
 
   /* Build a list of key ids */
   desc=xmalloc(sizeof(KEYDB_SEARCH_DESC)*num);
 
   for(;users;users=users->next)
     {
       err = classify_user_id (users->d, &desc[count], 1);
       if (err || (desc[count].mode    != KEYDB_SEARCH_MODE_SHORT_KID
                   && desc[count].mode != KEYDB_SEARCH_MODE_LONG_KID
                   && desc[count].mode != KEYDB_SEARCH_MODE_FPR16
                   && desc[count].mode != KEYDB_SEARCH_MODE_FPR20))
 	{
 	  log_error (_("\"%s\" not a key ID: skipping\n"), users->d);
 	  continue;
 	}
 
       count++;
       if(count==num)
 	{
 	  num+=100;
 	  desc=xrealloc(desc,sizeof(KEYDB_SEARCH_DESC)*num);
 	}
     }
 
   if(count>0)
     rc=keyserver_get (ctrl, desc, count, NULL, NULL, NULL);
 
   xfree(desc);
 
   return rc;
 }
 
 
 /* Import all keys that exactly match NAME */
 int
 keyserver_import_name (ctrl_t ctrl, const char *name,
                        unsigned char **fpr, size_t *fprlen,
                        struct keyserver_spec *keyserver)
 {
   KEYDB_SEARCH_DESC desc;
 
   memset (&desc, 0, sizeof desc);
 
   desc.mode = KEYDB_SEARCH_MODE_EXACT;
   desc.u.name = name;
 
   return keyserver_get (ctrl, &desc, 1, keyserver, fpr, fprlen);
 }
 
 
 int
 keyserver_import_fprint (ctrl_t ctrl, const byte *fprint,size_t fprint_len,
 			 struct keyserver_spec *keyserver)
 {
   KEYDB_SEARCH_DESC desc;
 
   memset(&desc,0,sizeof(desc));
 
   if(fprint_len==16)
     desc.mode=KEYDB_SEARCH_MODE_FPR16;
   else if(fprint_len==20)
     desc.mode=KEYDB_SEARCH_MODE_FPR20;
   else
     return -1;
 
   memcpy(desc.u.fpr,fprint,fprint_len);
 
   /* TODO: Warn here if the fingerprint we got doesn't match the one
      we asked for? */
   return keyserver_get (ctrl, &desc, 1, keyserver, NULL, NULL);
 }
 
 int
 keyserver_import_keyid (ctrl_t ctrl,
                         u32 *keyid,struct keyserver_spec *keyserver)
 {
   KEYDB_SEARCH_DESC desc;
 
   memset(&desc,0,sizeof(desc));
 
   desc.mode=KEYDB_SEARCH_MODE_LONG_KID;
   desc.u.kid[0]=keyid[0];
   desc.u.kid[1]=keyid[1];
 
   return keyserver_get (ctrl, &desc,1, keyserver, NULL, NULL);
 }
 
 /* code mostly stolen from do_export_stream */
 static int
 keyidlist(strlist_t users,KEYDB_SEARCH_DESC **klist,int *count,int fakev3)
 {
   int rc=0,ndesc,num=100;
   KBNODE keyblock=NULL,node;
   KEYDB_HANDLE kdbhd;
   KEYDB_SEARCH_DESC *desc;
   strlist_t sl;
 
   *count=0;
 
   *klist=xmalloc(sizeof(KEYDB_SEARCH_DESC)*num);
 
   kdbhd = keydb_new ();
   keydb_disable_caching (kdbhd);  /* We are looping the search.  */
 
   if(!users)
     {
       ndesc = 1;
       desc = xmalloc_clear ( ndesc * sizeof *desc);
       desc[0].mode = KEYDB_SEARCH_MODE_FIRST;
     }
   else
     {
       for (ndesc=0, sl=users; sl; sl = sl->next, ndesc++)
 	;
       desc = xmalloc ( ndesc * sizeof *desc);
 
       for (ndesc=0, sl=users; sl; sl = sl->next)
 	{
           gpg_error_t err;
 	  if (!(err = classify_user_id (sl->d, desc+ndesc, 1)))
 	    ndesc++;
 	  else
 	    log_error (_("key \"%s\" not found: %s\n"),
 		       sl->d, gpg_strerror (err));
 	}
     }
 
-  while (!(rc = keydb_search (kdbhd, desc, ndesc, NULL)))
+  for (;;)
     {
+      rc = keydb_search (kdbhd, desc, ndesc, NULL);
+      if (rc && gpg_err_code (rc) != GPG_ERR_LEGACY_KEY)
+        break;  /* ready.  */
+
       if (!users)
 	desc[0].mode = KEYDB_SEARCH_MODE_NEXT;
 
+      if (gpg_err_code (rc) == GPG_ERR_LEGACY_KEY)
+        continue;
+
       /* read the keyblock */
       rc = keydb_get_keyblock (kdbhd, &keyblock );
       if( rc )
 	{
-	  log_error (_("error reading keyblock: %s\n"), gpg_strerror (rc) );
+          if (gpg_err_code (rc) == GPG_ERR_LEGACY_KEY)
+            continue;
+          log_error (_("error reading keyblock: %s\n"), gpg_strerror (rc) );
 	  goto leave;
 	}
 
       if((node=find_kbnode(keyblock,PKT_PUBLIC_KEY)))
 	{
 	  /* This is to work around a bug in some keyservers (pksd and
              OKS) that calculate v4 RSA keyids as if they were v3 RSA.
              The answer is to refresh both the correct v4 keyid
              (e.g. 99242560) and the fake v3 keyid (e.g. 68FDDBC7).
              This only happens for key refresh using the HKP scheme
              and if the refresh-add-fake-v3-keyids keyserver option is
              set. */
 	  if(fakev3 && is_RSA(node->pkt->pkt.public_key->pubkey_algo) &&
 	     node->pkt->pkt.public_key->version>=4)
 	    {
 	      (*klist)[*count].mode=KEYDB_SEARCH_MODE_LONG_KID;
 	      v3_keyid (node->pkt->pkt.public_key->pkey[0],
                         (*klist)[*count].u.kid);
 	      (*count)++;
 
 	      if(*count==num)
 		{
 		  num+=100;
 		  *klist=xrealloc(*klist,sizeof(KEYDB_SEARCH_DESC)*num);
 		}
 	    }
 
 	  /* v4 keys get full fingerprints.  v3 keys get long keyids.
              This is because it's easy to calculate any sort of keyid
              from a v4 fingerprint, but not a v3 fingerprint. */
 
 	  if(node->pkt->pkt.public_key->version<4)
 	    {
 	      (*klist)[*count].mode=KEYDB_SEARCH_MODE_LONG_KID;
 	      keyid_from_pk(node->pkt->pkt.public_key,
 			    (*klist)[*count].u.kid);
 	    }
 	  else
 	    {
 	      size_t dummy;
 
 	      (*klist)[*count].mode=KEYDB_SEARCH_MODE_FPR20;
 	      fingerprint_from_pk(node->pkt->pkt.public_key,
 				  (*klist)[*count].u.fpr,&dummy);
 	    }
 
 	  /* This is a little hackish, using the skipfncvalue as a
 	     void* pointer to the keyserver spec, but we don't need
 	     the skipfnc here, and it saves having an additional field
 	     for this (which would be wasted space most of the
 	     time). */
 
 	  (*klist)[*count].skipfncvalue=NULL;
 
 	  /* Are we honoring preferred keyservers? */
 	  if(opt.keyserver_options.options&KEYSERVER_HONOR_KEYSERVER_URL)
 	    {
 	      PKT_user_id *uid=NULL;
 	      PKT_signature *sig=NULL;
 
 	      merge_keys_and_selfsig(keyblock);
 
 	      for(node=node->next;node;node=node->next)
 		{
 		  if(node->pkt->pkttype==PKT_USER_ID
 		     && node->pkt->pkt.user_id->is_primary)
 		    uid=node->pkt->pkt.user_id;
 		  else if(node->pkt->pkttype==PKT_SIGNATURE
 			  && node->pkt->pkt.signature->
 			  flags.chosen_selfsig && uid)
 		    {
 		      sig=node->pkt->pkt.signature;
 		      break;
 		    }
 		}
 
 	      /* Try and parse the keyserver URL.  If it doesn't work,
 		 then we end up writing NULL which indicates we are
 		 the same as any other key. */
 	      if(sig)
 		(*klist)[*count].skipfncvalue=parse_preferred_keyserver(sig);
 	    }
 
 	  (*count)++;
 
 	  if(*count==num)
 	    {
 	      num+=100;
 	      *klist=xrealloc(*klist,sizeof(KEYDB_SEARCH_DESC)*num);
 	    }
 	}
     }
 
   if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
     rc = 0;
 
  leave:
   if(rc)
     xfree(*klist);
   xfree(desc);
   keydb_release(kdbhd);
   release_kbnode(keyblock);
 
   return rc;
 }
 
 /* Note this is different than the original HKP refresh.  It allows
    usernames to refresh only part of the keyring. */
 
 int
 keyserver_refresh (ctrl_t ctrl, strlist_t users)
 {
   int rc,count,numdesc,fakev3=0;
   KEYDB_SEARCH_DESC *desc;
   unsigned int options=opt.keyserver_options.import_options;
 
   /* We switch merge-only on during a refresh, as 'refresh' should
      never import new keys, even if their keyids match. */
   opt.keyserver_options.import_options|=IMPORT_MERGE_ONLY;
 
   /* Similarly, we switch on fast-import, since refresh may make
      multiple import sets (due to preferred keyserver URLs).  We don't
      want each set to rebuild the trustdb.  Instead we do it once at
      the end here. */
   opt.keyserver_options.import_options|=IMPORT_FAST;
 
   /* If refresh_add_fake_v3_keyids is on and it's a HKP or MAILTO
      scheme, then enable fake v3 keyid generation. */
   if((opt.keyserver_options.options&KEYSERVER_ADD_FAKE_V3) && opt.keyserver
      && (ascii_strcasecmp(opt.keyserver->scheme,"hkp")==0 ||
 	 ascii_strcasecmp(opt.keyserver->scheme,"mailto")==0))
     fakev3=1;
 
   rc=keyidlist(users,&desc,&numdesc,fakev3);
   if(rc)
     return rc;
 
   count=numdesc;
   if(count>0)
     {
       int i;
 
       /* Try to handle preferred keyserver keys first */
       for(i=0;i<numdesc;i++)
 	{
 	  if(desc[i].skipfncvalue)
 	    {
 	      struct keyserver_spec *keyserver=desc[i].skipfncvalue;
 
 	      /* We use the keyserver structure we parsed out before.
 		 Note that a preferred keyserver without a scheme://
 		 will be interpreted as hkp:// */
 	      rc = keyserver_get (ctrl, &desc[i], 1, keyserver, NULL, NULL);
 	      if(rc)
 		log_info(_("WARNING: unable to refresh key %s"
 			   " via %s: %s\n"),keystr_from_desc(&desc[i]),
 			 keyserver->uri,gpg_strerror (rc));
 	      else
 		{
 		  /* We got it, so mark it as NONE so we don't try and
 		     get it again from the regular keyserver. */
 
 		  desc[i].mode=KEYDB_SEARCH_MODE_NONE;
 		  count--;
 		}
 
 	      free_keyserver_spec(keyserver);
 	    }
 	}
     }
 
   if(count>0)
     {
       if(opt.keyserver)
 	{
 	  if(count==1)
 	    log_info(_("refreshing 1 key from %s\n"),opt.keyserver->uri);
 	  else
 	    log_info(_("refreshing %d keys from %s\n"),
 		     count,opt.keyserver->uri);
 	}
 
       rc=keyserver_get (ctrl, desc, numdesc, NULL, NULL, NULL);
     }
 
   xfree(desc);
 
   opt.keyserver_options.import_options=options;
 
   /* If the original options didn't have fast import, and the trustdb
      is dirty, rebuild. */
   if(!(opt.keyserver_options.import_options&IMPORT_FAST))
     check_or_update_trustdb ();
 
   return rc;
 }
 
 
 /* Search for keys on the keyservers.  The patterns are given in the
    string list TOKENS.  */
 gpg_error_t
 keyserver_search (ctrl_t ctrl, strlist_t tokens)
 {
   gpg_error_t err;
   char *searchstr;
   struct search_line_handler_parm_s parm;
 
   memset (&parm, 0, sizeof parm);
 
   if (!tokens)
     return 0;  /* Return success if no patterns are given.  */
 
   if (!opt.keyserver)
     {
       log_error (_("no keyserver known (use option --keyserver)\n"));
       return gpg_error (GPG_ERR_NO_KEYSERVER);
     }
 
   /* Write global options */
 
   /* for(temp=opt.keyserver_options.other;temp;temp=temp->next) */
   /*   fprintf(spawn->tochild,"OPTION %s\n",temp->d); */
 
   /* Write per-keyserver options */
 
   /* for(temp=keyserver->options;temp;temp=temp->next) */
   /*   fprintf(spawn->tochild,"OPTION %s\n",temp->d); */
 
   {
     membuf_t mb;
     strlist_t item;
 
     init_membuf (&mb, 1024);
     for (item = tokens; item; item = item->next)
     {
       if (item != tokens)
         put_membuf (&mb, " ", 1);
       put_membuf_str (&mb, item->d);
     }
     put_membuf (&mb, "", 1); /* Append Nul.  */
     searchstr = get_membuf (&mb, NULL);
     if (!searchstr)
       {
         err = gpg_error_from_syserror ();
         goto leave;
       }
   }
   /* FIXME: Enable the next line */
   /* log_info (_("searching for \"%s\" from %s\n"), searchstr, keyserver->uri); */
 
   parm.ctrl = ctrl;
   if (searchstr)
     parm.searchstr_disp = utf8_to_native (searchstr, strlen (searchstr), 0);
 
   err = gpg_dirmngr_ks_search (ctrl, searchstr, search_line_handler, &parm);
 
   if (parm.not_found)
     {
       if (parm.searchstr_disp)
         log_info (_("key \"%s\" not found on keyserver\n"),
                   parm.searchstr_disp);
       else
         log_info (_("key not found on keyserver\n"));
     }
 
   if (gpg_err_code (err) == GPG_ERR_NO_KEYSERVER)
     log_error (_("no keyserver known (use option --keyserver)\n"));
   else if (err)
     log_error ("error searching keyserver: %s\n", gpg_strerror (err));
 
   /* switch(ret) */
   /*   { */
   /*   case KEYSERVER_SCHEME_NOT_FOUND: */
   /*     log_error(_("no handler for keyserver scheme '%s'\n"), */
   /*   	    opt.keyserver->scheme); */
   /*     break; */
 
   /*   case KEYSERVER_NOT_SUPPORTED: */
   /*     log_error(_("action '%s' not supported with keyserver " */
   /*   	      "scheme '%s'\n"), "search", opt.keyserver->scheme); */
   /*     break; */
 
   /*   case KEYSERVER_TIMEOUT: */
   /*     log_error(_("keyserver timed out\n")); */
   /*     break; */
 
   /*   case KEYSERVER_INTERNAL_ERROR: */
   /*   default: */
   /*     log_error(_("keyserver internal error\n")); */
   /*     break; */
   /*   } */
 
   /* return gpg_error (GPG_ERR_KEYSERVER); */
 
 
  leave:
   xfree (parm.desc);
   xfree (parm.searchstr_disp);
   xfree(searchstr);
 
   return err;
 }
 
 /* Helper for keyserver_get.  Here we only receive a chunk of the
    description to be processed in one batch.  This is required due to
    the limited number of patterns the dirmngr interface (KS_GET) can
    grok and to limit the amount of temporary required memory.  */
 static gpg_error_t
 keyserver_get_chunk (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc,
                      int *r_ndesc_used,
                      void *stats_handle,
                      struct keyserver_spec *keyserver,
                      unsigned char **r_fpr, size_t *r_fprlen)
 
 {
   gpg_error_t err = 0;
   char **pattern;
   int idx, npat;
   estream_t datastream;
   char *source = NULL;
   size_t linelen;  /* Estimated linelen for KS_GET.  */
   size_t n;
 
 #define MAX_KS_GET_LINELEN 950  /* Somewhat lower than the real limit.  */
 
   *r_ndesc_used = 0;
 
   /* Create an array filled with a search pattern for each key.  The
      array is delimited by a NULL entry.  */
   pattern = xtrycalloc (ndesc+1, sizeof *pattern);
   if (!pattern)
     return gpg_error_from_syserror ();
 
   /* Note that we break the loop as soon as our estimation of the to
      be used line length reaches the limit.  But we do this only if we
      have processed at leas one search requests so that an overlong
      single request will be rejected only later by gpg_dirmngr_ks_get
      but we are sure that R_NDESC_USED has been updated.  This avoids
      a possible indefinite loop.  */
   linelen = 9; /* "KS_GET --" */
   for (npat=idx=0; idx < ndesc; idx++)
     {
       int quiet = 0;
 
       if (desc[idx].mode == KEYDB_SEARCH_MODE_FPR20
           || desc[idx].mode == KEYDB_SEARCH_MODE_FPR16)
         {
           n = 1+2+2*20;
           if (idx && linelen + n > MAX_KS_GET_LINELEN)
             break; /* Declare end of this chunk.  */
           linelen += n;
 
           pattern[npat] = xtrymalloc (n);
           if (!pattern[npat])
             err = gpg_error_from_syserror ();
           else
             {
               strcpy (pattern[npat], "0x");
               bin2hex (desc[idx].u.fpr,
                        desc[idx].mode == KEYDB_SEARCH_MODE_FPR20? 20 : 16,
                        pattern[npat]+2);
               npat++;
             }
         }
       else if(desc[idx].mode == KEYDB_SEARCH_MODE_LONG_KID)
         {
           n = 1+2+16;
           if (idx && linelen + n > MAX_KS_GET_LINELEN)
             break; /* Declare end of this chunk.  */
           linelen += n;
 
           pattern[npat] = xtryasprintf ("0x%08lX%08lX",
                                         (ulong)desc[idx].u.kid[0],
                                         (ulong)desc[idx].u.kid[1]);
           if (!pattern[npat])
             err = gpg_error_from_syserror ();
           else
             npat++;
         }
       else if(desc[idx].mode == KEYDB_SEARCH_MODE_SHORT_KID)
         {
           n = 1+2+8;
           if (idx && linelen + n > MAX_KS_GET_LINELEN)
             break; /* Declare end of this chunk.  */
           linelen += n;
 
           pattern[npat] = xtryasprintf ("0x%08lX", (ulong)desc[idx].u.kid[1]);
           if (!pattern[npat])
             err = gpg_error_from_syserror ();
           else
             npat++;
         }
       else if(desc[idx].mode == KEYDB_SEARCH_MODE_EXACT)
         {
           /* The Dirmngr also uses classify_user_id to detect the type
              of the search string.  By adding the '=' prefix we force
              Dirmngr's KS_GET to consider this an exact search string.
              (In gpg 1.4 and gpg 2.0 the keyserver helpers used the
              KS_GETNAME command to indicate this.)  */
 
           n = 1+1+strlen (desc[idx].u.name);
           if (idx && linelen + n > MAX_KS_GET_LINELEN)
             break; /* Declare end of this chunk.  */
           linelen += n;
 
           pattern[npat] = strconcat ("=", desc[idx].u.name, NULL);
           if (!pattern[npat])
             err = gpg_error_from_syserror ();
           else
             {
               npat++;
               quiet = 1;
             }
         }
       else if (desc[idx].mode == KEYDB_SEARCH_MODE_NONE)
         continue;
       else
         BUG();
 
       if (err)
         {
           for (idx=0; idx < npat; idx++)
             xfree (pattern[idx]);
           xfree (pattern);
           return err;
         }
 
       if (!quiet && keyserver)
         {
           if (keyserver->host)
             log_info (_("requesting key %s from %s server %s\n"),
                       keystr_from_desc (&desc[idx]),
                       keyserver->scheme, keyserver->host);
           else
             log_info (_("requesting key %s from %s\n"),
                       keystr_from_desc (&desc[idx]), keyserver->uri);
         }
     }
 
   /* Remember now many of search items were considered.  Note that
      this is different from NPAT.  */
   *r_ndesc_used = idx;
 
   err = gpg_dirmngr_ks_get (ctrl, pattern, &datastream, &source);
   for (idx=0; idx < npat; idx++)
     xfree (pattern[idx]);
   xfree (pattern);
   if (opt.verbose && source)
     log_info ("data source: %s\n", source);
 
   if (!err)
     {
       struct ks_retrieval_screener_arg_s screenerarg;
 
       /* FIXME: Check whether this comment should be moved to dirmngr.
 
          Slurp up all the key data.  In the future, it might be nice
          to look for KEY foo OUTOFBAND and FAILED indicators.  It's
          harmless to ignore them, but ignoring them does make gpg
          complain about "no valid OpenPGP data found".  One way to do
          this could be to continue parsing this line-by-line and make
          a temp iobuf for each key.  Note that we don't allow the
          import of secret keys from a keyserver.  Keyservers should
          never accept or send them but we better protect against rogue
          keyservers. */
 
       screenerarg.desc = desc;
       screenerarg.ndesc = *r_ndesc_used;
       import_keys_es_stream (ctrl, datastream, stats_handle,
                              r_fpr, r_fprlen,
                              (opt.keyserver_options.import_options
                               | IMPORT_NO_SECKEY),
                              keyserver_retrieval_screener, &screenerarg);
     }
   es_fclose (datastream);
   xfree (source);
 
   return err;
 }
 
 
 /* Retrieve a key from a keyserver.  The search pattern are in
    (DESC,NDESC).  Allowed search modes are keyid, fingerprint, and
    exact searches.  KEYSERVER gives an optional override keyserver. If
    (R_FPR,R_FPRLEN) are not NULL, they may return the fingerprint of a
    single imported key.  */
 static gpg_error_t
 keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc,
                struct keyserver_spec *keyserver,
                unsigned char **r_fpr, size_t *r_fprlen)
 {
   gpg_error_t err;
   void *stats_handle;
   int ndesc_used;
   int any_good = 0;
 
   stats_handle = import_new_stats_handle();
 
   for (;;)
     {
       err = keyserver_get_chunk (ctrl, desc, ndesc, &ndesc_used, stats_handle,
                                  keyserver, r_fpr, r_fprlen);
       if (!err)
         any_good = 1;
       if (err || ndesc_used >= ndesc)
         break; /* Error or all processed.  */
       /* Prepare for the next chunk.  */
       desc += ndesc_used;
       ndesc -= ndesc_used;
     }
 
   if (any_good)
     import_print_stats (stats_handle);
 
   import_release_stats_handle (stats_handle);
   return err;
 }
 
 
 /* Send all keys specified by KEYSPECS to the KEYSERVERS.  */
 static gpg_error_t
 keyserver_put (ctrl_t ctrl, strlist_t keyspecs,
                struct keyserver_spec *keyserver)
 
 {
   gpg_error_t err;
   strlist_t kspec;
 
   if (!keyspecs)
     return 0;  /* Return success if the list is empty.  */
 
   if (!opt.keyserver)
     {
       log_error (_("no keyserver known (use option --keyserver)\n"));
       return gpg_error (GPG_ERR_NO_KEYSERVER);
     }
 
   for (kspec = keyspecs; kspec; kspec = kspec->next)
     {
       void *data;
       size_t datalen;
       kbnode_t keyblock;
 
       err = export_pubkey_buffer (ctrl, kspec->d,
                                   opt.keyserver_options.export_options,
                                   &keyblock, &data, &datalen);
       if (err)
         log_error (_("skipped \"%s\": %s\n"), kspec->d, gpg_strerror (err));
       else
         {
           if (keyserver->host)
             log_info (_("sending key %s to %s server %s\n"),
                       keystr (keyblock->pkt->pkt.public_key->keyid),
                       keyserver->scheme, keyserver->host);
           else
             log_info (_("sending key %s to %s\n"),
                       keystr (keyblock->pkt->pkt.public_key->keyid),
                       keyserver->uri);
 
           err = gpg_dirmngr_ks_put (ctrl, data, datalen, keyblock);
           release_kbnode (keyblock);
           xfree (data);
           if (err)
             {
               write_status_error ("keyserver_send", err);
               log_error (_("keyserver send failed: %s\n"), gpg_strerror (err));
             }
         }
     }
 
 
   return err;
 
 }
 
 
 /* Loop over all URLs in STRLIST and fetch the key at that URL.  Note
    that the fetch operation ignores the configured key servers and
    instead directly retrieves the keys.  */
 int
 keyserver_fetch (ctrl_t ctrl, strlist_t urilist)
 {
   gpg_error_t err;
   strlist_t sl;
   estream_t datastream;
   unsigned int save_options = opt.keyserver_options.import_options;
 
   /* Switch on fast-import, since fetch can handle more than one
      import and we don't want each set to rebuild the trustdb.
      Instead we do it once at the end. */
   opt.keyserver_options.import_options |= IMPORT_FAST;
 
   for (sl=urilist; sl; sl=sl->next)
     {
       if (!opt.quiet)
         log_info (_("requesting key from '%s'\n"), sl->d);
 
       err = gpg_dirmngr_ks_fetch (ctrl, sl->d, &datastream);
       if (!err)
         {
           void *stats_handle;
 
           stats_handle = import_new_stats_handle();
           import_keys_es_stream (ctrl, datastream, stats_handle, NULL, NULL,
                                  opt.keyserver_options.import_options,
                                  NULL, NULL);
 
           import_print_stats (stats_handle);
           import_release_stats_handle (stats_handle);
         }
       else
         log_info (_("WARNING: unable to fetch URI %s: %s\n"),
                   sl->d, gpg_strerror (err));
       es_fclose (datastream);
     }
 
   opt.keyserver_options.import_options = save_options;
 
   /* If the original options didn't have fast import, and the trustdb
      is dirty, rebuild. */
   if (!(opt.keyserver_options.import_options&IMPORT_FAST))
     check_or_update_trustdb ();
 
   return 0;
 }
 
 
 /* Import key in a CERT or pointed to by a CERT */
 int
 keyserver_import_cert (ctrl_t ctrl,
                        const char *name,unsigned char **fpr,size_t *fpr_len)
 {
   gpg_error_t err;
   char *domain,*look,*url;
   estream_t key;
 
 
   look=xstrdup(name);
 
   domain=strrchr(look,'@');
   if(domain)
     *domain='.';
 
   err = get_dns_cert (look, &key, fpr, fpr_len, &url);
   if (err)
     ;
   else if (key)
     {
       int armor_status=opt.no_armor;
 
       /* CERTs are always in binary format */
       opt.no_armor=1;
 
       err = import_keys_es_stream (ctrl, key, NULL, fpr, fpr_len,
                                    (opt.keyserver_options.import_options
                                     | IMPORT_NO_SECKEY),
                                    NULL, NULL);
 
       opt.no_armor=armor_status;
 
       es_fclose (key);
       key = NULL;
     }
   else if (*fpr)
     {
       /* We only consider the IPGP type if a fingerprint was provided.
 	 This lets us select the right key regardless of what a URL
 	 points to, or get the key from a keyserver. */
       if(url)
 	{
 	  struct keyserver_spec *spec;
 
 	  spec = parse_keyserver_uri (url, 1);
 	  if(spec)
 	    {
 	      err = keyserver_import_fprint (ctrl, *fpr,*fpr_len,spec);
 	      free_keyserver_spec(spec);
 	    }
 	}
       else if(opt.keyserver)
 	{
 	  /* If only a fingerprint is provided, try and fetch it from
 	     our --keyserver */
 
 	  err = keyserver_import_fprint (ctrl, *fpr,*fpr_len,opt.keyserver);
 	}
       else
 	log_info(_("no keyserver known (use option --keyserver)\n"));
 
       /* Give a better string here? "CERT fingerprint for \"%s\"
 	 found, but no keyserver" " known (use option
 	 --keyserver)\n" ? */
 
     }
 
   xfree(url);
   xfree(look);
 
   return err;
 }
 
 /* Import key pointed to by a PKA record. Return the requested
    fingerprint in fpr. */
 int
 keyserver_import_pka (ctrl_t ctrl,
                       const char *name,unsigned char **fpr,size_t *fpr_len)
 {
   char *uri;
   int rc = GPG_ERR_NO_PUBKEY;
 
   *fpr = xmalloc (20);
   *fpr_len = 20;
 
   uri = get_pka_info (name, *fpr);
   if (uri && *uri)
     {
       /* An URI is available.  Lookup the key. */
       struct keyserver_spec *spec;
       spec = parse_keyserver_uri (uri, 1);
       if (spec)
 	{
 	  rc = keyserver_import_fprint (ctrl, *fpr, 20, spec);
 	  free_keyserver_spec (spec);
 	}
       xfree (uri);
     }
 
   if (rc)
     {
       xfree(*fpr);
       *fpr = NULL;
     }
 
   return rc;
 }
 
 
 /* Import a key by name using LDAP */
 int
 keyserver_import_ldap (ctrl_t ctrl,
                        const char *name, unsigned char **fpr, size_t *fprlen)
 {
   (void)ctrl;
   (void)name;
   (void)fpr;
   (void)fprlen;
   return gpg_error (GPG_ERR_NOT_IMPLEMENTED); /*FIXME*/
 #if 0
   char *domain;
   struct keyserver_spec *keyserver;
   strlist_t list=NULL;
   int rc,hostlen=1;
 #ifdef USE_DNS_SRV
   struct srventry *srvlist=NULL;
   int srvcount,i;
   char srvname[MAXDNAME];
 #endif
 
   /* Parse out the domain */
   domain=strrchr(name,'@');
   if(!domain)
     return GPG_ERR_GENERAL;
 
   domain++;
 
   keyserver=xmalloc_clear(sizeof(struct keyserver_spec));
   keyserver->scheme=xstrdup("ldap");
   keyserver->host=xmalloc(1);
   keyserver->host[0]='\0';
 
 #ifdef USE_DNS_SRV
   snprintf(srvname,MAXDNAME,"_pgpkey-ldap._tcp.%s",domain);
 
   srvcount=getsrv(srvname,&srvlist);
 
   for(i=0;i<srvcount;i++)
     {
       hostlen+=strlen(srvlist[i].target)+1;
       keyserver->host=xrealloc(keyserver->host,hostlen);
 
       strcat(keyserver->host,srvlist[i].target);
 
       if(srvlist[i].port!=389)
 	{
 	  char port[7];
 
 	  hostlen+=6; /* a colon, plus 5 digits (unsigned 16-bit value) */
 	  keyserver->host=xrealloc(keyserver->host,hostlen);
 
 	  snprintf(port,7,":%u",srvlist[i].port);
 	  strcat(keyserver->host,port);
 	}
 
       strcat(keyserver->host," ");
     }
 
   free(srvlist);
 #endif
 
   /* If all else fails, do the PGP Universal trick of
      ldap://keys.(domain) */
 
   hostlen+=5+strlen(domain);
   keyserver->host=xrealloc(keyserver->host,hostlen);
   strcat(keyserver->host,"keys.");
   strcat(keyserver->host,domain);
 
   append_to_strlist(&list,name);
 
   rc = gpg_error (GPG_ERR_NOT_IMPLEMENTED); /*FIXME*/
        /* keyserver_work (ctrl, KS_GETNAME, list, NULL, */
        /*                 0, fpr, fpr_len, keyserver); */
 
   free_strlist(list);
 
   free_keyserver_spec(keyserver);
 
   return rc;
 #endif
 }
diff --git a/g10/trustdb.c b/g10/trustdb.c
index 84179f0b0..08f6cf4a1 100644
--- a/g10/trustdb.c
+++ b/g10/trustdb.c
@@ -1,1983 +1,1987 @@
 /* trustdb.c
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
  *               2008, 2012 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
  * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
 
 #ifndef DISABLE_REGEX
 #include <sys/types.h>
 #include <regex.h>
 #endif /* !DISABLE_REGEX */
 
 #include "gpg.h"
 #include "status.h"
 #include "iobuf.h"
 #include "keydb.h"
 #include "util.h"
 #include "options.h"
 #include "packet.h"
 #include "main.h"
 #include "i18n.h"
 #include "tdbio.h"
 #include "trustdb.h"
 
 
 typedef struct key_item **KeyHashTable; /* see new_key_hash_table() */
 
 /*
  * Structure to keep track of keys, this is used as an array wherre
  * the item right after the last one has a keyblock set to NULL.
  * Maybe we can drop this thing and replace it by key_item
  */
 struct key_array
 {
   KBNODE keyblock;
 };
 
 
 /* Control information for the trust DB.  */
 static struct
 {
   int init;
   int level;
   char *dbname;
   int no_trustdb;
 } trustdb_args;
 
 /* Some globals.  */
 static struct key_item *user_utk_list; /* temp. used to store --trusted-keys */
 static struct key_item *utk_list;      /* all ultimately trusted keys */
 
 static int pending_check_trustdb;
 
 static int validate_keys (int interactive);
 
 
 /**********************************************
  ************* some helpers *******************
  **********************************************/
 
 static struct key_item *
 new_key_item (void)
 {
   struct key_item *k;
 
   k = xmalloc_clear (sizeof *k);
   return k;
 }
 
 static void
 release_key_items (struct key_item *k)
 {
   struct key_item *k2;
 
   for (; k; k = k2)
     {
       k2 = k->next;
       xfree (k->trust_regexp);
       xfree (k);
     }
 }
 
 /*
  * For fast keylook up we need a hash table.  Each byte of a KeyIDs
  * should be distributed equally over the 256 possible values (except
  * for v3 keyIDs but we consider them as not important here). So we
  * can just use 10 bits to index a table of 1024 key items.
  * Possible optimization: Don not use key_items but other hash_table when the
  * duplicates lists gets too large.
  */
 static KeyHashTable
 new_key_hash_table (void)
 {
   struct key_item **tbl;
 
   tbl = xmalloc_clear (1024 * sizeof *tbl);
   return tbl;
 }
 
 static void
 release_key_hash_table (KeyHashTable tbl)
 {
   int i;
 
   if (!tbl)
     return;
   for (i=0; i < 1024; i++)
     release_key_items (tbl[i]);
   xfree (tbl);
 }
 
 /*
  * Returns: True if the keyID is in the given hash table
  */
 static int
 test_key_hash_table (KeyHashTable tbl, u32 *kid)
 {
   struct key_item *k;
 
   for (k = tbl[(kid[1] & 0x03ff)]; k; k = k->next)
     if (k->kid[0] == kid[0] && k->kid[1] == kid[1])
       return 1;
   return 0;
 }
 
 /*
  * Add a new key to the hash table.  The key is identified by its key ID.
  */
 static void
 add_key_hash_table (KeyHashTable tbl, u32 *kid)
 {
   struct key_item *k, *kk;
 
   for (k = tbl[(kid[1] & 0x03ff)]; k; k = k->next)
     if (k->kid[0] == kid[0] && k->kid[1] == kid[1])
       return; /* already in table */
 
   kk = new_key_item ();
   kk->kid[0] = kid[0];
   kk->kid[1] = kid[1];
   kk->next = tbl[(kid[1] & 0x03ff)];
   tbl[(kid[1] & 0x03ff)] = kk;
 }
 
 /*
  * Release a key_array
  */
 static void
 release_key_array ( struct key_array *keys )
 {
     struct key_array *k;
 
     if (keys) {
         for (k=keys; k->keyblock; k++)
             release_kbnode (k->keyblock);
         xfree (keys);
     }
 }
 
 
 /*********************************************
  **********  Initialization  *****************
  *********************************************/
 
 
 
 /*
  * Used to register extra ultimately trusted keys - this has to be done
  * before initializing the validation module.
  * FIXME: Should be replaced by a function to add those keys to the trustdb.
  */
 void
 tdb_register_trusted_keyid (u32 *keyid)
 {
   struct key_item *k;
 
   k = new_key_item ();
   k->kid[0] = keyid[0];
   k->kid[1] = keyid[1];
   k->next = user_utk_list;
   user_utk_list = k;
 }
 
 void
 tdb_register_trusted_key( const char *string )
 {
   gpg_error_t err;
   KEYDB_SEARCH_DESC desc;
 
   err = classify_user_id (string, &desc, 1);
   if (err || desc.mode != KEYDB_SEARCH_MODE_LONG_KID )
     {
       log_error(_("'%s' is not a valid long keyID\n"), string );
       return;
     }
 
   register_trusted_keyid(desc.u.kid);
 }
 
 /*
  * Helper to add a key to the global list of ultimately trusted keys.
  * Retruns: true = inserted, false = already in in list.
  */
 static int
 add_utk (u32 *kid)
 {
   struct key_item *k;
 
   for (k = utk_list; k; k = k->next)
     {
       if (k->kid[0] == kid[0] && k->kid[1] == kid[1])
         {
           return 0;
         }
     }
 
   k = new_key_item ();
   k->kid[0] = kid[0];
   k->kid[1] = kid[1];
   k->ownertrust = TRUST_ULTIMATE;
   k->next = utk_list;
   utk_list = k;
   if( opt.verbose > 1 )
     log_info(_("key %s: accepted as trusted key\n"), keystr(kid));
   return 1;
 }
 
 
 /****************
  * Verify that all our secret keys are usable and put them into the utk_list.
  */
 static void
 verify_own_keys(void)
 {
   TRUSTREC rec;
   ulong recnum;
   int rc;
   struct key_item *k;
 
   if (utk_list)
     return;
 
   /* scan the trustdb to find all ultimately trusted keys */
   for (recnum=1; !tdbio_read_record (recnum, &rec, 0); recnum++ )
     {
       if ( rec.rectype == RECTYPE_TRUST
            && (rec.r.trust.ownertrust & TRUST_MASK) == TRUST_ULTIMATE)
         {
             byte *fpr = rec.r.trust.fingerprint;
             int fprlen;
             u32 kid[2];
 
             /* Problem: We do only use fingerprints in the trustdb but
              * we need the keyID here to indetify the key; we can only
              * use that ugly hack to distinguish between 16 and 20
              * butes fpr - it does not work always so we better change
              * the whole validation code to only work with
              * fingerprints */
             fprlen = (!fpr[16] && !fpr[17] && !fpr[18] && !fpr[19])? 16:20;
             keyid_from_fingerprint (fpr, fprlen, kid);
             if (!add_utk (kid))
 	      log_info(_("key %s occurs more than once in the trustdb\n"),
 		       keystr(kid));
         }
     }
 
   /* Put any --trusted-key keys into the trustdb */
   for (k = user_utk_list; k; k = k->next)
     {
       if ( add_utk (k->kid) )
         { /* not yet in trustDB as ultimately trusted */
           PKT_public_key pk;
 
           memset (&pk, 0, sizeof pk);
           rc = get_pubkey (&pk, k->kid);
           if (rc)
 	    log_info(_("key %s: no public key for trusted key - skipped\n"),
 		     keystr(k->kid));
           else
 	    {
 	      tdb_update_ownertrust (&pk,
                                      ((tdb_get_ownertrust (&pk) & ~TRUST_MASK)
                                       | TRUST_ULTIMATE ));
 	      release_public_key_parts (&pk);
 	    }
 
           log_info (_("key %s marked as ultimately trusted\n"),keystr(k->kid));
         }
     }
 
   /* release the helper table table */
   release_key_items (user_utk_list);
   user_utk_list = NULL;
   return;
 }
 
 
 /*********************************************
  *********** TrustDB stuff *******************
  *********************************************/
 
 /*
  * Read a record but die if it does not exist
  */
 static void
 read_record (ulong recno, TRUSTREC *rec, int rectype )
 {
   int rc = tdbio_read_record (recno, rec, rectype);
   if (rc)
     {
       log_error(_("trust record %lu, req type %d: read failed: %s\n"),
                 recno, rec->rectype, gpg_strerror (rc) );
       tdbio_invalid();
     }
   if (rectype != rec->rectype)
     {
       log_error(_("trust record %lu is not of requested type %d\n"),
                 rec->recnum, rectype);
       tdbio_invalid();
     }
 }
 
 /*
  * Write a record and die on error
  */
 static void
 write_record (TRUSTREC *rec)
 {
   int rc = tdbio_write_record (rec);
   if (rc)
     {
       log_error(_("trust record %lu, type %d: write failed: %s\n"),
 			    rec->recnum, rec->rectype, gpg_strerror (rc) );
       tdbio_invalid();
     }
 }
 
 /*
  * sync the TrustDb and die on error
  */
 static void
 do_sync(void)
 {
     int rc = tdbio_sync ();
     if(rc)
       {
         log_error (_("trustdb: sync failed: %s\n"), gpg_strerror (rc) );
         g10_exit(2);
       }
 }
 
 static const char *
 trust_model_string(void)
 {
   switch(opt.trust_model)
     {
     case TM_CLASSIC:  return "classic";
     case TM_PGP:      return "PGP";
     case TM_EXTERNAL: return "external";
     case TM_ALWAYS:   return "always";
     case TM_DIRECT:   return "direct";
     default:          return "unknown";
     }
 }
 
 /****************
  * Perform some checks over the trustdb
  *  level 0: only open the db
  *	  1: used for initial program startup
  */
 int
 setup_trustdb( int level, const char *dbname )
 {
     /* just store the args */
     if( trustdb_args.init )
 	return 0;
     trustdb_args.level = level;
     trustdb_args.dbname = dbname? xstrdup(dbname): NULL;
     return 0;
 }
 
 void
 how_to_fix_the_trustdb ()
 {
   const char *name = trustdb_args.dbname;
 
   if (!name)
     name = "trustdb.gpg";
 
   log_info (_("You may try to re-create the trustdb using the commands:\n"));
   log_info ("  cd %s\n", default_homedir ());
   log_info ("  gpg2 --export-ownertrust > otrust.tmp\n");
 #ifdef HAVE_W32_SYSTEM
   log_info ("  del %s\n", name);
 #else
   log_info ("  rm %s\n", name);
 #endif
   log_info ("  gpg2 --import-ownertrust < otrust.tmp\n");
   log_info (_("If that does not work, please consult the manual\n"));
 }
 
 
 void
 init_trustdb ()
 {
   int level = trustdb_args.level;
   const char* dbname = trustdb_args.dbname;
 
   if( trustdb_args.init )
     return;
 
   trustdb_args.init = 1;
 
   if(level==0 || level==1)
     {
       int rc = tdbio_set_dbname( dbname, !!level, &trustdb_args.no_trustdb);
       if( rc )
 	log_fatal("can't init trustdb: %s\n", gpg_strerror (rc) );
     }
   else
     BUG();
 
   if(opt.trust_model==TM_AUTO)
     {
       /* Try and set the trust model off of whatever the trustdb says
 	 it is. */
       opt.trust_model=tdbio_read_model();
 
       /* Sanity check this ;) */
       if(opt.trust_model!=TM_CLASSIC
 	 && opt.trust_model!=TM_PGP
 	 && opt.trust_model!=TM_EXTERNAL)
 	{
 	  log_info(_("unable to use unknown trust model (%d) - "
 		     "assuming %s trust model\n"),opt.trust_model,"PGP");
 	  opt.trust_model=TM_PGP;
 	}
 
       if(opt.verbose)
 	log_info(_("using %s trust model\n"),trust_model_string());
     }
 
   if(opt.trust_model==TM_PGP || opt.trust_model==TM_CLASSIC)
     {
       /* Verify the list of ultimately trusted keys and move the
 	 --trusted-keys list there as well. */
       if(level==1)
 	verify_own_keys();
 
       if(!tdbio_db_matches_options())
 	pending_check_trustdb=1;
     }
 }
 
 
 /****************
  * Recreate the WoT but do not ask for new ownertrusts.  Special
  * feature: In batch mode and without a forced yes, this is only done
  * when a check is due.  This can be used to run the check from a crontab
  */
 void
 check_trustdb ()
 {
   init_trustdb();
   if(opt.trust_model==TM_PGP || opt.trust_model==TM_CLASSIC)
     {
       if (opt.batch && !opt.answer_yes)
 	{
 	  ulong scheduled;
 
 	  scheduled = tdbio_read_nextcheck ();
 	  if (!scheduled)
 	    {
 	      log_info (_("no need for a trustdb check\n"));
 	      return;
 	    }
 
 	  if (scheduled > make_timestamp ())
 	    {
 	      log_info (_("next trustdb check due at %s\n"),
 			strtimestamp (scheduled));
 	      return;
 	    }
 	}
 
       validate_keys (0);
     }
   else
     log_info (_("no need for a trustdb check with '%s' trust model\n"),
 	      trust_model_string());
 }
 
 
 /*
  * Recreate the WoT.
  */
 void
 update_trustdb()
 {
   init_trustdb();
   if(opt.trust_model==TM_PGP || opt.trust_model==TM_CLASSIC)
     validate_keys (1);
   else
     log_info (_("no need for a trustdb update with '%s' trust model\n"),
 	      trust_model_string());
 }
 
 void
 tdb_revalidation_mark (void)
 {
   init_trustdb();
   if (trustdb_args.no_trustdb && opt.trust_model == TM_ALWAYS)
     return;
 
   /* We simply set the time for the next check to 1 (far back in 1970)
      so that a --update-trustdb will be scheduled.  */
   if (tdbio_write_nextcheck (1))
     do_sync ();
   pending_check_trustdb = 1;
 }
 
 int
 trustdb_pending_check(void)
 {
   return pending_check_trustdb;
 }
 
 /* If the trustdb is dirty, and we're interactive, update it.
    Otherwise, check it unless no-auto-check-trustdb is set. */
 void
 tdb_check_or_update (void)
 {
   if(trustdb_pending_check())
     {
       if(opt.interactive)
 	update_trustdb();
       else if(!opt.no_auto_check_trustdb)
 	check_trustdb();
     }
 }
 
 void
 read_trust_options(byte *trust_model,ulong *created,ulong *nextcheck,
 		   byte *marginals,byte *completes,byte *cert_depth,
 		   byte *min_cert_level)
 {
   TRUSTREC opts;
 
   init_trustdb();
   if (trustdb_args.no_trustdb && opt.trust_model == TM_ALWAYS)
     memset (&opts, 0, sizeof opts);
   else
     read_record (0, &opts, RECTYPE_VER);
 
   if(trust_model)
     *trust_model=opts.r.ver.trust_model;
   if(created)
     *created=opts.r.ver.created;
   if(nextcheck)
     *nextcheck=opts.r.ver.nextcheck;
   if(marginals)
     *marginals=opts.r.ver.marginals;
   if(completes)
     *completes=opts.r.ver.completes;
   if(cert_depth)
     *cert_depth=opts.r.ver.cert_depth;
   if(min_cert_level)
     *min_cert_level=opts.r.ver.min_cert_level;
 }
 
 /***********************************************
  ***********  Ownertrust et al. ****************
  ***********************************************/
 
 static int
 read_trust_record (PKT_public_key *pk, TRUSTREC *rec)
 {
   int rc;
 
   init_trustdb();
   rc = tdbio_search_trust_bypk (pk, rec);
   if (rc == -1)
     return -1; /* no record yet */
   if (rc)
     {
       log_error ("trustdb: searching trust record failed: %s\n",
                  gpg_strerror (rc));
       return rc;
     }
 
   if (rec->rectype != RECTYPE_TRUST)
     {
       log_error ("trustdb: record %lu is not a trust record\n",
                  rec->recnum);
       return GPG_ERR_TRUSTDB;
     }
 
   return 0;
 }
 
 /****************
  * Return the assigned ownertrust value for the given public key.
  * The key should be the primary key.
  */
 unsigned int
 tdb_get_ownertrust ( PKT_public_key *pk)
 {
   TRUSTREC rec;
   int rc;
 
   if (trustdb_args.no_trustdb && opt.trust_model == TM_ALWAYS)
     return TRUST_UNKNOWN;
 
   rc = read_trust_record (pk, &rec);
   if (rc == -1)
     return TRUST_UNKNOWN; /* no record yet */
   if (rc)
     {
       tdbio_invalid ();
       return rc; /* actually never reached */
     }
 
   return rec.r.trust.ownertrust;
 }
 
 
 unsigned int
 tdb_get_min_ownertrust (PKT_public_key *pk)
 {
   TRUSTREC rec;
   int rc;
 
   if (trustdb_args.no_trustdb && opt.trust_model == TM_ALWAYS)
     return TRUST_UNKNOWN;
 
   rc = read_trust_record (pk, &rec);
   if (rc == -1)
     return TRUST_UNKNOWN; /* no record yet */
   if (rc)
     {
       tdbio_invalid ();
       return rc; /* actually never reached */
     }
 
   return rec.r.trust.min_ownertrust;
 }
 
 
 /*
  * Set the trust value of the given public key to the new value.
  * The key should be a primary one.
  */
 void
 tdb_update_ownertrust (PKT_public_key *pk, unsigned int new_trust )
 {
   TRUSTREC rec;
   int rc;
 
   if (trustdb_args.no_trustdb && opt.trust_model == TM_ALWAYS)
     return;
 
   rc = read_trust_record (pk, &rec);
   if (!rc)
     {
       if (DBG_TRUST)
         log_debug ("update ownertrust from %u to %u\n",
                    (unsigned int)rec.r.trust.ownertrust, new_trust );
       if (rec.r.trust.ownertrust != new_trust)
         {
           rec.r.trust.ownertrust = new_trust;
           write_record( &rec );
           tdb_revalidation_mark ();
           do_sync ();
         }
     }
   else if (rc == -1)
     { /* no record yet - create a new one */
       size_t dummy;
 
       if (DBG_TRUST)
         log_debug ("insert ownertrust %u\n", new_trust );
 
       memset (&rec, 0, sizeof rec);
       rec.recnum = tdbio_new_recnum ();
       rec.rectype = RECTYPE_TRUST;
       fingerprint_from_pk (pk, rec.r.trust.fingerprint, &dummy);
       rec.r.trust.ownertrust = new_trust;
       write_record (&rec);
       tdb_revalidation_mark ();
       do_sync ();
       rc = 0;
     }
   else
     {
       tdbio_invalid ();
     }
 }
 
 static void
 update_min_ownertrust (u32 *kid, unsigned int new_trust )
 {
   PKT_public_key *pk;
   TRUSTREC rec;
   int rc;
 
   if (trustdb_args.no_trustdb && opt.trust_model == TM_ALWAYS)
     return;
 
   pk = xmalloc_clear (sizeof *pk);
   rc = get_pubkey (pk, kid);
   if (rc)
     {
       log_error(_("public key %s not found: %s\n"),keystr(kid),gpg_strerror (rc));
       return;
     }
 
   rc = read_trust_record (pk, &rec);
   if (!rc)
     {
       if (DBG_TRUST)
         log_debug ("key %08lX%08lX: update min_ownertrust from %u to %u\n",
                    (ulong)kid[0],(ulong)kid[1],
 		   (unsigned int)rec.r.trust.min_ownertrust,
 		   new_trust );
       if (rec.r.trust.min_ownertrust != new_trust)
         {
           rec.r.trust.min_ownertrust = new_trust;
           write_record( &rec );
           tdb_revalidation_mark ();
           do_sync ();
         }
     }
   else if (rc == -1)
     { /* no record yet - create a new one */
       size_t dummy;
 
       if (DBG_TRUST)
         log_debug ("insert min_ownertrust %u\n", new_trust );
 
       memset (&rec, 0, sizeof rec);
       rec.recnum = tdbio_new_recnum ();
       rec.rectype = RECTYPE_TRUST;
       fingerprint_from_pk (pk, rec.r.trust.fingerprint, &dummy);
       rec.r.trust.min_ownertrust = new_trust;
       write_record (&rec);
       tdb_revalidation_mark ();
       do_sync ();
       rc = 0;
     }
   else
     {
       tdbio_invalid ();
     }
 }
 
 
 /* Clear the ownertrust and min_ownertrust values.  Return true if a
    change actually happened. */
 int
 tdb_clear_ownertrusts (PKT_public_key *pk)
 {
   TRUSTREC rec;
   int rc;
 
   init_trustdb ();
 
   if (trustdb_args.no_trustdb && opt.trust_model == TM_ALWAYS)
     return 0;
 
   rc = read_trust_record (pk, &rec);
   if (!rc)
     {
       if (DBG_TRUST)
 	{
 	  log_debug ("clearing ownertrust (old value %u)\n",
 		     (unsigned int)rec.r.trust.ownertrust);
 	  log_debug ("clearing min_ownertrust (old value %u)\n",
 		     (unsigned int)rec.r.trust.min_ownertrust);
 	}
       if (rec.r.trust.ownertrust || rec.r.trust.min_ownertrust)
         {
           rec.r.trust.ownertrust = 0;
           rec.r.trust.min_ownertrust = 0;
           write_record( &rec );
           tdb_revalidation_mark ();
           do_sync ();
           return 1;
         }
     }
   else if (rc != -1)
     {
       tdbio_invalid ();
     }
   return 0;
 }
 
 /*
  * Note: Caller has to do a sync
  */
 static void
 update_validity (PKT_public_key *pk, PKT_user_id *uid,
                  int depth, int validity)
 {
   TRUSTREC trec, vrec;
   int rc;
   ulong recno;
 
   namehash_from_uid(uid);
 
   rc = read_trust_record (pk, &trec);
   if (rc && rc != -1)
     {
       tdbio_invalid ();
       return;
     }
   if (rc == -1) /* no record yet - create a new one */
     {
       size_t dummy;
 
       rc = 0;
       memset (&trec, 0, sizeof trec);
       trec.recnum = tdbio_new_recnum ();
       trec.rectype = RECTYPE_TRUST;
       fingerprint_from_pk (pk, trec.r.trust.fingerprint, &dummy);
       trec.r.trust.ownertrust = 0;
       }
 
   /* locate an existing one */
   recno = trec.r.trust.validlist;
   while (recno)
     {
       read_record (recno, &vrec, RECTYPE_VALID);
       if ( !memcmp (vrec.r.valid.namehash, uid->namehash, 20) )
         break;
       recno = vrec.r.valid.next;
     }
 
   if (!recno) /* insert a new validity record */
     {
       memset (&vrec, 0, sizeof vrec);
       vrec.recnum = tdbio_new_recnum ();
       vrec.rectype = RECTYPE_VALID;
       memcpy (vrec.r.valid.namehash, uid->namehash, 20);
       vrec.r.valid.next = trec.r.trust.validlist;
       trec.r.trust.validlist = vrec.recnum;
     }
   vrec.r.valid.validity = validity;
   vrec.r.valid.full_count = uid->help_full_count;
   vrec.r.valid.marginal_count = uid->help_marginal_count;
   write_record (&vrec);
   trec.r.trust.depth = depth;
   write_record (&trec);
 }
 
 
 /***********************************************
  *********  Query trustdb values  **************
  ***********************************************/
 
 /* Return true if key is disabled.  Note that this is usually used via
    the pk_is_disabled macro.  */
 int
 tdb_cache_disabled_value (PKT_public_key *pk)
 {
   int rc;
   TRUSTREC trec;
   int disabled = 0;
 
   if (pk->flags.disabled_valid)
     return pk->flags.disabled;
 
   init_trustdb();
 
   if (trustdb_args.no_trustdb)
     return 0;  /* No trustdb => not disabled.  */
 
   rc = read_trust_record (pk, &trec);
   if (rc && rc != -1)
     {
       tdbio_invalid ();
       goto leave;
     }
   if (rc == -1) /* no record found, so assume not disabled */
     goto leave;
 
   if (trec.r.trust.ownertrust & TRUST_FLAG_DISABLED)
     disabled = 1;
 
   /* Cache it for later so we don't need to look at the trustdb every
      time */
   pk->flags.disabled = disabled;
   pk->flags.disabled_valid = 1;
 
  leave:
    return disabled;
 }
 
 
 void
 tdb_check_trustdb_stale (void)
 {
   static int did_nextcheck=0;
 
   init_trustdb ();
 
   if (trustdb_args.no_trustdb)
     return;  /* No trustdb => can't be stale.  */
 
   if (!did_nextcheck
       && (opt.trust_model==TM_PGP || opt.trust_model==TM_CLASSIC))
     {
       ulong scheduled;
 
       did_nextcheck = 1;
       scheduled = tdbio_read_nextcheck ();
       if ((scheduled && scheduled <= make_timestamp ())
 	  || pending_check_trustdb)
         {
           if (opt.no_auto_check_trustdb)
             {
               pending_check_trustdb = 1;
               log_info (_("please do a --check-trustdb\n"));
             }
           else
             {
               log_info (_("checking the trustdb\n"));
               validate_keys (0);
             }
         }
     }
 }
 
 /*
  * Return the validity information for PK.  This is the core of
  * get_validity.
  */
 unsigned int
 tdb_get_validity_core (PKT_public_key *pk, PKT_user_id *uid,
                        PKT_public_key *main_pk)
 {
   TRUSTREC trec, vrec;
   int rc;
   ulong recno;
   unsigned int validity;
 
   init_trustdb ();
 
   /* If we have no trustdb (which also means it has not been created)
      and the trust-model is always, we don't know the validity -
      return immediately.  If we won't do that the tdbio code would try
      to open the trustdb and run into a fatal error.  */
   if (trustdb_args.no_trustdb && opt.trust_model == TM_ALWAYS)
     return TRUST_UNKNOWN;
 
   check_trustdb_stale();
 
   if(opt.trust_model==TM_DIRECT)
     {
       /* Note that this happens BEFORE any user ID stuff is checked.
 	 The direct trust model applies to keys as a whole. */
       validity = tdb_get_ownertrust (main_pk);
       goto leave;
     }
 
   rc = read_trust_record (main_pk, &trec);
   if (rc && rc != -1)
     {
       tdbio_invalid ();
       return 0;
     }
   if (rc == -1) /* no record found */
     {
       validity = TRUST_UNKNOWN;
       goto leave;
     }
 
   /* loop over all user IDs */
   recno = trec.r.trust.validlist;
   validity = 0;
   while (recno)
     {
       read_record (recno, &vrec, RECTYPE_VALID);
 
       if(uid)
 	{
 	  /* If a user ID is given we return the validity for that
 	     user ID ONLY.  If the namehash is not found, then there
 	     is no validity at all (i.e. the user ID wasn't
 	     signed). */
 	  if(memcmp(vrec.r.valid.namehash,uid->namehash,20)==0)
 	    {
 	      validity=(vrec.r.valid.validity & TRUST_MASK);
 	      break;
 	    }
 	}
       else
 	{
 	  /* If no namehash is given, we take the maximum validity
 	     over all user IDs */
 	  if ( validity < (vrec.r.valid.validity & TRUST_MASK) )
 	    validity = (vrec.r.valid.validity & TRUST_MASK);
 	}
 
       recno = vrec.r.valid.next;
     }
 
   if ( (trec.r.trust.ownertrust & TRUST_FLAG_DISABLED) )
     {
       validity |= TRUST_FLAG_DISABLED;
       pk->flags.disabled = 1;
     }
   else
     pk->flags.disabled = 0;
   pk->flags.disabled_valid = 1;
 
  leave:
   if (pending_check_trustdb)
     validity |= TRUST_FLAG_PENDING_CHECK;
 
   return validity;
 }
 
 
 static void
 get_validity_counts (PKT_public_key *pk, PKT_user_id *uid)
 {
   TRUSTREC trec, vrec;
   ulong recno;
 
   if(pk==NULL || uid==NULL)
     BUG();
 
   namehash_from_uid(uid);
 
   uid->help_marginal_count=uid->help_full_count=0;
 
   init_trustdb ();
 
   if(read_trust_record (pk, &trec)!=0)
     return;
 
   /* loop over all user IDs */
   recno = trec.r.trust.validlist;
   while (recno)
     {
       read_record (recno, &vrec, RECTYPE_VALID);
 
       if(memcmp(vrec.r.valid.namehash,uid->namehash,20)==0)
 	{
 	  uid->help_marginal_count=vrec.r.valid.marginal_count;
 	  uid->help_full_count=vrec.r.valid.full_count;
 	  /*  printf("Fetched marginal %d, full %d\n",uid->help_marginal_count,uid->help_full_count); */
 	  break;
 	}
 
       recno = vrec.r.valid.next;
     }
 }
 
 void
 list_trust_path( const char *username )
 {
   (void)username;
 }
 
 /****************
  * Enumerate all keys, which are needed to build all trust paths for
  * the given key.  This function does not return the key itself or
  * the ultimate key (the last point in cerificate chain).  Only
  * certificate chains which ends up at an ultimately trusted key
  * are listed.	If ownertrust or validity is not NULL, the corresponding
  * value for the returned LID is also returned in these variable(s).
  *
  *  1) create a void pointer and initialize it to NULL
  *  2) pass this void pointer by reference to this function.
  *     Set lid to the key you want to enumerate and pass it by reference.
  *  3) call this function as long as it does not return -1
  *     to indicate EOF. LID does contain the next key used to build the web
  *  4) Always call this function a last time with LID set to NULL,
  *     so that it can free its context.
  *
  * Returns: -1 on EOF or the level of the returned LID
  */
 int
 enum_cert_paths( void **context, ulong *lid,
 		 unsigned *ownertrust, unsigned *validity )
 {
   (void)context;
   (void)lid;
   (void)ownertrust;
   (void)validity;
   return -1;
 }
 
 
 /****************
  * Print the current path
  */
 void
 enum_cert_paths_print (void **context, FILE *fp,
                        int refresh, ulong selected_lid)
 {
   (void)context;
   (void)fp;
   (void)refresh;
   (void)selected_lid;
 }
 
 
 
 /****************************************
  *********** NEW NEW NEW ****************
  ****************************************/
 
 static int
 ask_ownertrust (u32 *kid,int minimum)
 {
   PKT_public_key *pk;
   int rc;
   int ot;
 
   pk = xmalloc_clear (sizeof *pk);
   rc = get_pubkey (pk, kid);
   if (rc)
     {
       log_error (_("public key %s not found: %s\n"),
                  keystr(kid), gpg_strerror (rc) );
       return TRUST_UNKNOWN;
     }
 
   if(opt.force_ownertrust)
     {
       log_info("force trust for key %s to %s\n",
 	       keystr(kid),trust_value_to_string(opt.force_ownertrust));
       tdb_update_ownertrust (pk, opt.force_ownertrust);
       ot=opt.force_ownertrust;
     }
   else
     {
       ot=edit_ownertrust(pk,0);
       if(ot>0)
 	ot = tdb_get_ownertrust (pk);
       else if(ot==0)
 	ot = minimum?minimum:TRUST_UNDEFINED;
       else
 	ot = -1; /* quit */
     }
 
   free_public_key( pk );
 
   return ot;
 }
 
 
 static void
 mark_keyblock_seen (KeyHashTable tbl, KBNODE node)
 {
   for ( ;node; node = node->next )
     if (node->pkt->pkttype == PKT_PUBLIC_KEY
 	|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
       {
         u32 aki[2];
 
         keyid_from_pk (node->pkt->pkt.public_key, aki);
         add_key_hash_table (tbl, aki);
       }
 }
 
 
 static void
 dump_key_array (int depth, struct key_array *keys)
 {
   struct key_array *kar;
 
   for (kar=keys; kar->keyblock; kar++)
     {
       KBNODE node = kar->keyblock;
       u32 kid[2];
 
       keyid_from_pk(node->pkt->pkt.public_key, kid);
       printf ("%d:%08lX%08lX:K::%c::::\n",
               depth, (ulong)kid[0], (ulong)kid[1], '?');
 
       for (; node; node = node->next)
         {
           if (node->pkt->pkttype == PKT_USER_ID)
             {
               int len = node->pkt->pkt.user_id->len;
 
               if (len > 30)
                 len = 30;
               printf ("%d:%08lX%08lX:U:::%c:::",
                       depth, (ulong)kid[0], (ulong)kid[1],
                       (node->flag & 4)? 'f':
                       (node->flag & 2)? 'm':
                       (node->flag & 1)? 'q':'-');
               es_write_sanitized (es_stdout, node->pkt->pkt.user_id->name,
                                   len, ":", NULL);
               putchar (':');
               putchar ('\n');
             }
         }
     }
 }
 
 
 static void
 store_validation_status (int depth, KBNODE keyblock, KeyHashTable stored)
 {
   KBNODE node;
   int status;
   int any = 0;
 
   for (node=keyblock; node; node = node->next)
     {
       if (node->pkt->pkttype == PKT_USER_ID)
         {
           PKT_user_id *uid = node->pkt->pkt.user_id;
           if (node->flag & 4)
             status = TRUST_FULLY;
           else if (node->flag & 2)
             status = TRUST_MARGINAL;
           else if (node->flag & 1)
             status = TRUST_UNDEFINED;
           else
             status = 0;
 
           if (status)
             {
               update_validity (keyblock->pkt->pkt.public_key,
 			       uid, depth, status);
 
 	      mark_keyblock_seen(stored,keyblock);
 
               any = 1;
             }
         }
     }
 
   if (any)
     do_sync ();
 }
 
 
 /* Returns a sanitized copy of the regexp (which might be "", but not
    NULL). */
 #ifndef DISABLE_REGEX
 static char *
 sanitize_regexp(const char *old)
 {
   size_t start=0,len=strlen(old),idx=0;
   int escaped=0,standard_bracket=0;
   char *new=xmalloc((len*2)+1); /* enough to \-escape everything if we
 				   have to */
 
   /* There are basically two commonly-used regexps here.  GPG and most
      versions of PGP use "<[^>]+[@.]example\.com>$" and PGP (9)
      command line uses "example.com" (i.e. whatever the user specfies,
      and we can't expect users know to use "\." instead of ".").  So
      here are the rules: we're allowed to start with "<[^>]+[@.]" and
      end with ">$" or start and end with nothing.  In between, the
      only legal regex character is ".", and everything else gets
      escaped.  Part of the gotcha here is that some regex packages
      allow more than RFC-4880 requires.  For example, 4880 has no "{}"
      operator, but GNU regex does.  Commenting removes these operators
      from consideration.  A possible future enhancement is to use
      commenting to effectively back off a given regex to the Henry
      Spencer syntax in 4880. -dshaw */
 
   /* Are we bracketed between "<[^>]+[@.]" and ">$" ? */
   if(len>=12 && strncmp(old,"<[^>]+[@.]",10)==0
      && old[len-2]=='>' && old[len-1]=='$')
     {
       strcpy(new,"<[^>]+[@.]");
       idx=strlen(new);
       standard_bracket=1;
       start+=10;
       len-=2;
     }
 
   /* Walk the remaining characters and ensure that everything that is
      left is not an operational regex character. */
   for(;start<len;start++)
     {
       if(!escaped && old[start]=='\\')
 	escaped=1;
       else if(!escaped && old[start]!='.')
 	new[idx++]='\\';
       else
 	escaped=0;
 
       new[idx++]=old[start];
     }
 
   new[idx]='\0';
 
   /* Note that the (sub)string we look at might end with a bare "\".
      If it does, leave it that way.  If the regexp actually ended with
      ">$", then it was escaping the ">" and is fine.  If the regexp
      actually ended with the bare "\", then it's an illegal regexp and
      regcomp should kick it out. */
 
   if(standard_bracket)
     strcat(new,">$");
 
   return new;
 }
 #endif /*!DISABLE_REGEX*/
 
 /* Used by validate_one_keyblock to confirm a regexp within a trust
    signature.  Returns 1 for match, and 0 for no match or regex
    error. */
 static int
 check_regexp(const char *expr,const char *string)
 {
 #ifdef DISABLE_REGEX
   (void)expr;
   (void)string;
   /* When DISABLE_REGEX is defined, assume all regexps do not
      match. */
   return 0;
 #else
   int ret;
   char *regexp;
 
   regexp=sanitize_regexp(expr);
 
 #ifdef __riscos__
   ret=riscos_check_regexp(expr, string, DBG_TRUST);
 #else
   {
     regex_t pat;
 
     ret=regcomp(&pat,regexp,REG_ICASE|REG_NOSUB|REG_EXTENDED);
     if(ret==0)
       {
 	ret=regexec(&pat,string,0,NULL,0);
 	regfree(&pat);
 	ret=(ret==0);
       }
   }
 #endif
 
   if(DBG_TRUST)
     log_debug("regexp '%s' ('%s') on '%s': %s\n",
 	      regexp,expr,string,ret==0?"YES":"NO");
 
   xfree(regexp);
 
   return ret;
 #endif
 }
 
 /*
  * Return true if the key is signed by one of the keys in the given
  * key ID list.  User IDs with a valid signature are marked by node
  * flags as follows:
  *  flag bit 0: There is at least one signature
  *           1: There is marginal confidence that this is a legitimate uid
  *           2: There is full confidence that this is a legitimate uid.
  *           8: Used for internal purposes.
  *           9: Ditto (in mark_usable_uid_certs())
  *          10: Ditto (ditto)
  * This function assumes that all kbnode flags are cleared on entry.
  */
 static int
 validate_one_keyblock (KBNODE kb, struct key_item *klist,
                        u32 curtime, u32 *next_expire)
 {
   struct key_item *kr;
   KBNODE node, uidnode=NULL;
   PKT_user_id *uid=NULL;
   PKT_public_key *pk = kb->pkt->pkt.public_key;
   u32 main_kid[2];
   int issigned=0, any_signed = 0;
 
   keyid_from_pk(pk, main_kid);
   for (node=kb; node; node = node->next)
     {
       /* A bit of discussion here: is it better for the web of trust
 	 to be built among only self-signed uids?  On the one hand, a
 	 self-signed uid is a statement that the key owner definitely
 	 intended that uid to be there, but on the other hand, a
 	 signed (but not self-signed) uid does carry trust, of a sort,
 	 even if it is a statement being made by people other than the
 	 key owner "through" the uids on the key owner's key.  I'm
 	 going with the latter.  However, if the user ID was
 	 explicitly revoked, or passively allowed to expire, that
 	 should stop validity through the user ID until it is
 	 resigned.  -dshaw */
 
       if (node->pkt->pkttype == PKT_USER_ID
 	  && !node->pkt->pkt.user_id->is_revoked
 	  && !node->pkt->pkt.user_id->is_expired)
         {
           if (uidnode && issigned)
             {
               if (uid->help_full_count >= opt.completes_needed
                   || uid->help_marginal_count >= opt.marginals_needed )
                 uidnode->flag |= 4;
               else if (uid->help_full_count || uid->help_marginal_count)
                 uidnode->flag |= 2;
               uidnode->flag |= 1;
               any_signed = 1;
             }
           uidnode = node;
 	  uid=uidnode->pkt->pkt.user_id;
 
 	  /* If the selfsig is going to expire... */
 	  if(uid->expiredate && uid->expiredate<*next_expire)
 	    *next_expire = uid->expiredate;
 
           issigned = 0;
 	  get_validity_counts(pk,uid);
           mark_usable_uid_certs (kb, uidnode, main_kid, klist,
                                  curtime, next_expire);
         }
       else if (node->pkt->pkttype == PKT_SIGNATURE
 	       && (node->flag & (1<<8)) && uid)
         {
 	  /* Note that we are only seeing unrevoked sigs here */
           PKT_signature *sig = node->pkt->pkt.signature;
 
           kr = is_in_klist (klist, sig);
 	  /* If the trust_regexp does not match, it's as if the sig
              did not exist.  This is safe for non-trust sigs as well
              since we don't accept a regexp on the sig unless it's a
              trust sig. */
           if (kr && (!kr->trust_regexp
                      || opt.trust_model != TM_PGP
                      || (uidnode
                          && check_regexp(kr->trust_regexp,
                                          uidnode->pkt->pkt.user_id->name))))
             {
 	      /* Are we part of a trust sig chain?  We always favor
                  the latest trust sig, rather than the greater or
                  lesser trust sig or value.  I could make a decent
                  argument for any of these cases, but this seems to be
                  what PGP does, and I'd like to be compatible. -dms */
               if (opt.trust_model == TM_PGP
                   && sig->trust_depth
                   && pk->trust_timestamp <= sig->timestamp)
 		{
 		  unsigned char depth;
 
 		  /* If the depth on the signature is less than the
 		     chain currently has, then use the signature depth
 		     so we don't increase the depth beyond what the
 		     signer wanted.  If the depth on the signature is
 		     more than the chain currently has, then use the
 		     chain depth so we use as much of the signature
 		     depth as the chain will permit.  An ultimately
 		     trusted signature can restart the depth to
 		     whatever level it likes. */
 
 		  if (sig->trust_depth < kr->trust_depth
                       || kr->ownertrust == TRUST_ULTIMATE)
 		    depth = sig->trust_depth;
 		  else
 		    depth = kr->trust_depth;
 
 		  if (depth)
 		    {
 		      if(DBG_TRUST)
 			log_debug ("trust sig on %s, sig depth is %d,"
                                    " kr depth is %d\n",
                                    uidnode->pkt->pkt.user_id->name,
                                    sig->trust_depth,
                                    kr->trust_depth);
 
 		      /* If we got here, we know that:
 
 			 this is a trust sig.
 
 			 it's a newer trust sig than any previous trust
 			 sig on this key (not uid).
 
 			 it is legal in that it was either generated by an
 			 ultimate key, or a key that was part of a trust
 			 chain, and the depth does not violate the
 			 original trust sig.
 
 			 if there is a regexp attached, it matched
 			 successfully.
 		      */
 
 		      if (DBG_TRUST)
 			log_debug ("replacing trust value %d with %d and "
                                    "depth %d with %d\n",
                                    pk->trust_value,sig->trust_value,
                                    pk->trust_depth,depth);
 
 		      pk->trust_value = sig->trust_value;
 		      pk->trust_depth = depth-1;
 
 		      /* If the trust sig contains a regexp, record it
 			 on the pk for the next round. */
 		      if (sig->trust_regexp)
 			pk->trust_regexp = sig->trust_regexp;
 		    }
 		}
 
               if (kr->ownertrust == TRUST_ULTIMATE)
                 uid->help_full_count = opt.completes_needed;
               else if (kr->ownertrust == TRUST_FULLY)
                 uid->help_full_count++;
               else if (kr->ownertrust == TRUST_MARGINAL)
                 uid->help_marginal_count++;
               issigned = 1;
 	    }
         }
     }
 
   if (uidnode && issigned)
     {
       if (uid->help_full_count >= opt.completes_needed
 	  || uid->help_marginal_count >= opt.marginals_needed )
         uidnode->flag |= 4;
       else if (uid->help_full_count || uid->help_marginal_count)
         uidnode->flag |= 2;
       uidnode->flag |= 1;
       any_signed = 1;
     }
 
   return any_signed;
 }
 
 
 static int
 search_skipfnc (void *opaque, u32 *kid, PKT_user_id *dummy)
 {
   (void)dummy;
   return test_key_hash_table ((KeyHashTable)opaque, kid);
 }
 
 
 /*
  * Scan all keys and return a key_array of all suitable keys from
  * kllist.  The caller has to pass keydb handle so that we don't use
  * to create our own.  Returns either a key_array or NULL in case of
  * an error.  No results found are indicated by an empty array.
  * Caller hast to release the returned array.
  */
 static struct key_array *
 validate_key_list (KEYDB_HANDLE hd, KeyHashTable full_trust,
                    struct key_item *klist, u32 curtime, u32 *next_expire)
 {
   KBNODE keyblock = NULL;
   struct key_array *keys = NULL;
   size_t nkeys, maxkeys;
   int rc;
   KEYDB_SEARCH_DESC desc;
 
   maxkeys = 1000;
   keys = xmalloc ((maxkeys+1) * sizeof *keys);
   nkeys = 0;
 
   rc = keydb_search_reset (hd);
   if (rc)
     {
       log_error ("keydb_search_reset failed: %s\n", gpg_strerror (rc));
       xfree (keys);
       return NULL;
     }
 
   memset (&desc, 0, sizeof desc);
   desc.mode = KEYDB_SEARCH_MODE_FIRST;
   desc.skipfnc = search_skipfnc;
   desc.skipfncvalue = full_trust;
   rc = keydb_search (hd, &desc, 1, NULL);
   if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
     {
       keys[nkeys].keyblock = NULL;
       return keys;
     }
   if (rc)
     {
       log_error ("keydb_search_first failed: %s\n", gpg_strerror (rc));
       xfree (keys);
       return NULL;
     }
 
   desc.mode = KEYDB_SEARCH_MODE_NEXT; /* change mode */
   do
     {
       PKT_public_key *pk;
 
+      if (gpg_err_code (rc) == GPG_ERR_LEGACY_KEY)
+        continue;
+
       rc = keydb_get_keyblock (hd, &keyblock);
       if (rc)
         {
           log_error ("keydb_get_keyblock failed: %s\n", gpg_strerror (rc));
           xfree (keys);
           return NULL;
         }
 
       if ( keyblock->pkt->pkttype != PKT_PUBLIC_KEY)
         {
           log_debug ("ooops: invalid pkttype %d encountered\n",
                      keyblock->pkt->pkttype);
           dump_kbnode (keyblock);
           release_kbnode(keyblock);
           continue;
         }
 
       /* prepare the keyblock for further processing */
       merge_keys_and_selfsig (keyblock);
       clear_kbnode_flags (keyblock);
       pk = keyblock->pkt->pkt.public_key;
       if (pk->has_expired || pk->flags.revoked)
         {
           /* it does not make sense to look further at those keys */
           mark_keyblock_seen (full_trust, keyblock);
         }
       else if (validate_one_keyblock (keyblock, klist, curtime, next_expire))
         {
 	  KBNODE node;
 
           if (pk->expiredate && pk->expiredate >= curtime
               && pk->expiredate < *next_expire)
             *next_expire = pk->expiredate;
 
           if (nkeys == maxkeys) {
             maxkeys += 1000;
             keys = xrealloc (keys, (maxkeys+1) * sizeof *keys);
           }
           keys[nkeys++].keyblock = keyblock;
 
 	  /* Optimization - if all uids are fully trusted, then we
 	     never need to consider this key as a candidate again. */
 
 	  for (node=keyblock; node; node = node->next)
 	    if (node->pkt->pkttype == PKT_USER_ID && !(node->flag & 4))
 	      break;
 
 	  if(node==NULL)
 	    mark_keyblock_seen (full_trust, keyblock);
 
           keyblock = NULL;
         }
 
       release_kbnode (keyblock);
       keyblock = NULL;
     }
-  while (!(rc = keydb_search (hd, &desc, 1, NULL)));
+  while (!(rc = keydb_search (hd, &desc, 1, NULL))
+         || gpg_err_code (rc) == GPG_ERR_LEGACY_KEY);
 
   if (rc && gpg_err_code (rc) != GPG_ERR_NOT_FOUND)
     {
       log_error ("keydb_search_next failed: %s\n", gpg_strerror (rc));
       xfree (keys);
       return NULL;
     }
 
   keys[nkeys].keyblock = NULL;
   return keys;
 }
 
 /* Caller must sync */
 static void
 reset_trust_records(void)
 {
   TRUSTREC rec;
   ulong recnum;
   int count = 0, nreset = 0;
 
   for (recnum=1; !tdbio_read_record (recnum, &rec, 0); recnum++ )
     {
       if(rec.rectype==RECTYPE_TRUST)
 	{
 	  count++;
 	  if(rec.r.trust.min_ownertrust)
 	    {
 	      rec.r.trust.min_ownertrust=0;
 	      write_record(&rec);
 	    }
 
 	}
       else if(rec.rectype==RECTYPE_VALID
 	      && ((rec.r.valid.validity&TRUST_MASK)
 		  || rec.r.valid.marginal_count
 		  || rec.r.valid.full_count))
 	{
 	  rec.r.valid.validity &= ~TRUST_MASK;
 	  rec.r.valid.marginal_count=rec.r.valid.full_count=0;
 	  nreset++;
 	  write_record(&rec);
 	}
 
     }
 
   if (opt.verbose)
     log_info (_("%d keys processed (%d validity counts cleared)\n"),
 	      count, nreset);
 }
 
 /*
  * Run the key validation procedure.
  *
  * This works this way:
  * Step 1: Find all ultimately trusted keys (UTK).
  *         mark them all as seen and put them into klist.
  * Step 2: loop max_cert_times
  * Step 3:   if OWNERTRUST of any key in klist is undefined
  *             ask user to assign ownertrust
  * Step 4:   Loop over all keys in the keyDB which are not marked seen
  * Step 5:     if key is revoked or expired
  *                mark key as seen
  *                continue loop at Step 4
  * Step 6:     For each user ID of that key signed by a key in klist
  *                Calculate validity by counting trusted signatures.
  *                Set validity of user ID
  * Step 7:     If any signed user ID was found
  *                mark key as seen
  *             End Loop
  * Step 8:   Build a new klist from all fully trusted keys from step 6
  *           End Loop
  *         Ready
  *
  */
 static int
 validate_keys (int interactive)
 {
   int rc = 0;
   int quit=0;
   struct key_item *klist = NULL;
   struct key_item *k;
   struct key_array *keys = NULL;
   struct key_array *kar;
   KEYDB_HANDLE kdb = NULL;
   KBNODE node;
   int depth;
   int ot_unknown, ot_undefined, ot_never, ot_marginal, ot_full, ot_ultimate;
   KeyHashTable stored,used,full_trust;
   u32 start_time, next_expire;
 
   /* Make sure we have all sigs cached.  TODO: This is going to
      require some architectual re-thinking, as it is agonizingly slow.
      Perhaps combine this with reset_trust_records(), or only check
      the caches on keys that are actually involved in the web of
      trust. */
   keydb_rebuild_caches(0);
 
   start_time = make_timestamp ();
   next_expire = 0xffffffff; /* set next expire to the year 2106 */
   stored = new_key_hash_table ();
   used = new_key_hash_table ();
   full_trust = new_key_hash_table ();
 
   kdb = keydb_new ();
   reset_trust_records();
 
   /* Fixme: Instead of always building a UTK list, we could just build it
    * here when needed */
   if (!utk_list)
     {
       if (!opt.quiet)
         log_info (_("no ultimately trusted keys found\n"));
       goto leave;
     }
 
   /* mark all UTKs as used and fully_trusted and set validity to
      ultimate */
   for (k=utk_list; k; k = k->next)
     {
       KBNODE keyblock;
       PKT_public_key *pk;
 
       keyblock = get_pubkeyblock (k->kid);
       if (!keyblock)
         {
           log_error (_("public key of ultimately"
                        " trusted key %s not found\n"), keystr(k->kid));
           continue;
         }
       mark_keyblock_seen (used, keyblock);
       mark_keyblock_seen (stored, keyblock);
       mark_keyblock_seen (full_trust, keyblock);
       pk = keyblock->pkt->pkt.public_key;
       for (node=keyblock; node; node = node->next)
         {
           if (node->pkt->pkttype == PKT_USER_ID)
 	    update_validity (pk, node->pkt->pkt.user_id, 0, TRUST_ULTIMATE);
         }
       if ( pk->expiredate && pk->expiredate >= start_time
            && pk->expiredate < next_expire)
         next_expire = pk->expiredate;
 
       release_kbnode (keyblock);
       do_sync ();
     }
 
   klist = utk_list;
 
   log_info(_("%d marginal(s) needed, %d complete(s) needed, %s trust model\n"),
 	   opt.marginals_needed,opt.completes_needed,trust_model_string());
 
   for (depth=0; depth < opt.max_cert_depth; depth++)
     {
       int valids=0,key_count;
       /* See whether we should assign ownertrust values to the keys in
          klist.  */
       ot_unknown = ot_undefined = ot_never = 0;
       ot_marginal = ot_full = ot_ultimate = 0;
       for (k=klist; k; k = k->next)
         {
 	  int min=0;
 
 	  /* 120 and 60 are as per RFC2440 */
 	  if(k->trust_value>=120)
 	    min=TRUST_FULLY;
 	  else if(k->trust_value>=60)
 	    min=TRUST_MARGINAL;
 
 	  if(min!=k->min_ownertrust)
 	    update_min_ownertrust(k->kid,min);
 
           if (interactive && k->ownertrust == TRUST_UNKNOWN)
 	    {
 	      k->ownertrust = ask_ownertrust (k->kid,min);
 
 	      if (k->ownertrust == (unsigned int)(-1))
 		{
 		  quit=1;
 		  goto leave;
 		}
 	    }
 
 	  /* This can happen during transition from an old trustdb
 	     before trust sigs.  It can also happen if a user uses two
 	     different versions of GnuPG or changes the --trust-model
 	     setting. */
 	  if(k->ownertrust<min)
 	    {
 	      if(DBG_TRUST)
 		log_debug("key %08lX%08lX:"
 			  " overriding ownertrust '%s' with '%s'\n",
 			  (ulong)k->kid[0],(ulong)k->kid[1],
 			  trust_value_to_string(k->ownertrust),
 			  trust_value_to_string(min));
 
 	      k->ownertrust=min;
 	    }
 
 	  if (k->ownertrust == TRUST_UNKNOWN)
             ot_unknown++;
           else if (k->ownertrust == TRUST_UNDEFINED)
             ot_undefined++;
           else if (k->ownertrust == TRUST_NEVER)
             ot_never++;
           else if (k->ownertrust == TRUST_MARGINAL)
             ot_marginal++;
           else if (k->ownertrust == TRUST_FULLY)
             ot_full++;
           else if (k->ownertrust == TRUST_ULTIMATE)
             ot_ultimate++;
 
 	  valids++;
         }
 
       /* Find all keys which are signed by a key in kdlist */
       keys = validate_key_list (kdb, full_trust, klist,
 				start_time, &next_expire);
       if (!keys)
         {
           log_error ("validate_key_list failed\n");
           rc = GPG_ERR_GENERAL;
           goto leave;
         }
 
       for (key_count=0, kar=keys; kar->keyblock; kar++, key_count++)
         ;
 
       /* Store the calculated valididation status somewhere */
       if (opt.verbose > 1)
         dump_key_array (depth, keys);
 
       for (kar=keys; kar->keyblock; kar++)
           store_validation_status (depth, kar->keyblock, stored);
 
       log_info (_("depth: %d  valid: %3d  signed: %3d"
                   "  trust: %d-, %dq, %dn, %dm, %df, %du\n"),
                 depth, valids, key_count, ot_unknown, ot_undefined,
                 ot_never, ot_marginal, ot_full, ot_ultimate );
 
       /* Build a new kdlist from all fully valid keys in KEYS */
       if (klist != utk_list)
         release_key_items (klist);
       klist = NULL;
       for (kar=keys; kar->keyblock; kar++)
         {
           for (node=kar->keyblock; node; node = node->next)
             {
               if (node->pkt->pkttype == PKT_USER_ID && (node->flag & 4))
                 {
 		  u32 kid[2];
 
 		  /* have we used this key already? */
                   keyid_from_pk (kar->keyblock->pkt->pkt.public_key, kid);
 		  if(test_key_hash_table(used,kid)==0)
 		    {
 		      /* Normally we add both the primary and subkey
 			 ids to the hash via mark_keyblock_seen, but
 			 since we aren't using this hash as a skipfnc,
 			 that doesn't matter here. */
 		      add_key_hash_table (used,kid);
 		      k = new_key_item ();
 		      k->kid[0]=kid[0];
 		      k->kid[1]=kid[1];
 		      k->ownertrust =
 			(tdb_get_ownertrust
                          (kar->keyblock->pkt->pkt.public_key) & TRUST_MASK);
 		      k->min_ownertrust = tdb_get_min_ownertrust
                         (kar->keyblock->pkt->pkt.public_key);
 		      k->trust_depth=
 			kar->keyblock->pkt->pkt.public_key->trust_depth;
 		      k->trust_value=
 			kar->keyblock->pkt->pkt.public_key->trust_value;
 		      if(kar->keyblock->pkt->pkt.public_key->trust_regexp)
 			k->trust_regexp=
 			  xstrdup(kar->keyblock->pkt->
 				   pkt.public_key->trust_regexp);
 		      k->next = klist;
 		      klist = k;
 		      break;
 		    }
 		}
 	    }
 	}
       release_key_array (keys);
       keys = NULL;
       if (!klist)
         break; /* no need to dive in deeper */
     }
 
  leave:
   keydb_release (kdb);
   release_key_array (keys);
   release_key_items (klist);
   release_key_hash_table (full_trust);
   release_key_hash_table (used);
   release_key_hash_table (stored);
   if (!rc && !quit) /* mark trustDB as checked */
     {
       if (next_expire == 0xffffffff || next_expire < start_time )
         tdbio_write_nextcheck (0);
       else
         {
           tdbio_write_nextcheck (next_expire);
           log_info (_("next trustdb check due at %s\n"),
                     strtimestamp (next_expire));
         }
 
       if(tdbio_update_version_record()!=0)
 	{
 	  log_error(_("unable to update trustdb version record: "
 		      "write failed: %s\n"), gpg_strerror (rc));
 	  tdbio_invalid();
 	}
 
       do_sync ();
       pending_check_trustdb = 0;
     }
 
   return rc;
 }