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