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