From: Kevin McCarthy Date: Sat, 6 Jul 2019 21:01:13 +0000 (-0700) Subject: Add database and schema initialization. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=be89dc7b3c3af202cfb770550fdf0083ee6ac253;p=mutt Add database and schema initialization. Add mutt_mkdir() library function supporting recursive mkdir. --- diff --git a/autocrypt/Makefile.am b/autocrypt/Makefile.am index 235c43c2..a874a3d1 100644 --- a/autocrypt/Makefile.am +++ b/autocrypt/Makefile.am @@ -7,4 +7,5 @@ AM_CPPFLAGS = -I$(top_srcdir) -I../intl noinst_LIBRARIES = libautocrypt.a -libautocrypt_a_SOURCES = autocrypt.c autocrypt.h +libautocrypt_a_SOURCES = autocrypt.c autocrypt.h autocrypt_db.c autocrypt_private.h \ + autocrypt_schema.c diff --git a/autocrypt/autocrypt.c b/autocrypt/autocrypt.c index 6aecf6fe..fe40b613 100644 --- a/autocrypt/autocrypt.c +++ b/autocrypt/autocrypt.c @@ -22,13 +22,68 @@ #include "mutt.h" #include "autocrypt.h" +#include "autocrypt_private.h" -void mutt_autocrypt_init (void) +#include + +static int autocrypt_dir_init (int can_create) { + int rv = 0; + struct stat sb; + BUFFER *prompt = NULL; + + if (!stat (AutocryptDir, &sb)) + return 0; + + if (!can_create) + return -1; + + prompt = mutt_buffer_pool_get (); + mutt_buffer_printf (prompt, _("%s does not exist. Create it?"), AutocryptDir); + if (mutt_yesorno (mutt_b2s (prompt), MUTT_YES) == MUTT_YES) + { + if (mutt_mkdir (AutocryptDir, 0700) < 0) + { + mutt_error ( _("Can't create %s: %s."), AutocryptDir, strerror (errno)); + mutt_sleep (0); + rv = -1; + } + } + + mutt_buffer_pool_release (&prompt); + return rv; +} + +int mutt_autocrypt_init (int can_create) +{ + if (AutocryptDB) + return 0; + + if (!option (OPTAUTOCRYPT) || !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? + */ dprint (1, (debugfile, "In mutt_autocrypt_init()\n")); + return 0; + +bail: + unset_option (OPTAUTOCRYPT); + mutt_autocrypt_db_close (); + return -1; } void mutt_autocrypt_cleanup (void) { + mutt_autocrypt_db_close (); dprint (1, (debugfile, "In mutt_autocrypt_cleanup()\n")); } diff --git a/autocrypt/autocrypt.h b/autocrypt/autocrypt.h index f866e76b..2429539e 100644 --- a/autocrypt/autocrypt.h +++ b/autocrypt/autocrypt.h @@ -19,7 +19,11 @@ #ifndef _AUTOCRYPT_H #define _AUTOCRYPT_H 1 -void mutt_autocrypt_init (void); +#include + +WHERE sqlite3 *AutocryptDB; + +int mutt_autocrypt_init (int); void mutt_autocrypt_cleanup (void); #endif diff --git a/autocrypt/autocrypt_db.c b/autocrypt/autocrypt_db.c new file mode 100644 index 00000000..e7baa603 --- /dev/null +++ b/autocrypt/autocrypt_db.c @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2019 Kevin J. McCarthy + * + * 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 "autocrypt.h" +#include "autocrypt_private.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); + mutt_sleep (0); + return -1; + } + return mutt_autocrypt_schema_init (); +} + +int mutt_autocrypt_db_init (int can_create) +{ + int rv = -1; + BUFFER *db_path = NULL; + struct stat sb; + + if (AutocryptDB) + return 0; + + if (!option (OPTAUTOCRYPT) || !AutocryptDir) + return -1; + + db_path = mutt_buffer_pool_get (); + mutt_buffer_concat_path (db_path, 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)); + mutt_sleep (0); + 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 00000000..56f0dda3 --- /dev/null +++ b/autocrypt/autocrypt_private.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2019 Kevin J. McCarthy + * + * 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. + */ + +#ifndef _AUTOCRYPT_PRIVATE_H +#define _AUTOCRYPT_PRIVATE_H 1 + +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 diff --git a/autocrypt/autocrypt_schema.c b/autocrypt/autocrypt_schema.c new file mode 100644 index 00000000..cb9d63d6 --- /dev/null +++ b/autocrypt/autocrypt_schema.c @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2019 Kevin J. McCarthy + * + * 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 "autocrypt.h" +#include "autocrypt_private.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) + { + dprint (1, (debugfile, "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"); + mutt_sleep (0); + 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/lib.c b/lib.c index ed93c846..16fa21a9 100644 --- a/lib.c +++ b/lib.c @@ -307,6 +307,41 @@ char *mutt_strlower (char *s) return (s); } +int mutt_mkdir (char *path, mode_t mode) +{ + struct stat sb; + char *s; + int rv = -1; + + if (stat (path, &sb) >= 0) + return 0; + + s = path; + do + { + s = strchr (s + 1, '/'); + if (s) + *s = '\0'; + if (stat (path, &sb) < 0) + { + if (errno != ENOENT) + goto cleanup; + if (mkdir (path, mode) < 0) + goto cleanup; + } + if (s) + *s = '/'; + } while (s); + + rv = 0; + +cleanup: + if (s) + *s = '/'; + + return rv; +} + void mutt_unlink (const char *s) { int fd; diff --git a/lib.h b/lib.h index 1cc1b610..09c25d76 100644 --- a/lib.h +++ b/lib.h @@ -218,6 +218,7 @@ void mutt_nocurses_error (const char *, ...); void mutt_remove_trailing_ws (char *); void mutt_sanitize_filename (char *, short); void mutt_str_replace (char **p, const char *s); +int mutt_mkdir (char *path, mode_t mode); void mutt_str_adjust (char **p); void mutt_unlink (const char *); void safe_free (void *); diff --git a/main.c b/main.c index 7b32dbd1..9f4c7d2b 100644 --- a/main.c +++ b/main.c @@ -868,7 +868,8 @@ int main (int argc, char **argv, char **environ) /* Initialize crypto backends. */ crypt_init (); #ifdef USE_AUTOCRYPT - mutt_autocrypt_init (); + if (option (OPTAUTOCRYPT)) + mutt_autocrypt_init (!(sendflags & SENDBATCH)); #endif if (newMagic)