gpg: Add debug helper to --edit-keys's check sub-command.
[gnupg.git] / g10 / keyedit.c
index b7f7ad6..8d87a01 100644 (file)
@@ -1,7 +1,6 @@
-/* keyedit.c - keyedit stuff
- * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
- *               2008, 2009, 2010 Free Software Foundation, Inc.
- * Copyright (C) 2013, 2014 Werner Koch
+/* keyedit.c - Edit properties of a key
+ * Copyright (C) 1998-2010 Free Software Foundation, Inc.
+ * Copyright (C) 1998-2015 Werner Koch
  *
  * This file is part of GnuPG.
  *
@@ -31,7 +30,6 @@
 # include <readline/readline.h>
 #endif
 
-#define JNLIB_NEED_LOG_LOGV
 #include "gpg.h"
 #include "options.h"
 #include "packet.h"
@@ -53,12 +51,16 @@ 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,
                        unsigned int flag, int with_prefs);
-static void show_key_with_all_names (estream_t fp,
+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);
-static void show_key_and_fingerprint (KBNODE keyblock);
-static int menu_adduid (KBNODE keyblock, int photo, const char *photo_name);
+                                    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_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 void menu_deluid (KBNODE pub_keyblock);
 static int menu_delsig (KBNODE pub_keyblock);
 static int menu_clean (KBNODE keyblock, int self_only);
@@ -126,20 +128,21 @@ 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 */
 
-  switch ((rc = check_key_signature (keyblock, node, is_selfsig)))
+  rc = check_key_signature (keyblock, node, is_selfsig);
+  switch (gpg_err_code (rc))
     {
     case 0:
       node->flag &= ~(NODFLG_BADSIG | NODFLG_NOKEY | NODFLG_SIGERR);
       sigrc = '!';
       break;
-    case G10ERR_BAD_SIGN:
+    case GPG_ERR_BAD_SIGNATURE:
       node->flag = NODFLG_BADSIG;
       sigrc = '-';
       if (inv_sigs)
        ++ * inv_sigs;
       break;
-    case G10ERR_NO_PUBKEY:
-    case G10ERR_UNU_PUBKEY:
+    case GPG_ERR_NO_PUBKEY:
+    case GPG_ERR_UNUSABLE_PUBKEY:
       node->flag = NODFLG_NOKEY;
       sigrc = '?';
       if (no_key)
@@ -155,23 +158,23 @@ print_and_check_one_sig_colon (KBNODE keyblock, KBNODE node,
 
   if (sigrc != '?' || print_without_key)
     {
-      printf ("sig:%c::%d:%08lX%08lX:%lu:%lu:",
-             sigrc, sig->pubkey_algo, (ulong) sig->keyid[0],
-             (ulong) sig->keyid[1], (ulong) sig->timestamp,
-             (ulong) sig->expiredate);
+      es_printf ("sig:%c::%d:%08lX%08lX:%lu:%lu:",
+                 sigrc, sig->pubkey_algo, (ulong) sig->keyid[0],
+                 (ulong) sig->keyid[1], (ulong) sig->timestamp,
+                 (ulong) sig->expiredate);
 
       if (sig->trust_depth || sig->trust_value)
-       printf ("%d %d", sig->trust_depth, sig->trust_value);
+       es_printf ("%d %d", sig->trust_depth, sig->trust_value);
 
-      printf (":");
+      es_printf (":");
 
       if (sig->trust_regexp)
        es_write_sanitized (es_stdout,
                            sig->trust_regexp, strlen (sig->trust_regexp),
                            ":", NULL);
 
-      printf ("::%02x%c\n", sig->sig_class,
-             sig->flags.exportable ? 'x' : 'l');
+      es_printf ("::%02x%c\n", sig->sig_class,
+                 sig->flags.exportable ? 'x' : 'l');
 
       if (opt.show_subpackets)
        print_subpackets_colon (sig);
@@ -182,13 +185,15 @@ 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.
+ * 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.
  */
 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 *is_selfsig, int print_without_key, int extended)
 {
   PKT_signature *sig = node->pkt->pkt.signature;
   int rc, sigrc;
@@ -197,20 +202,21 @@ print_and_check_one_sig (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 */
 
-  switch ((rc = check_key_signature (keyblock, node, is_selfsig)))
+  rc = check_key_signature (keyblock, node, is_selfsig);
+  switch (gpg_err_code (rc))
     {
     case 0:
       node->flag &= ~(NODFLG_BADSIG | NODFLG_NOKEY | NODFLG_SIGERR);
       sigrc = '!';
       break;
-    case G10ERR_BAD_SIGN:
+    case GPG_ERR_BAD_SIGNATURE:
       node->flag = NODFLG_BADSIG;
       sigrc = '-';
       if (inv_sigs)
        ++ * inv_sigs;
       break;
-    case G10ERR_NO_PUBKEY:
-    case G10ERR_UNU_PUBKEY:
+    case GPG_ERR_NO_PUBKEY:
+    case GPG_ERR_UNUSABLE_PUBKEY:
       node->flag = NODFLG_NOKEY;
       sigrc = '?';
       if (no_key)
@@ -237,18 +243,21 @@ print_and_check_one_sig (KBNODE keyblock, KBNODE node,
                  sig->flags.expired ? 'X' : ' ',
                  (sig->trust_depth > 9) ? 'T' : (sig->trust_depth >
                                                  0) ? '0' +
-                 sig->trust_depth : ' ', keystr (sig->keyid),
+                 sig->trust_depth : ' ',
+                  keystr (sig->keyid),
                  datestr_from_sig (sig));
-      if (opt.list_options & LIST_SHOW_SIG_EXPIRE)
+      if ((opt.list_options & LIST_SHOW_SIG_EXPIRE) || extended )
        tty_printf (" %s", expirestr_from_sig (sig));
       tty_printf ("  ");
       if (sigrc == '%')
-       tty_printf ("[%s] ", g10_errstr (rc));
+       tty_printf ("[%s] ", gpg_strerror (rc));
       else if (sigrc == '?')
        ;
       else if (*is_selfsig)
        {
          tty_printf (is_rev ? _("[revocation]") : _("[self-signature]"));
+          if (extended && sig->flags.chosen_selfsig)
+            tty_printf ("*");
        }
       else
        {
@@ -263,17 +272,20 @@ print_and_check_one_sig (KBNODE keyblock, KBNODE node,
        }
       tty_printf ("\n");
 
-      if (sig->flags.policy_url && (opt.list_options & LIST_SHOW_POLICY_URLS))
+      if (sig->flags.policy_url
+          && ((opt.list_options & LIST_SHOW_POLICY_URLS) || extended))
        show_policy_url (sig, 3, 0);
 
-      if (sig->flags.notation && (opt.list_options & LIST_SHOW_NOTATIONS))
+      if (sig->flags.notation
+          && ((opt.list_options & LIST_SHOW_NOTATIONS) || extended))
        show_notation (sig, 3, 0,
                       ((opt.
                         list_options & LIST_SHOW_STD_NOTATIONS) ? 1 : 0) +
                       ((opt.
                         list_options & LIST_SHOW_USER_NOTATIONS) ? 2 : 0));
 
-      if (sig->flags.pref_ks && (opt.list_options & LIST_SHOW_KEYSERVER_URLS))
+      if (sig->flags.pref_ks
+          && ((opt.list_options & LIST_SHOW_KEYSERVER_URLS) || extended))
        show_keyserver_url (sig, 3, 0);
     }
 
@@ -287,7 +299,7 @@ print_and_check_one_sig (KBNODE keyblock, KBNODE node,
  * Returns true if error found.
  */
 static int
-check_all_keysigs (KBNODE keyblock, int only_selected)
+check_all_keysigs (KBNODE keyblock, int only_selected, int only_selfsigs)
 {
   KBNODE kbctx;
   KBNODE node;
@@ -298,10 +310,16 @@ check_all_keysigs (KBNODE keyblock, int only_selected)
   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_USER_ID)
+      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;
 
@@ -323,9 +341,14 @@ check_all_keysigs (KBNODE keyblock, int only_selected)
                   || node->pkt->pkt.signature->sig_class == 0x30))
        {
          int selfsig;
-
-         if (print_and_check_one_sig (keyblock, node, &inv_sigs,
-                                      &no_key, &oth_err, &selfsig, 0))
+          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;
@@ -499,13 +522,16 @@ trustsig_prompt (byte * trust_value, byte * trust_depth, char **regexp)
 
 
 /*
- * Loop over all LOCUSR and and sign the uids after asking.
- * If no user id is marked, all user ids will be signed;
- * if some user_ids are marked those will be signed.
+ * Loop over all LOCUSR and 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.
  */
 static int
-sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified,
-          int local, int nonrevocable, int trust, int interactive)
+sign_uids (ctrl_t ctrl, estream_t fp,
+           kbnode_t keyblock, strlist_t locusr, int *ret_modified,
+          int local, int nonrevocable, int trust, int interactive,
+           int quick)
 {
   int rc = 0;
   SK_LIST sk_list = NULL;
@@ -514,17 +540,6 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified,
   KBNODE node, uidnode;
   PKT_public_key *primary_pk = NULL;
   int select_all = !count_selected_uids (keyblock) || interactive;
-  int all_v3 = 1;
-
-  /* Are there any non-v3 sigs on this key already? */
-  if (PGP2)
-    for (node = keyblock; node; node = node->next)
-      if (node->pkt->pkttype == PKT_SIGNATURE &&
-         node->pkt->pkt.signature->version > 3)
-       {
-         all_v3 = 0;
-         break;
-       }
 
   /* Build a list of all signators.
    *
@@ -542,14 +557,10 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified,
     {
       u32 sk_keyid[2], pk_keyid[2];
       char *p, *trust_regexp = NULL;
-      int force_v4 = 0, class = 0, selfsig = 0;
+      int class = 0, selfsig = 0;
       u32 duration = 0, timestamp = 0;
       byte trust_depth = 0, trust_value = 0;
 
-      if (local || nonrevocable || trust
-          || opt.cert_policy_url || opt.cert_notations)
-       force_v4 = 1;
-
       pk = sk_rover->pk;
       keyid_from_pk (pk, sk_keyid);
 
@@ -573,14 +584,7 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified,
 
              /* Is this a self-sig? */
              if (pk_keyid[0] == sk_keyid[0] && pk_keyid[1] == sk_keyid[1])
-               {
-                 selfsig = 1;
-                 /* Do not force a v4 sig here, otherwise it would
-                    be difficult to remake a v3 selfsig.  If this
-                    is a v3->v4 promotion case, then we set
-                    force_v4 later anyway. */
-                 force_v4 = 0;
-               }
+                selfsig = 1;
            }
          else if (node->pkt->pkttype == PKT_USER_ID)
            {
@@ -595,13 +599,13 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified,
 
                  if (uidnode->pkt->pkt.user_id->is_revoked)
                    {
-                     tty_printf (_("User ID \"%s\" is revoked."), user);
+                     tty_fprintf (fp, _("User ID \"%s\" is revoked."), user);
 
                      if (selfsig)
-                       tty_printf ("\n");
-                     else if (opt.expert)
+                       tty_fprintf (fp, "\n");
+                     else if (opt.expert && !quick)
                        {
-                         tty_printf ("\n");
+                         tty_fprintf (fp, "\n");
                          /* No, so remove the mark and continue */
                          if (!cpr_get_answer_is_yes ("sign_uid.revoke_okay",
                                                      _("Are you sure you "
@@ -618,18 +622,18 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified,
                        {
                          uidnode->flag &= ~NODFLG_MARK_A;
                          uidnode = NULL;
-                         tty_printf (_("  Unable to sign.\n"));
+                         tty_fprintf (fp, _("  Unable to sign.\n"));
                        }
                    }
                  else if (uidnode->pkt->pkt.user_id->is_expired)
                    {
-                     tty_printf (_("User ID \"%s\" is expired."), user);
+                     tty_fprintf (fp, _("User ID \"%s\" is expired."), user);
 
                      if (selfsig)
-                       tty_printf ("\n");
-                     else if (opt.expert)
+                       tty_fprintf (fp, "\n");
+                     else if (opt.expert && !quick)
                        {
-                         tty_printf ("\n");
+                         tty_fprintf (fp, "\n");
                          /* No, so remove the mark and continue */
                          if (!cpr_get_answer_is_yes ("sign_uid.expire_okay",
                                                      _("Are you sure you "
@@ -646,17 +650,17 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified,
                        {
                          uidnode->flag &= ~NODFLG_MARK_A;
                          uidnode = NULL;
-                         tty_printf (_("  Unable to sign.\n"));
+                         tty_fprintf (fp, _("  Unable to sign.\n"));
                        }
                    }
                  else if (!uidnode->pkt->pkt.user_id->created && !selfsig)
                    {
-                     tty_printf (_("User ID \"%s\" is not self-signed."),
-                                 user);
+                     tty_fprintf (fp, _("User ID \"%s\" is not self-signed."),
+                                   user);
 
-                     if (opt.expert)
+                     if (opt.expert && !quick)
                        {
-                         tty_printf ("\n");
+                         tty_fprintf (fp, "\n");
                          /* No, so remove the mark and continue */
                          if (!cpr_get_answer_is_yes ("sign_uid.nosig_okay",
                                                      _("Are you sure you "
@@ -673,13 +677,14 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified,
                        {
                          uidnode->flag &= ~NODFLG_MARK_A;
                          uidnode = NULL;
-                         tty_printf (_("  Unable to sign.\n"));
+                         tty_fprintf (fp, _("  Unable to sign.\n"));
                        }
                    }
 
-                 if (uidnode && interactive && !yesreally)
+                 if (uidnode && interactive && !yesreally && !quick)
                    {
-                     tty_printf (_("User ID \"%s\" is signable.  "), user);
+                     tty_fprintf (fp,
+                                   _("User ID \"%s\" is signable.  "), user);
                      if (!cpr_get_answer_is_yes ("sign_uid.sign_okay",
                                                  _("Sign it? (y/N) ")))
                        {
@@ -704,10 +709,12 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified,
                                          uidnode->pkt->pkt.user_id->len, 0);
 
                  /* It's a v3 self-sig.  Make it into a v4 self-sig? */
-                 if (node->pkt->pkt.signature->version < 4 && selfsig)
+                 if (node->pkt->pkt.signature->version < 4
+                      && selfsig && !quick)
                    {
-                     tty_printf (_("The self-signature on \"%s\"\n"
-                                   "is a PGP 2.x-style signature.\n"), user);
+                     tty_fprintf (fp,
+                                   _("The self-signature on \"%s\"\n"
+                                     "is a PGP 2.x-style signature.\n"), user);
 
                      /* Note that the regular PGP2 warning below
                         still applies if there are no v4 sigs on
@@ -719,7 +726,6 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified,
                                                     "it to an OpenPGP self-"
                                                     "signature? (y/N) ")))
                          {
-                           force_v4 = 1;
                            node->flag |= NODFLG_DELSIG;
                            xfree (user);
                            continue;
@@ -729,10 +735,10 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified,
                  /* Is the current signature expired? */
                  if (node->pkt->pkt.signature->flags.expired)
                    {
-                     tty_printf (_("Your current signature on \"%s\"\n"
-                                   "has expired.\n"), user);
+                     tty_fprintf (fp, _("Your current signature on \"%s\"\n"
+                                         "has expired.\n"), user);
 
-                     if (cpr_get_answer_is_yes
+                     if (quick || cpr_get_answer_is_yes
                          ("sign_uid.replace_expired_okay",
                           _("Do you want to issue a "
                             "new signature to replace "
@@ -755,10 +761,10 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified,
                    {
                      /* It's a local sig, and we want to make a
                         exportable sig. */
-                     tty_printf (_("Your current signature on \"%s\"\n"
-                                   "is a local signature.\n"), user);
+                     tty_fprintf (fp, _("Your current signature on \"%s\"\n"
+                                         "is a local signature.\n"), user);
 
-                     if (cpr_get_answer_is_yes
+                     if (quick || cpr_get_answer_is_yes
                          ("sign_uid.local_promote_okay",
                           _("Do you want to promote "
                             "it to a full exportable " "signature? (y/N) ")))
@@ -779,14 +785,15 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified,
                  /* Fixme: see whether there is a revocation in which
                   * case we should allow to sign it again. */
                  if (!node->pkt->pkt.signature->flags.exportable && local)
-                   tty_printf
-                      (_("\"%s\" was already locally signed by key %s\n"),
+                   tty_fprintf ( fp,
+                       _("\"%s\" was already locally signed by key %s\n"),
                        user, keystr_from_pk (pk));
                  else
-                   tty_printf (_("\"%s\" was already signed by key %s\n"),
+                   tty_fprintf (fp,
+                                _("\"%s\" was already signed by key %s\n"),
                                user, keystr_from_pk (pk));
 
-                 if (opt.expert
+                 if (opt.expert && !quick
                      && cpr_get_answer_is_yes ("sign_uid.dupe_okay",
                                                _("Do you want to sign it "
                                                  "again anyway? (y/N) ")))
@@ -810,15 +817,15 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified,
       /* Check whether any uids are left for signing.  */
       if (!count_uids_with_flag (keyblock, NODFLG_MARK_A))
        {
-         tty_printf (_("Nothing to sign with key %s\n"),
+         tty_fprintf (fp, _("Nothing to sign with key %s\n"),
                      keystr_from_pk (pk));
          continue;
        }
 
       /* Ask whether we really should sign these user id(s). */
-      tty_printf ("\n");
-      show_key_with_all_names (NULL, keyblock, 1, 0, 1, 0, 0);
-      tty_printf ("\n");
+      tty_fprintf (fp, "\n");
+      show_key_with_all_names (ctrl, fp, keyblock, 1, 0, 1, 0, 0, 0);
+      tty_fprintf (fp, "\n");
 
       if (primary_pk->expiredate && !selfsig)
        {
@@ -826,11 +833,11 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified,
 
          if (primary_pk->expiredate <= now)
            {
-             tty_printf (_("This key has expired!"));
+             tty_fprintf (fp, _("This key has expired!"));
 
-             if (opt.expert)
+             if (opt.expert && !quick)
                {
-                 tty_printf ("  ");
+                 tty_fprintf (fp, "  ");
                  if (!cpr_get_answer_is_yes ("sign_uid.expired_okay",
                                              _("Are you sure you still "
                                                "want to sign it? (y/N) ")))
@@ -838,16 +845,16 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified,
                }
              else
                {
-                 tty_printf (_("  Unable to sign.\n"));
+                 tty_fprintf (fp, _("  Unable to sign.\n"));
                  continue;
                }
            }
          else
            {
-             tty_printf (_("This key is due to expire on %s.\n"),
-                         expirestr_from_pk (primary_pk));
+             tty_fprintf (fp, _("This key is due to expire on %s.\n"),
+                           expirestr_from_pk (primary_pk));
 
-             if (opt.ask_cert_expire)
+             if (opt.ask_cert_expire && !quick)
                {
                  char *answer = cpr_get ("sign_uid.expire",
                                          _("Do you want your signature to "
@@ -862,7 +869,6 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified,
                         passphrase, etc). */
                      timestamp = now;
                      duration = primary_pk->expiredate - now;
-                     force_v4 = 1;
                    }
 
                  cpr_kill_prompt ();
@@ -875,62 +881,38 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified,
          the expiration of the pk */
       if (!duration && !selfsig)
        {
-         if (opt.ask_cert_expire)
+         if (opt.ask_cert_expire && !quick)
            duration = ask_expire_interval (1, opt.def_cert_expire);
          else
            duration = parse_expire_string (opt.def_cert_expire);
        }
 
-      if (duration)
-       force_v4 = 1;
-
-      /* Is --pgp2 on, it's a v3 key, all the sigs on the key are
-         currently v3 and we're about to sign it with a v4 sig?  If
-         so, danger! */
-      if (PGP2 && all_v3 &&
-         (pk->version > 3 || force_v4) && primary_pk->version <= 3)
-       {
-         tty_printf (_("You may not make an OpenPGP signature on a "
-                       "PGP 2.x key while in --pgp2 mode.\n"));
-         tty_printf (_("This would make the key unusable in PGP 2.x.\n"));
-
-         if (opt.expert)
-           {
-             if (!cpr_get_answer_is_yes ("sign_uid.v4_on_v3_okay",
-                                         _("Are you sure you still "
-                                           "want to sign it? (y/N) ")))
-               continue;
-
-             all_v3 = 0;
-           }
-         else
-           continue;
-       }
-
       if (selfsig)
        ;
       else
        {
-         if (opt.batch || !opt.ask_cert_level)
+         if (opt.batch || !opt.ask_cert_level || quick)
            class = 0x10 + opt.def_cert_level;
          else
            {
              char *answer;
 
-             tty_printf (_("How carefully have you verified the key you are "
+             tty_fprintf (fp,
+                           _("How carefully have you verified the key you are "
                            "about to sign actually belongs\nto the person "
                            "named above?  If you don't know what to "
                            "answer, enter \"0\".\n"));
-             tty_printf ("\n");
-             tty_printf (_("   (0) I will not answer.%s\n"),
+             tty_fprintf (fp, "\n");
+             tty_fprintf (fp, _("   (0) I will not answer.%s\n"),
                          opt.def_cert_level == 0 ? " (default)" : "");
-             tty_printf (_("   (1) I have not checked at all.%s\n"),
+             tty_fprintf (fp, _("   (1) I have not checked at all.%s\n"),
                          opt.def_cert_level == 1 ? " (default)" : "");
-             tty_printf (_("   (2) I have done casual checking.%s\n"),
+             tty_fprintf (fp, _("   (2) I have done casual checking.%s\n"),
                          opt.def_cert_level == 2 ? " (default)" : "");
-             tty_printf (_("   (3) I have done very careful checking.%s\n"),
+             tty_fprintf (fp,
+                           _("   (3) I have done very careful checking.%s\n"),
                          opt.def_cert_level == 3 ? " (default)" : "");
-             tty_printf ("\n");
+             tty_fprintf (fp, "\n");
 
              while (class == 0)
                {
@@ -948,79 +930,85 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified,
                  else if (ascii_strcasecmp (answer, "3") == 0)
                    class = 0x13;       /* Positive */
                  else
-                   tty_printf (_("Invalid selection.\n"));
+                   tty_fprintf (fp, _("Invalid selection.\n"));
 
                  xfree (answer);
                }
            }
 
-         if (trust)
+         if (trust && !quick)
            trustsig_prompt (&trust_value, &trust_depth, &trust_regexp);
        }
 
-      p = get_user_id_native (sk_keyid);
-      tty_printf (_("Are you sure that you want to sign this key with your\n"
-                   "key \"%s\" (%s)\n"), p, keystr_from_pk (pk));
-      xfree (p);
+      if (!quick)
+        {
+          p = get_user_id_native (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));
+          xfree (p);
+        }
 
       if (selfsig)
        {
-         tty_printf ("\n");
-         tty_printf (_("This will be a self-signature.\n"));
+         tty_fprintf (fp, "\n");
+         tty_fprintf (fp, _("This will be a self-signature.\n"));
 
          if (local)
            {
-             tty_printf ("\n");
-             tty_printf (_("WARNING: the signature will not be marked "
-                           "as non-exportable.\n"));
+             tty_fprintf (fp, "\n");
+             tty_fprintf (fp, _("WARNING: the signature will not be marked "
+                                 "as non-exportable.\n"));
            }
 
          if (nonrevocable)
            {
-             tty_printf ("\n");
-             tty_printf (_("WARNING: the signature will not be marked "
-                           "as non-revocable.\n"));
+             tty_fprintf (fp, "\n");
+             tty_fprintf (fp, _("WARNING: the signature will not be marked "
+                                 "as non-revocable.\n"));
            }
        }
       else
        {
          if (local)
            {
-             tty_printf ("\n");
-             tty_printf
-                (_("The signature will be marked as non-exportable.\n"));
+             tty_fprintf (fp, "\n");
+             tty_fprintf (fp,
+                 _("The signature will be marked as non-exportable.\n"));
            }
 
          if (nonrevocable)
            {
-             tty_printf ("\n");
-             tty_printf
-                (_("The signature will be marked as non-revocable.\n"));
+             tty_fprintf (fp, "\n");
+             tty_fprintf (fp,
+                 _("The signature will be marked as non-revocable.\n"));
            }
 
          switch (class)
            {
            case 0x11:
-             tty_printf ("\n");
-             tty_printf (_("I have not checked this key at all.\n"));
+             tty_fprintf (fp, "\n");
+             tty_fprintf (fp, _("I have not checked this key at all.\n"));
              break;
 
            case 0x12:
-             tty_printf ("\n");
-             tty_printf (_("I have checked this key casually.\n"));
+             tty_fprintf (fp, "\n");
+             tty_fprintf (fp, _("I have checked this key casually.\n"));
              break;
 
            case 0x13:
-             tty_printf ("\n");
-             tty_printf (_("I have checked this key very carefully.\n"));
+             tty_fprintf (fp, "\n");
+             tty_fprintf (fp, _("I have checked this key very carefully.\n"));
              break;
            }
        }
 
-      tty_printf ("\n");
+      tty_fprintf (fp, "\n");
 
       if (opt.batch && opt.answer_yes)
        ;
+      else if (quick)
+        ;
       else if (!cpr_get_answer_is_yes ("sign_uid.okay",
                                       _("Really sign? (y/N) ")))
        continue;
@@ -1058,7 +1046,7 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified,
                                         node->pkt->pkt.user_id,
                                         NULL,
                                         pk,
-                                        0x13, 0, force_v4 ? 4 : 0, 0, 0,
+                                        0x13, 0, 0, 0,
                                         keygen_add_std_prefs, primary_pk,
                                          NULL);
              else
@@ -1066,13 +1054,14 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified,
                                         node->pkt->pkt.user_id,
                                         NULL,
                                         pk,
-                                        class, 0, force_v4 ? 4 : 0,
+                                        class, 0,
                                         timestamp, duration,
                                         sign_mk_attrib, &attrib,
                                          NULL);
              if (rc)
                {
-                 log_error (_("signing failed: %s\n"), g10_errstr (rc));
+                  write_status_error ("keysig", rc);
+                 log_error (_("signing failed: %s\n"), gpg_strerror (rc));
                  goto leave;
                }
 
@@ -1093,7 +1082,7 @@ sign_uids (KBNODE keyblock, strlist_t locusr, int *ret_modified,
          delete_kbnode (node);
     } /* End loop over signators.  */
 
-leave:
+ leave:
   release_sk_list (sk_list);
   return rc;
 }
@@ -1180,14 +1169,14 @@ change_passphrase (ctrl_t ctrl, kbnode_t keyblock)
           if (err)
             goto leave;
 
-          desc = gpg_format_keydesc (pk, 0, 1);
+          desc = gpg_format_keydesc (pk, FORMAT_KEYDESC_NORMAL, 1);
           err = agent_passwd (ctrl, hexgrip, desc, &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)
-                     ? JNLIB_LOG_INFO : JNLIB_LOG_ERROR,
+                     ? GPGRT_LOG_INFO : GPGRT_LOG_ERROR,
                      _("key %s: error changing passphrase: %s\n"),
                        keystr_with_sub (keyid, subid),
                        gpg_strerror (err));
@@ -1213,7 +1202,7 @@ change_passphrase (ctrl_t ctrl, kbnode_t keyblock)
  * Note:  This function does not work if there is more than one user ID.
  */
 static int
-fix_keyblock (KBNODE keyblock)
+fix_key_signature_order (KBNODE keyblock)
 {
   KBNODE node, last, subkey;
   int fixed = 0;
@@ -1253,6 +1242,27 @@ fix_keyblock (KBNODE keyblock)
 }
 
 
+/* 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)
+{
+  int changed = 0;
+
+  if (fix_key_signature_order (*keyblockp))
+    changed++;
+  if (collapse_uids (keyblockp))
+    changed++;
+  reorder_keyblock (*keyblockp);
+  /* If we modified the keyblock, make sure the flags are right. */
+  if (changed)
+    merge_keys_and_selfsig (*keyblockp);
+
+  return changed;
+}
+
+
 static int
 parse_sign_type (const char *str, int *localsig, int *nonrevokesig,
                 int *trustsig)
@@ -1316,7 +1326,7 @@ enum cmdids
   cmdSHOWPREF,
   cmdSETPREF, cmdPREFKS, cmdNOTATION, cmdINVCMD, cmdSHOWPHOTO, cmdUPDTRUST,
   cmdCHKTRUST, cmdADDCARDKEY, cmdKEYTOCARD, cmdBKUPTOCARD, cmdCHECKBKUPKEY,
-  cmdCLEAN, cmdMINIMIZE, cmdNOP
+  cmdCLEAN, cmdMINIMIZE, cmdGRIP, cmdNOP
 };
 
 static struct
@@ -1333,6 +1343,7 @@ static struct
   { "help", cmdHELP, 0, N_("show this help")},
   { "?", cmdHELP, 0, NULL},
   { "fpr", cmdFPR, 0, N_("show key fingerprint")},
+  { "grip", cmdGRIP, 0, N_("show the keygrip")},
   { "list", cmdLIST, 0, N_("list key and user IDs")},
   { "l", cmdLIST, 0, NULL},
   { "uid", cmdSELUID, 0, N_("select user ID N")},
@@ -1377,8 +1388,7 @@ static struct
     N_("change the expiration date for the key or selected subkeys")},
   { "primary", cmdPRIMARY, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK,
     N_("flag the selected user ID as primary")},
-  { "toggle", cmdTOGGLE, KEYEDIT_NEED_SK,
-    N_("toggle between the secret and public key listings")},
+  { "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)")},
@@ -1481,7 +1491,8 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
   char *answer = NULL;
   int redisplay = 1;
   int modified = 0;
-  int toggle;
+  int sec_shadowing = 0;
+  int run_subkey_warnings = 0;
   int have_commands = !!commands;
 
   if (opt.command_fd != -1)
@@ -1512,15 +1523,9 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
       log_error (_("key \"%s\" not found: %s\n"), username, gpg_strerror (err));
       goto leave;
     }
-  if (fix_keyblock (keyblock))
-    modified++;
-  if (collapse_uids (&keyblock))
+
+  if (fix_keyblock (&keyblock))
     modified++;
-  reorder_keyblock (keyblock);
-  /* We modified the keyblock, so let's make sure the flags are
-     right. */
-  if (modified)
-    merge_keys_and_selfsig (keyblock);
 
   /* See whether we have a matching secret key.  */
   if (seckey_check)
@@ -1530,8 +1535,6 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
        tty_printf (_("Secret key is available.\n"));
     }
 
-  toggle = 0;
-
   /* Main command loop.  */
   for (;;)
     {
@@ -1544,10 +1547,19 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
 
       if (redisplay && !quiet)
        {
-         show_key_with_all_names (NULL, keyblock, 0, 1, 0, 1, 0);
+          /* Show using flags: with_revoker, with_subkeys.  */
+         show_key_with_all_names (ctrl, NULL, keyblock, 0, 1, 0, 1, 0, 0);
          tty_printf ("\n");
          redisplay = 0;
        }
+
+      if (run_subkey_warnings)
+        {
+          run_subkey_warnings = 0;
+          if (!count_selected_keys (keyblock))
+            subkey_expire_warning (keyblock);
+        }
+
       do
        {
          xfree (answer);
@@ -1570,7 +1582,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
 #ifdef HAVE_LIBREADLINE
              tty_enable_completion (keyedit_completion);
 #endif
-             answer = cpr_get_no_help ("keyedit.prompt", "gpg> ");
+             answer = cpr_get_no_help ("keyedit.prompt", GPG_NAME "> ");
              cpr_kill_prompt ();
              tty_disable_completion ();
            }
@@ -1623,13 +1635,6 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
              tty_printf (_("Need the secret key to do this.\n"));
              cmd = cmdNOP;
            }
-         else if (((cmds[i].flags & KEYEDIT_NOT_SK) && have_seckey && toggle)
-                  || ((cmds[i].flags & KEYEDIT_ONLY_SK) && have_seckey
-                      && !toggle))
-           {
-             tty_printf (_("Please use the command \"toggle\" first.\n"));
-             cmd = cmdNOP;
-           }
          else
            cmd = cmds[i].id;
        }
@@ -1661,7 +1666,13 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
          break;
 
        case cmdFPR:
-         show_key_and_fingerprint (keyblock);
+         show_key_and_fingerprint
+            (keyblock, (*arg_string == '*'
+                        && (!arg_string[1] || spacep (arg_string + 1))));
+         break;
+
+       case cmdGRIP:
+         show_key_and_grip (keyblock);
          break;
 
        case cmdSELUID:
@@ -1687,7 +1698,8 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
          break;
 
        case cmdCHECK:
-         check_all_keysigs (keyblock, count_selected_uids (keyblock));
+         check_all_keysigs (keyblock, count_selected_uids (keyblock),
+                             !strcmp (arg_string, "selfsig"));
          break;
 
        case cmdSIGN:
@@ -1736,8 +1748,8 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
                break;
              }
 
-           sign_uids (keyblock, locusr, &modified,
-                      localsig, nonrevokesig, trustsig, interactive);
+           sign_uids (ctrl, NULL, keyblock, locusr, &modified,
+                      localsig, nonrevokesig, trustsig, interactive, 0);
          }
          break;
 
@@ -1750,12 +1762,11 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
              where we worked with a secret and a public keyring.  It
              is not necessary anymore but we keep this command for the
              sake of scripts using it.  */
-         toggle = !toggle;
          redisplay = 1;
          break;
 
        case cmdADDPHOTO:
-         if (RFC2440 || RFC1991 || PGP2)
+         if (RFC2440)
            {
              tty_printf (_("This command is not allowed while in %s mode.\n"),
                          compliance_option_string ());
@@ -1764,7 +1775,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
          photo = 1;
          /* fall through */
        case cmdADDUID:
-         if (menu_adduid (keyblock, photo, arg_string))
+         if (menu_adduid (keyblock, photo, arg_string, NULL))
            {
              update_trust = 1;
              redisplay = 1;
@@ -1778,7 +1789,11 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
            int n1;
 
            if (!(n1 = count_selected_uids (keyblock)))
-             tty_printf (_("You must select at least one user ID.\n"));
+              {
+                tty_printf (_("You must select at least one user ID.\n"));
+                if (!opt.expert)
+                  tty_printf (_("(Use the '%s' command.)\n"), "uid");
+              }
            else if (real_uids_left (keyblock) < 1)
              tty_printf (_("You can't delete the last user ID!\n"));
            else if (cpr_get_answer_is_yes
@@ -1798,7 +1813,11 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
            int n1;
 
            if (!(n1 = count_selected_uids (keyblock)))
-             tty_printf (_("You must select at least one user ID.\n"));
+              {
+                tty_printf (_("You must select at least one user ID.\n"));
+                if (!opt.expert)
+                  tty_printf (_("(Use the '%s' command.)\n"), "uid");
+              }
            else if (menu_delsig (keyblock))
              {
                /* No redisplay here, because it may scroll away some
@@ -1858,8 +1877,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
                if (card_store_subkey (node, xxpk ? xxpk->pubkey_usage : 0))
                  {
                    redisplay = 1;
-                   /* Only the secret key has been modified; thus
-                       there is no need to set the modified flag.  */
+                   sec_shadowing = 1;
                  }
              }
          }
@@ -1907,11 +1925,11 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
            iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char *) fname);
            if (!err && pkt->pkttype != PKT_SECRET_KEY
                && pkt->pkttype != PKT_SECRET_SUBKEY)
-             err = G10ERR_NO_SECKEY;
+             err = GPG_ERR_NO_SECKEY;
            if (err)
              {
                tty_printf (_("Error reading backup key from '%s': %s\n"),
-                           fname, g10_errstr (err));
+                           fname, gpg_strerror (err));
                free_packet (pkt);
                xfree (pkt);
                break;
@@ -1945,7 +1963,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
                if (card_store_subkey (node, 0))
                  {
                    redisplay = 1;
-                   /* FIXME:sec_modified = 1;*/
+                   sec_shadowing = 1;
                  }
              }
            release_kbnode (node);
@@ -1959,7 +1977,11 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
            int n1;
 
            if (!(n1 = count_selected_keys (keyblock)))
-             tty_printf (_("You must select at least one key.\n"));
+              {
+                tty_printf (_("You must select at least one key.\n"));
+                if (!opt.expert)
+                  tty_printf (_("(Use the '%s' command.)\n"), "key");
+              }
            else if (!cpr_get_answer_is_yes
                      ("keyedit.remove.subkey.okay",
                       n1 > 1 ? _("Do you really want to delete the "
@@ -1995,7 +2017,11 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
            int n1;
 
            if (!(n1 = count_selected_uids (keyblock)))
-             tty_printf (_("You must select at least one user ID.\n"));
+              {
+                tty_printf (_("You must select at least one user ID.\n"));
+                if (!opt.expert)
+                  tty_printf (_("(Use the '%s' command.)\n"), "uid");
+              }
            else if (cpr_get_answer_is_yes
                      ("keyedit.revoke.uid.okay",
                       n1 > 1 ? _("Really revoke all selected user IDs? (y/N) ")
@@ -2048,6 +2074,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
          if (menu_expire (keyblock))
            {
              merge_keys_and_selfsig (keyblock);
+              run_subkey_warnings = 1;
              modified = 1;
              redisplay = 1;
            }
@@ -2083,7 +2110,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
              break;
            }
 
-         show_key_with_all_names (NULL, keyblock, 0, 0, 0, 1, 0);
+         show_key_with_all_names (ctrl, NULL, keyblock, 0, 0, 0, 1, 0, 0);
          tty_printf ("\n");
          if (edit_ownertrust (find_kbnode (keyblock,
                                            PKT_PUBLIC_KEY)->pkt->pkt.
@@ -2203,7 +2230,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
        case cmdQUIT:
          if (have_commands)
            goto leave;
-         if (!modified)
+         if (!modified && !sec_shadowing)
            goto leave;
          if (!cpr_get_answer_is_yes ("keyedit.save.okay",
                                      _("Save changes? (y/N) ")))
@@ -2221,11 +2248,22 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
               err = keydb_update_keyblock (kdbhd, keyblock);
               if (err)
                 {
-                  log_error (_("update failed: %s\n"), g10_errstr (err));
+                  log_error (_("update failed: %s\n"), gpg_strerror (err));
                   break;
                 }
            }
-         else
+
+         if (sec_shadowing)
+           {
+             err = agent_scd_learn (NULL, 1);
+             if (err)
+                {
+                  log_error (_("update failed: %s\n"), gpg_strerror (err));
+                  break;
+                }
+           }
+
+         if (!modified && !sec_shadowing)
            tty_printf (_("Key not changed so no update needed.\n"));
 
          if (update_trust)
@@ -2284,6 +2322,244 @@ 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)
+{
+  gpg_error_t err;
+  KEYDB_HANDLE kdbhd = NULL;
+  KEYDB_SEARCH_DESC desc;
+  kbnode_t keyblock = NULL;
+  kbnode_t node;
+  char *uidstring = NULL;
+
+  uidstring = xstrdup (newuid);
+  trim_spaces (uidstring);
+  if (!*uidstring)
+    {
+      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 ();
+#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);
+  if (!err)
+    {
+      err = keydb_get_keyblock (kdbhd, &keyblock);
+      if (err)
+        {
+          log_error (_("error reading keyblock: %s\n"), gpg_strerror (err));
+          goto leave;
+        }
+      /* Now with the keyblock retrieved, search again to detect an
+         ambiguous specification.  We need to save the found state so
+         that we can do an update later.  */
+      keydb_push_found_state (kdbhd);
+      err = keydb_search (kdbhd, &desc, 1, NULL);
+      if (!err)
+        err = gpg_error (GPG_ERR_AMBIGUOUS_NAME);
+      else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
+        err = 0;
+      keydb_pop_found_state (kdbhd);
+
+      if (!err)
+        {
+          /* We require the secret primary key to add a UID.  */
+          node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
+          if (!node)
+            BUG ();
+          err = agent_probe_secret_key (ctrl, node->pkt->pkt.public_key);
+        }
+    }
+  if (err)
+    {
+      log_error (_("secret key \"%s\" not found: %s\n"),
+                 username, gpg_strerror (err));
+      goto leave;
+    }
+
+  fix_keyblock (&keyblock);
+
+  if (menu_adduid (keyblock, 0, NULL, uidstring))
+    {
+      err = keydb_update_keyblock (kdbhd, keyblock);
+      if (err)
+        {
+          log_error (_("update failed: %s\n"), gpg_strerror (err));
+          goto leave;
+        }
+
+      if (update_trust)
+        revalidation_mark ();
+    }
+
+ leave:
+  xfree (uidstring);
+  release_kbnode (keyblock);
+  keydb_release (kdbhd);
+}
+
+
+/* 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.  */
+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;
+  KEYDB_SEARCH_DESC desc;
+  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 ();
+#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 (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);
+      goto leave;
+    }
+  err = get_pubkey_byname (ctrl, NULL, NULL, fpr, &keyblock, &kdbhd, 1, 1);
+  if (err)
+    {
+      log_error (_("key \"%s\" not found: %s\n"), fpr, gpg_strerror (err));
+      goto leave;
+    }
+
+  /* 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;
+      }
+  }
+
+  if (fix_keyblock (&keyblock))
+    modified++;
+
+  /* Give some info in verbose.  */
+  if (opt.verbose)
+    {
+      show_key_with_all_names (ctrl, es_stdout, keyblock, 0,
+                               1/*with_revoker*/, 1/*with_fingerprint*/,
+                               0, 0, 1);
+      es_fflush (es_stdout);
+    }
+
+  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."), _("  Unable to sign.\n"));
+      goto leave;
+    }
+
+  /* Set the flags according to the UIDS list.  Fixme: We may want to
+     use classify_user_id along with dedicated compare functions so
+     that we match the same way as in the key lookup. */
+  any = 0;
+  menu_select_uid (keyblock, 0);   /* Better clear the flags first. */
+  for (sl=uids; sl; sl = sl->next)
+    {
+      for (node = keyblock; node; node = node->next)
+        {
+          if (node->pkt->pkttype == PKT_USER_ID)
+            {
+              PKT_user_id *uid = node->pkt->pkt.user_id;
+
+              if (!uid->attrib_data
+                  && ascii_memistr (uid->name, uid->len, sl->d))
+                {
+                  node->flag |= NODFLG_SELUID;
+                  any = 1;
+                }
+            }
+        }
+    }
+
+  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;
+    }
+
+  /* Sign. */
+  sign_uids (ctrl, es_stdout, keyblock, locusr, &modified, local, 0, 0, 0, 1);
+  es_fflush (es_stdout);
+
+  if (modified)
+    {
+      err = keydb_update_keyblock (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 ();
+
+
+ leave:
+  release_kbnode (keyblock);
+  keydb_release (kdbhd);
+}
+
+
+\f
 static void
 tty_print_notations (int indent, PKT_signature * sig)
 {
@@ -2484,12 +2760,13 @@ show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose)
    opt.with_colons is used.  It prints all available data in a easy to
    parse format and does not translate utf8 */
 static void
-show_key_with_all_names_colon (estream_t fp, kbnode_t keyblock)
+show_key_with_all_names_colon (ctrl_t ctrl, estream_t fp, kbnode_t keyblock)
 {
   KBNODE node;
   int i, j, ulti_hack = 0;
   byte pk_version = 0;
   PKT_public_key *primary = NULL;
+  int have_seckey;
 
   if (!fp)
     fp = es_stdout;
@@ -2510,9 +2787,13 @@ show_key_with_all_names_colon (estream_t fp, kbnode_t keyblock)
            }
 
          keyid_from_pk (pk, keyid);
+          have_seckey = !agent_probe_secret_key (ctrl, pk);
+
+          if (node->pkt->pkttype == PKT_PUBLIC_KEY)
+            es_fputs (have_seckey? "sec:" : "pub:", fp);
+          else
+            es_fputs (have_seckey? "ssb:" : "sub:", fp);
 
-         es_fputs (node->pkt->pkttype == PKT_PUBLIC_KEY ? "pub:" : "sub:",
-                    fp);
          if (!pk->flags.valid)
            es_putc ('i', fp);
          else if (pk->flags.revoked)
@@ -2703,19 +2984,23 @@ show_names (estream_t fp,
  * tty (ignored in with-colons mode).
  */
 static void
-show_key_with_all_names (estream_t fp,
+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 with_fpr, int with_subkeys, int with_prefs,
+                         int nowarn)
 {
-  KBNODE node;
+  gpg_error_t err;
+  kbnode_t node;
   int i;
   int do_warn = 0;
+  int have_seckey = 0;
+  char *serialno = NULL;
   PKT_public_key *primary = NULL;
   char pkstrbuf[PUBKEY_STRING_SIZE];
 
   if (opt.with_colons)
     {
-      show_key_with_all_names_colon (fp, keyblock);
+      show_key_with_all_names_colon (ctrl, fp, keyblock);
       return;
     }
 
@@ -2793,13 +3078,33 @@ show_key_with_all_names (estream_t fp,
            }
 
          keyid_from_pk (pk, NULL);
-         tty_fprintf (fp, "%s%c %s/%s",
-                     node->pkt->pkttype == PKT_PUBLIC_KEY ? "pub" :
-                     node->pkt->pkttype == PKT_PUBLIC_SUBKEY ? "sub" :
-                     node->pkt->pkttype == PKT_SECRET_KEY ? "sec" : "ssb",
-                     (node->flag & NODFLG_SELKEY) ? '*' : ' ',
-                      pubkey_string (pk, pkstrbuf, sizeof pkstrbuf),
-                     keystr (pk->keyid));
+
+          xfree (serialno);
+          serialno = NULL;
+          {
+            char *hexgrip;
+
+            err = hexkeygrip_from_pk (pk, &hexgrip);
+            if (err)
+              {
+                log_error ("error computing a keygrip: %s\n",
+                           gpg_strerror (err));
+                have_seckey = 0;
+              }
+            else
+              have_seckey = !agent_get_keyinfo (ctrl, hexgrip, &serialno);
+            xfree (hexgrip);
+          }
+
+         tty_fprintf
+            (fp, "%s%c %s/%s",
+             node->pkt->pkttype == PKT_PUBLIC_KEY && have_seckey? "sec" :
+             node->pkt->pkttype == PKT_PUBLIC_KEY ?               "pub" :
+             have_seckey ?                                        "ssb" :
+                                                                  "sub",
+             (node->flag & NODFLG_SELKEY) ? '*' : ' ',
+             pubkey_string (pk, pkstrbuf, sizeof pkstrbuf),
+             keystr (pk->keyid));
 
           if (opt.legacy_list_mode)
             tty_fprintf (fp, "  ");
@@ -2815,13 +3120,33 @@ show_key_with_all_names (estream_t fp,
          else
            tty_fprintf (fp, _("expires: %s"), expirestr_from_pk (pk));
          tty_fprintf (fp, "  ");
-         tty_fprintf (fp, _("usage: %s"), usagestr_from_pk (pk));
+         tty_fprintf (fp, _("usage: %s"), usagestr_from_pk (pk, 1));
          tty_fprintf (fp, "\n");
 
-         if (pk->seckey_info
+          if (serialno)
+            {
+              /* The agent told us that a secret key is available and
+                 that it has been stored on a card.  */
+             tty_fprintf (fp, "%*s%s", opt.legacy_list_mode? 21:5, "",
+                           _("card-no: "));
+              if (strlen (serialno) == 32
+                  && !strncmp (serialno, "D27600012401", 12))
+                {
+                  /* This is an OpenPGP card.  Print the relevant part.  */
+                  /* Example: D2760001240101010001000003470000 */
+                  /*                          xxxxyyyyyyyy     */
+                  tty_fprintf (fp, "%.*s %.*s\n",
+                               4, serialno+16, 8, serialno+20);
+                }
+              else
+                tty_fprintf (fp, "%s\n", serialno);
+
+            }
+         else if (pk->seckey_info
               && pk->seckey_info->is_protected
               && pk->seckey_info->s2k.mode == 1002)
            {
+              /* FIXME: Check wether 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
@@ -2889,17 +3214,21 @@ show_key_with_all_names (estream_t fp,
   show_names (fp,
               keyblock, primary, only_marked ? NODFLG_MARK_A : 0, with_prefs);
 
-  if (do_warn)
+  if (do_warn && !nowarn)
     tty_fprintf (fp, _("Please note that the shown key validity"
                        " is not necessarily correct\n"
                        "unless you restart the program.\n"));
+
+  xfree (serialno);
 }
 
 
 /* Display basic key information.  This function is suitable to show
    information on the key without any dependencies on the trustdb or
    any other internal GnuPG stuff.  KEYBLOCK may either be a public or
-   a secret key.*/
+   a secret key.  This function may be called with KEYBLOCK containing
+   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)
 {
@@ -2951,10 +3280,11 @@ show_basic_key_info (KBNODE keyblock)
     }
 }
 
+
 static void
-show_key_and_fingerprint (KBNODE keyblock)
+show_key_and_fingerprint (kbnode_t keyblock, int with_subkeys)
 {
-  KBNODE node;
+  kbnode_t node;
   PKT_public_key *pk = NULL;
   char pkstrbuf[PUBKEY_STRING_SIZE];
 
@@ -2978,6 +3308,56 @@ show_key_and_fingerprint (KBNODE keyblock)
   tty_printf ("\n");
   if (pk)
     print_fingerprint (NULL, pk, 2);
+  if (with_subkeys)
+    {
+      for (node = keyblock; node; node = node->next)
+        {
+          if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+            {
+              pk = node->pkt->pkt.public_key;
+              tty_printf ("sub   %s/%s %s [%s]\n",
+                          pubkey_string (pk, pkstrbuf, sizeof pkstrbuf),
+                          keystr_from_pk(pk),
+                          datestr_from_pk (pk),
+                          usagestr_from_pk (pk, 0));
+
+              print_fingerprint (NULL, pk, 4);
+            }
+        }
+    }
+}
+
+
+/* Show a listing of the primary and its subkeys along with their
+   keygrips.  */
+static void
+show_key_and_grip (kbnode_t keyblock)
+{
+  kbnode_t node;
+  PKT_public_key *pk = NULL;
+  char pkstrbuf[PUBKEY_STRING_SIZE];
+  char *hexgrip;
+
+  for (node = keyblock; node; node = node->next)
+    {
+      if (node->pkt->pkttype == PKT_PUBLIC_KEY
+          || node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+        {
+          pk = node->pkt->pkt.public_key;
+          tty_printf ("%s   %s/%s %s [%s]\n",
+                      node->pkt->pkttype == PKT_PUBLIC_KEY? "pub":"sub",
+                      pubkey_string (pk, pkstrbuf, sizeof pkstrbuf),
+                      keystr_from_pk(pk),
+                      datestr_from_pk (pk),
+                      usagestr_from_pk (pk, 0));
+
+          if (!hexkeygrip_from_pk (pk, &hexgrip))
+            {
+              tty_printf ("      Keygrip: %s\n", hexgrip);
+              xfree (hexgrip);
+            }
+        }
+    }
 }
 
 
@@ -3016,12 +3396,68 @@ no_primary_warning (KBNODE keyblock)
 }
 
 
+/* Print a warning if the latest encryption subkey expires soon.  This
+   function is called after the expire data of the primary key has
+   been changed.  */
+static void
+subkey_expire_warning (kbnode_t keyblock)
+{
+  u32 curtime = make_timestamp ();
+  kbnode_t node;
+  PKT_public_key *pk;
+  /* u32 mainexpire = 0; */
+  u32 subexpire = 0;
+  u32 latest_date = 0;
+
+  for (node = keyblock; node; node = node->next)
+    {
+      /* if (node->pkt->pkttype == PKT_PUBLIC_KEY) */
+      /*   { */
+      /*     pk = node->pkt->pkt.public_key; */
+      /*     mainexpire = pk->expiredate; */
+      /*   } */
+
+      if (node->pkt->pkttype != PKT_PUBLIC_SUBKEY)
+        continue;
+      pk = node->pkt->pkt.public_key;
+
+      if (!pk->flags.valid)
+        continue;
+      if (pk->flags.revoked)
+        continue;
+      if (pk->timestamp > curtime)
+        continue; /* Ignore future keys.  */
+      if (!(pk->pubkey_usage & PUBKEY_USAGE_ENC))
+        continue; /* Not an encryption key.  */
+
+      if (pk->timestamp > latest_date || (!pk->timestamp && !latest_date))
+        {
+          latest_date = pk->timestamp;
+          subexpire = pk->expiredate;
+        }
+    }
+
+  if (!subexpire)
+    return;  /* No valid subkey with an expiration time.  */
+
+  if (curtime + (10*86400) > subexpire)
+    {
+      log_info (_("WARNING: Your encryption subkey expires soon.\n"));
+      log_info (_("You may want to change its expiration date too.\n"));
+    }
+}
+
+
 /*
- * Ask for a new user id, add the self-signature and update the keyblock.
- * Return true if there is a new user id
+ * Ask for a new user id, add the self-signature, and update the
+ * keyblock.  If UIDSTRING is not NULL the user ID is generated
+ * unattended using that string.  UIDSTRING is expected to be utf-8
+ * encoded and white space trimmed.  Returns true if there is a new
+ * user id.
  */
 static int
-menu_adduid (KBNODE pub_keyblock, int photo, const char *photo_name)
+menu_adduid (kbnode_t pub_keyblock, int photo, const char *photo_name,
+             const char *uidstring)
 {
   PKT_user_id *uid;
   PKT_public_key *pk = NULL;
@@ -3031,6 +3467,9 @@ menu_adduid (KBNODE pub_keyblock, int photo, const char *photo_name)
   KBNODE pub_where = NULL;
   gpg_error_t err;
 
+  if (photo && uidstring)
+    return 0;  /* Not allowed.  */
+
   for (node = pub_keyblock; node; pub_where = node, node = node->next)
     {
       if (node->pkt->pkttype == PKT_PUBLIC_KEY)
@@ -3083,15 +3522,20 @@ menu_adduid (KBNODE pub_keyblock, int photo, const char *photo_name)
       uid = generate_photo_id (pk, photo_name);
     }
   else
-    uid = generate_user_id (pub_keyblock);
+    uid = generate_user_id (pub_keyblock, uidstring);
   if (!uid)
-    return 0;
+    {
+      if (uidstring)
+        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, 0,
+  err = make_keysig_packet (&sig, pk, uid, NULL, pk, 0x13, 0, 0, 0,
                             keygen_add_std_prefs, pk, NULL);
   if (err)
     {
-      log_error ("signing failed: %s\n", g10_errstr (err));
+      write_status_error ("keysig", err);
+      log_error ("signing failed: %s\n", gpg_strerror (err));
       free_user_id (uid);
       return 0;
     }
@@ -3177,7 +3621,7 @@ menu_delsig (KBNODE pub_keyblock)
          else
            valid = print_and_check_one_sig (pub_keyblock, node,
                                             &inv_sig, &no_key, &other_err,
-                                            &selfsig, 1);
+                                            &selfsig, 1, 0);
 
          if (valid)
            {
@@ -3390,7 +3834,7 @@ menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive)
       if (rc)
        {
          log_error (_("key \"%s\" not found: %s\n"), answer,
-                    g10_errstr (rc));
+                    gpg_strerror (rc));
          xfree (answer);
          continue;
        }
@@ -3471,13 +3915,12 @@ menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive)
       break;
     }
 
-  /* The 1F signature must be at least v4 to carry the revocation key
-     subpacket. */
-  rc = make_keysig_packet (&sig, pk, NULL, NULL, pk, 0x1F, 0, 4, 0, 0,
+  rc = make_keysig_packet (&sig, pk, NULL, NULL, pk, 0x1F, 0, 0, 0,
                           keygen_add_revkey, &revkey, NULL);
   if (rc)
     {
-      log_error ("signing failed: %s\n", g10_errstr (rc));
+      write_status_error ("keysig", rc);
+      log_error ("signing failed: %s\n", gpg_strerror (rc));
       goto fail;
     }
 
@@ -3581,7 +4024,7 @@ menu_expire (KBNODE pub_keyblock)
              if (rc)
                {
                  log_error ("make_keysig_packet failed: %s\n",
-                            g10_errstr (rc));
+                            gpg_strerror (rc));
                  return 0;
                }
 
@@ -3697,13 +4140,13 @@ menu_backsign (KBNODE pub_keyblock)
          else
            {
              log_error ("update_keysig_packet failed: %s\n",
-                        g10_errstr (rc));
+                        gpg_strerror (rc));
              break;
            }
        }
       else
        {
-         log_error ("make_backsig failed: %s\n", g10_errstr (rc));
+         log_error ("make_backsig failed: %s\n", gpg_strerror (rc));
          break;
        }
     }
@@ -3839,7 +4282,7 @@ menu_set_primary_uid (KBNODE pub_keyblock)
                      if (rc)
                        {
                          log_error ("update_keysig_packet failed: %s\n",
-                                    g10_errstr (rc));
+                                    gpg_strerror (rc));
                          return 0;
                        }
                      /* replace the packet */
@@ -3928,7 +4371,7 @@ menu_set_preferences (KBNODE pub_keyblock)
                  if (rc)
                    {
                      log_error ("update_keysig_packet failed: %s\n",
-                                g10_errstr (rc));
+                                gpg_strerror (rc));
                      return 0;
                    }
                  /* replace the packet */
@@ -3980,7 +4423,7 @@ menu_set_keyserver_url (const char *url, KBNODE pub_keyblock)
     {
       struct keyserver_spec *keyserver = NULL;
       /* Sanity check the format */
-      keyserver = parse_keyserver_uri (answer, 1, NULL, 0);
+      keyserver = parse_keyserver_uri (answer, 1);
       xfree (answer);
       if (!keyserver)
        {
@@ -4063,7 +4506,7 @@ menu_set_keyserver_url (const char *url, KBNODE pub_keyblock)
                  if (rc)
                    {
                      log_error ("update_keysig_packet failed: %s\n",
-                                g10_errstr (rc));
+                                gpg_strerror (rc));
                      xfree (uri);
                      return 0;
                    }
@@ -4262,7 +4705,7 @@ menu_set_notation (const char *string, KBNODE pub_keyblock)
                  if (rc)
                    {
                      log_error ("update_keysig_packet failed: %s\n",
-                                g10_errstr (rc));
+                                gpg_strerror (rc));
                      free_notation (notation);
                      xfree (user);
                      return 0;
@@ -4548,11 +4991,11 @@ ask_revoke_sig (KBNODE keyblock, KBNODE node)
        printf ("uat:::::::::%u %lu", uid->numattribs, uid->attrib_len);
       else
        {
-         printf ("uid:::::::::");
+         es_printf ("uid:::::::::");
          es_write_sanitized (es_stdout, uid->name, uid->len, ":", NULL);
        }
 
-      printf ("\n");
+      es_printf ("\n");
 
       print_and_check_one_sig_colon (keyblock, node, NULL, NULL, NULL, NULL,
                                     1);
@@ -4763,12 +5206,13 @@ reloop:                 /* (must use this, because we are modifing the list) */
        }
       rc = make_keysig_packet (&sig, primary_pk,
                               unode->pkt->pkt.user_id,
-                              NULL, signerkey, 0x30, 0, 0, 0, 0,
+                              NULL, signerkey, 0x30, 0, 0, 0,
                                sign_mk_attrib, &attrib, NULL);
       free_public_key (signerkey);
       if (rc)
        {
-         log_error (_("signing failed: %s\n"), g10_errstr (rc));
+          write_status_error ("keysig", rc);
+         log_error (_("signing failed: %s\n"), gpg_strerror (rc));
          release_revocation_reason_info (reason);
          return changed;
        }
@@ -4855,11 +5299,12 @@ menu_revuid (KBNODE pub_keyblock)
            node->flag &= ~NODFLG_SELUID;
 
            rc = make_keysig_packet (&sig, pk, uid, NULL, pk, 0x30, 0,
-                                    (reason == NULL) ? 3 : 0, timestamp, 0,
+                                    timestamp, 0,
                                     sign_mk_attrib, &attrib, NULL);
            if (rc)
              {
-               log_error (_("signing failed: %s\n"), g10_errstr (rc));
+                write_status_error ("keysig", rc);
+               log_error (_("signing failed: %s\n"), gpg_strerror (rc));
                goto leave;
              }
            else
@@ -4919,11 +5364,12 @@ menu_revkey (KBNODE pub_keyblock)
     return 0;
 
   rc = make_keysig_packet (&sig, pk, NULL, NULL, pk,
-                          0x20, 0, opt.force_v4_certs ? 4 : 0, 0, 0,
+                          0x20, 0, 0, 0,
                           revocation_reason_build_cb, reason, NULL);
   if (rc)
     {
-      log_error (_("signing failed: %s\n"), g10_errstr (rc));
+      write_status_error ("keysig", rc);
+      log_error (_("signing failed: %s\n"), gpg_strerror (rc));
       goto scram;
     }
 
@@ -4980,11 +5426,12 @@ menu_revsubkey (KBNODE pub_keyblock)
 
          node->flag &= ~NODFLG_SELKEY;
          rc = make_keysig_packet (&sig, mainpk, NULL, subpk, mainpk,
-                                  0x28, 0, 0, 0, 0, sign_mk_attrib, &attrib,
+                                  0x28, 0, 0, 0, sign_mk_attrib, &attrib,
                                    NULL);
          if (rc)
            {
-             log_error (_("signing failed: %s\n"), g10_errstr (rc));
+              write_status_error ("keysig", rc);
+             log_error (_("signing failed: %s\n"), gpg_strerror (rc));
              release_revocation_reason_info (reason);
              return changed;
            }