gpg: Convey --quick option to dirmngr for --auto-key-retrieve.
[gnupg.git] / g10 / import.c
index 60a037b..d65a7ae 100644 (file)
@@ -1,6 +1,6 @@
 /* import.c - import a key into our key storage.
  * Copyright (C) 1998-2007, 2010-2011 Free Software Foundation, Inc.
- * Copyright (C) 2014  Werner Koch
+ * Copyright (C) 2014, 2016  Werner Koch
  *
  * This file is part of GnuPG.
  *
@@ -23,7 +23,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <assert.h>
 
 #include "gpg.h"
 #include "options.h"
 #include "i18n.h"
 #include "ttyio.h"
 #include "status.h"
+#include "recsel.h"
 #include "keyserver-internal.h"
 #include "call-agent.h"
 #include "../common/membuf.h"
+#include "../common/init.h"
+#include "../common/mbox-util.h"
 
-struct stats_s
+
+struct import_stats_s
 {
   ulong count;
   ulong no_user_id;
@@ -61,39 +64,83 @@ struct stats_s
 };
 
 
+/* Node flag to indicate that a user ID or a subkey has a
+ * valid self-signature.  */
+#define NODE_GOOD_SELFSIG  1
+/* Node flag to indicate that a user ID or subkey has
+ * an invalid self-signature.  */
+#define NODE_BAD_SELFSIG   2
+/* Node flag to indicate that the node shall be deleted.  */
+#define NODE_DELETION_MARK 4
+/* A node flag used to temporary mark a node. */
+#define NODE_FLAG_A  8
+
+
+/* A an object and a global instance to store selectors created from
+ * --import-filter keep-uid=EXPR.
+ * --import-filter drop-sig=EXPR.
+ *
+ * FIXME: We should put this into the CTRL object but that requires a
+ * lot more changes right now.  For now we use save and restore
+ * fucntion to temporary change them.
+ */
+/* Definition of the import filters.  */
+struct import_filter_s
+{
+  recsel_expr_t keep_uid;
+  recsel_expr_t drop_sig;
+};
+/* The current instance.  */
+struct import_filter_s import_filter;
+
+
 static int import (ctrl_t ctrl,
-                   IOBUF inp, const char* fname, struct stats_s *stats,
+                   IOBUF inp, const char* fname, struct import_stats_s *stats,
                   unsigned char **fpr, size_t *fpr_len, unsigned int options,
                   import_screener_t screener, void *screener_arg);
 static int read_block (IOBUF a, PACKET **pending_pkt, kbnode_t *ret_root,
                        int *r_v3keys);
 static void revocation_present (ctrl_t ctrl, kbnode_t keyblock);
 static int import_one (ctrl_t ctrl,
-                       const char *fname, kbnode_t keyblock,struct stats_s *stats,
+                       kbnode_t keyblock,
+                       struct import_stats_s *stats,
                        unsigned char **fpr, size_t *fpr_len,
                        unsigned int options, int from_sk, int silent,
                        import_screener_t screener, void *screener_arg);
-static int import_secret_one (ctrl_t ctrl, const char *fname, kbnode_t keyblock,
-                              struct stats_s *stats, int batch,
+static int import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
+                              struct import_stats_s *stats, int batch,
                               unsigned int options, int for_migration,
                               import_screener_t screener, void *screener_arg);
-static int import_revoke_cert( const char *fname, kbnode_t node,
-                               struct stats_s *stats);
-static int chk_self_sigs (const char *fname, kbnode_t keyblock,
-                         PKT_public_key *pk, u32 *keyid, int *non_self );
-static int delete_inv_parts (const char *fname, kbnode_t keyblock,
-                            u32 *keyid, unsigned int options );
-static int merge_blocks (const char *fname, kbnode_t keyblock_orig,
+static int import_revoke_cert (kbnode_t node, struct import_stats_s *stats);
+static int chk_self_sigs (kbnode_t keyblock, u32 *keyid, int *non_self);
+static int delete_inv_parts (kbnode_t keyblock,
+                             u32 *keyid, unsigned int options);
+static int any_uid_left (kbnode_t keyblock);
+static int merge_blocks (kbnode_t keyblock_orig,
                         kbnode_t keyblock, u32 *keyid,
                         int *n_uids, int *n_sigs, int *n_subk );
-static int append_uid (kbnode_t keyblock, kbnode_t node, int *n_sigs,
-                            const char *fname, u32 *keyid );
-static int append_key (kbnode_t keyblock, kbnode_t node, int *n_sigs,
-                            const char *fname, u32 *keyid );
-static int merge_sigs (kbnode_t dst, kbnode_t src, int *n_sigs,
-                            const char *fname, u32 *keyid );
-static int merge_keysigs (kbnode_t dst, kbnode_t src, int *n_sigs,
-                            const char *fname, u32 *keyid );
+static int append_uid (kbnode_t keyblock, kbnode_t node, int *n_sigs);
+static int append_key (kbnode_t keyblock, kbnode_t node, int *n_sigs);
+static int merge_sigs (kbnode_t dst, kbnode_t src, int *n_sigs);
+static int merge_keysigs (kbnode_t dst, kbnode_t src, int *n_sigs);
+
+
+\f
+static void
+release_import_filter (import_filter_t filt)
+{
+  recsel_release (filt->keep_uid);
+  filt->keep_uid = NULL;
+  recsel_release (filt->drop_sig);
+  filt->drop_sig = NULL;
+}
+
+static void
+cleanup_import_globals (void)
+{
+  release_import_filter (&import_filter);
+}
+
 
 int
 parse_import_options(char *str,unsigned int *options,int noisy)
@@ -112,6 +159,9 @@ parse_import_options(char *str,unsigned int *options,int noisy)
       {"fast-import",IMPORT_FAST,NULL,
        N_("do not update the trustdb after import")},
 
+      {"import-show",IMPORT_SHOW,NULL,
+       N_("show key during import")},
+
       {"merge-only",IMPORT_MERGE_ONLY,NULL,
        N_("only accept updates to existing keys")},
 
@@ -121,6 +171,9 @@ parse_import_options(char *str,unsigned int *options,int noisy)
       {"import-minimal",IMPORT_MINIMAL|IMPORT_CLEAN,NULL,
        N_("remove as much as possible from key after import")},
 
+      {"import-export", IMPORT_EXPORT, NULL,
+       N_("run import filters and export key immediately")},
+
       /* Aliases for backward compatibility */
       {"allow-local-sigs",IMPORT_LOCAL_SIGS,NULL,NULL},
       {"repair-hkp-subkey-bug",IMPORT_REPAIR_PKS_SUBKEY_BUG,NULL,NULL},
@@ -137,20 +190,192 @@ parse_import_options(char *str,unsigned int *options,int noisy)
 }
 
 
-void *
+/* Parse and set an import filter from string.  STRING has the format
+ * "NAME=EXPR" with NAME being the name of the filter.  Spaces before
+ * and after NAME are not allowed.  If this function is all called
+ * several times all expressions for the same NAME are concatenated.
+ * Supported filter names are:
+ *
+ *  - keep-uid :: If the expression evaluates to true for a certain
+ *                user ID packet, that packet and all it dependencies
+ *                will be imported.  The expression may use these
+ *                variables:
+ *
+ *                - uid  :: The entire user ID.
+ *                - mbox :: The mail box part of the user ID.
+ *                - primary :: Evaluate to true for the primary user ID.
+ */
+gpg_error_t
+parse_and_set_import_filter (const char *string)
+{
+  gpg_error_t err;
+
+  /* Auto register the cleanup function.  */
+  register_mem_cleanup_func (cleanup_import_globals);
+
+  if (!strncmp (string, "keep-uid=", 9))
+    err = recsel_parse_expr (&import_filter.keep_uid, string+9);
+  else if (!strncmp (string, "drop-sig=", 9))
+    err = recsel_parse_expr (&import_filter.drop_sig, string+9);
+  else
+    err = gpg_error (GPG_ERR_INV_NAME);
+
+  return err;
+}
+
+
+/* Save the current import filters, return them, and clear the current
+ * filters.  Returns NULL on error and sets ERRNO.  */
+import_filter_t
+save_and_clear_import_filter (void)
+{
+  import_filter_t filt;
+
+  filt = xtrycalloc (1, sizeof *filt);
+  if (!filt)
+    return NULL;
+  *filt = import_filter;
+  memset (&import_filter, 0, sizeof import_filter);
+
+  return filt;
+}
+
+
+/* Release the current import filters and restore them from NEWFILT.
+ * Ownership of NEWFILT is moved to this function.  */
+void
+restore_import_filter (import_filter_t filt)
+{
+  if (filt)
+    {
+      release_import_filter (&import_filter);
+      import_filter = *filt;
+      xfree (filt);
+    }
+}
+
+
+import_stats_t
 import_new_stats_handle (void)
 {
-  return xmalloc_clear ( sizeof (struct stats_s) );
+  return xmalloc_clear ( sizeof (struct import_stats_s) );
 }
 
 
 void
-import_release_stats_handle (void *p)
+import_release_stats_handle (import_stats_t p)
 {
   xfree (p);
 }
 
 
+/* Read a key from a file.  Only the first key in the file is
+ * considered and stored at R_KEYBLOCK.  FNAME is the name of the
+ * file.
+ */
+gpg_error_t
+read_key_from_file (ctrl_t ctrl, const char *fname, kbnode_t *r_keyblock)
+{
+  gpg_error_t err;
+  iobuf_t inp;
+  PACKET *pending_pkt = NULL;
+  kbnode_t keyblock = NULL;
+  u32 keyid[2];
+  int v3keys;   /* Dummy */
+  int non_self; /* Dummy */
+
+  (void)ctrl;
+
+  *r_keyblock = NULL;
+
+  inp = iobuf_open (fname);
+  if (!inp)
+    err = gpg_error_from_syserror ();
+  else if (is_secured_file (iobuf_get_fd (inp)))
+    {
+      iobuf_close (inp);
+      inp = NULL;
+      err = gpg_error (GPG_ERR_EPERM);
+    }
+  else
+    err = 0;
+  if (err)
+    {
+      log_error (_("can't open '%s': %s\n"),
+                 iobuf_is_pipe_filename (fname)? "[stdin]": fname,
+                 gpg_strerror (err));
+      if (gpg_err_code (err) == GPG_ERR_ENOENT)
+        err = gpg_error (GPG_ERR_NO_PUBKEY);
+      goto leave;
+    }
+
+  /* Push the armor filter.  */
+  {
+    armor_filter_context_t *afx;
+    afx = new_armor_context ();
+    afx->only_keyblocks = 1;
+    push_armor_filter (afx, inp);
+    release_armor_context (afx);
+  }
+
+  /* Read the first non-v3 keyblock.  */
+  while (!(err = read_block (inp, &pending_pkt, &keyblock, &v3keys)))
+    {
+      if (keyblock->pkt->pkttype == PKT_PUBLIC_KEY)
+        break;
+      log_info (_("skipping block of type %d\n"), keyblock->pkt->pkttype);
+      release_kbnode (keyblock);
+      keyblock = NULL;
+    }
+  if (err)
+    {
+      if (gpg_err_code (err) != GPG_ERR_INV_KEYRING)
+        log_error (_("error reading '%s': %s\n"),
+                   iobuf_is_pipe_filename (fname)? "[stdin]": fname,
+                   gpg_strerror (err));
+      goto leave;
+    }
+
+  keyid_from_pk (keyblock->pkt->pkt.public_key, keyid);
+
+  if (!find_next_kbnode (keyblock, PKT_USER_ID))
+    {
+      err = gpg_error (GPG_ERR_NO_USER_ID);
+      goto leave;
+    }
+
+  collapse_uids (&keyblock);
+
+  clear_kbnode_flags (keyblock);
+  if (chk_self_sigs (keyblock, keyid, &non_self))
+    {
+      err = gpg_error (GPG_ERR_INV_KEYRING);
+      goto leave;
+    }
+
+  if (!delete_inv_parts (keyblock, keyid, 0) )
+    {
+      err = gpg_error (GPG_ERR_NO_USER_ID);
+      goto leave;
+    }
+
+  *r_keyblock = keyblock;
+  keyblock = NULL;
+
+ leave:
+  if (inp)
+    {
+      iobuf_close (inp);
+      /* Must invalidate that ugly cache to actually close the file. */
+      iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname);
+    }
+  release_kbnode (keyblock);
+  /* FIXME: Do we need to free PENDING_PKT ? */
+  return err;
+}
+
+
+
 /*
  * Import the public keys from the given filename. Input may be armored.
  * This function rejects all keys which are not validly self signed on at
@@ -183,13 +408,14 @@ import_release_stats_handle (void *p)
  */
 static int
 import_keys_internal (ctrl_t ctrl, iobuf_t inp, char **fnames, int nnames,
-                     void *stats_handle, unsigned char **fpr, size_t *fpr_len,
+                     import_stats_t stats_handle,
+                      unsigned char **fpr, size_t *fpr_len,
                      unsigned int options,
                       import_screener_t screener, void *screener_arg)
 {
   int i;
   int rc = 0;
-  struct stats_s *stats = stats_handle;
+  struct import_stats_s *stats = stats_handle;
 
   if (!stats)
     stats = import_new_stats_handle ();
@@ -248,7 +474,7 @@ import_keys_internal (ctrl_t ctrl, iobuf_t inp, char **fnames, int nnames,
      interactive or by not setting no-auto-check-trustdb */
 
   if (!(options & IMPORT_FAST))
-    check_or_update_trustdb ();
+    check_or_update_trustdb (ctrl);
 
   return rc;
 }
@@ -256,14 +482,14 @@ import_keys_internal (ctrl_t ctrl, iobuf_t inp, char **fnames, int nnames,
 
 void
 import_keys (ctrl_t ctrl, char **fnames, int nnames,
-            void *stats_handle, unsigned int options )
+            import_stats_t stats_handle, unsigned int options )
 {
   import_keys_internal (ctrl, NULL, fnames, nnames, stats_handle,
                         NULL, NULL, options, NULL, NULL);
 }
 
 int
-import_keys_stream (ctrl_t ctrl, IOBUF inp, void *stats_handle,
+import_keys_stream (ctrl_t ctrl, IOBUF inp, import_stats_t stats_handle,
                    unsigned char **fpr, size_t *fpr_len, unsigned int options)
 {
   return import_keys_internal (ctrl, inp, NULL, 0, stats_handle,
@@ -273,7 +499,8 @@ import_keys_stream (ctrl_t ctrl, IOBUF inp, void *stats_handle,
 
 /* Variant of import_keys_stream reading from an estream_t.  */
 int
-import_keys_es_stream (ctrl_t ctrl, estream_t fp, void *stats_handle,
+import_keys_es_stream (ctrl_t ctrl, estream_t fp,
+                       import_stats_t stats_handle,
                        unsigned char **fpr, size_t *fpr_len,
                        unsigned int options,
                        import_screener_t screener, void *screener_arg)
@@ -281,7 +508,7 @@ import_keys_es_stream (ctrl_t ctrl, estream_t fp, void *stats_handle,
   int rc;
   iobuf_t inp;
 
-  inp = iobuf_esopen (fp, "r", 1);
+  inp = iobuf_esopen (fp, "rb", 1);
   if (!inp)
     {
       rc = gpg_error_from_syserror ();
@@ -299,7 +526,7 @@ import_keys_es_stream (ctrl_t ctrl, estream_t fp, void *stats_handle,
 
 
 static int
-import (ctrl_t ctrl, IOBUF inp, const char* fname,struct stats_s *stats,
+import (ctrl_t ctrl, IOBUF inp, const char* fname,struct import_stats_s *stats,
        unsigned char **fpr,size_t *fpr_len, unsigned int options,
        import_screener_t screener, void *screener_arg)
 {
@@ -326,16 +553,16 @@ import (ctrl_t ctrl, IOBUF inp, const char* fname,struct stats_s *stats,
     {
       stats->v3keys += v3keys;
       if (keyblock->pkt->pkttype == PKT_PUBLIC_KEY)
-        rc = import_one (ctrl, fname, keyblock,
+        rc = import_one (ctrl, keyblock,
                          stats, fpr, fpr_len, options, 0, 0,
                          screener, screener_arg);
       else if (keyblock->pkt->pkttype == PKT_SECRET_KEY)
-        rc = import_secret_one (ctrl, fname, keyblock, stats,
+        rc = import_secret_one (ctrl, keyblock, stats,
                                 opt.batch, options, 0,
                                 screener, screener_arg);
       else if (keyblock->pkt->pkttype == PKT_SIGNATURE
                && keyblock->pkt->pkt.signature->sig_class == 0x20 )
-        rc = import_revoke_cert( fname, keyblock, stats );
+        rc = import_revoke_cert (keyblock, stats);
       else
         {
           log_info (_("skipping block of type %d\n"), keyblock->pkt->pkttype);
@@ -350,7 +577,6 @@ import (ctrl_t ctrl, IOBUF inp, const char* fname,struct stats_s *stats,
             && gpg_err_source (rc) == GPG_ERR_SOURCE_KEYBOX)
         {
           stats->not_imported++;
-          rc = 0;
         }
       else if (rc)
         break;
@@ -378,7 +604,7 @@ import_old_secring (ctrl_t ctrl, const char *fname)
   kbnode_t keyblock = NULL;  /* Need to initialize because gcc can't
                                 grasp the return semantics of
                                 read_block. */
-  struct stats_s *stats;
+  struct import_stats_s *stats;
   int v3keys;
 
   inp = iobuf_open (fname);
@@ -400,7 +626,7 @@ import_old_secring (ctrl_t ctrl, const char *fname)
   while (!(err = read_block (inp, &pending_pkt, &keyblock, &v3keys)))
     {
       if (keyblock->pkt->pkttype == PKT_SECRET_KEY)
-        err = import_secret_one (ctrl, fname, keyblock, stats, 1, 0, 1,
+        err = import_secret_one (ctrl, keyblock, stats, 1, 0, 1,
                                  NULL, NULL);
       release_kbnode (keyblock);
       if (err)
@@ -422,10 +648,8 @@ import_old_secring (ctrl_t ctrl, const char *fname)
 
 
 void
-import_print_stats (void *hd)
+import_print_stats (import_stats_t stats)
 {
-  struct stats_s *stats = hd;
-
   if (!opt.quiet)
     {
       log_info(_("Total number processed: %lu\n"),
@@ -708,8 +932,8 @@ fix_pks_corruption (kbnode_t keyblock)
            }
          else
            {
-             sknode->flag |= 1; /* Mark it good so we don't need to
-                                    check it again */
+              /* Mark it good so we don't need to check it again */
+             sknode->flag |= NODE_GOOD_SELFSIG;
              changed = 1;
              break;
            }
@@ -798,7 +1022,6 @@ print_import_check (PKT_public_key * pk, PKT_user_id * id)
   for (i = 0; i < n; i++, pos += 2)
     sprintf (buf+pos, "%02X", fpr[i]);
   strcat (buf, " ");
-  pos += 1;
   strcat (buf, id->name);
   write_status_text (STATUS_IMPORT_CHECK, buf);
   xfree (buf);
@@ -923,6 +1146,176 @@ check_prefs (ctrl_t ctrl, kbnode_t keyblock)
 }
 
 
+/* Helper for apply_*_filter in im,port.c and export.c.  */
+const char *
+impex_filter_getval (void *cookie, const char *propname)
+{
+  /* FIXME: Malloc our static buffers and access them via the cookie.  */
+  kbnode_t node = cookie;
+  static char numbuf[20];
+  const char *result;
+
+  if (node->pkt->pkttype == PKT_USER_ID)
+    {
+      if (!strcmp (propname, "uid"))
+        result = node->pkt->pkt.user_id->name;
+      else if (!strcmp (propname, "mbox"))
+        {
+          if (!node->pkt->pkt.user_id->mbox)
+            {
+              node->pkt->pkt.user_id->mbox
+                = mailbox_from_userid (node->pkt->pkt.user_id->name);
+            }
+          result = node->pkt->pkt.user_id->mbox;
+        }
+      else if (!strcmp (propname, "primary"))
+        result = node->pkt->pkt.user_id->is_primary? "1":"0";
+      else
+        result = NULL;
+    }
+  else if (node->pkt->pkttype == PKT_SIGNATURE
+           || node->pkt->pkttype == PKT_ATTRIBUTE)
+    {
+      PKT_signature *sig = node->pkt->pkt.signature;
+
+      if (!strcmp (propname, "sig_created"))
+        {
+          snprintf (numbuf, sizeof numbuf, "%lu", (ulong)sig->timestamp);
+          result = numbuf;
+        }
+      else if (!strcmp (propname, "sig_created_d"))
+        {
+          result = datestr_from_sig (sig);
+        }
+      else if (!strcmp (propname, "sig_algo"))
+        {
+          snprintf (numbuf, sizeof numbuf, "%d", sig->pubkey_algo);
+          result = numbuf;
+        }
+      else if (!strcmp (propname, "sig_digest_algo"))
+        {
+          snprintf (numbuf, sizeof numbuf, "%d", sig->digest_algo);
+          result = numbuf;
+        }
+      else
+        result = NULL;
+    }
+  else if (node->pkt->pkttype == PKT_PUBLIC_KEY
+           || node->pkt->pkttype == PKT_SECRET_KEY
+           || node->pkt->pkttype == PKT_PUBLIC_SUBKEY
+           || node->pkt->pkttype == PKT_SECRET_SUBKEY)
+    {
+      PKT_public_key *pk = node->pkt->pkt.public_key;
+
+      if (!strcmp (propname, "secret"))
+        {
+          result = (node->pkt->pkttype == PKT_SECRET_KEY
+                    || node->pkt->pkttype == PKT_SECRET_SUBKEY)? "1":"0";
+        }
+      else if (!strcmp (propname, "key_algo"))
+        {
+          snprintf (numbuf, sizeof numbuf, "%d", pk->pubkey_algo);
+          result = numbuf;
+        }
+      if (!strcmp (propname, "key_created"))
+        {
+          snprintf (numbuf, sizeof numbuf, "%lu", (ulong)pk->timestamp);
+          result = numbuf;
+        }
+      else if (!strcmp (propname, "key_created_d"))
+        {
+          result = datestr_from_pk (pk);
+        }
+      else
+        result = NULL;
+    }
+  else
+    result = NULL;
+
+  return result;
+}
+
+
+/*
+ * Apply the keep-uid filter to the keyblock.  The deleted nodes are
+ * marked and thus the caller should call commit_kbnode afterwards.
+ * KEYBLOCK must not have any blocks marked as deleted.
+ */
+static void
+apply_keep_uid_filter (kbnode_t keyblock, recsel_expr_t selector)
+{
+  kbnode_t node;
+
+  for (node = keyblock->next; node; node = node->next )
+    {
+      if (node->pkt->pkttype == PKT_USER_ID)
+        {
+          if (!recsel_select (selector, impex_filter_getval, node))
+            {
+
+              /* log_debug ("keep-uid: deleting '%s'\n", */
+              /*            node->pkt->pkt.user_id->name); */
+              /* The UID packet and all following packets up to the
+               * next UID or a subkey.  */
+              delete_kbnode (node);
+              for (; node->next
+                     && node->next->pkt->pkttype != PKT_USER_ID
+                     && node->next->pkt->pkttype != PKT_PUBLIC_SUBKEY
+                     && node->next->pkt->pkttype != PKT_SECRET_SUBKEY ;
+                   node = node->next)
+                delete_kbnode (node->next);
+           }
+          /* else */
+          /*   log_debug ("keep-uid: keeping '%s'\n", */
+          /*              node->pkt->pkt.user_id->name); */
+        }
+    }
+}
+
+
+/*
+ * Apply the drop-sig filter to the keyblock.  The deleted nodes are
+ * marked and thus the caller should call commit_kbnode afterwards.
+ * KEYBLOCK must not have any blocks marked as deleted.
+ */
+static void
+apply_drop_sig_filter (kbnode_t keyblock, recsel_expr_t selector)
+{
+  kbnode_t node;
+  int active = 0;
+  u32 main_keyid[2];
+  PKT_signature *sig;
+
+  keyid_from_pk (keyblock->pkt->pkt.public_key, main_keyid);
+
+  /* Loop over all signatures for user id and attribute packets which
+   * are not self signatures.  */
+  for (node = keyblock->next; node; node = node->next )
+    {
+      if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
+          || node->pkt->pkttype == PKT_SECRET_SUBKEY)
+        break; /* ready.  */
+      if (node->pkt->pkttype == PKT_USER_ID)
+        active = 1;
+      if (!active)
+        continue;
+      if (node->pkt->pkttype != PKT_SIGNATURE
+          && node->pkt->pkttype != PKT_ATTRIBUTE)
+        continue;
+
+      sig = node->pkt->pkt.signature;
+      if (main_keyid[0] == sig->keyid[0] || main_keyid[1] == sig->keyid[1])
+        continue;  /* Skip self-signatures.  */
+
+      if (IS_UID_SIG(sig) || IS_UID_REV(sig))
+        {
+          if (recsel_select (selector, impex_filter_getval, node))
+            delete_kbnode (node);
+        }
+    }
+}
+
+
 /*
  * Try to import one keyblock. Return an error only in serious cases,
  * but never for an invalid keyblock.  It uses log_error to increase
@@ -932,13 +1325,13 @@ check_prefs (ctrl_t ctrl, kbnode_t keyblock)
  */
 static int
 import_one (ctrl_t ctrl,
-            const char *fname, kbnode_t keyblock, struct stats_s *stats,
+            kbnode_t keyblock, struct import_stats_s *stats,
            unsigned char **fpr, size_t *fpr_len, unsigned int options,
            int from_sk, int silent,
             import_screener_t screener, void *screener_arg)
 {
   PKT_public_key *pk;
-  PKT_public_key *pk_orig;
+  PKT_public_key *pk_orig = NULL;
   kbnode_t node, uidnode;
   kbnode_t keyblock_orig = NULL;
   byte fpr2[MAX_FINGERPRINT_LEN];
@@ -951,6 +1344,8 @@ import_one (ctrl_t ctrl,
   int non_self = 0;
   size_t an;
   char pkstrbuf[PUBKEY_STRING_SIZE];
+  int merge_keys_done = 0;
+  int any_filter = 0;
 
   /* Get the key and print some info about it. */
   node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
@@ -1021,26 +1416,28 @@ import_one (ctrl_t ctrl,
     log_info (_("key %s: PKS subkey corruption repaired\n"),
               keystr_from_pk(pk));
 
-  rc = chk_self_sigs( fname, keyblock , pk, keyid, &non_self );
-  if (rc )
-    return rc== -1? 0:rc;
+  if (chk_self_sigs (keyblock, keyid, &non_self))
+    return 0;  /* Invalid keyblock - error already printed.  */
 
   /* If we allow such a thing, mark unsigned uids as valid */
   if (opt.allow_non_selfsigned_uid)
     {
       for (node=keyblock; node; node = node->next )
-        if (node->pkt->pkttype == PKT_USER_ID && !(node->flag & 1) )
+        if (node->pkt->pkttype == PKT_USER_ID
+            && !(node->flag & NODE_GOOD_SELFSIG)
+            && !(node->flag & NODE_BAD_SELFSIG) )
           {
             char *user=utf8_to_native(node->pkt->pkt.user_id->name,
                                       node->pkt->pkt.user_id->len,0);
-            node->flag |= 1;
+            /* Fake a good signature status for the user id.  */
+            node->flag |= NODE_GOOD_SELFSIG;
             log_info( _("key %s: accepted non self-signed user ID \"%s\"\n"),
                       keystr_from_pk(pk),user);
             xfree(user);
          }
     }
 
-  if (!delete_inv_parts( fname, keyblock, keyid, options ) )
+  if (!delete_inv_parts (keyblock, keyid, options ) )
     {
       if (!silent)
         {
@@ -1052,6 +1449,63 @@ import_one (ctrl_t ctrl,
       return 0;
     }
 
+  /* Get rid of deleted nodes.  */
+  commit_kbnode (&keyblock);
+
+  /* Apply import filter.  */
+  if (import_filter.keep_uid)
+    {
+      apply_keep_uid_filter (keyblock, import_filter.keep_uid);
+      commit_kbnode (&keyblock);
+      any_filter = 1;
+    }
+  if (import_filter.drop_sig)
+    {
+      apply_drop_sig_filter (keyblock, import_filter.drop_sig);
+      commit_kbnode (&keyblock);
+      any_filter = 1;
+    }
+
+  /* If we ran any filter we need to check that at least one user id
+   * is left in the keyring.  Note that we do not use log_error in
+   * this case. */
+  if (any_filter && !any_uid_left (keyblock))
+    {
+      if (!opt.quiet )
+        log_info ( _("key %s: no valid user IDs\n"), keystr_from_pk (pk));
+      stats->no_user_id++;
+      return 0;
+    }
+
+  /* Show the key in the form it is merged or inserted.  We skip this
+   * if "import-export" is also active without --armor or the output
+   * file has explicily been given. */
+  if ((options & IMPORT_SHOW)
+      && !((options & IMPORT_EXPORT) && !opt.armor && !opt.outfile))
+    {
+      merge_keys_and_selfsig (keyblock);
+      merge_keys_done = 1;
+      /* Note that we do not want to show the validity because the key
+       * has not yet imported.  */
+      list_keyblock_direct (ctrl, keyblock, 0, 0, 1, 1);
+      es_fflush (es_stdout);
+    }
+
+  /* Write the keyblock to the output and do not actually import.  */
+  if ((options & IMPORT_EXPORT))
+    {
+      if (!merge_keys_done)
+        {
+          merge_keys_and_selfsig (keyblock);
+          merge_keys_done = 1;
+        }
+      rc = write_keyblock_to_output (keyblock, opt.armor, opt.export_options);
+      goto leave;
+    }
+
+  if (opt.dry_run)
+    goto leave;
+
   /* Do we have this key already in one of our pubrings ? */
   pk_orig = xmalloc_clear( sizeof *pk_orig );
   rc = get_pubkey_byfprint_fast (pk_orig, fpr2, fpr2len);
@@ -1071,9 +1525,13 @@ import_one (ctrl_t ctrl,
     }
   else if (rc )  /* Insert this key. */
     {
-      KEYDB_HANDLE hd = keydb_new ();
+      KEYDB_HANDLE hd;
+
+      hd = keydb_new ();
+      if (!hd)
+        return gpg_error_from_syserror ();
 
-      rc = keydb_locate_writable (hd, NULL);
+      rc = keydb_locate_writable (hd);
       if (rc)
         {
           log_error (_("no writable keyring found: %s\n"), gpg_strerror (rc));
@@ -1136,6 +1594,11 @@ import_one (ctrl_t ctrl,
       /* Now read the original keyblock again so that we can use
          that handle for updating the keyblock.  */
       hd = keydb_new ();
+      if (!hd)
+        {
+          rc = gpg_error_from_syserror ();
+          goto leave;
+        }
       keydb_disable_caching (hd);
       rc = keydb_search_fpr (hd, fpr2);
       if (rc )
@@ -1163,7 +1626,7 @@ import_one (ctrl_t ctrl,
       clear_kbnode_flags( keyblock_orig );
       clear_kbnode_flags( keyblock );
       n_uids = n_sigs = n_subk = n_uids_cleaned = 0;
-      rc = merge_blocks( fname, keyblock_orig, keyblock,
+      rc = merge_blocks (keyblock_orig, keyblock,
                          keyid, &n_uids, &n_sigs, &n_subk );
       if (rc )
         {
@@ -1251,7 +1714,7 @@ import_one (ctrl_t ctrl,
       keydb_release (hd); hd = NULL;
     }
 
 leave:
+ leave:
   if (mod_key || new_key || same_key)
     {
       /* A little explanation for this: we fill in the fingerprint
@@ -1271,7 +1734,7 @@ import_one (ctrl_t ctrl,
         {
           xfree (*fpr);
           /* Note that we need to compare against 0 here because
-             COUNT gets only incremented after returning form this
+             COUNT gets only incremented after returning from this
              function.  */
           if (!stats->count)
             *fpr = fingerprint_from_pk (pk, NULL, fpr_len);
@@ -1308,9 +1771,9 @@ import_one (ctrl_t ctrl,
    function prints diagnostics and returns an error code.  If BATCH is
    true the secret keys are stored by gpg-agent in the transfer format
    (i.e. no re-protection and aksing for passphrases). */
-static gpg_error_t
-transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock,
-                      int batch)
+gpg_error_t
+transfer_secret_keys (ctrl_t ctrl, struct import_stats_s *stats,
+                      kbnode_t sec_keyblock, int batch, int force)
 {
   gpg_error_t err = 0;
   void *kek = NULL;
@@ -1331,6 +1794,7 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock,
   unsigned char *wrappedkey = NULL;
   size_t wrappedkeylen;
   char *cache_nonce = NULL;
+  int stub_key_skipped = 0;
 
   /* Get the current KEK.  */
   err = agent_keywrap_key (ctrl, 0, &kek, &keklen);
@@ -1378,8 +1842,11 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock,
       if (!ski)
         BUG ();
 
-      stats->count++;
-      stats->secret_read++;
+      if (stats)
+        {
+          stats->count++;
+          stats->secret_read++;
+        }
 
       /* We ignore stub keys.  The way we handle them in other parts
          of the code is by asking the agent whether any secret key is
@@ -1391,7 +1858,10 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock,
          has been inserted and a stub key is in turn generated by the
          agent.  */
       if (ski->s2k.mode == 1001 || ski->s2k.mode == 1002)
-        continue;
+        {
+          stub_key_skipped = 1;
+          continue;
+        }
 
       /* Convert our internal secret key object into an S-expression.  */
       nskey = pubkey_get_nskey (pk->pubkey_algo);
@@ -1415,6 +1885,7 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock,
           else
             {
               const char *curvename = openpgp_oid_to_curve (curvestr, 1);
+              gcry_sexp_release (curve);
               err = gcry_sexp_build (&curve, NULL, "(curve %s)",
                                      curvename?curvename:curvestr);
               xfree (curvestr);
@@ -1539,7 +2010,7 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock,
       {
         char *desc = gpg_format_keydesc (pk, FORMAT_KEYDESC_IMPORT, 1);
         err = agent_import_key (ctrl, desc, &cache_nonce,
-                                wrappedkey, wrappedkeylen, batch);
+                                wrappedkey, wrappedkeylen, batch, force);
         xfree (desc);
       }
       if (!err)
@@ -1547,7 +2018,8 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock,
           if (opt.verbose)
             log_info (_("key %s: secret key imported\n"),
                       keystr_from_pk_with_sub (main_pk, pk));
-          stats->secret_imported++;
+          if (stats)
+            stats->secret_imported++;
         }
       else if ( gpg_err_code (err) == GPG_ERR_EEXIST )
         {
@@ -1555,7 +2027,8 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock,
             log_info (_("key %s: secret key already exists\n"),
                       keystr_from_pk_with_sub (main_pk, pk));
           err = 0;
-          stats->secret_dups++;
+          if (stats)
+            stats->secret_dups++;
         }
       else
         {
@@ -1568,6 +2041,10 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock,
         }
     }
 
+  if (!err && stub_key_skipped)
+    /* We need to notify user how to migrate stub keys.  */
+    err = gpg_error (GPG_ERR_NOT_PROCESSED);
+
  leave:
   gcry_sexp_release (curve);
   xfree (cache_nonce);
@@ -1630,12 +2107,12 @@ sec_to_pub_keyblock (kbnode_t sec_keyblock)
 /****************
  * Ditto for secret keys.  Handling is simpler than for public keys.
  * We allow secret key importing only when allow is true, this is so
- * that a secret key can not be imported accidently and thereby tampering
+ * that a secret key can not be imported accidentally and thereby tampering
  * with the trust calculation.
  */
 static int
-import_secret_one (ctrl_t ctrl, const char *fname, kbnode_t keyblock,
-                   struct stats_s *stats, int batch, unsigned int options,
+import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
+                   struct import_stats_s *stats, int batch, unsigned int options,
                    int for_migration,
                    import_screener_t screener, void *screener_arg)
 {
@@ -1712,7 +2189,7 @@ import_secret_one (ctrl_t ctrl, const char *fname, kbnode_t keyblock,
 #ifdef ENABLE_SELINUX_HACKS
   if (1)
     {
-      /* We don't allow to import secret keys because that may be used
+      /* We don't allow importing secret keys because that may be used
          to put a secret key into the keyring and the user might later
          be tricked into signing stuff with that key.  */
       log_error (_("importing secret keys not allowed\n"));
@@ -1734,7 +2211,7 @@ import_secret_one (ctrl_t ctrl, const char *fname, kbnode_t keyblock,
       /* Note that this outputs an IMPORT_OK status message for the
         public key block, and below we will output another one for
         the secret keys.  FIXME?  */
-      import_one (ctrl, fname, pub_keyblock, stats,
+      import_one (ctrl, pub_keyblock, stats,
                  NULL, NULL, options, 1, for_migration,
                   screener, screener_arg);
 
@@ -1757,15 +2234,43 @@ import_secret_one (ctrl_t ctrl, const char *fname, kbnode_t keyblock,
                        keystr_from_pk (pk));
           else
             {
-             nr_prev = stats->secret_imported;
-              if (!transfer_secret_keys (ctrl, stats, keyblock, batch))
+              gpg_error_t err;
+
+              /* transfer_secret_keys collects subkey stats.  */
+              struct import_stats_s subkey_stats = {0};
+
+              err = transfer_secret_keys (ctrl, &subkey_stats, keyblock,
+                                          batch, 0);
+              if (gpg_err_code (err) == GPG_ERR_NOT_PROCESSED)
+                {
+                  /* TRANSLATORS: For smartcard, each private key on
+                     host has a reference (stub) to a smartcard and
+                     actual private key data is stored on the card.  A
+                     single smartcard can have up to three private key
+                     data.  Importing private key stub is always
+                     skipped in 2.1, and it returns
+                     GPG_ERR_NOT_PROCESSED.  Instead, user should be
+                     suggested to run 'gpg --card-status', then,
+                     references to a card will be automatically
+                     created again.  */
+                  log_info (_("To migrate '%s', with each smartcard, "
+                              "run: %s\n"), "secring.gpg", "gpg --card-status");
+                  err = 0;
+                }
+              if (!err)
                 {
                  int status = 16;
                   if (!opt.quiet)
                     log_info (_("key %s: secret key imported\n"),
                               keystr_from_pk (pk));
-                 if (stats->secret_imported > nr_prev)
-                   status |= 1;
+                 if (subkey_stats.secret_imported)
+                    {
+                      status |= 1;
+                      stats->secret_imported += 1;
+                    }
+                 if (subkey_stats.secret_dups)
+                    stats->secret_dups += 1;
+
                   if (is_status_enabled ())
                     print_import_ok (pk, status);
                   check_prefs (ctrl, node);
@@ -1783,7 +2288,7 @@ import_secret_one (ctrl_t ctrl, const char *fname, kbnode_t keyblock,
  * Import a revocation certificate; this is a single signature packet.
  */
 static int
-import_revoke_cert( const char *fname, kbnode_t node, struct stats_s *stats )
+import_revoke_cert (kbnode_t node, struct import_stats_s *stats)
 {
   PKT_public_key *pk = NULL;
   kbnode_t onode;
@@ -1792,11 +2297,9 @@ import_revoke_cert( const char *fname, kbnode_t node, struct stats_s *stats )
   u32 keyid[2];
   int rc = 0;
 
-  (void)fname;
-
-  assert( !node->next );
-  assert( node->pkt->pkttype == PKT_SIGNATURE );
-  assert( node->pkt->pkt.signature->sig_class == 0x20 );
+  log_assert (!node->next );
+  log_assert (node->pkt->pkttype == PKT_SIGNATURE );
+  log_assert (node->pkt->pkt.signature->sig_class == 0x20 );
 
   keyid[0] = node->pkt->pkt.signature->keyid[0];
   keyid[1] = node->pkt->pkt.signature->keyid[1];
@@ -1819,6 +2322,12 @@ import_revoke_cert( const char *fname, kbnode_t node, struct stats_s *stats )
 
   /* Read the original keyblock. */
   hd = keydb_new ();
+  if (!hd)
+    {
+      rc = gpg_error_from_syserror ();
+      goto leave;
+    }
+
   {
     byte afp[MAX_FINGERPRINT_LEN];
     size_t an;
@@ -1903,18 +2412,21 @@ import_revoke_cert( const char *fname, kbnode_t node, struct stats_s *stats )
 }
 
 
-/*
- * Loop over the keyblock and check all self signatures.
- * Mark all user-ids with a self-signature by setting flag bit 0.
- * Mark all user-ids with an invalid self-signature by setting bit 1.
- * This works also for subkeys, here the subkey is marked.  Invalid or
- * extra subkey sigs (binding or revocation) are marked for deletion.
- * non_self is set to true if there are any sigs other than self-sigs
+/* Loop over the keyblock and check all self signatures.  On return
+ * the following bis in the node flags are set:
+ *
+ * - NODE_GOOD_SELFSIG  :: User ID or subkey has a self-signature
+ * - NODE_BAD_SELFSIG   :: Used ID or subkey has an invalid self-signature
+ * - NODE_DELETION_MARK :: This node shall be deleted
+ *
+ * NON_SELF is set to true if there are any sigs other than self-sigs
  * in this keyblock.
+ *
+ * Returns 0 on success or -1 (but not an error code) if the keyblock
+ * is invalid.
  */
 static int
-chk_self_sigs (const char *fname, kbnode_t keyblock,
-              PKT_public_key *pk, u32 *keyid, int *non_self )
+chk_self_sigs (kbnode_t keyblock, u32 *keyid, int *non_self )
 {
   kbnode_t n, knode = NULL;
   PKT_signature *sig;
@@ -1922,9 +2434,6 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
   u32 bsdate=0, rsdate=0;
   kbnode_t bsnode = NULL, rsnode = NULL;
 
-  (void)fname;
-  (void)pk;
-
   for (n=keyblock; (n = find_next_kbnode (n, 0)); )
     {
       if (n->pkt->pkttype == PKT_PUBLIC_SUBKEY)
@@ -1963,7 +2472,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
             }
 
           /* If it hasn't been marked valid yet, keep trying.  */
-          if (!(unode->flag&1))
+          if (!(unode->flag & NODE_GOOD_SELFSIG))
             {
               rc = check_key_signature (keyblock, n, NULL);
               if ( rc )
@@ -1983,7 +2492,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
                     }
                 }
               else
-                unode->flag |= 1; /* Mark that signature checked. */
+                unode->flag |= NODE_GOOD_SELFSIG;
             }
         }
       else if (IS_KEY_SIG (sig))
@@ -1996,7 +2505,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
                           _("key %s: unsupported public key algorithm\n"):
                           _("key %s: invalid direct key signature\n"),
                           keystr (keyid));
-              n->flag |= 4;
+              n->flag |= NODE_DELETION_MARK;
             }
         }
       else if ( IS_SUBKEY_SIG (sig) )
@@ -2010,7 +2519,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
               if (opt.verbose)
                 log_info (_("key %s: no subkey for key binding\n"),
                           keystr (keyid));
-              n->flag |= 4; /* delete this */
+              n->flag |= NODE_DELETION_MARK;
             }
           else
             {
@@ -2023,19 +2532,19 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
                                 " algorithm\n"):
                               _("key %s: invalid subkey binding\n"),
                               keystr (keyid));
-                  n->flag |= 4;
+                  n->flag |= NODE_DELETION_MARK;
                 }
               else
                 {
                   /* It's valid, so is it newer? */
                   if (sig->timestamp >= bsdate)
                     {
-                      knode->flag |= 1;  /* The subkey is valid.  */
+                      knode->flag |= NODE_GOOD_SELFSIG; /* Subkey is valid.  */
                       if (bsnode)
                         {
                           /* Delete the last binding sig since this
                              one is newer */
-                          bsnode->flag |= 4;
+                          bsnode->flag |= NODE_DELETION_MARK;
                           if (opt.verbose)
                             log_info (_("key %s: removed multiple subkey"
                                         " binding\n"),keystr(keyid));
@@ -2045,7 +2554,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
                       bsdate = sig->timestamp;
                     }
                   else
-                    n->flag |= 4; /* older */
+                    n->flag |= NODE_DELETION_MARK; /* older */
                 }
             }
         }
@@ -2061,7 +2570,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
               if (opt.verbose)
                 log_info (_("key %s: no subkey for key revocation\n"),
                           keystr(keyid));
-              n->flag |= 4; /* delete this */
+              n->flag |= NODE_DELETION_MARK;
             }
           else
             {
@@ -2074,7 +2583,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
                                 " key algorithm\n"):
                               _("key %s: invalid subkey revocation\n"),
                               keystr(keyid));
-                  n->flag |= 4;
+                  n->flag |= NODE_DELETION_MARK;
                 }
               else
                 {
@@ -2085,7 +2594,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
                         {
                           /* Delete the last revocation sig since
                              this one is newer.  */
-                          rsnode->flag |= 4;
+                          rsnode->flag |= NODE_DELETION_MARK;
                           if (opt.verbose)
                             log_info (_("key %s: removed multiple subkey"
                                         " revocation\n"),keystr(keyid));
@@ -2095,7 +2604,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
                       rsdate = sig->timestamp;
                     }
                   else
-                    n->flag |= 4; /* older */
+                    n->flag |= NODE_DELETION_MARK; /* older */
                 }
             }
         }
@@ -2105,28 +2614,25 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
 }
 
 
-/****************
- * delete all parts which are invalid and those signatures whose
- * public key algorithm is not available in this implemenation;
- * but consider RSA as valid, because parse/build_packets knows
- * about it.
- * returns: true if at least one valid user-id is left over.
+/* Delete all parts which are invalid and those signatures whose
+ * public key algorithm is not available in this implemenation; but
+ * consider RSA as valid, because parse/build_packets knows about it.
+ *
+ * Returns: True if at least one valid user-id is left over.
  */
 static int
-delete_inv_parts( const char *fname, kbnode_t keyblock,
-                 u32 *keyid, unsigned int options)
+delete_inv_parts (kbnode_t keyblock, u32 *keyid, unsigned int options)
 {
   kbnode_t node;
   int nvalid=0, uid_seen=0, subkey_seen=0;
 
-  (void)fname;
-
   for (node=keyblock->next; node; node = node->next )
     {
       if (node->pkt->pkttype == PKT_USER_ID)
         {
           uid_seen = 1;
-          if ((node->flag & 2) || !(node->flag & 1) )
+          if ((node->flag & NODE_BAD_SELFSIG)
+              || !(node->flag & NODE_GOOD_SELFSIG))
             {
               if (opt.verbose )
                 {
@@ -2152,7 +2658,8 @@ delete_inv_parts( const char *fname, kbnode_t keyblock,
       else if (   node->pkt->pkttype == PKT_PUBLIC_SUBKEY
                || node->pkt->pkttype == PKT_SECRET_SUBKEY )
         {
-          if ((node->flag & 2) || !(node->flag & 1) )
+          if ((node->flag & NODE_BAD_SELFSIG)
+              || !(node->flag & NODE_GOOD_SELFSIG))
             {
               if (opt.verbose )
                 log_info( _("key %s: skipped subkey\n"),keystr(keyid));
@@ -2240,7 +2747,7 @@ delete_inv_parts( const char *fname, kbnode_t keyblock,
                      node->pkt->pkt.signature->sig_class);
           delete_kbnode(node);
          }
-      else if ((node->flag & 4) ) /* marked for deletion */
+      else if ((node->flag & NODE_DELETION_MARK))
         delete_kbnode( node );
     }
 
@@ -2250,6 +2757,19 @@ delete_inv_parts( const char *fname, kbnode_t keyblock,
   return nvalid;
 }
 
+/* This function returns true if any UID is left in the keyring.  */
+static int
+any_uid_left (kbnode_t keyblock)
+{
+  kbnode_t node;
+
+  for (node=keyblock->next; node; node = node->next)
+    if (node->pkt->pkttype == PKT_USER_ID)
+      return 1;
+  return 0;
+}
+
+
 
 /****************
  * It may happen that the imported keyblock has duplicated user IDs.
@@ -2424,9 +2944,9 @@ revocation_present (ctrl_t ctrl, kbnode_t keyblock)
                          char *tempkeystr=xstrdup(keystr_from_pk(pk));
 
                          /* No, so try and get it */
-                         if(opt.keyserver
-                            && (opt.keyserver_options.options
-                                & KEYSERVER_AUTO_KEY_RETRIEVE))
+                         if ((opt.keyserver_options.options
+                               & KEYSERVER_AUTO_KEY_RETRIEVE)
+                              && keyserver_any_configured (ctrl))
                            {
                              log_info(_("WARNING: key %s may be revoked:"
                                         " fetching revocation key %s\n"),
@@ -2434,7 +2954,7 @@ revocation_present (ctrl_t ctrl, kbnode_t keyblock)
                              keyserver_import_fprint (ctrl,
                                                        sig->revkey[idx].fpr,
                                                        MAX_FINGERPRINT_LEN,
-                                                       opt.keyserver);
+                                                       opt.keyserver, 0);
 
                              /* Do we have it now? */
                              rc=get_pubkey_byfprint_fast (NULL,
@@ -2467,10 +2987,10 @@ revocation_present (ctrl_t ctrl, kbnode_t keyblock)
  *   the signature's public key yet; verification is done when putting it
  *   into the trustdb, which is done automagically as soon as this pubkey
  *   is used.
- * Note: We indicate newly inserted packets with flag bit 0
+ * Note: We indicate newly inserted packets with NODE_FLAG_A.
  */
 static int
-merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
+merge_blocks (kbnode_t keyblock_orig, kbnode_t keyblock,
              u32 *keyid, int *n_uids, int *n_sigs, int *n_subk )
 {
   kbnode_t onode, node;
@@ -2503,7 +3023,7 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
             {
               kbnode_t n2 = clone_kbnode(node);
               insert_kbnode( keyblock_orig, n2, 0 );
-              n2->flag |= 1;
+              n2->flag |= NODE_FLAG_A;
               ++*n_sigs;
               if(!opt.quiet)
                 {
@@ -2543,7 +3063,7 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
             {
               kbnode_t n2 = clone_kbnode(node);
               insert_kbnode( keyblock_orig, n2, 0 );
-              n2->flag |= 1;
+              n2->flag |= NODE_FLAG_A;
               ++*n_sigs;
               if(!opt.quiet)
                 log_info( _("key %s: direct key signature added\n"),
@@ -2555,7 +3075,7 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
   /* 3rd: try to merge new certificates in */
   for (onode=keyblock_orig->next; onode; onode=onode->next)
     {
-      if (!(onode->flag & 1) && onode->pkt->pkttype == PKT_USER_ID)
+      if (!(onode->flag & NODE_FLAG_A) && onode->pkt->pkttype == PKT_USER_ID)
         {
           /* find the user id in the imported keyblock */
           for (node=keyblock->next; node; node=node->next)
@@ -2565,7 +3085,7 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
               break;
           if (node ) /* found: merge */
             {
-              rc = merge_sigs( onode, node, n_sigs, fname, keyid );
+              rc = merge_sigs (onode, node, n_sigs);
               if (rc )
                 return rc;
            }
@@ -2585,7 +3105,7 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
               break;
           if (!onode ) /* this is a new user id: append */
             {
-              rc = append_uid( keyblock_orig, node, n_sigs, fname, keyid);
+              rc = append_uid (keyblock_orig, node, n_sigs);
               if (rc )
                 return rc;
               ++*n_uids;
@@ -2607,7 +3127,7 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
               break;
           if (!onode ) /* This is a new subkey: append.  */
             {
-              rc = append_key (keyblock_orig, node, n_sigs, fname, keyid);
+              rc = append_key (keyblock_orig, node, n_sigs);
               if (rc)
                 return rc;
               ++*n_subk;
@@ -2623,7 +3143,7 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
               break;
           if (!onode ) /* This is a new subkey: append.  */
             {
-              rc = append_key (keyblock_orig, node, n_sigs, fname, keyid);
+              rc = append_key (keyblock_orig, node, n_sigs);
               if (rc )
                 return rc;
               ++*n_subk;
@@ -2634,7 +3154,7 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
   /* 6th: merge subkey certificates */
   for (onode=keyblock_orig->next; onode; onode=onode->next)
     {
-      if (!(onode->flag & 1)
+      if (!(onode->flag & NODE_FLAG_A)
           && (onode->pkt->pkttype == PKT_PUBLIC_SUBKEY
               || onode->pkt->pkttype == PKT_SECRET_SUBKEY))
         {
@@ -2649,7 +3169,7 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
            }
           if (node) /* Found: merge.  */
             {
-              rc = merge_keysigs( onode, node, n_sigs, fname, keyid );
+              rc = merge_keysigs( onode, node, n_sigs);
               if (rc )
                 return rc;
            }
@@ -2660,20 +3180,16 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
 }
 
 
-/*
+/* Helper function for merge_blocks.
  * Append the userid starting with NODE and all signatures to KEYBLOCK.
  */
 static int
-append_uid (kbnode_t keyblock, kbnode_t node, int *n_sigs,
-            const char *fname, u32 *keyid )
+append_uid (kbnode_t keyblock, kbnode_t node, int *n_sigs)
 {
   kbnode_t n;
   kbnode_t n_where = NULL;
 
-  (void)fname;
-  (void)keyid;
-
-  assert(node->pkt->pkttype == PKT_USER_ID );
+  log_assert (node->pkt->pkttype == PKT_USER_ID );
 
   /* find the position */
   for (n = keyblock; n; n_where = n, n = n->next)
@@ -2698,8 +3214,8 @@ append_uid (kbnode_t keyblock, kbnode_t node, int *n_sigs,
        }
       else
         add_kbnode( keyblock, n );
-      n->flag |= 1;
-      node->flag |= 1;
+      n->flag |= NODE_FLAG_A;
+      node->flag |= NODE_FLAG_A;
       if (n->pkt->pkttype == PKT_SIGNATURE )
         ++*n_sigs;
 
@@ -2712,22 +3228,18 @@ append_uid (kbnode_t keyblock, kbnode_t node, int *n_sigs,
 }
 
 
-/*
+/* Helper function for merge_blocks
  * Merge the sigs from SRC onto DST. SRC and DST are both a PKT_USER_ID.
  * (how should we handle comment packets here?)
  */
 static int
-merge_sigs (kbnode_t dst, kbnode_t src, int *n_sigs,
-            const char *fname, u32 *keyid)
+merge_sigs (kbnode_t dst, kbnode_t src, int *n_sigs)
 {
   kbnode_t n, n2;
   int found = 0;
 
-  (void)fname;
-  (void)keyid;
-
-  assert(dst->pkt->pkttype == PKT_USER_ID );
-  assert(src->pkt->pkttype == PKT_USER_ID );
+  log_assert (dst->pkt->pkttype == PKT_USER_ID);
+  log_assert (src->pkt->pkttype == PKT_USER_ID);
 
   for (n=src->next; n && n->pkt->pkttype != PKT_USER_ID; n = n->next)
     {
@@ -2751,8 +3263,8 @@ merge_sigs (kbnode_t dst, kbnode_t src, int *n_sigs,
            * one is released first */
           n2 = clone_kbnode(n);
           insert_kbnode( dst, n2, PKT_SIGNATURE );
-          n2->flag |= 1;
-          n->flag |= 1;
+          n2->flag |= NODE_FLAG_A;
+          n->flag |= NODE_FLAG_A;
           ++*n_sigs;
        }
     }
@@ -2761,21 +3273,17 @@ merge_sigs (kbnode_t dst, kbnode_t src, int *n_sigs,
 }
 
 
-/*
+/* Helper function for merge_blocks
  * Merge the sigs from SRC onto DST. SRC and DST are both a PKT_xxx_SUBKEY.
  */
 static int
-merge_keysigs (kbnode_t dst, kbnode_t src, int *n_sigs,
-               const char *fname, u32 *keyid)
+merge_keysigs (kbnode_t dst, kbnode_t src, int *n_sigs)
 {
   kbnode_t n, n2;
   int found = 0;
 
-  (void)fname;
-  (void)keyid;
-
-  assert (dst->pkt->pkttype == PKT_PUBLIC_SUBKEY
-          || dst->pkt->pkttype == PKT_SECRET_SUBKEY);
+  log_assert (dst->pkt->pkttype == PKT_PUBLIC_SUBKEY
+              || dst->pkt->pkttype == PKT_SECRET_SUBKEY);
 
   for (n=src->next; n ; n = n->next)
     {
@@ -2812,8 +3320,8 @@ merge_keysigs (kbnode_t dst, kbnode_t src, int *n_sigs,
            * one is released first */
           n2 = clone_kbnode(n);
           insert_kbnode( dst, n2, PKT_SIGNATURE );
-          n2->flag |= 1;
-          n->flag |= 1;
+          n2->flag |= NODE_FLAG_A;
+          n->flag |= NODE_FLAG_A;
           ++*n_sigs;
        }
     }
@@ -2822,21 +3330,17 @@ merge_keysigs (kbnode_t dst, kbnode_t src, int *n_sigs,
 }
 
 
-/*
+/* Helper function for merge_blocks.
  * Append the subkey starting with NODE and all signatures to KEYBLOCK.
  * Mark all new and copied packets by setting flag bit 0.
  */
 static int
-append_key (kbnode_t keyblock, kbnode_t node, int *n_sigs,
-            const char *fname, u32 *keyid)
+append_key (kbnode_t keyblock, kbnode_t node, int *n_sigs)
 {
   kbnode_t n;
 
-  (void)fname;
-  (void)keyid;
-
-  assert( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
-          || node->pkt->pkttype == PKT_SECRET_SUBKEY );
+  log_assert (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
+              || node->pkt->pkttype == PKT_SECRET_SUBKEY);
 
   while (node)
     {
@@ -2844,8 +3348,8 @@ append_key (kbnode_t keyblock, kbnode_t node, int *n_sigs,
        * one is released first */
       n = clone_kbnode(node);
       add_kbnode( keyblock, n );
-      n->flag |= 1;
-      node->flag |= 1;
+      n->flag |= NODE_FLAG_A;
+      node->flag |= NODE_FLAG_A;
       if (n->pkt->pkttype == PKT_SIGNATURE )
         ++*n_sigs;