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