mutt stable branch with some hacks
1/*
2 * Copyright (C) 1997-2003 Thomas Roessler <roessler@does-not-exist.org>
3 *
4 * This program is free software; you can redistribute it
5 * and/or modify it under the terms of the GNU General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later
8 * version.
9 *
10 * This program is distributed in the hope that it will be
11 * useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13 * PURPOSE. See the GNU General Public License for more
14 * details.
15 *
16 * You should have received a copy of the GNU General Public
17 * License along with this program; if not, write to the Free
18 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22/*
23 * This is a "simple" PGP key ring dumper.
24 *
25 * The output format is supposed to be compatible to the one GnuPG
26 * emits and Mutt expects.
27 *
28 * Note that the code of this program could be considerably less
29 * complex, but most of it was taken from mutt's second generation
30 * key ring parser.
31 *
32 * You can actually use this to put together some fairly general
33 * PGP key management applications.
34 *
35 */
36
37#if HAVE_CONFIG_H
38# include "config.h"
39#endif
40
41#include <stdio.h>
42#include <stdlib.h>
43#include <string.h>
44#include <unistd.h>
45#include <time.h>
46#ifdef HAVE_GETOPT_H
47# include <getopt.h>
48#endif
49#include <errno.h>
50
51extern char *optarg;
52extern int optind;
53
54#include "sha1.h"
55#include "md5.h"
56#include "lib.h"
57#include "pgplib.h"
58#include "pgppacket.h"
59
60#define MD5_DIGEST_LENGTH 16
61
62#ifdef HAVE_FGETPOS
63#define FGETPOS(fp,pos) fgetpos((fp),&(pos))
64#define FSETPOS(fp,pos) fsetpos((fp),&(pos))
65#else
66#define FGETPOS(fp,pos) pos=ftello((fp));
67#define FSETPOS(fp,pos) fseeko((fp),(pos),SEEK_SET)
68#endif
69
70
71static short dump_signatures = 0;
72static short dump_fingerprints = 0;
73
74
75static void pgpring_find_candidates (char *ringfile, const char *hints[], int nhints);
76static void pgpring_dump_keyblock (pgp_key_t p);
77
78int main (int argc, char * const argv[])
79{
80 int c;
81
82 short version = 2;
83 short secring = 0;
84
85 const char *_kring = NULL;
86 char *env_pgppath, *env_home;
87
88 char pgppath[_POSIX_PATH_MAX];
89 char kring[_POSIX_PATH_MAX+12];
90
91 while ((c = getopt (argc, argv, "f25sk:S")) != EOF)
92 {
93 switch (c)
94 {
95 case 'S':
96 {
97 dump_signatures = 1;
98 break;
99 }
100
101 case 'f':
102 {
103 dump_fingerprints = 1;
104 break;
105 }
106
107 case 'k':
108 {
109 _kring = optarg;
110 break;
111 }
112
113 case '2': case '5':
114 {
115 version = c - '0';
116 break;
117 }
118
119 case 's':
120 {
121 secring = 1;
122 break;
123 }
124
125 default:
126 {
127 fprintf (stderr, "usage: %s [-k <key ring> | [-2 | -5] [ -s] [-S] [-f]] [hints]\n",
128 argv[0]);
129 exit (1);
130 }
131 }
132 }
133
134 if (_kring)
135 strfcpy (kring, _kring, sizeof (kring));
136 else
137 {
138 if ((env_pgppath = getenv ("PGPPATH")))
139 strfcpy (pgppath, env_pgppath, sizeof (pgppath));
140 else if ((env_home = getenv ("HOME")))
141 snprintf (pgppath, sizeof (pgppath), "%s/.pgp", env_home);
142 else
143 {
144 fprintf (stderr, "%s: Can't determine your PGPPATH.\n", argv[0]);
145 exit (1);
146 }
147
148 if (secring)
149 snprintf (kring, sizeof (kring), "%s/secring.%s", pgppath, version == 2 ? "pgp" : "skr");
150 else
151 snprintf (kring, sizeof (kring), "%s/pubring.%s", pgppath, version == 2 ? "pgp" : "pkr");
152 }
153
154 pgpring_find_candidates (kring, (const char**) argv + optind, argc - optind);
155
156 return 0;
157}
158
159static char *binary_fingerprint_to_string (unsigned char *buff, size_t length)
160{
161 int i;
162 char *fingerprint, *pf;
163
164 pf = fingerprint = (char *)safe_malloc ((length * 2) + 1);
165
166 for (i = 0; i < length; i++)
167 {
168 sprintf (pf, "%02X", buff[i]);
169 pf += 2;
170 }
171 *pf = 0;
172
173 return fingerprint;
174}
175
176
177/* The actual key ring parser */
178static void pgp_make_pgp2_fingerprint (unsigned char *buff,
179 unsigned char *digest)
180{
181 struct md5_ctx ctx;
182 unsigned int size = 0;
183
184 md5_init_ctx (&ctx);
185
186 size = (buff[0] << 8) + buff[1];
187 size = ((size + 7) / 8);
188 buff = &buff[2];
189
190 md5_process_bytes (buff, size, &ctx);
191
192 buff = &buff[size];
193
194 size = (buff[0] << 8) + buff[1];
195 size = ((size + 7) / 8);
196 buff = &buff[2];
197
198 md5_process_bytes (buff, size, &ctx);
199
200 md5_finish_ctx (&ctx, digest);
201} /* pgp_make_pgp2_fingerprint() */
202
203static pgp_key_t pgp_parse_pgp2_key (unsigned char *buff, size_t l)
204{
205 pgp_key_t p;
206 unsigned char alg;
207 unsigned char digest[MD5_DIGEST_LENGTH];
208 size_t expl;
209 unsigned long id;
210 time_t gen_time = 0;
211 unsigned short exp_days = 0;
212 size_t j;
213 int i, k;
214 unsigned char scratch[LONG_STRING];
215
216 if (l < 12)
217 return NULL;
218
219 p = pgp_new_keyinfo();
220
221 for (i = 0, j = 2; i < 4; i++)
222 gen_time = (gen_time << 8) + buff[j++];
223
224 p->gen_time = gen_time;
225
226 for (i = 0; i < 2; i++)
227 exp_days = (exp_days << 8) + buff[j++];
228
229 if (exp_days && time (NULL) > gen_time + exp_days * 24 * 3600)
230 p->flags |= KEYFLAG_EXPIRED;
231
232 alg = buff[j++];
233
234 p->numalg = alg;
235 p->algorithm = pgp_pkalgbytype (alg);
236 p->flags |= pgp_get_abilities (alg);
237
238 if (dump_fingerprints)
239 {
240 /* j now points to the key material, which we need for the fingerprint */
241 pgp_make_pgp2_fingerprint (&buff[j], digest);
242 p->fingerprint = binary_fingerprint_to_string (digest, MD5_DIGEST_LENGTH);
243 }
244
245 expl = 0;
246 for (i = 0; i < 2; i++)
247 expl = (expl << 8) + buff[j++];
248
249 p->keylen = expl;
250
251 expl = (expl + 7) / 8;
252 if (expl < 4)
253 goto bailout;
254
255
256 j += expl - 8;
257
258 for (k = 0; k < 2; k++)
259 {
260 for (id = 0, i = 0; i < 4; i++)
261 id = (id << 8) + buff[j++];
262
263 snprintf ((char *) scratch + k * 8, sizeof (scratch) - k * 8,
264 "%08lX", id);
265 }
266
267 p->keyid = safe_strdup ((char *) scratch);
268
269 return p;
270
271bailout:
272
273 FREE (&p);
274 return NULL;
275}
276
277static void pgp_make_pgp3_fingerprint (unsigned char *buff, size_t l,
278 unsigned char *digest)
279{
280 unsigned char dummy;
281 SHA1_CTX context;
282
283 SHA1_Init (&context);
284
285 dummy = buff[0] & 0x3f;
286
287 if (dummy == PT_SUBSECKEY || dummy == PT_SUBKEY || dummy == PT_SECKEY)
288 dummy = PT_PUBKEY;
289
290 dummy = (dummy << 2) | 0x81;
291 SHA1_Update (&context, &dummy, 1);
292 dummy = ((l - 1) >> 8) & 0xff;
293 SHA1_Update (&context, &dummy, 1);
294 dummy = (l - 1) & 0xff;
295 SHA1_Update (&context, &dummy, 1);
296 SHA1_Update (&context, buff + 1, l - 1);
297 SHA1_Final (digest, &context);
298
299}
300
301static void skip_bignum (unsigned char *buff, size_t l, size_t j,
302 size_t * toff, size_t n)
303{
304 size_t len;
305
306 do
307 {
308 len = (buff[j] << 8) + buff[j + 1];
309 j += (len + 7) / 8 + 2;
310 }
311 while (j <= l && --n > 0);
312
313 if (toff)
314 *toff = j;
315}
316
317
318static pgp_key_t pgp_parse_pgp3_key (unsigned char *buff, size_t l)
319{
320 pgp_key_t p;
321 unsigned char alg;
322 unsigned char digest[SHA_DIGEST_LENGTH];
323 unsigned char scratch[LONG_STRING];
324 time_t gen_time = 0;
325 unsigned long id;
326 int i, k;
327 short len;
328 size_t j;
329
330 p = pgp_new_keyinfo ();
331 j = 2;
332
333 for (i = 0; i < 4; i++)
334 gen_time = (gen_time << 8) + buff[j++];
335
336 p->gen_time = gen_time;
337
338 alg = buff[j++];
339
340 p->numalg = alg;
341 p->algorithm = pgp_pkalgbytype (alg);
342 p->flags |= pgp_get_abilities (alg);
343
344 len = (buff[j] << 8) + buff[j + 1];
345 p->keylen = len;
346
347 if (alg >= 1 && alg <= 3)
348 skip_bignum (buff, l, j, &j, 2);
349 else if (alg == 16 || alg == 20)
350 skip_bignum (buff, l, j, &j, 3);
351 else if (alg == 17)
352 skip_bignum (buff, l, j, &j, 4);
353
354 pgp_make_pgp3_fingerprint (buff, j, digest);
355 if (dump_fingerprints)
356 {
357 p->fingerprint = binary_fingerprint_to_string (digest, SHA_DIGEST_LENGTH);
358 }
359
360 for (k = 0; k < 2; k++)
361 {
362 for (id = 0, i = SHA_DIGEST_LENGTH - 8 + k * 4;
363 i < SHA_DIGEST_LENGTH + (k - 1) * 4; i++)
364 id = (id << 8) + digest[i];
365
366 snprintf ((char *) scratch + k * 8, sizeof (scratch) - k * 8, "%08lX", id);
367 }
368
369 p->keyid = safe_strdup ((char *) scratch);
370
371 return p;
372}
373
374static pgp_key_t pgp_parse_keyinfo (unsigned char *buff, size_t l)
375{
376 if (!buff || l < 2)
377 return NULL;
378
379 switch (buff[1])
380 {
381 case 2:
382 case 3:
383 return pgp_parse_pgp2_key (buff, l);
384 case 4:
385 return pgp_parse_pgp3_key (buff, l);
386 default:
387 return NULL;
388 }
389}
390
391static int pgp_parse_pgp2_sig (unsigned char *buff, size_t l,
392 pgp_key_t p, pgp_sig_t *s)
393{
394 unsigned char sigtype;
395 time_t sig_gen_time;
396 unsigned long signerid1;
397 unsigned long signerid2;
398 size_t j;
399 int i;
400
401 if (l < 22)
402 return -1;
403
404 j = 3;
405 sigtype = buff[j++];
406
407 sig_gen_time = 0;
408 for (i = 0; i < 4; i++)
409 sig_gen_time = (sig_gen_time << 8) + buff[j++];
410
411 signerid1 = signerid2 = 0;
412 for (i = 0; i < 4; i++)
413 signerid1 = (signerid1 << 8) + buff[j++];
414
415 for (i = 0; i < 4; i++)
416 signerid2 = (signerid2 << 8) + buff[j++];
417
418
419 if (sigtype == 0x20 || sigtype == 0x28)
420 p->flags |= KEYFLAG_REVOKED;
421
422 if (s)
423 {
424 s->sigtype = sigtype;
425 s->sid1 = signerid1;
426 s->sid2 = signerid2;
427 }
428
429 return 0;
430}
431
432static int pgp_parse_pgp3_sig (unsigned char *buff, size_t l,
433 pgp_key_t p, pgp_sig_t *s)
434{
435 unsigned char sigtype;
436 unsigned char skt;
437 time_t sig_gen_time = -1;
438 long validity = -1;
439 long key_validity = -1;
440 unsigned long signerid1 = 0;
441 unsigned long signerid2 = 0;
442 size_t ml;
443 size_t j;
444 int i;
445 short ii;
446 short have_critical_spks = 0;
447
448 if (l < 7)
449 return -1;
450
451 j = 2;
452
453 sigtype = buff[j++];
454 j += 2; /* pkalg, hashalg */
455
456 for (ii = 0; ii < 2; ii++)
457 {
458 size_t skl;
459 size_t nextone;
460
461 ml = (buff[j] << 8) + buff[j + 1];
462 j += 2;
463
464 if (j + ml > l)
465 break;
466
467 nextone = j;
468 while (ml)
469 {
470 j = nextone;
471 skl = buff[j++];
472 if (!--ml)
473 break;
474
475 if (skl >= 192)
476 {
477 skl = (skl - 192) * 256 + buff[j++] + 192;
478 if (!--ml)
479 break;
480 }
481
482 if ((int) ml - (int) skl < 0)
483 break;
484 ml -= skl;
485
486 nextone = j + skl;
487 skt = buff[j++];
488
489 switch (skt & 0x7f)
490 {
491 case 2: /* creation time */
492 {
493 if (skl < 4)
494 break;
495 sig_gen_time = 0;
496 for (i = 0; i < 4; i++)
497 sig_gen_time = (sig_gen_time << 8) + buff[j++];
498
499 break;
500 }
501 case 3: /* expiration time */
502 {
503 if (skl < 4)
504 break;
505 validity = 0;
506 for (i = 0; i < 4; i++)
507 validity = (validity << 8) + buff[j++];
508 break;
509 }
510 case 9: /* key expiration time */
511 {
512 if (skl < 4)
513 break;
514 key_validity = 0;
515 for (i = 0; i < 4; i++)
516 key_validity = (key_validity << 8) + buff[j++];
517 break;
518 }
519 case 16: /* issuer key ID */
520 {
521 if (skl < 8)
522 break;
523 signerid2 = signerid1 = 0;
524 for (i = 0; i < 4; i++)
525 signerid1 = (signerid1 << 8) + buff[j++];
526 for (i = 0; i < 4; i++)
527 signerid2 = (signerid2 << 8) + buff[j++];
528
529 break;
530 }
531 case 10: /* CMR key */
532 break;
533 case 4: /* exportable */
534 case 5: /* trust */
535 case 6: /* regexp */
536 case 7: /* revocable */
537 case 11: /* Pref. symm. alg. */
538 case 12: /* revocation key */
539 case 20: /* notation data */
540 case 21: /* pref. hash */
541 case 22: /* pref. comp.alg. */
542 case 23: /* key server prefs. */
543 case 24: /* pref. key server */
544 default:
545 {
546 if (skt & 0x80)
547 have_critical_spks = 1;
548 }
549 }
550 }
551 j = nextone;
552 }
553
554 if (sigtype == 0x20 || sigtype == 0x28)
555 p->flags |= KEYFLAG_REVOKED;
556 if (key_validity != -1 && time (NULL) > p->gen_time + key_validity)
557 p->flags |= KEYFLAG_EXPIRED;
558 if (have_critical_spks)
559 p->flags |= KEYFLAG_CRITICAL;
560
561 if (s)
562 {
563 s->sigtype = sigtype;
564 s->sid1 = signerid1;
565 s->sid2 = signerid2;
566 }
567
568
569 return 0;
570
571}
572
573
574static int pgp_parse_sig (unsigned char *buff, size_t l,
575 pgp_key_t p, pgp_sig_t *sig)
576{
577 if (!buff || l < 2 || !p)
578 return -1;
579
580 switch (buff[1])
581 {
582 case 2:
583 case 3:
584 return pgp_parse_pgp2_sig (buff, l, p, sig);
585 case 4:
586 return pgp_parse_pgp3_sig (buff, l, p, sig);
587 default:
588 return -1;
589 }
590}
591
592/* parse one key block, including all subkeys. */
593
594static pgp_key_t pgp_parse_keyblock (FILE * fp)
595{
596 unsigned char *buff;
597 unsigned char pt = 0;
598 unsigned char last_pt;
599 size_t l;
600 short err = 0;
601
602#ifdef HAVE_FGETPOS
603 fpos_t pos;
604#else
605 LOFF_T pos;
606#endif
607
608 pgp_key_t root = NULL;
609 pgp_key_t *last = &root;
610 pgp_key_t p = NULL;
611 pgp_uid_t *uid = NULL;
612 pgp_uid_t **addr = NULL;
613 pgp_sig_t **lsig = NULL;
614
615 FGETPOS(fp,pos);
616
617 while (!err && (buff = pgp_read_packet (fp, &l)) != NULL)
618 {
619 last_pt = pt;
620 pt = buff[0] & 0x3f;
621
622 /* check if we have read the complete key block. */
623
624 if ((pt == PT_SECKEY || pt == PT_PUBKEY) && root)
625 {
626 FSETPOS(fp, pos);
627 return root;
628 }
629
630 switch (pt)
631 {
632 case PT_SECKEY:
633 case PT_PUBKEY:
634 case PT_SUBKEY:
635 case PT_SUBSECKEY:
636 {
637 if (!(*last = p = pgp_parse_keyinfo (buff, l)))
638 {
639 err = 1;
640 break;
641 }
642
643 last = &p->next;
644 addr = &p->address;
645 lsig = &p->sigs;
646
647 if (pt == PT_SUBKEY || pt == PT_SUBSECKEY)
648 {
649 p->flags |= KEYFLAG_SUBKEY;
650 if (p != root)
651 {
652 p->parent = root;
653 p->address = pgp_copy_uids (root->address, p);
654 while (*addr) addr = &(*addr)->next;
655 }
656 }
657
658 if (pt == PT_SECKEY || pt == PT_SUBSECKEY)
659 p->flags |= KEYFLAG_SECRET;
660
661 break;
662 }
663
664 case PT_SIG:
665 {
666 if (lsig)
667 {
668 pgp_sig_t *signature = safe_calloc (sizeof (pgp_sig_t), 1);
669 *lsig = signature;
670 lsig = &signature->next;
671
672 pgp_parse_sig (buff, l, p, signature);
673 }
674 break;
675 }
676
677 case PT_TRUST:
678 {
679 if (p && (last_pt == PT_SECKEY || last_pt == PT_PUBKEY ||
680 last_pt == PT_SUBKEY || last_pt == PT_SUBSECKEY))
681 {
682 if (buff[1] & 0x20)
683 {
684 p->flags |= KEYFLAG_DISABLED;
685 }
686 }
687 else if (last_pt == PT_NAME && uid)
688 {
689 uid->trust = buff[1];
690 }
691 break;
692 }
693 case PT_NAME:
694 {
695 char *chr;
696
697
698 if (!addr)
699 break;
700
701 chr = safe_malloc (l);
702 memcpy (chr, buff + 1, l - 1);
703 chr[l - 1] = '\0';
704
705
706 *addr = uid = safe_calloc (1, sizeof (pgp_uid_t)); /* XXX */
707 uid->addr = chr;
708 uid->parent = p;
709 uid->trust = 0;
710 addr = &uid->next;
711 lsig = &uid->sigs;
712
713 /* the following tags are generated by
714 * pgp 2.6.3in.
715 */
716
717 if (strstr (chr, "ENCR"))
718 p->flags |= KEYFLAG_PREFER_ENCRYPTION;
719 if (strstr (chr, "SIGN"))
720 p->flags |= KEYFLAG_PREFER_SIGNING;
721
722 break;
723 }
724 }
725
726 FGETPOS(fp,pos);
727 }
728
729 if (err)
730 pgp_free_key (&root);
731
732 return root;
733}
734
735static int pgpring_string_matches_hint (const char *s, const char *hints[], int nhints)
736{
737 int i;
738
739 if (!hints || !nhints)
740 return 1;
741
742 for (i = 0; i < nhints; i++)
743 {
744 if (mutt_stristr (s, hints[i]) != NULL)
745 return 1;
746 }
747
748 return 0;
749}
750
751/*
752 * Go through the key ring file and look for keys with
753 * matching IDs.
754 */
755
756static void pgpring_find_candidates (char *ringfile, const char *hints[], int nhints)
757{
758 FILE *rfp;
759#ifdef HAVE_FGETPOS
760 fpos_t pos, keypos;
761#else
762 LOFF_T pos, keypos;
763#endif
764
765 unsigned char *buff = NULL;
766 unsigned char pt = 0;
767 size_t l = 0;
768
769 short err = 0;
770
771 if ((rfp = fopen (ringfile, "r")) == NULL)
772 {
773 char *error_buf;
774 size_t error_buf_len;
775
776 error_buf_len = sizeof ("fopen: ") - 1 + strlen (ringfile) + 1;
777 error_buf = safe_malloc (error_buf_len);
778 snprintf (error_buf, error_buf_len, "fopen: %s", ringfile);
779 perror (error_buf);
780 FREE (&error_buf);
781 return;
782 }
783
784 FGETPOS(rfp,pos);
785 FGETPOS(rfp,keypos);
786
787 while (!err && (buff = pgp_read_packet (rfp, &l)) != NULL)
788 {
789 pt = buff[0] & 0x3f;
790
791 if (l < 1)
792 continue;
793
794 if ((pt == PT_SECKEY) || (pt == PT_PUBKEY))
795 {
796 keypos = pos;
797 }
798 else if (pt == PT_NAME)
799 {
800 char *tmp = safe_malloc (l);
801
802 memcpy (tmp, buff + 1, l - 1);
803 tmp[l - 1] = '\0';
804
805 /* mutt_decode_utf8_string (tmp, chs); */
806
807 if (pgpring_string_matches_hint (tmp, hints, nhints))
808 {
809 pgp_key_t p;
810
811 FSETPOS(rfp, keypos);
812
813 /* Not bailing out here would lead us into an endless loop. */
814
815 if ((p = pgp_parse_keyblock (rfp)) == NULL)
816 err = 1;
817
818 pgpring_dump_keyblock (p);
819 pgp_free_key (&p);
820 }
821
822 FREE (&tmp);
823 }
824
825 FGETPOS(rfp,pos);
826 }
827
828 safe_fclose (&rfp);
829
830}
831
832static void print_userid (const char *id)
833{
834 for (; id && *id; id++)
835 {
836 if (*id >= ' ' && *id <= 'z' && *id != ':')
837 putchar (*id);
838 else
839 printf ("\\x%02x", (*id) & 0xff);
840 }
841}
842
843static void print_fingerprint (pgp_key_t p)
844{
845 if (!p->fingerprint)
846 return;
847
848 printf ("fpr:::::::::%s:\n", p->fingerprint);
849} /* print_fingerprint() */
850
851
852static void pgpring_dump_signatures (pgp_sig_t *sig)
853{
854 for (; sig; sig = sig->next)
855 {
856 if (sig->sigtype == 0x10 || sig->sigtype == 0x11 ||
857 sig->sigtype == 0x12 || sig->sigtype == 0x13)
858 printf ("sig::::%08lX%08lX::::::%X:\n",
859 sig->sid1, sig->sid2, sig->sigtype);
860 else if (sig->sigtype == 0x20)
861 printf ("rev::::%08lX%08lX::::::%X:\n",
862 sig->sid1, sig->sid2, sig->sigtype);
863 }
864}
865
866
867static char gnupg_trustletter (int t)
868{
869 switch (t)
870 {
871 case 1: return 'n';
872 case 2: return 'm';
873 case 3: return 'f';
874 }
875 return 'q';
876}
877
878static void pgpring_dump_keyblock (pgp_key_t p)
879{
880 pgp_uid_t *uid;
881 short first;
882 struct tm *tp;
883 time_t t;
884
885 for (; p; p = p->next)
886 {
887 first = 1;
888
889 if (p->flags & KEYFLAG_SECRET)
890 {
891 if (p->flags & KEYFLAG_SUBKEY)
892 printf ("ssb:");
893 else
894 printf ("sec:");
895 }
896 else
897 {
898 if (p->flags & KEYFLAG_SUBKEY)
899 printf ("sub:");
900 else
901 printf ("pub:");
902 }
903
904 if (p->flags & KEYFLAG_REVOKED)
905 putchar ('r');
906 if (p->flags & KEYFLAG_EXPIRED)
907 putchar ('e');
908 if (p->flags & KEYFLAG_DISABLED)
909 putchar ('d');
910
911 for (uid = p->address; uid; uid = uid->next, first = 0)
912 {
913 if (!first)
914 {
915 printf ("uid:%c::::::::", gnupg_trustletter (uid->trust));
916 print_userid (uid->addr);
917 printf (":\n");
918 }
919 else
920 {
921 if (p->flags & KEYFLAG_SECRET)
922 putchar ('u');
923 else
924 putchar (gnupg_trustletter (uid->trust));
925
926 t = p->gen_time;
927 tp = gmtime (&t);
928
929 printf (":%d:%d:%s:%04d-%02d-%02d::::", p->keylen, p->numalg, p->keyid,
930 1900 + tp->tm_year, tp->tm_mon + 1, tp->tm_mday);
931
932 print_userid (uid->addr);
933 printf ("::");
934
935 if (pgp_canencrypt(p->numalg))
936 putchar ('e');
937 if (pgp_cansign(p->numalg))
938 putchar ('s');
939 if (p->flags & KEYFLAG_DISABLED)
940 putchar ('D');
941 printf (":\n");
942
943 if (dump_fingerprints)
944 print_fingerprint (p);
945 }
946
947 if (dump_signatures)
948 {
949 if (first) pgpring_dump_signatures (p->sigs);
950 pgpring_dump_signatures (uid->sigs);
951 }
952 }
953 }
954}
955
956/*
957 * The mutt_gettext () defined in gettext.c requires iconv,
958 * so we do without charset conversion here.
959 */
960
961char *mutt_gettext (const char *message)
962{
963 return (char *)message;
964}