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