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