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