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