]> git.llucax.com Git - software/mutt-debian.git/blob - crypt-gpgme.c
new patch to do a better debug, some minor changes to hyphen-as-minus.patch
[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);
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);
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 = DISPINLINE;
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 = DISPINLINE;
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);
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);
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);
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);
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);
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);
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);
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 #if 0
2375       else
2376       {
2377         /* why would we want to display this at all? */
2378         /* XXX - we may wish to recode here */
2379         if (s->prefix)
2380           state_puts (s->prefix, s);
2381         state_puts (buf, s);
2382       }
2383 #endif
2384     }
2385
2386   m->goodsig = (maybe_goodsig && have_any_sigs);
2387   
2388   if (needpass == -1)
2389     {
2390       state_attach_puts (_("[-- Error: could not find beginning"
2391                            " of PGP message! --]\n\n"), s);
2392       return 1;
2393     }
2394   dprint (2, (debugfile, "Leaving pgp_application_pgp handler\n"));
2395
2396   return err;
2397 }
2398
2399 /* 
2400  * Implementation of `encrypted_handler'.
2401  */
2402
2403 /* MIME handler for pgp/mime encrypted messages. */
2404 int pgp_gpgme_encrypted_handler (BODY *a, STATE *s)
2405 {
2406   char tempfile[_POSIX_PATH_MAX];
2407   FILE *fpout;
2408   BODY *tattach;
2409   BODY *orig_body = a;
2410   int is_signed;
2411   int rc = 0;
2412   
2413   dprint (2, (debugfile, "Entering pgp_encrypted handler\n"));
2414   a = a->parts;
2415   if (!a || a->type != TYPEAPPLICATION || !a->subtype
2416       || ascii_strcasecmp ("pgp-encrypted", a->subtype) 
2417       || !a->next || a->next->type != TYPEAPPLICATION || !a->next->subtype
2418       || ascii_strcasecmp ("octet-stream", a->next->subtype) )
2419     {
2420       if (s->flags & M_DISPLAY)
2421         state_attach_puts (_("[-- Error: malformed PGP/MIME message! --]\n\n"),
2422                            s);
2423       return -1;
2424     }
2425
2426   /* Move forward to the application/pgp-encrypted body. */
2427   a = a->next;
2428
2429   mutt_mktemp (tempfile);
2430   if (!(fpout = safe_fopen (tempfile, "w+")))
2431     {
2432       if (s->flags & M_DISPLAY)
2433         state_attach_puts (_("[-- Error: could not create temporary file! "
2434                              "--]\n"), s);
2435       return -1;
2436     }
2437
2438   tattach = decrypt_part (a, s, fpout, 0, &is_signed);
2439   if (tattach)
2440     {
2441       tattach->goodsig = is_signed > 0;
2442
2443       if (s->flags & M_DISPLAY)
2444         state_attach_puts (is_signed?
2445           _("[-- The following data is PGP/MIME signed and encrypted --]\n\n"):
2446           _("[-- The following data is PGP/MIME encrypted --]\n\n"),
2447                            s);
2448       
2449       {
2450         FILE *savefp = s->fpin;
2451         s->fpin = fpout;
2452         rc = mutt_body_handler (tattach, s);
2453         s->fpin = savefp;
2454       }
2455
2456       /* 
2457        * if a multipart/signed is the _only_ sub-part of a
2458        * multipart/encrypted, cache signature verification
2459        * status.
2460        */
2461       if (mutt_is_multipart_signed (tattach) && !tattach->next)
2462         orig_body->goodsig |= tattach->goodsig;
2463     
2464       if (s->flags & M_DISPLAY)
2465         {
2466           state_puts ("\n", s);
2467           state_attach_puts (is_signed?
2468              _("[-- End of PGP/MIME signed and encrypted data --]\n"):
2469              _("[-- End of PGP/MIME encrypted data --]\n"),
2470                              s);
2471         }
2472
2473       mutt_free_body (&tattach);
2474     }
2475   
2476   safe_fclose (&fpout);
2477   mutt_unlink(tempfile);
2478   dprint (2, (debugfile, "Leaving pgp_encrypted handler\n"));
2479
2480   return rc;
2481 }
2482
2483 /* Support for application/smime */
2484 int smime_gpgme_application_handler (BODY *a, STATE *s)
2485 {
2486   char tempfile[_POSIX_PATH_MAX];
2487   FILE *fpout;
2488   BODY *tattach;
2489   int is_signed;
2490   int rc = 0;
2491
2492   dprint (2, (debugfile, "Entering smime_encrypted handler\n"));
2493   
2494   a->warnsig = 0;
2495   mutt_mktemp (tempfile);
2496   if (!(fpout = safe_fopen (tempfile, "w+")))
2497     {
2498       if (s->flags & M_DISPLAY)
2499         state_attach_puts (_("[-- Error: could not create temporary file! "
2500                              "--]\n"), s);
2501       return -1;
2502     }
2503
2504   tattach = decrypt_part (a, s, fpout, 1, &is_signed);
2505   if (tattach)
2506     {
2507       tattach->goodsig = is_signed > 0;
2508
2509       if (s->flags & M_DISPLAY)
2510         state_attach_puts (is_signed?
2511           _("[-- The following data is S/MIME signed --]\n\n"):
2512           _("[-- The following data is S/MIME encrypted --]\n\n"),
2513                            s);
2514       
2515       {
2516         FILE *savefp = s->fpin;
2517         s->fpin = fpout;
2518         rc = mutt_body_handler (tattach, s);
2519         s->fpin = savefp;
2520       }
2521
2522       /* 
2523        * if a multipart/signed is the _only_ sub-part of a
2524        * multipart/encrypted, cache signature verification
2525        * status.
2526        */
2527       if (mutt_is_multipart_signed (tattach) && !tattach->next)
2528         {
2529           if (!(a->goodsig = tattach->goodsig))
2530             a->warnsig = tattach->warnsig;
2531         }
2532       else if (tattach->goodsig)
2533         {
2534           a->goodsig = 1;
2535           a->warnsig = tattach->warnsig;
2536         }
2537
2538       if (s->flags & M_DISPLAY)
2539         {
2540           state_puts ("\n", s);
2541           state_attach_puts (is_signed?
2542              _("[-- End of S/MIME signed data --]\n"):
2543              _("[-- End of S/MIME encrypted data --]\n"),
2544                              s);
2545         }
2546
2547       mutt_free_body (&tattach);
2548     }
2549   
2550   safe_fclose (&fpout);
2551   mutt_unlink(tempfile);
2552   dprint (2, (debugfile, "Leaving smime_encrypted handler\n"));
2553   
2554   return rc;
2555 }
2556
2557
2558 /*
2559  * Format an entry on the CRYPT key selection menu.
2560  * 
2561  * %n   number
2562  * %k   key id          %K      key id of the principal key
2563  * %u   user id
2564  * %a   algorithm       %A      algorithm of the princ. key
2565  * %l   length          %L      length of the princ. key
2566  * %f   flags           %F      flags of the princ. key
2567  * %c   capabilities    %C      capabilities of the princ. key
2568  * %t   trust/validity of the key-uid association
2569  * %p           protocol
2570  * %[...] date of key using strftime(3)
2571  */
2572
2573 static const char *crypt_entry_fmt (char *dest,
2574                                     size_t destlen,
2575                                     size_t col,
2576                                     char op,
2577                                     const char *src,
2578                                     const char *prefix,
2579                                     const char *ifstring,
2580                                     const char *elsestring,
2581                                     unsigned long data,
2582                                     format_flag flags)
2583 {
2584   char fmt[16];
2585   crypt_entry_t *entry;
2586   crypt_key_t *key;
2587   int kflags = 0;
2588   int optional = (flags & M_FORMAT_OPTIONAL);
2589   const char *s = NULL;
2590   unsigned long val;
2591
2592   entry = (crypt_entry_t *) data;
2593   key   = entry->key;
2594
2595 /*    if (isupper ((unsigned char) op)) */
2596 /*      key = pkey; */
2597
2598   kflags = (key->flags /*| (pkey->flags & KEYFLAG_RESTRICTIONS)
2599                          | uid->flags*/);
2600   
2601   switch (ascii_tolower (op))
2602     {
2603     case '[':
2604       {
2605         const char *cp;
2606         char buf2[SHORT_STRING], *p;
2607         int do_locales;
2608         struct tm *tm;
2609         size_t len;
2610
2611         p = dest;
2612
2613         cp = src;
2614         if (*cp == '!')
2615         {
2616           do_locales = 0;
2617           cp++;
2618         }
2619         else
2620           do_locales = 1;
2621
2622         len = destlen - 1;
2623         while (len > 0 && *cp != ']')
2624         {
2625           if (*cp == '%')
2626           {
2627             cp++;
2628             if (len >= 2)
2629             {
2630               *p++ = '%';
2631               *p++ = *cp;
2632               len -= 2;
2633             }
2634             else
2635               break; /* not enough space */
2636             cp++;
2637           }
2638           else
2639           {
2640             *p++ = *cp++;
2641             len--;
2642           }
2643         }
2644         *p = 0;
2645
2646         if (do_locales && Locale)
2647           setlocale (LC_TIME, Locale);
2648         
2649         {
2650           time_t tt = 0;
2651
2652           if (key->kobj->subkeys && (key->kobj->subkeys->timestamp > 0))
2653             tt = key->kobj->subkeys->timestamp;
2654
2655           tm = localtime (&tt);
2656         }
2657         strftime (buf2, sizeof (buf2), dest, tm);
2658
2659         if (do_locales)
2660           setlocale (LC_TIME, "C");
2661         
2662         snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2663         snprintf (dest, destlen, fmt, buf2);
2664         if (len > 0)
2665           src = cp + 1;
2666       }
2667       break;
2668     case 'n':
2669       if (!optional)
2670       {
2671         snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
2672         snprintf (dest, destlen, fmt, entry->num);
2673       }
2674       break;
2675     case 'k':
2676       if (!optional)
2677       {
2678         /* fixme: we need a way to distinguish between main and subkeys.
2679            Store the idx in entry? */
2680         snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2681         snprintf (dest, destlen, fmt, crypt_keyid (key));
2682       }
2683       break;
2684     case 'u':
2685       if (!optional)
2686       {
2687         snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2688         snprintf (dest, destlen, fmt, key->uid);
2689       }
2690       break;
2691     case 'a':
2692       if (!optional)
2693       {
2694         snprintf (fmt, sizeof (fmt), "%%%s.3s", prefix);
2695         if (key->kobj->subkeys)
2696           s = gpgme_pubkey_algo_name (key->kobj->subkeys->pubkey_algo);
2697         else
2698           s = "?";
2699         snprintf (dest, destlen, fmt, s);
2700       }
2701       break;
2702     case 'l':
2703       if (!optional)
2704       {
2705         snprintf (fmt, sizeof (fmt), "%%%slu", prefix);
2706         if (key->kobj->subkeys)
2707           val = key->kobj->subkeys->length;
2708         else
2709           val = 0;
2710         snprintf (dest, destlen, fmt, val);
2711       }
2712       break;
2713     case 'f':
2714       if (!optional)
2715       {
2716         snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2717         snprintf (dest, destlen, fmt, crypt_flags (kflags));
2718       }
2719       else if (!(kflags & (KEYFLAG_RESTRICTIONS)))
2720         optional = 0;
2721       break;
2722     case 'c':
2723       if (!optional)
2724       {
2725         snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2726         snprintf (dest, destlen, fmt, crypt_key_abilities (kflags));
2727       }
2728       else if (!(kflags & (KEYFLAG_ABILITIES)))
2729         optional = 0;
2730       break;
2731     case 't':
2732       if ((kflags & KEYFLAG_ISX509))
2733         s = "x";
2734       else
2735         {
2736           gpgme_user_id_t uid = NULL;
2737           unsigned int i = 0;
2738
2739           for (i = 0, uid = key->kobj->uids; uid && (i < key->idx);
2740                i++, uid = uid->next)
2741             ;
2742           if (uid)
2743             switch (uid->validity)
2744               {
2745               case GPGME_VALIDITY_UNDEFINED:
2746                 s = "q";
2747                 break;
2748               case GPGME_VALIDITY_NEVER:
2749                 s = "n";
2750                 break;
2751               case GPGME_VALIDITY_MARGINAL:
2752                 s = "m";
2753                 break;
2754               case GPGME_VALIDITY_FULL:
2755                 s = "f";
2756                 break;
2757               case GPGME_VALIDITY_ULTIMATE:
2758                 s = "u";
2759                 break;
2760               case GPGME_VALIDITY_UNKNOWN:
2761               default:
2762                 s = "?";
2763                 break;
2764               }
2765         }
2766       snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
2767       snprintf (dest, destlen, fmt, s? *s: 'B');
2768       break;
2769     case 'p':
2770       snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
2771       snprintf (dest, destlen, fmt,
2772                 gpgme_get_protocol_name (key->kobj->protocol));
2773       break;
2774
2775     default:
2776       *dest = '\0';
2777   }
2778
2779   if (optional)
2780     mutt_FormatString (dest, destlen, col, ifstring, mutt_attach_fmt, data, 0);
2781   else if (flags & M_FORMAT_OPTIONAL)
2782     mutt_FormatString (dest, destlen, col, elsestring, mutt_attach_fmt, data, 0);
2783   return (src);
2784 }
2785       
2786 /* Used by the display fucntion to format a line. */
2787 static void crypt_entry (char *s, size_t l, MUTTMENU * menu, int num)
2788 {
2789   crypt_key_t **key_table = (crypt_key_t **) menu->data;
2790   crypt_entry_t entry;
2791   
2792   entry.key = key_table[num];
2793   entry.num = num + 1;
2794
2795   mutt_FormatString (s, l, 0, NONULL (PgpEntryFormat), crypt_entry_fmt, 
2796                      (unsigned long) &entry, M_FORMAT_ARROWCURSOR);
2797 }
2798
2799 /* Compare two addresses and the keyid to be used for sorting. */
2800 static int _crypt_compare_address (const void *a, const void *b)
2801 {
2802   crypt_key_t **s = (crypt_key_t **) a;
2803   crypt_key_t **t = (crypt_key_t **) b;
2804   int r;
2805
2806   if ((r = mutt_strcasecmp ((*s)->uid, (*t)->uid)))
2807     return r > 0;
2808   else
2809     return mutt_strcasecmp (crypt_keyid (*s), crypt_keyid (*t)) > 0;
2810 }
2811
2812 static int crypt_compare_address (const void *a, const void *b)
2813 {
2814   return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_address (a, b)
2815                                          :  _crypt_compare_address (a, b));
2816 }
2817
2818
2819 /* Compare two key IDs and the addresses to be used for sorting. */
2820 static int _crypt_compare_keyid (const void *a, const void *b)
2821 {
2822   crypt_key_t **s = (crypt_key_t **) a;
2823   crypt_key_t **t = (crypt_key_t **) b;
2824   int r;
2825
2826   if ((r = mutt_strcasecmp (crypt_keyid (*s), crypt_keyid (*t))))
2827     return r > 0;
2828   else
2829     return mutt_strcasecmp ((*s)->uid, (*t)->uid) > 0;
2830 }
2831
2832 static int crypt_compare_keyid (const void *a, const void *b)
2833 {
2834   return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_keyid (a, b)
2835                                          :  _crypt_compare_keyid (a, b));
2836 }
2837
2838 /* Compare 2 creation dates and the addresses.  For sorting. */
2839 static int _crypt_compare_date (const void *a, const void *b)
2840 {
2841   crypt_key_t **s = (crypt_key_t **) a;
2842   crypt_key_t **t = (crypt_key_t **) b;
2843   unsigned long ts = 0, tt = 0;
2844
2845   if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2846     ts = (*s)->kobj->subkeys->timestamp;
2847   if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2848     tt = (*t)->kobj->subkeys->timestamp;
2849
2850   if (ts > tt)
2851     return 1;
2852   if (ts < tt)
2853     return 0;
2854
2855   return mutt_strcasecmp ((*s)->uid, (*t)->uid) > 0;
2856 }
2857
2858 static int crypt_compare_date (const void *a, const void *b)
2859 {
2860   return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_date (a, b)
2861                                          :  _crypt_compare_date (a, b));
2862 }
2863
2864 /* Compare two trust values, the key length, the creation dates. the
2865    addresses and the key IDs.  For sorting. */
2866 static int _crypt_compare_trust (const void *a, const void *b)
2867 {
2868   crypt_key_t **s = (crypt_key_t **) a;
2869   crypt_key_t **t = (crypt_key_t **) b;
2870   unsigned long ts = 0, tt = 0;
2871   int r;
2872
2873   if ((r = (((*s)->flags & (KEYFLAG_RESTRICTIONS))
2874             - ((*t)->flags & (KEYFLAG_RESTRICTIONS)))))
2875     return r > 0;
2876
2877   if ((*s)->kobj->uids)
2878     ts = (*s)->kobj->uids->validity;
2879   if ((*t)->kobj->uids)
2880     tt = (*t)->kobj->uids->validity;
2881   if ((r = (tt - ts)))
2882     return r < 0;
2883
2884   if ((*s)->kobj->subkeys)
2885     ts = (*s)->kobj->subkeys->length;
2886   if ((*t)->kobj->subkeys)
2887     tt = (*t)->kobj->subkeys->length;
2888   if (ts != tt)
2889     return ts > tt;
2890
2891   if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
2892     ts = (*s)->kobj->subkeys->timestamp;
2893   if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
2894     tt = (*t)->kobj->subkeys->timestamp;
2895   if (ts > tt)
2896     return 1;
2897   if (ts < tt)
2898     return 0;
2899
2900   if ((r = mutt_strcasecmp ((*s)->uid, (*t)->uid)))
2901     return r > 0;
2902   return (mutt_strcasecmp (crypt_keyid ((*s)), crypt_keyid ((*t)))) > 0;
2903 }
2904
2905 static int crypt_compare_trust (const void *a, const void *b)
2906 {
2907   return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_trust (a, b)
2908                                        : _crypt_compare_trust (a, b));
2909 }
2910
2911 /* Print the X.500 Distinguished Name part KEY from the array of parts
2912    DN to FP. */
2913 static int
2914 print_dn_part (FILE *fp, struct dn_array_s *dn, const char *key)
2915 {
2916   int any = 0;
2917
2918   for (; dn->key; dn++)
2919     {
2920       if (!strcmp (dn->key, key))
2921         {
2922           if (any)
2923             fputs (" + ", fp);
2924           print_utf8 (fp, dn->value, strlen (dn->value));
2925           any = 1;
2926         }
2927     }
2928   return any;
2929 }
2930
2931 /* Print all parts of a DN in a standard sequence. */
2932 static void
2933 print_dn_parts (FILE *fp, struct dn_array_s *dn)
2934 {
2935   const char *stdpart[] = {
2936     "CN", "OU", "O", "STREET", "L", "ST", "C", NULL 
2937   };
2938   int any=0, any2=0, i;
2939   
2940   for (i=0; stdpart[i]; i++)
2941     {
2942       if (any)
2943         fputs (", ", fp);
2944       any = print_dn_part (fp, dn, stdpart[i]);
2945     }
2946   /* now print the rest without any specific ordering */
2947   for (; dn->key; dn++)
2948     {
2949       for (i=0; stdpart[i]; i++)
2950         {
2951           if (!strcmp (dn->key, stdpart[i]))
2952             break;
2953         }
2954       if (!stdpart[i])
2955         {
2956           if (any)
2957             fputs (", ", fp);
2958           if (!any2)
2959             fputs ("(", fp);
2960           any = print_dn_part (fp, dn, dn->key);
2961           any2 = 1;
2962         }
2963     }
2964   if (any2)
2965     fputs (")", fp);
2966 }
2967
2968
2969 /* Parse an RDN; this is a helper to parse_dn(). */
2970 static const unsigned char *
2971 parse_dn_part (struct dn_array_s *array, const unsigned char *string)
2972 {
2973   const unsigned char *s, *s1;
2974   size_t n;
2975   unsigned char *p;
2976
2977   /* parse attributeType */
2978   for (s = string+1; *s && *s != '='; s++)
2979     ;
2980   if (!*s)
2981     return NULL; /* error */
2982   n = s - string;
2983   if (!n)
2984     return NULL; /* empty key */
2985   array->key = safe_malloc (n+1);
2986   p = (unsigned char *)array->key;
2987   memcpy (p, string, n); /* fixme: trim trailing spaces */
2988   p[n] = 0;
2989   string = s + 1;
2990
2991   if (*string == '#')
2992     { /* hexstring */
2993       string++;
2994       for (s=string; hexdigitp (s); s++)
2995         s++;
2996       n = s - string;
2997       if (!n || (n & 1))
2998         return NULL; /* empty or odd number of digits */
2999       n /= 2;
3000       p = safe_malloc (n+1);
3001       array->value = (char*)p;
3002       for (s1=string; n; s1 += 2, n--)
3003         *p++ = xtoi_2 (s1);
3004       *p = 0;
3005    }
3006   else
3007     { /* regular v3 quoted string */
3008       for (n=0, s=string; *s; s++)
3009         {
3010           if (*s == '\\')
3011             { /* pair */
3012               s++;
3013               if (*s == ',' || *s == '=' || *s == '+'
3014                   || *s == '<' || *s == '>' || *s == '#' || *s == ';' 
3015                   || *s == '\\' || *s == '\"' || *s == ' ')
3016                 n++;
3017               else if (hexdigitp (s) && hexdigitp (s+1))
3018                 {
3019                   s++;
3020                   n++;
3021                 }
3022               else
3023                 return NULL; /* invalid escape sequence */
3024             }
3025           else if (*s == '\"')
3026             return NULL; /* invalid encoding */
3027           else if (*s == ',' || *s == '=' || *s == '+'
3028                    || *s == '<' || *s == '>' || *s == '#' || *s == ';' )
3029             break; 
3030           else
3031             n++;
3032         }
3033
3034       p = safe_malloc (n+1);
3035       array->value = (char*)p;
3036       for (s=string; n; s++, n--)
3037         {
3038           if (*s == '\\')
3039             { 
3040               s++;
3041               if (hexdigitp (s))
3042                 {
3043                   *p++ = xtoi_2 (s);
3044                   s++;
3045                 }
3046               else
3047                 *p++ = *s;
3048             }
3049           else
3050             *p++ = *s;
3051         }
3052       *p = 0;
3053     }
3054   return s;
3055 }
3056
3057
3058 /* Parse a DN and return an array-ized one.  This is not a validating
3059    parser and it does not support any old-stylish syntax; gpgme is
3060    expected to return only rfc2253 compatible strings. */
3061 static struct dn_array_s *
3062 parse_dn (const unsigned char *string)
3063 {
3064   struct dn_array_s *array;
3065   size_t arrayidx, arraysize;
3066   int i;
3067
3068   arraysize = 7; /* C,ST,L,O,OU,CN,email */
3069   array = safe_malloc ((arraysize+1) * sizeof *array);
3070   arrayidx = 0;
3071   while (*string)
3072     {
3073       while (*string == ' ')
3074         string++;
3075       if (!*string)
3076         break; /* ready */
3077       if (arrayidx >= arraysize)
3078         { /* mutt lacks a real safe_realoc - so we need to copy */
3079           struct dn_array_s *a2;
3080
3081           arraysize += 5;
3082           a2 = safe_malloc ((arraysize+1) * sizeof *array);
3083           for (i=0; i < arrayidx; i++)
3084             {
3085               a2[i].key = array[i].key;
3086               a2[i].value = array[i].value;
3087             }
3088           FREE (&array);
3089           array = a2;
3090         }
3091       array[arrayidx].key = NULL;
3092       array[arrayidx].value = NULL;
3093       string = parse_dn_part (array+arrayidx, string);
3094       arrayidx++;
3095       if (!string)
3096         goto failure;
3097       while (*string == ' ')
3098         string++;
3099       if (*string && *string != ',' && *string != ';' && *string != '+')
3100         goto failure; /* invalid delimiter */
3101       if (*string)
3102         string++;
3103     }
3104   array[arrayidx].key = NULL;
3105   array[arrayidx].value = NULL;
3106   return array;
3107
3108  failure:
3109   for (i=0; i < arrayidx; i++)
3110     {
3111       FREE (&array[i].key);
3112       FREE (&array[i].value);
3113     }
3114   FREE (&array);
3115   return NULL;
3116 }
3117
3118
3119 /* Print a nice representation of the USERID and make sure it is
3120    displayed in a proper way, which does mean to reorder some parts
3121    for S/MIME's DNs.  USERID is a string as returned by the gpgme key
3122    functions.  It is utf-8 encoded. */
3123 static void
3124 parse_and_print_user_id (FILE *fp, const char *userid)
3125 {
3126   const char *s;
3127   int i;
3128
3129   if (*userid == '<')
3130     {
3131       s = strchr (userid+1, '>');
3132       if (s)
3133         print_utf8 (fp, userid+1, s-userid-1);
3134     }
3135   else if (*userid == '(')
3136     fputs (_("[Can't display this user ID (unknown encoding)]"), fp);
3137   else if (!digit_or_letter ((const unsigned char *)userid))
3138     fputs (_("[Can't display this user ID (invalid encoding)]"), fp);
3139   else
3140     {
3141       struct dn_array_s *dn = parse_dn ((const unsigned char *)userid);
3142       if (!dn)
3143         fputs (_("[Can't display this user ID (invalid DN)]"), fp);
3144       else 
3145         {
3146           print_dn_parts (fp, dn);          
3147           for (i=0; dn[i].key; i++)
3148             {
3149               FREE (&dn[i].key);
3150               FREE (&dn[i].value);
3151             }
3152           FREE (&dn);
3153         }
3154     }
3155 }
3156
3157 typedef enum
3158   {
3159     KEY_CAP_CAN_ENCRYPT,
3160     KEY_CAP_CAN_SIGN,
3161     KEY_CAP_CAN_CERTIFY
3162   }
3163 key_cap_t;
3164
3165 static unsigned int
3166 key_check_cap (gpgme_key_t key, key_cap_t cap)
3167 {
3168   gpgme_subkey_t subkey = NULL;
3169   unsigned int ret = 0;
3170
3171   switch (cap)
3172     {
3173     case KEY_CAP_CAN_ENCRYPT:
3174       if (! (ret = key->can_encrypt))
3175         for (subkey = key->subkeys; subkey; subkey = subkey->next)
3176           if ((ret = subkey->can_encrypt))
3177             break;
3178       break;
3179     case KEY_CAP_CAN_SIGN:
3180       if (! (ret = key->can_sign))
3181         for (subkey = key->subkeys; subkey; subkey = subkey->next)
3182           if ((ret = subkey->can_sign))
3183             break;
3184       break;
3185     case KEY_CAP_CAN_CERTIFY:
3186       if (! (ret = key->can_certify))
3187         for (subkey = key->subkeys; subkey; subkey = subkey->next)
3188           if ((ret = subkey->can_certify))
3189             break;
3190       break;
3191     }
3192
3193   return ret;
3194 }
3195
3196
3197 /* Print verbose information about a key or certificate to FP. */
3198 static void print_key_info (gpgme_key_t key, FILE *fp)
3199 {
3200   int idx;
3201   const char *s = NULL, *s2 = NULL;
3202   time_t tt = 0;
3203   struct tm *tm;
3204   char shortbuf[SHORT_STRING];
3205   unsigned long aval = 0;
3206   const char *delim;
3207   int is_pgp = 0;
3208   int i;
3209   gpgme_user_id_t uid = NULL;
3210
3211   if (Locale)
3212     setlocale (LC_TIME, Locale);
3213
3214   is_pgp = key->protocol == GPGME_PROTOCOL_OpenPGP;
3215
3216   for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3217     {
3218       if (uid->revoked)
3219         continue;
3220
3221       s = uid->uid;
3222       fputs (idx ? _(" aka ......: ") :_("Name ......: "), fp);
3223       if (uid->invalid)
3224         {
3225           fputs (_("[Invalid]"), fp);
3226           putc (' ', fp);
3227         }
3228       if (is_pgp)
3229         print_utf8 (fp, s, strlen(s));
3230       else
3231         parse_and_print_user_id (fp, s);
3232       putc ('\n', fp);
3233     }
3234
3235   if (key->subkeys && (key->subkeys->timestamp > 0))
3236     {
3237       tt = key->subkeys->timestamp;
3238
3239       tm = localtime (&tt);
3240 #ifdef HAVE_LANGINFO_D_T_FMT
3241       strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
3242 #else
3243       strftime (shortbuf, sizeof shortbuf, "%c", tm);
3244 #endif
3245       fprintf (fp, _("Valid From : %s\n"), shortbuf);
3246     }
3247   
3248   if (key->subkeys && (key->subkeys->expires > 0))
3249     {
3250       tt = key->subkeys->expires;
3251       
3252       tm = localtime (&tt);
3253 #ifdef HAVE_LANGINFO_D_T_FMT
3254       strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
3255 #else
3256       strftime (shortbuf, sizeof shortbuf, "%c", tm);
3257 #endif
3258       fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
3259     }
3260
3261   if (key->subkeys)
3262     s = gpgme_pubkey_algo_name (key->subkeys->pubkey_algo);
3263   else
3264     s = "?";
3265
3266   s2 = is_pgp ? "PGP" : "X.509";
3267
3268   if (key->subkeys)
3269     aval = key->subkeys->length;
3270
3271   fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), s2, aval, s);
3272
3273   fprintf (fp, _("Key Usage .: "));
3274   delim = "";
3275
3276   if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3277     {
3278       fprintf (fp, "%s%s", delim, _("encryption"));
3279       delim = _(", ");
3280     }
3281   if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3282     {
3283       fprintf (fp, "%s%s", delim, _("signing"));
3284       delim = _(", ");
3285     }
3286   if (key_check_cap (key, KEY_CAP_CAN_CERTIFY))
3287     {
3288       fprintf (fp, "%s%s", delim, _("certification"));
3289       delim = _(", ");
3290     }
3291   putc ('\n', fp);
3292
3293   if (key->subkeys)
3294     {
3295       s = key->subkeys->fpr;
3296       fputs (_("Fingerprint: "), fp);
3297       if (is_pgp && strlen (s) == 40)
3298         {
3299           for (i=0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++)
3300             {
3301               putc (*s, fp);
3302               putc (s[1], fp);
3303               putc (s[2], fp);
3304               putc (s[3], fp);
3305               putc (is_pgp? ' ':':', fp);
3306               if (is_pgp && i == 4)
3307                 putc (' ', fp);
3308             }
3309         }
3310       else
3311         {
3312           for (i=0; *s && s[1] && s[2]; s += 2, i++)
3313             {
3314               putc (*s, fp);
3315               putc (s[1], fp);
3316               putc (is_pgp? ' ':':', fp);
3317               if (is_pgp && i == 7)
3318                 putc (' ', fp);
3319             }
3320         }
3321       fprintf (fp, "%s\n", s);
3322     }
3323
3324   if (key->issuer_serial)
3325     {
3326       s = key->issuer_serial;
3327       if (s)
3328         fprintf (fp, _("Serial-No .: 0x%s\n"), s);
3329     }
3330
3331   if (key->issuer_name)
3332     {
3333       s = key->issuer_name;
3334       if (s)
3335         {
3336           fprintf (fp, _("Issued By .: "));
3337           parse_and_print_user_id (fp, s);
3338           putc ('\n', fp);
3339         }
3340     }
3341
3342   /* For PGP we list all subkeys. */
3343   if (is_pgp)
3344     {
3345       gpgme_subkey_t subkey = NULL;
3346
3347       for (idx = 1, subkey = key->subkeys; subkey;
3348            idx++, subkey = subkey->next)
3349         {
3350           s = subkey->keyid;
3351           
3352           putc ('\n', fp);
3353           if ( strlen (s) == 16)
3354             s += 8; /* display only the short keyID */
3355           fprintf (fp, _("Subkey ....: 0x%s"), s);
3356           if (subkey->revoked)
3357             {
3358               putc (' ', fp);
3359               fputs (_("[Revoked]"), fp);
3360             }
3361           if (subkey->invalid)
3362             {
3363               putc (' ', fp);
3364               fputs (_("[Invalid]"), fp);
3365             }
3366           if (subkey->expired)
3367             {
3368               putc (' ', fp);
3369               fputs (_("[Expired]"), fp);
3370             }
3371           if (subkey->disabled)
3372             {
3373               putc (' ', fp);
3374               fputs (_("[Disabled]"), fp);
3375             }
3376           putc ('\n', fp);
3377
3378           if (subkey->timestamp > 0)
3379             {
3380               tt = subkey->timestamp;
3381
3382               tm = localtime (&tt);
3383 #ifdef HAVE_LANGINFO_D_T_FMT
3384               strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
3385 #else
3386               strftime (shortbuf, sizeof shortbuf, "%c", tm);
3387 #endif
3388               fprintf (fp, _("Valid From : %s\n"), shortbuf);
3389             }
3390
3391           if (subkey->expires > 0)
3392             {
3393               tt = subkey->expires;
3394
3395               tm = localtime (&tt);
3396 #ifdef HAVE_LANGINFO_D_T_FMT
3397               strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
3398 #else
3399               strftime (shortbuf, sizeof shortbuf, "%c", tm);
3400 #endif
3401               fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
3402             }
3403
3404           if (subkey)
3405             s = gpgme_pubkey_algo_name (subkey->pubkey_algo);
3406           else
3407             s = "?";
3408
3409           if (subkey)
3410             aval = subkey->length;
3411           else
3412             aval = 0;
3413
3414           fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), "PGP", aval, s);
3415
3416           fprintf (fp, _("Key Usage .: "));
3417           delim = "";
3418
3419           if (subkey->can_encrypt)
3420             {
3421               fprintf (fp, "%s%s", delim, _("encryption"));
3422               delim = _(", ");
3423             }
3424           if (subkey->can_sign)
3425             {
3426               fprintf (fp, "%s%s", delim, _("signing"));
3427               delim = _(", ");
3428             }
3429           if (subkey->can_certify)
3430             {
3431               fprintf (fp, "%s%s", delim, _("certification"));
3432               delim = _(", ");
3433             }
3434           putc ('\n', fp);
3435         }
3436     }
3437
3438   if (Locale)
3439     setlocale (LC_TIME, "C");
3440 }
3441
3442
3443 /* Show detailed information about the selected key */
3444 static void 
3445 verify_key (crypt_key_t *key)
3446 {
3447   FILE *fp;
3448   char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
3449   const char *s;
3450   gpgme_ctx_t listctx = NULL;
3451   gpgme_error_t err;
3452   gpgme_key_t k = NULL;
3453   int maxdepth = 100;
3454
3455   mutt_mktemp (tempfile);
3456   if (!(fp = safe_fopen (tempfile, "w")))
3457     {
3458       mutt_perror _("Can't create temporary file");
3459       return;
3460     }
3461   mutt_message _("Collecting data...");
3462
3463   print_key_info (key->kobj, fp);
3464
3465   err = gpgme_new (&listctx);
3466   if (err)
3467     {
3468       fprintf (fp, "Internal error: can't create gpgme context: %s\n",
3469                gpgme_strerror (err));
3470       goto leave;
3471     }
3472   if ((key->flags & KEYFLAG_ISX509))
3473       gpgme_set_protocol (listctx, GPGME_PROTOCOL_CMS);
3474
3475   k = key->kobj;
3476   gpgme_key_ref (k);
3477   while ((s = k->chain_id) && k->subkeys && strcmp (s, k->subkeys->fpr) )
3478     {
3479       putc ('\n', fp);
3480       err = gpgme_op_keylist_start (listctx, s, 0);
3481       gpgme_key_release (k);
3482       k = NULL;
3483       if (!err)
3484         err = gpgme_op_keylist_next (listctx, &k);
3485       if (err)
3486         {
3487           fprintf (fp, _("Error finding issuer key: %s\n"),
3488                    gpgme_strerror (err));
3489           goto leave;
3490         }
3491       gpgme_op_keylist_end (listctx);
3492       
3493       print_key_info (k, fp);
3494       if (!--maxdepth)
3495         {
3496           putc ('\n', fp);
3497           fputs (_("Error: certification chain to long - stopping here\n"),
3498                  fp);
3499           break;
3500         }
3501     }
3502
3503  leave:
3504   gpgme_key_release (k);
3505   gpgme_release (listctx);
3506   safe_fclose (&fp);
3507   mutt_clear_error ();
3508   snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"),  crypt_keyid (key));
3509   mutt_do_pager (cmd, tempfile, 0, NULL);
3510 }
3511
3512 /* 
3513  * Implementation of `findkeys'.
3514  */
3515
3516
3517 /* Convert LIST into a pattern string suitable to be passed to GPGME.
3518    We need to convert spaces in an item into a '+' and '%' into
3519    "%25". */
3520 static char *list_to_pattern (LIST *list)
3521 {
3522   LIST *l;
3523   char *pattern, *p;
3524   const char *s;
3525   size_t n;
3526
3527   n = 0;
3528   for(l=list; l; l = l->next)
3529     {
3530       for(s = l->data; *s; s++)
3531         {
3532           if (*s == '%')
3533             n += 2;
3534           n++;
3535         }
3536       n++; /* delimiter or end of string */
3537     }
3538   n++; /* make sure to allocate at least one byte */
3539   pattern = p = safe_calloc (1,n);
3540   for(l=list; l; l = l->next)
3541     {
3542       s = l->data;
3543       if (*s)
3544         {
3545           if (l != list)
3546             *p++ = ' ';
3547           for(s = l->data; *s; s++)
3548             {
3549               if (*s == '%')
3550                 {
3551                   *p++ = '%';
3552                   *p++ = '2';
3553                   *p++ = '5';
3554                 }
3555               else if (*s == '+')
3556                 {
3557                   *p++ = '%';
3558                   *p++ = '2';
3559                   *p++ = 'B';
3560                 }
3561               else if (*s == ' ')
3562                 *p++ = '+';
3563               else
3564                 *p++ = *s;
3565             }
3566         }
3567     }
3568   *p = 0;
3569   return pattern;
3570 }
3571
3572 /* Return a list of keys which are candidates for the selection.
3573    Select by looking at the HINTS list. */
3574 static crypt_key_t *get_candidates (LIST * hints, unsigned int app, int secret)
3575 {
3576   crypt_key_t *db, *k, **kend;
3577   char *pattern;
3578   gpgme_error_t err;
3579   gpgme_ctx_t ctx;
3580   gpgme_key_t key;
3581   int idx;
3582   gpgme_user_id_t uid = NULL;
3583
3584   pattern = list_to_pattern (hints);
3585   if (!pattern)
3586     return NULL;
3587   
3588   err = gpgme_new (&ctx);
3589   if (err) 
3590     {
3591       mutt_error (_("gpgme_new failed: %s"), gpgme_strerror (err));
3592       FREE (&pattern);
3593       return NULL;
3594     }
3595
3596   db = NULL;
3597   kend = &db;
3598   
3599   if ((app & APPLICATION_PGP))
3600     {
3601       /* Its all a mess.  That old GPGME expects different things
3602          depending on the protocol.  For gpg we don' t need percent
3603          escaped pappert but simple strings passed in an array to the
3604          keylist_ext_start function. */
3605       LIST *l;
3606       size_t n;
3607       char **patarr;
3608
3609       for(l=hints, n=0; l; l = l->next)
3610         {
3611           if (l->data && *l->data)
3612             n++;
3613         }
3614       if (!n)
3615         goto no_pgphints;
3616
3617       patarr = safe_calloc (n+1, sizeof *patarr);
3618       for(l=hints, n=0; l; l = l->next)
3619         {
3620           if (l->data && *l->data)
3621             patarr[n++] = safe_strdup (l->data);
3622         }
3623       patarr[n] = NULL;
3624       err = gpgme_op_keylist_ext_start (ctx, (const char**)patarr, secret, 0);
3625       for (n=0; patarr[n]; n++)
3626         FREE (&patarr[n]);
3627       FREE (&patarr);
3628       if (err) 
3629         {
3630           mutt_error (_("gpgme_op_keylist_start failed: %s"),
3631                       gpgme_strerror (err));
3632           gpgme_release (ctx);
3633           FREE (&pattern);
3634           return NULL;
3635         }
3636
3637       while (!(err = gpgme_op_keylist_next (ctx, &key)) )
3638         {
3639           unsigned int flags = 0;
3640           
3641           if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3642             flags |= KEYFLAG_CANENCRYPT;
3643           if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3644             flags |= KEYFLAG_CANSIGN;
3645
3646 #if 0 /* DISABLED code */
3647           if (!flags)
3648             {
3649               /* Bug in gpg.  Capabilities are not listed for secret
3650                  keys.  Try to deduce them from the algorithm. */
3651
3652               switch (key->subkeys[0].pubkey_algo)
3653                 {
3654                 case GPGME_PK_RSA:
3655                   flags |= KEYFLAG_CANENCRYPT;
3656                   flags |= KEYFLAG_CANSIGN;
3657                   break;
3658                 case GPGME_PK_ELG_E:
3659                   flags |= KEYFLAG_CANENCRYPT;
3660                   break;
3661                 case GPGME_PK_DSA:
3662                   flags |= KEYFLAG_CANSIGN;
3663                   break;
3664                 }
3665             }
3666 #endif /* DISABLED code */
3667
3668           for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3669             {
3670               k = safe_calloc (1, sizeof *k);
3671               k->kobj = key;
3672               k->idx = idx;
3673               k->uid = uid->uid;
3674               k->flags = flags;
3675               *kend = k;
3676               kend = &k->next;
3677             }
3678         }
3679       if (gpg_err_code (err) != GPG_ERR_EOF)
3680         mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3681       gpgme_op_keylist_end (ctx);
3682     no_pgphints:
3683       ;
3684     }
3685
3686   if ((app & APPLICATION_SMIME))
3687     {
3688       /* and now look for x509 certificates */
3689       gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
3690       err = gpgme_op_keylist_start (ctx, pattern, 0);
3691       if (err) 
3692         {
3693           mutt_error (_("gpgme_op_keylist_start failed: %s"),
3694                       gpgme_strerror (err));
3695           gpgme_release (ctx);
3696           FREE (&pattern);
3697           return NULL;
3698         }
3699
3700       while (!(err = gpgme_op_keylist_next (ctx, &key)) )
3701         {
3702           unsigned int flags = KEYFLAG_ISX509;
3703
3704           if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
3705             flags |= KEYFLAG_CANENCRYPT;
3706           if (key_check_cap (key, KEY_CAP_CAN_SIGN))
3707             flags |= KEYFLAG_CANSIGN;
3708           
3709           for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3710             {
3711               k = safe_calloc (1, sizeof *k);
3712               k->kobj = key;
3713               k->idx = idx;
3714               k->uid = uid->uid;
3715               k->flags = flags;
3716               *kend = k;
3717               kend = &k->next;
3718             }
3719         }
3720       if (gpg_err_code (err) != GPG_ERR_EOF)
3721         mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
3722       gpgme_op_keylist_end (ctx);
3723     }
3724
3725   gpgme_release (ctx);
3726   FREE (&pattern);
3727   return db;
3728 }
3729
3730 /* Add the string STR to the list HINTS.  This list is later used to
3731    match addresses. */
3732 static LIST *crypt_add_string_to_hints (LIST *hints, const char *str)
3733 {
3734   char *scratch;
3735   char *t;
3736
3737   if ((scratch = safe_strdup (str)) == NULL)
3738     return hints;
3739
3740   for (t = strtok (scratch, " ,.:\"()<>\n"); t;
3741        t = strtok (NULL, " ,.:\"()<>\n"))
3742     {
3743       if (strlen (t) > 3)
3744         hints = mutt_add_list (hints, t);
3745     }
3746   
3747   FREE (&scratch);
3748   return hints;
3749 }
3750
3751 /* Display a menu to select a key from the array KEYS. FORCED_VALID
3752    will be set to true on return if the user did override the the
3753    key's validity. */
3754 static crypt_key_t *crypt_select_key (crypt_key_t *keys,
3755                                       ADDRESS * p, const char *s, 
3756                                       unsigned int app, int *forced_valid)
3757 {
3758   int keymax;
3759   crypt_key_t **key_table;
3760   MUTTMENU *menu;
3761   int i, done = 0;
3762   char helpstr[LONG_STRING], buf[LONG_STRING];
3763   crypt_key_t *k;
3764   int (*f) (const void *, const void *);
3765   int menu_to_use = 0;
3766   int unusable = 0;
3767
3768   *forced_valid = 0;
3769
3770   /* build the key table */
3771   keymax = i = 0;
3772   key_table = NULL;
3773   for (k = keys; k; k = k->next)
3774     {
3775       if (!option (OPTPGPSHOWUNUSABLE) && (k->flags & KEYFLAG_CANTUSE))
3776         {
3777           unusable = 1;
3778           continue;
3779         }
3780       
3781       if (i == keymax)
3782         {
3783           keymax += 20;
3784           safe_realloc (&key_table, sizeof (crypt_key_t*)*keymax);
3785         }
3786       
3787       key_table[i++] = k;
3788     }
3789
3790   if (!i && unusable)
3791     {
3792       mutt_error _("All matching keys are marked expired/revoked.");
3793       mutt_sleep (1);
3794       return NULL;
3795     }
3796
3797   switch (PgpSortKeys & SORT_MASK)
3798   {
3799     case SORT_DATE:
3800       f = crypt_compare_date;
3801       break;
3802     case SORT_KEYID:
3803       f = crypt_compare_keyid;
3804       break;
3805     case SORT_ADDRESS:
3806       f = crypt_compare_address;
3807       break;
3808     case SORT_TRUST:
3809     default:
3810       f = crypt_compare_trust;
3811       break;
3812   }
3813   qsort (key_table, i, sizeof (crypt_key_t*), f);
3814
3815   if (app & APPLICATION_PGP)
3816     menu_to_use = MENU_KEY_SELECT_PGP;
3817   else if (app & APPLICATION_SMIME)
3818     menu_to_use = MENU_KEY_SELECT_SMIME;
3819
3820   helpstr[0] = 0;
3821   mutt_make_help (buf, sizeof (buf), _("Exit  "), menu_to_use, OP_EXIT);
3822   strcat (helpstr, buf);        /* __STRCAT_CHECKED__ */
3823   mutt_make_help (buf, sizeof (buf), _("Select  "), menu_to_use,
3824                   OP_GENERIC_SELECT_ENTRY);
3825   strcat (helpstr, buf);        /* __STRCAT_CHECKED__ */
3826   mutt_make_help (buf, sizeof (buf), _("Check key  "),
3827                   menu_to_use, OP_VERIFY_KEY);
3828   strcat (helpstr, buf);        /* __STRCAT_CHECKED__ */
3829   mutt_make_help (buf, sizeof (buf), _("Help"), menu_to_use, OP_HELP);
3830   strcat (helpstr, buf);        /* __STRCAT_CHECKED__ */
3831
3832   menu = mutt_new_menu (menu_to_use);
3833   menu->max = i;
3834   menu->make_entry = crypt_entry;
3835   menu->help = helpstr;
3836   menu->data = key_table;
3837
3838   {
3839     const char *ts;
3840
3841     if ((app & APPLICATION_PGP) && (app &  APPLICATION_SMIME))
3842       ts = _("PGP and S/MIME keys matching");
3843     else if ((app & APPLICATION_PGP))
3844       ts = _("PGP keys matching");
3845     else if ((app & APPLICATION_SMIME))
3846       ts = _("S/MIME keys matching");
3847     else
3848       ts = _("keys matching");
3849
3850     if (p)
3851       snprintf (buf, sizeof (buf), _("%s <%s>."), ts, p->mailbox);
3852     else
3853       snprintf (buf, sizeof (buf), _("%s \"%s\"."), ts, s);
3854     menu->title = buf; 
3855   }
3856
3857   mutt_clear_error ();
3858   k = NULL;
3859   while (!done)
3860     {
3861       *forced_valid = 0;
3862       switch (mutt_menuLoop (menu))
3863         {
3864         case OP_VERIFY_KEY:
3865           verify_key (key_table[menu->current]);
3866           menu->redraw = REDRAW_FULL;
3867           break;
3868           
3869         case OP_VIEW_ID:
3870           mutt_message ("%s", key_table[menu->current]->uid);
3871           break;
3872           
3873         case OP_GENERIC_SELECT_ENTRY:
3874           /* FIXME make error reporting more verbose - this should be
3875              easy because gpgme provides more information */
3876           if (option (OPTPGPCHECKTRUST))
3877             {
3878             if (!crypt_key_is_valid (key_table[menu->current]))
3879               {
3880                 mutt_error _("This key can't be used: "
3881                              "expired/disabled/revoked.");
3882                 break;
3883               }
3884             }
3885           
3886           if (option (OPTPGPCHECKTRUST) &&
3887               (!crypt_id_is_valid (key_table[menu->current])
3888                || !crypt_id_is_strong (key_table[menu->current])))
3889             {
3890               const char *warn_s;
3891               char buff[LONG_STRING];
3892               
3893               if (key_table[menu->current]->flags & KEYFLAG_CANTUSE)
3894                 s = N_("ID is expired/disabled/revoked.");
3895               else 
3896                 {
3897                   gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
3898                   gpgme_user_id_t uid = NULL;
3899                   unsigned int j = 0;
3900
3901                   warn_s = "??";
3902
3903                   uid = key_table[menu->current]->kobj->uids;
3904                   for (j = 0; (j < key_table[menu->current]->idx) && uid;
3905                        j++, uid = uid->next)
3906                     ;
3907                   if (uid)
3908                     val = uid->validity;
3909
3910                   switch (val)
3911                     {
3912                     case GPGME_VALIDITY_UNKNOWN:   
3913                     case GPGME_VALIDITY_UNDEFINED: 
3914                       warn_s = N_("ID has undefined validity.");
3915                       break;
3916                     case GPGME_VALIDITY_NEVER:     
3917                       warn_s = N_("ID is not valid.");
3918                       break;
3919                     case GPGME_VALIDITY_MARGINAL:  
3920                       warn_s = N_("ID is only marginally valid.");
3921                       break;
3922                     case GPGME_VALIDITY_FULL:      
3923                     case GPGME_VALIDITY_ULTIMATE:  
3924                       break;
3925                     }
3926
3927                   snprintf (buff, sizeof (buff),
3928                             _("%s Do you really want to use the key?"),
3929                             _(warn_s));
3930                   
3931                   if (mutt_yesorno (buff, 0) != 1)
3932                     {
3933                       mutt_clear_error ();
3934                       break;
3935                     }
3936                   *forced_valid = 1;
3937                 }
3938             }  
3939
3940           k = crypt_copy_key (key_table[menu->current]);
3941           done = 1;
3942           break;
3943           
3944         case OP_EXIT:
3945           k = NULL;
3946           done = 1;
3947           break;
3948         }
3949     }
3950   
3951   mutt_menuDestroy (&menu);
3952   FREE (&key_table);
3953
3954   set_option (OPTNEEDREDRAW);
3955   
3956   return k;
3957 }
3958
3959 static crypt_key_t *crypt_getkeybyaddr (ADDRESS * a, short abilities,
3960                                         unsigned int app, int *forced_valid)
3961 {
3962   ADDRESS *r, *p;
3963   LIST *hints = NULL;
3964
3965   int weak    = 0;
3966   int invalid = 0;
3967   int multi   = 0;
3968   int this_key_has_strong;
3969   int this_key_has_weak;
3970   int this_key_has_invalid;
3971   int match;
3972
3973   crypt_key_t *keys, *k;
3974   crypt_key_t *the_valid_key = NULL;
3975   crypt_key_t *matches = NULL;
3976   crypt_key_t **matches_endp = &matches;
3977   
3978   *forced_valid = 0;
3979
3980   if (a && a->mailbox)
3981     hints = crypt_add_string_to_hints (hints, a->mailbox);
3982   if (a && a->personal)
3983     hints = crypt_add_string_to_hints (hints, a->personal);
3984
3985   mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
3986   keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN) );
3987
3988   mutt_free_list (&hints);
3989   
3990   if (!keys)
3991     return NULL;
3992   
3993   dprint (5, (debugfile, "crypt_getkeybyaddr: looking for %s <%s>.",
3994               a->personal, a->mailbox));
3995
3996   for (k = keys; k; k = k->next)
3997     {
3998       dprint (5, (debugfile, "  looking at key: %s `%.15s'\n",
3999                   crypt_keyid (k), k->uid));
4000       
4001       if (abilities && !(k->flags & abilities))
4002         {
4003           dprint (5, (debugfile, "  insufficient abilities: Has %x, want %x\n",
4004                       k->flags, abilities));
4005           continue;
4006         }
4007
4008       this_key_has_weak    = 0; /* weak but valid match   */
4009       this_key_has_invalid = 0;   /* invalid match          */
4010       this_key_has_strong  = 0; /* strong and valid match */
4011       match                = 0;   /* any match            */
4012
4013       r = rfc822_parse_adrlist (NULL, k->uid);
4014       for (p = r; p; p = p->next)
4015         {
4016           int validity = crypt_id_matches_addr (a, p, k);
4017               
4018           if (validity & CRYPT_KV_MATCH)        /* something matches */
4019             match = 1;
4020
4021           /* is this key a strong candidate? */
4022           if ((validity & CRYPT_KV_VALID)
4023               && (validity & CRYPT_KV_STRONGID) 
4024               && (validity & CRYPT_KV_ADDR))
4025             {
4026               if (the_valid_key && the_valid_key != k)
4027                 multi             = 1;
4028               the_valid_key       = k;
4029               this_key_has_strong = 1;
4030             }
4031           else if ((validity & CRYPT_KV_MATCH)
4032                    && !(validity & CRYPT_KV_VALID))
4033             this_key_has_invalid = 1;
4034           else if ((validity & CRYPT_KV_MATCH) 
4035                    && (!(validity & CRYPT_KV_STRONGID)
4036                        || !(validity & CRYPT_KV_ADDR)))
4037             this_key_has_weak    = 1;
4038         }
4039       rfc822_free_address (&r);
4040       
4041       if (match)
4042         {
4043           crypt_key_t *tmp;
4044
4045           if (!this_key_has_strong && this_key_has_invalid)
4046             invalid = 1;
4047           if (!this_key_has_strong && this_key_has_weak)
4048             weak = 1;
4049
4050           *matches_endp = tmp = crypt_copy_key (k);
4051           matches_endp = &tmp->next;
4052           the_valid_key = tmp;
4053         }
4054     }
4055   
4056   crypt_free_key (&keys);
4057   
4058   if (matches)
4059     {
4060       if (the_valid_key && !multi && !weak 
4061           && !(invalid && option (OPTPGPSHOWUNUSABLE)))
4062         {       
4063           /* 
4064            * There was precisely one strong match on a valid ID, there
4065            * were no valid keys with weak matches, and we aren't
4066            * interested in seeing invalid keys.
4067            * 
4068            * Proceed without asking the user.
4069            */
4070           k = crypt_copy_key (the_valid_key);
4071         }
4072       else 
4073         {
4074           /* 
4075            * Else: Ask the user.
4076            */
4077           k = crypt_select_key (matches, a, NULL, app, forced_valid);
4078         }
4079       crypt_free_key (&matches);
4080     }
4081   else 
4082     k = NULL;
4083   
4084   return k;
4085 }
4086
4087
4088 static crypt_key_t *crypt_getkeybystr (char *p, short abilities,
4089                                        unsigned int app, int *forced_valid)
4090 {
4091   LIST *hints = NULL;
4092   crypt_key_t *keys;
4093   crypt_key_t *matches = NULL;
4094   crypt_key_t **matches_endp = &matches;
4095   crypt_key_t *k;
4096   int match;
4097
4098   mutt_message (_("Looking for keys matching \"%s\"..."), p);
4099
4100   *forced_valid = 0;
4101
4102   hints = crypt_add_string_to_hints (hints, p);
4103   keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
4104   mutt_free_list (&hints);
4105
4106   if (!keys)
4107     return NULL;
4108   
4109   for (k = keys; k; k = k->next)
4110     {
4111       if (abilities && !(k->flags & abilities))
4112         continue;
4113
4114       match = 0;
4115       dprint (5, (debugfile, "crypt_getkeybystr: matching \"%s\" against "
4116                   "key %s, \"%s\": ",  p, crypt_keyid (k), k->uid));
4117
4118       if (!*p
4119           || !mutt_strcasecmp (p, crypt_keyid (k))
4120           || (!mutt_strncasecmp (p, "0x", 2)
4121               && !mutt_strcasecmp (p + 2, crypt_keyid (k)))
4122           || (option (OPTPGPLONGIDS)
4123               && !mutt_strncasecmp (p, "0x", 2) 
4124               && !mutt_strcasecmp (p + 2, crypt_keyid (k) + 8))
4125           || mutt_stristr (k->uid, p))
4126         {
4127           crypt_key_t *tmp;
4128
4129           dprint (5, (debugfile, "match.\n"));
4130
4131           *matches_endp = tmp = crypt_copy_key (k);
4132           matches_endp = &tmp->next;
4133         }
4134     }
4135   
4136   crypt_free_key (&keys);
4137   
4138   if (matches)
4139     {
4140       k = crypt_select_key (matches, NULL, p, app, forced_valid);
4141       crypt_free_key (&matches);
4142       return k;
4143     }
4144   
4145   return NULL;
4146 }
4147
4148 /* Display TAG as a prompt to ask for a key.  If WHATFOR is not null
4149    use it as default and store it under that label as the next
4150    default.  ABILITIES describe the required key abilities (sign,
4151    encrypt) and APP the type of the requested key; ether S/MIME or
4152    PGP.  Return a copy of the key or NULL if not found. */
4153 static crypt_key_t *crypt_ask_for_key (char *tag, 
4154                                        char *whatfor, 
4155                                        short abilities,
4156                                        unsigned int app,
4157                                        int *forced_valid)
4158 {
4159   crypt_key_t *key;
4160   char resp[SHORT_STRING];
4161   struct crypt_cache *l = NULL;
4162   int dummy;
4163
4164   if (!forced_valid)
4165     forced_valid = &dummy;
4166
4167   mutt_clear_error ();
4168
4169   *forced_valid = 0;
4170   resp[0] = 0;
4171   if (whatfor)
4172     {
4173       
4174       for (l = id_defaults; l; l = l->next)
4175         if (!mutt_strcasecmp (whatfor, l->what))
4176           {
4177             strfcpy (resp, NONULL (l->dflt), sizeof (resp));
4178             break;
4179           }
4180     }
4181
4182
4183   for (;;)
4184     {
4185       resp[0] = 0;
4186       if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0)
4187         return NULL;
4188       
4189       if (whatfor)
4190         {
4191           if (l)
4192             mutt_str_replace (&l->dflt, resp);
4193           else
4194             {
4195               l = safe_malloc (sizeof (struct crypt_cache));
4196               l->next = id_defaults;
4197               id_defaults = l;
4198               l->what = safe_strdup (whatfor);
4199               l->dflt = safe_strdup (resp);
4200             }
4201         }
4202       
4203       if ((key = crypt_getkeybystr (resp, abilities, app, forced_valid)))
4204         return key;
4205       
4206       BEEP ();
4207     }
4208   /* not reached */
4209 }
4210
4211 /* This routine attempts to find the keyids of the recipients of a
4212    message.  It returns NULL if any of the keys can not be found.  */
4213 static char *find_keys (ADDRESS *to, ADDRESS *cc, ADDRESS *bcc,
4214                         unsigned int app)
4215 {
4216   char *keyID, *keylist = NULL, *t;
4217   size_t keylist_size = 0;
4218   size_t keylist_used = 0;
4219   ADDRESS *tmp = NULL, *addr = NULL;
4220   ADDRESS **last = &tmp;
4221   ADDRESS *p, *q;
4222   int i;
4223   crypt_key_t *k_info, *key;
4224   const char *fqdn = mutt_fqdn (1);
4225
4226 #if 0
4227   *r_application = APPLICATION_PGP|APPLICATION_SMIME;
4228 #endif
4229   
4230   for (i = 0; i < 3; i++) 
4231     {
4232       switch (i)
4233         {
4234         case 0: p = to; break;
4235         case 1: p = cc; break;
4236         case 2: p = bcc; break;
4237         default: abort ();
4238         }
4239       
4240       *last = rfc822_cpy_adr (p, 0);
4241       while (*last)
4242         last = &((*last)->next);
4243     }
4244   
4245   if (fqdn)
4246     rfc822_qualify (tmp, fqdn);
4247   
4248   tmp = mutt_remove_duplicates (tmp);
4249   
4250   for (p = tmp; p ; p = p->next)
4251     {
4252       char buf[LONG_STRING];
4253       int forced_valid = 0;
4254       
4255       q = p;
4256       k_info = NULL;
4257       
4258       if ((keyID = mutt_crypt_hook (p)) != NULL)
4259         {
4260           int r;
4261           snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"),
4262                     keyID, p->mailbox);
4263           if ((r = mutt_yesorno (buf, M_YES)) == M_YES)
4264             {
4265               /* check for e-mail address */
4266               if ((t = strchr (keyID, '@')) && 
4267                   (addr = rfc822_parse_adrlist (NULL, keyID)))
4268                 {
4269                   if (fqdn)
4270                     rfc822_qualify (addr, fqdn);
4271                   q = addr;
4272                 }
4273               else
4274                 {
4275 #if 0             
4276                   k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT, 
4277                                               *r_application, &forced_valid);
4278 #else
4279                   k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT, 
4280                                               app, &forced_valid);
4281 #endif
4282                 }
4283             }
4284           else if (r == -1)
4285             {
4286               FREE (&keylist);
4287               rfc822_free_address (&tmp);
4288               rfc822_free_address (&addr);
4289               return NULL;
4290             }
4291         }
4292
4293       if (k_info == NULL
4294           && (k_info = crypt_getkeybyaddr (q, KEYFLAG_CANENCRYPT,
4295                                            app, &forced_valid)) == NULL)
4296         {
4297           snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
4298           
4299           if ((key = crypt_ask_for_key (buf, q->mailbox,
4300                                         KEYFLAG_CANENCRYPT,
4301 #if 0
4302                                         *r_application,
4303 #else
4304                                         app,
4305 #endif
4306                                         &forced_valid)) == NULL)
4307             {
4308               FREE (&keylist);
4309               rfc822_free_address (&tmp);
4310               rfc822_free_address (&addr);
4311               return NULL;
4312             }
4313         }
4314       else
4315         key = k_info;
4316
4317       {
4318         const char *s = crypt_fpr (key);
4319
4320 #if 0
4321         if (key->flags & KEYFLAG_ISX509)
4322           *r_application &= ~APPLICATION_PGP;
4323         if (!(key->flags & KEYFLAG_ISX509))
4324           *r_application &= ~APPLICATION_SMIME;
4325 #endif
4326       
4327         keylist_size += mutt_strlen (s) + 4 + 1;
4328         safe_realloc (&keylist, keylist_size);
4329         sprintf (keylist + keylist_used, "%s0x%s%s", /* __SPRINTF_CHECKED__ */
4330                  keylist_used ? " " : "",  s,
4331                  forced_valid? "!":"");
4332       }
4333       keylist_used = mutt_strlen (keylist);
4334         
4335       crypt_free_key (&key);
4336       rfc822_free_address (&addr);
4337     }
4338   rfc822_free_address (&tmp);
4339   return (keylist);
4340 }
4341
4342 char *pgp_gpgme_findkeys (ADDRESS *to, ADDRESS *cc, ADDRESS *bcc)
4343 {
4344   return find_keys (to, cc, bcc, APPLICATION_PGP);
4345 }
4346
4347 char *smime_gpgme_findkeys (ADDRESS *to, ADDRESS *cc, ADDRESS *bcc)
4348 {
4349   return find_keys (to, cc, bcc, APPLICATION_SMIME);
4350 }
4351
4352 /*
4353  * Implementation of `init'.
4354  */
4355
4356 /* Initialization.  */
4357 static void init_gpgme (void)
4358 {
4359   /* Make sure that gpg-agent is running.  */
4360   if (! getenv ("GPG_AGENT_INFO"))
4361     {
4362       mutt_error (_("\nUsing GPGME backend, although no gpg-agent is running"));
4363       if (mutt_any_key_to_continue (NULL) == -1)
4364         mutt_exit(1);
4365     }
4366 }
4367
4368 void pgp_gpgme_init (void)
4369 {
4370   init_gpgme ();
4371 }
4372
4373 void smime_gpgme_init (void)
4374 {
4375 }
4376
4377 static int gpgme_send_menu (HEADER *msg, int *redraw, int is_smime)
4378 {
4379   crypt_key_t *p;
4380   char input_signas[SHORT_STRING];
4381   int choice;
4382
4383   if (msg->security & APPLICATION_PGP)
4384     is_smime = 0;
4385   else if (msg->security & APPLICATION_SMIME)
4386     is_smime = 1;
4387
4388   if (is_smime)
4389     choice = mutt_multi_choice (
4390     _("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?"),
4391              _("esabpfc"));
4392   else 
4393     choice = mutt_multi_choice (
4394     _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?"),
4395                 _("esabmfc"));
4396
4397   switch (choice)
4398   {
4399   case 1: /* (e)ncrypt */
4400     msg->security |= (is_smime ? SMIMEENCRYPT : PGPENCRYPT);
4401     msg->security &= ~(is_smime ? SMIMESIGN : PGPSIGN);
4402     break;
4403
4404   case 2: /* (s)ign */
4405     msg->security |= (is_smime? SMIMESIGN :PGPSIGN);
4406     msg->security &= ~(is_smime ? SMIMEENCRYPT : PGPENCRYPT);
4407     break;
4408
4409   case 3: /* sign (a)s */
4410 /*      unset_option(OPTCRYPTCHECKTRUST); */
4411     if ((p = crypt_ask_for_key (_("Sign as: "), NULL, KEYFLAG_CANSIGN,
4412                                 is_smime? APPLICATION_SMIME:APPLICATION_PGP,
4413                                 NULL)))
4414     {
4415       snprintf (input_signas, sizeof (input_signas), "0x%s", crypt_keyid (p));
4416       mutt_str_replace (is_smime? &SmimeDefaultKey : &PgpSignAs, input_signas);
4417       crypt_free_key (&p); 
4418       
4419       msg->security |= (is_smime? SMIMESIGN:PGPSIGN);
4420     }
4421 #if 0
4422     else
4423     {
4424       msg->security &= (is_smime? ~SMIMESIGN : ~PGPSIGN);
4425     }
4426 #endif
4427     *redraw = REDRAW_FULL;
4428     break;
4429
4430   case 4: /* (b)oth */
4431     msg->security = (is_smime? (SMIMEENCRYPT|SMIMESIGN):(PGPENCRYPT|PGPSIGN));
4432     break;
4433
4434   case 5: /* (p)gp or s/(m)ime */
4435     is_smime = !is_smime;
4436     break;
4437
4438   case 6: /* (f)orget it */
4439   case 7: /* (c)lear */
4440     msg->security = 0;
4441     break;
4442   }
4443
4444   if (choice == 6 || choice == 7)
4445     ;
4446   else if (is_smime)
4447     {
4448       msg->security &= ~APPLICATION_PGP;
4449       msg->security |= APPLICATION_SMIME;
4450     }
4451   else
4452     {
4453       msg->security &= ~APPLICATION_SMIME;
4454       msg->security |= APPLICATION_PGP;
4455     }
4456   
4457   return (msg->security);
4458 }
4459
4460 int pgp_gpgme_send_menu (HEADER *msg, int *redraw)
4461 {
4462   return gpgme_send_menu (msg, redraw, 0);
4463 }
4464
4465 int smime_gpgme_send_menu (HEADER *msg, int *redraw)
4466 {
4467   return gpgme_send_menu (msg, redraw, 1);
4468 }
4469
4470 static int verify_sender (HEADER *h, gpgme_protocol_t protocol)
4471 {
4472   ADDRESS *sender = NULL;
4473   unsigned int ret = 1;
4474
4475   if (h->env->from)
4476     {
4477       h->env->from = mutt_expand_aliases (h->env->from);
4478       sender = h->env->from;
4479     }
4480   else if (h->env->sender)
4481     {
4482       h->env->sender = mutt_expand_aliases (h->env->sender);
4483       sender = h->env->sender;
4484     }
4485
4486   if (sender)
4487     {
4488       if (signature_key)
4489         {
4490           gpgme_key_t key = signature_key;
4491           gpgme_user_id_t uid = NULL;
4492           int sender_length = 0;
4493           int uid_length = 0;
4494
4495           sender_length = strlen (sender->mailbox);
4496           for (uid = key->uids; uid && ret; uid = uid->next)
4497             {
4498               uid_length = strlen (uid->email);
4499               if (1
4500                   && (uid->email[0] == '<')
4501                   && (uid->email[uid_length - 1] == '>')
4502                   && (uid_length == sender_length + 2)
4503                   && (! strncmp (uid->email + 1, sender->mailbox, sender_length)))
4504                 ret = 0;
4505             }
4506         }
4507       else
4508         mutt_any_key_to_continue (_("Failed to verify sender"));
4509     }
4510   else
4511     mutt_any_key_to_continue (_("Failed to figure out sender"));
4512
4513   if (signature_key)
4514     {
4515       gpgme_key_release (signature_key);
4516       signature_key = NULL;
4517     }
4518
4519   return ret;
4520 }
4521
4522 int smime_gpgme_verify_sender (HEADER *h)
4523 {
4524   return verify_sender (h, GPGME_PROTOCOL_CMS);
4525 }
4526
4527 void gpgme_set_sender (const char *sender)
4528 {
4529   mutt_error ("[setting sender] mailbox: %s\n", sender);
4530   FREE (&current_sender);
4531   current_sender = safe_strdup (sender);
4532 }
4533
4534
4535 #endif