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 <telepathy-glib/interfaces.h>
27 #include "empathy-dispatch-operation.h"
28 #include <libempathy/empathy-enum-types.h>
29 #include <libempathy/empathy-tp-contact-factory.h>
30 #include <libempathy/empathy-tp-call.h>
31 #include <libempathy/empathy-tp-file.h>
33 #include "empathy-marshal.h"
35 #include "extensions/extensions.h"
37 #define DEBUG_FLAG EMPATHY_DEBUG_DISPATCHER
38 #include <libempathy/empathy-debug.h>
40 G_DEFINE_TYPE(EmpathyDispatchOperation, empathy_dispatch_operation,
43 static void empathy_dispatch_operation_set_status (
44 EmpathyDispatchOperation *self, EmpathyDispatchOperationState status);
45 static void empathy_dispatch_operation_channel_ready_cb (TpChannel *channel,
46 const GError *error, gpointer user_data);
51 /* Ready for dispatching */
53 /* Claimed by a handler */
55 /* Error, channel went away, inspecting it failed etc */
60 static guint signals[LAST_SIGNAL] = {0};
70 PROP_USER_ACTION_TIME,
73 /* private structure */
74 typedef struct _EmpathyDispatchOperationPriv \
75 EmpathyDispatchOperationPriv;
77 struct _EmpathyDispatchOperationPriv
79 gboolean dispose_has_run;
80 TpConnection *connection;
82 GObject *channel_wrapper;
83 EmpathyContact *contact;
84 EmpathyDispatchOperationState status;
86 gint64 user_action_time;
87 gulong invalidated_handler;
92 (G_TYPE_INSTANCE_GET_PRIVATE ((o), EMPATHY_TYPE_DISPATCH_OPERATION, \
93 EmpathyDispatchOperationPriv))
96 empathy_dispatch_operation_init (EmpathyDispatchOperation *obj)
98 //EmpathyDispatchOperationPriv *priv =
101 /* allocate any data required by the object here */
104 static void empathy_dispatch_operation_dispose (GObject *object);
105 static void empathy_dispatch_operation_finalize (GObject *object);
108 empathy_dispatch_operation_set_property (GObject *object,
109 guint property_id, const GValue *value, GParamSpec *pspec)
111 EmpathyDispatchOperation *operation = EMPATHY_DISPATCH_OPERATION (object);
112 EmpathyDispatchOperationPriv *priv = GET_PRIV (operation);
116 case PROP_CONNECTION:
117 priv->connection = g_value_dup_object (value);
120 priv->channel = g_value_dup_object (value);
122 case PROP_CHANNEL_WRAPPER:
123 priv->channel_wrapper = g_value_dup_object (value);
126 if (priv->contact != NULL)
127 g_object_unref (priv->contact);
128 priv->contact = g_value_dup_object (value);
131 priv->incoming = g_value_get_boolean (value);
134 case PROP_USER_ACTION_TIME:
135 priv->user_action_time = g_value_get_int64 (value);
141 empathy_dispatch_operation_get_property (GObject *object,
142 guint property_id, GValue *value, GParamSpec *pspec)
144 EmpathyDispatchOperation *operation = EMPATHY_DISPATCH_OPERATION (object);
145 EmpathyDispatchOperationPriv *priv = GET_PRIV (operation);
149 case PROP_CONNECTION:
150 g_value_set_object (value, priv->connection);
153 g_value_set_object (value, priv->channel);
155 case PROP_CHANNEL_WRAPPER:
156 g_value_set_object (value, priv->channel_wrapper);
159 g_value_set_object (value, priv->contact);
162 g_value_set_boolean (value, priv->incoming);
165 g_value_set_enum (value, priv->status);
167 case PROP_USER_ACTION_TIME:
168 g_value_set_int64 (value, priv->user_action_time);
174 empathy_dispatch_operation_invalidated (TpProxy *proxy, guint domain,
175 gint code, char *message, EmpathyDispatchOperation *self)
177 empathy_dispatch_operation_set_status (self,
178 EMPATHY_DISPATCHER_OPERATION_STATE_INVALIDATED);
180 g_signal_emit (self, signals[INVALIDATED], 0, domain, code, message);
184 dispatcher_operation_got_contact_cb (TpConnection *connection,
185 EmpathyContact *contact,
190 EmpathyDispatchOperationPriv *priv = GET_PRIV (self);
194 /* FIXME: We should cancel the operation */
195 DEBUG ("Error: %s", error->message);
199 if (priv->contact != NULL)
200 g_object_unref (priv->contact);
201 priv->contact = g_object_ref (contact);
202 g_object_notify (G_OBJECT (self), "contact");
204 /* Ensure to keep the self object alive while the call_when_ready is
207 tp_channel_call_when_ready (priv->channel,
208 empathy_dispatch_operation_channel_ready_cb, self);
212 dispatch_operation_connection_ready (TpConnection *connection,
216 EmpathyDispatchOperation *self = EMPATHY_DISPATCH_OPERATION (user_data);
217 EmpathyDispatchOperationPriv *priv = GET_PRIV (self);
219 TpHandleType handle_type;
224 if (priv->status >= EMPATHY_DISPATCHER_OPERATION_STATE_CLAIMED)
225 /* no point to get more information */
228 handle = tp_channel_get_handle (priv->channel, &handle_type);
229 if (handle_type == TP_HANDLE_TYPE_CONTACT && priv->contact == NULL)
231 empathy_tp_contact_factory_get_from_handle (priv->connection, handle,
232 dispatcher_operation_got_contact_cb, NULL, NULL, G_OBJECT (self));
237 tp_channel_call_when_ready (priv->channel,
238 empathy_dispatch_operation_channel_ready_cb, self);
242 g_object_unref (self);
246 empathy_dispatch_operation_constructed (GObject *object)
248 EmpathyDispatchOperation *self = EMPATHY_DISPATCH_OPERATION (object);
249 EmpathyDispatchOperationPriv *priv = GET_PRIV (self);
251 empathy_dispatch_operation_set_status (self,
252 EMPATHY_DISPATCHER_OPERATION_STATE_PREPARING);
254 priv->invalidated_handler =
255 g_signal_connect (priv->channel, "invalidated",
256 G_CALLBACK (empathy_dispatch_operation_invalidated), self);
259 tp_connection_call_when_ready (priv->connection,
260 dispatch_operation_connection_ready, object);
264 empathy_dispatch_operation_class_init (
265 EmpathyDispatchOperationClass *empathy_dispatch_operation_class)
267 GObjectClass *object_class =
268 G_OBJECT_CLASS (empathy_dispatch_operation_class);
269 GParamSpec *param_spec;
271 g_type_class_add_private (empathy_dispatch_operation_class,
272 sizeof (EmpathyDispatchOperationPriv));
274 object_class->set_property = empathy_dispatch_operation_set_property;
275 object_class->get_property = empathy_dispatch_operation_get_property;
277 object_class->dispose = empathy_dispatch_operation_dispose;
278 object_class->finalize = empathy_dispatch_operation_finalize;
279 object_class->constructed = empathy_dispatch_operation_constructed;
281 signals[READY] = g_signal_new ("ready",
282 G_OBJECT_CLASS_TYPE(empathy_dispatch_operation_class),
286 g_cclosure_marshal_VOID__VOID,
289 signals[CLAIMED] = g_signal_new ("claimed",
290 G_OBJECT_CLASS_TYPE(empathy_dispatch_operation_class),
294 g_cclosure_marshal_VOID__VOID,
297 signals[INVALIDATED] = g_signal_new ("invalidated",
298 G_OBJECT_CLASS_TYPE(empathy_dispatch_operation_class),
302 _empathy_marshal_VOID__UINT_INT_STRING,
303 G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_INT, G_TYPE_STRING);
305 param_spec = g_param_spec_object ("connection",
306 "connection", "The telepathy connection",
308 G_PARAM_CONSTRUCT_ONLY |
309 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
310 g_object_class_install_property (object_class, PROP_CONNECTION,
313 param_spec = g_param_spec_object ("channel",
314 "channel", "The telepathy channel",
316 G_PARAM_CONSTRUCT_ONLY |
317 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
318 g_object_class_install_property (object_class, PROP_CHANNEL,
321 param_spec = g_param_spec_object ("channel-wrapper",
322 "channel wrapper", "The empathy specific channel wrapper",
324 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
325 g_object_class_install_property (object_class, PROP_CHANNEL_WRAPPER,
328 param_spec = g_param_spec_object ("contact",
329 "contact", "The empathy contact",
330 EMPATHY_TYPE_CONTACT,
331 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
332 g_object_class_install_property (object_class, PROP_CONTACT,
335 param_spec = g_param_spec_boolean ("incoming",
336 "incoming", "Whether or not the channel is incoming",
338 G_PARAM_CONSTRUCT_ONLY |
339 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
340 g_object_class_install_property (object_class, PROP_INCOMING,
343 param_spec = g_param_spec_enum ("status",
344 "status", "Status of the dispatch operation",
345 EMPATHY_TYPE_DISPATCH_OPERATION_STATE, 0,
346 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
347 g_object_class_install_property (object_class, PROP_STATUS, param_spec);
349 param_spec = g_param_spec_int64 ("user-action-time",
350 "user action time", "The user action time of the operation",
351 G_MININT64, G_MAXINT64, 0,
352 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
353 g_object_class_install_property (object_class, PROP_USER_ACTION_TIME,
358 empathy_dispatch_operation_dispose (GObject *object)
360 EmpathyDispatchOperation *self = EMPATHY_DISPATCH_OPERATION (object);
361 EmpathyDispatchOperationPriv *priv =
364 if (priv->dispose_has_run)
367 priv->dispose_has_run = TRUE;
369 g_object_unref (priv->connection);
371 if (priv->ready_handler != 0)
372 g_signal_handler_disconnect (priv->channel_wrapper,
373 priv->ready_handler);
375 if (priv->channel_wrapper != NULL)
376 g_object_unref (priv->channel_wrapper);
378 g_signal_handler_disconnect (priv->channel, priv->invalidated_handler);
379 g_object_unref (priv->channel);
381 if (priv->contact != NULL)
382 g_object_unref (priv->contact);
384 if (G_OBJECT_CLASS (empathy_dispatch_operation_parent_class)->dispose)
385 G_OBJECT_CLASS (empathy_dispatch_operation_parent_class)->dispose (object);
389 empathy_dispatch_operation_finalize (GObject *object)
391 /* free any data held directly by the object here */
392 G_OBJECT_CLASS (empathy_dispatch_operation_parent_class)->finalize (object);
396 empathy_dispatch_operation_set_status (EmpathyDispatchOperation *self,
397 EmpathyDispatchOperationState status)
399 EmpathyDispatchOperationPriv *priv = GET_PRIV (self);
401 g_assert (status >= priv->status);
404 if (priv->status != status)
406 DEBUG ("Dispatch operation %s status: %d -> %d",
407 empathy_dispatch_operation_get_object_path (self),
408 priv->status, status);
410 priv->status = status;
411 g_object_notify (G_OBJECT (self), "status");
413 if (status == EMPATHY_DISPATCHER_OPERATION_STATE_PENDING)
414 g_signal_emit (self, signals[READY], 0);
419 empathy_dispatch_operation_channel_ready_cb (TpChannel *channel,
420 const GError *error, gpointer user_data)
422 EmpathyDispatchOperation *self = EMPATHY_DISPATCH_OPERATION (user_data);
423 EmpathyDispatchOperationPriv *priv = GET_PRIV (self);
426 /* The error will be handled in empathy_dispatch_operation_invalidated */
430 g_assert (channel == priv->channel);
432 if (priv->status >= EMPATHY_DISPATCHER_OPERATION_STATE_CLAIMED)
433 /* no point to get more information */
436 /* If the channel wrapper is defined, we assume it's ready */
437 if (priv->channel_wrapper != NULL)
440 channel_type = tp_channel_get_channel_type_id (channel);
442 if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_FILE_TRANSFER)
444 EmpathyTpFile *file = empathy_tp_file_new (channel, priv->incoming);
445 priv->channel_wrapper = G_OBJECT (file);
449 empathy_dispatch_operation_set_status (self,
450 EMPATHY_DISPATCHER_OPERATION_STATE_PENDING);
452 g_object_unref (self);
455 EmpathyDispatchOperation *
456 empathy_dispatch_operation_new (TpConnection *connection,
458 EmpathyContact *contact,
460 gint64 user_action_time)
462 g_return_val_if_fail (connection != NULL, NULL);
463 g_return_val_if_fail (channel != NULL, NULL);
465 return g_object_new (EMPATHY_TYPE_DISPATCH_OPERATION,
466 "connection", connection,
469 "incoming", incoming,
470 "user-action-time", user_action_time,
475 empathy_dispatch_operation_start (EmpathyDispatchOperation *operation)
477 EmpathyDispatchOperationPriv *priv;
479 g_return_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation));
481 priv = GET_PRIV (operation);
484 priv->status == EMPATHY_DISPATCHER_OPERATION_STATE_PENDING);
486 empathy_dispatch_operation_set_status (operation,
487 EMPATHY_DISPATCHER_OPERATION_STATE_DISPATCHING);
490 /* Returns whether or not the operation was successfully claimed */
492 empathy_dispatch_operation_claim (EmpathyDispatchOperation *operation)
494 EmpathyDispatchOperationPriv *priv;
496 g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), FALSE);
498 priv = GET_PRIV (operation);
500 if (priv->status == EMPATHY_DISPATCHER_OPERATION_STATE_CLAIMED)
503 empathy_dispatch_operation_set_status (operation,
504 EMPATHY_DISPATCHER_OPERATION_STATE_CLAIMED);
506 g_signal_emit (operation, signals[CLAIMED], 0);
512 empathy_dispatch_operation_get_tp_connection (
513 EmpathyDispatchOperation *operation)
515 EmpathyDispatchOperationPriv *priv;
517 g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), NULL);
519 priv = GET_PRIV (operation);
521 return priv->connection;
525 empathy_dispatch_operation_get_channel (EmpathyDispatchOperation *operation)
527 EmpathyDispatchOperationPriv *priv;
529 g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), NULL);
531 priv = GET_PRIV (operation);
533 return priv->channel;
537 empathy_dispatch_operation_get_channel_wrapper (
538 EmpathyDispatchOperation *operation)
540 EmpathyDispatchOperationPriv *priv;
542 g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), NULL);
544 priv = GET_PRIV (operation);
546 return priv->channel_wrapper;
550 empathy_dispatch_operation_get_channel_type (
551 EmpathyDispatchOperation *operation)
553 EmpathyDispatchOperationPriv *priv;
555 g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), NULL);
557 priv = GET_PRIV (operation);
559 return tp_channel_get_channel_type (priv->channel);
563 empathy_dispatch_operation_get_channel_type_id (
564 EmpathyDispatchOperation *operation)
566 EmpathyDispatchOperationPriv *priv;
568 g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), 0);
570 priv = GET_PRIV (operation);
572 return tp_channel_get_channel_type_id (priv->channel);
576 empathy_dispatch_operation_get_object_path (
577 EmpathyDispatchOperation *operation)
579 EmpathyDispatchOperationPriv *priv;
581 g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), NULL);
583 priv = GET_PRIV (operation);
585 return tp_proxy_get_object_path (TP_PROXY (priv->channel));
588 EmpathyDispatchOperationState
589 empathy_dispatch_operation_get_status (EmpathyDispatchOperation *operation)
591 EmpathyDispatchOperationPriv *priv;
593 g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation),
594 EMPATHY_DISPATCHER_OPERATION_STATE_PREPARING);
596 priv = GET_PRIV (operation);
602 empathy_dispatch_operation_is_incoming (EmpathyDispatchOperation *operation)
604 EmpathyDispatchOperationPriv *priv;
606 g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), FALSE);
608 priv = GET_PRIV (operation);
610 return priv->incoming;
614 empathy_dispatch_operation_set_user_action_time (
615 EmpathyDispatchOperation *self,
616 gint64 user_action_time)
618 EmpathyDispatchOperationPriv *priv = GET_PRIV (self);
620 priv->user_action_time = user_action_time;
624 empathy_dispatch_operation_get_user_action_time (EmpathyDispatchOperation *self)
626 EmpathyDispatchOperationPriv *priv;
628 g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (self), FALSE);
630 priv = GET_PRIV (self);
632 return priv->user_action_time;