* keyedit.c (keyedit_menu): Prompt for subkey removal for both secret and
[gnupg.git] / g10 / keylist.c
1 /* keylist.c
2  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
3  *               2004 Free Software Foundation, Inc.
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * GnuPG is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20  */
21
22 #include <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <assert.h>
28
29 #include "options.h"
30 #include "packet.h"
31 #include "errors.h"
32 #include "keydb.h"
33 #include "memory.h"
34 #include "photoid.h"
35 #include "util.h"
36 #include "ttyio.h"
37 #include "trustdb.h"
38 #include "main.h"
39 #include "i18n.h"
40 #include "status.h"
41
42 static void list_all(int);
43 static void list_one( STRLIST names, int secret);
44
45 struct sig_stats
46 {
47   int inv_sigs;
48   int no_key;
49   int oth_err;
50 };
51
52 static FILE *attrib_fp=NULL;
53
54 /****************
55  * List the keys
56  * If list is NULL, all available keys are listed
57  */
58 void
59 public_key_list( STRLIST list )
60 {
61   if(opt.with_colons)
62     {
63       byte trust_model,marginals,completes,cert_depth;
64       ulong created,nextcheck;
65
66       read_trust_options(&trust_model,&created,&nextcheck,
67                          &marginals,&completes,&cert_depth);
68
69       printf("tru:");
70
71       if(nextcheck && nextcheck <= make_timestamp())
72         printf("o");
73       if(trust_model!=opt.trust_model)
74         printf("t");
75       if(opt.trust_model==TM_PGP || opt.trust_model==TM_CLASSIC)
76         {
77           if(marginals!=opt.marginals_needed)
78             printf("m");
79           if(completes!=opt.completes_needed)
80             printf("c");
81           if(cert_depth!=opt.max_cert_depth)
82             printf("d");
83         }
84
85       printf(":%d:%lu:%lu",trust_model,created,nextcheck);
86
87       /* Only show marginals, completes, and cert_depth in the classic
88          or PGP trust models since they are not meaningful
89          otherwise. */
90
91       if(trust_model==TM_PGP || trust_model==TM_CLASSIC)
92         printf(":%d:%d:%d",marginals,completes,cert_depth);
93
94       printf("\n");
95     }
96
97   if( !list )
98     list_all(0);
99   else
100     list_one( list, 0 );
101 }
102
103 void
104 secret_key_list( STRLIST list )
105 {
106     if( !list )
107         list_all(1);
108     else  /* List by user id */
109         list_one( list, 1 );
110 }
111
112 void
113 print_seckey_info (PKT_secret_key *sk)
114 {
115     u32 sk_keyid[2];
116     size_t n;
117     char *p;
118
119     keyid_from_sk (sk, sk_keyid);
120     tty_printf ("\nsec  %4u%c/%08lX %s   ",
121                 nbits_from_sk (sk),
122                 pubkey_letter (sk->pubkey_algo),
123                 (ulong)sk_keyid[1], datestr_from_sk (sk));
124     
125     p = get_user_id (sk_keyid, &n);
126     tty_print_utf8_string (p, n);
127     m_free (p);
128
129     tty_printf ("\n");   
130 }
131
132 /* Print information about the public key.  With FP passed as NULL,
133    the tty output interface is used, otherwise output is directted to
134    the given stream. */
135 void
136 print_pubkey_info (FILE *fp, PKT_public_key *pk)
137 {
138   u32 pk_keyid[2];
139   size_t n;
140   char *p;
141
142   keyid_from_pk (pk, pk_keyid);
143   if (fp)
144     fprintf (fp, "pub  %4u%c/%08lX %s   ",
145              nbits_from_pk (pk),
146              pubkey_letter (pk->pubkey_algo),
147              (ulong)pk_keyid[1], datestr_from_pk (pk));
148   else
149     tty_printf ("\npub  %4u%c/%08lX %s   ",
150                 nbits_from_pk (pk),
151                 pubkey_letter (pk->pubkey_algo),
152                 (ulong)pk_keyid[1], datestr_from_pk (pk));
153
154   p = get_user_id (pk_keyid, &n);
155   if (fp)
156     print_utf8_string2 (fp, p, n, '\n');
157   else
158     tty_print_utf8_string (p, n);
159   m_free (p);
160   
161   if (fp)
162     putc ('\n', fp);
163   else
164     tty_printf ("\n\n"); 
165 }
166
167 /*
168   mode=0 for stdout.
169   mode=1 for log_info + status messages
170   mode=2 for status messages only
171 */
172
173 void
174 show_policy_url(PKT_signature *sig,int indent,int mode)
175 {
176   const byte *p;
177   size_t len;
178   int seq=0,crit;
179   FILE *fp=mode?log_stream():stdout;
180
181   while((p=enum_sig_subpkt(sig->hashed,SIGSUBPKT_POLICY,&len,&seq,&crit)))
182     {
183       if(mode!=2)
184         {
185           int i;
186           char *str;
187
188           for(i=0;i<indent;i++)
189             putchar(' ');
190
191           if(crit)
192             str=_("Critical signature policy: ");
193           else
194             str=_("Signature policy: ");
195           if(mode)
196             log_info("%s",str);
197           else
198             printf("%s",str);
199           print_utf8_string(fp,p,len);
200           fprintf(fp,"\n");
201         }
202
203       if(mode)
204         write_status_buffer ( STATUS_POLICY_URL, p, len, 0 );
205     }
206 }
207
208 /*
209   mode=0 for stdout.
210   mode=1 for log_info + status messages
211   mode=2 for status messages only
212 */
213 /* TODO: use this */
214 void
215 show_keyserver_url(PKT_signature *sig,int indent,int mode)
216 {
217   const byte *p;
218   size_t len;
219   int seq=0,crit;
220   FILE *fp=mode?log_stream():stdout;
221
222   while((p=enum_sig_subpkt(sig->hashed,SIGSUBPKT_PREF_KS,&len,&seq,&crit)))
223     {
224       if(mode!=2)
225         {
226           int i;
227           char *str;
228
229           for(i=0;i<indent;i++)
230             putchar(' ');
231
232           if(crit)
233             str=_("Critical preferred keyserver: ");
234           else
235             str=_("Preferred keyserver: ");
236           if(mode)
237             log_info("%s",str);
238           else
239             printf("%s",str);
240           print_utf8_string(fp,p,len);
241           fprintf(fp,"\n");
242         }
243
244       /* TODO: put in a status-fd tag for preferred keyservers */
245     }
246 }
247
248 /*
249   mode=0 for stdout.
250   mode=1 for log_info + status messages
251   mode=2 for status messages only
252 */
253
254 void
255 show_notation(PKT_signature *sig,int indent,int mode)
256 {
257   const byte *p;
258   size_t len;
259   int seq=0,crit;
260   FILE *fp=mode?log_stream():stdout;
261
262   /* There may be multiple notations in the same sig. */
263
264   while((p=enum_sig_subpkt(sig->hashed,SIGSUBPKT_NOTATION,&len,&seq,&crit)))
265     if(len>=8)
266       {
267         int n1,n2;
268
269         n1=(p[4]<<8)|p[5];
270         n2=(p[6]<<8)|p[7];
271
272         if(8+n1+n2!=len)
273           {
274             log_info(_("WARNING: invalid notation data found\n"));
275             return;
276           }
277
278         if(mode!=2)
279           {
280             int i;
281             char *str;
282
283             for(i=0;i<indent;i++)
284               putchar(' ');
285
286             /* This is UTF8 */
287             if(crit)
288               str=_("Critical signature notation: ");
289             else
290               str=_("Signature notation: ");
291             if(mode)
292               log_info("%s",str);
293             else
294               printf("%s",str);
295             print_utf8_string(fp,p+8,n1);
296             fprintf(fp,"=");
297
298             if(*p&0x80)
299               print_utf8_string(fp,p+8+n1,n2);
300             else
301               fprintf(fp,"[ %s ]",_("not human readable"));
302
303             fprintf(fp,"\n");
304           }
305
306         if(mode)
307           {
308             write_status_buffer ( STATUS_NOTATION_NAME, p+8   , n1, 0 );
309             write_status_buffer ( STATUS_NOTATION_DATA, p+8+n1, n2, 50 );
310           }
311       }
312   else
313     log_info(_("WARNING: invalid notation data found\n"));
314 }
315
316 static void
317 print_signature_stats(struct sig_stats *s)
318 {
319   if( s->inv_sigs == 1 )
320     tty_printf(_("1 bad signature\n") );
321   else if( s->inv_sigs )
322     tty_printf(_("%d bad signatures\n"), s->inv_sigs );
323   if( s->no_key == 1 )
324     tty_printf(_("1 signature not checked due to a missing key\n") );
325   else if( s->no_key )
326     tty_printf(_("%d signatures not checked due to missing keys\n"),s->no_key);
327   if( s->oth_err == 1 )
328     tty_printf(_("1 signature not checked due to an error\n") );
329   else if( s->oth_err )
330     tty_printf(_("%d signatures not checked due to errors\n"), s->oth_err );
331 }
332
333 static void
334 list_all( int secret )
335 {
336     KEYDB_HANDLE hd;
337     KBNODE keyblock = NULL;
338     int rc=0;
339     const char *lastresname, *resname;
340     struct sig_stats stats;
341
342     memset(&stats,0,sizeof(stats));
343
344     hd = keydb_new (secret);
345     if (!hd)
346         rc = G10ERR_GENERAL;
347     else
348         rc = keydb_search_first (hd);
349     if( rc ) {
350         if( rc != -1 )
351             log_error("keydb_search_first failed: %s\n", g10_errstr(rc) );
352         goto leave;
353     }
354
355     lastresname = NULL;
356     do {
357         rc = keydb_get_keyblock (hd, &keyblock);
358         if (rc) {
359             log_error ("keydb_get_keyblock failed: %s\n", g10_errstr(rc));
360             goto leave;
361         }
362         if(!opt.with_colons)
363           {
364             resname = keydb_get_resource_name (hd);
365             if (lastresname != resname )
366               {
367                 int i;
368
369                 printf("%s\n", resname );
370                 for(i=strlen(resname); i; i-- )
371                   putchar('-');
372                 putchar('\n');
373                 lastresname = resname;
374               }
375           }
376         merge_keys_and_selfsig( keyblock );
377         list_keyblock( keyblock, secret, opt.fingerprint,
378                        opt.check_sigs?&stats:NULL);
379         release_kbnode( keyblock ); 
380         keyblock = NULL;
381     } while (!(rc = keydb_search_next (hd)));
382     if( rc && rc != -1 )
383         log_error ("keydb_search_next failed: %s\n", g10_errstr(rc));
384
385     if(opt.check_sigs && !opt.with_colons)
386       print_signature_stats(&stats);
387
388   leave:
389     release_kbnode (keyblock);
390     keydb_release (hd);
391 }
392
393
394 static void
395 list_one( STRLIST names, int secret )
396 {
397     int rc = 0;
398     KBNODE keyblock = NULL;
399     GETKEY_CTX ctx;
400     const char *resname;
401     char *keyring_str = _("Keyring");
402     int i;
403     struct sig_stats stats;
404
405     memset(&stats,0,sizeof(stats));
406
407     /* fixme: using the bynames function has the disadvantage that we
408      * don't know wether one of the names given was not found.  OTOH,
409      * this function has the advantage to list the names in the
410      * sequence as defined by the keyDB and does not duplicate
411      * outputs.  A solution could be do test whether all given have
412      * been listed (this needs a way to use the keyDB search
413      * functions) or to have the search function return indicators for
414      * found names.  Yet another way is to use the keydb search
415      * facilities directly. */
416     if( secret ) {
417         rc = get_seckey_bynames( &ctx, NULL, names, &keyblock );
418         if( rc ) {
419             log_error("error reading key: %s\n",  g10_errstr(rc) );
420             get_seckey_end( ctx );
421             return;
422         }
423         do {
424             if ((opt.list_options&LIST_SHOW_KEYRING) && !opt.with_colons) {
425                 resname = keydb_get_resource_name (get_ctx_handle(ctx));
426                 printf("%s: %s\n", keyring_str, resname);
427                 for(i = strlen(resname) + strlen(keyring_str) + 2; i; i-- )
428                     putchar('-');
429                 putchar('\n');
430             }
431             list_keyblock( keyblock, 1, opt.fingerprint, NULL );
432             release_kbnode( keyblock );
433         } while( !get_seckey_next( ctx, NULL, &keyblock ) );
434         get_seckey_end( ctx );
435     }
436     else {
437         rc = get_pubkey_bynames( &ctx, NULL, names, &keyblock );
438         if( rc ) {
439             log_error("error reading key: %s\n", g10_errstr(rc) );
440             get_pubkey_end( ctx );
441             return;
442         }
443         do {
444           if ((opt.list_options&LIST_SHOW_KEYRING) && !opt.with_colons) {
445                 resname = keydb_get_resource_name (get_ctx_handle(ctx));
446                 printf("%s: %s\n", keyring_str, resname);
447                 for(i = strlen(resname) + strlen(keyring_str) + 2; i; i-- )
448                     putchar('-');
449                 putchar('\n');
450             }
451             list_keyblock( keyblock, 0, opt.fingerprint,
452                            opt.check_sigs?&stats:NULL );
453             release_kbnode( keyblock );
454         } while( !get_pubkey_next( ctx, NULL, &keyblock ) );
455         get_pubkey_end( ctx );
456     }
457
458     if(opt.check_sigs && !opt.with_colons)
459       print_signature_stats(&stats);
460 }
461
462 static void
463 print_key_data( PKT_public_key *pk, u32 *keyid )
464 {
465     int n = pk ? pubkey_get_npkey( pk->pubkey_algo ) : 0;
466     int i;
467
468     for(i=0; i < n; i++ ) {
469         printf("pkd:%d:%u:", i, mpi_get_nbits( pk->pkey[i] ) );
470         mpi_print(stdout, pk->pkey[i], 1 );
471         putchar(':');
472         putchar('\n');
473     }
474 }
475
476 static void
477 print_capabilities (PKT_public_key *pk, PKT_secret_key *sk, KBNODE keyblock)
478 {
479   if(pk || (sk && sk->protect.s2k.mode!=1001))
480     {
481       unsigned int use = pk? pk->pubkey_usage : sk->pubkey_usage;
482     
483       if ( use & PUBKEY_USAGE_ENC )
484         putchar ('e');
485
486       if ( use & PUBKEY_USAGE_SIG )
487         {
488           putchar ('s');
489           if( pk? pk->is_primary : sk->is_primary )
490             putchar ('c');
491         }
492
493       if ( (use & PUBKEY_USAGE_AUTH) )
494         putchar ('a');
495     }
496
497     if ( keyblock ) { /* figure out the usable capabilities */
498         KBNODE k;
499         int enc=0, sign=0, cert=0, auth=0, disabled=0;
500
501         for (k=keyblock; k; k = k->next ) {
502             if ( k->pkt->pkttype == PKT_PUBLIC_KEY 
503                  || k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
504                 pk = k->pkt->pkt.public_key;
505
506                 if(pk->is_primary)
507                   disabled=pk_is_disabled(pk);
508
509                 if ( pk->is_valid && !pk->is_revoked && !pk->has_expired ) {
510                     if ( pk->pubkey_usage & PUBKEY_USAGE_ENC )
511                         enc = 1;
512                     if ( pk->pubkey_usage & PUBKEY_USAGE_SIG )
513                       {
514                         sign = 1;
515                         if(pk->is_primary)
516                           cert = 1;
517                       }
518                     if ( (pk->pubkey_usage & PUBKEY_USAGE_AUTH) )
519                       auth = 1;
520                 }
521             }
522             else if ( k->pkt->pkttype == PKT_SECRET_KEY 
523                       || k->pkt->pkttype == PKT_SECRET_SUBKEY ) {
524                 sk = k->pkt->pkt.secret_key;
525                 if ( sk->is_valid && !sk->is_revoked && !sk->has_expired
526                      && sk->protect.s2k.mode!=1001 ) {
527                     if ( sk->pubkey_usage & PUBKEY_USAGE_ENC )
528                         enc = 1;
529                     if ( sk->pubkey_usage & PUBKEY_USAGE_SIG )
530                       {
531                         sign = 1;
532                         if(sk->is_primary)
533                           cert = 1;
534                       }
535                     if ( (sk->pubkey_usage & PUBKEY_USAGE_AUTH) )
536                         auth = 1;
537                 }
538             }
539         }
540         if (enc)
541             putchar ('E');
542         if (sign)
543             putchar ('S');
544         if (cert)
545             putchar ('C');
546         if (auth)
547             putchar ('A');
548         if (disabled)
549             putchar ('D');
550     }
551
552     putchar(':');
553 }
554
555 void
556 dump_attribs(const PKT_user_id *uid,PKT_public_key *pk,PKT_secret_key *sk)
557 {
558   int i;
559
560   if(!attrib_fp)
561     return;
562
563   for(i=0;i<uid->numattribs;i++)
564     {
565       if(is_status_enabled())
566         {
567           byte array[MAX_FINGERPRINT_LEN], *p;
568           char buf[(MAX_FINGERPRINT_LEN*2)+90];
569           size_t j,n;
570
571           if(pk)
572             fingerprint_from_pk( pk, array, &n );
573           else if(sk)
574             fingerprint_from_sk( sk, array, &n );
575           else
576             BUG();
577
578           p = array;
579           for(j=0; j < n ; j++, p++ )
580             sprintf(buf+2*j, "%02X", *p );
581
582           sprintf(buf+strlen(buf)," %lu %u %u %u %lu %lu %u",
583                   (ulong)uid->attribs[i].len,uid->attribs[i].type,i+1,
584                   uid->numattribs,(ulong)uid->created,(ulong)uid->expiredate,
585                   ((uid->is_primary?0x01:0)|
586                    (uid->is_revoked?0x02:0)|
587                    (uid->is_expired?0x04:0)));
588           write_status_text(STATUS_ATTRIBUTE,buf);
589         }
590
591       fwrite(uid->attribs[i].data,uid->attribs[i].len,1,attrib_fp);
592     }
593 }
594
595 static void
596 list_keyblock_print ( KBNODE keyblock, int secret, int fpr, void *opaque )
597 {
598     int rc = 0;
599     KBNODE kbctx;
600     KBNODE node;
601     PKT_public_key *pk;
602     PKT_secret_key *sk;
603     u32 keyid[2];
604     int any=0;
605     struct sig_stats *stats=opaque;
606     int skip_sigs=0;
607     int newformat=((opt.list_options&LIST_SHOW_VALIDITY) && !secret)
608       || (opt.list_options & (LIST_SHOW_LONG_KEYIDS|LIST_SHOW_UNUSABLE_UIDS));
609
610     /* get the keyid from the keyblock */
611     node = find_kbnode( keyblock, secret? PKT_SECRET_KEY : PKT_PUBLIC_KEY );
612     if( !node ) {
613         log_error("Oops; key lost!\n");
614         dump_kbnode( keyblock );
615         return;
616     }
617
618     if( secret )
619       {
620         pk = NULL;
621         sk = node->pkt->pkt.secret_key;
622         keyid_from_sk( sk, keyid );
623
624         printf("sec%c  %4u%c/",(sk->protect.s2k.mode==1001)?'#':
625                                (sk->protect.s2k.mode==1002)?'>':' ',
626                nbits_from_sk( sk ),pubkey_letter( sk->pubkey_algo ));
627
628         if(opt.list_options&LIST_SHOW_LONG_KEYIDS)
629           printf("%08lX%08lX",(ulong)keyid[0],(ulong)keyid[1]);
630         else
631           printf("%08lX",(ulong)keyid[1]);
632
633         printf(" %s%s",datestr_from_sk( sk ),newformat?"":" " );
634
635         if(newformat && sk->expiredate )
636           printf(_(" [expires: %s]"), expirestr_from_sk( sk ) );
637       }
638     else
639       {
640 #if 0
641         int validity;
642 #endif
643         pk = node->pkt->pkt.public_key;
644         sk = NULL;
645         keyid_from_pk( pk, keyid );
646
647 #if 0
648         validity=get_validity(pk,NULL);
649 #endif
650
651         check_trustdb_stale();
652
653         printf("pub   %4u%c/",
654                nbits_from_pk(pk),pubkey_letter(pk->pubkey_algo));
655
656         if(opt.list_options&LIST_SHOW_LONG_KEYIDS)
657           printf("%08lX%08lX",(ulong)keyid[0],(ulong)keyid[1]);
658         else
659           printf("%08lX",(ulong)keyid[1]);
660
661         printf(" %s%s",datestr_from_pk( pk ),newformat?"":" " );
662
663         /* We didn't include this before in the key listing, but there
664            is room in the new format, so why not? */
665         if(newformat)
666           {
667             if(pk->is_revoked)
668               printf(_(" [revoked: %s]"), revokestr_from_pk( pk ) );
669             else if(pk->has_expired)
670               printf(_(" [expired: %s]"), expirestr_from_pk( pk ) );
671             else if(pk->expiredate)
672               printf(_(" [expires: %s]"), expirestr_from_pk( pk ) );
673           }
674
675 #if 0
676         /* I need to think about this some more.  It's easy enough to
677            include, but it looks sort of confusing in the
678            listing... */
679         if(opt.list_options&LIST_SHOW_VALIDITY)
680           printf(" [%s]",trust_value_to_string(validity));
681 #endif
682       }
683
684     for( kbctx=NULL; (node=walk_kbnode( keyblock, &kbctx, 0)) ; ) {
685         if( node->pkt->pkttype == PKT_USER_ID && !opt.fast_list_mode ) {
686             int indent;
687             PKT_user_id *uid=node->pkt->pkt.user_id;
688
689             if((uid->is_expired || uid->is_revoked)
690                && !(opt.list_options&LIST_SHOW_UNUSABLE_UIDS))
691               {
692                 skip_sigs=1;
693                 continue;
694               }
695             else
696               skip_sigs=0;
697
698             if(attrib_fp && uid->attrib_data!=NULL)
699               dump_attribs(uid,pk,sk);
700
701             if(!any && newformat)
702               printf("\n");
703
704             if(uid->is_revoked || uid->is_expired)
705               printf("uid%*s[%s] ",
706                      (opt.list_options&LIST_SHOW_LONG_KEYIDS)?16:8,"",
707                      uid->is_revoked?_("revoked"):_("expired"));
708             else if((opt.list_options&LIST_SHOW_VALIDITY) && pk)
709               {
710                 const char *validity=
711                   trust_value_to_string(get_validity(pk,uid));
712
713                 /* Includes the 3 spaces for [, ], and " ". */
714                 indent=((opt.list_options&LIST_SHOW_LONG_KEYIDS)?23:15)
715                   -strlen(validity);
716
717                 if(indent<0)
718                   indent=0;
719
720                 printf("uid%*s[%s] ",indent,"",validity);
721               }
722             else if(newformat)
723               printf("uid%*s",
724                      (opt.list_options&LIST_SHOW_LONG_KEYIDS)?26:18,"");
725             else if(any)
726               printf("uid%*s",29,"");
727
728             print_utf8_string( stdout, uid->name, uid->len );
729             putchar('\n');
730             if( !any ) {
731                 if( fpr )
732                     print_fingerprint( pk, sk, 0 );
733                 if( opt.with_key_data )
734                     print_key_data( pk, keyid );
735                 any = 1;
736             }
737
738             if((opt.list_options&LIST_SHOW_PHOTOS) && uid->attribs!=NULL)
739               show_photos(uid->attribs,uid->numattribs,pk,sk);
740         }
741         else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
742             u32 keyid2[2];
743             PKT_public_key *pk2 = node->pkt->pkt.public_key;
744
745             if( !any ) {
746                 putchar('\n');
747                 if( fpr )
748                     print_fingerprint( pk, sk, 0 ); /* of the main key */
749                 any = 1;
750             }
751
752             keyid_from_pk( pk2, keyid2 );
753             printf("sub   %4u%c/",
754                    nbits_from_pk( pk2 ),pubkey_letter( pk2->pubkey_algo ));
755             if(opt.list_options&LIST_SHOW_LONG_KEYIDS)
756               printf("%08lX%08lX",(ulong)keyid2[0],(ulong)keyid2[1]);
757             else
758               printf("%08lX",(ulong)keyid2[1]);
759             printf(" %s",datestr_from_pk(pk2));
760             if( pk2->is_revoked )
761               printf(_(" [revoked: %s]"), revokestr_from_pk(pk2));
762             else if( pk2->has_expired )
763                 printf(_(" [expired: %s]"), expirestr_from_pk( pk2 ) );
764             else if( pk2->expiredate )
765                 printf(_(" [expires: %s]"), expirestr_from_pk( pk2 ) );
766             putchar('\n');
767             if( fpr > 1 )
768                 print_fingerprint( pk2, NULL, 0 );
769             if( opt.with_key_data )
770                 print_key_data( pk2, keyid2 );
771         }
772         else if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
773             u32 keyid2[2];
774             PKT_secret_key *sk2 = node->pkt->pkt.secret_key;
775
776             if( !any ) {
777                 putchar('\n');
778                 if( fpr )
779                     print_fingerprint( pk, sk, 0 ); /* of the main key */
780                 any = 1;
781             }
782
783             keyid_from_sk( sk2, keyid2 );
784             printf("ssb%c  %4u%c/",
785                    (sk->protect.s2k.mode==1001)?'#':
786                    (sk->protect.s2k.mode==1002)?'>':' ',
787                    nbits_from_sk( sk2 ),pubkey_letter( sk2->pubkey_algo ));
788             if(opt.list_options&LIST_SHOW_LONG_KEYIDS)
789               printf("%08lX%08lX",(ulong)keyid2[0],(ulong)keyid2[1]);
790             else
791               printf("%08lX",(ulong)keyid2[1]);
792             printf(" %s",datestr_from_sk( sk2 ) );
793             if( sk2->expiredate )
794               printf(_(" [expires: %s]"), expirestr_from_sk( sk2 ) );
795             putchar('\n');
796             if( fpr > 1 )
797                 print_fingerprint( NULL, sk2, 0 );
798         }
799         else if( opt.list_sigs
800                  && node->pkt->pkttype == PKT_SIGNATURE
801                  && !skip_sigs ) {
802             PKT_signature *sig = node->pkt->pkt.signature;
803             int sigrc;
804             char *sigstr;
805
806             if( stats ) {
807                 /*fflush(stdout);*/
808                 rc = check_key_signature( keyblock, node, NULL );
809                 switch( rc ) {
810                  case 0:                 sigrc = '!'; break;
811                  case G10ERR_BAD_SIGN:   stats->inv_sigs++; sigrc = '-'; break;
812                  case G10ERR_NO_PUBKEY: 
813                  case G10ERR_UNU_PUBKEY: stats->no_key++; continue;
814                  default:                stats->oth_err++; sigrc = '%'; break;
815                 }
816
817                 /* TODO: Make sure a cached sig record here still has
818                    the pk that issued it.  See also
819                    keyedit.c:print_and_check_one_sig */
820
821             }
822             else {
823                 rc = 0;
824                 sigrc = ' ';
825             }
826
827             if( !any ) { /* no user id, (maybe a revocation follows)*/
828               /* Check if the pk is really revoked - there could be a
829                  0x20 sig packet there even if we are not revoked
830                  (say, if a revocation key issued the packet, but the
831                  revocation key isn't present to verify it.) */
832                 if( sig->sig_class == 0x20 && pk->is_revoked )
833                     puts("[revoked]");
834                 else if( sig->sig_class == 0x18 )
835                     puts("[key binding]");
836                 else if( sig->sig_class == 0x28 )
837                     puts("[subkey revoked]");
838                 else
839                     putchar('\n');
840                 if( fpr )
841                     print_fingerprint( pk, sk, 0 );
842                 any=1;
843             }
844
845             if( sig->sig_class == 0x20 || sig->sig_class == 0x28
846                                        || sig->sig_class == 0x30 )
847                sigstr = "rev";
848             else if( (sig->sig_class&~3) == 0x10 )
849                sigstr = "sig";
850             else if( sig->sig_class == 0x18 )
851                sigstr = "sig";
852             else if( sig->sig_class == 0x1F )
853                sigstr = "sig";
854             else {
855                 printf("sig                             "
856                        "[unexpected signature class 0x%02x]\n",sig->sig_class );
857                 continue;
858             }
859
860             fputs( sigstr, stdout );
861             printf("%c%c %c%c%c%c%c%c ",
862                    sigrc,(sig->sig_class-0x10>0 &&
863                           sig->sig_class-0x10<4)?'0'+sig->sig_class-0x10:' ',
864                    sig->flags.exportable?' ':'L',
865                    sig->flags.revocable?' ':'R',
866                    sig->flags.policy_url?'P':' ',
867                    sig->flags.notation?'N':' ',
868                    sig->flags.expired?'X':' ',
869                    (sig->trust_depth>9)?'T':
870                    (sig->trust_depth>0)?'0'+sig->trust_depth:' ');
871             if(opt.list_options&LIST_SHOW_LONG_KEYIDS)
872               printf("%08lX%08lX",(ulong)sig->keyid[0],(ulong)sig->keyid[1]);
873             else
874               printf("%08lX",(ulong)sig->keyid[1]);
875             printf(" %s", datestr_from_sig(sig));
876             if(opt.list_options&LIST_SHOW_SIG_EXPIRE)
877               printf(" %s", expirestr_from_sig(sig));
878             printf("  ");
879             if( sigrc == '%' )
880                 printf("[%s] ", g10_errstr(rc) );
881             else if( sigrc == '?' )
882                 ;
883             else if ( !opt.fast_list_mode ) {
884                 size_t n;
885                 char *p = get_user_id( sig->keyid, &n );
886                 print_utf8_string( stdout, p, n );
887                 m_free(p);
888             }
889             putchar('\n');
890
891             if(sig->flags.policy_url
892                && (opt.list_options&LIST_SHOW_POLICY_URLS))
893               show_policy_url(sig,3,0);
894
895             if(sig->flags.notation
896                && (opt.list_options&LIST_SHOW_NOTATIONS))
897               show_notation(sig,3,0);
898
899             if(sig->flags.pref_ks
900                && (opt.list_options&LIST_SHOW_KEYSERVER_URLS))
901               show_keyserver_url(sig,3,0);
902
903             /* fixme: check or list other sigs here */
904         }
905     }
906     putchar('\n');
907 }
908
909
910 static void
911 list_keyblock_colon( KBNODE keyblock, int secret, int fpr )
912 {
913     int rc = 0;
914     KBNODE kbctx;
915     KBNODE node;
916     PKT_public_key *pk;
917     PKT_secret_key *sk;
918     u32 keyid[2];
919     int any=0;
920     int trustletter = 0;
921     int ulti_hack = 0;
922     int i;
923
924     /* get the keyid from the keyblock */
925     node = find_kbnode( keyblock, secret? PKT_SECRET_KEY : PKT_PUBLIC_KEY );
926     if( !node ) {
927         log_error("Oops; key lost!\n");
928         dump_kbnode( keyblock );
929         return;
930     }
931
932     if( secret ) {
933         pk = NULL;
934         sk = node->pkt->pkt.secret_key;
935         keyid_from_sk( sk, keyid );
936         printf("sec::%u:%d:%08lX%08lX:%s:%s:::",
937                     nbits_from_sk( sk ),
938                     sk->pubkey_algo,
939                     (ulong)keyid[0],(ulong)keyid[1],
940                     colon_datestr_from_sk( sk ),
941                     colon_strtime (sk->expiredate)
942                     /* fixme: add LID here */ );
943     }
944     else {
945         pk = node->pkt->pkt.public_key;
946         sk = NULL;
947         keyid_from_pk( pk, keyid );
948         fputs( "pub:", stdout );
949         if ( !pk->is_valid )
950             putchar ('i');
951         else if ( pk->is_revoked )
952             putchar ('r');
953         else if ( pk->has_expired )
954             putchar ('e');
955         else if ( opt.fast_list_mode || opt.no_expensive_trust_checks ) 
956             ;
957         else {
958             trustletter = get_validity_info ( pk, NULL );
959             if( trustletter == 'u' )
960                 ulti_hack = 1;
961             putchar(trustletter);
962         }
963         printf(":%u:%d:%08lX%08lX:%s:%s::",
964                     nbits_from_pk( pk ),
965                     pk->pubkey_algo,
966                     (ulong)keyid[0],(ulong)keyid[1],
967                     colon_datestr_from_pk( pk ),
968                     colon_strtime (pk->expiredate) );
969         if( !opt.fast_list_mode && !opt.no_expensive_trust_checks  )
970             putchar( get_ownertrust_info(pk) );
971             putchar(':');
972     }
973     
974     if (opt.fixed_list_mode) {
975         /* do not merge the first uid with the primary key */
976         putchar(':');
977         putchar(':');
978         print_capabilities (pk, sk, keyblock);
979         if (secret) {
980           putchar(':'); /* End of field 13. */
981           putchar(':'); /* End of field 14. */
982           if (sk->protect.s2k.mode == 1001)
983             putchar('#'); /* Key is just a stub. */
984           else if (sk->protect.s2k.mode == 1002) {
985             /* Key is stored on an external token (card) or handled by
986                the gpg-agent.  Print the serial number of that token
987                here. */
988             for (i=0; i < sk->protect.ivlen; i++)
989               printf ("%02X", sk->protect.iv[i]);
990           }
991           putchar(':'); /* End of field 15. */
992         }
993         putchar('\n');
994         if( fpr )
995             print_fingerprint( pk, sk, 0 );
996         if( opt.with_key_data )
997             print_key_data( pk, keyid );
998         any = 1;
999     }
1000
1001
1002     for( kbctx=NULL; (node=walk_kbnode( keyblock, &kbctx, 0)) ; ) {
1003         if( node->pkt->pkttype == PKT_USER_ID && !opt.fast_list_mode ) {
1004             PKT_user_id *uid=node->pkt->pkt.user_id;
1005             if(attrib_fp && node->pkt->pkt.user_id->attrib_data!=NULL)
1006               dump_attribs(node->pkt->pkt.user_id,pk,sk);
1007             /*
1008              * Fixme: We need a is_valid flag here too 
1009              */
1010             if( any ) {
1011                 char *str=uid->attrib_data?"uat":"uid";
1012                 /* If we're listing a secret key, leave out the
1013                    validity values for now.  This is handled better in
1014                    1.9. */
1015                 if ( sk )
1016                     printf("%s:::::",str);
1017                 else if ( uid->is_revoked )
1018                     printf("%s:r::::",str);
1019                 else if ( uid->is_expired )
1020                     printf("%s:e::::",str);
1021                 else if ( opt.no_expensive_trust_checks )
1022                     printf("%s:::::",str);
1023                 else {
1024                     int uid_validity;
1025
1026                     if( pk && !ulti_hack )
1027                       uid_validity=get_validity_info (pk, uid);
1028                     else
1029                         uid_validity = 'u';
1030                     printf("%s:%c::::",str,uid_validity);
1031                 }
1032
1033                 printf("%s:",colon_strtime(uid->created));
1034                 printf("%s:",colon_strtime(uid->expiredate));
1035
1036                 namehash_from_uid(uid);
1037
1038                 for(i=0; i < 20; i++ )
1039                   printf("%02X",uid->namehash[i]);
1040
1041                 printf("::");
1042             }
1043             if(uid->attrib_data)
1044               printf("%u %lu",uid->numattribs,uid->attrib_len);
1045             else
1046               print_string(stdout,uid->name,uid->len, ':' );
1047             putchar(':');
1048             if (any)
1049                 putchar('\n');
1050             else {
1051                 putchar(':');
1052                 print_capabilities (pk, sk, keyblock);
1053                 putchar('\n');
1054                 if( fpr )
1055                     print_fingerprint( pk, sk, 0 );
1056                 if( opt.with_key_data )
1057                     print_key_data( pk, keyid );
1058                 any = 1;
1059             }
1060         }
1061         else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
1062             u32 keyid2[2];
1063             PKT_public_key *pk2 = node->pkt->pkt.public_key;
1064
1065             if( !any ) {
1066                 putchar(':');
1067                 putchar(':');
1068                 print_capabilities (pk, sk, keyblock);
1069                 putchar('\n');
1070                 if( fpr )
1071                     print_fingerprint( pk, sk, 0 ); /* of the main key */
1072                 any = 1;
1073             }
1074
1075             keyid_from_pk( pk2, keyid2 );
1076             fputs ("sub:", stdout );
1077             if ( !pk2->is_valid )
1078                 putchar ('i');
1079             else if ( pk2->is_revoked )
1080                 putchar ('r');
1081             else if ( pk2->has_expired )
1082                 putchar ('e');
1083             else if ( opt.fast_list_mode || opt.no_expensive_trust_checks )
1084                 ;
1085             else {
1086                 /* trustletter should always be defined here */
1087                 if(trustletter)
1088                   printf("%c", trustletter );
1089             }
1090             printf(":%u:%d:%08lX%08lX:%s:%s:::::",
1091                         nbits_from_pk( pk2 ),
1092                         pk2->pubkey_algo,
1093                         (ulong)keyid2[0],(ulong)keyid2[1],
1094                         colon_datestr_from_pk( pk2 ),
1095                         colon_strtime (pk2->expiredate)
1096                         /* fixme: add LID and ownertrust here */
1097                                                 );
1098             print_capabilities (pk2, NULL, NULL);
1099             putchar('\n');
1100             if( fpr > 1 )
1101                 print_fingerprint( pk2, NULL, 0 );
1102             if( opt.with_key_data )
1103                 print_key_data( pk2, keyid2 );
1104         }
1105         else if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
1106             u32 keyid2[2];
1107             PKT_secret_key *sk2 = node->pkt->pkt.secret_key;
1108
1109             if( !any ) {
1110                 putchar(':');
1111                 putchar(':');
1112                 print_capabilities (pk, sk, keyblock);
1113                 putchar('\n');
1114                 if( fpr )
1115                     print_fingerprint( pk, sk, 0 ); /* of the main key */
1116                 any = 1;
1117             }
1118
1119             keyid_from_sk( sk2, keyid2 );
1120             printf("ssb::%u:%d:%08lX%08lX:%s:%s:::::",
1121                         nbits_from_sk( sk2 ),
1122                         sk2->pubkey_algo,
1123                         (ulong)keyid2[0],(ulong)keyid2[1],
1124                         colon_datestr_from_sk( sk2 ),
1125                         colon_strtime (sk2->expiredate)
1126                    /* fixme: add LID */ );
1127             print_capabilities (NULL, sk2, NULL);
1128             if (opt.fixed_list_mode) {
1129               /* We print the serial number only in fixed list mode
1130                  for the primary key so, so avoid questions we print
1131                  it for subkeys also only in this mode.  There is no
1132                  technical reason, though. */
1133               putchar(':'); /* End of field 13. */
1134               putchar(':'); /* End of field 14. */
1135               if (sk2->protect.s2k.mode == 1001)
1136                 putchar('#'); /* Key is just a stub. */
1137               else if (sk2->protect.s2k.mode == 1002) {
1138                 /* Key is stored on an external token (card) or handled by
1139                    the gpg-agent.  Print the serial number of that token
1140                    here. */
1141                 for (i=0; i < sk2->protect.ivlen; i++)
1142                   printf ("%02X", sk2->protect.iv[i]);
1143               }
1144               putchar(':'); /* End of field 15. */
1145             }
1146             putchar ('\n');
1147             if( fpr > 1 )
1148               print_fingerprint( NULL, sk2, 0 );
1149         }
1150         else if( opt.list_sigs && node->pkt->pkttype == PKT_SIGNATURE ) {
1151             PKT_signature *sig = node->pkt->pkt.signature;
1152             int sigrc,fprokay=0;
1153             char *sigstr;
1154             size_t fplen;
1155             byte fparray[MAX_FINGERPRINT_LEN];
1156
1157             if( !any ) { /* no user id, (maybe a revocation follows)*/
1158                 if( sig->sig_class == 0x20 )
1159                     fputs("[revoked]:", stdout);
1160                 else if( sig->sig_class == 0x18 )
1161                     fputs("[key binding]:", stdout);
1162                 else if( sig->sig_class == 0x28 )
1163                     fputs("[subkey revoked]:", stdout);
1164                 else
1165                     putchar (':');
1166                 putchar(':');
1167                 print_capabilities (pk, sk, keyblock);
1168                 putchar('\n');
1169                 if( fpr )
1170                     print_fingerprint( pk, sk, 0 );
1171                 any=1;
1172             }
1173
1174             if( sig->sig_class == 0x20 || sig->sig_class == 0x28
1175                                        || sig->sig_class == 0x30 )
1176                sigstr = "rev";
1177             else if( (sig->sig_class&~3) == 0x10 )
1178                sigstr = "sig";
1179             else if( sig->sig_class == 0x18 )
1180                sigstr = "sig";
1181             else if( sig->sig_class == 0x1F )
1182                sigstr = "sig";
1183             else {
1184                 printf ("sig::::::::::%02x%c:\n",
1185                         sig->sig_class, sig->flags.exportable?'x':'l');
1186                 continue;
1187             }
1188             if( opt.check_sigs ) {
1189                 PKT_public_key *signer_pk=NULL;
1190
1191                 fflush(stdout);
1192                 if(opt.no_sig_cache)
1193                   signer_pk=m_alloc_clear(sizeof(PKT_public_key));
1194
1195                 rc = check_key_signature2( keyblock, node, NULL, signer_pk,
1196                                            NULL, NULL, NULL );
1197                 switch( rc ) {
1198                   case 0:                  sigrc = '!'; break;
1199                   case G10ERR_BAD_SIGN:    sigrc = '-'; break;
1200                   case G10ERR_NO_PUBKEY: 
1201                   case G10ERR_UNU_PUBKEY:  sigrc = '?'; break;
1202                   default:                 sigrc = '%'; break;
1203                 }
1204
1205                 if(opt.no_sig_cache)
1206                   {
1207                     if(rc==0)
1208                       {
1209                         fingerprint_from_pk (signer_pk, fparray, &fplen);
1210                         fprokay=1;
1211                       }
1212                     free_public_key(signer_pk);
1213                   }
1214             }
1215             else {
1216                 rc = 0;
1217                 sigrc = ' ';
1218             }
1219             fputs( sigstr, stdout );
1220             putchar(':');
1221             if( sigrc != ' ' )
1222                 putchar(sigrc);
1223             printf("::%d:%08lX%08lX:%s:%s:", sig->pubkey_algo,
1224                    (ulong)sig->keyid[0], (ulong)sig->keyid[1],
1225                    colon_datestr_from_sig(sig),
1226                    colon_expirestr_from_sig(sig));
1227
1228             if(sig->trust_depth || sig->trust_value)
1229               printf("%d %d",sig->trust_depth,sig->trust_value);
1230             printf(":");
1231
1232             if(sig->trust_regexp)
1233               print_string(stdout,sig->trust_regexp,
1234                            strlen(sig->trust_regexp),':');
1235             printf(":");
1236
1237             if( sigrc == '%' )
1238                 printf("[%s] ", g10_errstr(rc) );
1239             else if( sigrc == '?' )
1240                 ;
1241             else if ( !opt.fast_list_mode ) {
1242                 size_t n;
1243                 char *p = get_user_id( sig->keyid, &n );
1244                 print_string( stdout, p, n, ':' );
1245                 m_free(p);
1246             }
1247             printf(":%02x%c:", sig->sig_class,sig->flags.exportable?'x':'l');
1248
1249             if(opt.no_sig_cache && opt.check_sigs && fprokay)
1250               {
1251                 printf(":");
1252
1253                 for (i=0; i < fplen ; i++ )
1254                   printf ("%02X", fparray[i] );
1255
1256                 printf(":");
1257               }
1258
1259             printf("\n");
1260
1261             /* fixme: check or list other sigs here */
1262         }
1263     }
1264     if( !any ) {/* oops, no user id */
1265         putchar(':');
1266         putchar(':');
1267         print_capabilities (pk, sk, keyblock);
1268         putchar('\n');
1269     }
1270 }
1271
1272 /*
1273  * Reorder the keyblock so that the primary user ID (and not attribute
1274  * packet) comes first.  Fixme: Replace this by a generic sort
1275  * function.  */
1276 void
1277 reorder_keyblock (KBNODE keyblock)
1278 {
1279     KBNODE primary = NULL, primary0 = NULL, primary2 = NULL;
1280     KBNODE last, node;
1281
1282     for (node=keyblock; node; primary0=node, node = node->next) {
1283         if( node->pkt->pkttype == PKT_USER_ID &&
1284             !node->pkt->pkt.user_id->attrib_data &&
1285             node->pkt->pkt.user_id->is_primary ) {
1286             primary = primary2 = node;
1287             for (node=node->next; node; primary2=node, node = node->next ) {
1288                 if( node->pkt->pkttype == PKT_USER_ID 
1289                     || node->pkt->pkttype == PKT_PUBLIC_SUBKEY 
1290                     || node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
1291                     break;
1292                 }
1293             }
1294             break;
1295         }
1296     }
1297     if ( !primary )
1298         return;  /* no primary key flag found (should not happen) */
1299
1300     for (last=NULL, node=keyblock; node; last = node, node = node->next) {
1301         if( node->pkt->pkttype == PKT_USER_ID )
1302             break;
1303     }
1304     assert (node);
1305     assert (last); /* the user ID is never the first packet */
1306     assert (primary0);  /* ditto (this is the node before primary) */
1307     if ( node == primary )
1308         return; /* already the first one */
1309
1310     last->next = primary;
1311     primary0->next = primary2->next;
1312     primary2->next = node;
1313 }
1314
1315 void
1316 list_keyblock( KBNODE keyblock, int secret, int fpr, void *opaque )
1317 {
1318     reorder_keyblock (keyblock);
1319     if (opt.with_colons)
1320         list_keyblock_colon (keyblock, secret, fpr );
1321     else
1322         list_keyblock_print (keyblock, secret, fpr, opaque );
1323 }
1324
1325 /*
1326  * standard function to print the finperprint.
1327  * mode 0: as used in key listings, opt.with_colons is honored
1328  *      1: print using log_info ()
1329  *      2: direct use of tty
1330  *      3: direct use of tty but only primary key.
1331  * modes 1 and 2 will try and print both subkey and primary key fingerprints
1332  */
1333 void
1334 print_fingerprint (PKT_public_key *pk, PKT_secret_key *sk, int mode )
1335 {
1336     byte array[MAX_FINGERPRINT_LEN], *p;
1337     size_t i, n;
1338     FILE *fp;
1339     const char *text;
1340     int primary=0;
1341
1342     if(sk)
1343       {
1344         if(sk->main_keyid[0]==sk->keyid[0] && sk->main_keyid[1]==sk->keyid[1])
1345           primary=1;
1346       }
1347     else
1348       {
1349         if(pk->main_keyid[0]==pk->keyid[0] && pk->main_keyid[1]==pk->keyid[1])
1350           primary=1;
1351       }
1352
1353     /* Just to be safe */
1354     if(mode&0x80 && !primary)
1355       {
1356         log_error("primary key is not really primary!\n");
1357         return;
1358       }
1359
1360     mode&=~0x80;
1361
1362     if(!primary && (mode==1 || mode==2))
1363       {
1364         if(sk)
1365           {
1366             PKT_secret_key *primary_sk=m_alloc_clear(sizeof(*primary_sk));
1367             get_seckey(primary_sk,sk->main_keyid);
1368             print_fingerprint(NULL,primary_sk,mode|0x80);
1369             free_secret_key(primary_sk);
1370           }
1371         else
1372           {
1373             PKT_public_key *primary_pk=m_alloc_clear(sizeof(*primary_pk));
1374             get_pubkey(primary_pk,pk->main_keyid);
1375             print_fingerprint(primary_pk,NULL,mode|0x80);
1376             free_public_key(primary_pk);
1377           }
1378       }
1379
1380     if (mode == 1) {
1381         fp = log_stream ();
1382         if(primary)
1383           text = _("Primary key fingerprint:");
1384         else
1385           text = _("     Subkey fingerprint:");
1386     }
1387     else if (mode == 2) {
1388         fp = NULL; /* use tty */
1389         /* Translators: this should fit into 24 bytes to that the fingerprint
1390          * data is properly aligned with the user ID */
1391         if(primary)
1392           text = _(" Primary key fingerprint:");
1393         else
1394           text = _("      Subkey fingerprint:");
1395     }
1396     else if (mode == 3) {
1397         fp = NULL; /* use tty */
1398         text = _("      Key fingerprint =");
1399     }
1400     else {
1401         fp = stdout;
1402         text = _("      Key fingerprint =");
1403     }
1404   
1405     if (sk)
1406         fingerprint_from_sk (sk, array, &n);
1407     else
1408         fingerprint_from_pk (pk, array, &n);
1409     p = array;
1410     if (opt.with_colons && !mode) {
1411         fprintf (fp, "fpr:::::::::");
1412         for (i=0; i < n ; i++, p++ )
1413             fprintf (fp, "%02X", *p );
1414         putc(':', fp);
1415     }
1416     else {
1417         if (fp)
1418             fputs (text, fp);
1419         else
1420             tty_printf ("%s", text);
1421         if (n == 20) {
1422             for (i=0; i < n ; i++, i++, p += 2 ) {
1423                 if (fp) {
1424                     if (i == 10 )
1425                         putc(' ', fp);
1426                     fprintf (fp, " %02X%02X", *p, p[1] );
1427                 }
1428                 else {
1429                     if (i == 10 )
1430                         tty_printf (" ");
1431                     tty_printf (" %02X%02X", *p, p[1]);
1432                 }
1433             }
1434         }
1435         else {
1436             for (i=0; i < n ; i++, p++ ) {
1437                 if (fp) {
1438                     if (i && !(i%8) )
1439                         putc (' ', fp);
1440                     fprintf (fp, " %02X", *p );
1441                 }
1442                 else {
1443                     if (i && !(i%8) )
1444                         tty_printf (" ");
1445                     tty_printf (" %02X", *p );
1446                 }
1447             }
1448         }
1449     }
1450     if (fp)
1451         putc ('\n', fp);
1452     else
1453         tty_printf ("\n");
1454 }
1455
1456 void set_attrib_fd(int fd)
1457 {
1458   static int last_fd=-1;
1459
1460   if ( fd != -1 && last_fd == fd )
1461     return;
1462
1463   if ( attrib_fp && attrib_fp != stdout && attrib_fp != stderr )
1464     fclose (attrib_fp);
1465   attrib_fp = NULL;
1466   if ( fd == -1 ) 
1467     return;
1468
1469   if( fd == 1 )
1470     attrib_fp = stdout;
1471   else if( fd == 2 )
1472     attrib_fp = stderr;
1473   else
1474     attrib_fp = fdopen( fd, "wb" );
1475   if( !attrib_fp ) {
1476     log_fatal("can't open fd %d for attribute output: %s\n",
1477               fd, strerror(errno));
1478   }
1479
1480   last_fd = fd;
1481 }