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
#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
/* Approved by an approver, can only happens on incoming operations */
53
/* Claimed by a handler */
55
/* Error, channel went away, inspecting it failed etc */
60
static guint signals[LAST_SIGNAL] = {0};
72
/* private structure */
73
typedef struct _EmpathyDispatchOperationPriv \
74
EmpathyDispatchOperationPriv;
76
struct _EmpathyDispatchOperationPriv
78
gboolean dispose_has_run;
79
TpConnection *connection;
81
GObject *channel_wrapper;
82
EmpathyContact *contact;
83
EmpathyDispatchOperationState status;
86
gulong invalidated_handler;
91
(G_TYPE_INSTANCE_GET_PRIVATE ((o), EMPATHY_TYPE_DISPATCH_OPERATION, \
92
EmpathyDispatchOperationPriv))
95
empathy_dispatch_operation_init (EmpathyDispatchOperation *obj)
97
//EmpathyDispatchOperationPriv *priv =
100
/* allocate any data required by the object here */
103
static void empathy_dispatch_operation_dispose (GObject *object);
104
static void empathy_dispatch_operation_finalize (GObject *object);
107
empathy_dispatch_operation_set_property (GObject *object,
108
guint property_id, const GValue *value, GParamSpec *pspec)
110
EmpathyDispatchOperation *operation = EMPATHY_DISPATCH_OPERATION (object);
111
EmpathyDispatchOperationPriv *priv = GET_PRIV (operation);
115
case PROP_CONNECTION:
116
priv->connection = g_value_dup_object (value);
119
priv->channel = g_value_dup_object (value);
121
case PROP_CHANNEL_WRAPPER:
122
priv->channel_wrapper = g_value_dup_object (value);
125
if (priv->contact != NULL)
126
g_object_unref (priv->contact);
127
priv->contact = g_value_dup_object (value);
130
priv->incoming = g_value_get_boolean (value);
136
empathy_dispatch_operation_get_property (GObject *object,
137
guint property_id, GValue *value, GParamSpec *pspec)
139
EmpathyDispatchOperation *operation = EMPATHY_DISPATCH_OPERATION (object);
140
EmpathyDispatchOperationPriv *priv = GET_PRIV (operation);
144
case PROP_CONNECTION:
145
g_value_set_object (value, priv->connection);
148
g_value_set_object (value, priv->channel);
150
case PROP_CHANNEL_WRAPPER:
151
g_value_set_object (value, priv->channel_wrapper);
154
g_value_set_object (value, priv->contact);
157
g_value_set_boolean (value, priv->incoming);
160
g_value_set_enum (value, priv->status);
166
empathy_dispatch_operation_invalidated (TpProxy *proxy, guint domain,
167
gint code, char *message, EmpathyDispatchOperation *self)
169
empathy_dispatch_operation_set_status (self,
170
EMPATHY_DISPATCHER_OPERATION_STATE_INVALIDATED);
172
g_signal_emit (self, signals[INVALIDATED], 0, domain, code, message);
176
empathy_dispatch_operation_constructed (GObject *object)
178
EmpathyDispatchOperation *self = EMPATHY_DISPATCH_OPERATION (object);
179
EmpathyDispatchOperationPriv *priv = GET_PRIV (self);
181
empathy_dispatch_operation_set_status (self,
182
EMPATHY_DISPATCHER_OPERATION_STATE_PREPARING);
184
priv->invalidated_handler =
185
g_signal_connect (priv->channel, "invalidated",
186
G_CALLBACK (empathy_dispatch_operation_invalidated), self);
188
tp_channel_call_when_ready (priv->channel,
189
empathy_dispatch_operation_channel_ready_cb, self);
193
empathy_dispatch_operation_class_init (
194
EmpathyDispatchOperationClass *empathy_dispatch_operation_class)
196
GObjectClass *object_class =
197
G_OBJECT_CLASS (empathy_dispatch_operation_class);
198
GParamSpec *param_spec;
200
g_type_class_add_private (empathy_dispatch_operation_class,
201
sizeof (EmpathyDispatchOperationPriv));
203
object_class->set_property = empathy_dispatch_operation_set_property;
204
object_class->get_property = empathy_dispatch_operation_get_property;
206
object_class->dispose = empathy_dispatch_operation_dispose;
207
object_class->finalize = empathy_dispatch_operation_finalize;
208
object_class->constructed = empathy_dispatch_operation_constructed;
210
signals[READY] = g_signal_new ("ready",
211
G_OBJECT_CLASS_TYPE(empathy_dispatch_operation_class),
215
g_cclosure_marshal_VOID__VOID,
218
signals[APPROVED] = g_signal_new ("approved",
219
G_OBJECT_CLASS_TYPE(empathy_dispatch_operation_class),
223
g_cclosure_marshal_VOID__VOID,
226
signals[CLAIMED] = g_signal_new ("claimed",
227
G_OBJECT_CLASS_TYPE(empathy_dispatch_operation_class),
231
g_cclosure_marshal_VOID__VOID,
234
signals[INVALIDATED] = g_signal_new ("invalidated",
235
G_OBJECT_CLASS_TYPE(empathy_dispatch_operation_class),
239
_empathy_marshal_VOID__UINT_INT_STRING,
240
G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_INT, G_TYPE_STRING);
242
param_spec = g_param_spec_object ("connection",
243
"connection", "The telepathy connection",
245
G_PARAM_CONSTRUCT_ONLY |
246
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
247
g_object_class_install_property (object_class, PROP_CONNECTION,
250
param_spec = g_param_spec_object ("channel",
251
"channel", "The telepathy channel",
253
G_PARAM_CONSTRUCT_ONLY |
254
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
255
g_object_class_install_property (object_class, PROP_CHANNEL,
258
param_spec = g_param_spec_object ("channel-wrapper",
259
"channel wrapper", "The empathy specific channel wrapper",
261
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
262
g_object_class_install_property (object_class, PROP_CHANNEL_WRAPPER,
265
param_spec = g_param_spec_object ("contact",
266
"contact", "The empathy contact",
267
EMPATHY_TYPE_CONTACT,
268
G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
269
g_object_class_install_property (object_class, PROP_CONTACT,
272
param_spec = g_param_spec_boolean ("incoming",
273
"incoming", "Whether or not the channel is incoming",
275
G_PARAM_CONSTRUCT_ONLY |
276
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
277
g_object_class_install_property (object_class, PROP_INCOMING,
280
param_spec = g_param_spec_enum ("status",
281
"status", "Status of the dispatch operation",
282
EMPATHY_TYPE_DISPATCH_OPERATION_STATE, 0,
283
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
284
g_object_class_install_property (object_class, PROP_STATUS, param_spec);
288
empathy_dispatch_operation_dispose (GObject *object)
290
EmpathyDispatchOperation *self = EMPATHY_DISPATCH_OPERATION (object);
291
EmpathyDispatchOperationPriv *priv =
294
if (priv->dispose_has_run)
297
priv->dispose_has_run = TRUE;
299
g_object_unref (priv->connection);
301
if (priv->channel_wrapper != NULL)
302
g_object_unref (priv->channel_wrapper);
304
if (priv->ready_handler != 0)
305
g_signal_handler_disconnect (priv->channel_wrapper,
306
priv->invalidated_handler);
309
g_signal_handler_disconnect (priv->channel, priv->invalidated_handler);
310
g_object_unref (priv->channel);
313
if (priv->contact != NULL)
314
g_object_unref (priv->contact);
316
if (G_OBJECT_CLASS (empathy_dispatch_operation_parent_class)->dispose)
317
G_OBJECT_CLASS (empathy_dispatch_operation_parent_class)->dispose (object);
321
empathy_dispatch_operation_finalize (GObject *object)
323
/* free any data held directly by the object here */
324
G_OBJECT_CLASS (empathy_dispatch_operation_parent_class)->finalize (object);
328
empathy_dispatch_operation_set_status (EmpathyDispatchOperation *self,
329
EmpathyDispatchOperationState status)
331
EmpathyDispatchOperationPriv *priv = GET_PRIV (self);
333
g_assert (status >= priv->status);
336
if (priv->status != status)
338
DEBUG ("Dispatch operation %s status: %d -> %d",
339
empathy_dispatch_operation_get_object_path (self),
340
priv->status, status);
342
priv->status = status;
343
g_object_notify (G_OBJECT (self), "status");
345
if (status == EMPATHY_DISPATCHER_OPERATION_STATE_PENDING)
346
g_signal_emit (self, signals[READY], 0);
351
empathy_dispatcher_operation_tp_chat_ready_cb (GObject *object,
352
GParamSpec *spec, gpointer user_data)
354
EmpathyDispatchOperation *self = EMPATHY_DISPATCH_OPERATION (user_data);
355
EmpathyDispatchOperationPriv *priv = GET_PRIV (self);
357
if (!empathy_tp_chat_is_ready (EMPATHY_TP_CHAT (priv->channel_wrapper)))
360
g_signal_handler_disconnect (priv->channel_wrapper, priv->ready_handler);
361
priv->ready_handler = 0;
363
empathy_dispatch_operation_set_status (self,
364
EMPATHY_DISPATCHER_OPERATION_STATE_PENDING);
368
empathy_dispatch_operation_channel_ready_cb (TpChannel *channel,
369
const GError *error, gpointer user_data)
371
EmpathyDispatchOperation *self = EMPATHY_DISPATCH_OPERATION (user_data);
372
EmpathyDispatchOperationPriv *priv = GET_PRIV (self);
375
/* The error will be handled in empathy_dispatch_operation_invalidated */
379
g_assert (channel == priv->channel);
381
/* If the channel wrapper is defined, we assume it's ready */
382
if (priv->channel_wrapper != NULL)
385
channel_type = tp_channel_get_channel_type_id (channel);
387
if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_TEXT)
389
EmpathyTpChat *chat= empathy_tp_chat_new (channel);
390
priv->channel_wrapper = G_OBJECT (chat);
392
if (!empathy_tp_chat_is_ready (chat))
394
priv->ready_handler = g_signal_connect (chat, "notify::ready",
395
G_CALLBACK (empathy_dispatcher_operation_tp_chat_ready_cb), self);
400
else if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_STREAMED_MEDIA)
402
EmpathyTpCall *call = empathy_tp_call_new (channel);
403
priv->channel_wrapper = G_OBJECT (call);
406
else if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_FILE_TRANSFER)
408
EmpathyTpFile *file = empathy_tp_file_new (channel);
409
priv->channel_wrapper = G_OBJECT (file);
413
empathy_dispatch_operation_set_status (self,
414
EMPATHY_DISPATCHER_OPERATION_STATE_PENDING);
417
EmpathyDispatchOperation *
418
empathy_dispatch_operation_new (TpConnection *connection, TpChannel *channel,
419
EmpathyContact *contact, gboolean incoming)
421
return empathy_dispatch_operation_new_with_wrapper (connection, channel,
422
contact, incoming, NULL);
425
EmpathyDispatchOperation *
426
empathy_dispatch_operation_new_with_wrapper (TpConnection *connection,
427
TpChannel *channel, EmpathyContact *contact, gboolean incoming,
430
g_return_val_if_fail (connection != NULL, NULL);
431
g_return_val_if_fail (channel != NULL, NULL);
433
return EMPATHY_DISPATCH_OPERATION (
434
g_object_new (EMPATHY_TYPE_DISPATCH_OPERATION,
435
"connection", connection,
437
"channel-wrapper", wrapper,
439
"incoming", incoming,
444
empathy_dispatch_operation_start (EmpathyDispatchOperation *operation)
446
EmpathyDispatchOperationPriv *priv;
448
g_return_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation));
450
priv = GET_PRIV (operation);
453
priv->status == EMPATHY_DISPATCHER_OPERATION_STATE_PENDING);
455
if (priv->incoming && !priv->approved)
456
empathy_dispatch_operation_set_status (operation,
457
EMPATHY_DISPATCHER_OPERATION_STATE_APPROVING);
459
empathy_dispatch_operation_set_status (operation,
460
EMPATHY_DISPATCHER_OPERATION_STATE_DISPATCHING);
464
empathy_dispatch_operation_approve (EmpathyDispatchOperation *operation)
466
EmpathyDispatchOperationPriv *priv;
468
g_return_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation));
470
priv = GET_PRIV (operation);
472
if (priv->status == EMPATHY_DISPATCHER_OPERATION_STATE_APPROVING)
474
DEBUG ("Approving operation %s",
475
empathy_dispatch_operation_get_object_path (operation));
477
empathy_dispatch_operation_set_status (operation,
478
EMPATHY_DISPATCHER_OPERATION_STATE_DISPATCHING);
480
g_signal_emit (operation, signals[APPROVED], 0);
482
else if (priv->status < EMPATHY_DISPATCHER_OPERATION_STATE_APPROVING)
484
DEBUG ("Pre-approving operation %s",
485
empathy_dispatch_operation_get_object_path (operation));
486
priv->approved = TRUE;
491
"Ignoring approval for %s as it's already past the approval stage",
492
empathy_dispatch_operation_get_object_path (operation));
496
/* Returns whether or not the operation was successfully claimed */
498
empathy_dispatch_operation_claim (EmpathyDispatchOperation *operation)
500
EmpathyDispatchOperationPriv *priv;
502
g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), FALSE);
504
priv = GET_PRIV (operation);
506
if (priv->status == EMPATHY_DISPATCHER_OPERATION_STATE_CLAIMED)
509
empathy_dispatch_operation_set_status (operation,
510
EMPATHY_DISPATCHER_OPERATION_STATE_CLAIMED);
512
g_signal_emit (operation, signals[CLAIMED], 0);
518
empathy_dispatch_operation_get_tp_connection (
519
EmpathyDispatchOperation *operation)
521
EmpathyDispatchOperationPriv *priv;
523
g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), NULL);
525
priv = GET_PRIV (operation);
527
return g_object_ref (priv->connection);
531
empathy_dispatch_operation_get_channel (EmpathyDispatchOperation *operation)
533
EmpathyDispatchOperationPriv *priv;
535
g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), NULL);
537
priv = GET_PRIV (operation);
539
return priv->channel;
543
empathy_dispatch_operation_get_channel_wrapper (
544
EmpathyDispatchOperation *operation)
546
EmpathyDispatchOperationPriv *priv;
548
g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), NULL);
550
priv = GET_PRIV (operation);
552
return priv->channel_wrapper;
556
empathy_dispatch_operation_get_channel_type (
557
EmpathyDispatchOperation *operation)
559
EmpathyDispatchOperationPriv *priv;
561
g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), NULL);
563
priv = GET_PRIV (operation);
565
return tp_channel_get_channel_type (priv->channel);
569
empathy_dispatch_operation_get_channel_type_id (
570
EmpathyDispatchOperation *operation)
572
EmpathyDispatchOperationPriv *priv;
574
g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), 0);
576
priv = GET_PRIV (operation);
578
return tp_channel_get_channel_type_id (priv->channel);
582
empathy_dispatch_operation_get_object_path (
583
EmpathyDispatchOperation *operation)
585
EmpathyDispatchOperationPriv *priv;
587
g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), NULL);
589
priv = GET_PRIV (operation);
591
return tp_proxy_get_object_path (TP_PROXY (priv->channel));
594
EmpathyDispatchOperationState
595
empathy_dispatch_operation_get_status (EmpathyDispatchOperation *operation)
597
EmpathyDispatchOperationPriv *priv;
599
g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation),
600
EMPATHY_DISPATCHER_OPERATION_STATE_PREPARING);
602
priv = GET_PRIV (operation);
608
empathy_dispatch_operation_is_incoming (EmpathyDispatchOperation *operation)
610
EmpathyDispatchOperationPriv *priv;
612
g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), FALSE);
614
priv = GET_PRIV (operation);
616
return priv->incoming;