Fix dereferencing for the mutt_hcache_close calls. Use hcache_t* instead of evil...
[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/lib-ui.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   if (err) {
1221     char buf[200];
1222
1223     snprintf (buf, sizeof (buf) - 1,
1224               _("Error: verification failed: %s\n"), gpgme_strerror (err));
1225     state_attach_puts (buf, s);
1226   }
1227   else {                        /* Verification succeeded, see what the result is. */
1228     int res, idx;
1229     int anybad = 0;
1230
1231     if (signature_key) {
1232       gpgme_key_unref(signature_key);
1233       signature_key = NULL;
1234     }
1235
1236     for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1237       if (res == 1)
1238         anybad = 1;
1239       else if (res == 2)
1240         anywarn = 2;
1241     }
1242     if (!anybad)
1243       badsig = 0;
1244   }
1245
1246   if (!badsig) {
1247     gpgme_verify_result_t result;
1248     gpgme_sig_notation_t notation;
1249     gpgme_signature_t sig;
1250
1251     result = gpgme_op_verify_result (ctx);
1252     if (result) {
1253       for (sig = result->signatures; sig; sig = sig->next) {
1254         if (sig->notations) {
1255           state_attach_puts ("*** Begin Notation (signature by: ", s);
1256           state_attach_puts (sig->fpr, s);
1257           state_attach_puts (") ***\n", s);
1258           for (notation = sig->notations; notation; notation = notation->next)
1259           {
1260             if (notation->name) {
1261               state_attach_puts (notation->name, s);
1262               state_attach_puts ("=", s);
1263             }
1264             if (notation->value) {
1265               state_attach_puts (notation->value, s);
1266               if (!(*notation->value
1267                     && (notation->value[m_strlen(notation->value) - 1] ==
1268                         '\n')))
1269                 state_attach_puts ("\n", s);
1270             }
1271           }
1272           state_attach_puts ("*** End Notation ***\n", s);
1273         }
1274       }
1275     }
1276   }
1277
1278   gpgme_release (ctx);
1279
1280   state_attach_puts (_("[-- End signature information --]\n\n"), s);
1281
1282   return badsig ? 1 : anywarn ? 2 : 0;
1283 }
1284
1285 /* Decrypt a PGP or SMIME message (depending on the boolean flag
1286    IS_SMIME) with body A described further by state S.  Write
1287    plaintext out to file FPOUT and return a new body.  For PGP returns
1288    a flag in R_IS_SIGNED to indicate whether this is a combined
1289    encrypted and signed message, for S/MIME it returns true when it is
1290    not a encrypted but a signed message.  */
1291 static BODY *
1292 decrypt_part(BODY *a, STATE *s, FILE *fpout, int is_smime, int *r_is_signed)
1293 {
1294   struct stat info;
1295   BODY *tattach;
1296   int err = 0;
1297   gpgme_ctx_t ctx;
1298   gpgme_data_t ciphertext, plaintext;
1299   int maybe_signed = 0;
1300   int anywarn = 0;
1301   int sig_stat = 0;
1302
1303   if (r_is_signed)
1304     *r_is_signed = 0;
1305
1306   ctx = create_gpgme_context (is_smime);
1307
1308 restart:
1309   /* Make a data object from the body, create context etc. */
1310   ciphertext = file_to_data_object (s->fpin, a->offset, a->length);
1311   if (!ciphertext)
1312     return NULL;
1313   plaintext = create_gpgme_data ();
1314
1315   /* Do the decryption or the verification in case of the S/MIME hack. */
1316   if ((!is_smime) || maybe_signed) {
1317     if (!is_smime)
1318       err = gpgme_op_decrypt_verify (ctx, ciphertext, plaintext);
1319     else if (maybe_signed)
1320       err = gpgme_op_verify (ctx, ciphertext, NULL, plaintext);
1321
1322     {
1323       /* Check wether signatures have been verified.  */
1324       gpgme_verify_result_t verify_result = gpgme_op_verify_result (ctx);
1325
1326       if (verify_result->signatures)
1327         sig_stat = 1;
1328     }
1329   }
1330   else
1331     err = gpgme_op_decrypt (ctx, ciphertext, plaintext);
1332   gpgme_data_release (ciphertext);
1333   if (err) {
1334     if (is_smime && !maybe_signed && gpg_err_code (err) == GPG_ERR_NO_DATA) {
1335       /* Check whether this might be a signed message despite what
1336          the mime header told us.  Retry then.  gpgsm returns the
1337          error information "unsupported Algorithm '?'" but gpgme
1338          will not store this unknown algorithm, thus we test that
1339          it has not been set. */
1340       gpgme_decrypt_result_t result;
1341
1342       result = gpgme_op_decrypt_result (ctx);
1343       if (!result->unsupported_algorithm) {
1344         maybe_signed = 1;
1345         gpgme_data_release (plaintext);
1346         goto restart;
1347       }
1348     }
1349     mutt_need_hard_redraw ();
1350     if ((s->flags & M_DISPLAY)) {
1351       char buf[200];
1352
1353       snprintf (buf, sizeof (buf) - 1,
1354                 _("[-- Error: decryption failed: %s --]\n\n"),
1355                 gpgme_strerror (err));
1356       state_attach_puts (buf, s);
1357     }
1358     gpgme_data_release (plaintext);
1359     gpgme_release (ctx);
1360     return NULL;
1361   }
1362   mutt_need_hard_redraw ();
1363
1364   /* Read the output from GPGME, and make sure to change CRLF to LF,
1365      otherwise read_mime_header has a hard time parsing the message.  */
1366   if (data_object_to_stream (plaintext, fpout)) {
1367     gpgme_data_release (plaintext);
1368     gpgme_release (ctx);
1369     return NULL;
1370   }
1371   gpgme_data_release (plaintext);
1372
1373   a->is_signed_data = 0;
1374   if (sig_stat) {
1375     int res, idx;
1376     int anybad = 0;
1377
1378     if (maybe_signed)
1379       a->is_signed_data = 1;
1380     if (r_is_signed)
1381       *r_is_signed = -1;        /* A signature exists. */
1382
1383     if ((s->flags & M_DISPLAY))
1384       state_attach_puts (_("[-- Begin signature " "information --]\n"), s);
1385     for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1386       if (res == 1)
1387         anybad = 1;
1388       else if (res == 2)
1389         anywarn = 1;
1390     }
1391     if (!anybad && idx && r_is_signed && *r_is_signed)
1392       *r_is_signed = anywarn ? 2 : 1;   /* Good signature. */
1393
1394     if ((s->flags & M_DISPLAY))
1395       state_attach_puts (_("[-- End signature " "information --]\n\n"), s);
1396   }
1397   gpgme_release (ctx);
1398   ctx = NULL;
1399
1400   fflush (fpout);
1401   rewind (fpout);
1402   tattach = mutt_read_mime_header (fpout, 0);
1403   if (tattach) {
1404     /*
1405      * Need to set the length of this body part.
1406      */
1407     fstat (fileno (fpout), &info);
1408     tattach->length = info.st_size - tattach->offset;
1409
1410     tattach->warnsig = anywarn;
1411
1412     /* See if we need to recurse on this MIME part.  */
1413     mutt_parse_part (fpout, tattach);
1414   }
1415
1416   return tattach;
1417 }
1418
1419 /* Decrypt a PGP/MIME message in FPIN and B and return a new body and
1420    the stream in CUR and FPOUT.  Returns 0 on success. */
1421 int crypt_pgp_decrypt_mime (FILE * fpin, FILE **fpout, BODY *b, BODY **cur)
1422 {
1423     STATE s;
1424     BODY *first_part = b;
1425     int is_signed;
1426
1427     first_part->goodsig = 0;
1428     first_part->warnsig = 0;
1429
1430     if (!mutt_is_multipart_encrypted(b) || !b->parts || !b->parts->next)
1431         return -1;
1432
1433     b = b->parts->next;
1434
1435     p_clear(&s, 1);
1436     s.fpin = fpin;
1437     *fpout = tmpfile();
1438     if (!*fpout) {
1439         mutt_perror (_("Can't create temporary file"));
1440         return -1;
1441     }
1442
1443     *cur = decrypt_part(b, &s, *fpout, 0, &is_signed);
1444     rewind(*fpout);
1445     first_part->goodsig = is_signed > 0;
1446     return *cur ? 0 : -1;
1447 }
1448
1449
1450 /* Decrypt a S/MIME message in FPIN and B and return a new body and
1451    the stream in CUR and FPOUT.  Returns 0 on success. */
1452 int crypt_smime_decrypt_mime(FILE *fpin, FILE **fpout, BODY *b, BODY **cur)
1453 {
1454   STATE s;
1455   FILE *tmpfp = NULL;
1456   int is_signed;
1457   long saved_b_offset;
1458   ssize_t saved_b_length;
1459   int saved_b_type;
1460
1461   if (!mutt_is_application_smime (b))
1462     return -1;
1463
1464   if (b->parts)
1465     return -1;
1466
1467   /* Decode the body - we need to pass binary CMS to the
1468      backend.  The backend allows for Base64 encoded data but it does
1469      not allow for QP which I have seen in some messages.  So better
1470      do it here. */
1471   saved_b_type = b->type;
1472   saved_b_offset = b->offset;
1473   saved_b_length = b->length;
1474   p_clear(&s, 1);
1475   s.fpin = fpin;
1476   fseeko (s.fpin, b->offset, 0);
1477   tmpfp = tmpfile();
1478   if (!tmpfp) {
1479     mutt_perror (_("Can't create temporary file"));
1480     return -1;
1481   }
1482
1483   s.fpout = tmpfp;
1484   mutt_decode_attachment (b, &s);
1485   fflush (tmpfp);
1486   b->length = ftello (s.fpout);
1487   b->offset = 0;
1488   rewind (tmpfp);
1489
1490   p_clear(&s, 1);
1491   s.fpin = tmpfp;
1492   s.fpout = 0;
1493   *fpout = tmpfile();
1494   if (!*fpout) {
1495     mutt_perror (_("Can't create temporary file"));
1496     return -1;
1497   }
1498
1499   *cur = decrypt_part (b, &s, *fpout, 1, &is_signed);
1500   if (*cur)
1501     (*cur)->goodsig = is_signed > 0;
1502   b->type = saved_b_type;
1503   b->length = saved_b_length;
1504   b->offset = saved_b_offset;
1505   m_fclose(&tmpfp);
1506   rewind (*fpout);
1507   if (*cur && !is_signed && !(*cur)->parts
1508       && mutt_is_application_smime (*cur)) {
1509     /* Assume that this is a opaque signed s/mime message.  This is
1510        an ugly way of doing it but we have anyway a problem with
1511        arbitrary encoded S/MIME messages: Only the outer part may be
1512        encrypted.  The entire mime parsing should be revamped,
1513        probably by keeping the temportary files so that we don't
1514        need to decrypt them all the time.  Inner parts of an
1515        encrypted part can then pint into this file and tehre won't
1516        never be a need to decrypt again.  This needs a partial
1517        rewrite of the MIME engine. */
1518     BODY *bb = *cur;
1519     BODY *tmp_b;
1520
1521     saved_b_type = bb->type;
1522     saved_b_offset = bb->offset;
1523     saved_b_length = bb->length;
1524     p_clear(&s, 1);
1525     s.fpin = *fpout;
1526     fseeko (s.fpin, bb->offset, 0);
1527     tmpfp = tmpfile();
1528     if (!tmpfp) {
1529       mutt_perror (_("Can't create temporary file"));
1530       return -1;
1531     }
1532
1533     s.fpout = tmpfp;
1534     mutt_decode_attachment (bb, &s);
1535     fflush (tmpfp);
1536     bb->length = ftello (s.fpout);
1537     bb->offset = 0;
1538     rewind (tmpfp);
1539     m_fclose(&*fpout);
1540
1541     p_clear(&s, 1);
1542     s.fpin = tmpfp;
1543     s.fpout = 0;
1544     *fpout = tmpfile();
1545     if (!*fpout) {
1546       mutt_perror (_("Can't create temporary file"));
1547       return -1;
1548     }
1549
1550     tmp_b = decrypt_part (bb, &s, *fpout, 1, &is_signed);
1551     if (tmp_b)
1552       tmp_b->goodsig = is_signed > 0;
1553     bb->type = saved_b_type;
1554     bb->length = saved_b_length;
1555     bb->offset = saved_b_offset;
1556     m_fclose(&tmpfp);
1557     rewind (*fpout);
1558     body_list_wipe(cur);
1559     *cur = tmp_b;
1560   }
1561   return *cur ? 0 : -1;
1562 }
1563
1564
1565 static int
1566 pgp_check_traditional_one_body(FILE *fp, BODY *b, int tagged_only)
1567 {
1568   char tempfile[_POSIX_PATH_MAX];
1569   char buf[HUGE_STRING];
1570   FILE *tfp;
1571   int tempfd;
1572
1573   short sgn = 0;
1574   short enc = 0;
1575
1576   if (b->type != TYPETEXT)
1577     return 0;
1578
1579   if (tagged_only && !b->tagged)
1580     return 0;
1581
1582   tempfd = m_tempfd(tempfile, sizeof(tempfile), NONULL(mod_core.tmpdir), NULL);
1583   if (mutt_decode_save_attachment (fp, b, tempfd, 0) != 0) {
1584     unlink (tempfile);
1585     return 0;
1586   }
1587
1588   if ((tfp = fopen(tempfile, "r")) == NULL) {
1589     unlink (tempfile);
1590     return 0;
1591   }
1592
1593   while (fgets (buf, sizeof (buf), tfp)) {
1594     if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
1595       if (!m_strcmp("MESSAGE-----\n", buf + 15))
1596         enc = 1;
1597       else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15))
1598         sgn = 1;
1599     }
1600   }
1601   m_fclose(&tfp);
1602   unlink (tempfile);
1603
1604   if (!enc && !sgn)
1605     return 0;
1606
1607   /* fix the content type */
1608
1609   parameter_setval(&b->parameter, "format", "fixed");
1610   parameter_setval(&b->parameter, "x-action",
1611                    enc ? "pgp-encrypted" : "pgp-signed");
1612   return 1;
1613 }
1614
1615 int crypt_pgp_check_traditional(FILE *fp, BODY *b, int tagged_only)
1616 {
1617     int rv = 0;
1618
1619     for (; b; b = b->next) {
1620         if (is_multipart(b))
1621             rv |= crypt_pgp_check_traditional(fp, b->parts, tagged_only);
1622         if (b->type == TYPETEXT) {
1623             int r;
1624             if ((r = mutt_is_application_pgp(b))) {
1625                 rv |= r;
1626             } else {
1627                 rv |= pgp_check_traditional_one_body(fp, b, tagged_only);
1628             }
1629         }
1630     }
1631
1632     return rv;
1633 }
1634
1635 /*
1636   Copy a clearsigned message, and strip the signature and PGP's
1637   dash-escaping.
1638
1639   XXX - charset handling: We assume that it is safe to do
1640   character set decoding first, dash decoding second here, while
1641   we do it the other way around in the main handler.
1642
1643   (Note that we aren't worse than Outlook & Cie in this, and also
1644   note that we can successfully handle anything produced by any
1645   existing versions of mutt.)  */
1646 static void copy_clearsigned(gpgme_data_t data, STATE * s, char *charset)
1647 {
1648   char buf[HUGE_STRING];
1649   short complete, armor_header;
1650   fgetconv_t *fc;
1651   char *fname;
1652   FILE *fp;
1653
1654   fname = data_object_to_tempfile(data, &fp);
1655   if (!fname)
1656     return;
1657   unlink (fname);
1658   p_delete(&fname);
1659
1660   fc = fgetconv_open (fp, charset, mod_cset.charset, M_ICONV_HOOK_FROM);
1661
1662   for (complete = 1, armor_header = 1;
1663        fgetconvs (buf, sizeof (buf), fc) != NULL;
1664        complete = strchr (buf, '\n') != NULL) {
1665     if (!complete) {
1666       if (!armor_header)
1667         state_puts (buf, s);
1668       continue;
1669     }
1670
1671     if (!m_strcmp(buf, "-----BEGIN PGP SIGNATURE-----\n"))
1672       break;
1673
1674     if (armor_header) {
1675       if (buf[0] == '\n')
1676         armor_header = 0;
1677       continue;
1678     }
1679
1680     if (s->prefix)
1681       state_puts (s->prefix, s);
1682
1683     if (buf[0] == '-' && buf[1] == ' ')
1684       state_puts (buf + 2, s);
1685     else
1686       state_puts (buf, s);
1687   }
1688
1689   fgetconv_close (&fc);
1690   m_fclose(&fp);
1691 }
1692
1693 /* Support for classic_application/pgp */
1694 int crypt_pgp_application_pgp_handler(BODY *m, STATE *s)
1695 {
1696   int needpass = -1, pgp_keyblock = 0;
1697   int clearsign = 0;
1698   long start_pos = 0;
1699   long bytes;
1700   off_t last_pos, offset;
1701   char buf[HUGE_STRING];
1702   FILE *pgpout = NULL;
1703
1704   gpgme_error_t err = 0;
1705   gpgme_data_t armored_data = NULL;
1706
1707   short maybe_goodsig = 1;
1708   short have_any_sigs = 0;
1709
1710   char body_charset[STRING];    /* Only used for clearsigned messages. */
1711
1712   /* For clearsigned messages we won't be able to get a character set
1713      but we know that this may only be text thus we assume Latin-1
1714      here. */
1715   if (!mutt_get_body_charset (body_charset, sizeof (body_charset), m))
1716     m_strcpy(body_charset, sizeof(body_charset), "iso-8859-1");
1717
1718   fseeko (s->fpin, m->offset, 0);
1719   last_pos = m->offset;
1720
1721   for (bytes = m->length; bytes > 0;) {
1722     if (fgets (buf, sizeof (buf), s->fpin) == NULL)
1723       break;
1724
1725     offset = ftello (s->fpin);
1726     bytes -= (offset - last_pos);       /* don't rely on m_strlen(buf) */
1727     last_pos = offset;
1728
1729     if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
1730       clearsign = 0;
1731       start_pos = last_pos;
1732
1733       if (!m_strcmp("MESSAGE-----\n", buf + 15))
1734         needpass = 1;
1735       else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15)) {
1736         clearsign = 1;
1737         needpass = 0;
1738       }
1739       else if (!m_strcmp("PUBLIC KEY BLOCK-----\n", buf + 15)) {
1740         needpass = 0;
1741         pgp_keyblock = 1;
1742       }
1743       else {
1744         /* XXX - we may wish to recode here */
1745         if (s->prefix)
1746           state_puts (s->prefix, s);
1747         state_puts (buf, s);
1748         continue;
1749       }
1750
1751       have_any_sigs = (have_any_sigs || (clearsign && (s->flags & M_VERIFY)));
1752
1753       /* Copy PGP material to an data container */
1754       armored_data = create_gpgme_data ();
1755       gpgme_data_write (armored_data, buf, m_strlen(buf));
1756       while (bytes > 0 && fgets (buf, sizeof (buf) - 1, s->fpin) != NULL) {
1757         offset = ftello (s->fpin);
1758         bytes -= (offset - last_pos);   /* don't rely on m_strlen(buf) */
1759         last_pos = offset;
1760
1761         gpgme_data_write (armored_data, buf, m_strlen(buf));
1762
1763         if ((needpass && !m_strcmp("-----END PGP MESSAGE-----\n", buf))
1764             || (!needpass
1765                 && (!m_strcmp("-----END PGP SIGNATURE-----\n", buf)
1766                     || !m_strcmp("-----END PGP PUBLIC KEY BLOCK-----\n",
1767                                      buf))))
1768           break;
1769       }
1770
1771       /* Invoke PGP if needed */
1772       if (!clearsign || (s->flags & M_VERIFY)) {
1773         unsigned int sig_stat = 0;
1774         gpgme_data_t plaintext;
1775         gpgme_ctx_t ctx;
1776
1777         plaintext = create_gpgme_data ();
1778         ctx = create_gpgme_context (0);
1779
1780         if (clearsign)
1781           err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1782         else {
1783           err = gpgme_op_decrypt_verify (ctx, armored_data, plaintext);
1784           if (gpg_err_code (err) == GPG_ERR_NO_DATA) {
1785             /* Decrypt verify can't handle signed only messages. */
1786             err = (gpgme_data_seek (armored_data, 0, SEEK_SET) == -1)
1787               ? gpgme_error_from_errno (errno) : 0;
1788             /* Must release plaintext so that we supply an
1789                uninitialized object. */
1790             gpgme_data_release (plaintext);
1791             plaintext = create_gpgme_data ();
1792             err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
1793           }
1794         }
1795
1796         if (err) {
1797           char errbuf[200];
1798
1799           snprintf (errbuf, sizeof (errbuf) - 1,
1800                     _("Error: decryption/verification failed: %s\n"),
1801                     gpgme_strerror (err));
1802           state_attach_puts (errbuf, s);
1803         }
1804         else {                  /* Decryption/Verification succeeded */
1805           char *tmpfname;
1806
1807           {
1808             /* Check wether signatures have been verified.  */
1809             gpgme_verify_result_t verify_result;
1810
1811             verify_result = gpgme_op_verify_result (ctx);
1812             if (verify_result->signatures)
1813               sig_stat = 1;
1814           }
1815
1816           have_any_sigs = 0;
1817           maybe_goodsig = 0;
1818           if ((s->flags & M_DISPLAY) && sig_stat) {
1819             int res, idx;
1820             int anybad = 0;
1821             int anywarn = 0;
1822
1823             state_attach_puts (_("[-- Begin signature "
1824                                  "information --]\n"), s);
1825             have_any_sigs = 1;
1826             for (idx = 0;
1827                  (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
1828               if (res == 1)
1829                 anybad = 1;
1830               else if (res == 2)
1831                 anywarn = 1;
1832             }
1833             if (!anybad && idx)
1834               maybe_goodsig = 1;
1835
1836             state_attach_puts (_("[-- End signature "
1837                                  "information --]\n\n"), s);
1838           }
1839
1840           tmpfname = data_object_to_tempfile(plaintext, &pgpout);
1841           if (!tmpfname) {
1842             pgpout = NULL;
1843             state_attach_puts (_("Error: copy data failed\n"), s);
1844           }
1845           else {
1846             unlink (tmpfname);
1847             p_delete(&tmpfname);
1848           }
1849         }
1850         gpgme_release (ctx);
1851       }
1852
1853       /*
1854        * Now, copy cleartext to the screen.  NOTE - we expect that PGP
1855        * outputs utf-8 cleartext.  This may not always be true, but it
1856        * seems to be a reasonable guess.
1857        */
1858
1859       if (s->flags & M_DISPLAY) {
1860         if (needpass)
1861           state_attach_puts (_("[-- BEGIN PGP MESSAGE --]\n\n"), s);
1862         else if (pgp_keyblock)
1863           state_attach_puts (_("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"), s);
1864         else
1865           state_attach_puts (_("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"), s);
1866       }
1867
1868       if (clearsign) {
1869         copy_clearsigned (armored_data, s, body_charset);
1870       }
1871       else if (pgpout) {
1872         fgetconv_t *fc;
1873         int c;
1874
1875         rewind (pgpout);
1876         fc = fgetconv_open (pgpout, "utf-8", mod_cset.charset, 0);
1877         while ((c = fgetconv (fc)) != EOF) {
1878           state_putc (c, s);
1879           if (c == '\n' && s->prefix)
1880             state_puts (s->prefix, s);
1881         }
1882         fgetconv_close (&fc);
1883       }
1884
1885       if (s->flags & M_DISPLAY) {
1886         state_putc ('\n', s);
1887         if (needpass)
1888           state_attach_puts (_("[-- END PGP MESSAGE --]\n"), s);
1889         else if (pgp_keyblock)
1890           state_attach_puts (_("[-- END PGP PUBLIC KEY BLOCK --]\n"), s);
1891         else
1892           state_attach_puts (_("[-- END PGP SIGNED MESSAGE --]\n"), s);
1893       }
1894
1895       if (pgpout) {
1896         m_fclose(&pgpout);
1897       }
1898     }
1899     else {
1900       /* XXX - we may wish to recode here */
1901       if (s->prefix)
1902         state_puts (s->prefix, s);
1903       state_puts (buf, s);
1904     }
1905   }
1906
1907   m->goodsig = (maybe_goodsig && have_any_sigs);
1908
1909   if (needpass == -1) {
1910     state_attach_puts (_("[-- Error: could not find beginning"
1911                          " of PGP message! --]\n\n"), s);
1912     return (-1);
1913   }
1914   return (err);
1915 }
1916
1917 /* MIME handler for pgp/mime encrypted messages. */
1918 int crypt_pgp_encrypted_handler (BODY * a, STATE * s)
1919 {
1920   char tempfile[_POSIX_PATH_MAX];
1921   FILE *fpout;
1922   BODY *tattach;
1923   BODY *orig_body = a;
1924   int is_signed;
1925   int rc = 0;
1926
1927   a = a->parts;
1928   if (!a || a->type != TYPEAPPLICATION || !a->subtype
1929       || ascii_strcasecmp ("pgp-encrypted", a->subtype)
1930       || !a->next || a->next->type != TYPEAPPLICATION || !a->next->subtype
1931       || ascii_strcasecmp ("octet-stream", a->next->subtype)) {
1932     if (s->flags & M_DISPLAY)
1933       state_attach_puts (_("[-- Error: malformed PGP/MIME message! --]\n\n"),
1934                          s);
1935     return (-1);
1936   }
1937
1938   /* Move forward to the application/pgp-encrypted body. */
1939   a = a->next;
1940
1941   fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(mod_core.tmpdir), NULL);
1942   if (!fpout) {
1943     if (s->flags & M_DISPLAY)
1944       state_attach_puts (_("[-- Error: could not create temporary file! "
1945                            "--]\n"), s);
1946     return (-1);
1947   }
1948
1949   tattach = decrypt_part (a, s, fpout, 0, &is_signed);
1950   if (tattach) {
1951     tattach->goodsig = is_signed > 0;
1952
1953     if (s->flags & M_DISPLAY)
1954       state_attach_puts (is_signed ?
1955                          _
1956                          ("[-- The following data is PGP/MIME signed and encrypted --]\n\n") :
1957                          _("[-- The following data is PGP/MIME encrypted --]\n\n"), s);
1958
1959     {
1960       FILE *savefp = s->fpin;
1961
1962       s->fpin = fpout;
1963       rc = mutt_body_handler (tattach, s);
1964       s->fpin = savefp;
1965     }
1966
1967     /*
1968      * if a multipart/signed is the _only_ sub-part of a
1969      * multipart/encrypted, cache signature verification
1970      * status.
1971      */
1972     if (mutt_is_multipart_signed (tattach) && !tattach->next)
1973       orig_body->goodsig |= tattach->goodsig;
1974
1975     if (s->flags & M_DISPLAY) {
1976       state_puts ("\n", s);
1977       state_attach_puts (is_signed ?
1978                          _
1979                          ("[-- End of PGP/MIME signed and encrypted data --]\n")
1980                          : _("[-- End of PGP/MIME encrypted data --]\n"), s);
1981     }
1982
1983     body_list_wipe(&tattach);
1984   }
1985
1986   m_fclose(&fpout);
1987   mutt_unlink (tempfile);
1988   return (rc);
1989 }
1990
1991 /* Support for application/smime */
1992 int crypt_smime_application_smime_handler (BODY * a, STATE * s)
1993 {
1994   char tempfile[_POSIX_PATH_MAX];
1995   FILE *fpout;
1996   BODY *tattach;
1997   int is_signed;
1998   int rc = 0;
1999
2000   a->warnsig = 0;
2001   fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(mod_core.tmpdir), NULL);
2002   if (!fpout) {
2003     if (s->flags & M_DISPLAY)
2004       state_attach_puts (_("[-- Error: could not create temporary file! "
2005                            "--]\n"), s);
2006     return (-1);
2007   }
2008
2009   tattach = decrypt_part (a, s, fpout, 1, &is_signed);
2010   if (tattach) {
2011     tattach->goodsig = is_signed > 0;
2012
2013     if (s->flags & M_DISPLAY)
2014       state_attach_puts (is_signed ?
2015                          _("[-- The following data is S/MIME signed --]\n\n") :
2016                          _("[-- The following data is S/MIME encrypted --]\n\n"), s);
2017
2018     {
2019       FILE *savefp = s->fpin;
2020
2021       s->fpin = fpout;
2022       rc = mutt_body_handler (tattach, s);
2023       s->fpin = savefp;
2024     }
2025
2026     /*
2027      * if a multipart/signed is the _only_ sub-part of a
2028      * multipart/encrypted, cache signature verification
2029      * status.
2030      */
2031     if (mutt_is_multipart_signed (tattach) && !tattach->next) {
2032       if (!(a->goodsig = tattach->goodsig))
2033         a->warnsig = tattach->warnsig;
2034     }
2035     else if (tattach->goodsig) {
2036       a->goodsig = 1;
2037       a->warnsig = tattach->warnsig;
2038     }
2039
2040     if (s->flags & M_DISPLAY) {
2041       state_puts ("\n", s);
2042       state_attach_puts (is_signed ?
2043                          _("[-- End of S/MIME signed data --]\n") :
2044                          _("[-- End of S/MIME encrypted data --]\n"), s);
2045     }
2046
2047     body_list_wipe(&tattach);
2048   }
2049
2050   m_fclose(&fpout);
2051   mutt_unlink (tempfile);
2052   return (rc);
2053 }
2054
2055
2056 /*
2057  * Format an entry on the CRYPT key selection menu.
2058  *
2059  * %n   number
2060  * %k   key id          %K      key id of the principal key
2061  * %u   user id
2062  * %a   algorithm       %A      algorithm of the princ. key
2063  * %l   length          %L      length of the princ. key
2064  * %f   flags           %F      flags of the princ. key
2065  * %c   capabilities    %C      capabilities of the princ. key
2066  * %t   trust/validity of the key-uid association
2067  * %p           protocol
2068  * %[...] date of key using strftime(3)
2069  */
2070
2071 static const char *
2072 crypt_entry_fmt (char *dest, ssize_t destlen, char op,
2073                  const char *src, const char *prefix,
2074                  const char *ifstr, const char *elstr,
2075                  anytype data, format_flag flags)
2076 {
2077   char fmt[16];
2078   crypt_entry_t *entry;
2079   cryptkey_t *key;
2080   int kflags = 0;
2081   int optional = (flags & M_FORMAT_OPTIONAL);
2082   const char *s = NULL;
2083   unsigned long val;
2084
2085   entry = data.ptr;
2086   key = entry->key;
2087
2088 /*    if (isupper ((unsigned char) op)) */
2089 /*      key = pkey; */
2090
2091   kflags = (key->flags          /*| (pkey->flags & KEYFLAG_RESTRICTIONS)
2092                                    | uid->flags */ );
2093
2094   switch (ascii_tolower (op)) {
2095   case '[':
2096     {
2097       const char *cp;
2098       char buf2[STRING], *p;
2099       int do_locales;
2100       struct tm *tm;
2101       ssize_t len;
2102
2103       p = dest;
2104
2105       cp = src;
2106       if (*cp == '!') {
2107         do_locales = 0;
2108         cp++;
2109       }
2110       else
2111         do_locales = 1;
2112
2113       len = destlen - 1;
2114       while (len > 0 && *cp != ']') {
2115         if (*cp == '%') {
2116           cp++;
2117           if (len >= 2) {
2118             *p++ = '%';
2119             *p++ = *cp;
2120             len -= 2;
2121           }
2122           else
2123             break;              /* not enough space */
2124           cp++;
2125         }
2126         else {
2127           *p++ = *cp++;
2128           len--;
2129         }
2130       }
2131       *p = 0;
2132
2133       if (do_locales && Locale)
2134         setlocale (LC_TIME, Locale);
2135
2136       {
2137         time_t tt = 0;
2138
2139         if (key->kobj->subkeys && (key->kobj->subkeys->timestamp > 0))
2140           tt = key->kobj->subkeys->timestamp;
2141
2142         tm = localtime (&tt);
2143       }
2144       strftime (buf2, sizeof (buf2), dest, tm);
2145
2146       if (do_locales)
2147         setlocale (LC_TIME, "C");
2148
2149       snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2150       snprintf (dest, destlen, fmt, buf2);
2151       if (len > 0)
2152         src = cp + 1;
2153     }
2154     break;
2155   case 'n':
2156     if (!optional) {
2157       snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
2158       snprintf (dest, destlen, fmt, entry->num);
2159     }
2160     break;
2161   case 'k':
2162     if (!optional) {
2163       /* fixme: we need a way to distinguish between main and subkeys.
2164          Store the idx in entry? */
2165       snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2166       snprintf (dest, destlen, fmt, crypt_keyid (key));
2167     }
2168     break;
2169   case 'u':
2170     if (!optional) {
2171       snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2172       snprintf (dest, destlen, fmt, key->uid);
2173     }
2174     break;
2175   case 'a':
2176     if (!optional) {
2177       snprintf (fmt, sizeof (fmt), "%%%s.3s", prefix);
2178       if (key->kobj->subkeys)
2179         s = gpgme_pubkey_algo_name (key->kobj->subkeys->pubkey_algo);
2180       else
2181         s = "?";
2182       snprintf (dest, destlen, fmt, s);
2183     }
2184     break;
2185   case 'l':
2186     if (!optional) {
2187       snprintf (fmt, sizeof (fmt), "%%%slu", prefix);
2188       if (key->kobj->subkeys)
2189         val = key->kobj->subkeys->length;
2190       else
2191         val = 0;
2192       snprintf (dest, destlen, fmt, val);
2193     }
2194     break;
2195   case 'f':
2196     if (!optional) {
2197       snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2198       snprintf (dest, destlen, fmt, crypt_flags (kflags));
2199     }
2200     else if (!(kflags & (KEYFLAG_RESTRICTIONS)))
2201       optional = 0;
2202     break;
2203   case 'c':
2204     if (!optional) {
2205       snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2206       snprintf (dest, destlen, fmt, crypt_key_abilities (kflags));
2207     }
2208     else if (!(kflags & (KEYFLAG_ABILITIES)))
2209       optional = 0;
2210     break;
2211   case 't':
2212     if ((kflags & KEYFLAG_ISX509))
2213       s = "x";
2214     else {
2215       gpgme_user_id_t uid = NULL;
2216       int i = 0;
2217
2218       for (i = 0, uid = key->kobj->uids; uid && (i < key->idx);
2219            i++, uid = uid->next);
2220       if (uid)
2221         switch (uid->validity) {
2222         case GPGME_VALIDITY_UNDEFINED:
2223           s = "q";
2224           break;
2225         case GPGME_VALIDITY_NEVER:
2226           s = "n";
2227           break;
2228         case GPGME_VALIDITY_MARGINAL:
2229           s = "m";
2230           break;
2231         case GPGME_VALIDITY_FULL:
2232           s = "f";
2233           break;
2234         case GPGME_VALIDITY_ULTIMATE:
2235           s = "u";
2236           break;
2237         case GPGME_VALIDITY_UNKNOWN:
2238         default:
2239           s = "?";
2240           break;
2241         }
2242     }
2243     snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2244     snprintf (dest, destlen, fmt, s ? *s : 'B');
2245     break;
2246   case 'p':
2247     snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2248     snprintf (dest, destlen, fmt,
2249               gpgme_get_protocol_name (key->kobj->protocol));
2250     break;
2251
2252   default:
2253     *dest = '\0';
2254   }
2255
2256   if (flags & M_FORMAT_OPTIONAL)
2257     m_strformat(dest, destlen, 0, optional ? ifstr: elstr,
2258                 mutt_attach_fmt, data, 0);
2259   return src;
2260 }
2261
2262 /* Used by the display fucntion to format a line. */
2263 static void crypt_entry (char *s, ssize_t l, MUTTMENU * menu, int num)
2264 {
2265   cryptkey_t **cryptkey_table = (cryptkey_t **) menu->data;
2266   crypt_entry_t entry;
2267
2268   entry.key = cryptkey_table[num];
2269   entry.num = num + 1;
2270
2271   m_strformat(s, l, getmaxx(main_w), mod_crypt.pgp_entry_format,
2272               crypt_entry_fmt, &entry, 0);
2273 }
2274
2275 /* Compare two addresses and the keyid to be used for sorting. */
2276 static int _crypt_compare_address (const void *a, const void *b)
2277 {
2278   cryptkey_t **s = (cryptkey_t **) a;
2279   cryptkey_t **t = (cryptkey_t **) b;
2280   int r;
2281
2282   if ((r = m_strcasecmp((*s)->uid, (*t)->uid)))
2283     return r > 0;
2284   else
2285     return m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t)) > 0;
2286 }
2287
2288 static int crypt_compare_address (const void *a, const void *b)
2289 {
2290   return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_address (a, b)
2291           : _crypt_compare_address (a, b));
2292 }
2293
2294
2295 /* Compare two key IDs and the addresses to be used for sorting. */
2296 static int _crypt_compare_keyid (const void *a, const void *b)
2297 {
2298   cryptkey_t **s = (cryptkey_t **) a;
2299   cryptkey_t **t = (cryptkey_t **) b;
2300   int r;
2301
2302   if ((r = m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t))))
2303     return r > 0;
2304   else
2305     return m_strcasecmp((*s)->uid, (*t)->uid) > 0;
2306 }
2307
2308 static int crypt_compare_keyid (const void *a, const void *b)
2309 {
2310   return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_keyid (a, b)
2311           : _crypt_compare_keyid (a, b));
2312 }
2313
2314 /* Compare 2 creation dates and the addresses.  For sorting. */
2315 static int _crypt_compare_date (const void *a, const void *b)
2316 {
2317   cryptkey_t **s = (cryptkey_t **) a;
2318   cryptkey_t **t = (cryptkey_t **) b;
2319   unsigned long ts = 0, tt = 0;
2320
2321   if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2322     ts = (*s)->kobj->subkeys->timestamp;
2323   if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2324     tt = (*t)->kobj->subkeys->timestamp;
2325
2326   if (ts > tt)
2327     return 1;
2328   if (ts < tt)
2329     return 0;
2330
2331   return m_strcasecmp((*s)->uid, (*t)->uid) > 0;
2332 }
2333
2334 static int crypt_compare_date (const void *a, const void *b)
2335 {
2336   return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_date (a, b)
2337           : _crypt_compare_date (a, b));
2338 }
2339
2340 /* Compare two trust values, the key length, the creation dates. the
2341    addresses and the key IDs.  For sorting. */
2342 static int _crypt_compare_trust (const void *a, const void *b)
2343 {
2344   cryptkey_t **s = (cryptkey_t **) a;
2345   cryptkey_t **t = (cryptkey_t **) b;
2346   unsigned long ts = 0, tt = 0;
2347   int r;
2348
2349   if ((r = (((*s)->flags & (KEYFLAG_RESTRICTIONS))
2350             - ((*t)->flags & (KEYFLAG_RESTRICTIONS)))))
2351     return r > 0;
2352
2353   if ((*s)->kobj->uids)
2354     ts = (*s)->kobj->uids->validity;
2355   if ((*t)->kobj->uids)
2356     tt = (*t)->kobj->uids->validity;
2357   if ((r = (tt - ts)))
2358     return r < 0;
2359
2360   if ((*s)->kobj->subkeys)
2361     ts = (*s)->kobj->subkeys->length;
2362   if ((*t)->kobj->subkeys)
2363     tt = (*t)->kobj->subkeys->length;
2364   if (ts != tt)
2365     return ts > tt;
2366
2367   if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2368     ts = (*s)->kobj->subkeys->timestamp;
2369   if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2370     tt = (*t)->kobj->subkeys->timestamp;
2371   if (ts > tt)
2372     return 1;
2373   if (ts < tt)
2374     return 0;
2375
2376   if ((r = m_strcasecmp((*s)->uid, (*t)->uid)))
2377     return r > 0;
2378   return (m_strcasecmp(crypt_keyid ((*s)), crypt_keyid ((*t)))) > 0;
2379 }
2380
2381 static int crypt_compare_trust (const void *a, const void *b)
2382 {
2383   return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_trust (a, b)
2384           : _crypt_compare_trust (a, b));
2385 }
2386
2387 /* Print the X.500 Distinguished Name part KEY from the array of parts
2388    DN to FP. */
2389 static int print_dn_part (FILE * fp, struct dn_array_s *dn, const char *key)
2390 {
2391   int any = 0;
2392
2393   for (; dn->key; dn++) {
2394     if (!m_strcmp(dn->key, key)) {
2395       if (any)
2396         fputs (" + ", fp);
2397       print_utf8 (fp, dn->value, m_strlen(dn->value));
2398       any = 1;
2399     }
2400   }
2401   return any;
2402 }
2403
2404 /* Print all parts of a DN in a standard sequence. */
2405 static void print_dn_parts (FILE * fp, struct dn_array_s *dn)
2406 {
2407   const char *stdpart[] = {
2408     "CN", "OU", "O", "STREET", "L", "ST", "C", NULL
2409   };
2410   int any = 0, any2 = 0, i;
2411
2412   for (i = 0; stdpart[i]; i++) {
2413     if (any)
2414       fputs (", ", fp);
2415     any = print_dn_part (fp, dn, stdpart[i]);
2416   }
2417   /* now print the rest without any specific ordering */
2418   for (; dn->key; dn++) {
2419     for (i = 0; stdpart[i]; i++) {
2420       if (!m_strcmp(dn->key, stdpart[i]))
2421         break;
2422     }
2423     if (!stdpart[i]) {
2424       if (any)
2425         fputs (", ", fp);
2426       if (!any2)
2427         fputs ("(", fp);
2428       any = print_dn_part (fp, dn, dn->key);
2429       any2 = 1;
2430     }
2431   }
2432   if (any2)
2433     fputs (")", fp);
2434 }
2435
2436
2437 /* Parse an RDN; this is a helper to parse_dn(). */
2438 static const unsigned char *parse_dn_part (struct dn_array_s *array,
2439                                            const unsigned char *string)
2440 {
2441   const unsigned char *s, *s1;
2442   ssize_t n;
2443   unsigned char *p;
2444
2445   /* parse attributeType */
2446   for (s = string + 1; *s && *s != '='; s++);
2447   if (!*s)
2448     return NULL;                /* error */
2449   n = s - string;
2450   if (!n)
2451     return NULL;                /* empty key */
2452   array->key = p_dupstr(string, n );
2453   p = (unsigned char *) array->key;
2454   string = s + 1;
2455
2456   if (*string == '#') {         /* hexstring */
2457     string++;
2458     for (s = string; hexval(*s) >= 0; s++)
2459       s++;
2460     n = s - string;
2461     if (!n || (n & 1))
2462       return NULL;              /* empty or odd number of digits */
2463     n /= 2;
2464     p = p_new(unsigned char, n + 1);
2465     array->value = (char *) p;
2466     for (s1 = string; n; s1 += 2, n--)
2467       *p++ = (hexval(*s1) << 8) | hexval(*s1);
2468     *p = 0;
2469   }
2470   else {                        /* regular v3 quoted string */
2471     for (n = 0, s = string; *s; s++) {
2472       if (*s == '\\') {         /* pair */
2473         s++;
2474         if (*s == ',' || *s == '=' || *s == '+'
2475             || *s == '<' || *s == '>' || *s == '#' || *s == ';'
2476             || *s == '\\' || *s == '"' || *s == ' ')
2477           n++;
2478         else if (hexval(*s) >= 0 && hexval(*s + 1) >= 0) {
2479           s++;
2480           n++;
2481         }
2482         else
2483           return NULL;          /* invalid escape sequence */
2484       }
2485       else if (*s == '"')
2486         return NULL;            /* invalid encoding */
2487       else if (*s == ',' || *s == '=' || *s == '+'
2488                || *s == '<' || *s == '>' || *s == '#' || *s == ';')
2489         break;
2490       else
2491         n++;
2492     }
2493
2494     p = p_new(unsigned char, n + 1);
2495     array->value = (char *) p;
2496     for (s = string; n; s++, n--) {
2497       if (*s == '\\') {
2498         s++;
2499         if (hexval(*s) >= 0) {
2500           *p++ = (hexval(*s) << 8) | hexval(*s + 1);
2501           s++;
2502         }
2503         else
2504           *p++ = *s;
2505       }
2506       else
2507         *p++ = *s;
2508     }
2509     *p = 0;
2510   }
2511   return s;
2512 }
2513
2514
2515 /* Parse a DN and return an array-ized one.  This is not a validating
2516    parser and it does not support any old-stylish syntax; gpgme is
2517    expected to return only rfc2253 compatible strings. */
2518 static struct dn_array_s *parse_dn (const unsigned char *string)
2519 {
2520   struct dn_array_s *array;
2521   ssize_t arrayidx, arraysize;
2522   int i;
2523
2524   arraysize = 7;                /* C,ST,L,O,OU,CN,email */
2525   array = p_new(struct dn_array_s, arraysize + 1);
2526   arrayidx = 0;
2527   while (*string) {
2528     while (*string == ' ')
2529       string++;
2530     if (!*string)
2531       break;                    /* ready */
2532     if (arrayidx >= arraysize) {        /* mutt lacks a real safe_realoc - so we need to copy */
2533       struct dn_array_s *a2;
2534
2535       arraysize += 5;
2536       a2 = p_new(struct dn_array_s, arraysize + 1);
2537       for (i = 0; i < arrayidx; i++) {
2538         a2[i].key = array[i].key;
2539         a2[i].value = array[i].value;
2540       }
2541       p_delete(&array);
2542       array = a2;
2543     }
2544     array[arrayidx].key = NULL;
2545     array[arrayidx].value = NULL;
2546     string = parse_dn_part (array + arrayidx, string);
2547     arrayidx++;
2548     if (!string)
2549       goto failure;
2550     while (*string == ' ')
2551       string++;
2552     if (*string && *string != ',' && *string != ';' && *string != '+')
2553       goto failure;             /* invalid delimiter */
2554     if (*string)
2555       string++;
2556   }
2557   array[arrayidx].key = NULL;
2558   array[arrayidx].value = NULL;
2559   return array;
2560
2561 failure:
2562   for (i = 0; i < arrayidx; i++) {
2563     p_delete(&array[i].key);
2564     p_delete(&array[i].value);
2565   }
2566   p_delete(&array);
2567   return NULL;
2568 }
2569
2570
2571 /* Print a nice representation of the USERID and make sure it is
2572    displayed in a proper way, which does mean to reorder some parts
2573    for S/MIME's DNs.  USERID is a string as returned by the gpgme key
2574    functions.  It is utf-8 encoded. */
2575 static void parse_and_print_user_id(FILE * fp, const char *userid)
2576 {
2577   const char *s;
2578   int i;
2579
2580   if (*userid == '<') {
2581     s = strchr (userid + 1, '>');
2582     if (s)
2583       print_utf8 (fp, userid + 1, s - userid - 1);
2584   }
2585   else if (*userid == '(')
2586     fputs (_("[Can't display this user ID (unknown encoding)]"), fp);
2587   else if (*userid & ~127 || __m_strdigits[(int)*userid] == 255)
2588     fputs (_("[Can't display this user ID (invalid encoding)]"), fp);
2589   else {
2590     struct dn_array_s *dn = parse_dn ((const unsigned char *) userid);
2591
2592     if (!dn)
2593       fputs (_("[Can't display this user ID (invalid DN)]"), fp);
2594     else {
2595       print_dn_parts (fp, dn);
2596       for (i = 0; dn[i].key; i++) {
2597         p_delete(&dn[i].key);
2598         p_delete(&dn[i].value);
2599       }
2600       p_delete(&dn);
2601     }
2602   }
2603 }
2604
2605 typedef enum {
2606     KEY_CAP_CAN_ENCRYPT,
2607     KEY_CAP_CAN_SIGN,
2608     KEY_CAP_CAN_CERTIFY
2609 } key_cap_t;
2610
2611 static unsigned int key_check_cap(gpgme_key_t key, key_cap_t cap)
2612 {
2613   gpgme_subkey_t subkey = NULL;
2614   unsigned int ret = 0;
2615
2616   switch (cap) {
2617   case KEY_CAP_CAN_ENCRYPT:
2618     if (!(ret = key->can_encrypt))
2619       for (subkey = key->subkeys; subkey; subkey = subkey->next)
2620         if ((ret = subkey->can_encrypt))
2621           break;
2622     break;
2623   case KEY_CAP_CAN_SIGN:
2624     if (!(ret = key->can_sign))
2625       for (subkey = key->subkeys; subkey; subkey = subkey->next)
2626         if ((ret = subkey->can_sign))
2627           break;
2628     break;
2629   case KEY_CAP_CAN_CERTIFY:
2630     if (!(ret = key->can_certify))
2631       for (subkey = key->subkeys; subkey; subkey = subkey->next)
2632         if ((ret = subkey->can_certify))
2633           break;
2634     break;
2635   }
2636
2637   return ret;
2638 }
2639
2640
2641 /* Print verbose information about a key or certificate to FP. */
2642 static void print_key_info (gpgme_key_t key, FILE * fp)
2643 {
2644   int idx;
2645   const char *s = NULL, *s2 = NULL;
2646   time_t tt = 0;
2647   struct tm *tm;
2648   char shortbuf[STRING];
2649   unsigned long aval = 0;
2650   const char *delim;
2651   int is_pgp = 0;
2652   int i;
2653   gpgme_user_id_t uid = NULL;
2654
2655   if (Locale)
2656     setlocale (LC_TIME, Locale);
2657
2658   is_pgp = key->protocol == GPGME_PROTOCOL_OpenPGP;
2659
2660   for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
2661     if (uid->revoked)
2662       continue;
2663
2664     s = uid->uid;
2665     fputs (idx ? _(" aka ......: ") :_("Name ......: "), fp);
2666
2667     if (uid->invalid) {
2668       fputs (_("[Invalid]"), fp);
2669       putc (' ', fp);
2670     }
2671     if (is_pgp)
2672       print_utf8 (fp, s, m_strlen(s));
2673     else
2674       parse_and_print_user_id (fp, s);
2675     putc ('\n', fp);
2676   }
2677
2678   if (key->subkeys && (key->subkeys->timestamp > 0)) {
2679     tt = key->subkeys->timestamp;
2680
2681     tm = localtime (&tt);
2682 #ifdef D_T_FMT
2683     strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2684 #else
2685     strftime (shortbuf, sizeof shortbuf, "%c", tm);
2686 #endif
2687     fprintf (fp, _("Valid From : %s\n"), shortbuf);
2688   }
2689
2690   if (key->subkeys && (key->subkeys->expires > 0)) {
2691     tt = key->subkeys->expires;
2692
2693     tm = localtime (&tt);
2694 #ifdef D_T_FMT
2695     strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2696 #else
2697     strftime (shortbuf, sizeof shortbuf, "%c", tm);
2698 #endif
2699     fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2700   }
2701
2702   if (key->subkeys)
2703     s = gpgme_pubkey_algo_name (key->subkeys->pubkey_algo);
2704   else
2705     s = "?";
2706
2707   s2 = is_pgp ? "PGP" : "X.509";
2708
2709   if (key->subkeys)
2710     aval = key->subkeys->length;
2711
2712   fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), s2, aval, s);
2713
2714   fprintf (fp, _("Key Usage .: "));
2715   delim = "";
2716
2717   if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT)) {
2718     fprintf (fp, "%s%s", delim, _("encryption"));
2719     delim = _(", ");
2720   }
2721   if (key_check_cap (key, KEY_CAP_CAN_SIGN)) {
2722     fprintf (fp, "%s%s", delim, _("signing"));
2723     delim = _(", ");
2724   }
2725   if (key_check_cap (key, KEY_CAP_CAN_CERTIFY)) {
2726     fprintf (fp, "%s%s", delim, _("certification"));
2727     delim = _(", ");
2728   }
2729   putc ('\n', fp);
2730
2731   if (key->subkeys) {
2732     s = key->subkeys->fpr;
2733     fputs (_("Fingerprint: "), fp);
2734     if (is_pgp && m_strlen(s) == 40) {
2735       for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
2736         putc (*s, fp);
2737         putc (s[1], fp);
2738         putc (s[2], fp);
2739         putc (s[3], fp);
2740         putc (is_pgp ? ' ' : ':', fp);
2741         if (is_pgp && i == 4)
2742           putc (' ', fp);
2743       }
2744     }
2745     else {
2746       for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
2747         putc (*s, fp);
2748         putc (s[1], fp);
2749         putc (is_pgp ? ' ' : ':', fp);
2750         if (is_pgp && i == 7)
2751           putc (' ', fp);
2752       }
2753     }
2754     fprintf (fp, "%s\n", s);
2755   }
2756
2757   if (key->issuer_serial) {
2758     s = key->issuer_serial;
2759     if (s)
2760       fprintf (fp, _("Serial-No .: 0x%s\n"), s);
2761   }
2762
2763   if (key->issuer_name) {
2764     s = key->issuer_name;
2765     if (s) {
2766       fprintf (fp, _("Issued By .: "));
2767       parse_and_print_user_id (fp, s);
2768       putc ('\n', fp);
2769     }
2770   }
2771
2772   /* For PGP we list all subkeys. */
2773   if (is_pgp) {
2774     gpgme_subkey_t subkey = NULL;
2775
2776     for (idx = 1, subkey = key->subkeys; subkey; idx++, subkey = subkey->next) {
2777       s = subkey->keyid;
2778
2779       putc ('\n', fp);
2780       if (m_strlen(s) == 16)
2781         s += 8;                 /* display only the short keyID */
2782       fprintf (fp, _("Subkey ....: 0x%s"), s);
2783       if (subkey->revoked) {
2784         putc (' ', fp);
2785         fputs (_("[Revoked]"), fp);
2786       }
2787       if (subkey->invalid) {
2788         putc (' ', fp);
2789         fputs (_("[Invalid]"), fp);
2790       }
2791       if (subkey->expired) {
2792         putc (' ', fp);
2793         fputs (_("[Expired]"), fp);
2794       }
2795       if (subkey->disabled) {
2796         putc (' ', fp);
2797         fputs (_("[Disabled]"), fp);
2798       }
2799       putc ('\n', fp);
2800
2801       if (subkey->timestamp > 0) {
2802         tt = subkey->timestamp;
2803
2804         tm = localtime (&tt);
2805 #ifdef D_T_FMT
2806         strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2807 #else
2808         strftime (shortbuf, sizeof shortbuf, "%c", tm);
2809 #endif
2810         fprintf (fp, _("Valid From : %s\n"), shortbuf);
2811       }
2812
2813       if (subkey->expires > 0) {
2814         tt = subkey->expires;
2815
2816         tm = localtime (&tt);
2817 #ifdef D_T_FMT
2818         strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2819 #else
2820         strftime (shortbuf, sizeof shortbuf, "%c", tm);
2821 #endif
2822         fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2823       }
2824
2825       if (subkey)
2826         s = gpgme_pubkey_algo_name (subkey->pubkey_algo);
2827       else
2828         s = "?";
2829
2830       if (subkey)
2831         aval = subkey->length;
2832       else
2833         aval = 0;
2834
2835       fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), "PGP", aval, s);
2836
2837       fprintf (fp, _("Key Usage .: "));
2838       delim = "";
2839
2840       if (subkey->can_encrypt) {
2841         fprintf (fp, "%s%s", delim, _("encryption"));
2842         delim = _(", ");
2843       }
2844       if (subkey->can_sign) {
2845         fprintf (fp, "%s%s", delim, _("signing"));
2846         delim = _(", ");
2847       }
2848       if (subkey->can_certify) {
2849         fprintf (fp, "%s%s", delim, _("certification"));
2850         delim = _(", ");
2851       }
2852       putc ('\n', fp);
2853     }
2854   }
2855
2856   if (Locale)
2857     setlocale (LC_TIME, "C");
2858 }
2859
2860
2861 /* Show detailed information about the selected key */
2862 static void verify_key (cryptkey_t * key)
2863 {
2864   FILE *fp;
2865   char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
2866   const char *s;
2867   gpgme_ctx_t listctx = NULL;
2868   gpgme_error_t err;
2869   gpgme_key_t k = NULL;
2870   int maxdepth = 100;
2871
2872   fp = m_tempfile (tempfile, sizeof(tempfile), NONULL(mod_core.tmpdir), NULL);
2873   if (!fp) {
2874     mutt_perror (_("Can't create temporary file"));
2875     return;
2876   }
2877   mutt_message _("Collecting data...");
2878
2879   print_key_info (key->kobj, fp);
2880
2881   err = gpgme_new (&listctx);
2882   if (err) {
2883     fprintf (fp, "Internal error: can't create gpgme context: %s\n",
2884              gpgme_strerror (err));
2885     goto leave;
2886   }
2887   if ((key->flags & KEYFLAG_ISX509))
2888     gpgme_set_protocol (listctx, GPGME_PROTOCOL_CMS);
2889
2890   k = key->kobj;
2891   gpgme_key_ref (k);
2892   while ((s = k->chain_id) && k->subkeys && m_strcmp(s, k->subkeys->fpr)) {
2893     putc ('\n', fp);
2894     err = gpgme_op_keylist_start (listctx, s, 0);
2895     gpgme_key_unref(k);
2896     k = NULL;
2897     if (!err)
2898       err = gpgme_op_keylist_next (listctx, &k);
2899     if (err) {
2900       fprintf (fp, _("Error finding issuer key: %s\n"), gpgme_strerror (err));
2901       goto leave;
2902     }
2903     gpgme_op_keylist_end (listctx);
2904
2905     print_key_info (k, fp);
2906     if (!--maxdepth) {
2907       putc ('\n', fp);
2908       fputs (_("Error: certification chain to long - stopping here\n"), fp);
2909       break;
2910     }
2911   }
2912
2913 leave:
2914   gpgme_key_unref(k);
2915   gpgme_release (listctx);
2916   m_fclose(&fp);
2917   mutt_clear_error ();
2918   snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), crypt_keyid (key));
2919   mutt_pager(cmd, tempfile, 0, NULL);
2920 }
2921
2922 /* Implementation of `findkeys'. */
2923
2924 static void add_hints(string_array *arr, const char *s)
2925 {
2926     if (!s)
2927         return;
2928
2929     while (*s) {
2930         int l = strcspn(s, " ,.:\"()<>\n");
2931         string_array_append(arr, p_dupstr(s, l));
2932         s += l;
2933         s += strspn(s, " ,.:\"()<>\n");
2934     }
2935 }
2936
2937 /* Return a list of keys which are candidates for the selection. */
2938 static cryptkey_t *
2939 get_candidates(string_array *hints, unsigned int app, int secret)
2940 {
2941     cryptkey_t  *res = NULL, **kend = &res;
2942     gpgme_error_t err;
2943     gpgme_ctx_t   ctx;
2944     gpgme_key_t   key;
2945
2946     if (hints->len <= 0)
2947         return NULL;
2948     string_array_append(hints, NULL);
2949     ctx = create_gpgme_context(0);
2950
2951     if ((app & APPLICATION_PGP)) {
2952         err = gpgme_op_keylist_ext_start(ctx, (const char **)hints->arr,
2953                                          secret, 0);
2954         if (err) {
2955             mutt_error(_("gpgme_op_keylist_start failed: %s"),
2956                        gpgme_strerror(err));
2957             gpgme_release(ctx);
2958             return NULL;
2959         }
2960
2961         while (!(err = gpgme_op_keylist_next(ctx, &key))) {
2962             gpgme_user_id_t uid = NULL;
2963             unsigned int flags = 0;
2964             int idx;
2965
2966             if (key_check_cap(key, KEY_CAP_CAN_ENCRYPT))
2967                 flags |= KEYFLAG_CANENCRYPT;
2968             if (key_check_cap(key, KEY_CAP_CAN_SIGN))
2969                 flags |= KEYFLAG_CANSIGN;
2970
2971             for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
2972                 cryptkey_t *k = p_new(cryptkey_t, 1);
2973                 k->kobj = key;
2974                 k->idx = idx;
2975                 k->uid = uid->uid;
2976                 k->flags = flags;
2977                 *kend = k;
2978                 kend = &k->next;
2979             }
2980         }
2981         if (gpg_err_code(err) != GPG_ERR_EOF)
2982             mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
2983         gpgme_op_keylist_end(ctx);
2984     }
2985
2986     if ((app & APPLICATION_SMIME)) {
2987         gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS);
2988         err = gpgme_op_keylist_ext_start(ctx, (const char **)hints->arr,
2989                                          secret, 0);
2990         if (err) {
2991             mutt_error(_("gpgme_op_keylist_start failed: %s"),
2992                        gpgme_strerror(err));
2993             gpgme_release(ctx);
2994             return NULL;
2995         }
2996
2997         while (!(err = gpgme_op_keylist_next(ctx, &key))) {
2998             gpgme_user_id_t uid = NULL;
2999             unsigned int flags = KEYFLAG_ISX509;
3000             int idx;
3001
3002             if (key_check_cap(key, KEY_CAP_CAN_ENCRYPT))
3003                 flags |= KEYFLAG_CANENCRYPT;
3004             if (key_check_cap(key, KEY_CAP_CAN_SIGN))
3005                 flags |= KEYFLAG_CANSIGN;
3006
3007             for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3008                 cryptkey_t *k = p_new(cryptkey_t, 1);
3009                 k->kobj = key;
3010                 k->idx = idx;
3011                 k->uid = uid->uid;
3012                 k->flags = flags;
3013                 *kend = k;
3014                 kend = &k->next;
3015             }
3016         }
3017         if (gpg_err_code(err) != GPG_ERR_EOF)
3018             mutt_error(_("gpgme_op_keylist_next failed: %s"),
3019                        gpgme_strerror(err));
3020         gpgme_op_keylist_end(ctx);
3021     }
3022
3023     gpgme_release(ctx);
3024     return res;
3025 }
3026
3027 /* Display a menu to select a key from the array KEYS. FORCED_VALID
3028    will be set to true on return if the user did override the the
3029    key's validity. */
3030 static cryptkey_t *crypt_select_key (cryptkey_t * keys,
3031                                       address_t * p, const char *s,
3032                                       unsigned int app, int *forced_valid)
3033 {
3034   int keymax;
3035   cryptkey_t **cryptkey_table;
3036   MUTTMENU *menu;
3037   int i, done = 0;
3038   char buf[LONG_STRING];
3039   cryptkey_t *k;
3040   int (*f) (const void *, const void *);
3041   int menu_to_use = 0;
3042   int unusable = 0;
3043
3044   *forced_valid = 0;
3045
3046   /* build the key table */
3047   keymax = i = 0;
3048   cryptkey_table = NULL;
3049   for (k = keys; k; k = k->next) {
3050       if (!option (OPTPGPSHOWUNUSABLE) && (k->flags & KEYFLAG_CANTUSE)) {
3051           unusable = 1;
3052           continue;
3053       }
3054
3055       if (i == keymax) {
3056           keymax += 20;
3057           p_realloc(&cryptkey_table, keymax);
3058       }
3059
3060       cryptkey_table[i++] = k;
3061   }
3062
3063   if (!i && unusable) {
3064       mutt_error _("All matching keys are marked expired/revoked.");
3065
3066       mutt_sleep (1);
3067       return NULL;
3068   }
3069
3070   switch (PgpSortKeys & SORT_MASK) {
3071     case SORT_DATE:
3072       f = crypt_compare_date;
3073       break;
3074     case SORT_KEYID:
3075       f = crypt_compare_keyid;
3076       break;
3077     case SORT_ADDRESS:
3078       f = crypt_compare_address;
3079       break;
3080     case SORT_TRUST:
3081     default:
3082       f = crypt_compare_trust;
3083       break;
3084   }
3085   qsort (cryptkey_table, i, sizeof (cryptkey_t *), f);
3086
3087   if (app & APPLICATION_PGP)
3088       menu_to_use = MENU_KEY_SELECT_PGP;
3089   else if (app & APPLICATION_SMIME)
3090       menu_to_use = MENU_KEY_SELECT_SMIME;
3091
3092   menu = mutt_new_menu ();
3093   menu->max = i;
3094   menu->make_entry = crypt_entry;
3095   menu->menu = menu_to_use;
3096   menu->data = cryptkey_table;
3097
3098   {
3099       const char *ts;
3100
3101       if ((app & APPLICATION_PGP) && (app & APPLICATION_SMIME))
3102           ts = _("PGP and S/MIME keys matching");
3103       else if ((app & APPLICATION_PGP))
3104           ts = _("PGP keys matching");
3105       else if ((app & APPLICATION_SMIME))
3106           ts = _("S/MIME keys matching");
3107       else
3108           ts = _("keys matching");
3109
3110       if (p)
3111           snprintf (buf, sizeof (buf), _("%s <%s>."), ts, p->mailbox);
3112       else
3113           snprintf (buf, sizeof (buf), _("%s \"%s\"."), ts, s);
3114       menu->title = buf;
3115   }
3116
3117   mutt_clear_error ();
3118   k = NULL;
3119   while (!done) {
3120       *forced_valid = 0;
3121       switch (mutt_menuLoop (menu)) {
3122         case OP_VERIFY_KEY:
3123           verify_key (cryptkey_table[menu->current]);
3124           menu->redraw = REDRAW_FULL;
3125           break;
3126
3127         case OP_VIEW_ID:
3128           mutt_message ("%s", cryptkey_table[menu->current]->uid);
3129           break;
3130
3131         case OP_GENERIC_SELECT_ENTRY:
3132           /* FIXME make error reporting more verbose - this should be
3133              easy because gpgme provides more information */
3134           if (option (OPTPGPCHECKTRUST)) {
3135               if (cryptkey_table[menu->current]->flags & KEYFLAG_CANTUSE ) {
3136                   mutt_error(_("This key can't be used: "
3137                                "expired/disabled/revoked."));
3138                   break;
3139               }
3140           }
3141
3142           if (option (OPTPGPCHECKTRUST) &&
3143               ((cryptkey_table[menu->current]->flags & KEYFLAG_CANTUSE)
3144                || !crypt_id_is_strong (cryptkey_table[menu->current]))) {
3145               const char *warn_s;
3146               char buff[LONG_STRING];
3147
3148               if (cryptkey_table[menu->current]->flags & KEYFLAG_CANTUSE)
3149                   s = N_("ID is expired/disabled/revoked.");
3150               else {
3151                   gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
3152                   gpgme_user_id_t uid = NULL;
3153                   int j = 0;
3154
3155                   warn_s = "??";
3156
3157                   uid = cryptkey_table[menu->current]->kobj->uids;
3158                   for (j = 0; (j < cryptkey_table[menu->current]->idx) && uid;
3159                        j++, uid = uid->next);
3160                   if (uid)
3161                       val = uid->validity;
3162
3163                   switch (val) {
3164                     case GPGME_VALIDITY_UNKNOWN:
3165                     case GPGME_VALIDITY_UNDEFINED:
3166                       warn_s = N_("ID has undefined validity.");
3167                       break;
3168                     case GPGME_VALIDITY_NEVER:
3169                       warn_s = N_("ID is not valid.");
3170                       break;
3171                     case GPGME_VALIDITY_MARGINAL:
3172                       warn_s = N_("ID is only marginally valid.");
3173                       break;
3174                     case GPGME_VALIDITY_FULL:
3175                     case GPGME_VALIDITY_ULTIMATE:
3176                       break;
3177                   }
3178
3179                   snprintf (buff, sizeof (buff),
3180                             _("%s Do you really want to use the key?"), _(warn_s));
3181
3182                   if (mutt_yesorno (buff, 0) != 1) {
3183                       mutt_clear_error ();
3184                       break;
3185                   }
3186                   *forced_valid = 1;
3187               }
3188           }
3189
3190           k = cryptkey_dup(cryptkey_table[menu->current]);
3191           done = 1;
3192           break;
3193
3194         case OP_EXIT:
3195           k = NULL;
3196           done = 1;
3197           break;
3198       }
3199   }
3200
3201   mutt_menuDestroy (&menu);
3202   p_delete(&cryptkey_table);
3203
3204   set_option (OPTNEEDREDRAW);
3205
3206   return k;
3207 }
3208
3209 static cryptkey_t *
3210 crypt_getkeybyaddr(address_t * a, int abilities, int app, int *forced_valid)
3211 {
3212     address_t *r, *p;
3213
3214     int weak = 0;
3215     int invalid = 0;
3216     int multi = 0;
3217     int this_key_has_strong;
3218     int this_key_has_weak;
3219     int this_key_has_invalid;
3220     int match;
3221
3222     cryptkey_t *keys, *k;
3223     cryptkey_t *the_valid_key = NULL;
3224     cryptkey_t *matches = NULL;
3225     cryptkey_t **matches_endp = &matches;
3226
3227     *forced_valid = 0;
3228
3229     {
3230         string_array hints;
3231         string_array_init(&hints); 
3232         add_hints(&hints, a->mailbox);
3233         add_hints(&hints, a->personal);
3234
3235         mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
3236         keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3237         string_array_wipe(&hints);
3238     }
3239
3240     if (!keys)
3241         return NULL;
3242
3243     for (k = keys; k; k = k->next) {
3244         if (abilities && !(k->flags & abilities)) {
3245             continue;
3246         }
3247
3248         this_key_has_weak = 0;      /* weak but valid match   */
3249         this_key_has_invalid = 0;   /* invalid match          */
3250         this_key_has_strong = 0;    /* strong and valid match */
3251         match = 0;                  /* any match            */
3252
3253         r = rfc822_parse_adrlist (NULL, k->uid);
3254         for (p = r; p; p = p->next) {
3255             int validity = crypt_id_matches_addr (a, p, k);
3256
3257             if (validity & CRYPT_KV_MATCH)    /* something matches */
3258                 match = 1;
3259
3260             /* is this key a strong candidate? */
3261             if ((validity & CRYPT_KV_VALID)
3262                 && (validity & CRYPT_KV_STRONGID)
3263                 && (validity & CRYPT_KV_ADDR)) {
3264                 if (the_valid_key && the_valid_key != k)
3265                     multi = 1;
3266                 the_valid_key = k;
3267                 this_key_has_strong = 1;
3268             }
3269             else if ((validity & CRYPT_KV_MATCH)
3270                      && !(validity & CRYPT_KV_VALID))
3271                 this_key_has_invalid = 1;
3272             else if ((validity & CRYPT_KV_MATCH)
3273                      && (!(validity & CRYPT_KV_STRONGID)
3274                          || !(validity & CRYPT_KV_ADDR)))
3275                 this_key_has_weak = 1;
3276         }
3277         address_list_wipe(&r);
3278
3279         if (match) {
3280             cryptkey_t *tmp;
3281
3282             if (!this_key_has_strong && this_key_has_invalid)
3283                 invalid = 1;
3284             if (!this_key_has_strong && this_key_has_weak)
3285                 weak = 1;
3286
3287             *matches_endp = tmp = cryptkey_dup(k);
3288             matches_endp = &tmp->next;
3289             the_valid_key = tmp;
3290         }
3291     }
3292     key_list_wipe(&keys);
3293
3294     if (matches) {
3295         if (the_valid_key && !multi && !weak
3296             && !(invalid && option (OPTPGPSHOWUNUSABLE))) {
3297             /*
3298              * There was precisely one strong match on a valid ID, there
3299              * were no valid keys with weak matches, and we aren't
3300              * interested in seeing invalid keys.
3301              *
3302              * Proceed without asking the user.
3303              */
3304             k = cryptkey_dup(the_valid_key);
3305         } else {
3306             /*
3307              * Else: Ask the user.
3308              */
3309             k = crypt_select_key (matches, a, NULL, app, forced_valid);
3310         }
3311         key_list_wipe(&matches);
3312     } else {
3313         k = NULL;
3314     }
3315
3316     return k;
3317 }
3318
3319
3320 static cryptkey_t *
3321 crypt_getkeybystr(const char *p, int abilities, int app, int *forced_valid)
3322 {
3323   cryptkey_t *keys;
3324   cryptkey_t *matches = NULL;
3325   cryptkey_t **matches_endp = &matches;
3326   cryptkey_t *k;
3327   int match;
3328
3329   mutt_message (_("Looking for keys matching \"%s\"..."), p);
3330
3331   *forced_valid = 0;
3332
3333   {
3334       string_array hints;
3335       string_array_init(&hints);
3336       add_hints(&hints, p);
3337       keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3338       string_array_wipe(&hints);
3339   }
3340
3341   if (!keys)
3342     return NULL;
3343
3344   for (k = keys; k; k = k->next) {
3345     const char *s = crypt_keyid(k);
3346
3347     if (abilities && !(k->flags & abilities))
3348       continue;
3349
3350     match = 0;
3351
3352     if (!*p || !m_strcasecmp(p, s)
3353         || (!m_strncasecmp(p, "0x", 2) && !m_strcasecmp(p + 2, s))
3354         || m_stristr(k->uid, p))
3355     {
3356       cryptkey_t *tmp;
3357
3358       *matches_endp = tmp = cryptkey_dup(k);
3359       matches_endp = &tmp->next;
3360     }
3361   }
3362   key_list_wipe(&keys);
3363
3364   if (matches) {
3365     k = crypt_select_key (matches, NULL, p, app, forced_valid);
3366     key_list_wipe(&matches);
3367     return k;
3368   }
3369
3370   return NULL;
3371 }
3372
3373 /* Display TAG as a prompt to ask for a key.
3374  * ABILITIES describe the required key abilities (sign, encrypt) and APP the
3375  * type of the requested key; ether S/MIME or PGP.
3376  * Return a copy of the key or NULL if not found. */
3377 static cryptkey_t *
3378 crypt_ask_for_key(const char *tag, int abilities, int app, int *forced_valid)
3379 {
3380     cryptkey_t *key;
3381     char resp[STRING];
3382     int dummy;
3383
3384     if (!forced_valid)
3385         forced_valid = &dummy;
3386     *forced_valid = 0;
3387
3388     mutt_clear_error();
3389     for (;;) {
3390         resp[0] = 0;
3391         if (mutt_get_field(tag, resp, sizeof(resp), M_CLEAR) != 0)
3392             return NULL;
3393
3394         if (m_strisempty(resp))
3395             return NULL;
3396
3397         if ((key = crypt_getkeybystr(resp, abilities, app, forced_valid)))
3398             return key;
3399
3400         BEEP ();
3401     }
3402 }
3403
3404 /* This routine attempts to find the keyids of the recipients of a
3405    message.  It returns NULL if any of the keys can not be found.  */
3406 static char *find_keys(ENVELOPE *env, unsigned int app)
3407 {
3408     address_t *lst = NULL, *addr;
3409     buffer_t *keylist = buffer_new();
3410
3411     {
3412         address_t **last = &lst;
3413         *last = address_list_dup(env->to);
3414         last  = address_list_last(last);
3415         *last = address_list_dup(env->cc);
3416         last  = address_list_last(last);
3417         *last = address_list_dup(env->bcc);
3418
3419         rfc822_qualify(lst, mutt_fqdn(1));
3420         address_list_uniq(lst);
3421     }
3422
3423     while ((addr = address_list_pop(&lst))) {
3424         char buf[STRING];
3425         int forced_valid = 0;
3426         const char *keyID;
3427         cryptkey_t *key = NULL;
3428
3429         if ((keyID = mutt_crypt_hook(addr))) {
3430             int r;
3431
3432             snprintf(buf, sizeof(buf), _("Use keyID = \"%s\" for %s?"), keyID,
3433                      addr->mailbox);
3434             r = mutt_yesorno(buf, M_YES);
3435
3436             if (r == -1) {
3437                 address_list_wipe(&lst);
3438                 address_list_wipe(&addr);
3439                 buffer_delete(&keylist);
3440                 return NULL;
3441             }
3442
3443             if (r == M_YES) {
3444                 address_t *a;
3445                 /* check for e-mail address */
3446                 if (strchr(keyID, '@') && (a = rfc822_parse_adrlist(NULL, keyID))) {
3447                     rfc822_qualify(a, mutt_fqdn(1));
3448                     address_list_wipe(&addr);
3449                     addr = a;
3450                 } else {
3451                     key = crypt_getkeybystr(keyID, KEYFLAG_CANENCRYPT, app,
3452                                             &forced_valid);
3453                 }
3454             }
3455         }
3456
3457         if (!key) {
3458             key = crypt_getkeybyaddr(addr, KEYFLAG_CANENCRYPT, app, &forced_valid);
3459         }
3460         if (!key) {
3461             snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), addr->mailbox);
3462             key = crypt_ask_for_key(buf, KEYFLAG_CANENCRYPT, app,
3463                                     &forced_valid);
3464             if (!key) {
3465                 address_list_wipe(&lst);
3466                 address_list_wipe(&addr);
3467                 buffer_delete(&keylist);
3468                 return NULL;
3469             }
3470         }
3471
3472         if (keylist->len)
3473             buffer_addch(keylist, ' ');
3474         buffer_addstr(keylist, "0x");
3475         buffer_addstr(keylist, crypt_fpr(key));
3476         if (forced_valid)
3477             buffer_addch(keylist, '!');
3478
3479         key_list_wipe(&key);
3480         address_list_wipe(&addr);
3481     }
3482
3483     address_list_wipe(&lst);
3484     return buffer_unwrap(&keylist);
3485 }
3486
3487 int crypt_get_keys(HEADER *msg, char **keylist)
3488 {
3489     /* Do a quick check to make sure that we can find all of the encryption
3490      * keys if the user has requested this service.
3491      */
3492
3493     *keylist = NULL;
3494
3495     if (msg->security & ENCRYPT) {
3496         if (msg->security & APPLICATION_PGP) {
3497             set_option(OPTPGPCHECKTRUST);
3498             *keylist = find_keys(msg->env, APPLICATION_PGP);
3499             unset_option(OPTPGPCHECKTRUST);
3500             if (!*keylist)
3501                 return -1;
3502         }
3503
3504         if (msg->security & APPLICATION_SMIME) {
3505             *keylist = find_keys(msg->env, APPLICATION_SMIME);
3506             if (!*keylist)
3507                 return -1;
3508         }
3509     }
3510
3511     return 0;
3512 }
3513
3514
3515 int crypt_send_menu (HEADER * msg, int *redraw, int is_smime)
3516 {
3517     cryptkey_t *p;
3518     char buf[STRING];
3519     int choice;
3520
3521     if (msg->security & APPLICATION_SMIME)
3522         is_smime = 1;
3523     if (msg->security & APPLICATION_PGP)
3524         is_smime = 0;
3525
3526     choice = is_smime
3527         ? mutt_multi_choice(_("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?"),
3528                             _("esabpc"))
3529         : mutt_multi_choice(_("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?"),
3530                             _("esabmc"));
3531
3532     switch (choice) {
3533       case 1:                      /* (e)ncrypt */
3534         msg->security |= (is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3535         msg->security &= ~(is_smime ? SMIMESIGN : PGPSIGN);
3536         break;
3537
3538       case 2:                      /* (s)ign */
3539         msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3540         msg->security &= ~(is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3541         break;
3542
3543       case 3:                      /* sign (a)s */
3544         p = crypt_ask_for_key(_("Sign as: "), KEYFLAG_CANSIGN,
3545                               is_smime ?  APPLICATION_SMIME : APPLICATION_PGP,
3546                               NULL);
3547         if (p) {
3548             snprintf(buf, sizeof(buf), "0x%s", crypt_keyid(p));
3549             m_strreplace(is_smime ? &SmimeDefaultKey : &PgpSignAs, buf);
3550             key_list_wipe(&p);
3551             msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3552         }
3553         *redraw = REDRAW_FULL;
3554         break;
3555
3556       case 4:                      /* (b)oth */
3557         if (is_smime) {
3558             msg->security = SMIMEENCRYPT | SMIMESIGN;
3559         } else {
3560             msg->security = PGPENCRYPT | PGPSIGN;
3561         }
3562         break;
3563
3564       case 5:                      /* (p)gp or s/(m)ime */
3565         is_smime = !is_smime;
3566         break;
3567
3568       case 6:                      /* (c)lear */
3569         return msg->security = 0;
3570     }
3571
3572     if (is_smime) {
3573         msg->security &= ~APPLICATION_PGP;
3574         msg->security |= APPLICATION_SMIME;
3575     } else {
3576         msg->security &= ~APPLICATION_SMIME;
3577         msg->security |= APPLICATION_PGP;
3578     }
3579
3580     return msg->security;
3581 }
3582
3583 int crypt_smime_verify_sender(HEADER *h)
3584 {
3585     address_t *sender = NULL;
3586     unsigned int ret = 1;
3587
3588     if (h->env->from) {
3589         h->env->from = mutt_expand_aliases(h->env->from);
3590         sender = h->env->from;
3591     } else if (h->env->sender) {
3592         h->env->sender = mutt_expand_aliases (h->env->sender);
3593         sender = h->env->sender;
3594     }
3595
3596     if (!sender) {
3597         mutt_any_key_to_continue ("Failed to figure out sender");
3598         goto end;
3599     }
3600
3601     if (signature_key) {
3602         gpgme_key_t key = signature_key;
3603         gpgme_user_id_t uid = NULL;
3604         int sender_length = 0;
3605         int uid_length = 0;
3606
3607         sender_length = m_strlen(sender->mailbox);
3608         for (uid = key->uids; uid && ret; uid = uid->next) {
3609             uid_length = m_strlen(uid->email);
3610             if (1 && (uid->email[0] == '<')
3611                 && (uid->email[uid_length - 1] == '>')
3612                 && (uid_length == sender_length + 2)
3613                 && (!m_strncmp (uid->email + 1, sender->mailbox, sender_length)))
3614                 ret = 0;
3615         }
3616     } else {
3617         mutt_any_key_to_continue ("Failed to verify sender");
3618     }
3619
3620   end:
3621     if (signature_key) {
3622         gpgme_key_unref(signature_key);
3623         signature_key = NULL;
3624     }
3625     return ret;
3626 }
3627
3628 static void crypt_invoke_import(FILE *stream, int smime)
3629 {
3630     gpgme_ctx_t ctx = create_gpgme_context(smime);
3631     gpgme_data_t data;
3632     gpgme_error_t err;
3633
3634     err = gpgme_data_new_from_stream(&data, stream);
3635     if (err) {
3636         mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
3637         gpgme_release(ctx);
3638         return;
3639     }
3640
3641     err = gpgme_op_import(ctx, data);
3642     if (err) {
3643         mutt_error(_("error importing gpg data: %s\n"), gpgme_strerror(err));
3644         gpgme_data_release(data);
3645         gpgme_release(ctx);
3646         return;
3647     }
3648
3649     gpgme_data_release(data);
3650     gpgme_release(ctx);
3651     return;
3652 }
3653
3654 static void pgp_extract_keys_from_attachment(FILE * fp, BODY * top)
3655 {
3656     STATE s;
3657     FILE *tmpfp = tmpfile();
3658
3659     if (tmpfp == NULL) {
3660         mutt_perror (_("Can't create temporary file"));
3661         return;
3662     }
3663
3664     p_clear(&s, 1);
3665     s.fpin  = fp;
3666     s.fpout = tmpfp;
3667     mutt_body_handler(top, &s);
3668
3669     rewind(tmpfp);
3670     crypt_invoke_import(tmpfp, 0);
3671     m_fclose(&tmpfp);
3672 }
3673
3674 void crypt_pgp_extract_keys_from_attachment_list(FILE * fp, int tag, BODY * top)
3675 {
3676     mutt_endwin (NULL);
3677
3678     for (; top; top = top->next) {
3679         if (!tag || top->tagged)
3680             pgp_extract_keys_from_attachment (fp, top);
3681
3682         if (!tag)
3683             break;
3684     }
3685 }
3686
3687 void crypt_invoke_message (int type)
3688 {
3689     if (type & APPLICATION_PGP) {
3690         mutt_message _("Invoking PGP...");
3691     }
3692     else if (type & APPLICATION_SMIME) {
3693         mutt_message _("Invoking S/MIME...");
3694     }
3695 }
3696
3697 int mutt_protect (HEADER * msg, char *keylist)
3698 {
3699   BODY *pbody = NULL, *tmp_pbody = NULL;
3700   BODY *tmp_smime_pbody = NULL;
3701   BODY *tmp_pgp_pbody = NULL;
3702   int flags = msg->security;
3703
3704   if (!isendwin ())
3705     mutt_endwin (NULL);
3706
3707   tmp_smime_pbody = msg->content;
3708   tmp_pgp_pbody = msg->content;
3709
3710   if (msg->security & SIGN) {
3711     if (msg->security & APPLICATION_SMIME) {
3712       if (!(tmp_pbody = sign_message(msg->content, 1)))
3713         return -1;
3714       pbody = tmp_smime_pbody = tmp_pbody;
3715     }
3716
3717     if ((msg->security & APPLICATION_PGP)
3718         && (!(flags & ENCRYPT) || option (OPTPGPRETAINABLESIG))) {
3719       if (!(tmp_pbody = sign_message(msg->content, 0)))
3720         return -1;
3721
3722       flags &= ~SIGN;
3723       pbody = tmp_pgp_pbody = tmp_pbody;
3724     }
3725
3726     if ((msg->security & APPLICATION_SMIME)
3727         && (msg->security & APPLICATION_PGP)) {
3728       /* here comes the draft ;-) */
3729     }
3730   }
3731
3732
3733   if (msg->security & ENCRYPT) {
3734     if ((msg->security & APPLICATION_SMIME)) {
3735       if (!(tmp_pbody = crypt_smime_build_smime_entity (tmp_smime_pbody,
3736                                                         keylist))) {
3737         /* signed ? free it! */
3738         return (-1);
3739       }
3740       /* free tmp_body if messages was signed AND encrypted ... */
3741       if (tmp_smime_pbody != msg->content && tmp_smime_pbody != tmp_pbody) {
3742         /* detatch and dont't delete msg->content,
3743            which tmp_smime_pbody->parts after signing. */
3744         tmp_smime_pbody->parts = tmp_smime_pbody->parts->next;
3745         msg->content->next = NULL;
3746         body_list_wipe(&tmp_smime_pbody);
3747       }
3748       pbody = tmp_pbody;
3749     }
3750
3751     if ((msg->security & APPLICATION_PGP)) {
3752       if (!(pbody = crypt_pgp_encrypt_message (tmp_pgp_pbody, keylist,
3753                                                flags & SIGN))) {
3754
3755         /* did we perform a retainable signature? */
3756         if (flags != msg->security) {
3757           /* remove the outer multipart layer */
3758           tmp_pgp_pbody = mutt_remove_multipart (tmp_pgp_pbody);
3759           /* get rid of the signature */
3760           body_list_wipe(&tmp_pgp_pbody->next);
3761         }
3762
3763         return (-1);
3764       }
3765
3766       /* destroy temporary signature envelope when doing retainable 
3767        * signatures.
3768
3769        */
3770       if (flags != msg->security) {
3771         tmp_pgp_pbody = mutt_remove_multipart (tmp_pgp_pbody);
3772         body_list_wipe(&tmp_pgp_pbody->next);
3773       }
3774     }
3775   }
3776
3777   if (pbody)
3778     msg->content = pbody;
3779
3780   return 0;
3781 }
3782
3783
3784 int crypt_query (BODY * m)
3785 {
3786   int t = 0;
3787
3788   if (!m)
3789     return 0;
3790
3791   if (m->type == TYPEAPPLICATION) {
3792     t |= mutt_is_application_pgp (m);
3793
3794     t |= mutt_is_application_smime (m);
3795     if (t && m->goodsig)
3796       t |= GOODSIGN;
3797     if (t && m->badsig)
3798       t |= BADSIGN;
3799   }
3800   else if (m->type == TYPETEXT) {
3801     t |= mutt_is_application_pgp (m);
3802     if (t && m->goodsig)
3803       t |= GOODSIGN;
3804   }
3805
3806   if (m->type == TYPEMULTIPART) {
3807     t |= mutt_is_multipart_encrypted (m);
3808     t |= mutt_is_multipart_signed (m);
3809
3810     if (t && m->goodsig)
3811       t |= GOODSIGN;
3812   }
3813
3814   if (m->type == TYPEMULTIPART || m->type == TYPEMESSAGE) {
3815     BODY *p;
3816     int u, v, w;
3817
3818     u = m->parts ? ~0 : 0;      /* Bits set in all parts */
3819     w = 0;                      /* Bits set in any part  */
3820
3821     for (p = m->parts; p; p = p->next) {
3822       v = crypt_query (p);
3823       u &= v;
3824       w |= v;
3825     }
3826     t |= u | (w & ~GOODSIGN);
3827
3828     if ((w & GOODSIGN) && !(u & GOODSIGN))
3829       t |= PARTSIGN;
3830   }
3831
3832   return t;
3833 }
3834
3835
3836 static void crypt_write_signed(BODY * a, STATE * s, FILE *fp)
3837 {
3838     int c;
3839     short hadcr;
3840     size_t bytes;
3841
3842     fseeko (s->fpin, a->hdr_offset, 0);
3843     bytes = a->length + a->offset - a->hdr_offset;
3844     hadcr = 0;
3845     while (bytes > 0) {
3846         if ((c = fgetc (s->fpin)) == EOF)
3847             break;
3848
3849         bytes--;
3850
3851         if (c == '\r')
3852             hadcr = 1;
3853         else {
3854             if (c == '\n' && !hadcr)
3855                 fputc ('\r', fp);
3856
3857             hadcr = 0;
3858         }
3859         fputc (c, fp);
3860     }
3861 }
3862
3863 static void extract_keys_aux(FILE *fpout, HEADER *h)
3864 {
3865     mutt_parse_mime_message (Context, h);
3866
3867     rewind(fpout);
3868     if (h->security & APPLICATION_PGP) {
3869         mutt_copy_message(fpout, Context, h, M_CM_DECODE | M_CM_CHARCONV, 0);
3870         fflush (fpout);
3871
3872         mutt_endwin (_("Trying to extract PGP keys...\n"));
3873     }
3874
3875     if (h->security & APPLICATION_SMIME) {
3876         if (h->security & ENCRYPT)
3877             mutt_copy_message (fpout, Context, h, M_CM_NOHEADER
3878                                | M_CM_DECODE_CRYPT | M_CM_DECODE_SMIME, 0);
3879         else
3880             mutt_copy_message(fpout, Context, h, 0, 0);
3881         fflush (fpout);
3882
3883         mutt_message (_("Trying to extract S/MIME certificates...\n"));
3884     }
3885
3886     rewind(fpout);
3887     crypt_invoke_import(fpout, h->security & APPLICATION_SMIME);
3888 }
3889
3890 void crypt_extract_keys_from_messages(HEADER * h)
3891 {
3892     FILE *tmpfp = tmpfile();
3893     if (!tmpfp) {
3894         mutt_error(_("Could not create temporary file"));
3895         return;
3896     }
3897
3898     if (!h) {
3899         int i;
3900         for (i = 0; i < Context->vcount; i++) {
3901             if (!Context->hdrs[Context->v2r[i]]->tagged)
3902                 continue;
3903             extract_keys_aux(tmpfp, Context->hdrs[Context->v2r[i]]);
3904         }
3905     } else {
3906         extract_keys_aux(tmpfp, h);
3907     }
3908     m_fclose(&tmpfp);
3909
3910     if (isendwin())
3911         mutt_any_key_to_continue(NULL);
3912 }
3913
3914 static void crypt_fetch_signatures(BODY ***signatures, BODY * a, int *n)
3915 {
3916     for (; a; a = a->next) {
3917         if (a->type == TYPEMULTIPART) {
3918             crypt_fetch_signatures(signatures, a->parts, n);
3919         } else {
3920             if ((*n % 5) == 0)
3921                 p_realloc(signatures, *n + 6);
3922
3923             (*signatures)[(*n)++] = a;
3924         }
3925     }
3926 }
3927
3928 int mutt_signed_handler(BODY *a, STATE *s)
3929 {
3930   unsigned major, minor;
3931   char *protocol;
3932   int rc, i, goodsig = 1, sigcnt = 0;
3933   BODY *b = a;
3934
3935   protocol = parameter_getval(a->parameter, "protocol");
3936   a = a->parts;
3937
3938   switch (mime_which_token(protocol, -1)) {
3939     case MIME_APPLICATION_PGP_SIGNATURE:
3940       major = TYPEAPPLICATION;
3941       minor = MIME_PGP_SIGNATURE;
3942       break;
3943     case MIME_APPLICATION_X_PKCS7_SIGNATURE:
3944       major = TYPEAPPLICATION;
3945       minor = MIME_X_PKCS7_SIGNATURE;
3946       break;
3947     case MIME_APPLICATION_PKCS7_SIGNATURE:
3948       major = TYPEAPPLICATION;
3949       minor = MIME_PKCS7_SIGNATURE;
3950       break;
3951     case MIME_MULTIPART_MIXED:
3952       major = TYPEMULTIPART;
3953       minor = MIME_MIXED;
3954       break;
3955
3956     default:
3957       state_printf(s, _("[-- Error: "
3958                         "Unknown multipart/signed protocol %s! --]\n\n"),
3959                     protocol);
3960       return mutt_body_handler (a, s);
3961   }
3962
3963   /* consistency check */
3964   if (!(a && a->next && a->next->type == major &&
3965         mime_which_token(a->next->subtype, -1) == minor))
3966   {
3967     state_attach_puts(_("[-- Error: "
3968                         "Inconsistent multipart/signed structure! --]\n\n"),
3969                       s);
3970     return mutt_body_handler (a, s);
3971   }
3972
3973   if (s->flags & M_DISPLAY) {
3974     BODY **sigs = NULL;
3975
3976     crypt_fetch_signatures (&sigs, a->next, &sigcnt);
3977     if (sigcnt) {
3978       FILE *tmpfp = tmpfile();
3979
3980       if (!tmpfp) {
3981           mutt_error(_("Could not create temporary file"));
3982       } else {
3983         crypt_write_signed(a, s, tmpfp);
3984         rewind(tmpfp);
3985         for (i = 0; i < sigcnt; i++) {
3986           if (sigs[i]->type == TYPEAPPLICATION) {
3987             int subtype;
3988
3989             switch ((subtype = mime_which_token(sigs[i]->subtype, -1))) {
3990               case MIME_PGP_SIGNATURE:
3991               case MIME_X_PKCS7_SIGNATURE:
3992               case MIME_PKCS7_SIGNATURE:
3993                 if (crypt_verify_one(sigs[i], s, tmpfp, subtype != MIME_PGP_SIGNATURE) != 0)
3994                   goodsig = 0;
3995
3996                 m_fclose(&tmpfp);
3997                 continue;
3998
3999               default:
4000                 break;
4001             }
4002           }
4003
4004           state_printf(s, _("[-- Warning: "
4005                             "We can't verify %s/%s signatures. --]\n\n"),
4006                        TYPE (sigs[i]), sigs[i]->subtype);
4007         }
4008       }
4009
4010       b->goodsig = goodsig;
4011       b->badsig  = !goodsig;
4012
4013       /* Now display the signed body */
4014       state_attach_puts(_("[-- The following data is signed --]\n\n"), s);
4015
4016       p_delete(&sigs);
4017     } else {
4018       state_attach_puts(_("[-- Warning: Can't find any signatures. --]\n\n"),
4019                         s);
4020     }
4021   }
4022
4023   rc = mutt_body_handler (a, s);
4024
4025   if (s->flags & M_DISPLAY && sigcnt)
4026     state_attach_puts (_("\n[-- End of signed data --]\n"), s);
4027
4028   return (rc);
4029 }
4030
4031 static int _mutt_check_traditional_pgp (HEADER * h, int *redraw)
4032 {
4033   MESSAGE *msg;
4034   int rv = 0;
4035
4036   h->security |= PGP_TRADITIONAL_CHECKED;
4037
4038   mutt_parse_mime_message (Context, h);
4039   if ((msg = mx_open_message (Context, h->msgno)) == NULL)
4040     return 0;
4041   if (crypt_pgp_check_traditional (msg->fp, h->content, 0)) {
4042     h->security = crypt_query (h->content);
4043     *redraw |= REDRAW_FULL;
4044     rv = 1;
4045   }
4046
4047   h->security |= PGP_TRADITIONAL_CHECKED;
4048   mx_close_message (&msg);
4049   return rv;
4050 }
4051
4052 int mutt_check_traditional_pgp (HEADER * h, int *redraw)
4053 {
4054   int i;
4055   int rv = 0;
4056
4057   if (h && !(h->security & PGP_TRADITIONAL_CHECKED))
4058     rv = _mutt_check_traditional_pgp (h, redraw);
4059   else {
4060     for (i = 0; i < Context->vcount; i++)
4061       if (Context->hdrs[Context->v2r[i]]->tagged &&
4062           !(Context->hdrs[Context->v2r[i]]->
4063             security & PGP_TRADITIONAL_CHECKED))
4064         rv =
4065           _mutt_check_traditional_pgp (Context->hdrs[Context->v2r[i]], redraw)
4066           || rv;
4067   }
4068   return rv;
4069 }
4070
4071 /* vim:set ft=c: */