From b3acc55a8c6401de41cfc320081e1aa0be17c27a Mon Sep 17 00:00:00 2001 From: Sjoerd Simons Date: Sat, 29 Aug 2009 00:01:47 +0100 Subject: 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/empathy-handler.c | 369 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 369 insertions(+) create mode 100644 libempathy/empathy-handler.c (limited to 'libempathy/empathy-handler.c') diff --git a/libempathy/empathy-handler.c b/libempathy/empathy-handler.c new file mode 100644 index 000000000..649903058 --- /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 + * Sjoerd Simons + * Cosimo Cecchi + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "empathy-handler.h" +#include "empathy-utils.h" + +#define DEBUG_FLAG EMPATHY_DEBUG_DISPATCHER +#include + +#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; +} + -- cgit v1.2.3