]> git.0d.be Git - empathy.git/blob - libempathy/empathy-dispatch-operation.c
add myself to AUTHORS
[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   return empathy_dispatch_operation_new_with_wrapper (connection, channel,
499     contact, incoming, NULL);
500 }
501
502 EmpathyDispatchOperation *
503 empathy_dispatch_operation_new_with_wrapper (TpConnection *connection,
504   TpChannel *channel, EmpathyContact *contact, gboolean incoming,
505   GObject *wrapper)
506 {
507   g_return_val_if_fail (connection != NULL, NULL);
508   g_return_val_if_fail (channel != NULL, NULL);
509
510   return EMPATHY_DISPATCH_OPERATION (
511     g_object_new (EMPATHY_TYPE_DISPATCH_OPERATION,
512       "connection", connection,
513       "channel", channel,
514       "channel-wrapper", wrapper,
515       "contact", contact,
516       "incoming", incoming,
517       NULL));
518 }
519
520 void
521 empathy_dispatch_operation_start (EmpathyDispatchOperation *operation)
522 {
523   EmpathyDispatchOperationPriv *priv;
524
525   g_return_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation));
526
527   priv = GET_PRIV (operation);
528
529   g_return_if_fail (
530     priv->status == EMPATHY_DISPATCHER_OPERATION_STATE_PENDING);
531
532   if (priv->incoming && !priv->approved)
533     empathy_dispatch_operation_set_status (operation,
534       EMPATHY_DISPATCHER_OPERATION_STATE_APPROVING);
535   else
536     empathy_dispatch_operation_set_status (operation,
537       EMPATHY_DISPATCHER_OPERATION_STATE_DISPATCHING);
538 }
539
540 void
541 empathy_dispatch_operation_approve (EmpathyDispatchOperation *operation)
542 {
543   EmpathyDispatchOperationPriv *priv;
544
545   g_return_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation));
546
547   priv = GET_PRIV (operation);
548
549   if (priv->status == EMPATHY_DISPATCHER_OPERATION_STATE_APPROVING)
550     {
551       DEBUG ("Approving operation %s",
552         empathy_dispatch_operation_get_object_path (operation));
553
554       empathy_dispatch_operation_set_status (operation,
555         EMPATHY_DISPATCHER_OPERATION_STATE_DISPATCHING);
556
557       g_signal_emit (operation, signals[APPROVED], 0);
558     }
559   else if (priv->status < EMPATHY_DISPATCHER_OPERATION_STATE_APPROVING)
560     {
561       DEBUG ("Pre-approving operation %s",
562         empathy_dispatch_operation_get_object_path (operation));
563       priv->approved = TRUE;
564     }
565   else
566     {
567       DEBUG (
568         "Ignoring approval for %s as it's already past the approval stage",
569         empathy_dispatch_operation_get_object_path (operation));
570     }
571 }
572
573 /* Returns whether or not the operation was successfully claimed */
574 gboolean
575 empathy_dispatch_operation_claim (EmpathyDispatchOperation *operation)
576 {
577   EmpathyDispatchOperationPriv *priv;
578
579   g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), FALSE);
580
581   priv = GET_PRIV (operation);
582
583   if (priv->status == EMPATHY_DISPATCHER_OPERATION_STATE_CLAIMED)
584     return FALSE;
585
586   empathy_dispatch_operation_set_status (operation,
587     EMPATHY_DISPATCHER_OPERATION_STATE_CLAIMED);
588
589   g_signal_emit (operation, signals[CLAIMED], 0);
590
591   return TRUE;
592 }
593
594 TpConnection *
595 empathy_dispatch_operation_get_tp_connection (
596   EmpathyDispatchOperation *operation)
597 {
598   EmpathyDispatchOperationPriv *priv;
599
600   g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), NULL);
601
602   priv = GET_PRIV (operation);
603
604   return priv->connection;
605 }
606
607 TpChannel *
608 empathy_dispatch_operation_get_channel (EmpathyDispatchOperation *operation)
609 {
610   EmpathyDispatchOperationPriv *priv;
611
612   g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), NULL);
613
614   priv = GET_PRIV (operation);
615
616   return priv->channel;
617 }
618
619 GObject *
620 empathy_dispatch_operation_get_channel_wrapper (
621   EmpathyDispatchOperation *operation)
622 {
623   EmpathyDispatchOperationPriv *priv;
624
625   g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), NULL);
626
627   priv = GET_PRIV (operation);
628
629   return priv->channel_wrapper;
630 }
631
632 const gchar *
633 empathy_dispatch_operation_get_channel_type (
634   EmpathyDispatchOperation *operation)
635 {
636   EmpathyDispatchOperationPriv *priv;
637
638   g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), NULL);
639
640   priv = GET_PRIV (operation);
641
642   return tp_channel_get_channel_type (priv->channel);
643 }
644
645 GQuark
646 empathy_dispatch_operation_get_channel_type_id (
647   EmpathyDispatchOperation *operation)
648 {
649   EmpathyDispatchOperationPriv *priv;
650
651   g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), 0);
652
653   priv = GET_PRIV (operation);
654
655   return tp_channel_get_channel_type_id (priv->channel);
656 }
657
658 const gchar *
659 empathy_dispatch_operation_get_object_path (
660   EmpathyDispatchOperation *operation)
661 {
662   EmpathyDispatchOperationPriv *priv;
663
664   g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), NULL);
665
666   priv = GET_PRIV (operation);
667
668   return tp_proxy_get_object_path (TP_PROXY (priv->channel));
669 }
670
671 EmpathyDispatchOperationState
672 empathy_dispatch_operation_get_status (EmpathyDispatchOperation *operation)
673 {
674   EmpathyDispatchOperationPriv *priv;
675
676   g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation),
677     EMPATHY_DISPATCHER_OPERATION_STATE_PREPARING);
678
679   priv = GET_PRIV (operation);
680
681   return priv->status;
682 }
683
684 gboolean
685 empathy_dispatch_operation_is_incoming (EmpathyDispatchOperation *operation)
686 {
687   EmpathyDispatchOperationPriv *priv;
688
689   g_return_val_if_fail (EMPATHY_IS_DISPATCH_OPERATION (operation), FALSE);
690
691   priv = GET_PRIV (operation);
692
693   return priv->incoming;
694 }