return rv;
}
+
+static struct Address *matching_gossip_address(struct Envelope *env, const char *addr)
+{
+ struct Address *np = NULL;
+
+ TAILQ_FOREACH(np, &env->to, entries)
+ {
+ if (!mutt_str_strcasecmp(np->mailbox, addr))
+ return np;
+ }
+
+ TAILQ_FOREACH(np, &env->cc, entries)
+ {
+ if (!mutt_str_strcasecmp(np->mailbox, addr))
+ return np;
+ }
+
+ TAILQ_FOREACH(np, &env->reply_to, entries)
+ {
+ if (!mutt_str_strcasecmp(np->mailbox, addr))
+ return np;
+ }
+
+ return NULL;
+}
+
+int mutt_autocrypt_process_gossip_header(struct Email *hdr, struct Envelope *env)
+{
+ struct AutocryptHeader *ac_hdr;
+ struct timeval now;
+ struct AutocryptPeer *peer = NULL;
+ struct AutocryptGossipHistory *gossip_hist = NULL;
+ struct Address *peer_addr;
+ struct Buffer *keyid = NULL;
+ int update_db = 0, insert_db = 0, insert_db_history = 0, import_gpg = 0;
+ int rv = -1;
+
+ if (!C_Autocrypt)
+ return 0;
+
+ if (mutt_autocrypt_init(0))
+ return -1;
+
+ if (!hdr || !hdr->content || !env)
+ return 0;
+
+ struct Address *from = TAILQ_FIRST(&env->from);
+ if (!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(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_str_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 = mutt_str_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 = mutt_str_strdup(from->mailbox);
+ gossip_hist->email_msgid = mutt_str_strdup(env->message_id);
+ gossip_hist->timestamp = hdr->date_sent;
+ gossip_hist->gossip_keydata = mutt_str_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_reset(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;
};
+struct AutocryptGossipHistory
+{
+ char *peer_email_addr;
+ char *sender_email_addr;
+ char *email_msgid;
+ sqlite3_int64 timestamp;
+ char *gossip_keydata;
+};
+
int mutt_autocrypt_init (int);
void mutt_autocrypt_cleanup (void);
int mutt_autocrypt_process_autocrypt_header (struct Email *hdr, struct Envelope *env);
+int mutt_autocrypt_process_gossip_header (struct Email *hdr, struct Envelope *env);
#endif /* MUTT_AUTOCRYPT_AUTOCRYPT_H */
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;
}
+
+struct AutocryptGossipHistory *mutt_autocrypt_db_gossip_history_new(void)
+{
+ return mutt_mem_calloc(1, sizeof(struct AutocryptGossipHistory));
+}
+
+void mutt_autocrypt_db_gossip_history_free(struct AutocryptGossipHistory **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);
+}
+
+int mutt_autocrypt_db_gossip_history_insert(struct Address *addr,
+ struct AutocryptGossipHistory *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 (struct AutocryptPeerHistory **peerhist);
int mutt_autocrypt_db_peer_history_insert (struct Address *addr, struct AutocryptPeerHistory *peerhist);
+struct AutocryptGossipHistory *mutt_autocrypt_db_gossip_history_new (void);
+void mutt_autocrypt_db_gossip_history_free (struct AutocryptGossipHistory **gossip_hist);
+int mutt_autocrypt_db_gossip_history_insert (struct Address *addr, struct AutocryptGossipHistory *gossip_hist);
+
int mutt_autocrypt_schema_init (void);
int mutt_autocrypt_schema_update (void);
#ifdef ENABLE_NLS
#include <libintl.h>
#endif
+#ifdef USE_AUTOCRYPT
+#include "autocrypt/autocrypt.h"
+#endif
/* These Config Variables are only used in commands.c */
unsigned char C_CryptVerifySig; ///< Config: Verify PGP or SMIME signatures
static char LastSaveFolder[PATH_MAX] = "";
/**
- * update_protected_headers - Get the protected header and update the index
+ * process_protected_headers - Get the protected header and update the index
* @param e Email to update
*/
-static void update_protected_headers(struct Email *e)
+static void process_protected_headers(struct Email *e)
{
struct Envelope *prot_headers = NULL;
regmatch_t pmatch[1];
- if (!C_CryptProtectedHeadersRead)
+ if (!C_CryptProtectedHeadersRead
+#ifdef USE_AUTOCRYPT
+ && !C_Autocrypt
+#endif
+ )
+ {
return;
+ }
/* Grab protected headers to update in the index */
if (e->security & SEC_SIGN)
}
/* Update protected headers in the index and header cache. */
- if (prot_headers && prot_headers->subject &&
+ if (C_CryptProtectedHeadersRead && prot_headers && prot_headers->subject &&
mutt_str_strcmp(e->env->subject, prot_headers->subject))
{
if (Context->mailbox->subj_hash && e->env->real_subj)
Context->mailbox->changed = 1;
}
}
+
+#ifdef USE_AUTOCRYPT
+ if (C_Autocrypt && (e->security & SEC_ENCRYPT) && prot_headers && prot_headers->autocrypt_gossip)
+ {
+ mutt_autocrypt_process_gossip_header(e, e->env);
+ }
+#endif
}
/**
* are color patterns for both ~g and ~V */
e->pair = 0;
- /* Grab protected headers and update the header and index */
- update_protected_headers(e);
+ /* Process protected headers and autocrypt gossip headers */
+ process_protected_headers(e);
}
if (builtin)
#ifdef USE_AUTOCRYPT
mutt_free_autocrypthdr(&(*p)->autocrypt);
+ mutt_free_autocrypthdr(&(*p)->autocrypt_gossip);
#endif
FREE(p);
struct ListHead userhdrs; ///< user defined headers
#ifdef USE_AUTOCRYPT
struct AutocryptHeader *autocrypt;
+ struct AutocryptHeader *autocrypt_gossip;
#endif
unsigned char changed; ///< Changed fields, e.g. #MUTT_ENV_CHANGED_SUBJECT
};
matched = 1;
}
}
+ else if (mutt_str_strcasecmp(line + 1, "utocrypt-gossip") == 0)
+ {
+ if (C_Autocrypt)
+ {
+ env->autocrypt_gossip = parse_autocrypt(env->autocrypt_gossip, p);
+ matched = 1;
+ }
+ }
#endif
break;