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