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