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