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