8f6fffe4ef32a862dd7d91d14c4d19b9d99c7816
[empathy.git] / libempathy / empathy-dispatch-operation.c
1 /*
2  * empathy-dispatch-operation.c - Source for EmpathyDispatchOperation
3  * Copyright (C) 2008 Collabora Ltd.
4  * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk>
5  *
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.
10  *
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.
15  *
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
19  */
20
21
22 #include <stdio.h>
23 #include <stdlib.h>
24
25 #include "empathy-dispatch-operation.h"
26 #include <libempathy/empathy-enum-types.h>
27 #include <libempathy/empathy-tp-contact-factory.h>
28 #include <libempathy/empathy-tp-chat.h>
29 #include <libempathy/empathy-tp-call.h>
30 #include <libempathy/empathy-tp-file.h>
31
32 #include "empathy-marshal.h"
33
34 #include "extensions/extensions.h"
35
36 #define DEBUG_FLAG EMPATHY_DEBUG_DISPATCHER
37 #include <libempathy/empathy-debug.h>
38
39 G_DEFINE_TYPE(EmpathyDispatchOperation, empathy_dispatch_operation,
40   G_TYPE_OBJECT)
41
42 static void empathy_dispatch_operation_set_status (
43   EmpathyDispatchOperation *self, EmpathyDispatchOperationState status);
44 static void empathy_dispatch_operation_channel_ready_cb (TpChannel *channel,
45   const GError *error, gpointer user_data);
46
47 /* signal enum */
48 enum
49 {
50     /* Ready for dispatching */
51     READY,
52     /* Approved by an approver, can only happens on incoming operations */
53     APPROVED,
54     /* Claimed by a handler */
55     CLAIMED,
56     /* Error, channel went away, inspecting it failed etc */
57     INVALIDATED,
58     LAST_SIGNAL
59 };
60
61 static guint signals[LAST_SIGNAL] = {0};
62
63 /* properties */
64 enum {
65   PROP_CONNECTION = 1,
66   PROP_CHANNEL,
67   PROP_CHANNEL_WRAPPER,
68   PROP_CONTACT,
69   PROP_INCOMING,
70   PROP_STATUS,
71 };
72
73 /* private structure */
74 typedef struct _EmpathyDispatchOperationPriv \
75   EmpathyDispatchOperationPriv;
76
77 struct _EmpathyDispatchOperationPriv
78 {
79   gboolean dispose_has_run;
80   TpConnection *connection;
81   TpChannel *channel;
82   GObject *channel_wrapper;
83   EmpathyContact *contact;
84   EmpathyDispatchOperationState status;
85   gboolean incoming;
86   gboolean approved;
87   gulong invalidated_handler;
88   gulong ready_handler;
89 };
90
91 #define GET_PRIV(o)  \
92   (G_TYPE_INSTANCE_GET_PRIVATE ((o), EMPATHY_TYPE_DISPATCH_OPERATION, \
93     EmpathyDispatchOperationPriv))
94
95 static void
96 empathy_dispatch_operation_init (EmpathyDispatchOperation *obj)
97 {
98   //EmpathyDispatchOperationPriv *priv =
99   //  GET_PRIV (obj);
100
101   /* allocate any data required by the object here */
102 }
103
104 static void empathy_dispatch_operation_dispose (GObject *object);
105 static void empathy_dispatch_operation_finalize (GObject *object);
106
107 static void
108 empathy_dispatch_operation_set_property (GObject *object,
109   guint property_id, const GValue *value, GParamSpec *pspec)
110 {
111   EmpathyDispatchOperation *operation = EMPATHY_DISPATCH_OPERATION (object);
112   EmpathyDispatchOperationPriv *priv = GET_PRIV (operation);
113
114   switch (property_id)
115     {
116       case PROP_CONNECTION:
117         priv->connection = g_value_dup_object (value);
118         break;
119       case PROP_CHANNEL:
120         priv->channel = g_value_dup_object (value);
121         break;
122       case PROP_CHANNEL_WRAPPER:
123         priv->channel_wrapper = g_value_dup_object (value);
124         break;
125       case PROP_CONTACT:
126         if (priv->contact != NULL)
127           g_object_unref (priv->contact);
128         priv->contact = g_value_dup_object (value);
129         break;
130       case PROP_INCOMING:
131         priv->incoming = g_value_get_boolean (value);
132         break;
133     }
134 }
135
136 static void
137 empathy_dispatch_operation_get_property (GObject *object,
138   guint property_id, GValue *value, GParamSpec *pspec)
139 {
140   EmpathyDispatchOperation *operation = EMPATHY_DISPATCH_OPERATION (object);
141   EmpathyDispatchOperationPriv *priv = GET_PRIV (operation);
142
143   switch (property_id)
144     {
145       case PROP_CONNECTION:
146         g_value_set_object (value, priv->connection);
147         break;
148       case PROP_CHANNEL:
149         g_value_set_object (value, priv->channel);
150         break;
151       case PROP_CHANNEL_WRAPPER:
152         g_value_set_object (value, priv->channel_wrapper);
153         break;
154       case PROP_CONTACT:
155         g_value_set_object (value, priv->contact);
156         break;
157       case PROP_INCOMING:
158         g_value_set_boolean (value, priv->incoming);
159         break;
160       case PROP_STATUS:
161         g_value_set_enum (value, priv->status);
162         break;
163     }
164 }
165
166 static void
167 empathy_dispatch_operation_invalidated (TpProxy *proxy, guint domain,
168   gint code, char *message, EmpathyDispatchOperation *self)
169 {
170   empathy_dispatch_operation_set_status (self,
171     EMPATHY_DISPATCHER_OPERATION_STATE_INVALIDATED);
172
173   g_signal_emit (self, signals[INVALIDATED], 0, domain, code, message);
174 }
175
176 static void
177 dispatcher_operation_got_contact_cb (EmpathyTpContactFactory *factory,
178                                      EmpathyContact *contact,
179                                      const GError *error,
180                                      gpointer user_data,
181                                      GObject *self)
182 {
183   EmpathyDispatchOperationPriv *priv = GET_PRIV (self);
184
185   if (error)
186     {
187       /* FIXME: We should cancel the operation */
188       DEBUG ("Error: %s", error->message);
189       return;
190     }
191
192   if (priv->contact != NULL)
193     g_object_unref (priv->contact);
194   priv->contact = g_object_ref (contact);
195   g_object_notify (G_OBJECT (self), "contact");
196
197   tp_channel_call_when_ready (priv->channel,
198     empathy_dispatch_operation_channel_ready_cb, self);
199 }
200
201 static void
202 empathy_dispatch_operation_constructed (GObject *object)
203 {
204   EmpathyDispatchOperation *self = EMPATHY_DISPATCH_OPERATION (object);
205   EmpathyDispatchOperationPriv *priv = GET_PRIV (self);
206   TpHandle handle;
207   TpHandleType handle_type;
208
209   empathy_dispatch_operation_set_status (self,
210     EMPATHY_DISPATCHER_OPERATION_STATE_PREPARING);
211
212   priv->invalidated_handler =
213     g_signal_connect (priv->channel, "invalidated",
214       G_CALLBACK (empathy_dispatch_operation_invalidated), self);
215
216   handle = tp_channel_get_handle (priv->channel, &handle_type);
217
218   if (handle_type == TP_CONN_HANDLE_TYPE_CONTACT && priv->contact == NULL)
219     {
220       EmpathyTpContactFactory *factory;
221
222       factory = empathy_tp_contact_factory_dup_singleton (priv->connection);
223       empathy_tp_contact_factory_get_from_handle (factory, handle,
224         dispatcher_operation_got_contact_cb, NULL, NULL, object);
225       g_object_unref (factory);
226       return;
227     }
228
229   tp_channel_call_when_ready (priv->channel,
230     empathy_dispatch_operation_channel_ready_cb, self);
231 }
232
233 static void
234 empathy_dispatch_operation_class_init (
235   EmpathyDispatchOperationClass *empathy_dispatch_operation_class)
236 {
237   GObjectClass *object_class =
238     G_OBJECT_CLASS (empathy_dispatch_operation_class);
239   GParamSpec *param_spec;
240
241   g_type_class_add_private (empathy_dispatch_operation_class,
242     sizeof (EmpathyDispatchOperationPriv));
243
244   object_class->set_property = empathy_dispatch_operation_set_property;
245   object_class->get_property = empathy_dispatch_operation_get_property;
246
247   object_class->dispose = empathy_dispatch_operation_dispose;
248   object_class->finalize = empathy_dispatch_operation_finalize;
249   object_class->constructed = empathy_dispatch_operation_constructed;
250
251   signals[READY] = g_signal_new ("ready",
252     G_OBJECT_CLASS_TYPE(empathy_dispatch_operation_class),
253       G_SIGNAL_RUN_LAST,
254       0,
255       NULL, NULL,
256       g_cclosure_marshal_VOID__VOID,
257       G_TYPE_NONE, 0);
258
259   signals[APPROVED] = g_signal_new ("approved",
260     G_OBJECT_CLASS_TYPE(empathy_dispatch_operation_class),
261       G_SIGNAL_RUN_LAST,
262       0,
263       NULL, NULL,
264       g_cclosure_marshal_VOID__VOID,
265       G_TYPE_NONE, 0);
266
267   signals[CLAIMED] = g_signal_new ("claimed",
268     G_OBJECT_CLASS_TYPE(empathy_dispatch_operation_class),
269       G_SIGNAL_RUN_LAST,
270       0,
271       NULL, NULL,
272       g_cclosure_marshal_VOID__VOID,
273       G_TYPE_NONE, 0);
274
275   signals[INVALIDATED] = g_signal_new ("invalidated",
276     G_OBJECT_CLASS_TYPE(empathy_dispatch_operation_class),
277       G_SIGNAL_RUN_LAST,
278       0,
279       NULL, NULL,
280       _empathy_marshal_VOID__UINT_INT_STRING,
281       G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_INT, G_TYPE_STRING);
282
283   param_spec = g_param_spec_object ("connection",
284     "connection", "The telepathy connection",
285     TP_TYPE_CONNECTION,
286     G_PARAM_CONSTRUCT_ONLY |
287     G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
288   g_object_class_install_property (object_class, PROP_CONNECTION,
289                                   param_spec);
290
291   param_spec = g_param_spec_object ("channel",
292     "channel", "The telepathy channel",
293     TP_TYPE_CHANNEL,
294     G_PARAM_CONSTRUCT_ONLY |
295     G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
296   g_object_class_install_property (object_class, PROP_CHANNEL,
297                                   param_spec);
298
299   param_spec = g_param_spec_object ("channel-wrapper",
300     "channel wrapper", "The empathy specific channel wrapper",
301     G_TYPE_OBJECT,
302     G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
303   g_object_class_install_property (object_class, PROP_CHANNEL_WRAPPER,
304                                   param_spec);
305
306   param_spec = g_param_spec_object ("contact",
307     "contact", "The empathy contact",
308     EMPATHY_TYPE_CONTACT,
309     G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
310   g_object_class_install_property (object_class, PROP_CONTACT,
311                                   param_spec);
312
313   param_spec = g_param_spec_boolean ("incoming",
314     "incoming", "Whether or not the channel is incoming",
315     FALSE,
316     G_PARAM_CONSTRUCT_ONLY |
317     G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
318   g_object_class_install_property (object_class, PROP_INCOMING,
319                                   param_spec);
320
321   param_spec = g_param_spec_enum ("status",
322     "status", "Status of the dispatch operation",
323     EMPATHY_TYPE_DISPATCH_OPERATION_STATE, 0,
324     G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
325   g_object_class_install_property (object_class, PROP_STATUS, param_spec);
326 }
327
328 void
329 empathy_dispatch_operation_dispose (GObject *object)
330 {
331   EmpathyDispatchOperation *self = EMPATHY_DISPATCH_OPERATION (object);
332   EmpathyDispatchOperationPriv *priv =
333     GET_PRIV (self);
334
335   if (priv->dispose_has_run)
336     return;
337
338   priv->dispose_has_run = TRUE;
339
340   g_object_unref (priv->connection);
341
342   if (priv->channel_wrapper != NULL)
343     g_object_unref (priv->channel_wrapper);
344
345   if (priv->ready_handler != 0)
346     g_signal_handler_disconnect (priv->channel_wrapper,
347       priv->invalidated_handler);
348
349
350   g_signal_handler_disconnect (priv->channel, priv->invalidated_handler);
351   g_object_unref (priv->channel);
352
353
354   if (priv->contact != NULL)
355     g_object_unref (priv->contact);
356
357   if (G_OBJECT_CLASS (empathy_dispatch_operation_parent_class)->dispose)
358     G_OBJECT_CLASS (empathy_dispatch_operation_parent_class)->dispose (object);
359 }
360
361 void
362 empathy_dispatch_operation_finalize (GObject *object)
363 {
364   /* free any data held directly by the object here */
365   G_OBJECT_CLASS (empathy_dispatch_operation_parent_class)->finalize (object);
366 }
367
368 static void
369 empathy_dispatch_operation_set_status (EmpathyDispatchOperation *self,
370   EmpathyDispatchOperationState status)
371 {
372   EmpathyDispatchOperationPriv *priv = GET_PRIV (self);
373
374   g_assert (status >= priv->status);
375
376
377   if (priv->status != status)
378     {
379       DEBUG ("Dispatch operation %s status: %d -> %d",
380         empathy_dispatch_operation_get_object_path (self),
381         priv->status, status);
382
383       priv->status = status;
384       g_object_notify (G_OBJECT (self), "status");
385
386       if (status == EMPATHY_DISPATCHER_OPERATION_STATE_PENDING)
387         g_signal_emit (self, signals[READY], 0);
388     }
389 }
390
391 static void
392 empathy_dispatcher_operation_tp_chat_ready_cb (GObject *object,
393   GParamSpec *spec, gpointer user_data)
394 {
395   EmpathyDispatchOperation *self = EMPATHY_DISPATCH_OPERATION (user_data);
396   EmpathyDispatchOperationPriv *priv = GET_PRIV (self);
397
398   if (!empathy_tp_chat_is_ready (EMPATHY_TP_CHAT (priv->channel_wrapper)))
399     return;
400
401   g_signal_handler_disconnect (priv->channel_wrapper, priv->ready_handler);
402   priv->ready_handler = 0;
403
404   empathy_dispatch_operation_set_status (self,
405     EMPATHY_DISPATCHER_OPERATION_STATE_PENDING);
406 }
407
408 static void
409 empathy_dispatcher_operation_tp_file_ready_cb (GObject *object,
410   GParamSpec *spec, gpointer user_data)
411 {
412   EmpathyDispatchOperation *self = EMPATHY_DISPATCH_OPERATION (user_data);
413   EmpathyDispatchOperationPriv *priv = GET_PRIV (self);
414
415   if (!empathy_tp_file_is_ready (EMPATHY_TP_FILE (priv->channel_wrapper)))
416     return;
417
418   g_signal_handler_disconnect (priv->channel_wrapper, priv->ready_handler);
419   priv->ready_handler = 0;
420
421   empathy_dispatch_operation_set_status (self,
422     EMPATHY_DISPATCHER_OPERATION_STATE_PENDING);
423 }
424
425 static void
426 empathy_dispatch_operation_channel_ready_cb (TpChannel *channel,
427   const GError *error, gpointer user_data)
428 {
429   EmpathyDispatchOperation *self = EMPATHY_DISPATCH_OPERATION (user_data);
430   EmpathyDispatchOperationPriv *priv = GET_PRIV (self);
431   GQuark channel_type;
432
433   /* The error will be handled in empathy_dispatch_operation_invalidated */
434   if (error != NULL)
435     return;
436
437   g_assert (channel == priv->channel);
438
439   /* If the channel wrapper is defined, we assume it's ready */
440   if (priv->channel_wrapper != NULL)
441     goto ready;
442
443   channel_type = tp_channel_get_channel_type_id (channel);
444
445   if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_TEXT)
446     {
447       EmpathyTpChat *chat= empathy_tp_chat_new (channel);
448       priv->channel_wrapper = G_OBJECT (chat);
449
450       if (!empathy_tp_chat_is_ready (chat))
451         {
452           priv->ready_handler = g_signal_connect (chat, "notify::ready",
453             G_CALLBACK (empathy_dispatcher_operation_tp_chat_ready_cb), self);
454           return;
455         }
456     }
457   else if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_STREAMED_MEDIA)
458     {
459       EmpathyTpCall *call = empathy_tp_call_new (channel);
460       priv->channel_wrapper = G_OBJECT (call);
461     }
462   else if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_FILE_TRANSFER)
463     {
464       EmpathyTpFile *file = empathy_tp_file_new (channel);
465       priv->channel_wrapper = G_OBJECT (file);
466
467       if (!empathy_tp_file_is_ready (file))
468         {
469           priv->ready_handler = g_signal_connect (file, "notify::ready",
470             G_CALLBACK (empathy_dispatcher_operation_tp_file_ready_cb), self);
471           return;
472         }
473     }
474
475 ready:
476   empathy_dispatch_operation_set_status (self,
477     EMPATHY_DISPATCHER_OPERATION_STATE_PENDING);
478 }
479
480 EmpathyDispatchOperation *
481 empathy_dispatch_operation_new (TpConnection *connection, TpChannel *channel,
482   EmpathyContact *contact, gboolean incoming)
483 {
484   return empathy_dispatch_operation_new_with_wrapper (connection, channel,
485     contact, incoming, NULL);
486 }
487
488 EmpathyDispatchOperation *
489 empathy_dispatch_operation_new_with_wrapper (TpConnection *connection,
490   TpChannel *channel, EmpathyContact *contact, gboolean incoming,
491   GObject *wrapper)
492 {
493   g_return_val_if_fail (connection != NULL, NULL);
494   g_return_val_if_fail (channel != NULL, NULL);
495
496   return EMPATHY_DISPATCH_OPERATION (
497     g_object_new (EMPATHY_TYPE_DISPATCH_OPERATION,
498       "connection", connection,
499       "channel", channel,
500       "channel-wrapper", wrapper,
501       "contact", contact,
502       "incoming", incoming,
503       NULL));
504 }
505
506 void
507 empathy_dispatch_operation_start (EmpathyDispatchOperation *operation)
508 {
509   EmpathyDispatchOperationPriv *priv;
510
511   g_return_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation));
512
513   priv = GET_PRIV (operation);
514
515   g_return_if_fail (
516     priv->status == EMPATHY_DISPATCHER_OPERATION_STATE_PENDING);
517
518   if (priv->incoming && !priv->approved)
519     empathy_dispatch_operation_set_status (operation,
520       EMPATHY_DISPATCHER_OPERATION_STATE_APPROVING);
521   else
522     empathy_dispatch_operation_set_status (operation,
523       EMPATHY_DISPATCHER_OPERATION_STATE_DISPATCHING);
524 }
525
526 void
527 empathy_dispatch_operation_approve (EmpathyDispatchOperation *operation)
528 {
529   EmpathyDispatchOperationPriv *priv;
530
531   g_return_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation));
532
533   priv = GET_PRIV (operation);
534
535   if (priv->status == EMPATHY_DISPATCHER_OPERATION_STATE_APPROVING)
536     {
537       DEBUG ("Approving operation %s",
538         empathy_dispatch_operation_get_object_path (operation));
539
540       empathy_dispatch_operation_set_status (operation,
541         EMPATHY_DISPATCHER_OPERATION_STATE_DISPATCHING);
542
543       g_signal_emit (operation, signals[APPROVED], 0);
544     }
545   else if (priv->status < EMPATHY_DISPATCHER_OPERATION_STATE_APPROVING)
546     {
547       DEBUG ("Pre-approving operation %s",
548         empathy_dispatch_operation_get_object_path (operation));
549       priv->approved = TRUE;
550     }
551   else
552     {
553       DEBUG (
554         "Ignoring approval for %s as it's already past the approval stage",
555         empathy_dispatch_operation_get_object_path (operation));
556     }
557 }
558
559 /* Returns whether or not the operation was successfully claimed */
560 gboolean
561 empathy_dispatch_operation_claim (EmpathyDispatchOperation *operation)
562 {
563   EmpathyDispatchOperationPriv *priv;
564
565   g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), FALSE);
566
567   priv = GET_PRIV (operation);
568
569   if (priv->status == EMPATHY_DISPATCHER_OPERATION_STATE_CLAIMED)
570     return FALSE;
571
572   empathy_dispatch_operation_set_status (operation,
573     EMPATHY_DISPATCHER_OPERATION_STATE_CLAIMED);
574
575   g_signal_emit (operation, signals[CLAIMED], 0);
576
577   return TRUE;
578 }
579
580 TpConnection *
581 empathy_dispatch_operation_get_tp_connection (
582   EmpathyDispatchOperation *operation)
583 {
584   EmpathyDispatchOperationPriv *priv;
585
586   g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), NULL);
587
588   priv = GET_PRIV (operation);
589
590   return g_object_ref (priv->connection);
591 }
592
593 TpChannel *
594 empathy_dispatch_operation_get_channel (EmpathyDispatchOperation *operation)
595 {
596   EmpathyDispatchOperationPriv *priv;
597
598   g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), NULL);
599
600   priv = GET_PRIV (operation);
601
602   return priv->channel;
603 }
604
605 GObject *
606 empathy_dispatch_operation_get_channel_wrapper (
607   EmpathyDispatchOperation *operation)
608 {
609   EmpathyDispatchOperationPriv *priv;
610
611   g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), NULL);
612
613   priv = GET_PRIV (operation);
614
615   return priv->channel_wrapper;
616 }
617
618 const gchar *
619 empathy_dispatch_operation_get_channel_type (
620   EmpathyDispatchOperation *operation)
621 {
622   EmpathyDispatchOperationPriv *priv;
623
624   g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), NULL);
625
626   priv = GET_PRIV (operation);
627
628   return tp_channel_get_channel_type (priv->channel);
629 }
630
631 GQuark
632 empathy_dispatch_operation_get_channel_type_id (
633   EmpathyDispatchOperation *operation)
634 {
635   EmpathyDispatchOperationPriv *priv;
636
637   g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), 0);
638
639   priv = GET_PRIV (operation);
640
641   return tp_channel_get_channel_type_id (priv->channel);
642 }
643
644 const gchar *
645 empathy_dispatch_operation_get_object_path (
646   EmpathyDispatchOperation *operation)
647 {
648   EmpathyDispatchOperationPriv *priv;
649
650   g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), NULL);
651
652   priv = GET_PRIV (operation);
653
654   return tp_proxy_get_object_path (TP_PROXY (priv->channel));
655 }
656
657 EmpathyDispatchOperationState
658 empathy_dispatch_operation_get_status (EmpathyDispatchOperation *operation)
659 {
660   EmpathyDispatchOperationPriv *priv;
661
662   g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation),
663     EMPATHY_DISPATCHER_OPERATION_STATE_PREPARING);
664
665   priv = GET_PRIV (operation);
666
667   return priv->status;
668 }
669
670 gboolean
671 empathy_dispatch_operation_is_incoming (EmpathyDispatchOperation *operation)
672 {
673   EmpathyDispatchOperationPriv *priv;
674
675   g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), FALSE);
676
677   priv = GET_PRIV (operation);
678
679   return priv->incoming;
680 }