# HG changeset patch # User Mark Doliner # Date 1123910529 0 # Node ID b4b1be482b4eb94307e2e30389248c9b62f016d2 # Parent a2eababc78a83919166f394f51239ae7f5de4b14 [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 diff -r a2eababc78a8 -r b4b1be482b4e plugins/perl/common/Status.xs --- 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 diff -r a2eababc78a8 -r b4b1be482b4e src/account.c --- 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 diff -r a2eababc78a8 -r b4b1be482b4e src/account.h --- 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. diff -r a2eababc78a8 -r b4b1be482b4e src/status.c --- 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); } diff -r a2eababc78a8 -r b4b1be482b4e src/status.h --- 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.