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