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