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