]> git.0d.be Git - empathy.git/blob - libempathy/empathy-dispatch-operation.c
empathy-dispatch-operation: ensure that the operation stays alive while tp_channel_ca...
[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->channel_wrapper != NULL)
377     g_object_unref (priv->channel_wrapper);
378
379   if (priv->ready_handler != 0)
380     g_signal_handler_disconnect (priv->channel_wrapper,
381       priv->invalidated_handler);
382
383
384   g_signal_handler_disconnect (priv->channel, priv->invalidated_handler);
385   g_object_unref (priv->channel);
386
387
388   if (priv->contact != NULL)
389     g_object_unref (priv->contact);
390
391   if (G_OBJECT_CLASS (empathy_dispatch_operation_parent_class)->dispose)
392     G_OBJECT_CLASS (empathy_dispatch_operation_parent_class)->dispose (object);
393 }
394
395 void
396 empathy_dispatch_operation_finalize (GObject *object)
397 {
398   /* free any data held directly by the object here */
399   G_OBJECT_CLASS (empathy_dispatch_operation_parent_class)->finalize (object);
400 }
401
402 static void
403 empathy_dispatch_operation_set_status (EmpathyDispatchOperation *self,
404   EmpathyDispatchOperationState status)
405 {
406   EmpathyDispatchOperationPriv *priv = GET_PRIV (self);
407
408   g_assert (status >= priv->status);
409
410
411   if (priv->status != status)
412     {
413       DEBUG ("Dispatch operation %s status: %d -> %d",
414         empathy_dispatch_operation_get_object_path (self),
415         priv->status, status);
416
417       priv->status = status;
418       g_object_notify (G_OBJECT (self), "status");
419
420       if (status == EMPATHY_DISPATCHER_OPERATION_STATE_PENDING)
421         g_signal_emit (self, signals[READY], 0);
422     }
423 }
424
425 static void
426 empathy_dispatcher_operation_tp_chat_ready_cb (GObject *object,
427   GParamSpec *spec, gpointer user_data)
428 {
429   EmpathyDispatchOperation *self = EMPATHY_DISPATCH_OPERATION (user_data);
430   EmpathyDispatchOperationPriv *priv = GET_PRIV (self);
431
432   if (!empathy_tp_chat_is_ready (EMPATHY_TP_CHAT (priv->channel_wrapper)))
433     return;
434
435   g_signal_handler_disconnect (priv->channel_wrapper, priv->ready_handler);
436   priv->ready_handler = 0;
437
438   empathy_dispatch_operation_set_status (self,
439     EMPATHY_DISPATCHER_OPERATION_STATE_PENDING);
440 }
441
442 static void
443 empathy_dispatch_operation_channel_ready_cb (TpChannel *channel,
444   const GError *error, gpointer user_data)
445 {
446   EmpathyDispatchOperation *self = EMPATHY_DISPATCH_OPERATION (user_data);
447   EmpathyDispatchOperationPriv *priv = GET_PRIV (self);
448   GQuark channel_type;
449
450   /* The error will be handled in empathy_dispatch_operation_invalidated */
451   if (error != NULL)
452     goto out;
453
454   g_assert (channel == priv->channel);
455
456   if (priv->status >= EMPATHY_DISPATCHER_OPERATION_STATE_CLAIMED)
457     /* no point to get more information */
458     goto out;
459
460   /* If the channel wrapper is defined, we assume it's ready */
461   if (priv->channel_wrapper != NULL)
462     goto ready;
463
464   channel_type = tp_channel_get_channel_type_id (channel);
465
466   if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_TEXT)
467     {
468       EmpathyTpChat *chat= empathy_tp_chat_new (channel);
469       priv->channel_wrapper = G_OBJECT (chat);
470
471       if (!empathy_tp_chat_is_ready (chat))
472         {
473           priv->ready_handler = g_signal_connect (chat, "notify::ready",
474             G_CALLBACK (empathy_dispatcher_operation_tp_chat_ready_cb), self);
475           goto out;
476         }
477     }
478   else if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_STREAMED_MEDIA)
479     {
480       EmpathyTpCall *call = empathy_tp_call_new (channel);
481       priv->channel_wrapper = G_OBJECT (call);
482     }
483   else if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_FILE_TRANSFER)
484     {
485        EmpathyTpFile *file = empathy_tp_file_new (channel, priv->incoming);
486        priv->channel_wrapper = G_OBJECT (file);
487     }
488
489 ready:
490   empathy_dispatch_operation_set_status (self,
491     EMPATHY_DISPATCHER_OPERATION_STATE_PENDING);
492 out:
493   g_object_unref (self);
494 }
495
496 EmpathyDispatchOperation *
497 empathy_dispatch_operation_new (TpConnection *connection, TpChannel *channel,
498   EmpathyContact *contact, gboolean incoming)
499 {
500   return empathy_dispatch_operation_new_with_wrapper (connection, channel,
501     contact, incoming, NULL);
502 }
503
504 EmpathyDispatchOperation *
505 empathy_dispatch_operation_new_with_wrapper (TpConnection *connection,
506   TpChannel *channel, EmpathyContact *contact, gboolean incoming,
507   GObject *wrapper)
508 {
509   g_return_val_if_fail (connection != NULL, NULL);
510   g_return_val_if_fail (channel != NULL, NULL);
511
512   return EMPATHY_DISPATCH_OPERATION (
513     g_object_new (EMPATHY_TYPE_DISPATCH_OPERATION,
514       "connection", connection,
515       "channel", channel,
516       "channel-wrapper", wrapper,
517       "contact", contact,
518       "incoming", incoming,
519       NULL));
520 }
521
522 void
523 empathy_dispatch_operation_start (EmpathyDispatchOperation *operation)
524 {
525   EmpathyDispatchOperationPriv *priv;
526
527   g_return_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation));
528
529   priv = GET_PRIV (operation);
530
531   g_return_if_fail (
532     priv->status == EMPATHY_DISPATCHER_OPERATION_STATE_PENDING);
533
534   if (priv->incoming && !priv->approved)
535     empathy_dispatch_operation_set_status (operation,
536       EMPATHY_DISPATCHER_OPERATION_STATE_APPROVING);
537   else
538     empathy_dispatch_operation_set_status (operation,
539       EMPATHY_DISPATCHER_OPERATION_STATE_DISPATCHING);
540 }
541
542 void
543 empathy_dispatch_operation_approve (EmpathyDispatchOperation *operation)
544 {
545   EmpathyDispatchOperationPriv *priv;
546
547   g_return_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation));
548
549   priv = GET_PRIV (operation);
550
551   if (priv->status == EMPATHY_DISPATCHER_OPERATION_STATE_APPROVING)
552     {
553       DEBUG ("Approving operation %s",
554         empathy_dispatch_operation_get_object_path (operation));
555
556       empathy_dispatch_operation_set_status (operation,
557         EMPATHY_DISPATCHER_OPERATION_STATE_DISPATCHING);
558
559       g_signal_emit (operation, signals[APPROVED], 0);
560     }
561   else if (priv->status < EMPATHY_DISPATCHER_OPERATION_STATE_APPROVING)
562     {
563       DEBUG ("Pre-approving operation %s",
564         empathy_dispatch_operation_get_object_path (operation));
565       priv->approved = TRUE;
566     }
567   else
568     {
569       DEBUG (
570         "Ignoring approval for %s as it's already past the approval stage",
571         empathy_dispatch_operation_get_object_path (operation));
572     }
573 }
574
575 /* Returns whether or not the operation was successfully claimed */
576 gboolean
577 empathy_dispatch_operation_claim (EmpathyDispatchOperation *operation)
578 {
579   EmpathyDispatchOperationPriv *priv;
580
581   g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), FALSE);
582
583   priv = GET_PRIV (operation);
584
585   if (priv->status == EMPATHY_DISPATCHER_OPERATION_STATE_CLAIMED)
586     return FALSE;
587
588   empathy_dispatch_operation_set_status (operation,
589     EMPATHY_DISPATCHER_OPERATION_STATE_CLAIMED);
590
591   g_signal_emit (operation, signals[CLAIMED], 0);
592
593   return TRUE;
594 }
595
596 TpConnection *
597 empathy_dispatch_operation_get_tp_connection (
598   EmpathyDispatchOperation *operation)
599 {
600   EmpathyDispatchOperationPriv *priv;
601
602   g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), NULL);
603
604   priv = GET_PRIV (operation);
605
606   return priv->connection;
607 }
608
609 TpChannel *
610 empathy_dispatch_operation_get_channel (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;
619 }
620
621 GObject *
622 empathy_dispatch_operation_get_channel_wrapper (
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 priv->channel_wrapper;
632 }
633
634 const gchar *
635 empathy_dispatch_operation_get_channel_type (
636   EmpathyDispatchOperation *operation)
637 {
638   EmpathyDispatchOperationPriv *priv;
639
640   g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), NULL);
641
642   priv = GET_PRIV (operation);
643
644   return tp_channel_get_channel_type (priv->channel);
645 }
646
647 GQuark
648 empathy_dispatch_operation_get_channel_type_id (
649   EmpathyDispatchOperation *operation)
650 {
651   EmpathyDispatchOperationPriv *priv;
652
653   g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), 0);
654
655   priv = GET_PRIV (operation);
656
657   return tp_channel_get_channel_type_id (priv->channel);
658 }
659
660 const gchar *
661 empathy_dispatch_operation_get_object_path (
662   EmpathyDispatchOperation *operation)
663 {
664   EmpathyDispatchOperationPriv *priv;
665
666   g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), NULL);
667
668   priv = GET_PRIV (operation);
669
670   return tp_proxy_get_object_path (TP_PROXY (priv->channel));
671 }
672
673 EmpathyDispatchOperationState
674 empathy_dispatch_operation_get_status (EmpathyDispatchOperation *operation)
675 {
676   EmpathyDispatchOperationPriv *priv;
677
678   g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation),
679     EMPATHY_DISPATCHER_OPERATION_STATE_PREPARING);
680
681   priv = GET_PRIV (operation);
682
683   return priv->status;
684 }
685
686 gboolean
687 empathy_dispatch_operation_is_incoming (EmpathyDispatchOperation *operation)
688 {
689   EmpathyDispatchOperationPriv *priv;
690
691   g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), FALSE);
692
693   priv = GET_PRIV (operation);
694
695   return priv->incoming;
696 }