changeset 9787:904b757835ca

[gaim-migrate @ 10655] after an utter failure to get comments on this since it was updated, and thinking that the functionality is worth having, i present to you: " This is a patch to blist.c and blist.h to modify the GaimBuddy structure to add a field for flags. It also adds a single flag GAIM_BUDDY_NO_SAVE, which can be used to indicate that a particular buddy should not be saved to file. This will be particularly useful for prpls with dynamic group support (which I am working on adding to Meanwhile), such as Oscar's recent buddies group. I used a negative flag (NO_SAVE rather than SAVE) because the default should be for saving to happen, and I didn't want to have to initiate the buddy with a save flag set. To counteract this, there is a macro called GAIM_BUDDY_SHOULD_SAVE which checks for the absense of the flag. Woo-hoo double negative!! The beefy part of this patch also factors out the deeply nested loops of the saving code into separate functions. This code also fixes a minor possible bug wherein when saving only a particular account, a group could be written containing empty contacts (due to checking for the specific account only at the group and buddy levels) Here's a version that places the flags field in the BlistNode, and checks for it at each stage (group, chat, contact, buddy). It didn't erase my buddy list when I tried it, so that's nice at least." --Christopher (siege) O'Brien committer: Tailor Script <tailor@pidgin.im>
author Luke Schierer <lschiere@pidgin.im>
date Fri, 20 Aug 2004 03:40:33 +0000
parents 3e7e294f56f3
children 1e9ecca6c97e
files src/blist.c src/blist.h
diffstat 2 files changed, 207 insertions(+), 97 deletions(-) [+]
line wrap: on
line diff
--- a/src/blist.c	Thu Aug 19 22:48:27 2004 +0000
+++ b/src/blist.c	Fri Aug 20 03:40:33 2004 +0000
@@ -918,6 +918,26 @@
 	return gaim_buddy_get_alias(contact->priority);
 }
 
+gboolean gaim_contact_on_account(GaimContact *c, GaimAccount *account)
+{
+	GaimBlistNode *bnode, *cnode = (GaimBlistNode *) c;
+
+	g_return_val_if_fail(c != NULL, FALSE);
+	g_return_val_if_fail(account != NULL, FALSE);
+
+	for (bnode = cnode->child; bnode; bnode = bnode->next) {
+		GaimBuddy *buddy;
+
+		if (! GAIM_BLIST_NODE_IS_BUDDY(bnode))
+			continue;
+
+		buddy = (GaimBuddy *)bnode;
+		if (buddy->account == account)
+			return TRUE;
+	}
+	return FALSE;
+}
+
 GaimGroup *gaim_group_new(const char *name)
 {
 	GaimBlistUiOps *ops = gaim_blist_get_ui_ops();
@@ -1729,17 +1749,11 @@
 
 gboolean gaim_group_on_account(GaimGroup *g, GaimAccount *account)
 {
-	GaimBlistNode *cnode, *bnode;
+	GaimBlistNode *cnode;
 	for (cnode = ((GaimBlistNode *)g)->child; cnode; cnode = cnode->next) {
 		if (GAIM_BLIST_NODE_IS_CONTACT(cnode)) {
-			for (bnode = cnode->child; bnode; bnode = bnode->next) {
-				if (GAIM_BLIST_NODE_IS_BUDDY(bnode)) {
-					GaimBuddy *buddy = (GaimBuddy *)bnode;
-					if ((!account && gaim_account_is_connected(buddy->account))
-							|| buddy->account == account)
-						return TRUE;
-				}
-			}
+			if(gaim_contact_on_account((GaimContact *) cnode, account))
+				return TRUE;
 		} else if (GAIM_BLIST_NODE_IS_CHAT(cnode)) {
 			GaimChat *chat = (GaimChat *)cnode;
 			if ((!account && gaim_account_is_connected(chat->account))
@@ -2171,111 +2185,187 @@
 	g_free(acct_name);
 }
 
+
+/* check for flagging and account exclusion on buddy */
+static gboolean blist_buddy_should_save(GaimAccount *exp_acct, GaimBuddy *buddy)
+{
+	if (! GAIM_BLIST_NODE_SHOULD_SAVE((GaimBlistNode *) buddy))
+		return FALSE;
+
+	if (exp_acct && buddy->account != exp_acct)
+		return FALSE;
+
+	return TRUE;
+}
+
+
+static void blist_write_buddy(FILE *file, GaimAccount *exp_acct, GaimBuddy *buddy)
+{
+	if (blist_buddy_should_save(exp_acct, buddy))
+		print_buddy(file, buddy);
+}
+
+
+/* check for flagging and account exclusion on contact and all members */
+static gboolean blist_contact_should_save(GaimAccount *exp_acct, GaimContact *contact)
+{
+	GaimBlistNode *bnode, *cnode = (GaimBlistNode *) contact;
+
+	if (! GAIM_BLIST_NODE_SHOULD_SAVE(cnode))
+		return FALSE;
+
+	for (bnode = cnode->child; bnode; bnode = bnode->next) {
+		if (! GAIM_BLIST_NODE_IS_BUDDY(bnode))
+			continue;
+
+		if (blist_buddy_should_save(exp_acct, (GaimBuddy *) bnode))
+			return TRUE;
+	}
+	
+	return FALSE;
+}
+
+
+static void blist_write_contact(FILE *file, GaimAccount *exp_acct, GaimContact *contact)
+{
+	GaimBlistNode *bnode, *cnode = (GaimBlistNode *) contact;
+
+	if (! blist_contact_should_save(exp_acct, contact))
+		return;
+
+	fprintf(file, "\t\t\t<contact");
+	if (contact->alias) {
+		char *alias = g_markup_escape_text(contact->alias, -1);
+		fprintf(file, " alias=\"%s\"", alias);
+		g_free(alias);
+	}
+	fprintf(file, ">\n");
+
+	for (bnode = cnode->child; bnode; bnode = bnode->next) {
+		if (GAIM_BLIST_NODE_IS_BUDDY(bnode)) {
+			blist_write_buddy(file, exp_acct, (GaimBuddy *) bnode);
+		}
+	}
+
+	g_hash_table_foreach(cnode->settings, blist_print_cnode_settings, file);
+	fprintf(file, "\t\t\t</contact>\n");
+}
+
+
+static void blist_write_chat(FILE *file, GaimAccount *exp_acct, GaimChat *chat)
+{
+	char *acct_name;
+
+	if (! GAIM_BLIST_NODE_SHOULD_SAVE((GaimBlistNode *) chat))
+		return;
+
+	if (exp_acct && chat->account != exp_acct)
+		return;
+	
+	acct_name = g_markup_escape_text(chat->account->username, -1);
+	fprintf(file, "\t\t\t<chat proto=\"%s\" account=\"%s\">\n",
+			gaim_account_get_protocol_id(chat->account), acct_name);
+	g_free(acct_name);
+
+	if (chat->alias) {
+		char *chat_alias = g_markup_escape_text(chat->alias, -1);
+		fprintf(file, "\t\t\t\t<alias>%s</alias>\n", chat_alias);
+		g_free(chat_alias);
+	}
+
+	g_hash_table_foreach(chat->components, blist_print_chat_components, file);
+	g_hash_table_foreach(chat->node.settings, blist_print_cnode_settings, file);
+
+	fprintf(file, "\t\t\t</chat>\n");
+}
+
+
+static void blist_write_group(FILE *file, GaimAccount *exp_acct, GaimGroup *group)
+{
+	GaimBlistNode *cnode, *gnode = (GaimBlistNode *) group;
+	char *group_name;
+
+	if (! GAIM_BLIST_NODE_SHOULD_SAVE(gnode))
+		return;
+
+	if (exp_acct && ! gaim_group_on_account(group, exp_acct))
+		return; 
+
+	group_name = g_markup_escape_text(group->name, -1);
+	fprintf(file, "\t\t<group name=\"%s\">\n", group_name);
+	g_free(group_name);
+
+	g_hash_table_foreach(group->node.settings,
+			blist_print_group_settings, file);
+
+	for (cnode = gnode->child; cnode; cnode = cnode->next) {
+		if (GAIM_BLIST_NODE_IS_CONTACT(cnode)) {
+			blist_write_contact(file, exp_acct, (GaimContact *) cnode);
+		} else if (GAIM_BLIST_NODE_IS_CHAT(cnode)) {
+			blist_write_chat(file, exp_acct, (GaimChat *) cnode);
+		}
+	}
+
+	fprintf(file, "\t\t</group>\n");
+}
+
+
+static void blist_write_privacy_account(FILE *file, GaimAccount *exp_acct, GaimAccount *account)
+{
+	char *acct_name;
+	GSList *buds;
+
+	if(exp_acct && exp_acct != account)
+		return;
+
+	acct_name = g_markup_escape_text(account->username, -1);
+	fprintf(file, "\t\t<account proto=\"%s\" name=\"%s\" mode=\"%d\">\n",
+			gaim_account_get_protocol_id(account),
+			acct_name, account->perm_deny);
+	g_free(acct_name);
+
+	for (buds = account->permit; buds; buds = buds->next) {
+		char *bud_name = g_markup_escape_text(buds->data, -1);
+		fprintf(file, "\t\t\t<permit>%s</permit>\n", bud_name);
+		g_free(bud_name);
+	}
+
+	for (buds = account->deny; buds; buds = buds->next) {
+		char *bud_name = g_markup_escape_text(buds->data, -1);
+		fprintf(file, "\t\t\t<block>%s</block>\n", bud_name);
+		g_free(bud_name);
+	}
+
+	fprintf(file, "\t\t</account>\n");
+}
+
+
 static void gaim_blist_write(FILE *file, GaimAccount *exp_acct)
 {
 	GList *accounts;
-	GSList *buds;
-	GaimBlistNode *gnode, *cnode, *bnode;
+	GaimBlistNode *gnode;
+
 	fprintf(file, "<?xml version='1.0' encoding='UTF-8' ?>\n");
 	fprintf(file, "<gaim version=\"1\">\n");
 	fprintf(file, "\t<blist>\n");
 
 	for (gnode = gaimbuddylist->root; gnode; gnode = gnode->next) {
-		GaimGroup *group;
-
-		if (!GAIM_BLIST_NODE_IS_GROUP(gnode))
-			continue;
-
-		group = (GaimGroup *)gnode;
-		if (!exp_acct || gaim_group_on_account(group, exp_acct)) {
-			char *group_name = g_markup_escape_text(group->name, -1);
-			fprintf(file, "\t\t<group name=\"%s\">\n", group_name);
-			g_hash_table_foreach(group->node.settings,
-					blist_print_group_settings, file);
-			for (cnode = gnode->child; cnode; cnode = cnode->next) {
-				if (GAIM_BLIST_NODE_IS_CONTACT(cnode)) {
-					GaimContact *contact = (GaimContact*)cnode;
-					fprintf(file, "\t\t\t<contact");
-					if (contact->alias) {
-						char *alias = g_markup_escape_text(contact->alias, -1);
-						fprintf(file, " alias=\"%s\"", alias);
-						g_free(alias);
-					}
-					fprintf(file, ">\n");
-
-					for (bnode = cnode->child; bnode; bnode = bnode->next) {
-						if (GAIM_BLIST_NODE_IS_BUDDY(bnode)) {
-							GaimBuddy *buddy = (GaimBuddy *)bnode;
-							if (!exp_acct || buddy->account == exp_acct) {
-								print_buddy(file, buddy);
-							}
-						}
-					}
-
-					g_hash_table_foreach(cnode->settings,
-							blist_print_cnode_settings, file);
-
-					fprintf(file, "\t\t\t</contact>\n");
-				} else if (GAIM_BLIST_NODE_IS_CHAT(cnode)) {
-					GaimChat *chat = (GaimChat *)cnode;
-					if (!exp_acct || chat->account == exp_acct) {
-						char *acct_name = g_markup_escape_text(chat->account->username, -1);
-						fprintf(file, "\t\t\t<chat proto=\"%s\" account=\"%s\">\n",
-								gaim_account_get_protocol_id(chat->account),
-								acct_name);
-
-						if (chat->alias) {
-							char *chat_alias = g_markup_escape_text(chat->alias, -1);
-							fprintf(file, "\t\t\t\t<alias>%s</alias>\n", chat_alias);
-							g_free(chat_alias);
-						}
-						g_hash_table_foreach(chat->components,
-								blist_print_chat_components, file);
-						g_hash_table_foreach(chat->node.settings,
-								blist_print_cnode_settings, file);
-						fprintf(file, "\t\t\t</chat>\n");
-						g_free(acct_name);
-					}
-				}
-			}
-			fprintf(file, "\t\t</group>\n");
-			g_free(group_name);
-		}
+		if (GAIM_BLIST_NODE_IS_GROUP(gnode))
+			blist_write_group(file, exp_acct, (GaimGroup *) gnode);
 	}
 
 	fprintf(file, "\t</blist>\n");
 	fprintf(file, "\t<privacy>\n");
 
-	for (accounts = gaim_accounts_get_all();
-		accounts != NULL;
-		accounts = accounts->next) {
-
-		GaimAccount *account = accounts->data;
-		char *acct_name = g_markup_escape_text(account->username, -1);
-		if (!exp_acct || account == exp_acct) {
-			fprintf(file, "\t\t<account proto=\"%s\" name=\"%s\" "
-					"mode=\"%d\">\n", gaim_account_get_protocol_id(account),
-					acct_name, account->perm_deny);
-
-			for (buds = account->permit; buds; buds = buds->next) {
-				char *bud_name = g_markup_escape_text(buds->data, -1);
-				fprintf(file, "\t\t\t<permit>%s</permit>\n", bud_name);
-				g_free(bud_name);
-			}
-			for (buds = account->deny; buds; buds = buds->next) {
-				char *bud_name = g_markup_escape_text(buds->data, -1);
-				fprintf(file, "\t\t\t<block>%s</block>\n", bud_name);
-				g_free(bud_name);
-			}
-			fprintf(file, "\t\t</account>\n");
-		}
-		g_free(acct_name);
+	for (accounts = gaim_accounts_get_all(); accounts; accounts = accounts->next) {
+		blist_write_privacy_account(file, exp_acct, (GaimAccount *) accounts->data);
 	}
 
 	fprintf(file, "\t</privacy>\n");
 	fprintf(file, "</gaim>\n");
 }
 
+
 void gaim_blist_sync()
 {
 	FILE *file;
--- a/src/blist.h	Thu Aug 19 22:48:27 2004 +0000
+++ b/src/blist.h	Fri Aug 20 03:40:33 2004 +0000
@@ -74,6 +74,14 @@
 		((b)->present == GAIM_BUDDY_ONLINE || \
 		 (b)->present == GAIM_BUDDY_SIGNING_ON))
 
+typedef enum
+{
+	GAIM_BLIST_NODE_FLAG_NO_SAVE = 1,	/**< node should not be saved with the buddy list */
+} GaimBlistNodeFlags;
+
+#define GAIM_BLIST_NODE_HAS_FLAG(b, f) ((b)->flags & (f))
+#define GAIM_BLIST_NODE_SHOULD_SAVE(b) (! GAIM_BLIST_NODE_HAS_FLAG(b, GAIM_BLIST_NODE_FLAG_NO_SAVE))
+
 
 /**************************************************************************/
 /* Data Structures                                                        */
@@ -90,6 +98,7 @@
 	GaimBlistNode *child;               /**< The child of this node         */
 	GHashTable *settings;               /**< per-node settings              */
 	void          *ui_data;             /**< The UI can put data here.      */
+	GaimBlistNodeFlags flags;           /**< The buddy flags                */
 };
 
 /**
@@ -108,8 +117,8 @@
 	int uc;                                 /**< This is a cryptic bitmask that makes sense only to the prpl.  This will get changed */
 	void *proto_data;                       /**< This allows the prpl to associate whatever data it wants with a buddy */
 	GaimBuddyIcon *icon;                    /**< The buddy icon. */
-	GaimAccount *account;           /**< the account this buddy belongs to */
-	guint timer;							/**< The timer handle. */
+	GaimAccount *account;           	/**< the account this buddy belongs to */
+	guint timer;				/**< The timer handle. */
 };
 
 /**
@@ -493,6 +502,17 @@
 const char *gaim_contact_get_alias(GaimContact *contact);
 
 /**
+ * Determines whether an account owns any buddies in a given contact
+ *
+ * @param contact  The contact to search through.
+ * @param account  The account.
+ *
+ * @return TRUE if there are any buddies from account in the contact, or FALSE otherwise.
+ */
+gboolean gaim_contact_on_account(GaimContact *contact, GaimAccount *account);
+
+
+/**
  * Removes a buddy from the buddy list and frees the memory allocated to it.
  *
  * @param buddy   The buddy to be removed