Fri, 30 Jun 2017 15:03:16 +0300
Merged pidgin/main into default
--- a/libpurple/buddyicon.c Thu Jun 29 23:14:26 2017 -0500 +++ b/libpurple/buddyicon.c Fri Jun 30 15:03:16 2017 +0300 @@ -1094,8 +1094,8 @@ g_free, NULL); pointer_icon_cache = g_hash_table_new(g_direct_hash, g_direct_equal); - if (!cache_dir) - cache_dir = g_build_filename(purple_user_dir(), "icons", NULL); + if (!cache_dir) + cache_dir = g_build_filename(purple_cache_dir(), "icons", NULL); } void
--- a/libpurple/log.c Thu Jun 29 23:14:26 2017 -0500 +++ b/libpurple/log.c Fri Jun 30 15:03:16 2017 +0300 @@ -360,7 +360,7 @@ target = purple_escape_filename(purple_normalize(account, name)); } - dir = g_build_filename(purple_user_dir(), "logs", protocol_name, acct_name, target, NULL); + dir = g_build_filename(purple_data_dir(), "logs", protocol_name, acct_name, target, NULL); g_free(acct_name); @@ -1078,7 +1078,7 @@ * functions because they use the same directory structure. */ static void log_get_log_sets_common(GHashTable *sets) { - gchar *log_path = g_build_filename(purple_user_dir(), "logs", NULL); + gchar *log_path = g_build_filename(purple_data_dir(), "logs", NULL); GDir *log_dir = g_dir_open(log_path, 0, NULL); const gchar *protocol; @@ -1585,7 +1585,7 @@ static GList *old_logger_list(PurpleLogType type, const char *sn, PurpleAccount *account) { char *logfile = g_strdup_printf("%s.log", purple_normalize(account, sn)); - char *pathstr = g_build_filename(purple_user_dir(), "logs", logfile, NULL); + char *pathstr = g_build_filename(purple_data_dir(), "logs", logfile, NULL); PurpleStringref *pathref = purple_stringref_new(pathstr); GStatBuf st; time_t log_last_modified; @@ -1846,7 +1846,7 @@ static int old_logger_total_size(PurpleLogType type, const char *name, PurpleAccount *account) { char *logfile = g_strdup_printf("%s.log", purple_normalize(account, name)); - char *pathstr = g_build_filename(purple_user_dir(), "logs", logfile, NULL); + char *pathstr = g_build_filename(purple_data_dir(), "logs", logfile, NULL); int size; GStatBuf st; @@ -1898,7 +1898,7 @@ static void old_logger_get_log_sets(PurpleLogSetCallback cb, GHashTable *sets) { - char *log_path = g_build_filename(purple_user_dir(), "logs", NULL); + char *log_path = g_build_filename(purple_data_dir(), "logs", NULL); GDir *log_dir = g_dir_open(log_path, 0, NULL); gchar *name; PurpleBlistNode *gnode, *cnode, *bnode;
--- a/libpurple/theme-manager.c Thu Jun 29 23:14:26 2017 -0500 +++ b/libpurple/theme-manager.c Fri Jun 30 15:03:16 2017 +0300 @@ -147,7 +147,7 @@ purple_theme_manager_refresh(void) { gchar *path; - const gchar *xdg; + const gchar *const *xdg_dirs; gint i; GSList *loaders = NULL; @@ -159,27 +159,19 @@ purple_theme_manager_build_dir(loaders, path); g_free(path); - /* look for XDG_DATA_HOME. If we don't have it use ~/.local, and add it */ - if ((xdg = g_getenv("XDG_DATA_HOME")) != NULL) - path = g_build_filename(xdg, "themes", NULL); - else - path = g_build_filename(purple_home_dir(), ".local", "themes", NULL); - + /* look for XDG_DATA_HOME */ + /* NOTE: will work on Windows, see g_get_user_data_dir() documentation */ + path = g_build_filename(g_get_user_data_dir(), "themes", NULL); purple_theme_manager_build_dir(loaders, path); g_free(path); /* now dig through XDG_DATA_DIRS and add those too */ - xdg = g_getenv("XDG_DATA_DIRS"); - if (xdg) { - gchar **xdg_dirs = g_strsplit(xdg, G_SEARCHPATH_SEPARATOR_S, 0); - - for (i = 0; xdg_dirs[i]; i++) { - path = g_build_filename(xdg_dirs[i], "themes", NULL); - purple_theme_manager_build_dir(loaders, path); - g_free(path); - } - - g_strfreev(xdg_dirs); + /* NOTE: will work on Windows, see g_get_system_data_dirs() documentation */ + xdg_dirs = g_get_system_data_dirs(); + for (i = 0; xdg_dirs[i] != NULL; i++) { + path = g_build_filename(xdg_dirs[i], "themes", NULL); + purple_theme_manager_build_dir(loaders, path); + g_free(path); } g_slist_free(loaders);
--- a/libpurple/tls-certificate.c Thu Jun 29 23:14:26 2017 -0500 +++ b/libpurple/tls-certificate.c Fri Jun 30 15:03:16 2017 +0300 @@ -32,7 +32,7 @@ static gchar * make_certificate_path(const gchar *id) { - return g_build_filename(purple_user_dir(), + return g_build_filename(purple_data_dir(), "certificates", "tls", id != NULL ? purple_escape_filename(id) : NULL, NULL);
--- a/libpurple/util.c Thu Jun 29 23:14:26 2017 -0500 +++ b/libpurple/util.c Fri Jun 30 15:03:16 2017 +0300 @@ -40,10 +40,74 @@ static char *custom_user_dir = NULL; static char *user_dir = NULL; +static char *cache_dir = NULL; +static char *config_dir = NULL; +static char *data_dir = NULL; static JsonNode *escape_js_node = NULL; static JsonGenerator *escape_js_gen = NULL; +static void +move_to_xdg_base_dir(const char *purple_xdg_dir, char *subdir) +{ + char *xdg_dir; + gboolean xdg_dir_exists; + + xdg_dir_exists = g_file_test(purple_xdg_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR); + if (!xdg_dir_exists) { + gint mkdir_res; + + mkdir_res = purple_build_dir(purple_xdg_dir, (S_IRUSR | S_IWUSR | S_IXUSR)); + if (mkdir_res == -1) { + purple_debug_error("util", "Error creating xdg directory %s: %s; failed migration\n", + purple_xdg_dir, g_strerror(errno)); + return; + } + } + + xdg_dir = g_build_filename(purple_xdg_dir, subdir, NULL); + xdg_dir_exists = g_file_test(xdg_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR); + if (!xdg_dir_exists) { + char *old_dir; + gboolean old_dir_exists; + + old_dir = g_build_filename(purple_user_dir(), subdir, NULL); + old_dir_exists = g_file_test(old_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR); + + if (old_dir_exists) { + g_rename(old_dir, xdg_dir); + } + + g_free(old_dir); + old_dir = NULL; + } + + g_free(xdg_dir); + xdg_dir = NULL; + + return; +} + +/* If legacy directory for libpurple exists, move it to location following + * xdg base dir spec. https://developer.pidgin.im/ticket/10029 + */ +static void +migrate_to_xdg_base_dirs(void) +{ + const char *legacy_purple_dir; + gboolean dir_exists; + + legacy_purple_dir = purple_user_dir(); + dir_exists = g_file_test(legacy_purple_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR); + if (dir_exists) { + move_to_xdg_base_dir(purple_data_dir(), "certificates"); + move_to_xdg_base_dir(purple_cache_dir(), "icons"); + move_to_xdg_base_dir(purple_data_dir(), "logs"); + } + + return; +} + PurpleMenuAction * purple_menu_action_new(const char *label, PurpleCallback callback, gpointer data, GList *children) @@ -143,6 +207,8 @@ escape_js_node = json_node_new(JSON_NODE_VALUE); escape_js_gen = json_generator_new(); json_node_set_boolean(escape_js_node, FALSE); + + migrate_to_xdg_base_dirs(); } void @@ -156,6 +222,15 @@ g_free(user_dir); user_dir = NULL; + g_free(cache_dir); + cache_dir = NULL; + + g_free(config_dir); + config_dir = NULL; + + g_free(data_dir); + data_dir = NULL; + json_node_free(escape_js_node); escape_js_node = NULL; @@ -2910,6 +2985,48 @@ return user_dir; } +const char * +purple_cache_dir(void) +{ + if (!cache_dir) { + if (!custom_user_dir) { + cache_dir = g_build_filename(g_get_user_cache_dir(), "purple", NULL); + } else { + cache_dir = g_build_filename(custom_user_dir, "cache", NULL); + } + } + + return cache_dir; +} + +const char * +purple_config_dir(void) +{ + if (!config_dir) { + if (!custom_user_dir) { + config_dir = g_build_filename(g_get_user_config_dir(), "purple", NULL); + } else { + config_dir = g_build_filename(custom_user_dir, "config", NULL); + } + } + + return config_dir; +} + +const char * +purple_data_dir(void) +{ + if (!data_dir) { + if (!custom_user_dir) { + data_dir = g_build_filename(g_get_user_data_dir(), "purple", NULL); + } else { + data_dir = g_build_filename(custom_user_dir, "data", NULL); + } + } + + return data_dir; +} + void purple_util_set_user_dir(const char *dir) { g_free(custom_user_dir); @@ -2920,48 +3037,83 @@ custom_user_dir = NULL; } -int purple_build_dir (const char *path, int mode) +int purple_build_dir(const char *path, int mode) { return g_mkdir_with_parents(path, mode); } +static gboolean +purple_util_write_data_to_file_common(const char *dir, const char *filename, const char *data, gssize size) +{ + gchar *filename_full; + gboolean ret = FALSE; + + g_return_val_if_fail(dir != NULL, FALSE); + + purple_debug_misc("util", "Writing file %s to directory %s", + filename, dir); + + /* Ensure the directory exists */ + if (!g_file_test(dir, G_FILE_TEST_IS_DIR)) + { + if (g_mkdir(dir, S_IRUSR | S_IWUSR | S_IXUSR) == -1) + { + purple_debug_error("util", "Error creating directory %s: %s\n", + dir, g_strerror(errno)); + return FALSE; + } + } + + filename_full = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", dir, filename); + + ret = purple_util_write_data_to_file_absolute(filename_full, data, size); + + g_free(filename_full); + return ret; +} + +gboolean +purple_util_write_data_to_file(const char *filename, const char *data, gssize size) +{ + const char *user_dir = purple_user_dir(); + gboolean ret = purple_util_write_data_to_file_common(user_dir, filename, data, size); + + return ret; +} + +gboolean +purple_util_write_data_to_cache_file(const char *filename, const char *data, gssize size) +{ + const char *cache_dir = purple_cache_dir(); + gboolean ret = purple_util_write_data_to_file_common(cache_dir, filename, data, size); + + return ret; +} + +gboolean +purple_util_write_data_to_config_file(const char *filename, const char *data, gssize size) +{ + const char *config_dir = purple_config_dir(); + gboolean ret = purple_util_write_data_to_file_common(config_dir, filename, data, size); + + return ret; +} + +gboolean +purple_util_write_data_to_data_file(const char *filename, const char *data, gssize size) +{ + const char *data_dir = purple_data_dir(); + gboolean ret = purple_util_write_data_to_file_common(data_dir, filename, data, size); + + return ret; +} + /* * This function is long and beautiful, like my--um, yeah. Anyway, * it includes lots of error checking so as we don't overwrite * people's settings if there is a problem writing the new values. */ gboolean -purple_util_write_data_to_file(const char *filename, const char *data, gssize size) -{ - const char *user_dir = purple_user_dir(); - gchar *filename_full; - gboolean ret = FALSE; - - g_return_val_if_fail(user_dir != NULL, FALSE); - - purple_debug_misc("util", "Writing file %s to directory %s", - filename, user_dir); - - /* Ensure the user directory exists */ - if (!g_file_test(user_dir, G_FILE_TEST_IS_DIR)) - { - if (g_mkdir(user_dir, S_IRUSR | S_IWUSR | S_IXUSR) == -1) - { - purple_debug_error("util", "Error creating directory %s: %s\n", - user_dir, g_strerror(errno)); - return FALSE; - } - } - - filename_full = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", user_dir, filename); - - ret = purple_util_write_data_to_file_absolute(filename_full, data, size); - - g_free(filename_full); - return ret; -} - -gboolean purple_util_write_data_to_file_absolute(const char *filename_full, const char *data, gssize size) { gchar *filename_temp;
--- a/libpurple/util.h Thu Jun 29 23:14:26 2017 -0500 +++ b/libpurple/util.h Fri Jun 30 15:03:16 2017 +0300 @@ -751,6 +751,42 @@ const char *purple_user_dir(void); /** + * purple_cache_dir: + * + * Returns the purple cache directory according to XDG Base Directory Specification. + * This is usually ~/.cache/purple. + * If custom user dir was specified then this is cache + * sub-directory of DIR argument passed to -c option. + * + * Returns: The purple cache directory. + */ +const char *purple_cache_dir(void); + +/** + * purple_config_dir: + * + * Returns the purple configuration directory according to XDG Base Directory Specification. + * This is usually ~/.config/purple. + * If custom user dir was specified then this is config + * sub-directory of DIR argument passed to -c option. + * + * Returns: The purple configuration directory. + */ +const char *purple_config_dir(void); + +/** + * purple_data_dir: + * + * Returns the purple data directory according to XDG Base Directory Specification. + * This is usually ~/.local/share/purple. + * If custom user dir was specified then this is data + * sub-directory of DIR argument passed to -c option. + * + * Returns: The purple data directory. + */ +const char *purple_data_dir(void); + +/** * purple_util_set_user_dir: * @dir: The custom settings directory * @@ -791,6 +827,57 @@ gssize size); /** + * purple_util_write_data_to_cache_file: + * @filename: The basename of the file to write in the purple_cache_dir. + * @data: A null-terminated string of data to write. + * @size: The size of the data to save. If data is + * null-terminated you can pass in -1. + * + * Write a string of data to a file of the given name in the Purple + * cache directory ($HOME/.cache/purple by default). + * + * See purple_util_write_data_to_file() + * + * Returns: TRUE if the file was written successfully. FALSE otherwise. + */ +gboolean +purple_util_write_data_to_cache_file(const char *filename, const char *data, gssize size); + +/** + * purple_util_write_data_to_config_file: + * @filename: The basename of the file to write in the purple_config_dir. + * @data: A null-terminated string of data to write. + * @size: The size of the data to save. If data is + * null-terminated you can pass in -1. + * + * Write a string of data to a file of the given name in the Purple + * config directory ($HOME/.config/purple by default). + * + * See purple_util_write_data_to_file() + * + * Returns: TRUE if the file was written successfully. FALSE otherwise. + */ +gboolean +purple_util_write_data_to_config_file(const char *filename, const char *data, gssize size); + +/** + * purple_util_write_data_to_data_file: + * @filename: The basename of the file to write in the purple_data_dir. + * @data: A null-terminated string of data to write. + * @size: The size of the data to save. If data is + * null-terminated you can pass in -1. + * + * Write a string of data to a file of the given name in the Purple + * data directory ($HOME/.local/share/purple by default). + * + * See purple_util_write_data_to_file() + * + * Returns: TRUE if the file was written successfully. FALSE otherwise. + */ +gboolean +purple_util_write_data_to_data_file(const char *filename, const char *data, gssize size); + +/** * purple_util_write_data_to_file_absolute: * @filename_full: Filename to write to * @data: A null-terminated string of data to write.
--- a/libpurple/xmlnode.c Thu Jun 29 23:14:26 2017 -0500 +++ b/libpurple/xmlnode.c Fri Jun 30 15:03:16 2017 +0300 @@ -821,7 +821,7 @@ } PurpleXmlNode * -purple_xmlnode_from_file(const char *dir,const char *filename, const char *description, const char *process) +purple_xmlnode_from_file(const char *dir, const char *filename, const char *description, const char *process) { gchar *filename_full; GError *error = NULL;
--- a/pidgin/gtklog.c Thu Jun 29 23:14:26 2017 -0500 +++ b/pidgin/gtklog.c Fri Jun 30 15:03:16 2017 +0300 @@ -192,7 +192,7 @@ if (log == NULL) - logdir = g_build_filename(purple_user_dir(), "logs", NULL); + logdir = g_build_filename(purple_data_dir(), "logs", NULL); else logdir = purple_log_get_log_dir(log->type, log->name, log->account);