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