telepathygabble/src/group-mixin.c
changeset 10 59927b2d3b75
parent 0 d0f3a028347a
--- a/telepathygabble/src/group-mixin.c	Tue Feb 02 01:10:06 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,785 +0,0 @@
-/*
- * group-mixin.c - Source for GabbleGroupMixin
- * Copyright (C) 2006 Collabora Ltd.
- * 
- *   @author Ole Andre Vadla Ravnaas <ole.andre.ravnaas@collabora.co.uk>
- *   @author Robert McQueen <robert.mcqueen@collabora.co.uk>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#include <dbus/dbus-glib.h>
-#include <stdio.h>
-
-#include "ansi.h"
-#include "debug.h"
-#include "telepathy-errors.h"
-
-
-#include "group-mixin.h"
-#include "group-mixin-signals-marshal.h"
-
-#define DEBUG_FLAG GABBLE_DEBUG_GROUPS
-#ifdef DEBUG_FLAG
-//#define DEBUG(format, ...)
-#define DEBUGGING 0
-#define NODE_DEBUG(n, s)
-#endif /* DEBUG_FLAG */
-
-#ifdef EMULATOR
-#include "libgabble_wsd_solution.h"
-
-	GET_STATIC_VAR_FROM_TLS(offset_quark1,gabble_grp_mixin,GQuark)
-	#define offset_quark1 (*GET_WSD_VAR_NAME(offset_quark1,gabble_grp_mixin, s)())	
-	
-	GET_STATIC_VAR_FROM_TLS(offset_quark,gabble_grp_mixin,GQuark)
-	#define offset_quark (*GET_WSD_VAR_NAME(offset_quark,gabble_grp_mixin, s)())	
-	
-	
-#endif
-
-static const char *group_change_reason_str(guint reason)
-{
-  switch (reason)
-    {
-    case TP_CHANNEL_GROUP_CHANGE_REASON_NONE:
-      return "unspecified reason";
-    case TP_CHANNEL_GROUP_CHANGE_REASON_OFFLINE:
-      return "offline";
-    case TP_CHANNEL_GROUP_CHANGE_REASON_KICKED:
-      return "kicked";
-    case TP_CHANNEL_GROUP_CHANGE_REASON_BUSY:
-      return "busy";
-    case TP_CHANNEL_GROUP_CHANGE_REASON_INVITED:
-      return "invited";
-    case TP_CHANNEL_GROUP_CHANGE_REASON_BANNED:
-      return "banned";
-    default:
-      return "(unknown reason code)";
-    }
-}
-
-struct _GabbleGroupMixinPrivate {
-    GabbleHandleSet *actors;
-    GHashTable *handle_owners;
-};
-
-
-/**
- * gabble_group_mixin_class_get_offset_quark:
- *
- * Returns: the quark used for storing mixin offset on a GObjectClass
- */
-GQuark
-gabble_group_mixin_class_get_offset_quark ()
-{
-#ifndef EMULATOR
-  static GQuark offset_quark1 = 0;
-#endif
-  
-  if (!offset_quark1)
-    offset_quark1 = g_quark_from_static_string("GroupMixinClassOffsetQuark");
-  return offset_quark1;
-}
-
-/**
- * gabble_group_mixin_get_offset_quark:
- *
- * Returns: the quark used for storing mixin offset on a GObject
- */
-GQuark
-gabble_group_mixin_get_offset_quark ()
-{
-#ifndef EMULATOR
-  static GQuark offset_quark = 0;
-#endif
-  
-  if (!offset_quark)
-    offset_quark = g_quark_from_static_string("GroupMixinOffsetQuark");
-  return offset_quark;
-}
-
-void gabble_group_mixin_class_init (GObjectClass *obj_cls,
-                                    glong offset,
-                                    GabbleGroupMixinAddMemberFunc add_func,
-                                    GabbleGroupMixinRemMemberFunc rem_func)
-{
-  GabbleGroupMixinClass *mixin_cls;
-
-  g_assert (G_IS_OBJECT_CLASS (obj_cls));
-
-  g_type_set_qdata (G_OBJECT_CLASS_TYPE (obj_cls),
-                    GABBLE_GROUP_MIXIN_CLASS_OFFSET_QUARK,
-                    GINT_TO_POINTER (offset));
-
-  mixin_cls = GABBLE_GROUP_MIXIN_CLASS (obj_cls);
-
-  mixin_cls->add_member = add_func;
-  mixin_cls->remove_member = rem_func;
-
-  mixin_cls->group_flags_changed_signal_id =
-    g_signal_new ("group-flags-changed",
-                  G_OBJECT_CLASS_TYPE (obj_cls),
-                  G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
-                  0,
-                  NULL, NULL,
-                  group_mixin_marshal_VOID__UINT_UINT,
-                  G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
-
-  mixin_cls->members_changed_signal_id =
-    g_signal_new ("members-changed",
-                  G_OBJECT_CLASS_TYPE (obj_cls),
-                  G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
-                  0,
-                  NULL, NULL,
-                  group_mixin_marshal_VOID__STRING_BOXED_BOXED_BOXED_BOXED_UINT_UINT,
-                  G_TYPE_NONE, 7, G_TYPE_STRING, DBUS_TYPE_G_UINT_ARRAY, DBUS_TYPE_G_UINT_ARRAY, DBUS_TYPE_G_UINT_ARRAY, DBUS_TYPE_G_UINT_ARRAY, G_TYPE_UINT, G_TYPE_UINT);
-}
-
-void gabble_group_mixin_init (GObject *obj,
-                              glong offset,
-                              GabbleHandleRepo *handle_repo,
-                              GabbleHandle self_handle)
-{
-  GabbleGroupMixin *mixin;
-
-  g_assert (G_IS_OBJECT (obj));
-
-  g_type_set_qdata (G_OBJECT_TYPE (obj),
-                    GABBLE_GROUP_MIXIN_OFFSET_QUARK,
-                    GINT_TO_POINTER (offset));
-
-  mixin = GABBLE_GROUP_MIXIN (obj);
-
-  mixin->handle_repo = handle_repo;
-  mixin->self_handle = self_handle;
-
-  mixin->group_flags = 0;
-
-  mixin->members = handle_set_new (handle_repo, TP_HANDLE_TYPE_CONTACT);
-  mixin->local_pending = handle_set_new (handle_repo, TP_HANDLE_TYPE_CONTACT);
-  mixin->remote_pending = handle_set_new (handle_repo, TP_HANDLE_TYPE_CONTACT);
-
-  mixin->priv = g_new0 (GabbleGroupMixinPrivate, 1);
-  mixin->priv->handle_owners = g_hash_table_new (g_direct_hash, g_direct_equal);
-  mixin->priv->actors = handle_set_new (handle_repo, TP_HANDLE_TYPE_CONTACT);
-}
-
-static void
-handle_owners_foreach_unref (gpointer key,
-                             gpointer value,
-                             gpointer user_data)
-{
-  GabbleGroupMixin *mixin = user_data;
-
-  gabble_handle_unref (mixin->handle_repo, TP_HANDLE_TYPE_CONTACT,
-                       GPOINTER_TO_UINT (key));
-  gabble_handle_unref (mixin->handle_repo, TP_HANDLE_TYPE_CONTACT,
-                       GPOINTER_TO_UINT (value));
-}
-
-void gabble_group_mixin_finalize (GObject *obj)
-{
-  GabbleGroupMixin *mixin = GABBLE_GROUP_MIXIN (obj);
-
-  handle_set_destroy (mixin->priv->actors);
-
-  g_hash_table_foreach (mixin->priv->handle_owners,
-                        handle_owners_foreach_unref,
-                        mixin);
-
-  g_hash_table_destroy (mixin->priv->handle_owners);
-
-  g_free (mixin->priv);
-
-  handle_set_destroy (mixin->members);
-  handle_set_destroy (mixin->local_pending);
-  handle_set_destroy (mixin->remote_pending);
-}
-
-gboolean
-gabble_group_mixin_get_self_handle (GObject *obj, guint *ret, GError **error)
-{
-  GabbleGroupMixin *mixin = GABBLE_GROUP_MIXIN (obj);
-
-  if (handle_set_is_member (mixin->members, mixin->self_handle) ||
-      handle_set_is_member (mixin->local_pending, mixin->self_handle) ||
-      handle_set_is_member (mixin->remote_pending, mixin->self_handle))
-    {
-      *ret = mixin->self_handle;
-    }
-  else
-    {
-      *ret = 0;
-    }
-
-  return TRUE;
-}
-
-gboolean
-gabble_group_mixin_get_group_flags (GObject *obj, guint *ret, GError **error)
-{
-  GabbleGroupMixin *mixin = GABBLE_GROUP_MIXIN (obj);
-
-  *ret = mixin->group_flags;
-
-  return TRUE;
-}
-
-gboolean
-gabble_group_mixin_add_members (GObject *obj, const GArray *contacts, const gchar *message, GError **error)
-{
-  GabbleGroupMixinClass *mixin_cls = GABBLE_GROUP_MIXIN_CLASS (G_OBJECT_GET_CLASS (obj));
-  GabbleGroupMixin *mixin = GABBLE_GROUP_MIXIN (obj);
-  guint i;
-  GabbleHandle handle;
-
-  /* reject invalid handles */
-  if (!gabble_handles_are_valid (mixin->handle_repo,
-                                 TP_HANDLE_TYPE_CONTACT,
-                                 contacts,
-                                 FALSE,
-                                 error))
-    return FALSE;
-
-  /* check that adding is allowed by flags */
-  for (i = 0; i < contacts->len; i++)
-    {
-      handle = g_array_index (contacts, GabbleHandle, i);
-
-      if ((mixin->group_flags & TP_CHANNEL_GROUP_FLAG_CAN_ADD) == 0 &&
-          !handle_set_is_member (mixin->local_pending, handle))
-        {
-          gabble_debug (DEBUG_FLAG, "handle %u cannot be added to members without GROUP_FLAG_CAN_ADD",
-              handle);
-
-          g_set_error (error, TELEPATHY_ERRORS, PermissionDenied,
-              "handle %u cannot be added to members without GROUP_FLAG_CAN_ADD",
-              handle);
-
-          return FALSE;
-        }
-    }
-
-  /* add handle by handle */
-  for (i = 0; i < contacts->len; i++)
-    {
-      handle = g_array_index (contacts, GabbleHandle, i);
-
-      if (handle_set_is_member (mixin->members, handle))
-        {
-          gabble_debug (DEBUG_FLAG, "handle %u is already a member, skipping", handle);
-
-          continue;
-        }
-
-      if (!mixin_cls->add_member (obj, handle, message, error))
-        {
-          return FALSE;
-        }
-    }
-
-  return TRUE;
-}
-
-gboolean
-gabble_group_mixin_remove_members (GObject *obj, const GArray *contacts, const gchar *message, GError **error)
-{
-  GabbleGroupMixinClass *mixin_cls = GABBLE_GROUP_MIXIN_CLASS (G_OBJECT_GET_CLASS (obj));
-  GabbleGroupMixin *mixin = GABBLE_GROUP_MIXIN (obj);
-  guint i;
-  GabbleHandle handle;
-
-  /* reject invalid handles */
-  if (!gabble_handles_are_valid (mixin->handle_repo,
-                                 TP_HANDLE_TYPE_CONTACT,
-                                 contacts,
-                                 FALSE,
-                                 error))
-    return FALSE;
-
-  /* check removing is allowed by flags */
-  for (i = 0; i < contacts->len; i++)
-    {
-      handle = g_array_index (contacts, GabbleHandle, i);
-
-      if (handle_set_is_member (mixin->members, handle))
-        {
-          if ((mixin->group_flags & TP_CHANNEL_GROUP_FLAG_CAN_REMOVE) == 0)
-            {
-              gabble_debug (DEBUG_FLAG, "handle %u cannot be removed from members without GROUP_FLAG_CAN_REMOVE",
-                  handle);
-
-              g_set_error (error, TELEPATHY_ERRORS, PermissionDenied,
-                  "handle %u cannot be removed from members without GROUP_FLAG_CAN_REMOVE",
-                  handle);
-
-              return FALSE;
-            }
-        }
-      else if (handle_set_is_member (mixin->remote_pending, handle))
-        {
-          if ((mixin->group_flags & TP_CHANNEL_GROUP_FLAG_CAN_RESCIND) == 0)
-            {
-              gabble_debug (DEBUG_FLAG, "handle %u cannot be removed from remote pending without GROUP_FLAG_CAN_RESCIND",
-                  handle);
-
-              g_set_error (error, TELEPATHY_ERRORS, PermissionDenied,
-                  "handle %u cannot be removed from remote pending without GROUP_FLAG_CAN_RESCIND",
-                  handle);
-
-              return FALSE;
-            }
-        }
-      else if (!handle_set_is_member (mixin->local_pending, handle))
-        {
-          gabble_debug (DEBUG_FLAG, "handle %u is not a current or pending member",
-                   handle);
-
-          g_set_error (error, TELEPATHY_ERRORS, NotAvailable,
-              "handle %u is not a current or pending member", handle);
-
-          return FALSE;
-        }
-    }
-
-  /* remove handle by handle */
-  for (i = 0; i < contacts->len; i++)
-    {
-      handle = g_array_index (contacts, GabbleHandle, i);
-
-      if (!mixin_cls->remove_member (obj, handle, message, error))
-        {
-          return FALSE;
-        }
-    }
-
-  return TRUE;
-}
-
-gboolean
-gabble_group_mixin_get_members (GObject *obj, GArray **ret, GError **error)
-{
-  GabbleGroupMixin *mixin = GABBLE_GROUP_MIXIN (obj);
-
-  *ret = handle_set_to_array (mixin->members);
-
-  return TRUE;
-}
-
-gboolean
-gabble_group_mixin_get_local_pending_members (GObject *obj, GArray **ret, GError **error)
-{
-  GabbleGroupMixin *mixin = GABBLE_GROUP_MIXIN (obj);
-
-  *ret = handle_set_to_array (mixin->local_pending);
-
-  return TRUE;
-}
-
-gboolean
-gabble_group_mixin_get_remote_pending_members (GObject *obj, GArray **ret, GError **error)
-{
-  GabbleGroupMixin *mixin = GABBLE_GROUP_MIXIN (obj);
-
-  *ret = handle_set_to_array (mixin->remote_pending);
-
-  return TRUE;
-}
-
-gboolean
-gabble_group_mixin_get_all_members (GObject *obj, GArray **ret, GArray **ret1, GArray **ret2, GError **error)
-{
-  GabbleGroupMixin *mixin = GABBLE_GROUP_MIXIN (obj);
-
-  *ret = handle_set_to_array (mixin->members);
-  *ret1 = handle_set_to_array (mixin->local_pending);
-  *ret2 = handle_set_to_array (mixin->remote_pending);
-
-  return TRUE;
-}
-
-gboolean
-gabble_group_mixin_get_handle_owners (GObject *obj,
-                                      const GArray *handles,
-                                      GArray **ret,
-                                      GError **error)
-{
-  GabbleGroupMixin *mixin = GABBLE_GROUP_MIXIN (obj);
-  GabbleGroupMixinPrivate *priv = mixin->priv;
-  guint i;
-
-  if ((mixin->group_flags &
-        TP_CHANNEL_GROUP_FLAG_CHANNEL_SPECIFIC_HANDLES) == 0)
-    {
-      g_set_error (error, TELEPATHY_ERRORS, NotAvailable,
-          "channel doesn't have channel specific handles");
-
-      return FALSE;
-    }
-
-  if (!gabble_handles_are_valid (mixin->handle_repo, TP_HANDLE_TYPE_CONTACT,
-                                 handles, FALSE, error))
-    {
-      return FALSE;
-    }
-
-  *ret = g_array_sized_new (FALSE, FALSE, sizeof (GabbleHandle), handles->len);
-
-  for (i = 0; i < handles->len; i++)
-    {
-      GabbleHandle local_handle = g_array_index (handles, GabbleHandle, i);
-      GabbleHandle owner_handle;
-
-      if (!handle_set_is_member (mixin->members, local_handle))
-        {
-          g_set_error (error, TELEPATHY_ERRORS, InvalidArgument,
-              "handle %u is not a member", local_handle);
-
-          g_array_free (*ret, TRUE);
-          *ret = NULL;
-
-          return FALSE;
-        }
-
-      owner_handle = GPOINTER_TO_UINT (
-          g_hash_table_lookup (priv->handle_owners,
-                               GUINT_TO_POINTER (local_handle)));
-
-      g_array_append_val (*ret, owner_handle);
-    }
-
-  return TRUE;
-}
-
-#define GFTS_APPEND_FLAG_IF_SET(flag) \
-  if (flags & flag) \
-    { \
-      if (i++ > 0) \
-        g_string_append (str, "|"); \
-      g_string_append (str, #flag + 22); \
-    }
-
-static gchar *
-group_flags_to_string (TpChannelGroupFlags flags)
-{
-  gint i = 0;
-  GString *str;
-
-  str = g_string_new ("[" ANSI_BOLD_OFF);
-
-  GFTS_APPEND_FLAG_IF_SET (TP_CHANNEL_GROUP_FLAG_CAN_ADD);
-  GFTS_APPEND_FLAG_IF_SET (TP_CHANNEL_GROUP_FLAG_CAN_REMOVE);
-  GFTS_APPEND_FLAG_IF_SET (TP_CHANNEL_GROUP_FLAG_CAN_RESCIND);
-  GFTS_APPEND_FLAG_IF_SET (TP_CHANNEL_GROUP_FLAG_MESSAGE_ADD);
-  GFTS_APPEND_FLAG_IF_SET (TP_CHANNEL_GROUP_FLAG_MESSAGE_REMOVE);
-  GFTS_APPEND_FLAG_IF_SET (TP_CHANNEL_GROUP_FLAG_MESSAGE_ACCEPT);
-  GFTS_APPEND_FLAG_IF_SET (TP_CHANNEL_GROUP_FLAG_MESSAGE_REJECT);
-  GFTS_APPEND_FLAG_IF_SET (TP_CHANNEL_GROUP_FLAG_MESSAGE_RESCIND);
-
-  g_string_append (str, ANSI_BOLD_ON "]");
-
-  return g_string_free (str, FALSE);
-}
-
-/**
- * gabble_group_mixin_change_flags:
- *
- * Request a change to be made to the flags. Emits the
- * signal with the changes which were made.
- */
-void
-gabble_group_mixin_change_flags (GObject *obj,
-                                 TpChannelGroupFlags add,
-                                 TpChannelGroupFlags remove)
-{
-  GabbleGroupMixin *mixin = GABBLE_GROUP_MIXIN (obj);
-  GabbleGroupMixinClass *mixin_cls = GABBLE_GROUP_MIXIN_CLASS (G_OBJECT_GET_CLASS (obj));
-  TpChannelGroupFlags added, removed;
-
-  added = add & ~mixin->group_flags;
-  mixin->group_flags |= added;
-
-  removed = remove & mixin->group_flags;
-  mixin->group_flags &= ~removed;
-
-  if (add != 0 || remove != 0)
-    {
-      gchar *str_added, *str_removed, *str_flags;
-
-      if (DEBUGGING)
-        {
-          str_added = group_flags_to_string (added);
-          str_removed = group_flags_to_string (removed);
-          str_flags = group_flags_to_string (mixin->group_flags);
-
-          g_message (ANSI_BOLD_ON ANSI_FG_WHITE
-                  "%s: emitting group flags changed\n"
-                  "  added    : %s\n"
-                  "  removed  : %s\n"
-                  "  flags now: %s\n" ANSI_RESET,
-                  G_STRFUNC, str_added, str_removed, str_flags);
-
-          fflush (stdout);
-
-          g_free (str_added);
-          g_free (str_removed);
-          g_free (str_flags);
-        }
-
-      g_signal_emit(obj, mixin_cls->group_flags_changed_signal_id, 0, added, removed);
-    }
-}
-
-static gchar *
-member_array_to_string (GabbleHandleRepo *repo, const GArray *array)
-{
-  GString *str;
-  guint i;
-
-  str = g_string_new ("[" ANSI_BOLD_OFF);
-
-  for (i = 0; i < array->len; i++)
-    {
-      GabbleHandle handle;
-      const gchar *handle_str;
-
-      handle = g_array_index (array, guint32, i);
-      handle_str = gabble_handle_inspect (repo, TP_HANDLE_TYPE_CONTACT, handle);
-
-      g_string_append_printf (str, "%s%u (%s)",
-          (i > 0) ? "\n              " : "",
-          handle, handle_str);
-    }
-
-  g_string_append (str, ANSI_BOLD_ON "]");
-
-  return g_string_free (str, FALSE);
-}
-
-static void remove_handle_owners_if_exist (GObject *obj, GArray *array);
-
-/**
- * gabble_group_mixin_change_members:
- *
- * Request members to be added, removed or marked as local or remote pending.
- * Changes member sets, references, and emits the MembersChanged signal.
- */
-gboolean
-gabble_group_mixin_change_members (GObject *obj,
-                                   const gchar *message,
-                                   GIntSet *add,
-                                   GIntSet *remove,
-                                   GIntSet *local_pending,
-                                   GIntSet *remote_pending,
-                                   GabbleHandle actor,
-                                   guint reason)
-{
-  GabbleGroupMixin *mixin = GABBLE_GROUP_MIXIN (obj);
-  GabbleGroupMixinClass *mixin_cls = GABBLE_GROUP_MIXIN_CLASS (G_OBJECT_GET_CLASS (obj));
-  GIntSet *new_add, *new_remove, *new_local_pending,
-          *new_remote_pending, *tmp, *tmp2, *empty;
-  gboolean ret;
-
-  empty = g_intset_new ();
-
-  if (add == NULL)
-    add = empty;
-
-  if (remove == NULL)
-    remove = empty;
-
-  if (local_pending == NULL)
-    local_pending = empty;
-
-  if (remote_pending == NULL)
-    remote_pending = empty;
-
-  /* members + add */
-  new_add = handle_set_update (mixin->members, add);
-
-  /* members - remove */
-  new_remove = handle_set_difference_update (mixin->members, remove);
-
-  /* members - local_pending */
-  tmp = handle_set_difference_update (mixin->members, local_pending);
-  g_intset_destroy (tmp);
-
-  /* members - remote_pending */
-  tmp = handle_set_difference_update (mixin->members, remote_pending);
-  g_intset_destroy (tmp);
-
-
-  /* local pending + local_pending */
-  new_local_pending = handle_set_update (mixin->local_pending, local_pending);
-
-  /* local pending - add */
-  tmp = handle_set_difference_update (mixin->local_pending, add);
-  g_intset_destroy (tmp);
-
-  /* local pending - remove */
-  tmp = handle_set_difference_update (mixin->local_pending, remove);
-  tmp2 = g_intset_union (new_remove, tmp);
-  g_intset_destroy (new_remove);
-  g_intset_destroy (tmp);
-  new_remove = tmp2;
-
-  /* local pending - remote_pending */
-  tmp = handle_set_difference_update (mixin->local_pending, remote_pending);
-  g_intset_destroy (tmp);
-
-
-  /* remote pending + remote_pending */
-  new_remote_pending = handle_set_update (mixin->remote_pending, remote_pending);
-
-  /* remote pending - add */
-  tmp = handle_set_difference_update (mixin->remote_pending, add);
-  g_intset_destroy (tmp);
-
-  /* remote pending - remove */
-  tmp = handle_set_difference_update (mixin->remote_pending, remove);
-  tmp2 = g_intset_union (new_remove, tmp);
-  g_intset_destroy (new_remove);
-  g_intset_destroy (tmp);
-  new_remove = tmp2;
-
-  /* remote pending - local_pending */
-  tmp = handle_set_difference_update (mixin->remote_pending, local_pending);
-  g_intset_destroy (tmp);
-
-  if (g_intset_size (new_add) > 0 ||
-      g_intset_size (new_remove) > 0 ||
-      g_intset_size (new_local_pending) > 0 ||
-      g_intset_size (new_remote_pending) > 0)
-    {
-      GArray *arr_add, *arr_remove, *arr_local, *arr_remote;
-      gchar *add_str, *rem_str, *local_str, *remote_str;
-
-      /* translate intsets to arrays */
-      arr_add = g_intset_to_array (new_add);
-      arr_remove = g_intset_to_array (new_remove);
-      arr_local = g_intset_to_array (new_local_pending);
-      arr_remote = g_intset_to_array (new_remote_pending);
-
-      /* remove any handle owner mappings */
-      remove_handle_owners_if_exist (obj, arr_remove);
-
-      if (DEBUGGING)
-        {
-          add_str = member_array_to_string (mixin->handle_repo, arr_add);
-          rem_str = member_array_to_string (mixin->handle_repo, arr_remove);
-          local_str = member_array_to_string (mixin->handle_repo, arr_local);
-          remote_str = member_array_to_string (mixin->handle_repo, arr_remote);
-
-          g_message (ANSI_BOLD_ON ANSI_FG_CYAN
-                  "%s: emitting members changed\n"
-                  "  message       : \"%s\"\n"
-                  "  added         : %s\n"
-                  "  removed       : %s\n"
-                  "  local_pending : %s\n"
-                  "  remote_pending: %s\n"
-                  "  actor         : %u\n"
-                  "  reason        : %u: %s\n" ANSI_RESET,
-                  G_STRFUNC, message, add_str, rem_str, local_str, remote_str,
-                  actor, reason, group_change_reason_str(reason));
-
-          fflush (stdout);
-
-          g_free (add_str);
-          g_free (rem_str);
-          g_free (local_str);
-          g_free (remote_str);
-        }
-
-      if (actor)
-        {
-          handle_set_add (mixin->priv->actors, actor);
-        }
-      /* emit signal */
-      g_signal_emit(obj, mixin_cls->members_changed_signal_id, 0,
-                    message,
-                    arr_add, arr_remove,
-                    arr_local, arr_remote,
-                    actor, reason);
-
-      /* free arrays */
-      g_array_free (arr_add, TRUE);
-      g_array_free (arr_remove, TRUE);
-      g_array_free (arr_local, TRUE);
-      g_array_free (arr_remote, TRUE);
-
-      ret = TRUE;
-    }
-  else
-    {
-      gabble_debug (DEBUG_FLAG, "not emitting signal, nothing changed");
-
-      ret = FALSE;
-    }
-
-  /* free intsets */
-  g_intset_destroy (new_add);
-  g_intset_destroy (new_remove);
-  g_intset_destroy (new_local_pending);
-  g_intset_destroy (new_remote_pending);
-  g_intset_destroy (empty);
-
-  return ret;
-}
-
-void
-gabble_group_mixin_add_handle_owner (GObject *obj,
-                                     GabbleHandle local_handle,
-                                     GabbleHandle owner_handle)
-{
-  GabbleGroupMixin *mixin = GABBLE_GROUP_MIXIN (obj);
-  GabbleGroupMixinPrivate *priv = mixin->priv;
-
-  g_hash_table_insert (priv->handle_owners, GUINT_TO_POINTER (local_handle),
-                       GUINT_TO_POINTER (owner_handle));
-
-  gabble_handle_ref (mixin->handle_repo, TP_HANDLE_TYPE_CONTACT,
-                     local_handle);
-  gabble_handle_ref (mixin->handle_repo, TP_HANDLE_TYPE_CONTACT,
-                     owner_handle);
-}
-
-static void
-remove_handle_owners_if_exist (GObject *obj, GArray *array)
-{
-  GabbleGroupMixin *mixin = GABBLE_GROUP_MIXIN (obj);
-  GabbleGroupMixinPrivate *priv = mixin->priv;
-  guint i;
-
-  for (i = 0; i < array->len; i++)
-    {
-      GabbleHandle handle = g_array_index (array, guint32, i);
-      gpointer local_handle, owner_handle;
-
-      if (g_hash_table_lookup_extended (priv->handle_owners,
-                                        GUINT_TO_POINTER (handle),
-                                        &local_handle,
-                                        &owner_handle))
-        {
-          gabble_handle_unref (mixin->handle_repo, TP_HANDLE_TYPE_CONTACT,
-                               GPOINTER_TO_UINT (local_handle));
-          gabble_handle_unref (mixin->handle_repo, TP_HANDLE_TYPE_CONTACT,
-                               GPOINTER_TO_UINT (owner_handle));
-
-          g_hash_table_remove (priv->handle_owners, GUINT_TO_POINTER (handle));
-        }
-    }
-}
-