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