merge crypt back into $top_builddir :)
[apps/madmutt.git] / lib-crypt / crypt-gpgme.c
diff --git a/lib-crypt/crypt-gpgme.c b/lib-crypt/crypt-gpgme.c
deleted file mode 100644 (file)
index 5bd3173..0000000
+++ /dev/null
@@ -1,3909 +0,0 @@
-/*
- * Copyright notice from original mutt:
- * crypt-gpgme.c - GPGME based crypto operations
- * Copyright (C) 1996,1997 Michael R. Elkins <me@cs.hmc.edu>
- * Copyright (C) 1998,1999,2000 Thomas Roessler <roessler@guug.de>
- * Copyright (C) 2001  Thomas Roessler <roessler@guug.de>
- *                     Oliver Ehli <elmy@acm.org>
- * Copyright (C) 2002, 2003, 2004 g10 Code GmbH
- */
-/*
- * Copyright © 2006 Pierre Habouzit
- */
-
-#include <lib-lib/lib-lib.h>
-
-#include <gpgme.h>
-
-#include <lib-mime/mime.h>
-#include <lib-ui/curses.h>
-#include <lib-ui/enter.h>
-#include <lib-ui/menu.h>
-
-#include "crypt.h"
-
-#include "lib.h"
-#include "alias.h"
-#include "handler.h"
-#include "copy.h"
-#include "pager.h"
-#include "recvattach.h"
-#include "sort.h"
-
-/* Values used for comparing addresses. */
-#define CRYPT_KV_VALID    1
-#define CRYPT_KV_ADDR     2
-#define CRYPT_KV_STRING   4
-#define CRYPT_KV_STRONGID 8
-#define CRYPT_KV_MATCH (CRYPT_KV_ADDR|CRYPT_KV_STRING)
-
-/*
- * Type definitions.
- */
-
-struct crypt_cache {
-  char *what;
-  char *dflt;
-  struct crypt_cache *next;
-};
-
-struct dn_array_s {
-  char *key;
-  char *value;
-};
-
-/* We work based on user IDs, getting from a user ID to the key is
-   check and does not need any memory (gpgme uses reference counting). */
-typedef struct crypt_keyinfo {
-  struct crypt_keyinfo *next;
-  gpgme_key_t kobj;
-  int idx;                      /* and the user ID at this index */
-  const char *uid;              /* and for convenience point to this user ID */
-  unsigned int flags;           /* global and per uid flags (for convenience) */
-} crypt_key_t;
-
-typedef struct crypt_entry {
-  ssize_t num;
-  crypt_key_t *key;
-} crypt_entry_t;
-
-
-static struct crypt_cache *id_defaults = NULL;
-static gpgme_key_t signature_key = NULL;
-
-/*
- * General helper functions.
- */
-
-/* return true when S points to a didgit or letter. */
-static int digit_or_letter (const unsigned char *s)
-{
-  return ((*s >= '0' && *s <= '9')
-          || (*s >= 'A' && *s <= 'Z')
-          || (*s >= 'a' && *s <= 'z'));
-}
-
-
-/* Print the utf-8 encoded string BUF of length LEN bytes to stream
-   FP. Convert the character set. */
-static void print_utf8 (FILE * fp, const char *buf, ssize_t len)
-{
-  char *tstr;
-
-  tstr = p_dupstr(buf, len);
-  mutt_convert_string (&tstr, "utf-8", MCharset.charset, M_ICONV_HOOK_FROM);
-  fputs (tstr, fp);
-  p_delete(&tstr);
-}
-
-
-/*
- * Key management.
- */
-
-/* Return the keyID for the key K.  Note that this string is valid as
-   long as K is valid */
-static const char *crypt_keyid (crypt_key_t * k)
-{
-  const char *s = "????????";
-
-  if (k->kobj && k->kobj->subkeys) {
-    s = k->kobj->subkeys->keyid;
-    if ((!option (OPTPGPLONGIDS)) && (m_strlen(s) == 16))
-      /* Return only the short keyID.  */
-      s += 8;
-  }
-
-  return s;
-}
-
-/* Return the hexstring fingerprint from the key K. */
-static const char *crypt_fpr (crypt_key_t * k)
-{
-  const char *s = "";
-
-  if (k->kobj && k->kobj->subkeys)
-    s = k->kobj->subkeys->fpr;
-
-  return s;
-}
-
-/* Parse FLAGS and return a statically allocated(!) string with them. */
-static char *crypt_key_abilities (int flags)
-{
-  static char buff[3];
-
-  if (!(flags & KEYFLAG_CANENCRYPT))
-    buff[0] = '-';
-  else if (flags & KEYFLAG_PREFER_SIGNING)
-    buff[0] = '.';
-  else
-    buff[0] = 'e';
-
-  if (!(flags & KEYFLAG_CANSIGN))
-    buff[1] = '-';
-  else if (flags & KEYFLAG_PREFER_ENCRYPTION)
-    buff[1] = '.';
-  else
-    buff[1] = 's';
-
-  buff[2] = '\0';
-
-  return buff;
-}
-
-/* Parse FLAGS and return a character describing the most important flag. */
-static char crypt_flags (int flags)
-{
-  if (flags & KEYFLAG_REVOKED)
-    return 'R';
-  else if (flags & KEYFLAG_EXPIRED)
-    return 'X';
-  else if (flags & KEYFLAG_DISABLED)
-    return 'd';
-  else if (flags & KEYFLAG_CRITICAL)
-    return 'c';
-  else
-    return ' ';
-}
-
-/* Return a copy of KEY. */
-static crypt_key_t *crypt_copy_key (crypt_key_t *key)
-{
-  crypt_key_t *k;
-
-  k = p_new(crypt_key_t, 1);
-  k->kobj = key->kobj;
-  gpgme_key_ref (key->kobj);
-  k->idx = key->idx;
-  k->uid = key->uid;
-  k->flags = key->flags;
-
-  return k;
-}
-
-/* Release all the keys at the address of KEYLIST and set the address
-   to NULL. */
-static void crypt_free_key (crypt_key_t ** keylist)
-{
-  while (*keylist) {
-    crypt_key_t *k = (*keylist)->next;
-
-    p_delete(&k);
-    *keylist = k;
-  }
-}
-
-/* Return trute when key K is valid. */
-static int crypt_key_is_valid (crypt_key_t * k)
-{
-  if (k->flags & KEYFLAG_CANTUSE)
-    return 0;
-  return 1;
-}
-
-/* Return true whe validity of KEY is sufficient. */
-static int crypt_id_is_strong (crypt_key_t * key)
-{
-  gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
-  gpgme_user_id_t uid = NULL;
-  int is_strong = 0;
-  int i = 0;
-
-  if ((key->flags & KEYFLAG_ISX509))
-    return 1;
-
-  for (i = 0, uid = key->kobj->uids; (i < key->idx) && uid;
-       i++, uid = uid->next);
-  if (uid)
-    val = uid->validity;
-
-  switch (val) {
-  case GPGME_VALIDITY_UNKNOWN:
-  case GPGME_VALIDITY_UNDEFINED:
-  case GPGME_VALIDITY_NEVER:
-  case GPGME_VALIDITY_MARGINAL:
-    is_strong = 0;
-    break;
-
-  case GPGME_VALIDITY_FULL:
-  case GPGME_VALIDITY_ULTIMATE:
-    is_strong = 1;
-    break;
-  }
-
-  return is_strong;
-}
-
-/* Return true when the KEY is valid, i.e. not marked as unusable. */
-static int crypt_id_is_valid (crypt_key_t * key)
-{
-  return !(key->flags & KEYFLAG_CANTUSE);
-}
-
-/* Return a bit vector describing how well the addresses ADDR and
-   U_ADDR match and whether KEY is valid. */
-static int crypt_id_matches_addr (address_t * addr, address_t * u_addr,
-                                  crypt_key_t * key)
-{
-  int rv = 0;
-
-  if (crypt_id_is_valid (key))
-    rv |= CRYPT_KV_VALID;
-
-  if (crypt_id_is_strong (key))
-    rv |= CRYPT_KV_STRONGID;
-
-  if (addr->mailbox && u_addr->mailbox
-      && m_strcasecmp(addr->mailbox, u_addr->mailbox) == 0)
-    rv |= CRYPT_KV_ADDR;
-
-  if (addr->personal && u_addr->personal
-      && m_strcasecmp(addr->personal, u_addr->personal) == 0)
-    rv |= CRYPT_KV_STRING;
-
-  return rv;
-}
-
-
-/*
- * GPGME convenient functions.
- */
-
-/* Create a new gpgme context and return it.  With FOR_SMIME set to
-   true, the protocol of the context is set to CMS. */
-static gpgme_ctx_t create_gpgme_context (int for_smime)
-{
-  gpgme_error_t err;
-  gpgme_ctx_t ctx;
-
-  err = gpgme_new (&ctx);
-  if (err) {
-    mutt_error (_("error creating gpgme context: %s\n"), gpgme_strerror (err));
-    sleep (2);
-    mutt_exit (1);
-  }
-
-  if (for_smime) {
-    err = gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
-    if (err) {
-      mutt_error (_("error enabling CMS protocol: %s\n"), gpgme_strerror (err));
-      sleep (2);
-      mutt_exit (1);
-    }
-  }
-
-  return ctx;
-}
-
-/* Create a new gpgme data object.  This is a wrapper to die on
-   error. */
-static gpgme_data_t create_gpgme_data (void)
-{
-  gpgme_error_t err;
-  gpgme_data_t data;
-
-  err = gpgme_data_new (&data);
-  if (err) {
-    mutt_error (_("error creating gpgme data object: %s\n"),
-                gpgme_strerror (err));
-    sleep (2);
-    mutt_exit (1);
-  }
-  return data;
-}
-
-/* Create a new GPGME Data object from the mail body A.  With CONVERT
-   passed as true, the lines are converted to CR,LF if required.
-   Return NULL on error or the gpgme_data_t object on success. */
-static gpgme_data_t body_to_data_object (BODY * a, int convert)
-{
-  char tempfile[_POSIX_PATH_MAX];
-  FILE *fptmp;
-  int err = 0;
-  gpgme_data_t data;
-
-  fptmp = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
-  if (!fptmp) {
-    mutt_perror (_("Can't create temporary file"));
-    return NULL;
-  }
-
-  mutt_write_mime_header (a, fptmp);
-  fputc ('\n', fptmp);
-  mutt_write_mime_body (a, fptmp);
-
-  if (convert) {
-    int c, hadcr = 0;
-    unsigned char buf[1];
-
-    data = create_gpgme_data ();
-    rewind (fptmp);
-    while ((c = fgetc (fptmp)) != EOF) {
-      if (c == '\r')
-        hadcr = 1;
-      else {
-        if (c == '\n' && !hadcr) {
-          buf[0] = '\r';
-          gpgme_data_write (data, buf, 1);
-        }
-
-        hadcr = 0;
-      }
-      /* FIXME: This is quite suboptimal */
-      buf[0] = c;
-      gpgme_data_write (data, buf, 1);
-    }
-    gpgme_data_seek (data, 0, SEEK_SET);
-  } else {
-    err = gpgme_data_new_from_file (&data, tempfile, 1);
-  }
-  m_fclose(&fptmp);
-  unlink (tempfile);
-  if (err) {
-    mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
-    return NULL;
-  }
-
-  return data;
-}
-
-/* Create a GPGME data object from the stream FP but limit the object
-   to LENGTH bytes starting at OFFSET bytes from the beginning of the
-   file. */
-static gpgme_data_t file_to_data_object (FILE * fp, long offset, long length)
-{
-  int err = 0;
-  gpgme_data_t data;
-
-  err = gpgme_data_new_from_filepart (&data, NULL, fp, offset, length);
-  if (err) {
-    mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
-    return NULL;
-  }
-
-  return data;
-}
-
-/* Write a GPGME data object to the stream FP. */
-static int data_object_to_stream (gpgme_data_t data, FILE * fp)
-{
-  int err;
-  char buf[4096], *p;
-  ssize_t nread;
-
-  err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
-         ? gpgme_error_from_errno (errno) : 0);
-  if (err) {
-    mutt_error (_("error rewinding data object: %s\n"), gpgme_strerror (err));
-    return -1;
-  }
-
-  while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
-    /* fixme: we are not really converting CRLF to LF but just
-       skipping CR. Doing it correctly needs a more complex logic */
-    for (p = buf; nread; p++, nread--) {
-      if (*p != '\r')
-        putc (*p, fp);
-    }
-
-    if (ferror (fp)) {
-      mutt_perror ("[tempfile]");
-      return -1;
-    }
-  }
-  if (nread == -1) {
-    mutt_error (_("error reading data object: %s\n"), strerror (errno));
-    return -1;
-  }
-  return 0;
-}
-
-/* Copy a data object to a newly created temporay file and return that
-   filename. Caller must free.  With RET_FP not NULL, don't close the
-   stream but return it there. */
-static char *data_object_to_tempfile (gpgme_data_t data, FILE ** ret_fp)
-{
-  int err;
-  char tempfile[_POSIX_PATH_MAX];
-  FILE *fp;
-  ssize_t nread = 0;
-
-  fp = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
-  if (!fp) {
-    mutt_perror (_("Can't create temporary file"));
-    return NULL;
-  }
-
-  err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1)
-         ? gpgme_error_from_errno (errno) : 0);
-  if (!err) {
-    char buf[4096];
-
-    while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
-      if (fwrite (buf, nread, 1, fp) != 1) {
-        mutt_perror (_("Can't create temporary file"));
-        m_fclose(&fp);
-        unlink (tempfile);
-        return NULL;
-      }
-    }
-  }
-  if (ret_fp)
-    rewind (fp);
-  else
-    m_fclose(&fp);
-  if (nread == -1) {
-    mutt_error (_("error reading data object: %s\n"), gpgme_strerror (err));
-    unlink (tempfile);
-    m_fclose(&fp);
-    return NULL;
-  }
-  if (ret_fp)
-    *ret_fp = fp;
-  return m_strdup(tempfile);
-}
-
-
-/* FIXME: stolen from gpgme to avoid "ambiguous identity" errors */
-static gpgme_error_t
-gpgme_get_key2 (gpgme_ctx_t ctx, const char *fpr, gpgme_key_t *r_key,
-              int secret)
-{
-  gpgme_ctx_t listctx;
-  gpgme_error_t err;
-
-  if (!ctx || !r_key || !fpr)
-    return gpg_error (GPG_ERR_INV_VALUE);
-
-  if (strlen (fpr) < 8)        /* We have at least a key ID.  */
-    return gpg_error (GPG_ERR_INV_VALUE);
-
-  /* FIXME: We use our own context because we have to avoid the user's
-     I/O callback handlers.  */
-  err = gpgme_new (&listctx);
-  if (err)
-    return err;
-  gpgme_set_protocol (listctx, gpgme_get_protocol (ctx));
-  err = gpgme_op_keylist_start (listctx, fpr, secret);
-  if (!err)
-    err = gpgme_op_keylist_next (listctx, r_key);
-  gpgme_release (listctx);
-  return err;
-}
-
-/* Create a GpgmeRecipientSet from the keys in the string KEYLIST.
-   The keys must be space delimited. */
-static gpgme_key_t *create_recipient_set (const char *keylist,
-                                          gpgme_protocol_t protocol)
-{
-  int err;
-  const char *s;
-  char buf[100];
-  int i;
-  gpgme_key_t *rset = NULL;
-  unsigned int rset_n = 0;
-  gpgme_key_t key = NULL;
-  gpgme_ctx_t context = NULL;
-
-  err = gpgme_new (&context);
-  if (!err)
-    err = gpgme_set_protocol (context, protocol);
-
-  if (!err) {
-    s = keylist;
-    do {
-      while (*s == ' ')
-        s++;
-      for (i = 0; *s && *s != ' ' && i < ssizeof(buf) - 1;)
-        buf[i++] = *s++;
-      buf[i] = 0;
-      if (*buf) {
-        if (i > 1 && buf[i - 1] == '!') {
-          /* The user selected to override the valididy of that
-             key. */
-          buf[i - 1] = 0;
-
-          err = gpgme_get_key2 (context, buf, &key, 0);
-          if (!err)
-            key->uids->validity = GPGME_VALIDITY_FULL;
-          buf[i - 1] = '!';
-        }
-        else
-          err = gpgme_get_key2 (context, buf, &key, 0);
-
-        if (!err) {
-          p_realloc(&rset, rset_n + 1);
-          rset[rset_n++] = key;
-        }
-        else {
-          mutt_error (_("error adding recipient `%s': %s\n"),
-                      buf, gpgme_strerror (err));
-          p_delete(&rset);
-          return NULL;
-        }
-      }
-    } while (*s);
-  }
-
-  /* NULL terminate.  */
-  p_realloc(&rset, rset_n + 1);
-  rset[rset_n++] = NULL;
-
-  if (context)
-    gpgme_release (context);
-
-  return rset;
-}
-
-
-/* Make sure that the correct signer is set. Returns 0 on success. */
-static int set_signer (gpgme_ctx_t ctx, int for_smime)
-{
-  char *signid = for_smime ? SmimeDefaultKey : PgpSignAs;
-  gpgme_error_t err;
-  gpgme_ctx_t listctx;
-  gpgme_key_t key, key2;
-
-  if (!signid || !*signid)
-    return 0;
-
-  listctx = create_gpgme_context (for_smime);
-  err = gpgme_op_keylist_start (listctx, signid, 1);
-  if (!err)
-    err = gpgme_op_keylist_next (listctx, &key);
-  if (err) {
-    gpgme_release (listctx);
-    mutt_error (_("secret key `%s' not found: %s\n"),
-                signid, gpgme_strerror (err));
-    return -1;
-  }
-  err = gpgme_op_keylist_next (listctx, &key2);
-  if (!err) {
-    gpgme_key_release (key);
-    gpgme_key_release (key2);
-    gpgme_release (listctx);
-    mutt_error (_("ambiguous specification of secret key `%s'\n"), signid);
-    return -1;
-  }
-  gpgme_op_keylist_end (listctx);
-  gpgme_release (listctx);
-
-  gpgme_signers_clear (ctx);
-  err = gpgme_signers_add (ctx, key);
-  gpgme_key_release (key);
-  if (err) {
-    mutt_error (_("error setting secret key `%s': %s\n"),
-                signid, gpgme_strerror (err));
-    return -1;
-  }
-  return 0;
-}
-
-
-/* Encrypt the gpgme data object PLAINTEXT to the recipients in RSET
-   and return an allocated filename to a temporary file containing the
-   enciphered text.  With USE_SMIME set to true, the smime backend is
-   used.  With COMBINED_SIGNED a PGP message is signed and
-   encrypted.  Returns NULL in case of error */
-static char *encrypt_gpgme_object (gpgme_data_t plaintext, gpgme_key_t * rset,
-                                   int use_smime, int combined_signed)
-{
-  int err;
-  gpgme_ctx_t ctx;
-  gpgme_data_t ciphertext;
-  char *outfile;
-
-  ctx = create_gpgme_context (use_smime);
-  if (!use_smime)
-    gpgme_set_armor (ctx, 1);
-
-  ciphertext = create_gpgme_data ();
-
-  if (combined_signed) {
-    if (set_signer (ctx, use_smime)) {
-      gpgme_data_release (ciphertext);
-      gpgme_release (ctx);
-      return NULL;
-    }
-    err = gpgme_op_encrypt_sign (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
-                                 plaintext, ciphertext);
-  }
-  else
-    err = gpgme_op_encrypt (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST,
-                            plaintext, ciphertext);
-  mutt_need_hard_redraw ();
-  if (err) {
-    mutt_error (_("error encrypting data: %s\n"), gpgme_strerror (err));
-    gpgme_data_release (ciphertext);
-    gpgme_release (ctx);
-    return NULL;
-  }
-
-  gpgme_release (ctx);
-
-  outfile = data_object_to_tempfile (ciphertext, NULL);
-  gpgme_data_release (ciphertext);
-  return outfile;
-}
-
-/* Find the "micalg" parameter from the last Gpgme operation on
-   context CTX.  It is expected that this operation was a sign
-   operation.  Return the algorithm name as a C string in buffer BUF
-   which must have been allocated by the caller with size BUFLEN.
-   Returns 0 on success or -1 in case of an error.  The return string
-   is truncted to BUFLEN - 1. */
-static int get_micalg (gpgme_ctx_t ctx, char *buf, ssize_t buflen)
-{
-  gpgme_sign_result_t result = NULL;
-  const char *algorithm_name = NULL;
-
-  if (!buflen)
-    return -1;
-
-  *buf = 0;
-  result = gpgme_op_sign_result (ctx);
-  if (result) {
-    algorithm_name = gpgme_hash_algo_name (result->signatures->hash_algo);
-    if (algorithm_name) {
-      m_strcpy(buf, buflen, algorithm_name);
-    }
-  }
-
-  return *buf ? 0 : -1;
-}
-
-static void print_time (time_t t, STATE * s)
-{
-  char p[STRING];
-
-  setlocale (LC_TIME, "");
-#ifdef HAVE_LANGINFO_D_T_FMT
-  strftime (p, sizeof (p), nl_langinfo (D_T_FMT), localtime (&t));
-#else
-  strftime (p, sizeof (p), "%c", localtime (&t));
-#endif
-  setlocale (LC_TIME, "C");
-  state_attach_puts (p, s);
-}
-
-/* Implementation of `sign_message'. */
-
-/* Sign the MESSAGE in body A either using OpenPGP or S/MIME when
-   USE_SMIME is passed as true.  Returns the new body or NULL on
-   error. */
-static BODY *sign_message (BODY * a, int use_smime)
-{
-  BODY *t;
-  char *sigfile;
-  int err = 0;
-  char buf[100];
-  gpgme_ctx_t ctx;
-  gpgme_data_t message, signature;
-
-  convert_to_7bit (a);          /* Signed data _must_ be in 7-bit format. */
-
-  message = body_to_data_object (a, 1);
-  if (!message)
-    return NULL;
-  signature = create_gpgme_data ();
-
-  ctx = create_gpgme_context (use_smime);
-  if (!use_smime)
-    gpgme_set_armor (ctx, 1);
-
-  if (set_signer (ctx, use_smime)) {
-    gpgme_data_release (signature);
-    gpgme_release (ctx);
-    return NULL;
-  }
-
-  err = gpgme_op_sign (ctx, message, signature, GPGME_SIG_MODE_DETACH);
-  mutt_need_hard_redraw ();
-  gpgme_data_release (message);
-  if (err) {
-    gpgme_data_release (signature);
-    gpgme_release (ctx);
-    mutt_error (_("error signing data: %s\n"), gpgme_strerror (err));
-    return NULL;
-  }
-
-  sigfile = data_object_to_tempfile (signature, NULL);
-  gpgme_data_release (signature);
-  if (!sigfile) {
-    gpgme_release (ctx);
-    return NULL;
-  }
-
-  t = body_new();
-  t->type = TYPEMULTIPART;
-  t->subtype = m_strdup("signed");
-  t->encoding = ENC7BIT;
-  t->use_disp = 0;
-  t->disposition = DISPINLINE;
-
-  parameter_set_boundary(&t->parameter);
-  parameter_setval(&t->parameter, "protocol",
-                   use_smime ? "application/pkcs7-signature"
-                             : "application/pgp-signature");
-  /* Get the micalg from gpgme.  Old gpgme versions don't support this
-     for S/MIME so we assume sha-1 in this case. */
-  if (!get_micalg (ctx, buf, sizeof buf))
-    parameter_setval(&t->parameter, "micalg", buf);
-  else if (use_smime)
-    parameter_setval(&t->parameter, "micalg", "sha1");
-  gpgme_release (ctx);
-
-  t->parts = a;
-  a = t;
-
-  t->parts->next = body_new();
-  t = t->parts->next;
-  t->type = TYPEAPPLICATION;
-  if (use_smime) {
-    t->subtype = m_strdup("pkcs7-signature");
-    parameter_setval(&t->parameter, "name", "smime.p7s");
-    t->encoding = ENCBASE64;
-    t->use_disp = 1;
-    t->disposition = DISPATTACH;
-    t->d_filename = m_strdup("smime.p7s");
-  }
-  else {
-    t->subtype = m_strdup("pgp-signature");
-    t->use_disp = 0;
-    t->disposition = DISPINLINE;
-    t->encoding = ENC7BIT;
-  }
-  t->filename = sigfile;
-  t->unlink = 1;                /* ok to remove this file after sending. */
-
-  return a;
-}
-
-
-BODY *crypt_pgp_sign_message (BODY * a)
-{
-  return sign_message (a, 0);
-}
-
-BODY *crypt_smime_sign_message (BODY * a)
-{
-  return sign_message (a, 1);
-}
-
-/*
- * Implementation of `encrypt_message'.
- */
-
-/* Encrypt the mail body A to all keys given as space separated keyids
-   or fingerprints in KEYLIST and return the encrypted body.  */
-BODY *crypt_pgp_encrypt_message (BODY * a, char *keylist, int sign)
-{
-  char *outfile = NULL;
-  BODY *t;
-  gpgme_key_t *rset = NULL;
-  gpgme_data_t plaintext;
-
-  rset = create_recipient_set (keylist, GPGME_PROTOCOL_OpenPGP);
-  if (!rset)
-    return NULL;
-
-  if (sign)
-    convert_to_7bit (a);
-  plaintext = body_to_data_object (a, 0);
-  if (!plaintext) {
-    p_delete(&rset);
-    return NULL;
-  }
-
-  outfile = encrypt_gpgme_object (plaintext, rset, 0, sign);
-  gpgme_data_release (plaintext);
-  p_delete(&rset);
-  if (!outfile)
-    return NULL;
-
-  t = body_new();
-  t->type = TYPEMULTIPART;
-  t->subtype = m_strdup("encrypted");
-  t->encoding = ENC7BIT;
-  t->use_disp = 0;
-  t->disposition = DISPINLINE;
-
-  parameter_set_boundary(&t->parameter);
-  parameter_setval(&t->parameter, "protocol", "application/pgp-encrypted");
-
-  t->parts = body_new();
-  t->parts->type = TYPEAPPLICATION;
-  t->parts->subtype = m_strdup("pgp-encrypted");
-  t->parts->encoding = ENC7BIT;
-
-  t->parts->next = body_new();
-  t->parts->next->type = TYPEAPPLICATION;
-  t->parts->next->subtype = m_strdup("octet-stream");
-  t->parts->next->encoding = ENC7BIT;
-  t->parts->next->filename = outfile;
-  t->parts->next->use_disp = 1;
-  t->parts->next->disposition = DISPINLINE;
-  t->parts->next->unlink = 1;   /* delete after sending the message */
-  t->parts->next->d_filename = m_strdup("msg.asc"); /* non pgp/mime
-                                                           can save */
-
-  return t;
-}
-
-/*
- * Implementation of `smime_build_smime_entity'.
- */
-
-/* Encrypt the mail body A to all keys given as space separated
-   fingerprints in KEYLIST and return the S/MIME encrypted body.  */
-BODY *crypt_smime_build_smime_entity (BODY * a, char *keylist)
-{
-  char *outfile = NULL;
-  BODY *t;
-  gpgme_key_t *rset = NULL;
-  gpgme_data_t plaintext;
-
-  rset = create_recipient_set (keylist, GPGME_PROTOCOL_CMS);
-  if (!rset)
-    return NULL;
-
-  plaintext = body_to_data_object (a, 0);
-  if (!plaintext) {
-    p_delete(&rset);
-    return NULL;
-  }
-
-  outfile = encrypt_gpgme_object (plaintext, rset, 1, 0);
-  gpgme_data_release (plaintext);
-  p_delete(&rset);
-  if (!outfile)
-    return NULL;
-
-  t = body_new();
-  t->type = TYPEAPPLICATION;
-  t->subtype = m_strdup("pkcs7-mime");
-  parameter_setval(&t->parameter, "name", "smime.p7m");
-  parameter_setval(&t->parameter, "smime-type", "enveloped-data");
-  t->encoding = ENCBASE64;      /* The output of OpenSSL SHOULD be binary */
-  t->use_disp = 1;
-  t->disposition = DISPATTACH;
-  t->d_filename = m_strdup("smime.p7m");
-  t->filename = outfile;
-  t->unlink = 1;                /*delete after sending the message */
-  t->parts = 0;
-  t->next = 0;
-
-  return t;
-}
-
-
-/* Implementation of `verify_one'. */
-
-/* Display the common attributes of the signature summary SUM.
-   Return 1 if there is is a severe warning.
- */
-static int show_sig_summary (unsigned long sum,
-                             gpgme_ctx_t ctx, gpgme_key_t key, int idx,
-                             STATE * s)
-{
-  int severe = 0;
-
-  if ((sum & GPGME_SIGSUM_KEY_REVOKED)) {
-    state_attach_puts (_("Warning: One of the keys has been revoked\n"), s);
-    severe = 1;
-  }
-
-  if ((sum & GPGME_SIGSUM_KEY_EXPIRED)) {
-    time_t at = key->subkeys->expires ? key->subkeys->expires : 0;
-
-    if (at) {
-      state_attach_puts (_("Warning: The key used to create the "
-                           "signature expired at: "), s);
-      print_time (at, s);
-      state_attach_puts ("\n", s);
-    }
-    else
-      state_attach_puts (_("Warning: At least one certification key "
-                           "has expired\n"), s);
-  }
-
-  if ((sum & GPGME_SIGSUM_SIG_EXPIRED)) {
-    gpgme_verify_result_t result;
-    gpgme_signature_t sig;
-    int i;
-
-    result = gpgme_op_verify_result (ctx);
-
-    for (sig = result->signatures, i = 0; sig && (i < idx);
-         sig = sig->next, i++);
-
-    state_attach_puts (_("Warning: The signature expired at: "), s);
-    print_time (sig ? sig->exp_timestamp : 0, s);
-    state_attach_puts ("\n", s);
-  }
-
-  if ((sum & GPGME_SIGSUM_KEY_MISSING))
-    state_attach_puts (_("Can't verify due to a missing "
-                         "key or certificate\n"), s);
-
-  if ((sum & GPGME_SIGSUM_CRL_MISSING)) {
-    state_attach_puts (_("The CRL is not available\n"), s);
-    severe = 1;
-  }
-
-  if ((sum & GPGME_SIGSUM_CRL_TOO_OLD)) {
-    state_attach_puts (_("Available CRL is too old\n"), s);
-    severe = 1;
-  }
-
-  if ((sum & GPGME_SIGSUM_BAD_POLICY))
-    state_attach_puts (_("A policy requirement was not met\n"), s);
-
-  if ((sum & GPGME_SIGSUM_SYS_ERROR)) {
-    const char *t0 = NULL, *t1 = NULL;
-    gpgme_verify_result_t result;
-    gpgme_signature_t sig;
-    int i;
-
-    state_attach_puts (_("A system error occurred"), s);
-
-    /* Try to figure out some more detailed system error information. */
-    result = gpgme_op_verify_result (ctx);
-    for (sig = result->signatures, i = 0; sig && (i < idx);
-         sig = sig->next, i++);
-    if (sig) {
-      t0 = "";
-      t1 = sig->wrong_key_usage ? "Wrong_Key_Usage" : "";
-    }
-
-    if (t0 || t1) {
-      state_attach_puts (": ", s);
-      if (t0)
-        state_attach_puts (t0, s);
-      if (t1 && !(t0 && !m_strcmp(t0, t1))) {
-        if (t0)
-          state_attach_puts (",", s);
-        state_attach_puts (t1, s);
-      }
-    }
-    state_attach_puts ("\n", s);
-  }
-
-  return severe;
-}
-
-
-static void show_fingerprint (gpgme_key_t key, STATE * state)
-{
-  const char *s;
-  int i, is_pgp;
-  char *buf, *p;
-  const char *prefix = _("Fingerprint: ");
-  ssize_t bufsize;
-
-  if (!key)
-    return;
-  s = key->subkeys ? key->subkeys->fpr : NULL;
-  if (!s)
-    return;
-  is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
-
-  bufsize = m_strlen(prefix) + m_strlen(s) * 4 + 2;
-  buf = p_new(char, bufsize);
-  m_strcpy(buf, bufsize, prefix);
-  p = buf + m_strlen(buf);
-  if (is_pgp && m_strlen(s) == 40) {     /* PGP v4 style formatted. */
-    for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
-      *p++ = s[0];
-      *p++ = s[1];
-      *p++ = s[2];
-      *p++ = s[3];
-      *p++ = ' ';
-      if (i == 4)
-        *p++ = ' ';
-    }
-  }
-  else {
-    for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
-      *p++ = s[0];
-      *p++ = s[1];
-      *p++ = is_pgp ? ' ' : ':';
-      if (is_pgp && i == 7)
-        *p++ = ' ';
-    }
-  }
-
-  /* just in case print remaining odd digits */
-  for (; *s; s++)
-    *p++ = *s;
-  *p++ = '\n';
-  *p = 0;
-  state_attach_puts (buf, state);
-  p_delete(&buf);
-}
-
-/* Show the valididy of a key used for one signature. */
-static void show_one_sig_validity (gpgme_ctx_t ctx, int idx, STATE * s)
-{
-  gpgme_verify_result_t result = NULL;
-  gpgme_signature_t sig = NULL;
-  const char *txt = NULL;
-
-  result = gpgme_op_verify_result (ctx);
-  if (result)
-    for (sig = result->signatures; sig && (idx > 0); sig = sig->next, idx--);
-
-  switch (sig ? sig->validity : 0) {
-  case GPGME_VALIDITY_UNKNOWN:
-    txt = _("WARNING: We have NO indication whether "
-            "the key belongs to the person named " "as shown above\n");
-    break;
-  case GPGME_VALIDITY_UNDEFINED:
-    break;
-  case GPGME_VALIDITY_NEVER:
-    txt = _("WARNING: The key does NOT BELONG to "
-            "the person named as shown above\n");
-    break;
-  case GPGME_VALIDITY_MARGINAL:
-    txt = _("WARNING: It is NOT certain that the key "
-            "belongs to the person named as shown above\n");
-    break;
-  case GPGME_VALIDITY_FULL:
-  case GPGME_VALIDITY_ULTIMATE:
-    txt = NULL;
-    break;
-  }
-  if (txt)
-    state_attach_puts (txt, s);
-}
-
-/* Show information about one signature.  This fucntion is called with
-   the context CTX of a sucessful verification operation and the
-   enumerator IDX which should start at 0 and incremete for each
-   call/signature.
-
-   Return values are: 0 for normal procession, 1 for a bad signature,
-   2 for a signature with a warning or -1 for no more signature.  */
-static int show_one_sig_status (gpgme_ctx_t ctx, int idx, STATE * s)
-{
-  time_t created;
-  const char *fpr, *uid;
-  gpgme_key_t key = NULL;
-  int i, anybad = 0, anywarn = 0;
-  unsigned int sum;
-  gpgme_user_id_t uids = NULL;
-  gpgme_verify_result_t result;
-  gpgme_signature_t sig;
-  gpgme_error_t err = GPG_ERR_NO_ERROR;
-
-  result = gpgme_op_verify_result (ctx);
-  if (result) {
-    /* FIXME: this code should use a static variable and remember
-       the current position in the list of signatures, IMHO.
-       -moritz.  */
-
-    for (i = 0, sig = result->signatures; sig && (i < idx);
-         i++, sig = sig->next);
-    if (!sig)
-      return -1;                /* Signature not found.  */
-
-    if (signature_key) {
-      gpgme_key_release (signature_key);
-      signature_key = NULL;
-    }
-
-    created = sig->timestamp;
-    fpr = sig->fpr;
-    sum = sig->summary;
-
-    if (gpg_err_code (sig->status) != GPG_ERR_NO_ERROR)
-      anybad = 1;
-
-    err = gpgme_get_key2 (ctx, fpr, &key, 0);    /* secret key?  */
-    if (!err) {
-      uid = (key->uids && key->uids->uid) ? key->uids->uid : "[?]";
-      if (!signature_key)
-        signature_key = key;
-    }
-    else {
-      key = NULL;               /* Old gpgme versions did not set KEY to NULL on
-                                   error.   Do it here to avoid a double free. */
-      uid = "[?]";
-    }
-
-    if (!s || !s->fpout || !(s->flags & M_DISPLAY));    /* No state information so no way to print anything. */
-    else if (err) {
-      state_attach_puts (_("Error getting key information: "), s);
-      state_attach_puts (gpg_strerror (err), s);
-      state_attach_puts ("\n", s);
-      anybad = 1;
-    }
-    else if ((sum & GPGME_SIGSUM_GREEN)) {
-      state_attach_puts (_("Good signature from: "), s);
-      state_attach_puts (uid, s);
-      state_attach_puts ("\n", s);
-      for (i = 1, uids = key->uids; uids; i++, uids = uids->next) {
-        if (i == 1)
-          /* Skip primary UID.  */
-          continue;
-        if (uids->revoked)
-          continue;
-        state_attach_puts (_("                aka: "), s);
-        state_attach_puts (uids->uid, s);
-        state_attach_puts ("\n", s);
-      }
-      state_attach_puts (_("            created: "), s);
-      print_time (created, s);
-      state_attach_puts ("\n", s);
-      if (show_sig_summary (sum, ctx, key, idx, s))
-        anywarn = 1;
-      show_one_sig_validity (ctx, idx, s);
-    }
-    else if ((sum & GPGME_SIGSUM_RED)) {
-      state_attach_puts (_("*BAD* signature claimed to be from: "), s);
-      state_attach_puts (uid, s);
-      state_attach_puts ("\n", s);
-      show_sig_summary (sum, ctx, key, idx, s);
-    }
-    else if (!anybad && key && (key->protocol == GPGME_PROTOCOL_OpenPGP)) {     /* We can't decide (yellow) but this is a PGP key with a good
-                                                                                   signature, so we display what a PGP user expects: The name,
-                                                                                   fingerprint and the key validity (which is neither fully or
-                                                                                   ultimate). */
-      state_attach_puts (_("Good signature from: "), s);
-      state_attach_puts (uid, s);
-      state_attach_puts ("\n", s);
-      state_attach_puts (_("            created: "), s);
-      print_time (created, s);
-      state_attach_puts ("\n", s);
-      show_one_sig_validity (ctx, idx, s);
-      show_fingerprint (key, s);
-      if (show_sig_summary (sum, ctx, key, idx, s))
-        anywarn = 1;
-    }
-    else {                      /* can't decide (yellow) */
-
-      state_attach_puts (_("Error checking signature"), s);
-      state_attach_puts ("\n", s);
-      show_sig_summary (sum, ctx, key, idx, s);
-    }
-
-    if (key != signature_key)
-      gpgme_key_release (key);
-  }
-
-  return anybad ? 1 : anywarn ? 2 : 0;
-}
-
-/* Do the actual verification step. With IS_SMIME set to true we
-   assume S/MIME (surprise!) */
-int crypt_verify_one(BODY *sigbdy, STATE *s, FILE *fp, int is_smime)
-{
-  int badsig = -1;
-  int anywarn = 0;
-  int err;
-  gpgme_ctx_t ctx;
-  gpgme_data_t signature, message;
-
-  signature = file_to_data_object (s->fpin, sigbdy->offset, sigbdy->length);
-  if (!signature)
-    return -1;
-
-  /* We need to tell gpgme about the encoding because the backend can't
-     auto-detect plain base-64 encoding which is used by S/MIME. */
-  if (is_smime)
-    gpgme_data_set_encoding (signature, GPGME_DATA_ENCODING_BASE64);
-
-  err = gpgme_data_new_from_stream(&message, fp);
-  if (err) {
-    gpgme_data_release (signature);
-    mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
-    return -1;
-  }
-  ctx = create_gpgme_context (is_smime);
-
-  /* Note: We don't need a current time output because GPGME avoids
-     such an attack by separating the meta information from the
-     data. */
-  state_attach_puts (_("[-- Begin signature information --]\n"), s);
-
-  err = gpgme_op_verify (ctx, signature, message, NULL);
-  mutt_need_hard_redraw ();
-  if (err) {
-    char buf[200];
-
-    snprintf (buf, sizeof (buf) - 1,
-              _("Error: verification failed: %s\n"), gpgme_strerror (err));
-    state_attach_puts (buf, s);
-  }
-  else {                        /* Verification succeeded, see what the result is. */
-    int res, idx;
-    int anybad = 0;
-
-    if (signature_key) {
-      gpgme_key_release (signature_key);
-      signature_key = NULL;
-    }
-
-    for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
-      if (res == 1)
-        anybad = 1;
-      else if (res == 2)
-        anywarn = 2;
-    }
-    if (!anybad)
-      badsig = 0;
-  }
-
-  if (!badsig) {
-    gpgme_verify_result_t result;
-    gpgme_sig_notation_t notation;
-    gpgme_signature_t sig;
-
-    result = gpgme_op_verify_result (ctx);
-    if (result) {
-      for (sig = result->signatures; sig; sig = sig->next) {
-        if (sig->notations) {
-          state_attach_puts ("*** Begin Notation (signature by: ", s);
-          state_attach_puts (sig->fpr, s);
-          state_attach_puts (") ***\n", s);
-          for (notation = sig->notations; notation; notation = notation->next)
-          {
-            if (notation->name) {
-              state_attach_puts (notation->name, s);
-              state_attach_puts ("=", s);
-            }
-            if (notation->value) {
-              state_attach_puts (notation->value, s);
-              if (!(*notation->value
-                    && (notation->value[m_strlen(notation->value) - 1] ==
-                        '\n')))
-                state_attach_puts ("\n", s);
-            }
-          }
-          state_attach_puts ("*** End Notation ***\n", s);
-        }
-      }
-    }
-  }
-
-  gpgme_release (ctx);
-
-  state_attach_puts (_("[-- End signature information --]\n\n"), s);
-
-  return badsig ? 1 : anywarn ? 2 : 0;
-}
-
-/*
- * Implementation of `decrypt_part'.
- */
-
-/* Decrypt a PGP or SMIME message (depending on the boolean flag
-   IS_SMIME) with body A described further by state S.  Write
-   plaintext out to file FPOUT and return a new body.  For PGP returns
-   a flag in R_IS_SIGNED to indicate whether this is a combined
-   encrypted and signed message, for S/MIME it returns true when it is
-   not a encrypted but a signed message.  */
-static BODY *decrypt_part (BODY * a, STATE * s, FILE * fpout, int is_smime,
-                           int *r_is_signed)
-{
-  struct stat info;
-  BODY *tattach;
-  int err = 0;
-  gpgme_ctx_t ctx;
-  gpgme_data_t ciphertext, plaintext;
-  int maybe_signed = 0;
-  int anywarn = 0;
-  int sig_stat = 0;
-
-  if (r_is_signed)
-    *r_is_signed = 0;
-
-  ctx = create_gpgme_context (is_smime);
-
-restart:
-  /* Make a data object from the body, create context etc. */
-  ciphertext = file_to_data_object (s->fpin, a->offset, a->length);
-  if (!ciphertext)
-    return NULL;
-  plaintext = create_gpgme_data ();
-
-  /* Do the decryption or the verification in case of the S/MIME hack. */
-  if ((!is_smime) || maybe_signed) {
-    if (!is_smime)
-      err = gpgme_op_decrypt_verify (ctx, ciphertext, plaintext);
-    else if (maybe_signed)
-      err = gpgme_op_verify (ctx, ciphertext, NULL, plaintext);
-
-    {
-      /* Check wether signatures have been verified.  */
-      gpgme_verify_result_t verify_result = gpgme_op_verify_result (ctx);
-
-      if (verify_result->signatures)
-        sig_stat = 1;
-    }
-  }
-  else
-    err = gpgme_op_decrypt (ctx, ciphertext, plaintext);
-  gpgme_data_release (ciphertext);
-  if (err) {
-    if (is_smime && !maybe_signed && gpg_err_code (err) == GPG_ERR_NO_DATA) {
-      /* Check whether this might be a signed message despite what
-         the mime header told us.  Retry then.  gpgsm returns the
-         error information "unsupported Algorithm '?'" but gpgme
-         will not store this unknown algorithm, thus we test that
-         it has not been set. */
-      gpgme_decrypt_result_t result;
-
-      result = gpgme_op_decrypt_result (ctx);
-      if (!result->unsupported_algorithm) {
-        maybe_signed = 1;
-        gpgme_data_release (plaintext);
-        goto restart;
-      }
-    }
-    mutt_need_hard_redraw ();
-    if ((s->flags & M_DISPLAY)) {
-      char buf[200];
-
-      snprintf (buf, sizeof (buf) - 1,
-                _("[-- Error: decryption failed: %s --]\n\n"),
-                gpgme_strerror (err));
-      state_attach_puts (buf, s);
-    }
-    gpgme_data_release (plaintext);
-    gpgme_release (ctx);
-    return NULL;
-  }
-  mutt_need_hard_redraw ();
-
-  /* Read the output from GPGME, and make sure to change CRLF to LF,
-     otherwise read_mime_header has a hard time parsing the message.  */
-  if (data_object_to_stream (plaintext, fpout)) {
-    gpgme_data_release (plaintext);
-    gpgme_release (ctx);
-    return NULL;
-  }
-  gpgme_data_release (plaintext);
-
-  a->is_signed_data = 0;
-  if (sig_stat) {
-    int res, idx;
-    int anybad = 0;
-
-    if (maybe_signed)
-      a->is_signed_data = 1;
-    if (r_is_signed)
-      *r_is_signed = -1;        /* A signature exists. */
-
-    if ((s->flags & M_DISPLAY))
-      state_attach_puts (_("[-- Begin signature " "information --]\n"), s);
-    for (idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
-      if (res == 1)
-        anybad = 1;
-      else if (res == 2)
-        anywarn = 1;
-    }
-    if (!anybad && idx && r_is_signed && *r_is_signed)
-      *r_is_signed = anywarn ? 2 : 1;   /* Good signature. */
-
-    if ((s->flags & M_DISPLAY))
-      state_attach_puts (_("[-- End signature " "information --]\n\n"), s);
-  }
-  gpgme_release (ctx);
-  ctx = NULL;
-
-  fflush (fpout);
-  rewind (fpout);
-  tattach = mutt_read_mime_header (fpout, 0);
-  if (tattach) {
-    /*
-     * Need to set the length of this body part.
-     */
-    fstat (fileno (fpout), &info);
-    tattach->length = info.st_size - tattach->offset;
-
-    tattach->warnsig = anywarn;
-
-    /* See if we need to recurse on this MIME part.  */
-    mutt_parse_part (fpout, tattach);
-  }
-
-  return tattach;
-}
-
-/* Decrypt a PGP/MIME message in FPIN and B and return a new body and
-   the stream in CUR and FPOUT.  Returns 0 on success. */
-int crypt_pgp_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
-{
-  char tempfile[_POSIX_PATH_MAX];
-  STATE s;
-  BODY *first_part = b;
-  int is_signed;
-
-  first_part->goodsig = 0;
-  first_part->warnsig = 0;
-
-  if (!mutt_is_multipart_encrypted (b))
-    return -1;
-
-  if (!b->parts || !b->parts->next)
-    return -1;
-
-  b = b->parts->next;
-
-  p_clear(&s, 1);
-  s.fpin = fpin;
-  *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
-  if (!*fpout) {
-    mutt_perror (_("Can't create temporary file"));
-    return -1;
-  }
-  unlink (tempfile);
-
-  *cur = decrypt_part (b, &s, *fpout, 0, &is_signed);
-  rewind (*fpout);
-  if (is_signed > 0)
-    first_part->goodsig = 1;
-
-  return *cur ? 0 : -1;
-}
-
-
-/* Decrypt a S/MIME message in FPIN and B and return a new body and
-   the stream in CUR and FPOUT.  Returns 0 on success. */
-int crypt_smime_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b,
-                              BODY ** cur)
-{
-  char tempfile[_POSIX_PATH_MAX];
-  STATE s;
-  FILE *tmpfp = NULL;
-  int is_signed;
-  long saved_b_offset;
-  ssize_t saved_b_length;
-  int saved_b_type;
-
-  if (!mutt_is_application_smime (b))
-    return -1;
-
-  if (b->parts)
-    return -1;
-
-  /* Decode the body - we need to pass binary CMS to the
-     backend.  The backend allows for Base64 encoded data but it does
-     not allow for QP which I have seen in some messages.  So better
-     do it here. */
-  saved_b_type = b->type;
-  saved_b_offset = b->offset;
-  saved_b_length = b->length;
-  p_clear(&s, 1);
-  s.fpin = fpin;
-  fseeko (s.fpin, b->offset, 0);
-  tmpfp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
-  if (!tmpfp) {
-    mutt_perror (_("Can't create temporary file"));
-    return -1;
-  }
-  mutt_unlink (tempfile);
-
-  s.fpout = tmpfp;
-  mutt_decode_attachment (b, &s);
-  fflush (tmpfp);
-  b->length = ftello (s.fpout);
-  b->offset = 0;
-  rewind (tmpfp);
-
-  p_clear(&s, 1);
-  s.fpin = tmpfp;
-  s.fpout = 0;
-  *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
-  if (!*fpout) {
-    mutt_perror (_("Can't create temporary file"));
-    return -1;
-  }
-  mutt_unlink (tempfile);
-
-  *cur = decrypt_part (b, &s, *fpout, 1, &is_signed);
-  if (*cur)
-    (*cur)->goodsig = is_signed > 0;
-  b->type = saved_b_type;
-  b->length = saved_b_length;
-  b->offset = saved_b_offset;
-  m_fclose(&tmpfp);
-  rewind (*fpout);
-  if (*cur && !is_signed && !(*cur)->parts
-      && mutt_is_application_smime (*cur)) {
-    /* Assume that this is a opaque signed s/mime message.  This is
-       an ugly way of doing it but we have anyway a problem with
-       arbitrary encoded S/MIME messages: Only the outer part may be
-       encrypted.  The entire mime parsing should be revamped,
-       probably by keeping the temportary files so that we don't
-       need to decrypt them all the time.  Inner parts of an
-       encrypted part can then pint into this file and tehre won't
-       never be a need to decrypt again.  This needs a partial
-       rewrite of the MIME engine. */
-    BODY *bb = *cur;
-    BODY *tmp_b;
-
-    saved_b_type = bb->type;
-    saved_b_offset = bb->offset;
-    saved_b_length = bb->length;
-    p_clear(&s, 1);
-    s.fpin = *fpout;
-    fseeko (s.fpin, bb->offset, 0);
-    tmpfp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
-    if (!tmpfp) {
-      mutt_perror (_("Can't create temporary file"));
-      return -1;
-    }
-    mutt_unlink (tempfile);
-
-    s.fpout = tmpfp;
-    mutt_decode_attachment (bb, &s);
-    fflush (tmpfp);
-    bb->length = ftello (s.fpout);
-    bb->offset = 0;
-    rewind (tmpfp);
-    m_fclose(&*fpout);
-
-    p_clear(&s, 1);
-    s.fpin = tmpfp;
-    s.fpout = 0;
-    *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
-    if (!*fpout) {
-      mutt_perror (_("Can't create temporary file"));
-      return -1;
-    }
-    mutt_unlink (tempfile);
-
-    tmp_b = decrypt_part (bb, &s, *fpout, 1, &is_signed);
-    if (tmp_b)
-      tmp_b->goodsig = is_signed > 0;
-    bb->type = saved_b_type;
-    bb->length = saved_b_length;
-    bb->offset = saved_b_offset;
-    m_fclose(&tmpfp);
-    rewind (*fpout);
-    body_list_wipe(cur);
-    *cur = tmp_b;
-  }
-  return *cur ? 0 : -1;
-}
-
-
-/*
- * Implementation of `pgp_check_traditional'.
- */
-
-static int pgp_check_traditional_one_body (FILE * fp, BODY * b,
-                                           int tagged_only)
-{
-  char tempfile[_POSIX_PATH_MAX];
-  char buf[HUGE_STRING];
-  FILE *tfp;
-  int tempfd;
-
-  short sgn = 0;
-  short enc = 0;
-
-  if (b->type != TYPETEXT)
-    return 0;
-
-  if (tagged_only && !b->tagged)
-    return 0;
-
-  tempfd = m_tempfd(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
-  if (mutt_decode_save_attachment (fp, b, tempfd, 0) != 0) {
-    unlink (tempfile);
-    return 0;
-  }
-
-  if ((tfp = fopen(tempfile, "r")) == NULL) {
-    unlink (tempfile);
-    return 0;
-  }
-
-  while (fgets (buf, sizeof (buf), tfp)) {
-    if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
-      if (!m_strcmp("MESSAGE-----\n", buf + 15))
-        enc = 1;
-      else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15))
-        sgn = 1;
-    }
-  }
-  m_fclose(&tfp);
-  unlink (tempfile);
-
-  if (!enc && !sgn)
-    return 0;
-
-  /* fix the content type */
-
-  parameter_setval(&b->parameter, "format", "fixed");
-  parameter_setval(&b->parameter, "x-action",
-                   enc ? "pgp-encrypted" : "pgp-signed");
-  return 1;
-}
-
-int crypt_pgp_check_traditional (FILE * fp, BODY * b, int tagged_only)
-{
-  int rv = 0;
-  int r;
-
-  for (; b; b = b->next) {
-    if (is_multipart (b))
-      rv = (crypt_pgp_check_traditional (fp, b->parts, tagged_only) || rv);
-    else if (b->type == TYPETEXT) {
-      if ((r = mutt_is_application_pgp (b)))
-        rv = (rv || r);
-      else
-        rv = (pgp_check_traditional_one_body (fp, b, tagged_only) || rv);
-    }
-  }
-  return rv;
-}
-
-
-/* Implementation of `application_handler'. */
-
-/*
-  Copy a clearsigned message, and strip the signature and PGP's
-  dash-escaping.
-
-  XXX - charset handling: We assume that it is safe to do
-  character set decoding first, dash decoding second here, while
-  we do it the other way around in the main handler.
-
-  (Note that we aren't worse than Outlook & Cie in this, and also
-  note that we can successfully handle anything produced by any
-  existing versions of mutt.)  */
-
-static void copy_clearsigned (gpgme_data_t data, STATE * s, char *charset)
-{
-  char buf[HUGE_STRING];
-  short complete, armor_header;
-  fgetconv_t *fc;
-  char *fname;
-  FILE *fp;
-
-  fname = data_object_to_tempfile (data, &fp);
-  if (!fname)
-    return;
-  unlink (fname);
-  p_delete(&fname);
-
-  fc = fgetconv_open (fp, charset, MCharset.charset, M_ICONV_HOOK_FROM);
-
-  for (complete = 1, armor_header = 1;
-       fgetconvs (buf, sizeof (buf), fc) != NULL;
-       complete = strchr (buf, '\n') != NULL) {
-    if (!complete) {
-      if (!armor_header)
-        state_puts (buf, s);
-      continue;
-    }
-
-    if (!m_strcmp(buf, "-----BEGIN PGP SIGNATURE-----\n"))
-      break;
-
-    if (armor_header) {
-      if (buf[0] == '\n')
-        armor_header = 0;
-      continue;
-    }
-
-    if (s->prefix)
-      state_puts (s->prefix, s);
-
-    if (buf[0] == '-' && buf[1] == ' ')
-      state_puts (buf + 2, s);
-    else
-      state_puts (buf, s);
-  }
-
-  fgetconv_close (&fc);
-  m_fclose(&fp);
-}
-
-
-/* Support for classic_application/pgp */
-int crypt_pgp_application_pgp_handler (BODY * m, STATE * s)
-{
-  int needpass = -1, pgp_keyblock = 0;
-  int clearsign = 0;
-  long start_pos = 0;
-  long bytes;
-  off_t last_pos, offset;
-  char buf[HUGE_STRING];
-  FILE *pgpout = NULL;
-
-  gpgme_error_t err = 0;
-  gpgme_data_t armored_data = NULL;
-
-  short maybe_goodsig = 1;
-  short have_any_sigs = 0;
-
-  char body_charset[STRING];    /* Only used for clearsigned messages. */
-
-  /* For clearsigned messages we won't be able to get a character set
-     but we know that this may only be text thus we assume Latin-1
-     here. */
-  if (!mutt_get_body_charset (body_charset, sizeof (body_charset), m))
-    m_strcpy(body_charset, sizeof(body_charset), "iso-8859-1");
-
-  fseeko (s->fpin, m->offset, 0);
-  last_pos = m->offset;
-
-  for (bytes = m->length; bytes > 0;) {
-    if (fgets (buf, sizeof (buf), s->fpin) == NULL)
-      break;
-
-    offset = ftello (s->fpin);
-    bytes -= (offset - last_pos);       /* don't rely on m_strlen(buf) */
-    last_pos = offset;
-
-    if (!m_strncmp("-----BEGIN PGP ", buf, 15)) {
-      clearsign = 0;
-      start_pos = last_pos;
-
-      if (!m_strcmp("MESSAGE-----\n", buf + 15))
-        needpass = 1;
-      else if (!m_strcmp("SIGNED MESSAGE-----\n", buf + 15)) {
-        clearsign = 1;
-        needpass = 0;
-      }
-      else if (!option (OPTDONTHANDLEPGPKEYS) &&
-               !m_strcmp("PUBLIC KEY BLOCK-----\n", buf + 15)) {
-        needpass = 0;
-        pgp_keyblock = 1;
-      }
-      else {
-        /* XXX - we may wish to recode here */
-        if (s->prefix)
-          state_puts (s->prefix, s);
-        state_puts (buf, s);
-        continue;
-      }
-
-      have_any_sigs = (have_any_sigs || (clearsign && (s->flags & M_VERIFY)));
-
-      /* Copy PGP material to an data container */
-      armored_data = create_gpgme_data ();
-      gpgme_data_write (armored_data, buf, m_strlen(buf));
-      while (bytes > 0 && fgets (buf, sizeof (buf) - 1, s->fpin) != NULL) {
-        offset = ftello (s->fpin);
-        bytes -= (offset - last_pos);   /* don't rely on m_strlen(buf) */
-        last_pos = offset;
-
-        gpgme_data_write (armored_data, buf, m_strlen(buf));
-
-        if ((needpass && !m_strcmp("-----END PGP MESSAGE-----\n", buf))
-            || (!needpass
-                && (!m_strcmp("-----END PGP SIGNATURE-----\n", buf)
-                    || !m_strcmp("-----END PGP PUBLIC KEY BLOCK-----\n",
-                                     buf))))
-          break;
-      }
-
-      /* Invoke PGP if needed */
-      if (!clearsign || (s->flags & M_VERIFY)) {
-        unsigned int sig_stat = 0;
-        gpgme_data_t plaintext;
-        gpgme_ctx_t ctx;
-
-        plaintext = create_gpgme_data ();
-        ctx = create_gpgme_context (0);
-
-        if (clearsign)
-          err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
-        else {
-          err = gpgme_op_decrypt_verify (ctx, armored_data, plaintext);
-          if (gpg_err_code (err) == GPG_ERR_NO_DATA) {
-            /* Decrypt verify can't handle signed only messages. */
-            err = (gpgme_data_seek (armored_data, 0, SEEK_SET) == -1)
-              ? gpgme_error_from_errno (errno) : 0;
-            /* Must release plaintext so that we supply an
-               uninitialized object. */
-            gpgme_data_release (plaintext);
-            plaintext = create_gpgme_data ();
-            err = gpgme_op_verify (ctx, armored_data, NULL, plaintext);
-          }
-        }
-
-        if (err) {
-          char errbuf[200];
-
-          snprintf (errbuf, sizeof (errbuf) - 1,
-                    _("Error: decryption/verification failed: %s\n"),
-                    gpgme_strerror (err));
-          state_attach_puts (errbuf, s);
-        }
-        else {                  /* Decryption/Verification succeeded */
-          char *tmpfname;
-
-          {
-            /* Check wether signatures have been verified.  */
-            gpgme_verify_result_t verify_result;
-
-            verify_result = gpgme_op_verify_result (ctx);
-            if (verify_result->signatures)
-              sig_stat = 1;
-          }
-
-          have_any_sigs = 0;
-          maybe_goodsig = 0;
-          if ((s->flags & M_DISPLAY) && sig_stat) {
-            int res, idx;
-            int anybad = 0;
-            int anywarn = 0;
-
-            state_attach_puts (_("[-- Begin signature "
-                                 "information --]\n"), s);
-            have_any_sigs = 1;
-            for (idx = 0;
-                 (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) {
-              if (res == 1)
-                anybad = 1;
-              else if (res == 2)
-                anywarn = 1;
-            }
-            if (!anybad && idx)
-              maybe_goodsig = 1;
-
-            state_attach_puts (_("[-- End signature "
-                                 "information --]\n\n"), s);
-          }
-
-          tmpfname = data_object_to_tempfile (plaintext, &pgpout);
-          if (!tmpfname) {
-            pgpout = NULL;
-            state_attach_puts (_("Error: copy data failed\n"), s);
-          }
-          else {
-            unlink (tmpfname);
-            p_delete(&tmpfname);
-          }
-        }
-        gpgme_release (ctx);
-      }
-
-      /*
-       * Now, copy cleartext to the screen.  NOTE - we expect that PGP
-       * outputs utf-8 cleartext.  This may not always be true, but it
-       * seems to be a reasonable guess.
-       */
-
-      if (s->flags & M_DISPLAY) {
-        if (needpass)
-          state_attach_puts (_("[-- BEGIN PGP MESSAGE --]\n\n"), s);
-        else if (pgp_keyblock)
-          state_attach_puts (_("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"), s);
-        else
-          state_attach_puts (_("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"), s);
-      }
-
-      if (clearsign) {
-        copy_clearsigned (armored_data, s, body_charset);
-      }
-      else if (pgpout) {
-        fgetconv_t *fc;
-        int c;
-
-        rewind (pgpout);
-        fc = fgetconv_open (pgpout, "utf-8", MCharset.charset, 0);
-        while ((c = fgetconv (fc)) != EOF) {
-          state_putc (c, s);
-          if (c == '\n' && s->prefix)
-            state_puts (s->prefix, s);
-        }
-        fgetconv_close (&fc);
-      }
-
-      if (s->flags & M_DISPLAY) {
-        state_putc ('\n', s);
-        if (needpass)
-          state_attach_puts (_("[-- END PGP MESSAGE --]\n"), s);
-        else if (pgp_keyblock)
-          state_attach_puts (_("[-- END PGP PUBLIC KEY BLOCK --]\n"), s);
-        else
-          state_attach_puts (_("[-- END PGP SIGNED MESSAGE --]\n"), s);
-      }
-
-      if (pgpout) {
-        m_fclose(&pgpout);
-      }
-    }
-    else {
-      /* XXX - we may wish to recode here */
-      if (s->prefix)
-        state_puts (s->prefix, s);
-      state_puts (buf, s);
-    }
-  }
-
-  m->goodsig = (maybe_goodsig && have_any_sigs);
-
-  if (needpass == -1) {
-    state_attach_puts (_("[-- Error: could not find beginning"
-                         " of PGP message! --]\n\n"), s);
-    return (-1);
-  }
-  return (err);
-}
-
-/* Implementation of `encrypted_handler'. */
-
-/* MIME handler for pgp/mime encrypted messages. */
-int crypt_pgp_encrypted_handler (BODY * a, STATE * s)
-{
-  char tempfile[_POSIX_PATH_MAX];
-  FILE *fpout;
-  BODY *tattach;
-  BODY *orig_body = a;
-  int is_signed;
-  int rc = 0;
-
-  a = a->parts;
-  if (!a || a->type != TYPEAPPLICATION || !a->subtype
-      || ascii_strcasecmp ("pgp-encrypted", a->subtype)
-      || !a->next || a->next->type != TYPEAPPLICATION || !a->next->subtype
-      || ascii_strcasecmp ("octet-stream", a->next->subtype)) {
-    if (s->flags & M_DISPLAY)
-      state_attach_puts (_("[-- Error: malformed PGP/MIME message! --]\n\n"),
-                         s);
-    return (-1);
-  }
-
-  /* Move forward to the application/pgp-encrypted body. */
-  a = a->next;
-
-  fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
-  if (!fpout) {
-    if (s->flags & M_DISPLAY)
-      state_attach_puts (_("[-- Error: could not create temporary file! "
-                           "--]\n"), s);
-    return (-1);
-  }
-
-  tattach = decrypt_part (a, s, fpout, 0, &is_signed);
-  if (tattach) {
-    tattach->goodsig = is_signed > 0;
-
-    if (s->flags & M_DISPLAY)
-      state_attach_puts (is_signed ?
-                         _
-                         ("[-- The following data is PGP/MIME signed and encrypted --]\n\n") :
-                         _("[-- The following data is PGP/MIME encrypted --]\n\n"), s);
-
-    {
-      FILE *savefp = s->fpin;
-
-      s->fpin = fpout;
-      rc = mutt_body_handler (tattach, s);
-      s->fpin = savefp;
-    }
-
-    /*
-     * if a multipart/signed is the _only_ sub-part of a
-     * multipart/encrypted, cache signature verification
-     * status.
-     */
-    if (mutt_is_multipart_signed (tattach) && !tattach->next)
-      orig_body->goodsig |= tattach->goodsig;
-
-    if (s->flags & M_DISPLAY) {
-      state_puts ("\n", s);
-      state_attach_puts (is_signed ?
-                         _
-                         ("[-- End of PGP/MIME signed and encrypted data --]\n")
-                         : _("[-- End of PGP/MIME encrypted data --]\n"), s);
-    }
-
-    body_list_wipe(&tattach);
-  }
-
-  m_fclose(&fpout);
-  mutt_unlink (tempfile);
-  return (rc);
-}
-
-/* Support for application/smime */
-int crypt_smime_application_smime_handler (BODY * a, STATE * s)
-{
-  char tempfile[_POSIX_PATH_MAX];
-  FILE *fpout;
-  BODY *tattach;
-  int is_signed;
-  int rc = 0;
-
-  a->warnsig = 0;
-  fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
-  if (!fpout) {
-    if (s->flags & M_DISPLAY)
-      state_attach_puts (_("[-- Error: could not create temporary file! "
-                           "--]\n"), s);
-    return (-1);
-  }
-
-  tattach = decrypt_part (a, s, fpout, 1, &is_signed);
-  if (tattach) {
-    tattach->goodsig = is_signed > 0;
-
-    if (s->flags & M_DISPLAY)
-      state_attach_puts (is_signed ?
-                         _("[-- The following data is S/MIME signed --]\n\n") :
-                         _("[-- The following data is S/MIME encrypted --]\n\n"), s);
-
-    {
-      FILE *savefp = s->fpin;
-
-      s->fpin = fpout;
-      rc = mutt_body_handler (tattach, s);
-      s->fpin = savefp;
-    }
-
-    /*
-     * if a multipart/signed is the _only_ sub-part of a
-     * multipart/encrypted, cache signature verification
-     * status.
-     */
-    if (mutt_is_multipart_signed (tattach) && !tattach->next) {
-      if (!(a->goodsig = tattach->goodsig))
-        a->warnsig = tattach->warnsig;
-    }
-    else if (tattach->goodsig) {
-      a->goodsig = 1;
-      a->warnsig = tattach->warnsig;
-    }
-
-    if (s->flags & M_DISPLAY) {
-      state_puts ("\n", s);
-      state_attach_puts (is_signed ?
-                         _("[-- End of S/MIME signed data --]\n") :
-                         _("[-- End of S/MIME encrypted data --]\n"), s);
-    }
-
-    body_list_wipe(&tattach);
-  }
-
-  m_fclose(&fpout);
-  mutt_unlink (tempfile);
-  return (rc);
-}
-
-
-/*
- * Format an entry on the CRYPT key selection menu.
- *
- * %n  number
- * %k  key id          %K      key id of the principal key
- * %u  user id
- * %a  algorithm       %A      algorithm of the princ. key
- * %l  length          %L      length of the princ. key
- * %f  flags           %F      flags of the princ. key
- * %c  capabilities    %C      capabilities of the princ. key
- * %t  trust/validity of the key-uid association
- * %p           protocol
- * %[...] date of key using strftime(3)
- */
-
-static const char *
-crypt_entry_fmt (char *dest, ssize_t destlen, char op,
-                 const char *src, const char *prefix,
-                 const char *ifstr, const char *elstr,
-                 anytype data, format_flag flags)
-{
-  char fmt[16];
-  crypt_entry_t *entry;
-  crypt_key_t *key;
-  int kflags = 0;
-  int optional = (flags & M_FORMAT_OPTIONAL);
-  const char *s = NULL;
-  unsigned long val;
-
-  entry = data.ptr;
-  key = entry->key;
-
-/*    if (isupper ((unsigned char) op)) */
-/*      key = pkey; */
-
-  kflags = (key->flags          /*| (pkey->flags & KEYFLAG_RESTRICTIONS)
-                                   | uid->flags */ );
-
-  switch (ascii_tolower (op)) {
-  case '[':
-    {
-      const char *cp;
-      char buf2[STRING], *p;
-      int do_locales;
-      struct tm *tm;
-      ssize_t len;
-
-      p = dest;
-
-      cp = src;
-      if (*cp == '!') {
-        do_locales = 0;
-        cp++;
-      }
-      else
-        do_locales = 1;
-
-      len = destlen - 1;
-      while (len > 0 && *cp != ']') {
-        if (*cp == '%') {
-          cp++;
-          if (len >= 2) {
-            *p++ = '%';
-            *p++ = *cp;
-            len -= 2;
-          }
-          else
-            break;              /* not enough space */
-          cp++;
-        }
-        else {
-          *p++ = *cp++;
-          len--;
-        }
-      }
-      *p = 0;
-
-      if (do_locales && Locale)
-        setlocale (LC_TIME, Locale);
-
-      {
-        time_t tt = 0;
-
-        if (key->kobj->subkeys && (key->kobj->subkeys->timestamp > 0))
-          tt = key->kobj->subkeys->timestamp;
-
-        tm = localtime (&tt);
-      }
-      strftime (buf2, sizeof (buf2), dest, tm);
-
-      if (do_locales)
-        setlocale (LC_TIME, "C");
-
-      snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
-      snprintf (dest, destlen, fmt, buf2);
-      if (len > 0)
-        src = cp + 1;
-    }
-    break;
-  case 'n':
-    if (!optional) {
-      snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
-      snprintf (dest, destlen, fmt, entry->num);
-    }
-    break;
-  case 'k':
-    if (!optional) {
-      /* fixme: we need a way to distinguish between main and subkeys.
-         Store the idx in entry? */
-      snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
-      snprintf (dest, destlen, fmt, crypt_keyid (key));
-    }
-    break;
-  case 'u':
-    if (!optional) {
-      snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
-      snprintf (dest, destlen, fmt, key->uid);
-    }
-    break;
-  case 'a':
-    if (!optional) {
-      snprintf (fmt, sizeof (fmt), "%%%s.3s", prefix);
-      if (key->kobj->subkeys)
-        s = gpgme_pubkey_algo_name (key->kobj->subkeys->pubkey_algo);
-      else
-        s = "?";
-      snprintf (dest, destlen, fmt, s);
-    }
-    break;
-  case 'l':
-    if (!optional) {
-      snprintf (fmt, sizeof (fmt), "%%%slu", prefix);
-      if (key->kobj->subkeys)
-        val = key->kobj->subkeys->length;
-      else
-        val = 0;
-      snprintf (dest, destlen, fmt, val);
-    }
-    break;
-  case 'f':
-    if (!optional) {
-      snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
-      snprintf (dest, destlen, fmt, crypt_flags (kflags));
-    }
-    else if (!(kflags & (KEYFLAG_RESTRICTIONS)))
-      optional = 0;
-    break;
-  case 'c':
-    if (!optional) {
-      snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
-      snprintf (dest, destlen, fmt, crypt_key_abilities (kflags));
-    }
-    else if (!(kflags & (KEYFLAG_ABILITIES)))
-      optional = 0;
-    break;
-  case 't':
-    if ((kflags & KEYFLAG_ISX509))
-      s = "x";
-    else {
-      gpgme_user_id_t uid = NULL;
-      int i = 0;
-
-      for (i = 0, uid = key->kobj->uids; uid && (i < key->idx);
-           i++, uid = uid->next);
-      if (uid)
-        switch (uid->validity) {
-        case GPGME_VALIDITY_UNDEFINED:
-          s = "q";
-          break;
-        case GPGME_VALIDITY_NEVER:
-          s = "n";
-          break;
-        case GPGME_VALIDITY_MARGINAL:
-          s = "m";
-          break;
-        case GPGME_VALIDITY_FULL:
-          s = "f";
-          break;
-        case GPGME_VALIDITY_ULTIMATE:
-          s = "u";
-          break;
-        case GPGME_VALIDITY_UNKNOWN:
-        default:
-          s = "?";
-          break;
-        }
-    }
-    snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
-    snprintf (dest, destlen, fmt, s ? *s : 'B');
-    break;
-  case 'p':
-    snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
-    snprintf (dest, destlen, fmt,
-              gpgme_get_protocol_name (key->kobj->protocol));
-    break;
-
-  default:
-    *dest = '\0';
-  }
-
-  if (flags & M_FORMAT_OPTIONAL)
-    m_strformat(dest, destlen, 0, optional ? ifstr: elstr,
-                mutt_attach_fmt, data, 0);
-  return src;
-}
-
-/* Used by the display fucntion to format a line. */
-static void crypt_entry (char *s, ssize_t l, MUTTMENU * menu, int num)
-{
-  crypt_key_t **key_table = (crypt_key_t **) menu->data;
-  crypt_entry_t entry;
-
-  entry.key = key_table[num];
-  entry.num = num + 1;
-
-  m_strformat(s, l, COLS - SW, PgpEntryFormat, crypt_entry_fmt, &entry,
-              option(OPTARROWCURSOR) ? M_FORMAT_ARROWCURSOR : 0);
-}
-
-/* Compare two addresses and the keyid to be used for sorting. */
-static int _crypt_compare_address (const void *a, const void *b)
-{
-  crypt_key_t **s = (crypt_key_t **) a;
-  crypt_key_t **t = (crypt_key_t **) b;
-  int r;
-
-  if ((r = m_strcasecmp((*s)->uid, (*t)->uid)))
-    return r > 0;
-  else
-    return m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t)) > 0;
-}
-
-static int crypt_compare_address (const void *a, const void *b)
-{
-  return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_address (a, b)
-          : _crypt_compare_address (a, b));
-}
-
-
-/* Compare two key IDs and the addresses to be used for sorting. */
-static int _crypt_compare_keyid (const void *a, const void *b)
-{
-  crypt_key_t **s = (crypt_key_t **) a;
-  crypt_key_t **t = (crypt_key_t **) b;
-  int r;
-
-  if ((r = m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t))))
-    return r > 0;
-  else
-    return m_strcasecmp((*s)->uid, (*t)->uid) > 0;
-}
-
-static int crypt_compare_keyid (const void *a, const void *b)
-{
-  return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_keyid (a, b)
-          : _crypt_compare_keyid (a, b));
-}
-
-/* Compare 2 creation dates and the addresses.  For sorting. */
-static int _crypt_compare_date (const void *a, const void *b)
-{
-  crypt_key_t **s = (crypt_key_t **) a;
-  crypt_key_t **t = (crypt_key_t **) b;
-  unsigned long ts = 0, tt = 0;
-
-  if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
-    ts = (*s)->kobj->subkeys->timestamp;
-  if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
-    tt = (*t)->kobj->subkeys->timestamp;
-
-  if (ts > tt)
-    return 1;
-  if (ts < tt)
-    return 0;
-
-  return m_strcasecmp((*s)->uid, (*t)->uid) > 0;
-}
-
-static int crypt_compare_date (const void *a, const void *b)
-{
-  return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_date (a, b)
-          : _crypt_compare_date (a, b));
-}
-
-/* Compare two trust values, the key length, the creation dates. the
-   addresses and the key IDs.  For sorting. */
-static int _crypt_compare_trust (const void *a, const void *b)
-{
-  crypt_key_t **s = (crypt_key_t **) a;
-  crypt_key_t **t = (crypt_key_t **) b;
-  unsigned long ts = 0, tt = 0;
-  int r;
-
-  if ((r = (((*s)->flags & (KEYFLAG_RESTRICTIONS))
-            - ((*t)->flags & (KEYFLAG_RESTRICTIONS)))))
-    return r > 0;
-
-  if ((*s)->kobj->uids)
-    ts = (*s)->kobj->uids->validity;
-  if ((*t)->kobj->uids)
-    tt = (*t)->kobj->uids->validity;
-  if ((r = (tt - ts)))
-    return r < 0;
-
-  if ((*s)->kobj->subkeys)
-    ts = (*s)->kobj->subkeys->length;
-  if ((*t)->kobj->subkeys)
-    tt = (*t)->kobj->subkeys->length;
-  if (ts != tt)
-    return ts > tt;
-
-  if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
-    ts = (*s)->kobj->subkeys->timestamp;
-  if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
-    tt = (*t)->kobj->subkeys->timestamp;
-  if (ts > tt)
-    return 1;
-  if (ts < tt)
-    return 0;
-
-  if ((r = m_strcasecmp((*s)->uid, (*t)->uid)))
-    return r > 0;
-  return (m_strcasecmp(crypt_keyid ((*s)), crypt_keyid ((*t)))) > 0;
-}
-
-static int crypt_compare_trust (const void *a, const void *b)
-{
-  return ((PgpSortKeys & SORT_REVERSE) ? !_crypt_compare_trust (a, b)
-          : _crypt_compare_trust (a, b));
-}
-
-/* Print the X.500 Distinguished Name part KEY from the array of parts
-   DN to FP. */
-static int print_dn_part (FILE * fp, struct dn_array_s *dn, const char *key)
-{
-  int any = 0;
-
-  for (; dn->key; dn++) {
-    if (!m_strcmp(dn->key, key)) {
-      if (any)
-        fputs (" + ", fp);
-      print_utf8 (fp, dn->value, m_strlen(dn->value));
-      any = 1;
-    }
-  }
-  return any;
-}
-
-/* Print all parts of a DN in a standard sequence. */
-static void print_dn_parts (FILE * fp, struct dn_array_s *dn)
-{
-  const char *stdpart[] = {
-    "CN", "OU", "O", "STREET", "L", "ST", "C", NULL
-  };
-  int any = 0, any2 = 0, i;
-
-  for (i = 0; stdpart[i]; i++) {
-    if (any)
-      fputs (", ", fp);
-    any = print_dn_part (fp, dn, stdpart[i]);
-  }
-  /* now print the rest without any specific ordering */
-  for (; dn->key; dn++) {
-    for (i = 0; stdpart[i]; i++) {
-      if (!m_strcmp(dn->key, stdpart[i]))
-        break;
-    }
-    if (!stdpart[i]) {
-      if (any)
-        fputs (", ", fp);
-      if (!any2)
-        fputs ("(", fp);
-      any = print_dn_part (fp, dn, dn->key);
-      any2 = 1;
-    }
-  }
-  if (any2)
-    fputs (")", fp);
-}
-
-
-/* Parse an RDN; this is a helper to parse_dn(). */
-static const unsigned char *parse_dn_part (struct dn_array_s *array,
-                                           const unsigned char *string)
-{
-  const unsigned char *s, *s1;
-  ssize_t n;
-  unsigned char *p;
-
-  /* parse attributeType */
-  for (s = string + 1; *s && *s != '='; s++);
-  if (!*s)
-    return NULL;                /* error */
-  n = s - string;
-  if (!n)
-    return NULL;                /* empty key */
-  array->key = p_dupstr(string, n );
-  p = (unsigned char *) array->key;
-  string = s + 1;
-
-  if (*string == '#') {         /* hexstring */
-    string++;
-    for (s = string; hexval(*s) >= 0; s++)
-      s++;
-    n = s - string;
-    if (!n || (n & 1))
-      return NULL;              /* empty or odd number of digits */
-    n /= 2;
-    p = p_new(unsigned char, n + 1);
-    array->value = (char *) p;
-    for (s1 = string; n; s1 += 2, n--)
-      *p++ = (hexval(*s1) << 8) | hexval(*s1);
-    *p = 0;
-  }
-  else {                        /* regular v3 quoted string */
-    for (n = 0, s = string; *s; s++) {
-      if (*s == '\\') {         /* pair */
-        s++;
-        if (*s == ',' || *s == '=' || *s == '+'
-            || *s == '<' || *s == '>' || *s == '#' || *s == ';'
-            || *s == '\\' || *s == '\"' || *s == ' ')
-          n++;
-        else if (hexval(*s) >= 0 && hexval(*s + 1) >= 0) {
-          s++;
-          n++;
-        }
-        else
-          return NULL;          /* invalid escape sequence */
-      }
-      else if (*s == '\"')
-        return NULL;            /* invalid encoding */
-      else if (*s == ',' || *s == '=' || *s == '+'
-               || *s == '<' || *s == '>' || *s == '#' || *s == ';')
-        break;
-      else
-        n++;
-    }
-
-    p = p_new(unsigned char, n + 1);
-    array->value = (char *) p;
-    for (s = string; n; s++, n--) {
-      if (*s == '\\') {
-        s++;
-        if (hexval(*s) >= 0) {
-          *p++ = (hexval(*s) << 8) | hexval(*s + 1);
-          s++;
-        }
-        else
-          *p++ = *s;
-      }
-      else
-        *p++ = *s;
-    }
-    *p = 0;
-  }
-  return s;
-}
-
-
-/* Parse a DN and return an array-ized one.  This is not a validating
-   parser and it does not support any old-stylish syntax; gpgme is
-   expected to return only rfc2253 compatible strings. */
-static struct dn_array_s *parse_dn (const unsigned char *string)
-{
-  struct dn_array_s *array;
-  ssize_t arrayidx, arraysize;
-  int i;
-
-  arraysize = 7;                /* C,ST,L,O,OU,CN,email */
-  array = p_new(struct dn_array_s, arraysize + 1);
-  arrayidx = 0;
-  while (*string) {
-    while (*string == ' ')
-      string++;
-    if (!*string)
-      break;                    /* ready */
-    if (arrayidx >= arraysize) {        /* mutt lacks a real safe_realoc - so we need to copy */
-      struct dn_array_s *a2;
-
-      arraysize += 5;
-      a2 = p_new(struct dn_array_s, arraysize + 1);
-      for (i = 0; i < arrayidx; i++) {
-        a2[i].key = array[i].key;
-        a2[i].value = array[i].value;
-      }
-      p_delete(&array);
-      array = a2;
-    }
-    array[arrayidx].key = NULL;
-    array[arrayidx].value = NULL;
-    string = parse_dn_part (array + arrayidx, string);
-    arrayidx++;
-    if (!string)
-      goto failure;
-    while (*string == ' ')
-      string++;
-    if (*string && *string != ',' && *string != ';' && *string != '+')
-      goto failure;             /* invalid delimiter */
-    if (*string)
-      string++;
-  }
-  array[arrayidx].key = NULL;
-  array[arrayidx].value = NULL;
-  return array;
-
-failure:
-  for (i = 0; i < arrayidx; i++) {
-    p_delete(&array[i].key);
-    p_delete(&array[i].value);
-  }
-  p_delete(&array);
-  return NULL;
-}
-
-
-/* Print a nice representation of the USERID and make sure it is
-   displayed in a proper way, which does mean to reorder some parts
-   for S/MIME's DNs.  USERID is a string as returned by the gpgme key
-   functions.  It is utf-8 encoded. */
-static void parse_and_print_user_id (FILE * fp, const char *userid)
-{
-  const char *s;
-  int i;
-
-  if (*userid == '<') {
-    s = strchr (userid + 1, '>');
-    if (s)
-      print_utf8 (fp, userid + 1, s - userid - 1);
-  }
-  else if (*userid == '(')
-    fputs (_("[Can't display this user ID (unknown encoding)]"), fp);
-  else if (!digit_or_letter ((const unsigned char *) userid))
-    fputs (_("[Can't display this user ID (invalid encoding)]"), fp);
-  else {
-    struct dn_array_s *dn = parse_dn ((const unsigned char *) userid);
-
-    if (!dn)
-      fputs (_("[Can't display this user ID (invalid DN)]"), fp);
-    else {
-      print_dn_parts (fp, dn);
-      for (i = 0; dn[i].key; i++) {
-        p_delete(&dn[i].key);
-        p_delete(&dn[i].value);
-      }
-      p_delete(&dn);
-    }
-  }
-}
-
-typedef enum {
-  KEY_CAP_CAN_ENCRYPT,
-  KEY_CAP_CAN_SIGN,
-  KEY_CAP_CAN_CERTIFY
-} key_cap_t;
-
-static unsigned int key_check_cap (gpgme_key_t key, key_cap_t cap)
-{
-  gpgme_subkey_t subkey = NULL;
-  unsigned int ret = 0;
-
-  switch (cap) {
-  case KEY_CAP_CAN_ENCRYPT:
-    if (!(ret = key->can_encrypt))
-      for (subkey = key->subkeys; subkey; subkey = subkey->next)
-        if ((ret = subkey->can_encrypt))
-          break;
-    break;
-  case KEY_CAP_CAN_SIGN:
-    if (!(ret = key->can_sign))
-      for (subkey = key->subkeys; subkey; subkey = subkey->next)
-        if ((ret = subkey->can_sign))
-          break;
-    break;
-  case KEY_CAP_CAN_CERTIFY:
-    if (!(ret = key->can_certify))
-      for (subkey = key->subkeys; subkey; subkey = subkey->next)
-        if ((ret = subkey->can_certify))
-          break;
-    break;
-  }
-
-  return ret;
-}
-
-
-/* Print verbose information about a key or certificate to FP. */
-static void print_key_info (gpgme_key_t key, FILE * fp)
-{
-  int idx;
-  const char *s = NULL, *s2 = NULL;
-  time_t tt = 0;
-  struct tm *tm;
-  char shortbuf[STRING];
-  unsigned long aval = 0;
-  const char *delim;
-  int is_pgp = 0;
-  int i;
-  gpgme_user_id_t uid = NULL;
-
-  if (Locale)
-    setlocale (LC_TIME, Locale);
-
-  is_pgp = key->protocol == GPGME_PROTOCOL_OpenPGP;
-
-  for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
-    if (uid->revoked)
-      continue;
-
-    s = uid->uid;
-    fputs (idx ? _(" aka ......: ") :_("Name ......: "), fp);
-
-    if (uid->invalid) {
-      fputs (_("[Invalid]"), fp);
-      putc (' ', fp);
-    }
-    if (is_pgp)
-      print_utf8 (fp, s, m_strlen(s));
-    else
-      parse_and_print_user_id (fp, s);
-    putc ('\n', fp);
-  }
-
-  if (key->subkeys && (key->subkeys->timestamp > 0)) {
-    tt = key->subkeys->timestamp;
-
-    tm = localtime (&tt);
-#ifdef HAVE_LANGINFO_D_T_FMT
-    strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
-#else
-    strftime (shortbuf, sizeof shortbuf, "%c", tm);
-#endif
-    fprintf (fp, _("Valid From : %s\n"), shortbuf);
-  }
-
-  if (key->subkeys && (key->subkeys->expires > 0)) {
-    tt = key->subkeys->expires;
-
-    tm = localtime (&tt);
-#ifdef HAVE_LANGINFO_D_T_FMT
-    strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
-#else
-    strftime (shortbuf, sizeof shortbuf, "%c", tm);
-#endif
-    fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
-  }
-
-  if (key->subkeys)
-    s = gpgme_pubkey_algo_name (key->subkeys->pubkey_algo);
-  else
-    s = "?";
-
-  s2 = is_pgp ? "PGP" : "X.509";
-
-  if (key->subkeys)
-    aval = key->subkeys->length;
-
-  fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), s2, aval, s);
-
-  fprintf (fp, _("Key Usage .: "));
-  delim = "";
-
-  if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT)) {
-    fprintf (fp, "%s%s", delim, _("encryption"));
-    delim = _(", ");
-  }
-  if (key_check_cap (key, KEY_CAP_CAN_SIGN)) {
-    fprintf (fp, "%s%s", delim, _("signing"));
-    delim = _(", ");
-  }
-  if (key_check_cap (key, KEY_CAP_CAN_CERTIFY)) {
-    fprintf (fp, "%s%s", delim, _("certification"));
-    delim = _(", ");
-  }
-  putc ('\n', fp);
-
-  if (key->subkeys) {
-    s = key->subkeys->fpr;
-    fputs (_("Fingerprint: "), fp);
-    if (is_pgp && m_strlen(s) == 40) {
-      for (i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) {
-        putc (*s, fp);
-        putc (s[1], fp);
-        putc (s[2], fp);
-        putc (s[3], fp);
-        putc (is_pgp ? ' ' : ':', fp);
-        if (is_pgp && i == 4)
-          putc (' ', fp);
-      }
-    }
-    else {
-      for (i = 0; *s && s[1] && s[2]; s += 2, i++) {
-        putc (*s, fp);
-        putc (s[1], fp);
-        putc (is_pgp ? ' ' : ':', fp);
-        if (is_pgp && i == 7)
-          putc (' ', fp);
-      }
-    }
-    fprintf (fp, "%s\n", s);
-  }
-
-  if (key->issuer_serial) {
-    s = key->issuer_serial;
-    if (s)
-      fprintf (fp, _("Serial-No .: 0x%s\n"), s);
-  }
-
-  if (key->issuer_name) {
-    s = key->issuer_name;
-    if (s) {
-      fprintf (fp, _("Issued By .: "));
-      parse_and_print_user_id (fp, s);
-      putc ('\n', fp);
-    }
-  }
-
-  /* For PGP we list all subkeys. */
-  if (is_pgp) {
-    gpgme_subkey_t subkey = NULL;
-
-    for (idx = 1, subkey = key->subkeys; subkey; idx++, subkey = subkey->next) {
-      s = subkey->keyid;
-
-      putc ('\n', fp);
-      if (m_strlen(s) == 16)
-        s += 8;                 /* display only the short keyID */
-      fprintf (fp, _("Subkey ....: 0x%s"), s);
-      if (subkey->revoked) {
-        putc (' ', fp);
-        fputs (_("[Revoked]"), fp);
-      }
-      if (subkey->invalid) {
-        putc (' ', fp);
-        fputs (_("[Invalid]"), fp);
-      }
-      if (subkey->expired) {
-        putc (' ', fp);
-        fputs (_("[Expired]"), fp);
-      }
-      if (subkey->disabled) {
-        putc (' ', fp);
-        fputs (_("[Disabled]"), fp);
-      }
-      putc ('\n', fp);
-
-      if (subkey->timestamp > 0) {
-        tt = subkey->timestamp;
-
-        tm = localtime (&tt);
-#ifdef HAVE_LANGINFO_D_T_FMT
-        strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
-#else
-        strftime (shortbuf, sizeof shortbuf, "%c", tm);
-#endif
-        fprintf (fp, _("Valid From : %s\n"), shortbuf);
-      }
-
-      if (subkey->expires > 0) {
-        tt = subkey->expires;
-
-        tm = localtime (&tt);
-#ifdef HAVE_LANGINFO_D_T_FMT
-        strftime (shortbuf, sizeof shortbuf, nl_langinfo (D_T_FMT), tm);
-#else
-        strftime (shortbuf, sizeof shortbuf, "%c", tm);
-#endif
-        fprintf (fp, _("Valid To ..: %s\n"), shortbuf);
-      }
-
-      if (subkey)
-        s = gpgme_pubkey_algo_name (subkey->pubkey_algo);
-      else
-        s = "?";
-
-      if (subkey)
-        aval = subkey->length;
-      else
-        aval = 0;
-
-      fprintf (fp, _("Key Type ..: %s, %lu bit %s\n"), "PGP", aval, s);
-
-      fprintf (fp, _("Key Usage .: "));
-      delim = "";
-
-      if (subkey->can_encrypt) {
-        fprintf (fp, "%s%s", delim, _("encryption"));
-        delim = _(", ");
-      }
-      if (subkey->can_sign) {
-        fprintf (fp, "%s%s", delim, _("signing"));
-        delim = _(", ");
-      }
-      if (subkey->can_certify) {
-        fprintf (fp, "%s%s", delim, _("certification"));
-        delim = _(", ");
-      }
-      putc ('\n', fp);
-    }
-  }
-
-  if (Locale)
-    setlocale (LC_TIME, "C");
-}
-
-
-/* Show detailed information about the selected key */
-static void verify_key (crypt_key_t * key)
-{
-  FILE *fp;
-  char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
-  const char *s;
-  gpgme_ctx_t listctx = NULL;
-  gpgme_error_t err;
-  gpgme_key_t k = NULL;
-  int maxdepth = 100;
-
-  fp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
-  if (!fp) {
-    mutt_perror (_("Can't create temporary file"));
-    return;
-  }
-  mutt_message _("Collecting data...");
-
-  print_key_info (key->kobj, fp);
-
-  err = gpgme_new (&listctx);
-  if (err) {
-    fprintf (fp, "Internal error: can't create gpgme context: %s\n",
-             gpgme_strerror (err));
-    goto leave;
-  }
-  if ((key->flags & KEYFLAG_ISX509))
-    gpgme_set_protocol (listctx, GPGME_PROTOCOL_CMS);
-
-  k = key->kobj;
-  gpgme_key_ref (k);
-  while ((s = k->chain_id) && k->subkeys && m_strcmp(s, k->subkeys->fpr)) {
-    putc ('\n', fp);
-    err = gpgme_op_keylist_start (listctx, s, 0);
-    gpgme_key_release (k);
-    k = NULL;
-    if (!err)
-      err = gpgme_op_keylist_next (listctx, &k);
-    if (err) {
-      fprintf (fp, _("Error finding issuer key: %s\n"), gpgme_strerror (err));
-      goto leave;
-    }
-    gpgme_op_keylist_end (listctx);
-
-    print_key_info (k, fp);
-    if (!--maxdepth) {
-      putc ('\n', fp);
-      fputs (_("Error: certification chain to long - stopping here\n"), fp);
-      break;
-    }
-  }
-
-leave:
-  gpgme_key_release (k);
-  gpgme_release (listctx);
-  m_fclose(&fp);
-  mutt_clear_error ();
-  snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"), crypt_keyid (key));
-  mutt_do_pager (cmd, tempfile, 0, NULL);
-}
-
-/* Implementation of `findkeys'. */
-
-/* Convert string_list_t into a pattern string suitable to be passed to GPGME.
-   We need to convert spaces in an item into a '+' and '%' into
-   "%25". */
-static char *list_to_pattern (string_list_t * list)
-{
-  string_list_t *l;
-  char *pattern, *p;
-  const char *s;
-  ssize_t n;
-
-  n = 0;
-  for (l = list; l; l = l->next) {
-    for (s = l->data; *s; s++) {
-      if (*s == '%')
-        n += 2;
-      n++;
-    }
-    n++;                        /* delimiter or end of string */
-  }
-  n++;                          /* make sure to allocate at least one byte */
-  pattern = p = p_new(char, n);
-  for (l = list; l; l = l->next) {
-    s = l->data;
-    if (*s) {
-      if (l != list)
-        *p++ = ' ';
-      for (s = l->data; *s; s++) {
-        if (*s == '%') {
-          *p++ = '%';
-          *p++ = '2';
-          *p++ = '5';
-        }
-        else if (*s == '+') {
-          *p++ = '%';
-          *p++ = '2';
-          *p++ = 'B';
-        }
-        else if (*s == ' ')
-          *p++ = '+';
-        else
-          *p++ = *s;
-      }
-    }
-  }
-  *p = 0;
-  return pattern;
-}
-
-/* Return a list of keys which are candidates for the selection.
-   Select by looking at the HINTS list. */
-static crypt_key_t *get_candidates (string_list_t * hints, unsigned int app,
-                                    int secret)
-{
-  crypt_key_t *db, *k, **kend;
-  char *pattern;
-  gpgme_error_t err;
-  gpgme_ctx_t ctx;
-  gpgme_key_t key;
-  int idx;
-  gpgme_user_id_t uid = NULL;
-
-  pattern = list_to_pattern (hints);
-  if (!pattern)
-    return NULL;
-
-  err = gpgme_new (&ctx);
-  if (err) {
-    mutt_error (_("gpgme_new failed: %s"), gpgme_strerror (err));
-    p_delete(&pattern);
-    return NULL;
-  }
-
-  db = NULL;
-  kend = &db;
-
-  if ((app & APPLICATION_PGP)) {
-    /* Its all a mess.  That old GPGME expects different things
-       depending on the protocol.  For gpg we don' t need percent
-       escaped pappert but simple strings passed in an array to the
-       keylist_ext_start function. */
-    string_list_t *l;
-    ssize_t n;
-    char **patarr;
-
-    for (l = hints, n = 0; l; l = l->next) {
-      if (l->data && *l->data)
-        n++;
-    }
-    if (!n)
-      goto no_pgphints;
-
-    patarr = p_new(char *, n + 1);
-    for (l = hints, n = 0; l; l = l->next) {
-      if (l->data && *l->data)
-        patarr[n++] = m_strdup(l->data);
-    }
-    patarr[n] = NULL;
-    err = gpgme_op_keylist_ext_start (ctx, (const char **) patarr, secret, 0);
-    for (n = 0; patarr[n]; n++)
-      p_delete(&patarr[n]);
-    p_delete(&patarr);
-    if (err) {
-      mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
-      gpgme_release (ctx);
-      p_delete(&pattern);
-      return NULL;
-    }
-
-    while (!(err = gpgme_op_keylist_next (ctx, &key))) {
-      unsigned int flags = 0;
-
-      if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
-        flags |= KEYFLAG_CANENCRYPT;
-      if (key_check_cap (key, KEY_CAP_CAN_SIGN))
-        flags |= KEYFLAG_CANSIGN;
-
-      for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
-        k = p_new(crypt_key_t, 1);
-        k->kobj = key;
-        k->idx = idx;
-        k->uid = uid->uid;
-        k->flags = flags;
-        *kend = k;
-        kend = &k->next;
-      }
-    }
-    if (gpg_err_code (err) != GPG_ERR_EOF)
-      mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
-    gpgme_op_keylist_end (ctx);
-  no_pgphints:
-    ;
-  }
-
-  if ((app & APPLICATION_SMIME)) {
-    /* and now look for x509 certificates */
-    gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
-    err = gpgme_op_keylist_start (ctx, pattern, 0);
-    if (err) {
-      mutt_error (_("gpgme_op_keylist_start failed: %s"), gpgme_strerror (err));
-      gpgme_release (ctx);
-      p_delete(&pattern);
-      return NULL;
-    }
-
-    while (!(err = gpgme_op_keylist_next (ctx, &key))) {
-      unsigned int flags = KEYFLAG_ISX509;
-
-      if (key_check_cap (key, KEY_CAP_CAN_ENCRYPT))
-        flags |= KEYFLAG_CANENCRYPT;
-      if (key_check_cap (key, KEY_CAP_CAN_SIGN))
-        flags |= KEYFLAG_CANSIGN;
-
-      for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next) {
-        k = p_new(crypt_key_t, 1);
-        k->kobj = key;
-        k->idx = idx;
-        k->uid = uid->uid;
-        k->flags = flags;
-        *kend = k;
-        kend = &k->next;
-      }
-    }
-    if (gpg_err_code (err) != GPG_ERR_EOF)
-      mutt_error (_("gpgme_op_keylist_next failed: %s"), gpgme_strerror (err));
-    gpgme_op_keylist_end (ctx);
-  }
-
-  gpgme_release (ctx);
-  p_delete(&pattern);
-  return db;
-}
-
-/* Add the string STR to the list HINTS.  This list is later used to
-   match addresses. */
-static string_list_t *crypt_add_string_to_hints (string_list_t * hints, const char *str)
-{
-  char *scratch;
-  char *t;
-
-  if ((scratch = m_strdup(str)) == NULL)
-    return hints;
-
-  for (t = strtok (scratch, " ,.:\"()<>\n"); t;
-       t = strtok (NULL, " ,.:\"()<>\n")) {
-    if (m_strlen(t) > 3)
-      hints = mutt_add_list(hints, t);
-  }
-
-  p_delete(&scratch);
-  return hints;
-}
-
-/* Display a menu to select a key from the array KEYS. FORCED_VALID
-   will be set to true on return if the user did override the the
-   key's validity. */
-static crypt_key_t *crypt_select_key (crypt_key_t * keys,
-                                      address_t * p, const char *s,
-                                      unsigned int app, int *forced_valid)
-{
-  int keymax;
-  crypt_key_t **key_table;
-  MUTTMENU *menu;
-  int i, done = 0;
-  char helpstr[STRING], buf[LONG_STRING];
-  crypt_key_t *k;
-  int (*f) (const void *, const void *);
-  int menu_to_use = 0;
-  int unusable = 0;
-
-  *forced_valid = 0;
-
-  /* build the key table */
-  keymax = i = 0;
-  key_table = NULL;
-  for (k = keys; k; k = k->next) {
-    if (!option (OPTPGPSHOWUNUSABLE) && (k->flags & KEYFLAG_CANTUSE)) {
-      unusable = 1;
-      continue;
-    }
-
-    if (i == keymax) {
-      keymax += 20;
-      p_realloc(&key_table, keymax);
-    }
-
-    key_table[i++] = k;
-  }
-
-  if (!i && unusable) {
-    mutt_error _("All matching keys are marked expired/revoked.");
-
-    mutt_sleep (1);
-    return NULL;
-  }
-
-  switch (PgpSortKeys & SORT_MASK) {
-  case SORT_DATE:
-    f = crypt_compare_date;
-    break;
-  case SORT_KEYID:
-    f = crypt_compare_keyid;
-    break;
-  case SORT_ADDRESS:
-    f = crypt_compare_address;
-    break;
-  case SORT_TRUST:
-  default:
-    f = crypt_compare_trust;
-    break;
-  }
-  qsort (key_table, i, sizeof (crypt_key_t *), f);
-
-  if (app & APPLICATION_PGP)
-    menu_to_use = MENU_KEY_SELECT_PGP;
-  else if (app & APPLICATION_SMIME)
-    menu_to_use = MENU_KEY_SELECT_SMIME;
-
-  helpstr[0] = 0;
-  mutt_make_help (buf, sizeof (buf), _("Exit  "), menu_to_use, OP_EXIT);
-  m_strcat(helpstr, sizeof(helpstr), buf);
-  mutt_make_help (buf, sizeof (buf), _("Select  "), menu_to_use,
-                  OP_GENERIC_SELECT_ENTRY);
-  m_strcat(helpstr, sizeof(helpstr), buf);
-  mutt_make_help (buf, sizeof (buf), _("Check key  "),
-                  menu_to_use, OP_VERIFY_KEY);
-  m_strcat(helpstr, sizeof(helpstr), buf);
-  mutt_make_help (buf, sizeof (buf), _("Help"), menu_to_use, OP_HELP);
-  m_strcat(helpstr, sizeof(helpstr), buf);
-
-  menu = mutt_new_menu ();
-  menu->max = i;
-  menu->make_entry = crypt_entry;
-  menu->menu = menu_to_use;
-  menu->help = helpstr;
-  menu->data = key_table;
-
-  {
-    const char *ts;
-
-    if ((app & APPLICATION_PGP) && (app & APPLICATION_SMIME))
-      ts = _("PGP and S/MIME keys matching");
-    else if ((app & APPLICATION_PGP))
-      ts = _("PGP keys matching");
-    else if ((app & APPLICATION_SMIME))
-      ts = _("S/MIME keys matching");
-    else
-      ts = _("keys matching");
-
-    if (p)
-      snprintf (buf, sizeof (buf), _("%s <%s>."), ts, p->mailbox);
-    else
-      snprintf (buf, sizeof (buf), _("%s \"%s\"."), ts, s);
-    menu->title = buf;
-  }
-
-  mutt_clear_error ();
-  k = NULL;
-  while (!done) {
-    *forced_valid = 0;
-    switch (mutt_menuLoop (menu)) {
-    case OP_VERIFY_KEY:
-      verify_key (key_table[menu->current]);
-      menu->redraw = REDRAW_FULL;
-      break;
-
-    case OP_VIEW_ID:
-      mutt_message ("%s", key_table[menu->current]->uid);
-      break;
-
-    case OP_GENERIC_SELECT_ENTRY:
-      /* FIXME make error reporting more verbose - this should be
-         easy because gpgme provides more information */
-      if (option (OPTPGPCHECKTRUST)) {
-        if (!crypt_key_is_valid (key_table[menu->current])) {
-          mutt_error _("This key can't be used: "
-                       "expired/disabled/revoked.");
-          break;
-        }
-      }
-
-      if (option (OPTPGPCHECKTRUST) &&
-          (!crypt_id_is_valid (key_table[menu->current])
-           || !crypt_id_is_strong (key_table[menu->current]))) {
-        const char *warn_s;
-        char buff[LONG_STRING];
-
-        if (key_table[menu->current]->flags & KEYFLAG_CANTUSE)
-          s = N_("ID is expired/disabled/revoked.");
-        else {
-          gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
-          gpgme_user_id_t uid = NULL;
-          int j = 0;
-
-          warn_s = "??";
-
-          uid = key_table[menu->current]->kobj->uids;
-          for (j = 0; (j < key_table[menu->current]->idx) && uid;
-               j++, uid = uid->next);
-          if (uid)
-            val = uid->validity;
-
-          switch (val) {
-          case GPGME_VALIDITY_UNKNOWN:
-          case GPGME_VALIDITY_UNDEFINED:
-            warn_s = N_("ID has undefined validity.");
-            break;
-          case GPGME_VALIDITY_NEVER:
-            warn_s = N_("ID is not valid.");
-            break;
-          case GPGME_VALIDITY_MARGINAL:
-            warn_s = N_("ID is only marginally valid.");
-            break;
-          case GPGME_VALIDITY_FULL:
-          case GPGME_VALIDITY_ULTIMATE:
-            break;
-          }
-
-          snprintf (buff, sizeof (buff),
-                    _("%s Do you really want to use the key?"), _(warn_s));
-
-          if (mutt_yesorno (buff, 0) != 1) {
-            mutt_clear_error ();
-            break;
-          }
-          *forced_valid = 1;
-        }
-      }
-
-      k = crypt_copy_key (key_table[menu->current]);
-      done = 1;
-      break;
-
-    case OP_EXIT:
-      k = NULL;
-      done = 1;
-      break;
-    }
-  }
-
-  mutt_menuDestroy (&menu);
-  p_delete(&key_table);
-
-  set_option (OPTNEEDREDRAW);
-
-  return k;
-}
-
-static crypt_key_t *crypt_getkeybyaddr (address_t * a, short abilities,
-                                        unsigned int app, int *forced_valid)
-{
-  address_t *r, *p;
-  string_list_t *hints = NULL;
-
-  int weak = 0;
-  int invalid = 0;
-  int multi = 0;
-  int this_key_has_strong;
-  int this_key_has_weak;
-  int this_key_has_invalid;
-  int match;
-
-  crypt_key_t *keys, *k;
-  crypt_key_t *the_valid_key = NULL;
-  crypt_key_t *matches = NULL;
-  crypt_key_t **matches_endp = &matches;
-
-  *forced_valid = 0;
-
-  if (a && a->mailbox)
-    hints = crypt_add_string_to_hints (hints, a->mailbox);
-  if (a && a->personal)
-    hints = crypt_add_string_to_hints (hints, a->personal);
-
-  mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
-  keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
-
-  string_list_wipe(&hints);
-
-  if (!keys)
-    return NULL;
-
-  for (k = keys; k; k = k->next) {
-    if (abilities && !(k->flags & abilities)) {
-      continue;
-    }
-
-    this_key_has_weak = 0;      /* weak but valid match   */
-    this_key_has_invalid = 0;   /* invalid match          */
-    this_key_has_strong = 0;    /* strong and valid match */
-    match = 0;                  /* any match            */
-
-    r = rfc822_parse_adrlist (NULL, k->uid);
-    for (p = r; p; p = p->next) {
-      int validity = crypt_id_matches_addr (a, p, k);
-
-      if (validity & CRYPT_KV_MATCH)    /* something matches */
-        match = 1;
-
-      /* is this key a strong candidate? */
-      if ((validity & CRYPT_KV_VALID)
-          && (validity & CRYPT_KV_STRONGID)
-          && (validity & CRYPT_KV_ADDR)) {
-        if (the_valid_key && the_valid_key != k)
-          multi = 1;
-        the_valid_key = k;
-        this_key_has_strong = 1;
-      }
-      else if ((validity & CRYPT_KV_MATCH)
-               && !(validity & CRYPT_KV_VALID))
-        this_key_has_invalid = 1;
-      else if ((validity & CRYPT_KV_MATCH)
-               && (!(validity & CRYPT_KV_STRONGID)
-                   || !(validity & CRYPT_KV_ADDR)))
-        this_key_has_weak = 1;
-    }
-    address_list_wipe(&r);
-
-    if (match) {
-      crypt_key_t *tmp;
-
-      if (!this_key_has_strong && this_key_has_invalid)
-        invalid = 1;
-      if (!this_key_has_strong && this_key_has_weak)
-        weak = 1;
-
-      *matches_endp = tmp = crypt_copy_key (k);
-      matches_endp = &tmp->next;
-      the_valid_key = tmp;
-    }
-  }
-
-  crypt_free_key (&keys);
-
-  if (matches) {
-    if (the_valid_key && !multi && !weak
-        && !(invalid && option (OPTPGPSHOWUNUSABLE))) {
-      /*
-       * There was precisely one strong match on a valid ID, there
-       * were no valid keys with weak matches, and we aren't
-       * interested in seeing invalid keys.
-       *
-       * Proceed without asking the user.
-       */
-      k = crypt_copy_key (the_valid_key);
-    }
-    else {
-      /*
-       * Else: Ask the user.
-       */
-      k = crypt_select_key (matches, a, NULL, app, forced_valid);
-    }
-    crypt_free_key (&matches);
-  }
-  else
-    k = NULL;
-
-  return k;
-}
-
-
-static crypt_key_t *crypt_getkeybystr (const char *p, short abilities,
-                                       unsigned int app, int *forced_valid)
-{
-  string_list_t *hints = NULL;
-  crypt_key_t *keys;
-  crypt_key_t *matches = NULL;
-  crypt_key_t **matches_endp = &matches;
-  crypt_key_t *k;
-  int match;
-
-  mutt_message (_("Looking for keys matching \"%s\"..."), p);
-
-  *forced_valid = 0;
-
-  hints = crypt_add_string_to_hints (hints, p);
-  keys = get_candidates (hints, app, (abilities & KEYFLAG_CANSIGN));
-  string_list_wipe(&hints);
-
-  if (!keys)
-    return NULL;
-
-  for (k = keys; k; k = k->next) {
-    if (abilities && !(k->flags & abilities))
-      continue;
-
-    match = 0;
-
-    if (!*p || !m_strcasecmp(p, crypt_keyid (k))
-        || (!m_strncasecmp(p, "0x", 2)
-            && !m_strcasecmp(p + 2, crypt_keyid (k)))
-        || (option (OPTPGPLONGIDS)
-            && !m_strncasecmp(p, "0x", 2)
-            && !m_strcasecmp(p + 2, crypt_keyid (k) + 8))
-        || m_stristr(k->uid, p)) {
-      crypt_key_t *tmp;
-
-      *matches_endp = tmp = crypt_copy_key (k);
-      matches_endp = &tmp->next;
-    }
-  }
-
-  crypt_free_key (&keys);
-
-  if (matches) {
-    k = crypt_select_key (matches, NULL, p, app, forced_valid);
-    crypt_free_key (&matches);
-    return k;
-  }
-
-  return NULL;
-}
-
-/* Display TAG as a prompt to ask for a key.  If WHATFOR is not null
-   use it as default and store it under that label as the next
-   default.  ABILITIES describe the required key abilities (sign,
-   encrypt) and APP the type of the requested key; ether S/MIME or
-   PGP.  Return a copy of the key or NULL if not found. */
-static crypt_key_t *crypt_ask_for_key (char *tag,
-                                       char *whatfor,
-                                       short abilities,
-                                       unsigned int app, int *forced_valid)
-{
-  crypt_key_t *key;
-  char resp[STRING];
-  struct crypt_cache *l = NULL;
-  int dummy;
-
-  if (!forced_valid)
-    forced_valid = &dummy;
-
-  mutt_clear_error ();
-
-  *forced_valid = 0;
-  resp[0] = 0;
-  if (whatfor) {
-
-    for (l = id_defaults; l; l = l->next)
-      if (!m_strcasecmp(whatfor, l->what)) {
-        m_strcpy(resp, sizeof(resp), NONULL(l->dflt));
-        break;
-      }
-  }
-
-
-  for (;;) {
-    resp[0] = 0;
-    if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0)
-      return NULL;
-
-    if (whatfor) {
-      if (l)
-        m_strreplace(&l->dflt, resp);
-      else {
-        l = p_new(struct crypt_cache, 1);
-        l->next = id_defaults;
-        id_defaults = l;
-        l->what = m_strdup(whatfor);
-        l->dflt = m_strdup(resp);
-      }
-    }
-
-    if ((key = crypt_getkeybystr (resp, abilities, app, forced_valid)))
-      return key;
-
-    BEEP ();
-  }
-  /* not reached */
-}
-
-/* This routine attempts to find the keyids of the recipients of a
-   message.  It returns NULL if any of the keys can not be found.  */
-static char *find_keys (address_t * to, address_t * cc, address_t * bcc,
-                        unsigned int app)
-{
-  char *keylist = NULL, *t;
-  const char *keyID;
-  ssize_t keylist_size = 0;
-  ssize_t keylist_used = 0;
-  address_t *tmp = NULL, *addr = NULL;
-  address_t **last = &tmp;
-  address_t *p, *q;
-  int i;
-  crypt_key_t *k_info, *key;
-  const char *fqdn = mutt_fqdn (1);
-
-#if 0
-  *r_application = APPLICATION_PGP | APPLICATION_SMIME;
-#endif
-
-  for (i = 0; i < 3; i++) {
-    switch (i) {
-    case 0:
-      p = to;
-      break;
-    case 1:
-      p = cc;
-      break;
-    case 2:
-      p = bcc;
-      break;
-    default:
-      abort ();
-    }
-
-    *last = address_list_dup (p);
-    while (*last)
-      last = &((*last)->next);
-  }
-
-  rfc822_qualify(tmp, fqdn);
-  address_list_uniq(tmp);
-
-  for (p = tmp; p; p = p->next) {
-    char buf[LONG_STRING];
-    int forced_valid = 0;
-
-    q = p;
-    k_info = NULL;
-
-    if ((keyID = mutt_crypt_hook (p)) != NULL) {
-      int r;
-
-      snprintf (buf, sizeof (buf), _("Use keyID = \"%s\" for %s?"),
-                keyID, p->mailbox);
-      if ((r = mutt_yesorno (buf, M_YES)) == M_YES) {
-        /* check for e-mail address */
-        if ((t = strchr (keyID, '@')) &&
-            (addr = rfc822_parse_adrlist (NULL, keyID))) {
-          rfc822_qualify(addr, fqdn);
-          q = addr;
-        }
-        else {
-          k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
-                                      app, &forced_valid);
-        }
-      }
-      else if (r == -1) {
-        p_delete(&keylist);
-        address_list_wipe(&tmp);
-        address_list_wipe(&addr);
-        return NULL;
-      }
-    }
-
-    if (k_info == NULL
-        && (k_info = crypt_getkeybyaddr (q, KEYFLAG_CANENCRYPT,
-                                         app, &forced_valid)) == NULL) {
-      snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
-
-      if ((key = crypt_ask_for_key (buf, q->mailbox, KEYFLAG_CANENCRYPT,
-                                    app,
-                                    &forced_valid)) == NULL) {
-        p_delete(&keylist);
-        address_list_wipe(&tmp);
-        address_list_wipe(&addr);
-        return NULL;
-      }
-    }
-    else
-      key = k_info;
-
-    {
-      const char *s = crypt_fpr (key);
-
-      keylist_size += m_strlen(s) + 4 + 1;
-      p_realloc(&keylist, keylist_size);
-      sprintf (keylist + keylist_used, "%s0x%s%s",
-               keylist_used ? " " : "", s, forced_valid ? "!" : "");
-    }
-    keylist_used = m_strlen(keylist);
-
-    crypt_free_key (&key);
-    address_list_wipe(&addr);
-  }
-  address_list_wipe(&tmp);
-  return (keylist);
-}
-
-int crypt_get_keys (HEADER * msg, char **keylist)
-{
-  /* Do a quick check to make sure that we can find all of the encryption
-   * keys if the user has requested this service.
-   */
-
-  *keylist = NULL;
-
-  if (msg->security & ENCRYPT) {
-    if (msg->security & APPLICATION_PGP) {
-      set_option(OPTPGPCHECKTRUST);
-      *keylist = find_keys(msg->env->to, msg->env->cc, msg->env->bcc,
-                           APPLICATION_PGP);
-      unset_option(OPTPGPCHECKTRUST);
-      if (!*keylist)
-          return -1;
-    }
-
-    if (msg->security & APPLICATION_SMIME) {
-      *keylist = find_keys(msg->env->to, msg->env->cc, msg->env->bcc,
-                           APPLICATION_SMIME);
-      if (!*keylist)
-          return -1;
-    }
-  }
-
-  return (0);
-}
-
-
-int crypt_send_menu (HEADER * msg, int *redraw, int is_smime)
-{
-  crypt_key_t *p;
-  char input_signas[STRING];
-  int choice;
-
-  if (msg->security & APPLICATION_PGP)
-    is_smime = 0;
-  else if (msg->security & APPLICATION_SMIME)
-    is_smime = 1;
-
-  if (is_smime)
-    choice =
-      mutt_multi_choice (_
-                         ("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?"),
-                         _("esabpc"));
-  else
-    choice =
-      mutt_multi_choice (_
-                         ("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?"),
-                         _("esabmc"));
-
-  switch (choice) {
-  case 1:                      /* (e)ncrypt */
-    msg->security |= (is_smime ? SMIMEENCRYPT : PGPENCRYPT);
-    msg->security &= ~(is_smime ? SMIMESIGN : PGPSIGN);
-    break;
-
-  case 2:                      /* (s)ign */
-    msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
-    msg->security &= ~(is_smime ? SMIMEENCRYPT : PGPENCRYPT);
-    break;
-
-  case 3:                      /* sign (a)s */
-    if ((p = crypt_ask_for_key (_("Sign as: "), NULL, KEYFLAG_CANSIGN,
-                                is_smime ? APPLICATION_SMIME :
-                                APPLICATION_PGP, NULL))) {
-      snprintf (input_signas, sizeof (input_signas), "0x%s", crypt_keyid (p));
-      m_strreplace(is_smime ? &SmimeDefaultKey : &PgpSignAs,
-                        input_signas);
-      crypt_free_key (&p);
-
-      msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
-    }
-    *redraw = REDRAW_FULL;
-    break;
-
-  case 4:                      /* (b)oth */
-    msg->security =
-      (is_smime ? (SMIMEENCRYPT | SMIMESIGN) : (PGPENCRYPT | PGPSIGN));
-    break;
-
-  case 5:                      /* (p)gp or s/(m)ime */
-    is_smime = !is_smime;
-    break;
-
-  case 6:                      /* (c)lear */
-    return msg->security = 0;
-  }
-
-  if (is_smime) {
-    msg->security &= ~APPLICATION_PGP;
-    msg->security |= APPLICATION_SMIME;
-  } else {
-    msg->security &= ~APPLICATION_SMIME;
-    msg->security |= APPLICATION_PGP;
-  }
-
-  return msg->security;
-}
-
-int crypt_smime_verify_sender (HEADER * h)
-{
-  address_t *sender = NULL;
-  unsigned int ret = 1;
-
-  if (h->env->from) {
-    h->env->from = mutt_expand_aliases (h->env->from);
-    sender = h->env->from;
-  }
-  else if (h->env->sender) {
-    h->env->sender = mutt_expand_aliases (h->env->sender);
-    sender = h->env->sender;
-  }
-
-  if (sender) {
-    if (signature_key) {
-      gpgme_key_t key = signature_key;
-      gpgme_user_id_t uid = NULL;
-      int sender_length = 0;
-      int uid_length = 0;
-
-      sender_length = m_strlen(sender->mailbox);
-      for (uid = key->uids; uid && ret; uid = uid->next) {
-        uid_length = m_strlen(uid->email);
-        if (1 && (uid->email[0] == '<')
-            && (uid->email[uid_length - 1] == '>')
-            && (uid_length == sender_length + 2)
-            && (!m_strncmp (uid->email + 1, sender->mailbox, sender_length)))
-          ret = 0;
-      }
-    }
-    else
-      mutt_any_key_to_continue ("Failed to verify sender");
-  }
-  else
-    mutt_any_key_to_continue ("Failed to figure out sender");
-
-  if (signature_key) {
-    gpgme_key_release (signature_key);
-    signature_key = NULL;
-  }
-
-  return ret;
-}
-
-void crypt_invoke_import(FILE *stream, int smime)
-{
-    gpgme_ctx_t ctx = create_gpgme_context(smime);
-    gpgme_data_t data;
-    gpgme_error_t err;
-
-    err = gpgme_data_new_from_stream(&data, stream);
-    if (err) {
-        mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
-        gpgme_release(ctx);
-        return;
-    }
-
-    err = gpgme_op_import(ctx, data);
-    if (err) {
-        mutt_error(_("error importing gpg data: %s\n"), gpgme_strerror(err));
-        gpgme_data_release(data);
-        gpgme_release(ctx);
-        return;
-    }
-
-    gpgme_data_release(data);
-    gpgme_release(ctx);
-    return;
-}
-
-static void pgp_extract_keys_from_attachment(FILE * fp, BODY * top)
-{
-    STATE s;
-    FILE *tmpfp = tmpfile();
-
-    if (tmpfp == NULL) {
-        mutt_perror (_("Can't create temporary file"));
-        return;
-    }
-
-    p_clear(&s, 1);
-    s.fpin  = fp;
-    s.fpout = tmpfp;
-    mutt_body_handler(top, &s);
-
-    rewind(tmpfp);
-    crypt_invoke_import(tmpfp, 0);
-    m_fclose(&tmpfp);
-}
-
-void crypt_pgp_extract_keys_from_attachment_list(FILE * fp, int tag, BODY * top)
-{
-  mutt_endwin (NULL);
-  set_option (OPTDONTHANDLEPGPKEYS);
-
-  for (; top; top = top->next) {
-    if (!tag || top->tagged)
-      pgp_extract_keys_from_attachment (fp, top);
-
-    if (!tag)
-      break;
-  }
-
-  unset_option (OPTDONTHANDLEPGPKEYS);
-}
-
-
-/* TODO */
-
-/* fixme: needs documentation. */
-void crypt_pgp_invoke_getkeys (address_t * addr)
-{
-}
-
-/* Generate a PGP public key attachment. */
-BODY *crypt_pgp_make_key_attachment (char *tempf)
-{
-    return NULL;
-}
-
-/* S/MIME */
-
-/* fixme: Needs documentation. */
-void crypt_smime_getkeys (ENVELOPE * env)
-{
-}
-