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