]> git.0d.be Git - empathy.git/blob - src/empathy-tube-dispatch.c
Make the dispatch operation _get_ functions not return a ref
[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 <gtk/gtk.h>
30 #include <glib/gi18n.h>
31
32
33 #include <libempathy/empathy-tube-handler.h>
34 #include <extensions/extensions.h>
35
36
37 #include "empathy-tube-dispatch.h"
38 #include "empathy-tube-dispatch-enumtypes.h"
39
40
41 G_DEFINE_TYPE(EmpathyTubeDispatch, empathy_tube_dispatch, G_TYPE_OBJECT)
42
43 static void empathy_tube_dispatch_set_ability (
44   EmpathyTubeDispatch *tube_dispatch,
45   EmpathyTubeDispatchAbility dispatchability);
46
47 /* private structure */
48 typedef struct _EmpathyTubeDispatchPriv EmpathyTubeDispatchPriv;
49
50 /* properties */
51 enum {
52     PROP_OPERATION = 1,
53     PROP_DISPATCHABILITY
54 };
55
56
57 struct _EmpathyTubeDispatchPriv
58 {
59   gboolean dispose_has_run;
60   EmpathyDispatchOperation *operation;
61   EmpathyTubeDispatchAbility dispatchability;
62   gchar *service;
63   gchar *bus_name;
64   gchar *object_path;
65   TpDBusDaemon *dbus;
66 };
67
68 #define GET_PRIV(o) \
69  (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
70   EMPATHY_TYPE_TUBE_DISPATCH, EmpathyTubeDispatchPriv))
71
72 static void
73 empathy_tube_dispatch_init (EmpathyTubeDispatch *obj)
74 {
75   EmpathyTubeDispatchPriv *priv = GET_PRIV (obj);
76
77   priv->dispatchability = EMPATHY_TUBE_DISPATCHABILITY_UNKNOWN;
78 }
79
80 static void empathy_tube_dispatch_dispose (GObject *object);
81 static void empathy_tube_dispatch_finalize (GObject *object);
82
83 static void
84 empathy_tube_dispatch_list_activatable_names_cb (TpDBusDaemon *proxy,
85   const gchar **names, const GError *error, gpointer user_data,
86   GObject *object)
87 {
88   EmpathyTubeDispatch *self = EMPATHY_TUBE_DISPATCH (object);
89   EmpathyTubeDispatchPriv *priv = GET_PRIV (self);
90   gchar **name;
91
92   for (name = (gchar **) names; *name != NULL; name++)
93     {
94       if (!tp_strdiff (*name, priv->bus_name))
95         {
96           empathy_tube_dispatch_set_ability (self,
97             EMPATHY_TUBE_DISPATCHABILITY_POSSIBLE);
98           return;
99         }
100     }
101
102   empathy_tube_dispatch_set_ability (self,
103     EMPATHY_TUBE_DISPATCHABILITY_IMPOSSIBLE);
104 }
105
106 static void
107 empathy_tube_dispatch_name_has_owner_cb (TpDBusDaemon *proxy,
108   gboolean has_owner, const GError *error, gpointer user_data,
109   GObject *object)
110 {
111   EmpathyTubeDispatch *self = EMPATHY_TUBE_DISPATCH (object);
112   EmpathyTubeDispatchPriv *priv = GET_PRIV (self);
113
114   if (error != NULL)
115     {
116       empathy_tube_dispatch_set_ability (self,
117         EMPATHY_TUBE_DISPATCHABILITY_IMPOSSIBLE);
118       return;
119     }
120
121   if (has_owner)
122     {
123       empathy_tube_dispatch_set_ability (self,
124         EMPATHY_TUBE_DISPATCHABILITY_POSSIBLE);
125     }
126   else
127     {
128       tp_cli_dbus_daemon_call_list_activatable_names (priv->dbus, -1,
129         empathy_tube_dispatch_list_activatable_names_cb, NULL, NULL,
130         G_OBJECT (self));
131     }
132 }
133
134 static void
135 empathy_tube_dispatch_constructed (GObject *object)
136 {
137   EmpathyTubeDispatch *self = EMPATHY_TUBE_DISPATCH (object);
138   EmpathyTubeDispatchPriv *priv = GET_PRIV (self);
139   TpChannel *channel;
140   GHashTable *properties;
141   const gchar *service;
142
143   priv->dbus = tp_dbus_daemon_new (tp_get_bus());
144
145   channel = empathy_dispatch_operation_get_channel (priv->operation);
146   properties = tp_channel_borrow_immutable_properties (channel);
147
148   service = tp_asv_get_string (properties,
149     EMP_IFACE_CHANNEL_TYPE_STREAM_TUBE  ".Service");
150
151   if (service == NULL)
152     goto failed;
153
154   priv->bus_name = empathy_tube_handler_build_bus_name (
155     TP_TUBE_TYPE_STREAM, service);
156   priv->object_path =
157     empathy_tube_handler_build_object_path (TP_TUBE_TYPE_STREAM, service);
158
159   priv->service = g_strdup (service);
160
161   tp_cli_dbus_daemon_call_name_has_owner (priv->dbus, -1, priv->bus_name,
162     empathy_tube_dispatch_name_has_owner_cb, NULL, NULL, G_OBJECT (self));
163
164   return;
165
166 failed:
167   empathy_tube_dispatch_set_ability (self,
168     EMPATHY_TUBE_DISPATCHABILITY_IMPOSSIBLE);
169 }
170
171 static void
172 empathy_tube_dispatch_set_property (GObject *object,
173   guint property_id, const GValue *value, GParamSpec *pspec)
174 {
175   EmpathyTubeDispatch *tube_dispatch = EMPATHY_TUBE_DISPATCH (object);
176   EmpathyTubeDispatchPriv *priv = GET_PRIV (tube_dispatch);
177
178   switch (property_id)
179     {
180       case PROP_OPERATION:
181         priv->operation = g_value_dup_object (value);
182         break;
183       default:
184         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
185         break;
186     }
187 }
188
189 static void
190 empathy_tube_dispatch_get_property (GObject *object,
191   guint property_id, GValue *value, GParamSpec *pspec)
192 {
193   EmpathyTubeDispatch *tube_dispatch = EMPATHY_TUBE_DISPATCH (object);
194   EmpathyTubeDispatchPriv *priv = GET_PRIV (tube_dispatch);
195
196   switch (property_id)
197     {
198       case PROP_OPERATION:
199         g_value_set_object (value, priv->operation);
200         break;
201       case PROP_DISPATCHABILITY:
202         g_value_set_enum (value, priv->dispatchability);
203         break;
204       default:
205         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
206         break;
207     }
208 }
209
210 static void
211 empathy_tube_dispatch_class_init (
212   EmpathyTubeDispatchClass *empathy_tube_dispatch_class)
213 {
214   GObjectClass *object_class = G_OBJECT_CLASS (empathy_tube_dispatch_class);
215   GParamSpec *param_spec;
216
217   g_type_class_add_private (empathy_tube_dispatch_class,
218     sizeof (EmpathyTubeDispatchPriv));
219
220   object_class->set_property = empathy_tube_dispatch_set_property;
221   object_class->get_property = empathy_tube_dispatch_get_property;
222
223   object_class->constructed = empathy_tube_dispatch_constructed;
224   object_class->dispose = empathy_tube_dispatch_dispose;
225   object_class->finalize = empathy_tube_dispatch_finalize;
226
227   param_spec = g_param_spec_object ("operation",
228     "operation", "The telepathy connection",
229     EMPATHY_TYPE_DISPATCH_OPERATION,
230     G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
231   g_object_class_install_property (object_class, PROP_OPERATION, param_spec);
232
233   param_spec = g_param_spec_enum ("dispatchability",
234     "dispatchability",
235     "Whether or not there is a handler to dispatch the operation to",
236     EMPATHY_TYPE_TUBE_DISPATCH_ABILITY, EMPATHY_TUBE_DISPATCHABILITY_UNKNOWN,
237     G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
238   g_object_class_install_property (object_class, PROP_DISPATCHABILITY,
239     param_spec);
240
241 }
242
243 void
244 empathy_tube_dispatch_dispose (GObject *object)
245 {
246   EmpathyTubeDispatch *self = EMPATHY_TUBE_DISPATCH (object);
247   EmpathyTubeDispatchPriv *priv = GET_PRIV (self);
248
249   if (priv->dispose_has_run)
250     return;
251
252   priv->dispose_has_run = TRUE;
253
254   /* release any references held by the object here */
255   if (priv->operation != NULL)
256     g_object_unref (priv->operation);
257
258   priv->operation = NULL;
259
260   if (priv->dbus != NULL)
261     g_object_unref (priv->dbus);
262
263   priv->dbus = NULL;
264
265
266   if (G_OBJECT_CLASS (empathy_tube_dispatch_parent_class)->dispose)
267     G_OBJECT_CLASS (empathy_tube_dispatch_parent_class)->dispose (object);
268 }
269
270 void
271 empathy_tube_dispatch_finalize (GObject *object)
272 {
273   EmpathyTubeDispatch *self = EMPATHY_TUBE_DISPATCH (object);
274   EmpathyTubeDispatchPriv *priv = GET_PRIV (self);
275
276   g_free (priv->bus_name);
277   g_free (priv->object_path);
278   g_free (priv->service);
279
280   /* free any data held directly by the object here */
281
282   G_OBJECT_CLASS (empathy_tube_dispatch_parent_class)->finalize (object);
283 }
284
285 EmpathyTubeDispatch *
286 empathy_tube_dispatch_new (EmpathyDispatchOperation *operation)
287 {
288   return EMPATHY_TUBE_DISPATCH (g_object_new (EMPATHY_TYPE_TUBE_DISPATCH,
289       "operation", operation, NULL));
290 }
291
292 EmpathyTubeDispatchAbility
293 empathy_tube_dispatch_is_dispatchable (EmpathyTubeDispatch *tube_dispatch)
294 {
295   EmpathyTubeDispatchPriv *priv = GET_PRIV (tube_dispatch);
296
297   return priv->dispatchability;
298 }
299
300 static void
301 empathy_tube_dispatch_set_ability (EmpathyTubeDispatch *tube_dispatch,
302   EmpathyTubeDispatchAbility dispatchability)
303 {
304   EmpathyTubeDispatchPriv *priv = GET_PRIV (tube_dispatch);
305
306   if (priv->dispatchability == dispatchability)
307     return;
308
309   priv->dispatchability = dispatchability;
310   g_object_notify (G_OBJECT (tube_dispatch), "dispatchability");
311 }
312
313 static void
314 empathy_tube_dispatch_show_error (EmpathyTubeDispatch *self, gchar *message)
315 {
316   GtkWidget *dialog;
317
318   dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL,
319       GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE, message);
320
321   gtk_dialog_run (GTK_DIALOG (dialog));
322
323   gtk_widget_destroy (dialog);
324 }
325
326 static void
327 empathy_tube_dispatch_handle_tube_cb (TpProxy *proxy, const GError *error,
328   gpointer user_data, GObject *object)
329 {
330   EmpathyTubeDispatch *self = EMPATHY_TUBE_DISPATCH (object);
331   EmpathyTubeDispatchPriv *priv = GET_PRIV (self);
332
333   if (error != NULL)
334     {
335       gchar *msg = g_strdup_printf (
336         _("Unable to start application for service %s: %s"),
337           priv->service,  error->message);
338
339       empathy_tube_dispatch_show_error (self, msg);
340       g_free (msg);
341     }
342
343   /* Remove the ref we were holding because of the dispatching */
344   g_object_unref (object);
345 }
346
347 static void
348 empathy_tube_do_dispatch (EmpathyTubeDispatch *self)
349 {
350   EmpathyTubeDispatchPriv *priv = GET_PRIV (self);
351   TpChannel *channel;
352   TpProxy *connection;
353   TpProxy *thandler;
354   gchar   *object_path;
355   guint    handle_type;
356   guint    handle;
357
358   channel = empathy_dispatch_operation_get_channel (priv->operation);
359
360   /* Create the proxy for the tube handler */
361   thandler = g_object_new (TP_TYPE_PROXY,
362     "dbus-connection", tp_get_bus (),
363     "bus-name", priv->bus_name,
364     "object-path", priv->object_path,
365     NULL);
366
367   tp_proxy_add_interface_by_id (thandler, EMP_IFACE_QUARK_TUBE_HANDLER);
368
369   /* Give the tube to the handler */
370   g_object_get (channel,
371     "connection", &connection,
372     "object-path", &object_path,
373     "handle_type", &handle_type,
374     "handle", &handle,
375     NULL);
376
377   emp_cli_tube_handler_call_handle_tube (thandler, -1,
378     connection->bus_name, connection->object_path,
379     object_path, handle_type, handle,
380     empathy_tube_dispatch_handle_tube_cb, NULL, NULL, G_OBJECT (self));
381
382   g_object_unref (thandler);
383   g_object_unref (connection);
384   g_free (object_path);
385 }
386
387 void
388 empathy_tube_dispatch_handle (EmpathyTubeDispatch *tube_dispatch)
389 {
390   EmpathyTubeDispatchPriv *priv = GET_PRIV (tube_dispatch);
391
392   /* Keep ourselves alive untill the dispatching is finished */
393   g_object_ref (tube_dispatch);
394
395   /* If we can't claim it, don't do anything */
396   if (!empathy_dispatch_operation_claim (priv->operation))
397     goto done;
398
399   if (priv->dispatchability != EMPATHY_TUBE_DISPATCHABILITY_POSSIBLE)
400     {
401       gchar *msg;
402       TpChannel *channel;
403
404       channel = empathy_dispatch_operation_get_channel (priv->operation);
405
406       msg = g_strdup_printf (
407         _(" An invitation was offered for service %s, but you don't have the"
408           " needed application to handle it "), priv->service);
409
410       empathy_tube_dispatch_show_error (tube_dispatch, msg);
411
412       g_free (msg);
413
414       tp_cli_channel_call_close (channel, -1, NULL, NULL, NULL, NULL);
415
416       goto done;
417     }
418   else
419     {
420       empathy_tube_do_dispatch (tube_dispatch);
421     }
422
423   return;
424 done:
425   g_object_unref (tube_dispatch);
426 }
427