changeset 11249:b4b1be482b4e

[gaim-migrate @ 13418] sf patch #1235519, from Sadrul Habib Chowdhury This is a pretty big patch that makes Gaim correctly save and restore the current status (away/available, away message, available message, invisible, etc). The GaimGtkStatusBoxWidget thing I think defaults to "Available" every time its created, which overrides the setting that was saved to the XML file. So that still needs to be fixed before this will really work. Anyway, mad props to Sadrul for putting up with my requests on this patch committer: Tailor Script <tailor@pidgin.im>
author Mark Doliner <mark@kingant.net>
date Sat, 13 Aug 2005 05:22:09 +0000
parents a2eababc78a8
children 4e25fb6678bd
files plugins/perl/common/Status.xs src/account.c src/account.h src/status.c src/status.h
diffstat 5 files changed, 256 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- a/plugins/perl/common/Status.xs	Sat Aug 13 03:55:07 2005 +0000
+++ b/plugins/perl/common/Status.xs	Sat Aug 13 05:22:09 2005 +0000
@@ -218,7 +218,7 @@
 	Gaim::StatusAttr attr
 
 Gaim::Value
-gaim_status_attr_get_value_type(attr)
+gaim_status_attr_get_value(attr)
 	Gaim::StatusAttr attr
 
 Gaim::StatusAttr
--- a/src/account.c	Sat Aug 13 03:55:07 2005 +0000
+++ b/src/account.c	Sat Aug 13 05:22:09 2005 +0000
@@ -119,9 +119,102 @@
 }
 
 static xmlnode *
+status_attr_to_xmlnode(const GaimStatus *status, const GaimStatusType *type, const GaimStatusAttr *attr)
+{
+	xmlnode *node;
+	const char *id;
+	char *value = NULL;
+	GaimStatusAttr *default_attr;
+	GaimValue *default_value;
+	GaimType attr_type;
+	GaimValue *attr_value;
+
+	id = gaim_status_attr_get_id(attr);
+	g_return_val_if_fail(id, NULL);
+
+	attr_value = gaim_status_get_attr_value(status, id);
+	g_return_val_if_fail(attr_value, NULL);
+	attr_type = gaim_value_get_type(attr_value);
+
+	/*
+	 * If attr_value is a different type than it should be
+	 * then don't write it to the file.
+	 */
+	default_attr = gaim_status_type_get_attr(type, id);
+	default_value = gaim_status_attr_get_value(default_attr);
+	if (attr_type != gaim_value_get_type(default_value))
+		return NULL;
+
+	/*
+	 * If attr_value is the same as the default for this status
+	 * then there is no need to write it to the file.
+	 */
+	if (attr_type == GAIM_TYPE_STRING)
+	{
+		const char *string_value = gaim_value_get_string(attr_value);
+		const char *default_string_value = gaim_value_get_string(default_value);
+		if (((string_value == NULL) && (default_string_value == NULL)) ||
+			((string_value != NULL) && (default_string_value != NULL) &&
+			 !strcmp(string_value, default_string_value)))
+			return NULL;
+		value = g_strdup(gaim_value_get_string(attr_value));
+	}
+	else if (attr_type == GAIM_TYPE_INT)
+	{
+		int int_value = gaim_value_get_int(attr_value);
+		if (int_value == gaim_value_get_int(default_value))
+			return NULL;
+		value = g_strdup_printf("%d", int_value);
+	}
+	else if (attr_type == GAIM_TYPE_BOOLEAN)
+	{
+		gboolean boolean_value = gaim_value_get_boolean(attr_value);
+		if (boolean_value == gaim_value_get_boolean(default_value))
+			return NULL;
+		value = g_strdup(boolean_value ?
+								"true" : "false");
+	}
+	else
+	{
+		return NULL;
+	}
+
+	g_return_val_if_fail(value, NULL);
+
+	node = xmlnode_new("attribute");
+
+	xmlnode_set_attrib(node, "id", id);
+	xmlnode_set_attrib(node, "value", value);
+
+	g_free(value);
+
+	return node;
+}
+
+static xmlnode *
+status_attrs_to_xmlnode(const GaimStatus *status)
+{
+	GaimStatusType *type = gaim_status_get_type(status);
+	xmlnode *node, *child;
+	const GList *attrs, *attr;
+
+	node = xmlnode_new("attributes");
+
+	attrs = gaim_status_type_get_attrs(type);
+	for (attr = attrs; attr != NULL; attr = attr->next)
+	{
+		child = status_attr_to_xmlnode(status, type, (const GaimStatusAttr *)attr->data);
+		if (child)
+			xmlnode_insert_child(node, child);
+	}
+
+	return node;
+}
+
+static xmlnode *
 status_to_xmlnode(const GaimStatus *status)
 {
-	xmlnode *node;
+	xmlnode *node, *child;
 
 	node = xmlnode_new("status");
 	xmlnode_set_attrib(node, "type", gaim_status_get_id(status));
@@ -129,7 +222,8 @@
 		xmlnode_set_attrib(node, "name", gaim_status_get_name(status));
 	xmlnode_set_attrib(node, "active", gaim_status_is_active(status) ? "true" : "false");
 
-	/* QQQ: Need to save status->attr_values */
+	child = status_attrs_to_xmlnode(status);
+	xmlnode_insert_child(node, child);
 
 	return node;
 }
@@ -398,12 +492,59 @@
 	}
 }
 
+static GList *
+parse_status_attrs(xmlnode *node, GaimStatus *status)
+{
+	GList *list = NULL;
+	xmlnode *child;
+	GaimValue *attr_value;
+
+	for (child = xmlnode_get_child(node, "attribute"); child != NULL;
+			child = xmlnode_get_next_twin(child))
+	{
+		const char *id = xmlnode_get_attrib(child, "id");
+		const char *value = xmlnode_get_attrib(child, "value");
+
+		if (!id || !*id || !value || !*value)
+			continue;
+
+		attr_value = gaim_status_get_attr_value(status, id);
+		if (!attr_value)
+			continue;
+
+		list = g_list_append(list, (char *)id);
+
+		switch (gaim_value_get_type(attr_value))
+		{
+			case GAIM_TYPE_STRING:
+				list = g_list_append(list, (char *)value);
+				break;
+			case GAIM_TYPE_INT:
+			case GAIM_TYPE_BOOLEAN:
+			{
+				int v;
+				if (sscanf(value, "%d", &v) == 1)
+					list = g_list_append(list, GINT_TO_POINTER(v));
+				else
+					list = g_list_remove(list, id);
+				break;
+			}
+			default:
+				break;
+		}
+	}
+
+	return list;
+}
+
 static void
 parse_status(xmlnode *node, GaimAccount *account)
 {
 	gboolean active = FALSE;
 	const char *data;
 	const char *type;
+	xmlnode *child;
+	GList *attrs = NULL;
 
 	/* Get the active/inactive state */
 	data = xmlnode_get_attrib(node, "active");
@@ -421,10 +562,17 @@
 	if (type == NULL)
 		return;
 
-	/* QQQ: Need to read attributes into a vargs */
+	/* Read attributes into a GList */
+	child = xmlnode_get_child(node, "attributes");
+	if (child != NULL)
+	{
+		attrs = parse_status_attrs(child,
+						gaim_account_get_status(account, type));
+	}
 
-	/* QQQ: This needs to do a better job of adding attributes and stuff */
-	gaim_account_set_status_vargs(account, type, active, NULL);
+	gaim_account_set_status_list(account, type, active, attrs);
+
+	g_list_free(attrs);
 }
 
 static void
@@ -1162,6 +1310,27 @@
 gaim_account_set_status_vargs(GaimAccount *account, const char *status_id,
 							  gboolean active, va_list args)
 {
+	GList *attrs = NULL;
+	const gchar *id;
+	gpointer data;
+
+	if (args != NULL)
+	{
+		while ((id = va_arg(args, const char *)) != NULL)
+		{
+			attrs = g_list_append(attrs, (char *)id);
+			data = va_arg(args, void *);
+			attrs = g_list_append(attrs, data);
+		}
+	}
+	gaim_account_set_status_list(account, status_id, active, attrs);
+	g_list_free(attrs);
+}
+
+void
+gaim_account_set_status_list(GaimAccount *account, const char *status_id,
+							 gboolean active, GList *attrs)
+{
 	GaimStatus *status;
 
 	g_return_if_fail(account   != NULL);
@@ -1181,7 +1350,7 @@
 	}
 
 	if (active || gaim_status_is_independent(status))
-		gaim_status_set_active_with_attrs(status, active, args);
+		gaim_status_set_active_with_attrs_list(status, active, attrs);
 
 	/*
 	 * Our current statuses are saved to accounts.xml (so that when we
--- a/src/account.h	Sat Aug 13 03:55:07 2005 +0000
+++ b/src/account.h	Sat Aug 13 05:22:09 2005 +0000
@@ -274,7 +274,8 @@
 
 /**
  * Activates or deactivates a status.  All changes to the statuses of
- * an account go through this function or gaim_account_set_status_vargs.
+ * an account go through this function or gaim_account_set_status_vargs
+ * or gaim_account_set_status_list.
  *
  * Only independent statuses can be deactivated with this. To deactivate
  * an exclusive status, activate a different (and exclusive?) status.
@@ -291,7 +292,8 @@
 
 /**
  * Activates or deactivates a status.  All changes to the statuses of
- * an account go through this function or gaim_account_set_status.
+ * an account go through this function or gaim_account_set_status or
+ * gaim_account_set_status_list.
  *
  * Only independent statuses can be deactivated with this. To deactivate
  * an exclusive status, activate a different (and exclusive?) status.
@@ -306,6 +308,23 @@
 								   gboolean active, va_list args);
 
 /**
+ * Activates or deactivates a status.  All changes to the statuses of
+ * an account go through this function or gaim_account_set_status or
+ * gaim_account_set_status_vargs.
+ *
+ * Only independent statuses can be deactivated with this. To deactivate
+ * an exclusive status, activate a different (and exclusive?) status.
+ *
+ * @param account   The account.
+ * @param status_id The ID of the status.
+ * @param active    The active state.
+ * @param attrs		A list of attributes in key/value pairs
+ */
+void gaim_account_set_status_list(GaimAccount *account,
+								  const char *status_id,
+								  gboolean active, GList *attrs);
+
+/**
  * Clears all protocol-specific settings on an account.
  *
  * @param account The account.
--- a/src/status.c	Sat Aug 13 03:55:07 2005 +0000
+++ b/src/status.c	Sat Aug 13 05:22:09 2005 +0000
@@ -69,7 +69,7 @@
 
 	gboolean idle;
 	time_t idle_time;
- 	time_t login_time;
+	time_t login_time;
 
 	unsigned int warning_level;
 
@@ -547,7 +547,7 @@
 }
 
 GaimValue *
-gaim_status_attr_get_value_type(const GaimStatusAttr *attr)
+gaim_status_attr_get_value(const GaimStatusAttr *attr)
 {
 	g_return_val_if_fail(attr != NULL, NULL);
 
@@ -580,7 +580,7 @@
 	for (l = gaim_status_type_get_attrs(status_type); l != NULL; l = l->next)
 	{
 		GaimStatusAttr *attr = (GaimStatusAttr *)l->data;
-		GaimValue *value = gaim_status_attr_get_value_type(attr);
+		GaimValue *value = gaim_status_attr_get_value(attr);
 		GaimValue *new_value = gaim_value_dup(value);
 
 		g_hash_table_insert(status->attr_values,
@@ -747,9 +747,36 @@
 	gaim_status_set_active_with_attrs(status, active, NULL);
 }
 
+/*
+ * This used to parse the va_list directly, but now it creates a GList
+ * and passes it to gaim_status_set_active_with_attrs_list().  That
+ * function was created because accounts.c needs to pass a GList of
+ * attributes to the status API.
+ */
 void
 gaim_status_set_active_with_attrs(GaimStatus *status, gboolean active, va_list args)
 {
+	GList *attrs = NULL;
+	const gchar *id;
+	gpointer data;
+
+	if (args != NULL)
+	{
+		while ((id = va_arg(args, const char *)) != NULL)
+		{
+			attrs = g_list_append(attrs, (char *)id);
+			data = va_arg(args, void *);
+			attrs = g_list_append(attrs, data);
+		}
+	}
+	gaim_status_set_active_with_attrs_list(status, active, attrs);
+	g_list_free(attrs);
+}
+
+void
+gaim_status_set_active_with_attrs_list(GaimStatus *status, gboolean active,
+									   const GList *attrs)
+{
 	gboolean changed = FALSE;
 	const gchar *id;
 
@@ -771,23 +798,26 @@
 	status->active = active;
 
 	/* Set any attributes */
-	if (args != NULL)
-	while ((id = va_arg(args, const char *)) != NULL)
+	while (attrs)
 	{
 		GaimValue *value;
+
+		id = attrs->data;
+		attrs = attrs->next;
 		value = gaim_status_get_attr_value(status, id);
 		if (value == NULL)
 		{
 			gaim_debug_warning("status", "The attribute \"%s\" on the status \"%s\" is "
 							   "not supported.\n", id, status->type->name);
 			/* Skip over the data and move on to the next attribute */
-			va_arg(args, void *);
+			attrs = attrs->next;
 			continue;
 		}
 
 		if (value->type == GAIM_TYPE_STRING)
 		{
-			const gchar *string_data = va_arg(args, const char *);
+			const gchar *string_data = attrs->data;
+			attrs = attrs->next;
 			if (((string_data == NULL) && (value->data.string_data == NULL)) ||
 				((string_data != NULL) && (value->data.string_data != NULL) &&
 				!strcmp(string_data, value->data.string_data)))
@@ -799,7 +829,8 @@
 		}
 		else if (value->type == GAIM_TYPE_INT)
 		{
-			int int_data = va_arg(args, int);
+			int int_data = (int)attrs->data;
+			attrs = attrs->next;
 			if (int_data == value->data.int_data)
 				continue;
 			gaim_status_set_attr_int(status, id, int_data);
@@ -807,7 +838,8 @@
 		}
 		else if (value->type == GAIM_TYPE_BOOLEAN)
 		{
-			gboolean boolean_data = va_arg(args, gboolean);
+			gboolean boolean_data = (gboolean)attrs->data;
+			attrs = attrs->next;
 			if (boolean_data == value->data.boolean_data)
 				continue;
 			gaim_status_set_attr_int(status, id, boolean_data);
@@ -816,13 +848,12 @@
 		else
 		{
 			/* We don't know what the data is--skip over it */
-			va_arg(args, void *);
+			attrs = attrs->next;
 		}
 	}
 
 	if (!changed)
 		return;
-
 	status_has_changed(status);
 }
 
--- a/src/status.h	Sat Aug 13 03:55:07 2005 +0000
+++ b/src/status.h	Sat Aug 13 05:22:09 2005 +0000
@@ -437,13 +437,13 @@
 const char *gaim_status_attr_get_name(const GaimStatusAttr *attr);
 
 /**
- * Returns the value type of a status attribute.
+ * Returns the value of a status attribute.
  *
  * @param attr The status attribute.
  *
- * @return The status attribute's value type.
+ * @return The status attribute's value.
  */
-GaimValue *gaim_status_attr_get_value_type(const GaimStatusAttr *attr);
+GaimValue *gaim_status_attr_get_value(const GaimStatusAttr *attr);
 
 /*@}*/
 
@@ -496,6 +496,20 @@
 									   va_list args);
 
 /**
+ * Sets whether or not a status is active.
+ *
+ * This should only be called by the account, conversation, and buddy APIs.
+ *
+ * @param status The status.
+ * @param active The active state.
+ * @param list   A list of attributes to set on the status.  This list is
+ *               composed of key/value pairs, where each key is a valid
+ *               attribute name for this GaimStatusType.
+ */
+void gaim_status_set_active_with_attrs_list(GaimStatus *status, gboolean active,
+											const GList *attrs);
+
+/**
  * Sets the boolean value of an attribute in a status with the specified ID.
  *
  * @param status The status.