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