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>
31 #include "empathy-marshal.h"
33 #include "extensions/extensions.h"
35 #define DEBUG_FLAG EMPATHY_DEBUG_DISPATCHER
36 #include <libempathy/empathy-debug.h>
38 G_DEFINE_TYPE(EmpathyDispatchOperation
, empathy_dispatch_operation
,
41 static void empathy_dispatch_operation_set_status (
42 EmpathyDispatchOperation
*self
, EmpathyDispatchOperationState status
);
43 static void empathy_dispatch_operation_channel_ready_cb (TpChannel
*channel
,
44 const GError
*error
, gpointer user_data
);
49 /* Ready for dispatching */
51 /* Claimed by a handler */
53 /* Error, channel went away, inspecting it failed etc */
58 static guint signals
[LAST_SIGNAL
] = {0};
68 PROP_USER_ACTION_TIME
,
71 /* private structure */
72 typedef struct _EmpathyDispatchOperationPriv \
73 EmpathyDispatchOperationPriv
;
75 struct _EmpathyDispatchOperationPriv
77 gboolean dispose_has_run
;
78 TpConnection
*connection
;
80 GObject
*channel_wrapper
;
81 EmpathyContact
*contact
;
82 EmpathyDispatchOperationState status
;
84 gint64 user_action_time
;
85 gulong invalidated_handler
;
90 (G_TYPE_INSTANCE_GET_PRIVATE ((o), EMPATHY_TYPE_DISPATCH_OPERATION, \
91 EmpathyDispatchOperationPriv))
94 empathy_dispatch_operation_init (EmpathyDispatchOperation
*obj
)
96 //EmpathyDispatchOperationPriv *priv =
99 /* allocate any data required by the object here */
102 static void empathy_dispatch_operation_dispose (GObject
*object
);
103 static void empathy_dispatch_operation_finalize (GObject
*object
);
106 empathy_dispatch_operation_set_property (GObject
*object
,
107 guint property_id
, const GValue
*value
, GParamSpec
*pspec
)
109 EmpathyDispatchOperation
*operation
= EMPATHY_DISPATCH_OPERATION (object
);
110 EmpathyDispatchOperationPriv
*priv
= GET_PRIV (operation
);
114 case PROP_CONNECTION
:
115 priv
->connection
= g_value_dup_object (value
);
118 priv
->channel
= g_value_dup_object (value
);
120 case PROP_CHANNEL_WRAPPER
:
121 priv
->channel_wrapper
= g_value_dup_object (value
);
124 if (priv
->contact
!= NULL
)
125 g_object_unref (priv
->contact
);
126 priv
->contact
= g_value_dup_object (value
);
129 priv
->incoming
= g_value_get_boolean (value
);
131 case PROP_USER_ACTION_TIME
:
132 priv
->user_action_time
= g_value_get_int64 (value
);
135 g_assert_not_reached ();
140 empathy_dispatch_operation_get_property (GObject
*object
,
141 guint property_id
, GValue
*value
, GParamSpec
*pspec
)
143 EmpathyDispatchOperation
*operation
= EMPATHY_DISPATCH_OPERATION (object
);
144 EmpathyDispatchOperationPriv
*priv
= GET_PRIV (operation
);
148 case PROP_CONNECTION
:
149 g_value_set_object (value
, priv
->connection
);
152 g_value_set_object (value
, priv
->channel
);
154 case PROP_CHANNEL_WRAPPER
:
155 g_value_set_object (value
, priv
->channel_wrapper
);
158 g_value_set_object (value
, priv
->contact
);
161 g_value_set_boolean (value
, priv
->incoming
);
164 g_value_set_enum (value
, priv
->status
);
166 case PROP_USER_ACTION_TIME
:
167 g_value_set_int64 (value
, priv
->user_action_time
);
170 g_assert_not_reached ();
175 empathy_dispatch_operation_invalidated (TpProxy
*proxy
, guint domain
,
176 gint code
, char *message
, EmpathyDispatchOperation
*self
)
178 empathy_dispatch_operation_set_status (self
,
179 EMPATHY_DISPATCHER_OPERATION_STATE_INVALIDATED
);
181 g_signal_emit (self
, signals
[INVALIDATED
], 0, domain
, code
, message
);
185 dispatcher_operation_got_contact_cb (TpConnection
*connection
,
186 EmpathyContact
*contact
,
191 EmpathyDispatchOperationPriv
*priv
= GET_PRIV (self
);
195 /* FIXME: We should cancel the operation */
196 DEBUG ("Error: %s", error
->message
);
200 if (priv
->contact
!= NULL
)
201 g_object_unref (priv
->contact
);
202 priv
->contact
= g_object_ref (contact
);
203 g_object_notify (G_OBJECT (self
), "contact");
205 /* Ensure to keep the self object alive while the call_when_ready is
208 tp_channel_call_when_ready (priv
->channel
,
209 empathy_dispatch_operation_channel_ready_cb
, self
);
213 dispatch_operation_connection_ready (TpConnection
*connection
,
217 EmpathyDispatchOperation
*self
= EMPATHY_DISPATCH_OPERATION (user_data
);
218 EmpathyDispatchOperationPriv
*priv
= GET_PRIV (self
);
220 TpHandleType handle_type
;
225 if (priv
->status
>= EMPATHY_DISPATCHER_OPERATION_STATE_CLAIMED
)
226 /* no point to get more information */
229 handle
= tp_channel_get_handle (priv
->channel
, &handle_type
);
230 if (handle_type
== TP_HANDLE_TYPE_CONTACT
&& priv
->contact
== NULL
)
232 empathy_tp_contact_factory_get_from_handle (priv
->connection
, handle
,
233 dispatcher_operation_got_contact_cb
, NULL
, NULL
, G_OBJECT (self
));
238 tp_channel_call_when_ready (priv
->channel
,
239 empathy_dispatch_operation_channel_ready_cb
, self
);
243 g_object_unref (self
);
247 empathy_dispatch_operation_constructed (GObject
*object
)
249 EmpathyDispatchOperation
*self
= EMPATHY_DISPATCH_OPERATION (object
);
250 EmpathyDispatchOperationPriv
*priv
= GET_PRIV (self
);
252 empathy_dispatch_operation_set_status (self
,
253 EMPATHY_DISPATCHER_OPERATION_STATE_PREPARING
);
255 priv
->invalidated_handler
=
256 g_signal_connect (priv
->channel
, "invalidated",
257 G_CALLBACK (empathy_dispatch_operation_invalidated
), self
);
260 tp_connection_call_when_ready (priv
->connection
,
261 dispatch_operation_connection_ready
, object
);
265 empathy_dispatch_operation_class_init (
266 EmpathyDispatchOperationClass
*empathy_dispatch_operation_class
)
268 GObjectClass
*object_class
=
269 G_OBJECT_CLASS (empathy_dispatch_operation_class
);
270 GParamSpec
*param_spec
;
272 g_type_class_add_private (empathy_dispatch_operation_class
,
273 sizeof (EmpathyDispatchOperationPriv
));
275 object_class
->set_property
= empathy_dispatch_operation_set_property
;
276 object_class
->get_property
= empathy_dispatch_operation_get_property
;
278 object_class
->dispose
= empathy_dispatch_operation_dispose
;
279 object_class
->finalize
= empathy_dispatch_operation_finalize
;
280 object_class
->constructed
= empathy_dispatch_operation_constructed
;
282 signals
[READY
] = g_signal_new ("ready",
283 G_OBJECT_CLASS_TYPE(empathy_dispatch_operation_class
),
287 g_cclosure_marshal_VOID__VOID
,
290 signals
[CLAIMED
] = g_signal_new ("claimed",
291 G_OBJECT_CLASS_TYPE(empathy_dispatch_operation_class
),
295 g_cclosure_marshal_VOID__VOID
,
298 signals
[INVALIDATED
] = g_signal_new ("invalidated",
299 G_OBJECT_CLASS_TYPE(empathy_dispatch_operation_class
),
303 _empathy_marshal_VOID__UINT_INT_STRING
,
304 G_TYPE_NONE
, 3, G_TYPE_UINT
, G_TYPE_INT
, G_TYPE_STRING
);
306 param_spec
= g_param_spec_object ("connection",
307 "connection", "The telepathy connection",
309 G_PARAM_CONSTRUCT_ONLY
|
310 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
311 g_object_class_install_property (object_class
, PROP_CONNECTION
,
314 param_spec
= g_param_spec_object ("channel",
315 "channel", "The telepathy channel",
317 G_PARAM_CONSTRUCT_ONLY
|
318 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
319 g_object_class_install_property (object_class
, PROP_CHANNEL
,
322 param_spec
= g_param_spec_object ("channel-wrapper",
323 "channel wrapper", "The empathy specific channel wrapper",
325 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
326 g_object_class_install_property (object_class
, PROP_CHANNEL_WRAPPER
,
329 param_spec
= g_param_spec_object ("contact",
330 "contact", "The empathy contact",
331 EMPATHY_TYPE_CONTACT
,
332 G_PARAM_CONSTRUCT
| G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
333 g_object_class_install_property (object_class
, PROP_CONTACT
,
336 param_spec
= g_param_spec_boolean ("incoming",
337 "incoming", "Whether or not the channel is incoming",
339 G_PARAM_CONSTRUCT_ONLY
|
340 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
341 g_object_class_install_property (object_class
, PROP_INCOMING
,
344 param_spec
= g_param_spec_enum ("status",
345 "status", "Status of the dispatch operation",
346 EMPATHY_TYPE_DISPATCH_OPERATION_STATE
, 0,
347 G_PARAM_READABLE
| G_PARAM_STATIC_STRINGS
);
348 g_object_class_install_property (object_class
, PROP_STATUS
, param_spec
);
350 param_spec
= g_param_spec_int64 ("user-action-time",
351 "user action time", "The user action time of the operation",
352 G_MININT64
, G_MAXINT64
, 0,
353 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
354 g_object_class_install_property (object_class
, PROP_USER_ACTION_TIME
,
359 empathy_dispatch_operation_dispose (GObject
*object
)
361 EmpathyDispatchOperation
*self
= EMPATHY_DISPATCH_OPERATION (object
);
362 EmpathyDispatchOperationPriv
*priv
=
365 if (priv
->dispose_has_run
)
368 priv
->dispose_has_run
= TRUE
;
370 g_object_unref (priv
->connection
);
372 if (priv
->ready_handler
!= 0)
373 g_signal_handler_disconnect (priv
->channel_wrapper
,
374 priv
->ready_handler
);
376 if (priv
->channel_wrapper
!= NULL
)
377 g_object_unref (priv
->channel_wrapper
);
379 g_signal_handler_disconnect (priv
->channel
, priv
->invalidated_handler
);
380 g_object_unref (priv
->channel
);
382 if (priv
->contact
!= NULL
)
383 g_object_unref (priv
->contact
);
385 if (G_OBJECT_CLASS (empathy_dispatch_operation_parent_class
)->dispose
)
386 G_OBJECT_CLASS (empathy_dispatch_operation_parent_class
)->dispose (object
);
390 empathy_dispatch_operation_finalize (GObject
*object
)
392 /* free any data held directly by the object here */
393 G_OBJECT_CLASS (empathy_dispatch_operation_parent_class
)->finalize (object
);
397 empathy_dispatch_operation_set_status (EmpathyDispatchOperation
*self
,
398 EmpathyDispatchOperationState status
)
400 EmpathyDispatchOperationPriv
*priv
= GET_PRIV (self
);
402 g_assert (status
>= priv
->status
);
405 if (priv
->status
!= status
)
407 DEBUG ("Dispatch operation %s status: %d -> %d",
408 empathy_dispatch_operation_get_object_path (self
),
409 priv
->status
, status
);
411 priv
->status
= status
;
412 g_object_notify (G_OBJECT (self
), "status");
414 if (status
== EMPATHY_DISPATCHER_OPERATION_STATE_PENDING
)
415 g_signal_emit (self
, signals
[READY
], 0);
420 empathy_dispatch_operation_channel_ready_cb (TpChannel
*channel
,
421 const GError
*error
, gpointer user_data
)
423 EmpathyDispatchOperation
*self
= EMPATHY_DISPATCH_OPERATION (user_data
);
424 EmpathyDispatchOperationPriv
*priv
= GET_PRIV (self
);
428 /* The error will be handled in empathy_dispatch_operation_invalidated */
432 g_assert (channel
== priv
->channel
);
434 if (priv
->status
>= EMPATHY_DISPATCHER_OPERATION_STATE_CLAIMED
)
435 /* no point to get more information */
438 /* If the channel wrapper is defined, we assume it's ready */
439 if (priv
->channel_wrapper
!= NULL
)
443 empathy_dispatch_operation_set_status (self
,
444 EMPATHY_DISPATCHER_OPERATION_STATE_PENDING
);
446 g_object_unref (self
);
449 EmpathyDispatchOperation
*
450 empathy_dispatch_operation_new (TpConnection
*connection
,
452 EmpathyContact
*contact
,
454 gint64 user_action_time
)
456 g_return_val_if_fail (connection
!= NULL
, NULL
);
457 g_return_val_if_fail (channel
!= NULL
, NULL
);
459 return g_object_new (EMPATHY_TYPE_DISPATCH_OPERATION
,
460 "connection", connection
,
463 "incoming", incoming
,
464 "user-action-time", user_action_time
,
469 empathy_dispatch_operation_start (EmpathyDispatchOperation
*operation
)
471 EmpathyDispatchOperationPriv
*priv
;
473 g_return_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation
));
475 priv
= GET_PRIV (operation
);
478 priv
->status
== EMPATHY_DISPATCHER_OPERATION_STATE_PENDING
);
480 empathy_dispatch_operation_set_status (operation
,
481 EMPATHY_DISPATCHER_OPERATION_STATE_DISPATCHING
);
484 /* Returns whether or not the operation was successfully claimed */
486 empathy_dispatch_operation_claim (EmpathyDispatchOperation
*operation
)
488 EmpathyDispatchOperationPriv
*priv
;
490 g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation
), FALSE
);
492 priv
= GET_PRIV (operation
);
494 if (priv
->status
== EMPATHY_DISPATCHER_OPERATION_STATE_CLAIMED
)
497 empathy_dispatch_operation_set_status (operation
,
498 EMPATHY_DISPATCHER_OPERATION_STATE_CLAIMED
);
500 g_signal_emit (operation
, signals
[CLAIMED
], 0);
506 empathy_dispatch_operation_get_tp_connection (
507 EmpathyDispatchOperation
*operation
)
509 EmpathyDispatchOperationPriv
*priv
;
511 g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation
), NULL
);
513 priv
= GET_PRIV (operation
);
515 return priv
->connection
;
519 empathy_dispatch_operation_get_channel (EmpathyDispatchOperation
*operation
)
521 EmpathyDispatchOperationPriv
*priv
;
523 g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation
), NULL
);
525 priv
= GET_PRIV (operation
);
527 return priv
->channel
;
531 empathy_dispatch_operation_get_channel_wrapper (
532 EmpathyDispatchOperation
*operation
)
534 EmpathyDispatchOperationPriv
*priv
;
536 g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation
), NULL
);
538 priv
= GET_PRIV (operation
);
540 return priv
->channel_wrapper
;
544 empathy_dispatch_operation_get_channel_type (
545 EmpathyDispatchOperation
*operation
)
547 EmpathyDispatchOperationPriv
*priv
;
549 g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation
), NULL
);
551 priv
= GET_PRIV (operation
);
553 return tp_channel_get_channel_type (priv
->channel
);
557 empathy_dispatch_operation_get_channel_type_id (
558 EmpathyDispatchOperation
*operation
)
560 EmpathyDispatchOperationPriv
*priv
;
562 g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation
), 0);
564 priv
= GET_PRIV (operation
);
566 return tp_channel_get_channel_type_id (priv
->channel
);
570 empathy_dispatch_operation_get_object_path (
571 EmpathyDispatchOperation
*operation
)
573 EmpathyDispatchOperationPriv
*priv
;
575 g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation
), NULL
);
577 priv
= GET_PRIV (operation
);
579 return tp_proxy_get_object_path (TP_PROXY (priv
->channel
));
582 EmpathyDispatchOperationState
583 empathy_dispatch_operation_get_status (EmpathyDispatchOperation
*operation
)
585 EmpathyDispatchOperationPriv
*priv
;
587 g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation
),
588 EMPATHY_DISPATCHER_OPERATION_STATE_PREPARING
);
590 priv
= GET_PRIV (operation
);
596 empathy_dispatch_operation_is_incoming (EmpathyDispatchOperation
*operation
)
598 EmpathyDispatchOperationPriv
*priv
;
600 g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation
), FALSE
);
602 priv
= GET_PRIV (operation
);
604 return priv
->incoming
;
608 empathy_dispatch_operation_set_user_action_time (
609 EmpathyDispatchOperation
*self
,
610 gint64 user_action_time
)
612 EmpathyDispatchOperationPriv
*priv
= GET_PRIV (self
);
614 priv
->user_action_time
= user_action_time
;
618 empathy_dispatch_operation_get_user_action_time (EmpathyDispatchOperation
*self
)
620 EmpathyDispatchOperationPriv
*priv
;
622 g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (self
), FALSE
);
624 priv
= GET_PRIV (self
);
626 return priv
->user_action_time
;