[empathy] Add a simple abstraction for implementing handlers



commit b3acc55a8c6401de41cfc320081e1aa0be17c27a
Author: Sjoerd Simons <sjoerd simons collabora co uk>
Date:   Sat Aug 29 00:01:47 2009 +0100

    Add a simple abstraction for implementing handlers
    
    Implement an EmpathyHandler object which can be used to easily add extra
    Client.Handler heads on D-Bus.

 libempathy/Makefile.am          |    2 +
 libempathy/empathy-dispatcher.c |  215 ++++++++++-------------
 libempathy/empathy-dispatcher.h |    7 +-
 libempathy/empathy-handler.c    |  369 +++++++++++++++++++++++++++++++++++++++
 libempathy/empathy-handler.h    |   89 ++++++++++
 src/empathy.c                   |   59 ++++++-
 6 files changed, 615 insertions(+), 126 deletions(-)
---
diff --git a/libempathy/Makefile.am b/libempathy/Makefile.am
index ad36ede..e45b16d 100644
--- a/libempathy/Makefile.am
+++ b/libempathy/Makefile.am
@@ -45,6 +45,7 @@ libempathy_la_SOURCES =					\
 	empathy-dispatch-operation.c			\
 	empathy-ft-factory.c				\
 	empathy-ft-handler.c				\
+	empathy-handler.c				\
 	empathy-idle.c					\
 	empathy-irc-network.c				\
 	empathy-irc-network-manager.c			\
@@ -100,6 +101,7 @@ libempathy_headers =				\
 	empathy-dispatch-operation.h		\
 	empathy-ft-factory.h			\
 	empathy-ft-handler.h			\
+	empathy-handler.h			\
 	empathy-idle.h				\
 	empathy-irc-network.h			\
 	empathy-irc-network-manager.h		\
diff --git a/libempathy/empathy-dispatcher.c b/libempathy/empathy-dispatcher.c
index c1a19f6..dfd041d 100644
--- a/libempathy/empathy-dispatcher.c
+++ b/libempathy/empathy-dispatcher.c
@@ -42,6 +42,7 @@
 #include <extensions/extensions.h>
 
 #include "empathy-dispatcher.h"
+#include "empathy-handler.h"
 #include "empathy-utils.h"
 #include "empathy-tube-handler.h"
 #include "empathy-account-manager.h"
@@ -64,33 +65,33 @@ typedef struct
 
   /* channels which the dispatcher is listening "invalidated" */
   GList *channels;
+  GPtrArray *array;
+  EmpathyHandler *handler;
 
   GHashTable *request_channel_class_async_ids;
 } EmpathyDispatcherPriv;
 
-static void empathy_dispatcher_client_handler_iface_init (gpointer g_iface,
-  gpointer g_iface_data);
-
-G_DEFINE_TYPE_WITH_CODE (EmpathyDispatcher,
-    empathy_dispatcher,
-    G_TYPE_OBJECT,
-    G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES,
-      tp_dbus_properties_mixin_iface_init);
-    G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CLIENT, NULL);
-    G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CLIENT_HANDLER,
-      empathy_dispatcher_client_handler_iface_init);
-  );
-
-static const gchar *empathy_dispatcher_interfaces[] = {
-  TP_IFACE_CLIENT_HANDLER,
-  NULL
-};
+static GList *
+empathy_dispatcher_get_channels (EmpathyHandler *handler,
+    gpointer user_data);
+
+static gboolean
+empathy_dispatcher_handle_channels (EmpathyHandler *handler,
+    const gchar *account_path,
+    const gchar *connection_path,
+    const GPtrArray *channels,
+    const GPtrArray *requests_satisfied,
+    guint64 timestamp,
+    GHashTable *handler_info,
+    gpointer user_data,
+    GError **error);
+
+G_DEFINE_TYPE (EmpathyDispatcher, empathy_dispatcher, G_TYPE_OBJECT);
 
 enum
 {
   PROP_INTERFACES = 1,
-  PROP_CHANNEL_FILTER,
-  PROP_CHANNELS
+  PROP_HANDLER,
 };
 
 enum
@@ -865,7 +866,7 @@ dispatcher_constructor (GType type,
                         GObjectConstructParam *construct_params)
 {
   GObject *retval;
-  TpDBusDaemon *dbus;
+  EmpathyDispatcherPriv *priv;
 
   if (dispatcher != NULL)
     return g_object_ref (dispatcher);
@@ -876,14 +877,15 @@ dispatcher_constructor (GType type,
   dispatcher = EMPATHY_DISPATCHER (retval);
   g_object_add_weak_pointer (retval, (gpointer) &dispatcher);
 
-  dbus = tp_dbus_daemon_dup (NULL);
+  priv = GET_PRIV (dispatcher);
 
-  g_assert (tp_dbus_daemon_request_name (dbus,
-    DISPATCHER_BUS_NAME, TRUE, NULL));
-  dbus_g_connection_register_g_object (tp_get_bus (),
-    DISPATCHER_OBJECT_PATH, retval);
+  empathy_handler_set_handle_channels_func (priv->handler,
+    empathy_dispatcher_handle_channels,
+    dispatcher);
 
-  DEBUG ("Registering at '%s'", DISPATCHER_OBJECT_PATH);
+  empathy_handler_set_channels_func (priv->handler,
+    empathy_dispatcher_get_channels,
+    dispatcher);
 
   return retval;
 }
@@ -936,9 +938,9 @@ dispatcher_finalize (GObject *object)
 }
 
 static void
-dispatcher_get_property (GObject *object,
+dispatcher_set_property (GObject *object,
   guint property_id,
-  GValue *value,
+  const GValue *value,
   GParamSpec *pspec)
 {
   EmpathyDispatcher *dispatcher = EMPATHY_DISPATCHER (object);
@@ -946,37 +948,29 @@ dispatcher_get_property (GObject *object,
 
   switch (property_id)
     {
-      case PROP_INTERFACES:
-        g_value_set_boxed (value, empathy_dispatcher_interfaces);
+      case PROP_HANDLER:
+        priv->handler = g_value_dup_object (value);
         break;
-      case PROP_CHANNEL_FILTER:
-        {
-          GPtrArray *filters = g_ptr_array_new ();
-          GHashTable *filter = g_hash_table_new (NULL, NULL);
-
-          g_ptr_array_add (filters, filter);
-
-          g_value_set_boxed (value, filters);
-          break;
-        }
-      case PROP_CHANNELS:
-        {
-          GPtrArray *accounts;
-          GList *l;
-
-          accounts = g_ptr_array_new ();
-
-          for (l = priv->channels; l != NULL; l = g_list_next (l))
-            {
-              TpProxy *channel = TP_PROXY (l->data);
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+        break;
+    }
+}
 
-              g_ptr_array_add (accounts,
-                g_strdup (tp_proxy_get_object_path (channel)));
-            }
+static void
+dispatcher_get_property (GObject *object,
+  guint property_id,
+  GValue *value,
+  GParamSpec *pspec)
+{
+  EmpathyDispatcher *dispatcher = EMPATHY_DISPATCHER (object);
+  EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher);
 
-          g_value_set_boxed (value, accounts);
-          break;
-        }
+  switch (property_id)
+    {
+      case PROP_HANDLER:
+        g_value_set_object (value, priv->handler);
+        break;
       default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
         break;
@@ -989,53 +983,18 @@ empathy_dispatcher_class_init (EmpathyDispatcherClass *klass)
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
   GParamSpec *param_spec;
 
-  static TpDBusPropertiesMixinPropImpl client_props[] = {
-    { "Interfaces", "interfaces", NULL },
-    { NULL }
-  };
-  static TpDBusPropertiesMixinPropImpl client_handler_props[] = {
-    { "HandlerChannelFilter", "channel-filter", NULL },
-    { "HandledChannels", "channels", NULL },
-    { NULL }
-  };
-  static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = {
-    { TP_IFACE_CLIENT,
-      tp_dbus_properties_mixin_getter_gobject_properties,
-      NULL,
-      client_props
-    },
-    { TP_IFACE_CLIENT_HANDLER,
-      tp_dbus_properties_mixin_getter_gobject_properties,
-      NULL,
-      client_handler_props
-    },
-    { NULL }
-  };
-
   object_class->finalize = dispatcher_finalize;
   object_class->constructor = dispatcher_constructor;
 
   object_class->get_property = dispatcher_get_property;
+  object_class->set_property = dispatcher_set_property;
 
-  param_spec = g_param_spec_boxed ("interfaces", "interfaces",
-    "Available D-Bus interfaces",
-    G_TYPE_STRV,
-    G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
-  g_object_class_install_property (object_class, PROP_INTERFACES, param_spec);
-
-  param_spec = g_param_spec_boxed ("channel-filter", "channel-filter",
-    "Filter for channels this handles",
-    TP_ARRAY_TYPE_CHANNEL_CLASS_LIST,
-    G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
-  g_object_class_install_property (object_class,
-    PROP_CHANNEL_FILTER, param_spec);
-
-  param_spec = g_param_spec_boxed ("channels", "channels",
-    "List of channels we're handling",
-    EMPATHY_ARRAY_TYPE_OBJECT,
-    G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+  param_spec = g_param_spec_object ("handler", "handler",
+    "The main Telepathy Client Hander object",
+    EMPATHY_TYPE_HANDLER,
+    G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
   g_object_class_install_property (object_class,
-    PROP_CHANNELS, param_spec);
+    PROP_HANDLER, param_spec);
 
   signals[OBSERVE] =
     g_signal_new ("observe",
@@ -1069,10 +1028,6 @@ empathy_dispatcher_class_init (EmpathyDispatcherClass *klass)
 
 
   g_type_class_add_private (object_class, sizeof (EmpathyDispatcherPriv));
-
-  klass->dbus_props_class.interfaces = prop_interfaces;
-  tp_dbus_properties_mixin_class_init (object_class,
-    G_STRUCT_OFFSET (EmpathyDispatcherClass, dbus_props_class));
 }
 
 static void
@@ -1110,6 +1065,26 @@ empathy_dispatcher_init (EmpathyDispatcher *dispatcher)
 }
 
 EmpathyDispatcher *
+empathy_dispatcher_new (const gchar *name,
+  GPtrArray *filters,
+  GStrv capabilities)
+{
+  g_assert (dispatcher == NULL);
+  EmpathyHandler *handler;
+  EmpathyDispatcher *ret;
+
+  handler = empathy_handler_new (name, filters, capabilities);
+
+  ret = EMPATHY_DISPATCHER (
+    g_object_new (EMPATHY_TYPE_DISPATCHER,
+      "handler", handler,
+      NULL));
+  g_object_unref (handler);
+
+  return ret;
+}
+
+EmpathyDispatcher *
 empathy_dispatcher_dup_singleton (void)
 {
   return EMPATHY_DISPATCHER (g_object_new (EMPATHY_TYPE_DISPATCHER, NULL));
@@ -1797,17 +1772,28 @@ empathy_dispatcher_find_requestable_channel_classes_async
     request, GUINT_TO_POINTER (source_id));
 }
 
-static void
-empathy_dispatcher_handle_channels (TpSvcClientHandler *self,
+static GList *
+empathy_dispatcher_get_channels (EmpathyHandler *handler,
+  gpointer user_data)
+{
+  EmpathyDispatcher *dispatcher = EMPATHY_DISPATCHER (user_data);
+  EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher);
+
+  return priv->channels;
+}
+
+static gboolean
+empathy_dispatcher_handle_channels (EmpathyHandler *handler,
     const gchar *account_path,
     const gchar *connection_path,
     const GPtrArray *channels,
     const GPtrArray *requests_satisfied,
     guint64 timestamp,
     GHashTable *handler_info,
-    DBusGMethodInvocation *context)
+    gpointer user_data,
+    GError **error)
 {
-  EmpathyDispatcher *dispatcher = EMPATHY_DISPATCHER (self);
+  EmpathyDispatcher *dispatcher = EMPATHY_DISPATCHER (user_data);
   EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher);
   int i;
   EmpathyAccount *account;
@@ -1821,10 +1807,9 @@ empathy_dispatcher_handle_channels (TpSvcClientHandler *self,
       connection_path);
   if (connection == NULL)
     {
-      GError error = { TP_ERRORS, TP_ERROR_INVALID_ARGUMENT,
-        "Invalid connection argument" };
-      dbus_g_method_return_error (context, &error);
-      return;
+      g_set_error_literal (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT,
+        "Invalid connection argument");
+      return FALSE;
     }
 
   for (i = 0; i < channels->len ; i++)
@@ -1840,15 +1825,5 @@ empathy_dispatcher_handle_channels (TpSvcClientHandler *self,
         connection, object_path, properties);
     }
 
-  tp_svc_client_handler_return_from_handle_channels (context);
-}
-
-static void
-empathy_dispatcher_client_handler_iface_init (gpointer g_iface,
-  gpointer g_iface_data)
-{
-  TpSvcClientHandlerClass *klass = (TpSvcClientHandlerClass *) g_iface;
-
-  tp_svc_client_handler_implement_handle_channels (klass,
-    empathy_dispatcher_handle_channels);
+  return TRUE;
 }
diff --git a/libempathy/empathy-dispatcher.h b/libempathy/empathy-dispatcher.h
index 41a1430..c4daa60 100644
--- a/libempathy/empathy-dispatcher.h
+++ b/libempathy/empathy-dispatcher.h
@@ -26,7 +26,6 @@
 #include <gio/gio.h>
 
 #include <telepathy-glib/channel.h>
-#include <telepathy-glib/dbus-properties-mixin.h>
 
 #include "empathy-contact.h"
 #include "empathy-dispatch-operation.h"
@@ -52,7 +51,6 @@ struct _EmpathyDispatcher
 struct _EmpathyDispatcherClass
 {
  GObjectClass parent_class;
- TpDBusPropertiesMixinClass dbus_props_class;
 };
 
 /* Will be called when the channel is ready for dispatching. The requestor
@@ -98,6 +96,11 @@ GList * empathy_dispatcher_find_requestable_channel_classes
      const gchar *channel_type, guint handle_type,
      const char *first_property_name, ...);
 
+/* Create the dispatcher singleton */
+EmpathyDispatcher * empathy_dispatcher_new (const gchar *name,
+  GPtrArray *filters,
+  GStrv capabilities);
+
 /* Get the dispatcher singleton */
 EmpathyDispatcher *    empathy_dispatcher_dup_singleton (void);
 
diff --git a/libempathy/empathy-handler.c b/libempathy/empathy-handler.c
new file mode 100644
index 0000000..6499030
--- /dev/null
+++ b/libempathy/empathy-handler.c
@@ -0,0 +1,369 @@
+/*
+ * 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
+ * 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
+ *
+ * Authors: Xavier Claessens <xclaesse gmail com>
+ *          Sjoerd Simons <sjoerd simons collabora co uk>
+ *          Cosimo Cecchi <cosimo cecchi collabora co uk>
+ */
+
+#include <config.h>
+
+#include <telepathy-glib/dbus.h>
+#include <telepathy-glib/proxy-subclass.h>
+#include <telepathy-glib/gtypes.h>
+#include <telepathy-glib/defs.h>
+#include <telepathy-glib/svc-client.h>
+#include <telepathy-glib/svc-generic.h>
+#include <telepathy-glib/interfaces.h>
+
+#include "empathy-handler.h"
+#include "empathy-utils.h"
+
+#define DEBUG_FLAG EMPATHY_DEBUG_DISPATCHER
+#include <libempathy/empathy-debug.h>
+
+#define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyHandler)
+typedef struct
+{
+  EmpathyHandlerHandleChannelsFunc *handle_channels;
+  gpointer handle_channels_user_data;
+
+  EmpathyHandlerChannelsFunc *channels;
+  gpointer channels_user_data;
+
+  gchar *name;
+
+  GPtrArray *filters;
+  GStrv *capabilities;
+} EmpathyHandlerPriv;
+
+static void empathy_handler_client_handler_iface_init (gpointer g_iface,
+    gpointer g_iface_data);
+
+G_DEFINE_TYPE_WITH_CODE (EmpathyHandler,
+    empathy_handler,
+    G_TYPE_OBJECT,
+    G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES,
+      tp_dbus_properties_mixin_iface_init);
+    G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CLIENT, NULL);
+    G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CLIENT_HANDLER,
+      empathy_handler_client_handler_iface_init);
+  );
+
+static const gchar *empathy_handler_interfaces[] = {
+  TP_IFACE_CLIENT_HANDLER,
+  NULL
+};
+
+enum
+{
+  PROP_INTERFACES = 1,
+  PROP_CHANNEL_FILTER,
+  PROP_CHANNELS,
+  PROP_CAPABILITIES,
+  PROP_NAME,
+};
+
+static GObject *
+handler_constructor (GType type,
+    guint n_construct_params,
+    GObjectConstructParam *construct_params)
+{
+  GObject *obj =
+    G_OBJECT_CLASS (empathy_handler_parent_class)->constructor
+      (type, n_construct_params, construct_params);
+  EmpathyHandler *handler = EMPATHY_HANDLER (obj);
+  EmpathyHandlerPriv *priv = GET_PRIV (handler);
+  TpDBusDaemon *dbus;
+  gchar *busname;
+  gchar *object_path;
+
+  priv = GET_PRIV (handler);
+
+  busname = g_strdup_printf (TP_CLIENT_BUS_NAME_BASE"%s", priv->name);
+  object_path = g_strdup_printf (TP_CLIENT_OBJECT_PATH_BASE"%s",
+    priv->name);
+
+  dbus = tp_dbus_daemon_dup (NULL);
+
+  g_assert (tp_dbus_daemon_request_name (dbus,
+    busname, TRUE, NULL));
+  dbus_g_connection_register_g_object (tp_get_bus (),
+    object_path, obj);
+
+  DEBUG ("Registered at '%s'", object_path);
+
+  g_free (busname);
+  g_free (object_path);
+  g_object_unref (dbus);
+
+  return G_OBJECT (handler);
+}
+
+static void
+handler_finalize (GObject *object)
+{
+  EmpathyHandlerPriv *priv = GET_PRIV (object);
+
+  if (priv->filters != NULL)
+    g_boxed_free (TP_ARRAY_TYPE_CHANNEL_CLASS_LIST, priv->filters);
+
+  if (priv->capabilities != NULL)
+    g_boxed_free (G_TYPE_STRV, priv->capabilities);
+
+  g_free (priv->name);
+}
+
+static void
+handler_set_property (GObject *object,
+    guint property_id,
+    const GValue *value,
+    GParamSpec *pspec)
+{
+  EmpathyHandler *handler = EMPATHY_HANDLER (object);
+  EmpathyHandlerPriv *priv = GET_PRIV (handler);
+
+  switch (property_id)
+    {
+      case PROP_CHANNEL_FILTER:
+        priv->filters = g_value_dup_boxed (value);
+        break;
+      case PROP_CAPABILITIES:
+        priv->capabilities = g_value_dup_boxed (value);
+        break;
+      case PROP_NAME:
+        priv->name = g_value_dup_string (value);
+        break;
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+        break;
+    }
+}
+
+static void
+handler_get_property (GObject *object,
+    guint property_id,
+    GValue *value,
+    GParamSpec *pspec)
+{
+  EmpathyHandler *self = EMPATHY_HANDLER (object);
+  EmpathyHandlerPriv *priv = GET_PRIV (self);
+
+  switch (property_id)
+    {
+      case PROP_INTERFACES:
+        g_value_set_boxed (value, empathy_handler_interfaces);
+        break;
+      case PROP_CHANNEL_FILTER:
+        g_value_set_boxed (value, priv->filters);
+        break;
+      case PROP_CAPABILITIES:
+        g_value_set_boxed (value, priv->capabilities);
+        break;
+      case PROP_NAME:
+        g_value_set_string (value, priv->name);
+        break;
+      case PROP_CHANNELS:
+        {
+          GList *l, *channels = NULL;
+          GPtrArray *array = g_ptr_array_new ();
+
+          if (priv->channels != NULL)
+            channels =  priv->channels (self, priv->channels_user_data);
+
+          for (l = channels ; l != NULL; l = g_list_next (l))
+            {
+              TpProxy *channel = TP_PROXY (l->data);
+              g_ptr_array_add (array,
+                (gpointer) tp_proxy_get_object_path (channel));
+            }
+          g_value_set_boxed (value, array);
+          g_ptr_array_free (array, TRUE);
+          break;
+        }
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+        break;
+    }
+}
+
+static void
+empathy_handler_class_init (EmpathyHandlerClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GParamSpec *param_spec;
+
+  static TpDBusPropertiesMixinPropImpl client_props[] = {
+    { "Interfaces", "interfaces", NULL },
+    { NULL }
+  };
+  static TpDBusPropertiesMixinPropImpl client_handler_props[] = {
+    { "HandlerChannelFilter", "channel-filter", NULL },
+    { "HandledChannels", "channels", NULL },
+    { "Capabilities", "capabilities", NULL },
+    { NULL }
+  };
+  static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = {
+    { TP_IFACE_CLIENT,
+      tp_dbus_properties_mixin_getter_gobject_properties,
+      NULL,
+      client_props
+    },
+    { TP_IFACE_CLIENT_HANDLER,
+      tp_dbus_properties_mixin_getter_gobject_properties,
+      NULL,
+      client_handler_props
+    },
+    { NULL }
+  };
+
+  object_class->finalize = handler_finalize;
+  object_class->constructor = handler_constructor;
+
+  object_class->get_property = handler_get_property;
+  object_class->set_property = handler_set_property;
+
+  param_spec = g_param_spec_boxed ("interfaces", "interfaces",
+    "Available D-Bus interfaces",
+    G_TYPE_STRV,
+    G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+  g_object_class_install_property (object_class, PROP_INTERFACES, param_spec);
+
+  param_spec = g_param_spec_boxed ("channel-filter", "channel-filter",
+    "Filter for channels this handles",
+    TP_ARRAY_TYPE_CHANNEL_CLASS_LIST,
+    G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
+  g_object_class_install_property (object_class,
+    PROP_CHANNEL_FILTER, param_spec);
+
+  param_spec = g_param_spec_boxed ("capabilities", "capabilities",
+    "Filter for channels this handles",
+    G_TYPE_STRV,
+    G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
+  g_object_class_install_property (object_class,
+    PROP_CAPABILITIES, param_spec);
+
+  param_spec = g_param_spec_boxed ("channels", "channels",
+    "List of channels we're handling",
+    EMPATHY_ARRAY_TYPE_OBJECT,
+    G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+  g_object_class_install_property (object_class,
+    PROP_CHANNELS, param_spec);
+
+  param_spec = g_param_spec_string ("name", "name",
+    "The local name of the handler",
+    NULL,
+    G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
+  g_object_class_install_property (object_class,
+    PROP_NAME, param_spec);
+
+  g_type_class_add_private (object_class, sizeof (EmpathyHandlerPriv));
+
+  klass->dbus_props_class.interfaces = prop_interfaces;
+  tp_dbus_properties_mixin_class_init (object_class,
+    G_STRUCT_OFFSET (EmpathyHandlerClass, dbus_props_class));
+}
+
+static void
+empathy_handler_init (EmpathyHandler *handler)
+{
+  EmpathyHandlerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (handler,
+    EMPATHY_TYPE_HANDLER, EmpathyHandlerPriv);
+
+  handler->priv = priv;
+}
+
+EmpathyHandler *
+empathy_handler_new (const gchar *name,
+    GPtrArray *filters,
+    GStrv capabilities)
+{
+  return EMPATHY_HANDLER (
+    g_object_new (EMPATHY_TYPE_HANDLER,
+      "name", name,
+      "channel-filter", filters,
+      "capabilities", capabilities,
+      NULL));
+}
+
+static void
+empathy_handler_handle_channels (TpSvcClientHandler *self,
+    const gchar *account_path,
+    const gchar *connection_path,
+    const GPtrArray *channels,
+    const GPtrArray *requests_satisfied,
+    guint64 timestamp,
+    GHashTable *handler_info,
+    DBusGMethodInvocation *context)
+{
+  EmpathyHandler *handler = EMPATHY_HANDLER (self);
+  EmpathyHandlerPriv *priv = GET_PRIV (handler);
+  GError *error = NULL;
+
+  if (!priv->handle_channels)
+    {
+      error = g_error_new_literal (TP_ERRORS,
+        TP_ERROR_NOT_AVAILABLE,
+        "No handler function setup");
+      goto error;
+    }
+
+  if (!priv->handle_channels (handler, account_path, connection_path,
+      channels, requests_satisfied, timestamp, handler_info,
+      priv->handle_channels_user_data, &error))
+    goto error;
+
+  tp_svc_client_handler_return_from_handle_channels (context);
+  return;
+
+error:
+  dbus_g_method_return_error (context, error);
+  g_error_free (error);
+}
+
+static void
+empathy_handler_client_handler_iface_init (gpointer g_iface,
+    gpointer g_iface_data)
+{
+  TpSvcClientHandlerClass *klass = (TpSvcClientHandlerClass *) g_iface;
+
+  tp_svc_client_handler_implement_handle_channels (klass,
+    empathy_handler_handle_channels);
+}
+
+void
+empathy_handler_set_handle_channels_func (EmpathyHandler *handler,
+    EmpathyHandlerHandleChannelsFunc *func,
+    gpointer user_data)
+{
+  EmpathyHandlerPriv *priv = GET_PRIV (handler);
+
+  priv->handle_channels = func;
+  priv->handle_channels_user_data = user_data;
+}
+
+void
+empathy_handler_set_channels_func (EmpathyHandler *handler,
+    EmpathyHandlerChannelsFunc *func,
+    gpointer user_data)
+{
+  EmpathyHandlerPriv *priv = GET_PRIV (handler);
+
+  priv->channels = func;
+  priv->channels_user_data = user_data;
+}
+
diff --git a/libempathy/empathy-handler.h b/libempathy/empathy-handler.h
new file mode 100644
index 0000000..684ec0c
--- /dev/null
+++ b/libempathy/empathy-handler.h
@@ -0,0 +1,89 @@
+/*
+ * 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
+ * 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
+ *
+ * Authors: Sjoerd Simons <sjoerd simons collabora co uk>
+ */
+
+#ifndef __EMPATHY_HANDLER_H__
+#define __EMPATHY_HANDLER_H__
+
+#include <glib.h>
+
+#include <telepathy-glib/channel.h>
+#include <telepathy-glib/dbus-properties-mixin.h>
+
+G_BEGIN_DECLS
+
+#define EMPATHY_TYPE_HANDLER         (empathy_handler_get_type ())
+#define EMPATHY_HANDLER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), \
+  EMPATHY_TYPE_HANDLER, EmpathyHandler))
+#define EMPATHY_HANDLER_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), \
+  EMPATHY_TYPE_HANDLER, EmpathyHandlerClass))
+#define EMPATHY_IS_HANDLER(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), \
+  EMPATHY_TYPE_HANDLER))
+#define EMPATHY_IS_HANDLER_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), \
+  EMPATHY_TYPE_HANDLER))
+#define EMPATHY_HANDLER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), \
+  EMPATHY_TYPE_HANDLER, EmpathyHandlerClass))
+
+GType empathy_handler_get_type (void) G_GNUC_CONST;
+
+typedef struct _EmpathyHandler      EmpathyHandler;
+typedef struct _EmpathyHandlerClass EmpathyHandlerClass;
+
+struct _EmpathyHandler
+{
+  GObject parent;
+  gpointer priv;
+};
+
+struct _EmpathyHandlerClass
+{
+  GObjectClass parent_class;
+  TpDBusPropertiesMixinClass dbus_props_class;
+};
+
+
+EmpathyHandler * empathy_handler_new (const gchar *name,
+    GPtrArray *filters,
+    GStrv capabilities);
+
+typedef gboolean (EmpathyHandlerHandleChannelsFunc) (EmpathyHandler *handler,
+    const gchar *account_path,
+    const gchar *connection_path,
+    const GPtrArray *channels,
+    const GPtrArray *requests_satisfied,
+    guint64 timestamp,
+    GHashTable *handler_info,
+    gpointer user_data,
+    GError **error);
+
+void empathy_handler_set_handle_channels_func (EmpathyHandler *handler,
+    EmpathyHandlerHandleChannelsFunc *func,
+    gpointer user_data);
+
+typedef GList * (EmpathyHandlerChannelsFunc) (
+    EmpathyHandler *handler,
+    gpointer user_data);
+
+void empathy_handler_set_channels_func (EmpathyHandler *handler,
+    EmpathyHandlerChannelsFunc func,
+    gpointer user_data);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_HANDLER_H__ */
diff --git a/src/empathy.c b/src/empathy.c
index 38fd56c..f7017bd 100644
--- a/src/empathy.c
+++ b/src/empathy.c
@@ -558,6 +558,57 @@ account_manager_ready_cb (EmpathyAccountManager *manager,
     }
 }
 
+static EmpathyDispatcher *
+setup_dispatcher (void)
+{
+  EmpathyDispatcher *d;
+  GPtrArray *filters;
+  struct {
+    const gchar *channeltype;
+    TpHandleType handletype;
+  } types[] = {
+    /* Text channels with handle types none, contact and room */
+    { TP_IFACE_CHANNEL_TYPE_TEXT, TP_HANDLE_TYPE_NONE  },
+    { TP_IFACE_CHANNEL_TYPE_TEXT, TP_HANDLE_TYPE_CONTACT  },
+    { TP_IFACE_CHANNEL_TYPE_TEXT, TP_HANDLE_TYPE_ROOM  },
+    /* file transfer to contacts */
+    { TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER, TP_HANDLE_TYPE_CONTACT  },
+    /* stream media to contacts */
+    { TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, TP_HANDLE_TYPE_CONTACT  },
+    /* stream tubes to contacts and rooms */
+    { TP_IFACE_CHANNEL_TYPE_STREAM_TUBE, TP_HANDLE_TYPE_CONTACT  },
+    { TP_IFACE_CHANNEL_TYPE_STREAM_TUBE, TP_HANDLE_TYPE_ROOM  },
+    /* d-bus tubes to contacts and rooms */
+    { TP_IFACE_CHANNEL_TYPE_DBUS_TUBE, TP_HANDLE_TYPE_CONTACT },
+    { TP_IFACE_CHANNEL_TYPE_DBUS_TUBE, TP_HANDLE_TYPE_ROOM  },
+    /* roomlists */
+    { TP_IFACE_CHANNEL_TYPE_ROOM_LIST, TP_HANDLE_TYPE_NONE },
+  };
+  GStrv capabilities = { NULL };
+  int i;
+
+  filters = g_ptr_array_new ();
+
+  for (i = 0 ; i < G_N_ELEMENTS (types); i++)
+    {
+      GHashTable *asv;
+
+      asv = tp_asv_new (
+        TP_IFACE_CHANNEL ".ChannelType", G_TYPE_STRING, types[i].channeltype,
+        TP_IFACE_CHANNEL ".TargetHandleType", G_TYPE_INT, types[i].handletype,
+        NULL);
+
+      g_ptr_array_add (filters, asv);
+    }
+
+  d = empathy_dispatcher_new (PACKAGE_NAME, filters, capabilities);
+
+  g_ptr_array_foreach (filters, (GFunc) g_hash_table_destroy, NULL);
+  g_ptr_array_free (filters, TRUE);
+
+  return d;
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -699,6 +750,10 @@ main (int argc, char *argv[])
   g_signal_connect (account_manager, "notify::ready",
       G_CALLBACK (account_manager_ready_cb), NULL);
 
+  /* Handle channels */
+  dispatcher = setup_dispatcher ();
+  g_signal_connect (dispatcher, "dispatch", G_CALLBACK (dispatch_cb), NULL);
+
   migrate_config_to_xdg_dir ();
 
   /* Setting up UI */
@@ -708,10 +763,6 @@ main (int argc, char *argv[])
   g_signal_connect (unique_app, "message-received",
       G_CALLBACK (unique_app_message_cb), window);
 
-  /* Handle channels */
-  dispatcher = empathy_dispatcher_dup_singleton ();
-  g_signal_connect (dispatcher, "dispatch", G_CALLBACK (dispatch_cb), NULL);
-
   /* Logging */
   log_manager = empathy_log_manager_dup_singleton ();
   empathy_log_manager_observe (log_manager, dispatcher);



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