Browse Source

core: split WeeChat home in 4 directories, use XDG directories by default (issue #1285)

The 4 directories (which can be the same):

- config: configuration files, certificates
- data: log/upgrade files, local plugins, scripts, xfer files
- cache: script repository, scripts downloaded (temporary location)
- runtime: FIFO pipe, relay UNIX sockets
master
Sébastien Helleu 2 years ago
parent
commit
0f9640a5f3
  1. 4
      src/core/wee-command.c
  2. 14
      src/core/wee-completion.c
  3. 10
      src/core/wee-config-file.c
  4. 26
      src/core/wee-debug.c
  5. 541
      src/core/wee-dir.c
  6. 4
      src/core/wee-dir.h
  7. 106
      src/core/wee-eval.c
  8. 20
      src/core/wee-log.c
  9. 14
      src/core/wee-network.c
  10. 25
      src/core/wee-string.c
  11. 4
      src/core/wee-upgrade-file.c
  12. 2
      src/core/wee-upgrade.c
  13. 39
      src/core/weechat.c
  14. 6
      src/core/weechat.h
  15. 5
      src/plugins/fifo/fifo-command.c
  16. 14
      src/plugins/fifo/fifo.c
  17. 3
      src/plugins/irc/irc-command.c
  18. 12
      src/plugins/irc/irc-sasl.c
  19. 12
      src/plugins/irc/irc-server.c
  20. 17
      src/plugins/logger/logger.c
  21. 101
      src/plugins/plugin-api-info.c
  22. 27
      src/plugins/plugin-api.c
  23. 96
      src/plugins/plugin-script.c
  24. 12
      src/plugins/plugin.c
  25. 14
      src/plugins/python/weechat-python.c
  26. 12
      src/plugins/relay/relay-network.c
  27. 26
      src/plugins/relay/relay-server.c
  28. 2
      src/plugins/script/script-action.c
  29. 18
      src/plugins/script/script-completion.c
  30. 34
      src/plugins/script/script-config.c
  31. 32
      src/plugins/script/script-repo.c
  32. 2
      src/plugins/script/script.c
  33. 4
      src/plugins/spell/spell.c
  34. 12
      src/plugins/xfer/xfer-file.c
  35. 28
      src/plugins/xfer/xfer.c
  36. 5
      tests/scripts/test-scripts.cpp
  37. 87
      tests/unit/core/test-core-dir.cpp
  38. 100
      tests/unit/core/test-core-string.cpp

4
src/core/wee-command.c

@ -6483,7 +6483,7 @@ COMMAND_CALLBACK(upgrade) @@ -6483,7 +6483,7 @@ COMMAND_CALLBACK(upgrade)
/* execute binary */
exec_args[0] = ptr_binary;
exec_args[3] = strdup (weechat_home);
exec_args[3] = dir_get_string_home_dirs ();
execvp (exec_args[0], exec_args);
/* this code should not be reached if execvp is OK */
@ -8332,7 +8332,7 @@ command_init () @@ -8332,7 +8332,7 @@ command_init ()
"IMPORTANT: you must restore the session with exactly same "
"configuration (files *.conf).\n"
"It is possible to restore WeeChat session on another machine if you "
"copy the content of directory \"~/.weechat\"."),
"copy the content of WeeChat home directories (see /debug dirs)."),
"%(filename)|-dummy|-quit",
&command_upgrade, NULL, NULL);
hook_command (

14
src/core/wee-completion.c

@ -573,7 +573,7 @@ completion_list_add_filename_cb (const void *pointer, void *data, @@ -573,7 +573,7 @@ completion_list_add_filename_cb (const void *pointer, void *data,
}
}
if (!real_prefix)
real_prefix = strdup (weechat_home);
real_prefix = strdup (weechat_data_dir);
prefix = strdup ("");
}
else
@ -984,6 +984,7 @@ completion_list_add_plugins_installed_cb (const void *pointer, void *data, @@ -984,6 +984,7 @@ completion_list_add_plugins_installed_cb (const void *pointer, void *data,
{
char *plugin_path, *dir_name, *extra_libdir;
int length;
struct t_hashtable *options;
/* make C compiler happy */
(void) pointer;
@ -1011,8 +1012,17 @@ completion_list_add_plugins_installed_cb (const void *pointer, void *data, @@ -1011,8 +1012,17 @@ completion_list_add_plugins_installed_cb (const void *pointer, void *data,
if (CONFIG_STRING(config_plugin_path)
&& CONFIG_STRING(config_plugin_path)[0])
{
options = hashtable_new (
32,
WEECHAT_HASHTABLE_STRING,
WEECHAT_HASHTABLE_STRING,
NULL, NULL);
if (options)
hashtable_set (options, "directory", "data");
plugin_path = string_eval_path_home (CONFIG_STRING(config_plugin_path),
NULL, NULL, NULL);
NULL, NULL, options);
if (options)
hashtable_free (options);
if (plugin_path)
{
dir_exec_on_files (plugin_path, 1, 0,

10
src/core/wee-config-file.c

@ -2366,13 +2366,13 @@ config_file_write_internal (struct t_config_file *config_file, @@ -2366,13 +2366,13 @@ config_file_write_internal (struct t_config_file *config_file,
return WEECHAT_CONFIG_WRITE_ERROR;
/* build filename */
filename_length = strlen (weechat_home) +
strlen (config_file->filename) + 2;
filename_length = strlen (weechat_config_dir) + strlen (DIR_SEPARATOR) +
strlen (config_file->filename) + 1;
filename = malloc (filename_length);
if (!filename)
return WEECHAT_CONFIG_WRITE_MEMORY_ERROR;
snprintf (filename, filename_length, "%s%s%s",
weechat_home, DIR_SEPARATOR, config_file->filename);
weechat_config_dir, DIR_SEPARATOR, config_file->filename);
/*
* build temporary filename, this temp file will be renamed to filename
@ -2561,13 +2561,13 @@ config_file_read_internal (struct t_config_file *config_file, int reload) @@ -2561,13 +2561,13 @@ config_file_read_internal (struct t_config_file *config_file, int reload)
return WEECHAT_CONFIG_READ_FILE_NOT_FOUND;
/* build filename */
filename_length = strlen (weechat_home) + strlen (DIR_SEPARATOR) +
filename_length = strlen (weechat_config_dir) + strlen (DIR_SEPARATOR) +
strlen (config_file->filename) + 1;
filename = malloc (filename_length);
if (!filename)
return WEECHAT_CONFIG_READ_MEMORY_ERROR;
snprintf (filename, filename_length, "%s%s%s",
weechat_home, DIR_SEPARATOR, config_file->filename);
weechat_config_dir, DIR_SEPARATOR, config_file->filename);
/* create file with default options if it does not exist */
if (access (filename, F_OK) != 0)

26
src/core/wee-debug.c

@ -161,7 +161,7 @@ debug_sigsegv_cb () @@ -161,7 +161,7 @@ debug_sigsegv_cb ()
string_fprintf (stderr,
"*** Full crash dump was saved to %s/weechat.log file."
"\n",
weechat_home);
weechat_data_dir);
}
string_fprintf (
stderr,
@ -590,19 +590,27 @@ debug_libs_cb (const void *pointer, void *data, @@ -590,19 +590,27 @@ debug_libs_cb (const void *pointer, void *data,
void
debug_directories ()
{
char *extra_libdir;
const char *ptr_home = WEECHAT_HOME;
char *extra_libdir, str_temp[1024];
extra_libdir = getenv (WEECHAT_EXTRA_LIBDIR);
if (weechat_home_temp)
{
snprintf (str_temp, sizeof (str_temp),
" (%s)", _("TEMPORARY, deleted on exit"));
}
else
{
str_temp[0] = '\0';
}
gui_chat_printf (NULL, "");
gui_chat_printf (NULL, _("Directories:"));
gui_chat_printf (NULL, " home: %s%s%s",
weechat_home,
(weechat_home_temp) ? " " : "",
(weechat_home_temp) ? _("(TEMPORARY, deleted on exit)") : "");
gui_chat_printf (NULL, _(" (default: %s)"),
(ptr_home && ptr_home[0]) ? ptr_home : "~/.weechat");
gui_chat_printf (NULL, " home:");
gui_chat_printf (NULL, " config: %s%s", weechat_config_dir, str_temp);
gui_chat_printf (NULL, " data: %s%s", weechat_data_dir, str_temp);
gui_chat_printf (NULL, " cache: %s%s", weechat_cache_dir, str_temp);
gui_chat_printf (NULL, " runtime: %s%s", weechat_runtime_dir, str_temp);
gui_chat_printf (NULL, " lib: %s", WEECHAT_LIBDIR);
gui_chat_printf (NULL, " lib (extra): %s",
(extra_libdir && extra_libdir[0]) ? extra_libdir : "-");

541
src/core/wee-dir.c

@ -57,7 +57,7 @@ @@ -57,7 +57,7 @@
*/
char *
dir_get_temp_dir()
dir_get_temp_dir ()
{
char *tmpdir;
struct stat buf;
@ -101,31 +101,70 @@ dir_get_temp_dir() @@ -101,31 +101,70 @@ dir_get_temp_dir()
int
dir_mkdir_home (const char *directory, int mode)
{
char *dir_name;
int dir_length;
char *dir, *dir1, *dir2, *dir3, *dir4;
int rc, dir_length;
rc = 0;
dir = NULL;
dir1 = NULL;
dir2 = NULL;
dir3 = NULL;
dir4 = NULL;
if (!directory)
return 0;
goto end;
/* build directory, adding WeeChat home */
dir_length = strlen (weechat_home) + strlen (directory) + 2;
dir_name = malloc (dir_length);
if (!dir_name)
return 0;
if (strncmp (directory, "${", 2) == 0)
{
dir = strdup (directory);
}
else
{
/* build directory in data dir by default */
dir_length = strlen (weechat_data_dir) + strlen (directory) + 2;
dir = malloc (dir_length);
if (!dir)
goto end;
snprintf (dir, dir_length, "%s/%s", weechat_data_dir, directory);
}
dir1 = string_replace (dir, "${weechat_config_dir}", weechat_config_dir);
if (!dir1)
goto end;
dir2 = string_replace (dir1, "${weechat_data_dir}", weechat_data_dir);
if (!dir2)
goto end;
dir3 = string_replace (dir2, "${weechat_cache_dir}", weechat_cache_dir);
if (!dir3)
goto end;
snprintf (dir_name, dir_length, "%s/%s", weechat_home, directory);
dir4 = string_replace (dir3, "${weechat_runtime_dir}", weechat_runtime_dir);
if (!dir4)
goto end;
if (mkdir (dir_name, mode) < 0)
/* build directory, adding WeeChat home */
if (mkdir (dir4, mode) < 0)
{
if (errno != EEXIST)
{
free (dir_name);
return 0;
}
goto end;
}
free (dir_name);
return 1;
rc = 1;
end:
if (dir)
free (dir);
if (dir1)
free (dir1);
if (dir2)
free (dir2);
if (dir3)
free (dir3);
if (dir4)
free (dir4);
return rc;
}
/*
@ -353,7 +392,7 @@ dir_search_full_lib_name_ext (const char *filename, const char *extension, @@ -353,7 +392,7 @@ dir_search_full_lib_name_ext (const char *filename, const char *extension,
}
/* try WeeChat user's dir */
length = strlen (weechat_home) + strlen (name_with_ext) +
length = strlen (weechat_data_dir) + strlen (name_with_ext) +
strlen (plugins_dir) + 16;
final_name = malloc (length);
if (!final_name)
@ -363,7 +402,7 @@ dir_search_full_lib_name_ext (const char *filename, const char *extension, @@ -363,7 +402,7 @@ dir_search_full_lib_name_ext (const char *filename, const char *extension,
}
snprintf (final_name, length,
"%s%s%s%s%s",
weechat_home,
weechat_data_dir,
DIR_SEPARATOR,
plugins_dir,
DIR_SEPARATOR,
@ -514,154 +553,404 @@ error: @@ -514,154 +553,404 @@ error:
}
/*
* Expands and assigns given path to "weechat_home".
* Uses one or four different paths for WeeChat home directories.
*
* If 4 paths are given, they must be separated by colons and given in this
* order: config, data, cache, runtime.
*
* Returns:
* 1: OK
* 0: error
*/
void
dir_set_home_path (char *home_path)
int
dir_set_home_path (char *path)
{
char *ptr_home;
int dir_length;
char **paths;
int rc, num_paths;
rc = 0;
paths = NULL;
if (home_path[0] == '~')
if (!path)
goto end;
paths = string_split (path, ":", NULL, 0, 0, &num_paths);
if (!paths)
{
/* replace leading '~' by $HOME */
ptr_home = getenv ("HOME");
if (!ptr_home)
{
string_fprintf (stderr, _("Error: unable to get HOME directory\n"));
weechat_shutdown (EXIT_FAILURE, 0);
/* make C static analyzer happy (never executed) */
return;
}
dir_length = strlen (ptr_home) + strlen (home_path + 1) + 1;
weechat_home = malloc (dir_length);
if (weechat_home)
{
snprintf (weechat_home, dir_length,
"%s%s", ptr_home, home_path + 1);
}
string_fprintf (stderr, _("Error: not enough memory\n"));
goto end;
}
else
if (num_paths == 1)
{
weechat_home = strdup (home_path);
weechat_config_dir = string_expand_home (paths[0]);
weechat_data_dir = string_expand_home (paths[0]);
weechat_cache_dir = string_expand_home (paths[0]);
weechat_runtime_dir = string_expand_home (paths[0]);
}
if (!weechat_home)
else if (num_paths == 4)
{
weechat_config_dir = string_expand_home (paths[0]);
weechat_data_dir = string_expand_home (paths[1]);
weechat_cache_dir = string_expand_home (paths[2]);
weechat_runtime_dir = string_expand_home (paths[3]);
}
else
{
string_fprintf (stderr,
_("Error: not enough memory for home directory\n"));
weechat_shutdown (EXIT_FAILURE, 0);
/* make C static analyzer happy (never executed) */
return;
_("Error: wrong number of paths for home directories "
"(expected: 1 or 4, received: %d)\n"),
num_paths);
goto end;
}
rc = 1;
end:
if (paths)
string_free_split (paths);
return rc;
}
/*
* Creates WeeChat home directory (by default ~/.weechat).
* Creates WeeChat temporary home directory (deleted on exit).
*
* Any error in this function is fatal: WeeChat can not run without a home
* directory.
* Returns:
* 1: OK
* 0: error
*/
void
dir_create_home_dir ()
int
dir_create_home_temp_dir ()
{
char *temp_dir, *temp_home_template, *ptr_weechat_home;
char *config_weechat_home;
int length, add_separator;
struct stat statinfo;
/* temporary WeeChat home */
if (weechat_home_temp)
int rc, length, add_separator;
rc = 0;
temp_dir = NULL;
temp_home_template = NULL;
temp_dir = dir_get_temp_dir ();
if (!temp_dir || !temp_dir[0])
goto memory_error;
length = strlen (temp_dir) + 32 + 1;
temp_home_template = malloc (length);
if (!temp_home_template)
goto memory_error;
add_separator = (temp_dir[strlen (temp_dir) - 1] != DIR_SEPARATOR_CHAR);
snprintf (temp_home_template, length,
"%s%sweechat_temp_XXXXXX",
temp_dir,
add_separator ? DIR_SEPARATOR : "");
ptr_weechat_home = mkdtemp (temp_home_template);
if (!ptr_weechat_home)
{
temp_dir = dir_get_temp_dir ();
if (!temp_dir || !temp_dir[0])
{
string_fprintf (stderr,
_("Error: not enough memory for home "
"directory\n"));
weechat_shutdown (EXIT_FAILURE, 0);
/* make C static analyzer happy (never executed) */
return;
}
length = strlen (temp_dir) + 32 + 1;
temp_home_template = malloc (length);
if (!temp_home_template)
{
free (temp_dir);
string_fprintf (stderr,
_("Error: not enough memory for home "
"directory\n"));
weechat_shutdown (EXIT_FAILURE, 0);
/* make C static analyzer happy (never executed) */
return;
}
add_separator = (temp_dir[strlen (temp_dir) - 1] != DIR_SEPARATOR_CHAR);
snprintf (temp_home_template, length,
"%s%sweechat_temp_XXXXXX",
temp_dir,
add_separator ? DIR_SEPARATOR : "");
string_fprintf (stderr,
_("Error: unable to create a temporary "
"home directory (using template: \"%s\")\n"),
temp_home_template);
goto end;
}
weechat_config_dir = strdup (ptr_weechat_home);
weechat_data_dir = strdup (ptr_weechat_home);
weechat_cache_dir = strdup (ptr_weechat_home);
weechat_runtime_dir = strdup (ptr_weechat_home);
weechat_home_delete_on_exit = 1;
rc = 1;
goto end;
memory_error:
string_fprintf (stderr, _("Error: not enough memory\n"));
end:
if (temp_dir)
free (temp_dir);
ptr_weechat_home = mkdtemp (temp_home_template);
if (!ptr_weechat_home)
{
string_fprintf (stderr,
_("Error: unable to create a temporary "
"home directory (using template: \"%s\")\n"),
temp_home_template);
free (temp_home_template);
weechat_shutdown (EXIT_FAILURE, 0);
/* make C static analyzer happy (never executed) */
return;
}
weechat_home = strdup (ptr_weechat_home);
if (temp_home_template)
free (temp_home_template);
weechat_home_delete_on_exit = 1;
return;
return rc;
}
/*
* Finds XDG directories.
*
* Returns:
* 1: OK
* 0: error
*/
int
dir_find_xdg_dirs (char **config_dir, char **data_dir, char **cache_dir,
char **runtime_dir)
{
char *ptr_home, path[PATH_MAX];
char *xdg_config_home, *xdg_data_home, *xdg_cache_home, *xdg_runtime_dir;
ptr_home = getenv ("HOME");
xdg_config_home = getenv ("XDG_CONFIG_HOME");
xdg_data_home = getenv ("XDG_DATA_HOME");
xdg_cache_home = getenv ("XDG_CACHE_HOME");
xdg_runtime_dir = getenv ("XDG_RUNTIME_DIR");
/* set config dir: $XDG_CONFIG_HOME/weechat or $HOME/.config/weechat */
if (xdg_config_home && xdg_config_home[0])
{
snprintf (path, sizeof (path),
"%s%s%s",
xdg_config_home, DIR_SEPARATOR, "weechat");
}
else
{
snprintf (path, sizeof (path),
"%s%s%s%s%s",
ptr_home, DIR_SEPARATOR, ".config", DIR_SEPARATOR, "weechat");
}
*config_dir = strdup (path);
if (!*config_dir)
goto error;
/*
* weechat_home is not set yet: look for environment variable
* "WEECHAT_HOME"
*/
if (!weechat_home)
/* set data dir: $XDG_DATA_HOME/weechat or $HOME/.local/share/weechat */
if (xdg_data_home && xdg_data_home[0])
{
ptr_weechat_home = getenv ("WEECHAT_HOME");
if (ptr_weechat_home && ptr_weechat_home[0])
dir_set_home_path (ptr_weechat_home);
snprintf (path, sizeof (path),
"%s%s%s",
xdg_data_home, DIR_SEPARATOR, "weechat");
}
else
{
snprintf (path, sizeof (path),
"%s%s%s%s%s%s%s",
ptr_home, DIR_SEPARATOR, ".local", DIR_SEPARATOR, "share",
DIR_SEPARATOR, "weechat");
}
*data_dir = strdup (path);
if (!*data_dir)
goto error;
/* weechat_home is still not set: try to use compile time default */
if (!weechat_home)
/* set cache dir: $XDG_CACHE_HOME/weechat or $HOME/.cache/weechat */
if (xdg_cache_home && xdg_cache_home[0])
{
config_weechat_home = WEECHAT_HOME;
dir_set_home_path (
(config_weechat_home[0] ? config_weechat_home : "~/.weechat"));
snprintf (path, sizeof (path),
"%s%s%s",
xdg_cache_home, DIR_SEPARATOR, "weechat");
}
else
{
snprintf (path, sizeof (path),
"%s%s%s%s%s",
ptr_home, DIR_SEPARATOR, ".cache", DIR_SEPARATOR, "weechat");
}
*cache_dir = strdup (path);
if (!*cache_dir)
goto error;
/* set runtime dir: $XDG_RUNTIME_DIR/weechat or same as cache dir */
if (xdg_runtime_dir && xdg_runtime_dir[0])
{
snprintf (path, sizeof (path),
"%s%s%s",
xdg_runtime_dir, DIR_SEPARATOR, "weechat");
*runtime_dir = strdup (path);
}
else
{
*runtime_dir = strdup (*cache_dir);
}
if (!*runtime_dir)
goto error;
return 1;
error:
string_fprintf (stderr, _("Error: not enough memory\n"));
return 0;
}
/*
* Finds WeeChat home directories: it can be either XDG directories or the
* same directory for all files (like the legacy directory ~/.weechat).
*
* Returns:
* 1: OK
* 0: error
*/
int
dir_find_home_dirs ()
{
char *ptr_home, *ptr_weechat_home, *config_weechat_home;
char *config_dir, *data_dir, *cache_dir, *runtime_dir;
char path[PATH_MAX];
/* temporary WeeChat home */
if (weechat_home_temp)
return dir_create_home_temp_dir ();
/* use a forced home with -d/--dir */
if (weechat_home_force)
return dir_set_home_path (weechat_home_force);
/* use environment variable "WEECHAT_HOME" (if set) */
ptr_weechat_home = getenv ("WEECHAT_HOME");
if (ptr_weechat_home && ptr_weechat_home[0])
return dir_set_home_path (ptr_weechat_home);
/* use the home forced at compilation time (if set) */
config_weechat_home = WEECHAT_HOME;
if (config_weechat_home[0])
return dir_set_home_path (config_weechat_home);
if (!dir_find_xdg_dirs (&config_dir, &data_dir, &cache_dir, &runtime_dir))
return 0;
/* check if {weechat_config_dir}/weechat.conf exists */
snprintf (path, sizeof (path),
"%s%s%s",
config_dir, DIR_SEPARATOR, "weechat.conf");
if (access (path, F_OK) == 0)
goto use_xdg;
/*
* check if $HOME/.weechat/weechat.conf exists
* (compatibility with old releases not supporting XDG directories)
*/
ptr_home = getenv ("HOME");
snprintf (path, sizeof (path),
"%s%s%s%s%s",
ptr_home, DIR_SEPARATOR, ".weechat", DIR_SEPARATOR, "weechat.conf");
if (access (path, F_OK) == 0)
{
snprintf (path, sizeof (path),
"%s%s%s",
ptr_home, DIR_SEPARATOR, ".weechat");
weechat_config_dir = strdup (path);
weechat_data_dir = strdup (path);
weechat_cache_dir = strdup (path);
weechat_runtime_dir = strdup (path);
free (config_dir);
free (data_dir);
free (cache_dir);
free (runtime_dir);
return 1;
}
/* use XDG directories */
use_xdg:
weechat_config_dir = config_dir;
weechat_data_dir = data_dir;
weechat_cache_dir = cache_dir;
weechat_runtime_dir = runtime_dir;
return 1;
}
/*
* Creates a home directory.
*
* Returns:
* 1: OK
* 0: error
*/
int
dir_create_home_dir (char *path)
{
struct stat statinfo;
/* if home already exists, it has to be a directory */
if (stat (weechat_home, &statinfo) == 0)
if (stat (path, &statinfo) == 0)
{
if (!S_ISDIR (statinfo.st_mode))
{
string_fprintf (stderr,
_("Error: home (%s) is not a directory\n"),
weechat_home);
weechat_shutdown (EXIT_FAILURE, 0);
/* make C static analyzer happy (never executed) */
return;
_("Error: \"%s\" is not a directory\n"),
path);
return 0;
}
}
/* create home directory; error is fatal */
if (!dir_mkdir (weechat_home, 0755))
if (!dir_mkdir_parents (path, 0700))
{
string_fprintf (stderr,
_("Error: cannot create directory \"%s\"\n"),
weechat_home);
weechat_shutdown (EXIT_FAILURE, 0);
/* make C static analyzer happy (never executed) */
return;
path);
return 0;
}
return 1;
}
/*
* Creates WeeChat home directories.
*
* Any error in this function (or a sub function called) is fatal: WeeChat
* can not run at all without the home directories.
*/
void
dir_create_home_dirs ()
{
int rc;
if (!dir_find_home_dirs ())
goto error;
rc = dir_create_home_dir (weechat_config_dir);
if (rc && (strcmp (weechat_config_dir, weechat_data_dir) != 0))
rc = dir_create_home_dir (weechat_data_dir);
if (rc && (strcmp (weechat_config_dir, weechat_cache_dir) != 0))
rc = dir_create_home_dir (weechat_cache_dir);
if (rc && (strcmp (weechat_config_dir, weechat_runtime_dir) != 0))
rc = dir_create_home_dir (weechat_runtime_dir);
if (rc)
return;
error:
weechat_shutdown (EXIT_FAILURE, 0);
}
/*
* Removes WeeChat home directories (called when -t / --temp-dir is given).
*/
void
dir_remove_home_dirs ()
{
dir_rmtree (weechat_config_dir);
if (strcmp (weechat_config_dir, weechat_data_dir) != 0)
dir_rmtree (weechat_data_dir);
if (strcmp (weechat_config_dir, weechat_cache_dir) != 0)
dir_rmtree (weechat_cache_dir);
if (strcmp (weechat_config_dir, weechat_runtime_dir) != 0)
dir_rmtree (weechat_runtime_dir);
}
/*
* Returns a string with home directories separated by colons, in this order:
* config_dir, data_dir, cache_dir, runtime_dir.
*
* Example of value returned:
* /home/user/.config/weechat:/home/user/.local/share/weechat:
* /home/user/.cache/weechat:/run/user/1000/weechat
*
* Note: result must be freed after use.
*/
char *
dir_get_string_home_dirs ()
{
char *dirs[5];
dirs[0] = weechat_config_dir;
dirs[1] = weechat_data_dir;
dirs[2] = weechat_cache_dir;
dirs[3] = weechat_runtime_dir;
dirs[4] = NULL;
return string_build_with_split_string ((const char **)dirs, ":");
}

4
src/core/wee-dir.h

@ -33,6 +33,8 @@ extern void dir_exec_on_files (const char *directory, int recurse_subdirs, @@ -33,6 +33,8 @@ extern void dir_exec_on_files (const char *directory, int recurse_subdirs,
extern char *dir_search_full_lib_name (const char *filename,
const char *sys_directory);
extern char *dir_file_get_content (const char *filename);
extern void dir_create_home_dir ();
extern void dir_create_home_dirs ();
extern void dir_remove_home_dirs ();
extern char *dir_get_string_home_dirs ();
#endif /* WEECHAT_DIR_H */

106
src/core/wee-eval.c

@ -1010,32 +1010,34 @@ end: @@ -1010,32 +1010,34 @@ end:
* Replaces variables, which can be, by order of priority:
* 1. the string itself without evaluation (format: raw:xxx)
* 2. an extra variable from hashtable "extra_vars"
* 3. a string to evaluate (format: eval:xxx)
* 4. a condition to evaluate (format: eval_cond:xxx)
* 5. a string with escaped chars (format: esc:xxx or \xxx)
* 6. a string with chars to hide (format: hide:char,string)
* 7. a string with max chars (format: cut:max,suffix,string or
* 3. a WeeChat home directory, one of: "weechat_config_dir",
* "weechat_data_dir", "weechat_cache_dir", "weechat_runtime_dir"
* 4. a string to evaluate (format: eval:xxx)
* 5. a condition to evaluate (format: eval_cond:xxx)
* 6. a string with escaped chars (format: esc:xxx or \xxx)
* 7. a string with chars to hide (format: hide:char,string)
* 8. a string with max chars (format: cut:max,suffix,string or
* cut:+max,suffix,string) or max chars on screen
* (format: cutscr:max,suffix,string or cutscr:+max,suffix,string)
* 8. a reversed string (format: rev:xxx) or reversed string for screen,
* 9. a reversed string (format: rev:xxx) or reversed string for screen,
* color codes are not reversed (format: revscr:xxx)
* 9. a repeated string (format: repeat:count,string)
* 10. length of a string (format: length:xxx) or length of a string on screen
* 10. a repeated string (format: repeat:count,string)
* 11. length of a string (format: length:xxx) or length of a string on screen
* (format: lengthscr:xxx); color codes are ignored
* 11. a regex group captured (format: re:N (0.99) or re:+)
* 12. a color (format: color:xxx)
* 13. a modifier (format: modifier:name,data,xxx)
* 14. an info (format: info:name,arguments)
* 15. a base 16/32/64 encoded/decoded string (format: base_encode:base,xxx
* 12. a regex group captured (format: re:N (0.99) or re:+)
* 13. a color (format: color:xxx)
* 14. a modifier (format: modifier:name,data,xxx)
* 15. an info (format: info:name,arguments)
* 16. a base 16/32/64 encoded/decoded string (format: base_encode:base,xxx
* or base_decode:base,xxx)
* 16. current date/time (format: date or date:xxx)
* 17. an environment variable (format: env:XXX)
* 18. a ternary operator (format: if:condition?value_if_true:value_if_false)
* 19. calculate result of an expression (format: calc:xxx)
* 20. an option (format: file.section.option)
* 21. a buffer local variable
* 22. a pointer name from hashtable "pointers"
* 23. a hdata variable (format: hdata.var1.var2 or hdata[list].var1.var2
* 17. current date/time (format: date or date:xxx)
* 18. an environment variable (format: env:XXX)
* 19. a ternary operator (format: if:condition?value_if_true:value_if_false)
* 20. calculate result of an expression (format: calc:xxx)
* 21. an option (format: file.section.option)
* 22. a buffer local variable
* 23. a pointer name from hashtable "pointers"
* 24. a hdata variable (format: hdata.var1.var2 or hdata[list].var1.var2
* or hdata[ptr].var1.var2 or hdata[ptr_name].var1.var2)
*
* See /help in WeeChat for examples.
@ -1093,8 +1095,30 @@ eval_replace_vars_cb (void *data, const char *text) @@ -1093,8 +1095,30 @@ eval_replace_vars_cb (void *data, const char *text)
}
}
/* 3. WeeChat home directory */
if (strcmp (text, "weechat_config_dir") == 0)
{
value = strdup (weechat_config_dir);
goto end;
}
if (strcmp (text, "weechat_data_dir") == 0)
{
value = strdup (weechat_data_dir);
goto end;
}
if (strcmp (text, "weechat_cache_dir") == 0)
{
value = strdup (weechat_cache_dir);
goto end;
}
if (strcmp (text, "weechat_runtime_dir") == 0)
{
value = strdup (weechat_runtime_dir);
goto end;
}
/*
* 3. force evaluation of string (recursive call)
* 4. force evaluation of string (recursive call)
* --> use with caution: the text must be safe!
*/
if (strncmp (text, "eval:", 5) == 0)
@ -1104,7 +1128,7 @@ eval_replace_vars_cb (void *data, const char *text) @@ -1104,7 +1128,7 @@ eval_replace_vars_cb (void *data, const char *text)
}
/*
* 4. force evaluation of condition (recursive call)
* 5. force evaluation of condition (recursive call)
* --> use with caution: the text must be safe!
*/
if (strncmp (text, "eval_cond:", 10) == 0)
@ -1113,7 +1137,7 @@ eval_replace_vars_cb (void *data, const char *text) @@ -1113,7 +1137,7 @@ eval_replace_vars_cb (void *data, const char *text)
goto end;
}
/* 5. convert escaped chars */
/* 6. convert escaped chars */
if (strncmp (text, "esc:", 4) == 0)
{
value = string_convert_escaped_chars (text + 4);
@ -1125,7 +1149,7 @@ eval_replace_vars_cb (void *data, const char *text) @@ -1125,7 +1149,7 @@ eval_replace_vars_cb (void *data, const char *text)
goto end;
}
/* 6. hide chars: replace all chars by a given char/string */
/* 7. hide chars: replace all chars by a given char/string */
if (strncmp (text, "hide:", 5) == 0)
{
value = eval_string_hide (text + 5);
@ -1133,7 +1157,7 @@ eval_replace_vars_cb (void *data, const char *text) @@ -1133,7 +1157,7 @@ eval_replace_vars_cb (void *data, const char *text)
}
/*
* 7. cut chars:
* 8. cut chars:
* cut: max number of chars, and add an optional suffix when the
* string is cut
* cutscr: max number of chars displayed on screen, and add an optional
@ -1150,7 +1174,7 @@ eval_replace_vars_cb (void *data, const char *text) @@ -1150,7 +1174,7 @@ eval_replace_vars_cb (void *data, const char *text)
goto end;
}
/* 8. reverse string */
/* 9. reverse string */
if (strncmp (text, "rev:", 4) == 0)
{
value = string_reverse (text + 4);
@ -1162,7 +1186,7 @@ eval_replace_vars_cb (void *data, const char *text) @@ -1162,7 +1186,7 @@ eval_replace_vars_cb (void *data, const char *text)
goto end;
}
/* 9. repeated string */
/* 10. repeated string */
if (strncmp (text, "repeat:", 7) == 0)
{
value = eval_string_repeat (text + 7);
@ -1170,7 +1194,7 @@ eval_replace_vars_cb (void *data, const char *text) @@ -1170,7 +1194,7 @@ eval_replace_vars_cb (void *data, const char *text)
}
/*
* 10. length of string:
* 11. length of string:
* length: number of chars
* lengthscr: number of chars displayed on screen
*/
@ -1189,35 +1213,35 @@ eval_replace_vars_cb (void *data, const char *text) @@ -1189,35 +1213,35 @@ eval_replace_vars_cb (void *data, const char *text)
goto end;
}
/* 11. regex group captured */
/* 12. regex group captured */
if (strncmp (text, "re:", 3) == 0)
{
value = eval_string_regex_group (text + 3, eval_context);
goto end;
}
/* 12. color code */
/* 13. color code */
if (strncmp (text, "color:", 6) == 0)
{
value = eval_string_color (text + 6);
goto end;
}
/* 13. modifier */
/* 14. modifier */
if (strncmp (text, "modifier:", 9) == 0)
{
value = eval_string_modifier (text + 9);
goto end;
}
/* 14. info */
/* 15. info */
if (strncmp (text, "info:", 5) == 0)
{
value = eval_string_info (text + 5);
goto end;
}
/* 15. base_encode/base_decode */
/* 16. base_encode/base_decode */
if (strncmp (text, "base_encode:", 12) == 0)
{
value = eval_string_base_encode (text + 12);
@ -1229,14 +1253,14 @@ eval_replace_vars_cb (void *data, const char *text) @@ -1229,14 +1253,14 @@ eval_replace_vars_cb (void *data, const char *text)
goto end;
}
/* 16. current date/time */
/* 17. current date/time */
if ((strncmp (text, "date", 4) == 0) && (!text[4] || (text[4] == ':')))
{
value = eval_string_date (text + 4);
goto end;
}
/* 17. environment variable */
/* 18. environment variable */
if (strncmp (text, "env:", 4) == 0)
{
ptr_value = getenv (text + 4);
@ -1244,7 +1268,7 @@ eval_replace_vars_cb (void *data, const char *text) @@ -1244,7 +1268,7 @@ eval_replace_vars_cb (void *data, const char *text)
goto end;
}
/* 18: ternary operator: if:condition?value_if_true:value_if_false */
/* 19: ternary operator: if:condition?value_if_true:value_if_false */
if (strncmp (text, "if:", 3) == 0)
{
value = eval_string_if (text + 3, eval_context);
@ -1252,7 +1276,7 @@ eval_replace_vars_cb (void *data, const char *text) @@ -1252,7 +1276,7 @@ eval_replace_vars_cb (void *data, const char *text)
}
/*
* 19. calculate the result of an expression
* 20. calculate the result of an expression
* (with number, operators and parentheses)
*/
if (strncmp (text, "calc:", 5) == 0)
@ -1261,7 +1285,7 @@ eval_replace_vars_cb (void *data, const char *text) @@ -1261,7 +1285,7 @@ eval_replace_vars_cb (void *data, const char *text)
goto end;
}
/* 20. option: if found, return this value */
/* 21. option: if found, return this value */
if (strncmp (text, "sec.data.", 9) == 0)
{
ptr_value = hashtable_get (secure_hashtable_data, text + 9);
@ -1304,7 +1328,7 @@ eval_replace_vars_cb (void *data, const char *text) @@ -1304,7 +1328,7 @@ eval_replace_vars_cb (void *data, const char *text)
}
}
/* 21. local variable in buffer */
/* 22. local variable in buffer */
ptr_buffer = hashtable_get (eval_context->pointers, "buffer");
if (ptr_buffer)
{
@ -1316,7 +1340,7 @@ eval_replace_vars_cb (void *data, const char *text) @@ -1316,7 +1340,7 @@ eval_replace_vars_cb (void *data, const char *text)
}
}
/* 22. hdata */
/* 23. hdata */
value = eval_string_hdata (text, eval_context);
end:

20
src/core/wee-log.c

@ -45,7 +45,7 @@ @@ -45,7 +45,7 @@
#include "../plugins/plugin.h"
char *weechat_log_filename = NULL; /* log name (~/.weechat/weechat.log) */
char *weechat_log_filename = NULL; /* WeeChat log filename (weechat.log) */
FILE *weechat_log_file = NULL; /* WeeChat log file */
int weechat_log_use_time = 1; /* 0 to temporary disable time in log, */
/* for example when dumping data */
@ -79,10 +79,10 @@ log_open (const char *filename, const char *mode) @@ -79,10 +79,10 @@ log_open (const char *filename, const char *mode)
}
else
{
filename_length = strlen (weechat_home) + 64;
filename_length = strlen (weechat_data_dir) + 64;
weechat_log_filename = malloc (filename_length);
snprintf (weechat_log_filename, filename_length,
"%s/%s", weechat_home, WEECHAT_LOG_NAME);
"%s/%s", weechat_data_dir, WEECHAT_LOG_NAME);
weechat_log_file = fopen (weechat_log_filename, mode);
}
@ -122,10 +122,12 @@ log_init () @@ -122,10 +122,12 @@ log_init ()
{
if (!log_open (NULL, "w"))
{
string_fprintf (stderr,
_("Error: unable to create/append to log file (weechat.log)\n"
"If another WeeChat process is using this file, try to run WeeChat\n"
"with another home using the \"--dir\" command line option.\n"));
string_fprintf (
stderr,
_("Error: unable to create/append to log file (weechat.log)\n"
"If another WeeChat process is using this file, try to run "
"WeeChat with a specific home directory using the \"--dir\" "
"command line option.\n"));
exit (1);
}
log_printf ("WeeChat %s (%s %s %s)",
@ -271,7 +273,7 @@ log_crash_rename () @@ -271,7 +273,7 @@ log_crash_rename ()
log_close ();
length = strlen (weechat_home) + 128;
length = strlen (weechat_data_dir) + 128;
new_name = malloc (length);
if (new_name)
{
@ -279,7 +281,7 @@ log_crash_rename () @@ -279,7 +281,7 @@ log_crash_rename ()
local_time = localtime (&time_now);
snprintf (new_name, length,
"%s/weechat_crash_%04d%02d%02d_%d.log",
weechat_home,
weechat_data_dir,
local_time->tm_year + 1900,
local_time->tm_mon + 1,
local_time->tm_mday,

14
src/core/wee-network.c

@ -57,6 +57,7 @@ @@ -57,6 +57,7 @@
#include "weechat.h"
#include "wee-network.h"
#include "wee-eval.h"
#include "wee-hashtable.h"
#include "wee-hook.h"
#include "wee-config.h"
#include "wee-proxy.h"
@ -93,13 +94,24 @@ void @@ -93,13 +94,24 @@ void
network_set_gnutls_ca_file ()
{
char *ca_path;
struct t_hashtable *options;
if (weechat_no_gnutls)
return;
options = hashtable_new (
32,
WEECHAT_HASHTABLE_STRING,
WEECHAT_HASHTABLE_STRING,
NULL, NULL);
if (options)
hashtable_set (options, "directory", "config");
ca_path = string_eval_path_home (
CONFIG_STRING(config_network_gnutls_ca_file),
NULL, NULL, NULL);
NULL, NULL, options);
if (options)
hashtable_free (options);
if (ca_path)
{
if (access (ca_path, R_OK) == 0)

25
src/core/wee-string.c

@ -774,7 +774,7 @@ string_expand_home (const char *path) @@ -774,7 +774,7 @@ string_expand_home (const char *path)
/*
* Evaluate a path by replacing (in this order):
* 1. "%h" (at beginning of string) by WeeChat home directory.
* 1. "%h" (at beginning of string) by WeeChat home directory (deprecated)
* 2. "~" by user home directory (call to string_expand_home)
* 3. evaluated variables (see /help eval)
*
@ -790,6 +790,7 @@ string_eval_path_home (const char *path, @@ -790,6 +790,7 @@ string_eval_path_home (const char *path,
struct t_hashtable *options)
{
char *path1, *path2, *path3;
const char *ptr_option_directory, *ptr_directory;
int length;
if (!path)
@ -799,13 +800,29 @@ string_eval_path_home (const char *path, @@ -799,13 +800,29 @@ string_eval_path_home (const char *path,
path2 = NULL;
path3 = NULL;
/* replace "%h" by WeeChat home */
/*
* replace "%h" by WeeChat home
* (deprecated: "%h" should not be used any more with WeeChat 3.2)
*/
if (strncmp (path, "%h", 2) == 0)
{
length = strlen (weechat_home) + strlen (path + 2) + 1;
ptr_directory = weechat_data_dir;
ptr_option_directory = hashtable_get (options, "directory");
if (ptr_option_directory)
{
if (strcmp (ptr_option_directory, "config") == 0)
ptr_directory = weechat_config_dir;
else if (strcmp (ptr_option_directory, "data") == 0)
ptr_directory = weechat_data_dir;
else if (strcmp (ptr_option_directory, "cache") == 0)
ptr_directory = weechat_cache_dir;
else if (strcmp (ptr_option_directory, "runtime") == 0)
ptr_directory = weechat_runtime_dir;
}
length = strlen (ptr_directory) + strlen (path + 2) + 1;
path1 = malloc (length);
if (path1)
snprintf (path1, length, "%s%s", weechat_home, path + 2);
snprintf (path1, length, "%s%s", ptr_directory, path + 2);
}
else
path1 = strdup (path);

4
src/core/wee-upgrade-file.c

@ -203,7 +203,7 @@ upgrade_file_new (const char *filename, @@ -203,7 +203,7 @@ upgrade_file_new (const char *filename,
if (new_upgrade_file)
{
/* build name of file */
length = strlen (weechat_home) + 1 + strlen (filename) + 16 + 1;
length = strlen (weechat_data_dir) + 1 + strlen (filename) + 16 + 1;
new_upgrade_file->filename = malloc (length);
if (!new_upgrade_file->filename)
{
@ -211,7 +211,7 @@ upgrade_file_new (const char *filename, @@ -211,7 +211,7 @@ upgrade_file_new (const char *filename,
return NULL;
}
snprintf (new_upgrade_file->filename, length, "%s/%s.upgrade",
weechat_home, filename);
weechat_data_dir, filename);
new_upgrade_file->callback_read = callback_read;
new_upgrade_file->callback_read_pointer = callback_read_pointer;
new_upgrade_file->callback_read_data = callback_read_data;

2
src/core/wee-upgrade.c

@ -925,7 +925,7 @@ upgrade_weechat_end () @@ -925,7 +925,7 @@ upgrade_weechat_end ()
long long time_diff;
/* remove .upgrade files */
dir_exec_on_files (weechat_home,
dir_exec_on_files (weechat_data_dir,
0, 0,
&upgrade_weechat_remove_file_cb, NULL);

39
src/core/weechat.c

@ -106,9 +106,13 @@ volatile sig_atomic_t weechat_quit_signal = 0; /* signal received, */ @@ -106,9 +106,13 @@ volatile sig_atomic_t weechat_quit_signal = 0; /* signal received, */
/* WeeChat must quit */
volatile sig_atomic_t weechat_reload_signal = 0; /* signal received, */
/* WeeChat must reload configuration */
char *weechat_home = NULL; /* home dir. (default: ~/.weechat) */
char *weechat_home_force = NULL; /* forced home (with -d/--dir) */
int weechat_home_temp = 0; /* 1 if using a temporary home */
int weechat_home_delete_on_exit = 0; /* 1 if home is deleted on exit */
char *weechat_config_dir = NULL; /* config directory */
char *weechat_data_dir = NULL; /* data directory */
char *weechat_cache_dir = NULL; /* cache directory */
char *weechat_runtime_dir = NULL; /* runtime directory */
int weechat_locale_ok = 0; /* is locale OK? */
char *weechat_local_charset = NULL; /* example: ISO-8859-1, UTF-8 */
int weechat_server_cmd_line = 0; /* at least 1 server on cmd line */
@ -164,8 +168,7 @@ weechat_display_usage () @@ -164,8 +168,7 @@ weechat_display_usage ()
_(" -a, --no-connect disable auto-connect to servers at "
"startup\n"
" -c, --colors display default colors in terminal\n"
" -d, --dir <path> set WeeChat home directory "
"(default: ~/.weechat)\n"
" -d, --dir <path> force a single WeeChat home directory\n"
" (environment variable WEECHAT_HOME is "
"read if this option is not given)\n"
" -t, --temp-dir create a temporary WeeChat home"
@ -255,7 +258,7 @@ weechat_parse_args (int argc, char *argv[]) @@ -255,7 +258,7 @@ weechat_parse_args (int argc, char *argv[])
weechat_argv0 = (argv[0]) ? strdup (argv[0]) : NULL;
weechat_upgrading = 0;
weechat_home = NULL;
weechat_home_force = NULL;
weechat_home_temp = 0;
weechat_home_delete_on_exit = 0;
weechat_server_cmd_line = 0;
@ -280,16 +283,16 @@ weechat_parse_args (int argc, char *argv[]) @@ -280,16 +283,16 @@ weechat_parse_args (int argc, char *argv[])
break;
case 'd': /* -d / --dir */
weechat_home_temp = 0;
if (weechat_home)
free (weechat_home);
weechat_home = strdup (optarg);
if (weechat_home_force)
free (weechat_home_force);
weechat_home_force = strdup (optarg);
break;
case 't': /* -t / --temp-dir */
weechat_home_temp = 1;
if (weechat_home)
if (weechat_home_force)
{
free (weechat_home);
weechat_home = NULL;
free (weechat_home_force);
weechat_home_force = NULL;
}
break;
case 'h': /* -h / --help */
@ -545,13 +548,21 @@ weechat_shutdown (int return_code, int crash) @@ -545,13 +548,21 @@ weechat_shutdown (int return_code, int crash)
if (!crash && weechat_home_delete_on_exit)
{
/* remove temporary home (only if not crashing) */
dir_rmtree (weechat_home);
dir_remove_home_dirs ();
}
if (weechat_argv0)
free (weechat_argv0);
if (weechat_home)
free (weechat_home);
if (weechat_home_force)
free (weechat_home_force);
if (weechat_config_dir)
free (weechat_config_dir);
if (weechat_data_dir)
free (weechat_data_dir);
if (weechat_cache_dir)
free (weechat_cache_dir);
if (weechat_runtime_dir)
free (weechat_runtime_dir);
if (weechat_local_charset)
free (weechat_local_charset);
if (weechat_force_plugin_autoload)
@ -614,7 +625,7 @@ weechat_init (int argc, char *argv[], void (*gui_init_cb)()) @@ -614,7 +625,7 @@ weechat_init (int argc, char *argv[], void (*gui_init_cb)())
if (!config_weechat_init ()) /* init WeeChat options (weechat.*) */
weechat_shutdown (EXIT_FAILURE, 0);
weechat_parse_args (argc, argv); /* parse command line args */
dir_create_home_dir (); /* create WeeChat home directory */
dir_create_home_dirs (); /* create WeeChat home directories */
log_init (); /* init log file */
plugin_api_init (); /* create some hooks (info,hdata,..)*/
secure_config_read (); /* read secured data options */

6
src/core/weechat.h

@ -112,9 +112,13 @@ extern int weechat_upgrade_count; @@ -112,9 +112,13 @@ extern int weechat_upgrade_count;
extern int weechat_quit;
extern volatile sig_atomic_t weechat_quit_signal;
extern volatile sig_atomic_t weechat_reload_signal;
extern char *weechat_home;
extern char *weechat_home_force;
extern int weechat_home_temp;
extern int weechat_home_delete_on_exit;
extern char *weechat_config_dir;
extern char *weechat_data_dir;
extern char *weechat_cache_dir;
extern char *weechat_runtime_dir;
extern char *weechat_local_charset;
extern int weechat_plugin_no_dlclose;
extern int weechat_no_gnutls;

5
src/plugins/fifo/fifo-command.c