]> git.0d.be Git - empathy.git/blob - libempathy/empathy-handler.c
Always call _ensure_channel for text chats.
[empathy.git] / libempathy / empathy-handler.c
1 /*
2  * Copyright (C) 2007-2009 Collabora Ltd.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  *
18  * Authors: Xavier Claessens <xclaesse@gmail.com>
19  *          Sjoerd Simons <sjoerd.simons@collabora.co.uk>
20  *          Cosimo Cecchi <cosimo.cecchi@collabora.co.uk>
21  */
22
23 #include <config.h>
24
25 #include <telepathy-glib/dbus.h>
26 #include <telepathy-glib/proxy-subclass.h>
27 #include <telepathy-glib/gtypes.h>
28 #include <telepathy-glib/defs.h>
29 #include <telepathy-glib/svc-client.h>
30 #include <telepathy-glib/svc-generic.h>
31 #include <telepathy-glib/interfaces.h>
32
33 #include "empathy-handler.h"
34 #include "empathy-utils.h"
35
36 #define DEBUG_FLAG EMPATHY_DEBUG_DISPATCHER
37 #include <libempathy/empathy-debug.h>
38
39 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyHandler)
40 typedef struct
41 {
42   EmpathyHandlerHandleChannelsFunc *handle_channels;
43   gpointer handle_channels_user_data;
44
45   EmpathyHandlerChannelsFunc *channels;
46   gpointer channels_user_data;
47
48   gchar *name;
49   gchar *busname;
50
51   GPtrArray *filters;
52   GStrv *capabilities;
53
54   gboolean dispose_run;
55 } EmpathyHandlerPriv;
56
57 static void empathy_handler_client_handler_iface_init (gpointer g_iface,
58     gpointer g_iface_data);
59
60 G_DEFINE_TYPE_WITH_CODE (EmpathyHandler,
61     empathy_handler,
62     G_TYPE_OBJECT,
63     G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES,
64       tp_dbus_properties_mixin_iface_init);
65     G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CLIENT, NULL);
66     G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CLIENT_HANDLER,
67       empathy_handler_client_handler_iface_init);
68   );
69
70 static const gchar *empathy_handler_interfaces[] = {
71   TP_IFACE_CLIENT_HANDLER,
72   NULL
73 };
74
75 enum
76 {
77   PROP_INTERFACES = 1,
78   PROP_CHANNEL_FILTER,
79   PROP_CHANNELS,
80   PROP_CAPABILITIES,
81   PROP_NAME,
82 };
83
84 static GObject *
85 handler_constructor (GType type,
86     guint n_construct_params,
87     GObjectConstructParam *construct_params)
88 {
89   GObject *obj =
90     G_OBJECT_CLASS (empathy_handler_parent_class)->constructor
91       (type, n_construct_params, construct_params);
92   EmpathyHandler *handler = EMPATHY_HANDLER (obj);
93   EmpathyHandlerPriv *priv = GET_PRIV (handler);
94   TpDBusDaemon *dbus;
95   gchar *object_path;
96
97   priv = GET_PRIV (handler);
98
99   priv->busname = g_strdup_printf (TP_CLIENT_BUS_NAME_BASE"%s", priv->name);
100   object_path = g_strdup_printf (TP_CLIENT_OBJECT_PATH_BASE"%s",
101     priv->name);
102
103   dbus = tp_dbus_daemon_dup (NULL);
104
105   g_assert (tp_dbus_daemon_request_name (dbus,
106     priv->busname, TRUE, NULL));
107   dbus_g_connection_register_g_object (tp_get_bus (),
108     object_path, obj);
109
110   DEBUG ("Registered at '%s'", object_path);
111
112   g_free (object_path);
113   g_object_unref (dbus);
114
115   return G_OBJECT (handler);
116 }
117
118 static void
119 handler_dispose (GObject *object)
120 {
121   EmpathyHandlerPriv *priv = GET_PRIV (object);
122   TpDBusDaemon *dbus;
123
124   if (priv->dispose_run)
125     return;
126
127   priv->dispose_run = TRUE;
128
129   dbus = tp_dbus_daemon_dup (NULL);
130
131   tp_dbus_daemon_release_name (dbus, priv->busname, NULL);
132
133   g_object_unref (dbus);
134
135   if (G_OBJECT_CLASS (empathy_handler_parent_class)->dispose != NULL)
136     G_OBJECT_CLASS (empathy_handler_parent_class)->dispose (object);
137 }
138
139 static void
140 handler_finalize (GObject *object)
141 {
142   EmpathyHandlerPriv *priv = GET_PRIV (object);
143
144   if (priv->filters != NULL)
145     g_boxed_free (TP_ARRAY_TYPE_CHANNEL_CLASS_LIST, priv->filters);
146
147   if (priv->capabilities != NULL)
148     g_boxed_free (G_TYPE_STRV, priv->capabilities);
149
150   g_free (priv->name);
151   g_free (priv->busname);
152
153   if (G_OBJECT_CLASS (empathy_handler_parent_class)->finalize != NULL)
154     G_OBJECT_CLASS (empathy_handler_parent_class)->finalize (object);
155 }
156
157 static void
158 handler_set_property (GObject *object,
159     guint property_id,
160     const GValue *value,
161     GParamSpec *pspec)
162 {
163   EmpathyHandler *handler = EMPATHY_HANDLER (object);
164   EmpathyHandlerPriv *priv = GET_PRIV (handler);
165
166   switch (property_id)
167     {
168       case PROP_CHANNEL_FILTER:
169         priv->filters = g_value_dup_boxed (value);
170         if (priv->filters == NULL)
171           priv->filters = g_ptr_array_new ();
172         break;
173       case PROP_CAPABILITIES:
174         priv->capabilities = g_value_dup_boxed (value);
175         break;
176       case PROP_NAME:
177         priv->name = g_value_dup_string (value);
178         if (EMP_STR_EMPTY (priv->name))
179           {
180             TpDBusDaemon *bus;
181
182             bus = tp_dbus_daemon_dup (NULL);
183             priv->name = g_strdup_printf ("%s%p",
184                 tp_dbus_daemon_get_unique_name (bus), object);
185             g_object_unref (bus);
186           }
187         break;
188       default:
189         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
190         break;
191     }
192 }
193
194 static void
195 handler_get_property (GObject *object,
196     guint property_id,
197     GValue *value,
198     GParamSpec *pspec)
199 {
200   EmpathyHandler *self = EMPATHY_HANDLER (object);
201   EmpathyHandlerPriv *priv = GET_PRIV (self);
202
203   switch (property_id)
204     {
205       case PROP_INTERFACES:
206         g_value_set_boxed (value, empathy_handler_interfaces);
207         break;
208       case PROP_CHANNEL_FILTER:
209         g_value_set_boxed (value, priv->filters);
210         break;
211       case PROP_CAPABILITIES:
212         g_value_set_boxed (value, priv->capabilities);
213         break;
214       case PROP_NAME:
215         g_value_set_string (value, priv->name);
216         break;
217       case PROP_CHANNELS:
218         {
219           GList *l, *channels = NULL;
220           GPtrArray *array = g_ptr_array_new ();
221
222           if (priv->channels != NULL)
223             channels =  priv->channels (self, priv->channels_user_data);
224
225           for (l = channels ; l != NULL; l = g_list_next (l))
226             {
227               TpProxy *channel = TP_PROXY (l->data);
228               g_ptr_array_add (array,
229                 (gpointer) tp_proxy_get_object_path (channel));
230             }
231           g_value_set_boxed (value, array);
232           g_ptr_array_free (array, TRUE);
233           break;
234         }
235       default:
236         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
237         break;
238     }
239 }
240
241 static void
242 empathy_handler_class_init (EmpathyHandlerClass *klass)
243 {
244   GObjectClass *object_class = G_OBJECT_CLASS (klass);
245   GParamSpec *param_spec;
246
247   static TpDBusPropertiesMixinPropImpl client_props[] = {
248     { "Interfaces", "interfaces", NULL },
249     { NULL }
250   };
251   static TpDBusPropertiesMixinPropImpl client_handler_props[] = {
252     { "HandlerChannelFilter", "channel-filter", NULL },
253     { "HandledChannels", "channels", NULL },
254     { "Capabilities", "capabilities", NULL },
255     { NULL }
256   };
257   static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = {
258     { TP_IFACE_CLIENT,
259       tp_dbus_properties_mixin_getter_gobject_properties,
260       NULL,
261       client_props
262     },
263     { TP_IFACE_CLIENT_HANDLER,
264       tp_dbus_properties_mixin_getter_gobject_properties,
265       NULL,
266       client_handler_props
267     },
268     { NULL }
269   };
270
271   object_class->finalize = handler_finalize;
272   object_class->dispose = handler_dispose;
273   object_class->constructor = handler_constructor;
274
275   object_class->get_property = handler_get_property;
276   object_class->set_property = handler_set_property;
277
278   param_spec = g_param_spec_boxed ("interfaces", "interfaces",
279     "Available D-Bus interfaces",
280     G_TYPE_STRV,
281     G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
282   g_object_class_install_property (object_class, PROP_INTERFACES, param_spec);
283
284   param_spec = g_param_spec_boxed ("channel-filter", "channel-filter",
285     "Filter for channels this handles",
286     TP_ARRAY_TYPE_CHANNEL_CLASS_LIST,
287     G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
288   g_object_class_install_property (object_class,
289     PROP_CHANNEL_FILTER, param_spec);
290
291   param_spec = g_param_spec_boxed ("capabilities", "capabilities",
292     "Filter for channels this handles",
293     G_TYPE_STRV,
294     G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
295   g_object_class_install_property (object_class,
296     PROP_CAPABILITIES, param_spec);
297
298   param_spec = g_param_spec_boxed ("channels", "channels",
299     "List of channels we're handling",
300     EMPATHY_ARRAY_TYPE_OBJECT,
301     G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
302   g_object_class_install_property (object_class,
303     PROP_CHANNELS, param_spec);
304
305   param_spec = g_param_spec_string ("name", "name",
306     "The local name of the handler",
307     NULL,
308     G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
309   g_object_class_install_property (object_class,
310     PROP_NAME, param_spec);
311
312   g_type_class_add_private (object_class, sizeof (EmpathyHandlerPriv));
313
314   klass->dbus_props_class.interfaces = prop_interfaces;
315   tp_dbus_properties_mixin_class_init (object_class,
316     G_STRUCT_OFFSET (EmpathyHandlerClass, dbus_props_class));
317 }
318
319 static void
320 empathy_handler_init (EmpathyHandler *handler)
321 {
322   EmpathyHandlerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (handler,
323     EMPATHY_TYPE_HANDLER, EmpathyHandlerPriv);
324
325   handler->priv = priv;
326 }
327
328 EmpathyHandler *
329 empathy_handler_new (const gchar *name,
330     GPtrArray *filters,
331     GStrv capabilities)
332 {
333   return EMPATHY_HANDLER (
334     g_object_new (EMPATHY_TYPE_HANDLER,
335       "name", name,
336       "channel-filter", filters,
337       "capabilities", capabilities,
338       NULL));
339 }
340
341 static void
342 empathy_handler_handle_channels (TpSvcClientHandler *self,
343     const gchar *account_path,
344     const gchar *connection_path,
345     const GPtrArray *channels,
346     const GPtrArray *requests_satisfied,
347     guint64 timestamp,
348     GHashTable *handler_info,
349     DBusGMethodInvocation *context)
350 {
351   EmpathyHandler *handler = EMPATHY_HANDLER (self);
352   EmpathyHandlerPriv *priv = GET_PRIV (handler);
353   GError *error = NULL;
354
355   if (!priv->handle_channels)
356     {
357       error = g_error_new_literal (TP_ERRORS,
358         TP_ERROR_NOT_AVAILABLE,
359         "No handler function setup");
360       goto error;
361     }
362
363   if (!priv->handle_channels (handler, account_path, connection_path,
364       channels, requests_satisfied, timestamp, handler_info,
365       priv->handle_channels_user_data, &error))
366     goto error;
367
368   tp_svc_client_handler_return_from_handle_channels (context);
369   return;
370
371 error:
372   dbus_g_method_return_error (context, error);
373   g_error_free (error);
374 }
375
376 static void
377 empathy_handler_client_handler_iface_init (gpointer g_iface,
378     gpointer g_iface_data)
379 {
380   TpSvcClientHandlerClass *klass = (TpSvcClientHandlerClass *) g_iface;
381
382   tp_svc_client_handler_implement_handle_channels (klass,
383     empathy_handler_handle_channels);
384 }
385
386 void
387 empathy_handler_set_handle_channels_func (EmpathyHandler *handler,
388     EmpathyHandlerHandleChannelsFunc *func,
389     gpointer user_data)
390 {
391   EmpathyHandlerPriv *priv = GET_PRIV (handler);
392
393   priv->handle_channels = func;
394   priv->handle_channels_user_data = user_data;
395 }
396
397 void
398 empathy_handler_set_channels_func (EmpathyHandler *handler,
399     EmpathyHandlerChannelsFunc *func,
400     gpointer user_data)
401 {
402   EmpathyHandlerPriv *priv = GET_PRIV (handler);
403
404   priv->channels = func;
405   priv->channels_user_data = user_data;
406 }
407