See ChangeLog: Tue Aug 31 17:20:44 CEST 1999 Werner Koch
[gnupg.git] / g10 / keyedit.c
index a2b0a76..d54e90d 100644 (file)
@@ -1,14 +1,14 @@
 /* keyedit.c - keyedit stuff
- *     Copyright (C) 1998 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 1999 Free Software Foundation, Inc.
  *
- * This file is part of GNUPG.
+ * This file is part of GnuPG.
  *
- * GNUPG is free software; you can redistribute it and/or modify
+ * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  *
- * GNUPG is distributed in the hope that it will be useful,
+ * GnuPG is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
@@ -47,15 +47,19 @@ static void show_key_and_fingerprint( KBNODE keyblock );
 static void show_fingerprint( PKT_public_key *pk );
 static int menu_adduid( KBNODE keyblock, KBNODE sec_keyblock );
 static void menu_deluid( KBNODE pub_keyblock, KBNODE sec_keyblock );
+static int  menu_delsig( KBNODE pub_keyblock );
 static void menu_delkey( KBNODE pub_keyblock, KBNODE sec_keyblock );
 static int menu_expire( KBNODE pub_keyblock, KBNODE sec_keyblock );
-static int menu_select_uid( KBNODE keyblock, int index );
-static int menu_select_key( KBNODE keyblock, int index );
+static int menu_select_uid( KBNODE keyblock, int idx );
+static int menu_select_key( KBNODE keyblock, int idx );
 static int count_uids( KBNODE keyblock );
 static int count_uids_with_flag( KBNODE keyblock, unsigned flag );
 static int count_keys_with_flag( KBNODE keyblock, unsigned flag );
 static int count_selected_uids( KBNODE keyblock );
 static int count_selected_keys( KBNODE keyblock );
+static int menu_revsig( KBNODE keyblock );
+static int menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock );
+static int enable_disable_key( KBNODE keyblock, int disable );
 
 #define CONTROL_D ('D' - 'A' + 1)
 
@@ -67,6 +71,14 @@ static int count_selected_keys( KBNODE keyblock );
 
 #define NODFLG_SELUID (1<<8)  /* indicate the selected userid */
 #define NODFLG_SELKEY (1<<9)  /* indicate the selected key */
+#define NODFLG_SELSIG (1<<10) /* indicate a selected signature */
+
+
+struct sign_uid_attrib {
+    int non_exportable;
+};
+
+
 
 
 static int
@@ -94,6 +106,68 @@ get_keyblock_byname( KBNODE *keyblock, KBPOS *kbpos, const char *username )
 
 
 /****************
+ * Print information about a signature, chek it and return true
+ * if the signature is okay. NODE must be a signature packet.
+ */
+static int
+print_and_check_one_sig( KBNODE keyblock, KBNODE node,
+                        int *inv_sigs, int *no_key, int *oth_err,
+                       int *is_selfsig, int print_without_key )
+{
+    PKT_signature *sig = node->pkt->pkt.signature;
+    int rc, sigrc;
+    int is_rev = sig->sig_class == 0x30;
+
+    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:
+       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 ) {
+       tty_printf("%s%c       %08lX %s   ",
+               is_rev? "rev":"sig",
+               sigrc, sig->keyid[1], datestr_from_sig(sig));
+       if( sigrc == '%' )
+           tty_printf("[%s] ", g10_errstr(rc) );
+       else if( sigrc == '?' )
+           ;
+       else if( *is_selfsig ) {
+           tty_printf( is_rev? _("[revocation]")
+                             : _("[self-signature]") );
+       }
+       else {
+           size_t n;
+           char *p = get_user_id( sig->keyid, &n );
+           tty_print_utf8_string( p, n > 40? 40 : n );
+           m_free(p);
+       }
+       tty_printf("\n");
+    }
+    return (sigrc == '!');
+}
+
+
+
+/****************
  * Check the keysigs and set the flags to indicate errors.
  * Returns true if error found.
  */
@@ -102,7 +176,6 @@ check_all_keysigs( KBNODE keyblock, int only_selected )
 {
     KBNODE kbctx;
     KBNODE node;
-    int rc;
     int inv_sigs = 0;
     int no_key = 0;
     int oth_err = 0;
@@ -119,7 +192,7 @@ check_all_keysigs( KBNODE keyblock, int only_selected )
                selected = (node->flag & NODFLG_SELUID);
            if( selected ) {
                tty_printf("uid  ");
-               tty_print_string( uid->name, uid->len );
+               tty_print_utf8_string( uid->name, uid->len );
                tty_printf("\n");
                if( anyuid && !has_selfsig )
                    mis_selfsig++;
@@ -128,52 +201,16 @@ check_all_keysigs( KBNODE keyblock, int only_selected )
            }
        }
        else if( selected && node->pkt->pkttype == PKT_SIGNATURE
-                && (node->pkt->pkt.signature->sig_class&~3) == 0x10 ) {
-           PKT_signature *sig = node->pkt->pkt.signature;
-           int sigrc, selfsig;
-
-           switch( (rc = check_key_signature( keyblock, node, &selfsig)) ) {
-             case 0:
-               node->flag &= ~(NODFLG_BADSIG|NODFLG_NOKEY|NODFLG_SIGERR);
-               sigrc = '!';
-               break;
-             case G10ERR_BAD_SIGN:
-               node->flag = NODFLG_BADSIG;
-               sigrc = '-';
-               inv_sigs++;
-               break;
-             case G10ERR_NO_PUBKEY:
-               node->flag = NODFLG_NOKEY;
-               sigrc = '?';
-               no_key++;
-               break;
-             default:
-               node->flag = NODFLG_SIGERR;
-               sigrc = '%';
-               oth_err++;
-               break;
-           }
-           if( sigrc != '?' ) {
-               tty_printf("sig%c       %08lX %s   ",
-                       sigrc, sig->keyid[1], datestr_from_sig(sig));
-               if( sigrc == '%' )
-                   tty_printf("[%s] ", g10_errstr(rc) );
-               else if( sigrc == '?' )
-                   ;
-               else if( selfsig ) {
-                   tty_printf( _("[self-signature]") );
-                   if( sigrc == '!' )
-                       has_selfsig = 1;
-               }
-               else {
-                   size_t n;
-                   char *p = get_user_id( sig->keyid, &n );
-                   tty_print_string( p, n > 40? 40 : n );
-                   m_free(p);
-               }
-               tty_printf("\n");
-               /* fixme: Should we update the trustdb here */
+                && ( (node->pkt->pkt.signature->sig_class&~3) == 0x10
+                    || node->pkt->pkt.signature->sig_class == 0x30 )  ) {
+           int selfsig;
+
+           if( print_and_check_one_sig( keyblock, node, &inv_sigs,
+                                       &no_key, &oth_err, &selfsig, 0 ) ) {
+               if( selfsig )
+                   has_selfsig = 1;
            }
+           /* Hmmm: should we update the trustdb here? */
        }
     }
     if( !has_selfsig )
@@ -200,22 +237,38 @@ check_all_keysigs( KBNODE keyblock, int only_selected )
 }
 
 
+
+
+int
+sign_uid_mk_attrib( PKT_signature *sig, void *opaque )
+{
+    struct sign_uid_attrib *attrib = opaque;
+    byte buf[8];
+
+    if( attrib->non_exportable ) {
+       buf[0] = 0; /* not exportable */
+       build_sig_subpkt( sig, SIGSUBPKT_EXPORTABLE, buf, 1 );
+    }
+
+    return 0;
+}
+
+
+
 /****************
  * Loop over all locusr and and sign the uids after asking.
  * If no user id is marked, all user ids will be signed;
  * if some user_ids are marked those will be signed.
- *
- * fixme: Add support for our proposed sign-all scheme
  */
 static int
-sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified )
+sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified, int local )
 {
     int rc = 0;
     SK_LIST sk_list = NULL;
     SK_LIST sk_rover = NULL;
     PKT_secret_key *sk = NULL;
     KBNODE node, uidnode;
-    PKT_public_key *primary_pk;
+    PKT_public_key *primary_pk=NULL;
     int select_all = !count_selected_uids(keyblock);
     int upd_trust = 0;
 
@@ -255,6 +308,8 @@ sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified )
                && (node->pkt->pkt.signature->sig_class&~3) == 0x10 ) {
                if( sk_keyid[0] == node->pkt->pkt.signature->keyid[0]
                    && sk_keyid[1] == node->pkt->pkt.signature->keyid[1] ) {
+                   /* Fixme: see whether there is a revocation in which
+                    * case we should allow to sign it again. */
                    tty_printf(_("Already signed by key %08lX\n"),
                                                        (ulong)sk_keyid[1] );
                    uidnode->flag &= ~NODFLG_MARK_A; /* remove mark */
@@ -275,12 +330,19 @@ sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified )
             "Are you really sure that you want to sign this key\n"
             "with your key: \""));
        p = get_user_id( sk_keyid, &n );
-       tty_print_string( p, n );
+       tty_print_utf8_string( p, n );
        m_free(p); p = NULL;
        tty_printf("\"\n\n");
 
-       if( !cpr_get_answer_is_yes(N_("sign_uid.okay"), _("Really sign? ")) )
-           continue;;
+       if( local )
+           tty_printf(
+                 _("The signature will be marked as non-exportable.\n\n"));
+
+
+       if( opt.batch && opt.answer_yes )
+           ;
+       else if( !cpr_get_answer_is_yes("sign_uid.okay", _("Really sign? ")) )
+           continue;
        /* now we can sign the user ids */
       reloop: /* (must use this, because we are modifing the list) */
        primary_pk = NULL;
@@ -291,14 +353,19 @@ sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified )
                     && (node->flag & NODFLG_MARK_A) ) {
                PACKET *pkt;
                PKT_signature *sig;
+               struct sign_uid_attrib attrib;
 
                assert( primary_pk );
+               memset( &attrib, 0, sizeof attrib );
+               attrib.non_exportable = local;
                node->flag &= ~NODFLG_MARK_A;
                rc = make_keysig_packet( &sig, primary_pk,
                                               node->pkt->pkt.user_id,
                                               NULL,
                                               sk,
-                                              0x10, 0, NULL, NULL );
+                                              0x10, 0,
+                                              sign_uid_mk_attrib,
+                                              &attrib );
                if( rc ) {
                    log_error(_("signing failed: %s\n"), g10_errstr(rc));
                    goto leave;
@@ -384,7 +451,7 @@ change_passphrase( KBNODE keyblock )
        for(;;) {
            s2k->mode = opt.s2k_mode;
            s2k->hash_algo = opt.s2k_digest_algo;
-           dek = passphrase_to_dek( NULL, opt.s2k_cipher_algo, s2k, 2 );
+           dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k, 2 );
            if( !dek ) {
                tty_printf(_("passphrase not correctly repeated; try again.\n"));
            }
@@ -392,7 +459,7 @@ change_passphrase( KBNODE keyblock )
                rc = 0;
                tty_printf(_( "You don't want a passphrase -"
                            " this is probably a *bad* idea!\n\n"));
-               if( cpr_get_answer_is_yes(N_("change_passwd.empty.okay"),
+               if( cpr_get_answer_is_yes("change_passwd.empty.okay",
                               _("Do you really want to do this? ")))
                    changed++;
                break;
@@ -430,7 +497,9 @@ change_passphrase( KBNODE keyblock )
 /****************
  * There are some keys out (due to a bug in gnupg), where the sequence
  * of the packets is wrong.  This function fixes that.
- * Returns: true if the keyblock has fixed.
+ * Returns: true if the keyblock has been fixed.
+ *
+ * Note:  This function does not work if there is more than one user ID.
  */
 static int
 fix_keyblock( KBNODE keyblock )
@@ -451,7 +520,8 @@ fix_keyblock( KBNODE keyblock )
            if( subkey ) {
                PKT_signature *sig = node->pkt->pkt.signature;
                if( sig->sig_class >= 0x10 && sig->sig_class <= 0x13 ) {
-                   log_info("moving a key signature to the correct place\n");
+                   log_info(_(
+                       "moving a key signature to the correct place\n"));
                    last->next = node->next;
                    node->next = subkey->next;
                    subkey->next = node;
@@ -468,53 +538,64 @@ fix_keyblock( KBNODE keyblock )
 }
 
 /****************
- * Menu driven key editor
+ * Menu driven key editor.  If sign_mode is true semi-automatical signing
+ * will be performed. commands are ignore in this case
  *
  * Note: to keep track of some selection we use node->mark MARKBIT_xxxx.
  */
 
 void
-keyedit_menu( const char *username, STRLIST locusr )
+keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
+                                                   int sign_mode )
 {
     enum cmdids { cmdNONE = 0,
           cmdQUIT, cmdHELP, cmdFPR, cmdLIST, cmdSELUID, cmdCHECK, cmdSIGN,
+          cmdLSIGN, cmdREVSIG, cmdREVKEY, cmdDELSIG,
           cmdDEBUG, cmdSAVE, cmdADDUID, cmdDELUID, cmdADDKEY, cmdDELKEY,
           cmdTOGGLE, cmdSELKEY, cmdPASSWD, cmdTRUST, cmdPREF, cmdEXPIRE,
-          cmdNOP };
+          cmdENABLEKEY, cmdDISABLEKEY,
+          cmdINVCMD, cmdNOP };
     static struct { const char *name;
                    enum cmdids id;
                    int need_sk;
+                   int signmode;
                    const char *desc;
                  } cmds[] = {
-       { N_("quit")    , cmdQUIT   , 0, N_("quit this menu") },
-       { N_("q")       , cmdQUIT   , 0, NULL   },
-       { N_("save")    , cmdSAVE   , 0, N_("save and quit") },
-       { N_("help")    , cmdHELP   , 0, N_("show this help") },
-       {    "?"        , cmdHELP   , 0, NULL   },
-       { N_("fpr")     , cmdFPR    , 0, N_("show fingerprint") },
-       { N_("list")    , cmdLIST   , 0, N_("list key and user ids") },
-       { N_("l")       , cmdLIST   , 0, NULL   },
-       { N_("uid")     , cmdSELUID , 0, N_("select user id N") },
-       { N_("key")     , cmdSELKEY , 0, N_("select secondary key N") },
-       { N_("check")   , cmdCHECK  , 0, N_("list signatures") },
-       { N_("c")       , cmdCHECK  , 0, NULL },
-       { N_("sign")    , cmdSIGN   , 0, N_("sign the key") },
-       { N_("s")       , cmdSIGN   , 0, NULL },
-       { N_("debug")   , cmdDEBUG  , 0, NULL },
-       { N_("adduid")  , cmdADDUID , 1, N_("add a user id") },
-       { N_("deluid")  , cmdDELUID , 0, N_("delete user id") },
-       { N_("addkey")  , cmdADDKEY , 1, N_("add a secondary key") },
-       { N_("delkey")  , cmdDELKEY , 0, N_("delete a secondary key") },
-       { N_("expire")  , cmdEXPIRE , 1, N_("change the expire date") },
-       { N_("toggle")  , cmdTOGGLE , 1, N_("toggle between secret "
-                                           "and public key listing") },
-       { N_("t"     )  , cmdTOGGLE , 1, NULL },
-       { N_("pref")    , cmdPREF  , 0, N_("list preferences") },
-       { N_("passwd")  , cmdPASSWD , 1, N_("change the passphrase") },
-       { N_("trust")   , cmdTRUST , 0, N_("change the ownertrust") },
+       { N_("quit")    , cmdQUIT      , 0,1, N_("quit this menu") },
+       { N_("q")       , cmdQUIT      , 0,1, NULL   },
+       { N_("save")    , cmdSAVE      , 0,1, N_("save and quit") },
+       { N_("help")    , cmdHELP      , 0,1, N_("show this help") },
+       {    "?"        , cmdHELP      , 0,1, NULL   },
+       { N_("fpr")     , cmdFPR       , 0,1, N_("show fingerprint") },
+       { N_("list")    , cmdLIST      , 0,1, N_("list key and user ids") },
+       { N_("l")       , cmdLIST      , 0,1, NULL   },
+       { N_("uid")     , cmdSELUID    , 0,1, N_("select user id N") },
+       { N_("key")     , cmdSELKEY    , 0,0, N_("select secondary key N") },
+       { N_("check")   , cmdCHECK     , 0,1, N_("list signatures") },
+       { N_("c")       , cmdCHECK     , 0,1, NULL },
+       { N_("sign")    , cmdSIGN      , 0,1, N_("sign the key") },
+       { N_("s")       , cmdSIGN      , 0,1, NULL },
+       { N_("lsign")   , cmdLSIGN     , 0,1, N_("sign the key locally") },
+       { N_("debug")   , cmdDEBUG     , 0,0, NULL },
+       { N_("adduid")  , cmdADDUID    , 1,0, N_("add a user id") },
+       { N_("deluid")  , cmdDELUID    , 0,0, N_("delete user id") },
+       { N_("addkey")  , cmdADDKEY    , 1,0, N_("add a secondary key") },
+       { N_("delkey")  , cmdDELKEY    , 0,0, N_("delete a secondary key") },
+       { N_("delsig")  , cmdDELSIG    , 0,0, N_("delete signatures") },
+       { N_("expire")  , cmdEXPIRE    , 1,0, N_("change the expire date") },
+       { N_("toggle")  , cmdTOGGLE    , 1,0, N_("toggle between secret "
+                                                "and public key listing") },
+       { N_("t"     )  , cmdTOGGLE    , 1,0, NULL },
+       { N_("pref")    , cmdPREF      , 0,0,  N_("list preferences") },
+       { N_("passwd")  , cmdPASSWD    , 1,0, N_("change the passphrase") },
+       { N_("trust")   , cmdTRUST     , 0,0,  N_("change the ownertrust") },
+       { N_("revsig")  , cmdREVSIG    , 0,0, N_("revoke signatures") },
+       { N_("revkey")  , cmdREVKEY    , 1,0, N_("revoke a secondary key") },
+       { N_("disable") , cmdDISABLEKEY, 0,0, N_("disable a key") },
+       { N_("enable")  , cmdENABLEKEY , 0,0, N_("enable a key") },
 
     { NULL, cmdNONE } };
-    enum cmdids cmd;
+    enum cmdids cmd = 0;
     int rc = 0;
     KBNODE keyblock = NULL;
     KBPOS keyblockpos;
@@ -526,25 +607,35 @@ keyedit_menu( const char *username, STRLIST locusr )
     int modified = 0;
     int sec_modified = 0;
     int toggle;
+    int have_commands = !!commands;
 
 
-    if( opt.batch ) {
+    if( opt.batch && !have_commands ) {
        log_error(_("can't do that in batchmode\n"));
        goto leave;
     }
 
-    /* first try to locate it as secret key */
-    rc = find_secret_keyblock_byname( &sec_keyblockpos, username );
-    if( !rc ) {
-       rc = read_keyblock( &sec_keyblockpos, &sec_keyblock );
-       if( rc ) {
-           log_error("%s: secret keyblock read problem: %s\n",
-                                           username, g10_errstr(rc));
-           goto leave;
+    if( sign_mode ) {
+       commands = NULL;
+       append_to_strlist( &commands, sign_mode == 1? "sign":"lsign" );
+       have_commands = 1;
+    }
+
+
+    if( !sign_mode ) {
+       /* first try to locate it as secret key */
+       rc = find_secret_keyblock_byname( &sec_keyblockpos, username );
+       if( !rc ) {
+           rc = read_keyblock( &sec_keyblockpos, &sec_keyblock );
+           if( rc ) {
+               log_error("%s: secret keyblock read problem: %s\n",
+                                               username, g10_errstr(rc));
+               goto leave;
+           }
+           merge_keys_and_selfsig( sec_keyblock );
+           if( fix_keyblock( sec_keyblock ) )
+               sec_modified++;
        }
-       merge_keys_and_selfsig( sec_keyblock );
-       if( fix_keyblock( sec_keyblock ) )
-           sec_modified++;
     }
 
     /* and now get the public key */
@@ -553,9 +644,11 @@ keyedit_menu( const char *username, STRLIST locusr )
        goto leave;
     if( fix_keyblock( keyblock ) )
        modified++;
+    if( collapse_uids( &keyblock ) )
+       modified++;
 
     if( sec_keyblock ) { /* check that they match */
-       /* FIXME: check that they both match */
+       /* fixme: check that they both match */
        tty_printf(_("Secret key is available.\n"));
     }
 
@@ -573,12 +666,25 @@ keyedit_menu( const char *username, STRLIST locusr )
        }
        do {
            m_free(answer);
-           answer = cpr_get(N_("keyedit.cmd"), _("Command> "));
-           cpr_kill_prompt();
+           if( have_commands ) {
+               if( commands ) {
+                   answer = m_strdup( commands->d );
+                   commands = commands->next;
+               }
+               else if( opt.batch ) {
+                   answer = m_strdup("quit");
+               }
+               else
+                   have_commands = 0;
+           }
+           if( !have_commands ) {
+               answer = cpr_get("", _("Command> "));
+               cpr_kill_prompt();
+           }
            trim_spaces(answer);
        } while( *answer == '#' );
 
-       arg_number = 0;
+       arg_number = 0; /* Yes, here is the init which egcc complains about*/
        if( !*answer )
            cmd = cmdLIST;
        else if( *answer == CONTROL_D )
@@ -595,11 +701,14 @@ keyedit_menu( const char *username, STRLIST locusr )
                arg_number = atoi(p);
            }
 
-           for(i=0; cmds[i].name; i++ )
+           for(i=0; cmds[i].name; i++ ) {
                if( !stricmp( answer, cmds[i].name ) )
                    break;
-           if( cmds[i].need_sk && !sec_keyblock ) {
-               tty_printf(_("Need the secret key to to this.\n"));
+           }
+           if( sign_mode && !cmds[i].signmode )
+               cmd = cmdINVCMD;
+           else if( cmds[i].need_sk && !sec_keyblock ) {
+               tty_printf(_("Need the secret key to do this.\n"));
                cmd = cmdNOP;
            }
            else
@@ -608,51 +717,15 @@ keyedit_menu( const char *username, STRLIST locusr )
        switch( cmd )  {
          case cmdHELP:
            for(i=0; cmds[i].name; i++ ) {
-               if( cmds[i].need_sk && !sec_keyblock )
+               if( sign_mode && !cmds[i].signmode )
+                   ;
+               else if( cmds[i].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) );
            }
            break;
 
-         case cmdQUIT:
-           if( !modified && !sec_modified )
-               goto leave;
-           if( !cpr_get_answer_is_yes(N_("keyedit.save.okay"),
-                                       _("Save changes? ")) ) {
-               if( cpr_enabled()
-                   || cpr_get_answer_is_yes(N_("keyedit.cancel.okay"),
-                                            _("Quit without saving? ")) )
-                   goto leave;
-               break;
-           }
-           /* fall thru */
-         case cmdSAVE:
-           if( modified || sec_modified  ) {
-               if( modified ) {
-                   rc = update_keyblock( &keyblockpos, keyblock );
-                   if( rc ) {
-                       log_error(_("update failed: %s\n"), g10_errstr(rc) );
-                       break;
-                   }
-               }
-               if( sec_modified ) {
-                   rc = update_keyblock( &sec_keyblockpos, sec_keyblock );
-                   if( rc ) {
-                       log_error(_("update secret failed: %s\n"),
-                                                           g10_errstr(rc) );
-                       break;
-                   }
-               }
-           }
-           else
-               tty_printf(_("Key not changed so no update needed.\n"));
-           rc = update_trust_record( keyblock, 0, NULL );
-           if( rc )
-               log_error(_("update of trust db failed: %s\n"),
-                           g10_errstr(rc) );
-           goto leave;
-
          case cmdLIST:
            redisplay = 1;
            break;
@@ -679,14 +752,17 @@ keyedit_menu( const char *username, STRLIST locusr )
            break;
 
          case cmdSIGN: /* sign (only the public key) */
+         case cmdLSIGN: /* sign (only the public key) */
            if( count_uids(keyblock) > 1 && !count_selected_uids(keyblock) ) {
-               if( !cpr_get_answer_is_yes(N_("keyedit.sign_all.okay"),
+               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;
                }
            }
-           sign_uids( keyblock, locusr, &modified );
+           if( !sign_uids( keyblock, locusr, &modified, cmd == cmdLSIGN )
+               && sign_mode )
+               goto do_cmd_save;
            break;
 
          case cmdDEBUG:
@@ -707,7 +783,7 @@ keyedit_menu( const char *username, STRLIST locusr )
                 * get listed correctly */
                rc = update_trust_record( keyblock, 0, NULL );
                if( rc ) {
-                   log_error(_("update of trust db failed: %s\n"),
+                   log_error(_("update of trustdb failed: %s\n"),
                                g10_errstr(rc) );
                    rc = 0;
                }
@@ -722,7 +798,7 @@ keyedit_menu( const char *username, STRLIST locusr )
                else if( count_uids(keyblock) - n1 < 1 )
                    tty_printf(_("You can't delete the last user id!\n"));
                else if( cpr_get_answer_is_yes(
-                           N_("keyedit.remove.uid.okay"),
+                           "keyedit.remove.uid.okay",
                        n1 > 1? _("Really remove all selected user ids? ")
                              : _("Really remove this user id? ")
                       ) ) {
@@ -735,6 +811,19 @@ keyedit_menu( const char *username, STRLIST locusr )
            }
            break;
 
+         case cmdDELSIG: {
+               int n1;
+
+               if( !(n1=count_selected_uids(keyblock)) )
+                   tty_printf(_("You must select at least one user id.\n"));
+               else if( menu_delsig( keyblock ) ) {
+                   /* no redisplay here, because it may scroll away some
+                    * status output of delsig */
+                   modified = 1;
+               }
+           }
+           break;
+
          case cmdADDKEY:
            if( generate_subkeypair( keyblock, sec_keyblock ) ) {
                redisplay = 1;
@@ -749,7 +838,7 @@ keyedit_menu( const char *username, STRLIST locusr )
                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(
-                           N_("keyedit.remove.subkey.okay"),
+                           "keyedit.remove.subkey.okay",
                       n1 > 1?
                        _("Do you really want to delete the selected keys? "):
                        _("Do you really want to delete this key? ")
@@ -765,6 +854,28 @@ keyedit_menu( const char *username, STRLIST locusr )
            }
            break;
 
+         case cmdREVKEY: {
+               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.revoke.subkey.okay",
+                      n1 > 1?
+                       _("Do you really want to revoke the selected keys? "):
+                       _("Do you really want to revoke this key? ")
+                      ))
+                   ;
+               else {
+                   if( menu_revkey( keyblock, sec_keyblock ) ) {
+                       modified = 1;
+                       /*sec_modified = 1;*/
+                   }
+                   redisplay = 1;
+               }
+           }
+           break;
+
          case cmdEXPIRE:
            if( menu_expire( keyblock, sec_keyblock ) ) {
                merge_keys_and_selfsig( sec_keyblock );
@@ -797,6 +908,68 @@ keyedit_menu( const char *username, STRLIST locusr )
          case cmdNOP:
            break;
 
+         case cmdREVSIG:
+           if( menu_revsig( keyblock ) ) {
+               redisplay = 1;
+               modified = 1;
+           }
+           break;
+
+         case cmdENABLEKEY:
+         case cmdDISABLEKEY:
+           if( enable_disable_key( keyblock, cmd == cmdDISABLEKEY ) ) {
+               redisplay = 1;
+               modified = 1;
+           }
+           break;
+
+         case cmdQUIT:
+           if( have_commands )
+               goto leave;
+           if( !modified && !sec_modified )
+               goto leave;
+           if( !cpr_get_answer_is_yes("keyedit.save.okay",
+                                       _("Save changes? ")) ) {
+               if( cpr_enabled()
+                   || cpr_get_answer_is_yes("keyedit.cancel.okay",
+                                            _("Quit without saving? ")) )
+                   goto leave;
+               break;
+           }
+           /* fall thru */
+         case cmdSAVE:
+         do_cmd_save:
+           if( modified || sec_modified  ) {
+               if( modified ) {
+                   rc = update_keyblock( &keyblockpos, keyblock );
+                   if( rc ) {
+                       log_error(_("update failed: %s\n"), g10_errstr(rc) );
+                       break;
+                   }
+               }
+               if( sec_modified ) {
+                   rc = update_keyblock( &sec_keyblockpos, sec_keyblock );
+                   if( rc ) {
+                       log_error(_("update secret failed: %s\n"),
+                                                           g10_errstr(rc) );
+                       break;
+                   }
+               }
+           }
+           else
+               tty_printf(_("Key not changed so no update needed.\n"));
+           /* TODO: we should keep track whether we have changed
+            *       something relevant to the trustdb */
+           if( !modified && sign_mode )
+               rc = 0; /* we can skip at least in this case */
+           else
+               rc = update_trust_record( keyblock, 0, NULL );
+           if( rc )
+               log_error(_("update of trustdb failed: %s\n"),
+                           g10_errstr(rc) );
+           goto leave;
+
+         case cmdINVCMD:
          default:
            tty_printf("\n");
            tty_printf(_("Invalid command  (try \"help\")\n"));
@@ -860,7 +1033,7 @@ show_key_with_all_names( KBNODE keyblock, int only_marked,
                         int with_fpr, int with_subkeys, int with_prefs )
 {
     KBNODE node;
-    int i;
+    int i, rc;
 
     /* the keys */
     for( node = keyblock; node; node = node->next ) {
@@ -872,7 +1045,7 @@ show_key_with_all_names( KBNODE keyblock, int only_marked,
            if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
                /* do it here, so that debug messages don't clutter the
                 * output */
-               trust = query_trust_info(pk);
+               trust = query_trust_info(pk, NULL);
                otrust = get_ownertrust_info( pk->local_id );
            }
 
@@ -886,6 +1059,12 @@ show_key_with_all_names( KBNODE keyblock, int only_marked,
                          expirestr_from_pk(pk) );
            if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
                tty_printf(" trust: %c/%c", otrust, trust );
+               if( node->pkt->pkttype == PKT_PUBLIC_KEY
+                   && (get_ownertrust( pk->local_id )&TRUST_FLAG_DISABLED)) {
+                   tty_printf("\n*** ");
+                   tty_printf(_("This key has been disabled"));
+               }
+
                if( with_fpr  ) {
                    tty_printf("\n");
                    show_fingerprint( pk );
@@ -905,6 +1084,20 @@ show_key_with_all_names( KBNODE keyblock, int only_marked,
                          datestr_from_sk(sk),
                          expirestr_from_sk(sk) );
        }
+       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) );
+       }
     }
     /* the user ids */
     i = 0;
@@ -919,7 +1112,7 @@ show_key_with_all_names( KBNODE keyblock, int only_marked,
                   tty_printf("(%d)* ", i);
                else
                   tty_printf("(%d)  ", i);
-               tty_print_string( uid->name, uid->len );
+               tty_print_utf8_string( uid->name, uid->len );
                tty_printf("\n");
                if( with_prefs )
                    show_prefs( keyblock, uid );
@@ -945,7 +1138,7 @@ show_key_and_fingerprint( KBNODE keyblock )
        }
        else if( node->pkt->pkttype == PKT_USER_ID ) {
            PKT_user_id *uid = node->pkt->pkt.user_id;
-           tty_print_string( uid->name, uid->len );
+           tty_print_utf8_string( uid->name, uid->len );
            break;
        }
     }
@@ -1022,7 +1215,7 @@ menu_adduid( KBNODE pub_keyblock, KBNODE sec_keyblock )
     assert(pk && sk );
 
     rc = make_keysig_packet( &sig, pk, uid, NULL, sk, 0x13, 0,
-                            keygen_add_std_prefs, sk );
+                            keygen_add_std_prefs, pk );
     free_secret_key( sk );
     if( rc ) {
        log_error("signing failed: %s\n", g10_errstr(rc) );
@@ -1114,6 +1307,70 @@ menu_deluid( KBNODE pub_keyblock, KBNODE sec_keyblock )
 }
 
 
+static int
+menu_delsig( KBNODE pub_keyblock )
+{
+    KBNODE node;
+    PKT_user_id *uid = NULL;
+    int changed=0;
+
+    for( node = pub_keyblock; node; node = node->next ) {
+       if( node->pkt->pkttype == PKT_USER_ID ) {
+           uid = (node->flag & NODFLG_SELUID)? node->pkt->pkt.user_id : NULL;
+       }
+       else if( uid && node->pkt->pkttype == PKT_SIGNATURE ) {
+          int okay, valid, selfsig, inv_sig, no_key, other_err;
+
+           tty_printf("uid  ");
+           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 );
+
+          if( valid )
+              okay = cpr_get_answer_yes_no_quit(
+                  "keyedit.delsig.valid",
+                  _("Delete this good signature? (y/N/q)"));
+          else if( inv_sig || other_err )
+              okay = cpr_get_answer_yes_no_quit(
+                  "keyedit.delsig.invalid",
+                  _("Delete this invalid signature? (y/N/q)"));
+          else if( no_key )
+              okay = cpr_get_answer_yes_no_quit(
+                  "keyedit.delsig.unknown",
+                  _("Delete this unknown signature? (y/N/q)"));
+
+           if( okay == -1 )
+               break;
+          if( okay && selfsig && !cpr_get_answer_is_yes(
+                              "keyedit.delsig.selfsig",
+                             _("Really delete this self-signature? (y/N)") ))
+               okay = 0;
+           if( okay ) {
+               delete_kbnode( node );
+               changed++;
+           }
+
+       }
+       else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
+           uid = NULL;
+    }
+
+    if( changed ) {
+       commit_kbnode( &pub_keyblock );
+       tty_printf( changed == 1? _("Deleted %d signature.\n")
+                               : _("Deleted %d signatures.\n"), changed );
+    }
+    else
+       tty_printf( _("Nothing deleted.\n") );
+
+    return changed;
+}
+
+
 /****************
  * Remove some of the secondary keys
  */
@@ -1167,7 +1424,7 @@ menu_delkey( KBNODE pub_keyblock, KBNODE sec_keyblock )
 static int
 menu_expire( KBNODE pub_keyblock, KBNODE sec_keyblock )
 {
-    int n1, rc;
+    int n1, signumber, rc;
     u32 expiredate;
     int mainkey=0;
     PKT_secret_key *sk;    /* copy of the main sk */
@@ -1187,33 +1444,31 @@ menu_expire( KBNODE pub_keyblock, KBNODE sec_keyblock )
        return 0;
     }
     else if( n1 )
-       tty_printf(_("Changing exiration time for a secondary key.\n"));
+       tty_printf(_("Changing expiration time for a secondary key.\n"));
     else {
-       tty_printf(_("Changing exiration time for the primary key.\n"));
+       tty_printf(_("Changing expiration time for the primary key.\n"));
        mainkey=1;
     }
 
     expiredate = ask_expiredate();
-    /* fixme: check that expiredate is > key creation date */
-
-    /* get the secret key , make a copy and set the expiration time into
-     * that key (because keygen_add-key-expire expects it there)
-     */
     node = find_kbnode( sec_keyblock, PKT_SECRET_KEY );
     sk = copy_secret_key( NULL, node->pkt->pkt.secret_key);
-    sk->expiredate = expiredate;
 
     /* Now we can actually change the self signature(s) */
     main_pk = sub_pk = NULL;
     uid = NULL;
+    signumber = 0;
     for( node=pub_keyblock; node; node = node->next ) {
        if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
            main_pk = node->pkt->pkt.public_key;
            keyid_from_pk( main_pk, keyid );
+           main_pk->expiredate = expiredate;
        }
        else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
-                && (node->flag & NODFLG_SELKEY ) )
+                && (node->flag & NODFLG_SELKEY ) ) {
            sub_pk = node->pkt->pkt.public_key;
+           sub_pk->expiredate = expiredate;
+       }
        else if( node->pkt->pkttype == PKT_USER_ID )
            uid = node->pkt->pkt.user_id;
        else if( main_pk && node->pkt->pkttype == PKT_SIGNATURE ) {
@@ -1221,16 +1476,31 @@ menu_expire( KBNODE pub_keyblock, KBNODE sec_keyblock )
            if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1]
                && (    (mainkey && uid && (sig->sig_class&~3) == 0x10)
                     || (!mainkey && sig->sig_class == 0x18)  ) ) {
-               /* this is a selfsignature which should be replaced */
+               /* this is a selfsignature which is to be replaced */
                PKT_signature *newsig;
                PACKET *newpkt;
                KBNODE sn;
+               int signumber2 = 0;
+
+               signumber++;
+
+               if( (mainkey && main_pk->version < 4)
+                   || (!mainkey && sub_pk->version < 4 ) ) {
+                   log_info(_(
+                       "You can't change the expiration date of a v3 key\n"));
+                   free_secret_key( sk );
+                   return 0;
+               }
 
                /* find the corresponding secret self-signature */
                for( sn=sec_keyblock; sn; sn = sn->next ) {
-                   if( sn->pkt->pkttype == PKT_SIGNATURE
-                       && !cmp_signatures( sn->pkt->pkt.signature, sig ) )
-                       break;
+                   if( sn->pkt->pkttype == PKT_SIGNATURE ) {
+                       PKT_signature *b = sn->pkt->pkt.signature;
+                       if( keyid[0] == b->keyid[0] && keyid[1] == b->keyid[1]
+                           && sig->sig_class == b->sig_class
+                           && ++signumber2 == signumber )
+                           break;
+                   }
                }
                if( !sn )
                    log_info(_("No corresponding signature in secret ring\n"));
@@ -1239,11 +1509,11 @@ menu_expire( KBNODE pub_keyblock, KBNODE sec_keyblock )
                if( mainkey )
                    rc = make_keysig_packet( &newsig, main_pk, uid, NULL,
                                             sk, 0x13, 0,
-                                            keygen_add_std_prefs, sk );
+                                            keygen_add_std_prefs, main_pk );
                else
                    rc = make_keysig_packet( &newsig, main_pk, NULL, sub_pk,
                                             sk, 0x18, 0,
-                                            keygen_add_key_expire, sk );
+                                            keygen_add_key_expire, sub_pk );
                if( rc ) {
                    log_error("make_keysig_packet failed: %s\n",
                                                    g10_errstr(rc));
@@ -1279,21 +1549,21 @@ menu_expire( KBNODE pub_keyblock, KBNODE sec_keyblock )
  * Returns: True if the selection changed;
  */
 static int
-menu_select_uid( KBNODE keyblock, int index )
+menu_select_uid( KBNODE keyblock, int idx )
 {
     KBNODE node;
     int i;
 
     /* first check that the index is valid */
-    if( index ) {
+    if( idx ) {
        for( i=0, node = keyblock; node; node = node->next ) {
            if( node->pkt->pkttype == PKT_USER_ID ) {
-               if( ++i == index )
+               if( ++i == idx )
                    break;
            }
        }
        if( !node ) {
-           tty_printf(_("No user id with index %d\n"), index );
+           tty_printf(_("No user id with index %d\n"), idx );
            return 0;
        }
     }
@@ -1307,11 +1577,12 @@ menu_select_uid( KBNODE keyblock, int index )
     /* and toggle the new index */
     for( i=0, node = keyblock; node; node = node->next ) {
        if( node->pkt->pkttype == PKT_USER_ID ) {
-           if( ++i == index )
+           if( ++i == idx ) {
                if( (node->flag & NODFLG_SELUID) )
                    node->flag &= ~NODFLG_SELUID;
                else
                    node->flag |= NODFLG_SELUID;
+           }
        }
     }
 
@@ -1323,22 +1594,22 @@ menu_select_uid( KBNODE keyblock, int index )
  * Returns: True if the selection changed;
  */
 static int
-menu_select_key( KBNODE keyblock, int index )
+menu_select_key( KBNODE keyblock, int idx )
 {
     KBNODE node;
     int i;
 
     /* first check that the index is valid */
-    if( index ) {
+    if( idx ) {
        for( i=0, node = keyblock; node; node = node->next ) {
            if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
                || node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
-               if( ++i == index )
+               if( ++i == idx )
                    break;
            }
        }
        if( !node ) {
-           tty_printf(_("No secondary key with index %d\n"), index );
+           tty_printf(_("No secondary key with index %d\n"), idx );
            return 0;
        }
     }
@@ -1354,11 +1625,12 @@ menu_select_key( KBNODE keyblock, int index )
     for( i=0, node = keyblock; node; node = node->next ) {
        if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
            || node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
-           if( ++i == index )
+           if( ++i == idx ) {
                if( (node->flag & NODFLG_SELKEY) )
                    node->flag &= ~NODFLG_SELKEY;
                else
                    node->flag |= NODFLG_SELKEY;
+           }
        }
     }
 
@@ -1420,3 +1692,232 @@ count_selected_keys( KBNODE keyblock )
     return count_keys_with_flag( keyblock, NODFLG_SELKEY);
 }
 
+/*
+ * Ask whether the signature should be revoked.  If the user commits this,
+ * flag bit MARK_A is set on the signature and the user ID.
+ */
+static void
+ask_revoke_sig( KBNODE keyblock, KBNODE node )
+{
+    PKT_signature *sig = node->pkt->pkt.signature;
+    KBNODE unode = find_prev_kbnode( keyblock, node, PKT_USER_ID );
+
+    if( !unode ) {
+       log_error("Oops: no user ID for signature\n");
+       return;
+    }
+
+    tty_printf(_("user ID: \""));
+    tty_print_utf8_string( unode->pkt->pkt.user_id->name,
+                          unode->pkt->pkt.user_id->len );
+    tty_printf(_("\"\nsigned with your key %08lX at %s\n"),
+               sig->keyid[1], datestr_from_sig(sig) );
+
+    if( cpr_get_answer_is_yes("ask_revoke_sig.one",
+        _("Create a revocation certificate for this signature? (y/N)")) ) {
+       node->flag |= NODFLG_MARK_A;
+       unode->flag |= NODFLG_MARK_A;
+    }
+}
+
+/****************
+ * Display all user ids of the current public key together with signatures
+ * done by one of our keys.  Then walk over all this sigs and ask the user
+ * whether he wants to revoke this signature.
+ * Return: True when the keyblock has changed.
+ */
+static int
+menu_revsig( KBNODE keyblock )
+{
+    PKT_signature *sig;
+    PKT_public_key *primary_pk;
+    KBNODE node;
+    int changed = 0;
+    int upd_trust = 0;
+    int rc, any;
+
+    /* FIXME: detect duplicates here  */
+    tty_printf("You have signed these user IDs:\n");
+    for( node = keyblock; node; node = node->next ) {
+       node->flag &= ~(NODFLG_SELSIG | NODFLG_MARK_A);
+       if( node->pkt->pkttype == PKT_USER_ID ) {
+           PKT_user_id *uid = node->pkt->pkt.user_id;
+           /* Hmmm: Should we show only UIDs with a signature? */
+           tty_printf("     ");
+           tty_print_utf8_string( uid->name, uid->len );
+           tty_printf("\n");
+       }
+       else if( 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\n",
+                           sig->keyid[1], datestr_from_sig(sig) );
+               node->flag |= NODFLG_SELSIG;
+           }
+           else if( sig->sig_class == 0x30 ) {
+               tty_printf("   revoked by %08lX at %s\n",
+                           sig->keyid[1], datestr_from_sig(sig) );
+           }
+       }
+    }
+
+    /* ask */
+    for( node = keyblock; node; node = node->next ) {
+       if( !(node->flag & NODFLG_SELSIG) )
+           continue;
+       ask_revoke_sig( keyblock, node );
+    }
+
+    /* present selected */
+    any = 0;
+    for( node = keyblock; node; node = node->next ) {
+       if( !(node->flag & NODFLG_MARK_A) )
+           continue;
+       if( !any ) {
+           any = 1;
+           tty_printf("You are about to revoke these signatures:\n");
+       }
+       if( node->pkt->pkttype == PKT_USER_ID ) {
+           PKT_user_id *uid = node->pkt->pkt.user_id;
+           tty_printf("     ");
+           tty_print_utf8_string( uid->name, uid->len );
+           tty_printf("\n");
+       }
+       else if( node->pkt->pkttype == PKT_SIGNATURE ) {
+           sig = node->pkt->pkt.signature;
+           tty_printf("   signed by %08lX at %s\n",
+                           sig->keyid[1], datestr_from_sig(sig) );
+       }
+    }
+    if( !any )
+       return 0; /* none selected */
+
+    if( !cpr_get_answer_is_yes("ask_revoke_sig.okay",
+        _("Really create the revocation certificates? (y/N)")) )
+       return 0; /* forget it */
+
+
+    /* now we can sign the user ids */
+  reloop: /* (must use this, because we are modifing the list) */
+    primary_pk = keyblock->pkt->pkt.public_key;
+    for( node=keyblock; node; node = node->next ) {
+       KBNODE unode;
+       PACKET *pkt;
+       struct sign_uid_attrib attrib;
+       PKT_secret_key *sk;
+
+       if( !(node->flag & NODFLG_MARK_A)
+           || node->pkt->pkttype != PKT_SIGNATURE )
+           continue;
+       unode = find_prev_kbnode( keyblock, node, PKT_USER_ID );
+       assert( unode ); /* we already checked this */
+
+       memset( &attrib, 0, sizeof attrib );
+       node->flag &= ~NODFLG_MARK_A;
+       sk = m_alloc_secure_clear( sizeof *sk );
+       if( get_seckey( sk, node->pkt->pkt.signature->keyid ) ) {
+           log_info(_("no secret key\n"));
+           continue;
+       }
+       rc = make_keysig_packet( &sig, primary_pk,
+                                      unode->pkt->pkt.user_id,
+                                      NULL,
+                                      sk,
+                                      0x30, 0,
+                                      sign_uid_mk_attrib,
+                                      &attrib );
+       free_secret_key(sk);
+       if( rc ) {
+           log_error(_("signing failed: %s\n"), g10_errstr(rc));
+           return changed;
+       }
+       changed = 1; /* we changed the keyblock */
+       upd_trust = 1;
+
+       pkt = m_alloc_clear( sizeof *pkt );
+       pkt->pkttype = PKT_SIGNATURE;
+       pkt->pkt.signature = sig;
+       insert_kbnode( unode, new_kbnode(pkt), 0 );
+       goto reloop;
+    }
+
+    if( upd_trust )
+       clear_trust_checked_flag( primary_pk );
+
+    return changed;
+}
+
+/****************
+ * Revoke some of the secondary keys.
+ * Hmmm: Should we add a revocation to the secret keyring too?
+ *      Does its all make sense to duplicate most of the information?
+ */
+static int
+menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock )
+{
+    PKT_public_key *mainpk;
+    KBNODE node;
+    int changed = 0;
+    int upd_trust = 0;
+    int rc;
+
+  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 ) {
+       if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
+           && (node->flag & NODFLG_SELKEY) ) {
+           PACKET *pkt;
+           PKT_signature *sig;
+           PKT_secret_key *sk;
+           PKT_public_key *subpk = node->pkt->pkt.public_key;
+
+           node->flag &= ~NODFLG_SELKEY;
+           sk = copy_secret_key( NULL, sec_keyblock->pkt->pkt.secret_key );
+           rc = make_keysig_packet( &sig, mainpk, NULL, subpk, sk, 0x28, 0,
+                                    NULL, NULL );
+           free_secret_key(sk);
+           if( rc ) {
+               log_error(_("signing failed: %s\n"), g10_errstr(rc));
+               return changed;
+           }
+           changed = 1; /* we changed the keyblock */
+           upd_trust = 1;
+
+           pkt = m_alloc_clear( sizeof *pkt );
+           pkt->pkttype = PKT_SIGNATURE;
+           pkt->pkt.signature = sig;
+           insert_kbnode( node, new_kbnode(pkt), 0 );
+           goto reloop;
+       }
+    }
+    commit_kbnode( &pub_keyblock );
+    /*commit_kbnode( &sec_keyblock );*/
+
+    if( upd_trust )
+       clear_trust_checked_flag( mainpk );
+
+    return changed;
+}
+
+
+static int
+enable_disable_key( KBNODE keyblock, int disable )
+{
+    ulong lid = find_kbnode( keyblock, PKT_PUBLIC_KEY )
+                           ->pkt->pkt.public_key->local_id;
+    unsigned int trust, newtrust;
+
+    /* Note: Because the keys have beed displayed, we have
+     * ensured that local_id has been set */
+    trust = newtrust = get_ownertrust( lid );
+    newtrust &= ~TRUST_FLAG_DISABLED;
+    if( disable )
+       newtrust |= TRUST_FLAG_DISABLED;
+    if( trust == newtrust )
+       return 0; /* already in that state */
+    if( !update_ownertrust( lid, newtrust ) )
+       return 1;
+    return 0;
+}
+