/* * account.c - proxy for an account in the Telepathy account manager * * Copyright © 2009–2012 Collabora Ltd. * Copyright © 2009–2010 Nokia Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "config.h" #include #include "telepathy-glib/account-internal.h" #include "telepathy-glib/account.h" #include #include #include #include #include #include #include #define DEBUG_FLAG TP_DEBUG_ACCOUNTS #include "telepathy-glib/connection-internal.h" #include "telepathy-glib/dbus-internal.h" #include "telepathy-glib/debug-internal.h" #include "telepathy-glib/proxy-internal.h" #include "telepathy-glib/simple-client-factory-internal.h" #include "telepathy-glib/util-internal.h" #include "telepathy-glib/variant-util-internal.h" #include "telepathy-glib/_gen/tp-cli-account-body.h" /** * SECTION:account * @title: TpAccount * @short_description: proxy object for an account in the Telepathy account * manager * @see_also: #TpAccountManager * * The Telepathy Account Manager stores the user's configured real-time * communication accounts. The #TpAccount object represents a stored account. * * Since: 0.7.32 */ /** * TpAccount: * * The Telepathy Account Manager stores the user's configured real-time * communication accounts. This object represents a stored account. * * If this account is deleted from the account manager, the * #TpProxy::invalidated signal will be emitted * with the domain %TP_DBUS_ERRORS and the error code * %TP_DBUS_ERROR_OBJECT_REMOVED. * * One can connect to the #GObject::notify signal to get change notifications * for many of the properties on this object. Refer to each property's * documentation for whether it can be used in this way. * * #TpAccount objects should normally be obtained from the #TpAccountManager. * * Since 0.16, #TpAccount always has a non-%NULL #TpProxy:factory, and its * #TpProxy:factory will be propagated to its #TpConnection * (if any). If a #TpAccount is created without going via the * #TpAccountManager or specifying a #TpProxy:factory, the default * is to use a new #TpAutomaticClientFactory. * * Since: 0.7.32 */ /** * TpAccountClass: * * The class of a #TpAccount. */ struct _TpAccountPrivate { gboolean dispose_has_run; TpConnection *connection; gchar *connection_object_path; TpConnectionStatus connection_status; TpConnectionStatusReason reason; gchar *error; GHashTable *error_details; TpConnectionPresenceType cur_presence; gchar *cur_status; gchar *cur_message; TpConnectionPresenceType requested_presence; gchar *requested_status; gchar *requested_message; TpConnectionPresenceType auto_presence; gchar *auto_status; gchar *auto_message; gboolean changing_presence; gboolean connect_automatically; gboolean has_been_online; gchar *normalized_name; gchar *nickname; gboolean enabled; gboolean valid; gboolean removed; gchar *cm_name; gchar *proto_name; gchar *icon_name; gchar *service; gchar *display_name; GStrv supersedes; GHashTable *parameters; gchar *storage_provider; GValue *storage_identifier; TpStorageRestrictionFlags storage_restrictions; GStrv uri_schemes; gboolean connection_prepared; }; G_DEFINE_TYPE (TpAccount, tp_account, TP_TYPE_PROXY) /* signals */ enum { STATUS_CHANGED, PRESENCE_CHANGED, AVATAR_CHANGED, LAST_SIGNAL }; static guint signals[LAST_SIGNAL]; /* properties */ enum { PROP_ENABLED = 1, PROP_CHANGING_PRESENCE, PROP_CURRENT_PRESENCE_TYPE, PROP_CURRENT_STATUS, PROP_CURRENT_STATUS_MESSAGE, PROP_CONNECTION_STATUS, PROP_CONNECTION_STATUS_REASON, PROP_CONNECTION_ERROR, PROP_CONNECTION_ERROR_DETAILS, PROP_CONNECTION, PROP_DISPLAY_NAME, PROP_CONNECTION_MANAGER, PROP_CM_NAME, PROP_PROTOCOL, PROP_PROTOCOL_NAME, PROP_ICON_NAME, PROP_CONNECT_AUTOMATICALLY, PROP_HAS_BEEN_ONLINE, PROP_SERVICE, PROP_VALID, PROP_REQUESTED_PRESENCE_TYPE, PROP_REQUESTED_STATUS, PROP_REQUESTED_STATUS_MESSAGE, PROP_NICKNAME, PROP_AUTOMATIC_PRESENCE_TYPE, PROP_AUTOMATIC_STATUS, PROP_AUTOMATIC_STATUS_MESSAGE, PROP_NORMALIZED_NAME, PROP_STORAGE_PROVIDER, PROP_STORAGE_IDENTIFIER, PROP_STORAGE_IDENTIFIER_VARIANT, PROP_STORAGE_RESTRICTIONS, PROP_SUPERSEDES, PROP_URI_SCHEMES, N_PROPS }; static void tp_account_prepare_connection_async (TpProxy *proxy, const TpProxyFeature *feature, GAsyncReadyCallback callback, gpointer user_data); static void tp_account_prepare_addressing_async (TpProxy *proxy, const TpProxyFeature *feature, GAsyncReadyCallback callback, gpointer user_data); static void tp_account_prepare_storage_async (TpProxy *proxy, const TpProxyFeature *feature, GAsyncReadyCallback callback, gpointer user_data); static gboolean connection_is_internal (TpAccount *self) { if (!tp_proxy_is_prepared (self, TP_ACCOUNT_FEATURE_CONNECTION)) return FALSE; return !self->priv->connection_prepared; } /** * TP_ACCOUNT_FEATURE_CORE: * * Expands to a call to a function that returns a quark for the "core" feature * on a #TpAccount. * * When this feature is prepared, the basic properties of the Account have * been retrieved and are available for use, and change-notification has been * set up. * * One can ask for a feature to be prepared using the * tp_proxy_prepare_async() function, and waiting for it to callback. * * Since: 0.9.0 */ /** * TP_ACCOUNT_FEATURE_CONNECTION: * * Expands to a call to a function that returns a quark for the "connection" * feature on a #TpAccount. * * When this feature is prepared, it is guaranteed that #TpAccount:connection * will always be either %NULL or prepared. The account's #TpProxy:factory * will be used to create the #TpConnection object and to determine its * desired connection features. Change notification of the * #TpAccount:connection property will be delayed until all features (at least * %TP_CONNECTION_FEATURE_CORE) are prepared. See * tp_simple_client_factory_add_account_features() to define which features * needs to be prepared. * * One can ask for a feature to be prepared using the * tp_proxy_prepare_async() function, and waiting for it to callback. * * Since: 0.15.5 */ /** * TP_ACCOUNT_FEATURE_STORAGE: * * Expands to a call to a function that returns a quark for the "storage" * feature on a #TpAccount. * * When this feature is prepared, the Account.Interface.Storage properties have * been retrieved and are available for use. * * One can ask for a feature to be prepared using the * tp_proxy_prepare_async() function, and waiting for it to callback. * * Since: 0.13.2 */ /** * TP_ACCOUNT_FEATURE_ADDRESSING: * * Expands to a call to a function that returns a quark for the "addressing" * feature on a #TpAccount. * * When this feature is prepared, the list of URI schemes from * Account.Interface.Addressing has been retrieved and is available for use. * * One can ask for a feature to be prepared using the * tp_proxy_prepare_async() function, and waiting for it to callback. * * Since: 0.13.8 */ /** * tp_account_get_feature_quark_core: * * * * Returns: the quark used for representing the core feature of a * #TpAccount * * Since: 0.9.0 */ GQuark tp_account_get_feature_quark_core (void) { return g_quark_from_static_string ("tp-account-feature-core"); } /** * tp_account_get_feature_quark_connection: * * * * Returns: the quark used for representing the connection feature of a * #TpAccount * * Since: 0.15.5 */ GQuark tp_account_get_feature_quark_connection (void) { return g_quark_from_static_string ("tp-account-feature-connection"); } /** * tp_account_get_feature_quark_storage: * * * * Returns: the quark used for representing the storage interface of a * #TpAccount * * Since: 0.13.2 */ GQuark tp_account_get_feature_quark_storage (void) { return g_quark_from_static_string ("tp-account-feature-storage"); } GQuark tp_account_get_feature_quark_addressing (void) { return g_quark_from_static_string ("tp-account-feature-addressing"); } enum { FEAT_CORE, FEAT_CONNECTION, FEAT_ADDRESSING, FEAT_STORAGE, N_FEAT }; static const TpProxyFeature * _tp_account_list_features (TpProxyClass *cls G_GNUC_UNUSED) { static TpProxyFeature features[N_FEAT + 1] = { { 0 } }; if (G_UNLIKELY (features[0].name == 0)) { features[FEAT_CORE].name = TP_ACCOUNT_FEATURE_CORE; features[FEAT_CORE].core = TRUE; /* no need for a prepare_async function - the constructor starts it */ features[FEAT_CONNECTION].name = TP_ACCOUNT_FEATURE_CONNECTION; features[FEAT_CONNECTION].prepare_async = tp_account_prepare_connection_async; features[FEAT_ADDRESSING].name = TP_ACCOUNT_FEATURE_ADDRESSING; features[FEAT_ADDRESSING].prepare_async = tp_account_prepare_addressing_async; features[FEAT_STORAGE].name = TP_ACCOUNT_FEATURE_STORAGE; features[FEAT_STORAGE].prepare_async = tp_account_prepare_storage_async; /* assert that the terminator at the end is there */ g_assert (features[N_FEAT].name == 0); } return features; } static void tp_account_init (TpAccount *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TP_TYPE_ACCOUNT, TpAccountPrivate); self->priv->connection_status = TP_CONNECTION_STATUS_DISCONNECTED; self->priv->error = g_strdup (TP_ERROR_STR_DISCONNECTED); self->priv->error_details = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) tp_g_value_slice_free); self->priv->supersedes = g_new0 (gchar *, 1); } static void _tp_account_invalidated_cb (TpAccount *self, guint domain, guint code, gchar *message) { TpAccountPrivate *priv = self->priv; /* The connection will get disconnected as a result of account deletion, * but by then we will no longer be telling the API user about changes - * so claim the disconnection already happened (see fd.o#25149) */ if (priv->connection_status != TP_CONNECTION_STATUS_DISCONNECTED) { priv->connection_status = TP_CONNECTION_STATUS_DISCONNECTED; tp_clear_pointer (&priv->error, g_free); g_hash_table_remove_all (priv->error_details); if (domain == TP_DBUS_ERRORS && code == TP_DBUS_ERROR_OBJECT_REMOVED) { /* presumably the user asked for it to be deleted... */ priv->reason = TP_CONNECTION_STATUS_REASON_REQUESTED; priv->error = g_strdup (TP_ERROR_STR_CANCELLED); g_hash_table_insert (priv->error_details, g_strdup ("debug-message"), tp_g_value_slice_new_static_string ("TpAccount was removed")); } else { gchar *s; priv->reason = TP_CONNECTION_STATUS_REASON_NONE_SPECIFIED; priv->error = g_strdup (TP_ERROR_STR_DISCONNECTED); s = g_strdup_printf ("TpAccount was invalidated: %s #%u: %s", g_quark_to_string (domain), code, message); g_hash_table_insert (priv->error_details, g_strdup ("debug-message"), tp_g_value_slice_new_take_string (s)); } g_object_notify ((GObject *) self, "connection-status"); g_object_notify ((GObject *) self, "connection-status-reason"); g_object_notify ((GObject *) self, "connection-error"); g_object_notify ((GObject *) self, "connection-error-details"); } } static void _tp_account_removed_cb (TpAccount *self, gpointer unused G_GNUC_UNUSED, GObject *object G_GNUC_UNUSED) { GError e = { TP_DBUS_ERRORS, TP_DBUS_ERROR_OBJECT_REMOVED, "Account removed" }; if (self->priv->removed) return; self->priv->removed = TRUE; tp_proxy_invalidate ((TpProxy *) self, &e); } static void set_connection_prepare_cb (GObject *object, GAsyncResult *res, gpointer user_data) { TpConnection *connection = (TpConnection *) object; TpAccount *self = user_data; GError *error = NULL; if (!tp_proxy_prepare_finish (object, res, &error)) { DEBUG ("Error preparing connection: %s", error->message); g_clear_error (&error); goto OUT; } /* Connection could have changed again while we were preparing it */ if (self->priv->connection == connection) { self->priv->connection_prepared = TRUE; g_object_notify ((GObject *) self, "connection"); } OUT: g_object_unref (self); } static void _tp_account_set_connection (TpAccount *account, const gchar *path); static void connection_invalidated_cb (TpConnection *connection, guint domain, gint code, gchar *message, TpAccount *account) { _tp_account_set_connection (account, "/"); } static void _tp_account_set_connection (TpAccount *account, const gchar *path) { TpAccountPrivate *priv = account->priv; gboolean had_public_connection; gboolean have_public_connection; GError *error = NULL; if (priv->connection != NULL) { const gchar *current; /* Do nothing if we already have a connection for the same path */ current = tp_proxy_get_object_path (priv->connection); if (!tp_strdiff (current, path)) return; g_signal_handlers_disconnect_by_func (priv->connection, connection_invalidated_cb, account); } had_public_connection = (priv->connection != NULL && !connection_is_internal (account)); tp_clear_object (&account->priv->connection); g_free (priv->connection_object_path); priv->connection_object_path = g_strdup (path); priv->connection_prepared = FALSE; /* The account has no connection */ if (!tp_strdiff ("/", path)) { /* Do not emit change notifications if the connection was not yet made * public */ if (had_public_connection) g_object_notify (G_OBJECT (account), "connection"); return; } priv->connection = tp_simple_client_factory_ensure_connection ( tp_proxy_get_factory (account), path, NULL, &error); if (priv->connection == NULL) { DEBUG ("Failed to create a new TpConnection: %s", error->message); g_error_free (error); } else { tp_g_signal_connect_object (priv->connection, "invalidated", G_CALLBACK (connection_invalidated_cb), account, 0); _tp_connection_set_account (priv->connection, account); if (tp_proxy_is_prepared (account, TP_ACCOUNT_FEATURE_CONNECTION)) { GArray *features; features = tp_simple_client_factory_dup_connection_features ( tp_proxy_get_factory (account), priv->connection); tp_proxy_prepare_async (priv->connection, (GQuark *) features->data, set_connection_prepare_cb, g_object_ref (account)); g_array_unref (features); } } have_public_connection = (priv->connection != NULL && !connection_is_internal (account)); /* Do not emit signal if connection wasn't public and still isn't */ if (had_public_connection || have_public_connection) g_object_notify (G_OBJECT (account), "connection"); } static void _tp_account_got_all_storage_cb (TpProxy *proxy, GHashTable *properties, const GError *error, gpointer user_data, GObject *object) { TpAccount *self = TP_ACCOUNT (proxy); GSimpleAsyncResult *result = user_data; if (error != NULL) DEBUG ("Error getting Storage properties: %s", error->message); if (properties == NULL) self->priv->storage_provider = NULL; else self->priv->storage_provider = g_strdup (tp_asv_get_string (properties, "StorageProvider")); if (!tp_str_empty (self->priv->storage_provider)) { self->priv->storage_identifier = tp_g_value_slice_dup ( tp_asv_get_boxed (properties, "StorageIdentifier", G_TYPE_VALUE)); self->priv->storage_restrictions = tp_asv_get_uint32 (properties, "StorageRestrictions", NULL); } /* if the StorageProvider isn't known, set it to the empty string */ if (self->priv->storage_provider == NULL) self->priv->storage_provider = g_strdup (""); g_simple_async_result_complete_in_idle (result); } static void tp_account_prepare_storage_async (TpProxy *proxy, const TpProxyFeature *feature, GAsyncReadyCallback callback, gpointer user_data) { TpAccount *self = TP_ACCOUNT (proxy); GSimpleAsyncResult *result; result = g_simple_async_result_new ((GObject *) proxy, callback, user_data, tp_account_prepare_storage_async); g_assert (self->priv->storage_provider == NULL); tp_cli_dbus_properties_call_get_all (self, -1, TP_IFACE_ACCOUNT_INTERFACE_STORAGE, _tp_account_got_all_storage_cb, result, g_object_unref, G_OBJECT (self)); } static void _tp_account_update (TpAccount *account, GHashTable *properties) { TpProxy *proxy = TP_PROXY (account); TpAccountPrivate *priv = account->priv; GValueArray *arr; TpConnectionStatus old_s = priv->connection_status; gboolean status_changed = FALSE; gboolean presence_changed = FALSE; const gchar *status; const gchar *message; tp_proxy_add_interfaces (proxy, tp_asv_get_strv (properties, "Interfaces")); if (g_hash_table_lookup (properties, "ConnectionStatus") != NULL) { priv->connection_status = tp_asv_get_uint32 (properties, "ConnectionStatus", NULL); if (old_s != priv->connection_status) status_changed = TRUE; } if (g_hash_table_lookup (properties, "ConnectionStatusReason") != NULL) { TpConnectionStatusReason old = priv->reason; priv->reason = tp_asv_get_uint32 (properties, "ConnectionStatusReason", NULL); if (old != priv->reason) status_changed = TRUE; } if (g_hash_table_lookup (properties, "ConnectionError") != NULL) { const gchar *new_error = tp_asv_get_string (properties, "ConnectionError"); if (tp_str_empty (new_error)) new_error = NULL; if (tp_strdiff (new_error, priv->error)) { tp_clear_pointer (&priv->error, g_free); priv->error = g_strdup (new_error); status_changed = TRUE; } } if (g_hash_table_lookup (properties, "ConnectionErrorDetails") != NULL) { const GHashTable *details = tp_asv_get_boxed (properties, "ConnectionErrorDetails", TP_HASH_TYPE_STRING_VARIANT_MAP); if ((details != NULL && tp_asv_size (details) > 0) || tp_asv_size (priv->error_details) > 0) { g_hash_table_remove_all (priv->error_details); if (details != NULL) tp_g_hash_table_update (priv->error_details, (GHashTable *) details, (GBoxedCopyFunc) g_strdup, (GBoxedCopyFunc) tp_g_value_slice_dup); status_changed = TRUE; } } if (status_changed) { if (priv->connection_status == TP_CONNECTION_STATUS_CONNECTED) { /* our connection status is CONNECTED - clear any error we may * have recorded previously */ g_hash_table_remove_all (priv->error_details); tp_clear_pointer (&priv->error, g_free); } else if (priv->error == NULL) { /* our connection status is worse than CONNECTED but the * AccountManager didn't tell us why, so attempt to guess * a detailed error from the status reason */ const gchar *guessed = NULL; _tp_connection_status_reason_to_gerror (priv->reason, old_s, &guessed, NULL); if (guessed == NULL) guessed = TP_ERROR_STR_DISCONNECTED; priv->error = g_strdup (guessed); } } if (g_hash_table_lookup (properties, "CurrentPresence") != NULL) { presence_changed = TRUE; arr = tp_asv_get_boxed (properties, "CurrentPresence", TP_STRUCT_TYPE_SIMPLE_PRESENCE); tp_value_array_unpack (arr, 3, &priv->cur_presence, &status, &message); g_free (priv->cur_status); priv->cur_status = g_strdup (status); g_free (priv->cur_message); priv->cur_message = g_strdup (message); } if (g_hash_table_lookup (properties, "RequestedPresence") != NULL) { arr = tp_asv_get_boxed (properties, "RequestedPresence", TP_STRUCT_TYPE_SIMPLE_PRESENCE); tp_value_array_unpack (arr, 3, &priv->requested_presence, &status, &message); g_free (priv->requested_status); priv->requested_status = g_strdup (status); g_free (priv->requested_message); priv->requested_message = g_strdup (message); g_object_notify (G_OBJECT (account), "requested-presence-type"); g_object_notify (G_OBJECT (account), "requested-status"); g_object_notify (G_OBJECT (account), "requested-status-message"); } if (g_hash_table_lookup (properties, "AutomaticPresence") != NULL) { arr = tp_asv_get_boxed (properties, "AutomaticPresence", TP_STRUCT_TYPE_SIMPLE_PRESENCE); tp_value_array_unpack (arr, 3, &priv->auto_presence, &status, &message); g_free (priv->auto_status); priv->auto_status = g_strdup (status); g_free (priv->auto_message); priv->auto_message = g_strdup (message); g_object_notify (G_OBJECT (account), "automatic-presence-type"); g_object_notify (G_OBJECT (account), "automatic-status"); g_object_notify (G_OBJECT (account), "automatic-status-message"); } if (g_hash_table_lookup (properties, "DisplayName") != NULL) { gchar *old = priv->display_name; priv->display_name = g_strdup (tp_asv_get_string (properties, "DisplayName")); if (tp_strdiff (old, priv->display_name)) g_object_notify (G_OBJECT (account), "display-name"); g_free (old); } if (g_hash_table_lookup (properties, "Nickname") != NULL) { gchar *old = priv->nickname; priv->nickname = g_strdup (tp_asv_get_string (properties, "Nickname")); if (tp_strdiff (old, priv->nickname)) g_object_notify (G_OBJECT (account), "nickname"); g_free (old); } if (g_hash_table_lookup (properties, "Supersedes") != NULL) { GStrv old = priv->supersedes; GPtrArray *new_arr = tp_asv_get_boxed (properties, "Supersedes", TP_ARRAY_TYPE_OBJECT_PATH_LIST); gboolean changed = FALSE; guint i; if (new_arr == NULL) { priv->supersedes = g_new0 (gchar *, 1); } else { priv->supersedes = g_new0 (gchar *, new_arr->len + 1); for (i = 0; i < new_arr->len; i++) priv->supersedes[i] = g_strdup (g_ptr_array_index (new_arr, i)); } if (new_arr == NULL || new_arr->len == 0) { changed = (old != NULL && *old != NULL); } else if (old == NULL || *old == NULL || g_strv_length (old) != new_arr->len) { changed = TRUE; } else { for (i = 0; i < new_arr->len; i++) { if (tp_strdiff (old[i], priv->supersedes[i])) { changed = TRUE; break; } } } if (changed) g_object_notify (G_OBJECT (account), "supersedes"); g_strfreev (old); } if (g_hash_table_lookup (properties, "NormalizedName") != NULL) { gchar *old = priv->normalized_name; priv->normalized_name = g_strdup (tp_asv_get_string (properties, "NormalizedName")); if (tp_strdiff (old, priv->normalized_name)) g_object_notify (G_OBJECT (account), "normalized-name"); g_free (old); } if (g_hash_table_lookup (properties, "Icon") != NULL) { const gchar *icon_name; gchar *old = priv->icon_name; icon_name = tp_asv_get_string (properties, "Icon"); if (tp_str_empty (icon_name)) priv->icon_name = g_strdup_printf ("im-%s", priv->proto_name); else priv->icon_name = g_strdup (icon_name); if (tp_strdiff (old, priv->icon_name)) g_object_notify (G_OBJECT (account), "icon-name"); g_free (old); } if (g_hash_table_lookup (properties, "Enabled") != NULL) { gboolean enabled = tp_asv_get_boolean (properties, "Enabled", NULL); if (priv->enabled != enabled) { priv->enabled = enabled; g_object_notify (G_OBJECT (account), "enabled"); } } if (g_hash_table_lookup (properties, "Service") != NULL) { const gchar *service; gchar *old = priv->service; service = tp_asv_get_string (properties, "Service"); if (tp_str_empty (service)) priv->service = g_strdup (priv->proto_name); else priv->service = g_strdup (service); if (tp_strdiff (old, priv->service)) g_object_notify (G_OBJECT (account), "service"); g_free (old); } if (g_hash_table_lookup (properties, "Valid") != NULL) { gboolean old = priv->valid; priv->valid = tp_asv_get_boolean (properties, "Valid", NULL); if (old != priv->valid) g_object_notify (G_OBJECT (account), "valid"); } if (g_hash_table_lookup (properties, "Parameters") != NULL) { GHashTable *parameters; parameters = tp_asv_get_boxed (properties, "Parameters", TP_HASH_TYPE_STRING_VARIANT_MAP); if (priv->parameters != NULL) g_hash_table_unref (priv->parameters); priv->parameters = g_boxed_copy (TP_HASH_TYPE_STRING_VARIANT_MAP, parameters); /* this isn't a property, so we don't notify */ } if (status_changed) { g_signal_emit (account, signals[STATUS_CHANGED], 0, old_s, priv->connection_status, priv->reason, priv->error, priv->error_details); g_object_notify (G_OBJECT (account), "connection-status"); g_object_notify (G_OBJECT (account), "connection-status-reason"); g_object_notify (G_OBJECT (account), "connection-error"); g_object_notify (G_OBJECT (account), "connection-error-details"); } if (presence_changed) { g_signal_emit (account, signals[PRESENCE_CHANGED], 0, priv->cur_presence, priv->cur_status, priv->cur_message); g_object_notify (G_OBJECT (account), "current-presence-type"); g_object_notify (G_OBJECT (account), "current-status"); g_object_notify (G_OBJECT (account), "current-status-message"); } if (g_hash_table_lookup (properties, "Connection") != NULL) { const gchar *path = tp_asv_get_object_path (properties, "Connection"); _tp_account_set_connection (account, path); } if (g_hash_table_lookup (properties, "ChangingPresence") != NULL) { gboolean old = priv->changing_presence; priv->changing_presence = tp_asv_get_boolean (properties, "ChangingPresence", NULL); if (old != priv->changing_presence) g_object_notify (G_OBJECT (account), "changing-presence"); } if (g_hash_table_lookup (properties, "ConnectAutomatically") != NULL) { gboolean old = priv->connect_automatically; priv->connect_automatically = tp_asv_get_boolean (properties, "ConnectAutomatically", NULL); if (old != priv->connect_automatically) g_object_notify (G_OBJECT (account), "connect-automatically"); } if (g_hash_table_lookup (properties, "HasBeenOnline") != NULL) { gboolean old = priv->has_been_online; priv->has_been_online = tp_asv_get_boolean (properties, "HasBeenOnline", NULL); if (old != priv->has_been_online) g_object_notify (G_OBJECT (account), "has-been-online"); } _tp_proxy_set_feature_prepared (proxy, TP_ACCOUNT_FEATURE_CORE, TRUE); } static void _tp_account_properties_changed (TpAccount *proxy, GHashTable *properties, gpointer user_data, GObject *weak_object) { TpAccount *self = TP_ACCOUNT (weak_object); if (!tp_proxy_is_prepared (self, TP_ACCOUNT_FEATURE_CORE)) return; _tp_account_update (self, properties); } static void avatar_changed_cb (TpAccount *self, gpointer user_data, GObject *weak_object) { g_signal_emit (self, signals[AVATAR_CHANGED], 0); } static void _tp_account_got_all_cb (TpProxy *proxy, GHashTable *properties, const GError *error, gpointer user_data, GObject *weak_object) { TpAccount *self = TP_ACCOUNT (weak_object); DEBUG ("Got whole set of properties for %s", tp_proxy_get_object_path (self)); if (error != NULL) { DEBUG ("Failed to get the initial set of account properties: %s", error->message); tp_proxy_invalidate ((TpProxy *) self, error); return; } _tp_account_update (self, properties); /* We can't try connecting this signal earlier as tp_proxy_add_interfaces() * has to be called first if we support the Avatar interface. */ tp_cli_account_interface_avatar_connect_to_avatar_changed (self, avatar_changed_cb, NULL, NULL, G_OBJECT (self), NULL); } static void addressing_props_changed (TpAccount *self, GHashTable *changed_properties) { const gchar * const * v; if (self->priv->uri_schemes == NULL) /* We did not fetch the initial value yet, ignoring */ return; v = tp_asv_get_strv (changed_properties, "URISchemes"); if (v == NULL) return; g_strfreev (self->priv->uri_schemes); self->priv->uri_schemes = g_strdupv ((GStrv) v); g_object_notify (G_OBJECT (self), "uri-schemes"); } 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) { TpAccount *self = TP_ACCOUNT (weak_object); if (!tp_strdiff (interface_name, TP_IFACE_ACCOUNT_INTERFACE_ADDRESSING)) { addressing_props_changed (self, changed_properties); } } static void _tp_account_constructed (GObject *object) { TpAccount *self = TP_ACCOUNT (object); TpAccountPrivate *priv = self->priv; void (*chain_up) (GObject *) = ((GObjectClass *) tp_account_parent_class)->constructed; GError *error = NULL; TpProxySignalConnection *sc; if (chain_up != NULL) chain_up (object); g_return_if_fail (tp_proxy_get_dbus_daemon (self) != NULL); _tp_proxy_ensure_factory (self, NULL); sc = tp_cli_account_connect_to_removed (self, _tp_account_removed_cb, NULL, NULL, NULL, &error); if (sc == NULL) { CRITICAL ("Couldn't connect to Removed: %s", error->message); g_error_free (error); } G_GNUC_BEGIN_IGNORE_DEPRECATIONS tp_account_parse_object_path (tp_proxy_get_object_path (self), &(priv->cm_name), &(priv->proto_name), NULL, NULL); G_GNUC_END_IGNORE_DEPRECATIONS priv->icon_name = g_strdup_printf ("im-%s", priv->proto_name); priv->service = g_strdup (priv->proto_name); g_signal_connect (self, "invalidated", G_CALLBACK (_tp_account_invalidated_cb), NULL); tp_cli_account_connect_to_account_property_changed (self, _tp_account_properties_changed, NULL, NULL, object, NULL); tp_cli_dbus_properties_connect_to_properties_changed (self, dbus_properties_changed_cb, NULL, NULL, object, NULL); tp_cli_dbus_properties_call_get_all (self, -1, TP_IFACE_ACCOUNT, _tp_account_got_all_cb, NULL, NULL, G_OBJECT (self)); } static void _tp_account_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { TpAccount *self = TP_ACCOUNT (object); switch (prop_id) { case PROP_ENABLED: g_value_set_boolean (value, self->priv->enabled); break; case PROP_CURRENT_PRESENCE_TYPE: g_value_set_uint (value, self->priv->cur_presence); break; case PROP_CURRENT_STATUS: g_value_set_string (value, self->priv->cur_status); break; case PROP_CURRENT_STATUS_MESSAGE: g_value_set_string (value, self->priv->cur_message); break; case PROP_CONNECTION_STATUS: g_value_set_uint (value, self->priv->connection_status); break; case PROP_CONNECTION_STATUS_REASON: g_value_set_uint (value, self->priv->reason); break; case PROP_CONNECTION_ERROR: g_value_set_string (value, self->priv->error); break; case PROP_CONNECTION_ERROR_DETAILS: g_value_set_boxed (value, self->priv->error_details); break; case PROP_CONNECTION: g_value_set_object (value, tp_account_get_connection (self)); break; case PROP_DISPLAY_NAME: g_value_set_string (value, tp_account_get_display_name (self)); break; case PROP_CONNECTION_MANAGER: g_value_set_string (value, self->priv->cm_name); break; case PROP_CM_NAME: g_value_set_string (value, self->priv->cm_name); break; case PROP_PROTOCOL: g_value_set_string (value, self->priv->proto_name); break; case PROP_PROTOCOL_NAME: g_value_set_string (value, self->priv->proto_name); break; case PROP_ICON_NAME: g_value_set_string (value, self->priv->icon_name); break; case PROP_CHANGING_PRESENCE: g_value_set_boolean (value, self->priv->changing_presence); break; case PROP_CONNECT_AUTOMATICALLY: g_value_set_boolean (value, self->priv->connect_automatically); break; case PROP_HAS_BEEN_ONLINE: g_value_set_boolean (value, self->priv->has_been_online); break; case PROP_SERVICE: g_value_set_string (value, self->priv->service); break; case PROP_VALID: g_value_set_boolean (value, self->priv->valid); break; case PROP_REQUESTED_PRESENCE_TYPE: g_value_set_uint (value, self->priv->requested_presence); break; case PROP_REQUESTED_STATUS: g_value_set_string (value, self->priv->requested_status); break; case PROP_REQUESTED_STATUS_MESSAGE: g_value_set_string (value, self->priv->requested_message); break; case PROP_NICKNAME: g_value_set_string (value, self->priv->nickname); break; case PROP_SUPERSEDES: g_value_set_boxed (value, self->priv->supersedes); break; case PROP_URI_SCHEMES: g_value_set_boxed (value, self->priv->uri_schemes); break; case PROP_AUTOMATIC_PRESENCE_TYPE: g_value_set_uint (value, self->priv->auto_presence); break; case PROP_AUTOMATIC_STATUS: g_value_set_string (value, self->priv->auto_status); break; case PROP_AUTOMATIC_STATUS_MESSAGE: g_value_set_string (value, self->priv->auto_message); break; case PROP_NORMALIZED_NAME: g_value_set_string (value, tp_account_get_normalized_name (self)); break; case PROP_STORAGE_PROVIDER: g_value_set_string (value, self->priv->storage_provider); break; case PROP_STORAGE_IDENTIFIER: g_value_set_boxed (value, self->priv->storage_identifier); break; case PROP_STORAGE_IDENTIFIER_VARIANT: g_value_take_variant (value, tp_account_dup_storage_identifier_variant (self)); break; case PROP_STORAGE_RESTRICTIONS: g_value_set_uint (value, self->priv->storage_restrictions); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void _tp_account_dispose (GObject *object) { TpAccount *self = TP_ACCOUNT (object); TpAccountPrivate *priv = self->priv; if (priv->dispose_has_run) return; priv->dispose_has_run = TRUE; _tp_account_set_connection (self, "/"); /* release any references held by the object here */ if (G_OBJECT_CLASS (tp_account_parent_class)->dispose != NULL) G_OBJECT_CLASS (tp_account_parent_class)->dispose (object); } static void _tp_account_finalize (GObject *object) { TpAccount *self = TP_ACCOUNT (object); TpAccountPrivate *priv = self->priv; g_free (priv->connection_object_path); g_free (priv->cur_status); g_free (priv->cur_message); g_free (priv->requested_status); g_free (priv->requested_message); g_free (priv->error); g_free (priv->auto_status); g_free (priv->auto_message); g_free (priv->normalized_name); g_free (priv->nickname); g_strfreev (priv->supersedes); g_free (priv->cm_name); g_free (priv->proto_name); g_free (priv->icon_name); g_free (priv->display_name); g_free (priv->service); tp_clear_pointer (&priv->parameters, g_hash_table_unref); tp_clear_pointer (&priv->error_details, g_hash_table_unref); g_free (priv->storage_provider); tp_clear_pointer (&priv->storage_identifier, tp_g_value_slice_free); g_strfreev (priv->uri_schemes); /* free any data held directly by the object here */ if (G_OBJECT_CLASS (tp_account_parent_class)->finalize != NULL) G_OBJECT_CLASS (tp_account_parent_class)->finalize (object); } static void tp_account_class_init (TpAccountClass *klass) { TpProxyClass *proxy_class = (TpProxyClass *) klass; GObjectClass *object_class = (GObjectClass *) klass; g_type_class_add_private (klass, sizeof (TpAccountPrivate)); object_class->constructed = _tp_account_constructed; object_class->get_property = _tp_account_get_property; object_class->dispose = _tp_account_dispose; object_class->finalize = _tp_account_finalize; /** * TpAccount:enabled: * * Whether this account is enabled or not. * * One can receive change notifications on this property by connecting * to the #GObject::notify signal and using this property as the signal * detail. * * This is not guaranteed to have been retrieved until * tp_proxy_prepare_async() has finished; until then, the value is FALSE. * * Since: 0.9.0 */ g_object_class_install_property (object_class, PROP_ENABLED, g_param_spec_boolean ("enabled", "Enabled", "Whether this account is enabled or not", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); /** * TpAccount:current-presence-type: * * The account connection's current presence type * (a %TpConnectionPresenceType). * * One can receive change notifications on this property by connecting * to the #GObject::notify signal and using this property as the signal * detail. Change notifications for current-presence-type, * current-status and current-status-message are always emitted together, * so it is sufficient to connect to one of the notification signals. * * This is not guaranteed to have been retrieved until * tp_proxy_prepare_async() has finished; until then, the value is * %TP_CONNECTION_PRESENCE_TYPE_UNSET. * * Since: 0.9.0 */ g_object_class_install_property (object_class, PROP_CURRENT_PRESENCE_TYPE, g_param_spec_uint ("current-presence-type", "Presence", "The account connection's current presence type", 0, TP_NUM_CONNECTION_PRESENCE_TYPES, TP_CONNECTION_PRESENCE_TYPE_UNSET, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); /** * TpAccount:current-status: * * The current Status string of the account. * * One can receive change notifications on this property by connecting * to the #GObject::notify signal and using this property as the signal * detail. Change notifications for current-presence-type, * current-status and current-status-message are always emitted together, * so it is sufficient to connect to one of the notification signals. * * This is not guaranteed to have been retrieved until * tp_proxy_prepare_async() has finished; until then, the value is * %NULL. * * Since: 0.9.0 */ g_object_class_install_property (object_class, PROP_CURRENT_STATUS, g_param_spec_string ("current-status", "Current Status", "The Status string of the account", NULL, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); /** * TpAccount:current-status-message: * * The current status message message of the account. * * One can receive change notifications on this property by connecting * to the #GObject::notify signal and using this property as the signal * detail. Change notifications for current-presence-type, * current-status and current-status-message are always emitted together, * so it is sufficient to connect to one of the notification signals. * * This is not guaranteed to have been retrieved until * tp_proxy_prepare_async() has finished; until then, the value is * %NULL. * * Since: 0.9.0 */ g_object_class_install_property (object_class, PROP_CURRENT_STATUS_MESSAGE, g_param_spec_string ("current-status-message", "current-status-message", "The Status message string of the account", NULL, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); /** * TpAccount:changing-presence: * * %TRUE if an attempt is currently being made to change the account's * presence (#TpAccount:current-presence-type, #TpAccount:current-status * and #TpAccount:current-status-message) to match its requested presence * (#TpAccount:requested-presence-type, #TpAccount:requested-status * and #TpAccount:requested-status-message). * * One can receive change notifications on this property by connecting * to the #GObject::notify signal and using this property as the signal * detail. * * This is not guaranteed to have been retrieved until * tp_proxy_prepare_async() has finished; until then, the value is * %FALSE. * * Since: 0.11.6 */ g_object_class_install_property (object_class, PROP_CHANGING_PRESENCE, g_param_spec_boolean ("changing-presence", "Changing Presence", "TRUE if presence is changing", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); /** * TpAccount:connection-status: * * The account's connection status type (a %TpConnectionStatus). * * One can receive change notifications on this property by connecting * to the #TpAccount::status-changed signal, or by connecting * to the #GObject::notify signal and using this property as the signal * detail. * * This is not guaranteed to have been retrieved until * tp_proxy_prepare_async() has finished; until then, the value is * %TP_CONNECTION_STATUS_DISCONNECTED. * * Since: 0.9.0 */ g_object_class_install_property (object_class, PROP_CONNECTION_STATUS, g_param_spec_uint ("connection-status", "ConnectionStatus", "The account's connection status type", 0, TP_NUM_CONNECTION_STATUSES, TP_CONNECTION_STATUS_DISCONNECTED, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); /** * TpAccount:connection-status-reason: * * The account's connection status reason (a %TpConnectionStatusReason). * * One can receive change notifications on this property by connecting * to the #TpAccount::status-changed signal, or by connecting * to the #GObject::notify signal and using this property as the signal * detail. * * This is not guaranteed to have been retrieved until * tp_proxy_prepare_async() has finished; until then, the value is * %TP_CONNECTION_STATUS_REASON_NONE_SPECIFIED. * * Since: 0.9.0 */ g_object_class_install_property (object_class, PROP_CONNECTION_STATUS_REASON, g_param_spec_uint ("connection-status-reason", "ConnectionStatusReason", "The account's connection status reason", 0, TP_NUM_CONNECTION_STATUS_REASONS, TP_CONNECTION_STATUS_REASON_NONE_SPECIFIED, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); /** * TpAccount:connection-error: * * The D-Bus error name for the last disconnection or connection failure, * (in particular, %TP_ERROR_STR_CANCELLED if it was disconnected by user * request), or %NULL if the account is connected. * * One can receive change notifications on this property by connecting * to the #TpAccount::status-changed signal, or by connecting * to the #GObject::notify signal and using this property as the signal * detail. * * This is not guaranteed to have been retrieved until * tp_proxy_prepare_async() has finished; until then, the value is * %NULL. * * Since: 0.11.7 */ g_object_class_install_property (object_class, PROP_CONNECTION_ERROR, g_param_spec_string ("connection-error", "ConnectionError", "The account's last connection error", NULL, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); /** * TpAccount:connection-error-details: * * A map from string to #GValue containing extensible error details * related to #TpAccount:connection-error. Functions like tp_asv_get_string() * can be used to read from this map. * * The keys for this map are defined by * the Telepathy D-Bus * Interface Specification. They will typically include * debug-message, which is a debugging message in the C * locale, analogous to #GError.message. * * One can receive change notifications on this property by connecting * to the #TpAccount::status-changed signal, or by connecting * to the #GObject::notify signal and using this property as the signal * detail. * * This is not guaranteed to have been retrieved until * tp_proxy_prepare_async() has finished; until then, the value is * an empty map. * * Since: 0.11.7 */ g_object_class_install_property (object_class, PROP_CONNECTION_ERROR_DETAILS, g_param_spec_boxed ("connection-error-details", "ConnectionErrorDetails", "Extensible details of the account's last connection error", G_TYPE_HASH_TABLE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); /** * TpAccount:connection: * * The connection of the account, or %NULL if account is offline. * Note that the returned #TpConnection is not guaranteed to have any * features pre-prepared (not even %TP_CONNECTION_FEATURE_CORE) unless * %TP_ACCOUNT_FEATURE_CONNECTION has been prepared on the account * * One can receive change notifications on this property by connecting * to the #GObject::notify signal and using this property as the signal * detail. If %TP_ACCOUNT_FEATURE_CONNECTION has been prepared, this signal * will be delayed until the connection is ready. * * This is not guaranteed to have been retrieved until * tp_proxy_prepare_async() has finished; until then, the value is * %NULL. * * Since: 0.9.0 */ g_object_class_install_property (object_class, PROP_CONNECTION, g_param_spec_object ("connection", "Connection", "The account's connection", TP_TYPE_CONNECTION, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); /** * TpAccount:display-name: * * The account's display name, from the DisplayName property. * * One can receive change notifications on this property by connecting * to the #GObject::notify signal and using this property as the signal * detail. * * This is not guaranteed to have been retrieved until * tp_proxy_prepare_async() has finished; until then, the value is * %NULL. * * Since: 0.9.0 */ g_object_class_install_property (object_class, PROP_DISPLAY_NAME, g_param_spec_string ("display-name", "DisplayName", "The account's display name", NULL, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); /** * TpAccount:connection-manager: * * The account's connection manager name. * * Since: 0.9.0 * Deprecated: Use #TpAccount:cm-name instead. */ g_object_class_install_property (object_class, PROP_CONNECTION_MANAGER, g_param_spec_string ("connection-manager", "Connection manager", "The account's connection manager name", NULL, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); /** * TpAccount:protocol: * * The account's machine-readable protocol name, such as "jabber", "msn" or * "local-xmpp". Recommended names for most protocols can be found in the * Telepathy D-Bus Interface Specification. * * Since: 0.9.0 * Deprecated: Use #TpAccount:protocol-name instead. */ g_object_class_install_property (object_class, PROP_PROTOCOL, g_param_spec_string ("protocol", "Protocol", "The account's protocol name", NULL, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); /** * TpAccount:cm-name: * * The account's connection manager name. * * Since: 0.19.3 */ g_object_class_install_property (object_class, PROP_CM_NAME, g_param_spec_string ("cm-name", "Connection manager", "The account's connection manager name", NULL, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); /** * TpAccount:protocol-name: * * The account's machine-readable protocol name, such as "jabber", "msn" or * "local-xmpp". Recommended names for most protocols can be found in the * Telepathy D-Bus Interface Specification. * * Since: 0.19.3 */ g_object_class_install_property (object_class, PROP_PROTOCOL_NAME, g_param_spec_string ("protocol-name", "Protocol", "The account's protocol name", NULL, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); /** * TpAccount:service: * * A machine-readable name identifying a specific service to which this * account connects, or a copy of #TpAccount:protocol if there is no more * specific service. * * Well-known names for various services can be found in the Telepathy D-Bus * Interface Specification. * * For instance, accounts for the "jabber" protocol should have the service * names "google-talk", "ovi-chat", "facebook" and "lj-talk" for accounts * that connect to Google Talk, Ovi Chat, Facebook and Livejournal, * respectively, and this property will be "jabber" for accounts that * connect to a generic Jabber server. * * To change this property, use * tp_account_set_service_async(). * * Since: 0.11.9 */ g_object_class_install_property (object_class, PROP_SERVICE, g_param_spec_string ("service", "Service", "The account's service name", NULL, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); /** * TpAccount:icon-name: * * The account's icon name. To change this propery, use * tp_account_set_icon_name_async(). * * One can receive change notifications on this property by connecting * to the #GObject::notify signal and using this property as the signal * detail. * * This is not guaranteed to have been retrieved until * tp_proxy_prepare_async() has finished; until then, the value is * %NULL. * * Since: 0.9.0 */ g_object_class_install_property (object_class, PROP_ICON_NAME, g_param_spec_string ("icon-name", "Icon", "The account's icon name", NULL, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); /** * TpAccount:connect-automatically: * * Whether the account should connect automatically or not. To change this * property, use tp_account_set_connect_automatically_async(). * * One can receive change notifications on this property by connecting * to the #GObject::notify signal and using this property as the signal * detail. * * This is not guaranteed to have been retrieved until * tp_proxy_prepare_async() has finished; until then, the value is * %FALSE. * * Since: 0.9.0 */ g_object_class_install_property (object_class, PROP_CONNECT_AUTOMATICALLY, g_param_spec_boolean ("connect-automatically", "ConnectAutomatically", "Whether this account should connect automatically or not", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); /** * TpAccount:has-been-online: * * Whether this account has been online or not. * * One can receive change notifications on this property by connecting * to the #GObject::notify signal and using this property as the signal * detail. * * This is not guaranteed to have been retrieved until * tp_proxy_prepare_async() has finished; until then, the value is * %FALSE. * * Since: 0.9.0 */ g_object_class_install_property (object_class, PROP_HAS_BEEN_ONLINE, g_param_spec_boolean ("has-been-online", "HasBeenOnline", "Whether this account has been online or not", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); /** * TpAccount:valid: * * Whether this account is valid. * * One can receive change notifications on this property by connecting * to the #GObject::notify signal and using this property as the signal * detail. * * This is not guaranteed to have been retrieved until * tp_proxy_prepare_async() has finished; until then, the value is * %FALSE. * * Since: 0.9.0 */ g_object_class_install_property (object_class, PROP_VALID, g_param_spec_boolean ("valid", "Valid", "Whether this account is valid", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); /** * TpAccount:requested-presence-type: * * The account's requested presence type (a #TpConnectionPresenceType). * * Since 0.13.8, * one can receive change notifications on this property by connecting * to the #GObject::notify signal and using this property as the signal * detail. Change notifications for requested-presence-type, * requested-status and requested-status-message are always emitted together, * so it is sufficient to connect to one of the notification signals. * * This is not guaranteed to have been retrieved until * tp_proxy_prepare_async() has finished; until then, the value is * %NULL. * * Since: 0.9.0 */ g_object_class_install_property (object_class, PROP_REQUESTED_PRESENCE_TYPE, g_param_spec_uint ("requested-presence-type", "RequestedPresence", "The account's requested presence type", 0, TP_NUM_CONNECTION_PRESENCE_TYPES, TP_CONNECTION_PRESENCE_TYPE_UNSET, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); /** * TpAccount:requested-status: * * The requested Status string of the account. * * Since 0.13.8, * one can receive change notifications on this property by connecting * to the #GObject::notify signal and using this property as the signal * detail. Change notifications for requested-presence-type, * requested-status and requested-status-message are always emitted together, * so it is sufficient to connect to one of the notification signals. * * This is not guaranteed to have been retrieved until * tp_proxy_prepare_async() has finished; until then, the value is * %NULL. * * Since: 0.9.0 */ g_object_class_install_property (object_class, PROP_REQUESTED_STATUS, g_param_spec_string ("requested-status", "RequestedStatus", "The account's requested status string", NULL, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); /** * TpAccount:requested-status-message: * * The requested status message message of the account. * * Since 0.13.8, * one can receive change notifications on this property by connecting * to the #GObject::notify signal and using this property as the signal * detail. Change notifications for requested-presence-type, * requested-status and requested-status-message are always emitted together, * so it is sufficient to connect to one of the notification signals. * * This is not guaranteed to have been retrieved until * tp_proxy_prepare_async() has finished; until then, the value is * %NULL. * * Since: 0.9.0 */ g_object_class_install_property (object_class, PROP_REQUESTED_STATUS_MESSAGE, g_param_spec_string ("requested-status-message", "RequestedStatusMessage", "The requested Status message string of the account", NULL, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); /** * TpAccount:nickname: * * The nickname that should be set for the user on this account. * * One can receive change notifications on this property by connecting * to the #GObject::notify signal and using this property as the signal * detail. * * This is not guaranteed to have been retrieved until * tp_proxy_prepare_async() has finished; until then, the value is * %NULL. * * Since: 0.9.0 */ g_object_class_install_property (object_class, PROP_NICKNAME, g_param_spec_string ("nickname", "Nickname", "The account's nickname", NULL, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); /** * TpAccount:automatic-presence-type: * * The account's automatic presence type (a #TpConnectionPresenceType). * * When the account is put online automatically, for instance to make a * channel request or because network connectivity becomes available, * the automatic presence type, status and message will be copied to * their "requested" counterparts. * * One can receive change notifications on this property by connecting * to the #GObject::notify signal and using this property as the signal * detail. Change notifications for automatic-presence-type, * automatic-status and automatic-status-message are always emitted together, * so it is sufficient to connect to one of the notification signals. * * This is not guaranteed to have been retrieved until * tp_proxy_prepare_async() has finished; until then, the value is * %TP_CONNECTION_PRESENCE_TYPE_UNSET. * * Since: 0.13.8 */ g_object_class_install_property (object_class, PROP_AUTOMATIC_PRESENCE_TYPE, g_param_spec_uint ("automatic-presence-type", "AutomaticPresence type", "Presence type used to put the account online automatically", 0, TP_NUM_CONNECTION_PRESENCE_TYPES, TP_CONNECTION_PRESENCE_TYPE_UNSET, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); /** * TpAccount:automatic-status: * * The string status name to use in conjunction with the * #TpAccount:automatic-presence-type. * * One can receive change notifications on this property by connecting * to the #GObject::notify signal and using this property as the signal * detail. Change notifications for automatic-presence-type, * automatic-status and automatic-status-message are always emitted together, * so it is sufficient to connect to one of the notification signals. * * This is not guaranteed to have been retrieved until * tp_proxy_prepare_async() has finished; until then, the value is * %NULL. * * Since: 0.13.8 */ g_object_class_install_property (object_class, PROP_AUTOMATIC_STATUS, g_param_spec_string ("automatic-status", "AutomaticPresence status", "Presence status used to put the account online automatically", NULL, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); /** * TpAccount:automatic-status-message: * * The user-defined message to use in conjunction with the * #TpAccount:automatic-presence-type. * * One can receive change notifications on this property by connecting * to the #GObject::notify signal and using this property as the signal * detail. Change notifications for automatic-presence-type, * automatic-status and automatic-status-message are always emitted together, * so it is sufficient to connect to one of the notification signals. * * This is not guaranteed to have been retrieved until * tp_proxy_prepare_async() has finished; until then, the value is * %NULL. * * Since: 0.13.8 */ g_object_class_install_property (object_class, PROP_AUTOMATIC_STATUS_MESSAGE, g_param_spec_string ("automatic-status-message", "AutomaticPresence message", "User-defined message used to put the account online automatically", NULL, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); /** * TpAccount:normalized-name: * * The normalized form of the user's own unique identifier on this * protocol. For example, on XMPP accounts this is the user's JID; on * ICQ this is the user's UIN; and so on. * * One can receive change notifications on this property by connecting * to the #GObject::notify signal and using this property as the signal * detail. * * This is not guaranteed to have been retrieved until * tp_proxy_prepare_async() has finished; until then, the value is * %NULL. * * Since: 0.13.8 */ g_object_class_install_property (object_class, PROP_NORMALIZED_NAME, g_param_spec_string ("normalized-name", "NormalizedName", "The normalized identifier of the user", NULL, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); /** * TpAccount:storage-provider: * * The storage provider for this account. * * The name of the account storage implementation. When this * is the empty string the account is internally stored. * * This property cannot change once an Account has been created. * * This is not guaranteed to have been retrieved until the * %TP_ACCOUNT_FEATURE_STORAGE feature has been prepared; until then, * the value is %NULL. * * Since: 0.13.2 */ g_object_class_install_property (object_class, PROP_STORAGE_PROVIDER, g_param_spec_string ("storage-provider", "StorageProvider", "The storage provider for this account", NULL, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); /** * TpAccount:storage-identifier: * * The storage identifier for this account. * * A provider-specific variant type used to identify this account with the * provider. This value will be %NULL if #TpAccount:storage-provider is * an empty string. * * This property cannot change once an Account has been created. * * This is not guaranteed to have been retrieved until the * %TP_ACCOUNT_FEATURE_STORAGE feature has been prepared; until then, * the value is %NULL. * * Since: 0.13.2 */ g_object_class_install_property (object_class, PROP_STORAGE_IDENTIFIER, g_param_spec_boxed ("storage-identifier", "StorageIdentifier", "The storage identifier for this account", G_TYPE_VALUE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); /** * TpAccount:storage-identifier-variant: * * Provider-specific information used to identify this * account. Use g_variant_get_type() to check that the type * is what you expect. For instance, if you use a * #TpAccount:storage-provider with numeric identifiers for accounts, * this variant might have type %G_VARIANT_TYPE_UINT32; * if the storage provider has string-based identifiers, it should * have type %G_VARIANT_TYPE_STRING. * * This property cannot change once an Account has been created. * * This is not guaranteed to have been retrieved until the * %TP_ACCOUNT_FEATURE_STORAGE feature has been prepared; until then, * the value is %NULL. * * Since: 0.13.2 */ g_object_class_install_property (object_class, PROP_STORAGE_IDENTIFIER_VARIANT, g_param_spec_variant ("storage-identifier-variant", "StorageIdentifier as variant", "The storage identifier for this account", G_VARIANT_TYPE_ANY, NULL, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); /** * TpAccount:storage-restrictions: * * The storage restrictions for this account. * * A bitfield of #TpStorageRestrictionFlags that give the limitations of * this account imposed by the storage provider. This value will be 0 * if #TpAccount:storage-provider is an empty string. * * This property cannot change once an Account has been created. * * This is not guaranteed to have been retrieved until the * %TP_ACCOUNT_FEATURE_STORAGE feature has been prepared; until then, * the value is 0. * * Since: 0.13.2 */ g_object_class_install_property (object_class, PROP_STORAGE_RESTRICTIONS, g_param_spec_uint ("storage-restrictions", "StorageRestrictions", "The storage restrictions for this account", 0, G_MAXUINT, 0, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); /** * TpAccount:supersedes: * * The object paths of previously-active accounts superseded by this one. * For instance, this can be used in a logger to read old logs for an * account that has been migrated from one connection manager to another. * * This is not guaranteed to have been retrieved until the * %TP_ACCOUNT_FEATURE_CORE feature has been prepared; until then, * the value is NULL. * * Since: 0.17.5 */ g_object_class_install_property (object_class, PROP_SUPERSEDES, g_param_spec_boxed ("supersedes", "Supersedes", "Accounts superseded by this one", G_TYPE_STRV, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); /** * TpAccount:uri-schemes: * * If the %TP_ACCOUNT_FEATURE_ADDRESSING feature has been prepared * successfully, a list of additional URI schemes for which this * account should be used if possible. Otherwise %NULL. * * For instance, a SIP or Skype account might have "tel" in this list if the * user would like to use that account to call phone numbers. * * This list should not contain the primary URI scheme(s) for the account's * protocol (for instance, "xmpp" for XMPP, or "sip" or "sips" for SIP), * since it should be assumed to be useful for those schemes in any case. * * The notify::uri-schemes signal cannot be relied on if the Account Manager * is Mission Control version 5.14.0 or older. * * Since: 0.21.0 */ g_object_class_install_property (object_class, PROP_URI_SCHEMES, g_param_spec_boxed ("uri-schemes", "URISchemes", "URISchemes", G_TYPE_STRV, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); /** * TpAccount::status-changed: * @account: the #TpAccount * @old_status: old #TpAccount:connection-status * @new_status: new #TpAccount:connection-status * @reason: the #TpAccount:connection-status-reason * @dbus_error_name: (allow-none): the #TpAccount:connection-error * @details: (element-type utf8 GObject.Value): the * #TpAccount:connection-error-details * * Emitted when the connection status on the account changes. * * The @dbus_error_name and @details parameters were present, but * non-functional (always %NULL), in older versions. They have been * available with their current behaviour since version 0.11.7. * * Since: 0.9.0 */ signals[STATUS_CHANGED] = g_signal_new ("status-changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 5, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_HASH_TABLE); /** * TpAccount::presence-changed: * @account: the #TpAccount * @presence: the new presence * @status: the new presence status * @status_message: the new presence status message * * Emitted when the presence of the account changes. * * Since: 0.9.0 */ signals[PRESENCE_CHANGED] = g_signal_new ("presence-changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING); /** * TpAccount::avatar-changed: * @self: a #TpAccount * * Emitted when the avatar changes. Call tp_account_get_avatar_async() * to get the new avatar data. * * Since: 0.23.0 */ signals[AVATAR_CHANGED] = g_signal_new ("avatar-changed", G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); proxy_class->interface = TP_IFACE_QUARK_ACCOUNT; proxy_class->list_features = _tp_account_list_features; tp_account_init_known_interfaces (); } /** * tp_account_init_known_interfaces: * * Ensure that the known interfaces for TpAccount have been set up. * This is done automatically when necessary, but for correct * overriding of library interfaces by local extensions, you should * call this function before calling * tp_proxy_or_subclass_hook_on_interface_add() with first argument * %TP_TYPE_ACCOUNT. * * Since: 0.7.32 */ void tp_account_init_known_interfaces (void) { static gsize once = 0; if (g_once_init_enter (&once)) { GType tp_type = TP_TYPE_ACCOUNT; tp_proxy_init_known_interfaces (); tp_proxy_or_subclass_hook_on_interface_add (tp_type, tp_cli_account_add_signals); tp_proxy_subclass_add_error_mapping (tp_type, TP_ERROR_PREFIX, TP_ERROR, TP_TYPE_ERROR); g_once_init_leave (&once, 1); } } /** * tp_account_new: * @bus_daemon: Proxy for the D-Bus daemon * @object_path: The non-NULL object path of this account * @error: Used to raise an error if @object_path is not valid * * Convenience function to create a new account proxy. The returned #TpAccount * is not guaranteed to be ready at the point of return. * * Returns: a new reference to an account proxy, or %NULL if @object_path is * not valid * Deprecated: Use tp_simple_client_factory_ensure_account() instead. */ TpAccount * tp_account_new (TpDBusDaemon *bus_daemon, const gchar *object_path, GError **error) { return _tp_account_new_with_factory (NULL, bus_daemon, object_path, error); } TpAccount * _tp_account_new_with_factory (TpSimpleClientFactory *factory, TpDBusDaemon *bus_daemon, const gchar *object_path, GError **error) { TpAccount *self; g_return_val_if_fail (TP_IS_DBUS_DAEMON (bus_daemon), NULL); g_return_val_if_fail (object_path != NULL, NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); G_GNUC_BEGIN_IGNORE_DEPRECATIONS if (!tp_account_parse_object_path (object_path, NULL, NULL, NULL, error)) return NULL; G_GNUC_END_IGNORE_DEPRECATIONS self = TP_ACCOUNT (g_object_new (TP_TYPE_ACCOUNT, "dbus-daemon", bus_daemon, "dbus-connection", ((TpProxy *) bus_daemon)->dbus_connection, "bus-name", TP_ACCOUNT_MANAGER_BUS_NAME, "object-path", object_path, "factory", factory, NULL)); return self; } static gchar * unescape_protocol (gchar *protocol) { if (strstr (protocol, "_2d") != NULL) { /* Work around MC5 bug where it escapes with tp_escape_as_identifier * rather than doing it properly. MC5 saves the object path in your * config, so if you've ever used a buggy MC5, the path will be wrong * forever. */ gchar **chunks = g_strsplit (protocol, "_2d", 0); gchar *new = g_strjoinv ("-", chunks); g_strfreev (chunks); g_free (protocol); protocol = new; } g_strdelimit (protocol, "_", '-'); return protocol; } /** * tp_account_get_connection: * @account: a #TpAccount * * * * Returns: (transfer none): the same as the #TpAccount:connection property * * Since: 0.9.0 **/ TpConnection * tp_account_get_connection (TpAccount *account) { TpAccountPrivate *priv; g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL); priv = account->priv; /* If we want to expose only prepared connection */ if (connection_is_internal (account)) return NULL; return priv->connection; } /** * tp_account_ensure_connection: * @account: a #TpAccount * @path: the path to connection object for #TpAccount * * Set the connection of the account by specifying the connection object path. * This function does not return a new ref and it is not guaranteed that the * returned #TpConnection object is ready. * * The use-case for this function is in a HandleChannels callback and you * already know the object path for the connection, so you can let @account * create its #TpConnection and return it for use. * * Returns: (transfer none): the connection of the account, or %NULL if either * the object path @path is invalid or it is the null-value "/" * * Since: 0.9.0 * Deprecated: New code should use tp_simple_client_factory_ensure_connection() * instead. **/ TpConnection * tp_account_ensure_connection (TpAccount *account, const gchar *path) { TpAccountPrivate *priv; g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL); priv = account->priv; /* double-check that the object path is valid */ if (!tp_dbus_check_valid_object_path (path, NULL)) return NULL; /* Should be a full object path, not the special "/" value */ if (!tp_strdiff (path, "/")) return NULL; _tp_account_set_connection (account, path); return priv->connection; } /** * tp_account_get_path_suffix: * @account: a #TpAccount * * Returns the portion of @account's object path after the standard * #TP_ACCOUNT_OBJECT_PATH_BASE prefix, of the form "cm/protocol/acct". This * string uniquely identifies the account. * * This function is only intended to be used when printing debug messages or in * tools for developer. For a string suitable for displaying to the user, see * tp_account_get_display_name(). To retrieve the connection manager and * protocol name parts of the object path, see * tp_account_get_connection_manager() and tp_account_get_protocol(). For * persistent identification of the account, use tp_proxy_get_object_path(). * * Returns: a suffix of @account's object path, for debugging purposes. * Since: 0.13.9 */ const gchar * tp_account_get_path_suffix (TpAccount *account) { const gchar *path; g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL); path = tp_proxy_get_object_path (account); g_return_val_if_fail (g_str_has_prefix (path, TP_ACCOUNT_OBJECT_PATH_BASE), path); return path + strlen (TP_ACCOUNT_OBJECT_PATH_BASE); } /** * tp_account_get_display_name: * @account: a #TpAccount * * * * Returns: the same as the #TpAccount:display-name property * * Since: 0.9.0 **/ const gchar * tp_account_get_display_name (TpAccount *account) { g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL); return account->priv->display_name; } /** * tp_account_is_valid: * @account: a #TpAccount * * * * Returns: the same as the #TpAccount:valid property * * Since: 0.9.0 */ gboolean tp_account_is_valid (TpAccount *account) { g_return_val_if_fail (TP_IS_ACCOUNT (account), FALSE); return account->priv->valid; } /** * tp_account_get_connection_manager: * @account: a #TpAccount * * * * Returns: the same as the #TpAccount:connection-manager property * * Since: 0.9.0 * Deprecated: Use tp_account_get_cm_name() instead. */ const gchar * tp_account_get_connection_manager (TpAccount *account) { g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL); return account->priv->cm_name; } /** * tp_account_get_protocol: * @account: a #TpAccount * * * * Returns: the same as the #TpAccount:protocol property * * Since: 0.9.0 * Deprecated: Use tp_account_get_cm_name() instead. */ const gchar * tp_account_get_protocol (TpAccount *account) { g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL); return account->priv->proto_name; } /** * tp_account_get_cm_name: * @account: a #TpAccount * * * * Returns: the same as the #TpAccount:cm-name property * * Since: 0.19.3 */ const gchar * tp_account_get_cm_name (TpAccount *account) { g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL); return account->priv->cm_name; } /** * tp_account_get_protocol_name: * @account: a #TpAccount * * * * Returns: the same as the #TpAccount:protocol-name property * * Since: 0.19.3 */ const gchar * tp_account_get_protocol_name (TpAccount *account) { g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL); return account->priv->proto_name; } /** * tp_account_get_service: * @self: an account * * * * Returns: the same as the #TpAccount:service property * * Since: 0.11.9 */ const gchar * tp_account_get_service (TpAccount *self) { g_return_val_if_fail (TP_IS_ACCOUNT (self), NULL); return self->priv->service; } /** * tp_account_get_icon_name: * @account: a #TpAccount * * * * Returns: the same as the #TpAccount:icon-name property * * Since: 0.9.0 */ const gchar * tp_account_get_icon_name (TpAccount *account) { g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL); return account->priv->icon_name; } /** * tp_account_get_parameters: * @account: a #TpAccount * * Returns the parameters of the account, in a hash table where each string * is the parameter name (account, password, require-encryption etc.), and * each value is a #GValue. Using the tp_asv_get family of functions * (tp_asv_get_uint32(), tp_asv_get_string() etc.) to access the parameters is * recommended. * * The allowed parameters depend on the connection manager, and can be found * via tp_connection_manager_get_protocol() and * tp_connection_manager_protocol_get_param(). Well-known parameters are * listed * in * the Telepathy D-Bus Interface Specification. * * Returns: (transfer none) (element-type utf8 GObject.Value): the hash table of * parameters on @account * * Since: 0.9.0 */ const GHashTable * tp_account_get_parameters (TpAccount *account) { g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL); return account->priv->parameters; } /** * tp_account_dup_parameters_vardict: * @account: a #TpAccount * * Returns the parameters of the account, in a variant of type * %G_VARIANT_TYPE_VARDICT where the keys * are parameter names (account, password, require-encryption etc.). * Use g_variant_lookup() or g_variant_lookup_value() for convenient * access to the values. * * The allowed parameters depend on the connection manager, and can be found * via tp_connection_manager_get_protocol() and * tp_connection_manager_protocol_get_param(). Well-known parameters are * listed * in * the Telepathy D-Bus Interface Specification. * * Returns: (transfer full): the dictionary of * parameters on @account, of type %G_VARIANT_TYPE_VARDICT * * Since: 0.17.6 */ GVariant * tp_account_dup_parameters_vardict (TpAccount *account) { g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL); return _tp_asv_to_vardict (account->priv->parameters); } /** * tp_account_is_enabled: * @account: a #TpAccount * * * * Returns: the same as the #TpAccount:enabled property * * Since: 0.9.0 */ gboolean tp_account_is_enabled (TpAccount *account) { g_return_val_if_fail (TP_IS_ACCOUNT (account), FALSE); return account->priv->enabled; } static void _tp_account_property_set_cb (TpProxy *proxy, const GError *error, gpointer user_data, GObject *weak_object) { GSimpleAsyncResult *result = user_data; if (error != NULL) { DEBUG ("Failed to set property: %s", error->message); g_simple_async_result_set_from_error (result, error); } g_simple_async_result_complete_in_idle (result); g_object_unref (result); } /** * tp_account_set_enabled_finish: * @account: a #TpAccount * @result: a #GAsyncResult * @error: a #GError to fill * * Finishes an async set of the Enabled property. * * Returns: %TRUE if the set was successful, otherwise %FALSE * * Since: 0.9.0 */ gboolean tp_account_set_enabled_finish (TpAccount *account, GAsyncResult *result, GError **error) { _tp_implement_finish_void (account, tp_account_set_enabled_finish); } /** * tp_account_set_enabled_async: * @account: a #TpAccount * @enabled: the new enabled value of @account * @callback: a callback to call when the request is satisfied * @user_data: data to pass to @callback * * Requests an asynchronous set of the Enabled property of @account. When the * operation is finished, @callback will be called. You can then call * tp_account_set_enabled_finish() to get the result of the operation. * * Since: 0.9.0 */ void tp_account_set_enabled_async (TpAccount *account, gboolean enabled, GAsyncReadyCallback callback, gpointer user_data) { GValue value = {0, }; GSimpleAsyncResult *result; g_return_if_fail (TP_IS_ACCOUNT (account)); result = g_simple_async_result_new (G_OBJECT (account), callback, user_data, tp_account_set_enabled_finish); g_value_init (&value, G_TYPE_BOOLEAN); g_value_set_boolean (&value, enabled); tp_cli_dbus_properties_call_set (TP_PROXY (account), -1, TP_IFACE_ACCOUNT, "Enabled", &value, _tp_account_property_set_cb, result, NULL, G_OBJECT (account)); g_value_reset (&value); } static void _tp_account_void_cb (TpAccount *proxy, const GError *error, gpointer user_data, GObject *weak_object) { GSimpleAsyncResult *result = user_data; if (error != NULL) g_simple_async_result_set_from_error (result, error); g_simple_async_result_complete_in_idle (result); g_object_unref (result); } /** * tp_account_reconnect_finish: * @account: a #TpAccount * @result: a #GAsyncResult * @error: a #GError to be filled * * Finishes an async reconnect of @account. * * Returns: %TRUE if the reconnect call was successful, otherwise %FALSE * * Since: 0.9.0 */ gboolean tp_account_reconnect_finish (TpAccount *account, GAsyncResult *result, GError **error) { _tp_implement_finish_void (account, tp_account_reconnect_finish); } /** * tp_account_reconnect_async: * @account: a #TpAccount * @callback: a callback to call when the request is satisfied * @user_data: data to pass to @callback * * Requests an asynchronous reconnect of @account. When the operation is * finished, @callback will be called. You can then call * tp_account_reconnect_finish() to get the result of the operation. * * Since: 0.9.0 */ void tp_account_reconnect_async (TpAccount *account, GAsyncReadyCallback callback, gpointer user_data) { GSimpleAsyncResult *result; g_return_if_fail (TP_IS_ACCOUNT (account)); result = g_simple_async_result_new (G_OBJECT (account), callback, user_data, tp_account_reconnect_finish); tp_cli_account_call_reconnect (account, -1, _tp_account_void_cb, result, NULL, G_OBJECT (account)); } /** * tp_account_set_automatic_presence_finish: * @account: a #TpAccount * @result: a #GAsyncResult * @error: a #GError to fill * * Finishes an asynchronous request to change the automatic presence of * @account. * * Returns: %TRUE if the operation was successful, otherwise %FALSE * * Since: 0.13.8 */ gboolean tp_account_set_automatic_presence_finish (TpAccount *account, GAsyncResult *result, GError **error) { _tp_implement_finish_void (account, tp_account_set_automatic_presence_async) } /** * tp_account_set_automatic_presence_async: * @account: a #TpAccount * @type: the requested presence * @status: a status message to set, or %NULL * @message: a message for the change, or %NULL * @callback: a callback to call when the request is satisfied * @user_data: data to pass to @callback * * Requests an asynchronous change of @account's automatic presence. When the * operation is finished, @callback will be called. You can then call * tp_account_set_automatic_presence_finish() to get the result of the * operation. * * Since: 0.13.8 */ void tp_account_set_automatic_presence_async (TpAccount *account, TpConnectionPresenceType type, const gchar *status, const gchar *message, GAsyncReadyCallback callback, gpointer user_data) { GValue value = {0, }; GSimpleAsyncResult *result; g_return_if_fail (TP_IS_ACCOUNT (account)); result = g_simple_async_result_new (G_OBJECT (account), callback, user_data, tp_account_set_automatic_presence_async); g_value_init (&value, TP_STRUCT_TYPE_SIMPLE_PRESENCE); g_value_take_boxed (&value, tp_value_array_build (3, G_TYPE_UINT, type, G_TYPE_STRING, status, G_TYPE_STRING, message, G_TYPE_INVALID)); tp_cli_dbus_properties_call_set (TP_PROXY (account), -1, TP_IFACE_ACCOUNT, "AutomaticPresence", &value, _tp_account_property_set_cb, result, NULL, G_OBJECT (account)); g_value_unset (&value); } /** * tp_account_request_presence_finish: * @account: a #TpAccount * @result: a #GAsyncResult * @error: a #GError to fill * * Finishes an async presence change request on @account. * * Returns: %TRUE if the operation was successful, otherwise %FALSE * * Since: 0.9.0 */ gboolean tp_account_request_presence_finish (TpAccount *account, GAsyncResult *result, GError **error) { _tp_implement_finish_void (account, tp_account_request_presence_finish); } /** * tp_account_request_presence_async: * @account: a #TpAccount * @type: the requested presence * @status: a status message to set, or %NULL * @message: a message for the change, or %NULL * @callback: a callback to call when the request is satisfied * @user_data: data to pass to @callback * * Requests an asynchronous change of presence on @account. When the * operation is finished, @callback will be called. You can then call * tp_account_request_presence_finish() to get the result of the operation. * * Since: 0.9.0 */ void tp_account_request_presence_async (TpAccount *account, TpConnectionPresenceType type, const gchar *status, const gchar *message, GAsyncReadyCallback callback, gpointer user_data) { GValue value = {0, }; GValueArray *arr; GSimpleAsyncResult *result; g_return_if_fail (TP_IS_ACCOUNT (account)); result = g_simple_async_result_new (G_OBJECT (account), callback, user_data, tp_account_request_presence_finish); g_value_init (&value, TP_STRUCT_TYPE_SIMPLE_PRESENCE); g_value_take_boxed (&value, dbus_g_type_specialized_construct ( TP_STRUCT_TYPE_SIMPLE_PRESENCE)); arr = (GValueArray *) g_value_get_boxed (&value); g_value_set_uint (arr->values, type); g_value_set_static_string (arr->values + 1, status); g_value_set_static_string (arr->values + 2, message); tp_cli_dbus_properties_call_set (TP_PROXY (account), -1, TP_IFACE_ACCOUNT, "RequestedPresence", &value, _tp_account_property_set_cb, result, NULL, G_OBJECT (account)); g_value_unset (&value); } static void _tp_account_updated_cb (TpAccount *proxy, const gchar **reconnect_required, const GError *error, gpointer user_data, GObject *weak_object) { GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (user_data); if (error != NULL) g_simple_async_result_set_from_error (result, error); else g_simple_async_result_set_op_res_gpointer (result, g_strdupv ((GStrv) reconnect_required), (GDestroyNotify) g_strfreev); g_simple_async_result_complete_in_idle (result); g_object_unref (G_OBJECT (result)); } /** * tp_account_update_parameters_async: * @account: a #TpAccount * @parameters: (element-type utf8 GObject.Value) (transfer none): new * parameters to set on @account * @unset_parameters: list of parameters to unset on @account * @callback: a callback to call when the request is satisfied * @user_data: data to pass to @callback * * Requests an asynchronous update of parameters of @account. When the * operation is finished, @callback will be called. You can then call * tp_account_update_parameters_finish() to get the result of the operation. * * Since: 0.9.0 */ void tp_account_update_parameters_async (TpAccount *account, GHashTable *parameters, const gchar **unset_parameters, GAsyncReadyCallback callback, gpointer user_data) { GSimpleAsyncResult *result; g_return_if_fail (TP_IS_ACCOUNT (account)); result = g_simple_async_result_new (G_OBJECT (account), callback, user_data, tp_account_update_parameters_finish); tp_cli_account_call_update_parameters (account, -1, parameters, unset_parameters, _tp_account_updated_cb, result, NULL, G_OBJECT (account)); } /** * tp_account_update_parameters_finish: * @account: a #TpAccount * @result: a #GAsyncResult * @reconnect_required: (out) (array zero-terminated=1) (transfer full): a #GStrv to * fill with properties that need a reconnect to take effect * @error: a #GError to fill * * Finishes an async update of the parameters on @account. * * Returns: %TRUE if the request succeeded, otherwise %FALSE * * Since: 0.9.0 */ gboolean tp_account_update_parameters_finish (TpAccount *account, GAsyncResult *result, gchar ***reconnect_required, GError **error) { _tp_implement_finish_copy_pointer (account, tp_account_update_parameters_finish, g_strdupv, reconnect_required); } /** * tp_account_update_parameters_vardict_async: * @account: a #TpAccount * @parameters: (transfer none): a variant of type %G_VARIANT_TYPE_VARDICT * containing new parameters to set on @account * @unset_parameters: (array zero-terminated=1): list of parameters to unset on @account * @callback: a callback to call when the request is satisfied * @user_data: data to pass to @callback * * Requests an asynchronous update of parameters of @account. When the * operation is finished, @callback will be called. You can then call * tp_account_update_parameters_finish() to get the result of the operation. * * If @parameters is a floating reference (see g_variant_ref_sink()), * ownership of @parameters is taken by this function. This means * you can pass the result of g_variant_new() or g_variant_new_parsed() * directly to this function without additional reference-count management. * * Since: 0.17.6 */ void tp_account_update_parameters_vardict_async (TpAccount *account, GVariant *parameters, const gchar **unset_parameters, GAsyncReadyCallback callback, gpointer user_data) { GHashTable *hash; hash = _tp_asv_from_vardict (parameters); g_variant_ref_sink (parameters); tp_account_update_parameters_async (account, hash, unset_parameters, callback, user_data); g_variant_unref (parameters); g_hash_table_unref (hash); } /** * tp_account_update_parameters_vardict_finish: * @account: a #TpAccount * @result: a #GAsyncResult * @reconnect_required: (out) (type GStrv) (transfer full): a #GStrv to * fill with properties that need a reconnect to take effect * @error: a #GError to fill * * Finishes an async update of the parameters on @account. * * Returns: %TRUE if the request succeeded, otherwise %FALSE * * Since: 0.17.6 */ gboolean tp_account_update_parameters_vardict_finish (TpAccount *account, GAsyncResult *result, gchar ***reconnect_required, GError **error) { /* share an implementation with the non-vardict version */ return tp_account_update_parameters_finish (account, result, reconnect_required, error); } /** * tp_account_set_display_name_async: * @account: a #TpAccount * @display_name: a new display name, or %NULL to unset the display name * @callback: a callback to call when the request is satisfied * @user_data: data to pass to @callback * * Requests an asynchronous set of the DisplayName property of @account. When * the operation is finished, @callback will be called. You can then call * tp_account_set_display_name_finish() to get the result of the operation. * * Since: 0.9.0 */ void tp_account_set_display_name_async (TpAccount *account, const char *display_name, GAsyncReadyCallback callback, gpointer user_data) { GSimpleAsyncResult *result; GValue value = {0, }; const gchar *display_name_set; g_return_if_fail (TP_IS_ACCOUNT (account)); if (display_name == NULL) display_name_set = ""; else display_name_set = display_name; result = g_simple_async_result_new (G_OBJECT (account), callback, user_data, tp_account_set_display_name_finish); g_value_init (&value, G_TYPE_STRING); g_value_set_string (&value, display_name_set); tp_cli_dbus_properties_call_set (account, -1, TP_IFACE_ACCOUNT, "DisplayName", &value, _tp_account_property_set_cb, result, NULL, G_OBJECT (account)); g_value_unset (&value); } /** * tp_account_set_display_name_finish: * @account: a #TpAccount * @result: a #GAsyncResult * @error: a #GError to fill * * Finishes an async set of the DisplayName property. * * Returns: %TRUE if the call was successful, otherwise %FALSE * * Since: 0.9.0 */ gboolean tp_account_set_display_name_finish (TpAccount *account, GAsyncResult *result, GError **error) { _tp_implement_finish_void (account, tp_account_set_display_name_finish); } /** * tp_account_set_service_async: * @self: a #TpAccount * @service: a new service name, or %NULL or the empty string to unset the * service name (which will result in the #TpAccount:service property * becoming the same as #TpAccount:protocol) * @callback: a callback to call when the request is satisfied * @user_data: data to pass to @callback * * Requests an asynchronous set of the Service property on @self. When * the operation is finished, @callback will be called. You can then call * tp_account_set_service_finish() to get the result of the operation. * * Since: 0.11.9 */ void tp_account_set_service_async (TpAccount *self, const char *service, GAsyncReadyCallback callback, gpointer user_data) { GSimpleAsyncResult *result; GValue value = {0, }; g_return_if_fail (TP_IS_ACCOUNT (self)); if (service == NULL) service = ""; result = g_simple_async_result_new (G_OBJECT (self), callback, user_data, tp_account_set_service_async); g_value_init (&value, G_TYPE_STRING); g_value_set_string (&value, service); tp_cli_dbus_properties_call_set (self, -1, TP_IFACE_ACCOUNT, "Service", &value, _tp_account_property_set_cb, result, NULL, G_OBJECT (self)); g_value_unset (&value); } /** * tp_account_set_service_finish: * @self: a #TpAccount * @result: a #GAsyncResult * @error: a #GError to fill * * Finishes an async set of the Service parameter. * * Returns: %TRUE if the operation was successful, otherwise %FALSE * * Since: 0.11.9 */ gboolean tp_account_set_service_finish (TpAccount *self, GAsyncResult *result, GError **error) { _tp_implement_finish_void (self, tp_account_set_service_async); } /** * tp_account_set_icon_name_async: * @account: a #TpAccount * @icon_name: a new icon name, or %NULL to unset the icon name * @callback: a callback to call when the request is satisfied * @user_data: data to pass to @callback * * Requests an asynchronous set of the Icon property of @account. When * the operation is finished, @callback will be called. You can then call * tp_account_set_icon_name_finish() to get the result of the operation. * * Since: 0.9.0 */ void tp_account_set_icon_name_async (TpAccount *account, const char *icon_name, GAsyncReadyCallback callback, gpointer user_data) { GSimpleAsyncResult *result; GValue value = {0, }; const char *icon_name_set; g_return_if_fail (TP_IS_ACCOUNT (account)); if (icon_name == NULL) /* settings an empty icon name is allowed */ icon_name_set = ""; else icon_name_set = icon_name; result = g_simple_async_result_new (G_OBJECT (account), callback, user_data, tp_account_set_icon_name_finish); g_value_init (&value, G_TYPE_STRING); g_value_set_string (&value, icon_name_set); tp_cli_dbus_properties_call_set (account, -1, TP_IFACE_ACCOUNT, "Icon", &value, _tp_account_property_set_cb, result, NULL, G_OBJECT (account)); g_value_unset (&value); } /** * tp_account_set_icon_name_finish: * @account: a #TpAccount * @result: a #GAsyncResult * @error: a #GError to fill * * Finishes an async set of the Icon parameter. * * Returns: %TRUE if the operation was successful, otherwise %FALSE * * Since: 0.9.0 */ gboolean tp_account_set_icon_name_finish (TpAccount *account, GAsyncResult *result, GError **error) { _tp_implement_finish_void (account, tp_account_set_icon_name_finish); } /** * tp_account_remove_async: * @account: a #TpAccount * @callback: a callback to call when the request is satisfied * @user_data: data to pass to @callback * * Requests an asynchronous removal of @account. When the operation is * finished, @callback will be called. You can then call * tp_account_remove_finish() to get the result of the operation. * * Since: 0.9.0 */ void tp_account_remove_async (TpAccount *account, GAsyncReadyCallback callback, gpointer user_data) { GSimpleAsyncResult *result; g_return_if_fail (TP_IS_ACCOUNT (account)); result = g_simple_async_result_new (G_OBJECT (account), callback, user_data, tp_account_remove_finish); tp_cli_account_call_remove (account, -1, _tp_account_void_cb, result, NULL, G_OBJECT (account)); } /** * tp_account_remove_finish: * @account: a #TpAccount * @result: a #GAsyncResult * @error: a #GError to fill * * Finishes an async removal of @account. * * Returns: %TRUE if the operation was successful, otherwise %FALSE * * Since: 0.9.0 */ gboolean tp_account_remove_finish (TpAccount *account, GAsyncResult *result, GError **error) { _tp_implement_finish_void (account, tp_account_remove_finish); } /** * tp_account_get_changing_presence: * @self: an account * * * * Returns: the same as the #TpAccount:changing-presence property * * Since: 0.11.6 */ gboolean tp_account_get_changing_presence (TpAccount *self) { g_return_val_if_fail (TP_IS_ACCOUNT (self), FALSE); return self->priv->changing_presence; } /** * tp_account_get_connect_automatically: * @account: a #TpAccount * * * * Returns: the same as the #TpAccount:connect-automatically property * * Since: 0.9.0 */ gboolean tp_account_get_connect_automatically (TpAccount *account) { g_return_val_if_fail (TP_IS_ACCOUNT (account), FALSE); return account->priv->connect_automatically; } /** * tp_account_set_connect_automatically_async: * @account: a #TpAccount * @connect_automatically: new value for the parameter * @callback: a callback to call when the request is satisfied * @user_data: data to pass to @callback * * Requests an asynchronous set of the ConnectAutomatically property of * @account. When the operation is finished, @callback will be called. You can * then call tp_account_set_display_name_finish() to get the result of the * operation. * * Since: 0.9.0 */ void tp_account_set_connect_automatically_async (TpAccount *account, gboolean connect_automatically, GAsyncReadyCallback callback, gpointer user_data) { GSimpleAsyncResult *result; GValue value = {0, }; g_return_if_fail (TP_IS_ACCOUNT (account)); result = g_simple_async_result_new (G_OBJECT (account), callback, user_data, tp_account_set_connect_automatically_finish); g_value_init (&value, G_TYPE_BOOLEAN); g_value_set_boolean (&value, connect_automatically); tp_cli_dbus_properties_call_set (account, -1, TP_IFACE_ACCOUNT, "ConnectAutomatically", &value, _tp_account_property_set_cb, result, NULL, G_OBJECT (account)); g_value_unset (&value); } /** * tp_account_set_connect_automatically_finish: * @account: a #TpAccount * @result: a #GAsyncResult * @error: a #GError to fill * * Finishes an async set of the ConnectAutomatically property. * * Returns: %TRUE if the call was successful, otherwise %FALSE * * Since: 0.9.0 */ gboolean tp_account_set_connect_automatically_finish (TpAccount *account, GAsyncResult *result, GError **error) { _tp_implement_finish_void (account, tp_account_set_connect_automatically_finish); } /** * tp_account_get_has_been_online: * @account: a #TpAccount * * * * Returns: the same as the #TpAccount:has-been-online property * * Since: 0.9.0 */ gboolean tp_account_get_has_been_online (TpAccount *account) { g_return_val_if_fail (TP_IS_ACCOUNT (account), FALSE); return account->priv->has_been_online; } /** * tp_account_get_connection_status: * @account: a #TpAccount * @reason: (out): a #TpConnectionStatusReason to fill, or %NULL * * Gets the connection status and reason from @account. The two values * are the same as the #TpAccount:connection-status and * #TpAccount:connection-status-reason properties. * * Returns: the same as the #TpAccount:connection-status property * * Since: 0.9.0 */ TpConnectionStatus tp_account_get_connection_status (TpAccount *account, TpConnectionStatusReason *reason) { g_return_val_if_fail (TP_IS_ACCOUNT (account), TP_CONNECTION_STATUS_DISCONNECTED); /* there's no _UNSET */ if (reason != NULL) *reason = account->priv->reason; return account->priv->connection_status; } /** * tp_account_get_current_presence: * @account: a #TpAccount * @status: (out) (transfer full): return location for the current status * @status_message: (out) (transfer full): return location for the current * status message * * Gets the current presence, status and status message of @account. These * values are the same as the #TpAccount:current-presence-type, * #TpAccount:current-status and #TpAccount:current-status-message properties. * * Returns: the same as the #TpAccount:current-presence-type property * * Since: 0.9.0 */ TpConnectionPresenceType tp_account_get_current_presence (TpAccount *account, gchar **status, gchar **status_message) { g_return_val_if_fail (TP_IS_ACCOUNT (account), TP_CONNECTION_PRESENCE_TYPE_UNSET); if (status != NULL) *status = g_strdup (account->priv->cur_status); if (status_message != NULL) *status_message = g_strdup (account->priv->cur_message); return account->priv->cur_presence; } /** * tp_account_get_requested_presence: * @account: a #TpAccount * @status: (out) (transfer none): return location for the requested status * @status_message: (out) (transfer full): return location for the requested * status message * * Gets the requested presence, status and status message of @account. These * values are the same as the #TpAccount:requested-presence-type, * #TpAccount:requested-status and #TpAccount:requested-status-message * properties. * * Returns: the same as the #TpAccount:requested-presence-type property * * Since: 0.9.0 */ TpConnectionPresenceType tp_account_get_requested_presence (TpAccount *account, gchar **status, gchar **status_message) { g_return_val_if_fail (TP_IS_ACCOUNT (account), TP_CONNECTION_PRESENCE_TYPE_UNSET); if (status != NULL) *status = g_strdup (account->priv->requested_status); if (status_message != NULL) *status_message = g_strdup (account->priv->requested_message); return account->priv->requested_presence; } /** * tp_account_get_nickname: * @account: a #TpAccount * * * * Returns: the same as the #TpAccount:nickname property * * Since: 0.9.0 */ const gchar * tp_account_get_nickname (TpAccount *account) { g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL); return account->priv->nickname; } /** * tp_account_set_nickname_finish: * @account: a #TpAccount * @result: a #GAsyncResult * @error: a #GError to fill * * Finishes an async nickname change request on @account. * * Returns: %TRUE if the operation was successful, otherwise %FALSE * * Since: 0.9.0 */ gboolean tp_account_set_nickname_finish (TpAccount *account, GAsyncResult *result, GError **error) { _tp_implement_finish_void (account, tp_account_set_nickname_finish); } /** * tp_account_set_nickname_async: * @account: a #TpAccount * @nickname: a new nickname to set * @callback: a callback to call when the request is satisfied * @user_data: data to pass to @callback * * Requests an asynchronous change of the Nickname parameter on @account. When * the operation is finished, @callback will be called. You can then call * tp_account_set_nickname_finish() to get the result of the operation. * * Since: 0.9.0 */ void tp_account_set_nickname_async (TpAccount *account, const gchar *nickname, GAsyncReadyCallback callback, gpointer user_data) { GValue value = {0, }; GSimpleAsyncResult *result; g_return_if_fail (TP_IS_ACCOUNT (account)); g_return_if_fail (nickname != NULL); result = g_simple_async_result_new (G_OBJECT (account), callback, user_data, tp_account_set_nickname_finish); if (nickname == NULL) { g_simple_async_report_error_in_idle (G_OBJECT (account), callback, user_data, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "Can't set an empty nickname"); return; } g_value_init (&value, G_TYPE_STRING); g_value_set_string (&value, nickname); tp_cli_dbus_properties_call_set (TP_PROXY (account), -1, TP_IFACE_ACCOUNT, "Nickname", &value, _tp_account_property_set_cb, result, NULL, G_OBJECT (account)); g_value_unset (&value); } /** * tp_account_get_supersedes: * @self: a #TpAccount * * Return the same thing as the #TpAccount:supersedes property, in a way * that may be more convenient for C code. * * The returned pointers are not guaranteed to remain valid after the * main loop has been re-entered. * * Returns: (transfer none): the same as the #TpAccount:supersedes property * * Since: 0.17.5 */ const gchar * const * tp_account_get_supersedes (TpAccount *self) { g_return_val_if_fail (TP_IS_ACCOUNT (self), NULL); return (const gchar * const *) self->priv->supersedes; } static void _tp_account_got_avatar_cb (TpProxy *proxy, const GValue *out_Value, const GError *error, gpointer user_data, GObject *weak_object) { GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (user_data); if (error != NULL) { DEBUG ("Failed to get avatar: %s", error->message); g_simple_async_result_set_from_error (result, error); } else if (!G_VALUE_HOLDS (out_Value, TP_STRUCT_TYPE_AVATAR)) { DEBUG ("Avatar had wrong type: %s", G_VALUE_TYPE_NAME (out_Value)); g_simple_async_result_set_error (result, TP_ERROR, TP_ERROR_CONFUSED, "Incorrect type for Avatar property"); } else { GValueArray *avatar; GArray *res; const GArray *tmp; const gchar *mime_type; avatar = g_value_get_boxed (out_Value); tp_value_array_unpack (avatar, 2, &tmp, &mime_type); res = g_array_sized_new (FALSE, FALSE, 1, tmp->len); g_array_append_vals (res, tmp->data, tmp->len); g_simple_async_result_set_op_res_gpointer (result, res, (GDestroyNotify) g_array_unref); } g_simple_async_result_complete_in_idle (result); g_object_unref (result); } /** * tp_account_get_avatar_async: * @account: a #TpAccount * @callback: a callback to call when the request is satisfied * @user_data: data to pass to @callback * * Requests an asynchronous get of @account's avatar. When * the operation is finished, @callback will be called. You can then call * tp_account_get_avatar_finish() to get the result of the operation. * * Since: 0.9.0 */ void tp_account_get_avatar_async (TpAccount *account, GAsyncReadyCallback callback, gpointer user_data) { GSimpleAsyncResult *result; g_return_if_fail (TP_IS_ACCOUNT (account)); result = g_simple_async_result_new (G_OBJECT (account), callback, user_data, tp_account_get_avatar_finish); tp_cli_dbus_properties_call_get (account, -1, TP_IFACE_ACCOUNT_INTERFACE_AVATAR, "Avatar", _tp_account_got_avatar_cb, result, NULL, G_OBJECT (account)); } /** * tp_account_get_avatar_finish: * @account: a #TpAccount * @result: a #GAsyncResult * @error: a #GError to fill * * Finishes an async get operation of @account's avatar. * * Beware that the returned value is only valid until @result is freed. * Copy it with g_array_ref() if you need to keep it for longer. * * Returns: (element-type guchar) (transfer none): a #GArray of #guchar * containing the bytes of the account's avatar, or %NULL on failure * * Since: 0.9.0 */ const GArray * tp_account_get_avatar_finish (TpAccount *account, GAsyncResult *result, GError **error) { _tp_implement_finish_return_copy_pointer (account, tp_account_get_avatar_finish, /* do not copy */); } /** * tp_account_is_prepared: (skip) * @account: a #TpAccount * @feature: a feature which is required * * * * Returns: the same thing as tp_proxy_is_prepared() * * Since: 0.9.0 * Deprecated: since 0.23.0, use tp_proxy_is_prepared() instead. */ gboolean tp_account_is_prepared (TpAccount *account, GQuark feature) { return tp_proxy_is_prepared (account, feature); } /** * tp_account_prepare_async: (skip) * @account: a #TpAccount * @features: a 0-terminated list of features, or %NULL * @callback: a callback to call when the request is satisfied * @user_data: data to pass to @callback * * Requests an asynchronous preparation of @account with the features specified * by @features. When the operation is finished, @callback will be called. You * can then call tp_account_prepare_finish() to get the result of the * operation. * * If @features is %NULL, then @callback will be called when the implied * %TP_ACCOUNT_FEATURE_CORE feature is ready. * * If %NULL is given to @callback, then no callback will be called when the * operation is finished. Instead, it will simply set @features on @manager. * Note that if @callback is %NULL, then @user_data must also be %NULL. * * Since 0.11.3, this is equivalent to calling the new function * tp_proxy_prepare_async() with the same arguments. * * Since: 0.9.0 * Deprecated: since 0.15.6, use tp_proxy_prepare_async() instead. */ void tp_account_prepare_async (TpAccount *account, const GQuark *features, GAsyncReadyCallback callback, gpointer user_data) { tp_proxy_prepare_async (account, features, callback, user_data); } /** * tp_account_prepare_finish: (skip) * @account: a #TpAccount * @result: a #GAsyncResult * @error: a #GError to fill * * Finishes an async preparation of the account @account. * * Returns: %TRUE if the preparation was successful, otherwise %FALSE * * Since: 0.9.0 * Deprecated: since 0.15.6, use tp_proxy_prepare_finish() instead. */ gboolean tp_account_prepare_finish (TpAccount *account, GAsyncResult *result, GError **error) { return tp_proxy_prepare_finish (account, result, error); } static void set_or_free (gchar **target, gchar *source) { if (target != NULL) *target = source; else g_free (source); } /** * tp_account_parse_object_path: * @object_path: a Telepathy Account's object path * @cm: (out) (transfer full): location at which to store the account's * connection manager's name * @protocol: (out) (transfer full): location at which to store the account's * protocol * @account_id: (out) (transfer full): location at which to store the account's * unique identifier * @error: location at which to return an error * * Validates and parses a Telepathy Account's object path, extracting the * connection manager's name, the protocol, and the account's unique identifier * from the path. This includes replacing underscores with hyphens in the * protocol name, as defined in the Account specification. * * Any of the out parameters may be %NULL if not needed. If %TRUE is returned, * the caller is responsible for freeing the strings stored in any non-%NULL * out parameters, using g_free(). * * Returns: %TRUE if @object_path was successfully parsed; %FALSE and sets * @error otherwise. * * Since: 0.9.0 * Deprecated: Use tp_account_get_protocol() and * tp_account_get_connection_manager() instead. */ gboolean tp_account_parse_object_path (const gchar *object_path, gchar **cm, gchar **protocol, gchar **account_id, GError **error) { const gchar *suffix; gchar **segments; if (!tp_dbus_check_valid_object_path (object_path, error)) return FALSE; if (!g_str_has_prefix (object_path, TP_ACCOUNT_OBJECT_PATH_BASE)) { g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Account path does not start with the right prefix: %s", object_path); return FALSE; } suffix = object_path + strlen (TP_ACCOUNT_OBJECT_PATH_BASE); segments = g_strsplit (suffix, "/", 0); if (g_strv_length (segments) != 3) { g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Account path '%s' is malformed: should have 3 trailing components, " "not %u", object_path, g_strv_length (segments)); goto free_segments_and_fail; } if (!g_ascii_isalpha (segments[0][0])) { g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Account path '%s' is malformed: CM name should start with a letter", object_path); goto free_segments_and_fail; } if (!g_ascii_isalpha (segments[1][0])) { g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Account path '%s' is malformed: " "protocol name should start with a letter", object_path); goto free_segments_and_fail; } if (!g_ascii_isalpha (segments[2][0]) && segments[2][0] != '_') { g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Account path '%s' is malformed: " "account ID should start with a letter or underscore", object_path); goto free_segments_and_fail; } set_or_free (cm, segments[0]); set_or_free (protocol, unescape_protocol (segments[1])); set_or_free (account_id, segments[2]); /* Not g_strfreev because we stole or freed the individual strings */ g_free (segments); return TRUE; free_segments_and_fail: g_strfreev (segments); return FALSE; } /** * _tp_account_refresh_properties: * @account: a #TpAccount * * Refreshes @account's hashtable of properties with what actually exists on * the account manager. * * Since: 0.9.0 */ void _tp_account_refresh_properties (TpAccount *account) { g_return_if_fail (TP_IS_ACCOUNT (account)); tp_cli_dbus_properties_call_get_all (account, -1, TP_IFACE_ACCOUNT, _tp_account_got_all_cb, NULL, NULL, G_OBJECT (account)); } /** * tp_account_set_avatar_finish: * @self: a #TpAccount * @result: a #GAsyncResult * @error: a #GError to fill * * Finishes an async avatar change request on @account. * * Returns: %TRUE if the operation was successful, otherwise %FALSE * * Since: 0.11.1 */ gboolean tp_account_set_avatar_finish (TpAccount *self, GAsyncResult *result, GError **error) { _tp_implement_finish_void (self, tp_account_set_avatar_async); } /** * tp_account_set_avatar_async: * @self: a #TpAccount * @avatar: (allow-none) (array length=len): a new avatar to set; can be %NULL * only if @len equals 0 * @len: the length of the new avatar * @mime_type: (allow-none): the MIME type of the new avatar; can be %NULL * only if @len equals 0 * @callback: a callback to call when the request is satisfied * @user_data: data to pass to @callback * * Requests an asynchronous change of the Avatar parameter on @self. When * the operation is finished, @callback will be called. You can then call * tp_account_set_avatar_finish() to get the result of the operation. * * If @len equals 0, the avatar is cleared. * * Since: 0.11.1 */ void tp_account_set_avatar_async (TpAccount *self, const guchar *avatar, gsize len, const gchar *mime_type, GAsyncReadyCallback callback, gpointer user_data) { GValue value = {0, }; GSimpleAsyncResult *result; GValueArray *arr; GArray *tmp; g_return_if_fail (TP_IS_ACCOUNT (self)); g_return_if_fail (avatar != NULL || len == 0); g_return_if_fail (mime_type != NULL || len == 0); result = g_simple_async_result_new (G_OBJECT (self), callback, user_data, tp_account_set_avatar_async); tmp = g_array_new (FALSE, FALSE, sizeof (guchar)); if (len > 0) g_array_append_vals (tmp, avatar, len); arr = tp_value_array_build (2, TP_TYPE_UCHAR_ARRAY, tmp, G_TYPE_STRING, mime_type, G_TYPE_INVALID); g_value_init (&value, TP_STRUCT_TYPE_AVATAR); g_value_take_boxed (&value, arr); tp_cli_dbus_properties_call_set (self, -1, TP_IFACE_ACCOUNT_INTERFACE_AVATAR, "Avatar", &value, _tp_account_property_set_cb, result, NULL, NULL); g_value_unset (&value); } /** * tp_account_get_detailed_error: (skip) * @self: an account * @details: (out) (allow-none) (element-type utf8 GObject.Value) (transfer none): * optionally used to return a map from string to #GValue, which must not be * modified, destroyed or unreffed by the caller * * If the account's connection is not connected, return the D-Bus error name * with which it last disconnected or failed to connect (in particular, this * is %TP_ERROR_STR_CANCELLED if it was disconnected by a user request). * This is the same as #TpAccount:connection-error. * * If @details is not %NULL, it will be used to return additional details about * the error (the same as #TpAccount:connection-error-details). * * Otherwise, return %NULL, without altering @details. * * The returned string and @details may become invalid when the main loop is * re-entered or the account is destroyed. * * Returns: (transfer none) (allow-none): a D-Bus error name, or %NULL. * * Since: 0.11.7 */ const gchar * tp_account_get_detailed_error (TpAccount *self, const GHashTable **details) { g_return_val_if_fail (TP_IS_ACCOUNT (self), NULL); if (self->priv->connection_status == TP_CONNECTION_STATUS_CONNECTED) return NULL; if (details != NULL) *details = self->priv->error_details; return self->priv->error; } /** * tp_account_dup_detailed_error_vardict: * @self: an account * @details: (out) (allow-none) (transfer full): * optionally used to return a variant of type %G_VARIANT_TYPE_VARDICT, * which must be unreffed by the caller with g_variant_unref() * * If the account's connection is not connected, return the D-Bus error name * with which it last disconnected or failed to connect (in particular, this * is %TP_ERROR_STR_CANCELLED if it was disconnected by a user request). * This is the same as #TpAccount:connection-error. * * If @details is not %NULL, it will be used to return additional details about * the error (the same as #TpAccount:connection-error-details). * * Otherwise, return %NULL, without altering @details. * * The returned string and @details may become invalid when the main loop is * re-entered or the account is destroyed. * * Returns: (transfer full) (allow-none): a D-Bus error name, or %NULL. * * Since: 0.17.6 */ gchar * tp_account_dup_detailed_error_vardict (TpAccount *self, GVariant **details) { g_return_val_if_fail (TP_IS_ACCOUNT (self), NULL); if (self->priv->connection_status == TP_CONNECTION_STATUS_CONNECTED) return NULL; if (details != NULL) *details = _tp_asv_to_vardict (self->priv->error_details); return g_strdup (self->priv->error); } /** * tp_account_get_storage_provider: * @self: a #TpAccount * * * * Returns: the same as the #TpAccount:storage-provider property * * Since: 0.13.2 */ const gchar * tp_account_get_storage_provider (TpAccount *self) { g_return_val_if_fail (TP_IS_ACCOUNT (self), NULL); return self->priv->storage_provider; } /* FIXME: in 1.0, remove */ /** * tp_account_get_storage_identifier: * @self: a #TpAccount * * * * Returns: the same as the #TpAccount:storage-identifier property * * Since: 0.13.2 */ const GValue * tp_account_get_storage_identifier (TpAccount *self) { g_return_val_if_fail (TP_IS_ACCOUNT (self), NULL); return self->priv->storage_identifier; } /* FIXME: in 1.0, rename to tp_account_get_storage_identifier */ /** * tp_account_dup_storage_identifier_variant: * @self: a #TpAccount * * Return provider-specific information used to identify this * account. Use g_variant_get_type() to check that the type * is what you expect; for instance, if the * #TpAccount:storage-provider has string-based user identifiers, * this variant should have type %G_VARIANT_TYPE_STRING. * * Returns: (transfer full): the same as the * #TpAccount:storage-identifier-variant property * * Since: 0.13.2 */ GVariant * tp_account_dup_storage_identifier_variant (TpAccount *self) { g_return_val_if_fail (TP_IS_ACCOUNT (self), NULL); if (self->priv->storage_identifier == NULL) return NULL; return g_variant_ref_sink (dbus_g_value_build_g_variant ( self->priv->storage_identifier)); } /** * tp_account_get_storage_restrictions: * @self: a #TpAccount * * * * Returns: the same as the #TpAccount:storage-restrictions property * * Since: 0.13.2 */ TpStorageRestrictionFlags tp_account_get_storage_restrictions (TpAccount *self) { g_return_val_if_fail (TP_IS_ACCOUNT (self), 0); return self->priv->storage_restrictions; } static void _tp_account_get_storage_specific_information_cb (TpProxy *self, const GValue *value, const GError *error, gpointer user_data, GObject *weak_obj) { GSimpleAsyncResult *result = user_data; if (error != NULL) { DEBUG ("Failed to retrieve StorageSpecificInformation: %s", error->message); g_simple_async_result_set_from_error (result, error); } else { g_simple_async_result_set_op_res_gpointer (result, g_value_dup_boxed (value), (GDestroyNotify) g_hash_table_unref); } g_simple_async_result_complete_in_idle (result); g_object_unref (result); } /* FIXME: in Telepathy 1.0, remove this */ /** * tp_account_get_storage_specific_information_async: * @self: a #TpAccount * @callback: a callback to call when the request is satisfied * @user_data: data to pass to @callback * * Makes an asynchronous request of @self's StorageSpecificInformation * property (part of the Account.Interface.Storage interface). * * When the operation is finished, @callback will be called. You must then * call tp_account_get_storage_specific_information_finish() to get the * result of the request. * * Since: 0.13.2 */ void tp_account_get_storage_specific_information_async (TpAccount *self, GAsyncReadyCallback callback, gpointer user_data) { GSimpleAsyncResult *result; g_return_if_fail (TP_IS_ACCOUNT (self)); result = g_simple_async_result_new (G_OBJECT (self), callback, user_data, tp_account_get_storage_specific_information_async); tp_cli_dbus_properties_call_get (self, -1, TP_IFACE_ACCOUNT_INTERFACE_STORAGE, "StorageSpecificInformation", _tp_account_get_storage_specific_information_cb, result, NULL, NULL); } /* FIXME: in Telepathy 1.0, rename to ...get_storage_specific_information... */ /** * tp_account_dup_storage_specific_information_vardict_async: * @self: a #TpAccount * @callback: a callback to call when the request is satisfied * @user_data: data to pass to @callback * * Makes an asynchronous request of @self's StorageSpecificInformation * property (part of the Account.Interface.Storage interface). * * When the operation is finished, @callback will be called. You must then * call tp_account_dup_storage_specific_information_vardict_finish() to get the * result of the request. * * Since: 0.17.6 */ void tp_account_dup_storage_specific_information_vardict_async (TpAccount *self, GAsyncReadyCallback callback, gpointer user_data) { /* we share an implementation */ tp_account_get_storage_specific_information_async (self, callback, user_data); } /* FIXME: in Telepathy 1.0, remove this */ /** * tp_account_get_storage_specific_information_finish: * @self: a #TpAccount * @result: a #GAsyncResult * @error: a #GError to fill * * Retrieve the value of the request begun with * tp_account_get_storage_specific_information_async(). * * Beware that the returned value is only valid until @result is freed. * Copy it with g_hash_table_ref() if you need to keep it for longer. * * Returns: (element-type utf8 GObject.Value) (transfer none): a #GHashTable * of strings to GValues representing the D-Bus type a{sv}. * * Since: 0.13.2 */ GHashTable * tp_account_get_storage_specific_information_finish (TpAccount *self, GAsyncResult *result, GError **error) { _tp_implement_finish_return_copy_pointer (self, tp_account_get_storage_specific_information_async, /* do not copy */); } /* FIXME: in Telepathy 1.0, rename to ...get_storage_specific_information... */ /** * tp_account_dup_storage_specific_information_vardict_finish: * @self: a #TpAccount * @result: a #GAsyncResult * @error: a #GError to fill * * Retrieve the value of the request begun with * tp_account_dup_storage_specific_information_vardict_async(). * * Returns: (transfer full): a map from strings to variants, * of type %G_VARIANT_TYPE_VARDICT * * Since: 0.17.6 */ GVariant * tp_account_dup_storage_specific_information_vardict_finish (TpAccount *self, GAsyncResult *result, GError **error) { /* we share the source tag with the non-vardict version */ _tp_implement_finish_return_copy_pointer (self, tp_account_get_storage_specific_information_async, _tp_asv_to_vardict); } static void _tp_account_got_all_addressing_cb (TpProxy *proxy, GHashTable *properties, const GError *error, gpointer user_data, GObject *object) { TpAccount *self = TP_ACCOUNT (proxy); GSimpleAsyncResult *result = user_data; if (error != NULL) { DEBUG ("Error getting Addressing properties: %s", error->message); } else { self->priv->uri_schemes = g_strdupv (tp_asv_get_boxed (properties, "URISchemes", G_TYPE_STRV)); } if (self->priv->uri_schemes == NULL) self->priv->uri_schemes = g_new0 (gchar *, 1); g_simple_async_result_complete_in_idle (result); } static void connection_prepare_cb (GObject *object, GAsyncResult *res, gpointer user_data) { TpConnection *connection = (TpConnection *) object; TpAccount *self = tp_connection_get_account (connection); GSimpleAsyncResult *result = user_data; GError *error = NULL; self->priv->connection_prepared = TRUE; if (!tp_proxy_prepare_finish (object, res, &error)) { DEBUG ("Error preparing connection: %s", error->message); g_simple_async_result_take_error (result, error); } g_simple_async_result_complete (result); g_object_unref (result); } static void tp_account_prepare_connection_async (TpProxy *proxy, const TpProxyFeature *feature, GAsyncReadyCallback callback, gpointer user_data) { TpAccount *self = TP_ACCOUNT (proxy); GSimpleAsyncResult *result; GArray *features; result = g_simple_async_result_new ((GObject *) proxy, callback, user_data, tp_account_prepare_connection_async); if (self->priv->connection == NULL) { g_simple_async_result_complete_in_idle (result); g_object_unref (result); return; } features = tp_simple_client_factory_dup_connection_features ( tp_proxy_get_factory (self), self->priv->connection); tp_proxy_prepare_async (self->priv->connection, (GQuark *) features->data, connection_prepare_cb, result); g_array_unref (features); } static void tp_account_prepare_addressing_async (TpProxy *proxy, const TpProxyFeature *feature, GAsyncReadyCallback callback, gpointer user_data) { TpAccount *self = TP_ACCOUNT (proxy); GSimpleAsyncResult *result; result = g_simple_async_result_new ((GObject *) proxy, callback, user_data, tp_account_prepare_addressing_async); g_assert (self->priv->uri_schemes == NULL); tp_cli_dbus_properties_call_get_all (self, -1, TP_IFACE_ACCOUNT_INTERFACE_ADDRESSING, _tp_account_got_all_addressing_cb, result, g_object_unref, NULL); } /** * tp_account_get_uri_schemes: * @self: a #TpAccount * * Return the #TpAccount:uri-schemes property * * Returns: (transfer none): the value of #TpAccount:uri_schemes property * * Since: 0.13.8 */ const gchar * const * tp_account_get_uri_schemes (TpAccount *self) { g_return_val_if_fail (TP_IS_ACCOUNT (self), NULL); return (const gchar * const *) self->priv->uri_schemes; } /** * tp_account_associated_with_uri_scheme: * @self: a #TpAccount * @scheme: (transfer none): a URI scheme such as "tel", "sip" or "xmpp" * * * * Returns: %TRUE if the result of tp_account_get_uri_schemes() would include * @scheme * * Since: 0.13.8 */ gboolean tp_account_associated_with_uri_scheme (TpAccount *self, const gchar *scheme) { return tp_strv_contains (tp_account_get_uri_schemes (self), scheme); } /** * tp_account_set_uri_scheme_association_async: * @self: a #TpAccount * @scheme: a non-%NULL URI scheme such as "tel" * @associate: %TRUE to use this account for @scheme, or %FALSE to not use it * @callback: a callback to call when the request is satisfied * @user_data: data to pass to @callback * * Add @scheme to the list of additional URI schemes that would be returned * by tp_account_get_uri_schemes(), or remove it from that list. * * @scheme should not be the primary URI scheme for the account's * protocol (for instance, "xmpp" for XMPP, or "sip" or "sips" for SIP), * since the account should be assumed to be useful for those schemes * regardless of the contents of the list. * * Calling this method does not require the %TP_ACCOUNT_FEATURE_ADDRESSING * feature to be enabled, but the change will not be reflected in the result * of tp_account_get_uri_schemes() or tp_account_associated_with_uri_scheme() * unless that feature has been enabled. * * Since: 0.13.8 */ void tp_account_set_uri_scheme_association_async (TpAccount *self, const gchar *scheme, gboolean associate, GAsyncReadyCallback callback, gpointer user_data) { GSimpleAsyncResult *result; g_return_if_fail (TP_IS_ACCOUNT (self)); g_return_if_fail (scheme != NULL); result = g_simple_async_result_new (G_OBJECT (self), callback, user_data, tp_account_set_uri_scheme_association_async); tp_cli_account_interface_addressing_call_set_uri_scheme_association ( self, -1, scheme, associate, _tp_account_void_cb, result, NULL, NULL); } /** * tp_account_set_uri_scheme_association_finish: * @self: a #TpAccount * @result: a #GAsyncResult * @error: a #GError to fill * * Interpret the result of tp_account_set_uri_scheme_association_async(). * * Returns: %TRUE if the call was successful, otherwise %FALSE * * Since: 0.13.8 */ gboolean tp_account_set_uri_scheme_association_finish (TpAccount *self, GAsyncResult *result, GError **error) { _tp_implement_finish_void (self, tp_account_set_uri_scheme_association_async); } /** * tp_account_get_automatic_presence: * @self: an account * @status: (out) (transfer none): return location for the presence status * @status_message: (out) (transfer full): return location for the * user-defined message * * Gets the automatic presence, status and status message of @account. These * values are the same as the #TpAccount:automatic-presence-type, * #TpAccount:automatic-status and #TpAccount:automatic-status-message * properties, and are the values that will be used if the account should * be put online automatically. * * Returns: the same as the #TpAccount:automatic-presence-type property * * Since: 0.13.8 */ TpConnectionPresenceType tp_account_get_automatic_presence (TpAccount *self, gchar **status, gchar **status_message) { g_return_val_if_fail (TP_IS_ACCOUNT (self), TP_CONNECTION_PRESENCE_TYPE_UNSET); if (status != NULL) *status = g_strdup (self->priv->auto_status); if (status_message != NULL) *status_message = g_strdup (self->priv->auto_message); return self->priv->auto_presence; } /** * tp_account_get_normalized_name: * @self: a #TpAccount * * * * Returns: (transfer none): the same as the #TpAccount:normalized-name * property * * Since: 0.13.8 **/ const gchar * tp_account_get_normalized_name (TpAccount *self) { g_return_val_if_fail (TP_IS_ACCOUNT (self), NULL); return self->priv->normalized_name; } /** * tp_account_bind_connection_status_to_property: * @self: a #TpAccount * @target: the target #GObject * @target_property: the property on @target to bind (must be %G_TYPE_BOOLEAN) * @invert: %TRUE if you wish to invert the value of @target_property * (i.e. %FALSE if connected) * * Binds the :connection-status of @self to the boolean property of another * object using a #GBinding such that the @target_property will be set to * %TRUE when @self is connected (and @invert is %FALSE). * * @target_property will be synchronised immediately (%G_BINDING_SYNC_CREATE). * @invert can be interpreted as analogous to %G_BINDING_INVERT_BOOLEAN. * * For instance, this function can be used to bind the GtkWidget:sensitive * property to only make a widget sensitive when the account is connected. * * See g_object_bind_property() for more information. * * Returns: (transfer none): the #GBinding instance representing the binding * between the @self and the @target. The binding is released whenever the * #GBinding reference count reaches zero. * Since: 0.13.16 */ GBinding * tp_account_bind_connection_status_to_property (TpAccount *self, gpointer target, const char *target_property, gboolean invert) { g_return_val_if_fail (TP_IS_ACCOUNT (self), NULL); return g_object_bind_property_full (self, "connection-status", target, target_property, G_BINDING_SYNC_CREATE, _tp_bind_connection_status_to_boolean, NULL, GUINT_TO_POINTER (invert), NULL); }