Minor fixes
[gnupg.git] / g10 / keyedit.c
index d9c3df0..0fab9c8 100644 (file)
@@ -1,5 +1,6 @@
 /* keyedit.c - keyedit stuff
- * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003,
+ *               2004 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -40,8 +41,9 @@
 #include "ttyio.h"
 #include "status.h"
 #include "i18n.h"
+#include "keyserver-internal.h"
 
-static void show_prefs( PKT_user_id *uid, int verbose );
+static void show_prefs( PKT_user_id *uid, PKT_signature *selfsig, int verbose);
 static void show_key_with_all_names( 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 );
@@ -54,6 +56,8 @@ static int menu_addrevoker( KBNODE pub_keyblock,
 static int menu_expire( KBNODE pub_keyblock, KBNODE sec_keyblock );
 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_select_uid( KBNODE keyblock, int idx );
 static int menu_select_key( KBNODE keyblock, int idx );
 static int count_uids( KBNODE keyblock );
@@ -63,6 +67,7 @@ static int count_selected_uids( KBNODE keyblock );
 static int real_uids_left( KBNODE keyblock );
 static int count_selected_keys( KBNODE keyblock );
 static int menu_revsig( KBNODE keyblock );
+static int menu_revuid( KBNODE keyblock, KBNODE sec_keyblock );
 static int menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock );
 static int enable_disable_key( KBNODE keyblock, int disable );
 static void menu_showphoto( KBNODE keyblock );
@@ -85,8 +90,104 @@ static int update_trust=0;
 struct sign_attrib {
     int non_exportable,non_revocable;
     struct revocation_reason_info *reason;
+    byte trust_depth,trust_value;
+    char *trust_regexp;
 };
 
+
+#ifdef ENABLE_CARD_SUPPORT
+/* Given a node SEC_NODE with a secret key or subkey, locate the
+   corresponding public key from pub_keyblock. */
+static PKT_public_key *
+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;
+  if (sec_node->pkt->pkttype != PKT_SECRET_SUBKEY)
+    return NULL;
+  sk = sec_node->pkt->pkt.secret_key;
+  for (; node; node = node->next)
+    if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+      {
+        pk = node->pkt->pkt.public_key;
+        if (pk->keyid[0] == sk->keyid[0] && pk->keyid[1] == sk->keyid[1])
+          return pk;
+      }
+      
+  return NULL;
+}
+#endif /* ENABLE_CARD_SUPPORT */
+
+
+/* TODO: Fix duplicated code between here and the check-sigs/list-sigs
+   code in keylist.c. */
+static int
+print_and_check_one_sig_colon( KBNODE keyblock, KBNODE node,
+                              int *inv_sigs, int *no_key, int *oth_err,
+                              int *is_selfsig, int print_without_key )
+{
+  PKT_signature *sig = node->pkt->pkt.signature;
+  int rc, sigrc;
+
+  /* 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)))
+    {
+    case 0:
+      node->flag &= ~(NODFLG_BADSIG|NODFLG_NOKEY|NODFLG_SIGERR);
+      sigrc = '!';
+      break;
+    case G10ERR_BAD_SIGN:
+      node->flag = NODFLG_BADSIG;
+      sigrc = '-';
+      if( inv_sigs )
+       ++*inv_sigs;
+      break;
+    case G10ERR_NO_PUBKEY:
+    case G10ERR_UNU_PUBKEY:
+      node->flag = NODFLG_NOKEY;
+      sigrc = '?';
+      if( no_key )
+       ++*no_key;
+      break;
+    default:
+      node->flag = NODFLG_SIGERR;
+      sigrc = '%';
+      if( oth_err )
+       ++*oth_err;
+      break;
+    }
+
+  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);
+
+      if(sig->trust_depth || sig->trust_value)
+       printf("%d %d",sig->trust_depth,sig->trust_value);
+
+      printf(":");
+
+      if(sig->trust_regexp)
+       print_string(stdout,sig->trust_regexp,strlen(sig->trust_regexp),':');
+
+      printf("::%02x%c\n",sig->sig_class,sig->flags.exportable?'x':'l');
+
+      if(opt.show_subpackets)
+       print_subpackets_colon(sig);
+    }
+
+  return (sigrc == '!');
+}
+
+
 /****************
  * Print information about a signature, check it and return true
  * if the signature is okay. NODE must be a signature packet.
@@ -100,6 +201,9 @@ print_and_check_one_sig( KBNODE keyblock, KBNODE node,
     int rc, sigrc;
     int is_rev = sig->sig_class == 0x30;
 
+    /* TODO: Make sure a cached sig record here still has the pk that
+       issued it.  See also keylist.c:list_keyblock_print */
+
     switch( (rc = check_key_signature( keyblock, node, is_selfsig)) ) {
       case 0:
        node->flag &= ~(NODFLG_BADSIG|NODFLG_NOKEY|NODFLG_SIGERR);
@@ -126,7 +230,7 @@ print_and_check_one_sig( KBNODE keyblock, KBNODE node,
        break;
     }
     if( sigrc != '?' || print_without_key ) {
-        tty_printf("%s%c%c %c%c%c%c%c %08lX %s   ",
+        tty_printf("%s%c%c %c%c%c%c%c%c %s %s",
                   is_rev? "rev":"sig",sigrc,
                   (sig->sig_class-0x10>0 &&
                    sig->sig_class-0x10<4)?'0'+sig->sig_class-0x10:' ',
@@ -135,7 +239,12 @@ print_and_check_one_sig( KBNODE keyblock, KBNODE node,
                   sig->flags.policy_url?'P':' ',
                   sig->flags.notation?'N':' ',
                    sig->flags.expired?'X':' ',
-                  (ulong)sig->keyid[1], datestr_from_sig(sig));
+                  (sig->trust_depth>9)?'T':
+                  (sig->trust_depth>0)?'0'+sig->trust_depth:' ',
+                  keystr(sig->keyid),datestr_from_sig(sig));
+       if(opt.list_options&LIST_SHOW_SIG_EXPIRE)
+         tty_printf(" %s",expirestr_from_sig(sig));
+       tty_printf("  ");
        if( sigrc == '%' )
            tty_printf("[%s] ", g10_errstr(rc) );
        else if( sigrc == '?' )
@@ -144,19 +253,26 @@ print_and_check_one_sig( KBNODE keyblock, KBNODE node,
            tty_printf( is_rev? _("[revocation]")
                              : _("[self-signature]") );
        }
-       else {
+       else
+         {
            size_t n;
            char *p = get_user_id( sig->keyid, &n );
-           tty_print_utf8_string2( p, n, 40 );
+           tty_print_utf8_string2(p, n, opt.screen_columns-keystrlen()-26-
+                              ((opt.list_options&LIST_SHOW_SIG_EXPIRE)?11:0));
            m_free(p);
-       }
+         }
        tty_printf("\n");
 
-       if(sig->flags.policy_url && opt.show_policy_url)
-         show_policy_url(sig,3);
+       if(sig->flags.policy_url && (opt.list_options&LIST_SHOW_POLICY_URLS))
+         show_policy_url(sig,3,0);
+
+       if(sig->flags.notation && (opt.list_options&LIST_SHOW_NOTATIONS))
+         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.notation && opt.show_notation)
-         show_notation(sig,3);
+       if(sig->flags.pref_ks && (opt.list_options&LIST_SHOW_KEYSERVER_URLS))
+         show_keyserver_url(sig,3,0);
     }
 
     return (sigrc == '!');
@@ -234,8 +350,6 @@ check_all_keysigs( KBNODE keyblock, int only_selected )
 }
 
 
-
-
 static int
 sign_mk_attrib( PKT_signature *sig, void *opaque )
 {
@@ -255,10 +369,123 @@ sign_mk_attrib( PKT_signature *sig, void *opaque )
     if( attrib->reason )
        revocation_reason_build_cb( sig, attrib->reason );
 
+    if(attrib->trust_depth)
+      {
+       /* Not critical.  If someone doesn't understand trust sigs,
+          this can still be a valid regular signature. */
+        buf[0] = attrib->trust_depth;
+       buf[1] = attrib->trust_value;
+       build_sig_subpkt(sig,SIGSUBPKT_TRUST,buf,2);
+
+       /* Critical.  If someone doesn't understands regexps, this
+          whole sig should be invalid.  Note the +1 for the length -
+          regexps are null terminated. */
+       if(attrib->trust_regexp)
+         build_sig_subpkt(sig,SIGSUBPKT_FLAG_CRITICAL|SIGSUBPKT_REGEXP,
+                          attrib->trust_regexp,
+                          strlen(attrib->trust_regexp)+1);
+      }
+
     return 0;
 }
 
+static void
+trustsig_prompt(byte *trust_value,byte *trust_depth,char **regexp)
+{
+  char *p;
+
+  *trust_value=0;
+  *trust_depth=0;
+  *regexp=NULL;
+
+  /* Same string as pkclist.c:do_edit_ownertrust */
+  tty_printf(_("Please decide how far you trust this user to correctly verify"
+              " other users' keys\n(by looking at passports, checking"
+              " fingerprints from different sources, etc.)\n"));
+  tty_printf("\n");
+  tty_printf (_("  %d = I trust marginally\n"), 1);
+  tty_printf (_("  %d = I trust fully\n"), 2);
+  tty_printf("\n");
+
+  while(*trust_value==0)
+    {
+      p = cpr_get("trustsig_prompt.trust_value",_("Your selection? "));
+      trim_spaces(p);
+      cpr_kill_prompt();
+      /* 60 and 120 are as per RFC2440 */
+      if(p[0]=='1' && !p[1])
+       *trust_value=60;
+      else if(p[0]=='2' && !p[1])
+       *trust_value=120;
+      m_free(p);
+    }
+
+  tty_printf("\n");
+
+  tty_printf(_(
+             "Please enter the depth of this trust signature.\n"
+             "A depth greater than 1 allows the key you are signing to make\n"
+             "trust signatures on your behalf.\n"));
+  tty_printf("\n");
+
+  while(*trust_depth==0)
+    {
+      p = cpr_get("trustsig_prompt.trust_depth",_("Your selection? "));
+      trim_spaces(p);
+      cpr_kill_prompt();
+      *trust_depth=atoi(p);
+      m_free(p);
+    }
+
+  tty_printf("\n");
 
+  tty_printf(_("Please enter a domain to restrict this signature, "
+              "or enter for none.\n"));
+
+  tty_printf("\n");
+
+  p=cpr_get("trustsig_prompt.trust_regexp",_("Your selection? "));
+  trim_spaces(p);
+  cpr_kill_prompt();
+
+  if(strlen(p)>0)
+    {
+      char *q=p;
+      int regexplen=100,ind;
+
+      *regexp=m_alloc(regexplen);
+
+      /* Now mangle the domain the user entered into a regexp.  To do
+        this, \-escape everything that isn't alphanumeric, and attach
+        "<[^>]+[@.]" to the front, and ">$" to the end. */
+
+      strcpy(*regexp,"<[^>]+[@.]");
+      ind=strlen(*regexp);
+
+      while(*q)
+       {
+         if(!((*q>='A' && *q<='Z')
+              || (*q>='a' && *q<='z') || (*q>='0' && *q<='9')))
+           (*regexp)[ind++]='\\';
+
+         (*regexp)[ind++]=*q;
+
+         if((regexplen-ind)<3)
+           {
+             regexplen+=100;
+             *regexp=m_realloc(*regexp,regexplen);
+           }
+
+         q++;
+       }
+
+      (*regexp)[ind]='\0';
+      strcat(*regexp,">$");
+    }
+
+  m_free(p);
+  tty_printf("\n");
+}
 
 /****************
  * Loop over all locusr and and sign the uids after asking.
@@ -267,7 +494,7 @@ sign_mk_attrib( PKT_signature *sig, void *opaque )
  */
 static int
 sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified,
-          int local , int nonrevocable )
+          int local, int nonrevocable, int trust )
 {
     int rc = 0;
     SK_LIST sk_list = NULL;
@@ -279,7 +506,7 @@ sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified,
     int all_v3=1;
 
     /* Are there any non-v3 sigs on this key already? */
-    if(opt.pgp2)
+    if(PGP2)
       for(node=keyblock;node;node=node->next)
        if(node->pkt->pkttype==PKT_SIGNATURE &&
           node->pkt->pkt.signature->version>3)
@@ -302,12 +529,12 @@ sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified,
     /* loop over all signators */
     for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) {
         u32 sk_keyid[2],pk_keyid[2];
-       size_t n;
-       char *p;
+       char *p,*trust_regexp=NULL;
        int force_v4=0,class=0,selfsig=0;
        u32 duration=0,timestamp=0;
+       byte trust_depth=0,trust_value=0;
 
-       if(local || nonrevocable ||
+       if(local || nonrevocable || trust ||
           opt.cert_policy_url || opt.cert_notation_data)
          force_v4=1;
 
@@ -356,7 +583,9 @@ sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified,
                      {
                        tty_printf(_("User ID \"%s\" is revoked."),user);
 
-                       if(opt.expert)
+                       if(selfsig)
+                         tty_printf("\n");
+                       else if(opt.expert)
                          {
                            tty_printf("\n");
                            /* No, so remove the mark and continue */
@@ -364,18 +593,68 @@ sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified,
                                                      _("Are you sure you "
                                                        "still want to sign "
                                                        "it? (y/N) ")))
-                             uidnode->flag &= ~NODFLG_MARK_A;
+                             {
+                               uidnode->flag &= ~NODFLG_MARK_A;
+                               uidnode=NULL;
+                             }
+                         }
+                       else
+                         {
+                           uidnode->flag &= ~NODFLG_MARK_A;
+                           uidnode=NULL;
+                           tty_printf(_("  Unable to sign.\n"));
+                         }
+                     }
+                   else if(uidnode->pkt->pkt.user_id->is_expired)
+                     {
+                       tty_printf(_("User ID \"%s\" is expired."),user);
+
+                       if(selfsig)
+                         tty_printf("\n");
+                       else if(opt.expert)
+                         {
+                           tty_printf("\n");
+                           /* No, so remove the mark and continue */
+                           if(!cpr_get_answer_is_yes("sign_uid.expire_okay",
+                                                     _("Are you sure you "
+                                                       "still want to sign "
+                                                       "it? (y/N) ")))
+                             {
+                               uidnode->flag &= ~NODFLG_MARK_A;
+                               uidnode=NULL;
+                             }
                          }
                        else
                          {
                            uidnode->flag &= ~NODFLG_MARK_A;
+                           uidnode=NULL;
                            tty_printf(_("  Unable to sign.\n"));
                          }
                      }
-                   else if(!uidnode->pkt->pkt.user_id->created)
+                   else if(!uidnode->pkt->pkt.user_id->created && !selfsig)
                      {
-                       tty_printf(_("WARNING: user ID \"%s\" is not "
-                                    "self-signed.\n"),user);
+                       tty_printf(_("User ID \"%s\" is not self-signed."),
+                                  user);
+
+                       if(opt.expert)
+                         {
+                           tty_printf("\n");
+                           /* No, so remove the mark and continue */
+                           if(!cpr_get_answer_is_yes("sign_uid.nosig_okay",
+                                                     _("Are you sure you "
+                                                       "still want to sign "
+                                                       "it? (y/N) ")))
+                             {
+                               uidnode->flag &= ~NODFLG_MARK_A;
+                               uidnode=NULL;
+                             }
+                         }
+                       else
+                         {
+                           uidnode->flag &= ~NODFLG_MARK_A;
+                           uidnode=NULL;
+                           tty_printf(_("  Unable to sign.\n"));
+                         }
                      }
 
                    m_free(user);
@@ -408,10 +687,35 @@ sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified,
                            {
                              force_v4=1;
                              node->flag|=NODFLG_DELSIG;
+                             m_free(user);
                              continue;
                            }
                      }
 
+                   /* Is the current signature expired? */
+                   if(node->pkt->pkt.signature->flags.expired)
+                     {
+                       tty_printf(_("Your current signature on \"%s\"\n"
+                                    "has expired.\n"),user);
+
+                       if(cpr_get_answer_is_yes("sign_uid.replace_expired_okay",
+                                                _("Do you want to issue a "
+                                                  "new signature to replace "
+                                                  "the expired one? (y/N) ")))
+                         {
+                           /* Mark these for later deletion.  We
+                               don't want to delete them here, just in
+                               case the replacement signature doesn't
+                               happen for some reason.  We only delete
+                               these after the replacement is already
+                               in place. */
+
+                           node->flag|=NODFLG_DELSIG;
+                           m_free(user);
+                           continue;
+                         }
+                     }
+
                    if(!node->pkt->pkt.signature->flags.exportable && !local)
                      {
                        /* It's a local sig, and we want to make a
@@ -432,6 +736,7 @@ sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified,
                                in place. */
 
                            node->flag|=NODFLG_DELSIG;
+                           m_free(user);
                            continue;
                          }
                      }
@@ -440,12 +745,23 @@ sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified,
                     * 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 %08lX\n"),
-                                user,(ulong)sk_keyid[1] );
+                             "\"%s\" was already locally signed by key %s\n"),
+                                user,keystr_from_sk(sk));
                     else
-                      tty_printf(_(
-                         "\"%s\" was already signed by key %08lX\n"),
-                                 user,(ulong)sk_keyid[1] );
+                      tty_printf(_("\"%s\" was already signed by key %s\n"),
+                                 user,keystr_from_sk(sk));
+
+                   if(opt.expert
+                      && cpr_get_answer_is_yes("sign_uid.dupe_okay",
+                                               _("Do you want to sign it "
+                                                 "again anyway? (y/N) ")))
+                     {
+                       /* Don't delete the old sig here since this is
+                          an --expert thing. */
+                       m_free(user);
+                       continue;
+                     }
+
                     sprintf (buf, "%08lX%08lX",
                              (ulong)sk->keyid[0], (ulong)sk->keyid[1] );
                     write_status_text (STATUS_ALREADY_SIGNED, buf);
@@ -455,12 +771,14 @@ sign_uids( KBNODE keyblock, STRLIST 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 %08lX\n"),
-                                                 (ulong)sk_keyid[1] );
+       if( !count_uids_with_flag(keyblock, NODFLG_MARK_A) )
+         {
+           tty_printf(_("Nothing to sign with key %s\n"),keystr_from_sk(sk));
            continue;
-       }
+         }
+
        /* Ask whether we really should sign these user id(s) */
        tty_printf("\n");
        show_key_with_all_names( keyblock, 1, 0, 1, 0, 0 );
@@ -526,7 +844,7 @@ sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified,
        /* 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(opt.pgp2 && all_v3 &&
+       if(PGP2 && all_v3 &&
           (sk->version>3 || force_v4) && primary_pk->version<=3)
          {
            tty_printf(_("You may not make an OpenPGP signature on a "
@@ -548,90 +866,111 @@ sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified,
 
        if(selfsig)
          ;
-       else if(opt.batch)
-         class=0x10+opt.def_cert_check_level;
        else
          {
-           char *answer;
+           if(opt.batch || !opt.ask_cert_level)
+             class=0x10+opt.def_cert_level;
+           else
+             {
+               char *answer;
 
-           tty_printf(_("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"),
-                      opt.def_cert_check_level==0?" (default)":"");
-           tty_printf(_("   (1) I have not checked at all.%s\n"),
-                      opt.def_cert_check_level==1?" (default)":"");
-           tty_printf(_("   (2) I have done casual checking.%s\n"),
-                      opt.def_cert_check_level==2?" (default)":"");
-           tty_printf(_("   (3) I have done very careful checking.%s\n"),
-                      opt.def_cert_check_level==3?" (default)":"");
-           tty_printf("\n");
+               tty_printf(_("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"),
+                          opt.def_cert_level==0?" (default)":"");
+               tty_printf(_("   (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"),
+                          opt.def_cert_level==2?" (default)":"");
+               tty_printf(_("   (3) I have done very careful checking.%s\n"),
+                          opt.def_cert_level==3?" (default)":"");
+               tty_printf("\n");
 
-           while(class==0)
-             {
-               answer = cpr_get("sign_uid.class",_("Your selection? "));
-
-               if(answer[0]=='\0')
-                 class=0x10+opt.def_cert_check_level; /* Default */
-               else if(ascii_strcasecmp(answer,"0")==0)
-                 class=0x10; /* Generic */
-               else if(ascii_strcasecmp(answer,"1")==0)
-                 class=0x11; /* Persona */
-               else if(ascii_strcasecmp(answer,"2")==0)
-                 class=0x12; /* Casual */
-               else if(ascii_strcasecmp(answer,"3")==0)
-                 class=0x13; /* Positive */
-               else
-                 tty_printf(_("Invalid selection.\n"));
+               while(class==0)
+                 {
+                   answer = cpr_get("sign_uid.class",_("Your selection? "
+                                       "(enter `?' for more information): "));
+                   if(answer[0]=='\0')
+                     class=0x10+opt.def_cert_level; /* Default */
+                   else if(ascii_strcasecmp(answer,"0")==0)
+                     class=0x10; /* Generic */
+                   else if(ascii_strcasecmp(answer,"1")==0)
+                     class=0x11; /* Persona */
+                   else if(ascii_strcasecmp(answer,"2")==0)
+                     class=0x12; /* Casual */
+                   else if(ascii_strcasecmp(answer,"3")==0)
+                     class=0x13; /* Positive */
+                   else
+                     tty_printf(_("Invalid selection.\n"));
 
-               m_free(answer);
+                   m_free(answer);
+                 }
              }
+
+           if(trust)
+             trustsig_prompt(&trust_value,&trust_depth,&trust_regexp);
          }
 
-       tty_printf(_("Are you really sure that you want to sign this key\n"
-                    "with your key: \""));
-       p = get_user_id( sk_keyid, &n );
-       tty_print_utf8_string( p, n );
-       m_free(p); p = NULL;
-       tty_printf("\"\n");
+       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_sk(sk));
+       m_free(p);
 
        if(selfsig)
          {
-           tty_printf(_("\nThis will be a self-signature.\n"));
+            tty_printf("\n");
+           tty_printf(_("This will be a self-signature.\n"));
 
            if( local )
-             tty_printf(
-                        _("\nWARNING: the signature will not be marked "
+              {
+                tty_printf("\n");
+                tty_printf(
+                        _("WARNING: the signature will not be marked "
                           "as non-exportable.\n"));
+              }
 
            if( nonrevocable )
-             tty_printf(
-                        _("\nWARNING: the signature will not be marked "
+              {
+                tty_printf("\n");
+                tty_printf(
+                        _("WARNING: the signature will not be marked "
                           "as non-revocable.\n"));
+              }
          }
        else
          {
            if( local )
-             tty_printf(
-                    _("\nThe signature will be marked as non-exportable.\n"));
+              {
+                tty_printf("\n");
+                tty_printf(
+                    _("The signature will be marked as non-exportable.\n"));
+              }
 
            if( nonrevocable )
-             tty_printf(
-                     _("\nThe signature will be marked as non-revocable.\n"));
+              {
+                tty_printf("\n");
+                tty_printf(
+                     _("The signature will be marked as non-revocable.\n"));
+              }
 
            switch(class)
              {
              case 0x11:
-               tty_printf(_("\nI have not checked this key at all.\n"));
+                tty_printf("\n");
+               tty_printf(_("I have not checked this key at all.\n"));
                break;
 
              case 0x12:
-               tty_printf(_("\nI have checked this key casually.\n"));
+                tty_printf("\n");
+               tty_printf(_("I have checked this key casually.\n"));
                break;
 
              case 0x13:
-               tty_printf(_("\nI have checked this key very carefully.\n"));
+                tty_printf("\n");
+               tty_printf(_("I have checked this key very carefully.\n"));
                break;
              }
          }
@@ -640,7 +979,8 @@ sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified,
 
        if( opt.batch && opt.answer_yes )
          ;
-       else if( !cpr_get_answer_is_yes("sign_uid.okay", _("Really sign? ")) )
+       else if( !cpr_get_answer_is_yes("sign_uid.okay",
+                                       _("Really sign? (y/N) ")) )
            continue;
 
        /* now we can sign the user ids */
@@ -659,6 +999,9 @@ sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified,
                memset( &attrib, 0, sizeof attrib );
                attrib.non_exportable = local;
                attrib.non_revocable = nonrevocable;
+               attrib.trust_depth = trust_depth;
+               attrib.trust_value = trust_value;
+               attrib.trust_regexp = trust_regexp;
                node->flag &= ~NODFLG_MARK_A;
 
                 /* we force creation of a v4 signature for local
@@ -777,21 +1120,23 @@ change_passphrase( KBNODE keyblock )
        set_next_passphrase( NULL );
        for(;;) {
            s2k->mode = opt.s2k_mode;
-           s2k->hash_algo = opt.s2k_digest_algo;
+           s2k->hash_algo = S2K_DIGEST_ALGO;
            dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo,
-                                     s2k, 2, errtext);
+                                     s2k, 2, errtext, NULL);
            if( !dek ) {
-               errtext = _("passphrase not correctly repeated; try again");
-               tty_printf ("%s.\n", errtext);
+               errtext = N_("passphrase not correctly repeated; try again");
+               tty_printf ("%s.\n", _(errtext));
            }
            else if( !dek->keylen ) {
                rc = 0;
                tty_printf(_( "You don't want a passphrase -"
                            " this is probably a *bad* idea!\n\n"));
                if( cpr_get_answer_is_yes("change_passwd.empty.okay",
-                              _("Do you really want to do this? ")))
+                              _("Do you really want to do this? (y/N) ")))
+                 {
                    changed++;
-               break;
+                   break;
+                 }
            }
            else { /* okay */
                rc = 0;
@@ -869,77 +1214,124 @@ fix_keyblock( KBNODE keyblock )
     return fixed;
 }
 
+static int
+parse_sign_type(const char *str,int *localsig,int *nonrevokesig,int *trustsig)
+{
+  const char *p=str;
+
+  while(*p)
+    {
+      if(ascii_strncasecmp(p,"l",1)==0)
+       {
+         *localsig=1;
+         p++;
+       }
+      else if(ascii_strncasecmp(p,"nr",2)==0)
+       {
+         *nonrevokesig=1;
+         p+=2;
+       }
+      else if(ascii_strncasecmp(p,"t",1)==0)
+       {
+         *trustsig=1;
+         p++;
+       }
+      else
+       return 0;
+    }
+
+  return 1;
+}
+
 /****************
- * Menu driven key editor.  If sign_mode is true semi-automatical signing
- * will be performed. commands are ignore in this case
+ * Menu driven key editor.  If seckey_check is true, then a secret key
+ * that matches username will be looked for.  If it is false, not all
+ * commands will be available.
  *
  * Note: to keep track of some selection we use node->mark MARKBIT_xxxx.
  */
 
+/* Need an SK for this command */
+#define KEYEDIT_NEED_SK 1
+/* Cannot be viewing the SK for this command */
+#define KEYEDIT_NOT_SK  2
+/* Must be viewing the SK for this command */
+#define KEYEDIT_ONLY_SK 4
+/* Match the tail of the string */
+#define KEYEDIT_TAIL_MATCH 8
+
 void
-keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
-                                                   int sign_mode )
+keyedit_menu( const char *username, STRLIST locusr,
+             STRLIST commands, int quiet, int seckey_check )
 {
-    enum cmdids { cmdNONE = 0,
-          cmdQUIT, cmdHELP, cmdFPR, cmdLIST, cmdSELUID, cmdCHECK, cmdSIGN,
-           cmdLSIGN, cmdNRSIGN, cmdNRLSIGN, cmdREVSIG, cmdREVKEY, cmdDELSIG,
-          cmdPRIMARY, cmdDEBUG, cmdSAVE, cmdADDUID, cmdADDPHOTO, cmdDELUID,
-           cmdADDKEY, cmdDELKEY, cmdADDREVOKER, cmdTOGGLE, cmdSELKEY,
-          cmdPASSWD, cmdTRUST, cmdPREF, cmdEXPIRE, cmdENABLEKEY,
-          cmdDISABLEKEY, cmdSHOWPREF, cmdSETPREF, cmdUPDPREF, cmdINVCMD,
-           cmdSHOWPHOTO, cmdUPDTRUST, cmdCHKTRUST, cmdNOP };
-    static struct { const char *name;
-                   enum cmdids id;
-                   int need_sk;
-                   int not_with_sk;
-                   int signmode;
-                   const char *desc;
-                 } cmds[] = {
-       { N_("quit")    , cmdQUIT      , 0,0,1, N_("quit this menu") },
-       { N_("q")       , cmdQUIT      , 0,0,1, NULL   },
-       { N_("save")    , cmdSAVE      , 0,0,1, N_("save and quit") },
-       { N_("help")    , cmdHELP      , 0,0,1, N_("show this help") },
-       {    "?"        , cmdHELP      , 0,0,1, NULL   },
-       { N_("fpr")     , cmdFPR       , 0,0,1, N_("show fingerprint") },
-       { N_("list")    , cmdLIST      , 0,0,1, N_("list key and user IDs") },
-       { N_("l")       , cmdLIST      , 0,0,1, NULL   },
-       { N_("uid")     , cmdSELUID    , 0,0,1, N_("select user ID N") },
-       { N_("key")     , cmdSELKEY    , 0,0,0, N_("select secondary key N") },
-       { N_("check")   , cmdCHECK     , 0,0,1, N_("list signatures") },
-       { N_("c")       , cmdCHECK     , 0,0,1, NULL },
-       { N_("sign")    , cmdSIGN      , 0,1,1, N_("sign the key") },
-       { N_("s")       , cmdSIGN      , 0,1,1, NULL },
-       { N_("lsign")   , cmdLSIGN     , 0,1,1, N_("sign the key locally") },
-       { N_("nrsign")  , cmdNRSIGN    , 0,1,1, N_("sign the key non-revocably") },
-       { N_("nrlsign") , cmdNRLSIGN   , 0,1,1, N_("sign the key locally and non-revocably") },
-       { N_("debug")   , cmdDEBUG     , 0,0,0, NULL },
-       { N_("adduid")  , cmdADDUID    , 1,1,0, N_("add a user ID") },
-       { N_("addphoto"), cmdADDPHOTO  , 1,1,0, N_("add a photo ID") },
-       { N_("deluid")  , cmdDELUID    , 0,1,0, N_("delete user ID") },
-       /* delphoto is really deluid in disguise */
-       { N_("delphoto"), cmdDELUID    , 0,1,0, NULL },
-       { N_("addkey")  , cmdADDKEY    , 1,1,0, N_("add a secondary key") },
-       { N_("delkey")  , cmdDELKEY    , 0,1,0, N_("delete a secondary key") },
-       { N_("addrevoker"),cmdADDREVOKER,1,1,0, N_("add a revocation key") },
-       { N_("delsig")  , cmdDELSIG    , 0,1,0, N_("delete signatures") },
-       { N_("expire")  , cmdEXPIRE    , 1,1,0, N_("change the expire date") },
-        { N_("primary") , cmdPRIMARY   , 1,1,0, N_("flag user ID as primary")},
-       { N_("toggle")  , cmdTOGGLE    , 1,0,0, N_("toggle between secret "
-                                                  "and public key listing") },
-       { N_("t"     )  , cmdTOGGLE    , 1,0,0, NULL },
-       { N_("pref")    , cmdPREF      , 0,1,0, N_("list preferences (expert)") },
-       { N_("showpref"), cmdSHOWPREF  , 0,1,0, N_("list preferences (verbose)") },
-       { N_("setpref") , cmdSETPREF   , 1,1,0, N_("set preference list") },
-       { N_("updpref") , cmdUPDPREF   , 1,1,0, N_("updated preferences") },
-       { N_("passwd")  , cmdPASSWD    , 1,1,0, N_("change the passphrase") },
-       { N_("trust")   , cmdTRUST     , 0,1,0, N_("change the ownertrust") },
-       { N_("revsig")  , cmdREVSIG    , 0,1,0, N_("revoke signatures") },
-       { N_("revkey")  , cmdREVKEY    , 1,1,0, N_("revoke a secondary key") },
-       { N_("disable") , cmdDISABLEKEY, 0,1,0, N_("disable a key") },
-       { N_("enable")  , cmdENABLEKEY , 0,1,0, N_("enable a key") },
-       { N_("showphoto"),cmdSHOWPHOTO , 0,0,0, N_("show photo ID") },
-
-    { NULL, cmdNONE } };
+  enum cmdids
+    { cmdNONE = 0,
+      cmdQUIT, cmdHELP, cmdFPR, cmdLIST, cmdSELUID, cmdCHECK, cmdSIGN,
+      cmdREVSIG, cmdREVKEY, cmdREVUID, cmdDELSIG, cmdPRIMARY, cmdDEBUG,
+      cmdSAVE, cmdADDUID, cmdADDPHOTO, cmdDELUID, cmdADDKEY, cmdDELKEY,
+      cmdADDREVOKER, cmdTOGGLE, cmdSELKEY, cmdPASSWD, cmdTRUST, cmdPREF,
+      cmdEXPIRE, cmdENABLEKEY, cmdDISABLEKEY, cmdSHOWPREF, cmdSETPREF,
+      cmdUPDPREF, cmdPREFKS, cmdINVCMD, cmdSHOWPHOTO, cmdUPDTRUST,
+      cmdCHKTRUST, cmdADDCARDKEY, cmdKEYTOCARD,
+      cmdNOP };
+  static struct
+  {
+    const char *name;
+    enum cmdids id;
+    int flags;
+    const char *desc;
+  } cmds[] =
+    { 
+      { "quit"    , cmdQUIT      , 0, N_("quit this menu") },
+      { "q"       , cmdQUIT      , 0, NULL   },
+      { "save"    , cmdSAVE      , 0, N_("save and quit") },
+      { "help"    , cmdHELP      , 0, N_("show this help") },
+      { "?"       , cmdHELP      , 0, NULL   },
+      { "fpr"     , cmdFPR       , 0, N_("show fingerprint") },
+      { "list"    , cmdLIST      , 0, N_("list key and user IDs") },
+      { "l"       , cmdLIST      , 0, NULL   },
+      { "uid"     , cmdSELUID    , 0, N_("select user ID N") },
+      { "key"     , cmdSELKEY    , 0, N_("select secondary key N") },
+      { "check"   , cmdCHECK     , 0, N_("list signatures") },
+      { "c"       , cmdCHECK     , 0, NULL },
+      { "sign"    , cmdSIGN      , KEYEDIT_NOT_SK|KEYEDIT_TAIL_MATCH, N_("sign the key") },
+      { "s"       , cmdSIGN      , KEYEDIT_NOT_SK, NULL },
+      /* "lsign" will never match since "sign" comes first and it is a
+        tail match.  It is here so it shows up in the help menu. */
+      { "lsign"   , cmdNOP       , 0, N_("sign the key locally") },
+      { "debug"   , cmdDEBUG     , 0, NULL },
+      { "adduid"  , cmdADDUID    , KEYEDIT_NOT_SK|KEYEDIT_NEED_SK, N_("add a user ID") },
+      { "addphoto", cmdADDPHOTO  , KEYEDIT_NOT_SK|KEYEDIT_NEED_SK, N_("add a photo ID") },
+      { "deluid"  , cmdDELUID    , KEYEDIT_NOT_SK, N_("delete user ID") },
+      /* delphoto is really deluid in disguise */
+      { "delphoto", cmdDELUID    , KEYEDIT_NOT_SK, NULL },
+      { "addkey"  , cmdADDKEY    , KEYEDIT_NOT_SK|KEYEDIT_NEED_SK, N_("add a secondary key") },
+#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, N_("move a key to a smartcard")},
+#endif /*ENABLE_CARD_SUPPORT*/
+      { "delkey"  , cmdDELKEY    , KEYEDIT_NOT_SK, N_("delete a secondary key") },
+      { "addrevoker",cmdADDREVOKER,KEYEDIT_NOT_SK|KEYEDIT_NEED_SK, N_("add a revocation key") },
+      { "delsig"  , cmdDELSIG    , KEYEDIT_NOT_SK, N_("delete signatures") },
+      { "expire"  , cmdEXPIRE    , KEYEDIT_NOT_SK|KEYEDIT_NEED_SK, N_("change the expire date") },
+      { "primary" , cmdPRIMARY   , KEYEDIT_NOT_SK|KEYEDIT_NEED_SK, N_("flag user ID as primary")},
+      { "toggle"  , cmdTOGGLE    , KEYEDIT_NEED_SK, N_("toggle between secret and public key listing") },
+      { "t"       , cmdTOGGLE    , KEYEDIT_NEED_SK, NULL },
+      { "pref"    , cmdPREF      , KEYEDIT_NOT_SK, N_("list preferences (expert)")},
+      { "showpref", cmdSHOWPREF  , KEYEDIT_NOT_SK, N_("list preferences (verbose)") },
+      { "setpref" , cmdSETPREF   , KEYEDIT_NOT_SK|KEYEDIT_NEED_SK, N_("set preference list") },
+      { "updpref" , cmdUPDPREF   , KEYEDIT_NOT_SK|KEYEDIT_NEED_SK, N_("updated preferences") },
+      { "keyserver",cmdPREFKS    , KEYEDIT_NOT_SK|KEYEDIT_NEED_SK, N_("set preferred keyserver URL")},
+      { "passwd"  , cmdPASSWD    , KEYEDIT_NOT_SK|KEYEDIT_NEED_SK, N_("change the passphrase") },
+      { "trust"   , cmdTRUST     , KEYEDIT_NOT_SK, N_("change the ownertrust") },
+      { "revsig"  , cmdREVSIG    , KEYEDIT_NOT_SK, N_("revoke signatures") },
+      { "revuid"  , cmdREVUID    , KEYEDIT_NOT_SK|KEYEDIT_NEED_SK, N_("revoke a user ID") },
+      { "revkey"  , cmdREVKEY    , KEYEDIT_NOT_SK|KEYEDIT_NEED_SK, N_("revoke a secondary key") },
+      { "disable" , cmdDISABLEKEY, KEYEDIT_NOT_SK, N_("disable a key") },
+      { "enable"  , cmdENABLEKEY , KEYEDIT_NOT_SK, N_("enable a key") },
+      { "showphoto",cmdSHOWPHOTO , 0, N_("show photo ID") },
+      { NULL, cmdNONE, 0, NULL }
+    };
     enum cmdids cmd = 0;
     int rc = 0;
     KBNODE keyblock = NULL;
@@ -956,29 +1348,24 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
 
     if ( opt.command_fd != -1 )
         ;
-    else if( opt.batch && !have_commands  ) {
-       log_error(_("can't do that in batchmode\n"));
+    else if( opt.batch && !have_commands )
+      {
+       log_error(_("can't do this in batch mode\n"));
        goto leave;
-    }
-
-    if( sign_mode ) {
-       commands = NULL;
-       append_to_strlist( &commands, sign_mode == 1? "sign":
-                          sign_mode == 2?"lsign":
-                          sign_mode == 3?"nrsign":"nrlsign");
-       have_commands = 1;
-    }
+      }
 
     /* get the public key */
-    rc = get_pubkey_byname (NULL, username, &keyblock, &kdbhd);
+    rc = get_pubkey_byname (NULL, username, &keyblock, &kdbhd, 1);
     if( rc )
        goto leave;
     if( fix_keyblock( keyblock ) )
        modified++;
     if( collapse_uids( &keyblock ) )
        modified++;
+    reorder_keyblock(keyblock);
 
-    if( !sign_mode ) {/* see whether we have a matching secret key */
+    if(seckey_check)
+      {/* see whether we have a matching secret key */
         PKT_public_key *pk = keyblock->pkt->pkt.public_key;
 
         sec_kdbhd = keydb_new (1);
@@ -991,28 +1378,30 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
                 afp[an++] = 0;
             rc = keydb_search_fpr (sec_kdbhd, afp);
         }
-       if (!rc) {
+       if (!rc)
+         {
            rc = keydb_get_keyblock (sec_kdbhd, &sec_keyblock);
-           if (rc) {
-               log_error (_("error reading secret keyblock `%s': %s\n"),
-                                               username, g10_errstr(rc));
-           }
-            else {
+           if (rc)
+             {
+               log_error (_("error reading secret keyblock \"%s\": %s\n"),
+                          username, g10_errstr(rc));
+             }
+            else
+             {
                 merge_keys_and_selfsig( sec_keyblock );
                 if( fix_keyblock( sec_keyblock ) )
-                    sec_modified++;
-            }
-       }
+                 sec_modified++;
+             }
+         }
 
         if (rc) {
             sec_keyblock = NULL;
             keydb_release (sec_kdbhd); sec_kdbhd = NULL;
             rc = 0;
         }
-    }
 
-    if( sec_keyblock ) { 
-       tty_printf(_("Secret key is available.\n"));
+       if( sec_keyblock && !quiet )
+         tty_printf(_("Secret key is available.\n"));
     }
 
     toggle = 0;
@@ -1024,11 +1413,12 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
        PKT_public_key *pk=keyblock->pkt->pkt.public_key;
 
        tty_printf("\n");
-       if( redisplay ) {
+       if( redisplay && !quiet )
+         {
            show_key_with_all_names( cur_keyblock, 0, 1, 0, 1, 0 );
            tty_printf("\n");
            redisplay = 0;
-       }
+         }
        do {
            m_free(answer);
            if( have_commands ) {
@@ -1055,7 +1445,7 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
            cmd = cmdLIST;
        else if( *answer == CONTROL_D )
            cmd = cmdQUIT;
-       else if( isdigit( *answer ) ) {
+       else if( digitp(answer ) ) {
            cmd = cmdSELUID;
            arg_number = atoi(answer);
        }
@@ -1068,33 +1458,49 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
                 arg_string = p;
            }
 
-           for(i=0; cmds[i].name; i++ ) {
-               if( !ascii_strcasecmp( answer, cmds[i].name ) )
-                   break;
-           }
-           if( sign_mode && !cmds[i].signmode )
-               cmd = cmdINVCMD;
-           else if( cmds[i].need_sk && !sec_keyblock ) {
+           for(i=0; cmds[i].name; i++ )
+             {
+               if(cmds[i].flags & KEYEDIT_TAIL_MATCH)
+                 {
+                   size_t l=strlen(cmds[i].name);
+                   size_t a=strlen(answer);
+                   if(a>=l)
+                     {
+                       if(ascii_strcasecmp(&answer[a-l],cmds[i].name)==0)
+                         {
+                           answer[a-l]='\0';
+                           break;
+                         }
+                     }
+                 }
+               else if( !ascii_strcasecmp( answer, cmds[i].name ) )
+                 break;
+             }
+           if((cmds[i].flags & KEYEDIT_NEED_SK) && !sec_keyblock )
+             {
                tty_printf(_("Need the secret key to do this.\n"));
                cmd = cmdNOP;
-           }
-           else if( cmds[i].not_with_sk && sec_keyblock && toggle ) {
+             }
+           else if(((cmds[i].flags & KEYEDIT_NOT_SK) && sec_keyblock
+                    && toggle)
+                    ||((cmds[i].flags & KEYEDIT_ONLY_SK) && sec_keyblock
+                      && !toggle))
+             {
                tty_printf(_("Please use the command \"toggle\" first.\n"));
                cmd = cmdNOP;
-           }
+             }
            else
-               cmd = cmds[i].id;
+             cmd = cmds[i].id;
        }
        switch( cmd )  {
          case cmdHELP:
-           for(i=0; cmds[i].name; i++ ) {
-               if( sign_mode && !cmds[i].signmode )
-                   ;
-               else if( cmds[i].need_sk && !sec_keyblock )
-                   ; /* skip if we do not have the secret key */
+           for(i=0; cmds[i].name; i++ )
+             {
+               if((cmds[i].flags & KEYEDIT_NEED_SK) && !sec_keyblock )
+                 ; /* skip if we do not have the secret key */
                else if( cmds[i].desc )
-                   tty_printf("%-10s %s\n", cmds[i].name, _(cmds[i].desc) );
-           }
+                 tty_printf("%-10s %s\n", cmds[i].name, _(cmds[i].desc) );
+             }
            break;
 
          case cmdLIST:
@@ -1123,40 +1529,49 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
            break;
 
          case cmdSIGN: /* sign (only the public key) */
-         case cmdLSIGN: /* sign (only the public key) */
-         case cmdNRSIGN: /* sign (only the public key) */
-         case cmdNRLSIGN: /* sign (only the public key) */
-           if( pk->is_revoked )
-             {
-               tty_printf(_("Key is revoked."));
+           {
+             int localsig=0,nonrevokesig=0,trustsig=0;
 
-               if(opt.expert)
-                 {
-                   tty_printf("  ");
-                   if(!cpr_get_answer_is_yes("keyedit.sign_revoked.okay",
-                                             _("Are you sure you still want "
-                                               "to sign it? (y/N) ")))
+             if( pk->is_revoked )
+               {
+                 tty_printf(_("Key is revoked."));
+
+                 if(opt.expert)
+                   {
+                     tty_printf("  ");
+                     if(!cpr_get_answer_is_yes("keyedit.sign_revoked.okay",
+                                               _("Are you sure you still want"
+                                                 " to sign it? (y/N) ")))
+                       break;
+                   }
+                 else
+                   {
+                     tty_printf(_("  Unable to sign.\n"));
                      break;
-                 }
-               else
-                 {
-                   tty_printf(_("  Unable to sign.\n"));
-                   break;
-                 }
-             }
+                   }
+               }
 
-           if( count_uids(keyblock) > 1 && !count_selected_uids(keyblock) ) {
-               if( !cpr_get_answer_is_yes("keyedit.sign_all.okay",
-                                          _("Really sign all user IDs? ")) ) {
-                   tty_printf(_("Hint: Select the user IDs to sign\n"));
-                   break;
+             if( count_uids(keyblock) > 1 && !count_selected_uids(keyblock) )
+               {
+                 if( !cpr_get_answer_is_yes("keyedit.sign_all.okay",
+                                            _("Really sign all user IDs?"
+                                              " (y/N) ")))
+                   {
+                     tty_printf(_("Hint: Select the user IDs to sign\n"));
+                     break;
+                   }
                }
+
+             /* What sort of signing are we doing? */
+             if(!parse_sign_type(answer,&localsig,&nonrevokesig,&trustsig))
+               {
+                 tty_printf(_("Unknown signature type `%s'\n"),answer);
+                 break;
+               }
+
+             sign_uids(keyblock, locusr, &modified,
+                       localsig, nonrevokesig, trustsig);
            }
-           if( !sign_uids( keyblock, locusr, &modified,
-                           (cmd == cmdLSIGN) || (cmd == cmdNRLSIGN),
-                           (cmd == cmdNRSIGN) || (cmd==cmdNRLSIGN))
-               && sign_mode )
-               goto do_cmd_save;
            break;
 
          case cmdDEBUG:
@@ -1170,23 +1585,25 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
            break;
 
          case cmdADDPHOTO:
-            if (opt.rfc2440 || opt.rfc1991 || opt.pgp2)
+            if (RFC2440 || RFC1991 || PGP2)
               {
                 tty_printf(
                    _("This command is not allowed while in %s mode.\n"),
-                  opt.rfc2440?"OpenPGP":opt.pgp2?"PGP2":"RFC-1991");
+                  RFC2440?"OpenPGP":PGP2?"PGP2":"RFC-1991");
                 break;
               }
            photo=1;
            /* fall through */
 
          case cmdADDUID:
-           if( menu_adduid( keyblock, sec_keyblock, photo ) ) {
+           if( menu_adduid( keyblock, sec_keyblock, photo ) )
+             {
+               update_trust = 1;
                redisplay = 1;
                sec_modified = modified = 1;
                merge_keys_and_selfsig( sec_keyblock );
                merge_keys_and_selfsig( keyblock );
-           }
+             }
            break;
 
          case cmdDELUID: {
@@ -1196,10 +1613,9 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
                    tty_printf(_("You must select at least one user ID.\n"));
                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(
-                           "keyedit.remove.uid.okay",
-                       n1 > 1? _("Really remove all selected user IDs? ")
-                             : _("Really remove this user ID? ")
+               else if( cpr_get_answer_is_yes("keyedit.remove.uid.okay",
+               n1 > 1? _("Really remove all selected user IDs? (y/N) ")
+                           : _("Really remove this user ID? (y/N) ")
                       ) ) {
                    menu_deluid( keyblock, sec_keyblock );
                    redisplay = 1;
@@ -1232,17 +1648,60 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
            }
            break;
 
+#ifdef ENABLE_CARD_SUPPORT
+         case cmdADDCARDKEY:
+           if (card_generate_subkey (keyblock, sec_keyblock)) {
+               redisplay = 1;
+               sec_modified = modified = 1;
+               merge_keys_and_selfsig( sec_keyblock );
+               merge_keys_and_selfsig( keyblock );
+           }
+           break;
+
+        case cmdKEYTOCARD:
+         {
+           KBNODE node=NULL;
+           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) ")))
+                 node = sec_keyblock;
+               break;
+             case 1:
+               for (node = sec_keyblock; node; node = node->next )
+                 {
+                   if (node->pkt->pkttype == PKT_SECRET_SUBKEY 
+                       && node->flag & NODFLG_SELKEY)
+                     break;
+                 }
+               break;
+             default:
+               tty_printf(_("You must select exactly one key.\n"));
+               break;
+             }
+           if (node)
+             {
+               PKT_public_key *xxpk = find_pk_from_sknode (keyblock, node);
+               if (card_store_subkey (node, xxpk?xxpk->pubkey_usage:0))
+                 {
+                   redisplay = 1;
+                   sec_modified = 1;
+                 }
+             }
+         }
+          break;
+#endif /* ENABLE_CARD_SUPPORT */
 
          case cmdDELKEY: {
                int n1;
 
                if( !(n1=count_selected_keys( keyblock )) )
                    tty_printf(_("You must select at least one key.\n"));
-               else if( sec_keyblock && !cpr_get_answer_is_yes(
-                           "keyedit.remove.subkey.okay",
+               else if( !cpr_get_answer_is_yes( "keyedit.remove.subkey.okay",
                       n1 > 1?
-                       _("Do you really want to delete the selected keys? "):
-                       _("Do you really want to delete this key? ")
+                  _("Do you really want to delete the selected keys? (y/N) "):
+                       _("Do you really want to delete this key? (y/N) ")
                       ))
                    ;
                else {
@@ -1270,6 +1729,25 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
            }
            break;
 
+         case cmdREVUID: {
+               int n1;
+
+               if( !(n1=count_selected_uids(keyblock)) )
+                   tty_printf(_("You must select at least one user ID.\n"));
+               else if( cpr_get_answer_is_yes(
+                           "keyedit.revoke.uid.okay",
+                      n1 > 1? _("Really revoke all selected user IDs? (y/N) ")
+                            : _("Really revoke this user ID? (y/N) ")
+                      ) ) {
+                 if(menu_revuid(keyblock,sec_keyblock))
+                   {
+                     modified=1;
+                     redisplay=1;
+                   }
+               }
+           }
+           break;
+
          case cmdREVKEY: {
                int n1;
 
@@ -1278,8 +1756,8 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
                else if( sec_keyblock && !cpr_get_answer_is_yes(
                            "keyedit.revoke.subkey.okay",
                       n1 > 1?
-                       _("Do you really want to revoke the selected keys? "):
-                       _("Do you really want to revoke this key? ")
+                  _("Do you really want to revoke the selected keys? (y/N) "):
+                  _("Do you really want to revoke this key? (y/N) ")
                       ))
                    ;
                else {
@@ -1316,6 +1794,13 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
            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"));
+               break;
+             }
+
            show_key_with_all_names( keyblock, 0, 0, 0, 1, 0 );
            tty_printf("\n");
            if( edit_ownertrust( find_kbnode( keyblock,
@@ -1342,22 +1827,35 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
 
          case cmdUPDPREF: 
             {
-                p = keygen_get_std_prefs ();
-                tty_printf (("Current preference list: %s\n"), p);
-                m_free (p);
+             PKT_user_id *temp=keygen_get_std_prefs();
+             tty_printf(_("Set preference list to:\n"));
+             show_prefs(temp,NULL,1);
+             m_free(temp);
             }
             if (cpr_get_answer_is_yes ("keyedit.updpref.okay",
                                         count_selected_uids (keyblock)?
-                                        _("Really update the preferences"
-                                          " for the selected user IDs? "):
-                                       _("Really update the preferences? "))){
+                                       _("Really update the preferences"
+                                        " for the selected user IDs? (y/N) "):
+                                   _("Really update the preferences? (y/N) ")))
+             {
 
-                if ( menu_set_preferences (keyblock, sec_keyblock) ) {
-                    merge_keys_and_selfsig (keyblock);
-                    modified = 1;
-                    redisplay = 1;
-                }
-            }
+                if ( menu_set_preferences (keyblock, sec_keyblock) )
+                 {
+                   merge_keys_and_selfsig (keyblock);
+                   modified = 1;
+                   redisplay = 1;
+                 }
+             }
+           break;
+
+         case cmdPREFKS:
+           if( menu_set_keyserver_url ( *arg_string?arg_string:NULL,
+                                        keyblock, sec_keyblock ) )
+             {
+               merge_keys_and_selfsig( keyblock );
+               modified = 1;
+               redisplay = 1;
+             }
            break;
 
          case cmdNOP:
@@ -1388,16 +1886,15 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
            if( !modified && !sec_modified )
                goto leave;
            if( !cpr_get_answer_is_yes("keyedit.save.okay",
-                                       _("Save changes? ")) ) {
+                                       _("Save changes? (y/N) ")) ) {
                if( cpr_enabled()
                    || cpr_get_answer_is_yes("keyedit.cancel.okay",
-                                            _("Quit without saving? ")) )
+                                            _("Quit without saving? (y/N) ")))
                    goto leave;
                break;
            }
            /* fall thru */
          case cmdSAVE:
-         do_cmd_save:
            if( modified || sec_modified  ) {
                if( modified ) {
                    rc = keydb_update_keyblock (kdbhd, keyblock);
@@ -1445,7 +1942,7 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
  * show preferences of a public keyblock.
  */
 static void
-show_prefs (PKT_user_id *uid, int verbose)
+show_prefs (PKT_user_id *uid, PKT_signature *selfsig, int verbose)
 {
     const prefitem_t fake={0,0};
     const prefitem_t *prefs;
@@ -1463,7 +1960,9 @@ show_prefs (PKT_user_id *uid, int verbose)
 
     if (verbose) {
         int any, des_seen=0, sha1_seen=0, uncomp_seen=0;
-        tty_printf ("     Cipher: ");
+
+        tty_printf ("     ");
+       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);
@@ -1485,7 +1984,8 @@ show_prefs (PKT_user_id *uid, int verbose)
                 tty_printf (", ");
             tty_printf ("%s",cipher_algo_to_string(CIPHER_ALGO_3DES));
         }
-        tty_printf ("\n     Hash: ");
+        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);
@@ -1507,7 +2007,8 @@ show_prefs (PKT_user_id *uid, int verbose)
                 tty_printf (", ");
             tty_printf ("%s",digest_algo_to_string(DIGEST_ALGO_SHA1));
         }
-        tty_printf ("\n     Compression: ");
+        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);
@@ -1520,7 +2021,7 @@ show_prefs (PKT_user_id *uid, int verbose)
                     tty_printf ("%s", s );
                 else
                     tty_printf ("[%d]", prefs[i].value);
-                if (prefs[i].value == 0 )
+                if (prefs[i].value == COMPRESS_ALGO_NONE )
                     uncomp_seen = 1;
             }
         }
@@ -1528,15 +2029,45 @@ show_prefs (PKT_user_id *uid, int verbose)
             if (any)
                 tty_printf (", ");
            else {
-             tty_printf ("%s",compress_algo_to_string(1));
+             tty_printf ("%s",compress_algo_to_string(COMPRESS_ALGO_ZIP));
              tty_printf (", ");
            }
-           tty_printf ("%s",compress_algo_to_string(0));
+           tty_printf ("%s",compress_algo_to_string(COMPRESS_ALGO_NONE));
         }
-        tty_printf ("\n     Features: ");
-       if(uid->mdc_feature)
-         tty_printf ("MDC");
+       if(uid->mdc_feature || !uid->ks_modify)
+         {
+           tty_printf ("\n     ");
+           tty_printf (_("Features: "));
+           any=0;
+           if(uid->mdc_feature)
+             {
+               tty_printf ("MDC");
+               any=1;
+             }
+           if(!uid->ks_modify)
+             {
+               if(any)
+                 tty_printf (", ");
+               tty_printf (_("Keyserver no-modify"));
+             }
+         }
        tty_printf("\n");
+
+       if(selfsig)
+         {
+           const byte *pref_ks;
+           size_t pref_ks_len;
+
+           pref_ks=parse_sig_subpkt(selfsig->hashed,
+                                    SIGSUBPKT_PREF_KS,&pref_ks_len);
+           if(pref_ks && pref_ks_len)
+             {
+               tty_printf ("     ");
+               tty_printf(_("Preferred keyserver: "));
+               tty_print_utf8_string(pref_ks,pref_ks_len);
+               tty_printf("\n");
+             }
+         }
     }
     else {
         tty_printf("    ");
@@ -1548,6 +2079,8 @@ show_prefs (PKT_user_id *uid, int verbose)
         }
         if (uid->mdc_feature)
             tty_printf (" [mdc]");
+        if (!uid->ks_modify)
+            tty_printf (" [no-ks-modify]");
         tty_printf("\n");
     }
 }
@@ -1560,8 +2093,9 @@ static void
 show_key_with_all_names_colon (KBNODE keyblock)
 {
   KBNODE node;
-  int i, j;
+  int i, j, ulti_hack=0;
   byte pk_version=0;
+  PKT_public_key *primary=NULL;
 
   /* the keys */
   for ( node = keyblock; node; node = node->next )
@@ -1570,14 +2104,12 @@ show_key_with_all_names_colon (KBNODE keyblock)
           || (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) )
         {
           PKT_public_key *pk = node->pkt->pkt.public_key;
-          int otrust=0, trust=0;
           u32 keyid[2];
 
           if (node->pkt->pkttype == PKT_PUBLIC_KEY)
             {
-              trust = get_validity_info (pk, NULL);
-              otrust = get_ownertrust_info (pk);
               pk_version = pk->version;
+             primary=pk;
            }
 
           keyid_from_pk (pk, keyid);
@@ -1589,18 +2121,23 @@ show_key_with_all_names_colon (KBNODE keyblock)
             putchar ('r');
           else if (pk->has_expired)
             putchar ('e');
-          else 
-            putchar (trust);
-          printf (":%u:%d:%08lX%08lX:%lu:%lu:",
+          else if (!(opt.fast_list_mode || opt.no_expensive_trust_checks ))
+           {
+             int trust = get_validity_info (pk, NULL);
+             if(trust=='u')
+               ulti_hack=1;
+             putchar (trust);
+           }
+
+          printf (":%u:%d:%08lX%08lX:%lu:%lu::",
                   nbits_from_pk (pk),
                   pk->pubkey_algo,
                   (ulong)keyid[0], (ulong)keyid[1],
                   (ulong)pk->timestamp,
                   (ulong)pk->expiredate );
-          if (pk->local_id)
-            printf ("%lu", pk->local_id);
-          putchar (':');
-          putchar (otrust);
+          if (node->pkt->pkttype==PKT_PUBLIC_KEY
+             && !(opt.fast_list_mode || opt.no_expensive_trust_checks ))
+           putchar(get_ownertrust_info (pk));
           putchar(':');
           putchar('\n');
           
@@ -1633,19 +2170,36 @@ show_key_with_all_names_colon (KBNODE keyblock)
        if ( node->pkt->pkttype == PKT_USER_ID )
           {
             PKT_user_id *uid = node->pkt->pkt.user_id;
-            int trustletter = '?';
 
            ++i;
+
            if(uid->attrib_data)
-             {
-               printf ("uat:%c::::::::%u %lu", trustletter,
-                       uid->numattribs,uid->attrib_len);
-             }
+             printf("uat:");
+           else
+             printf("uid:");
+
+           if ( uid->is_revoked )
+             printf("r::::::::");
+           else if ( uid->is_expired )
+             printf("e::::::::");
+           else if ( opt.fast_list_mode || opt.no_expensive_trust_checks )
+             printf("::::::::");
            else
              {
-               printf ("uid:%c::::::::", trustletter);
-               print_string (stdout, uid->name, uid->len, ':');
+               int uid_validity;
+
+               if( primary && !ulti_hack )
+                 uid_validity = get_validity_info( primary, uid );
+               else
+                 uid_validity = 'u';
+               printf("%c::::::::",uid_validity);
              }
+
+           if(uid->attrib_data)
+             printf ("%u %lu",uid->numattribs,uid->attrib_len);
+           else
+             print_string (stdout, uid->name, uid->len, ':');
+
             putchar (':');
             /* signature class */
             putchar (':');
@@ -1667,6 +2221,8 @@ show_key_with_all_names_colon (KBNODE keyblock)
                   } 
                 if (uid->mdc_feature)
                   printf (",mdc");
+                if (!uid->ks_modify)
+                  printf (",no-ks-modify");
               } 
             putchar (':');
             /* flags */
@@ -1697,9 +2253,10 @@ show_key_with_all_names( KBNODE keyblock, int only_marked, int with_revoker,
                         int with_fpr, int with_subkeys, int with_prefs )
 {
     KBNODE node;
-    int i, rc;
+    int i;
     int do_warn = 0;
     byte pk_version=0;
+    PKT_public_key *primary=NULL;
 
     if (opt.with_colons)
       {
@@ -1712,15 +2269,15 @@ show_key_with_all_names( KBNODE keyblock, int only_marked, int with_revoker,
        if( node->pkt->pkttype == PKT_PUBLIC_KEY
            || (with_subkeys && node->pkt->pkttype == PKT_PUBLIC_SUBKEY) ) {
            PKT_public_key *pk = node->pkt->pkt.public_key;
-           int otrust=0, trust=0;
+           const char *otrust="err",*trust="err";
 
            if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
                /* do it here, so that debug messages don't clutter the
                 * output */
                 static int did_warn = 0;
 
-                trust = get_validity_info (pk, NULL);
-               otrust = get_ownertrust_info (pk);
+                trust = get_validity_string (pk, NULL);
+               otrust = get_ownertrust_string (pk);
 
                 /* Show a warning once */
                 if (!did_warn
@@ -1730,148 +2287,320 @@ show_key_with_all_names( KBNODE keyblock, int only_marked, int with_revoker,
                 }
 
                pk_version=pk->version;
+               primary=pk;
            }
 
-           if(with_revoker) {
+           if(with_revoker)
+             {
                if( !pk->revkey && pk->numrevkeys )
-                   BUG();
+                 BUG();
                else
-                    for(i=0;i<pk->numrevkeys;i++) {
-                        u32 r_keyid[2];
-                        char *user;
-           
-                        keyid_from_fingerprint(pk->revkey[i].fpr,
-                                               MAX_FINGERPRINT_LEN,r_keyid);
-                        
-                        user=get_user_id_string (r_keyid);
-                        tty_printf (_("This key may be revoked by %s key "),
-                                 pubkey_algo_to_string (pk->revkey[i].algid));
-                        tty_print_utf8_string (user, strlen (user));
-                        if ((pk->revkey[i].class&0x40))
-                          tty_printf (_(" (sensitive)"));
-                        tty_printf ("\n");
-                        m_free(user);
-                      }
-            }
+                 for(i=0;i<pk->numrevkeys;i++)
+                   {
+                     u32 r_keyid[2];
+                     char *user;
+                     const char *algo=
+                       pubkey_algo_to_string(pk->revkey[i].algid);
+
+                     keyid_from_fingerprint(pk->revkey[i].fpr,
+                                            MAX_FINGERPRINT_LEN,r_keyid);
+
+                     user=get_user_id_string_native(r_keyid);
+                     tty_printf(_("This key may be revoked by %s key %s"),
+                                algo?algo:"?",user);
+
+                     if(pk->revkey[i].class&0x40)
+                       {
+                         tty_printf(" ");
+                         tty_printf(_("(sensitive)"));
+                       }
 
-           tty_printf(_("%s%c %4u%c/%08lX  created: %s expires: %s"),
-                         node->pkt->pkttype == PKT_PUBLIC_KEY? "pub":"sub",
-                         (node->flag & NODFLG_SELKEY)? '*':' ',
-                         nbits_from_pk( pk ),
-                         pubkey_letter( pk->pubkey_algo ),
-                         (ulong)keyid_from_pk(pk,NULL),
-                         datestr_from_pk(pk),
-                         expirestr_from_pk(pk) );
-           if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
-               tty_printf(_(" trust: %c/%c"), otrust, trust );
+                     tty_printf ("\n");
+                     m_free(user);
+                   }
+             }
+
+           keyid_from_pk(pk,NULL);
+           tty_printf("%s%c %4u%c/%s  ",
+                      node->pkt->pkttype == PKT_PUBLIC_KEY? "pub":"sub",
+                      (node->flag & NODFLG_SELKEY)? '*':' ',
+                      nbits_from_pk( pk ),
+                      pubkey_letter( pk->pubkey_algo ),
+                      keystr(pk->keyid));
+
+           tty_printf(_("created: %s"),datestr_from_pk(pk));
+           tty_printf("  ");
+           if(pk->is_revoked)
+             tty_printf(_("revoked: %s"),revokestr_from_pk(pk));
+           else if(pk->has_expired)
+             tty_printf(_("expired: %s"),expirestr_from_pk(pk));
+           else
+             tty_printf(_("expires: %s"),expirestr_from_pk(pk));
+           tty_printf("  ");
+            tty_printf(_("usage: %s"),usagestr_from_pk(pk));
+           tty_printf("\n");
+
+           if( node->pkt->pkttype == PKT_PUBLIC_KEY )
+             {
+               if(opt.trust_model!=TM_ALWAYS)
+                 {
+                   tty_printf("%*s",keystrlen()+13,"");
+                   /* Ownertrust is only meaningful for the PGP or
+                      classic trust models */
+                   if(opt.trust_model==TM_PGP || opt.trust_model==TM_CLASSIC)
+                     {
+                       int width=14-strlen(otrust);
+                       if(width<=0)
+                         width=1;
+                       tty_printf(_("trust: %s"), otrust);
+                       tty_printf("%*s",width,"");
+                     }
+                   
+                   tty_printf(_("validity: %s"), trust );
+                   tty_printf("\n");
+                 }
                if( node->pkt->pkttype == PKT_PUBLIC_KEY
-                   && (get_ownertrust (pk)&TRUST_FLAG_DISABLED)) {
-                   tty_printf("\n*** ");
+                   && (get_ownertrust (pk)&TRUST_FLAG_DISABLED))
+                 {
+                   tty_printf("*** ");
                    tty_printf(_("This key has been disabled"));
-               }
-
-               if( with_fpr  ) {
                    tty_printf("\n");
-                   print_fingerprint ( pk, NULL, 2 );
-               }
-           }
-           tty_printf("\n");
+                 }
+             }
+
+           if( node->pkt->pkttype == PKT_PUBLIC_KEY && with_fpr )
+             {
+               print_fingerprint ( pk, NULL, 2 );
+               tty_printf("\n");
+             }
        }
        else if( node->pkt->pkttype == PKT_SECRET_KEY
-           || (with_subkeys && node->pkt->pkttype == PKT_SECRET_SUBKEY) ) {
+           || (with_subkeys && node->pkt->pkttype == PKT_SECRET_SUBKEY) )
+         {
            PKT_secret_key *sk = node->pkt->pkt.secret_key;
-           tty_printf(_("%s%c %4u%c/%08lX  created: %s expires: %s"),
-                         node->pkt->pkttype == PKT_SECRET_KEY? "sec":"ssb",
-                         (node->flag & NODFLG_SELKEY)? '*':' ',
-                         nbits_from_sk( sk ),
-                         pubkey_letter( sk->pubkey_algo ),
-                         (ulong)keyid_from_sk(sk,NULL),
-                         datestr_from_sk(sk),
-                         expirestr_from_sk(sk) );
+           tty_printf("%s%c %4u%c/%s  ",
+                      node->pkt->pkttype == PKT_SECRET_KEY? "sec":"ssb",
+                      (node->flag & NODFLG_SELKEY)? '*':' ',
+                      nbits_from_sk( sk ),
+                      pubkey_letter( sk->pubkey_algo ),
+                      keystr_from_sk(sk));
+           tty_printf(_("created: %s"),datestr_from_sk(sk));
+           tty_printf("  ");
+           tty_printf(_("expires: %s"),expirestr_from_sk(sk));
            tty_printf("\n");
-       }
-       else if( with_subkeys && node->pkt->pkttype == PKT_SIGNATURE
-                && node->pkt->pkt.signature->sig_class == 0x28       ) {
-           PKT_signature *sig = node->pkt->pkt.signature;
-
-           rc = check_key_signature( keyblock, node, NULL );
-           if( !rc )
-               tty_printf( _("rev! subkey has been revoked: %s\n"),
-                           datestr_from_sig( sig ) );
-           else if( rc == G10ERR_BAD_SIGN )
-               tty_printf( _("rev- faked revocation found\n") );
-           else if( rc )
-               tty_printf( _("rev? problem checking revocation: %s\n"),
-                                                        g10_errstr(rc) );
-       }
+            if (sk->is_protected && sk->protect.s2k.mode == 1002)
+              {
+               tty_printf("                     ");
+                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. */
+                    for (i=8; i < 14; i++)
+                      {
+                        if (i == 10)
+                          tty_printf (" ");
+                        tty_printf ("%02X", sk->protect.iv[i]);
+                      }
+                  }
+                else
+                  { /* Something is wrong: Print all. */
+                    for (i=0; i < sk->protect.ivlen; i++)
+                      tty_printf ("%02X", sk->protect.iv[i]);
+                  }
+                tty_printf ("\n");
+              }
+         }
     }
+    
     /* the user ids */
+
     i = 0;
-    for( node = keyblock; node; node = node->next ) {
-       if( node->pkt->pkttype == PKT_USER_ID ) {
+    for( node = keyblock; node; node = node->next )
+      {
+       if( node->pkt->pkttype == PKT_USER_ID )
+         {
            PKT_user_id *uid = node->pkt->pkt.user_id;
            ++i;
-           if( !only_marked || (only_marked && (node->flag & NODFLG_MARK_A))){
+           if( !only_marked || (only_marked && (node->flag & NODFLG_MARK_A)))
+             {
+               if(!only_marked && primary)
+                 tty_printf("%s ",uid_trust_string_fixed(primary,uid));
+
                if( only_marked )
-                  tty_printf("     ");
+                 tty_printf("     ");
                else if( node->flag & NODFLG_SELUID )
-                  tty_printf("(%d)* ", i);
+                 tty_printf("(%d)* ", i);
                else if( uid->is_primary )
-                  tty_printf("(%d). ", i);
+                 tty_printf("(%d). ", i);
                else
-                  tty_printf("(%d)  ", i);
-                if ( uid->is_revoked )
-                    tty_printf ("[revoked] ");
-                if ( uid->is_expired )
-                    tty_printf ("[expired] ");
+                 tty_printf("(%d)  ", i);
                tty_print_utf8_string( uid->name, uid->len );
                tty_printf("\n");
                if( with_prefs )
                  {
                    if(pk_version>3 || uid->selfsigversion>3)
-                     show_prefs (uid, with_prefs == 2);
+                     {
+                       PKT_signature *selfsig=NULL;
+                       KBNODE signode;
+
+                       for(signode=node->next;
+                           signode && signode->pkt->pkttype==PKT_SIGNATURE;
+                           signode=signode->next)
+                         {
+                           if(signode->pkt->pkt.signature->
+                              flags.chosen_selfsig)
+                             {
+                               selfsig=signode->pkt->pkt.signature;
+                               break;
+                             }
+                         }
+
+                       show_prefs (uid, selfsig, with_prefs == 2);
+                     }
                    else
-                     tty_printf(_("There are no preferences on a "
-                                  "PGP 2.x-style key.\n"));
+                     tty_printf(_("There are no preferences on a"
+                                  " PGP 2.x-style user ID.\n"));
                  }
-           }
-       }
-    }
+             }
+         }
+      }
 
     if (do_warn)
-        tty_printf (_("Please note that the shown key validity "
-                      "is not necessarily correct\n"
+        tty_printf (_("Please note that the shown key validity"
+                      " is not necessarily correct\n"
                       "unless you restart the program.\n")); 
+}
+
+
+/* Display basic key information.  This fucntion 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.*/
+void
+show_basic_key_info ( KBNODE keyblock )
+{
+  KBNODE node;
+  int i;
+
+  /* The primary key */
+  for (node = keyblock; node; node = node->next)
+    {
+      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  ",
+                      node->pkt->pkttype == PKT_PUBLIC_KEY? "pub":"sub",
+                      nbits_from_pk( pk ),
+                      pubkey_letter( pk->pubkey_algo ),
+                      keystr_from_pk(pk));
+         tty_printf(_("created: %s"),datestr_from_pk(pk));
+         tty_printf("  ");
+         tty_printf(_("expires: %s"),expirestr_from_pk(pk));
+          tty_printf("\n");
+          print_fingerprint ( pk, NULL, 3 );
+          tty_printf("\n");
+       }
+      else if (node->pkt->pkttype == PKT_SECRET_KEY)
+        {
+          PKT_secret_key *sk = node->pkt->pkt.secret_key;
+          tty_printf("%s  %4u%c/%s",
+                     node->pkt->pkttype == PKT_SECRET_KEY? "sec":"ssb",
+                     nbits_from_sk( sk ),
+                     pubkey_letter( sk->pubkey_algo ),
+                     keystr_from_sk(sk));
+         tty_printf(_("created: %s"),datestr_from_sk(sk));
+         tty_printf("  ");
+         tty_printf(_("expires: %s"),expirestr_from_sk(sk));
+          tty_printf("\n");
+          print_fingerprint (NULL, sk, 3 );
+          tty_printf("\n");
+       }
+    }
 
+  /* The user IDs. */
+  for (i=0, node = keyblock; node; node = node->next)
+    {
+      if (node->pkt->pkttype == PKT_USER_ID)
+        {
+          PKT_user_id *uid = node->pkt->pkt.user_id;
+          ++i;
+     
+          tty_printf ("     ");
+          if (uid->is_revoked)
+            tty_printf("[%s] ",_("revoked"));
+          else if ( uid->is_expired )
+            tty_printf("[%s] ",_("expired"));
+          tty_print_utf8_string (uid->name, uid->len);
+          tty_printf ("\n");
+        }
+    }
 }
 
 static void
 show_key_and_fingerprint( KBNODE keyblock )
 {
-    KBNODE node;
-    PKT_public_key *pk = NULL;
+  KBNODE node;
+  PKT_public_key *pk = NULL;
 
-    for( node = keyblock; node; node = node->next ) {
-       if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
-           pk = node->pkt->pkt.public_key;
-           tty_printf("pub  %4u%c/%08lX %s ",
-                         nbits_from_pk( pk ),
-                         pubkey_letter( pk->pubkey_algo ),
-                         (ulong)keyid_from_pk(pk,NULL),
-                         datestr_from_pk(pk) );
+  for( node = keyblock; node; node = node->next )
+    {
+      if( node->pkt->pkttype == PKT_PUBLIC_KEY )
+       {
+         pk = node->pkt->pkt.public_key;
+         tty_printf("pub   %4u%c/%s %s ",
+                    nbits_from_pk( pk ),
+                    pubkey_letter( pk->pubkey_algo ),
+                    keystr_from_pk(pk),
+                    datestr_from_pk(pk) );
        }
-       else if( node->pkt->pkttype == PKT_USER_ID ) {
-           PKT_user_id *uid = node->pkt->pkt.user_id;
-           tty_print_utf8_string( uid->name, uid->len );
-           break;
+      else if( node->pkt->pkttype == PKT_USER_ID )
+       {
+         PKT_user_id *uid = node->pkt->pkt.user_id;
+         tty_print_utf8_string( uid->name, uid->len );
+         break;
        }
     }
-    tty_printf("\n");
-    if( pk )
-       print_fingerprint( pk, NULL, 2 );
+  tty_printf("\n");
+  if( pk )
+    print_fingerprint( pk, NULL, 2 );
 }
 
 
+/* Show a warning if no uids on the key have the primary uid flag
+   set. */
+static void
+no_primary_warning(KBNODE keyblock)
+{
+  KBNODE node;
+  int have_primary=0,uid_count=0;
+
+  /* TODO: if we ever start behaving differently with a primary or
+     non-primary attribute ID, we will need to check for attributes
+     here as well. */
+
+  for(node=keyblock; node; node = node->next)
+    {
+      if(node->pkt->pkttype==PKT_USER_ID
+        && node->pkt->pkt.user_id->attrib_data==NULL)
+       {
+         uid_count++;
+
+         if(node->pkt->pkt.user_id->is_primary==2)
+           {
+             have_primary=1;
+             break;
+           }
+       }
+    }
+
+  if(uid_count>1 && !have_primary)
+    log_info(_("WARNING: no user ID has been marked as primary.  This command"
+              " may\n              cause a different user ID to become"
+              " the assumed primary.\n"));
+}
 
 /****************
  * Ask for a new user id, do the selfsignature and put it into
@@ -1921,8 +2650,9 @@ menu_adduid( KBNODE pub_keyblock, KBNODE sec_keyblock, int photo)
 
       /* It is legal but bad for compatibility to add a photo ID to a
          v3 key as it means that PGP2 will not be able to use that key
-         anymore.  Don't bother to ask this if the key already has a
-         photo - any damage has already been done at that point. -dms */
+         anymore.  Also, PGP may not expect a photo on a v3 key.
+         Don't bother to ask this if the key already has a photo - any
+         damage has already been done at that point. -dms */
       if(pk->version==3 && !hasattrib)
        {
          if(opt.expert)
@@ -1996,7 +2726,7 @@ menu_adduid( KBNODE pub_keyblock, KBNODE sec_keyblock, int photo)
 
 
 /****************
- * Remove all selceted userids from the keyrings
+ * Remove all selected userids from the keyrings
  */
 static void
 menu_deluid( KBNODE pub_keyblock, KBNODE sec_keyblock )
@@ -2065,10 +2795,15 @@ menu_delsig( KBNODE pub_keyblock )
            tty_print_utf8_string( uid->name, uid->len );
            tty_printf("\n");
 
-          okay = inv_sig = no_key = other_err = 0;
-           valid = print_and_check_one_sig( pub_keyblock, node,
-                                           &inv_sig, &no_key, &other_err,
-                                           &selfsig, 1 );
+           okay = inv_sig = no_key = other_err = 0;
+           if(opt.with_colons)
+             valid = print_and_check_one_sig_colon( pub_keyblock, node,
+                                              &inv_sig, &no_key, &other_err,
+                                              &selfsig, 1 );
+           else
+             valid = print_and_check_one_sig( pub_keyblock, node,
+                                              &inv_sig, &no_key, &other_err,
+                                              &selfsig, 1 );
 
           if( valid ) {
               okay = cpr_get_answer_yes_no_quit(
@@ -2164,9 +2899,9 @@ menu_delkey( KBNODE pub_keyblock, KBNODE sec_keyblock )
     if( sec_keyblock )
        commit_kbnode( &sec_keyblock );
 
-    /* No need to set update_trust here since signing keys no longer
-       are used to certify other keys, so there is no change in trust
-       when revoking/removing them */
+    /* No need to set update_trust here since signing keys are no
+       longer used to certify other keys, so there is no change in
+       trust when revoking/removing them */
 }
 
 
@@ -2190,14 +2925,38 @@ menu_addrevoker( KBNODE pub_keyblock, KBNODE sec_keyblock, int sensitive )
   assert(sec_keyblock->pkt->pkttype==PKT_SECRET_KEY);
 
   pk=pub_keyblock->pkt->pkt.public_key;
+
+  if(pk->numrevkeys==0 && pk->version==3)
+    {
+      /* It is legal but bad for compatibility to add a revoker to a
+         v3 key as it means that PGP2 will not be able to use that key
+         anymore.  Also, PGP may not expect a revoker on a v3 key.
+         Don't bother to ask this if the key already has a revoker -
+         any damage has already been done at that point. -dms */
+      if(opt.expert)
+       {
+         tty_printf(_("WARNING: This is a PGP 2.x-style key.  "
+                      "Adding a designated revoker may cause\n"
+                      "         some versions of PGP to reject this key.\n"));
+
+         if(!cpr_get_answer_is_yes("keyedit.v3_revoker.okay",
+                                   _("Are you sure you still want "
+                                     "to add it? (y/N) ")))
+           return 0;
+       }
+      else
+       {
+         tty_printf(_("You may not add a designated revoker to "
+                      "a PGP 2.x-style key.\n"));
+         return 0;
+       }
+    }
+
   sk=copy_secret_key(NULL,sec_keyblock->pkt->pkt.secret_key);
 
   for(;;)
     {
       char *answer;
-      u32 keyid[2];
-      char *p;
-      size_t n;
 
       if(revoker_pk)
        free_public_key(revoker_pk);
@@ -2209,16 +2968,24 @@ menu_addrevoker( KBNODE pub_keyblock, KBNODE sec_keyblock, int sensitive )
       answer=cpr_get_utf8("keyedit.add_revoker",
                          _("Enter the user ID of the designated revoker: "));
       if(answer[0]=='\0' || answer[0]=='\004')
-       goto fail;
-
-      rc=get_pubkey_byname(revoker_pk,answer,NULL,NULL);
+       {
+         m_free(answer);
+         goto fail;
+       }
 
+      /* Note that I'm requesting SIG here and not CERT.  We're making
+        a certification, but it is okay to be a subkey. */
+      revoker_pk->req_usage=PUBKEY_USAGE_SIG;
+      rc=get_pubkey_byname(revoker_pk,answer,NULL,NULL,1);
       if(rc)
        {
-         log_error (_("key `%s' not found: %s\n"),answer,g10_errstr(rc));
+         log_error (_("key \"%s\" not found: %s\n"),answer,g10_errstr(rc));
+         m_free(answer);
          continue;
        }
 
+      m_free(answer);
+
       fingerprint_from_pk(revoker_pk,revkey.fpr,&fprlen);
       if(fprlen!=20)
        {
@@ -2227,6 +2994,11 @@ menu_addrevoker( KBNODE pub_keyblock, KBNODE sec_keyblock, int sensitive )
          continue;
        }
 
+      revkey.class=0x80;
+      if(sensitive)
+       revkey.class|=0x40;
+      revkey.algid=revoker_pk->pubkey_algo;
+
       if(cmp_public_keys(revoker_pk,pk)==0)
        {
          /* This actually causes no harm (after all, a key that
@@ -2234,42 +3006,63 @@ menu_addrevoker( KBNODE pub_keyblock, KBNODE sec_keyblock, int sensitive )
             regular key), but it's easy enough to check. */
          log_error(_("you cannot appoint a key as its own "
                      "designated revoker\n"));
+
          continue;
        }
 
-      keyid_from_pk(revoker_pk,keyid);
+      keyid_from_pk(pk,NULL);
 
-      tty_printf("\npub  %4u%c/%08lX %s   ",
-                nbits_from_pk( revoker_pk ),
-                pubkey_letter( revoker_pk->pubkey_algo ),
-                (ulong)keyid[1], datestr_from_pk(pk) );
+      /* Does this revkey already exist? */
+      if(!pk->revkey && pk->numrevkeys)
+       BUG();
+      else
+       {
+         int i;
 
-      p = get_user_id( keyid, &n );
-      tty_print_utf8_string( p, n );
-      m_free(p);
-      tty_printf("\n");
+         for(i=0;i<pk->numrevkeys;i++)
+           {
+             if(memcmp(&pk->revkey[i],&revkey,
+                       sizeof(struct revocation_key))==0)
+               {
+                 char buf[50];
+
+                 log_error(_("this key has already been designated "
+                             "as a revoker\n"));
+
+                 sprintf(buf,"%08lX%08lX",
+                         (ulong)pk->keyid[0],(ulong)pk->keyid[1]);
+                 write_status_text(STATUS_ALREADY_SIGNED,buf);
+
+                 break;
+               }
+           }
+
+         if(i<pk->numrevkeys)
+           continue;
+       }
+
+      print_pubkey_info(NULL,revoker_pk);
       print_fingerprint(revoker_pk,NULL,2);
       tty_printf("\n");
 
-      tty_printf("WARNING: appointing a key as a designated revoker "
-                "cannot be undone!\n");
+      tty_printf(_("WARNING: appointing a key as a designated revoker "
+                  "cannot be undone!\n"));
 
       tty_printf("\n");
 
       if(!cpr_get_answer_is_yes("keyedit.add_revoker.okay",
-                               "Are you sure you want to appoint this "
-                               "key as a designated revoker? (y/N): "))
+                               _("Are you sure you want to appoint this "
+                                 "key as a designated revoker? (y/N) ")))
        continue;
 
-      revkey.class=0x80;
-      if(sensitive)
-       revkey.class|=0x40;
-      revkey.algid=revoker_pk->pubkey_algo;
       free_public_key(revoker_pk);
+      revoker_pk=NULL;
       break;
     }
 
-  rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 0x1F, 0, 0, 0, 0,
+  /* The 1F signature must be at least v4 to carry the revocation key
+     subpacket. */
+  rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 0x1F, 0, 4, 0, 0,
                           keygen_add_revkey,&revkey );
   if( rc )
     {
@@ -2330,10 +3123,12 @@ menu_expire( KBNODE pub_keyblock, KBNODE sec_keyblock )
     }
     else if( n1 )
        tty_printf(_("Changing expiration time for a secondary key.\n"));
-    else {
+    else
+      {
        tty_printf(_("Changing expiration time for the primary key.\n"));
        mainkey=1;
-    }
+       no_primary_warning(pub_keyblock);
+      }
 
     expiredate = ask_expiredate();
     node = find_kbnode( sec_keyblock, PKT_SECRET_KEY );
@@ -2360,8 +3155,11 @@ menu_expire( KBNODE pub_keyblock, KBNODE sec_keyblock )
                 && ( mainkey || sub_pk ) ) {
            PKT_signature *sig = node->pkt->pkt.signature;
            if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1]
-               && (    (mainkey && uid && (sig->sig_class&~3) == 0x10)
-                    || (!mainkey && sig->sig_class == 0x18)  ) ) {
+               && ( (mainkey && uid
+                     && uid->created && (sig->sig_class&~3) == 0x10)
+                    || (!mainkey && sig->sig_class == 0x18)  )
+               && sig->flags.chosen_selfsig )
+             {
                /* this is a selfsignature which is to be replaced */
                PKT_signature *newsig;
                PACKET *newpkt;
@@ -2391,15 +3189,12 @@ menu_expire( KBNODE pub_keyblock, KBNODE sec_keyblock )
                if( !sn )
                    log_info(_("No corresponding signature in secret ring\n"));
 
-               /* create new self signature */
                if( mainkey )
-                   rc = make_keysig_packet( &newsig, main_pk, uid, NULL,
-                                            sk, 0x13, 0, 0, 0, 0,
-                                            keygen_add_std_prefs, main_pk );
+                 rc = update_keysig_packet(&newsig, sig, main_pk, uid, NULL,
+                                           sk, keygen_add_key_expire, main_pk);
                else
-                   rc = make_keysig_packet( &newsig, main_pk, NULL, sub_pk,
-                                            sk, 0x18, 0, 0, 0, 0,
-                                            keygen_add_key_expire, sub_pk );
+                 rc = update_keysig_packet(&newsig, sig, main_pk, NULL, sub_pk,
+                                           sk, keygen_add_key_expire, sub_pk );
                if( rc ) {
                    log_error("make_keysig_packet failed: %s\n",
                                                    g10_errstr(rc));
@@ -2504,12 +3299,14 @@ menu_set_primary_uid ( KBNODE pub_keyblock, KBNODE sec_keyblock )
        else if ( main_pk && uid && 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)
-               && attribute == (uid->attrib_data!=NULL)) {
+                && (uid && (sig->sig_class&~3) == 0x10)
+                && attribute == (uid->attrib_data!=NULL)
+                && sig->flags.chosen_selfsig )
+             {
              if(sig->version < 4) {
                char *user=utf8_to_native(uid->name,strlen(uid->name),0);
 
-               log_info(_("skipping v3 self-signature on user id \"%s\"\n"),
+               log_info(_("skipping v3 self-signature on user ID \"%s\"\n"),
                         user);
                m_free(user);
              }
@@ -2544,7 +3341,7 @@ menu_set_primary_uid ( KBNODE pub_keyblock, KBNODE sec_keyblock )
 
                 if (action) {
                     int rc = update_keysig_packet (&newsig, sig,
-                                               main_pk, uid, 
+                                              main_pk, uid, NULL,
                                                sk,
                                                change_primary_uid_cb,
                                                action > 0? "x":NULL );
@@ -2587,6 +3384,8 @@ menu_set_preferences (KBNODE pub_keyblock, KBNODE sec_keyblock )
     int selected, select_all;
     int modified = 0;
 
+    no_primary_warning(pub_keyblock);
+
     select_all = !count_selected_uids (pub_keyblock);
 
     node = find_kbnode( sec_keyblock, PKT_SECRET_KEY );
@@ -2612,11 +3411,12 @@ menu_set_preferences (KBNODE pub_keyblock, KBNODE sec_keyblock )
                   && 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) ) {
+                && (uid && (sig->sig_class&~3) == 0x10)
+                && sig->flags.chosen_selfsig ) {
              if( sig->version < 4 ) {
                char *user=utf8_to_native(uid->name,strlen(uid->name),0);
 
-               log_info(_("skipping v3 self-signature on user id \"%s\"\n"),
+               log_info(_("skipping v3 self-signature on user ID \"%s\"\n"),
                         user);
                m_free(user);
              }
@@ -2629,7 +3429,7 @@ menu_set_preferences (KBNODE pub_keyblock, KBNODE sec_keyblock )
                 int rc;
 
                 rc = update_keysig_packet (&newsig, sig,
-                                           main_pk, uid, 
+                                           main_pk, uid, NULL,
                                            sk,
                                            keygen_upd_std_prefs,
                                            NULL );
@@ -2657,6 +3457,149 @@ menu_set_preferences (KBNODE pub_keyblock, KBNODE sec_keyblock )
 }
 
 
+static int
+menu_set_keyserver_url (const char *url,
+                       KBNODE pub_keyblock, KBNODE sec_keyblock )
+{
+  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,*uri;
+
+  no_primary_warning(pub_keyblock);
+
+  if(url)
+    answer=m_strdup(url);
+  else
+    {
+      answer=cpr_get_utf8("keyedit.add_keyserver",
+                         _("Enter your preferred keyserver URL: "));
+      if(answer[0]=='\0' || answer[0]=='\004')
+       {
+         m_free(answer);
+         return 0;
+       }
+    }
+
+  if(ascii_strcasecmp(answer,"none")==0)
+    uri=NULL;
+  else
+    {
+      struct keyserver_spec *keyserver=NULL;
+      /* Sanity check the format */
+      keyserver=parse_keyserver_uri(answer,1,NULL,0);
+      m_free(answer);
+      if(!keyserver)
+       {
+         log_info(_("could not parse keyserver URL\n"));
+         return 0;
+       }
+      uri=m_strdup(keyserver->uri);
+      free_keyserver_spec(keyserver);
+    }
+
+  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) )
+           {
+             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
+               {
+                 /* This is a selfsignature which is to be replaced
+                  * We have to ignore v3 signatures because they are
+                  * not able to carry the subpacket. */
+                 PKT_signature *newsig;
+                 PACKET *newpkt;
+                 int rc;
+                 const byte *p;
+                 size_t plen;
+
+                 p=parse_sig_subpkt(sig->hashed,SIGSUBPKT_PREF_KS,&plen);
+                 if(p && plen)
+                   {
+                     tty_printf("Current preferred keyserver for user"
+                                " ID \"%s\": ",user);
+                     tty_print_utf8_string(p,plen);
+                     tty_printf("\n");
+                     if(!cpr_get_answer_is_yes("keyedit.confirm_keyserver",
+                        uri?_("Are you sure you want to replace it? (y/N) "):
+                            _("Are you sure you want to delete it? (y/N) ")))
+                       continue;
+                   }
+                 else if(uri==NULL)
+                   {
+                     /* There is no current keyserver URL, so there
+                        is no point in trying to un-set it. */
+                     continue;
+                   }
+
+                 rc = update_keysig_packet (&newsig, sig,
+                                            main_pk, uid, NULL,
+                                            sk,
+                                            keygen_add_keyserver_url, uri );
+                 if( rc )
+                   {
+                     log_error ("update_keysig_packet failed: %s\n",
+                                g10_errstr(rc));
+                     free_secret_key( sk );
+                     m_free(uri);
+                     return 0;
+                   }
+                 /* replace the packet */
+                 newpkt = m_alloc_clear( sizeof *newpkt );
+                 newpkt->pkttype = PKT_SIGNATURE;
+                 newpkt->pkt.signature = newsig;
+                 free_packet( node->pkt );
+                 m_free( node->pkt );
+                 node->pkt = newpkt;
+                 modified = 1;
+               }
+
+             m_free(user);
+           }
+       }
+    }
+
+  m_free(uri);
+  free_secret_key( sk );
+  return modified;
+}
+
+
 /****************
  * Select one user id or remove all selection if index is 0.
  * Returns: True if the selection changed;
@@ -2828,6 +3771,7 @@ static void
 ask_revoke_sig( KBNODE keyblock, KBNODE node )
 {
     int doit=0;
+    char *p;
     PKT_signature *sig = node->pkt->pkt.signature;
     KBNODE unode = find_prev_kbnode( keyblock, node, PKT_USER_ID );
 
@@ -2836,16 +3780,14 @@ ask_revoke_sig( KBNODE keyblock, KBNODE node )
        return;
     }
 
-    tty_printf(_("user ID: \""));
-    tty_print_utf8_string( unode->pkt->pkt.user_id->name,
-                          unode->pkt->pkt.user_id->len );
+    p=utf8_to_native(unode->pkt->pkt.user_id->name,
+                    unode->pkt->pkt.user_id->len,0);
+    tty_printf(_("user ID: \"%s\"\n"),p);
+    m_free(p);
 
-    if(sig->flags.exportable)
-      tty_printf(_("\"\nsigned with your key %08lX at %s\n"),
-                (ulong)sig->keyid[1], datestr_from_sig(sig) );
-    else
-      tty_printf(_("\"\nlocally signed with your key %08lX at %s\n"),
-                (ulong)sig->keyid[1], datestr_from_sig(sig) );
+    tty_printf(_("signed by your key %s on %s%s%s\n"),
+              keystr(sig->keyid),datestr_from_sig(sig),
+              sig->flags.exportable?"":_(" (non-exportable)"),"");
 
     if(sig->flags.expired)
       {
@@ -2881,8 +3823,11 @@ menu_revsig( KBNODE keyblock )
     int rc, any, skip=1, all=!count_selected_uids(keyblock);
     struct revocation_reason_info *reason = NULL;
 
+    assert(keyblock->pkt->pkttype==PKT_PUBLIC_KEY);
+
     /* FIXME: detect duplicates here  */
-    tty_printf(_("You have signed these user IDs:\n"));
+    tty_printf(_("You have signed these user IDs on key %s:\n"),
+              keystr_from_pk(keyblock->pkt->pkt.public_key));
     for( node = keyblock; node; node = node->next ) {
        node->flag &= ~(NODFLG_SELSIG | NODFLG_MARK_A);
        if( node->pkt->pkttype == PKT_USER_ID ) {
@@ -2899,22 +3844,29 @@ menu_revsig( KBNODE keyblock )
        }
        else if( !skip && node->pkt->pkttype == PKT_SIGNATURE
                && ((sig = node->pkt->pkt.signature),
-                     !seckey_available(sig->keyid)  ) ) {
-           if( (sig->sig_class&~3) == 0x10 ) {
-               tty_printf(_("   signed by %08lX at %s%s%s\n"),
-                          (ulong)sig->keyid[1], datestr_from_sig(sig),
-                          sig->flags.exportable?"":" (non-exportable)",
-                          sig->flags.revocable?"":" (non-revocable)");
+                     !seckey_available(sig->keyid)  ) )
+         {
+           if( (sig->sig_class&~3) == 0x10 )
+             {
+               tty_printf("   ");
+               tty_printf(_("signed by your key %s on %s%s%s\n"),
+                          keystr(sig->keyid), datestr_from_sig(sig),
+                          sig->flags.exportable?"":_(" (non-exportable)"),
+                          sig->flags.revocable?"":_(" (non-revocable)"));
                if(sig->flags.revocable)
                  node->flag |= NODFLG_SELSIG;
-           }
-           else if( sig->sig_class == 0x30 ) {
-               tty_printf(_("   revoked by %08lX at %s\n"),
-                           (ulong)sig->keyid[1], datestr_from_sig(sig) );
-           }
-       }
+             }
+           else if( sig->sig_class == 0x30 )
+             {
+               tty_printf("   ");
+               tty_printf(_("revoked by your key %s on %s\n"),
+                          keystr(sig->keyid),datestr_from_sig(sig));
+             }
+         }
     }
 
+    tty_printf("\n");
+
     /* ask */
     for( node = keyblock; node; node = node->next ) {
        if( !(node->flag & NODFLG_SELSIG) )
@@ -2939,8 +3891,9 @@ menu_revsig( KBNODE keyblock )
        }
        else if( node->pkt->pkttype == PKT_SIGNATURE ) {
            sig = node->pkt->pkt.signature;
-           tty_printf(_("   signed by %08lX at %s%s\n"),
-                      (ulong)sig->keyid[1], datestr_from_sig(sig),
+           tty_printf("   ");
+           tty_printf(_("signed by your key %s on %s%s%s\n"),
+                      keystr(sig->keyid), datestr_from_sig(sig),"",
                       sig->flags.exportable?"":_(" (non-exportable)") );
        }
     }
@@ -3011,6 +3964,109 @@ menu_revsig( KBNODE keyblock )
     return changed;
 }
 
+/* Revoke a user ID (i.e. revoke a user ID selfsig).  Return true if
+   keyblock changed. */
+static int
+menu_revuid( KBNODE pub_keyblock, KBNODE sec_keyblock )
+{
+  PKT_public_key *pk = pub_keyblock->pkt->pkt.public_key;
+  PKT_secret_key *sk = copy_secret_key( NULL,
+                                       sec_keyblock->pkt->pkt.secret_key );
+  KBNODE node;
+  int changed = 0;
+  int rc;
+  struct revocation_reason_info *reason = NULL;
+
+  /* Note that this is correct as per the RFCs, but nevertheless
+     somewhat meaningless in the real world.  1991 did define the 0x30
+     sig class, but PGP 2.x did not actually implement it, so it would
+     probably be safe to use v4 revocations everywhere. -ds */
+
+  for( node = pub_keyblock; node; node = node->next )
+    if(pk->version>3 || (node->pkt->pkttype==PKT_USER_ID &&
+                        node->pkt->pkt.user_id->selfsigversion>3))
+      {
+       if((reason = ask_revocation_reason( 0, 1, 4 )))
+         break;
+       else
+         goto leave;
+      }
+
+ reloop: /* (better this way because we are modifing the keyring) */
+  for( node = pub_keyblock; node; node = node->next )
+    if(node->pkt->pkttype == PKT_USER_ID && (node->flag & NODFLG_SELUID))
+      {
+       PKT_user_id *uid=node->pkt->pkt.user_id;
+
+       if(uid->is_revoked)
+         {
+           char *user=utf8_to_native(uid->name,uid->len,0);
+           log_info(_("user ID \"%s\" is already revoked\n"),user);
+           m_free(user);
+         }
+       else
+         {
+           PACKET *pkt;
+           PKT_signature *sig;
+           struct sign_attrib attrib;
+           u32 timestamp=make_timestamp();
+
+           if(uid->created>=timestamp)
+             {
+               /* Okay, this is a problem.  The user ID selfsig was
+                  created in the future, so we need to warn the user and
+                  set our revocation timestamp one second after that so
+                  everything comes out clean. */
+
+               log_info(_("WARNING: a user ID signature is dated %d"
+                          " seconds in the future\n"),uid->created-timestamp);
+
+               timestamp=uid->created+1;
+             }
+
+           memset( &attrib, 0, sizeof attrib );
+           attrib.reason = reason;
+
+           node->flag &= ~NODFLG_SELUID;
+
+           rc = make_keysig_packet( &sig, pk, uid, NULL, sk, 0x30, 0,
+                                    (reason==NULL)?3:0, timestamp, 0,
+                                    sign_mk_attrib, &attrib );
+           if( rc )
+             {
+               log_error(_("signing failed: %s\n"), g10_errstr(rc));
+               goto leave;
+             }
+           else
+             {
+               pkt = m_alloc_clear( sizeof *pkt );
+               pkt->pkttype = PKT_SIGNATURE;
+               pkt->pkt.signature = sig;
+               insert_kbnode( node, new_kbnode(pkt), 0 );
+
+               /* If the trustdb has an entry for this key+uid then the
+                  trustdb needs an update. */
+               if(!update_trust
+                  && (get_validity(pk,uid)&TRUST_MASK)>=TRUST_UNDEFINED)
+                 update_trust=1;
+
+               changed = 1;
+               node->pkt->pkt.user_id->is_revoked=1;
+
+               goto reloop;
+             }
+         }
+      }
+
+  if(changed)
+    commit_kbnode( &pub_keyblock );
+
+ leave:
+  free_secret_key(sk);
+  release_revocation_reason_info( reason );
+  return changed;
+}
+
 /****************
  * Revoke some of the secondary keys.
  * Hmmm: Should we add a revocation to the secret keyring too?
@@ -3030,7 +4086,6 @@ menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock )
        return 0;
     }
 
-
   reloop: /* (better this way because we are modifing the keyring) */
     mainpk = pub_keyblock->pkt->pkt.public_key;
     for( node = pub_keyblock; node; node = node->next ) {
@@ -3076,7 +4131,10 @@ menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock )
     return changed;
 }
 
-
+/* Note that update_ownertrust is going to mark the trustdb dirty when
+   enabling or disabling a key.  This is arguably sub-optimal as
+   disabled keys are still counted in the web of trust, but perhaps
+   not worth adding extra complexity to change. -ds */
 static int
 enable_disable_key( KBNODE keyblock, int disable )
 {
@@ -3102,7 +4160,6 @@ menu_showphoto( KBNODE keyblock )
   int select_all = !count_selected_uids(keyblock);
   int count=0;
   PKT_public_key *pk=NULL;
-  u32 keyid[2];
 
   /* Look for the public key first.  We have to be really, really,
      explicit as to which photo this is, and what key it is a UID on
@@ -3111,10 +4168,7 @@ menu_showphoto( KBNODE keyblock )
   for( node = keyblock; node; node = node->next )
     {
       if( node->pkt->pkttype == PKT_PUBLIC_KEY )
-       {
-         pk = node->pkt->pkt.public_key;
-         keyid_from_pk(pk, keyid);
-       }
+       pk = node->pkt->pkt.public_key;
       else if( node->pkt->pkttype == PKT_USER_ID )
        {
          PKT_user_id *uid = node->pkt->pkt.user_id;
@@ -3134,9 +4188,9 @@ menu_showphoto( KBNODE keyblock )
                     parse_image_header(&uid->attribs[i],&type,&size))
                    {
                      tty_printf(_("Displaying %s photo ID of size %ld for "
-                                  "key 0x%08lX (uid %d)\n"),
+                                  "key %s (uid %d)\n"),
                                 image_type_to_string(type,1),
-                                (ulong)size,(ulong)keyid[1],count);
+                                (ulong)size,keystr_from_pk(pk),count);
                      show_photos(&uid->attribs[i],1,pk,NULL);
                    }
                }