Some bug fixes of the last release
[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 index );
53 static int menu_select_key( KBNODE keyblock, int index );
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(N_("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(N_("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 )
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
531
532     if( opt.batch ) {
533         log_error(_("can't do that in batchmode\n"));
534         goto leave;
535     }
536
537     /* first try to locate it as secret key */
538     rc = find_secret_keyblock_byname( &sec_keyblockpos, username );
539     if( !rc ) {
540         rc = read_keyblock( &sec_keyblockpos, &sec_keyblock );
541         if( rc ) {
542             log_error("%s: secret keyblock read problem: %s\n",
543                                             username, g10_errstr(rc));
544             goto leave;
545         }
546         merge_keys_and_selfsig( sec_keyblock );
547         if( fix_keyblock( sec_keyblock ) )
548             sec_modified++;
549     }
550
551     /* and now get the public key */
552     rc = get_keyblock_byname( &keyblock, &keyblockpos, username );
553     if( rc )
554         goto leave;
555     if( fix_keyblock( keyblock ) )
556         modified++;
557
558     if( sec_keyblock ) { /* check that they match */
559         /* FIXME: check that they both match */
560         tty_printf(_("Secret key is available.\n"));
561     }
562
563     toggle = 0;
564     cur_keyblock = keyblock;
565     for(;;) { /* main loop */
566         int i, arg_number;
567         char *p;
568
569         tty_printf("\n");
570         if( redisplay ) {
571             show_key_with_all_names( cur_keyblock, 0, 0, 1, 0 );
572             tty_printf("\n");
573             redisplay = 0;
574         }
575         do {
576             m_free(answer);
577             answer = cpr_get(N_("keyedit.cmd"), _("Command> "));
578             cpr_kill_prompt();
579             trim_spaces(answer);
580         } while( *answer == '#' );
581
582         arg_number = 0;
583         if( !*answer )
584             cmd = cmdLIST;
585         else if( *answer == CONTROL_D )
586             cmd = cmdQUIT;
587         else if( isdigit( *answer ) ) {
588             cmd = cmdSELUID;
589             arg_number = atoi(answer);
590         }
591         else {
592             if( (p=strchr(answer,' ')) ) {
593                 *p++ = 0;
594                 trim_spaces(answer);
595                 trim_spaces(p);
596                 arg_number = atoi(p);
597             }
598
599             for(i=0; cmds[i].name; i++ )
600                 if( !stricmp( answer, cmds[i].name ) )
601                     break;
602             if( cmds[i].need_sk && !sec_keyblock ) {
603                 tty_printf(_("Need the secret key to to this.\n"));
604                 cmd = cmdNOP;
605             }
606             else
607                 cmd = cmds[i].id;
608         }
609         switch( cmd )  {
610           case cmdHELP:
611             for(i=0; cmds[i].name; i++ ) {
612                 if( cmds[i].need_sk && !sec_keyblock )
613                     ; /* skip if we do not have the secret key */
614                 else if( cmds[i].desc )
615                     tty_printf("%-10s %s\n", cmds[i].name, _(cmds[i].desc) );
616             }
617             break;
618
619           case cmdQUIT:
620             if( !modified && !sec_modified )
621                 goto leave;
622             if( !cpr_get_answer_is_yes(N_("keyedit.save.okay"),
623                                         _("Save changes? ")) ) {
624                 if( cpr_enabled()
625                     || cpr_get_answer_is_yes(N_("keyedit.cancel.okay"),
626                                              _("Quit without saving? ")) )
627                     goto leave;
628                 break;
629             }
630             /* fall thru */
631           case cmdSAVE:
632             if( modified || sec_modified  ) {
633                 if( modified ) {
634                     rc = update_keyblock( &keyblockpos, keyblock );
635                     if( rc ) {
636                         log_error(_("update failed: %s\n"), g10_errstr(rc) );
637                         break;
638                     }
639                 }
640                 if( sec_modified ) {
641                     rc = update_keyblock( &sec_keyblockpos, sec_keyblock );
642                     if( rc ) {
643                         log_error(_("update secret failed: %s\n"),
644                                                             g10_errstr(rc) );
645                         break;
646                     }
647                 }
648             }
649             else
650                 tty_printf(_("Key not changed so no update needed.\n"));
651             rc = update_trust_record( keyblock, 0, NULL );
652             if( rc )
653                 log_error(_("update of trust db failed: %s\n"),
654                             g10_errstr(rc) );
655             goto leave;
656
657           case cmdLIST:
658             redisplay = 1;
659             break;
660
661           case cmdFPR:
662             show_key_and_fingerprint( keyblock );
663             break;
664
665           case cmdSELUID:
666             if( menu_select_uid( cur_keyblock, arg_number ) )
667                 redisplay = 1;
668             break;
669
670           case cmdSELKEY:
671             if( menu_select_key( cur_keyblock, arg_number ) )
672                 redisplay = 1;
673             break;
674
675           case cmdCHECK:
676             /* we can only do this with the public key becuase the
677              * check functions can't cope with secret keys and it
678              * is questionable whether this would make sense at all */
679             check_all_keysigs( keyblock, count_selected_uids(keyblock) );
680             break;
681
682           case cmdSIGN: /* sign (only the public key) */
683             if( count_uids(keyblock) > 1 && !count_selected_uids(keyblock) ) {
684                 if( !cpr_get_answer_is_yes(N_("keyedit.sign_all.okay"),
685                                            _("Really sign all user ids? ")) ) {
686                     tty_printf(_("Hint: Select the user ids to sign\n"));
687                     break;
688                 }
689             }
690             sign_uids( keyblock, locusr, &modified );
691             break;
692
693           case cmdDEBUG:
694             dump_kbnode( cur_keyblock );
695             break;
696
697           case cmdTOGGLE:
698             toggle = !toggle;
699             cur_keyblock = toggle? sec_keyblock : keyblock;
700             redisplay = 1;
701             break;
702
703           case cmdADDUID:
704             if( menu_adduid( keyblock, sec_keyblock ) ) {
705                 redisplay = 1;
706                 sec_modified = modified = 1;
707                 /* must update the trustdb already here, so that preferences
708                  * get listed correctly */
709                 rc = update_trust_record( keyblock, 0, NULL );
710                 if( rc ) {
711                     log_error(_("update of trust db failed: %s\n"),
712                                 g10_errstr(rc) );
713                     rc = 0;
714                 }
715             }
716             break;
717
718           case cmdDELUID: {
719                 int n1;
720
721                 if( !(n1=count_selected_uids(keyblock)) )
722                     tty_printf(_("You must select at least one user id.\n"));
723                 else if( count_uids(keyblock) - n1 < 1 )
724                     tty_printf(_("You can't delete the last user id!\n"));
725                 else if( cpr_get_answer_is_yes(
726                             N_("keyedit.remove.uid.okay"),
727                         n1 > 1? _("Really remove all selected user ids? ")
728                               : _("Really remove this user id? ")
729                        ) ) {
730                     menu_deluid( keyblock, sec_keyblock );
731                     redisplay = 1;
732                     modified = 1;
733                     if( sec_keyblock )
734                        sec_modified = 1;
735                 }
736             }
737             break;
738
739           case cmdADDKEY:
740             if( generate_subkeypair( keyblock, sec_keyblock ) ) {
741                 redisplay = 1;
742                 sec_modified = modified = 1;
743             }
744             break;
745
746
747           case cmdDELKEY: {
748                 int n1;
749
750                 if( !(n1=count_selected_keys( keyblock )) )
751                     tty_printf(_("You must select at least one key.\n"));
752                 else if( sec_keyblock && !cpr_get_answer_is_yes(
753                             N_("keyedit.remove.subkey.okay"),
754                        n1 > 1?
755                         _("Do you really want to delete the selected keys? "):
756                         _("Do you really want to delete this key? ")
757                        ))
758                     ;
759                 else {
760                     menu_delkey( keyblock, sec_keyblock );
761                     redisplay = 1;
762                     modified = 1;
763                     if( sec_keyblock )
764                        sec_modified = 1;
765                 }
766             }
767             break;
768
769           case cmdEXPIRE:
770             if( menu_expire( keyblock, sec_keyblock ) ) {
771                 merge_keys_and_selfsig( sec_keyblock );
772                 merge_keys_and_selfsig( keyblock );
773                 sec_modified = 1;
774                 modified = 1;
775                 redisplay = 1;
776             }
777             break;
778
779           case cmdPASSWD:
780             if( change_passphrase( sec_keyblock ) )
781                 sec_modified = 1;
782             break;
783
784           case cmdTRUST:
785             show_key_with_all_names( keyblock, 0, 0, 1, 0 );
786             tty_printf("\n");
787             if( edit_ownertrust( find_kbnode( keyblock,
788                       PKT_PUBLIC_KEY )->pkt->pkt.public_key->local_id, 1 ) )
789                 redisplay = 1;
790             /* we don't need to set modified here, as the trustvalues
791              * are updated immediately */
792             break;
793
794           case cmdPREF:
795             show_key_with_all_names( keyblock, 0, 0, 0, 1 );
796             break;
797
798           case cmdNOP:
799             break;
800
801           default:
802             tty_printf("\n");
803             tty_printf(_("Invalid command  (try \"help\")\n"));
804             break;
805         }
806     } /* end main loop */
807
808   leave:
809     release_kbnode( keyblock );
810     release_kbnode( sec_keyblock );
811     m_free(answer);
812 }
813
814
815 /****************
816  * show preferences of a public keyblock.
817  */
818 static void
819 show_prefs( KBNODE keyblock, PKT_user_id *uid )
820 {
821     KBNODE node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
822     PKT_public_key *pk;
823     byte *p;
824     int i;
825     size_t n;
826     byte namehash[20];
827
828     if( !node )
829         return; /* is a secret keyblock */
830     pk = node->pkt->pkt.public_key;
831     if( !pk->local_id ) {
832         log_error("oops: no LID\n");
833         return;
834     }
835
836     rmd160_hash_buffer( namehash, uid->name, uid->len );
837
838     p = get_pref_data( pk->local_id, namehash, &n );
839     if( !p )
840         return;
841
842     tty_printf("    ");
843     for(i=0; i < n; i+=2 ) {
844         if( p[i] )
845             tty_printf( " %c%d", p[i] == PREFTYPE_SYM    ? 'S' :
846                                  p[i] == PREFTYPE_HASH   ? 'H' :
847                                  p[i] == PREFTYPE_COMPR  ? 'Z' : '?', p[i+1]);
848     }
849     tty_printf("\n");
850
851     m_free(p);
852 }
853
854
855 /****************
856  * Display the key a the user ids, if only_marked is true, do only
857  * so for user ids with mark A flag set and dont display the index number
858  */
859 static void
860 show_key_with_all_names( KBNODE keyblock, int only_marked,
861                          int with_fpr, int with_subkeys, int with_prefs )
862 {
863     KBNODE node;
864     int i;
865
866     /* the keys */
867     for( node = keyblock; node; node = node->next ) {
868         if( node->pkt->pkttype == PKT_PUBLIC_KEY
869             || (with_subkeys && node->pkt->pkttype == PKT_PUBLIC_SUBKEY) ) {
870             PKT_public_key *pk = node->pkt->pkt.public_key;
871             int otrust=0, trust=0;
872
873             if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
874                 /* do it here, so that debug messages don't clutter the
875                  * output */
876                 trust = query_trust_info(pk);
877                 otrust = get_ownertrust_info( pk->local_id );
878             }
879
880             tty_printf("%s%c %4u%c/%08lX  created: %s expires: %s",
881                           node->pkt->pkttype == PKT_PUBLIC_KEY? "pub":"sub",
882                           (node->flag & NODFLG_SELKEY)? '*':' ',
883                           nbits_from_pk( pk ),
884                           pubkey_letter( pk->pubkey_algo ),
885                           (ulong)keyid_from_pk(pk,NULL),
886                           datestr_from_pk(pk),
887                           expirestr_from_pk(pk) );
888             if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
889                 tty_printf(" trust: %c/%c", otrust, trust );
890                 if( with_fpr  ) {
891                     tty_printf("\n");
892                     show_fingerprint( pk );
893                 }
894             }
895             tty_printf("\n");
896         }
897         else if( node->pkt->pkttype == PKT_SECRET_KEY
898             || (with_subkeys && node->pkt->pkttype == PKT_SECRET_SUBKEY) ) {
899             PKT_secret_key *sk = node->pkt->pkt.secret_key;
900             tty_printf("%s%c %4u%c/%08lX  created: %s expires: %s\n",
901                           node->pkt->pkttype == PKT_SECRET_KEY? "sec":"sbb",
902                           (node->flag & NODFLG_SELKEY)? '*':' ',
903                           nbits_from_sk( sk ),
904                           pubkey_letter( sk->pubkey_algo ),
905                           (ulong)keyid_from_sk(sk,NULL),
906                           datestr_from_sk(sk),
907                           expirestr_from_sk(sk) );
908         }
909     }
910     /* the user ids */
911     i = 0;
912     for( node = keyblock; node; node = node->next ) {
913         if( node->pkt->pkttype == PKT_USER_ID ) {
914             PKT_user_id *uid = node->pkt->pkt.user_id;
915             ++i;
916             if( !only_marked || (only_marked && (node->flag & NODFLG_MARK_A))){
917                 if( only_marked )
918                    tty_printf("     ");
919                 else if( node->flag & NODFLG_SELUID )
920                    tty_printf("(%d)* ", i);
921                 else
922                    tty_printf("(%d)  ", i);
923                 tty_print_string( uid->name, uid->len );
924                 tty_printf("\n");
925                 if( with_prefs )
926                     show_prefs( keyblock, uid );
927             }
928         }
929     }
930 }
931
932 static void
933 show_key_and_fingerprint( KBNODE keyblock )
934 {
935     KBNODE node;
936     PKT_public_key *pk = NULL;
937
938     for( node = keyblock; node; node = node->next ) {
939         if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
940             pk = node->pkt->pkt.public_key;
941             tty_printf("pub  %4u%c/%08lX %s ",
942                           nbits_from_pk( pk ),
943                           pubkey_letter( pk->pubkey_algo ),
944                           (ulong)keyid_from_pk(pk,NULL),
945                           datestr_from_pk(pk) );
946         }
947         else if( node->pkt->pkttype == PKT_USER_ID ) {
948             PKT_user_id *uid = node->pkt->pkt.user_id;
949             tty_print_string( uid->name, uid->len );
950             break;
951         }
952     }
953     tty_printf("\n");
954     if( pk )
955         show_fingerprint( pk );
956 }
957
958
959 static void
960 show_fingerprint( PKT_public_key *pk )
961 {
962     byte array[MAX_FINGERPRINT_LEN], *p;
963     size_t i, n;
964
965     fingerprint_from_pk( pk, array, &n );
966     p = array;
967     tty_printf("             Fingerprint:");
968     if( n == 20 ) {
969         for(i=0; i < n ; i++, i++, p += 2 ) {
970             if( i == 10 )
971                 tty_printf(" ");
972             tty_printf(" %02X%02X", *p, p[1] );
973         }
974     }
975     else {
976         for(i=0; i < n ; i++, p++ ) {
977             if( i && !(i%8) )
978                 tty_printf(" ");
979             tty_printf(" %02X", *p );
980         }
981     }
982     tty_printf("\n");
983 }
984
985
986 /****************
987  * Ask for a new user id , do the selfsignature and put it into
988  * both keyblocks.
989  * Return true if there is a new user id
990  */
991 static int
992 menu_adduid( KBNODE pub_keyblock, KBNODE sec_keyblock )
993 {
994     PKT_user_id *uid;
995     PKT_public_key *pk=NULL;
996     PKT_secret_key *sk=NULL;
997     PKT_signature *sig=NULL;
998     PACKET *pkt;
999     KBNODE node;
1000     KBNODE pub_where=NULL, sec_where=NULL;
1001     int rc;
1002
1003     uid = generate_user_id();
1004     if( !uid )
1005         return 0;
1006
1007     for( node = pub_keyblock; node; pub_where = node, node = node->next ) {
1008         if( node->pkt->pkttype == PKT_PUBLIC_KEY )
1009             pk = node->pkt->pkt.public_key;
1010         else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
1011             break;
1012     }
1013     if( !node ) /* no subkey */
1014         pub_where = NULL;
1015     for( node = sec_keyblock; node; sec_where = node, node = node->next ) {
1016         if( node->pkt->pkttype == PKT_SECRET_KEY )
1017             sk = copy_secret_key( NULL, node->pkt->pkt.secret_key);
1018         else if( node->pkt->pkttype == PKT_SECRET_SUBKEY )
1019             break;
1020     }
1021     if( !node ) /* no subkey */
1022         sec_where = NULL;
1023     assert(pk && sk );
1024
1025     rc = make_keysig_packet( &sig, pk, uid, NULL, sk, 0x13, 0,
1026                              keygen_add_std_prefs, sk );
1027     free_secret_key( sk );
1028     if( rc ) {
1029         log_error("signing failed: %s\n", g10_errstr(rc) );
1030         free_user_id(uid);
1031         return 0;
1032     }
1033
1034     /* insert/append to secret keyblock */
1035     pkt = m_alloc_clear( sizeof *pkt );
1036     pkt->pkttype = PKT_USER_ID;
1037     pkt->pkt.user_id = copy_user_id(NULL, uid);
1038     node = new_kbnode(pkt);
1039     if( sec_where )
1040         insert_kbnode( sec_where, node, 0 );
1041     else
1042         add_kbnode( sec_keyblock, node );
1043     pkt = m_alloc_clear( sizeof *pkt );
1044     pkt->pkttype = PKT_SIGNATURE;
1045     pkt->pkt.signature = copy_signature(NULL, sig);
1046     if( sec_where )
1047         insert_kbnode( node, new_kbnode(pkt), 0 );
1048     else
1049         add_kbnode( sec_keyblock, new_kbnode(pkt) );
1050     /* insert/append to public keyblock */
1051     pkt = m_alloc_clear( sizeof *pkt );
1052     pkt->pkttype = PKT_USER_ID;
1053     pkt->pkt.user_id = uid;
1054     node = new_kbnode(pkt);
1055     if( pub_where )
1056         insert_kbnode( pub_where, node, 0 );
1057     else
1058         add_kbnode( pub_keyblock, node );
1059     pkt = m_alloc_clear( sizeof *pkt );
1060     pkt->pkttype = PKT_SIGNATURE;
1061     pkt->pkt.signature = copy_signature(NULL, sig);
1062     if( pub_where )
1063         insert_kbnode( node, new_kbnode(pkt), 0 );
1064     else
1065         add_kbnode( pub_keyblock, new_kbnode(pkt) );
1066     return 1;
1067 }
1068
1069
1070 /****************
1071  * Remove all selceted userids from the keyrings
1072  */
1073 static void
1074 menu_deluid( KBNODE pub_keyblock, KBNODE sec_keyblock )
1075 {
1076     KBNODE node;
1077     int selected=0;
1078
1079     for( node = pub_keyblock; node; node = node->next ) {
1080         if( node->pkt->pkttype == PKT_USER_ID ) {
1081             selected = node->flag & NODFLG_SELUID;
1082             if( selected ) {
1083                 delete_kbnode( node );
1084                 if( sec_keyblock ) {
1085                     KBNODE snode;
1086                     int s_selected = 0;
1087                     PKT_user_id *uid = node->pkt->pkt.user_id;
1088                     for( snode = sec_keyblock; snode; snode = snode->next ) {
1089                         if( snode->pkt->pkttype == PKT_USER_ID ) {
1090                             PKT_user_id *suid = snode->pkt->pkt.user_id;
1091
1092                             s_selected =
1093                                 (uid->len == suid->len
1094                                  && !memcmp( uid->name, suid->name, uid->len));
1095                             if( s_selected )
1096                                 delete_kbnode( snode );
1097                         }
1098                         else if( s_selected
1099                                  && snode->pkt->pkttype == PKT_SIGNATURE )
1100                             delete_kbnode( snode );
1101                         else if( snode->pkt->pkttype == PKT_SECRET_SUBKEY )
1102                             s_selected = 0;
1103                     }
1104                 }
1105             }
1106         }
1107         else if( selected && node->pkt->pkttype == PKT_SIGNATURE )
1108             delete_kbnode( node );
1109         else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
1110             selected = 0;
1111     }
1112     commit_kbnode( &pub_keyblock );
1113     if( sec_keyblock )
1114         commit_kbnode( &sec_keyblock );
1115 }
1116
1117
1118 /****************
1119  * Remove some of the secondary keys
1120  */
1121 static void
1122 menu_delkey( KBNODE pub_keyblock, KBNODE sec_keyblock )
1123 {
1124     KBNODE node;
1125     int selected=0;
1126
1127     for( node = pub_keyblock; node; node = node->next ) {
1128         if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
1129             selected = node->flag & NODFLG_SELKEY;
1130             if( selected ) {
1131                 delete_kbnode( node );
1132                 if( sec_keyblock ) {
1133                     KBNODE snode;
1134                     int s_selected = 0;
1135                     u32 ki[2];
1136
1137                     keyid_from_pk( node->pkt->pkt.public_key, ki );
1138                     for( snode = sec_keyblock; snode; snode = snode->next ) {
1139                         if( snode->pkt->pkttype == PKT_SECRET_SUBKEY ) {
1140                             u32 ki2[2];
1141
1142                             keyid_from_sk( snode->pkt->pkt.secret_key, ki2 );
1143                             s_selected = (ki[0] == ki2[0] && ki[1] == ki2[1]);
1144                             if( s_selected )
1145                                 delete_kbnode( snode );
1146                         }
1147                         else if( s_selected
1148                                  && snode->pkt->pkttype == PKT_SIGNATURE )
1149                             delete_kbnode( snode );
1150                         else
1151                             s_selected = 0;
1152                     }
1153                 }
1154             }
1155         }
1156         else if( selected && node->pkt->pkttype == PKT_SIGNATURE )
1157             delete_kbnode( node );
1158         else
1159             selected = 0;
1160     }
1161     commit_kbnode( &pub_keyblock );
1162     if( sec_keyblock )
1163         commit_kbnode( &sec_keyblock );
1164 }
1165
1166
1167
1168 static int
1169 menu_expire( KBNODE pub_keyblock, KBNODE sec_keyblock )
1170 {
1171     int n1, rc;
1172     u32 expiredate;
1173     int mainkey=0;
1174     PKT_secret_key *sk;    /* copy of the main sk */
1175     PKT_public_key *main_pk, *sub_pk;
1176     PKT_user_id *uid;
1177     KBNODE node;
1178     u32 keyid[2];
1179
1180     if( count_selected_keys( sec_keyblock ) ) {
1181         tty_printf(_("Please remove selections from the secret keys.\n"));
1182         return 0;
1183     }
1184
1185     n1 = count_selected_keys( pub_keyblock );
1186     if( n1 > 1 ) {
1187         tty_printf(_("Please select at most one secondary key.\n"));
1188         return 0;
1189     }
1190     else if( n1 )
1191         tty_printf(_("Changing exiration time for a secondary key.\n"));
1192     else {
1193         tty_printf(_("Changing exiration time for the primary key.\n"));
1194         mainkey=1;
1195     }
1196
1197     expiredate = ask_expiredate();
1198     /* fixme: check that expiredate is > key creation date */
1199
1200     /* get the secret key , make a copy and set the expiration time into
1201      * that key (because keygen_add-key-expire expects it there)
1202      */
1203     node = find_kbnode( sec_keyblock, PKT_SECRET_KEY );
1204     sk = copy_secret_key( NULL, node->pkt->pkt.secret_key);
1205     sk->expiredate = expiredate;
1206
1207     /* Now we can actually change the self signature(s) */
1208     main_pk = sub_pk = NULL;
1209     uid = NULL;
1210     for( node=pub_keyblock; node; node = node->next ) {
1211         if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
1212             main_pk = node->pkt->pkt.public_key;
1213             keyid_from_pk( main_pk, keyid );
1214         }
1215         else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
1216                  && (node->flag & NODFLG_SELKEY ) )
1217             sub_pk = node->pkt->pkt.public_key;
1218         else if( node->pkt->pkttype == PKT_USER_ID )
1219             uid = node->pkt->pkt.user_id;
1220         else if( main_pk && node->pkt->pkttype == PKT_SIGNATURE ) {
1221             PKT_signature *sig = node->pkt->pkt.signature;
1222             if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1]
1223                 && (    (mainkey && uid && (sig->sig_class&~3) == 0x10)
1224                      || (!mainkey && sig->sig_class == 0x18)  ) ) {
1225                 /* this is a selfsignature which should be replaced */
1226                 PKT_signature *newsig;
1227                 PACKET *newpkt;
1228                 KBNODE sn;
1229
1230                 /* find the corresponding secret self-signature */
1231                 for( sn=sec_keyblock; sn; sn = sn->next ) {
1232                     if( sn->pkt->pkttype == PKT_SIGNATURE
1233                         && !cmp_signatures( sn->pkt->pkt.signature, sig ) )
1234                         break;
1235                 }
1236                 if( !sn )
1237                     log_info(_("No corresponding signature in secret ring\n"));
1238
1239                 /* create new self signature */
1240                 if( mainkey )
1241                     rc = make_keysig_packet( &newsig, main_pk, uid, NULL,
1242                                              sk, 0x13, 0,
1243                                              keygen_add_std_prefs, sk );
1244                 else
1245                     rc = make_keysig_packet( &newsig, main_pk, NULL, sub_pk,
1246                                              sk, 0x18, 0,
1247                                              keygen_add_key_expire, sk );
1248                 if( rc ) {
1249                     log_error("make_keysig_packet failed: %s\n",
1250                                                     g10_errstr(rc));
1251                     free_secret_key( sk );
1252                     return 0;
1253                 }
1254                 /* replace the packet */
1255                 newpkt = m_alloc_clear( sizeof *newpkt );
1256                 newpkt->pkttype = PKT_SIGNATURE;
1257                 newpkt->pkt.signature = newsig;
1258                 free_packet( node->pkt );
1259                 m_free( node->pkt );
1260                 node->pkt = newpkt;
1261                 if( sn ) {
1262                     newpkt = m_alloc_clear( sizeof *newpkt );
1263                     newpkt->pkttype = PKT_SIGNATURE;
1264                     newpkt->pkt.signature = copy_signature( NULL, newsig );
1265                     free_packet( sn->pkt );
1266                     m_free( sn->pkt );
1267                     sn->pkt = newpkt;
1268                 }
1269             }
1270         }
1271     }
1272
1273     free_secret_key( sk );
1274     return 1;
1275 }
1276
1277
1278 /****************
1279  * Select one user id or remove all selection if index is 0.
1280  * Returns: True if the selection changed;
1281  */
1282 static int
1283 menu_select_uid( KBNODE keyblock, int index )
1284 {
1285     KBNODE node;
1286     int i;
1287
1288     /* first check that the index is valid */
1289     if( index ) {
1290         for( i=0, node = keyblock; node; node = node->next ) {
1291             if( node->pkt->pkttype == PKT_USER_ID ) {
1292                 if( ++i == index )
1293                     break;
1294             }
1295         }
1296         if( !node ) {
1297             tty_printf(_("No user id with index %d\n"), index );
1298             return 0;
1299         }
1300     }
1301     else { /* reset all */
1302         for( i=0, node = keyblock; node; node = node->next ) {
1303             if( node->pkt->pkttype == PKT_USER_ID )
1304                 node->flag &= ~NODFLG_SELUID;
1305         }
1306         return 1;
1307     }
1308     /* and toggle the new index */
1309     for( i=0, node = keyblock; node; node = node->next ) {
1310         if( node->pkt->pkttype == PKT_USER_ID ) {
1311             if( ++i == index )
1312                 if( (node->flag & NODFLG_SELUID) )
1313                     node->flag &= ~NODFLG_SELUID;
1314                 else
1315                     node->flag |= NODFLG_SELUID;
1316         }
1317     }
1318
1319     return 1;
1320 }
1321
1322 /****************
1323  * Select secondary keys
1324  * Returns: True if the selection changed;
1325  */
1326 static int
1327 menu_select_key( KBNODE keyblock, int index )
1328 {
1329     KBNODE node;
1330     int i;
1331
1332     /* first check that the index is valid */
1333     if( index ) {
1334         for( i=0, node = keyblock; node; node = node->next ) {
1335             if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
1336                 || node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
1337                 if( ++i == index )
1338                     break;
1339             }
1340         }
1341         if( !node ) {
1342             tty_printf(_("No secondary key with index %d\n"), index );
1343             return 0;
1344         }
1345     }
1346     else { /* reset all */
1347         for( i=0, node = keyblock; node; node = node->next ) {
1348             if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
1349                 || node->pkt->pkttype == PKT_SECRET_SUBKEY )
1350                 node->flag &= ~NODFLG_SELKEY;
1351         }
1352         return 1;
1353     }
1354     /* and set the new index */
1355     for( i=0, node = keyblock; node; node = node->next ) {
1356         if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
1357             || node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
1358             if( ++i == index )
1359                 if( (node->flag & NODFLG_SELKEY) )
1360                     node->flag &= ~NODFLG_SELKEY;
1361                 else
1362                     node->flag |= NODFLG_SELKEY;
1363         }
1364     }
1365
1366     return 1;
1367 }
1368
1369
1370 static int
1371 count_uids_with_flag( KBNODE keyblock, unsigned flag )
1372 {
1373     KBNODE node;
1374     int i=0;
1375
1376     for( node = keyblock; node; node = node->next )
1377         if( node->pkt->pkttype == PKT_USER_ID && (node->flag & flag) )
1378             i++;
1379     return i;
1380 }
1381
1382 static int
1383 count_keys_with_flag( KBNODE keyblock, unsigned flag )
1384 {
1385     KBNODE node;
1386     int i=0;
1387
1388     for( node = keyblock; node; node = node->next )
1389         if( ( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
1390               || node->pkt->pkttype == PKT_SECRET_SUBKEY)
1391             && (node->flag & flag) )
1392             i++;
1393     return i;
1394 }
1395
1396 static int
1397 count_uids( KBNODE keyblock )
1398 {
1399     KBNODE node;
1400     int i=0;
1401
1402     for( node = keyblock; node; node = node->next )
1403         if( node->pkt->pkttype == PKT_USER_ID )
1404             i++;
1405     return i;
1406 }
1407
1408
1409 /****************
1410  * Returns true if there is at least one selected user id
1411  */
1412 static int
1413 count_selected_uids( KBNODE keyblock )
1414 {
1415     return count_uids_with_flag( keyblock, NODFLG_SELUID);
1416 }
1417
1418 static int
1419 count_selected_keys( KBNODE keyblock )
1420 {
1421     return count_keys_with_flag( keyblock, NODFLG_SELKEY);
1422 }
1423