From: Kevin McCarthy Date: Sat, 6 Jul 2019 21:01:13 +0000 (-0700) Subject: Add database and schema initialization X-Git-Tag: 2019-10-25~97^2~50 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8dee445a440724fb4340d3bf07e82d312ec1f68a;p=neomutt Add database and schema initialization Add mutt_mkdir() library function supporting recursive mkdir. Co-authored-by: Richard Russon --- diff --git a/Makefile.autosetup b/Makefile.autosetup index 0dab42461..f3ade9630 100644 --- a/Makefile.autosetup +++ b/Makefile.autosetup @@ -96,7 +96,9 @@ ALLOBJS+= $(NEOMUTTOBJS) # libautocrypt @if USE_AUTOCRYPT LIBAUTOCRYPT= libautocrypt.a -LIBAUTOCRYPTOBJS= autocrypt/autocrypt.o +LIBAUTOCRYPTOBJS= autocrypt/autocrypt.o \ + autocrypt/autocrypt_db.o \ + autocrypt/autocrypt_schema.o CLEANFILES+= $(LIBAUTOCRYPT) $(LIBAUTOCRYPTOBJS) MUTTLIBS+= $(LIBAUTOCRYPT) ALLOBJS+= $(LIBAUTOCRYPTOBJS) diff --git a/autocrypt/autocrypt.c b/autocrypt/autocrypt.c index 4e859efa8..fa8ff9187 100644 --- a/autocrypt/autocrypt.c +++ b/autocrypt/autocrypt.c @@ -21,16 +21,74 @@ */ #include "config.h" - +#include +#include +#include +#include +#include +#include "autocrypt_private.h" #include "mutt.h" #include "autocrypt.h" +#include "curs_lib.h" +#include "globals.h" -void mutt_autocrypt_init(void) +static int autocrypt_dir_init(int can_create) { + int rv = 0; + struct stat sb; + struct Buffer *prompt = NULL; + + if (!stat(C_AutocryptDir, &sb)) + return 0; + + if (!can_create) + return -1; + + prompt = mutt_buffer_pool_get(); + mutt_buffer_printf(prompt, _("%s does not exist. Create it?"), C_AutocryptDir); + if (mutt_yesorno(mutt_b2s(prompt), MUTT_YES) == MUTT_YES) + { + if (mutt_file_mkdir(C_AutocryptDir, S_IRWXU) < 0) + { + mutt_error(_("Can't create %s: %s."), C_AutocryptDir, strerror(errno)); + rv = -1; + } + } + + mutt_buffer_pool_release(&prompt); + return rv; +} + +int mutt_autocrypt_init(int can_create) +{ + if (AutocryptDB) + return 0; + + if (!C_Autocrypt || !C_AutocryptDir) + return -1; + + if (autocrypt_dir_init(can_create)) + goto bail; + + if (mutt_autocrypt_db_init(can_create)) + goto bail; + + /* mutt_autocrypt_gpgme_init() + * - init gpgme + * - create key if doesn't exist + * - perhaps should query account table and if empty do that? + */ mutt_debug(LL_DEBUG1, "In mutt_autocrypt_init()\n"); + return 0; + +bail: + C_Autocrypt = false; + mutt_autocrypt_db_close(); + return -1; } void mutt_autocrypt_cleanup(void) { + mutt_autocrypt_db_close(); mutt_debug(LL_DEBUG1, "In mutt_autocrypt_cleanup()\n"); } diff --git a/autocrypt/autocrypt.h b/autocrypt/autocrypt.h index 6172203e1..8cb6d543b 100644 --- a/autocrypt/autocrypt.h +++ b/autocrypt/autocrypt.h @@ -23,7 +23,12 @@ #ifndef MUTT_AUTOCRYPT_AUTOCRYPT_H #define MUTT_AUTOCRYPT_AUTOCRYPT_H -void mutt_autocrypt_init (void); +#include +#include "where.h" + +WHERE sqlite3 *AutocryptDB; + +int mutt_autocrypt_init (int); void mutt_autocrypt_cleanup (void); #endif /* MUTT_AUTOCRYPT_AUTOCRYPT_H */ diff --git a/autocrypt/autocrypt_db.c b/autocrypt/autocrypt_db.c new file mode 100644 index 000000000..e0cc46ea0 --- /dev/null +++ b/autocrypt/autocrypt_db.c @@ -0,0 +1,92 @@ +/** + * @file + * XXX + * + * @authors + * Copyright (C) 2019 Kevin J. McCarthy + * + * @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 . + */ + +#include "config.h" +#include +#include +#include +#include "autocrypt_private.h" +#include "mutt.h" +#include "autocrypt.h" +#include "globals.h" + +static int autocrypt_db_create(const char *db_path) +{ + if (sqlite3_open_v2(db_path, &AutocryptDB, + SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL) != SQLITE_OK) + { + mutt_error(_("Unable to open autocrypt database %s"), db_path); + return -1; + } + return mutt_autocrypt_schema_init(); +} + +int mutt_autocrypt_db_init(int can_create) +{ + int rv = -1; + struct Buffer *db_path = NULL; + struct stat sb; + + if (AutocryptDB) + return 0; + + if (!C_Autocrypt || !C_AutocryptDir) + return -1; + + db_path = mutt_buffer_pool_get(); + mutt_buffer_concat_path(db_path, C_AutocryptDir, "autocrypt.db"); + if (stat(mutt_b2s(db_path), &sb)) + { + if (!can_create || autocrypt_db_create(mutt_b2s(db_path))) + goto cleanup; + } + else + { + if (sqlite3_open_v2(mutt_b2s(db_path), &AutocryptDB, SQLITE_OPEN_READWRITE, NULL) != SQLITE_OK) + { + mutt_error(_("Unable to open autocrypt database %s"), mutt_b2s(db_path)); + goto cleanup; + } + } + + if (mutt_autocrypt_schema_update()) + goto cleanup; + + rv = 0; + +cleanup: + mutt_buffer_pool_release(&db_path); + return rv; +} + +void mutt_autocrypt_db_close(void) +{ + if (!AutocryptDB) + return; + + /* TODO: + * call sqlite3_finalize () for each prepared statement + */ + + sqlite3_close_v2(AutocryptDB); + AutocryptDB = NULL; +} diff --git a/autocrypt/autocrypt_private.h b/autocrypt/autocrypt_private.h new file mode 100644 index 000000000..56a45aa8b --- /dev/null +++ b/autocrypt/autocrypt_private.h @@ -0,0 +1,32 @@ +/** + * @file + * XXX + * + * @authors + * Copyright (C) 2019 Kevin J. McCarthy + * + * @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 . + */ + +#ifndef MUTT_AUTOCRYPT_AUTOCRYPT_PRIVATE_H +#define MUTT_AUTOCRYPT_AUTOCRYPT_PRIVATE_H + +int mutt_autocrypt_db_init(int can_create); +void mutt_autocrypt_db_close(void); + +int mutt_autocrypt_schema_init(void); +int mutt_autocrypt_schema_update(void); + +#endif /* MUTT_AUTOCRYPT_AUTOCRYPT_PRIVATE_H */ diff --git a/autocrypt/autocrypt_schema.c b/autocrypt/autocrypt_schema.c new file mode 100644 index 000000000..756a88621 --- /dev/null +++ b/autocrypt/autocrypt_schema.c @@ -0,0 +1,123 @@ +/** + * @file + * XXX + * + * @authors + * Copyright (C) 2019 Kevin J. McCarthy + * + * @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 . + */ + +#include "config.h" +#include "autocrypt_private.h" +#include "mutt.h" +#include "autocrypt.h" + +int mutt_autocrypt_schema_init(void) +{ + const char *schema; + char *errmsg = NULL; + + schema = "BEGIN TRANSACTION; " + + "CREATE TABLE account (" + "email_addr text primary key not null, " + "keyid text, " + "keydata text, " + "prefer_encrypt int, " + "enabled int);" + + "CREATE TABLE peer (" + "email_addr text primary key not null, " + "last_seen int, " + "autocrypt_timestamp int, " + "keyid text, " + "keydata text, " + "prefer_encrypt int, " + "gossip_timestamp int, " + "gossip_keyid text, " + "gossip_keydata text);" + + "CREATE TABLE peer_history (" + "peer_email_addr text not null, " + "email_msgid text, " + "timestamp int, " + "keydata text);" + + "CREATE INDEX peer_history_email " + "ON peer_history (" + "peer_email_addr);" + + "CREATE TABLE gossip_history (" + "peer_email_addr text not null, " + "sender_email_addr text, " + "email_msgid text, " + "timestamp int, " + "gossip_keydata text);" + + "CREATE INDEX gossip_history_email " + "ON gossip_history (" + "peer_email_addr);" + + "CREATE TABLE schema (" + "version int);" + + "INSERT into schema (version) values (1);" + + "COMMIT TRANSACTION"; + + if (sqlite3_exec(AutocryptDB, schema, NULL, NULL, &errmsg) != SQLITE_OK) + { + mutt_debug(LL_DEBUG1, "mutt_autocrypt_schema_init() returned %s\n", errmsg); + sqlite3_free(errmsg); + return -1; + } + return 0; +} + +int mutt_autocrypt_schema_update(void) +{ + sqlite3_stmt *stmt = NULL; + int rv = -1, version; + + if (sqlite3_prepare_v2(AutocryptDB, "SELECT version FROM schema;", -1, &stmt, NULL) != SQLITE_OK) + goto cleanup; + + if (sqlite3_step(stmt) != SQLITE_ROW) + goto cleanup; + + version = sqlite3_column_int(stmt, 0); + + if (version > 1) + { + /* L10N: + The autocrypt database keeps track of schema version numbers. + This error occurs if the version number is too high. + Presumably because this is an old version of mutt and the + database was upgraded by a future version. + */ + mutt_error(_("Autocrypt database version is too new")); + goto cleanup; + } + + /* TODO: schema version upgrades go here. + * Bump one by one, each update inside a transaction. */ + + rv = 0; + +cleanup: + sqlite3_finalize(stmt); + return rv; +} diff --git a/main.c b/main.c index 37c436ad7..9bf30e242 100644 --- a/main.c +++ b/main.c @@ -737,7 +737,8 @@ int main(int argc, char *argv[], char *envp[]) /* Initialize crypto backends. */ crypt_init(); #ifdef USE_AUTOCRYPT - mutt_autocrypt_init(); + if (C_Autocrypt) + mutt_autocrypt_init(!(sendflags & SEND_BATCH)); #endif if (new_magic)