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