static void
contact_list_view_drag_data_received (GtkWidget         *widget,
				      GdkDragContext    *context,
				      gint               x,
				      gint               y,
				      GtkSelectionData  *selection,
				      guint              info,
				      guint              time)
{
	EmpathyContactListViewPriv *priv;
	EmpathyContactList         *list;
	EmpathyContactFactory      *factory;
	McAccount                  *account;
	GtkTreeModel               *model;
	GtkTreePath                *path;
	GtkTreeViewDropPosition     position;
	EmpathyContact             *contact = NULL;
	const gchar                *id;
	gchar                     **strv;
	gchar                      *new_group = NULL;
	gchar                      *old_group = NULL;
	gboolean                    is_row;

	priv = GET_PRIV (widget);

	id = (const gchar*) selection->data;
	DEBUG ("Received %s%s drag & drop contact from roster with id:'%s'",
		context->action == GDK_ACTION_MOVE ? "move" : "",
		context->action == GDK_ACTION_COPY ? "copy" : "",
		id);

	strv = g_strsplit (id, "/", 2);
	factory = empathy_contact_factory_new ();
	account = mc_account_lookup (strv[0]);
	if (account) {
		contact = empathy_contact_factory_get_from_id (factory,
							       account,
							       strv[1]);
		g_object_unref (account);
	}
	g_object_unref (factory);
	g_strfreev (strv);

	if (!contact) {
		DEBUG ("No contact found associated with drag & drop");
		return;
	}

	empathy_contact_run_until_ready (contact,
					 EMPATHY_CONTACT_READY_HANDLE,
					 NULL);

	model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));

	/* Get source group information. */
	if (priv->drag_row) {
		path = gtk_tree_row_reference_get_path (priv->drag_row);
		if (path) {
			old_group = empathy_contact_list_store_get_parent_group (model, path, NULL);
			gtk_tree_path_free (path);
		}
	}

	/* Get destination group information. */
	is_row = gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (widget),
						    x,
						    y,
						    &path,
						    &position);

	if (is_row) {
		new_group = empathy_contact_list_store_get_parent_group (model, path, NULL);
		gtk_tree_path_free (path);
	}

	DEBUG ("contact %s (%d) dragged from '%s' to '%s'",
		empathy_contact_get_id (contact),
		empathy_contact_get_handle (contact),
		old_group, new_group);

	list = empathy_contact_list_store_get_list_iface (priv->store);
	if (new_group) {
		empathy_contact_list_add_to_group (list, contact, new_group);
	}
	if (old_group && context->action == GDK_ACTION_MOVE) {	
		empathy_contact_list_remove_from_group (list, contact, old_group);
	}

	g_free (old_group);
	g_free (new_group);

	gtk_drag_finish (context, TRUE, FALSE, GDK_CURRENT_TIME);
}
static void
contact_list_view_drag_data_received (GtkWidget         *view,
				      GdkDragContext    *context,
				      gint               x,
				      gint               y,
				      GtkSelectionData  *selection,
				      guint              info,
				      guint              time)
{
	EmpathyContactListViewPriv *priv;
	EmpathyAccountManager      *account_manager;
	EmpathyTpContactFactory    *factory = NULL;
	EmpathyAccount             *account;
	GtkTreeModel               *model;
	GtkTreeViewDropPosition     position;
	GtkTreePath                *path;
	const gchar                *id;
	gchar                     **strv = NULL;
	const gchar                *account_id;
	const gchar                *contact_id;
	gchar                      *new_group = NULL;
	gchar                      *old_group = NULL;
	DndGetContactData          *data;
	gboolean                    is_row;
	gboolean                    success = TRUE;

	priv = GET_PRIV (view);
	model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));

	/* Get destination group information. */
	is_row = gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (view),
						    x,
						    y,
						    &path,
						    &position);

	if (is_row) {
		new_group = empathy_contact_list_store_get_parent_group (model,
			path, NULL);
		gtk_tree_path_free (path);
	}

	/* Get source group information. */
	if (priv->drag_row) {
		path = gtk_tree_row_reference_get_path (priv->drag_row);
		if (path) {
			old_group = empathy_contact_list_store_get_parent_group (
				model, path, NULL);
			gtk_tree_path_free (path);
		}
	}

	if (!tp_strdiff (old_group, new_group)) {
		g_free (new_group);
		g_free (old_group);
		goto OUT;
	}

	id = (const gchar*) gtk_selection_data_get_data (selection);
	DEBUG ("Received %s%s drag & drop contact from roster with id:'%s'",
		context->action == GDK_ACTION_MOVE ? "move" : "",
		context->action == GDK_ACTION_COPY ? "copy" : "",
		id);

	strv = g_strsplit (id, "/", 2);
	account_id = strv[0];
	contact_id = strv[1];
  account_manager = empathy_account_manager_dup_singleton ();
	account = empathy_account_manager_lookup (account_manager, account_id);
	if (account) {
		TpConnection *connection;

		connection = empathy_account_get_connection (account);
		if (connection) {
			factory = empathy_tp_contact_factory_dup_singleton (connection);
		}
	}
	g_object_unref (account_manager);

	if (!factory) {
		DEBUG ("Failed to get factory for account '%s'", account_id);
		success = FALSE;
		g_free (new_group);
		g_free (old_group);
		goto OUT;
	}

	data = g_slice_new0 (DndGetContactData);
	data->new_group = new_group;
	data->old_group = old_group;
	data->action = context->action;

	/* FIXME: We should probably wait for the cb before calling
	 * gtk_drag_finish */
	empathy_tp_contact_factory_get_from_id (factory, contact_id,
		contact_list_view_drag_got_contact,
		data, (GDestroyNotify) contact_list_view_dnd_get_contact_free,
		G_OBJECT (view));

	g_object_unref (factory);

OUT:
	g_strfreev (strv);
	gtk_drag_finish (context, success, FALSE, GDK_CURRENT_TIME);
}