]> granicus.if.org Git - mutt/commitdiff
Process autocrypt headers.
authorKevin McCarthy <kevin@8t8.us>
Fri, 12 Jul 2019 01:45:45 +0000 (18:45 -0700)
committerKevin McCarthy <kevin@8t8.us>
Sat, 3 Aug 2019 21:08:09 +0000 (14:08 -0700)
Create/update peer database accounts and gpg keys based on the headers.

autocrypt/autocrypt.c
autocrypt/autocrypt.h
autocrypt/autocrypt_db.c
autocrypt/autocrypt_gpgme.c
autocrypt/autocrypt_private.h
mutt.h
parse.c
protos.h

index c9269bcf4e6fc99b432b123aaa35ac12c47aa39a..5207af4ba320f2a511bfa452b437d2c560c1a85c 100644 (file)
 
 #include "mutt.h"
 #include "mutt_curses.h"
+#include "mime.h"
 #include "autocrypt.h"
 #include "autocrypt_private.h"
 
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
 #include <errno.h>
 
 static int autocrypt_dir_init (int can_create)
@@ -156,3 +160,145 @@ cleanup:
   mutt_buffer_pool_release (&keydata);
   return rv;
 }
+
+int mutt_autocrypt_process_autocrypt_header (HEADER *hdr, ENVELOPE *env)
+{
+  AUTOCRYPTHDR *ac_hdr, *valid_ac_hdr = NULL;
+  struct timeval now;
+  AUTOCRYPT_PEER *peer = NULL;
+  AUTOCRYPT_PEER_HISTORY *peerhist = NULL;
+  BUFFER *keyid = NULL;
+  int update_db = 0, insert_db = 0, insert_db_history = 0, import_gpg = 0;
+  int rv = -1;
+
+  if (!option (OPTAUTOCRYPT))
+    return 0;
+
+  if (mutt_autocrypt_init (0))
+    return -1;
+
+  if (!hdr || !hdr->content || !env)
+    return 0;
+
+  /* 1.1 spec says to skip emails with more than one From header */
+  if (!env->from || env->from->next)
+    return 0;
+
+  /* 1.1 spec also says to skip multipart/report emails */
+  if (hdr->content->type == TYPEMULTIPART &&
+      !(ascii_strcasecmp (hdr->content->subtype, "report")))
+    return 0;
+
+  /* Ignore emails that appear to be more than a week in the future,
+   * since they can block all future updates during that time. */
+  gettimeofday (&now, NULL);
+  if (hdr->date_sent > (now.tv_sec + 7 * 24 * 60 * 60))
+    return 0;
+
+  for (ac_hdr = env->autocrypt; ac_hdr; ac_hdr = ac_hdr->next)
+  {
+    if (ac_hdr->invalid)
+      continue;
+
+    /* NOTE: this assumes the processing is occurring right after
+     * mutt_parse_rfc822_line() and the from ADDR is still in the same
+     * form (intl) as the autocrypt header addr field */
+    if (ascii_strcasecmp (env->from->mailbox, ac_hdr->addr))
+      continue;
+
+    /* 1.1 spec says ignore all, if more than one valid header is found. */
+    if (valid_ac_hdr)
+    {
+      valid_ac_hdr = NULL;
+      break;
+    }
+    valid_ac_hdr = ac_hdr;
+  }
+
+  if (mutt_autocrypt_db_peer_get (env->from, &peer) < 0)
+    goto cleanup;
+
+  if (peer)
+  {
+    if (hdr->date_sent <= peer->autocrypt_timestamp)
+    {
+      rv = 0;
+      goto cleanup;
+    }
+
+    if (hdr->date_sent > peer->last_seen)
+    {
+      update_db = 1;
+      peer->last_seen = hdr->date_sent;
+    }
+
+    if (valid_ac_hdr)
+    {
+      update_db = 1;
+      peer->autocrypt_timestamp = hdr->date_sent;
+      peer->prefer_encrypt = valid_ac_hdr->prefer_encrypt;
+      if (mutt_strcmp (peer->keydata, valid_ac_hdr->keydata))
+      {
+        import_gpg = 1;
+        insert_db_history = 1;
+        mutt_str_replace (&peer->keydata, valid_ac_hdr->keydata);
+      }
+    }
+  }
+  else if (valid_ac_hdr)
+  {
+    import_gpg = 1;
+    insert_db = 1;
+    insert_db_history = 1;
+  }
+
+  if (!(import_gpg || insert_db || update_db))
+  {
+    rv = 0;
+    goto cleanup;
+  }
+
+  if (!peer)
+  {
+    peer = mutt_autocrypt_db_peer_new ();
+    peer->last_seen = hdr->date_sent;
+    peer->autocrypt_timestamp = hdr->date_sent;
+    peer->keydata = safe_strdup (valid_ac_hdr->keydata);
+    peer->prefer_encrypt = valid_ac_hdr->prefer_encrypt;
+  }
+
+  if (import_gpg)
+  {
+    keyid = mutt_buffer_pool_get ();
+    if (mutt_autocrypt_gpgme_import_key (peer->keydata, keyid))
+      goto cleanup;
+    mutt_str_replace (&peer->keyid, mutt_b2s (keyid));
+  }
+
+  if (insert_db &&
+      mutt_autocrypt_db_peer_insert (env->from, peer))
+    goto cleanup;
+
+  if (update_db &&
+      mutt_autocrypt_db_peer_update (env->from, peer))
+    goto cleanup;
+
+  if (insert_db_history)
+  {
+    peerhist = mutt_autocrypt_db_peer_history_new ();
+    peerhist->email_msgid = safe_strdup (env->message_id);
+    peerhist->timestamp = hdr->date_sent;
+    peerhist->keydata = safe_strdup (peer->keydata);
+    if (mutt_autocrypt_db_peer_history_insert (env->from, peerhist))
+      goto cleanup;
+  }
+
+  rv = 0;
+
+cleanup:
+  mutt_autocrypt_db_peer_free (&peer);
+  mutt_autocrypt_db_peer_history_free (&peerhist);
+  mutt_buffer_pool_release (&keyid);
+
+  return rv;
+}
index c690fae256552b68c022bce33ce1d08f015ff920..859a708a1bbe08546e0f823522d8becf43d942b1 100644 (file)
@@ -32,7 +32,29 @@ typedef struct
   int enabled;
 } AUTOCRYPT_ACCOUNT;
 
+typedef struct
+{
+  char *email_addr;
+  sqlite3_int64 last_seen;
+  sqlite3_int64 autocrypt_timestamp;
+  char *keyid;
+  char *keydata;
+  int prefer_encrypt;    /* 0 = nopref, 1 = mutual */
+  sqlite3_int64 gossip_timestamp;
+  char *gossip_keyid;
+  char *gossip_keydata;
+} AUTOCRYPT_PEER;
+
+typedef struct
+{
+  char *peer_email_addr;
+  char *email_msgid;
+  sqlite3_int64 timestamp;
+  char *keydata;
+} AUTOCRYPT_PEER_HISTORY;
+
 int mutt_autocrypt_init (int);
 void mutt_autocrypt_cleanup (void);
+int mutt_autocrypt_process_autocrypt_header (HEADER *hdr, ENVELOPE *env);
 
 #endif
index a053c433c83d72746a7ece2c35d5084b7441de8a..604c1f340fe7c050330906867e1547e7ebd92315 100644 (file)
 #include "autocrypt.h"
 #include "autocrypt_private.h"
 
+/* Prepared statements */
+static sqlite3_stmt *AccountGetStmt;
+static sqlite3_stmt *AccountInsertStmt;
+static sqlite3_stmt *PeerGetStmt;
+static sqlite3_stmt *PeerInsertStmt;
+static sqlite3_stmt *PeerUpdateStmt;
+static sqlite3_stmt *PeerHistoryInsertStmt;
+
 static int autocrypt_db_create (const char *db_path)
 {
   if (sqlite3_open_v2 (db_path,
@@ -96,6 +104,16 @@ void mutt_autocrypt_db_close (void)
   sqlite3_finalize (AccountInsertStmt);
   AccountInsertStmt = NULL;
 
+  sqlite3_finalize (PeerGetStmt);
+  PeerGetStmt = NULL;
+  sqlite3_finalize (PeerInsertStmt);
+  PeerInsertStmt = NULL;
+  sqlite3_finalize (PeerUpdateStmt);
+  PeerUpdateStmt = NULL;
+
+  sqlite3_finalize (PeerHistoryInsertStmt);
+  PeerHistoryInsertStmt = NULL;
+
   sqlite3_close_v2 (AutocryptDB);
   AutocryptDB = NULL;
 }
@@ -263,3 +281,327 @@ cleanup:
   sqlite3_reset (AccountInsertStmt);
   return rv;
 }
+
+AUTOCRYPT_PEER *mutt_autocrypt_db_peer_new (void)
+{
+  return safe_calloc (1, sizeof(AUTOCRYPT_PEER));
+}
+
+void mutt_autocrypt_db_peer_free (AUTOCRYPT_PEER **peer)
+{
+  if (!peer || !*peer)
+    return;
+  FREE (&(*peer)->email_addr);
+  FREE (&(*peer)->keyid);
+  FREE (&(*peer)->keydata);
+  FREE (&(*peer)->gossip_keyid);
+  FREE (&(*peer)->gossip_keydata);
+  FREE (peer);      /* __FREE_CHECKED__ */
+}
+
+int mutt_autocrypt_db_peer_get (ADDRESS *addr, AUTOCRYPT_PEER **peer)
+{
+  int rv = -1, result;
+  char *email = NULL;
+
+  email = normalize_email_addr (addr);
+  *peer = NULL;
+
+  if (!PeerGetStmt)
+  {
+    if (sqlite3_prepare_v2 (
+          AutocryptDB,
+          "SELECT "
+          "email_addr, "
+          "last_seen, "
+          "autocrypt_timestamp, "
+          "keyid, "
+          "keydata, "
+          "prefer_encrypt, "
+          "gossip_timestamp, "
+          "gossip_keyid, "
+          "gossip_keydata "
+          "FROM peer "
+          "WHERE email_addr = ?",
+          -1,
+          &PeerGetStmt,
+          NULL) != SQLITE_OK)
+      goto cleanup;
+  }
+
+  if (sqlite3_bind_text (PeerGetStmt,
+                         1,
+                         email,
+                         -1,
+                         SQLITE_STATIC) != SQLITE_OK)
+    goto cleanup;
+
+  result = sqlite3_step (PeerGetStmt);
+  if (result != SQLITE_ROW)
+  {
+    if (result == SQLITE_DONE)
+      rv = 0;
+    goto cleanup;
+  }
+
+  *peer = mutt_autocrypt_db_peer_new ();
+  (*peer)->email_addr = strdup_column_text (PeerGetStmt, 0);
+  (*peer)->last_seen = sqlite3_column_int64 (PeerGetStmt, 1);
+  (*peer)->autocrypt_timestamp = sqlite3_column_int64 (PeerGetStmt, 2);
+  (*peer)->keyid = strdup_column_text (PeerGetStmt, 3);
+  (*peer)->keydata = strdup_column_text (PeerGetStmt, 4);
+  (*peer)->prefer_encrypt = sqlite3_column_int (PeerGetStmt, 5);
+  (*peer)->gossip_timestamp = sqlite3_column_int64 (PeerGetStmt, 6);
+  (*peer)->gossip_keyid = strdup_column_text (PeerGetStmt, 7);
+  (*peer)->gossip_keydata = strdup_column_text (PeerGetStmt, 8);
+
+  rv = 1;
+
+cleanup:
+  FREE (&email);
+  sqlite3_reset (PeerGetStmt);
+  return rv;
+}
+
+int mutt_autocrypt_db_peer_insert (ADDRESS *addr, AUTOCRYPT_PEER *peer)
+{
+  int rv = -1;
+  char *email = NULL;
+
+  email = normalize_email_addr (addr);
+
+  if (!PeerInsertStmt)
+  {
+    if (sqlite3_prepare_v2 (
+          AutocryptDB,
+          "INSERT INTO peer "
+          "(email_addr, "
+          "last_seen, "
+          "autocrypt_timestamp, "
+          "keyid, "
+          "keydata, "
+          "prefer_encrypt, "
+          "gossip_timestamp, "
+          "gossip_keyid, "
+          "gossip_keydata) "
+          "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);",
+          -1,
+          &PeerInsertStmt,
+          NULL) != SQLITE_OK)
+      goto cleanup;
+  }
+
+  if (sqlite3_bind_text (PeerInsertStmt,
+                         1,
+                         email,
+                         -1,
+                         SQLITE_STATIC) != SQLITE_OK)
+    goto cleanup;
+  if (sqlite3_bind_int64 (PeerInsertStmt,
+                          2,
+                          peer->last_seen) != SQLITE_OK)
+    goto cleanup;
+  if (sqlite3_bind_int64 (PeerInsertStmt,
+                          3,
+                          peer->autocrypt_timestamp) != SQLITE_OK)
+    goto cleanup;
+  if (sqlite3_bind_text (PeerInsertStmt,
+                         4,
+                         peer->keyid,
+                         -1,
+                         SQLITE_STATIC) != SQLITE_OK)
+    goto cleanup;
+  if (sqlite3_bind_text (PeerInsertStmt,
+                         5,
+                         peer->keydata,
+                         -1,
+                         SQLITE_STATIC) != SQLITE_OK)
+    goto cleanup;
+  if (sqlite3_bind_int (PeerInsertStmt,
+                        6,
+                        peer->prefer_encrypt) != SQLITE_OK)
+    goto cleanup;
+  if (sqlite3_bind_int64 (PeerInsertStmt,
+                          7,
+                          peer->gossip_timestamp) != SQLITE_OK)
+    goto cleanup;
+  if (sqlite3_bind_text (PeerInsertStmt,
+                         8,
+                         peer->gossip_keyid,
+                         -1,
+                         SQLITE_STATIC) != SQLITE_OK)
+    goto cleanup;
+  if (sqlite3_bind_text (PeerInsertStmt,
+                         9,
+                         peer->gossip_keydata,
+                         -1,
+                         SQLITE_STATIC) != SQLITE_OK)
+    goto cleanup;
+
+  if (sqlite3_step (PeerInsertStmt) != SQLITE_DONE)
+    goto cleanup;
+
+  rv = 0;
+
+cleanup:
+  FREE (&email);
+  sqlite3_reset (PeerInsertStmt);
+  return rv;
+}
+
+int mutt_autocrypt_db_peer_update (ADDRESS *addr, AUTOCRYPT_PEER *peer)
+{
+  int rv = -1;
+  char *email = NULL;
+
+  email = normalize_email_addr (addr);
+
+  if (!PeerUpdateStmt)
+  {
+    if (sqlite3_prepare_v2 (
+          AutocryptDB,
+          "UPDATE peer SET "
+          "last_seen = ?, "
+          "autocrypt_timestamp = ?, "
+          "keyid = ?, "
+          "keydata = ?, "
+          "prefer_encrypt = ?, "
+          "gossip_timestamp = ?, "
+          "gossip_keyid = ?, "
+          "gossip_keydata = ? "
+          "WHERE email_addr = ?;",
+          -1,
+          &PeerUpdateStmt,
+          NULL) != SQLITE_OK)
+      goto cleanup;
+  }
+
+  if (sqlite3_bind_int64 (PeerUpdateStmt,
+                          1,
+                          peer->last_seen) != SQLITE_OK)
+    goto cleanup;
+  if (sqlite3_bind_int64 (PeerUpdateStmt,
+                          2,
+                          peer->autocrypt_timestamp) != SQLITE_OK)
+    goto cleanup;
+  if (sqlite3_bind_text (PeerUpdateStmt,
+                         3,
+                         peer->keyid,
+                         -1,
+                         SQLITE_STATIC) != SQLITE_OK)
+    goto cleanup;
+  if (sqlite3_bind_text (PeerUpdateStmt,
+                         4,
+                         peer->keydata,
+                         -1,
+                         SQLITE_STATIC) != SQLITE_OK)
+    goto cleanup;
+  if (sqlite3_bind_int (PeerUpdateStmt,
+                        5,
+                        peer->prefer_encrypt) != SQLITE_OK)
+    goto cleanup;
+  if (sqlite3_bind_int64 (PeerUpdateStmt,
+                          6,
+                          peer->gossip_timestamp) != SQLITE_OK)
+    goto cleanup;
+  if (sqlite3_bind_text (PeerUpdateStmt,
+                         7,
+                         peer->gossip_keyid,
+                         -1,
+                         SQLITE_STATIC) != SQLITE_OK)
+    goto cleanup;
+  if (sqlite3_bind_text (PeerUpdateStmt,
+                         8,
+                         peer->gossip_keydata,
+                         -1,
+                         SQLITE_STATIC) != SQLITE_OK)
+    goto cleanup;
+  if (sqlite3_bind_text (PeerUpdateStmt,
+                         9,
+                         email,
+                         -1,
+                         SQLITE_STATIC) != SQLITE_OK)
+    goto cleanup;
+
+  if (sqlite3_step (PeerUpdateStmt) != SQLITE_DONE)
+    goto cleanup;
+
+  rv = 0;
+
+cleanup:
+  FREE (&email);
+  sqlite3_reset (PeerUpdateStmt);
+  return rv;
+}
+
+AUTOCRYPT_PEER_HISTORY *mutt_autocrypt_db_peer_history_new (void)
+{
+  return safe_calloc (1, sizeof(AUTOCRYPT_PEER_HISTORY));
+}
+
+void mutt_autocrypt_db_peer_history_free (AUTOCRYPT_PEER_HISTORY **peerhist)
+{
+  if (!peerhist || !*peerhist)
+    return;
+  FREE (&(*peerhist)->peer_email_addr);
+  FREE (&(*peerhist)->email_msgid);
+  FREE (&(*peerhist)->keydata);
+  FREE (peerhist);      /* __FREE_CHECKED__ */
+}
+
+int mutt_autocrypt_db_peer_history_insert (ADDRESS *addr, AUTOCRYPT_PEER_HISTORY *peerhist)
+{
+  int rv = -1;
+  char *email = NULL;
+
+  email = normalize_email_addr (addr);
+
+  if (!PeerHistoryInsertStmt)
+  {
+    if (sqlite3_prepare_v2 (
+          AutocryptDB,
+          "INSERT INTO peer_history "
+          "(peer_email_addr, "
+          "email_msgid, "
+          "timestamp, "
+          "keydata) "
+          "VALUES (?, ?, ?, ?);",
+          -1,
+          &PeerHistoryInsertStmt,
+          NULL) != SQLITE_OK)
+      goto cleanup;
+  }
+
+  if (sqlite3_bind_text (PeerHistoryInsertStmt,
+                         1,
+                         email,
+                         -1,
+                         SQLITE_STATIC) != SQLITE_OK)
+    goto cleanup;
+  if (sqlite3_bind_text (PeerHistoryInsertStmt,
+                         2,
+                         peerhist->email_msgid,
+                         -1,
+                         SQLITE_STATIC) != SQLITE_OK)
+    goto cleanup;
+  if (sqlite3_bind_int64 (PeerHistoryInsertStmt,
+                          3,
+                          peerhist->timestamp) != SQLITE_OK)
+    goto cleanup;
+  if (sqlite3_bind_text (PeerHistoryInsertStmt,
+                         4,
+                         peerhist->keydata,
+                         -1,
+                         SQLITE_STATIC) != SQLITE_OK)
+    goto cleanup;
+
+  if (sqlite3_step (PeerHistoryInsertStmt) != SQLITE_DONE)
+    goto cleanup;
+
+  rv = 0;
+
+cleanup:
+  FREE (&email);
+  sqlite3_reset (PeerHistoryInsertStmt);
+  return rv;
+}
index f37fca7faf415c2590ac0d5d687b067216b0add7..952f648b45f1e1fc89d289e645de5fa5fd47eea1 100644 (file)
@@ -176,3 +176,39 @@ cleanup:
   gpgme_release (ctx);
   return rv;
 }
+
+int mutt_autocrypt_gpgme_import_key (const char *keydata, BUFFER *keyid)
+{
+  int rv = -1;
+  gpgme_ctx_t ctx = NULL;
+  BUFFER *raw_keydata = NULL;
+  gpgme_data_t dh = NULL;
+  gpgme_import_result_t result;
+
+  if (create_gpgme_context (&ctx))
+    goto cleanup;
+
+  raw_keydata = mutt_buffer_pool_get ();
+  if (!mutt_buffer_from_base64 (raw_keydata, keydata))
+    goto cleanup;
+
+  if (gpgme_data_new_from_mem (&dh, mutt_b2s (raw_keydata),
+                               mutt_buffer_len (raw_keydata), 0))
+    goto cleanup;
+
+  if (gpgme_op_import (ctx, dh))
+    goto cleanup;
+
+  result = gpgme_op_import_result (ctx);
+  if (!result->imports || !result->imports->fpr)
+    goto cleanup;
+  mutt_buffer_strcpy (keyid, result->imports->fpr);
+
+  rv = 0;
+
+cleanup:
+  gpgme_data_release (dh);
+  gpgme_release (ctx);
+  mutt_buffer_pool_release (&raw_keydata);
+  return rv;
+}
index 8bb757a3a0972855e50881f1c79451283ddc25a3..d43c9e83ec3403f31beb3d6c244d1bd000f9ab0a 100644 (file)
@@ -32,14 +32,21 @@ int mutt_autocrypt_db_account_get (ADDRESS *addr, AUTOCRYPT_ACCOUNT **account);
 int mutt_autocrypt_db_account_insert (ADDRESS *addr, const char *keyid,
                                       const char *keydata, int prefer_encrypt);
 
+AUTOCRYPT_PEER *mutt_autocrypt_db_peer_new (void);
+void mutt_autocrypt_db_peer_free (AUTOCRYPT_PEER **peer);
+int mutt_autocrypt_db_peer_get (ADDRESS *addr, AUTOCRYPT_PEER **peer);
+int mutt_autocrypt_db_peer_insert (ADDRESS *addr, AUTOCRYPT_PEER *peer);
+int mutt_autocrypt_db_peer_update (ADDRESS *addr, AUTOCRYPT_PEER *peer);
+
+AUTOCRYPT_PEER_HISTORY *mutt_autocrypt_db_peer_history_new (void);
+void mutt_autocrypt_db_peer_history_free (AUTOCRYPT_PEER_HISTORY **peerhist);
+int mutt_autocrypt_db_peer_history_insert (ADDRESS *addr, AUTOCRYPT_PEER_HISTORY *peerhist);
+
 int mutt_autocrypt_schema_init (void);
 int mutt_autocrypt_schema_update (void);
 
 int mutt_autocrypt_gpgme_init (void);
 int mutt_autocrypt_gpgme_create_key (ADDRESS *addr, BUFFER *keyid, BUFFER *keydata);
-
-/* Prepared statements */
-sqlite3_stmt *AccountGetStmt;
-sqlite3_stmt *AccountInsertStmt;
+int mutt_autocrypt_gpgme_import_key (const char *keydata, BUFFER *keyid);
 
 #endif
diff --git a/mutt.h b/mutt.h
index 7e6cdc5a8ee2c03369fa3ef3ffc4cbdac4e04d57..d15ab1068e5fe903ce7523ec6cecfe120d8d5948 100644 (file)
--- a/mutt.h
+++ b/mutt.h
@@ -680,7 +680,7 @@ typedef struct autocrypt
   char *keydata;
   unsigned int prefer_encrypt : 1;
   unsigned int invalid : 1;
-  struct autocrypt *next;           /* used by gossip headers */
+  struct autocrypt *next;
 } AUTOCRYPTHDR;
 #endif
 
diff --git a/parse.c b/parse.c
index 50b23b37da91045ca07ae8c02348dda4b4361ced..8dd9240a23d8f8b947a3a4c8a7d73457bf6e2f57 100644 (file)
--- a/parse.c
+++ b/parse.c
 #include "mutt_crypt.h"
 #include "url.h"
 
+#ifdef USE_AUTOCRYPT
+#include "autocrypt/autocrypt.h"
+#endif
+
 #include <string.h>
 #include <ctype.h>
 #include <sys/stat.h>
@@ -1131,8 +1135,11 @@ int mutt_parse_rfc822_line (ENVELOPE *e, HEADER *hdr, char *line, char *p, short
 #ifdef USE_AUTOCRYPT
       else if (ascii_strcasecmp (line+1, "utocrypt") == 0)
       {
-        e->autocrypt = parse_autocrypt (e->autocrypt, p);
-        matched = 1;
+        if (option (OPTAUTOCRYPT))
+        {
+          e->autocrypt = parse_autocrypt (e->autocrypt, p);
+          matched = 1;
+        }
       }
 #endif
       break;
@@ -1600,6 +1607,15 @@ ENVELOPE *mutt_read_rfc822_header (FILE *f, HEADER *hdr, short user_hdrs,
       dprint(1,(debugfile,"read_rfc822_header(): no date found, using received time from msg separator\n"));
       hdr->date_sent = hdr->received;
     }
+
+#ifdef USE_AUTOCRYPT
+    if (option (OPTAUTOCRYPT))
+    {
+      mutt_autocrypt_process_autocrypt_header (hdr, e);
+      /* No sense in taking up memory after the header is processed */
+      mutt_free_autocrypthdr (&e->autocrypt);
+    }
+#endif
   }
 
   return (e);
index 8a0616ba52d7f422b3592450a0a5c970c482797c..8eec3b1558f06d2ff40df89d36f8fa68918d452b 100644 (file)
--- a/protos.h
+++ b/protos.h
@@ -220,6 +220,9 @@ void mutt_format_s_tree (char *, size_t, const char *, const char *);
 void mutt_forward_intro (CONTEXT *ctx, HEADER *cur, FILE *fp);
 void mutt_forward_trailer (CONTEXT *ctx, HEADER *cur, FILE *fp);
 void mutt_free_alias (ALIAS **);
+#ifdef USE_AUTOCRYPT
+void mutt_free_autocrypthdr (AUTOCRYPTHDR **p);
+#endif
 void mutt_free_body (BODY **);
 void mutt_free_color (int fg, int bg);
 void mutt_free_enter_state (ENTER_STATE **);