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"
41 G_DEFINE_TYPE(EmpathyTubeDispatch, empathy_tube_dispatch, G_TYPE_OBJECT)
43 static void empathy_tube_dispatch_set_ability (
44 EmpathyTubeDispatch *tube_dispatch,
45 EmpathyTubeDispatchAbility dispatchability);
47 /* private structure */
48 typedef struct _EmpathyTubeDispatchPriv EmpathyTubeDispatchPriv;
57 struct _EmpathyTubeDispatchPriv
59 gboolean dispose_has_run;
60 EmpathyDispatchOperation *operation;
61 EmpathyTubeDispatchAbility dispatchability;
69 (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
70 EMPATHY_TYPE_TUBE_DISPATCH, EmpathyTubeDispatchPriv))
73 empathy_tube_dispatch_init (EmpathyTubeDispatch *obj)
75 EmpathyTubeDispatchPriv *priv = GET_PRIV (obj);
77 priv->dispatchability = EMPATHY_TUBE_DISPATCHABILITY_UNKNOWN;
80 static void empathy_tube_dispatch_dispose (GObject *object);
81 static void empathy_tube_dispatch_finalize (GObject *object);
84 empathy_tube_dispatch_list_activatable_names_cb (TpDBusDaemon *proxy,
85 const gchar **names, const GError *error, gpointer user_data,
88 EmpathyTubeDispatch *self = EMPATHY_TUBE_DISPATCH (object);
89 EmpathyTubeDispatchPriv *priv = GET_PRIV (self);
92 for (name = (gchar **) names; *name != NULL; name++)
94 if (!tp_strdiff (*name, priv->bus_name))
96 empathy_tube_dispatch_set_ability (self,
97 EMPATHY_TUBE_DISPATCHABILITY_POSSIBLE);
102 empathy_tube_dispatch_set_ability (self,
103 EMPATHY_TUBE_DISPATCHABILITY_IMPOSSIBLE);
107 empathy_tube_dispatch_name_has_owner_cb (TpDBusDaemon *proxy,
108 gboolean has_owner, const GError *error, gpointer user_data,
111 EmpathyTubeDispatch *self = EMPATHY_TUBE_DISPATCH (object);
112 EmpathyTubeDispatchPriv *priv = GET_PRIV (self);
116 empathy_tube_dispatch_set_ability (self,
117 EMPATHY_TUBE_DISPATCHABILITY_IMPOSSIBLE);
123 empathy_tube_dispatch_set_ability (self,
124 EMPATHY_TUBE_DISPATCHABILITY_POSSIBLE);
128 tp_cli_dbus_daemon_call_list_activatable_names (priv->dbus, -1,
129 empathy_tube_dispatch_list_activatable_names_cb, NULL, NULL,
135 empathy_tube_dispatch_constructed (GObject *object)
137 EmpathyTubeDispatch *self = EMPATHY_TUBE_DISPATCH (object);
138 EmpathyTubeDispatchPriv *priv = GET_PRIV (self);
140 GHashTable *properties;
141 const gchar *service;
142 const gchar *channel_type;
143 EmpathyTubeType type;
145 priv->dbus = tp_dbus_daemon_new (tp_get_bus());
147 channel = empathy_dispatch_operation_get_channel (priv->operation);
148 properties = tp_channel_borrow_immutable_properties (channel);
150 channel_type = tp_asv_get_string (properties,
151 TP_IFACE_CHANNEL ".ChannelType");
152 if (channel_type == NULL)
155 if (!tp_strdiff (channel_type, EMP_IFACE_CHANNEL_TYPE_STREAM_TUBE))
157 type = EMPATHY_TYPE_STREAM_TUBE;
158 service = tp_asv_get_string (properties,
159 EMP_IFACE_CHANNEL_TYPE_STREAM_TUBE ".Service");
161 else if (!tp_strdiff (channel_type, EMP_IFACE_CHANNEL_TYPE_DBUS_TUBE))
163 type = EMPATHY_TYPE_DBUS_TUBE;
164 service = tp_asv_get_string (properties,
165 EMP_IFACE_CHANNEL_TYPE_DBUS_TUBE ".ServiceName");
176 priv->bus_name = empathy_tube_handler_build_bus_name (type, service);
177 priv->object_path = empathy_tube_handler_build_object_path (type, service);
179 priv->service = g_strdup (service);
181 tp_cli_dbus_daemon_call_name_has_owner (priv->dbus, -1, priv->bus_name,
182 empathy_tube_dispatch_name_has_owner_cb, NULL, NULL, G_OBJECT (self));
187 empathy_tube_dispatch_set_ability (self,
188 EMPATHY_TUBE_DISPATCHABILITY_IMPOSSIBLE);
192 empathy_tube_dispatch_set_property (GObject *object,
193 guint property_id, const GValue *value, GParamSpec *pspec)
195 EmpathyTubeDispatch *tube_dispatch = EMPATHY_TUBE_DISPATCH (object);
196 EmpathyTubeDispatchPriv *priv = GET_PRIV (tube_dispatch);
201 priv->operation = g_value_dup_object (value);
204 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
210 empathy_tube_dispatch_get_property (GObject *object,
211 guint property_id, GValue *value, GParamSpec *pspec)
213 EmpathyTubeDispatch *tube_dispatch = EMPATHY_TUBE_DISPATCH (object);
214 EmpathyTubeDispatchPriv *priv = GET_PRIV (tube_dispatch);
219 g_value_set_object (value, priv->operation);
221 case PROP_DISPATCHABILITY:
222 g_value_set_enum (value, priv->dispatchability);
225 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
231 empathy_tube_dispatch_class_init (
232 EmpathyTubeDispatchClass *empathy_tube_dispatch_class)
234 GObjectClass *object_class = G_OBJECT_CLASS (empathy_tube_dispatch_class);
235 GParamSpec *param_spec;
237 g_type_class_add_private (empathy_tube_dispatch_class,
238 sizeof (EmpathyTubeDispatchPriv));
240 object_class->set_property = empathy_tube_dispatch_set_property;
241 object_class->get_property = empathy_tube_dispatch_get_property;
243 object_class->constructed = empathy_tube_dispatch_constructed;
244 object_class->dispose = empathy_tube_dispatch_dispose;
245 object_class->finalize = empathy_tube_dispatch_finalize;
247 param_spec = g_param_spec_object ("operation",
248 "operation", "The telepathy connection",
249 EMPATHY_TYPE_DISPATCH_OPERATION,
250 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
251 g_object_class_install_property (object_class, PROP_OPERATION, param_spec);
253 param_spec = g_param_spec_enum ("dispatchability",
255 "Whether or not there is a handler to dispatch the operation to",
256 EMPATHY_TYPE_TUBE_DISPATCH_ABILITY, EMPATHY_TUBE_DISPATCHABILITY_UNKNOWN,
257 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
258 g_object_class_install_property (object_class, PROP_DISPATCHABILITY,
264 empathy_tube_dispatch_dispose (GObject *object)
266 EmpathyTubeDispatch *self = EMPATHY_TUBE_DISPATCH (object);
267 EmpathyTubeDispatchPriv *priv = GET_PRIV (self);
269 if (priv->dispose_has_run)
272 priv->dispose_has_run = TRUE;
274 /* release any references held by the object here */
275 if (priv->operation != NULL)
276 g_object_unref (priv->operation);
278 priv->operation = NULL;
280 if (priv->dbus != NULL)
281 g_object_unref (priv->dbus);
286 if (G_OBJECT_CLASS (empathy_tube_dispatch_parent_class)->dispose)
287 G_OBJECT_CLASS (empathy_tube_dispatch_parent_class)->dispose (object);
291 empathy_tube_dispatch_finalize (GObject *object)
293 EmpathyTubeDispatch *self = EMPATHY_TUBE_DISPATCH (object);
294 EmpathyTubeDispatchPriv *priv = GET_PRIV (self);
296 g_free (priv->bus_name);
297 g_free (priv->object_path);
298 g_free (priv->service);
300 /* free any data held directly by the object here */
302 G_OBJECT_CLASS (empathy_tube_dispatch_parent_class)->finalize (object);
305 EmpathyTubeDispatch *
306 empathy_tube_dispatch_new (EmpathyDispatchOperation *operation)
308 return EMPATHY_TUBE_DISPATCH (g_object_new (EMPATHY_TYPE_TUBE_DISPATCH,
309 "operation", operation, NULL));
312 EmpathyTubeDispatchAbility
313 empathy_tube_dispatch_is_dispatchable (EmpathyTubeDispatch *tube_dispatch)
315 EmpathyTubeDispatchPriv *priv = GET_PRIV (tube_dispatch);
317 return priv->dispatchability;
321 empathy_tube_dispatch_set_ability (EmpathyTubeDispatch *tube_dispatch,
322 EmpathyTubeDispatchAbility dispatchability)
324 EmpathyTubeDispatchPriv *priv = GET_PRIV (tube_dispatch);
326 if (priv->dispatchability == dispatchability)
329 priv->dispatchability = dispatchability;
330 g_object_notify (G_OBJECT (tube_dispatch), "dispatchability");
334 empathy_tube_dispatch_show_error (EmpathyTubeDispatch *self, gchar *message)
338 dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL,
339 GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE, "%s", message);
341 gtk_dialog_run (GTK_DIALOG (dialog));
343 gtk_widget_destroy (dialog);
347 empathy_tube_dispatch_handle_tube_cb (TpProxy *proxy, const GError *error,
348 gpointer user_data, GObject *object)
350 EmpathyTubeDispatch *self = EMPATHY_TUBE_DISPATCH (object);
351 EmpathyTubeDispatchPriv *priv = GET_PRIV (self);
355 gchar *msg = g_strdup_printf (
356 _("Unable to start application for service %s: %s"),
357 priv->service, error->message);
359 empathy_tube_dispatch_show_error (self, msg);
363 /* Remove the ref we were holding because of the dispatching */
364 g_object_unref (object);
368 empathy_tube_do_dispatch (EmpathyTubeDispatch *self)
370 EmpathyTubeDispatchPriv *priv = GET_PRIV (self);
378 channel = empathy_dispatch_operation_get_channel (priv->operation);
380 /* Create the proxy for the tube handler */
381 thandler = g_object_new (TP_TYPE_PROXY,
382 "dbus-connection", tp_get_bus (),
383 "bus-name", priv->bus_name,
384 "object-path", priv->object_path,
387 tp_proxy_add_interface_by_id (thandler, EMP_IFACE_QUARK_TUBE_HANDLER);
389 /* Give the tube to the handler */
390 g_object_get (channel,
391 "connection", &connection,
392 "object-path", &object_path,
393 "handle_type", &handle_type,
397 emp_cli_tube_handler_call_handle_tube (thandler, -1,
398 connection->bus_name, connection->object_path,
399 object_path, handle_type, handle,
400 empathy_tube_dispatch_handle_tube_cb, NULL, NULL, G_OBJECT (self));
402 g_object_unref (thandler);
403 g_object_unref (connection);
404 g_free (object_path);
408 empathy_tube_dispatch_handle (EmpathyTubeDispatch *tube_dispatch)
410 EmpathyTubeDispatchPriv *priv = GET_PRIV (tube_dispatch);
412 /* Keep ourselves alive untill the dispatching is finished */
413 g_object_ref (tube_dispatch);
415 /* If we can't claim it, don't do anything */
416 if (!empathy_dispatch_operation_claim (priv->operation))
419 if (priv->dispatchability != EMPATHY_TUBE_DISPATCHABILITY_POSSIBLE)
424 channel = empathy_dispatch_operation_get_channel (priv->operation);
426 msg = g_strdup_printf (
427 _("An invitation was offered for service %s, but you don't have the "
428 "needed application to handle it"), priv->service);
430 empathy_tube_dispatch_show_error (tube_dispatch, msg);
434 tp_cli_channel_call_close (channel, -1, NULL, NULL, NULL, NULL);
440 empathy_tube_do_dispatch (tube_dispatch);
445 g_object_unref (tube_dispatch);