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