]> granicus.if.org Git - mutt/commitdiff
Add database and schema initialization.
authorKevin McCarthy <kevin@8t8.us>
Sat, 6 Jul 2019 21:01:13 +0000 (14:01 -0700)
committerKevin McCarthy <kevin@8t8.us>
Sat, 3 Aug 2019 21:08:09 +0000 (14:08 -0700)
Add mutt_mkdir() library function supporting recursive mkdir.

autocrypt/Makefile.am
autocrypt/autocrypt.c
autocrypt/autocrypt.h
autocrypt/autocrypt_db.c [new file with mode: 0644]
autocrypt/autocrypt_private.h [new file with mode: 0644]
autocrypt/autocrypt_schema.c [new file with mode: 0644]
lib.c
lib.h
main.c

index 235c43c298c2282b1520a6e318c2c4a5a3d9d828..a874a3d16101bb193433a312f8bfc4dc13878db3 100644 (file)
@@ -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
index 6aecf6febbfd2ad04a4e96332682e5b14a63a407..fe40b6131f299665b7bc3f24cc309a67f840f21c 100644 (file)
 
 #include "mutt.h"
 #include "autocrypt.h"
+#include "autocrypt_private.h"
 
-void mutt_autocrypt_init (void)
+#include <errno.h>
+
+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"));
 }
index f866e76b90f9ba9b6453acb0706670b944a257b7..2429539efd352eb16ce1764e86688f9e715becfe 100644 (file)
 #ifndef _AUTOCRYPT_H
 #define _AUTOCRYPT_H 1
 
-void mutt_autocrypt_init (void);
+#include <sqlite3.h>
+
+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 (file)
index 0000000..e7baa60
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * 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 "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 (file)
index 0000000..56f0dda
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+#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 (file)
index 0000000..cb9d63d
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * 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 "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 ed93c846c0a9f5c55cfed998b3e60eb1e38a3b0b..16fa21a9c8b66cce85c266970df70c5fdddb1bbb 100644 (file)
--- 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 1cc1b61010863bc7539577468c9c8f592c359229..09c25d76af6518020d6c52cef987383d9ac5b060 100644 (file)
--- 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 7b32dbd180f88a655dc50869201b027ff59ba258..9f4c7d2b5f32a922c9d3bb0755f6fc35ff674778 100644 (file)
--- 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)