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