summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon McVittie <simon.mcvittie@collabora.co.uk>2013-01-08 15:09:12 +0000
committerSimon McVittie <simon.mcvittie@collabora.co.uk>2013-01-08 15:09:12 +0000
commit57eaa0241be6ad60ca2a818cb120e4a8243a99ea (patch)
treeced24d2b0474bc3457cec44b4108f57e94d12b55
parent76ca6e930930a711393a1e15fc783512b6ba295b (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.txt4
-rw-r--r--telepathy-glib/names-mixin.c343
-rw-r--r--telepathy-glib/names-mixin.h17
-rw-r--r--tests/lib/contacts-conn.c94
-rw-r--r--tests/lib/debug.h8
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;
+}