diff --git a/lib/Makefile.am b/lib/Makefile.am index b0663523..cf563602 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -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 diff --git a/lib/mu-runtime.c b/lib/mu-runtime.c deleted file mode 100644 index 0ddee988..00000000 --- a/lib/mu-runtime.c +++ /dev/null @@ -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 -** -** 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 -#include /* for setlocale() */ -#include /* for fileno() */ -#include -#include -#include - -#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=\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); -} diff --git a/lib/mu-runtime.cc b/lib/mu-runtime.cc new file mode 100644 index 00000000..e4ea62a8 --- /dev/null +++ b/lib/mu-runtime.cc @@ -0,0 +1,115 @@ +/* +** Copyright (C) 2019 Dirk-Jan C. Binnema +** +** 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 /* for setlocale() */ +#include +static std::unordered_map 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(); +} diff --git a/lib/mu-runtime.h b/lib/mu-runtime.h index 87751636..2dc650eb 100644 --- a/lib/mu-runtime.h +++ b/lib/mu-runtime.h @@ -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 +** Copyright (C) 2012-2019 Dirk-Jan C. Binnema ** ** 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 diff --git a/lib/mu-util.c b/lib/mu-util.c index a25e145e..4dfb4af3 100644 --- a/lib/mu-util.c +++ b/lib/mu-util.c @@ -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) { diff --git a/lib/mu-util.h b/lib/mu-util.h index fb891edf..302db23c 100644 --- a/lib/mu-util.h +++ b/lib/mu-util.h @@ -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) diff --git a/man/mu-bookmarks.5 b/man/mu-bookmarks.5 index 4e167e61..f68a3358 100644 --- a/man/mu-bookmarks.5 +++ b/man/mu-bookmarks.5 @@ -1,17 +1,18 @@ -.TH MU-BOOKMARKS 5 "May 2011" "User Manuals" +.TH MU-BOOKMARKS 5 "July 2019" "User Manuals" -.SH NAME +.SH NAME bookmarks \- file with bookmarks (shortcuts) for mu search expressions .SH DESCRIPTION -Bookmarks are named shortcuts for search queries. They allow using a -convenient name for often-used queries. The bookmarks are also visible as -shortcuts in the mu experimental user interfaces, \fImug\fR and \fImug2\fR. +Bookmarks are named shortcuts for search queries. They allow using a convenient +name for often-used queries. The bookmarks are also visible as shortcuts in the +mu experimental user interfaces, \fImug\fR and \fImug2\fR. -\fBmu\fR supports bookmarks stored in a file called \fBbookmarks\fR in the mu -home directory (typically, this would be \fI~/.mu/bookmarks\fR). +The bookmarks file is read from \fI/bookmarks\fR. On Unix this would +typically be w be \fI~/.config/mu/bookmarks\fR, but this can be influenced using +the \fB\-\-muhome\fR parameter for \fBmu-find\fR(1) and \fBmug\fR(1). The bookmarks file is a typical key=value \fB.ini\fR-file, which is best shown by means of an example: @@ -26,12 +27,6 @@ The \fB[mu]\fR group header is required. For practical uses of bookmarks, see \fBmu-find\fR(1). -.SH LOCATION - -The bookmarks file is read from \fI/bookmarks\fR. Typically, this -would be \fI~/.mu/bookmarks\fR, but this can be influenced using the -\fB\-\-muhome\fR parameter for \fBmu-find\fR(1) and \fBmug\fR(1). - .SH AUTHOR Dirk-Jan C. Binnema diff --git a/man/mu.1 b/man/mu.1 index 1d85254b..6b4c88c1 100644 --- a/man/mu.1 +++ b/man/mu.1 @@ -1,4 +1,4 @@ -.TH MU 1 "September 2018" "User Manuals" +.TH MU 1 "July 2019" "User Manuals" .SH NAME @@ -120,10 +120,10 @@ including \fBmu\fR without any command. .TP \fB\-\-muhome\fR -causes \fBmu\fR to use an alternative directory to -store and read its database and logs. By default, \fBmu\fR uses -whatever the \fBMU_HOME\fR environment variable is set to; if it is -not set, \fI~/.mu\fR is used. +use an alternative directory to store and read the database, write the logs, +etc. By default, \fBmu\fR uses XDG Base Directory Specification (e.g. on Linux +by default \fI~/.cache/mu\fR, \fI~/.config/mu\fR). Earlier versions of \fBmu\fR defaulted +to \fI~/.mu\fR, which now requires \fI\-\-muhome=~/.mu\fR. .TP \fB\-d\fR, \fB\-\-debug\fR @@ -157,40 +157,7 @@ lists the various command line options. .SH ERROR CODES The various mu subcommands typically exit with 0 (zero) upon success, and -non-zero when some error occurred. The table lists the various error codes. - -.nf -exit code | error -----------+------------------------------------------- - 1 | MU_ERROR - 2 | MU_ERROR_IN_PARAMETERS - 3 | MU_ERROR_INTERNAL - 4 | MU_ERROR_NO_MATCHES - | - 11 | MU_ERROR_XAPIAN - | - 13 | MU_ERROR_XAPIAN_QUERY - 14 | MU_ERROR_XAPIAN_DIR_NOT_ACCESSIBLE - 15 | MU_ERROR_XAPIAN_NOT_UP_TO_DATE - 16 | MU_ERROR_XAPIAN_MISSING_DATA - 17 | MU_ERROR_XAPIAN_CORRUPTION - 18 | MU_ERROR_XAPIAN_CANNOT_GET_WRITELOCK - 30 | MU_ERROR_GMIME - | - 50 | MU_ERROR_CONTACTS - 51 | MU_ERROR_CONTACTS_CANNOT_RETRIEVE - | - 70 | MU_ERROR_FILE - 71 | MU_ERROR_FILE_INVALID_NAME - 72 | MU_ERROR_FILE_CANNOT_LINK - 73 | MU_ERROR_FILE_CANNOT_OPEN - 74 | MU_ERROR_FILE_CANNOT_READ - 75 | MU_ERROR_FILE_CANNOT_CREATE - 76 | MU_ERROR_FILE_CANNOT_MKDIR - 77 | MU_ERROR_FILE_STAT_FAILED - 78 | MU_ERROR_FILE_READDIR_FAILED - 79 | MU_ERROR_FILE_INVALID_SOURCE -.fi +non-zero when some error occurred. .SH BUGS @@ -204,3 +171,4 @@ Dirk-Jan C. Binnema .SH "SEE ALSO" .BR mu-index (1), mu-find (1), mu-cfind (1), mu-mkdir (1), mu-view (1), .BR mu-extract (1), mu-easy (1), mu-bookmarks (5), mu-query (7) +.BR https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html diff --git a/mu/mu-config.c b/mu/mu-config.c index 27a49013..ea29c6e0 100644 --- a/mu/mu-config.c +++ b/mu/mu-config.c @@ -69,15 +69,16 @@ get_output_format (const char *formatstr) static void set_group_mu_defaults (void) { - gchar *exp; + /* If muhome is not set, we use the XDG Base Directory Specification + * locations. */ - if (!MU_CONFIG.muhome) - MU_CONFIG.muhome = mu_util_guess_mu_homedir(); - - exp = mu_util_dir_expand(MU_CONFIG.muhome); - if (exp) { - g_free(MU_CONFIG.muhome); - MU_CONFIG.muhome = exp; + if (MU_CONFIG.muhome) { + gchar *exp; + exp = mu_util_dir_expand(MU_CONFIG.muhome); + if (exp) { + g_free(MU_CONFIG.muhome); + MU_CONFIG.muhome = exp; + } } /* check for the MU_NOCOLOR or NO_COLOR env vars; but in any case don't diff --git a/mu4e/mu4e-vars.el b/mu4e/mu4e-vars.el index 51c23c4b..9702b09f 100644 --- a/mu4e/mu4e-vars.el +++ b/mu4e/mu4e-vars.el @@ -34,7 +34,8 @@ :group 'mail) (defcustom mu4e-mu-home nil - "Location of the mu homedir, or nil for the default." + "Location of an alternate mu home dir. If not set, use the +defaults, based on the XDG Base Directory Specification." :group 'mu4e :type '(choice (const :tag "Default location" nil) (directory :tag "Specify location")) diff --git a/mu4e/mu4e.texi b/mu4e/mu4e.texi index d9a9f6e0..df34a2d1 100644 --- a/mu4e/mu4e.texi +++ b/mu4e/mu4e.texi @@ -12,7 +12,7 @@ @c %**end of header @copying -Copyright @copyright{} 2012-2018 Dirk-Jan C. Binnema +Copyright @copyright{} 2012-2019 Dirk-Jan C. Binnema @quotation Permission is granted to copy, distribute and/or modify this document @@ -2637,8 +2637,9 @@ invoke those function even in that case. the current context is also visible in the mode-line when in headers, view or main mode. @item You can set any kind of variable; including settings for mail servers etc. -However, settings such as @code{mu4e-maildir} and @code{mu4e-mu-home} are -not changeable after they have been set without quitting @t{mu4e} first. +However, settings such as @code{mu4e-maildir} and @code{mu4e-mu-home} +are not changeable after they have been set without quitting @t{mu4e} +first. @item @code{leave-func} (if defined) for the context we are leaving, is invoked before the @code{enter-func} (if defined) of the context we are entering. @@ -3917,7 +3918,7 @@ Use @kbd{M-x mu4e-update-index} errors like:} @verbatim mu: mu_store_new_writable: xapian error - 'Unable to get write lock on ~/.mu/xapian: already locked + 'Unable to get write lock on ~/.cache/mu/xapian: already locked @end verbatim @emph{What to do about this?} You get this error because the underlying Xapian database is locked by some other process; it can be opened only once in @@ -4736,10 +4737,10 @@ log-buffer is called @t{*mu4e-log*}, and in the @ref{Main view}, @ref{Headers view} and @ref{Message view}, there's a keybinding @key{$} that takes you there. You can quit it by pressing @key{q}. -Logging can be a bit resource-intensive, so you may not want to leave it on -all the time. By default, the log only maintains the most recent 1200 -lines. @t{mu} itself keeps a log as well, you can find this it in -@t{/log/mu.log}, typically @t{~/.mu/log/mu.log}. +Logging can be a bit resource-intensive, so you may not want to leave +it on all the time. By default, the log only maintains the most recent +1200 lines. @t{mu} itself keeps a log as well, you can find it in +@t{/mu.log}, on Unix typically @t{~/.cache/mu/mu.log}. @node GNU Free Documentation License @appendix GNU Free Documentation License