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