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