d0295766b7bfe7de20f1697e23326d0c66511906
[gnupg.git] / g10 / keyedit.c
1 /* keyedit.c - keyedit stuff
2  * Copyright (C) 1998, 1999, 2000, 2001, 2002 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 "photoid.h"
36 #include "util.h"
37 #include "main.h"
38 #include "trustdb.h"
39 #include "filter.h"
40 #include "ttyio.h"
41 #include "status.h"
42 #include "i18n.h"
43
44 static void show_prefs( PKT_user_id *uid, int verbose );
45 static void show_key_with_all_names( KBNODE keyblock, int only_marked,
46             int with_revoker, int with_fpr, int with_subkeys, int with_prefs );
47 static void show_key_and_fingerprint( KBNODE keyblock );
48 static int menu_adduid( KBNODE keyblock, KBNODE sec_keyblock, int photo );
49 static void menu_deluid( KBNODE pub_keyblock, KBNODE sec_keyblock );
50 static int  menu_delsig( KBNODE pub_keyblock );
51 static void menu_delkey( KBNODE pub_keyblock, KBNODE sec_keyblock );
52 static int menu_addrevoker( KBNODE pub_keyblock,
53                             KBNODE sec_keyblock, int sensitive );
54 static int menu_expire( KBNODE pub_keyblock, KBNODE sec_keyblock );
55 static int menu_set_primary_uid( KBNODE pub_keyblock, KBNODE sec_keyblock );
56 static int menu_set_preferences( KBNODE pub_keyblock, KBNODE sec_keyblock );
57 static int menu_select_uid( KBNODE keyblock, int idx );
58 static int menu_select_key( KBNODE keyblock, int idx );
59 static int count_uids( KBNODE keyblock );
60 static int count_uids_with_flag( KBNODE keyblock, unsigned flag );
61 static int count_keys_with_flag( KBNODE keyblock, unsigned flag );
62 static int count_selected_uids( KBNODE keyblock );
63 static int real_uids_left( KBNODE keyblock );
64 static int count_selected_keys( KBNODE keyblock );
65 static int menu_revsig( KBNODE keyblock );
66 static int menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock );
67 static int enable_disable_key( KBNODE keyblock, int disable );
68 static void menu_showphoto( KBNODE keyblock );
69
70 static int update_trust=0;
71
72 #define CONTROL_D ('D' - 'A' + 1)
73
74 #define NODFLG_BADSIG (1<<0)  /* bad signature */
75 #define NODFLG_NOKEY  (1<<1)  /* no public key */
76 #define NODFLG_SIGERR (1<<2)  /* other sig error */
77
78 #define NODFLG_MARK_A (1<<4)  /* temporary mark */
79 #define NODFLG_DELSIG (1<<5)  /* to be deleted */
80
81 #define NODFLG_SELUID (1<<8)  /* indicate the selected userid */
82 #define NODFLG_SELKEY (1<<9)  /* indicate the selected key */
83 #define NODFLG_SELSIG (1<<10) /* indicate a selected signature */
84
85 struct sign_attrib {
86     int non_exportable,non_revocable;
87     struct revocation_reason_info *reason;
88 };
89
90 /****************
91  * Print information about a signature, check it and return true
92  * if the signature is okay. NODE must be a signature packet.
93  */
94 static int
95 print_and_check_one_sig( KBNODE keyblock, KBNODE node,
96                          int *inv_sigs, int *no_key, int *oth_err,
97                         int *is_selfsig, int print_without_key )
98 {
99     PKT_signature *sig = node->pkt->pkt.signature;
100     int rc, sigrc;
101     int is_rev = sig->sig_class == 0x30;
102
103     /* TODO: Make sure a cached sig record here still has the pk that
104        issued it.  See also keylist.c:list_keyblock_print */
105
106     switch( (rc = check_key_signature( keyblock, node, is_selfsig)) ) {
107       case 0:
108         node->flag &= ~(NODFLG_BADSIG|NODFLG_NOKEY|NODFLG_SIGERR);
109         sigrc = '!';
110         break;
111       case G10ERR_BAD_SIGN:
112         node->flag = NODFLG_BADSIG;
113         sigrc = '-';
114         if( inv_sigs )
115             ++*inv_sigs;
116         break;
117       case G10ERR_NO_PUBKEY:
118       case G10ERR_UNU_PUBKEY:
119         node->flag = NODFLG_NOKEY;
120         sigrc = '?';
121         if( no_key )
122             ++*no_key;
123         break;
124       default:
125         node->flag = NODFLG_SIGERR;
126         sigrc = '%';
127         if( oth_err )
128             ++*oth_err;
129         break;
130     }
131     if( sigrc != '?' || print_without_key ) {
132         tty_printf("%s%c%c %c%c%c%c%c%c %08lX %s   ",
133                    is_rev? "rev":"sig",sigrc,
134                    (sig->sig_class-0x10>0 &&
135                     sig->sig_class-0x10<4)?'0'+sig->sig_class-0x10:' ',
136                    sig->flags.exportable?' ':'L',
137                    sig->flags.revocable?' ':'R',
138                    sig->flags.policy_url?'P':' ',
139                    sig->flags.notation?'N':' ',
140                    sig->flags.expired?'X':' ',
141                    (sig->trust_depth>9)?'T':
142                    (sig->trust_depth>0)?'0'+sig->trust_depth:' ',
143                    (ulong)sig->keyid[1], datestr_from_sig(sig));
144         if( sigrc == '%' )
145             tty_printf("[%s] ", g10_errstr(rc) );
146         else if( sigrc == '?' )
147             ;
148         else if( *is_selfsig ) {
149             tty_printf( is_rev? _("[revocation]")
150                               : _("[self-signature]") );
151         }
152         else {
153             size_t n;
154             char *p = get_user_id( sig->keyid, &n );
155             tty_print_utf8_string2( p, n, 40 );
156             m_free(p);
157         }
158         tty_printf("\n");
159
160         if(sig->flags.policy_url && opt.show_policy_url)
161           show_policy_url(sig,3);
162
163         if(sig->flags.notation && opt.show_notation)
164           show_notation(sig,3);
165     }
166
167     return (sigrc == '!');
168 }
169
170
171
172 /****************
173  * Check the keysigs and set the flags to indicate errors.
174  * Returns true if error found.
175  */
176 static int
177 check_all_keysigs( KBNODE keyblock, int only_selected )
178 {
179     KBNODE kbctx;
180     KBNODE node;
181     int inv_sigs = 0;
182     int no_key = 0;
183     int oth_err = 0;
184     int has_selfsig = 0;
185     int mis_selfsig = 0;
186     int selected = !only_selected;
187     int anyuid = 0;
188
189     for( kbctx=NULL; (node=walk_kbnode( keyblock, &kbctx, 0)) ; ) {
190         if( node->pkt->pkttype == PKT_USER_ID ) {
191             PKT_user_id *uid = node->pkt->pkt.user_id;
192
193             if( only_selected )
194                 selected = (node->flag & NODFLG_SELUID);
195             if( selected ) {
196                 tty_printf("uid  ");
197                 tty_print_utf8_string( uid->name, uid->len );
198                 tty_printf("\n");
199                 if( anyuid && !has_selfsig )
200                     mis_selfsig++;
201                 has_selfsig = 0;
202                 anyuid = 1;
203             }
204         }
205         else if( selected && node->pkt->pkttype == PKT_SIGNATURE
206                  && ( (node->pkt->pkt.signature->sig_class&~3) == 0x10
207                      || node->pkt->pkt.signature->sig_class == 0x30 )  ) {
208             int selfsig;
209
210             if( print_and_check_one_sig( keyblock, node, &inv_sigs,
211                                         &no_key, &oth_err, &selfsig, 0 ) ) {
212                 if( selfsig )
213                     has_selfsig = 1;
214             }
215             /* Hmmm: should we update the trustdb here? */
216         }
217     }
218     if( !has_selfsig )
219         mis_selfsig++;
220     if( inv_sigs == 1 )
221         tty_printf(_("1 bad signature\n") );
222     else if( inv_sigs )
223         tty_printf(_("%d bad signatures\n"), inv_sigs );
224     if( no_key == 1 )
225         tty_printf(_("1 signature not checked due to a missing key\n") );
226     else if( no_key )
227         tty_printf(_("%d signatures not checked due to missing keys\n"), no_key );
228     if( oth_err == 1 )
229         tty_printf(_("1 signature not checked due to an error\n") );
230     else if( oth_err )
231         tty_printf(_("%d signatures not checked due to errors\n"), oth_err );
232     if( mis_selfsig == 1 )
233         tty_printf(_("1 user ID without valid self-signature detected\n"));
234     else if( mis_selfsig  )
235         tty_printf(_("%d user IDs without valid self-signatures detected\n"),
236                                                                     mis_selfsig);
237
238     return inv_sigs || no_key || oth_err || mis_selfsig;
239 }
240
241
242
243
244 static int
245 sign_mk_attrib( PKT_signature *sig, void *opaque )
246 {
247     struct sign_attrib *attrib = opaque;
248     byte buf[8];
249
250     if( attrib->non_exportable ) {
251         buf[0] = 0; /* not exportable */
252         build_sig_subpkt( sig, SIGSUBPKT_EXPORTABLE, buf, 1 );
253     }
254
255     if( attrib->non_revocable ) {
256         buf[0] = 0; /* not revocable */
257         build_sig_subpkt( sig, SIGSUBPKT_REVOCABLE, buf, 1 );
258     }
259
260     if( attrib->reason )
261         revocation_reason_build_cb( sig, attrib->reason );
262
263     return 0;
264 }
265
266
267
268 /****************
269  * Loop over all locusr and and sign the uids after asking.
270  * If no user id is marked, all user ids will be signed;
271  * if some user_ids are marked those will be signed.
272  */
273 static int
274 sign_uids( KBNODE keyblock, STRLIST locusr, int *ret_modified,
275            int local , int nonrevocable )
276 {
277     int rc = 0;
278     SK_LIST sk_list = NULL;
279     SK_LIST sk_rover = NULL;
280     PKT_secret_key *sk = NULL;
281     KBNODE node, uidnode;
282     PKT_public_key *primary_pk=NULL;
283     int select_all = !count_selected_uids(keyblock);
284     int all_v3=1;
285
286     /* Are there any non-v3 sigs on this key already? */
287     if(opt.pgp2)
288       for(node=keyblock;node;node=node->next)
289         if(node->pkt->pkttype==PKT_SIGNATURE &&
290            node->pkt->pkt.signature->version>3)
291           {
292             all_v3=0;
293             break;
294           }
295
296     /* build a list of all signators.
297      *    
298      * We use the CERT flag to request the primary which must always
299      * be one which is capable of signing keys.  I can't see a reason
300      * why to sign keys using a subkey.  Implementation of USAGE_CERT
301      * is just a hack in getkey.c and does not mean that a subkey
302      * marked as certification capable will be used */
303     rc=build_sk_list( locusr, &sk_list, 0, PUBKEY_USAGE_SIG|PUBKEY_USAGE_CERT);
304     if( rc )
305         goto leave;
306
307     /* loop over all signators */
308     for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) {
309         u32 sk_keyid[2],pk_keyid[2];
310         size_t n;
311         char *p;
312         int force_v4=0,class=0,selfsig=0;
313         u32 duration=0,timestamp=0;
314
315         if(local || nonrevocable ||
316            opt.cert_policy_url || opt.cert_notation_data)
317           force_v4=1;
318
319         /* we have to use a copy of the sk, because make_keysig_packet
320          * may remove the protection from sk and if we did other
321          * changes to the secret key, we would save the unprotected
322          * version */
323         if( sk )
324             free_secret_key(sk);
325         sk = copy_secret_key( NULL, sk_rover->sk );
326         keyid_from_sk( sk, sk_keyid );
327         /* set mark A for all selected user ids */
328         for( node=keyblock; node; node = node->next ) {
329             if( select_all || (node->flag & NODFLG_SELUID) )
330                 node->flag |= NODFLG_MARK_A;
331             else
332                 node->flag &= ~NODFLG_MARK_A;
333         }
334         /* reset mark for uids which are already signed */
335         uidnode = NULL;
336         for( node=keyblock; node; node = node->next ) {
337             if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
338                 primary_pk=node->pkt->pkt.public_key;
339                 keyid_from_pk( primary_pk, pk_keyid );
340
341                 /* Is this a self-sig? */
342                 if(pk_keyid[0]==sk_keyid[0] && pk_keyid[1]==sk_keyid[1])
343                   {
344                     selfsig=1;
345                     /* Do not force a v4 sig here, otherwise it would
346                        be difficult to remake a v3 selfsig.  If this
347                        is a v3->v4 promotion case, then we set
348                        force_v4 later anyway. */
349                     force_v4=0;
350                   }
351             }
352             else if( node->pkt->pkttype == PKT_USER_ID ) {
353                 uidnode = (node->flag & NODFLG_MARK_A)? node : NULL;
354                 if(uidnode)
355                   {
356                     char *user=utf8_to_native(uidnode->pkt->pkt.user_id->name,
357                                               uidnode->pkt->pkt.user_id->len,
358                                               0);
359
360                     if(uidnode->pkt->pkt.user_id->is_revoked)
361                       {
362                         tty_printf(_("User ID \"%s\" is revoked."),user);
363
364                         if(opt.expert)
365                           {
366                             tty_printf("\n");
367                             /* No, so remove the mark and continue */
368                             if(!cpr_get_answer_is_yes("sign_uid.revoke_okay",
369                                                       _("Are you sure you "
370                                                         "still want to sign "
371                                                         "it? (y/N) ")))
372                               uidnode->flag &= ~NODFLG_MARK_A;
373                           }
374                         else
375                           {
376                             uidnode->flag &= ~NODFLG_MARK_A;
377                             tty_printf(_("  Unable to sign.\n"));
378                           }
379                       }
380                     else if(!uidnode->pkt->pkt.user_id->created)
381                       {
382                         tty_printf(_("WARNING: user ID \"%s\" is not "
383                                      "self-signed.\n"),user);
384                       }
385
386                     m_free(user);
387                   }
388             }
389             else if( uidnode && node->pkt->pkttype == PKT_SIGNATURE
390                 && (node->pkt->pkt.signature->sig_class&~3) == 0x10 ) {
391                 if( sk_keyid[0] == node->pkt->pkt.signature->keyid[0]
392                     && sk_keyid[1] == node->pkt->pkt.signature->keyid[1] ) {
393                     char buf[50];
394                     char *user=utf8_to_native(uidnode->pkt->pkt.user_id->name,
395                                               uidnode->pkt->pkt.user_id->len,
396                                               0);
397
398                     /* It's a v3 self-sig.  Make it into a v4 self-sig? */
399                     if(node->pkt->pkt.signature->version<4 && selfsig)
400                       {
401                         tty_printf(_("The self-signature on \"%s\"\n"
402                                      "is a PGP 2.x-style signature.\n"),user);
403  
404                         /* Note that the regular PGP2 warning below
405                            still applies if there are no v4 sigs on
406                            this key at all. */
407
408                         if(opt.expert)
409                           if(cpr_get_answer_is_yes("sign_uid.v4_promote_okay",
410                                                    _("Do you want to promote "
411                                                      "it to an OpenPGP self-"
412                                                      "signature? (y/N) ")))
413                             {
414                               force_v4=1;
415                               node->flag|=NODFLG_DELSIG;
416                               continue;
417                             }
418                       }
419
420                     if(!node->pkt->pkt.signature->flags.exportable && !local)
421                       {
422                         /* It's a local sig, and we want to make a
423                            exportable sig. */
424                         tty_printf(_("Your current signature on \"%s\"\n"
425                                      "is a local signature.\n"),user);
426
427                         if(cpr_get_answer_is_yes("sign_uid.local_promote_okay",
428                                                  _("Do you want to promote "
429                                                    "it to a full exportable "
430                                                    "signature? (y/N) ")))
431                           {
432                             /* Mark these for later deletion.  We
433                                don't want to delete them here, just in
434                                case the replacement signature doesn't
435                                happen for some reason.  We only delete
436                                these after the replacement is already
437                                in place. */
438
439                             node->flag|=NODFLG_DELSIG;
440                             continue;
441                           }
442                       }
443
444                     /* Fixme: see whether there is a revocation in which
445                      * case we should allow to sign it again. */
446                     if (!node->pkt->pkt.signature->flags.exportable && local)
447                       tty_printf(_(
448                          "\"%s\" was already locally signed by key %08lX\n"),
449                                  user,(ulong)sk_keyid[1] );
450                     else
451                       tty_printf(_(
452                          "\"%s\" was already signed by key %08lX\n"),
453                                  user,(ulong)sk_keyid[1] );
454                     sprintf (buf, "%08lX%08lX",
455                              (ulong)sk->keyid[0], (ulong)sk->keyid[1] );
456                     write_status_text (STATUS_ALREADY_SIGNED, buf);
457                     uidnode->flag &= ~NODFLG_MARK_A; /* remove mark */
458
459                     m_free(user);
460                 }
461             }
462         }
463         /* check whether any uids are left for signing */
464         if( !count_uids_with_flag(keyblock, NODFLG_MARK_A) ) {
465             tty_printf(_("Nothing to sign with key %08lX\n"),
466                                                   (ulong)sk_keyid[1] );
467             continue;
468         }
469         /* Ask whether we really should sign these user id(s) */
470         tty_printf("\n");
471         show_key_with_all_names( keyblock, 1, 0, 1, 0, 0 );
472         tty_printf("\n");
473
474         if(primary_pk->expiredate && !selfsig)
475           {
476             u32 now=make_timestamp();
477
478             if(primary_pk->expiredate<=now)
479               {
480                 tty_printf(_("This key has expired!"));
481
482                 if(opt.expert)
483                   {
484                     tty_printf("  ");
485                     if(!cpr_get_answer_is_yes("sign_uid.expired_okay",
486                                               _("Are you sure you still "
487                                                 "want to sign it? (y/N) ")))
488                       continue;
489                   }
490                 else
491                   {
492                     tty_printf(_("  Unable to sign.\n"));
493                     continue;
494                   }
495               }
496             else
497               {
498                 char *answer;
499
500                 tty_printf(_("This key is due to expire on %s.\n"),
501                            expirestr_from_pk(primary_pk));
502
503                 answer=cpr_get("sign_uid.expire",
504                                _("Do you want your signature to "
505                                  "expire at the same time? (Y/n) "));
506                 if(answer_is_yes_no_default(answer,1))
507                   {
508                     /* This fixes the signature timestamp we're going
509                        to make as now.  This is so the expiration date
510                        is exactly correct, and not a few seconds off
511                        (due to the time it takes to answer the
512                        questions, enter the passphrase, etc). */
513                     timestamp=now;
514                     duration=primary_pk->expiredate-now;
515                     force_v4=1;
516                   }
517
518                 cpr_kill_prompt();
519                 m_free(answer);
520               }
521           }
522
523         /* Only ask for duration if we haven't already set it to match
524            the expiration of the pk */
525         if(opt.ask_cert_expire && !duration && !selfsig)
526           duration=ask_expire_interval(1);
527
528         if(duration)
529           force_v4=1;
530
531         /* Is --pgp2 on, it's a v3 key, all the sigs on the key are
532            currently v3 and we're about to sign it with a v4 sig?  If
533            so, danger! */
534         if(opt.pgp2 && all_v3 &&
535            (sk->version>3 || force_v4) && primary_pk->version<=3)
536           {
537             tty_printf(_("You may not make an OpenPGP signature on a "
538                          "PGP 2.x key while in --pgp2 mode.\n"));
539             tty_printf(_("This would make the key unusable in PGP 2.x.\n"));
540
541             if(opt.expert)
542               {
543                 if(!cpr_get_answer_is_yes("sign_uid.v4_on_v3_okay",
544                                           _("Are you sure you still "
545                                             "want to sign it? (y/N) ")))
546                   continue;
547
548                 all_v3=0;
549               }
550             else
551               continue;
552           }
553
554         if(selfsig)
555           ;
556         else if(opt.batch)
557           class=0x10+opt.def_cert_check_level;
558         else
559           {
560             char *answer;
561
562             tty_printf(_("How carefully have you verified the key you are "
563                          "about to sign actually belongs\nto the person named "
564                          "above?  If you don't know what to answer, enter \"0\".\n"));
565             tty_printf("\n");
566             tty_printf(_("   (0) I will not answer.%s\n"),
567                        opt.def_cert_check_level==0?_(" (default)"):"");
568             tty_printf(_("   (1) I have not checked at all.%s\n"),
569                        opt.def_cert_check_level==1?_(" (default)"):"");
570             tty_printf(_("   (2) I have done casual checking.%s\n"),
571                        opt.def_cert_check_level==2?_(" (default)"):"");
572             tty_printf(_("   (3) I have done very careful checking.%s\n"),
573                        opt.def_cert_check_level==3?_(" (default)"):"");
574             tty_printf("\n");
575
576             while(class==0)
577               {
578                 answer = cpr_get("sign_uid.class",_("Your selection? "));
579
580                 if(answer[0]=='\0')
581                   class=0x10+opt.def_cert_check_level; /* Default */
582                 else if(ascii_strcasecmp(answer,"0")==0)
583                   class=0x10; /* Generic */
584                 else if(ascii_strcasecmp(answer,"1")==0)
585                   class=0x11; /* Persona */
586                 else if(ascii_strcasecmp(answer,"2")==0)
587                   class=0x12; /* Casual */
588                 else if(ascii_strcasecmp(answer,"3")==0)
589                   class=0x13; /* Positive */
590                 else
591                   tty_printf(_("Invalid selection.\n"));
592
593                 m_free(answer);
594               }
595           }
596
597         tty_printf(_("Are you really sure that you want to sign this key\n"
598                      "with your key: \""));
599         p = get_user_id( sk_keyid, &n );
600         tty_print_utf8_string( p, n );
601         m_free(p); p = NULL;
602         tty_printf("\"\n");
603
604         if(selfsig)
605           {
606             tty_printf(_("\nThis will be a self-signature.\n"));
607
608             if( local )
609               tty_printf(
610                          _("\nWARNING: the signature will not be marked "
611                            "as non-exportable.\n"));
612
613             if( nonrevocable )
614               tty_printf(
615                          _("\nWARNING: the signature will not be marked "
616                            "as non-revocable.\n"));
617           }
618         else
619           {
620             if( local )
621               tty_printf(
622                      _("\nThe signature will be marked as non-exportable.\n"));
623
624             if( nonrevocable )
625               tty_printf(
626                       _("\nThe signature will be marked as non-revocable.\n"));
627
628             switch(class)
629               {
630               case 0x11:
631                 tty_printf(_("\nI have not checked this key at all.\n"));
632                 break;
633
634               case 0x12:
635                 tty_printf(_("\nI have checked this key casually.\n"));
636                 break;
637
638               case 0x13:
639                 tty_printf(_("\nI have checked this key very carefully.\n"));
640                 break;
641               }
642           }
643
644         tty_printf("\n");
645
646         if( opt.batch && opt.answer_yes )
647           ;
648         else if( !cpr_get_answer_is_yes("sign_uid.okay", _("Really sign? ")) )
649             continue;
650
651         /* now we can sign the user ids */
652       reloop: /* (must use this, because we are modifing the list) */
653         primary_pk = NULL;
654         for( node=keyblock; node; node = node->next ) {
655             if( node->pkt->pkttype == PKT_PUBLIC_KEY )
656                 primary_pk = node->pkt->pkt.public_key;
657             else if( node->pkt->pkttype == PKT_USER_ID
658                      && (node->flag & NODFLG_MARK_A) ) {
659                 PACKET *pkt;
660                 PKT_signature *sig;
661                 struct sign_attrib attrib;
662
663                 assert( primary_pk );
664                 memset( &attrib, 0, sizeof attrib );
665                 attrib.non_exportable = local;
666                 attrib.non_revocable = nonrevocable;
667                 node->flag &= ~NODFLG_MARK_A;
668
669                 /* we force creation of a v4 signature for local
670                  * signatures, otherwise we would not generate the
671                  * subpacket with v3 keys and the signature becomes
672                  * exportable */
673
674                 if(selfsig)
675                   rc = make_keysig_packet( &sig, primary_pk,
676                                            node->pkt->pkt.user_id,
677                                            NULL,
678                                            sk,
679                                            0x13, 0, force_v4?4:0, 0, 0,
680                                            keygen_add_std_prefs, primary_pk);
681                 else
682                   rc = make_keysig_packet( &sig, primary_pk,
683                                            node->pkt->pkt.user_id,
684                                            NULL,
685                                            sk,
686                                            class, 0, force_v4?4:0,
687                                            timestamp, duration,
688                                            sign_mk_attrib, &attrib );
689                 if( rc ) {
690                     log_error(_("signing failed: %s\n"), g10_errstr(rc));
691                     goto leave;
692                 }
693
694                 *ret_modified = 1; /* we changed the keyblock */
695                 update_trust = 1;
696
697                 pkt = m_alloc_clear( sizeof *pkt );
698                 pkt->pkttype = PKT_SIGNATURE;
699                 pkt->pkt.signature = sig;
700                 insert_kbnode( node, new_kbnode(pkt), PKT_SIGNATURE );
701                 goto reloop;
702             }
703         }
704
705         /* Delete any sigs that got promoted */
706         for( node=keyblock; node; node = node->next )
707           if( node->flag & NODFLG_DELSIG)
708             delete_kbnode(node);
709     } /* end loop over signators */
710
711   leave:
712     release_sk_list( sk_list );
713     if( sk )
714         free_secret_key(sk);
715     return rc;
716 }
717
718
719
720 /****************
721  * Change the passphrase of the primary and all secondary keys.
722  * We use only one passphrase for all keys.
723  */
724 static int
725 change_passphrase( KBNODE keyblock )
726 {
727     int rc = 0;
728     int changed=0;
729     KBNODE node;
730     PKT_secret_key *sk;
731     char *passphrase = NULL;
732     int no_primary_secrets = 0;
733
734     node = find_kbnode( keyblock, PKT_SECRET_KEY );
735     if( !node ) {
736         log_error("Oops; secret key not found anymore!\n");
737         goto leave;
738     }
739     sk = node->pkt->pkt.secret_key;
740
741     switch( is_secret_key_protected( sk ) ) {
742       case -1:
743         rc = G10ERR_PUBKEY_ALGO;
744         break;
745       case 0:
746         tty_printf(_("This key is not protected.\n"));
747         break;
748       default:
749         if( sk->protect.s2k.mode == 1001 ) {
750             tty_printf(_("Secret parts of primary key are not available.\n"));
751             no_primary_secrets = 1;
752         }
753         else {
754             tty_printf(_("Key is protected.\n"));
755             rc = check_secret_key( sk, 0 );
756             if( !rc )
757                 passphrase = get_last_passphrase();
758         }
759         break;
760     }
761
762     /* unprotect all subkeys (use the supplied passphrase or ask)*/
763     for(node=keyblock; !rc && node; node = node->next ) {
764         if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
765             PKT_secret_key *subsk = node->pkt->pkt.secret_key;
766             set_next_passphrase( passphrase );
767             rc = check_secret_key( subsk, 0 );
768             if( !rc && !passphrase )
769                 passphrase = get_last_passphrase();
770         }
771     }
772
773     if( rc )
774         tty_printf(_("Can't edit this key: %s\n"), g10_errstr(rc));
775     else {
776         DEK *dek = NULL;
777         STRING2KEY *s2k = m_alloc_secure( sizeof *s2k );
778         const char *errtext = NULL;
779
780         tty_printf(_("Enter the new passphrase for this secret key.\n\n") );
781
782         set_next_passphrase( NULL );
783         for(;;) {
784             s2k->mode = opt.s2k_mode;
785             s2k->hash_algo = opt.s2k_digest_algo;
786             dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo,
787                                      s2k, 2, errtext);
788             if( !dek ) {
789                 errtext = _("passphrase not correctly repeated; try again");
790                 tty_printf ("%s.\n", errtext);
791             }
792             else if( !dek->keylen ) {
793                 rc = 0;
794                 tty_printf(_( "You don't want a passphrase -"
795                             " this is probably a *bad* idea!\n\n"));
796                 if( cpr_get_answer_is_yes("change_passwd.empty.okay",
797                                _("Do you really want to do this? ")))
798                     changed++;
799                 break;
800             }
801             else { /* okay */
802                 rc = 0;
803                 if( !no_primary_secrets ) {
804                     sk->protect.algo = dek->algo;
805                     sk->protect.s2k = *s2k;
806                     rc = protect_secret_key( sk, dek );
807                 }
808                 for(node=keyblock; !rc && node; node = node->next ) {
809                     if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
810                         PKT_secret_key *subsk = node->pkt->pkt.secret_key;
811                         subsk->protect.algo = dek->algo;
812                         subsk->protect.s2k = *s2k;
813                         rc = protect_secret_key( subsk, dek );
814                     }
815                 }
816                 if( rc )
817                     log_error("protect_secret_key failed: %s\n", g10_errstr(rc) );
818                 else
819                     changed++;
820                 break;
821             }
822         }
823         m_free(s2k);
824         m_free(dek);
825     }
826
827   leave:
828     m_free( passphrase );
829     set_next_passphrase( NULL );
830     return changed && !rc;
831 }
832
833
834 /****************
835  * There are some keys out (due to a bug in gnupg), where the sequence
836  * of the packets is wrong.  This function fixes that.
837  * Returns: true if the keyblock has been fixed.
838  *
839  * Note:  This function does not work if there is more than one user ID.
840  */
841 static int
842 fix_keyblock( KBNODE keyblock )
843 {
844     KBNODE node, last, subkey;
845     int fixed=0;
846
847     /* locate key signatures of class 0x10..0x13 behind sub key packets */
848     for( subkey=last=NULL, node = keyblock; node;
849                                             last=node, node = node->next ) {
850         switch( node->pkt->pkttype ) {
851           case PKT_PUBLIC_SUBKEY:
852           case PKT_SECRET_SUBKEY:
853             if( !subkey )
854                 subkey = last; /* actually it is the one before the subkey */
855             break;
856           case PKT_SIGNATURE:
857             if( subkey ) {
858                 PKT_signature *sig = node->pkt->pkt.signature;
859                 if( sig->sig_class >= 0x10 && sig->sig_class <= 0x13 ) {
860                     log_info(_(
861                         "moving a key signature to the correct place\n"));
862                     last->next = node->next;
863                     node->next = subkey->next;
864                     subkey->next = node;
865                     node = last;
866                     fixed=1;
867                 }
868             }
869             break;
870           default: break;
871         }
872     }
873
874     return fixed;
875 }
876
877 /****************
878  * Menu driven key editor.  If sign_mode is true semi-automatical signing
879  * will be performed. commands are ignore in this case
880  *
881  * Note: to keep track of some selection we use node->mark MARKBIT_xxxx.
882  */
883
884 void
885 keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
886                                                     int sign_mode )
887 {
888     enum cmdids { cmdNONE = 0,
889            cmdQUIT, cmdHELP, cmdFPR, cmdLIST, cmdSELUID, cmdCHECK, cmdSIGN,
890            cmdLSIGN, cmdNRSIGN, cmdNRLSIGN, cmdREVSIG, cmdREVKEY, cmdDELSIG,
891            cmdPRIMARY, cmdDEBUG, cmdSAVE, cmdADDUID, cmdADDPHOTO, cmdDELUID,
892            cmdADDKEY, cmdDELKEY, cmdADDREVOKER, cmdTOGGLE, cmdSELKEY,
893            cmdPASSWD, cmdTRUST, cmdPREF, cmdEXPIRE, cmdENABLEKEY,
894            cmdDISABLEKEY, cmdSHOWPREF, cmdSETPREF, cmdUPDPREF, cmdINVCMD,
895            cmdSHOWPHOTO, cmdUPDTRUST, cmdCHKTRUST, cmdNOP };
896     static struct { const char *name;
897                     enum cmdids id;
898                     int need_sk;
899                     int not_with_sk;
900                     int signmode;
901                     const char *desc;
902                   } cmds[] = {
903         { N_("quit")    , cmdQUIT      , 0,0,1, N_("quit this menu") },
904         { N_("q")       , cmdQUIT      , 0,0,1, NULL   },
905         { N_("save")    , cmdSAVE      , 0,0,1, N_("save and quit") },
906         { N_("help")    , cmdHELP      , 0,0,1, N_("show this help") },
907         {    "?"        , cmdHELP      , 0,0,1, NULL   },
908         { N_("fpr")     , cmdFPR       , 0,0,1, N_("show fingerprint") },
909         { N_("list")    , cmdLIST      , 0,0,1, N_("list key and user IDs") },
910         { N_("l")       , cmdLIST      , 0,0,1, NULL   },
911         { N_("uid")     , cmdSELUID    , 0,0,1, N_("select user ID N") },
912         { N_("key")     , cmdSELKEY    , 0,0,0, N_("select secondary key N") },
913         { N_("check")   , cmdCHECK     , 0,0,1, N_("list signatures") },
914         { N_("c")       , cmdCHECK     , 0,0,1, NULL },
915         { N_("sign")    , cmdSIGN      , 0,1,1, N_("sign the key") },
916         { N_("s")       , cmdSIGN      , 0,1,1, NULL },
917         { N_("lsign")   , cmdLSIGN     , 0,1,1, N_("sign the key locally") },
918         { N_("nrsign")  , cmdNRSIGN    , 0,1,1, N_("sign the key non-revocably") },
919         { N_("nrlsign") , cmdNRLSIGN   , 0,1,1, N_("sign the key locally and non-revocably") },
920         { N_("debug")   , cmdDEBUG     , 0,0,0, NULL },
921         { N_("adduid")  , cmdADDUID    , 1,1,0, N_("add a user ID") },
922         { N_("addphoto"), cmdADDPHOTO  , 1,1,0, N_("add a photo ID") },
923         { N_("deluid")  , cmdDELUID    , 0,1,0, N_("delete user ID") },
924         /* delphoto is really deluid in disguise */
925         { N_("delphoto"), cmdDELUID    , 0,1,0, NULL },
926         { N_("addkey")  , cmdADDKEY    , 1,1,0, N_("add a secondary key") },
927         { N_("delkey")  , cmdDELKEY    , 0,1,0, N_("delete a secondary key") },
928         { N_("addrevoker"),cmdADDREVOKER,1,1,0, N_("add a revocation key") },
929         { N_("delsig")  , cmdDELSIG    , 0,1,0, N_("delete signatures") },
930         { N_("expire")  , cmdEXPIRE    , 1,1,0, N_("change the expire date") },
931         { N_("primary") , cmdPRIMARY   , 1,1,0, N_("flag user ID as primary")},
932         { N_("toggle")  , cmdTOGGLE    , 1,0,0, N_("toggle between secret "
933                                                    "and public key listing") },
934         { N_("t"     )  , cmdTOGGLE    , 1,0,0, NULL },
935         { N_("pref")    , cmdPREF      , 0,1,0, N_("list preferences (expert)") },
936         { N_("showpref"), cmdSHOWPREF  , 0,1,0, N_("list preferences (verbose)") },
937         { N_("setpref") , cmdSETPREF   , 1,1,0, N_("set preference list") },
938         { N_("updpref") , cmdUPDPREF   , 1,1,0, N_("updated preferences") },
939         { N_("passwd")  , cmdPASSWD    , 1,1,0, N_("change the passphrase") },
940         { N_("trust")   , cmdTRUST     , 0,1,0, N_("change the ownertrust") },
941         { N_("revsig")  , cmdREVSIG    , 0,1,0, N_("revoke signatures") },
942         { N_("revkey")  , cmdREVKEY    , 1,1,0, N_("revoke a secondary key") },
943         { N_("disable") , cmdDISABLEKEY, 0,1,0, N_("disable a key") },
944         { N_("enable")  , cmdENABLEKEY , 0,1,0, N_("enable a key") },
945         { N_("showphoto"),cmdSHOWPHOTO , 0,0,0, N_("show photo ID") },
946
947     { NULL, cmdNONE } };
948     enum cmdids cmd = 0;
949     int rc = 0;
950     KBNODE keyblock = NULL;
951     KEYDB_HANDLE kdbhd = NULL;
952     KBNODE sec_keyblock = NULL;
953     KEYDB_HANDLE sec_kdbhd = NULL;
954     KBNODE cur_keyblock;
955     char *answer = NULL;
956     int redisplay = 1;
957     int modified = 0;
958     int sec_modified = 0;
959     int toggle;
960     int have_commands = !!commands;
961
962     if ( opt.command_fd != -1 )
963         ;
964     else if( opt.batch && !have_commands  ) {
965         log_error(_("can't do that in batchmode\n"));
966         goto leave;
967     }
968
969     if( sign_mode ) {
970         commands = NULL;
971         append_to_strlist( &commands, sign_mode == 1? "sign":
972                            sign_mode == 2?"lsign":
973                            sign_mode == 3?"nrsign":"nrlsign");
974         have_commands = 1;
975     }
976
977     /* get the public key */
978     rc = get_pubkey_byname (NULL, username, &keyblock, &kdbhd);
979     if( rc )
980         goto leave;
981     if( fix_keyblock( keyblock ) )
982         modified++;
983     if( collapse_uids( &keyblock ) )
984         modified++;
985
986     if( !sign_mode ) {/* see whether we have a matching secret key */
987         PKT_public_key *pk = keyblock->pkt->pkt.public_key;
988
989         sec_kdbhd = keydb_new (1);
990         {
991             byte afp[MAX_FINGERPRINT_LEN];
992             size_t an;
993
994             fingerprint_from_pk (pk, afp, &an);
995             while (an < MAX_FINGERPRINT_LEN) 
996                 afp[an++] = 0;
997             rc = keydb_search_fpr (sec_kdbhd, afp);
998         }
999         if (!rc) {
1000             rc = keydb_get_keyblock (sec_kdbhd, &sec_keyblock);
1001             if (rc) {
1002                 log_error (_("error reading secret keyblock `%s': %s\n"),
1003                                                 username, g10_errstr(rc));
1004             }
1005             else {
1006                 merge_keys_and_selfsig( sec_keyblock );
1007                 if( fix_keyblock( sec_keyblock ) )
1008                     sec_modified++;
1009             }
1010         }
1011
1012         if (rc) {
1013             sec_keyblock = NULL;
1014             keydb_release (sec_kdbhd); sec_kdbhd = NULL;
1015             rc = 0;
1016         }
1017     }
1018
1019     if( sec_keyblock ) { 
1020         tty_printf(_("Secret key is available.\n"));
1021     }
1022
1023     toggle = 0;
1024     cur_keyblock = keyblock;
1025     for(;;) { /* main loop */
1026         int i, arg_number, photo;
1027         const char *arg_string = "";
1028         char *p;
1029         PKT_public_key *pk=keyblock->pkt->pkt.public_key;
1030
1031         tty_printf("\n");
1032         if( redisplay ) {
1033             show_key_with_all_names( cur_keyblock, 0, 1, 0, 1, 0 );
1034             tty_printf("\n");
1035             redisplay = 0;
1036         }
1037         do {
1038             m_free(answer);
1039             if( have_commands ) {
1040                 if( commands ) {
1041                     answer = m_strdup( commands->d );
1042                     commands = commands->next;
1043                 }
1044                 else if( opt.batch ) {
1045                     answer = m_strdup("quit");
1046                 }
1047                 else
1048                     have_commands = 0;
1049             }
1050             if( !have_commands ) {
1051                 answer = cpr_get_no_help("keyedit.prompt", _("Command> "));
1052                 cpr_kill_prompt();
1053             }
1054             trim_spaces(answer);
1055         } while( *answer == '#' );
1056
1057         arg_number = 0; /* Yes, here is the init which egcc complains about */
1058         photo = 0; /* This too */
1059         if( !*answer )
1060             cmd = cmdLIST;
1061         else if( *answer == CONTROL_D )
1062             cmd = cmdQUIT;
1063         else if( isdigit( *answer ) ) {
1064             cmd = cmdSELUID;
1065             arg_number = atoi(answer);
1066         }
1067         else {
1068             if( (p=strchr(answer,' ')) ) {
1069                 *p++ = 0;
1070                 trim_spaces(answer);
1071                 trim_spaces(p);
1072                 arg_number = atoi(p);
1073                 arg_string = p;
1074             }
1075
1076             for(i=0; cmds[i].name; i++ ) {
1077                 if( !ascii_strcasecmp( answer, cmds[i].name ) )
1078                     break;
1079             }
1080             if( sign_mode && !cmds[i].signmode )
1081                 cmd = cmdINVCMD;
1082             else if( cmds[i].need_sk && !sec_keyblock ) {
1083                 tty_printf(_("Need the secret key to do this.\n"));
1084                 cmd = cmdNOP;
1085             }
1086             else if( cmds[i].not_with_sk && sec_keyblock && toggle ) {
1087                 tty_printf(_("Please use the command \"toggle\" first.\n"));
1088                 cmd = cmdNOP;
1089             }
1090             else
1091                 cmd = cmds[i].id;
1092         }
1093         switch( cmd )  {
1094           case cmdHELP:
1095             for(i=0; cmds[i].name; i++ ) {
1096                 if( sign_mode && !cmds[i].signmode )
1097                     ;
1098                 else if( cmds[i].need_sk && !sec_keyblock )
1099                     ; /* skip if we do not have the secret key */
1100                 else if( cmds[i].desc )
1101                     tty_printf("%-10s %s\n", cmds[i].name, _(cmds[i].desc) );
1102             }
1103             break;
1104
1105           case cmdLIST:
1106             redisplay = 1;
1107             break;
1108
1109           case cmdFPR:
1110             show_key_and_fingerprint( keyblock );
1111             break;
1112
1113           case cmdSELUID:
1114             if( menu_select_uid( cur_keyblock, arg_number ) )
1115                 redisplay = 1;
1116             break;
1117
1118           case cmdSELKEY:
1119             if( menu_select_key( cur_keyblock, arg_number ) )
1120                 redisplay = 1;
1121             break;
1122
1123           case cmdCHECK:
1124             /* we can only do this with the public key becuase the
1125              * check functions can't cope with secret keys and it
1126              * is questionable whether this would make sense at all */
1127             check_all_keysigs( keyblock, count_selected_uids(keyblock) );
1128             break;
1129
1130           case cmdSIGN: /* sign (only the public key) */
1131           case cmdLSIGN: /* sign (only the public key) */
1132           case cmdNRSIGN: /* sign (only the public key) */
1133           case cmdNRLSIGN: /* sign (only the public key) */
1134             if( pk->is_revoked )
1135               {
1136                 tty_printf(_("Key is revoked."));
1137
1138                 if(opt.expert)
1139                   {
1140                     tty_printf("  ");
1141                     if(!cpr_get_answer_is_yes("keyedit.sign_revoked.okay",
1142                                               _("Are you sure you still want "
1143                                                 "to sign it? (y/N) ")))
1144                       break;
1145                   }
1146                 else
1147                   {
1148                     tty_printf(_("  Unable to sign.\n"));
1149                     break;
1150                   }
1151               }
1152
1153             if( count_uids(keyblock) > 1 && !count_selected_uids(keyblock) ) {
1154                 if( !cpr_get_answer_is_yes("keyedit.sign_all.okay",
1155                                            _("Really sign all user IDs? ")) ) {
1156                     tty_printf(_("Hint: Select the user IDs to sign\n"));
1157                     break;
1158                 }
1159             }
1160             if( !sign_uids( keyblock, locusr, &modified,
1161                             (cmd == cmdLSIGN) || (cmd == cmdNRLSIGN),
1162                             (cmd == cmdNRSIGN) || (cmd==cmdNRLSIGN))
1163                 && sign_mode )
1164                 goto do_cmd_save;
1165             break;
1166
1167           case cmdDEBUG:
1168             dump_kbnode( cur_keyblock );
1169             break;
1170
1171           case cmdTOGGLE:
1172             toggle = !toggle;
1173             cur_keyblock = toggle? sec_keyblock : keyblock;
1174             redisplay = 1;
1175             break;
1176
1177           case cmdADDPHOTO:
1178             if (opt.rfc2440 || opt.rfc1991 || opt.pgp2)
1179               {
1180                 tty_printf(
1181                    _("This command is not allowed while in %s mode.\n"),
1182                    opt.rfc2440?"OpenPGP":opt.pgp2?"PGP2":"RFC-1991");
1183                 break;
1184               }
1185             photo=1;
1186             /* fall through */
1187
1188           case cmdADDUID:
1189             if( menu_adduid( keyblock, sec_keyblock, photo ) ) {
1190                 redisplay = 1;
1191                 sec_modified = modified = 1;
1192                 merge_keys_and_selfsig( sec_keyblock );
1193                 merge_keys_and_selfsig( keyblock );
1194             }
1195             break;
1196
1197           case cmdDELUID: {
1198                 int n1;
1199
1200                 if( !(n1=count_selected_uids(keyblock)) )
1201                     tty_printf(_("You must select at least one user ID.\n"));
1202                 else if( real_uids_left(keyblock) < 1 )
1203                     tty_printf(_("You can't delete the last user ID!\n"));
1204                 else if( cpr_get_answer_is_yes(
1205                             "keyedit.remove.uid.okay",
1206                         n1 > 1? _("Really remove all selected user IDs? ")
1207                               : _("Really remove this user ID? ")
1208                        ) ) {
1209                     menu_deluid( keyblock, sec_keyblock );
1210                     redisplay = 1;
1211                     modified = 1;
1212                     if( sec_keyblock )
1213                        sec_modified = 1;
1214                 }
1215             }
1216             break;
1217
1218           case cmdDELSIG: {
1219                 int n1;
1220
1221                 if( !(n1=count_selected_uids(keyblock)) )
1222                     tty_printf(_("You must select at least one user ID.\n"));
1223                 else if( menu_delsig( keyblock ) ) {
1224                     /* no redisplay here, because it may scroll away some
1225                      * status output of delsig */
1226                     modified = 1;
1227                 }
1228             }
1229             break;
1230
1231           case cmdADDKEY:
1232             if( generate_subkeypair( keyblock, sec_keyblock ) ) {
1233                 redisplay = 1;
1234                 sec_modified = modified = 1;
1235                 merge_keys_and_selfsig( sec_keyblock );
1236                 merge_keys_and_selfsig( keyblock );
1237             }
1238             break;
1239
1240
1241           case cmdDELKEY: {
1242                 int n1;
1243
1244                 if( !(n1=count_selected_keys( keyblock )) )
1245                     tty_printf(_("You must select at least one key.\n"));
1246                 else if( sec_keyblock && !cpr_get_answer_is_yes(
1247                             "keyedit.remove.subkey.okay",
1248                        n1 > 1?
1249                         _("Do you really want to delete the selected keys? "):
1250                         _("Do you really want to delete this key? ")
1251                        ))
1252                     ;
1253                 else {
1254                     menu_delkey( keyblock, sec_keyblock );
1255                     redisplay = 1;
1256                     modified = 1;
1257                     if( sec_keyblock )
1258                        sec_modified = 1;
1259                 }
1260             }
1261             break;
1262
1263           case cmdADDREVOKER:
1264             {
1265               int sensitive=0;
1266
1267               if(arg_string && ascii_strcasecmp(arg_string,"sensitive")==0)
1268                 sensitive=1;
1269               if( menu_addrevoker( keyblock, sec_keyblock, sensitive ) ) {
1270                 redisplay = 1;
1271                 sec_modified = modified = 1;
1272                 merge_keys_and_selfsig( sec_keyblock );
1273                 merge_keys_and_selfsig( keyblock );
1274               }
1275             }
1276             break;
1277
1278           case cmdREVKEY: {
1279                 int n1;
1280
1281                 if( !(n1=count_selected_keys( keyblock )) )
1282                     tty_printf(_("You must select at least one key.\n"));
1283                 else if( sec_keyblock && !cpr_get_answer_is_yes(
1284                             "keyedit.revoke.subkey.okay",
1285                        n1 > 1?
1286                         _("Do you really want to revoke the selected keys? "):
1287                         _("Do you really want to revoke this key? ")
1288                        ))
1289                     ;
1290                 else {
1291                     if( menu_revkey( keyblock, sec_keyblock ) ) {
1292                         modified = 1;
1293                         /*sec_modified = 1;*/
1294                     }
1295                     redisplay = 1;
1296                 }
1297             }
1298             break;
1299
1300           case cmdEXPIRE:
1301             if( menu_expire( keyblock, sec_keyblock ) ) {
1302                 merge_keys_and_selfsig( sec_keyblock );
1303                 merge_keys_and_selfsig( keyblock );
1304                 sec_modified = 1;
1305                 modified = 1;
1306                 redisplay = 1;
1307             }
1308             break;
1309
1310           case cmdPRIMARY:
1311             if( menu_set_primary_uid ( keyblock, sec_keyblock ) ) {
1312                 merge_keys_and_selfsig( keyblock );
1313                 modified = 1;
1314                 redisplay = 1;
1315             }
1316             break;
1317
1318           case cmdPASSWD:
1319             if( change_passphrase( sec_keyblock ) )
1320                 sec_modified = 1;
1321             break;
1322
1323           case cmdTRUST:
1324             show_key_with_all_names( keyblock, 0, 0, 0, 1, 0 );
1325             tty_printf("\n");
1326             if( edit_ownertrust( find_kbnode( keyblock,
1327                                  PKT_PUBLIC_KEY )->pkt->pkt.public_key, 1 ) ) {
1328                 redisplay = 1;
1329                 /* No real need to set update_trust here as
1330                    edit_ownertrust() calls revalidation_mark()
1331                    anyway. */
1332                 update_trust=1;
1333             }
1334             break;
1335
1336           case cmdPREF:
1337             show_key_with_all_names( keyblock, 0, 0, 0, 0, 1 );
1338             break;
1339
1340           case cmdSHOWPREF:
1341             show_key_with_all_names( keyblock, 0, 0, 0, 0, 2 );
1342             break;
1343
1344           case cmdSETPREF:
1345             keygen_set_std_prefs ( !*arg_string? "default" : arg_string, 0);
1346             break;
1347
1348           case cmdUPDPREF: 
1349             {
1350                 p = keygen_get_std_prefs ();
1351                 tty_printf (("Current preference list: %s\n"), p);
1352                 m_free (p);
1353             }
1354             if (cpr_get_answer_is_yes ("keyedit.updpref.okay",
1355                                         count_selected_uids (keyblock)?
1356                                         _("Really update the preferences"
1357                                           " for the selected user IDs? "):
1358                                        _("Really update the preferences? "))){
1359
1360                 if ( menu_set_preferences (keyblock, sec_keyblock) ) {
1361                     merge_keys_and_selfsig (keyblock);
1362                     modified = 1;
1363                     redisplay = 1;
1364                 }
1365             }
1366             break;
1367
1368           case cmdNOP:
1369             break;
1370
1371           case cmdREVSIG:
1372             if( menu_revsig( keyblock ) ) {
1373                 redisplay = 1;
1374                 modified = 1;
1375             }
1376             break;
1377
1378           case cmdENABLEKEY:
1379           case cmdDISABLEKEY:
1380             if( enable_disable_key( keyblock, cmd == cmdDISABLEKEY ) ) {
1381                 redisplay = 1;
1382                 modified = 1;
1383             }
1384             break;
1385
1386          case cmdSHOWPHOTO:
1387            menu_showphoto(keyblock);
1388            break;
1389
1390           case cmdQUIT:
1391             if( have_commands )
1392                 goto leave;
1393             if( !modified && !sec_modified )
1394                 goto leave;
1395             if( !cpr_get_answer_is_yes("keyedit.save.okay",
1396                                         _("Save changes? ")) ) {
1397                 if( cpr_enabled()
1398                     || cpr_get_answer_is_yes("keyedit.cancel.okay",
1399                                              _("Quit without saving? ")) )
1400                     goto leave;
1401                 break;
1402             }
1403             /* fall thru */
1404           case cmdSAVE:
1405           do_cmd_save:
1406             if( modified || sec_modified  ) {
1407                 if( modified ) {
1408                     rc = keydb_update_keyblock (kdbhd, keyblock);
1409                     if( rc ) {
1410                         log_error(_("update failed: %s\n"), g10_errstr(rc) );
1411                         break;
1412                     }
1413                 }
1414                 if( sec_modified ) {
1415                     rc = keydb_update_keyblock (sec_kdbhd, sec_keyblock );
1416                     if( rc ) {
1417                         log_error( _("update secret failed: %s\n"),
1418                                    g10_errstr(rc) );
1419                         break;
1420                     }
1421                 }
1422             }
1423             else
1424                 tty_printf(_("Key not changed so no update needed.\n"));
1425
1426             if( update_trust )
1427               {
1428                 revalidation_mark ();
1429                 update_trust=0;
1430               }
1431             goto leave;
1432
1433           case cmdINVCMD:
1434           default:
1435             tty_printf("\n");
1436             tty_printf(_("Invalid command  (try \"help\")\n"));
1437             break;
1438         }
1439     } /* end main loop */
1440
1441   leave:
1442     release_kbnode( keyblock );
1443     release_kbnode( sec_keyblock );
1444     keydb_release (kdbhd);
1445     m_free(answer);
1446 }
1447
1448
1449 /****************
1450  * show preferences of a public keyblock.
1451  */
1452 static void
1453 show_prefs (PKT_user_id *uid, int verbose)
1454 {
1455     const prefitem_t fake={0,0};
1456     const prefitem_t *prefs;
1457     int i;
1458
1459     if( !uid )
1460         return;
1461
1462     if( uid->prefs )
1463         prefs=uid->prefs;
1464     else if(verbose)
1465         prefs=&fake;
1466     else
1467       return;
1468
1469     if (verbose) {
1470         int any, des_seen=0, sha1_seen=0, uncomp_seen=0;
1471         tty_printf ("     Cipher: ");
1472         for(i=any=0; prefs[i].type; i++ ) {
1473             if( prefs[i].type == PREFTYPE_SYM ) {
1474                 const char *s = cipher_algo_to_string (prefs[i].value);
1475                 
1476                 if (any)
1477                     tty_printf (", ");
1478                 any = 1;
1479                 /* We don't want to display strings for experimental algos */
1480                 if (s && prefs[i].value < 100 )
1481                     tty_printf ("%s", s );
1482                 else
1483                     tty_printf ("[%d]", prefs[i].value);
1484                 if (prefs[i].value == CIPHER_ALGO_3DES )
1485                     des_seen = 1;
1486             }    
1487         }
1488         if (!des_seen) {
1489             if (any)
1490                 tty_printf (", ");
1491             tty_printf ("%s",cipher_algo_to_string(CIPHER_ALGO_3DES));
1492         }
1493         tty_printf ("\n     Hash: ");
1494         for(i=any=0; prefs[i].type; i++ ) {
1495             if( prefs[i].type == PREFTYPE_HASH ) {
1496                 const char *s = digest_algo_to_string (prefs[i].value);
1497                 
1498                 if (any)
1499                     tty_printf (", ");
1500                 any = 1;
1501                 /* We don't want to display strings for experimental algos */
1502                 if (s && prefs[i].value < 100 )
1503                     tty_printf ("%s", s );
1504                 else
1505                     tty_printf ("[%d]", prefs[i].value);
1506                 if (prefs[i].value == DIGEST_ALGO_SHA1 )
1507                     sha1_seen = 1;
1508             }
1509         }
1510         if (!sha1_seen) {
1511             if (any)
1512                 tty_printf (", ");
1513             tty_printf ("%s",digest_algo_to_string(DIGEST_ALGO_SHA1));
1514         }
1515         tty_printf ("\n     Compression: ");
1516         for(i=any=0; prefs[i].type; i++ ) {
1517             if( prefs[i].type == PREFTYPE_ZIP ) {
1518                 const char *s=compress_algo_to_string(prefs[i].value);
1519                 
1520                 if (any)
1521                     tty_printf (", ");
1522                 any = 1;
1523                 /* We don't want to display strings for experimental algos */
1524                 if (s && prefs[i].value < 100 )
1525                     tty_printf ("%s", s );
1526                 else
1527                     tty_printf ("[%d]", prefs[i].value);
1528                 if (prefs[i].value == 0 )
1529                     uncomp_seen = 1;
1530             }
1531         }
1532         if (!uncomp_seen) {
1533             if (any)
1534                 tty_printf (", ");
1535             else {
1536               tty_printf ("%s",compress_algo_to_string(1));
1537               tty_printf (", ");
1538             }
1539             tty_printf ("%s",compress_algo_to_string(0));
1540         }
1541         tty_printf ("\n     Features: ");
1542         if(uid->mdc_feature)
1543           tty_printf ("MDC");
1544         tty_printf("\n");
1545     }
1546     else {
1547         tty_printf("    ");
1548         for(i=0; prefs[i].type; i++ ) {
1549             tty_printf( " %c%d", prefs[i].type == PREFTYPE_SYM   ? 'S' :
1550                                  prefs[i].type == PREFTYPE_HASH  ? 'H' :
1551                                  prefs[i].type == PREFTYPE_ZIP ? 'Z':'?',
1552                                  prefs[i].value);
1553         }
1554         if (uid->mdc_feature)
1555             tty_printf (" [mdc]");
1556         tty_printf("\n");
1557     }
1558 }
1559
1560
1561 /* This is the version of show_key_with_all_names used when
1562    opt.with_colons is used.  It prints all available data in a easy to
1563    parse format and does not translate utf8 */
1564 static void
1565 show_key_with_all_names_colon (KBNODE keyblock)
1566 {
1567   KBNODE node;
1568   int i, j;
1569   byte pk_version=0;
1570
1571   /* the keys */
1572   for ( node = keyblock; node; node = node->next )
1573     {
1574       if (node->pkt->pkttype == PKT_PUBLIC_KEY
1575           || (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) )
1576         {
1577           PKT_public_key *pk = node->pkt->pkt.public_key;
1578           int otrust=0, trust=0;
1579           u32 keyid[2];
1580
1581           if (node->pkt->pkttype == PKT_PUBLIC_KEY)
1582             {
1583               trust = get_validity_info (pk, NULL);
1584               otrust = get_ownertrust_info (pk);
1585               pk_version = pk->version;
1586             }
1587
1588           keyid_from_pk (pk, keyid);
1589
1590           fputs (node->pkt->pkttype == PKT_PUBLIC_KEY?"pub:":"sub:", stdout);
1591           if (!pk->is_valid)
1592             putchar ('i');
1593           else if (pk->is_revoked)
1594             putchar ('r');
1595           else if (pk->has_expired)
1596             putchar ('e');
1597           else 
1598             putchar (trust);
1599           printf (":%u:%d:%08lX%08lX:%lu:%lu:",
1600                   nbits_from_pk (pk),
1601                   pk->pubkey_algo,
1602                   (ulong)keyid[0], (ulong)keyid[1],
1603                   (ulong)pk->timestamp,
1604                   (ulong)pk->expiredate );
1605           if (pk->local_id)
1606             printf ("%lu", pk->local_id);
1607           putchar (':');
1608           putchar (otrust);
1609           putchar(':');
1610           putchar('\n');
1611           
1612           print_fingerprint (pk, NULL, 0);
1613
1614           /* print the revoker record */
1615           if( !pk->revkey && pk->numrevkeys )
1616             BUG();
1617           else
1618             {
1619               for (i=0; i < pk->numrevkeys; i++)
1620                 {
1621                   byte *p;
1622
1623                   printf ("rvk:::%d::::::", pk->revkey[i].algid);
1624                   p = pk->revkey[i].fpr;
1625                   for (j=0; j < 20; j++, p++ )
1626                     printf ("%02X", *p);
1627                   printf (":%02x%s:\n", pk->revkey[i].class,
1628                           (pk->revkey[i].class&0x40)?"s":"");
1629                 }
1630             }
1631         }
1632     }
1633   
1634     /* the user ids */
1635     i = 0;
1636     for (node = keyblock; node; node = node->next) 
1637       {
1638         if ( node->pkt->pkttype == PKT_USER_ID )
1639           {
1640             PKT_user_id *uid = node->pkt->pkt.user_id;
1641             int trustletter = '?';
1642
1643             ++i;
1644             if(uid->attrib_data)
1645               {
1646                 printf ("uat:%c::::::::%u %lu", trustletter,
1647                         uid->numattribs,uid->attrib_len);
1648               }
1649             else
1650               {
1651                 printf ("uid:%c::::::::", trustletter);
1652                 print_string (stdout, uid->name, uid->len, ':');
1653               }
1654             putchar (':');
1655             /* signature class */
1656             putchar (':');
1657             /* capabilities */
1658             putchar (':');
1659             /* preferences */
1660             if (pk_version>3 || uid->selfsigversion>3)
1661               {
1662                 const prefitem_t *prefs = uid->prefs;
1663                 
1664                 for (j=0; prefs && prefs[j].type; j++)
1665                   {
1666                     if (j)
1667                       putchar (' ');
1668                     printf ("%c%d", prefs[j].type == PREFTYPE_SYM   ? 'S' :
1669                             prefs[j].type == PREFTYPE_HASH  ? 'H' :
1670                             prefs[j].type == PREFTYPE_ZIP ? 'Z':'?',
1671                             prefs[j].value);
1672                   } 
1673                 if (uid->mdc_feature)
1674                   printf (",mdc");
1675               } 
1676             putchar (':');
1677             /* flags */
1678             printf ("%d,", i);
1679             if (uid->is_primary)
1680               putchar ('p');
1681             if (uid->is_revoked)
1682               putchar ('r');
1683             if (uid->is_expired)
1684               putchar ('e');
1685             if ((node->flag & NODFLG_SELUID))
1686               putchar ('s');
1687             if ((node->flag & NODFLG_MARK_A))
1688               putchar ('m');
1689             putchar (':');
1690             putchar('\n');
1691           }
1692       }
1693 }
1694
1695
1696 /****************
1697  * Display the key a the user ids, if only_marked is true, do only
1698  * so for user ids with mark A flag set and dont display the index number
1699  */
1700 static void
1701 show_key_with_all_names( KBNODE keyblock, int only_marked, int with_revoker,
1702                          int with_fpr, int with_subkeys, int with_prefs )
1703 {
1704     KBNODE node;
1705     int i, rc;
1706     int do_warn = 0;
1707     byte pk_version=0;
1708
1709     if (opt.with_colons)
1710       {
1711         show_key_with_all_names_colon (keyblock);
1712         return;
1713       }
1714
1715     /* the keys */
1716     for( node = keyblock; node; node = node->next ) {
1717         if( node->pkt->pkttype == PKT_PUBLIC_KEY
1718             || (with_subkeys && node->pkt->pkttype == PKT_PUBLIC_SUBKEY) ) {
1719             PKT_public_key *pk = node->pkt->pkt.public_key;
1720             int otrust=0, trust=0;
1721
1722             if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
1723                 /* do it here, so that debug messages don't clutter the
1724                  * output */
1725                 static int did_warn = 0;
1726
1727                 trust = get_validity_info (pk, NULL);
1728                 otrust = get_ownertrust_info (pk);
1729
1730                 /* Show a warning once */
1731                 if (!did_warn
1732                     && (get_validity (pk, NULL) & TRUST_FLAG_PENDING_CHECK)) {
1733                     did_warn = 1;
1734                     do_warn = 1;
1735                 }
1736
1737                 pk_version=pk->version;
1738             }
1739
1740             if(with_revoker) {
1741                 if( !pk->revkey && pk->numrevkeys )
1742                     BUG();
1743                 else
1744                     for(i=0;i<pk->numrevkeys;i++) {
1745                         u32 r_keyid[2];
1746                         char *user;
1747            
1748                         keyid_from_fingerprint(pk->revkey[i].fpr,
1749                                                MAX_FINGERPRINT_LEN,r_keyid);
1750                         
1751                         user=get_user_id_string (r_keyid);
1752                         tty_printf (_("This key may be revoked by %s key "),
1753                                  pubkey_algo_to_string (pk->revkey[i].algid));
1754                         tty_print_utf8_string (user, strlen (user));
1755                         if ((pk->revkey[i].class&0x40))
1756                           tty_printf (_(" (sensitive)"));
1757                         tty_printf ("\n");
1758                         m_free(user);
1759                       }
1760             }
1761
1762             tty_printf(_("%s%c %4u%c/%08lX  created: %s expires: %s"),
1763                           node->pkt->pkttype == PKT_PUBLIC_KEY? "pub":"sub",
1764                           (node->flag & NODFLG_SELKEY)? '*':' ',
1765                           nbits_from_pk( pk ),
1766                           pubkey_letter( pk->pubkey_algo ),
1767                           (ulong)keyid_from_pk(pk,NULL),
1768                           datestr_from_pk(pk),
1769                           expirestr_from_pk(pk) );
1770             if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
1771                 tty_printf(_(" trust: %c/%c"), otrust, trust );
1772                 if( node->pkt->pkttype == PKT_PUBLIC_KEY
1773                     && (get_ownertrust (pk)&TRUST_FLAG_DISABLED)) {
1774                     tty_printf("\n*** ");
1775                     tty_printf(_("This key has been disabled"));
1776                 }
1777
1778                 if( with_fpr  ) {
1779                     tty_printf("\n");
1780                     print_fingerprint ( pk, NULL, 2 );
1781                 }
1782             }
1783             tty_printf("\n");
1784         }
1785         else if( node->pkt->pkttype == PKT_SECRET_KEY
1786             || (with_subkeys && node->pkt->pkttype == PKT_SECRET_SUBKEY) ) {
1787             PKT_secret_key *sk = node->pkt->pkt.secret_key;
1788             tty_printf(_("%s%c %4u%c/%08lX  created: %s expires: %s"),
1789                           node->pkt->pkttype == PKT_SECRET_KEY? "sec":"ssb",
1790                           (node->flag & NODFLG_SELKEY)? '*':' ',
1791                           nbits_from_sk( sk ),
1792                           pubkey_letter( sk->pubkey_algo ),
1793                           (ulong)keyid_from_sk(sk,NULL),
1794                           datestr_from_sk(sk),
1795                           expirestr_from_sk(sk) );
1796             tty_printf("\n");
1797         }
1798         else if( with_subkeys && node->pkt->pkttype == PKT_SIGNATURE
1799                  && node->pkt->pkt.signature->sig_class == 0x28       ) {
1800             PKT_signature *sig = node->pkt->pkt.signature;
1801
1802             rc = check_key_signature( keyblock, node, NULL );
1803             if( !rc )
1804                 tty_printf( _("rev! subkey has been revoked: %s\n"),
1805                             datestr_from_sig( sig ) );
1806             else if( rc == G10ERR_BAD_SIGN )
1807                 tty_printf( _("rev- faked revocation found\n") );
1808             else if( rc )
1809                 tty_printf( _("rev? problem checking revocation: %s\n"),
1810                                                          g10_errstr(rc) );
1811         }
1812     }
1813     /* the user ids */
1814     i = 0;
1815     for( node = keyblock; node; node = node->next ) {
1816         if( node->pkt->pkttype == PKT_USER_ID ) {
1817             PKT_user_id *uid = node->pkt->pkt.user_id;
1818             ++i;
1819             if( !only_marked || (only_marked && (node->flag & NODFLG_MARK_A))){
1820                 if( only_marked )
1821                    tty_printf("     ");
1822                 else if( node->flag & NODFLG_SELUID )
1823                    tty_printf("(%d)* ", i);
1824                 else if( uid->is_primary )
1825                    tty_printf("(%d). ", i);
1826                 else
1827                    tty_printf("(%d)  ", i);
1828                 if ( uid->is_revoked )
1829                     tty_printf ("[revoked] ");
1830                 if ( uid->is_expired )
1831                     tty_printf ("[expired] ");
1832                 tty_print_utf8_string( uid->name, uid->len );
1833                 tty_printf("\n");
1834                 if( with_prefs )
1835                   {
1836                     if(pk_version>3 || uid->selfsigversion>3)
1837                       show_prefs (uid, with_prefs == 2);
1838                     else
1839                       tty_printf(_("There are no preferences on a "
1840                                    "PGP 2.x-style user ID.\n"));
1841                   }
1842             }
1843         }
1844     }
1845
1846     if (do_warn)
1847         tty_printf (_("Please note that the shown key validity "
1848                       "is not necessarily correct\n"
1849                       "unless you restart the program.\n")); 
1850
1851 }
1852
1853
1854 /* Display basic key information.  This fucntion is suitable to show
1855    information on the key without any dependencies on the trustdb or
1856    any other internal GnuPG stuff.  KEYBLOCK may either be a public or
1857    a secret key.*/
1858 void
1859 show_basic_key_info ( KBNODE keyblock )
1860 {
1861   KBNODE node;
1862   int i;
1863
1864   /* The primary key */
1865   for (node = keyblock; node; node = node->next)
1866     {
1867       if (node->pkt->pkttype == PKT_PUBLIC_KEY)
1868         {
1869           PKT_public_key *pk = node->pkt->pkt.public_key;
1870           
1871           /* Note, we use the same format string as in other show
1872              functions to make the translation job easier. */
1873           tty_printf (_("%s%c %4u%c/%08lX  created: %s expires: %s"),
1874                       node->pkt->pkttype == PKT_PUBLIC_KEY? "pub":"sub",
1875                       ' ',
1876                       nbits_from_pk( pk ),
1877                       pubkey_letter( pk->pubkey_algo ),
1878                       (ulong)keyid_from_pk(pk,NULL),
1879                       datestr_from_pk(pk),
1880                       expirestr_from_pk(pk) );
1881           tty_printf("\n");
1882           print_fingerprint ( pk, NULL, 3 );
1883           tty_printf("\n");
1884         }
1885       else if (node->pkt->pkttype == PKT_SECRET_KEY)
1886         {
1887           PKT_secret_key *sk = node->pkt->pkt.secret_key;
1888           tty_printf(_("%s%c %4u%c/%08lX  created: %s expires: %s"),
1889                      node->pkt->pkttype == PKT_SECRET_KEY? "sec":"ssb",
1890                      ' ',
1891                      nbits_from_sk( sk ),
1892                      pubkey_letter( sk->pubkey_algo ),
1893                      (ulong)keyid_from_sk(sk,NULL),
1894                      datestr_from_sk(sk),
1895                      expirestr_from_sk(sk) );
1896           tty_printf("\n");
1897           print_fingerprint (NULL, sk, 3 );
1898           tty_printf("\n");
1899         }
1900     }
1901
1902   /* The user IDs. */
1903   for (i=0, node = keyblock; node; node = node->next)
1904     {
1905       if (node->pkt->pkttype == PKT_USER_ID)
1906         {
1907           PKT_user_id *uid = node->pkt->pkt.user_id;
1908           ++i;
1909      
1910           tty_printf ("     ");
1911           if (uid->is_revoked)
1912             tty_printf ("[revoked] ");
1913           if ( uid->is_expired )
1914             tty_printf ("[expired] ");
1915           tty_print_utf8_string (uid->name, uid->len);
1916           tty_printf ("\n");
1917         }
1918     }
1919 }
1920
1921 static void
1922 show_key_and_fingerprint( KBNODE keyblock )
1923 {
1924     KBNODE node;
1925     PKT_public_key *pk = NULL;
1926
1927     for( node = keyblock; node; node = node->next ) {
1928         if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
1929             pk = node->pkt->pkt.public_key;
1930             tty_printf("pub   %4u%c/%08lX %s ",
1931                           nbits_from_pk( pk ),
1932                           pubkey_letter( pk->pubkey_algo ),
1933                           (ulong)keyid_from_pk(pk,NULL),
1934                           datestr_from_pk(pk) );
1935         }
1936         else if( node->pkt->pkttype == PKT_USER_ID ) {
1937             PKT_user_id *uid = node->pkt->pkt.user_id;
1938             tty_print_utf8_string( uid->name, uid->len );
1939             break;
1940         }
1941     }
1942     tty_printf("\n");
1943     if( pk )
1944         print_fingerprint( pk, NULL, 2 );
1945 }
1946
1947
1948
1949 /****************
1950  * Ask for a new user id, do the selfsignature and put it into
1951  * both keyblocks.
1952  * Return true if there is a new user id
1953  */
1954 static int
1955 menu_adduid( KBNODE pub_keyblock, KBNODE sec_keyblock, int photo)
1956 {
1957     PKT_user_id *uid;
1958     PKT_public_key *pk=NULL;
1959     PKT_secret_key *sk=NULL;
1960     PKT_signature *sig=NULL;
1961     PACKET *pkt;
1962     KBNODE node;
1963     KBNODE pub_where=NULL, sec_where=NULL;
1964     int rc;
1965
1966     for( node = pub_keyblock; node; pub_where = node, node = node->next ) {
1967         if( node->pkt->pkttype == PKT_PUBLIC_KEY )
1968             pk = node->pkt->pkt.public_key;
1969         else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
1970             break;
1971     }
1972     if( !node ) /* no subkey */
1973         pub_where = NULL;
1974     for( node = sec_keyblock; node; sec_where = node, node = node->next ) {
1975         if( node->pkt->pkttype == PKT_SECRET_KEY )
1976             sk = copy_secret_key( NULL, node->pkt->pkt.secret_key);
1977         else if( node->pkt->pkttype == PKT_SECRET_SUBKEY )
1978             break;
1979     }
1980     if( !node ) /* no subkey */
1981         sec_where = NULL;
1982     assert(pk && sk);
1983
1984     if(photo) {
1985       int hasattrib=0;
1986
1987       for( node = pub_keyblock; node; node = node->next )
1988         if( node->pkt->pkttype == PKT_USER_ID &&
1989             node->pkt->pkt.user_id->attrib_data!=NULL)
1990           {
1991             hasattrib=1;
1992             break;
1993           }
1994
1995       /* It is legal but bad for compatibility to add a photo ID to a
1996          v3 key as it means that PGP2 will not be able to use that key
1997          anymore.  Also, PGP may not expect a photo on a v3 key.
1998          Don't bother to ask this if the key already has a photo - any
1999          damage has already been done at that point. -dms */
2000       if(pk->version==3 && !hasattrib)
2001         {
2002           if(opt.expert)
2003             {
2004               tty_printf(_("WARNING: This is a PGP2-style key.  "
2005                            "Adding a photo ID may cause some versions\n"
2006                            "         of PGP to reject this key.\n"));
2007
2008               if(!cpr_get_answer_is_yes("keyedit.v3_photo.okay",
2009                                         _("Are you sure you still want "
2010                                           "to add it? (y/N) ")))
2011                 return 0;
2012             }
2013           else
2014             {
2015               tty_printf(_("You may not add a photo ID to "
2016                            "a PGP2-style key.\n"));
2017               return 0;
2018             }
2019         }
2020
2021       uid = generate_photo_id(pk);
2022     } else
2023       uid = generate_user_id();
2024     if( !uid )
2025         return 0;
2026
2027     rc = make_keysig_packet( &sig, pk, uid, NULL, sk, 0x13, 0, 0, 0, 0,
2028                              keygen_add_std_prefs, pk );
2029     free_secret_key( sk );
2030     if( rc ) {
2031         log_error("signing failed: %s\n", g10_errstr(rc) );
2032         free_user_id(uid);
2033         return 0;
2034     }
2035
2036     /* insert/append to secret keyblock */
2037     pkt = m_alloc_clear( sizeof *pkt );
2038     pkt->pkttype = PKT_USER_ID;
2039     pkt->pkt.user_id = scopy_user_id(uid);
2040     node = new_kbnode(pkt);
2041     if( sec_where )
2042         insert_kbnode( sec_where, node, 0 );
2043     else
2044         add_kbnode( sec_keyblock, node );
2045     pkt = m_alloc_clear( sizeof *pkt );
2046     pkt->pkttype = PKT_SIGNATURE;
2047     pkt->pkt.signature = copy_signature(NULL, sig);
2048     if( sec_where )
2049         insert_kbnode( node, new_kbnode(pkt), 0 );
2050     else
2051         add_kbnode( sec_keyblock, new_kbnode(pkt) );
2052     /* insert/append to public keyblock */
2053     pkt = m_alloc_clear( sizeof *pkt );
2054     pkt->pkttype = PKT_USER_ID;
2055     pkt->pkt.user_id = uid;
2056     node = new_kbnode(pkt);
2057     if( pub_where )
2058         insert_kbnode( pub_where, node, 0 );
2059     else
2060         add_kbnode( pub_keyblock, node );
2061     pkt = m_alloc_clear( sizeof *pkt );
2062     pkt->pkttype = PKT_SIGNATURE;
2063     pkt->pkt.signature = copy_signature(NULL, sig);
2064     if( pub_where )
2065         insert_kbnode( node, new_kbnode(pkt), 0 );
2066     else
2067         add_kbnode( pub_keyblock, new_kbnode(pkt) );
2068     return 1;
2069 }
2070
2071
2072 /****************
2073  * Remove all selceted userids from the keyrings
2074  */
2075 static void
2076 menu_deluid( KBNODE pub_keyblock, KBNODE sec_keyblock )
2077 {
2078     KBNODE node;
2079     int selected=0;
2080
2081     for( node = pub_keyblock; node; node = node->next ) {
2082         if( node->pkt->pkttype == PKT_USER_ID ) {
2083             selected = node->flag & NODFLG_SELUID;
2084             if( selected ) {
2085                 /* Only cause a trust update if we delete a
2086                    non-revoked user id */
2087                 if(!node->pkt->pkt.user_id->is_revoked)
2088                   update_trust=1;
2089                 delete_kbnode( node );
2090                 if( sec_keyblock ) {
2091                     KBNODE snode;
2092                     int s_selected = 0;
2093                     PKT_user_id *uid = node->pkt->pkt.user_id;
2094                     for( snode = sec_keyblock; snode; snode = snode->next ) {
2095                         if( snode->pkt->pkttype == PKT_USER_ID ) {
2096                             PKT_user_id *suid = snode->pkt->pkt.user_id;
2097
2098                             s_selected =
2099                                 (uid->len == suid->len
2100                                  && !memcmp( uid->name, suid->name, uid->len));
2101                             if( s_selected )
2102                                 delete_kbnode( snode );
2103                         }
2104                         else if( s_selected
2105                                  && snode->pkt->pkttype == PKT_SIGNATURE )
2106                             delete_kbnode( snode );
2107                         else if( snode->pkt->pkttype == PKT_SECRET_SUBKEY )
2108                             s_selected = 0;
2109                     }
2110                 }
2111             }
2112         }
2113         else if( selected && node->pkt->pkttype == PKT_SIGNATURE )
2114             delete_kbnode( node );
2115         else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
2116             selected = 0;
2117     }
2118     commit_kbnode( &pub_keyblock );
2119     if( sec_keyblock )
2120         commit_kbnode( &sec_keyblock );
2121 }
2122
2123
2124 static int
2125 menu_delsig( KBNODE pub_keyblock )
2126 {
2127     KBNODE node;
2128     PKT_user_id *uid = NULL;
2129     int changed=0;
2130
2131     for( node = pub_keyblock; node; node = node->next ) {
2132         if( node->pkt->pkttype == PKT_USER_ID ) {
2133             uid = (node->flag & NODFLG_SELUID)? node->pkt->pkt.user_id : NULL;
2134         }
2135         else if( uid && node->pkt->pkttype == PKT_SIGNATURE ) {
2136            int okay, valid, selfsig, inv_sig, no_key, other_err;
2137
2138             tty_printf("uid  ");
2139             tty_print_utf8_string( uid->name, uid->len );
2140             tty_printf("\n");
2141
2142            okay = inv_sig = no_key = other_err = 0;
2143             valid = print_and_check_one_sig( pub_keyblock, node,
2144                                             &inv_sig, &no_key, &other_err,
2145                                             &selfsig, 1 );
2146
2147            if( valid ) {
2148                okay = cpr_get_answer_yes_no_quit(
2149                    "keyedit.delsig.valid",
2150                    _("Delete this good signature? (y/N/q)"));
2151
2152                /* Only update trust if we delete a good signature.
2153                   The other two cases do not affect trust. */
2154                if(okay)
2155                  update_trust=1;
2156            }
2157            else if( inv_sig || other_err )
2158                okay = cpr_get_answer_yes_no_quit(
2159                    "keyedit.delsig.invalid",
2160                    _("Delete this invalid signature? (y/N/q)"));
2161            else if( no_key )
2162                okay = cpr_get_answer_yes_no_quit(
2163                    "keyedit.delsig.unknown",
2164                    _("Delete this unknown signature? (y/N/q)"));
2165
2166             if( okay == -1 )
2167                 break;
2168            if( okay && selfsig && !cpr_get_answer_is_yes(
2169                                "keyedit.delsig.selfsig",
2170                               _("Really delete this self-signature? (y/N)") ))
2171                 okay = 0;
2172             if( okay ) {
2173                 delete_kbnode( node );
2174                 changed++;
2175             }
2176
2177         }
2178         else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
2179             uid = NULL;
2180     }
2181
2182     if( changed ) {
2183         commit_kbnode( &pub_keyblock );
2184         tty_printf( changed == 1? _("Deleted %d signature.\n")
2185                                 : _("Deleted %d signatures.\n"), changed );
2186     }
2187     else
2188         tty_printf( _("Nothing deleted.\n") );
2189
2190     return changed;
2191 }
2192
2193
2194 /****************
2195  * Remove some of the secondary keys
2196  */
2197 static void
2198 menu_delkey( KBNODE pub_keyblock, KBNODE sec_keyblock )
2199 {
2200     KBNODE node;
2201     int selected=0;
2202
2203     for( node = pub_keyblock; node; node = node->next ) {
2204         if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
2205             selected = node->flag & NODFLG_SELKEY;
2206             if( selected ) {
2207                 delete_kbnode( node );
2208                 if( sec_keyblock ) {
2209                     KBNODE snode;
2210                     int s_selected = 0;
2211                     u32 ki[2];
2212
2213                     keyid_from_pk( node->pkt->pkt.public_key, ki );
2214                     for( snode = sec_keyblock; snode; snode = snode->next ) {
2215                         if( snode->pkt->pkttype == PKT_SECRET_SUBKEY ) {
2216                             u32 ki2[2];
2217
2218                             keyid_from_sk( snode->pkt->pkt.secret_key, ki2 );
2219                             s_selected = (ki[0] == ki2[0] && ki[1] == ki2[1]);
2220                             if( s_selected )
2221                                 delete_kbnode( snode );
2222                         }
2223                         else if( s_selected
2224                                  && snode->pkt->pkttype == PKT_SIGNATURE )
2225                             delete_kbnode( snode );
2226                         else
2227                             s_selected = 0;
2228                     }
2229                 }
2230             }
2231         }
2232         else if( selected && node->pkt->pkttype == PKT_SIGNATURE )
2233             delete_kbnode( node );
2234         else
2235             selected = 0;
2236     }
2237     commit_kbnode( &pub_keyblock );
2238     if( sec_keyblock )
2239         commit_kbnode( &sec_keyblock );
2240
2241     /* No need to set update_trust here since signing keys no longer
2242        are used to certify other keys, so there is no change in trust
2243        when revoking/removing them */
2244 }
2245
2246
2247 /****************
2248  * Ask for a new revoker, do the selfsignature and put it into
2249  * both keyblocks.
2250  * Return true if there is a new revoker
2251  */
2252 static int
2253 menu_addrevoker( KBNODE pub_keyblock, KBNODE sec_keyblock, int sensitive )
2254 {
2255   PKT_public_key *pk=NULL,*revoker_pk=NULL;
2256   PKT_secret_key *sk=NULL;
2257   PKT_signature *sig=NULL;
2258   PACKET *pkt;
2259   struct revocation_key revkey;
2260   size_t fprlen;
2261   int rc;
2262
2263   assert(pub_keyblock->pkt->pkttype==PKT_PUBLIC_KEY);
2264   assert(sec_keyblock->pkt->pkttype==PKT_SECRET_KEY);
2265
2266   pk=pub_keyblock->pkt->pkt.public_key;
2267
2268   if(pk->numrevkeys==0 && pk->version==3)
2269     {
2270       /* It is legal but bad for compatibility to add a revoker to a
2271          v3 key as it means that PGP2 will not be able to use that key
2272          anymore.  Also, PGP may not expect a revoker on a v3 key.
2273          Don't bother to ask this if the key already has a revoker -
2274          any damage has already been done at that point. -dms */
2275       if(opt.expert)
2276         {
2277           tty_printf(_("WARNING: This is a PGP 2.x-style key.  "
2278                        "Adding a designated revoker may cause\n"
2279                        "         some versions of PGP to reject this key.\n"));
2280
2281           if(!cpr_get_answer_is_yes("keyedit.v3_revoker.okay",
2282                                     _("Are you sure you still want "
2283                                       "to add it? (y/N) ")))
2284             return 0;
2285         }
2286       else
2287         {
2288           tty_printf(_("You may not add a designated revoker to "
2289                        "a PGP 2.x-style key.\n"));
2290           return 0;
2291         }
2292     }
2293
2294   sk=copy_secret_key(NULL,sec_keyblock->pkt->pkt.secret_key);
2295
2296   for(;;)
2297     {
2298       char *answer;
2299       u32 keyid[2];
2300       char *p;
2301       size_t n;
2302
2303       if(revoker_pk)
2304         free_public_key(revoker_pk);
2305
2306       revoker_pk=m_alloc_clear(sizeof(*revoker_pk));
2307
2308       tty_printf("\n");
2309
2310       answer=cpr_get_utf8("keyedit.add_revoker",
2311                           _("Enter the user ID of the designated revoker: "));
2312       if(answer[0]=='\0' || answer[0]=='\004')
2313         goto fail;
2314
2315       rc=get_pubkey_byname(revoker_pk,answer,NULL,NULL);
2316
2317       if(rc)
2318         {
2319           log_error (_("key `%s' not found: %s\n"),answer,g10_errstr(rc));
2320           continue;
2321         }
2322
2323       fingerprint_from_pk(revoker_pk,revkey.fpr,&fprlen);
2324       if(fprlen!=20)
2325         {
2326           log_error(_("cannot appoint a PGP 2.x style key as a "
2327                       "designated revoker\n"));
2328           continue;
2329         }
2330
2331       revkey.class=0x80;
2332       if(sensitive)
2333         revkey.class|=0x40;
2334       revkey.algid=revoker_pk->pubkey_algo;
2335
2336       if(cmp_public_keys(revoker_pk,pk)==0)
2337         {
2338           /* This actually causes no harm (after all, a key that
2339              designates itself as a revoker is the same as a
2340              regular key), but it's easy enough to check. */
2341           log_error(_("you cannot appoint a key as its own "
2342                       "designated revoker\n"));
2343
2344           continue;
2345         }
2346
2347       keyid_from_pk(pk,NULL);
2348
2349       /* Does this revkey already exist? */
2350       if(!pk->revkey && pk->numrevkeys)
2351         BUG();
2352       else
2353         {
2354           int i;
2355
2356           for(i=0;i<pk->numrevkeys;i++)
2357             {
2358               if(memcmp(&pk->revkey[i],&revkey,
2359                         sizeof(struct revocation_key))==0)
2360                 {
2361                   char buf[50];
2362
2363                   log_error(_("this key has already been designated "
2364                               "as a revoker\n"));
2365
2366                   sprintf(buf,"%08lX%08lX",
2367                           (ulong)pk->keyid[0],(ulong)pk->keyid[1]);
2368                   write_status_text(STATUS_ALREADY_SIGNED,buf);
2369
2370                   break;
2371                 }
2372             }
2373
2374           if(i<pk->numrevkeys)
2375             continue;
2376         }
2377
2378       keyid_from_pk(revoker_pk,keyid);
2379
2380       tty_printf("\npub   %4u%c/%08lX %s   ",
2381                  nbits_from_pk( revoker_pk ),
2382                  pubkey_letter( revoker_pk->pubkey_algo ),
2383                  (ulong)keyid[1], datestr_from_pk(pk) );
2384
2385       p = get_user_id( keyid, &n );
2386       tty_print_utf8_string( p, n );
2387       m_free(p);
2388       tty_printf("\n");
2389       print_fingerprint(revoker_pk,NULL,2);
2390       tty_printf("\n");
2391
2392       tty_printf("WARNING: appointing a key as a designated revoker "
2393                  "cannot be undone!\n");
2394
2395       tty_printf("\n");
2396
2397       if(!cpr_get_answer_is_yes("keyedit.add_revoker.okay",
2398                                 "Are you sure you want to appoint this "
2399                                 "key as a designated revoker? (y/N): "))
2400         continue;
2401
2402       free_public_key(revoker_pk);
2403       revoker_pk=NULL;
2404       break;
2405     }
2406
2407   /* The 1F signature must be at least v4 to carry the revocation key
2408      subpacket. */
2409   rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 0x1F, 0, 4, 0, 0,
2410                            keygen_add_revkey,&revkey );
2411   if( rc )
2412     {
2413       log_error("signing failed: %s\n", g10_errstr(rc) );
2414       goto fail;
2415     }
2416
2417   free_secret_key(sk);
2418   sk=NULL;
2419
2420   /* insert into secret keyblock */
2421   pkt = m_alloc_clear( sizeof *pkt );
2422   pkt->pkttype = PKT_SIGNATURE;
2423   pkt->pkt.signature = copy_signature(NULL, sig);
2424   insert_kbnode( sec_keyblock, new_kbnode(pkt), PKT_SIGNATURE );
2425
2426   /* insert into public keyblock */
2427   pkt = m_alloc_clear( sizeof *pkt );
2428   pkt->pkttype = PKT_SIGNATURE;
2429   pkt->pkt.signature = sig;
2430   insert_kbnode( pub_keyblock, new_kbnode(pkt), PKT_SIGNATURE );
2431
2432   return 1;
2433
2434  fail:
2435   if(sk)
2436     free_secret_key(sk);
2437   if(sig)
2438     free_seckey_enc(sig);
2439   if(revoker_pk)
2440     free_public_key(revoker_pk);
2441
2442   return 0;
2443 }
2444
2445
2446 static int
2447 menu_expire( KBNODE pub_keyblock, KBNODE sec_keyblock )
2448 {
2449     int n1, signumber, rc;
2450     u32 expiredate;
2451     int mainkey=0;
2452     PKT_secret_key *sk;    /* copy of the main sk */
2453     PKT_public_key *main_pk, *sub_pk;
2454     PKT_user_id *uid;
2455     KBNODE node;
2456     u32 keyid[2];
2457
2458     if( count_selected_keys( sec_keyblock ) ) {
2459         tty_printf(_("Please remove selections from the secret keys.\n"));
2460         return 0;
2461     }
2462
2463     n1 = count_selected_keys( pub_keyblock );
2464     if( n1 > 1 ) {
2465         tty_printf(_("Please select at most one secondary key.\n"));
2466         return 0;
2467     }
2468     else if( n1 )
2469         tty_printf(_("Changing expiration time for a secondary key.\n"));
2470     else {
2471         tty_printf(_("Changing expiration time for the primary key.\n"));
2472         mainkey=1;
2473     }
2474
2475     expiredate = ask_expiredate();
2476     node = find_kbnode( sec_keyblock, PKT_SECRET_KEY );
2477     sk = copy_secret_key( NULL, node->pkt->pkt.secret_key);
2478
2479     /* Now we can actually change the self signature(s) */
2480     main_pk = sub_pk = NULL;
2481     uid = NULL;
2482     signumber = 0;
2483     for( node=pub_keyblock; node; node = node->next ) {
2484         if( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
2485             main_pk = node->pkt->pkt.public_key;
2486             keyid_from_pk( main_pk, keyid );
2487             main_pk->expiredate = expiredate;
2488         }
2489         else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
2490                  && (node->flag & NODFLG_SELKEY ) ) {
2491             sub_pk = node->pkt->pkt.public_key;
2492             sub_pk->expiredate = expiredate;
2493         }
2494         else if( node->pkt->pkttype == PKT_USER_ID )
2495             uid = node->pkt->pkt.user_id;
2496         else if( main_pk && node->pkt->pkttype == PKT_SIGNATURE
2497                  && ( mainkey || sub_pk ) ) {
2498             PKT_signature *sig = node->pkt->pkt.signature;
2499             if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1]
2500                 && (    (mainkey && uid && (sig->sig_class&~3) == 0x10)
2501                      || (!mainkey && sig->sig_class == 0x18)  ) ) {
2502                 /* this is a selfsignature which is to be replaced */
2503                 PKT_signature *newsig;
2504                 PACKET *newpkt;
2505                 KBNODE sn;
2506                 int signumber2 = 0;
2507
2508                 signumber++;
2509
2510                 if( (mainkey && main_pk->version < 4)
2511                     || (!mainkey && sub_pk->version < 4 ) ) {
2512                     log_info(_(
2513                         "You can't change the expiration date of a v3 key\n"));
2514                     free_secret_key( sk );
2515                     return 0;
2516                 }
2517
2518                 /* find the corresponding secret self-signature */
2519                 for( sn=sec_keyblock; sn; sn = sn->next ) {
2520                     if( sn->pkt->pkttype == PKT_SIGNATURE ) {
2521                         PKT_signature *b = sn->pkt->pkt.signature;
2522                         if( keyid[0] == b->keyid[0] && keyid[1] == b->keyid[1]
2523                             && sig->sig_class == b->sig_class
2524                             && ++signumber2 == signumber )
2525                             break;
2526                     }
2527                 }
2528                 if( !sn )
2529                     log_info(_("No corresponding signature in secret ring\n"));
2530
2531                 /* create new self signature */
2532                 if( mainkey )
2533                     rc = make_keysig_packet( &newsig, main_pk, uid, NULL,
2534                                              sk, 0x13, 0, 0, 0, 0,
2535                                              keygen_add_std_prefs, main_pk );
2536                 else
2537                     rc = make_keysig_packet( &newsig, main_pk, NULL, sub_pk,
2538                                              sk, 0x18, 0, 0, 0, 0,
2539                                              keygen_add_key_expire, sub_pk );
2540                 if( rc ) {
2541                     log_error("make_keysig_packet failed: %s\n",
2542                                                     g10_errstr(rc));
2543                     free_secret_key( sk );
2544                     return 0;
2545                 }
2546                 /* replace the packet */
2547                 newpkt = m_alloc_clear( sizeof *newpkt );
2548                 newpkt->pkttype = PKT_SIGNATURE;
2549                 newpkt->pkt.signature = newsig;
2550                 free_packet( node->pkt );
2551                 m_free( node->pkt );
2552                 node->pkt = newpkt;
2553                 if( sn ) {
2554                     newpkt = m_alloc_clear( sizeof *newpkt );
2555                     newpkt->pkttype = PKT_SIGNATURE;
2556                     newpkt->pkt.signature = copy_signature( NULL, newsig );
2557                     free_packet( sn->pkt );
2558                     m_free( sn->pkt );
2559                     sn->pkt = newpkt;
2560                 }
2561                 sub_pk = NULL;
2562             }
2563         }
2564     }
2565
2566     free_secret_key( sk );
2567     update_trust=1;
2568     return 1;
2569 }
2570
2571 static int
2572 change_primary_uid_cb ( PKT_signature *sig, void *opaque )
2573 {
2574     byte buf[1];
2575
2576     /* first clear all primary uid flags so that we are sure none are
2577      * lingering around */
2578     delete_sig_subpkt (sig->hashed,   SIGSUBPKT_PRIMARY_UID);
2579     delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PRIMARY_UID);
2580
2581     /* if opaque is set,we want to set the primary id */
2582     if (opaque) { 
2583         buf[0] = 1;
2584         build_sig_subpkt (sig, SIGSUBPKT_PRIMARY_UID, buf, 1 );
2585     }
2586
2587     return 0;
2588 }
2589
2590
2591 /*
2592  * Set the primary uid flag for the selected UID.  We will also reset
2593  * all other primary uid flags.  For this to work with have to update
2594  * all the signature timestamps.  If we would do this with the current
2595  * time, we lose quite a lot of information, so we use a a kludge to
2596  * do this: Just increment the timestamp by one second which is
2597  * sufficient to updated a signature during import.
2598  */
2599 static int
2600 menu_set_primary_uid ( KBNODE pub_keyblock, KBNODE sec_keyblock )
2601 {
2602     PKT_secret_key *sk;    /* copy of the main sk */
2603     PKT_public_key *main_pk;
2604     PKT_user_id *uid;
2605     KBNODE node;
2606     u32 keyid[2];
2607     int selected;
2608     int attribute = 0;
2609     int modified = 0;
2610
2611     if ( count_selected_uids (pub_keyblock) != 1 ) {
2612         tty_printf(_("Please select exactly one user ID.\n"));
2613         return 0;
2614     }
2615
2616     node = find_kbnode( sec_keyblock, PKT_SECRET_KEY );
2617     sk = copy_secret_key( NULL, node->pkt->pkt.secret_key);
2618
2619     /* Now we can actually change the self signature(s) */
2620     main_pk = NULL;
2621     uid = NULL;
2622     selected = 0;
2623
2624     /* Is our selected uid an attribute packet? */
2625     for ( node=pub_keyblock; node; node = node->next )
2626       if (node->pkt->pkttype == PKT_USER_ID && node->flag & NODFLG_SELUID)
2627         attribute = (node->pkt->pkt.user_id->attrib_data!=NULL);
2628
2629     for ( node=pub_keyblock; node; node = node->next ) {
2630         if ( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
2631             break; /* ready */
2632
2633         if ( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
2634             main_pk = node->pkt->pkt.public_key;
2635             keyid_from_pk( main_pk, keyid );
2636         }
2637         else if ( node->pkt->pkttype == PKT_USER_ID ) {
2638             uid = node->pkt->pkt.user_id;
2639             selected = node->flag & NODFLG_SELUID;
2640         }
2641         else if ( main_pk && uid && node->pkt->pkttype == PKT_SIGNATURE ) {
2642             PKT_signature *sig = node->pkt->pkt.signature;
2643             if ( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1]
2644                 && (uid && (sig->sig_class&~3) == 0x10)
2645                 && attribute == (uid->attrib_data!=NULL)) {
2646               if(sig->version < 4) {
2647                 char *user=utf8_to_native(uid->name,strlen(uid->name),0);
2648
2649                 log_info(_("skipping v3 self-signature on user id \"%s\"\n"),
2650                          user);
2651                 m_free(user);
2652               }
2653               else {
2654                 /* This is a selfsignature which is to be replaced.
2655                    We can just ignore v3 signatures because they are
2656                    not able to carry the primary ID flag.  We also
2657                    ignore self-sigs on user IDs that are not of the
2658                    same type that we are making primary.  That is, if
2659                    we are making a user ID primary, we alter user IDs.
2660                    If we are making an attribute packet primary, we
2661                    alter attribute packets. */
2662
2663                 /* FIXME: We must make sure that we only have one
2664                    self-signature per user ID here (not counting
2665                    revocations) */
2666                 PKT_signature *newsig;
2667                 PACKET *newpkt;
2668                 const byte *p;
2669                 int action;
2670
2671                 /* see whether this signature has the primary UID flag */
2672                 p = parse_sig_subpkt (sig->hashed,
2673                                       SIGSUBPKT_PRIMARY_UID, NULL );
2674                 if ( !p )
2675                     p = parse_sig_subpkt (sig->unhashed,
2676                                           SIGSUBPKT_PRIMARY_UID, NULL );
2677                 if ( p && *p ) /* yes */
2678                     action = selected? 0 : -1;
2679                 else /* no */
2680                     action = selected? 1 : 0;
2681
2682                 if (action) {
2683                     int rc = update_keysig_packet (&newsig, sig,
2684                                                main_pk, uid, 
2685                                                sk,
2686                                                change_primary_uid_cb,
2687                                                action > 0? "x":NULL );
2688                     if( rc ) {
2689                         log_error ("update_keysig_packet failed: %s\n",
2690                                    g10_errstr(rc));
2691                         free_secret_key( sk );
2692                         return 0;
2693                     }
2694                     /* replace the packet */
2695                     newpkt = m_alloc_clear( sizeof *newpkt );
2696                     newpkt->pkttype = PKT_SIGNATURE;
2697                     newpkt->pkt.signature = newsig;
2698                     free_packet( node->pkt );
2699                     m_free( node->pkt );
2700                     node->pkt = newpkt;
2701                     modified = 1;
2702                 }
2703               }
2704             }
2705         }
2706     }
2707
2708     free_secret_key( sk );
2709     return modified;
2710 }
2711
2712
2713 /* 
2714  * Set preferences to new values for the selected user IDs
2715  */
2716 static int
2717 menu_set_preferences (KBNODE pub_keyblock, KBNODE sec_keyblock )
2718 {
2719     PKT_secret_key *sk;    /* copy of the main sk */
2720     PKT_public_key *main_pk;
2721     PKT_user_id *uid;
2722     KBNODE node;
2723     u32 keyid[2];
2724     int selected, select_all;
2725     int modified = 0;
2726
2727     select_all = !count_selected_uids (pub_keyblock);
2728
2729     node = find_kbnode( sec_keyblock, PKT_SECRET_KEY );
2730     sk = copy_secret_key( NULL, node->pkt->pkt.secret_key);
2731
2732     /* Now we can actually change the self signature(s) */
2733     main_pk = NULL;
2734     uid = NULL;
2735     selected = 0;
2736     for ( node=pub_keyblock; node; node = node->next ) {
2737         if ( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
2738             break; /* ready */
2739
2740         if ( node->pkt->pkttype == PKT_PUBLIC_KEY ) {
2741             main_pk = node->pkt->pkt.public_key;
2742             keyid_from_pk( main_pk, keyid );
2743         }
2744         else if ( node->pkt->pkttype == PKT_USER_ID ) {
2745             uid = node->pkt->pkt.user_id;
2746             selected = select_all || (node->flag & NODFLG_SELUID);
2747         }
2748         else if ( main_pk && uid && selected
2749                   && node->pkt->pkttype == PKT_SIGNATURE ) {
2750             PKT_signature *sig = node->pkt->pkt.signature;
2751             if ( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1]
2752                  && (uid && (sig->sig_class&~3) == 0x10) ) {
2753               if( sig->version < 4 ) {
2754                 char *user=utf8_to_native(uid->name,strlen(uid->name),0);
2755
2756                 log_info(_("skipping v3 self-signature on user id \"%s\"\n"),
2757                          user);
2758                 m_free(user);
2759               }
2760               else {
2761                 /* This is a selfsignature which is to be replaced 
2762                  * We have to ignore v3 signatures because they are
2763                  * not able to carry the preferences */
2764                 PKT_signature *newsig;
2765                 PACKET *newpkt;
2766                 int rc;
2767
2768                 rc = update_keysig_packet (&newsig, sig,
2769                                            main_pk, uid, 
2770                                            sk,
2771                                            keygen_upd_std_prefs,
2772                                            NULL );
2773                 if( rc ) {
2774                     log_error ("update_keysig_packet failed: %s\n",
2775                                g10_errstr(rc));
2776                     free_secret_key( sk );
2777                     return 0;
2778                 }
2779                 /* replace the packet */
2780                 newpkt = m_alloc_clear( sizeof *newpkt );
2781                 newpkt->pkttype = PKT_SIGNATURE;
2782                 newpkt->pkt.signature = newsig;
2783                 free_packet( node->pkt );
2784                 m_free( node->pkt );
2785                 node->pkt = newpkt;
2786                 modified = 1;
2787               }
2788             }
2789         }
2790     }
2791     
2792     free_secret_key( sk );
2793     return modified;
2794 }
2795
2796
2797 /****************
2798  * Select one user id or remove all selection if index is 0.
2799  * Returns: True if the selection changed;
2800  */
2801 static int
2802 menu_select_uid( KBNODE keyblock, int idx )
2803 {
2804     KBNODE node;
2805     int i;
2806
2807     /* first check that the index is valid */
2808     if( idx ) {
2809         for( i=0, node = keyblock; node; node = node->next ) {
2810             if( node->pkt->pkttype == PKT_USER_ID ) {
2811                 if( ++i == idx )
2812                     break;
2813             }
2814         }
2815         if( !node ) {
2816             tty_printf(_("No user ID with index %d\n"), idx );
2817             return 0;
2818         }
2819     }
2820     else { /* reset all */
2821         for( i=0, node = keyblock; node; node = node->next ) {
2822             if( node->pkt->pkttype == PKT_USER_ID )
2823                 node->flag &= ~NODFLG_SELUID;
2824         }
2825         return 1;
2826     }
2827     /* and toggle the new index */
2828     for( i=0, node = keyblock; node; node = node->next ) {
2829         if( node->pkt->pkttype == PKT_USER_ID ) {
2830             if( ++i == idx ) {
2831                 if( (node->flag & NODFLG_SELUID) )
2832                     node->flag &= ~NODFLG_SELUID;
2833                 else
2834                     node->flag |= NODFLG_SELUID;
2835             }
2836         }
2837     }
2838
2839     return 1;
2840 }
2841
2842 /****************
2843  * Select secondary keys
2844  * Returns: True if the selection changed;
2845  */
2846 static int
2847 menu_select_key( KBNODE keyblock, int idx )
2848 {
2849     KBNODE node;
2850     int i;
2851
2852     /* first check that the index is valid */
2853     if( idx ) {
2854         for( i=0, node = keyblock; node; node = node->next ) {
2855             if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
2856                 || node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
2857                 if( ++i == idx )
2858                     break;
2859             }
2860         }
2861         if( !node ) {
2862             tty_printf(_("No secondary key with index %d\n"), idx );
2863             return 0;
2864         }
2865     }
2866     else { /* reset all */
2867         for( i=0, node = keyblock; node; node = node->next ) {
2868             if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
2869                 || node->pkt->pkttype == PKT_SECRET_SUBKEY )
2870                 node->flag &= ~NODFLG_SELKEY;
2871         }
2872         return 1;
2873     }
2874     /* and set the new index */
2875     for( i=0, node = keyblock; node; node = node->next ) {
2876         if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
2877             || node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
2878             if( ++i == idx ) {
2879                 if( (node->flag & NODFLG_SELKEY) )
2880                     node->flag &= ~NODFLG_SELKEY;
2881                 else
2882                     node->flag |= NODFLG_SELKEY;
2883             }
2884         }
2885     }
2886
2887     return 1;
2888 }
2889
2890
2891 static int
2892 count_uids_with_flag( KBNODE keyblock, unsigned flag )
2893 {
2894     KBNODE node;
2895     int i=0;
2896
2897     for( node = keyblock; node; node = node->next )
2898         if( node->pkt->pkttype == PKT_USER_ID && (node->flag & flag) )
2899             i++;
2900     return i;
2901 }
2902
2903 static int
2904 count_keys_with_flag( KBNODE keyblock, unsigned flag )
2905 {
2906     KBNODE node;
2907     int i=0;
2908
2909     for( node = keyblock; node; node = node->next )
2910         if( ( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
2911               || node->pkt->pkttype == PKT_SECRET_SUBKEY)
2912             && (node->flag & flag) )
2913             i++;
2914     return i;
2915 }
2916
2917 static int
2918 count_uids( KBNODE keyblock )
2919 {
2920     KBNODE node;
2921     int i=0;
2922
2923     for( node = keyblock; node; node = node->next )
2924         if( node->pkt->pkttype == PKT_USER_ID )
2925             i++;
2926     return i;
2927 }
2928
2929
2930 /****************
2931  * Returns true if there is at least one selected user id
2932  */
2933 static int
2934 count_selected_uids( KBNODE keyblock )
2935 {
2936     return count_uids_with_flag( keyblock, NODFLG_SELUID);
2937 }
2938
2939 static int
2940 count_selected_keys( KBNODE keyblock )
2941 {
2942     return count_keys_with_flag( keyblock, NODFLG_SELKEY);
2943 }
2944
2945 /* returns how many real (i.e. not attribute) uids are unmarked */
2946 static int
2947 real_uids_left( KBNODE keyblock )
2948 {
2949   KBNODE node;
2950   int real=0;
2951
2952   for(node=keyblock;node;node=node->next)
2953     if(node->pkt->pkttype==PKT_USER_ID && !(node->flag&NODFLG_SELUID) &&
2954        !node->pkt->pkt.user_id->attrib_data)
2955       real++;
2956
2957   return real;
2958 }
2959
2960 /*
2961  * Ask whether the signature should be revoked.  If the user commits this,
2962  * flag bit MARK_A is set on the signature and the user ID.
2963  */
2964 static void
2965 ask_revoke_sig( KBNODE keyblock, KBNODE node )
2966 {
2967     int doit=0;
2968     PKT_signature *sig = node->pkt->pkt.signature;
2969     KBNODE unode = find_prev_kbnode( keyblock, node, PKT_USER_ID );
2970
2971     if( !unode ) {
2972         log_error("Oops: no user ID for signature\n");
2973         return;
2974     }
2975
2976     tty_printf(_("user ID: \""));
2977     tty_print_utf8_string( unode->pkt->pkt.user_id->name,
2978                            unode->pkt->pkt.user_id->len );
2979
2980     if(sig->flags.exportable)
2981       tty_printf(_("\"\nsigned with your key %08lX at %s\n"),
2982                  (ulong)sig->keyid[1], datestr_from_sig(sig) );
2983     else
2984       tty_printf(_("\"\nlocally signed with your key %08lX at %s\n"),
2985                  (ulong)sig->keyid[1], datestr_from_sig(sig) );
2986
2987     if(sig->flags.expired)
2988       {
2989         tty_printf(_("This signature expired on %s.\n"),
2990                    expirestr_from_sig(sig));
2991         /* Use a different question so we can have different help text */
2992         doit=cpr_get_answer_is_yes("ask_revoke_sig.expired",
2993                         _("Are you sure you still want to revoke it? (y/N) "));
2994       }
2995     else
2996       doit=cpr_get_answer_is_yes("ask_revoke_sig.one",
2997               _("Create a revocation certificate for this signature? (y/N) "));
2998
2999     if(doit) {
3000       node->flag |= NODFLG_MARK_A;
3001       unode->flag |= NODFLG_MARK_A;
3002     }
3003 }
3004
3005 /****************
3006  * Display all user ids of the current public key together with signatures
3007  * done by one of our keys.  Then walk over all this sigs and ask the user
3008  * whether he wants to revoke this signature.
3009  * Return: True when the keyblock has changed.
3010  */
3011 static int
3012 menu_revsig( KBNODE keyblock )
3013 {
3014     PKT_signature *sig;
3015     PKT_public_key *primary_pk;
3016     KBNODE node;
3017     int changed = 0;
3018     int rc, any, skip=1, all=!count_selected_uids(keyblock);
3019     struct revocation_reason_info *reason = NULL;
3020
3021     /* FIXME: detect duplicates here  */
3022     tty_printf(_("You have signed these user IDs:\n"));
3023     for( node = keyblock; node; node = node->next ) {
3024         node->flag &= ~(NODFLG_SELSIG | NODFLG_MARK_A);
3025         if( node->pkt->pkttype == PKT_USER_ID ) {
3026             if( node->flag&NODFLG_SELUID || all ) {
3027               PKT_user_id *uid = node->pkt->pkt.user_id;
3028               /* Hmmm: Should we show only UIDs with a signature? */
3029               tty_printf("     ");
3030               tty_print_utf8_string( uid->name, uid->len );
3031               tty_printf("\n");
3032               skip=0;
3033             }
3034             else
3035               skip=1;
3036         }
3037         else if( !skip && node->pkt->pkttype == PKT_SIGNATURE
3038                 && ((sig = node->pkt->pkt.signature),
3039                      !seckey_available(sig->keyid)  ) ) {
3040             if( (sig->sig_class&~3) == 0x10 ) {
3041                 tty_printf(_("   signed by %08lX at %s%s%s\n"),
3042                            (ulong)sig->keyid[1], datestr_from_sig(sig),
3043                            sig->flags.exportable?"":" (non-exportable)",
3044                            sig->flags.revocable?"":" (non-revocable)");
3045                 if(sig->flags.revocable)
3046                   node->flag |= NODFLG_SELSIG;
3047             }
3048             else if( sig->sig_class == 0x30 ) {
3049                 tty_printf(_("   revoked by %08lX at %s\n"),
3050                             (ulong)sig->keyid[1], datestr_from_sig(sig) );
3051             }
3052         }
3053     }
3054
3055     /* ask */
3056     for( node = keyblock; node; node = node->next ) {
3057         if( !(node->flag & NODFLG_SELSIG) )
3058             continue;
3059         ask_revoke_sig( keyblock, node );
3060     }
3061
3062     /* present selected */
3063     any = 0;
3064     for( node = keyblock; node; node = node->next ) {
3065         if( !(node->flag & NODFLG_MARK_A) )
3066             continue;
3067         if( !any ) {
3068             any = 1;
3069             tty_printf(_("You are about to revoke these signatures:\n"));
3070         }
3071         if( node->pkt->pkttype == PKT_USER_ID ) {
3072             PKT_user_id *uid = node->pkt->pkt.user_id;
3073             tty_printf("     ");
3074             tty_print_utf8_string( uid->name, uid->len );
3075             tty_printf("\n");
3076         }
3077         else if( node->pkt->pkttype == PKT_SIGNATURE ) {
3078             sig = node->pkt->pkt.signature;
3079             tty_printf(_("   signed by %08lX at %s%s\n"),
3080                        (ulong)sig->keyid[1], datestr_from_sig(sig),
3081                        sig->flags.exportable?"":_(" (non-exportable)") );
3082         }
3083     }
3084     if( !any )
3085         return 0; /* none selected */
3086
3087     if( !cpr_get_answer_is_yes("ask_revoke_sig.okay",
3088          _("Really create the revocation certificates? (y/N) ")) )
3089         return 0; /* forget it */
3090
3091     reason = ask_revocation_reason( 0, 1, 0 );
3092     if( !reason ) { /* user decided to cancel */
3093         return 0;
3094     }
3095
3096     /* now we can sign the user ids */
3097   reloop: /* (must use this, because we are modifing the list) */
3098     primary_pk = keyblock->pkt->pkt.public_key;
3099     for( node=keyblock; node; node = node->next ) {
3100         KBNODE unode;
3101         PACKET *pkt;
3102         struct sign_attrib attrib;
3103         PKT_secret_key *sk;
3104
3105         if( !(node->flag & NODFLG_MARK_A)
3106             || node->pkt->pkttype != PKT_SIGNATURE )
3107             continue;
3108         unode = find_prev_kbnode( keyblock, node, PKT_USER_ID );
3109         assert( unode ); /* we already checked this */
3110
3111         memset( &attrib, 0, sizeof attrib );
3112         attrib.reason = reason;
3113         attrib.non_exportable=!node->pkt->pkt.signature->flags.exportable;
3114
3115         node->flag &= ~NODFLG_MARK_A;
3116         sk = m_alloc_secure_clear( sizeof *sk );
3117         if( get_seckey( sk, node->pkt->pkt.signature->keyid ) ) {
3118             log_info(_("no secret key\n"));
3119             continue;
3120         }
3121         rc = make_keysig_packet( &sig, primary_pk,
3122                                        unode->pkt->pkt.user_id,
3123                                        NULL,
3124                                        sk,
3125                                        0x30, 0, 0, 0, 0,
3126                                        sign_mk_attrib,
3127                                        &attrib );
3128         free_secret_key(sk);
3129         if( rc ) {
3130             log_error(_("signing failed: %s\n"), g10_errstr(rc));
3131             release_revocation_reason_info( reason );
3132             return changed;
3133         }
3134         changed = 1; /* we changed the keyblock */
3135         update_trust = 1;
3136         /* Are we revoking our own uid? */
3137         if(primary_pk->keyid[0]==sig->keyid[0] &&
3138            primary_pk->keyid[1]==sig->keyid[1])
3139           unode->pkt->pkt.user_id->is_revoked=1;
3140         pkt = m_alloc_clear( sizeof *pkt );
3141         pkt->pkttype = PKT_SIGNATURE;
3142         pkt->pkt.signature = sig;
3143         insert_kbnode( unode, new_kbnode(pkt), 0 );
3144         goto reloop;
3145     }
3146
3147     release_revocation_reason_info( reason );
3148     return changed;
3149 }
3150
3151 /****************
3152  * Revoke some of the secondary keys.
3153  * Hmmm: Should we add a revocation to the secret keyring too?
3154  *       Does its all make sense to duplicate most of the information?
3155  */
3156 static int
3157 menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock )
3158 {
3159     PKT_public_key *mainpk;
3160     KBNODE node;
3161     int changed = 0;
3162     int rc;
3163     struct revocation_reason_info *reason = NULL;
3164
3165     reason = ask_revocation_reason( 1, 0, 0 );
3166     if( !reason ) { /* user decided to cancel */
3167         return 0;
3168     }
3169
3170
3171   reloop: /* (better this way because we are modifing the keyring) */
3172     mainpk = pub_keyblock->pkt->pkt.public_key;
3173     for( node = pub_keyblock; node; node = node->next ) {
3174         if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
3175             && (node->flag & NODFLG_SELKEY) ) {
3176             PACKET *pkt;
3177             PKT_signature *sig;
3178             PKT_secret_key *sk;
3179             PKT_public_key *subpk = node->pkt->pkt.public_key;
3180             struct sign_attrib attrib;
3181
3182             memset( &attrib, 0, sizeof attrib );
3183             attrib.reason = reason;
3184
3185             node->flag &= ~NODFLG_SELKEY;
3186             sk = copy_secret_key( NULL, sec_keyblock->pkt->pkt.secret_key );
3187             rc = make_keysig_packet( &sig, mainpk, NULL, subpk, sk,
3188                                      0x28, 0, 0, 0, 0,
3189                                      sign_mk_attrib, &attrib );
3190             free_secret_key(sk);
3191             if( rc ) {
3192                 log_error(_("signing failed: %s\n"), g10_errstr(rc));
3193                 release_revocation_reason_info( reason );
3194                 return changed;
3195             }
3196             changed = 1; /* we changed the keyblock */
3197
3198             pkt = m_alloc_clear( sizeof *pkt );
3199             pkt->pkttype = PKT_SIGNATURE;
3200             pkt->pkt.signature = sig;
3201             insert_kbnode( node, new_kbnode(pkt), 0 );
3202             goto reloop;
3203         }
3204     }
3205     commit_kbnode( &pub_keyblock );
3206     /*commit_kbnode( &sec_keyblock );*/
3207
3208     /* No need to set update_trust here since signing keys no longer
3209        are used to certify other keys, so there is no change in trust
3210        when revoking/removing them */
3211
3212     release_revocation_reason_info( reason );
3213     return changed;
3214 }
3215
3216
3217 static int
3218 enable_disable_key( KBNODE keyblock, int disable )
3219 {
3220     PKT_public_key *pk = find_kbnode( keyblock, PKT_PUBLIC_KEY )
3221                             ->pkt->pkt.public_key;
3222     unsigned int trust, newtrust;
3223
3224     trust = newtrust = get_ownertrust (pk);
3225     newtrust &= ~TRUST_FLAG_DISABLED;
3226     if( disable )
3227         newtrust |= TRUST_FLAG_DISABLED;
3228     if( trust == newtrust )
3229         return 0; /* already in that state */
3230     update_ownertrust(pk, newtrust );
3231     return 0;
3232 }
3233
3234
3235 static void
3236 menu_showphoto( KBNODE keyblock )
3237 {
3238   KBNODE node;
3239   int select_all = !count_selected_uids(keyblock);
3240   int count=0;
3241   PKT_public_key *pk=NULL;
3242   u32 keyid[2];
3243
3244   /* Look for the public key first.  We have to be really, really,
3245      explicit as to which photo this is, and what key it is a UID on
3246      since people may want to sign it. */
3247
3248   for( node = keyblock; node; node = node->next )
3249     {
3250       if( node->pkt->pkttype == PKT_PUBLIC_KEY )
3251         {
3252           pk = node->pkt->pkt.public_key;
3253           keyid_from_pk(pk, keyid);
3254         }
3255       else if( node->pkt->pkttype == PKT_USER_ID )
3256         {
3257           PKT_user_id *uid = node->pkt->pkt.user_id;
3258           count++;
3259
3260           if((select_all || (node->flag & NODFLG_SELUID)) &&
3261              uid->attribs!=NULL)
3262             {
3263               int i;
3264
3265               for(i=0;i<uid->numattribs;i++)
3266                 {
3267                   byte type;
3268                   u32 size;
3269
3270                   if(uid->attribs[i].type==ATTRIB_IMAGE &&
3271                      parse_image_header(&uid->attribs[i],&type,&size))
3272                     {
3273                       tty_printf(_("Displaying %s photo ID of size %ld for "
3274                                    "key 0x%08lX (uid %d)\n"),
3275                                  image_type_to_string(type,1),
3276                                  (ulong)size,(ulong)keyid[1],count);
3277                       show_photos(&uid->attribs[i],1,pk,NULL);
3278                     }
3279                 }
3280             }
3281         }