various rewrites and cleanups.
authorPierre Habouzit <madcoder@debian.org>
Fri, 6 Apr 2007 23:10:44 +0000 (01:10 +0200)
committerPierre Habouzit <madcoder@debian.org>
Fri, 6 Apr 2007 23:10:44 +0000 (01:10 +0200)
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
compose.c
crypt.c
init.h
lib-lib/array.h
lib-ui/enter.c
mutt.h

index 4d4cc8b..72e6737 100644 (file)
--- a/compose.c
+++ b/compose.c
@@ -1252,7 +1252,7 @@ int mutt_compose_menu (HEADER * msg,    /* structure for new message */
         }
         msg->security = 0;
       }
-      msg->security = crypt_send_menu (msg, &menu->redraw, 1);
+      msg->security = crypt_send_menu(msg, &menu->redraw, 1);
       redraw_crypt_lines (msg);
       mutt_message_hook (NULL, msg, M_SEND2HOOK);
       break;
diff --git a/crypt.c b/crypt.c
index bf8c81d..ba50f4a 100644 (file)
--- a/crypt.c
+++ b/crypt.c
 #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;
+    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 cryptkey_t {
+    struct cryptkey_t *next;
+    int idx;                      /* and the user ID at this index */
+    int flags;                    /* global and per uid flags (for convenience) */
+    gpgme_key_t kobj;
+    const char *uid;              /* and for convenience point to this user ID */
+} cryptkey_t;
+
+DO_INIT(cryptkey_t, cryptkey);
+static void cryptkey_wipe(cryptkey_t *key) {
+    gpgme_key_release(key->kobj);
+}
+DO_NEW(cryptkey_t, cryptkey);
+DO_DELETE(cryptkey_t, cryptkey);
+DO_SLIST(cryptkey_t, key, cryptkey_delete);
+
+static cryptkey_t *cryptkey_dup(const cryptkey_t *k)
+{
+    cryptkey_t *res = cryptkey_new();
+    *res = *k;
+    res->next = NULL;
+    gpgme_key_ref(k->kobj);
+    return res;
+}
 
 typedef struct crypt_entry {
-  ssize_t num;
-  crypt_key_t *key;
+    ssize_t num;
+    cryptkey_t *key;
 } crypt_entry_t;
 
-
-static struct crypt_cache *id_defaults = NULL;
 static gpgme_key_t signature_key = NULL;
 
-/*
- * General helper functions.
- */
-
 static void convert_to_7bit (BODY * a)
 {
-  while (a) {
-    if (a->type == TYPEMULTIPART) {
-      if (a->encoding != ENC7BIT) {
-        a->encoding = ENC7BIT;
-        convert_to_7bit (a->parts);
-      } else {
-        convert_to_7bit (a->parts);
-      }
-    }
-    else if (a->type == TYPEMESSAGE &&
-             m_strcasecmp(a->subtype, "delivery-status")) {
-      if (a->encoding != ENC7BIT)
-        mutt_message_to_7bit (a, NULL);
+    for (; a; a = a->next) {
+        int tok = mime_which_token(a->subtype, -1);
+
+        if (a->type == TYPEMULTIPART) {
+            a->encoding = ENC7BIT;
+            convert_to_7bit(a->parts);
+        } else if (a->type == TYPEMESSAGE && tok == MIME_DELIVERY_STATUS) {
+            if (a->encoding != ENC7BIT)
+                mutt_message_to_7bit(a, NULL);
+        } else if (a->encoding == ENC8BIT) {
+            a->encoding = ENCQUOTEDPRINTABLE;
+        } else if (a->encoding == ENCBINARY) {
+            a->encoding = ENCBASE64;
+        } else if (a->content && a->encoding != ENCBASE64
+               && (a->content->from || a->content->space))
+        {
+            a->encoding = ENCQUOTEDPRINTABLE;
+        }
     }
-    else if (a->encoding == ENC8BIT)
-      a->encoding = ENCQUOTEDPRINTABLE;
-    else if (a->encoding == ENCBINARY)
-      a->encoding = ENCBASE64;
-    else if (a->content && a->encoding != ENCBASE64 &&
-             (a->content->from || a->content->space))
-      a->encoding = ENCQUOTEDPRINTABLE;
-    a = a->next;
-  }
 }
 
 /* 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;
+    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);
+    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)
+static const char *crypt_keyid (cryptkey_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;
-  }
+    if (k->kobj && k->kobj->subkeys) {
+        const char *s = k->kobj->subkeys->keyid;
+        return m_strlen(s) == 16 ? s + 8 : s;
+    }
 
-  return s;
+    return "????????";
 }
 
 /* Return the hexstring fingerprint from the key K. */
-static const char *crypt_fpr (crypt_key_t * k)
+static const char *crypt_fpr (cryptkey_t * k)
 {
-  const char *s = "";
-
-  if (k->kobj && k->kobj->subkeys)
-    s = k->kobj->subkeys->fpr;
-
-  return s;
+    return k->kobj && k->kobj->subkeys ? k->kobj->subkeys->fpr : "";
 }
 
 /* Parse FLAGS and return a statically allocated(!) string with them. */
@@ -185,301 +168,240 @@ static char crypt_flags (int flags)
     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)
+static int crypt_id_is_strong (cryptkey_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;
+    gpgme_user_id_t uid;
+    int i;
 
-  case GPGME_VALIDITY_FULL:
-  case GPGME_VALIDITY_ULTIMATE:
-    is_strong = 1;
-    break;
-  }
+    if (key->flags & KEYFLAG_ISX509)
+        return 1;
 
-  return is_strong;
-}
+    for (i = 0, uid = key->kobj->uids; uid; i++, uid = uid->next) {
+        if (i == key->idx) {
+            return uid->validity == GPGME_VALIDITY_FULL
+                || uid->validity == GPGME_VALIDITY_ULTIMATE;
+        }
+    }
 
-/* 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 0;
 }
 
 /* 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)
+static int
+crypt_id_matches_addr(address_t *addr, address_t *u_addr, cryptkey_t *key)
 {
-  int rv = 0;
+    int rv = 0;
 
-  if (crypt_id_is_valid (key))
-    rv |= CRYPT_KV_VALID;
+    if (!(key->flags & KEYFLAG_CANTUSE))
+        rv |= CRYPT_KV_VALID;
 
-  if (crypt_id_is_strong (key))
-    rv |= CRYPT_KV_STRONGID;
+    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->mailbox && !m_strcasecmp(addr->mailbox, u_addr->mailbox))
+        rv |= CRYPT_KV_ADDR;
 
-  if (addr->personal && u_addr->personal
-      && m_strcasecmp(addr->personal, u_addr->personal) == 0)
-    rv |= CRYPT_KV_STRING;
+    if (addr->personal && m_strcasecmp(addr->personal, u_addr->personal))
+        rv |= CRYPT_KV_STRING;
 
-  return rv;
+    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)
+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);
-  }
+    gpgme_error_t err;
+    gpgme_ctx_t ctx;
 
-  if (for_smime) {
-    err = gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
+    err = gpgme_new (&ctx);
     if (err) {
-      mutt_error (_("error enabling CMS protocol: %s\n"), gpgme_strerror (err));
-      sleep (2);
-      mutt_exit (1);
+        mutt_error(_("error creating gpgme context: %s\n"),
+                   gpgme_strerror(err));
+        sleep(2);
+        mutt_exit(1);
     }
-  }
+    if (!for_smime)
+        return ctx;
 
-  return ctx;
+    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)
+static gpgme_data_t create_gpgme_data(void)
 {
-  gpgme_error_t err;
-  gpgme_data_t data;
+    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;
+    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)
+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;
+    gpgme_data_t data;
+    int err = 0;
+    FILE *fptmp = tmpfile();
 
-  fptmp = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
-  if (!fptmp) {
-    mutt_perror (_("Can't create temporary file"));
-    return 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);
+    mutt_write_mime_header(a, fptmp);
+    fputc('\n', fptmp);
+    mutt_write_mime_body(a, fptmp);
+    rewind(fptmp);
 
-  if (convert) {
-    int c, hadcr = 0;
-    unsigned char buf[1];
+    if (convert) {
+        char buf[STRING];
+        int spare = 0;
 
-    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);
-        }
+        data = create_gpgme_data();
+        while (fgets(buf + spare, sizeof(buf) - 1, fptmp)) {
+            int l = m_strlen(buf);
 
-        hadcr = 0;
-      }
-      /* FIXME: This is quite suboptimal */
-      buf[0] = c;
-      gpgme_data_write (data, buf, 1);
+            spare = buf[l - 1] != '\n';
+            if (!spare) {
+                if (l > 2 && buf[l - 2] == '\r') {
+                    buf[l - 2] = '\n';
+                    l--;
+                }
+            }
+            gpgme_data_write(data, buf, l - spare);
+            if (spare)
+                buf[0] = buf[l - 1];
+        }
+        if (spare)
+            gpgme_data_write(data, buf, 1);
+        gpgme_data_seek(data, 0, SEEK_SET);
+    } else {
+        err = gpgme_data_new_from_stream(&data, fptmp);
+    }
+    m_fclose(&fptmp);
+    if (err) {
+        mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err));
+        return NULL;
     }
-    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;
+    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)
+static gpgme_data_t file_to_data_object(FILE *fp, long offset, long length)
 {
-  int err = 0;
-  gpgme_data_t data;
+    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;
-  }
+    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;
+    return data;
 }
 
 /* Write a GPGME data object to the stream FP. */
-static int data_object_to_stream (gpgme_data_t data, FILE * 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;
-  }
+    int err;
+    char buf[4096], *p;
+    ssize_t nread;
 
-  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);
+    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;
     }
 
-    if (ferror (fp)) {
-      mutt_perror ("[tempfile]");
-      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;
+    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)
+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;
+    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;
-  }
+    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];
+    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;
+            }
+        }
+    }
 
-    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);
+    if (nread == -1) {
+        mutt_error (_("error reading data object: %s\n"), gpgme_strerror (err));
         unlink (tempfile);
+        m_fclose(&fp);
         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);
+    if (ret_fp) {
+        rewind(fp);
+        *ret_fp = fp;
+    } else {
+        m_fclose(&fp);
+    }
+    return m_strdup(tempfile);
 }
 
 
@@ -512,8 +434,8 @@ gpgme_get_key2 (gpgme_ctx_t ctx, const char *fpr, gpgme_key_t *r_key,
 
 /* 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)
+static gpgme_key_t *
+create_recipient_set(const char *keylist, gpgme_protocol_t protocol)
 {
   int err;
   const char *s;
@@ -598,8 +520,8 @@ static int set_signer (gpgme_ctx_t ctx, int for_smime)
   }
   err = gpgme_op_keylist_next (listctx, &key2);
   if (!err) {
-    gpgme_key_release (key);
-    gpgme_key_release (key2);
+    gpgme_key_unref(key);
+    gpgme_key_unref(key2);
     gpgme_release (listctx);
     mutt_error (_("ambiguous specification of secret key `%s'\n"), signid);
     return -1;
@@ -609,7 +531,7 @@ static int set_signer (gpgme_ctx_t ctx, int for_smime)
 
   gpgme_signers_clear (ctx);
   err = gpgme_signers_add (ctx, key);
-  gpgme_key_release (key);
+  gpgme_key_unref(key);
   if (err) {
     mutt_error (_("error setting secret key `%s': %s\n"),
                 signid, gpgme_strerror (err));
@@ -710,7 +632,7 @@ static void print_time (time_t t, STATE * s)
 /* 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)
+static BODY *sign_message(BODY * a, int use_smime)
 {
   BODY *t;
   char *sigfile;
@@ -721,7 +643,7 @@ static BODY *sign_message (BODY * a, int use_smime)
 
   convert_to_7bit (a);          /* Signed data _must_ be in 7-bit format. */
 
-  message = body_to_data_object (a, 1);
+  message = body_to_data_object(a, 1);
   if (!message)
     return NULL;
   signature = create_gpgme_data ();
@@ -798,10 +720,6 @@ static BODY *sign_message (BODY * a, int use_smime)
   return a;
 }
 
-/*
- * 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.  */
 static BODY *crypt_pgp_encrypt_message (BODY * a, char *keylist, int sign)
@@ -817,7 +735,7 @@ static BODY *crypt_pgp_encrypt_message (BODY * a, char *keylist, int sign)
 
   if (sign)
     convert_to_7bit (a);
-  plaintext = body_to_data_object (a, 0);
+  plaintext = body_to_data_object(a, 0);
   if (!plaintext) {
     p_delete(&rset);
     return NULL;
@@ -852,16 +770,11 @@ static BODY *crypt_pgp_encrypt_message (BODY * a, char *keylist, int sign)
   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 */
+  t->parts->next->d_filename = m_strdup("msg.asc");
 
   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.  */
 static BODY *crypt_smime_build_smime_entity (BODY * a, char *keylist)
@@ -875,7 +788,7 @@ static BODY *crypt_smime_build_smime_entity (BODY * a, char *keylist)
   if (!rset)
     return NULL;
 
-  plaintext = body_to_data_object (a, 0);
+  plaintext = body_to_data_object(a, 0);
   if (!plaintext) {
     p_delete(&rset);
     return NULL;
@@ -904,9 +817,6 @@ static BODY *crypt_smime_build_smime_entity (BODY * a, char *keylist)
   return t;
 }
 
-
-/* Implementation of `verify_one'. */
-
 /* Display the common attributes of the signature summary SUM.
    Return 1 if there is is a severe warning.
  */
@@ -1116,7 +1026,7 @@ static int show_one_sig_status (gpgme_ctx_t ctx, int idx, STATE * s)
       return -1;                /* Signature not found.  */
 
     if (signature_key) {
-      gpgme_key_release (signature_key);
+      gpgme_key_unref(signature_key);
       signature_key = NULL;
     }
 
@@ -1196,7 +1106,7 @@ static int show_one_sig_status (gpgme_ctx_t ctx, int idx, STATE * s)
     }
 
     if (key != signature_key)
-      gpgme_key_release (key);
+      gpgme_key_unref(key);
   }
 
   return anybad ? 1 : anywarn ? 2 : 0;
@@ -1248,7 +1158,7 @@ static int crypt_verify_one(BODY *sigbdy, STATE *s, FILE *fp, int is_smime)
     int anybad = 0;
 
     if (signature_key) {
-      gpgme_key_release (signature_key);
+      gpgme_key_unref(signature_key);
       signature_key = NULL;
     }
 
@@ -1301,18 +1211,14 @@ static int crypt_verify_one(BODY *sigbdy, STATE *s, FILE *fp, int is_smime)
   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)
+static BODY *
+decrypt_part(BODY *a, STATE *s, FILE *fpout, int is_smime, int *r_is_signed)
 {
   struct stat info;
   BODY *tattach;
@@ -1479,8 +1385,7 @@ int crypt_pgp_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
 
 /* 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)
+int crypt_smime_decrypt_mime(FILE *fpin, FILE **fpout, BODY *b, BODY **cur)
 {
   char tempfile[_POSIX_PATH_MAX];
   STATE s;
@@ -1598,12 +1503,8 @@ int crypt_smime_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b,
 }
 
 
-/*
- * Implementation of `pgp_check_traditional'.
- */
-
-static int pgp_check_traditional_one_body (FILE * fp, BODY * b,
-                                           int tagged_only)
+static int
+pgp_check_traditional_one_body(FILE *fp, BODY *b, int tagged_only)
 {
   char tempfile[_POSIX_PATH_MAX];
   char buf[HUGE_STRING];
@@ -1652,7 +1553,7 @@ static int pgp_check_traditional_one_body (FILE * fp, BODY * b,
   return 1;
 }
 
-int crypt_pgp_check_traditional (FILE * fp, BODY * b, int tagged_only)
+int crypt_pgp_check_traditional(FILE *fp, BODY *b, int tagged_only)
 {
   int rv = 0;
   int r;
@@ -1670,9 +1571,6 @@ int crypt_pgp_check_traditional (FILE * fp, BODY * b, int tagged_only)
   return rv;
 }
 
-
-/* Implementation of `application_handler'. */
-
 /*
   Copy a clearsigned message, and strip the signature and PGP's
   dash-escaping.
@@ -1684,8 +1582,7 @@ int crypt_pgp_check_traditional (FILE * fp, BODY * b, int tagged_only)
   (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)
+static void copy_clearsigned(gpgme_data_t data, STATE * s, char *charset)
 {
   char buf[HUGE_STRING];
   short complete, armor_header;
@@ -1732,9 +1629,8 @@ static void copy_clearsigned (gpgme_data_t data, STATE * s, char *charset)
   m_fclose(&fp);
 }
 
-
 /* Support for classic_application/pgp */
-int crypt_pgp_application_pgp_handler (BODY * m, STATE * s)
+int crypt_pgp_application_pgp_handler(BODY *m, STATE *s)
 {
   int needpass = -1, pgp_keyblock = 0;
   int clearsign = 0;
@@ -1958,8 +1854,6 @@ int crypt_pgp_application_pgp_handler (BODY * m, STATE * s)
   return (err);
 }
 
-/* Implementation of `encrypted_handler'. */
-
 /* MIME handler for pgp/mime encrypted messages. */
 int crypt_pgp_encrypted_handler (BODY * a, STATE * s)
 {
@@ -2122,7 +2016,7 @@ crypt_entry_fmt (char *dest, ssize_t destlen, char op,
 {
   char fmt[16];
   crypt_entry_t *entry;
-  crypt_key_t *key;
+  cryptkey_t *key;
   int kflags = 0;
   int optional = (flags & M_FORMAT_OPTIONAL);
   const char *s = NULL;
@@ -2308,10 +2202,10 @@ crypt_entry_fmt (char *dest, ssize_t destlen, char op,
 /* 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;
+  cryptkey_t **cryptkey_table = (cryptkey_t **) menu->data;
   crypt_entry_t entry;
 
-  entry.key = key_table[num];
+  entry.key = cryptkey_table[num];
   entry.num = num + 1;
 
   m_strformat(s, l, COLS - SW, PgpEntryFormat, crypt_entry_fmt, &entry,
@@ -2321,8 +2215,8 @@ static void crypt_entry (char *s, ssize_t l, MUTTMENU * menu, int num)
 /* 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;
+  cryptkey_t **s = (cryptkey_t **) a;
+  cryptkey_t **t = (cryptkey_t **) b;
   int r;
 
   if ((r = m_strcasecmp((*s)->uid, (*t)->uid)))
@@ -2341,8 +2235,8 @@ static int crypt_compare_address (const void *a, const void *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;
+  cryptkey_t **s = (cryptkey_t **) a;
+  cryptkey_t **t = (cryptkey_t **) b;
   int r;
 
   if ((r = m_strcasecmp(crypt_keyid (*s), crypt_keyid (*t))))
@@ -2360,8 +2254,8 @@ static int crypt_compare_keyid (const void *a, const void *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;
+  cryptkey_t **s = (cryptkey_t **) a;
+  cryptkey_t **t = (cryptkey_t **) b;
   unsigned long ts = 0, tt = 0;
 
   if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
@@ -2387,8 +2281,8 @@ static int crypt_compare_date (const void *a, const void *b)
    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;
+  cryptkey_t **s = (cryptkey_t **) a;
+  cryptkey_t **t = (cryptkey_t **) b;
   unsigned long ts = 0, tt = 0;
   int r;
 
@@ -2649,12 +2543,12 @@ static void parse_and_print_user_id(FILE * fp, const char *userid)
 }
 
 typedef enum {
-  KEY_CAP_CAN_ENCRYPT,
-  KEY_CAP_CAN_SIGN,
-  KEY_CAP_CAN_CERTIFY
+    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)
+static unsigned int key_check_cap(gpgme_key_t key, key_cap_t cap)
 {
   gpgme_subkey_t subkey = NULL;
   unsigned int ret = 0;
@@ -2905,7 +2799,7 @@ static void print_key_info (gpgme_key_t key, FILE * fp)
 
 
 /* Show detailed information about the selected key */
-static void verify_key (crypt_key_t * key)
+static void verify_key (cryptkey_t * key)
 {
   FILE *fp;
   char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
@@ -2938,7 +2832,7 @@ static void verify_key (crypt_key_t * key)
   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);
+    gpgme_key_unref(k);
     k = NULL;
     if (!err)
       err = gpgme_op_keylist_next (listctx, &k);
@@ -2957,7 +2851,7 @@ static void verify_key (crypt_key_t * key)
   }
 
 leave:
-  gpgme_key_release (k);
+  gpgme_key_unref(k);
   gpgme_release (listctx);
   m_fclose(&fp);
   mutt_clear_error ();
@@ -2967,211 +2861,122 @@ leave:
 
 /* 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)
+static void add_hints(string_array *arr, const char *s)
 {
-  string_list_t *l;
-  char *pattern, *p;
-  const char *s;
-  ssize_t n;
+    if (!s)
+        return;
 
-  n = 0;
-  for (l = list; l; l = l->next) {
-    for (s = l->data; *s; s++) {
-      if (*s == '%')
-        n += 2;
-      n++;
+    while (*s) {
+        int l = strcspn(s, " ,.:\"()<>\n");
+        string_array_append(arr, p_dupstr(s, l));
+        s += l;
+        s += strspn(s, " ,.:\"()<>\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)
+/* Return a list of keys which are candidates for the selection. */
+static cryptkey_t *
+get_candidates(string_array *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;
+    cryptkey_t  *res = NULL, **kend = &res;
+    gpgme_error_t err;
+    gpgme_ctx_t   ctx;
+    gpgme_key_t   key;
 
-    for (l = hints, n = 0; l; l = l->next) {
-      if (l->data && *l->data)
-        n++;
-    }
-    if (!n)
-      goto no_pgphints;
+    if (hints->len <= 0)
+        return NULL;
+    string_array_append(hints, NULL);
+    ctx = create_gpgme_context(0);
 
-    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;
-    }
+    if ((app & APPLICATION_PGP)) {
+        err = gpgme_op_keylist_ext_start(ctx, (const char **)hints->arr,
+                                         secret, 0);
+        if (err) {
+            mutt_error(_("gpgme_op_keylist_start failed: %s"),
+                       gpgme_strerror(err));
+            gpgme_release(ctx);
+            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;
-      }
+        while (!(err = gpgme_op_keylist_next(ctx, &key))) {
+            gpgme_user_id_t uid = NULL;
+            unsigned int flags = 0;
+            int idx;
+
+            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) {
+                cryptkey_t *k = p_new(cryptkey_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);
     }
-    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;
-    }
+    if ((app & APPLICATION_SMIME)) {
+        gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS);
+        err = gpgme_op_keylist_ext_start(ctx, (const char **)hints->arr,
+                                         secret, 0);
+        if (err) {
+            mutt_error(_("gpgme_op_keylist_start failed: %s"),
+                       gpgme_strerror(err));
+            gpgme_release(ctx);
+            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;
-      }
+        while (!(err = gpgme_op_keylist_next(ctx, &key))) {
+            gpgme_user_id_t uid = NULL;
+            unsigned int flags = KEYFLAG_ISX509;
+            int idx;
+
+            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) {
+                cryptkey_t *k = p_new(cryptkey_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);
     }
-    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;
+    gpgme_release(ctx);
+    return res;
 }
 
 /* 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,
+static cryptkey_t *crypt_select_key (cryptkey_t * keys,
                                       address_t * p, const char *s,
                                       unsigned int app, int *forced_valid)
 {
   int keymax;
-  crypt_key_t **key_table;
+  cryptkey_t **cryptkey_table;
   MUTTMENU *menu;
   int i, done = 0;
   char helpstr[STRING], buf[LONG_STRING];
-  crypt_key_t *k;
+  cryptkey_t *k;
   int (*f) (const void *, const void *);
   int menu_to_use = 0;
   int unusable = 0;
@@ -3180,7 +2985,7 @@ static crypt_key_t *crypt_select_key (crypt_key_t * keys,
 
   /* build the key table */
   keymax = i = 0;
-  key_table = NULL;
+  cryptkey_table = NULL;
   for (k = keys; k; k = k->next) {
       if (!option (OPTPGPSHOWUNUSABLE) && (k->flags & KEYFLAG_CANTUSE)) {
           unusable = 1;
@@ -3189,10 +2994,10 @@ static crypt_key_t *crypt_select_key (crypt_key_t * keys,
 
       if (i == keymax) {
           keymax += 20;
-          p_realloc(&key_table, keymax);
+          p_realloc(&cryptkey_table, keymax);
       }
 
-      key_table[i++] = k;
+      cryptkey_table[i++] = k;
   }
 
   if (!i && unusable) {
@@ -3217,7 +3022,7 @@ static crypt_key_t *crypt_select_key (crypt_key_t * keys,
       f = crypt_compare_trust;
       break;
   }
-  qsort (key_table, i, sizeof (crypt_key_t *), f);
+  qsort (cryptkey_table, i, sizeof (cryptkey_t *), f);
 
   if (app & APPLICATION_PGP)
       menu_to_use = MENU_KEY_SELECT_PGP;
@@ -3241,7 +3046,7 @@ static crypt_key_t *crypt_select_key (crypt_key_t * keys,
   menu->make_entry = crypt_entry;
   menu->menu = menu_to_use;
   menu->help = helpstr;
-  menu->data = key_table;
+  menu->data = cryptkey_table;
 
   {
       const char *ts;
@@ -3268,32 +3073,32 @@ static crypt_key_t *crypt_select_key (crypt_key_t * keys,
       *forced_valid = 0;
       switch (mutt_menuLoop (menu)) {
         case OP_VERIFY_KEY:
-          verify_key (key_table[menu->current]);
+          verify_key (cryptkey_table[menu->current]);
           menu->redraw = REDRAW_FULL;
           break;
 
         case OP_VIEW_ID:
-          mutt_message ("%s", key_table[menu->current]->uid);
+          mutt_message ("%s", cryptkey_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.");
+              if (cryptkey_table[menu->current]->flags & KEYFLAG_CANTUSE ) {
+                  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]))) {
+              ((cryptkey_table[menu->current]->flags & KEYFLAG_CANTUSE)
+               || !crypt_id_is_strong (cryptkey_table[menu->current]))) {
               const char *warn_s;
               char buff[LONG_STRING];
 
-              if (key_table[menu->current]->flags & KEYFLAG_CANTUSE)
+              if (cryptkey_table[menu->current]->flags & KEYFLAG_CANTUSE)
                   s = N_("ID is expired/disabled/revoked.");
               else {
                   gpgme_validity_t val = GPGME_VALIDITY_UNKNOWN;
@@ -3302,8 +3107,8 @@ static crypt_key_t *crypt_select_key (crypt_key_t * keys,
 
                   warn_s = "??";
 
-                  uid = key_table[menu->current]->kobj->uids;
-                  for (j = 0; (j < key_table[menu->current]->idx) && uid;
+                  uid = cryptkey_table[menu->current]->kobj->uids;
+                  for (j = 0; (j < cryptkey_table[menu->current]->idx) && uid;
                        j++, uid = uid->next);
                   if (uid)
                       val = uid->validity;
@@ -3335,7 +3140,7 @@ static crypt_key_t *crypt_select_key (crypt_key_t * keys,
               }
           }
 
-          k = crypt_copy_key (key_table[menu->current]);
+          k = cryptkey_dup(cryptkey_table[menu->current]);
           done = 1;
           break;
 
@@ -3347,18 +3152,17 @@ static crypt_key_t *crypt_select_key (crypt_key_t * keys,
   }
 
   mutt_menuDestroy (&menu);
-  p_delete(&key_table);
+  p_delete(&cryptkey_table);
 
   set_option (OPTNEEDREDRAW);
 
   return k;
 }
 
-static crypt_key_t *crypt_getkeybyaddr (address_t * a, short abilities,
+static cryptkey_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;
@@ -3368,22 +3172,23 @@ static crypt_key_t *crypt_getkeybyaddr (address_t * a, short abilities,
     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;
+    cryptkey_t *keys, *k;
+    cryptkey_t *the_valid_key = NULL;
+    cryptkey_t *matches = NULL;
+    cryptkey_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_array hints;
+        string_array_init(&hints); 
+        add_hints(&hints, a->mailbox);
+        add_hints(&hints, a->personal);
 
-    string_list_wipe(&hints);
+        mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
+        keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
+        string_array_wipe(&hints);
+    }
 
     if (!keys)
         return NULL;
@@ -3425,20 +3230,19 @@ static crypt_key_t *crypt_getkeybyaddr (address_t * a, short abilities,
         address_list_wipe(&r);
 
         if (match) {
-            crypt_key_t *tmp;
+            cryptkey_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 = cryptkey_dup(k);
             matches_endp = &tmp->next;
             the_valid_key = tmp;
         }
     }
-
-    crypt_free_key (&keys);
+    key_list_wipe(&keys);
 
     if (matches) {
         if (the_valid_key && !multi && !weak
@@ -3450,383 +3254,328 @@ static crypt_key_t *crypt_getkeybyaddr (address_t * a, short abilities,
        *
        * Proceed without asking the user.
        */
-      k = crypt_copy_key (the_valid_key);
-    }
-    else {
+      k = cryptkey_dup(the_valid_key);
+    } else {
       /*
        * Else: Ask the user.
        */
       k = crypt_select_key (matches, a, NULL, app, forced_valid);
     }
-    crypt_free_key (&matches);
-  }
-  else
+    key_list_wipe(&matches);
+  } else {
     k = NULL;
+  }
 
   return k;
 }
 
 
-static crypt_key_t *crypt_getkeybystr (const char *p, short abilities,
+static cryptkey_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;
+  cryptkey_t *keys;
+  cryptkey_t *matches = NULL;
+  cryptkey_t **matches_endp = &matches;
+  cryptkey_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);
+  {
+      string_array hints;
+      string_array_init(&hints);
+      add_hints(&hints, p);
+      keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
+      string_array_wipe(&hints);
+  }
 
   if (!keys)
     return NULL;
 
   for (k = keys; k; k = k->next) {
+    const char *s = crypt_keyid(k);
+
     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;
+    if (!*p || !m_strcasecmp(p, s)
+        || (!m_strncasecmp(p, "0x", 2) && !m_strcasecmp(p + 2, s))
+        || m_stristr(k->uid, p))
+    {
+      cryptkey_t *tmp;
 
-      *matches_endp = tmp = crypt_copy_key (k);
+      *matches_endp = tmp = cryptkey_dup(k);
       matches_endp = &tmp->next;
     }
   }
-
-  crypt_free_key (&keys);
+  key_list_wipe(&keys);
 
   if (matches) {
     k = crypt_select_key (matches, NULL, p, app, forced_valid);
-    crypt_free_key (&matches);
+    key_list_wipe(&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)
+/* Display TAG as a prompt to ask for a key.
+ * 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 cryptkey_t *
+crypt_ask_for_key(const char *tag, int abilities, int app, int *forced_valid)
 {
-  crypt_key_t *key;
-  char resp[STRING];
-  struct crypt_cache *l = NULL;
-  int dummy;
+    cryptkey_t *key;
+    char resp[STRING];
+    int dummy;
 
-  if (!forced_valid)
-    forced_valid = &dummy;
+    if (!forced_valid)
+        forced_valid = &dummy;
+    *forced_valid = 0;
 
-  mutt_clear_error ();
+    mutt_clear_error();
+    for (;;) {
+        resp[0] = 0;
+        if (mutt_get_field(tag, resp, sizeof(resp), M_CLEAR) != 0)
+            return NULL;
 
-  *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;
-      }
-  }
+        if (m_strisempty(resp))
+            return NULL;
 
-  for (;;) {
-    resp[0] = 0;
-    if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0)
-      return NULL;
+        if ((key = crypt_getkeybystr(resp, abilities, app, forced_valid)))
+            return key;
 
-    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);
-      }
+        BEEP ();
     }
-
-    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)
+static char *find_keys(ENVELOPE *env, 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);
+    address_t *lst = NULL, *addr;
+    buffer_t *keylist = buffer_new();
 
-#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;
+    {
+        address_t **last = &lst;
+        *last = address_list_dup(env->to);
+        last  = address_list_last(last);
+        *last = address_list_dup(env->cc);
+        last  = address_list_last(last);
+        *last = address_list_dup(env->bcc);
+
+        rfc822_qualify(lst, mutt_fqdn(1));
+        address_list_uniq(lst);
+    }
+
+    while ((addr = address_list_pop(&lst))) {
+        char buf[STRING];
+        int forced_valid = 0;
+        const char *keyID;
+        cryptkey_t *key = NULL;
+
+        if ((keyID = mutt_crypt_hook(addr))) {
+            int r;
+
+            snprintf(buf, sizeof(buf), _("Use keyID = \"%s\" for %s?"), keyID,
+                     addr->mailbox);
+            r = mutt_yesorno(buf, M_YES);
+
+            if (r == -1) {
+                address_list_wipe(&lst);
+                address_list_wipe(&addr);
+                buffer_delete(&keylist);
+                return NULL;
+            }
 
-    if ((keyID = mutt_crypt_hook (p)) != NULL) {
-      int r;
+            if (r == M_YES) {
+                address_t *a;
+                /* check for e-mail address */
+                if (strchr(keyID, '@') && (a = rfc822_parse_adrlist(NULL, keyID))) {
+                    rfc822_qualify(a, mutt_fqdn(1));
+                    address_list_wipe(&addr);
+                    addr = a;
+                } else {
+                    key = crypt_getkeybystr(keyID, KEYFLAG_CANENCRYPT, app,
+                                            &forced_valid);
+                }
+            }
+        }
 
-      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;
+        if (!key) {
+            key = crypt_getkeybyaddr(addr, KEYFLAG_CANENCRYPT, app, &forced_valid);
         }
-        else {
-          k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
-                                      app, &forced_valid);
+        if (!key) {
+            snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), addr->mailbox);
+            key = crypt_ask_for_key(buf, KEYFLAG_CANENCRYPT, app,
+                                    &forced_valid);
+            if (!key) {
+                address_list_wipe(&lst);
+                address_list_wipe(&addr);
+                buffer_delete(&keylist);
+                return NULL;
+            }
         }
-      }
-      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 (keylist->len)
+            buffer_addch(keylist, ' ');
+        buffer_addstr(keylist, "0x");
+        buffer_addstr(keylist, crypt_fpr(key));
+        if (forced_valid)
+            buffer_addch(keylist, '!');
 
-      if ((key = crypt_ask_for_key (buf, q->mailbox, KEYFLAG_CANENCRYPT, app,
-                                    &forced_valid)) == NULL)
-      {
-        p_delete(&keylist);
-        address_list_wipe(&tmp);
+        key_list_wipe(&key);
         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);
+    address_list_wipe(&lst);
+    return buffer_unwrap(&keylist);
 }
 
-int crypt_get_keys (HEADER * msg, char **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.
-   */
+    /* 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;
+    *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 & ENCRYPT) {
+        if (msg->security & APPLICATION_PGP) {
+            set_option(OPTPGPCHECKTRUST);
+            *keylist = find_keys(msg->env, 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;
+        if (msg->security & APPLICATION_SMIME) {
+            *keylist = find_keys(msg->env, APPLICATION_SMIME);
+            if (!*keylist)
+                return -1;
+        }
     }
-  }
 
-  return (0);
+    return 0;
 }
 
 
 int crypt_send_menu (HEADER * msg, int *redraw, int is_smime)
 {
-  crypt_key_t *p;
-  char input_signas[STRING];
-  int choice;
+    cryptkey_t *p;
+    char buf[STRING];
+    int choice;
+
+    if (msg->security & APPLICATION_SMIME)
+        is_smime = 1;
+    if (msg->security & APPLICATION_PGP)
+        is_smime = 0;
+
+    choice = is_smime
+        ? mutt_multi_choice(_("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?"),
+                            _("esabpc"))
+        : 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;
 
-  if (msg->security & APPLICATION_PGP)
-    is_smime = 0;
-  else if (msg->security & APPLICATION_SMIME)
-    is_smime = 1;
+      case 2:                      /* (s)ign */
+        msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
+        msg->security &= ~(is_smime ? SMIMEENCRYPT : PGPENCRYPT);
+        break;
 
-  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 3:                      /* sign (a)s */
+        p = crypt_ask_for_key(_("Sign as: "), KEYFLAG_CANSIGN,
+                              is_smime ?  APPLICATION_SMIME : APPLICATION_PGP,
+                              NULL);
+        if (p) {
+            snprintf(buf, sizeof(buf), "0x%s", crypt_keyid(p));
+            m_strreplace(is_smime ? &SmimeDefaultKey : &PgpSignAs, buf);
+            key_list_wipe(&p);
+            msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
+        }
+        *redraw = REDRAW_FULL;
+        break;
 
-  case 2:                      /* (s)ign */
-    msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
-    msg->security &= ~(is_smime ? SMIMEENCRYPT : PGPENCRYPT);
-    break;
+      case 4:                      /* (b)oth */
+        if (is_smime) {
+            msg->security = SMIMEENCRYPT | SMIMESIGN;
+        } else {
+            msg->security = PGPENCRYPT | PGPSIGN;
+        }
+        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);
+      case 5:                      /* (p)gp or s/(m)ime */
+        is_smime = !is_smime;
+        break;
 
-      msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
+      case 6:                      /* (c)lear */
+        return msg->security = 0;
     }
-    *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;
-  }
+    if (is_smime) {
+        msg->security &= ~APPLICATION_PGP;
+        msg->security |= APPLICATION_SMIME;
+    } else {
+        msg->security &= ~APPLICATION_SMIME;
+        msg->security |= APPLICATION_PGP;
+    }
 
-  return msg->security;
+    return msg->security;
 }
 
-int crypt_smime_verify_sender (HEADER * h)
+int crypt_smime_verify_sender(HEADER *h)
 {
-  address_t *sender = NULL;
-  unsigned int ret = 1;
+    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 (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;
-      }
+    if (!sender) {
+        mutt_any_key_to_continue ("Failed to figure out sender");
+        goto end;
     }
-    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;
-  }
+    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");
+    }
 
-  return ret;
+  end:
+    if (signature_key) {
+        gpgme_key_unref(signature_key);
+        signature_key = NULL;
+    }
+    return ret;
 }
 
 static void crypt_invoke_import(FILE *stream, int smime)
diff --git a/init.h b/init.h
index 046fecd..1dac55d 100644 (file)
--- a/init.h
+++ b/init.h
@@ -1652,12 +1652,6 @@ struct option_t MuttVars[] = {
    ** .pp
    ** (PGP only)
    */
-  {"pgp_long_ids", DT_BOOL, R_NONE, OPTPGPLONGIDS, "no" },
-  /*
-   ** .pp
-   ** If \fIset\fP, use 64 bit PGP key IDs. \fIUnset\fP uses the normal 32 bit Key IDs.
-   ** (PGP only)
-   */
   {"pgp_retainable_sigs", DT_BOOL, R_NONE, OPTPGPRETAINABLESIG, "no" },
   /*
    ** .pp
index f0f6c9c..dd23a35 100644 (file)
@@ -35,7 +35,7 @@
     static inline void                                                        \
     prefix##_array_wipe(prefix##_array *array) {                              \
         while (array->len) {                                                  \
-            (dtor)(&array->arr[--array->len]);                                \
+            dtor(&array->arr[--array->len]);                                  \
         }                                                                     \
         p_delete(&array->arr);                                                \
     }                                                                         \
@@ -57,4 +57,7 @@ DO_ARRAY_TYPE(void, _);
 void __array_insert(__array *array, ssize_t pos, void *item);
 void *__array_take(__array *array, ssize_t pos);
 
+DO_ARRAY_TYPE(char *, string);
+DO_ARRAY_FUNCS(char *, string, p_delete);
+
 #endif /* MUTT_LIB_LIB_ARRAY_H */
index d42c855..0d61f2d 100644 (file)
@@ -177,7 +177,7 @@ int mutt_enter_string (char *buf, size_t buflen, int y, int x, int flags)
   int rv;
   ENTER_STATE *es = mutt_new_enter_state ();
 
-  rv = _mutt_enter_string (buf, buflen, y, x, flags, 0, NULL, NULL, es);
+  rv = _mutt_enter_string(buf, buflen, y, x, flags, 0, NULL, NULL, es);
   mutt_free_enter_state (&es);
   return rv;
 }
diff --git a/mutt.h b/mutt.h
index 43d7ffb..1ee8fb4 100644 (file)
--- a/mutt.h
+++ b/mutt.h
@@ -341,7 +341,6 @@ enum {
   OPTCRYPTREPLYSIGN,
   OPTCRYPTREPLYSIGNENCRYPTED,
   OPTSMIMEISDEFAULT,
-  OPTPGPLONGIDS,
   OPTPGPAUTODEC,
   OPTPGPRETAINABLESIG,
   OPTFORWDECRYPT,