* keyedit.c, keylist.c, keyserver.c, mainproc.c: The
[gnupg.git] / g10 / keylist.c
1 /* keylist.c
2  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003,
3  *               2004 Free Software Foundation, Inc.
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * GnuPG is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20  */
21
22 #include <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <assert.h>
28
29 #include "options.h"
30 #include "packet.h"
31 #include "errors.h"
32 #include "keydb.h"
33 #include "memory.h"
34 #include "photoid.h"
35 #include "util.h"
36 #include "ttyio.h"
37 #include "trustdb.h"
38 #include "main.h"
39 #include "i18n.h"
40 #include "status.h"
41
42 static void list_all(int);
43 static void list_one( STRLIST names, int secret);
44 static void print_card_serialno (PKT_secret_key *sk);
45
46 struct sig_stats
47 {
48   int inv_sigs;
49   int no_key;
50   int oth_err;
51 };
52
53 static FILE *attrib_fp=NULL;
54
55 /****************
56  * List the keys
57  * If list is NULL, all available keys are listed
58  */
59 void
60 public_key_list( STRLIST list )
61 {
62   if(opt.with_colons)
63     {
64       byte trust_model,marginals,completes,cert_depth;
65       ulong created,nextcheck;
66
67       read_trust_options(&trust_model,&created,&nextcheck,
68                          &marginals,&completes,&cert_depth);
69
70       printf("tru:");
71
72       if(nextcheck && nextcheck <= make_timestamp())
73         printf("o");
74       if(trust_model!=opt.trust_model)
75         printf("t");
76       if(opt.trust_model==TM_PGP || opt.trust_model==TM_CLASSIC)
77         {
78           if(marginals!=opt.marginals_needed)
79             printf("m");
80           if(completes!=opt.completes_needed)
81             printf("c");
82           if(cert_depth!=opt.max_cert_depth)
83             printf("d");
84         }
85
86       printf(":%d:%lu:%lu",trust_model,created,nextcheck);
87
88       /* Only show marginals, completes, and cert_depth in the classic
89          or PGP trust models since they are not meaningful
90          otherwise. */
91
92       if(trust_model==TM_PGP || trust_model==TM_CLASSIC)
93         printf(":%d:%d:%d",marginals,completes,cert_depth);
94
95       printf("\n");
96     }
97
98   if( !list )
99     list_all(0);
100   else
101     list_one( list, 0 );
102 }
103
104 void
105 secret_key_list( STRLIST list )
106 {
107     if( !list )
108         list_all(1);
109     else  /* List by user id */
110         list_one( list, 1 );
111 }
112
113 void
114 print_seckey_info (PKT_secret_key *sk)
115 {
116   u32 keyid[2];
117   char *p;
118
119   keyid_from_sk (sk, keyid);
120   p=get_user_id_native(keyid);
121
122   tty_printf ("\nsec  %4u%c/%s %s   %s\n",
123               nbits_from_sk (sk),
124               pubkey_letter (sk->pubkey_algo),
125               keystr(keyid), datestr_from_sk (sk), p);
126     
127   m_free (p);
128 }
129
130 /* Print information about the public key.  With FP passed as NULL,
131    the tty output interface is used, otherwise output is directted to
132    the given stream. */
133 void
134 print_pubkey_info (FILE *fp, PKT_public_key *pk)
135 {
136   u32 keyid[2];
137   char *p;
138
139   keyid_from_pk (pk, keyid);
140   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           {
672             printf(" [");
673             printf(_("expired: %s"),expirestr_from_sk(sk));
674             printf("]");
675           }
676         else if(sk->expiredate )
677           {
678             printf(" [");
679             printf(_("expires: %s"),expirestr_from_sk(sk));
680             printf("]");
681           }
682
683         printf("\n");
684       }
685     else
686       {
687         pk = node->pkt->pkt.public_key;
688         sk = NULL;
689
690         check_trustdb_stale();
691
692         printf("pub   %4u%c/%s %s",
693                nbits_from_pk(pk),pubkey_letter(pk->pubkey_algo),
694                keystr_from_pk(pk),datestr_from_pk( pk ));
695
696         /* We didn't include this before in the key listing, but there
697            is room in the new format, so why not? */
698
699         if(pk->is_revoked)
700           {
701             printf(" [");
702             printf(_("revoked: %s"),revokestr_from_pk(pk));
703             printf("]");
704           }
705         else if(pk->has_expired)
706           {
707             printf(" [");
708             printf(_("expired: %s)"),expirestr_from_pk(pk));
709             printf("]");
710           }
711         else if(pk->expiredate)
712           {
713             printf(" [");
714             printf(_("expires: %s"),expirestr_from_pk(pk));
715             printf("]");
716           }
717
718 #if 0
719         /* I need to think about this some more.  It's easy enough to
720            include, but it looks sort of confusing in the
721            listing... */
722         if(opt.list_options&LIST_SHOW_VALIDITY)
723           {
724             int validity=get_validity(pk,NULL);
725             printf(" [%s]",trust_value_to_string(validity));
726           }
727 #endif
728
729         printf("\n");
730       }
731
732     for( kbctx=NULL; (node=walk_kbnode( keyblock, &kbctx, 0)) ; ) {
733         if( node->pkt->pkttype == PKT_USER_ID && !opt.fast_list_mode ) {
734             PKT_user_id *uid=node->pkt->pkt.user_id;
735
736             if((uid->is_expired || uid->is_revoked)
737                && !(opt.list_options&LIST_SHOW_UNUSABLE_UIDS))
738               {
739                 skip_sigs=1;
740                 continue;
741               }
742             else
743               skip_sigs=0;
744
745             if(attrib_fp && uid->attrib_data!=NULL)
746               dump_attribs(uid,pk,sk);
747
748             if((uid->is_revoked || uid->is_expired)
749                || ((opt.list_options&LIST_SHOW_UID_VALIDITY) && pk))
750               {
751                 const char *validity;
752                 int indent;
753
754                 if(uid->is_revoked)
755                   validity=_("revoked");
756                 else if(uid->is_expired)
757                   validity=_("expired");
758                 else
759                   validity=trust_value_to_string(get_validity(pk,uid));
760
761                 indent=(keystrlen()+7)-strlen(validity);
762
763                 if(indent<0)
764                   indent=0;
765
766                 printf("uid%*s[%s] ",indent,"",validity);
767               }
768             else
769               printf("uid%*s",keystrlen()+10,"");
770
771             print_utf8_string( stdout, uid->name, uid->len );
772             putchar('\n');
773             if( !any ) {
774                 if( fpr )
775                     print_fingerprint( pk, sk, 0 );
776                 print_card_serialno (sk);
777                 if( opt.with_key_data )
778                     print_key_data( pk );
779                 any = 1;
780             }
781
782             if((opt.list_options&LIST_SHOW_PHOTOS) && uid->attribs!=NULL)
783               show_photos(uid->attribs,uid->numattribs,pk,sk);
784         }
785         else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
786           {
787             PKT_public_key *pk2 = node->pkt->pkt.public_key;
788
789             if((pk2->is_revoked || pk2->has_expired)
790                && !(opt.list_options&LIST_SHOW_UNUSABLE_SUBKEYS))
791               {
792                 skip_sigs=1;
793                 continue;
794               }
795             else
796               skip_sigs=0;
797
798             if( !any )
799               {
800                 putchar('\n');
801                 if( fpr )
802                   print_fingerprint( pk, sk, 0 ); /* of the main key */
803                 any = 1;
804               }
805
806             printf("sub   %4u%c/%s %s",
807                    nbits_from_pk( pk2 ),pubkey_letter( pk2->pubkey_algo ),
808                    keystr_from_pk(pk2),datestr_from_pk(pk2));
809             if( pk2->is_revoked )
810               {
811                 printf(" [");
812                 printf(_("revoked: %s"),revokestr_from_pk(pk2));
813                 printf("]");
814               }
815             else if( pk2->has_expired )
816               {
817                 printf(" [");
818                 printf(_("expired: %s"),expirestr_from_pk(pk2));
819                 printf("]");
820               }
821             else if( pk2->expiredate )
822               {
823                 printf(" [");
824                 printf(_("expires: %s"),expirestr_from_pk(pk2));
825                 printf("]");
826               }
827             putchar('\n');
828             if( fpr > 1 )
829               print_fingerprint( pk2, NULL, 0 );
830             if( opt.with_key_data )
831               print_key_data( pk2 );
832           }
833         else if( node->pkt->pkttype == PKT_SECRET_SUBKEY )
834           {
835             PKT_secret_key *sk2 = node->pkt->pkt.secret_key;
836
837             if( !any )
838               {
839                 putchar('\n');
840                 if( fpr )
841                   print_fingerprint( pk, sk, 0 ); /* of the main key */
842                 print_card_serialno (sk);
843                 any = 1;
844               }
845
846             printf("ssb%c  %4u%c/%s %s",
847                    (sk2->protect.s2k.mode==1001)?'#':
848                    (sk2->protect.s2k.mode==1002)?'>':' ',
849                    nbits_from_sk( sk2 ),pubkey_letter( sk2->pubkey_algo ),
850                    keystr_from_sk(sk2),datestr_from_sk( sk2 ) );
851             if( sk2->expiredate )
852               {
853                 printf(" [");
854                 printf(_("expires: %s"),expirestr_from_sk(sk2));
855                 printf("]");
856               }
857             putchar('\n');
858             if( fpr > 1 )
859               {
860                 print_fingerprint( NULL, sk2, 0 );
861                 print_card_serialno (sk2);
862               }
863           }
864         else if( opt.list_sigs
865                  && node->pkt->pkttype == PKT_SIGNATURE
866                  && !skip_sigs ) {
867             PKT_signature *sig = node->pkt->pkt.signature;
868             int sigrc;
869             char *sigstr;
870
871             if( stats ) {
872                 /*fflush(stdout);*/
873                 rc = check_key_signature( keyblock, node, NULL );
874                 switch( rc ) {
875                  case 0:                 sigrc = '!'; break;
876                  case G10ERR_BAD_SIGN:   stats->inv_sigs++; sigrc = '-'; break;
877                  case G10ERR_NO_PUBKEY: 
878                  case G10ERR_UNU_PUBKEY: stats->no_key++; continue;
879                  default:                stats->oth_err++; sigrc = '%'; break;
880                 }
881
882                 /* TODO: Make sure a cached sig record here still has
883                    the pk that issued it.  See also
884                    keyedit.c:print_and_check_one_sig */
885             }
886             else {
887                 rc = 0;
888                 sigrc = ' ';
889             }
890
891             if( !any ) { /* no user id, (maybe a revocation follows)*/
892               /* Check if the pk is really revoked - there could be a
893                  0x20 sig packet there even if we are not revoked
894                  (say, if a revocation key issued the packet, but the
895                  revocation key isn't present to verify it.) */
896                 if( sig->sig_class == 0x20 && pk->is_revoked )
897                     puts("[revoked]");
898                 else if( sig->sig_class == 0x18 )
899                     puts("[key binding]");
900                 else if( sig->sig_class == 0x28 )
901                     puts("[subkey revoked]");
902                 else
903                     putchar('\n');
904                 if( fpr )
905                     print_fingerprint( pk, sk, 0 );
906                 print_card_serialno (sk);
907                 any=1;
908             }
909
910             if( sig->sig_class == 0x20 || sig->sig_class == 0x28
911                                        || sig->sig_class == 0x30 )
912                sigstr = "rev";
913             else if( (sig->sig_class&~3) == 0x10 )
914                sigstr = "sig";
915             else if( sig->sig_class == 0x18 )
916                sigstr = "sig";
917             else if( sig->sig_class == 0x1F )
918                sigstr = "sig";
919             else {
920                 printf("sig                             "
921                        "[unexpected signature class 0x%02x]\n",sig->sig_class );
922                 continue;
923             }
924
925             fputs( sigstr, stdout );
926             printf("%c%c %c%c%c%c%c%c %s %s",
927                    sigrc,(sig->sig_class-0x10>0 &&
928                           sig->sig_class-0x10<4)?'0'+sig->sig_class-0x10:' ',
929                    sig->flags.exportable?' ':'L',
930                    sig->flags.revocable?' ':'R',
931                    sig->flags.policy_url?'P':' ',
932                    sig->flags.notation?'N':' ',
933                    sig->flags.expired?'X':' ',
934                    (sig->trust_depth>9)?'T':
935                    (sig->trust_depth>0)?'0'+sig->trust_depth:' ',
936                    keystr(sig->keyid),datestr_from_sig(sig));
937             if(opt.list_options&LIST_SHOW_SIG_EXPIRE)
938               printf(" %s", expirestr_from_sig(sig));
939             printf("  ");
940             if( sigrc == '%' )
941                 printf("[%s] ", g10_errstr(rc) );
942             else if( sigrc == '?' )
943                 ;
944             else if ( !opt.fast_list_mode ) {
945                 size_t n;
946                 char *p = get_user_id( sig->keyid, &n );
947                 print_utf8_string( stdout, p, n );
948                 m_free(p);
949             }
950             putchar('\n');
951
952             if(sig->flags.policy_url
953                && (opt.list_options&LIST_SHOW_POLICY_URLS))
954               show_policy_url(sig,3,0);
955
956             if(sig->flags.notation && (opt.list_options&LIST_SHOW_NOTATIONS))
957               show_notation(sig,3,0,
958                             ((opt.list_options&LIST_SHOW_STD_NOTATIONS)?1:0)+
959                             ((opt.list_options&LIST_SHOW_USER_NOTATIONS)?2:0));
960
961             if(sig->flags.pref_ks
962                && (opt.list_options&LIST_SHOW_KEYSERVER_URLS))
963               show_keyserver_url(sig,3,0);
964
965             /* fixme: check or list other sigs here */
966         }
967     }
968     putchar('\n');
969 }
970
971
972 static void
973 list_keyblock_colon( KBNODE keyblock, int secret, int fpr )
974 {
975     int rc = 0;
976     KBNODE kbctx;
977     KBNODE node;
978     PKT_public_key *pk;
979     PKT_secret_key *sk;
980     u32 keyid[2];
981     int any=0;
982     int trustletter = 0;
983     int ulti_hack = 0;
984     int i;
985
986     /* get the keyid from the keyblock */
987     node = find_kbnode( keyblock, secret? PKT_SECRET_KEY : PKT_PUBLIC_KEY );
988     if( !node ) {
989         log_error("Oops; key lost!\n");
990         dump_kbnode( keyblock );
991         return;
992     }
993
994     if( secret ) {
995         pk = NULL;
996         sk = node->pkt->pkt.secret_key;
997         keyid_from_sk( sk, keyid );
998         printf("sec::%u:%d:%08lX%08lX:%s:%s:::",
999                     nbits_from_sk( sk ),
1000                     sk->pubkey_algo,
1001                     (ulong)keyid[0],(ulong)keyid[1],
1002                     colon_datestr_from_sk( sk ),
1003                     colon_strtime (sk->expiredate)
1004                     /* fixme: add LID here */ );
1005     }
1006     else {
1007         pk = node->pkt->pkt.public_key;
1008         sk = NULL;
1009         keyid_from_pk( pk, keyid );
1010         fputs( "pub:", stdout );
1011         if ( !pk->is_valid )
1012             putchar ('i');
1013         else if ( pk->is_revoked )
1014             putchar ('r');
1015         else if ( pk->has_expired )
1016             putchar ('e');
1017         else if ( opt.fast_list_mode || opt.no_expensive_trust_checks ) 
1018             ;
1019         else {
1020             trustletter = get_validity_info ( pk, NULL );
1021             if( trustletter == 'u' )
1022                 ulti_hack = 1;
1023             putchar(trustletter);
1024         }
1025         printf(":%u:%d:%08lX%08lX:%s:%s::",
1026                     nbits_from_pk( pk ),
1027                     pk->pubkey_algo,
1028                     (ulong)keyid[0],(ulong)keyid[1],
1029                     colon_datestr_from_pk( pk ),
1030                     colon_strtime (pk->expiredate) );
1031         if( !opt.fast_list_mode && !opt.no_expensive_trust_checks  )
1032             putchar( get_ownertrust_info(pk) );
1033             putchar(':');
1034     }
1035     
1036     if (opt.fixed_list_mode) {
1037         /* do not merge the first uid with the primary key */
1038         putchar(':');
1039         putchar(':');
1040         print_capabilities (pk, sk, keyblock);
1041         if (secret) {
1042           putchar(':'); /* End of field 13. */
1043           putchar(':'); /* End of field 14. */
1044           if (sk->protect.s2k.mode == 1001)
1045             putchar('#'); /* Key is just a stub. */
1046           else if (sk->protect.s2k.mode == 1002) {
1047             /* Key is stored on an external token (card) or handled by
1048                the gpg-agent.  Print the serial number of that token
1049                here. */
1050             for (i=0; i < sk->protect.ivlen; i++)
1051               printf ("%02X", sk->protect.iv[i]);
1052           }
1053           putchar(':'); /* End of field 15. */
1054         }
1055         putchar('\n');
1056         if( fpr )
1057             print_fingerprint( pk, sk, 0 );
1058         if( opt.with_key_data )
1059             print_key_data( pk );
1060         any = 1;
1061     }
1062
1063
1064     for( kbctx=NULL; (node=walk_kbnode( keyblock, &kbctx, 0)) ; ) {
1065         if( node->pkt->pkttype == PKT_USER_ID && !opt.fast_list_mode ) {
1066             PKT_user_id *uid=node->pkt->pkt.user_id;
1067             if(attrib_fp && node->pkt->pkt.user_id->attrib_data!=NULL)
1068               dump_attribs(node->pkt->pkt.user_id,pk,sk);
1069             /*
1070              * Fixme: We need a is_valid flag here too 
1071              */
1072             if( any ) {
1073                 char *str=uid->attrib_data?"uat":"uid";
1074                 /* If we're listing a secret key, leave out the
1075                    validity values for now.  This is handled better in
1076                    1.9. */
1077                 if ( sk )
1078                     printf("%s:::::",str);
1079                 else if ( uid->is_revoked )
1080                     printf("%s:r::::",str);
1081                 else if ( uid->is_expired )
1082                     printf("%s:e::::",str);
1083                 else if ( opt.no_expensive_trust_checks )
1084                     printf("%s:::::",str);
1085                 else {
1086                     int uid_validity;
1087
1088                     if( pk && !ulti_hack )
1089                       uid_validity=get_validity_info (pk, uid);
1090                     else
1091                         uid_validity = 'u';
1092                     printf("%s:%c::::",str,uid_validity);
1093                 }
1094
1095                 printf("%s:",colon_strtime(uid->created));
1096                 printf("%s:",colon_strtime(uid->expiredate));
1097
1098                 namehash_from_uid(uid);
1099
1100                 for(i=0; i < 20; i++ )
1101                   printf("%02X",uid->namehash[i]);
1102
1103                 printf("::");
1104             }
1105             if(uid->attrib_data)
1106               printf("%u %lu",uid->numattribs,uid->attrib_len);
1107             else
1108               print_string(stdout,uid->name,uid->len, ':' );
1109             putchar(':');
1110             if (any)
1111                 putchar('\n');
1112             else {
1113                 putchar(':');
1114                 print_capabilities (pk, sk, keyblock);
1115                 putchar('\n');
1116                 if( fpr )
1117                     print_fingerprint( pk, sk, 0 );
1118                 if( opt.with_key_data )
1119                     print_key_data( pk );
1120                 any = 1;
1121             }
1122         }
1123         else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
1124             u32 keyid2[2];
1125             PKT_public_key *pk2 = node->pkt->pkt.public_key;
1126
1127             if( !any ) {
1128                 putchar(':');
1129                 putchar(':');
1130                 print_capabilities (pk, sk, keyblock);
1131                 putchar('\n');
1132                 if( fpr )
1133                     print_fingerprint( pk, sk, 0 ); /* of the main key */
1134                 any = 1;
1135             }
1136
1137             keyid_from_pk( pk2, keyid2 );
1138             fputs ("sub:", stdout );
1139             if ( !pk2->is_valid )
1140                 putchar ('i');
1141             else if ( pk2->is_revoked )
1142                 putchar ('r');
1143             else if ( pk2->has_expired )
1144                 putchar ('e');
1145             else if ( opt.fast_list_mode || opt.no_expensive_trust_checks )
1146                 ;
1147             else {
1148                 /* trustletter should always be defined here */
1149                 if(trustletter)
1150                   printf("%c", trustletter );
1151             }
1152             printf(":%u:%d:%08lX%08lX:%s:%s:::::",
1153                         nbits_from_pk( pk2 ),
1154                         pk2->pubkey_algo,
1155                         (ulong)keyid2[0],(ulong)keyid2[1],
1156                         colon_datestr_from_pk( pk2 ),
1157                         colon_strtime (pk2->expiredate)
1158                         /* fixme: add LID and ownertrust here */
1159                                                 );
1160             print_capabilities (pk2, NULL, NULL);
1161             putchar('\n');
1162             if( fpr > 1 )
1163                 print_fingerprint( pk2, NULL, 0 );
1164             if( opt.with_key_data )
1165                 print_key_data( pk2 );
1166         }
1167         else if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
1168             u32 keyid2[2];
1169             PKT_secret_key *sk2 = node->pkt->pkt.secret_key;
1170
1171             if( !any ) {
1172                 putchar(':');
1173                 putchar(':');
1174                 print_capabilities (pk, sk, keyblock);
1175                 putchar('\n');
1176                 if( fpr )
1177                     print_fingerprint( pk, sk, 0 ); /* of the main key */
1178                 any = 1;
1179             }
1180
1181             keyid_from_sk( sk2, keyid2 );
1182             printf("ssb::%u:%d:%08lX%08lX:%s:%s:::::",
1183                         nbits_from_sk( sk2 ),
1184                         sk2->pubkey_algo,
1185                         (ulong)keyid2[0],(ulong)keyid2[1],
1186                         colon_datestr_from_sk( sk2 ),
1187                         colon_strtime (sk2->expiredate)
1188                    /* fixme: add LID */ );
1189             print_capabilities (NULL, sk2, NULL);
1190             if (opt.fixed_list_mode) {
1191               /* We print the serial number only in fixed list mode
1192                  for the primary key so, so avoid questions we print
1193                  it for subkeys also only in this mode.  There is no
1194                  technical reason, though. */
1195               putchar(':'); /* End of field 13. */
1196               putchar(':'); /* End of field 14. */
1197               if (sk2->protect.s2k.mode == 1001)
1198                 putchar('#'); /* Key is just a stub. */
1199               else if (sk2->protect.s2k.mode == 1002) {
1200                 /* Key is stored on an external token (card) or handled by
1201                    the gpg-agent.  Print the serial number of that token
1202                    here. */
1203                 for (i=0; i < sk2->protect.ivlen; i++)
1204                   printf ("%02X", sk2->protect.iv[i]);
1205               }
1206               putchar(':'); /* End of field 15. */
1207             }
1208             putchar ('\n');
1209             if( fpr > 1 )
1210               print_fingerprint( NULL, sk2, 0 );
1211         }
1212         else if( opt.list_sigs && node->pkt->pkttype == PKT_SIGNATURE ) {
1213             PKT_signature *sig = node->pkt->pkt.signature;
1214             int sigrc,fprokay=0;
1215             char *sigstr;
1216             size_t fplen;
1217             byte fparray[MAX_FINGERPRINT_LEN];
1218
1219             if( !any ) { /* no user id, (maybe a revocation follows)*/
1220                 if( sig->sig_class == 0x20 )
1221                     fputs("[revoked]:", stdout);
1222                 else if( sig->sig_class == 0x18 )
1223                     fputs("[key binding]:", stdout);
1224                 else if( sig->sig_class == 0x28 )
1225                     fputs("[subkey revoked]:", stdout);
1226                 else
1227                     putchar (':');
1228                 putchar(':');
1229                 print_capabilities (pk, sk, keyblock);
1230                 putchar('\n');
1231                 if( fpr )
1232                     print_fingerprint( pk, sk, 0 );
1233                 any=1;
1234             }
1235
1236             if( sig->sig_class == 0x20 || sig->sig_class == 0x28
1237                                        || sig->sig_class == 0x30 )
1238                sigstr = "rev";
1239             else if( (sig->sig_class&~3) == 0x10 )
1240                sigstr = "sig";
1241             else if( sig->sig_class == 0x18 )
1242                sigstr = "sig";
1243             else if( sig->sig_class == 0x1F )
1244                sigstr = "sig";
1245             else {
1246                 printf ("sig::::::::::%02x%c:\n",
1247                         sig->sig_class, sig->flags.exportable?'x':'l');
1248                 continue;
1249             }
1250             if( opt.check_sigs ) {
1251                 PKT_public_key *signer_pk=NULL;
1252
1253                 fflush(stdout);
1254                 if(opt.no_sig_cache)
1255                   signer_pk=m_alloc_clear(sizeof(PKT_public_key));
1256
1257                 rc = check_key_signature2( keyblock, node, NULL, signer_pk,
1258                                            NULL, NULL, NULL );
1259                 switch( rc ) {
1260                   case 0:                  sigrc = '!'; break;
1261                   case G10ERR_BAD_SIGN:    sigrc = '-'; break;
1262                   case G10ERR_NO_PUBKEY: 
1263                   case G10ERR_UNU_PUBKEY:  sigrc = '?'; break;
1264                   default:                 sigrc = '%'; break;
1265                 }
1266
1267                 if(opt.no_sig_cache)
1268                   {
1269                     if(rc==0)
1270                       {
1271                         fingerprint_from_pk (signer_pk, fparray, &fplen);
1272                         fprokay=1;
1273                       }
1274                     free_public_key(signer_pk);
1275                   }
1276             }
1277             else {
1278                 rc = 0;
1279                 sigrc = ' ';
1280             }
1281             fputs( sigstr, stdout );
1282             putchar(':');
1283             if( sigrc != ' ' )
1284                 putchar(sigrc);
1285             printf("::%d:%08lX%08lX:%s:%s:", sig->pubkey_algo,
1286                    (ulong)sig->keyid[0], (ulong)sig->keyid[1],
1287                    colon_datestr_from_sig(sig),
1288                    colon_expirestr_from_sig(sig));
1289
1290             if(sig->trust_depth || sig->trust_value)
1291               printf("%d %d",sig->trust_depth,sig->trust_value);
1292             printf(":");
1293
1294             if(sig->trust_regexp)
1295               print_string(stdout,sig->trust_regexp,
1296                            strlen(sig->trust_regexp),':');
1297             printf(":");
1298
1299             if( sigrc == '%' )
1300                 printf("[%s] ", g10_errstr(rc) );
1301             else if( sigrc == '?' )
1302                 ;
1303             else if ( !opt.fast_list_mode ) {
1304                 size_t n;
1305                 char *p = get_user_id( sig->keyid, &n );
1306                 print_string( stdout, p, n, ':' );
1307                 m_free(p);
1308             }
1309             printf(":%02x%c:", sig->sig_class,sig->flags.exportable?'x':'l');
1310
1311             if(opt.no_sig_cache && opt.check_sigs && fprokay)
1312               {
1313                 printf(":");
1314
1315                 for (i=0; i < fplen ; i++ )
1316                   printf ("%02X", fparray[i] );
1317
1318                 printf(":");
1319               }
1320
1321             printf("\n");
1322
1323             if(opt.show_subpackets)
1324               print_subpackets_colon(sig);
1325
1326             /* fixme: check or list other sigs here */
1327         }
1328     }
1329     if( !any ) {/* oops, no user id */
1330         putchar(':');
1331         putchar(':');
1332         print_capabilities (pk, sk, keyblock);
1333         putchar('\n');
1334     }
1335 }
1336
1337 /*
1338  * Reorder the keyblock so that the primary user ID (and not attribute
1339  * packet) comes first.  Fixme: Replace this by a generic sort
1340  * function.  */
1341 void
1342 reorder_keyblock (KBNODE keyblock)
1343 {
1344     KBNODE primary = NULL, primary0 = NULL, primary2 = NULL;
1345     KBNODE last, node;
1346
1347     for (node=keyblock; node; primary0=node, node = node->next) {
1348         if( node->pkt->pkttype == PKT_USER_ID &&
1349             !node->pkt->pkt.user_id->attrib_data &&
1350             node->pkt->pkt.user_id->is_primary ) {
1351             primary = primary2 = node;
1352             for (node=node->next; node; primary2=node, node = node->next ) {
1353                 if( node->pkt->pkttype == PKT_USER_ID 
1354                     || node->pkt->pkttype == PKT_PUBLIC_SUBKEY 
1355                     || node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
1356                     break;
1357                 }
1358             }
1359             break;
1360         }
1361     }
1362     if ( !primary )
1363         return;  /* no primary key flag found (should not happen) */
1364
1365     for (last=NULL, node=keyblock; node; last = node, node = node->next) {
1366         if( node->pkt->pkttype == PKT_USER_ID )
1367             break;
1368     }
1369     assert (node);
1370     assert (last); /* the user ID is never the first packet */
1371     assert (primary0);  /* ditto (this is the node before primary) */
1372     if ( node == primary )
1373         return; /* already the first one */
1374
1375     last->next = primary;
1376     primary0->next = primary2->next;
1377     primary2->next = node;
1378 }
1379
1380 void
1381 list_keyblock( KBNODE keyblock, int secret, int fpr, void *opaque )
1382 {
1383     reorder_keyblock (keyblock);
1384     if (opt.with_colons)
1385         list_keyblock_colon (keyblock, secret, fpr );
1386     else
1387         list_keyblock_print (keyblock, secret, fpr, opaque );
1388 }
1389
1390 /*
1391  * standard function to print the finperprint.
1392  * mode 0: as used in key listings, opt.with_colons is honored
1393  *      1: print using log_info ()
1394  *      2: direct use of tty
1395  *      3: direct use of tty but only primary key.
1396  * modes 1 and 2 will try and print both subkey and primary key fingerprints
1397  */
1398 void
1399 print_fingerprint (PKT_public_key *pk, PKT_secret_key *sk, int mode )
1400 {
1401     byte array[MAX_FINGERPRINT_LEN], *p;
1402     size_t i, n;
1403     FILE *fp;
1404     const char *text;
1405     int primary=0;
1406
1407     if(sk)
1408       {
1409         if(sk->main_keyid[0]==sk->keyid[0] && sk->main_keyid[1]==sk->keyid[1])
1410           primary=1;
1411       }
1412     else
1413       {
1414         if(pk->main_keyid[0]==pk->keyid[0] && pk->main_keyid[1]==pk->keyid[1])
1415           primary=1;
1416       }
1417
1418     /* Just to be safe */
1419     if(mode&0x80 && !primary)
1420       {
1421         log_error("primary key is not really primary!\n");
1422         return;
1423       }
1424
1425     mode&=~0x80;
1426
1427     if(!primary && (mode==1 || mode==2))
1428       {
1429         if(sk)
1430           {
1431             PKT_secret_key *primary_sk=m_alloc_clear(sizeof(*primary_sk));
1432             get_seckey(primary_sk,sk->main_keyid);
1433             print_fingerprint(NULL,primary_sk,mode|0x80);
1434             free_secret_key(primary_sk);
1435           }
1436         else
1437           {
1438             PKT_public_key *primary_pk=m_alloc_clear(sizeof(*primary_pk));
1439             get_pubkey(primary_pk,pk->main_keyid);
1440             print_fingerprint(primary_pk,NULL,mode|0x80);
1441             free_public_key(primary_pk);
1442           }
1443       }
1444
1445     if (mode == 1) {
1446         fp = log_stream ();
1447         if(primary)
1448           text = _("Primary key fingerprint:");
1449         else
1450           text = _("     Subkey fingerprint:");
1451     }
1452     else if (mode == 2) {
1453         fp = NULL; /* use tty */
1454         /* Translators: this should fit into 24 bytes to that the fingerprint
1455          * data is properly aligned with the user ID */
1456         if(primary)
1457           text = _(" Primary key fingerprint:");
1458         else
1459           text = _("      Subkey fingerprint:");
1460     }
1461     else if (mode == 3) {
1462         fp = NULL; /* use tty */
1463         text = _("      Key fingerprint =");
1464     }
1465     else {
1466         fp = stdout;
1467         text = _("      Key fingerprint =");
1468     }
1469   
1470     if (sk)
1471         fingerprint_from_sk (sk, array, &n);
1472     else
1473         fingerprint_from_pk (pk, array, &n);
1474     p = array;
1475     if (opt.with_colons && !mode) {
1476         fprintf (fp, "fpr:::::::::");
1477         for (i=0; i < n ; i++, p++ )
1478             fprintf (fp, "%02X", *p );
1479         putc(':', fp);
1480     }
1481     else {
1482         if (fp)
1483             fputs (text, fp);
1484         else
1485             tty_printf ("%s", text);
1486         if (n == 20) {
1487             for (i=0; i < n ; i++, i++, p += 2 ) {
1488                 if (fp) {
1489                     if (i == 10 )
1490                         putc(' ', fp);
1491                     fprintf (fp, " %02X%02X", *p, p[1] );
1492                 }
1493                 else {
1494                     if (i == 10 )
1495                         tty_printf (" ");
1496                     tty_printf (" %02X%02X", *p, p[1]);
1497                 }
1498             }
1499         }
1500         else {
1501             for (i=0; i < n ; i++, p++ ) {
1502                 if (fp) {
1503                     if (i && !(i%8) )
1504                         putc (' ', fp);
1505                     fprintf (fp, " %02X", *p );
1506                 }
1507                 else {
1508                     if (i && !(i%8) )
1509                         tty_printf (" ");
1510                     tty_printf (" %02X", *p );
1511                 }
1512             }
1513         }
1514     }
1515     if (fp)
1516         putc ('\n', fp);
1517     else
1518         tty_printf ("\n");
1519 }
1520
1521 /* Print the serial number of an OpenPGP card if available. */
1522 static void
1523 print_card_serialno (PKT_secret_key *sk)
1524 {
1525   int i;
1526
1527   if (!sk)
1528     return;
1529   if (!sk->is_protected || sk->protect.s2k.mode != 1002) 
1530     return; /* Not a card. */
1531   if (opt.with_colons)
1532     return; /* Handled elesewhere. */
1533
1534   fputs (_("      Card serial no. ="), stdout);
1535   putchar (' ');
1536   if (sk->protect.ivlen == 16
1537       && !memcmp (sk->protect.iv, "\xD2\x76\x00\x01\x24\x01", 6) )
1538     { /* This is an OpenPGP card. Just print the relevant part. */
1539       for (i=8; i < 14; i++)
1540         {
1541           if (i == 10)
1542             putchar (' ');
1543           printf ("%02X", sk->protect.iv[i]);
1544         }
1545     }
1546   else
1547     { /* Something is wrong: Print all. */
1548       for (i=0; i < sk->protect.ivlen; i++)
1549         printf ("%02X", sk->protect.iv[i]);
1550     }
1551   putchar ('\n');
1552 }
1553
1554
1555
1556 void set_attrib_fd(int fd)
1557 {
1558   static int last_fd=-1;
1559
1560   if ( fd != -1 && last_fd == fd )
1561     return;
1562
1563   if ( attrib_fp && attrib_fp != stdout && attrib_fp != stderr )
1564     fclose (attrib_fp);
1565   attrib_fp = NULL;
1566   if ( fd == -1 ) 
1567     return;
1568
1569   if( fd == 1 )
1570     attrib_fp = stdout;
1571   else if( fd == 2 )
1572     attrib_fp = stderr;
1573   else
1574     attrib_fp = fdopen( fd, "wb" );
1575   if( !attrib_fp ) {
1576     log_fatal("can't open fd %d for attribute output: %s\n",
1577               fd, strerror(errno));
1578   }
1579
1580   last_fd = fd;
1581 }