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 GError *error = NULL;
172 type = TP_TUBE_TYPE_DBUS;
173 service = tp_asv_get_string (properties,
174 EMP_IFACE_CHANNEL_TYPE_DBUS_TUBE ".ServiceName");
176 if (!tp_dbus_check_valid_bus_name (service, TP_DBUS_NAME_TYPE_WELL_KNOWN,
179 DEBUG ("Can't dispatch tube; invalid ServiceName %s: %s", service,
181 g_error_free (error);
194 priv->bus_name = empathy_tube_handler_build_bus_name (type, service);
195 priv->object_path = empathy_tube_handler_build_object_path (type, service);
197 priv->service = g_strdup (service);
199 DEBUG ("Look for tube handler %s\n", priv->bus_name);
200 tp_cli_dbus_daemon_call_name_has_owner (priv->dbus, -1, priv->bus_name,
201 empathy_tube_dispatch_name_has_owner_cb, NULL, NULL, G_OBJECT (self));
206 empathy_tube_dispatch_set_ability (self,
207 EMPATHY_TUBE_DISPATCHABILITY_IMPOSSIBLE);
211 empathy_tube_dispatch_set_property (GObject *object,
212 guint property_id, const GValue *value, GParamSpec *pspec)
214 EmpathyTubeDispatch *tube_dispatch = EMPATHY_TUBE_DISPATCH (object);
215 EmpathyTubeDispatchPriv *priv = GET_PRIV (tube_dispatch);
220 priv->operation = g_value_dup_object (value);
223 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
229 empathy_tube_dispatch_get_property (GObject *object,
230 guint property_id, GValue *value, GParamSpec *pspec)
232 EmpathyTubeDispatch *tube_dispatch = EMPATHY_TUBE_DISPATCH (object);
233 EmpathyTubeDispatchPriv *priv = GET_PRIV (tube_dispatch);
238 g_value_set_object (value, priv->operation);
240 case PROP_DISPATCHABILITY:
241 g_value_set_enum (value, priv->dispatchability);
244 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
250 empathy_tube_dispatch_class_init (
251 EmpathyTubeDispatchClass *empathy_tube_dispatch_class)
253 GObjectClass *object_class = G_OBJECT_CLASS (empathy_tube_dispatch_class);
254 GParamSpec *param_spec;
256 g_type_class_add_private (empathy_tube_dispatch_class,
257 sizeof (EmpathyTubeDispatchPriv));
259 object_class->set_property = empathy_tube_dispatch_set_property;
260 object_class->get_property = empathy_tube_dispatch_get_property;
262 object_class->constructed = empathy_tube_dispatch_constructed;
263 object_class->dispose = empathy_tube_dispatch_dispose;
264 object_class->finalize = empathy_tube_dispatch_finalize;
266 param_spec = g_param_spec_object ("operation",
267 "operation", "The telepathy connection",
268 EMPATHY_TYPE_DISPATCH_OPERATION,
269 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
270 g_object_class_install_property (object_class, PROP_OPERATION, param_spec);
272 param_spec = g_param_spec_enum ("dispatchability",
274 "Whether or not there is a handler to dispatch the operation to",
275 EMPATHY_TYPE_TUBE_DISPATCH_ABILITY, EMPATHY_TUBE_DISPATCHABILITY_UNKNOWN,
276 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
277 g_object_class_install_property (object_class, PROP_DISPATCHABILITY,
283 empathy_tube_dispatch_dispose (GObject *object)
285 EmpathyTubeDispatch *self = EMPATHY_TUBE_DISPATCH (object);
286 EmpathyTubeDispatchPriv *priv = GET_PRIV (self);
288 if (priv->dispose_has_run)
291 priv->dispose_has_run = TRUE;
293 /* release any references held by the object here */
294 if (priv->operation != NULL)
295 g_object_unref (priv->operation);
297 priv->operation = NULL;
299 if (priv->dbus != NULL)
300 g_object_unref (priv->dbus);
305 if (G_OBJECT_CLASS (empathy_tube_dispatch_parent_class)->dispose)
306 G_OBJECT_CLASS (empathy_tube_dispatch_parent_class)->dispose (object);
310 empathy_tube_dispatch_finalize (GObject *object)
312 EmpathyTubeDispatch *self = EMPATHY_TUBE_DISPATCH (object);
313 EmpathyTubeDispatchPriv *priv = GET_PRIV (self);
315 g_free (priv->bus_name);
316 g_free (priv->object_path);
317 g_free (priv->service);
319 /* free any data held directly by the object here */
321 G_OBJECT_CLASS (empathy_tube_dispatch_parent_class)->finalize (object);
324 EmpathyTubeDispatch *
325 empathy_tube_dispatch_new (EmpathyDispatchOperation *operation)
327 return EMPATHY_TUBE_DISPATCH (g_object_new (EMPATHY_TYPE_TUBE_DISPATCH,
328 "operation", operation, NULL));
331 EmpathyTubeDispatchAbility
332 empathy_tube_dispatch_is_dispatchable (EmpathyTubeDispatch *tube_dispatch)
334 EmpathyTubeDispatchPriv *priv = GET_PRIV (tube_dispatch);
336 return priv->dispatchability;
340 empathy_tube_dispatch_set_ability (EmpathyTubeDispatch *tube_dispatch,
341 EmpathyTubeDispatchAbility dispatchability)
343 EmpathyTubeDispatchPriv *priv = GET_PRIV (tube_dispatch);
345 if (priv->dispatchability == dispatchability)
348 priv->dispatchability = dispatchability;
349 g_object_notify (G_OBJECT (tube_dispatch), "dispatchability");
353 empathy_tube_dispatch_show_error (EmpathyTubeDispatch *self, gchar *message)
357 dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL,
358 GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE, "%s", message);
360 gtk_dialog_run (GTK_DIALOG (dialog));
362 gtk_widget_destroy (dialog);
366 empathy_tube_dispatch_handle_tube_cb (TpProxy *proxy, const GError *error,
367 gpointer user_data, GObject *object)
369 EmpathyTubeDispatch *self = EMPATHY_TUBE_DISPATCH (object);
370 EmpathyTubeDispatchPriv *priv = GET_PRIV (self);
374 gchar *msg = g_strdup_printf (
375 _("Unable to start application for service %s: %s"),
376 priv->service, error->message);
378 empathy_tube_dispatch_show_error (self, msg);
382 /* Remove the ref we were holding because of the dispatching */
383 g_object_unref (object);
387 empathy_tube_do_dispatch (EmpathyTubeDispatch *self)
389 EmpathyTubeDispatchPriv *priv = GET_PRIV (self);
397 channel = empathy_dispatch_operation_get_channel (priv->operation);
399 /* Create the proxy for the tube handler */
400 thandler = g_object_new (TP_TYPE_PROXY,
401 "dbus-connection", tp_get_bus (),
402 "bus-name", priv->bus_name,
403 "object-path", priv->object_path,
406 tp_proxy_add_interface_by_id (thandler, EMP_IFACE_QUARK_TUBE_HANDLER);
408 /* Give the tube to the handler */
409 g_object_get (channel,
410 "connection", &connection,
411 "object-path", &object_path,
412 "handle_type", &handle_type,
416 emp_cli_tube_handler_call_handle_tube (thandler, -1,
417 connection->bus_name, connection->object_path,
418 object_path, handle_type, handle,
419 empathy_tube_dispatch_handle_tube_cb, NULL, NULL, G_OBJECT (self));
421 g_object_unref (thandler);
422 g_object_unref (connection);
423 g_free (object_path);
427 empathy_tube_dispatch_handle (EmpathyTubeDispatch *tube_dispatch)
429 EmpathyTubeDispatchPriv *priv = GET_PRIV (tube_dispatch);
431 /* Keep ourselves alive untill the dispatching is finished */
432 g_object_ref (tube_dispatch);
434 /* If we can't claim it, don't do anything */
435 if (!empathy_dispatch_operation_claim (priv->operation))
438 if (priv->dispatchability != EMPATHY_TUBE_DISPATCHABILITY_POSSIBLE)
443 channel = empathy_dispatch_operation_get_channel (priv->operation);
445 msg = g_strdup_printf (
446 _("An invitation was offered for service %s, but you don't have the "
447 "needed application to handle it"), priv->service);
449 empathy_tube_dispatch_show_error (tube_dispatch, msg);
453 tp_cli_channel_call_close (channel, -1, NULL, NULL, NULL, NULL);
459 empathy_tube_do_dispatch (tube_dispatch);
464 g_object_unref (tube_dispatch);