See ChangeLog: Sun Apr 18 10:11:28 CEST 1999 Werner Koch
[gnupg.git] / g10 / keyedit.c
1 /* keyedit.c - keyedit stuff
2  *      Copyright (C) 1998 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <assert.h>
27 #include <ctype.h>
28
29 #include "options.h"
30 #include "packet.h"
31 #include "errors.h"
32 #include "iobuf.h"
33 #include "keydb.h"
34 #include "memory.h"
35 #include "util.h"
36 #include "main.h"
37 #include "trustdb.h"
38 #include "filter.h"
39 #include "ttyio.h"
40 #include "status.h"
41 #include "i18n.h"
42
43 static void show_prefs( KBNODE keyblock, PKT_user_id *uid );
44 static void show_key_with_all_names( KBNODE keyblock,
45             int only_marked, int with_fpr, int with_subkeys, int with_prefs );
46 static void show_key_and_fingerprint( KBNODE keyblock );
47 static void show_fingerprint( PKT_public_key *pk );
48 static int menu_adduid( KBNODE keyblock, KBNODE sec_keyblock );
49 static void menu_deluid( KBNODE pub_keyblock, KBNODE sec_keyblock );
50 static void menu_delkey( KBNODE pub_keyblock, KBNODE sec_keyblock );
51 static int menu_expire( KBNODE pub_keyblock, KBNODE sec_keyblock );
52 static int menu_select_uid( KBNODE keyblock, int idx );
53 static int menu_select_key( KBNODE keyblock, int idx );
54 static int count_uids( KBNODE keyblock );
55 static int count_uids_with_flag( KBNODE keyblock, unsigned flag );
56 static int count_keys_with_flag( KBNODE keyblock, unsigned flag );
57 static int count_selected_uids( KBNODE keyblock );
58 static int count_selected_keys( KBNODE keyblock );
59
60 #define CONTROL_D ('D' - 'A' + 1)
61
62 #define NODFLG_BADSIG (1<<0)  /* bad signature */
63 #define NODFLG_NOKEY  (1<<1)  /* no public key */
64 #define NODFLG_SIGERR (1<<2)  /* other sig error */
65
66 #define NODFLG_MARK_A (1<<4)  /* temporary mark */
67
68 #define NODFLG_SELUID (1<<8)  /* indicate the selected userid */
69 #define NODFLG_SELKEY (1<<9)  /* indicate the selected key */
70
71
72 struct sign_uid_attrib {
73     int non_exportable;
74 };
75
76
77
78
79 static int
80 get_keyblock_byname( KBNODE *keyblock, KBPOS *kbpos, const char *username )
81 {
82     int rc;
83
84     *keyblock = NULL;
85     /* search the userid */
86     rc = find_keyblock_byname( kbpos, username );
87     if( rc ) {
88         log_error(_("%s: user not found\n"), username );
89         return rc;
90     }
91
92     /* read the keyblock */
93     rc = read_keyblock( kbpos, keyblock );
94     if( rc )
95         log_error("%s: keyblock read problem: %s\n", username, g10_errstr(rc));
96     else
97         merge_keys_and_selfsig( *keyblock );
98
99     return rc;
100 }
101
102
103 /****************
104  * Check the keysigs and set the flags to indicate errors.
105  * Returns true if error found.
106  */
107 static int
108 check_all_keysigs( KBNODE keyblock, int only_selected )
109 {
110     KBNODE kbctx;
111     KBNODE node;
112     int rc;
113     int inv_sigs = 0;
114     int no_key = 0;
115     int oth_err = 0;
116     int has_selfsig = 0;
117     int mis_selfsig = 0;
118     int selected = !only_selected;
119     int anyuid = 0;
120
121     for( kbctx=NULL; (node=walk_kbnode( keyblock, &kbctx, 0)) ; ) {
122         if( node->pkt->pkttype == PKT_USER_ID ) {
123             PKT_user_id *uid = node->pkt->pkt.user_id;
124
125             if( only_selected )
126                 selected = (node->flag & NODFLG_SELUID);
127             if( selected ) {
128                 tty_printf("uid  ");
129                 tty_print_string( uid->name, uid->len );
130                 tty_printf("\n");
131                 if( anyuid && !has_selfsig )
132                     mis_selfsig++;
133                 has_selfsig = 0;
134                 anyuid = 1;
135             }
136         }
137         else if( selected && node->pkt->pkttype == PKT_SIGNATURE
138                  && (node->pkt->pkt.signature->sig_class&~3) == 0x10 ) {
139             PKT_signature *sig = node->pkt->pkt.signature;
140             int sigrc, selfsig;
141
142             switch( (rc = check_key_signature( keyblock, node, &selfsig)) ) {
143               case 0:
144                 node->flag &= ~(NODFLG_BADSIG|NODFLG_NOKEY|NODFLG_SIGERR);
145                 sigrc = '!';
146                 break;
147               case G10ERR_BAD_SIGN:
148                 node->flag = NODFLG_BADSIG;
149                 sigrc = '-';
150                 inv_sigs++;
151                 break;
152               case G10ERR_NO_PUBKEY:
153                 node->flag = NODFLG_NOKEY;
154                 sigrc = '?';
155                 no_key++;
156                 break;
157               default:
158                 node->flag = NODFLG_SIGERR;
159                 sigrc = '%';
160                 oth_err++;
161                 break;
162             }
163             if( sigrc != '?' ) {
164                 tty_printf("sig%c       %08lX %s   ",
165                         sigrc, sig->keyid[1], datestr_from_sig(sig));
166                 if( sigrc == '%' )
167                     tty_printf("[%s] ", g10_errstr(rc) );
168                 else if( sigrc == '?' )
169                     ;
170                 else if( selfsig ) {
171                     tty_printf( _("[self-signature]") );
172                     if( sigrc == '!' )
173                         has_selfsig = 1;
174                 }
175                 else {
176                     size_t n;
177                     char *p = get_user_id( sig->keyid, &n );
178                     tty_print_string( p, n > 40? 40 : n );
179                     m_free(p);
180                 }
181                 tty_printf("\n");
182                 /* fixme: Should we update the trustdb here */
183             }
184         }
185     }
186     if( !has_selfsig )
187         mis_selfsig++;
188     if( inv_sigs == 1 )
189         tty_printf(_("1 bad signature\n"), inv_sigs );
190     else if( inv_sigs )
191         tty_printf(_("%d bad signatures\n"), inv_sigs );
192     if( no_key == 1 )
193         tty_printf(_("1 signature not checked due to a missing key\n") );
194     else if( no_key )
195         tty_printf(_("%d signatures not checked due to missing keys\n"), no_key );
196     if( oth_err == 1 )
197         tty_printf(_("1 signature not checked due to an error\n") );
198     else if( oth_err )
199         tty_printf(_("%d signatures not checked due to errors\n"), oth_err );
200     if( mis_selfsig == 1 )
201         tty_printf(_("1 user id without valid self-signature detected\n"));
202     else if( mis_selfsig  )
203         tty_printf(_("%d user ids without valid self-signatures detected\n"),
204                                                                     mis_selfsig);
205
206     return inv_sigs || no_key || oth_err || mis_selfsig;
207 }
208
209
210
211
212 int
213 sign_uid_mk_attrib( PKT_signature *sig, void *opaque )
214 {
215     struct sign_uid_attrib *attrib = opaque;
216     byte buf[8];
217
218     if( attrib->non_exportable ) {
219         buf[0] = 0; /* not exportable */
220         build_sig_subpkt( sig, SIGSUBPKT_EXPORTABLE, buf, 1 );
221     }
222
223     return 0;
224 }
225
226
227
228 /****************
229  * Loop over all locusr and and sign the uids after asking.
230  * If no user id is marked, all user ids will be signed;
231  * if some user_ids are marked those will be signed.
232  */
233 static int
234 sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified, int local )
235 {
236     int rc = 0;
237     SK_LIST sk_list = NULL;
238     SK_LIST sk_rover = NULL;
239     PKT_secret_key *sk = NULL;
240     KBNODE node, uidnode;
241     PKT_public_key *primary_pk=NULL;
242     int select_all = !count_selected_uids(keyblock);
243     int upd_trust = 0;
244
245     /* build a list of all signators */
246     rc=build_sk_list( locusr, &sk_list, 0, 1 );
247     if( rc )
248         goto leave;
249
250     /* loop over all signaturs */
251     for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) {
252         u32 sk_keyid[2];
253         size_t n;
254         char *p;
255
256         /* we have to use a copy of the sk, because make_keysig_packet
257          * may remove the protection from sk and if we did other
258          * changes to the secret key, we would save the unprotected
259          * version */
260         if( sk )
261             free_secret_key(sk);
262         sk = copy_secret_key( NULL, sk_rover->sk );
263         keyid_from_sk( sk, sk_keyid );
264         /* set mark A for all selected user ids */
265         for( node=keyblock; node; node = node->next ) {
266             if( select_all || (node->flag & NODFLG_SELUID) )
267                 node->flag |= NODFLG_MARK_A;
268             else
269                 node->flag &= ~NODFLG_MARK_A;
270         }
271         /* reset mark for uids which are already signed */
272         uidnode = NULL;
273         for( node=keyblock; node; node = node->next ) {
274             if( node->pkt->pkttype == PKT_USER_ID ) {
275                 uidnode = (node->flag & NODFLG_MARK_A)? node : NULL;
276             }
277             else if( uidnode && node->pkt->pkttype == PKT_SIGNATURE
278                 && (node->pkt->pkt.signature->sig_class&~3) == 0x10 ) {
279                 if( sk_keyid[0] == node->pkt->pkt.signature->keyid[0]
280                     && sk_keyid[1] == node->pkt->pkt.signature->keyid[1] ) {
281                     tty_printf(_("Already signed by key %08lX\n"),
282                                                         (ulong)sk_keyid[1] );
283                     uidnode->flag &= ~NODFLG_MARK_A; /* remove mark */
284                 }
285             }
286         }
287         /* check whether any uids are left for signing */
288         if( !count_uids_with_flag(keyblock, NODFLG_MARK_A) ) {
289             tty_printf(_("Nothing to sign with key %08lX\n"),
290                                                   (ulong)sk_keyid[1] );
291             continue;
292         }
293         /* Ask whether we really should sign these user id(s) */
294         tty_printf("\n");
295         show_key_with_all_names( keyblock, 1, 1, 0, 0 );
296         tty_printf("\n");
297         tty_printf(_(
298              "Are you really sure that you want to sign this key\n"
299              "with your key: \""));
300         p = get_user_id( sk_keyid, &n );
301         tty_print_string( p, n );
302         m_free(p); p = NULL;
303         tty_printf("\"\n\n");
304
305         if( local )
306             tty_printf(
307                   _("The signature will be marked as non-exportable.\n\n"));
308
309
310         if( opt.batch && opt.answer_yes )
311             ;
312         else if( !cpr_get_answer_is_yes("sign_uid.okay", _("Really sign? ")) )
313             continue;
314         /* now we can sign the user ids */
315       reloop: /* (must use this, because we are modifing the list) */
316         primary_pk = NULL;
317         for( node=keyblock; node; node = node->next ) {
318             if( node->pkt->pkttype == PKT_PUBLIC_KEY )
319                 primary_pk = node->pkt->pkt.public_key;
320             else if( node->pkt->pkttype == PKT_USER_ID
321                      && (node->flag & NODFLG_MARK_A) ) {
322                 PACKET *pkt;
323                 PKT_signature *sig;
324                 struct sign_uid_attrib attrib;
325
326                 assert( primary_pk );
327                 memset( &attrib, 0, sizeof attrib );
328                 attrib.non_exportable = local;
329                 node->flag &= ~NODFLG_MARK_A;
330                 rc = make_keysig_packet( &sig, primary_pk,
331                                                node->pkt->pkt.user_id,
332                                                NULL,
333                                                sk,
334                                                0x10, 0,
335                                                sign_uid_mk_attrib,
336                                                &attrib );
337                 if( rc ) {
338                     log_error(_("signing failed: %s\n"), g10_errstr(rc));
339                     goto leave;
340                 }
341                 *ret_modified = 1; /* we changed the keyblock */
342                 upd_trust = 1;
343
344                 pkt = m_alloc_clear( sizeof *pkt );
345                 pkt->pkttype = PKT_SIGNATURE;
346                 pkt->pkt.signature = sig;
347                 insert_kbnode( node, new_kbnode(pkt), PKT_SIGNATURE );
348                 goto reloop;
349             }
350         }
351     } /* end loop over signators */
352     if( upd_trust && primary_pk ) {
353         rc = clear_trust_checked_flag( primary_pk );
354     }
355
356
357   leave:
358     release_sk_list( sk_list );
359     if( sk )
360         free_secret_key(sk);
361     return rc;
362 }
363
364
365
366 /****************
367  * Change the passphrase of the primary and all secondary keys.
368  * We use only one passphrase for all keys.
369  */
370 static int
371 change_passphrase( KBNODE keyblock )
372 {
373     int rc = 0;
374     int changed=0;
375     KBNODE node;
376     PKT_secret_key *sk;
377     char *passphrase = NULL;
378
379     node = find_kbnode( keyblock, PKT_SECRET_KEY );
380     if( !node ) {
381         log_error("Oops; secret key not found anymore!\n");
382         goto leave;
383     }
384     sk = node->pkt->pkt.secret_key;
385
386     switch( is_secret_key_protected( sk ) ) {
387       case -1:
388         rc = G10ERR_PUBKEY_ALGO;
389         break;
390       case 0:
391         tty_printf(_("This key is not protected.\n"));
392         break;
393       default:
394         tty_printf(_("Key is protected.\n"));
395         rc = check_secret_key( sk, 0 );
396         if( !rc )
397             passphrase = get_last_passphrase();
398         break;
399     }
400
401     /* unprotect all subkeys (use the supplied passphrase or ask)*/
402     for(node=keyblock; !rc && node; node = node->next ) {
403         if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
404             PKT_secret_key *subsk = node->pkt->pkt.secret_key;
405             set_next_passphrase( passphrase );
406             rc = check_secret_key( subsk, 0 );
407         }
408     }
409
410     if( rc )
411         tty_printf(_("Can't edit this key: %s\n"), g10_errstr(rc));
412     else {
413         DEK *dek = NULL;
414         STRING2KEY *s2k = m_alloc_secure( sizeof *s2k );
415
416         tty_printf(_("Enter the new passphrase for this secret key.\n\n") );
417
418         set_next_passphrase( NULL );
419         for(;;) {
420             s2k->mode = opt.s2k_mode;
421             s2k->hash_algo = opt.s2k_digest_algo;
422             dek = passphrase_to_dek( NULL, opt.s2k_cipher_algo, s2k, 2 );
423             if( !dek ) {
424                 tty_printf(_("passphrase not correctly repeated; try again.\n"));
425             }
426             else if( !dek->keylen ) {
427                 rc = 0;
428                 tty_printf(_( "You don't want a passphrase -"
429                             " this is probably a *bad* idea!\n\n"));
430                 if( cpr_get_answer_is_yes("change_passwd.empty.okay",
431                                _("Do you really want to do this? ")))
432                     changed++;
433                 break;
434             }
435             else { /* okay */
436                 sk->protect.algo = dek->algo;
437                 sk->protect.s2k = *s2k;
438                 rc = protect_secret_key( sk, dek );
439                 for(node=keyblock; !rc && node; node = node->next ) {
440                     if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
441                         PKT_secret_key *subsk = node->pkt->pkt.secret_key;
442                         subsk->protect.algo = dek->algo;
443                         subsk->protect.s2k = *s2k;
444                         rc = protect_secret_key( subsk, dek );
445                     }
446                 }
447                 if( rc )
448                     log_error("protect_secret_key failed: %s\n", g10_errstr(rc) );
449                 else
450                     changed++;
451                 break;
452             }
453         }
454         m_free(s2k);
455         m_free(dek);
456     }
457
458   leave:
459     m_free( passphrase );
460     set_next_passphrase( NULL );
461     return changed && !rc;
462 }
463
464
465 /****************
466  * There are some keys out (due to a bug in gnupg), where the sequence
467  * of the packets is wrong.  This function fixes that.
468  * Returns: true if the keyblock has fixed.
469  */
470 static int
471 fix_keyblock( KBNODE keyblock )
472 {
473     KBNODE node, last, subkey;
474     int fixed=0;
475
476     /* locate key signatures of class 0x10..0x13 behind sub key packets */
477     for( subkey=last=NULL, node = keyblock; node;
478                                             last=node, node = node->next ) {
479         switch( node->pkt->pkttype ) {
480           case PKT_PUBLIC_SUBKEY:
481           case PKT_SECRET_SUBKEY:
482             if( !subkey )
483                 subkey = last; /* actually it is the one before the subkey */
484             break;
485           case PKT_SIGNATURE:
486             if( subkey ) {
487                 PKT_signature *sig = node->pkt->pkt.signature;
488                 if( sig->sig_class >= 0x10 && sig->sig_class <= 0x13 ) {
489                     log_info(_(
490                         "moving a key signature to the correct place\n"));
491                     last->next = node->next;
492                     node->next = subkey->next;
493                     subkey->next = node;
494                     node = last;
495                     fixed=1;
496                 }
497             }
498             break;
499           default: break;
500         }
501     }
502
503     return fixed;
504 }
505
506 /****************
507  * Menu driven key editor
508  *
509  * Note: to keep track of some selection we use node->mark MARKBIT_xxxx.
510  */
511
512 void
513 keyedit_menu( const char *username, STRLIST locusr, STRLIST commands )
514 {
515     enum cmdids { cmdNONE = 0,
516            cmdQUIT, cmdHELP, cmdFPR, cmdLIST, cmdSELUID, cmdCHECK, cmdSIGN,
517            cmdLSIGN,
518            cmdDEBUG, cmdSAVE, cmdADDUID, cmdDELUID, cmdADDKEY, cmdDELKEY,
519            cmdTOGGLE, cmdSELKEY, cmdPASSWD, cmdTRUST, cmdPREF, cmdEXPIRE,
520            cmdNOP };
521     static struct { const char *name;
522                     enum cmdids id;
523                     int need_sk;
524                     const char *desc;
525                   } cmds[] = {
526         { N_("quit")    , cmdQUIT   , 0, N_("quit this menu") },
527         { N_("q")       , cmdQUIT   , 0, NULL   },
528         { N_("save")    , cmdSAVE   , 0, N_("save and quit") },
529         { N_("help")    , cmdHELP   , 0, N_("show this help") },
530         {    "?"        , cmdHELP   , 0, NULL   },
531         { N_("fpr")     , cmdFPR    , 0, N_("show fingerprint") },
532         { N_("list")    , cmdLIST   , 0, N_("list key and user ids") },
533         { N_("l")       , cmdLIST   , 0, NULL   },
534         { N_("uid")     , cmdSELUID , 0, N_("select user id N") },
535         { N_("key")     , cmdSELKEY , 0, N_("select secondary key N") },
536         { N_("check")   , cmdCHECK  , 0, N_("list signatures") },
537         { N_("c")       , cmdCHECK  , 0, NULL },
538         { N_("sign")    , cmdSIGN   , 0, N_("sign the key") },
539         { N_("s")       , cmdSIGN   , 0, NULL },
540         { N_("lsign")   , cmdLSIGN  , 0, N_("sign the key locally") },
541         { N_("debug")   , cmdDEBUG  , 0, NULL },
542         { N_("adduid")  , cmdADDUID , 1, N_("add a user id") },
543         { N_("deluid")  , cmdDELUID , 0, N_("delete user id") },
544         { N_("addkey")  , cmdADDKEY , 1, N_("add a secondary key") },
545         { N_("delkey")  , cmdDELKEY , 0, N_("delete a secondary key") },
546         { N_("expire")  , cmdEXPIRE , 1, N_("change the expire date") },
547         { N_("toggle")  , cmdTOGGLE , 1, N_("toggle between secret "
548                                             "and public key listing") },
549         { N_("t"     )  , cmdTOGGLE , 1, NULL },
550         { N_("pref")    , cmdPREF  , 0, N_("list preferences") },
551         { N_("passwd")  , cmdPASSWD , 1, N_("change the passphrase") },
552         { N_("trust")   , cmdTRUST , 0, N_("change the ownertrust") },
553
554     { NULL, cmdNONE } };
555     enum cmdids cmd;
556     int rc = 0;
557     KBNODE keyblock = NULL;
558     KBPOS keyblockpos;
559     KBNODE sec_keyblock = NULL;
560     KBPOS sec_keyblockpos;
561     KBNODE cur_keyblock;
562     char *answer = NULL;
563     int redisplay = 1;
564     int modified = 0;
565     int sec_modified = 0;
566     int toggle;
567     int have_commands = !!commands;
568
569
570     if( opt.batch && !have_commands ) {
571         log_error(_("can't do that in batchmode\n"));
572         goto leave;
573     }
574
575     /* first try to locate it as secret key */
576     rc = find_secret_keyblock_byname( &sec_keyblockpos, username );
577     if( !rc ) {
578         rc = read_keyblock( &sec_keyblockpos, &sec_keyblock );
579         if( rc ) {
580             log_error("%s: secret keyblock read problem: %s\n",
581                                             username, g10_errstr(rc));
582             goto leave;
583         }
584         merge_keys_and_selfsig( sec_keyblock );
585         if( fix_keyblock( sec_keyblock ) )
586             sec_modified++;
587     }
588
589     /* and now get the public key */
590     rc = get_keyblock_byname( &keyblock, &keyblockpos, username );
591     if( rc )
592         goto leave;
593     if( fix_keyblock( keyblock ) )
594         modified++;
595
596     if( sec_keyblock ) { /* check that they match */
597         /* FIXME: check that they both match */
598         tty_printf(_("Secret key is available.\n"));
599     }
600
601     toggle = 0;
602     cur_keyblock = keyblock;
603     for(;;) { /* main loop */
604         int i, arg_number;
605         char *p;
606
607         tty_printf("\n");
608         if( redisplay ) {
609             show_key_with_all_names( cur_keyblock, 0, 0, 1, 0 );
610             tty_printf("\n");
611             redisplay = 0;
612         }
613         do {
614             m_free(answer);
615             if( have_commands ) {
616                 if( commands ) {
617                     answer = m_strdup( commands->d );
618                     commands = commands->next;
619                 }
620                 else if( opt.batch ) {
621                     answer = m_strdup("quit");
622                 }
623                 else
624                     have_commands = 0;
625             }
626             if( !have_commands ) {
627                 answer = cpr_get("keyedit.cmd", _("Command> "));
628                 cpr_kill_prompt();
629             }
630             trim_spaces(answer);
631         } while( *answer == '#' );
632
633         arg_number = 0;
634         if( !*answer )
635             cmd = cmdLIST;
636         else if( *answer == CONTROL_D )
637             cmd = cmdQUIT;
638         else if( isdigit( *answer ) ) {
639             cmd = cmdSELUID;
640             arg_number = atoi(answer);
641         }
642         else {
643             if( (p=strchr(answer,' ')) ) {
644                 *p++ = 0;
645                 trim_spaces(answer);
646                 trim_spaces(p);
647                 arg_number = atoi(p);
648             }
649
650             for(i=0; cmds[i].name; i++ )
651                 if( !stricmp( answer, cmds[i].name ) )
652                     break;
653             if( cmds[i].need_sk && !sec_keyblock ) {
654                 tty_printf(_("Need the secret key to do this.\n"));
655                 cmd = cmdNOP;
656             }
657             else
658                 cmd = cmds[i].id;
659         }
660         switch( cmd )  {
661           case cmdHELP:
662             for(i=0; cmds[i].name; i++ ) {
663                 if( cmds[i].need_sk && !sec_keyblock )
664                     ; /* skip if we do not have the secret key */
665                 else if( cmds[i].desc )
666                     tty_printf("%-10s %s\n", cmds[i].name, _(cmds[i].desc) );
667             }
668             break;
669
670           case cmdQUIT:
671             if( have_commands )
672                 goto leave;
673             if( !modified && !sec_modified )
674                 goto leave;
675             if( !cpr_get_answer_is_yes("keyedit.save.okay",
676                                         _("Save changes? ")) ) {
677                 if( cpr_enabled()
678                     || cpr_get_answer_is_yes("keyedit.cancel.okay",
679                                              _("Quit without saving? ")) )
680                     goto leave;
681                 break;
682             }
683             /* fall thru */
684           case cmdSAVE:
685             if( modified || sec_modified  ) {
686                 if( modified ) {
687                     rc = update_keyblock( &keyblockpos, keyblock );
688                     if( rc ) {
689                         log_error(_("update failed: %s\n"), g10_errstr(rc) );
690                         break;
691                     }
692                 }
693                 if( sec_modified ) {
694                     rc = update_keyblock( &sec_keyblockpos, sec_keyblock );
695                     if( rc ) {
696                         log_error(_("update secret failed: %s\n"),
697                                                             g10_errstr(rc) );
698                         break;
699                     }
700                 }
701             }
702             else
703                 tty_printf(_("Key not changed so no update needed.\n"));
704             rc = update_trust_record( keyblock, 0, NULL );
705             if( rc )
706                 log_error(_("update of trustdb failed: %s\n"),
707                             g10_errstr(rc) );
708             goto leave;
709
710           case cmdLIST:
711             redisplay = 1;
712             break;
713
714           case cmdFPR:
715             show_key_and_fingerprint( keyblock );
716             break;
717
718           case cmdSELUID:
719             if( menu_select_uid( cur_keyblock, arg_number ) )
720                 redisplay = 1;
721             break;
722
723           case cmdSELKEY:
724             if( menu_select_key( cur_keyblock, arg_number ) )
725                 redisplay = 1;
726             break;
727
728           case cmdCHECK:
729             /* we can only do this with the public key becuase the
730              * check functions can't cope with secret keys and it
731              * is questionable whether this would make sense at all */
732             check_all_keysigs( keyblock, count_selected_uids(keyblock) );
733             break;
734
735           case cmdSIGN: /* sign (only the public key) */
736           case cmdLSIGN: /* sign (only the public key) */
737             if( count_uids(keyblock) > 1 && !count_selected_uids(keyblock) ) {
738                 if( !cpr_get_answer_is_yes("keyedit.sign_all.okay",
739                                            _("Really sign all user ids? ")) ) {
740                     tty_printf(_("Hint: Select the user ids to sign\n"));
741                     break;
742                 }
743             }
744             sign_uids( keyblock, locusr, &modified, cmd == cmdLSIGN );
745             break;
746
747           case cmdDEBUG:
748             dump_kbnode( cur_keyblock );
749             break;
750
751           case cmdTOGGLE:
752             toggle = !toggle;
753             cur_keyblock = toggle? sec_keyblock : keyblock;
754             redisplay = 1;
755             break;
756
757           case cmdADDUID:
758             if( menu_adduid( keyblock, sec_keyblock ) ) {
759                 redisplay = 1;
760                 sec_modified = modified = 1;
761                 /* must update the trustdb already here, so that preferences
762                  * get listed correctly */
763                 rc = update_trust_record( keyblock, 0, NULL );
764                 if( rc ) {
765                     log_error(_("update of trustdb failed: %s\n"),
766                                 g10_errstr(rc) );
767                     rc = 0;
768                 }
769             }
770             break;
771
772           case cmdDELUID: {
773                 int n1;
774
775                 if( !(n1=count_selected_uids(keyblock)) )
776                     tty_printf(_("You must select at least one user id.\n"));
777                 else if( count_uids(keyblock) - n1 < 1 )
778                     tty_printf(_("You can't delete the last user id!\n"));
779                 else if( cpr_get_answer_is_yes(
780                             "keyedit.remove.uid.okay",
781                         n1 > 1? _("Really remove all selected user ids? ")
782                               : _("Really remove this user id? ")
783                        ) ) {
784                     menu_deluid( keyblock, sec_keyblock );
785                     redisplay = 1;
786                     modified = 1;
787                     if( sec_keyblock )
788                        sec_modified = 1;
789                 }
790             }
791             break;
792
793           case cmdADDKEY:
794             if( generate_subkeypair( keyblock, sec_keyblock ) ) {
795                 redisplay = 1;
796                 sec_modified = modified = 1;
797             }
798             break;
799
800
801           case cmdDELKEY: {
802                 int n1;
803
804                 if( !(n1=count_selected_keys( keyblock )) )
805                     tty_printf(_("You must select at least one key.\n"));
806                 else if( sec_keyblock && !cpr_get_answer_is_yes(
807                             "keyedit.remove.subkey.okay",
808                        n1 > 1?
809                         _("Do you really want to delete the selected keys? "):
810                         _("Do you really want to delete this key? ")
811                        ))
812                     ;
813                 else {
814                     menu_delkey( keyblock, sec_keyblock );
815                     redisplay = 1;
816                     modified = 1;
817                     if( sec_keyblock )
818                        sec_modified = 1;
819                 }
820             }
821             break;
822
823           case cmdEXPIRE:
824             if( menu_expire( keyblock, sec_keyblock ) ) {
825                 merge_keys_and_selfsig( sec_keyblock );
826                 merge_keys_and_selfsig( keyblock );
827                 sec_modified = 1;
828                 modified = 1;
829                 redisplay = 1;
830             }
831             break;
832
833           case cmdPASSWD:
834             if( change_passphrase( sec_keyblock ) )
835                 sec_modified = 1;
836             break;
837
838           case cmdTRUST:
839             show_key_with_all_names( keyblock, 0, 0, 1, 0 );
840             tty_printf("\n");
841             if( edit_ownertrust( find_kbnode( keyblock,
842                       PKT_PUBLIC_KEY )->pkt->pkt.public_key->local_id, 1 ) )
843                 redisplay = 1;
844             /* we don't need to set modified here, as the trustvalues
845              * are updated immediately */
846             break;
847
848           case cmdPREF:
849             show_key_with_all_names( keyblock, 0, 0, 0, 1 );
850             break;
851
852           case cmdNOP:
853             break;
854
855           default:
856             tty_printf("\n");
857             tty_printf(_("Invalid command  (try \"help\")\n"));
858             break;
859         }
860     } /* end main loop */
861
862   leave:
863     release_kbnode( keyblock );
864     release_kbnode( sec_keyblock );
865     m_free(answer);
866 }
867
868
869 /****************
870  * show preferences of a public keyblock.
871  */
872 static void
873 show_prefs( KBNODE keyblock, PKT_user_id *uid )
874 {
875     KBNODE node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
876     PKT_public_key *pk;
877     byte *p;
878     int i;
879     size_t n;
880     byte namehash[20];
881
882     if( !node )
883         return; /* is a secret keyblock */
884     pk = node->pkt->pkt.public_key;
885     if( !pk->local_id ) {
886         log_error("oops: no LID\n");
887         return;
888     }
889
890     rmd160_hash_buffer( namehash, uid->name, uid->len );
891
892     p = get_pref_data( pk->local_id, namehash, &n );
893     if( !p )
894         return;
895
896     tty_printf("    ");
897     for(i=0; i < n; i+=2 ) {
898         if( p[i] )
899             tty_printf( " %c%d", p[i] == PREFTYPE_SYM    ? 'S' :
900                                  p[i] == PREFTYPE_HASH   ? 'H' :
901                                  p[i] == PREFTYPE_COMPR  ? 'Z' : '?', p[i+1]);
902     }
903     tty_printf("\n");
904
905     m_free(p);
906 }
907
908
909 /****************
910  * Display the key a the user ids, if only_marked is true, do only
911  * so for user ids with mark A flag set and dont display the index number
912  */
913 static void
914 show_key_with_all_names( KBNODE keyblock, int only_marked,
915                          int with_fpr, int with_subkeys, int with_prefs )
916 {
917     KBNODE node;
918     int i;
919
920     /* the keys */
921     for( node = keyblock; node; node = node->next ) {
922         if( node->pkt->pkttype == PKT_PUBLIC_KEY
923             || (with_subkeys && node->pkt->pkttype == PKT_PUBLIC_SUBKEY) ) {
924             PKT_public_key *pk = node->pkt->pkt.public_key;
925             int otrust=0, trust=0;
926
927             if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
928                 /* do it here, so that debug messages don't clutter the
929                  * output */
930                 trust = query_trust_info(pk, NULL);
931                 otrust = get_ownertrust_info( pk->local_id );
932             }
933
934             tty_printf("%s%c %4u%c/%08lX  created: %s expires: %s",
935                           node->pkt->pkttype == PKT_PUBLIC_KEY? "pub":"sub",
936                           (node->flag & NODFLG_SELKEY)? '*':' ',
937                           nbits_from_pk( pk ),
938                           pubkey_letter( pk->pubkey_algo ),
939                           (ulong)keyid_from_pk(pk,NULL),
940                           datestr_from_pk(pk),
941                           expirestr_from_pk(pk) );
942             if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
943                 tty_printf(" trust: %c/%c", otrust, trust );
944                 if( with_fpr  ) {
945                     tty_printf("\n");
946                     show_fingerprint( pk );
947                 }
948             }
949             tty_printf("\n");
950         }
951         else if( node->pkt->pkttype == PKT_SECRET_KEY
952             || (with_subkeys && node->pkt->pkttype == PKT_SECRET_SUBKEY) ) {
953             PKT_secret_key *sk = node->pkt->pkt.secret_key;
954             tty_printf("%s%c %4u%c/%08lX  created: %s expires: %s\n",
955                           node->pkt->pkttype == PKT_SECRET_KEY? "sec":"sbb",
956                           (node->flag & NODFLG_SELKEY)? '*':' ',
957                           nbits_from_sk( sk ),
958                           pubkey_letter( sk->pubkey_algo ),
959                           (ulong)keyid_from_sk(sk,NULL),
960                           datestr_from_sk(sk),
961                           expirestr_from_sk(sk) );
962         }
963     }
964     /* the user ids */
965     i = 0;
966     for( node = keyblock; node; node = node->next ) {
967         if( node->pkt->pkttype == PKT_USER_ID ) {
968             PKT_user_id *uid = node->pkt->pkt.user_id;
969             ++i;
970             if( !only_marked || (only_marked && (node->flag & NODFLG_MARK_A))){
971                 if( only_marked )
972                    tty_printf("     ");
973                 else if( node->flag & NODFLG_SELUID )
974                    tty_printf("(%d)* ", i);
975                 else
976                    tty_printf("(%d)  ", i);
977                 tty_print_string( uid->name, uid->len );
978                 tty_printf("\n");
979                 if( with_prefs )
980                     show_prefs( keyblock, uid );
981             }
982         }
983     }
984 }
985
986 static void
987 show_key_and_fingerprint( KBNODE keyblock )
988 {
989     KBNODE node;
990     PKT_public_key *pk = NULL;
991
992     for( node = keyblock; node; node = node->next ) {
993         if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
994             pk = node->pkt->pkt.public_key;
995             tty_printf("pub  %4u%c/%08lX %s ",
996                           nbits_from_pk( pk ),
997                           pubkey_letter( pk->pubkey_algo ),
998                           (ulong)keyid_from_pk(pk,NULL),
999                           datestr_from_pk(pk) );
1000         }
1001         else if( node->pkt->pkttype == PKT_USER_ID ) {
1002             PKT_user_id *uid = node->pkt->pkt.user_id;
1003             tty_print_string( uid->name, uid->len );
1004             break;
1005         }
1006     }
1007     tty_printf("\n");
1008     if( pk )
1009         show_fingerprint( pk );
1010 }
1011
1012
1013 static void
1014 show_fingerprint( PKT_public_key *pk )
1015 {
1016     byte array[MAX_FINGERPRINT_LEN], *p;
1017     size_t i, n;
1018
1019     fingerprint_from_pk( pk, array, &n );
1020     p = array;
1021     tty_printf("             Fingerprint:");
1022     if( n == 20 ) {
1023         for(i=0; i < n ; i++, i++, p += 2 ) {
1024             if( i == 10 )
1025                 tty_printf(" ");
1026             tty_printf(" %02X%02X", *p, p[1] );
1027         }
1028     }
1029     else {
1030         for(i=0; i < n ; i++, p++ ) {
1031             if( i && !(i%8) )
1032                 tty_printf(" ");
1033             tty_printf(" %02X", *p );
1034         }
1035     }
1036     tty_printf("\n");
1037 }
1038
1039
1040 /****************
1041  * Ask for a new user id , do the selfsignature and put it into
1042  * both keyblocks.
1043  * Return true if there is a new user id
1044  */
1045 static int
1046 menu_adduid( KBNODE pub_keyblock, KBNODE sec_keyblock )
1047 {
1048     PKT_user_id *uid;
1049     PKT_public_key *pk=NULL;
1050     PKT_secret_key *sk=NULL;
1051     PKT_signature *sig=NULL;
1052     PACKET *pkt;
1053     KBNODE node;
1054     KBNODE pub_where=NULL, sec_where=NULL;
1055     int rc;
1056
1057     uid = generate_user_id();
1058     if( !uid )
1059         return 0;
1060
1061     for( node = pub_keyblock; node; pub_where = node, node = node->next ) {
1062         if( node->pkt->pkttype == PKT_PUBLIC_KEY )
1063             pk = node->pkt->pkt.public_key;
1064         else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
1065             break;
1066     }
1067     if( !node ) /* no subkey */
1068         pub_where = NULL;
1069     for( node = sec_keyblock; node; sec_where = node, node = node->next ) {
1070         if( node->pkt->pkttype == PKT_SECRET_KEY )
1071             sk = copy_secret_key( NULL, node->pkt->pkt.secret_key);
1072         else if( node->pkt->pkttype == PKT_SECRET_SUBKEY )
1073             break;
1074     }
1075     if( !node ) /* no subkey */
1076         sec_where = NULL;
1077     assert(pk && sk );
1078
1079     rc = make_keysig_packet( &sig, pk, uid, NULL, sk, 0x13, 0,
1080                              keygen_add_std_prefs, pk );
1081     free_secret_key( sk );
1082     if( rc ) {
1083         log_error("signing failed: %s\n", g10_errstr(rc) );
1084         free_user_id(uid);
1085         return 0;
1086     }
1087
1088     /* insert/append to secret keyblock */
1089     pkt = m_alloc_clear( sizeof *pkt );
1090     pkt->pkttype = PKT_USER_ID;
1091     pkt->pkt.user_id = copy_user_id(NULL, uid);
1092     node = new_kbnode(pkt);
1093     if( sec_where )
1094         insert_kbnode( sec_where, node, 0 );
1095     else
1096         add_kbnode( sec_keyblock, node );
1097     pkt = m_alloc_clear( sizeof *pkt );
1098     pkt->pkttype = PKT_SIGNATURE;
1099     pkt->pkt.signature = copy_signature(NULL, sig);
1100     if( sec_where )
1101         insert_kbnode( node, new_kbnode(pkt), 0 );
1102     else
1103         add_kbnode( sec_keyblock, new_kbnode(pkt) );
1104     /* insert/append to public keyblock */
1105     pkt = m_alloc_clear( sizeof *pkt );
1106     pkt->pkttype = PKT_USER_ID;
1107     pkt->pkt.user_id = uid;
1108     node = new_kbnode(pkt);
1109     if( pub_where )
1110         insert_kbnode( pub_where, node, 0 );
1111     else
1112         add_kbnode( pub_keyblock, node );
1113     pkt = m_alloc_clear( sizeof *pkt );
1114     pkt->pkttype = PKT_SIGNATURE;
1115     pkt->pkt.signature = copy_signature(NULL, sig);
1116     if( pub_where )
1117         insert_kbnode( node, new_kbnode(pkt), 0 );
1118     else
1119         add_kbnode( pub_keyblock, new_kbnode(pkt) );
1120     return 1;
1121 }
1122
1123
1124 /****************
1125  * Remove all selceted userids from the keyrings
1126  */
1127 static void
1128 menu_deluid( KBNODE pub_keyblock, KBNODE sec_keyblock )
1129 {
1130     KBNODE node;
1131     int selected=0;
1132
1133     for( node = pub_keyblock; node; node = node->next ) {
1134         if( node->pkt->pkttype == PKT_USER_ID ) {
1135             selected = node->flag & NODFLG_SELUID;
1136             if( selected ) {
1137                 delete_kbnode( node );
1138                 if( sec_keyblock ) {
1139                     KBNODE snode;
1140                     int s_selected = 0;
1141                     PKT_user_id *uid = node->pkt->pkt.user_id;
1142                     for( snode = sec_keyblock; snode; snode = snode->next ) {
1143                         if( snode->pkt->pkttype == PKT_USER_ID ) {
1144                             PKT_user_id *suid = snode->pkt->pkt.user_id;
1145
1146                             s_selected =
1147                                 (uid->len == suid->len
1148                                  && !memcmp( uid->name, suid->name, uid->len));
1149                             if( s_selected )
1150                                 delete_kbnode( snode );
1151                         }
1152                         else if( s_selected
1153                                  && snode->pkt->pkttype == PKT_SIGNATURE )
1154                             delete_kbnode( snode );
1155                         else if( snode->pkt->pkttype == PKT_SECRET_SUBKEY )
1156                             s_selected = 0;
1157                     }
1158                 }
1159             }
1160         }
1161         else if( selected && node->pkt->pkttype == PKT_SIGNATURE )
1162             delete_kbnode( node );
1163         else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
1164             selected = 0;
1165     }
1166     commit_kbnode( &pub_keyblock );
1167     if( sec_keyblock )
1168         commit_kbnode( &sec_keyblock );
1169 }
1170
1171
1172 /****************
1173  * Remove some of the secondary keys
1174  */
1175 static void
1176 menu_delkey( KBNODE pub_keyblock, KBNODE sec_keyblock )
1177 {
1178     KBNODE node;
1179     int selected=0;
1180
1181     for( node = pub_keyblock; node; node = node->next ) {
1182         if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
1183             selected = node->flag & NODFLG_SELKEY;
1184             if( selected ) {
1185                 delete_kbnode( node );
1186                 if( sec_keyblock ) {
1187                     KBNODE snode;
1188                     int s_selected = 0;
1189                     u32 ki[2];
1190
1191                     keyid_from_pk( node->pkt->pkt.public_key, ki );
1192                     for( snode = sec_keyblock; snode; snode = snode->next ) {
1193                         if( snode->pkt->pkttype == PKT_SECRET_SUBKEY ) {
1194                             u32 ki2[2];
1195
1196                             keyid_from_sk( snode->pkt->pkt.secret_key, ki2 );
1197                             s_selected = (ki[0] == ki2[0] && ki[1] == ki2[1]);
1198                             if( s_selected )
1199                                 delete_kbnode( snode );
1200                         }
1201                         else if( s_selected
1202                                  && snode->pkt->pkttype == PKT_SIGNATURE )
1203                             delete_kbnode( snode );
1204                         else
1205                             s_selected = 0;
1206                     }
1207                 }
1208             }
1209         }
1210         else if( selected && node->pkt->pkttype == PKT_SIGNATURE )
1211             delete_kbnode( node );
1212         else
1213             selected = 0;
1214     }
1215     commit_kbnode( &pub_keyblock );
1216     if( sec_keyblock )
1217         commit_kbnode( &sec_keyblock );
1218 }
1219
1220
1221
1222 static int
1223 menu_expire( KBNODE pub_keyblock, KBNODE sec_keyblock )
1224 {
1225     int n1, signumber, rc;
1226     u32 expiredate;
1227     int mainkey=0;
1228     PKT_secret_key *sk;    /* copy of the main sk */
1229     PKT_public_key *main_pk, *sub_pk;
1230     PKT_user_id *uid;
1231     KBNODE node;
1232     u32 keyid[2];
1233
1234     if( count_selected_keys( sec_keyblock ) ) {
1235         tty_printf(_("Please remove selections from the secret keys.\n"));
1236         return 0;
1237     }
1238
1239     n1 = count_selected_keys( pub_keyblock );
1240     if( n1 > 1 ) {
1241         tty_printf(_("Please select at most one secondary key.\n"));
1242         return 0;
1243     }
1244     else if( n1 )
1245         tty_printf(_("Changing exiration time for a secondary key.\n"));
1246     else {
1247         tty_printf(_("Changing exiration time for the primary key.\n"));
1248         mainkey=1;
1249     }
1250
1251     expiredate = ask_expiredate();
1252     node = find_kbnode( sec_keyblock, PKT_SECRET_KEY );
1253     sk = copy_secret_key( NULL, node->pkt->pkt.secret_key);
1254
1255     /* Now we can actually change the self signature(s) */
1256     main_pk = sub_pk = NULL;
1257     uid = NULL;
1258     signumber = 0;
1259     for( node=pub_keyblock; node; node = node->next ) {
1260         if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
1261             main_pk = node->pkt->pkt.public_key;
1262             keyid_from_pk( main_pk, keyid );
1263             main_pk->expiredate = expiredate;
1264         }
1265         else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
1266                  && (node->flag & NODFLG_SELKEY ) ) {
1267             sub_pk = node->pkt->pkt.public_key;
1268             sub_pk->expiredate = expiredate;
1269         }
1270         else if( node->pkt->pkttype == PKT_USER_ID )
1271             uid = node->pkt->pkt.user_id;
1272         else if( main_pk && node->pkt->pkttype == PKT_SIGNATURE ) {
1273             PKT_signature *sig = node->pkt->pkt.signature;
1274             if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1]
1275                 && (    (mainkey && uid && (sig->sig_class&~3) == 0x10)
1276                      || (!mainkey && sig->sig_class == 0x18)  ) ) {
1277                 /* this is a selfsignature which is to be replaced */
1278                 PKT_signature *newsig;
1279                 PACKET *newpkt;
1280                 KBNODE sn;
1281                 int signumber2 = 0;
1282
1283                 signumber++;
1284
1285                 if( (mainkey && main_pk->version < 4)
1286                     || (!mainkey && sub_pk->version < 4 ) ) {
1287                     log_info(_(
1288                         "You can't change the expiration date of a v3 key\n"));
1289                     free_secret_key( sk );
1290                     return 0;
1291                 }
1292
1293                 /* find the corresponding secret self-signature */
1294                 for( sn=sec_keyblock; sn; sn = sn->next ) {
1295                     if( sn->pkt->pkttype == PKT_SIGNATURE ) {
1296                         PKT_signature *b = sn->pkt->pkt.signature;
1297                         if( keyid[0] == b->keyid[0] && keyid[1] == b->keyid[1]
1298                             && sig->sig_class == b->sig_class
1299                             && ++signumber2 == signumber )
1300                             break;
1301                     }
1302                 }
1303                 if( !sn )
1304                     log_info(_("No corresponding signature in secret ring\n"));
1305
1306                 /* create new self signature */
1307                 if( mainkey )
1308                     rc = make_keysig_packet( &newsig, main_pk, uid, NULL,
1309                                              sk, 0x13, 0,
1310                                              keygen_add_std_prefs, main_pk );
1311                 else
1312                     rc = make_keysig_packet( &newsig, main_pk, NULL, sub_pk,
1313                                              sk, 0x18, 0,
1314                                              keygen_add_key_expire, sub_pk );
1315                 if( rc ) {
1316                     log_error("make_keysig_packet failed: %s\n",
1317                                                     g10_errstr(rc));
1318                     free_secret_key( sk );
1319                     return 0;
1320                 }
1321                 /* replace the packet */
1322                 newpkt = m_alloc_clear( sizeof *newpkt );
1323                 newpkt->pkttype = PKT_SIGNATURE;
1324                 newpkt->pkt.signature = newsig;
1325                 free_packet( node->pkt );
1326                 m_free( node->pkt );
1327                 node->pkt = newpkt;
1328                 if( sn ) {
1329                     newpkt = m_alloc_clear( sizeof *newpkt );
1330                     newpkt->pkttype = PKT_SIGNATURE;
1331                     newpkt->pkt.signature = copy_signature( NULL, newsig );
1332                     free_packet( sn->pkt );
1333                     m_free( sn->pkt );
1334                     sn->pkt = newpkt;
1335                 }
1336             }
1337         }
1338     }
1339
1340     free_secret_key( sk );
1341     return 1;
1342 }
1343
1344
1345 /****************
1346  * Select one user id or remove all selection if index is 0.
1347  * Returns: True if the selection changed;
1348  */
1349 static int
1350 menu_select_uid( KBNODE keyblock, int idx )
1351 {
1352     KBNODE node;
1353     int i;
1354
1355     /* first check that the index is valid */
1356     if( idx ) {
1357         for( i=0, node = keyblock; node; node = node->next ) {
1358             if( node->pkt->pkttype == PKT_USER_ID ) {
1359                 if( ++i == idx )
1360                     break;
1361             }
1362         }
1363         if( !node ) {
1364             tty_printf(_("No user id with index %d\n"), idx );
1365             return 0;
1366         }
1367     }
1368     else { /* reset all */
1369         for( i=0, node = keyblock; node; node = node->next ) {
1370             if( node->pkt->pkttype == PKT_USER_ID )
1371                 node->flag &= ~NODFLG_SELUID;
1372         }
1373         return 1;
1374     }
1375     /* and toggle the new index */
1376     for( i=0, node = keyblock; node; node = node->next ) {
1377         if( node->pkt->pkttype == PKT_USER_ID ) {
1378             if( ++i == idx ) {
1379                 if( (node->flag & NODFLG_SELUID) )
1380                     node->flag &= ~NODFLG_SELUID;
1381                 else
1382                     node->flag |= NODFLG_SELUID;
1383             }
1384         }
1385     }
1386
1387     return 1;
1388 }
1389
1390 /****************
1391  * Select secondary keys
1392  * Returns: True if the selection changed;
1393  */
1394 static int
1395 menu_select_key( KBNODE keyblock, int idx )
1396 {
1397     KBNODE node;
1398     int i;
1399
1400     /* first check that the index is valid */
1401     if( idx ) {
1402         for( i=0, node = keyblock; node; node = node->next ) {
1403             if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
1404                 || node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
1405                 if( ++i == idx )
1406                     break;
1407             }
1408         }
1409         if( !node ) {
1410             tty_printf(_("No secondary key with index %d\n"), idx );
1411             return 0;
1412         }
1413     }
1414     else { /* reset all */
1415         for( i=0, node = keyblock; node; node = node->next ) {
1416             if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
1417                 || node->pkt->pkttype == PKT_SECRET_SUBKEY )
1418                 node->flag &= ~NODFLG_SELKEY;
1419         }
1420         return 1;
1421     }
1422     /* and set the new index */
1423     for( i=0, node = keyblock; node; node = node->next ) {
1424         if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
1425             || node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
1426             if( ++i == idx ) {
1427                 if( (node->flag & NODFLG_SELKEY) )
1428                     node->flag &= ~NODFLG_SELKEY;
1429                 else
1430                     node->flag |= NODFLG_SELKEY;
1431             }
1432         }
1433     }
1434
1435     return 1;
1436 }
1437
1438
1439 static int
1440 count_uids_with_flag( KBNODE keyblock, unsigned flag )
1441 {
1442     KBNODE node;
1443     int i=0;
1444
1445     for( node = keyblock; node; node = node->next )
1446         if( node->pkt->pkttype == PKT_USER_ID && (node->flag & flag) )
1447             i++;
1448     return i;
1449 }
1450
1451 static int
1452 count_keys_with_flag( KBNODE keyblock, unsigned flag )
1453 {
1454     KBNODE node;
1455     int i=0;
1456
1457     for( node = keyblock; node; node = node->next )
1458         if( ( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
1459               || node->pkt->pkttype == PKT_SECRET_SUBKEY)
1460             && (node->flag & flag) )
1461             i++;
1462     return i;
1463 }
1464
1465 static int
1466 count_uids( KBNODE keyblock )
1467 {
1468     KBNODE node;
1469     int i=0;
1470
1471     for( node = keyblock; node; node = node->next )
1472         if( node->pkt->pkttype == PKT_USER_ID )
1473             i++;
1474     return i;
1475 }
1476
1477
1478 /****************
1479  * Returns true if there is at least one selected user id
1480  */
1481 static int
1482 count_selected_uids( KBNODE keyblock )
1483 {
1484     return count_uids_with_flag( keyblock, NODFLG_SELUID);
1485 }
1486
1487 static int
1488 count_selected_keys( KBNODE keyblock )
1489 {
1490     return count_keys_with_flag( keyblock, NODFLG_SELKEY);
1491 }
1492