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>
28 #include <telepathy-glib/interfaces.h>
31 #include <glib/gi18n.h>
34 #include <libempathy/empathy-tube-handler.h>
35 #include <extensions/extensions.h>
38 #include "empathy-tube-dispatch.h"
39 #include "empathy-tube-dispatch-enumtypes.h"
41 #define DEBUG_FLAG EMPATHY_DEBUG_DISPATCHER
42 #include <libempathy/empathy-debug.h>
44 G_DEFINE_TYPE(EmpathyTubeDispatch, empathy_tube_dispatch, G_TYPE_OBJECT)
46 static void empathy_tube_dispatch_set_ability (
47 EmpathyTubeDispatch *tube_dispatch,
48 EmpathyTubeDispatchAbility dispatchability);
50 /* private structure */
51 typedef struct _EmpathyTubeDispatchPriv EmpathyTubeDispatchPriv;
60 struct _EmpathyTubeDispatchPriv
62 gboolean dispose_has_run;
63 EmpathyDispatchOperation *operation;
64 EmpathyTubeDispatchAbility dispatchability;
72 (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
73 EMPATHY_TYPE_TUBE_DISPATCH, EmpathyTubeDispatchPriv))
76 empathy_tube_dispatch_init (EmpathyTubeDispatch *obj)
78 EmpathyTubeDispatchPriv *priv = GET_PRIV (obj);
80 priv->dispatchability = EMPATHY_TUBE_DISPATCHABILITY_UNKNOWN;
83 static void empathy_tube_dispatch_dispose (GObject *object);
84 static void empathy_tube_dispatch_finalize (GObject *object);
87 empathy_tube_dispatch_list_activatable_names_cb (TpDBusDaemon *proxy,
88 const gchar **names, const GError *error, gpointer user_data,
91 EmpathyTubeDispatch *self = EMPATHY_TUBE_DISPATCH (object);
92 EmpathyTubeDispatchPriv *priv = GET_PRIV (self);
95 for (name = (gchar **) names; *name != NULL; name++)
97 if (!tp_strdiff (*name, priv->bus_name))
99 DEBUG ("Found tube handler. Can dispatch it");
100 empathy_tube_dispatch_set_ability (self,
101 EMPATHY_TUBE_DISPATCHABILITY_POSSIBLE);
106 DEBUG ("Didn't find tube handler. Can't dispatch it");
107 empathy_tube_dispatch_set_ability (self,
108 EMPATHY_TUBE_DISPATCHABILITY_IMPOSSIBLE);
112 empathy_tube_dispatch_name_has_owner_cb (TpDBusDaemon *proxy,
113 gboolean has_owner, const GError *error, gpointer user_data,
116 EmpathyTubeDispatch *self = EMPATHY_TUBE_DISPATCH (object);
117 EmpathyTubeDispatchPriv *priv = GET_PRIV (self);
121 DEBUG ("NameHasOwner failed. Can't dispatch tube");
122 empathy_tube_dispatch_set_ability (self,
123 EMPATHY_TUBE_DISPATCHABILITY_IMPOSSIBLE);
129 DEBUG ("Tube handler is running. Can dispatch it");
130 empathy_tube_dispatch_set_ability (self,
131 EMPATHY_TUBE_DISPATCHABILITY_POSSIBLE);
135 DEBUG ("Tube handler is not running. Calling ListActivatableNames");
136 tp_cli_dbus_daemon_call_list_activatable_names (priv->dbus, -1,
137 empathy_tube_dispatch_list_activatable_names_cb, NULL, NULL,
143 empathy_tube_dispatch_constructed (GObject *object)
145 EmpathyTubeDispatch *self = EMPATHY_TUBE_DISPATCH (object);
146 EmpathyTubeDispatchPriv *priv = GET_PRIV (self);
148 GHashTable *properties;
149 const gchar *service;
150 const gchar *channel_type;
153 priv->dbus = tp_dbus_daemon_new (tp_get_bus ());
155 channel = empathy_dispatch_operation_get_channel (priv->operation);
156 properties = tp_channel_borrow_immutable_properties (channel);
158 channel_type = tp_asv_get_string (properties,
159 TP_IFACE_CHANNEL ".ChannelType");
160 if (channel_type == NULL)
163 if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE))
165 type = TP_TUBE_TYPE_STREAM;
166 service = tp_asv_get_string (properties,
167 TP_IFACE_CHANNEL_TYPE_STREAM_TUBE ".Service");
169 else if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE))
171 GError *error = NULL;
173 type = TP_TUBE_TYPE_DBUS;
174 service = tp_asv_get_string (properties,
175 TP_IFACE_CHANNEL_TYPE_DBUS_TUBE ".ServiceName");
177 if (!tp_dbus_check_valid_bus_name (service, TP_DBUS_NAME_TYPE_WELL_KNOWN,
180 DEBUG ("Can't dispatch tube; invalid ServiceName %s: %s", service,
182 g_error_free (error);
195 priv->bus_name = empathy_tube_handler_build_bus_name (type, service);
196 priv->object_path = empathy_tube_handler_build_object_path (type, service);
198 priv->service = g_strdup (service);
200 DEBUG ("Look for tube handler %s\n", priv->bus_name);
201 tp_cli_dbus_daemon_call_name_has_owner (priv->dbus, -1, priv->bus_name,
202 empathy_tube_dispatch_name_has_owner_cb, NULL, NULL, G_OBJECT (self));
207 empathy_tube_dispatch_set_ability (self,
208 EMPATHY_TUBE_DISPATCHABILITY_IMPOSSIBLE);
212 empathy_tube_dispatch_set_property (GObject *object,
213 guint property_id, const GValue *value, GParamSpec *pspec)
215 EmpathyTubeDispatch *tube_dispatch = EMPATHY_TUBE_DISPATCH (object);
216 EmpathyTubeDispatchPriv *priv = GET_PRIV (tube_dispatch);
221 priv->operation = g_value_dup_object (value);
224 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
230 empathy_tube_dispatch_get_property (GObject *object,
231 guint property_id, GValue *value, GParamSpec *pspec)
233 EmpathyTubeDispatch *tube_dispatch = EMPATHY_TUBE_DISPATCH (object);
234 EmpathyTubeDispatchPriv *priv = GET_PRIV (tube_dispatch);
239 g_value_set_object (value, priv->operation);
241 case PROP_DISPATCHABILITY:
242 g_value_set_enum (value, priv->dispatchability);
245 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
251 empathy_tube_dispatch_class_init (
252 EmpathyTubeDispatchClass *empathy_tube_dispatch_class)
254 GObjectClass *object_class = G_OBJECT_CLASS (empathy_tube_dispatch_class);
255 GParamSpec *param_spec;
257 g_type_class_add_private (empathy_tube_dispatch_class,
258 sizeof (EmpathyTubeDispatchPriv));
260 object_class->set_property = empathy_tube_dispatch_set_property;
261 object_class->get_property = empathy_tube_dispatch_get_property;
263 object_class->constructed = empathy_tube_dispatch_constructed;
264 object_class->dispose = empathy_tube_dispatch_dispose;
265 object_class->finalize = empathy_tube_dispatch_finalize;
267 param_spec = g_param_spec_object ("operation",
268 "operation", "The telepathy connection",
269 EMPATHY_TYPE_DISPATCH_OPERATION,
270 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
271 g_object_class_install_property (object_class, PROP_OPERATION, param_spec);
273 param_spec = g_param_spec_enum ("dispatchability",
275 "Whether or not there is a handler to dispatch the operation to",
276 EMPATHY_TYPE_TUBE_DISPATCH_ABILITY, EMPATHY_TUBE_DISPATCHABILITY_UNKNOWN,
277 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
278 g_object_class_install_property (object_class, PROP_DISPATCHABILITY,
284 empathy_tube_dispatch_dispose (GObject *object)
286 EmpathyTubeDispatch *self = EMPATHY_TUBE_DISPATCH (object);
287 EmpathyTubeDispatchPriv *priv = GET_PRIV (self);
289 if (priv->dispose_has_run)
292 priv->dispose_has_run = TRUE;
294 /* release any references held by the object here */
295 if (priv->operation != NULL)
296 g_object_unref (priv->operation);
298 priv->operation = NULL;
300 if (priv->dbus != NULL)
301 g_object_unref (priv->dbus);
306 if (G_OBJECT_CLASS (empathy_tube_dispatch_parent_class)->dispose)
307 G_OBJECT_CLASS (empathy_tube_dispatch_parent_class)->dispose (object);
311 empathy_tube_dispatch_finalize (GObject *object)
313 EmpathyTubeDispatch *self = EMPATHY_TUBE_DISPATCH (object);
314 EmpathyTubeDispatchPriv *priv = GET_PRIV (self);
316 g_free (priv->bus_name);
317 g_free (priv->object_path);
318 g_free (priv->service);
320 /* free any data held directly by the object here */
322 G_OBJECT_CLASS (empathy_tube_dispatch_parent_class)->finalize (object);
325 EmpathyTubeDispatch *
326 empathy_tube_dispatch_new (EmpathyDispatchOperation *operation)
328 return EMPATHY_TUBE_DISPATCH (g_object_new (EMPATHY_TYPE_TUBE_DISPATCH,
329 "operation", operation, NULL));
332 EmpathyTubeDispatchAbility
333 empathy_tube_dispatch_is_dispatchable (EmpathyTubeDispatch *tube_dispatch)
335 EmpathyTubeDispatchPriv *priv = GET_PRIV (tube_dispatch);
337 return priv->dispatchability;
341 empathy_tube_dispatch_set_ability (EmpathyTubeDispatch *tube_dispatch,
342 EmpathyTubeDispatchAbility dispatchability)
344 EmpathyTubeDispatchPriv *priv = GET_PRIV (tube_dispatch);
346 if (priv->dispatchability == dispatchability)
349 priv->dispatchability = dispatchability;
350 g_object_notify (G_OBJECT (tube_dispatch), "dispatchability");
354 empathy_tube_dispatch_show_error (EmpathyTubeDispatch *self, gchar *message)
358 dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL,
359 GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE, "%s", message);
361 gtk_dialog_run (GTK_DIALOG (dialog));
363 gtk_widget_destroy (dialog);
367 empathy_tube_dispatch_handle_tube_cb (TpProxy *proxy, const GError *error,
368 gpointer user_data, GObject *object)
370 EmpathyTubeDispatch *self = EMPATHY_TUBE_DISPATCH (object);
371 EmpathyTubeDispatchPriv *priv = GET_PRIV (self);
375 gchar *msg = g_strdup_printf (
376 _("Unable to start application for service %s: %s"),
377 priv->service, error->message);
379 empathy_tube_dispatch_show_error (self, msg);
383 /* Remove the ref we were holding because of the dispatching */
384 g_object_unref (object);
388 empathy_tube_do_dispatch (EmpathyTubeDispatch *self)
390 EmpathyTubeDispatchPriv *priv = GET_PRIV (self);
398 channel = empathy_dispatch_operation_get_channel (priv->operation);
400 /* Create the proxy for the tube handler */
401 thandler = g_object_new (TP_TYPE_PROXY,
402 "dbus-connection", tp_get_bus (),
403 "bus-name", priv->bus_name,
404 "object-path", priv->object_path,
407 tp_proxy_add_interface_by_id (thandler, EMP_IFACE_QUARK_TUBE_HANDLER);
409 /* Give the tube to the handler */
410 g_object_get (channel,
411 "connection", &connection,
412 "object-path", &object_path,
413 "handle_type", &handle_type,
417 emp_cli_tube_handler_call_handle_tube (thandler, -1,
418 connection->bus_name, connection->object_path,
419 object_path, handle_type, handle,
420 empathy_tube_dispatch_handle_tube_cb, NULL, NULL, G_OBJECT (self));
422 g_object_unref (thandler);
423 g_object_unref (connection);
424 g_free (object_path);
428 empathy_tube_dispatch_handle (EmpathyTubeDispatch *tube_dispatch)
430 EmpathyTubeDispatchPriv *priv = GET_PRIV (tube_dispatch);
432 /* Keep ourselves alive untill the dispatching is finished */
433 g_object_ref (tube_dispatch);
435 /* If we can't claim it, don't do anything */
436 if (!empathy_dispatch_operation_claim (priv->operation))
439 if (priv->dispatchability != EMPATHY_TUBE_DISPATCHABILITY_POSSIBLE)
444 channel = empathy_dispatch_operation_get_channel (priv->operation);
446 msg = g_strdup_printf (
447 _("An invitation was offered for service %s, but you don't have the "
448 "needed application to handle it"), priv->service);
450 empathy_tube_dispatch_show_error (tube_dispatch, msg);
454 tp_cli_channel_call_close (channel, -1, NULL, NULL, NULL, NULL);
460 empathy_tube_do_dispatch (tube_dispatch);
465 g_object_unref (tube_dispatch);