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