* keygen.c (keygen_set_std_prefs): Build the default preferences list at
[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 && pk->expiredate)
666           printf(_(" [expires: %s]"), expirestr_from_pk( pk ) );
667
668 #if 0
669         /* I need to think about this some more.  It's easy enough to
670            include, but it looks sort of confusing in the
671            listing... */
672         if(opt.list_options&LIST_SHOW_VALIDITY)
673           printf(" [%s]",trust_value_to_string(validity));
674 #endif
675       }
676
677     for( kbctx=NULL; (node=walk_kbnode( keyblock, &kbctx, 0)) ; ) {
678         if( node->pkt->pkttype == PKT_USER_ID && !opt.fast_list_mode ) {
679             int indent;
680             PKT_user_id *uid=node->pkt->pkt.user_id;
681
682             if((uid->is_expired || uid->is_revoked)
683                && !(opt.list_options&LIST_SHOW_UNUSABLE_UIDS))
684               {
685                 skip_sigs=1;
686                 continue;
687               }
688             else
689               skip_sigs=0;
690
691             if(attrib_fp && uid->attrib_data!=NULL)
692               dump_attribs(uid,pk,sk);
693
694             if(!any && newformat)
695               printf("\n");
696
697             if(uid->is_revoked || uid->is_expired)
698               printf("uid%*s[%s] ",
699                      (opt.list_options&LIST_SHOW_LONG_KEYIDS)?16:8,"",
700                      uid->is_revoked?"revoked":"expired");
701             else if((opt.list_options&LIST_SHOW_VALIDITY) && pk)
702               {
703                 const char *validity=
704                   trust_value_to_string(get_validity(pk,uid));
705
706                 /* Includes the 3 spaces for [, ], and " ". */
707                 indent=((opt.list_options&LIST_SHOW_LONG_KEYIDS)?23:15)
708                   -strlen(validity);
709
710                 if(indent<0)
711                   indent=0;
712
713                 printf("uid%*s[%s] ",indent,"",validity);
714               }
715             else if(newformat)
716               printf("uid%*s",
717                      (opt.list_options&LIST_SHOW_LONG_KEYIDS)?26:18,"");
718             else if(any)
719               printf("uid%*s",29,"");
720
721             print_utf8_string( stdout, uid->name, uid->len );
722             putchar('\n');
723             if( !any ) {
724                 if( fpr )
725                     print_fingerprint( pk, sk, 0 );
726                 if( opt.with_key_data )
727                     print_key_data( pk, keyid );
728                 any = 1;
729             }
730
731             if((opt.list_options&LIST_SHOW_PHOTOS) && uid->attribs!=NULL)
732               show_photos(uid->attribs,uid->numattribs,pk,sk);
733         }
734         else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
735             u32 keyid2[2];
736             PKT_public_key *pk2 = node->pkt->pkt.public_key;
737
738             if( !any ) {
739                 putchar('\n');
740                 if( fpr )
741                     print_fingerprint( pk, sk, 0 ); /* of the main key */
742                 any = 1;
743             }
744
745             keyid_from_pk( pk2, keyid2 );
746             printf("sub   %4u%c/",
747                    nbits_from_pk( pk2 ),pubkey_letter( pk2->pubkey_algo ));
748             if(opt.list_options&LIST_SHOW_LONG_KEYIDS)
749               printf("%08lX%08lX",(ulong)keyid2[0],(ulong)keyid2[1]);
750             else
751               printf("%08lX",(ulong)keyid2[1]);
752             printf(" %s",datestr_from_pk(pk2));
753             /* Yes, this is an odd way to print the revoked string,
754                but we already have translations for "[revoked] " (with
755                the trailing space) and this is a simple way to take
756                advantage of it.  In devel, this will be done rather
757                more elegantly. */
758             if( pk2->is_revoked )
759                 printf(" %s",_("[revoked] "));
760             else if( pk2->expiredate )
761                 printf(_(" [expires: %s]"), expirestr_from_pk( pk2 ) );
762             putchar('\n');
763             if( fpr > 1 )
764                 print_fingerprint( pk2, NULL, 0 );
765             if( opt.with_key_data )
766                 print_key_data( pk2, keyid2 );
767         }
768         else if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
769             u32 keyid2[2];
770             PKT_secret_key *sk2 = node->pkt->pkt.secret_key;
771
772             if( !any ) {
773                 putchar('\n');
774                 if( fpr )
775                     print_fingerprint( pk, sk, 0 ); /* of the main key */
776                 any = 1;
777             }
778
779             keyid_from_sk( sk2, keyid2 );
780             printf("ssb%c  %4u%c/",
781                    (sk->protect.s2k.mode==1001)?'#':
782                    (sk->protect.s2k.mode==1002)?'>':' ',
783                    nbits_from_sk( sk2 ),pubkey_letter( sk2->pubkey_algo ));
784             if(opt.list_options&LIST_SHOW_LONG_KEYIDS)
785               printf("%08lX%08lX",(ulong)keyid2[0],(ulong)keyid2[1]);
786             else
787               printf("%08lX",(ulong)keyid2[1]);
788             printf(" %s",datestr_from_sk( sk2 ) );
789             if( sk2->expiredate )
790               printf(_(" [expires: %s]"), expirestr_from_sk( sk2 ) );
791             putchar('\n');
792             if( fpr > 1 )
793                 print_fingerprint( NULL, sk2, 0 );
794         }
795         else if( opt.list_sigs
796                  && node->pkt->pkttype == PKT_SIGNATURE
797                  && !skip_sigs ) {
798             PKT_signature *sig = node->pkt->pkt.signature;
799             int sigrc;
800             char *sigstr;
801
802             if( stats ) {
803                 /*fflush(stdout);*/
804                 rc = check_key_signature( keyblock, node, NULL );
805                 switch( rc ) {
806                  case 0:                 sigrc = '!'; break;
807                  case G10ERR_BAD_SIGN:   stats->inv_sigs++; sigrc = '-'; break;
808                  case G10ERR_NO_PUBKEY: 
809                  case G10ERR_UNU_PUBKEY: stats->no_key++; continue;
810                  default:                stats->oth_err++; sigrc = '%'; break;
811                 }
812
813                 /* TODO: Make sure a cached sig record here still has
814                    the pk that issued it.  See also
815                    keyedit.c:print_and_check_one_sig */
816
817             }
818             else {
819                 rc = 0;
820                 sigrc = ' ';
821             }
822
823             if( !any ) { /* no user id, (maybe a revocation follows)*/
824               /* Check if the pk is really revoked - there could be a
825                  0x20 sig packet there even if we are not revoked
826                  (say, if a revocation key issued the packet, but the
827                  revocation key isn't present to verify it.) */
828                 if( sig->sig_class == 0x20 && pk->is_revoked )
829                     puts("[revoked]");
830                 else if( sig->sig_class == 0x18 )
831                     puts("[key binding]");
832                 else if( sig->sig_class == 0x28 )
833                     puts("[subkey revoked]");
834                 else
835                     putchar('\n');
836                 if( fpr )
837                     print_fingerprint( pk, sk, 0 );
838                 any=1;
839             }
840
841             if( sig->sig_class == 0x20 || sig->sig_class == 0x28
842                                        || sig->sig_class == 0x30 )
843                sigstr = "rev";
844             else if( (sig->sig_class&~3) == 0x10 )
845                sigstr = "sig";
846             else if( sig->sig_class == 0x18 )
847                sigstr = "sig";
848             else if( sig->sig_class == 0x1F )
849                sigstr = "sig";
850             else {
851                 printf("sig                             "
852                        "[unexpected signature class 0x%02x]\n",sig->sig_class );
853                 continue;
854             }
855
856             fputs( sigstr, stdout );
857             printf("%c%c %c%c%c%c%c%c ",
858                    sigrc,(sig->sig_class-0x10>0 &&
859                           sig->sig_class-0x10<4)?'0'+sig->sig_class-0x10:' ',
860                    sig->flags.exportable?' ':'L',
861                    sig->flags.revocable?' ':'R',
862                    sig->flags.policy_url?'P':' ',
863                    sig->flags.notation?'N':' ',
864                    sig->flags.expired?'X':' ',
865                    (sig->trust_depth>9)?'T':
866                    (sig->trust_depth>0)?'0'+sig->trust_depth:' ');
867             if(opt.list_options&LIST_SHOW_LONG_KEYIDS)
868               printf("%08lX%08lX",(ulong)sig->keyid[0],(ulong)sig->keyid[1]);
869             else
870               printf("%08lX",(ulong)sig->keyid[1]);
871             printf(" %s", datestr_from_sig(sig));
872             if(opt.list_options&LIST_SHOW_SIG_EXPIRE)
873               printf(" %s", expirestr_from_sig(sig));
874             printf("  ");
875             if( sigrc == '%' )
876                 printf("[%s] ", g10_errstr(rc) );
877             else if( sigrc == '?' )
878                 ;
879             else if ( !opt.fast_list_mode ) {
880                 size_t n;
881                 char *p = get_user_id( sig->keyid, &n );
882                 print_utf8_string( stdout, p, n );
883                 m_free(p);
884             }
885             putchar('\n');
886
887             if(sig->flags.policy_url
888                && (opt.list_options&LIST_SHOW_POLICY_URLS))
889               show_policy_url(sig,3,0);
890
891             if(sig->flags.notation
892                && (opt.list_options&LIST_SHOW_NOTATIONS))
893               show_notation(sig,3,0);
894
895             if(sig->flags.pref_ks
896                && (opt.list_options&LIST_SHOW_KEYSERVER_URLS))
897               show_keyserver_url(sig,3,0);
898
899             /* fixme: check or list other sigs here */
900         }
901     }
902     putchar('\n');
903 }
904
905
906 static void
907 list_keyblock_colon( KBNODE keyblock, int secret, int fpr )
908 {
909     int rc = 0;
910     KBNODE kbctx;
911     KBNODE node;
912     PKT_public_key *pk;
913     PKT_secret_key *sk;
914     u32 keyid[2];
915     int any=0;
916     int trustletter = 0;
917     int ulti_hack = 0;
918     int i;
919
920     /* get the keyid from the keyblock */
921     node = find_kbnode( keyblock, secret? PKT_SECRET_KEY : PKT_PUBLIC_KEY );
922     if( !node ) {
923         log_error("Oops; key lost!\n");
924         dump_kbnode( keyblock );
925         return;
926     }
927
928     if( secret ) {
929         pk = NULL;
930         sk = node->pkt->pkt.secret_key;
931         keyid_from_sk( sk, keyid );
932         printf("sec::%u:%d:%08lX%08lX:%s:%s:::",
933                     nbits_from_sk( sk ),
934                     sk->pubkey_algo,
935                     (ulong)keyid[0],(ulong)keyid[1],
936                     colon_datestr_from_sk( sk ),
937                     colon_strtime (sk->expiredate)
938                     /* fixme: add LID here */ );
939     }
940     else {
941         pk = node->pkt->pkt.public_key;
942         sk = NULL;
943         keyid_from_pk( pk, keyid );
944         fputs( "pub:", stdout );
945         if ( !pk->is_valid )
946             putchar ('i');
947         else if ( pk->is_revoked )
948             putchar ('r');
949         else if ( pk->has_expired )
950             putchar ('e');
951         else if ( opt.fast_list_mode || opt.no_expensive_trust_checks ) 
952             ;
953         else {
954             trustletter = get_validity_info ( pk, NULL );
955             if( trustletter == 'u' )
956                 ulti_hack = 1;
957             putchar(trustletter);
958         }
959         printf(":%u:%d:%08lX%08lX:%s:%s::",
960                     nbits_from_pk( pk ),
961                     pk->pubkey_algo,
962                     (ulong)keyid[0],(ulong)keyid[1],
963                     colon_datestr_from_pk( pk ),
964                     colon_strtime (pk->expiredate) );
965         if( !opt.fast_list_mode && !opt.no_expensive_trust_checks  )
966             putchar( get_ownertrust_info(pk) );
967             putchar(':');
968     }
969     
970     if (opt.fixed_list_mode) {
971         /* do not merge the first uid with the primary key */
972         putchar(':');
973         putchar(':');
974         print_capabilities (pk, sk, keyblock);
975         if (secret) {
976           putchar(':'); /* End of field 13. */
977           putchar(':'); /* End of field 14. */
978           if (sk->protect.s2k.mode == 1001)
979             putchar('#'); /* Key is just a stub. */
980           else if (sk->protect.s2k.mode == 1002) {
981             /* Key is stored on an external token (card) or handled by
982                the gpg-agent.  Print the serial number of that token
983                here. */
984             for (i=0; i < sk->protect.ivlen; i++)
985               printf ("%02X", sk->protect.iv[i]);
986           }
987           putchar(':'); /* End of field 15. */
988         }
989         putchar('\n');
990         if( fpr )
991             print_fingerprint( pk, sk, 0 );
992         if( opt.with_key_data )
993             print_key_data( pk, keyid );
994         any = 1;
995     }
996
997
998     for( kbctx=NULL; (node=walk_kbnode( keyblock, &kbctx, 0)) ; ) {
999         if( node->pkt->pkttype == PKT_USER_ID && !opt.fast_list_mode ) {
1000             PKT_user_id *uid=node->pkt->pkt.user_id;
1001             if(attrib_fp && node->pkt->pkt.user_id->attrib_data!=NULL)
1002               dump_attribs(node->pkt->pkt.user_id,pk,sk);
1003             /*
1004              * Fixme: We need a is_valid flag here too 
1005              */
1006             if( any ) {
1007                 char *str=uid->attrib_data?"uat":"uid";
1008                 /* If we're listing a secret key, leave out the
1009                    validity values for now.  This is handled better in
1010                    1.9. */
1011                 if ( sk )
1012                     printf("%s:::::",str);
1013                 else if ( uid->is_revoked )
1014                     printf("%s:r::::",str);
1015                 else if ( uid->is_expired )
1016                     printf("%s:e::::",str);
1017                 else if ( opt.no_expensive_trust_checks )
1018                     printf("%s:::::",str);
1019                 else {
1020                     int uid_validity;
1021
1022                     if( pk && !ulti_hack )
1023                       uid_validity=get_validity_info (pk, uid);
1024                     else
1025                         uid_validity = 'u';
1026                     printf("%s:%c::::",str,uid_validity);
1027                 }
1028
1029                 printf("%s:",colon_strtime(uid->created));
1030                 printf("%s:",colon_strtime(uid->expiredate));
1031
1032                 namehash_from_uid(uid);
1033
1034                 for(i=0; i < 20; i++ )
1035                   printf("%02X",uid->namehash[i]);
1036
1037                 printf("::");
1038             }
1039             if(uid->attrib_data)
1040               printf("%u %lu",uid->numattribs,uid->attrib_len);
1041             else
1042               print_string(stdout,uid->name,uid->len, ':' );
1043             putchar(':');
1044             if (any)
1045                 putchar('\n');
1046             else {
1047                 putchar(':');
1048                 print_capabilities (pk, sk, keyblock);
1049                 putchar('\n');
1050                 if( fpr )
1051                     print_fingerprint( pk, sk, 0 );
1052                 if( opt.with_key_data )
1053                     print_key_data( pk, keyid );
1054                 any = 1;
1055             }
1056         }
1057         else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
1058             u32 keyid2[2];
1059             PKT_public_key *pk2 = node->pkt->pkt.public_key;
1060
1061             if( !any ) {
1062                 putchar(':');
1063                 putchar(':');
1064                 print_capabilities (pk, sk, keyblock);
1065                 putchar('\n');
1066                 if( fpr )
1067                     print_fingerprint( pk, sk, 0 ); /* of the main key */
1068                 any = 1;
1069             }
1070
1071             keyid_from_pk( pk2, keyid2 );
1072             fputs ("sub:", stdout );
1073             if ( !pk2->is_valid )
1074                 putchar ('i');
1075             else if ( pk2->is_revoked )
1076                 putchar ('r');
1077             else if ( pk2->has_expired )
1078                 putchar ('e');
1079             else if ( opt.fast_list_mode || opt.no_expensive_trust_checks )
1080                 ;
1081             else {
1082                 /* trustletter should always be defined here */
1083                 if(trustletter)
1084                   printf("%c", trustletter );
1085             }
1086             printf(":%u:%d:%08lX%08lX:%s:%s:::::",
1087                         nbits_from_pk( pk2 ),
1088                         pk2->pubkey_algo,
1089                         (ulong)keyid2[0],(ulong)keyid2[1],
1090                         colon_datestr_from_pk( pk2 ),
1091                         colon_strtime (pk2->expiredate)
1092                         /* fixme: add LID and ownertrust here */
1093                                                 );
1094             print_capabilities (pk2, NULL, NULL);
1095             putchar('\n');
1096             if( fpr > 1 )
1097                 print_fingerprint( pk2, NULL, 0 );
1098             if( opt.with_key_data )
1099                 print_key_data( pk2, keyid2 );
1100         }
1101         else if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
1102             u32 keyid2[2];
1103             PKT_secret_key *sk2 = node->pkt->pkt.secret_key;
1104
1105             if( !any ) {
1106                 putchar(':');
1107                 putchar(':');
1108                 print_capabilities (pk, sk, keyblock);
1109                 putchar('\n');
1110                 if( fpr )
1111                     print_fingerprint( pk, sk, 0 ); /* of the main key */
1112                 any = 1;
1113             }
1114
1115             keyid_from_sk( sk2, keyid2 );
1116             printf("ssb::%u:%d:%08lX%08lX:%s:%s:::::",
1117                         nbits_from_sk( sk2 ),
1118                         sk2->pubkey_algo,
1119                         (ulong)keyid2[0],(ulong)keyid2[1],
1120                         colon_datestr_from_sk( sk2 ),
1121                         colon_strtime (sk2->expiredate)
1122                    /* fixme: add LID */ );
1123             print_capabilities (NULL, sk2, NULL);
1124             if (opt.fixed_list_mode) {
1125               /* We print the serial number only in fixed list mode
1126                  for the primary key so, so avoid questions we print
1127                  it for subkeys also only in this mode.  There is no
1128                  technical reason, though. */
1129               putchar(':'); /* End of field 13. */
1130               putchar(':'); /* End of field 14. */
1131               if (sk2->protect.s2k.mode == 1001)
1132                 putchar('#'); /* Key is just a stub. */
1133               else if (sk2->protect.s2k.mode == 1002) {
1134                 /* Key is stored on an external token (card) or handled by
1135                    the gpg-agent.  Print the serial number of that token
1136                    here. */
1137                 for (i=0; i < sk2->protect.ivlen; i++)
1138                   printf ("%02X", sk2->protect.iv[i]);
1139               }
1140               putchar(':'); /* End of field 15. */
1141             }
1142             putchar ('\n');
1143             if( fpr > 1 )
1144               print_fingerprint( NULL, sk2, 0 );
1145         }
1146         else if( opt.list_sigs && node->pkt->pkttype == PKT_SIGNATURE ) {
1147             PKT_signature *sig = node->pkt->pkt.signature;
1148             int sigrc,fprokay=0;
1149             char *sigstr;
1150             size_t fplen;
1151             byte fparray[MAX_FINGERPRINT_LEN];
1152
1153             if( !any ) { /* no user id, (maybe a revocation follows)*/
1154                 if( sig->sig_class == 0x20 )
1155                     fputs("[revoked]:", stdout);
1156                 else if( sig->sig_class == 0x18 )
1157                     fputs("[key binding]:", stdout);
1158                 else if( sig->sig_class == 0x28 )
1159                     fputs("[subkey revoked]:", stdout);
1160                 else
1161                     putchar (':');
1162                 putchar(':');
1163                 print_capabilities (pk, sk, keyblock);
1164                 putchar('\n');
1165                 if( fpr )
1166                     print_fingerprint( pk, sk, 0 );
1167                 any=1;
1168             }
1169
1170             if( sig->sig_class == 0x20 || sig->sig_class == 0x28
1171                                        || sig->sig_class == 0x30 )
1172                sigstr = "rev";
1173             else if( (sig->sig_class&~3) == 0x10 )
1174                sigstr = "sig";
1175             else if( sig->sig_class == 0x18 )
1176                sigstr = "sig";
1177             else if( sig->sig_class == 0x1F )
1178                sigstr = "sig";
1179             else {
1180                 printf ("sig::::::::::%02x%c:\n",
1181                         sig->sig_class, sig->flags.exportable?'x':'l');
1182                 continue;
1183             }
1184             if( opt.check_sigs ) {
1185                 PKT_public_key *signer_pk=NULL;
1186
1187                 fflush(stdout);
1188                 if(opt.no_sig_cache)
1189                   signer_pk=m_alloc_clear(sizeof(PKT_public_key));
1190
1191                 rc = check_key_signature2( keyblock, node, NULL, signer_pk,
1192                                            NULL, NULL, NULL );
1193                 switch( rc ) {
1194                   case 0:                  sigrc = '!'; break;
1195                   case G10ERR_BAD_SIGN:    sigrc = '-'; break;
1196                   case G10ERR_NO_PUBKEY: 
1197                   case G10ERR_UNU_PUBKEY:  sigrc = '?'; break;
1198                   default:                 sigrc = '%'; break;
1199                 }
1200
1201                 if(opt.no_sig_cache)
1202                   {
1203                     if(rc==0)
1204                       {
1205                         fingerprint_from_pk (signer_pk, fparray, &fplen);
1206                         fprokay=1;
1207                       }
1208                     free_public_key(signer_pk);
1209                   }
1210             }
1211             else {
1212                 rc = 0;
1213                 sigrc = ' ';
1214             }
1215             fputs( sigstr, stdout );
1216             putchar(':');
1217             if( sigrc != ' ' )
1218                 putchar(sigrc);
1219             printf("::%d:%08lX%08lX:%s:%s:", sig->pubkey_algo,
1220                    (ulong)sig->keyid[0], (ulong)sig->keyid[1],
1221                    colon_datestr_from_sig(sig),
1222                    colon_expirestr_from_sig(sig));
1223
1224             if(sig->trust_depth || sig->trust_value)
1225               printf("%d %d",sig->trust_depth,sig->trust_value);
1226             printf(":");
1227
1228             if(sig->trust_regexp)
1229               print_string(stdout,sig->trust_regexp,
1230                            strlen(sig->trust_regexp),':');
1231             printf(":");
1232
1233             if( sigrc == '%' )
1234                 printf("[%s] ", g10_errstr(rc) );
1235             else if( sigrc == '?' )
1236                 ;
1237             else if ( !opt.fast_list_mode ) {
1238                 size_t n;
1239                 char *p = get_user_id( sig->keyid, &n );
1240                 print_string( stdout, p, n, ':' );
1241                 m_free(p);
1242             }
1243             printf(":%02x%c:", sig->sig_class,sig->flags.exportable?'x':'l');
1244
1245             if(opt.no_sig_cache && opt.check_sigs && fprokay)
1246               {
1247                 printf(":");
1248
1249                 for (i=0; i < fplen ; i++ )
1250                   printf ("%02X", fparray[i] );
1251
1252                 printf(":");
1253               }
1254
1255             printf("\n");
1256
1257             /* fixme: check or list other sigs here */
1258         }
1259     }
1260     if( !any ) {/* oops, no user id */
1261         putchar(':');
1262         putchar(':');
1263         print_capabilities (pk, sk, keyblock);
1264         putchar('\n');
1265     }
1266 }
1267
1268 /*
1269  * Reorder the keyblock so that the primary user ID (and not attribute
1270  * packet) comes first.  Fixme: Replace this by a generic sort
1271  * function.  */
1272 void
1273 reorder_keyblock (KBNODE keyblock)
1274 {
1275     KBNODE primary = NULL, primary0 = NULL, primary2 = NULL;
1276     KBNODE last, node;
1277
1278     for (node=keyblock; node; primary0=node, node = node->next) {
1279         if( node->pkt->pkttype == PKT_USER_ID &&
1280             !node->pkt->pkt.user_id->attrib_data &&
1281             node->pkt->pkt.user_id->is_primary ) {
1282             primary = primary2 = node;
1283             for (node=node->next; node; primary2=node, node = node->next ) {
1284                 if( node->pkt->pkttype == PKT_USER_ID 
1285                     || node->pkt->pkttype == PKT_PUBLIC_SUBKEY 
1286                     || node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
1287                     break;
1288                 }
1289             }
1290             break;
1291         }
1292     }
1293     if ( !primary )
1294         return;  /* no primary key flag found (should not happen) */
1295
1296     for (last=NULL, node=keyblock; node; last = node, node = node->next) {
1297         if( node->pkt->pkttype == PKT_USER_ID )
1298             break;
1299     }
1300     assert (node);
1301     assert (last); /* the user ID is never the first packet */
1302     assert (primary0);  /* ditto (this is the node before primary) */
1303     if ( node == primary )
1304         return; /* already the first one */
1305
1306     last->next = primary;
1307     primary0->next = primary2->next;
1308     primary2->next = node;
1309 }
1310
1311 void
1312 list_keyblock( KBNODE keyblock, int secret, int fpr, void *opaque )
1313 {
1314     reorder_keyblock (keyblock);
1315     if (opt.with_colons)
1316         list_keyblock_colon (keyblock, secret, fpr );
1317     else
1318         list_keyblock_print (keyblock, secret, fpr, opaque );
1319 }
1320
1321 /*
1322  * standard function to print the finperprint.
1323  * mode 0: as used in key listings, opt.with_colons is honored
1324  *      1: print using log_info ()
1325  *      2: direct use of tty
1326  *      3: direct use of tty but only primary key.
1327  * modes 1 and 2 will try and print both subkey and primary key fingerprints
1328  */
1329 void
1330 print_fingerprint (PKT_public_key *pk, PKT_secret_key *sk, int mode )
1331 {
1332     byte array[MAX_FINGERPRINT_LEN], *p;
1333     size_t i, n;
1334     FILE *fp;
1335     const char *text;
1336     int primary=0;
1337
1338     if(sk)
1339       {
1340         if(sk->main_keyid[0]==sk->keyid[0] && sk->main_keyid[1]==sk->keyid[1])
1341           primary=1;
1342       }
1343     else
1344       {
1345         if(pk->main_keyid[0]==pk->keyid[0] && pk->main_keyid[1]==pk->keyid[1])
1346           primary=1;
1347       }
1348
1349     /* Just to be safe */
1350     if(mode&0x80 && !primary)
1351       {
1352         log_error("primary key is not really primary!\n");
1353         return;
1354       }
1355
1356     mode&=~0x80;
1357
1358     if(!primary && (mode==1 || mode==2))
1359       {
1360         if(sk)
1361           {
1362             PKT_secret_key *primary_sk=m_alloc_clear(sizeof(*primary_sk));
1363             get_seckey(primary_sk,sk->main_keyid);
1364             print_fingerprint(NULL,primary_sk,mode|0x80);
1365             free_secret_key(primary_sk);
1366           }
1367         else
1368           {
1369             PKT_public_key *primary_pk=m_alloc_clear(sizeof(*primary_pk));
1370             get_pubkey(primary_pk,pk->main_keyid);
1371             print_fingerprint(primary_pk,NULL,mode|0x80);
1372             free_public_key(primary_pk);
1373           }
1374       }
1375
1376     if (mode == 1) {
1377         fp = log_stream ();
1378         if(primary)
1379           text = _("Primary key fingerprint:");
1380         else
1381           text = _("     Subkey fingerprint:");
1382     }
1383     else if (mode == 2) {
1384         fp = NULL; /* use tty */
1385         /* Translators: this should fit into 24 bytes to that the fingerprint
1386          * data is properly aligned with the user ID */
1387         if(primary)
1388           text = _(" Primary key fingerprint:");
1389         else
1390           text = _("      Subkey fingerprint:");
1391     }
1392     else if (mode == 3) {
1393         fp = NULL; /* use tty */
1394         text = _("      Key fingerprint =");
1395     }
1396     else {
1397         fp = stdout;
1398         text = _("      Key fingerprint =");
1399     }
1400   
1401     if (sk)
1402         fingerprint_from_sk (sk, array, &n);
1403     else
1404         fingerprint_from_pk (pk, array, &n);
1405     p = array;
1406     if (opt.with_colons && !mode) {
1407         fprintf (fp, "fpr:::::::::");
1408         for (i=0; i < n ; i++, p++ )
1409             fprintf (fp, "%02X", *p );
1410         putc(':', fp);
1411     }
1412     else {
1413         if (fp)
1414             fputs (text, fp);
1415         else
1416             tty_printf ("%s", text);
1417         if (n == 20) {
1418             for (i=0; i < n ; i++, i++, p += 2 ) {
1419                 if (fp) {
1420                     if (i == 10 )
1421                         putc(' ', fp);
1422                     fprintf (fp, " %02X%02X", *p, p[1] );
1423                 }
1424                 else {
1425                     if (i == 10 )
1426                         tty_printf (" ");
1427                     tty_printf (" %02X%02X", *p, p[1]);
1428                 }
1429             }
1430         }
1431         else {
1432             for (i=0; i < n ; i++, p++ ) {
1433                 if (fp) {
1434                     if (i && !(i%8) )
1435                         putc (' ', fp);
1436                     fprintf (fp, " %02X", *p );
1437                 }
1438                 else {
1439                     if (i && !(i%8) )
1440                         tty_printf (" ");
1441                     tty_printf (" %02X", *p );
1442                 }
1443             }
1444         }
1445     }
1446     if (fp)
1447         putc ('\n', fp);
1448     else
1449         tty_printf ("\n");
1450 }
1451
1452 void set_attrib_fd(int fd)
1453 {
1454   static int last_fd=-1;
1455
1456   if ( fd != -1 && last_fd == fd )
1457     return;
1458
1459   if ( attrib_fp && attrib_fp != stdout && attrib_fp != stderr )
1460     fclose (attrib_fp);
1461   attrib_fp = NULL;
1462   if ( fd == -1 ) 
1463     return;
1464
1465   if( fd == 1 )
1466     attrib_fp = stdout;
1467   else if( fd == 2 )
1468     attrib_fp = stderr;
1469   else
1470     attrib_fp = fdopen( fd, "wb" );
1471   if( !attrib_fp ) {
1472     log_fatal("can't open fd %d for attribute output: %s\n",
1473               fd, strerror(errno));
1474   }
1475
1476   last_fd = fd;
1477 }