]> git.0d.be Git - empathy.git/blob - src/empathy-tube-dispatch.c
Add EmpathyTubeDispatcher as a helper for dispatching tubes
[empathy.git] / src / empathy-tube-dispatch.c
1 /*
2  * empathy-tube-dispatch.c - Source for EmpathyTubeDispatch
3  * Copyright (C) 2008 Collabora Ltd.
4  * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20
21
22 #include <stdio.h>
23 #include <stdlib.h>
24
25 #include <telepathy-glib/dbus.h>
26 #include <telepathy-glib/util.h>
27 #include <telepathy-glib/proxy-subclass.h>
28
29 #include <libempathy/empathy-tube-handler.h>
30 #include <extensions/extensions.h>
31
32 #include "empathy-tube-dispatch.h"
33 #include "empathy-tube-dispatch-enumtypes.h"
34
35
36 G_DEFINE_TYPE(EmpathyTubeDispatch, empathy_tube_dispatch, G_TYPE_OBJECT)
37
38 static void empathy_tube_dispatch_set_ability (
39   EmpathyTubeDispatch *tube_dispatch,
40   EmpathyTubeDispatchAbility dispatchability);
41
42 /* private structure */
43 typedef struct _EmpathyTubeDispatchPriv EmpathyTubeDispatchPriv;
44
45 /* properties */
46 enum {
47     PROP_OPERATION = 1,
48     PROP_DISPATCHABILITY
49 };
50
51
52 struct _EmpathyTubeDispatchPriv
53 {
54   gboolean dispose_has_run;
55   EmpathyDispatchOperation *operation;
56   EmpathyTubeDispatchAbility dispatchability;
57   gchar *bus_name;
58   gchar *object_path;
59   TpDBusDaemon *dbus;
60 };
61
62 #define GET_PRIV(o) \
63  (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
64   EMPATHY_TYPE_TUBE_DISPATCH, EmpathyTubeDispatchPriv))
65
66 static void
67 empathy_tube_dispatch_init (EmpathyTubeDispatch *obj)
68 {
69   EmpathyTubeDispatchPriv *priv = GET_PRIV (obj);
70
71   priv->dispatchability = EMPATHY_TUBE_DISPATCHABILITY_UNKNOWN;
72 }
73
74 static void empathy_tube_dispatch_dispose (GObject *object);
75 static void empathy_tube_dispatch_finalize (GObject *object);
76
77 static void
78 empathy_tube_dispatch_list_activatable_names_cb (TpDBusDaemon *proxy,
79   const gchar **names, const GError *error, gpointer user_data,
80   GObject *object)
81 {
82   EmpathyTubeDispatch *self = EMPATHY_TUBE_DISPATCH (object);
83   EmpathyTubeDispatchPriv *priv = GET_PRIV (self);
84   gchar **name;
85
86   for (name = (gchar **) names; *name != NULL; name++)
87     {
88       if (!tp_strdiff (*name, priv->bus_name))
89         {
90           empathy_tube_dispatch_set_ability (self,
91             EMPATHY_TUBE_DISPATCHABILITY_POSSIBLE);
92           return;
93         }
94     }
95
96   empathy_tube_dispatch_set_ability (self,
97     EMPATHY_TUBE_DISPATCHABILITY_IMPOSSIBLE);
98 }
99
100 static void
101 empathy_tube_dispatch_name_has_owner_cb (TpDBusDaemon *proxy,
102   gboolean has_owner, const GError *error, gpointer user_data,
103   GObject *object)
104 {
105   EmpathyTubeDispatch *self = EMPATHY_TUBE_DISPATCH (object);
106   EmpathyTubeDispatchPriv *priv = GET_PRIV (self);
107
108   if (error != NULL)
109     {
110       empathy_tube_dispatch_set_ability (self,
111         EMPATHY_TUBE_DISPATCHABILITY_IMPOSSIBLE);
112       return;
113     }
114
115   if (has_owner)
116     {
117       empathy_tube_dispatch_set_ability (self,
118         EMPATHY_TUBE_DISPATCHABILITY_POSSIBLE);
119     }
120   else
121     {
122       tp_cli_dbus_daemon_call_list_activatable_names (priv->dbus, -1,
123         empathy_tube_dispatch_list_activatable_names_cb, NULL, NULL,
124         G_OBJECT (self));
125     }
126 }
127
128 static void
129 empathy_tube_dispatch_constructed (GObject *object)
130 {
131   EmpathyTubeDispatch *self = EMPATHY_TUBE_DISPATCH (object);
132   EmpathyTubeDispatchPriv *priv = GET_PRIV (self);
133   TpChannel *channel;
134   GHashTable *properties;
135   const gchar *service;
136
137   priv->dbus = tp_dbus_daemon_new (tp_get_bus());
138
139   channel = empathy_dispatch_operation_get_channel (priv->operation);
140   properties = tp_channel_borrow_immutable_properties (channel);
141
142   service = tp_asv_get_string (properties,
143     EMP_IFACE_CHANNEL_TYPE_STREAM_TUBE  ".Service");
144
145
146   if (service == NULL)
147     goto failed;
148
149   priv->bus_name = empathy_tube_handler_build_bus_name (
150     TP_TUBE_TYPE_STREAM, service);
151   priv->object_path =
152     empathy_tube_handler_build_object_path (TP_TUBE_TYPE_STREAM, service);
153
154   tp_cli_dbus_daemon_call_name_has_owner (priv->dbus, -1, priv->bus_name,
155     empathy_tube_dispatch_name_has_owner_cb, NULL, NULL, G_OBJECT (self));
156
157
158   g_object_unref (channel);
159   return;
160
161 failed:
162   empathy_tube_dispatch_set_ability (self,
163     EMPATHY_TUBE_DISPATCHABILITY_IMPOSSIBLE);
164 }
165
166 static void
167 empathy_tube_dispatch_set_property (GObject *object,
168   guint property_id, const GValue *value, GParamSpec *pspec)
169 {
170   EmpathyTubeDispatch *tube_dispatch = EMPATHY_TUBE_DISPATCH (object);
171   EmpathyTubeDispatchPriv *priv = GET_PRIV (tube_dispatch);
172
173   switch (property_id)
174     {
175       case PROP_OPERATION:
176         priv->operation = g_value_dup_object (value);
177         break;
178       default:
179         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
180         break;
181     }
182 }
183
184 static void
185 empathy_tube_dispatch_get_property (GObject *object,
186   guint property_id, GValue *value, GParamSpec *pspec)
187 {
188   EmpathyTubeDispatch *tube_dispatch = EMPATHY_TUBE_DISPATCH (object);
189   EmpathyTubeDispatchPriv *priv = GET_PRIV (tube_dispatch);
190
191   switch (property_id)
192     {
193       case PROP_OPERATION:
194         g_value_set_object (value, priv->operation);
195         break;
196       case PROP_DISPATCHABILITY:
197         g_value_set_enum (value, priv->dispatchability);
198         break;
199       default:
200         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
201         break;
202     }
203 }
204
205 static void
206 empathy_tube_dispatch_class_init (
207   EmpathyTubeDispatchClass *empathy_tube_dispatch_class)
208 {
209   GObjectClass *object_class = G_OBJECT_CLASS (empathy_tube_dispatch_class);
210   GParamSpec *param_spec;
211
212   g_type_class_add_private (empathy_tube_dispatch_class,
213     sizeof (EmpathyTubeDispatchPriv));
214
215   object_class->set_property = empathy_tube_dispatch_set_property;
216   object_class->get_property = empathy_tube_dispatch_get_property;
217
218   object_class->constructed = empathy_tube_dispatch_constructed;
219   object_class->dispose = empathy_tube_dispatch_dispose;
220   object_class->finalize = empathy_tube_dispatch_finalize;
221
222   param_spec = g_param_spec_object ("operation",
223     "operation", "The telepathy connection",
224     EMPATHY_TYPE_DISPATCH_OPERATION,
225     G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
226   g_object_class_install_property (object_class, PROP_OPERATION, param_spec);
227
228   param_spec = g_param_spec_enum ("dispatchability",
229     "dispatchability",
230     "Whether or not there is a handler to dispatch the operation to",
231     EMPATHY_TYPE_TUBE_DISPATCH_ABILITY, EMPATHY_TUBE_DISPATCHABILITY_UNKNOWN,
232     G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
233   g_object_class_install_property (object_class, PROP_DISPATCHABILITY,
234     param_spec);
235
236 }
237
238 void
239 empathy_tube_dispatch_dispose (GObject *object)
240 {
241   EmpathyTubeDispatch *self = EMPATHY_TUBE_DISPATCH (object);
242   EmpathyTubeDispatchPriv *priv = GET_PRIV (self);
243
244   if (priv->dispose_has_run)
245     return;
246
247   priv->dispose_has_run = TRUE;
248
249   /* release any references held by the object here */
250   if (priv->operation != NULL)
251     g_object_unref (priv->operation);
252
253   priv->operation = NULL;
254
255   if (priv->dbus != NULL)
256     g_object_unref (priv->dbus);
257
258   priv->dbus = NULL;
259
260
261   if (G_OBJECT_CLASS (empathy_tube_dispatch_parent_class)->dispose)
262     G_OBJECT_CLASS (empathy_tube_dispatch_parent_class)->dispose (object);
263 }
264
265 void
266 empathy_tube_dispatch_finalize (GObject *object)
267 {
268   EmpathyTubeDispatch *self = EMPATHY_TUBE_DISPATCH (object);
269   EmpathyTubeDispatchPriv *priv = GET_PRIV (self);
270
271   g_free (priv->bus_name);
272   g_free (priv->object_path);
273
274   /* free any data held directly by the object here */
275
276   G_OBJECT_CLASS (empathy_tube_dispatch_parent_class)->finalize (object);
277 }
278
279 EmpathyTubeDispatch *
280 empathy_tube_dispatch_new (EmpathyDispatchOperation *operation)
281 {
282   return EMPATHY_TUBE_DISPATCH (g_object_new (EMPATHY_TYPE_TUBE_DISPATCH,
283       "operation", operation, NULL));
284 }
285
286 EmpathyTubeDispatchAbility
287 empathy_tube_dispatch_is_dispatchable (EmpathyTubeDispatch *tube_dispatch)
288 {
289   EmpathyTubeDispatchPriv *priv = GET_PRIV (tube_dispatch);
290
291   return priv->dispatchability;
292 }
293
294 static void
295 empathy_tube_dispatch_set_ability (EmpathyTubeDispatch *tube_dispatch,
296   EmpathyTubeDispatchAbility dispatchability)
297 {
298   EmpathyTubeDispatchPriv *priv = GET_PRIV (tube_dispatch);
299
300   if (priv->dispatchability == dispatchability)
301     return;
302
303   priv->dispatchability = dispatchability;
304   g_object_notify (G_OBJECT (tube_dispatch), "dispatchability");
305 }
306
307 static void
308 empathy_tube_do_dispatch (EmpathyTubeDispatch *self)
309 {
310   EmpathyTubeDispatchPriv *priv = GET_PRIV (self);
311   TpChannel *channel;
312   TpProxy *connection;
313   TpProxy *thandler;
314   gchar   *object_path;
315   guint    handle_type;
316   guint    handle;
317
318   channel = empathy_dispatch_operation_get_channel (priv->operation);
319
320
321   /* Create the proxy for the tube handler */
322   thandler = g_object_new (TP_TYPE_PROXY,
323     "dbus-connection", tp_get_bus (),
324     "bus-name", priv->bus_name,
325     "object-path", priv->object_path,
326     NULL);
327
328   tp_proxy_add_interface_by_id (thandler, EMP_IFACE_QUARK_TUBE_HANDLER);
329
330   /* Give the tube to the handler */
331   g_object_get (channel,
332     "connection", &connection,
333     "object-path", &object_path,
334     "handle_type", &handle_type,
335     "handle", &handle,
336     NULL);
337
338   emp_cli_tube_handler_call_handle_tube (thandler, -1,
339     connection->bus_name, connection->object_path,
340     object_path, handle_type, handle, NULL, NULL, NULL, NULL);
341
342   g_object_unref (channel);
343   g_object_unref (thandler);
344   g_object_unref (connection);
345   g_free (object_path);
346 }
347
348 void
349 empathy_tube_dispatch_handle (EmpathyTubeDispatch *tube_dispatch)
350 {
351   EmpathyTubeDispatchPriv *priv = GET_PRIV (tube_dispatch);
352
353   /* Keep ourselves alive untill the dispatching is finished */
354   g_object_ref (tube_dispatch);
355
356   /* If we can't claim it, don't do anything */
357   if (!empathy_dispatch_operation_claim (priv->operation))
358     goto done;
359
360   if (priv->dispatchability != EMPATHY_TUBE_DISPATCHABILITY_POSSIBLE)
361     {
362       TpChannel *channel = empathy_dispatch_operation_get_channel (
363         priv->operation);
364
365       tp_cli_channel_call_close (channel, -1, NULL, NULL, NULL, NULL);
366
367       g_object_unref (channel);
368       goto done;
369     }
370
371   empathy_tube_do_dispatch (tube_dispatch);
372
373   return;
374 done:
375   g_object_unref (tube_dispatch);
376 }
377