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