#include <unistd.h>
#include <libgen.h>
#include "database-private.h"
#include "parse-time-vrp.h"
#include "path-util.h"
#if HAVE_XAPIAN_DB_RETRY_LOCK
#define DB_ACTION (Xapian::DB_CREATE_OR_OPEN | Xapian::DB_RETRY_LOCK)
#else
#define DB_ACTION Xapian::DB_CREATE_OR_OPEN
#endif
notmuch_status_t
notmuch_database_open (const char *path,
notmuch_database_mode_t mode,
notmuch_database_t **database)
{
char *status_string = NULL;
notmuch_status_t status;
status = notmuch_database_open_verbose (path, mode, database,
&status_string);
if (status_string) {
fputs (status_string, stderr);
free (status_string);
}
return status;
}
notmuch_status_t
notmuch_database_open_verbose (const char *path,
notmuch_database_mode_t mode,
notmuch_database_t **database,
char **status_string)
{
return notmuch_database_open_with_config (path, mode, "", NULL,
database, status_string);
}
static const char *
_xdg_dir (void *ctx,
const char *xdg_root_variable,
const char *xdg_prefix,
const char *profile_name)
{
const char *xdg_root = getenv (xdg_root_variable);
if (! xdg_root) {
const char *home = getenv ("HOME");
if (! home) return NULL;
xdg_root = talloc_asprintf (ctx,
"%s/%s",
home,
xdg_prefix);
}
if (! profile_name)
profile_name = getenv ("NOTMUCH_PROFILE");
if (! profile_name)
profile_name = "default";
return talloc_asprintf (ctx,
"%s/notmuch/%s",
xdg_root,
profile_name);
}
static notmuch_status_t
_choose_dir (notmuch_database_t *notmuch,
const char *profile,
notmuch_config_key_t key,
const char *xdg_var,
const char *xdg_subdir,
const char *subdir,
char **message = NULL)
{
const char *parent;
const char *dir;
struct stat st;
int err;
dir = notmuch_config_get (notmuch, key);
if (dir)
return NOTMUCH_STATUS_SUCCESS;
parent = _xdg_dir (notmuch, xdg_var, xdg_subdir, profile);
if (! parent)
return NOTMUCH_STATUS_PATH_ERROR;
dir = talloc_asprintf (notmuch, "%s/%s", parent, subdir);
err = stat (dir, &st);
if (err) {
if (errno == ENOENT) {
char *notmuch_path = dirname (talloc_strdup (notmuch, notmuch->xapian_path));
dir = talloc_asprintf (notmuch, "%s/%s", notmuch_path, subdir);
} else {
IGNORE_RESULT (asprintf (message, "Error: Cannot stat %s: %s.\n",
dir, strerror (errno)));
return NOTMUCH_STATUS_FILE_ERROR;
}
}
_notmuch_config_cache (notmuch, key, dir);
return NOTMUCH_STATUS_SUCCESS;
}
static notmuch_status_t
_load_key_file (notmuch_database_t *notmuch,
const char *path,
const char *profile,
GKeyFile **key_file)
{
notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
if (path && EMPTY_STRING (path))
goto DONE;
if (! path)
path = getenv ("NOTMUCH_CONFIG");
if (path)
path = talloc_strdup (notmuch, path);
else {
const char *dir = _xdg_dir (notmuch, "XDG_CONFIG_HOME", ".config", profile);
if (dir) {
path = talloc_asprintf (notmuch, "%s/config", dir);
if (access (path, R_OK) != 0)
path = NULL;
}
}
if (! path) {
const char *home = getenv ("HOME");
path = talloc_asprintf (notmuch, "%s/.notmuch-config", home);
if (! profile)
profile = getenv ("NOTMUCH_PROFILE");
if (profile)
path = talloc_asprintf (notmuch, "%s.%s", path, profile);
}
*key_file = g_key_file_new ();
if (! g_key_file_load_from_file (*key_file, path, G_KEY_FILE_NONE, NULL)) {
status = NOTMUCH_STATUS_NO_CONFIG;
}
DONE:
if (path)
notmuch->config_path = path;
return status;
}
static notmuch_status_t
_db_dir_exists (const char *database_path, char **message)
{
struct stat st;
int err;
err = stat (database_path, &st);
if (err) {
IGNORE_RESULT