1 /*
2  * account.c - proxy for an account in the Telepathy account manager
3  *
4  * Copyright © 2009–2012 Collabora Ltd. <http://www.collabora.co.uk/>
5  * Copyright © 2009–2010 Nokia Corporation
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21 
22 #include "config.h"
23 
24 #include <string.h>
25 
26 #include "telepathy-glib/account-internal.h"
27 #include "telepathy-glib/account.h"
28 
29 #include <telepathy-glib/dbus.h>
30 #include <telepathy-glib/defs.h>
31 #include <telepathy-glib/errors.h>
32 #include <telepathy-glib/gtypes.h>
33 #include <telepathy-glib/interfaces.h>
34 #include <telepathy-glib/proxy-subclass.h>
35 #include <telepathy-glib/util.h>
36 
37 #define DEBUG_FLAG TP_DEBUG_ACCOUNTS
38 #include "telepathy-glib/connection-internal.h"
39 #include "telepathy-glib/dbus-internal.h"
40 #include "telepathy-glib/debug-internal.h"
41 #include "telepathy-glib/proxy-internal.h"
42 #include "telepathy-glib/simple-client-factory-internal.h"
43 #include "telepathy-glib/util-internal.h"
44 #include "telepathy-glib/variant-util-internal.h"
45 
46 #include "telepathy-glib/_gen/tp-cli-account-body.h"
47 
48 /**
49  * SECTION:account
50  * @title: TpAccount
51  * @short_description: proxy object for an account in the Telepathy account
52  *  manager
53  * @see_also: #TpAccountManager
54  *
55  * The Telepathy Account Manager stores the user's configured real-time
56  * communication accounts. The #TpAccount object represents a stored account.
57  *
58  * Since: 0.7.32
59  */
60 
61 /**
62  * TpAccount:
63  *
64  * The Telepathy Account Manager stores the user's configured real-time
65  * communication accounts. This object represents a stored account.
66  *
67  * If this account is deleted from the account manager, the
68  * #TpProxy::invalidated signal will be emitted
69  * with the domain %TP_DBUS_ERRORS and the error code
70  * %TP_DBUS_ERROR_OBJECT_REMOVED.
71  *
72  * One can connect to the #GObject::notify signal to get change notifications
73  * for many of the properties on this object. Refer to each property's
74  * documentation for whether it can be used in this way.
75  *
76  * #TpAccount objects should normally be obtained from the #TpAccountManager.
77  *
78  * Since 0.16, #TpAccount always has a non-%NULL #TpProxy:factory, and its
79  * #TpProxy:factory will be propagated to its #TpConnection
80  * (if any). If a #TpAccount is created without going via the
81  * #TpAccountManager or specifying a #TpProxy:factory, the default
82  * is to use a new #TpAutomaticClientFactory.
83  *
84  * Since: 0.7.32
85  */
86 
87 /**
88  * TpAccountClass:
89  *
90  * The class of a #TpAccount.
91  */
92 
93 struct _TpAccountPrivate {
94   gboolean dispose_has_run;
95 
96   TpConnection *connection;
97   gchar *connection_object_path;
98 
99   TpConnectionStatus connection_status;
100   TpConnectionStatusReason reason;
101   gchar *error;
102   GHashTable *error_details;
103 
104   TpConnectionPresenceType cur_presence;
105   gchar *cur_status;
106   gchar *cur_message;
107 
108   TpConnectionPresenceType requested_presence;
109   gchar *requested_status;
110   gchar *requested_message;
111 
112   TpConnectionPresenceType auto_presence;
113   gchar *auto_status;
114   gchar *auto_message;
115 
116   gboolean changing_presence;
117   gboolean connect_automatically;
118   gboolean has_been_online;
119 
120   gchar *normalized_name;
121   gchar *nickname;
122 
123   gboolean enabled;
124   gboolean valid;
125   gboolean removed;
126 
127   gchar *cm_name;
128   gchar *proto_name;
129   gchar *icon_name;
130   gchar *service;
131 
132   gchar *display_name;
133   GStrv supersedes;
134 
135   GHashTable *parameters;
136 
137   gchar *storage_provider;
138   GValue *storage_identifier;
139   TpStorageRestrictionFlags storage_restrictions;
140 
141   GStrv uri_schemes;
142 
143   gboolean connection_prepared;
144 };
145 
146 G_DEFINE_TYPE (TpAccount, tp_account, TP_TYPE_PROXY)
147 
148 /* signals */
149 enum {
150   STATUS_CHANGED,
151   PRESENCE_CHANGED,
152   AVATAR_CHANGED,
153   LAST_SIGNAL
154 };
155 
156 static guint signals[LAST_SIGNAL];
157 
158 /* properties */
159 enum {
160   PROP_ENABLED = 1,
161   PROP_CHANGING_PRESENCE,
162   PROP_CURRENT_PRESENCE_TYPE,
163   PROP_CURRENT_STATUS,
164   PROP_CURRENT_STATUS_MESSAGE,
165   PROP_CONNECTION_STATUS,
166   PROP_CONNECTION_STATUS_REASON,
167   PROP_CONNECTION_ERROR,
168   PROP_CONNECTION_ERROR_DETAILS,
169   PROP_CONNECTION,
170   PROP_DISPLAY_NAME,
171   PROP_CONNECTION_MANAGER,
172   PROP_CM_NAME,
173   PROP_PROTOCOL,
174   PROP_PROTOCOL_NAME,
175   PROP_ICON_NAME,
176   PROP_CONNECT_AUTOMATICALLY,
177   PROP_HAS_BEEN_ONLINE,
178   PROP_SERVICE,
179   PROP_VALID,
180   PROP_REQUESTED_PRESENCE_TYPE,
181   PROP_REQUESTED_STATUS,
182   PROP_REQUESTED_STATUS_MESSAGE,
183   PROP_NICKNAME,
184   PROP_AUTOMATIC_PRESENCE_TYPE,
185   PROP_AUTOMATIC_STATUS,
186   PROP_AUTOMATIC_STATUS_MESSAGE,
187   PROP_NORMALIZED_NAME,
188   PROP_STORAGE_PROVIDER,
189   PROP_STORAGE_IDENTIFIER,
190   PROP_STORAGE_IDENTIFIER_VARIANT,
191   PROP_STORAGE_RESTRICTIONS,
192   PROP_SUPERSEDES,
193   PROP_URI_SCHEMES,
194   N_PROPS
195 };
196 
197 static void tp_account_prepare_connection_async (TpProxy *proxy,
198     const TpProxyFeature *feature,
199     GAsyncReadyCallback callback,
200     gpointer user_data);
201 
202 static void tp_account_prepare_addressing_async (TpProxy *proxy,
203     const TpProxyFeature *feature,
204     GAsyncReadyCallback callback,
205     gpointer user_data);
206 
207 static void tp_account_prepare_storage_async (TpProxy *proxy,
208     const TpProxyFeature *feature,
209     GAsyncReadyCallback callback,
210     gpointer user_data);
211 
212 static gboolean
connection_is_internal(TpAccount * self)213 connection_is_internal (TpAccount *self)
214 {
215   if (!tp_proxy_is_prepared (self, TP_ACCOUNT_FEATURE_CONNECTION))
216     return FALSE;
217 
218   return !self->priv->connection_prepared;
219 }
220 
221 /**
222  * TP_ACCOUNT_FEATURE_CORE:
223  *
224  * Expands to a call to a function that returns a quark for the "core" feature
225  * on a #TpAccount.
226  *
227  * When this feature is prepared, the basic properties of the Account have
228  * been retrieved and are available for use, and change-notification has been
229  * set up.
230  *
231  * One can ask for a feature to be prepared using the
232  * tp_proxy_prepare_async() function, and waiting for it to callback.
233  *
234  * Since: 0.9.0
235  */
236 
237 /**
238  * TP_ACCOUNT_FEATURE_CONNECTION:
239  *
240  * Expands to a call to a function that returns a quark for the "connection"
241  * feature on a #TpAccount.
242  *
243  * When this feature is prepared, it is guaranteed that #TpAccount:connection
244  * will always be either %NULL or prepared. The account's #TpProxy:factory
245  * will be used to create the #TpConnection object and to determine its
246  * desired connection features. Change notification of the
247  * #TpAccount:connection property will be delayed until all features (at least
248  * %TP_CONNECTION_FEATURE_CORE) are prepared. See
249  * tp_simple_client_factory_add_account_features() to define which features
250  * needs to be prepared.
251  *
252  * One can ask for a feature to be prepared using the
253  * tp_proxy_prepare_async() function, and waiting for it to callback.
254  *
255  * Since: 0.15.5
256  */
257 
258 /**
259  * TP_ACCOUNT_FEATURE_STORAGE:
260  *
261  * Expands to a call to a function that returns a quark for the "storage"
262  * feature on a #TpAccount.
263  *
264  * When this feature is prepared, the Account.Interface.Storage properties have
265  * been retrieved and are available for use.
266  *
267  * One can ask for a feature to be prepared using the
268  * tp_proxy_prepare_async() function, and waiting for it to callback.
269  *
270  * Since: 0.13.2
271  */
272 
273 /**
274  * TP_ACCOUNT_FEATURE_ADDRESSING:
275  *
276  * Expands to a call to a function that returns a quark for the "addressing"
277  * feature on a #TpAccount.
278  *
279  * When this feature is prepared, the list of URI schemes from
280  * Account.Interface.Addressing has been retrieved and is available for use.
281  *
282  * One can ask for a feature to be prepared using the
283  * tp_proxy_prepare_async() function, and waiting for it to callback.
284  *
285  * Since: 0.13.8
286  */
287 
288 /**
289  * tp_account_get_feature_quark_core:
290  *
291  * <!-- -->
292  *
293  * Returns: the quark used for representing the core feature of a
294  *          #TpAccount
295  *
296  * Since: 0.9.0
297  */
298 GQuark
tp_account_get_feature_quark_core(void)299 tp_account_get_feature_quark_core (void)
300 {
301   return g_quark_from_static_string ("tp-account-feature-core");
302 }
303 
304 /**
305  * tp_account_get_feature_quark_connection:
306  *
307  * <!-- -->
308  *
309  * Returns: the quark used for representing the connection feature of a
310  *          #TpAccount
311  *
312  * Since: 0.15.5
313  */
314 GQuark
tp_account_get_feature_quark_connection(void)315 tp_account_get_feature_quark_connection (void)
316 {
317   return g_quark_from_static_string ("tp-account-feature-connection");
318 }
319 
320 /**
321  * tp_account_get_feature_quark_storage:
322  *
323  * <!-- -->
324  *
325  * Returns: the quark used for representing the storage interface of a
326  *          #TpAccount
327  *
328  * Since: 0.13.2
329  */
330 GQuark
tp_account_get_feature_quark_storage(void)331 tp_account_get_feature_quark_storage (void)
332 {
333   return g_quark_from_static_string ("tp-account-feature-storage");
334 }
335 
336 GQuark
tp_account_get_feature_quark_addressing(void)337 tp_account_get_feature_quark_addressing (void)
338 {
339   return g_quark_from_static_string ("tp-account-feature-addressing");
340 }
341 
342 enum {
343     FEAT_CORE,
344     FEAT_CONNECTION,
345     FEAT_ADDRESSING,
346     FEAT_STORAGE,
347     N_FEAT
348 };
349 
350 static const TpProxyFeature *
_tp_account_list_features(TpProxyClass * cls G_GNUC_UNUSED)351 _tp_account_list_features (TpProxyClass *cls G_GNUC_UNUSED)
352 {
353   static TpProxyFeature features[N_FEAT + 1] = { { 0 } };
354 
355   if (G_UNLIKELY (features[0].name == 0))
356     {
357       features[FEAT_CORE].name = TP_ACCOUNT_FEATURE_CORE;
358       features[FEAT_CORE].core = TRUE;
359       /* no need for a prepare_async function - the constructor starts it */
360 
361       features[FEAT_CONNECTION].name = TP_ACCOUNT_FEATURE_CONNECTION;
362       features[FEAT_CONNECTION].prepare_async =
363         tp_account_prepare_connection_async;
364 
365       features[FEAT_ADDRESSING].name = TP_ACCOUNT_FEATURE_ADDRESSING;
366       features[FEAT_ADDRESSING].prepare_async =
367         tp_account_prepare_addressing_async;
368 
369       features[FEAT_STORAGE].name = TP_ACCOUNT_FEATURE_STORAGE;
370       features[FEAT_STORAGE].prepare_async =
371         tp_account_prepare_storage_async;
372 
373       /* assert that the terminator at the end is there */
374       g_assert (features[N_FEAT].name == 0);
375     }
376 
377   return features;
378 }
379 
380 static void
tp_account_init(TpAccount * self)381 tp_account_init (TpAccount *self)
382 {
383   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TP_TYPE_ACCOUNT,
384       TpAccountPrivate);
385 
386   self->priv->connection_status = TP_CONNECTION_STATUS_DISCONNECTED;
387   self->priv->error = g_strdup (TP_ERROR_STR_DISCONNECTED);
388   self->priv->error_details = g_hash_table_new_full (g_str_hash, g_str_equal,
389       g_free, (GDestroyNotify) tp_g_value_slice_free);
390   self->priv->supersedes = g_new0 (gchar *, 1);
391 }
392 
393 static void
_tp_account_invalidated_cb(TpAccount * self,guint domain,guint code,gchar * message)394 _tp_account_invalidated_cb (TpAccount *self,
395     guint domain,
396     guint code,
397     gchar *message)
398 {
399   TpAccountPrivate *priv = self->priv;
400 
401   /* The connection will get disconnected as a result of account deletion,
402    * but by then we will no longer be telling the API user about changes -
403    * so claim the disconnection already happened (see fd.o#25149) */
404   if (priv->connection_status != TP_CONNECTION_STATUS_DISCONNECTED)
405     {
406       priv->connection_status = TP_CONNECTION_STATUS_DISCONNECTED;
407       tp_clear_pointer (&priv->error, g_free);
408       g_hash_table_remove_all (priv->error_details);
409 
410       if (domain == TP_DBUS_ERRORS && code == TP_DBUS_ERROR_OBJECT_REMOVED)
411         {
412           /* presumably the user asked for it to be deleted... */
413           priv->reason = TP_CONNECTION_STATUS_REASON_REQUESTED;
414           priv->error = g_strdup (TP_ERROR_STR_CANCELLED);
415           g_hash_table_insert (priv->error_details,
416               g_strdup ("debug-message"),
417               tp_g_value_slice_new_static_string ("TpAccount was removed"));
418         }
419       else
420         {
421           gchar *s;
422 
423           priv->reason = TP_CONNECTION_STATUS_REASON_NONE_SPECIFIED;
424           priv->error = g_strdup (TP_ERROR_STR_DISCONNECTED);
425           s = g_strdup_printf ("TpAccount was invalidated: %s #%u: %s",
426               g_quark_to_string (domain), code, message);
427           g_hash_table_insert (priv->error_details,
428               g_strdup ("debug-message"),
429               tp_g_value_slice_new_take_string (s));
430         }
431 
432       g_object_notify ((GObject *) self, "connection-status");
433       g_object_notify ((GObject *) self, "connection-status-reason");
434       g_object_notify ((GObject *) self, "connection-error");
435       g_object_notify ((GObject *) self, "connection-error-details");
436     }
437 }
438 
439 static void
_tp_account_removed_cb(TpAccount * self,gpointer unused G_GNUC_UNUSED,GObject * object G_GNUC_UNUSED)440 _tp_account_removed_cb (TpAccount *self,
441     gpointer unused G_GNUC_UNUSED,
442     GObject *object G_GNUC_UNUSED)
443 {
444   GError e = { TP_DBUS_ERRORS, TP_DBUS_ERROR_OBJECT_REMOVED,
445                "Account removed" };
446 
447   if (self->priv->removed)
448     return;
449 
450   self->priv->removed = TRUE;
451 
452   tp_proxy_invalidate ((TpProxy *) self, &e);
453 }
454 
455 static void
set_connection_prepare_cb(GObject * object,GAsyncResult * res,gpointer user_data)456 set_connection_prepare_cb (GObject *object,
457     GAsyncResult *res,
458     gpointer user_data)
459 {
460   TpConnection *connection = (TpConnection *) object;
461   TpAccount *self = user_data;
462   GError *error = NULL;
463 
464   if (!tp_proxy_prepare_finish (object, res, &error))
465     {
466       DEBUG ("Error preparing connection: %s", error->message);
467       g_clear_error (&error);
468       goto OUT;
469     }
470 
471   /* Connection could have changed again while we were preparing it */
472   if (self->priv->connection == connection)
473     {
474       self->priv->connection_prepared = TRUE;
475       g_object_notify ((GObject *) self, "connection");
476     }
477 
478 OUT:
479   g_object_unref (self);
480 }
481 
482 static void _tp_account_set_connection (TpAccount *account, const gchar *path);
483 
484 static void
connection_invalidated_cb(TpConnection * connection,guint domain,gint code,gchar * message,TpAccount * account)485 connection_invalidated_cb (TpConnection *connection,
486     guint domain,
487     gint code,
488     gchar *message,
489     TpAccount *account)
490 {
491   _tp_account_set_connection (account, "/");
492 }
493 
494 static void
_tp_account_set_connection(TpAccount * account,const gchar * path)495 _tp_account_set_connection (TpAccount *account,
496     const gchar *path)
497 {
498   TpAccountPrivate *priv = account->priv;
499   gboolean had_public_connection;
500   gboolean have_public_connection;
501   GError *error = NULL;
502 
503   if (priv->connection != NULL)
504     {
505       const gchar *current;
506 
507       /* Do nothing if we already have a connection for the same path */
508       current = tp_proxy_get_object_path (priv->connection);
509       if (!tp_strdiff (current, path))
510         return;
511 
512       g_signal_handlers_disconnect_by_func (priv->connection,
513           connection_invalidated_cb, account);
514     }
515 
516   had_public_connection = (priv->connection != NULL &&
517       !connection_is_internal (account));
518 
519   tp_clear_object (&account->priv->connection);
520   g_free (priv->connection_object_path);
521   priv->connection_object_path = g_strdup (path);
522   priv->connection_prepared = FALSE;
523 
524   /* The account has no connection */
525   if (!tp_strdiff ("/", path))
526     {
527       /* Do not emit change notifications if the connection was not yet made
528        * public */
529       if (had_public_connection)
530         g_object_notify (G_OBJECT (account), "connection");
531 
532       return;
533     }
534 
535   priv->connection = tp_simple_client_factory_ensure_connection (
536       tp_proxy_get_factory (account), path, NULL, &error);
537 
538   if (priv->connection == NULL)
539     {
540       DEBUG ("Failed to create a new TpConnection: %s",
541           error->message);
542       g_error_free (error);
543     }
544   else
545     {
546       tp_g_signal_connect_object (priv->connection, "invalidated",
547           G_CALLBACK (connection_invalidated_cb), account, 0);
548 
549       _tp_connection_set_account (priv->connection, account);
550       if (tp_proxy_is_prepared (account, TP_ACCOUNT_FEATURE_CONNECTION))
551         {
552           GArray *features;
553 
554           features = tp_simple_client_factory_dup_connection_features (
555               tp_proxy_get_factory (account), priv->connection);
556 
557           tp_proxy_prepare_async (priv->connection, (GQuark *) features->data,
558               set_connection_prepare_cb, g_object_ref (account));
559 
560           g_array_unref (features);
561         }
562     }
563 
564   have_public_connection = (priv->connection != NULL &&
565       !connection_is_internal (account));
566 
567   /* Do not emit signal if connection wasn't public and still isn't */
568   if (had_public_connection || have_public_connection)
569     g_object_notify (G_OBJECT (account), "connection");
570 }
571 
572 static void
_tp_account_got_all_storage_cb(TpProxy * proxy,GHashTable * properties,const GError * error,gpointer user_data,GObject * object)573 _tp_account_got_all_storage_cb (TpProxy *proxy,
574     GHashTable *properties,
575     const GError *error,
576     gpointer user_data,
577     GObject *object)
578 {
579   TpAccount *self = TP_ACCOUNT (proxy);
580   GSimpleAsyncResult *result = user_data;
581 
582   if (error != NULL)
583     DEBUG ("Error getting Storage properties: %s", error->message);
584 
585   if (properties == NULL)
586     self->priv->storage_provider = NULL;
587   else
588     self->priv->storage_provider = g_strdup (tp_asv_get_string (properties,
589           "StorageProvider"));
590 
591   if (!tp_str_empty (self->priv->storage_provider))
592     {
593       self->priv->storage_identifier = tp_g_value_slice_dup (
594           tp_asv_get_boxed (properties, "StorageIdentifier", G_TYPE_VALUE));
595       self->priv->storage_restrictions = tp_asv_get_uint32 (properties,
596           "StorageRestrictions", NULL);
597     }
598 
599   /* if the StorageProvider isn't known, set it to the empty string */
600   if (self->priv->storage_provider == NULL)
601     self->priv->storage_provider = g_strdup ("");
602 
603   g_simple_async_result_complete_in_idle (result);
604 }
605 
606 static void
tp_account_prepare_storage_async(TpProxy * proxy,const TpProxyFeature * feature,GAsyncReadyCallback callback,gpointer user_data)607 tp_account_prepare_storage_async (TpProxy *proxy,
608     const TpProxyFeature *feature,
609     GAsyncReadyCallback callback,
610     gpointer user_data)
611 {
612   TpAccount *self = TP_ACCOUNT (proxy);
613   GSimpleAsyncResult *result;
614 
615   result = g_simple_async_result_new ((GObject *) proxy, callback, user_data,
616       tp_account_prepare_storage_async);
617 
618   g_assert (self->priv->storage_provider == NULL);
619 
620   tp_cli_dbus_properties_call_get_all (self, -1,
621       TP_IFACE_ACCOUNT_INTERFACE_STORAGE,
622       _tp_account_got_all_storage_cb, result, g_object_unref, G_OBJECT (self));
623 }
624 
625 static void
_tp_account_update(TpAccount * account,GHashTable * properties)626 _tp_account_update (TpAccount *account,
627     GHashTable *properties)
628 {
629   TpProxy *proxy = TP_PROXY (account);
630   TpAccountPrivate *priv = account->priv;
631   GValueArray *arr;
632   TpConnectionStatus old_s = priv->connection_status;
633   gboolean status_changed = FALSE;
634   gboolean presence_changed = FALSE;
635   const gchar *status;
636   const gchar *message;
637 
638   tp_proxy_add_interfaces (proxy, tp_asv_get_strv (properties, "Interfaces"));
639 
640   if (g_hash_table_lookup (properties, "ConnectionStatus") != NULL)
641     {
642       priv->connection_status =
643         tp_asv_get_uint32 (properties, "ConnectionStatus", NULL);
644 
645       if (old_s != priv->connection_status)
646         status_changed = TRUE;
647     }
648 
649   if (g_hash_table_lookup (properties, "ConnectionStatusReason") != NULL)
650     {
651       TpConnectionStatusReason old = priv->reason;
652 
653       priv->reason =
654         tp_asv_get_uint32 (properties, "ConnectionStatusReason", NULL);
655 
656       if (old != priv->reason)
657         status_changed = TRUE;
658     }
659 
660   if (g_hash_table_lookup (properties, "ConnectionError") != NULL)
661     {
662       const gchar *new_error = tp_asv_get_string (properties,
663           "ConnectionError");
664 
665       if (tp_str_empty (new_error))
666         new_error = NULL;
667 
668       if (tp_strdiff (new_error, priv->error))
669         {
670           tp_clear_pointer (&priv->error, g_free);
671           priv->error = g_strdup (new_error);
672           status_changed = TRUE;
673         }
674     }
675 
676   if (g_hash_table_lookup (properties, "ConnectionErrorDetails") != NULL)
677     {
678       const GHashTable *details = tp_asv_get_boxed (properties,
679           "ConnectionErrorDetails", TP_HASH_TYPE_STRING_VARIANT_MAP);
680 
681       if ((details != NULL && tp_asv_size (details) > 0) ||
682           tp_asv_size (priv->error_details) > 0)
683         {
684           g_hash_table_remove_all (priv->error_details);
685 
686           if (details != NULL)
687             tp_g_hash_table_update (priv->error_details,
688                 (GHashTable *) details,
689                 (GBoxedCopyFunc) g_strdup,
690                 (GBoxedCopyFunc) tp_g_value_slice_dup);
691 
692           status_changed = TRUE;
693         }
694     }
695 
696   if (status_changed)
697     {
698       if (priv->connection_status == TP_CONNECTION_STATUS_CONNECTED)
699         {
700           /* our connection status is CONNECTED - clear any error we may
701            * have recorded previously */
702           g_hash_table_remove_all (priv->error_details);
703           tp_clear_pointer (&priv->error, g_free);
704         }
705       else if (priv->error == NULL)
706         {
707           /* our connection status is worse than CONNECTED but the
708            * AccountManager didn't tell us why, so attempt to guess
709            * a detailed error from the status reason */
710           const gchar *guessed = NULL;
711 
712           _tp_connection_status_reason_to_gerror (priv->reason,
713               old_s, &guessed, NULL);
714 
715           if (guessed == NULL)
716             guessed = TP_ERROR_STR_DISCONNECTED;
717 
718           priv->error = g_strdup (guessed);
719         }
720     }
721 
722   if (g_hash_table_lookup (properties, "CurrentPresence") != NULL)
723     {
724       presence_changed = TRUE;
725       arr = tp_asv_get_boxed (properties, "CurrentPresence",
726           TP_STRUCT_TYPE_SIMPLE_PRESENCE);
727 
728       tp_value_array_unpack (arr, 3,
729           &priv->cur_presence,
730           &status,
731           &message);
732       g_free (priv->cur_status);
733       priv->cur_status = g_strdup (status);
734       g_free (priv->cur_message);
735       priv->cur_message = g_strdup (message);
736     }
737 
738   if (g_hash_table_lookup (properties, "RequestedPresence") != NULL)
739     {
740       arr = tp_asv_get_boxed (properties, "RequestedPresence",
741           TP_STRUCT_TYPE_SIMPLE_PRESENCE);
742 
743       tp_value_array_unpack (arr, 3,
744           &priv->requested_presence,
745           &status,
746           &message);
747       g_free (priv->requested_status);
748       priv->requested_status = g_strdup (status);
749       g_free (priv->requested_message);
750       priv->requested_message = g_strdup (message);
751 
752       g_object_notify (G_OBJECT (account), "requested-presence-type");
753       g_object_notify (G_OBJECT (account), "requested-status");
754       g_object_notify (G_OBJECT (account), "requested-status-message");
755     }
756 
757   if (g_hash_table_lookup (properties, "AutomaticPresence") != NULL)
758     {
759       arr = tp_asv_get_boxed (properties, "AutomaticPresence",
760           TP_STRUCT_TYPE_SIMPLE_PRESENCE);
761 
762       tp_value_array_unpack (arr, 3,
763           &priv->auto_presence,
764           &status,
765           &message);
766       g_free (priv->auto_status);
767       priv->auto_status = g_strdup (status);
768       g_free (priv->auto_message);
769       priv->auto_message = g_strdup (message);
770 
771       g_object_notify (G_OBJECT (account), "automatic-presence-type");
772       g_object_notify (G_OBJECT (account), "automatic-status");
773       g_object_notify (G_OBJECT (account), "automatic-status-message");
774     }
775 
776   if (g_hash_table_lookup (properties, "DisplayName") != NULL)
777     {
778       gchar *old = priv->display_name;
779 
780       priv->display_name =
781         g_strdup (tp_asv_get_string (properties, "DisplayName"));
782 
783       if (tp_strdiff (old, priv->display_name))
784         g_object_notify (G_OBJECT (account), "display-name");
785 
786       g_free (old);
787     }
788 
789   if (g_hash_table_lookup (properties, "Nickname") != NULL)
790     {
791       gchar *old = priv->nickname;
792 
793       priv->nickname = g_strdup (tp_asv_get_string (properties, "Nickname"));
794 
795       if (tp_strdiff (old, priv->nickname))
796         g_object_notify (G_OBJECT (account), "nickname");
797 
798       g_free (old);
799     }
800 
801   if (g_hash_table_lookup (properties, "Supersedes") != NULL)
802     {
803       GStrv old = priv->supersedes;
804       GPtrArray *new_arr = tp_asv_get_boxed (properties, "Supersedes",
805           TP_ARRAY_TYPE_OBJECT_PATH_LIST);
806       gboolean changed = FALSE;
807       guint i;
808 
809       if (new_arr == NULL)
810         {
811           priv->supersedes = g_new0 (gchar *, 1);
812         }
813       else
814         {
815           priv->supersedes = g_new0 (gchar *, new_arr->len + 1);
816 
817           for (i = 0; i < new_arr->len; i++)
818             priv->supersedes[i] = g_strdup (g_ptr_array_index (new_arr, i));
819         }
820 
821       if (new_arr == NULL || new_arr->len == 0)
822         {
823           changed = (old != NULL && *old != NULL);
824         }
825       else if (old == NULL || *old == NULL ||
826           g_strv_length (old) != new_arr->len)
827         {
828           changed = TRUE;
829         }
830       else
831         {
832           for (i = 0; i < new_arr->len; i++)
833             {
834               if (tp_strdiff (old[i], priv->supersedes[i]))
835                 {
836                   changed = TRUE;
837                   break;
838                 }
839             }
840         }
841 
842       if (changed)
843         g_object_notify (G_OBJECT (account), "supersedes");
844 
845       g_strfreev (old);
846     }
847 
848   if (g_hash_table_lookup (properties, "NormalizedName") != NULL)
849     {
850       gchar *old = priv->normalized_name;
851 
852       priv->normalized_name = g_strdup (tp_asv_get_string (properties,
853             "NormalizedName"));
854 
855       if (tp_strdiff (old, priv->normalized_name))
856         g_object_notify (G_OBJECT (account), "normalized-name");
857 
858       g_free (old);
859     }
860 
861   if (g_hash_table_lookup (properties, "Icon") != NULL)
862     {
863       const gchar *icon_name;
864       gchar *old = priv->icon_name;
865 
866       icon_name = tp_asv_get_string (properties, "Icon");
867 
868       if (tp_str_empty (icon_name))
869         priv->icon_name = g_strdup_printf ("im-%s", priv->proto_name);
870       else
871         priv->icon_name = g_strdup (icon_name);
872 
873       if (tp_strdiff (old, priv->icon_name))
874         g_object_notify (G_OBJECT (account), "icon-name");
875 
876       g_free (old);
877     }
878 
879   if (g_hash_table_lookup (properties, "Enabled") != NULL)
880     {
881       gboolean enabled = tp_asv_get_boolean (properties, "Enabled", NULL);
882       if (priv->enabled != enabled)
883         {
884           priv->enabled = enabled;
885           g_object_notify (G_OBJECT (account), "enabled");
886         }
887     }
888 
889   if (g_hash_table_lookup (properties, "Service") != NULL)
890     {
891       const gchar *service;
892       gchar *old = priv->service;
893 
894       service = tp_asv_get_string (properties, "Service");
895 
896       if (tp_str_empty (service))
897         priv->service = g_strdup (priv->proto_name);
898       else
899         priv->service = g_strdup (service);
900 
901       if (tp_strdiff (old, priv->service))
902         g_object_notify (G_OBJECT (account), "service");
903 
904       g_free (old);
905     }
906 
907   if (g_hash_table_lookup (properties, "Valid") != NULL)
908     {
909       gboolean old = priv->valid;
910 
911       priv->valid = tp_asv_get_boolean (properties, "Valid", NULL);
912 
913       if (old != priv->valid)
914         g_object_notify (G_OBJECT (account), "valid");
915     }
916 
917   if (g_hash_table_lookup (properties, "Parameters") != NULL)
918     {
919       GHashTable *parameters;
920 
921       parameters = tp_asv_get_boxed (properties, "Parameters",
922           TP_HASH_TYPE_STRING_VARIANT_MAP);
923 
924       if (priv->parameters != NULL)
925         g_hash_table_unref (priv->parameters);
926 
927       priv->parameters = g_boxed_copy (TP_HASH_TYPE_STRING_VARIANT_MAP,
928           parameters);
929       /* this isn't a property, so we don't notify */
930     }
931 
932   if (status_changed)
933     {
934       g_signal_emit (account, signals[STATUS_CHANGED], 0,
935           old_s, priv->connection_status, priv->reason, priv->error,
936           priv->error_details);
937 
938       g_object_notify (G_OBJECT (account), "connection-status");
939       g_object_notify (G_OBJECT (account), "connection-status-reason");
940       g_object_notify (G_OBJECT (account), "connection-error");
941       g_object_notify (G_OBJECT (account), "connection-error-details");
942     }
943 
944   if (presence_changed)
945     {
946       g_signal_emit (account, signals[PRESENCE_CHANGED], 0,
947           priv->cur_presence, priv->cur_status, priv->cur_message);
948       g_object_notify (G_OBJECT (account), "current-presence-type");
949       g_object_notify (G_OBJECT (account), "current-status");
950       g_object_notify (G_OBJECT (account), "current-status-message");
951     }
952 
953   if (g_hash_table_lookup (properties, "Connection") != NULL)
954     {
955       const gchar *path = tp_asv_get_object_path (properties, "Connection");
956 
957       _tp_account_set_connection (account, path);
958     }
959 
960   if (g_hash_table_lookup (properties, "ChangingPresence") != NULL)
961     {
962       gboolean old = priv->changing_presence;
963 
964       priv->changing_presence =
965         tp_asv_get_boolean (properties, "ChangingPresence", NULL);
966 
967       if (old != priv->changing_presence)
968         g_object_notify (G_OBJECT (account), "changing-presence");
969     }
970 
971   if (g_hash_table_lookup (properties, "ConnectAutomatically") != NULL)
972     {
973       gboolean old = priv->connect_automatically;
974 
975       priv->connect_automatically =
976         tp_asv_get_boolean (properties, "ConnectAutomatically", NULL);
977 
978       if (old != priv->connect_automatically)
979         g_object_notify (G_OBJECT (account), "connect-automatically");
980     }
981 
982   if (g_hash_table_lookup (properties, "HasBeenOnline") != NULL)
983     {
984       gboolean old = priv->has_been_online;
985 
986       priv->has_been_online =
987         tp_asv_get_boolean (properties, "HasBeenOnline", NULL);
988 
989       if (old != priv->has_been_online)
990         g_object_notify (G_OBJECT (account), "has-been-online");
991     }
992 
993   _tp_proxy_set_feature_prepared (proxy, TP_ACCOUNT_FEATURE_CORE, TRUE);
994 }
995 
996 static void
_tp_account_properties_changed(TpAccount * proxy,GHashTable * properties,gpointer user_data,GObject * weak_object)997 _tp_account_properties_changed (TpAccount *proxy,
998     GHashTable *properties,
999     gpointer user_data,
1000     GObject *weak_object)
1001 {
1002   TpAccount *self = TP_ACCOUNT (weak_object);
1003 
1004   if (!tp_proxy_is_prepared (self, TP_ACCOUNT_FEATURE_CORE))
1005     return;
1006 
1007   _tp_account_update (self, properties);
1008 }
1009 
1010 static void
avatar_changed_cb(TpAccount * self,gpointer user_data,GObject * weak_object)1011 avatar_changed_cb (TpAccount *self,
1012     gpointer user_data,
1013     GObject *weak_object)
1014 {
1015   g_signal_emit (self, signals[AVATAR_CHANGED], 0);
1016 }
1017 
1018 static void
_tp_account_got_all_cb(TpProxy * proxy,GHashTable * properties,const GError * error,gpointer user_data,GObject * weak_object)1019 _tp_account_got_all_cb (TpProxy *proxy,
1020     GHashTable *properties,
1021     const GError *error,
1022     gpointer user_data,
1023     GObject *weak_object)
1024 {
1025   TpAccount *self = TP_ACCOUNT (weak_object);
1026 
1027   DEBUG ("Got whole set of properties for %s",
1028       tp_proxy_get_object_path (self));
1029 
1030   if (error != NULL)
1031     {
1032       DEBUG ("Failed to get the initial set of account properties: %s",
1033           error->message);
1034       tp_proxy_invalidate ((TpProxy *) self, error);
1035       return;
1036     }
1037 
1038   _tp_account_update (self, properties);
1039 
1040   /* We can't try connecting this signal earlier as tp_proxy_add_interfaces()
1041    * has to be called first if we support the Avatar interface. */
1042   tp_cli_account_interface_avatar_connect_to_avatar_changed (self,
1043       avatar_changed_cb, NULL, NULL, G_OBJECT (self), NULL);
1044 }
1045 
1046 static void
addressing_props_changed(TpAccount * self,GHashTable * changed_properties)1047 addressing_props_changed (TpAccount *self,
1048     GHashTable *changed_properties)
1049 {
1050   const gchar * const * v;
1051 
1052   if (self->priv->uri_schemes == NULL)
1053     /* We did not fetch the initial value yet, ignoring */
1054     return;
1055 
1056   v = tp_asv_get_strv (changed_properties, "URISchemes");
1057   if (v == NULL)
1058     return;
1059 
1060   g_strfreev (self->priv->uri_schemes);
1061   self->priv->uri_schemes = g_strdupv ((GStrv) v);
1062 
1063   g_object_notify (G_OBJECT (self), "uri-schemes");
1064 }
1065 
1066 static void
dbus_properties_changed_cb(TpProxy * proxy,const gchar * interface_name,GHashTable * changed_properties,const gchar ** invalidated_properties,gpointer user_data,GObject * weak_object)1067 dbus_properties_changed_cb (TpProxy *proxy,
1068     const gchar *interface_name,
1069     GHashTable *changed_properties,
1070     const gchar **invalidated_properties,
1071     gpointer user_data,
1072     GObject *weak_object)
1073 {
1074   TpAccount *self = TP_ACCOUNT (weak_object);
1075 
1076   if (!tp_strdiff (interface_name, TP_IFACE_ACCOUNT_INTERFACE_ADDRESSING))
1077     {
1078       addressing_props_changed (self, changed_properties);
1079     }
1080 }
1081 
1082 static void
_tp_account_constructed(GObject * object)1083 _tp_account_constructed (GObject *object)
1084 {
1085   TpAccount *self = TP_ACCOUNT (object);
1086   TpAccountPrivate *priv = self->priv;
1087   void (*chain_up) (GObject *) =
1088     ((GObjectClass *) tp_account_parent_class)->constructed;
1089   GError *error = NULL;
1090   TpProxySignalConnection *sc;
1091 
1092   if (chain_up != NULL)
1093     chain_up (object);
1094 
1095   g_return_if_fail (tp_proxy_get_dbus_daemon (self) != NULL);
1096 
1097   _tp_proxy_ensure_factory (self, NULL);
1098 
1099   sc = tp_cli_account_connect_to_removed (self, _tp_account_removed_cb,
1100       NULL, NULL, NULL, &error);
1101 
1102   if (sc == NULL)
1103     {
1104       CRITICAL ("Couldn't connect to Removed: %s", error->message);
1105       g_error_free (error);
1106     }
1107 
1108   G_GNUC_BEGIN_IGNORE_DEPRECATIONS
1109   tp_account_parse_object_path (tp_proxy_get_object_path (self),
1110       &(priv->cm_name), &(priv->proto_name), NULL, NULL);
1111   G_GNUC_END_IGNORE_DEPRECATIONS
1112 
1113   priv->icon_name = g_strdup_printf ("im-%s", priv->proto_name);
1114   priv->service = g_strdup (priv->proto_name);
1115 
1116   g_signal_connect (self, "invalidated",
1117       G_CALLBACK (_tp_account_invalidated_cb), NULL);
1118 
1119   tp_cli_account_connect_to_account_property_changed (self,
1120       _tp_account_properties_changed, NULL, NULL, object, NULL);
1121 
1122   tp_cli_dbus_properties_connect_to_properties_changed (self,
1123       dbus_properties_changed_cb, NULL, NULL, object, NULL);
1124 
1125   tp_cli_dbus_properties_call_get_all (self, -1, TP_IFACE_ACCOUNT,
1126       _tp_account_got_all_cb, NULL, NULL, G_OBJECT (self));
1127 }
1128 
1129 static void
_tp_account_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)1130 _tp_account_get_property (GObject *object,
1131     guint prop_id,
1132     GValue *value,
1133     GParamSpec *pspec)
1134 {
1135   TpAccount *self = TP_ACCOUNT (object);
1136 
1137   switch (prop_id)
1138     {
1139     case PROP_ENABLED:
1140       g_value_set_boolean (value, self->priv->enabled);
1141       break;
1142     case PROP_CURRENT_PRESENCE_TYPE:
1143       g_value_set_uint (value, self->priv->cur_presence);
1144       break;
1145     case PROP_CURRENT_STATUS:
1146       g_value_set_string (value, self->priv->cur_status);
1147       break;
1148     case PROP_CURRENT_STATUS_MESSAGE:
1149       g_value_set_string (value, self->priv->cur_message);
1150       break;
1151     case PROP_CONNECTION_STATUS:
1152       g_value_set_uint (value, self->priv->connection_status);
1153       break;
1154     case PROP_CONNECTION_STATUS_REASON:
1155       g_value_set_uint (value, self->priv->reason);
1156       break;
1157     case PROP_CONNECTION_ERROR:
1158       g_value_set_string (value, self->priv->error);
1159       break;
1160     case PROP_CONNECTION_ERROR_DETAILS:
1161       g_value_set_boxed (value, self->priv->error_details);
1162       break;
1163     case PROP_CONNECTION:
1164       g_value_set_object (value,
1165           tp_account_get_connection (self));
1166       break;
1167     case PROP_DISPLAY_NAME:
1168       g_value_set_string (value,
1169           tp_account_get_display_name (self));
1170       break;
1171     case PROP_CONNECTION_MANAGER:
1172       g_value_set_string (value, self->priv->cm_name);
1173       break;
1174     case PROP_CM_NAME:
1175       g_value_set_string (value, self->priv->cm_name);
1176       break;
1177     case PROP_PROTOCOL:
1178       g_value_set_string (value, self->priv->proto_name);
1179       break;
1180     case PROP_PROTOCOL_NAME:
1181       g_value_set_string (value, self->priv->proto_name);
1182       break;
1183     case PROP_ICON_NAME:
1184       g_value_set_string (value, self->priv->icon_name);
1185       break;
1186     case PROP_CHANGING_PRESENCE:
1187       g_value_set_boolean (value, self->priv->changing_presence);
1188       break;
1189     case PROP_CONNECT_AUTOMATICALLY:
1190       g_value_set_boolean (value, self->priv->connect_automatically);
1191       break;
1192     case PROP_HAS_BEEN_ONLINE:
1193       g_value_set_boolean (value, self->priv->has_been_online);
1194       break;
1195     case PROP_SERVICE:
1196       g_value_set_string (value, self->priv->service);
1197       break;
1198     case PROP_VALID:
1199       g_value_set_boolean (value, self->priv->valid);
1200       break;
1201     case PROP_REQUESTED_PRESENCE_TYPE:
1202       g_value_set_uint (value, self->priv->requested_presence);
1203       break;
1204     case PROP_REQUESTED_STATUS:
1205       g_value_set_string (value, self->priv->requested_status);
1206       break;
1207     case PROP_REQUESTED_STATUS_MESSAGE:
1208       g_value_set_string (value, self->priv->requested_message);
1209       break;
1210     case PROP_NICKNAME:
1211       g_value_set_string (value, self->priv->nickname);
1212       break;
1213     case PROP_SUPERSEDES:
1214       g_value_set_boxed (value, self->priv->supersedes);
1215       break;
1216     case PROP_URI_SCHEMES:
1217       g_value_set_boxed (value, self->priv->uri_schemes);
1218       break;
1219     case PROP_AUTOMATIC_PRESENCE_TYPE:
1220       g_value_set_uint (value, self->priv->auto_presence);
1221       break;
1222     case PROP_AUTOMATIC_STATUS:
1223       g_value_set_string (value, self->priv->auto_status);
1224       break;
1225     case PROP_AUTOMATIC_STATUS_MESSAGE:
1226       g_value_set_string (value, self->priv->auto_message);
1227       break;
1228     case PROP_NORMALIZED_NAME:
1229       g_value_set_string (value,
1230           tp_account_get_normalized_name (self));
1231       break;
1232     case PROP_STORAGE_PROVIDER:
1233       g_value_set_string (value, self->priv->storage_provider);
1234       break;
1235     case PROP_STORAGE_IDENTIFIER:
1236       g_value_set_boxed (value, self->priv->storage_identifier);
1237       break;
1238     case PROP_STORAGE_IDENTIFIER_VARIANT:
1239       g_value_take_variant (value,
1240           tp_account_dup_storage_identifier_variant (self));
1241       break;
1242     case PROP_STORAGE_RESTRICTIONS:
1243       g_value_set_uint (value, self->priv->storage_restrictions);
1244       break;
1245     default:
1246       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1247       break;
1248     }
1249 }
1250 
1251 static void
_tp_account_dispose(GObject * object)1252 _tp_account_dispose (GObject *object)
1253 {
1254   TpAccount *self = TP_ACCOUNT (object);
1255   TpAccountPrivate *priv = self->priv;
1256 
1257   if (priv->dispose_has_run)
1258     return;
1259 
1260   priv->dispose_has_run = TRUE;
1261 
1262   _tp_account_set_connection (self, "/");
1263 
1264   /* release any references held by the object here */
1265   if (G_OBJECT_CLASS (tp_account_parent_class)->dispose != NULL)
1266     G_OBJECT_CLASS (tp_account_parent_class)->dispose (object);
1267 }
1268 
1269 static void
_tp_account_finalize(GObject * object)1270 _tp_account_finalize (GObject *object)
1271 {
1272   TpAccount *self = TP_ACCOUNT (object);
1273   TpAccountPrivate *priv = self->priv;
1274 
1275   g_free (priv->connection_object_path);
1276   g_free (priv->cur_status);
1277   g_free (priv->cur_message);
1278   g_free (priv->requested_status);
1279   g_free (priv->requested_message);
1280   g_free (priv->error);
1281   g_free (priv->auto_status);
1282   g_free (priv->auto_message);
1283   g_free (priv->normalized_name);
1284 
1285   g_free (priv->nickname);
1286   g_strfreev (priv->supersedes);
1287 
1288   g_free (priv->cm_name);
1289   g_free (priv->proto_name);
1290   g_free (priv->icon_name);
1291   g_free (priv->display_name);
1292   g_free (priv->service);
1293 
1294   tp_clear_pointer (&priv->parameters, g_hash_table_unref);
1295   tp_clear_pointer (&priv->error_details, g_hash_table_unref);
1296 
1297   g_free (priv->storage_provider);
1298   tp_clear_pointer (&priv->storage_identifier, tp_g_value_slice_free);
1299 
1300   g_strfreev (priv->uri_schemes);
1301 
1302   /* free any data held directly by the object here */
1303   if (G_OBJECT_CLASS (tp_account_parent_class)->finalize != NULL)
1304     G_OBJECT_CLASS (tp_account_parent_class)->finalize (object);
1305 }
1306 
1307 static void
tp_account_class_init(TpAccountClass * klass)1308 tp_account_class_init (TpAccountClass *klass)
1309 {
1310   TpProxyClass *proxy_class = (TpProxyClass *) klass;
1311   GObjectClass *object_class = (GObjectClass *) klass;
1312 
1313   g_type_class_add_private (klass, sizeof (TpAccountPrivate));
1314 
1315   object_class->constructed = _tp_account_constructed;
1316   object_class->get_property = _tp_account_get_property;
1317   object_class->dispose = _tp_account_dispose;
1318   object_class->finalize = _tp_account_finalize;
1319 
1320   /**
1321    * TpAccount:enabled:
1322    *
1323    * Whether this account is enabled or not.
1324    *
1325    * One can receive change notifications on this property by connecting
1326    * to the #GObject::notify signal and using this property as the signal
1327    * detail.
1328    *
1329    * This is not guaranteed to have been retrieved until
1330    * tp_proxy_prepare_async() has finished; until then, the value is FALSE.
1331    *
1332    * Since: 0.9.0
1333    */
1334   g_object_class_install_property (object_class, PROP_ENABLED,
1335       g_param_spec_boolean ("enabled",
1336           "Enabled",
1337           "Whether this account is enabled or not",
1338           FALSE,
1339           G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
1340 
1341   /**
1342    * TpAccount:current-presence-type:
1343    *
1344    * The account connection's current presence type
1345    * (a %TpConnectionPresenceType).
1346    *
1347    * One can receive change notifications on this property by connecting
1348    * to the #GObject::notify signal and using this property as the signal
1349    * detail. Change notifications for current-presence-type,
1350    * current-status and current-status-message are always emitted together,
1351    * so it is sufficient to connect to one of the notification signals.
1352    *
1353    * This is not guaranteed to have been retrieved until
1354    * tp_proxy_prepare_async() has finished; until then, the value is
1355    * %TP_CONNECTION_PRESENCE_TYPE_UNSET.
1356    *
1357    * Since: 0.9.0
1358    */
1359   g_object_class_install_property (object_class, PROP_CURRENT_PRESENCE_TYPE,
1360       g_param_spec_uint ("current-presence-type",
1361           "Presence",
1362           "The account connection's current presence type",
1363           0,
1364           TP_NUM_CONNECTION_PRESENCE_TYPES,
1365           TP_CONNECTION_PRESENCE_TYPE_UNSET,
1366           G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
1367 
1368   /**
1369    * TpAccount:current-status:
1370    *
1371    * The current Status string of the account.
1372    *
1373    * One can receive change notifications on this property by connecting
1374    * to the #GObject::notify signal and using this property as the signal
1375    * detail. Change notifications for current-presence-type,
1376    * current-status and current-status-message are always emitted together,
1377    * so it is sufficient to connect to one of the notification signals.
1378    *
1379    * This is not guaranteed to have been retrieved until
1380    * tp_proxy_prepare_async() has finished; until then, the value is
1381    * %NULL.
1382    *
1383    * Since: 0.9.0
1384    */
1385   g_object_class_install_property (object_class, PROP_CURRENT_STATUS,
1386       g_param_spec_string ("current-status",
1387           "Current Status",
1388           "The Status string of the account",
1389           NULL,
1390           G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
1391 
1392   /**
1393    * TpAccount:current-status-message:
1394    *
1395    * The current status message message of the account.
1396    *
1397    * One can receive change notifications on this property by connecting
1398    * to the #GObject::notify signal and using this property as the signal
1399    * detail. Change notifications for current-presence-type,
1400    * current-status and current-status-message are always emitted together,
1401    * so it is sufficient to connect to one of the notification signals.
1402    *
1403    * This is not guaranteed to have been retrieved until
1404    * tp_proxy_prepare_async() has finished; until then, the value is
1405    * %NULL.
1406    *
1407    * Since: 0.9.0
1408    */
1409   g_object_class_install_property (object_class, PROP_CURRENT_STATUS_MESSAGE,
1410       g_param_spec_string ("current-status-message",
1411           "current-status-message",
1412           "The Status message string of the account",
1413           NULL,
1414           G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
1415 
1416   /**
1417    * TpAccount:changing-presence:
1418    *
1419    * %TRUE if an attempt is currently being made to change the account's
1420    * presence (#TpAccount:current-presence-type, #TpAccount:current-status
1421    * and #TpAccount:current-status-message) to match its requested presence
1422    * (#TpAccount:requested-presence-type, #TpAccount:requested-status
1423    * and #TpAccount:requested-status-message).
1424    *
1425    * One can receive change notifications on this property by connecting
1426    * to the #GObject::notify signal and using this property as the signal
1427    * detail.
1428    *
1429    * This is not guaranteed to have been retrieved until
1430    * tp_proxy_prepare_async() has finished; until then, the value is
1431    * %FALSE.
1432    *
1433    * Since: 0.11.6
1434    */
1435   g_object_class_install_property (object_class, PROP_CHANGING_PRESENCE,
1436       g_param_spec_boolean ("changing-presence",
1437           "Changing Presence",
1438           "TRUE if presence is changing",
1439           FALSE,
1440           G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
1441 
1442   /**
1443    * TpAccount:connection-status:
1444    *
1445    * The account's connection status type (a %TpConnectionStatus).
1446    *
1447    * One can receive change notifications on this property by connecting
1448    * to the #TpAccount::status-changed signal, or by connecting
1449    * to the #GObject::notify signal and using this property as the signal
1450    * detail.
1451    *
1452    * This is not guaranteed to have been retrieved until
1453    * tp_proxy_prepare_async() has finished; until then, the value is
1454    * %TP_CONNECTION_STATUS_DISCONNECTED.
1455    *
1456    * Since: 0.9.0
1457    */
1458   g_object_class_install_property (object_class, PROP_CONNECTION_STATUS,
1459       g_param_spec_uint ("connection-status",
1460           "ConnectionStatus",
1461           "The account's connection status type",
1462           0,
1463           TP_NUM_CONNECTION_STATUSES,
1464           TP_CONNECTION_STATUS_DISCONNECTED,
1465           G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
1466 
1467   /**
1468    * TpAccount:connection-status-reason:
1469    *
1470    * The account's connection status reason (a %TpConnectionStatusReason).
1471    *
1472    * One can receive change notifications on this property by connecting
1473    * to the #TpAccount::status-changed signal, or by connecting
1474    * to the #GObject::notify signal and using this property as the signal
1475    * detail.
1476    *
1477    * This is not guaranteed to have been retrieved until
1478    * tp_proxy_prepare_async() has finished; until then, the value is
1479    * %TP_CONNECTION_STATUS_REASON_NONE_SPECIFIED.
1480    *
1481    * Since: 0.9.0
1482    */
1483   g_object_class_install_property (object_class, PROP_CONNECTION_STATUS_REASON,
1484       g_param_spec_uint ("connection-status-reason",
1485           "ConnectionStatusReason",
1486           "The account's connection status reason",
1487           0,
1488           TP_NUM_CONNECTION_STATUS_REASONS,
1489           TP_CONNECTION_STATUS_REASON_NONE_SPECIFIED,
1490           G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
1491 
1492   /**
1493    * TpAccount:connection-error:
1494    *
1495    * The D-Bus error name for the last disconnection or connection failure,
1496    * (in particular, %TP_ERROR_STR_CANCELLED if it was disconnected by user
1497    * request), or %NULL if the account is connected.
1498    *
1499    * One can receive change notifications on this property by connecting
1500    * to the #TpAccount::status-changed signal, or by connecting
1501    * to the #GObject::notify signal and using this property as the signal
1502    * detail.
1503    *
1504    * This is not guaranteed to have been retrieved until
1505    * tp_proxy_prepare_async() has finished; until then, the value is
1506    * %NULL.
1507    *
1508    * Since: 0.11.7
1509    */
1510   g_object_class_install_property (object_class, PROP_CONNECTION_ERROR,
1511       g_param_spec_string ("connection-error",
1512           "ConnectionError",
1513           "The account's last connection error",
1514           NULL,
1515           G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
1516 
1517   /**
1518    * TpAccount:connection-error-details:
1519    *
1520    * A map from string to #GValue containing extensible error details
1521    * related to #TpAccount:connection-error. Functions like tp_asv_get_string()
1522    * can be used to read from this map.
1523    *
1524    * The keys for this map are defined by
1525    * <ulink url="http://telepathy.freedesktop.org/spec/">the Telepathy D-Bus
1526    * Interface Specification</ulink>. They will typically include
1527    * <literal>debug-message</literal>, which is a debugging message in the C
1528    * locale, analogous to #GError<!-- -->.message.
1529    *
1530    * One can receive change notifications on this property by connecting
1531    * to the #TpAccount::status-changed signal, or by connecting
1532    * to the #GObject::notify signal and using this property as the signal
1533    * detail.
1534    *
1535    * This is not guaranteed to have been retrieved until
1536    * tp_proxy_prepare_async() has finished; until then, the value is
1537    * an empty map.
1538    *
1539    * Since: 0.11.7
1540    */
1541   g_object_class_install_property (object_class, PROP_CONNECTION_ERROR_DETAILS,
1542       g_param_spec_boxed ("connection-error-details",
1543           "ConnectionErrorDetails",
1544           "Extensible details of the account's last connection error",
1545           G_TYPE_HASH_TABLE,
1546           G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
1547 
1548   /**
1549    * TpAccount:connection:
1550    *
1551    * The connection of the account, or %NULL if account is offline.
1552    * Note that the returned #TpConnection is not guaranteed to have any
1553    * features pre-prepared (not even %TP_CONNECTION_FEATURE_CORE) unless
1554    * %TP_ACCOUNT_FEATURE_CONNECTION has been prepared on the account
1555    *
1556    * One can receive change notifications on this property by connecting
1557    * to the #GObject::notify signal and using this property as the signal
1558    * detail. If %TP_ACCOUNT_FEATURE_CONNECTION has been prepared, this signal
1559    * will be delayed until the connection is ready.
1560    *
1561    * This is not guaranteed to have been retrieved until
1562    * tp_proxy_prepare_async() has finished; until then, the value is
1563    * %NULL.
1564    *
1565    * Since: 0.9.0
1566    */
1567   g_object_class_install_property (object_class, PROP_CONNECTION,
1568       g_param_spec_object ("connection",
1569           "Connection",
1570           "The account's connection",
1571           TP_TYPE_CONNECTION,
1572           G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
1573 
1574   /**
1575    * TpAccount:display-name:
1576    *
1577    * The account's display name, from the DisplayName property.
1578    *
1579    * One can receive change notifications on this property by connecting
1580    * to the #GObject::notify signal and using this property as the signal
1581    * detail.
1582    *
1583    * This is not guaranteed to have been retrieved until
1584    * tp_proxy_prepare_async() has finished; until then, the value is
1585    * %NULL.
1586    *
1587    * Since: 0.9.0
1588    */
1589   g_object_class_install_property (object_class, PROP_DISPLAY_NAME,
1590       g_param_spec_string ("display-name",
1591           "DisplayName",
1592           "The account's display name",
1593           NULL,
1594           G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
1595 
1596   /**
1597    * TpAccount:connection-manager:
1598    *
1599    * The account's connection manager name.
1600    *
1601    * Since: 0.9.0
1602    * Deprecated: Use #TpAccount:cm-name instead.
1603    */
1604   g_object_class_install_property (object_class, PROP_CONNECTION_MANAGER,
1605       g_param_spec_string ("connection-manager",
1606           "Connection manager",
1607           "The account's connection manager name",
1608           NULL,
1609           G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
1610 
1611   /**
1612    * TpAccount:protocol:
1613    *
1614    * The account's machine-readable protocol name, such as "jabber", "msn" or
1615    * "local-xmpp". Recommended names for most protocols can be found in the
1616    * Telepathy D-Bus Interface Specification.
1617    *
1618    * Since: 0.9.0
1619    * Deprecated: Use #TpAccount:protocol-name instead.
1620    */
1621   g_object_class_install_property (object_class, PROP_PROTOCOL,
1622       g_param_spec_string ("protocol",
1623           "Protocol",
1624           "The account's protocol name",
1625           NULL,
1626           G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
1627 
1628   /**
1629    * TpAccount:cm-name:
1630    *
1631    * The account's connection manager name.
1632    *
1633    * Since: 0.19.3
1634    */
1635   g_object_class_install_property (object_class, PROP_CM_NAME,
1636       g_param_spec_string ("cm-name",
1637           "Connection manager",
1638           "The account's connection manager name",
1639           NULL,
1640           G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
1641 
1642   /**
1643    * TpAccount:protocol-name:
1644    *
1645    * The account's machine-readable protocol name, such as "jabber", "msn" or
1646    * "local-xmpp". Recommended names for most protocols can be found in the
1647    * Telepathy D-Bus Interface Specification.
1648    *
1649    * Since: 0.19.3
1650    */
1651   g_object_class_install_property (object_class, PROP_PROTOCOL_NAME,
1652       g_param_spec_string ("protocol-name",
1653           "Protocol",
1654           "The account's protocol name",
1655           NULL,
1656           G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
1657 
1658   /**
1659    * TpAccount:service:
1660    *
1661    * A machine-readable name identifying a specific service to which this
1662    * account connects, or a copy of #TpAccount:protocol if there is no more
1663    * specific service.
1664    *
1665    * Well-known names for various services can be found in the Telepathy D-Bus
1666    * Interface Specification.
1667    *
1668    * For instance, accounts for the "jabber" protocol should have the service
1669    * names "google-talk", "ovi-chat", "facebook" and "lj-talk" for accounts
1670    * that connect to Google Talk, Ovi Chat, Facebook and Livejournal,
1671    * respectively, and this property will be "jabber" for accounts that
1672    * connect to a generic Jabber server.
1673    *
1674    * To change this property, use
1675    * tp_account_set_service_async().
1676    *
1677    * Since: 0.11.9
1678    */
1679   g_object_class_install_property (object_class, PROP_SERVICE,
1680       g_param_spec_string ("service",
1681           "Service",
1682           "The account's service name",
1683           NULL,
1684           G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
1685 
1686   /**
1687    * TpAccount:icon-name:
1688    *
1689    * The account's icon name. To change this propery, use
1690    * tp_account_set_icon_name_async().
1691    *
1692    * One can receive change notifications on this property by connecting
1693    * to the #GObject::notify signal and using this property as the signal
1694    * detail.
1695    *
1696    * This is not guaranteed to have been retrieved until
1697    * tp_proxy_prepare_async() has finished; until then, the value is
1698    * %NULL.
1699    *
1700    * Since: 0.9.0
1701    */
1702   g_object_class_install_property (object_class, PROP_ICON_NAME,
1703       g_param_spec_string ("icon-name",
1704           "Icon",
1705           "The account's icon name",
1706           NULL,
1707           G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
1708 
1709   /**
1710    * TpAccount:connect-automatically:
1711    *
1712    * Whether the account should connect automatically or not. To change this
1713    * property, use tp_account_set_connect_automatically_async().
1714    *
1715    * One can receive change notifications on this property by connecting
1716    * to the #GObject::notify signal and using this property as the signal
1717    * detail.
1718    *
1719    * This is not guaranteed to have been retrieved until
1720    * tp_proxy_prepare_async() has finished; until then, the value is
1721    * %FALSE.
1722    *
1723    * Since: 0.9.0
1724    */
1725   g_object_class_install_property (object_class, PROP_CONNECT_AUTOMATICALLY,
1726       g_param_spec_boolean ("connect-automatically",
1727           "ConnectAutomatically",
1728           "Whether this account should connect automatically or not",
1729           FALSE,
1730           G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
1731 
1732   /**
1733    * TpAccount:has-been-online:
1734    *
1735    * Whether this account has been online or not.
1736    *
1737    * One can receive change notifications on this property by connecting
1738    * to the #GObject::notify signal and using this property as the signal
1739    * detail.
1740    *
1741    * This is not guaranteed to have been retrieved until
1742    * tp_proxy_prepare_async() has finished; until then, the value is
1743    * %FALSE.
1744    *
1745    * Since: 0.9.0
1746    */
1747   g_object_class_install_property (object_class, PROP_HAS_BEEN_ONLINE,
1748       g_param_spec_boolean ("has-been-online",
1749           "HasBeenOnline",
1750           "Whether this account has been online or not",
1751           FALSE,
1752           G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
1753 
1754   /**
1755    * TpAccount:valid:
1756    *
1757    * Whether this account is valid.
1758    *
1759    * One can receive change notifications on this property by connecting
1760    * to the #GObject::notify signal and using this property as the signal
1761    * detail.
1762    *
1763    * This is not guaranteed to have been retrieved until
1764    * tp_proxy_prepare_async() has finished; until then, the value is
1765    * %FALSE.
1766    *
1767    * Since: 0.9.0
1768    */
1769   g_object_class_install_property (object_class, PROP_VALID,
1770       g_param_spec_boolean ("valid",
1771           "Valid",
1772           "Whether this account is valid",
1773           FALSE,
1774           G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
1775 
1776   /**
1777    * TpAccount:requested-presence-type:
1778    *
1779    * The account's requested presence type (a #TpConnectionPresenceType).
1780    *
1781    * Since 0.13.8,
1782    * one can receive change notifications on this property by connecting
1783    * to the #GObject::notify signal and using this property as the signal
1784    * detail. Change notifications for requested-presence-type,
1785    * requested-status and requested-status-message are always emitted together,
1786    * so it is sufficient to connect to one of the notification signals.
1787    *
1788    * This is not guaranteed to have been retrieved until
1789    * tp_proxy_prepare_async() has finished; until then, the value is
1790    * %NULL.
1791    *
1792    * Since: 0.9.0
1793    */
1794   g_object_class_install_property (object_class, PROP_REQUESTED_PRESENCE_TYPE,
1795       g_param_spec_uint ("requested-presence-type",
1796           "RequestedPresence",
1797           "The account's requested presence type",
1798           0,
1799           TP_NUM_CONNECTION_PRESENCE_TYPES,
1800           TP_CONNECTION_PRESENCE_TYPE_UNSET,
1801           G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
1802 
1803   /**
1804    * TpAccount:requested-status:
1805    *
1806    * The requested Status string of the account.
1807    *
1808    * Since 0.13.8,
1809    * one can receive change notifications on this property by connecting
1810    * to the #GObject::notify signal and using this property as the signal
1811    * detail. Change notifications for requested-presence-type,
1812    * requested-status and requested-status-message are always emitted together,
1813    * so it is sufficient to connect to one of the notification signals.
1814    *
1815    * This is not guaranteed to have been retrieved until
1816    * tp_proxy_prepare_async() has finished; until then, the value is
1817    * %NULL.
1818    *
1819    * Since: 0.9.0
1820    */
1821   g_object_class_install_property (object_class, PROP_REQUESTED_STATUS,
1822       g_param_spec_string ("requested-status",
1823           "RequestedStatus",
1824           "The account's requested status string",
1825           NULL,
1826           G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
1827 
1828   /**
1829    * TpAccount:requested-status-message:
1830    *
1831    * The requested status message message of the account.
1832    *
1833    * Since 0.13.8,
1834    * one can receive change notifications on this property by connecting
1835    * to the #GObject::notify signal and using this property as the signal
1836    * detail. Change notifications for requested-presence-type,
1837    * requested-status and requested-status-message are always emitted together,
1838    * so it is sufficient to connect to one of the notification signals.
1839    *
1840    * This is not guaranteed to have been retrieved until
1841    * tp_proxy_prepare_async() has finished; until then, the value is
1842    * %NULL.
1843    *
1844    * Since: 0.9.0
1845    */
1846   g_object_class_install_property (object_class, PROP_REQUESTED_STATUS_MESSAGE,
1847       g_param_spec_string ("requested-status-message",
1848           "RequestedStatusMessage",
1849           "The requested Status message string of the account",
1850           NULL,
1851           G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
1852 
1853   /**
1854    * TpAccount:nickname:
1855    *
1856    * The nickname that should be set for the user on this account.
1857    *
1858    * One can receive change notifications on this property by connecting
1859    * to the #GObject::notify signal and using this property as the signal
1860    * detail.
1861    *
1862    * This is not guaranteed to have been retrieved until
1863    * tp_proxy_prepare_async() has finished; until then, the value is
1864    * %NULL.
1865    *
1866    * Since: 0.9.0
1867    */
1868   g_object_class_install_property (object_class, PROP_NICKNAME,
1869       g_param_spec_string ("nickname",
1870           "Nickname",
1871           "The account's nickname",
1872           NULL,
1873           G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
1874 
1875   /**
1876    * TpAccount:automatic-presence-type:
1877    *
1878    * The account's automatic presence type (a #TpConnectionPresenceType).
1879    *
1880    * When the account is put online automatically, for instance to make a
1881    * channel request or because network connectivity becomes available,
1882    * the automatic presence type, status and message will be copied to
1883    * their "requested" counterparts.
1884    *
1885    * One can receive change notifications on this property by connecting
1886    * to the #GObject::notify signal and using this property as the signal
1887    * detail. Change notifications for automatic-presence-type,
1888    * automatic-status and automatic-status-message are always emitted together,
1889    * so it is sufficient to connect to one of the notification signals.
1890    *
1891    * This is not guaranteed to have been retrieved until
1892    * tp_proxy_prepare_async() has finished; until then, the value is
1893    * %TP_CONNECTION_PRESENCE_TYPE_UNSET.
1894    *
1895    * Since: 0.13.8
1896    */
1897   g_object_class_install_property (object_class, PROP_AUTOMATIC_PRESENCE_TYPE,
1898       g_param_spec_uint ("automatic-presence-type",
1899           "AutomaticPresence type",
1900           "Presence type used to put the account online automatically",
1901           0,
1902           TP_NUM_CONNECTION_PRESENCE_TYPES,
1903           TP_CONNECTION_PRESENCE_TYPE_UNSET,
1904           G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
1905 
1906   /**
1907    * TpAccount:automatic-status:
1908    *
1909    * The string status name to use in conjunction with the
1910    * #TpAccount:automatic-presence-type.
1911    *
1912    * One can receive change notifications on this property by connecting
1913    * to the #GObject::notify signal and using this property as the signal
1914    * detail. Change notifications for automatic-presence-type,
1915    * automatic-status and automatic-status-message are always emitted together,
1916    * so it is sufficient to connect to one of the notification signals.
1917    *
1918    * This is not guaranteed to have been retrieved until
1919    * tp_proxy_prepare_async() has finished; until then, the value is
1920    * %NULL.
1921    *
1922    * Since: 0.13.8
1923    */
1924   g_object_class_install_property (object_class, PROP_AUTOMATIC_STATUS,
1925       g_param_spec_string ("automatic-status",
1926           "AutomaticPresence status",
1927           "Presence status used to put the account online automatically",
1928           NULL,
1929           G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
1930 
1931   /**
1932    * TpAccount:automatic-status-message:
1933    *
1934    * The user-defined message to use in conjunction with the
1935    * #TpAccount:automatic-presence-type.
1936    *
1937    * One can receive change notifications on this property by connecting
1938    * to the #GObject::notify signal and using this property as the signal
1939    * detail. Change notifications for automatic-presence-type,
1940    * automatic-status and automatic-status-message are always emitted together,
1941    * so it is sufficient to connect to one of the notification signals.
1942    *
1943    * This is not guaranteed to have been retrieved until
1944    * tp_proxy_prepare_async() has finished; until then, the value is
1945    * %NULL.
1946    *
1947    * Since: 0.13.8
1948    */
1949   g_object_class_install_property (object_class, PROP_AUTOMATIC_STATUS_MESSAGE,
1950       g_param_spec_string ("automatic-status-message",
1951           "AutomaticPresence message",
1952           "User-defined message used to put the account online automatically",
1953           NULL,
1954           G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
1955 
1956   /**
1957    * TpAccount:normalized-name:
1958    *
1959    * The normalized form of the user's own unique identifier on this
1960    * protocol. For example, on XMPP accounts this is the user's JID; on
1961    * ICQ this is the user's UIN; and so on.
1962    *
1963    * One can receive change notifications on this property by connecting
1964    * to the #GObject::notify signal and using this property as the signal
1965    * detail.
1966    *
1967    * This is not guaranteed to have been retrieved until
1968    * tp_proxy_prepare_async() has finished; until then, the value is
1969    * %NULL.
1970    *
1971    * Since: 0.13.8
1972    */
1973   g_object_class_install_property (object_class, PROP_NORMALIZED_NAME,
1974       g_param_spec_string ("normalized-name",
1975           "NormalizedName",
1976           "The normalized identifier of the user",
1977           NULL,
1978           G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
1979 
1980   /**
1981    * TpAccount:storage-provider:
1982    *
1983    * The storage provider for this account.
1984    *
1985    * The name of the account storage implementation. When this
1986    * is the empty string the account is internally stored.
1987    *
1988    * This property cannot change once an Account has been created.
1989    *
1990    * This is not guaranteed to have been retrieved until the
1991    * %TP_ACCOUNT_FEATURE_STORAGE feature has been prepared; until then,
1992    * the value is %NULL.
1993    *
1994    * Since: 0.13.2
1995    */
1996   g_object_class_install_property (object_class, PROP_STORAGE_PROVIDER,
1997       g_param_spec_string ("storage-provider",
1998         "StorageProvider",
1999         "The storage provider for this account",
2000         NULL,
2001         G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
2002 
2003   /**
2004    * TpAccount:storage-identifier:
2005    *
2006    * The storage identifier for this account.
2007    *
2008    * A provider-specific variant type used to identify this account with the
2009    * provider. This value will be %NULL if #TpAccount:storage-provider is
2010    * an empty string.
2011    *
2012    * This property cannot change once an Account has been created.
2013    *
2014    * This is not guaranteed to have been retrieved until the
2015    * %TP_ACCOUNT_FEATURE_STORAGE feature has been prepared; until then,
2016    * the value is %NULL.
2017    *
2018    * Since: 0.13.2
2019    */
2020   g_object_class_install_property (object_class, PROP_STORAGE_IDENTIFIER,
2021       g_param_spec_boxed ("storage-identifier",
2022         "StorageIdentifier",
2023         "The storage identifier for this account",
2024         G_TYPE_VALUE,
2025         G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
2026 
2027   /**
2028    * TpAccount:storage-identifier-variant:
2029    *
2030    * Provider-specific information used to identify this
2031    * account. Use g_variant_get_type() to check that the type
2032    * is what you expect. For instance, if you use a
2033    * #TpAccount:storage-provider with numeric identifiers for accounts,
2034    * this variant might have type %G_VARIANT_TYPE_UINT32;
2035    * if the storage provider has string-based identifiers, it should
2036    * have type %G_VARIANT_TYPE_STRING.
2037    *
2038    * This property cannot change once an Account has been created.
2039    *
2040    * This is not guaranteed to have been retrieved until the
2041    * %TP_ACCOUNT_FEATURE_STORAGE feature has been prepared; until then,
2042    * the value is %NULL.
2043    *
2044    * Since: 0.13.2
2045    */
2046   g_object_class_install_property (object_class,
2047       PROP_STORAGE_IDENTIFIER_VARIANT,
2048       g_param_spec_variant ("storage-identifier-variant",
2049         "StorageIdentifier as variant",
2050         "The storage identifier for this account",
2051         G_VARIANT_TYPE_ANY,
2052         NULL,
2053         G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
2054 
2055   /**
2056    * TpAccount:storage-restrictions:
2057    *
2058    * The storage restrictions for this account.
2059    *
2060    * A bitfield of #TpStorageRestrictionFlags that give the limitations of
2061    * this account imposed by the storage provider. This value will be 0
2062    * if #TpAccount:storage-provider is an empty string.
2063    *
2064    * This property cannot change once an Account has been created.
2065    *
2066    * This is not guaranteed to have been retrieved until the
2067    * %TP_ACCOUNT_FEATURE_STORAGE feature has been prepared; until then,
2068    * the value is 0.
2069    *
2070    * Since: 0.13.2
2071    */
2072   g_object_class_install_property (object_class, PROP_STORAGE_RESTRICTIONS,
2073       g_param_spec_uint ("storage-restrictions",
2074         "StorageRestrictions",
2075         "The storage restrictions for this account",
2076         0, G_MAXUINT, 0,
2077         G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
2078 
2079   /**
2080    * TpAccount:supersedes:
2081    *
2082    * The object paths of previously-active accounts superseded by this one.
2083    * For instance, this can be used in a logger to read old logs for an
2084    * account that has been migrated from one connection manager to another.
2085    *
2086    * This is not guaranteed to have been retrieved until the
2087    * %TP_ACCOUNT_FEATURE_CORE feature has been prepared; until then,
2088    * the value is NULL.
2089    *
2090    * Since: 0.17.5
2091    */
2092   g_object_class_install_property (object_class, PROP_SUPERSEDES,
2093       g_param_spec_boxed ("supersedes",
2094         "Supersedes",
2095         "Accounts superseded by this one",
2096         G_TYPE_STRV,
2097         G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
2098 
2099   /**
2100    * TpAccount:uri-schemes:
2101    *
2102    * If the %TP_ACCOUNT_FEATURE_ADDRESSING feature has been prepared
2103    * successfully, a list of additional URI schemes for which this
2104    * account should be used if possible. Otherwise %NULL.
2105    *
2106    * For instance, a SIP or Skype account might have "tel" in this list if the
2107    * user would like to use that account to call phone numbers.
2108    *
2109    * This list should not contain the primary URI scheme(s) for the account's
2110    * protocol (for instance, "xmpp" for XMPP, or "sip" or "sips" for SIP),
2111    * since it should be assumed to be useful for those schemes in any case.
2112    *
2113    * The notify::uri-schemes signal cannot be relied on if the Account Manager
2114    * is Mission Control version 5.14.0 or older.
2115    *
2116    * Since: 0.21.0
2117    */
2118   g_object_class_install_property (object_class, PROP_URI_SCHEMES,
2119       g_param_spec_boxed ("uri-schemes",
2120         "URISchemes",
2121         "URISchemes",
2122         G_TYPE_STRV,
2123         G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
2124 
2125   /**
2126    * TpAccount::status-changed:
2127    * @account: the #TpAccount
2128    * @old_status: old #TpAccount:connection-status
2129    * @new_status: new #TpAccount:connection-status
2130    * @reason: the #TpAccount:connection-status-reason
2131    * @dbus_error_name: (allow-none): the #TpAccount:connection-error
2132    * @details: (element-type utf8 GObject.Value): the
2133    *  #TpAccount:connection-error-details
2134    *
2135    * Emitted when the connection status on the account changes.
2136    *
2137    * The @dbus_error_name and @details parameters were present, but
2138    * non-functional (always %NULL), in older versions. They have been
2139    * available with their current behaviour since version 0.11.7.
2140    *
2141    * Since: 0.9.0
2142    */
2143   signals[STATUS_CHANGED] = g_signal_new ("status-changed",
2144       G_TYPE_FROM_CLASS (object_class),
2145       G_SIGNAL_RUN_LAST,
2146       0, NULL, NULL, NULL,
2147       G_TYPE_NONE, 5, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING,
2148       G_TYPE_HASH_TABLE);
2149 
2150   /**
2151    * TpAccount::presence-changed:
2152    * @account: the #TpAccount
2153    * @presence: the new presence
2154    * @status: the new presence status
2155    * @status_message: the new presence status message
2156    *
2157    * Emitted when the presence of the account changes.
2158    *
2159    * Since: 0.9.0
2160    */
2161   signals[PRESENCE_CHANGED] = g_signal_new ("presence-changed",
2162       G_TYPE_FROM_CLASS (object_class),
2163       G_SIGNAL_RUN_LAST,
2164       0, NULL, NULL, NULL,
2165       G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING);
2166 
2167   /**
2168    * TpAccount::avatar-changed:
2169    * @self: a #TpAccount
2170    *
2171    * Emitted when the avatar changes. Call tp_account_get_avatar_async()
2172    * to get the new avatar data.
2173    *
2174    * Since: 0.23.0
2175    */
2176   signals[AVATAR_CHANGED] = g_signal_new ("avatar-changed",
2177       G_OBJECT_CLASS_TYPE (klass),
2178       G_SIGNAL_RUN_LAST,
2179       0, NULL, NULL, NULL,
2180       G_TYPE_NONE,
2181       0);
2182 
2183   proxy_class->interface = TP_IFACE_QUARK_ACCOUNT;
2184   proxy_class->list_features = _tp_account_list_features;
2185   tp_account_init_known_interfaces ();
2186 }
2187 
2188 /**
2189  * tp_account_init_known_interfaces:
2190  *
2191  * Ensure that the known interfaces for TpAccount have been set up.
2192  * This is done automatically when necessary, but for correct
2193  * overriding of library interfaces by local extensions, you should
2194  * call this function before calling
2195  * tp_proxy_or_subclass_hook_on_interface_add() with first argument
2196  * %TP_TYPE_ACCOUNT.
2197  *
2198  * Since: 0.7.32
2199  */
2200 void
tp_account_init_known_interfaces(void)2201 tp_account_init_known_interfaces (void)
2202 {
2203   static gsize once = 0;
2204 
2205   if (g_once_init_enter (&once))
2206     {
2207       GType tp_type = TP_TYPE_ACCOUNT;
2208 
2209       tp_proxy_init_known_interfaces ();
2210       tp_proxy_or_subclass_hook_on_interface_add (tp_type,
2211           tp_cli_account_add_signals);
2212       tp_proxy_subclass_add_error_mapping (tp_type,
2213           TP_ERROR_PREFIX, TP_ERROR, TP_TYPE_ERROR);
2214 
2215       g_once_init_leave (&once, 1);
2216     }
2217 }
2218 
2219 /**
2220  * tp_account_new:
2221  * @bus_daemon: Proxy for the D-Bus daemon
2222  * @object_path: The non-NULL object path of this account
2223  * @error: Used to raise an error if @object_path is not valid
2224  *
2225  * Convenience function to create a new account proxy. The returned #TpAccount
2226  * is not guaranteed to be ready at the point of return.
2227  *
2228  * Returns: a new reference to an account proxy, or %NULL if @object_path is
2229  *    not valid
2230  * Deprecated: Use tp_simple_client_factory_ensure_account() instead.
2231  */
2232 TpAccount *
tp_account_new(TpDBusDaemon * bus_daemon,const gchar * object_path,GError ** error)2233 tp_account_new (TpDBusDaemon *bus_daemon,
2234     const gchar *object_path,
2235     GError **error)
2236 {
2237   return _tp_account_new_with_factory (NULL, bus_daemon, object_path, error);
2238 }
2239 
2240 TpAccount *
_tp_account_new_with_factory(TpSimpleClientFactory * factory,TpDBusDaemon * bus_daemon,const gchar * object_path,GError ** error)2241 _tp_account_new_with_factory (TpSimpleClientFactory *factory,
2242     TpDBusDaemon *bus_daemon,
2243     const gchar *object_path,
2244     GError **error)
2245 {
2246   TpAccount *self;
2247 
2248   g_return_val_if_fail (TP_IS_DBUS_DAEMON (bus_daemon), NULL);
2249   g_return_val_if_fail (object_path != NULL, NULL);
2250   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
2251 
2252   G_GNUC_BEGIN_IGNORE_DEPRECATIONS
2253   if (!tp_account_parse_object_path (object_path, NULL, NULL, NULL, error))
2254     return NULL;
2255   G_GNUC_END_IGNORE_DEPRECATIONS
2256 
2257   self = TP_ACCOUNT (g_object_new (TP_TYPE_ACCOUNT,
2258           "dbus-daemon", bus_daemon,
2259           "dbus-connection", ((TpProxy *) bus_daemon)->dbus_connection,
2260           "bus-name", TP_ACCOUNT_MANAGER_BUS_NAME,
2261           "object-path", object_path,
2262           "factory", factory,
2263           NULL));
2264 
2265   return self;
2266 }
2267 
2268 static gchar *
unescape_protocol(gchar * protocol)2269 unescape_protocol (gchar *protocol)
2270 {
2271   if (strstr (protocol, "_2d") != NULL)
2272     {
2273       /* Work around MC5 bug where it escapes with tp_escape_as_identifier
2274        * rather than doing it properly. MC5 saves the object path in your
2275        * config, so if you've ever used a buggy MC5, the path will be wrong
2276        * forever.
2277        */
2278       gchar **chunks = g_strsplit (protocol, "_2d", 0);
2279       gchar *new = g_strjoinv ("-", chunks);
2280 
2281       g_strfreev (chunks);
2282       g_free (protocol);
2283       protocol = new;
2284     }
2285 
2286   g_strdelimit (protocol, "_", '-');
2287 
2288   return protocol;
2289 }
2290 
2291 /**
2292  * tp_account_get_connection:
2293  * @account: a #TpAccount
2294  *
2295  * <!-- -->
2296  *
2297  * Returns: (transfer none): the same as the #TpAccount:connection property
2298  *
2299  * Since: 0.9.0
2300  **/
2301 TpConnection *
tp_account_get_connection(TpAccount * account)2302 tp_account_get_connection (TpAccount *account)
2303 {
2304   TpAccountPrivate *priv;
2305 
2306   g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
2307 
2308   priv = account->priv;
2309 
2310   /* If we want to expose only prepared connection */
2311   if (connection_is_internal (account))
2312     return NULL;
2313 
2314   return priv->connection;
2315 }
2316 
2317 /**
2318  * tp_account_ensure_connection:
2319  * @account: a #TpAccount
2320  * @path: the path to connection object for #TpAccount
2321  *
2322  * Set the connection of the account by specifying the connection object path.
2323  * This function does not return a new ref and it is not guaranteed that the
2324  * returned #TpConnection object is ready.
2325  *
2326  * The use-case for this function is in a HandleChannels callback and you
2327  * already know the object path for the connection, so you can let @account
2328  * create its #TpConnection and return it for use.
2329  *
2330  * Returns: (transfer none): the connection of the account, or %NULL if either
2331  *  the object path @path is invalid or it is the null-value "/"
2332  *
2333  * Since: 0.9.0
2334  * Deprecated: New code should use tp_simple_client_factory_ensure_connection()
2335  *  instead.
2336  **/
2337 TpConnection *
tp_account_ensure_connection(TpAccount * account,const gchar * path)2338 tp_account_ensure_connection (TpAccount *account,
2339     const gchar *path)
2340 {
2341   TpAccountPrivate *priv;
2342 
2343   g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
2344 
2345   priv = account->priv;
2346 
2347   /* double-check that the object path is valid */
2348   if (!tp_dbus_check_valid_object_path (path, NULL))
2349     return NULL;
2350 
2351   /* Should be a full object path, not the special "/" value */
2352   if (!tp_strdiff (path, "/"))
2353     return NULL;
2354 
2355   _tp_account_set_connection (account, path);
2356 
2357   return priv->connection;
2358 }
2359 
2360 /**
2361  * tp_account_get_path_suffix:
2362  * @account: a #TpAccount
2363  *
2364  * Returns the portion of @account's object path after the standard
2365  * #TP_ACCOUNT_OBJECT_PATH_BASE prefix, of the form "cm/protocol/acct". This
2366  * string uniquely identifies the account.
2367  *
2368  * This function is only intended to be used when printing debug messages or in
2369  * tools for developer. For a string suitable for displaying to the user, see
2370  * tp_account_get_display_name(). To retrieve the connection manager and
2371  * protocol name parts of the object path, see
2372  * tp_account_get_connection_manager() and tp_account_get_protocol(). For
2373  * persistent identification of the account, use tp_proxy_get_object_path().
2374  *
2375  * Returns: a suffix of @account's object path, for debugging purposes.
2376  * Since: 0.13.9
2377  */
2378 const gchar *
tp_account_get_path_suffix(TpAccount * account)2379 tp_account_get_path_suffix (TpAccount *account)
2380 {
2381   const gchar *path;
2382 
2383   g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
2384 
2385   path = tp_proxy_get_object_path (account);
2386   g_return_val_if_fail (g_str_has_prefix (path, TP_ACCOUNT_OBJECT_PATH_BASE),
2387       path);
2388 
2389   return path + strlen (TP_ACCOUNT_OBJECT_PATH_BASE);
2390 }
2391 
2392 /**
2393  * tp_account_get_display_name:
2394  * @account: a #TpAccount
2395  *
2396  * <!-- -->
2397  *
2398  * Returns: the same as the #TpAccount:display-name property
2399  *
2400  * Since: 0.9.0
2401  **/
2402 const gchar *
tp_account_get_display_name(TpAccount * account)2403 tp_account_get_display_name (TpAccount *account)
2404 {
2405   g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
2406 
2407   return account->priv->display_name;
2408 }
2409 
2410 /**
2411  * tp_account_is_valid:
2412  * @account: a #TpAccount
2413  *
2414  * <!-- -->
2415  *
2416  * Returns: the same as the #TpAccount:valid property
2417  *
2418  * Since: 0.9.0
2419  */
2420 gboolean
tp_account_is_valid(TpAccount * account)2421 tp_account_is_valid (TpAccount *account)
2422 {
2423   g_return_val_if_fail (TP_IS_ACCOUNT (account), FALSE);
2424 
2425   return account->priv->valid;
2426 }
2427 
2428 /**
2429  * tp_account_get_connection_manager:
2430  * @account: a #TpAccount
2431  *
2432  * <!-- -->
2433  *
2434  * Returns: the same as the #TpAccount:connection-manager property
2435  *
2436  * Since: 0.9.0
2437  * Deprecated: Use tp_account_get_cm_name() instead.
2438  */
2439 const gchar *
tp_account_get_connection_manager(TpAccount * account)2440 tp_account_get_connection_manager (TpAccount *account)
2441 {
2442   g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
2443 
2444   return account->priv->cm_name;
2445 }
2446 
2447 /**
2448  * tp_account_get_protocol:
2449  * @account: a #TpAccount
2450  *
2451  * <!-- -->
2452  *
2453  * Returns: the same as the #TpAccount:protocol property
2454  *
2455  * Since: 0.9.0
2456  * Deprecated: Use tp_account_get_cm_name() instead.
2457  */
2458 const gchar *
tp_account_get_protocol(TpAccount * account)2459 tp_account_get_protocol (TpAccount *account)
2460 {
2461   g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
2462 
2463   return account->priv->proto_name;
2464 }
2465 
2466 /**
2467  * tp_account_get_cm_name:
2468  * @account: a #TpAccount
2469  *
2470  * <!-- -->
2471  *
2472  * Returns: the same as the #TpAccount:cm-name property
2473  *
2474  * Since: 0.19.3
2475  */
2476 const gchar *
tp_account_get_cm_name(TpAccount * account)2477 tp_account_get_cm_name (TpAccount *account)
2478 {
2479   g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
2480 
2481   return account->priv->cm_name;
2482 }
2483 
2484 /**
2485  * tp_account_get_protocol_name:
2486  * @account: a #TpAccount
2487  *
2488  * <!-- -->
2489  *
2490  * Returns: the same as the #TpAccount:protocol-name property
2491  *
2492  * Since: 0.19.3
2493  */
2494 const gchar *
tp_account_get_protocol_name(TpAccount * account)2495 tp_account_get_protocol_name (TpAccount *account)
2496 {
2497   g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
2498 
2499   return account->priv->proto_name;
2500 }
2501 
2502 /**
2503  * tp_account_get_service:
2504  * @self: an account
2505  *
2506  * <!-- -->
2507  *
2508  * Returns: the same as the #TpAccount:service property
2509  *
2510  * Since: 0.11.9
2511  */
2512 const gchar *
tp_account_get_service(TpAccount * self)2513 tp_account_get_service (TpAccount *self)
2514 {
2515   g_return_val_if_fail (TP_IS_ACCOUNT (self), NULL);
2516 
2517   return self->priv->service;
2518 }
2519 
2520 /**
2521  * tp_account_get_icon_name:
2522  * @account: a #TpAccount
2523  *
2524  * <!-- -->
2525  *
2526  * Returns: the same as the #TpAccount:icon-name property
2527  *
2528  * Since: 0.9.0
2529  */
2530 const gchar *
tp_account_get_icon_name(TpAccount * account)2531 tp_account_get_icon_name (TpAccount *account)
2532 {
2533   g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
2534 
2535   return account->priv->icon_name;
2536 }
2537 
2538 /**
2539  * tp_account_get_parameters:
2540  * @account: a #TpAccount
2541  *
2542  * Returns the parameters of the account, in a hash table where each string
2543  * is the parameter name (account, password, require-encryption etc.), and
2544  * each value is a #GValue. Using the tp_asv_get family of functions
2545  * (tp_asv_get_uint32(), tp_asv_get_string() etc.) to access the parameters is
2546  * recommended.
2547  *
2548  * The allowed parameters depend on the connection manager, and can be found
2549  * via tp_connection_manager_get_protocol() and
2550  * tp_connection_manager_protocol_get_param(). Well-known parameters are
2551  * listed
2552  * <ulink url="http://telepathy.freedesktop.org/spec/org.freedesktop.Telepathy.ConnectionManager.html#org.freedesktop.Telepathy.ConnectionManager.RequestConnection">in
2553  * the Telepathy D-Bus Interface Specification</ulink>.
2554  *
2555  * Returns: (transfer none) (element-type utf8 GObject.Value): the hash table of
2556  *  parameters on @account
2557  *
2558  * Since: 0.9.0
2559  */
2560 const GHashTable *
tp_account_get_parameters(TpAccount * account)2561 tp_account_get_parameters (TpAccount *account)
2562 {
2563   g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
2564 
2565   return account->priv->parameters;
2566 }
2567 
2568 /**
2569  * tp_account_dup_parameters_vardict:
2570  * @account: a #TpAccount
2571  *
2572  * Returns the parameters of the account, in a variant of type
2573  * %G_VARIANT_TYPE_VARDICT where the keys
2574  * are parameter names (account, password, require-encryption etc.).
2575  * Use g_variant_lookup() or g_variant_lookup_value() for convenient
2576  * access to the values.
2577  *
2578  * The allowed parameters depend on the connection manager, and can be found
2579  * via tp_connection_manager_get_protocol() and
2580  * tp_connection_manager_protocol_get_param(). Well-known parameters are
2581  * listed
2582  * <ulink url="http://telepathy.freedesktop.org/spec/org.freedesktop.Telepathy.ConnectionManager.html#org.freedesktop.Telepathy.ConnectionManager.RequestConnection">in
2583  * the Telepathy D-Bus Interface Specification</ulink>.
2584  *
2585  * Returns: (transfer full): the dictionary of
2586  *  parameters on @account, of type %G_VARIANT_TYPE_VARDICT
2587  *
2588  * Since: 0.17.6
2589  */
2590 GVariant *
tp_account_dup_parameters_vardict(TpAccount * account)2591 tp_account_dup_parameters_vardict (TpAccount *account)
2592 {
2593   g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
2594 
2595   return _tp_asv_to_vardict (account->priv->parameters);
2596 }
2597 
2598 /**
2599  * tp_account_is_enabled:
2600  * @account: a #TpAccount
2601  *
2602  * <!-- -->
2603  *
2604  * Returns: the same as the #TpAccount:enabled property
2605  *
2606  * Since: 0.9.0
2607  */
2608 gboolean
tp_account_is_enabled(TpAccount * account)2609 tp_account_is_enabled (TpAccount *account)
2610 {
2611   g_return_val_if_fail (TP_IS_ACCOUNT (account), FALSE);
2612 
2613   return account->priv->enabled;
2614 }
2615 
2616 static void
_tp_account_property_set_cb(TpProxy * proxy,const GError * error,gpointer user_data,GObject * weak_object)2617 _tp_account_property_set_cb (TpProxy *proxy,
2618     const GError *error,
2619     gpointer user_data,
2620     GObject *weak_object)
2621 {
2622   GSimpleAsyncResult *result = user_data;
2623 
2624   if (error != NULL)
2625     {
2626       DEBUG ("Failed to set property: %s", error->message);
2627       g_simple_async_result_set_from_error (result, error);
2628     }
2629 
2630   g_simple_async_result_complete_in_idle (result);
2631   g_object_unref (result);
2632 }
2633 
2634 /**
2635  * tp_account_set_enabled_finish:
2636  * @account: a #TpAccount
2637  * @result: a #GAsyncResult
2638  * @error: a #GError to fill
2639  *
2640  * Finishes an async set of the Enabled property.
2641  *
2642  * Returns: %TRUE if the set was successful, otherwise %FALSE
2643  *
2644  * Since: 0.9.0
2645  */
2646 gboolean
tp_account_set_enabled_finish(TpAccount * account,GAsyncResult * result,GError ** error)2647 tp_account_set_enabled_finish (TpAccount *account,
2648     GAsyncResult *result,
2649     GError **error)
2650 {
2651   _tp_implement_finish_void (account, tp_account_set_enabled_finish);
2652 }
2653 
2654 /**
2655  * tp_account_set_enabled_async:
2656  * @account: a #TpAccount
2657  * @enabled: the new enabled value of @account
2658  * @callback: a callback to call when the request is satisfied
2659  * @user_data: data to pass to @callback
2660  *
2661  * Requests an asynchronous set of the Enabled property of @account. When the
2662  * operation is finished, @callback will be called. You can then call
2663  * tp_account_set_enabled_finish() to get the result of the operation.
2664  *
2665  * Since: 0.9.0
2666  */
2667 void
tp_account_set_enabled_async(TpAccount * account,gboolean enabled,GAsyncReadyCallback callback,gpointer user_data)2668 tp_account_set_enabled_async (TpAccount *account,
2669     gboolean enabled,
2670     GAsyncReadyCallback callback,
2671     gpointer user_data)
2672 {
2673   GValue value = {0, };
2674   GSimpleAsyncResult *result;
2675 
2676   g_return_if_fail (TP_IS_ACCOUNT (account));
2677 
2678   result = g_simple_async_result_new (G_OBJECT (account),
2679       callback, user_data, tp_account_set_enabled_finish);
2680 
2681   g_value_init (&value, G_TYPE_BOOLEAN);
2682   g_value_set_boolean (&value, enabled);
2683 
2684   tp_cli_dbus_properties_call_set (TP_PROXY (account),
2685       -1, TP_IFACE_ACCOUNT, "Enabled", &value,
2686       _tp_account_property_set_cb, result, NULL, G_OBJECT (account));
2687 
2688   g_value_reset (&value);
2689 }
2690 
2691 static void
_tp_account_void_cb(TpAccount * proxy,const GError * error,gpointer user_data,GObject * weak_object)2692 _tp_account_void_cb (TpAccount *proxy,
2693     const GError *error,
2694     gpointer user_data,
2695     GObject *weak_object)
2696 {
2697   GSimpleAsyncResult *result = user_data;
2698 
2699   if (error != NULL)
2700     g_simple_async_result_set_from_error (result, error);
2701 
2702   g_simple_async_result_complete_in_idle (result);
2703   g_object_unref (result);
2704 }
2705 
2706 /**
2707  * tp_account_reconnect_finish:
2708  * @account: a #TpAccount
2709  * @result: a #GAsyncResult
2710  * @error: a #GError to be filled
2711  *
2712  * Finishes an async reconnect of @account.
2713  *
2714  * Returns: %TRUE if the reconnect call was successful, otherwise %FALSE
2715  *
2716  * Since: 0.9.0
2717  */
2718 gboolean
tp_account_reconnect_finish(TpAccount * account,GAsyncResult * result,GError ** error)2719 tp_account_reconnect_finish (TpAccount *account,
2720     GAsyncResult *result,
2721     GError **error)
2722 {
2723   _tp_implement_finish_void (account, tp_account_reconnect_finish);
2724 }
2725 
2726 /**
2727  * tp_account_reconnect_async:
2728  * @account: a #TpAccount
2729  * @callback: a callback to call when the request is satisfied
2730  * @user_data: data to pass to @callback
2731  *
2732  * Requests an asynchronous reconnect of @account. When the operation is
2733  * finished, @callback will be called. You can then call
2734  * tp_account_reconnect_finish() to get the result of the operation.
2735  *
2736  * Since: 0.9.0
2737  */
2738 void
tp_account_reconnect_async(TpAccount * account,GAsyncReadyCallback callback,gpointer user_data)2739 tp_account_reconnect_async (TpAccount *account,
2740     GAsyncReadyCallback callback,
2741     gpointer user_data)
2742 {
2743   GSimpleAsyncResult *result;
2744 
2745   g_return_if_fail (TP_IS_ACCOUNT (account));
2746 
2747   result = g_simple_async_result_new (G_OBJECT (account),
2748       callback, user_data, tp_account_reconnect_finish);
2749 
2750   tp_cli_account_call_reconnect (account, -1, _tp_account_void_cb,
2751       result, NULL, G_OBJECT (account));
2752 }
2753 
2754 /**
2755  * tp_account_set_automatic_presence_finish:
2756  * @account: a #TpAccount
2757  * @result: a #GAsyncResult
2758  * @error: a #GError to fill
2759  *
2760  * Finishes an asynchronous request to change the automatic presence of
2761  * @account.
2762  *
2763  * Returns: %TRUE if the operation was successful, otherwise %FALSE
2764  *
2765  * Since: 0.13.8
2766  */
2767 gboolean
tp_account_set_automatic_presence_finish(TpAccount * account,GAsyncResult * result,GError ** error)2768 tp_account_set_automatic_presence_finish (TpAccount *account,
2769     GAsyncResult *result,
2770     GError **error)
2771 {
2772   _tp_implement_finish_void (account, tp_account_set_automatic_presence_async)
2773 }
2774 
2775 /**
2776  * tp_account_set_automatic_presence_async:
2777  * @account: a #TpAccount
2778  * @type: the requested presence
2779  * @status: a status message to set, or %NULL
2780  * @message: a message for the change, or %NULL
2781  * @callback: a callback to call when the request is satisfied
2782  * @user_data: data to pass to @callback
2783  *
2784  * Requests an asynchronous change of @account's automatic presence. When the
2785  * operation is finished, @callback will be called. You can then call
2786  * tp_account_set_automatic_presence_finish() to get the result of the
2787  * operation.
2788  *
2789  * Since: 0.13.8
2790  */
2791 void
tp_account_set_automatic_presence_async(TpAccount * account,TpConnectionPresenceType type,const gchar * status,const gchar * message,GAsyncReadyCallback callback,gpointer user_data)2792 tp_account_set_automatic_presence_async (TpAccount *account,
2793     TpConnectionPresenceType type,
2794     const gchar *status,
2795     const gchar *message,
2796     GAsyncReadyCallback callback,
2797     gpointer user_data)
2798 {
2799   GValue value = {0, };
2800   GSimpleAsyncResult *result;
2801 
2802   g_return_if_fail (TP_IS_ACCOUNT (account));
2803 
2804   result = g_simple_async_result_new (G_OBJECT (account),
2805       callback, user_data, tp_account_set_automatic_presence_async);
2806 
2807   g_value_init (&value, TP_STRUCT_TYPE_SIMPLE_PRESENCE);
2808   g_value_take_boxed (&value, tp_value_array_build (3,
2809         G_TYPE_UINT, type,
2810         G_TYPE_STRING, status,
2811         G_TYPE_STRING, message,
2812         G_TYPE_INVALID));
2813 
2814   tp_cli_dbus_properties_call_set (TP_PROXY (account), -1,
2815       TP_IFACE_ACCOUNT, "AutomaticPresence", &value,
2816       _tp_account_property_set_cb, result, NULL, G_OBJECT (account));
2817 
2818   g_value_unset (&value);
2819 }
2820 
2821 /**
2822  * tp_account_request_presence_finish:
2823  * @account: a #TpAccount
2824  * @result: a #GAsyncResult
2825  * @error: a #GError to fill
2826  *
2827  * Finishes an async presence change request on @account.
2828  *
2829  * Returns: %TRUE if the operation was successful, otherwise %FALSE
2830  *
2831  * Since: 0.9.0
2832  */
2833 gboolean
tp_account_request_presence_finish(TpAccount * account,GAsyncResult * result,GError ** error)2834 tp_account_request_presence_finish (TpAccount *account,
2835     GAsyncResult *result,
2836     GError **error)
2837 {
2838   _tp_implement_finish_void (account, tp_account_request_presence_finish);
2839 }
2840 
2841 /**
2842  * tp_account_request_presence_async:
2843  * @account: a #TpAccount
2844  * @type: the requested presence
2845  * @status: a status message to set, or %NULL
2846  * @message: a message for the change, or %NULL
2847  * @callback: a callback to call when the request is satisfied
2848  * @user_data: data to pass to @callback
2849  *
2850  * Requests an asynchronous change of presence on @account. When the
2851  * operation is finished, @callback will be called. You can then call
2852  * tp_account_request_presence_finish() to get the result of the operation.
2853  *
2854  * Since: 0.9.0
2855  */
2856 void
tp_account_request_presence_async(TpAccount * account,TpConnectionPresenceType type,const gchar * status,const gchar * message,GAsyncReadyCallback callback,gpointer user_data)2857 tp_account_request_presence_async (TpAccount *account,
2858     TpConnectionPresenceType type,
2859     const gchar *status,
2860     const gchar *message,
2861     GAsyncReadyCallback callback,
2862     gpointer user_data)
2863 {
2864   GValue value = {0, };
2865   GValueArray *arr;
2866   GSimpleAsyncResult *result;
2867 
2868   g_return_if_fail (TP_IS_ACCOUNT (account));
2869 
2870   result = g_simple_async_result_new (G_OBJECT (account),
2871       callback, user_data, tp_account_request_presence_finish);
2872 
2873   g_value_init (&value, TP_STRUCT_TYPE_SIMPLE_PRESENCE);
2874   g_value_take_boxed (&value, dbus_g_type_specialized_construct (
2875           TP_STRUCT_TYPE_SIMPLE_PRESENCE));
2876   arr = (GValueArray *) g_value_get_boxed (&value);
2877 
2878   g_value_set_uint (arr->values, type);
2879   g_value_set_static_string (arr->values + 1, status);
2880   g_value_set_static_string (arr->values + 2, message);
2881 
2882   tp_cli_dbus_properties_call_set (TP_PROXY (account), -1,
2883       TP_IFACE_ACCOUNT, "RequestedPresence", &value,
2884       _tp_account_property_set_cb, result, NULL, G_OBJECT (account));
2885 
2886   g_value_unset (&value);
2887 }
2888 
2889 static void
_tp_account_updated_cb(TpAccount * proxy,const gchar ** reconnect_required,const GError * error,gpointer user_data,GObject * weak_object)2890 _tp_account_updated_cb (TpAccount *proxy,
2891     const gchar **reconnect_required,
2892     const GError *error,
2893     gpointer user_data,
2894     GObject *weak_object)
2895 {
2896   GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (user_data);
2897 
2898   if (error != NULL)
2899     g_simple_async_result_set_from_error (result, error);
2900   else
2901     g_simple_async_result_set_op_res_gpointer (result,
2902         g_strdupv ((GStrv) reconnect_required), (GDestroyNotify) g_strfreev);
2903 
2904   g_simple_async_result_complete_in_idle (result);
2905   g_object_unref (G_OBJECT (result));
2906 }
2907 
2908 /**
2909  * tp_account_update_parameters_async:
2910  * @account: a #TpAccount
2911  * @parameters: (element-type utf8 GObject.Value) (transfer none): new
2912  *  parameters to set on @account
2913  * @unset_parameters: list of parameters to unset on @account
2914  * @callback: a callback to call when the request is satisfied
2915  * @user_data: data to pass to @callback
2916  *
2917  * Requests an asynchronous update of parameters of @account. When the
2918  * operation is finished, @callback will be called. You can then call
2919  * tp_account_update_parameters_finish() to get the result of the operation.
2920  *
2921  * Since: 0.9.0
2922  */
2923 void
tp_account_update_parameters_async(TpAccount * account,GHashTable * parameters,const gchar ** unset_parameters,GAsyncReadyCallback callback,gpointer user_data)2924 tp_account_update_parameters_async (TpAccount *account,
2925     GHashTable *parameters,
2926     const gchar **unset_parameters,
2927     GAsyncReadyCallback callback,
2928     gpointer user_data)
2929 {
2930   GSimpleAsyncResult *result;
2931 
2932   g_return_if_fail (TP_IS_ACCOUNT (account));
2933 
2934   result = g_simple_async_result_new (G_OBJECT (account),
2935       callback, user_data, tp_account_update_parameters_finish);
2936 
2937   tp_cli_account_call_update_parameters (account, -1, parameters,
2938       unset_parameters, _tp_account_updated_cb, result,
2939       NULL, G_OBJECT (account));
2940 }
2941 
2942 /**
2943  * tp_account_update_parameters_finish:
2944  * @account: a #TpAccount
2945  * @result: a #GAsyncResult
2946  * @reconnect_required: (out) (array zero-terminated=1) (transfer full): a #GStrv to
2947  *  fill with properties that need a reconnect to take effect
2948  * @error: a #GError to fill
2949  *
2950  * Finishes an async update of the parameters on @account.
2951  *
2952  * Returns: %TRUE if the request succeeded, otherwise %FALSE
2953  *
2954  * Since: 0.9.0
2955  */
2956 gboolean
tp_account_update_parameters_finish(TpAccount * account,GAsyncResult * result,gchar *** reconnect_required,GError ** error)2957 tp_account_update_parameters_finish (TpAccount *account,
2958     GAsyncResult *result,
2959     gchar ***reconnect_required,
2960     GError **error)
2961 {
2962   _tp_implement_finish_copy_pointer (account,
2963       tp_account_update_parameters_finish, g_strdupv,
2964       reconnect_required);
2965 }
2966 
2967 /**
2968  * tp_account_update_parameters_vardict_async:
2969  * @account: a #TpAccount
2970  * @parameters: (transfer none): a variant of type %G_VARIANT_TYPE_VARDICT
2971  *  containing new parameters to set on @account
2972  * @unset_parameters: (array zero-terminated=1): list of parameters to unset on @account
2973  * @callback: a callback to call when the request is satisfied
2974  * @user_data: data to pass to @callback
2975  *
2976  * Requests an asynchronous update of parameters of @account. When the
2977  * operation is finished, @callback will be called. You can then call
2978  * tp_account_update_parameters_finish() to get the result of the operation.
2979  *
2980  * If @parameters is a floating reference (see g_variant_ref_sink()),
2981  * ownership of @parameters is taken by this function. This means
2982  * you can pass the result of g_variant_new() or g_variant_new_parsed()
2983  * directly to this function without additional reference-count management.
2984  *
2985  * Since: 0.17.6
2986  */
2987 void
tp_account_update_parameters_vardict_async(TpAccount * account,GVariant * parameters,const gchar ** unset_parameters,GAsyncReadyCallback callback,gpointer user_data)2988 tp_account_update_parameters_vardict_async (TpAccount *account,
2989     GVariant *parameters,
2990     const gchar **unset_parameters,
2991     GAsyncReadyCallback callback,
2992     gpointer user_data)
2993 {
2994   GHashTable *hash;
2995 
2996   hash = _tp_asv_from_vardict (parameters);
2997 
2998   g_variant_ref_sink (parameters);
2999 
3000   tp_account_update_parameters_async (account, hash,
3001       unset_parameters, callback, user_data);
3002   g_variant_unref (parameters);
3003   g_hash_table_unref (hash);
3004 }
3005 
3006 /**
3007  * tp_account_update_parameters_vardict_finish:
3008  * @account: a #TpAccount
3009  * @result: a #GAsyncResult
3010  * @reconnect_required: (out) (type GStrv) (transfer full): a #GStrv to
3011  *  fill with properties that need a reconnect to take effect
3012  * @error: a #GError to fill
3013  *
3014  * Finishes an async update of the parameters on @account.
3015  *
3016  * Returns: %TRUE if the request succeeded, otherwise %FALSE
3017  *
3018  * Since: 0.17.6
3019  */
3020 gboolean
tp_account_update_parameters_vardict_finish(TpAccount * account,GAsyncResult * result,gchar *** reconnect_required,GError ** error)3021 tp_account_update_parameters_vardict_finish (TpAccount *account,
3022     GAsyncResult *result,
3023     gchar ***reconnect_required,
3024     GError **error)
3025 {
3026   /* share an implementation with the non-vardict version */
3027   return tp_account_update_parameters_finish (account, result,
3028       reconnect_required, error);
3029 }
3030 
3031 /**
3032  * tp_account_set_display_name_async:
3033  * @account: a #TpAccount
3034  * @display_name: a new display name, or %NULL to unset the display name
3035  * @callback: a callback to call when the request is satisfied
3036  * @user_data: data to pass to @callback
3037  *
3038  * Requests an asynchronous set of the DisplayName property of @account. When
3039  * the operation is finished, @callback will be called. You can then call
3040  * tp_account_set_display_name_finish() to get the result of the operation.
3041  *
3042  * Since: 0.9.0
3043  */
3044 void
tp_account_set_display_name_async(TpAccount * account,const char * display_name,GAsyncReadyCallback callback,gpointer user_data)3045 tp_account_set_display_name_async (TpAccount *account,
3046     const char *display_name,
3047     GAsyncReadyCallback callback,
3048     gpointer user_data)
3049 {
3050   GSimpleAsyncResult *result;
3051   GValue value = {0, };
3052   const gchar *display_name_set;
3053 
3054   g_return_if_fail (TP_IS_ACCOUNT (account));
3055 
3056   if (display_name == NULL)
3057     display_name_set = "";
3058   else
3059     display_name_set = display_name;
3060 
3061   result = g_simple_async_result_new (G_OBJECT (account), callback,
3062       user_data, tp_account_set_display_name_finish);
3063 
3064   g_value_init (&value, G_TYPE_STRING);
3065   g_value_set_string (&value, display_name_set);
3066 
3067   tp_cli_dbus_properties_call_set (account, -1, TP_IFACE_ACCOUNT,
3068       "DisplayName", &value, _tp_account_property_set_cb, result, NULL,
3069       G_OBJECT (account));
3070 
3071   g_value_unset (&value);
3072 }
3073 
3074 /**
3075  * tp_account_set_display_name_finish:
3076  * @account: a #TpAccount
3077  * @result: a #GAsyncResult
3078  * @error: a #GError to fill
3079  *
3080  * Finishes an async set of the DisplayName property.
3081  *
3082  * Returns: %TRUE if the call was successful, otherwise %FALSE
3083  *
3084  * Since: 0.9.0
3085  */
3086 gboolean
tp_account_set_display_name_finish(TpAccount * account,GAsyncResult * result,GError ** error)3087 tp_account_set_display_name_finish (TpAccount *account,
3088     GAsyncResult *result,
3089     GError **error)
3090 {
3091   _tp_implement_finish_void (account, tp_account_set_display_name_finish);
3092 }
3093 
3094 /**
3095  * tp_account_set_service_async:
3096  * @self: a #TpAccount
3097  * @service: a new service name, or %NULL or the empty string to unset the
3098  *  service name (which will result in the #TpAccount:service property
3099  *  becoming the same as #TpAccount:protocol)
3100  * @callback: a callback to call when the request is satisfied
3101  * @user_data: data to pass to @callback
3102  *
3103  * Requests an asynchronous set of the Service property on @self. When
3104  * the operation is finished, @callback will be called. You can then call
3105  * tp_account_set_service_finish() to get the result of the operation.
3106  *
3107  * Since: 0.11.9
3108  */
3109 void
tp_account_set_service_async(TpAccount * self,const char * service,GAsyncReadyCallback callback,gpointer user_data)3110 tp_account_set_service_async (TpAccount *self,
3111     const char *service,
3112     GAsyncReadyCallback callback,
3113     gpointer user_data)
3114 {
3115   GSimpleAsyncResult *result;
3116   GValue value = {0, };
3117 
3118   g_return_if_fail (TP_IS_ACCOUNT (self));
3119 
3120   if (service == NULL)
3121     service = "";
3122 
3123   result = g_simple_async_result_new (G_OBJECT (self), callback,
3124       user_data, tp_account_set_service_async);
3125 
3126   g_value_init (&value, G_TYPE_STRING);
3127   g_value_set_string (&value, service);
3128 
3129   tp_cli_dbus_properties_call_set (self, -1, TP_IFACE_ACCOUNT,
3130       "Service", &value, _tp_account_property_set_cb, result, NULL,
3131       G_OBJECT (self));
3132 
3133   g_value_unset (&value);
3134 }
3135 
3136 /**
3137  * tp_account_set_service_finish:
3138  * @self: a #TpAccount
3139  * @result: a #GAsyncResult
3140  * @error: a #GError to fill
3141  *
3142  * Finishes an async set of the Service parameter.
3143  *
3144  * Returns: %TRUE if the operation was successful, otherwise %FALSE
3145  *
3146  * Since: 0.11.9
3147  */
3148 gboolean
tp_account_set_service_finish(TpAccount * self,GAsyncResult * result,GError ** error)3149 tp_account_set_service_finish (TpAccount *self,
3150     GAsyncResult *result,
3151     GError **error)
3152 {
3153   _tp_implement_finish_void (self, tp_account_set_service_async);
3154 }
3155 
3156 /**
3157  * tp_account_set_icon_name_async:
3158  * @account: a #TpAccount
3159  * @icon_name: a new icon name, or %NULL to unset the icon name
3160  * @callback: a callback to call when the request is satisfied
3161  * @user_data: data to pass to @callback
3162  *
3163  * Requests an asynchronous set of the Icon property of @account. When
3164  * the operation is finished, @callback will be called. You can then call
3165  * tp_account_set_icon_name_finish() to get the result of the operation.
3166  *
3167  * Since: 0.9.0
3168  */
3169 void
tp_account_set_icon_name_async(TpAccount * account,const char * icon_name,GAsyncReadyCallback callback,gpointer user_data)3170 tp_account_set_icon_name_async (TpAccount *account,
3171     const char *icon_name,
3172     GAsyncReadyCallback callback,
3173     gpointer user_data)
3174 {
3175   GSimpleAsyncResult *result;
3176   GValue value = {0, };
3177   const char *icon_name_set;
3178 
3179   g_return_if_fail (TP_IS_ACCOUNT (account));
3180 
3181   if (icon_name == NULL)
3182     /* settings an empty icon name is allowed */
3183     icon_name_set = "";
3184   else
3185     icon_name_set = icon_name;
3186 
3187   result = g_simple_async_result_new (G_OBJECT (account), callback,
3188       user_data, tp_account_set_icon_name_finish);
3189 
3190   g_value_init (&value, G_TYPE_STRING);
3191   g_value_set_string (&value, icon_name_set);
3192 
3193   tp_cli_dbus_properties_call_set (account, -1, TP_IFACE_ACCOUNT,
3194       "Icon", &value, _tp_account_property_set_cb, result, NULL,
3195       G_OBJECT (account));
3196 
3197   g_value_unset (&value);
3198 }
3199 
3200 /**
3201  * tp_account_set_icon_name_finish:
3202  * @account: a #TpAccount
3203  * @result: a #GAsyncResult
3204  * @error: a #GError to fill
3205  *
3206  * Finishes an async set of the Icon parameter.
3207  *
3208  * Returns: %TRUE if the operation was successful, otherwise %FALSE
3209  *
3210  * Since: 0.9.0
3211  */
3212 gboolean
tp_account_set_icon_name_finish(TpAccount * account,GAsyncResult * result,GError ** error)3213 tp_account_set_icon_name_finish (TpAccount *account,
3214     GAsyncResult *result,
3215     GError **error)
3216 {
3217   _tp_implement_finish_void (account, tp_account_set_icon_name_finish);
3218 }
3219 
3220 /**
3221  * tp_account_remove_async:
3222  * @account: a #TpAccount
3223  * @callback: a callback to call when the request is satisfied
3224  * @user_data: data to pass to @callback
3225  *
3226  * Requests an asynchronous removal of @account. When the operation is
3227  * finished, @callback will be called. You can then call
3228  * tp_account_remove_finish() to get the result of the operation.
3229  *
3230  * Since: 0.9.0
3231  */
3232 void
tp_account_remove_async(TpAccount * account,GAsyncReadyCallback callback,gpointer user_data)3233 tp_account_remove_async (TpAccount *account,
3234     GAsyncReadyCallback callback,
3235     gpointer user_data)
3236 {
3237   GSimpleAsyncResult *result;
3238 
3239   g_return_if_fail (TP_IS_ACCOUNT (account));
3240 
3241   result = g_simple_async_result_new (G_OBJECT (account),
3242       callback, user_data, tp_account_remove_finish);
3243 
3244   tp_cli_account_call_remove (account, -1, _tp_account_void_cb, result, NULL,
3245       G_OBJECT (account));
3246 }
3247 
3248 /**
3249  * tp_account_remove_finish:
3250  * @account: a #TpAccount
3251  * @result: a #GAsyncResult
3252  * @error: a #GError to fill
3253  *
3254  * Finishes an async removal of @account.
3255  *
3256  * Returns: %TRUE if the operation was successful, otherwise %FALSE
3257  *
3258  * Since: 0.9.0
3259  */
3260 gboolean
tp_account_remove_finish(TpAccount * account,GAsyncResult * result,GError ** error)3261 tp_account_remove_finish (TpAccount *account,
3262     GAsyncResult *result,
3263     GError **error)
3264 {
3265   _tp_implement_finish_void (account, tp_account_remove_finish);
3266 }
3267 
3268 /**
3269  * tp_account_get_changing_presence:
3270  * @self: an account
3271  *
3272  * <!-- -->
3273  *
3274  * Returns: the same as the #TpAccount:changing-presence property
3275  *
3276  * Since: 0.11.6
3277  */
3278 gboolean
tp_account_get_changing_presence(TpAccount * self)3279 tp_account_get_changing_presence (TpAccount *self)
3280 {
3281   g_return_val_if_fail (TP_IS_ACCOUNT (self), FALSE);
3282 
3283   return self->priv->changing_presence;
3284 }
3285 
3286 /**
3287  * tp_account_get_connect_automatically:
3288  * @account: a #TpAccount
3289  *
3290  * <!-- -->
3291  *
3292  * Returns: the same as the #TpAccount:connect-automatically property
3293  *
3294  * Since: 0.9.0
3295  */
3296 gboolean
tp_account_get_connect_automatically(TpAccount * account)3297 tp_account_get_connect_automatically (TpAccount *account)
3298 {
3299   g_return_val_if_fail (TP_IS_ACCOUNT (account), FALSE);
3300 
3301   return account->priv->connect_automatically;
3302 }
3303 
3304 /**
3305  * tp_account_set_connect_automatically_async:
3306  * @account: a #TpAccount
3307  * @connect_automatically: new value for the parameter
3308  * @callback: a callback to call when the request is satisfied
3309  * @user_data: data to pass to @callback
3310  *
3311  * Requests an asynchronous set of the ConnectAutomatically property of
3312  * @account. When the operation is finished, @callback will be called. You can
3313  * then call tp_account_set_display_name_finish() to get the result of the
3314  * operation.
3315  *
3316  * Since: 0.9.0
3317  */
3318 void
tp_account_set_connect_automatically_async(TpAccount * account,gboolean connect_automatically,GAsyncReadyCallback callback,gpointer user_data)3319 tp_account_set_connect_automatically_async (TpAccount *account,
3320     gboolean connect_automatically,
3321     GAsyncReadyCallback callback,
3322     gpointer user_data)
3323 {
3324   GSimpleAsyncResult *result;
3325   GValue value = {0, };
3326 
3327   g_return_if_fail (TP_IS_ACCOUNT (account));
3328 
3329   result = g_simple_async_result_new (G_OBJECT (account), callback,
3330       user_data, tp_account_set_connect_automatically_finish);
3331 
3332   g_value_init (&value, G_TYPE_BOOLEAN);
3333   g_value_set_boolean (&value, connect_automatically);
3334 
3335   tp_cli_dbus_properties_call_set (account, -1, TP_IFACE_ACCOUNT,
3336       "ConnectAutomatically", &value, _tp_account_property_set_cb, result,
3337       NULL, G_OBJECT (account));
3338 
3339   g_value_unset (&value);
3340 }
3341 
3342 /**
3343  * tp_account_set_connect_automatically_finish:
3344  * @account: a #TpAccount
3345  * @result: a #GAsyncResult
3346  * @error: a #GError to fill
3347  *
3348  * Finishes an async set of the ConnectAutomatically property.
3349  *
3350  * Returns: %TRUE if the call was successful, otherwise %FALSE
3351  *
3352  * Since: 0.9.0
3353  */
3354 gboolean
tp_account_set_connect_automatically_finish(TpAccount * account,GAsyncResult * result,GError ** error)3355 tp_account_set_connect_automatically_finish (TpAccount *account,
3356     GAsyncResult *result,
3357     GError **error)
3358 {
3359   _tp_implement_finish_void (account,
3360       tp_account_set_connect_automatically_finish);
3361 }
3362 
3363 /**
3364  * tp_account_get_has_been_online:
3365  * @account: a #TpAccount
3366  *
3367  * <!-- -->
3368  *
3369  * Returns: the same as the #TpAccount:has-been-online property
3370  *
3371  * Since: 0.9.0
3372  */
3373 gboolean
tp_account_get_has_been_online(TpAccount * account)3374 tp_account_get_has_been_online (TpAccount *account)
3375 {
3376   g_return_val_if_fail (TP_IS_ACCOUNT (account), FALSE);
3377 
3378   return account->priv->has_been_online;
3379 }
3380 
3381 /**
3382  * tp_account_get_connection_status:
3383  * @account: a #TpAccount
3384  * @reason: (out): a #TpConnectionStatusReason to fill, or %NULL
3385  *
3386  * Gets the connection status and reason from @account. The two values
3387  * are the same as the #TpAccount:connection-status and
3388  * #TpAccount:connection-status-reason properties.
3389  *
3390  * Returns: the same as the #TpAccount:connection-status property
3391  *
3392  * Since: 0.9.0
3393  */
3394 TpConnectionStatus
tp_account_get_connection_status(TpAccount * account,TpConnectionStatusReason * reason)3395 tp_account_get_connection_status (TpAccount *account,
3396     TpConnectionStatusReason *reason)
3397 {
3398   g_return_val_if_fail (TP_IS_ACCOUNT (account),
3399       TP_CONNECTION_STATUS_DISCONNECTED); /* there's no _UNSET */
3400 
3401   if (reason != NULL)
3402     *reason = account->priv->reason;
3403 
3404   return account->priv->connection_status;
3405 }
3406 
3407 /**
3408  * tp_account_get_current_presence:
3409  * @account: a #TpAccount
3410  * @status: (out) (transfer full): return location for the current status
3411  * @status_message: (out) (transfer full): return location for the current
3412  *  status message
3413  *
3414  * Gets the current presence, status and status message of @account. These
3415  * values are the same as the #TpAccount:current-presence-type,
3416  * #TpAccount:current-status and #TpAccount:current-status-message properties.
3417  *
3418  * Returns: the same as the #TpAccount:current-presence-type property
3419  *
3420  * Since: 0.9.0
3421  */
3422 TpConnectionPresenceType
tp_account_get_current_presence(TpAccount * account,gchar ** status,gchar ** status_message)3423 tp_account_get_current_presence (TpAccount *account,
3424     gchar **status,
3425     gchar **status_message)
3426 {
3427   g_return_val_if_fail (TP_IS_ACCOUNT (account),
3428       TP_CONNECTION_PRESENCE_TYPE_UNSET);
3429 
3430   if (status != NULL)
3431     *status = g_strdup (account->priv->cur_status);
3432 
3433   if (status_message != NULL)
3434     *status_message = g_strdup (account->priv->cur_message);
3435 
3436   return account->priv->cur_presence;
3437 }
3438 
3439 /**
3440  * tp_account_get_requested_presence:
3441  * @account: a #TpAccount
3442  * @status: (out) (transfer none): return location for the requested status
3443  * @status_message: (out) (transfer full): return location for the requested
3444  *  status message
3445  *
3446  * Gets the requested presence, status and status message of @account. These
3447  * values are the same as the #TpAccount:requested-presence-type,
3448  * #TpAccount:requested-status and #TpAccount:requested-status-message
3449  * properties.
3450  *
3451  * Returns: the same as the #TpAccount:requested-presence-type property
3452  *
3453  * Since: 0.9.0
3454  */
3455 TpConnectionPresenceType
tp_account_get_requested_presence(TpAccount * account,gchar ** status,gchar ** status_message)3456 tp_account_get_requested_presence (TpAccount *account,
3457     gchar **status,
3458     gchar **status_message)
3459 {
3460   g_return_val_if_fail (TP_IS_ACCOUNT (account),
3461       TP_CONNECTION_PRESENCE_TYPE_UNSET);
3462 
3463   if (status != NULL)
3464     *status = g_strdup (account->priv->requested_status);
3465 
3466   if (status_message != NULL)
3467     *status_message = g_strdup (account->priv->requested_message);
3468 
3469   return account->priv->requested_presence;
3470 }
3471 
3472 /**
3473  * tp_account_get_nickname:
3474  * @account: a #TpAccount
3475  *
3476  * <!-- -->
3477  *
3478  * Returns: the same as the #TpAccount:nickname property
3479  *
3480  * Since: 0.9.0
3481  */
3482 const gchar *
tp_account_get_nickname(TpAccount * account)3483 tp_account_get_nickname (TpAccount *account)
3484 {
3485   g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
3486 
3487   return account->priv->nickname;
3488 }
3489 
3490 /**
3491  * tp_account_set_nickname_finish:
3492  * @account: a #TpAccount
3493  * @result: a #GAsyncResult
3494  * @error: a #GError to fill
3495  *
3496  * Finishes an async nickname change request on @account.
3497  *
3498  * Returns: %TRUE if the operation was successful, otherwise %FALSE
3499  *
3500  * Since: 0.9.0
3501  */
3502 gboolean
tp_account_set_nickname_finish(TpAccount * account,GAsyncResult * result,GError ** error)3503 tp_account_set_nickname_finish (TpAccount *account,
3504     GAsyncResult *result,
3505     GError **error)
3506 {
3507   _tp_implement_finish_void (account, tp_account_set_nickname_finish);
3508 }
3509 
3510 /**
3511  * tp_account_set_nickname_async:
3512  * @account: a #TpAccount
3513  * @nickname: a new nickname to set
3514  * @callback: a callback to call when the request is satisfied
3515  * @user_data: data to pass to @callback
3516  *
3517  * Requests an asynchronous change of the Nickname parameter on @account. When
3518  * the operation is finished, @callback will be called. You can then call
3519  * tp_account_set_nickname_finish() to get the result of the operation.
3520  *
3521  * Since: 0.9.0
3522  */
3523 void
tp_account_set_nickname_async(TpAccount * account,const gchar * nickname,GAsyncReadyCallback callback,gpointer user_data)3524 tp_account_set_nickname_async (TpAccount *account,
3525     const gchar *nickname,
3526     GAsyncReadyCallback callback,
3527     gpointer user_data)
3528 {
3529   GValue value = {0, };
3530   GSimpleAsyncResult *result;
3531 
3532   g_return_if_fail (TP_IS_ACCOUNT (account));
3533   g_return_if_fail (nickname != NULL);
3534 
3535   result = g_simple_async_result_new (G_OBJECT (account),
3536       callback, user_data, tp_account_set_nickname_finish);
3537 
3538   if (nickname == NULL)
3539     {
3540       g_simple_async_report_error_in_idle (G_OBJECT (account),
3541           callback, user_data, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
3542           "Can't set an empty nickname");
3543       return;
3544     }
3545 
3546   g_value_init (&value, G_TYPE_STRING);
3547   g_value_set_string (&value, nickname);
3548 
3549   tp_cli_dbus_properties_call_set (TP_PROXY (account), -1,
3550       TP_IFACE_ACCOUNT, "Nickname", &value,
3551       _tp_account_property_set_cb, result, NULL, G_OBJECT (account));
3552 
3553   g_value_unset (&value);
3554 }
3555 
3556 /**
3557  * tp_account_get_supersedes:
3558  * @self: a #TpAccount
3559  *
3560  * Return the same thing as the #TpAccount:supersedes property, in a way
3561  * that may be more convenient for C code.
3562  *
3563  * The returned pointers are not guaranteed to remain valid after the
3564  * main loop has been re-entered.
3565  *
3566  * Returns: (transfer none): the same as the #TpAccount:supersedes property
3567  *
3568  * Since: 0.17.5
3569  */
3570 const gchar * const *
tp_account_get_supersedes(TpAccount * self)3571 tp_account_get_supersedes (TpAccount *self)
3572 {
3573   g_return_val_if_fail (TP_IS_ACCOUNT (self), NULL);
3574 
3575   return (const gchar * const *) self->priv->supersedes;
3576 }
3577 
3578 static void
_tp_account_got_avatar_cb(TpProxy * proxy,const GValue * out_Value,const GError * error,gpointer user_data,GObject * weak_object)3579 _tp_account_got_avatar_cb (TpProxy *proxy,
3580     const GValue *out_Value,
3581     const GError *error,
3582     gpointer user_data,
3583     GObject *weak_object)
3584 {
3585   GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (user_data);
3586 
3587   if (error != NULL)
3588     {
3589       DEBUG ("Failed to get avatar: %s", error->message);
3590       g_simple_async_result_set_from_error (result, error);
3591     }
3592   else if (!G_VALUE_HOLDS (out_Value, TP_STRUCT_TYPE_AVATAR))
3593     {
3594       DEBUG ("Avatar had wrong type: %s", G_VALUE_TYPE_NAME (out_Value));
3595       g_simple_async_result_set_error (result, TP_ERROR, TP_ERROR_CONFUSED,
3596           "Incorrect type for Avatar property");
3597     }
3598   else
3599     {
3600       GValueArray *avatar;
3601       GArray *res;
3602       const GArray *tmp;
3603       const gchar *mime_type;
3604 
3605       avatar = g_value_get_boxed (out_Value);
3606       tp_value_array_unpack (avatar, 2,
3607           &tmp,
3608           &mime_type);
3609 
3610       res = g_array_sized_new (FALSE, FALSE, 1, tmp->len);
3611       g_array_append_vals (res, tmp->data, tmp->len);
3612       g_simple_async_result_set_op_res_gpointer (result, res,
3613           (GDestroyNotify) g_array_unref);
3614     }
3615 
3616   g_simple_async_result_complete_in_idle (result);
3617   g_object_unref (result);
3618 }
3619 
3620 /**
3621  * tp_account_get_avatar_async:
3622  * @account: a #TpAccount
3623  * @callback: a callback to call when the request is satisfied
3624  * @user_data: data to pass to @callback
3625  *
3626  * Requests an asynchronous get of @account's avatar. When
3627  * the operation is finished, @callback will be called. You can then call
3628  * tp_account_get_avatar_finish() to get the result of the operation.
3629  *
3630  * Since: 0.9.0
3631  */
3632 void
tp_account_get_avatar_async(TpAccount * account,GAsyncReadyCallback callback,gpointer user_data)3633 tp_account_get_avatar_async (TpAccount *account,
3634     GAsyncReadyCallback callback,
3635     gpointer user_data)
3636 {
3637   GSimpleAsyncResult *result;
3638 
3639   g_return_if_fail (TP_IS_ACCOUNT (account));
3640 
3641   result = g_simple_async_result_new (G_OBJECT (account),
3642       callback, user_data, tp_account_get_avatar_finish);
3643 
3644   tp_cli_dbus_properties_call_get (account, -1,
3645       TP_IFACE_ACCOUNT_INTERFACE_AVATAR, "Avatar", _tp_account_got_avatar_cb,
3646       result, NULL, G_OBJECT (account));
3647 }
3648 
3649 /**
3650  * tp_account_get_avatar_finish:
3651  * @account: a #TpAccount
3652  * @result: a #GAsyncResult
3653  * @error: a #GError to fill
3654  *
3655  * Finishes an async get operation of @account's avatar.
3656  *
3657  * Beware that the returned value is only valid until @result is freed.
3658  * Copy it with g_array_ref() if you need to keep it for longer.
3659  *
3660  * Returns: (element-type guchar) (transfer none): a #GArray of #guchar
3661  *  containing the bytes of the account's avatar, or %NULL on failure
3662  *
3663  * Since: 0.9.0
3664  */
3665 const GArray *
tp_account_get_avatar_finish(TpAccount * account,GAsyncResult * result,GError ** error)3666 tp_account_get_avatar_finish (TpAccount *account,
3667     GAsyncResult *result,
3668     GError **error)
3669 {
3670   _tp_implement_finish_return_copy_pointer (account,
3671       tp_account_get_avatar_finish, /* do not copy */);
3672 }
3673 
3674 /**
3675  * tp_account_is_prepared: (skip)
3676  * @account: a #TpAccount
3677  * @feature: a feature which is required
3678  *
3679  * <!-- -->
3680  *
3681  * Returns: the same thing as tp_proxy_is_prepared()
3682  *
3683  * Since: 0.9.0
3684  * Deprecated: since 0.23.0, use tp_proxy_is_prepared() instead.
3685  */
3686 gboolean
tp_account_is_prepared(TpAccount * account,GQuark feature)3687 tp_account_is_prepared (TpAccount *account,
3688     GQuark feature)
3689 {
3690   return tp_proxy_is_prepared (account, feature);
3691 }
3692 
3693 /**
3694  * tp_account_prepare_async: (skip)
3695  * @account: a #TpAccount
3696  * @features: a 0-terminated list of features, or %NULL
3697  * @callback: a callback to call when the request is satisfied
3698  * @user_data: data to pass to @callback
3699  *
3700  * Requests an asynchronous preparation of @account with the features specified
3701  * by @features. When the operation is finished, @callback will be called. You
3702  * can then call tp_account_prepare_finish() to get the result of the
3703  * operation.
3704  *
3705  * If @features is %NULL, then @callback will be called when the implied
3706  * %TP_ACCOUNT_FEATURE_CORE feature is ready.
3707  *
3708  * If %NULL is given to @callback, then no callback will be called when the
3709  * operation is finished. Instead, it will simply set @features on @manager.
3710  * Note that if @callback is %NULL, then @user_data must also be %NULL.
3711  *
3712  * Since 0.11.3, this is equivalent to calling the new function
3713  * tp_proxy_prepare_async() with the same arguments.
3714  *
3715  * Since: 0.9.0
3716  * Deprecated: since 0.15.6, use tp_proxy_prepare_async() instead.
3717  */
3718 void
tp_account_prepare_async(TpAccount * account,const GQuark * features,GAsyncReadyCallback callback,gpointer user_data)3719 tp_account_prepare_async (TpAccount *account,
3720     const GQuark *features,
3721     GAsyncReadyCallback callback,
3722     gpointer user_data)
3723 {
3724   tp_proxy_prepare_async (account, features, callback, user_data);
3725 }
3726 
3727 /**
3728  * tp_account_prepare_finish: (skip)
3729  * @account: a #TpAccount
3730  * @result: a #GAsyncResult
3731  * @error: a #GError to fill
3732  *
3733  * Finishes an async preparation of the account @account.
3734  *
3735  * Returns: %TRUE if the preparation was successful, otherwise %FALSE
3736  *
3737  * Since: 0.9.0
3738  * Deprecated: since 0.15.6, use tp_proxy_prepare_finish() instead.
3739  */
3740 gboolean
tp_account_prepare_finish(TpAccount * account,GAsyncResult * result,GError ** error)3741 tp_account_prepare_finish (TpAccount *account,
3742     GAsyncResult *result,
3743     GError **error)
3744 {
3745   return tp_proxy_prepare_finish (account, result, error);
3746 }
3747 
3748 static void
set_or_free(gchar ** target,gchar * source)3749 set_or_free (gchar **target,
3750     gchar *source)
3751 {
3752   if (target != NULL)
3753     *target = source;
3754   else
3755     g_free (source);
3756 }
3757 
3758 /**
3759  * tp_account_parse_object_path:
3760  * @object_path: a Telepathy Account's object path
3761  * @cm: (out) (transfer full): location at which to store the account's
3762  *  connection manager's name
3763  * @protocol: (out) (transfer full): location at which to store the account's
3764  *  protocol
3765  * @account_id: (out) (transfer full): location at which to store the account's
3766  *  unique identifier
3767  * @error: location at which to return an error
3768  *
3769  * Validates and parses a Telepathy Account's object path, extracting the
3770  * connection manager's name, the protocol, and the account's unique identifier
3771  * from the path. This includes replacing underscores with hyphens in the
3772  * protocol name, as defined in the Account specification.
3773  *
3774  * Any of the out parameters may be %NULL if not needed. If %TRUE is returned,
3775  * the caller is responsible for freeing the strings stored in any non-%NULL
3776  * out parameters, using g_free().
3777  *
3778  * Returns: %TRUE if @object_path was successfully parsed; %FALSE and sets
3779  *          @error otherwise.
3780  *
3781  * Since: 0.9.0
3782  * Deprecated: Use tp_account_get_protocol() and
3783  *  tp_account_get_connection_manager() instead.
3784  */
3785 gboolean
tp_account_parse_object_path(const gchar * object_path,gchar ** cm,gchar ** protocol,gchar ** account_id,GError ** error)3786 tp_account_parse_object_path (const gchar *object_path,
3787     gchar **cm,
3788     gchar **protocol,
3789     gchar **account_id,
3790     GError **error)
3791 {
3792   const gchar *suffix;
3793   gchar **segments;
3794 
3795   if (!tp_dbus_check_valid_object_path (object_path, error))
3796     return FALSE;
3797 
3798   if (!g_str_has_prefix (object_path, TP_ACCOUNT_OBJECT_PATH_BASE))
3799     {
3800       g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
3801           "Account path does not start with the right prefix: %s",
3802           object_path);
3803       return FALSE;
3804     }
3805 
3806   suffix = object_path + strlen (TP_ACCOUNT_OBJECT_PATH_BASE);
3807 
3808   segments = g_strsplit (suffix, "/", 0);
3809 
3810   if (g_strv_length (segments) != 3)
3811     {
3812       g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
3813           "Account path '%s' is malformed: should have 3 trailing components, "
3814           "not %u", object_path, g_strv_length (segments));
3815       goto free_segments_and_fail;
3816     }
3817 
3818   if (!g_ascii_isalpha (segments[0][0]))
3819     {
3820       g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
3821           "Account path '%s' is malformed: CM name should start with a letter",
3822           object_path);
3823       goto free_segments_and_fail;
3824     }
3825 
3826   if (!g_ascii_isalpha (segments[1][0]))
3827     {
3828       g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
3829           "Account path '%s' is malformed: "
3830           "protocol name should start with a letter",
3831           object_path);
3832       goto free_segments_and_fail;
3833     }
3834 
3835   if (!g_ascii_isalpha (segments[2][0]) && segments[2][0] != '_')
3836     {
3837       g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
3838           "Account path '%s' is malformed: "
3839           "account ID should start with a letter or underscore",
3840           object_path);
3841       goto free_segments_and_fail;
3842     }
3843 
3844   set_or_free (cm, segments[0]);
3845   set_or_free (protocol, unescape_protocol (segments[1]));
3846   set_or_free (account_id, segments[2]);
3847 
3848   /* Not g_strfreev because we stole or freed the individual strings */
3849   g_free (segments);
3850   return TRUE;
3851 
3852 free_segments_and_fail:
3853   g_strfreev (segments);
3854   return FALSE;
3855 }
3856 
3857 /**
3858  * _tp_account_refresh_properties:
3859  * @account: a #TpAccount
3860  *
3861  * Refreshes @account's hashtable of properties with what actually exists on
3862  * the account manager.
3863  *
3864  * Since: 0.9.0
3865  */
3866 void
_tp_account_refresh_properties(TpAccount * account)3867 _tp_account_refresh_properties (TpAccount *account)
3868 {
3869   g_return_if_fail (TP_IS_ACCOUNT (account));
3870 
3871   tp_cli_dbus_properties_call_get_all (account, -1, TP_IFACE_ACCOUNT,
3872       _tp_account_got_all_cb, NULL, NULL, G_OBJECT (account));
3873 }
3874 
3875 /**
3876  * tp_account_set_avatar_finish:
3877  * @self: a #TpAccount
3878  * @result: a #GAsyncResult
3879  * @error: a #GError to fill
3880  *
3881  * Finishes an async avatar change request on @account.
3882  *
3883  * Returns: %TRUE if the operation was successful, otherwise %FALSE
3884  *
3885  * Since: 0.11.1
3886  */
3887 gboolean
tp_account_set_avatar_finish(TpAccount * self,GAsyncResult * result,GError ** error)3888 tp_account_set_avatar_finish (TpAccount *self,
3889     GAsyncResult *result,
3890     GError **error)
3891 {
3892   _tp_implement_finish_void (self, tp_account_set_avatar_async);
3893 }
3894 
3895 /**
3896  * tp_account_set_avatar_async:
3897  * @self: a #TpAccount
3898  * @avatar: (allow-none) (array length=len): a new avatar to set; can be %NULL
3899  *  only if @len equals 0
3900  * @len: the length of the new avatar
3901  * @mime_type: (allow-none): the MIME type of the new avatar; can be %NULL
3902  *  only if @len equals 0
3903  * @callback: a callback to call when the request is satisfied
3904  * @user_data: data to pass to @callback
3905  *
3906  * Requests an asynchronous change of the Avatar parameter on @self. When
3907  * the operation is finished, @callback will be called. You can then call
3908  * tp_account_set_avatar_finish() to get the result of the operation.
3909  *
3910  * If @len equals 0, the avatar is cleared.
3911  *
3912  * Since: 0.11.1
3913  */
3914 void
tp_account_set_avatar_async(TpAccount * self,const guchar * avatar,gsize len,const gchar * mime_type,GAsyncReadyCallback callback,gpointer user_data)3915 tp_account_set_avatar_async (TpAccount *self,
3916     const guchar *avatar,
3917     gsize len,
3918     const gchar *mime_type,
3919     GAsyncReadyCallback callback,
3920     gpointer user_data)
3921 {
3922   GValue value = {0, };
3923   GSimpleAsyncResult *result;
3924   GValueArray *arr;
3925   GArray *tmp;
3926 
3927   g_return_if_fail (TP_IS_ACCOUNT (self));
3928   g_return_if_fail (avatar != NULL || len == 0);
3929   g_return_if_fail (mime_type != NULL || len == 0);
3930 
3931   result = g_simple_async_result_new (G_OBJECT (self),
3932       callback, user_data, tp_account_set_avatar_async);
3933 
3934   tmp = g_array_new (FALSE, FALSE, sizeof (guchar));
3935 
3936   if (len > 0)
3937     g_array_append_vals (tmp, avatar, len);
3938 
3939   arr = tp_value_array_build (2,
3940       TP_TYPE_UCHAR_ARRAY, tmp,
3941       G_TYPE_STRING, mime_type,
3942       G_TYPE_INVALID);
3943 
3944   g_value_init (&value, TP_STRUCT_TYPE_AVATAR);
3945   g_value_take_boxed (&value, arr);
3946 
3947   tp_cli_dbus_properties_call_set (self, -1,
3948       TP_IFACE_ACCOUNT_INTERFACE_AVATAR, "Avatar", &value,
3949       _tp_account_property_set_cb, result, NULL, NULL);
3950 
3951   g_value_unset (&value);
3952 }
3953 
3954 /**
3955  * tp_account_get_detailed_error: (skip)
3956  * @self: an account
3957  * @details: (out) (allow-none) (element-type utf8 GObject.Value) (transfer none):
3958  *  optionally used to return a map from string to #GValue, which must not be
3959  *  modified, destroyed or unreffed by the caller
3960  *
3961  * If the account's connection is not connected, return the D-Bus error name
3962  * with which it last disconnected or failed to connect (in particular, this
3963  * is %TP_ERROR_STR_CANCELLED if it was disconnected by a user request).
3964  * This is the same as #TpAccount:connection-error.
3965  *
3966  * If @details is not %NULL, it will be used to return additional details about
3967  * the error (the same as #TpAccount:connection-error-details).
3968  *
3969  * Otherwise, return %NULL, without altering @details.
3970  *
3971  * The returned string and @details may become invalid when the main loop is
3972  * re-entered or the account is destroyed.
3973  *
3974  * Returns: (transfer none) (allow-none): a D-Bus error name, or %NULL.
3975  *
3976  * Since: 0.11.7
3977  */
3978 const gchar *
tp_account_get_detailed_error(TpAccount * self,const GHashTable ** details)3979 tp_account_get_detailed_error (TpAccount *self,
3980     const GHashTable **details)
3981 {
3982   g_return_val_if_fail (TP_IS_ACCOUNT (self), NULL);
3983 
3984   if (self->priv->connection_status == TP_CONNECTION_STATUS_CONNECTED)
3985     return NULL;
3986 
3987   if (details != NULL)
3988     *details = self->priv->error_details;
3989 
3990   return self->priv->error;
3991 }
3992 
3993 /**
3994  * tp_account_dup_detailed_error_vardict:
3995  * @self: an account
3996  * @details: (out) (allow-none) (transfer full):
3997  *  optionally used to return a variant of type %G_VARIANT_TYPE_VARDICT,
3998  *  which must be unreffed by the caller with g_variant_unref()
3999  *
4000  * If the account's connection is not connected, return the D-Bus error name
4001  * with which it last disconnected or failed to connect (in particular, this
4002  * is %TP_ERROR_STR_CANCELLED if it was disconnected by a user request).
4003  * This is the same as #TpAccount:connection-error.
4004  *
4005  * If @details is not %NULL, it will be used to return additional details about
4006  * the error (the same as #TpAccount:connection-error-details).
4007  *
4008  * Otherwise, return %NULL, without altering @details.
4009  *
4010  * The returned string and @details may become invalid when the main loop is
4011  * re-entered or the account is destroyed.
4012  *
4013  * Returns: (transfer full) (allow-none): a D-Bus error name, or %NULL.
4014  *
4015  * Since: 0.17.6
4016  */
4017 gchar *
tp_account_dup_detailed_error_vardict(TpAccount * self,GVariant ** details)4018 tp_account_dup_detailed_error_vardict (TpAccount *self,
4019     GVariant **details)
4020 {
4021   g_return_val_if_fail (TP_IS_ACCOUNT (self), NULL);
4022 
4023   if (self->priv->connection_status == TP_CONNECTION_STATUS_CONNECTED)
4024     return NULL;
4025 
4026   if (details != NULL)
4027     *details = _tp_asv_to_vardict (self->priv->error_details);
4028 
4029   return g_strdup (self->priv->error);
4030 }
4031 
4032 /**
4033  * tp_account_get_storage_provider:
4034  * @self: a #TpAccount
4035  *
4036  * <!-- -->
4037  *
4038  * Returns: the same as the #TpAccount:storage-provider property
4039  *
4040  * Since: 0.13.2
4041  */
4042 const gchar *
tp_account_get_storage_provider(TpAccount * self)4043 tp_account_get_storage_provider (TpAccount *self)
4044 {
4045   g_return_val_if_fail (TP_IS_ACCOUNT (self), NULL);
4046 
4047   return self->priv->storage_provider;
4048 }
4049 
4050 /* FIXME: in 1.0, remove */
4051 /**
4052  * tp_account_get_storage_identifier:
4053  * @self: a #TpAccount
4054  *
4055  * <!-- -->
4056  *
4057  * Returns: the same as the #TpAccount:storage-identifier property
4058  *
4059  * Since: 0.13.2
4060  */
4061 const GValue *
tp_account_get_storage_identifier(TpAccount * self)4062 tp_account_get_storage_identifier (TpAccount *self)
4063 {
4064   g_return_val_if_fail (TP_IS_ACCOUNT (self), NULL);
4065 
4066   return self->priv->storage_identifier;
4067 }
4068 
4069 /* FIXME: in 1.0, rename to tp_account_get_storage_identifier */
4070 /**
4071  * tp_account_dup_storage_identifier_variant:
4072  * @self: a #TpAccount
4073  *
4074  * Return provider-specific information used to identify this
4075  * account. Use g_variant_get_type() to check that the type
4076  * is what you expect; for instance, if the
4077  * #TpAccount:storage-provider has string-based user identifiers,
4078  * this variant should have type %G_VARIANT_TYPE_STRING.
4079  *
4080  * Returns: (transfer full): the same as the
4081  *  #TpAccount:storage-identifier-variant property
4082  *
4083  * Since: 0.13.2
4084  */
4085 GVariant *
tp_account_dup_storage_identifier_variant(TpAccount * self)4086 tp_account_dup_storage_identifier_variant (TpAccount *self)
4087 {
4088   g_return_val_if_fail (TP_IS_ACCOUNT (self), NULL);
4089 
4090   if (self->priv->storage_identifier == NULL)
4091     return NULL;
4092 
4093   return g_variant_ref_sink (dbus_g_value_build_g_variant (
4094         self->priv->storage_identifier));
4095 }
4096 
4097 /**
4098  * tp_account_get_storage_restrictions:
4099  * @self: a #TpAccount
4100  *
4101  * <!-- -->
4102  *
4103  * Returns: the same as the #TpAccount:storage-restrictions property
4104  *
4105  * Since: 0.13.2
4106  */
4107 TpStorageRestrictionFlags
tp_account_get_storage_restrictions(TpAccount * self)4108 tp_account_get_storage_restrictions (TpAccount *self)
4109 {
4110   g_return_val_if_fail (TP_IS_ACCOUNT (self), 0);
4111 
4112   return self->priv->storage_restrictions;
4113 }
4114 
4115 static void
_tp_account_get_storage_specific_information_cb(TpProxy * self,const GValue * value,const GError * error,gpointer user_data,GObject * weak_obj)4116 _tp_account_get_storage_specific_information_cb (TpProxy *self,
4117     const GValue *value,
4118     const GError *error,
4119     gpointer user_data,
4120     GObject *weak_obj)
4121 {
4122   GSimpleAsyncResult *result = user_data;
4123 
4124   if (error != NULL)
4125     {
4126       DEBUG ("Failed to retrieve StorageSpecificInformation: %s",
4127           error->message);
4128       g_simple_async_result_set_from_error (result, error);
4129     }
4130   else
4131     {
4132       g_simple_async_result_set_op_res_gpointer (result,
4133           g_value_dup_boxed (value),
4134           (GDestroyNotify) g_hash_table_unref);
4135     }
4136 
4137   g_simple_async_result_complete_in_idle (result);
4138   g_object_unref (result);
4139 }
4140 
4141 /* FIXME: in Telepathy 1.0, remove this */
4142 /**
4143  * tp_account_get_storage_specific_information_async:
4144  * @self: a #TpAccount
4145  * @callback: a callback to call when the request is satisfied
4146  * @user_data: data to pass to @callback
4147  *
4148  * Makes an asynchronous request of @self's StorageSpecificInformation
4149  * property (part of the Account.Interface.Storage interface).
4150  *
4151  * When the operation is finished, @callback will be called. You must then
4152  * call tp_account_get_storage_specific_information_finish() to get the
4153  * result of the request.
4154  *
4155  * Since: 0.13.2
4156  */
4157 void
tp_account_get_storage_specific_information_async(TpAccount * self,GAsyncReadyCallback callback,gpointer user_data)4158 tp_account_get_storage_specific_information_async (TpAccount *self,
4159     GAsyncReadyCallback callback,
4160     gpointer user_data)
4161 {
4162   GSimpleAsyncResult *result;
4163 
4164   g_return_if_fail (TP_IS_ACCOUNT (self));
4165 
4166   result = g_simple_async_result_new (G_OBJECT (self),
4167       callback, user_data, tp_account_get_storage_specific_information_async);
4168 
4169   tp_cli_dbus_properties_call_get (self, -1,
4170       TP_IFACE_ACCOUNT_INTERFACE_STORAGE, "StorageSpecificInformation",
4171       _tp_account_get_storage_specific_information_cb, result, NULL, NULL);
4172 }
4173 
4174 /* FIXME: in Telepathy 1.0, rename to ...get_storage_specific_information... */
4175 /**
4176  * tp_account_dup_storage_specific_information_vardict_async:
4177  * @self: a #TpAccount
4178  * @callback: a callback to call when the request is satisfied
4179  * @user_data: data to pass to @callback
4180  *
4181  * Makes an asynchronous request of @self's StorageSpecificInformation
4182  * property (part of the Account.Interface.Storage interface).
4183  *
4184  * When the operation is finished, @callback will be called. You must then
4185  * call tp_account_dup_storage_specific_information_vardict_finish() to get the
4186  * result of the request.
4187  *
4188  * Since: 0.17.6
4189  */
4190 void
tp_account_dup_storage_specific_information_vardict_async(TpAccount * self,GAsyncReadyCallback callback,gpointer user_data)4191 tp_account_dup_storage_specific_information_vardict_async (TpAccount *self,
4192     GAsyncReadyCallback callback,
4193     gpointer user_data)
4194 {
4195   /* we share an implementation */
4196   tp_account_get_storage_specific_information_async (self, callback,
4197       user_data);
4198 }
4199 
4200 /* FIXME: in Telepathy 1.0, remove this */
4201 /**
4202  * tp_account_get_storage_specific_information_finish:
4203  * @self: a #TpAccount
4204  * @result: a #GAsyncResult
4205  * @error: a #GError to fill
4206  *
4207  * Retrieve the value of the request begun with
4208  * tp_account_get_storage_specific_information_async().
4209  *
4210  * Beware that the returned value is only valid until @result is freed.
4211  * Copy it with g_hash_table_ref() if you need to keep it for longer.
4212  *
4213  * Returns: (element-type utf8 GObject.Value) (transfer none): a #GHashTable
4214  *  of strings to GValues representing the D-Bus type a{sv}.
4215  *
4216  * Since: 0.13.2
4217  */
4218 GHashTable *
tp_account_get_storage_specific_information_finish(TpAccount * self,GAsyncResult * result,GError ** error)4219 tp_account_get_storage_specific_information_finish (TpAccount *self,
4220     GAsyncResult *result,
4221     GError **error)
4222 {
4223   _tp_implement_finish_return_copy_pointer (self,
4224       tp_account_get_storage_specific_information_async, /* do not copy */);
4225 }
4226 
4227 /* FIXME: in Telepathy 1.0, rename to ...get_storage_specific_information... */
4228 /**
4229  * tp_account_dup_storage_specific_information_vardict_finish:
4230  * @self: a #TpAccount
4231  * @result: a #GAsyncResult
4232  * @error: a #GError to fill
4233  *
4234  * Retrieve the value of the request begun with
4235  * tp_account_dup_storage_specific_information_vardict_async().
4236  *
4237  * Returns: (transfer full): a map from strings to variants,
4238  *  of type %G_VARIANT_TYPE_VARDICT
4239  *
4240  * Since: 0.17.6
4241  */
4242 GVariant *
tp_account_dup_storage_specific_information_vardict_finish(TpAccount * self,GAsyncResult * result,GError ** error)4243 tp_account_dup_storage_specific_information_vardict_finish (TpAccount *self,
4244     GAsyncResult *result,
4245     GError **error)
4246 {
4247   /* we share the source tag with the non-vardict version */
4248   _tp_implement_finish_return_copy_pointer (self,
4249       tp_account_get_storage_specific_information_async, _tp_asv_to_vardict);
4250 }
4251 
4252 static void
_tp_account_got_all_addressing_cb(TpProxy * proxy,GHashTable * properties,const GError * error,gpointer user_data,GObject * object)4253 _tp_account_got_all_addressing_cb (TpProxy *proxy,
4254     GHashTable *properties,
4255     const GError *error,
4256     gpointer user_data,
4257     GObject *object)
4258 {
4259   TpAccount *self = TP_ACCOUNT (proxy);
4260   GSimpleAsyncResult *result = user_data;
4261 
4262   if (error != NULL)
4263     {
4264       DEBUG ("Error getting Addressing properties: %s", error->message);
4265     }
4266   else
4267     {
4268       self->priv->uri_schemes = g_strdupv (tp_asv_get_boxed (properties,
4269             "URISchemes", G_TYPE_STRV));
4270     }
4271 
4272   if (self->priv->uri_schemes == NULL)
4273     self->priv->uri_schemes = g_new0 (gchar *, 1);
4274 
4275   g_simple_async_result_complete_in_idle (result);
4276 }
4277 
4278 static void
connection_prepare_cb(GObject * object,GAsyncResult * res,gpointer user_data)4279 connection_prepare_cb (GObject *object,
4280     GAsyncResult *res,
4281     gpointer user_data)
4282 {
4283   TpConnection *connection = (TpConnection *) object;
4284   TpAccount *self = tp_connection_get_account (connection);
4285   GSimpleAsyncResult *result = user_data;
4286   GError *error = NULL;
4287 
4288   self->priv->connection_prepared = TRUE;
4289 
4290   if (!tp_proxy_prepare_finish (object, res, &error))
4291     {
4292       DEBUG ("Error preparing connection: %s", error->message);
4293       g_simple_async_result_take_error (result, error);
4294     }
4295   g_simple_async_result_complete (result);
4296 
4297   g_object_unref (result);
4298 }
4299 
4300 static void
tp_account_prepare_connection_async(TpProxy * proxy,const TpProxyFeature * feature,GAsyncReadyCallback callback,gpointer user_data)4301 tp_account_prepare_connection_async (TpProxy *proxy,
4302     const TpProxyFeature *feature,
4303     GAsyncReadyCallback callback,
4304     gpointer user_data)
4305 {
4306   TpAccount *self = TP_ACCOUNT (proxy);
4307   GSimpleAsyncResult *result;
4308   GArray *features;
4309 
4310   result = g_simple_async_result_new ((GObject *) proxy, callback, user_data,
4311       tp_account_prepare_connection_async);
4312 
4313   if (self->priv->connection == NULL)
4314     {
4315       g_simple_async_result_complete_in_idle (result);
4316       g_object_unref (result);
4317       return;
4318     }
4319 
4320   features = tp_simple_client_factory_dup_connection_features (
4321       tp_proxy_get_factory (self), self->priv->connection);
4322 
4323   tp_proxy_prepare_async (self->priv->connection, (GQuark *) features->data,
4324       connection_prepare_cb, result);
4325 
4326   g_array_unref (features);
4327 }
4328 
4329 static void
tp_account_prepare_addressing_async(TpProxy * proxy,const TpProxyFeature * feature,GAsyncReadyCallback callback,gpointer user_data)4330 tp_account_prepare_addressing_async (TpProxy *proxy,
4331     const TpProxyFeature *feature,
4332     GAsyncReadyCallback callback,
4333     gpointer user_data)
4334 {
4335   TpAccount *self = TP_ACCOUNT (proxy);
4336   GSimpleAsyncResult *result;
4337 
4338   result = g_simple_async_result_new ((GObject *) proxy, callback, user_data,
4339       tp_account_prepare_addressing_async);
4340 
4341   g_assert (self->priv->uri_schemes == NULL);
4342 
4343   tp_cli_dbus_properties_call_get_all (self, -1,
4344       TP_IFACE_ACCOUNT_INTERFACE_ADDRESSING,
4345       _tp_account_got_all_addressing_cb, result, g_object_unref, NULL);
4346 }
4347 
4348 /**
4349  * tp_account_get_uri_schemes:
4350  * @self: a #TpAccount
4351  *
4352  * Return the #TpAccount:uri-schemes property
4353  *
4354  * Returns: (transfer none): the value of #TpAccount:uri_schemes property
4355  *
4356  * Since: 0.13.8
4357  */
4358 const gchar * const *
tp_account_get_uri_schemes(TpAccount * self)4359 tp_account_get_uri_schemes (TpAccount *self)
4360 {
4361   g_return_val_if_fail (TP_IS_ACCOUNT (self), NULL);
4362 
4363   return (const gchar * const *) self->priv->uri_schemes;
4364 }
4365 
4366 /**
4367  * tp_account_associated_with_uri_scheme:
4368  * @self: a #TpAccount
4369  * @scheme: (transfer none): a URI scheme such as "tel", "sip" or "xmpp"
4370  *
4371  * <!-- -->
4372  *
4373  * Returns: %TRUE if the result of tp_account_get_uri_schemes() would include
4374  *  @scheme
4375  *
4376  * Since: 0.13.8
4377  */
4378 gboolean
tp_account_associated_with_uri_scheme(TpAccount * self,const gchar * scheme)4379 tp_account_associated_with_uri_scheme (TpAccount *self,
4380     const gchar *scheme)
4381 {
4382   return tp_strv_contains (tp_account_get_uri_schemes (self), scheme);
4383 }
4384 
4385 /**
4386  * tp_account_set_uri_scheme_association_async:
4387  * @self: a #TpAccount
4388  * @scheme: a non-%NULL URI scheme such as "tel"
4389  * @associate: %TRUE to use this account for @scheme, or %FALSE to not use it
4390  * @callback: a callback to call when the request is satisfied
4391  * @user_data: data to pass to @callback
4392  *
4393  * Add @scheme to the list of additional URI schemes that would be returned
4394  * by tp_account_get_uri_schemes(), or remove it from that list.
4395  *
4396  * @scheme should not be the primary URI scheme for the account's
4397  * protocol (for instance, "xmpp" for XMPP, or "sip" or "sips" for SIP),
4398  * since the account should be assumed to be useful for those schemes
4399  * regardless of the contents of the list.
4400  *
4401  * Calling this method does not require the %TP_ACCOUNT_FEATURE_ADDRESSING
4402  * feature to be enabled, but the change will not be reflected in the result
4403  * of tp_account_get_uri_schemes() or tp_account_associated_with_uri_scheme()
4404  * unless that feature has been enabled.
4405  *
4406  * Since: 0.13.8
4407  */
4408 void
tp_account_set_uri_scheme_association_async(TpAccount * self,const gchar * scheme,gboolean associate,GAsyncReadyCallback callback,gpointer user_data)4409 tp_account_set_uri_scheme_association_async (TpAccount *self,
4410     const gchar *scheme,
4411     gboolean associate,
4412     GAsyncReadyCallback callback,
4413     gpointer user_data)
4414 {
4415   GSimpleAsyncResult *result;
4416 
4417   g_return_if_fail (TP_IS_ACCOUNT (self));
4418   g_return_if_fail (scheme != NULL);
4419 
4420   result = g_simple_async_result_new (G_OBJECT (self), callback,
4421       user_data, tp_account_set_uri_scheme_association_async);
4422 
4423   tp_cli_account_interface_addressing_call_set_uri_scheme_association (
4424       self, -1, scheme, associate,
4425       _tp_account_void_cb, result, NULL, NULL);
4426 }
4427 
4428 /**
4429  * tp_account_set_uri_scheme_association_finish:
4430  * @self: a #TpAccount
4431  * @result: a #GAsyncResult
4432  * @error: a #GError to fill
4433  *
4434  * Interpret the result of tp_account_set_uri_scheme_association_async().
4435  *
4436  * Returns: %TRUE if the call was successful, otherwise %FALSE
4437  *
4438  * Since: 0.13.8
4439  */
4440 gboolean
tp_account_set_uri_scheme_association_finish(TpAccount * self,GAsyncResult * result,GError ** error)4441 tp_account_set_uri_scheme_association_finish (TpAccount *self,
4442     GAsyncResult *result,
4443     GError **error)
4444 {
4445   _tp_implement_finish_void (self, tp_account_set_uri_scheme_association_async);
4446 }
4447 
4448 /**
4449  * tp_account_get_automatic_presence:
4450  * @self: an account
4451  * @status: (out) (transfer none): return location for the presence status
4452  * @status_message: (out) (transfer full): return location for the
4453  *  user-defined message
4454  *
4455  * Gets the automatic presence, status and status message of @account. These
4456  * values are the same as the #TpAccount:automatic-presence-type,
4457  * #TpAccount:automatic-status and #TpAccount:automatic-status-message
4458  * properties, and are the values that will be used if the account should
4459  * be put online automatically.
4460  *
4461  * Returns: the same as the #TpAccount:automatic-presence-type property
4462  *
4463  * Since: 0.13.8
4464  */
4465 TpConnectionPresenceType
tp_account_get_automatic_presence(TpAccount * self,gchar ** status,gchar ** status_message)4466 tp_account_get_automatic_presence (TpAccount *self,
4467     gchar **status,
4468     gchar **status_message)
4469 {
4470   g_return_val_if_fail (TP_IS_ACCOUNT (self),
4471       TP_CONNECTION_PRESENCE_TYPE_UNSET);
4472 
4473   if (status != NULL)
4474     *status = g_strdup (self->priv->auto_status);
4475 
4476   if (status_message != NULL)
4477     *status_message = g_strdup (self->priv->auto_message);
4478 
4479   return self->priv->auto_presence;
4480 }
4481 
4482 /**
4483  * tp_account_get_normalized_name:
4484  * @self: a #TpAccount
4485  *
4486  * <!-- -->
4487  *
4488  * Returns: (transfer none): the same as the #TpAccount:normalized-name
4489  *  property
4490  *
4491  * Since: 0.13.8
4492  **/
4493 const gchar *
tp_account_get_normalized_name(TpAccount * self)4494 tp_account_get_normalized_name (TpAccount *self)
4495 {
4496   g_return_val_if_fail (TP_IS_ACCOUNT (self), NULL);
4497 
4498   return self->priv->normalized_name;
4499 }
4500 
4501 /**
4502  * tp_account_bind_connection_status_to_property:
4503  * @self: a #TpAccount
4504  * @target: the target #GObject
4505  * @target_property: the property on @target to bind (must be %G_TYPE_BOOLEAN)
4506  * @invert: %TRUE if you wish to invert the value of @target_property
4507  *   (i.e. %FALSE if connected)
4508  *
4509  * Binds the :connection-status of @self to the boolean property of another
4510  * object using a #GBinding such that the @target_property will be set to
4511  * %TRUE when @self is connected (and @invert is %FALSE).
4512  *
4513  * @target_property will be synchronised immediately (%G_BINDING_SYNC_CREATE).
4514  * @invert can be interpreted as analogous to %G_BINDING_INVERT_BOOLEAN.
4515  *
4516  * For instance, this function can be used to bind the GtkWidget:sensitive
4517  * property to only make a widget sensitive when the account is connected.
4518  *
4519  * See g_object_bind_property() for more information.
4520  *
4521  * Returns: (transfer none): the #GBinding instance representing the binding
4522  *   between the @self and the @target. The binding is released whenever the
4523  *   #GBinding reference count reaches zero.
4524  * Since: 0.13.16
4525  */
4526 GBinding *
tp_account_bind_connection_status_to_property(TpAccount * self,gpointer target,const char * target_property,gboolean invert)4527 tp_account_bind_connection_status_to_property (TpAccount *self,
4528     gpointer target,
4529     const char *target_property,
4530     gboolean invert)
4531 {
4532   g_return_val_if_fail (TP_IS_ACCOUNT (self), NULL);
4533 
4534   return g_object_bind_property_full (self, "connection-status",
4535       target, target_property,
4536       G_BINDING_SYNC_CREATE,
4537       _tp_bind_connection_status_to_boolean,
4538       NULL, GUINT_TO_POINTER (invert), NULL);
4539 }
4540