Nico Golde:
[apps/madmutt.git] / pgp.c
1 /*
2  * Copyright notice from original mutt:
3  * Copyright (C) 1996,1997 Michael R. Elkins <me@mutt.org>
4  * Copyright (C) 1998,1999 Thomas Roessler <roessler@does-not-exist.org>
5  * Copyright (C) 2004 g10 Code GmbH
6  *
7  * This file is part of mutt-ng, see http://www.muttng.org/.
8  * It's licensed under the GNU General Public License,
9  * please see the file GPL in the top level source directory.
10  */
11
12 /*
13  * This file contains all of the PGP routines necessary to sign, encrypt,
14  * verify and decrypt PGP messages in either the new PGP/MIME format, or
15  * in the older Application/Pgp format.  It also contains some code to
16  * cache the user's passphrase for repeat use when decrypting or signing
17  * a message.
18  */
19
20 #if HAVE_CONFIG_H
21 # include "config.h"
22 #endif
23
24 #include "mutt.h"
25 #include "mutt_curses.h"
26 #include "pgp.h"
27 #include "mime.h"
28 #include "copy.h"
29
30 #include <sys/wait.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <sys/stat.h>
35 #include <errno.h>
36 #include <ctype.h>
37
38 #ifdef HAVE_LOCALE_H
39 #include <locale.h>
40 #endif
41
42 #ifdef HAVE_SYS_TIME_H
43 # include <sys/time.h>
44 #endif
45
46 #ifdef HAVE_SYS_RESOURCE_H
47 # include <sys/resource.h>
48 #endif
49
50 #ifdef CRYPT_BACKEND_CLASSIC_PGP
51
52 #include "mutt_crypt.h"
53 #include "mutt_menu.h"
54
55
56 char PgpPass[STRING];
57 time_t PgpExptime = 0;          /* when does the cached passphrase expire? */
58
59 void pgp_void_passphrase (void)
60 {
61   memset (PgpPass, 0, sizeof (PgpPass));
62   PgpExptime = 0;
63 }
64
65 int pgp_valid_passphrase (void)
66 {
67   time_t now = time (NULL);
68
69   if (pgp_use_gpg_agent ()) {
70     *PgpPass = 0;
71     return 1;                   /* handled by gpg-agent */
72   }
73
74   if (now < PgpExptime)
75     /* Use cached copy.  */
76     return 1;
77
78   pgp_void_passphrase ();
79
80   if (mutt_get_password
81       (_("Enter PGP passphrase:"), PgpPass, sizeof (PgpPass)) == 0) {
82     PgpExptime = time (NULL) + PgpTimeout;
83     return (1);
84   }
85   else
86     PgpExptime = 0;
87
88   return 0;
89 }
90
91 void pgp_forget_passphrase (void)
92 {
93   pgp_void_passphrase ();
94   mutt_message _("PGP passphrase forgotten.");
95 }
96
97 int pgp_use_gpg_agent (void)
98 {
99   return option (OPTUSEGPGAGENT) && getenv ("GPG_TTY")
100     && getenv ("GPG_AGENT_INFO");
101 }
102
103 char *pgp_keyid (pgp_key_t k)
104 {
105   if ((k->flags & KEYFLAG_SUBKEY) && k->parent && option (OPTPGPIGNORESUB))
106     k = k->parent;
107
108   return _pgp_keyid (k);
109 }
110
111 char *_pgp_keyid (pgp_key_t k)
112 {
113   if (option (OPTPGPLONGIDS))
114     return k->keyid;
115   else
116     return (k->keyid + 8);
117 }
118
119 /* ----------------------------------------------------------------------------
120  * Routines for handing PGP input.
121  */
122
123
124
125 /* Copy PGP output messages and look for signs of a good signature */
126
127 static int pgp_copy_checksig (FILE * fpin, FILE * fpout)
128 {
129   int rv = -1;
130
131   if (PgpGoodSign.pattern) {
132     char *line = NULL;
133     int lineno = 0;
134     size_t linelen;
135
136     while ((line = mutt_read_line (line, &linelen, fpin, &lineno)) != NULL) {
137       if (regexec (PgpGoodSign.rx, line, 0, NULL, 0) == 0) {
138         dprint (2, (debugfile, "pgp_copy_checksig: \"%s\" matches regexp.\n",
139                     line));
140         rv = 0;
141       }
142       else
143         dprint (2,
144                 (debugfile,
145                  "pgp_copy_checksig: \"%s\" doesn't match regexp.\n", line));
146
147       if (strncmp (line, "[GNUPG:] ", 9) == 0)
148         continue;
149       fputs (line, fpout);
150       fputc ('\n', fpout);
151     }
152     FREE (&line);
153   }
154   else {
155     dprint (2, (debugfile, "pgp_copy_checksig: No pattern.\n"));
156     mutt_copy_stream (fpin, fpout);
157     rv = 1;
158   }
159
160   return rv;
161 }
162
163 /* 
164  * Copy a clearsigned message, and strip the signature and PGP's
165  * dash-escaping.
166  * 
167  * XXX - charset handling: We assume that it is safe to do
168  * character set decoding first, dash decoding second here, while
169  * we do it the other way around in the main handler.
170  * 
171  * (Note that we aren't worse than Outlook &c in this, and also
172  * note that we can successfully handle anything produced by any
173  * existing versions of mutt.) 
174  */
175
176 static void pgp_copy_clearsigned (FILE * fpin, STATE * s, char *charset)
177 {
178   char buf[HUGE_STRING];
179   short complete, armor_header;
180
181   FGETCONV *fc;
182
183   rewind (fpin);
184
185   fc = fgetconv_open (fpin, charset, Charset, M_ICONV_HOOK_FROM);
186
187   for (complete = 1, armor_header = 1;
188        fgetconvs (buf, sizeof (buf), fc) != NULL;
189        complete = strchr (buf, '\n') != NULL) {
190     if (!complete) {
191       if (!armor_header)
192         state_puts (buf, s);
193       continue;
194     }
195
196     if (mutt_strcmp (buf, "-----BEGIN PGP SIGNATURE-----\n") == 0)
197       break;
198
199     if (armor_header) {
200       char *p = mutt_skip_whitespace (buf);
201
202       if (*p == '\0')
203         armor_header = 0;
204       continue;
205     }
206
207     if (s->prefix)
208       state_puts (s->prefix, s);
209
210     if (buf[0] == '-' && buf[1] == ' ')
211       state_puts (buf + 2, s);
212     else
213       state_puts (buf, s);
214   }
215
216   fgetconv_close (&fc);
217 }
218
219
220 /* Support for the Application/PGP Content Type. */
221
222 void pgp_application_pgp_handler (BODY * m, STATE * s)
223 {
224   int needpass = -1, pgp_keyblock = 0;
225   int clearsign = 0, rv, rc;
226   long start_pos = 0;
227   long bytes, last_pos, offset;
228   char buf[HUGE_STRING];
229   char outfile[_POSIX_PATH_MAX];
230   char tmpfname[_POSIX_PATH_MAX];
231   FILE *pgpout = NULL, *pgpin = NULL, *pgperr = NULL;
232   FILE *tmpfp;
233   pid_t thepid;
234
235   short maybe_goodsig = 1;
236   short have_any_sigs = 0;
237
238   char body_charset[STRING];
239
240   mutt_get_body_charset (body_charset, sizeof (body_charset), m);
241
242   rc = 0;                       /* silence false compiler warning if (s->flags & M_DISPLAY) */
243
244   fseek (s->fpin, m->offset, 0);
245   last_pos = m->offset;
246
247   for (bytes = m->length; bytes > 0;) {
248     if (fgets (buf, sizeof (buf), s->fpin) == NULL)
249       break;
250
251     offset = ftell (s->fpin);
252     bytes -= (offset - last_pos);       /* don't rely on mutt_strlen(buf) */
253     last_pos = offset;
254
255     if (mutt_strncmp ("-----BEGIN PGP ", buf, 15) == 0) {
256       clearsign = 0;
257       start_pos = last_pos;
258
259       if (mutt_strcmp ("MESSAGE-----\n", buf + 15) == 0)
260         needpass = 1;
261       else if (mutt_strcmp ("SIGNED MESSAGE-----\n", buf + 15) == 0) {
262         clearsign = 1;
263         needpass = 0;
264       }
265       else if (!option (OPTDONTHANDLEPGPKEYS) &&
266                mutt_strcmp ("PUBLIC KEY BLOCK-----\n", buf + 15) == 0) {
267         needpass = 0;
268         pgp_keyblock = 1;
269       }
270       else {
271         /* XXX - we may wish to recode here */
272         if (s->prefix)
273           state_puts (s->prefix, s);
274         state_puts (buf, s);
275         continue;
276       }
277
278       have_any_sigs = have_any_sigs || (clearsign && (s->flags & M_VERIFY));
279
280       /* Copy PGP material to temporary file */
281       mutt_mktemp (tmpfname);
282       if ((tmpfp = safe_fopen (tmpfname, "w+")) == NULL) {
283         mutt_perror (tmpfname);
284         return;
285       }
286
287       fputs (buf, tmpfp);
288       while (bytes > 0 && fgets (buf, sizeof (buf) - 1, s->fpin) != NULL) {
289         offset = ftell (s->fpin);
290         bytes -= (offset - last_pos);   /* don't rely on mutt_strlen(buf) */
291         last_pos = offset;
292
293         fputs (buf, tmpfp);
294
295         if ((needpass
296              && mutt_strcmp ("-----END PGP MESSAGE-----\n", buf) == 0)
297             || (!needpass
298                 && (mutt_strcmp ("-----END PGP SIGNATURE-----\n", buf) == 0
299                     || mutt_strcmp ("-----END PGP PUBLIC KEY BLOCK-----\n",
300                                     buf) == 0)))
301           break;
302       }
303
304       /* leave tmpfp open in case we still need it - but flush it! */
305       fflush (tmpfp);
306
307
308       /* Invoke PGP if needed */
309       if (!clearsign || (s->flags & M_VERIFY)) {
310         mutt_mktemp (outfile);
311         if ((pgpout = safe_fopen (outfile, "w+")) == NULL) {
312           mutt_perror (tmpfname);
313           return;
314         }
315
316         if ((thepid = pgp_invoke_decode (&pgpin, NULL, &pgperr, -1,
317                                          fileno (pgpout), -1, tmpfname,
318                                          needpass)) == -1) {
319           safe_fclose (&pgpout);
320           maybe_goodsig = 0;
321           pgpin = NULL;
322           pgperr = NULL;
323           state_attach_puts (_
324                              ("[-- Error: unable to create PGP subprocess! --]\n"),
325                              s);
326         }
327         else {                  /* PGP started successfully */
328
329           if (needpass) {
330             if (!pgp_valid_passphrase ())
331               pgp_void_passphrase ();
332             if (pgp_use_gpg_agent ())
333               *PgpPass = 0;
334             fprintf (pgpin, "%s\n", PgpPass);
335           }
336
337           safe_fclose (&pgpin);
338
339           if (s->flags & M_DISPLAY) {
340             crypt_current_time (s, "PGP");
341             rc = pgp_copy_checksig (pgperr, s->fpout);
342           }
343
344           safe_fclose (&pgperr);
345           rv = mutt_wait_filter (thepid);
346
347           if (s->flags & M_DISPLAY) {
348             if (rc == 0)
349               have_any_sigs = 1;
350 /*
351  * Sig is bad if
352  * gpg_good_sign-pattern did not match || pgp_decode_command returned not 0
353  * Sig _is_ correct if
354  *  gpg_good_sign="" && pgp_decode_command returned 0
355  */
356             if (rc == -1 || rv)
357               maybe_goodsig = 0;
358
359             state_putc ('\n', s);
360             state_attach_puts (_("[-- End of PGP output --]\n\n"), s);
361           }
362         }
363       }
364
365
366       /*
367        * Now, copy cleartext to the screen.  NOTE - we expect that PGP
368        * outputs utf-8 cleartext.  This may not always be true, but it 
369        * seems to be a reasonable guess.
370        */
371
372       if (s->flags & M_DISPLAY) {
373         if (needpass)
374           state_attach_puts (_("[-- BEGIN PGP MESSAGE --]\n\n"), s);
375         else if (pgp_keyblock)
376           state_attach_puts (_("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"), s);
377         else
378           state_attach_puts (_("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"), s);
379       }
380
381       if (clearsign) {
382         rewind (tmpfp);
383         if (tmpfp)
384           pgp_copy_clearsigned (tmpfp, s, body_charset);
385       }
386       else if (pgpout) {
387         FGETCONV *fc;
388         int c;
389
390         rewind (pgpout);
391         state_set_prefix (s);
392         fc = fgetconv_open (pgpout, "utf-8", Charset, 0);
393         while ((c = fgetconv (fc)) != EOF)
394           state_prefix_putc (c, s);
395         fgetconv_close (&fc);
396       }
397
398       if (s->flags & M_DISPLAY) {
399         state_putc ('\n', s);
400         if (needpass)
401           state_attach_puts (_("[-- END PGP MESSAGE --]\n"), s);
402         else if (pgp_keyblock)
403           state_attach_puts (_("[-- END PGP PUBLIC KEY BLOCK --]\n"), s);
404         else
405           state_attach_puts (_("[-- END PGP SIGNED MESSAGE --]\n"), s);
406       }
407
408       if (tmpfp) {
409         safe_fclose (&tmpfp);
410         mutt_unlink (tmpfname);
411       }
412       if (pgpout) {
413         safe_fclose (&pgpout);
414         mutt_unlink (outfile);
415       }
416     }
417     else {
418       /* XXX - we may wish to recode here */
419       if (s->prefix)
420         state_puts (s->prefix, s);
421       state_puts (buf, s);
422     }
423   }
424
425   m->goodsig = (maybe_goodsig && have_any_sigs);
426
427   if (needpass == -1) {
428     state_attach_puts (_
429                        ("[-- Error: could not find beginning of PGP message! --]\n\n"),
430                        s);
431     return;
432   }
433 }
434
435 static int pgp_check_traditional_one_body (FILE * fp, BODY * b,
436                                            int tagged_only)
437 {
438   char tempfile[_POSIX_PATH_MAX];
439   char buf[HUGE_STRING];
440   FILE *tfp;
441
442   short sgn = 0;
443   short enc = 0;
444   short key = 0;
445
446   if (b->type != TYPETEXT)
447     return 0;
448
449   if (tagged_only && !b->tagged)
450     return 0;
451
452   mutt_mktemp (tempfile);
453   if (mutt_decode_save_attachment (fp, b, tempfile, 0, 0) != 0) {
454     unlink (tempfile);
455     return 0;
456   }
457
458   if ((tfp = fopen (tempfile, "r")) == NULL) {
459     unlink (tempfile);
460     return 0;
461   }
462
463   while (fgets (buf, sizeof (buf), tfp)) {
464     if (mutt_strncmp ("-----BEGIN PGP ", buf, 15) == 0) {
465       if (mutt_strcmp ("MESSAGE-----\n", buf + 15) == 0)
466         enc = 1;
467       else if (mutt_strcmp ("SIGNED MESSAGE-----\n", buf + 15) == 0)
468         sgn = 1;
469       else if (mutt_strcmp ("PUBLIC KEY BLOCK-----\n", buf + 15) == 0)
470         key = 1;
471     }
472   }
473   safe_fclose (&tfp);
474   unlink (tempfile);
475
476   if (!enc && !sgn && !key)
477     return 0;
478
479   /* fix the content type */
480
481   mutt_set_parameter ("format", "fixed", &b->parameter);
482   if (enc)
483     mutt_set_parameter ("x-action", "pgp-encrypted", &b->parameter);
484   else if (sgn)
485     mutt_set_parameter ("x-action", "pgp-signed", &b->parameter);
486   else if (key)
487     mutt_set_parameter ("x-action", "pgp-keys", &b->parameter);
488
489   return 1;
490 }
491
492 int pgp_check_traditional (FILE * fp, BODY * b, int tagged_only)
493 {
494   int rv = 0;
495   int r;
496
497   for (; b; b = b->next) {
498     if (is_multipart (b))
499       rv = pgp_check_traditional (fp, b->parts, tagged_only) || rv;
500     else if (b->type == TYPETEXT) {
501       if ((r = mutt_is_application_pgp (b)))
502         rv = rv || r;
503       else
504         rv = pgp_check_traditional_one_body (fp, b, tagged_only) || rv;
505     }
506   }
507
508   return rv;
509 }
510
511
512
513
514
515 int pgp_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
516 {
517   char sigfile[_POSIX_PATH_MAX], pgperrfile[_POSIX_PATH_MAX];
518   FILE *fp, *pgpout, *pgperr;
519   pid_t thepid;
520   int badsig = -1;
521   int rv;
522
523   snprintf (sigfile, sizeof (sigfile), "%s.asc", tempfile);
524
525   if (!(fp = safe_fopen (sigfile, "w"))) {
526     mutt_perror (sigfile);
527     return -1;
528   }
529
530   fseek (s->fpin, sigbdy->offset, 0);
531   mutt_copy_bytes (s->fpin, fp, sigbdy->length);
532   fclose (fp);
533
534   mutt_mktemp (pgperrfile);
535   if (!(pgperr = safe_fopen (pgperrfile, "w+"))) {
536     mutt_perror (pgperrfile);
537     unlink (sigfile);
538     return -1;
539   }
540
541   crypt_current_time (s, "PGP");
542
543   if ((thepid = pgp_invoke_verify (NULL, &pgpout, NULL,
544                                    -1, -1, fileno (pgperr),
545                                    tempfile, sigfile)) != -1) {
546     if (pgp_copy_checksig (pgpout, s->fpout) >= 0)
547       badsig = 0;
548
549
550     safe_fclose (&pgpout);
551     fflush (pgperr);
552     rewind (pgperr);
553
554     if (pgp_copy_checksig (pgperr, s->fpout) >= 0)
555       badsig = 0;
556
557     if ((rv = mutt_wait_filter (thepid)))
558       badsig = -1;
559
560     dprint (1,
561             (debugfile, "pgp_verify_one: mutt_wait_filter returned %d.\n",
562              rv));
563   }
564
565   safe_fclose (&pgperr);
566
567   state_attach_puts (_("[-- End of PGP output --]\n\n"), s);
568
569   mutt_unlink (sigfile);
570   mutt_unlink (pgperrfile);
571
572   dprint (1, (debugfile, "pgp_verify_one: returning %d.\n", badsig));
573
574   return badsig;
575 }
576
577
578 /* Extract pgp public keys from messages or attachments */
579
580 void pgp_extract_keys_from_messages (HEADER * h)
581 {
582   int i;
583   char tempfname[_POSIX_PATH_MAX];
584   FILE *fpout;
585
586   if (h) {
587     mutt_parse_mime_message (Context, h);
588     if (h->security & PGPENCRYPT && !pgp_valid_passphrase ())
589       return;
590   }
591
592   mutt_mktemp (tempfname);
593   if (!(fpout = safe_fopen (tempfname, "w"))) {
594     mutt_perror (tempfname);
595     return;
596   }
597
598   set_option (OPTDONTHANDLEPGPKEYS);
599
600   if (!h) {
601     for (i = 0; i < Context->vcount; i++) {
602       if (Context->hdrs[Context->v2r[i]]->tagged) {
603         mutt_parse_mime_message (Context, Context->hdrs[Context->v2r[i]]);
604         if (Context->hdrs[Context->v2r[i]]->security & PGPENCRYPT
605             && !pgp_valid_passphrase ()) {
606           fclose (fpout);
607           goto bailout;
608         }
609         mutt_copy_message (fpout, Context, Context->hdrs[Context->v2r[i]],
610                            M_CM_DECODE | M_CM_CHARCONV, 0);
611       }
612     }
613   }
614   else {
615     mutt_parse_mime_message (Context, h);
616     if (h->security & PGPENCRYPT && !pgp_valid_passphrase ()) {
617       fclose (fpout);
618       goto bailout;
619     }
620     mutt_copy_message (fpout, Context, h, M_CM_DECODE | M_CM_CHARCONV, 0);
621   }
622
623   fclose (fpout);
624   mutt_endwin (NULL);
625   pgp_invoke_import (tempfname);
626   mutt_any_key_to_continue (NULL);
627
628 bailout:
629
630   mutt_unlink (tempfname);
631   unset_option (OPTDONTHANDLEPGPKEYS);
632
633 }
634
635 static void pgp_extract_keys_from_attachment (FILE * fp, BODY * top)
636 {
637   STATE s;
638   FILE *tempfp;
639   char tempfname[_POSIX_PATH_MAX];
640
641   mutt_mktemp (tempfname);
642   if (!(tempfp = safe_fopen (tempfname, "w"))) {
643     mutt_perror (tempfname);
644     return;
645   }
646
647   memset (&s, 0, sizeof (STATE));
648
649   s.fpin = fp;
650   s.fpout = tempfp;
651
652   mutt_body_handler (top, &s);
653
654   fclose (tempfp);
655
656   pgp_invoke_import (tempfname);
657   mutt_any_key_to_continue (NULL);
658
659   mutt_unlink (tempfname);
660 }
661
662 void pgp_extract_keys_from_attachment_list (FILE * fp, int tag, BODY * top)
663 {
664   if (!fp) {
665     mutt_error _("Internal error. Inform <roessler@does-not-exist.org>.");
666
667     return;
668   }
669
670   mutt_endwin (NULL);
671   set_option (OPTDONTHANDLEPGPKEYS);
672
673   for (; top; top = top->next) {
674     if (!tag || top->tagged)
675       pgp_extract_keys_from_attachment (fp, top);
676
677     if (!tag)
678       break;
679   }
680
681   unset_option (OPTDONTHANDLEPGPKEYS);
682 }
683
684 BODY *pgp_decrypt_part (BODY * a, STATE * s, FILE * fpout, BODY * p)
685 {
686   char buf[LONG_STRING];
687   FILE *pgpin, *pgpout, *pgperr, *pgptmp;
688   struct stat info;
689   BODY *tattach;
690   int len;
691   char pgperrfile[_POSIX_PATH_MAX];
692   char pgptmpfile[_POSIX_PATH_MAX];
693   pid_t thepid;
694
695   mutt_mktemp (pgperrfile);
696   if ((pgperr = safe_fopen (pgperrfile, "w+")) == NULL) {
697     mutt_perror (pgperrfile);
698     return NULL;
699   }
700   unlink (pgperrfile);
701
702   mutt_mktemp (pgptmpfile);
703   if ((pgptmp = safe_fopen (pgptmpfile, "w")) == NULL) {
704     mutt_perror (pgptmpfile);
705     fclose (pgperr);
706     return NULL;
707   }
708
709   /* Position the stream at the beginning of the body, and send the data to
710    * the temporary file.
711    */
712
713   fseek (s->fpin, a->offset, 0);
714   mutt_copy_bytes (s->fpin, pgptmp, a->length);
715   fclose (pgptmp);
716
717   if ((thepid = pgp_invoke_decrypt (&pgpin, &pgpout, NULL, -1, -1,
718                                     fileno (pgperr), pgptmpfile)) == -1) {
719     fclose (pgperr);
720     unlink (pgptmpfile);
721     if (s->flags & M_DISPLAY)
722       state_attach_puts (_
723                          ("[-- Error: could not create a PGP subprocess! --]\n\n"),
724                          s);
725     return (NULL);
726   }
727
728   /* send the PGP passphrase to the subprocess.  Never do this if the
729      agent is active, because this might lead to a passphrase send as
730      the message. */
731   if (!pgp_use_gpg_agent ())
732     fputs (PgpPass, pgpin);
733   fputc ('\n', pgpin);
734   fclose (pgpin);
735
736   /* Read the output from PGP, and make sure to change CRLF to LF, otherwise
737    * read_mime_header has a hard time parsing the message.
738    */
739   while (fgets (buf, sizeof (buf) - 1, pgpout) != NULL) {
740     len = mutt_strlen (buf);
741     if (len > 1 && buf[len - 2] == '\r')
742       strcpy (buf + len - 2, "\n");     /* __STRCPY_CHECKED__ */
743     fputs (buf, fpout);
744   }
745
746   fclose (pgpout);
747   mutt_wait_filter (thepid);
748   mutt_unlink (pgptmpfile);
749
750   if (s->flags & M_DISPLAY) {
751     fflush (pgperr);
752     rewind (pgperr);
753     if (pgp_copy_checksig (pgperr, s->fpout) == 0 && p)
754       p->goodsig = 1;
755     state_attach_puts (_("[-- End of PGP output --]\n\n"), s);
756   }
757   fclose (pgperr);
758
759   fflush (fpout);
760   rewind (fpout);
761
762   if (fgetc (fpout) == EOF)
763     return NULL;
764
765   rewind (fpout);
766
767   if ((tattach = mutt_read_mime_header (fpout, 0)) != NULL) {
768     /*
769      * Need to set the length of this body part.
770      */
771     fstat (fileno (fpout), &info);
772     tattach->length = info.st_size - tattach->offset;
773
774     /* See if we need to recurse on this MIME part.  */
775
776     mutt_parse_part (fpout, tattach);
777   }
778
779   return (tattach);
780 }
781
782 int pgp_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
783 {
784   char tempfile[_POSIX_PATH_MAX];
785   STATE s;
786   BODY *p = b;
787
788   if (!mutt_is_multipart_encrypted (b))
789     return -1;
790
791   if (!b->parts || !b->parts->next)
792     return -1;
793
794   b = b->parts->next;
795
796   memset (&s, 0, sizeof (s));
797   s.fpin = fpin;
798   mutt_mktemp (tempfile);
799   if ((*fpout = safe_fopen (tempfile, "w+")) == NULL) {
800     mutt_perror (tempfile);
801     return (-1);
802   }
803   unlink (tempfile);
804
805   *cur = pgp_decrypt_part (b, &s, *fpout, p);
806
807   rewind (*fpout);
808
809   if (!*cur)
810     return -1;
811
812   return (0);
813 }
814
815 void pgp_encrypted_handler (BODY * a, STATE * s)
816 {
817   char tempfile[_POSIX_PATH_MAX];
818   FILE *fpout, *fpin;
819   BODY *tattach;
820   BODY *p = a;
821
822   a = a->parts;
823   if (!a || a->type != TYPEAPPLICATION || !a->subtype ||
824       ascii_strcasecmp ("pgp-encrypted", a->subtype) != 0 ||
825       !a->next || a->next->type != TYPEAPPLICATION || !a->next->subtype ||
826       ascii_strcasecmp ("octet-stream", a->next->subtype) != 0) {
827     if (s->flags & M_DISPLAY)
828       state_attach_puts (_("[-- Error: malformed PGP/MIME message! --]\n\n"),
829                          s);
830     return;
831   }
832
833   /*
834    * Move forward to the application/pgp-encrypted body.
835    */
836   a = a->next;
837
838   mutt_mktemp (tempfile);
839   if ((fpout = safe_fopen (tempfile, "w+")) == NULL) {
840     if (s->flags & M_DISPLAY)
841       state_attach_puts (_
842                          ("[-- Error: could not create temporary file! --]\n"),
843                          s);
844     return;
845   }
846
847   if (s->flags & M_DISPLAY)
848     crypt_current_time (s, "PGP");
849
850   if ((tattach = pgp_decrypt_part (a, s, fpout, p)) != NULL) {
851     if (s->flags & M_DISPLAY)
852       state_attach_puts (_
853                          ("[-- The following data is PGP/MIME encrypted --]\n\n"),
854                          s);
855
856     fpin = s->fpin;
857     s->fpin = fpout;
858     mutt_body_handler (tattach, s);
859     s->fpin = fpin;
860
861     /* 
862      * if a multipart/signed is the _only_ sub-part of a
863      * multipart/encrypted, cache signature verification
864      * status.
865      *
866      */
867
868     if (mutt_is_multipart_signed (tattach) && !tattach->next)
869       p->goodsig |= tattach->goodsig;
870
871     if (s->flags & M_DISPLAY) {
872       state_puts ("\n", s);
873       state_attach_puts (_("[-- End of PGP/MIME encrypted data --]\n"), s);
874     }
875
876     mutt_free_body (&tattach);
877   }
878
879   fclose (fpout);
880   mutt_unlink (tempfile);
881 }
882
883 /* ----------------------------------------------------------------------------
884  * Routines for sending PGP/MIME messages.
885  */
886
887
888 BODY *pgp_sign_message (BODY * a)
889 {
890   BODY *t;
891   char buffer[LONG_STRING];
892   char sigfile[_POSIX_PATH_MAX], signedfile[_POSIX_PATH_MAX];
893   FILE *pgpin, *pgpout, *pgperr, *fp, *sfp;
894   int err = 0;
895   int empty = 1;
896   pid_t thepid;
897
898   convert_to_7bit (a);          /* Signed data _must_ be in 7-bit format. */
899
900   mutt_mktemp (sigfile);
901   if ((fp = safe_fopen (sigfile, "w")) == NULL) {
902     return (NULL);
903   }
904
905   mutt_mktemp (signedfile);
906   if ((sfp = safe_fopen (signedfile, "w")) == NULL) {
907     mutt_perror (signedfile);
908     fclose (fp);
909     unlink (sigfile);
910     return NULL;
911   }
912
913   mutt_write_mime_header (a, sfp);
914   fputc ('\n', sfp);
915   mutt_write_mime_body (a, sfp);
916   fclose (sfp);
917
918   if ((thepid = pgp_invoke_sign (&pgpin, &pgpout, &pgperr,
919                                  -1, -1, -1, signedfile)) == -1) {
920     mutt_perror _("Can't open PGP subprocess!");
921
922     fclose (fp);
923     unlink (sigfile);
924     unlink (signedfile);
925     return NULL;
926   }
927
928   if (!pgp_use_gpg_agent ())
929     fputs (PgpPass, pgpin);
930   fputc ('\n', pgpin);
931   fclose (pgpin);
932
933   /*
934    * Read back the PGP signature.  Also, change MESSAGE=>SIGNATURE as
935    * recommended for future releases of PGP.
936    */
937   while (fgets (buffer, sizeof (buffer) - 1, pgpout) != NULL) {
938     if (mutt_strcmp ("-----BEGIN PGP MESSAGE-----\n", buffer) == 0)
939       fputs ("-----BEGIN PGP SIGNATURE-----\n", fp);
940     else if (mutt_strcmp ("-----END PGP MESSAGE-----\n", buffer) == 0)
941       fputs ("-----END PGP SIGNATURE-----\n", fp);
942     else
943       fputs (buffer, fp);
944     empty = 0;                  /* got some output, so we're ok */
945   }
946
947   /* check for errors from PGP */
948   err = 0;
949   while (fgets (buffer, sizeof (buffer) - 1, pgperr) != NULL) {
950     err = 1;
951     fputs (buffer, stdout);
952   }
953
954   if (mutt_wait_filter (thepid) && option (OPTPGPCHECKEXIT))
955     empty = 1;
956
957   fclose (pgperr);
958   fclose (pgpout);
959   unlink (signedfile);
960
961   if (fclose (fp) != 0) {
962     mutt_perror ("fclose");
963     unlink (sigfile);
964     return (NULL);
965   }
966
967   if (err) {
968     pgp_void_passphrase ();
969     mutt_any_key_to_continue (NULL);
970   }
971
972   if (empty) {
973     unlink (sigfile);
974     return (NULL);              /* fatal error while signing */
975   }
976
977   t = mutt_new_body ();
978   t->type = TYPEMULTIPART;
979   t->subtype = safe_strdup ("signed");
980   t->encoding = ENC7BIT;
981   t->use_disp = 0;
982   t->disposition = DISPINLINE;
983
984   mutt_generate_boundary (&t->parameter);
985   mutt_set_parameter ("protocol", "application/pgp-signature", &t->parameter);
986   mutt_set_parameter ("micalg", pgp_micalg (sigfile), &t->parameter);
987
988   t->parts = a;
989   a = t;
990
991   t->parts->next = mutt_new_body ();
992   t = t->parts->next;
993   t->type = TYPEAPPLICATION;
994   t->subtype = safe_strdup ("pgp-signature");
995   t->filename = safe_strdup (sigfile);
996   t->use_disp = 0;
997   t->disposition = DISPINLINE;
998   t->encoding = ENC7BIT;
999   t->unlink = 1;                /* ok to remove this file after sending. */
1000
1001   return (a);
1002 }
1003
1004 static short is_numerical_keyid (const char *s)
1005 {
1006   /* or should we require the "0x"? */
1007   if (strncmp (s, "0x", 2) == 0)
1008     s += 2;
1009   if (strlen (s) % 8)
1010     return 0;
1011   while (*s)
1012     if (strchr ("0123456789ABCDEFabcdef", *s++) == NULL)
1013       return 0;
1014
1015   return 1;
1016 }
1017
1018 /* This routine attempts to find the keyids of the recipients of a message.
1019  * It returns NULL if any of the keys can not be found.
1020  */
1021 char *pgp_findKeys (ADDRESS * to, ADDRESS * cc, ADDRESS * bcc)
1022 {
1023   char *keyID, *keylist = NULL, *t;
1024   size_t keylist_size = 0;
1025   size_t keylist_used = 0;
1026   ADDRESS *tmp = NULL, *addr = NULL;
1027   ADDRESS **last = &tmp;
1028   ADDRESS *p, *q;
1029   int i;
1030   pgp_key_t k_info = NULL, key = NULL;
1031
1032   const char *fqdn = mutt_fqdn (1);
1033
1034   for (i = 0; i < 3; i++) {
1035     switch (i) {
1036     case 0:
1037       p = to;
1038       break;
1039     case 1:
1040       p = cc;
1041       break;
1042     case 2:
1043       p = bcc;
1044       break;
1045     default:
1046       abort ();
1047     }
1048
1049     *last = rfc822_cpy_adr (p);
1050     while (*last)
1051       last = &((*last)->next);
1052   }
1053
1054   if (fqdn)
1055     rfc822_qualify (tmp, fqdn);
1056
1057   tmp = mutt_remove_duplicates (tmp);
1058
1059   for (p = tmp; p; p = p->next) {
1060     char buf[LONG_STRING];
1061
1062     q = p;
1063     k_info = NULL;
1064
1065     if ((keyID = mutt_crypt_hook (p)) != NULL) {
1066       int r;
1067
1068       snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"), keyID,
1069                 p->mailbox);
1070       if ((r = mutt_yesorno (buf, M_YES)) == M_YES) {
1071         if (is_numerical_keyid (keyID)) {
1072           if (strncmp (keyID, "0x", 2) == 0)
1073             keyID += 2;
1074           goto bypass_selection;        /* you don't see this. */
1075         }
1076
1077         /* check for e-mail address */
1078         if ((t = strchr (keyID, '@')) &&
1079             (addr = rfc822_parse_adrlist (NULL, keyID))) {
1080           if (fqdn)
1081             rfc822_qualify (addr, fqdn);
1082           q = addr;
1083         }
1084         else
1085           k_info = pgp_getkeybystr (keyID, KEYFLAG_CANENCRYPT, PGP_PUBRING);
1086       }
1087       else if (r == -1) {
1088         FREE (&keylist);
1089         rfc822_free_address (&tmp);
1090         rfc822_free_address (&addr);
1091         return NULL;
1092       }
1093     }
1094
1095     if (k_info == NULL)
1096       pgp_invoke_getkeys (q);
1097
1098     if (k_info == NULL
1099         && (k_info =
1100             pgp_getkeybyaddr (q, KEYFLAG_CANENCRYPT, PGP_PUBRING)) == NULL) {
1101       snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
1102
1103       if ((key = pgp_ask_for_key (buf, q->mailbox,
1104                                   KEYFLAG_CANENCRYPT, PGP_PUBRING)) == NULL) {
1105         FREE (&keylist);
1106         rfc822_free_address (&tmp);
1107         rfc822_free_address (&addr);
1108         return NULL;
1109       }
1110     }
1111     else
1112       key = k_info;
1113
1114     keyID = pgp_keyid (key);
1115
1116   bypass_selection:
1117     keylist_size += mutt_strlen (keyID) + 4;
1118     safe_realloc (&keylist, keylist_size);
1119     sprintf (keylist + keylist_used, "%s0x%s", keylist_used ? " " : "", /* __SPRINTF_CHECKED__ */
1120              keyID);
1121     keylist_used = mutt_strlen (keylist);
1122
1123     pgp_free_key (&key);
1124     rfc822_free_address (&addr);
1125
1126   }
1127   rfc822_free_address (&tmp);
1128   return (keylist);
1129 }
1130
1131 /* Warning: "a" is no longer freed in this routine, you need
1132  * to free it later.  This is necessary for $fcc_attach. */
1133
1134 BODY *pgp_encrypt_message (BODY * a, char *keylist, int sign)
1135 {
1136   char buf[LONG_STRING];
1137   char tempfile[_POSIX_PATH_MAX], pgperrfile[_POSIX_PATH_MAX];
1138   char pgpinfile[_POSIX_PATH_MAX];
1139   FILE *pgpin, *pgperr, *fpout, *fptmp;
1140   BODY *t;
1141   int err = 0;
1142   int empty = 0;
1143   pid_t thepid;
1144
1145   mutt_mktemp (tempfile);
1146   if ((fpout = safe_fopen (tempfile, "w+")) == NULL) {
1147     mutt_perror (tempfile);
1148     return (NULL);
1149   }
1150
1151   mutt_mktemp (pgperrfile);
1152   if ((pgperr = safe_fopen (pgperrfile, "w+")) == NULL) {
1153     mutt_perror (pgperrfile);
1154     unlink (tempfile);
1155     fclose (fpout);
1156     return NULL;
1157   }
1158   unlink (pgperrfile);
1159
1160   mutt_mktemp (pgpinfile);
1161   if ((fptmp = safe_fopen (pgpinfile, "w")) == NULL) {
1162     mutt_perror (pgpinfile);
1163     unlink (tempfile);
1164     fclose (fpout);
1165     fclose (pgperr);
1166     return NULL;
1167   }
1168
1169   if (sign)
1170     convert_to_7bit (a);
1171
1172   mutt_write_mime_header (a, fptmp);
1173   fputc ('\n', fptmp);
1174   mutt_write_mime_body (a, fptmp);
1175   fclose (fptmp);
1176
1177   if ((thepid = pgp_invoke_encrypt (&pgpin, NULL, NULL, -1,
1178                                     fileno (fpout), fileno (pgperr),
1179                                     pgpinfile, keylist, sign)) == -1) {
1180     fclose (pgperr);
1181     unlink (pgpinfile);
1182     return (NULL);
1183   }
1184
1185   if (sign) {
1186     if (!pgp_use_gpg_agent ())
1187       fputs (PgpPass, pgpin);
1188     fputc ('\n', pgpin);
1189   }
1190   fclose (pgpin);
1191
1192   if (mutt_wait_filter (thepid) && option (OPTPGPCHECKEXIT))
1193     empty = 1;
1194
1195   unlink (pgpinfile);
1196
1197   fflush (fpout);
1198   rewind (fpout);
1199   if (!empty)
1200     empty = (fgetc (fpout) == EOF);
1201   fclose (fpout);
1202
1203   fflush (pgperr);
1204   rewind (pgperr);
1205   while (fgets (buf, sizeof (buf) - 1, pgperr) != NULL) {
1206     err = 1;
1207     fputs (buf, stdout);
1208   }
1209   fclose (pgperr);
1210
1211   /* pause if there is any error output from PGP */
1212   if (err)
1213     mutt_any_key_to_continue (NULL);
1214
1215   if (empty) {
1216     /* fatal error while trying to encrypt message */
1217     unlink (tempfile);
1218     return (NULL);
1219   }
1220
1221   t = mutt_new_body ();
1222   t->type = TYPEMULTIPART;
1223   t->subtype = safe_strdup ("encrypted");
1224   t->encoding = ENC7BIT;
1225   t->use_disp = 0;
1226   t->disposition = DISPINLINE;
1227
1228   mutt_generate_boundary (&t->parameter);
1229   mutt_set_parameter ("protocol", "application/pgp-encrypted", &t->parameter);
1230
1231   t->parts = mutt_new_body ();
1232   t->parts->type = TYPEAPPLICATION;
1233   t->parts->subtype = safe_strdup ("pgp-encrypted");
1234   t->parts->encoding = ENC7BIT;
1235
1236   t->parts->next = mutt_new_body ();
1237   t->parts->next->type = TYPEAPPLICATION;
1238   t->parts->next->subtype = safe_strdup ("octet-stream");
1239   t->parts->next->encoding = ENC7BIT;
1240   t->parts->next->filename = safe_strdup (tempfile);
1241   t->parts->next->use_disp = 1;
1242   t->parts->next->disposition = DISPINLINE;
1243   t->parts->next->unlink = 1;   /* delete after sending the message */
1244   t->parts->next->d_filename = safe_strdup ("msg.asc"); /* non pgp/mime can save */
1245
1246   return (t);
1247 }
1248
1249 BODY *pgp_traditional_encryptsign (BODY * a, int flags, char *keylist)
1250 {
1251   BODY *b;
1252
1253   char pgpoutfile[_POSIX_PATH_MAX];
1254   char pgperrfile[_POSIX_PATH_MAX];
1255   char pgpinfile[_POSIX_PATH_MAX];
1256
1257   char body_charset[STRING];
1258   char *from_charset;
1259   const char *send_charset;
1260
1261   FILE *pgpout = NULL, *pgperr = NULL, *pgpin = NULL;
1262   FILE *fp;
1263
1264   int empty = 0;
1265   int err;
1266
1267   char buff[STRING];
1268
1269   pid_t thepid;
1270
1271   if (a->type != TYPETEXT)
1272     return NULL;
1273   if (ascii_strcasecmp (a->subtype, "plain"))
1274     return NULL;
1275
1276   if ((fp = fopen (a->filename, "r")) == NULL) {
1277     mutt_perror (a->filename);
1278     return NULL;
1279   }
1280
1281   mutt_mktemp (pgpinfile);
1282   if ((pgpin = safe_fopen (pgpinfile, "w")) == NULL) {
1283     mutt_perror (pgpinfile);
1284     fclose (fp);
1285     return NULL;
1286   }
1287
1288   /* The following code is really correct:  If noconv is set,
1289    * a's charset parameter contains the on-disk character set, and
1290    * we have to convert from that to utf-8.  If noconv is not set,
1291    * we have to convert from $charset to utf-8.
1292    */
1293
1294   mutt_get_body_charset (body_charset, sizeof (body_charset), a);
1295   if (a->noconv)
1296     from_charset = body_charset;
1297   else
1298     from_charset = Charset;
1299
1300   if (!mutt_is_us_ascii (body_charset)) {
1301     int c;
1302     FGETCONV *fc;
1303
1304     if (flags & ENCRYPT)
1305       send_charset = "us-ascii";
1306     else
1307       send_charset = "utf-8";
1308
1309     fc = fgetconv_open (fp, from_charset, "utf-8", M_ICONV_HOOK_FROM);
1310     while ((c = fgetconv (fc)) != EOF)
1311       fputc (c, pgpin);
1312
1313     fgetconv_close (&fc);
1314   }
1315   else {
1316     send_charset = "us-ascii";
1317     mutt_copy_stream (fp, pgpin);
1318   }
1319   safe_fclose (&fp);
1320   fclose (pgpin);
1321
1322   mutt_mktemp (pgpoutfile);
1323   mutt_mktemp (pgperrfile);
1324   if ((pgpout = safe_fopen (pgpoutfile, "w+")) == NULL ||
1325       (pgperr = safe_fopen (pgperrfile, "w+")) == NULL) {
1326     mutt_perror (pgpout ? pgperrfile : pgpoutfile);
1327     unlink (pgpinfile);
1328     if (pgpout) {
1329       fclose (pgpout);
1330       unlink (pgpoutfile);
1331     }
1332     return NULL;
1333   }
1334
1335   unlink (pgperrfile);
1336
1337   if ((thepid = pgp_invoke_traditional (&pgpin, NULL, NULL,
1338                                         -1, fileno (pgpout), fileno (pgperr),
1339                                         pgpinfile, keylist, flags)) == -1) {
1340     mutt_perror _("Can't invoke PGP");
1341
1342     fclose (pgpout);
1343     fclose (pgperr);
1344     mutt_unlink (pgpinfile);
1345     unlink (pgpoutfile);
1346     return NULL;
1347   }
1348
1349   if (pgp_use_gpg_agent ())
1350     *PgpPass = 0;
1351   if (flags & SIGN)
1352     fprintf (pgpin, "%s\n", PgpPass);
1353   fclose (pgpin);
1354
1355   if (mutt_wait_filter (thepid) && option (OPTPGPCHECKEXIT))
1356     empty = 1;
1357
1358   mutt_unlink (pgpinfile);
1359
1360   fflush (pgpout);
1361   fflush (pgperr);
1362
1363   rewind (pgpout);
1364   rewind (pgperr);
1365
1366   if (!empty)
1367     empty = (fgetc (pgpout) == EOF);
1368   fclose (pgpout);
1369
1370   err = 0;
1371
1372   while (fgets (buff, sizeof (buff), pgperr)) {
1373     err = 1;
1374     fputs (buff, stdout);
1375   }
1376
1377   fclose (pgperr);
1378
1379   if (err)
1380     mutt_any_key_to_continue (NULL);
1381
1382   if (empty) {
1383     unlink (pgpoutfile);
1384     return NULL;
1385   }
1386
1387   b = mutt_new_body ();
1388
1389   b->encoding = ENC7BIT;
1390
1391   b->type = TYPETEXT;
1392   b->subtype = safe_strdup ("plain");
1393
1394   mutt_set_parameter ("x-action",
1395                       flags & ENCRYPT ? "pgp-encrypted" : "pgp-signed",
1396                       &b->parameter);
1397   mutt_set_parameter ("charset", send_charset, &b->parameter);
1398
1399   b->filename = safe_strdup (pgpoutfile);
1400
1401 #if 0
1402   /* The following is intended to give a clue to some completely brain-dead 
1403    * "mail environments" which are typically used by large corporations.
1404    */
1405
1406   b->d_filename = safe_strdup ("msg.pgp");
1407   b->use_disp = 1;
1408
1409 #endif
1410
1411   b->disposition = DISPINLINE;
1412   b->unlink = 1;
1413
1414   b->noconv = 1;
1415   b->use_disp = 0;
1416
1417   if (!(flags & ENCRYPT))
1418     b->encoding = a->encoding;
1419
1420   return b;
1421 }
1422
1423 int pgp_send_menu (HEADER * msg, int *redraw)
1424 {
1425   pgp_key_t p;
1426   char input_signas[SHORT_STRING];
1427
1428   char prompt[LONG_STRING];
1429
1430   if (!(WithCrypto & APPLICATION_PGP))
1431     return msg->security;
1432
1433   /* If autoinline and no crypto options set, then set inline. */
1434   if (option (OPTPGPAUTOINLINE) && !((msg->security & APPLICATION_PGP)
1435                                      && (msg->security & (SIGN | ENCRYPT))))
1436     msg->security |= INLINE;
1437
1438   snprintf (prompt, sizeof (prompt),
1439             _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, %s, or (c)lear? "),
1440             (msg->security & INLINE) ? _("PGP/M(i)ME") : _("(i)nline"));
1441
1442   switch (mutt_multi_choice (prompt, _("esabifc"))) {
1443   case 1:                      /* (e)ncrypt */
1444     msg->security |= ENCRYPT;
1445     msg->security &= ~SIGN;
1446     break;
1447
1448   case 2:                      /* (s)ign */
1449     msg->security |= SIGN;
1450     msg->security &= ~ENCRYPT;
1451     break;
1452
1453   case 3:                      /* sign (a)s */
1454     unset_option (OPTPGPCHECKTRUST);
1455
1456     if ((p =
1457          pgp_ask_for_key (_("Sign as: "), NULL, KEYFLAG_CANSIGN,
1458                           PGP_PUBRING))) {
1459       snprintf (input_signas, sizeof (input_signas), "0x%s", pgp_keyid (p));
1460       mutt_str_replace (&PgpSignAs, input_signas);
1461       pgp_free_key (&p);
1462
1463       msg->security |= SIGN;
1464
1465       crypt_pgp_void_passphrase ();     /* probably need a different passphrase */
1466     }
1467 #if 0
1468     else {
1469       msg->security &= ~SIGN;
1470     }
1471 #endif
1472
1473     *redraw = REDRAW_FULL;
1474     break;
1475
1476   case 4:                      /* (b)oth */
1477     msg->security |= (ENCRYPT | SIGN);
1478     break;
1479
1480   case 5:                      /* (i)nline */
1481     if ((msg->security & (ENCRYPT | SIGN)))
1482       msg->security ^= INLINE;
1483     else
1484       msg->security &= ~INLINE;
1485     break;
1486
1487   case 6:                      /* (f)orget it */
1488   case 7:                      /* (c)lear     */
1489     msg->security = 0;
1490     break;
1491   }
1492
1493   if (msg->security) {
1494     if (!(msg->security & (ENCRYPT | SIGN)))
1495       msg->security = 0;
1496     else
1497       msg->security |= APPLICATION_PGP;
1498   }
1499
1500   return (msg->security);
1501 }
1502
1503
1504 #endif /* CRYPT_BACKEND_CLASSIC_PGP */