]> granicus.if.org Git - mutt/commitdiff
Add gossip header processing.
authorKevin McCarthy <kevin@8t8.us>
Tue, 16 Jul 2019 01:36:57 +0000 (18:36 -0700)
committerKevin McCarthy <kevin@8t8.us>
Sat, 3 Aug 2019 21:08:09 +0000 (14:08 -0700)
autocrypt/autocrypt.c
autocrypt/autocrypt.h
autocrypt/autocrypt_db.c
autocrypt/autocrypt_private.h
commands.c
mutt.h
muttlib.c
parse.c

index 5207af4ba320f2a511bfa452b437d2c560c1a85c..73fe536499a6cfcfb1bc4957a4552332dccc8b67 100644 (file)
@@ -23,6 +23,7 @@
 #include "mutt.h"
 #include "mutt_curses.h"
 #include "mime.h"
+#include "mutt_idna.h"
 #include "autocrypt.h"
 #include "autocrypt_private.h"
 
@@ -302,3 +303,141 @@ cleanup:
 
   return rv;
 }
+
+static ADDRESS *matching_gossip_address (ENVELOPE *env, const char *addr)
+{
+  ADDRESS *cur;
+
+  for (cur = env->to; cur; cur = cur->next)
+    if (!ascii_strcasecmp (cur->mailbox, addr))
+      return cur;
+
+  for (cur = env->cc; cur; cur = cur->next)
+    if (!ascii_strcasecmp (cur->mailbox, addr))
+      return cur;
+
+  for (cur = env->reply_to; cur; cur = cur->next)
+    if (!ascii_strcasecmp (cur->mailbox, addr))
+      return cur;
+
+  return NULL;
+}
+
+int mutt_autocrypt_process_gossip_header (HEADER *hdr, ENVELOPE *env)
+{
+  AUTOCRYPTHDR *ac_hdr;
+  struct timeval now;
+  AUTOCRYPT_PEER *peer = NULL;
+  AUTOCRYPT_GOSSIP_HISTORY *gossip_hist = NULL;
+  ADDRESS *peer_addr;
+  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;
+
+  if (!env->from)
+    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;
+
+  keyid = mutt_buffer_pool_get ();
+
+  /* To ensure the address headers match the gossip header format */
+  mutt_env_to_intl (env, NULL, NULL);
+
+  for (ac_hdr = env->autocrypt_gossip; ac_hdr; ac_hdr = ac_hdr->next)
+  {
+    if (ac_hdr->invalid)
+      continue;
+
+    peer_addr = matching_gossip_address (env, ac_hdr->addr);
+    if (!peer_addr)
+      continue;
+
+    if (mutt_autocrypt_db_peer_get (env->from, &peer) < 0)
+      goto cleanup;
+
+    if (peer)
+    {
+      if (hdr->date_sent <= peer->gossip_timestamp)
+      {
+        mutt_autocrypt_db_peer_free (&peer);
+        continue;
+      }
+
+      update_db = 1;
+      peer->gossip_timestamp = hdr->date_sent;
+      if (mutt_strcmp (peer->gossip_keydata, ac_hdr->keydata))
+      {
+        import_gpg = 1;
+        insert_db_history = 1;
+        mutt_str_replace (&peer->gossip_keydata, ac_hdr->keydata);
+      }
+    }
+    else
+    {
+      import_gpg = 1;
+      insert_db = 1;
+      insert_db_history = 1;
+    }
+
+    if (!peer)
+    {
+      peer = mutt_autocrypt_db_peer_new ();
+      peer->gossip_timestamp = hdr->date_sent;
+      peer->gossip_keydata = safe_strdup (ac_hdr->keydata);
+    }
+
+    if (import_gpg)
+    {
+      if (mutt_autocrypt_gpgme_import_key (peer->gossip_keydata, keyid))
+        goto cleanup;
+      mutt_str_replace (&peer->gossip_keyid, mutt_b2s (keyid));
+    }
+
+    if (insert_db &&
+        mutt_autocrypt_db_peer_insert (peer_addr, peer))
+      goto cleanup;
+
+    if (update_db &&
+        mutt_autocrypt_db_peer_update (peer_addr, peer))
+      goto cleanup;
+
+    if (insert_db_history)
+    {
+      gossip_hist = mutt_autocrypt_db_gossip_history_new ();
+      gossip_hist->sender_email_addr = safe_strdup (env->from->mailbox);
+      gossip_hist->email_msgid = safe_strdup (env->message_id);
+      gossip_hist->timestamp = hdr->date_sent;
+      gossip_hist->gossip_keydata = safe_strdup (peer->gossip_keydata);
+      if (mutt_autocrypt_db_gossip_history_insert (peer_addr, gossip_hist))
+        goto cleanup;
+    }
+
+    mutt_autocrypt_db_peer_free (&peer);
+    mutt_autocrypt_db_gossip_history_free (&gossip_hist);
+    mutt_buffer_clear (keyid);
+    update_db = insert_db = insert_db_history = import_gpg = 0;
+  }
+
+  rv = 0;
+
+cleanup:
+  mutt_autocrypt_db_peer_free (&peer);
+  mutt_autocrypt_db_gossip_history_free (&gossip_hist);
+  mutt_buffer_pool_release (&keyid);
+
+  return rv;
+}
index 859a708a1bbe08546e0f823522d8becf43d942b1..a2401bc3855a0ff862ca7c3dc6a09568ba00f6a9 100644 (file)
@@ -53,8 +53,18 @@ typedef struct
   char *keydata;
 } AUTOCRYPT_PEER_HISTORY;
 
+typedef struct
+{
+  char *peer_email_addr;
+  char *sender_email_addr;
+  char *email_msgid;
+  sqlite3_int64 timestamp;
+  char *gossip_keydata;
+} AUTOCRYPT_GOSSIP_HISTORY;
+
 int mutt_autocrypt_init (int);
 void mutt_autocrypt_cleanup (void);
 int mutt_autocrypt_process_autocrypt_header (HEADER *hdr, ENVELOPE *env);
+int mutt_autocrypt_process_gossip_header (HEADER *hdr, ENVELOPE *env);
 
 #endif
index d549d678b578ffbfc1deea00ac5d2ffa65a60adf..8b0ff0b38775f85a4faf8f4651b3eb6e05c76317 100644 (file)
@@ -32,6 +32,7 @@ static sqlite3_stmt *PeerGetStmt;
 static sqlite3_stmt *PeerInsertStmt;
 static sqlite3_stmt *PeerUpdateStmt;
 static sqlite3_stmt *PeerHistoryInsertStmt;
+static sqlite3_stmt *GossipHistoryInsertStmt;
 
 static int autocrypt_db_create (const char *db_path)
 {
@@ -114,6 +115,9 @@ void mutt_autocrypt_db_close (void)
   sqlite3_finalize (PeerHistoryInsertStmt);
   PeerHistoryInsertStmt = NULL;
 
+  sqlite3_finalize (GossipHistoryInsertStmt);
+  GossipHistoryInsertStmt = NULL;
+
   sqlite3_close_v2 (AutocryptDB);
   AutocryptDB = NULL;
 }
@@ -611,3 +615,83 @@ cleanup:
   sqlite3_reset (PeerHistoryInsertStmt);
   return rv;
 }
+
+AUTOCRYPT_GOSSIP_HISTORY *mutt_autocrypt_db_gossip_history_new (void)
+{
+  return safe_calloc (1, sizeof(AUTOCRYPT_GOSSIP_HISTORY));
+}
+
+void mutt_autocrypt_db_gossip_history_free (AUTOCRYPT_GOSSIP_HISTORY **gossip_hist)
+{
+  if (!gossip_hist || !*gossip_hist)
+    return;
+  FREE (&(*gossip_hist)->peer_email_addr);
+  FREE (&(*gossip_hist)->sender_email_addr);
+  FREE (&(*gossip_hist)->email_msgid);
+  FREE (&(*gossip_hist)->gossip_keydata);
+  FREE (gossip_hist);      /* __FREE_CHECKED__ */
+}
+
+int mutt_autocrypt_db_gossip_history_insert (ADDRESS *addr, AUTOCRYPT_GOSSIP_HISTORY *gossip_hist)
+{
+  int rv = -1;
+  char *email = NULL;
+
+  email = normalize_email_addr (addr);
+
+  if (!GossipHistoryInsertStmt)
+  {
+    if (sqlite3_prepare_v3 (
+          AutocryptDB,
+          "INSERT INTO gossip_history "
+          "(peer_email_addr, "
+          "sender_email_addr, "
+          "email_msgid, "
+          "timestamp, "
+          "gossip_keydata) "
+          "VALUES (?, ?, ?, ?, ?);",
+          -1,
+          SQLITE_PREPARE_PERSISTENT,
+          &GossipHistoryInsertStmt,
+          NULL) != SQLITE_OK)
+      goto cleanup;
+  }
+
+  if (sqlite3_bind_text (GossipHistoryInsertStmt,
+                         1,
+                         email,
+                         -1,
+                         SQLITE_STATIC) != SQLITE_OK)
+    goto cleanup;
+  if (sqlite3_bind_text (GossipHistoryInsertStmt,
+                         2,
+                         gossip_hist->sender_email_addr,
+                         -1,
+                         SQLITE_STATIC) != SQLITE_OK)
+  if (sqlite3_bind_text (GossipHistoryInsertStmt,
+                         3,
+                         gossip_hist->email_msgid,
+                         -1,
+                         SQLITE_STATIC) != SQLITE_OK)
+    goto cleanup;
+  if (sqlite3_bind_int64 (GossipHistoryInsertStmt,
+                          4,
+                          gossip_hist->timestamp) != SQLITE_OK)
+    goto cleanup;
+  if (sqlite3_bind_text (GossipHistoryInsertStmt,
+                         5,
+                         gossip_hist->gossip_keydata,
+                         -1,
+                         SQLITE_STATIC) != SQLITE_OK)
+    goto cleanup;
+
+  if (sqlite3_step (GossipHistoryInsertStmt) != SQLITE_DONE)
+    goto cleanup;
+
+  rv = 0;
+
+cleanup:
+  FREE (&email);
+  sqlite3_reset (GossipHistoryInsertStmt);
+  return rv;
+}
index d43c9e83ec3403f31beb3d6c244d1bd000f9ab0a..de8638f9dd7c7deda1bc3cfbe078159da7f96053 100644 (file)
@@ -42,6 +42,10 @@ 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);
 
+AUTOCRYPT_GOSSIP_HISTORY *mutt_autocrypt_db_gossip_history_new (void);
+void mutt_autocrypt_db_gossip_history_free (AUTOCRYPT_GOSSIP_HISTORY **gossip_hist);
+int mutt_autocrypt_db_gossip_history_insert (ADDRESS *addr, AUTOCRYPT_GOSSIP_HISTORY *gossip_hist);
+
 int mutt_autocrypt_schema_init (void);
 int mutt_autocrypt_schema_update (void);
 
index ac8a120bf8fb19f03a27df188fa8177d3db8c1ba..902e3f2ab635b6216037524b1b9ac3e7ada09c3c 100644 (file)
 #include "imap.h"
 #endif
 
+#ifdef USE_AUTOCRYPT
+#include "autocrypt/autocrypt.h"
+#endif
+
 #include "buffy.h"
 
 #include <errno.h>
@@ -57,12 +61,16 @@ static const char *ExtPagerProgress = "all";
 /* The folder the user last saved to.  Used by ci_save_message() */
 static char LastSaveFolder[_POSIX_PATH_MAX] = "";
 
-static void update_protected_headers (HEADER *cur)
+static void process_protected_headers (HEADER *cur)
 {
   ENVELOPE *prot_headers = NULL;
   regmatch_t pmatch[1];
 
-  if (!option (OPTCRYPTPROTHDRSREAD))
+  if (!option (OPTCRYPTPROTHDRSREAD)
+#ifdef USE_AUTOCRYPT
+      && !option (OPTAUTOCRYPT)
+#endif
+    )
     return;
 
   /* Grab protected headers to update in the index */
@@ -104,7 +112,8 @@ static void update_protected_headers (HEADER *cur)
   }
 
   /* Update protected headers in the index and header cache. */
-  if (prot_headers &&
+  if (option (OPTCRYPTPROTHDRSREAD) &&
+      prot_headers &&
       prot_headers->subject &&
       mutt_strcmp (cur->env->subject, prot_headers->subject))
   {
@@ -131,6 +140,16 @@ static void update_protected_headers (HEADER *cur)
       Context->changed = 1;
     }
   }
+
+#ifdef USE_AUTOCRYPT
+  if (option (OPTAUTOCRYPT) &&
+      (cur->security & ENCRYPT) &&
+      prot_headers &&
+      prot_headers->autocrypt_gossip)
+  {
+    mutt_autocrypt_process_gossip_header (cur, cur->env);
+  }
+#endif
 }
 
 int mutt_display_message (HEADER *cur)
@@ -253,8 +272,8 @@ int mutt_display_message (HEADER *cur)
        are color patterns for both ~g and ~V */
     cur->pair = 0;
 
-    /* Grab protected headers and update the header and index */
-    update_protected_headers (cur);
+    /* Process protected headers and autocrypt gossip headers */
+    process_protected_headers (cur);
   }
 
   if (builtin)
diff --git a/mutt.h b/mutt.h
index d15ab1068e5fe903ce7523ec6cecfe120d8d5948..7bd2be2891a8812ea800a1ec9cc2e0ff3e88f315 100644 (file)
--- a/mutt.h
+++ b/mutt.h
@@ -708,6 +708,7 @@ typedef struct envelope
   LIST *userhdrs;              /* user defined headers */
 #ifdef USE_AUTOCRYPT
   AUTOCRYPTHDR *autocrypt;
+  AUTOCRYPTHDR *autocrypt_gossip;
 #endif
   unsigned char changed;       /* The MUTT_ENV_CHANGED_* flags specify which
                                 * fields are modified */
index c31817ccdd326e2496aac241f0f017b626c64409..ba8f99701a648583d78f1a15d8e4c40050048ec8 100644 (file)
--- a/muttlib.c
+++ b/muttlib.c
@@ -827,6 +827,7 @@ void mutt_free_envelope (ENVELOPE **p)
 
 #ifdef USE_AUTOCRYPT
   mutt_free_autocrypthdr (&(*p)->autocrypt);
+  mutt_free_autocrypthdr (&(*p)->autocrypt_gossip);
 #endif
 
   FREE (p);            /* __FREE_CHECKED__ */
diff --git a/parse.c b/parse.c
index 8dd9240a23d8f8b947a3a4c8a7d73457bf6e2f57..777e7a644746fbaeb6d7dbffa6b1c540a5b81630 100644 (file)
--- a/parse.c
+++ b/parse.c
@@ -1141,6 +1141,14 @@ int mutt_parse_rfc822_line (ENVELOPE *e, HEADER *hdr, char *line, char *p, short
           matched = 1;
         }
       }
+      else if (ascii_strcasecmp (line+1, "utocrypt-gossip") == 0)
+      {
+        if (option (OPTAUTOCRYPT))
+        {
+          e->autocrypt_gossip = parse_autocrypt (e->autocrypt_gossip, p);
+          matched = 1;
+        }
+      }
 #endif
       break;