mu: Default to XDG Base Directory Specification

Instead of using ~/.mu, use the XDG Base Directory Specification, typically:
  ~/.cache/xapian
  ~/.cache/mu.log
  ~/.cache/parts
  ~/.config/bookmarks

Update dependencies, documentation.
This commit is contained in:
Dirk-Jan C. Binnema
2019-07-12 17:36:08 +03:00
parent 003d0a39b5
commit 632f383c38
11 changed files with 156 additions and 343 deletions

View File

@ -64,7 +64,6 @@ libmu_la_SOURCES= \
mu-bookmarks.h \
mu-contacts.cc \
mu-contacts.hh \
mu-contacts.h \
mu-container.c \
mu-container.h \
mu-date.c \
@ -98,7 +97,7 @@ libmu_la_SOURCES= \
mu-msg.h \
mu-query.cc \
mu-query.h \
mu-runtime.c \
mu-runtime.cc \
mu-runtime.h \
mu-script.c \
mu-script.h \
@ -125,7 +124,6 @@ libmu_la_LIBADD= \
libmu_la_LDFLAGS= \
$(ASAN_LDFLAGS)
EXTRA_DIST= \
mu-msg-crypto.c \
doxyfile.in

View File

@ -1,206 +0,0 @@
/* -*- mode: c; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
**
** Copyright (C) 2010-2013 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
**
** 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 3, 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.
**
*/
#include "mu-runtime.h"
#include <glib-object.h>
#include <locale.h> /* for setlocale() */
#include <stdio.h> /* for fileno() */
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include "mu-msg.h"
#include "mu-log.h"
#include "mu-util.h"
#define MU_XAPIAN_DIRNAME "xapian"
#define MU_BOOKMARKS_FILENAME "bookmarks"
#define MU_CACHE_DIRNAME "cache"
#define MU_CONTACTS_FILENAME "contacts"
#define MU_LOG_DIRNAME "log"
struct _MuRuntimeData {
gchar *_str[MU_RUNTIME_PATH_NUM];
gchar *_name; /* e.g., 'mu', 'mug' */
};
typedef struct _MuRuntimeData MuRuntimeData;
/* static, global data for this singleton */
static gboolean _initialized = FALSE;
static MuRuntimeData *_data = NULL;
static void runtime_free (void);
static gboolean init_paths (const char* muhome, MuRuntimeData *data);
static const char* runtime_path (MuRuntimePath path);
static gboolean
init_log (const char *muhome, const char *name, MuLogOptions opts)
{
gboolean rv;
char *logpath;
logpath = g_strdup_printf ("%s%c%s%c%s.log",
muhome, G_DIR_SEPARATOR,
MU_LOG_DIRNAME, G_DIR_SEPARATOR,
name);
rv = mu_log_init (logpath, opts);
g_free (logpath);
return rv;
}
gboolean
mu_runtime_init (const char* muhome_arg, const char *name)
{
gchar *muhome;
g_return_val_if_fail (!_initialized, FALSE);
g_return_val_if_fail (name, FALSE);
setlocale (LC_ALL, "");
if (muhome_arg)
muhome = g_strdup (muhome_arg);
else
muhome = mu_util_guess_mu_homedir ();
if (!mu_util_create_dir_maybe (muhome, 0700, TRUE)) {
g_printerr ("mu: invalid mu homedir specified;"
" use --muhome=<dir>\n");
runtime_free ();
return FALSE;
}
_data = g_new0 (MuRuntimeData, 1);
_data->_str[MU_RUNTIME_PATH_MUHOME] = muhome;
init_paths (muhome, _data);
_data->_name = g_strdup (name);
if (!init_log (muhome, name, MU_LOG_OPTIONS_BACKUP)) {
runtime_free ();
g_free (muhome);
return FALSE;
}
return _initialized = TRUE;
}
static void
runtime_free (void)
{
int i;
mu_log_uninit();
if (!_data)
return;
for (i = 0; i != MU_RUNTIME_PATH_NUM; ++i)
g_free (_data->_str[i]);
g_free (_data->_name);
g_free (_data);
}
void
mu_runtime_uninit (void)
{
if (!_initialized)
return;
runtime_free ();
_initialized = FALSE;
}
static gboolean
create_dirs_maybe (MuRuntimeData *data)
{
if (!mu_util_create_dir_maybe
(data->_str[MU_RUNTIME_PATH_CACHE], 0700, TRUE)) {
g_warning ("failed to create cache dir");
return FALSE;
}
if (!mu_util_create_dir_maybe
(data->_str[MU_RUNTIME_PATH_LOG], 0700, TRUE)) {
g_warning ("failed to create log dir");
return FALSE;
}
return TRUE;
}
static gboolean
init_paths (const char* muhome, MuRuntimeData *data)
{
data->_str [MU_RUNTIME_PATH_XAPIANDB] =
g_strdup_printf ("%s%c%s", muhome, G_DIR_SEPARATOR,
MU_XAPIAN_DIRNAME);
data->_str [MU_RUNTIME_PATH_BOOKMARKS] =
g_strdup_printf ("%s%c%s", muhome, G_DIR_SEPARATOR,
MU_BOOKMARKS_FILENAME);
data->_str [MU_RUNTIME_PATH_CACHE] =
g_strdup_printf ("%s%c%s", muhome, G_DIR_SEPARATOR,
MU_CACHE_DIRNAME);
data->_str [MU_RUNTIME_PATH_CONTACTS] =
g_strdup_printf ("%s%c%s", data->_str[MU_RUNTIME_PATH_CACHE],
G_DIR_SEPARATOR, MU_CONTACTS_FILENAME);
data->_str [MU_RUNTIME_PATH_LOG] =
g_strdup_printf ("%s%c%s", muhome,
G_DIR_SEPARATOR, MU_LOG_DIRNAME);
if (!create_dirs_maybe (data))
return FALSE;
return TRUE;
}
/* so we can called when _initialized is FALSE still */
static const char*
runtime_path (MuRuntimePath path)
{
return _data->_str[path];
}
const char*
mu_runtime_path (MuRuntimePath path)
{
g_return_val_if_fail (_initialized, NULL);
g_return_val_if_fail (path < MU_RUNTIME_PATH_NUM, NULL);
return runtime_path (path);
}

115
lib/mu-runtime.cc Normal file
View File

@ -0,0 +1,115 @@
/*
** Copyright (C) 2019 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
**
** 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 3, 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.
**
*/
#include "mu-runtime.h"
#include "mu-util.h"
#include <locale.h> /* for setlocale() */
#include <unordered_map>
static std::unordered_map<MuRuntimePath, std::string> RuntimePaths;
#include "mu-log.h"
constexpr auto PartsDir = "parts";
constexpr auto LogDir = "log";
constexpr auto XapianDir = "xapian";
constexpr auto Mu = "mu";
constexpr auto Bookmarks = "bookmarks";
static const std::string Sepa{G_DIR_SEPARATOR_S};
static void
init_paths_xdg ()
{
RuntimePaths.emplace(MU_RUNTIME_PATH_XAPIANDB, g_get_user_cache_dir() +
Sepa + Mu + Sepa + XapianDir);
RuntimePaths.emplace(MU_RUNTIME_PATH_MIMECACHE, g_get_user_cache_dir() +
Sepa + Mu + Sepa + PartsDir);
RuntimePaths.emplace(MU_RUNTIME_PATH_LOGDIR, g_get_user_cache_dir() +
Sepa + Mu);
RuntimePaths.emplace(MU_RUNTIME_PATH_BOOKMARKS, g_get_user_config_dir() +
Sepa + Mu);
}
static void
init_paths_muhome (const char *muhome)
{
RuntimePaths.emplace(MU_RUNTIME_PATH_XAPIANDB, muhome + Sepa + XapianDir);
RuntimePaths.emplace(MU_RUNTIME_PATH_MIMECACHE, muhome + Sepa + PartsDir);
RuntimePaths.emplace(MU_RUNTIME_PATH_LOGDIR, muhome + Sepa + LogDir);
RuntimePaths.emplace(MU_RUNTIME_PATH_BOOKMARKS, muhome + Sepa + Bookmarks);
}
gboolean
mu_runtime_init (const char* muhome, const char *name)
{
g_return_val_if_fail (RuntimePaths.empty(), FALSE);
g_return_val_if_fail (name, FALSE);
setlocale (LC_ALL, "");
if (muhome)
init_paths_muhome (muhome);
else
init_paths_xdg();
for (const auto& d: RuntimePaths ) {
char* dir;
if (d.first == MU_RUNTIME_PATH_BOOKMARKS) // special case
dir = g_path_get_dirname (d.second.c_str());
else
dir = g_strdup (d.second.c_str());
auto ok = mu_util_create_dir_maybe (dir, 0700, TRUE);
if (!ok) {
g_critical ("failed to create %s", dir);
g_free (dir);
mu_runtime_uninit();
return FALSE;
}
g_free (dir);
}
const auto log_path = RuntimePaths[MU_RUNTIME_PATH_LOGDIR] +
Sepa + name + ".log";
if (!mu_log_init (log_path.c_str(), MU_LOG_OPTIONS_BACKUP)) {
mu_runtime_uninit();
return FALSE;
}
return TRUE;
}
void
mu_runtime_uninit (void)
{
RuntimePaths.clear();
mu_log_uninit();
}
const char*
mu_runtime_path (MuRuntimePath path)
{
const auto it = RuntimePaths.find (path);
if (it == RuntimePaths.end())
return NULL;
else
return it->second.c_str();
}

View File

@ -1,6 +1,6 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
**
** Copyright (C) 2012-2013 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
** Copyright (C) 2012-2019 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
**
** 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
@ -37,24 +37,6 @@ G_BEGIN_DECLS
*/
gboolean mu_runtime_init (const char *muhome, const char *name);
/**
* initialize the mu runtime system with comand line argument; this
* will parse the command line assuming the parameters of the 'mu'
* program. Initializes logging and other systems. To uninitialize,
* use mu_runtime_uninit
*
* @param ptr to the param count (typically, argc)
* @param ptr to the params (typically, argv)
* @param name of the main program, ie. 'mu', 'mug' or
* 'procmule'. this influences the name of the e.g. the logfile
*
* @return TRUE if succeeded, FALSE in case of error
*/
gboolean mu_runtime_init_from_cmdline (int *pargc, char ***pargv,
const char *name);
/**
* free all resources
*
@ -62,17 +44,14 @@ gboolean mu_runtime_init_from_cmdline (int *pargc, char ***pargv,
void mu_runtime_uninit (void);
enum _MuRuntimePath {
MU_RUNTIME_PATH_MUHOME, /* mu home path */
typedef enum {
MU_RUNTIME_PATH_XAPIANDB, /* mu xapian db path */
MU_RUNTIME_PATH_BOOKMARKS, /* mu bookmarks file path */
MU_RUNTIME_PATH_CACHE, /* mu cache path */
MU_RUNTIME_PATH_LOG, /* mu path for log files */
MU_RUNTIME_PATH_CONTACTS, /* mu path to the contacts cache */
MU_RUNTIME_PATH_MIMECACHE, /* mu cache path for attachments etc. */
MU_RUNTIME_PATH_LOGDIR, /* mu path for log files */
MU_RUNTIME_PATH_NUM
};
typedef enum _MuRuntimePath MuRuntimePath;
} MuRuntimePath;
/**
* get a file system path to some 'special' file or directory

View File

@ -194,32 +194,6 @@ mu_util_guess_maildir (void)
return NULL;
}
gchar*
mu_util_guess_mu_homedir (void)
{
const char* home;
const gchar *hdir1;
/* first, try MU_HOME */
hdir1 = g_getenv ("MU_HOME");
if (hdir1 && mu_util_check_dir (hdir1, TRUE, FALSE))
return g_strdup (hdir1);
/* then, g_get_home_dir use /etc/passwd, not $HOME; this is
* better, as HOME may be wrong when using 'sudo' etc.*/
home = g_get_home_dir ();
if (!home) {
MU_WRITE_LOG ("failed to determine homedir");
return NULL;
}
return g_strdup_printf ("%s%c%s", home ? home : ".",
G_DIR_SEPARATOR, ".mu");
}
gboolean
mu_util_create_dir_maybe (const gchar *path, mode_t mode, gboolean nowarn)
{

View File

@ -60,19 +60,6 @@ char* mu_util_dir_expand (const char* path)
char* mu_util_guess_maildir (void)
G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
/**
* guess the place of the mu homedir; first try $MU_HOME; if it is
* unset or non-existant, try ~/.mu. Note, the fallback ~/.mu
* directory does not necessarily exist. mu_util_check_dir can be used
* to check that
*
* @return the guessed mu homedir, which needs to be freed with g_free
* when no longer needed.
*/
gchar* mu_util_guess_mu_homedir (void)
G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
/**
* if path exists, check that's a read/writeable dir; otherwise try to
* create it (with perms 0700)