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;

  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.
             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;
}