Merged in qarkai/pidgin/xdg-dirs (pull request #230)

Fri, 23 Feb 2018 04:30:06 +0000

author
Gary Kramlich <grim@reaperworld.com>
date
Fri, 23 Feb 2018 04:30:06 +0000
changeset 38902
7c693d88bdbc
parent 38868
de9d792c0d2d (current diff)
parent 38901
14aa09f9caac (diff)
child 38904
3cbcbdb00e29

Merged in qarkai/pidgin/xdg-dirs (pull request #230)

Migrate to XDG dirs

Approved-by: Eion Robb <eionrobb@gmail.com>
Approved-by: Gary Kramlich <grim@reaperworld.com>

libpurple/buddyicon.c file | annotate | diff | comparison | revisions
libpurple/log.c file | annotate | diff | comparison | revisions
libpurple/util.c file | annotate | diff | comparison | revisions
libpurple/util.h file | annotate | diff | comparison | revisions
libpurple/xmlnode.c file | annotate | diff | comparison | revisions
--- a/libpurple/buddyicon.c	Fri Feb 16 00:52:52 2018 -0600
+++ b/libpurple/buddyicon.c	Fri Feb 23 04:30:06 2018 +0000
@@ -1095,8 +1095,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/core.c	Fri Feb 16 00:52:52 2018 -0600
+++ b/libpurple/core.c	Fri Feb 23 04:30:06 2018 +0000
@@ -263,7 +263,7 @@
 	purple_prefs_uninit();
 	purple_plugins_uninit();
 
-	static_proto_unload();	
+	static_proto_unload();
 	purple_protocols_uninit();
 
 #ifdef HAVE_DBUS
@@ -422,3 +422,30 @@
 
 	return ops->get_ui_info();
 }
+
+#define MIGRATE_TO_XDG_DIR(xdg_base_dir, legacy_path) \
+	G_STMT_START { \
+		gboolean migrate_res; \
+		\
+		migrate_res = purple_move_to_xdg_base_dir(xdg_base_dir, legacy_path); \
+		if (!migrate_res) { \
+			purple_debug_error("core", "Error migrating %s to %s\n", \
+						legacy_path, xdg_base_dir); \
+			return FALSE; \
+		} \
+	} G_STMT_END
+
+gboolean
+purple_core_migrate_to_xdg_base_dirs(void)
+{
+	gboolean xdg_dir_exists;
+
+	xdg_dir_exists = g_file_test(purple_data_dir(), G_FILE_TEST_EXISTS);
+	if (!xdg_dir_exists) {
+		MIGRATE_TO_XDG_DIR(purple_data_dir(), "certificates");
+		MIGRATE_TO_XDG_DIR(purple_data_dir(), "logs");
+		MIGRATE_TO_XDG_DIR(purple_config_dir(), "pounces.xml");
+	}
+
+	return TRUE;
+}
--- a/libpurple/core.h	Fri Feb 16 00:52:52 2018 -0600
+++ b/libpurple/core.h	Fri Feb 23 04:30:06 2018 +0000
@@ -226,6 +226,19 @@
  */
 GHashTable* purple_core_get_ui_info(void);
 
+/**
+ * purple_core_migrate_to_xdg_base_dirs:
+ * 
+ * Migrates from legacy directory for libpurple to location following 
+ * XDG base dir spec. https://developer.pidgin.im/ticket/10029
+ * NOTE This is not finished yet. Need to decide where other profile files
+ * should be moved. Search for usages of purple_user_dir().
+ * 
+ * Returns: TRUE if migrated successfully, FALSE otherwise. On failure,
+ *         the application must display an error to the user and then exit.
+ */
+gboolean purple_core_migrate_to_xdg_base_dirs(void);
+
 G_END_DECLS
 
 #endif /* _PURPLE_CORE_H_ */
--- a/libpurple/log.c	Fri Feb 16 00:52:52 2018 -0600
+++ b/libpurple/log.c	Fri Feb 23 04:30:06 2018 +0000
@@ -332,7 +332,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);
 
@@ -1010,7 +1010,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;
 
@@ -1526,7 +1526,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;
@@ -1788,7 +1788,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;
 
@@ -1840,7 +1840,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/pounce.c	Fri Feb 16 00:52:52 2018 -0600
+++ b/libpurple/pounce.c	Fri Feb 23 04:30:06 2018 +0000
@@ -278,7 +278,7 @@
 
 	node = pounces_to_xmlnode();
 	data = purple_xmlnode_to_formatted_str(node, NULL);
-	purple_util_write_data_to_file("pounces.xml", data, -1);
+	purple_util_write_data_to_config_file("pounces.xml", data, -1);
 	g_free(data);
 	purple_xmlnode_free(node);
 }
@@ -534,7 +534,7 @@
 		g_free(data->account_name);
 
 		data->ui_name      = NULL;
-		data->pounce       = NULL;
+		data->pouncee      = NULL;
 		data->protocol_id  = NULL;
 		data->event_type   = NULL;
 		data->option_type  = NULL;
@@ -570,7 +570,7 @@
 static gboolean
 purple_pounces_load(void)
 {
-	gchar *filename = g_build_filename(purple_user_dir(), "pounces.xml", NULL);
+	gchar *filename = g_build_filename(purple_config_dir(), "pounces.xml", NULL);
 	gchar *contents = NULL;
 	gsize length;
 	GMarkupParseContext *context;
--- a/libpurple/protocols/jabber/caps.c	Fri Feb 16 00:52:52 2018 -0600
+++ b/libpurple/protocols/jabber/caps.c	Fri Feb 23 04:30:06 2018 +0000
@@ -206,10 +206,11 @@
 	char *str;
 	int length = 0;
 	PurpleXmlNode *root = purple_xmlnode_new("capabilities");
+
 	g_hash_table_foreach(capstable, jabber_caps_store_client, root);
 	str = purple_xmlnode_to_formatted_str(root, &length);
 	purple_xmlnode_free(root);
-	purple_util_write_data_to_file(JABBER_CAPS_FILENAME, str, length);
+	purple_util_write_data_to_cache_file(JABBER_CAPS_FILENAME, str, length);
 	g_free(str);
 
 	save_timer = 0;
@@ -226,7 +227,7 @@
 static void
 jabber_caps_load(void)
 {
-	PurpleXmlNode *capsdata = purple_util_read_xml_from_file(JABBER_CAPS_FILENAME, "XMPP capabilities cache");
+	PurpleXmlNode *capsdata = purple_util_read_xml_from_cache_file(JABBER_CAPS_FILENAME, "XMPP capabilities cache");
 	PurpleXmlNode *client;
 
 	if(!capsdata)
--- a/libpurple/theme-manager.c	Fri Feb 16 00:52:52 2018 -0600
+++ b/libpurple/theme-manager.c	Fri Feb 23 04:30:06 2018 +0000
@@ -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	Fri Feb 16 00:52:52 2018 -0600
+++ b/libpurple/tls-certificate.c	Fri Feb 23 04:30:06 2018 +0000
@@ -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	Fri Feb 16 00:52:52 2018 -0600
+++ b/libpurple/util.c	Fri Feb 23 04:30:06 2018 +0000
@@ -40,6 +40,9 @@
 
 static char *custom_user_dir = NULL;
 static char *user_dir = NULL;
+static gchar *cache_dir = NULL;
+static gchar *config_dir = NULL;
+static gchar *data_dir = NULL;
 
 static JsonNode *escape_js_node = NULL;
 static JsonGenerator *escape_js_gen = NULL;
@@ -156,6 +159,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;
 
@@ -3026,6 +3038,83 @@
 	return user_dir;
 }
 
+static const gchar *
+purple_xdg_dir(gchar **xdg_dir, const gchar *xdg_base_dir, const gchar *xdg_type)
+{
+	if (!*xdg_dir) {
+		if (!custom_user_dir) {
+			*xdg_dir = g_build_filename(xdg_base_dir, "purple", NULL);
+		} else {
+			*xdg_dir = g_build_filename(custom_user_dir, xdg_type, NULL);
+		}
+	}
+
+	return *xdg_dir;
+}
+
+const gchar *
+purple_cache_dir(void)
+{
+	return purple_xdg_dir(&cache_dir, g_get_user_cache_dir(), "cache");
+}
+
+const gchar *
+purple_config_dir(void)
+{
+	return purple_xdg_dir(&config_dir, g_get_user_config_dir(), "config");
+}
+
+const gchar *
+purple_data_dir(void)
+{
+	return purple_xdg_dir(&data_dir, g_get_user_data_dir(), "data");
+}
+
+gboolean
+purple_move_to_xdg_base_dir(const char *purple_xdg_dir, char *path)
+{
+	gint mkdir_res;
+	gchar *xdg_path;
+	gboolean xdg_path_exists;
+
+	/* Create destination directory */
+	mkdir_res = purple_build_dir(purple_xdg_dir, S_IRWXU);
+	if (mkdir_res == -1) {
+		purple_debug_error("util", "Error creating xdg directory %s: %s; failed migration\n",
+					purple_xdg_dir, g_strerror(errno));
+		return FALSE;
+	}
+
+	xdg_path = g_build_filename(purple_xdg_dir, path, NULL);
+	xdg_path_exists = g_file_test(xdg_path, G_FILE_TEST_EXISTS);
+	if (!xdg_path_exists) {
+		gchar *old_path;
+		gboolean old_path_exists;
+
+		old_path = g_build_filename(purple_user_dir(), path, NULL);
+		old_path_exists = g_file_test(old_path, G_FILE_TEST_EXISTS);
+		if (old_path_exists) {
+			int rename_res;
+
+			rename_res = g_rename(old_path, xdg_path);
+			if (rename_res == -1) {
+				purple_debug_error("util", "Error renaming %s to %s; failed migration\n",
+							old_path, xdg_path);
+				g_free(old_path);
+				g_free(xdg_path);
+
+				return FALSE;
+			}
+		}
+
+		g_free(old_path);
+	}
+
+	g_free(xdg_path);
+
+	return TRUE;
+}
+
 void purple_util_set_user_dir(const char *dir)
 {
 	g_free(custom_user_dir);
@@ -3036,48 +3125,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_build_filename(dir, filename, NULL);
+
+	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;
@@ -3234,6 +3358,24 @@
 	return purple_xmlnode_from_file(purple_user_dir(), filename, description, "util");
 }
 
+PurpleXmlNode *
+purple_util_read_xml_from_cache_file(const char *filename, const char *description)
+{
+	return purple_xmlnode_from_file(purple_cache_dir(), filename, description, "util");
+}
+
+PurpleXmlNode *
+purple_util_read_xml_from_config_file(const char *filename, const char *description)
+{
+	return purple_xmlnode_from_file(purple_config_dir(), filename, description, "util");
+}
+
+PurpleXmlNode *
+purple_util_read_xml_from_data_file(const char *filename, const char *description)
+{
+	return purple_xmlnode_from_file(purple_data_dir(), filename, description, "util");
+}
+
 /*
  * Like mkstemp() but returns a file pointer, uses a pre-set template,
  * uses the semantics of tempnam() for the directory to use and allocates
--- a/libpurple/util.h	Fri Feb 16 00:52:52 2018 -0600
+++ b/libpurple/util.h	Fri Feb 23 04:30:06 2018 +0000
@@ -754,15 +754,68 @@
  * purple_user_dir:
  *
  * Returns the purple settings directory in the user's home directory.
- * This is usually ~/.purple
+ * This is usually $HOME/.purple
  *
  *  See purple_home_dir()
  *
  * Returns: The purple settings directory.
+ * 
+ * Deprecated: Use purple_cache_dir(), purple_config_dir() or
+ *             purple_data_dir() instead.
  */
 const char *purple_user_dir(void);
 
 /**
+ * purple_cache_dir:
+ *
+ * Returns the purple cache directory according to XDG Base Directory Specification.
+ * This is usually $HOME/.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 gchar *purple_cache_dir(void);
+
+/**
+ * purple_config_dir:
+ *
+ * Returns the purple configuration directory according to XDG Base Directory Specification.
+ * This is usually $HOME/.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 gchar *purple_config_dir(void);
+
+/**
+ * purple_data_dir:
+ *
+ * Returns the purple data directory according to XDG Base Directory Specification.
+ * This is usually $HOME/.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 gchar *purple_data_dir(void);
+
+/**
+ * purple_move_to_xdg_base_dir:
+ * @purple_xdg_dir: The path to cache, config or data dir.
+ *                  Use respective function
+ * @path:           File or directory in purple_user_dir
+ * 
+ * Moves file or directory from legacy user dir to XDG
+ * based dir.
+ * 
+ * Returns: TRUE if moved successfully, FALSE otherwise
+ */
+gboolean
+purple_move_to_xdg_base_dir(const char *purple_xdg_dir, char *path);
+
+/**
  * purple_util_set_user_dir:
  * @dir: The custom settings directory
  *
@@ -786,7 +839,7 @@
 /**
  * purple_util_write_data_to_file:
  * @filename: The basename of the file to write in the purple_user_dir.
- * @data:     A null-terminated string of data to write.
+ * @data:     A string of data to write.
  * @size:     The size of the data to save.  If data is
  *                 null-terminated you can pass in -1.
  *
@@ -798,14 +851,69 @@
  * should work fine for saving binary files as well.
  *
  * Returns: TRUE if the file was written successfully.  FALSE otherwise.
+ * 
+ * Deprecated: Use purple_util_write_data_to_cache_file(),
+ *             purple_util_write_data_to_config_file() or
+ *             purple_util_write_data_to_data_file() instead.
  */
 gboolean purple_util_write_data_to_file(const char *filename, const char *data,
 									  gssize size);
 
 /**
+ * purple_util_write_data_to_cache_file:
+ * @filename: The basename of the file to write in the purple_cache_dir.
+ * @data:     A 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 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 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.
+ * @data:          A string of data to write.
  * @size:          The size of the data to save.  If data is
  *                      null-terminated you can pass in -1.
  *
@@ -836,11 +944,69 @@
  *
  * Returns: An PurpleXmlNode tree of the contents of the given file.  Or NULL, if
  *         the file does not exist or there was an error reading the file.
+ * 
+ * Deprecated: Use purple_util_read_xml_from_cache_file(),
+ *             purple_util_read_xml_from_config_file() or
+ *             purple_util_read_xml_from_data_file() instead.
  */
 PurpleXmlNode *purple_util_read_xml_from_file(const char *filename,
 									  const char *description);
 
 /**
+ * purple_util_read_xml_from_cache_file:
+ * @filename:    The basename of the file to open in the purple_cache_dir.
+ * @description: A very short description of the contents of this
+ *                    file.  This is used in error messages shown to the
+ *                    user when the file can not be opened.  For example,
+ *                    "preferences," or "buddy pounces."
+ *
+ * Read the contents of a given file and parse the results into an
+ * PurpleXmlNode tree structure.  This is intended to be used to read
+ * Purple's cache xml files (xmpp-caps.xml, etc.)
+ *
+ * Returns: An PurpleXmlNode tree of the contents of the given file.  Or NULL, if
+ *         the file does not exist or there was an error reading the file.
+ */
+PurpleXmlNode *
+purple_util_read_xml_from_cache_file(const char *filename, const char *description);
+
+/**
+ * purple_util_read_xml_from_config_file:
+ * @filename:    The basename of the file to open in the purple_config_dir.
+ * @description: A very short description of the contents of this
+ *                    file.  This is used in error messages shown to the
+ *                    user when the file can not be opened.  For example,
+ *                    "preferences," or "buddy pounces."
+ *
+ * Read the contents of a given file and parse the results into an
+ * PurpleXmlNode tree structure.  This is intended to be used to read
+ * Purple's config xml files (prefs.xml, pounces.xml, etc.)
+ *
+ * Returns: An PurpleXmlNode tree of the contents of the given file.  Or NULL, if
+ *         the file does not exist or there was an error reading the file.
+ */
+PurpleXmlNode *
+purple_util_read_xml_from_config_file(const char *filename, const char *description);
+
+/**
+ * purple_util_read_xml_from_data_file:
+ * @filename:    The basename of the file to open in the purple_data_dir.
+ * @description: A very short description of the contents of this
+ *                    file.  This is used in error messages shown to the
+ *                    user when the file can not be opened.  For example,
+ *                    "preferences," or "buddy pounces."
+ *
+ * Read the contents of a given file and parse the results into an
+ * PurpleXmlNode tree structure.  This is intended to be used to read
+ * Purple's cache xml files (accounts.xml, etc.)
+ *
+ * Returns: An PurpleXmlNode tree of the contents of the given file.  Or NULL, if
+ *         the file does not exist or there was an error reading the file.
+ */
+PurpleXmlNode *
+purple_util_read_xml_from_data_file(const char *filename, const char *description);
+
+/**
  * purple_mkstemp:
  * @path:   The returned path to the temp file.
  * @binary: Text or binary, for platforms where it matters.
--- a/libpurple/xmlnode.c	Fri Feb 16 00:52:52 2018 -0600
+++ b/libpurple/xmlnode.c	Fri Feb 23 04:30:06 2018 +0000
@@ -808,7 +808,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	Fri Feb 16 00:52:52 2018 -0600
+++ b/pidgin/gtklog.c	Fri Feb 23 04:30:06 2018 +0000
@@ -196,7 +196,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);
 

mercurial