[empathy] Remove usage of EmpathyTpGroup from EmpathyTpContactList



commit 2e5dc5d7b1449383f3b9e1e9987f2162f3bece84
Author: Xavier Claessens <xclaesse gmail com>
Date:   Sat Feb 14 17:20:28 2009 +0100

    Remove usage of EmpathyTpGroup from EmpathyTpContactList
---
 libempathy/empathy-tp-contact-list.c | 1176 ++++++++++++++++++----------------
 1 files changed, 610 insertions(+), 566 deletions(-)

diff --git a/libempathy/empathy-tp-contact-list.c b/libempathy/empathy-tp-contact-list.c
index f9d073b..4937f56 100644
--- a/libempathy/empathy-tp-contact-list.c
+++ b/libempathy/empathy-tp-contact-list.c
@@ -1,7 +1,7 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
  * Copyright (C) 2007 Xavier Claessens <xclaesse gmail com>
- * Copyright (C) 2007-2008 Collabora Ltd.
+ * Copyright (C) 2007-2009 Collabora Ltd.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -31,8 +31,8 @@
 #include <telepathy-glib/dbus.h>
 
 #include "empathy-tp-contact-list.h"
+#include "empathy-tp-contact-factory.h"
 #include "empathy-contact-list.h"
-#include "empathy-tp-group.h"
 #include "empathy-utils.h"
 
 #define DEBUG_FLAG EMPATHY_DEBUG_TP | EMPATHY_DEBUG_CONTACT
@@ -40,17 +40,15 @@
 
 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyTpContactList)
 typedef struct {
+	EmpathyTpContactFactory *factory;
 	TpConnection   *connection;
 	const gchar    *protocol_group;
-	gboolean        ready;
 
-	EmpathyTpGroup *publish;
-	EmpathyTpGroup *subscribe;
-	GList          *members;
-	GList          *pendings;
-
-	GList          *groups;
-	GHashTable     *contacts_groups;
+	TpChannel      *publish;
+	TpChannel      *subscribe;
+	GHashTable     *members;
+	GHashTable     *pendings;
+	GHashTable     *groups;
 } EmpathyTpContactListPriv;
 
 typedef enum {
@@ -71,520 +69,587 @@ G_DEFINE_TYPE_WITH_CODE (EmpathyTpContactList, empathy_tp_contact_list, G_TYPE_O
 						tp_contact_list_iface_init));
 
 static void
-tp_contact_list_group_destroy_cb (EmpathyTpGroup       *group,
-				  EmpathyTpContactList *list)
+tp_contact_list_group_invalidated_cb (TpChannel *channel,
+				      guint      domain,
+				      gint       code,
+				      gchar     *message,
+				      EmpathyTpContactList *list)
 {
 	EmpathyTpContactListPriv *priv = GET_PRIV (list);
+	const TpIntSet *members;
+	TpIntSetIter iter;
+	const gchar *group_name;
+
+	group_name = tp_channel_get_identifier (channel);
+	DEBUG ("Group %s invalidated. Message: %s", group_name, message);
+
+	/* Signal that all members are not in that group anymore */
+	members = tp_channel_group_get_members (channel);
+	tp_intset_iter_init (&iter, members);
+	while (tp_intset_iter_next (&iter)) {
+		EmpathyContact *contact;
+
+		contact = g_hash_table_lookup (priv->members,
+					       GUINT_TO_POINTER (iter.element));
+		if (contact == NULL) {
+			continue;
+		}
 
-	DEBUG ("Group destroyed: %s", empathy_tp_group_get_name (group));
+		DEBUG ("Contact %s (%d) removed from group %s",
+			empathy_contact_get_id (contact), iter.element,
+			group_name);
+		g_signal_emit_by_name (list, "groups-changed", contact,
+				       group_name,
+				       FALSE);
+	}
 
-	priv->groups = g_list_remove (priv->groups, group);
-	g_object_unref (group);
+	g_hash_table_remove (priv->groups, group_name);
 }
 
 static void
-tp_contact_list_group_member_added_cb (EmpathyTpGroup       *group,
-				       EmpathyContact       *contact,
-				       EmpathyContact       *actor,
-				       guint                 reason,
-				       const gchar          *message,
-				       EmpathyTpContactList *list)
+tp_contact_list_group_ready_cb (TpChannel *channel,
+				const GError *error,
+				gpointer list)
 {
-	EmpathyTpContactListPriv  *priv = GET_PRIV (list);
-	const gchar               *group_name;
-	GList                    **groups;
+	EmpathyTpContactListPriv *priv = GET_PRIV (list);
 
-	if (!g_list_find (priv->members, contact)) {
+	if (error) {
+		DEBUG ("Error: %s", error->message);
+		g_object_unref (channel);
 		return;
 	}
+	
+	DEBUG ("Add group %s", tp_channel_get_identifier (channel));
+	g_hash_table_insert (priv->groups,
+			     (gpointer) tp_channel_get_identifier (channel),
+			     channel);
 
-	groups = g_hash_table_lookup (priv->contacts_groups, contact);
-	if (!groups) {
-		groups = g_slice_new0 (GList*);
-		g_hash_table_insert (priv->contacts_groups,
-				     g_object_ref (contact),
-				     groups);
-	}
-
-	group_name = empathy_tp_group_get_name (group);
-	if (!g_list_find_custom (*groups, group_name, (GCompareFunc) strcmp)) {
-		DEBUG ("Contact %s (%d) added to group %s",
-			empathy_contact_get_id (contact),
-			empathy_contact_get_handle (contact),
-			group_name);
-		*groups = g_list_prepend (*groups, g_strdup (group_name));
-		g_signal_emit_by_name (list, "groups-changed", contact,
-				       group_name,
-				       TRUE);
-	}
+	g_signal_connect (channel, "invalidated",
+			  G_CALLBACK (tp_contact_list_group_invalidated_cb),
+			  list);
 }
 
 static void
-tp_contact_list_group_member_removed_cb (EmpathyTpGroup       *group,
-					 EmpathyContact       *contact,
-					 EmpathyContact       *actor,
-					 guint                 reason,
-					 const gchar          *message,
-					 EmpathyTpContactList *list)
+tp_contact_list_group_members_changed_cb (TpChannel     *channel,
+					  gchar         *message,
+					  GArray        *added,
+					  GArray        *removed,
+					  GArray        *local_pending,
+					  GArray        *remote_pending,
+					  guint          actor,
+					  guint          reason,
+					  EmpathyTpContactList *list)
 {
 	EmpathyTpContactListPriv  *priv = GET_PRIV (list);
-	const gchar               *group_name;
-	GList                    **groups, *l;
+	const gchar *group_name;
+	gint i;
 
-	if (!g_list_find (priv->members, contact)) {
-		return;
-	}
+	group_name = tp_channel_get_identifier (channel);
 
-	groups = g_hash_table_lookup (priv->contacts_groups, contact);
-	if (!groups) {
-		return;
-	}
+	for (i = 0; i < added->len; i++) {
+		EmpathyContact *contact;
+		TpHandle handle;
+
+		handle = g_array_index (added, TpHandle, i);
+		contact = g_hash_table_lookup (priv->members,
+					       GUINT_TO_POINTER (handle));
+		if (contact == NULL) {
+			continue;
+		}
+
+		DEBUG ("Contact %s (%d) added to group %s",
+			empathy_contact_get_id (contact), handle, group_name);
+		g_signal_emit_by_name (list, "groups-changed", contact,
+				       group_name,
+				       TRUE);
+	}	
+
+	for (i = 0; i < removed->len; i++) {
+		EmpathyContact *contact;
+		TpHandle handle;
+
+		handle = g_array_index (removed, TpHandle, i);
+		contact = g_hash_table_lookup (priv->members,
+					       GUINT_TO_POINTER (handle));
+		if (contact == NULL) {
+			continue;
+		}
 
-	group_name = empathy_tp_group_get_name (group);
-	if ((l = g_list_find_custom (*groups, group_name, (GCompareFunc) strcmp))) {
 		DEBUG ("Contact %s (%d) removed from group %s",
-			empathy_contact_get_id (contact),
-			empathy_contact_get_handle (contact),
-			group_name);
-		g_free (l->data);
-		*groups = g_list_delete_link (*groups, l);
+			empathy_contact_get_id (contact), handle, group_name);
+
 		g_signal_emit_by_name (list, "groups-changed", contact,
 				       group_name,
 				       FALSE);
-	}
+	}	
 }
 
-static EmpathyTpGroup *
-tp_contact_list_find_group (EmpathyTpContactList *list,
-			    const gchar          *group)
+static TpChannel *
+tp_contact_list_group_add_channel (EmpathyTpContactList *list,
+				   const gchar          *object_path,
+				   const gchar          *channel_type,
+				   TpHandleType          handle_type,
+				   guint                 handle)
 {
 	EmpathyTpContactListPriv *priv = GET_PRIV (list);
-	GList                    *l;
+	TpChannel                *channel;
 
-	for (l = priv->groups; l; l = l->next) {
-		if (!tp_strdiff (group, empathy_tp_group_get_name (l->data))) {
-			return l->data;
-		}
+	/* Only accept server-side contact groups */
+	if (tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_CONTACT_LIST) ||
+	    handle_type != TP_HANDLE_TYPE_GROUP) {
+		return NULL;
 	}
-	return NULL;
+
+	channel = tp_channel_new (priv->connection,
+				  object_path, channel_type,
+				  handle_type, handle, NULL);
+
+	/* TpChannel emits initial set of members just before being ready */
+	g_signal_connect (channel, "group-members-changed",
+			  G_CALLBACK (tp_contact_list_group_members_changed_cb),
+			  list);
+
+	/* Give the ref to the callback */
+	tp_channel_call_when_ready (channel,
+				    tp_contact_list_group_ready_cb,
+				    list);
+
+	return channel;
 }
 
-static TpContactListType
-tp_contact_list_get_type (EmpathyTpContactList *list,
-			  EmpathyTpGroup       *group)
+typedef struct {
+	GArray *handles;
+	TpHandle channel_handle;
+	guint ref_count;
+} GroupAddData;
+
+static void
+tp_contact_list_group_add_data_unref (gpointer user_data)
 {
-	const gchar *name;
+	GroupAddData *data = user_data;
 
-	name = empathy_tp_group_get_name (group);
-	if (!tp_strdiff (name, "subscribe")) {
-		return TP_CONTACT_LIST_TYPE_SUBSCRIBE;
-	} else if (!tp_strdiff (name, "publish")) {
-		return TP_CONTACT_LIST_TYPE_PUBLISH;
+	if (--data->ref_count == 0) {
+		g_array_free (data->handles, TRUE);
+		g_slice_free (GroupAddData, data);
 	}
-
-	return TP_CONTACT_LIST_TYPE_UNKNOWN;
 }
 
 static void
-tp_contact_list_add_member (EmpathyTpContactList *list,
-			    EmpathyContact       *contact,
-			    EmpathyContact       *actor,
-			    guint                 reason,
-			    const gchar          *message)
+tp_contact_list_group_add_ready_cb (TpChannel    *channel,
+				    const GError *error,
+				    gpointer      user_data)
 {
-	EmpathyTpContactListPriv *priv = GET_PRIV (list);
-	GList                    *l;
+	GroupAddData *data = user_data;
 
-	/* Add to the list and emit signal */
-	priv->members = g_list_prepend (priv->members, g_object_ref (contact));
-	g_signal_emit_by_name (list, "members-changed",
-			       contact, actor, reason, message,
-			       TRUE);
-
-	/* This contact is now member, implicitly accept pending. */
-	if (g_list_find (priv->pendings, contact)) {
-		empathy_tp_group_add_member (priv->publish, contact, "");
+	if (error) {
+		tp_contact_list_group_add_data_unref (data);
+		return;
 	}
 
-	/* Update groups of the contact */
-	for (l = priv->groups; l; l = l->next) {
-		if (empathy_tp_group_is_member (l->data, contact)) {
-			tp_contact_list_group_member_added_cb (l->data, contact,
-							       NULL, 0, NULL, 
-							       list);
-		}
-	}
+	tp_cli_channel_interface_group_call_add_members (channel, -1,
+		data->handles, NULL, NULL, NULL, NULL, NULL);
+	tp_contact_list_group_add_data_unref (data);
 }
 
 static void
-tp_contact_list_added_cb (EmpathyTpGroup       *group,
-			  EmpathyContact       *contact,
-			  EmpathyContact       *actor,
-			  guint                 reason,
-			  const gchar          *message,
-			  EmpathyTpContactList *list)
+tp_contact_list_group_request_channel_cb (TpConnection *connection,
+					  const gchar  *object_path,
+					  const GError *error,
+					  gpointer      user_data,
+					  GObject      *list)
 {
-	EmpathyTpContactListPriv *priv = GET_PRIV (list);
-	TpContactListType         list_type;
-
-	list_type = tp_contact_list_get_type (list, group);
-	DEBUG ("Contact %s (%d) added to list type %d",
-		empathy_contact_get_id (contact),
-		empathy_contact_get_handle (contact),
-		list_type);
-
-	/* We now get the presence of that contact, add it to members */
-	if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE &&
-	    !g_list_find (priv->members, contact)) {
-		tp_contact_list_add_member (list, contact, actor, reason, message);
+	GroupAddData *data = user_data;
+	TpChannel *channel;
+
+	if (error) {
+		DEBUG ("Error: %s", error->message);
+		return;
 	}
 
-	/* We now send our presence to that contact, remove it from pendings */
-	if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH &&
-	    g_list_find (priv->pendings, contact)) {
-		g_signal_emit_by_name (list, "pendings-changed",
-				       contact, actor, reason, message,
-				       FALSE);
-		priv->pendings = g_list_remove (priv->pendings, contact);
-		g_object_unref (contact);
+	channel = tp_contact_list_group_add_channel (EMPATHY_TP_CONTACT_LIST (list),
+						     object_path,
+						     TP_IFACE_CHANNEL_TYPE_CONTACT_LIST,
+						     TP_HANDLE_TYPE_GROUP,
+						     data->channel_handle);
+
+	data->ref_count++;
+	tp_channel_call_when_ready (channel,
+				    tp_contact_list_group_add_ready_cb,
+				    data);
+}
+
+static void
+tp_contact_list_group_request_handles_cb (TpConnection *connection,
+					  const GArray *handles,
+					  const GError *error,
+					  gpointer      user_data,
+					  GObject      *list)
+{
+	GroupAddData *data = user_data;
+
+	if (error) {
+		DEBUG ("Error: %s", error->message);
+		return;
 	}
+
+	data->channel_handle = g_array_index (handles, TpHandle, 1);
+	data->ref_count++;
+	tp_cli_connection_call_request_channel (connection, -1,
+						TP_IFACE_CHANNEL_TYPE_CONTACT_LIST,
+						TP_HANDLE_TYPE_GROUP,
+						data->channel_handle,
+						TRUE,
+						tp_contact_list_group_request_channel_cb,
+						data, tp_contact_list_group_add_data_unref,
+						list);
 }
 
 static void
-tp_contact_list_removed_cb (EmpathyTpGroup       *group,
-			    EmpathyContact       *contact,
-			    EmpathyContact       *actor,
-			    guint                 reason,
-			    const gchar          *message,
-			    EmpathyTpContactList *list)
+tp_contact_list_group_add (EmpathyTpContactList *list,
+			   const gchar          *group_name,
+			   GArray               *handles)
 {
 	EmpathyTpContactListPriv *priv = GET_PRIV (list);
-	TpContactListType         list_type;
-
-	list_type = tp_contact_list_get_type (list, group);
-	DEBUG ("Contact %s (%d) removed from list type %d",
-		empathy_contact_get_id (contact),
-		empathy_contact_get_handle (contact),
-		list_type);
-
-	/* This contact refuses to send us his presence, remove from members. */
-	if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE &&
-	    g_list_find (priv->members, contact)) {
-		g_signal_emit_by_name (list, "members-changed",
-				       contact, actor, reason, message,
-				       FALSE);
-		priv->members = g_list_remove (priv->members, contact);
-		g_object_unref (contact);
+	TpChannel                *channel;
+	const gchar              *names[] = {group_name, NULL};
+	GroupAddData             *data;
+
+	channel = g_hash_table_lookup (priv->groups, group_name);
+	if (channel) {
+		tp_cli_channel_interface_group_call_add_members (channel, -1,
+			handles, NULL, NULL, NULL, NULL, NULL);
+		g_array_free (handles, TRUE);
+		return;
 	}
 
-	/* We refuse to send our presence to that contact, remove from pendings */
-	if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH &&
-	    g_list_find (priv->pendings, contact)) {
-		g_signal_emit_by_name (list, "pendings-changed",
-				       contact, actor, reason, message,
-				       FALSE);
-		priv->pendings = g_list_remove (priv->pendings, contact);
-		g_object_unref (contact);
-	}
+	data = g_slice_new0 (GroupAddData);
+	data->handles = handles;
+	data->ref_count = 1;
+	tp_cli_connection_call_request_handles (priv->connection, -1,
+						TP_HANDLE_TYPE_GROUP, names,
+						tp_contact_list_group_request_handles_cb,
+						data, tp_contact_list_group_add_data_unref,
+						G_OBJECT (list));
 }
 
 static void
-tp_contact_list_pending_cb (EmpathyTpGroup       *group,
-			    EmpathyContact       *contact,
-			    EmpathyContact       *actor,
-			    guint                 reason,
-			    const gchar          *message,
-			    EmpathyTpContactList *list)
+tp_contact_list_got_added_members_cb (EmpathyTpContactFactory *factory,
+				      GList                   *contacts,
+				      gpointer                 user_data,
+				      GObject                 *list)
 {
 	EmpathyTpContactListPriv *priv = GET_PRIV (list);
-	TpContactListType         list_type;
+	GList *l;
 
-	list_type = tp_contact_list_get_type (list, group);
-	DEBUG ("Contact %s (%d) pending in list type %d",
-		empathy_contact_get_id (contact),
-		empathy_contact_get_handle (contact),
-		list_type);
+	for (l = contacts; l; l = l->next) {
+		EmpathyContact *contact = l->data;
+		TpHandle handle;
 
-	/* We want this contact in our contact list but we don't get its 
-	 * presence yet. Add to members anyway. */
-	if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE &&
-	    !g_list_find (priv->members, contact)) {
-		tp_contact_list_add_member (list, contact, actor, reason, message);
-	}
+		handle = empathy_contact_get_handle (contact);
+		if (g_hash_table_lookup (priv->members, GUINT_TO_POINTER (handle)))
+			continue;
+
+		/* Add to the list and emit signal */
+		g_hash_table_insert (priv->members, GUINT_TO_POINTER (handle),
+				     g_object_ref (contact));
+		g_signal_emit_by_name (list, "members-changed", contact,
+				       0, 0, NULL, TRUE);
+
+		/* This contact is now member, implicitly accept pending. */
+		if (g_hash_table_lookup (priv->pendings, GUINT_TO_POINTER (handle))) {
+			GArray handles = {(gchar*) &handle, 1};
 
-	/* This contact wants our presence, auto accept if he is member,
-	 * otherwise he is pending. */
-	if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH &&
-	    !g_list_find (priv->pendings, contact)) {
-		if (g_list_find (priv->members, contact)) {
-			empathy_tp_group_add_member (priv->publish, contact, "");
-		} else {
-			priv->pendings = g_list_prepend (priv->pendings,
-							 g_object_ref (contact));
-			g_signal_emit_by_name (list, "pendings-changed",
-					       contact, actor, reason, message,
-					       TRUE);
+			tp_cli_channel_interface_group_call_add_members (priv->publish,
+				-1, &handles, NULL, NULL, NULL, NULL, NULL);
 		}
 	}
 }
 
 static void
-tp_contact_list_group_list_free (GList **groups)
+tp_contact_list_got_local_pending_cb (EmpathyTpContactFactory *factory,
+				      GList                   *contacts,
+				      gpointer                 info,
+				      GObject                 *list)
 {
-	g_list_foreach (*groups, (GFunc) g_free, NULL);
-	g_list_free (*groups);
-	g_slice_free (GList*, groups);
+	EmpathyTpContactListPriv *priv = GET_PRIV (list);
+	GList *l;
+
+	for (l = contacts; l; l = l->next) {
+		EmpathyContact *contact = l->data;
+		TpHandle handle;
+		const gchar *message;
+		TpChannelGroupChangeReason reason;
+
+		handle = empathy_contact_get_handle (contact);
+		if (g_hash_table_lookup (priv->members, GUINT_TO_POINTER (handle))) {
+			GArray handles = {(gchar*) &handle, 1};
+
+			/* This contact is already member, auto accept. */
+			tp_cli_channel_interface_group_call_add_members (priv->publish,
+				-1, &handles, NULL, NULL, NULL, NULL, NULL);
+		}
+		else if (tp_channel_group_get_local_pending_info (priv->publish,
+								  handle,
+								  NULL,
+								  &reason,
+								  &message)) {
+			/* Add contact to pendings */
+			g_hash_table_insert (priv->pendings, GUINT_TO_POINTER (handle),
+					     g_object_ref (contact));
+			g_signal_emit_by_name (list, "pendings-changed", contact,
+					       contact, reason, message, TRUE);
+		}
+	}
 }
 
 static void
-tp_contact_list_add_channel (EmpathyTpContactList *list,
-			     const gchar          *object_path,
-			     const gchar          *channel_type,
-			     TpHandleType          handle_type,
-			     guint                 handle)
+tp_contact_list_remove_handle (EmpathyTpContactList *list,
+			       GHashTable *table,
+			       TpHandle handle)
 {
 	EmpathyTpContactListPriv *priv = GET_PRIV (list);
-	TpChannel                *channel;
-	EmpathyTpGroup           *group;
-	const gchar              *group_name;
-	GList                    *contacts, *l;
-
-	if (strcmp (channel_type, TP_IFACE_CHANNEL_TYPE_CONTACT_LIST) != 0 ||
-	    handle_type != TP_HANDLE_TYPE_GROUP) {
+	EmpathyContact *contact;
+	const gchar *signal;
+
+	if (table == priv->pendings)
+		signal = "pendings-changed";
+	else if (table == priv->members)
+		signal = "members-changed";
+	else
 		return;
-	}
 
-	channel = tp_channel_new (priv->connection,
-				  object_path, channel_type,
-				  handle_type, handle, NULL);
+	contact = g_hash_table_lookup (table, GUINT_TO_POINTER (handle));
+	if (contact) {
+		g_object_ref (contact);
+		g_hash_table_remove (table, GUINT_TO_POINTER (handle));
+		g_signal_emit_by_name (list, signal, contact, 0, 0, NULL,
+				       FALSE);
+		g_object_unref (contact);
+	}
+}
 
-	group = empathy_tp_group_new (channel);
-	empathy_run_until_ready (group);
-	g_object_unref (channel);
+static void
+tp_contact_list_publish_group_members_changed_cb (TpChannel     *channel,
+						  gchar         *message,
+						  GArray        *added,
+						  GArray        *removed,
+						  GArray        *local_pending,
+						  GArray        *remote_pending,
+						  TpHandle       actor,
+						  TpChannelGroupChangeReason reason,
+						  EmpathyTpContactList *list)
+{
+	EmpathyTpContactListPriv *priv = GET_PRIV (list);
+	guint i;
 
-	/* Check if already exists */
-	group_name = empathy_tp_group_get_name (group);
-	if (tp_contact_list_find_group (list, group_name)) {
-		g_object_unref (group);
-		return;
+	/* We now send our presence to those contacts, remove them from pendings */
+	for (i = 0; i < added->len; i++) {
+		tp_contact_list_remove_handle (list, priv->pendings,
+			g_array_index (added, TpHandle, i));
 	}
 
-	/* Add the group */
-	DEBUG ("New server-side group: %s", group_name);
-	priv->groups = g_list_prepend (priv->groups, group);
-	g_signal_connect (group, "member-added",
-			  G_CALLBACK (tp_contact_list_group_member_added_cb),
-			  list);
-	g_signal_connect (group, "member-removed",
-			  G_CALLBACK (tp_contact_list_group_member_removed_cb),
-			  list);
-	g_signal_connect (group, "destroy",
-			  G_CALLBACK (tp_contact_list_group_destroy_cb),
-			  list);
+	/* We refuse to send our presence to those contacts, remove from pendings */
+	for (i = 0; i < removed->len; i++) {
+		tp_contact_list_remove_handle (list, priv->pendings,
+			g_array_index (added, TpHandle, i));
+	}
 
-	/* Get initial members */
-	contacts = empathy_tp_group_get_members (group);
-	for (l = contacts; l; l = l->next) {
-		tp_contact_list_group_member_added_cb (group, l->data,
-						       NULL, 0, NULL,
-						       list);
-		g_object_unref (l->data);
+	/* Those contacts want our presence, auto accept those that are already
+	 * member, otherwise add in pendings. */
+	if (local_pending->len > 0) {
+		empathy_tp_contact_factory_get_from_handles (priv->factory,
+			local_pending->len, (TpHandle*) local_pending->data,
+			tp_contact_list_got_local_pending_cb, NULL, NULL,
+			G_OBJECT (list));
 	}
-	g_list_free (contacts);
 }
 
 static void
-tp_contact_list_new_channel_cb (TpConnection *proxy,
-				const gchar  *object_path,
-				const gchar  *channel_type,
-				guint         handle_type,
-				guint         handle,
-				gboolean      suppress_handler,
-				gpointer      user_data,
-				GObject      *list)
+tp_contact_list_publish_request_channel_cb (TpConnection *connection,
+					    const gchar  *object_path,
+					    const GError *error,
+					    gpointer      user_data,
+					    GObject      *list)
 {
 	EmpathyTpContactListPriv *priv = GET_PRIV (list);
 
-	if (!suppress_handler && priv->ready) {
-		tp_contact_list_add_channel (EMPATHY_TP_CONTACT_LIST (list),
-					     object_path, channel_type,
-					     handle_type, handle);
+	if (error) {
+		DEBUG ("Error: %s", error->message);
+		return;
 	}
+
+	priv->publish = tp_channel_new (connection, object_path,
+					TP_IFACE_CHANNEL_TYPE_CONTACT_LIST,
+					TP_HANDLE_TYPE_LIST,
+					GPOINTER_TO_UINT (user_data),
+					NULL);
+
+	/* TpChannel emits initial set of members just before being ready */
+	g_signal_connect (priv->publish, "group-members-changed",
+			  G_CALLBACK (tp_contact_list_publish_group_members_changed_cb),
+			  list);
 }
 
 static void
-tp_contact_list_list_channels_cb (TpConnection    *connection,
-				  const GPtrArray *channels,
-				  const GError    *error,
-				  gpointer         user_data,
-				  GObject         *list)
+tp_contact_list_publish_request_handle_cb (TpConnection *connection,
+					   const GArray *handles,
+					   const GError *error,
+					   gpointer      user_data,
+					   GObject      *list)
 {
-	EmpathyTpContactListPriv *priv = GET_PRIV (list);
-	guint                     i;
+	TpHandle handle;
 
 	if (error) {
 		DEBUG ("Error: %s", error->message);
 		return;
 	}
 
-	for (i = 0; i < channels->len; i++) {
-		GValueArray  *chan_struct;
-		const gchar  *object_path;
-		const gchar  *channel_type;
-		TpHandleType  handle_type;
-		guint         handle;
+	handle = g_array_index (handles, TpHandle, 0);
+	tp_cli_connection_call_request_channel (connection, -1,
+						TP_IFACE_CHANNEL_TYPE_CONTACT_LIST,
+						TP_HANDLE_TYPE_LIST,
+						handle,
+						TRUE,
+						tp_contact_list_publish_request_channel_cb,
+						GUINT_TO_POINTER (handle), NULL,
+						list);
+}
 
-		chan_struct = g_ptr_array_index (channels, i);
-		object_path = g_value_get_boxed (g_value_array_get_nth (chan_struct, 0));
-		channel_type = g_value_get_string (g_value_array_get_nth (chan_struct, 1));
-		handle_type = g_value_get_uint (g_value_array_get_nth (chan_struct, 2));
-		handle = g_value_get_uint (g_value_array_get_nth (chan_struct, 3));
+static void
+tp_contact_list_subscribe_group_members_changed_cb (TpChannel     *channel,
+						    gchar         *message,
+						    GArray        *added,
+						    GArray        *removed,
+						    GArray        *local_pending,
+						    GArray        *remote_pending,
+						    guint          actor,
+						    guint          reason,
+						    EmpathyTpContactList *list)
+{
+	EmpathyTpContactListPriv *priv = GET_PRIV (list);
+	guint i;
+
+	/* We now get the presence of those contacts, add them to members */
+	if (added->len > 0) {
+		empathy_tp_contact_factory_get_from_handles (priv->factory,
+			added->len, (TpHandle*) added->data,
+			tp_contact_list_got_added_members_cb, NULL, NULL,
+			G_OBJECT (list));
+	}
 
-		tp_contact_list_add_channel (EMPATHY_TP_CONTACT_LIST (list),
-					     object_path, channel_type,
-					     handle_type, handle);
+	/* Those contacts refuse to send us their presence, remove from members. */
+	for (i = 0; i < removed->len; i++) {
+		tp_contact_list_remove_handle (list, priv->members,
+			g_array_index (added, TpHandle, i));
 	}
 
-	priv->ready = TRUE;
+	/* We want those contacts in our contact list but we don't get their 
+	 * presence yet. Add to members anyway. */
+	if (remote_pending->len > 0) {
+		empathy_tp_contact_factory_get_from_handles (priv->factory,
+			remote_pending->len, (TpHandle*) remote_pending->data,
+			tp_contact_list_got_added_members_cb, NULL, NULL,
+			G_OBJECT (list));
+	}
 }
 
 static void
-tp_contact_list_request_channel_cb (TpConnection *connection,
-				    const gchar  *object_path,
-				    const GError *error,
-				    gpointer      user_data,
-				    GObject      *weak_object)
+tp_contact_list_subscribe_request_channel_cb (TpConnection *connection,
+					      const gchar  *object_path,
+					      const GError *error,
+					      gpointer      user_data,
+					      GObject      *list)
 {
-	EmpathyTpContactList     *list = EMPATHY_TP_CONTACT_LIST (weak_object);
 	EmpathyTpContactListPriv *priv = GET_PRIV (list);
-	EmpathyTpGroup           *group;
-	TpChannel                *channel;
-	TpContactListType         list_type;
-	GList                    *contacts, *l;
 
 	if (error) {
 		DEBUG ("Error: %s", error->message);
 		return;
 	}
 
-	channel = tp_channel_new (connection, object_path,
-				  TP_IFACE_CHANNEL_TYPE_CONTACT_LIST,
-				  TP_HANDLE_TYPE_LIST,
-				  GPOINTER_TO_UINT (user_data),
-				  NULL);
-	group = empathy_tp_group_new (channel);
-	empathy_run_until_ready (group);
-
-	list_type = tp_contact_list_get_type (list, group);
-	if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH && !priv->publish) {
-		DEBUG ("Got publish list");
-		priv->publish = group;
-
-		/* Publish is the list of contacts to who we send our
-		 * presence. Makes no sense to be in remote-pending */
-		g_signal_connect (group, "local-pending",
-				  G_CALLBACK (tp_contact_list_pending_cb),
-				  list);
-
-		contacts = empathy_tp_group_get_local_pendings (group);
-		for (l = contacts; l; l = l->next) {
-			EmpathyPendingInfo *info = l->data;
-				tp_contact_list_pending_cb (group,
-						    info->member,
-						    info->actor,
-						    0,
-						    info->message,
-						    list);
-			empathy_pending_info_free (info);
-		}
-		g_list_free (contacts);
-	}
-	else if (list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE && !priv->subscribe) {
-		DEBUG ("Got subscribe list");
-		priv->subscribe = group;
-
-		/* Subscribe is the list of contacts from who we
-		 * receive presence. Makes no sense to be in
-		 * local-pending */
-		g_signal_connect (group, "remote-pending",
-				  G_CALLBACK (tp_contact_list_pending_cb),
-				  list);
-
-		contacts = empathy_tp_group_get_remote_pendings (group);
-		for (l = contacts; l; l = l->next) {
-			tp_contact_list_pending_cb (group,
-						    l->data,
-						    NULL, 0,
-						    NULL, list);
-			g_object_unref (l->data);
-		}
-		g_list_free (contacts);
-	} else {
-		DEBUG ("Type of contact list channel unknown or aleady "
-			"have that list: %s",
-			empathy_tp_group_get_name (group));
-		g_object_unref (group);
-		return;
-	}
+	priv->subscribe = tp_channel_new (connection, object_path,
+					  TP_IFACE_CHANNEL_TYPE_CONTACT_LIST,
+					  TP_HANDLE_TYPE_LIST,
+					  GPOINTER_TO_UINT (user_data),
+					  NULL);
 
-	/* For all list types when need to get members */
-	g_signal_connect (group, "member-added",
-			  G_CALLBACK (tp_contact_list_added_cb),
+	/* TpChannel emits initial set of members just before being ready */
+	g_signal_connect (priv->subscribe, "group-members-changed",
+			  G_CALLBACK (tp_contact_list_subscribe_group_members_changed_cb),
 			  list);
-	g_signal_connect (group, "member-removed",
-			  G_CALLBACK (tp_contact_list_removed_cb),
-			  list);
-
-	contacts = empathy_tp_group_get_members (group);
-	for (l = contacts; l; l = l->next) {
-		tp_contact_list_added_cb (group,
-					  l->data,
-					  NULL, 0, NULL,
-					  list);
-		g_object_unref (l->data);
-	}
-	g_list_free (contacts);
 }
 
 static void
-tp_contact_list_request_handle_cb (TpConnection *connection,
-				   const GArray *handles,
-				   const GError *error,
-				   gpointer      user_data,
-				   GObject      *list)
+tp_contact_list_subscribe_request_handle_cb (TpConnection *connection,
+					     const GArray *handles,
+					     const GError *error,
+					     gpointer      user_data,
+					     GObject      *list)
 {
-	guint handle;
+	TpHandle handle;
 
 	if (error) {
 		DEBUG ("Error: %s", error->message);
 		return;
 	}
 
-	handle = g_array_index (handles, guint, 0);
+	handle = g_array_index (handles, TpHandle, 0);
 	tp_cli_connection_call_request_channel (connection, -1,
 						TP_IFACE_CHANNEL_TYPE_CONTACT_LIST,
 						TP_HANDLE_TYPE_LIST,
 						handle,
 						TRUE,
-						tp_contact_list_request_channel_cb,
+						tp_contact_list_subscribe_request_channel_cb,
 						GUINT_TO_POINTER (handle), NULL,
 						list);
 }
 
 static void
-tp_contact_list_request_list (EmpathyTpContactList *list,
-			      const gchar          *type)
+tp_contact_list_new_channel_cb (TpConnection *proxy,
+				const gchar  *object_path,
+				const gchar  *channel_type,
+				guint         handle_type,
+				guint         handle,
+				gboolean      suppress_handler,
+				gpointer      user_data,
+				GObject      *list)
 {
-	EmpathyTpContactListPriv *priv = GET_PRIV (list);
-	const gchar *names[] = {type, NULL};
+	tp_contact_list_group_add_channel (EMPATHY_TP_CONTACT_LIST (list),
+					   object_path, channel_type,
+					   handle_type, handle);
+}
 
-	tp_cli_connection_call_request_handles (priv->connection,
-						-1,
-						TP_HANDLE_TYPE_LIST,
-						names,
-						tp_contact_list_request_handle_cb,
-						NULL, NULL,
-						G_OBJECT (list));
+static void
+tp_contact_list_list_channels_cb (TpConnection    *connection,
+				  const GPtrArray *channels,
+				  const GError    *error,
+				  gpointer         user_data,
+				  GObject         *list)
+{
+	guint i;
+
+	if (error) {
+		DEBUG ("Error: %s", error->message);
+		return;
+	}
+
+	for (i = 0; i < channels->len; i++) {
+		GValueArray  *chan_struct;
+		const gchar  *object_path;
+		const gchar  *channel_type;
+		TpHandleType  handle_type;
+		guint         handle;
+
+		chan_struct = g_ptr_array_index (channels, i);
+		object_path = g_value_get_boxed (g_value_array_get_nth (chan_struct, 0));
+		channel_type = g_value_get_string (g_value_array_get_nth (chan_struct, 1));
+		handle_type = g_value_get_uint (g_value_array_get_nth (chan_struct, 2));
+		handle = g_value_get_uint (g_value_array_get_nth (chan_struct, 3));
+
+		tp_contact_list_group_add_channel (EMPATHY_TP_CONTACT_LIST (list),
+						   object_path, channel_type,
+						   handle_type, handle);
+	}
 }
 
 static void
@@ -592,6 +657,8 @@ tp_contact_list_finalize (GObject *object)
 {
 	EmpathyTpContactListPriv *priv;
 	EmpathyTpContactList     *list;
+	GHashTableIter            iter;
+	gpointer                  channel;
 
 	list = EMPATHY_TP_CONTACT_LIST (object);
 	priv = GET_PRIV (list);
@@ -609,13 +676,19 @@ tp_contact_list_finalize (GObject *object)
 		g_object_unref (priv->connection);
 	}
 
-	g_hash_table_destroy (priv->contacts_groups);
-	g_list_foreach (priv->groups, (GFunc) g_object_unref, NULL);
-	g_list_free (priv->groups);
-	g_list_foreach (priv->members, (GFunc) g_object_unref, NULL);
-	g_list_free (priv->members);
-	g_list_foreach (priv->pendings, (GFunc) g_object_unref, NULL);
-	g_list_free (priv->pendings);
+	if (priv->factory) {
+		g_object_unref (priv->factory);
+	}
+
+	g_hash_table_iter_init (&iter, priv->groups);
+	while (g_hash_table_iter_next (&iter, NULL, &channel)) {
+		g_signal_handlers_disconnect_by_func (channel,
+			tp_contact_list_group_invalidated_cb, list);
+	}
+
+	g_hash_table_destroy (priv->groups);
+	g_hash_table_destroy (priv->members);
+	g_hash_table_destroy (priv->pendings);
 
 	G_OBJECT_CLASS (empathy_tp_contact_list_parent_class)->finalize (object);
 }
@@ -626,9 +699,24 @@ tp_contact_list_constructed (GObject *list)
 
 	EmpathyTpContactListPriv *priv = GET_PRIV (list);
 	const gchar              *protocol_name = NULL;
+	const gchar              *names[] = {NULL, NULL};
 
-	tp_contact_list_request_list (EMPATHY_TP_CONTACT_LIST (list), "publish");
-	tp_contact_list_request_list (EMPATHY_TP_CONTACT_LIST (list), "subscribe");
+	names[0] = "publish";
+	tp_cli_connection_call_request_handles (priv->connection,
+						-1,
+						TP_HANDLE_TYPE_LIST,
+						names,
+						tp_contact_list_publish_request_handle_cb,
+						NULL, NULL,
+						G_OBJECT (list));
+	names[0] = "subscribe";
+	tp_cli_connection_call_request_handles (priv->connection,
+						-1,
+						TP_HANDLE_TYPE_LIST,
+						names,
+						tp_contact_list_subscribe_request_handle_cb,
+						NULL, NULL,
+						G_OBJECT (list));
 
 	tp_cli_connection_call_list_channels (priv->connection, -1,
 					      tp_contact_list_list_channels_cb,
@@ -714,10 +802,22 @@ empathy_tp_contact_list_init (EmpathyTpContactList *list)
 		EMPATHY_TYPE_TP_CONTACT_LIST, EmpathyTpContactListPriv);
 
 	list->priv = priv;
-	priv->contacts_groups = g_hash_table_new_full (g_direct_hash,
-						       g_direct_equal,
-						       (GDestroyNotify) g_object_unref,
-						       (GDestroyNotify) tp_contact_list_group_list_free);
+	priv->factory = empathy_tp_contact_factory_dup_singleton (priv->connection);
+
+	/* Map group's name to group's channel */
+	priv->groups = g_hash_table_new_full (g_str_hash, g_str_equal,
+					      NULL,
+					      (GDestroyNotify) g_object_unref);
+
+	/* Map contact's handle to EmpathyContact object */
+	priv->members = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+					       NULL,
+					       (GDestroyNotify) g_object_unref);
+
+	/* Map contact's handle to EmpathyContact object */
+	priv->pendings = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+						NULL,
+						(GDestroyNotify) g_object_unref);
 }
 
 EmpathyTpContactList *
@@ -746,15 +846,13 @@ tp_contact_list_add (EmpathyContactList *list,
 		     const gchar        *message)
 {
 	EmpathyTpContactListPriv *priv = GET_PRIV (list);
+	TpHandle handle;
+	GArray handles = {(gchar *) &handle, 1};
 
-	g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
-
+	handle = empathy_contact_get_handle (contact);
 	if (priv->subscribe) {
-		empathy_tp_group_add_member (priv->subscribe, contact, message);
-	}
-
-	if (priv->publish && g_list_find (priv->pendings, contact)) {
-		empathy_tp_group_add_member (priv->publish, contact, message);		
+		tp_cli_channel_interface_group_call_add_members (priv->subscribe,
+			-1, &handles, message, NULL, NULL, NULL, NULL);
 	}
 }
 
@@ -764,14 +862,17 @@ tp_contact_list_remove (EmpathyContactList *list,
 			const gchar        *message)
 {
 	EmpathyTpContactListPriv *priv = GET_PRIV (list);
+	TpHandle handle;
+	GArray handles = {(gchar *) &handle, 1};
 
-	g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
-
+	handle = empathy_contact_get_handle (contact);
 	if (priv->subscribe) {
-		empathy_tp_group_remove_member (priv->subscribe, contact, message);
+		tp_cli_channel_interface_group_call_remove_members (priv->subscribe,
+			-1, &handles, message, NULL, NULL, NULL, NULL);
 	}
 	if (priv->publish) {
-		empathy_tp_group_remove_member (priv->publish, contact, message);		
+		tp_cli_channel_interface_group_call_remove_members (priv->publish,
+			-1, &handles, message, NULL, NULL, NULL, NULL);
 	}
 }
 
@@ -779,44 +880,40 @@ static GList *
 tp_contact_list_get_members (EmpathyContactList *list)
 {
 	EmpathyTpContactListPriv *priv = GET_PRIV (list);
+	GList *ret;
 
-	g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
-
-	g_list_foreach (priv->members, (GFunc) g_object_ref, NULL);
-	return g_list_copy (priv->members);
+	ret = g_hash_table_get_values (priv->members);
+	g_list_foreach (ret, (GFunc) g_object_ref, NULL);
+	return ret;
 }
 
 static GList *
 tp_contact_list_get_pendings (EmpathyContactList *list)
 {
 	EmpathyTpContactListPriv *priv = GET_PRIV (list);
+	GList *ret;
 
-	g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
-
-	g_list_foreach (priv->pendings, (GFunc) g_object_ref, NULL);
-	return g_list_copy (priv->pendings);
+	ret = g_hash_table_get_values (priv->pendings);
+	g_list_foreach (ret, (GFunc) g_object_ref, NULL);
+	return ret;
 }
 
 static GList *
 tp_contact_list_get_all_groups (EmpathyContactList *list)
 {
 	EmpathyTpContactListPriv *priv = GET_PRIV (list);
-	GList                    *groups = NULL, *l;
+	GList                    *ret, *l;
 
-	g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
-
-	if (priv->protocol_group) {
-		groups = g_list_prepend (groups, g_strdup (priv->protocol_group));
+	ret = g_hash_table_get_keys (priv->groups);
+	for (l = ret; l; l = l->next) {
+		l->data = g_strdup (l->data);
 	}
 
-	for (l = priv->groups; l; l = l->next) {
-		const gchar *name;
-
-		name = empathy_tp_group_get_name (l->data);
-		groups = g_list_prepend (groups, g_strdup (name));
+	if (priv->protocol_group) {
+		ret = g_list_prepend (ret, g_strdup (priv->protocol_group));
 	}
 
-	return groups;
+	return ret;
 }
 
 static GList *
@@ -824,174 +921,119 @@ tp_contact_list_get_groups (EmpathyContactList *list,
 			    EmpathyContact     *contact)
 {
 	EmpathyTpContactListPriv  *priv = GET_PRIV (list);
-	GList                    **groups;
-	GList                     *ret = NULL, *l;
-
-	g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
+	GList                     *ret = NULL;
+	GHashTableIter             iter;
+	gpointer                   group_name;
+	gpointer                   channel;
+	TpHandle                   handle;
+
+	handle = empathy_contact_get_handle (contact);
+	g_hash_table_iter_init (&iter, priv->groups);
+	while (g_hash_table_iter_next (&iter, &group_name, &channel)) {
+		const TpIntSet *members;
+
+		members = tp_channel_group_get_members (channel);
+		if (tp_intset_is_member (members, handle)) {
+			ret = g_list_prepend (ret, g_strdup (group_name));
+		}
+	}
 
 	if (priv->protocol_group) {
 		ret = g_list_prepend (ret, g_strdup (priv->protocol_group));
 	}
 
-	groups = g_hash_table_lookup (priv->contacts_groups, contact);
-	if (!groups) {
-		return ret;
-	}
-
-	for (l = *groups; l; l = l->next) {
-		ret = g_list_prepend (ret, g_strdup (l->data));
-	}
-
-
 	return ret;
 }
 
-static EmpathyTpGroup *
-tp_contact_list_get_group (EmpathyTpContactList *list,
-			   const gchar          *group)
-{
-	EmpathyTpContactListPriv *priv = GET_PRIV (list);
-	EmpathyTpGroup           *tp_group;
-	gchar                    *object_path;
-	guint                     handle;
-	GArray                   *handles;
-	const char               *names[2] = {group, NULL};
-	GError                   *error = NULL;
-
-	tp_group = tp_contact_list_find_group (list, group);
-	if (tp_group) {
-		return tp_group;
-	}
-
-	DEBUG ("creating new group: %s", group);
-
-	if (!tp_cli_connection_run_request_handles (priv->connection, -1,
-						    TP_HANDLE_TYPE_GROUP,
-						    names,
-						    &handles,
-						    &error, NULL)) {
-		DEBUG ("Failed to RequestHandles: %s",
-			error ? error->message : "No error given");
-		g_clear_error (&error);
-		return NULL;
-	}
-	handle = g_array_index (handles, guint, 0);
-	g_array_free (handles, TRUE);
-
-	if (!tp_cli_connection_run_request_channel (priv->connection, -1,
-						    TP_IFACE_CHANNEL_TYPE_CONTACT_LIST,
-						    TP_HANDLE_TYPE_GROUP,
-						    handle,
-						    TRUE,
-						    &object_path,
-						    &error, NULL)) {
-		DEBUG ("Failed to RequestChannel: %s",
-			error ? error->message : "No error given");
-		g_clear_error (&error);
-		return NULL;
-	}
-
-	tp_contact_list_add_channel (EMPATHY_TP_CONTACT_LIST (list),
-				     object_path,
-				     TP_IFACE_CHANNEL_TYPE_CONTACT_LIST,
-				     TP_HANDLE_TYPE_GROUP, handle);
-
-	g_free (object_path);
-
-	return tp_contact_list_find_group (list, group);
-}
-
 static void
 tp_contact_list_add_to_group (EmpathyContactList *list,
 			      EmpathyContact     *contact,
-			      const gchar        *group)
+			      const gchar        *group_name)
 {
-	EmpathyTpGroup *tp_group;
-
-	g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
-
-	tp_group = tp_contact_list_get_group (EMPATHY_TP_CONTACT_LIST (list),
-					      group);
-
-	if (tp_group) {
-		empathy_tp_group_add_member (tp_group, contact, "");
-	}
+	TpHandle handle;
+	GArray *handles;
+
+	handle = empathy_contact_get_handle (contact);
+	handles = g_array_sized_new (FALSE, FALSE, sizeof (TpHandle), 1);
+	g_array_append_val (handles, handle);
+	tp_contact_list_group_add (EMPATHY_TP_CONTACT_LIST (list),
+				   group_name, handles);
 }
 
 static void
 tp_contact_list_remove_from_group (EmpathyContactList *list,
 				   EmpathyContact     *contact,
-				   const gchar        *group)
+				   const gchar        *group_name)
 {
-	EmpathyTpGroup *tp_group;
+	EmpathyTpContactListPriv *priv = GET_PRIV (list);
+	TpChannel                *channel;
+	TpHandle                  handle;
+	GArray                    handles = {(gchar *) &handle, 1};
 
-	g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
+	channel = g_hash_table_lookup (priv->groups, group_name);
+	if (channel == NULL) {
+		return;
+	}
 
-	tp_group = tp_contact_list_find_group (EMPATHY_TP_CONTACT_LIST (list),
-					       group);
+	handle = empathy_contact_get_handle (contact);
+	DEBUG ("remove contact %s (%d) from group %s",
+		empathy_contact_get_id (contact), handle, group_name);
 
-	if (tp_group) {
-		empathy_tp_group_remove_member (tp_group, contact, "");
-	}
+	tp_cli_channel_interface_group_call_remove_members (channel, -1,
+		&handles, NULL, NULL, NULL, NULL, NULL);
 }
 
 static void
 tp_contact_list_rename_group (EmpathyContactList *list,
-			      const gchar        *old_group,
-			      const gchar        *new_group)
+			      const gchar        *old_group_name,
+			      const gchar        *new_group_name)
 {
-	EmpathyTpGroup *tp_group;
-	GList          *members;
-
-	g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
+	EmpathyTpContactListPriv *priv = GET_PRIV (list);
+	TpChannel                *channel;
+	const TpIntSet           *members;
+	GArray                   *handles;
 
-	tp_group = tp_contact_list_find_group (EMPATHY_TP_CONTACT_LIST (list),
-					       old_group);
-	if (!tp_group) {
+	channel = g_hash_table_lookup (priv->groups, old_group_name);
+	if (channel == NULL) {
 		return;
 	}
 
-	DEBUG ("rename group %s to %s", old_group, new_group);
-
-	/* Remove all members from the old group */
-	members = empathy_tp_group_get_members (tp_group);
-	empathy_tp_group_remove_members (tp_group, members, "");
-	empathy_tp_group_close (tp_group);
+	DEBUG ("rename group %s to %s", old_group_name, new_group_name);
 
-	/* Add all members to the new group */
-	tp_group = tp_contact_list_get_group (EMPATHY_TP_CONTACT_LIST (list),
-					      new_group);
-	empathy_tp_group_add_members (tp_group, members, "");
+	/* Remove all members and close the old channel */
+	members = tp_channel_group_get_members (channel);
+	handles = tp_intset_to_array (members);
+	tp_cli_channel_interface_group_call_remove_members (channel, -1,
+		handles, NULL, NULL, NULL, NULL, NULL);
+	tp_cli_channel_call_close (channel, -1, NULL, NULL, NULL, NULL);
 
-	g_list_foreach (members, (GFunc) g_object_unref, NULL);
-	g_list_free (members);
+	tp_contact_list_group_add (EMPATHY_TP_CONTACT_LIST (list),
+				   new_group_name, handles);
 }
 
 static void
 tp_contact_list_remove_group (EmpathyContactList *list,
-			      const gchar *group)
+			      const gchar *group_name)
 {
-	EmpathyTpGroup *tp_group;
-	GList	       *members;
-
-	g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
+	EmpathyTpContactListPriv *priv = GET_PRIV (list);
+	TpChannel                *channel;
+	const TpIntSet           *members;
+	GArray                   *handles;
 
-	tp_group = tp_contact_list_find_group (EMPATHY_TP_CONTACT_LIST (list),
-					       group);
-	
-	if (!tp_group) {
+	channel = g_hash_table_lookup (priv->groups, group_name);
+	if (channel == NULL) {
 		return;
 	}
 
-	DEBUG ("remove group %s", group);
-
-	/* Remove all members of the group */
-	members = empathy_tp_group_get_members (tp_group);
-	empathy_tp_group_remove_members (tp_group, members, "");
-	empathy_tp_group_close (tp_group);
+	DEBUG ("remove group %s", group_name);
 
-	g_list_foreach (members, (GFunc) g_object_unref, NULL);
-	g_list_free (members);
+	/* Remove all members and close the channel */
+	members = tp_channel_group_get_members (channel);
+	handles = tp_intset_to_array (members);
+	tp_cli_channel_interface_group_call_remove_members (channel, -1,
+		handles, NULL, NULL, NULL, NULL, NULL);
+	tp_cli_channel_call_close (channel, -1, NULL, NULL, NULL, NULL);
+	g_array_free (handles, TRUE);
 }
 
 static void
@@ -1022,7 +1064,7 @@ empathy_tp_contact_list_can_add (EmpathyTpContactList *list)
 	if (priv->subscribe == NULL)
 		return FALSE;
 
-	flags = empathy_tp_group_get_flags (priv->subscribe);
+	flags = tp_channel_group_get_flags (priv->subscribe);
 	return (flags & TP_CHANNEL_GROUP_FLAG_CAN_ADD) != 0;
 }
 
@@ -1030,24 +1072,26 @@ void
 empathy_tp_contact_list_remove_all (EmpathyTpContactList *list)
 {
 	EmpathyTpContactListPriv *priv = GET_PRIV (list);
-	GList                    *l;
+	GHashTableIter            iter;
+	gpointer                  contact;
+
+	g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
 
 	/* Remove all contacts */
-	for (l = priv->members; l; l = l->next) {
-		g_signal_emit_by_name (list, "members-changed", l->data,
+	g_hash_table_iter_init (&iter, priv->members);
+	while (g_hash_table_iter_next (&iter, NULL, &contact)) {
+		g_signal_emit_by_name (list, "members-changed", contact,
 				       NULL, 0, NULL,
 				       FALSE);
-		g_object_unref (l->data);
 	}
-	for (l = priv->pendings; l; l = l->next) {
-		g_signal_emit_by_name (list, "pendings-changed", l->data,
+	g_hash_table_remove_all (priv->members);
+
+	g_hash_table_iter_init (&iter, priv->pendings);
+	while (g_hash_table_iter_next (&iter, NULL, &contact)) {
+		g_signal_emit_by_name (list, "pendings-changed", contact,
 				       NULL, 0, NULL,
 				       FALSE);
-		g_object_unref (l->data);
 	}
-	g_list_free (priv->members);
-	g_list_free (priv->pendings);
-	priv->members = NULL;
-	priv->pendings = NULL;
+	g_hash_table_remove_all (priv->pendings);
 }
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]