[Telepathy-commits] [telepathy-gabble/master] rename gabble-roster-channel.c to roster-channel.c

Dafydd Harries dafydd.harries at collabora.co.uk
Tue Aug 19 10:53:19 PDT 2008


20080714115838-c9803-b82f2f0fb4634f9430ca1a81b5ed7e1ea246ccfd.gz
---
 src/Makefile.am             |    2 +-
 src/gabble-roster-channel.c |  685 -------------------------------------------
 src/roster-channel.c        |  685 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 686 insertions(+), 686 deletions(-)
 delete mode 100644 src/gabble-roster-channel.c
 create mode 100644 src/roster-channel.c

diff --git a/src/Makefile.am b/src/Makefile.am
index 7aed46d..2a9cba2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -66,7 +66,7 @@ libgabble_convenience_la_our_sources = \
     register.c \
     register.h \
     roster-channel.h \
-    gabble-roster-channel.c \
+    roster-channel.c \
     roomlist-channel.h \
     roomlist-channel.c \
     types.h \
diff --git a/src/gabble-roster-channel.c b/src/gabble-roster-channel.c
deleted file mode 100644
index 5ffd191..0000000
--- a/src/gabble-roster-channel.c
+++ /dev/null
@@ -1,685 +0,0 @@
-/*
- * gabble-roster-channel.c - Source for GabbleRosterChannel
- * Copyright (C) 2005, 2006 Collabora Ltd.
- * Copyright (C) 2005 Nokia Corporation
- *
- * 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 "roster-channel.h"
-
-#include <dbus/dbus-glib.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#define DEBUG_FLAG GABBLE_DEBUG_ROSTER
-
-#include "debug.h"
-#include "connection.h"
-#include <telepathy-glib/group-mixin.h>
-#include "roster.h"
-#include <telepathy-glib/dbus.h>
-#include <telepathy-glib/errors.h>
-#include <telepathy-glib/interfaces.h>
-#include <telepathy-glib/channel-iface.h>
-#include <telepathy-glib/svc-generic.h>
-#include <telepathy-glib/svc-channel.h>
-#include "util.h"
-
-static void channel_iface_init (gpointer, gpointer);
-
-G_DEFINE_TYPE_WITH_CODE (GabbleRosterChannel, gabble_roster_channel,
-    G_TYPE_OBJECT,
-    G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL, channel_iface_init);
-    G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_GROUP,
-      tp_group_mixin_iface_init);
-    G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_CONTACT_LIST, NULL);
-    G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES,
-      tp_dbus_properties_mixin_iface_init);
-    G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_IFACE, NULL));
-
-static const gchar *gabble_roster_channel_interfaces[] = {
-    TP_IFACE_CHANNEL_INTERFACE_GROUP,
-    NULL
-};
-
-/* properties */
-enum
-{
-  PROP_OBJECT_PATH = 1,
-  PROP_CHANNEL_TYPE,
-  PROP_HANDLE_TYPE,
-  PROP_HANDLE,
-  PROP_CONNECTION,
-  PROP_INTERFACES,
-  LAST_PROPERTY
-};
-
-/* private structure */
-typedef struct _GabbleRosterChannelPrivate GabbleRosterChannelPrivate;
-
-struct _GabbleRosterChannelPrivate
-{
-  GabbleConnection *conn;
-  char *object_path;
-  TpHandle handle;
-  guint handle_type;
-
-  gboolean dispose_has_run;
-  gboolean closed;
-};
-
-#define GABBLE_ROSTER_CHANNEL_GET_PRIVATE(obj) \
-    ((GabbleRosterChannelPrivate *)obj->priv)
-
-static void
-gabble_roster_channel_init (GabbleRosterChannel *self)
-{
-  GabbleRosterChannelPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
-      GABBLE_TYPE_ROSTER_CHANNEL, GabbleRosterChannelPrivate);
-
-  self->priv = priv;
-
-  /* allocate any data required by the object here */
-}
-
-static GObject *
-gabble_roster_channel_constructor (GType type, guint n_props,
-                                   GObjectConstructParam *props)
-{
-  GObject *obj;
-  GabbleRosterChannelPrivate *priv;
-  DBusGConnection *bus;
-  TpBaseConnection *conn;
-  TpHandle self_handle;
-  guint handle_type;
-  TpHandleRepoIface *handle_repo, *contact_repo;
-
-  obj = G_OBJECT_CLASS (gabble_roster_channel_parent_class)->
-           constructor (type, n_props, props);
-  priv = GABBLE_ROSTER_CHANNEL_GET_PRIVATE (GABBLE_ROSTER_CHANNEL (obj));
-  conn = (TpBaseConnection *)priv->conn;
-  handle_type = priv->handle_type;
-  handle_repo = tp_base_connection_get_handles (conn, handle_type);
-  contact_repo = tp_base_connection_get_handles (conn, TP_HANDLE_TYPE_CONTACT);
-  self_handle = conn->self_handle;
-
-  /* register object on the bus */
-  bus = tp_get_bus ();
-  dbus_g_connection_register_g_object (bus, priv->object_path, obj);
-
-  g_assert (handle_type == TP_HANDLE_TYPE_GROUP
-      || handle_type == TP_HANDLE_TYPE_LIST);
-
-  /* ref our list handle */
-  tp_handle_ref (handle_repo, priv->handle);
-
-  /* initialize group mixin */
-  tp_group_mixin_init (obj,
-      G_STRUCT_OFFSET (GabbleRosterChannel, group),
-      contact_repo,
-      self_handle);
-
-  if (handle_type == TP_HANDLE_TYPE_GROUP)
-    {
-      tp_group_mixin_change_flags (obj,
-          TP_CHANNEL_GROUP_FLAG_CAN_ADD |
-          TP_CHANNEL_GROUP_FLAG_CAN_REMOVE |
-          TP_CHANNEL_GROUP_FLAG_PROPERTIES,
-          0);
-    }
-  else if (handle_type != TP_HANDLE_TYPE_LIST)
-    {
-      g_assert_not_reached ();
-    }
-  /* magic contact lists from here down... */
-  else if (GABBLE_LIST_HANDLE_PUBLISH == priv->handle)
-    {
-      tp_group_mixin_change_flags (obj,
-          TP_CHANNEL_GROUP_FLAG_CAN_REMOVE |
-          TP_CHANNEL_GROUP_FLAG_MESSAGE_ACCEPT |
-          TP_CHANNEL_GROUP_FLAG_MESSAGE_REMOVE |
-          TP_CHANNEL_GROUP_FLAG_PROPERTIES,
-          0);
-    }
-  else if (GABBLE_LIST_HANDLE_SUBSCRIBE == priv->handle)
-    {
-      tp_group_mixin_change_flags (obj,
-          TP_CHANNEL_GROUP_FLAG_CAN_ADD |
-          TP_CHANNEL_GROUP_FLAG_CAN_REMOVE |
-          TP_CHANNEL_GROUP_FLAG_CAN_RESCIND |
-          TP_CHANNEL_GROUP_FLAG_MESSAGE_ADD |
-          TP_CHANNEL_GROUP_FLAG_MESSAGE_REMOVE |
-          TP_CHANNEL_GROUP_FLAG_MESSAGE_RESCIND |
-          TP_CHANNEL_GROUP_FLAG_PROPERTIES,
-          0);
-    }
-  else if (GABBLE_LIST_HANDLE_KNOWN == priv->handle)
-    {
-      tp_group_mixin_change_flags (obj,
-          TP_CHANNEL_GROUP_FLAG_CAN_REMOVE |
-          TP_CHANNEL_GROUP_FLAG_PROPERTIES,
-          0);
-    }
-  else if (GABBLE_LIST_HANDLE_DENY == priv->handle)
-    {
-      tp_group_mixin_change_flags (obj,
-          TP_CHANNEL_GROUP_FLAG_CAN_ADD |
-          TP_CHANNEL_GROUP_FLAG_CAN_REMOVE |
-          TP_CHANNEL_GROUP_FLAG_PROPERTIES,
-          0);
-    }
-  else
-    {
-      g_assert_not_reached ();
-    }
-
-  return obj;
-}
-
-static void
-gabble_roster_channel_get_property (GObject    *object,
-                                    guint       property_id,
-                                    GValue     *value,
-                                    GParamSpec *pspec)
-{
-  GabbleRosterChannel *chan = GABBLE_ROSTER_CHANNEL (object);
-  GabbleRosterChannelPrivate *priv = GABBLE_ROSTER_CHANNEL_GET_PRIVATE (chan);
-
-  switch (property_id) {
-    case PROP_OBJECT_PATH:
-      g_value_set_string (value, priv->object_path);
-      break;
-    case PROP_CHANNEL_TYPE:
-      g_value_set_static_string (value, TP_IFACE_CHANNEL_TYPE_CONTACT_LIST);
-      break;
-    case PROP_HANDLE_TYPE:
-      g_value_set_uint (value, priv->handle_type);
-      break;
-    case PROP_HANDLE:
-      g_value_set_uint (value, priv->handle);
-      break;
-    case PROP_CONNECTION:
-      g_value_set_object (value, priv->conn);
-      break;
-    case PROP_INTERFACES:
-      g_value_set_boxed (value, gabble_roster_channel_interfaces);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
-      break;
-  }
-}
-
-static void
-gabble_roster_channel_set_property (GObject     *object,
-                                    guint        property_id,
-                                    const GValue *value,
-                                    GParamSpec   *pspec)
-{
-  GabbleRosterChannel *chan = GABBLE_ROSTER_CHANNEL (object);
-  GabbleRosterChannelPrivate *priv = GABBLE_ROSTER_CHANNEL_GET_PRIVATE (chan);
-
-  switch (property_id) {
-    case PROP_OBJECT_PATH:
-      g_free (priv->object_path);
-      priv->object_path = g_value_dup_string (value);
-    case PROP_CHANNEL_TYPE:
-      /* in telepathy-glib > 0.7.0 this property is writable in the
-       * interface, but not actually meaningfully changeable on this channel,
-       * so we do nothing */
-      break;
-    case PROP_HANDLE_TYPE:
-      priv->handle_type = g_value_get_uint (value);
-      break;
-    case PROP_HANDLE:
-      priv->handle = g_value_get_uint (value);
-      break;
-    case PROP_CONNECTION:
-      priv->conn = g_value_get_object (value);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
-      break;
-  }
-}
-
-static void gabble_roster_channel_dispose (GObject *object);
-static void gabble_roster_channel_finalize (GObject *object);
-
-static gboolean _gabble_roster_channel_add_member_cb (GObject *obj,
-    TpHandle handle, const gchar *message, GError **error);
-static gboolean _gabble_roster_channel_remove_member_cb (GObject *obj,
-    TpHandle handle, const gchar *message, GError **error);
-
-static void
-gabble_roster_channel_class_init (GabbleRosterChannelClass *gabble_roster_channel_class)
-{
-  static TpDBusPropertiesMixinPropImpl channel_props[] = {
-      { "TargetHandleType", "handle-type", NULL },
-      { "TargetHandle", "handle", NULL },
-      { "ChannelType", "channel-type", NULL },
-      { "Interfaces", "interfaces", NULL },
-      { NULL }
-  };
-  static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = {
-      { TP_IFACE_CHANNEL,
-        tp_dbus_properties_mixin_getter_gobject_properties,
-        NULL,
-        channel_props,
-      },
-      { NULL }
-  };
-  GObjectClass *object_class = G_OBJECT_CLASS (gabble_roster_channel_class);
-  GParamSpec *param_spec;
-
-  g_type_class_add_private (gabble_roster_channel_class,
-      sizeof (GabbleRosterChannelPrivate));
-
-  object_class->constructor = gabble_roster_channel_constructor;
-
-  object_class->get_property = gabble_roster_channel_get_property;
-  object_class->set_property = gabble_roster_channel_set_property;
-
-  object_class->dispose = gabble_roster_channel_dispose;
-  object_class->finalize = gabble_roster_channel_finalize;
-
-  param_spec = g_param_spec_object ("connection", "GabbleConnection object",
-      "Gabble connection object that owns this Roster channel object.",
-      GABBLE_TYPE_CONNECTION,
-      G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
-      G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB);
-  g_object_class_install_property (object_class, PROP_CONNECTION, param_spec);
-
-  param_spec = g_param_spec_boxed ("interfaces", "Extra D-Bus interfaces",
-      "Additional Channel.Interface.* interfaces",
-      G_TYPE_STRV,
-      G_PARAM_READABLE |
-      G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NAME);
-  g_object_class_install_property (object_class, PROP_INTERFACES, param_spec);
-
-  g_object_class_override_property (object_class, PROP_OBJECT_PATH,
-      "object-path");
-  g_object_class_override_property (object_class, PROP_CHANNEL_TYPE,
-      "channel-type");
-  g_object_class_override_property (object_class, PROP_HANDLE_TYPE,
-      "handle-type");
-  g_object_class_override_property (object_class, PROP_HANDLE, "handle");
-
-  gabble_roster_channel_class->properties_class.interfaces = prop_interfaces;
-  tp_dbus_properties_mixin_class_init (object_class,
-      G_STRUCT_OFFSET (GabbleRosterChannelClass, properties_class));
-
-  tp_group_mixin_class_init (object_class,
-      G_STRUCT_OFFSET (GabbleRosterChannelClass, group_class),
-      _gabble_roster_channel_add_member_cb,
-      _gabble_roster_channel_remove_member_cb);
-  tp_group_mixin_init_dbus_properties (object_class);
-}
-
-void
-gabble_roster_channel_dispose (GObject *object)
-{
-  GabbleRosterChannel *self = GABBLE_ROSTER_CHANNEL (object);
-  GabbleRosterChannelPrivate *priv = GABBLE_ROSTER_CHANNEL_GET_PRIVATE (self);
-
-  if (priv->dispose_has_run)
-    return;
-
-  priv->dispose_has_run = TRUE;
-
-  if (!priv->closed)
-    tp_svc_channel_emit_closed ((TpSvcChannel *)object);
-
-  /* release any references held by the object here */
-
-  if (G_OBJECT_CLASS (gabble_roster_channel_parent_class)->dispose)
-    G_OBJECT_CLASS (gabble_roster_channel_parent_class)->dispose (object);
-}
-
-void
-gabble_roster_channel_finalize (GObject *object)
-{
-  GabbleRosterChannel *self = GABBLE_ROSTER_CHANNEL (object);
-  GabbleRosterChannelPrivate *priv = GABBLE_ROSTER_CHANNEL_GET_PRIVATE (self);
-  TpBaseConnection *conn = (TpBaseConnection *)priv->conn;
-  TpHandleRepoIface *handle_repo = tp_base_connection_get_handles (conn,
-      priv->handle_type);
-
-  /* free any data held directly by the object here */
-
-  g_free (priv->object_path);
-
-  tp_handle_unref (handle_repo, priv->handle);
-
-  tp_group_mixin_finalize (object);
-
-  G_OBJECT_CLASS (gabble_roster_channel_parent_class)->finalize (object);
-}
-
-
-static gboolean
-_gabble_roster_channel_send_presence (GabbleRosterChannel *chan,
-                                      LmMessageSubType sub_type,
-                                      TpHandle handle,
-                                      const gchar *status,
-                                      GError **error)
-{
-  GabbleRosterChannelPrivate *priv;
-  TpBaseConnection *conn;
-  TpHandleRepoIface *repo;
-  const char *contact;
-  LmMessage *message;
-  gboolean result;
-
-  priv = GABBLE_ROSTER_CHANNEL_GET_PRIVATE (chan);
-  conn = (TpBaseConnection *)priv->conn;
-  repo = tp_base_connection_get_handles (conn, TP_HANDLE_TYPE_CONTACT);
-  contact = tp_handle_inspect (repo, handle);
-
-  message = lm_message_new_with_sub_type (contact,
-      LM_MESSAGE_TYPE_PRESENCE,
-      sub_type);
-
-  if (LM_MESSAGE_SUB_TYPE_SUBSCRIBE == sub_type)
-    lm_message_node_add_own_nick (message->node, priv->conn);
-
-  if (status != NULL && status[0] != '\0')
-    lm_message_node_add_child (message->node, "status", status);
-
-  result = _gabble_connection_send (priv->conn, message, error);
-
-  lm_message_unref (message);
-
-  return result;
-}
-
-
-/**
- * _gabble_roster_channel_add_member_cb
- *
- * Called by the group mixin to add one member.
- */
-static gboolean
-_gabble_roster_channel_add_member_cb (GObject *obj,
-                                      TpHandle handle,
-                                      const gchar *message,
-                                      GError **error)
-{
-  GabbleRosterChannelPrivate *priv;
-  gboolean ret = FALSE;
-#ifdef ENABLE_DEBUG
-  TpHandleRepoIface *handle_repo, *contact_repo;
-#endif
-
-  priv = GABBLE_ROSTER_CHANNEL_GET_PRIVATE (GABBLE_ROSTER_CHANNEL (obj));
-#ifdef ENABLE_DEBUG
-  handle_repo = tp_base_connection_get_handles ((TpBaseConnection *)priv->conn,
-      priv->handle_type);
-  contact_repo = tp_base_connection_get_handles (
-      (TpBaseConnection *)priv->conn, TP_HANDLE_TYPE_CONTACT);
-#endif
-
-  DEBUG ("called on %s with handle %u (%s) \"%s\"",
-      tp_handle_inspect (handle_repo, priv->handle), handle,
-      tp_handle_inspect (contact_repo, handle), message);
-
-  if (TP_HANDLE_TYPE_GROUP == priv->handle_type)
-    {
-      ret = gabble_roster_handle_add_to_group (priv->conn->roster,
-          handle, priv->handle, error);
-    }
-  else if (TP_HANDLE_TYPE_LIST != priv->handle_type)
-    {
-      g_assert_not_reached ();
-      return FALSE;
-    }
-  /* "magic" contact lists, from here down... */
-  /* publish list */
-  else if (GABBLE_LIST_HANDLE_PUBLISH == priv->handle)
-    {
-      /* send <presence type="subscribed"> */
-      ret = _gabble_roster_channel_send_presence (GABBLE_ROSTER_CHANNEL (obj),
-          LM_MESSAGE_SUB_TYPE_SUBSCRIBED, handle, message, error);
-    }
-  /* subscribe list */
-  else if (GABBLE_LIST_HANDLE_SUBSCRIBE == priv->handle)
-    {
-      /* add item to the roster (GTalk depends on this, clearing the H flag) */
-      gabble_roster_handle_add (priv->conn->roster, handle, NULL);
-
-      /* send <presence type="subscribe"> */
-      ret = _gabble_roster_channel_send_presence (GABBLE_ROSTER_CHANNEL (obj),
-          LM_MESSAGE_SUB_TYPE_SUBSCRIBE, handle, message, error);
-    }
-  /* deny list */
-  else if (GABBLE_LIST_HANDLE_DENY == priv->handle)
-    {
-      /* block contact */
-      ret = gabble_roster_handle_set_blocked (priv->conn->roster, handle, TRUE,
-          error);
-    }
-  else
-    {
-      g_assert_not_reached ();
-    }
-
-  return ret;
-}
-
-
-/**
- * _gabble_roster_channel_remove_member_cb
- *
- * Called by the group mixin to remove one member.
- */
-static gboolean
-_gabble_roster_channel_remove_member_cb (GObject *obj,
-                                         TpHandle handle,
-                                         const gchar *message,
-                                         GError **error)
-{
-  GabbleRosterChannelPrivate *priv;
-#ifdef ENABLE_DEBUG
-  TpBaseConnection *conn;
-  TpHandleRepoIface *handle_repo, *contact_repo;
-#endif
-  gboolean ret = FALSE;
-
-  priv = GABBLE_ROSTER_CHANNEL_GET_PRIVATE (GABBLE_ROSTER_CHANNEL (obj));
-#ifdef ENABLE_DEBUG
-  conn = (TpBaseConnection *)priv->conn;
-  handle_repo = tp_base_connection_get_handles (conn, priv->handle_type);
-  contact_repo = tp_base_connection_get_handles (conn, TP_HANDLE_TYPE_CONTACT);
-#endif
-
-  DEBUG ("called on %s with handle %u (%s) \"%s\"",
-      tp_handle_inspect (handle_repo, priv->handle), handle,
-      tp_handle_inspect (contact_repo, handle), message);
-
-  if (TP_HANDLE_TYPE_GROUP == priv->handle_type)
-    {
-      ret = gabble_roster_handle_remove_from_group (priv->conn->roster,
-          handle, priv->handle, error);
-    }
-  else if (TP_HANDLE_TYPE_LIST != priv->handle_type)
-    {
-      g_assert_not_reached ();
-      return FALSE;
-    }
-  /* "magic" contact lists, from here down... */
-  /* publish list */
-  else if (GABBLE_LIST_HANDLE_PUBLISH == priv->handle)
-    {
-      /* send <presence type="unsubscribed"> */
-      ret = _gabble_roster_channel_send_presence (GABBLE_ROSTER_CHANNEL (obj),
-          LM_MESSAGE_SUB_TYPE_UNSUBSCRIBED, handle, message, error);
-
-      /* remove it from local_pending here, because roster callback doesn't
-         know if it can (subscription='none' is used both during request and
-         when it's rejected) */
-      if (tp_handle_set_is_member (GABBLE_ROSTER_CHANNEL (obj)->group.local_pending, handle))
-        {
-          TpIntSet *rem = tp_intset_new ();
-
-          tp_intset_add (rem, handle);
-          tp_group_mixin_change_members (obj, "", NULL, rem, NULL, NULL,
-              0, 0);
-
-          tp_intset_destroy (rem);
-        }
-    }
-  /* subscribe list */
-  else if (GABBLE_LIST_HANDLE_SUBSCRIBE == priv->handle)
-    {
-      /* send <presence type="unsubscribe"> */
-      ret = _gabble_roster_channel_send_presence (GABBLE_ROSTER_CHANNEL (obj),
-          LM_MESSAGE_SUB_TYPE_UNSUBSCRIBE, handle, message, error);
-    }
-  /* known list */
-  else if (GABBLE_LIST_HANDLE_KNOWN == priv->handle)
-    {
-      /* send roster subscription=remove IQ */
-      ret = gabble_roster_handle_remove (priv->conn->roster, handle, error);
-    }
-  /* deny list */
-  else if (GABBLE_LIST_HANDLE_DENY == priv->handle)
-    {
-      /* unblock contact */
-      ret = gabble_roster_handle_set_blocked (priv->conn->roster, handle,
-          FALSE, error);
-    }
-  else
-    {
-      g_assert_not_reached ();
-    }
-
-  return ret;
-}
-
-
-/**
- * gabble_roster_channel_close
- *
- * Implements D-Bus method Close
- * on interface org.freedesktop.Telepathy.Channel
- */
-static void
-gabble_roster_channel_close (TpSvcChannel *iface,
-                             DBusGMethodInvocation *context)
-{
-  GabbleRosterChannel *self = GABBLE_ROSTER_CHANNEL (iface);
-  GabbleRosterChannelPrivate *priv;
-
-  g_assert (GABBLE_IS_ROSTER_CHANNEL (self));
-
-  priv = GABBLE_ROSTER_CHANNEL_GET_PRIVATE (self);
-
-  if (priv->handle_type == TP_HANDLE_TYPE_LIST)
-    {
-      GError e = { TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED,
-          "you may not close contact list channels" };
-
-      dbus_g_method_return_error (context, &e);
-    }
-  else /* TP_HANDLE_TYPE_GROUP */
-    {
-      if (tp_handle_set_size (self->group.members) == 0)
-        {
-          /* deleting groups isn't a concept that exists on XMPP,
-           * so just close the channel */
-
-          priv->closed = TRUE;
-          tp_svc_channel_emit_closed ((TpSvcChannel *)self);
-          tp_svc_channel_return_from_close (context);
-          return;
-        }
-
-      else
-        {
-          GError e = { TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
-              "you may not close this group, because it's not empty" };
-
-          dbus_g_method_return_error (context, &e);
-        }
-    }
-}
-
-
-/**
- * gabble_roster_channel_get_channel_type
- *
- * Implements D-Bus method GetChannelType
- * on interface org.freedesktop.Telepathy.Channel
- */
-static void
-gabble_roster_channel_get_channel_type (TpSvcChannel *iface,
-                                        DBusGMethodInvocation *context)
-{
-  tp_svc_channel_return_from_get_channel_type (context,
-      TP_IFACE_CHANNEL_TYPE_CONTACT_LIST);
-}
-
-
-/**
- * gabble_roster_channel_get_handle
- *
- * Implements D-Bus method GetHandle
- * on interface org.freedesktop.Telepathy.Channel
- */
-static void
-gabble_roster_channel_get_handle (TpSvcChannel *iface,
-                                  DBusGMethodInvocation *context)
-{
-  GabbleRosterChannel *self = GABBLE_ROSTER_CHANNEL (iface);
-  GabbleRosterChannelPrivate *priv;
-
-  g_assert (GABBLE_IS_ROSTER_CHANNEL (self));
-
-  priv = GABBLE_ROSTER_CHANNEL_GET_PRIVATE (self);
-
-  tp_svc_channel_return_from_get_handle (context, priv->handle_type,
-      priv->handle);
-}
-
-
-/**
- * gabble_roster_channel_get_interfaces
- *
- * Implements D-Bus method GetInterfaces
- * on interface org.freedesktop.Telepathy.Channel
- */
-static void
-gabble_roster_channel_get_interfaces (TpSvcChannel *self,
-                                      DBusGMethodInvocation *context)
-{
-  tp_svc_channel_return_from_get_interfaces (context,
-      gabble_roster_channel_interfaces);
-}
-
-
-static void
-channel_iface_init (gpointer g_iface, gpointer iface_data)
-{
-  TpSvcChannelClass *klass = (TpSvcChannelClass *)g_iface;
-
-#define IMPLEMENT(x) tp_svc_channel_implement_##x (\
-    klass, gabble_roster_channel_##x)
-  IMPLEMENT(close);
-  IMPLEMENT(get_channel_type);
-  IMPLEMENT(get_handle);
-  IMPLEMENT(get_interfaces);
-#undef IMPLEMENT
-}
diff --git a/src/roster-channel.c b/src/roster-channel.c
new file mode 100644
index 0000000..5ffd191
--- /dev/null
+++ b/src/roster-channel.c
@@ -0,0 +1,685 @@
+/*
+ * gabble-roster-channel.c - Source for GabbleRosterChannel
+ * Copyright (C) 2005, 2006 Collabora Ltd.
+ * Copyright (C) 2005 Nokia Corporation
+ *
+ * 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 "roster-channel.h"
+
+#include <dbus/dbus-glib.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define DEBUG_FLAG GABBLE_DEBUG_ROSTER
+
+#include "debug.h"
+#include "connection.h"
+#include <telepathy-glib/group-mixin.h>
+#include "roster.h"
+#include <telepathy-glib/dbus.h>
+#include <telepathy-glib/errors.h>
+#include <telepathy-glib/interfaces.h>
+#include <telepathy-glib/channel-iface.h>
+#include <telepathy-glib/svc-generic.h>
+#include <telepathy-glib/svc-channel.h>
+#include "util.h"
+
+static void channel_iface_init (gpointer, gpointer);
+
+G_DEFINE_TYPE_WITH_CODE (GabbleRosterChannel, gabble_roster_channel,
+    G_TYPE_OBJECT,
+    G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL, channel_iface_init);
+    G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_GROUP,
+      tp_group_mixin_iface_init);
+    G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_CONTACT_LIST, NULL);
+    G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES,
+      tp_dbus_properties_mixin_iface_init);
+    G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_IFACE, NULL));
+
+static const gchar *gabble_roster_channel_interfaces[] = {
+    TP_IFACE_CHANNEL_INTERFACE_GROUP,
+    NULL
+};
+
+/* properties */
+enum
+{
+  PROP_OBJECT_PATH = 1,
+  PROP_CHANNEL_TYPE,
+  PROP_HANDLE_TYPE,
+  PROP_HANDLE,
+  PROP_CONNECTION,
+  PROP_INTERFACES,
+  LAST_PROPERTY
+};
+
+/* private structure */
+typedef struct _GabbleRosterChannelPrivate GabbleRosterChannelPrivate;
+
+struct _GabbleRosterChannelPrivate
+{
+  GabbleConnection *conn;
+  char *object_path;
+  TpHandle handle;
+  guint handle_type;
+
+  gboolean dispose_has_run;
+  gboolean closed;
+};
+
+#define GABBLE_ROSTER_CHANNEL_GET_PRIVATE(obj) \
+    ((GabbleRosterChannelPrivate *)obj->priv)
+
+static void
+gabble_roster_channel_init (GabbleRosterChannel *self)
+{
+  GabbleRosterChannelPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+      GABBLE_TYPE_ROSTER_CHANNEL, GabbleRosterChannelPrivate);
+
+  self->priv = priv;
+
+  /* allocate any data required by the object here */
+}
+
+static GObject *
+gabble_roster_channel_constructor (GType type, guint n_props,
+                                   GObjectConstructParam *props)
+{
+  GObject *obj;
+  GabbleRosterChannelPrivate *priv;
+  DBusGConnection *bus;
+  TpBaseConnection *conn;
+  TpHandle self_handle;
+  guint handle_type;
+  TpHandleRepoIface *handle_repo, *contact_repo;
+
+  obj = G_OBJECT_CLASS (gabble_roster_channel_parent_class)->
+           constructor (type, n_props, props);
+  priv = GABBLE_ROSTER_CHANNEL_GET_PRIVATE (GABBLE_ROSTER_CHANNEL (obj));
+  conn = (TpBaseConnection *)priv->conn;
+  handle_type = priv->handle_type;
+  handle_repo = tp_base_connection_get_handles (conn, handle_type);
+  contact_repo = tp_base_connection_get_handles (conn, TP_HANDLE_TYPE_CONTACT);
+  self_handle = conn->self_handle;
+
+  /* register object on the bus */
+  bus = tp_get_bus ();
+  dbus_g_connection_register_g_object (bus, priv->object_path, obj);
+
+  g_assert (handle_type == TP_HANDLE_TYPE_GROUP
+      || handle_type == TP_HANDLE_TYPE_LIST);
+
+  /* ref our list handle */
+  tp_handle_ref (handle_repo, priv->handle);
+
+  /* initialize group mixin */
+  tp_group_mixin_init (obj,
+      G_STRUCT_OFFSET (GabbleRosterChannel, group),
+      contact_repo,
+      self_handle);
+
+  if (handle_type == TP_HANDLE_TYPE_GROUP)
+    {
+      tp_group_mixin_change_flags (obj,
+          TP_CHANNEL_GROUP_FLAG_CAN_ADD |
+          TP_CHANNEL_GROUP_FLAG_CAN_REMOVE |
+          TP_CHANNEL_GROUP_FLAG_PROPERTIES,
+          0);
+    }
+  else if (handle_type != TP_HANDLE_TYPE_LIST)
+    {
+      g_assert_not_reached ();
+    }
+  /* magic contact lists from here down... */
+  else if (GABBLE_LIST_HANDLE_PUBLISH == priv->handle)
+    {
+      tp_group_mixin_change_flags (obj,
+          TP_CHANNEL_GROUP_FLAG_CAN_REMOVE |
+          TP_CHANNEL_GROUP_FLAG_MESSAGE_ACCEPT |
+          TP_CHANNEL_GROUP_FLAG_MESSAGE_REMOVE |
+          TP_CHANNEL_GROUP_FLAG_PROPERTIES,
+          0);
+    }
+  else if (GABBLE_LIST_HANDLE_SUBSCRIBE == priv->handle)
+    {
+      tp_group_mixin_change_flags (obj,
+          TP_CHANNEL_GROUP_FLAG_CAN_ADD |
+          TP_CHANNEL_GROUP_FLAG_CAN_REMOVE |
+          TP_CHANNEL_GROUP_FLAG_CAN_RESCIND |
+          TP_CHANNEL_GROUP_FLAG_MESSAGE_ADD |
+          TP_CHANNEL_GROUP_FLAG_MESSAGE_REMOVE |
+          TP_CHANNEL_GROUP_FLAG_MESSAGE_RESCIND |
+          TP_CHANNEL_GROUP_FLAG_PROPERTIES,
+          0);
+    }
+  else if (GABBLE_LIST_HANDLE_KNOWN == priv->handle)
+    {
+      tp_group_mixin_change_flags (obj,
+          TP_CHANNEL_GROUP_FLAG_CAN_REMOVE |
+          TP_CHANNEL_GROUP_FLAG_PROPERTIES,
+          0);
+    }
+  else if (GABBLE_LIST_HANDLE_DENY == priv->handle)
+    {
+      tp_group_mixin_change_flags (obj,
+          TP_CHANNEL_GROUP_FLAG_CAN_ADD |
+          TP_CHANNEL_GROUP_FLAG_CAN_REMOVE |
+          TP_CHANNEL_GROUP_FLAG_PROPERTIES,
+          0);
+    }
+  else
+    {
+      g_assert_not_reached ();
+    }
+
+  return obj;
+}
+
+static void
+gabble_roster_channel_get_property (GObject    *object,
+                                    guint       property_id,
+                                    GValue     *value,
+                                    GParamSpec *pspec)
+{
+  GabbleRosterChannel *chan = GABBLE_ROSTER_CHANNEL (object);
+  GabbleRosterChannelPrivate *priv = GABBLE_ROSTER_CHANNEL_GET_PRIVATE (chan);
+
+  switch (property_id) {
+    case PROP_OBJECT_PATH:
+      g_value_set_string (value, priv->object_path);
+      break;
+    case PROP_CHANNEL_TYPE:
+      g_value_set_static_string (value, TP_IFACE_CHANNEL_TYPE_CONTACT_LIST);
+      break;
+    case PROP_HANDLE_TYPE:
+      g_value_set_uint (value, priv->handle_type);
+      break;
+    case PROP_HANDLE:
+      g_value_set_uint (value, priv->handle);
+      break;
+    case PROP_CONNECTION:
+      g_value_set_object (value, priv->conn);
+      break;
+    case PROP_INTERFACES:
+      g_value_set_boxed (value, gabble_roster_channel_interfaces);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+  }
+}
+
+static void
+gabble_roster_channel_set_property (GObject     *object,
+                                    guint        property_id,
+                                    const GValue *value,
+                                    GParamSpec   *pspec)
+{
+  GabbleRosterChannel *chan = GABBLE_ROSTER_CHANNEL (object);
+  GabbleRosterChannelPrivate *priv = GABBLE_ROSTER_CHANNEL_GET_PRIVATE (chan);
+
+  switch (property_id) {
+    case PROP_OBJECT_PATH:
+      g_free (priv->object_path);
+      priv->object_path = g_value_dup_string (value);
+    case PROP_CHANNEL_TYPE:
+      /* in telepathy-glib > 0.7.0 this property is writable in the
+       * interface, but not actually meaningfully changeable on this channel,
+       * so we do nothing */
+      break;
+    case PROP_HANDLE_TYPE:
+      priv->handle_type = g_value_get_uint (value);
+      break;
+    case PROP_HANDLE:
+      priv->handle = g_value_get_uint (value);
+      break;
+    case PROP_CONNECTION:
+      priv->conn = g_value_get_object (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+  }
+}
+
+static void gabble_roster_channel_dispose (GObject *object);
+static void gabble_roster_channel_finalize (GObject *object);
+
+static gboolean _gabble_roster_channel_add_member_cb (GObject *obj,
+    TpHandle handle, const gchar *message, GError **error);
+static gboolean _gabble_roster_channel_remove_member_cb (GObject *obj,
+    TpHandle handle, const gchar *message, GError **error);
+
+static void
+gabble_roster_channel_class_init (GabbleRosterChannelClass *gabble_roster_channel_class)
+{
+  static TpDBusPropertiesMixinPropImpl channel_props[] = {
+      { "TargetHandleType", "handle-type", NULL },
+      { "TargetHandle", "handle", NULL },
+      { "ChannelType", "channel-type", NULL },
+      { "Interfaces", "interfaces", NULL },
+      { NULL }
+  };
+  static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = {
+      { TP_IFACE_CHANNEL,
+        tp_dbus_properties_mixin_getter_gobject_properties,
+        NULL,
+        channel_props,
+      },
+      { NULL }
+  };
+  GObjectClass *object_class = G_OBJECT_CLASS (gabble_roster_channel_class);
+  GParamSpec *param_spec;
+
+  g_type_class_add_private (gabble_roster_channel_class,
+      sizeof (GabbleRosterChannelPrivate));
+
+  object_class->constructor = gabble_roster_channel_constructor;
+
+  object_class->get_property = gabble_roster_channel_get_property;
+  object_class->set_property = gabble_roster_channel_set_property;
+
+  object_class->dispose = gabble_roster_channel_dispose;
+  object_class->finalize = gabble_roster_channel_finalize;
+
+  param_spec = g_param_spec_object ("connection", "GabbleConnection object",
+      "Gabble connection object that owns this Roster channel object.",
+      GABBLE_TYPE_CONNECTION,
+      G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
+      G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB);
+  g_object_class_install_property (object_class, PROP_CONNECTION, param_spec);
+
+  param_spec = g_param_spec_boxed ("interfaces", "Extra D-Bus interfaces",
+      "Additional Channel.Interface.* interfaces",
+      G_TYPE_STRV,
+      G_PARAM_READABLE |
+      G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NAME);
+  g_object_class_install_property (object_class, PROP_INTERFACES, param_spec);
+
+  g_object_class_override_property (object_class, PROP_OBJECT_PATH,
+      "object-path");
+  g_object_class_override_property (object_class, PROP_CHANNEL_TYPE,
+      "channel-type");
+  g_object_class_override_property (object_class, PROP_HANDLE_TYPE,
+      "handle-type");
+  g_object_class_override_property (object_class, PROP_HANDLE, "handle");
+
+  gabble_roster_channel_class->properties_class.interfaces = prop_interfaces;
+  tp_dbus_properties_mixin_class_init (object_class,
+      G_STRUCT_OFFSET (GabbleRosterChannelClass, properties_class));
+
+  tp_group_mixin_class_init (object_class,
+      G_STRUCT_OFFSET (GabbleRosterChannelClass, group_class),
+      _gabble_roster_channel_add_member_cb,
+      _gabble_roster_channel_remove_member_cb);
+  tp_group_mixin_init_dbus_properties (object_class);
+}
+
+void
+gabble_roster_channel_dispose (GObject *object)
+{
+  GabbleRosterChannel *self = GABBLE_ROSTER_CHANNEL (object);
+  GabbleRosterChannelPrivate *priv = GABBLE_ROSTER_CHANNEL_GET_PRIVATE (self);
+
+  if (priv->dispose_has_run)
+    return;
+
+  priv->dispose_has_run = TRUE;
+
+  if (!priv->closed)
+    tp_svc_channel_emit_closed ((TpSvcChannel *)object);
+
+  /* release any references held by the object here */
+
+  if (G_OBJECT_CLASS (gabble_roster_channel_parent_class)->dispose)
+    G_OBJECT_CLASS (gabble_roster_channel_parent_class)->dispose (object);
+}
+
+void
+gabble_roster_channel_finalize (GObject *object)
+{
+  GabbleRosterChannel *self = GABBLE_ROSTER_CHANNEL (object);
+  GabbleRosterChannelPrivate *priv = GABBLE_ROSTER_CHANNEL_GET_PRIVATE (self);
+  TpBaseConnection *conn = (TpBaseConnection *)priv->conn;
+  TpHandleRepoIface *handle_repo = tp_base_connection_get_handles (conn,
+      priv->handle_type);
+
+  /* free any data held directly by the object here */
+
+  g_free (priv->object_path);
+
+  tp_handle_unref (handle_repo, priv->handle);
+
+  tp_group_mixin_finalize (object);
+
+  G_OBJECT_CLASS (gabble_roster_channel_parent_class)->finalize (object);
+}
+
+
+static gboolean
+_gabble_roster_channel_send_presence (GabbleRosterChannel *chan,
+                                      LmMessageSubType sub_type,
+                                      TpHandle handle,
+                                      const gchar *status,
+                                      GError **error)
+{
+  GabbleRosterChannelPrivate *priv;
+  TpBaseConnection *conn;
+  TpHandleRepoIface *repo;
+  const char *contact;
+  LmMessage *message;
+  gboolean result;
+
+  priv = GABBLE_ROSTER_CHANNEL_GET_PRIVATE (chan);
+  conn = (TpBaseConnection *)priv->conn;
+  repo = tp_base_connection_get_handles (conn, TP_HANDLE_TYPE_CONTACT);
+  contact = tp_handle_inspect (repo, handle);
+
+  message = lm_message_new_with_sub_type (contact,
+      LM_MESSAGE_TYPE_PRESENCE,
+      sub_type);
+
+  if (LM_MESSAGE_SUB_TYPE_SUBSCRIBE == sub_type)
+    lm_message_node_add_own_nick (message->node, priv->conn);
+
+  if (status != NULL && status[0] != '\0')
+    lm_message_node_add_child (message->node, "status", status);
+
+  result = _gabble_connection_send (priv->conn, message, error);
+
+  lm_message_unref (message);
+
+  return result;
+}
+
+
+/**
+ * _gabble_roster_channel_add_member_cb
+ *
+ * Called by the group mixin to add one member.
+ */
+static gboolean
+_gabble_roster_channel_add_member_cb (GObject *obj,
+                                      TpHandle handle,
+                                      const gchar *message,
+                                      GError **error)
+{
+  GabbleRosterChannelPrivate *priv;
+  gboolean ret = FALSE;
+#ifdef ENABLE_DEBUG
+  TpHandleRepoIface *handle_repo, *contact_repo;
+#endif
+
+  priv = GABBLE_ROSTER_CHANNEL_GET_PRIVATE (GABBLE_ROSTER_CHANNEL (obj));
+#ifdef ENABLE_DEBUG
+  handle_repo = tp_base_connection_get_handles ((TpBaseConnection *)priv->conn,
+      priv->handle_type);
+  contact_repo = tp_base_connection_get_handles (
+      (TpBaseConnection *)priv->conn, TP_HANDLE_TYPE_CONTACT);
+#endif
+
+  DEBUG ("called on %s with handle %u (%s) \"%s\"",
+      tp_handle_inspect (handle_repo, priv->handle), handle,
+      tp_handle_inspect (contact_repo, handle), message);
+
+  if (TP_HANDLE_TYPE_GROUP == priv->handle_type)
+    {
+      ret = gabble_roster_handle_add_to_group (priv->conn->roster,
+          handle, priv->handle, error);
+    }
+  else if (TP_HANDLE_TYPE_LIST != priv->handle_type)
+    {
+      g_assert_not_reached ();
+      return FALSE;
+    }
+  /* "magic" contact lists, from here down... */
+  /* publish list */
+  else if (GABBLE_LIST_HANDLE_PUBLISH == priv->handle)
+    {
+      /* send <presence type="subscribed"> */
+      ret = _gabble_roster_channel_send_presence (GABBLE_ROSTER_CHANNEL (obj),
+          LM_MESSAGE_SUB_TYPE_SUBSCRIBED, handle, message, error);
+    }
+  /* subscribe list */
+  else if (GABBLE_LIST_HANDLE_SUBSCRIBE == priv->handle)
+    {
+      /* add item to the roster (GTalk depends on this, clearing the H flag) */
+      gabble_roster_handle_add (priv->conn->roster, handle, NULL);
+
+      /* send <presence type="subscribe"> */
+      ret = _gabble_roster_channel_send_presence (GABBLE_ROSTER_CHANNEL (obj),
+          LM_MESSAGE_SUB_TYPE_SUBSCRIBE, handle, message, error);
+    }
+  /* deny list */
+  else if (GABBLE_LIST_HANDLE_DENY == priv->handle)
+    {
+      /* block contact */
+      ret = gabble_roster_handle_set_blocked (priv->conn->roster, handle, TRUE,
+          error);
+    }
+  else
+    {
+      g_assert_not_reached ();
+    }
+
+  return ret;
+}
+
+
+/**
+ * _gabble_roster_channel_remove_member_cb
+ *
+ * Called by the group mixin to remove one member.
+ */
+static gboolean
+_gabble_roster_channel_remove_member_cb (GObject *obj,
+                                         TpHandle handle,
+                                         const gchar *message,
+                                         GError **error)
+{
+  GabbleRosterChannelPrivate *priv;
+#ifdef ENABLE_DEBUG
+  TpBaseConnection *conn;
+  TpHandleRepoIface *handle_repo, *contact_repo;
+#endif
+  gboolean ret = FALSE;
+
+  priv = GABBLE_ROSTER_CHANNEL_GET_PRIVATE (GABBLE_ROSTER_CHANNEL (obj));
+#ifdef ENABLE_DEBUG
+  conn = (TpBaseConnection *)priv->conn;
+  handle_repo = tp_base_connection_get_handles (conn, priv->handle_type);
+  contact_repo = tp_base_connection_get_handles (conn, TP_HANDLE_TYPE_CONTACT);
+#endif
+
+  DEBUG ("called on %s with handle %u (%s) \"%s\"",
+      tp_handle_inspect (handle_repo, priv->handle), handle,
+      tp_handle_inspect (contact_repo, handle), message);
+
+  if (TP_HANDLE_TYPE_GROUP == priv->handle_type)
+    {
+      ret = gabble_roster_handle_remove_from_group (priv->conn->roster,
+          handle, priv->handle, error);
+    }
+  else if (TP_HANDLE_TYPE_LIST != priv->handle_type)
+    {
+      g_assert_not_reached ();
+      return FALSE;
+    }
+  /* "magic" contact lists, from here down... */
+  /* publish list */
+  else if (GABBLE_LIST_HANDLE_PUBLISH == priv->handle)
+    {
+      /* send <presence type="unsubscribed"> */
+      ret = _gabble_roster_channel_send_presence (GABBLE_ROSTER_CHANNEL (obj),
+          LM_MESSAGE_SUB_TYPE_UNSUBSCRIBED, handle, message, error);
+
+      /* remove it from local_pending here, because roster callback doesn't
+         know if it can (subscription='none' is used both during request and
+         when it's rejected) */
+      if (tp_handle_set_is_member (GABBLE_ROSTER_CHANNEL (obj)->group.local_pending, handle))
+        {
+          TpIntSet *rem = tp_intset_new ();
+
+          tp_intset_add (rem, handle);
+          tp_group_mixin_change_members (obj, "", NULL, rem, NULL, NULL,
+              0, 0);
+
+          tp_intset_destroy (rem);
+        }
+    }
+  /* subscribe list */
+  else if (GABBLE_LIST_HANDLE_SUBSCRIBE == priv->handle)
+    {
+      /* send <presence type="unsubscribe"> */
+      ret = _gabble_roster_channel_send_presence (GABBLE_ROSTER_CHANNEL (obj),
+          LM_MESSAGE_SUB_TYPE_UNSUBSCRIBE, handle, message, error);
+    }
+  /* known list */
+  else if (GABBLE_LIST_HANDLE_KNOWN == priv->handle)
+    {
+      /* send roster subscription=remove IQ */
+      ret = gabble_roster_handle_remove (priv->conn->roster, handle, error);
+    }
+  /* deny list */
+  else if (GABBLE_LIST_HANDLE_DENY == priv->handle)
+    {
+      /* unblock contact */
+      ret = gabble_roster_handle_set_blocked (priv->conn->roster, handle,
+          FALSE, error);
+    }
+  else
+    {
+      g_assert_not_reached ();
+    }
+
+  return ret;
+}
+
+
+/**
+ * gabble_roster_channel_close
+ *
+ * Implements D-Bus method Close
+ * on interface org.freedesktop.Telepathy.Channel
+ */
+static void
+gabble_roster_channel_close (TpSvcChannel *iface,
+                             DBusGMethodInvocation *context)
+{
+  GabbleRosterChannel *self = GABBLE_ROSTER_CHANNEL (iface);
+  GabbleRosterChannelPrivate *priv;
+
+  g_assert (GABBLE_IS_ROSTER_CHANNEL (self));
+
+  priv = GABBLE_ROSTER_CHANNEL_GET_PRIVATE (self);
+
+  if (priv->handle_type == TP_HANDLE_TYPE_LIST)
+    {
+      GError e = { TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED,
+          "you may not close contact list channels" };
+
+      dbus_g_method_return_error (context, &e);
+    }
+  else /* TP_HANDLE_TYPE_GROUP */
+    {
+      if (tp_handle_set_size (self->group.members) == 0)
+        {
+          /* deleting groups isn't a concept that exists on XMPP,
+           * so just close the channel */
+
+          priv->closed = TRUE;
+          tp_svc_channel_emit_closed ((TpSvcChannel *)self);
+          tp_svc_channel_return_from_close (context);
+          return;
+        }
+
+      else
+        {
+          GError e = { TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
+              "you may not close this group, because it's not empty" };
+
+          dbus_g_method_return_error (context, &e);
+        }
+    }
+}
+
+
+/**
+ * gabble_roster_channel_get_channel_type
+ *
+ * Implements D-Bus method GetChannelType
+ * on interface org.freedesktop.Telepathy.Channel
+ */
+static void
+gabble_roster_channel_get_channel_type (TpSvcChannel *iface,
+                                        DBusGMethodInvocation *context)
+{
+  tp_svc_channel_return_from_get_channel_type (context,
+      TP_IFACE_CHANNEL_TYPE_CONTACT_LIST);
+}
+
+
+/**
+ * gabble_roster_channel_get_handle
+ *
+ * Implements D-Bus method GetHandle
+ * on interface org.freedesktop.Telepathy.Channel
+ */
+static void
+gabble_roster_channel_get_handle (TpSvcChannel *iface,
+                                  DBusGMethodInvocation *context)
+{
+  GabbleRosterChannel *self = GABBLE_ROSTER_CHANNEL (iface);
+  GabbleRosterChannelPrivate *priv;
+
+  g_assert (GABBLE_IS_ROSTER_CHANNEL (self));
+
+  priv = GABBLE_ROSTER_CHANNEL_GET_PRIVATE (self);
+
+  tp_svc_channel_return_from_get_handle (context, priv->handle_type,
+      priv->handle);
+}
+
+
+/**
+ * gabble_roster_channel_get_interfaces
+ *
+ * Implements D-Bus method GetInterfaces
+ * on interface org.freedesktop.Telepathy.Channel
+ */
+static void
+gabble_roster_channel_get_interfaces (TpSvcChannel *self,
+                                      DBusGMethodInvocation *context)
+{
+  tp_svc_channel_return_from_get_interfaces (context,
+      gabble_roster_channel_interfaces);
+}
+
+
+static void
+channel_iface_init (gpointer g_iface, gpointer iface_data)
+{
+  TpSvcChannelClass *klass = (TpSvcChannelClass *)g_iface;
+
+#define IMPLEMENT(x) tp_svc_channel_implement_##x (\
+    klass, gabble_roster_channel_##x)
+  IMPLEMENT(close);
+  IMPLEMENT(get_channel_type);
+  IMPLEMENT(get_handle);
+  IMPLEMENT(get_interfaces);
+#undef IMPLEMENT
+}
-- 
1.5.6.3




More information about the Telepathy-commits mailing list