spaces
[apps/madmutt.git] / lib-crypt / crypt-gpgme.c
index 3afaea0..c6142af 100644 (file)
  * please see the file GPL in the top level source directory.
  */
 
-#if HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#ifdef CRYPT_BACKEND_GPGME
-
-#include <sys/wait.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <ctype.h>
+#include <lib-lib/lib-lib.h>
 
 #ifdef HAVE_LOCALE_H
 #  include <locale.h>
 #ifdef HAVE_LANGINFO_D_T_FMT
 #  include <langinfo.h>
 #endif
-#ifdef HAVE_SYS_TIME_H
-#  include <sys/time.h>
-#endif
 #ifdef HAVE_SYS_RESOURCE_H
 #  include <sys/resource.h>
 #endif
 
 #include <gpgme.h>
 
-#include <lib-lib/mem.h>
-#include <lib-lib/str.h>
-#include <lib-lib/ascii.h>
-#include <lib-lib/macros.h>
-#include <lib-lib/file.h>
-
 #include <lib-mime/mime.h>
-
 #include <lib-ui/curses.h>
 #include <lib-ui/enter.h>
 #include <lib-ui/menu.h>
 
-#include "mutt.h"
+#include "crypt.h"
+
 #include "lib.h"
 #include "alias.h"
-#include <lib-crypt/crypt.h>
 #include "handler.h"
 #include "copy.h"
 #include "pager.h"
 #include "recvattach.h"
 #include "sort.h"
 
-/*
- * Helper macros.
- */
-#define digitp(p)   (*(p) >= '0' && *(p) <= '9')
-#define hexdigitp(a) (digitp (a)                     \
-                      || (*(a) >= 'A' && *(a) <= 'F')  \
-                      || (*(a) >= 'a' && *(a) <= 'f'))
-#define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
-                     *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
-#define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
-
 /* Values used for comparing addresses. */
 #define CRYPT_KV_VALID    1
 #define CRYPT_KV_ADDR     2
@@ -115,6 +82,17 @@ typedef struct crypt_entry {
 static struct crypt_cache *id_defaults = NULL;
 static gpgme_key_t signature_key = NULL;
 
+/* Show a message that a backend will be invoked. */
+void crypt_invoke_message (int type)
+{
+    if (type & APPLICATION_PGP) {
+        mutt_message _("Invoking PGP...");
+    }
+    else if (type & APPLICATION_SMIME) {
+        mutt_message _("Invoking S/MIME...");
+    }
+}
+
 /*
  * General helper functions.
  */
@@ -135,7 +113,7 @@ 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", Charset, M_ICONV_HOOK_FROM);
+  mutt_convert_string (&tstr, "utf-8", MCharset.charset, M_ICONV_HOOK_FROM);
   fputs (tstr, fp);
   p_delete(&tstr);
 }
@@ -367,10 +345,9 @@ static gpgme_data_t body_to_data_object (BODY * a, int convert)
   int err = 0;
   gpgme_data_t data;
 
-  mutt_mktemp (tempfile);
-  fptmp = safe_fopen (tempfile, "w+");
+  fptmp = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
   if (!fptmp) {
-    mutt_perror (tempfile);
+    mutt_perror (_("Can't create temporary file"));
     return NULL;
   }
 
@@ -399,13 +376,11 @@ static gpgme_data_t body_to_data_object (BODY * a, int convert)
       buf[0] = c;
       gpgme_data_write (data, buf, 1);
     }
-    fclose (fptmp);
     gpgme_data_seek (data, 0, SEEK_SET);
-  }
-  else {
-    fclose (fptmp);
+  } 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));
@@ -476,10 +451,9 @@ static char *data_object_to_tempfile (gpgme_data_t data, FILE ** ret_fp)
   FILE *fp;
   ssize_t nread = 0;
 
-  mutt_mktemp (tempfile);
-  fp = safe_fopen (tempfile, "w+");
+  fp = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
   if (!fp) {
-    mutt_perror (tempfile);
+    mutt_perror (_("Can't create temporary file"));
     return NULL;
   }
 
@@ -490,8 +464,8 @@ static char *data_object_to_tempfile (gpgme_data_t data, FILE ** ret_fp)
 
     while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) {
       if (fwrite (buf, nread, 1, fp) != 1) {
-        mutt_perror (tempfile);
-        fclose (fp);
+        mutt_perror (_("Can't create temporary file"));
+        m_fclose(&fp);
         unlink (tempfile);
         return NULL;
       }
@@ -500,11 +474,11 @@ static char *data_object_to_tempfile (gpgme_data_t data, FILE ** ret_fp)
   if (ret_fp)
     rewind (fp);
   else
-    fclose (fp);
+    m_fclose(&fp);
   if (nread == -1) {
     mutt_error (_("error reading data object: %s\n"), gpgme_strerror (err));
     unlink (tempfile);
-    fclose (fp);
+    m_fclose(&fp);
     return NULL;
   }
   if (ret_fp)
@@ -708,9 +682,7 @@ static void print_time (time_t t, STATE * s)
   state_attach_puts (p, s);
 }
 
-/* 
- * Implementation of `sign_message'.
- */
+/* 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
@@ -758,7 +730,7 @@ static BODY *sign_message (BODY * a, int use_smime)
     return NULL;
   }
 
-  t = mutt_new_body ();
+  t = body_new();
   t->type = TYPEMULTIPART;
   t->subtype = m_strdup("signed");
   t->encoding = ENC7BIT;
@@ -780,7 +752,7 @@ static BODY *sign_message (BODY * a, int use_smime)
   t->parts = a;
   a = t;
 
-  t->parts->next = mutt_new_body ();
+  t->parts->next = body_new();
   t = t->parts->next;
   t->type = TYPEAPPLICATION;
   if (use_smime) {
@@ -804,12 +776,12 @@ static BODY *sign_message (BODY * a, int use_smime)
 }
 
 
-BODY *pgp_gpgme_sign_message (BODY * a)
+BODY *crypt_pgp_sign_message (BODY * a)
 {
   return sign_message (a, 0);
 }
 
-BODY *smime_gpgme_sign_message (BODY * a)
+BODY *crypt_smime_sign_message (BODY * a)
 {
   return sign_message (a, 1);
 }
@@ -820,7 +792,7 @@ BODY *smime_gpgme_sign_message (BODY * a)
 
 /* Encrypt the mail body A to all keys given as space separated keyids
    or fingerprints in KEYLIST and return the encrypted body.  */
-BODY *pgp_gpgme_encrypt_message (BODY * a, char *keylist, int sign)
+BODY *crypt_pgp_encrypt_message (BODY * a, char *keylist, int sign)
 {
   char *outfile = NULL;
   BODY *t;
@@ -845,7 +817,7 @@ BODY *pgp_gpgme_encrypt_message (BODY * a, char *keylist, int sign)
   if (!outfile)
     return NULL;
 
-  t = mutt_new_body ();
+  t = body_new();
   t->type = TYPEMULTIPART;
   t->subtype = m_strdup("encrypted");
   t->encoding = ENC7BIT;
@@ -855,12 +827,12 @@ BODY *pgp_gpgme_encrypt_message (BODY * a, char *keylist, int sign)
   parameter_set_boundary(&t->parameter);
   parameter_setval(&t->parameter, "protocol", "application/pgp-encrypted");
 
-  t->parts = mutt_new_body ();
+  t->parts = body_new();
   t->parts->type = TYPEAPPLICATION;
   t->parts->subtype = m_strdup("pgp-encrypted");
   t->parts->encoding = ENC7BIT;
 
-  t->parts->next = mutt_new_body ();
+  t->parts->next = body_new();
   t->parts->next->type = TYPEAPPLICATION;
   t->parts->next->subtype = m_strdup("octet-stream");
   t->parts->next->encoding = ENC7BIT;
@@ -880,7 +852,7 @@ BODY *pgp_gpgme_encrypt_message (BODY * a, char *keylist, int sign)
 
 /* Encrypt the mail body A to all keys given as space separated
    fingerprints in KEYLIST and return the S/MIME encrypted body.  */
-BODY *smime_gpgme_build_smime_entity (BODY * a, char *keylist)
+BODY *crypt_smime_build_smime_entity (BODY * a, char *keylist)
 {
   char *outfile = NULL;
   BODY *t;
@@ -903,7 +875,7 @@ BODY *smime_gpgme_build_smime_entity (BODY * a, char *keylist)
   if (!outfile)
     return NULL;
 
-  t = mutt_new_body ();
+  t = body_new();
   t->type = TYPEAPPLICATION;
   t->subtype = m_strdup("pkcs7-mime");
   parameter_setval(&t->parameter, "name", "smime.p7m");
@@ -921,9 +893,7 @@ BODY *smime_gpgme_build_smime_entity (BODY * a, char *keylist)
 }
 
 
-/* 
- * Implementation of `verify_one'.
- */
+/* Implementation of `verify_one'. */
 
 /* Display the common attributes of the signature summary SUM.
    Return 1 if there is is a severe warning.
@@ -1025,6 +995,7 @@ static void show_fingerprint (gpgme_key_t key, STATE * state)
   int i, is_pgp;
   char *buf, *p;
   const char *prefix = _("Fingerprint: ");
+  ssize_t bufsize;
 
   if (!key)
     return;
@@ -1033,8 +1004,9 @@ static void show_fingerprint (gpgme_key_t key, STATE * state)
     return;
   is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
 
-  buf = xmalloc(m_strlen(prefix) + m_strlen(s) * 4 + 2);
-  strcpy (buf, prefix);         /* __STRCPY_CHECKED__ */
+  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++) {
@@ -1104,7 +1076,7 @@ static void show_one_sig_validity (gpgme_ctx_t ctx, int idx, STATE * 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. 
+   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.  */
@@ -1318,12 +1290,12 @@ static int verify_one (BODY * sigbdy, STATE * s,
   return badsig ? 1 : anywarn ? 2 : 0;
 }
 
-int pgp_gpgme_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
+int crypt_pgp_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
 {
   return verify_one (sigbdy, s, tempfile, 0);
 }
 
-int smime_gpgme_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
+int crypt_smime_verify_one (BODY * sigbdy, STATE * s, const char *tempfile)
 {
   return verify_one (sigbdy, s, tempfile, 1);
 }
@@ -1468,7 +1440,7 @@ restart:
 
 /* 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 pgp_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
+int crypt_pgp_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
 {
   char tempfile[_POSIX_PATH_MAX];
   STATE s;
@@ -1488,9 +1460,9 @@ int pgp_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b, BODY ** cur)
 
   p_clear(&s, 1);
   s.fpin = fpin;
-  mutt_mktemp (tempfile);
-  if (!(*fpout = safe_fopen (tempfile, "w+"))) {
-    mutt_perror (tempfile);
+  *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
+  if (!*fpout) {
+    mutt_perror (_("Can't create temporary file"));
     return -1;
   }
   unlink (tempfile);
@@ -1506,7 +1478,7 @@ int pgp_gpgme_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 smime_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b,
+int crypt_smime_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b,
                               BODY ** cur)
 {
   char tempfile[_POSIX_PATH_MAX];
@@ -1533,9 +1505,9 @@ int smime_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b,
   p_clear(&s, 1);
   s.fpin = fpin;
   fseeko (s.fpin, b->offset, 0);
-  mutt_mktemp (tempfile);
-  if (!(tmpfp = safe_fopen (tempfile, "w+"))) {
-    mutt_perror (tempfile);
+  tmpfp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
+  if (!tmpfp) {
+    mutt_perror (_("Can't create temporary file"));
     return -1;
   }
   mutt_unlink (tempfile);
@@ -1550,9 +1522,9 @@ int smime_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b,
   p_clear(&s, 1);
   s.fpin = tmpfp;
   s.fpout = 0;
-  mutt_mktemp (tempfile);
-  if (!(*fpout = safe_fopen (tempfile, "w+"))) {
-    mutt_perror (tempfile);
+  *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
+  if (!*fpout) {
+    mutt_perror (_("Can't create temporary file"));
     return -1;
   }
   mutt_unlink (tempfile);
@@ -1563,7 +1535,7 @@ int smime_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b,
   b->type = saved_b_type;
   b->length = saved_b_length;
   b->offset = saved_b_offset;
-  fclose (tmpfp);
+  m_fclose(&tmpfp);
   rewind (*fpout);
   if (*cur && !is_signed && !(*cur)->parts
       && mutt_is_application_smime (*cur)) {
@@ -1585,9 +1557,9 @@ int smime_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b,
     p_clear(&s, 1);
     s.fpin = *fpout;
     fseeko (s.fpin, bb->offset, 0);
-    mutt_mktemp (tempfile);
-    if (!(tmpfp = safe_fopen (tempfile, "w+"))) {
-      mutt_perror (tempfile);
+    tmpfp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
+    if (!tmpfp) {
+      mutt_perror (_("Can't create temporary file"));
       return -1;
     }
     mutt_unlink (tempfile);
@@ -1598,14 +1570,14 @@ int smime_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b,
     bb->length = ftello (s.fpout);
     bb->offset = 0;
     rewind (tmpfp);
-    fclose (*fpout);
+    m_fclose(&*fpout);
 
     p_clear(&s, 1);
     s.fpin = tmpfp;
     s.fpout = 0;
-    mutt_mktemp (tempfile);
-    if (!(*fpout = safe_fopen (tempfile, "w+"))) {
-      mutt_perror (tempfile);
+    *fpout = m_tempfile(tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
+    if (!*fpout) {
+      mutt_perror (_("Can't create temporary file"));
       return -1;
     }
     mutt_unlink (tempfile);
@@ -1616,16 +1588,16 @@ int smime_gpgme_decrypt_mime (FILE * fpin, FILE ** fpout, BODY * b,
     bb->type = saved_b_type;
     bb->length = saved_b_length;
     bb->offset = saved_b_offset;
-    fclose (tmpfp);
+    m_fclose(&tmpfp);
     rewind (*fpout);
-    mutt_free_body (cur);
+    body_list_wipe(cur);
     *cur = tmp_b;
   }
   return *cur ? 0 : -1;
 }
 
 
-/* 
+/*
  * Implementation of `pgp_check_traditional'.
  */
 
@@ -1635,6 +1607,7 @@ static int pgp_check_traditional_one_body (FILE * fp, BODY * b,
   char tempfile[_POSIX_PATH_MAX];
   char buf[HUGE_STRING];
   FILE *tfp;
+  int tempfd;
 
   short sgn = 0;
   short enc = 0;
@@ -1645,13 +1618,13 @@ static int pgp_check_traditional_one_body (FILE * fp, BODY * b,
   if (tagged_only && !b->tagged)
     return 0;
 
-  mutt_mktemp (tempfile);
-  if (mutt_decode_save_attachment (fp, b, tempfile, 0, 0) != 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) {
+  if ((tfp = fopen(tempfile, "r")) == NULL) {
     unlink (tempfile);
     return 0;
   }
@@ -1664,7 +1637,7 @@ static int pgp_check_traditional_one_body (FILE * fp, BODY * b,
         sgn = 1;
     }
   }
-  safe_fclose (&tfp);
+  m_fclose(&tfp);
   unlink (tempfile);
 
   if (!enc && !sgn)
@@ -1678,14 +1651,14 @@ static int pgp_check_traditional_one_body (FILE * fp, BODY * b,
   return 1;
 }
 
-int pgp_gpgme_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;
 
   for (; b; b = b->next) {
     if (is_multipart (b))
-      rv = (pgp_gpgme_check_traditional (fp, b->parts, tagged_only) || rv);
+      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);
@@ -1697,18 +1670,16 @@ int pgp_gpgme_check_traditional (FILE * fp, BODY * b, int tagged_only)
 }
 
 
-/* 
- * Implementation of `application_handler'.
- */
+/* 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.)  */
@@ -1727,7 +1698,7 @@ static void copy_clearsigned (gpgme_data_t data, STATE * s, char *charset)
   unlink (fname);
   p_delete(&fname);
 
-  fc = fgetconv_open (fp, charset, Charset, M_ICONV_HOOK_FROM);
+  fc = fgetconv_open (fp, charset, MCharset.charset, M_ICONV_HOOK_FROM);
 
   for (complete = 1, armor_header = 1;
        fgetconvs (buf, sizeof (buf), fc) != NULL;
@@ -1757,12 +1728,12 @@ static void copy_clearsigned (gpgme_data_t data, STATE * s, char *charset)
   }
 
   fgetconv_close (&fc);
-  fclose (fp);
+  m_fclose(&fp);
 }
 
 
 /* Support for classic_application/pgp */
-int pgp_gpgme_application_handler (BODY * m, STATE * s)
+int crypt_pgp_application_pgp_handler (BODY * m, STATE * s)
 {
   int needpass = -1, pgp_keyblock = 0;
   int clearsign = 0;
@@ -1924,7 +1895,7 @@ int pgp_gpgme_application_handler (BODY * m, STATE * s)
 
       /*
        * Now, copy cleartext to the screen.  NOTE - we expect that PGP
-       * outputs utf-8 cleartext.  This may not always be true, but it 
+       * outputs utf-8 cleartext.  This may not always be true, but it
        * seems to be a reasonable guess.
        */
 
@@ -1945,7 +1916,7 @@ int pgp_gpgme_application_handler (BODY * m, STATE * s)
         int c;
 
         rewind (pgpout);
-        fc = fgetconv_open (pgpout, "utf-8", Charset, 0);
+        fc = fgetconv_open (pgpout, "utf-8", MCharset.charset, 0);
         while ((c = fgetconv (fc)) != EOF) {
           state_putc (c, s);
           if (c == '\n' && s->prefix)
@@ -1965,7 +1936,7 @@ int pgp_gpgme_application_handler (BODY * m, STATE * s)
       }
 
       if (pgpout) {
-        safe_fclose (&pgpout);
+        m_fclose(&pgpout);
       }
     }
     else {
@@ -1986,12 +1957,10 @@ int pgp_gpgme_application_handler (BODY * m, STATE * s)
   return (err);
 }
 
-/* 
- * Implementation of `encrypted_handler'.
- */
+/* Implementation of `encrypted_handler'. */
 
 /* MIME handler for pgp/mime encrypted messages. */
-int pgp_gpgme_encrypted_handler (BODY * a, STATE * s)
+int crypt_pgp_encrypted_handler (BODY * a, STATE * s)
 {
   char tempfile[_POSIX_PATH_MAX];
   FILE *fpout;
@@ -2014,8 +1983,8 @@ int pgp_gpgme_encrypted_handler (BODY * a, STATE * s)
   /* Move forward to the application/pgp-encrypted body. */
   a = a->next;
 
-  mutt_mktemp (tempfile);
-  if (!(fpout = safe_fopen (tempfile, "w+"))) {
+  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);
@@ -2040,7 +2009,7 @@ int pgp_gpgme_encrypted_handler (BODY * a, STATE * s)
       s->fpin = savefp;
     }
 
-    /* 
+    /*
      * if a multipart/signed is the _only_ sub-part of a
      * multipart/encrypted, cache signature verification
      * status.
@@ -2056,16 +2025,16 @@ int pgp_gpgme_encrypted_handler (BODY * a, STATE * s)
                          : _("[-- End of PGP/MIME encrypted data --]\n"), s);
     }
 
-    mutt_free_body (&tattach);
+    body_list_wipe(&tattach);
   }
 
-  fclose (fpout);
+  m_fclose(&fpout);
   mutt_unlink (tempfile);
   return (rc);
 }
 
 /* Support for application/smime */
-int smime_gpgme_application_handler (BODY * a, STATE * s)
+int crypt_smime_application_smime_handler (BODY * a, STATE * s)
 {
   char tempfile[_POSIX_PATH_MAX];
   FILE *fpout;
@@ -2074,8 +2043,8 @@ int smime_gpgme_application_handler (BODY * a, STATE * s)
   int rc = 0;
 
   a->warnsig = 0;
-  mutt_mktemp (tempfile);
-  if (!(fpout = safe_fopen (tempfile, "w+"))) {
+  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);
@@ -2099,7 +2068,7 @@ int smime_gpgme_application_handler (BODY * a, STATE * s)
       s->fpin = savefp;
     }
 
-    /* 
+    /*
      * if a multipart/signed is the _only_ sub-part of a
      * multipart/encrypted, cache signature verification
      * status.
@@ -2120,10 +2089,10 @@ int smime_gpgme_application_handler (BODY * a, STATE * s)
                          _("[-- End of S/MIME encrypted data --]\n"), s);
     }
 
-    mutt_free_body (&tattach);
+    body_list_wipe(&tattach);
   }
 
-  fclose (fpout);
+  m_fclose(&fpout);
   mutt_unlink (tempfile);
   return (rc);
 }
@@ -2131,7 +2100,7 @@ int smime_gpgme_application_handler (BODY * a, STATE * s)
 
 /*
  * Format an entry on the CRYPT key selection menu.
- * 
+ *
  * %n  number
  * %k  key id          %K      key id of the principal key
  * %u  user id
@@ -2147,8 +2116,8 @@ int smime_gpgme_application_handler (BODY * a, STATE * s)
 static const char *
 crypt_entry_fmt (char *dest, ssize_t destlen, char op,
                  const char *src, const char *prefix,
-                 const char *ifstring, const char *elsestring,
-                 unsigned long data, format_flag flags)
+                 const char *ifstr, const char *elstr,
+                 anytype data, format_flag flags)
 {
   char fmt[16];
   crypt_entry_t *entry;
@@ -2158,7 +2127,7 @@ crypt_entry_fmt (char *dest, ssize_t destlen, char op,
   const char *s = NULL;
   unsigned long val;
 
-  entry = (crypt_entry_t *) data;
+  entry = data.ptr;
   key = entry->key;
 
 /*    if (isupper ((unsigned char) op)) */
@@ -2171,7 +2140,7 @@ crypt_entry_fmt (char *dest, ssize_t destlen, char op,
   case '[':
     {
       const char *cp;
-      char buf2[SHORT_STRING], *p;
+      char buf2[STRING], *p;
       int do_locales;
       struct tm *tm;
       ssize_t len;
@@ -2329,11 +2298,10 @@ crypt_entry_fmt (char *dest, ssize_t destlen, char op,
     *dest = '\0';
   }
 
-  if (optional)
-    mutt_FormatString (dest, destlen, ifstring, mutt_attach_fmt, data, 0);
-  else if (flags & M_FORMAT_OPTIONAL)
-    mutt_FormatString (dest, destlen, elsestring, mutt_attach_fmt, data, 0);
-  return (src);
+  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. */
@@ -2345,8 +2313,8 @@ static void crypt_entry (char *s, ssize_t l, MUTTMENU * menu, int num)
   entry.key = key_table[num];
   entry.num = num + 1;
 
-  mutt_FormatString (s, l, NONULL (PgpEntryFormat), crypt_entry_fmt,
-                     (unsigned long) &entry, M_FORMAT_ARROWCURSOR);
+  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. */
@@ -2532,16 +2500,16 @@ static const unsigned char *parse_dn_part (struct dn_array_s *array,
 
   if (*string == '#') {         /* hexstring */
     string++;
-    for (s = string; hexdigitp (s); s++)
+    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 = xmalloc(n + 1);
+    p = p_new(unsigned char, n + 1);
     array->value = (char *) p;
     for (s1 = string; n; s1 += 2, n--)
-      *p++ = xtoi_2 (s1);
+      *p++ = (hexval(*s1) << 8) | hexval(*s1);
     *p = 0;
   }
   else {                        /* regular v3 quoted string */
@@ -2552,7 +2520,7 @@ static const unsigned char *parse_dn_part (struct dn_array_s *array,
             || *s == '<' || *s == '>' || *s == '#' || *s == ';'
             || *s == '\\' || *s == '\"' || *s == ' ')
           n++;
-        else if (hexdigitp (s) && hexdigitp (s + 1)) {
+        else if (hexval(*s) >= 0 && hexval(*s + 1) >= 0) {
           s++;
           n++;
         }
@@ -2568,13 +2536,13 @@ static const unsigned char *parse_dn_part (struct dn_array_s *array,
         n++;
     }
 
-    p = xmalloc(n + 1);
+    p = p_new(unsigned char, n + 1);
     array->value = (char *) p;
     for (s = string; n; s++, n--) {
       if (*s == '\\') {
         s++;
-        if (hexdigitp (s)) {
-          *p++ = xtoi_2 (s);
+        if (hexval(*s) >= 0) {
+          *p++ = (hexval(*s) << 8) | hexval(*s + 1);
           s++;
         }
         else
@@ -2722,7 +2690,7 @@ static void print_key_info (gpgme_key_t key, FILE * fp)
   const char *s = NULL, *s2 = NULL;
   time_t tt = 0;
   struct tm *tm;
-  char shortbuf[SHORT_STRING];
+  char shortbuf[STRING];
   unsigned long aval = 0;
   const char *delim;
   int is_pgp = 0;
@@ -2946,10 +2914,9 @@ static void verify_key (crypt_key_t * key)
   gpgme_key_t k = NULL;
   int maxdepth = 100;
 
-  mutt_mktemp (tempfile);
-  if (!(fp = safe_fopen (tempfile, "w"))) {
+  fp = m_tempfile (tempfile, sizeof(tempfile), NONULL(MCore.tmpdir), NULL);
+  if (!fp) {
     mutt_perror (_("Can't create temporary file"));
-
     return;
   }
   mutt_message _("Collecting data...");
@@ -2991,16 +2958,13 @@ static void verify_key (crypt_key_t * key)
 leave:
   gpgme_key_release (k);
   gpgme_release (listctx);
-  fclose (fp);
+  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'.
- */
-
+/* 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
@@ -3225,7 +3189,7 @@ static crypt_key_t *crypt_select_key (crypt_key_t * keys,
   crypt_key_t **key_table;
   MUTTMENU *menu;
   int i, done = 0;
-  char helpstr[SHORT_STRING], buf[LONG_STRING];
+  char helpstr[STRING], buf[LONG_STRING];
   crypt_key_t *k;
   int (*f) (const void *, const void *);
   int menu_to_use = 0;
@@ -3281,15 +3245,15 @@ static crypt_key_t *crypt_select_key (crypt_key_t * keys,
 
   helpstr[0] = 0;
   mutt_make_help (buf, sizeof (buf), _("Exit  "), menu_to_use, OP_EXIT);
-  strcat (helpstr, buf);        /* __STRCAT_CHECKED__ */
+  m_strcat(helpstr, sizeof(helpstr), buf);
   mutt_make_help (buf, sizeof (buf), _("Select  "), menu_to_use,
                   OP_GENERIC_SELECT_ENTRY);
-  strcat (helpstr, buf);        /* __STRCAT_CHECKED__ */
+  m_strcat(helpstr, sizeof(helpstr), buf);
   mutt_make_help (buf, sizeof (buf), _("Check key  "),
                   menu_to_use, OP_VERIFY_KEY);
-  strcat (helpstr, buf);        /* __STRCAT_CHECKED__ */
+  m_strcat(helpstr, sizeof(helpstr), buf);
   mutt_make_help (buf, sizeof (buf), _("Help"), menu_to_use, OP_HELP);
-  strcat (helpstr, buf);        /* __STRCAT_CHECKED__ */
+  m_strcat(helpstr, sizeof(helpstr), buf);
 
   menu = mutt_new_menu ();
   menu->max = i;
@@ -3498,17 +3462,17 @@ static crypt_key_t *crypt_getkeybyaddr (address_t * a, short abilities,
   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);
@@ -3522,7 +3486,7 @@ static crypt_key_t *crypt_getkeybyaddr (address_t * a, short abilities,
 }
 
 
-static crypt_key_t *crypt_getkeybystr (char *p, short abilities,
+static crypt_key_t *crypt_getkeybystr (const char *p, short abilities,
                                        unsigned int app, int *forced_valid)
 {
   string_list_t *hints = NULL;
@@ -3585,7 +3549,7 @@ static crypt_key_t *crypt_ask_for_key (char *tag,
                                        unsigned int app, int *forced_valid)
 {
   crypt_key_t *key;
-  char resp[SHORT_STRING];
+  char resp[STRING];
   struct crypt_cache *l = NULL;
   int dummy;
 
@@ -3636,7 +3600,8 @@ static crypt_key_t *crypt_ask_for_key (char *tag,
 static char *find_keys (address_t * to, address_t * cc, address_t * bcc,
                         unsigned int app)
 {
-  char *keyID, *keylist = NULL, *t;
+  char *keylist = NULL, *t;
+  const char *keyID;
   ssize_t keylist_size = 0;
   ssize_t keylist_used = 0;
   address_t *tmp = NULL, *addr = NULL;
@@ -3670,10 +3635,8 @@ static char *find_keys (address_t * to, address_t * cc, address_t * bcc,
       last = &((*last)->next);
   }
 
-  if (fqdn)
-    rfc822_qualify (tmp, fqdn);
-
-  tmp = mutt_remove_duplicates (tmp);
+  rfc822_qualify(tmp, fqdn);
+  address_list_uniq(tmp);
 
   for (p = tmp; p; p = p->next) {
     char buf[LONG_STRING];
@@ -3691,18 +3654,12 @@ static char *find_keys (address_t * to, address_t * cc, address_t * bcc,
         /* check for e-mail address */
         if ((t = strchr (keyID, '@')) &&
             (addr = rfc822_parse_adrlist (NULL, keyID))) {
-          if (fqdn)
-            rfc822_qualify (addr, fqdn);
+          rfc822_qualify(addr, fqdn);
           q = addr;
         }
         else {
-#if 0
-          k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
-                                      *r_application, &forced_valid);
-#else
           k_info = crypt_getkeybystr (keyID, KEYFLAG_CANENCRYPT,
                                       app, &forced_valid);
-#endif
         }
       }
       else if (r == -1) {
@@ -3719,11 +3676,7 @@ static char *find_keys (address_t * to, address_t * cc, address_t * bcc,
       snprintf (buf, sizeof (buf), _("Enter keyID for %s: "), q->mailbox);
 
       if ((key = crypt_ask_for_key (buf, q->mailbox, KEYFLAG_CANENCRYPT,
-#if 0
-                                    *r_application,
-#else
                                     app,
-#endif
                                     &forced_valid)) == NULL) {
         p_delete(&keylist);
         address_list_wipe(&tmp);
@@ -3737,16 +3690,9 @@ static char *find_keys (address_t * to, address_t * cc, address_t * bcc,
     {
       const char *s = crypt_fpr (key);
 
-#if 0
-      if (key->flags & KEYFLAG_ISX509)
-        *r_application &= ~APPLICATION_PGP;
-      if (!(key->flags & KEYFLAG_ISX509))
-        *r_application &= ~APPLICATION_SMIME;
-#endif
-
       keylist_size += m_strlen(s) + 4 + 1;
       p_realloc(&keylist, keylist_size);
-      sprintf (keylist + keylist_used, "%s0x%s%s",      /* __SPRINTF_CHECKED__ */
+      sprintf (keylist + keylist_used, "%s0x%s%s",
                keylist_used ? " " : "", s, forced_valid ? "!" : "");
     }
     keylist_used = m_strlen(keylist);
@@ -3758,44 +3704,20 @@ static char *find_keys (address_t * to, address_t * cc, address_t * bcc,
   return (keylist);
 }
 
-char *pgp_gpgme_findkeys (address_t * to, address_t * cc, address_t * bcc)
+char *crypt_pgp_findkeys (address_t * to, address_t * cc, address_t * bcc)
 {
   return find_keys (to, cc, bcc, APPLICATION_PGP);
 }
 
-char *smime_gpgme_findkeys (address_t * to, address_t * cc, address_t * bcc)
+char *crypt_smime_findkeys (address_t * to, address_t * cc, address_t * bcc)
 {
   return find_keys (to, cc, bcc, APPLICATION_SMIME);
 }
 
-/*
- * Implementation of `init'.
- */
-
-/* Initialization.  */
-static void init_gpgme (void)
-{
-  /* Make sure that gpg-agent is running.  */
-  if (!getenv ("GPG_AGENT_INFO")) {
-    mutt_error ("\nUsing GPGME backend, although no gpg-agent is running");
-    if (mutt_any_key_to_continue (NULL) == -1)
-      mutt_exit (1);
-  }
-}
-
-void pgp_gpgme_init (void)
-{
-  init_gpgme ();
-}
-
-void smime_gpgme_init (void)
-{
-}
-
 static int gpgme_send_menu (HEADER * msg, int *redraw, int is_smime)
 {
   crypt_key_t *p;
-  char input_signas[SHORT_STRING];
+  char input_signas[STRING];
   int choice;
 
   if (msg->security & APPLICATION_PGP)
@@ -3837,11 +3759,6 @@ static int gpgme_send_menu (HEADER * msg, int *redraw, int is_smime)
 
       msg->security |= (is_smime ? SMIMESIGN : PGPSIGN);
     }
-#if 0
-    else {
-      msg->security &= (is_smime ? ~SMIMESIGN : ~PGPSIGN);
-    }
-#endif
     *redraw = REDRAW_FULL;
     break;
 
@@ -3872,17 +3789,17 @@ static int gpgme_send_menu (HEADER * msg, int *redraw, int is_smime)
   return (msg->security);
 }
 
-int pgp_gpgme_send_menu (HEADER * msg, int *redraw)
+int crypt_pgp_send_menu(HEADER * msg, int *redraw)
 {
-  return gpgme_send_menu (msg, redraw, 0);
+  return gpgme_send_menu(msg, redraw, 0);
 }
 
-int smime_gpgme_send_menu (HEADER * msg, int *redraw)
+int crypt_smime_send_menu(HEADER * msg, int *redraw)
 {
   return gpgme_send_menu (msg, redraw, 1);
 }
 
-static int verify_sender (HEADER * h, gpgme_protocol_t protocol __attribute__((unused)))
+int crypt_smime_verify_sender (HEADER * h)
 {
   address_t *sender = NULL;
   unsigned int ret = 1;
@@ -3909,7 +3826,7 @@ static int verify_sender (HEADER * h, gpgme_protocol_t protocol __attribute__((u
         if (1 && (uid->email[0] == '<')
             && (uid->email[uid_length - 1] == '>')
             && (uid_length == sender_length + 2)
-            && (!strncmp (uid->email + 1, sender->mailbox, sender_length)))
+            && (!m_strncmp (uid->email + 1, sender->mailbox, sender_length)))
           ret = 0;
       }
     }
@@ -3927,9 +3844,79 @@ static int verify_sender (HEADER * h, gpgme_protocol_t protocol __attribute__((u
   return ret;
 }
 
-int smime_gpgme_verify_sender (HEADER * h)
+static void invoke_import(const char *fname, int smime)
 {
-  return verify_sender (h, GPGME_PROTOCOL_CMS);
+    gpgme_ctx_t ctx = create_gpgme_context(smime);
+    gpgme_data_t data;
+    gpgme_error_t err;
+
+    err = gpgme_data_new_from_file(&data, fname, 1);
+    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;
+}
+
+void crypt_pgp_invoke_import(const char *fname)
+{
+    invoke_import(fname, 0);
+}
+
+void crypt_smime_invoke_import(const char *fname)
+{
+    invoke_import(fname, 1);
+}
+
+static void pgp_extract_keys_from_attachment (FILE * fp, BODY * top)
+{
+  STATE s;
+  FILE *tempfp;
+  char tempfname[_POSIX_PATH_MAX];
+
+  tempfp = m_tempfile(tempfname, sizeof(tempfname), NONULL(MCore.tmpdir), NULL);
+  if (tempfp == NULL) {
+    mutt_perror (_("Can't create temporary file"));
+    return;
+  }
+
+  p_clear(&s, 1);
+
+  s.fpin = fp;
+  s.fpout = tempfp;
+
+  mutt_body_handler (top, &s);
+
+  m_fclose(&tempfp);
+  crypt_pgp_invoke_import(tempfname);
+  mutt_unlink (tempfname);
+}
+
+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);
 }
 
-#endif