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