* plaintext.c (handle_plaintext): Properly handle a --max-output of zero
[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
45 struct sig_stats
46 {
47   int inv_sigs;
48   int no_key;
49   int oth_err;
50 };
51
52 static FILE *attrib_fp=NULL;
53
54 /****************
55  * List the keys
56  * If list is NULL, all available keys are listed
57  */
58 void
59 public_key_list( STRLIST list )
60 {
61   if(opt.with_colons)
62     {
63       byte trust_model,marginals,completes,cert_depth;
64       ulong created,nextcheck;
65
66       read_trust_options(&trust_model,&created,&nextcheck,
67                          &marginals,&completes,&cert_depth);
68
69       printf("tru:");
70
71       if(nextcheck && nextcheck <= make_timestamp())
72         printf("o");
73       if(trust_model!=opt.trust_model)
74         printf("t");
75       if(opt.trust_model==TM_PGP || opt.trust_model==TM_CLASSIC)
76         {
77           if(marginals!=opt.marginals_needed)
78             printf("m");
79           if(completes!=opt.completes_needed)
80             printf("c");
81           if(cert_depth!=opt.max_cert_depth)
82             printf("d");
83         }
84
85       printf(":%d:%lu:%lu",trust_model,created,nextcheck);
86
87       /* Only show marginals, completes, and cert_depth in the classic
88          or PGP trust models since they are not meaningful
89          otherwise. */
90
91       if(trust_model==TM_PGP || trust_model==TM_CLASSIC)
92         printf(":%d:%d:%d",marginals,completes,cert_depth);
93
94       printf("\n");
95     }
96
97   if( !list )
98     list_all(0);
99   else
100     list_one( list, 0 );
101 }
102
103 void
104 secret_key_list( STRLIST list )
105 {
106     if( !list )
107         list_all(1);
108     else  /* List by user id */
109         list_one( list, 1 );
110 }
111
112 void
113 print_seckey_info (PKT_secret_key *sk)
114 {
115     u32 sk_keyid[2];
116     size_t n;
117     char *p;
118
119     keyid_from_sk (sk, sk_keyid);
120     tty_printf ("\nsec  %4u%c/%08lX %s   ",
121                 nbits_from_sk (sk),
122                 pubkey_letter (sk->pubkey_algo),
123                 (ulong)sk_keyid[1], datestr_from_sk (sk));
124     
125     p = get_user_id (sk_keyid, &n);
126     tty_print_utf8_string (p, n);
127     m_free (p);
128
129     tty_printf ("\n");   
130 }
131
132 /* Print information about the public key.  With FP passed as NULL,
133    the tty output interface is used, otherwise output is directted to
134    the given stream. */
135 void
136 print_pubkey_info (FILE *fp, PKT_public_key *pk)
137 {
138   u32 pk_keyid[2];
139   size_t n;
140   char *p;
141
142   keyid_from_pk (pk, pk_keyid);
143   if (fp)
144     fprintf (fp, "pub  %4u%c/%08lX %s   ",
145              nbits_from_pk (pk),
146              pubkey_letter (pk->pubkey_algo),
147              (ulong)pk_keyid[1], datestr_from_pk (pk));
148   else
149     tty_printf ("\npub  %4u%c/%08lX %s   ",
150                 nbits_from_pk (pk),
151                 pubkey_letter (pk->pubkey_algo),
152                 (ulong)pk_keyid[1], datestr_from_pk (pk));
153
154   p = get_user_id (pk_keyid, &n);
155   if (fp)
156     print_utf8_string2 (fp, p, n, '\n');
157   else
158     tty_print_utf8_string (p, n);
159   m_free (p);
160   
161   if (fp)
162     putc ('\n', fp);
163   else
164     tty_printf ("\n\n"); 
165 }
166
167 /*
168   mode=0 for stdout.
169   mode=1 for log_info + status messages
170   mode=2 for status messages only
171 */
172
173 void
174 show_policy_url(PKT_signature *sig,int indent,int mode)
175 {
176   const byte *p;
177   size_t len;
178   int seq=0,crit;
179   FILE *fp=mode?log_stream():stdout;
180
181   while((p=enum_sig_subpkt(sig->hashed,SIGSUBPKT_POLICY,&len,&seq,&crit)))
182     {
183       if(mode!=2)
184         {
185           int i;
186           char *str;
187
188           for(i=0;i<indent;i++)
189             putchar(' ');
190
191           if(crit)
192             str=_("Critical signature policy: ");
193           else
194             str=_("Signature policy: ");
195           if(mode)
196             log_info("%s",str);
197           else
198             printf("%s",str);
199           print_utf8_string(fp,p,len);
200           fprintf(fp,"\n");
201         }
202
203       if(mode)
204         write_status_buffer ( STATUS_POLICY_URL, p, len, 0 );
205     }
206 }
207
208 /*
209   mode=0 for stdout.
210   mode=1 for log_info + status messages
211   mode=2 for status messages only
212 */
213 /* TODO: use this */
214 void
215 show_keyserver_url(PKT_signature *sig,int indent,int mode)
216 {
217   const byte *p;
218   size_t len;
219   int seq=0,crit;
220   FILE *fp=mode?log_stream():stdout;
221
222   while((p=enum_sig_subpkt(sig->hashed,SIGSUBPKT_PREF_KS,&len,&seq,&crit)))
223     {
224       if(mode!=2)
225         {
226           int i;
227           char *str;
228
229           for(i=0;i<indent;i++)
230             putchar(' ');
231
232           if(crit)
233             str=_("Critical preferred keyserver: ");
234           else
235             str=_("Preferred keyserver: ");
236           if(mode)
237             log_info("%s",str);
238           else
239             printf("%s",str);
240           print_utf8_string(fp,p,len);
241           fprintf(fp,"\n");
242         }
243
244       /* TODO: put in a status-fd tag for preferred keyservers */
245     }
246 }
247
248 /*
249   mode=0 for stdout.
250   mode=1 for log_info + status messages
251   mode=2 for status messages only
252 */
253
254 void
255 show_notation(PKT_signature *sig,int indent,int mode)
256 {
257   const byte *p;
258   size_t len;
259   int seq=0,crit;
260   FILE *fp=mode?log_stream():stdout;
261
262   /* There may be multiple notations in the same sig. */
263
264   while((p=enum_sig_subpkt(sig->hashed,SIGSUBPKT_NOTATION,&len,&seq,&crit)))
265     if(len>=8)
266       {
267         int n1,n2;
268
269         n1=(p[4]<<8)|p[5];
270         n2=(p[6]<<8)|p[7];
271
272         if(8+n1+n2!=len)
273           {
274             log_info(_("WARNING: invalid notation data found\n"));
275             return;
276           }
277
278         if(mode!=2)
279           {
280             int i;
281             char *str;
282
283             for(i=0;i<indent;i++)
284               putchar(' ');
285
286             /* This is UTF8 */
287             if(crit)
288               str=_("Critical signature notation: ");
289             else
290               str=_("Signature notation: ");
291             if(mode)
292               log_info("%s",str);
293             else
294               printf("%s",str);
295             print_utf8_string(fp,p+8,n1);
296             fprintf(fp,"=");
297
298             if(*p&0x80)
299               print_utf8_string(fp,p+8+n1,n2);
300             else
301               fprintf(fp,"[ %s ]",_("not human readable"));
302
303             fprintf(fp,"\n");
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     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, u32 *keyid )
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 void
556 dump_attribs(const PKT_user_id *uid,PKT_public_key *pk,PKT_secret_key *sk)
557 {
558   int i;
559
560   if(!attrib_fp)
561     return;
562
563   for(i=0;i<uid->numattribs;i++)
564     {
565       if(is_status_enabled())
566         {
567           byte array[MAX_FINGERPRINT_LEN], *p;
568           char buf[(MAX_FINGERPRINT_LEN*2)+90];
569           size_t j,n;
570
571           if(pk)
572             fingerprint_from_pk( pk, array, &n );
573           else if(sk)
574             fingerprint_from_sk( sk, array, &n );
575           else
576             BUG();
577
578           p = array;
579           for(j=0; j < n ; j++, p++ )
580             sprintf(buf+2*j, "%02X", *p );
581
582           sprintf(buf+strlen(buf)," %lu %u %u %u %lu %lu %u",
583                   (ulong)uid->attribs[i].len,uid->attribs[i].type,i+1,
584                   uid->numattribs,(ulong)uid->created,(ulong)uid->expiredate,
585                   ((uid->is_primary?0x01:0)|
586                    (uid->is_revoked?0x02:0)|
587                    (uid->is_expired?0x04:0)));
588           write_status_text(STATUS_ATTRIBUTE,buf);
589         }
590
591       fwrite(uid->attribs[i].data,uid->attribs[i].len,1,attrib_fp);
592     }
593 }
594
595 static void
596 list_keyblock_print ( KBNODE keyblock, int secret, int fpr, void *opaque )
597 {
598     int rc = 0;
599     KBNODE kbctx;
600     KBNODE node;
601     PKT_public_key *pk;
602     PKT_secret_key *sk;
603     u32 keyid[2];
604     int any=0;
605     struct sig_stats *stats=opaque;
606     int skip_sigs=0;
607     int newformat=((opt.list_options&LIST_SHOW_VALIDITY) && !secret)
608       || (opt.list_options & (LIST_SHOW_LONG_KEYIDS
609                               | LIST_SHOW_UNUSABLE_UIDS
610                               | LIST_SHOW_UNUSABLE_SUBKEYS));
611
612     /* get the keyid from the keyblock */
613     node = find_kbnode( keyblock, secret? PKT_SECRET_KEY : PKT_PUBLIC_KEY );
614     if( !node ) {
615         log_error("Oops; key lost!\n");
616         dump_kbnode( keyblock );
617         return;
618     }
619
620     if( secret )
621       {
622         pk = NULL;
623         sk = node->pkt->pkt.secret_key;
624         keyid_from_sk( sk, keyid );
625
626         printf("sec%c  %4u%c/",(sk->protect.s2k.mode==1001)?'#':
627                                (sk->protect.s2k.mode==1002)?'>':' ',
628                nbits_from_sk( sk ),pubkey_letter( sk->pubkey_algo ));
629
630         if(opt.list_options&LIST_SHOW_LONG_KEYIDS)
631           printf("%08lX%08lX",(ulong)keyid[0],(ulong)keyid[1]);
632         else
633           printf("%08lX",(ulong)keyid[1]);
634
635         printf(" %s%s",datestr_from_sk( sk ),newformat?"":" " );
636
637         if(newformat && sk->expiredate )
638           printf(_(" [expires: %s]"), expirestr_from_sk( sk ) );
639       }
640     else
641       {
642 #if 0
643         int validity;
644 #endif
645         pk = node->pkt->pkt.public_key;
646         sk = NULL;
647         keyid_from_pk( pk, keyid );
648
649 #if 0
650         validity=get_validity(pk,NULL);
651 #endif
652
653         check_trustdb_stale();
654
655         printf("pub   %4u%c/",
656                nbits_from_pk(pk),pubkey_letter(pk->pubkey_algo));
657
658         if(opt.list_options&LIST_SHOW_LONG_KEYIDS)
659           printf("%08lX%08lX",(ulong)keyid[0],(ulong)keyid[1]);
660         else
661           printf("%08lX",(ulong)keyid[1]);
662
663         printf(" %s%s",datestr_from_pk( pk ),newformat?"":" " );
664
665         /* We didn't include this before in the key listing, but there
666            is room in the new format, so why not? */
667         if(newformat)
668           {
669             if(pk->is_revoked)
670               printf(_(" [revoked: %s]"), revokestr_from_pk( pk ) );
671             else if(pk->has_expired)
672               printf(_(" [expired: %s]"), expirestr_from_pk( pk ) );
673             else if(pk->expiredate)
674               printf(_(" [expires: %s]"), expirestr_from_pk( pk ) );
675           }
676
677 #if 0
678         /* I need to think about this some more.  It's easy enough to
679            include, but it looks sort of confusing in the
680            listing... */
681         if(opt.list_options&LIST_SHOW_VALIDITY)
682           printf(" [%s]",trust_value_to_string(validity));
683 #endif
684       }
685
686     for( kbctx=NULL; (node=walk_kbnode( keyblock, &kbctx, 0)) ; ) {
687         if( node->pkt->pkttype == PKT_USER_ID && !opt.fast_list_mode ) {
688             int indent;
689             PKT_user_id *uid=node->pkt->pkt.user_id;
690
691             if((uid->is_expired || uid->is_revoked)
692                && !(opt.list_options&LIST_SHOW_UNUSABLE_UIDS))
693               {
694                 skip_sigs=1;
695                 continue;
696               }
697             else
698               skip_sigs=0;
699
700             if(attrib_fp && uid->attrib_data!=NULL)
701               dump_attribs(uid,pk,sk);
702
703             if(!any && newformat)
704               printf("\n");
705
706             if(uid->is_revoked || uid->is_expired)
707               printf("uid%*s[%s] ",
708                      (opt.list_options&LIST_SHOW_LONG_KEYIDS)?16:8,"",
709                      uid->is_revoked?_("revoked"):_("expired"));
710             else if((opt.list_options&LIST_SHOW_VALIDITY) && pk)
711               {
712                 const char *validity=
713                   trust_value_to_string(get_validity(pk,uid));
714
715                 /* Includes the 3 spaces for [, ], and " ". */
716                 indent=((opt.list_options&LIST_SHOW_LONG_KEYIDS)?23:15)
717                   -strlen(validity);
718
719                 if(indent<0)
720                   indent=0;
721
722                 printf("uid%*s[%s] ",indent,"",validity);
723               }
724             else if(newformat)
725               printf("uid%*s",
726                      (opt.list_options&LIST_SHOW_LONG_KEYIDS)?26:18,"");
727             else if(any)
728               printf("uid%*s",29,"");
729
730             print_utf8_string( stdout, uid->name, uid->len );
731             putchar('\n');
732             if( !any ) {
733                 if( fpr )
734                     print_fingerprint( pk, sk, 0 );
735                 if( opt.with_key_data )
736                     print_key_data( pk, keyid );
737                 any = 1;
738             }
739
740             if((opt.list_options&LIST_SHOW_PHOTOS) && uid->attribs!=NULL)
741               show_photos(uid->attribs,uid->numattribs,pk,sk);
742         }
743         else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
744             u32 keyid2[2];
745             PKT_public_key *pk2 = node->pkt->pkt.public_key;
746
747             if((pk2->is_revoked || pk2->has_expired)
748                && !(opt.list_options&LIST_SHOW_UNUSABLE_SUBKEYS))
749               {
750                 skip_sigs=1;
751                 continue;
752               }
753             else
754               skip_sigs=0;
755
756             if( !any ) {
757                 putchar('\n');
758                 if( fpr )
759                     print_fingerprint( pk, sk, 0 ); /* of the main key */
760                 any = 1;
761             }
762
763             keyid_from_pk( pk2, keyid2 );
764             printf("sub   %4u%c/",
765                    nbits_from_pk( pk2 ),pubkey_letter( pk2->pubkey_algo ));
766             if(opt.list_options&LIST_SHOW_LONG_KEYIDS)
767               printf("%08lX%08lX",(ulong)keyid2[0],(ulong)keyid2[1]);
768             else
769               printf("%08lX",(ulong)keyid2[1]);
770             printf(" %s",datestr_from_pk(pk2));
771             if( pk2->is_revoked )
772               printf(_(" [revoked: %s]"), revokestr_from_pk(pk2));
773             else if( pk2->has_expired )
774                 printf(_(" [expired: %s]"), expirestr_from_pk( pk2 ) );
775             else if( pk2->expiredate )
776                 printf(_(" [expires: %s]"), expirestr_from_pk( pk2 ) );
777             putchar('\n');
778             if( fpr > 1 )
779                 print_fingerprint( pk2, NULL, 0 );
780             if( opt.with_key_data )
781                 print_key_data( pk2, keyid2 );
782         }
783         else if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
784             u32 keyid2[2];
785             PKT_secret_key *sk2 = node->pkt->pkt.secret_key;
786
787             if( !any ) {
788                 putchar('\n');
789                 if( fpr )
790                     print_fingerprint( pk, sk, 0 ); /* of the main key */
791                 any = 1;
792             }
793
794             keyid_from_sk( sk2, keyid2 );
795             printf("ssb%c  %4u%c/",
796                    (sk->protect.s2k.mode==1001)?'#':
797                    (sk->protect.s2k.mode==1002)?'>':' ',
798                    nbits_from_sk( sk2 ),pubkey_letter( sk2->pubkey_algo ));
799             if(opt.list_options&LIST_SHOW_LONG_KEYIDS)
800               printf("%08lX%08lX",(ulong)keyid2[0],(ulong)keyid2[1]);
801             else
802               printf("%08lX",(ulong)keyid2[1]);
803             printf(" %s",datestr_from_sk( sk2 ) );
804             if( sk2->expiredate )
805               printf(_(" [expires: %s]"), expirestr_from_sk( sk2 ) );
806             putchar('\n');
807             if( fpr > 1 )
808                 print_fingerprint( NULL, sk2, 0 );
809         }
810         else if( opt.list_sigs
811                  && node->pkt->pkttype == PKT_SIGNATURE
812                  && !skip_sigs ) {
813             PKT_signature *sig = node->pkt->pkt.signature;
814             int sigrc;
815             char *sigstr;
816
817             if( stats ) {
818                 /*fflush(stdout);*/
819                 rc = check_key_signature( keyblock, node, NULL );
820                 switch( rc ) {
821                  case 0:                 sigrc = '!'; break;
822                  case G10ERR_BAD_SIGN:   stats->inv_sigs++; sigrc = '-'; break;
823                  case G10ERR_NO_PUBKEY: 
824                  case G10ERR_UNU_PUBKEY: stats->no_key++; continue;
825                  default:                stats->oth_err++; sigrc = '%'; break;
826                 }
827
828                 /* TODO: Make sure a cached sig record here still has
829                    the pk that issued it.  See also
830                    keyedit.c:print_and_check_one_sig */
831             }
832             else {
833                 rc = 0;
834                 sigrc = ' ';
835             }
836
837             if( !any ) { /* no user id, (maybe a revocation follows)*/
838               /* Check if the pk is really revoked - there could be a
839                  0x20 sig packet there even if we are not revoked
840                  (say, if a revocation key issued the packet, but the
841                  revocation key isn't present to verify it.) */
842                 if( sig->sig_class == 0x20 && pk->is_revoked )
843                     puts("[revoked]");
844                 else if( sig->sig_class == 0x18 )
845                     puts("[key binding]");
846                 else if( sig->sig_class == 0x28 )
847                     puts("[subkey revoked]");
848                 else
849                     putchar('\n');
850                 if( fpr )
851                     print_fingerprint( pk, sk, 0 );
852                 any=1;
853             }
854
855             if( sig->sig_class == 0x20 || sig->sig_class == 0x28
856                                        || sig->sig_class == 0x30 )
857                sigstr = "rev";
858             else if( (sig->sig_class&~3) == 0x10 )
859                sigstr = "sig";
860             else if( sig->sig_class == 0x18 )
861                sigstr = "sig";
862             else if( sig->sig_class == 0x1F )
863                sigstr = "sig";
864             else {
865                 printf("sig                             "
866                        "[unexpected signature class 0x%02x]\n",sig->sig_class );
867                 continue;
868             }
869
870             fputs( sigstr, stdout );
871             printf("%c%c %c%c%c%c%c%c ",
872                    sigrc,(sig->sig_class-0x10>0 &&
873                           sig->sig_class-0x10<4)?'0'+sig->sig_class-0x10:' ',
874                    sig->flags.exportable?' ':'L',
875                    sig->flags.revocable?' ':'R',
876                    sig->flags.policy_url?'P':' ',
877                    sig->flags.notation?'N':' ',
878                    sig->flags.expired?'X':' ',
879                    (sig->trust_depth>9)?'T':
880                    (sig->trust_depth>0)?'0'+sig->trust_depth:' ');
881             if(opt.list_options&LIST_SHOW_LONG_KEYIDS)
882               printf("%08lX%08lX",(ulong)sig->keyid[0],(ulong)sig->keyid[1]);
883             else
884               printf("%08lX",(ulong)sig->keyid[1]);
885             printf(" %s", datestr_from_sig(sig));
886             if(opt.list_options&LIST_SHOW_SIG_EXPIRE)
887               printf(" %s", expirestr_from_sig(sig));
888             printf("  ");
889             if( sigrc == '%' )
890                 printf("[%s] ", g10_errstr(rc) );
891             else if( sigrc == '?' )
892                 ;
893             else if ( !opt.fast_list_mode ) {
894                 size_t n;
895                 char *p = get_user_id( sig->keyid, &n );
896                 print_utf8_string( stdout, p, n );
897                 m_free(p);
898             }
899             putchar('\n');
900
901             if(sig->flags.policy_url
902                && (opt.list_options&LIST_SHOW_POLICY_URLS))
903               show_policy_url(sig,3,0);
904
905             if(sig->flags.notation
906                && (opt.list_options&LIST_SHOW_NOTATIONS))
907               show_notation(sig,3,0);
908
909             if(sig->flags.pref_ks
910                && (opt.list_options&LIST_SHOW_KEYSERVER_URLS))
911               show_keyserver_url(sig,3,0);
912
913             /* fixme: check or list other sigs here */
914         }
915     }
916     putchar('\n');
917 }
918
919
920 static void
921 list_keyblock_colon( KBNODE keyblock, int secret, int fpr )
922 {
923     int rc = 0;
924     KBNODE kbctx;
925     KBNODE node;
926     PKT_public_key *pk;
927     PKT_secret_key *sk;
928     u32 keyid[2];
929     int any=0;
930     int trustletter = 0;
931     int ulti_hack = 0;
932     int i;
933
934     /* get the keyid from the keyblock */
935     node = find_kbnode( keyblock, secret? PKT_SECRET_KEY : PKT_PUBLIC_KEY );
936     if( !node ) {
937         log_error("Oops; key lost!\n");
938         dump_kbnode( keyblock );
939         return;
940     }
941
942     if( secret ) {
943         pk = NULL;
944         sk = node->pkt->pkt.secret_key;
945         keyid_from_sk( sk, keyid );
946         printf("sec::%u:%d:%08lX%08lX:%s:%s:::",
947                     nbits_from_sk( sk ),
948                     sk->pubkey_algo,
949                     (ulong)keyid[0],(ulong)keyid[1],
950                     colon_datestr_from_sk( sk ),
951                     colon_strtime (sk->expiredate)
952                     /* fixme: add LID here */ );
953     }
954     else {
955         pk = node->pkt->pkt.public_key;
956         sk = NULL;
957         keyid_from_pk( pk, keyid );
958         fputs( "pub:", stdout );
959         if ( !pk->is_valid )
960             putchar ('i');
961         else if ( pk->is_revoked )
962             putchar ('r');
963         else if ( pk->has_expired )
964             putchar ('e');
965         else if ( opt.fast_list_mode || opt.no_expensive_trust_checks ) 
966             ;
967         else {
968             trustletter = get_validity_info ( pk, NULL );
969             if( trustletter == 'u' )
970                 ulti_hack = 1;
971             putchar(trustletter);
972         }
973         printf(":%u:%d:%08lX%08lX:%s:%s::",
974                     nbits_from_pk( pk ),
975                     pk->pubkey_algo,
976                     (ulong)keyid[0],(ulong)keyid[1],
977                     colon_datestr_from_pk( pk ),
978                     colon_strtime (pk->expiredate) );
979         if( !opt.fast_list_mode && !opt.no_expensive_trust_checks  )
980             putchar( get_ownertrust_info(pk) );
981             putchar(':');
982     }
983     
984     if (opt.fixed_list_mode) {
985         /* do not merge the first uid with the primary key */
986         putchar(':');
987         putchar(':');
988         print_capabilities (pk, sk, keyblock);
989         if (secret) {
990           putchar(':'); /* End of field 13. */
991           putchar(':'); /* End of field 14. */
992           if (sk->protect.s2k.mode == 1001)
993             putchar('#'); /* Key is just a stub. */
994           else if (sk->protect.s2k.mode == 1002) {
995             /* Key is stored on an external token (card) or handled by
996                the gpg-agent.  Print the serial number of that token
997                here. */
998             for (i=0; i < sk->protect.ivlen; i++)
999               printf ("%02X", sk->protect.iv[i]);
1000           }
1001           putchar(':'); /* End of field 15. */
1002         }
1003         putchar('\n');
1004         if( fpr )
1005             print_fingerprint( pk, sk, 0 );
1006         if( opt.with_key_data )
1007             print_key_data( pk, keyid );
1008         any = 1;
1009     }
1010
1011
1012     for( kbctx=NULL; (node=walk_kbnode( keyblock, &kbctx, 0)) ; ) {
1013         if( node->pkt->pkttype == PKT_USER_ID && !opt.fast_list_mode ) {
1014             PKT_user_id *uid=node->pkt->pkt.user_id;
1015             if(attrib_fp && node->pkt->pkt.user_id->attrib_data!=NULL)
1016               dump_attribs(node->pkt->pkt.user_id,pk,sk);
1017             /*
1018              * Fixme: We need a is_valid flag here too 
1019              */
1020             if( any ) {
1021                 char *str=uid->attrib_data?"uat":"uid";
1022                 /* If we're listing a secret key, leave out the
1023                    validity values for now.  This is handled better in
1024                    1.9. */
1025                 if ( sk )
1026                     printf("%s:::::",str);
1027                 else if ( uid->is_revoked )
1028                     printf("%s:r::::",str);
1029                 else if ( uid->is_expired )
1030                     printf("%s:e::::",str);
1031                 else if ( opt.no_expensive_trust_checks )
1032                     printf("%s:::::",str);
1033                 else {
1034                     int uid_validity;
1035
1036                     if( pk && !ulti_hack )
1037                       uid_validity=get_validity_info (pk, uid);
1038                     else
1039                         uid_validity = 'u';
1040                     printf("%s:%c::::",str,uid_validity);
1041                 }
1042
1043                 printf("%s:",colon_strtime(uid->created));
1044                 printf("%s:",colon_strtime(uid->expiredate));
1045
1046                 namehash_from_uid(uid);
1047
1048                 for(i=0; i < 20; i++ )
1049                   printf("%02X",uid->namehash[i]);
1050
1051                 printf("::");
1052             }
1053             if(uid->attrib_data)
1054               printf("%u %lu",uid->numattribs,uid->attrib_len);
1055             else
1056               print_string(stdout,uid->name,uid->len, ':' );
1057             putchar(':');
1058             if (any)
1059                 putchar('\n');
1060             else {
1061                 putchar(':');
1062                 print_capabilities (pk, sk, keyblock);
1063                 putchar('\n');
1064                 if( fpr )
1065                     print_fingerprint( pk, sk, 0 );
1066                 if( opt.with_key_data )
1067                     print_key_data( pk, keyid );
1068                 any = 1;
1069             }
1070         }
1071         else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
1072             u32 keyid2[2];
1073             PKT_public_key *pk2 = node->pkt->pkt.public_key;
1074
1075             if( !any ) {
1076                 putchar(':');
1077                 putchar(':');
1078                 print_capabilities (pk, sk, keyblock);
1079                 putchar('\n');
1080                 if( fpr )
1081                     print_fingerprint( pk, sk, 0 ); /* of the main key */
1082                 any = 1;
1083             }
1084
1085             keyid_from_pk( pk2, keyid2 );
1086             fputs ("sub:", stdout );
1087             if ( !pk2->is_valid )
1088                 putchar ('i');
1089             else if ( pk2->is_revoked )
1090                 putchar ('r');
1091             else if ( pk2->has_expired )
1092                 putchar ('e');
1093             else if ( opt.fast_list_mode || opt.no_expensive_trust_checks )
1094                 ;
1095             else {
1096                 /* trustletter should always be defined here */
1097                 if(trustletter)
1098                   printf("%c", trustletter );
1099             }
1100             printf(":%u:%d:%08lX%08lX:%s:%s:::::",
1101                         nbits_from_pk( pk2 ),
1102                         pk2->pubkey_algo,
1103                         (ulong)keyid2[0],(ulong)keyid2[1],
1104                         colon_datestr_from_pk( pk2 ),
1105                         colon_strtime (pk2->expiredate)
1106                         /* fixme: add LID and ownertrust here */
1107                                                 );
1108             print_capabilities (pk2, NULL, NULL);
1109             putchar('\n');
1110             if( fpr > 1 )
1111                 print_fingerprint( pk2, NULL, 0 );
1112             if( opt.with_key_data )
1113                 print_key_data( pk2, keyid2 );
1114         }
1115         else if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
1116             u32 keyid2[2];
1117             PKT_secret_key *sk2 = node->pkt->pkt.secret_key;
1118
1119             if( !any ) {
1120                 putchar(':');
1121                 putchar(':');
1122                 print_capabilities (pk, sk, keyblock);
1123                 putchar('\n');
1124                 if( fpr )
1125                     print_fingerprint( pk, sk, 0 ); /* of the main key */
1126                 any = 1;
1127             }
1128
1129             keyid_from_sk( sk2, keyid2 );
1130             printf("ssb::%u:%d:%08lX%08lX:%s:%s:::::",
1131                         nbits_from_sk( sk2 ),
1132                         sk2->pubkey_algo,
1133                         (ulong)keyid2[0],(ulong)keyid2[1],
1134                         colon_datestr_from_sk( sk2 ),
1135                         colon_strtime (sk2->expiredate)
1136                    /* fixme: add LID */ );
1137             print_capabilities (NULL, sk2, NULL);
1138             if (opt.fixed_list_mode) {
1139               /* We print the serial number only in fixed list mode
1140                  for the primary key so, so avoid questions we print
1141                  it for subkeys also only in this mode.  There is no
1142                  technical reason, though. */
1143               putchar(':'); /* End of field 13. */
1144               putchar(':'); /* End of field 14. */
1145               if (sk2->protect.s2k.mode == 1001)
1146                 putchar('#'); /* Key is just a stub. */
1147               else if (sk2->protect.s2k.mode == 1002) {
1148                 /* Key is stored on an external token (card) or handled by
1149                    the gpg-agent.  Print the serial number of that token
1150                    here. */
1151                 for (i=0; i < sk2->protect.ivlen; i++)
1152                   printf ("%02X", sk2->protect.iv[i]);
1153               }
1154               putchar(':'); /* End of field 15. */
1155             }
1156             putchar ('\n');
1157             if( fpr > 1 )
1158               print_fingerprint( NULL, sk2, 0 );
1159         }
1160         else if( opt.list_sigs && node->pkt->pkttype == PKT_SIGNATURE ) {
1161             PKT_signature *sig = node->pkt->pkt.signature;
1162             int sigrc,fprokay=0;
1163             char *sigstr;
1164             size_t fplen;
1165             byte fparray[MAX_FINGERPRINT_LEN];
1166
1167             if( !any ) { /* no user id, (maybe a revocation follows)*/
1168                 if( sig->sig_class == 0x20 )
1169                     fputs("[revoked]:", stdout);
1170                 else if( sig->sig_class == 0x18 )
1171                     fputs("[key binding]:", stdout);
1172                 else if( sig->sig_class == 0x28 )
1173                     fputs("[subkey revoked]:", stdout);
1174                 else
1175                     putchar (':');
1176                 putchar(':');
1177                 print_capabilities (pk, sk, keyblock);
1178                 putchar('\n');
1179                 if( fpr )
1180                     print_fingerprint( pk, sk, 0 );
1181                 any=1;
1182             }
1183
1184             if( sig->sig_class == 0x20 || sig->sig_class == 0x28
1185                                        || sig->sig_class == 0x30 )
1186                sigstr = "rev";
1187             else if( (sig->sig_class&~3) == 0x10 )
1188                sigstr = "sig";
1189             else if( sig->sig_class == 0x18 )
1190                sigstr = "sig";
1191             else if( sig->sig_class == 0x1F )
1192                sigstr = "sig";
1193             else {
1194                 printf ("sig::::::::::%02x%c:\n",
1195                         sig->sig_class, sig->flags.exportable?'x':'l');
1196                 continue;
1197             }
1198             if( opt.check_sigs ) {
1199                 PKT_public_key *signer_pk=NULL;
1200
1201                 fflush(stdout);
1202                 if(opt.no_sig_cache)
1203                   signer_pk=m_alloc_clear(sizeof(PKT_public_key));
1204
1205                 rc = check_key_signature2( keyblock, node, NULL, signer_pk,
1206                                            NULL, NULL, NULL );
1207                 switch( rc ) {
1208                   case 0:                  sigrc = '!'; break;
1209                   case G10ERR_BAD_SIGN:    sigrc = '-'; break;
1210                   case G10ERR_NO_PUBKEY: 
1211                   case G10ERR_UNU_PUBKEY:  sigrc = '?'; break;
1212                   default:                 sigrc = '%'; break;
1213                 }
1214
1215                 if(opt.no_sig_cache)
1216                   {
1217                     if(rc==0)
1218                       {
1219                         fingerprint_from_pk (signer_pk, fparray, &fplen);
1220                         fprokay=1;
1221                       }
1222                     free_public_key(signer_pk);
1223                   }
1224             }
1225             else {
1226                 rc = 0;
1227                 sigrc = ' ';
1228             }
1229             fputs( sigstr, stdout );
1230             putchar(':');
1231             if( sigrc != ' ' )
1232                 putchar(sigrc);
1233             printf("::%d:%08lX%08lX:%s:%s:", sig->pubkey_algo,
1234                    (ulong)sig->keyid[0], (ulong)sig->keyid[1],
1235                    colon_datestr_from_sig(sig),
1236                    colon_expirestr_from_sig(sig));
1237
1238             if(sig->trust_depth || sig->trust_value)
1239               printf("%d %d",sig->trust_depth,sig->trust_value);
1240             printf(":");
1241
1242             if(sig->trust_regexp)
1243               print_string(stdout,sig->trust_regexp,
1244                            strlen(sig->trust_regexp),':');
1245             printf(":");
1246
1247             if( sigrc == '%' )
1248                 printf("[%s] ", g10_errstr(rc) );
1249             else if( sigrc == '?' )
1250                 ;
1251             else if ( !opt.fast_list_mode ) {
1252                 size_t n;
1253                 char *p = get_user_id( sig->keyid, &n );
1254                 print_string( stdout, p, n, ':' );
1255                 m_free(p);
1256             }
1257             printf(":%02x%c:", sig->sig_class,sig->flags.exportable?'x':'l');
1258
1259             if(opt.no_sig_cache && opt.check_sigs && fprokay)
1260               {
1261                 printf(":");
1262
1263                 for (i=0; i < fplen ; i++ )
1264                   printf ("%02X", fparray[i] );
1265
1266                 printf(":");
1267               }
1268
1269             printf("\n");
1270
1271             /* fixme: check or list other sigs here */
1272         }
1273     }
1274     if( !any ) {/* oops, no user id */
1275         putchar(':');
1276         putchar(':');
1277         print_capabilities (pk, sk, keyblock);
1278         putchar('\n');
1279     }
1280 }
1281
1282 /*
1283  * Reorder the keyblock so that the primary user ID (and not attribute
1284  * packet) comes first.  Fixme: Replace this by a generic sort
1285  * function.  */
1286 void
1287 reorder_keyblock (KBNODE keyblock)
1288 {
1289     KBNODE primary = NULL, primary0 = NULL, primary2 = NULL;
1290     KBNODE last, node;
1291
1292     for (node=keyblock; node; primary0=node, node = node->next) {
1293         if( node->pkt->pkttype == PKT_USER_ID &&
1294             !node->pkt->pkt.user_id->attrib_data &&
1295             node->pkt->pkt.user_id->is_primary ) {
1296             primary = primary2 = node;
1297             for (node=node->next; node; primary2=node, node = node->next ) {
1298                 if( node->pkt->pkttype == PKT_USER_ID 
1299                     || node->pkt->pkttype == PKT_PUBLIC_SUBKEY 
1300                     || node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
1301                     break;
1302                 }
1303             }
1304             break;
1305         }
1306     }
1307     if ( !primary )
1308         return;  /* no primary key flag found (should not happen) */
1309
1310     for (last=NULL, node=keyblock; node; last = node, node = node->next) {
1311         if( node->pkt->pkttype == PKT_USER_ID )
1312             break;
1313     }
1314     assert (node);
1315     assert (last); /* the user ID is never the first packet */
1316     assert (primary0);  /* ditto (this is the node before primary) */
1317     if ( node == primary )
1318         return; /* already the first one */
1319
1320     last->next = primary;
1321     primary0->next = primary2->next;
1322     primary2->next = node;
1323 }
1324
1325 void
1326 list_keyblock( KBNODE keyblock, int secret, int fpr, void *opaque )
1327 {
1328     reorder_keyblock (keyblock);
1329     if (opt.with_colons)
1330         list_keyblock_colon (keyblock, secret, fpr );
1331     else
1332         list_keyblock_print (keyblock, secret, fpr, opaque );
1333 }
1334
1335 /*
1336  * standard function to print the finperprint.
1337  * mode 0: as used in key listings, opt.with_colons is honored
1338  *      1: print using log_info ()
1339  *      2: direct use of tty
1340  *      3: direct use of tty but only primary key.
1341  * modes 1 and 2 will try and print both subkey and primary key fingerprints
1342  */
1343 void
1344 print_fingerprint (PKT_public_key *pk, PKT_secret_key *sk, int mode )
1345 {
1346     byte array[MAX_FINGERPRINT_LEN], *p;
1347     size_t i, n;
1348     FILE *fp;
1349     const char *text;
1350     int primary=0;
1351
1352     if(sk)
1353       {
1354         if(sk->main_keyid[0]==sk->keyid[0] && sk->main_keyid[1]==sk->keyid[1])
1355           primary=1;
1356       }
1357     else
1358       {
1359         if(pk->main_keyid[0]==pk->keyid[0] && pk->main_keyid[1]==pk->keyid[1])
1360           primary=1;
1361       }
1362
1363     /* Just to be safe */
1364     if(mode&0x80 && !primary)
1365       {
1366         log_error("primary key is not really primary!\n");
1367         return;
1368       }
1369
1370     mode&=~0x80;
1371
1372     if(!primary && (mode==1 || mode==2))
1373       {
1374         if(sk)
1375           {
1376             PKT_secret_key *primary_sk=m_alloc_clear(sizeof(*primary_sk));
1377             get_seckey(primary_sk,sk->main_keyid);
1378             print_fingerprint(NULL,primary_sk,mode|0x80);
1379             free_secret_key(primary_sk);
1380           }
1381         else
1382           {
1383             PKT_public_key *primary_pk=m_alloc_clear(sizeof(*primary_pk));
1384             get_pubkey(primary_pk,pk->main_keyid);
1385             print_fingerprint(primary_pk,NULL,mode|0x80);
1386             free_public_key(primary_pk);
1387           }
1388       }
1389
1390     if (mode == 1) {
1391         fp = log_stream ();
1392         if(primary)
1393           text = _("Primary key fingerprint:");
1394         else
1395           text = _("     Subkey fingerprint:");
1396     }
1397     else if (mode == 2) {
1398         fp = NULL; /* use tty */
1399         /* Translators: this should fit into 24 bytes to that the fingerprint
1400          * data is properly aligned with the user ID */
1401         if(primary)
1402           text = _(" Primary key fingerprint:");
1403         else
1404           text = _("      Subkey fingerprint:");
1405     }
1406     else if (mode == 3) {
1407         fp = NULL; /* use tty */
1408         text = _("      Key fingerprint =");
1409     }
1410     else {
1411         fp = stdout;
1412         text = _("      Key fingerprint =");
1413     }
1414   
1415     if (sk)
1416         fingerprint_from_sk (sk, array, &n);
1417     else
1418         fingerprint_from_pk (pk, array, &n);
1419     p = array;
1420     if (opt.with_colons && !mode) {
1421         fprintf (fp, "fpr:::::::::");
1422         for (i=0; i < n ; i++, p++ )
1423             fprintf (fp, "%02X", *p );
1424         putc(':', fp);
1425     }
1426     else {
1427         if (fp)
1428             fputs (text, fp);
1429         else
1430             tty_printf ("%s", text);
1431         if (n == 20) {
1432             for (i=0; i < n ; i++, i++, p += 2 ) {
1433                 if (fp) {
1434                     if (i == 10 )
1435                         putc(' ', fp);
1436                     fprintf (fp, " %02X%02X", *p, p[1] );
1437                 }
1438                 else {
1439                     if (i == 10 )
1440                         tty_printf (" ");
1441                     tty_printf (" %02X%02X", *p, p[1]);
1442                 }
1443             }
1444         }
1445         else {
1446             for (i=0; i < n ; i++, p++ ) {
1447                 if (fp) {
1448                     if (i && !(i%8) )
1449                         putc (' ', fp);
1450                     fprintf (fp, " %02X", *p );
1451                 }
1452                 else {
1453                     if (i && !(i%8) )
1454                         tty_printf (" ");
1455                     tty_printf (" %02X", *p );
1456                 }
1457             }
1458         }
1459     }
1460     if (fp)
1461         putc ('\n', fp);
1462     else
1463         tty_printf ("\n");
1464 }
1465
1466 void set_attrib_fd(int fd)
1467 {
1468   static int last_fd=-1;
1469
1470   if ( fd != -1 && last_fd == fd )
1471     return;
1472
1473   if ( attrib_fp && attrib_fp != stdout && attrib_fp != stderr )
1474     fclose (attrib_fp);
1475   attrib_fp = NULL;
1476   if ( fd == -1 ) 
1477     return;
1478
1479   if( fd == 1 )
1480     attrib_fp = stdout;
1481   else if( fd == 2 )
1482     attrib_fp = stderr;
1483   else
1484     attrib_fp = fdopen( fd, "wb" );
1485   if( !attrib_fp ) {
1486     log_fatal("can't open fd %d for attribute output: %s\n",
1487               fd, strerror(errno));
1488   }
1489
1490   last_fd = fd;
1491 }