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