diff options
author | Jonny Lamb <jonny.lamb@collabora.co.uk> | 2009-08-26 13:05:44 +0100 |
---|---|---|
committer | Jonny Lamb <jonny.lamb@collabora.co.uk> | 2009-08-26 13:05:45 +0100 |
commit | 65f2c739ddbdfeb2ab9a4f0b38b4e7d906b9abcb (patch) | |
tree | e9c44fd630d082cef512456e071d75de95c62ea0 | |
parent | 07248b054fe4a78166de01d66029f3151b012890 (diff) | |
download | telepathy-mission-control-65f2c739ddbdfeb2ab9a4f0b38b4e7d906b9abcb.tar.gz |
mcd-account: refactored set_parameters to be async and iteratively set params
Signed-off-by: Jonny Lamb <jonny.lamb@collabora.co.uk>
-rw-r--r-- | src/mcd-account-connection.c | 28 | ||||
-rw-r--r-- | src/mcd-account-manager.c | 99 | ||||
-rw-r--r-- | src/mcd-account-priv.h | 24 | ||||
-rw-r--r-- | src/mcd-account.c | 976 | ||||
-rw-r--r-- | src/mcd-account.h | 17 |
5 files changed, 781 insertions, 363 deletions
diff --git a/src/mcd-account-connection.c b/src/mcd-account-connection.c index 37cbd869..ec119d7f 100644 --- a/src/mcd-account-connection.c +++ b/src/mcd-account-connection.c @@ -51,29 +51,37 @@ _mcd_account_connection_context_free (McdAccountConnectionContext *c) g_free (c); } -void -_mcd_account_connection_begin (McdAccount *account) +static void +connection_begin_dup_params_cb (McdAccount *account, GHashTable *params, + gpointer user_data) { McdAccountConnectionContext *ctx; - /* check whether a connection process is already ongoing */ - if (_mcd_account_get_connection_context (account) != NULL) - { - DEBUG ("already trying to connect"); - return; - } - /* get account params */ /* create dynamic params HT */ /* run the handlers */ ctx = g_malloc (sizeof (McdAccountConnectionContext)); ctx->i_filter = 0; - ctx->params = _mcd_account_dup_parameters (account); + + ctx->params = params; g_assert (ctx->params != NULL); _mcd_account_set_connection_context (account, ctx); mcd_account_connection_proceed (account, TRUE); } +void +_mcd_account_connection_begin (McdAccount *account) +{ + /* check whether a connection process is already ongoing */ + if (_mcd_account_get_connection_context (account) != NULL) + { + DEBUG ("already trying to connect"); + return; + } + + _mcd_account_dup_parameters (account, connection_begin_dup_params_cb, NULL); +} + void mcd_account_connection_proceed (McdAccount *account, gboolean success) { diff --git a/src/mcd-account-manager.c b/src/mcd-account-manager.c index 2bb85f61..84e5090d 100644 --- a/src/mcd-account-manager.c +++ b/src/mcd-account-manager.c @@ -115,6 +115,9 @@ typedef struct McdGetAccountCb callback; gpointer user_data; GDestroyNotify destroy; + + gboolean ok; + GError *error; } McdCreateAccountData; enum @@ -346,6 +349,9 @@ mcd_create_account_data_free (McdCreateAccountData *cad) g_hash_table_unref (cad->properties); } + if (G_UNLIKELY (cad->error)) + g_error_free (cad->error); + g_slice_free (McdCreateAccountData, cad); } @@ -408,44 +414,22 @@ create_account_with_properties_cb (McdAccountManager *account_manager, } static void -complete_account_creation (McdAccount *account, - const GError *cb_error, - gpointer user_data) +complete_account_creation_finish (McdAccount *account, gboolean valid, + gpointer user_data) { - McdCreateAccountData *cad = user_data; + McdCreateAccountData *cad = (McdCreateAccountData *) user_data; McdAccountManager *account_manager; - GError *error = NULL; - gboolean ok; account_manager = cad->account_manager; - if (G_UNLIKELY (cb_error)) - { - cad->callback (account_manager, account, cb_error, cad->user_data); - mcd_create_account_data_free (cad); - return; - } - - ok = _mcd_account_set_parameters (account, cad->parameters, NULL, NULL, - &error); - if (ok && cad->properties != NULL) + if (!valid) { - ok = set_new_account_properties (account, cad->properties, &error); - } - - if (ok) - { - add_account (account_manager, account); - - if (!mcd_account_check_validity (account)) - { - ok = FALSE; - g_set_error (&error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + cad->ok = FALSE; + g_set_error (&cad->error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, "The supplied CM parameters were not valid"); - } } - if (!ok) + if (!cad->ok) { mcd_account_delete (account, NULL, NULL); g_object_unref (account); @@ -454,15 +438,65 @@ complete_account_creation (McdAccount *account, mcd_account_manager_write_conf_async (account_manager, NULL, NULL); - cad->callback (account_manager, account, error, cad->user_data); - if (G_UNLIKELY (error)) - g_error_free (error); + if (cad->callback != NULL) + cad->callback (account_manager, account, cad->error, cad->user_data); mcd_create_account_data_free (cad); if (account != NULL) { g_object_unref (account); } + +} + +static void +complete_account_creation_set_cb (McdAccount *account, GPtrArray *not_yet, + const GError *set_error, gpointer user_data) +{ + McdCreateAccountData *cad = user_data; + McdAccountManager *account_manager; + cad->ok = (set_error == NULL); + + account_manager = cad->account_manager; + + if (cad->ok && cad->properties != NULL) + { + cad->ok = set_new_account_properties (account, cad->properties, &cad->error); + } + + if (cad->ok) + { + add_account (account_manager, account); + mcd_account_check_validity (account, complete_account_creation_finish, cad); + } + else + { + complete_account_creation_finish (account, TRUE, cad); + } + + g_ptr_array_foreach (not_yet, (GFunc) g_free, NULL); + g_ptr_array_free (not_yet, TRUE); +} + +static void +complete_account_creation (McdAccount *account, + const GError *cb_error, + gpointer user_data) +{ + McdCreateAccountData *cad = user_data; + McdAccountManager *account_manager; + + account_manager = cad->account_manager; + if (G_UNLIKELY (cb_error)) + { + cad->callback (account_manager, account, cb_error, cad->user_data); + mcd_create_account_data_free (cad); + return; + } + + _mcd_account_set_parameters (account, cad->parameters, NULL, + complete_account_creation_set_cb, + cad); } static gchar * @@ -566,6 +600,7 @@ _mcd_account_manager_create_account (McdAccountManager *account_manager, cad->callback = callback; cad->user_data = user_data; cad->destroy = destroy; + cad->error = NULL; _mcd_account_load (account, complete_account_creation, cad); } else diff --git a/src/mcd-account-priv.h b/src/mcd-account-priv.h index af4d130f..b5e2f39a 100644 --- a/src/mcd-account-priv.h +++ b/src/mcd-account-priv.h @@ -43,11 +43,17 @@ G_GNUC_INTERNAL void _mcd_account_maybe_autoconnect (McdAccount *account); G_GNUC_INTERNAL void _mcd_account_connect (McdAccount *account, GHashTable *params); -G_GNUC_INTERNAL gboolean _mcd_account_set_parameters (McdAccount *account, - GHashTable *params, - const gchar **unset, - GPtrArray *not_yet, - GError **error); + +typedef void (McdAccountSetParametersCb) (McdAccount *account, + GPtrArray *not_yet, + const GError *error, + gpointer user_data); + +G_GNUC_INTERNAL void _mcd_account_set_parameters (McdAccount *account, + GHashTable *params, + const gchar **unset, + McdAccountSetParametersCb callback, + gpointer user_data); G_GNUC_INTERNAL void _mcd_account_request_temporary_presence (McdAccount *self, TpConnectionPresenceType type, const gchar *status); @@ -152,7 +158,13 @@ void _mcd_account_set_connection_context (McdAccount *self, G_GNUC_INTERNAL void _mcd_account_connection_context_free (McdAccountConnectionContext *c); -G_GNUC_INTERNAL GHashTable *_mcd_account_dup_parameters (McdAccount *account); +typedef void (*McdAccountDupParametersCb) (McdAccount *account, + GHashTable *params, + gpointer user_data); + +G_GNUC_INTERNAL void _mcd_account_dup_parameters (McdAccount *account, + McdAccountDupParametersCb callback, + gpointer user_data); extern const McdDBusProp account_conditions_properties[]; diff --git a/src/mcd-account.c b/src/mcd-account.c index 9a3e5ab7..427b2a34 100644 --- a/src/mcd-account.c +++ b/src/mcd-account.c @@ -342,6 +342,14 @@ set_parameter (McdAccount *account, const gchar *name, const GValue *value, McdAccountPrivate *priv = account->priv; gchar key[MAX_KEY_LENGTH]; gchar buf[21]; /* enough for '-' + the 19 digits of 2**63 + '\0' */ + const TpConnectionManagerParam *param; + gboolean is_secret = FALSE; + + param = mcd_manager_get_protocol_param (priv->manager, + priv->protocol_name, name); + + if (param != NULL && param->flags & TP_CONN_MGR_PARAM_FLAG_SECRET) + is_secret = TRUE; g_snprintf (key, sizeof (key), "param-%s", name); @@ -428,138 +436,184 @@ out: } } -static gboolean -get_parameter (McdAccount *account, const gchar *name, GValue *value) +static GType mc_param_type (const TpConnectionManagerParam *param); + + +static void +get_parameter (McdAccount *account, const gchar *name, + McdAccountGetParameterCb callback, gpointer user_data) { McdAccountPrivate *priv = account->priv; gchar key[MAX_KEY_LENGTH]; + const TpConnectionManagerParam *param; + gboolean is_secret = FALSE; + GError *error = NULL; + GValue *value = NULL; + GType type; + + gchar *v_string = NULL; + gint64 v_int = 0; + guint64 v_uint = 0; + gboolean v_bool = FALSE; + double v_double = 0.0; + + param = mcd_manager_get_protocol_param (priv->manager, + priv->protocol_name, name); + + if (param != NULL && param->flags & TP_CONN_MGR_PARAM_FLAG_SECRET) + is_secret = TRUE; g_snprintf (key, sizeof (key), "param-%s", name); if (!g_key_file_has_key (priv->keyfile, priv->unique_name, key, NULL)) - return FALSE; + goto error; + + type = mc_param_type (param); - if (value) + switch (type) { - gchar *v_string = NULL; - gint64 v_int = 0; - guint64 v_uint = 0; - gboolean v_bool = FALSE; - double v_double = 0.0; + case G_TYPE_STRING: + v_string = g_key_file_get_string (priv->keyfile, priv->unique_name, + key, NULL); + value = tp_g_value_slice_new_take_string (v_string); + break; + + case G_TYPE_INT: + v_int = g_key_file_get_integer (priv->keyfile, priv->unique_name, + key, NULL); + value = tp_g_value_slice_new_int (v_int); + break; + + case G_TYPE_INT64: + v_int = tp_g_key_file_get_int64 (priv->keyfile, priv->unique_name, + key, NULL); + value = tp_g_value_slice_new_int64 (v_int); + break; - switch (G_VALUE_TYPE (value)) + case G_TYPE_UINT: + v_uint = tp_g_key_file_get_uint64 (priv->keyfile, + priv->unique_name, key, NULL); + + if (v_uint > 0xFFFFFFFFU) { - case G_TYPE_STRING: - v_string = g_key_file_get_string (priv->keyfile, priv->unique_name, - key, NULL); - g_value_take_string (value, v_string); - break; - - case G_TYPE_INT: - v_int = g_key_file_get_integer (priv->keyfile, priv->unique_name, - key, NULL); - g_value_set_int (value, v_int); - break; - - case G_TYPE_INT64: - v_int = tp_g_key_file_get_int64 (priv->keyfile, priv->unique_name, - key, NULL); - g_value_set_int64 (value, v_int); - break; - - case G_TYPE_UCHAR: - v_int = g_key_file_get_integer (priv->keyfile, priv->unique_name, - key, NULL); - - if (v_int < 0 || v_int > 0xFF) - { - return FALSE; - } + goto error; + } - g_value_set_uchar (value, v_int); - break; + value = tp_g_value_slice_new_uint (v_uint); + break; - case G_TYPE_UINT: - v_uint = tp_g_key_file_get_uint64 (priv->keyfile, - priv->unique_name, key, NULL); + case G_TYPE_UCHAR: + v_int = g_key_file_get_integer (priv->keyfile, priv->unique_name, + key, NULL); - if (v_uint > 0xFFFFFFFFU) - { - return FALSE; - } + if (v_int < 0 || v_int > 0xFF) + { + goto error; + } + value = tp_g_value_slice_new (G_TYPE_UCHAR); + g_value_set_uchar (value, v_int); + break; - g_value_set_uint (value, v_uint); - break; + case G_TYPE_UINT64: + v_uint = tp_g_key_file_get_uint64 (priv->keyfile, + priv->unique_name, key, NULL); - case G_TYPE_UINT64: - v_uint = tp_g_key_file_get_uint64 (priv->keyfile, - priv->unique_name, key, NULL); - g_value_set_uint64 (value, v_uint); - break; + value = tp_g_value_slice_new_uint64 (v_uint); + break; - case G_TYPE_BOOLEAN: - v_bool = g_key_file_get_boolean (priv->keyfile, priv->unique_name, - key, NULL); - g_value_set_boolean (value, v_bool); - break; + case G_TYPE_BOOLEAN: + v_bool = g_key_file_get_boolean (priv->keyfile, priv->unique_name, + key, NULL); - case G_TYPE_DOUBLE: - v_double = g_key_file_get_double (priv->keyfile, priv->unique_name, - key, NULL); - g_value_set_double (value, v_double); - break; + value = tp_g_value_slice_new_boolean (v_bool); + break; - default: - if (G_VALUE_HOLDS (value, G_TYPE_STRV)) - { - gchar **v = g_key_file_get_string_list (priv->keyfile, - priv->unique_name, key, - NULL, NULL); + case G_TYPE_DOUBLE: + v_double = g_key_file_get_double (priv->keyfile, priv->unique_name, + key, NULL); - g_value_take_boxed (value, v); - } - else if (G_VALUE_HOLDS (value, DBUS_TYPE_G_OBJECT_PATH)) - { - v_string = g_key_file_get_string (priv->keyfile, - priv->unique_name, key, - NULL); + value = tp_g_value_slice_new_double (v_double); + break; - if (!tp_dbus_check_valid_object_path (v_string, NULL)) - { - g_free (v_string); - return FALSE; - } + default: + if (type == G_TYPE_STRV) + { + gchar **v = g_key_file_get_string_list (priv->keyfile, + priv->unique_name, key, + NULL, NULL); - g_value_take_boxed (value, v_string); - } - else + value = tp_g_value_slice_new_take_boxed (G_TYPE_STRV, v); + } + else if (type == DBUS_TYPE_G_OBJECT_PATH) + { + v_string = g_key_file_get_string (priv->keyfile, + priv->unique_name, key, + NULL); + + if (!tp_dbus_check_valid_object_path (v_string, NULL)) { - g_warning ("%s: skipping parameter %s, unknown type %s", - G_STRFUNC, name, G_VALUE_TYPE_NAME (value)); - return FALSE; + g_free (v_string); + goto error; } + + value = tp_g_value_slice_new_take_object_path (v_string); + } + else + { + g_warning ("%s: skipping parameter %s, unknown type %s", + G_STRFUNC, name, + value ? G_VALUE_TYPE_NAME (value) : "(null)"); + goto error; } } - return TRUE; + if (value != NULL) + { + if (callback != NULL) + callback (account, value, NULL, user_data); + tp_g_value_slice_free (value); + + return; + } + +error: + if (callback != NULL) + callback (account, NULL, error, user_data); + if (error != NULL) + g_error_free (error); } -static gboolean mcd_account_check_parameters (McdAccount *account); + +typedef void (*CheckParametersCb) (McdAccount *account, gboolean valid, + gpointer user_data); +static void mcd_account_check_parameters (McdAccount *account, + CheckParametersCb callback, gpointer user_data); + +static void +manager_ready_check_params_cb (McdAccount *account, + gboolean valid, + gpointer user_data) +{ + McdAccountPrivate *priv = account->priv; + + priv->valid = valid; + mcd_account_loaded (account); +} static void on_manager_ready (McdManager *manager, const GError *error, gpointer user_data) { McdAccount *account = MCD_ACCOUNT (user_data); - McdAccountPrivate *priv = account->priv; if (error) { DEBUG ("got error: %s", error->message); + mcd_account_loaded (account); } else { - priv->valid = mcd_account_check_parameters (account); + mcd_account_check_parameters (account, manager_ready_check_params_cb, + NULL); } - mcd_account_loaded (account); } static gboolean @@ -1122,10 +1176,16 @@ get_avatar (TpSvcDBusProperties *self, const gchar *name, GValue *value) static void get_parameters (TpSvcDBusProperties *self, const gchar *name, GValue *value) { - McdAccount *account = MCD_ACCOUNT (self); - GHashTable *parameters; + GHashTable *parameters = NULL; + + /* TODO FIXME RIGHT NOW: move to async dbus properties solution + * so we can call dup_parameters + * parameters = _mcd_account_dup_parameters (account); + * For now, just return an empty asv. + */ + parameters = g_hash_table_new_full (g_str_hash, g_str_equal, + NULL, (GDestroyNotify) tp_g_value_slice_free); - parameters = _mcd_account_dup_parameters (account); g_value_init (value, TP_HASH_TYPE_STRING_VARIANT_MAP); g_value_take_boxed (value, parameters); } @@ -1591,50 +1651,90 @@ account_remove (TpSvcAccount *svc, DBusGMethodInvocation *context) mcd_account_delete (self, account_remove_delete_cb, data); } -/* +/** * mcd_account_get_parameter: * @account: the #McdAccount. * @name: the parameter name. - * @value: a initialized #GValue to receive the parameter value, or %NULL. - * - * Get the @name parameter for @account. + * @callback: function to call with the value + * @user_data: data to pass to @callback * - * Returns: %TRUE if found, %FALSE otherwise. + * Get the @name parameter for @account, asynchronously. */ -static gboolean +static void mcd_account_get_parameter (McdAccount *account, const gchar *name, - GValue *value) + McdAccountGetParameterCb callback, + gpointer user_data) { - return MCD_ACCOUNT_GET_CLASS (account)->get_parameter (account, name, - value); + MCD_ACCOUNT_GET_CLASS (account)->get_parameter (account, name, + callback, user_data); } -static gboolean -mcd_account_check_parameters (McdAccount *account) +typedef struct +{ + McdAccount *account; + const TpConnectionManagerParam *param; + CheckParametersCb callback; + gpointer user_data; +} CheckParameterData; + +static void +check_parameters_get_param_cb (McdAccount *account, const GValue *value, + const GError *error, gpointer user_data) +{ + CheckParameterData *data = (CheckParameterData *) user_data; + const TpConnectionManagerParam *p; + + if ((account != NULL && value == NULL) || error != NULL) + { + data->callback (data->account, FALSE, data->user_data); + } + else + { + while (data->param->name != NULL + && !(data->param->flags & TP_CONN_MGR_PARAM_FLAG_REQUIRED)) + { + data->param++; + } + + if (data->param->name != NULL) + { + p = data->param++; + mcd_account_get_parameter (data->account, p->name, + check_parameters_get_param_cb, data); + } + else + { + data->callback (data->account, TRUE, data->user_data); + g_slice_free (CheckParameterData, data); + } + } +} + +static void +mcd_account_check_parameters (McdAccount *account, + CheckParametersCb callback, + gpointer user_data) { McdAccountPrivate *priv = account->priv; const TpConnectionManagerParam *param; - gboolean valid; + CheckParameterData *data; DEBUG ("called for %s", priv->unique_name); param = mcd_manager_get_parameters (priv->manager, priv->protocol_name); - if (!param) return FALSE; - valid = TRUE; - while (param->name != NULL) + if (!param) { - if (param->flags & TP_CONN_MGR_PARAM_FLAG_REQUIRED) - { - if (!mcd_account_get_parameter (account, param->name, NULL)) - { - DEBUG ("missing required parameter %s", param->name); - valid = FALSE; - break; - } - } - param++; + if (callback != NULL) + callback (account, FALSE, user_data); + return; } - return valid; + data = g_slice_new0 (CheckParameterData); + data->account = account; + data->param = param; + data->callback = callback; + data->user_data = user_data; + + check_parameters_get_param_cb (NULL, NULL, NULL, data); } /* @@ -1658,206 +1758,392 @@ _mcd_account_set_parameter (McdAccount *account, const gchar *name, callback, user_data); } +static GHashTable * +hash_table_copy (GHashTable *orig) +{ + GHashTable *dest; + + dest = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) tp_g_value_slice_free); + tp_g_hash_table_update (dest, orig, (GBoxedCopyFunc) g_strdup, + (GBoxedCopyFunc) tp_g_value_slice_dup); + return dest; +} + +typedef struct +{ + McdAccount *account; + GHashTable *params; + GHashTableIter iter; + gchar **unset; + gchar **unset_iter; + const TpConnectionManagerParam *param; + const GValue *new; + guint n_params; + GSList *dbus_properties; + GPtrArray *not_yet; + McdAccountSetParametersCb *callback; + gpointer user_data; +} SetParametersData; + +static void +set_parameters_data_free (SetParametersData *data) +{ + if (data->account != NULL) + g_object_unref (data->account); + + if (data->params != NULL) + g_hash_table_destroy (data->params); + + if (data->unset != NULL) + g_strfreev (data->unset); + + if (data->dbus_properties != NULL) + g_slist_free (data->dbus_properties); + + g_slice_free (SetParametersData, data); +} + +static void +set_parameters_finish (SetParametersData *data) +{ + McdAccountPrivate *priv = data->account->priv; + + if (mcd_account_get_connection_status (data->account) == + TP_CONNECTION_STATUS_CONNECTED) + { + GSList *list; + const gchar *name; + const GValue *value; + + for (list = data->dbus_properties; list != NULL; list = list->next) + { + name = list->data; + DEBUG ("updating parameter %s", name); + value = g_hash_table_lookup (data->params, name); + _mcd_connection_update_property (priv->connection, name, value); + } + } + + mcd_account_check_validity (data->account, NULL, NULL); + _mcd_account_maybe_autoconnect (data->account); + + if (data->callback != NULL) + { + data->callback (data->account, data->not_yet, NULL, data->user_data); + } + set_parameters_data_free (data); +} + +static void set_parameters_unset_single (McdAccount *account, + const GError *error, + gpointer user_data); + + +static void +set_parameters_unset_check_present (McdAccount *account, + const GValue *value, + const GError *error, + gpointer user_data) +{ + SetParametersData *data = (SetParametersData *) user_data; + + if (value != NULL) + { + DEBUG ("unsetting %s", *data->unset_iter); + /* pessimistically assume that removing any parameter merits + * reconnection (in a perfect implementation, if the + * Has_Default flag was set we'd check whether the current + * value is the default already) */ + + g_ptr_array_add (data->not_yet, g_strdup (*data->unset_iter)); + } + _mcd_account_set_parameter (data->account, *data->unset_iter, NULL, + set_parameters_unset_single, data); +} + +static void +set_parameters_unset_single (McdAccount *account, const GError *error, + gpointer user_data) +{ + SetParametersData *data = (SetParametersData *) user_data; + + if (data->unset == NULL) + { + set_parameters_finish (data); + return; + } + + if (account == NULL) + { + data->unset_iter = data->unset; /* first time */ + } + else + { + data->unset_iter++; + } + + if (*data->unset_iter != NULL) + { + mcd_account_get_parameter (data->account, *data->unset_iter, + set_parameters_unset_check_present, data); + } + else + { + set_parameters_finish (data); + } +} + +static void +set_parameters_set_single (McdAccount *account, + const GError *error, + gpointer user_data) +{ + SetParametersData *data = (SetParametersData *) user_data; + const gchar *name; + const GValue *value; + + if (g_hash_table_iter_next (&data->iter, (gpointer) &name, (gpointer) &value)) + { + _mcd_account_set_parameter (data->account, name, value, + set_parameters_set_single, data); + } + else + { + /* End of the hash table */ + set_parameters_unset_single (NULL, NULL, data); + } +} + +static void +set_parameters_iter_param (McdAccount *account, + const GValue *ret_value, + const GError *error, + gpointer user_data) +{ + SetParametersData *data = (SetParametersData *) user_data; + GError *out_error = NULL; + + /* account == NULL means this is the first run by + * _mcd_account_set_parameters itself or in this function, + * but with no call to mcd_account_get_parameter. */ + if (account != NULL + && (ret_value == NULL || !value_is_same (ret_value, data->new))) + { + DEBUG ("Parameter %s changed", data->param->name); + /* can the param be updated on the fly? If yes, prepare to + * do so; and if not, prepare to reset the connection */ + if (data->param->flags & TP_CONN_MGR_PARAM_FLAG_DBUS_PROPERTY) + { + data->dbus_properties = g_slist_prepend (data->dbus_properties, + data->param->name); + } + else + { + g_ptr_array_add (data->not_yet, g_strdup (data->param->name)); + } + + data->param++; + } + + if (data->param->name != NULL) + { + GType type; + + type = mc_param_type (data->param); + data->new = g_hash_table_lookup (data->params, data->param->name); + + if (data->new != NULL) + { + DEBUG ("Got param %s", data->param->name); + data->n_params++; + + if (G_VALUE_TYPE (data->new) != type) + { + /* FIXME: define proper error */ + g_set_error (&out_error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + "parameter %s must be of type %s, not %s", + data->param->name, + g_type_name (type), G_VALUE_TYPE_NAME (data->new)); + goto error; + } + + if (mcd_account_get_connection_status (data->account) == + TP_CONNECTION_STATUS_CONNECTED) + { + mcd_account_get_parameter (data->account, data->param->name, + set_parameters_iter_param, data); + } + else + { + data->param++; + set_parameters_iter_param (NULL, NULL, NULL, data); + } + } + else + { + data->param++; + set_parameters_iter_param (NULL, NULL, NULL, data); + } + } + else + { + if (data->n_params != g_hash_table_size (data->params)) + { + g_set_error (&out_error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + "Not all parameters were recognized"); + goto error; + } + g_hash_table_iter_init (&data->iter, data->params); + set_parameters_set_single (data->account, NULL, data); + } + + return; + +error: + if (data->callback != NULL) + data->callback (data->account, data->not_yet, out_error, data->user_data); + + set_parameters_data_free (data); +} + /* * _mcd_account_set_parameters: * @account: the #McdAccount. * @name: the parameter name. * @params: names and values of parameters to set * @unset: names of parameters to unset - * @not_yet: if not %NULL, borrowed names of parameters that cannot take - * effect until Reconnect() is called will be appended to this array + * @callback: function to be called when finished + * @user_data: data to be passed to @callback * * Alter the account parameters. * - * Returns: %TRUE (possibly appending borrowed strings to @not_yet) on success, - * %FALSE (setting @error) on failure */ -gboolean +void _mcd_account_set_parameters (McdAccount *account, GHashTable *params, - const gchar ** unset, GPtrArray *not_yet, - GError **error) + const gchar **unset, + McdAccountSetParametersCb callback, + gpointer user_data) { McdAccountPrivate *priv = account->priv; const TpConnectionManagerParam *param; - guint n_params = 0; - GHashTableIter iter; - const gchar *name; - const GValue *value; GSList *dbus_properties = NULL; - gboolean reset_connection; + GPtrArray *not_yet = NULL; + SetParametersData *data; + GError *error = NULL; + guint unset_size; DEBUG ("called"); if (G_UNLIKELY (!priv->manager && !load_manager (account))) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (&error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, "Manager %s not found", priv->manager_name); - return FALSE; + goto error; } param = mcd_manager_get_parameters (priv->manager, priv->protocol_name); if (G_UNLIKELY (!param)) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (&error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, "Protocol %s not found", priv->protocol_name); - return FALSE; + goto error; } - reset_connection = FALSE; - while (param->name != NULL) - { - GType type; + unset_size = (unset != NULL) ? g_strv_length ((gchar **) unset) : 0; - type = mc_param_type (param); - value = g_hash_table_lookup (params, param->name); - if (value) - { - DEBUG ("Got param %s", param->name); - if (G_VALUE_TYPE (value) != type) - { - /* FIXME: define proper error */ - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, - "parameter %s must be of type %s, not %s", - param->name, - g_type_name (type), G_VALUE_TYPE_NAME (value)); - return FALSE; - } + /* pessimistically assume that every parameter mentioned will be deferred + * until reconnection */ + not_yet = g_ptr_array_sized_new (g_hash_table_size (params) + unset_size); + + data = g_slice_new0 (SetParametersData); + data->account = g_object_ref (account); + data->params = hash_table_copy (params); + data->unset = g_strdupv ((gchar **) unset); + data->param = param; + data->n_params = 0; + data->dbus_properties = dbus_properties; + data->not_yet = not_yet; + data->callback = callback; + data->user_data = user_data; - if (mcd_account_get_connection_status (account) == - TP_CONNECTION_STATUS_CONNECTED) - { - GValue old = { 0 }; + set_parameters_iter_param (NULL, NULL, NULL, data); + return; - g_value_init (&old, type); - if (!mcd_account_get_parameter (account, param->name, &old) || - !value_is_same (value, &old)) - { - DEBUG ("Parameter %s changed", param->name); - /* can the param be updated on the fly? If yes, prepare to - * do so; and if not, prepare to reset the connection */ - if (param->flags & TP_CONN_MGR_PARAM_FLAG_DBUS_PROPERTY) - { - dbus_properties = g_slist_prepend (dbus_properties, - param->name); - } - else - { - if (not_yet != NULL) - { - /* we assume that the TpConnectionManager won't get - * freed */ - g_ptr_array_add (not_yet, param->name); - } - - reset_connection = TRUE; - } - } - g_value_unset (&old); - } - n_params++; - } - param++; - } +error: + if (callback != NULL) + callback (account, NULL, error, user_data); - if (n_params != g_hash_table_size (params)) - { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, - "Not all parameters were recognized"); - return FALSE; - } + g_error_free (error); + if (not_yet != NULL) + g_ptr_array_free (not_yet, TRUE); +} - g_hash_table_iter_init (&iter, params); - while (g_hash_table_iter_next (&iter, (gpointer)&name, (gpointer)&value)) - { - _mcd_account_set_parameter (account, name, value, NULL, NULL); - } +typedef struct +{ + DBusGMethodInvocation *context; + GPtrArray *not_yet; +} UpdateParametersData; - if (unset != NULL) - { - const gchar **unset_iter; +static void +update_parameters_dup_params_cb (McdAccount *account, GHashTable *params, + gpointer user_data) +{ + McdAccountPrivate *priv = account->priv; + UpdateParametersData *data = (UpdateParametersData *) user_data; + GValue value = { 0 }; - for (unset_iter = unset; *unset_iter != NULL; unset_iter++) - { - if (mcd_account_get_parameter (account, *unset_iter, NULL)) - { - DEBUG ("unsetting %s", *unset_iter); - /* pessimistically assume that removing any parameter merits - * reconnection (in a perfect implementation, if the - * Has_Default flag was set we'd check whether the current - * value is the default already) */ - if (not_yet != NULL) - { - /* we assume that the TpConnectionManager won't get - * freed */ - g_ptr_array_add (not_yet, (gchar *) *unset_iter); - } + g_value_init (&value, TP_HASH_TYPE_STRING_VARIANT_MAP); + g_value_take_boxed (&value, params); + mcd_account_changed_property (account, "Parameters", &value); + g_value_unset (&value); - reset_connection = TRUE; - } + mcd_account_manager_write_conf_async (priv->account_manager, NULL, NULL); - _mcd_account_set_parameter (account, *unset_iter, NULL, NULL, NULL); - } - } + g_ptr_array_add (data->not_yet, NULL); - if (mcd_account_get_connection_status (account) == - TP_CONNECTION_STATUS_CONNECTED) - { - GSList *list; + tp_svc_account_return_from_update_parameters (data->context, + (const gchar **) data->not_yet->pdata); - for (list = dbus_properties; list != NULL; list = list->next) - { - name = list->data; - DEBUG ("updating parameter %s", name); - value = g_hash_table_lookup (params, name); - _mcd_connection_update_property (priv->connection, name, value); - } - } - g_slist_free (dbus_properties); + g_ptr_array_foreach (data->not_yet, (GFunc) g_free, NULL); + g_ptr_array_free (data->not_yet, TRUE); - mcd_account_check_validity (account); - _mcd_account_maybe_autoconnect (account); - return TRUE; + g_slice_free (UpdateParametersData, data); } static void -account_update_parameters (TpSvcAccount *self, GHashTable *set, - const gchar **unset, DBusGMethodInvocation *context) +account_update_parameters_cb (McdAccount *account, GPtrArray *not_yet, + const GError *error, gpointer user_data) { - McdAccount *account = MCD_ACCOUNT (self); - McdAccountPrivate *priv = account->priv; - GHashTable *parameters; - GValue value = { 0 }; - GError *error = NULL; - GPtrArray *not_yet; - - DEBUG ("called for %s", priv->unique_name); - - /* pessimistically assume that every parameter mentioned will be deferred - * until reconnection */ - not_yet = g_ptr_array_sized_new (g_hash_table_size (set) + - g_strv_length ((gchar **) unset) + 1); + DBusGMethodInvocation *context = (DBusGMethodInvocation *) user_data; + UpdateParametersData *data; - if (!_mcd_account_set_parameters (account, set, unset, not_yet, &error)) + if (error != NULL) { - g_ptr_array_free (not_yet, TRUE); - dbus_g_method_return_error (context, error); - g_error_free (error); + dbus_g_method_return_error (context, (GError *) error); return; } + data = g_slice_new0 (UpdateParametersData); + data->not_yet = not_yet; + data->context = context; + /* emit the PropertiesChanged signal */ - parameters = _mcd_account_dup_parameters (account); - g_value_init (&value, TP_HASH_TYPE_STRING_VARIANT_MAP); - g_value_take_boxed (&value, parameters); - mcd_account_changed_property (account, "Parameters", &value); - g_value_unset (&value); + _mcd_account_dup_parameters (account, update_parameters_dup_params_cb, + data); +} - mcd_account_manager_write_conf_async (priv->account_manager, NULL, NULL); +static void +account_update_parameters (TpSvcAccount *self, GHashTable *set, + const gchar **unset, DBusGMethodInvocation *context) +{ + McdAccount *account = MCD_ACCOUNT (self); + McdAccountPrivate *priv = account->priv; - g_ptr_array_add (not_yet, NULL); + DEBUG ("called for %s", priv->unique_name); - tp_svc_account_return_from_update_parameters (context, - (const gchar **) not_yet->pdata); - g_ptr_array_free (not_yet, TRUE); + _mcd_account_set_parameters (account, set, unset, + account_update_parameters_cb, context); } static void @@ -2320,54 +2606,93 @@ mcd_account_get_object_path (McdAccount *account) return account->priv->object_path; } -static inline void -add_parameter (McdAccount *account, const TpConnectionManagerParam *param, - GHashTable *params) +typedef struct { - GValue *value; - GType type; - - type = mc_param_type (param); - if (G_UNLIKELY (type == G_TYPE_INVALID)) return; - - value = tp_g_value_slice_new (type); + GHashTable *params; + const TpConnectionManagerParam *param; + McdAccountDupParametersCb callback; + gpointer user_data; +} DupParametersData; - if (mcd_account_get_parameter (account, param->name, value)) - g_hash_table_insert (params, g_strdup (param->name), value); - else - tp_g_value_slice_free (value); +static void +dup_parameters_get_parameter_cb (McdAccount *account, + const GValue *value, + const GError *error, + gpointer user_data) +{ + DupParametersData *data = (DupParametersData *) user_data; + + if (value != NULL) + { + g_hash_table_insert (data->params, g_strdup (data->param->name), + tp_g_value_slice_dup (value)); + } + + data->param++; + + if (data->param->name != NULL) + { + mcd_account_get_parameter (account, data->param->name, + dup_parameters_get_parameter_cb, data); + } + else + { + if (data->callback != NULL) + data->callback (account, data->params, data->user_data); + g_slice_free (DupParametersData, data); + } } -/* +/** * _mcd_account_dup_parameters: * @account: the #McdAccount. + * @callback: function to call with the result + * @user_data: data to pass to @callback * - * Get the parameters set for this account. - * - * Returns: a newly allocated #GHashTable containing the account parameters. + * Get the parameters set for this account. The resulting #GHashTable in the + * callback will be newly allocated and must be g_hash_table_unref() 'd after + * use. */ -GHashTable * -_mcd_account_dup_parameters (McdAccount *account) +void +_mcd_account_dup_parameters (McdAccount *account, + McdAccountDupParametersCb callback, + gpointer user_data) { - McdAccountPrivate *priv = MCD_ACCOUNT_PRIV (account); + McdAccountPrivate *priv; + DupParametersData *data; const TpConnectionManagerParam *param; - GHashTable *params; + + g_return_if_fail (MCD_IS_ACCOUNT (account)); + + priv = account->priv; DEBUG ("called"); - if (!priv->manager && !load_manager (account)) return NULL; + if (!priv->manager && !load_manager (account)) + { + callback (account, NULL, user_data); + return; + } - params = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, - (GDestroyNotify)tp_g_value_slice_free); - param = mcd_manager_get_parameters (priv->manager, priv->protocol_name); - if (G_UNLIKELY (!param)) return params; + param = mcd_manager_get_parameters (priv->manager, + priv->protocol_name); - while (param->name != NULL) + if (G_UNLIKELY (!param)) { - add_parameter (account, param, params); - param++; + callback (account, NULL, user_data); + return; } - return params; + + data = g_slice_new0 (DupParametersData); + data->param = param; + data->callback = callback; + data->user_data = user_data; + + data->params = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, + (GDestroyNotify) tp_g_value_slice_free); + + mcd_account_get_parameter (account, param->name, + dup_parameters_get_parameter_cb, data); } /** @@ -2840,25 +3165,31 @@ mcd_account_get_connection (McdAccount *account) return priv->connection; } -gboolean -mcd_account_check_validity (McdAccount *account) +typedef struct { - McdAccountPrivate *priv = account->priv; - gboolean valid; + McdAccountCheckValidityCb callback; + gpointer user_data; +} CheckValidityData; - valid = (priv->loaded && mcd_account_check_parameters (account)); +static void +check_validity_check_parameters_cb (McdAccount *account, + gboolean valid, + gpointer user_data) +{ + CheckValidityData *data = (CheckValidityData *) user_data; + McdAccountPrivate *priv = account->priv; if (valid != priv->valid) { - GValue value = { 0 }; + GValue value = { 0 }; DEBUG ("Account validity changed (old: %d, new: %d)", priv->valid, valid); - priv->valid = valid; - g_signal_emit (account, _mcd_account_signals[VALIDITY_CHANGED], 0, - valid); - g_value_init (&value, G_TYPE_BOOLEAN); - g_value_set_boolean (&value, valid); - mcd_account_changed_property (account, "Valid", &value); + priv->valid = valid; + g_signal_emit (account, _mcd_account_signals[VALIDITY_CHANGED], 0, + valid); + g_value_init (&value, G_TYPE_BOOLEAN); + g_value_set_boolean (&value, valid); + mcd_account_changed_property (account, "Valid", &value); if (valid) { @@ -2869,7 +3200,28 @@ mcd_account_check_validity (McdAccount *account) priv->req_presence_message); } } - return valid; + + if (data->callback != NULL) + data->callback (account, valid, data->user_data); + + g_slice_free (CheckValidityData, data); +} + +void +mcd_account_check_validity (McdAccount *account, + McdAccountCheckValidityCb callback, + gpointer user_data) +{ + CheckValidityData *data; + + g_return_if_fail (MCD_IS_ACCOUNT (account)); + + data = g_slice_new0 (CheckValidityData); + data->callback = callback; + data->user_data = user_data; + + mcd_account_check_parameters (account, check_validity_check_parameters_cb, + data); } /* diff --git a/src/mcd-account.h b/src/mcd-account.h index 16aa2297..85c2f285 100644 --- a/src/mcd-account.h +++ b/src/mcd-account.h @@ -57,12 +57,17 @@ typedef void (*McdAccountDeleteCb) (McdAccount *account, typedef void (*McdAccountSetParameterCb) (McdAccount *account, const GError *error, gpointer user_data); +typedef void (*McdAccountGetParameterCb) (McdAccount *account, + const GValue *value, + const GError *error, + gpointer user_data); struct _McdAccountClass { GObjectClass parent_class; - gboolean (*get_parameter) (McdAccount *account, const gchar *name, - GValue *value); + void (*get_parameter) (McdAccount *account, const gchar *name, + McdAccountGetParameterCb callback, + gpointer user_data); void (*set_parameter) (McdAccount *account, const gchar *name, const GValue *value, McdAccountSetParameterCb callback, @@ -92,7 +97,13 @@ const gchar *mcd_account_get_unique_name (McdAccount *account); const gchar *mcd_account_get_object_path (McdAccount *account); gboolean mcd_account_is_valid (McdAccount *account); -gboolean mcd_account_check_validity (McdAccount *account); + +typedef void (*McdAccountCheckValidityCb) (McdAccount *account, + gboolean valid, + gpointer user_data); +void mcd_account_check_validity (McdAccount *account, + McdAccountCheckValidityCb callback, + gpointer user_data); gboolean mcd_account_is_enabled (McdAccount *account); |