diff options
author | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2013-01-08 15:09:12 +0000 |
---|---|---|
committer | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2013-01-08 15:09:12 +0000 |
commit | 57eaa0241be6ad60ca2a818cb120e4a8243a99ea (patch) | |
tree | ced24d2b0474bc3457cec44b4108f57e94d12b55 | |
parent | 76ca6e930930a711393a1e15fc783512b6ba295b (diff) |
Names mixin: don't store any datanames
In practice, connection managers already have all the necessary
information to tell us the local aliases and nicknames, if any.
-rw-r--r-- | docs/reference/telepathy-glib-sections.txt | 4 | ||||
-rw-r--r-- | telepathy-glib/names-mixin.c | 343 | ||||
-rw-r--r-- | telepathy-glib/names-mixin.h | 17 | ||||
-rw-r--r-- | tests/lib/contacts-conn.c | 94 | ||||
-rw-r--r-- | tests/lib/debug.h | 8 |
5 files changed, 301 insertions, 165 deletions
diff --git a/docs/reference/telepathy-glib-sections.txt b/docs/reference/telepathy-glib-sections.txt index 2eec5596e..5a490e181 100644 --- a/docs/reference/telepathy-glib-sections.txt +++ b/docs/reference/telepathy-glib-sections.txt @@ -2289,6 +2289,8 @@ TP_CONTACTS_MIXIN <INCLUDE>telepathy-glib/telepathy-glib.h</INCLUDE> <FILE>names-mixin</FILE> TpNamesInterface +TpNamesInterfaceDupNameFunc +TpNamesInterfaceGetStorageTypeFunc TpNamesInterfaceRequestNicknameAsyncFunc TpNamesInterfaceRequestNicknameFinishFunc TpNamesInterfaceSetLocalAliasAsyncFunc @@ -2300,8 +2302,6 @@ tp_names_mixin_nicknames_changed tp_names_mixin_one_nickname_changed tp_names_mixin_local_aliases_changed tp_names_mixin_one_local_alias_changed -tp_names_mixin_drop -tp_names_mixin_set_storage_type tp_names_mixin_iface_init tp_names_mixin_aliasing_iface_init tp_names_mixin_init diff --git a/telepathy-glib/names-mixin.c b/telepathy-glib/names-mixin.c index 9bd4a7cf7..3dc7828b5 100644 --- a/telepathy-glib/names-mixin.c +++ b/telepathy-glib/names-mixin.c @@ -79,6 +79,43 @@ */ /** + * TpNamesInterfaceDupNameFunc: + * @base: a #TpBaseConnection implementing #TpNamesInterface + * @contact: a #TpHandle of type %TP_HANDLE_TYPE_CONTACT representing + * the contact whose "name" is desired + * + * Signature of a virtual method to be used to check one of a contact's + * "names". Depending on the particular virtual method being implemented, this + * could mean the contact's nickname (a string chosen by them to + * represent themselves, which could be an attempt to impersonate + * someone else), the contact's local alias (a string chosen by the + * local user to represent them, which can be trusted), or some other + * sort of name. + * + * If no appropriate name is known, this function should not return + * the identifier that would be returned by tp_handle_inspect(): just + * return %NULL instead. Telepathy user interfaces are expected to respond + * to an empty or missing nickname, local alias etc. by falling back to the + * identifier, and doing this in the user interface avoids confusion about + * the source and trust level of a particular name. + * + * Returns: (transfer full): @contact's "name", or %NULL if no "name" is known + */ + +/** + * TpNamesInterfaceGetStorageTypeFunc: + * @base: a #TpBaseConnection implementing #TpNamesInterface + * + * Signature of a callback to get the storage type for local aliases. + * + * After tp_base_connection_change_status() is used to move to + * the %TP_CONNECTION_STATUS_CONNECTED state, implementations + * must not change the value returned by this function. + * + * Returns: the extent to which this connection can store local aliases + */ + +/** * TpNamesInterfaceRequestNicknameAsyncFunc: * @base: a #TpBaseConnection implementing #TpNamesInterface * @contact: a #TpHandle, contact whose nickname needs to be @@ -89,7 +126,8 @@ * Signature of a callback to be used to request nicknames. * * If a new nickname is retrieved, @base is expected to call either - * tp_names_mixin_nicknames_changed() or tp_names_mixin_one_nickname_changed() + * tp_names_mixin_nicknames_changed() or tp_names_mixin_one_nickname_changed(), + * and change what it would return from the @dup_nickname virtual method, * before it allows the async result of this function to complete. * * Since: 0.UNRELEASED @@ -119,7 +157,8 @@ * Signature of a callback to be used to set user's nickname. * * If a new nickname is set, @base is expected to call either - * tp_names_mixin_nicknames_changed() or tp_names_mixin_one_nickname_changed() + * tp_names_mixin_nicknames_changed() or tp_names_mixin_one_nickname_changed(), + * and change what it would return from the @dup_nickname virtual method, * before it allows the async result of this function to complete. * * Since: 0.UNRELEASED @@ -153,7 +192,8 @@ * * If a new local alias is set, @base is expected to call either * tp_names_mixin_local_aliases_changed() or - * tp_names_mixin_one_local_alias_changed() + * tp_names_mixin_one_local_alias_changed(), + * and change what it would return from the @dup_local_alias virtual method, * before it allows the async result of this function to complete. * * Since: 0.UNRELEASED @@ -175,6 +215,7 @@ /** * TpNamesInterface: * @parent: the parent interface + * @dup_nickname: virtual function to get a contact's nickname, if known * @request_nickname_async: virtual function to re-download a contact's * nickname from the server * @request_nickname_finish: virtual function to interpret the result @@ -182,16 +223,21 @@ * @set_nickname_async: virtual function to set the user's nickname * @set_nickname_finish: virtual function to interpret the result * of @set_nickname_async + * @dup_local_alias: virtual function to get a contact's local alias, if known + * @get_alias_storage: virtual function returning the extent to which + * local aliases can be modified * @set_local_alias_async: virtual function to set a contact's local alias * @set_local_alias_finish: virtual function to interpret the result * of @set_local_alias_async * * Interface structure of virtual methods needed by #TpNamesMixin. * + * The default implementation of @dup_nickname returns %NULL, indicating + * that no contact has a nickname. Most connection managers should override + * this. + * * The default implementation of @request_nickname_async returns whatever - * nickname was last stored in the mixin by - * tp_names_mixin_nicknames_changed() or tp_names_mixin_one_nickname_changed() - * (or "" if no nickname is stored for that contact), indicating that + * @dup_nickname does (or an empty string if it returns %NULL), indicating that * either nicknames are not supported at all, or all nicknames are known * already. Connection managers for protocols where the user may need to * "refresh" a contact's nickname by re-querying the server, such as XMPP, @@ -206,9 +252,16 @@ * %TP_ERROR_NOT_IMPLEMENTED. Connection managers for protocols where * the user can change their own nickname should override this method. * + * The default implementation of @dup_local_alias returns %NULL, indicating + * that no contact has a stored local-alias. Connection managers which support + * user-assigned aliases for contacts (even if they are read-only) should + * override this method. + * * The default implementation of @set_local_alias_async raises - * %TP_ERROR_NOT_IMPLEMENTED. Connection managers for protocols where - * aliases can be stored should override this method. + * %TP_ERROR_NOT_IMPLEMENTED, and the default implementation of + * @get_alias_storage returns %TP_CONTACT_METADATA_STORAGE_TYPE_NONE. + * Connection managers for protocols where aliases can be stored should + * override both of these methods. * * The @set_nickname_finish and @set_local_alias functions have a default * implementation, which assumes that the corresponding @async function @@ -245,12 +298,7 @@ G_DEFINE_INTERFACE (TpNames, tp_names_interface, TP_TYPE_BASE_CONNECTION) typedef struct { - /* Immutable properties once CONNECTED */ - TpContactMetadataStorageType alias_storage; - - /* TpHandle -> owned string */ - GHashTable *nicknames; - GHashTable *local_aliases; + gint dummy; } TpNamesMixinPrivate; #define TP_NAMES_MIXIN_GET_PRIVATE(o) \ @@ -269,13 +317,20 @@ tp_names_mixin_get_quark (void) static void tp_names_mixin_private_free (gpointer); +static gchar * +default_dup_null (TpBaseConnection *base, + TpHandle contact) +{ + return NULL; +} + static void default_request_nickname_async (TpBaseConnection *base, TpHandle contact, GAsyncReadyCallback callback, gpointer user_data) { - TpNamesMixinPrivate *priv = TP_NAMES_MIXIN_GET_PRIVATE (base); + TpNamesInterface *iface = TP_NAMES_INTERFACE_GET_IFACE (base); gchar *nickname; GSimpleAsyncResult *simple; @@ -283,8 +338,7 @@ default_request_nickname_async (TpBaseConnection *base, if (callback == NULL) return; - nickname = g_strdup (g_hash_table_lookup (priv->nicknames, - GUINT_TO_POINTER (contact))); + nickname = iface->dup_nickname (base, contact); /* NULL means error here, so avoid it */ if (nickname == NULL) @@ -328,6 +382,12 @@ default_set_nickname_finish (TpBaseConnection *base, _tp_implement_finish_void (base, NULL); } +static TpContactMetadataStorageType +default_get_alias_storage (TpBaseConnection *base) +{ + return TP_CONTACT_METADATA_STORAGE_TYPE_NONE; +} + static void default_set_local_alias_async (TpBaseConnection *base, TpHandle contact, @@ -354,8 +414,11 @@ default_set_local_alias_finish (TpBaseConnection *base, static void tp_names_interface_default_init (TpNamesInterface *iface) { + iface->dup_nickname = default_dup_null; iface->request_nickname_async = default_request_nickname_async; iface->request_nickname_finish = default_request_nickname_finish; + iface->dup_local_alias = default_dup_null; + iface->get_alias_storage = default_get_alias_storage; iface->set_nickname_async = default_set_nickname_async; iface->set_nickname_finish = default_set_nickname_finish; iface->set_local_alias_async = default_set_local_alias_async; @@ -393,11 +456,6 @@ tp_names_mixin_init (GObject *object) priv = g_slice_new0 (TpNamesMixinPrivate); - priv->nicknames = g_hash_table_new_full (NULL, NULL, - NULL, g_free); - priv->local_aliases = g_hash_table_new_full (NULL, NULL, - NULL, g_free); - g_object_set_qdata_full (object, tp_names_mixin_get_quark (), priv, tp_names_mixin_private_free); } @@ -407,9 +465,6 @@ tp_names_mixin_private_free (gpointer p) { TpNamesMixinPrivate *priv = p; - g_hash_table_unref (priv->nicknames); - g_hash_table_unref (priv->local_aliases); - g_slice_free (TpNamesMixinPrivate, priv); } @@ -436,19 +491,22 @@ tp_names_mixin_get_dbus_property (GObject *object, gpointer user_data) { TpBaseConnection *conn = (TpBaseConnection *) object; + TpNamesInterface *iface = TP_NAMES_INTERFACE_GET_IFACE (conn); TpNamesMixinPrivate *priv = TP_NAMES_MIXIN_GET_PRIVATE (object); + g_return_if_fail (iface != NULL); g_return_if_fail (priv != NULL); switch (GPOINTER_TO_UINT (user_data)) { case MIXIN_DP_NICKNAME: - g_value_set_string (value, g_hash_table_lookup (priv->nicknames, - GUINT_TO_POINTER (tp_base_connection_get_self_handle (conn)))); + g_value_set_string (value, + iface->dup_nickname (conn, + tp_base_connection_get_self_handle (conn))); break; case MIXIN_DP_ALIAS_STORAGE: - g_value_set_uint (value, priv->alias_storage); + g_value_set_uint (value, iface->get_alias_storage (conn)); break; default: @@ -465,9 +523,10 @@ tp_names_mixin_set_dbus_property (GObject *object, GError **error) { TpBaseConnection *base = (TpBaseConnection *) object; - TpNamesInterface *iface = TP_NAMES_INTERFACE_GET_IFACE (base); + TpNamesInterface *iface = TP_NAMES_INTERFACE_GET_IFACE (object); TpNamesMixinPrivate *priv = TP_NAMES_MIXIN_GET_PRIVATE (object); + g_return_val_if_fail (iface != NULL, FALSE); g_return_val_if_fail (priv != NULL, FALSE); switch (GPOINTER_TO_UINT (user_data)) @@ -670,53 +729,59 @@ tp_names_mixin_aliasing_get_alias_flags ( { TpBaseConnection *base = TP_BASE_CONNECTION (dbus_iface); TpConnectionAliasFlags flags = 0; + TpNamesInterface *iface = TP_NAMES_INTERFACE_GET_IFACE (base); TpNamesMixinPrivate *priv = TP_NAMES_MIXIN_GET_PRIVATE (dbus_iface); + g_return_if_fail (iface != NULL); g_return_if_fail (priv != NULL); TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context); - if (priv->alias_storage != TP_CONTACT_METADATA_STORAGE_TYPE_NONE) + if (iface->get_alias_storage (base) != TP_CONTACT_METADATA_STORAGE_TYPE_NONE) flags |= TP_CONNECTION_ALIAS_FLAG_USER_SET; tp_svc_connection_interface_aliasing_return_from_get_alias_flags (context, flags); } -static const gchar * -aliasing_get_alias (TpBaseConnection *base, +static gchar * +aliasing_dup_alias (TpBaseConnection *base, TpHandle contact, gboolean *request) { TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (base, TP_HANDLE_TYPE_CONTACT); - const gchar *str; + gchar *str; + TpNamesInterface *iface = TP_NAMES_INTERFACE_GET_IFACE (base); TpNamesMixinPrivate *priv = TP_NAMES_MIXIN_GET_PRIVATE (base); + g_return_val_if_fail (iface != NULL, NULL); g_return_val_if_fail (priv != NULL, NULL); if (request != NULL) *request = FALSE; /* First try local alias */ - str = g_hash_table_lookup (priv->local_aliases, - GUINT_TO_POINTER (contact)); + str = iface->dup_local_alias (base, contact); if (!tp_str_empty (str)) return str; + g_free (str); + /* Fallback to Nickname */ - str = g_hash_table_lookup (priv->nicknames, - GUINT_TO_POINTER (contact)); + str = iface->dup_nickname (base, contact); if (!tp_str_empty (str)) return str; + g_free (str); + if (request != NULL) *request = TRUE; /* Fallback to id */ - return tp_handle_inspect (contact_repo, contact); + return g_strdup (tp_handle_inspect (contact_repo, contact)); } static void @@ -741,15 +806,15 @@ tp_names_mixin_aliasing_get_aliases ( return; } - table = g_hash_table_new (NULL, NULL); + table = g_hash_table_new_full (NULL, NULL, NULL, g_free); for (i = 0; i < contacts->len; i++) { TpHandle contact = g_array_index (contacts, TpHandle, i); gboolean request; - const gchar *str; + gchar *str; - str = aliasing_get_alias (base, contact, &request); - g_hash_table_insert (table, GUINT_TO_POINTER (contact), (gchar *) str); + str = aliasing_dup_alias (base, contact, &request); + g_hash_table_insert (table, GUINT_TO_POINTER (contact), str); if (request) implicit_request_nickname (base, contact); @@ -995,23 +1060,25 @@ tp_names_mixin_fill_contact_attributes (GObject *object, { TpBaseConnection *base = TP_BASE_CONNECTION (object); guint i; + TpNamesInterface *iface = TP_NAMES_INTERFACE_GET_IFACE (base); TpNamesMixinPrivate *priv = TP_NAMES_MIXIN_GET_PRIVATE (object); + g_return_if_fail (iface != NULL); g_return_if_fail (priv != NULL); for (i = 0; i < contacts->len; i++) { TpHandle contact = g_array_index (contacts, guint, i); - const gchar *str; + gchar *str; /* Nickname */ - str = g_hash_table_lookup (priv->nicknames, - GUINT_TO_POINTER (contact)); - if (str != NULL) + str = iface->dup_nickname (base, contact); + + if (!tp_str_empty (str)) { tp_contacts_mixin_set_contact_attribute (attributes, contact, TP_TOKEN_CONNECTION_INTERFACE_NAMES_NICKNAME, - tp_g_value_slice_new_string (str)); + tp_g_value_slice_new_take_string (str)); } else { @@ -1019,13 +1086,13 @@ tp_names_mixin_fill_contact_attributes (GObject *object, } /* Alias */ - str = g_hash_table_lookup (priv->local_aliases, - GUINT_TO_POINTER (contact)); - if (str != NULL) + str = iface->dup_local_alias (base, contact); + + if (!tp_str_empty (str)) { tp_contacts_mixin_set_contact_attribute (attributes, contact, TP_TOKEN_CONNECTION_INTERFACE_NAMES_LOCAL_ALIAS, - tp_g_value_slice_new_string (str)); + tp_g_value_slice_new_take_string (str)); } } } @@ -1042,12 +1109,13 @@ tp_names_mixin_aliasing_fill_contact_attributes (GObject *object, { TpHandle contact = g_array_index (contacts, guint, i); gboolean request; - const gchar *str; + gchar *str; + + str = aliasing_dup_alias (base, contact, &request); - str = aliasing_get_alias (base, contact, &request); tp_contacts_mixin_set_contact_attribute (attributes, contact, TP_TOKEN_CONNECTION_INTERFACE_ALIASING_ALIAS, - tp_g_value_slice_new_string (str)); + tp_g_value_slice_new_take_string (str)); if (request) { @@ -1094,6 +1162,10 @@ tp_names_mixin_register_with_contacts_mixin (GObject *object) * Update contact nicknames. This should be called by the Connection Manager * when multiple nicknames changed. * + * By the time this function is called, the @dup_nickname virtual method, + * if called for an affected contact, should already return the new + * nickname. + * * If only one nickname changed, tp_names_mixin_one_nickname_changed() is more * convenient. * @@ -1106,12 +1178,16 @@ tp_names_mixin_nicknames_changed (TpBaseConnection *base, GPtrArray *array; GHashTableIter iter; gpointer key, value; - gboolean one_changed = FALSE; + TpNamesInterface *iface = TP_NAMES_INTERFACE_GET_IFACE (base); TpNamesMixinPrivate *priv = TP_NAMES_MIXIN_GET_PRIVATE (base); + g_return_if_fail (iface != NULL); g_return_if_fail (priv != NULL); g_return_if_fail (table != NULL); + if (g_hash_table_size (table) == 0) + return; + array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_value_array_free); g_hash_table_iter_init (&iter, table); @@ -1119,33 +1195,41 @@ tp_names_mixin_nicknames_changed (TpBaseConnection *base, { TpHandle contact = GPOINTER_TO_UINT (key); const gchar *nickname = value; - const gchar *old_nickname; + gchar *local_alias = iface->dup_local_alias (base, contact); /* Don't distinguish between "" and NULL */ if (tp_str_empty (nickname)) nickname = NULL; - old_nickname = g_hash_table_lookup (priv->nicknames, key); - - if (!tp_strdiff (old_nickname, nickname)) - continue; - - one_changed = TRUE; - g_hash_table_insert (priv->nicknames, key, g_strdup (nickname)); - /* Local alias takes precedence, but if we don't have one then alias * changed */ - if (!g_hash_table_contains (priv->local_aliases, key)) + if (tp_str_empty (local_alias)) { - DEBUG ("contact#%u changed nickname and legacy alias to %s", - contact, nickname); + gchar *legacy_alias; + + /* This is not necessarily the same as nickname: if nickname + * is now empty/NULL, this will reset to the identifier */ + legacy_alias = aliasing_dup_alias (base, contact, NULL); + + if (tp_strdiff (nickname, legacy_alias)) + { + DEBUG ("contact#%u changed nickname to %s", + contact, nickname); + DEBUG ("contact#%u legacy alias changed to %s", + contact, legacy_alias); + } + else + { + DEBUG ("contact#%u changed nickname and legacy alias to %s", + contact, nickname); + } g_ptr_array_add (array, tp_value_array_build (2, G_TYPE_UINT, contact, - /* This is not necessarily the same as nickname: if nickname - * is now empty/NULL, this will reset to the identifier */ - G_TYPE_STRING, aliasing_get_alias (base, contact, NULL), + G_TYPE_STRING, legacy_alias, G_TYPE_INVALID)); + + g_free (legacy_alias); } else { @@ -1154,11 +1238,8 @@ tp_names_mixin_nicknames_changed (TpBaseConnection *base, } } - if (one_changed) - tp_svc_connection_interface_names_emit_nicknames_updated (base, table); - - if (array->len > 0) - tp_svc_connection_interface_aliasing_emit_aliases_changed (base, array); + tp_svc_connection_interface_names_emit_nicknames_updated (base, table); + tp_svc_connection_interface_aliasing_emit_aliases_changed (base, array); g_ptr_array_unref (array); } @@ -1173,6 +1254,9 @@ tp_names_mixin_nicknames_changed (TpBaseConnection *base, * Update @contact's nickname. This should be called by the Connection Manager * when a nickname changed. * + * By the time this function is called, the @dup_nickname virtual method, + * if called for @contact, should already return the new nickname. + * * If more than one nickname changed at once, it is recommended to use * tp_names_mixin_nicknames_changed() instead. * @@ -1202,6 +1286,9 @@ tp_names_mixin_one_nickname_changed (TpBaseConnection *base, * Update contact local aliases. This should be called by the * Connection Manager when multiple local aliases changed. * + * By the time this function is called, the @dup_local_alias virtual method, + * if called for an affected contact, should already return the new alias. + * * If only one local alias changed, tp_names_mixin_one_local_alias_changed() * is more convenient. * @@ -1214,12 +1301,16 @@ tp_names_mixin_local_aliases_changed (TpBaseConnection *base, GPtrArray *array; GHashTableIter iter; gpointer key, value; - gboolean one_changed = FALSE; + TpNamesInterface *iface = TP_NAMES_INTERFACE_GET_IFACE (base); TpNamesMixinPrivate *priv = TP_NAMES_MIXIN_GET_PRIVATE (base); + g_return_if_fail (iface != NULL); g_return_if_fail (priv != NULL); g_return_if_fail (table != NULL); + if (g_hash_table_size (table) == 0) + return; + array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_value_array_free); g_hash_table_iter_init (&iter, table); @@ -1227,36 +1318,39 @@ tp_names_mixin_local_aliases_changed (TpBaseConnection *base, { TpHandle contact = GPOINTER_TO_UINT (key); const gchar *alias = value; - const gchar *old_alias; + gchar *legacy_alias; /* Don't distinguish between "" and NULL */ if (tp_str_empty (alias)) alias = NULL; - old_alias = g_hash_table_lookup (priv->local_aliases, key); + /* This is not necessarily the same as alias: if nickname + * is now empty/NULL, this will reset to the identifier */ + legacy_alias = aliasing_dup_alias (base, contact, NULL); - if (!tp_strdiff (old_alias, alias)) - continue; - - one_changed = TRUE; - g_hash_table_insert (priv->local_aliases, key, g_strdup (alias)); + if (tp_strdiff (alias, legacy_alias)) + { + DEBUG ("contact#%u changed local-alias to %s", + contact, alias); + DEBUG ("contact#%u legacy alias changed to %s", + contact, legacy_alias); + } + else + { + DEBUG ("contact#%u changed local-alias and legacy alias to %s", + contact, alias); + } - DEBUG ("contact#%u changed local-alias and legacy alias to %s", - contact, alias); g_ptr_array_add (array, tp_value_array_build (2, G_TYPE_UINT, contact, - /* This is not necessarily the same as nickname: if local-alias - * is now empty/NULL, this will reset to the nickname or - * identifier */ - G_TYPE_STRING, aliasing_get_alias (base, contact, NULL), + G_TYPE_STRING, legacy_alias, G_TYPE_INVALID)); - } - if (one_changed) - tp_svc_connection_interface_names_emit_local_aliases_updated (base, table); + g_free (legacy_alias); + } - if (array->len > 0) - tp_svc_connection_interface_aliasing_emit_aliases_changed (base, array); + tp_svc_connection_interface_names_emit_local_aliases_updated (base, table); + tp_svc_connection_interface_aliasing_emit_aliases_changed (base, array); g_ptr_array_unref (array); } @@ -1271,6 +1365,9 @@ tp_names_mixin_local_aliases_changed (TpBaseConnection *base, * Update @contact's local alias. This should be called by the * Connection Manager when a local alias changed. * + * By the time this function is called, the @dup_local_alias virtual method, + * if called for @contact, should already return the new alias. + * * If more than one alias changed at once, it is recommended to use * tp_names_mixin_local_aliases_changed() instead. * @@ -1290,61 +1387,3 @@ tp_names_mixin_one_local_alias_changed (TpBaseConnection *base, tp_names_mixin_local_aliases_changed (base, table); g_hash_table_unref (table); } - -/** - * tp_names_mixin_drop: (skip) - * @base: a #TpBaseConnection that uses this mixin - * @contact: A contact #TpHandle - * - * To be called to free allocated memory when the contact's names (nickname and - * local alias) are not relevant anymore. For example when the contact is - * removed from roster, or when a channel with channel-specific contacts is - * left. - * - * Note that this won't tell the client about the change, so last known name - * will still be displayed. - * - * Since: 0.UNRELEASED - */ -void -tp_names_mixin_drop (TpBaseConnection *base, - TpHandle contact) -{ - TpNamesMixinPrivate *priv = TP_NAMES_MIXIN_GET_PRIVATE (base); - - g_return_if_fail (priv != NULL); - - g_hash_table_remove (priv->nicknames, GUINT_TO_POINTER (contact)); - g_hash_table_remove (priv->local_aliases, GUINT_TO_POINTER (contact)); -} - -/** - * tp_names_mixin_set_storage_type: (skip) - * @base: a #TpBaseConnection that uses this mixin - * @alias_storage: a #TpContactMetadataStorageType - * - * Set the alias storage type. This defines for which contacts we are expected - * to be able to store the local alias on server. - * - * This cannot be called once Connection' status is - * %TP_CONNECTION_STATUS_CONNECTED. - * - * Since: 0.UNRELEASED - */ -void -tp_names_mixin_set_storage_type (TpBaseConnection *base, - TpContactMetadataStorageType alias_storage) -{ - TpNamesInterface *iface = TP_NAMES_INTERFACE_GET_IFACE (base); - TpNamesMixinPrivate *priv = TP_NAMES_MIXIN_GET_PRIVATE (base); - - g_return_if_fail (priv != NULL); - - g_return_if_fail (tp_base_connection_get_status (base) != - TP_CONNECTION_STATUS_CONNECTED); - g_return_if_fail ( - iface->set_local_alias_async != default_set_local_alias_async || - alias_storage == TP_CONTACT_METADATA_STORAGE_TYPE_NONE); - - priv->alias_storage = alias_storage; -} diff --git a/telepathy-glib/names-mixin.h b/telepathy-glib/names-mixin.h index 584bdad2c..f3ca0cedd 100644 --- a/telepathy-glib/names-mixin.h +++ b/telepathy-glib/names-mixin.h @@ -43,6 +43,12 @@ G_BEGIN_DECLS typedef struct _TpNamesInterface TpNamesInterface; +typedef gchar *(*TpNamesInterfaceDupNameFunc) (TpBaseConnection *base, + TpHandle contact); + +typedef TpContactMetadataStorageType (*TpNamesInterfaceGetStorageTypeFunc) ( + TpBaseConnection *base); + typedef void (*TpNamesInterfaceRequestNicknameAsyncFunc) ( TpBaseConnection *base, TpHandle contact, @@ -78,12 +84,17 @@ struct _TpNamesInterface { GTypeInterface parent; + TpNamesInterfaceDupNameFunc dup_nickname; + TpNamesInterfaceRequestNicknameAsyncFunc request_nickname_async; TpNamesInterfaceRequestNicknameFinishFunc request_nickname_finish; TpNamesInterfaceSetNicknameAsyncFunc set_nickname_async; TpNamesInterfaceSetNicknameFinishFunc set_nickname_finish; + TpNamesInterfaceDupNameFunc dup_local_alias; + TpNamesInterfaceGetStorageTypeFunc get_alias_storage; + TpNamesInterfaceSetLocalAliasAsyncFunc set_local_alias_async; TpNamesInterfaceSetLocalAliasFinishFunc set_local_alias_finish; }; @@ -103,12 +114,6 @@ void tp_names_mixin_one_local_alias_changed (TpBaseConnection *base, TpHandle contact, const gchar *local_alias); -void tp_names_mixin_drop (TpBaseConnection *base, - TpHandle contact); - -void tp_names_mixin_set_storage_type (TpBaseConnection *base, - TpContactMetadataStorageType alias_storage); - /* Initialisation */ void tp_names_mixin_init (GObject *object); diff --git a/tests/lib/contacts-conn.c b/tests/lib/contacts-conn.c index d17b7f337..0608b400e 100644 --- a/tests/lib/contacts-conn.c +++ b/tests/lib/contacts-conn.c @@ -87,6 +87,10 @@ enum struct _TpTestsContactsConnectionPrivate { + /* TpHandle => gchar * */ + GHashTable *aliases; + /* TpHandle => gchar * */ + GHashTable *nicknames; /* TpHandle => AvatarData */ GHashTable *avatars; /* TpHandle => ContactsConnectionPresenceStatusIndex */ @@ -152,6 +156,10 @@ tp_tests_contacts_connection_init (TpTestsContactsConnection *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TP_TESTS_TYPE_CONTACTS_CONNECTION, TpTestsContactsConnectionPrivate); + self->priv->nicknames = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, g_free); + self->priv->aliases = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, g_free); self->priv->avatars = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, avatar_data_free); self->priv->presence_statuses = g_hash_table_new_full (g_direct_hash, @@ -172,6 +180,8 @@ finalize (GObject *object) TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (object); tp_contacts_mixin_finalize (object); + g_hash_table_unref (self->priv->aliases); + g_hash_table_unref (self->priv->nicknames); g_hash_table_unref (self->priv->avatars); g_hash_table_unref (self->priv->presence_statuses); g_hash_table_unref (self->priv->presence_messages); @@ -362,6 +372,19 @@ client_types_fill_contact_attributes ( */ } +static gchar * +dup_nickname (TpBaseConnection *base, + TpHandle contact) +{ + TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (base); + + DEBUG ("#%u -> %s", contact, + nonnull (g_hash_table_lookup (self->priv->nicknames, + GUINT_TO_POINTER (contact)))); + return g_strdup (g_hash_table_lookup (self->priv->nicknames, + GUINT_TO_POINTER (contact))); +} + typedef struct { /* (transfer full) */ GSimpleAsyncResult *result; @@ -377,6 +400,8 @@ request_nickname_cb (gpointer data) RequestNicknameAsyncData *rnad = data; TpBaseConnection *base = TP_BASE_CONNECTION (rnad->self); gchar *nickname; + const gchar *old = g_hash_table_lookup (rnad->self->priv->nicknames, + GUINT_TO_POINTER (rnad->contact)); /* Just make something up */ nickname = g_strdup ("default-nickname"); @@ -384,7 +409,15 @@ request_nickname_cb (gpointer data) DEBUG ("contact#%u has nickname: %s", rnad->contact, nickname); g_simple_async_result_set_op_res_gpointer (rnad->result, g_strdup (nickname), g_free); - tp_names_mixin_one_nickname_changed (base, rnad->contact, nickname); + + if (tp_strdiff (old, nickname)) + { + DEBUG ("previously %s", nonnull (old)); + g_hash_table_replace (rnad->self->priv->nicknames, + GUINT_TO_POINTER (rnad->contact), nickname); + tp_names_mixin_one_nickname_changed (base, rnad->contact, nickname); + } + g_simple_async_result_complete_in_idle (rnad->result); g_object_unref (rnad->result); @@ -423,15 +456,29 @@ set_nickname_async (TpBaseConnection *base, gpointer user_data) { TpHandle self_handle = tp_base_connection_get_self_handle (base); + TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (base); GSimpleAsyncResult *result; + const gchar *old; DEBUG ("changing our nickname to %s", nickname); + result = g_simple_async_result_new (G_OBJECT (base), callback, user_data, set_nickname_async); /* In real life, time would pass here. Eventually, setting our own nickname * would succeed, and in a callback, we'd do this: */ - tp_names_mixin_one_nickname_changed (base, self_handle, nickname); + + old = g_hash_table_lookup (self->priv->nicknames, + GUINT_TO_POINTER (self_handle)); + + if (tp_strdiff (old, nickname)) + { + DEBUG ("previously %s", nonnull (old)); + g_hash_table_insert (self->priv->nicknames, + GUINT_TO_POINTER (self_handle), g_strdup (nickname)); + tp_names_mixin_one_nickname_changed (base, self_handle, nickname); + } + g_simple_async_result_complete_in_idle (result); g_object_unref (result); } @@ -443,25 +490,60 @@ set_local_alias_async (TpBaseConnection *base, GAsyncReadyCallback callback, gpointer user_data) { + TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (base); GSimpleAsyncResult *result; + const gchar *old; DEBUG ("changing alias of contact#%u to %s", contact, alias); + result = g_simple_async_result_new (G_OBJECT (base), callback, user_data, set_local_alias_async); /* In real life, time would pass here. Eventually, setting our own local * alias would succeed, and in a callback, we'd do this: */ - tp_names_mixin_one_local_alias_changed (base, contact, alias); + + old = g_hash_table_lookup (self->priv->aliases, GUINT_TO_POINTER (contact)); + + if (tp_strdiff (old, alias)) + { + DEBUG ("previously %s", nonnull (old)); + g_hash_table_insert (self->priv->aliases, + GUINT_TO_POINTER (contact), g_strdup (alias)); + tp_names_mixin_one_local_alias_changed (base, contact, alias); + } + g_simple_async_result_complete_in_idle (result); g_object_unref (result); } +static gchar * +dup_local_alias (TpBaseConnection *base, + TpHandle contact) +{ + TpTestsContactsConnection *self = TP_TESTS_CONTACTS_CONNECTION (base); + + DEBUG ("#%u -> %s", contact, + nonnull (g_hash_table_lookup (self->priv->aliases, + GUINT_TO_POINTER (contact)))); + return g_strdup (g_hash_table_lookup (self->priv->aliases, + GUINT_TO_POINTER (contact))); +} + +static TpContactMetadataStorageType +get_alias_storage (TpBaseConnection *base) +{ + return TP_CONTACT_METADATA_STORAGE_TYPE_ANYONE; +} + static void init_names (gpointer g_iface, gpointer iface_data) { TpNamesInterface *iface = g_iface; + iface->dup_nickname = dup_nickname; + iface->dup_local_alias = dup_local_alias; + iface->get_alias_storage = get_alias_storage; iface->request_nickname_async = request_nickname_async; iface->set_nickname_async = set_nickname_async; iface->set_local_alias_async = set_local_alias_async; @@ -505,8 +587,6 @@ constructed (GObject *object) tp_names_mixin_init (object); tp_names_mixin_register_with_contacts_mixin (object); - tp_names_mixin_set_storage_type (base, - TP_CONTACT_METADATA_STORAGE_TYPE_ANYONE); } static const TpPresenceStatusOptionalArgumentSpec can_have_message[] = { @@ -724,6 +804,8 @@ tp_tests_contacts_connection_change_aliases (TpTestsContactsConnection *self, table = g_hash_table_new (NULL, NULL); for (i = 0; i < n; i++) { + g_hash_table_insert (self->priv->aliases, GUINT_TO_POINTER (handles[i]), + g_strdup (aliases[i])); g_hash_table_insert (table, GUINT_TO_POINTER (handles[i]), (gchar *) aliases[i]); } @@ -752,6 +834,8 @@ tp_tests_contacts_connection_change_nicknames (TpTestsContactsConnection *self, table = g_hash_table_new (NULL, NULL); for (i = 0; i < n; i++) { + g_hash_table_insert (self->priv->nicknames, GUINT_TO_POINTER (handles[i]), + g_strdup (nicknames[i])); g_hash_table_insert (table, GUINT_TO_POINTER (handles[i]), (gchar *) nicknames[i]); } diff --git a/tests/lib/debug.h b/tests/lib/debug.h index 60e070b4c..0f14a8bad 100644 --- a/tests/lib/debug.h +++ b/tests/lib/debug.h @@ -1,3 +1,11 @@ #undef DEBUG #define DEBUG(format, ...) \ g_debug ("%s: " format, G_STRFUNC, ##__VA_ARGS__) + +static inline const char *nonnull (const char *s) +{ + if (s == NULL) + return "(null)"; + + return s; +} |