@if USE_AUTOCRYPT
LIBAUTOCRYPT= libautocrypt.a
LIBAUTOCRYPTOBJS= autocrypt/autocrypt.o \
+ autocrypt/autocrypt_acct_menu.o \
autocrypt/autocrypt_db.o \
autocrypt/autocrypt_gpgme.o \
autocrypt/autocrypt_schema.o
+
CLEANFILES+= $(LIBAUTOCRYPT) $(LIBAUTOCRYPTOBJS)
MUTTLIBS+= $(LIBAUTOCRYPT)
ALLOBJS+= $(LIBAUTOCRYPTOBJS)
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)
{
struct Address *addr = NULL;
struct AutocryptAccount *account = NULL;
int rc = -1;
int prefer_encrypt = 0;
- mutt_debug(LL_DEBUG1, "In mutt_autocrypt_account_init\n");
- if (mutt_yesorno(_("Create an initial autocrypt account?"), MUTT_YES) != MUTT_YES)
- return 0;
+ if (prompt)
+ {
+ if (mutt_yesorno(_("Create an initial autocrypt account?"), MUTT_YES) != MUTT_YES)
+ return 0;
+ }
struct Buffer *keyid = mutt_buffer_pool_get();
struct Buffer *keydata = mutt_buffer_pool_get();
int mutt_autocrypt_write_autocrypt_header (struct Envelope *env, FILE *fp);
int mutt_autocrypt_write_gossip_headers (struct Envelope *env, FILE *fp);
int mutt_autocrypt_generate_gossip_list (struct Email *hdr);
+void mutt_autocrypt_account_menu (void);
#endif /* MUTT_AUTOCRYPT_AUTOCRYPT_H */
--- /dev/null
+/**
+ * @file
+ * XXX
+ *
+ * @authors
+ * Copyright (C) 2019 Kevin J. McCarthy <kevin@8t8.us>
+ *
+ * @copyright
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+#include "autocrypt_private.h"
+#include "address/lib.h"
+#include "mutt.h"
+#include "autocrypt.h"
+#include "curs_lib.h"
+#include "format_flags.h"
+#include "globals.h"
+#include "mutt_menu.h"
+#include "mutt_window.h"
+#include "muttlib.h"
+#include "opcodes.h"
+
+struct Entry
+{
+ int tagged; /* TODO */
+ int num;
+ struct AutocryptAccount *account;
+ struct Address *addr;
+};
+
+static const struct Mapping 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, MuttFormatFlags flags)
+{
+ struct Entry *entry = (struct Entry *) data;
+ char tmp[128];
+
+ 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, struct Menu *m, int num)
+{
+ struct Entry *entry = &((struct Entry *) m->data)[num];
+
+ mutt_expando_format(s, slen, 0, MuttIndexWindow->cols,
+ NONULL(C_AutocryptAcctFormat), account_format_str,
+ (unsigned long) entry, MUTT_FORMAT_ARROWCURSOR);
+}
+
+static struct Menu *create_menu(void)
+{
+ struct Menu *menu = NULL;
+ struct AutocryptAccount **accounts = NULL;
+ struct 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_menu_new(MENU_AUTOCRYPT_ACCT);
+ menu->menu_make_entry = account_entry;
+ /* menu->tag = account_tag; */
+ /* L10N:
+ Autocrypt Account Management Menu title
+ */
+ menu->title = _("Autocrypt Accounts");
+ helpstr = mutt_mem_malloc(256);
+ menu->help = mutt_compile_help(helpstr, 256, MENU_AUTOCRYPT_ACCT, AutocryptAcctHelp);
+
+ menu->data = entries = mutt_mem_calloc(num_accounts, sizeof(struct 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 = mutt_addr_new();
+ entries[i].addr->mailbox = mutt_str_strdup(accounts[i]->email_addr);
+ mutt_addr_to_local(entries[i].addr);
+ }
+ FREE(&accounts);
+
+ mutt_menu_push_current(menu);
+
+ return menu;
+}
+
+static void free_menu(struct Menu **menu)
+{
+ int i;
+ struct Entry *entries;
+
+ entries = (struct Entry *) (*menu)->data;
+ for (i = 0; i < (*menu)->max; i++)
+ {
+ mutt_autocrypt_db_account_free(&entries[i].account);
+ mutt_addr_free(&entries[i].addr);
+ }
+ FREE(&(*menu)->data);
+
+ mutt_menu_pop_current(*menu);
+ FREE(&(*menu)->help);
+ mutt_menu_destroy(menu);
+}
+
+static void toggle_active(struct 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(struct 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)
+{
+ struct Menu *menu;
+ int done = 0, op;
+ struct Entry *entry;
+ char msg[128];
+
+ if (!C_Autocrypt)
+ return;
+
+ if (mutt_autocrypt_init(0))
+ return;
+
+ menu = create_menu();
+ if (!menu)
+ return;
+
+ while (!done)
+ {
+ switch ((op = mutt_menu_loop(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 = (struct 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 = (struct Entry *) (menu->data) + menu->current;
+ toggle_active(entry);
+ menu->redraw |= REDRAW_FULL;
+ }
+ break;
+
+ case OP_AUTOCRYPT_TOGGLE_PREFER:
+ if (menu->data)
+ {
+ entry = (struct Entry *) (menu->data) + menu->current;
+ toggle_prefer_encrypt(entry);
+ menu->redraw |= REDRAW_FULL;
+ }
+ break;
+ }
+ }
+
+ free_menu(&menu);
+}
/* 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;
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
{
AccountGetStmt = NULL;
sqlite3_finalize(AccountInsertStmt);
AccountInsertStmt = NULL;
+ sqlite3_finalize(AccountUpdateStmt);
+ AccountUpdateStmt = NULL;
+ sqlite3_finalize(AccountDeleteStmt);
+ AccountDeleteStmt = NULL;
sqlite3_finalize(PeerGetStmt);
PeerGetStmt = NULL;
return rv;
}
+int mutt_autocrypt_db_account_update(struct AutocryptAccount *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(struct AutocryptAccount *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(struct AutocryptAccount ***accounts, int *num_accounts)
+{
+ int rv = -1, result;
+ sqlite3_stmt *stmt = NULL;
+ struct AutocryptAccount **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;
+ mutt_mem_realloc(&results, results_len * sizeof(struct AutocryptAccount *));
+ }
+
+ 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;
+}
+
struct AutocryptPeer *mutt_autocrypt_db_peer_new(void)
{
return mutt_mem_calloc(1, sizeof(struct AutocryptPeer));
struct AddressList;
struct Buffer;
-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);
int mutt_autocrypt_db_account_get (struct Address *addr, struct AutocryptAccount **account);
int mutt_autocrypt_db_account_insert (struct Address *addr, const char *keyid,
const char *keydata, int prefer_encrypt);
+int mutt_autocrypt_db_account_update (struct AutocryptAccount *acct);
+int mutt_autocrypt_db_account_delete (struct AutocryptAccount *acct);
+int mutt_autocrypt_db_account_get_all (struct AutocryptAccount ***accounts, int *num_accounts);
struct AutocryptPeer *mutt_autocrypt_db_peer_new (void);
void mutt_autocrypt_db_peer_free (struct AutocryptPeer **peer);
__print_map(summary)
__print_map(mixmaster)
__print_map(editor)
+__print_map(autocrypt account)
</sect1>
</chapter>
* OpMain - Key bindings for the index menu
*/
const struct Binding OpMain[] = { /* map: index */
+#ifdef USE_AUTOCRYPT
+ { "autocrypt-acct-menu", OP_AUTOCRYPT_ACCT_MENU, "A" },
+#endif
{ "bounce-message", OP_BOUNCE_MESSAGE, "b" },
{ "break-thread", OP_MAIN_BREAK_THREAD, "#" },
#ifdef USE_NNTP
};
#endif /* MIXMASTER */
+#ifdef USE_AUTOCRYPT
+const struct Binding OpAutocryptAcct[] = { /* map: autocrypt account */
+ { "create-account", OP_AUTOCRYPT_CREATE_ACCT, "c" },
+ { "delete-account", OP_AUTOCRYPT_DELETE_ACCT, "D" },
+ { "toggle-active", OP_AUTOCRYPT_TOGGLE_ACTIVE, "a" },
+ { "toggle-prefer-encrypt", OP_AUTOCRYPT_TOGGLE_PREFER, "p" },
+ { NULL, 0, NULL }
+};
+#endif
+
// clang-format on
#endif /* MUTT_FUNCTIONS_H */
WHERE char *C_AttributionLocale; ///< Config: Locale for dates in the attribution message
WHERE char *C_AttachFormat; ///< Config: printf-like format string for the attachment menu
#ifdef USE_AUTOCRYPT
+WHERE char *C_AutocryptAcctFormat;
WHERE char *C_AutocryptDir;
WHERE char *AutocryptSignAs; /* This is used in ncrypt/crypt_gpgme.c */
WHERE char *AutocryptDefaultKey; /* Used for postponing messages */
#ifdef USE_INOTIFY
#include "monitor.h"
#endif
+#ifdef USE_AUTOCRYPT
+#include "autocrypt/autocrypt.h"
+#endif
/* These Config Variables are only used in index.c */
bool C_ChangeFolderNext; ///< Config: Suggest the next folder, rather than the first when using '<change-folder>'
mutt_window_reflow();
break;
#endif
+
+#ifdef USE_AUTOCRYPT
+ case OP_AUTOCRYPT_ACCT_MENU:
+ mutt_autocrypt_account_menu();
+ break;
+#endif
+
default:
if (menu->menu == MENU_MAIN)
km_error_key(MENU_MAIN);
** passive encryption protection with keys exchanged via headers.
** TODO: add a section in the manual describing this is more detail.
*/
+ { "autocrypt_acct_format", DT_STRING|R_MENU, &C_AutocryptAcctFormat, IP "%4n %-30a %20p %10s" },
+ /*
+ ** .pp
+ ** This variable describes the format of the ``autocrypt account'' menu.
+ ** The following \fCprintf(3)\fP-style sequences are understood
+ ** .dl
+ ** .dt %a .dd email address
+ ** .dt %k .dd gpg keyid
+ ** .dt %n .dd current entry number
+ ** .dt %p .dd prefer-encrypt flag
+ ** .dt %s .dd status flag (active/inactive)
+ ** .de
+ ** .pp
+ */
{ "autocrypt_dir", DT_STRING|DT_PATH, &C_AutocryptDir, IP "~/.mutt/autocrypt" },
/*
** .pp
km_bindkey("l", MENU_MIX, OP_MIX_CHAIN_NEXT);
#endif
+#ifdef USE_AUTOCRYPT
+ create_bindings(OpAutocryptAcct, MENU_AUTOCRYPT_ACCT);
+#endif
+
/* bindings for the line editor */
create_bindings(OpEditor, MENU_EDITOR);
return OpAlias;
case MENU_ATTACH:
return OpAttach;
+#ifdef USE_AUTOCRYPT
+ case MENU_AUTOCRYPT_ACCT:
+ return OpAutocryptAcct;
+#endif
case MENU_COMPOSE:
return OpCompose;
case MENU_EDITOR:
#endif
#ifdef MIXMASTER
MENU_MIX, ///< Create/edit a Mixmaster chain
+#endif
+#ifdef USE_AUTOCRYPT
+ MENU_AUTOCRYPT_ACCT,
#endif
MENU_MAX,
};
extern const struct Binding OpMix[];
#endif
+#ifdef USE_AUTOCRYPT
+extern const struct Binding OpAutocryptAcct[];
+#endif
+
void mutt_free_keys(void);
enum CommandResult mutt_parse_bind(struct Buffer *buf, struct Buffer *s, unsigned long data, struct Buffer *err);
_fmt(OP_ATTACH_COLLAPSE, N_("toggle display of subparts")) \
_fmt(OP_ATTACH_VIEW_MAILCAP, N_("force viewing of attachment using mailcap")) \
_fmt(OP_ATTACH_VIEW_TEXT, N_("view attachment as text")) \
+ _fmt(OP_AUTOCRYPT_ACCT_MENU, N_("manage autocrypt accounts")) \
+ _fmt(OP_AUTOCRYPT_CREATE_ACCT, N_("create a new autocrypt account")) \
+ _fmt(OP_AUTOCRYPT_DELETE_ACCT, N_("delete the current account")) \
+ _fmt(OP_AUTOCRYPT_TOGGLE_ACTIVE, N_("toggle the current account active/inactive")) \
+ _fmt(OP_AUTOCRYPT_TOGGLE_PREFER, N_("toggle the current account prefer-encrypt flag")) \
_fmt(OP_BOTTOM_PAGE, N_("move to the bottom of the page")) \
_fmt(OP_BOUNCE_MESSAGE, N_("remail a message to another user")) \
_fmt(OP_BROWSER_GOTO_FOLDER, N_("swap the current folder position with $folder if it exists")) \
alias.c
autocrypt/autocrypt.c
autocrypt/autocrypt_db.c
+autocrypt/autocrypt_acct_menu.c
autocrypt/autocrypt_gpgme.c
autocrypt/autocrypt_schema.c
backtrace.c