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