2 * empathy-tube-dispatch.c - Source for EmpathyTubeDispatch
3 * Copyright (C) 2008 Collabora Ltd.
4 * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk>
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.
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.
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
25 #include <telepathy-glib/dbus.h>
26 #include <telepathy-glib/util.h>
27 #include <telepathy-glib/proxy-subclass.h>
30 #include <glib/gi18n.h>
33 #include <libempathy/empathy-tube-handler.h>
34 #include <extensions/extensions.h>
37 #include "empathy-tube-dispatch.h"
38 #include "empathy-tube-dispatch-enumtypes.h"
40 #define DEBUG_FLAG EMPATHY_DEBUG_DISPATCHER
41 #include <libempathy/empathy-debug.h>
43 G_DEFINE_TYPE(EmpathyTubeDispatch
, empathy_tube_dispatch
, G_TYPE_OBJECT
)
45 static void empathy_tube_dispatch_set_ability (
46 EmpathyTubeDispatch
*tube_dispatch
,
47 EmpathyTubeDispatchAbility dispatchability
);
49 /* private structure */
50 typedef struct _EmpathyTubeDispatchPriv EmpathyTubeDispatchPriv
;
59 struct _EmpathyTubeDispatchPriv
61 gboolean dispose_has_run
;
62 EmpathyDispatchOperation
*operation
;
63 EmpathyTubeDispatchAbility dispatchability
;
71 (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
72 EMPATHY_TYPE_TUBE_DISPATCH, EmpathyTubeDispatchPriv))
75 empathy_tube_dispatch_init (EmpathyTubeDispatch
*obj
)
77 EmpathyTubeDispatchPriv
*priv
= GET_PRIV (obj
);
79 priv
->dispatchability
= EMPATHY_TUBE_DISPATCHABILITY_UNKNOWN
;
82 static void empathy_tube_dispatch_dispose (GObject
*object
);
83 static void empathy_tube_dispatch_finalize (GObject
*object
);
86 empathy_tube_dispatch_list_activatable_names_cb (TpDBusDaemon
*proxy
,
87 const gchar
**names
, const GError
*error
, gpointer user_data
,
90 EmpathyTubeDispatch
*self
= EMPATHY_TUBE_DISPATCH (object
);
91 EmpathyTubeDispatchPriv
*priv
= GET_PRIV (self
);
94 for (name
= (gchar
**) names
; *name
!= NULL
; name
++)
96 if (!tp_strdiff (*name
, priv
->bus_name
))
98 DEBUG ("Found tube handler. Can dispatch it");
99 empathy_tube_dispatch_set_ability (self
,
100 EMPATHY_TUBE_DISPATCHABILITY_POSSIBLE
);
105 DEBUG ("Didn't find tube handler. Can't dispatch it");
106 empathy_tube_dispatch_set_ability (self
,
107 EMPATHY_TUBE_DISPATCHABILITY_IMPOSSIBLE
);
111 empathy_tube_dispatch_name_has_owner_cb (TpDBusDaemon
*proxy
,
112 gboolean has_owner
, const GError
*error
, gpointer user_data
,
115 EmpathyTubeDispatch
*self
= EMPATHY_TUBE_DISPATCH (object
);
116 EmpathyTubeDispatchPriv
*priv
= GET_PRIV (self
);
120 DEBUG ("NameHasOwner failed. Can't dispatch tube");
121 empathy_tube_dispatch_set_ability (self
,
122 EMPATHY_TUBE_DISPATCHABILITY_IMPOSSIBLE
);
128 DEBUG ("Tube handler is running. Can dispatch it");
129 empathy_tube_dispatch_set_ability (self
,
130 EMPATHY_TUBE_DISPATCHABILITY_POSSIBLE
);
134 DEBUG ("Tube handler is not running. Calling ListActivatableNames");
135 tp_cli_dbus_daemon_call_list_activatable_names (priv
->dbus
, -1,
136 empathy_tube_dispatch_list_activatable_names_cb
, NULL
, NULL
,
142 empathy_tube_dispatch_constructed (GObject
*object
)
144 EmpathyTubeDispatch
*self
= EMPATHY_TUBE_DISPATCH (object
);
145 EmpathyTubeDispatchPriv
*priv
= GET_PRIV (self
);
147 GHashTable
*properties
;
148 const gchar
*service
;
149 const gchar
*channel_type
;
152 priv
->dbus
= tp_dbus_daemon_new (tp_get_bus());
154 channel
= empathy_dispatch_operation_get_channel (priv
->operation
);
155 properties
= tp_channel_borrow_immutable_properties (channel
);
157 channel_type
= tp_asv_get_string (properties
,
158 TP_IFACE_CHANNEL
".ChannelType");
159 if (channel_type
== NULL
)
162 if (!tp_strdiff (channel_type
, EMP_IFACE_CHANNEL_TYPE_STREAM_TUBE
))
164 type
= TP_TUBE_TYPE_STREAM
;
165 service
= tp_asv_get_string (properties
,
166 EMP_IFACE_CHANNEL_TYPE_STREAM_TUBE
".Service");
168 else if (!tp_strdiff (channel_type
, EMP_IFACE_CHANNEL_TYPE_DBUS_TUBE
))
170 type
= TP_TUBE_TYPE_DBUS
;
171 service
= tp_asv_get_string (properties
,
172 EMP_IFACE_CHANNEL_TYPE_DBUS_TUBE
".ServiceName");
183 priv
->bus_name
= empathy_tube_handler_build_bus_name (type
, service
);
184 priv
->object_path
= empathy_tube_handler_build_object_path (type
, service
);
186 priv
->service
= g_strdup (service
);
188 DEBUG ("Look for tube handler %s\n", priv
->bus_name
);
189 tp_cli_dbus_daemon_call_name_has_owner (priv
->dbus
, -1, priv
->bus_name
,
190 empathy_tube_dispatch_name_has_owner_cb
, NULL
, NULL
, G_OBJECT (self
));
195 empathy_tube_dispatch_set_ability (self
,
196 EMPATHY_TUBE_DISPATCHABILITY_IMPOSSIBLE
);
200 empathy_tube_dispatch_set_property (GObject
*object
,
201 guint property_id
, const GValue
*value
, GParamSpec
*pspec
)
203 EmpathyTubeDispatch
*tube_dispatch
= EMPATHY_TUBE_DISPATCH (object
);
204 EmpathyTubeDispatchPriv
*priv
= GET_PRIV (tube_dispatch
);
209 priv
->operation
= g_value_dup_object (value
);
212 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
218 empathy_tube_dispatch_get_property (GObject
*object
,
219 guint property_id
, GValue
*value
, GParamSpec
*pspec
)
221 EmpathyTubeDispatch
*tube_dispatch
= EMPATHY_TUBE_DISPATCH (object
);
222 EmpathyTubeDispatchPriv
*priv
= GET_PRIV (tube_dispatch
);
227 g_value_set_object (value
, priv
->operation
);
229 case PROP_DISPATCHABILITY
:
230 g_value_set_enum (value
, priv
->dispatchability
);
233 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
239 empathy_tube_dispatch_class_init (
240 EmpathyTubeDispatchClass
*empathy_tube_dispatch_class
)
242 GObjectClass
*object_class
= G_OBJECT_CLASS (empathy_tube_dispatch_class
);
243 GParamSpec
*param_spec
;
245 g_type_class_add_private (empathy_tube_dispatch_class
,
246 sizeof (EmpathyTubeDispatchPriv
));
248 object_class
->set_property
= empathy_tube_dispatch_set_property
;
249 object_class
->get_property
= empathy_tube_dispatch_get_property
;
251 object_class
->constructed
= empathy_tube_dispatch_constructed
;
252 object_class
->dispose
= empathy_tube_dispatch_dispose
;
253 object_class
->finalize
= empathy_tube_dispatch_finalize
;
255 param_spec
= g_param_spec_object ("operation",
256 "operation", "The telepathy connection",
257 EMPATHY_TYPE_DISPATCH_OPERATION
,
258 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
259 g_object_class_install_property (object_class
, PROP_OPERATION
, param_spec
);
261 param_spec
= g_param_spec_enum ("dispatchability",
263 "Whether or not there is a handler to dispatch the operation to",
264 EMPATHY_TYPE_TUBE_DISPATCH_ABILITY
, EMPATHY_TUBE_DISPATCHABILITY_UNKNOWN
,
265 G_PARAM_READABLE
| G_PARAM_STATIC_STRINGS
);
266 g_object_class_install_property (object_class
, PROP_DISPATCHABILITY
,
272 empathy_tube_dispatch_dispose (GObject
*object
)
274 EmpathyTubeDispatch
*self
= EMPATHY_TUBE_DISPATCH (object
);
275 EmpathyTubeDispatchPriv
*priv
= GET_PRIV (self
);
277 if (priv
->dispose_has_run
)
280 priv
->dispose_has_run
= TRUE
;
282 /* release any references held by the object here */
283 if (priv
->operation
!= NULL
)
284 g_object_unref (priv
->operation
);
286 priv
->operation
= NULL
;
288 if (priv
->dbus
!= NULL
)
289 g_object_unref (priv
->dbus
);
294 if (G_OBJECT_CLASS (empathy_tube_dispatch_parent_class
)->dispose
)
295 G_OBJECT_CLASS (empathy_tube_dispatch_parent_class
)->dispose (object
);
299 empathy_tube_dispatch_finalize (GObject
*object
)
301 EmpathyTubeDispatch
*self
= EMPATHY_TUBE_DISPATCH (object
);
302 EmpathyTubeDispatchPriv
*priv
= GET_PRIV (self
);
304 g_free (priv
->bus_name
);
305 g_free (priv
->object_path
);
306 g_free (priv
->service
);
308 /* free any data held directly by the object here */
310 G_OBJECT_CLASS (empathy_tube_dispatch_parent_class
)->finalize (object
);
313 EmpathyTubeDispatch
*
314 empathy_tube_dispatch_new (EmpathyDispatchOperation
*operation
)
316 return EMPATHY_TUBE_DISPATCH (g_object_new (EMPATHY_TYPE_TUBE_DISPATCH
,
317 "operation", operation
, NULL
));
320 EmpathyTubeDispatchAbility
321 empathy_tube_dispatch_is_dispatchable (EmpathyTubeDispatch
*tube_dispatch
)
323 EmpathyTubeDispatchPriv
*priv
= GET_PRIV (tube_dispatch
);
325 return priv
->dispatchability
;
329 empathy_tube_dispatch_set_ability (EmpathyTubeDispatch
*tube_dispatch
,
330 EmpathyTubeDispatchAbility dispatchability
)
332 EmpathyTubeDispatchPriv
*priv
= GET_PRIV (tube_dispatch
);
334 if (priv
->dispatchability
== dispatchability
)
337 priv
->dispatchability
= dispatchability
;
338 g_object_notify (G_OBJECT (tube_dispatch
), "dispatchability");
342 empathy_tube_dispatch_show_error (EmpathyTubeDispatch
*self
, gchar
*message
)
346 dialog
= gtk_message_dialog_new (NULL
, GTK_DIALOG_MODAL
,
347 GTK_MESSAGE_WARNING
, GTK_BUTTONS_CLOSE
, "%s", message
);
349 gtk_dialog_run (GTK_DIALOG (dialog
));
351 gtk_widget_destroy (dialog
);
355 empathy_tube_dispatch_handle_tube_cb (TpProxy
*proxy
, const GError
*error
,
356 gpointer user_data
, GObject
*object
)
358 EmpathyTubeDispatch
*self
= EMPATHY_TUBE_DISPATCH (object
);
359 EmpathyTubeDispatchPriv
*priv
= GET_PRIV (self
);
363 gchar
*msg
= g_strdup_printf (
364 _("Unable to start application for service %s: %s"),
365 priv
->service
, error
->message
);
367 empathy_tube_dispatch_show_error (self
, msg
);
371 /* Remove the ref we were holding because of the dispatching */
372 g_object_unref (object
);
376 empathy_tube_do_dispatch (EmpathyTubeDispatch
*self
)
378 EmpathyTubeDispatchPriv
*priv
= GET_PRIV (self
);
386 channel
= empathy_dispatch_operation_get_channel (priv
->operation
);
388 /* Create the proxy for the tube handler */
389 thandler
= g_object_new (TP_TYPE_PROXY
,
390 "dbus-connection", tp_get_bus (),
391 "bus-name", priv
->bus_name
,
392 "object-path", priv
->object_path
,
395 tp_proxy_add_interface_by_id (thandler
, EMP_IFACE_QUARK_TUBE_HANDLER
);
397 /* Give the tube to the handler */
398 g_object_get (channel
,
399 "connection", &connection
,
400 "object-path", &object_path
,
401 "handle_type", &handle_type
,
405 emp_cli_tube_handler_call_handle_tube (thandler
, -1,
406 connection
->bus_name
, connection
->object_path
,
407 object_path
, handle_type
, handle
,
408 empathy_tube_dispatch_handle_tube_cb
, NULL
, NULL
, G_OBJECT (self
));
410 g_object_unref (thandler
);
411 g_object_unref (connection
);
412 g_free (object_path
);
416 empathy_tube_dispatch_handle (EmpathyTubeDispatch
*tube_dispatch
)
418 EmpathyTubeDispatchPriv
*priv
= GET_PRIV (tube_dispatch
);
420 /* Keep ourselves alive untill the dispatching is finished */
421 g_object_ref (tube_dispatch
);
423 /* If we can't claim it, don't do anything */
424 if (!empathy_dispatch_operation_claim (priv
->operation
))
427 if (priv
->dispatchability
!= EMPATHY_TUBE_DISPATCHABILITY_POSSIBLE
)
432 channel
= empathy_dispatch_operation_get_channel (priv
->operation
);
434 msg
= g_strdup_printf (
435 _("An invitation was offered for service %s, but you don't have the "
436 "needed application to handle it"), priv
->service
);
438 empathy_tube_dispatch_show_error (tube_dispatch
, msg
);
442 tp_cli_channel_call_close (channel
, -1, NULL
, NULL
, NULL
, NULL
);
448 empathy_tube_do_dispatch (tube_dispatch
);
453 g_object_unref (tube_dispatch
);