* build-packet.c (build_sig_subpkt): Comments.
[gnupg.git] / g10 / keyedit.c
index d029576..333552c 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 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -63,6 +64,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,6 +87,8 @@ 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;
 };
 
 /****************
@@ -260,10 +264,126 @@ 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;
+
+  tty_printf("\n");
+  /* Same string as pkclist.c:do_edit_ownertrust */
+  tty_printf(_(
+              "Please decide how far you trust this user to correctly\n"
+              "verify other users' keys (by looking at passports,\n"
+              "checking fingerprints from different sources...)?\n\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);
+      if(*trust_depth<1 || *trust_depth>255)
+       *trust_depth=0;
+    }
+
+  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.
@@ -272,7 +392,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;
@@ -308,11 +428,12 @@ sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified,
     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;
 
@@ -413,10 +534,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
@@ -437,6 +583,7 @@ sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified,
                                in place. */
 
                            node->flag|=NODFLG_DELSIG;
+                           m_free(user);
                            continue;
                          }
                      }
@@ -451,6 +598,18 @@ sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified,
                       tty_printf(_(
                          "\"%s\" was already signed by key %08lX\n"),
                                  user,(ulong)sk_keyid[1] );
+
+                   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);
@@ -553,45 +712,52 @@ 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)
+             class=0x10+opt.def_cert_check_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_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");
 
-           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? "));
+
+                   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"));
 
-               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"
@@ -664,6 +830,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
@@ -784,10 +953,10 @@ change_passphrase( KBNODE keyblock )
            s2k->mode = opt.s2k_mode;
            s2k->hash_algo = opt.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;
@@ -887,12 +1056,12 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
 {
     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 };
+           cmdTSIGN, cmdLSIGN, cmdNRSIGN, cmdNRLSIGN, cmdREVSIG, cmdREVKEY,
+          cmdREVUID, 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;
@@ -914,6 +1083,7 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
        { 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_("tsign")   , cmdTSIGN     , 0,1,1, N_("make a trust signature")},
        { 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") },
@@ -939,6 +1109,7 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
        { 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_("revuid")  , cmdREVUID    , 1,1,0, N_("revoke a user ID") },
        { 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") },
@@ -975,13 +1146,14 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
     }
 
     /* 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 */
         PKT_public_key *pk = keyblock->pkt->pkt.public_key;
@@ -1131,6 +1303,7 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
          case cmdLSIGN: /* sign (only the public key) */
          case cmdNRSIGN: /* sign (only the public key) */
          case cmdNRLSIGN: /* sign (only the public key) */
+         case cmdTSIGN:
            if( pk->is_revoked )
              {
                tty_printf(_("Key is revoked."));
@@ -1159,7 +1332,8 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
            }
            if( !sign_uids( keyblock, locusr, &modified,
                            (cmd == cmdLSIGN) || (cmd == cmdNRLSIGN),
-                           (cmd == cmdNRSIGN) || (cmd==cmdNRLSIGN))
+                           (cmd == cmdNRSIGN) || (cmd==cmdNRLSIGN),
+                           (cmd == cmdTSIGN))
                && sign_mode )
                goto do_cmd_save;
            break;
@@ -1275,6 +1449,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? ")
+                             : _("Really revoke this user ID? ")
+                      ) ) {
+                 if(menu_revuid(keyblock,sec_keyblock))
+                   {
+                     modified=1;
+                     redisplay=1;
+                   }
+               }
+           }
+           break;
+
          case cmdREVKEY: {
                int n1;
 
@@ -1347,9 +1540,10 @@ 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(_("Current preference list:\n"));
+             show_prefs(temp,1);
+             m_free(temp);
             }
             if (cpr_get_answer_is_yes ("keyedit.updpref.okay",
                                         count_selected_uids (keyblock)?
@@ -1468,7 +1662,8 @@ 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);
@@ -1490,7 +1685,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);
@@ -1512,7 +1708,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);
@@ -1538,9 +1735,23 @@ show_prefs (PKT_user_id *uid, int verbose)
            }
            tty_printf ("%s",compress_algo_to_string(0));
         }
-        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");
     }
     else {
@@ -1553,6 +1764,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");
     }
 }
@@ -1565,8 +1778,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 )
@@ -1575,14 +1789,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);
@@ -1594,8 +1806,14 @@ show_key_with_all_names_colon (KBNODE keyblock)
             putchar ('r');
           else if (pk->has_expired)
             putchar ('e');
-          else 
-            putchar (trust);
+          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,
@@ -1605,7 +1823,9 @@ show_key_with_all_names_colon (KBNODE keyblock)
           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');
           
@@ -1638,19 +1858,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 (':');
@@ -1672,6 +1909,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 */
@@ -1717,15 +1956,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
@@ -1744,13 +1983,15 @@ show_key_with_all_names( KBNODE keyblock, int only_marked, int with_revoker,
                     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 (r_keyid);
                         tty_printf (_("This key may be revoked by %s key "),
-                                 pubkey_algo_to_string (pk->revkey[i].algid));
+                                   algo?algo:"?");
                         tty_print_utf8_string (user, strlen (user));
                         if ((pk->revkey[i].class&0x40))
                           tty_printf (_(" (sensitive)"));
@@ -1767,20 +2008,28 @@ show_key_with_all_names( KBNODE keyblock, int only_marked, int with_revoker,
                          (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");
+
+           if( node->pkt->pkttype == PKT_PUBLIC_KEY )
+             {
+               tty_printf("                     ");
+               tty_printf(_("trust: %-13s"), otrust);
+               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) ) {
@@ -1826,9 +2075,9 @@ show_key_with_all_names( KBNODE keyblock, int only_marked, int with_revoker,
                else
                   tty_printf("(%d)  ", i);
                 if ( uid->is_revoked )
-                    tty_printf ("[revoked] ");
+                    tty_printf (_("[revoked] "));
                 if ( uid->is_expired )
-                    tty_printf ("[expired] ");
+                    tty_printf (_("[expired] "));
                tty_print_utf8_string( uid->name, uid->len );
                tty_printf("\n");
                if( with_prefs )
@@ -2238,9 +2487,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 */
 }
 
 
@@ -2312,7 +2561,7 @@ menu_addrevoker( KBNODE pub_keyblock, KBNODE sec_keyblock, int sensitive )
       if(answer[0]=='\0' || answer[0]=='\004')
        goto fail;
 
-      rc=get_pubkey_byname(revoker_pk,answer,NULL,NULL);
+      rc=get_pubkey_byname(revoker_pk,answer,NULL,NULL,1);
 
       if(rc)
        {
@@ -2389,14 +2638,14 @@ menu_addrevoker( KBNODE pub_keyblock, KBNODE sec_keyblock, int sensitive )
       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;
 
       free_public_key(revoker_pk);
@@ -2528,15 +2777,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));
@@ -2681,7 +2927,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 );
@@ -2766,7 +3012,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 );
@@ -3148,6 +3394,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?
@@ -3167,7 +3516,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 ) {
@@ -3213,7 +3561,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 )
 {