2 * empathy-dispatch-operation.c - Source for EmpathyDispatchOperation
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 "empathy-dispatch-operation.h"
26 #include <libempathy/empathy-enum-types.h>
27 #include <libempathy/empathy-tp-chat.h>
28 #include <libempathy/empathy-tp-call.h>
29 #include <libempathy/empathy-tp-file.h>
31 #include "empathy-marshal.h"
33 #define DEBUG_FLAG EMPATHY_DEBUG_DISPATCHER
34 #include <libempathy/empathy-debug.h>
36 G_DEFINE_TYPE(EmpathyDispatchOperation, empathy_dispatch_operation,
39 static void empathy_dispatch_operation_set_status (
40 EmpathyDispatchOperation *self, EmpathyDispatchOperationState status);
41 static void empathy_dispatch_operation_channel_ready_cb (TpChannel *channel,
42 const GError *error, gpointer user_data);
47 /* Ready for dispatching */
49 /* Approved by an approver, can only happens on incoming operations */
51 /* Claimed by a handler */
53 /* Error, channel went away, inspecting it failed etc */
58 static guint signals[LAST_SIGNAL] = {0};
70 /* private structure */
71 typedef struct _EmpathyDispatchOperationPriv \
72 EmpathyDispatchOperationPriv;
74 struct _EmpathyDispatchOperationPriv
76 gboolean dispose_has_run;
77 TpConnection *connection;
79 GObject *channel_wrapper;
80 EmpathyContact *contact;
81 EmpathyDispatchOperationState status;
84 gulong invalidated_handler;
89 (G_TYPE_INSTANCE_GET_PRIVATE ((o), EMPATHY_TYPE_DISPATCH_OPERATION, \
90 EmpathyDispatchOperationPriv))
93 empathy_dispatch_operation_init (EmpathyDispatchOperation *obj)
95 //EmpathyDispatchOperationPriv *priv =
98 /* allocate any data required by the object here */
101 static void empathy_dispatch_operation_dispose (GObject *object);
102 static void empathy_dispatch_operation_finalize (GObject *object);
105 empathy_dispatch_operation_set_property (GObject *object,
106 guint property_id, const GValue *value, GParamSpec *pspec)
108 EmpathyDispatchOperation *operation = EMPATHY_DISPATCH_OPERATION (object);
109 EmpathyDispatchOperationPriv *priv = GET_PRIV (operation);
113 case PROP_CONNECTION:
114 priv->connection = g_value_dup_object (value);
117 priv->channel = g_value_dup_object (value);
119 case PROP_CHANNEL_WRAPPER:
120 priv->channel_wrapper = g_value_dup_object (value);
123 if (priv->contact != NULL)
124 g_object_unref (priv->contact);
125 priv->contact = g_value_dup_object (value);
128 priv->incoming = g_value_get_boolean (value);
134 empathy_dispatch_operation_get_property (GObject *object,
135 guint property_id, GValue *value, GParamSpec *pspec)
137 EmpathyDispatchOperation *operation = EMPATHY_DISPATCH_OPERATION (object);
138 EmpathyDispatchOperationPriv *priv = GET_PRIV (operation);
142 case PROP_CONNECTION:
143 g_value_set_object (value, priv->connection);
146 g_value_set_object (value, priv->channel);
148 case PROP_CHANNEL_WRAPPER:
149 g_value_set_object (value, priv->channel_wrapper);
152 g_value_set_object (value, priv->contact);
155 g_value_set_boolean (value, priv->incoming);
158 g_value_set_enum (value, priv->status);
164 empathy_dispatch_operation_invalidated (TpProxy *proxy, guint domain,
165 gint code, char *message, EmpathyDispatchOperation *self)
167 empathy_dispatch_operation_set_status (self,
168 EMPATHY_DISPATCHER_OPERATION_STATE_INVALIDATED);
170 g_signal_emit (self, signals[INVALIDATED], 0, domain, code, message);
174 empathy_dispatch_operation_constructed (GObject *object)
176 EmpathyDispatchOperation *self = EMPATHY_DISPATCH_OPERATION (object);
177 EmpathyDispatchOperationPriv *priv = GET_PRIV (self);
179 empathy_dispatch_operation_set_status (self,
180 EMPATHY_DISPATCHER_OPERATION_STATE_PREPARING);
182 priv->invalidated_handler =
183 g_signal_connect (priv->channel, "invalidated",
184 G_CALLBACK (empathy_dispatch_operation_invalidated), self);
186 tp_channel_call_when_ready (priv->channel,
187 empathy_dispatch_operation_channel_ready_cb, self);
191 empathy_dispatch_operation_class_init (
192 EmpathyDispatchOperationClass *empathy_dispatch_operation_class)
194 GObjectClass *object_class =
195 G_OBJECT_CLASS (empathy_dispatch_operation_class);
196 GParamSpec *param_spec;
198 g_type_class_add_private (empathy_dispatch_operation_class,
199 sizeof (EmpathyDispatchOperationPriv));
201 object_class->set_property = empathy_dispatch_operation_set_property;
202 object_class->get_property = empathy_dispatch_operation_get_property;
204 object_class->dispose = empathy_dispatch_operation_dispose;
205 object_class->finalize = empathy_dispatch_operation_finalize;
206 object_class->constructed = empathy_dispatch_operation_constructed;
208 signals[READY] = g_signal_new ("ready",
209 G_OBJECT_CLASS_TYPE(empathy_dispatch_operation_class),
213 g_cclosure_marshal_VOID__VOID,
216 signals[APPROVED] = g_signal_new ("approved",
217 G_OBJECT_CLASS_TYPE(empathy_dispatch_operation_class),
221 g_cclosure_marshal_VOID__VOID,
224 signals[CLAIMED] = g_signal_new ("claimed",
225 G_OBJECT_CLASS_TYPE(empathy_dispatch_operation_class),
229 g_cclosure_marshal_VOID__VOID,
232 signals[INVALIDATED] = g_signal_new ("invalidated",
233 G_OBJECT_CLASS_TYPE(empathy_dispatch_operation_class),
237 _empathy_marshal_VOID__UINT_INT_STRING,
240 param_spec = g_param_spec_object ("connection",
241 "connection", "The telepathy connection",
243 G_PARAM_CONSTRUCT_ONLY |
244 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
245 g_object_class_install_property (object_class, PROP_CONNECTION,
248 param_spec = g_param_spec_object ("channel",
249 "channel", "The telepathy channel",
251 G_PARAM_CONSTRUCT_ONLY |
252 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
253 g_object_class_install_property (object_class, PROP_CHANNEL,
256 param_spec = g_param_spec_object ("channel-wrapper",
257 "channel wrapper", "The empathy specific channel wrapper",
259 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
260 g_object_class_install_property (object_class, PROP_CHANNEL_WRAPPER,
263 param_spec = g_param_spec_object ("contact",
264 "contact", "The empathy contact",
265 EMPATHY_TYPE_CONTACT,
266 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
267 g_object_class_install_property (object_class, PROP_CONTACT,
270 param_spec = g_param_spec_boolean ("incoming",
271 "incoming", "Whether or not the channel is incoming",
273 G_PARAM_CONSTRUCT_ONLY |
274 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
275 g_object_class_install_property (object_class, PROP_INCOMING,
278 param_spec = g_param_spec_enum ("status",
279 "status", "Status of the dispatch operation",
280 EMPATHY_TYPE_DISPATCH_OPERATION_STATE, 0,
281 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
282 g_object_class_install_property (object_class, PROP_STATUS, param_spec);
286 empathy_dispatch_operation_dispose (GObject *object)
288 EmpathyDispatchOperation *self = EMPATHY_DISPATCH_OPERATION (object);
289 EmpathyDispatchOperationPriv *priv =
292 if (priv->dispose_has_run)
295 priv->dispose_has_run = TRUE;
297 g_object_unref (priv->connection);
299 if (priv->channel_wrapper != NULL)
300 g_object_unref (priv->channel_wrapper);
302 if (priv->ready_handler != 0)
303 g_signal_handler_disconnect (priv->channel_wrapper,
304 priv->invalidated_handler);
307 g_signal_handler_disconnect (priv->channel, priv->invalidated_handler);
308 g_object_unref (priv->channel);
311 if (priv->contact != NULL)
312 g_object_unref (priv->contact);
314 if (G_OBJECT_CLASS (empathy_dispatch_operation_parent_class)->dispose)
315 G_OBJECT_CLASS (empathy_dispatch_operation_parent_class)->dispose (object);
319 empathy_dispatch_operation_finalize (GObject *object)
321 /* free any data held directly by the object here */
322 G_OBJECT_CLASS (empathy_dispatch_operation_parent_class)->finalize (object);
326 empathy_dispatch_operation_set_status (EmpathyDispatchOperation *self,
327 EmpathyDispatchOperationState status)
329 EmpathyDispatchOperationPriv *priv = GET_PRIV (self);
331 g_assert (status >= priv->status);
334 if (priv->status != status)
336 DEBUG ("Dispatch operation %s status: %d -> %d",
337 empathy_dispatch_operation_get_object_path (self),
338 priv->status, status);
340 priv->status = status;
341 g_object_notify (G_OBJECT (self), "status");
343 if (status == EMPATHY_DISPATCHER_OPERATION_STATE_PENDING)
344 g_signal_emit (self, signals[READY], 0);
349 empathy_dispatcher_operation_tp_chat_ready_cb (GObject *object,
350 GParamSpec *spec, gpointer user_data)
352 EmpathyDispatchOperation *self = EMPATHY_DISPATCH_OPERATION (user_data);
353 EmpathyDispatchOperationPriv *priv = GET_PRIV (self);
355 if (!empathy_tp_chat_is_ready (EMPATHY_TP_CHAT (priv->channel_wrapper)))
358 g_signal_handler_disconnect (priv->channel_wrapper, priv->ready_handler);
359 priv->ready_handler = 0;
361 empathy_dispatch_operation_set_status (self,
362 EMPATHY_DISPATCHER_OPERATION_STATE_PENDING);
366 empathy_dispatch_operation_channel_ready_cb (TpChannel *channel,
367 const GError *error, gpointer user_data)
369 EmpathyDispatchOperation *self = EMPATHY_DISPATCH_OPERATION (user_data);
370 EmpathyDispatchOperationPriv *priv = GET_PRIV (self);
373 g_assert (channel == priv->channel);
375 /* If the channel wrapper is defined, we assume it's ready */
376 if (priv->channel_wrapper != NULL)
379 channel_type = tp_channel_get_channel_type_id (channel);
381 if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_TEXT)
383 EmpathyTpChat *chat= empathy_tp_chat_new (channel);
384 priv->channel_wrapper = G_OBJECT (chat);
386 if (!empathy_tp_chat_is_ready (chat))
388 priv->ready_handler = g_signal_connect (chat, "notify::ready",
389 G_CALLBACK (empathy_dispatcher_operation_tp_chat_ready_cb), self);
394 else if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_STREAMED_MEDIA)
396 EmpathyTpCall *call = empathy_tp_call_new (channel);
397 priv->channel_wrapper = G_OBJECT (call);
400 else if (channel_type == EMP_IFACE_QUARK_CHANNEL_TYPE_FILE_TRANSFER)
402 EmpathyTpFile *file = empathy_tp_file_new (channel);
403 priv->channel_wrapper = G_OBJECT (file);
407 empathy_dispatch_operation_set_status (self,
408 EMPATHY_DISPATCHER_OPERATION_STATE_PENDING);
413 EmpathyDispatchOperation *
414 empathy_dispatch_operation_new (TpConnection *connection, TpChannel *channel,
415 EmpathyContact *contact, gboolean incoming)
417 return empathy_dispatch_operation_new_with_wrapper (connection, channel,
418 contact, incoming, NULL);
421 EmpathyDispatchOperation *
422 empathy_dispatch_operation_new_with_wrapper (TpConnection *connection,
423 TpChannel *channel, EmpathyContact *contact, gboolean incoming,
426 g_return_val_if_fail (connection != NULL, NULL);
427 g_return_val_if_fail (channel != NULL, NULL);
429 return EMPATHY_DISPATCH_OPERATION (
430 g_object_new (EMPATHY_TYPE_DISPATCH_OPERATION,
431 "connection", connection,
433 "channel-wrapper", wrapper,
435 "incoming", incoming,
440 empathy_dispatch_operation_start (EmpathyDispatchOperation *operation)
442 EmpathyDispatchOperationPriv *priv = GET_PRIV (operation);
444 priv->status == EMPATHY_DISPATCHER_OPERATION_STATE_PENDING);
446 if (priv->incoming && !priv->approved)
447 empathy_dispatch_operation_set_status (operation,
448 EMPATHY_DISPATCHER_OPERATION_STATE_APPROVING);
450 empathy_dispatch_operation_set_status (operation,
451 EMPATHY_DISPATCHER_OPERATION_STATE_DISPATCHING);
455 empathy_dispatch_operation_approve (EmpathyDispatchOperation *operation)
457 EmpathyDispatchOperationPriv *priv = GET_PRIV (operation);
459 if (priv->status == EMPATHY_DISPATCHER_OPERATION_STATE_APPROVING)
461 DEBUG ("Approving operation %s",
462 empathy_dispatch_operation_get_object_path (operation));
464 empathy_dispatch_operation_set_status (operation,
465 EMPATHY_DISPATCHER_OPERATION_STATE_DISPATCHING);
467 g_signal_emit (operation, signals[APPROVED], 0);
471 DEBUG ("Pre-approving operation %s",
472 empathy_dispatch_operation_get_object_path (operation));
473 priv->approved = TRUE;
477 /* Returns whether or not the operation was successfully claimed */
479 empathy_dispatch_operation_claim (EmpathyDispatchOperation *operation)
481 EmpathyDispatchOperationPriv *priv = GET_PRIV (operation);
483 if (priv->status == EMPATHY_DISPATCHER_OPERATION_STATE_CLAIMED)
486 empathy_dispatch_operation_set_status (operation,
487 EMPATHY_DISPATCHER_OPERATION_STATE_CLAIMED);
489 g_signal_emit (operation, signals[CLAIMED], 0);
495 empathy_dispatch_operation_get_tp_connection (
496 EmpathyDispatchOperation *operation)
498 EmpathyDispatchOperationPriv *priv = GET_PRIV (operation);
500 return g_object_ref (priv->connection);
504 empathy_dispatch_operation_get_channel (EmpathyDispatchOperation *operation)
506 EmpathyDispatchOperationPriv *priv = GET_PRIV (operation);
508 return TP_CHANNEL (g_object_ref (priv->channel));
512 empathy_dispatch_operation_get_channel_wrapper (
513 EmpathyDispatchOperation *operation)
515 EmpathyDispatchOperationPriv *priv = GET_PRIV (operation);
517 if (priv->channel_wrapper != NULL)
518 g_object_ref (priv->channel_wrapper);
520 return priv->channel_wrapper;
524 empathy_dispatch_operation_get_channel_type (
525 EmpathyDispatchOperation *operation)
527 EmpathyDispatchOperationPriv *priv = GET_PRIV (operation);
529 return tp_channel_get_channel_type (priv->channel);
533 empathy_dispatch_operation_get_channel_type_id (
534 EmpathyDispatchOperation *operation)
536 EmpathyDispatchOperationPriv *priv = GET_PRIV (operation);
538 return tp_channel_get_channel_type_id (priv->channel);
542 empathy_dispatch_operation_get_object_path (
543 EmpathyDispatchOperation *operation)
545 EmpathyDispatchOperationPriv *priv = GET_PRIV (operation);
547 return tp_proxy_get_object_path (TP_PROXY (priv->channel));
550 EmpathyDispatchOperationState
551 empathy_dispatch_operation_get_status (EmpathyDispatchOperation *operation)
553 EmpathyDispatchOperationPriv *priv = GET_PRIV (operation);
559 empathy_dispatch_operation_is_incoming (EmpathyDispatchOperation *operation)
561 EmpathyDispatchOperationPriv *priv = GET_PRIV (operation);
563 return priv->incoming;