]> git.llucax.com Git - software/mutt-debian.git/blobdiff - crypt-gpgme.c
Make mutt-nntp depend on mutt >= 1.5.21-5
[software/mutt-debian.git] / crypt-gpgme.c
index 3809daab4086e6656cf430d7d0f19ea6287c8b8c..ca69edd251381421a625a45883122fad76516b64 100644 (file)
@@ -1,5 +1,5 @@
 /* crypt-gpgme.c - GPGME based crypto operations
 /* crypt-gpgme.c - GPGME based crypto operations
- * Copyright (C) 1996,1997 Michael R. Elkins <me@cs.hmc.edu>
+ * Copyright (C) 1996-7,2007 Michael R. Elkins <me@cs.hmc.edu>
  * Copyright (C) 1998,1999,2000 Thomas Roessler <roessler@does-not-exist.org>
  * Copyright (C) 2001  Thomas Roessler <roessler@does-not-exist.org>
  *                     Oliver Ehli <elmy@acm.org>
  * Copyright (C) 1998,1999,2000 Thomas Roessler <roessler@does-not-exist.org>
  * Copyright (C) 2001  Thomas Roessler <roessler@does-not-exist.org>
  *                     Oliver Ehli <elmy@acm.org>
@@ -82,6 +82,9 @@
 #define CRYPT_KV_STRONGID 8
 #define CRYPT_KV_MATCH (CRYPT_KV_ADDR|CRYPT_KV_STRING)
 
 #define CRYPT_KV_STRONGID 8
 #define CRYPT_KV_MATCH (CRYPT_KV_ADDR|CRYPT_KV_STRING)
 
+/* static local variables */
+static int GpgmeLocaleSet = 0;
+
 /*
  * Type definitions.
  */
 /*
  * Type definitions.
  */
@@ -339,6 +342,16 @@ static gpgme_ctx_t create_gpgme_context (int for_smime)
   gpgme_error_t err;
   gpgme_ctx_t ctx;
 
   gpgme_error_t err;
   gpgme_ctx_t ctx;
 
+  if (!GpgmeLocaleSet)
+  {
+    gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
+#ifdef ENABLE_NLS
+    gpgme_set_locale (NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL));
+#endif
+
+    GpgmeLocaleSet = 1;
+  }
+
   err = gpgme_new (&ctx);
   if (err)
     {
   err = gpgme_new (&ctx);
   if (err)
     {
@@ -390,7 +403,7 @@ static gpgme_data_t body_to_data_object (BODY *a, int convert)
   int err = 0;
   gpgme_data_t data;
   
   int err = 0;
   gpgme_data_t data;
   
-  mutt_mktemp (tempfile);
+  mutt_mktemp (tempfile, sizeof (tempfile));
   fptmp = safe_fopen (tempfile, "w+");
   if (!fptmp)
     {
   fptmp = safe_fopen (tempfile, "w+");
   if (!fptmp)
     {
@@ -427,12 +440,12 @@ static gpgme_data_t body_to_data_object (BODY *a, int convert)
           buf[0] = c;
           gpgme_data_write (data, buf, 1);
         }
           buf[0] = c;
           gpgme_data_write (data, buf, 1);
         }
-      fclose(fptmp);
+      safe_fclose (&fptmp);
       gpgme_data_seek (data, 0, SEEK_SET);
     }
   else
     {
       gpgme_data_seek (data, 0, SEEK_SET);
     }
   else
     {
-      fclose(fptmp);
+      safe_fclose (&fptmp);
       err = gpgme_data_new_from_file (&data, tempfile, 1);
     }
   unlink (tempfile);
       err = gpgme_data_new_from_file (&data, tempfile, 1);
     }
   unlink (tempfile);
@@ -512,7 +525,7 @@ static char *data_object_to_tempfile (gpgme_data_t data, FILE **ret_fp)
   FILE *fp;
   size_t nread = 0;
 
   FILE *fp;
   size_t nread = 0;
 
-  mutt_mktemp (tempfile);
+  mutt_mktemp (tempfile, sizeof (tempfile));
   fp = safe_fopen (tempfile, "w+");
   if (!fp)
     {
   fp = safe_fopen (tempfile, "w+");
   if (!fp)
     {
@@ -531,7 +544,7 @@ static char *data_object_to_tempfile (gpgme_data_t data, FILE **ret_fp)
           if (fwrite (buf, nread, 1, fp) != 1)
             {
               mutt_perror (tempfile);
           if (fwrite (buf, nread, 1, fp) != 1)
             {
               mutt_perror (tempfile);
-              fclose (fp);
+              safe_fclose (&fp);
               unlink (tempfile);
               return NULL;
             }
               unlink (tempfile);
               return NULL;
             }
@@ -540,12 +553,12 @@ static char *data_object_to_tempfile (gpgme_data_t data, FILE **ret_fp)
   if (ret_fp)
     rewind (fp);
   else
   if (ret_fp)
     rewind (fp);
   else
-    fclose (fp);
+    safe_fclose (&fp);
   if (nread == -1)
     {
       mutt_error (_("error reading data object: %s\n"), gpgme_strerror (err));
       unlink (tempfile);
   if (nread == -1)
     {
       mutt_error (_("error reading data object: %s\n"), gpgme_strerror (err));
       unlink (tempfile);
-      fclose (fp);
+      safe_fclose (&fp);
       return NULL;
     }
   if (ret_fp)
       return NULL;
     }
   if (ret_fp)
@@ -756,7 +769,7 @@ static char *encrypt_gpgme_object (gpgme_data_t plaintext, gpgme_key_t *rset,
    which must have been allocated by the caller with size BUFLEN.
    Returns 0 on success or -1 in case of an error.  The return string
    is truncted to BUFLEN - 1. */
    which must have been allocated by the caller with size BUFLEN.
    Returns 0 on success or -1 in case of an error.  The return string
    is truncted to BUFLEN - 1. */
-static int get_micalg (gpgme_ctx_t ctx, char *buf, size_t buflen)
+static int get_micalg (gpgme_ctx_t ctx, int use_smime, char *buf, size_t buflen)
 {
   gpgme_sign_result_t result = NULL;
   const char *algorithm_name = NULL;
 {
   gpgme_sign_result_t result = NULL;
   const char *algorithm_name = NULL;
@@ -771,9 +784,16 @@ static int get_micalg (gpgme_ctx_t ctx, char *buf, size_t buflen)
     algorithm_name = gpgme_hash_algo_name (result->signatures->hash_algo);
     if (algorithm_name)
     {
     algorithm_name = gpgme_hash_algo_name (result->signatures->hash_algo);
     if (algorithm_name)
     {
-      /* convert GPGME raw hash name to RFC 3156 format */
-      snprintf (buf, buflen, "pgp-%s", algorithm_name);
-      ascii_strlower (buf + 4);
+      if (use_smime)
+      {
+        /* convert GPGME raw hash name to RFC 2633 format */
+        snprintf (buf, buflen, "%s", algorithm_name);
+        ascii_strlower (buf);
+      } else {
+        /* convert GPGME raw hash name to RFC 3156 format */
+        snprintf (buf, buflen, "pgp-%s", algorithm_name);
+        ascii_strlower (buf + 4);
+      }
     }
   }
 
     }
   }
 
@@ -873,10 +893,10 @@ static BODY *sign_message (BODY *a, int use_smime)
                       &t->parameter);
   /* Get the micalg from gpgme.  Old gpgme versions don't support this
      for S/MIME so we assume sha-1 in this case. */
                       &t->parameter);
   /* Get the micalg from gpgme.  Old gpgme versions don't support this
      for S/MIME so we assume sha-1 in this case. */
-  if (!get_micalg (ctx, buf, sizeof buf))
+  if (!get_micalg (ctx, use_smime, buf, sizeof buf))
     mutt_set_parameter ("micalg", buf, &t->parameter);
   else if (use_smime)
     mutt_set_parameter ("micalg", buf, &t->parameter);
   else if (use_smime)
-    mutt_set_parameter ("micalg", "pgp-sha1", &t->parameter);
+    mutt_set_parameter ("micalg", "sha1", &t->parameter);
   gpgme_release (ctx);
 
   t->parts = a;
   gpgme_release (ctx);
 
   t->parts = a;
@@ -898,7 +918,7 @@ static BODY *sign_message (BODY *a, int use_smime)
     {
       t->subtype = safe_strdup ("pgp-signature");
       t->use_disp = 0;
     {
       t->subtype = safe_strdup ("pgp-signature");
       t->use_disp = 0;
-      t->disposition = DISPINLINE;
+      t->disposition = DISPNONE;
       t->encoding = ENC7BIT;
     }
   t->filename = sigfile;
       t->encoding = ENC7BIT;
     }
   t->filename = sigfile;
@@ -971,7 +991,7 @@ BODY *pgp_gpgme_encrypt_message (BODY *a, char *keylist, int sign)
   t->parts->next->encoding = ENC7BIT;
   t->parts->next->filename = outfile;
   t->parts->next->use_disp = 1;
   t->parts->next->encoding = ENC7BIT;
   t->parts->next->filename = outfile;
   t->parts->next->use_disp = 1;
-  t->parts->next->disposition = DISPINLINE;
+  t->parts->next->disposition = DISPATTACH;
   t->parts->next->unlink = 1; /* delete after sending the message */
   t->parts->next->d_filename = safe_strdup ("msg.asc"); /* non pgp/mime
                                                            can save */
   t->parts->next->unlink = 1; /* delete after sending the message */
   t->parts->next->d_filename = safe_strdup ("msg.asc"); /* non pgp/mime
                                                            can save */
@@ -1245,6 +1265,40 @@ static void show_one_sig_validity (gpgme_ctx_t ctx, int idx, STATE *s)
     state_attach_puts (txt, s);
 }
 
     state_attach_puts (txt, s);
 }
 
+static void print_smime_keyinfo (const char* msg, gpgme_signature_t sig,
+                                 gpgme_key_t key, STATE *s)
+{
+  size_t msglen;
+  gpgme_user_id_t uids = NULL;
+  int i, aka = 0;
+
+  state_attach_puts (msg, s);
+  state_attach_puts (" ", s);
+  for (uids = key->uids; uids; uids = uids->next)
+  {
+    if (uids->revoked)
+      continue;
+    if (aka)
+    {
+      msglen = mutt_strlen (msg) - 4;
+      for (i = 0; i < msglen; i++)
+        state_attach_puts(" ", s);
+      state_attach_puts(_("aka: "), s);
+    }
+    state_attach_puts (uids->uid, s);
+    state_attach_puts ("\n", s);
+    
+    aka = 1;
+  }
+
+  msglen = mutt_strlen (msg) - 8;
+  for (i = 0; i < msglen; i++)
+    state_attach_puts(" ", s);
+  state_attach_puts (_("created: "), s);
+  print_time (sig->timestamp, s);
+  state_attach_puts ("\n", 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
 /* 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
@@ -1254,12 +1308,10 @@ static void show_one_sig_validity (gpgme_ctx_t ctx, int idx, STATE *s)
    2 for a signature with a warning or -1 for no more signature.  */
 static int show_one_sig_status (gpgme_ctx_t ctx, int idx, STATE *s)
 {
    2 for a signature with a warning or -1 for no more signature.  */
 static int show_one_sig_status (gpgme_ctx_t ctx, int idx, STATE *s)
 {
-  time_t created;
   const char *fpr, *uid;
   gpgme_key_t key = NULL;
   int i, anybad = 0, anywarn = 0;
   unsigned int sum;
   const char *fpr, *uid;
   gpgme_key_t key = NULL;
   int i, anybad = 0, anywarn = 0;
   unsigned int sum;
-  gpgme_user_id_t uids = NULL;
   gpgme_verify_result_t result;
   gpgme_signature_t sig;
   gpgme_error_t err = GPG_ERR_NO_ERROR;
   gpgme_verify_result_t result;
   gpgme_signature_t sig;
   gpgme_error_t err = GPG_ERR_NO_ERROR;
@@ -1283,7 +1335,6 @@ static int show_one_sig_status (gpgme_ctx_t ctx, int idx, STATE *s)
          signature_key = NULL;
        }
       
          signature_key = NULL;
        }
       
-      created = sig->timestamp;
       fpr = sig->fpr;
       sum = sig->summary;
 
       fpr = sig->fpr;
       sum = sig->summary;
 
@@ -1308,63 +1359,43 @@ static int show_one_sig_status (gpgme_ctx_t ctx, int idx, STATE *s)
        ; /* No state information so no way to print anything. */
       else if (err)
        {
        ; /* No state information so no way to print anything. */
       else if (err)
        {
-         state_attach_puts (_("Error getting key information: "), s);
-         state_attach_puts ( gpg_strerror (err), s );
-         state_attach_puts ("\n", s);
-         anybad = 1;
+          state_attach_puts (_("Error getting key information: "), s);
+          state_attach_puts ( gpg_strerror (err), s );
+          state_attach_puts ("\n", s);
+          anybad = 1;
        }
       else if ((sum & GPGME_SIGSUM_GREEN))
        }
       else if ((sum & GPGME_SIGSUM_GREEN))
-       {
-         state_attach_puts (_("Good signature from: "), s);
-         state_attach_puts (uid, s);
-         state_attach_puts ("\n", s);
-         for (i = 1, uids = key->uids; uids; i++, uids = uids->next)
-           {
-             if (i == 1)
-               /* Skip primary UID.  */
-               continue;
-             if (uids->revoked)
-               continue;
-             state_attach_puts (_("                aka: "), s);
-             state_attach_puts (uids->uid, s);
-             state_attach_puts ("\n", s);
-           }
-         state_attach_puts (_("            created: "), s);
-         print_time (created, s);
-         state_attach_puts ("\n", s);
-         if (show_sig_summary (sum, ctx, key, idx, s, sig))
-           anywarn = 1;
-         show_one_sig_validity (ctx, idx, s);
-       }
+      {
+        print_smime_keyinfo (_("Good signature from:"), sig, key, s);
+       if (show_sig_summary (sum, ctx, key, idx, s, sig))
+         anywarn = 1;
+       show_one_sig_validity (ctx, idx, s);
+      }
       else if ((sum & GPGME_SIGSUM_RED))
       else if ((sum & GPGME_SIGSUM_RED))
-       {
-         state_attach_puts (_("*BAD* signature claimed to be from: "), s);
-         state_attach_puts (uid, s);
-         state_attach_puts ("\n", s);
-         show_sig_summary (sum, ctx, key, idx, s, sig);
-       }
+      {
+        print_smime_keyinfo (_("*BAD* signature from:"), sig, key, s);
+        show_sig_summary (sum, ctx, key, idx, s, sig);
+      }
       else if (!anybad && key && (key->protocol == GPGME_PROTOCOL_OpenPGP))
       else if (!anybad && key && (key->protocol == GPGME_PROTOCOL_OpenPGP))
-       { /* We can't decide (yellow) but this is a PGP key with a good
-            signature, so we display what a PGP user expects: The name,
-            fingerprint and the key validity (which is neither fully or
-            ultimate). */
-         state_attach_puts (_("Good signature from: "), s);
-         state_attach_puts (uid, s);
-         state_attach_puts ("\n", s);
-         state_attach_puts (_("            created: "), s);
-         print_time (created, s);
-         state_attach_puts ("\n", s);
-         show_one_sig_validity (ctx, idx, s);
-         show_fingerprint (key,s);
-         if (show_sig_summary (sum, ctx, key, idx, s, sig))
-           anywarn = 1;
-       }
+      { /* We can't decide (yellow) but this is a PGP key with a good
+           signature, so we display what a PGP user expects: The name,
+          fingerprint and the key validity (which is neither fully or
+          ultimate). */
+        print_smime_keyinfo (_("Good signature from:"), sig, key, s);
+       show_one_sig_validity (ctx, idx, s);
+       show_fingerprint (key,s);
+       if (show_sig_summary (sum, ctx, key, idx, s, sig))
+         anywarn = 1;
+      }
       else /* can't decide (yellow) */
       else /* can't decide (yellow) */
-       {
-         state_attach_puts (_("Error checking signature"), s);
-         state_attach_puts ("\n", s);
-         show_sig_summary (sum, ctx, key, idx, s, sig);
-       }
+      {
+        print_smime_keyinfo (_("Problem signature from:"), sig, key, s);
+        state_attach_puts (_("               expires: "), s);
+        print_time (sig->exp_timestamp, s);
+        state_attach_puts ("\n", s);
+       show_sig_summary (sum, ctx, key, idx, s, sig);
+        anywarn = 1;
+      }
 
       if (key != signature_key)
        gpgme_key_release (key);
 
       if (key != signature_key)
        gpgme_key_release (key);
@@ -1680,7 +1711,7 @@ int pgp_gpgme_decrypt_mime (FILE *fpin, FILE **fpout, BODY *b, BODY **cur)
   
   memset (&s, 0, sizeof (s));
   s.fpin = fpin;
   
   memset (&s, 0, sizeof (s));
   s.fpin = fpin;
-  mutt_mktemp (tempfile);
+  mutt_mktemp (tempfile, sizeof (tempfile));
   if (!(*fpout = safe_fopen (tempfile, "w+")))
   {
     mutt_perror (tempfile);
   if (!(*fpout = safe_fopen (tempfile, "w+")))
   {
     mutt_perror (tempfile);
@@ -1725,7 +1756,7 @@ int smime_gpgme_decrypt_mime (FILE *fpin, FILE **fpout, BODY *b, BODY **cur)
   memset (&s, 0, sizeof (s));
   s.fpin = fpin;
   fseeko (s.fpin, b->offset, 0); 
   memset (&s, 0, sizeof (s));
   s.fpin = fpin;
   fseeko (s.fpin, b->offset, 0); 
-  mutt_mktemp (tempfile);
+  mutt_mktemp (tempfile, sizeof (tempfile));
   if (!(tmpfp = safe_fopen (tempfile, "w+")))
     {
       mutt_perror (tempfile);
   if (!(tmpfp = safe_fopen (tempfile, "w+")))
     {
       mutt_perror (tempfile);
@@ -1743,7 +1774,7 @@ int smime_gpgme_decrypt_mime (FILE *fpin, FILE **fpout, BODY *b, BODY **cur)
   memset (&s, 0, sizeof (s));
   s.fpin = tmpfp;
   s.fpout = 0;
   memset (&s, 0, sizeof (s));
   s.fpin = tmpfp;
   s.fpout = 0;
-  mutt_mktemp (tempfile);
+  mutt_mktemp (tempfile, sizeof (tempfile));
   if (!(*fpout = safe_fopen (tempfile, "w+")))
     {
       mutt_perror (tempfile);
   if (!(*fpout = safe_fopen (tempfile, "w+")))
     {
       mutt_perror (tempfile);
@@ -1757,7 +1788,7 @@ int smime_gpgme_decrypt_mime (FILE *fpin, FILE **fpout, BODY *b, BODY **cur)
   b->type = saved_b_type;
   b->length = saved_b_length;
   b->offset = saved_b_offset;
   b->type = saved_b_type;
   b->length = saved_b_length;
   b->offset = saved_b_offset;
-  fclose (tmpfp);
+  safe_fclose (&tmpfp);
   rewind (*fpout);
   if (*cur && !is_signed && !(*cur)->parts && mutt_is_application_smime (*cur))
     {
   rewind (*fpout);
   if (*cur && !is_signed && !(*cur)->parts && mutt_is_application_smime (*cur))
     {
@@ -1779,7 +1810,7 @@ int smime_gpgme_decrypt_mime (FILE *fpin, FILE **fpout, BODY *b, BODY **cur)
       memset (&s, 0, sizeof (s));
       s.fpin = *fpout;
       fseeko (s.fpin, bb->offset, 0); 
       memset (&s, 0, sizeof (s));
       s.fpin = *fpout;
       fseeko (s.fpin, bb->offset, 0); 
-      mutt_mktemp (tempfile);
+      mutt_mktemp (tempfile, sizeof (tempfile));
       if (!(tmpfp = safe_fopen (tempfile, "w+")))
         {
           mutt_perror (tempfile);
       if (!(tmpfp = safe_fopen (tempfile, "w+")))
         {
           mutt_perror (tempfile);
@@ -1793,12 +1824,12 @@ int smime_gpgme_decrypt_mime (FILE *fpin, FILE **fpout, BODY *b, BODY **cur)
       bb->length = ftello (s.fpout);
       bb->offset = 0;
       rewind (tmpfp);
       bb->length = ftello (s.fpout);
       bb->offset = 0;
       rewind (tmpfp);
-      fclose (*fpout); 
+      safe_fclose (fpout); 
 
       memset (&s, 0, sizeof (s));
       s.fpin = tmpfp;
       s.fpout = 0;
 
       memset (&s, 0, sizeof (s));
       s.fpin = tmpfp;
       s.fpout = 0;
-      mutt_mktemp (tempfile);
+      mutt_mktemp (tempfile, sizeof (tempfile));
       if (!(*fpout = safe_fopen (tempfile, "w+")))
         {
           mutt_perror (tempfile);
       if (!(*fpout = safe_fopen (tempfile, "w+")))
         {
           mutt_perror (tempfile);
@@ -1812,7 +1843,7 @@ int smime_gpgme_decrypt_mime (FILE *fpin, FILE **fpout, BODY *b, BODY **cur)
       bb->type = saved_b_type;
       bb->length = saved_b_length;
       bb->offset = saved_b_offset;
       bb->type = saved_b_type;
       bb->length = saved_b_length;
       bb->offset = saved_b_offset;
-      fclose (tmpfp);
+      safe_fclose (&tmpfp);
       rewind (*fpout);
       mutt_free_body (cur);
       *cur = tmp_b;
       rewind (*fpout);
       mutt_free_body (cur);
       *cur = tmp_b;
@@ -1820,6 +1851,120 @@ int smime_gpgme_decrypt_mime (FILE *fpin, FILE **fpout, BODY *b, BODY **cur)
   return *cur? 0:-1;
 }
 
   return *cur? 0:-1;
 }
 
+static int pgp_gpgme_extract_keys (gpgme_data_t keydata, FILE** fp, int dryrun)
+{
+  /* there's no side-effect free way to view key data in GPGME,
+   * so we import the key into a temporary keyring */
+  char tmpdir[_POSIX_PATH_MAX];
+  char tmpfile[_POSIX_PATH_MAX];
+  gpgme_ctx_t tmpctx;
+  gpgme_error_t err;
+  gpgme_engine_info_t engineinfo;
+  gpgme_key_t key;
+  gpgme_user_id_t uid;
+  gpgme_subkey_t subkey;
+  const char* shortid;
+  int len;
+  char date[STRING];
+  int more;
+  int rc = -1;
+
+  if ((err = gpgme_new (&tmpctx)) != GPG_ERR_NO_ERROR)
+  {
+    dprint (1, (debugfile, "Error creating GPGME context\n"));
+    return rc;
+  }
+  
+  if (dryrun)
+  {
+    snprintf (tmpdir, sizeof(tmpdir), "%s/mutt-gpgme-XXXXXX", Tempdir);
+    if (!mkdtemp (tmpdir))
+    {
+      dprint (1, (debugfile, "Error creating temporary GPGME home\n"));
+      goto err_ctx;
+    }
+
+    engineinfo = gpgme_ctx_get_engine_info (tmpctx);
+    while (engineinfo && engineinfo->protocol != GPGME_PROTOCOL_OpenPGP)
+      engineinfo = engineinfo->next;
+    if (!engineinfo)
+    {
+      dprint (1, (debugfile, "Error finding GPGME PGP engine\n"));
+      goto err_tmpdir;
+    }
+
+    err = gpgme_ctx_set_engine_info (tmpctx, GPGME_PROTOCOL_OpenPGP,
+                                     engineinfo->file_name, tmpdir);
+    if (err != GPG_ERR_NO_ERROR)
+    {
+      dprint (1, (debugfile, "Error setting GPGME context home\n"));
+      goto err_tmpdir;
+    }
+  }
+
+  if ((err = gpgme_op_import (tmpctx, keydata)) != GPG_ERR_NO_ERROR)
+  {
+    dprint (1, (debugfile, "Error importing key\n"));
+    goto err_tmpdir;
+  }
+
+  mutt_mktemp (tmpfile, sizeof (tmpfile));
+  *fp = safe_fopen (tmpfile, "w+");
+  if (!*fp)
+  {
+    mutt_perror (tmpfile);
+    goto err_tmpdir;
+  }
+  unlink (tmpfile);
+
+  err = gpgme_op_keylist_start (tmpctx, NULL, 0);
+  while (!err)
+  {
+    if ((err = gpgme_op_keylist_next (tmpctx, &key)))
+      break;
+    uid = key->uids;
+    subkey = key->subkeys;
+    more = 0;
+    while (subkey)
+    {
+      shortid = subkey->keyid;
+      len = mutt_strlen (subkey->keyid);
+      if (len > 8)
+        shortid += len - 8;
+      strftime (date, sizeof (date), "%Y-%m-%d", localtime (&subkey->timestamp));
+
+      if (!more)
+        fprintf (*fp, "%s %5.5s %d/%8s %s %s\n", more ? "sub" : "pub",
+                 gpgme_pubkey_algo_name (subkey->pubkey_algo), subkey->length,
+                 shortid, date, uid->uid);
+      else
+        fprintf (*fp, "%s %5.5s %d/%8s %s\n", more ? "sub" : "pub",
+                 gpgme_pubkey_algo_name (subkey->pubkey_algo), subkey->length,
+                 shortid, date);      
+      subkey = subkey->next;
+      more = 1;
+    }
+    gpgme_key_release (key);
+  }
+  if (gpg_err_code (err) != GPG_ERR_EOF)
+  {
+    dprint (1, (debugfile, "Error listing keys\n"));
+    goto err_fp;
+  }
+
+  rc = 0;
+
+err_fp:
+  if (rc)
+    safe_fclose (fp);
+err_tmpdir:
+  if (dryrun)
+    mutt_rmtree (tmpdir);
+err_ctx:
+  gpgme_release (tmpctx);
+
+  return rc;
+}
 
 /* 
  * Implementation of `pgp_check_traditional'.
 
 /* 
  * Implementation of `pgp_check_traditional'.
@@ -1840,7 +1985,7 @@ static int pgp_check_traditional_one_body (FILE *fp, BODY *b, int tagged_only)
   if (tagged_only && !b->tagged)
     return 0;
 
   if (tagged_only && !b->tagged)
     return 0;
 
-  mutt_mktemp (tempfile);
+  mutt_mktemp (tempfile, sizeof (tempfile));
   if (mutt_decode_save_attachment (fp, b, tempfile, 0, 0) != 0)
   {
     unlink (tempfile);
   if (mutt_decode_save_attachment (fp, b, tempfile, 0, 0) != 0)
   {
     unlink (tempfile);
@@ -1903,6 +2048,37 @@ int pgp_gpgme_check_traditional (FILE *fp, BODY *b, int tagged_only)
   return rv;
 }
 
   return rv;
 }
 
+/* TODO: looks like this won't work and we'll have to fully parse the
+ * message file. GPGME makes life hard yet again. */
+void pgp_gpgme_invoke_import (const char *fname)
+{
+  gpgme_data_t keydata;
+  gpgme_error_t err;
+  FILE* in;
+  FILE* out;
+  long outlen;
+
+  if (!(in = safe_fopen (fname, "r")))
+    return;
+  if ((err = gpgme_data_new_from_stream (&keydata, in)) != GPG_ERR_NO_ERROR)
+  {
+    dprint (1, (debugfile, "error converting key file into data object\n"));
+    return;
+  }
+  safe_fclose (&in);
+
+  if (!pgp_gpgme_extract_keys (keydata, &out, 0))
+  {
+    /* display import results */
+    outlen = ftell (out);
+    fseek (out, 0, SEEK_SET);
+    mutt_copy_bytes (out, stdout, outlen);
+    safe_fclose (&out);
+  }
+  else
+    printf (_("Error extracting key data!\n"));
+}
+
 
 /* 
  * Implementation of `application_handler'.
 
 /* 
  * Implementation of `application_handler'.
@@ -1971,7 +2147,7 @@ static void copy_clearsigned (gpgme_data_t data, STATE *s, char *charset)
   }
   
   fgetconv_close (&fc);
   }
   
   fgetconv_close (&fc);
-  fclose (fp);
+  safe_fclose (&fp);
 }
 
 
 }
 
 
@@ -2026,12 +2202,11 @@ int pgp_gpgme_application_handler (BODY *m, STATE *s)
               clearsign = 1;
               needpass = 0;
             }
               clearsign = 1;
               needpass = 0;
             }
-          else if (!option (OPTDONTHANDLEPGPKEYS) &&
-                   !mutt_strcmp ("PUBLIC KEY BLOCK-----\n", buf + 15))
-            {
-              needpass = 0;
-              pgp_keyblock =1;
-            } 
+          else if (!mutt_strcmp ("PUBLIC KEY BLOCK-----\n", buf + 15))
+          {
+            needpass = 0;
+            pgp_keyblock = 1;
+          } 
           else
             {
               /* XXX - we may wish to recode here */
           else
             {
               /* XXX - we may wish to recode here */
@@ -2047,7 +2222,11 @@ int pgp_gpgme_application_handler (BODY *m, STATE *s)
           /* Copy PGP material to an data container */
          armored_data = file_to_data_object (s->fpin, m->offset, m->length);
           /* Invoke PGP if needed */
           /* Copy PGP material to an data container */
          armored_data = file_to_data_object (s->fpin, m->offset, m->length);
           /* Invoke PGP if needed */
-          if (!clearsign || (s->flags & M_VERIFY))
+          if (pgp_keyblock)
+          {
+            pgp_gpgme_extract_keys (armored_data, &pgpout, 1);
+          }
+          else if (!clearsign || (s->flags & M_VERIFY))
             {
               unsigned int sig_stat = 0;
               gpgme_data_t plaintext;
             {
               unsigned int sig_stat = 0;
               gpgme_data_t plaintext;
@@ -2089,7 +2268,7 @@ int pgp_gpgme_application_handler (BODY *m, STATE *s)
                   char *tmpfname;
 
                  {
                   char *tmpfname;
 
                  {
-                   /* Check wether signatures have been verified.  */
+                   /* Check whether signatures have been verified.  */
                    gpgme_verify_result_t verify_result;
 
                     verify_result = gpgme_op_verify_result (ctx);
                    gpgme_verify_result_t verify_result;
 
                     verify_result = gpgme_op_verify_result (ctx);
@@ -2193,12 +2372,13 @@ int pgp_gpgme_application_handler (BODY *m, STATE *s)
             }
         }
       else
             }
         }
       else
-        {
-          /* XXX - we may wish to recode here */
-          if (s->prefix)
-            state_puts (s->prefix, s);
-          state_puts (buf, s);
-        }
+      {
+       /* A traditional PGP part may mix signed and unsigned content */
+        /* XXX - we may wish to recode here */
+        if (s->prefix)
+          state_puts (s->prefix, s);
+        state_puts (buf, s);
+      }
     }
 
   m->goodsig = (maybe_goodsig && have_any_sigs);
     }
 
   m->goodsig = (maybe_goodsig && have_any_sigs);
@@ -2207,7 +2387,7 @@ int pgp_gpgme_application_handler (BODY *m, STATE *s)
     {
       state_attach_puts (_("[-- Error: could not find beginning"
                            " of PGP message! --]\n\n"), s);
     {
       state_attach_puts (_("[-- Error: could not find beginning"
                            " of PGP message! --]\n\n"), s);
-      return -1;
+      return 1;
     }
   dprint (2, (debugfile, "Leaving pgp_application_pgp handler\n"));
 
     }
   dprint (2, (debugfile, "Leaving pgp_application_pgp handler\n"));
 
@@ -2244,7 +2424,7 @@ int pgp_gpgme_encrypted_handler (BODY *a, STATE *s)
   /* Move forward to the application/pgp-encrypted body. */
   a = a->next;
 
   /* Move forward to the application/pgp-encrypted body. */
   a = a->next;
 
-  mutt_mktemp (tempfile);
+  mutt_mktemp (tempfile, sizeof (tempfile));
   if (!(fpout = safe_fopen (tempfile, "w+")))
     {
       if (s->flags & M_DISPLAY)
   if (!(fpout = safe_fopen (tempfile, "w+")))
     {
       if (s->flags & M_DISPLAY)
@@ -2291,7 +2471,7 @@ int pgp_gpgme_encrypted_handler (BODY *a, STATE *s)
       mutt_free_body (&tattach);
     }
   
       mutt_free_body (&tattach);
     }
   
-  fclose (fpout);
+  safe_fclose (&fpout);
   mutt_unlink(tempfile);
   dprint (2, (debugfile, "Leaving pgp_encrypted handler\n"));
 
   mutt_unlink(tempfile);
   dprint (2, (debugfile, "Leaving pgp_encrypted handler\n"));
 
@@ -2310,7 +2490,7 @@ int smime_gpgme_application_handler (BODY *a, STATE *s)
   dprint (2, (debugfile, "Entering smime_encrypted handler\n"));
   
   a->warnsig = 0;
   dprint (2, (debugfile, "Entering smime_encrypted handler\n"));
   
   a->warnsig = 0;
-  mutt_mktemp (tempfile);
+  mutt_mktemp (tempfile, sizeof (tempfile));
   if (!(fpout = safe_fopen (tempfile, "w+")))
     {
       if (s->flags & M_DISPLAY)
   if (!(fpout = safe_fopen (tempfile, "w+")))
     {
       if (s->flags & M_DISPLAY)
@@ -2365,7 +2545,7 @@ int smime_gpgme_application_handler (BODY *a, STATE *s)
       mutt_free_body (&tattach);
     }
   
       mutt_free_body (&tattach);
     }
   
-  fclose (fpout);
+  safe_fclose (&fpout);
   mutt_unlink(tempfile);
   dprint (2, (debugfile, "Leaving smime_encrypted handler\n"));
   
   mutt_unlink(tempfile);
   dprint (2, (debugfile, "Leaving smime_encrypted handler\n"));
   
@@ -3270,7 +3450,7 @@ verify_key (crypt_key_t *key)
   gpgme_key_t k = NULL;
   int maxdepth = 100;
 
   gpgme_key_t k = NULL;
   int maxdepth = 100;
 
-  mutt_mktemp (tempfile);
+  mutt_mktemp (tempfile, sizeof (tempfile));
   if (!(fp = safe_fopen (tempfile, "w")))
     {
       mutt_perror _("Can't create temporary file");
   if (!(fp = safe_fopen (tempfile, "w")))
     {
       mutt_perror _("Can't create temporary file");
@@ -3321,7 +3501,7 @@ verify_key (crypt_key_t *key)
  leave:
   gpgme_key_release (k);
   gpgme_release (listctx);
  leave:
   gpgme_key_release (k);
   gpgme_release (listctx);
-  fclose (fp);
+  safe_fclose (&fp);
   mutt_clear_error ();
   snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"),  crypt_keyid (key));
   mutt_do_pager (cmd, tempfile, 0, NULL);
   mutt_clear_error ();
   snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"),  crypt_keyid (key));
   mutt_do_pager (cmd, tempfile, 0, NULL);
@@ -3647,10 +3827,9 @@ static crypt_key_t *crypt_select_key (crypt_key_t *keys,
   mutt_make_help (buf, sizeof (buf), _("Help"), menu_to_use, OP_HELP);
   strcat (helpstr, buf);       /* __STRCAT_CHECKED__ */
 
   mutt_make_help (buf, sizeof (buf), _("Help"), menu_to_use, OP_HELP);
   strcat (helpstr, buf);       /* __STRCAT_CHECKED__ */
 
-  menu = mutt_new_menu ();
+  menu = mutt_new_menu (menu_to_use);
   menu->max = i;
   menu->make_entry = crypt_entry;
   menu->max = i;
   menu->make_entry = crypt_entry;
-  menu->menu = menu_to_use;
   menu->help = helpstr;
   menu->data = key_table;
 
   menu->help = helpstr;
   menu->data = key_table;
 
@@ -4056,7 +4235,7 @@ static char *find_keys (ADDRESS *to, ADDRESS *cc, ADDRESS *bcc,
         default: abort ();
         }
       
         default: abort ();
         }
       
-      *last = rfc822_cpy_adr (p);
+      *last = rfc822_cpy_adr (p, 0);
       while (*last)
         last = &((*last)->next);
     }
       while (*last)
         last = &((*last)->next);
     }
@@ -4303,37 +4482,66 @@ static int verify_sender (HEADER *h, gpgme_protocol_t protocol)
     }
 
   if (sender)
     }
 
   if (sender)
+  {
+    if (signature_key)
     {
     {
-      if (signature_key)
-       {
-         gpgme_key_t key = signature_key;
-         gpgme_user_id_t uid = NULL;
-         int sender_length = 0;
-         int uid_length = 0;
+      gpgme_key_t key = signature_key;
+      gpgme_user_id_t uid = NULL;
+      int sender_length = 0;
+      int uid_length = 0;
 
 
-         sender_length = strlen (sender->mailbox);
-         for (uid = key->uids; uid && ret; uid = uid->next)
-           {
-             uid_length = strlen (uid->email);
-             if (1
-                 && (uid->email[0] == '<')
-                 && (uid->email[uid_length - 1] == '>')
-                 && (uid_length == sender_length + 2)
-                 && (! strncmp (uid->email + 1, sender->mailbox, sender_length)))
-               ret = 0;
-           }
+      sender_length = strlen (sender->mailbox);
+      for (uid = key->uids; uid && ret; uid = uid->next)
+      {
+       uid_length = strlen (uid->email);
+       if (1
+           && (uid->email[0] == '<')
+           && (uid->email[uid_length - 1] == '>')
+           && (uid_length == sender_length + 2))
+       {
+         const char* at_sign = strchr(uid->email + 1, '@');
+         if (at_sign == NULL)
+         {
+           if (! strncmp (uid->email + 1, sender->mailbox, sender_length))
+             ret = 0;
+         }
+         else
+         {
+           /*
+            * Assume address is 'mailbox@domainname'.
+            * The mailbox part is case-sensitive,
+            * the domainname is not. (RFC 2821)
+            */
+           const char* tmp_email = uid->email + 1;
+           const char* tmp_sender = sender->mailbox;
+           /* length of mailbox part including '@' */
+           int mailbox_length = at_sign - tmp_email + 1;
+           int domainname_length = sender_length - mailbox_length;
+           int mailbox_match, domainname_match;
+
+           mailbox_match = (! strncmp (tmp_email, tmp_sender,
+               mailbox_length));
+           tmp_email += mailbox_length;
+           tmp_sender += mailbox_length;
+           domainname_match = (! strncasecmp (tmp_email, tmp_sender,
+               domainname_length));
+           if (mailbox_match && domainname_match)
+             ret = 0;
+         }
        }
        }
-      else
-       mutt_any_key_to_continue (_("Failed to verify sender"));
+      }
     }
     }
+    else
+      mutt_any_key_to_continue (_("Failed to verify sender"));
+  }
   else
     mutt_any_key_to_continue (_("Failed to figure out sender"));
 
   if (signature_key)
   else
     mutt_any_key_to_continue (_("Failed to figure out sender"));
 
   if (signature_key)
-    {
-      gpgme_key_release (signature_key);
-      signature_key = NULL;
-    }
+  {
+    gpgme_key_release (signature_key);
+    signature_key = NULL;
+  }
 
   return ret;
 }
 
   return ret;
 }