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