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