changeset 27704:14ce47859540

Add blist ui-ops to overload the saving of data to blist.xml. Closes #9630. Patch from Jan "HanzZ" Kaluza with some changes by me so that it's easier to merge with Sulabh and Eric's SoC projects (mostly so grim wouldn't yell at me). Anyway, any bugs introduced by me (darkrain42). committer: Paul Aurich <paul@darkrain42.org>
author hanzz@soc.pidgin.im
date Mon, 27 Jul 2009 05:20:52 +0000
parents 2cb2da84663d
children 12ab4c1112e5 bd3cf895e19a
files ChangeLog.API libpurple/account.c libpurple/blist.c libpurple/blist.h libpurple/privacy.c
diffstat 5 files changed, 180 insertions(+), 36 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog.API	Mon Jul 27 05:09:21 2009 +0000
+++ b/ChangeLog.API	Mon Jul 27 05:20:52 2009 +0000
@@ -15,6 +15,9 @@
 			* account-destroying
 		* blist-node-added and blist-node-removed signals (see
 		  blist-signals.dox)
+		* Three Blist UI ops used to overload libpurple's built-in saving
+		  of the buddy list to blist.xml. If a UI implements these, it probably
+		  wants to add the buddies itself and not call purple_blist_load.
 		* Jabber plugin signals (see jabber-signals.dox)
 		* purple_account_remove_setting
 		* purple_buddy_destroy
--- a/libpurple/account.c	Mon Jul 27 05:09:21 2009 +0000
+++ b/libpurple/account.c	Mon Jul 27 05:20:52 2009 +0000
@@ -1534,6 +1534,8 @@
 void
 purple_account_set_username(PurpleAccount *account, const char *username)
 {
+	PurpleBlistUiOps *blist_ops;
+
 	g_return_if_fail(account != NULL);
 
 	g_free(account->username);
@@ -1543,7 +1545,9 @@
 
 	/* if the name changes, we should re-write the buddy list
 	 * to disk with the new name */
-	purple_blist_schedule_save();
+	blist_ops = purple_blist_get_ui_ops();
+	if (blist_ops != NULL && blist_ops->save_account != NULL)
+		blist_ops->save_account(account);
 }
 
 void
--- a/libpurple/blist.c	Mon Jul 27 05:09:21 2009 +0000
+++ b/libpurple/blist.c	Mon Jul 27 05:20:52 2009 +0000
@@ -393,13 +393,42 @@
 	return FALSE;
 }
 
-void
-purple_blist_schedule_save()
+static void
+_purple_blist_schedule_save()
 {
 	if (save_timer == 0)
 		save_timer = purple_timeout_add_seconds(5, save_cb, NULL);
 }
 
+static void
+purple_blist_save_account(PurpleAccount *account)
+{
+#if 1
+	_purple_blist_schedule_save();
+#else
+	if (account != NULL) {
+		/* Save the buddies and privacy data for this account */
+	} else {
+		/* Save all buddies and privacy data */
+	}
+#endif
+}
+
+static void
+purple_blist_save_node(PurpleBlistNode *node)
+{
+	_purple_blist_schedule_save();
+}
+
+void purple_blist_schedule_save()
+{
+	PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
+
+	/* Save everything */
+	if (ops && ops->save_account)
+		ops->save_account(NULL);
+}
+
 
 /*********************************************************************
  * Reading from disk                                                 *
@@ -971,7 +1000,8 @@
 	g_free(buddy->name);
 	buddy->name = g_strdup(name);
 
-	purple_blist_schedule_save();
+	if (ops && ops->save_node)
+		ops->save_node((PurpleBlistNode *) buddy);
 
 	if (ops && ops->update)
 		ops->update(purplebuddylist, (PurpleBlistNode *)buddy);
@@ -1011,7 +1041,8 @@
 		g_free(new_alias); /* could be "\0" */
 	}
 
-	purple_blist_schedule_save();
+	if (ops && ops->save_node)
+		ops->save_node((PurpleBlistNode*) contact);
 
 	if (ops && ops->update)
 		ops->update(purplebuddylist, (PurpleBlistNode *)contact);
@@ -1056,7 +1087,8 @@
 		g_free(new_alias); /* could be "\0" */
 	}
 
-	purple_blist_schedule_save();
+	if (ops && ops->save_node)
+		ops->save_node((PurpleBlistNode*) chat);
 
 	if (ops && ops->update)
 		ops->update(purplebuddylist, (PurpleBlistNode *)chat);
@@ -1092,7 +1124,8 @@
 		g_free(new_alias); /* could be "\0" */
 	}
 
-	purple_blist_schedule_save();
+	if (ops && ops->save_node)
+		ops->save_node((PurpleBlistNode*) buddy);
 
 	if (ops && ops->update)
 		ops->update(purplebuddylist, (PurpleBlistNode *)buddy);
@@ -1133,7 +1166,8 @@
 		g_free(new_alias); /* could be "\0"; */
 	}
 
-	purple_blist_schedule_save();
+	if (ops && ops->save_node)
+		ops->save_node((PurpleBlistNode*) buddy);
 
 	if (ops && ops->update)
 		ops->update(purplebuddylist, (PurpleBlistNode *)buddy);
@@ -1235,7 +1269,8 @@
 	}
 
 	/* Save our changes */
-	purple_blist_schedule_save();
+	if (ops && ops->save_node)
+		ops->save_node((PurpleBlistNode*) source);
 
 	/* Update the UI */
 	if (ops && ops->update)
@@ -1493,8 +1528,6 @@
 		 * reinitialize it */
 		if (ops && ops->new_node)
 			ops->new_node(cnode);
-
-		purple_blist_schedule_save();
 	}
 
 	if (node != NULL) {
@@ -1523,7 +1556,8 @@
 		}
 	}
 
-	purple_blist_schedule_save();
+	if (ops && ops->save_node)
+		ops->save_node(cnode);
 
 	if (ops && ops->update)
 		ops->update(purplebuddylist, (PurpleBlistNode *)cnode);
@@ -1601,8 +1635,6 @@
 		if (ops && ops->remove)
 			ops->remove(purplebuddylist, bnode);
 
-		purple_blist_schedule_save();
-
 		if (bnode->parent->parent != (PurpleBlistNode*)g) {
 			struct _purple_hbuddy hb;
 			hb.name = (gchar *)purple_normalize(buddy->account, buddy->name);
@@ -1667,7 +1699,8 @@
 
 	purple_contact_invalidate_priority_buddy(purple_buddy_get_contact(buddy));
 
-	purple_blist_schedule_save();
+	if (ops && ops->save_node)
+		ops->save_node((PurpleBlistNode*) buddy);
 
 	if (ops && ops->update)
 		ops->update(purplebuddylist, (PurpleBlistNode*)buddy);
@@ -1886,7 +1919,8 @@
 		if (ops && ops->remove)
 			ops->remove(purplebuddylist, cnode);
 
-		purple_blist_schedule_save();
+		if (ops && ops->remove_node)
+			ops->remove_node(cnode);
 	}
 
 	if (node && (PURPLE_BLIST_NODE_IS_CONTACT(node) ||
@@ -1912,7 +1946,13 @@
 		g->currentsize++;
 	g->totalsize++;
 
-	purple_blist_schedule_save();
+	if (ops && ops->save_node)
+	{
+		if (cnode->child)
+			ops->save_node(cnode);
+		for (bnode = cnode->child; bnode; bnode = bnode->next)
+			ops->save_node(bnode);
+	}
 
 	if (ops && ops->update)
 	{
@@ -2012,7 +2052,11 @@
 		purplebuddylist->root = gnode;
 	}
 
-	purple_blist_schedule_save();
+	if (ops && ops->save_node) {
+		ops->save_node(gnode);
+		for (node = gnode->child; node; node = node->next)
+			ops->save_node(node);
+	}
 
 	if (ops && ops->update) {
 		ops->update(purplebuddylist, gnode);
@@ -2058,12 +2102,13 @@
 		if (node->next)
 			node->next->prev = node->prev;
 
-		purple_blist_schedule_save();
-
 		/* Update the UI */
 		if (ops && ops->remove)
 			ops->remove(purplebuddylist, node);
 
+		if (ops && ops->remove_node)
+			ops->remove_node(node);
+
 		purple_signal_emit(purple_blist_get_handle(), "blist-node-removed",
 				PURPLE_BLIST_NODE(contact));
 
@@ -2119,8 +2164,6 @@
 		}
 	}
 
-	purple_blist_schedule_save();
-
 	/* Remove this buddy from the buddies hash table */
 	hb.name = (gchar *)purple_normalize(buddy->account, buddy->name);
 	hb.account = buddy->account;
@@ -2134,6 +2177,9 @@
 	if (ops && ops->remove)
 		ops->remove(purplebuddylist, node);
 
+	if (ops && ops->remove_node)
+		ops->remove_node(node);
+
 	/* Signal that the buddy has been removed before freeing the memory for it */
 	purple_signal_emit(purple_blist_get_handle(), "buddy-removed", buddy);
 
@@ -2176,13 +2222,15 @@
 		}
 		group->totalsize--;
 
-		purple_blist_schedule_save();
 	}
 
 	/* Update the UI */
 	if (ops && ops->remove)
 		ops->remove(purplebuddylist, node);
 
+	if (ops && ops->remove_node)
+		ops->remove_node(node);
+
 	purple_signal_emit(purple_blist_get_handle(), "blist-node-removed",
 			PURPLE_BLIST_NODE(chat));
 
@@ -2217,12 +2265,13 @@
 	g_hash_table_remove(groups_cache, key);
 	g_free(key);
 
-	purple_blist_schedule_save();
-
 	/* Update the UI */
 	if (ops && ops->remove)
 		ops->remove(purplebuddylist, node);
 
+	if (ops && ops->remove_node)
+		ops->remove_node(node);
+
 	purple_signal_emit(purple_blist_get_handle(), "blist-node-removed",
 			PURPLE_BLIST_NODE(group));
 
@@ -2827,13 +2876,16 @@
 
 void purple_blist_node_remove_setting(PurpleBlistNode *node, const char *key)
 {
+	PurpleBlistUiOps *ops;
 	g_return_if_fail(node != NULL);
 	g_return_if_fail(node->settings != NULL);
 	g_return_if_fail(key != NULL);
 
 	g_hash_table_remove(node->settings, key);
 
-	purple_blist_schedule_save();
+	ops = purple_blist_get_ui_ops();
+	if (ops && ops->save_node)
+		ops->save_node(node);
 }
 
 void
@@ -2863,6 +2915,7 @@
 purple_blist_node_set_bool(PurpleBlistNode* node, const char *key, gboolean data)
 {
 	PurpleValue *value;
+	PurpleBlistUiOps *ops;
 
 	g_return_if_fail(node != NULL);
 	g_return_if_fail(node->settings != NULL);
@@ -2873,7 +2926,9 @@
 
 	g_hash_table_replace(node->settings, g_strdup(key), value);
 
-	purple_blist_schedule_save();
+	ops = purple_blist_get_ui_ops();
+	if (ops && ops->save_node)
+		ops->save_node(node);
 }
 
 gboolean
@@ -2899,6 +2954,7 @@
 purple_blist_node_set_int(PurpleBlistNode* node, const char *key, int data)
 {
 	PurpleValue *value;
+	PurpleBlistUiOps *ops;
 
 	g_return_if_fail(node != NULL);
 	g_return_if_fail(node->settings != NULL);
@@ -2909,7 +2965,9 @@
 
 	g_hash_table_replace(node->settings, g_strdup(key), value);
 
-	purple_blist_schedule_save();
+	ops = purple_blist_get_ui_ops();
+	if (ops && ops->save_node)
+		ops->save_node(node);
 }
 
 int
@@ -2935,6 +2993,7 @@
 purple_blist_node_set_string(PurpleBlistNode* node, const char *key, const char *data)
 {
 	PurpleValue *value;
+	PurpleBlistUiOps *ops;
 
 	g_return_if_fail(node != NULL);
 	g_return_if_fail(node->settings != NULL);
@@ -2945,7 +3004,9 @@
 
 	g_hash_table_replace(node->settings, g_strdup(key), value);
 
-	purple_blist_schedule_save();
+	ops = purple_blist_get_ui_ops();
+	if (ops && ops->save_node)
+		ops->save_node(node);
 }
 
 const char *
@@ -2999,7 +3060,31 @@
 void
 purple_blist_set_ui_ops(PurpleBlistUiOps *ops)
 {
+	gboolean overrode = FALSE;
 	blist_ui_ops = ops;
+
+	if (!ops)
+		return;
+
+	if (!ops->save_node) {
+		ops->save_node = purple_blist_save_node;
+		overrode = TRUE;
+	}
+	if (!ops->remove_node) {
+		ops->remove_node = purple_blist_save_node;
+		overrode = TRUE;
+	}
+	if (!ops->save_account) {
+		ops->save_account = purple_blist_save_account;
+		overrode = TRUE;
+	}
+
+	if (overrode && (ops->save_node    != purple_blist_save_node ||
+	                 ops->remove_node  != purple_blist_save_node ||
+	                 ops->save_account != purple_blist_save_account)) {
+		purple_debug_warning("blist", "Only some of the blist saving UI ops "
+				"were overridden. This probably is not what you want!\n");
+	}
 }
 
 PurpleBlistUiOps *
--- a/libpurple/blist.h	Mon Jul 27 05:09:21 2009 +0000
+++ b/libpurple/blist.h	Mon Jul 27 05:20:52 2009 +0000
@@ -216,10 +216,49 @@
 							 const char *alias, const char *name);
 	void (*request_add_group)(void);
 
+	/**
+	 * This is called when a node has been modified and should be saved.
+	 *
+	 * Implementation of this UI op is OPTIONAL. If not implemented, it will
+	 * be set to a fallback function that saves data to blist.xml like in
+	 * previous libpurple versions.
+	 *
+	 * @attrib node    The node which has been modified.
+	 *
+	 * @since 2.6.0.
+	 */
+	void (*save_node)(PurpleBlistNode *node);
+
+	/**
+	 * Called when a node is about to be removed from the buddy list.
+	 * The UI op should update the relevant data structures to remove this
+	 * node (for example, removing a buddy from the group this node is in).
+	 *
+	 * Implementation of this UI op is OPTIONAL. If not implemented, it will
+	 * be set to a fallback function that saves data to blist.xml like in
+	 * previous libpurple versions.
+	 *
+	 * @attrib node  The node which has been modified.
+	 * @since 2.6.0.
+	 */
+	void (*remove_node)(PurpleBlistNode *node);
+
+	/**
+	 * Called to save all the data for an account. If the UI sets this,
+	 * the callback must save the privacy and buddy list data for an account.
+	 * If the account is NULL, save the data for all accounts.
+	 *
+	 * Implementation of this UI op is OPTIONAL. If not implemented, it will
+	 * be set to a fallback function that saves data to blist.xml like in
+	 * previous libpurple versions.
+	 *
+	 * @attrib account  The account whose data to save. If NULL, save all data
+	 *                  for all accounts.
+	 * @since 2.6.0.
+	 */
+	void (*save_account)(PurpleAccount *account);
+
 	void (*_purple_reserved1)(void);
-	void (*_purple_reserved2)(void);
-	void (*_purple_reserved3)(void);
-	void (*_purple_reserved4)(void);
 };
 
 #ifdef __cplusplus
--- a/libpurple/privacy.c	Mon Jul 27 05:09:21 2009 +0000
+++ b/libpurple/privacy.c	Mon Jul 27 05:20:52 2009 +0000
@@ -35,6 +35,7 @@
 	GSList *l;
 	char *name;
 	PurpleBuddy *buddy;
+	PurpleBlistUiOps *blist_ops;
 
 	g_return_val_if_fail(account != NULL, FALSE);
 	g_return_val_if_fail(who     != NULL, FALSE);
@@ -62,7 +63,9 @@
 	if (privacy_ops != NULL && privacy_ops->permit_added != NULL)
 		privacy_ops->permit_added(account, who);
 
-	purple_blist_schedule_save();
+	blist_ops = purple_blist_get_ui_ops();
+	if (blist_ops != NULL && blist_ops->save_account != NULL)
+		blist_ops->save_account(account);
 
 	/* This lets the UI know a buddy has had its privacy setting changed */
 	buddy = purple_find_buddy(account, name);
@@ -81,6 +84,7 @@
 	const char *name;
 	PurpleBuddy *buddy;
 	char *del;
+	PurpleBlistUiOps *blist_ops;
 
 	g_return_val_if_fail(account != NULL, FALSE);
 	g_return_val_if_fail(who     != NULL, FALSE);
@@ -109,7 +113,9 @@
 	if (privacy_ops != NULL && privacy_ops->permit_removed != NULL)
 		privacy_ops->permit_removed(account, who);
 
-	purple_blist_schedule_save();
+	blist_ops = purple_blist_get_ui_ops();
+	if (blist_ops != NULL && blist_ops->save_account != NULL)
+		blist_ops->save_account(account);
 
 	buddy = purple_find_buddy(account, name);
 	if (buddy != NULL) {
@@ -127,6 +133,7 @@
 	GSList *l;
 	char *name;
 	PurpleBuddy *buddy;
+	PurpleBlistUiOps *blist_ops;
 
 	g_return_val_if_fail(account != NULL, FALSE);
 	g_return_val_if_fail(who     != NULL, FALSE);
@@ -154,7 +161,9 @@
 	if (privacy_ops != NULL && privacy_ops->deny_added != NULL)
 		privacy_ops->deny_added(account, who);
 
-	purple_blist_schedule_save();
+	blist_ops = purple_blist_get_ui_ops();
+	if (blist_ops != NULL && blist_ops->save_account != NULL)
+		blist_ops->save_account(account);
 
 	buddy = purple_find_buddy(account, name);
 	if (buddy != NULL) {
@@ -172,6 +181,7 @@
 	const char *normalized;
 	char *name;
 	PurpleBuddy *buddy;
+	PurpleBlistUiOps *blist_ops;
 
 	g_return_val_if_fail(account != NULL, FALSE);
 	g_return_val_if_fail(who     != NULL, FALSE);
@@ -205,7 +215,10 @@
 	}
 
 	g_free(name);
-	purple_blist_schedule_save();
+
+	blist_ops = purple_blist_get_ui_ops();
+	if (blist_ops != NULL && blist_ops->save_account != NULL)
+		blist_ops->save_account(account);
 
 	return TRUE;
 }