various rewrites and cleanups.
[apps/madmutt.git] / crypt.c
1 /*
2  * Copyright notice from original mutt:
3  * crypt-gpgme.c - GPGME based crypto operations
4  * Copyright (C) 1996,1997 Michael R. Elkins <me@cs.hmc.edu>
5  * Copyright (C) 1998,1999,2000 Thomas Roessler <roessler@guug.de>
6  * Copyright (C) 2001  Thomas Roessler <roessler@guug.de>
7  *                     Oliver Ehli <elmy@acm.org>
8  * Copyright (C) 2002, 2003, 2004 g10 Code GmbH
9  */
10 /*
11  * Copyright © 2006 Pierre Habouzit
12  */
13
14 #include <lib-lib/lib-lib.h>
15
16 #include <gpgme.h>
17
18 #include <lib-mime/mime.h>
19 #include <lib-ui/curses.h>
20 #include <lib-ui/enter.h>
21 #include <lib-ui/menu.h>
22 #include <lib-mx/mx.h>
23
24 #include "crypt.h"
25 #include "lib.h"
26 #include "alias.h"
27 #include "handler.h"
28 #include "copy.h"
29 #include "pager.h"
30 #include "recvattach.h"
31 #include "sort.h"
32
33 /* Values used for comparing addresses. */
34 #define CRYPT_KV_VALID    1
35 #define CRYPT_KV_ADDR     2
36 #define CRYPT_KV_STRING   4
37 #define CRYPT_KV_STRONGID 8
38 #define CRYPT_KV_MATCH (CRYPT_KV_ADDR|CRYPT_KV_STRING)
39
40 struct dn_array_s {
41     char *key;
42     char *value;
43 };
44
45 /* We work based on user IDs, getting from a user ID to the key is
46    check and does not need any memory (gpgme uses reference counting). */
47 typedef struct cryptkey_t {
48     struct cryptkey_t *next;
49     int idx;                      /* and the user ID at this index */
50     int flags;                    /* global and per uid flags (for convenience) */
51     gpgme_key_t kobj;
52     const char *uid;              /* and for convenience point to this user ID */
53 } cryptkey_t;
54
55 DO_INIT(cryptkey_t, cryptkey);
56 static void cryptkey_wipe(cryptkey_t *key) {
57     gpgme_key_release(key->kobj);
58 }
59 DO_NEW(cryptkey_t, cryptkey);
60 DO_DELETE(cryptkey_t, cryptkey);
61 DO_SLIST(cryptkey_t, key, cryptkey_delete);
62
63 static cryptkey_t *cryptkey_dup(const cryptkey_t *k)
64 {
65     cryptkey_t *res = cryptkey_new();
66     *res = *k;
67     res->next = NULL;
68     gpgme_key_ref(k->kobj);
69     return res;
70 }
71
72 typedef struct crypt_entry {
73     ssize_t num;
74     cryptkey_t *key;
75 } crypt_entry_t;
76
77 static gpgme_key_t signature_key = NULL;
78
79 static void convert_to_7bit (BODY * a)
80 {
81     for (; a; a = a->next) {
82         int tok = mime_which_token(a->subtype, -1);
83
84         if (a->type == TYPEMULTIPART) {
85             a->encoding = ENC7BIT;
86             convert_to_7bit(a->parts);
87         } else if (a->type == TYPEMESSAGE && tok == MIME_DELIVERY_STATUS) {
88             if (a->encoding != ENC7BIT)
89                 mutt_message_to_7bit(a, NULL);
90         } else if (a->encoding == ENC8BIT) {
91             a->encoding = ENCQUOTEDPRINTABLE;
92         } else if (a->encoding == ENCBINARY) {
93             a->encoding = ENCBASE64;
94         } else if (a->content && a->encoding != ENCBASE64
95                && (a->content->from || a->content->space))
96         {
97             a->encoding = ENCQUOTEDPRINTABLE;
98         }
99     }
100 }
101
102 /* Print the utf-8 encoded string BUF of length LEN bytes to stream
103    FP. Convert the character set. */
104 static void print_utf8 (FILE * fp, const char *buf, ssize_t len)
105 {
106     char *tstr;
107
108     tstr = p_dupstr(buf, len);
109     mutt_convert_string(&tstr, "utf-8", MCharset.charset, M_ICONV_HOOK_FROM);
110     fputs(tstr, fp);
111     p_delete(&tstr);
112 }
113
114 /* Return the keyID for the key K.  Note that this string is valid as
115    long as K is valid */
116 static const char *crypt_keyid (cryptkey_t * k)
117 {
118     if (k->kobj && k->kobj->subkeys) {
119         const char *s = k->kobj->subkeys->keyid;
120         return m_strlen(s) == 16 ? s + 8 : s;
121     }
122
123     return "????????";
124 }
125
126 /* Return the hexstring fingerprint from the key K. */
127 static const char *crypt_fpr (cryptkey_t * k)
128 {
129     return k->kobj && k->kobj->subkeys ? k->kobj->subkeys->fpr : "";
130 }
131
132 /* Parse FLAGS and return a statically allocated(!) string with them. */
133 static char *crypt_key_abilities (int flags)
134 {
135   static char buff[3];
136
137   if (!(flags & KEYFLAG_CANENCRYPT))
138     buff[0] = '-';
139   else if (flags & KEYFLAG_PREFER_SIGNING)
140     buff[0] = '.';
141   else
142     buff[0] = 'e';
143
144   if (!(flags & KEYFLAG_CANSIGN))
145     buff[1] = '-';
146   else if (flags & KEYFLAG_PREFER_ENCRYPTION)
147     buff[1] = '.';
148   else
149     buff[1] = 's';
150
151   buff[2] = '\0';
152
153   return buff;
154 }
155
156 /* Parse FLAGS and return a character describing the most important flag. */
157 static char crypt_flags (int flags)
158 {
159   if (flags & KEYFLAG_REVOKED)
160     return 'R';
161   else if (flags & KEYFLAG_EXPIRED)
162     return 'X';
163   else if (flags & KEYFLAG_DISABLED)
164     return 'd';
165   else if (flags & KEYFLAG_CRITICAL)
166     return 'c';
167   else
168     return ' ';
169 }
170
171 /* Return true whe validity of KEY is sufficient. */
172 static int crypt_id_is_strong (cryptkey_t * key)
173 {
174     gpgme_user_id_t uid;
175     int i;
176
177     if (key->flags & KEYFLAG_ISX509)
178         return 1;
179
180     for (i = 0, uid = key->kobj->uids; uid; i++, uid = uid->next) {
181         if (i == key->idx) {
182             return uid->validity == GPGME_VALIDITY_FULL
183                 || uid->validity == GPGME_VALIDITY_ULTIMATE;
184         }
185     }
186
187     return 0;
188 }
189
190 /* Return a bit vector describing how well the addresses ADDR and
191    U_ADDR match and whether KEY is valid. */
192 static int
193 crypt_id_matches_addr(address_t *addr, address_t *u_addr, cryptkey_t *key)
194 {
195     int rv = 0;
196
197     if (!(key->flags & KEYFLAG_CANTUSE))
198         rv |= CRYPT_KV_VALID;
199
200     if (crypt_id_is_strong(key))
201         rv |= CRYPT_KV_STRONGID;
202
203     if (addr->mailbox && !m_strcasecmp(addr->mailbox, u_addr->mailbox))
204         rv |= CRYPT_KV_ADDR;
205
206     if (addr->personal && m_strcasecmp(addr->personal, u_addr->personal))
207         rv |= CRYPT_KV_STRING;
208
209     return rv;
210 }
211
212
213 /* Create a new gpgme context and return it.  With FOR_SMIME set to
214    true, the protocol of the context is set to CMS. */
215 static gpgme_ctx_t create_gpgme_context(int for_smime)
216 {
217     gpgme_error_t err;
218     gpgme_ctx_t ctx;
219
220     err = gpgme_new (&ctx);
221     if (err) {
222         mutt_error(_("error creating gpgme context: %s\n"),
223                    gpgme_strerror(err));
224         sleep(2);
225         mutt_exit(1);
226     }
227     if (!for_smime)
228         return ctx;
229
230     err = gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS);
231     if (err) {
232         mutt_error(_("error enabling CMS protocol: %s\n"), gpgme_strerror(err));
233         sleep(2);
234         mutt_exit(1);
235     }
236     return ctx;
237 }
238
239 /* Create a new gpgme data object.  This is a wrapper to die on
240    error. */
241 static gpgme_data_t create_gpgme_data(void)
242 {
243     gpgme_error_t err;
244     gpgme_data_t data;
245
246     err = gpgme_data_new(&data);
247     if (err) {
248         mutt_error(_("error creating gpgme data object: %s\n"),
249                    gpgme_strerror(err));
250         sleep(2);
251         mutt_exit(1);
252     }
253     return data;
254 }
255
256 /* Create a new GPGME Data object from the mail body A.  With CONVERT
257    passed as true, the lines are converted to CR,LF if required.
258    Return NULL on error or the gpgme_data_t object on success. */
259 static gpgme_data_t body_to_data_object(BODY *a, int convert)
260 {
261     gpgme_data_t data;
262     int err = 0;
263     FILE *fptmp = tmpfile();
264
265     if (!fptmp) {
266         mutt_perror (_("Can't create temporary file"));
267         return NULL;
268     }
269
270     mutt_write_mime_header(a, fptmp);
271     fputc('\n', fptmp);
272     mutt_write_mime_body(a, fptmp);
273     rewind(fptmp);
274
275     if (convert) {
276         char buf[STRING];
277         int spare = 0;
278
279         data = create_gpgme_data();
280         while (fgets(buf + spare, sizeof(buf) - 1, fptmp)) {
281             int l = m_strlen(buf);
282
283             spare = buf[l - 1] != '\n';
284             if (!spare) {
285                 if (l > 2 && buf[l - 2] == '\r') {
286                     buf[l - 2] = '\n';
287                     l--;
288                 }
289             }
290             gpgme_data_write(data, buf, l - spare);
291             if (spare)
292                 buf[0] = buf[l - 1];
293         }
294         if (spare)
295             gpgme_data_write(data, buf, 1);
296         gpgme_data_seek(data, 0, SEEK_SET);
297     } else {
298         err = gpgme_data_new_from_stream(&data, fptmp);
299     }
300     m_fclose(&fptmp);
301     if (err) {
302         mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
303         return NULL;
304     }
305
306     return data;
307 }
308
309 /* Create a GPGME data object from the stream FP but limit the object
310    to LENGTH bytes starting at OFFSET bytes from the beginning of the
311    file. */
312 static gpgme_data_t file_to_data_object(FILE *fp, long offset, long length)
313 {
314     int err = 0;
315     gpgme_data_t data;
316
317     err = gpgme_data_new_from_filepart(&data, NULL, fp, offset, length);
318     if (err) {
319         mutt_error(_("error allocating data object: %s\n"),
320                    gpgme_strerror(err));
321         return NULL;
322     }
323
324     return data;
325 }
326
327 /* Write a GPGME data object to the stream FP. */
328 static int data_object_to_stream(gpgme_data_t data, FILE * fp)
329 {
330     int err;
331     char buf[4096], *p;
332     ssize_t nread;
333
334     err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
335            ? gpgme_error_from_errno (errno) : 0);
336     if (err) {
337         mutt_error (_("error rewinding data object: %s\n"), gpgme_strerror (err));
338         return -1;
339     }
340
341     while ((nread = gpgme_data_read(data, buf, sizeof (buf)))) {
342         /* fixme: we are not really converting CRLF to LF but just
343            skipping CR. Doing it correctly needs a more complex logic */
344         for (p = buf; nread; p++, nread--) {
345             if (*p != '\r')
346                 putc (*p, fp);
347         }
348
349         if (ferror (fp)) {
350             mutt_perror ("[tempfile]");
351             return -1;
352         }
353     }
354     if (nread == -1) {
355         mutt_error (_("error reading data object: %s\n"), strerror (errno));
356         return -1;
357     }
358     return 0;
359 }
360
361 /* Copy a data object to a newly created temporay file and return that
362    filename. Caller must free.  With RET_FP not NULL, don't close the
363    stream but return it there. */
364 static char *data_object_to_tempfile(gpgme_data_t data, FILE ** ret_fp)
365 {
366     int err;
367     char tempfile[_POSIX_PATH_MAX];
368     FILE *fp;
369     ssize_t nread = 0;
370
371     fp = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
372     if (!fp) {
373         mutt_perror (_("Can't create temporary file"));
374         return NULL;
375     }
376
377     err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
378            ? gpgme_error_from_errno (errno) : 0);
379     if (!err) {
380         char buf[4096];
381
382         while ((nread = gpgme_data_read(data, buf, sizeof(buf)))) {
383             if (fwrite (buf, nread, 1, fp) != 1) {
384                 mutt_perror (_("Can't create temporary file"));
385                 m_fclose(&fp);
386                 unlink (tempfile);
387                 return NULL;
388             }
389         }
390     }
391
392     if (nread == -1) {
393         mutt_error (_("error reading data object: %s\n"), gpgme_strerror (err));
394         unlink (tempfile);
395         m_fclose(&fp);
396         return NULL;
397     }
398     if (ret_fp) {
399         rewind(fp);
400         *ret_fp = fp;
401     } else {
402         m_fclose(&fp);
403     }
404     return m_strdup(tempfile);
405 }
406
407
408 /* FIXME: stolen from gpgme to avoid "ambiguous identity" errors */
409 static gpgme_error_t
410 gpgme_get_key2 (gpgme_ctx_t ctx, const char *fpr, gpgme_key_t *r_key,
411                int secret)
412 {
413   gpgme_ctx_t listctx;
414   gpgme_error_t err;
415
416   if (!ctx || !r_key || !fpr)
417     return gpg_error (GPG_ERR_INV_VALUE);
418
419   if (strlen (fpr) < 8) /* We have at least a key ID.  */
420     return gpg_error (GPG_ERR_INV_VALUE);
421
422   /* FIXME: We use our own context because we have to avoid the user's
423      I/O callback handlers.  */
424   err = gpgme_new (&listctx);
425   if (err)
426     return err;
427   gpgme_set_protocol (listctx, gpgme_get_protocol (ctx));
428   err = gpgme_op_keylist_start (listctx, fpr, secret);
429   if (!err)
430     err = gpgme_op_keylist_next (listctx, r_key);
431   gpgme_release (listctx);
432   return err;
433 }
434
435 /* Create a GpgmeRecipientSet from the keys in the string KEYLIST.
436    The keys must be space delimited. */
437 static gpgme_key_t *
438 create_recipient_set(const char *keylist, gpgme_protocol_t protocol)
439 {
440   int err;
441   const char *s;
442   char buf[100];
443   int i;
444   gpgme_key_t *rset = NULL;
445   unsigned int rset_n = 0;
446   gpgme_key_t key = NULL;
447   gpgme_ctx_t context = NULL;
448
449   err = gpgme_new (&context);
450   if (!err)
451     err = gpgme_set_protocol (context, protocol);
452
453   if (!err) {
454     s = keylist;
455     do {
456       while (*s == ' ')
457         s++;
458       for (i = 0; *s && *s != ' ' && i < ssizeof(buf) - 1;)
459         buf[i++] = *s++;
460       buf[i] = 0;
461       if (*buf) {
462         if (i > 1 && buf[i - 1] == '!') {
463           /* The user selected to override the valididy of that
464              key. */
465           buf[i - 1] = 0;
466
467           err = gpgme_get_key2 (context, buf, &key, 0);
468           if (!err)
469             key->uids->validity = GPGME_VALIDITY_FULL;
470           buf[i - 1] = '!';
471         }
472         else
473           err = gpgme_get_key2 (context, buf, &key, 0);
474
475         if (!err) {
476           p_realloc(&rset, rset_n + 1);
477           rset[rset_n++] = key;
478         }
479         else {
480           mutt_error (_("error adding recipient `%s': %s\n"),
481                       buf, gpgme_strerror (err));
482           p_delete(&rset);
483           return NULL;
484         }
485       }
486     } while (*s);
487   }
488
489   /* NULL terminate.  */
490   p_realloc(&rset, rset_n + 1);
491   rset[rset_n++] = NULL;
492
493   if (context)
494     gpgme_release (context);
495
496   return rset;
497 }
498
499
500 /* Make sure that the correct signer is set. Returns 0 on success. */
501 static int set_signer (gpgme_ctx_t ctx, int for_smime)
502 {
503   char *signid = for_smime ? SmimeDefaultKey : PgpSignAs;
504   gpgme_error_t err;
505   gpgme_ctx_t listctx;
506   gpgme_key_t key, key2;
507
508   if (!signid || !*signid)
509     return 0;
510
511   listctx = create_gpgme_context (for_smime);
512   err = gpgme_op_keylist_start (listctx, signid, 1);
513   if (!err)
514     err = gpgme_op_keylist_next (listctx, &key);
515   if (err) {
516     gpgme_release (listctx);
517     mutt_error (_("secret key `%s' not found: %s\n"),
518                 signid, gpgme_strerror (err));
519     return -1;
520   }
521   err = gpgme_op_keylist_next (listctx, &key2);
522   if (!err) {
523     gpgme_key_unref(key);
524     gpgme_key_unref(key2);
525     gpgme_release (listctx);
526     mutt_error (_("ambiguous specification of secret key `%s'\n"), signid);
527     return -1;
528   }
529   gpgme_op_keylist_end (listctx);
530   gpgme_release (listctx);
531
532   gpgme_signers_clear (ctx);
533   err = gpgme_signers_add (ctx, key);
534   gpgme_key_unref(key);
535   if (err) {
536     mutt_error (_("error setting secret key `%s': %s\n"),
537                 signid, gpgme_strerror (err));
538     return -1;
539   }
540   return 0;
541 }
542
543
544 /* Encrypt the gpgme data object PLAINTEXT to the recipients in RSET
545    and return an allocated filename to a temporary file containing the
546    enciphered text.  With USE_SMIME set to true, the smime backend is
547    used.  With COMBINED_SIGNED a PGP message is signed and
548    encrypted.  Returns NULL in case of error */
549 static char *encrypt_gpgme_object (gpgme_data_t plaintext, gpgme_key_t * rset,
550                                    int use_smime, int combined_signed)
551 {
552   int err;
553   gpgme_ctx_t ctx;
554   gpgme_data_t ciphertext;
555   char *outfile;
556
557   ctx = create_gpgme_context (use_smime);
558   if (!use_smime)
559     gpgme_set_armor (ctx, 1);
560
561   ciphertext = create_gpgme_data ();
562
563   if (combined_signed) {
564     if (set_signer (ctx, use_smime)) {
565       gpgme_data_release (ciphertext);
566       gpgme_release (ctx);
567       return NULL;
568     }
569     err = gpgme_op_encrypt_sign (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
570                                  plaintext, ciphertext);
571   }
572   else
573     err = gpgme_op_encrypt (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
574                             plaintext, ciphertext);
575   mutt_need_hard_redraw ();
576   if (err) {
577     mutt_error (_("error encrypting data: %s\n"), gpgme_strerror (err));
578     gpgme_data_release (ciphertext);
579     gpgme_release (ctx);
580     return NULL;
581   }
582
583   gpgme_release (ctx);
584
585   outfile = data_object_to_tempfile (ciphertext, NULL);
586   gpgme_data_release (ciphertext);
587   return outfile;
588 }
589
590 /* Find the "micalg" parameter from the last Gpgme operation on
591    context CTX.  It is expected that this operation was a sign
592    operation.  Return the algorithm name as a C string in buffer BUF
593    which must have been allocated by the caller with size BUFLEN.
594    Returns 0 on success or -1 in case of an error.  The return string
595    is truncted to BUFLEN - 1. */
596 static int get_micalg (gpgme_ctx_t ctx, char *buf, ssize_t buflen)
597 {
598   gpgme_sign_result_t result = NULL;
599   const char *algorithm_name = NULL;
600
601   if (!buflen)
602     return -1;
603
604   *buf = 0;
605   result = gpgme_op_sign_result (ctx);
606   if (result) {
607     algorithm_name = gpgme_hash_algo_name (result->signatures->hash_algo);
608     if (algorithm_name) {
609       m_strcpy(buf, buflen, algorithm_name);
610     }
611   }
612
613   return *buf ? 0 : -1;
614 }
615
616 static void print_time (time_t t, STATE * s)
617 {
618   char p[STRING];
619
620   setlocale (LC_TIME, "");
621 #ifdef HAVE_LANGINFO_D_T_FMT
622   strftime (p, sizeof (p), nl_langinfo (D_T_FMT), localtime (&t));
623 #else
624   strftime (p, sizeof (p), "%c", localtime (&t));
625 #endif
626   setlocale (LC_TIME, "C");
627   state_attach_puts (p, s);
628 }
629
630 /* Implementation of `sign_message'. */
631
632 /* Sign the MESSAGE in body A either using OpenPGP or S/MIME when
633    USE_SMIME is passed as true.  Returns the new body or NULL on
634    error. */
635 static BODY *sign_message(BODY * a, int use_smime)
636 {
637   BODY *t;
638   char *sigfile;
639   int err = 0;
640   char buf[100];
641   gpgme_ctx_t ctx;
642   gpgme_data_t message, signature;
643
644   convert_to_7bit (a);          /* Signed data _must_ be in 7-bit format. */
645
646   message = body_to_data_object(a, 1);
647   if (!message)
648     return NULL;
649   signature = create_gpgme_data ();
650
651   ctx = create_gpgme_context (use_smime);
652   if (!use_smime)
653     gpgme_set_armor (ctx, 1);
654
655   if (set_signer (ctx, use_smime)) {
656     gpgme_data_release (signature);
657     gpgme_release (ctx);
658     return NULL;
659   }
660
661   err = gpgme_op_sign (ctx, message, signature, GPGME_SIG_MODE_DETACH);
662   mutt_need_hard_redraw ();
663   gpgme_data_release (message);
664   if (err) {
665     gpgme_data_release (signature);
666     gpgme_release (ctx);
667     mutt_error (_("error signing data: %s\n"), gpgme_strerror (err));
668     return NULL;
669   }
670
671   sigfile = data_object_to_tempfile (signature, NULL);
672   gpgme_data_release (signature);
673   if (!sigfile) {
674     gpgme_release (ctx);
675     return NULL;
676   }
677
678   t = body_new();
679   t->type = TYPEMULTIPART;
680   t->subtype = m_strdup("signed");
681   t->encoding = ENC7BIT;
682   t->use_disp = 0;
683   t->disposition = DISPINLINE;
684
685   parameter_set_boundary(&t->parameter);
686   parameter_setval(&t->parameter, "protocol",
687                    use_smime ? "application/pkcs7-signature"
688                              : "application/pgp-signature");
689   /* Get the micalg from gpgme.  Old gpgme versions don't support this
690      for S/MIME so we assume sha-1 in this case. */
691   if (!get_micalg (ctx, buf, sizeof buf))
692     parameter_setval(&t->parameter, "micalg", buf);
693   else if (use_smime)
694     parameter_setval(&t->parameter, "micalg", "sha1");
695   gpgme_release (ctx);
696
697   t->parts = a;
698   a = t;
699
700   t->parts->next = body_new();
701   t = t->parts->next;
702   t->type = TYPEAPPLICATION;
703   if (use_smime) {
704     t->subtype = m_strdup("pkcs7-signature");
705     parameter_setval(&t->parameter, "name", "smime.p7s");
706     t->encoding = ENCBASE64;
707     t->use_disp = 1;
708     t->disposition = DISPATTACH;
709     t->d_filename = m_strdup("smime.p7s");
710   }
711   else {
712     t->subtype = m_strdup("pgp-signature");
713     t->use_disp = 0;
714     t->disposition = DISPINLINE;
715     t->encoding = ENC7BIT;
716   }
717   t->filename = sigfile;
718   t->unlink = 1;                /* ok to remove this file after sending. */
719
720   return a;
721 }
722
723 /* Encrypt the mail body A to all keys given as space separated keyids
724    or fingerprints in KEYLIST and return the encrypted body.  */
725 static BODY *crypt_pgp_encrypt_message (BODY * a, char *keylist, int sign)
726 {
727   char *outfile = NULL;
728   BODY *t;
729   gpgme_key_t *rset = NULL;
730   gpgme_data_t plaintext;
731
732   rset = create_recipient_set (keylist, GPGME_PROTOCOL_OpenPGP);
733   if (!rset)
734     return NULL;
735
736   if (sign)
737     convert_to_7bit (a);
738   plaintext = body_to_data_object(a, 0);
739   if (!plaintext) {
740     p_delete(&rset);
741     return NULL;
742   }
743
744   outfile = encrypt_gpgme_object (plaintext, rset, 0, sign);
745   gpgme_data_release (plaintext);
746   p_delete(&rset);
747   if (!outfile)
748     return NULL;
749
750   t = body_new();
751   t->type = TYPEMULTIPART;
752   t->subtype = m_strdup("encrypted");
753   t->encoding = ENC7BIT;
754   t->use_disp = 0;
755   t->disposition = DISPINLINE;
756
757   parameter_set_boundary(&t->parameter);
758   parameter_setval(&t->parameter, "protocol", "application/pgp-encrypted");
759
760   t->parts = body_new();
761   t->parts->type = TYPEAPPLICATION;
762   t->parts->subtype = m_strdup("pgp-encrypted");
763   t->parts->encoding = ENC7BIT;
764
765   t->parts->next = body_new();
766   t->parts->next->type = TYPEAPPLICATION;
767   t->parts->next->subtype = m_strdup("octet-stream");
768   t->parts->next->encoding = ENC7BIT;
769   t->parts->next->filename = outfile;
770   t->parts->next->use_disp = 1;
771   t->parts->next->disposition = DISPINLINE;
772   t->parts->next->unlink = 1;   /* delete after sending the message */
773   t->parts->next->d_filename = m_strdup("msg.asc");
774
775   return t;
776 }
777
778 /* Encrypt the mail body A to all keys given as space separated
779    fingerprints in KEYLIST and return the S/MIME encrypted body.  */
780 static BODY *crypt_smime_build_smime_entity (BODY * a, char *keylist)
781 {
782   char *outfile = NULL;
783   BODY *t;
784   gpgme_key_t *rset = NULL;
785   gpgme_data_t plaintext;
786
787   rset = create_recipient_set (keylist, GPGME_PROTOCOL_CMS);
788   if (!rset)
789     return NULL;
790
791   plaintext = body_to_data_object(a, 0);
792   if (!plaintext) {
793     p_delete(&rset);
794     return NULL;
795   }
796
797   outfile = encrypt_gpgme_object (plaintext, rset, 1, 0);
798   gpgme_data_release (plaintext);
799   p_delete(&rset);
800   if (!outfile)
801     return NULL;
802
803   t = body_new();
804   t->type = TYPEAPPLICATION;
805   t->subtype = m_strdup("pkcs7-mime");
806   parameter_setval(&t->parameter, "name", "smime.p7m");
807   parameter_setval(&t->parameter, "smime-type", "enveloped-data");
808   t->encoding = ENCBASE64;      /* The output of OpenSSL SHOULD be binary */
809   t->use_disp = 1;
810   t->disposition = DISPATTACH;
811   t->d_filename = m_strdup("smime.p7m");
812   t->filename = outfile;
813   t->unlink = 1;                /*delete after sending the message */
814   t->parts = 0;
815   t->next = 0;
816
817   return t;
818 }
819
820 /* Display the common attributes of the signature summary SUM.
821    Return 1 if there is is a severe warning.
822  */
823 static int show_sig_summary (unsigned long sum,
824                              gpgme_ctx_t ctx, gpgme_key_t key, int idx,
825                              STATE * s)
826 {
827   int severe = 0;
828
829   if ((sum & GPGME_SIGSUM_KEY_REVOKED)) {
830     state_attach_puts (_("Warning: One of the keys has been revoked\n"), s);
831     severe = 1;
832   }
833
834   if ((sum & GPGME_SIGSUM_KEY_EXPIRED)) {
835     time_t at = key->subkeys->expires ? key->subkeys->expires : 0;
836
837     if (at) {
838       state_attach_puts (_("Warning: The key used to create the "
839                            "signature expired at: "), s);
840       print_time (at, s);
841       state_attach_puts ("\n", s);
842     }
843     else
844       state_attach_puts (_("Warning: At least one certification key "
845                            "has expired\n"), s);
846   }
847
848   if ((sum & GPGME_SIGSUM_SIG_EXPIRED)) {
849     gpgme_verify_result_t result;
850     gpgme_signature_t sig;
851     int i;
852
853     result = gpgme_op_verify_result (ctx);
854
855     for (sig = result->signatures, i = 0; sig && (i < idx);
856          sig = sig->next, i++);
857
858     state_attach_puts (_("Warning: The signature expired at: "), s);
859     print_time (sig ? sig->exp_timestamp : 0, s);
860     state_attach_puts ("\n", s);
861   }
862
863   if ((sum & GPGME_SIGSUM_KEY_MISSING))
864     state_attach_puts (_("Can't verify due to a missing "
865                          "key or certificate\n"), s);
866
867   if ((sum & GPGME_SIGSUM_CRL_MISSING)) {
868     state_attach_puts (_("The CRL is not available\n"), s);
869     severe = 1;
870   }
871
872   if ((sum & GPGME_SIGSUM_CRL_TOO_OLD)) {
873     state_attach_puts (_("Available CRL is too old\n"), s);
874     severe = 1;
875   }
876
877   if ((sum & GPGME_SIGSUM_BAD_POLICY))
878     state_attach_puts (_("A policy requirement was not met\n"), s);
879
880   if ((sum & GPGME_SIGSUM_SYS_ERROR)) {
881     const char *t0 = NULL, *t1 = NULL;
882     gpgme_verify_result_t result;
883     gpgme_signature_t sig;
884     int i;
885
886     state_attach_puts (_("A system error occurred"), s);
887
888     /* Try to figure out some more detailed system error information. */
889     result = gpgme_op_verify_result (ctx);
890     for (sig = result->signatures, i = 0; sig && (i < idx);
891          sig = sig->next, i++);
892     if (sig) {
893       t0 = "";
894       t1 = sig->wrong_key_usage ? "Wrong_Key_Usage" : "";
895     }
896
897     if (t0 || t1) {
898       state_attach_puts (": ", s);
899       if (t0)
900         state_attach_puts (t0, s);
901       if (t1 && !(t0 && !m_strcmp(t0, t1))) {
902         if (t0)
903           state_attach_puts (",", s);
904         state_attach_puts (t1, s);
905       }
906     }
907     state_attach_puts ("\n", s);
908   }
909
910   return severe;
911 }
912
913
914 static void show_fingerprint (gpgme_key_t key, STATE * state)
915 {
916   const char *s;
917   int i, is_pgp;
918   char *buf, *p;
919   const char *prefix = _("Fingerprint: ");
920   ssize_t bufsize;
921
922   if (!key)
923     return;
924   s = key->subkeys ? key->subkeys->fpr : NULL;
925   if (!s)
926     return;
927   is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
928
929   bufsize = m_strlen(prefix) + m_strlen(s) * 4 + 2;
930   buf = p_new(char, bufsize);
931   m_strcpy(buf, bufsize, prefix);
932   p = buf + m_strlen(buf);
933   if (is_pgp && m_strlen(s) == 40) {     /* PGP v4 style formatted. */
934     for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
935       *p++ = s[0];
936       *p++ = s[1];
937       *p++ = s[2];
938       *p++ = s[3];
939       *p++ = ' ';
940       if (i == 4)
941         *p++ = ' ';
942     }
943   }
944   else {
945     for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
946       *p++ = s[0];
947       *p++ = s[1];
948       *p++ = is_pgp ? ' ' : ':';
949       if (is_pgp && i == 7)
950         *p++ = ' ';
951     }
952   }
953
954   /* just in case print remaining odd digits */
955   for (; *s; s++)
956     *p++ = *s;
957   *p++ = '\n';
958   *p = 0;
959   state_attach_puts (buf, state);
960   p_delete(&buf);
961 }
962
963 /* Show the valididy of a key used for one signature. */
964 static void show_one_sig_validity (gpgme_ctx_t ctx, int idx, STATE * s)
965 {
966   gpgme_verify_result_t result = NULL;
967   gpgme_signature_t sig = NULL;
968   const char *txt = NULL;
969
970   result = gpgme_op_verify_result (ctx);
971   if (result)
972     for (sig = result->signatures; sig && (idx > 0); sig = sig->next, idx--);
973
974   switch (sig ? sig->validity : 0) {
975   case GPGME_VALIDITY_UNKNOWN:
976     txt = _("WARNING: We have NO indication whether "
977             "the key belongs to the person named " "as shown above\n");
978     break;
979   case GPGME_VALIDITY_UNDEFINED:
980     break;
981   case GPGME_VALIDITY_NEVER:
982     txt = _("WARNING: The key does NOT BELONG to "
983             "the person named as shown above\n");
984     break;
985   case GPGME_VALIDITY_MARGINAL:
986     txt = _("WARNING: It is NOT certain that the key "
987             "belongs to the person named as shown above\n");
988     break;
989   case GPGME_VALIDITY_FULL:
990   case GPGME_VALIDITY_ULTIMATE:
991     txt = NULL;
992     break;
993   }
994   if (txt)
995     state_attach_puts (txt, s);
996 }
997
998 /* Show information about one signature.  This fucntion is called with
999    the context CTX of a sucessful verification operation and the
1000    enumerator IDX which should start at 0 and incremete for each
1001    call/signature.
1002
1003    Return values are: 0 for normal procession, 1 for a bad signature,
1004    2 for a signature with a warning or -1 for no more signature.  */
1005 static int show_one_sig_status (gpgme_ctx_t ctx, int idx, STATE * s)
1006 {
1007   time_t created;
1008   const char *fpr, *uid;
1009   gpgme_key_t key = NULL;
1010   int i, anybad = 0, anywarn = 0;
1011   unsigned int sum;
1012   gpgme_user_id_t uids = NULL;
1013   gpgme_verify_result_t result;
1014   gpgme_signature_t sig;
1015   gpgme_error_t err = GPG_ERR_NO_ERROR;
1016
1017   result = gpgme_op_verify_result (ctx);
1018   if (result) {
1019     /* FIXME: this code should use a static variable and remember
1020        the current position in the list of signatures, IMHO.
1021        -moritz.  */
1022
1023     for (i = 0, sig = result->signatures; sig && (i < idx);
1024          i++, sig = sig->next);
1025     if (!sig)
1026       return -1;                /* Signature not found.  */
1027
1028     if (signature_key) {
1029       gpgme_key_unref(signature_key);
1030       signature_key = NULL;
1031     }
1032
1033     created = sig->timestamp;
1034     fpr = sig->fpr;
1035     sum = sig->summary;
1036
1037     if (gpg_err_code (sig->status) != GPG_ERR_NO_ERROR)
1038       anybad = 1;
1039
1040     err = gpgme_get_key2 (ctx, fpr, &key, 0);    /* secret key?  */
1041     if (!err) {
1042       uid = (key->uids && key->uids->uid) ? key->uids->uid : "[?]";
1043       if (!signature_key)
1044         signature_key = key;
1045     }
1046     else {
1047       key = NULL;               /* Old gpgme versions did not set KEY to NULL on
1048                                    error.   Do it here to avoid a double free. */
1049       uid = "[?]";
1050     }
1051
1052     if (!s || !s->fpout || !(s->flags & M_DISPLAY));    /* No state information so no way to print anything. */
1053     else if (err) {
1054       state_attach_puts (_("Error getting key information: "), s);
1055       state_attach_puts (gpg_strerror (err), s);
1056       state_attach_puts ("\n", s);
1057       anybad = 1;
1058     }
1059     else if ((sum & GPGME_SIGSUM_GREEN)) {
1060       state_attach_puts (_("Good signature from: "), s);
1061       state_attach_puts (uid, s);
1062       state_attach_puts ("\n", s);
1063       for (i = 1, uids = key->uids; uids; i++, uids = uids->next) {
1064         if (i == 1)
1065           /* Skip primary UID.  */
1066           continue;
1067         if (uids->revoked)
1068           continue;
1069         state_attach_puts (_("                aka: "), s);
1070         state_attach_puts (uids->uid, s);
1071         state_attach_puts ("\n", s);
1072       }
1073       state_attach_puts (_("            created: "), s);
1074       print_time (created, s);
1075       state_attach_puts ("\n", s);
1076       if (show_sig_summary (sum, ctx, key, idx, s))
1077         anywarn = 1;
1078       show_one_sig_validity (ctx, idx, s);
1079     }
1080     else if ((sum & GPGME_SIGSUM_RED)) {
1081       state_attach_puts (_("*BAD* signature claimed to be from: "), s);
1082       state_attach_puts (uid, s);
1083       state_attach_puts ("\n", s);
1084       show_sig_summary (sum, ctx, key, idx, s);
1085     }
1086     else if (!anybad && key && (key->protocol == GPGME_PROTOCOL_OpenPGP)) {     /* We can't decide (yellow) but this is a PGP key with a good
1087                                                                                    signature, so we display what a PGP user expects: The name,
1088                                                                                    fingerprint and the key validity (which is neither fully or
1089                                                                                    ultimate). */
1090       state_attach_puts (_("Good signature from: "), s);
1091       state_attach_puts (uid, s);
1092       state_attach_puts ("\n", s);
1093       state_attach_puts (_("            created: "), s);
1094       print_time (created, s);
1095       state_attach_puts ("\n", s);
1096       show_one_sig_validity (ctx, idx, s);
1097       show_fingerprint (key, s);
1098       if (show_sig_summary (sum, ctx, key, idx, s))
1099         anywarn = 1;
1100     }
1101     else {                      /* can't decide (yellow) */
1102
1103       state_attach_puts (_("Error checking signature"), s);
1104       state_attach_puts ("\n", s);
1105       show_sig_summary (sum, ctx, key, idx, s);
1106     }
1107
1108     if (key != signature_key)
1109       gpgme_key_unref(key);
1110   }
1111
1112   return anybad ? 1 : anywarn ? 2 : 0;
1113 }
1114
1115 /* Do the actual verification step. With IS_SMIME set to true we
1116    assume S/MIME (surprise!) */
1117 static int crypt_verify_one(BODY *sigbdy, STATE *s, FILE *fp, int is_smime)
1118 {
1119   int badsig = -1;
1120   int anywarn = 0;
1121   int err;
1122   gpgme_ctx_t ctx;
1123   gpgme_data_t signature, message;
1124
1125   signature = file_to_data_object (s->fpin, sigbdy->offset, sigbdy->length);
1126   if (!signature)
1127     return -1;
1128
1129   /* We need to tell gpgme about the encoding because the backend can't
1130      auto-detect plain base-64 encoding which is used by S/MIME. */
1131   if (is_smime)
1132     gpgme_data_set_encoding (signature, GPGME_DATA_ENCODING_BASE64);
1133
1134   err = gpgme_data_new_from_stream(&message, fp);
1135   if (err) {
1136     gpgme_data_release (signature);
1137     mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
1138     return -1;
1139   }
1140   ctx = create_gpgme_context (is_smime);
1141
1142   /* Note: We don't need a current time output because GPGME avoids
1143      such an attack by separating the meta information from the
1144      data. */
1145   state_attach_puts (_("[-- Begin signature information --]\n"), s);
1146
1147   err = gpgme_op_verify (ctx, signature, message, NULL);
1148   mutt_need_hard_redraw ();
1149   if (err) {
1150     char buf[200];
1151
1152     snprintf (buf, sizeof (buf) - 1,
1153               _("Error: verification failed: %s\n"), gpgme_strerror (err));
1154     state_attach_puts (buf, s);
1155   }
1156   else {                        /* Verification succeeded, see what the result is. */
1157     int res, idx;
1158     int anybad = 0;
1159
1160     if (signature_key) {
1161       gpgme_key_unref(signature_key);
1162       signature_key = NULL;
1163     }
1164
1165     for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1166       if (res == 1)
1167         anybad = 1;
1168       else if (res == 2)
1169         anywarn = 2;
1170     }
1171     if (!anybad)
1172       badsig = 0;
1173   }
1174
1175   if (!badsig) {
1176     gpgme_verify_result_t result;
1177     gpgme_sig_notation_t notation;
1178     gpgme_signature_t sig;
1179
1180     result = gpgme_op_verify_result (ctx);
1181     if (result) {
1182       for (sig = result->signatures; sig; sig = sig->next) {
1183         if (sig->notations) {
1184           state_attach_puts ("*** Begin Notation (signature by: ", s);
1185           state_attach_puts (sig->fpr, s);
1186           state_attach_puts (") ***\n", s);
1187           for (notation = sig->notations; notation; notation = notation->next)
1188           {
1189             if (notation->name) {
1190               state_attach_puts (notation->name, s);
1191               state_attach_puts ("=", s);
1192             }
1193             if (notation->value) {
1194               state_attach_puts (notation->value, s);
1195               if (!(*notation->value
1196                     && (notation->value[m_strlen(notation->value) - 1] ==
1197                         '\n')))
1198                 state_attach_puts ("\n", s);
1199             }
1200           }
1201           state_attach_puts ("*** End Notation ***\n", s);
1202         }
1203       }
1204     }
1205   }
1206
1207   gpgme_release (ctx);
1208
1209   state_attach_puts (_("[-- End signature information --]\n\n"), s);
1210
1211   return badsig ? 1 : anywarn ? 2 : 0;
1212 }
1213
1214 /* Decrypt a PGP or SMIME message (depending on the boolean flag
1215    IS_SMIME) with body A described further by state S.  Write
1216    plaintext out to file FPOUT and return a new body.  For PGP returns
1217    a flag in R_IS_SIGNED to indicate whether this is a combined
1218    encrypted and signed message, for S/MIME it returns true when it is
1219    not a encrypted but a signed message.  */
1220 static BODY *
1221 decrypt_part(BODY *a, STATE *s, FILE *fpout, int is_smime, int *r_is_signed)
1222 {
1223   struct stat info;
1224   BODY *tattach;
1225   int err = 0;
1226   gpgme_ctx_t ctx;
1227   gpgme_data_t ciphertext, plaintext;
1228   int maybe_signed = 0;
1229   int anywarn = 0;
1230   int sig_stat = 0;
1231
1232   if (r_is_signed)
1233     *r_is_signed = 0;
1234
1235   ctx = create_gpgme_context (is_smime);
1236
1237 restart:
1238   /* Make a data object from the body, create context etc. */
1239   ciphertext = file_to_data_object (s->fpin, a->offset, a->length);
1240   if (!ciphertext)
1241     return NULL;
1242   plaintext = create_gpgme_data ();
1243
1244   /* Do the decryption or the verification in case of the S/MIME hack. */
1245   if ((!is_smime) || maybe_signed) {
1246     if (!is_smime)
1247       err = gpgme_op_decrypt_verify (ctx, ciphertext, plaintext);
1248     else if (maybe_signed)
1249       err = gpgme_op_verify (ctx, ciphertext, NULL, plaintext);
1250
1251     {
1252       /* Check wether signatures have been verified.  */
1253       gpgme_verify_result_t verify_result = gpgme_op_verify_result (ctx);
1254
1255       if (verify_result->signatures)
1256         sig_stat = 1;
1257     }
1258   }
1259   else
1260     err = gpgme_op_decrypt (ctx, ciphertext, plaintext);
1261   gpgme_data_release (ciphertext);
1262   if (err) {
1263     if (is_smime && !maybe_signed && gpg_err_code (err) == GPG_ERR_NO_DATA) {
1264       /* Check whether this might be a signed message despite what
1265          the mime header told us.  Retry then.  gpgsm returns the
1266          error information "unsupported Algorithm '?'" but gpgme
1267          will not store this unknown algorithm, thus we test that
1268          it has not been set. */
1269       gpgme_decrypt_result_t result;
1270
1271       result = gpgme_op_decrypt_result (ctx);
1272       if (!result->unsupported_algorithm) {
1273         maybe_signed = 1;
1274         gpgme_data_release (plaintext);
1275         goto restart;
1276       }
1277     }
1278     mutt_need_hard_redraw ();
1279     if ((s->flags & M_DISPLAY)) {
1280       char buf[200];
1281
1282       snprintf (buf, sizeof (buf) - 1,
1283                 _("[-- Error: decryption failed: %s --]\n\n"),
1284                 gpgme_strerror (err));
1285       state_attach_puts (buf, s);
1286     }
1287     gpgme_data_release (plaintext);
1288     gpgme_release (ctx);
1289     return NULL;
1290   }
1291   mutt_need_hard_redraw ();
1292
1293   /* Read the output from GPGME, and make sure to change CRLF to LF,
1294      otherwise read_mime_header has a hard time parsing the message.  */
1295   if (data_object_to_stream (plaintext, fpout)) {
1296     gpgme_data_release (plaintext);
1297     gpgme_release (ctx);
1298     return NULL;
1299   }
1300   gpgme_data_release (plaintext);
1301
1302   a->is_signed_data = 0;
1303   if (sig_stat) {
1304     int res, idx;
1305     int anybad = 0;
1306
1307     if (maybe_signed)
1308       a->is_signed_data = 1;
1309     if (r_is_signed)
1310       *r_is_signed = -1;        /* A signature exists. */
1311
1312     if ((s->flags & M_DISPLAY))
1313       state_attach_puts (_("[-- Begin signature " "information --]\n"), s);
1314     for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1315       if (res == 1)
1316         anybad = 1;
1317       else if (res == 2)
1318         anywarn = 1;
1319     }
1320     if (!anybad && idx && r_is_signed && *r_is_signed)
1321       *r_is_signed = anywarn ? 2 : 1;   /* Good signature. */
1322
1323     if ((s->flags & M_DISPLAY))
1324       state_attach_puts (_("[-- End signature " "information --]\n\n"), s);
1325   }
1326   gpgme_release (ctx);
1327   ctx = NULL;
1328
1329   fflush (fpout);
1330   rewind (fpout);
1331   tattach = mutt_read_mime_header (fpout, 0);
1332   if (tattach) {
1333     /*
1334      * Need to set the length of this body part.
1335      */
1336     fstat (fileno (fpout), &info);
1337     tattach->length = info.st_size - tattach->offset;
1338
1339     tattach->warnsig = anywarn;
1340
1341     /* See if we need to recurse on this MIME part.  */
1342     mutt_parse_part (fpout, tattach);
1343   }
1344
1345   return tattach;
1346 }
1347
1348 /* Decrypt a PGP/MIME message in FPIN and B and return a new body and
1349    the stream in CUR and FPOUT.  Returns 0 on success. */
1350 int crypt_pgp_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
1351 {
1352   char tempfile[_POSIX_PATH_MAX];
1353   STATE s;
1354   BODY *first_part = b;
1355   int is_signed;
1356
1357   first_part->goodsig = 0;
1358   first_part->warnsig = 0;
1359
1360   if (!mutt_is_multipart_encrypted (b))
1361     return -1;
1362
1363   if (!b->parts || !b->parts->next)
1364     return -1;
1365
1366   b = b->parts->next;
1367
1368   p_clear(&s, 1);
1369   s.fpin = fpin;
1370   *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1371   if (!*fpout) {
1372     mutt_perror (_("Can't create temporary file"));
1373     return -1;
1374   }
1375   unlink (tempfile);
1376
1377   *cur = decrypt_part (b, &s, *fpout, 0, &is_signed);
1378   rewind (*fpout);
1379   if (is_signed > 0)
1380     first_part->goodsig = 1;
1381
1382   return *cur ? 0 : -1;
1383 }
1384
1385
1386 /* Decrypt a S/MIME message in FPIN and B and return a new body and
1387    the stream in CUR and FPOUT.  Returns 0 on success. */
1388 int crypt_smime_decrypt_mime(FILE *fpin, FILE **fpout, BODY *b, BODY **cur)
1389 {
1390   char tempfile[_POSIX_PATH_MAX];
1391   STATE s;
1392   FILE *tmpfp = NULL;
1393   int is_signed;
1394   long saved_b_offset;
1395   ssize_t saved_b_length;
1396   int saved_b_type;
1397
1398   if (!mutt_is_application_smime (b))
1399     return -1;
1400
1401   if (b->parts)
1402     return -1;
1403
1404   /* Decode the body - we need to pass binary CMS to the
1405      backend.  The backend allows for Base64 encoded data but it does
1406      not allow for QP which I have seen in some messages.  So better
1407      do it here. */
1408   saved_b_type = b->type;
1409   saved_b_offset = b->offset;
1410   saved_b_length = b->length;
1411   p_clear(&s, 1);
1412   s.fpin = fpin;
1413   fseeko (s.fpin, b->offset, 0);
1414   tmpfp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1415   if (!tmpfp) {
1416     mutt_perror (_("Can't create temporary file"));
1417     return -1;
1418   }
1419   mutt_unlink (tempfile);
1420
1421   s.fpout = tmpfp;
1422   mutt_decode_attachment (b, &s);
1423   fflush (tmpfp);
1424   b->length = ftello (s.fpout);
1425   b->offset = 0;
1426   rewind (tmpfp);
1427
1428   p_clear(&s, 1);
1429   s.fpin = tmpfp;
1430   s.fpout = 0;
1431   *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1432   if (!*fpout) {
1433     mutt_perror (_("Can't create temporary file"));
1434     return -1;
1435   }
1436   mutt_unlink (tempfile);
1437
1438   *cur = decrypt_part (b, &s, *fpout, 1, &is_signed);
1439   if (*cur)
1440     (*cur)->goodsig = is_signed > 0;
1441   b->type = saved_b_type;
1442   b->length = saved_b_length;
1443   b->offset = saved_b_offset;
1444   m_fclose(&tmpfp);
1445   rewind (*fpout);
1446   if (*cur && !is_signed && !(*cur)->parts
1447       && mutt_is_application_smime (*cur)) {
1448     /* Assume that this is a opaque signed s/mime message.  This is
1449        an ugly way of doing it but we have anyway a problem with
1450        arbitrary encoded S/MIME messages: Only the outer part may be
1451        encrypted.  The entire mime parsing should be revamped,
1452        probably by keeping the temportary files so that we don't
1453        need to decrypt them all the time.  Inner parts of an
1454        encrypted part can then pint into this file and tehre won't
1455        never be a need to decrypt again.  This needs a partial
1456        rewrite of the MIME engine. */
1457     BODY *bb = *cur;
1458     BODY *tmp_b;
1459
1460     saved_b_type = bb->type;
1461     saved_b_offset = bb->offset;
1462     saved_b_length = bb->length;
1463     p_clear(&s, 1);
1464     s.fpin = *fpout;
1465     fseeko (s.fpin, bb->offset, 0);
1466     tmpfp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1467     if (!tmpfp) {
1468       mutt_perror (_("Can't create temporary file"));
1469       return -1;
1470     }
1471     mutt_unlink (tempfile);
1472
1473     s.fpout = tmpfp;
1474     mutt_decode_attachment (bb, &s);
1475     fflush (tmpfp);
1476     bb->length = ftello (s.fpout);
1477     bb->offset = 0;
1478     rewind (tmpfp);
1479     m_fclose(&*fpout);
1480
1481     p_clear(&s, 1);
1482     s.fpin = tmpfp;
1483     s.fpout = 0;
1484     *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1485     if (!*fpout) {
1486       mutt_perror (_("Can't create temporary file"));
1487       return -1;
1488     }
1489     mutt_unlink (tempfile);
1490
1491     tmp_b = decrypt_part (bb, &s, *fpout, 1, &is_signed);
1492     if (tmp_b)
1493       tmp_b->goodsig = is_signed > 0;
1494     bb->type = saved_b_type;
1495     bb->length = saved_b_length;
1496     bb->offset = saved_b_offset;
1497     m_fclose(&tmpfp);
1498     rewind (*fpout);
1499     body_list_wipe(cur);
1500     *cur = tmp_b;
1501   }
1502   return *cur ? 0 : -1;
1503 }
1504
1505
1506 static int
1507 pgp_check_traditional_one_body(FILE *fp, BODY *b, int tagged_only)
1508 {
1509   char tempfile[_POSIX_PATH_MAX];
1510   char buf[HUGE_STRING];
1511   FILE *tfp;
1512   int tempfd;
1513
1514   short sgn = 0;
1515   short enc = 0;
1516
1517   if (b->type != TYPETEXT)
1518     return 0;
1519
1520   if (tagged_only && !b->tagged)
1521     return 0;
1522
1523   tempfd = m_tempfd(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1524   if (mutt_decode_save_attachment (fp, b, tempfd, 0) != 0) {
1525     unlink (tempfile);
1526     return 0;
1527   }
1528
1529   if ((tfp = fopen(tempfile, "r")) == NULL) {
1530     unlink (tempfile);
1531     return 0;
1532   }
1533
1534   while (fgets (buf, sizeof (buf), tfp)) {
1535     if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
1536       if (!m_strcmp("MESSAGE-----\n", buf + 15))
1537         enc = 1;
1538       else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15))
1539         sgn = 1;
1540     }
1541   }
1542   m_fclose(&tfp);
1543   unlink (tempfile);
1544
1545   if (!enc && !sgn)
1546     return 0;
1547
1548   /* fix the content type */
1549
1550   parameter_setval(&b->parameter, "format", "fixed");
1551   parameter_setval(&b->parameter, "x-action",
1552                    enc ? "pgp-encrypted" : "pgp-signed");
1553   return 1;
1554 }
1555
1556 int crypt_pgp_check_traditional(FILE *fp, BODY *b, int tagged_only)
1557 {
1558   int rv = 0;
1559   int r;
1560
1561   for (; b; b = b->next) {
1562     if (is_multipart (b))
1563       rv = (crypt_pgp_check_traditional (fp, b->parts, tagged_only) || rv);
1564     else if (b->type == TYPETEXT) {
1565       if ((r = mutt_is_application_pgp (b)))
1566         rv = (rv || r);
1567       else
1568         rv = (pgp_check_traditional_one_body (fp, b, tagged_only) || rv);
1569     }
1570   }
1571   return rv;
1572 }
1573
1574 /*
1575   Copy a clearsigned message, and strip the signature and PGP's
1576   dash-escaping.
1577
1578   XXX - charset handling: We assume that it is safe to do
1579   character set decoding first, dash decoding second here, while
1580   we do it the other way around in the main handler.
1581
1582   (Note that we aren't worse than Outlook & Cie in this, and also
1583   note that we can successfully handle anything produced by any
1584   existing versions of mutt.)  */
1585 static void copy_clearsigned(gpgme_data_t data, STATE * s, char *charset)
1586 {
1587   char buf[HUGE_STRING];
1588   short complete, armor_header;
1589   fgetconv_t *fc;
1590   char *fname;
1591   FILE *fp;
1592
1593   fname = data_object_to_tempfile (data, &fp);
1594   if (!fname)
1595     return;
1596   unlink (fname);
1597   p_delete(&fname);
1598
1599   fc = fgetconv_open (fp, charset, MCharset.charset, M_ICONV_HOOK_FROM);
1600
1601   for (complete = 1, armor_header = 1;
1602        fgetconvs (buf, sizeof (buf), fc) != NULL;
1603        complete = strchr (buf, '\n') != NULL) {
1604     if (!complete) {
1605       if (!armor_header)
1606         state_puts (buf, s);
1607       continue;
1608     }
1609
1610     if (!m_strcmp(buf, "-----BEGIN PGP SIGNATURE-----\n"))
1611       break;
1612
1613     if (armor_header) {
1614       if (buf[0] == '\n')
1615         armor_header = 0;
1616       continue;
1617     }
1618
1619     if (s->prefix)
1620       state_puts (s->prefix, s);
1621
1622     if (buf[0] == '-' && buf[1] == ' ')
1623       state_puts (buf + 2, s);
1624     else
1625       state_puts (buf, s);
1626   }
1627
1628   fgetconv_close (&fc);
1629   m_fclose(&fp);
1630 }
1631
1632 /* Support for classic_application/pgp */
1633 int crypt_pgp_application_pgp_handler(BODY *m, STATE *s)
1634 {
1635   int needpass = -1, pgp_keyblock = 0;
1636   int clearsign = 0;
1637   long start_pos = 0;
1638   long bytes;
1639   off_t last_pos, offset;
1640   char buf[HUGE_STRING];
1641   FILE *pgpout = NULL;
1642
1643   gpgme_error_t err = 0;
1644   gpgme_data_t armored_data = NULL;
1645
1646   short maybe_goodsig = 1;
1647   short have_any_sigs = 0;
1648
1649   char body_charset[STRING];    /* Only used for clearsigned messages. */
1650
1651   /* For clearsigned messages we won't be able to get a character set
1652      but we know that this may only be text thus we assume Latin-1
1653      here. */
1654   if (!mutt_get_body_charset (body_charset, sizeof (body_charset), m))
1655     m_strcpy(body_charset, sizeof(body_charset), "iso-8859-1");
1656
1657   fseeko (s->fpin, m->offset, 0);
1658   last_pos = m->offset;
1659
1660   for (bytes = m->length; bytes > 0;) {
1661     if (fgets (buf, sizeof (buf), s->fpin) == NULL)
1662       break;
1663
1664     offset = ftello (s->fpin);
1665     bytes -= (offset - last_pos);       /* don't rely on m_strlen(buf) */
1666     last_pos = offset;
1667
1668     if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
1669       clearsign = 0;
1670       start_pos = last_pos;
1671
1672       if (!m_strcmp("MESSAGE-----\n", buf + 15))
1673         needpass = 1;
1674       else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15)) {
1675         clearsign = 1;
1676         needpass = 0;
1677       }
1678       else if (!option (OPTDONTHANDLEPGPKEYS) &&
1679                !m_strcmp("PUBLIC KEY BLOCK-----\n", buf + 15)) {
1680         needpass = 0;
1681         pgp_keyblock = 1;
1682       }
1683       else {
1684         /* XXX - we may wish to recode here */
1685         if (s->prefix)
1686           state_puts (s->prefix, s);
1687         state_puts (buf, s);
1688         continue;
1689       }
1690
1691       have_any_sigs = (have_any_sigs || (clearsign && (s->flags & M_VERIFY)));
1692
1693       /* Copy PGP material to an data container */
1694       armored_data = create_gpgme_data ();
1695       gpgme_data_write (armored_data, buf, m_strlen(buf));
1696       while (bytes > 0 && fgets (buf, sizeof (buf) - 1, s->fpin) != NULL) {
1697         offset = ftello (s->fpin);
1698         bytes -= (offset - last_pos);   /* don't rely on m_strlen(buf) */
1699         last_pos = offset;
1700
1701         gpgme_data_write (armored_data, buf, m_strlen(buf));
1702
1703         if ((needpass && !m_strcmp("-----END PGP MESSAGE-----\n", buf))
1704             || (!needpass
1705                 && (!m_strcmp("-----END PGP SIGNATURE-----\n", buf)
1706                     || !m_strcmp("-----END PGP PUBLIC KEY BLOCK-----\n",
1707                                      buf))))
1708           break;
1709       }
1710
1711       /* Invoke PGP if needed */
1712       if (!clearsign || (s->flags & M_VERIFY)) {
1713         unsigned int sig_stat = 0;
1714         gpgme_data_t plaintext;
1715         gpgme_ctx_t ctx;
1716
1717         plaintext = create_gpgme_data ();
1718         ctx = create_gpgme_context (0);
1719
1720         if (clearsign)
1721           err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1722         else {
1723           err = gpgme_op_decrypt_verify (ctx, armored_data, plaintext);
1724           if (gpg_err_code (err) == GPG_ERR_NO_DATA) {
1725             /* Decrypt verify can't handle signed only messages. */
1726             err = (gpgme_data_seek (armored_data, 0, SEEK_SET) == -1)
1727               ? gpgme_error_from_errno (errno) : 0;
1728             /* Must release plaintext so that we supply an
1729                uninitialized object. */
1730             gpgme_data_release (plaintext);
1731             plaintext = create_gpgme_data ();
1732             err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1733           }
1734         }
1735
1736         if (err) {
1737           char errbuf[200];
1738
1739           snprintf (errbuf, sizeof (errbuf) - 1,
1740                     _("Error: decryption/verification failed: %s\n"),
1741                     gpgme_strerror (err));
1742           state_attach_puts (errbuf, s);
1743         }
1744         else {                  /* Decryption/Verification succeeded */
1745           char *tmpfname;
1746
1747           {
1748             /* Check wether signatures have been verified.  */
1749             gpgme_verify_result_t verify_result;
1750
1751             verify_result = gpgme_op_verify_result (ctx);
1752             if (verify_result->signatures)
1753               sig_stat = 1;
1754           }
1755
1756           have_any_sigs = 0;
1757           maybe_goodsig = 0;
1758           if ((s->flags & M_DISPLAY) && sig_stat) {
1759             int res, idx;
1760             int anybad = 0;
1761             int anywarn = 0;
1762
1763             state_attach_puts (_("[-- Begin signature "
1764                                  "information --]\n"), s);
1765             have_any_sigs = 1;
1766             for (idx = 0;
1767                  (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1768               if (res == 1)
1769                 anybad = 1;
1770               else if (res == 2)
1771                 anywarn = 1;
1772             }
1773             if (!anybad && idx)
1774               maybe_goodsig = 1;
1775
1776             state_attach_puts (_("[-- End signature "
1777                                  "information --]\n\n"), s);
1778           }
1779
1780           tmpfname = data_object_to_tempfile (plaintext, &pgpout);
1781           if (!tmpfname) {
1782             pgpout = NULL;
1783             state_attach_puts (_("Error: copy data failed\n"), s);
1784           }
1785           else {
1786             unlink (tmpfname);
1787             p_delete(&tmpfname);
1788           }
1789         }
1790         gpgme_release (ctx);
1791       }
1792
1793       /*
1794        * Now, copy cleartext to the screen.  NOTE - we expect that PGP
1795        * outputs utf-8 cleartext.  This may not always be true, but it
1796        * seems to be a reasonable guess.
1797        */
1798
1799       if (s->flags & M_DISPLAY) {
1800         if (needpass)
1801           state_attach_puts (_("[-- BEGIN PGP MESSAGE --]\n\n"), s);
1802         else if (pgp_keyblock)
1803           state_attach_puts (_("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"), s);
1804         else
1805           state_attach_puts (_("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"), s);
1806       }
1807
1808       if (clearsign) {
1809         copy_clearsigned (armored_data, s, body_charset);
1810       }
1811       else if (pgpout) {
1812         fgetconv_t *fc;
1813         int c;
1814
1815         rewind (pgpout);
1816         fc = fgetconv_open (pgpout, "utf-8", MCharset.charset, 0);
1817         while ((c = fgetconv (fc)) != EOF) {
1818           state_putc (c, s);
1819           if (c == '\n' && s->prefix)
1820             state_puts (s->prefix, s);
1821         }
1822         fgetconv_close (&fc);
1823       }
1824
1825       if (s->flags & M_DISPLAY) {
1826         state_putc ('\n', s);
1827         if (needpass)
1828           state_attach_puts (_("[-- END PGP MESSAGE --]\n"), s);
1829         else if (pgp_keyblock)
1830           state_attach_puts (_("[-- END PGP PUBLIC KEY BLOCK --]\n"), s);
1831         else
1832           state_attach_puts (_("[-- END PGP SIGNED MESSAGE --]\n"), s);
1833       }
1834
1835       if (pgpout) {
1836         m_fclose(&pgpout);
1837       }
1838     }
1839     else {
1840       /* XXX - we may wish to recode here */
1841       if (s->prefix)
1842         state_puts (s->prefix, s);
1843       state_puts (buf, s);
1844     }
1845   }
1846
1847   m->goodsig = (maybe_goodsig && have_any_sigs);
1848
1849   if (needpass == -1) {
1850     state_attach_puts (_("[-- Error: could not find beginning"
1851                          " of PGP message! --]\n\n"), s);
1852     return (-1);
1853   }
1854   return (err);
1855 }
1856
1857 /* MIME handler for pgp/mime encrypted messages. */
1858 int crypt_pgp_encrypted_handler (BODY * a, STATE * s)
1859 {
1860   char tempfile[_POSIX_PATH_MAX];
1861   FILE *fpout;
1862   BODY *tattach;
1863   BODY *orig_body = a;
1864   int is_signed;
1865   int rc = 0;
1866
1867   a = a->parts;
1868   if (!a || a->type != TYPEAPPLICATION || !a->subtype
1869       || ascii_strcasecmp ("pgp-encrypted", a->subtype)
1870       || !a->next || a->next->type != TYPEAPPLICATION || !a->next->subtype
1871       || ascii_strcasecmp ("octet-stream", a->next->subtype)) {
1872     if (s->flags & M_DISPLAY)
1873       state_attach_puts (_("[-- Error: malformed PGP/MIME message! --]\n\n"),
1874                          s);
1875     return (-1);
1876   }
1877
1878   /* Move forward to the application/pgp-encrypted body. */
1879   a = a->next;
1880
1881   fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1882   if (!fpout) {
1883     if (s->flags & M_DISPLAY)
1884       state_attach_puts (_("[-- Error: could not create temporary file! "
1885                            "--]\n"), s);
1886     return (-1);
1887   }
1888
1889   tattach = decrypt_part (a, s, fpout, 0, &is_signed);
1890   if (tattach) {
1891     tattach->goodsig = is_signed > 0;
1892
1893     if (s->flags & M_DISPLAY)
1894       state_attach_puts (is_signed ?
1895                          _
1896                          ("[-- The following data is PGP/MIME signed and encrypted --]\n\n") :
1897                          _("[-- The following data is PGP/MIME encrypted --]\n\n"), s);
1898
1899     {
1900       FILE *savefp = s->fpin;
1901
1902       s->fpin = fpout;
1903       rc = mutt_body_handler (tattach, s);
1904       s->fpin = savefp;
1905     }
1906
1907     /*
1908      * if a multipart/signed is the _only_ sub-part of a
1909      * multipart/encrypted, cache signature verification
1910      * status.
1911      */
1912     if (mutt_is_multipart_signed (tattach) && !tattach->next)
1913       orig_body->goodsig |= tattach->goodsig;
1914
1915     if (s->flags & M_DISPLAY) {
1916       state_puts ("\n", s);
1917       state_attach_puts (is_signed ?
1918                          _
1919                          ("[-- End of PGP/MIME signed and encrypted data --]\n")
1920                          : _("[-- End of PGP/MIME encrypted data --]\n"), s);
1921     }
1922
1923     body_list_wipe(&tattach);
1924   }
1925
1926   m_fclose(&fpout);
1927   mutt_unlink (tempfile);
1928   return (rc);
1929 }
1930
1931 /* Support for application/smime */
1932 int crypt_smime_application_smime_handler (BODY * a, STATE * s)
1933 {
1934   char tempfile[_POSIX_PATH_MAX];
1935   FILE *fpout;
1936   BODY *tattach;
1937   int is_signed;
1938   int rc = 0;
1939
1940   a->warnsig = 0;
1941   fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
1942   if (!fpout) {
1943     if (s->flags & M_DISPLAY)
1944       state_attach_puts (_("[-- Error: could not create temporary file! "
1945                            "--]\n"), s);
1946     return (-1);
1947   }
1948
1949   tattach = decrypt_part (a, s, fpout, 1, &is_signed);
1950   if (tattach) {
1951     tattach->goodsig = is_signed > 0;
1952
1953     if (s->flags & M_DISPLAY)
1954       state_attach_puts (is_signed ?
1955                          _("[-- The following data is S/MIME signed --]\n\n") :
1956                          _("[-- The following data is S/MIME encrypted --]\n\n"), s);
1957
1958     {
1959       FILE *savefp = s->fpin;
1960
1961       s->fpin = fpout;
1962       rc = mutt_body_handler (tattach, s);
1963       s->fpin = savefp;
1964     }
1965
1966     /*
1967      * if a multipart/signed is the _only_ sub-part of a
1968      * multipart/encrypted, cache signature verification
1969      * status.
1970      */
1971     if (mutt_is_multipart_signed (tattach) && !tattach->next) {
1972       if (!(a->goodsig = tattach->goodsig))
1973         a->warnsig = tattach->warnsig;
1974     }
1975     else if (tattach->goodsig) {
1976       a->goodsig = 1;
1977       a->warnsig = tattach->warnsig;
1978     }
1979
1980     if (s->flags & M_DISPLAY) {
1981       state_puts ("\n", s);
1982       state_attach_puts (is_signed ?
1983                          _("[-- End of S/MIME signed data --]\n") :
1984                          _("[-- End of S/MIME encrypted data --]\n"), s);
1985     }
1986
1987     body_list_wipe(&tattach);
1988   }
1989
1990   m_fclose(&fpout);
1991   mutt_unlink (tempfile);
1992   return (rc);
1993 }
1994
1995
1996 /*
1997  * Format an entry on the CRYPT key selection menu.
1998  *
1999  * %n   number
2000  * %k   key id          %K      key id of the principal key
2001  * %u   user id
2002  * %a   algorithm       %A      algorithm of the princ. key
2003  * %l   length          %L      length of the princ. key
2004  * %f   flags           %F      flags of the princ. key
2005  * %c   capabilities    %C      capabilities of the princ. key
2006  * %t   trust/validity of the key-uid association
2007  * %p           protocol
2008  * %[...] date of key using strftime(3)
2009  */
2010
2011 static const char *
2012 crypt_entry_fmt (char *dest, ssize_t destlen, char op,
2013                  const char *src, const char *prefix,
2014                  const char *ifstr, const char *elstr,
2015                  anytype data, format_flag flags)
2016 {
2017   char fmt[16];
2018   crypt_entry_t *entry;
2019   cryptkey_t *key;
2020   int kflags = 0;
2021   int optional = (flags & M_FORMAT_OPTIONAL);
2022   const char *s = NULL;
2023   unsigned long val;
2024
2025   entry = data.ptr;
2026   key = entry->key;
2027
2028 /*    if (isupper ((unsigned char) op)) */
2029 /*      key = pkey; */
2030
2031   kflags = (key->flags          /*| (pkey->flags & KEYFLAG_RESTRICTIONS)
2032                                    | uid->flags */ );
2033
2034   switch (ascii_tolower (op)) {
2035   case '[':
2036     {
2037       const char *cp;
2038       char buf2[STRING], *p;
2039       int do_locales;
2040       struct tm *tm;
2041       ssize_t len;
2042
2043       p = dest;
2044
2045       cp = src;
2046       if (*cp == '!') {
2047         do_locales = 0;
2048         cp++;
2049       }
2050       else
2051         do_locales = 1;
2052
2053       len = destlen - 1;
2054       while (len > 0 && *cp != ']') {
2055         if (*cp == '%') {
2056           cp++;
2057           if (len >= 2) {
2058             *p++ = '%';
2059             *p++ = *cp;
2060             len -= 2;
2061           }
2062           else
2063             break;              /* not enough space */
2064           cp++;
2065         }
2066         else {
2067           *p++ = *cp++;
2068           len--;
2069         }
2070       }
2071       *p = 0;
2072
2073       if (do_locales && Locale)
2074         setlocale (LC_TIME, Locale);
2075
2076       {
2077         time_t tt = 0;
2078
2079         if (key->kobj->subkeys && (key->kobj->subkeys->timestamp > 0))
2080           tt = key->kobj->subkeys->timestamp;
2081
2082         tm = localtime (&tt);
2083       }
2084       strftime (buf2, sizeof (buf2), dest, tm);
2085
2086       if (do_locales)
2087         setlocale (LC_TIME, "C");
2088
2089       snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2090       snprintf (dest, destlen, fmt, buf2);
2091       if (len > 0)
2092         src = cp + 1;
2093     }
2094     break;
2095   case 'n':
2096     if (!optional) {
2097       snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
2098       snprintf (dest, destlen, fmt, entry->num);
2099     }
2100     break;
2101   case 'k':
2102     if (!optional) {
2103       /* fixme: we need a way to distinguish between main and subkeys.
2104          Store the idx in entry? */
2105       snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2106       snprintf (dest, destlen, fmt, crypt_keyid (key));
2107     }
2108     break;
2109   case 'u':
2110     if (!optional) {
2111       snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2112       snprintf (dest, destlen, fmt, key->uid);
2113     }
2114     break;
2115   case 'a':
2116     if (!optional) {
2117       snprintf (fmt, sizeof (fmt), "%%%s.3s", prefix);
2118       if (key->kobj->subkeys)
2119         s = gpgme_pubkey_algo_name (key->kobj->subkeys->pubkey_algo);
2120       else
2121         s = "?";
2122       snprintf (dest, destlen, fmt, s);
2123     }
2124     break;
2125   case 'l':
2126     if (!optional) {
2127       snprintf (fmt, sizeof (fmt), "%%%slu", prefix);
2128       if (key->kobj->subkeys)
2129         val = key->kobj->subkeys->length;
2130       else
2131         val = 0;
2132       snprintf (dest, destlen, fmt, val);
2133     }
2134     break;
2135   case 'f':
2136     if (!optional) {
2137       snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2138       snprintf (dest, destlen, fmt, crypt_flags (kflags));
2139     }
2140     else if (!(kflags & (KEYFLAG_RESTRICTIONS)))
2141       optional = 0;
2142     break;
2143   case 'c':
2144     if (!optional) {
2145       snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2146       snprintf (dest, destlen, fmt, crypt_key_abilities (kflags));
2147     }
2148     else if (!(kflags & (KEYFLAG_ABILITIES)))
2149       optional = 0;
2150     break;
2151   case 't':
2152     if ((kflags & KEYFLAG_ISX509))
2153       s = "x";
2154     else {
2155       gpgme_user_id_t uid = NULL;
2156       int i = 0;
2157
2158       for (i = 0, uid = key->kobj->uids; uid && (i < key->idx);
2159            i++, uid = uid->next);
2160       if (uid)
2161         switch (uid->validity) {
2162         case GPGME_VALIDITY_UNDEFINED:
2163           s = "q";
2164           break;
2165         case GPGME_VALIDITY_NEVER:
2166           s = "n";
2167           break;
2168         case GPGME_VALIDITY_MARGINAL:
2169           s = "m";
2170           break;
2171         case GPGME_VALIDITY_FULL:
2172           s = "f";
2173           break;
2174         case GPGME_VALIDITY_ULTIMATE:
2175           s = "u";
2176           break;
2177         case GPGME_VALIDITY_UNKNOWN:
2178         default:
2179           s = "?";
2180           break;
2181         }
2182     }
2183     snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2184     snprintf (dest, destlen, fmt, s ? *s : 'B');
2185     break;
2186   case 'p':
2187     snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2188     snprintf (dest, destlen, fmt,
2189               gpgme_get_protocol_name (key->kobj->protocol));
2190     break;
2191
2192   default:
2193     *dest = '\0';
2194   }
2195
2196   if (flags & M_FORMAT_OPTIONAL)
2197     m_strformat(dest, destlen, 0, optional ? ifstr: elstr,
2198                 mutt_attach_fmt, data, 0);
2199   return src;
2200 }
2201
2202 /* Used by the display fucntion to format a line. */
2203 static void crypt_entry (char *s, ssize_t l, MUTTMENU * menu, int num)
2204 {
2205   cryptkey_t **cryptkey_table = (cryptkey_t **) menu->data;
2206   crypt_entry_t entry;
2207
2208   entry.key = cryptkey_table[num];
2209   entry.num = num + 1;
2210
2211   m_strformat(s, l, COLS - SW, PgpEntryFormat, crypt_entry_fmt, &entry,
2212               option(OPTARROWCURSOR) ? M_FORMAT_ARROWCURSOR : 0);
2213 }
2214
2215 /* Compare two addresses and the keyid to be used for sorting. */
2216 static int _crypt_compare_address (const void *a, const void *b)
2217 {
2218   cryptkey_t **s = (cryptkey_t **) a;
2219   cryptkey_t **t = (cryptkey_t **) b;
2220   int r;
2221
2222   if ((r = m_strcasecmp((*s)->uid, (*t)->uid)))
2223     return r > 0;
2224   else
2225     return m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t)) > 0;
2226 }
2227
2228 static int crypt_compare_address (const void *a, const void *b)
2229 {
2230   return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_address (a, b)
2231           : _crypt_compare_address (a, b));
2232 }
2233
2234
2235 /* Compare two key IDs and the addresses to be used for sorting. */
2236 static int _crypt_compare_keyid (const void *a, const void *b)
2237 {
2238   cryptkey_t **s = (cryptkey_t **) a;
2239   cryptkey_t **t = (cryptkey_t **) b;
2240   int r;
2241
2242   if ((r = m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t))))
2243     return r > 0;
2244   else
2245     return m_strcasecmp((*s)->uid, (*t)->uid) > 0;
2246 }
2247
2248 static int crypt_compare_keyid (const void *a, const void *b)
2249 {
2250   return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_keyid (a, b)
2251           : _crypt_compare_keyid (a, b));
2252 }
2253
2254 /* Compare 2 creation dates and the addresses.  For sorting. */
2255 static int _crypt_compare_date (const void *a, const void *b)
2256 {
2257   cryptkey_t **s = (cryptkey_t **) a;
2258   cryptkey_t **t = (cryptkey_t **) b;
2259   unsigned long ts = 0, tt = 0;
2260
2261   if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2262     ts = (*s)->kobj->subkeys->timestamp;
2263   if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2264     tt = (*t)->kobj->subkeys->timestamp;
2265
2266   if (ts > tt)
2267     return 1;
2268   if (ts < tt)
2269     return 0;
2270
2271   return m_strcasecmp((*s)->uid, (*t)->uid) > 0;
2272 }
2273
2274 static int crypt_compare_date (const void *a, const void *b)
2275 {
2276   return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_date (a, b)
2277           : _crypt_compare_date (a, b));
2278 }
2279
2280 /* Compare two trust values, the key length, the creation dates. the
2281    addresses and the key IDs.  For sorting. */
2282 static int _crypt_compare_trust (const void *a, const void *b)
2283 {
2284   cryptkey_t **s = (cryptkey_t **) a;
2285   cryptkey_t **t = (cryptkey_t **) b;
2286   unsigned long ts = 0, tt = 0;
2287   int r;
2288
2289   if ((r = (((*s)->flags & (KEYFLAG_RESTRICTIONS))
2290             - ((*t)->flags & (KEYFLAG_RESTRICTIONS)))))
2291     return r > 0;
2292
2293   if ((*s)->kobj->uids)
2294     ts = (*s)->kobj->uids->validity;
2295   if ((*t)->kobj->uids)
2296     tt = (*t)->kobj->uids->validity;
2297   if ((r = (tt - ts)))
2298     return r < 0;
2299
2300   if ((*s)->kobj->subkeys)
2301     ts = (*s)->kobj->subkeys->length;
2302   if ((*t)->kobj->subkeys)
2303     tt = (*t)->kobj->subkeys->length;
2304   if (ts != tt)
2305     return ts > tt;
2306
2307   if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2308     ts = (*s)->kobj->subkeys->timestamp;
2309   if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2310     tt = (*t)->kobj->subkeys->timestamp;
2311   if (ts > tt)
2312     return 1;
2313   if (ts < tt)
2314     return 0;
2315
2316   if ((r = m_strcasecmp((*s)->uid, (*t)->uid)))
2317     return r > 0;
2318   return (m_strcasecmp(crypt_keyid ((*s)), crypt_keyid ((*t)))) > 0;
2319 }
2320
2321 static int crypt_compare_trust (const void *a, const void *b)
2322 {
2323   return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_trust (a, b)
2324           : _crypt_compare_trust (a, b));
2325 }
2326
2327 /* Print the X.500 Distinguished Name part KEY from the array of parts
2328    DN to FP. */
2329 static int print_dn_part (FILE * fp, struct dn_array_s *dn, const char *key)
2330 {
2331   int any = 0;
2332
2333   for (; dn->key; dn++) {
2334     if (!m_strcmp(dn->key, key)) {
2335       if (any)
2336         fputs (" + ", fp);
2337       print_utf8 (fp, dn->value, m_strlen(dn->value));
2338       any = 1;
2339     }
2340   }
2341   return any;
2342 }
2343
2344 /* Print all parts of a DN in a standard sequence. */
2345 static void print_dn_parts (FILE * fp, struct dn_array_s *dn)
2346 {
2347   const char *stdpart[] = {
2348     "CN", "OU", "O", "STREET", "L", "ST", "C", NULL
2349   };
2350   int any = 0, any2 = 0, i;
2351
2352   for (i = 0; stdpart[i]; i++) {
2353     if (any)
2354       fputs (", ", fp);
2355     any = print_dn_part (fp, dn, stdpart[i]);
2356   }
2357   /* now print the rest without any specific ordering */
2358   for (; dn->key; dn++) {
2359     for (i = 0; stdpart[i]; i++) {
2360       if (!m_strcmp(dn->key, stdpart[i]))
2361         break;
2362     }
2363     if (!stdpart[i]) {
2364       if (any)
2365         fputs (", ", fp);
2366       if (!any2)
2367         fputs ("(", fp);
2368       any = print_dn_part (fp, dn, dn->key);
2369       any2 = 1;
2370     }
2371   }
2372   if (any2)
2373     fputs (")", fp);
2374 }
2375
2376
2377 /* Parse an RDN; this is a helper to parse_dn(). */
2378 static const unsigned char *parse_dn_part (struct dn_array_s *array,
2379                                            const unsigned char *string)
2380 {
2381   const unsigned char *s, *s1;
2382   ssize_t n;
2383   unsigned char *p;
2384
2385   /* parse attributeType */
2386   for (s = string + 1; *s && *s != '='; s++);
2387   if (!*s)
2388     return NULL;                /* error */
2389   n = s - string;
2390   if (!n)
2391     return NULL;                /* empty key */
2392   array->key = p_dupstr(string, n );
2393   p = (unsigned char *) array->key;
2394   string = s + 1;
2395
2396   if (*string == '#') {         /* hexstring */
2397     string++;
2398     for (s = string; hexval(*s) >= 0; s++)
2399       s++;
2400     n = s - string;
2401     if (!n || (n & 1))
2402       return NULL;              /* empty or odd number of digits */
2403     n /= 2;
2404     p = p_new(unsigned char, n + 1);
2405     array->value = (char *) p;
2406     for (s1 = string; n; s1 += 2, n--)
2407       *p++ = (hexval(*s1) << 8) | hexval(*s1);
2408     *p = 0;
2409   }
2410   else {                        /* regular v3 quoted string */
2411     for (n = 0, s = string; *s; s++) {
2412       if (*s == '\\') {         /* pair */
2413         s++;
2414         if (*s == ',' || *s == '=' || *s == '+'
2415             || *s == '<' || *s == '>' || *s == '#' || *s == ';'
2416             || *s == '\\' || *s == '\"' || *s == ' ')
2417           n++;
2418         else if (hexval(*s) >= 0 && hexval(*s + 1) >= 0) {
2419           s++;
2420           n++;
2421         }
2422         else
2423           return NULL;          /* invalid escape sequence */
2424       }
2425       else if (*s == '\"')
2426         return NULL;            /* invalid encoding */
2427       else if (*s == ',' || *s == '=' || *s == '+'
2428                || *s == '<' || *s == '>' || *s == '#' || *s == ';')
2429         break;
2430       else
2431         n++;
2432     }
2433
2434     p = p_new(unsigned char, n + 1);
2435     array->value = (char *) p;
2436     for (s = string; n; s++, n--) {
2437       if (*s == '\\') {
2438         s++;
2439         if (hexval(*s) >= 0) {
2440           *p++ = (hexval(*s) << 8) | hexval(*s + 1);
2441           s++;
2442         }
2443         else
2444           *p++ = *s;
2445       }
2446       else
2447         *p++ = *s;
2448     }
2449     *p = 0;
2450   }
2451   return s;
2452 }
2453
2454
2455 /* Parse a DN and return an array-ized one.  This is not a validating
2456    parser and it does not support any old-stylish syntax; gpgme is
2457    expected to return only rfc2253 compatible strings. */
2458 static struct dn_array_s *parse_dn (const unsigned char *string)
2459 {
2460   struct dn_array_s *array;
2461   ssize_t arrayidx, arraysize;
2462   int i;
2463
2464   arraysize = 7;                /* C,ST,L,O,OU,CN,email */
2465   array = p_new(struct dn_array_s, arraysize + 1);
2466   arrayidx = 0;
2467   while (*string) {
2468     while (*string == ' ')
2469       string++;
2470     if (!*string)
2471       break;                    /* ready */
2472     if (arrayidx >= arraysize) {        /* mutt lacks a real safe_realoc - so we need to copy */
2473       struct dn_array_s *a2;
2474
2475       arraysize += 5;
2476       a2 = p_new(struct dn_array_s, arraysize + 1);
2477       for (i = 0; i < arrayidx; i++) {
2478         a2[i].key = array[i].key;
2479         a2[i].value = array[i].value;
2480       }
2481       p_delete(&array);
2482       array = a2;
2483     }
2484     array[arrayidx].key = NULL;
2485     array[arrayidx].value = NULL;
2486     string = parse_dn_part (array + arrayidx, string);
2487     arrayidx++;
2488     if (!string)
2489       goto failure;
2490     while (*string == ' ')
2491       string++;
2492     if (*string && *string != ',' && *string != ';' && *string != '+')
2493       goto failure;             /* invalid delimiter */
2494     if (*string)
2495       string++;
2496   }
2497   array[arrayidx].key = NULL;
2498   array[arrayidx].value = NULL;
2499   return array;
2500
2501 failure:
2502   for (i = 0; i < arrayidx; i++) {
2503     p_delete(&array[i].key);
2504     p_delete(&array[i].value);
2505   }
2506   p_delete(&array);
2507   return NULL;
2508 }
2509
2510
2511 /* Print a nice representation of the USERID and make sure it is
2512    displayed in a proper way, which does mean to reorder some parts
2513    for S/MIME's DNs.  USERID is a string as returned by the gpgme key
2514    functions.  It is utf-8 encoded. */
2515 static void parse_and_print_user_id(FILE * fp, const char *userid)
2516 {
2517   const char *s;
2518   int i;
2519
2520   if (*userid == '<') {
2521     s = strchr (userid + 1, '>');
2522     if (s)
2523       print_utf8 (fp, userid + 1, s - userid - 1);
2524   }
2525   else if (*userid == '(')
2526     fputs (_("[Can't display this user ID (unknown encoding)]"), fp);
2527   else if (*userid & ~127 || __m_strdigits[(int)*userid] == 255)
2528     fputs (_("[Can't display this user ID (invalid encoding)]"), fp);
2529   else {
2530     struct dn_array_s *dn = parse_dn ((const unsigned char *) userid);
2531
2532     if (!dn)
2533       fputs (_("[Can't display this user ID (invalid DN)]"), fp);
2534     else {
2535       print_dn_parts (fp, dn);
2536       for (i = 0; dn[i].key; i++) {
2537         p_delete(&dn[i].key);
2538         p_delete(&dn[i].value);
2539       }
2540       p_delete(&dn);
2541     }
2542   }
2543 }
2544
2545 typedef enum {
2546     KEY_CAP_CAN_ENCRYPT,
2547     KEY_CAP_CAN_SIGN,
2548     KEY_CAP_CAN_CERTIFY
2549 } key_cap_t;
2550
2551 static unsigned int key_check_cap(gpgme_key_t key, key_cap_t cap)
2552 {
2553   gpgme_subkey_t subkey = NULL;
2554   unsigned int ret = 0;
2555
2556   switch (cap) {
2557   case KEY_CAP_CAN_ENCRYPT:
2558     if (!(ret = key->can_encrypt))
2559       for (subkey = key->subkeys; subkey; subkey = subkey->next)
2560         if ((ret = subkey->can_encrypt))
2561           break;
2562     break;
2563   case KEY_CAP_CAN_SIGN:
2564     if (!(ret = key->can_sign))
2565       for (subkey = key->subkeys; subkey; subkey = subkey->next)
2566         if ((ret = subkey->can_sign))
2567           break;
2568     break;
2569   case KEY_CAP_CAN_CERTIFY:
2570     if (!(ret = key->can_certify))
2571       for (subkey = key->subkeys; subkey; subkey = subkey->next)
2572         if ((ret = subkey->can_certify))
2573           break;
2574     break;
2575   }
2576
2577   return ret;
2578 }
2579
2580
2581 /* Print verbose information about a key or certificate to FP. */
2582 static void print_key_info (gpgme_key_t key, FILE * fp)
2583 {
2584   int idx;
2585   const char *s = NULL, *s2 = NULL;
2586   time_t tt = 0;
2587   struct tm *tm;
2588   char shortbuf[STRING];
2589   unsigned long aval = 0;
2590   const char *delim;
2591   int is_pgp = 0;
2592   int i;
2593   gpgme_user_id_t uid = NULL;
2594
2595   if (Locale)
2596     setlocale (LC_TIME, Locale);
2597
2598   is_pgp = key->protocol == GPGME_PROTOCOL_OpenPGP;
2599
2600   for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
2601     if (uid->revoked)
2602       continue;
2603
2604     s = uid->uid;
2605     fputs (idx ? _(" aka ......: ") :_("Name ......: "), fp);
2606
2607     if (uid->invalid) {
2608       fputs (_("[Invalid]"), fp);
2609       putc (' ', fp);
2610     }
2611     if (is_pgp)
2612       print_utf8 (fp, s, m_strlen(s));
2613     else
2614       parse_and_print_user_id (fp, s);
2615     putc ('\n', fp);
2616   }
2617
2618   if (key->subkeys && (key->subkeys->timestamp > 0)) {
2619     tt = key->subkeys->timestamp;
2620
2621     tm = localtime (&tt);
2622 #ifdef HAVE_LANGINFO_D_T_FMT
2623     strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2624 #else
2625     strftime (shortbuf, sizeof shortbuf, "%c", tm);
2626 #endif
2627     fprintf (fp, _("Valid From : %s\n"), shortbuf);
2628   }
2629
2630   if (key->subkeys && (key->subkeys->expires > 0)) {
2631     tt = key->subkeys->expires;
2632
2633     tm = localtime (&tt);
2634 #ifdef HAVE_LANGINFO_D_T_FMT
2635     strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2636 #else
2637     strftime (shortbuf, sizeof shortbuf, "%c", tm);
2638 #endif
2639     fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2640   }
2641
2642   if (key->subkeys)
2643     s = gpgme_pubkey_algo_name (key->subkeys->pubkey_algo);
2644   else
2645     s = "?";
2646
2647   s2 = is_pgp ? "PGP" : "X.509";
2648
2649   if (key->subkeys)
2650     aval = key->subkeys->length;
2651
2652   fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), s2, aval, s);
2653
2654   fprintf (fp, _("Key Usage .: "));
2655   delim = "";
2656
2657   if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT)) {
2658     fprintf (fp, "%s%s", delim, _("encryption"));
2659     delim = _(", ");
2660   }
2661   if (key_check_cap (key, KEY_CAP_CAN_SIGN)) {
2662     fprintf (fp, "%s%s", delim, _("signing"));
2663     delim = _(", ");
2664   }
2665   if (key_check_cap (key, KEY_CAP_CAN_CERTIFY)) {
2666     fprintf (fp, "%s%s", delim, _("certification"));
2667     delim = _(", ");
2668   }
2669   putc ('\n', fp);
2670
2671   if (key->subkeys) {
2672     s = key->subkeys->fpr;
2673     fputs (_("Fingerprint: "), fp);
2674     if (is_pgp && m_strlen(s) == 40) {
2675       for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
2676         putc (*s, fp);
2677         putc (s[1], fp);
2678         putc (s[2], fp);
2679         putc (s[3], fp);
2680         putc (is_pgp ? ' ' : ':', fp);
2681         if (is_pgp && i == 4)
2682           putc (' ', fp);
2683       }
2684     }
2685     else {
2686       for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
2687         putc (*s, fp);
2688         putc (s[1], fp);
2689         putc (is_pgp ? ' ' : ':', fp);
2690         if (is_pgp && i == 7)
2691           putc (' ', fp);
2692       }
2693     }
2694     fprintf (fp, "%s\n", s);
2695   }
2696
2697   if (key->issuer_serial) {
2698     s = key->issuer_serial;
2699     if (s)
2700       fprintf (fp, _("Serial-No .: 0x%s\n"), s);
2701   }
2702
2703   if (key->issuer_name) {
2704     s = key->issuer_name;
2705     if (s) {
2706       fprintf (fp, _("Issued By .: "));
2707       parse_and_print_user_id (fp, s);
2708       putc ('\n', fp);
2709     }
2710   }
2711
2712   /* For PGP we list all subkeys. */
2713   if (is_pgp) {
2714     gpgme_subkey_t subkey = NULL;
2715
2716     for (idx = 1, subkey = key->subkeys; subkey; idx++, subkey = subkey->next) {
2717       s = subkey->keyid;
2718
2719       putc ('\n', fp);
2720       if (m_strlen(s) == 16)
2721         s += 8;                 /* display only the short keyID */
2722       fprintf (fp, _("Subkey ....: 0x%s"), s);
2723       if (subkey->revoked) {
2724         putc (' ', fp);
2725         fputs (_("[Revoked]"), fp);
2726       }
2727       if (subkey->invalid) {
2728         putc (' ', fp);
2729         fputs (_("[Invalid]"), fp);
2730       }
2731       if (subkey->expired) {
2732         putc (' ', fp);
2733         fputs (_("[Expired]"), fp);
2734       }
2735       if (subkey->disabled) {
2736         putc (' ', fp);
2737         fputs (_("[Disabled]"), fp);
2738       }
2739       putc ('\n', fp);
2740
2741       if (subkey->timestamp > 0) {
2742         tt = subkey->timestamp;
2743
2744         tm = localtime (&tt);
2745 #ifdef HAVE_LANGINFO_D_T_FMT
2746         strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2747 #else
2748         strftime (shortbuf, sizeof shortbuf, "%c", tm);
2749 #endif
2750         fprintf (fp, _("Valid From : %s\n"), shortbuf);
2751       }
2752
2753       if (subkey->expires > 0) {
2754         tt = subkey->expires;
2755
2756         tm = localtime (&tt);
2757 #ifdef HAVE_LANGINFO_D_T_FMT
2758         strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2759 #else
2760         strftime (shortbuf, sizeof shortbuf, "%c", tm);
2761 #endif
2762         fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2763       }
2764
2765       if (subkey)
2766         s = gpgme_pubkey_algo_name (subkey->pubkey_algo);
2767       else
2768         s = "?";
2769
2770       if (subkey)
2771         aval = subkey->length;
2772       else
2773         aval = 0;
2774
2775       fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), "PGP", aval, s);
2776
2777       fprintf (fp, _("Key Usage .: "));
2778       delim = "";
2779
2780       if (subkey->can_encrypt) {
2781         fprintf (fp, "%s%s", delim, _("encryption"));
2782         delim = _(", ");
2783       }
2784       if (subkey->can_sign) {
2785         fprintf (fp, "%s%s", delim, _("signing"));
2786         delim = _(", ");
2787       }
2788       if (subkey->can_certify) {
2789         fprintf (fp, "%s%s", delim, _("certification"));
2790         delim = _(", ");
2791       }
2792       putc ('\n', fp);
2793     }
2794   }
2795
2796   if (Locale)
2797     setlocale (LC_TIME, "C");
2798 }
2799
2800
2801 /* Show detailed information about the selected key */
2802 static void verify_key (cryptkey_t * key)
2803 {
2804   FILE *fp;
2805   char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
2806   const char *s;
2807   gpgme_ctx_t listctx = NULL;
2808   gpgme_error_t err;
2809   gpgme_key_t k = NULL;
2810   int maxdepth = 100;
2811
2812   fp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
2813   if (!fp) {
2814     mutt_perror (_("Can't create temporary file"));
2815     return;
2816   }
2817   mutt_message _("Collecting data...");
2818
2819   print_key_info (key->kobj, fp);
2820
2821   err = gpgme_new (&listctx);
2822   if (err) {
2823     fprintf (fp, "Internal error: can't create gpgme context: %s\n",
2824              gpgme_strerror (err));
2825     goto leave;
2826   }
2827   if ((key->flags & KEYFLAG_ISX509))
2828     gpgme_set_protocol (listctx, GPGME_PROTOCOL_CMS);
2829
2830   k = key->kobj;
2831   gpgme_key_ref (k);
2832   while ((s = k->chain_id) && k->subkeys && m_strcmp(s, k->subkeys->fpr)) {
2833     putc ('\n', fp);
2834     err = gpgme_op_keylist_start (listctx, s, 0);
2835     gpgme_key_unref(k);
2836     k = NULL;
2837     if (!err)
2838       err = gpgme_op_keylist_next (listctx, &k);
2839     if (err) {
2840       fprintf (fp, _("Error finding issuer key: %s\n"), gpgme_strerror (err));
2841       goto leave;
2842     }
2843     gpgme_op_keylist_end (listctx);
2844
2845     print_key_info (k, fp);
2846     if (!--maxdepth) {
2847       putc ('\n', fp);
2848       fputs (_("Error: certification chain to long - stopping here\n"), fp);
2849       break;
2850     }
2851   }
2852
2853 leave:
2854   gpgme_key_unref(k);
2855   gpgme_release (listctx);
2856   m_fclose(&fp);
2857   mutt_clear_error ();
2858   snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), crypt_keyid (key));
2859   mutt_do_pager (cmd, tempfile, 0, NULL);
2860 }
2861
2862 /* Implementation of `findkeys'. */
2863
2864 static void add_hints(string_array *arr, const char *s)
2865 {
2866     if (!s)
2867         return;
2868
2869     while (*s) {
2870         int l = strcspn(s, " ,.:\"()<>\n");
2871         string_array_append(arr, p_dupstr(s, l));
2872         s += l;
2873         s += strspn(s, " ,.:\"()<>\n");
2874     }
2875 }
2876
2877 /* Return a list of keys which are candidates for the selection. */
2878 static cryptkey_t *
2879 get_candidates(string_array *hints, unsigned int app, int secret)
2880 {
2881     cryptkey_t  *res = NULL, **kend = &res;
2882     gpgme_error_t err;
2883     gpgme_ctx_t   ctx;
2884     gpgme_key_t   key;
2885
2886     if (hints->len <= 0)
2887         return NULL;
2888     string_array_append(hints, NULL);
2889     ctx = create_gpgme_context(0);
2890
2891     if ((app & APPLICATION_PGP)) {
2892         err = gpgme_op_keylist_ext_start(ctx, (const char **)hints->arr,
2893                                          secret, 0);
2894         if (err) {
2895             mutt_error(_("gpgme_op_keylist_start failed: %s"),
2896                        gpgme_strerror(err));
2897             gpgme_release(ctx);
2898             return NULL;
2899         }
2900
2901         while (!(err = gpgme_op_keylist_next(ctx, &key))) {
2902             gpgme_user_id_t uid = NULL;
2903             unsigned int flags = 0;
2904             int idx;
2905
2906             if (key_check_cap(key, KEY_CAP_CAN_ENCRYPT))
2907                 flags |= KEYFLAG_CANENCRYPT;
2908             if (key_check_cap(key, KEY_CAP_CAN_SIGN))
2909                 flags |= KEYFLAG_CANSIGN;
2910
2911             for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
2912                 cryptkey_t *k = p_new(cryptkey_t, 1);
2913                 k->kobj = key;
2914                 k->idx = idx;
2915                 k->uid = uid->uid;
2916                 k->flags = flags;
2917                 *kend = k;
2918                 kend = &k->next;
2919             }
2920         }
2921         if (gpg_err_code(err) != GPG_ERR_EOF)
2922             mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
2923         gpgme_op_keylist_end(ctx);
2924     }
2925
2926     if ((app & APPLICATION_SMIME)) {
2927         gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS);
2928         err = gpgme_op_keylist_ext_start(ctx, (const char **)hints->arr,
2929                                          secret, 0);
2930         if (err) {
2931             mutt_error(_("gpgme_op_keylist_start failed: %s"),
2932                        gpgme_strerror(err));
2933             gpgme_release(ctx);
2934             return NULL;
2935         }
2936
2937         while (!(err = gpgme_op_keylist_next(ctx, &key))) {
2938             gpgme_user_id_t uid = NULL;
2939             unsigned int flags = KEYFLAG_ISX509;
2940             int idx;
2941
2942             if (key_check_cap(key, KEY_CAP_CAN_ENCRYPT))
2943                 flags |= KEYFLAG_CANENCRYPT;
2944             if (key_check_cap(key, KEY_CAP_CAN_SIGN))
2945                 flags |= KEYFLAG_CANSIGN;
2946
2947             for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
2948                 cryptkey_t *k = p_new(cryptkey_t, 1);
2949                 k->kobj = key;
2950                 k->idx = idx;
2951                 k->uid = uid->uid;
2952                 k->flags = flags;
2953                 *kend = k;
2954                 kend = &k->next;
2955             }
2956         }
2957         if (gpg_err_code(err) != GPG_ERR_EOF)
2958             mutt_error(_("gpgme_op_keylist_next failed: %s"),
2959                        gpgme_strerror(err));
2960         gpgme_op_keylist_end(ctx);
2961     }
2962
2963     gpgme_release(ctx);
2964     return res;
2965 }
2966
2967 /* Display a menu to select a key from the array KEYS. FORCED_VALID
2968    will be set to true on return if the user did override the the
2969    key's validity. */
2970 static cryptkey_t *crypt_select_key (cryptkey_t * keys,
2971                                       address_t * p, const char *s,
2972                                       unsigned int app, int *forced_valid)
2973 {
2974   int keymax;
2975   cryptkey_t **cryptkey_table;
2976   MUTTMENU *menu;
2977   int i, done = 0;
2978   char helpstr[STRING], buf[LONG_STRING];
2979   cryptkey_t *k;
2980   int (*f) (const void *, const void *);
2981   int menu_to_use = 0;
2982   int unusable = 0;
2983
2984   *forced_valid = 0;
2985
2986   /* build the key table */
2987   keymax = i = 0;
2988   cryptkey_table = NULL;
2989   for (k = keys; k; k = k->next) {
2990       if (!option (OPTPGPSHOWUNUSABLE) && (k->flags & KEYFLAG_CANTUSE)) {
2991           unusable = 1;
2992           continue;
2993       }
2994
2995       if (i == keymax) {
2996           keymax += 20;
2997           p_realloc(&cryptkey_table, keymax);
2998       }
2999
3000       cryptkey_table[i++] = k;
3001   }
3002
3003   if (!i && unusable) {
3004       mutt_error _("All matching keys are marked expired/revoked.");
3005
3006       mutt_sleep (1);
3007       return NULL;
3008   }
3009
3010   switch (PgpSortKeys & SORT_MASK) {
3011     case SORT_DATE:
3012       f = crypt_compare_date;
3013       break;
3014     case SORT_KEYID:
3015       f = crypt_compare_keyid;
3016       break;
3017     case SORT_ADDRESS:
3018       f = crypt_compare_address;
3019       break;
3020     case SORT_TRUST:
3021     default:
3022       f = crypt_compare_trust;
3023       break;
3024   }
3025   qsort (cryptkey_table, i, sizeof (cryptkey_t *), f);
3026
3027   if (app & APPLICATION_PGP)
3028       menu_to_use = MENU_KEY_SELECT_PGP;
3029   else if (app & APPLICATION_SMIME)
3030       menu_to_use = MENU_KEY_SELECT_SMIME;
3031
3032   helpstr[0] = 0;
3033   mutt_make_help (buf, sizeof (buf), _("Exit  "), menu_to_use, OP_EXIT);
3034   m_strcat(helpstr, sizeof(helpstr), buf);
3035   mutt_make_help (buf, sizeof (buf), _("Select  "), menu_to_use,
3036                   OP_GENERIC_SELECT_ENTRY);
3037   m_strcat(helpstr, sizeof(helpstr), buf);
3038   mutt_make_help (buf, sizeof (buf), _("Check key  "),
3039                   menu_to_use, OP_VERIFY_KEY);
3040   m_strcat(helpstr, sizeof(helpstr), buf);
3041   mutt_make_help (buf, sizeof (buf), _("Help"), menu_to_use, OP_HELP);
3042   m_strcat(helpstr, sizeof(helpstr), buf);
3043
3044   menu = mutt_new_menu ();
3045   menu->max = i;
3046   menu->make_entry = crypt_entry;
3047   menu->menu = menu_to_use;
3048   menu->help = helpstr;
3049   menu->data = cryptkey_table;
3050
3051   {
3052       const char *ts;
3053
3054       if ((app & APPLICATION_PGP) && (app & APPLICATION_SMIME))
3055           ts = _("PGP and S/MIME keys matching");
3056       else if ((app & APPLICATION_PGP))
3057           ts = _("PGP keys matching");
3058       else if ((app & APPLICATION_SMIME))
3059           ts = _("S/MIME keys matching");
3060       else
3061           ts = _("keys matching");
3062
3063       if (p)
3064           snprintf (buf, sizeof (buf), _("%s <%s>."), ts, p->mailbox);
3065       else
3066           snprintf (buf, sizeof (buf), _("%s \"%s\"."), ts, s);
3067       menu->title = buf;
3068   }
3069
3070   mutt_clear_error ();
3071   k = NULL;
3072   while (!done) {
3073       *forced_valid = 0;
3074       switch (mutt_menuLoop (menu)) {
3075         case OP_VERIFY_KEY:
3076           verify_key (cryptkey_table[menu->current]);
3077           menu->redraw = REDRAW_FULL;
3078           break;
3079
3080         case OP_VIEW_ID:
3081           mutt_message ("%s", cryptkey_table[menu->current]->uid);
3082           break;
3083
3084         case OP_GENERIC_SELECT_ENTRY:
3085           /* FIXME make error reporting more verbose - this should be
3086              easy because gpgme provides more information */
3087           if (option (OPTPGPCHECKTRUST)) {
3088               if (cryptkey_table[menu->current]->flags & KEYFLAG_CANTUSE ) {
3089                   mutt_error(_("This key can't be used: "
3090                                "expired/disabled/revoked."));
3091                   break;
3092               }
3093           }
3094
3095           if (option (OPTPGPCHECKTRUST) &&
3096               ((cryptkey_table[menu->current]->flags & KEYFLAG_CANTUSE)
3097                || !crypt_id_is_strong (cryptkey_table[menu->current]))) {
3098               const char *warn_s;
3099               char buff[LONG_STRING];
3100
3101               if (cryptkey_table[menu->current]->flags & KEYFLAG_CANTUSE)
3102                   s = N_("ID is expired/disabled/revoked.");
3103               else {
3104                   gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
3105                   gpgme_user_id_t uid = NULL;
3106                   int j = 0;
3107
3108                   warn_s = "??";
3109
3110                   uid = cryptkey_table[menu->current]->kobj->uids;
3111                   for (j = 0; (j < cryptkey_table[menu->current]->idx) && uid;
3112                        j++, uid = uid->next);
3113                   if (uid)
3114                       val = uid->validity;
3115
3116                   switch (val) {
3117                     case GPGME_VALIDITY_UNKNOWN:
3118                     case GPGME_VALIDITY_UNDEFINED:
3119                       warn_s = N_("ID has undefined validity.");
3120                       break;
3121                     case GPGME_VALIDITY_NEVER:
3122                       warn_s = N_("ID is not valid.");
3123                       break;
3124                     case GPGME_VALIDITY_MARGINAL:
3125                       warn_s = N_("ID is only marginally valid.");
3126                       break;
3127                     case GPGME_VALIDITY_FULL:
3128                     case GPGME_VALIDITY_ULTIMATE:
3129                       break;
3130                   }
3131
3132                   snprintf (buff, sizeof (buff),
3133                             _("%s Do you really want to use the key?"), _(warn_s));
3134
3135                   if (mutt_yesorno (buff, 0) != 1) {
3136                       mutt_clear_error ();
3137                       break;
3138                   }
3139                   *forced_valid = 1;
3140               }
3141           }
3142
3143           k = cryptkey_dup(cryptkey_table[menu->current]);
3144           done = 1;
3145           break;
3146
3147         case OP_EXIT:
3148           k = NULL;
3149           done = 1;
3150           break;
3151       }
3152   }
3153
3154   mutt_menuDestroy (&menu);
3155   p_delete(&cryptkey_table);
3156
3157   set_option (OPTNEEDREDRAW);
3158
3159   return k;
3160 }
3161
3162 static cryptkey_t *crypt_getkeybyaddr (address_t * a, short abilities,
3163                                         unsigned int app, int *forced_valid)
3164 {
3165     address_t *r, *p;
3166
3167     int weak = 0;
3168     int invalid = 0;
3169     int multi = 0;
3170     int this_key_has_strong;
3171     int this_key_has_weak;
3172     int this_key_has_invalid;
3173     int match;
3174
3175     cryptkey_t *keys, *k;
3176     cryptkey_t *the_valid_key = NULL;
3177     cryptkey_t *matches = NULL;
3178     cryptkey_t **matches_endp = &matches;
3179
3180     *forced_valid = 0;
3181
3182     {
3183         string_array hints;
3184         string_array_init(&hints); 
3185         add_hints(&hints, a->mailbox);
3186         add_hints(&hints, a->personal);
3187
3188         mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
3189         keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3190         string_array_wipe(&hints);
3191     }
3192
3193     if (!keys)
3194         return NULL;
3195
3196     for (k = keys; k; k = k->next) {
3197         if (abilities && !(k->flags & abilities)) {
3198             continue;
3199         }
3200
3201         this_key_has_weak = 0;      /* weak but valid match   */
3202         this_key_has_invalid = 0;   /* invalid match          */
3203         this_key_has_strong = 0;    /* strong and valid match */
3204         match = 0;                  /* any match            */
3205
3206         r = rfc822_parse_adrlist (NULL, k->uid);
3207         for (p = r; p; p = p->next) {
3208             int validity = crypt_id_matches_addr (a, p, k);
3209
3210             if (validity & CRYPT_KV_MATCH)    /* something matches */
3211                 match = 1;
3212
3213             /* is this key a strong candidate? */
3214             if ((validity & CRYPT_KV_VALID)
3215                 && (validity & CRYPT_KV_STRONGID)
3216                 && (validity & CRYPT_KV_ADDR)) {
3217                 if (the_valid_key && the_valid_key != k)
3218                     multi = 1;
3219                 the_valid_key = k;
3220                 this_key_has_strong = 1;
3221             }
3222             else if ((validity & CRYPT_KV_MATCH)
3223                      && !(validity & CRYPT_KV_VALID))
3224                 this_key_has_invalid = 1;
3225             else if ((validity & CRYPT_KV_MATCH)
3226                      && (!(validity & CRYPT_KV_STRONGID)
3227                          || !(validity & CRYPT_KV_ADDR)))
3228                 this_key_has_weak = 1;
3229         }
3230         address_list_wipe(&r);
3231
3232         if (match) {
3233             cryptkey_t *tmp;
3234
3235             if (!this_key_has_strong && this_key_has_invalid)
3236                 invalid = 1;
3237             if (!this_key_has_strong && this_key_has_weak)
3238                 weak = 1;
3239
3240             *matches_endp = tmp = cryptkey_dup(k);
3241             matches_endp = &tmp->next;
3242             the_valid_key = tmp;
3243         }
3244     }
3245     key_list_wipe(&keys);
3246
3247     if (matches) {
3248         if (the_valid_key && !multi && !weak
3249             && !(invalid && option (OPTPGPSHOWUNUSABLE))) {
3250       /*
3251        * There was precisely one strong match on a valid ID, there
3252        * were no valid keys with weak matches, and we aren't
3253        * interested in seeing invalid keys.
3254        *
3255        * Proceed without asking the user.
3256        */
3257       k = cryptkey_dup(the_valid_key);
3258     } else {
3259       /*
3260        * Else: Ask the user.
3261        */
3262       k = crypt_select_key (matches, a, NULL, app, forced_valid);
3263     }
3264     key_list_wipe(&matches);
3265   } else {
3266     k = NULL;
3267   }
3268
3269   return k;
3270 }
3271
3272
3273 static cryptkey_t *crypt_getkeybystr (const char *p, short abilities,
3274                                        unsigned int app, int *forced_valid)
3275 {
3276   cryptkey_t *keys;
3277   cryptkey_t *matches = NULL;
3278   cryptkey_t **matches_endp = &matches;
3279   cryptkey_t *k;
3280   int match;
3281
3282   mutt_message (_("Looking for keys matching \"%s\"..."), p);
3283
3284   *forced_valid = 0;
3285
3286   {
3287       string_array hints;
3288       string_array_init(&hints);
3289       add_hints(&hints, p);
3290       keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3291       string_array_wipe(&hints);
3292   }
3293
3294   if (!keys)
3295     return NULL;
3296
3297   for (k = keys; k; k = k->next) {
3298     const char *s = crypt_keyid(k);
3299
3300     if (abilities && !(k->flags & abilities))
3301       continue;
3302
3303     match = 0;
3304
3305     if (!*p || !m_strcasecmp(p, s)
3306         || (!m_strncasecmp(p, "0x", 2) && !m_strcasecmp(p + 2, s))
3307         || m_stristr(k->uid, p))
3308     {
3309       cryptkey_t *tmp;
3310
3311       *matches_endp = tmp = cryptkey_dup(k);
3312       matches_endp = &tmp->next;
3313     }
3314   }
3315   key_list_wipe(&keys);
3316
3317   if (matches) {
3318     k = crypt_select_key (matches, NULL, p, app, forced_valid);
3319     key_list_wipe(&matches);
3320     return k;
3321   }
3322
3323   return NULL;
3324 }
3325
3326 /* Display TAG as a prompt to ask for a key.
3327  * ABILITIES describe the required key abilities (sign, encrypt) and APP the
3328  * type of the requested key; ether S/MIME or PGP.
3329  * Return a copy of the key or NULL if not found. */
3330 static cryptkey_t *
3331 crypt_ask_for_key(const char *tag, int abilities, int app, int *forced_valid)
3332 {
3333     cryptkey_t *key;
3334     char resp[STRING];
3335     int dummy;
3336
3337     if (!forced_valid)
3338         forced_valid = &dummy;
3339     *forced_valid = 0;
3340
3341     mutt_clear_error();
3342     for (;;) {
3343         resp[0] = 0;
3344         if (mutt_get_field(tag, resp, sizeof(resp), M_CLEAR) != 0)
3345             return NULL;
3346
3347         if (m_strisempty(resp))
3348             return NULL;
3349
3350         if ((key = crypt_getkeybystr(resp, abilities, app, forced_valid)))
3351             return key;
3352
3353         BEEP ();
3354     }
3355 }
3356
3357 /* This routine attempts to find the keyids of the recipients of a
3358    message.  It returns NULL if any of the keys can not be found.  */
3359 static char *find_keys(ENVELOPE *env, unsigned int app)
3360 {
3361     address_t *lst = NULL, *addr;
3362     buffer_t *keylist = buffer_new();
3363
3364     {
3365         address_t **last = &lst;
3366         *last = address_list_dup(env->to);
3367         last  = address_list_last(last);
3368         *last = address_list_dup(env->cc);
3369         last  = address_list_last(last);
3370         *last = address_list_dup(env->bcc);
3371
3372         rfc822_qualify(lst, mutt_fqdn(1));
3373         address_list_uniq(lst);
3374     }
3375
3376     while ((addr = address_list_pop(&lst))) {
3377         char buf[STRING];
3378         int forced_valid = 0;
3379         const char *keyID;
3380         cryptkey_t *key = NULL;
3381
3382         if ((keyID = mutt_crypt_hook(addr))) {
3383             int r;
3384
3385             snprintf(buf, sizeof(buf), _("Use keyID = \"%s\" for %s?"), keyID,
3386                      addr->mailbox);
3387             r = mutt_yesorno(buf, M_YES);
3388
3389             if (r == -1) {
3390                 address_list_wipe(&lst);
3391                 address_list_wipe(&addr);
3392                 buffer_delete(&keylist);
3393                 return NULL;
3394             }
3395
3396             if (r == M_YES) {
3397                 address_t *a;
3398                 /* check for e-mail address */
3399                 if (strchr(keyID, '@') && (a = rfc822_parse_adrlist(NULL, keyID))) {
3400                     rfc822_qualify(a, mutt_fqdn(1));
3401                     address_list_wipe(&addr);
3402                     addr = a;
3403                 } else {
3404                     key = crypt_getkeybystr(keyID, KEYFLAG_CANENCRYPT, app,
3405                                             &forced_valid);
3406                 }
3407             }
3408         }
3409
3410         if (!key) {
3411             key = crypt_getkeybyaddr(addr, KEYFLAG_CANENCRYPT, app, &forced_valid);
3412         }
3413         if (!key) {
3414             snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), addr->mailbox);
3415             key = crypt_ask_for_key(buf, KEYFLAG_CANENCRYPT, app,
3416                                     &forced_valid);
3417             if (!key) {
3418                 address_list_wipe(&lst);
3419                 address_list_wipe(&addr);
3420                 buffer_delete(&keylist);
3421                 return NULL;
3422             }
3423         }
3424
3425         if (keylist->len)
3426             buffer_addch(keylist, ' ');
3427         buffer_addstr(keylist, "0x");
3428         buffer_addstr(keylist, crypt_fpr(key));
3429         if (forced_valid)
3430             buffer_addch(keylist, '!');
3431
3432         key_list_wipe(&key);
3433         address_list_wipe(&addr);
3434     }
3435
3436     address_list_wipe(&lst);
3437     return buffer_unwrap(&keylist);
3438 }
3439
3440 int crypt_get_keys(HEADER *msg, char **keylist)
3441 {
3442     /* Do a quick check to make sure that we can find all of the encryption
3443      * keys if the user has requested this service.
3444      */
3445
3446     *keylist = NULL;
3447
3448     if (msg->security & ENCRYPT) {
3449         if (msg->security & APPLICATION_PGP) {
3450             set_option(OPTPGPCHECKTRUST);
3451             *keylist = find_keys(msg->env, APPLICATION_PGP);
3452             unset_option(OPTPGPCHECKTRUST);
3453             if (!*keylist)
3454                 return -1;
3455         }
3456
3457         if (msg->security & APPLICATION_SMIME) {
3458             *keylist = find_keys(msg->env, APPLICATION_SMIME);
3459             if (!*keylist)
3460                 return -1;
3461         }
3462     }
3463
3464     return 0;
3465 }
3466
3467
3468 int crypt_send_menu (HEADER * msg, int *redraw, int is_smime)
3469 {
3470     cryptkey_t *p;
3471     char buf[STRING];
3472     int choice;
3473
3474     if (msg->security & APPLICATION_SMIME)
3475         is_smime = 1;
3476     if (msg->security & APPLICATION_PGP)
3477         is_smime = 0;
3478
3479     choice = is_smime
3480         ? mutt_multi_choice(_("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?"),
3481                             _("esabpc"))
3482         : mutt_multi_choice(_("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?"),
3483                             _("esabmc"));
3484
3485     switch (choice) {
3486       case 1:                      /* (e)ncrypt */
3487         msg->security |= (is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3488         msg->security &= ~(is_smime ? SMIMESIGN : PGPSIGN);
3489         break;
3490
3491       case 2:                      /* (s)ign */
3492         msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3493         msg->security &= ~(is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3494         break;
3495
3496       case 3:                      /* sign (a)s */
3497         p = crypt_ask_for_key(_("Sign as: "), KEYFLAG_CANSIGN,
3498                               is_smime ?  APPLICATION_SMIME : APPLICATION_PGP,
3499                               NULL);
3500         if (p) {
3501             snprintf(buf, sizeof(buf), "0x%s", crypt_keyid(p));
3502             m_strreplace(is_smime ? &SmimeDefaultKey : &PgpSignAs, buf);
3503             key_list_wipe(&p);
3504             msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3505         }
3506         *redraw = REDRAW_FULL;
3507         break;
3508
3509       case 4:                      /* (b)oth */
3510         if (is_smime) {
3511             msg->security = SMIMEENCRYPT | SMIMESIGN;
3512         } else {
3513             msg->security = PGPENCRYPT | PGPSIGN;
3514         }
3515         break;
3516
3517       case 5:                      /* (p)gp or s/(m)ime */
3518         is_smime = !is_smime;
3519         break;
3520
3521       case 6:                      /* (c)lear */
3522         return msg->security = 0;
3523     }
3524
3525     if (is_smime) {
3526         msg->security &= ~APPLICATION_PGP;
3527         msg->security |= APPLICATION_SMIME;
3528     } else {
3529         msg->security &= ~APPLICATION_SMIME;
3530         msg->security |= APPLICATION_PGP;
3531     }
3532
3533     return msg->security;
3534 }
3535
3536 int crypt_smime_verify_sender(HEADER *h)
3537 {
3538     address_t *sender = NULL;
3539     unsigned int ret = 1;
3540
3541     if (h->env->from) {
3542         h->env->from = mutt_expand_aliases(h->env->from);
3543         sender = h->env->from;
3544     } else if (h->env->sender) {
3545         h->env->sender = mutt_expand_aliases (h->env->sender);
3546         sender = h->env->sender;
3547     }
3548
3549     if (!sender) {
3550         mutt_any_key_to_continue ("Failed to figure out sender");
3551         goto end;
3552     }
3553
3554     if (signature_key) {
3555         gpgme_key_t key = signature_key;
3556         gpgme_user_id_t uid = NULL;
3557         int sender_length = 0;
3558         int uid_length = 0;
3559
3560         sender_length = m_strlen(sender->mailbox);
3561         for (uid = key->uids; uid && ret; uid = uid->next) {
3562             uid_length = m_strlen(uid->email);
3563             if (1 && (uid->email[0] == '<')
3564                 && (uid->email[uid_length - 1] == '>')
3565                 && (uid_length == sender_length + 2)
3566                 && (!m_strncmp (uid->email + 1, sender->mailbox, sender_length)))
3567                 ret = 0;
3568         }
3569     } else {
3570         mutt_any_key_to_continue ("Failed to verify sender");
3571     }
3572
3573   end:
3574     if (signature_key) {
3575         gpgme_key_unref(signature_key);
3576         signature_key = NULL;
3577     }
3578     return ret;
3579 }
3580
3581 static void crypt_invoke_import(FILE *stream, int smime)
3582 {
3583     gpgme_ctx_t ctx = create_gpgme_context(smime);
3584     gpgme_data_t data;
3585     gpgme_error_t err;
3586
3587     err = gpgme_data_new_from_stream(&data, stream);
3588     if (err) {
3589         mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
3590         gpgme_release(ctx);
3591         return;
3592     }
3593
3594     err = gpgme_op_import(ctx, data);
3595     if (err) {
3596         mutt_error(_("error importing gpg data: %s\n"), gpgme_strerror(err));
3597         gpgme_data_release(data);
3598         gpgme_release(ctx);
3599         return;
3600     }
3601
3602     gpgme_data_release(data);
3603     gpgme_release(ctx);
3604     return;
3605 }
3606
3607 static void pgp_extract_keys_from_attachment(FILE * fp, BODY * top)
3608 {
3609     STATE s;
3610     FILE *tmpfp = tmpfile();
3611
3612     if (tmpfp == NULL) {
3613         mutt_perror (_("Can't create temporary file"));
3614         return;
3615     }
3616
3617     p_clear(&s, 1);
3618     s.fpin  = fp;
3619     s.fpout = tmpfp;
3620     mutt_body_handler(top, &s);
3621
3622     rewind(tmpfp);
3623     crypt_invoke_import(tmpfp, 0);
3624     m_fclose(&tmpfp);
3625 }
3626
3627 void crypt_pgp_extract_keys_from_attachment_list(FILE * fp, int tag, BODY * top)
3628 {
3629   mutt_endwin (NULL);
3630   set_option (OPTDONTHANDLEPGPKEYS);
3631
3632   for (; top; top = top->next) {
3633     if (!tag || top->tagged)
3634       pgp_extract_keys_from_attachment (fp, top);
3635
3636     if (!tag)
3637       break;
3638   }
3639
3640   unset_option (OPTDONTHANDLEPGPKEYS);
3641 }
3642
3643 void crypt_invoke_message (int type)
3644 {
3645     if (type & APPLICATION_PGP) {
3646         mutt_message _("Invoking PGP...");
3647     }
3648     else if (type & APPLICATION_SMIME) {
3649         mutt_message _("Invoking S/MIME...");
3650     }
3651 }
3652
3653 int mutt_protect (HEADER * msg, char *keylist)
3654 {
3655   BODY *pbody = NULL, *tmp_pbody = NULL;
3656   BODY *tmp_smime_pbody = NULL;
3657   BODY *tmp_pgp_pbody = NULL;
3658   int flags = msg->security;
3659
3660   if (!isendwin ())
3661     mutt_endwin (NULL);
3662
3663   tmp_smime_pbody = msg->content;
3664   tmp_pgp_pbody = msg->content;
3665
3666   if (msg->security & SIGN) {
3667     if (msg->security & APPLICATION_SMIME) {
3668       if (!(tmp_pbody = sign_message(msg->content, 1)))
3669         return -1;
3670       pbody = tmp_smime_pbody = tmp_pbody;
3671     }
3672
3673     if ((msg->security & APPLICATION_PGP)
3674         && (!(flags & ENCRYPT) || option (OPTPGPRETAINABLESIG))) {
3675       if (!(tmp_pbody = sign_message(msg->content, 0)))
3676         return -1;
3677
3678       flags &= ~SIGN;
3679       pbody = tmp_pgp_pbody = tmp_pbody;
3680     }
3681
3682     if ((msg->security & APPLICATION_SMIME)
3683         && (msg->security & APPLICATION_PGP)) {
3684       /* here comes the draft ;-) */
3685     }
3686   }
3687
3688
3689   if (msg->security & ENCRYPT) {
3690     if ((msg->security & APPLICATION_SMIME)) {
3691       if (!(tmp_pbody = crypt_smime_build_smime_entity (tmp_smime_pbody,
3692                                                         keylist))) {
3693         /* signed ? free it! */
3694         return (-1);
3695       }
3696       /* free tmp_body if messages was signed AND encrypted ... */
3697       if (tmp_smime_pbody != msg->content && tmp_smime_pbody != tmp_pbody) {
3698         /* detatch and dont't delete msg->content,
3699            which tmp_smime_pbody->parts after signing. */
3700         tmp_smime_pbody->parts = tmp_smime_pbody->parts->next;
3701         msg->content->next = NULL;
3702         body_list_wipe(&tmp_smime_pbody);
3703       }
3704       pbody = tmp_pbody;
3705     }
3706
3707     if ((msg->security & APPLICATION_PGP)) {
3708       if (!(pbody = crypt_pgp_encrypt_message (tmp_pgp_pbody, keylist,
3709                                                flags & SIGN))) {
3710
3711         /* did we perform a retainable signature? */
3712         if (flags != msg->security) {
3713           /* remove the outer multipart layer */
3714           tmp_pgp_pbody = mutt_remove_multipart (tmp_pgp_pbody);
3715           /* get rid of the signature */
3716           body_list_wipe(&tmp_pgp_pbody->next);
3717         }
3718
3719         return (-1);
3720       }
3721
3722       /* destroy temporary signature envelope when doing retainable 
3723        * signatures.
3724
3725        */
3726       if (flags != msg->security) {
3727         tmp_pgp_pbody = mutt_remove_multipart (tmp_pgp_pbody);
3728         body_list_wipe(&tmp_pgp_pbody->next);
3729       }
3730     }
3731   }
3732
3733   if (pbody)
3734     msg->content = pbody;
3735
3736   return 0;
3737 }
3738
3739
3740 int crypt_query (BODY * m)
3741 {
3742   int t = 0;
3743
3744   if (!m)
3745     return 0;
3746
3747   if (m->type == TYPEAPPLICATION) {
3748     t |= mutt_is_application_pgp (m);
3749
3750     t |= mutt_is_application_smime (m);
3751     if (t && m->goodsig)
3752       t |= GOODSIGN;
3753     if (t && m->badsig)
3754       t |= BADSIGN;
3755   }
3756   else if (m->type == TYPETEXT) {
3757     t |= mutt_is_application_pgp (m);
3758     if (t && m->goodsig)
3759       t |= GOODSIGN;
3760   }
3761
3762   if (m->type == TYPEMULTIPART) {
3763     t |= mutt_is_multipart_encrypted (m);
3764     t |= mutt_is_multipart_signed (m);
3765
3766     if (t && m->goodsig)
3767       t |= GOODSIGN;
3768   }
3769
3770   if (m->type == TYPEMULTIPART || m->type == TYPEMESSAGE) {
3771     BODY *p;
3772     int u, v, w;
3773
3774     u = m->parts ? ~0 : 0;      /* Bits set in all parts */
3775     w = 0;                      /* Bits set in any part  */
3776
3777     for (p = m->parts; p; p = p->next) {
3778       v = crypt_query (p);
3779       u &= v;
3780       w |= v;
3781     }
3782     t |= u | (w & ~GOODSIGN);
3783
3784     if ((w & GOODSIGN) && !(u & GOODSIGN))
3785       t |= PARTSIGN;
3786   }
3787
3788   return t;
3789 }
3790
3791
3792 static void crypt_write_signed(BODY * a, STATE * s, FILE *fp)
3793 {
3794     int c;
3795     short hadcr;
3796     size_t bytes;
3797
3798     fseeko (s->fpin, a->hdr_offset, 0);
3799     bytes = a->length + a->offset - a->hdr_offset;
3800     hadcr = 0;
3801     while (bytes > 0) {
3802         if ((c = fgetc (s->fpin)) == EOF)
3803             break;
3804
3805         bytes--;
3806
3807         if (c == '\r')
3808             hadcr = 1;
3809         else {
3810             if (c == '\n' && !hadcr)
3811                 fputc ('\r', fp);
3812
3813             hadcr = 0;
3814         }
3815         fputc (c, fp);
3816     }
3817 }
3818
3819 static void extract_keys_aux(FILE *fpout, HEADER *h)
3820 {
3821     mutt_parse_mime_message (Context, h);
3822
3823     rewind(fpout);
3824     if (h->security & APPLICATION_PGP) {
3825         mutt_copy_message(fpout, Context, h, M_CM_DECODE | M_CM_CHARCONV, 0);
3826         fflush (fpout);
3827
3828         mutt_endwin (_("Trying to extract PGP keys...\n"));
3829     }
3830
3831     if (h->security & APPLICATION_SMIME) {
3832         if (h->security & ENCRYPT)
3833             mutt_copy_message (fpout, Context, h, M_CM_NOHEADER
3834                                | M_CM_DECODE_CRYPT | M_CM_DECODE_SMIME, 0);
3835         else
3836             mutt_copy_message(fpout, Context, h, 0, 0);
3837         fflush (fpout);
3838
3839         mutt_message (_("Trying to extract S/MIME certificates...\n"));
3840     }
3841
3842     rewind(fpout);
3843     crypt_invoke_import(fpout, h->security & APPLICATION_SMIME);
3844 }
3845
3846 void crypt_extract_keys_from_messages(HEADER * h)
3847 {
3848     FILE *tmpfp = tmpfile();
3849     if (!tmpfp) {
3850         mutt_error(_("Could not create temporary file"));
3851         return;
3852     }
3853
3854     set_option(OPTDONTHANDLEPGPKEYS);
3855     if (!h) {
3856         int i;
3857         for (i = 0; i < Context->vcount; i++) {
3858             if (!Context->hdrs[Context->v2r[i]]->tagged)
3859                 continue;
3860             extract_keys_aux(tmpfp, Context->hdrs[Context->v2r[i]]);
3861         }
3862     } else {
3863         extract_keys_aux(tmpfp, h);
3864     }
3865     unset_option(OPTDONTHANDLEPGPKEYS);
3866     m_fclose(&tmpfp);
3867
3868     if (isendwin())
3869         mutt_any_key_to_continue(NULL);
3870 }
3871
3872
3873
3874 static void crypt_fetch_signatures (BODY ***signatures, BODY * a, int *n)
3875 {
3876   for (; a; a = a->next) {
3877     if (a->type == TYPEMULTIPART)
3878       crypt_fetch_signatures (signatures, a->parts, n);
3879     else {
3880       if ((*n % 5) == 0)
3881         p_realloc(signatures, *n + 6);
3882
3883       (*signatures)[(*n)++] = a;
3884     }
3885   }
3886 }
3887
3888
3889 /*
3890  * This routine verifies a  "multipart/signed"  body.
3891  */
3892
3893 int mutt_signed_handler (BODY * a, STATE * s)
3894 {
3895   unsigned major, minor;
3896   char *protocol;
3897   int rc, i, goodsig = 1, sigcnt = 0;
3898   BODY *b = a;
3899
3900   protocol = parameter_getval(a->parameter, "protocol");
3901   a = a->parts;
3902
3903   switch (mime_which_token(protocol, -1)) {
3904     case MIME_APPLICATION_PGP_SIGNATURE:
3905       major = TYPEAPPLICATION;
3906       minor = MIME_PGP_SIGNATURE;
3907       break;
3908     case MIME_APPLICATION_X_PKCS7_SIGNATURE:
3909       major = TYPEAPPLICATION;
3910       minor = MIME_X_PKCS7_SIGNATURE;
3911       break;
3912     case MIME_APPLICATION_PKCS7_SIGNATURE:
3913       major = TYPEAPPLICATION;
3914       minor = MIME_PKCS7_SIGNATURE;
3915       break;
3916     case MIME_MULTIPART_MIXED:
3917       major = TYPEMULTIPART;
3918       minor = MIME_MIXED;
3919       break;
3920
3921     default:
3922       state_printf(s, _("[-- Error: "
3923                         "Unknown multipart/signed protocol %s! --]\n\n"),
3924                     protocol);
3925       return mutt_body_handler (a, s);
3926   }
3927
3928   /* consistency check */
3929   if (!(a && a->next && a->next->type == major &&
3930         mime_which_token(a->next->subtype, -1) == minor))
3931   {
3932     state_attach_puts(_("[-- Error: "
3933                         "Inconsistent multipart/signed structure! --]\n\n"),
3934                       s);
3935     return mutt_body_handler (a, s);
3936   }
3937
3938   if (s->flags & M_DISPLAY) {
3939     BODY **sigs = NULL;
3940
3941     crypt_fetch_signatures (&sigs, a->next, &sigcnt);
3942     if (sigcnt) {
3943       FILE *tmpfp = tmpfile();
3944
3945       if (!tmpfp) {
3946           mutt_error(_("Could not create temporary file"));
3947       } else {
3948         crypt_write_signed(a, s, tmpfp);
3949         rewind(tmpfp);
3950         for (i = 0; i < sigcnt; i++) {
3951           if (sigs[i]->type == TYPEAPPLICATION) {
3952             int subtype;
3953
3954             switch ((subtype = mime_which_token(sigs[i]->subtype, -1))) {
3955               case MIME_PGP_SIGNATURE:
3956               case MIME_X_PKCS7_SIGNATURE:
3957               case MIME_PKCS7_SIGNATURE:
3958                 if (crypt_verify_one(sigs[i], s, tmpfp, subtype != MIME_PGP_SIGNATURE) != 0)
3959                   goodsig = 0;
3960
3961                 m_fclose(&tmpfp);
3962                 continue;
3963
3964               default:
3965                 break;
3966             }
3967           }
3968
3969           state_printf(s, _("[-- Warning: "
3970                             "We can't verify %s/%s signatures. --]\n\n"),
3971                        TYPE (sigs[i]), sigs[i]->subtype);
3972         }
3973       }
3974
3975       b->goodsig = goodsig;
3976       b->badsig  = !goodsig;
3977
3978       /* Now display the signed body */
3979       state_attach_puts(_("[-- The following data is signed --]\n\n"), s);
3980
3981       p_delete(&sigs);
3982     } else {
3983       state_attach_puts(_("[-- Warning: Can't find any signatures. --]\n\n"),
3984                         s);
3985     }
3986   }
3987
3988   rc = mutt_body_handler (a, s);
3989
3990   if (s->flags & M_DISPLAY && sigcnt)
3991     state_attach_puts (_("\n[-- End of signed data --]\n"), s);
3992
3993   return (rc);
3994 }