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