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