1 /*
2 * A factory for TpContacts and plain subclasses of TpProxy
3 *
4 * Copyright © 2011 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:simple-client-factory
23 * @title: TpSimpleClientFactory
24 * @short_description: a factory for #TpContact<!-- -->s and plain subclasses
25 * of #TpProxy
26 * @see_also: #TpAutomaticClientFactory
27 *
28 * This factory constructs various #TpProxy subclasses as well as #TpContact,
29 * which guarantees that at most one instance of those objects will exist for a
30 * given remote object or contact. It also stores the desired features for
31 * contacts and each type of proxy.
32 *
33 * Note that the factory will not prepare the desired features: it is the
34 * caller's responsibility to do so. By default, only core features are
35 * requested.
36 *
37 * Currently supported classes are #TpAccount, #TpConnection,
38 * #TpChannel and #TpContact. Those objects should always be acquired through a
39 * factory or a "larger" object (e.g. getting the #TpConnection from
40 * a #TpAccount), rather than being constructed directly.
41 *
42 * One can subclass #TpSimpleClientFactory and override some of its virtual
43 * methods to construct more specialized objects. See #TpAutomaticClientFactory
44 * for a subclass which automatically constructs subclasses of #TpChannel for
45 * common channel types.
46 *
47 * An application using its own factory subclass would look like this:
48 * |[
49 * int main(int argc, char *argv[])
50 * {
51 * TpSimpleClientFactory *factory;
52 * TpAccountManager *manager;
53 *
54 * factory = my_factory_new ();
55 * manager = tp_account_manager_new_with_factory (factory);
56 * tp_account_manager_set_default (manager);
57 *
58 * ...
59 * tp_proxy_prepare_async (manager, am_features, callback, user_data);
60 * ...
61 * }
62 * ]|
63 *
64 * The call to tp_account_manager_set_default() near the beginning of main()
65 * will ensure that any libraries or plugins which also use Telepathy (and call
66 * tp_account_manager_dup()) will share your #TpAccountManager.
67 *
68 * Since: 0.15.5
69 */
70
71 /**
72 * TpSimpleClientFactory:
73 *
74 * Data structure representing a #TpSimpleClientFactory
75 *
76 * Since: 0.15.5
77 */
78
79 /**
80 * TpSimpleClientFactoryClass:
81 * @parent_class: the parent
82 * @create_account: create a #TpAccount;
83 * see tp_simple_client_factory_ensure_account()
84 * @dup_account_features: implementation of tp_simple_client_factory_dup_account_features()
85 * @create_connection: create a #TpConnection;
86 * see tp_simple_client_factory_ensure_connection()
87 * @dup_connection_features: implementation of
88 * tp_simple_client_factory_dup_connection_features()
89 * @create_channel: create a #TpChannel;
90 * see tp_simple_client_factory_ensure_channel()
91 * @dup_channel_features: implementation of tp_simple_client_factory_dup_channel_features()
92 * @create_contact: create a #TpContact;
93 * see tp_simple_client_factory_ensure_contact()
94 * @dup_contact_features: implementation of tp_simple_client_factory_dup_contact_features()
95 *
96 * The class structure for #TpSimpleClientFactory.
97 *
98 * #TpSimpleClientFactory maintains a cache of previously-constructed proxy
99 * objects, so the implementations of @create_account,
100 * @create_connection, @create_channel, and @create_contact may assume that a
101 * new object should be created when they are called. The default
102 * implementations create unadorned instances of the relevant classes;
103 * subclasses of the factory may choose to create more interesting proxy
104 * subclasses.
105 *
106 * The default implementation of @dup_channel_features returns
107 * #TP_CHANNEL_FEATURE_CORE, plus all features passed to
108 * tp_simple_client_factory_add_channel_features() by the application.
109 * Subclasses may override this method to prepare more interesting features
110 * from subclasses of #TpChannel, for instance. The default implementations of
111 * the other <function>dup_x_features</function> methods behave similarly.
112 *
113 * Since: 0.15.5
114 */
115
116 #include "config.h"
117
118 #include "telepathy-glib/simple-client-factory.h"
119
120 #include <telepathy-glib/util.h>
121
122 #define DEBUG_FLAG TP_DEBUG_CLIENT
123 #include "telepathy-glib/connection-internal.h"
124 #include "telepathy-glib/contact-internal.h"
125 #include "telepathy-glib/debug-internal.h"
126 #include "telepathy-glib/simple-client-factory-internal.h"
127 #include "telepathy-glib/util-internal.h"
128
129 struct _TpSimpleClientFactoryPrivate
130 {
131 TpDBusDaemon *dbus;
132 /* Owned object-path -> weakref to TpProxy */
133 GHashTable *proxy_cache;
134 GArray *desired_account_features;
135 GArray *desired_connection_features;
136 GArray *desired_channel_features;
137 GArray *desired_contact_features;
138 };
139
140 enum
141 {
142 PROP_DBUS_DAEMON = 1,
143 N_PROPS
144 };
145
G_DEFINE_TYPE(TpSimpleClientFactory,tp_simple_client_factory,G_TYPE_OBJECT)146 G_DEFINE_TYPE (TpSimpleClientFactory, tp_simple_client_factory, G_TYPE_OBJECT)
147
148 static void
149 proxy_invalidated_cb (TpProxy *proxy,
150 guint domain,
151 gint code,
152 gchar *message,
153 TpSimpleClientFactory *self)
154 {
155 g_hash_table_remove (self->priv->proxy_cache,
156 tp_proxy_get_object_path (proxy));
157 }
158
159 static void
insert_proxy(TpSimpleClientFactory * self,gpointer proxy)160 insert_proxy (TpSimpleClientFactory *self,
161 gpointer proxy)
162 {
163 if (proxy == NULL)
164 return;
165
166 g_hash_table_insert (self->priv->proxy_cache,
167 (gpointer) tp_proxy_get_object_path (proxy), proxy);
168
169 /* This assume that invalidated signal is emitted from TpProxy dispose. May
170 * change in a future API break? */
171 tp_g_signal_connect_object (proxy, "invalidated",
172 G_CALLBACK (proxy_invalidated_cb), self, 0);
173 }
174
175 static gpointer
lookup_proxy(TpSimpleClientFactory * self,const gchar * object_path)176 lookup_proxy (TpSimpleClientFactory *self,
177 const gchar *object_path)
178 {
179 return g_hash_table_lookup (self->priv->proxy_cache, object_path);
180 }
181
182 void
_tp_simple_client_factory_insert_proxy(TpSimpleClientFactory * self,gpointer proxy)183 _tp_simple_client_factory_insert_proxy (TpSimpleClientFactory *self,
184 gpointer proxy)
185 {
186 g_return_if_fail (lookup_proxy (self,
187 tp_proxy_get_object_path (proxy)) == NULL);
188
189 insert_proxy (self, proxy);
190 }
191
192 static TpAccount *
create_account_impl(TpSimpleClientFactory * self,const gchar * object_path,const GHashTable * immutable_properties G_GNUC_UNUSED,GError ** error)193 create_account_impl (TpSimpleClientFactory *self,
194 const gchar *object_path,
195 const GHashTable *immutable_properties G_GNUC_UNUSED,
196 GError **error)
197 {
198 return _tp_account_new_with_factory (self, self->priv->dbus, object_path,
199 error);
200 }
201
202 static GArray *
dup_account_features_impl(TpSimpleClientFactory * self,TpAccount * account)203 dup_account_features_impl (TpSimpleClientFactory *self,
204 TpAccount *account)
205 {
206 return _tp_quark_array_copy (
207 (GQuark *) self->priv->desired_account_features->data);
208 }
209
210 static TpConnection *
create_connection_impl(TpSimpleClientFactory * self,const gchar * object_path,const GHashTable * immutable_properties G_GNUC_UNUSED,GError ** error)211 create_connection_impl (TpSimpleClientFactory *self,
212 const gchar *object_path,
213 const GHashTable *immutable_properties G_GNUC_UNUSED,
214 GError **error)
215 {
216 return _tp_connection_new_with_factory (self, self->priv->dbus, NULL,
217 object_path, error);
218 }
219
220 static GArray *
dup_connection_features_impl(TpSimpleClientFactory * self,TpConnection * connection)221 dup_connection_features_impl (TpSimpleClientFactory *self,
222 TpConnection *connection)
223 {
224 return _tp_quark_array_copy (
225 (GQuark *) self->priv->desired_connection_features->data);
226 }
227
228 static TpChannel *
create_channel_impl(TpSimpleClientFactory * self,TpConnection * conn,const gchar * object_path,const GHashTable * immutable_properties,GError ** error)229 create_channel_impl (TpSimpleClientFactory *self,
230 TpConnection *conn,
231 const gchar *object_path,
232 const GHashTable *immutable_properties,
233 GError **error)
234 {
235 return _tp_channel_new_with_factory (self, conn, object_path,
236 immutable_properties, error);
237 }
238
239 static GArray *
dup_channel_features_impl(TpSimpleClientFactory * self,TpChannel * channel)240 dup_channel_features_impl (TpSimpleClientFactory *self,
241 TpChannel *channel)
242 {
243 return _tp_quark_array_copy (
244 (GQuark *) self->priv->desired_channel_features->data);
245 }
246
247 static TpContact *
create_contact_impl(TpSimpleClientFactory * self,TpConnection * connection,TpHandle handle,const gchar * identifier)248 create_contact_impl (TpSimpleClientFactory *self,
249 TpConnection *connection,
250 TpHandle handle,
251 const gchar *identifier)
252 {
253 return _tp_contact_new (connection, handle, identifier);
254 }
255
256 static GArray *
dup_contact_features_impl(TpSimpleClientFactory * self,TpConnection * connection)257 dup_contact_features_impl (TpSimpleClientFactory *self,
258 TpConnection *connection)
259 {
260 GArray *array;
261
262 array = g_array_sized_new (FALSE, FALSE, sizeof (TpContactFeature),
263 self->priv->desired_contact_features->len);
264 g_array_append_vals (array, self->priv->desired_contact_features->data,
265 self->priv->desired_contact_features->len);
266
267 return array;
268 }
269
270 static void
tp_simple_client_factory_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)271 tp_simple_client_factory_get_property (GObject *object,
272 guint property_id,
273 GValue *value,
274 GParamSpec *pspec)
275 {
276 TpSimpleClientFactory *self = (TpSimpleClientFactory *) object;
277
278 switch (property_id)
279 {
280 case PROP_DBUS_DAEMON:
281 g_value_set_object (value, self->priv->dbus);
282 break;
283 default:
284 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
285 break;
286 }
287 }
288
289 static void
tp_simple_client_factory_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)290 tp_simple_client_factory_set_property (GObject *object,
291 guint property_id,
292 const GValue *value,
293 GParamSpec *pspec)
294 {
295 TpSimpleClientFactory *self = (TpSimpleClientFactory *) object;
296
297 switch (property_id)
298 {
299 case PROP_DBUS_DAEMON:
300 g_assert (self->priv->dbus == NULL); /* construct only */
301 self->priv->dbus = g_value_dup_object (value);
302 break;
303 default:
304 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
305 break;
306 }
307 }
308
309 static void
tp_simple_client_factory_constructed(GObject * object)310 tp_simple_client_factory_constructed (GObject *object)
311 {
312 TpSimpleClientFactory *self = (TpSimpleClientFactory *) object;
313
314 if (self->priv->dbus == NULL)
315 self->priv->dbus = tp_dbus_daemon_dup (NULL);
316
317 G_OBJECT_CLASS (tp_simple_client_factory_parent_class)->constructed (object);
318 }
319
320 static void
tp_simple_client_factory_finalize(GObject * object)321 tp_simple_client_factory_finalize (GObject *object)
322 {
323 TpSimpleClientFactory *self = (TpSimpleClientFactory *) object;
324
325 g_clear_object (&self->priv->dbus);
326 tp_clear_pointer (&self->priv->proxy_cache, g_hash_table_unref);
327 tp_clear_pointer (&self->priv->desired_account_features, g_array_unref);
328 tp_clear_pointer (&self->priv->desired_connection_features, g_array_unref);
329 tp_clear_pointer (&self->priv->desired_channel_features, g_array_unref);
330 tp_clear_pointer (&self->priv->desired_contact_features, g_array_unref);
331
332 G_OBJECT_CLASS (tp_simple_client_factory_parent_class)->finalize (object);
333 }
334
335 static void
tp_simple_client_factory_init(TpSimpleClientFactory * self)336 tp_simple_client_factory_init (TpSimpleClientFactory *self)
337 {
338 GQuark feature;
339
340 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TP_TYPE_SIMPLE_CLIENT_FACTORY,
341 TpSimpleClientFactoryPrivate);
342
343 self->priv->proxy_cache = g_hash_table_new (g_str_hash, g_str_equal);
344
345 self->priv->desired_account_features = g_array_new (TRUE, FALSE,
346 sizeof (GQuark));
347 feature = TP_ACCOUNT_FEATURE_CORE;
348 g_array_append_val (self->priv->desired_account_features, feature);
349
350 self->priv->desired_connection_features = g_array_new (TRUE, FALSE,
351 sizeof (GQuark));
352 feature = TP_CONNECTION_FEATURE_CORE;
353 g_array_append_val (self->priv->desired_connection_features, feature);
354
355 self->priv->desired_channel_features = g_array_new (TRUE, FALSE,
356 sizeof (GQuark));
357 feature = TP_CHANNEL_FEATURE_CORE;
358 g_array_append_val (self->priv->desired_channel_features, feature);
359
360 self->priv->desired_contact_features = g_array_new (FALSE, FALSE,
361 sizeof (TpContactFeature));
362 }
363
364 static void
tp_simple_client_factory_class_init(TpSimpleClientFactoryClass * klass)365 tp_simple_client_factory_class_init (TpSimpleClientFactoryClass *klass)
366 {
367 GObjectClass *object_class = (GObjectClass *) klass;
368 GParamSpec *param_spec;
369
370 g_type_class_add_private (klass, sizeof (TpSimpleClientFactoryPrivate));
371
372 object_class->get_property = tp_simple_client_factory_get_property;
373 object_class->set_property = tp_simple_client_factory_set_property;
374 object_class->constructed = tp_simple_client_factory_constructed;
375 object_class->finalize = tp_simple_client_factory_finalize;
376
377 klass->create_account = create_account_impl;
378 klass->dup_account_features = dup_account_features_impl;
379 klass->create_connection = create_connection_impl;
380 klass->dup_connection_features = dup_connection_features_impl;
381 klass->create_channel = create_channel_impl;
382 klass->dup_channel_features = dup_channel_features_impl;
383 klass->create_contact = create_contact_impl;
384 klass->dup_contact_features = dup_contact_features_impl;
385
386 /**
387 * TpSimpleClientFactory:dbus-daemon:
388 *
389 * The D-Bus daemon for this object.
390 */
391 param_spec = g_param_spec_object ("dbus-daemon", "D-Bus daemon",
392 "The D-Bus daemon used by this object",
393 TP_TYPE_DBUS_DAEMON,
394 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
395 g_object_class_install_property (object_class, PROP_DBUS_DAEMON,
396 param_spec);
397 }
398
399 /**
400 * tp_simple_client_factory_new:
401 * @dbus: (allow-none): a #TpDBusDaemon, or %NULL
402 *
403 * Creates a new #TpSimpleClientFactory instance. If @dbus is %NULL,
404 * tp_dbus_daemon_dup() will be used.
405 *
406 * Returns: a new #TpSimpleClientFactory
407 *
408 * Since: 0.15.5
409 */
410 TpSimpleClientFactory *
tp_simple_client_factory_new(TpDBusDaemon * dbus)411 tp_simple_client_factory_new (TpDBusDaemon *dbus)
412 {
413 return g_object_new (TP_TYPE_SIMPLE_CLIENT_FACTORY,
414 "dbus-daemon", dbus,
415 NULL);
416 }
417
418 /**
419 * tp_simple_client_factory_get_dbus_daemon:
420 * @self: a #TpSimpleClientFactory object
421 *
422 * <!-- -->
423 *
424 * Returns: (transfer none): the value of the #TpSimpleClientFactory:dbus-daemon
425 * property
426 *
427 * Since: 0.15.5
428 */
429 TpDBusDaemon *
tp_simple_client_factory_get_dbus_daemon(TpSimpleClientFactory * self)430 tp_simple_client_factory_get_dbus_daemon (TpSimpleClientFactory *self)
431 {
432 g_return_val_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self), NULL);
433
434 return self->priv->dbus;
435 }
436
437 /**
438 * tp_simple_client_factory_ensure_account:
439 * @self: a #TpSimpleClientFactory object
440 * @object_path: the object path of an account
441 * @immutable_properties: (transfer none) (element-type utf8 GObject.Value):
442 * the immutable properties of the account, or %NULL.
443 * @error: Used to raise an error if @object_path is not valid
444 *
445 * Returns a #TpAccount proxy for the account at @object_path. The returned
446 * #TpAccount is cached; the same #TpAccount object will be returned by this
447 * function repeatedly, as long as at least one reference exists.
448 *
449 * Note that the returned #TpAccount is not guaranteed to be ready; the caller
450 * is responsible for calling tp_proxy_prepare_async() with the desired
451 * features (as given by tp_simple_client_factory_dup_account_features()).
452 *
453 * This function is rather low-level. tp_account_manager_dup_valid_accounts()
454 * and #TpAccountManager::validity-changed are more appropriate for most
455 * applications.
456 *
457 * Returns: (transfer full): a reference to a #TpAccount;
458 * see tp_account_new().
459 *
460 * Since: 0.15.5
461 */
462 TpAccount *
tp_simple_client_factory_ensure_account(TpSimpleClientFactory * self,const gchar * object_path,const GHashTable * immutable_properties,GError ** error)463 tp_simple_client_factory_ensure_account (TpSimpleClientFactory *self,
464 const gchar *object_path,
465 const GHashTable *immutable_properties,
466 GError **error)
467 {
468 TpAccount *account;
469
470 g_return_val_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self), NULL);
471 g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
472
473 account = lookup_proxy (self, object_path);
474 if (account != NULL)
475 return g_object_ref (account);
476
477 account = TP_SIMPLE_CLIENT_FACTORY_GET_CLASS (self)->create_account (self,
478 object_path, immutable_properties, error);
479 insert_proxy (self, account);
480
481 return account;
482 }
483
484 /**
485 * tp_simple_client_factory_dup_account_features:
486 * @self: a #TpSimpleClientFactory object
487 * @account: a #TpAccount
488 *
489 * Return a zero-terminated #GArray containing the #TpAccount features that
490 * should be prepared on @account.
491 *
492 * Returns: (transfer full) (element-type GLib.Quark): a newly allocated
493 * #GArray
494 *
495 * Since: 0.15.5
496 */
497 GArray *
tp_simple_client_factory_dup_account_features(TpSimpleClientFactory * self,TpAccount * account)498 tp_simple_client_factory_dup_account_features (TpSimpleClientFactory *self,
499 TpAccount *account)
500 {
501 g_return_val_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self), NULL);
502 g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
503 g_return_val_if_fail (tp_proxy_get_factory (account) == self, NULL);
504
505 return TP_SIMPLE_CLIENT_FACTORY_GET_CLASS (self)->dup_account_features (self,
506 account);
507 }
508
509 /**
510 * tp_simple_client_factory_add_account_features:
511 * @self: a #TpSimpleClientFactory object
512 * @features: (transfer none) (array zero-terminated=1) (allow-none): an array
513 * of desired features, ending with 0; %NULL is equivalent to an array
514 * containing only 0
515 *
516 * Add @features to the desired features to be prepared on #TpAccount
517 * objects. Those features will be added to the features already returned be
518 * tp_simple_client_factory_dup_account_features().
519 *
520 * It is not necessary to add %TP_ACCOUNT_FEATURE_CORE as it is already
521 * included by default.
522 *
523 * Note that these features will not be added to existing #TpAccount
524 * objects; the user must call tp_proxy_prepare_async() themself.
525 *
526 * Since: 0.15.5
527 */
528 void
tp_simple_client_factory_add_account_features(TpSimpleClientFactory * self,const GQuark * features)529 tp_simple_client_factory_add_account_features (
530 TpSimpleClientFactory *self,
531 const GQuark *features)
532 {
533 g_return_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self));
534
535 _tp_quark_array_merge (self->priv->desired_account_features, features, -1);
536 }
537
538 /**
539 * tp_simple_client_factory_add_account_features_varargs: (skip)
540 * @self: a #TpSimpleClientFactory
541 * @feature: the first feature
542 * @...: the second and subsequent features, if any, ending with 0
543 *
544 * The same as tp_simple_client_factory_add_account_features(), but with a more
545 * convenient calling convention from C.
546 *
547 * Since: 0.15.5
548 */
549 void
tp_simple_client_factory_add_account_features_varargs(TpSimpleClientFactory * self,GQuark feature,...)550 tp_simple_client_factory_add_account_features_varargs (
551 TpSimpleClientFactory *self,
552 GQuark feature,
553 ...)
554 {
555 va_list var_args;
556
557 g_return_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self));
558
559 va_start (var_args, feature);
560 _tp_quark_array_merge_valist (self->priv->desired_account_features, feature,
561 var_args);
562 va_end (var_args);
563 }
564
565 /**
566 * tp_simple_client_factory_ensure_connection:
567 * @self: a #TpSimpleClientFactory object
568 * @object_path: the object path of a connection
569 * @immutable_properties: (transfer none) (element-type utf8 GObject.Value):
570 * the immutable properties of the connection.
571 * @error: Used to raise an error if @object_path is not valid
572 *
573 * Returns a #TpConnection proxy for the connection at @object_path.
574 * The returned #TpConnection is cached; the same #TpConnection object
575 * will be returned by this function repeatedly, as long as at least one
576 * reference exists.
577 *
578 * Note that the returned #TpConnection is not guaranteed to be ready; the
579 * caller is responsible for calling tp_proxy_prepare_async() with the desired
580 * features (as given by tp_simple_client_factory_dup_connection_features()).
581 *
582 * This function is rather low-level. #TpAccount:connection is more
583 * appropriate for most applications.
584 *
585 * Returns: (transfer full): a reference to a #TpConnection;
586 * see tp_connection_new().
587 *
588 * Since: 0.15.5
589 */
590 TpConnection *
tp_simple_client_factory_ensure_connection(TpSimpleClientFactory * self,const gchar * object_path,const GHashTable * immutable_properties,GError ** error)591 tp_simple_client_factory_ensure_connection (TpSimpleClientFactory *self,
592 const gchar *object_path,
593 const GHashTable *immutable_properties,
594 GError **error)
595 {
596 TpConnection *connection;
597
598 g_return_val_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self), NULL);
599 g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
600
601 connection = lookup_proxy (self, object_path);
602 if (connection != NULL)
603 return g_object_ref (connection);
604
605 connection = TP_SIMPLE_CLIENT_FACTORY_GET_CLASS (self)->create_connection (
606 self, object_path, immutable_properties, error);
607 insert_proxy (self, connection);
608
609 return connection;
610 }
611
612 /**
613 * tp_simple_client_factory_dup_connection_features:
614 * @self: a #TpSimpleClientFactory object
615 * @connection: a #TpConnection
616 *
617 * Return a zero-terminated #GArray containing the #TpConnection features that
618 * should be prepared on @connection.
619 *
620 * Returns: (transfer full) (element-type GLib.Quark): a newly allocated
621 * #GArray
622 *
623 * Since: 0.15.5
624 */
625 GArray *
tp_simple_client_factory_dup_connection_features(TpSimpleClientFactory * self,TpConnection * connection)626 tp_simple_client_factory_dup_connection_features (TpSimpleClientFactory *self,
627 TpConnection *connection)
628 {
629 g_return_val_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self), NULL);
630 g_return_val_if_fail (TP_IS_CONNECTION (connection), NULL);
631 g_return_val_if_fail (tp_proxy_get_factory (connection) == self, NULL);
632
633 return TP_SIMPLE_CLIENT_FACTORY_GET_CLASS (self)->dup_connection_features (
634 self, connection);
635 }
636
637 /**
638 * tp_simple_client_factory_add_connection_features:
639 * @self: a #TpSimpleClientFactory object
640 * @features: (transfer none) (array zero-terminated=1) (allow-none): an array
641 * of desired features, ending with 0; %NULL is equivalent to an array
642 * containing only 0
643 *
644 * Add @features to the desired features to be prepared on #TpConnection
645 * objects. Those features will be added to the features already returned be
646 * tp_simple_client_factory_dup_connection_features().
647 *
648 * It is not necessary to add %TP_CONNECTION_FEATURE_CORE as it is already
649 * included by default.
650 *
651 * Note that these features will not be added to existing #TpConnection
652 * objects; the user must call tp_proxy_prepare_async() themself.
653 *
654 * Since: 0.15.5
655 */
656 void
tp_simple_client_factory_add_connection_features(TpSimpleClientFactory * self,const GQuark * features)657 tp_simple_client_factory_add_connection_features (
658 TpSimpleClientFactory *self,
659 const GQuark *features)
660 {
661 g_return_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self));
662
663 _tp_quark_array_merge (self->priv->desired_connection_features, features, -1);
664 }
665
666 /**
667 * tp_simple_client_factory_add_connection_features_varargs: (skip)
668 * @self: a #TpSimpleClientFactory
669 * @feature: the first feature
670 * @...: the second and subsequent features, if any, ending with 0
671 *
672 * The same as tp_simple_client_factory_add_connection_features(), but with a
673 * more convenient calling convention from C.
674 *
675 * Since: 0.15.5
676 */
677 void
tp_simple_client_factory_add_connection_features_varargs(TpSimpleClientFactory * self,GQuark feature,...)678 tp_simple_client_factory_add_connection_features_varargs (
679 TpSimpleClientFactory *self,
680 GQuark feature,
681 ...)
682 {
683 va_list var_args;
684
685 g_return_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self));
686
687 va_start (var_args, feature);
688 _tp_quark_array_merge_valist (self->priv->desired_connection_features,
689 feature, var_args);
690 va_end (var_args);
691 }
692
693 /**
694 * tp_simple_client_factory_ensure_channel:
695 * @self: a #TpSimpleClientFactory object
696 * @connection: a #TpConnection whose #TpProxy:factory is this object
697 * @object_path: the object path of a channel on @connection
698 * @immutable_properties: (transfer none) (element-type utf8 GObject.Value):
699 * the immutable properties of the channel
700 * @error: Used to raise an error if @object_path is not valid
701 *
702 * Returns a #TpChannel proxy for the channel at @object_path on @connection.
703 * The returned #TpChannel is cached; the same #TpChannel object
704 * will be returned by this function repeatedly, as long as at least one
705 * reference exists.
706 *
707 * Note that the returned #TpChannel is not guaranteed to be ready; the
708 * caller is responsible for calling tp_proxy_prepare_async() with the desired
709 * features (as given by tp_simple_client_factory_dup_channel_features()).
710 *
711 * This function is rather low-level.
712 * #TpAccountChannelRequest and #TpBaseClient are more appropriate ways
713 * to obtain channels for most applications.
714 *
715 * Returns: (transfer full): a reference to a #TpChannel;
716 * see tp_channel_new_from_properties().
717 *
718 * Since: 0.15.5
719 */
720 TpChannel *
tp_simple_client_factory_ensure_channel(TpSimpleClientFactory * self,TpConnection * connection,const gchar * object_path,const GHashTable * immutable_properties,GError ** error)721 tp_simple_client_factory_ensure_channel (TpSimpleClientFactory *self,
722 TpConnection *connection,
723 const gchar *object_path,
724 const GHashTable *immutable_properties,
725 GError **error)
726 {
727 TpChannel *channel;
728
729 g_return_val_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self), NULL);
730 g_return_val_if_fail (TP_IS_CONNECTION (connection), NULL);
731 g_return_val_if_fail (tp_proxy_get_factory (connection) == self, NULL);
732 g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
733
734 channel = lookup_proxy (self, object_path);
735 if (channel != NULL)
736 return g_object_ref (channel);
737
738 channel = TP_SIMPLE_CLIENT_FACTORY_GET_CLASS (self)->create_channel (self,
739 connection, object_path, immutable_properties, error);
740 insert_proxy (self, channel);
741
742 return channel;
743 }
744
745 /**
746 * tp_simple_client_factory_dup_channel_features:
747 * @self: a #TpSimpleClientFactory object
748 * @channel: a #TpChannel
749 *
750 * Return a zero-terminated #GArray containing the #TpChannel features that
751 * should be prepared on @channel.
752 *
753 * Returns: (transfer full) (element-type GLib.Quark): a newly allocated
754 * #GArray
755 *
756 * Since: 0.15.5
757 */
758 GArray *
tp_simple_client_factory_dup_channel_features(TpSimpleClientFactory * self,TpChannel * channel)759 tp_simple_client_factory_dup_channel_features (TpSimpleClientFactory *self,
760 TpChannel *channel)
761 {
762 g_return_val_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self), NULL);
763 g_return_val_if_fail (TP_IS_CHANNEL (channel), NULL);
764 g_return_val_if_fail (tp_proxy_get_factory (channel) == self, NULL);
765
766 return TP_SIMPLE_CLIENT_FACTORY_GET_CLASS (self)->dup_channel_features (
767 self, channel);
768 }
769
770 /**
771 * tp_simple_client_factory_add_channel_features:
772 * @self: a #TpSimpleClientFactory object
773 * @features: (transfer none) (array zero-terminated=1) (allow-none): an array
774 * of desired features, ending with 0; %NULL is equivalent to an array
775 * containing only 0
776 *
777 * Add @features to the desired features to be prepared on #TpChannel
778 * objects. Those features will be added to the features already returned be
779 * tp_simple_client_factory_dup_channel_features().
780 *
781 * It is not necessary to add %TP_CHANNEL_FEATURE_CORE as it is already
782 * included by default.
783 *
784 * Note that these features will not be added to existing #TpChannel
785 * objects; the user must call tp_proxy_prepare_async() themself.
786 *
787 * Since: 0.15.5
788 */
789 void
tp_simple_client_factory_add_channel_features(TpSimpleClientFactory * self,const GQuark * features)790 tp_simple_client_factory_add_channel_features (
791 TpSimpleClientFactory *self,
792 const GQuark *features)
793 {
794 g_return_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self));
795
796 _tp_quark_array_merge (self->priv->desired_channel_features, features, -1);
797 }
798
799 /**
800 * tp_simple_client_factory_add_channel_features_varargs: (skip)
801 * @self: a #TpSimpleClientFactory
802 * @feature: the first feature
803 * @...: the second and subsequent features, if any, ending with 0
804 *
805 * The same as tp_simple_client_factory_add_channel_features(), but with a
806 * more convenient calling convention from C.
807 *
808 * Since: 0.15.5
809 */
810 void
tp_simple_client_factory_add_channel_features_varargs(TpSimpleClientFactory * self,GQuark feature,...)811 tp_simple_client_factory_add_channel_features_varargs (
812 TpSimpleClientFactory *self,
813 GQuark feature,
814 ...)
815 {
816 va_list var_args;
817
818 g_return_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self));
819
820 va_start (var_args, feature);
821 _tp_quark_array_merge_valist (self->priv->desired_channel_features,
822 feature, var_args);
823 va_end (var_args);
824 }
825
826 /**
827 * tp_simple_client_factory_ensure_contact:
828 * @self: a #TpSimpleClientFactory object
829 * @connection: a #TpConnection whose #TpProxy:factory is this object
830 * @handle: a #TpHandle
831 * @identifier: a string representing the contact's identifier
832 *
833 * Returns a #TpContact representing @identifier (and @handle) on @connection.
834 * The returned #TpContact is cached; the same #TpContact object
835 * will be returned by this function repeatedly, as long as at least one
836 * reference exists.
837 *
838 * Note that the returned #TpContact is not guaranteed to be ready; the caller
839 * is responsible for calling tp_connection_upgrade_contacts() with the desired
840 * features (as given by tp_simple_client_factory_dup_contact_features()).
841 *
842 * For this function to work properly, tp_connection_has_immortal_handles()
843 * must return %TRUE for @connection.
844 *
845 * Returns: (transfer full): a reference to a #TpContact.
846 *
847 * Since: 0.15.5
848 */
849 TpContact *
tp_simple_client_factory_ensure_contact(TpSimpleClientFactory * self,TpConnection * connection,TpHandle handle,const gchar * identifier)850 tp_simple_client_factory_ensure_contact (TpSimpleClientFactory *self,
851 TpConnection *connection,
852 TpHandle handle,
853 const gchar *identifier)
854 {
855 TpContact *contact;
856
857 g_return_val_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self), NULL);
858 g_return_val_if_fail (TP_IS_CONNECTION (connection), NULL);
859 g_return_val_if_fail (tp_proxy_get_factory (connection) == self, NULL);
860 g_return_val_if_fail (tp_connection_has_immortal_handles (connection), NULL);
861 g_return_val_if_fail (handle != 0, NULL);
862 g_return_val_if_fail (identifier != NULL, NULL);
863
864 contact = tp_connection_dup_contact_if_possible (connection,
865 handle, identifier);
866 if (contact != NULL)
867 return contact;
868
869 contact = TP_SIMPLE_CLIENT_FACTORY_GET_CLASS (self)->create_contact (self,
870 connection, handle, identifier);
871 _tp_connection_add_contact (connection, handle, contact);
872
873 return contact;
874 }
875
876 static void
upgrade_contacts_cb(GObject * source,GAsyncResult * result,gpointer user_data)877 upgrade_contacts_cb (GObject *source,
878 GAsyncResult *result,
879 gpointer user_data)
880 {
881 TpConnection *connection = (TpConnection *) source;
882 GSimpleAsyncResult *my_result = user_data;
883 GPtrArray *contacts;
884 GError *error = NULL;
885
886 if (!tp_connection_upgrade_contacts_finish (connection, result,
887 &contacts, &error))
888 {
889 g_simple_async_result_take_error (my_result, error);
890 }
891 else
892 {
893 g_simple_async_result_set_op_res_gpointer (my_result, contacts,
894 (GDestroyNotify) g_ptr_array_unref);
895 }
896
897 g_simple_async_result_complete (my_result);
898 g_object_unref (my_result);
899 }
900
901
902 /**
903 * tp_simple_client_factory_upgrade_contacts_async:
904 * @self: a #TpSimpleClientFactory object
905 * @connection: a #TpConnection whose #TpProxy:factory is this object
906 * @n_contacts: The number of contacts in @contacts (must be at least 1)
907 * @contacts: (array length=n_contacts): An array of #TpContact objects
908 * associated with @self
909 * @callback: a callback to call when the operation finishes
910 * @user_data: data to pass to @callback
911 *
912 * Same as tp_connection_upgrade_contacts_async(), but prepare contacts with all
913 * features previously passed to
914 * tp_simple_client_factory_add_contact_features().
915 *
916 * Since: 0.19.1
917 */
918 void
tp_simple_client_factory_upgrade_contacts_async(TpSimpleClientFactory * self,TpConnection * connection,guint n_contacts,TpContact * const * contacts,GAsyncReadyCallback callback,gpointer user_data)919 tp_simple_client_factory_upgrade_contacts_async (
920 TpSimpleClientFactory *self,
921 TpConnection *connection,
922 guint n_contacts,
923 TpContact * const *contacts,
924 GAsyncReadyCallback callback,
925 gpointer user_data)
926 {
927 GSimpleAsyncResult *result;
928 GArray *features;
929
930 /* no real reason this shouldn't work, but it's really confusing
931 * and probably indicates an error */
932 g_warn_if_fail (tp_proxy_get_factory (connection) == self);
933
934 result = g_simple_async_result_new ((GObject *) self, callback, user_data,
935 tp_simple_client_factory_upgrade_contacts_async);
936
937 features = tp_simple_client_factory_dup_contact_features (self, connection);
938 tp_connection_upgrade_contacts_async (connection, n_contacts, contacts,
939 features->len, (TpContactFeature *) features->data,
940 upgrade_contacts_cb, result);
941 g_array_unref (features);
942 }
943
944 /**
945 * tp_simple_client_factory_upgrade_contacts_finish:
946 * @self: a #TpSimpleClientFactory
947 * @result: a #GAsyncResult
948 * @contacts: (element-type TelepathyGLib.Contact) (transfer container) (out) (allow-none):
949 * a location to set a #GPtrArray of upgraded #TpContact, or %NULL.
950 * @error: a #GError to fill
951 *
952 * Finishes tp_simple_client_factory_upgrade_contacts_async()
953 *
954 * Returns: %TRUE on success, %FALSE otherwise.
955 * Since: 0.19.1
956 */
957 gboolean
tp_simple_client_factory_upgrade_contacts_finish(TpSimpleClientFactory * self,GAsyncResult * result,GPtrArray ** contacts,GError ** error)958 tp_simple_client_factory_upgrade_contacts_finish (
959 TpSimpleClientFactory *self,
960 GAsyncResult *result,
961 GPtrArray **contacts,
962 GError **error)
963 {
964 _tp_implement_finish_copy_pointer (self,
965 tp_simple_client_factory_upgrade_contacts_async,
966 g_ptr_array_ref, contacts);
967 }
968
969 static void
dup_contact_by_id_cb(GObject * source,GAsyncResult * result,gpointer user_data)970 dup_contact_by_id_cb (GObject *source,
971 GAsyncResult *result,
972 gpointer user_data)
973 {
974 TpConnection *connection = (TpConnection *) source;
975 GSimpleAsyncResult *my_result = user_data;
976 TpContact *contact;
977 GError *error = NULL;
978
979 contact = tp_connection_dup_contact_by_id_finish (connection, result, &error);
980 if (contact == NULL)
981 {
982 g_simple_async_result_take_error (my_result, error);
983 }
984 else
985 {
986 g_simple_async_result_set_op_res_gpointer (my_result, contact,
987 g_object_unref);
988 }
989
990 g_simple_async_result_complete (my_result);
991 g_object_unref (my_result);
992 }
993
994
995 /**
996 * tp_simple_client_factory_ensure_contact_by_id_async:
997 * @self: a #TpSimpleClientFactory object
998 * @connection: a #TpConnection
999 * @identifier: a string representing the contact's identifier
1000 * @callback: a callback to call when the operation finishes
1001 * @user_data: data to pass to @callback
1002 *
1003 * Same as tp_connection_dup_contact_by_id_async(), but prepare the
1004 * contact with all features previously passed to
1005 * tp_simple_client_factory_add_contact_features().
1006 *
1007 * Since: 0.19.1
1008 */
1009 void
tp_simple_client_factory_ensure_contact_by_id_async(TpSimpleClientFactory * self,TpConnection * connection,const gchar * identifier,GAsyncReadyCallback callback,gpointer user_data)1010 tp_simple_client_factory_ensure_contact_by_id_async (
1011 TpSimpleClientFactory *self,
1012 TpConnection *connection,
1013 const gchar *identifier,
1014 GAsyncReadyCallback callback,
1015 gpointer user_data)
1016 {
1017 GSimpleAsyncResult *result;
1018 GArray *features;
1019
1020 result = g_simple_async_result_new ((GObject *) self, callback, user_data,
1021 tp_simple_client_factory_ensure_contact_by_id_async);
1022
1023 features = tp_simple_client_factory_dup_contact_features (self, connection);
1024 tp_connection_dup_contact_by_id_async (connection, identifier,
1025 features->len, (TpContactFeature *) features->data,
1026 dup_contact_by_id_cb, result);
1027 g_array_unref (features);
1028 }
1029
1030 /**
1031 * tp_simple_client_factory_ensure_contact_by_id_finish:
1032 * @self: a #TpSimpleClientFactory
1033 * @result: a #GAsyncResult
1034 * @error: a #GError to fill
1035 *
1036 * Finishes tp_simple_client_factory_ensure_contact_by_id_async()
1037 *
1038 * Returns: (transfer full): a #TpContact or %NULL on error.
1039 * Since: 0.19.1
1040 */
1041 TpContact *
tp_simple_client_factory_ensure_contact_by_id_finish(TpSimpleClientFactory * self,GAsyncResult * result,GError ** error)1042 tp_simple_client_factory_ensure_contact_by_id_finish (
1043 TpSimpleClientFactory *self,
1044 GAsyncResult *result,
1045 GError **error)
1046 {
1047 _tp_implement_finish_return_copy_pointer (self,
1048 tp_simple_client_factory_ensure_contact_by_id_async, g_object_ref);
1049 }
1050
1051 /**
1052 * tp_simple_client_factory_dup_contact_features:
1053 * @self: a #TpSimpleClientFactory object
1054 * @connection: a #TpConnection
1055 *
1056 * Return a #GArray containing the #TpContactFeature that should be prepared on
1057 * all contacts of @connection.
1058 *
1059 * Returns: (transfer full) (element-type TelepathyGLib.ContactFeature): a newly
1060 * allocated #GArray
1061 *
1062 * Since: 0.15.5
1063 */
1064 GArray *
tp_simple_client_factory_dup_contact_features(TpSimpleClientFactory * self,TpConnection * connection)1065 tp_simple_client_factory_dup_contact_features (TpSimpleClientFactory *self,
1066 TpConnection *connection)
1067 {
1068 g_return_val_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self), NULL);
1069 g_return_val_if_fail (TP_IS_CONNECTION (connection), NULL);
1070 g_return_val_if_fail (tp_proxy_get_factory (connection) == self, NULL);
1071
1072 return TP_SIMPLE_CLIENT_FACTORY_GET_CLASS (self)->dup_contact_features (
1073 self, connection);
1074 }
1075
1076 /**
1077 * tp_simple_client_factory_add_contact_features:
1078 * @self: a #TpSimpleClientFactory object
1079 * @n_features: The number of features in @features (may be 0)
1080 * @features: (array length=n_features) (allow-none): an array of desired
1081 * features (may be %NULL if @n_features is 0)
1082 *
1083 * Add @features to the desired features to be prepared on #TpContact
1084 * objects. Those features will be added to the features already returned be
1085 * tp_simple_client_factory_dup_contact_features().
1086 *
1087 * Note that these features will not be added to existing #TpContact
1088 * objects; the user must call tp_connection_upgrade_contacts() themself.
1089 *
1090 * Since: 0.15.5
1091 */
1092 void
tp_simple_client_factory_add_contact_features(TpSimpleClientFactory * self,guint n_features,const TpContactFeature * features)1093 tp_simple_client_factory_add_contact_features (TpSimpleClientFactory *self,
1094 guint n_features, const TpContactFeature *features)
1095 {
1096 guint i;
1097
1098 g_return_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self));
1099
1100 /* Add features into desired_contact_features avoiding dups */
1101 for (i = 0; i < n_features; i++)
1102 {
1103 guint j;
1104 gboolean found = FALSE;
1105
1106 for (j = 0; j < self->priv->desired_contact_features->len; j++)
1107 {
1108 if (features[i] == g_array_index (
1109 self->priv->desired_contact_features, TpContactFeature, j))
1110 {
1111 found = TRUE;
1112 break;
1113 }
1114 }
1115
1116 if (!found)
1117 g_array_append_val (self->priv->desired_contact_features, features[i]);
1118 }
1119 }
1120
1121 /**
1122 * tp_simple_client_factory_add_contact_features_varargs: (skip)
1123 * @self: a #TpSimpleClientFactory
1124 * @feature: the first feature
1125 * @...: the second and subsequent features, if any, ending with
1126 * %TP_CONTACT_FEATURE_INVALID
1127 *
1128 * The same as tp_simple_client_factory_add_contact_features(), but with a
1129 * more convenient calling convention from C.
1130 *
1131 * Since: 0.15.5
1132 */
1133 void
tp_simple_client_factory_add_contact_features_varargs(TpSimpleClientFactory * self,TpContactFeature feature,...)1134 tp_simple_client_factory_add_contact_features_varargs (
1135 TpSimpleClientFactory *self,
1136 TpContactFeature feature,
1137 ...)
1138 {
1139 va_list var_args;
1140 GArray *features;
1141 TpContactFeature f;
1142
1143 g_return_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self));
1144
1145 va_start (var_args, feature);
1146 features = g_array_new (FALSE, FALSE, sizeof (TpContactFeature));
1147
1148 for (f = feature; f != TP_CONTACT_FEATURE_INVALID;
1149 f = va_arg (var_args, TpContactFeature))
1150 g_array_append_val (features, f);
1151
1152 tp_simple_client_factory_add_contact_features (self, features->len,
1153 (TpContactFeature *) features->data);
1154
1155 g_array_unref (features);
1156 va_end (var_args);
1157 }
1158
1159 /*
1160 * _tp_simple_client_factory_ensure_channel_request:
1161 * @self: a #TpSimpleClientFactory object
1162 * @object_path: the object path of a channel request
1163 * @immutable_properties: (transfer none) (element-type utf8 GObject.Value):
1164 * the immutable properties of the channel request
1165 * @error: Used to raise an error if @object_path is not valid
1166 *
1167 * Returns a #TpChannelRequest for @object_path. The returned
1168 * #TpChannelRequest is cached; the same #TpChannelRequest object will be
1169 * returned by this function repeatedly, as long as at least one reference
1170 * exists.
1171 *
1172 * Note that the returned #TpChannelRequest is not guaranteed to be ready; the
1173 * caller is responsible for calling tp_proxy_prepare_async().
1174 *
1175 * Returns: (transfer full): a reference to a #TpChannelRequest;
1176 * see tp_channel_request_new().
1177 *
1178 * Since: 0.15.5
1179 */
1180 TpChannelRequest *
_tp_simple_client_factory_ensure_channel_request(TpSimpleClientFactory * self,const gchar * object_path,GHashTable * immutable_properties,GError ** error)1181 _tp_simple_client_factory_ensure_channel_request (TpSimpleClientFactory *self,
1182 const gchar *object_path,
1183 GHashTable *immutable_properties,
1184 GError **error)
1185 {
1186 TpChannelRequest *request;
1187
1188 g_return_val_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self), NULL);
1189 g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
1190
1191 request = lookup_proxy (self, object_path);
1192 if (request != NULL)
1193 {
1194 /* A common usage is request_and_handle, in that case EnsureChannel
1195 * returns only the object-path of the ChannelRequest but not properties.
1196 * The TpChannelRequest will be created with no properties, then when
1197 * handling we get the properties and we reuse the same TpChannelRequest
1198 * object, and we can give it the immutable-properties. */
1199 _tp_channel_request_ensure_immutable_properties (request,
1200 immutable_properties);
1201 return g_object_ref (request);
1202 }
1203
1204 request = _tp_channel_request_new_with_factory (self, self->priv->dbus,
1205 object_path, immutable_properties, error);
1206 insert_proxy (self, request);
1207
1208 return request;
1209 }
1210
1211 /*
1212 * _tp_simple_client_factory_ensure_channel_dispatch_operation:
1213 * @self: a #TpSimpleClientFactory object
1214 * @object_path: the object path of a channel dispatch operation
1215 * @immutable_properties: (transfer none) (element-type utf8 GObject.Value):
1216 * the immutable properties of the channel dispatch operation
1217 * @error: Used to raise an error if @object_path is not valid
1218 *
1219 * Returns a #TpChannelDispatchOperation for @object_path.
1220 * The returned #TpChannelDispatchOperation is cached; the same
1221 * #TpChannelDispatchOperation object will be returned by this function
1222 * repeatedly, as long as at least one reference exists.
1223 *
1224 * Note that the returned #TpChannelDispatchOperation is not guaranteed to be
1225 * ready; the caller is responsible for calling tp_proxy_prepare_async().
1226 *
1227 * Returns: (transfer full): a reference to a
1228 * #TpChannelDispatchOperation; see tp_channel_dispatch_operation_new().
1229 *
1230 * Since: 0.15.5
1231 */
1232 TpChannelDispatchOperation *
_tp_simple_client_factory_ensure_channel_dispatch_operation(TpSimpleClientFactory * self,const gchar * object_path,GHashTable * immutable_properties,GError ** error)1233 _tp_simple_client_factory_ensure_channel_dispatch_operation (
1234 TpSimpleClientFactory *self,
1235 const gchar *object_path,
1236 GHashTable *immutable_properties,
1237 GError **error)
1238 {
1239 TpChannelDispatchOperation *dispatch;
1240
1241 g_return_val_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self), NULL);
1242 g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
1243
1244 dispatch = lookup_proxy (self, object_path);
1245 if (dispatch != NULL)
1246 return g_object_ref (dispatch);
1247
1248 dispatch = _tp_channel_dispatch_operation_new_with_factory (self,
1249 self->priv->dbus, object_path, immutable_properties, error);
1250 insert_proxy (self, dispatch);
1251
1252 return dispatch;
1253 }
1254