Tagged for release 2.26.0.
[empathy-mirror.git] / src / empathy-tube-dispatch.c
blobb1e7bce6d18d13c3ec1ef4efc087b4393a25afb6
1 /*
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
22 #include <stdio.h>
23 #include <stdlib.h>
25 #include <telepathy-glib/dbus.h>
26 #include <telepathy-glib/util.h>
27 #include <telepathy-glib/proxy-subclass.h>
29 #include <gtk/gtk.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;
52 /* properties */
53 enum {
54 PROP_OPERATION = 1,
55 PROP_DISPATCHABILITY
59 struct _EmpathyTubeDispatchPriv
61 gboolean dispose_has_run;
62 EmpathyDispatchOperation *operation;
63 EmpathyTubeDispatchAbility dispatchability;
64 gchar *service;
65 gchar *bus_name;
66 gchar *object_path;
67 TpDBusDaemon *dbus;
70 #define GET_PRIV(o) \
71 (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
72 EMPATHY_TYPE_TUBE_DISPATCH, EmpathyTubeDispatchPriv))
74 static void
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);
85 static void
86 empathy_tube_dispatch_list_activatable_names_cb (TpDBusDaemon *proxy,
87 const gchar **names, const GError *error, gpointer user_data,
88 GObject *object)
90 EmpathyTubeDispatch *self = EMPATHY_TUBE_DISPATCH (object);
91 EmpathyTubeDispatchPriv *priv = GET_PRIV (self);
92 gchar **name;
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);
101 return;
105 DEBUG ("Didn't find tube handler. Can't dispatch it");
106 empathy_tube_dispatch_set_ability (self,
107 EMPATHY_TUBE_DISPATCHABILITY_IMPOSSIBLE);
110 static void
111 empathy_tube_dispatch_name_has_owner_cb (TpDBusDaemon *proxy,
112 gboolean has_owner, const GError *error, gpointer user_data,
113 GObject *object)
115 EmpathyTubeDispatch *self = EMPATHY_TUBE_DISPATCH (object);
116 EmpathyTubeDispatchPriv *priv = GET_PRIV (self);
118 if (error != NULL)
120 DEBUG ("NameHasOwner failed. Can't dispatch tube");
121 empathy_tube_dispatch_set_ability (self,
122 EMPATHY_TUBE_DISPATCHABILITY_IMPOSSIBLE);
123 return;
126 if (has_owner)
128 DEBUG ("Tube handler is running. Can dispatch it");
129 empathy_tube_dispatch_set_ability (self,
130 EMPATHY_TUBE_DISPATCHABILITY_POSSIBLE);
132 else
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,
137 G_OBJECT (self));
141 static void
142 empathy_tube_dispatch_constructed (GObject *object)
144 EmpathyTubeDispatch *self = EMPATHY_TUBE_DISPATCH (object);
145 EmpathyTubeDispatchPriv *priv = GET_PRIV (self);
146 TpChannel *channel;
147 GHashTable *properties;
148 const gchar *service;
149 const gchar *channel_type;
150 TpTubeType 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)
160 goto failed;
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");
174 else
176 goto failed;
180 if (service == NULL)
181 goto failed;
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));
192 return;
194 failed:
195 empathy_tube_dispatch_set_ability (self,
196 EMPATHY_TUBE_DISPATCHABILITY_IMPOSSIBLE);
199 static void
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);
206 switch (property_id)
208 case PROP_OPERATION:
209 priv->operation = g_value_dup_object (value);
210 break;
211 default:
212 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
213 break;
217 static void
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);
224 switch (property_id)
226 case PROP_OPERATION:
227 g_value_set_object (value, priv->operation);
228 break;
229 case PROP_DISPATCHABILITY:
230 g_value_set_enum (value, priv->dispatchability);
231 break;
232 default:
233 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
234 break;
238 static void
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",
262 "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,
267 param_spec);
271 void
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)
278 return;
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);
291 priv->dbus = NULL;
294 if (G_OBJECT_CLASS (empathy_tube_dispatch_parent_class)->dispose)
295 G_OBJECT_CLASS (empathy_tube_dispatch_parent_class)->dispose (object);
298 void
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;
328 static void
329 empathy_tube_dispatch_set_ability (EmpathyTubeDispatch *tube_dispatch,
330 EmpathyTubeDispatchAbility dispatchability)
332 EmpathyTubeDispatchPriv *priv = GET_PRIV (tube_dispatch);
334 if (priv->dispatchability == dispatchability)
335 return;
337 priv->dispatchability = dispatchability;
338 g_object_notify (G_OBJECT (tube_dispatch), "dispatchability");
341 static void
342 empathy_tube_dispatch_show_error (EmpathyTubeDispatch *self, gchar *message)
344 GtkWidget *dialog;
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);
354 static void
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);
361 if (error != NULL)
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);
368 g_free (msg);
371 /* Remove the ref we were holding because of the dispatching */
372 g_object_unref (object);
375 static void
376 empathy_tube_do_dispatch (EmpathyTubeDispatch *self)
378 EmpathyTubeDispatchPriv *priv = GET_PRIV (self);
379 TpChannel *channel;
380 TpProxy *connection;
381 TpProxy *thandler;
382 gchar *object_path;
383 guint handle_type;
384 guint handle;
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,
393 NULL);
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,
402 "handle", &handle,
403 NULL);
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);
415 void
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))
425 goto done;
427 if (priv->dispatchability != EMPATHY_TUBE_DISPATCHABILITY_POSSIBLE)
429 gchar *msg;
430 TpChannel *channel;
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);
440 g_free (msg);
442 tp_cli_channel_call_close (channel, -1, NULL, NULL, NULL, NULL);
444 goto done;
446 else
448 empathy_tube_do_dispatch (tube_dispatch);
451 return;
452 done:
453 g_object_unref (tube_dispatch);