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