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