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_field_unbuffered (_("Enter PGP passphrase:"), PgpPass,
86                                  sizeof (PgpPass), M_PASS) == 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     mem_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 (str_cmp (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 str_len(buf) */
255     last_pos = offset;
256
257     if (str_ncmp ("-----BEGIN PGP ", buf, 15) == 0) {
258       clearsign = 0;
259       start_pos = last_pos;
260
261       if (str_cmp ("MESSAGE-----\n", buf + 15) == 0)
262         needpass = 1;
263       else if (str_cmp ("SIGNED MESSAGE-----\n", buf + 15) == 0) {
264         clearsign = 1;
265         needpass = 0;
266       }
267       else if (!option (OPTDONTHANDLEPGPKEYS) &&
268                str_cmp ("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 str_len(buf) */
293         last_pos = offset;
294
295         fputs (buf, tmpfp);
296
297         if ((needpass
298              && str_cmp ("-----END PGP MESSAGE-----\n", buf) == 0)
299             || (!needpass
300                 && (str_cmp ("-----END PGP SIGNATURE-----\n", buf) == 0
301                     || str_cmp ("-----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 (pgpout !=NULL)
368         if (! ftell(pgpout)) {
369           mutt_error _("Could not decrypt PGP message");
370           goto out;
371         }
372
373       /*
374        * Now, copy cleartext to the screen.  NOTE - we expect that PGP
375        * outputs utf-8 cleartext.  This may not always be true, but it 
376        * seems to be a reasonable guess.
377        */
378
379       if (s->flags & M_DISPLAY) {
380         if (needpass)
381           state_attach_puts (_("[-- BEGIN PGP MESSAGE --]\n\n"), s);
382         else if (pgp_keyblock)
383           state_attach_puts (_("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"), s);
384         else
385           state_attach_puts (_("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"), s);
386       }
387
388       if (clearsign) {
389         rewind (tmpfp);
390         if (tmpfp)
391           pgp_copy_clearsigned (tmpfp, s, body_charset);
392       }
393       else if (pgpout) {
394         FGETCONV *fc;
395         int c;
396
397         rewind (pgpout);
398         state_set_prefix (s);
399         fc = fgetconv_open (pgpout, "utf-8", Charset, 0);
400         while ((c = fgetconv (fc)) != EOF)
401           state_prefix_putc (c, s);
402         fgetconv_close (&fc);
403       }
404
405       if (s->flags & M_DISPLAY) {
406         state_putc ('\n', s);
407         if (needpass) {
408           state_attach_puts (_("[-- END PGP MESSAGE --]\n"), s);
409           mutt_message _("PGP message successfully decrypted.");
410         }
411         else if (pgp_keyblock)
412           state_attach_puts (_("[-- END PGP PUBLIC KEY BLOCK --]\n"), s);
413         else
414           state_attach_puts (_("[-- END PGP SIGNED MESSAGE --]\n"), s);
415       }
416
417     }
418     else {
419       /* XXX - we may wish to recode here */
420       if (s->prefix)
421         state_puts (s->prefix, s);
422       state_puts (buf, s);
423     }
424   }
425
426 out:
427   m->goodsig = (maybe_goodsig && have_any_sigs);
428
429   if (tmpfp) {
430     safe_fclose (&tmpfp);
431     mutt_unlink (tmpfname);
432   }
433   if (pgpout) {
434     safe_fclose (&pgpout);
435     mutt_unlink (outfile);
436   }
437
438   if (needpass == -1) {
439     state_attach_puts (_
440                        ("[-- Error: could not find beginning of PGP message! --]\n\n"),
441                        s);
442     return;
443   }
444 }
445
446 static int pgp_check_traditional_one_body (FILE * fp, BODY * b,
447                                            int tagged_only)
448 {
449   char tempfile[_POSIX_PATH_MAX];
450   char buf[HUGE_STRING];
451   FILE *tfp;
452
453   short sgn = 0;
454   short enc = 0;
455   short key = 0;
456
457   if (b->type != TYPETEXT)
458     return 0;
459
460   if (tagged_only && !b->tagged)
461     return 0;
462
463   mutt_mktemp (tempfile);
464   if (mutt_decode_save_attachment (fp, b, tempfile, 0, 0) != 0) {
465     unlink (tempfile);
466     return 0;
467   }
468
469   if ((tfp = fopen (tempfile, "r")) == NULL) {
470     unlink (tempfile);
471     return 0;
472   }
473
474   while (fgets (buf, sizeof (buf), tfp)) {
475     if (str_ncmp ("-----BEGIN PGP ", buf, 15) == 0) {
476       if (str_cmp ("MESSAGE-----\n", buf + 15) == 0)
477         enc = 1;
478       else if (str_cmp ("SIGNED MESSAGE-----\n", buf + 15) == 0)
479         sgn = 1;
480       else if (str_cmp ("PUBLIC KEY BLOCK-----\n", buf + 15) == 0)
481         key = 1;
482     }
483   }
484   safe_fclose (&tfp);
485   unlink (tempfile);
486
487   if (!enc && !sgn && !key)
488     return 0;
489
490   /* fix the content type */
491
492   mutt_set_parameter ("format", "fixed", &b->parameter);
493   if (enc)
494     mutt_set_parameter ("x-action", "pgp-encrypted", &b->parameter);
495   else if (sgn)
496     mutt_set_parameter ("x-action", "pgp-signed", &b->parameter);
497   else if (key)
498     mutt_set_parameter ("x-action", "pgp-keys", &b->parameter);
499
500   return 1;
501 }
502
503 int pgp_check_traditional (FILE * fp, BODY * b, int tagged_only)
504 {
505   int rv = 0;
506   int r;
507
508   for (; b; b = b->next) {
509     if (is_multipart (b))
510       rv = pgp_check_traditional (fp, b->parts, tagged_only) || rv;
511     else if (b->type == TYPETEXT) {
512       if ((r = mutt_is_application_pgp (b)))
513         rv = rv || r;
514       else
515         rv = pgp_check_traditional_one_body (fp, b, tagged_only) || rv;
516     }
517   }
518
519   return rv;
520 }
521
522
523
524
525
526 int pgp_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
527 {
528   char sigfile[_POSIX_PATH_MAX], pgperrfile[_POSIX_PATH_MAX];
529   FILE *fp, *pgpout, *pgperr;
530   pid_t thepid;
531   int badsig = -1;
532   int rv;
533
534   snprintf (sigfile, sizeof (sigfile), "%s.asc", tempfile);
535
536   if (!(fp = safe_fopen (sigfile, "w"))) {
537     mutt_perror (sigfile);
538     return -1;
539   }
540
541   fseek (s->fpin, sigbdy->offset, 0);
542   mutt_copy_bytes (s->fpin, fp, sigbdy->length);
543   fclose (fp);
544
545   mutt_mktemp (pgperrfile);
546   if (!(pgperr = safe_fopen (pgperrfile, "w+"))) {
547     mutt_perror (pgperrfile);
548     unlink (sigfile);
549     return -1;
550   }
551
552   crypt_current_time (s, "PGP");
553
554   if ((thepid = pgp_invoke_verify (NULL, &pgpout, NULL,
555                                    -1, -1, fileno (pgperr),
556                                    tempfile, sigfile)) != -1) {
557     if (pgp_copy_checksig (pgpout, s->fpout) >= 0)
558       badsig = 0;
559
560
561     safe_fclose (&pgpout);
562     fflush (pgperr);
563     rewind (pgperr);
564
565     if (pgp_copy_checksig (pgperr, s->fpout) >= 0)
566       badsig = 0;
567
568     if ((rv = mutt_wait_filter (thepid)))
569       badsig = -1;
570
571     debug_print (1, ("mutt_wait_filter returned %d.\n", rv));
572   }
573
574   safe_fclose (&pgperr);
575
576   state_attach_puts (_("[-- End of PGP output --]\n\n"), s);
577
578   mutt_unlink (sigfile);
579   mutt_unlink (pgperrfile);
580
581   debug_print (1, ("returning %d.\n", badsig));
582
583   return badsig;
584 }
585
586
587 /* Extract pgp public keys from messages or attachments */
588
589 void pgp_extract_keys_from_messages (HEADER * h)
590 {
591   int i;
592   char tempfname[_POSIX_PATH_MAX];
593   FILE *fpout;
594
595   if (h) {
596     mutt_parse_mime_message (Context, h);
597     if (h->security & PGPENCRYPT && !pgp_valid_passphrase ())
598       return;
599   }
600
601   mutt_mktemp (tempfname);
602   if (!(fpout = safe_fopen (tempfname, "w"))) {
603     mutt_perror (tempfname);
604     return;
605   }
606
607   set_option (OPTDONTHANDLEPGPKEYS);
608
609   if (!h) {
610     for (i = 0; i < Context->vcount; i++) {
611       if (Context->hdrs[Context->v2r[i]]->tagged) {
612         mutt_parse_mime_message (Context, Context->hdrs[Context->v2r[i]]);
613         if (Context->hdrs[Context->v2r[i]]->security & PGPENCRYPT
614             && !pgp_valid_passphrase ()) {
615           fclose (fpout);
616           goto bailout;
617         }
618         mutt_copy_message (fpout, Context, Context->hdrs[Context->v2r[i]],
619                            M_CM_DECODE | M_CM_CHARCONV, 0);
620       }
621     }
622   }
623   else {
624     mutt_parse_mime_message (Context, h);
625     if (h->security & PGPENCRYPT && !pgp_valid_passphrase ()) {
626       fclose (fpout);
627       goto bailout;
628     }
629     mutt_copy_message (fpout, Context, h, M_CM_DECODE | M_CM_CHARCONV, 0);
630   }
631
632   fclose (fpout);
633   mutt_endwin (NULL);
634   pgp_invoke_import (tempfname);
635   mutt_any_key_to_continue (NULL);
636
637 bailout:
638
639   mutt_unlink (tempfname);
640   unset_option (OPTDONTHANDLEPGPKEYS);
641
642 }
643
644 static void pgp_extract_keys_from_attachment (FILE * fp, BODY * top)
645 {
646   STATE s;
647   FILE *tempfp;
648   char tempfname[_POSIX_PATH_MAX];
649
650   mutt_mktemp (tempfname);
651   if (!(tempfp = safe_fopen (tempfname, "w"))) {
652     mutt_perror (tempfname);
653     return;
654   }
655
656   memset (&s, 0, sizeof (STATE));
657
658   s.fpin = fp;
659   s.fpout = tempfp;
660
661   mutt_body_handler (top, &s);
662
663   fclose (tempfp);
664
665   pgp_invoke_import (tempfname);
666   mutt_any_key_to_continue (NULL);
667
668   mutt_unlink (tempfname);
669 }
670
671 void pgp_extract_keys_from_attachment_list (FILE * fp, int tag, BODY * top)
672 {
673   if (!fp) {
674     mutt_error _("Internal error. Inform <roessler@does-not-exist.org>.");
675
676     return;
677   }
678
679   mutt_endwin (NULL);
680   set_option (OPTDONTHANDLEPGPKEYS);
681
682   for (; top; top = top->next) {
683     if (!tag || top->tagged)
684       pgp_extract_keys_from_attachment (fp, top);
685
686     if (!tag)
687       break;
688   }
689
690   unset_option (OPTDONTHANDLEPGPKEYS);
691 }
692
693 BODY *pgp_decrypt_part (BODY * a, STATE * s, FILE * fpout, BODY * p)
694 {
695   char buf[LONG_STRING];
696   FILE *pgpin, *pgpout, *pgperr, *pgptmp;
697   struct stat info;
698   BODY *tattach;
699   int len;
700   char pgperrfile[_POSIX_PATH_MAX];
701   char pgptmpfile[_POSIX_PATH_MAX];
702   pid_t thepid;
703   int rv;
704
705   mutt_mktemp (pgperrfile);
706   if ((pgperr = safe_fopen (pgperrfile, "w+")) == NULL) {
707     mutt_perror (pgperrfile);
708     return NULL;
709   }
710   unlink (pgperrfile);
711
712   mutt_mktemp (pgptmpfile);
713   if ((pgptmp = safe_fopen (pgptmpfile, "w")) == NULL) {
714     mutt_perror (pgptmpfile);
715     fclose (pgperr);
716     return NULL;
717   }
718
719   /* Position the stream at the beginning of the body, and send the data to
720    * the temporary file.
721    */
722
723   fseek (s->fpin, a->offset, 0);
724   mutt_copy_bytes (s->fpin, pgptmp, a->length);
725   fclose (pgptmp);
726
727   if ((thepid = pgp_invoke_decrypt (&pgpin, &pgpout, NULL, -1, -1,
728                                     fileno (pgperr), pgptmpfile)) == -1) {
729     fclose (pgperr);
730     unlink (pgptmpfile);
731     if (s->flags & M_DISPLAY)
732       state_attach_puts (_
733                          ("[-- Error: could not create a PGP subprocess! --]\n\n"),
734                          s);
735     return (NULL);
736   }
737
738   /* send the PGP passphrase to the subprocess.  Never do this if the
739      agent is active, because this might lead to a passphrase send as
740      the message. */
741   if (!pgp_use_gpg_agent ())
742     fputs (PgpPass, pgpin);
743   fputc ('\n', pgpin);
744   fclose (pgpin);
745
746   /* Read the output from PGP, and make sure to change CRLF to LF, otherwise
747    * read_mime_header has a hard time parsing the message.
748    */
749   while (fgets (buf, sizeof (buf) - 1, pgpout) != NULL) {
750     len = str_len (buf);
751     if (len > 1 && buf[len - 2] == '\r')
752       strcpy (buf + len - 2, "\n");     /* __STRCPY_CHECKED__ */
753     fputs (buf, fpout);
754   }
755
756   fclose (pgpout);
757   rv = mutt_wait_filter (thepid);
758   mutt_unlink (pgptmpfile);
759
760   if (s->flags & M_DISPLAY) {
761     fflush (pgperr);
762     rewind (pgperr);
763     if (pgp_copy_checksig (pgperr, s->fpout) == 0 && !rv && p)
764       p->goodsig = 1;
765     else
766       p->goodsig = 0;
767     state_attach_puts (_("[-- End of PGP output --]\n\n"), s);
768   }
769   fclose (pgperr);
770
771   fflush (fpout);
772   rewind (fpout);
773
774   if (fgetc (fpout) == EOF)
775     return NULL;
776
777   rewind (fpout);
778
779   if ((tattach = mutt_read_mime_header (fpout, 0)) != NULL) {
780     /*
781      * Need to set the length of this body part.
782      */
783     fstat (fileno (fpout), &info);
784     tattach->length = info.st_size - tattach->offset;
785
786     /* See if we need to recurse on this MIME part.  */
787
788     mutt_parse_part (fpout, tattach);
789   }
790
791   return (tattach);
792 }
793
794 int pgp_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
795 {
796   char tempfile[_POSIX_PATH_MAX];
797   STATE s;
798   BODY *p = b;
799
800   if (!mutt_is_multipart_encrypted (b))
801     return -1;
802
803   if (!b->parts || !b->parts->next)
804     return -1;
805
806   b = b->parts->next;
807
808   memset (&s, 0, sizeof (s));
809   s.fpin = fpin;
810   mutt_mktemp (tempfile);
811   if ((*fpout = safe_fopen (tempfile, "w+")) == NULL) {
812     mutt_perror (tempfile);
813     return (-1);
814   }
815   unlink (tempfile);
816
817   *cur = pgp_decrypt_part (b, &s, *fpout, p);
818
819   rewind (*fpout);
820
821   if (!*cur)
822     return -1;
823
824   return (0);
825 }
826
827 void pgp_encrypted_handler (BODY * a, STATE * s)
828 {
829   char tempfile[_POSIX_PATH_MAX];
830   FILE *fpout, *fpin;
831   BODY *tattach;
832   BODY *p = a;
833
834   a = a->parts;
835   if (!a || a->type != TYPEAPPLICATION || !a->subtype ||
836       ascii_strcasecmp ("pgp-encrypted", a->subtype) != 0 ||
837       !a->next || a->next->type != TYPEAPPLICATION || !a->next->subtype ||
838       ascii_strcasecmp ("octet-stream", a->next->subtype) != 0) {
839     if (s->flags & M_DISPLAY)
840       state_attach_puts (_("[-- Error: malformed PGP/MIME message! --]\n\n"),
841                          s);
842     return;
843   }
844
845   /*
846    * Move forward to the application/pgp-encrypted body.
847    */
848   a = a->next;
849
850   mutt_mktemp (tempfile);
851   if ((fpout = safe_fopen (tempfile, "w+")) == NULL) {
852     if (s->flags & M_DISPLAY)
853       state_attach_puts (_
854                          ("[-- Error: could not create temporary file! --]\n"),
855                          s);
856     return;
857   }
858
859   if (s->flags & M_DISPLAY)
860     crypt_current_time (s, "PGP");
861
862   if ((tattach = pgp_decrypt_part (a, s, fpout, p)) != NULL) {
863     if (s->flags & M_DISPLAY)
864       state_attach_puts (_
865                          ("[-- The following data is PGP/MIME encrypted --]\n\n"),
866                          s);
867
868     fpin = s->fpin;
869     s->fpin = fpout;
870     mutt_body_handler (tattach, s);
871     s->fpin = fpin;
872
873     /* 
874      * if a multipart/signed is the _only_ sub-part of a
875      * multipart/encrypted, cache signature verification
876      * status.
877      *
878      */
879
880     if (mutt_is_multipart_signed (tattach) && !tattach->next)
881       p->goodsig |= tattach->goodsig;
882
883     if (s->flags & M_DISPLAY) {
884       state_puts ("\n", s);
885       state_attach_puts (_("[-- End of PGP/MIME encrypted data --]\n"), s);
886     }
887
888     mutt_free_body (&tattach);
889     /* clear 'Invoking...' message, since there's no error */
890     mutt_message _("PGP message successfully decrypted.");
891   } else
892     mutt_error _("Could not decrypt PGP message");
893
894   fclose (fpout);
895   mutt_unlink (tempfile);
896 }
897
898 /* ----------------------------------------------------------------------------
899  * Routines for sending PGP/MIME messages.
900  */
901
902
903 BODY *pgp_sign_message (BODY * a)
904 {
905   BODY *t;
906   char buffer[LONG_STRING];
907   char sigfile[_POSIX_PATH_MAX], signedfile[_POSIX_PATH_MAX];
908   FILE *pgpin, *pgpout, *pgperr, *fp, *sfp;
909   int err = 0;
910   int empty = 1;
911   pid_t thepid;
912
913   convert_to_7bit (a);          /* Signed data _must_ be in 7-bit format. */
914
915   mutt_mktemp (sigfile);
916   if ((fp = safe_fopen (sigfile, "w")) == NULL) {
917     return (NULL);
918   }
919
920   mutt_mktemp (signedfile);
921   if ((sfp = safe_fopen (signedfile, "w")) == NULL) {
922     mutt_perror (signedfile);
923     fclose (fp);
924     unlink (sigfile);
925     return NULL;
926   }
927
928   mutt_write_mime_header (a, sfp);
929   fputc ('\n', sfp);
930   mutt_write_mime_body (a, sfp);
931   fclose (sfp);
932
933   if ((thepid = pgp_invoke_sign (&pgpin, &pgpout, &pgperr,
934                                  -1, -1, -1, signedfile)) == -1) {
935     mutt_perror (_("Can't open PGP subprocess!"));
936
937     fclose (fp);
938     unlink (sigfile);
939     unlink (signedfile);
940     return NULL;
941   }
942
943   if (!pgp_use_gpg_agent ())
944     fputs (PgpPass, pgpin);
945   fputc ('\n', pgpin);
946   fclose (pgpin);
947
948   /*
949    * Read back the PGP signature.  Also, change MESSAGE=>SIGNATURE as
950    * recommended for future releases of PGP.
951    */
952   while (fgets (buffer, sizeof (buffer) - 1, pgpout) != NULL) {
953     if (str_cmp ("-----BEGIN PGP MESSAGE-----\n", buffer) == 0)
954       fputs ("-----BEGIN PGP SIGNATURE-----\n", fp);
955     else if (str_cmp ("-----END PGP MESSAGE-----\n", buffer) == 0)
956       fputs ("-----END PGP SIGNATURE-----\n", fp);
957     else
958       fputs (buffer, fp);
959     empty = 0;                  /* got some output, so we're ok */
960   }
961
962   /* check for errors from PGP */
963   err = 0;
964   while (fgets (buffer, sizeof (buffer) - 1, pgperr) != NULL) {
965     err = 1;
966     fputs (buffer, stdout);
967   }
968
969   if (mutt_wait_filter (thepid) && option (OPTPGPCHECKEXIT))
970     empty = 1;
971
972   fclose (pgperr);
973   fclose (pgpout);
974   unlink (signedfile);
975
976   if (fclose (fp) != 0) {
977     mutt_perror ("fclose");
978     unlink (sigfile);
979     return (NULL);
980   }
981
982   if (err) {
983     pgp_void_passphrase ();
984     mutt_any_key_to_continue (NULL);
985   }
986
987   if (empty) {
988     unlink (sigfile);
989     return (NULL);              /* fatal error while signing */
990   }
991
992   t = mutt_new_body ();
993   t->type = TYPEMULTIPART;
994   t->subtype = str_dup ("signed");
995   t->encoding = ENC7BIT;
996   t->use_disp = 0;
997   t->disposition = DISPINLINE;
998
999   mutt_generate_boundary (&t->parameter);
1000   mutt_set_parameter ("protocol", "application/pgp-signature", &t->parameter);
1001   mutt_set_parameter ("micalg", pgp_micalg (sigfile), &t->parameter);
1002
1003   t->parts = a;
1004   a = t;
1005
1006   t->parts->next = mutt_new_body ();
1007   t = t->parts->next;
1008   t->type = TYPEAPPLICATION;
1009   t->subtype = str_dup ("pgp-signature");
1010   t->filename = str_dup (sigfile);
1011   t->use_disp = 0;
1012   t->disposition = DISPINLINE;
1013   t->encoding = ENC7BIT;
1014   t->unlink = 1;                /* ok to remove this file after sending. */
1015
1016   return (a);
1017 }
1018
1019 static short is_numerical_keyid (const char *s)
1020 {
1021   /* or should we require the "0x"? */
1022   if (strncmp (s, "0x", 2) == 0)
1023     s += 2;
1024   if (str_len (s) % 8)
1025     return 0;
1026   while (*s)
1027     if (strchr ("0123456789ABCDEFabcdef", *s++) == NULL)
1028       return 0;
1029
1030   return 1;
1031 }
1032
1033 /* This routine attempts to find the keyids of the recipients of a message.
1034  * It returns NULL if any of the keys can not be found.
1035  */
1036 char *pgp_findKeys (ADDRESS * to, ADDRESS * cc, ADDRESS * bcc)
1037 {
1038   char *keyID, *keylist = NULL, *t;
1039   size_t keylist_size = 0;
1040   size_t keylist_used = 0;
1041   ADDRESS *tmp = NULL, *addr = NULL;
1042   ADDRESS **last = &tmp;
1043   ADDRESS *p, *q;
1044   int i;
1045   pgp_key_t k_info = NULL, key = NULL;
1046
1047   const char *fqdn = mutt_fqdn (1);
1048
1049   for (i = 0; i < 3; i++) {
1050     switch (i) {
1051     case 0:
1052       p = to;
1053       break;
1054     case 1:
1055       p = cc;
1056       break;
1057     case 2:
1058       p = bcc;
1059       break;
1060     default:
1061       abort ();
1062     }
1063
1064     *last = rfc822_cpy_adr (p);
1065     while (*last)
1066       last = &((*last)->next);
1067   }
1068
1069   if (fqdn)
1070     rfc822_qualify (tmp, fqdn);
1071
1072   tmp = mutt_remove_duplicates (tmp);
1073
1074   for (p = tmp; p; p = p->next) {
1075     char buf[LONG_STRING];
1076
1077     q = p;
1078     k_info = NULL;
1079
1080     if ((keyID = mutt_crypt_hook (p)) != NULL) {
1081       int r;
1082
1083       snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"), keyID,
1084                 p->mailbox);
1085       if ((r = mutt_yesorno (buf, M_YES)) == M_YES) {
1086         if (is_numerical_keyid (keyID)) {
1087           if (strncmp (keyID, "0x", 2) == 0)
1088             keyID += 2;
1089           goto bypass_selection;        /* you don't see this. */
1090         }
1091
1092         /* check for e-mail address */
1093         if ((t = strchr (keyID, '@')) &&
1094             (addr = rfc822_parse_adrlist (NULL, keyID))) {
1095           if (fqdn)
1096             rfc822_qualify (addr, fqdn);
1097           q = addr;
1098         }
1099         else
1100           k_info = pgp_getkeybystr (keyID, KEYFLAG_CANENCRYPT, PGP_PUBRING);
1101       }
1102       else if (r == -1) {
1103         mem_free (&keylist);
1104         rfc822_free_address (&tmp);
1105         rfc822_free_address (&addr);
1106         return NULL;
1107       }
1108     }
1109
1110     if (k_info == NULL)
1111       pgp_invoke_getkeys (q);
1112
1113     if (k_info == NULL
1114         && (k_info =
1115             pgp_getkeybyaddr (q, KEYFLAG_CANENCRYPT, PGP_PUBRING)) == NULL) {
1116       snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
1117
1118       if ((key = pgp_ask_for_key (buf, q->mailbox,
1119                                   KEYFLAG_CANENCRYPT, PGP_PUBRING)) == NULL) {
1120         mem_free (&keylist);
1121         rfc822_free_address (&tmp);
1122         rfc822_free_address (&addr);
1123         return NULL;
1124       }
1125     }
1126     else
1127       key = k_info;
1128
1129     keyID = pgp_keyid (key);
1130
1131   bypass_selection:
1132     keylist_size += str_len (keyID) + 4;
1133     mem_realloc (&keylist, keylist_size);
1134     sprintf (keylist + keylist_used, "%s0x%s", keylist_used ? " " : "", /* __SPRINTF_CHECKED__ */
1135              keyID);
1136     keylist_used = str_len (keylist);
1137
1138     pgp_free_key (&key);
1139     rfc822_free_address (&addr);
1140
1141   }
1142   rfc822_free_address (&tmp);
1143   return (keylist);
1144 }
1145
1146 /* Warning: "a" is no longer freed in this routine, you need
1147  * to free it later.  This is necessary for $fcc_attach. */
1148
1149 BODY *pgp_encrypt_message (BODY * a, char *keylist, int sign)
1150 {
1151   char buf[LONG_STRING];
1152   char tempfile[_POSIX_PATH_MAX], pgperrfile[_POSIX_PATH_MAX];
1153   char pgpinfile[_POSIX_PATH_MAX];
1154   FILE *pgpin, *pgperr, *fpout, *fptmp;
1155   BODY *t;
1156   int err = 0;
1157   int empty = 0;
1158   pid_t thepid;
1159
1160   mutt_mktemp (tempfile);
1161   if ((fpout = safe_fopen (tempfile, "w+")) == NULL) {
1162     mutt_perror (tempfile);
1163     return (NULL);
1164   }
1165
1166   mutt_mktemp (pgperrfile);
1167   if ((pgperr = safe_fopen (pgperrfile, "w+")) == NULL) {
1168     mutt_perror (pgperrfile);
1169     unlink (tempfile);
1170     fclose (fpout);
1171     return NULL;
1172   }
1173   unlink (pgperrfile);
1174
1175   mutt_mktemp (pgpinfile);
1176   if ((fptmp = safe_fopen (pgpinfile, "w")) == NULL) {
1177     mutt_perror (pgpinfile);
1178     unlink (tempfile);
1179     fclose (fpout);
1180     fclose (pgperr);
1181     return NULL;
1182   }
1183
1184   if (sign)
1185     convert_to_7bit (a);
1186
1187   mutt_write_mime_header (a, fptmp);
1188   fputc ('\n', fptmp);
1189   mutt_write_mime_body (a, fptmp);
1190   fclose (fptmp);
1191
1192   if ((thepid = pgp_invoke_encrypt (&pgpin, NULL, NULL, -1,
1193                                     fileno (fpout), fileno (pgperr),
1194                                     pgpinfile, keylist, sign)) == -1) {
1195     fclose (pgperr);
1196     unlink (pgpinfile);
1197     return (NULL);
1198   }
1199
1200   if (sign) {
1201     if (!pgp_use_gpg_agent ())
1202       fputs (PgpPass, pgpin);
1203     fputc ('\n', pgpin);
1204   }
1205   fclose (pgpin);
1206
1207   if (mutt_wait_filter (thepid) && option (OPTPGPCHECKEXIT))
1208     empty = 1;
1209
1210   unlink (pgpinfile);
1211
1212   fflush (fpout);
1213   rewind (fpout);
1214   if (!empty)
1215     empty = (fgetc (fpout) == EOF);
1216   fclose (fpout);
1217
1218   fflush (pgperr);
1219   rewind (pgperr);
1220   while (fgets (buf, sizeof (buf) - 1, pgperr) != NULL) {
1221     err = 1;
1222     fputs (buf, stdout);
1223   }
1224   fclose (pgperr);
1225
1226   /* pause if there is any error output from PGP */
1227   if (err)
1228     mutt_any_key_to_continue (NULL);
1229
1230   if (empty) {
1231     /* fatal error while trying to encrypt message */
1232     if (sign)
1233       pgp_void_passphrase (); /* just in case */
1234     unlink (tempfile);
1235     return (NULL);
1236   }
1237
1238   t = mutt_new_body ();
1239   t->type = TYPEMULTIPART;
1240   t->subtype = str_dup ("encrypted");
1241   t->encoding = ENC7BIT;
1242   t->use_disp = 0;
1243   t->disposition = DISPINLINE;
1244
1245   mutt_generate_boundary (&t->parameter);
1246   mutt_set_parameter ("protocol", "application/pgp-encrypted", &t->parameter);
1247
1248   t->parts = mutt_new_body ();
1249   t->parts->type = TYPEAPPLICATION;
1250   t->parts->subtype = str_dup ("pgp-encrypted");
1251   t->parts->encoding = ENC7BIT;
1252
1253   t->parts->next = mutt_new_body ();
1254   t->parts->next->type = TYPEAPPLICATION;
1255   t->parts->next->subtype = str_dup ("octet-stream");
1256   t->parts->next->encoding = ENC7BIT;
1257   t->parts->next->filename = str_dup (tempfile);
1258   t->parts->next->use_disp = 1;
1259   t->parts->next->disposition = DISPINLINE;
1260   t->parts->next->unlink = 1;   /* delete after sending the message */
1261   t->parts->next->d_filename = str_dup ("msg.asc"); /* non pgp/mime can save */
1262
1263   return (t);
1264 }
1265
1266 BODY *pgp_traditional_encryptsign (BODY * a, int flags, char *keylist)
1267 {
1268   BODY *b;
1269
1270   char pgpoutfile[_POSIX_PATH_MAX];
1271   char pgperrfile[_POSIX_PATH_MAX];
1272   char pgpinfile[_POSIX_PATH_MAX];
1273
1274   char body_charset[STRING];
1275   char *from_charset;
1276   const char *send_charset;
1277
1278   FILE *pgpout = NULL, *pgperr = NULL, *pgpin = NULL;
1279   FILE *fp;
1280
1281   int empty = 0;
1282   int err;
1283
1284   char buff[STRING];
1285
1286   pid_t thepid;
1287
1288   if (a->type != TYPETEXT)
1289     return NULL;
1290   if (ascii_strcasecmp (a->subtype, "plain"))
1291     return NULL;
1292
1293   if ((fp = fopen (a->filename, "r")) == NULL) {
1294     mutt_perror (a->filename);
1295     return NULL;
1296   }
1297
1298   mutt_mktemp (pgpinfile);
1299   if ((pgpin = safe_fopen (pgpinfile, "w")) == NULL) {
1300     mutt_perror (pgpinfile);
1301     fclose (fp);
1302     return NULL;
1303   }
1304
1305   /* The following code is really correct:  If noconv is set,
1306    * a's charset parameter contains the on-disk character set, and
1307    * we have to convert from that to utf-8.  If noconv is not set,
1308    * we have to convert from $charset to utf-8.
1309    */
1310
1311   mutt_get_body_charset (body_charset, sizeof (body_charset), a);
1312   if (a->noconv)
1313     from_charset = body_charset;
1314   else
1315     from_charset = Charset;
1316
1317   if (!mutt_is_us_ascii (body_charset)) {
1318     int c;
1319     FGETCONV *fc;
1320
1321     if (flags & ENCRYPT)
1322       send_charset = "us-ascii";
1323     else
1324       send_charset = "utf-8";
1325
1326     fc = fgetconv_open (fp, from_charset, "utf-8", M_ICONV_HOOK_FROM);
1327     while ((c = fgetconv (fc)) != EOF)
1328       fputc (c, pgpin);
1329
1330     fgetconv_close (&fc);
1331   }
1332   else {
1333     send_charset = "us-ascii";
1334     mutt_copy_stream (fp, pgpin);
1335   }
1336   safe_fclose (&fp);
1337   fclose (pgpin);
1338
1339   mutt_mktemp (pgpoutfile);
1340   mutt_mktemp (pgperrfile);
1341   if ((pgpout = safe_fopen (pgpoutfile, "w+")) == NULL ||
1342       (pgperr = safe_fopen (pgperrfile, "w+")) == NULL) {
1343     mutt_perror (pgpout ? pgperrfile : pgpoutfile);
1344     unlink (pgpinfile);
1345     if (pgpout) {
1346       fclose (pgpout);
1347       unlink (pgpoutfile);
1348     }
1349     return NULL;
1350   }
1351
1352   unlink (pgperrfile);
1353
1354   if ((thepid = pgp_invoke_traditional (&pgpin, NULL, NULL,
1355                                         -1, fileno (pgpout), fileno (pgperr),
1356                                         pgpinfile, keylist, flags)) == -1) {
1357     mutt_perror (_("Can't invoke PGP"));
1358
1359     fclose (pgpout);
1360     fclose (pgperr);
1361     mutt_unlink (pgpinfile);
1362     unlink (pgpoutfile);
1363     return NULL;
1364   }
1365
1366   if (pgp_use_gpg_agent ())
1367     *PgpPass = 0;
1368   if (flags & SIGN)
1369     fprintf (pgpin, "%s\n", PgpPass);
1370   fclose (pgpin);
1371
1372   if (mutt_wait_filter (thepid) && option (OPTPGPCHECKEXIT))
1373     empty = 1;
1374
1375   mutt_unlink (pgpinfile);
1376
1377   fflush (pgpout);
1378   fflush (pgperr);
1379
1380   rewind (pgpout);
1381   rewind (pgperr);
1382
1383   if (!empty)
1384     empty = (fgetc (pgpout) == EOF);
1385   fclose (pgpout);
1386
1387   err = 0;
1388
1389   while (fgets (buff, sizeof (buff), pgperr)) {
1390     err = 1;
1391     fputs (buff, stdout);
1392   }
1393
1394   fclose (pgperr);
1395
1396   if (err)
1397     mutt_any_key_to_continue (NULL);
1398
1399   if (empty) {
1400     if (flags & SIGN)
1401       pgp_void_passphrase (); /* just in case */
1402     unlink (pgpoutfile);
1403     return NULL;
1404   }
1405
1406   b = mutt_new_body ();
1407
1408   b->encoding = ENC7BIT;
1409
1410   b->type = TYPETEXT;
1411   b->subtype = str_dup ("plain");
1412
1413   mutt_set_parameter ("x-action",
1414                       flags & ENCRYPT ? "pgp-encrypted" : "pgp-signed",
1415                       &b->parameter);
1416   mutt_set_parameter ("charset", send_charset, &b->parameter);
1417
1418   b->filename = str_dup (pgpoutfile);
1419
1420 #if 0
1421   /* The following is intended to give a clue to some completely brain-dead 
1422    * "mail environments" which are typically used by large corporations.
1423    */
1424
1425   b->d_filename = str_dup ("msg.pgp");
1426   b->use_disp = 1;
1427
1428 #endif
1429
1430   b->disposition = DISPINLINE;
1431   b->unlink = 1;
1432
1433   b->noconv = 1;
1434   b->use_disp = 0;
1435
1436   if (!(flags & ENCRYPT))
1437     b->encoding = a->encoding;
1438
1439   return b;
1440 }
1441
1442 int pgp_send_menu (HEADER * msg, int *redraw)
1443 {
1444   pgp_key_t p;
1445   char input_signas[SHORT_STRING];
1446
1447   char prompt[LONG_STRING];
1448
1449   if (!(WithCrypto & APPLICATION_PGP))
1450     return msg->security;
1451
1452   /* If autoinline and no crypto options set, then set inline. */
1453   if (option (OPTPGPAUTOINLINE) && !((msg->security & APPLICATION_PGP)
1454                                      && (msg->security & (SIGN | ENCRYPT))))
1455     msg->security |= INLINE;
1456
1457   snprintf (prompt, sizeof (prompt),
1458             _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, %s, or (c)lear? "),
1459             (msg->security & INLINE) ? _("PGP/M(i)ME") : _("(i)nline"));
1460
1461   switch (mutt_multi_choice (prompt, _("esabifc"))) {
1462   case 1:                      /* (e)ncrypt */
1463     msg->security |= ENCRYPT;
1464     msg->security &= ~SIGN;
1465     break;
1466
1467   case 2:                      /* (s)ign */
1468     msg->security |= SIGN;
1469     msg->security &= ~ENCRYPT;
1470     break;
1471
1472   case 3:                      /* sign (a)s */
1473     unset_option (OPTPGPCHECKTRUST);
1474
1475     if ((p =
1476          pgp_ask_for_key (_("Sign as: "), NULL, KEYFLAG_CANSIGN,
1477                           PGP_PUBRING))) {
1478       snprintf (input_signas, sizeof (input_signas), "0x%s", pgp_keyid (p));
1479       str_replace (&PgpSignAs, input_signas);
1480       pgp_free_key (&p);
1481
1482       msg->security |= SIGN;
1483
1484       crypt_pgp_void_passphrase ();     /* probably need a different passphrase */
1485     }
1486 #if 0
1487     else {
1488       msg->security &= ~SIGN;
1489     }
1490 #endif
1491
1492     *redraw = REDRAW_FULL;
1493     break;
1494
1495   case 4:                      /* (b)oth */
1496     msg->security |= (ENCRYPT | SIGN);
1497     break;
1498
1499   case 5:                      /* (i)nline */
1500     if ((msg->security & (ENCRYPT | SIGN)))
1501       msg->security ^= INLINE;
1502     else
1503       msg->security &= ~INLINE;
1504     break;
1505
1506   case 6:                      /* (f)orget it */
1507   case 7:                      /* (c)lear     */
1508     msg->security = 0;
1509     break;
1510   }
1511
1512   if (msg->security) {
1513     if (!(msg->security & (ENCRYPT | SIGN)))
1514       msg->security = 0;
1515     else
1516       msg->security |= APPLICATION_PGP;
1517   }
1518
1519   return (msg->security);
1520 }
1521
1522
1523 #endif /* CRYPT_BACKEND_CLASSIC_PGP */