1 /*
2 * Context objects for TpBaseClient calls
3 *
4 * Copyright © 2010 Collabora Ltd.
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 * SECTION:observe-channels-context
23 * @title: TpObserveChannelsContext
24 * @short_description: context of a Observer.ObserveChannels() call
25 *
26 * Object used to represent the context of a Observer.ObserveChannels()
27 * D-Bus call on a #TpBaseClient.
28 */
29
30 /**
31 * TpObserveChannelsContext:
32 *
33 * Data structure representing the context of a Observer.ObserveChannels()
34 * call.
35 *
36 * Since: 0.11.5
37 */
38
39 /**
40 * TpObserveChannelsContextClass:
41 *
42 * The class of a #TpObserveChannelsContext.
43 *
44 * Since: 0.11.5
45 */
46
47 #include "config.h"
48
49 #include "telepathy-glib/observe-channels-context-internal.h"
50 #include "telepathy-glib/observe-channels-context.h"
51
52 #include <telepathy-glib/channel.h>
53 #include <telepathy-glib/channel-request.h>
54 #include <telepathy-glib/dbus.h>
55 #include <telepathy-glib/gtypes.h>
56 #include <telepathy-glib/util-internal.h>
57
58 #define DEBUG_FLAG TP_DEBUG_CLIENT
59 #include "telepathy-glib/debug-internal.h"
60
61 struct _TpObserveChannelsContextClass {
62 /*<private>*/
63 GObjectClass parent_class;
64 };
65
66 G_DEFINE_TYPE(TpObserveChannelsContext, tp_observe_channels_context,
67 G_TYPE_OBJECT)
68
69 enum {
70 PROP_ACCOUNT = 1,
71 PROP_CONNECTION,
72 PROP_CHANNELS,
73 PROP_DISPATCH_OPERATION,
74 PROP_REQUESTS,
75 PROP_OBSERVER_INFO,
76 PROP_DBUS_CONTEXT,
77 N_PROPS
78 };
79
80 struct _TpObserveChannelsContextPrivate
81 {
82 TpObserveChannelsContextState state;
83 GSimpleAsyncResult *result;
84 DBusGMethodInvocation *dbus_context;
85
86 /* Number of calls we are waiting they return. Once they have all returned
87 * the context is considered as prepared */
88 guint num_pending;
89 };
90
91 static void
tp_observe_channels_context_init(TpObserveChannelsContext * self)92 tp_observe_channels_context_init (TpObserveChannelsContext *self)
93 {
94 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
95 TP_TYPE_OBSERVE_CHANNELS_CONTEXT, TpObserveChannelsContextPrivate);
96
97 self->priv->state = TP_OBSERVE_CHANNELS_CONTEXT_STATE_NONE;
98 }
99
100 static void
tp_observe_channels_context_dispose(GObject * object)101 tp_observe_channels_context_dispose (GObject *object)
102 {
103 TpObserveChannelsContext *self = TP_OBSERVE_CHANNELS_CONTEXT (object);
104 void (*dispose) (GObject *) =
105 G_OBJECT_CLASS (tp_observe_channels_context_parent_class)->dispose;
106
107 if (self->priv->state == TP_OBSERVE_CHANNELS_CONTEXT_STATE_NONE ||
108 self->priv->state == TP_OBSERVE_CHANNELS_CONTEXT_STATE_DELAYED)
109 {
110 GError error = { TP_ERROR, TP_ERROR_NOT_IMPLEMENTED,
111 "Disposing the TpObserveChannelsContext" };
112
113 WARNING ("Disposing a context in the %s state",
114 self->priv->state == TP_OBSERVE_CHANNELS_CONTEXT_STATE_NONE ?
115 "none": "delayed");
116
117 tp_observe_channels_context_fail (self, &error);
118 }
119
120 if (self->account != NULL)
121 {
122 g_object_unref (self->account);
123 self->account = NULL;
124 }
125
126 if (self->connection != NULL)
127 {
128 g_object_unref (self->connection);
129 self->connection = NULL;
130 }
131
132 if (self->channels != NULL)
133 {
134 g_ptr_array_unref (self->channels);
135 self->channels = NULL;
136 }
137
138 if (self->dispatch_operation != NULL)
139 {
140 g_object_unref (self->dispatch_operation);
141 self->dispatch_operation = NULL;
142 }
143
144 if (self->requests != NULL)
145 {
146 g_ptr_array_foreach (self->requests, (GFunc) g_object_unref, NULL);
147 g_ptr_array_unref (self->requests);
148 self->requests = NULL;
149 }
150
151 if (self->observer_info != NULL)
152 {
153 g_hash_table_unref (self->observer_info);
154 self->observer_info = NULL;
155 }
156
157 if (self->priv->result != NULL)
158 {
159 g_object_unref (self->priv->result);
160 self->priv->result = NULL;
161 }
162
163 if (dispose != NULL)
164 dispose (object);
165 }
166
167 static void
tp_observe_channels_context_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)168 tp_observe_channels_context_get_property (GObject *object,
169 guint property_id,
170 GValue *value,
171 GParamSpec *pspec)
172 {
173 TpObserveChannelsContext *self = TP_OBSERVE_CHANNELS_CONTEXT (object);
174
175 switch (property_id)
176 {
177 case PROP_ACCOUNT:
178 g_value_set_object (value, self->account);
179 break;
180 case PROP_CONNECTION:
181 g_value_set_object (value, self->connection);
182 break;
183 case PROP_CHANNELS:
184 g_value_set_boxed (value, self->channels);
185 break;
186 case PROP_DISPATCH_OPERATION:
187 g_value_set_object (value, self->dispatch_operation);
188 break;
189 case PROP_REQUESTS:
190 g_value_set_boxed (value, self->requests);
191 break;
192 case PROP_OBSERVER_INFO:
193 g_value_set_boxed (value, self->observer_info);
194 break;
195 default:
196 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
197 break;
198 }
199 }
200
201 static void
tp_observe_channels_context_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)202 tp_observe_channels_context_set_property (GObject *object,
203 guint property_id,
204 const GValue *value,
205 GParamSpec *pspec)
206 {
207 TpObserveChannelsContext *self = TP_OBSERVE_CHANNELS_CONTEXT (object);
208
209 switch (property_id)
210 {
211 case PROP_ACCOUNT:
212 self->account = g_value_dup_object (value);
213 break;
214 case PROP_CONNECTION:
215 self->connection = g_value_dup_object (value);
216 break;
217 case PROP_CHANNELS:
218 self->channels = g_value_dup_boxed (value);
219 break;
220 case PROP_DISPATCH_OPERATION:
221 self->dispatch_operation = g_value_dup_object (value);
222 break;
223 case PROP_REQUESTS:
224 self->requests = g_value_dup_boxed (value);
225 g_ptr_array_foreach (self->requests, (GFunc) g_object_ref, NULL);
226 break;
227 case PROP_DBUS_CONTEXT:
228 self->priv->dbus_context = g_value_get_pointer (value);
229 break;
230 case PROP_OBSERVER_INFO:
231 self->observer_info = g_value_dup_boxed (value);
232 break;
233 default:
234 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
235 break;
236 }
237 }
238
239 static void
tp_observe_channels_context_constructed(GObject * object)240 tp_observe_channels_context_constructed (GObject *object)
241 {
242 TpObserveChannelsContext *self = TP_OBSERVE_CHANNELS_CONTEXT (object);
243 void (*chain_up) (GObject *) =
244 ((GObjectClass *) tp_observe_channels_context_parent_class)->constructed;
245
246 if (chain_up != NULL)
247 chain_up (object);
248
249 g_assert (self->account != NULL);
250 g_assert (self->connection != NULL);
251 g_assert (self->channels != NULL);
252 g_assert (self->requests != NULL);
253 g_assert (self->observer_info != NULL);
254 g_assert (self->priv->dbus_context != NULL);
255
256 /* self->dispatch_operation may be NULL (channels were requested) */
257 }
258
259 static void
tp_observe_channels_context_class_init(TpObserveChannelsContextClass * cls)260 tp_observe_channels_context_class_init (TpObserveChannelsContextClass *cls)
261 {
262 GObjectClass *object_class = G_OBJECT_CLASS (cls);
263 GParamSpec *param_spec;
264
265 g_type_class_add_private (cls, sizeof (TpObserveChannelsContextPrivate));
266
267 object_class->get_property = tp_observe_channels_context_get_property;
268 object_class->set_property = tp_observe_channels_context_set_property;
269 object_class->constructed = tp_observe_channels_context_constructed;
270 object_class->dispose = tp_observe_channels_context_dispose;
271
272 /**
273 * TpObserveChannelsContext:account:
274 *
275 * A #TpAccount object representing the Account that has been passed to
276 * ObserveChannels.
277 * Read-only except during construction.
278 *
279 * This property can't be %NULL.
280 *
281 * Since: 0.11.5
282 */
283 param_spec = g_param_spec_object ("account", "TpAccount",
284 "The TpAccount that has been passed to ObserveChannels",
285 TP_TYPE_ACCOUNT,
286 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
287 g_object_class_install_property (object_class, PROP_ACCOUNT,
288 param_spec);
289
290 /**
291 * TpObserveChannelsContext:connection:
292 *
293 * A #TpConnection object representing the Connection that has been passed
294 * to ObserveChannels.
295 * Read-only except during construction.
296 *
297 * This property can't be %NULL.
298 *
299 * Since: 0.11.5
300 */
301 param_spec = g_param_spec_object ("connection", "TpConnection",
302 "The TpConnection that has been passed to ObserveChannels",
303 TP_TYPE_CONNECTION,
304 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
305 g_object_class_install_property (object_class, PROP_CONNECTION,
306 param_spec);
307
308 /**
309 * TpObserveChannelsContext:channels:
310 *
311 * A #GPtrArray containing #TpChannel objects representing the channels
312 * that have been passed to ObserveChannels.
313 * Read-only except during construction.
314 *
315 * This property can't be %NULL.
316 *
317 * Since: 0.11.5
318 */
319 param_spec = g_param_spec_boxed ("channels", "GPtrArray of TpChannel",
320 "The TpChannels that have been passed to ObserveChannels",
321 G_TYPE_PTR_ARRAY,
322 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
323 g_object_class_install_property (object_class, PROP_CHANNELS,
324 param_spec);
325
326 /**
327 * TpObserveChannelsContext:dispatch-operation:
328 *
329 * A #TpChannelDispatchOperation object representing the
330 * ChannelDispatchOperation that has been passed to ObserveChannels,
331 * or %NULL if none has been passed.
332 * Read-only except during construction.
333 *
334 * Since: 0.11.5
335 */
336 param_spec = g_param_spec_object ("dispatch-operation",
337 "TpChannelDispatchOperation",
338 "The TpChannelDispatchOperation that has been passed to ObserveChannels",
339 TP_TYPE_CHANNEL_DISPATCH_OPERATION,
340 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
341 g_object_class_install_property (object_class, PROP_DISPATCH_OPERATION,
342 param_spec);
343
344 /**
345 * TpObserveChannelsContext:requests:
346 *
347 * A #GPtrArray containing #TpChannelRequest objects representing the
348 * requests that have been passed to ObserveChannels.
349 * Read-only except during construction.
350 *
351 * This property can't be %NULL.
352 *
353 * Since: 0.11.5
354 */
355 param_spec = g_param_spec_boxed ("requests", "GPtrArray of TpChannelRequest",
356 "The TpChannelRequest that have been passed to ObserveChannels",
357 G_TYPE_PTR_ARRAY,
358 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
359 g_object_class_install_property (object_class, PROP_REQUESTS,
360 param_spec);
361
362 /**
363 * TpObserveChannelsContext:dbus-context: (skip)
364 *
365 * The #DBusGMethodInvocation representing the D-Bus context of the
366 * ObserveChannels call.
367 * Can only be written during construction.
368 *
369 * Since: 0.11.5
370 */
371 param_spec = g_param_spec_pointer ("dbus-context", "D-Bus context",
372 "The DBusGMethodInvocation associated with the ObserveChannels call",
373 G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
374 g_object_class_install_property (object_class, PROP_DBUS_CONTEXT,
375 param_spec);
376
377 /**
378 * TpObserveChannelsContext:observer-info:
379 *
380 * A #GHashTable where the keys are string and values are GValue instances.
381 * It represents the Observer_Info hash table that has been passed to
382 * ObserveChannels.
383 * It's recommended to use high-level method such as
384 * tp_observe_channels_context_is_recovering() to access to its content.
385 *
386 * This property can't be %NULL.
387 *
388 * Since: 0.11.5
389 */
390 param_spec = g_param_spec_boxed ("observer-info", "Observer info",
391 "The Observer_Info that has been passed to ObserveChannels",
392 TP_HASH_TYPE_STRING_VARIANT_MAP,
393 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
394 g_object_class_install_property (object_class, PROP_OBSERVER_INFO,
395 param_spec);
396 }
397
398 TpObserveChannelsContext *
_tp_observe_channels_context_new(TpAccount * account,TpConnection * connection,GPtrArray * channels,TpChannelDispatchOperation * dispatch_operation,GPtrArray * requests,GHashTable * observer_info,DBusGMethodInvocation * dbus_context)399 _tp_observe_channels_context_new (
400 TpAccount *account,
401 TpConnection *connection,
402 GPtrArray *channels,
403 TpChannelDispatchOperation *dispatch_operation,
404 GPtrArray *requests,
405 GHashTable *observer_info,
406 DBusGMethodInvocation *dbus_context)
407 {
408 return g_object_new (TP_TYPE_OBSERVE_CHANNELS_CONTEXT,
409 "account", account,
410 "connection", connection,
411 "channels", channels,
412 "dispatch-operation", dispatch_operation,
413 "requests", requests,
414 "observer-info", observer_info,
415 "dbus-context", dbus_context,
416 NULL);
417 }
418
419 /**
420 * tp_observe_channels_context_accept:
421 * @self: a #TpObserveChannelsContext
422 *
423 * Called by #TpBaseClientClassObserveChannelsImpl when it's done so the D-Bus
424 * method can return.
425 *
426 * Since: 0.11.5
427 */
428 void
tp_observe_channels_context_accept(TpObserveChannelsContext * self)429 tp_observe_channels_context_accept (TpObserveChannelsContext *self)
430 {
431 g_return_if_fail (self->priv->state == TP_OBSERVE_CHANNELS_CONTEXT_STATE_NONE
432 || self->priv->state == TP_OBSERVE_CHANNELS_CONTEXT_STATE_DELAYED);
433 g_return_if_fail (self->priv->dbus_context != NULL);
434
435 self->priv->state = TP_OBSERVE_CHANNELS_CONTEXT_STATE_DONE;
436 dbus_g_method_return (self->priv->dbus_context);
437
438 self->priv->dbus_context = NULL;
439 }
440
441 /**
442 * tp_observe_channels_context_fail:
443 * @self: a #TpObserveChannelsContext
444 * @error: the error to return from the method
445 *
446 * Called by #TpBaseClientClassObserveChannelsImpl to raise a D-Bus error.
447 *
448 * Since: 0.11.5
449 */
450 void
tp_observe_channels_context_fail(TpObserveChannelsContext * self,const GError * error)451 tp_observe_channels_context_fail (TpObserveChannelsContext *self,
452 const GError *error)
453 {
454 g_return_if_fail (self->priv->state == TP_OBSERVE_CHANNELS_CONTEXT_STATE_NONE
455 || self->priv->state == TP_OBSERVE_CHANNELS_CONTEXT_STATE_DELAYED);
456 g_return_if_fail (self->priv->dbus_context != NULL);
457
458 self->priv->state = TP_OBSERVE_CHANNELS_CONTEXT_STATE_FAILED;
459 dbus_g_method_return_error (self->priv->dbus_context, error);
460
461 self->priv->dbus_context = NULL;
462 }
463
464 /**
465 * tp_observe_channels_context_delay:
466 * @self: a #TpObserveChannelsContext
467 *
468 * Called by #TpBaseClientClassObserveChannelsImpl to indicate that it
469 * implements the method in an async way. The caller must take a reference
470 * to the #TpObserveChannelsContext before calling this function, and
471 * is responsible for calling either tp_observe_channels_context_accept() or
472 * tp_observe_channels_context_fail() later.
473 *
474 * Since: 0.11.5
475 */
476 void
tp_observe_channels_context_delay(TpObserveChannelsContext * self)477 tp_observe_channels_context_delay (TpObserveChannelsContext *self)
478 {
479 g_return_if_fail (self->priv->state ==
480 TP_OBSERVE_CHANNELS_CONTEXT_STATE_NONE);
481
482 self->priv->state = TP_OBSERVE_CHANNELS_CONTEXT_STATE_DELAYED;
483 }
484
485 /**
486 * tp_observe_channels_context_is_recovering:
487 * @self: a #TpObserveChannelsContext
488 *
489 * If this call to ObserveChannels is for channels that already
490 * existed before this observer started (because the observer used
491 * tp_base_client_set_observer_recover()), return %TRUE.
492 *
493 * In most cases, the result is %FALSE.
494 *
495 * Returns: %TRUE for pre-existing channels, %FALSE for new channels
496 *
497 * Since: 0.11.5
498 */
499 gboolean
tp_observe_channels_context_is_recovering(TpObserveChannelsContext * self)500 tp_observe_channels_context_is_recovering (TpObserveChannelsContext *self)
501 {
502 /* tp_asv_get_boolean returns FALSE if the key is not set which is what we
503 * want */
504 return tp_asv_get_boolean (self->observer_info, "recovering", NULL);
505 }
506
507 TpObserveChannelsContextState
_tp_observe_channels_context_get_state(TpObserveChannelsContext * self)508 _tp_observe_channels_context_get_state (
509 TpObserveChannelsContext *self)
510 {
511 return self->priv->state;
512 }
513
514 static gboolean
context_is_prepared(TpObserveChannelsContext * self)515 context_is_prepared (TpObserveChannelsContext *self)
516 {
517 return self->priv->num_pending == 0;
518 }
519
520 static void
context_check_prepare(TpObserveChannelsContext * self)521 context_check_prepare (TpObserveChannelsContext *self)
522 {
523 if (!context_is_prepared (self))
524 return;
525
526 /* Context is prepared */
527 g_simple_async_result_complete (self->priv->result);
528
529 g_object_unref (self->priv->result);
530 self->priv->result = NULL;
531 }
532
533 static void
cdo_prepare_cb(GObject * source,GAsyncResult * result,gpointer user_data)534 cdo_prepare_cb (GObject *source,
535 GAsyncResult *result,
536 gpointer user_data)
537 {
538 TpObserveChannelsContext *self = user_data;
539 GError *error = NULL;
540
541 if (self->priv->result == NULL)
542 goto out;
543
544 if (!tp_proxy_prepare_finish (source, result, &error))
545 {
546 DEBUG ("Failed to prepare ChannelDispatchOperation: %s", error->message);
547
548 g_error_free (error);
549 }
550
551 self->priv->num_pending--;
552 context_check_prepare (self);
553
554 out:
555 g_object_unref (self);
556 }
557
558 static void
account_prepare_cb(GObject * source,GAsyncResult * result,gpointer user_data)559 account_prepare_cb (GObject *source,
560 GAsyncResult *result,
561 gpointer user_data)
562 {
563 TpObserveChannelsContext *self = user_data;
564 GError *error = NULL;
565
566 if (self->priv->result == NULL)
567 goto out;
568
569 if (!tp_proxy_prepare_finish (source, result, &error))
570 {
571 DEBUG ("Failed to prepare account: %s", error->message);
572 g_error_free (error);
573 }
574
575 self->priv->num_pending--;
576 context_check_prepare (self);
577
578 out:
579 g_object_unref (self);
580 }
581
582 static void
conn_prepare_cb(GObject * source,GAsyncResult * result,gpointer user_data)583 conn_prepare_cb (GObject *source,
584 GAsyncResult *result,
585 gpointer user_data)
586 {
587 TpObserveChannelsContext *self = user_data;
588 GError *error = NULL;
589
590 if (self->priv->result == NULL)
591 goto out;
592
593 if (!tp_proxy_prepare_finish (source, result, &error))
594 {
595 DEBUG ("Failed to prepare connection: %s", error->message);
596 g_error_free (error);
597 }
598
599 self->priv->num_pending--;
600 context_check_prepare (self);
601
602 out:
603 g_object_unref (self);
604 }
605
606 static void
occ_channel_prepare_cb(GObject * source,GAsyncResult * result,gpointer user_data)607 occ_channel_prepare_cb (GObject *source,
608 GAsyncResult *result,
609 gpointer user_data)
610 {
611 TpObserveChannelsContext *self = user_data;
612 GError *error = NULL;
613
614 if (self->priv->result == NULL)
615 goto out;
616
617 if (!tp_proxy_prepare_finish (source, result, &error))
618 {
619 DEBUG ("Failed to prepare channel: %s", error->message);
620 g_error_free (error);
621 }
622
623 self->priv->num_pending--;
624 context_check_prepare (self);
625
626 out:
627 g_object_unref (self);
628 }
629
630 static void
context_prepare(TpObserveChannelsContext * self,const GQuark * account_features,const GQuark * connection_features,const GQuark * channel_features)631 context_prepare (TpObserveChannelsContext *self,
632 const GQuark *account_features,
633 const GQuark *connection_features,
634 const GQuark *channel_features)
635 {
636 GQuark cdo_features[] = { TP_CHANNEL_DISPATCH_OPERATION_FEATURE_CORE, 0 };
637 guint i;
638
639 self->priv->num_pending = 2;
640
641 tp_proxy_prepare_async (self->account, account_features,
642 account_prepare_cb, g_object_ref (self));
643
644 tp_proxy_prepare_async (self->connection, connection_features,
645 conn_prepare_cb, g_object_ref (self));
646
647 if (self->dispatch_operation != NULL)
648 {
649 self->priv->num_pending++;
650 tp_proxy_prepare_async (self->dispatch_operation, cdo_features,
651 cdo_prepare_cb, g_object_ref (self));
652 }
653
654 for (i = 0; i < self->channels->len; i++)
655 {
656 TpChannel *channel = g_ptr_array_index (self->channels, i);
657
658 self->priv->num_pending++;
659
660 tp_proxy_prepare_async (channel, channel_features,
661 occ_channel_prepare_cb, g_object_ref (self));
662 }
663 }
664
665 void
_tp_observe_channels_context_prepare_async(TpObserveChannelsContext * self,const GQuark * account_features,const GQuark * connection_features,const GQuark * channel_features,GAsyncReadyCallback callback,gpointer user_data)666 _tp_observe_channels_context_prepare_async (TpObserveChannelsContext *self,
667 const GQuark *account_features,
668 const GQuark *connection_features,
669 const GQuark *channel_features,
670 GAsyncReadyCallback callback,
671 gpointer user_data)
672 {
673 g_return_if_fail (TP_IS_OBSERVE_CHANNELS_CONTEXT (self));
674 /* This is only used once, by TpBaseClient, so for simplicity, we only
675 * allow one asynchronous preparation */
676 g_return_if_fail (self->priv->result == NULL);
677
678 self->priv->result = g_simple_async_result_new (G_OBJECT (self),
679 callback, user_data, _tp_observe_channels_context_prepare_async);
680
681 context_prepare (self, account_features, connection_features,
682 channel_features);
683 }
684
685 gboolean
_tp_observe_channels_context_prepare_finish(TpObserveChannelsContext * self,GAsyncResult * result,GError ** error)686 _tp_observe_channels_context_prepare_finish (
687 TpObserveChannelsContext *self,
688 GAsyncResult *result,
689 GError **error)
690 {
691 _tp_implement_finish_void (self, _tp_observe_channels_context_prepare_async);
692 }
693
694 /**
695 * tp_observe_channels_context_get_requests:
696 * @self: a #TpObserveChannelsContext
697 *
698 * Return a list of the #TpChannelRequest which have been satisfied by the
699 * channels associated with #self.
700 *
701 * Returns: (transfer full) (element-type TelepathyGLib.ChannelRequest):
702 * a newly allocated #GList of reffed #TpChannelRequest.
703 *
704 * Since: 0.13.14
705 */
706 GList *
tp_observe_channels_context_get_requests(TpObserveChannelsContext * self)707 tp_observe_channels_context_get_requests (TpObserveChannelsContext *self)
708 {
709 GHashTable *request_props;
710
711 request_props = tp_asv_get_boxed (self->observer_info, "request-properties",
712 TP_HASH_TYPE_OBJECT_IMMUTABLE_PROPERTIES_MAP);
713 if (request_props == NULL)
714 return NULL;
715
716 return _tp_create_channel_request_list (
717 tp_proxy_get_factory (self->account), request_props);
718 }
719