summaryrefslogtreecommitdiffstats
path: root/autocrypt
diff options
context:
space:
mode:
authorKevin McCarthy <kevin@8t8.us>2019-07-28 19:24:11 -0700
committerKevin McCarthy <kevin@8t8.us>2019-08-03 14:08:09 -0700
commit85bd11b08d66ceaaeb30bafb963a950a507185d1 (patch)
treea8e6ada0c4a856f6e826ccd8b1b76bf6b367bd0e /autocrypt
parent361156045e886b0aeba6920992aec4c20536d23c (diff)
Basic autocrypt account menu.
Provide ability to create, delete, and toggle the prefer-encrypt and enabled flag for an account. Hook into the index via 'A' <autocrypt-acct-menu>.
Diffstat (limited to 'autocrypt')
-rw-r--r--autocrypt/Makefile.am2
-rw-r--r--autocrypt/autocrypt.c15
-rw-r--r--autocrypt/autocrypt.h1
-rw-r--r--autocrypt/autocrypt_acct_menu.c282
-rw-r--r--autocrypt/autocrypt_db.c161
-rw-r--r--autocrypt/autocrypt_private.h5
6 files changed, 458 insertions, 8 deletions
diff --git a/autocrypt/Makefile.am b/autocrypt/Makefile.am
index d7f3f0da..aefff20a 100644
--- a/autocrypt/Makefile.am
+++ b/autocrypt/Makefile.am
@@ -8,4 +8,4 @@ AM_CPPFLAGS = -I$(top_srcdir) -I../intl
noinst_LIBRARIES = libautocrypt.a
libautocrypt_a_SOURCES = autocrypt.c autocrypt.h autocrypt_db.c autocrypt_private.h \
- autocrypt_schema.c autocrypt_gpgme.c
+ autocrypt_schema.c autocrypt_gpgme.c autocrypt_acct_menu.c
diff --git a/autocrypt/autocrypt.c b/autocrypt/autocrypt.c
index 82620035..2c866fca 100644
--- a/autocrypt/autocrypt.c
+++ b/autocrypt/autocrypt.c
@@ -100,18 +100,22 @@ void mutt_autocrypt_cleanup (void)
mutt_autocrypt_db_close ();
}
-/* Creates a brand new account the first time autocrypt is initialized */
-int mutt_autocrypt_account_init (void)
+/* Creates a brand new account.
+ * This is used the first time autocrypt is initialized, and
+ * in the account menu. */
+int mutt_autocrypt_account_init (int prompt)
{
ADDRESS *addr = NULL;
BUFFER *keyid = NULL, *keydata = NULL;
AUTOCRYPT_ACCOUNT *account = NULL;
int done = 0, rv = -1, prefer_encrypt = 0;
- dprint (1, (debugfile, "In mutt_autocrypt_account_init\n"));
- if (mutt_yesorno (_("Create an initial autocrypt account?"),
+ if (prompt)
+ {
+ if (mutt_yesorno (_("Create an initial autocrypt account?"),
MUTT_YES) != MUTT_YES)
- return 0;
+ return 0;
+ }
keyid = mutt_buffer_pool_get ();
keydata = mutt_buffer_pool_get ();
@@ -152,6 +156,7 @@ int mutt_autocrypt_account_init (void)
if (account)
{
mutt_error _("That email address already has an autocrypt account");
+ mutt_sleep (1);
goto cleanup;
}
diff --git a/autocrypt/autocrypt.h b/autocrypt/autocrypt.h
index 78779777..a50ec311 100644
--- a/autocrypt/autocrypt.h
+++ b/autocrypt/autocrypt.h
@@ -80,5 +80,6 @@ int mutt_autocrypt_set_sign_as_default_key (HEADER *hdr);
int mutt_autocrypt_write_autocrypt_header (ENVELOPE *env, FILE *fp);
int mutt_autocrypt_write_gossip_headers (ENVELOPE *env, FILE *fp);
int mutt_autocrypt_generate_gossip_list (HEADER *hdr);
+void mutt_autocrypt_account_menu (void);
#endif
diff --git a/autocrypt/autocrypt_acct_menu.c b/autocrypt/autocrypt_acct_menu.c
new file mode 100644
index 00000000..dd1f0c5c
--- /dev/null
+++ b/autocrypt/autocrypt_acct_menu.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2019 Kevin J. McCarthy <kevin@8t8.us>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "mutt.h"
+#include "mutt_menu.h"
+#include "mutt_idna.h"
+
+#include "autocrypt.h"
+#include "autocrypt_private.h"
+
+typedef struct entry
+{
+ int tagged; /* TODO */
+ int num;
+ AUTOCRYPT_ACCOUNT *account;
+ ADDRESS *addr;
+} ENTRY;
+
+static const struct mapping_t AutocryptAcctHelp[] = {
+ { N_("Exit"), OP_EXIT },
+ /* L10N: Autocrypt Account Menu Help line:
+ create new account
+ */
+ { N_("Create"), OP_AUTOCRYPT_CREATE_ACCT },
+ /* L10N: Autocrypt Account Menu Help line:
+ delete account
+ */
+ { N_("Delete"), OP_AUTOCRYPT_DELETE_ACCT },
+ /* L10N: Autocrypt Account Menu Help line:
+ toggle an account active/inactive
+ */
+ { N_("Tgl Active"), OP_AUTOCRYPT_TOGGLE_ACTIVE },
+ /* L10N: Autocrypt Account Menu Help line:
+ toggle "prefer-encrypt" on an account
+ */
+ { N_("Prf Enc"), OP_AUTOCRYPT_TOGGLE_PREFER },
+ { N_("Help"), OP_HELP },
+ { NULL, 0 }
+};
+
+static const char *account_format_str (char *dest, size_t destlen, size_t col,
+ int cols, char op, const char *src,
+ const char *fmt, const char *ifstring,
+ const char *elsestring,
+ unsigned long data, format_flag flags)
+{
+ ENTRY *entry = (ENTRY *)data;
+ char tmp[SHORT_STRING];
+
+ switch (op)
+ {
+ case 'a':
+ mutt_format_s (dest, destlen, fmt, entry->addr->mailbox);
+ break;
+ case 'k':
+ mutt_format_s (dest, destlen, fmt, entry->account->keyid);
+ break;
+ case 'n':
+ snprintf (tmp, sizeof (tmp), "%%%sd", fmt);
+ snprintf (dest, destlen, tmp, entry->num);
+ break;
+ case 'p':
+ if (entry->account->prefer_encrypt)
+ /* L10N:
+ Autocrypt Account menu.
+ flag that an account has prefer-encrypt set
+ */
+ mutt_format_s (dest, destlen, fmt, _("prefer encrypt"));
+ else
+ /* L10N:
+ Autocrypt Account menu.
+ flag that an account has prefer-encrypt unset;
+ thus encryption will need to be manually enabled.
+ */
+ mutt_format_s (dest, destlen, fmt, _("manual encrypt"));
+ break;
+ case 's':
+ if (entry->account->enabled)
+ /* L10N:
+ Autocrypt Account menu.
+ flag that an account is enabled/active
+ */
+ mutt_format_s (dest, destlen, fmt, _("active"));
+ else
+ /* L10N:
+ Autocrypt Account menu.
+ flag that an account is disabled/inactive
+ */
+ mutt_format_s (dest, destlen, fmt, _("inactive"));
+ break;
+ }
+
+ return (src);
+}
+
+static void account_entry (char *s, size_t slen, MUTTMENU *m, int num)
+{
+ ENTRY *entry = &((ENTRY *) m->data)[num];
+
+ mutt_FormatString (s, slen, 0, MuttIndexWindow->cols,
+ NONULL (AutocryptAcctFormat), account_format_str,
+ (unsigned long) entry, MUTT_FORMAT_ARROWCURSOR);
+}
+
+static MUTTMENU *create_menu ()
+{
+ MUTTMENU *menu = NULL;
+ AUTOCRYPT_ACCOUNT **accounts = NULL;
+ ENTRY *entries = NULL;
+ int num_accounts = 0, i;
+ char *helpstr;
+
+ if (mutt_autocrypt_db_account_get_all (&accounts, &num_accounts) < 0)
+ return NULL;
+
+ menu = mutt_new_menu (MENU_AUTOCRYPT_ACCT);
+ menu->make_entry = account_entry;
+ /* menu->tag = account_tag; */
+ /* L10N:
+ Autocrypt Account Management Menu title
+ */
+ menu->title = _("Autocrypt Accounts");
+ helpstr = safe_malloc (STRING);
+ menu->help = mutt_compile_help (helpstr, STRING, MENU_AUTOCRYPT_ACCT,
+ AutocryptAcctHelp);
+
+ menu->data = entries = safe_calloc (num_accounts, sizeof(ENTRY));
+ menu->max = num_accounts;
+
+ for (i = 0; i < num_accounts; i++)
+ {
+ entries[i].num = i + 1;
+ /* note: we are transfering the account pointer to the entries
+ * array, and freeing the accounts array below. the account
+ * will be freed in free_menu().
+ */
+ entries[i].account = accounts[i];
+
+ entries[i].addr = rfc822_new_address ();
+ entries[i].addr->mailbox = safe_strdup (accounts[i]->email_addr);
+ mutt_addrlist_to_local (entries[i].addr);
+ }
+ FREE (&accounts);
+
+ mutt_push_current_menu (menu);
+
+ return menu;
+}
+
+static void free_menu (MUTTMENU **menu)
+{
+ int i;
+ ENTRY *entries;
+
+ entries = (ENTRY *)(*menu)->data;
+ for (i = 0; i < (*menu)->max; i++)
+ {
+ mutt_autocrypt_db_account_free (&entries[i].account);
+ rfc822_free_address (&entries[i].addr);
+ }
+ FREE (&(*menu)->data);
+
+ mutt_pop_current_menu (*menu);
+ FREE (&(*menu)->help);
+ mutt_menuDestroy (menu);
+}
+
+static void toggle_active (ENTRY *entry)
+{
+ entry->account->enabled = !entry->account->enabled;
+ if (mutt_autocrypt_db_account_update (entry->account) != 0)
+ {
+ entry->account->enabled = !entry->account->enabled;
+ mutt_error _("Error updating account record");
+ }
+}
+
+static void toggle_prefer_encrypt (ENTRY *entry)
+{
+ entry->account->prefer_encrypt = !entry->account->prefer_encrypt;
+ if (mutt_autocrypt_db_account_update (entry->account))
+ {
+ entry->account->prefer_encrypt = !entry->account->prefer_encrypt;
+ mutt_error _("Error updating account record");
+ }
+}
+
+void mutt_autocrypt_account_menu (void)
+{
+ MUTTMENU *menu;
+ int done = 0, op;
+ ENTRY *entry;
+ char msg[SHORT_STRING];
+
+ if (!option (OPTAUTOCRYPT))
+ return;
+
+ if (mutt_autocrypt_init (0))
+ return;
+
+ menu = create_menu ();
+ if (!menu)
+ return;
+
+ while (!done)
+ {
+ switch ((op = mutt_menuLoop (menu)))
+ {
+ case OP_EXIT:
+ done = 1;
+ break;
+
+ case OP_AUTOCRYPT_CREATE_ACCT:
+ if (!mutt_autocrypt_account_init (0))
+ {
+ free_menu (&menu);
+ menu = create_menu ();
+ }
+ break;
+
+ case OP_AUTOCRYPT_DELETE_ACCT:
+ if (menu->data)
+ {
+ entry = (ENTRY *)(menu->data) + menu->current;
+ snprintf (msg, sizeof(msg),
+ /* L10N:
+ Confirms deleting an autocrypt account
+ */
+ _("Really delete account \"%s\"?"),
+ entry->addr->mailbox);
+ if (mutt_yesorno (msg, MUTT_NO) != MUTT_YES)
+ break;
+
+ if (!mutt_autocrypt_db_account_delete (entry->account))
+ {
+ free_menu (&menu);
+ menu = create_menu ();
+ }
+ }
+ break;
+
+ case OP_AUTOCRYPT_TOGGLE_ACTIVE:
+ if (menu->data)
+ {
+ entry = (ENTRY *)(menu->data) + menu->current;
+ toggle_active (entry);
+ menu->redraw |= REDRAW_FULL;
+ }
+ break;
+
+ case OP_AUTOCRYPT_TOGGLE_PREFER:
+ if (menu->data)
+ {
+ entry = (ENTRY *)(menu->data) + menu->current;
+ toggle_prefer_encrypt (entry);
+ menu->redraw |= REDRAW_FULL;
+ }
+ break;
+ }
+ }
+
+ free_menu (&menu);
+}
diff --git a/autocrypt/autocrypt_db.c b/autocrypt/autocrypt_db.c
index 7fad7068..cadd0dcd 100644
--- a/autocrypt/autocrypt_db.c
+++ b/autocrypt/autocrypt_db.c
@@ -28,6 +28,8 @@
/* Prepared statements */
static sqlite3_stmt *AccountGetStmt;
static sqlite3_stmt *AccountInsertStmt;
+static sqlite3_stmt *AccountUpdateStmt;
+static sqlite3_stmt *AccountDeleteStmt;
static sqlite3_stmt *PeerGetStmt;
static sqlite3_stmt *PeerInsertStmt;
static sqlite3_stmt *PeerUpdateStmt;
@@ -74,7 +76,7 @@ int mutt_autocrypt_db_init (int can_create)
if (autocrypt_db_create (mutt_b2s (db_path)))
goto cleanup;
/* Don't abort the whole init process because account creation failed */
- mutt_autocrypt_account_init ();
+ mutt_autocrypt_account_init (1);
}
else
{
@@ -108,6 +110,10 @@ void mutt_autocrypt_db_close (void)
AccountGetStmt = NULL;
sqlite3_finalize (AccountInsertStmt);
AccountInsertStmt = NULL;
+ sqlite3_finalize (AccountUpdateStmt);
+ AccountUpdateStmt = NULL;
+ sqlite3_finalize (AccountDeleteStmt);
+ AccountDeleteStmt = NULL;
sqlite3_finalize (PeerGetStmt);
PeerGetStmt = NULL;
@@ -307,6 +313,159 @@ cleanup:
return rv;
}
+int mutt_autocrypt_db_account_update (AUTOCRYPT_ACCOUNT *acct)
+{
+ int rv = -1;
+
+ if (!AccountUpdateStmt)
+ {
+ if (sqlite3_prepare_v3 (
+ AutocryptDB,
+ "UPDATE account SET "
+ "keyid = ?, "
+ "keydata = ?, "
+ "prefer_encrypt = ?, "
+ "enabled = ? "
+ "WHERE email_addr = ?;",
+ -1,
+ SQLITE_PREPARE_PERSISTENT,
+ &AccountUpdateStmt,
+ NULL) != SQLITE_OK)
+ goto cleanup;
+ }
+
+ if (sqlite3_bind_text (AccountUpdateStmt,
+ 1,
+ acct->keyid,
+ -1,
+ SQLITE_STATIC) != SQLITE_OK)
+ goto cleanup;
+ if (sqlite3_bind_text (AccountUpdateStmt,
+ 2,
+ acct->keydata,
+ -1,
+ SQLITE_STATIC) != SQLITE_OK)
+ goto cleanup;
+ if (sqlite3_bind_int (AccountUpdateStmt,
+ 3,
+ acct->prefer_encrypt) != SQLITE_OK)
+ goto cleanup;
+ if (sqlite3_bind_int (AccountUpdateStmt,
+ 4,
+ acct->enabled) != SQLITE_OK)
+ goto cleanup;
+ if (sqlite3_bind_text (AccountUpdateStmt,
+ 5,
+ acct->email_addr,
+ -1,
+ SQLITE_STATIC) != SQLITE_OK)
+ goto cleanup;
+
+ if (sqlite3_step (AccountUpdateStmt) != SQLITE_DONE)
+ goto cleanup;
+
+ rv = 0;
+
+cleanup:
+ sqlite3_reset (AccountUpdateStmt);
+ return rv;
+}
+
+int mutt_autocrypt_db_account_delete (AUTOCRYPT_ACCOUNT *acct)
+{
+ int rv = -1;
+
+ if (!AccountDeleteStmt)
+ {
+ if (sqlite3_prepare_v3 (
+ AutocryptDB,
+ "DELETE from account "
+ "WHERE email_addr = ?;",
+ -1,
+ SQLITE_PREPARE_PERSISTENT,
+ &AccountDeleteStmt,
+ NULL) != SQLITE_OK)
+ goto cleanup;
+ }
+
+ if (sqlite3_bind_text (AccountDeleteStmt,
+ 1,
+ acct->email_addr,
+ -1,
+ SQLITE_STATIC) != SQLITE_OK)
+ goto cleanup;
+
+ if (sqlite3_step (AccountDeleteStmt) != SQLITE_DONE)
+ goto cleanup;
+
+ rv = 0;
+
+cleanup:
+ sqlite3_reset (AccountDeleteStmt);
+ return rv;
+}
+
+int mutt_autocrypt_db_account_get_all (AUTOCRYPT_ACCOUNT ***accounts, int *num_accounts)
+{
+ int rv = -1, result;
+ sqlite3_stmt *stmt = NULL;
+ AUTOCRYPT_ACCOUNT **results = NULL, *account;
+ int results_len = 0, results_count = 0;
+
+ *accounts = NULL;
+ *num_accounts = 0;
+
+ /* Note, speed is not of the essence for the account management screen,
+ * so we don't bother with a persistent prepared statement */
+ if (sqlite3_prepare_v2 (
+ AutocryptDB,
+ "SELECT "
+ "email_addr, "
+ "keyid, "
+ "keydata, "
+ "prefer_encrypt, "
+ "enabled "
+ "FROM account "
+ "ORDER BY email_addr",
+ -1,
+ &stmt,
+ NULL) != SQLITE_OK)
+ goto cleanup;
+
+ while ((result = sqlite3_step (stmt)) == SQLITE_ROW)
+ {
+ if (results_count == results_len)
+ {
+ results_len += 5;
+ safe_realloc (&results, results_len * sizeof(AUTOCRYPT_ACCOUNT *));
+ }
+
+ results[results_count++] = account = mutt_autocrypt_db_account_new ();
+
+ account->email_addr = strdup_column_text (stmt, 0);
+ account->keyid = strdup_column_text (stmt, 1);
+ account->keydata = strdup_column_text (stmt, 2);
+ account->prefer_encrypt = sqlite3_column_int (stmt, 3);
+ account->enabled = sqlite3_column_int (stmt, 4);
+ }
+
+ if (result == SQLITE_DONE)
+ {
+ *accounts = results;
+ rv = *num_accounts = results_count;
+ }
+ else
+ {
+ while (results_count > 0)
+ mutt_autocrypt_db_account_free (&results[--results_count]);
+ FREE (&results);
+ }
+
+cleanup:
+ sqlite3_finalize (stmt);
+ return rv;
+}
+
AUTOCRYPT_PEER *mutt_autocrypt_db_peer_new (void)
{
return safe_calloc (1, sizeof(AUTOCRYPT_PEER));
diff --git a/autocrypt/autocrypt_private.h b/autocrypt/autocrypt_private.h
index 1c8a038f..96c487f5 100644
--- a/autocrypt/autocrypt_private.h
+++ b/autocrypt/autocrypt_private.h
@@ -21,7 +21,7 @@
#include <sqlite3.h>
-int mutt_autocrypt_account_init (void);
+int mutt_autocrypt_account_init (int prompt);
int mutt_autocrypt_db_init (int can_create);
void mutt_autocrypt_db_close (void);
@@ -33,6 +33,9 @@ void mutt_autocrypt_db_account_free (AUTOCRYPT_ACCOUNT **account);
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);
+int mutt_autocrypt_db_account_update (AUTOCRYPT_ACCOUNT *acct);
+int mutt_autocrypt_db_account_delete (AUTOCRYPT_ACCOUNT *acct);
+int mutt_autocrypt_db_account_get_all (AUTOCRYPT_ACCOUNT ***accounts, int *num_accounts);
AUTOCRYPT_PEER *mutt_autocrypt_db_peer_new (void);
void mutt_autocrypt_db_peer_free (AUTOCRYPT_PEER **peer);