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