00a32851cce6fe68e9c3087c08a1a4f68721fae3
[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           : _crypt_compare_address (a, b));
2293 }
2294
2295
2296 /* Compare two key IDs and the addresses to be used for sorting. */
2297 static int _crypt_compare_keyid (const void *a, const void *b)
2298 {
2299   cryptkey_t **s = (cryptkey_t **) a;
2300   cryptkey_t **t = (cryptkey_t **) b;
2301   int r;
2302
2303   if ((r = m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t))))
2304     return r > 0;
2305   else
2306     return m_strcasecmp((*s)->uid, (*t)->uid) > 0;
2307 }
2308
2309 static int crypt_compare_keyid (const void *a, const void *b)
2310 {
2311   return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_keyid (a, b)
2312           : _crypt_compare_keyid (a, b));
2313 }
2314
2315 /* Compare 2 creation dates and the addresses.  For sorting. */
2316 static int _crypt_compare_date (const void *a, const void *b)
2317 {
2318   cryptkey_t **s = (cryptkey_t **) a;
2319   cryptkey_t **t = (cryptkey_t **) b;
2320   unsigned long ts = 0, tt = 0;
2321
2322   if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2323     ts = (*s)->kobj->subkeys->timestamp;
2324   if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2325     tt = (*t)->kobj->subkeys->timestamp;
2326
2327   if (ts > tt)
2328     return 1;
2329   if (ts < tt)
2330     return 0;
2331
2332   return m_strcasecmp((*s)->uid, (*t)->uid) > 0;
2333 }
2334
2335 static int crypt_compare_date (const void *a, const void *b)
2336 {
2337   return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_date (a, b)
2338           : _crypt_compare_date (a, b));
2339 }
2340
2341 /* Compare two trust values, the key length, the creation dates. the
2342    addresses and the key IDs.  For sorting. */
2343 static int _crypt_compare_trust (const void *a, const void *b)
2344 {
2345   cryptkey_t **s = (cryptkey_t **) a;
2346   cryptkey_t **t = (cryptkey_t **) b;
2347   unsigned long ts = 0, tt = 0;
2348   int r;
2349
2350   if ((r = (((*s)->flags & (KEYFLAG_RESTRICTIONS))
2351             - ((*t)->flags & (KEYFLAG_RESTRICTIONS)))))
2352     return r > 0;
2353
2354   if ((*s)->kobj->uids)
2355     ts = (*s)->kobj->uids->validity;
2356   if ((*t)->kobj->uids)
2357     tt = (*t)->kobj->uids->validity;
2358   if ((r = (tt - ts)))
2359     return r < 0;
2360
2361   if ((*s)->kobj->subkeys)
2362     ts = (*s)->kobj->subkeys->length;
2363   if ((*t)->kobj->subkeys)
2364     tt = (*t)->kobj->subkeys->length;
2365   if (ts != tt)
2366     return ts > tt;
2367
2368   if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2369     ts = (*s)->kobj->subkeys->timestamp;
2370   if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2371     tt = (*t)->kobj->subkeys->timestamp;
2372   if (ts > tt)
2373     return 1;
2374   if (ts < tt)
2375     return 0;
2376
2377   if ((r = m_strcasecmp((*s)->uid, (*t)->uid)))
2378     return r > 0;
2379   return (m_strcasecmp(crypt_keyid ((*s)), crypt_keyid ((*t)))) > 0;
2380 }
2381
2382 static int crypt_compare_trust (const void *a, const void *b)
2383 {
2384   return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_trust (a, b)
2385           : _crypt_compare_trust (a, b));
2386 }
2387
2388 /* Print the X.500 Distinguished Name part KEY from the array of parts
2389    DN to FP. */
2390 static int print_dn_part (FILE * fp, struct dn_array_s *dn, const char *key)
2391 {
2392   int any = 0;
2393
2394   for (; dn->key; dn++) {
2395     if (!m_strcmp(dn->key, key)) {
2396       if (any)
2397         fputs (" + ", fp);
2398       print_utf8 (fp, dn->value, m_strlen(dn->value));
2399       any = 1;
2400     }
2401   }
2402   return any;
2403 }
2404
2405 /* Print all parts of a DN in a standard sequence. */
2406 static void print_dn_parts (FILE * fp, struct dn_array_s *dn)
2407 {
2408   const char *stdpart[] = {
2409     "CN", "OU", "O", "STREET", "L", "ST", "C", NULL
2410   };
2411   int any = 0, any2 = 0, i;
2412
2413   for (i = 0; stdpart[i]; i++) {
2414     if (any)
2415       fputs (", ", fp);
2416     any = print_dn_part (fp, dn, stdpart[i]);
2417   }
2418   /* now print the rest without any specific ordering */
2419   for (; dn->key; dn++) {
2420     for (i = 0; stdpart[i]; i++) {
2421       if (!m_strcmp(dn->key, stdpart[i]))
2422         break;
2423     }
2424     if (!stdpart[i]) {
2425       if (any)
2426         fputs (", ", fp);
2427       if (!any2)
2428         fputs ("(", fp);
2429       any = print_dn_part (fp, dn, dn->key);
2430       any2 = 1;
2431     }
2432   }
2433   if (any2)
2434     fputs (")", fp);
2435 }
2436
2437
2438 /* Parse an RDN; this is a helper to parse_dn(). */
2439 static const unsigned char *parse_dn_part (struct dn_array_s *array,
2440                                            const unsigned char *string)
2441 {
2442   const unsigned char *s, *s1;
2443   ssize_t n;
2444   unsigned char *p;
2445
2446   /* parse attributeType */
2447   for (s = string + 1; *s && *s != '='; s++);
2448   if (!*s)
2449     return NULL;                /* error */
2450   n = s - string;
2451   if (!n)
2452     return NULL;                /* empty key */
2453   array->key = p_dupstr(string, n );
2454   p = (unsigned char *) array->key;
2455   string = s + 1;
2456
2457   if (*string == '#') {         /* hexstring */
2458     string++;
2459     for (s = string; hexval(*s) >= 0; s++)
2460       s++;
2461     n = s - string;
2462     if (!n || (n & 1))
2463       return NULL;              /* empty or odd number of digits */
2464     n /= 2;
2465     p = p_new(unsigned char, n + 1);
2466     array->value = (char *) p;
2467     for (s1 = string; n; s1 += 2, n--)
2468       *p++ = (hexval(*s1) << 8) | hexval(*s1);
2469     *p = 0;
2470   }
2471   else {                        /* regular v3 quoted string */
2472     for (n = 0, s = string; *s; s++) {
2473       if (*s == '\\') {         /* pair */
2474         s++;
2475         if (*s == ',' || *s == '=' || *s == '+'
2476             || *s == '<' || *s == '>' || *s == '#' || *s == ';'
2477             || *s == '\\' || *s == '"' || *s == ' ')
2478           n++;
2479         else if (hexval(*s) >= 0 && hexval(*s + 1) >= 0) {
2480           s++;
2481           n++;
2482         }
2483         else
2484           return NULL;          /* invalid escape sequence */
2485       }
2486       else if (*s == '"')
2487         return NULL;            /* invalid encoding */
2488       else if (*s == ',' || *s == '=' || *s == '+'
2489                || *s == '<' || *s == '>' || *s == '#' || *s == ';')
2490         break;
2491       else
2492         n++;
2493     }
2494
2495     p = p_new(unsigned char, n + 1);
2496     array->value = (char *) p;
2497     for (s = string; n; s++, n--) {
2498       if (*s == '\\') {
2499         s++;
2500         if (hexval(*s) >= 0) {
2501           *p++ = (hexval(*s) << 8) | hexval(*s + 1);
2502           s++;
2503         }
2504         else
2505           *p++ = *s;
2506       }
2507       else
2508         *p++ = *s;
2509     }
2510     *p = 0;
2511   }
2512   return s;
2513 }
2514
2515
2516 /* Parse a DN and return an array-ized one.  This is not a validating
2517    parser and it does not support any old-stylish syntax; gpgme is
2518    expected to return only rfc2253 compatible strings. */
2519 static struct dn_array_s *parse_dn (const unsigned char *string)
2520 {
2521   struct dn_array_s *array;
2522   ssize_t arrayidx, arraysize;
2523   int i;
2524
2525   arraysize = 7;                /* C,ST,L,O,OU,CN,email */
2526   array = p_new(struct dn_array_s, arraysize + 1);
2527   arrayidx = 0;
2528   while (*string) {
2529     while (*string == ' ')
2530       string++;
2531     if (!*string)
2532       break;                    /* ready */
2533     if (arrayidx >= arraysize) {        /* mutt lacks a real safe_realoc - so we need to copy */
2534       struct dn_array_s *a2;
2535
2536       arraysize += 5;
2537       a2 = p_new(struct dn_array_s, arraysize + 1);
2538       for (i = 0; i < arrayidx; i++) {
2539         a2[i].key = array[i].key;
2540         a2[i].value = array[i].value;
2541       }
2542       p_delete(&array);
2543       array = a2;
2544     }
2545     array[arrayidx].key = NULL;
2546     array[arrayidx].value = NULL;
2547     string = parse_dn_part (array + arrayidx, string);
2548     arrayidx++;
2549     if (!string)
2550       goto failure;
2551     while (*string == ' ')
2552       string++;
2553     if (*string && *string != ',' && *string != ';' && *string != '+')
2554       goto failure;             /* invalid delimiter */
2555     if (*string)
2556       string++;
2557   }
2558   array[arrayidx].key = NULL;
2559   array[arrayidx].value = NULL;
2560   return array;
2561
2562 failure:
2563   for (i = 0; i < arrayidx; i++) {
2564     p_delete(&array[i].key);
2565     p_delete(&array[i].value);
2566   }
2567   p_delete(&array);
2568   return NULL;
2569 }
2570
2571
2572 /* Print a nice representation of the USERID and make sure it is
2573    displayed in a proper way, which does mean to reorder some parts
2574    for S/MIME's DNs.  USERID is a string as returned by the gpgme key
2575    functions.  It is utf-8 encoded. */
2576 static void parse_and_print_user_id(FILE * fp, const char *userid)
2577 {
2578   const char *s;
2579   int i;
2580
2581   if (*userid == '<') {
2582     s = strchr (userid + 1, '>');
2583     if (s)
2584       print_utf8 (fp, userid + 1, s - userid - 1);
2585   }
2586   else if (*userid == '(')
2587     fputs (_("[Can't display this user ID (unknown encoding)]"), fp);
2588   else if (*userid & ~127 || __m_strdigits[(int)*userid] == 255)
2589     fputs (_("[Can't display this user ID (invalid encoding)]"), fp);
2590   else {
2591     struct dn_array_s *dn = parse_dn ((const unsigned char *) userid);
2592
2593     if (!dn)
2594       fputs (_("[Can't display this user ID (invalid DN)]"), fp);
2595     else {
2596       print_dn_parts (fp, dn);
2597       for (i = 0; dn[i].key; i++) {
2598         p_delete(&dn[i].key);
2599         p_delete(&dn[i].value);
2600       }
2601       p_delete(&dn);
2602     }
2603   }
2604 }
2605
2606 typedef enum {
2607     KEY_CAP_CAN_ENCRYPT,
2608     KEY_CAP_CAN_SIGN,
2609     KEY_CAP_CAN_CERTIFY
2610 } key_cap_t;
2611
2612 static unsigned int key_check_cap(gpgme_key_t key, key_cap_t cap)
2613 {
2614   gpgme_subkey_t subkey = NULL;
2615   unsigned int ret = 0;
2616
2617   switch (cap) {
2618   case KEY_CAP_CAN_ENCRYPT:
2619     if (!(ret = key->can_encrypt))
2620       for (subkey = key->subkeys; subkey; subkey = subkey->next)
2621         if ((ret = subkey->can_encrypt))
2622           break;
2623     break;
2624   case KEY_CAP_CAN_SIGN:
2625     if (!(ret = key->can_sign))
2626       for (subkey = key->subkeys; subkey; subkey = subkey->next)
2627         if ((ret = subkey->can_sign))
2628           break;
2629     break;
2630   case KEY_CAP_CAN_CERTIFY:
2631     if (!(ret = key->can_certify))
2632       for (subkey = key->subkeys; subkey; subkey = subkey->next)
2633         if ((ret = subkey->can_certify))
2634           break;
2635     break;
2636   }
2637
2638   return ret;
2639 }
2640
2641
2642 /* Print verbose information about a key or certificate to FP. */
2643 static void print_key_info (gpgme_key_t key, FILE * fp)
2644 {
2645   int idx;
2646   const char *s = NULL, *s2 = NULL;
2647   time_t tt = 0;
2648   struct tm *tm;
2649   char shortbuf[STRING];
2650   unsigned long aval = 0;
2651   const char *delim;
2652   int is_pgp = 0;
2653   int i;
2654   gpgme_user_id_t uid = NULL;
2655
2656   if (Locale)
2657     setlocale (LC_TIME, Locale);
2658
2659   is_pgp = key->protocol == GPGME_PROTOCOL_OpenPGP;
2660
2661   for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
2662     if (uid->revoked)
2663       continue;
2664
2665     s = uid->uid;
2666     fputs (idx ? _(" aka ......: ") :_("Name ......: "), fp);
2667
2668     if (uid->invalid) {
2669       fputs (_("[Invalid]"), fp);
2670       putc (' ', fp);
2671     }
2672     if (is_pgp)
2673       print_utf8 (fp, s, m_strlen(s));
2674     else
2675       parse_and_print_user_id (fp, s);
2676     putc ('\n', fp);
2677   }
2678
2679   if (key->subkeys && (key->subkeys->timestamp > 0)) {
2680     tt = key->subkeys->timestamp;
2681
2682     tm = localtime (&tt);
2683 #ifdef D_T_FMT
2684     strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2685 #else
2686     strftime (shortbuf, sizeof shortbuf, "%c", tm);
2687 #endif
2688     fprintf (fp, _("Valid From : %s\n"), shortbuf);
2689   }
2690
2691   if (key->subkeys && (key->subkeys->expires > 0)) {
2692     tt = key->subkeys->expires;
2693
2694     tm = localtime (&tt);
2695 #ifdef D_T_FMT
2696     strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2697 #else
2698     strftime (shortbuf, sizeof shortbuf, "%c", tm);
2699 #endif
2700     fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2701   }
2702
2703   if (key->subkeys)
2704     s = gpgme_pubkey_algo_name (key->subkeys->pubkey_algo);
2705   else
2706     s = "?";
2707
2708   s2 = is_pgp ? "PGP" : "X.509";
2709
2710   if (key->subkeys)
2711     aval = key->subkeys->length;
2712
2713   fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), s2, aval, s);
2714
2715   fprintf (fp, _("Key Usage .: "));
2716   delim = "";
2717
2718   if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT)) {
2719     fprintf (fp, "%s%s", delim, _("encryption"));
2720     delim = _(", ");
2721   }
2722   if (key_check_cap (key, KEY_CAP_CAN_SIGN)) {
2723     fprintf (fp, "%s%s", delim, _("signing"));
2724     delim = _(", ");
2725   }
2726   if (key_check_cap (key, KEY_CAP_CAN_CERTIFY)) {
2727     fprintf (fp, "%s%s", delim, _("certification"));
2728     delim = _(", ");
2729   }
2730   putc ('\n', fp);
2731
2732   if (key->subkeys) {
2733     s = key->subkeys->fpr;
2734     fputs (_("Fingerprint: "), fp);
2735     if (is_pgp && m_strlen(s) == 40) {
2736       for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
2737         putc (*s, fp);
2738         putc (s[1], fp);
2739         putc (s[2], fp);
2740         putc (s[3], fp);
2741         putc (is_pgp ? ' ' : ':', fp);
2742         if (is_pgp && i == 4)
2743           putc (' ', fp);
2744       }
2745     }
2746     else {
2747       for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
2748         putc (*s, fp);
2749         putc (s[1], fp);
2750         putc (is_pgp ? ' ' : ':', fp);
2751         if (is_pgp && i == 7)
2752           putc (' ', fp);
2753       }
2754     }
2755     fprintf (fp, "%s\n", s);
2756   }
2757
2758   if (key->issuer_serial) {
2759     s = key->issuer_serial;
2760     if (s)
2761       fprintf (fp, _("Serial-No .: 0x%s\n"), s);
2762   }
2763
2764   if (key->issuer_name) {
2765     s = key->issuer_name;
2766     if (s) {
2767       fprintf (fp, _("Issued By .: "));
2768       parse_and_print_user_id (fp, s);
2769       putc ('\n', fp);
2770     }
2771   }
2772
2773   /* For PGP we list all subkeys. */
2774   if (is_pgp) {
2775     gpgme_subkey_t subkey = NULL;
2776
2777     for (idx = 1, subkey = key->subkeys; subkey; idx++, subkey = subkey->next) {
2778       s = subkey->keyid;
2779
2780       putc ('\n', fp);
2781       if (m_strlen(s) == 16)
2782         s += 8;                 /* display only the short keyID */
2783       fprintf (fp, _("Subkey ....: 0x%s"), s);
2784       if (subkey->revoked) {
2785         putc (' ', fp);
2786         fputs (_("[Revoked]"), fp);
2787       }
2788       if (subkey->invalid) {
2789         putc (' ', fp);
2790         fputs (_("[Invalid]"), fp);
2791       }
2792       if (subkey->expired) {
2793         putc (' ', fp);
2794         fputs (_("[Expired]"), fp);
2795       }
2796       if (subkey->disabled) {
2797         putc (' ', fp);
2798         fputs (_("[Disabled]"), fp);
2799       }
2800       putc ('\n', fp);
2801
2802       if (subkey->timestamp > 0) {
2803         tt = subkey->timestamp;
2804
2805         tm = localtime (&tt);
2806 #ifdef D_T_FMT
2807         strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2808 #else
2809         strftime (shortbuf, sizeof shortbuf, "%c", tm);
2810 #endif
2811         fprintf (fp, _("Valid From : %s\n"), shortbuf);
2812       }
2813
2814       if (subkey->expires > 0) {
2815         tt = subkey->expires;
2816
2817         tm = localtime (&tt);
2818 #ifdef D_T_FMT
2819         strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
2820 #else
2821         strftime (shortbuf, sizeof shortbuf, "%c", tm);
2822 #endif
2823         fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
2824       }
2825
2826       if (subkey)
2827         s = gpgme_pubkey_algo_name (subkey->pubkey_algo);
2828       else
2829         s = "?";
2830
2831       if (subkey)
2832         aval = subkey->length;
2833       else
2834         aval = 0;
2835
2836       fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), "PGP", aval, s);
2837
2838       fprintf (fp, _("Key Usage .: "));
2839       delim = "";
2840
2841       if (subkey->can_encrypt) {
2842         fprintf (fp, "%s%s", delim, _("encryption"));
2843         delim = _(", ");
2844       }
2845       if (subkey->can_sign) {
2846         fprintf (fp, "%s%s", delim, _("signing"));
2847         delim = _(", ");
2848       }
2849       if (subkey->can_certify) {
2850         fprintf (fp, "%s%s", delim, _("certification"));
2851         delim = _(", ");
2852       }
2853       putc ('\n', fp);
2854     }
2855   }
2856
2857   if (Locale)
2858     setlocale (LC_TIME, "C");
2859 }
2860
2861
2862 /* Show detailed information about the selected key */
2863 static void verify_key (cryptkey_t * key)
2864 {
2865   FILE *fp;
2866   char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
2867   const char *s;
2868   gpgme_ctx_t listctx = NULL;
2869   gpgme_error_t err;
2870   gpgme_key_t k = NULL;
2871   int maxdepth = 100;
2872
2873   fp = m_tempfile (tempfile, sizeof(tempfile), NONULL(mod_core.tmpdir), NULL);
2874   if (!fp) {
2875     mutt_perror (_("Can't create temporary file"));
2876     return;
2877   }
2878   mutt_message _("Collecting data...");
2879
2880   print_key_info (key->kobj, fp);
2881
2882   err = gpgme_new (&listctx);
2883   if (err) {
2884     fprintf (fp, "Internal error: can't create gpgme context: %s\n",
2885              gpgme_strerror (err));
2886     goto leave;
2887   }
2888   if ((key->flags & KEYFLAG_ISX509))
2889     gpgme_set_protocol (listctx, GPGME_PROTOCOL_CMS);
2890
2891   k = key->kobj;
2892   gpgme_key_ref (k);
2893   while ((s = k->chain_id) && k->subkeys && m_strcmp(s, k->subkeys->fpr)) {
2894     putc ('\n', fp);
2895     err = gpgme_op_keylist_start (listctx, s, 0);
2896     gpgme_key_unref(k);
2897     k = NULL;
2898     if (!err)
2899       err = gpgme_op_keylist_next (listctx, &k);
2900     if (err) {
2901       fprintf (fp, _("Error finding issuer key: %s\n"), gpgme_strerror (err));
2902       goto leave;
2903     }
2904     gpgme_op_keylist_end (listctx);
2905
2906     print_key_info (k, fp);
2907     if (!--maxdepth) {
2908       putc ('\n', fp);
2909       fputs (_("Error: certification chain to long - stopping here\n"), fp);
2910       break;
2911     }
2912   }
2913
2914 leave:
2915   gpgme_key_unref(k);
2916   gpgme_release (listctx);
2917   m_fclose(&fp);
2918   mutt_clear_error ();
2919   snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), crypt_keyid (key));
2920   mutt_pager(cmd, tempfile, 0, NULL);
2921 }
2922
2923 /* Implementation of `findkeys'. */
2924
2925 static void add_hints(string_array *arr, const char *s)
2926 {
2927     if (!s)
2928         return;
2929
2930     while (*s) {
2931         int l = strcspn(s, " ,.:\"()<>\n");
2932         string_array_append(arr, p_dupstr(s, l));
2933         s += l;
2934         s += strspn(s, " ,.:\"()<>\n");
2935     }
2936 }
2937
2938 /* Return a list of keys which are candidates for the selection. */
2939 static cryptkey_t *
2940 get_candidates(string_array *hints, unsigned int app, int secret)
2941 {
2942     cryptkey_t  *res = NULL, **kend = &res;
2943     gpgme_error_t err;
2944     gpgme_ctx_t   ctx;
2945     gpgme_key_t   key;
2946
2947     if (hints->len <= 0)
2948         return NULL;
2949     string_array_append(hints, NULL);
2950     ctx = create_gpgme_context(0);
2951
2952     if ((app & APPLICATION_PGP)) {
2953         err = gpgme_op_keylist_ext_start(ctx, (const char **)hints->arr,
2954                                          secret, 0);
2955         if (err) {
2956             mutt_error(_("gpgme_op_keylist_start failed: %s"),
2957                        gpgme_strerror(err));
2958             gpgme_release(ctx);
2959             return NULL;
2960         }
2961
2962         while (!(err = gpgme_op_keylist_next(ctx, &key))) {
2963             gpgme_user_id_t uid = NULL;
2964             unsigned int flags = 0;
2965             int idx;
2966
2967             if (key_check_cap(key, KEY_CAP_CAN_ENCRYPT))
2968                 flags |= KEYFLAG_CANENCRYPT;
2969             if (key_check_cap(key, KEY_CAP_CAN_SIGN))
2970                 flags |= KEYFLAG_CANSIGN;
2971
2972             for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
2973                 cryptkey_t *k = p_new(cryptkey_t, 1);
2974                 k->kobj = key;
2975                 k->idx = idx;
2976                 k->uid = uid->uid;
2977                 k->flags = flags;
2978                 *kend = k;
2979                 kend = &k->next;
2980             }
2981         }
2982         if (gpg_err_code(err) != GPG_ERR_EOF)
2983             mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
2984         gpgme_op_keylist_end(ctx);
2985     }
2986
2987     if ((app & APPLICATION_SMIME)) {
2988         gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS);
2989         err = gpgme_op_keylist_ext_start(ctx, (const char **)hints->arr,
2990                                          secret, 0);
2991         if (err) {
2992             mutt_error(_("gpgme_op_keylist_start failed: %s"),
2993                        gpgme_strerror(err));
2994             gpgme_release(ctx);
2995             return NULL;
2996         }
2997
2998         while (!(err = gpgme_op_keylist_next(ctx, &key))) {
2999             gpgme_user_id_t uid = NULL;
3000             unsigned int flags = KEYFLAG_ISX509;
3001             int idx;
3002
3003             if (key_check_cap(key, KEY_CAP_CAN_ENCRYPT))
3004                 flags |= KEYFLAG_CANENCRYPT;
3005             if (key_check_cap(key, KEY_CAP_CAN_SIGN))
3006                 flags |= KEYFLAG_CANSIGN;
3007
3008             for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
3009                 cryptkey_t *k = p_new(cryptkey_t, 1);
3010                 k->kobj = key;
3011                 k->idx = idx;
3012                 k->uid = uid->uid;
3013                 k->flags = flags;
3014                 *kend = k;
3015                 kend = &k->next;
3016             }
3017         }
3018         if (gpg_err_code(err) != GPG_ERR_EOF)
3019             mutt_error(_("gpgme_op_keylist_next failed: %s"),
3020                        gpgme_strerror(err));
3021         gpgme_op_keylist_end(ctx);
3022     }
3023
3024     gpgme_release(ctx);
3025     return res;
3026 }
3027
3028 /* Display a menu to select a key from the array KEYS. FORCED_VALID
3029    will be set to true on return if the user did override the the
3030    key's validity. */
3031 static cryptkey_t *crypt_select_key (cryptkey_t * keys,
3032                                       address_t * p, const char *s,
3033                                       unsigned int app, int *forced_valid)
3034 {
3035   int keymax;
3036   cryptkey_t **cryptkey_table;
3037   MUTTMENU *menu;
3038   int i, done = 0;
3039   char buf[LONG_STRING];
3040   cryptkey_t *k;
3041   int (*f) (const void *, const void *);
3042   int menu_to_use = 0;
3043   int unusable = 0;
3044
3045   *forced_valid = 0;
3046
3047   /* build the key table */
3048   keymax = i = 0;
3049   cryptkey_table = NULL;
3050   for (k = keys; k; k = k->next) {
3051       if (!option (OPTPGPSHOWUNUSABLE) && (k->flags & KEYFLAG_CANTUSE)) {
3052           unusable = 1;
3053           continue;
3054       }
3055
3056       if (i == keymax) {
3057           keymax += 20;
3058           p_realloc(&cryptkey_table, keymax);
3059       }
3060
3061       cryptkey_table[i++] = k;
3062   }
3063
3064   if (!i && unusable) {
3065       mutt_error _("All matching keys are marked expired/revoked.");
3066
3067       mutt_sleep (1);
3068       return NULL;
3069   }
3070
3071   switch (PgpSortKeys & SORT_MASK) {
3072     case SORT_DATE:
3073       f = crypt_compare_date;
3074       break;
3075     case SORT_KEYID:
3076       f = crypt_compare_keyid;
3077       break;
3078     case SORT_ADDRESS:
3079       f = crypt_compare_address;
3080       break;
3081     case SORT_TRUST:
3082     default:
3083       f = crypt_compare_trust;
3084       break;
3085   }
3086   qsort (cryptkey_table, i, sizeof (cryptkey_t *), f);
3087
3088   if (app & APPLICATION_PGP)
3089       menu_to_use = MENU_KEY_SELECT_PGP;
3090   else if (app & APPLICATION_SMIME)
3091       menu_to_use = MENU_KEY_SELECT_SMIME;
3092
3093   menu = mutt_new_menu ();
3094   menu->max = i;
3095   menu->make_entry = crypt_entry;
3096   menu->menu = menu_to_use;
3097   menu->data = cryptkey_table;
3098
3099   {
3100       const char *ts;
3101
3102       if ((app & APPLICATION_PGP) && (app & APPLICATION_SMIME))
3103           ts = _("PGP and S/MIME keys matching");
3104       else if ((app & APPLICATION_PGP))
3105           ts = _("PGP keys matching");
3106       else if ((app & APPLICATION_SMIME))
3107           ts = _("S/MIME keys matching");
3108       else
3109           ts = _("keys matching");
3110
3111       if (p)
3112           snprintf (buf, sizeof (buf), _("%s <%s>."), ts, p->mailbox);
3113       else
3114           snprintf (buf, sizeof (buf), _("%s \"%s\"."), ts, s);
3115       menu->title = buf;
3116   }
3117
3118   mutt_clear_error ();
3119   k = NULL;
3120   while (!done) {
3121       *forced_valid = 0;
3122       switch (mutt_menuLoop (menu)) {
3123         case OP_VERIFY_KEY:
3124           verify_key (cryptkey_table[menu->current]);
3125           menu->redraw = REDRAW_FULL;
3126           break;
3127
3128         case OP_VIEW_ID:
3129           mutt_message ("%s", cryptkey_table[menu->current]->uid);
3130           break;
3131
3132         case OP_GENERIC_SELECT_ENTRY:
3133           /* FIXME make error reporting more verbose - this should be
3134              easy because gpgme provides more information */
3135           if (option (OPTPGPCHECKTRUST)) {
3136               if (cryptkey_table[menu->current]->flags & KEYFLAG_CANTUSE ) {
3137                   mutt_error(_("This key can't be used: "
3138                                "expired/disabled/revoked."));
3139                   break;
3140               }
3141           }
3142
3143           if (option (OPTPGPCHECKTRUST) &&
3144               ((cryptkey_table[menu->current]->flags & KEYFLAG_CANTUSE)
3145                || !crypt_id_is_strong (cryptkey_table[menu->current]))) {
3146               const char *warn_s;
3147               char buff[LONG_STRING];
3148
3149               if (cryptkey_table[menu->current]->flags & KEYFLAG_CANTUSE)
3150                   s = N_("ID is expired/disabled/revoked.");
3151               else {
3152                   gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
3153                   gpgme_user_id_t uid = NULL;
3154                   int j = 0;
3155
3156                   warn_s = "??";
3157
3158                   uid = cryptkey_table[menu->current]->kobj->uids;
3159                   for (j = 0; (j < cryptkey_table[menu->current]->idx) && uid;
3160                        j++, uid = uid->next);
3161                   if (uid)
3162                       val = uid->validity;
3163
3164                   switch (val) {
3165                     case GPGME_VALIDITY_UNKNOWN:
3166                     case GPGME_VALIDITY_UNDEFINED:
3167                       warn_s = N_("ID has undefined validity.");
3168                       break;
3169                     case GPGME_VALIDITY_NEVER:
3170                       warn_s = N_("ID is not valid.");
3171                       break;
3172                     case GPGME_VALIDITY_MARGINAL:
3173                       warn_s = N_("ID is only marginally valid.");
3174                       break;
3175                     case GPGME_VALIDITY_FULL:
3176                     case GPGME_VALIDITY_ULTIMATE:
3177                       break;
3178                   }
3179
3180                   snprintf (buff, sizeof (buff),
3181                             _("%s Do you really want to use the key?"), _(warn_s));
3182
3183                   if (mutt_yesorno (buff, 0) != 1) {
3184                       mutt_clear_error ();
3185                       break;
3186                   }
3187                   *forced_valid = 1;
3188               }
3189           }
3190
3191           k = cryptkey_dup(cryptkey_table[menu->current]);
3192           done = 1;
3193           break;
3194
3195         case OP_EXIT:
3196           k = NULL;
3197           done = 1;
3198           break;
3199       }
3200   }
3201
3202   mutt_menuDestroy (&menu);
3203   p_delete(&cryptkey_table);
3204
3205   set_option (OPTNEEDREDRAW);
3206
3207   return k;
3208 }
3209
3210 static cryptkey_t *
3211 crypt_getkeybyaddr(address_t * a, int abilities, int app, int *forced_valid)
3212 {
3213     address_t *r, *p;
3214
3215     int weak = 0;
3216     int invalid = 0;
3217     int multi = 0;
3218     int this_key_has_strong;
3219     int this_key_has_weak;
3220     int this_key_has_invalid;
3221     int match;
3222
3223     cryptkey_t *keys, *k;
3224     cryptkey_t *the_valid_key = NULL;
3225     cryptkey_t *matches = NULL;
3226     cryptkey_t **matches_endp = &matches;
3227
3228     *forced_valid = 0;
3229
3230     {
3231         string_array hints;
3232         string_array_init(&hints); 
3233         add_hints(&hints, a->mailbox);
3234         add_hints(&hints, a->personal);
3235
3236         mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
3237         keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3238         string_array_wipe(&hints);
3239     }
3240
3241     if (!keys)
3242         return NULL;
3243
3244     for (k = keys; k; k = k->next) {
3245         if (abilities && !(k->flags & abilities)) {
3246             continue;
3247         }
3248
3249         this_key_has_weak = 0;      /* weak but valid match   */
3250         this_key_has_invalid = 0;   /* invalid match          */
3251         this_key_has_strong = 0;    /* strong and valid match */
3252         match = 0;                  /* any match            */
3253
3254         r = rfc822_parse_adrlist (NULL, k->uid);
3255         for (p = r; p; p = p->next) {
3256             int validity = crypt_id_matches_addr (a, p, k);
3257
3258             if (validity & CRYPT_KV_MATCH)    /* something matches */
3259                 match = 1;
3260
3261             /* is this key a strong candidate? */
3262             if ((validity & CRYPT_KV_VALID)
3263                 && (validity & CRYPT_KV_STRONGID)
3264                 && (validity & CRYPT_KV_ADDR)) {
3265                 if (the_valid_key && the_valid_key != k)
3266                     multi = 1;
3267                 the_valid_key = k;
3268                 this_key_has_strong = 1;
3269             }
3270             else if ((validity & CRYPT_KV_MATCH)
3271                      && !(validity & CRYPT_KV_VALID))
3272                 this_key_has_invalid = 1;
3273             else if ((validity & CRYPT_KV_MATCH)
3274                      && (!(validity & CRYPT_KV_STRONGID)
3275                          || !(validity & CRYPT_KV_ADDR)))
3276                 this_key_has_weak = 1;
3277         }
3278         address_list_wipe(&r);
3279
3280         if (match) {
3281             cryptkey_t *tmp;
3282
3283             if (!this_key_has_strong && this_key_has_invalid)
3284                 invalid = 1;
3285             if (!this_key_has_strong && this_key_has_weak)
3286                 weak = 1;
3287
3288             *matches_endp = tmp = cryptkey_dup(k);
3289             matches_endp = &tmp->next;
3290             the_valid_key = tmp;
3291         }
3292     }
3293     key_list_wipe(&keys);
3294
3295     if (matches) {
3296         if (the_valid_key && !multi && !weak
3297             && !(invalid && option (OPTPGPSHOWUNUSABLE))) {
3298             /*
3299              * There was precisely one strong match on a valid ID, there
3300              * were no valid keys with weak matches, and we aren't
3301              * interested in seeing invalid keys.
3302              *
3303              * Proceed without asking the user.
3304              */
3305             k = cryptkey_dup(the_valid_key);
3306         } else {
3307             /*
3308              * Else: Ask the user.
3309              */
3310             k = crypt_select_key (matches, a, NULL, app, forced_valid);
3311         }
3312         key_list_wipe(&matches);
3313     } else {
3314         k = NULL;
3315     }
3316
3317     return k;
3318 }
3319
3320
3321 static cryptkey_t *
3322 crypt_getkeybystr(const char *p, int abilities, int app, int *forced_valid)
3323 {
3324   cryptkey_t *keys;
3325   cryptkey_t *matches = NULL;
3326   cryptkey_t **matches_endp = &matches;
3327   cryptkey_t *k;
3328   int match;
3329
3330   mutt_message (_("Looking for keys matching \"%s\"..."), p);
3331
3332   *forced_valid = 0;
3333
3334   {
3335       string_array hints;
3336       string_array_init(&hints);
3337       add_hints(&hints, p);
3338       keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3339       string_array_wipe(&hints);
3340   }
3341
3342   if (!keys)
3343     return NULL;
3344
3345   for (k = keys; k; k = k->next) {
3346     const char *s = crypt_keyid(k);
3347
3348     if (abilities && !(k->flags & abilities))
3349       continue;
3350
3351     match = 0;
3352
3353     if (!*p || !m_strcasecmp(p, s)
3354         || (!m_strncasecmp(p, "0x", 2) && !m_strcasecmp(p + 2, s))
3355         || m_stristr(k->uid, p))
3356     {
3357       cryptkey_t *tmp;
3358
3359       *matches_endp = tmp = cryptkey_dup(k);
3360       matches_endp = &tmp->next;
3361     }
3362   }
3363   key_list_wipe(&keys);
3364
3365   if (matches) {
3366     k = crypt_select_key (matches, NULL, p, app, forced_valid);
3367     key_list_wipe(&matches);
3368     return k;
3369   }
3370
3371   return NULL;
3372 }
3373
3374 /* Display TAG as a prompt to ask for a key.
3375  * ABILITIES describe the required key abilities (sign, encrypt) and APP the
3376  * type of the requested key; ether S/MIME or PGP.
3377  * Return a copy of the key or NULL if not found. */
3378 static cryptkey_t *
3379 crypt_ask_for_key(const char *tag, int abilities, int app, int *forced_valid)
3380 {
3381     cryptkey_t *key;
3382     char resp[STRING];
3383     int dummy;
3384
3385     if (!forced_valid)
3386         forced_valid = &dummy;
3387     *forced_valid = 0;
3388
3389     mutt_clear_error();
3390     for (;;) {
3391         resp[0] = 0;
3392         if (mutt_get_field(tag, resp, sizeof(resp), M_CLEAR) != 0)
3393             return NULL;
3394
3395         if (m_strisempty(resp))
3396             return NULL;
3397
3398         if ((key = crypt_getkeybystr(resp, abilities, app, forced_valid)))
3399             return key;
3400
3401         BEEP ();
3402     }
3403 }
3404
3405 /* This routine attempts to find the keyids of the recipients of a
3406    message.  It returns NULL if any of the keys can not be found.  */
3407 static char *find_keys(ENVELOPE *env, unsigned int app)
3408 {
3409     address_t *lst = NULL, *addr;
3410     buffer_t *keylist = buffer_new();
3411
3412     {
3413         address_t **last = &lst;
3414         *last = address_list_dup(env->to);
3415         last  = address_list_last(last);
3416         *last = address_list_dup(env->cc);
3417         last  = address_list_last(last);
3418         *last = address_list_dup(env->bcc);
3419
3420         rfc822_qualify(lst, mutt_fqdn(1));
3421         address_list_uniq(lst);
3422     }
3423
3424     while ((addr = address_list_pop(&lst))) {
3425         char buf[STRING];
3426         int forced_valid = 0;
3427         const char *keyID;
3428         cryptkey_t *key = NULL;
3429
3430         if ((keyID = mutt_crypt_hook(addr))) {
3431             int r;
3432
3433             snprintf(buf, sizeof(buf), _("Use keyID = \"%s\" for %s?"), keyID,
3434                      addr->mailbox);
3435             r = mutt_yesorno(buf, M_YES);
3436
3437             if (r == -1) {
3438                 address_list_wipe(&lst);
3439                 address_list_wipe(&addr);
3440                 buffer_delete(&keylist);
3441                 return NULL;
3442             }
3443
3444             if (r == M_YES) {
3445                 address_t *a;
3446                 /* check for e-mail address */
3447                 if (strchr(keyID, '@') && (a = rfc822_parse_adrlist(NULL, keyID))) {
3448                     rfc822_qualify(a, mutt_fqdn(1));
3449                     address_list_wipe(&addr);
3450                     addr = a;
3451                 } else {
3452                     key = crypt_getkeybystr(keyID, KEYFLAG_CANENCRYPT, app,
3453                                             &forced_valid);
3454                 }
3455             }
3456         }
3457
3458         if (!key) {
3459             key = crypt_getkeybyaddr(addr, KEYFLAG_CANENCRYPT, app, &forced_valid);
3460         }
3461         if (!key) {
3462             snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), addr->mailbox);
3463             key = crypt_ask_for_key(buf, KEYFLAG_CANENCRYPT, app,
3464                                     &forced_valid);
3465             if (!key) {
3466                 address_list_wipe(&lst);
3467                 address_list_wipe(&addr);
3468                 buffer_delete(&keylist);
3469                 return NULL;
3470             }
3471         }
3472
3473         if (keylist->len)
3474             buffer_addch(keylist, ' ');
3475         buffer_addstr(keylist, "0x");
3476         buffer_addstr(keylist, crypt_fpr(key));
3477         if (forced_valid)
3478             buffer_addch(keylist, '!');
3479
3480         key_list_wipe(&key);
3481         address_list_wipe(&addr);
3482     }
3483
3484     address_list_wipe(&lst);
3485     return buffer_unwrap(&keylist);
3486 }
3487
3488 int crypt_get_keys(HEADER *msg, char **keylist)
3489 {
3490     /* Do a quick check to make sure that we can find all of the encryption
3491      * keys if the user has requested this service.
3492      */
3493
3494     *keylist = NULL;
3495
3496     if (msg->security & ENCRYPT) {
3497         if (msg->security & APPLICATION_PGP) {
3498             set_option(OPTPGPCHECKTRUST);
3499             *keylist = find_keys(msg->env, APPLICATION_PGP);
3500             unset_option(OPTPGPCHECKTRUST);
3501             if (!*keylist)
3502                 return -1;
3503         }
3504
3505         if (msg->security & APPLICATION_SMIME) {
3506             *keylist = find_keys(msg->env, APPLICATION_SMIME);
3507             if (!*keylist)
3508                 return -1;
3509         }
3510     }
3511
3512     return 0;
3513 }
3514
3515
3516 int crypt_send_menu (HEADER * msg, int *redraw, int is_smime)
3517 {
3518     cryptkey_t *p;
3519     char buf[STRING];
3520     int choice;
3521
3522     if (msg->security & APPLICATION_SMIME)
3523         is_smime = 1;
3524     if (msg->security & APPLICATION_PGP)
3525         is_smime = 0;
3526
3527     choice = is_smime
3528         ? mutt_multi_choice(_("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?"),
3529                             _("esabpc"))
3530         : mutt_multi_choice(_("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?"),
3531                             _("esabmc"));
3532
3533     switch (choice) {
3534       case 1:                      /* (e)ncrypt */
3535         msg->security |= (is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3536         msg->security &= ~(is_smime ? SMIMESIGN : PGPSIGN);
3537         break;
3538
3539       case 2:                      /* (s)ign */
3540         msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3541         msg->security &= ~(is_smime ? SMIMEENCRYPT : PGPENCRYPT);
3542         break;
3543
3544       case 3:                      /* sign (a)s */
3545         p = crypt_ask_for_key(_("Sign as: "), KEYFLAG_CANSIGN,
3546                               is_smime ?  APPLICATION_SMIME : APPLICATION_PGP,
3547                               NULL);
3548         if (p) {
3549             snprintf(buf, sizeof(buf), "0x%s", crypt_keyid(p));
3550             m_strreplace(is_smime ? &SmimeDefaultKey : &PgpSignAs, buf);
3551             key_list_wipe(&p);
3552             msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
3553         }
3554         *redraw = REDRAW_FULL;
3555         break;
3556
3557       case 4:                      /* (b)oth */
3558         if (is_smime) {
3559             msg->security = SMIMEENCRYPT | SMIMESIGN;
3560         } else {
3561             msg->security = PGPENCRYPT | PGPSIGN;
3562         }
3563         break;
3564
3565       case 5:                      /* (p)gp or s/(m)ime */
3566         is_smime = !is_smime;
3567         break;
3568
3569       case 6:                      /* (c)lear */
3570         return msg->security = 0;
3571     }
3572
3573     if (is_smime) {
3574         msg->security &= ~APPLICATION_PGP;
3575         msg->security |= APPLICATION_SMIME;
3576     } else {
3577         msg->security &= ~APPLICATION_SMIME;
3578         msg->security |= APPLICATION_PGP;
3579     }
3580
3581     return msg->security;
3582 }
3583
3584 int crypt_smime_verify_sender(HEADER *h)
3585 {
3586     address_t *sender = NULL;
3587     unsigned int ret = 1;
3588
3589     if (h->env->from) {
3590         h->env->from = mutt_expand_aliases(h->env->from);
3591         sender = h->env->from;
3592     } else if (h->env->sender) {
3593         h->env->sender = mutt_expand_aliases (h->env->sender);
3594         sender = h->env->sender;
3595     }
3596
3597     if (!sender) {
3598         mutt_any_key_to_continue ("Failed to figure out sender");
3599         goto end;
3600     }
3601
3602     if (signature_key) {
3603         gpgme_key_t key = signature_key;
3604         gpgme_user_id_t uid = NULL;
3605         int sender_length = 0;
3606         int uid_length = 0;
3607
3608         sender_length = m_strlen(sender->mailbox);
3609         for (uid = key->uids; uid && ret; uid = uid->next) {
3610             uid_length = m_strlen(uid->email);
3611             if (1 && (uid->email[0] == '<')
3612                 && (uid->email[uid_length - 1] == '>')
3613                 && (uid_length == sender_length + 2)
3614                 && (!m_strncmp (uid->email + 1, sender->mailbox, sender_length)))
3615                 ret = 0;
3616         }
3617     } else {
3618         mutt_any_key_to_continue ("Failed to verify sender");
3619     }
3620
3621   end:
3622     if (signature_key) {
3623         gpgme_key_unref(signature_key);
3624         signature_key = NULL;
3625     }
3626     return ret;
3627 }
3628
3629 static void crypt_invoke_import(FILE *stream, int smime)
3630 {
3631     gpgme_ctx_t ctx = create_gpgme_context(smime);
3632     gpgme_data_t data;
3633     gpgme_error_t err;
3634
3635     err = gpgme_data_new_from_stream(&data, stream);
3636     if (err) {
3637         mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
3638         gpgme_release(ctx);
3639         return;
3640     }
3641
3642     err = gpgme_op_import(ctx, data);
3643     if (err) {
3644         mutt_error(_("error importing gpg data: %s\n"), gpgme_strerror(err));
3645         gpgme_data_release(data);
3646         gpgme_release(ctx);
3647         return;
3648     }
3649
3650     gpgme_data_release(data);
3651     gpgme_release(ctx);
3652     return;
3653 }
3654
3655 static void pgp_extract_keys_from_attachment(FILE * fp, BODY * top)
3656 {
3657     STATE s;
3658     FILE *tmpfp = tmpfile();
3659
3660     if (tmpfp == NULL) {
3661         mutt_perror (_("Can't create temporary file"));
3662         return;
3663     }
3664
3665     p_clear(&s, 1);
3666     s.fpin  = fp;
3667     s.fpout = tmpfp;
3668     mutt_body_handler(top, &s);
3669
3670     rewind(tmpfp);
3671     crypt_invoke_import(tmpfp, 0);
3672     m_fclose(&tmpfp);
3673 }
3674
3675 void crypt_pgp_extract_keys_from_attachment_list(FILE * fp, int tag, BODY * top)
3676 {
3677     mutt_endwin (NULL);
3678
3679     for (; top; top = top->next) {
3680         if (!tag || top->tagged)
3681             pgp_extract_keys_from_attachment (fp, top);
3682
3683         if (!tag)
3684             break;
3685     }
3686 }
3687
3688 void crypt_invoke_message (int type)
3689 {
3690     if (type & APPLICATION_PGP) {
3691         mutt_message _("Invoking PGP...");
3692     }
3693     else if (type & APPLICATION_SMIME) {
3694         mutt_message _("Invoking S/MIME...");
3695     }
3696 }
3697
3698 int mutt_protect (HEADER * msg, char *keylist)
3699 {
3700   BODY *pbody = NULL, *tmp_pbody = NULL;
3701   BODY *tmp_smime_pbody = NULL;
3702   BODY *tmp_pgp_pbody = NULL;
3703   int flags = msg->security;
3704
3705   if (!isendwin ())
3706     mutt_endwin (NULL);
3707
3708   tmp_smime_pbody = msg->content;
3709   tmp_pgp_pbody = msg->content;
3710
3711   if (msg->security & SIGN) {
3712     if (msg->security & APPLICATION_SMIME) {
3713       if (!(tmp_pbody = sign_message(msg->content, 1)))
3714         return -1;
3715       pbody = tmp_smime_pbody = tmp_pbody;
3716     }
3717
3718     if ((msg->security & APPLICATION_PGP)
3719         && (!(flags & ENCRYPT) || option (OPTPGPRETAINABLESIG))) {
3720       if (!(tmp_pbody = sign_message(msg->content, 0)))
3721         return -1;
3722
3723       flags &= ~SIGN;
3724       pbody = tmp_pgp_pbody = tmp_pbody;
3725     }
3726
3727     if ((msg->security & APPLICATION_SMIME)
3728         && (msg->security & APPLICATION_PGP)) {
3729       /* here comes the draft ;-) */
3730     }
3731   }
3732
3733
3734   if (msg->security & ENCRYPT) {
3735     if ((msg->security & APPLICATION_SMIME)) {
3736       if (!(tmp_pbody = crypt_smime_build_smime_entity (tmp_smime_pbody,
3737                                                         keylist))) {
3738         /* signed ? free it! */
3739         return (-1);
3740       }
3741       /* free tmp_body if messages was signed AND encrypted ... */
3742       if (tmp_smime_pbody != msg->content && tmp_smime_pbody != tmp_pbody) {
3743         /* detatch and dont't delete msg->content,
3744            which tmp_smime_pbody->parts after signing. */
3745         tmp_smime_pbody->parts = tmp_smime_pbody->parts->next;
3746         msg->content->next = NULL;
3747         body_list_wipe(&tmp_smime_pbody);
3748       }
3749       pbody = tmp_pbody;
3750     }
3751
3752     if ((msg->security & APPLICATION_PGP)) {
3753       if (!(pbody = crypt_pgp_encrypt_message (tmp_pgp_pbody, keylist,
3754                                                flags & SIGN))) {
3755
3756         /* did we perform a retainable signature? */
3757         if (flags != msg->security) {
3758           /* remove the outer multipart layer */
3759           tmp_pgp_pbody = mutt_remove_multipart (tmp_pgp_pbody);
3760           /* get rid of the signature */
3761           body_list_wipe(&tmp_pgp_pbody->next);
3762         }
3763
3764         return (-1);
3765       }
3766
3767       /* destroy temporary signature envelope when doing retainable 
3768        * signatures.
3769
3770        */
3771       if (flags != msg->security) {
3772         tmp_pgp_pbody = mutt_remove_multipart (tmp_pgp_pbody);
3773         body_list_wipe(&tmp_pgp_pbody->next);
3774       }
3775     }
3776   }
3777
3778   if (pbody)
3779     msg->content = pbody;
3780
3781   return 0;
3782 }
3783
3784
3785 int crypt_query (BODY * m)
3786 {
3787   int t = 0;
3788
3789   if (!m)
3790     return 0;
3791
3792   if (m->type == TYPEAPPLICATION) {
3793     t |= mutt_is_application_pgp (m);
3794
3795     t |= mutt_is_application_smime (m);
3796     if (t && m->goodsig)
3797       t |= GOODSIGN;
3798     if (t && m->badsig)
3799       t |= BADSIGN;
3800   }
3801   else if (m->type == TYPETEXT) {
3802     t |= mutt_is_application_pgp (m);
3803     if (t && m->goodsig)
3804       t |= GOODSIGN;
3805   }
3806
3807   if (m->type == TYPEMULTIPART) {
3808     t |= mutt_is_multipart_encrypted (m);
3809     t |= mutt_is_multipart_signed (m);
3810
3811     if (t && m->goodsig)
3812       t |= GOODSIGN;
3813   }
3814
3815   if (m->type == TYPEMULTIPART || m->type == TYPEMESSAGE) {
3816     BODY *p;
3817     int u, v, w;
3818
3819     u = m->parts ? ~0 : 0;      /* Bits set in all parts */
3820     w = 0;                      /* Bits set in any part  */
3821
3822     for (p = m->parts; p; p = p->next) {
3823       v = crypt_query (p);
3824       u &= v;
3825       w |= v;
3826     }
3827     t |= u | (w & ~GOODSIGN);
3828
3829     if ((w & GOODSIGN) && !(u & GOODSIGN))
3830       t |= PARTSIGN;
3831   }
3832
3833   return t;
3834 }
3835
3836
3837 static void crypt_write_signed(BODY * a, STATE * s, FILE *fp)
3838 {
3839     int c;
3840     short hadcr;
3841     size_t bytes;
3842
3843     fseeko (s->fpin, a->hdr_offset, 0);
3844     bytes = a->length + a->offset - a->hdr_offset;
3845     hadcr = 0;
3846     while (bytes > 0) {
3847         if ((c = fgetc (s->fpin)) == EOF)
3848             break;
3849
3850         bytes--;
3851
3852         if (c == '\r')
3853             hadcr = 1;
3854         else {
3855             if (c == '\n' && !hadcr)
3856                 fputc ('\r', fp);
3857
3858             hadcr = 0;
3859         }
3860         fputc (c, fp);
3861     }
3862 }
3863
3864 static void extract_keys_aux(FILE *fpout, HEADER *h)
3865 {
3866     mutt_parse_mime_message (Context, h);
3867
3868     rewind(fpout);
3869     if (h->security & APPLICATION_PGP) {
3870         mutt_copy_message(fpout, Context, h, M_CM_DECODE | M_CM_CHARCONV, 0);
3871         fflush (fpout);
3872
3873         mutt_endwin (_("Trying to extract PGP keys...\n"));
3874     }
3875
3876     if (h->security & APPLICATION_SMIME) {
3877         if (h->security & ENCRYPT)
3878             mutt_copy_message (fpout, Context, h, M_CM_NOHEADER
3879                                | M_CM_DECODE_CRYPT | M_CM_DECODE_SMIME, 0);
3880         else
3881             mutt_copy_message(fpout, Context, h, 0, 0);
3882         fflush (fpout);
3883
3884         mutt_message (_("Trying to extract S/MIME certificates...\n"));
3885     }
3886
3887     rewind(fpout);
3888     crypt_invoke_import(fpout, h->security & APPLICATION_SMIME);