# HG changeset patch
# Node ID 9a8d0ab7b43e
# Parent  31e8c7c92e2f
diff --git a/libpurple/data/im.pidgin.Purple.PresenceManager.gschema.xml b/libpurple/data/im.pidgin.Purple.PresenceManager.gschema.xml
--- a/libpurple/data/im.pidgin.Purple.PresenceManager.gschema.xml
+++ b/libpurple/data/im.pidgin.Purple.PresenceManager.gschema.xml
@@ -10,7 +10,7 @@
     <value nick="streaming" value="6"/>
   </enum>
 
-  <schema id="im.pidgin.Purple.SavedPresence">
+  <schema path="/purple/saved-presence/" id="im.pidgin.Purple.SavedPresence">
     <key name="last-used" type="s">
       <default>""</default>
       <summary>The last time this presence was used</summary>
@@ -62,23 +62,11 @@
 
   <schema path="/purple/presence-manager/" id="im.pidgin.Purple.PresenceManager">
     <key name="active" type="s">
-      <default>""</default>
+      <default>"ffffffff-ffff-ffff-ffff-ffffffffffff"</default>
       <summary>The id of the active presence</summary>
       <description>
-        The name of the active presence that the libpurple user is currently
+        The id of the active presence that the libpurple user is currently
         using.
-
-        The presence itself should be have a path of `/presences/%name%` inside
-        the im.pidgin.Purple.PresenceManager settings.
-      </description>
-    </key>
-
-    <key name="presences" type="as">
-      <default>[]</default>
-      <summary>A list of the ids of all saved presences</summary>
-      <description>
-        The list is used to find all of the saved presences as they are
-        relocatable settings.
       </description>
     </key>
   </schema>
diff --git a/libpurple/meson.build b/libpurple/meson.build
--- a/libpurple/meson.build
+++ b/libpurple/meson.build
@@ -248,7 +248,6 @@
 	'purplefiletransfermanagerprivate.h',
 	'purplepresencemanagerprivate.h',
 	'purpleprivate.h',
-	'purplesavedpresenceprivate.h',
 ]
 
 purple_request_headers = [
diff --git a/libpurple/purplepresencemanager.h b/libpurple/purplepresencemanager.h
--- a/libpurple/purplepresencemanager.h
+++ b/libpurple/purplepresencemanager.h
@@ -48,7 +48,7 @@
  *
  * A manager for [class@SavedPresence]'s.
  *
- * Since: 3.0.0
+ * Since: 3.0
  */
 
 /**
@@ -63,7 +63,7 @@
  *
  * Returns: (transfer none) (nullable): The default presence manager.
  *
- * Since: 3.0.0
+ * Since: 3.0
  */
 PURPLE_AVAILABLE_IN_3_0
 PurplePresenceManager *purple_presence_manager_get_default(void);
@@ -84,39 +84,39 @@
  * Returns: (transfer none) (nullable): The default presence manager type cast
  *          to a list model.
  *
- * Since: 3.0.0
+ * Since: 3.0
  */
 PURPLE_AVAILABLE_IN_3_0
 GListModel *purple_presence_manager_get_default_as_model(void);
 
 /**
  * purple_presence_manager_new:
- * @filename: (nullable): An optional filename where settings will be stored.
+ * @path: (nullable): An optional directory path where settings will be stored.
  *
  * Creates a new presence manager instance.
  *
- * If @filename is %NULL, settings will not be stored to disk.
+ * If @path is %NULL, settings will not be stored to disk.
  *
  * Returns: (transfer full): The new instance.
  *
- * Since: 3.0.0
+ * Since: 3.0
  */
 PURPLE_AVAILABLE_IN_3_0
-PurplePresenceManager *purple_presence_manager_new(const char *filename);
+PurplePresenceManager *purple_presence_manager_new(const char *path);
 
 /**
- * purple_presence_manager_get_filename:
+ * purple_presence_manager_get_path:
  * @manager: The instance.
  *
- * Gets the file name that @manager is using for storage.
+ * Gets the directory path that @manager is using for storage.
  *
- * Returns: (nullable): The filename where settings are being saved to disk or
- *          %NULL.
+ * Returns: (nullable): The directory path where settings are being saved to
+ *          disk or %NULL.
  *
- * Since: 3.0.0
+ * Since: 3.0
  */
 PURPLE_AVAILABLE_IN_3_0
-const char *purple_presence_manager_get_filename(PurplePresenceManager *manager);
+const char *purple_presence_manager_get_path(PurplePresenceManager *manager);
 
 /**
  * purple_presence_manager_get_active:
@@ -127,7 +127,7 @@
  * Returns: (transfer none) (nullable): The active presence if there is one,
  *          otherwise %NULL.
  *
- * Since: 3.0.0
+ * Since: 3.0
  */
 PURPLE_AVAILABLE_IN_3_0
 PurpleSavedPresence *purple_presence_manager_get_active(PurplePresenceManager *manager);
@@ -135,21 +135,19 @@
 /**
  * purple_presence_manager_set_active:
  * @manager: The instance.
- * @id: The id of the presence to make active.
+ * @presence: The presence to set as active.
  *
- * Sets the active presence to the [class@SavedPresence] with a
- * [property@SavedPresence:id] of @id.
+ * Sets the active presence to @presence.
  *
- * If @manager doesn't know of a presence with an id of @id, %FALSE will be
- * returned to indicate failure.
+ * If @manager doesn't know about @presence, %FALSE will be returned to
+ * indicate a failure.
  *
- * Returns: %TRUE if a presence was found with an id of @id and made active,
- *          otherwise %FALSE.
+ * Returns: %TRUE if a presence was found and made active, otherwise %FALSE.
  *
- * Since: 3.0.0
+ * Since: 3.0
  */
 PURPLE_AVAILABLE_IN_3_0
-gboolean purple_presence_manager_set_active(PurplePresenceManager *manager, const char *id);
+gboolean purple_presence_manager_set_active(PurplePresenceManager *manager, PurpleSavedPresence *presence);
 
 /**
  * purple_presence_manager_create:
@@ -163,7 +161,7 @@
  *
  * Returns: (transfer full): The new [class@SavedPresence].
  *
- * Since: 3.0.0
+ * Since: 3.0
  */
 PURPLE_AVAILABLE_IN_3_0
 PurpleSavedPresence *purple_presence_manager_create(PurplePresenceManager *manager);
@@ -179,7 +177,7 @@
  * Returns: %TRUE if a [class@SavedPresence] was found with @id and removed,
  *          otherwise %FALSE.
  *
- * Since: 3.0.0
+ * Since: 3.0
  */
 PURPLE_AVAILABLE_IN_3_0
 gboolean purple_presence_manager_remove(PurplePresenceManager *manager, const char *id);
diff --git a/libpurple/purplepresencemanager.c b/libpurple/purplepresencemanager.c
--- a/libpurple/purplepresencemanager.c
+++ b/libpurple/purplepresencemanager.c
@@ -21,6 +21,7 @@
  */
 
 #include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
 
 #define G_SETTINGS_ENABLE_BACKEND
 #include <gio/gsettingsbackend.h>
@@ -29,17 +30,15 @@
 #include "purplepresencemanagerprivate.h"
 
 #include "core.h"
-#include "purplesavedpresenceprivate.h"
 #include "purpleui.h"
 #include "util.h"
 
 #define MANAGER_SCHEMA_ID "im.pidgin.Purple.PresenceManager"
-#define PRESENCE_SCHEMA_ID "im.pidgin.Purple.SavedPresence"
-#define MANAGER_PATH "/purple/presence-manager"
+#define SAVED_PRESENCE_SCHEMA_ID "im.pidgin.Purple.SavedPresence"
 
 enum {
 	PROP_0,
-	PROP_FILENAME,
+	PROP_PATH,
 	PROP_ACTIVE,
 	N_PROPERTIES,
 };
@@ -55,7 +54,7 @@
 struct _PurplePresenceManager {
 	GObject parent;
 
-	char *filename;
+	char *path;
 	GSettingsBackend *backend;
 	GSettings *settings;
 
@@ -69,8 +68,17 @@
  * Helpers
  *****************************************************************************/
 static inline char *
-purple_presence_manager_path_for_presence(const char *id) {
-	return g_strdup_printf("%s/presences/%s/", MANAGER_PATH, id);
+purple_presence_manager_get_path_for_id(PurplePresenceManager *manager,
+                                        const char *id)
+{
+	char *filename = NULL;
+	char *basename = NULL;
+
+	basename = g_strdup_printf("%s.ini", id);
+	filename = g_build_filename(manager->path, basename, NULL);
+	g_clear_pointer(&basename, g_free);
+
+	return filename;
 }
 
 static gboolean
@@ -116,116 +124,171 @@
 	return ret;
 }
 
-static void
-purple_presence_manager_update_presences_setting(PurplePresenceManager *manager)
-{
-	GStrvBuilder *builder = NULL;
-	GStrv presences = NULL;
+static PurpleSavedPresence *
+purple_presence_manager_add(PurplePresenceManager *manager, const char *id) {
+	PurpleSavedPresence *presence = NULL;
+	GSettingsBackend *backend = NULL;
+	GSettings *settings = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_PRESENCE_MANAGER(manager), NULL);
+	g_return_val_if_fail(!purple_strempty(id), NULL);
 
-	builder = g_strv_builder_new();
-	for(guint i = 0; i < manager->presences->len; i++) {
-		PurpleSavedPresence *presence = NULL;
-		const char *id = NULL;
+	/* Figure out which settings backend to use. */
+	if(!purple_strempty(manager->path)) {
+		char *filename = NULL;
 
-		presence = g_ptr_array_index(manager->presences, i);
-		id = purple_saved_presence_get_id(presence);
-		g_strv_builder_add(builder, id);
+		filename = purple_presence_manager_get_path_for_id(manager, id);
+		backend = g_keyfile_settings_backend_new(filename, "/", NULL);
+		g_clear_pointer(&filename, g_free);
+	} else {
+		backend = g_memory_settings_backend_new();
 	}
 
-	presences = g_strv_builder_end(builder);
-	g_settings_set_strv(manager->settings, "presences",
-	                    (const char * const *)presences);
-	g_strfreev(presences);
-	g_strv_builder_unref(builder);
-}
+	/* Create the settings object with the determined backend. */
+	settings = g_settings_new_with_backend(SAVED_PRESENCE_SCHEMA_ID, backend);
+	g_clear_object(&backend);
 
-static inline void
-purple_presence_manager_add(PurplePresenceManager *manager,
-                            PurpleSavedPresence *presence)
-{
-	g_return_if_fail(PURPLE_IS_PRESENCE_MANAGER(manager));
-	g_return_if_fail(PURPLE_IS_SAVED_PRESENCE(presence));
+	/* Create the presence. */
+	presence = g_object_new(
+		PURPLE_TYPE_SAVED_PRESENCE,
+		"id", id,
+		"settings", settings,
+		NULL);
 
 	g_ptr_array_add(manager->presences, g_object_ref(presence));
-	purple_presence_manager_update_presences_setting(manager);
 
 	g_signal_emit(manager, signals[SIG_ADDED], 0, presence);
 	g_list_model_items_changed(G_LIST_MODEL(manager),
 	                           manager->presences->len - 1, 0, 1);
+
+	return presence;
 }
 
 static void
-purple_presence_manager_set_filename(PurplePresenceManager *manager,
-                                     const char *filename)
+purple_presence_manager_set_path(PurplePresenceManager *manager,
+                                 const char *path)
 {
 	g_return_if_fail(PURPLE_IS_PRESENCE_MANAGER(manager));
 
-	if(!purple_strequal(filename, manager->filename)) {
-		g_free(manager->filename);
-		manager->filename = g_strdup(filename);
+	if(!purple_strequal(path, manager->path)) {
+		g_free(manager->path);
+		manager->path = g_strdup(path);
 
-		g_object_notify_by_pspec(G_OBJECT(manager), properties[PROP_FILENAME]);
+		g_object_notify_by_pspec(G_OBJECT(manager), properties[PROP_PATH]);
 	}
 }
 
 static void
 purple_presence_manager_load_saved_presences(PurplePresenceManager *manager) {
-	GStrv ids = NULL;
+	PurpleSavedPresence *presence = NULL;
+	const char *id = NULL;
+
+	/* Load the presences from disk. */
+	if(manager->path != NULL) {
+		GDir *dir = NULL;
+		GError *error = NULL;
+		const char *basename = NULL;
 
-	ids = g_settings_get_strv(manager->settings, "presences");
+		dir = g_dir_open(manager->path, 0, &error);
+		if(error != NULL) {
+			g_warning("failed to open directory '%s': %s", manager->path,
+			          error->message);
+		} else {
+			GPatternSpec *pattern = NULL;
+
+			/* We use ?* to make sure we have at least one character before the
+			 * .ini.
+			 */
+			pattern = g_pattern_spec_new("?*.ini");
 
-	/* If we don't have any existing presences, create an available one. */
-	if(ids[0] == NULL) {
-		PurpleSavedPresence *presence = NULL;
-		const char *id = NULL;
+			while((basename = g_dir_read_name(dir)) != NULL) {
+				if(purple_strequal(basename, "manager.ini")) {
+					continue;
+				}
+
+				if(g_pattern_spec_match_string(pattern, basename)) {
+					PurpleSavedPresence *presence = NULL;
+					char *id = NULL;
 
-		/* We aren't going to use the ids anymore so free them right away. */
-		g_strfreev(ids);
+					id = g_strndup(basename, strlen(basename) - 4);
+					presence = purple_presence_manager_add(manager, id);
+					g_clear_pointer(&id, g_free);
+					g_clear_object(&presence);
+				}
+			}
+			g_dir_close(dir);
 
-		/* Create the default available presence and set it as active. */
-		presence = purple_presence_manager_create(manager);
+			g_clear_pointer(&pattern, g_pattern_spec_free);
+		}
+	}
+
+	/* Make sure we have our default available presence. */
+	id = "ffffffff-ffff-ffff-ffff-ffffffffffff";
+	presence = purple_presence_manager_find_with_id(manager, id, NULL);
+	if(!PURPLE_IS_SAVED_PRESENCE(presence)) {
+		presence = purple_presence_manager_add(manager, id);
 		purple_saved_presence_set_name(presence, _("Available"));
 		purple_saved_presence_set_primitive(presence,
 		                                    PURPLE_PRESENCE_PRIMITIVE_AVAILABLE);
-
-		id = purple_saved_presence_get_id(presence);
-		purple_presence_manager_set_active(manager, id);
+		g_clear_object(&presence);
+	}
 
-		g_clear_object(&presence);
-
-		/* Create the default offline presence as well. */
-		presence = purple_presence_manager_create(manager);
+	/* Make sure we have our default offline presence as well. */
+	id = "00000000-0000-0000-0000-000000000000";
+	presence = purple_presence_manager_find_with_id(manager, id, NULL);
+	if(!PURPLE_IS_SAVED_PRESENCE(presence)) {
+		presence = purple_presence_manager_add(manager, id);
 		purple_saved_presence_set_name(presence, _("Offline"));
 		purple_saved_presence_set_primitive(presence,
 		                                    PURPLE_PRESENCE_PRIMITIVE_OFFLINE);
 		g_clear_object(&presence);
+	}
+}
 
-		return;
+/******************************************************************************
+ * GSettings Mappings
+ *****************************************************************************/
+static gboolean
+purple_presence_manager_get_active_mapping(GValue *value, GVariant *variant,
+                                           gpointer data)
+{
+	PurplePresenceManager *manager = data;
+	PurpleSavedPresence *presence = NULL;
+	const char *id = NULL;
+
+	/* Get the id of the saved presence from gsettings. */
+	id = g_variant_get_string(variant, NULL);
+
+	presence = purple_presence_manager_find_with_id(manager, id, NULL);
+	if(PURPLE_IS_SAVED_PRESENCE(presence)) {
+		g_value_set_object(value, G_OBJECT(presence));
+
+		return TRUE;
 	}
 
-	for(int i = 0; ids[i] != NULL; i++) {
-		PurpleSavedPresence *presence = NULL;
-		GSettings *settings = NULL;
-		char *path = NULL;
+	return FALSE;
+}
 
-		path = purple_presence_manager_path_for_presence(ids[i]);
-		settings = g_settings_new_with_backend_and_path(PRESENCE_SCHEMA_ID,
-		                                                manager->backend,
-		                                                path);
-		g_clear_pointer(&path, g_free);
+static GVariant *
+purple_presence_manager_set_active_mapping(const GValue *value,
+                                           const GVariantType *expected_type,
+                                           G_GNUC_UNUSED gpointer data)
+{
+	PurpleSavedPresence *presence = NULL;
+	const char *id = NULL;
 
-		presence = g_object_new(
-			PURPLE_TYPE_SAVED_PRESENCE,
-			"id", ids[i],
-			"settings", settings,
-			NULL);
-
-		purple_presence_manager_add(manager, presence);
-
-		g_clear_object(&presence);
+	if(!g_variant_type_equal(expected_type, G_VARIANT_TYPE_STRING)) {
+		return NULL;
 	}
 
-	g_strfreev(ids);
+	presence = g_value_get_object(value);
+	if(!PURPLE_IS_SAVED_PRESENCE(presence)) {
+		return NULL;
+	}
+
+	id = purple_saved_presence_get_id(presence);
+
+	return g_variant_new_string(id);
 }
 
 /******************************************************************************
@@ -274,15 +337,17 @@
 static void
 purple_presence_manager_constructed(GObject *obj) {
 	PurplePresenceManager *manager = PURPLE_PRESENCE_MANAGER(obj);
-	char *active_id = NULL;
 
 	G_OBJECT_CLASS(purple_presence_manager_parent_class)->constructed(obj);
 
-	if(manager->filename == NULL) {
+	if(manager->path == NULL) {
 		manager->backend = g_memory_settings_backend_new();
 	} else {
-		manager->backend = g_keyfile_settings_backend_new(manager->filename,
-		                                                  "/", NULL);
+		char *filename = NULL;
+
+		filename = g_build_filename(manager->path, "manager.ini", NULL);
+		manager->backend = g_keyfile_settings_backend_new(filename, "/", NULL);
+		g_clear_pointer(&filename, g_free);
 	}
 
 	manager->settings = g_settings_new_with_backend(MANAGER_SCHEMA_ID,
@@ -290,21 +355,18 @@
 
 	purple_presence_manager_load_saved_presences(manager);
 
-	active_id = g_settings_get_string(manager->settings, "active");
-	if(!purple_strempty(active_id)) {
-		if(!purple_presence_manager_set_active(manager, active_id)) {
-			g_warning("failed to set the active saved presence to %s",
-			          active_id);
-		}
-	}
-	g_clear_pointer(&active_id, g_free);
+	g_settings_bind_with_mapping(manager->settings, "active", manager,
+	                             "active-presence", G_SETTINGS_BIND_DEFAULT,
+	                             purple_presence_manager_get_active_mapping,
+	                             purple_presence_manager_set_active_mapping,
+	                             manager, NULL);
 }
 
 static void
 purple_presence_manager_finalize(GObject *obj) {
 	PurplePresenceManager *manager = PURPLE_PRESENCE_MANAGER(obj);
 
-	g_clear_pointer(&manager->filename, g_free);
+	g_clear_pointer(&manager->path, g_free);
 
 	g_clear_object(&manager->active);
 	if(manager->presences != NULL) {
@@ -325,9 +387,9 @@
 	PurplePresenceManager *manager = PURPLE_PRESENCE_MANAGER(obj);
 
 	switch(param_id) {
-		case PROP_FILENAME:
+		case PROP_PATH:
 			g_value_set_string(value,
-			                   purple_presence_manager_get_filename(manager));
+			                   purple_presence_manager_get_path(manager));
 			break;
 		case PROP_ACTIVE:
 			g_value_set_object(value,
@@ -346,9 +408,13 @@
 	PurplePresenceManager *manager = PURPLE_PRESENCE_MANAGER(obj);
 
 	switch(param_id) {
-		case PROP_FILENAME:
-			purple_presence_manager_set_filename(manager,
-			                                     g_value_get_string(value));
+		case PROP_PATH:
+			purple_presence_manager_set_path(manager,
+			                                 g_value_get_string(value));
+			break;
+		case PROP_ACTIVE:
+			purple_presence_manager_set_active(manager,
+			                                   g_value_get_object(value));
 			break;
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
@@ -372,16 +438,16 @@
 	obj_class->set_property = purple_presence_manager_set_property;
 
 	/**
-	 * PurplePresenceManager:filename:
+	 * PurplePresenceManager:path:
 	 *
-	 * The filename where settings should be stored. If this is %NULL settings
-	 * will not be saved to disk.
+	 * The directory path where settings should be stored. If this is %NULL
+	 * settings will not be saved to disk.
 	 *
 	 * Since: 3.0.0
 	 */
-	properties[PROP_FILENAME] = g_param_spec_string(
-		"filename", "filename",
-		"The name of the file where settings should be stored.",
+	properties[PROP_PATH] = g_param_spec_string(
+		"path", "path",
+		"The directory path where settings should be stored.",
 		NULL,
 		G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
 
@@ -396,7 +462,7 @@
 		"active-presence", "active-presence",
 		"The active presence.",
 		PURPLE_TYPE_SAVED_PRESENCE,
-		G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
 
 	g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
 
@@ -484,17 +550,17 @@
 }
 
 PurplePresenceManager *
-purple_presence_manager_new(const char *filename) {
+purple_presence_manager_new(const char *path) {
 	return g_object_new(PURPLE_TYPE_PRESENCE_MANAGER,
-	                    "filename", filename,
+	                    "path", path,
 	                    NULL);
 }
 
 const char *
-purple_presence_manager_get_filename(PurplePresenceManager *manager) {
+purple_presence_manager_get_path(PurplePresenceManager *manager) {
 	g_return_val_if_fail(PURPLE_IS_PRESENCE_MANAGER(manager), NULL);
 
-	return manager->filename;
+	return manager->path;
 }
 
 PurpleSavedPresence *
@@ -506,27 +572,21 @@
 
 gboolean
 purple_presence_manager_set_active(PurplePresenceManager *manager,
-                                   const char *id)
+                                   PurpleSavedPresence *presence)
 {
-	PurpleSavedPresence *presence = NULL;
+	PurpleSavedPresence *found = NULL;
+	const char *id = NULL;
 
 	g_return_val_if_fail(PURPLE_IS_PRESENCE_MANAGER(manager), FALSE);
+	g_return_val_if_fail(PURPLE_IS_SAVED_PRESENCE(presence), FALSE);
 
-	if(id != NULL) {
-		presence = purple_presence_manager_find_with_id(manager, id, NULL);
-		if(!PURPLE_IS_SAVED_PRESENCE(presence)) {
-			return FALSE;
-		}
-	}
+	/* We need to make sure the manager knows about the passed in presence. */
+	id = purple_saved_presence_get_id(presence);
+	found = purple_presence_manager_find_with_id(manager, id, NULL);
+	g_return_val_if_fail(PURPLE_IS_SAVED_PRESENCE(found), FALSE);
 
 	if(g_set_object(&manager->active, presence)) {
 		g_object_notify_by_pspec(G_OBJECT(manager), properties[PROP_ACTIVE]);
-
-		/* g_settings_set_string can't handle nulls, so use an empty string if
-		 * it is null.
-		 */
-		g_settings_set_string(manager->settings, "active",
-		                      id == NULL ? "" : id);
 	}
 
 	return TRUE;
@@ -535,28 +595,13 @@
 PurpleSavedPresence *
 purple_presence_manager_create(PurplePresenceManager *manager) {
 	PurpleSavedPresence *presence = NULL;
-	GSettings *settings = NULL;
 	char *id = NULL;
-	char *path = NULL;
 
 	g_return_val_if_fail(PURPLE_IS_PRESENCE_MANAGER(manager), FALSE);
 
 	id = g_uuid_string_random();
-	path = purple_presence_manager_path_for_presence(id);
-	settings = g_settings_new_with_backend_and_path(PRESENCE_SCHEMA_ID,
-	                                                manager->backend, path);
-	g_free(path);
-
-	presence = g_object_new(
-		PURPLE_TYPE_SAVED_PRESENCE,
-		"id", id,
-		"settings", settings,
-		NULL);
-
-	g_clear_pointer(&id, g_free);
-	g_clear_object(&settings);
-
-	purple_presence_manager_add(manager, presence);
+	presence = purple_presence_manager_add(manager, id);
+	g_free(id);
 
 	return presence;
 }
@@ -565,6 +610,7 @@
 purple_presence_manager_remove(PurplePresenceManager *manager, const char *id)
 {
 	PurpleSavedPresence *presence = NULL;
+	char *filename = NULL;
 	guint index;
 
 	g_return_val_if_fail(PURPLE_IS_PRESENCE_MANAGER(manager), FALSE);
@@ -581,8 +627,10 @@
 	g_object_ref(presence);
 
 	g_ptr_array_remove_index(manager->presences, index);
-	purple_presence_manager_update_presences_setting(manager);
-	purple_saved_presence_reset(presence);
+
+	filename = purple_presence_manager_get_path_for_id(manager, id);
+	g_remove(filename);
+	g_clear_pointer(&filename, g_free);
 
 	g_signal_emit(manager, signals[SIG_REMOVED], 0, presence);
 	g_list_model_items_changed(G_LIST_MODEL(manager), index, 1, 0);
diff --git a/libpurple/purplesavedpresence.c b/libpurple/purplesavedpresence.c
--- a/libpurple/purplesavedpresence.c
+++ b/libpurple/purplesavedpresence.c
@@ -24,7 +24,6 @@
 
 #include "purpleenums.h"
 #include "purplesavedpresence.h"
-#include "purplesavedpresenceprivate.h"
 #include "util.h"
 
 struct _PurpleSavedPresence {
@@ -437,27 +436,6 @@
 }
 
 /******************************************************************************
- * Private API
- *****************************************************************************/
-void
-purple_saved_presence_reset(PurpleSavedPresence *presence) {
-	GSettingsSchema *schema = NULL;
-	GStrv keys = NULL;
-
-	g_return_if_fail(PURPLE_IS_SAVED_PRESENCE(presence));
-
-	g_object_get(presence->settings, "settings-schema", &schema, NULL);
-
-	keys = g_settings_schema_list_keys(schema);
-	for(int i = 0; keys[i] != NULL; i++) {
-		g_settings_reset(presence->settings, keys[i]);
-	}
-	g_strfreev(keys);
-
-	g_clear_pointer(&schema, g_settings_schema_unref);
-}
-
-/******************************************************************************
  * Public API
  *****************************************************************************/
 GDateTime *
diff --git a/libpurple/purplesavedpresenceprivate.h b/libpurple/purplesavedpresenceprivate.h
deleted file mode 100644
--- a/libpurple/purplesavedpresenceprivate.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Purple - Internet Messaging Library
- * Copyright (C) Pidgin Developers <devel@pidgin.im>
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * 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 2 of the License, 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, see <https://www.gnu.org/licenses/>.
- */
-
-#ifndef PURPLE_COMPILATION
-# error "purplesavedpresenceprivate.h may only be include by libpurple"
-#endif
-
-#ifndef PURPLE_SAVED_PRESENCE_PRIVATE_H
-#define PURPLE_SAVED_PRESENCE_PRIVATE_H
-
-#include <glib.h>
-
-#include "purplesavedpresence.h"
-
-G_BEGIN_DECLS
-
-/**
- * purple_saved_presence_reset: (skip)
- * @presence: The instance.
- *
- * Resets all of the settings of @presence to their default values.
- *
- * As of at least glib 2.78.0, the GSettings API doesn't have a way to remove a
- * relocatable settings object. We use relocatable settings to store each saved
- * presence which means we can't delete the section from the GKeyFile.
- *
- * To minimize the amount of disk space wasted by this issue, this function
- * will default all of the keys in the settings object for @presence so that
- * the values will be removed from the GKeyFile.
- *
- * Since: 3.0.0
- */
-G_GNUC_INTERNAL void purple_saved_presence_reset(PurpleSavedPresence *presence);
-
-G_END_DECLS
-
-#endif /* PURPLE_SAVED_PRESENCE_PRIVATE_H */
diff --git a/libpurple/tests/test_presence_manager.c b/libpurple/tests/test_presence_manager.c
--- a/libpurple/tests/test_presence_manager.c
+++ b/libpurple/tests/test_presence_manager.c
@@ -71,7 +71,6 @@
 test_purple_presence_manager_add_remove(void) {
 	PurplePresenceManager *manager = NULL;
 	PurpleSavedPresence *presence = NULL;
-	GListModel *model = NULL;
 	gboolean success = FALSE;
 	guint len = 0;
 	guint added = 0;
@@ -81,26 +80,6 @@
 
 	manager = purple_presence_manager_new(NULL);
 
-	/* When a presence manager is created, if there are no saved statuses it
-	 * adds some default ones and sets the active presence. We need to clear
-	 * all of that to get to a known state.
-	 *
-	 * The default statuses are checked in test_purple_presence_manager_new.
-	 */
-	model = G_LIST_MODEL(manager);
-	purple_presence_manager_set_active(manager, NULL);
-	while(g_list_model_get_n_items(model) > 0) {
-		PurpleSavedPresence *presence = NULL;
-
-		/* Since we're removing items, the positions change, so we just always
-		 * want to remove the item at position 0.
-		 */
-		presence = g_list_model_get_item(model, 0);
-		purple_presence_manager_remove(manager,
-		                               purple_saved_presence_get_id(presence));
-		g_assert_finalize_object(presence);
-	}
-
 	/* Connect all of our signals to make sure they're being emitted. */
 	g_signal_connect(manager, "added",
 	                 G_CALLBACK(test_purple_presence_manager_add_remove_counter),
@@ -113,7 +92,8 @@
 	                 &changed);
 
 	len = g_list_model_get_n_items(G_LIST_MODEL(manager));
-	g_assert_cmpuint(len, ==, 0);
+	/* The manager makes sure we always have online and offline presences. */
+	g_assert_cmpuint(len, ==, 2);
 
 	presence = purple_presence_manager_create(manager);
 	g_assert_true(PURPLE_IS_SAVED_PRESENCE(presence));
@@ -126,7 +106,7 @@
 	g_assert_nonnull(id);
 
 	len = g_list_model_get_n_items(G_LIST_MODEL(manager));
-	g_assert_cmpuint(len, ==, 1);
+	g_assert_cmpuint(len, ==, 3);
 
 	success = purple_presence_manager_remove(manager, id);
 	g_assert_true(success);
@@ -135,7 +115,7 @@
 	g_assert_cmpuint(changed, ==, 2);
 
 	len = g_list_model_get_n_items(G_LIST_MODEL(manager));
-	g_assert_cmpuint(len, ==, 0);
+	g_assert_cmpuint(len, ==, 2);
 
 	g_clear_object(&presence);
 	g_clear_object(&manager);
@@ -145,32 +125,34 @@
 test_purple_presence_manager_persistence(void) {
 	PurplePresenceManager *manager = NULL;
 	PurpleSavedPresence *presence = NULL;
+	char *path = NULL;
 	char *filename = NULL;
 	char *old_id = NULL;
 	const char *id = NULL;
 	const char *id1 = NULL;
 	gboolean ret = FALSE;
 
-	filename = g_build_filename(TEST_CACHE_DIR,
-	                            "presence_manager_persistence.ini",
-	                            NULL);
+	path = g_build_filename(TEST_CACHE_DIR, "presence_manager_persistence",
+	                        NULL);
 
 	/* Remove the file if it exists so we can start from a known state. */
+	filename = g_build_filename(path, "manager.ini", NULL);
 	g_remove(filename);
+	g_clear_pointer(&filename, g_free);
 
 	/* Create the manager, add a presence, and make it active. */
-	manager = purple_presence_manager_new(filename);
+	manager = purple_presence_manager_new(path);
 	g_assert_true(PURPLE_IS_PRESENCE_MANAGER(manager));
 
 	presence = purple_presence_manager_create(manager);
-	g_assert_true(PURPLE_IS_SAVED_PRESENCE(presence));
+	purple_saved_presence_set_name(presence, "test-presence");
 
 	/* Save the id of the presence as we need to use it later. */
 	id = purple_saved_presence_get_id(presence);
 	old_id = g_strdup(id);
 
 	/* Make the presence active. */
-	ret = purple_presence_manager_set_active(manager, id);
+	ret = purple_presence_manager_set_active(manager, presence);
 	g_assert_true(ret);
 	g_clear_object(&presence);
 
@@ -187,7 +169,7 @@
 	g_clear_object(&manager);
 
 	/* Now create the manager again and verify that everything was restored. */
-	manager = purple_presence_manager_new(filename);
+	manager = purple_presence_manager_new(path);
 	g_assert_true(PURPLE_IS_PRESENCE_MANAGER(manager));
 
 	presence = purple_presence_manager_get_active(manager);
@@ -199,7 +181,7 @@
 
 	/* Cleanup. */
 	g_clear_object(&manager);
-	g_clear_pointer(&filename, g_free);
+	g_clear_pointer(&path, g_free);
 }
 
 /******************************************************************************
diff --git a/libpurple/tests/test_saved_presence.c b/libpurple/tests/test_saved_presence.c
--- a/libpurple/tests/test_saved_presence.c
+++ b/libpurple/tests/test_saved_presence.c
@@ -124,7 +124,7 @@
 	char *timestamp = NULL;
 
 	backend = g_memory_settings_backend_new();
-	settings = g_settings_new_with_backend_and_path(SCHEMA_ID, backend, "/");
+	settings = g_settings_new_with_backend(SCHEMA_ID, backend);
 
 	presence = g_object_new(
 		PURPLE_TYPE_SAVED_PRESENCE,
@@ -178,7 +178,7 @@
 	char *timestamp = NULL;
 
 	backend = g_memory_settings_backend_new();
-	settings = g_settings_new_with_backend_and_path(SCHEMA_ID, backend, "/");
+	settings = g_settings_new_with_backend(SCHEMA_ID, backend);
 
 	presence = g_object_new(
 		PURPLE_TYPE_SAVED_PRESENCE,
diff --git a/pidgin/pidginui.c b/pidgin/pidginui.c
--- a/pidgin/pidginui.c
+++ b/pidgin/pidginui.c
@@ -185,13 +185,13 @@
 static PurplePresenceManager *
 pidgin_ui_get_presence_manager(G_GNUC_UNUSED PurpleUi *ui) {
 	PurplePresenceManager *manager = NULL;
-	char *filename = NULL;
+	char *path = NULL;
 
 	g_mkdir_with_parents(purple_config_dir(), 0700);
 
-	filename = g_build_filename(purple_config_dir(), "presences.ini", NULL);
-	manager = purple_presence_manager_new(filename);
-	g_free(filename);
+	path = g_build_filename(purple_config_dir(), "presences", NULL);
+	manager = purple_presence_manager_new(path);
+	g_free(path);
 
 	return manager;
 }
