indent: Fix indentation of read_block in g10/import.c
[gnupg.git] / g10 / keyedit.c
index 4803f9e..00b4e72 100644 (file)
@@ -1,6 +1,7 @@
 /* keyedit.c - Edit properties of a key
  * Copyright (C) 1998-2010 Free Software Foundation, Inc.
- * Copyright (C) 1998-2015 Werner Koch
+ * Copyright (C) 1998-2017 Werner Koch
+ * Copyright (C) 2015, 2016 g10 Code GmbH
  *
  * This file is part of GnuPG.
  *
@@ -15,7 +16,7 @@
  * 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/>.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
@@ -23,7 +24,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <assert.h>
 #include <ctype.h>
 #ifdef HAVE_LIBREADLINE
 # define GNUPG_LIBREADLINE_H_INCLUDED
 #include "gpg.h"
 #include "options.h"
 #include "packet.h"
-#include "status.h"
-#include "iobuf.h"
+#include "../common/status.h"
+#include "../common/iobuf.h"
 #include "keydb.h"
 #include "photoid.h"
-#include "util.h"
+#include "../common/util.h"
 #include "main.h"
 #include "trustdb.h"
 #include "filter.h"
-#include "ttyio.h"
-#include "status.h"
-#include "i18n.h"
+#include "../common/ttyio.h"
+#include "../common/status.h"
+#include "../common/i18n.h"
 #include "keyserver-internal.h"
 #include "call-agent.h"
-#include "host2net.h"
+#include "../common/host2net.h"
+#include "tofu.h"
+#include "key-check.h"
+#include "keyedit.h"
 
 static void show_prefs (PKT_user_id * uid, PKT_signature * selfsig,
                        int verbose);
-static void show_names (estream_t fp, KBNODE keyblock, PKT_public_key * pk,
+static void show_names (ctrl_t ctrl, estream_t fp,
+                        kbnode_t keyblock, PKT_public_key * pk,
                        unsigned int flag, int with_prefs);
 static void show_key_with_all_names (ctrl_t ctrl, estream_t fp,
                                      KBNODE keyblock, int only_marked,
                                     int with_revoker, int with_fpr,
                                     int with_subkeys, int with_prefs,
                                      int nowarn);
-static void show_key_and_fingerprint (kbnode_t keyblock, int with_subkeys);
+static void show_key_and_fingerprint (ctrl_t ctrl,
+                                      kbnode_t keyblock, int with_subkeys);
 static void show_key_and_grip (kbnode_t keyblock);
 static void subkey_expire_warning (kbnode_t keyblock);
-static int menu_adduid (KBNODE keyblock, int photo, const char *photo_name,
-                        const char *uidstr);
+static int menu_adduid (ctrl_t ctrl, kbnode_t keyblock,
+                        int photo, const char *photo_name, const char *uidstr);
 static void menu_deluid (KBNODE pub_keyblock);
-static int menu_delsig (KBNODE pub_keyblock);
-static int menu_clean (KBNODE keyblock, int self_only);
+static int menu_delsig (ctrl_t ctrl, kbnode_t pub_keyblock);
+static int menu_clean (ctrl_t ctrl, kbnode_t keyblock, int self_only);
 static void menu_delkey (KBNODE pub_keyblock);
 static int menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive);
-static int menu_expire (KBNODE pub_keyblock);
-static int menu_backsign (KBNODE pub_keyblock);
-static int menu_set_primary_uid (KBNODE pub_keyblock);
-static int menu_set_preferences (KBNODE pub_keyblock);
-static int menu_set_keyserver_url (const char *url, KBNODE pub_keyblock);
-static int menu_set_notation (const char *string, KBNODE pub_keyblock);
+static gpg_error_t menu_expire (ctrl_t ctrl, kbnode_t pub_keyblock,
+                                int unattended, u32 newexpiration);
+static int menu_changeusage (ctrl_t ctrl, kbnode_t keyblock);
+static int menu_backsign (ctrl_t ctrl, kbnode_t pub_keyblock);
+static int menu_set_primary_uid (ctrl_t ctrl, kbnode_t pub_keyblock);
+static int menu_set_preferences (ctrl_t ctrl, kbnode_t pub_keyblock);
+static int menu_set_keyserver_url (ctrl_t ctrl,
+                                   const char *url, kbnode_t pub_keyblock);
+static int menu_set_notation (ctrl_t ctrl,
+                              const char *string, kbnode_t pub_keyblock);
 static int menu_select_uid (KBNODE keyblock, int idx);
 static int menu_select_uid_namehash (KBNODE keyblock, const char *namehash);
-static int menu_select_key (KBNODE keyblock, int idx);
+static int menu_select_key (KBNODE keyblock, int idx, char *p);
 static int count_uids (KBNODE keyblock);
 static int count_uids_with_flag (KBNODE keyblock, unsigned flag);
 static int count_keys_with_flag (KBNODE keyblock, unsigned flag);
 static int count_selected_uids (KBNODE keyblock);
 static int real_uids_left (KBNODE keyblock);
 static int count_selected_keys (KBNODE keyblock);
-static int menu_revsig (KBNODE keyblock);
-static int menu_revuid (KBNODE keyblock);
-static int menu_revkey (KBNODE pub_keyblock);
-static int menu_revsubkey (KBNODE pub_keyblock);
+static int menu_revsig (ctrl_t ctrl, kbnode_t keyblock);
+static int menu_revuid (ctrl_t ctrl, kbnode_t keyblock);
+static int core_revuid (ctrl_t ctrl, kbnode_t keyblock, KBNODE node,
+                        const struct revocation_reason_info *reason,
+                        int *modified);
+static int menu_revkey (ctrl_t ctrl, kbnode_t pub_keyblock);
+static int menu_revsubkey (ctrl_t ctrl, kbnode_t pub_keyblock);
 #ifndef NO_TRUST_MODELS
-static int enable_disable_key (KBNODE keyblock, int disable);
+static int enable_disable_key (ctrl_t ctrl, kbnode_t keyblock, int disable);
 #endif /*!NO_TRUST_MODELS*/
-static void menu_showphoto (KBNODE keyblock);
+static void menu_showphoto (ctrl_t ctrl, kbnode_t keyblock);
 
 static int update_trust = 0;
 
 #define CONTROL_D ('D' - 'A' + 1)
 
-#define NODFLG_BADSIG (1<<0)   /* Bad signature.  */
-#define NODFLG_NOKEY  (1<<1)   /* No public key.  */
-#define NODFLG_SIGERR (1<<2)   /* Other sig error.  */
-
-#define NODFLG_MARK_A (1<<4)   /* Temporary mark.  */
-#define NODFLG_DELSIG (1<<5)   /* To be deleted.  */
-
-#define NODFLG_SELUID (1<<8)   /* Indicate the selected userid. */
-#define NODFLG_SELKEY (1<<9)   /* Indicate the selected key.  */
-#define NODFLG_SELSIG (1<<10)  /* Indicate a selected signature.  */
-
 struct sign_attrib
 {
   int non_exportable, non_revocable;
@@ -119,7 +120,7 @@ struct sign_attrib
 /* TODO: Fix duplicated code between here and the check-sigs/list-sigs
    code in keylist.c. */
 static int
-print_and_check_one_sig_colon (KBNODE keyblock, KBNODE node,
+print_and_check_one_sig_colon (ctrl_t ctrl, kbnode_t keyblock, kbnode_t node,
                               int *inv_sigs, int *no_key, int *oth_err,
                               int *is_selfsig, int print_without_key)
 {
@@ -129,7 +130,7 @@ print_and_check_one_sig_colon (KBNODE keyblock, KBNODE node,
   /* TODO: Make sure a cached sig record here still has the pk that
      issued it.  See also keylist.c:list_keyblock_print */
 
-  rc = check_key_signature (keyblock, node, is_selfsig);
+  rc = check_key_signature (ctrl, keyblock, node, is_selfsig);
   switch (gpg_err_code (rc))
     {
     case 0:
@@ -186,24 +187,24 @@ print_and_check_one_sig_colon (KBNODE keyblock, KBNODE node,
 
 
 /*
- * Print information about a signature, check it and return true if
- * the signature is okay.  NODE must be a signature packet.  With
- * EXTENDED set all possible signature list options will always be
- * printed.
+ * Print information about a signature (rc is its status), check it
+ * and return true if the signature is okay.  NODE must be a signature
+ * packet.  With EXTENDED set all possible signature list options will
+ * always be printed.
  */
-static int
-print_and_check_one_sig (KBNODE keyblock, KBNODE node,
-                        int *inv_sigs, int *no_key, int *oth_err,
-                        int *is_selfsig, int print_without_key, int extended)
+int
+keyedit_print_one_sig (ctrl_t ctrl, estream_t fp,
+                       int rc, kbnode_t keyblock, kbnode_t node,
+                      int *inv_sigs, int *no_key, int *oth_err,
+                      int is_selfsig, int print_without_key, int extended)
 {
   PKT_signature *sig = node->pkt->pkt.signature;
-  int rc, sigrc;
+  int sigrc;
   int is_rev = sig->sig_class == 0x30;
 
   /* TODO: Make sure a cached sig record here still has the pk that
      issued it.  See also keylist.c:list_keyblock_print */
 
-  rc = check_key_signature (keyblock, node, is_selfsig);
   switch (gpg_err_code (rc))
     {
     case 0:
@@ -232,7 +233,7 @@ print_and_check_one_sig (KBNODE keyblock, KBNODE node,
     }
   if (sigrc != '?' || print_without_key)
     {
-      tty_printf ("%s%c%c %c%c%c%c%c%c %s %s",
+      tty_fprintf (fp, "%s%c%c %c%c%c%c%c%c %s %s",
                  is_rev ? "rev" : "sig", sigrc,
                  (sig->sig_class - 0x10 > 0 &&
                   sig->sig_class - 0x10 <
@@ -248,38 +249,41 @@ print_and_check_one_sig (KBNODE keyblock, KBNODE node,
                   keystr (sig->keyid),
                  datestr_from_sig (sig));
       if ((opt.list_options & LIST_SHOW_SIG_EXPIRE) || extended )
-       tty_printf (" %s", expirestr_from_sig (sig));
-      tty_printf ("  ");
+       tty_fprintf (fp, " %s", expirestr_from_sig (sig));
+      tty_fprintf (fp, "  ");
       if (sigrc == '%')
-       tty_printf ("[%s] ", gpg_strerror (rc));
+       tty_fprintf (fp, "[%s] ", gpg_strerror (rc));
       else if (sigrc == '?')
        ;
-      else if (*is_selfsig)
+      else if (is_selfsig)
        {
-         tty_printf (is_rev ? _("[revocation]") : _("[self-signature]"));
+         tty_fprintf (fp, is_rev ? _("[revocation]") : _("[self-signature]"));
           if (extended && sig->flags.chosen_selfsig)
-            tty_printf ("*");
+            tty_fprintf (fp, "*");
        }
       else
        {
          size_t n;
-         char *p = get_user_id (sig->keyid, &n);
-         tty_print_utf8_string2 (NULL, p, n,
+         char *p = get_user_id (ctrl, sig->keyid, &n, NULL);
+         tty_print_utf8_string2 (fp, p, n,
                                  opt.screen_columns - keystrlen () - 26 -
                                  ((opt.
                                    list_options & LIST_SHOW_SIG_EXPIRE) ? 11
                                   : 0));
          xfree (p);
        }
-      tty_printf ("\n");
+      if (fp == log_get_stream ())
+        log_printf ("\n");
+      else
+        tty_fprintf (fp, "\n");
 
       if (sig->flags.policy_url
           && ((opt.list_options & LIST_SHOW_POLICY_URLS) || extended))
-       show_policy_url (sig, 3, 0);
+       show_policy_url (sig, 3, (!fp? -1 : fp == log_get_stream ()? 1 : 0));
 
       if (sig->flags.notation
           && ((opt.list_options & LIST_SHOW_NOTATIONS) || extended))
-       show_notation (sig, 3, 0,
+       show_notation (sig, 3, (!fp? -1 : fp == log_get_stream ()? 1 : 0),
                       ((opt.
                         list_options & LIST_SHOW_STD_NOTATIONS) ? 1 : 0) +
                       ((opt.
@@ -287,7 +291,7 @@ print_and_check_one_sig (KBNODE keyblock, KBNODE node,
 
       if (sig->flags.pref_ks
           && ((opt.list_options & LIST_SHOW_KEYSERVER_URLS) || extended))
-       show_keyserver_url (sig, 3, 0);
+       show_keyserver_url (sig, 3, (!fp? -1 : fp == log_get_stream ()? 1 : 0));
 
       if (extended)
         {
@@ -296,12 +300,12 @@ print_and_check_one_sig (KBNODE keyblock, KBNODE node,
 
           s = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PRIMARY_UID, NULL);
           if (s && *s)
-            tty_printf ("             [primary]\n");
+            tty_fprintf (fp, "             [primary]\n");
 
           s = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL);
           if (s && buf32_to_u32 (s))
-            tty_printf ("             [expires: %s]\n",
-                        isotimestamp (pk->timestamp + buf32_to_u32 (s)));
+            tty_fprintf (fp, "             [expires: %s]\n",
+                         isotimestamp (pk->timestamp + buf32_to_u32 (s)));
         }
     }
 
@@ -309,90 +313,17 @@ print_and_check_one_sig (KBNODE keyblock, KBNODE node,
 }
 
 
-
-/*
- * Check the keysigs and set the flags to indicate errors.
- * Returns true if error found.
- */
 static int
-check_all_keysigs (KBNODE keyblock, int only_selected, int only_selfsigs)
+print_and_check_one_sig (ctrl_t ctrl, kbnode_t keyblock, kbnode_t node,
+                        int *inv_sigs, int *no_key, int *oth_err,
+                        int *is_selfsig, int print_without_key, int extended)
 {
-  KBNODE kbctx;
-  KBNODE node;
-  int inv_sigs = 0;
-  int no_key = 0;
-  int oth_err = 0;
-  int has_selfsig = 0;
-  int mis_selfsig = 0;
-  int selected = !only_selected;
-  int anyuid = 0;
-  u32 keyid[2];
-
-  for (kbctx = NULL; (node = walk_kbnode (keyblock, &kbctx, 0));)
-    {
-      if (node->pkt->pkttype == PKT_PUBLIC_KEY)
-        {
-          if (only_selfsigs)
-            keyid_from_pk (node->pkt->pkt.public_key, keyid);
-        }
-      else if (node->pkt->pkttype == PKT_USER_ID)
-       {
-         PKT_user_id *uid = node->pkt->pkt.user_id;
+  int rc;
 
-         if (only_selected)
-           selected = (node->flag & NODFLG_SELUID);
-         if (selected)
-           {
-             tty_printf ("uid  ");
-             tty_print_utf8_string (uid->name, uid->len);
-             tty_printf ("\n");
-             if (anyuid && !has_selfsig)
-               mis_selfsig++;
-             has_selfsig = 0;
-             anyuid = 1;
-           }
-       }
-      else if (selected && node->pkt->pkttype == PKT_SIGNATURE
-              && ((node->pkt->pkt.signature->sig_class & ~3) == 0x10
-                  || node->pkt->pkt.signature->sig_class == 0x30))
-       {
-         int selfsig;
-          PKT_signature *sig = node->pkt->pkt.signature;
-
-          if (only_selfsigs
-              && !(keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1]))
-            ;  /* Not a selfsig but we want only selfsigs - skip.  */
-         else if (print_and_check_one_sig (keyblock, node, &inv_sigs,
-                                            &no_key, &oth_err, &selfsig,
-                                            0, only_selfsigs))
-           {
-             if (selfsig)
-               has_selfsig = 1;
-           }
-         /* Hmmm: should we update the trustdb here? */
-       }
-    }
-  if (!has_selfsig)
-    mis_selfsig++;
-  if (inv_sigs == 1)
-    tty_printf (_("1 bad signature\n"));
-  else if (inv_sigs)
-    tty_printf (_("%d bad signatures\n"), inv_sigs);
-  if (no_key == 1)
-    tty_printf (_("1 signature not checked due to a missing key\n"));
-  else if (no_key)
-    tty_printf (_("%d signatures not checked due to missing keys\n"), no_key);
-  if (oth_err == 1)
-    tty_printf (_("1 signature not checked due to an error\n"));
-  else if (oth_err)
-    tty_printf (_("%d signatures not checked due to errors\n"), oth_err);
-  if (mis_selfsig == 1)
-    tty_printf (_("1 user ID without valid self-signature detected\n"));
-  else if (mis_selfsig)
-    tty_printf (_("%d user IDs without valid self-signatures detected\n"),
-               mis_selfsig);
-
-  return inv_sigs || no_key || oth_err || mis_selfsig;
+  rc = check_key_signature (ctrl, keyblock, node, is_selfsig);
+  return keyedit_print_one_sig (ctrl, NULL, rc,
+                               keyblock, node, inv_sigs, no_key, oth_err,
+                               *is_selfsig, print_without_key, extended);
 }
 
 
@@ -473,7 +404,8 @@ trustsig_prompt (byte * trust_value, byte * trust_depth, char **regexp)
   tty_printf ("\n");
 
   tty_printf (_("Please enter the depth of this trust signature.\n"
-               "A depth greater than 1 allows the key you are signing to make\n"
+               "A depth greater than 1 allows the key you are"
+                " signing to make\n"
                "trust signatures on your behalf.\n"));
   tty_printf ("\n");
 
@@ -538,7 +470,7 @@ trustsig_prompt (byte * trust_value, byte * trust_depth, char **regexp)
 
 
 /*
- * Loop over all LOCUSR and and sign the uids after asking.  If no
+ * Loop over all LOCUSR and sign the uids after asking.  If no
  * user id is marked, all user ids will be signed; if some user_ids
  * are marked only those will be signed.  If QUICK is true the
  * function won't ask the user and use sensible defaults.
@@ -564,7 +496,7 @@ sign_uids (ctrl_t ctrl, estream_t fp,
    * why to sign keys using a subkey.  Implementation of USAGE_CERT
    * is just a hack in getkey.c and does not mean that a subkey
    * marked as certification capable will be used. */
-  rc = build_sk_list (locusr, &sk_list, PUBKEY_USAGE_CERT);
+  rc = build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_CERT);
   if (rc)
     goto leave;
 
@@ -613,7 +545,16 @@ sign_uids (ctrl_t ctrl, estream_t fp,
                   user = utf8_to_native (uidnode->pkt->pkt.user_id->name,
                                          uidnode->pkt->pkt.user_id->len, 0);
 
-                 if (uidnode->pkt->pkt.user_id->is_revoked)
+                  if (opt.only_sign_text_ids
+                      && uidnode->pkt->pkt.user_id->attribs)
+                    {
+                      tty_fprintf (fp, _("Skipping user ID \"%s\","
+                                         " which is not a text ID.\n"),
+                                   user);
+                      uidnode->flag &= ~NODFLG_MARK_A;
+                      uidnode = NULL;
+                    }
+                 else if (uidnode->pkt->pkt.user_id->flags.revoked)
                    {
                      tty_fprintf (fp, _("User ID \"%s\" is revoked."), user);
 
@@ -641,7 +582,7 @@ sign_uids (ctrl_t ctrl, estream_t fp,
                          tty_fprintf (fp, _("  Unable to sign.\n"));
                        }
                    }
-                 else if (uidnode->pkt->pkt.user_id->is_expired)
+                 else if (uidnode->pkt->pkt.user_id->flags.expired)
                    {
                      tty_fprintf (fp, _("User ID \"%s\" is expired."), user);
 
@@ -799,7 +740,7 @@ sign_uids (ctrl_t ctrl, estream_t fp,
                    }
 
                  /* Fixme: see whether there is a revocation in which
-                  * case we should allow to sign it again. */
+                  * case we should allow signing it again. */
                  if (!node->pkt->pkt.signature->flags.exportable && local)
                    tty_fprintf ( fp,
                        _("\"%s\" was already locally signed by key %s\n"),
@@ -845,6 +786,14 @@ sign_uids (ctrl_t ctrl, estream_t fp,
 
       if (primary_pk->expiredate && !selfsig)
        {
+          /* Static analyzer note: A claim that PRIMARY_PK might be
+             NULL is not correct because it set from the public key
+             packet which is always the first packet in a keyblock and
+             parsed in the above loop over the keyblock.  In case the
+             keyblock has no packets at all and thus the loop was not
+             entered the above count_uids_with_flag would have
+             detected this case.  */
+
          u32 now = make_timestamp ();
 
          if (primary_pk->expiredate <= now)
@@ -958,7 +907,7 @@ sign_uids (ctrl_t ctrl, estream_t fp,
 
       if (!quick)
         {
-          p = get_user_id_native (sk_keyid);
+          p = get_user_id_native (ctrl, sk_keyid);
           tty_fprintf (fp,
                    _("Are you sure that you want to sign this key with your\n"
                      "key \"%s\" (%s)\n"), p, keystr_from_pk (pk));
@@ -1030,7 +979,7 @@ sign_uids (ctrl_t ctrl, estream_t fp,
        continue;
 
       /* Now we can sign the user ids.  */
-    reloop:  /* (Must use this, because we are modifing the list.)  */
+    reloop:  /* (Must use this, because we are modifying the list.)  */
       primary_pk = NULL;
       for (node = keyblock; node; node = node->next)
        {
@@ -1043,7 +992,7 @@ sign_uids (ctrl_t ctrl, estream_t fp,
              PKT_signature *sig;
              struct sign_attrib attrib;
 
-             assert (primary_pk);
+             log_assert (primary_pk);
              memset (&attrib, 0, sizeof attrib);
              attrib.non_exportable = local;
              attrib.non_revocable = nonrevocable;
@@ -1058,7 +1007,7 @@ sign_uids (ctrl_t ctrl, estream_t fp,
               * exportable.  */
 
              if (selfsig)
-               rc = make_keysig_packet (&sig, primary_pk,
+               rc = make_keysig_packet (ctrl, &sig, primary_pk,
                                         node->pkt->pkt.user_id,
                                         NULL,
                                         pk,
@@ -1066,7 +1015,7 @@ sign_uids (ctrl_t ctrl, estream_t fp,
                                         keygen_add_std_prefs, primary_pk,
                                          NULL);
              else
-               rc = make_keysig_packet (&sig, primary_pk,
+               rc = make_keysig_packet (ctrl, &sig, primary_pk,
                                         node->pkt->pkt.user_id,
                                         NULL,
                                         pk,
@@ -1148,7 +1097,7 @@ change_passphrase (ctrl_t ctrl, kbnode_t keyblock)
           err = hexkeygrip_from_pk (pk, &hexgrip);
           if (err)
             goto leave;
-          err = agent_get_keyinfo (ctrl, hexgrip, &serialno);
+          err = agent_get_keyinfo (ctrl, hexgrip, &serialno, NULL);
           if (!err && serialno)
             ; /* Key on card.  */
           else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
@@ -1170,7 +1119,7 @@ change_passphrase (ctrl_t ctrl, kbnode_t keyblock)
     }
 
   /* Change the passphrase for all keys.  */
-  for (any = 0, node = keyblock; node; node = node->next)
+  for (node = keyblock; node; node = node->next)
     {
       if (node->pkt->pkttype == PKT_PUBLIC_KEY
          || node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
@@ -1185,14 +1134,17 @@ change_passphrase (ctrl_t ctrl, kbnode_t keyblock)
           if (err)
             goto leave;
 
-          desc = gpg_format_keydesc (pk, FORMAT_KEYDESC_NORMAL, 1);
-          err = agent_passwd (ctrl, hexgrip, desc, &cache_nonce, &passwd_nonce);
+          /* Note that when using --dry-run we don't change the
+           * passphrase but merely verify the current passphrase.  */
+          desc = gpg_format_keydesc (ctrl, pk, FORMAT_KEYDESC_NORMAL, 1);
+          err = agent_passwd (ctrl, hexgrip, desc, !!opt.dry_run,
+                              &cache_nonce, &passwd_nonce);
           xfree (desc);
 
           if (err)
             log_log ((gpg_err_code (err) == GPG_ERR_CANCELED
                       || gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
-                     ? GPGRT_LOG_INFO : GPGRT_LOG_ERROR,
+                     ? GPGRT_LOGLVL_INFO : GPGRT_LOGLVL_ERROR,
                      _("key %s: error changing passphrase: %s\n"),
                        keystr_with_sub (keyid, subid),
                        gpg_strerror (err));
@@ -1210,70 +1162,22 @@ change_passphrase (ctrl_t ctrl, kbnode_t keyblock)
 
 
 \f
-/*
- * There are some keys out (due to a bug in gnupg), where the sequence
- * of the packets is wrong.  This function fixes that.
- * Returns: true if the keyblock has been fixed.
- *
- * Note:  This function does not work if there is more than one user ID.
- */
-static int
-fix_key_signature_order (KBNODE keyblock)
-{
-  KBNODE node, last, subkey;
-  int fixed = 0;
-
-  /* Locate key signatures of class 0x10..0x13 behind sub key packets.  */
-  for (subkey = last = NULL, node = keyblock; node;
-       last = node, node = node->next)
-    {
-      switch (node->pkt->pkttype)
-       {
-       case PKT_PUBLIC_SUBKEY:
-       case PKT_SECRET_SUBKEY:
-         if (!subkey)
-           subkey = last; /* Actually it is the one before the subkey.  */
-         break;
-       case PKT_SIGNATURE:
-         if (subkey)
-           {
-             PKT_signature *sig = node->pkt->pkt.signature;
-             if (sig->sig_class >= 0x10 && sig->sig_class <= 0x13)
-               {
-                 log_info (_("moving a key signature to the correct place\n"));
-                 last->next = node->next;
-                 node->next = subkey->next;
-                 subkey->next = node;
-                 node = last;
-                 fixed = 1;
-               }
-           }
-         break;
-       default:
-         break;
-       }
-    }
-
-  return fixed;
-}
-
-
 /* Fix various problems in the keyblock.  Returns true if the keyblock
    was changed.  Note that a pointer to the keyblock must be given and
    the function may change it (i.e. replacing the first node).  */
 static int
-fix_keyblock (kbnode_t *keyblockp)
+fix_keyblock (ctrl_t ctrl, kbnode_t *keyblockp)
 {
   int changed = 0;
 
-  if (fix_key_signature_order (*keyblockp))
-    changed++;
   if (collapse_uids (keyblockp))
     changed++;
+  if (key_check_all_keysigs (ctrl, 1, *keyblockp, 0, 1))
+    changed++;
   reorder_keyblock (*keyblockp);
   /* If we modified the keyblock, make sure the flags are right. */
   if (changed)
-    merge_keys_and_selfsig (*keyblockp);
+    merge_keys_and_selfsig (ctrl, *keyblockp);
 
   return changed;
 }
@@ -1321,10 +1225,8 @@ parse_sign_type (const char *str, int *localsig, int *nonrevokesig,
 
 /* Need an SK for this command */
 #define KEYEDIT_NEED_SK 1
-/* Cannot be viewing the SK for this command */
-#define KEYEDIT_NOT_SK  2
-/* Must be viewing the SK for this command */
-#define KEYEDIT_ONLY_SK 4
+/* Need an SUB KEY for this command */
+#define KEYEDIT_NEED_SUBSK 2
 /* Match the tail of the string */
 #define KEYEDIT_TAIL_MATCH 8
 
@@ -1335,13 +1237,13 @@ enum cmdids
   cmdREVSIG, cmdREVKEY, cmdREVUID, cmdDELSIG, cmdPRIMARY, cmdDEBUG,
   cmdSAVE, cmdADDUID, cmdADDPHOTO, cmdDELUID, cmdADDKEY, cmdDELKEY,
   cmdADDREVOKER, cmdTOGGLE, cmdSELKEY, cmdPASSWD, cmdTRUST, cmdPREF,
-  cmdEXPIRE, cmdBACKSIGN,
+  cmdEXPIRE, cmdCHANGEUSAGE, cmdBACKSIGN,
 #ifndef NO_TRUST_MODELS
   cmdENABLEKEY, cmdDISABLEKEY,
 #endif /*!NO_TRUST_MODELS*/
   cmdSHOWPREF,
   cmdSETPREF, cmdPREFKS, cmdNOTATION, cmdINVCMD, cmdSHOWPHOTO, cmdUPDTRUST,
-  cmdCHKTRUST, cmdADDCARDKEY, cmdKEYTOCARD, cmdBKUPTOCARD, cmdCHECKBKUPKEY,
+  cmdCHKTRUST, cmdADDCARDKEY, cmdKEYTOCARD, cmdBKUPTOCARD,
   cmdCLEAN, cmdMINIMIZE, cmdGRIP, cmdNOP
 };
 
@@ -1366,11 +1268,12 @@ static struct
   { "key", cmdSELKEY, 0, N_("select subkey N")},
   { "check", cmdCHECK, 0, N_("check signatures")},
   { "c", cmdCHECK, 0, NULL},
-  { "cross-certify", cmdBACKSIGN, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, NULL},
-  { "backsign", cmdBACKSIGN, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, NULL},
-  { "sign", cmdSIGN, KEYEDIT_NOT_SK | KEYEDIT_TAIL_MATCH,
+  { "change-usage", cmdCHANGEUSAGE, KEYEDIT_NEED_SK, NULL},
+  { "cross-certify", cmdBACKSIGN, KEYEDIT_NEED_SK, NULL},
+  { "backsign", cmdBACKSIGN,  KEYEDIT_NEED_SK, NULL},
+  { "sign", cmdSIGN,  KEYEDIT_TAIL_MATCH,
     N_("sign selected user IDs [* see below for related commands]")},
-  { "s", cmdSIGN, KEYEDIT_NOT_SK, NULL},
+  { "s", cmdSIGN, 0, NULL},
     /* "lsign" and friends will never match since "sign" comes first
        and it is a tail match.  They are just here so they show up in
        the help menu. */
@@ -1379,63 +1282,62 @@ static struct
   { "nrsign", cmdNOP, 0,
     N_("sign selected user IDs with a non-revocable signature")},
   { "debug", cmdDEBUG, 0, NULL},
-  { "adduid", cmdADDUID, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, N_("add a user ID")},
-  { "addphoto", cmdADDPHOTO, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK,
+  { "adduid", cmdADDUID,  KEYEDIT_NEED_SK, N_("add a user ID")},
+  { "addphoto", cmdADDPHOTO,  KEYEDIT_NEED_SK,
     N_("add a photo ID")},
-  { "deluid", cmdDELUID, KEYEDIT_NOT_SK, N_("delete selected user IDs")},
+  { "deluid", cmdDELUID, 0, N_("delete selected user IDs")},
     /* delphoto is really deluid in disguise */
-  { "delphoto", cmdDELUID, KEYEDIT_NOT_SK, NULL},
-  { "addkey", cmdADDKEY, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, N_("add a subkey")},
+  { "delphoto", cmdDELUID, 0, NULL},
+  { "addkey", cmdADDKEY,  KEYEDIT_NEED_SK, N_("add a subkey")},
 #ifdef ENABLE_CARD_SUPPORT
-  { "addcardkey", cmdADDCARDKEY, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK,
+  { "addcardkey", cmdADDCARDKEY,  KEYEDIT_NEED_SK,
     N_("add a key to a smartcard")},
-  { "keytocard", cmdKEYTOCARD, KEYEDIT_NEED_SK | KEYEDIT_ONLY_SK,
+  { "keytocard", cmdKEYTOCARD, KEYEDIT_NEED_SK | KEYEDIT_NEED_SUBSK,
     N_("move a key to a smartcard")},
-  { "bkuptocard", cmdBKUPTOCARD, KEYEDIT_NEED_SK | KEYEDIT_ONLY_SK,
+  { "bkuptocard", cmdBKUPTOCARD, KEYEDIT_NEED_SK | KEYEDIT_NEED_SUBSK,
     N_("move a backup key to a smartcard")},
-  { "checkbkupkey", cmdCHECKBKUPKEY, KEYEDIT_NEED_SK | KEYEDIT_ONLY_SK, NULL},
 #endif /*ENABLE_CARD_SUPPORT */
-  { "delkey", cmdDELKEY, KEYEDIT_NOT_SK, N_("delete selected subkeys")},
-  { "addrevoker", cmdADDREVOKER, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK,
+  { "delkey", cmdDELKEY, 0, N_("delete selected subkeys")},
+  { "addrevoker", cmdADDREVOKER,  KEYEDIT_NEED_SK,
     N_("add a revocation key")},
-  { "delsig", cmdDELSIG, KEYEDIT_NOT_SK,
+  { "delsig", cmdDELSIG, 0,
     N_("delete signatures from the selected user IDs")},
-  { "expire", cmdEXPIRE, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK,
+  { "expire", cmdEXPIRE,  KEYEDIT_NEED_SK | KEYEDIT_NEED_SUBSK,
     N_("change the expiration date for the key or selected subkeys")},
-  { "primary", cmdPRIMARY, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK,
+  { "primary", cmdPRIMARY,  KEYEDIT_NEED_SK,
     N_("flag the selected user ID as primary")},
   { "toggle", cmdTOGGLE, KEYEDIT_NEED_SK, NULL},  /* Dummy command.  */
   { "t", cmdTOGGLE, KEYEDIT_NEED_SK, NULL},
-  { "pref", cmdPREF, KEYEDIT_NOT_SK, N_("list preferences (expert)")},
-  { "showpref", cmdSHOWPREF, KEYEDIT_NOT_SK, N_("list preferences (verbose)")},
-  { "setpref", cmdSETPREF, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK,
+  { "pref", cmdPREF, 0, N_("list preferences (expert)")},
+  { "showpref", cmdSHOWPREF, 0, N_("list preferences (verbose)")},
+  { "setpref", cmdSETPREF,  KEYEDIT_NEED_SK,
     N_("set preference list for the selected user IDs")},
-  { "updpref", cmdSETPREF, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, NULL},
-  { "keyserver", cmdPREFKS, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK,
+  { "updpref", cmdSETPREF,  KEYEDIT_NEED_SK, NULL},
+  { "keyserver", cmdPREFKS,  KEYEDIT_NEED_SK,
     N_("set the preferred keyserver URL for the selected user IDs")},
-  { "notation", cmdNOTATION, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK,
+  { "notation", cmdNOTATION,  KEYEDIT_NEED_SK,
     N_("set a notation for the selected user IDs")},
-  { "passwd", cmdPASSWD, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK,
+  { "passwd", cmdPASSWD,  KEYEDIT_NEED_SK | KEYEDIT_NEED_SUBSK,
     N_("change the passphrase")},
-  { "password", cmdPASSWD, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, NULL},
+  { "password", cmdPASSWD,  KEYEDIT_NEED_SK | KEYEDIT_NEED_SUBSK, NULL},
 #ifndef NO_TRUST_MODELS
-  { "trust", cmdTRUST, KEYEDIT_NOT_SK, N_("change the ownertrust")},
+  { "trust", cmdTRUST, 0, N_("change the ownertrust")},
 #endif /*!NO_TRUST_MODELS*/
-  { "revsig", cmdREVSIG, KEYEDIT_NOT_SK,
+  { "revsig", cmdREVSIG, 0,
     N_("revoke signatures on the selected user IDs")},
-  { "revuid", cmdREVUID, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK,
+  { "revuid", cmdREVUID,  KEYEDIT_NEED_SK,
     N_("revoke selected user IDs")},
-  { "revphoto", cmdREVUID, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, NULL},
-  { "revkey", cmdREVKEY, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK,
+  { "revphoto", cmdREVUID,  KEYEDIT_NEED_SK, NULL},
+  { "revkey", cmdREVKEY,  KEYEDIT_NEED_SK,
     N_("revoke key or selected subkeys")},
 #ifndef NO_TRUST_MODELS
-  { "enable", cmdENABLEKEY, KEYEDIT_NOT_SK, N_("enable key")},
-  { "disable", cmdDISABLEKEY, KEYEDIT_NOT_SK, N_("disable key")},
+  { "enable", cmdENABLEKEY, 0, N_("enable key")},
+  { "disable", cmdDISABLEKEY, 0, N_("disable key")},
 #endif /*!NO_TRUST_MODELS*/
   { "showphoto", cmdSHOWPHOTO, 0, N_("show selected photo IDs")},
-  { "clean", cmdCLEAN, KEYEDIT_NOT_SK,
+  { "clean", cmdCLEAN, 0,
     N_("compact unusable user IDs and remove unusable signatures from key")},
-  { "minimize", cmdMINIMIZE, KEYEDIT_NOT_SK,
+  { "minimize", cmdMINIMIZE, 0,
     N_("compact unusable user IDs and remove all signatures from key")},
 
   { NULL, cmdNONE, 0, NULL}
@@ -1504,6 +1406,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
   KBNODE keyblock = NULL;
   KEYDB_HANDLE kdbhd = NULL;
   int have_seckey = 0;
+  int have_anyseckey = 0;
   char *answer = NULL;
   int redisplay = 1;
   int modified = 0;
@@ -1529,7 +1432,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
      and run the stale check as early as possible.  Note, that for
      non- W32 platforms it is run indirectly trough a call to
      get_validity ().  */
-  check_trustdb_stale ();
+  check_trustdb_stale (ctrl);
 #endif
 
   /* Get the public key */
@@ -1540,15 +1443,24 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
       goto leave;
     }
 
-  if (fix_keyblock (&keyblock))
+  if (fix_keyblock (ctrl, &keyblock))
     modified++;
 
   /* See whether we have a matching secret key.  */
   if (seckey_check)
     {
-      have_seckey = !agent_probe_any_secret_key (ctrl, keyblock);
+      have_anyseckey = !agent_probe_any_secret_key (ctrl, keyblock);
+      if (have_anyseckey
+          && !agent_probe_secret_key (ctrl, keyblock->pkt->pkt.public_key))
+        {
+          /* The primary key is also available.   */
+          have_seckey = 1;
+        }
+
       if (have_seckey && !quiet)
-       tty_printf (_("Secret key is available.\n"));
+        tty_printf (_("Secret key is available.\n"));
+      else if (have_anyseckey && !quiet)
+        tty_printf (_("Secret subkeys are available.\n"));
     }
 
   /* Main command loop.  */
@@ -1646,12 +1558,14 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
              else if (!ascii_strcasecmp (answer, cmds[i].name))
                break;
            }
-         if ((cmds[i].flags & KEYEDIT_NEED_SK) && !have_seckey)
+         if ((cmds[i].flags & (KEYEDIT_NEED_SK|KEYEDIT_NEED_SUBSK))
+              && !(((cmds[i].flags & KEYEDIT_NEED_SK) && have_seckey)
+                   || ((cmds[i].flags & KEYEDIT_NEED_SUBSK) && have_anyseckey)))
            {
              tty_printf (_("Need the secret key to do this.\n"));
              cmd = cmdNOP;
            }
-         else
+          else
            cmd = cmds[i].id;
        }
 
@@ -1661,7 +1575,9 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
        case cmdHELP:
          for (i = 0; cmds[i].name; i++)
            {
-             if ((cmds[i].flags & KEYEDIT_NEED_SK) && !have_seckey)
+              if ((cmds[i].flags & (KEYEDIT_NEED_SK|KEYEDIT_NEED_SUBSK))
+                  && !(((cmds[i].flags & KEYEDIT_NEED_SK) && have_seckey)
+                       ||((cmds[i].flags&KEYEDIT_NEED_SUBSK)&&have_anyseckey)))
                ; /* Skip those item if we do not have the secret key.  */
              else if (cmds[i].desc)
                tty_printf ("%-11s %s\n", cmds[i].name, _(cmds[i].desc));
@@ -1683,7 +1599,8 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
 
        case cmdFPR:
          show_key_and_fingerprint
-            (keyblock, (*arg_string == '*'
+            (ctrl,
+             keyblock, (*arg_string == '*'
                         && (!arg_string[1] || spacep (arg_string + 1))));
          break;
 
@@ -1708,14 +1625,16 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
            if (*arg_string == '*'
                && (!arg_string[1] || spacep (arg_string + 1)))
              arg_number = -1;  /* Select all. */
-           if (menu_select_key (keyblock, arg_number))
+           if (menu_select_key (keyblock, arg_number, p))
              redisplay = 1;
          }
          break;
 
        case cmdCHECK:
-         check_all_keysigs (keyblock, count_selected_uids (keyblock),
-                             !strcmp (arg_string, "selfsig"));
+         if (key_check_all_keysigs (ctrl, -1, keyblock,
+                                    count_selected_uids (keyblock),
+                                    !strcmp (arg_string, "selfsig")))
+            modified = 1;
          break;
 
        case cmdSIGN:
@@ -1741,21 +1660,31 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
                  }
              }
 
-           if (count_uids (keyblock) > 1 && !count_selected_uids (keyblock)
-               && !cpr_get_answer_is_yes ("keyedit.sign_all.okay",
-                                          _("Really sign all user IDs?"
-                                            " (y/N) ")))
-             {
-               if (opt.interactive)
-                 interactive = 1;
-               else
-                 {
-                   tty_printf (_("Hint: Select the user IDs to sign\n"));
-                   have_commands = 0;
-                   break;
-                 }
-
-             }
+           if (count_uids (keyblock) > 1 && !count_selected_uids (keyblock))
+              {
+                int result;
+                if (opt.only_sign_text_ids)
+                  result = cpr_get_answer_is_yes
+                    ("keyedit.sign_all.okay",
+                     _("Really sign all text user IDs? (y/N) "));
+                else
+                  result = cpr_get_answer_is_yes
+                    ("keyedit.sign_all.okay",
+                     _("Really sign all user IDs? (y/N) "));
+
+                if (! result)
+                  {
+                    if (opt.interactive)
+                      interactive = 1;
+                    else
+                      {
+                        tty_printf (_("Hint: Select the user IDs to sign\n"));
+                        have_commands = 0;
+                        break;
+                      }
+
+                  }
+              }
            /* What sort of signing are we doing? */
            if (!parse_sign_type
                (answer, &localsig, &nonrevokesig, &trustsig))
@@ -1785,18 +1714,18 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
          if (RFC2440)
            {
              tty_printf (_("This command is not allowed while in %s mode.\n"),
-                         compliance_option_string ());
+                         gnupg_compliance_option_string (opt.compliance));
              break;
            }
          photo = 1;
          /* fall through */
        case cmdADDUID:
-         if (menu_adduid (keyblock, photo, arg_string, NULL))
+         if (menu_adduid (ctrl, keyblock, photo, arg_string, NULL))
            {
              update_trust = 1;
              redisplay = 1;
              modified = 1;
-             merge_keys_and_selfsig (keyblock);
+             merge_keys_and_selfsig (ctrl, keyblock);
            }
          break;
 
@@ -1834,7 +1763,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
                 if (!opt.expert)
                   tty_printf (_("(Use the '%s' command.)\n"), "uid");
               }
-           else if (menu_delsig (keyblock))
+           else if (menu_delsig (ctrl, keyblock))
              {
                /* No redisplay here, because it may scroll away some
                 * of the status output of this command.  */
@@ -1844,21 +1773,21 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
          break;
 
        case cmdADDKEY:
-         if (!generate_subkeypair (ctrl, keyblock))
+         if (!generate_subkeypair (ctrl, keyblock, NULL, NULL, NULL))
            {
              redisplay = 1;
              modified = 1;
-             merge_keys_and_selfsig (keyblock);
+             merge_keys_and_selfsig (ctrl, keyblock);
            }
          break;
 
 #ifdef ENABLE_CARD_SUPPORT
        case cmdADDCARDKEY:
-         if (!card_generate_subkey (keyblock))
+         if (!card_generate_subkey (ctrl, keyblock))
            {
              redisplay = 1;
              modified = 1;
-             merge_keys_and_selfsig (keyblock);
+             merge_keys_and_selfsig (ctrl, keyblock);
            }
          break;
 
@@ -1900,24 +1829,29 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
          break;
 
        case cmdBKUPTOCARD:
-       case cmdCHECKBKUPKEY:
-          log_debug ("FIXME: This needs to be changed\n");
          {
            /* Ask for a filename, check whether this is really a
               backup key as generated by the card generation, parse
               that key and store it on card. */
            KBNODE node;
-           const char *fname;
+           char *fname;
            PACKET *pkt;
            IOBUF a;
+            struct parse_packet_ctx_s parsectx;
 
-           fname = arg_string;
-           if (!*fname)
+            if (!*arg_string)
              {
                tty_printf (_("Command expects a filename argument\n"));
                break;
              }
 
+            if (*arg_string == DIRSEP_C)
+              fname = xstrdup (arg_string);
+            else if (*arg_string == '~')
+              fname = make_filename (arg_string, NULL);
+            else
+              fname = make_filename (gnupg_homedir (), arg_string, NULL);
+
            /* Open that file.  */
            a = iobuf_open (fname);
            if (a && is_secured_file (iobuf_get_fd (a)))
@@ -1926,65 +1860,53 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
                a = NULL;
                gpg_err_set_errno (EPERM);
              }
-           if (!a)
-             {
-               tty_printf (_("Can't open '%s': %s\n"),
-                           fname, strerror (errno));
-               break;
-             }
+            if (!a)
+              {
+                tty_printf (_("Can't open '%s': %s\n"),
+                            fname, strerror (errno));
+                xfree (fname);
+                break;
+              }
 
            /* Parse and check that file.  */
            pkt = xmalloc (sizeof *pkt);
            init_packet (pkt);
-           err = parse_packet (a, pkt);
-           iobuf_close (a);
+            init_parse_packet (&parsectx, a);
+           err = parse_packet (&parsectx, pkt);
+           deinit_parse_packet (&parsectx);
+            iobuf_close (a);
            iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char *) fname);
            if (!err && pkt->pkttype != PKT_SECRET_KEY
                && pkt->pkttype != PKT_SECRET_SUBKEY)
              err = GPG_ERR_NO_SECKEY;
-           if (err)
-             {
-               tty_printf (_("Error reading backup key from '%s': %s\n"),
-                           fname, gpg_strerror (err));
-               free_packet (pkt);
-               xfree (pkt);
-               break;
-             }
+            if (err)
+              {
+                tty_printf (_("Error reading backup key from '%s': %s\n"),
+                            fname, gpg_strerror (err));
+                xfree (fname);
+                free_packet (pkt, NULL);
+                xfree (pkt);
+                break;
+              }
+
+           xfree (fname);
            node = new_kbnode (pkt);
 
-           if (cmd == cmdCHECKBKUPKEY)
-             {
-               /* PKT_public_key *sk = node->pkt->pkt.secret_key; */
-               /* switch (is_secret_key_protected (sk)) */
-               /*   { */
-               /*   case 0:    /\* Not protected. *\/ */
-               /*     tty_printf (_("This key is not protected.\n")); */
-               /*     break; */
-               /*   case -1: */
-               /*     log_error (_("unknown key protection algorithm\n")); */
-               /*     break; */
-               /*   default: */
-               /*     if (sk->protect.s2k.mode == 1001) */
-               /*       tty_printf (_("Secret parts of key" */
-               /*                  " are not available.\n")); */
-               /*     if (sk->protect.s2k.mode == 1002) */
-               /*       tty_printf (_("Secret parts of key" */
-               /*                  " are stored on-card.\n")); */
-                   /* else */
-                   /*   check_secret_key (sk, 0); */
-                 /* } */
-             }
-           else                /* Store it.  */
-             {
-               if (card_store_subkey (node, 0))
-                 {
-                   redisplay = 1;
-                   sec_shadowing = 1;
-                 }
-             }
-           release_kbnode (node);
-         }
-         break;
+            /* Transfer it to gpg-agent which handles secret keys.  */
+            err = transfer_secret_keys (ctrl, NULL, node, 1, 1);
+
+            /* Treat the pkt as a public key.  */
+            pkt->pkttype = PKT_PUBLIC_KEY;
+
+            /* Ask gpg-agent to store the secret key to card.  */
+            if (card_store_subkey (node, 0))
+              {
+                redisplay = 1;
+                sec_shadowing = 1;
+              }
+            release_kbnode (node);
+          }
+          break;
 
 #endif /* ENABLE_CARD_SUPPORT */
 
@@ -2023,7 +1945,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
              {
                redisplay = 1;
                modified = 1;
-               merge_keys_and_selfsig (keyblock);
+               merge_keys_and_selfsig (ctrl, keyblock);
              }
          }
          break;
@@ -2043,7 +1965,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
                       n1 > 1 ? _("Really revoke all selected user IDs? (y/N) ")
                      :        _("Really revoke this user ID? (y/N) ")))
              {
-               if (menu_revuid (keyblock))
+               if (menu_revuid (ctrl, keyblock))
                  {
                    modified = 1;
                    redisplay = 1;
@@ -2062,7 +1984,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
                                           _("Do you really want to revoke"
                                             " the entire key? (y/N) ")))
                  {
-                   if (menu_revkey (keyblock))
+                   if (menu_revkey (ctrl, keyblock))
                      modified = 1;
 
                    redisplay = 1;
@@ -2075,29 +1997,38 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
                                            : _("Do you really want to revoke"
                                                " this subkey? (y/N) ")))
              {
-               if (menu_revsubkey (keyblock))
+               if (menu_revsubkey (ctrl, keyblock))
                  modified = 1;
 
                redisplay = 1;
              }
 
            if (modified)
-             merge_keys_and_selfsig (keyblock);
+             merge_keys_and_selfsig (ctrl, keyblock);
          }
          break;
 
        case cmdEXPIRE:
-         if (menu_expire (keyblock))
+         if (gpg_err_code (menu_expire (ctrl, keyblock, 0, 0)) == GPG_ERR_TRUE)
            {
-             merge_keys_and_selfsig (keyblock);
+             merge_keys_and_selfsig (ctrl, keyblock);
               run_subkey_warnings = 1;
              modified = 1;
              redisplay = 1;
            }
          break;
 
+       case cmdCHANGEUSAGE:
+         if (menu_changeusage (ctrl, keyblock))
+           {
+             merge_keys_and_selfsig (ctrl, keyblock);
+             modified = 1;
+             redisplay = 1;
+           }
+         break;
+
        case cmdBACKSIGN:
-         if (menu_backsign (keyblock))
+         if (menu_backsign (ctrl, keyblock))
            {
              modified = 1;
              redisplay = 1;
@@ -2105,9 +2036,9 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
          break;
 
        case cmdPRIMARY:
-         if (menu_set_primary_uid (keyblock))
+         if (menu_set_primary_uid (ctrl, keyblock))
            {
-             merge_keys_and_selfsig (keyblock);
+             merge_keys_and_selfsig (ctrl, keyblock);
              modified = 1;
              redisplay = 1;
            }
@@ -2128,7 +2059,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
 
          show_key_with_all_names (ctrl, NULL, keyblock, 0, 0, 0, 1, 0, 0);
          tty_printf ("\n");
-         if (edit_ownertrust (find_kbnode (keyblock,
+         if (edit_ownertrust (ctrl, find_kbnode (keyblock,
                                            PKT_PUBLIC_KEY)->pkt->pkt.
                               public_key, 1))
            {
@@ -2144,8 +2075,8 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
        case cmdPREF:
          {
            int count = count_selected_uids (keyblock);
-           assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
-           show_names (NULL, keyblock, keyblock->pkt->pkt.public_key,
+           log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
+           show_names (ctrl, NULL, keyblock, keyblock->pkt->pkt.public_key,
                        count ? NODFLG_SELUID : 0, 1);
          }
          break;
@@ -2153,8 +2084,8 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
        case cmdSHOWPREF:
          {
            int count = count_selected_uids (keyblock);
-           assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
-           show_names (NULL, keyblock, keyblock->pkt->pkt.public_key,
+           log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
+           show_names (ctrl, NULL, keyblock, keyblock->pkt->pkt.public_key,
                        count ? NODFLG_SELUID : 0, 2);
          }
          break;
@@ -2177,9 +2108,9 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
                    " for the selected user IDs? (y/N) ")
                  : _("Really update the preferences? (y/N) ")))
              {
-               if (menu_set_preferences (keyblock))
+               if (menu_set_preferences (ctrl, keyblock))
                  {
-                   merge_keys_and_selfsig (keyblock);
+                   merge_keys_and_selfsig (ctrl, keyblock);
                    modified = 1;
                    redisplay = 1;
                  }
@@ -2188,20 +2119,20 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
          break;
 
        case cmdPREFKS:
-         if (menu_set_keyserver_url (*arg_string ? arg_string : NULL,
+         if (menu_set_keyserver_url (ctrl, *arg_string ? arg_string : NULL,
                                      keyblock))
            {
-             merge_keys_and_selfsig (keyblock);
+             merge_keys_and_selfsig (ctrl, keyblock);
              modified = 1;
              redisplay = 1;
            }
          break;
 
        case cmdNOTATION:
-         if (menu_set_notation (*arg_string ? arg_string : NULL,
+         if (menu_set_notation (ctrl, *arg_string ? arg_string : NULL,
                                 keyblock))
            {
-             merge_keys_and_selfsig (keyblock);
+             merge_keys_and_selfsig (ctrl, keyblock);
              modified = 1;
              redisplay = 1;
            }
@@ -2211,7 +2142,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
          break;
 
        case cmdREVSIG:
-         if (menu_revsig (keyblock))
+         if (menu_revsig (ctrl, keyblock))
            {
              redisplay = 1;
              modified = 1;
@@ -2221,7 +2152,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
 #ifndef NO_TRUST_MODELS
        case cmdENABLEKEY:
        case cmdDISABLEKEY:
-         if (enable_disable_key (keyblock, cmd == cmdDISABLEKEY))
+         if (enable_disable_key (ctrl, keyblock, cmd == cmdDISABLEKEY))
            {
              redisplay = 1;
              modified = 1;
@@ -2230,16 +2161,16 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
 #endif /*!NO_TRUST_MODELS*/
 
        case cmdSHOWPHOTO:
-         menu_showphoto (keyblock);
+         menu_showphoto (ctrl, keyblock);
          break;
 
        case cmdCLEAN:
-         if (menu_clean (keyblock, 0))
+         if (menu_clean (ctrl, keyblock, 0))
            redisplay = modified = 1;
          break;
 
        case cmdMINIMIZE:
-         if (menu_clean (keyblock, 1))
+         if (menu_clean (ctrl, keyblock, 1))
            redisplay = modified = 1;
          break;
 
@@ -2257,11 +2188,11 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
                goto leave;
              break;
            }
-         /* fall thru */
+         /* fall through */
        case cmdSAVE:
          if (modified)
            {
-              err = keydb_update_keyblock (kdbhd, keyblock);
+              err = keydb_update_keyblock (ctrl, kdbhd, keyblock);
               if (err)
                 {
                   log_error (_("update failed: %s\n"), gpg_strerror (err));
@@ -2284,7 +2215,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
 
          if (update_trust)
            {
-             revalidation_mark ();
+             revalidation_mark (ctrl);
              update_trust = 0;
            }
          goto leave;
@@ -2318,7 +2249,7 @@ keyedit_passwd (ctrl_t ctrl, const char *username)
       err = gpg_error_from_syserror ();
       goto leave;
     }
-  err = getkey_byname (NULL, pk, username, 1, &keyblock);
+  err = getkey_byname (ctrl, NULL, pk, username, 1, &keyblock);
   if (err)
     goto leave;
 
@@ -2338,33 +2269,31 @@ leave:
 }
 
 
-/* Unattended adding of a new keyid.  USERNAME specifies the
-   key. NEWUID is the new user id to add to the key.  */
-void
-keyedit_quick_adduid (ctrl_t ctrl, const char *username, const char *newuid)
+/* Helper for quick commands to find the keyblock for USERNAME.
+ * Returns on success the key database handle at R_KDBHD and the
+ * keyblock at R_KEYBLOCK.  */
+static gpg_error_t
+quick_find_keyblock (ctrl_t ctrl, const char *username,
+                     KEYDB_HANDLE *r_kdbhd, kbnode_t *r_keyblock)
 {
   gpg_error_t err;
   KEYDB_HANDLE kdbhd = NULL;
-  KEYDB_SEARCH_DESC desc;
   kbnode_t keyblock = NULL;
+  KEYDB_SEARCH_DESC desc;
   kbnode_t node;
-  char *uidstring = NULL;
 
-  uidstring = xstrdup (newuid);
-  trim_spaces (uidstring);
-  if (!*uidstring)
+  *r_kdbhd = NULL;
+  *r_keyblock = NULL;
+
+  /* Search the key; we don't want the whole getkey stuff here.  */
+  kdbhd = keydb_new ();
+  if (!kdbhd)
     {
-      log_error ("%s\n", gpg_strerror (GPG_ERR_INV_USER_ID));
+      /* Note that keydb_new has already used log_error.  */
+      err = gpg_error_from_syserror ();
       goto leave;
     }
 
-#ifdef HAVE_W32_SYSTEM
-  /* See keyedit_menu for why we need this.  */
-  check_trustdb_stale ();
-#endif
-
-  /* Search the key; we don't want the whole getkey stuff here.  */
-  kdbhd = keydb_new ();
   err = classify_user_id (username, &desc, 1);
   if (!err)
     err = keydb_search (kdbhd, &desc, 1, NULL);
@@ -2389,25 +2318,68 @@ keyedit_quick_adduid (ctrl_t ctrl, const char *username, const char *newuid)
 
       if (!err)
         {
-          /* We require the secret primary key to add a UID.  */
+          /* We require the secret primary key to set the primary UID.  */
           node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
-          if (!node)
-            BUG ();
+          log_assert (node);
           err = agent_probe_secret_key (ctrl, node->pkt->pkt.public_key);
         }
     }
+  else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
+    err = gpg_error (GPG_ERR_NO_PUBKEY);
+
   if (err)
     {
-      log_error (_("secret key \"%s\" not found: %s\n"),
+      log_error (_("key \"%s\" not found: %s\n"),
                  username, gpg_strerror (err));
       goto leave;
     }
 
-  fix_keyblock (&keyblock);
+  fix_keyblock (ctrl, &keyblock);
+  merge_keys_and_selfsig (ctrl, keyblock);
+
+  *r_keyblock = keyblock;
+  keyblock = NULL;
+  *r_kdbhd = kdbhd;
+  kdbhd = NULL;
 
-  if (menu_adduid (keyblock, 0, NULL, uidstring))
+ leave:
+  release_kbnode (keyblock);
+  keydb_release (kdbhd);
+  return err;
+}
+
+
+/* Unattended adding of a new keyid.  USERNAME specifies the
+   key. NEWUID is the new user id to add to the key.  */
+void
+keyedit_quick_adduid (ctrl_t ctrl, const char *username, const char *newuid)
+{
+  gpg_error_t err;
+  KEYDB_HANDLE kdbhd = NULL;
+  kbnode_t keyblock = NULL;
+  char *uidstring = NULL;
+
+  uidstring = xstrdup (newuid);
+  trim_spaces (uidstring);
+  if (!*uidstring)
     {
-      err = keydb_update_keyblock (kdbhd, keyblock);
+      log_error ("%s\n", gpg_strerror (GPG_ERR_INV_USER_ID));
+      goto leave;
+    }
+
+#ifdef HAVE_W32_SYSTEM
+  /* See keyedit_menu for why we need this.  */
+  check_trustdb_stale (ctrl);
+#endif
+
+  /* Search the key; we don't want the whole getkey stuff here.  */
+  err = quick_find_keyblock (ctrl, username, &kdbhd, &keyblock);
+  if (err)
+    goto leave;
+
+  if (menu_adduid (ctrl, keyblock, 0, NULL, uidstring))
+    {
+      err = keydb_update_keyblock (ctrl, kdbhd, keyblock);
       if (err)
         {
           log_error (_("update failed: %s\n"), gpg_strerror (err));
@@ -2415,7 +2387,7 @@ keyedit_quick_adduid (ctrl_t ctrl, const char *username, const char *newuid)
         }
 
       if (update_trust)
-        revalidation_mark ();
+        revalidation_mark (ctrl);
     }
 
  leave:
@@ -2425,41 +2397,178 @@ keyedit_quick_adduid (ctrl_t ctrl, const char *username, const char *newuid)
 }
 
 
-/* Unattended key signing function.  If the key specifified by FPR is
-   availabale and FPR is the primary fingerprint all user ids of the
-   user ids of the key are signed using the default signing key.  If
-   UIDS is an empty list all usable UIDs are signed, if it is not
-   empty, only those user ids matching one of the entries of the loist
-   are signed.  With LOCAL being true kthe signatures are marked as
-   non-exportable.  */
+/* Unattended revocation of a keyid.  USERNAME specifies the
+   key. UIDTOREV is the user id revoke from the key.  */
 void
-keyedit_quick_sign (ctrl_t ctrl, const char *fpr, strlist_t uids,
-                    strlist_t locusr, int local)
+keyedit_quick_revuid (ctrl_t ctrl, const char *username, const char *uidtorev)
 {
   gpg_error_t err;
-  kbnode_t keyblock = NULL;
   KEYDB_HANDLE kdbhd = NULL;
+  kbnode_t keyblock = NULL;
+  kbnode_t node;
   int modified = 0;
-  KEYDB_SEARCH_DESC desc;
-  PKT_public_key *pk;
+  size_t revlen;
+  size_t valid_uids;
+
+#ifdef HAVE_W32_SYSTEM
+  /* See keyedit_menu for why we need this.  */
+  check_trustdb_stale (ctrl);
+#endif
+
+  /* Search the key; we don't want the whole getkey stuff here.  */
+  err = quick_find_keyblock (ctrl, username, &kdbhd, &keyblock);
+  if (err)
+    goto leave;
+
+  /* Too make sure that we do not revoke the last valid UID, we first
+     count how many valid UIDs there are.  */
+  valid_uids = 0;
+  for (node = keyblock; node; node = node->next)
+    valid_uids += (node->pkt->pkttype == PKT_USER_ID
+                   && !node->pkt->pkt.user_id->flags.revoked
+                   && !node->pkt->pkt.user_id->flags.expired);
+
+  /* Find the right UID. */
+  revlen = strlen (uidtorev);
+  for (node = keyblock; node; node = node->next)
+    {
+      if (node->pkt->pkttype == PKT_USER_ID
+          && revlen == node->pkt->pkt.user_id->len
+          && !memcmp (node->pkt->pkt.user_id->name, uidtorev, revlen))
+        {
+          struct revocation_reason_info *reason;
+
+          /* Make sure that we do not revoke the last valid UID.  */
+          if (valid_uids == 1
+              && ! node->pkt->pkt.user_id->flags.revoked
+              && ! node->pkt->pkt.user_id->flags.expired)
+            {
+              log_error (_("cannot revoke the last valid user ID.\n"));
+              err = gpg_error (GPG_ERR_INV_USER_ID);
+              goto leave;
+            }
+
+          reason = get_default_uid_revocation_reason ();
+          err = core_revuid (ctrl, keyblock, node, reason, &modified);
+          release_revocation_reason_info (reason);
+          if (err)
+            goto leave;
+          err = keydb_update_keyblock (ctrl, kdbhd, keyblock);
+          if (err)
+            {
+              log_error (_("update failed: %s\n"), gpg_strerror (err));
+              goto leave;
+            }
+
+          revalidation_mark (ctrl);
+          goto leave;
+        }
+    }
+  err = gpg_error (GPG_ERR_NO_USER_ID);
+
+
+ leave:
+  if (err)
+    {
+      log_error (_("revoking the user ID failed: %s\n"), gpg_strerror (err));
+      write_status_error ("keyedit.revoke.uid", err);
+    }
+  release_kbnode (keyblock);
+  keydb_release (kdbhd);
+}
+
+
+/* Unattended setting of the primary uid.  USERNAME specifies the key.
+   PRIMARYUID is the user id which shall be primary.  */
+void
+keyedit_quick_set_primary (ctrl_t ctrl, const char *username,
+                           const char *primaryuid)
+{
+  gpg_error_t err;
+  KEYDB_HANDLE kdbhd = NULL;
+  kbnode_t keyblock = NULL;
   kbnode_t node;
-  strlist_t sl;
+  size_t primaryuidlen;
   int any;
 
 #ifdef HAVE_W32_SYSTEM
   /* See keyedit_menu for why we need this.  */
-  check_trustdb_stale ();
+  check_trustdb_stale (ctrl);
 #endif
 
-  /* We require a fingerprint because only this uniquely identifies a
-     key and may thus be used to select a key for unattended key
-     signing.  */
+  err = quick_find_keyblock (ctrl, username, &kdbhd, &keyblock);
+  if (err)
+    goto leave;
+
+  /* Find and mark the UID - we mark only the first valid one. */
+  primaryuidlen = strlen (primaryuid);
+  any = 0;
+  for (node = keyblock; node; node = node->next)
+    {
+      if (node->pkt->pkttype == PKT_USER_ID
+          && !any
+          && !node->pkt->pkt.user_id->flags.revoked
+          && !node->pkt->pkt.user_id->flags.expired
+          && primaryuidlen == node->pkt->pkt.user_id->len
+          && !memcmp (node->pkt->pkt.user_id->name, primaryuid, primaryuidlen))
+        {
+          node->flag |= NODFLG_SELUID;
+          any = 1;
+        }
+      else
+        node->flag &= ~NODFLG_SELUID;
+    }
+
+  if (!any)
+    err = gpg_error (GPG_ERR_NO_USER_ID);
+  else if (menu_set_primary_uid (ctrl, keyblock))
+    {
+      merge_keys_and_selfsig (ctrl, keyblock);
+      err = keydb_update_keyblock (ctrl, kdbhd, keyblock);
+      if (err)
+        {
+          log_error (_("update failed: %s\n"), gpg_strerror (err));
+          goto leave;
+        }
+      revalidation_mark (ctrl);
+    }
+  else
+    err = gpg_error (GPG_ERR_GENERAL);
+
+  if (err)
+    log_error (_("setting the primary user ID failed: %s\n"),
+               gpg_strerror (err));
+
+ leave:
+  release_kbnode (keyblock);
+  keydb_release (kdbhd);
+}
+
+
+/* Find a keyblock by fingerprint because only this uniquely
+ * identifies a key and may thus be used to select a key for
+ * unattended subkey creation os key signing.  */
+static gpg_error_t
+find_by_primary_fpr (ctrl_t ctrl, const char *fpr,
+                     kbnode_t *r_keyblock, KEYDB_HANDLE *r_kdbhd)
+{
+  gpg_error_t err;
+  kbnode_t keyblock = NULL;
+  KEYDB_HANDLE kdbhd = NULL;
+  KEYDB_SEARCH_DESC desc;
+  byte fprbin[MAX_FINGERPRINT_LEN];
+  size_t fprlen;
+
+  *r_keyblock = NULL;
+  *r_kdbhd = NULL;
+
   if (classify_user_id (fpr, &desc, 1)
       || !(desc.mode == KEYDB_SEARCH_MODE_FPR
            || desc.mode == KEYDB_SEARCH_MODE_FPR16
            || desc.mode == KEYDB_SEARCH_MODE_FPR20))
     {
       log_error (_("\"%s\" is not a fingerprint\n"), fpr);
+      err = gpg_error (GPG_ERR_INV_NAME);
       goto leave;
     }
   err = get_pubkey_byname (ctrl, NULL, NULL, fpr, &keyblock, &kdbhd, 1, 1);
@@ -2470,33 +2579,72 @@ keyedit_quick_sign (ctrl_t ctrl, const char *fpr, strlist_t uids,
     }
 
   /* Check that the primary fingerprint has been given. */
-  {
-    byte fprbin[MAX_FINGERPRINT_LEN];
-    size_t fprlen;
-
-    fingerprint_from_pk (keyblock->pkt->pkt.public_key, fprbin, &fprlen);
-    if (fprlen == 16 && desc.mode == KEYDB_SEARCH_MODE_FPR16
-        && !memcmp (fprbin, desc.u.fpr, 16))
-      ;
-    else if (fprlen == 16 && desc.mode == KEYDB_SEARCH_MODE_FPR
-             && !memcmp (fprbin, desc.u.fpr, 16)
-             && !desc.u.fpr[16]
-             && !desc.u.fpr[17]
-             && !desc.u.fpr[18]
-             && !desc.u.fpr[19])
-      ;
-    else if (fprlen == 20 && (desc.mode == KEYDB_SEARCH_MODE_FPR20
-                              || desc.mode == KEYDB_SEARCH_MODE_FPR)
-             && !memcmp (fprbin, desc.u.fpr, 20))
-      ;
-    else
-      {
-        log_error (_("\"%s\" is not the primary fingerprint\n"), fpr);
-        goto leave;
-      }
-  }
+  fingerprint_from_pk (keyblock->pkt->pkt.public_key, fprbin, &fprlen);
+  if (fprlen == 16 && desc.mode == KEYDB_SEARCH_MODE_FPR16
+      && !memcmp (fprbin, desc.u.fpr, 16))
+    ;
+  else if (fprlen == 16 && desc.mode == KEYDB_SEARCH_MODE_FPR
+           && !memcmp (fprbin, desc.u.fpr, 16)
+           && !desc.u.fpr[16]
+           && !desc.u.fpr[17]
+           && !desc.u.fpr[18]
+           && !desc.u.fpr[19])
+    ;
+  else if (fprlen == 20 && (desc.mode == KEYDB_SEARCH_MODE_FPR20
+                            || desc.mode == KEYDB_SEARCH_MODE_FPR)
+           && !memcmp (fprbin, desc.u.fpr, 20))
+    ;
+  else
+    {
+      log_error (_("\"%s\" is not the primary fingerprint\n"), fpr);
+      err = gpg_error (GPG_ERR_INV_NAME);
+      goto leave;
+    }
 
-  if (fix_keyblock (&keyblock))
+  *r_keyblock = keyblock;
+  keyblock = NULL;
+  *r_kdbhd = kdbhd;
+  kdbhd = NULL;
+  err = 0;
+
+ leave:
+  release_kbnode (keyblock);
+  keydb_release (kdbhd);
+  return err;
+}
+
+
+/* Unattended key signing function.  If the key specifified by FPR is
+   available and FPR is the primary fingerprint all user ids of the
+   key are signed using the default signing key.  If UIDS is an empty
+   list all usable UIDs are signed, if it is not empty, only those
+   user ids matching one of the entries of the list are signed.  With
+   LOCAL being true the signatures are marked as non-exportable.  */
+void
+keyedit_quick_sign (ctrl_t ctrl, const char *fpr, strlist_t uids,
+                    strlist_t locusr, int local)
+{
+  gpg_error_t err;
+  kbnode_t keyblock = NULL;
+  KEYDB_HANDLE kdbhd = NULL;
+  int modified = 0;
+  PKT_public_key *pk;
+  kbnode_t node;
+  strlist_t sl;
+  int any;
+
+#ifdef HAVE_W32_SYSTEM
+  /* See keyedit_menu for why we need this.  */
+  check_trustdb_stale (ctrl);
+#endif
+
+  /* We require a fingerprint because only this uniquely identifies a
+     key and may thus be used to select a key for unattended key
+     signing.  */
+  if (find_by_primary_fpr (ctrl, fpr, &keyblock, &kdbhd))
+    goto leave;
+
+  if (fix_keyblock (ctrl, &keyblock))
     modified++;
 
   /* Give some info in verbose.  */
@@ -2524,54 +2672,315 @@ keyedit_quick_sign (ctrl_t ctrl, const char *fpr, strlist_t uids,
   menu_select_uid (keyblock, 0);   /* Better clear the flags first. */
   for (sl=uids; sl; sl = sl->next)
     {
+      const char *name = sl->d;
+      int count = 0;
+
+      sl->flags &= ~(1|2);  /* Clear flags used for error reporting.  */
+
       for (node = keyblock; node; node = node->next)
         {
           if (node->pkt->pkttype == PKT_USER_ID)
             {
-              PKT_user_id *uid = node->pkt->pkt.user_id;
+              PKT_user_id *uid = node->pkt->pkt.user_id;
+
+              if (uid->attrib_data)
+                ;
+              else if (*name == '='
+                       && strlen (name+1) == uid->len
+                       && !memcmp (uid->name, name + 1, uid->len))
+                { /* Exact match - we don't do a check for ambiguity
+                   * in this case.  */
+                  node->flag |= NODFLG_SELUID;
+                  if (any != -1)
+                    {
+                      sl->flags |= 1;  /* Report as found.  */
+                      any = 1;
+                    }
+                }
+              else if (ascii_memistr (uid->name, uid->len,
+                                      *name == '*'? name+1:name))
+                {
+                  node->flag |= NODFLG_SELUID;
+                  if (any != -1)
+                    {
+                      sl->flags |= 1;  /* Report as found.  */
+                      any = 1;
+                    }
+                  count++;
+                }
+            }
+        }
+
+      if (count > 1)
+        {
+          any = -1;        /* Force failure at end.  */
+          sl->flags |= 2;  /* Report as ambiguous.  */
+        }
+    }
+
+  /* Check whether all given user ids were found.  */
+  for (sl=uids; sl; sl = sl->next)
+    if (!(sl->flags & 1))
+      any = -1;  /* That user id was not found.  */
+
+  /* Print an error if there was a problem with the user ids.  */
+  if (uids && any < 1)
+    {
+      if (!opt.verbose)
+        show_key_with_all_names (ctrl, es_stdout, keyblock, 0, 0, 0, 0, 0, 1);
+      es_fflush (es_stdout);
+      for (sl=uids; sl; sl = sl->next)
+        {
+          if ((sl->flags & 2))
+            log_info (_("Invalid user ID '%s': %s\n"),
+                      sl->d, gpg_strerror (GPG_ERR_AMBIGUOUS_NAME));
+          else if (!(sl->flags & 1))
+            log_info (_("Invalid user ID '%s': %s\n"),
+                      sl->d, gpg_strerror (GPG_ERR_NOT_FOUND));
+        }
+      log_error ("%s  %s", _("No matching user IDs."), _("Nothing to sign.\n"));
+      goto leave;
+    }
+
+  /* Sign. */
+  sign_uids (ctrl, es_stdout, keyblock, locusr, &modified, local, 0, 0, 0, 1);
+  es_fflush (es_stdout);
+
+  if (modified)
+    {
+      err = keydb_update_keyblock (ctrl, kdbhd, keyblock);
+      if (err)
+        {
+          log_error (_("update failed: %s\n"), gpg_strerror (err));
+          goto leave;
+        }
+    }
+  else
+    log_info (_("Key not changed so no update needed.\n"));
+
+  if (update_trust)
+    revalidation_mark (ctrl);
+
+
+ leave:
+  release_kbnode (keyblock);
+  keydb_release (kdbhd);
+}
+
+
+/* Unattended subkey creation function.
+ *
+ */
+void
+keyedit_quick_addkey (ctrl_t ctrl, const char *fpr, const char *algostr,
+                      const char *usagestr, const char *expirestr)
+{
+  gpg_error_t err;
+  kbnode_t keyblock;
+  KEYDB_HANDLE kdbhd;
+  int modified = 0;
+  PKT_public_key *pk;
+
+#ifdef HAVE_W32_SYSTEM
+  /* See keyedit_menu for why we need this.  */
+  check_trustdb_stale (ctrl);
+#endif
+
+  /* We require a fingerprint because only this uniquely identifies a
+   * key and may thus be used to select a key for unattended subkey
+   * creation.  */
+  if (find_by_primary_fpr (ctrl, fpr, &keyblock, &kdbhd))
+    goto leave;
+
+  if (fix_keyblock (ctrl, &keyblock))
+    modified++;
+
+  pk = keyblock->pkt->pkt.public_key;
+  if (pk->flags.revoked)
+    {
+      if (!opt.verbose)
+        show_key_with_all_names (ctrl, es_stdout, keyblock, 0, 0, 0, 0, 0, 1);
+      log_error ("%s%s", _("Key is revoked."), "\n");
+      goto leave;
+    }
+
+  /* Create the subkey.  Note that the called function already prints
+   * an error message. */
+  if (!generate_subkeypair (ctrl, keyblock, algostr, usagestr, expirestr))
+    modified = 1;
+  es_fflush (es_stdout);
+
+  /* Store.  */
+  if (modified)
+    {
+      err = keydb_update_keyblock (ctrl, kdbhd, keyblock);
+      if (err)
+        {
+          log_error (_("update failed: %s\n"), gpg_strerror (err));
+          goto leave;
+        }
+    }
+  else
+    log_info (_("Key not changed so no update needed.\n"));
+
+ leave:
+  release_kbnode (keyblock);
+  keydb_release (kdbhd);
+}
+
+
+/* Unattended expiration setting function for the main key.  If
+ * SUBKEYFPRS is not NULL and SUBKEYSFPRS[0] is neither NULL, it is
+ * expected to be an array of fingerprints for subkeys to change. It
+ * may also be an array which just one item "*" to indicate that all
+ * keys shall be set to that expiration date.
+ */
+void
+keyedit_quick_set_expire (ctrl_t ctrl, const char *fpr, const char *expirestr,
+                          char **subkeyfprs)
+{
+  gpg_error_t err;
+  kbnode_t keyblock, node;
+  KEYDB_HANDLE kdbhd;
+  int modified = 0;
+  PKT_public_key *pk;
+  u32 expire;
+  int primary_only = 0;
+  int idx;
+
+#ifdef HAVE_W32_SYSTEM
+  /* See keyedit_menu for why we need this.  */
+  check_trustdb_stale (ctrl);
+#endif
+
+  /* We require a fingerprint because only this uniquely identifies a
+   * key and may thus be used to select a key for unattended
+   * expiration setting.  */
+  err = find_by_primary_fpr (ctrl, fpr, &keyblock, &kdbhd);
+  if (err)
+    goto leave;
+
+  if (fix_keyblock (ctrl, &keyblock))
+    modified++;
+
+  pk = keyblock->pkt->pkt.public_key;
+  if (pk->flags.revoked)
+    {
+      if (!opt.verbose)
+        show_key_with_all_names (ctrl, es_stdout, keyblock, 0, 0, 0, 0, 0, 1);
+      log_error ("%s%s", _("Key is revoked."), "\n");
+      err = gpg_error (GPG_ERR_CERT_REVOKED);
+      goto leave;
+    }
+
+  expire = parse_expire_string (expirestr);
+  if (expire == (u32)-1 )
+    {
+      log_error (_("'%s' is not a valid expiration time\n"), expirestr);
+      err = gpg_error (GPG_ERR_INV_VALUE);
+      goto leave;
+    }
+  if (expire)
+    expire += make_timestamp ();
+
+  /* Check whether a subkey's expiration time shall be changed or the
+   * expiration time of all keys.  */
+  if (!subkeyfprs || !subkeyfprs[0])
+    primary_only = 1;
+  else if ( !strcmp (subkeyfprs[0], "*") && !subkeyfprs[1])
+    {
+      /* Change all subkeys keys which have not been revoked and are
+       * not yet expired.  */
+      merge_keys_and_selfsig (ctrl, keyblock);
+      for (node = keyblock; node; node = node->next)
+        {
+          if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
+              && (pk = node->pkt->pkt.public_key)
+              && !pk->flags.revoked
+              && !pk->has_expired)
+            node->flag |= NODFLG_SELKEY;
+        }
+    }
+  else
+    {
+      /* Change specified subkeys.  */
+      KEYDB_SEARCH_DESC desc;
+      byte fprbin[MAX_FINGERPRINT_LEN];
+      size_t fprlen;
+
+      err = 0;
+      merge_keys_and_selfsig (ctrl, keyblock);
+      for (idx=0; subkeyfprs[idx]; idx++)
+        {
+          int any = 0;
+
+          /* Parse the fingerprint.  */
+          if (classify_user_id (subkeyfprs[idx], &desc, 1)
+              || !(desc.mode == KEYDB_SEARCH_MODE_FPR
+                   || desc.mode == KEYDB_SEARCH_MODE_FPR20))
+            {
+              log_error (_("\"%s\" is not a proper fingerprint\n"),
+                         subkeyfprs[idx] );
+              if (!err)
+                err = gpg_error (GPG_ERR_INV_NAME);
+              continue;
+            }
 
-              if (!uid->attrib_data
-                  && ascii_memistr (uid->name, uid->len, sl->d))
+          /* Set the flag for the matching non revoked subkey.  */
+          for (node = keyblock; node; node = node->next)
+            {
+              if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
+                  && (pk = node->pkt->pkt.public_key)
+                  && !pk->flags.revoked )
                 {
-                  node->flag |= NODFLG_SELUID;
-                  any = 1;
+                  fingerprint_from_pk (pk, fprbin, &fprlen);
+                  if (fprlen == 20 && !memcmp (fprbin, desc.u.fpr, 20))
+                    {
+                      node->flag |= NODFLG_SELKEY;
+                      any = 1;
+                    }
                 }
             }
+          if (!any)
+            {
+              log_error (_("subkey \"%s\" not found\n"), subkeyfprs[idx]);
+              if (!err)
+                err = gpg_error (GPG_ERR_NOT_FOUND);
+            }
         }
-    }
 
-  if (uids && !any)
-    {
-      if (!opt.verbose)
-        show_key_with_all_names (ctrl, es_stdout, keyblock, 0, 0, 0, 0, 0, 1);
-      es_fflush (es_stdout);
-      log_error ("%s  %s", _("No matching user IDs."), _("Nothing to sign.\n"));
-      goto leave;
+      if (err)
+        goto leave;
     }
 
-  /* Sign. */
-  sign_uids (ctrl, es_stdout, keyblock, locusr, &modified, local, 0, 0, 0, 1);
+  /* Set the new expiration date.  */
+  err = menu_expire (ctrl, keyblock, primary_only? 1 : 2, expire);
+  if (gpg_err_code (err) == GPG_ERR_TRUE)
+    modified = 1;
+  else if (err)
+    goto leave;
   es_fflush (es_stdout);
 
+  /* Store.  */
   if (modified)
     {
-      err = keydb_update_keyblock (kdbhd, keyblock);
+      err = keydb_update_keyblock (ctrl, kdbhd, keyblock);
       if (err)
         {
           log_error (_("update failed: %s\n"), gpg_strerror (err));
           goto leave;
         }
+      if (update_trust)
+        revalidation_mark (ctrl);
     }
   else
     log_info (_("Key not changed so no update needed.\n"));
 
-  if (update_trust)
-    revalidation_mark ();
-
-
  leave:
   release_kbnode (keyblock);
   keydb_release (kdbhd);
+  if (err)
+    write_status_error ("set_expire", err);
 }
 
 
@@ -2657,6 +3066,23 @@ show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose)
          tty_printf ("%s", openpgp_cipher_algo_name (CIPHER_ALGO_3DES));
        }
       tty_printf ("\n     ");
+      tty_printf (_("AEAD: "));
+      for (i = any = 0; prefs[i].type; i++)
+       {
+         if (prefs[i].type == PREFTYPE_AEAD)
+           {
+             if (any)
+               tty_printf (", ");
+             any = 1;
+             /* We don't want to display strings for experimental algos */
+             if (!openpgp_aead_test_algo (prefs[i].value)
+                 && prefs[i].value < 100)
+               tty_printf ("%s", openpgp_aead_algo_name (prefs[i].value));
+             else
+               tty_printf ("[%d]", prefs[i].value);
+           }
+       }
+      tty_printf ("\n     ");
       tty_printf (_("Digest: "));
       for (i = any = 0; prefs[i].type; i++)
        {
@@ -2711,7 +3137,7 @@ show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose)
            }
          tty_printf ("%s", compress_algo_to_string (COMPRESS_ALGO_NONE));
        }
-      if (uid->flags.mdc || !uid->flags.ks_modify)
+      if (uid->flags.mdc || uid->flags.aead || !uid->flags.ks_modify)
        {
          tty_printf ("\n     ");
          tty_printf (_("Features: "));
@@ -2721,6 +3147,12 @@ show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose)
              tty_printf ("MDC");
              any = 1;
            }
+         if (!uid->flags.aead)
+           {
+             if (any)
+               tty_printf (", ");
+             tty_printf ("AEAD");
+           }
          if (!uid->flags.ks_modify)
            {
              if (any)
@@ -2759,12 +3191,15 @@ show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose)
       for (i = 0; prefs[i].type; i++)
        {
          tty_printf (" %c%d", prefs[i].type == PREFTYPE_SYM ? 'S' :
+                     prefs[i].type == PREFTYPE_AEAD ? 'A' :
                      prefs[i].type == PREFTYPE_HASH ? 'H' :
                      prefs[i].type == PREFTYPE_ZIP ? 'Z' : '?',
                      prefs[i].value);
        }
       if (uid->flags.mdc)
        tty_printf (" [mdc]");
+      if (uid->flags.aead)
+       tty_printf (" [aead]");
       if (!uid->flags.ks_modify)
        tty_printf (" [no-ks-modify]");
       tty_printf ("\n");
@@ -2818,7 +3253,7 @@ show_key_with_all_names_colon (ctrl_t ctrl, estream_t fp, kbnode_t keyblock)
            es_putc ('e', fp);
          else if (!(opt.fast_list_mode || opt.no_expensive_trust_checks))
            {
-             int trust = get_validity_info (pk, NULL);
+             int trust = get_validity_info (ctrl, keyblock, pk, NULL);
              if (trust == 'u')
                ulti_hack = 1;
              es_putc (trust, fp);
@@ -2831,7 +3266,7 @@ show_key_with_all_names_colon (ctrl_t ctrl, estream_t fp, kbnode_t keyblock)
                       (ulong) pk->timestamp, (ulong) pk->expiredate);
          if (node->pkt->pkttype == PKT_PUBLIC_KEY
              && !(opt.fast_list_mode || opt.no_expensive_trust_checks))
-           es_putc (get_ownertrust_info (pk), fp);
+           es_putc (get_ownertrust_info (ctrl, pk, 0), fp);
          es_putc (':', fp);
          es_putc (':', fp);
          es_putc (':', fp);
@@ -2846,7 +3281,7 @@ show_key_with_all_names_colon (ctrl_t ctrl, estream_t fp, kbnode_t keyblock)
            es_putc ('a', fp);
          es_putc ('\n', fp);
 
-         print_fingerprint (fp, pk, 0);
+         print_fingerprint (ctrl, fp, pk, 0);
          print_revokers (fp, pk);
        }
     }
@@ -2866,9 +3301,9 @@ show_key_with_all_names_colon (ctrl_t ctrl, estream_t fp, kbnode_t keyblock)
          else
            es_fputs ("uid:", fp);
 
-         if (uid->is_revoked)
+         if (uid->flags.revoked)
            es_fputs ("r::::::::", fp);
-         else if (uid->is_expired)
+         else if (uid->flags.expired)
            es_fputs ("e::::::::", fp);
          else if (opt.fast_list_mode || opt.no_expensive_trust_checks)
            es_fputs ("::::::::", fp);
@@ -2877,7 +3312,7 @@ show_key_with_all_names_colon (ctrl_t ctrl, estream_t fp, kbnode_t keyblock)
              int uid_validity;
 
              if (primary && !ulti_hack)
-               uid_validity = get_validity_info (primary, uid);
+               uid_validity = get_validity_info (ctrl, keyblock, primary, uid);
              else
                uid_validity = 'u';
              es_fprintf (fp, "%c::::::::", uid_validity);
@@ -2910,23 +3345,35 @@ show_key_with_all_names_colon (ctrl_t ctrl, estream_t fp, kbnode_t keyblock)
                }
              if (uid->flags.mdc)
                es_fputs (",mdc", fp);
+             if (uid->flags.aead)
+               es_fputs (",aead", fp);
              if (!uid->flags.ks_modify)
                es_fputs (",no-ks-modify", fp);
            }
          es_putc (':', fp);
          /* flags */
          es_fprintf (fp, "%d,", i);
-         if (uid->is_primary)
+         if (uid->flags.primary)
            es_putc ('p', fp);
-         if (uid->is_revoked)
+         if (uid->flags.revoked)
            es_putc ('r', fp);
-         if (uid->is_expired)
+         if (uid->flags.expired)
            es_putc ('e', fp);
          if ((node->flag & NODFLG_SELUID))
            es_putc ('s', fp);
          if ((node->flag & NODFLG_MARK_A))
            es_putc ('m', fp);
          es_putc (':', fp);
+         if (opt.trust_model == TM_TOFU || opt.trust_model == TM_TOFU_PGP)
+           {
+#ifdef USE_TOFU
+             enum tofu_policy policy;
+             if (! tofu_get_policy (ctrl, primary, uid, &policy)
+                 && policy != TOFU_POLICY_NONE)
+               es_fprintf (fp, "%s", tofu_policy_str (policy));
+#endif /*USE_TOFU*/
+           }
+         es_putc (':', fp);
          es_putc ('\n', fp);
        }
     }
@@ -2934,8 +3381,8 @@ show_key_with_all_names_colon (ctrl_t ctrl, estream_t fp, kbnode_t keyblock)
 
 
 static void
-show_names (estream_t fp,
-            KBNODE keyblock, PKT_public_key * pk, unsigned int flag,
+show_names (ctrl_t ctrl, estream_t fp,
+            kbnode_t keyblock, PKT_public_key * pk, unsigned int flag,
            int with_prefs)
 {
   KBNODE node;
@@ -2950,13 +3397,13 @@ show_names (estream_t fp,
          if (!flag || (flag && (node->flag & flag)))
            {
              if (!(flag & NODFLG_MARK_A) && pk)
-               tty_fprintf (fp, "%s ", uid_trust_string_fixed (pk, uid));
+               tty_fprintf (fp, "%s ", uid_trust_string_fixed (ctrl, pk, uid));
 
              if (flag & NODFLG_MARK_A)
                tty_fprintf (fp, "     ");
              else if (node->flag & NODFLG_SELUID)
                tty_fprintf (fp, "(%d)* ", i);
-             else if (uid->is_primary)
+             else if (uid->flags.primary)
                tty_fprintf (fp, "(%d). ", i);
              else
                tty_fprintf (fp, "(%d)  ", i);
@@ -3037,12 +3484,13 @@ show_key_with_all_names (ctrl_t ctrl, estream_t fp,
               * output */
              static int did_warn = 0;
 
-             trust = get_validity_string (pk, NULL);
-             otrust = get_ownertrust_string (pk);
+             trust = get_validity_string (ctrl, pk, NULL);
+             otrust = get_ownertrust_string (ctrl, pk, 0);
 
              /* Show a warning once */
              if (!did_warn
-                 && (get_validity (pk, NULL) & TRUST_FLAG_PENDING_CHECK))
+                 && (get_validity (ctrl, keyblock, pk, NULL, NULL, 0)
+                     & TRUST_FLAG_PENDING_CHECK))
                {
                  did_warn = 1;
                  do_warn = 1;
@@ -3053,7 +3501,7 @@ show_key_with_all_names (ctrl_t ctrl, estream_t fp,
 
          if (pk->flags.revoked)
            {
-             char *user = get_user_id_string_native (pk->revoked.keyid);
+             char *user = get_user_id_string_native (ctrl, pk->revoked.keyid);
               tty_fprintf (fp,
                            _("The following key was revoked on"
                             " %s by %s key %s\n"),
@@ -3074,10 +3522,10 @@ show_key_with_all_names (ctrl_t ctrl, estream_t fp,
                    const char *algo;
 
                    algo = gcry_pk_algo_name (pk->revkey[i].algid);
-                   keyid_from_fingerprint (pk->revkey[i].fpr,
+                   keyid_from_fingerprint (ctrl, pk->revkey[i].fpr,
                                            MAX_FINGERPRINT_LEN, r_keyid);
 
-                   user = get_user_id_string_native (r_keyid);
+                   user = get_user_id_string_native (ctrl, r_keyid);
                    tty_fprintf (fp,
                                  _("This key may be revoked by %s key %s"),
                                  algo ? algo : "?", user);
@@ -3108,7 +3556,7 @@ show_key_with_all_names (ctrl_t ctrl, estream_t fp,
                 have_seckey = 0;
               }
             else
-              have_seckey = !agent_get_keyinfo (ctrl, hexgrip, &serialno);
+              have_seckey = !agent_get_keyinfo (ctrl, hexgrip, &serialno, NULL);
             xfree (hexgrip);
           }
 
@@ -3162,7 +3610,7 @@ show_key_with_all_names (ctrl_t ctrl, estream_t fp,
               && pk->seckey_info->is_protected
               && pk->seckey_info->s2k.mode == 1002)
            {
-              /* FIXME: Check wether this code path is still used.  */
+              /* FIXME: Check whether this code path is still used.  */
              tty_fprintf (fp, "%*s%s", opt.legacy_list_mode? 21:5, "",
                            _("card-no: "));
              if (pk->seckey_info->ivlen == 16
@@ -3195,9 +3643,10 @@ show_key_with_all_names (ctrl_t ctrl, estream_t fp,
                                opt.legacy_list_mode?
                                ((int) keystrlen () + 13):5, "");
                  /* Ownertrust is only meaningful for the PGP or
-                    classic trust models */
+                    classic trust models, or PGP combined with TOFU */
                  if (opt.trust_model == TM_PGP
-                     || opt.trust_model == TM_CLASSIC)
+                     || opt.trust_model == TM_CLASSIC
+                     || opt.trust_model == TM_TOFU_PGP)
                    {
                      int width = 14 - strlen (otrust);
                      if (width <= 0)
@@ -3210,7 +3659,7 @@ show_key_with_all_names (ctrl_t ctrl, estream_t fp,
                  tty_fprintf (fp, "\n");
                }
              if (node->pkt->pkttype == PKT_PUBLIC_KEY
-                 && (get_ownertrust (pk) & TRUST_FLAG_DISABLED))
+                 && (get_ownertrust (ctrl, pk) & TRUST_FLAG_DISABLED))
                {
                  tty_fprintf (fp, "*** ");
                  tty_fprintf (fp, _("This key has been disabled"));
@@ -3221,13 +3670,13 @@ show_key_with_all_names (ctrl_t ctrl, estream_t fp,
          if ((node->pkt->pkttype == PKT_PUBLIC_KEY
                || node->pkt->pkttype == PKT_SECRET_KEY) && with_fpr)
            {
-              print_fingerprint (fp, pk, 2);
+              print_fingerprint (ctrl, fp, pk, 2);
              tty_fprintf (fp, "\n");
            }
        }
     }
 
-  show_names (fp,
+  show_names (ctrl, fp,
               keyblock, primary, only_marked ? NODFLG_MARK_A : 0, with_prefs);
 
   if (do_warn && !nowarn)
@@ -3246,7 +3695,7 @@ show_key_with_all_names (ctrl_t ctrl, estream_t fp,
    secret keys and thus the printing of "pub" vs. "sec" does only
    depend on the packet type and not by checking with gpg-agent.  */
 void
-show_basic_key_info (KBNODE keyblock)
+show_basic_key_info (ctrl_t ctrl, kbnode_t keyblock)
 {
   KBNODE node;
   int i;
@@ -3272,7 +3721,7 @@ show_basic_key_info (KBNODE keyblock)
          tty_printf ("  ");
          tty_printf (_("expires: %s"), expirestr_from_pk (pk));
          tty_printf ("\n");
-         print_fingerprint (NULL, pk, 3);
+         print_fingerprint (ctrl, NULL, pk, 3);
          tty_printf ("\n");
        }
     }
@@ -3286,9 +3735,9 @@ show_basic_key_info (KBNODE keyblock)
          ++i;
 
          tty_printf ("     ");
-         if (uid->is_revoked)
+         if (uid->flags.revoked)
            tty_printf ("[%s] ", _("revoked"));
-         else if (uid->is_expired)
+         else if (uid->flags.expired)
            tty_printf ("[%s] ", _("expired"));
          tty_print_utf8_string (uid->name, uid->len);
          tty_printf ("\n");
@@ -3298,7 +3747,7 @@ show_basic_key_info (KBNODE keyblock)
 
 
 static void
-show_key_and_fingerprint (kbnode_t keyblock, int with_subkeys)
+show_key_and_fingerprint (ctrl_t ctrl, kbnode_t keyblock, int with_subkeys)
 {
   kbnode_t node;
   PKT_public_key *pk = NULL;
@@ -3323,7 +3772,7 @@ show_key_and_fingerprint (kbnode_t keyblock, int with_subkeys)
     }
   tty_printf ("\n");
   if (pk)
-    print_fingerprint (NULL, pk, 2);
+    print_fingerprint (ctrl, NULL, pk, 2);
   if (with_subkeys)
     {
       for (node = keyblock; node; node = node->next)
@@ -3337,7 +3786,7 @@ show_key_and_fingerprint (kbnode_t keyblock, int with_subkeys)
                           datestr_from_pk (pk),
                           usagestr_from_pk (pk, 0));
 
-              print_fingerprint (NULL, pk, 4);
+              print_fingerprint (ctrl, NULL, pk, 4);
             }
         }
     }
@@ -3396,7 +3845,7 @@ no_primary_warning (KBNODE keyblock)
        {
          uid_count++;
 
-         if (node->pkt->pkt.user_id->is_primary == 2)
+         if (node->pkt->pkt.user_id->flags.primary == 2)
            {
              have_primary = 1;
              break;
@@ -3472,8 +3921,8 @@ subkey_expire_warning (kbnode_t keyblock)
  * user id.
  */
 static int
-menu_adduid (kbnode_t pub_keyblock, int photo, const char *photo_name,
-             const char *uidstring)
+menu_adduid (ctrl_t ctrl, kbnode_t pub_keyblock,
+             int photo, const char *photo_name, const char *uidstring)
 {
   PKT_user_id *uid;
   PKT_public_key *pk = NULL;
@@ -3495,7 +3944,7 @@ menu_adduid (kbnode_t pub_keyblock, int photo, const char *photo_name,
     }
   if (!node) /* No subkey.  */
     pub_where = NULL;
-  assert (pk);
+  log_assert (pk);
 
   if (photo)
     {
@@ -3535,18 +3984,21 @@ menu_adduid (kbnode_t pub_keyblock, int photo, const char *photo_name,
            }
        }
 
-      uid = generate_photo_id (pk, photo_name);
+      uid = generate_photo_id (ctrl, pk, photo_name);
     }
   else
     uid = generate_user_id (pub_keyblock, uidstring);
   if (!uid)
     {
       if (uidstring)
-        log_error ("%s", _("Such a user ID already exists on this key!\n"));
+        {
+          write_status_error ("adduid", gpg_error (304));
+          log_error ("%s", _("Such a user ID already exists on this key!\n"));
+        }
       return 0;
     }
 
-  err = make_keysig_packet (&sig, pk, uid, NULL, pk, 0x13, 0, 0, 0,
+  err = make_keysig_packet (ctrl, &sig, pk, uid, NULL, pk, 0x13, 0, 0, 0,
                             keygen_add_std_prefs, pk, NULL);
   if (err)
     {
@@ -3567,7 +4019,7 @@ menu_adduid (kbnode_t pub_keyblock, int photo, const char *photo_name,
     add_kbnode (pub_keyblock, node);
   pkt = xmalloc_clear (sizeof *pkt);
   pkt->pkttype = PKT_SIGNATURE;
-  pkt->pkt.signature = copy_signature (NULL, sig);
+  pkt->pkt.signature = sig;
   if (pub_where)
     insert_kbnode (node, new_kbnode (pkt), 0);
   else
@@ -3594,7 +4046,7 @@ menu_deluid (KBNODE pub_keyblock)
            {
              /* Only cause a trust update if we delete a
                 non-revoked user id */
-             if (!node->pkt->pkt.user_id->is_revoked)
+             if (!node->pkt->pkt.user_id->flags.revoked)
                update_trust = 1;
              delete_kbnode (node);
            }
@@ -3609,7 +4061,7 @@ menu_deluid (KBNODE pub_keyblock)
 
 
 static int
-menu_delsig (KBNODE pub_keyblock)
+menu_delsig (ctrl_t ctrl, kbnode_t pub_keyblock)
 {
   KBNODE node;
   PKT_user_id *uid = NULL;
@@ -3631,11 +4083,11 @@ menu_delsig (KBNODE pub_keyblock)
 
          okay = inv_sig = no_key = other_err = 0;
          if (opt.with_colons)
-           valid = print_and_check_one_sig_colon (pub_keyblock, node,
+           valid = print_and_check_one_sig_colon (ctrl, pub_keyblock, node,
                                                   &inv_sig, &no_key,
                                                   &other_err, &selfsig, 1);
          else
-           valid = print_and_check_one_sig (pub_keyblock, node,
+           valid = print_and_check_one_sig (ctrl, pub_keyblock, node,
                                             &inv_sig, &no_key, &other_err,
                                             &selfsig, 1, 0);
 
@@ -3680,8 +4132,8 @@ menu_delsig (KBNODE pub_keyblock)
   if (changed)
     {
       commit_kbnode (&pub_keyblock);
-      tty_printf (changed == 1 ? _("Deleted %d signature.\n")
-                 : _("Deleted %d signatures.\n"), changed);
+      tty_printf (ngettext("Deleted %d signature.\n",
+                           "Deleted %d signatures.\n", changed), changed);
     }
   else
     tty_printf (_("Nothing deleted.\n"));
@@ -3691,7 +4143,7 @@ menu_delsig (KBNODE pub_keyblock)
 
 
 static int
-menu_clean (KBNODE keyblock, int self_only)
+menu_clean (ctrl_t ctrl, kbnode_t keyblock, int self_only)
 {
   KBNODE uidnode;
   int modified = 0, select_all = !count_selected_uids (keyblock);
@@ -3708,15 +4160,15 @@ menu_clean (KBNODE keyblock, int self_only)
                                       uidnode->pkt->pkt.user_id->len,
                                       0);
 
-         clean_one_uid (keyblock, uidnode, opt.verbose, self_only, &uids,
+         clean_one_uid (ctrl, keyblock, uidnode, opt.verbose, self_only, &uids,
                         &sigs);
          if (uids)
            {
              const char *reason;
 
-             if (uidnode->pkt->pkt.user_id->is_revoked)
+             if (uidnode->pkt->pkt.user_id->flags.revoked)
                reason = _("revoked");
-             else if (uidnode->pkt->pkt.user_id->is_expired)
+             else if (uidnode->pkt->pkt.user_id->flags.expired)
                reason = _("expired");
              else
                reason = _("invalid");
@@ -3727,11 +4179,9 @@ menu_clean (KBNODE keyblock, int self_only)
            }
          else if (sigs)
            {
-             tty_printf (sigs == 1 ?
-                         _("User ID \"%s\": %d signature removed\n") :
-                         _("User ID \"%s\": %d signatures removed\n"),
-                         user, sigs);
-
+             tty_printf (ngettext("User ID \"%s\": %d signature removed\n",
+                                   "User ID \"%s\": %d signatures removed\n",
+                                   sigs), user, sigs);
              modified = 1;
            }
          else
@@ -3794,7 +4244,7 @@ menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive)
   size_t fprlen;
   int rc;
 
-  assert (pub_keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
+  log_assert (pub_keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
 
   pk = pub_keyblock->pkt->pkt.public_key;
 
@@ -3900,8 +4350,7 @@ menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive)
                  log_error (_("this key has already been designated "
                               "as a revoker\n"));
 
-                 sprintf (buf, "%08lX%08lX",
-                          (ulong) pk->keyid[0], (ulong) pk->keyid[1]);
+                  format_keyid (pk_keyid (pk), KF_LONG, buf, sizeof (buf));
                  write_status_text (STATUS_ALREADY_SIGNED, buf);
 
                  break;
@@ -3912,8 +4361,8 @@ menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive)
            continue;
        }
 
-      print_pubkey_info (NULL, revoker_pk);
-      print_fingerprint (NULL, revoker_pk, 2);
+      print_pubkey_info (ctrl, NULL, revoker_pk);
+      print_fingerprint (ctrl, NULL, revoker_pk, 2);
       tty_printf ("\n");
 
       tty_printf (_("WARNING: appointing a key as a designated revoker "
@@ -3931,7 +4380,7 @@ menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive)
       break;
     }
 
-  rc = make_keysig_packet (&sig, pk, NULL, NULL, pk, 0x1F, 0, 0, 0,
+  rc = make_keysig_packet (ctrl, &sig, pk, NULL, NULL, pk, 0x1F, 0, 0, 0,
                           keygen_add_revkey, &revkey, NULL);
   if (rc)
     {
@@ -3957,33 +4406,55 @@ fail:
 }
 
 
-static int
-menu_expire (KBNODE pub_keyblock)
+/* With FORCE_MAINKEY cleared this function handles the interactive
+ * menu option "expire".  With UNATTENDED set to 1 this function only
+ * sets the expiration date of the primary key to NEWEXPIRATION and
+ * avoid all interactivity; with a value of 2 only the flagged subkeys
+ * are set to NEWEXPIRATION.  Returns 0 if nothing was done,
+ * GPG_ERR_TRUE if the key was modified, or any other error code. */
+static gpg_error_t
+menu_expire (ctrl_t ctrl, kbnode_t pub_keyblock,
+             int unattended, u32 newexpiration)
 {
-  int n1, signumber, rc;
+  int signumber, rc;
   u32 expiredate;
-  int mainkey = 0;
+  int only_mainkey;  /* Set if only the mainkey is to be updated.  */
   PKT_public_key *main_pk, *sub_pk;
   PKT_user_id *uid;
-  KBNODE node;
+  kbnode_t node;
   u32 keyid[2];
 
-  n1 = count_selected_keys (pub_keyblock);
-  if (n1 > 1)
+  if (unattended)
     {
-      tty_printf (_("Please select at most one subkey.\n"));
-      return 0;
+      only_mainkey = (unattended == 1);
+      expiredate = newexpiration;
     }
-  else if (n1)
-    tty_printf (_("Changing expiration time for a subkey.\n"));
   else
     {
-      tty_printf (_("Changing expiration time for the primary key.\n"));
-      mainkey = 1;
-      no_primary_warning (pub_keyblock);
+      int n1;
+
+      only_mainkey = 0;
+      n1 = count_selected_keys (pub_keyblock);
+      if (n1 > 1)
+        {
+          if (!cpr_get_answer_is_yes
+              ("keyedit.expire_multiple_subkeys.okay",
+               _("Are you sure you want to change the"
+                 " expiration time for multiple subkeys? (y/N) ")))
+            return gpg_error (GPG_ERR_CANCELED);;
+        }
+      else if (n1)
+        tty_printf (_("Changing expiration time for a subkey.\n"));
+      else
+        {
+          tty_printf (_("Changing expiration time for the primary key.\n"));
+          only_mainkey = 1;
+          no_primary_warning (pub_keyblock);
+        }
+
+      expiredate = ask_expiredate ();
     }
 
-  expiredate = ask_expiredate ();
 
   /* Now we can actually change the self-signature(s) */
   main_pk = sub_pk = NULL;
@@ -3997,22 +4468,29 @@ menu_expire (KBNODE pub_keyblock)
          keyid_from_pk (main_pk, keyid);
          main_pk->expiredate = expiredate;
        }
-      else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
-              && (node->flag & NODFLG_SELKEY))
+      else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
        {
-         sub_pk = node->pkt->pkt.public_key;
-         sub_pk->expiredate = expiredate;
+          if ((node->flag & NODFLG_SELKEY) && unattended != 1)
+            {
+              /* The flag is set and we do not want to set the
+               * expiration date only for the main key.  */
+              sub_pk = node->pkt->pkt.public_key;
+              sub_pk->expiredate = expiredate;
+            }
+          else
+            sub_pk = NULL;
        }
       else if (node->pkt->pkttype == PKT_USER_ID)
        uid = node->pkt->pkt.user_id;
       else if (main_pk && node->pkt->pkttype == PKT_SIGNATURE
-              && (mainkey || sub_pk))
+              && (only_mainkey || sub_pk))
        {
          PKT_signature *sig = node->pkt->pkt.signature;
+
          if (keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1]
-             && ((mainkey && uid
+             && ((only_mainkey && uid
                   && uid->created && (sig->sig_class & ~3) == 0x10)
-                 || (!mainkey && sig->sig_class == 0x18))
+                 || (!only_mainkey && sig->sig_class == 0x18))
              && sig->flags.chosen_selfsig)
            {
              /* This is a self-signature which is to be replaced.  */
@@ -4021,34 +4499,38 @@ menu_expire (KBNODE pub_keyblock)
 
              signumber++;
 
-             if ((mainkey && main_pk->version < 4)
-                 || (!mainkey && sub_pk->version < 4))
+             if ((only_mainkey && main_pk->version < 4)
+                 || (!only_mainkey && sub_pk->version < 4))
                {
                  log_info
                     (_("You can't change the expiration date of a v3 key\n"));
-                 return 0;
+                 return gpg_error (GPG_ERR_LEGACY_KEY);
                }
 
-             if (mainkey)
-               rc = update_keysig_packet (&newsig, sig, main_pk, uid, NULL,
+             if (only_mainkey)
+               rc = update_keysig_packet (ctrl,
+                                           &newsig, sig, main_pk, uid, NULL,
                                           main_pk, keygen_add_key_expire,
                                           main_pk);
              else
                rc =
-                 update_keysig_packet (&newsig, sig, main_pk, NULL, sub_pk,
+                 update_keysig_packet (ctrl,
+                                        &newsig, sig, main_pk, NULL, sub_pk,
                                        main_pk, keygen_add_key_expire, sub_pk);
              if (rc)
                {
                  log_error ("make_keysig_packet failed: %s\n",
                             gpg_strerror (rc));
-                 return 0;
+                  if (gpg_err_code (rc) == GPG_ERR_TRUE)
+                    rc = GPG_ERR_GENERAL;
+                 return rc;
                }
 
              /* Replace the packet.  */
              newpkt = xmalloc_clear (sizeof *newpkt);
              newpkt->pkttype = PKT_SIGNATURE;
              newpkt->pkt.signature = newsig;
-             free_packet (node->pkt);
+             free_packet (node->pkt, NULL);
              xfree (node->pkt);
              node->pkt = newpkt;
              sub_pk = NULL;
@@ -4057,21 +4539,131 @@ menu_expire (KBNODE pub_keyblock)
     }
 
   update_trust = 1;
+  return gpg_error (GPG_ERR_TRUE);
+}
+
+
+/* Change the capability of a selected key.  This command should only
+ * be used to rectify badly created keys and as such is not suggested
+ * for general use.  */
+static int
+menu_changeusage (ctrl_t ctrl, kbnode_t keyblock)
+{
+  int n1, rc;
+  int mainkey = 0;
+  PKT_public_key *main_pk, *sub_pk;
+  PKT_user_id *uid;
+  kbnode_t node;
+  u32 keyid[2];
+
+  n1 = count_selected_keys (keyblock);
+  if (n1 > 1)
+    {
+      tty_printf (_("You must select exactly one key.\n"));
+      return 0;
+    }
+  else if (n1)
+    tty_printf (_("Changing usage of a subkey.\n"));
+  else
+    {
+      tty_printf (_("Changing usage of the primary key.\n"));
+      mainkey = 1;
+    }
+
+  /* Now we can actually change the self-signature(s) */
+  main_pk = sub_pk = NULL;
+  uid = NULL;
+  for (node = keyblock; node; node = node->next)
+    {
+      if (node->pkt->pkttype == PKT_PUBLIC_KEY)
+       {
+         main_pk = node->pkt->pkt.public_key;
+         keyid_from_pk (main_pk, keyid);
+       }
+      else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+       {
+          if (node->flag & NODFLG_SELKEY)
+            sub_pk = node->pkt->pkt.public_key;
+          else
+            sub_pk = NULL;
+       }
+      else if (node->pkt->pkttype == PKT_USER_ID)
+       uid = node->pkt->pkt.user_id;
+      else if (main_pk && node->pkt->pkttype == PKT_SIGNATURE
+              && (mainkey || sub_pk))
+       {
+         PKT_signature *sig = node->pkt->pkt.signature;
+         if (keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1]
+             && ((mainkey && uid
+                  && uid->created && (sig->sig_class & ~3) == 0x10)
+                 || (!mainkey && sig->sig_class == 0x18))
+             && sig->flags.chosen_selfsig)
+           {
+             /* This is the self-signature which is to be replaced.  */
+             PKT_signature *newsig;
+             PACKET *newpkt;
+
+             if ((mainkey && main_pk->version < 4)
+                 || (!mainkey && sub_pk->version < 4))
+               {
+                  /* Note: This won't happen because we don't support
+                   * v3 keys anymore.  */
+                 log_info ("You can't change the capabilities of a v3 key\n");
+                 return 0;
+               }
+
+              if (mainkey)
+                main_pk->pubkey_usage = ask_key_flags (main_pk->pubkey_algo, 0,
+                                                       main_pk->pubkey_usage);
+              else
+                sub_pk->pubkey_usage  = ask_key_flags (sub_pk->pubkey_algo, 1,
+                                                       sub_pk->pubkey_usage);
+
+             if (mainkey)
+               rc = update_keysig_packet (ctrl,
+                                           &newsig, sig, main_pk, uid, NULL,
+                                          main_pk, keygen_add_key_flags,
+                                          main_pk);
+             else
+               rc =
+                 update_keysig_packet (ctrl,
+                                        &newsig, sig, main_pk, NULL, sub_pk,
+                                       main_pk, keygen_add_key_flags, sub_pk);
+             if (rc)
+               {
+                 log_error ("make_keysig_packet failed: %s\n",
+                             gpg_strerror (rc));
+                 return 0;
+               }
+
+             /* Replace the packet.  */
+             newpkt = xmalloc_clear (sizeof *newpkt);
+             newpkt->pkttype = PKT_SIGNATURE;
+             newpkt->pkt.signature = newsig;
+             free_packet (node->pkt, NULL);
+             xfree (node->pkt);
+             node->pkt = newpkt;
+             sub_pk = NULL;
+              break;
+           }
+       }
+    }
+
   return 1;
 }
 
 
 static int
-menu_backsign (KBNODE pub_keyblock)
+menu_backsign (ctrl_t ctrl, kbnode_t pub_keyblock)
 {
   int rc, modified = 0;
   PKT_public_key *main_pk;
   KBNODE node;
   u32 timestamp;
 
-  assert (pub_keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
+  log_assert (pub_keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
 
-  merge_keys_and_selfsig (pub_keyblock);
+  merge_keys_and_selfsig (ctrl, pub_keyblock);
   main_pk = pub_keyblock->pkt->pkt.public_key;
   keyid_from_pk (main_pk, NULL);
 
@@ -4131,14 +4723,16 @@ menu_backsign (KBNODE pub_keyblock)
 
       /* Now we can get to work.  */
 
-      rc = make_backsig (sig_pk->pkt->pkt.signature, main_pk, sub_pk, sub_pk,
+      rc = make_backsig (ctrl,
+                         sig_pk->pkt->pkt.signature, main_pk, sub_pk, sub_pk,
                         timestamp, NULL);
       if (!rc)
        {
          PKT_signature *newsig;
          PACKET *newpkt;
 
-         rc = update_keysig_packet (&newsig, sig_pk->pkt->pkt.signature,
+         rc = update_keysig_packet (ctrl,
+                                     &newsig, sig_pk->pkt->pkt.signature,
                                      main_pk, NULL, sub_pk, main_pk,
                                      NULL, NULL);
          if (!rc)
@@ -4147,7 +4741,7 @@ menu_backsign (KBNODE pub_keyblock)
              newpkt = xmalloc_clear (sizeof (*newpkt));
              newpkt->pkttype = PKT_SIGNATURE;
              newpkt->pkt.signature = newsig;
-             free_packet (sig_pk->pkt);
+             free_packet (sig_pk->pkt, NULL);
              xfree (sig_pk->pkt);
              sig_pk->pkt = newpkt;
 
@@ -4194,14 +4788,14 @@ change_primary_uid_cb (PKT_signature * sig, void *opaque)
 
 /*
  * Set the primary uid flag for the selected UID.  We will also reset
- * all other primary uid flags.  For this to work with have to update
+ * all other primary uid flags.  For this to work we have to update
  * all the signature timestamps.  If we would do this with the current
- * time, we lose quite a lot of information, so we use a kludge to
+ * time, we lose quite a lot of information, so we use a kludge to
  * do this: Just increment the timestamp by one second which is
  * sufficient to updated a signature during import.
  */
 static int
-menu_set_primary_uid (KBNODE pub_keyblock)
+menu_set_primary_uid (ctrl_t ctrl, kbnode_t pub_keyblock)
 {
   PKT_public_key *main_pk;
   PKT_user_id *uid;
@@ -4290,7 +4884,7 @@ menu_set_primary_uid (KBNODE pub_keyblock)
 
                  if (action)
                    {
-                     int rc = update_keysig_packet (&newsig, sig,
+                     int rc = update_keysig_packet (ctrl, &newsig, sig,
                                                     main_pk, uid, NULL,
                                                     main_pk,
                                                     change_primary_uid_cb,
@@ -4305,7 +4899,7 @@ menu_set_primary_uid (KBNODE pub_keyblock)
                      newpkt = xmalloc_clear (sizeof *newpkt);
                      newpkt->pkttype = PKT_SIGNATURE;
                      newpkt->pkt.signature = newsig;
-                     free_packet (node->pkt);
+                     free_packet (node->pkt, NULL);
                      xfree (node->pkt);
                      node->pkt = newpkt;
                      modified = 1;
@@ -4323,7 +4917,7 @@ menu_set_primary_uid (KBNODE pub_keyblock)
  * Set preferences to new values for the selected user IDs
  */
 static int
-menu_set_preferences (KBNODE pub_keyblock)
+menu_set_preferences (ctrl_t ctrl, kbnode_t pub_keyblock)
 {
   PKT_public_key *main_pk;
   PKT_user_id *uid;
@@ -4381,7 +4975,7 @@ menu_set_preferences (KBNODE pub_keyblock)
                  PACKET *newpkt;
                  int rc;
 
-                 rc = update_keysig_packet (&newsig, sig,
+                 rc = update_keysig_packet (ctrl, &newsig, sig,
                                             main_pk, uid, NULL, main_pk,
                                              keygen_upd_std_prefs, NULL);
                  if (rc)
@@ -4394,7 +4988,7 @@ menu_set_preferences (KBNODE pub_keyblock)
                  newpkt = xmalloc_clear (sizeof *newpkt);
                  newpkt->pkttype = PKT_SIGNATURE;
                  newpkt->pkt.signature = newsig;
-                 free_packet (node->pkt);
+                 free_packet (node->pkt, NULL);
                  xfree (node->pkt);
                  node->pkt = newpkt;
                  modified = 1;
@@ -4408,7 +5002,7 @@ menu_set_preferences (KBNODE pub_keyblock)
 
 
 static int
-menu_set_keyserver_url (const char *url, KBNODE pub_keyblock)
+menu_set_keyserver_url (ctrl_t ctrl, const char *url, kbnode_t pub_keyblock)
 {
   PKT_public_key *main_pk;
   PKT_user_id *uid;
@@ -4515,7 +5109,7 @@ menu_set_keyserver_url (const char *url, KBNODE pub_keyblock)
                      continue;
                    }
 
-                 rc = update_keysig_packet (&newsig, sig,
+                 rc = update_keysig_packet (ctrl, &newsig, sig,
                                             main_pk, uid, NULL,
                                             main_pk,
                                             keygen_add_keyserver_url, uri);
@@ -4530,7 +5124,7 @@ menu_set_keyserver_url (const char *url, KBNODE pub_keyblock)
                  newpkt = xmalloc_clear (sizeof *newpkt);
                  newpkt->pkttype = PKT_SIGNATURE;
                  newpkt->pkt.signature = newsig;
-                 free_packet (node->pkt);
+                 free_packet (node->pkt, NULL);
                  xfree (node->pkt);
                  node->pkt = newpkt;
                  modified = 1;
@@ -4545,8 +5139,9 @@ menu_set_keyserver_url (const char *url, KBNODE pub_keyblock)
   return modified;
 }
 
+
 static int
-menu_set_notation (const char *string, KBNODE pub_keyblock)
+menu_set_notation (ctrl_t ctrl, const char *string, KBNODE pub_keyblock)
 {
   PKT_public_key *main_pk;
   PKT_user_id *uid;
@@ -4714,7 +5309,7 @@ menu_set_notation (const char *string, KBNODE pub_keyblock)
                                                  _("Proceed? (y/N) "))))
                    continue;
 
-                 rc = update_keysig_packet (&newsig, sig,
+                 rc = update_keysig_packet (ctrl, &newsig, sig,
                                             main_pk, uid, NULL,
                                             main_pk,
                                             keygen_add_notations, notation);
@@ -4731,7 +5326,7 @@ menu_set_notation (const char *string, KBNODE pub_keyblock)
                  newpkt = xmalloc_clear (sizeof *newpkt);
                  newpkt->pkttype = PKT_SIGNATURE;
                  newpkt->pkt.signature = newsig;
-                 free_packet (node->pkt);
+                 free_packet (node->pkt, NULL);
                  xfree (node->pkt);
                  node->pkt = newpkt;
                  modified = 1;
@@ -4818,7 +5413,7 @@ menu_select_uid_namehash (KBNODE keyblock, const char *namehash)
   KBNODE node;
   int i;
 
-  assert (strlen (namehash) == NAMEHASH_LEN * 2);
+  log_assert (strlen (namehash) == NAMEHASH_LEN * 2);
 
   for (i = 0; i < NAMEHASH_LEN; i++)
     hash[i] = hextobyte (&namehash[i * 2]);
@@ -4856,10 +5451,97 @@ menu_select_uid_namehash (KBNODE keyblock, const char *namehash)
  * Returns: True if the selection changed.
  */
 static int
-menu_select_key (KBNODE keyblock, int idx)
+menu_select_key (KBNODE keyblock, int idx, char *p)
 {
   KBNODE node;
-  int i;
+  int i, j;
+  int is_hex_digits;
+
+  is_hex_digits = p && strlen (p) >= 8;
+  if (is_hex_digits)
+    {
+      /* Skip initial spaces.  */
+      while (spacep (p))
+        p ++;
+      /* If the id starts with 0x accept and ignore it.  */
+      if (p[0] == '0' && p[1] == 'x')
+        p += 2;
+
+      for (i = 0, j = 0; p[i]; i ++)
+        if (hexdigitp (&p[i]))
+          {
+            p[j] = toupper (p[i]);
+            j ++;
+          }
+        else if (spacep (&p[i]))
+          /* Skip spaces.  */
+          {
+          }
+        else
+          {
+            is_hex_digits = 0;
+            break;
+          }
+      if (is_hex_digits)
+        /* In case we skipped some spaces, add a new NUL terminator.  */
+        {
+          p[j] = 0;
+          /* If we skipped some spaces, make sure that we still have
+             at least 8 characters.  */
+          is_hex_digits = (/* Short keyid.  */
+                           strlen (p) == 8
+                           /* Long keyid.  */
+                           || strlen (p) == 16
+                           /* Fingerprints are (currently) 32 or 40
+                              characters.  */
+                           || strlen (p) >= 32);
+        }
+    }
+
+  if (is_hex_digits)
+    {
+      int found_one = 0;
+      for (node = keyblock; node; node = node->next)
+       if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
+           || node->pkt->pkttype == PKT_SECRET_SUBKEY)
+          {
+            int match = 0;
+            if (strlen (p) == 8 || strlen (p) == 16)
+              {
+                u32 kid[2];
+                char kid_str[17];
+                keyid_from_pk (node->pkt->pkt.public_key, kid);
+                format_keyid (kid, strlen (p) == 8 ? KF_SHORT : KF_LONG,
+                              kid_str, sizeof (kid_str));
+
+                if (strcmp (p, kid_str) == 0)
+                  match = 1;
+              }
+            else
+              {
+                char fp[2*MAX_FINGERPRINT_LEN + 1];
+                hexfingerprint (node->pkt->pkt.public_key, fp, sizeof (fp));
+                if (strcmp (fp, p) == 0)
+                  match = 1;
+              }
+
+            if (match)
+              {
+                if ((node->flag & NODFLG_SELKEY))
+                  node->flag &= ~NODFLG_SELKEY;
+                else
+                  node->flag |= NODFLG_SELKEY;
+
+                found_one = 1;
+              }
+          }
+
+      if (found_one)
+        return 1;
+
+      tty_printf (_("No subkey with key ID '%s'.\n"), p);
+      return 0;
+    }
 
   if (idx == -1)               /* Select all.  */
     {
@@ -4986,7 +5668,7 @@ real_uids_left (KBNODE keyblock)
  * flag bit MARK_A is set on the signature and the user ID.
  */
 static void
-ask_revoke_sig (KBNODE keyblock, KBNODE node)
+ask_revoke_sig (ctrl_t ctrl, kbnode_t keyblock, kbnode_t node)
 {
   int doit = 0;
   PKT_user_id *uid;
@@ -5013,8 +5695,8 @@ ask_revoke_sig (KBNODE keyblock, KBNODE node)
 
       es_printf ("\n");
 
-      print_and_check_one_sig_colon (keyblock, node, NULL, NULL, NULL, NULL,
-                                    1);
+      print_and_check_one_sig_colon (ctrl, keyblock, node,
+                                     NULL, NULL, NULL, NULL, 1);
     }
   else
     {
@@ -5056,7 +5738,7 @@ ask_revoke_sig (KBNODE keyblock, KBNODE node)
  * Return: True when the keyblock has changed.
  */
 static int
-menu_revsig (KBNODE keyblock)
+menu_revsig (ctrl_t ctrl, kbnode_t keyblock)
 {
   PKT_signature *sig;
   PKT_public_key *primary_pk;
@@ -5065,7 +5747,7 @@ menu_revsig (KBNODE keyblock)
   int rc, any, skip = 1, all = !count_selected_uids (keyblock);
   struct revocation_reason_info *reason = NULL;
 
-  assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
+  log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
 
   /* First check whether we have any signatures at all.  */
   any = 0;
@@ -5148,7 +5830,7 @@ menu_revsig (KBNODE keyblock)
     {
       if (!(node->flag & NODFLG_SELSIG))
        continue;
-      ask_revoke_sig (keyblock, node);
+      ask_revoke_sig (ctrl, keyblock, node);
     }
 
   /* present selected */
@@ -5193,7 +5875,7 @@ menu_revsig (KBNODE keyblock)
     }
 
   /* now we can sign the user ids */
-reloop:                        /* (must use this, because we are modifing the list) */
+reloop:                        /* (must use this, because we are modifying the list) */
   primary_pk = keyblock->pkt->pkt.public_key;
   for (node = keyblock; node; node = node->next)
     {
@@ -5206,7 +5888,7 @@ reloop:                   /* (must use this, because we are modifing the list) */
          || node->pkt->pkttype != PKT_SIGNATURE)
        continue;
       unode = find_prev_kbnode (keyblock, node, PKT_USER_ID);
-      assert (unode);          /* we already checked this */
+      log_assert (unode); /* we already checked this */
 
       memset (&attrib, 0, sizeof attrib);
       attrib.reason = reason;
@@ -5214,13 +5896,13 @@ reloop:                 /* (must use this, because we are modifing the list) */
 
       node->flag &= ~NODFLG_MARK_A;
       signerkey = xmalloc_secure_clear (sizeof *signerkey);
-      if (get_seckey (signerkey, node->pkt->pkt.signature->keyid))
+      if (get_seckey (ctrl, signerkey, node->pkt->pkt.signature->keyid))
        {
          log_info (_("no secret key\n"));
           free_public_key (signerkey);
          continue;
        }
-      rc = make_keysig_packet (&sig, primary_pk,
+      rc = make_keysig_packet (ctrl, &sig, primary_pk,
                               unode->pkt->pkt.user_id,
                               NULL, signerkey, 0x30, 0, 0, 0,
                                sign_mk_attrib, &attrib, NULL);
@@ -5237,7 +5919,7 @@ reloop:                   /* (must use this, because we are modifing the list) */
       /* Are we revoking our own uid? */
       if (primary_pk->keyid[0] == sig->keyid[0] &&
          primary_pk->keyid[1] == sig->keyid[1])
-       unode->pkt->pkt.user_id->is_revoked = 1;
+       unode->pkt->pkt.user_id->flags.revoked = 1;
       pkt = xmalloc_clear (sizeof *pkt);
       pkt->pkttype = PKT_SIGNATURE;
       pkt->pkt.signature = sig;
@@ -5250,16 +5932,107 @@ reloop:                        /* (must use this, because we are modifing the list) */
 }
 
 
+/* return 0 if revocation of NODE (which must be a User ID) was
+   successful, non-zero if there was an error.  *modified will be set
+   to 1 if a change was made. */
+static int
+core_revuid (ctrl_t ctrl, kbnode_t keyblock, KBNODE node,
+             const struct revocation_reason_info *reason, int *modified)
+{
+  PKT_public_key *pk = keyblock->pkt->pkt.public_key;
+  gpg_error_t rc;
+
+  if (node->pkt->pkttype != PKT_USER_ID)
+    {
+      rc = gpg_error (GPG_ERR_NO_USER_ID);
+      write_status_error ("keysig", rc);
+      log_error (_("tried to revoke a non-user ID: %s\n"), gpg_strerror (rc));
+      return 1;
+    }
+  else
+    {
+      PKT_user_id *uid = node->pkt->pkt.user_id;
+
+      if (uid->flags.revoked)
+        {
+          char *user = utf8_to_native (uid->name, uid->len, 0);
+          log_info (_("user ID \"%s\" is already revoked\n"), user);
+          xfree (user);
+        }
+      else
+        {
+          PACKET *pkt;
+          PKT_signature *sig;
+          struct sign_attrib attrib;
+          u32 timestamp = make_timestamp ();
+
+          if (uid->created >= timestamp)
+            {
+              /* Okay, this is a problem.  The user ID selfsig was
+                 created in the future, so we need to warn the user and
+                 set our revocation timestamp one second after that so
+                 everything comes out clean. */
+
+              log_info (_("WARNING: a user ID signature is dated %d"
+                          " seconds in the future\n"),
+                        uid->created - timestamp);
+
+              timestamp = uid->created + 1;
+            }
+
+          memset (&attrib, 0, sizeof attrib);
+          /* should not need to cast away const here; but
+             revocation_reason_build_cb needs to take a non-const
+             void* in order to meet the function signtuare for the
+             mksubpkt argument to make_keysig_packet */
+          attrib.reason = (struct revocation_reason_info *)reason;
+
+          rc = make_keysig_packet (ctrl, &sig, pk, uid, NULL, pk, 0x30, 0,
+                                   timestamp, 0,
+                                   sign_mk_attrib, &attrib, NULL);
+          if (rc)
+            {
+              write_status_error ("keysig", rc);
+              log_error (_("signing failed: %s\n"), gpg_strerror (rc));
+              return 1;
+            }
+          else
+            {
+              pkt = xmalloc_clear (sizeof *pkt);
+              pkt->pkttype = PKT_SIGNATURE;
+              pkt->pkt.signature = sig;
+              insert_kbnode (node, new_kbnode (pkt), 0);
+
+#ifndef NO_TRUST_MODELS
+              /* If the trustdb has an entry for this key+uid then the
+                 trustdb needs an update. */
+              if (!update_trust
+                  && ((get_validity (ctrl, keyblock, pk, uid, NULL, 0)
+                       & TRUST_MASK)
+                      >= TRUST_UNDEFINED))
+                update_trust = 1;
+#endif /*!NO_TRUST_MODELS*/
+
+              node->pkt->pkt.user_id->flags.revoked = 1;
+              if (modified)
+                *modified = 1;
+            }
+        }
+      return 0;
+    }
+}
+
 /* Revoke a user ID (i.e. revoke a user ID selfsig).  Return true if
    keyblock changed.  */
 static int
-menu_revuid (KBNODE pub_keyblock)
+menu_revuid (ctrl_t ctrl, kbnode_t pub_keyblock)
 {
   PKT_public_key *pk = pub_keyblock->pkt->pkt.public_key;
   KBNODE node;
   int changed = 0;
   int rc;
   struct revocation_reason_info *reason = NULL;
+  size_t valid_uids;
 
   /* Note that this is correct as per the RFCs, but nevertheless
      somewhat meaningless in the real world.  1991 did define the 0x30
@@ -5276,75 +6049,39 @@ menu_revuid (KBNODE pub_keyblock)
          goto leave;
       }
 
- reloop: /* (better this way because we are modifing the keyring) */
+  /* Too make sure that we do not revoke the last valid UID, we first
+     count how many valid UIDs there are.  */
+  valid_uids = 0;
+  for (node = pub_keyblock; node; node = node->next)
+    valid_uids +=
+      node->pkt->pkttype == PKT_USER_ID
+      && ! node->pkt->pkt.user_id->flags.revoked
+      && ! node->pkt->pkt.user_id->flags.expired;
+
+ reloop: /* (better this way because we are modifying the keyring) */
   for (node = pub_keyblock; node; node = node->next)
     if (node->pkt->pkttype == PKT_USER_ID && (node->flag & NODFLG_SELUID))
       {
-       PKT_user_id *uid = node->pkt->pkt.user_id;
-
-       if (uid->is_revoked)
-         {
-           char *user = utf8_to_native (uid->name, uid->len, 0);
-           log_info (_("user ID \"%s\" is already revoked\n"), user);
-           xfree (user);
-         }
-       else
-         {
-           PACKET *pkt;
-           PKT_signature *sig;
-           struct sign_attrib attrib;
-           u32 timestamp = make_timestamp ();
+        int modified = 0;
 
-           if (uid->created >= timestamp)
-             {
-               /* Okay, this is a problem.  The user ID selfsig was
-                  created in the future, so we need to warn the user and
-                  set our revocation timestamp one second after that so
-                  everything comes out clean. */
-
-               log_info (_("WARNING: a user ID signature is dated %d"
-                           " seconds in the future\n"),
-                         uid->created - timestamp);
-
-               timestamp = uid->created + 1;
-             }
-
-           memset (&attrib, 0, sizeof attrib);
-           attrib.reason = reason;
+        /* Make sure that we do not revoke the last valid UID.  */
+        if (valid_uids == 1
+            && ! node->pkt->pkt.user_id->flags.revoked
+            && ! node->pkt->pkt.user_id->flags.expired)
+          {
+            log_error (_("Cannot revoke the last valid user ID.\n"));
+            goto leave;
+          }
 
+        rc = core_revuid (ctrl, pub_keyblock, node, reason, &modified);
+        if (rc)
+          goto leave;
+        if (modified)
+          {
            node->flag &= ~NODFLG_SELUID;
-
-           rc = make_keysig_packet (&sig, pk, uid, NULL, pk, 0x30, 0,
-                                    timestamp, 0,
-                                    sign_mk_attrib, &attrib, NULL);
-           if (rc)
-             {
-                write_status_error ("keysig", rc);
-               log_error (_("signing failed: %s\n"), gpg_strerror (rc));
-               goto leave;
-             }
-           else
-             {
-               pkt = xmalloc_clear (sizeof *pkt);
-               pkt->pkttype = PKT_SIGNATURE;
-               pkt->pkt.signature = sig;
-               insert_kbnode (node, new_kbnode (pkt), 0);
-
-#ifndef NO_TRUST_MODELS
-               /* If the trustdb has an entry for this key+uid then the
-                  trustdb needs an update. */
-               if (!update_trust
-                   && (get_validity (pk, uid) & TRUST_MASK) >=
-                   TRUST_UNDEFINED)
-                 update_trust = 1;
-#endif /*!NO_TRUST_MODELS*/
-
-               changed = 1;
-               node->pkt->pkt.user_id->is_revoked = 1;
-
-               goto reloop;
-             }
-         }
+            changed = 1;
+            goto reloop;
+          }
       }
 
   if (changed)
@@ -5360,7 +6097,7 @@ leave:
  * Revoke the whole key.
  */
 static int
-menu_revkey (KBNODE pub_keyblock)
+menu_revkey (ctrl_t ctrl, kbnode_t pub_keyblock)
 {
   PKT_public_key *pk = pub_keyblock->pkt->pkt.public_key;
   int rc, changed = 0;
@@ -5379,7 +6116,7 @@ menu_revkey (KBNODE pub_keyblock)
   if (!reason)
     return 0;
 
-  rc = make_keysig_packet (&sig, pk, NULL, NULL, pk,
+  rc = make_keysig_packet (ctrl, &sig, pk, NULL, NULL, pk,
                           0x20, 0, 0, 0,
                           revocation_reason_build_cb, reason, NULL);
   if (rc)
@@ -5406,7 +6143,7 @@ menu_revkey (KBNODE pub_keyblock)
 
 
 static int
-menu_revsubkey (KBNODE pub_keyblock)
+menu_revsubkey (ctrl_t ctrl, kbnode_t pub_keyblock)
 {
   PKT_public_key *mainpk;
   KBNODE node;
@@ -5418,7 +6155,7 @@ menu_revsubkey (KBNODE pub_keyblock)
   if (!reason)
       return 0; /* User decided to cancel.  */
 
- reloop: /* (better this way because we are modifing the keyring) */
+ reloop: /* (better this way because we are modifying the keyring) */
   mainpk = pub_keyblock->pkt->pkt.public_key;
   for (node = pub_keyblock; node; node = node->next)
     {
@@ -5441,7 +6178,7 @@ menu_revsubkey (KBNODE pub_keyblock)
          attrib.reason = reason;
 
          node->flag &= ~NODFLG_SELKEY;
-         rc = make_keysig_packet (&sig, mainpk, NULL, subpk, mainpk,
+         rc = make_keysig_packet (ctrl, &sig, mainpk, NULL, subpk, mainpk,
                                   0x28, 0, 0, 0, sign_mk_attrib, &attrib,
                                    NULL);
          if (rc)
@@ -5477,26 +6214,26 @@ menu_revsubkey (KBNODE pub_keyblock)
    not worth adding extra complexity to change. -ds */
 #ifndef NO_TRUST_MODELS
 static int
-enable_disable_key (KBNODE keyblock, int disable)
+enable_disable_key (ctrl_t ctrl, kbnode_t keyblock, int disable)
 {
   PKT_public_key *pk =
     find_kbnode (keyblock, PKT_PUBLIC_KEY)->pkt->pkt.public_key;
   unsigned int trust, newtrust;
 
-  trust = newtrust = get_ownertrust (pk);
+  trust = newtrust = get_ownertrust (ctrl, pk);
   newtrust &= ~TRUST_FLAG_DISABLED;
   if (disable)
     newtrust |= TRUST_FLAG_DISABLED;
   if (trust == newtrust)
     return 0;                  /* already in that state */
-  update_ownertrust (pk, newtrust);
+  update_ownertrust (ctrl, pk, newtrust);
   return 0;
 }
 #endif /*!NO_TRUST_MODELS*/
 
 
 static void
-menu_showphoto (KBNODE keyblock)
+menu_showphoto (ctrl_t ctrl, kbnode_t keyblock)
 {
   KBNODE node;
   int select_all = !count_selected_uids (keyblock);
@@ -5533,7 +6270,7 @@ menu_showphoto (KBNODE keyblock)
                                    "key %s (uid %d)\n"),
                                  image_type_to_string (type, 1),
                                  (ulong) size, keystr_from_pk (pk), count);
-                     show_photos (&uid->attribs[i], 1, pk, uid);
+                     show_photos (ctrl, &uid->attribs[i], 1, pk, uid);
                    }
                }
            }