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