#include "mutt.h"
#include "mutt_curses.h"
#include "mime.h"
+#include "mutt_idna.h"
#include "autocrypt.h"
#include "autocrypt_private.h"
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;
+}
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
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)
{
sqlite3_finalize (PeerHistoryInsertStmt);
PeerHistoryInsertStmt = NULL;
+ sqlite3_finalize (GossipHistoryInsertStmt);
+ GossipHistoryInsertStmt = NULL;
+
sqlite3_close_v2 (AutocryptDB);
AutocryptDB = NULL;
}
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;
+}
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);
#include "imap.h"
#endif
+#ifdef USE_AUTOCRYPT
+#include "autocrypt/autocrypt.h"
+#endif
+
#include "buffy.h"
#include <errno.h>
/* 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 */
}
/* 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))
{
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)
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)
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 */
#ifdef USE_AUTOCRYPT
mutt_free_autocrypthdr (&(*p)->autocrypt);
+ mutt_free_autocrypthdr (&(*p)->autocrypt_gossip);
#endif
FREE (p); /* __FREE_CHECKED__ */
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;