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