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