Actually show translators comments in PO files
[gnupg.git] / g10 / keyedit.c
index 52025ce..76830f0 100644 (file)
@@ -1,12 +1,12 @@
 /* keyedit.c - keyedit stuff
- * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
- *               2005 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
+ *               2008, 2009, 2010 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
  * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
@@ -15,9 +15,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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
 #include <assert.h>
 #include <ctype.h>
 #ifdef HAVE_LIBREADLINE
-#include <stdio.h>
+#define GNUPG_LIBREADLINE_H_INCLUDED
 #include <readline/readline.h>
 #endif
+
+#include "gpg.h"
 #include "options.h"
 #include "packet.h"
-#include "errors.h"
+#include "status.h"
 #include "iobuf.h"
 #include "keydb.h"
-#include "memory.h"
 #include "photoid.h"
 #include "util.h"
 #include "main.h"
@@ -67,6 +66,8 @@ static int menu_set_primary_uid( KBNODE pub_keyblock, KBNODE sec_keyblock );
 static int menu_set_preferences( KBNODE pub_keyblock, KBNODE sec_keyblock );
 static int menu_set_keyserver_url (const char *url,
                                   KBNODE pub_keyblock, KBNODE sec_keyblock );
+static int menu_set_notation(const char *string,
+                            KBNODE pub_keyblock,KBNODE sec_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 );
@@ -115,7 +116,7 @@ find_pk_from_sknode (KBNODE pub_keyblock, KBNODE sec_node)
   KBNODE node = pub_keyblock;
   PKT_secret_key *sk;
   PKT_public_key *pk;
-  
+
   if (sec_node->pkt->pkttype == PKT_SECRET_KEY
       && node->pkt->pkttype == PKT_PUBLIC_KEY)
     return node->pkt->pkt.public_key;
@@ -129,7 +130,7 @@ find_pk_from_sknode (KBNODE pub_keyblock, KBNODE sec_node)
         if (pk->keyid[0] == sk->keyid[0] && pk->keyid[1] == sk->keyid[1])
           return pk;
       }
-      
+
   return NULL;
 }
 #endif /* ENABLE_CARD_SUPPORT */
@@ -504,7 +505,7 @@ trustsig_prompt(byte *trust_value,byte *trust_depth,char **regexp)
  * if some user_ids are marked those will be signed.
  */
 static int
-sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified,
+sign_uids( KBNODE keyblock, strlist_t locusr, int *ret_modified,
           int local, int nonrevocable, int trust, int interactive )
 {
     int rc = 0;
@@ -527,7 +528,7 @@ sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified,
          }
 
     /* build a list of all signators.
-     *    
+     *
      * We use the CERT flag to request the primary which must always
      * be one which is capable of signing keys.  I can't see a reason
      * why to sign keys using a subkey.  Implementation of USAGE_CERT
@@ -546,7 +547,7 @@ sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified,
        byte trust_depth=0,trust_value=0;
 
        if(local || nonrevocable || trust ||
-          opt.cert_policy_url || opt.cert_notation_data)
+          opt.cert_policy_url || opt.cert_notations)
          force_v4=1;
 
        /* we have to use a copy of the sk, because make_keysig_packet
@@ -704,7 +705,7 @@ sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified,
                      {
                        tty_printf(_("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
                           this key at all. */
@@ -1097,7 +1098,7 @@ sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified,
  * We use only one passphrase for all keys.
  */
 static int
-change_passphrase( KBNODE keyblock )
+change_passphrase (KBNODE keyblock, int *r_err)
 {
     int rc = 0;
     int changed=0;
@@ -1115,11 +1116,11 @@ change_passphrase( KBNODE keyblock )
     sk = node->pkt->pkt.secret_key;
 
     for (any = 0, node=keyblock; node; node = node->next) {
-       if (node->pkt->pkttype == PKT_SECRET_KEY 
+       if (node->pkt->pkttype == PKT_SECRET_KEY
             || node->pkt->pkttype == PKT_SECRET_SUBKEY) {
            PKT_secret_key *tmpsk = node->pkt->pkt.secret_key;
             if (!(tmpsk->is_protected
-                  && (tmpsk->protect.s2k.mode == 1001 
+                  && (tmpsk->protect.s2k.mode == 1001
                       || tmpsk->protect.s2k.mode == 1002))) {
                 any = 1;
                 break;
@@ -1131,7 +1132,7 @@ change_passphrase( KBNODE keyblock )
                       "no passphrase to change.\n"));
         goto leave;
     }
-        
+
     /* See how to handle this key.  */
     switch( is_secret_key_protected( sk ) ) {
       case -1:
@@ -1150,7 +1151,15 @@ change_passphrase( KBNODE keyblock )
            no_primary_secrets = 1;
        }
        else {
+            u32 keyid[2];
+
            tty_printf(_("Key is protected.\n"));
+
+            /* Clear the passphrase cache so that the user is required
+               to enter the old passphrase.  */
+            keyid_from_sk (sk, keyid);
+            passphrase_clear_cache (keyid, NULL, 0);
+
            rc = check_secret_key( sk, 0 );
            if( !rc )
                passphrase = get_last_passphrase();
@@ -1163,7 +1172,7 @@ change_passphrase( KBNODE keyblock )
        if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
            PKT_secret_key *subsk = node->pkt->pkt.secret_key;
             if ( !(subsk->is_protected
-                   && (subsk->protect.s2k.mode == 1001 
+                   && (subsk->protect.s2k.mode == 1001
                        || subsk->protect.s2k.mode == 1002))) {
                 set_next_passphrase( passphrase );
                 rc = check_secret_key( subsk, 0 );
@@ -1184,11 +1193,17 @@ change_passphrase( KBNODE keyblock )
 
        set_next_passphrase( NULL );
        for(;;) {
+            int canceled;
+
            s2k->mode = opt.s2k_mode;
            s2k->hash_algo = S2K_DIGEST_ALGO;
            dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo,
-                                     s2k, 2, errtext, NULL);
-           if( !dek ) {
+                                     s2k, 2, errtext, &canceled);
+            if (!dek && canceled) {
+                rc = GPG_ERR_CANCELED;
+                break;
+            }
+           else if( !dek ) {
                errtext = N_("passphrase not correctly repeated; try again");
                tty_printf ("%s.\n", _(errtext));
            }
@@ -1214,7 +1229,7 @@ change_passphrase( KBNODE keyblock )
                    if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
                        PKT_secret_key *subsk = node->pkt->pkt.secret_key;
                         if ( !(subsk->is_protected
-                               && (subsk->protect.s2k.mode == 1001 
+                               && (subsk->protect.s2k.mode == 1001
                                    || subsk->protect.s2k.mode == 1002))) {
                             subsk->protect.algo = dek->algo;
                             subsk->protect.s2k = *s2k;
@@ -1226,7 +1241,17 @@ change_passphrase( KBNODE keyblock )
                    log_error("protect_secret_key failed: %s\n",
                               g10_errstr(rc) );
                else
+                  {
+                    u32 keyid[2];
+
+                    /* Clear the cahce again so that the user is
+                       required to enter the new passphrase at the
+                       next operation.  */
+                    keyid_from_sk (sk, keyid);
+                    passphrase_clear_cache (keyid, NULL, 0);
+
                    changed++;
+                  }
                break;
            }
        }
@@ -1237,6 +1262,8 @@ change_passphrase( KBNODE keyblock )
   leave:
     xfree( passphrase );
     set_next_passphrase( NULL );
+    if (r_err)
+      *r_err = rc;
     return changed && !rc;
 }
 
@@ -1339,8 +1366,9 @@ enum cmdids
     cmdSAVE, cmdADDUID, cmdADDPHOTO, cmdDELUID, cmdADDKEY, cmdDELKEY,
     cmdADDREVOKER, cmdTOGGLE, cmdSELKEY, cmdPASSWD, cmdTRUST, cmdPREF,
     cmdEXPIRE, cmdBACKSIGN, cmdENABLEKEY, cmdDISABLEKEY, cmdSHOWPREF,
-    cmdSETPREF, cmdPREFKS, cmdINVCMD, cmdSHOWPHOTO, cmdUPDTRUST, cmdCHKTRUST,
-    cmdADDCARDKEY, cmdKEYTOCARD, cmdBKUPTOCARD, cmdCLEAN, cmdMINIMIZE, cmdNOP
+    cmdSETPREF, cmdPREFKS, cmdNOTATION, cmdINVCMD, cmdSHOWPHOTO, cmdUPDTRUST,
+    cmdCHKTRUST, cmdADDCARDKEY, cmdKEYTOCARD, cmdBKUPTOCARD, cmdCLEAN,
+    cmdMINIMIZE, cmdNOP
   };
 
 static struct
@@ -1350,7 +1378,7 @@ static struct
   int flags;
   const char *desc;
 } cmds[] =
-  { 
+  {
     { "quit"    , cmdQUIT      , 0, N_("quit this menu") },
     { "q"       , cmdQUIT      , 0, NULL   },
     { "save"    , cmdSAVE      , 0, N_("save and quit") },
@@ -1363,6 +1391,7 @@ 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,
       N_("sign selected user IDs [* see below for related commands]") },
@@ -1392,9 +1421,9 @@ static struct
 #ifdef ENABLE_CARD_SUPPORT
     { "addcardkey", cmdADDCARDKEY , KEYEDIT_NOT_SK|KEYEDIT_NEED_SK,
       N_("add a key to a smartcard") },
-    { "keytocard", cmdKEYTOCARD , KEYEDIT_NEED_SK|KEYEDIT_ONLY_SK, 
+    { "keytocard", cmdKEYTOCARD , KEYEDIT_NEED_SK|KEYEDIT_ONLY_SK,
       N_("move a key to a smartcard")},
-    { "bkuptocard", cmdBKUPTOCARD , KEYEDIT_NEED_SK|KEYEDIT_ONLY_SK, 
+    { "bkuptocard", cmdBKUPTOCARD , KEYEDIT_NEED_SK|KEYEDIT_ONLY_SK,
       N_("move a backup key to a smartcard")},
 #endif /*ENABLE_CARD_SUPPORT*/
 
@@ -1421,7 +1450,9 @@ static struct
     { "updpref" , cmdSETPREF   , KEYEDIT_NOT_SK|KEYEDIT_NEED_SK, NULL },
 
     { "keyserver",cmdPREFKS    , KEYEDIT_NOT_SK|KEYEDIT_NEED_SK,
-      N_("set preferred keyserver URL for the selected user IDs")},
+      N_("set the preferred keyserver URL for the selected user IDs")},
+    { "notation", cmdNOTATION  , KEYEDIT_NOT_SK|KEYEDIT_NEED_SK,
+      N_("set a notation for the selected user IDs")},
     { "passwd"  , cmdPASSWD    , KEYEDIT_NOT_SK|KEYEDIT_NEED_SK,
       N_("change the passphrase") },
     /* Alias */
@@ -1483,6 +1514,8 @@ keyedit_completion(const char *text, int start, int end)
   /* If we are at the start of a line, we try and command-complete.
      If not, just do nothing for now. */
 
+  (void)end;
+
   if(start==0)
     return rl_completion_matches(text,command_generator);
 
@@ -1494,8 +1527,8 @@ keyedit_completion(const char *text, int start, int end)
 
 
 void
-keyedit_menu( const char *username, STRLIST locusr,
-             STRLIST commands, int quiet, int seckey_check )
+keyedit_menu( const char *username, strlist_t locusr,
+             strlist_t commands, int quiet, int seckey_check )
 {
     enum cmdids cmd = 0;
     int rc = 0;
@@ -1533,7 +1566,7 @@ keyedit_menu( const char *username, STRLIST locusr,
 #endif
 
     /* Get the public key */
-    rc = get_pubkey_byname (NULL, username, &keyblock, &kdbhd, 1);
+    rc = get_pubkey_byname (NULL, NULL, username, &keyblock, &kdbhd, 1, 1);
     if( rc )
        goto leave;
     if( fix_keyblock( keyblock ) )
@@ -1541,6 +1574,10 @@ keyedit_menu( const char *username, STRLIST locusr,
     if( collapse_uids( &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);
 
     if(seckey_check)
       {/* see whether we have a matching secret key */
@@ -1552,7 +1589,7 @@ keyedit_menu( const char *username, STRLIST locusr,
             size_t an;
 
             fingerprint_from_pk (pk, afp, &an);
-            while (an < MAX_FINGERPRINT_LEN) 
+            while (an < MAX_FINGERPRINT_LEN)
                 afp[an++] = 0;
             rc = keydb_search_fpr (sec_kdbhd, afp);
         }
@@ -1613,8 +1650,10 @@ keyedit_menu( const char *username, STRLIST locusr,
            }
            if( !have_commands )
              {
+#ifdef HAVE_LIBREADLINE
                tty_enable_completion(keyedit_completion);
-               answer = cpr_get_no_help("keyedit.prompt", _("Command> "));
+#endif
+               answer = cpr_get_no_help("keyedit.prompt", "gpg> ");
                cpr_kill_prompt();
                tty_disable_completion();
              }
@@ -1706,12 +1745,22 @@ keyedit_menu( const char *username, STRLIST locusr,
            if(strlen(arg_string)==NAMEHASH_LEN*2)
              redisplay=menu_select_uid_namehash(cur_keyblock,arg_string);
            else
-             redisplay=menu_select_uid(cur_keyblock,arg_number);
+              {
+                if (*arg_string == '*'
+                    && (!arg_string[1] || spacep (arg_string+1)))
+                  arg_number = -1; /* Select all. */
+                redisplay = menu_select_uid (cur_keyblock, arg_number);
+              }
            break;
 
          case cmdSELKEY:
-           if( menu_select_key( cur_keyblock, arg_number ) )
+            {
+              if (*arg_string == '*'
+                  && (!arg_string[1] || spacep (arg_string+1)))
+                arg_number = -1; /* Select all. */
+              if (menu_select_key( cur_keyblock, arg_number))
                redisplay = 1;
+            }
            break;
 
          case cmdCHECK:
@@ -1786,7 +1835,7 @@ keyedit_menu( const char *username, STRLIST locusr,
               {
                 tty_printf(
                    _("This command is not allowed while in %s mode.\n"),
-                  RFC2440?"OpenPGP":PGP2?"PGP2":"RFC-1991");
+                  compliance_option_string());
                 break;
               }
            photo=1;
@@ -1861,14 +1910,17 @@ keyedit_menu( const char *username, STRLIST locusr,
            switch ( count_selected_keys (sec_keyblock) )
              {
              case 0:
-               if (cpr_get_answer_is_yes("keyedit.keytocard.use_primary",
-                                    _("Really move the primary key? (y/N) ")))
+                if (cpr_get_answer_is_yes
+                    ("keyedit.keytocard.use_primary",
+                     /* TRANSLATORS: Please take care: This is about
+                        moving the key and not about removing it.  */
+                     _("Really move the primary key? (y/N) ")))
                  node = sec_keyblock;
                break;
              case 1:
                for (node = sec_keyblock; node; node = node->next )
                  {
-                   if (node->pkt->pkttype == PKT_SECRET_SUBKEY 
+                   if (node->pkt->pkttype == PKT_SECRET_SUBKEY
                        && node->flag & NODFLG_SELKEY)
                      break;
                  }
@@ -1920,15 +1972,15 @@ keyedit_menu( const char *username, STRLIST locusr,
                             fname, strerror(errno));
                 break;
               }
-            
+
             /* Parse and check that file.  */
             pkt = xmalloc (sizeof *pkt);
             init_packet (pkt);
             rc = parse_packet (a, pkt);
             iobuf_close (a);
             iobuf_ioctl (NULL, 2, 0, (char*)fname); /* (invalidate cache).  */
-            if (!rc 
-                && pkt->pkttype != PKT_SECRET_KEY 
+            if (!rc
+                && pkt->pkttype != PKT_SECRET_KEY
                 && pkt->pkttype != PKT_SECRET_SUBKEY)
               rc = G10ERR_NO_SECKEY;
             if (rc)
@@ -2071,15 +2123,15 @@ keyedit_menu( const char *username, STRLIST locusr,
            break;
 
          case cmdPASSWD:
-           if( change_passphrase( sec_keyblock ) )
+           if (change_passphrase (sec_keyblock, NULL))
                sec_modified = 1;
            break;
 
          case cmdTRUST:
            if(opt.trust_model==TM_EXTERNAL)
              {
-               tty_printf(_("Owner trust may not be set while "
-                            "using an user provided trust database\n"));
+               tty_printf (_("Owner trust may not be set while "
+                             "using a user provided trust database\n"));
                break;
              }
 
@@ -2150,6 +2202,16 @@ keyedit_menu( const char *username, STRLIST locusr,
              }
            break;
 
+         case cmdNOTATION:
+           if( menu_set_notation ( *arg_string?arg_string:NULL,
+                                   keyblock, sec_keyblock ) )
+             {
+               merge_keys_and_selfsig( keyblock );
+               modified = 1;
+               redisplay = 1;
+             }
+           break;
+
          case cmdNOP:
            break;
 
@@ -2173,11 +2235,13 @@ keyedit_menu( const char *username, STRLIST locusr,
            break;
 
          case cmdCLEAN:
-           redisplay=modified=menu_clean(keyblock,0);
+           if(menu_clean(keyblock,0))
+             redisplay=modified=1;
            break;
 
          case cmdMINIMIZE:
-           redisplay=modified=menu_clean(keyblock,1);
+           if(menu_clean(keyblock,1))
+             redisplay=modified=1;
            break;
 
          case cmdQUIT:
@@ -2238,7 +2302,100 @@ keyedit_menu( const char *username, STRLIST locusr,
 }
 
 
-\f
+/* Change the passphrase of the secret key identified by USERNAME.  */
+void
+keyedit_passwd (const char *username)
+{
+  gpg_error_t err;
+  PKT_public_key *pk;
+  unsigned char fpr[MAX_FINGERPRINT_LEN];
+  size_t fprlen;
+  KEYDB_HANDLE kdh = NULL;
+  KBNODE keyblock = NULL;
+
+  pk = xtrycalloc (1, sizeof *pk);
+  if (!pk)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+  err = get_pubkey_byname (NULL, pk, username, NULL, NULL, 1, 1);
+  if (err)
+    goto leave;
+  fingerprint_from_pk (pk, fpr, &fprlen);
+  while (fprlen < MAX_FINGERPRINT_LEN)
+    fpr[fprlen++] = 0;
+
+  kdh = keydb_new (1);
+  if (!kdh)
+    {
+      err = gpg_error (GPG_ERR_GENERAL);
+      goto leave;
+    }
+
+  err = keydb_search_fpr (kdh, fpr);
+  if (err == -1 || gpg_err_code (err) == GPG_ERR_EOF)
+    err = gpg_error (GPG_ERR_NO_SECKEY);
+  if (err)
+    goto leave;
+
+  err = keydb_get_keyblock (kdh, &keyblock);
+  if (err)
+    goto leave;
+
+  if (!change_passphrase (keyblock, &err))
+    goto leave;
+
+  err = keydb_update_keyblock (kdh, keyblock);
+  if (err)
+    log_error( _("update secret failed: %s\n"), gpg_strerror (err));
+
+ leave:
+  release_kbnode (keyblock);
+  if (pk)
+    free_public_key (pk);
+  keydb_release (kdh);
+  if (err)
+    {
+      log_info ("error changing the passphrase for `%s': %s\n",
+                username, gpg_strerror (err));
+      write_status_error ("keyedit.passwd", gpg_err_code (err));
+    }
+  else
+    write_status_text (STATUS_SUCCESS, "keyedit.passwd");
+}
+
+
+static void
+tty_print_notations(int indent,PKT_signature *sig)
+{
+  int first=1;
+  struct notation *notation,*nd;
+
+  if(indent<0)
+    {
+      first=0;
+      indent=-indent;
+    }
+
+  notation=sig_to_notation(sig);
+
+  for(nd=notation;nd;nd=nd->next)
+    {
+      if(!first)
+       tty_printf("%*s",indent,"");
+      else
+       first=0;
+
+      tty_print_utf8_string(nd->name,strlen(nd->name));
+      tty_printf("=");
+      tty_print_utf8_string(nd->value,strlen(nd->value));
+      tty_printf("\n");
+    }
+
+  free_notation(notation);
+}
+
 /****************
  * show preferences of a public keyblock.
  */
@@ -2266,37 +2423,36 @@ show_prefs (PKT_user_id *uid, PKT_signature *selfsig, int verbose)
        tty_printf (_("Cipher: "));
         for(i=any=0; prefs[i].type; i++ ) {
             if( prefs[i].type == PREFTYPE_SYM ) {
-                const char *s = cipher_algo_to_string (prefs[i].value);
-                
                 if (any)
                     tty_printf (", ");
                 any = 1;
                 /* We don't want to display strings for experimental algos */
-                if (s && prefs[i].value < 100 )
-                    tty_printf ("%s", s );
+                if (!openpgp_cipher_test_algo (prefs[i].value)
+                    && prefs[i].value < 100 )
+                    tty_printf ("%s",
+                                openpgp_cipher_algo_name (prefs[i].value));
                 else
                     tty_printf ("[%d]", prefs[i].value);
                 if (prefs[i].value == CIPHER_ALGO_3DES )
                     des_seen = 1;
-            }    
+            }
         }
         if (!des_seen) {
             if (any)
                 tty_printf (", ");
-            tty_printf ("%s",cipher_algo_to_string(CIPHER_ALGO_3DES));
+            tty_printf ("%s", openpgp_cipher_algo_name (CIPHER_ALGO_3DES));
         }
         tty_printf ("\n     ");
        tty_printf (_("Digest: "));
         for(i=any=0; prefs[i].type; i++ ) {
             if( prefs[i].type == PREFTYPE_HASH ) {
-                const char *s = digest_algo_to_string (prefs[i].value);
-                
                 if (any)
                     tty_printf (", ");
                 any = 1;
                 /* We don't want to display strings for experimental algos */
-                if (s && prefs[i].value < 100 )
-                    tty_printf ("%s", s );
+                if (!gcry_md_test_algo (prefs[i].value)
+                    && prefs[i].value < 100 )
+                    tty_printf ("%s", gcry_md_algo_name (prefs[i].value) );
                 else
                     tty_printf ("[%d]", prefs[i].value);
                 if (prefs[i].value == DIGEST_ALGO_SHA1 )
@@ -2306,14 +2462,14 @@ show_prefs (PKT_user_id *uid, PKT_signature *selfsig, int verbose)
         if (!sha1_seen) {
             if (any)
                 tty_printf (", ");
-            tty_printf ("%s",digest_algo_to_string(DIGEST_ALGO_SHA1));
+            tty_printf ("%s", gcry_md_algo_name (DIGEST_ALGO_SHA1));
         }
         tty_printf ("\n     ");
        tty_printf (_("Compression: "));
         for(i=any=0; prefs[i].type; i++ ) {
             if( prefs[i].type == PREFTYPE_ZIP ) {
                 const char *s=compress_algo_to_string(prefs[i].value);
-                
+
                 if (any)
                     tty_printf (", ");
                 any = 1;
@@ -2368,6 +2524,13 @@ show_prefs (PKT_user_id *uid, PKT_signature *selfsig, int verbose)
                tty_print_utf8_string(pref_ks,pref_ks_len);
                tty_printf("\n");
              }
+
+           if(selfsig->flags.notation)
+             {
+               tty_printf ("     ");
+               tty_printf(_("Notations: "));
+               tty_print_notations(5+strlen(_("Notations: ")),selfsig);
+             }
          }
     }
     else {
@@ -2439,16 +2602,27 @@ show_key_with_all_names_colon (KBNODE keyblock)
              && !(opt.fast_list_mode || opt.no_expensive_trust_checks ))
            putchar(get_ownertrust_info (pk));
           putchar(':');
+          putchar (':');
+          putchar (':');
+          /* Print capabilities.  */
+          if ( (pk->pubkey_usage & PUBKEY_USAGE_ENC) )
+            putchar ('e');
+          if ( (pk->pubkey_usage & PUBKEY_USAGE_SIG) )
+            putchar ('s');
+          if ( (pk->pubkey_usage & PUBKEY_USAGE_CERT) )
+            putchar ('c');
+          if ( (pk->pubkey_usage & PUBKEY_USAGE_AUTH) )
+            putchar ('a');
           putchar('\n');
-          
+
           print_fingerprint (pk, NULL, 0);
          print_revokers(pk);
         }
     }
-  
+
     /* the user ids */
     i = 0;
-    for (node = keyblock; node; node = node->next) 
+    for (node = keyblock; node; node = node->next)
       {
        if ( node->pkt->pkttype == PKT_USER_ID )
           {
@@ -2492,7 +2666,7 @@ show_key_with_all_names_colon (KBNODE keyblock)
             if (pk_version>3 || uid->selfsigversion>3)
               {
                 const prefitem_t *prefs = uid->prefs;
-                
+
                 for (j=0; prefs && prefs[j].type; j++)
                   {
                     if (j)
@@ -2501,12 +2675,12 @@ show_key_with_all_names_colon (KBNODE keyblock)
                             prefs[j].type == PREFTYPE_HASH  ? 'H' :
                             prefs[j].type == PREFTYPE_ZIP ? 'Z':'?',
                             prefs[j].value);
-                  } 
+                  }
                 if (uid->flags.mdc)
                   printf (",mdc");
                 if (!uid->flags.ks_modify)
                   printf (",no-ks-modify");
-              } 
+              }
             putchar (':');
             /* flags */
             printf ("%d,", i);
@@ -2595,7 +2769,6 @@ show_key_with_all_names( KBNODE keyblock, int only_marked, int with_revoker,
     KBNODE node;
     int i;
     int do_warn = 0;
-    byte pk_version=0;
     PKT_public_key *primary=NULL;
 
     if (opt.with_colons)
@@ -2627,15 +2800,15 @@ show_key_with_all_names( KBNODE keyblock, int only_marked, int with_revoker,
                     do_warn = 1;
                 }
 
-               pk_version=pk->version;
                primary=pk;
            }
 
            if(pk->is_revoked)
              {
                char *user=get_user_id_string_native(pk->revoked.keyid);
-               const char *algo=pubkey_algo_to_string(pk->revoked.algo);
-               tty_printf(_("This key was revoked on %s by %s key %s\n"),
+               const char *algo = gcry_pk_algo_name (pk->revoked.algo);
+               tty_printf (_("The following key was revoked on"
+                              " %s by %s key %s\n"),
                           revokestr_from_pk(pk),algo?algo:"?",user);
                xfree(user);
              }
@@ -2649,9 +2822,9 @@ show_key_with_all_names( KBNODE keyblock, int only_marked, int with_revoker,
                    {
                      u32 r_keyid[2];
                      char *user;
-                     const char *algo=
-                       pubkey_algo_to_string(pk->revkey[i].algid);
+                     const char *algo;
 
+                      algo = gcry_pk_algo_name (pk->revkey[i].algid);
                      keyid_from_fingerprint(pk->revkey[i].fpr,
                                             MAX_FINGERPRINT_LEN,r_keyid);
 
@@ -2705,7 +2878,7 @@ show_key_with_all_names( KBNODE keyblock, int only_marked, int with_revoker,
                        tty_printf(_("trust: %s"), otrust);
                        tty_printf("%*s",width,"");
                      }
-                   
+
                    tty_printf(_("validity: %s"), trust );
                    tty_printf("\n");
                  }
@@ -2741,7 +2914,7 @@ show_key_with_all_names( KBNODE keyblock, int only_marked, int with_revoker,
             if (sk->is_protected && sk->protect.s2k.mode == 1002)
               {
                tty_printf("                     ");
-                tty_printf(_("card-no: ")); 
+                tty_printf(_("card-no: "));
                 if (sk->protect.ivlen == 16
                     && !memcmp (sk->protect.iv, "\xD2\x76\x00\x01\x24\x01", 6))
                   { /* This is an OpenPGP card. */
@@ -2767,7 +2940,7 @@ show_key_with_all_names( KBNODE keyblock, int only_marked, int with_revoker,
     if (do_warn)
         tty_printf (_("Please note that the shown key validity"
                       " is not necessarily correct\n"
-                      "unless you restart the program.\n")); 
+                      "unless you restart the program.\n"));
 }
 
 
@@ -2787,7 +2960,7 @@ show_basic_key_info ( KBNODE keyblock )
       if (node->pkt->pkttype == PKT_PUBLIC_KEY)
         {
           PKT_public_key *pk = node->pkt->pkt.public_key;
-          
+
           /* Note, we use the same format string as in other show
              functions to make the translation job easier. */
           tty_printf ("%s  %4u%c/%s  ",
@@ -2826,7 +2999,7 @@ show_basic_key_info ( KBNODE keyblock )
         {
           PKT_user_id *uid = node->pkt->pkt.user_id;
           ++i;
-     
+
           tty_printf ("     ");
           if (uid->is_revoked)
             tty_printf("[%s] ",_("revoked"));
@@ -2976,7 +3149,7 @@ menu_adduid( KBNODE pub_keyblock, KBNODE sec_keyblock,
 
       uid = generate_photo_id(pk,photo_name);
     } else
-      uid = generate_user_id();
+      uid = generate_user_id (pub_keyblock);
     if( !uid )
        return 0;
 
@@ -3181,21 +3354,26 @@ menu_clean(KBNODE keyblock,int self_only)
              else
                reason=_("invalid");
 
-             tty_printf("User ID \"%s\" compacted: %s\n",user,reason);
+             tty_printf (_("User ID \"%s\" compacted: %s\n"), user, reason);
 
              modified=1;
            }
          else if(sigs)
            {
              tty_printf(sigs==1?
-                        "User ID \"%s\": %d signature removed\n":
-                        "User ID \"%s\": %d signatures removed\n",
+                        _("User ID \"%s\": %d signature removed\n") :
+                        _("User ID \"%s\": %d signatures removed\n"),
                         user,sigs);
 
              modified=1;
            }
          else
-           tty_printf(_("User ID \"%s\": already clean\n"),user);
+           {
+             tty_printf (self_only==1?
+                          _("User ID \"%s\": already minimized\n") :
+                          _("User ID \"%s\": already clean\n"),
+                          user);
+           }
 
          xfree(user);
        }
@@ -3330,7 +3508,7 @@ menu_addrevoker( KBNODE pub_keyblock, KBNODE sec_keyblock, int sensitive )
         GnuPG both can handle a designated revokation from a
         subkey. */
       revoker_pk->req_usage=PUBKEY_USAGE_CERT;
-      rc=get_pubkey_byname(revoker_pk,answer,NULL,NULL,1);
+      rc=get_pubkey_byname (NULL, revoker_pk,answer,NULL,NULL,1, 1);
       if(rc)
        {
          log_error (_("key \"%s\" not found: %s\n"),answer,g10_errstr(rc));
@@ -3587,6 +3765,7 @@ menu_backsign(KBNODE pub_keyblock,KBNODE sec_keyblock)
   PKT_public_key *main_pk;
   PKT_secret_key *main_sk,*sub_sk=NULL;
   KBNODE node;
+  u32 timestamp;
 
   assert(pub_keyblock->pkt->pkttype==PKT_PUBLIC_KEY);
   assert(sec_keyblock->pkt->pkttype==PKT_SECRET_KEY);
@@ -3596,6 +3775,10 @@ menu_backsign(KBNODE pub_keyblock,KBNODE sec_keyblock)
   main_sk=copy_secret_key(NULL,sec_keyblock->pkt->pkt.secret_key);
   keyid_from_pk(main_pk,NULL);
 
+  /* We use the same timestamp for all backsigs so that we don't
+     reveal information about the used machine.  */
+  timestamp = make_timestamp ();
+
   for(node=pub_keyblock;node;node=node->next)
     {
       PKT_public_key *sub_pk=NULL;
@@ -3609,10 +3792,21 @@ menu_backsign(KBNODE pub_keyblock,KBNODE sec_keyblock)
        }
 
       /* Find a signing subkey with no backsig */
-      if(node->pkt->pkttype==PKT_PUBLIC_SUBKEY
-         && (node->pkt->pkt.public_key->pubkey_usage&PUBKEY_USAGE_SIG)
-         && !node->pkt->pkt.public_key->backsig)
-        sub_pk=node->pkt->pkt.public_key;
+      if(node->pkt->pkttype==PKT_PUBLIC_SUBKEY)
+       {
+         if(node->pkt->pkt.public_key->pubkey_usage&PUBKEY_USAGE_SIG)
+           {
+             if(node->pkt->pkt.public_key->backsig)
+               tty_printf(_("signing subkey %s is already cross-certified\n"),
+                          keystr_from_pk(node->pkt->pkt.public_key));
+             else
+               sub_pk=node->pkt->pkt.public_key;
+           }
+         else
+           tty_printf(_("subkey %s does not sign and so does"
+                        " not need to be cross-certified\n"),
+                      keystr_from_pk(node->pkt->pkt.public_key));
+       }
 
       if(!sub_pk)
        continue;
@@ -3641,16 +3835,21 @@ menu_backsign(KBNODE pub_keyblock,KBNODE sec_keyblock)
          }
 
       if(!sub_sk)
-       continue;
+       {
+         tty_printf(_("no secret subkey for public subkey %s - ignoring\n"),
+                    keystr_from_pk(sub_pk));
+         continue;
+       }
 
       /* Now finally find the matching selfsig on the secret subkey.
         We can't use chosen_selfsig here (it's not set for secret
         keys), so we just pick the selfsig with the right class.
         This is what menu_expire does as well. */
       for(node2=node2->next;
-         node2 && node2->pkt->pkttype==PKT_SIGNATURE;
+         node2 && node2->pkt->pkttype!=PKT_SECRET_SUBKEY;
          node2=node2->next)
-       if(node2->pkt->pkt.signature->version>=4
+       if(node2->pkt->pkttype==PKT_SIGNATURE
+          && node2->pkt->pkt.signature->version>=4
           && node2->pkt->pkt.signature->keyid[0]==sig_pk->pkt->pkt.signature->keyid[0]
           && node2->pkt->pkt.signature->keyid[1]==sig_pk->pkt->pkt.signature->keyid[1]
           && node2->pkt->pkt.signature->sig_class==sig_pk->pkt->pkt.signature->sig_class)
@@ -3659,18 +3858,16 @@ menu_backsign(KBNODE pub_keyblock,KBNODE sec_keyblock)
            break;
          }
 
-      if(!sig_sk)
-       continue;
-
       /* Now we can get to work.  We have a main key and secret part,
-        a signing subkey with signature and secret part with
+        a signing subkey with signature and secret part possibly with
         signature. */
 
       passphrase=get_last_passphrase();
       set_next_passphrase(passphrase);
       xfree(passphrase);
 
-      rc=make_backsig(sig_pk->pkt->pkt.signature,main_pk,sub_pk,sub_sk);
+      rc = make_backsig (sig_pk->pkt->pkt.signature, main_pk, sub_pk, sub_sk,
+                         timestamp);
       if(rc==0)
        {
          PKT_signature *newsig;
@@ -3692,13 +3889,16 @@ menu_backsign(KBNODE pub_keyblock,KBNODE sec_keyblock)
              xfree(sig_pk->pkt);
              sig_pk->pkt=newpkt;
 
-             /* Put the new sig into place on the seckey */
-             newpkt=xmalloc_clear(sizeof(*newpkt));
-             newpkt->pkttype=PKT_SIGNATURE;
-             newpkt->pkt.signature=copy_signature(NULL,newsig);
-             free_packet(sig_sk->pkt);
-             xfree(sig_sk->pkt);
-             sig_sk->pkt=newpkt;
+             if(sig_sk)
+               {
+                 /* Put the new sig into place on the seckey */
+                 newpkt=xmalloc_clear(sizeof(*newpkt));
+                 newpkt->pkttype=PKT_SIGNATURE;
+                 newpkt->pkt.signature=copy_signature(NULL,newsig);
+                 free_packet(sig_sk->pkt);
+                 xfree(sig_sk->pkt);
+                 sig_sk->pkt=newpkt;
+               }
 
              modified=1;
            }
@@ -3736,7 +3936,7 @@ change_primary_uid_cb ( PKT_signature *sig, void *opaque )
     delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PRIMARY_UID);
 
     /* if opaque is set,we want to set the primary id */
-    if (opaque) { 
+    if (opaque) {
         buf[0] = 1;
         build_sig_subpkt (sig, SIGSUBPKT_PRIMARY_UID, buf, 1 );
     }
@@ -3869,7 +4069,7 @@ menu_set_primary_uid ( KBNODE pub_keyblock, KBNODE sec_keyblock )
 }
 
 
-/* 
+/*
  * Set preferences to new values for the selected user IDs
  */
 static int
@@ -3920,7 +4120,7 @@ menu_set_preferences (KBNODE pub_keyblock, KBNODE sec_keyblock )
                xfree(user);
              }
              else {
-               /* This is a selfsignature which is to be replaced 
+               /* This is a selfsignature which is to be replaced
                  * We have to ignore v3 signatures because they are
                  * not able to carry the preferences */
                PKT_signature *newsig;
@@ -3950,7 +4150,7 @@ menu_set_preferences (KBNODE pub_keyblock, KBNODE sec_keyblock )
             }
        }
     }
-    
+
     free_secret_key( sk );
     return modified;
 }
@@ -4099,52 +4299,276 @@ menu_set_keyserver_url (const char *url,
   return modified;
 }
 
-
-/****************
- * Select one user id or remove all selection if index is 0.
- * Returns: True if the selection changed;
- */
 static int
-menu_select_uid( KBNODE keyblock, int idx )
+menu_set_notation(const char *string,KBNODE pub_keyblock,KBNODE sec_keyblock)
 {
-    KBNODE node;
-    int i;
+  PKT_secret_key *sk;    /* copy of the main sk */
+  PKT_public_key *main_pk;
+  PKT_user_id *uid;
+  KBNODE node;
+  u32 keyid[2];
+  int selected, select_all;
+  int modified = 0;
+  char *answer;
+  struct notation *notation;
 
-    /* first check that the index is valid */
-    if( idx ) {
-       for( i=0, node = keyblock; node; node = node->next ) {
-           if( node->pkt->pkttype == PKT_USER_ID ) {
-               if( ++i == idx )
-                   break;
-           }
-       }
-       if( !node ) {
-           tty_printf(_("No user ID with index %d\n"), idx );
-           return 0;
+  no_primary_warning(pub_keyblock);
+
+  if(string)
+    answer=xstrdup(string);
+  else
+    {
+      answer=cpr_get_utf8("keyedit.add_notation",
+                         _("Enter the notation: "));
+      if(answer[0]=='\0' || answer[0]=='\004')
+       {
+         xfree(answer);
+         return 0;
        }
     }
-    else { /* reset all */
-       for( i=0, node = keyblock; node; node = node->next ) {
-           if( node->pkt->pkttype == PKT_USER_ID )
-               node->flag &= ~NODFLG_SELUID;
+
+  if(ascii_strcasecmp(answer,"none")==0
+     || ascii_strcasecmp(answer,"-")==0)
+    notation=NULL; /* delete them all */
+  else
+    {
+      notation=string_to_notation(answer,0);
+      if(!notation)
+       {
+         xfree(answer);
+         return 0;
        }
-       return 1;
     }
-    /* and toggle the new index */
-    for( i=0, node = keyblock; node; node = node->next ) {
-       if( node->pkt->pkttype == PKT_USER_ID ) {
-           if( ++i == idx ) {
-               if( (node->flag & NODFLG_SELUID) )
-                   node->flag &= ~NODFLG_SELUID;
-               else
-                   node->flag |= NODFLG_SELUID;
+
+  xfree(answer);
+
+  select_all = !count_selected_uids (pub_keyblock);
+
+  node = find_kbnode( sec_keyblock, PKT_SECRET_KEY );
+  sk = copy_secret_key( NULL, node->pkt->pkt.secret_key);
+
+  /* Now we can actually change the self signature(s) */
+  main_pk = NULL;
+  uid = NULL;
+  selected = 0;
+  for ( node=pub_keyblock; node; node = node->next )
+    {
+      if ( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
+       break; /* ready */
+
+      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_USER_ID )
+       {
+         uid = node->pkt->pkt.user_id;
+         selected = select_all || (node->flag & NODFLG_SELUID);
+       }
+      else if ( main_pk && uid && selected
+               && node->pkt->pkttype == PKT_SIGNATURE )
+       {
+         PKT_signature *sig = node->pkt->pkt.signature;
+         if ( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1]
+              && (uid && (sig->sig_class&~3) == 0x10)
+              && sig->flags.chosen_selfsig)
+           {
+             char *user=utf8_to_native(uid->name,strlen(uid->name),0);
+             if( sig->version < 4 )
+               log_info(_("skipping v3 self-signature on user ID \"%s\"\n"),
+                        user);
+             else
+               {
+                 PKT_signature *newsig;
+                 PACKET *newpkt;
+                 int rc,skip=0,addonly=1;
+
+                 if(sig->flags.notation)
+                   {
+                     tty_printf("Current notations for user ID \"%s\":\n",
+                                user);
+                     tty_print_notations(-9,sig);
+                   }
+                 else
+                   {
+                     tty_printf("No notations on user ID \"%s\"\n",user);
+                     if(notation==NULL)
+                       {
+                         /* There are no current notations, so there
+                            is no point in trying to un-set them. */
+                         continue;
+                       }
+                   }
+
+                 if(notation)
+                   {
+                     struct notation *n;
+                     int deleting=0;
+
+                     notation->next=sig_to_notation(sig);
+
+                     for(n=notation->next;n;n=n->next)
+                       if(strcmp(n->name,notation->name)==0)
+                         {
+                           if(notation->value)
+                             {
+                               if(strcmp(n->value,notation->value)==0)
+                                 {
+                                   if(notation->flags.ignore)
+                                     {
+                                       /* Value match with a delete
+                                          flag. */
+                                       n->flags.ignore=1;
+                                       deleting=1;
+                                     }
+                                   else
+                                     {
+                                       /* Adding the same notation
+                                          twice, so don't add it at
+                                          all. */
+                                       skip=1;
+                                       tty_printf("Skipping notation:"
+                                                  " %s=%s\n",
+                                                  notation->name,
+                                                  notation->value);
+                                       break;
+                                     }
+                                 }
+                             }
+                           else
+                             {
+                               /* No value, so it means delete. */
+                               n->flags.ignore=1;
+                               deleting=1;
+                             }
+
+                           if(n->flags.ignore)
+                             {
+                               tty_printf("Removing notation: %s=%s\n",
+                                          n->name,n->value);
+                               addonly=0;
+                             }
+                         }
+
+                     if(!notation->flags.ignore && !skip)
+                       tty_printf("Adding notation: %s=%s\n",
+                                  notation->name,notation->value);
+
+                     /* We tried to delete, but had no matches */
+                     if(notation->flags.ignore && !deleting)
+                       continue;
+                   }
+                 else
+                   {
+                     tty_printf("Removing all notations\n");
+                     addonly=0;
+                   }
+
+                 if(skip
+                    || (!addonly
+                        && !cpr_get_answer_is_yes("keyedit.confirm_notation",
+                                                  _("Proceed? (y/N) "))))
+                   continue;
+
+                 rc = update_keysig_packet (&newsig, sig,
+                                            main_pk, uid, NULL,
+                                            sk,
+                                            keygen_add_notations, notation );
+                 if( rc )
+                   {
+                     log_error ("update_keysig_packet failed: %s\n",
+                                g10_errstr(rc));
+                     free_secret_key( sk );
+                     free_notation(notation);
+                     xfree(user);
+                     return 0;
+                   }
+
+                 /* replace the packet */
+                 newpkt = xmalloc_clear( sizeof *newpkt );
+                 newpkt->pkttype = PKT_SIGNATURE;
+                 newpkt->pkt.signature = newsig;
+                 free_packet( node->pkt );
+                 xfree( node->pkt );
+                 node->pkt = newpkt;
+                 modified = 1;
+
+                 if(notation)
+                   {
+                     /* Snip off the notation list from the sig */
+                     free_notation(notation->next);
+                     notation->next=NULL;
+                   }
+
+                 xfree(user);
+               }
            }
        }
     }
 
-    return 1;
+  free_notation(notation);
+  free_secret_key( sk );
+  return modified;
+}
+
+
+/*
+ * Select one user id or remove all selection if IDX is 0 or select
+ * all if IDX is -1.  Returns: True if the selection changed.
+ */
+static int
+menu_select_uid (KBNODE keyblock, int idx)
+{
+  KBNODE node;
+  int i;
+
+  if (idx == -1) /* Select all. */
+    {
+      for (node = keyblock; node; node = node->next)
+        if (node->pkt->pkttype == PKT_USER_ID)
+          node->flag |= NODFLG_SELUID;
+      return 1;
+    }
+  else if (idx) /* Toggle.  */
+    {
+      for (i=0, node = keyblock; node; node = node->next)
+        {
+          if (node->pkt->pkttype == PKT_USER_ID)
+            if (++i == idx)
+              break;
+       }
+      if (!node)
+        {
+          tty_printf (_("No user ID with index %d\n"), idx );
+          return 0;
+       }
+
+      for (i=0, node = keyblock; node; node = node->next)
+        {
+          if (node->pkt->pkttype == PKT_USER_ID)
+            {
+              if (++i == idx)
+                {
+                  if ((node->flag & NODFLG_SELUID))
+                    node->flag &= ~NODFLG_SELUID;
+                  else
+                    node->flag |= NODFLG_SELUID;
+                }
+            }
+        }
+    }
+  else /* Unselect all */
+    {
+      for (node = keyblock; node; node = node->next)
+        if (node->pkt->pkttype == PKT_USER_ID)
+          node->flag &= ~NODFLG_SELUID;
+    }
+
+  return 1;
 }
 
+
 /* Search in the keyblock for a uid that matches namehash */
 static int
 menu_select_uid_namehash( KBNODE keyblock, const char *namehash )
@@ -4186,50 +4610,58 @@ menu_select_uid_namehash( KBNODE keyblock, const char *namehash )
 
 /****************
  * Select secondary keys
- * Returns: True if the selection changed;
+ * Returns: True if the selection changed.
  */
 static int
-menu_select_key( KBNODE keyblock, int idx )
+menu_select_key (KBNODE keyblock, int idx)
 {
-    KBNODE node;
-    int i;
+  KBNODE node;
+  int i;
 
-    /* first check that the index is valid */
-    if( idx ) {
-       for( i=0, node = keyblock; node; node = node->next ) {
-           if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
-               || node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
-               if( ++i == idx )
-                   break;
-           }
-       }
-       if( !node ) {
-           tty_printf(_("No subkey with index %d\n"), idx );
-           return 0;
-       }
+  if (idx == -1) /* Select all.  */
+    {
+      for (node = keyblock; node; node = node->next)
+        if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
+            || node->pkt->pkttype == PKT_SECRET_SUBKEY)
+          node->flag |= NODFLG_SELKEY;
     }
-    else { /* reset all */
-       for( i=0, node = keyblock; node; node = node->next ) {
-           if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
-               || node->pkt->pkttype == PKT_SECRET_SUBKEY )
-               node->flag &= ~NODFLG_SELKEY;
-       }
-       return 1;
+  else if (idx) /* Toggle selection.  */
+    {
+      for (i=0, node = keyblock; node; node = node->next)
+        {
+          if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
+              || node->pkt->pkttype == PKT_SECRET_SUBKEY)
+            if (++i == idx)
+              break;
+        }
+      if (!node)
+        {
+          tty_printf (_("No subkey with index %d\n"), idx );
+          return 0;
+        }
+
+      for (i=0, node = keyblock; node; node = node->next)
+        {
+          if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
+              || node->pkt->pkttype == PKT_SECRET_SUBKEY )
+            if (++i == idx)
+              {
+                if ((node->flag & NODFLG_SELKEY))
+                  node->flag &= ~NODFLG_SELKEY;
+                else
+                  node->flag |= NODFLG_SELKEY;
+              }
+        }
     }
-    /* and set the new index */
-    for( i=0, node = keyblock; node; node = node->next ) {
-       if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
-           || node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
-           if( ++i == idx ) {
-               if( (node->flag & NODFLG_SELKEY) )
-                   node->flag &= ~NODFLG_SELKEY;
-               else
-                   node->flag |= NODFLG_SELKEY;
-           }
-       }
+  else /* Unselect all. */
+    {
+      for (node = keyblock; node; node = node->next)
+        if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
+            || node->pkt->pkttype == PKT_SECRET_SUBKEY)
+          node->flag &= ~NODFLG_SELKEY;
     }
 
-    return 1;
+  return 1;
 }
 
 
@@ -4382,6 +4814,36 @@ menu_revsig( KBNODE keyblock )
 
     assert(keyblock->pkt->pkttype==PKT_PUBLIC_KEY);
 
+    /* First check whether we have any signatures at all.  */
+    any = 0;
+    for (node = keyblock; node; node = node->next )
+      {
+       node->flag &= ~(NODFLG_SELSIG | NODFLG_MARK_A);
+       if (node->pkt->pkttype == PKT_USER_ID) {
+          if (node->flag&NODFLG_SELUID || all)
+            skip = 0;
+          else
+            skip = 1;
+       }
+       else if (!skip && node->pkt->pkttype == PKT_SIGNATURE
+                 && ((sig = node->pkt->pkt.signature),
+                     !seckey_available(sig->keyid)     ))
+         {
+           if ((sig->sig_class&~3) == 0x10)
+             {
+                any = 1;
+                break;
+              }
+         }
+      }
+
+    if (!any)
+      {
+        tty_printf (_("Not signed by you.\n"));
+        return 0;
+      }
+
+
     /* FIXME: detect duplicates here  */
     tty_printf(_("You have signed these user IDs on key %s:\n"),
               keystr_from_pk(keyblock->pkt->pkt.public_key));
@@ -4800,7 +5262,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,NULL);
+                     show_photos(&uid->attribs[i],1,pk,NULL,uid);
                    }
                }
            }