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